From 54240a5829cac17ea59eeeb16f343f3f2817d7b3 Mon Sep 17 00:00:00 2001 From: Raimo Niskanen Date: Fri, 7 Jun 2013 12:05:02 +0200 Subject: Add test cases for host lookup case (in)sensitivity --- lib/kernel/test/inet_res_SUITE.erl | 198 +++++++++++++++++++++++++++++-------- 1 file changed, 159 insertions(+), 39 deletions(-) (limited to 'lib/kernel/test/inet_res_SUITE.erl') diff --git a/lib/kernel/test/inet_res_SUITE.erl b/lib/kernel/test/inet_res_SUITE.erl index f3ba28e4f9..1bc93e3138 100644 --- a/lib/kernel/test/inet_res_SUITE.erl +++ b/lib/kernel/test/inet_res_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2009-2011. All Rights Reserved. +%% Copyright Ericsson AB 2009-2013. 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 @@ -282,6 +282,7 @@ basic(doc) -> basic(Config) when is_list(Config) -> NS = ns(Config), Name = "ns.otptest", + NameC = caseflip(Name), IP = {127,0,0,254}, %% %% nslookup @@ -292,6 +293,17 @@ basic(Config) when is_list(Config) -> Bin1 = inet_dns:encode(Msg1), %%io:format("Bin1 = ~w~n", [Bin1]), {ok,Msg1} = inet_dns:decode(Bin1), + %% Now with scrambled case + {ok,Msg1b} = inet_res:nslookup(NameC, in, a, [NS]), + io:format("~p~n", [Msg1b]), + [RR1b] = inet_dns:msg(Msg1b, anlist), + IP = inet_dns:rr(RR1b, data), + Bin1b = inet_dns:encode(Msg1b), + %%io:format("Bin1b = ~w~n", [Bin1b]), + {ok,Msg1b} = inet_dns:decode(Bin1b), + true = + (tolower(inet_dns:rr(RR1, domain)) + =:= tolower(inet_dns:rr(RR1b, domain))), %% %% resolve {ok,Msg2} = inet_res:resolve(Name, in, a, [{nameservers,[NS]},verbose]), @@ -301,15 +313,29 @@ basic(Config) when is_list(Config) -> Bin2 = inet_dns:encode(Msg2), %%io:format("Bin2 = ~w~n", [Bin2]), {ok,Msg2} = inet_dns:decode(Bin2), + %% Now with scrambled case + {ok,Msg2b} = inet_res:resolve(NameC, in, a, [{nameservers,[NS]},verbose]), + io:format("~p~n", [Msg2b]), + [RR2b] = inet_dns:msg(Msg2b, anlist), + IP = inet_dns:rr(RR2b, data), + Bin2b = inet_dns:encode(Msg2b), + %%io:format("Bin2b = ~w~n", [Bin2b]), + {ok,Msg2b} = inet_dns:decode(Bin2b), + true = + (tolower(inet_dns:rr(RR2, domain)) + =:= tolower(inet_dns:rr(RR2b, domain))), %% %% lookup [IP] = inet_res:lookup(Name, in, a, [{nameservers,[NS]},verbose]), + [IP] = inet_res:lookup(NameC, in, a, [{nameservers,[NS]},verbose]), %% %% gethostbyname {ok,#hostent{h_addr_list=[IP]}} = inet_res:gethostbyname(Name), + {ok,#hostent{h_addr_list=[IP]}} = inet_res:gethostbyname(NameC), %% %% getbyname {ok,#hostent{h_addr_list=[IP]}} = inet_res:getbyname(Name, a), + {ok,#hostent{h_addr_list=[IP]}} = inet_res:getbyname(NameC, a), ok. %% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -317,63 +343,115 @@ basic(Config) when is_list(Config) -> resolve(doc) -> ["Lookup different records using resolve/2..4"]; resolve(Config) when is_list(Config) -> + Class = in, 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}]}, + L = [{a,Name,[{a,{127,0,0,28}}],undefined}, + {aaaa,Name,[{aaaa,{0,0,0,0,0,0,32512,28}}],undefined}, + {cname,"cname."++Name,[{cname,Name}],undefined}, + {a,"cname."++Name,[{cname,Name},{a,{127,0,0,28}}],undefined}, + {ns,"ns."++Name,[],[{ns,Name}]}, + {soa,Domain,[],[{soa,{"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} + {wks,"wks."++Name,[{wks,{{127,0,0,28},6,<<0,0,1,64>>}}],undefined}, + {ptr,"28."++RDomain4,[{ptr,Name}],undefined}, + {ptr,"c.1.0.0.0.0.f.7."++RDomain6,[{ptr,Name}],undefined}, + {hinfo,Name,[{hinfo,{"BEAM","Erlang/OTP"}}],undefined}, + {mx,RDomain4,[{mx,{10,"mx."++Domain}}],undefined}, + {srv,"_srv._tcp."++Name,[{srv,{10,3,4711,Name}}],undefined}, + {naptr,"naptr."++Name, + [{naptr,{10,5,"s","http","","_srv._tcp."++Name}}], + undefined}, + {txt,"txt."++Name, + [{txt,["Hej ","du ","glade "]},{txt,["ta ","en ","spade!"]}], + undefined}, + {mb,"mb."++Name,[{mb,"mx."++Name}],undefined}, + {mg,"mg."++Name,[{mg,"Lsa."++Domain}],undefined}, + {mr,"mr."++Name,[{mr,"LSA."++Domain}],undefined}, + {minfo,"minfo."++Name, + [{minfo,{"minfo-OWNER."++Name,"MinfoBounce."++Name}}], + undefined}, + {any,"cname."++Name,[{cname,Name}],undefined}, + {any,Name, + [{a,{127,0,0,28}}, + {aaaa,{0,0,0,0,0,0,32512,28}}, + {hinfo,{"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]) -> + resolve(Class, [{edns,0},{nameservers,[NS]}], L), + resolve(Class, [{edns,false},{nameservers,[NS]}], L), + %% Again, to see ensure the cache does not mess things up + resolve(Class, [{edns,0},{nameservers,[NS]}], L), + resolve(Class, [{edns,false},{nameservers,[NS]}], L). + +resolve(_Class, _Opts, []) -> + ok; +resolve(Class, Opts, [{Type,Nm,Answers,Authority}=Q|Qs]) -> io:format("Query: ~p~nOptions: ~p~n", [Q,Opts]), - {ok,Msg} = inet_res:resolve(Name, Class, Type, Opts), + {Name,NameC} = + case erlang:phash2(Q) band 4 of + 0 -> + {Nm,caseflip(Nm)}; + _ -> + {caseflip(Nm),Nm} + end, AnList = if Answers =/= undefined -> - lists:sort(Answers); + normalize_answers(Answers); true -> undefined end, NsList = if Authority =/= undefined -> - lists:sort(Authority); + normalize_answers(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 + {ok,Msg} = inet_res:resolve(Name, Class, Type, Opts), + check_msg(Class, Type, Msg, AnList, NsList), + {ok,MsgC} = inet_res:resolve(NameC, Class, Type, Opts), + check_msg(Class, Type, MsgC, AnList, NsList), + resolve(Class, Opts, Qs). + + + +normalize_answers(AnList) -> + lists:sort([normalize_answer(Answer) || Answer <- AnList]). + +normalize_answer({soa,{NS,HM,Ser,Ref,Ret,Exp,Min}}) -> + {tolower(NS),tolower_email(HM),Ser,Ref,Ret,Exp,Min}; +normalize_answer({mx,{Prio,DN}}) -> + {Prio,tolower(DN)}; +normalize_answer({srv,{Prio,Weight,Port,DN}}) -> + {Prio,Weight,Port,tolower(DN)}; +normalize_answer({naptr,{Order,Pref,Flags,Service,RE,Repl}}) -> + {Order,Pref,Flags,Service,RE,tolower(Repl)}; +normalize_answer({minfo,{RespM,ErrM}}) -> + {tolower_email(RespM),tolower_email(ErrM)}; +normalize_answer({T,MN}) when T =:= mg; T =:= mr -> + tolower_email(MN); +normalize_answer({T,DN}) when T =:= cname; T =:= ns; T =:= ptr; T =:= mb -> + tolower(DN); +normalize_answer(Answer) -> + Answer. + +check_msg(Class, Type, Msg, AnList, NsList) -> + io:format("check_msg Type: ~p, Msg: ~p~n.", [Type,Msg]), + case {normalize_answers( + [begin + Class = inet_dns:rr(RR, class), + {inet_dns:rr(RR, type),inet_dns:rr(RR, data)} + end || RR <- inet_dns:msg(Msg, anlist)]), + normalize_answers( + [begin + Class = inet_dns:rr(RR, class), + {inet_dns:rr(RR, type),inet_dns:rr(RR, data)} + end || RR <- inet_dns:msg(Msg, nslist)])} of {AnList,NsList} -> ok; {NsList,AnList} when Type =:= ns -> @@ -389,7 +467,7 @@ resolve(Opts, [{Class,Type,Name,Answers,Authority}=Q|Qs]) -> end, Buf = inet_dns:encode(Msg), {ok,Msg} = inet_dns:decode(Buf), - resolve(Opts, Qs). + ok. %% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -497,6 +575,7 @@ files_monitor(Config) when is_list(Config) -> do_files_monitor(Config) -> Dir = ?config(priv_dir, Config), {ok,Hostname} = inet:gethostname(), + io:format("Hostname = ~p.~n", [Hostname]), FQDN = case inet_db:res_option(domain) of "" -> @@ -504,11 +583,13 @@ do_files_monitor(Config) -> _ -> Hostname++"."++inet_db:res_option(domain) end, + io:format("FQDN = ~p.~n", [FQDN]), 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), + %% The inet function will use its final fallback to find this host {ok,#hostent{h_name = Hostname, h_addrtype = inet, h_length = 4, @@ -521,6 +602,7 @@ 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), + %% The inet function will use its final fallback to find this host {ok,#hostent{h_name = Hostname, h_addrtype = inet6, h_length = 16, @@ -603,3 +685,41 @@ ipv4_to_ipv6() -> inet_SUITE:ipv4_to_ipv6(). ipv4_to_ipv6(Config) -> inet_SUITE:ipv4_to_ipv6(Config). host_and_addr() -> inet_SUITE:host_and_addr(). host_and_addr(Config) -> inet_SUITE:host_and_addr(Config). + + + +%% Case flip helper + +caseflip([C|Cs]) when is_integer(C), $a =< C, C =< $z -> + [(C - $a + $A)|caseflip_skip(Cs)]; +caseflip([C|Cs]) when is_integer(C), $A =< C, C =< $Z -> + [(C - $A + $a)|caseflip_skip(Cs)]; +caseflip([C|Cs]) -> + [C|caseflip(Cs)]; +caseflip([]) -> + []. + +caseflip_skip([C|Cs]) when is_integer(C), $a =< C, C =< $z -> + [C|caseflip(Cs)]; +caseflip_skip([C|Cs]) when is_integer(C), $A =< C, C =< $Z -> + [C|caseflip(Cs)]; +caseflip_skip([C|Cs]) -> + [C|caseflip_skip(Cs)]; +caseflip_skip([]) -> + []. + +tolower_email([$.|Cs]) -> + [$.|tolower(Cs)]; +tolower_email([C|Cs]) -> + [C|tolower_email(Cs)]. + +%% Case fold to lower case according to RFC 4343 +%% +tolower([C|Cs]) when is_integer(C) -> + if $A =< C, C =< $Z -> + [(C - $A + $a)|tolower(Cs)]; + true -> + [C|tolower(Cs)] + end; +tolower([]) -> + []. -- cgit v1.2.3