+++ /dev/null
-{ Copyright (C) 2005 Bas Steendijk and Peter Green\r
- For conditions of distribution and use, see copyright notice in zlib_license.txt\r
- which is included in the package\r
- ----------------------------------------------------------------------------- }\r
-\r
-{\r
-\r
- code wanting to use this dns system should act as follows (note: app\r
- developers will probablly want to use dnsasync or dnssync or write a similar\r
- wrapper unit of thier own).\r
-\r
- for normal lookups call setstate_forward or setstate_reverse to set up the\r
- state, for more obscure lookups use setstate_request_init and fill in other\r
- relavent state manually.\r
-\r
- call state_process which will do processing on the information in the state\r
- and return an action\r
- action_ignore means that dnscore wants the code that calls it to go\r
- back to waiting for packets\r
- action_sendpacket means that dnscore wants the code that calls it to send\r
- the packet in sendpacket/sendpacketlen and then start (or go back to) listening\r
- for\r
- action_done means the request has completed (either suceeded or failed)\r
-\r
- callers should resend the last packet they tried to send if they have not\r
- been asked to send a new packet for more than some timeout value they choose.\r
-\r
- when a packet is received the application should put the packet in\r
- recvbuf/recvbuflen , set state.parsepacket and call state_process again\r
-\r
- once the app gets action_done it can determine sucess or failure in the\r
- following ways.\r
-\r
- on failure state.resultstr will be an empty string and state.resultbin will\r
- be zeroed out (easilly detected by the fact that it will have a family of 0)\r
-\r
- on success for a A or AAAA lookup state.resultstr will be an empty string\r
- and state.resultbin will contain the result (note: AAAA lookups require IPV6\r
- enabled).\r
-\r
- if an A lookup fails and the code is built with ipv6 enabled then the code\r
- will return any AAAA records with the same name. The reverse does not apply\r
- so if an application preffers IPV6 but wants IPV4 results as well it must\r
- check them seperately.\r
-\r
- on success for any other type of lookup state.resultstr will be an empty\r
-\r
- note the state contains ansistrings, setstate_init with a null name parameter\r
- can be used to clean theese up if required.\r
-\r
- callers may use setstate_failure to mark the state as failed themseleves\r
- before passing it on to other code, for example this may be done in the event\r
- of a timeout.\r
-}\r
-unit dnscore;\r
-\r
-\r
-\r
-{$ifdef fpc}{$mode delphi}{$endif}\r
-\r
-\r
-\r
-\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
-\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
- maxnamelength=127;\r
- maxnamefieldlen=63;\r
- //note: when using action_ignore the dnscore code *must* preserve the contents of state.sendpacket to allow for retries\r
- //note: action_ignore must not be used in response to the original request but there is no valid reason for doing this anyway\r
- action_ignore=0;\r
- action_done=1;\r
- action_sendquery=2;\r
- querytype_a=1;\r
- querytype_cname=5;\r
- querytype_aaaa=28;\r
- querytype_ptr=12;\r
- querytype_ns=2;\r
- querytype_soa=6;\r
- querytype_mx=15;\r
-\r
- maxrecursion=10;\r
- maxrrofakind=20;\r
-\r
- retryafter=300000; //microseconds must be less than one second;\r
- timeoutlag=1000000000; // penalty value to be treated as lag in the event of a timeout (microseconds)\r
-type\r
- dvar=array[0..0] of byte;\r
- pdvar=^dvar;\r
- tdnspacket=packed record\r
- id:word;\r
- flags:word;\r
- rrcount:array[0..3] of word;\r
- payload:array[0..511-12] of byte;\r
- end;\r
-\r
-\r
-\r
- tdnsstate=record\r
- id:word;\r
- recursioncount:integer;\r
- queryname:string;\r
- requesttype:word;\r
- parsepacket:boolean;\r
- resultstr:string;\r
- resultbin:tbinip;\r
- resultaction:integer;\r
- numrr1:array[0..3] of integer;\r
- numrr2:integer;\r
- rrdata:string;\r
- sendpacketlen:integer;\r
- sendpacket:tdnspacket;\r
- recvpacketlen:integer;\r
- recvpacket:tdnspacket;\r
- forwardfamily:integer;\r
- end;\r
-\r
- trr=packed record\r
- requesttypehi:byte;\r
- requesttype:byte;\r
- clas:word;\r
- ttl:integer;\r
- datalen:word;\r
- data:array[0..511] of byte;\r
- end;\r
-\r
- trrpointer=packed record\r
- p:pointer;\r
- ofs:integer;\r
- len:integer;\r
- namelen:integer;\r
- end;\r
-\r
-//commenting out functions from interface that do not have documented semantics\r
-//and probablly should not be called from outside this unit, reenable them\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
-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
-procedure setstate_forward(const name:string;var state:tdnsstate;family:integer);\r
-\r
-procedure setstate_reverse(const binip:tbinip;var state:tdnsstate);\r
-procedure setstate_failure(var state:tdnsstate);\r
-//procedure setstate_return(const rrp:trrpointer;len:integer;var state:tdnsstate);\r
-\r
-\r
-procedure state_process(var state:tdnsstate);\r
-\r
-//function decodename(const packet:tdnspacket;len,start,recursion:integer;var numread:integer):string;\r
-\r
-//presumablly this is exported to allow more secure random functions\r
-//to be substituted?\r
-var randomfunction:function:integer;\r
-\r
-\r
-procedure populatednsserverlist;\r
-procedure cleardnsservercache;\r
-\r
-var\r
- dnsserverlist : tstringlist;\r
-// currentdnsserverno : integer;\r
-\r
-function getcurrentsystemnameserver(var id:integer) :string;\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
-var\r
- failurereason:string;\r
-\r
-implementation\r
-\r
-uses\r
- {$ifdef win32}\r
- windows,\r
- {$endif}\r
-\r
- sysutils;\r
-\r
-function buildrequest(const name:string;var packet:tdnspacket;requesttype:word):integer;\r
-var\r
- a,b:integer;\r
- s:string;\r
- arr:array[0..sizeof(packet)-1] of byte absolute packet;\r
-begin\r
- { writeln('buildrequest: name: ',name);}\r
- result := 0;\r
- fillchar(packet,sizeof(packet),0);\r
- if assigned(randomfunction) then packet.id := (randomfunction and $ffff) else packet.id := random(65536);\r
- packet.flags := htons($0100);\r
- packet.rrcount[0] := htons($0001);\r
-\r
-\r
- s := copy(name,1,maxnamelength);\r
- if s = '' then exit;\r
- if s[length(s)] <> '.' then s := s + '.';\r
- b := 0;\r
- {encode name}\r
- if (s = '.') then begin\r
- packet.payload[0] := 0;\r
- result := 12+5;\r
- end else begin\r
- for a := 1 to length(s) do begin\r
- if s[a] = '.' then begin\r
- if b > maxnamefieldlen then exit;\r
- if (b = 0) then exit;\r
- packet.payload[a-b-1] := b;\r
- b := 0;\r
- end else begin\r
- packet.payload[a] := byte(s[a]);\r
- inc(b);\r
- end;\r
- end;\r
- if b > maxnamefieldlen then exit;\r
- packet.payload[length(s)-b] := b;\r
- result := length(s) + 12+5;\r
- end;\r
-\r
- arr[result-1] := 1;\r
- arr[result-3] := requesttype and $ff;\r
- arr[result-4] := requesttype shr 8;\r
-end;\r
-\r
-function makereversename(const binip:tbinip):string;\r
-var\r
- name:string;\r
- a,b:integer;\r
-begin\r
- name := '';\r
- if binip.family = AF_INET then begin\r
- b := htonl(binip.ip);\r
- for a := 0 to 3 do begin\r
- name := name + inttostr(b shr (a shl 3) and $ff)+'.';\r
- end;\r
- name := name + 'in-addr.arpa';\r
- end else\r
- {$ifdef ipv6}\r
- if binip.family = AF_INET6 then begin\r
- for a := 15 downto 0 do begin\r
- b := binip.ip6.u6_addr8[a];\r
- name := name + hexchars[b and $f]+'.'+hexchars[b shr 4]+'.';\r
- end;\r
- name := name + 'ip6.arpa';\r
- end else\r
- {$endif}\r
- begin\r
- {empty name}\r
- end;\r
- result := name;\r
-end;\r
-\r
-{\r
-decodes DNS format name to a string. does not includes the root dot.\r
-doesnt read beyond len.\r
-empty result + non null failurereason: failure\r
-empty result + null failurereason: internal use\r
-}\r
-function decodename(const packet:tdnspacket;len,start,recursion:integer;var numread:integer):string;\r
-var\r
- arr:array[0..sizeof(packet)-1] of byte absolute packet;\r
- s:string;\r
- a,b:integer;\r
-begin\r
- numread := 0;\r
- repeat\r
- if (start+numread < 0) or (start+numread >= len) then begin\r
- result := '';\r
- failurereason := 'decoding name: got out of range1';\r
- exit;\r
- end;\r
- b := arr[start+numread];\r
- if b >= $c0 then begin\r
- {recursive sub call}\r
- if recursion > 10 then begin\r
- result := '';\r
- failurereason := 'decoding name: max recursion';\r
- exit;\r
- end;\r
- if ((start+numread+1) >= len) then begin\r
- result := '';\r
- failurereason := 'decoding name: got out of range3';\r
- exit;\r
- end;\r
- a := ((b shl 8) or arr[start+numread+1]) and $3fff;\r
- s := decodename(packet,len,a,recursion+1,a);\r
- if (s = '') and (failurereason <> '') then begin\r
- result := '';\r
- exit;\r
- end;\r
- if result <> '' then result := result + '.';\r
- result := result + s;\r
- inc(numread,2);\r
- exit;\r
- end else if b < 64 then begin\r
- if (numread <> 0) and (b <> 0) then result := result + '.';\r
- for a := start+numread+1 to start+numread+b do begin\r
- if (a >= len) then begin\r
- result := '';\r
- failurereason := 'decoding name: got out of range2';\r
- exit;\r
- end;\r
- result := result + char(arr[a]);\r
- end;\r
- inc(numread,b+1);\r
-\r
- if b = 0 then begin\r
- if (result = '') and (recursion = 0) then result := '.';\r
- exit; {reached end of name}\r
- end;\r
- end else begin\r
- failurereason := 'decoding name: read invalid char';\r
- result := '';\r
- exit; {invalid}\r
- end;\r
- until false;\r
-end;\r
-\r
-{==============================================================================}\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: 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
- 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
- end;\r
- {$endif}\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
- fillchar(state.resultbin,sizeof(state.resultbin),0);\r
- end;\r
-end;\r
-\r
-procedure setstate_request_init(const name:string;var state:tdnsstate);\r
-begin\r
- {destroy things properly}\r
- state.resultstr := '';\r
- state.queryname := '';\r
- state.rrdata := '';\r
- fillchar(state,sizeof(state),0);\r
- state.queryname := name;\r
- state.parsepacket := false;\r
-end;\r
-\r
-procedure setstate_forward(const name:string;var state:tdnsstate;family:integer);\r
-begin\r
- setstate_request_init(name,state);\r
- state.forwardfamily := family;\r
- {$ifdef ipv6}\r
- if family = AF_INET6 then state.requesttype := querytype_aaaa else\r
- {$endif}\r
- state.requesttype := querytype_a;\r
-end;\r
-\r
-procedure setstate_reverse(const binip:tbinip;var state:tdnsstate);\r
-begin\r
- setstate_request_init(makereversename(binip),state);\r
- state.requesttype := querytype_ptr;\r
-end;\r
-\r
-procedure setstate_failure(var state:tdnsstate);\r
-begin\r
- state.resultstr := '';\r
- fillchar(state.resultbin,sizeof(state.resultbin),0);\r
- state.resultaction := action_done;\r
-end;\r
-\r
-procedure state_process(var state:tdnsstate);\r
-label recursed;\r
-label failure;\r
-var\r
- a,b,ofs:integer;\r
- rrtemp:^trr;\r
- rrptemp:^trrpointer;\r
-begin\r
- if state.parsepacket then begin\r
- if state.recvpacketlen < 12 then begin\r
- failurereason := 'Undersized packet';\r
- state.resultaction := action_ignore;\r
- exit;\r
- end;\r
- if state.id <> state.recvpacket.id then begin\r
- failurereason := 'ID mismatch';\r
- state.resultaction := action_ignore;\r
- exit;\r
- end;\r
- state.numrr2 := 0;\r
- for a := 0 to 3 do begin\r
- state.numrr1[a] := htons(state.recvpacket.rrcount[a]);\r
- if state.numrr1[a] > maxrrofakind then goto failure;\r
- inc(state.numrr2,state.numrr1[a]);\r
- end;\r
-\r
- setlength(state.rrdata,state.numrr2*sizeof(trrpointer));\r
-\r
- {- put all replies into a list}\r
-\r
- ofs := 12;\r
- {get all queries}\r
- for a := 0 to state.numrr1[0]-1 do begin\r
- if (ofs < 12) or (ofs > state.recvpacketlen-4) then goto failure;\r
- rrptemp := @state.rrdata[1+a*sizeof(trrpointer)];\r
- rrptemp.p := @state.recvpacket.payload[ofs-12];\r
- rrptemp.ofs := ofs;\r
- decodename(state.recvpacket,state.recvpacketlen,ofs,0,b);\r
- rrptemp.len := b + 4;\r
- inc(ofs,rrptemp.len);\r
- end;\r
-\r
- for a := state.numrr1[0] to state.numrr2-1 do begin\r
- if (ofs < 12) or (ofs > state.recvpacketlen-12) then goto failure;\r
- rrptemp := @state.rrdata[1+a*sizeof(trrpointer)];\r
- if decodename(state.recvpacket,state.recvpacketlen,ofs,0,b) = '' then goto failure;\r
- rrtemp := @state.recvpacket.payload[ofs-12+b]; {rrtemp points to values and result, after initial name}\r
- rrptemp.p := rrtemp;\r
- rrptemp.ofs := ofs; {ofs is start of RR before initial name from start of packet}\r
- rrptemp.namelen := b;\r
- b := htons(rrtemp.datalen);\r
- rrptemp.len := b + 10 + rrptemp.namelen;\r
- inc(ofs,rrptemp.len);\r
- end;\r
- if (ofs <> state.recvpacketlen) then begin\r
- failurereason := 'ofs <> state.packetlen';\r
- goto failure;\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
- rrtemp := rrptemp.p;\r
- b := rrptemp.len;\r
- if rrtemp.requesttype = state.requesttype then begin\r
- setstate_return(rrptemp^,b,state);\r
- exit;\r
- end;\r
- end;\r
-\r
- {if no items of correct type found, follow first cname in answer section}\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 = querytype_cname then begin\r
- state.queryname := decodename(state.recvpacket,state.recvpacketlen,rrptemp.ofs+12,0,b);\r
- goto recursed;\r
- end;\r
- end;\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
- goto failure;\r
-recursed:\r
- {here it needs recursed lookup}\r
- {if needing to follow a cname, change state to do so}\r
- inc(state.recursioncount);\r
- if state.recursioncount > maxrecursion then goto failure;\r
- end;\r
-\r
- {here, a name needs to be resolved}\r
- if state.queryname = '' then begin\r
- failurereason := 'empty query name';\r
- goto failure;\r
- end;\r
-\r
- {do /ets/hosts lookup here}\r
- state.sendpacketlen := buildrequest(state.queryname,state.sendpacket,state.requesttype);\r
- if state.sendpacketlen = 0 then begin\r
- failurereason := 'building request packet failed';\r
- goto failure;\r
- end;\r
- state.id := state.sendpacket.id;\r
- state.resultaction := action_sendquery;\r
-\r
- exit;\r
-failure:\r
- setstate_failure(state);\r
-end;\r
-{$ifdef win32}\r
- const\r
- MAX_HOSTNAME_LEN = 132;\r
- MAX_DOMAIN_NAME_LEN = 132;\r
- MAX_SCOPE_ID_LEN = 260 ;\r
- MAX_ADAPTER_NAME_LENGTH = 260;\r
- MAX_ADAPTER_ADDRESS_LENGTH = 8;\r
- MAX_ADAPTER_DESCRIPTION_LENGTH = 132;\r
- ERROR_BUFFER_OVERFLOW = 111;\r
- MIB_IF_TYPE_ETHERNET = 6;\r
- MIB_IF_TYPE_TOKENRING = 9;\r
- MIB_IF_TYPE_FDDI = 15;\r
- MIB_IF_TYPE_PPP = 23;\r
- MIB_IF_TYPE_LOOPBACK = 24;\r
- MIB_IF_TYPE_SLIP = 28;\r
-\r
-\r
- type\r
- tip_addr_string=packed record\r
- Next :pointer;\r
- IpAddress : array[0..15] of char;\r
- ipmask : array[0..15] of char;\r
- context : dword;\r
- end;\r
- pip_addr_string=^tip_addr_string;\r
- tFIXED_INFO=packed record\r
- HostName : array[0..MAX_HOSTNAME_LEN-1] of char;\r
- DomainName : array[0..MAX_DOMAIN_NAME_LEN-1] of char;\r
- currentdnsserver : pip_addr_string;\r
- dnsserverlist : tip_addr_string;\r
- nodetype : longint;\r
- ScopeId : array[0..MAX_SCOPE_ID_LEN + 4] of char;\r
- enablerouting : longbool;\r
- enableproxy : longbool;\r
- enabledns : longbool;\r
- end;\r
- pFIXED_INFO=^tFIXED_INFO;\r
-\r
- var\r
- iphlpapi : thandle;\r
- getnetworkparams : function(pFixedInfo : PFIXED_INFO;OutBufLen : plongint) : longint;stdcall;\r
-{$endif}\r
-procedure populatednsserverlist;\r
-var\r
- {$ifdef win32}\r
- fixed_info : pfixed_info;\r
- fixed_info_len : longint;\r
- currentdnsserver : pip_addr_string;\r
- {$else}\r
- t:textfile;\r
- s:string;\r
- a:integer;\r
- {$endif}\r
-begin\r
- //result := '';\r
- if assigned(dnsserverlist) then begin\r
- dnsserverlist.clear;\r
- end else begin\r
- dnsserverlist := tstringlist.Create;\r
- end;\r
- {$ifdef win32}\r
- if iphlpapi=0 then iphlpapi := loadlibrary('iphlpapi.dll');\r
- if not assigned(getnetworkparams) then @getnetworkparams := getprocaddress(iphlpapi,'GetNetworkParams');\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
- getmem(fixed_info,fixed_info_len);\r
- if GetNetworkParams(fixed_info,@fixed_info_len)<>0 then begin\r
- freemem(fixed_info);\r
- exit;\r
- end;\r
- currentdnsserver := @(fixed_info.dnsserverlist);\r
- while assigned(currentdnsserver) do begin\r
- dnsserverlist.Add(currentdnsserver.IpAddress);\r
- currentdnsserver := currentdnsserver.next;\r
- end;\r
- freemem(fixed_info);\r
- {$else}\r
- filemode := 0;\r
- assignfile(t,'/etc/resolv.conf');\r
- {$i-}reset(t);{$i+}\r
- if ioresult <> 0 then exit;\r
-\r
- while not eof(t) do begin\r
- readln(t,s);\r
- if not (copy(s,1,10) = 'nameserver') then continue;\r
- s := copy(s,11,500);\r
- while s <> '' do begin\r
- if (s[1] = #32) or (s[1] = #9) then s := copy(s,2,500) else break;\r
- end;\r
- a := pos(' ',s);\r
- if a <> 0 then s := copy(s,1,a-1);\r
- a := pos(#9,s);\r
- if a <> 0 then s := copy(s,1,a-1);\r
- //result := s;\r
- //if result <> '' then break;\r
- dnsserverlist.Add(s);\r
- end;\r
- close(t);\r
- {$endif}\r
-end;\r
-\r
-procedure cleardnsservercache;\r
-begin\r
- if assigned(dnsserverlist) then begin\r
- dnsserverlist.destroy;\r
- dnsserverlist := nil;\r
- end;\r
-end;\r
-\r
-function getcurrentsystemnameserver(var id:integer):string;\r
-var \r
- counter : integer;\r
-\r
-begin\r
- if not assigned(dnsserverlist) then populatednsserverlist;\r
- if dnsserverlist.count=0 then raise exception.create('no dns servers availible');\r
- id := 0;\r
- if dnsserverlist.count >1 then begin\r
-\r
- for counter := 1 to dnsserverlist.count-1 do begin\r
- if taddrint(dnsserverlist.objects[counter]) < taddrint(dnsserverlist.objects[id]) then id := counter;\r
- end;\r
- end;\r
- result := dnsserverlist[id]\r
-end;\r
-\r
-procedure reportlag(id:integer;lag:integer); //lag should be in microseconds and should be -1 to report a timeout\r
-var\r
- counter : integer;\r
- temp : integer;\r
-begin\r
- if (id < 0) or (id >= dnsserverlist.count) then exit;\r
- if lag = -1 then lag := timeoutlag;\r
- for counter := 0 to dnsserverlist.count-1 do begin\r
- temp := taddrint(dnsserverlist.objects[counter]) *15;\r
- if counter=id then temp := temp + lag;\r
- dnsserverlist.objects[counter] := tobject(temp div 16);\r
- end;\r
-\r
-end;\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
-\r
-www.google.com A request:\r
-\r
-0, 2: random transaction ID\r
-2, 2: flags: only the "recursion desired" bit set. (bit 8 of word)\r
-4, 2: questions: 1\r
-6, 2: answer RR's: 0.\r
-8, 2: authority RR's: 0.\r
-10, 2: additional RR's: 0.\r
-12, n: payload:\r
- query:\r
- #03 "www" #06 "google" #03 "com" #00\r
- size-4, 2: type: host address (1)\r
- size-2, 2: class: inet (1)\r
-\r
-reply:\r
-\r
-0,2: random transaction ID\r
-2,2: flags: set: response (bit 15), recursion desired (8), recursion available (7)\r
-4,4: questions: 1\r
-6,4: answer RR's: 2\r
-8,4: authority RR's: 9\r
-10,4: additional RR's: 9\r
-12: payload:\r
- query:\r
- ....\r
- answer: CNAME\r
- 0,2 "c0 0c" "name: www.google.com"\r
- 2,2 "00 05" "type: cname for an alias"\r
- 4,2 "00 01" "class: inet"\r
- 6,4: TTL\r
- 10,2: data length "00 17" (23)\r
- 12: the cname name (www.google.akadns.net)\r
- answer: A\r
- 0,2 ..\r
- 2,2 "00 01" host address\r
- 4,2 ...\r
- 6,4 ...\r
- 10,2: data length (4)\r
- 12,4: binary IP\r
- authority - 9 records\r
- additional - 9 records\r
-\r
-\r
- ipv6 AAAA reply:\r
- 0,2: ...\r
- 2,2: type: 001c\r
- 4,2: class: inet (0001)\r
- 6,2: TTL\r
- 10,2: data size (16)\r
- 12,16: binary IP\r
-\r
- ptr request: query type 000c\r
-\r
-name compression: word "cxxx" in the name, xxx points to offset in the packet}\r
-\r
-end.\r