From cc90d8c3642afa626b483b92c53964365d72b35a Mon Sep 17 00:00:00 2001
From: Raimo Niskanen
Date: Thu, 28 Jan 2010 17:01:00 +0100
Subject: inet:gethostbyname improved to parse IP strings and look up own
hostname
Now inet:gethostbyname tries to parse the hostname as an IP string
first if the 'native' lookup method is not used. One can also
make the IP string parsing explicit using the new 'string'
lookup method, or avoid it using the new pseudo lookup
method 'nostring'.
In R13B04 a bug was introduced when the gethostbyname code
was rewritten, so if the native resolver was used and
misconfigured to not be able to look up the own hostname,
inet:gethostbyname also failed. This is now fixed.
---
erts/doc/src/inet_cfg.xml | 7 +
lib/kernel/src/inet.erl | 137 ++++++++++--------
lib/kernel/src/inet_parse.erl | 275 ++++++++++++++++++++++++++-----------
lib/kernel/test/inet_SUITE.erl | 188 +++++++++++++++++++++++--
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
inet_res
for nameserver queries).
+ The lookup method tries to
+ parse the hostname as a IPv4 or IPv6 string and return
+ the resulting IP address. It is automatically tried
+ first when is not
+ in the list. To skip it in this case
+ the pseudo lookup method can be
+ inserted anywhere in the list.
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,D1] when D < (1 bsl 24), D1 < 256 ->
+ <> = <>,
+ {D1,D2,D3,D4};
+ [D,D2,D1] when D < (1 bsl 16), (D2 bor D1) < 256 ->
+ <> = <>,
+ {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,
--
cgit v1.2.3
From 502afaf945dc006c0d2859257b163fd581aee843 Mon Sep 17 00:00:00 2001
From: Raimo Niskanen
Date: Wed, 3 Feb 2010 09:02:34 +0100
Subject: inet_res_SUITE: testcase fix for empty domain name
---
lib/kernel/test/inet_res_SUITE.erl | 8 +++++++-
1 file changed, 7 insertions(+), 1 deletion(-)
diff --git a/lib/kernel/test/inet_res_SUITE.erl b/lib/kernel/test/inet_res_SUITE.erl
index d8a8d07a18..5c6e689253 100644
--- a/lib/kernel/test/inet_res_SUITE.erl
+++ b/lib/kernel/test/inet_res_SUITE.erl
@@ -344,7 +344,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),
--
cgit v1.2.3
From a53dfdc8d1656faf4b8fc7b41d036f25684d71fe Mon Sep 17 00:00:00 2001
From: Raimo Niskanen
Date: Wed, 3 Feb 2010 11:17:04 +0100
Subject: inet_gethost_native: workaround for empty result hostname on MacOS X
On MacOS X the getaddrinfo function apparently can return a result
without canonical hostname e.g when looking up a IPv6 address
string as hostname. The receiving erlang code was not prepared
for that and this patch does a workaround by using the
search string as default value for canonical hostname.
---
lib/kernel/src/inet_gethost_native.erl | 62 +++++++++++++++++++++-------------
1 file changed, 38 insertions(+), 24 deletions(-)
diff --git a/lib/kernel/src/inet_gethost_native.erl b/lib/kernel/src/inet_gethost_native.erl
index abdbe2b8cf..a1eb2612e0 100644
--- a/lib/kernel/src/inet_gethost_native.erl
+++ b/lib/kernel/src/inet_gethost_native.erl
@@ -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, <>);
-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, <>);
+gethostbyaddr({A,B,C,D}=Addr)
+ when ?VALID_V4(A), ?VALID_V4(B), ?VALID_V4(C), ?VALID_V4(D) ->
+ getit(?OP_GETHOSTBYADDR, ?PROTO_IPV4, <>, 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,
+ <>, 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, <>);
+ getit(?OP_CONTROL, ?SETOPT_DEBUG_LEVEL, <>, 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
<> ->
{error, list_to_atom(listify(Errstring))};
<> ->
- {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}};
<> ->
- {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,
<> = Bin,
--
cgit v1.2.3
From 0377ecdfb001c4dc1b507ebc06211f29b19048e3 Mon Sep 17 00:00:00 2001
From: Raimo Niskanen
Date: Tue, 2 Feb 2010 12:45:43 +0100
Subject: inet: delayed/avoided read of /etc/resolv.conf and /etc/hosts
The 'file' and 'dns' lookup methods configuration files
are now read and parsed at the time of the first lookup
instead of at boot time when per default none of these
lookup methods are used.
---
lib/kernel/src/inet_config.erl | 22 ++++++-----
lib/kernel/src/inet_db.erl | 88 +++++++++++++++++++++++++++---------------
2 files changed, 69 insertions(+), 41 deletions(-)
diff --git a/lib/kernel/src/inet_config.erl b/lib/kernel/src/inet_config.erl
index b5317f72f5..cba38359e1 100644
--- a/lib/kernel/src/inet_config.erl
+++ b/lib/kernel/src/inet_config.erl
@@ -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..9cdffb5f2c 100644
--- a/lib/kernel/src/inet_db.erl
+++ b/lib/kernel/src/inet_db.erl
@@ -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,46 @@ 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} ->
+ [del_ns,
+ clear_search,
+ clear_cache
+ |[Opt ||
+ {T,_}=Opt <- Opts,
+ (T =:= nameserver orelse
+ T =:= search)]];
+ _ -> error
+ end
+ end,
+ From, State);
%%
{res_set, Opt, Value} ->
case res_optname(Opt) of
@@ -1156,6 +1173,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 +1201,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.
--
cgit v1.2.3
From 8de5ac7737bd6f121af35ca60e22f0696bbdc06b Mon Sep 17 00:00:00 2001
From: Raimo Niskanen
Date: Wed, 3 Feb 2010 15:23:12 +0100
Subject: inet_res: /etc/resolv.conf: use domain as default search list
When the search list option in /etc/resolv.conf was empty, the
domain option was not used as default search domain.
That has been fixed in this patch.
---
lib/kernel/src/inet_db.erl | 19 ++++++++++++++-----
lib/kernel/test/inet_res_SUITE.erl | 2 ++
2 files changed, 16 insertions(+), 5 deletions(-)
diff --git a/lib/kernel/src/inet_db.erl b/lib/kernel/src/inet_db.erl
index 9cdffb5f2c..00c3a6af9c 100644
--- a/lib/kernel/src/inet_db.erl
+++ b/lib/kernel/src/inet_db.erl
@@ -1011,13 +1011,22 @@ handle_call(Request, From, #state{db=Db}=State) ->
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
- |[Opt ||
- {T,_}=Opt <- Opts,
- (T =:= nameserver orelse
- T =:= search)]];
+ clear_cache,
+ {search,Search}
+ |[Opt || {nameserver,_}=Opt <- Opts]];
_ -> error
end
end,
diff --git a/lib/kernel/test/inet_res_SUITE.erl b/lib/kernel/test/inet_res_SUITE.erl
index 5c6e689253..20e3e690d3 100644
--- a/lib/kernel/test/inet_res_SUITE.erl
+++ b/lib/kernel/test/inet_res_SUITE.erl
@@ -331,11 +331,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)
--
cgit v1.2.3
From 7dbd225787b498f4815d407ff889ff8630dabdbd Mon Sep 17 00:00:00 2001
From: Raimo Niskanen
Date: Thu, 4 Feb 2010 17:26:27 +0100
Subject: inet_res_SUITE: testcase fixes for legacy DNS resolver (Solaris 8)
---
lib/kernel/test/inet_res_SUITE.erl | 62 +++++++++++++++++++++++++++++---------
1 file changed, 48 insertions(+), 14 deletions(-)
diff --git a/lib/kernel/test/inet_res_SUITE.erl b/lib/kernel/test/inet_res_SUITE.erl
index 20e3e690d3..679b02d2fb 100644
--- a/lib/kernel/test/inet_res_SUITE.erl
+++ b/lib/kernel/test/inet_res_SUITE.erl
@@ -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,
--
cgit v1.2.3