/[lcore]/trunk/httpserver_20080306/dnscore.pas
ViewVC logotype

Contents of /trunk/httpserver_20080306/dnscore.pas

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1 - (show annotations)
Fri Mar 28 02:26:58 2008 UTC (12 years ago) by plugwash
File size: 22330 byte(s)
initial import

1 { Copyright (C) 2005 Bas Steendijk and Peter Green
2 For conditions of distribution and use, see copyright notice in zlib_license.txt
3 which is included in the package
4 ----------------------------------------------------------------------------- }
5
6 {
7
8 code wanting to use this dns system should act as follows (note: app
9 developers will probablly want to use dnsasync or dnssync or write a similar
10 wrapper unit of thier own).
11
12 for normal lookups call setstate_forward or setstate_reverse to set up the
13 state, for more obscure lookups use setstate_request_init and fill in other
14 relavent state manually.
15
16 call state_process which will do processing on the information in the state
17 and return an action
18 action_ignore means that dnscore wants the code that calls it to go
19 back to waiting for packets
20 action_sendpacket means that dnscore wants the code that calls it to send
21 the packet in sendpacket/sendpacketlen and then start (or go back to) listening
22 for
23 action_done means the request has completed (either suceeded or failed)
24
25 callers should resend the last packet they tried to send if they have not
26 been asked to send a new packet for more than some timeout value they choose.
27
28 when a packet is received the application should put the packet in
29 recvbuf/recvbuflen , set state.parsepacket and call state_process again
30
31 once the app gets action_done it can determine sucess or failure in the
32 following ways.
33
34 on failure state.resultstr will be an empty string and state.resultbin will
35 be zeroed out (easilly detected by the fact that it will have a family of 0)
36
37 on success for a A or AAAA lookup state.resultstr will be an empty string
38 and state.resultbin will contain the result (note: AAAA lookups require IPV6
39 enabled).
40
41 if an A lookup fails and the code is built with ipv6 enabled then the code
42 will return any AAAA records with the same name. The reverse does not apply
43 so if an application preffers IPV6 but wants IPV4 results as well it must
44 check them seperately.
45
46 on success for any other type of lookup state.resultstr will be an empty
47
48 note the state contains ansistrings, setstate_init with a null name parameter
49 can be used to clean theese up if required.
50
51 callers may use setstate_failure to mark the state as failed themseleves
52 before passing it on to other code, for example this may be done in the event
53 of a timeout.
54 }
55 unit dnscore;
56
57
58
59 {$ifdef fpc}{$mode delphi}{$endif}
60
61
62
63
64
65 interface
66
67 uses binipstuff,classes,pgtypes;
68
69 var usewindns : boolean = {$ifdef win32}true{$else}false{$endif};
70 //hint to users of this unit that they should use windows dns instead.
71 //May be disabled by applications if desired. (e.g. if setting a custom
72 //dnsserverlist).
73
74 //note: this unit will not be able to self populate it's dns server list on
75 //older versions of windows.
76
77 const
78 maxnamelength=127;
79 maxnamefieldlen=63;
80 //note: when using action_ignore the dnscore code *must* preserve the contents of state.sendpacket to allow for retries
81 //note: action_ignore must not be used in response to the original request but there is no valid reason for doing this anyway
82 action_ignore=0;
83 action_done=1;
84 action_sendquery=2;
85 querytype_a=1;
86 querytype_cname=5;
87 querytype_aaaa=28;
88 querytype_ptr=12;
89 querytype_ns=2;
90 querytype_soa=6;
91 querytype_mx=15;
92
93 maxrecursion=10;
94 maxrrofakind=20;
95
96 retryafter=300000; //microseconds must be less than one second;
97 timeoutlag=1000000000; // penalty value to be treated as lag in the event of a timeout (microseconds)
98 type
99 dvar=array[0..0] of byte;
100 pdvar=^dvar;
101 tdnspacket=packed record
102 id:word;
103 flags:word;
104 rrcount:array[0..3] of word;
105 payload:array[0..511-12] of byte;
106 end;
107
108
109
110 tdnsstate=record
111 id:word;
112 recursioncount:integer;
113 queryname:string;
114 requesttype:word;
115 parsepacket:boolean;
116 resultstr:string;
117 resultbin:tbinip;
118 resultaction:integer;
119 numrr1:array[0..3] of integer;
120 numrr2:integer;
121 rrdata:string;
122 sendpacketlen:integer;
123 sendpacket:tdnspacket;
124 recvpacketlen:integer;
125 recvpacket:tdnspacket;
126 forwardfamily:integer;
127 end;
128
129 trr=packed record
130 requesttypehi:byte;
131 requesttype:byte;
132 clas:word;
133 ttl:integer;
134 datalen:word;
135 data:array[0..511] of byte;
136 end;
137
138 trrpointer=packed record
139 p:pointer;
140 ofs:integer;
141 len:integer;
142 namelen:integer;
143 end;
144
145 //commenting out functions from interface that do not have documented semantics
146 //and probablly should not be called from outside this unit, reenable them
147 //if you must but please document them at the same time --plugwash
148
149 //function buildrequest(const name:string;var packet:tdnspacket;requesttype:word):integer;
150 //function makereversename(const binip:tbinip):string;
151
152 procedure setstate_request_init(const name:string;var state:tdnsstate);
153
154 //set up state for a foward lookup. A family value of AF_INET6 will give only
155 //ipv6 results. Any other value will give ipv4 results in preference and ipv6
156 //results if ipv4 results are not available;
157 procedure setstate_forward(const name:string;var state:tdnsstate;family:integer);
158
159 procedure setstate_reverse(const binip:tbinip;var state:tdnsstate);
160 procedure setstate_failure(var state:tdnsstate);
161 //procedure setstate_return(const rrp:trrpointer;len:integer;var state:tdnsstate);
162
163
164 procedure state_process(var state:tdnsstate);
165
166 //function decodename(const packet:tdnspacket;len,start,recursion:integer;var numread:integer):string;
167
168 //presumablly this is exported to allow more secure random functions
169 //to be substituted?
170 var randomfunction:function:integer;
171
172
173 procedure populatednsserverlist;
174 procedure cleardnsservercache;
175
176 var
177 dnsserverlist : tstringlist;
178 // currentdnsserverno : integer;
179
180 function getcurrentsystemnameserver(var id:integer) :string;
181
182 //var
183 // unixnameservercache:string;
184 { $endif}
185
186
187 procedure reportlag(id:integer;lag:integer); //lag should be in microseconds and should be -1 to report a timeout
188 var
189 failurereason:string;
190
191 implementation
192
193 uses
194 {$ifdef win32}
195 windows,
196 {$endif}
197
198 sysutils;
199
200 function buildrequest(const name:string;var packet:tdnspacket;requesttype:word):integer;
201 var
202 a,b:integer;
203 s:string;
204 arr:array[0..sizeof(packet)-1] of byte absolute packet;
205 begin
206 { writeln('buildrequest: name: ',name);}
207 result := 0;
208 fillchar(packet,sizeof(packet),0);
209 if assigned(randomfunction) then packet.id := (randomfunction and $ffff) else packet.id := random(65536);
210 packet.flags := htons($0100);
211 packet.rrcount[0] := htons($0001);
212
213
214 s := copy(name,1,maxnamelength);
215 if s = '' then exit;
216 if s[length(s)] <> '.' then s := s + '.';
217 b := 0;
218 {encode name}
219 if (s = '.') then begin
220 packet.payload[0] := 0;
221 result := 12+5;
222 end else begin
223 for a := 1 to length(s) do begin
224 if s[a] = '.' then begin
225 if b > maxnamefieldlen then exit;
226 if (b = 0) then exit;
227 packet.payload[a-b-1] := b;
228 b := 0;
229 end else begin
230 packet.payload[a] := byte(s[a]);
231 inc(b);
232 end;
233 end;
234 if b > maxnamefieldlen then exit;
235 packet.payload[length(s)-b] := b;
236 result := length(s) + 12+5;
237 end;
238
239 arr[result-1] := 1;
240 arr[result-3] := requesttype and $ff;
241 arr[result-4] := requesttype shr 8;
242 end;
243
244 function makereversename(const binip:tbinip):string;
245 var
246 name:string;
247 a,b:integer;
248 begin
249 name := '';
250 if binip.family = AF_INET then begin
251 b := htonl(binip.ip);
252 for a := 0 to 3 do begin
253 name := name + inttostr(b shr (a shl 3) and $ff)+'.';
254 end;
255 name := name + 'in-addr.arpa';
256 end else
257 {$ifdef ipv6}
258 if binip.family = AF_INET6 then begin
259 for a := 15 downto 0 do begin
260 b := binip.ip6.u6_addr8[a];
261 name := name + hexchars[b and $f]+'.'+hexchars[b shr 4]+'.';
262 end;
263 name := name + 'ip6.arpa';
264 end else
265 {$endif}
266 begin
267 {empty name}
268 end;
269 result := name;
270 end;
271
272 {
273 decodes DNS format name to a string. does not includes the root dot.
274 doesnt read beyond len.
275 empty result + non null failurereason: failure
276 empty result + null failurereason: internal use
277 }
278 function decodename(const packet:tdnspacket;len,start,recursion:integer;var numread:integer):string;
279 var
280 arr:array[0..sizeof(packet)-1] of byte absolute packet;
281 s:string;
282 a,b:integer;
283 begin
284 numread := 0;
285 repeat
286 if (start+numread < 0) or (start+numread >= len) then begin
287 result := '';
288 failurereason := 'decoding name: got out of range1';
289 exit;
290 end;
291 b := arr[start+numread];
292 if b >= $c0 then begin
293 {recursive sub call}
294 if recursion > 10 then begin
295 result := '';
296 failurereason := 'decoding name: max recursion';
297 exit;
298 end;
299 if ((start+numread+1) >= len) then begin
300 result := '';
301 failurereason := 'decoding name: got out of range3';
302 exit;
303 end;
304 a := ((b shl 8) or arr[start+numread+1]) and $3fff;
305 s := decodename(packet,len,a,recursion+1,a);
306 if (s = '') and (failurereason <> '') then begin
307 result := '';
308 exit;
309 end;
310 if result <> '' then result := result + '.';
311 result := result + s;
312 inc(numread,2);
313 exit;
314 end else if b < 64 then begin
315 if (numread <> 0) and (b <> 0) then result := result + '.';
316 for a := start+numread+1 to start+numread+b do begin
317 if (a >= len) then begin
318 result := '';
319 failurereason := 'decoding name: got out of range2';
320 exit;
321 end;
322 result := result + char(arr[a]);
323 end;
324 inc(numread,b+1);
325
326 if b = 0 then begin
327 if (result = '') and (recursion = 0) then result := '.';
328 exit; {reached end of name}
329 end;
330 end else begin
331 failurereason := 'decoding name: read invalid char';
332 result := '';
333 exit; {invalid}
334 end;
335 until false;
336 end;
337
338 {==============================================================================}
339
340 procedure setstate_return(const rrp:trrpointer;len:integer;var state:tdnsstate);
341 var
342 a:integer;
343 begin
344 state.resultaction := action_done;
345 state.resultstr := '';
346 case trr(rrp.p^).requesttype of
347 querytype_a: begin
348 if htons(trr(rrp.p^).datalen) <> 4 then exit;
349 move(trr(rrp.p^).data,state.resultbin.ip,4);
350 state.resultbin.family :=AF_INET;
351 end;
352 {$ifdef ipv6}
353 querytype_aaaa: begin
354 if htons(trr(rrp.p^).datalen) <> 16 then exit;
355 state.resultbin.family := AF_INET6;
356 move(trr(rrp.p^).data,state.resultbin.ip6,16);
357 end;
358 {$endif}
359 else
360 {other reply types (PTR, MX) return a hostname}
361 state.resultstr := decodename(state.recvpacket,state.recvpacketlen,taddrint(rrp.p)-taddrint(@state.recvpacket)+10,0,a);
362 fillchar(state.resultbin,sizeof(state.resultbin),0);
363 end;
364 end;
365
366 procedure setstate_request_init(const name:string;var state:tdnsstate);
367 begin
368 {destroy things properly}
369 state.resultstr := '';
370 state.queryname := '';
371 state.rrdata := '';
372 fillchar(state,sizeof(state),0);
373 state.queryname := name;
374 state.parsepacket := false;
375 end;
376
377 procedure setstate_forward(const name:string;var state:tdnsstate;family:integer);
378 begin
379 setstate_request_init(name,state);
380 state.forwardfamily := family;
381 {$ifdef ipv6}
382 if family = AF_INET6 then state.requesttype := querytype_aaaa else
383 {$endif}
384 state.requesttype := querytype_a;
385 end;
386
387 procedure setstate_reverse(const binip:tbinip;var state:tdnsstate);
388 begin
389 setstate_request_init(makereversename(binip),state);
390 state.requesttype := querytype_ptr;
391 end;
392
393 procedure setstate_failure(var state:tdnsstate);
394 begin
395 state.resultstr := '';
396 fillchar(state.resultbin,sizeof(state.resultbin),0);
397 state.resultaction := action_done;
398 end;
399
400 procedure state_process(var state:tdnsstate);
401 label recursed;
402 label failure;
403 var
404 a,b,ofs:integer;
405 rrtemp:^trr;
406 rrptemp:^trrpointer;
407 begin
408 if state.parsepacket then begin
409 if state.recvpacketlen < 12 then begin
410 failurereason := 'Undersized packet';
411 state.resultaction := action_ignore;
412 exit;
413 end;
414 if state.id <> state.recvpacket.id then begin
415 failurereason := 'ID mismatch';
416 state.resultaction := action_ignore;
417 exit;
418 end;
419 state.numrr2 := 0;
420 for a := 0 to 3 do begin
421 state.numrr1[a] := htons(state.recvpacket.rrcount[a]);
422 if state.numrr1[a] > maxrrofakind then goto failure;
423 inc(state.numrr2,state.numrr1[a]);
424 end;
425
426 setlength(state.rrdata,state.numrr2*sizeof(trrpointer));
427
428 {- put all replies into a list}
429
430 ofs := 12;
431 {get all queries}
432 for a := 0 to state.numrr1[0]-1 do begin
433 if (ofs < 12) or (ofs > state.recvpacketlen-4) then goto failure;
434 rrptemp := @state.rrdata[1+a*sizeof(trrpointer)];
435 rrptemp.p := @state.recvpacket.payload[ofs-12];
436 rrptemp.ofs := ofs;
437 decodename(state.recvpacket,state.recvpacketlen,ofs,0,b);
438 rrptemp.len := b + 4;
439 inc(ofs,rrptemp.len);
440 end;
441
442 for a := state.numrr1[0] to state.numrr2-1 do begin
443 if (ofs < 12) or (ofs > state.recvpacketlen-12) then goto failure;
444 rrptemp := @state.rrdata[1+a*sizeof(trrpointer)];
445 if decodename(state.recvpacket,state.recvpacketlen,ofs,0,b) = '' then goto failure;
446 rrtemp := @state.recvpacket.payload[ofs-12+b]; {rrtemp points to values and result, after initial name}
447 rrptemp.p := rrtemp;
448 rrptemp.ofs := ofs; {ofs is start of RR before initial name from start of packet}
449 rrptemp.namelen := b;
450 b := htons(rrtemp.datalen);
451 rrptemp.len := b + 10 + rrptemp.namelen;
452 inc(ofs,rrptemp.len);
453 end;
454 if (ofs <> state.recvpacketlen) then begin
455 failurereason := 'ofs <> state.packetlen';
456 goto failure;
457 end;
458
459 {- check for items of the requested type in answer section, if so return success first}
460 for a := state.numrr1[0] to (state.numrr1[0]+state.numrr1[1]-1) do begin
461 rrptemp := @state.rrdata[1+a*sizeof(trrpointer)];
462 rrtemp := rrptemp.p;
463 b := rrptemp.len;
464 if rrtemp.requesttype = state.requesttype then begin
465 setstate_return(rrptemp^,b,state);
466 exit;
467 end;
468 end;
469
470 {if no items of correct type found, follow first cname in answer section}
471 for a := state.numrr1[0] to (state.numrr1[0]+state.numrr1[1]-1) do begin
472 rrptemp := @state.rrdata[1+a*sizeof(trrpointer)];
473 rrtemp := rrptemp.p;
474 b := rrptemp.len;
475 if rrtemp.requesttype = querytype_cname then begin
476 state.queryname := decodename(state.recvpacket,state.recvpacketlen,rrptemp.ofs+12,0,b);
477 goto recursed;
478 end;
479 end;
480
481 {no cnames found, no items of correct type found}
482 if state.forwardfamily <> 0 then goto failure;
483 {$ifdef ipv6}
484 if (state.requesttype = querytype_a) then begin
485 {v6 only: in case of forward, look for AAAA in alternative section}
486 for a := state.numrr1[0]+state.numrr1[1]+state.numrr1[2] to (state.numrr2-1) do begin
487 rrptemp := @state.rrdata[1+a*sizeof(trrpointer)];
488 rrtemp := rrptemp.p;
489 b := rrptemp.len;
490 if rrtemp.requesttype = querytype_aaaa then begin
491 setstate_return(rrptemp^,b,state);
492 exit;
493 end;
494 end;
495 {no AAAA's found in alternative, do a recursive lookup for them}
496 state.requesttype := querytype_aaaa;
497 goto recursed;
498 end;
499 {$endif}
500 goto failure;
501 recursed:
502 {here it needs recursed lookup}
503 {if needing to follow a cname, change state to do so}
504 inc(state.recursioncount);
505 if state.recursioncount > maxrecursion then goto failure;
506 end;
507
508 {here, a name needs to be resolved}
509 if state.queryname = '' then begin
510 failurereason := 'empty query name';
511 goto failure;
512 end;
513
514 {do /ets/hosts lookup here}
515 state.sendpacketlen := buildrequest(state.queryname,state.sendpacket,state.requesttype);
516 if state.sendpacketlen = 0 then begin
517 failurereason := 'building request packet failed';
518 goto failure;
519 end;
520 state.id := state.sendpacket.id;
521 state.resultaction := action_sendquery;
522
523 exit;
524 failure:
525 setstate_failure(state);
526 end;
527 {$ifdef win32}
528 const
529 MAX_HOSTNAME_LEN = 132;
530 MAX_DOMAIN_NAME_LEN = 132;
531 MAX_SCOPE_ID_LEN = 260 ;
532 MAX_ADAPTER_NAME_LENGTH = 260;
533 MAX_ADAPTER_ADDRESS_LENGTH = 8;
534 MAX_ADAPTER_DESCRIPTION_LENGTH = 132;
535 ERROR_BUFFER_OVERFLOW = 111;
536 MIB_IF_TYPE_ETHERNET = 6;
537 MIB_IF_TYPE_TOKENRING = 9;
538 MIB_IF_TYPE_FDDI = 15;
539 MIB_IF_TYPE_PPP = 23;
540 MIB_IF_TYPE_LOOPBACK = 24;
541 MIB_IF_TYPE_SLIP = 28;
542
543
544 type
545 tip_addr_string=packed record
546 Next :pointer;
547 IpAddress : array[0..15] of char;
548 ipmask : array[0..15] of char;
549 context : dword;
550 end;
551 pip_addr_string=^tip_addr_string;
552 tFIXED_INFO=packed record
553 HostName : array[0..MAX_HOSTNAME_LEN-1] of char;
554 DomainName : array[0..MAX_DOMAIN_NAME_LEN-1] of char;
555 currentdnsserver : pip_addr_string;
556 dnsserverlist : tip_addr_string;
557 nodetype : longint;
558 ScopeId : array[0..MAX_SCOPE_ID_LEN + 4] of char;
559 enablerouting : longbool;
560 enableproxy : longbool;
561 enabledns : longbool;
562 end;
563 pFIXED_INFO=^tFIXED_INFO;
564
565 var
566 iphlpapi : thandle;
567 getnetworkparams : function(pFixedInfo : PFIXED_INFO;OutBufLen : plongint) : longint;stdcall;
568 {$endif}
569 procedure populatednsserverlist;
570 var
571 {$ifdef win32}
572 fixed_info : pfixed_info;
573 fixed_info_len : longint;
574 currentdnsserver : pip_addr_string;
575 {$else}
576 t:textfile;
577 s:string;
578 a:integer;
579 {$endif}
580 begin
581 //result := '';
582 if assigned(dnsserverlist) then begin
583 dnsserverlist.clear;
584 end else begin
585 dnsserverlist := tstringlist.Create;
586 end;
587 {$ifdef win32}
588 if iphlpapi=0 then iphlpapi := loadlibrary('iphlpapi.dll');
589 if not assigned(getnetworkparams) then @getnetworkparams := getprocaddress(iphlpapi,'GetNetworkParams');
590 fixed_info_len := 0;
591 if GetNetworkParams(nil,@fixed_info_len)<>ERROR_BUFFER_OVERFLOW then exit;
592 //fixed_info_len :=sizeof(tfixed_info);
593 getmem(fixed_info,fixed_info_len);
594 if GetNetworkParams(fixed_info,@fixed_info_len)<>0 then begin
595 freemem(fixed_info);
596 exit;
597 end;
598 currentdnsserver := @(fixed_info.dnsserverlist);
599 while assigned(currentdnsserver) do begin
600 dnsserverlist.Add(currentdnsserver.IpAddress);
601 currentdnsserver := currentdnsserver.next;
602 end;
603 freemem(fixed_info);
604 {$else}
605 filemode := 0;
606 assignfile(t,'/etc/resolv.conf');
607 {$i-}reset(t);{$i+}
608 if ioresult <> 0 then exit;
609
610 while not eof(t) do begin
611 readln(t,s);
612 if not (copy(s,1,10) = 'nameserver') then continue;
613 s := copy(s,11,500);
614 while s <> '' do begin
615 if (s[1] = #32) or (s[1] = #9) then s := copy(s,2,500) else break;
616 end;
617 a := pos(' ',s);
618 if a <> 0 then s := copy(s,1,a-1);
619 a := pos(#9,s);
620 if a <> 0 then s := copy(s,1,a-1);
621 //result := s;
622 //if result <> '' then break;
623 dnsserverlist.Add(s);
624 end;
625 close(t);
626 {$endif}
627 end;
628
629 procedure cleardnsservercache;
630 begin
631 if assigned(dnsserverlist) then begin
632 dnsserverlist.destroy;
633 dnsserverlist := nil;
634 end;
635 end;
636
637 function getcurrentsystemnameserver(var id:integer):string;
638 var
639 counter : integer;
640
641 begin
642 if not assigned(dnsserverlist) then populatednsserverlist;
643 if dnsserverlist.count=0 then raise exception.create('no dns servers availible');
644 id := 0;
645 if dnsserverlist.count >1 then begin
646
647 for counter := 1 to dnsserverlist.count-1 do begin
648 if taddrint(dnsserverlist.objects[counter]) < taddrint(dnsserverlist.objects[id]) then id := counter;
649 end;
650 end;
651 result := dnsserverlist[id]
652 end;
653
654 procedure reportlag(id:integer;lag:integer); //lag should be in microseconds and should be -1 to report a timeout
655 var
656 counter : integer;
657 temp : integer;
658 begin
659 if (id < 0) or (id >= dnsserverlist.count) then exit;
660 if lag = -1 then lag := timeoutlag;
661 for counter := 0 to dnsserverlist.count-1 do begin
662 temp := taddrint(dnsserverlist.objects[counter]) *15;
663 if counter=id then temp := temp + lag;
664 dnsserverlist.objects[counter] := tobject(temp div 16);
665 end;
666
667 end;
668
669 { quick and dirty description of dns packet structure to aid writing and
670 understanding of parser code, refer to appropriate RFCs for proper specs
671 - all words are network order
672
673 www.google.com A request:
674
675 0, 2: random transaction ID
676 2, 2: flags: only the "recursion desired" bit set. (bit 8 of word)
677 4, 2: questions: 1
678 6, 2: answer RR's: 0.
679 8, 2: authority RR's: 0.
680 10, 2: additional RR's: 0.
681 12, n: payload:
682 query:
683 #03 "www" #06 "google" #03 "com" #00
684 size-4, 2: type: host address (1)
685 size-2, 2: class: inet (1)
686
687 reply:
688
689 0,2: random transaction ID
690 2,2: flags: set: response (bit 15), recursion desired (8), recursion available (7)
691 4,4: questions: 1
692 6,4: answer RR's: 2
693 8,4: authority RR's: 9
694 10,4: additional RR's: 9
695 12: payload:
696 query:
697 ....
698 answer: CNAME
699 0,2 "c0 0c" "name: www.google.com"
700 2,2 "00 05" "type: cname for an alias"
701 4,2 "00 01" "class: inet"
702 6,4: TTL
703 10,2: data length "00 17" (23)
704 12: the cname name (www.google.akadns.net)
705 answer: A
706 0,2 ..
707 2,2 "00 01" host address
708 4,2 ...
709 6,4 ...
710 10,2: data length (4)
711 12,4: binary IP
712 authority - 9 records
713 additional - 9 records
714
715
716 ipv6 AAAA reply:
717 0,2: ...
718 2,2: type: 001c
719 4,2: class: inet (0001)
720 6,2: TTL
721 10,2: data size (16)
722 12,16: binary IP
723
724 ptr request: query type 000c
725
726 name compression: word "cxxx" in the name, xxx points to offset in the packet}
727
728 end.

Properties

Name Value
svn:executable

No admin address has been configured">No admin address has been configured
ViewVC Help
Powered by ViewVC 1.1.22