aboutsummaryrefslogtreecommitdiffstats
path: root/lib/kernel/test/inet_res_SUITE.erl
diff options
context:
space:
mode:
Diffstat (limited to 'lib/kernel/test/inet_res_SUITE.erl')
-rw-r--r--lib/kernel/test/inet_res_SUITE.erl418
1 files changed, 418 insertions, 0 deletions
diff --git a/lib/kernel/test/inet_res_SUITE.erl b/lib/kernel/test/inet_res_SUITE.erl
new file mode 100644
index 0000000000..659cfc5988
--- /dev/null
+++ b/lib/kernel/test/inet_res_SUITE.erl
@@ -0,0 +1,418 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2009. 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).
+
+-include("test_server.hrl").
+-include("test_server_line.hrl").
+
+-include_lib("kernel/include/inet.hrl").
+-include_lib("kernel/src/inet_dns.hrl").
+
+-export([all/1, init_per_testcase/2, end_per_testcase/2]).
+-export([basic/1, resolve/1, edns0/1, txt_record/1, files_monitor/1]).
+-export([gethostbyaddr/1, gethostbyaddr_v6/1,
+ gethostbyname/1, gethostbyname_v6/1,
+ getaddr/1, getaddr_v6/1, ipv4_to_ipv6/1, host_and_addr/1]).
+
+-define(RUN_NAMED, "run-named").
+
+all(suite) ->
+ [basic, resolve, edns0, txt_record, files_monitor,
+ gethostbyaddr, gethostbyaddr_v6, gethostbyname, gethostbyname_v6,
+ getaddr, getaddr_v6, ipv4_to_ipv6, host_and_addr].
+
+zone_dir(basic) ->
+ otptest;
+zone_dir(resolve) ->
+ otptest;
+zone_dir(edns0) ->
+ otptest;
+zone_dir(files_monitor) ->
+ otptest;
+zone_dir(_) ->
+ undefined.
+
+init_per_testcase(Func, Config) ->
+ PrivDir = ?config(priv_dir, Config),
+ DataDir = ?config(data_dir, Config),
+ try ns_init(zone_dir(Func), PrivDir, DataDir) of
+ NsSpec ->
+ Lookup = inet_db:res_option(lookup),
+ inet_db:set_lookup([file,dns]),
+ case NsSpec of
+ {_,{IP,Port},_} ->
+ inet_db:ins_alt_ns(IP, Port);
+ _ -> ok
+ end,
+ Dog = test_server:timetrap(test_server:seconds(10)),
+ [{nameserver,NsSpec},{res_lookup,Lookup},{watchdog,Dog}|Config]
+ catch
+ SkipReason ->
+ {skip,SkipReason}
+ end.
+
+end_per_testcase(_Func, Config) ->
+ test_server:timetrap_cancel(?config(watchdog, Config)),
+ inet_db:set_lookup(?config(res_lookup, Config)),
+ NsSpec = ?config(nameserver, Config),
+ case NsSpec of
+ {_,{IP,Port},_} ->
+ inet_db:del_alt_ns(IP, Port);
+ _ -> ok
+ end,
+ ns_end(NsSpec, ?config(priv_dir, Config)).
+
+%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% Nameserver control
+
+ns(Config) ->
+ {_ZoneDir,NS,_P} = ?config(nameserver, Config),
+ NS.
+
+ns_init(ZoneDir, PrivDir, DataDir) ->
+ case os:type() of
+ {unix,_} when ZoneDir =:= undefined -> undefined;
+ {unix,_} ->
+ {ok,S} = gen_udp:open(0, [{reuseaddr,true}]),
+ {ok,PortNum} = inet:port(S),
+ gen_udp:close(S),
+ RunNamed = filename:join(DataDir, ?RUN_NAMED),
+ NS = {{127,0,0,1},PortNum},
+ P = erlang:open_port({spawn_executable,RunNamed},
+ [{cd,PrivDir},
+ {line,80},
+ {args,["127.0.0.1",
+ integer_to_list(PortNum),
+ atom_to_list(ZoneDir)]},
+ stderr_to_stdout,
+ eof]),
+ ns_start(ZoneDir, NS, P);
+ _ ->
+ throw("Only run on Unix")
+ end.
+
+ns_start(ZoneDir, NS, P) ->
+ case ns_collect(P) of
+ eof ->
+ erlang:error(eof);
+ "Running: "++_ ->
+ {ZoneDir,NS,P};
+ "Error: "++Error ->
+ throw(Error);
+ _ ->
+ ns_start(ZoneDir, NS, P)
+ end.
+
+ns_end(undefined, _PrivDir) -> undefined;
+ns_end({ZoneDir,_NS,P}, PrivDir) ->
+ port_command(P, ["quit",io_lib:nl()]),
+ ns_stop(P),
+ ns_printlog(filename:join([PrivDir,ZoneDir,"named.log"])),
+ ok.
+
+ns_stop(P) ->
+ case ns_collect(P) of
+ eof ->
+ erlang:port_close(P);
+ _ ->
+ ns_stop(P)
+ end.
+
+ns_collect(P) ->
+ ns_collect(P, []).
+ns_collect(P, Buf) ->
+ receive
+ {P,{data,{eol,L}}} ->
+ Line = lists:flatten(lists:reverse(Buf, [L])),
+ io:format("~s", [Line]),
+ Line;
+ {P,{data,{noeol,L}}} ->
+ ns_collect(P, [L|Buf]);
+ {P,eof} ->
+ eof
+ end.
+
+ns_printlog(Fname) ->
+ io:format("Name server log file contents:~n", []),
+ case file:read_file(Fname) of
+ {ok,Bin} ->
+ io:format("~s~n", [Bin]);
+ _ ->
+ ok
+ end.
+
+%%
+%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+basic(doc) ->
+ ["Lookup an A record with different API functions"];
+basic(Config) when is_list(Config) ->
+ NS = ns(Config),
+ Name = "ns.otptest",
+ IP = {127,0,0,254},
+ %%
+ %% nslookup
+ {ok,Msg1} = inet_res:nslookup(Name, in, a, [NS]),
+ io:format("~p~n", [Msg1]),
+ [RR1] = inet_dns:msg(Msg1, anlist),
+ IP = inet_dns:rr(RR1, data),
+ Bin1 = inet_dns:encode(Msg1),
+ %%io:format("Bin1 = ~w~n", [Bin1]),
+ {ok,Msg1} = inet_dns:decode(Bin1),
+ %%
+ %% resolve
+ {ok,Msg2} = inet_res:resolve(Name, in, a, [{nameservers,[NS]}]),
+ io:format("~p~n", [Msg2]),
+ [RR2] = inet_dns:msg(Msg2, anlist),
+ IP = inet_dns:rr(RR2, data),
+ Bin2 = inet_dns:encode(Msg2),
+ %%io:format("Bin2 = ~w~n", [Bin2]),
+ {ok,Msg2} = inet_dns:decode(Bin2),
+ %%
+ %% lookup
+ [IP] = inet_res:lookup(Name, in, a, [{nameservers,[NS]}]),
+ %%
+ %% gethostbyname
+ {ok,#hostent{h_addr_list=[IP]}} = inet_res:gethostbyname(Name),
+ %%
+ %% getbyname
+ {ok,#hostent{h_addr_list=[IP]}} = inet_res:getbyname(Name, a),
+ ok.
+
+%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+resolve(doc) ->
+ ["Lookup different records using resolve/2..4"];
+resolve(Config) when is_list(Config) ->
+ NS = ns(Config),
+ Domain = "otptest",
+ RDomain4 = "0.0.127.in-addr.arpa",
+ RDomain6 = "0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.ip6.arpa",
+ Name = "resolve."++Domain,
+ L = [{in,a,Name,[{127,0,0,28}],undefined},
+ {in,aaaa,Name,[{0,0,0,0,0,0,32512,28}],undefined},
+ {in,cname,"cname."++Name,[Name],undefined},
+ {in,a,"cname."++Name,[Name,{127,0,0,28}],undefined},
+ {in,ns,"ns."++Name,[],[Name]},
+ {in,soa,Domain,[],[{"ns.otptest","lsa.otptest",1,60,10,300,30}]},
+ %% WKS: protocol TCP (6), services (bits) TELNET (23) and SMTP (25)
+ {in,wks,"wks."++Name,[{{127,0,0,28},6,<<0,0,1,64>>}],undefined},
+ {in,ptr,"28."++RDomain4,[Name],undefined},
+ {in,ptr,"c.1.0.0.0.0.f.7."++RDomain6,[Name],undefined},
+ {in,hinfo,Name,[{"BEAM","Erlang/OTP"}],undefined},
+ {in,mx,RDomain4,[{10,"mx."++Domain}],undefined},
+ {in,srv,"_srv._tcp."++Name,[{10,3,4711,Name}],undefined},
+ {in,naptr,"naptr."++Name,
+ [{10,5,"s","http","","_srv._tcp."++Name}],undefined},
+ {in,txt,"txt."++Name,
+ [["Hej ","du ","glade "],["ta ","en ","spade!"]],undefined},
+ {in,mb,"mb."++Name,["mx."++Name],undefined},
+ {in,mg,"mg."++Name,["lsa."++Domain],undefined},
+ {in,mr,"mr."++Name,["lsa."++Domain],undefined},
+ {in,minfo,"minfo."++Name,
+ [{"minfo-owner."++Name,"minfo-bounce."++Name}],undefined},
+ {in,any,"cname."++Name,[Name],undefined},
+ {in,any,Name,[{127,0,0,28},
+ {0,0,0,0,0,0,32512,28},
+ {"BEAM","Erlang/OTP"}],undefined}
+ ],
+ resolve([{edns,false},{nameservers,[NS]}], L),
+ resolve([{edns,0},{nameservers,[NS]}], L).
+
+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,
+ Buf = inet_dns:encode(Msg),
+ {ok,Msg} = inet_dns:decode(Buf),
+ resolve(Opts, Qs).
+
+%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+edns0(doc) ->
+ ["Test EDNS and truncation"];
+edns0(Config) when is_list(Config) ->
+ NS = ns(Config),
+ Domain = "otptest",
+ Filler = "-5678901234567890123456789012345678.",
+ MXs = lists:sort([{10,"mx."++Domain},
+ {20,"mx1"++Filler++Domain},
+ {20,"mx2"++Filler++Domain},
+ {20,"mx3"++Filler++Domain},
+ {20,"mx4"++Filler++Domain},
+ {20,"mx5"++Filler++Domain},
+ {20,"mx6"++Filler++Domain},
+ {20,"mx7"++Filler++Domain}]),
+ false = inet_db:res_option(edns), % ASSERT
+ true = inet_db:res_option(udp_payload_size) >= 1280, % ASSERT
+ %% These will fall back to TCP
+ MXs = lists:sort(inet_res:lookup(Domain, in, mx, [{nameservers,[NS]}])),
+ %%
+ {ok,#hostent{h_addr_list=As}} = inet_res:getbyname(Domain++".", mx),
+ MXs = lists:sort(As),
+ %%
+ {ok,Msg1} = inet_res:resolve(Domain, in, mx),
+ MXs = lists:sort(inet_res_filter(inet_dns:msg(Msg1, anlist), in, mx)),
+ %% There should be no OPT record in the answer
+ [] = [RR || RR <- inet_dns:msg(Msg1, arlist),
+ inet_dns:rr(RR, type) =:= opt],
+ Buf1 = inet_dns:encode(Msg1),
+ {ok,Msg1} = inet_dns:decode(Buf1),
+ %%
+ %% Use EDNS - should not need to fall back to TCP
+ %% there is no way to tell from the outside.
+ %%
+ {ok,Msg2} = inet_res:resolve(Domain, in, mx, [{edns,0}]),
+ 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.
+
+inet_res_filter(Anlist, Class, Type) ->
+ [inet_dns:rr(RR, data) || RR <- Anlist,
+ inet_dns:rr(RR, type) =:= Type,
+ inet_dns:rr(RR, class) =:= Class].
+
+%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+txt_record(suite) ->
+ [];
+txt_record(doc) ->
+ ["Tests TXT records"];
+txt_record(Config) when is_list(Config) ->
+ D1 = "cslab.ericsson.net",
+ D2 = "mail1.cslab.ericsson.net",
+ {ok,#dns_rec{anlist=[RR1]}} =
+ inet_res:nslookup(D1, in, txt),
+ io:format("~p~n", [RR1]),
+ {ok,#dns_rec{anlist=[RR2]}} =
+ inet_res:nslookup(D2, in, txt),
+ io:format("~p~n", [RR2]),
+ #dns_rr{domain=D1, class=in, type=txt, data=A1} = RR1,
+ #dns_rr{domain=D2, class=in, type=txt, data=A2} = RR2,
+ case [lists:flatten(A2)] of
+ A1 = [[_|_]] -> ok
+ end,
+ ok.
+
+%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+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) ->
+ 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(resolv_conf, ResolvConf),
+ inet_db:res_option(hosts_file, HostsFile),
+ inet_db:res_option(inet6, Inet6)
+ end.
+
+do_files_monitor(Config) ->
+ Dir = ?config(priv_dir, Config),
+ {ok,Hostname} = inet:gethostname(),
+ FQDN = Hostname++"."++inet_db:res_option(domain),
+ HostsFile = filename:join(Dir, "files_monitor_hosts"),
+ ResolvConf = filename:join(Dir, "files_monitor_resolv.conf"),
+ ok = inet_db:res_option(resolv_conf, ResolvConf),
+ ok = inet_db:res_option(hosts_file, HostsFile),
+ [] = inet_db:res_option(search),
+ {ok,#hostent{h_name = Hostname,
+ h_addrtype = inet,
+ h_length = 4,
+ h_addr_list = [{127,0,0,1}]}} = inet:gethostbyname(Hostname),
+ {ok,#hostent{h_name = FQDN,
+ h_addrtype = inet,
+ h_length = 4,
+ h_addr_list = [{127,0,0,1}]}} = inet:gethostbyname(FQDN),
+ {error,nxdomain} = inet_res:gethostbyname(Hostname),
+ {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),
+ {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),
+ {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,#hostent{h_name = "resolve.otptest",
+ h_addrtype = inet6,
+ h_length = 16,
+ h_addr_list = [{0,0,0,0,0,0,32512,28}]}} =
+ inet_res:gethostbyname("resolve.otptest"),
+ {error,nxdomain} = inet_hosts:gethostbyname("files_monitor"),
+ ok = file:write_file(ResolvConf, "search otptest\n"),
+ ok = file:write_file(HostsFile, "::100 files_monitor\n"),
+ receive after 7000 -> ok end, % RES_FILE_UPDATE_TM in inet_res.hrl is 5 s
+ {ok,#hostent{h_name = "resolve.otptest",
+ h_addrtype = inet6,
+ h_length = 16,
+ h_addr_list = [{0,0,0,0,0,0,32512,28}]}} =
+ inet_res:gethostbyname("resolve.otptest"),
+ ["otptest"] = inet_db:res_option(search),
+ {ok,#hostent{h_name = "files_monitor",
+ h_addrtype = inet6,
+ h_length = 16,
+ h_addr_list = [{0,0,0,0,0,0,0,256}]}} =
+ inet_hosts:gethostbyname("files_monitor"),
+ ok = inet_db:res_option(inet6, false),
+ {ok,#hostent{h_name = "resolve.otptest",
+ h_addrtype = inet,
+ h_length = 4,
+ h_addr_list = [{127,0,0,28}]}} =
+ inet:gethostbyname("resolve.otptest"),
+ ok.
+
+%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% Compatibility tests. Call the inet_SUITE tests, but with
+%% lookup = [file,dns] instead of [native]
+
+gethostbyaddr(Config) -> inet_SUITE:t_gethostbyaddr(Config).
+gethostbyaddr_v6(Config) -> inet_SUITE:t_gethostbyaddr_v6(Config).
+gethostbyname(Config) -> inet_SUITE:t_gethostbyname(Config).
+gethostbyname_v6(Config) -> inet_SUITE:t_gethostbyname_v6(Config).
+getaddr(Config) -> inet_SUITE:t_getaddr(Config).
+getaddr_v6(Config) -> inet_SUITE:t_getaddr_v6(Config).
+ipv4_to_ipv6(Config) -> inet_SUITE:ipv4_to_ipv6(Config).
+host_and_addr(Config) -> inet_SUITE:host_and_addr(Config).