aboutsummaryrefslogtreecommitdiffstats
path: root/lib/kernel
diff options
context:
space:
mode:
Diffstat (limited to 'lib/kernel')
-rw-r--r--lib/kernel/src/inet.erl147
-rw-r--r--lib/kernel/src/inet_config.erl32
-rw-r--r--lib/kernel/src/inet_db.erl107
-rw-r--r--lib/kernel/src/inet_gethost_native.erl72
-rw-r--r--lib/kernel/src/inet_parse.erl285
-rw-r--r--lib/kernel/test/inet_SUITE.erl198
-rw-r--r--lib/kernel/test/inet_res_SUITE.erl88
7 files changed, 658 insertions, 271 deletions
diff --git a/lib/kernel/src/inet.erl b/lib/kernel/src/inet.erl
index b86aa1839e..eb503235d8 100644
--- a/lib/kernel/src/inet.erl
+++ b/lib/kernel/src/inet.erl
@@ -1,19 +1,19 @@
%%
%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1997-2009. All Rights Reserved.
-%%
+%%
+%% Copyright Ericsson AB 1997-2010. All Rights Reserved.
+%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
%% compliance with the License. You should have received a copy of the
%% Erlang Public License along with this software. If not, it can be
%% retrieved online at http://www.erlang.org/.
-%%
+%%
%% Software distributed under the License is distributed on an "AS IS"
%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
%% the License for the specific language governing rights and limitations
%% under the License.
-%%
+%%
%% %CopyrightEnd%
%%
-module(inet).
@@ -45,6 +45,7 @@
%% resolve
-export([gethostbyname/1, gethostbyname/2, gethostbyname/3,
gethostbyname_tm/3]).
+-export([gethostbyname_string/2, gethostbyname_self/2]).
-export([gethostbyaddr/1, gethostbyaddr/2,
gethostbyaddr_tm/2]).
@@ -411,7 +412,17 @@ gethostbyname(Name,Family,Timeout) ->
Res.
gethostbyname_tm(Name,Family,Timer) ->
- gethostbyname_tm(Name,Family,Timer,inet_db:res_option(lookup)).
+ Opts0 = inet_db:res_option(lookup),
+ Opts =
+ case (lists:member(native, Opts0) orelse
+ lists:member(string, Opts0) orelse
+ lists:member(nostring, Opts0)) of
+ true ->
+ Opts0;
+ false ->
+ [string|Opts0]
+ end,
+ gethostbyname_tm(Name, Family, Timer, Opts).
-spec gethostbyaddr(Address :: string() | ip_address()) ->
@@ -850,75 +861,61 @@ getaddrs_tm(Address, Family, Timer) ->
%%
%% gethostbyname with option search
%%
-gethostbyname_tm(Name, Type, Timer, [dns | Opts]) ->
- Res = inet_res:gethostbyname_tm(Name, Type, Timer),
- case Res of
- {ok,_} -> Res;
- {error,timeout} -> Res;
- {error,formerr} -> {error,einval};
- {error,_} -> gethostbyname_tm(Name,Type,Timer,Opts)
- end;
-gethostbyname_tm(Name, Type, Timer, [file | Opts]) ->
- case inet_hosts:gethostbyname(Name, Type) of
- {error,formerr} -> {error,einval};
- {error,_} -> gethostbyname_tm(Name,Type,Timer,Opts);
- Result -> Result
- end;
-gethostbyname_tm(Name, Type, Timer, [yp | Opts]) ->
+gethostbyname_tm(Name, Type, Timer, [string|_]=Opts) ->
+ Result = gethostbyname_string(Name, Type),
+ gethostbyname_tm(Name, Type, Timer, Opts, Result);
+gethostbyname_tm(Name, Type, Timer, [dns|_]=Opts) ->
+ Result = inet_res:gethostbyname_tm(Name, Type, Timer),
+ gethostbyname_tm(Name, Type, Timer, Opts, Result);
+gethostbyname_tm(Name, Type, Timer, [file|_]=Opts) ->
+ Result = inet_hosts:gethostbyname(Name, Type),
+ gethostbyname_tm(Name, Type, Timer, Opts, Result);
+gethostbyname_tm(Name, Type, Timer, [yp|_]=Opts) ->
gethostbyname_tm_native(Name, Type, Timer, Opts);
-gethostbyname_tm(Name, Type, Timer, [nis | Opts]) ->
+gethostbyname_tm(Name, Type, Timer, [nis|_]=Opts) ->
gethostbyname_tm_native(Name, Type, Timer, Opts);
-gethostbyname_tm(Name, Type, Timer, [nisplus | Opts]) ->
+gethostbyname_tm(Name, Type, Timer, [nisplus|_]=Opts) ->
gethostbyname_tm_native(Name, Type, Timer, Opts);
-gethostbyname_tm(Name, Type, Timer, [wins | Opts]) ->
+gethostbyname_tm(Name, Type, Timer, [wins|_]=Opts) ->
gethostbyname_tm_native(Name, Type, Timer, Opts);
-gethostbyname_tm(Name, Type, Timer, [native | Opts]) ->
+gethostbyname_tm(Name, Type, Timer, [native|_]=Opts) ->
gethostbyname_tm_native(Name, Type, Timer, Opts);
-gethostbyname_tm(_, _, _, [no_default|_]) ->
- %% If the native resolver has failed, we should not bother
- %% to try to be smarter and parse the IP address here.
- {error,nxdomain};
-gethostbyname_tm(Name, Type, Timer, [_ | Opts]) ->
+gethostbyname_tm(Name, Type, Timer, [_|_]=Opts) ->
gethostbyname_tm(Name, Type, Timer, Opts);
-%% Last resort - parse the hostname as address
-gethostbyname_tm(Name, inet, _Timer, []) ->
- case inet_parse:ipv4_address(Name) of
- {ok,IP4} ->
- {ok,make_hostent(Name, [IP4], [], inet)};
- _ ->
- gethostbyname_self(Name)
- end;
-gethostbyname_tm(Name, inet6, _Timer, []) ->
- case inet_parse:ipv6_address(Name) of
- {ok,IP6} ->
- {ok,make_hostent(Name, [IP6], [], inet6)};
- _ ->
- %% Even if Name is a valid IPv4 address, we can't
- %% assume it's correct to return it on a IPv6
- %% format ( {0,0,0,0,0,16#ffff,?u16(A,B),?u16(C,D)} ).
- %% This host might not support IPv6.
- gethostbyname_self(Name)
+%% Make sure we always can look up our own hostname.
+gethostbyname_tm(Name, Type, Timer, []) ->
+ Result = gethostbyname_self(Name, Type),
+ gethostbyname_tm(Name, Type, Timer, [], Result).
+
+gethostbyname_tm(Name, Type, Timer, Opts, Result) ->
+ case Result of
+ {ok,_} ->
+ Result;
+ {error,formerr} ->
+ {error,einval};
+ {error,_} when Opts =:= [] ->
+ {error,nxdomain};
+ {error,_} ->
+ gethostbyname_tm(Name, Type, Timer, tl(Opts))
end.
gethostbyname_tm_native(Name, Type, Timer, Opts) ->
%% Fixme: add (global) timeout to gethost_native
- case inet_gethost_native:gethostbyname(Name, Type) of
- {error,formerr} -> {error,einval};
- {error,timeout} -> {error,timeout};
- {error,_} -> gethostbyname_tm(Name, Type, Timer, Opts++[no_default]);
- Result -> Result
- end.
+ Result = inet_gethost_native:gethostbyname(Name, Type),
+ gethostbyname_tm(Name, Type, Timer, Opts, Result).
-%% Make sure we always can look up our own hostname.
-gethostbyname_self(Name) ->
- Type = case inet_db:res_option(inet6) of
- true -> inet6;
- false -> inet
- end,
+
+
+gethostbyname_self(Name, Type) when is_atom(Name) ->
+ gethostbyname_self(atom_to_list(Name), Type);
+gethostbyname_self(Name, Type)
+ when is_list(Name), Type =:= inet;
+ is_list(Name), Type =:= inet6 ->
case inet_db:gethostname() of
Name ->
- {ok,make_hostent(Name, [translate_ip(loopback, Type)],
- [], Type)};
+ {ok,make_hostent(Name,
+ [translate_ip(loopback, Type)],
+ [], Type)};
Self ->
case inet_db:res_option(domain) of
"" -> {error,nxdomain};
@@ -931,7 +928,31 @@ gethostbyname_self(Name) ->
_ -> {error,nxdomain}
end
end
- end.
+ end;
+gethostbyname_self(_, _) ->
+ {error,formerr}.
+
+gethostbyname_string(Name, Type) when is_atom(Name) ->
+ gethostbyname_string(atom_to_list(Name), Type);
+gethostbyname_string(Name, Type)
+ when is_list(Name), Type =:= inet;
+ is_list(Name), Type =:= inet6 ->
+ case
+ case Type of
+ inet ->
+ inet_parse:ipv4_address(Name);
+ inet6 ->
+ %% XXX should we really translate IPv4 addresses here
+ %% even if we do not know if this host can do IPv6?
+ inet_parse:ipv6_address(Name)
+ end of
+ {ok,IP} ->
+ {ok,make_hostent(Name, [IP], [], Type)};
+ {error,einval} ->
+ {error,nxdomain}
+ end;
+gethostbyname_string(_, _) ->
+ {error,formerr}.
make_hostent(Name, Addrs, Aliases, Type) ->
#hostent{h_name = Name,
diff --git a/lib/kernel/src/inet_config.erl b/lib/kernel/src/inet_config.erl
index b5317f72f5..311e6bc9f9 100644
--- a/lib/kernel/src/inet_config.erl
+++ b/lib/kernel/src/inet_config.erl
@@ -1,19 +1,19 @@
%%
%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1997-2009. All Rights Reserved.
-%%
+%%
+%% Copyright Ericsson AB 1997-2010. All Rights Reserved.
+%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
%% compliance with the License. You should have received a copy of the
%% Erlang Public License along with this software. If not, it can be
%% retrieved online at http://www.erlang.org/.
-%%
+%%
%% Software distributed under the License is distributed on an "AS IS"
%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
%% the License for the specific language governing rights and limitations
%% under the License.
-%%
+%%
%% %CopyrightEnd%
%%
-module(inet_config).
@@ -130,21 +130,25 @@ init() ->
{unix,_} ->
%% The Etc variable enables us to run tests with other
%% configuration files than the normal ones
- Etc = case os:getenv("ERL_INET_ETC_DIR") of
- false -> ?DEFAULT_ETC;
- _EtcDir ->
- _EtcDir
- end,
+ Etc =
+ case os:getenv("ERL_INET_ETC_DIR") of
+ false ->
+ ?DEFAULT_ETC;
+ _EtcDir ->
+ _EtcDir
+ end,
case inet_db:res_option(resolv_conf) of
undefined ->
- inet_db:set_resolv_conf(filename:join(Etc,
- ?DEFAULT_RESOLV));
+ inet_db:res_option(
+ resolv_conf_name,
+ filename:join(Etc, ?DEFAULT_RESOLV));
_ -> ok
end,
case inet_db:res_option(hosts_file) of
undefined ->
- inet_db:set_hosts_file(filename:join(Etc,
- ?DEFAULT_HOSTS));
+ inet_db:res_option(
+ hosts_file_name,
+ filename:join(Etc, ?DEFAULT_HOSTS));
_ -> ok
end;
_ -> ok
diff --git a/lib/kernel/src/inet_db.erl b/lib/kernel/src/inet_db.erl
index 211847014f..a05b380855 100644
--- a/lib/kernel/src/inet_db.erl
+++ b/lib/kernel/src/inet_db.erl
@@ -1,19 +1,19 @@
%%
%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1997-2009. All Rights Reserved.
-%%
+%%
+%% Copyright Ericsson AB 1997-2010. All Rights Reserved.
+%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
%% compliance with the License. You should have received a copy of the
%% Erlang Public License along with this software. If not, it can be
%% retrieved online at http://www.erlang.org/.
-%%
+%%
%% Software distributed under the License is distributed on an "AS IS"
%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
%% the License for the specific language governing rights and limitations
%% under the License.
-%%
+%%
%% %CopyrightEnd%
%%
@@ -425,7 +425,9 @@ res_optname(usevc) -> res_usevc;
res_optname(edns) -> res_edns;
res_optname(udp_payload_size) -> res_udp_payload_size;
res_optname(resolv_conf) -> res_resolv_conf;
+res_optname(resolv_conf_name) -> res_resolv_conf;
res_optname(hosts_file) -> res_hosts_file;
+res_optname(hosts_file_name) -> res_hosts_file;
res_optname(_) -> undefined.
res_check_option(nameserver, NSs) -> %% Legacy
@@ -458,9 +460,15 @@ res_check_option(udp_payload_size, S) when is_integer(S), S >= 512 -> true;
res_check_option(resolv_conf, "") -> true;
res_check_option(resolv_conf, F) ->
res_check_option_absfile(F);
+res_check_option(resolv_conf_name, "") -> true;
+res_check_option(resolv_conf_name, F) ->
+ res_check_option_absfile(F);
res_check_option(hosts_file, "") -> true;
res_check_option(hosts_file, F) ->
res_check_option_absfile(F);
+res_check_option(hosts_file_name, "") -> true;
+res_check_option(hosts_file_name, F) ->
+ res_check_option_absfile(F);
res_check_option(_, _) -> false.
res_check_option_absfile(F) ->
@@ -503,7 +511,7 @@ res_update_hosts() ->
res_update(res_hosts_file, res_hosts_file_tm, res_hosts_file_info,
set_hosts_file_tm, fun set_hosts_file/1).
-res_update(Tag, TagTm, TagInfo, CallTag, SetFun) ->
+res_update(Tag, TagTm, TagInfo, TagSetTm, SetFun) ->
case db_get(TagTm) of
undefined -> ok;
TM ->
@@ -522,12 +530,12 @@ res_update(Tag, TagTm, TagInfo, CallTag, SetFun) ->
atime = undefined},
case db_get(TagInfo) of
Finfo ->
- call({CallTag, Now});
+ call({TagSetTm, Now});
_ ->
SetFun(File)
end;
_ ->
- call({CallTag, Now}),
+ call({TagSetTm, Now}),
error
end
end;
@@ -974,37 +982,55 @@ handle_call(Request, From, #state{db=Db}=State) ->
{reply, error, State}
end;
+ {res_set, hosts_file_name=Option, Fname} ->
+ handle_set_file(
+ Option, Fname, res_hosts_file_tm, res_hosts_file_info,
+ undefined, From, State);
+ {res_set, resolv_conf_name=Option, Fname} ->
+ handle_set_file(
+ Option, Fname, res_resolv_conf_tm, res_resolv_conf_info,
+ undefined, From, State);
+
{res_set, hosts_file=Option, Fname} ->
- handle_set_file(Option, Fname,
- res_hosts_file_tm, res_hosts_file_info,
- fun (Bin) ->
- case inet_parse:hosts(Fname,
- {chars,Bin}) of
- {ok,Opts} ->
- [{load_hosts_file,Opts}];
- _ -> error
- end
- end,
- From, State);
+ handle_set_file(
+ Option, Fname, res_hosts_file_tm, res_hosts_file_info,
+ fun (Bin) ->
+ case inet_parse:hosts(
+ Fname, {chars,Bin}) of
+ {ok,Opts} ->
+ [{load_hosts_file,Opts}];
+ _ -> error
+ end
+ end,
+ From, State);
%%
{res_set, resolv_conf=Option, Fname} ->
- handle_set_file(Option, Fname,
- res_resolv_conf_tm, res_resolv_conf_info,
- fun (Bin) ->
- case inet_parse:resolv(Fname,
- {chars,Bin}) of
- {ok,Opts} ->
- [del_ns,
- clear_search,
- clear_cache
- |[Opt ||
- {T,_}=Opt <- Opts,
- (T =:= nameserver orelse
- T =:= search)]];
- _ -> error
- end
- end,
- From, State);
+ handle_set_file(
+ Option, Fname, res_resolv_conf_tm, res_resolv_conf_info,
+ fun (Bin) ->
+ case inet_parse:resolv(
+ Fname, {chars,Bin}) of
+ {ok,Opts} ->
+ Search =
+ lists:foldl(
+ fun ({search,L}, _) ->
+ L;
+ ({domain,""}, S) ->
+ S;
+ ({domain,D}, _) ->
+ [D];
+ (_, S) ->
+ S
+ end, [], Opts),
+ [del_ns,
+ clear_search,
+ clear_cache,
+ {search,Search}
+ |[Opt || {nameserver,_}=Opt <- Opts]];
+ _ -> error
+ end
+ end,
+ From, State);
%%
{res_set, Opt, Value} ->
case res_optname(Opt) of
@@ -1156,6 +1182,12 @@ handle_set_file(Option, Fname, TagTm, TagInfo, ParseFun, From,
ets:delete(Db, TagInfo),
ets:delete(Db, TagTm),
handle_set_file(ParseFun, <<>>, From, State);
+ true when ParseFun =:= undefined ->
+ File = filename:flatten(Fname),
+ ets:insert(Db, {res_optname(Option), File}),
+ ets:insert(Db, {TagInfo, undefined}),
+ ets:insert(Db, {TagTm, 0}),
+ {reply,ok,State};
true ->
File = filename:flatten(Fname),
ets:insert(Db, {res_optname(Option), File}),
@@ -1178,7 +1210,8 @@ handle_set_file(Option, Fname, TagTm, TagInfo, ParseFun, From,
handle_set_file(ParseFun, Bin, From, State) ->
case ParseFun(Bin) of
- error -> {reply,error,State};
+ error ->
+ {reply,error,State};
Opts ->
handle_rc_list(Opts, From, State)
end.
diff --git a/lib/kernel/src/inet_gethost_native.erl b/lib/kernel/src/inet_gethost_native.erl
index abdbe2b8cf..fabe9bf8b3 100644
--- a/lib/kernel/src/inet_gethost_native.erl
+++ b/lib/kernel/src/inet_gethost_native.erl
@@ -1,19 +1,19 @@
%%
%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1998-2009. All Rights Reserved.
-%%
+%%
+%% Copyright Ericsson AB 1998-2010. All Rights Reserved.
+%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
%% compliance with the License. You should have received a copy of the
%% Erlang Public License along with this software. If not, it can be
%% retrieved online at http://www.erlang.org/.
-%%
+%%
%% Software distributed under the License is distributed on an "AS IS"
%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
%% the License for the specific language governing rights and limitations
%% under the License.
-%%
+%%
%% %CopyrightEnd%
%%
-module(inet_gethost_native).
@@ -443,19 +443,23 @@ gethostbyname(Name) ->
gethostbyname(Name, inet).
gethostbyname(Name, inet) when is_list(Name) ->
- getit(?OP_GETHOSTBYNAME, ?PROTO_IPV4, Name);
+ getit(?OP_GETHOSTBYNAME, ?PROTO_IPV4, Name, Name);
gethostbyname(Name, inet6) when is_list(Name) ->
- getit(?OP_GETHOSTBYNAME, ?PROTO_IPV6, Name);
+ getit(?OP_GETHOSTBYNAME, ?PROTO_IPV6, Name, Name);
gethostbyname(Name, Type) when is_atom(Name) ->
gethostbyname(atom_to_list(Name), Type);
gethostbyname(_, _) ->
{error, formerr}.
-gethostbyaddr({A,B,C,D}) when ?VALID_V4(A), ?VALID_V4(B), ?VALID_V4(C), ?VALID_V4(D) ->
- getit(?OP_GETHOSTBYADDR, ?PROTO_IPV4, <<A,B,C,D>>);
-gethostbyaddr({A,B,C,D,E,F,G,H}) when ?VALID_V6(A), ?VALID_V6(B), ?VALID_V6(C), ?VALID_V6(D),
- ?VALID_V6(E), ?VALID_V6(F), ?VALID_V6(G), ?VALID_V6(H) ->
- getit(?OP_GETHOSTBYADDR, ?PROTO_IPV6, <<A:16,B:16,C:16,D:16,E:16,F:16,G:16,H:16>>);
+gethostbyaddr({A,B,C,D}=Addr)
+ when ?VALID_V4(A), ?VALID_V4(B), ?VALID_V4(C), ?VALID_V4(D) ->
+ getit(?OP_GETHOSTBYADDR, ?PROTO_IPV4, <<A,B,C,D>>, Addr);
+gethostbyaddr({A,B,C,D,E,F,G,H}=Addr)
+ when ?VALID_V6(A), ?VALID_V6(B), ?VALID_V6(C), ?VALID_V6(D),
+ ?VALID_V6(E), ?VALID_V6(F), ?VALID_V6(G), ?VALID_V6(H) ->
+ getit
+ (?OP_GETHOSTBYADDR, ?PROTO_IPV6,
+ <<A:16,B:16,C:16,D:16,E:16,F:16,G:16,H:16>>, Addr);
gethostbyaddr(Addr) when is_list(Addr) ->
case inet_parse:address(Addr) of
{ok, IP} -> gethostbyaddr(IP);
@@ -466,30 +470,30 @@ gethostbyaddr(Addr) when is_atom(Addr) ->
gethostbyaddr(_) -> {error, formerr}.
control({debug_level, Level}) when is_integer(Level) ->
- getit(?OP_CONTROL, ?SETOPT_DEBUG_LEVEL, <<Level:32>>);
+ getit(?OP_CONTROL, ?SETOPT_DEBUG_LEVEL, <<Level:32>>, undefined);
control(soft_restart) ->
- getit(restart_port);
+ getit(restart_port, undefined);
control(_) -> {error, formerr}.
-getit(Op, Proto, Data) ->
- getit({Op, Proto, Data}).
+getit(Op, Proto, Data, DefaultName) ->
+ getit({Op, Proto, Data}, DefaultName).
-getit(Req) ->
+getit(Req, DefaultName) ->
Pid = ensure_started(),
Ref = make_ref(),
Pid ! {{self(),Ref}, Req},
receive
{Ref, {ok,BinHostent}} ->
- parse_address(BinHostent);
- {Ref, Error} ->
- Error
+ parse_address(BinHostent, DefaultName);
+ {Ref, Result} ->
+ Result
after 5000 ->
Ref2 = erlang:monitor(process,Pid),
Res2 = receive
{Ref, {ok,BinHostent}} ->
- parse_address(BinHostent);
- {Ref, Error} ->
- Error;
+ parse_address(BinHostent, DefaultName);
+ {Ref, Result} ->
+ Result;
{'DOWN', Ref2, process,
Pid, Reason} ->
{error, Reason}
@@ -546,21 +550,23 @@ ensure_started() ->
Pid
end.
-parse_address(BinHostent) ->
+parse_address(BinHostent, DefaultName) ->
case catch
begin
case BinHostent of
<<?UNIT_ERROR, Errstring/binary>> ->
{error, list_to_atom(listify(Errstring))};
<<?UNIT_IPV4, Naddr:32, T0/binary>> ->
- {T1,Addresses} = pick_addresses_v4(Naddr, T0),
- [Name | Names] = pick_names(T1),
+ {T1, Addresses} = pick_addresses_v4(Naddr, T0),
+ {Name, Names} =
+ expand_default_name(pick_names(T1), DefaultName),
{ok, #hostent{h_addr_list = Addresses, h_addrtype = inet,
h_aliases = Names, h_length = ?UNIT_IPV4,
h_name = Name}};
<<?UNIT_IPV6, Naddr:32, T0/binary>> ->
- {T1,Addresses} = pick_addresses_v6(Naddr, T0),
- [Name | Names] = pick_names(T1),
+ {T1, Addresses} = pick_addresses_v6(Naddr, T0),
+ {Name, Names} =
+ expand_default_name(pick_names(T1), DefaultName),
{ok, #hostent{h_addr_list = Addresses, h_addrtype = inet6,
h_aliases = Names, h_length = ?UNIT_IPV6,
h_name = Name}};
@@ -573,7 +579,15 @@ parse_address(BinHostent) ->
Normal ->
Normal
end.
-
+
+expand_default_name([], DefaultName) when is_list(DefaultName) ->
+ {DefaultName, []};
+expand_default_name([], DefaultName) when is_tuple(DefaultName) ->
+ {inet_parse:ntoa(DefaultName), []};
+expand_default_name([Name|Names], DefaultName)
+ when is_list(DefaultName); is_tuple(DefaultName) ->
+ {Name, Names}.
+
listify(Bin) ->
N = byte_size(Bin) - 1,
<<Bin2:N/binary, Ch>> = Bin,
diff --git a/lib/kernel/src/inet_parse.erl b/lib/kernel/src/inet_parse.erl
index 62d44fb723..3bd5fa0958 100644
--- a/lib/kernel/src/inet_parse.erl
+++ b/lib/kernel/src/inet_parse.erl
@@ -1,19 +1,19 @@
%%
%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1997-2009. All Rights Reserved.
-%%
+%%
+%% Copyright Ericsson AB 1997-2010. All Rights Reserved.
+%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
%% compliance with the License. You should have received a copy of the
%% Erlang Public License along with this software. If not, it can be
%% retrieved online at http://www.erlang.org/.
-%%
+%%
%% Software distributed under the License is distributed on an "AS IS"
%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
%% the License for the specific language governing rights and limitations
%% under the License.
-%%
+%%
%% %CopyrightEnd%
%%
-module(inet_parse).
@@ -34,6 +34,7 @@
-export([nsswitch_conf/1, nsswitch_conf/2]).
-export([ipv4_address/1, ipv6_address/1]).
+-export([ipv4strict_address/1, ipv6strict_address/1]).
-export([address/1]).
-export([visible_string/1, domain/1]).
-export([ntoa/1, dots/1]).
@@ -456,17 +457,15 @@ is_dom2(_) ->
%%
-%% Test ipv4 address or ipv6 address
+%% Parse ipv4 address or ipv6 address
%% Return {ok, Address} | {error, Reason}
%%
address(Cs) when is_list(Cs) ->
case ipv4_address(Cs) of
- {ok,IP} -> {ok,IP};
+ {ok,IP} ->
+ {ok,IP};
_ ->
- case ipv6_address(Cs) of
- {ok, IP} -> {ok, IP};
- Error -> Error
- end
+ ipv6strict_address(Cs)
end;
address(_) ->
{error, einval}.
@@ -477,49 +476,145 @@ address(_) ->
%% d1.d2.d4
%% d1.d4
%% d4
+%% Any d may be octal, hexadecimal or decimal by C language standards.
+%% d4 fills all LSB bytes. This is legacy behaviour from Solaris
+%% and FreeBSD. And partly Linux that behave the same except
+%% it does not accept hexadecimal.
%%
%% Return {ok, IP} | {error, einval}
%%
ipv4_address(Cs) ->
- case catch ipv4_addr(Cs) of
- {'EXIT',_} -> {error,einval};
- Addr -> {ok,Addr}
+ try ipv4_addr(Cs) of
+ Addr ->
+ {ok,Addr}
+ catch
+ error:badarg ->
+ {error,einval}
end.
-ipv4_addr(Cs) ->
- ipv4_addr(d3(Cs), []).
+ipv4_addr(Cs) ->
+ case ipv4_addr(Cs, []) of
+ [D] when D < (1 bsl 32) ->
+ <<D1,D2,D3,D4>> = <<D:32>>,
+ {D1,D2,D3,D4};
+ [D,D1] when D < (1 bsl 24), D1 < 256 ->
+ <<D2,D3,D4>> = <<D:24>>,
+ {D1,D2,D3,D4};
+ [D,D2,D1] when D < (1 bsl 16), (D2 bor D1) < 256 ->
+ <<D3,D4>> = <<D:16>>,
+ {D1,D2,D3,D4};
+ [D4,D3,D2,D1] when (D4 bor D3 bor D2 bor D1) < 256 ->
+ {D1,D2,D3,D4};
+ _ ->
+ erlang:error(badarg)
+ end.
-ipv4_addr({Cs0,[]}, A) when length(A) =< 3 ->
- case [tod(Cs0)|A] of
- [D4,D3,D2,D1] ->
+ipv4_addr([_|_], [_,_,_,_]) ->
+ %% Early bailout for extra characters
+ erlang:error(badarg);
+ipv4_addr("0x"++Cs, Ds) ->
+ ipv4_addr(strip0(Cs), Ds, [], 16, 8);
+ipv4_addr("0X"++Cs, Ds) ->
+ ipv4_addr(strip0(Cs), Ds, [], 16, 8);
+ipv4_addr("0"++Cs, Ds) ->
+ ipv4_addr(strip0(Cs), Ds, [$0], 8, 11);
+ipv4_addr(Cs, Ds) when is_list(Cs) ->
+ ipv4_addr(Cs, Ds, [], 10, 10).
+
+ipv4_addr(Cs0, Ds, Rs, Base, N) ->
+ case ipv4_field(Cs0, N, Rs, Base) of
+ {D,""} ->
+ [D|Ds];
+ {D,[$.|[_|_]=Cs]} ->
+ ipv4_addr(Cs, [D|Ds]);
+ {_,_} ->
+ erlang:error(badarg)
+ end.
+
+strip0("0"++Cs) ->
+ strip0(Cs);
+strip0(Cs) when is_list(Cs) ->
+ Cs.
+
+
+%%
+%% Parse IPv4 strict dotted decimal address, no leading zeros:
+%% d1.d2.d3.d4
+%%
+%% Return {ok, IP} | {error, einval}
+%%
+ipv4strict_address(Cs) ->
+ try ipv4strict_addr(Cs) of
+ Addr ->
+ {ok,Addr}
+ catch
+ error:badarg ->
+ {error,einval}
+ end.
+
+ipv4strict_addr(Cs) ->
+ case ipv4strict_addr(Cs, []) of
+ [D4,D3,D2,D1] when (D4 bor D3 bor D2 bor D1) < 256 ->
{D1,D2,D3,D4};
- [D4,D2,D1] ->
- {D1,D2,0,D4};
- [D4,D1] ->
- {D1,0,0,D4};
- [D4] ->
- {0,0,0,D4}
- end;
-ipv4_addr({Cs0,"."++Cs1}, A) when length(A) =< 2 ->
- ipv4_addr(d3(Cs1), [tod(Cs0)|A]).
+ _ ->
+ erlang:error(badarg)
+ end.
+
+ipv4strict_addr([_|_], [_,_,_,_]) ->
+ %% Early bailout for extra characters
+ erlang:error(badarg);
+ipv4strict_addr("0", Ds) ->
+ [0|Ds];
+ipv4strict_addr("0."++Cs, Ds) ->
+ ipv4strict_addr(Cs, [0|Ds]);
+ipv4strict_addr(Cs0, Ds) when is_list(Cs0) ->
+ case ipv4_field(Cs0, 3, [], 10) of
+ {D,""} ->
+ [D|Ds];
+ {D,[$.|[_|_]=Cs]} ->
+ ipv4strict_addr(Cs, [D|Ds]);
+ {_,_} ->
+ erlang:error(badarg)
+ end.
+
-d3(Cs) -> d3(Cs, []).
-d3([C|Cs], R) when C >= $0, C =< $9, length(R) =< 2 ->
- d3(Cs, [C|R]);
-d3(Cs, [_|_]=R) ->
- {lists:reverse(R),Cs}.
+ipv4_field("", _, Rs, Base) ->
+ {ipv4_field(Rs, Base),""};
+ipv4_field("."++_=Cs, _, Rs, Base) ->
+ {ipv4_field(Rs, Base),Cs};
+ipv4_field("0"++_, _, [], _) ->
+ erlang:error(badarg);
+ipv4_field([C|Cs], N, Rs, Base) when N > 0 ->
+ ipv4_field(Cs, N-1, [C|Rs], Base);
+ipv4_field(Cs, _, _, _) when is_list(Cs) ->
+ erlang:error(badarg).
+
+ipv4_field(Rs, Base) ->
+ V = erlang:list_to_integer(lists:reverse(Rs), Base),
+ if V < 0 ->
+ erlang:error(badarg);
+ true ->
+ V
+ end.
-tod(Cs) ->
- case erlang:list_to_integer(Cs) of
- D when D >= 0, D =< 255 ->
- D;
+
+
+%%
+%% Forgiving IPv6 address
+%%
+%% Accepts IPv4 address and returns it as a IPv4 compatible IPv6 address
+%%
+ipv6_address(Cs) ->
+ case ipv4_address(Cs) of
+ {ok,{D1,D2,D3,D4}} ->
+ {ok,{0,0,0,0,0,16#ffff,(D1 bsl 8) bor D2,(D3 bsl 8) bor D4}};
_ ->
- erlang:error(badarg, [Cs])
+ ipv6strict_address(Cs)
end.
%%
-%% Parse IPv6 address:
+%% Parse IPv6 address according to RFC 4291:
%% x1:x2:x3:x4:x5:x6:x7:x8
%% x1:x2::x7:x8
%% ::x7:x8
@@ -530,77 +625,89 @@ tod(Cs) ->
%% ::x5:x6:d7a.d7b.d8a.d8b
%% x1:x2::d7a.d7b.d8a.d8b
%% ::d7a.d7b.d8a.d8b
+%% etc
%%
%% Return {ok, IP} | {error, einval}
%%
-ipv6_address(Cs) ->
- case catch ipv6_addr(Cs) of
- {'EXIT',_} -> {error,einval};
- Addr -> {ok,Addr}
+ipv6strict_address(Cs) ->
+ try ipv6_addr(Cs) of
+ Addr ->
+ {ok,Addr}
+ catch
+ error:badarg ->
+ {error,einval}
end.
ipv6_addr("::") ->
- ipv6_addr_done([], []);
+ ipv6_addr_done([], [], 0);
ipv6_addr("::"++Cs) ->
- ipv6_addr(x4(Cs), [], []);
+ ipv6_addr(hex(Cs), [], [], 0);
ipv6_addr(Cs) ->
- ipv6_addr(x4(Cs), []).
+ ipv6_addr(hex(Cs), [], 0).
%% Before "::"
-ipv6_addr({Cs0,[]}, A) when length(A) =:= 7 ->
- ipv6_addr_done([tox(Cs0)|A]);
-ipv6_addr({Cs0,"::"}, A) when length(A) =< 6 ->
- ipv6_addr_done([tox(Cs0)|A], []);
-ipv6_addr({Cs0,"::"++Cs1}, A) when length(A) =< 5 ->
- ipv6_addr(x4(Cs1), [tox(Cs0)|A], []);
-ipv6_addr({Cs0,":"++Cs1}, A) when length(A) =< 6 ->
- ipv6_addr(x4(Cs1), [tox(Cs0)|A]);
-ipv6_addr({Cs0,"."++Cs1}, A) when length(A) =:= 6 ->
- ipv6_addr(d3(Cs1), A, [], [tod(Cs0)]).
+ipv6_addr({Cs0,[]}, A, N) when N == 7 ->
+ ipv6_addr_done([hex_to_int(Cs0)|A]);
+ipv6_addr({Cs0,"::"}, A, N) when N =< 6 ->
+ ipv6_addr_done([hex_to_int(Cs0)|A], [], N+1);
+ipv6_addr({Cs0,"::"++Cs1}, A, N) when N =< 5 ->
+ ipv6_addr(hex(Cs1), [hex_to_int(Cs0)|A], [], N+1);
+ipv6_addr({Cs0,":"++Cs1}, A, N) when N =< 6 ->
+ ipv6_addr(hex(Cs1), [hex_to_int(Cs0)|A], N+1);
+ipv6_addr({Cs0,"."++_=Cs1}, A, N) when N == 6 ->
+ ipv6_addr_done(A, [], N, ipv4strict_addr(Cs0++Cs1));
+ipv6_addr(_, _, _) ->
+ erlang:error(badarg).
%% After "::"
-ipv6_addr({Cs0,[]}, A, B) when length(A)+length(B) =< 6 ->
- ipv6_addr_done(A, [tox(Cs0)|B]);
-ipv6_addr({Cs0,":"++Cs1}, A, B) when length(A)+length(B) =< 5 ->
- ipv6_addr(x4(Cs1), A, [tox(Cs0)|B]);
-ipv6_addr({Cs0,"."++Cs1}, A, B) when length(A)+length(B) =< 5 ->
- ipv6_addr(x4(Cs1), A, B, [tod(Cs0)]).
+ipv6_addr({Cs0,[]}, A, B, N) when N =< 6 ->
+ ipv6_addr_done(A, [hex_to_int(Cs0)|B], N+1);
+ipv6_addr({Cs0,":"++Cs1}, A, B, N) when N =< 5 ->
+ ipv6_addr(hex(Cs1), A, [hex_to_int(Cs0)|B], N+1);
+ipv6_addr({Cs0,"."++_=Cs1}, A, B, N) when N =< 5 ->
+ ipv6_addr_done(A, B, N, ipv4strict_addr(Cs0++Cs1));
+ipv6_addr(_, _, _, _) ->
+ erlang:error(badarg).
-%% After "."
-ipv6_addr({Cs0,[]}, A, B, C) when length(C) =:= 3 ->
- ipv6_addr_done(A, B, [tod(Cs0)|C]);
-ipv6_addr({Cs0,"."++Cs1}, A, B, C) when length(C) =< 2 ->
- ipv6_addr(d3(Cs1), A, B, [tod(Cs0)|C]).
+ipv6_addr_done(Ar, Br, N, {D1,D2,D3,D4}) ->
+ ipv6_addr_done(Ar, [((D3 bsl 8) bor D4),((D1 bsl 8) bor D2)|Br], N+2).
-ipv6_addr_done(Ar, Br, [D4,D3,D2,D1]) ->
- ipv6_addr_done(Ar, [((D3 bsl 8) bor D4),((D1 bsl 8) bor D2)|Br]).
-
-ipv6_addr_done(Ar, Br) ->
- ipv6_addr_done(Br++dup(8-length(Ar)-length(Br), 0, Ar)).
+ipv6_addr_done(Ar, Br, N) ->
+ ipv6_addr_done(Br++dup(8-N, 0, Ar)).
ipv6_addr_done(Ar) ->
list_to_tuple(lists:reverse(Ar)).
-x4(Cs) -> x4(Cs, []).
-
-x4([C|Cs], R) when C >= $0, C =< $9, length(R) =< 3 ->
- x4(Cs, [C|R]);
-x4([C|Cs], R) when C >= $a, C =< $f, length(R) =< 3 ->
- x4(Cs, [C|R]);
-x4([C|Cs], R) when C >= $A, C =< $F, length(R) =< 3 ->
- x4(Cs, [C|R]);
-x4(Cs, [_|_]=R) ->
- {lists:reverse(R),Cs}.
-
-tox(Cs) ->
- erlang:list_to_integer(Cs, 16).
+%% Collect Hex digits
+hex(Cs) -> hex(Cs, []).
+%%
+hex([C|Cs], R) when C >= $0, C =< $9 ->
+ hex(Cs, [C|R]);
+hex([C|Cs], R) when C >= $a, C =< $f ->
+ hex(Cs, [C|R]);
+hex([C|Cs], R) when C >= $A, C =< $F ->
+ hex(Cs, [C|R]);
+hex(Cs, [_|_]=R) when is_list(Cs) ->
+ {lists:reverse(R),Cs};
+hex(_, _) ->
+ erlang:error(badarg).
+
+%% Hex string to integer
+hex_to_int(Cs0) ->
+ case strip0(Cs0) of
+ Cs when length(Cs) =< 4 ->
+ erlang:list_to_integer("0"++Cs, 16);
+ _ ->
+ erlang:error(badarg)
+ end.
+%% Dup onto head of existing list
dup(0, _, L) ->
L;
dup(N, E, L) when is_integer(N), N >= 1 ->
- dup(N-1, E, [E|L]);
-dup(N, E, L) ->
- erlang:error(badarg, [N,E,L]).
+ dup(N-1, E, [E|L]).
+
+
%% Convert IPv4 adress to ascii
%% Convert IPv6 / IPV4 adress to ascii (plain format)
@@ -674,7 +781,7 @@ separate(_E, [H], R) ->
lists:reverse(R, [H]).
%% convert to A.B decimal form
-dig_to_dec(0) -> [$0,$.,$0];
+dig_to_dec(0) -> "0.0";
dig_to_dec(X) ->
integer_to_list((X bsr 8) band 16#ff) ++ "." ++
integer_to_list(X band 16#ff).
diff --git a/lib/kernel/test/inet_SUITE.erl b/lib/kernel/test/inet_SUITE.erl
index cf33e8b27f..eb8f918491 100644
--- a/lib/kernel/test/inet_SUITE.erl
+++ b/lib/kernel/test/inet_SUITE.erl
@@ -1,19 +1,19 @@
%%
%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1997-2009. All Rights Reserved.
-%%
+%%
+%% Copyright Ericsson AB 1997-2010. All Rights Reserved.
+%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
%% compliance with the License. You should have received a copy of the
%% Erlang Public License along with this software. If not, it can be
%% retrieved online at http://www.erlang.org/.
-%%
+%%
%% Software distributed under the License is distributed on an "AS IS"
%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
%% the License for the specific language governing rights and limitations
%% under the License.
-%%
+%%
%% %CopyrightEnd%
%%
-module(inet_SUITE).
@@ -28,7 +28,7 @@
gethostnative_parallell/1, cname_loop/1,
gethostnative_soft_restart/1,gethostnative_debug_level/1,getif/1]).
--export([get_hosts/1, get_ipv6_hosts/1, parse_hosts/1,
+-export([get_hosts/1, get_ipv6_hosts/1, parse_hosts/1, parse_address/1,
kill_gethost/0, parallell_gethost/0]).
-export([init_per_testcase/2, end_per_testcase/2]).
@@ -249,14 +249,16 @@ t_getaddr_v6(Config) when is_list(Config) ->
?line {ok,IP46} = inet:getaddr(IP46, inet6),
?line {ok,IP46} = inet:getaddr(Name, inet6),
?line {ok,IP46} = inet:getaddr(FullName, inet6),
- ?line IP4toIP6 = inet:getaddr(IPStr, inet6),
- ?line case IP4toIP6 of
- {ok,IP46} -> % only native can do this
- ?line true = lists:member(native,
- inet_db:res_option(lookup));
- {error,nxdomain} ->
- ok
- end,
+ ?line {ok,IP46} = inet:getaddr(IPStr, inet6),
+%% ?line IP4toIP6 = inet:getaddr(IPStr, inet6),
+%% ?line case IP4toIP6 of
+%% {ok,IP46} ->
+%% ?line ok;
+%% {error,nxdomain} ->
+%% ?line false =
+%% lists:member(native,
+%% inet_db:res_option(lookup))
+%% end,
?line {Name6, FullName6, IPStr6, IP6, _} =
?config(test_host_ipv6_only, Config),
?line {ok,_} = inet:getaddr(list_to_atom(Name6), inet6),
@@ -301,7 +303,6 @@ ipv4_to_ipv6(Config) when is_list(Config) ->
end,
?line case {IP4to6Res,inet:gethostbyname(IPStr, inet6)} of
{true,{ok,HEnt}} ->
- ?line true = lists:member(native, inet_db:res_option(lookup)),
?line HEnt_ = HEnt#hostent{h_addrtype = inet6,
h_length = 16,
h_addr_list = [IP_46]},
@@ -374,9 +375,10 @@ get_hosts([C|Rest], Cur, Ip, Result) ->
get_hosts([], _, _, Result) ->
Result.
-parse(suite) -> [parse_hosts];
+parse(suite) -> [parse_hosts, parse_address];
parse(doc) -> ["Test that parsing of the hosts file or equivalent works,",
"and that erroneous lines are skipped"].
+
parse_hosts(Config) when is_list(Config) ->
?line DataDir = ?config(data_dir,Config),
?line HostFile = filename:join(DataDir, "hosts"),
@@ -388,6 +390,170 @@ parse_hosts(Config) when is_list(Config) ->
?line ResolvErr1 = filename:join(DataDir,"resolv.conf.err1"),
?line inet_parse:resolv(ResolvErr1).
+parse_address(Config) when is_list(Config) ->
+ V4Strict =
+ [{{0,0,0,0},"0.0.0.0"},
+ {{1,2,3,4},"1.2.3.4"},
+ {{253,252,251,250},"253.252.251.250"},
+ {{1,2,255,254},"1.2.255.254"}],
+ V6Strict =
+ [{{0,0,0,0,0,0,0,0},"::"},
+ {{15,0,0,0,0,0,0,2},"f::2"},
+ {{15,16#f11,0,0,0,0,256,2},"f:f11::0100:2"},
+ {{0,0,0,0,0,0,0,16#17},"::17"},
+ {{16#700,0,0,0,0,0,0,0},"0700::"},
+ {{0,0,0,0,0,0,2,1},"::2:1"},
+ {{0,0,0,0,0,3,2,1},"::3:2:1"},
+ {{0,0,0,0,4,3,2,1},"::4:3:2:1"},
+ {{0,0,0,5,4,3,2,1},"::5:4:3:2:1"},
+ {{0,0,6,5,4,3,2,1},"::6:5:4:3:2:1"},
+ {{0,7,6,5,4,3,2,1},"::7:6:5:4:3:2:1"},
+ {{7,0,0,0,0,0,0,0},"7::"},
+ {{7,6,0,0,0,0,0,0},"7:6::"},
+ {{7,6,5,0,0,0,0,0},"7:6:5::"},
+ {{7,6,5,4,0,0,0,0},"7:6:5:4::"},
+ {{7,6,5,4,3,0,0,0},"7:6:5:4:3::"},
+ {{7,6,5,4,3,2,0,0},"7:6:5:4:3:2::"},
+ {{7,6,5,4,3,2,1,0},"7:6:5:4:3:2:1::"},
+ {{16#c11,16#c22,16#5c33,16#c440,16#55c0,16#c66c,16#77,16#88},
+ "c11:0c22:5c33:c440:55c0:c66c:77:0088"},
+ {{16#c11,0,16#5c33,16#c440,16#55c0,16#c66c,16#77,16#88},
+ "c11::5c33:c440:55c0:c66c:77:0088"},
+ {{16#c11,16#c22,0,16#c440,16#55c0,16#c66c,16#77,16#88},
+ "c11:0c22::c440:55c0:c66c:77:0088"},
+ {{16#c11,16#c22,16#5c33,0,16#55c0,16#c66c,16#77,16#88},
+ "c11:0c22:5c33::55c0:c66c:77:0088"},
+ {{16#c11,16#c22,16#5c33,16#c440,0,16#c66c,16#77,16#88},
+ "c11:0c22:5c33:c440::c66c:77:0088"},
+ {{16#c11,16#c22,16#5c33,16#c440,16#55c0,0,16#77,16#88},
+ "c11:0c22:5c33:c440:55c0::77:0088"},
+ {{16#c11,16#c22,16#5c33,16#c440,16#55c0,16#c66c,0,16#88},
+ "c11:0c22:5c33:c440:55c0:c66c::0088"},
+ {{16#c11,0,0,16#c440,16#55c0,16#c66c,16#77,16#88},
+ "c11::c440:55c0:c66c:77:0088"},
+ {{16#c11,16#c22,0,0,16#55c0,16#c66c,16#77,16#88},
+ "c11:0c22::55c0:c66c:77:0088"},
+ {{16#c11,16#c22,16#5c33,0,0,16#c66c,16#77,16#88},
+ "c11:0c22:5c33::c66c:77:0088"},
+ {{16#c11,16#c22,16#5c33,16#c440,0,0,16#77,16#88},
+ "c11:0c22:5c33:c440::77:0088"},
+ {{16#c11,16#c22,16#5c33,16#c440,16#55c0,0,0,16#88},
+ "c11:0c22:5c33:c440:55c0::0088"},
+ {{16#c11,0,0,0,16#55c0,16#c66c,16#77,16#88},
+ "c11::55c0:c66c:77:0088"},
+ {{16#c11,16#c22,0,0,0,16#c66c,16#77,16#88},
+ "c11:0c22::c66c:77:0088"},
+ {{16#c11,16#c22,16#5c33,0,0,0,16#77,16#88},
+ "c11:0c22:5c33::77:0088"},
+ {{16#c11,16#c22,16#5c33,16#c440,0,0,0,16#88},
+ "c11:0c22:5c33:c440::0088"},
+ {{16#c11,0,0,0,0,16#c66c,16#77,16#88},
+ "c11::c66c:77:0088"},
+ {{16#c11,16#c22,0,0,0,0,16#77,16#88},
+ "c11:0c22::77:0088"},
+ {{16#c11,16#c22,16#5c33,0,0,0,0,16#88},
+ "c11:0c22:5c33::0088"},
+ {{16#c11,0,0,0,0,0,16#77,16#88},
+ "c11::77:0088"},
+ {{16#c11,16#c22,0,0,0,0,0,16#88},
+ "c11:0c22::0088"},
+ {{0,0,0,0,0,65535,258,65534},"::FFFF:1.2.255.254"},
+ {{16#ffff,16#ffff,16#ffff,16#ffff,16#ffff,16#ffff,16#ffff,16#ffff},
+ "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff"}
+ |[{{D2,0,0,0,0,P,(D1 bsl 8) bor D2,(D3 bsl 8) bor D4},
+ erlang:integer_to_list(D2, 16)++"::"++Q++S}
+ || {{D1,D2,D3,D4},S} <- V4Strict,
+ {P,Q} <- [{0,""},{16#17,"17:"},{16#ff0,"0ff0:"}]]],
+ V4Sloppy =
+ [{{10,1,16#98,16#76},"10.0x019876"},
+ {{8#12,1,8#130,8#321},"012.01.054321"},
+ {{255,255,255,255},"255.255.255.0377"},
+ {{255,255,255,255},"0Xff.000000000377.0x0000ff.255"},
+ {{255,255,255,255},"255.255.65535"},
+ {{255,255,255,255},"255.0xFF.0177777"},
+ {{255,255,255,255},"255.16777215"},
+ {{255,255,255,255},"00377.0XFFFFFF"},
+ {{255,255,255,255},"4294967295"},
+ {{255,255,255,255},"0xffffffff"},
+ {{255,255,255,255},"00000000000037777777777"},
+ {{16#12,16#34,16#56,16#78},"0x12345678"},
+ {{16#12,16#34,16#56,16#78},"0x12.0x345678"},
+ {{16#12,16#34,16#56,16#78},"0x12.0X34.0x5678"},
+ {{16#12,16#34,16#56,16#78},"0x12.0X34.0x56.0X78"},
+ {{0,0,0,0},"0"},
+ {{0,0,0,0},"00"},
+ {{0,0,0,0},"0.0"},
+ {{0,0,0,0},"00.00.00"},
+ {{0,0,0,0},"0.00.0.0"},
+ {{0,0,0,0},"0.0.000000000000.0"}],
+ V6Sloppy =
+ [{{0,0,0,0,0,65535,(D1 bsl 8) bor D2,(D3 bsl 8) bor D4},S}
+ || {{D1,D2,D3,D4},S} <- V4Strict++V4Sloppy],
+ V4Err =
+ ["0.256.0.1",
+ "1.2.3.4.5",
+ "256.255.65535",
+ "4294967296",
+ "0x100000000",
+ "040000000000",
+ "1.2.3.-4",
+ "1.2.-3.4",
+ "1.-2.3.4",
+ "-1.2.3.4",
+ "10.",
+ "172.16.",
+ "198.168.0.",
+ "127.0.0.1."],
+ V6Err =
+ [":::",
+ "f:::2",
+ "::-1",
+ "::g",
+ "f:f11::10100:2",
+ "::17000",
+ "10000::",
+ "::8:7:6:5:4:3:2:1",
+ "8:7:6:5:4:3:2:1::",
+ "8:7:6:5:4::3:2:1",
+ "::1.2.3.4.5",
+ "::1.2.3.04",
+ "::1.256.3.4",
+ "::-5.4.3.2",
+ "::5.-4.3.2",
+ "::5.4.-3.2",
+ "::5.4.3.-2",
+ "::FFFF:1.2.3.4.5",
+ "::10.",
+ "::FFFF:172.16.",
+ "fe80::198.168.0.",
+ "fec0::fFfF:127.0.0.1."],
+ t_parse_address
+ (ipv6_address,
+ V6Strict++V6Sloppy++V6Err++V4Err),
+ t_parse_address
+ (ipv6strict_address,
+ V6Strict++V6Err++V4Err++[S || {_,S} <- V6Sloppy]),
+ t_parse_address
+ (ipv4_address,
+ V4Strict++V4Sloppy++V4Err++V6Err++[S || {_,S} <- V6Strict]),
+ t_parse_address
+ (ipv4strict_address,
+ V4Strict++V4Err++V6Err++[S || {_,S} <- V4Sloppy++V6Strict]).
+
+t_parse_address(Func, []) ->
+ io:format("~p done.~n", [Func]),
+ ok;
+t_parse_address(Func, [{Addr,String}|L]) ->
+ io:format("~p = ~p.~n", [Addr,String]),
+ {ok,Addr} = inet_parse:Func(String),
+ t_parse_address(Func, L);
+t_parse_address(Func, [String|L]) ->
+ io:format("~p.~n", [String]),
+ {error,einval} = inet_parse:Func(String),
+ t_parse_address(Func, L).
+
+
+
t_gethostnative(suite) ->[];
t_gethostnative(doc) ->[];
t_gethostnative(Config) when is_list(Config) ->
diff --git a/lib/kernel/test/inet_res_SUITE.erl b/lib/kernel/test/inet_res_SUITE.erl
index 659cfc5988..cc32d1f8f9 100644
--- a/lib/kernel/test/inet_res_SUITE.erl
+++ b/lib/kernel/test/inet_res_SUITE.erl
@@ -1,19 +1,19 @@
%%
%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2009. All Rights Reserved.
-%%
+%%
+%% Copyright Ericsson AB 2009-2010. All Rights Reserved.
+%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
%% compliance with the License. You should have received a copy of the
%% Erlang Public License along with this software. If not, it can be
%% retrieved online at http://www.erlang.org/.
-%%
+%%
%% Software distributed under the License is distributed on an "AS IS"
%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
%% the License for the specific language governing rights and limitations
%% under the License.
-%%
+%%
%% %CopyrightEnd%
%%
-module(inet_res_SUITE).
@@ -239,16 +239,37 @@ resolve(_Opts, []) -> ok;
resolve(Opts, [{Class,Type,Name,Answers,Authority}=Q|Qs]) ->
io:format("Query: ~p~nOptions: ~p~n", [Q,Opts]),
{ok,Msg} = inet_res:resolve(Name, Class, Type, Opts),
- if Answers =/= undefined ->
- AnList = lists:sort(Answers),
- AnList = lists:sort([inet_dns:rr(RR, data) ||
- RR <- inet_dns:msg(Msg, anlist)]);
- true -> ok end,
- if Authority =/= undefined ->
- NsList = lists:sort(Authority),
- NsList = lists:sort([inet_dns:rr(RR, data) ||
- RR <- inet_dns:msg(Msg, nslist)]);
- true -> ok end,
+ AnList =
+ if
+ Answers =/= undefined ->
+ lists:sort(Answers);
+ true ->
+ undefined
+ end,
+ NsList =
+ if
+ Authority =/= undefined ->
+ lists:sort(Authority);
+ true ->
+ undefined
+ end,
+ case {lists:sort
+ ([inet_dns:rr(RR, data) || RR <- inet_dns:msg(Msg, anlist)]),
+ lists:sort
+ ([inet_dns:rr(RR, data) || RR <- inet_dns:msg(Msg, nslist)])} of
+ {AnList,NsList} ->
+ ok;
+ {NsList,AnList} when Type =:= ns ->
+ %% This whole case statement is kind of inside out just
+ %% to accept this case when some legacy DNS resolvers
+ %% return the answer to a NS query in the answer section
+ %% instead of in the authority section.
+ ok;
+ {AnList,_} when NsList =:= undefined ->
+ ok;
+ {_,NsList} when AnList =:= undefined ->
+ ok
+ end,
Buf = inet_dns:encode(Msg),
{ok,Msg} = inet_dns:decode(Buf),
resolve(Opts, Qs).
@@ -292,10 +313,23 @@ edns0(Config) when is_list(Config) ->
MXs = lists:sort(inet_res_filter(inet_dns:msg(Msg2, anlist), in, mx)),
Buf2 = inet_dns:encode(Msg2),
{ok,Msg2} = inet_dns:decode(Buf2),
- [OptRR] = [RR || RR <- inet_dns:msg(Msg2, arlist),
- inet_dns:rr(RR, type) =:= opt],
- io:format("~p~n", [inet_dns:rr(OptRR)]),
- ok.
+ case [RR || RR <- inet_dns:msg(Msg2, arlist),
+ inet_dns:rr(RR, type) =:= opt] of
+ [OptRR] ->
+ io:format("~p~n", [inet_dns:rr(OptRR)]),
+ ok;
+ [] ->
+ case os:type() of
+ {unix,sunos} ->
+ case os:version() of
+ {M,V,_} when M < 5; M == 5, V =< 8 ->
+ %% In our test park only known platform
+ %% with an DNS resolver that can not do
+ %% EDNS0.
+ {comment,"No EDNS0"}
+ end
+ end
+ end.
inet_res_filter(Anlist, Class, Type) ->
[inet_dns:rr(RR, data) || RR <- Anlist,
@@ -331,11 +365,13 @@ files_monitor(suite) ->
files_monitor(doc) ->
["Tests monitoring of /etc/hosts and /etc/resolv.conf, but not them"];
files_monitor(Config) when is_list(Config) ->
+ Search = inet_db:res_option(search),
HostsFile = inet_db:res_option(hosts_file),
ResolvConf = inet_db:res_option(resolv_conf),
Inet6 = inet_db:res_option(inet6),
try do_files_monitor(Config)
after
+ inet_db:res_option(search, Search),
inet_db:res_option(resolv_conf, ResolvConf),
inet_db:res_option(hosts_file, HostsFile),
inet_db:res_option(inet6, Inet6)
@@ -344,7 +380,13 @@ files_monitor(Config) when is_list(Config) ->
do_files_monitor(Config) ->
Dir = ?config(priv_dir, Config),
{ok,Hostname} = inet:gethostname(),
- FQDN = Hostname++"."++inet_db:res_option(domain),
+ FQDN =
+ case inet_db:res_option(domain) of
+ "" ->
+ Hostname;
+ _ ->
+ Hostname++"."++inet_db:res_option(domain)
+ end,
HostsFile = filename:join(Dir, "files_monitor_hosts"),
ResolvConf = filename:join(Dir, "files_monitor_resolv.conf"),
ok = inet_db:res_option(resolv_conf, ResolvConf),
@@ -362,20 +404,20 @@ do_files_monitor(Config) ->
{error,nxdomain} = inet_res:gethostbyname(FQDN),
{ok,{127,0,0,10}} = inet:getaddr("mx.otptest", inet),
{ok,{0,0,0,0,0,0,32512,28}} = inet:getaddr("resolve.otptest", inet6),
- ok = inet_db:res_option(inet6, true),
{ok,#hostent{h_name = Hostname,
h_addrtype = inet6,
h_length = 16,
h_addr_list = [{0,0,0,0,0,0,0,1}]}} =
- inet:gethostbyname(Hostname),
+ inet:gethostbyname(Hostname, inet6),
{ok,#hostent{h_name = FQDN,
h_addrtype = inet6,
h_length = 16,
h_addr_list = [{0,0,0,0,0,0,0,1}]}} =
- inet:gethostbyname(FQDN),
+ inet:gethostbyname(FQDN, inet6),
{error,nxdomain} = inet_res:gethostbyname("resolve"),
%% XXX inet does not honour res_option inet6, might be a problem?
%% therefore inet_res is called here
+ ok = inet_db:res_option(inet6, true),
{ok,#hostent{h_name = "resolve.otptest",
h_addrtype = inet6,
h_length = 16,