}\r
unit dnscore;\r
\r
-\r
-\r
{$ifdef fpc}{$mode delphi}{$endif}\r
\r
-\r
-\r
-\r
+{$include lcoreconfig.inc}\r
\r
interface\r
\r
uses binipstuff,classes,pgtypes;\r
\r
var usewindns : boolean = {$ifdef win32}true{$else}false{$endif};\r
-//hint to users of this unit that they should use windows dns instead.\r
-//May be disabled by applications if desired. (e.g. if setting a custom\r
-//dnsserverlist).\r
+{hint to users of this unit that they should use windows dns instead.\r
+May be disabled by applications if desired. (e.g. if setting a custom\r
+dnsserverlist).\r
\r
-//note: this unit will not be able to self populate it's dns server list on\r
-//older versions of windows.\r
+note: this unit will not be able to self populate it's dns server list on\r
+older versions of windows.}\r
+\r
+const\r
+ useaf_default=0;\r
+ useaf_preferv4=1;\r
+ useaf_preferv6=2;\r
+ useaf_v4=3;\r
+ useaf_v6=4;\r
+{\r
+hint to users of this unit to how to deal with connecting to hostnames regarding ipv4 or ipv6 usage\r
+can be set by apps as desired\r
+}\r
+var useaf:integer = useaf_default;\r
\r
const\r
maxnamelength=127;\r
parsepacket:boolean;\r
resultstr:string;\r
resultbin:tbinip;\r
+ resultlist:tbiniplist;\r
resultaction:integer;\r
numrr1:array[0..3] of integer;\r
numrr2:integer;\r
//if you must but please document them at the same time --plugwash\r
\r
//function buildrequest(const name:string;var packet:tdnspacket;requesttype:word):integer;\r
-//function makereversename(const binip:tbinip):string;\r
+\r
+//returns the DNS name used to reverse look up an IP, such as 4.3.2.1.in-addr.arpa for 1.2.3.4\r
+function makereversename(const binip:tbinip):string;\r
\r
procedure setstate_request_init(const name:string;var state:tdnsstate);\r
\r
//set up state for a foward lookup. A family value of AF_INET6 will give only\r
-//ipv6 results. Any other value will give ipv4 results in preference and ipv6\r
-//results if ipv4 results are not available;\r
+//ipv6 results. Any other value will give only ipv4 results\r
procedure setstate_forward(const name:string;var state:tdnsstate;family:integer);\r
\r
procedure setstate_reverse(const binip:tbinip;var state:tdnsstate);\r
dnsserverlist : tstringlist;\r
// currentdnsserverno : integer;\r
\r
+\r
+//getcurrentsystemnameserver returns the nameserver the app should use and sets\r
+//id to the id of that nameserver. id should later be used to report how laggy\r
+//the servers response was and if it was timed out.\r
function getcurrentsystemnameserver(var id:integer) :string;\r
+procedure reportlag(id:integer;lag:integer); //lag should be in microseconds and should be -1 to report a timeout\r
\r
//var\r
// unixnameservercache:string;\r
{ $endif}\r
\r
\r
-procedure reportlag(id:integer;lag:integer); //lag should be in microseconds and should be -1 to report a timeout\r
+{$ifdef linux}{$ifdef ipv6}\r
+function getv6localips:tbiniplist;\r
+procedure initpreferredmode;\r
+\r
+var\r
+ preferredmodeinited:boolean;\r
+\r
+{$endif}{$endif}\r
+\r
var\r
failurereason:string;\r
\r
\r
{==============================================================================}\r
\r
-procedure setstate_return(const rrp:trrpointer;len:integer;var state:tdnsstate);\r
-var\r
- a:integer;\r
+function getipfromrr(const rrp:trrpointer;len:integer):tbinip;\r
begin\r
- state.resultaction := action_done;\r
- state.resultstr := '';\r
+ fillchar(result,sizeof(result),0);\r
case trr(rrp.p^).requesttype of\r
querytype_a: begin\r
if htons(trr(rrp.p^).datalen) <> 4 then exit;\r
- move(trr(rrp.p^).data,state.resultbin.ip,4);\r
- state.resultbin.family :=AF_INET;\r
+ move(trr(rrp.p^).data,result.ip,4);\r
+ result.family :=AF_INET;\r
end;\r
{$ifdef ipv6}\r
querytype_aaaa: begin\r
if htons(trr(rrp.p^).datalen) <> 16 then exit;\r
- state.resultbin.family := AF_INET6;\r
- move(trr(rrp.p^).data,state.resultbin.ip6,16);\r
+ result.family := AF_INET6;\r
+ move(trr(rrp.p^).data,result.ip6,16);\r
end;\r
{$endif}\r
+ else\r
+ {}\r
+ end;\r
+end;\r
+\r
+procedure setstate_return(const rrp:trrpointer;len:integer;var state:tdnsstate);\r
+var\r
+ a:integer;\r
+begin\r
+ state.resultaction := action_done;\r
+ state.resultstr := '';\r
+ case trr(rrp.p^).requesttype of\r
+ querytype_a{$ifdef ipv6},querytype_aaaa{$endif}: begin\r
+ state.resultbin := getipfromrr(rrp,len);\r
+ end;\r
else\r
{other reply types (PTR, MX) return a hostname}\r
state.resultstr := decodename(state.recvpacket,state.recvpacketlen,taddrint(rrp.p)-taddrint(@state.recvpacket)+10,0,a);\r
goto failure;\r
end;\r
\r
+ {if we requested A or AAAA build a list of all replies}\r
+ if (state.requesttype = querytype_a) or (state.requesttype = querytype_aaaa) then begin\r
+ state.resultlist := biniplist_new;\r
+ for a := state.numrr1[0] to (state.numrr1[0]+state.numrr1[1]-1) do begin\r
+ rrptemp := @state.rrdata[1+a*sizeof(trrpointer)];\r
+ rrtemp := rrptemp.p;\r
+ b := rrptemp.len;\r
+ if rrtemp.requesttype = state.requesttype then begin\r
+ biniplist_add(state.resultlist,getipfromrr(rrptemp^,b));\r
+ end;\r
+ end;\r
+ end;\r
+\r
{- check for items of the requested type in answer section, if so return success first}\r
for a := state.numrr1[0] to (state.numrr1[0]+state.numrr1[1]-1) do begin\r
rrptemp := @state.rrdata[1+a*sizeof(trrpointer)];\r
\r
{no cnames found, no items of correct type found}\r
if state.forwardfamily <> 0 then goto failure;\r
-{$ifdef ipv6}\r
- if (state.requesttype = querytype_a) then begin\r
- {v6 only: in case of forward, look for AAAA in alternative section}\r
- for a := state.numrr1[0]+state.numrr1[1]+state.numrr1[2] to (state.numrr2-1) do begin\r
- rrptemp := @state.rrdata[1+a*sizeof(trrpointer)];\r
- rrtemp := rrptemp.p;\r
- b := rrptemp.len;\r
- if rrtemp.requesttype = querytype_aaaa then begin\r
- setstate_return(rrptemp^,b,state);\r
- exit;\r
- end;\r
- end;\r
- {no AAAA's found in alternative, do a recursive lookup for them}\r
- state.requesttype := querytype_aaaa;\r
- goto recursed;\r
- end;\r
-{$endif}\r
+\r
goto failure;\r
recursed:\r
{here it needs recursed lookup}\r
{$ifdef win32}\r
if iphlpapi=0 then iphlpapi := loadlibrary('iphlpapi.dll');\r
if not assigned(getnetworkparams) then @getnetworkparams := getprocaddress(iphlpapi,'GetNetworkParams');\r
+ if not assigned(getnetworkparams) then exit;\r
fixed_info_len := 0;\r
if GetNetworkParams(nil,@fixed_info_len)<>ERROR_BUFFER_OVERFLOW then exit;\r
//fixed_info_len :=sizeof(tfixed_info);\r
end;\r
\r
function getcurrentsystemnameserver(var id:integer):string;\r
-var \r
+var\r
counter : integer;\r
\r
begin\r
\r
end;\r
\r
+\r
+\r
+{$ifdef linux}{$ifdef ipv6}\r
+function getv6localips:tbiniplist;\r
+var\r
+ t:textfile;\r
+ s,s2:string;\r
+ ip:tbinip;\r
+ a:integer;\r
+begin\r
+ result := biniplist_new;\r
+\r
+ assignfile(t,'/proc/net/if_inet6');\r
+ {$i-}reset(t);{$i+}\r
+ if ioresult <> 0 then exit; {none found, return empty list}\r
+\r
+ while not eof(t) do begin\r
+ readln(t,s);\r
+ s2 := '';\r
+ for a := 0 to 7 do begin\r
+ if (s2 <> '') then s2 := s2 + ':';\r
+ s2 := s2 + copy(s,(a shl 2)+1,4);\r
+ end;\r
+ ipstrtobin(s2,ip);\r
+ if ip.family <> 0 then biniplist_add(result,ip);\r
+ end;\r
+ closefile(t);\r
+end;\r
+\r
+procedure initpreferredmode;\r
+var\r
+ l:tbiniplist;\r
+ a:integer;\r
+ ip:tbinip;\r
+ ipmask_global,ipmask_6to4,ipmask_teredo:tbinip;\r
+\r
+begin\r
+ if preferredmodeinited then exit;\r
+ if useaf <> useaf_default then exit;\r
+ useaf := useaf_preferv4;\r
+ l := getv6localips;\r
+ ipstrtobin('2000::',ipmask_global);\r
+ ipstrtobin('2001::',ipmask_teredo);\r
+ ipstrtobin('2002::',ipmask_6to4);\r
+ {if there is any v6 IP which is globally routable and not 6to4 and not teredo, prefer v6}\r
+ for a := biniplist_getcount(l)-1 downto 0 do begin\r
+ ip := biniplist_get(l,a);\r
+ if not comparebinipmask(ip,ipmask_global,3) then continue;\r
+ if comparebinipmask(ip,ipmask_teredo,32) then continue;\r
+ if comparebinipmask(ip,ipmask_6to4,16) then continue;\r
+ useaf := useaf_preferv6;\r
+ preferredmodeinited := true;\r
+ exit;\r
+ end;\r
+end;\r
+\r
+{$endif}{$endif}\r
+\r
+\r
{ quick and dirty description of dns packet structure to aid writing and\r
understanding of parser code, refer to appropriate RFCs for proper specs\r
- all words are network order\r