diff options
-rw-r--r-- | erts/doc/src/inet_cfg.xml | 7 | ||||
-rw-r--r-- | lib/kernel/src/inet.erl | 137 | ||||
-rw-r--r-- | lib/kernel/src/inet_parse.erl | 275 | ||||
-rw-r--r-- | lib/kernel/test/inet_SUITE.erl | 188 | ||||
-rw-r--r-- | lib/kernel/test/inet_res_SUITE.erl | 6 |
5 files changed, 457 insertions, 156 deletions
diff --git a/erts/doc/src/inet_cfg.xml b/erts/doc/src/inet_cfg.xml index 18cf65759a..d289c42557 100644 --- a/erts/doc/src/inet_cfg.xml +++ b/erts/doc/src/inet_cfg.xml @@ -230,6 +230,13 @@ (use the Erlang DNS client <seealso marker="kernel:inet_res">inet_res</seealso> for nameserver queries).</p> + <p>The lookup method <c><![CDATA[string]]></c> tries to + parse the hostname as a IPv4 or IPv6 string and return + the resulting IP address. It is automatically tried + first when <c><![CDATA[native]]></c> is <em>not</em> + in the <c><![CDATA[Methods]]></c> list. To skip it in this case + the pseudo lookup method <c><![CDATA[nostring]]></c> can be + inserted anywhere in the <c><![CDATA[Methods]]></c> list.</p> <p></p> </item> <tag><em><c><![CDATA[{cache_size, Size}.]]></c></em></tag> diff --git a/lib/kernel/src/inet.erl b/lib/kernel/src/inet.erl index b86aa1839e..77725372c2 100644 --- a/lib/kernel/src/inet.erl +++ b/lib/kernel/src/inet.erl @@ -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_parse.erl b/lib/kernel/src/inet_parse.erl index 62d44fb723..f44a5f1800 100644 --- a/lib/kernel/src/inet_parse.erl +++ b/lib/kernel/src/inet_parse.erl @@ -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([_|_], [_,_,_,_]) -> + %% 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. + -ipv4_addr({Cs0,[]}, A) when length(A) =< 3 -> - case [tod(Cs0)|A] of - [D4,D3,D2,D1] -> +%% +%% 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. -d3(Cs) -> d3(Cs, []). +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. + + + +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. -d3([C|Cs], R) when C >= $0, C =< $9, length(R) =< 2 -> - d3(Cs, [C|R]); -d3(Cs, [_|_]=R) -> - {lists:reverse(R),Cs}. -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)]). - -%% 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({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). -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, 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) -> - 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..db0f86fb82 100644 --- a/lib/kernel/test/inet_SUITE.erl +++ b/lib/kernel/test/inet_SUITE.erl @@ -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..d8a8d07a18 100644 --- a/lib/kernel/test/inet_res_SUITE.erl +++ b/lib/kernel/test/inet_res_SUITE.erl @@ -362,20 +362,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, |