14 IdDNSResolver_ReceiveTimeout
= 4000;
17 //fBitCode Bits and Masks
18 cQRBit
= $8000; //QR when 0 = Question when 1 Response
20 cOpCodeBits
= $7800; //Operation Code See Constansts Defined Below
22 cAABit
= $0400; //Valid in Responses Authoritative Answer if set (1)
24 cTCBit
= $0200; //Truncation Bit if Set Messages was truncated for length
26 cRDBit
= $0100; //If set(1) Recursive Search is Resquested by Query
28 cRABit
= $0080; //If set(1) Server supports Recursive Search (Available)
30 cRCodeBits
= $000F; //Response Code. See Constansts Defined Below
33 //Question Operation Code Values
37 cOPCodeStrs
: array[cResQuery
..cResStatus
] of string[7] =
42 // QType Identifes the type of Question
43 cA
= 1; // a Host Address
44 cNS
= 2; // An Authoritative name server
45 cMD
= 3; // A mail destination obsolete use MX (OBSOLETE)
46 cMF
= 4; // A mail forwarder obsolete use MX (OBSOLETE)
47 cName
= 5; // The canonical name for an alias
48 cSOA
= 6; // Marks the start of a zone of authority
49 cMB
= 7; // A mail box domain name (Experimental)
50 cMG
= 8; // A mail group member (Experimental)
51 cMR
= 9; // A mail Rename Domain Name (Experimental)
52 cNULL
= 10; // RR (Experimental)
53 cWKS
= 11; // A well known service description
54 cPTR
= 12; // A Domain Name Pointer;
55 cHINFO
= 13; // Host Information;
56 cMINFO
= 14; // Mailbox or Mail List Information;
57 cMX
= 15; // Mail Exchange
58 cTXT
= 16; // Text String;
59 cAXFR
= 252; // A Request for the Transfer of an entire zone;
60 cMAILB
= 253; // A request for mailbox related records (MB MG OR MR}
61 cMAILA
= 254; // A request for mail agent RRs (Obsolete see MX)
62 cStar
= 255; // A Request for all Records
65 cIN
= 1; //The Internet
66 cCS
= 2; // the CSNet Obsolete
67 cCH
= 3; // The Chaos Claee
68 cHS
= 4; // Hesiod [Dyer 87]
70 //CStar any Class is same as QType for all records;
71 cQClassStr
: array[cIN
..CHs
] of string[3] =
72 ('IN', 'CS', 'CH', 'HS');
74 //Sever Response codes (RCode)
79 cRCodeNotImplemented
= 4;
82 cRCodeStrs
: array[cRCodeNoError
..cRCodeRefused
] of string =
87 RSCodeQueryNotImplemented
,
88 RSCodeQueryQueryRefused
);
91 TWKSBits
= array[0..7] of byte;
93 TRequestedRecord
= cA
..cStar
;
95 TRequestedRecords
= set of TRequestedRecord
;
97 TIdDNSHeader
= object(TObj
)
105 function GetAA
: Boolean;
106 function GetOpCode
: Word;
107 function GetQr
: Boolean;
108 function GetRA
: Boolean;
109 function GetRCode
: Word;
110 function GetRD
: Boolean;
111 function GetTC
: Boolean;
112 procedure InitializefId
;
113 procedure SetAA(AuthAnswer
: Boolean);
114 // procedure SetOpCode(OpCode: Word);
115 procedure SetQr(IsResponse
: Boolean);
116 procedure SetRA(RecursionAvailable
: Boolean);
117 // procedure SetRCode(RCode: Word);
118 procedure SetRD(RecursionDesired
: Boolean);
119 procedure SetTC(IsTruncated
: Boolean);
121 { constructor Create;
122 } procedure InitVars
; virtual;
124 property AA
: boolean read GetAA write SetAA
;
125 property ANCount
: Word read FAnCount write FAnCount
;
126 property ARCount
: Word read FArCount write FArCount
;
127 property ID
: Word read FId write FId
;
128 property NSCount
: Word read FNsCount write FNsCount
;
129 // property Opcode: Word read GetOpCode write SetOpCode;
130 property QDCount
: Word read FQdCount write FQdCount
;
131 property Qr
: Boolean read GetQr write SetQr
;
132 property RA
: Boolean read GetRA write SetRA
;
133 // property RCode: Word read GetRCode write SetRCode;
134 property RD
: Boolean read GetRD write SetRD
;
135 property TC
: Boolean read GetTC write SetTC
;
137 PIdDNSHeader
=^TIdDNSHeader
;
138 function NewIdDNSHeader
:PIdDNSHeader
;
142 TQuestionItem
= object(TCollectionItem
)
148 PQuestionItem
=^TQuestionItem
;
149 function NewQuestionItem
:PQuestionItem
;
153 TIdDNSQuestionList
= object(TCollection
)
155 function GetItem(Index
: Integer): TQuestionItem
;
156 procedure SetItem(Index
: Integer; const Value
: TQuestionItem
);
158 { constructor Create; }// reintroduce;
159 function Add
: TQuestionItem
;
160 property Items
[Index
: Integer]: TQuestionItem read GetItem write SetItem
;
163 PIdDNSQuestionList
=^TIdDNSQuestionList
;
164 function NewIdDNSQuestionList
:PIdDNSQuestionList
;
174 EMailBox
: ShortString
;
175 RMailBox
: ShortString
;
179 Exchange
: ShortString
;
211 TIdDNSResourceItem
= object(TCollectionITem
)
221 PIdDNSResourceItem
=^TIdDNSResourceItem
;
222 function NewIdDNSResourceItem
:PIdDNSResourceItem
;
226 TIdDNSResourceList
= object(TCollection
)
228 function GetItem(Index
: Integer): TIdDNSResourceItem
;
229 procedure SetItem(Index
: Integer; const Value
: TIdDNSResourceItem
);
231 function Add
: TIdDNSResourceItem
;
232 { constructor Create; }// reintroduce;
233 property Items
[Index
: Integer]: TIdDNSResourceItem read GetItem write
236 function GetDNSMxExchangeNameEx(Idx
: Integer): string;
237 function GetDNSRDataDomainName(Idx
: Integer): string;
239 PIdDNSResourceList
=^TIdDNSResourceList
;
240 function NewIdDNSResourceList
:PIdDNSResourceList
;
244 TMXRecord
= object(TIdDNSResourceItem
)
249 property Preference
: Word read FPreference
;
250 property Exchange
: string read FExchange
;
252 PMXRecord
=^TMXRecord
;
253 function NewMXRecord
:PMXRecord
;
257 TARecord
= object(TIdDNSResourceItem
)
261 property DomainName
: string read FDomainName
;
264 function NewARecord
:PARecord
;
268 TNameRecord
= object(TIdDNSResourceItem
)
272 property DomainName
: string read FDomainName
;
274 PNameRecord
=^TNameRecord
;
275 function NewNameRecord
:PNameRecord
;
278 TPTRRecord
= object(TIdDNSResourceItem
)
282 property DomainName
: string read FDomainName
;
284 PPTRRecord
=^TPTRRecord
;
285 function NewPTRRecord
:PPTRRecord
;
288 THInfoRecord
= object(TIdDNSResourceItem
)
293 property CPUStr
: string read FCPUStr
;
294 property OsStr
: string read FOsStr
;
296 PHInfoRecord
=^THInfoRecord
;
297 function NewHInfoRecord
:PHInfoRecord
;
300 TMInfoRecord
= object(TIdDNSResourceItem
)
305 property EMmailBox
: string read FEMmailBox
;
306 property RMailBox
: string read FRMailBox
;
308 PMInfoRecord
=^TMInfoRecord
;
309 function NewMInfoRecord
:PMInfoRecord
;
312 TMRecord
= object(TIdDNSResourceItem
)
317 property EMailBox
: string read FEMailBox
;
318 property RMailBox
: string read FRMailBox
;
321 function NewMRecord
:PMRecord
;
324 TSOARecord
= object(TIdDNSResourceItem
)
334 property Expire
: Cardinal read FExpire
;
335 property Minimum
: Cardinal read FMinimum
;
336 property MName
: string read FMName
;
337 property Refresh
: Cardinal read FRefresh
;
338 property Retry
: Cardinal read FRetry
;
339 property RName
: string read FRName
;
340 property Serial
: Cardinal read FSerial
;
342 PSOARecord
=^TSOARecord
;
343 function NewSOARecord
:PSOARecord
;
347 TWKSRecord
= object(TIdDNSResourceItem
)
353 function GetBits(AIndex
: Integer): Byte;
355 property Address
: Cardinal read FAddress
;
356 property Bits
[AIndex
: Integer]: Byte read GetBits
;
357 property Protocol
: byte read FProtocol
;
359 PWKSRecord
=^TWKSRecord
;
360 function NewTWKSRecord
:PWKSRecord
;
363 TIdDNSResolver
= object(TIdUDPClient
)
365 FDNSAnList
: TIdDNSResourceList
;
366 FDNSArList
: TIdDNSResourceList
;
367 FDNSHeader
: TIdDNSHeader
;
368 FDNSQdList
: TIdDNSQuestionList
;
369 FDNSNsList
: TIdDNSResourceList
;
373 FRequestedRecords
: TRequestedRecords
;
376 FAnswers
: TIdDNSResourceList
;
378 function CreateLabelStr(QName
: string): string;
379 procedure CreateQueryPacket
;
380 procedure DecodeReplyPacket
;
382 procedure ClearVars
; virtual;
383 { constructor Create(AOwner: TComponent); override;
384 } destructor Destroy
;
385 virtual; procedure ResolveDNS
;
386 procedure ResolveDomain(const ADomain
: string);
388 property Answers
: TIdDNSResourceList read FAnswers
;
389 property DNSAnList
: TIdDNSResourceList read FDnsAnList write FDnsAnList
;
390 property DNSARList
: TIdDNSResourceList read FDnsArList write FDnsArList
;
391 property DNSHeader
: TIdDNSHeader read FDNSHeader write FDNSHeader
;
392 property DNSQDList
: TIdDNSQuestionList read FDnsQdList write FDnsQdList
;
393 property DNSNSList
: TIdDNSResourceList read FDnsNsList write FDnsNsList
;
394 property Port default IdPORT_DOMAIN
;
395 property QPacket
: string read FQPacket write FQpacket
;
396 property RequestedRecords
: TRequestedRecords read FRequestedRecords write
398 property RPacket
: string read FRPacket write FRPacket
;
399 // property ReceiveTimeout default IdDNSResolver_ReceiveTimeout;
401 PIdDNSResolver
=^TIdDNSResolver
;
402 function NewIdDNSResolver(AOwner
: PControl
):PIdDNSResolver
;
412 1: (TheBytes
: HiLoBytes
);
423 1: (aCardinal
: Cardinal);
424 2: (Words
: HILoWords
);
427 function GetQTypeStr(aQType
: Integer): string;
428 function GetQClassStr(QClass
: Integer): string;
435 function TwoCharToWord(AChar1
, AChar2
: Char): Word;
437 Result
:= Word((Ord(AChar1
) shl 8) and $FF00) or Word(Ord(AChar2
) and $00FF);
440 function FourCharToCardinal(AChar1
, AChar2
, AChar3
, AChar4
: Char): Cardinal;
444 ares
.Words
.HiWord
:= TwoCharToWord(AChar1
, AChar2
);
445 aRes
.Words
.LowWord
:= TwoCharToWord(AChar3
, AChar4
);
446 Result
:= ARes
.aCardinal
;
449 function WordToTwoCharStr(AWord
: Word): string;
451 Result
:= Chr(Hi(AWord
)) + Chr(Lo(AWord
));
454 function GetRCodeStr(RCode
: Integer): string;
456 if Rcode
in [cRCodeNoError
..cRCodeRefused
] then
458 Result
:= cRCodeStrs
[Rcode
];
462 Result
:= RSCodeQueryUnknownError
;
466 function GetQTypeStr(aQType
: Integer): string;
469 cA
: Result
:= 'A'; // a Host Address
470 cNS
: Result
:= 'NS'; // An Authoritative name server
471 cMD
: Result
:= 'MD'; // A mail destination obsolete use MX (OBSOLETE)
472 cMF
: Result
:= 'MF'; // A mail forwarder obsolete use MX (OBSOLETE)
473 cName
: Result
:= 'NAME'; // The canonical name for an alias
474 cSOA
: Result
:= 'SOA'; // Marks the start of a zone of authority
475 cMB
: Result
:= 'MB'; // A mail box domain name (Experimental)
476 cMG
: Result
:= 'MG'; // A mail group member (Experimental)
477 cMR
: Result
:= 'MR'; // A mail Rename Domain Name (Experimental)
478 cNULL
: Result
:= 'NULL'; // RR (Experimental)
479 cWKS
: Result
:= 'WKS'; // A well known service description
480 cPTR
: Result
:= 'PTR'; // A Domain Name Pointer;
481 cHINFO
: Result
:= 'HINFO'; // Host Information;
482 cMINFO
: Result
:= 'MINFO'; // Mailbox or Mail List Information;
483 cMX
: Result
:= 'MX'; // Mail Exchange
484 cTXT
: Result
:= 'TXT'; // Text String;
485 cAXFR
: Result
:= 'AXFR'; // A Request for the Transfer of an entire zone;
486 cMAILB
: Result
:= 'MAILB';
487 // A request for mailbox related records (MB MG OR MR}
488 cMAILA
: Result
:= 'MAILA'; // A request for mail agent RRs (Obsolete see MX)
489 cStar
: Result
:= '*'; // A Request for all Records
491 Result
:= IntToSTr(aQType
);
495 function GetQClassStr(QClass
: Integer): string;
497 if QClass
in [cIN
..CHs
] then
499 Result
:= cQClassStr
[QClass
];
509 Result
:= IntToStr(QClass
);
514 function GetErrorStr(Code
, Id
: Integer): string;
517 1: Result
:= Format(RSQueryInvalidQueryCount
, [Id
]);
518 2: Result
:= Format(RSQueryInvalidPacketSize
, [InttoSTr(Id
)]);
519 3: Result
:= Format(RSQueryLessThanFour
, [Id
]);
520 4: Result
:= Format(RSQueryInvalidHeaderID
, [Id
]);
521 5: Result
:= Format(RSQueryLessThanTwelve
, [Id
]);
522 6: Result
:= Format(RSQueryPackReceivedTooSmall
, [Id
]);
526 //constructor TIdDNSHeader.Create;
527 function NewIdDNSHeader
:PIdDNSHeader
;
530 New( Result
, Create
);
535 procedure TIdDNSHeader
.InitializefId
;
538 fId
:= Random(10000);
541 procedure TIdDNSHeader
.InitVars
;
544 { Holds Qr,OPCode AA TC RD RA RCode and Reserved Bits }
546 { Number of Question Entries in Question Section }
548 { Number of Resource Records in Answer Section }
550 { Number of Name Server Resource Recs in Authority Rec Section }
552 { Number of Resource Records in Additional records Section }
555 function TIdDNSHeader
.GetQR
: Boolean;
557 Result
:= (fBitCode
and cQRBit
) = cQRBit
;
560 procedure TIdDNSHeader
.SetQr(IsResponse
: Boolean);
564 fBitCode
:= fBitCode
or cQRBit
;
568 fBitCode
:= fBitCode
and cQRMask
572 function TIdDNSHeader
.GetOpCode
: Word;
574 Result
:= ((fBitCode
and cOpCodeBits
) shr 11) and $000F;
577 {procedure TIdDNSHeader.SetOpCode(OpCode: Word);
579 fBitCode := ((OpCode shl 11) and cOpCodeBits) or
580 (fBitCode and cOpCodeMask);
583 function TIdDNSHeader
.GetAA
: Boolean;
585 Result
:= (fBitCode
and cAABit
) = cAABit
;
588 procedure TIdDNSHeader
.SetAA(AuthAnswer
: Boolean);
592 fBitCode
:= fBitCode
or cAABit
;
596 fBitCode
:= fBitCode
and cAAMask
;
600 function TIdDNSHeader
.GetTC
: Boolean;
602 Result
:= (fBitCode
and cTCBit
) = cTCBit
;
605 procedure TIdDNSHeader
.SetTC(IsTruncated
: Boolean);
609 fBitCode
:= fBitCode
or cTCBit
;
613 fBitCode
:= fBitCode
and cTCMask
;
617 function TIdDNSHeader
.GetRD
: Boolean;
619 Result
:= (fBitCode
and cRDBit
) = cRDBit
;
622 procedure TIdDNSHeader
.SetRD(RecursionDesired
: Boolean);
624 if RecursionDesired
then
626 fBitCode
:= fBitCode
or cRDBit
;
630 fBitCode
:= fBitCode
and cRDMask
;
634 function TIdDNSHeader
.GetRA
: Boolean;
636 Result
:= (fBitCode
and cRABit
) = cRABit
;
639 procedure TIdDNSHeader
.SetRA(RecursionAvailable
: Boolean);
641 if RecursionAvailable
then
643 fBitCode
:= fBitCode
or cRABit
;
647 fBitCode
:= fBitCode
and cRAMask
;
651 function TIdDNSHeader
.GetRCode
: Word;
653 Result
:= (fBitCode
and cRCodeBits
);
656 {procedure TIdDNSHeader.SetRCode(RCode: Word);
658 fBitCode := (RCode and cRCodeBits) or (fBitCode and cRCodeMask);
661 function TIdDNSQuestionList
.Add
: TQuestionItem
;
663 // Result := TQuestionItem(inherited Add);
666 //constructor TIdDNSQuestionList.Create;
667 function NewIdDNSQuestionList
:PIdDNSQuestionList
;
669 New( Result
, Create
);
670 // inherited Create(TQuestionItem);
673 function TIdDNSQuestionList
.GetItem(Index
: Integer): TQuestionItem
;
675 // Result := TQuestionItem(inherited Items[Index]);
678 procedure TIdDNSQuestionList
.SetItem(Index
: Integer;
679 const Value
: TQuestionItem
);
681 // inherited SetItem(Index, Value);
684 //constructor TIdDNSResourceList.Create;
685 function NewIdDNSResourceList
:PIdDNSResourceList
;
687 New( Result
, Create
);
688 // inherited Create(TIdDNSResourceItem);
691 function TIdDNSResourceList
.GetDNSRDataDomainName(Idx
: Integer): string;
693 if (Idx
< Count
) and (Idx
>= 0) then
695 Result
:= TIdDNSResourceItem(Items
[Idx
]).RData
.DomainName
;
701 function TIdDNSResourceList
.GetDnsMxExchangeNameEx(Idx
: Integer): string;
703 if (Idx
< Count
) and (Idx
>= 0) then
706 IntToStr(TIdDNSResourceItem(Items
[Idx
]).RData
.MX
.Preference
);
707 while Length(Result
) < 5 do
709 Result
:= ' ' + Result
;
712 Result
+ ' ' + TIdDNSResourceItem(Items
[Idx
]).RData
.MX
.Exchange
;
720 function TIdDNSResourceList
.Add
: TIdDNSResourceItem
;
722 // Result := TIdDNSResourceItem(inherited Add);
725 function TIdDNSResourceList
.GetItem(Index
: Integer): TIdDNSResourceItem
;
727 // Result := TIdDNSResourceItem(inherited Items[Index]);
730 procedure TIdDNSResourceList
.SetItem(Index
: Integer;
731 const Value
: TIdDNSResourceItem
);
733 // inherited SetItem(Index, Value);
736 //constructor TIdDNSResolver.Create(aOwner: tComponent);
737 function NewIdDNSResolver(AOwner
: PControl
):PIdDNSResolver
;
739 New( Result
, Create
);
742 // inherited Create(aOwner);
743 { Port := IdPORT_DOMAIN;
744 ReceiveTimeout := IdDNSResolver_ReceiveTimeout;
745 fDNSHeader := TIdDNSHeader.Create;
746 fDnsQdList := TIdDNSQuestionList.Create;
747 fDnsAnList := TIdDNSResourceList.Create;
748 fDnsNsList := TIdDNSResourceList.Create;
749 fDnsArList := TIdDNSResourceList.Create;
750 FAnswers := TIdDNSREsourceList.Create;}
754 destructor TIdDNSResolver
.Destroy
;
765 procedure TIdDNSResolver
.ResolveDNS
;
770 fRPacket
:= ReceiveString
;
771 finally DecodeReplyPacket
;
775 procedure TIdDNSResolver
.ClearVars
;
784 function TIdDNSResolver
.CreateLabelStr(QName
: string): string;
789 ResultArray
: array[0..512] of Char;
796 FillChar(ResultArray
, SizeOf(ResultArray
), 0);
797 aPos
:= Pos(aPeriod
, QName
);
799 while (aPos
<> 0) and ((RaIdx
+ aPos
) < SizeOf(ResultArray
)) do
801 aLabel
:= Copy(QName
, 1, aPos
- 1);
802 NumBytes
:= Succ(Length(Alabel
));
803 Move(aLabel
, ResultArray
[RaIdx
], NumBytes
);
804 Inc(RaIdx
, NumBytes
);
805 Delete(QName
, 1, aPos
);
806 aPos
:= Pos(aPeriod
, QName
);
808 Result
:= string(ResultArray
);
811 procedure TIdDNSResolver
.CreateQueryPacket
;
814 DnsQuestion
: TQuestionItem
;
816 procedure DoDomainName(ADNS
: string);
821 while Length(aDns
) > 0 do
823 aPos
:= Pos('.', aDns
);
826 aPos
:= Length(aDns
) + 1;
828 BufStr
:= Copy(aDns
, 1, aPos
- 1);
829 Delete(aDns
, 1, aPos
);
830 QPacket
:= QPacket
+ Chr(Length(BufStr
)) + BufStr
;
834 procedure DoHostAddress(aDNS
: string);
840 while Length(aDns
) > 0 do
842 aPos
:= Pos('.', aDns
);
845 aPos
:= Length(aDns
) + 1;
847 BufStr
:= Copy(aDns
, 1, aPos
- 1);
848 Delete(aDns
, 1, aPos
);
849 BufStr2
:= Chr(Length(BufStr
)) + BufStr
+ BufStr2
;
852 QPacket
+ BufStr2
+ Chr(07) + 'in-addr' + Chr(04) + 'arpa';
856 { DNSHeader.fId := Random(62000);
857 DNSHeader.fQdCount := fDnsQdList.Count;
858 if DNSHeader.fQdCount < 1 then
860 raise EIdDnsResolverError.Create(GetErrorStr(1, 1));
862 QPacket := WordToTwoCharStr(DNSHeader.fId);
863 QPacket := QPacket + WordToTwoCharStr(DNSHeader.fBitCode);
864 QPacket := QPacket + WordToTwoCharStr(DNSHeader.fQdCount);
865 QPacket := QPacket + Chr(0) + Chr(0)
868 for QueryIdx := 0 to fDnsQdList.Count - 1 do
870 DNsQuestion := fDnsQdList.Items[QueryIdx];
871 case DNSQuestion.Qtype of
872 cA: DoDomainName(DNsQuestion.QName);
873 cNS: DoDomainName(DNsQuestion.QName);
874 cMD: raise EIdDnsResolverError.Create(RSDNSMDISObsolete);
875 cMF: raise EIdDnsResolverError.Create(RSDNSMFIsObsolete);
876 cName: DoDomainName(DNsQuestion.QName);
877 cSOA: DoDomainName(DNsQuestion.Qname);
878 cMB: DoDomainName(DNsQuestion.QName);
879 cMG: DoDomainName(DNsQuestion.QName);
880 cMR: DoDomainName(DNsQuestion.QName);
881 cNULL: DoDomainName(DNsQuestion.QName);
882 cWKS: DoDomainName(DNsQuestion.QName);
883 cPTR: DoHostAddress(DNsQuestion.QName);
884 cHINFO: DoDomainName(DNsQuestion.QName);
885 cMINFO: DoDomainName(DNsQuestion.QName);
886 cMX: DoDomainName(DNsQuestion.QName);
887 cTXT: DoDomainName(DNsQuestion.QName);
888 cAXFR: DoDomainName(DNsQuestion.QName);
889 cMAILB: DoDomainName(DNsQuestion.QName);
890 cMailA: raise EIdDnsResolverError.Create(RSDNSMailAObsolete);
891 cSTar: DoDomainName(DNsQuestion.QName);
893 fQPacket := fQPacket + Chr(0);
894 fQPacket := fQPacket + WordToTwoCharStr(DNsQuestion.QType);
895 fQPacket := fQPacket + WordToTwoCharStr(DNsQuestion.QClass);
897 FQPackSize := Length(fQPacket);}
900 procedure TIdDNSResolver
.DecodeReplyPacket
;
906 function LabelsToDomainName(const SrcStr
: string; var Idx
: Integer): string;
916 Len
:= Byte(SrcStr
[Idx
]);
921 SavedIdx
:= Succ(Idx
);
923 aChar
:= Char(Len
and $3F);
924 Idx
:= TwoCharToWord(aChar
, SrcStr
[Idx
+ 1]) + 1;
926 if Idx
> fRPackSize
then
928 // raise EIdDnsResolverError.Create(GetErrorStr(2, 2));
930 SetLength(LabelStr
, Byte(SrcStr
[Idx
]));
931 Move(SrcStr
[Idx
+ 1], LabelStr
[1], Length(LabelStr
));
932 Inc(Idx
, Length(LabelStr
) + 1);
933 if (Idx
- 1) > fRPackSize
then
935 // raise EIdDnsResolverError.Create(GetErrorStr(2, 3));
937 Result
:= Result
+ LabelStr
+ '.';
938 until (SrcStr
[Idx
] = Char(0)) or (Idx
>= Length(SrcStr
));
939 if Result
[Length(Result
)] = '.' then
941 Delete(Result
, Length(Result
), 1);
950 function ParseQuestions(StrIdx
: Integer): Integer;
952 DNSQuestion
: TQuestionItem
;
955 for Idx
:= 1 to fDNSHeader
.fQdCount
do
957 DnsQuestion
:= fDnsQdList
.Add
;
958 DnsQuestion
.QName
:= LabelsToDomainName(RPacket
, StrIdx
);
959 if StrIdx
> fRPackSize
then
961 // raise EIdDnsResolverError.Create(GetErrorStr(2, 4));
963 DnsQuestion
.Qtype
:= TwoCharToWord(RPacket
[StrIdx
], RPacket
[StrIdx
+ 1]);
965 if StrIdx
> fRPackSize
then
967 // raise EIdDnsResolverError.Create(GetErrorStr(2, 5));
969 DnsQuestion
.QClass
:= TwoCharToWord(RPacket
[StrIdx
], RPacket
[StrIdx
+ 1]);
970 if StrIdx
+ 1 > fRPackSize
then
972 // raise EIdDnsResolverError.Create(GetErrorStr(2, 6));
979 function ParseResource(NumItems
, StrIdx
: Integer; DnsList
: TIdDNSResourceList
)
982 RDataStartIdx
: Integer;
983 DnsResponse
: TIdDNSResourceItem
;
986 procedure ProcessRData(sIdx
: Integer);
988 procedure DoHostAddress
;
993 if sIdx
+ 3 > fRPackSize
then
995 // raise EIdDnsResolverError.Create(GetErrorStr(2, 7));
997 for Idx
:= sIdx
to sIdx
+ 3 do
999 DnsResponse
.RData
.HostAddrStr
:= DNSResponse
.RData
.HostAddrStr
+
1000 IntToStr(Ord(RPacket
[Idx
])) + '.';
1002 Delete(DNSResponse
.RData
.HostAddrStr
,
1003 Length(DNSResponse
.RData
.HostAddrStr
), 1);
1006 procedure DoDomainNameRData
;
1008 DnsResponse
.RData
.DomainName
:= LabelsToDomainName(RPacket
, sIdx
);
1009 if (sIdx
- 1) > fRPackSize
then
1011 // raise EIdDnsResolverError.Create(GetErrorStr(2, 8));
1015 procedure DoSOARdata
;
1017 DNSResponse
.RData
.SOA
.MName
:= LabelsToDomainName(RPacket
, sIdx
);
1018 if sIdx
> fRPackSize
then
1020 // raise EIdDnsResolverError.Create(GetErrorStr(2, 9));
1022 DNSResponse
.RData
.SOA
.RName
:= LabelsToDomainName(RPacket
, sIdx
);
1023 if sIdx
+ 4 > fRPackSize
then
1025 // raise EIdDnsResolverError.Create(GetErrorStr(2, 10));
1027 DNSResponse
.RData
.SOA
.Serial
:= FourCharToCardinal(RPacket
[sIdx
],
1028 RPacket
[sIdx
+ 1], RPacket
[sIdx
+ 2], RPacket
[sIdx
+ 3]);
1030 if sIdx
+ 4 > fRPackSize
then
1032 // raise EIdDnsResolverError.Create(GetErrorStr(2, 11));
1034 DNSResponse
.RData
.SOA
.Refresh
:= FourCharToCardinal(RPacket
[sIdx
],
1035 RPacket
[sIdx
+ 1], RPacket
[sIdx
+ 2], RPacket
[sIdx
+ 3]);
1037 if sIdx
+ 4 > fRPackSize
then
1039 // raise EIdDnsResolverError.Create(GetErrorStr(2, 12));
1041 DNSResponse
.RData
.SOA
.ReTry
:= FourCharToCardinal(RPacket
[sIdx
],
1042 RPacket
[sIdx
+ 1], RPacket
[sIdx
+ 2], RPacket
[sIdx
+ 3]);
1044 if sIdx
+ 4 > fRPackSize
then
1046 // raise EIdDnsResolverError.Create(GetErrorStr(2, 13));
1048 DNSResponse
.RData
.SOA
.Expire
:= FourCharToCardinal(RPacket
[sIdx
],
1049 RPacket
[sIdx
+ 1], RPacket
[sIdx
+ 2], RPacket
[sIdx
+ 3]);
1051 if sIdx
+ 3 > fRPackSize
then
1053 // raise EIdDnsResolverError.Create(GetErrorStr(2, 14));
1055 DNSResponse
.RData
.SOA
.Minimum
:= FourCharToCardinal(RPacket
[sIdx
],
1056 RPacket
[sIdx
+ 1], RPacket
[sIdx
+ 2], RPacket
[sIdx
+ 3]);
1060 procedure DoWKSRdata
;
1062 if sIdx
+ 4 > fRPackSize
then
1064 // raise EIdDnsResolverError.Create(GetErrorStr(2, 15));
1066 DNSResponse
.RData
.WKS
.Address
:=
1067 FourCharToCardinal(RPacket
[sIdx
], RPacket
[sIdx
+ 1], RPacket
[sIdx
+
1068 2], RPacket
[sIdx
+ 3]);
1070 DNSResponse
.RData
.WKS
.Protocol
:= Byte(RPacket
[sIdx
]);
1072 if sIdx
+ 7 > fRPackSize
then
1074 // raise EIdDnsResolverError.Create(GetErrorStr(2, 16));
1076 Move(RPacket
[sIdx
], DNSResponse
.RData
.WKS
.Bits
, 8);
1079 procedure DoHInfoRdata
;
1081 if sIdx
+ Ord(RPacket
[sIdx
]) + 1 > fRPackSize
then
1083 // raise EIdDnsResolverError.Create(GetErrorStr(2, 17));
1085 Move(RPacket
[sIdx
], DNSResponse
.RData
.Hinfo
.CpuStr
,
1086 Ord(RPacket
[sIdx
]) + 1);
1087 sIdx
:= sIdx
+ Length(DNSResponse
.RData
.Hinfo
.CpuStr
) + 2;
1088 if sIdx
+ Ord(RPacket
[sIdx
]) + 1 > fRPackSize
then
1090 // raise EIdDnsResolverError.Create(GetErrorStr(2, 18));
1092 Move(RPacket
[sIdx
], DNSResponse
.RData
.Hinfo
.OSStr
,
1093 Ord(RPacket
[sIdx
]) + 1);
1096 procedure DoMInfoRdata
;
1098 DNSResponse
.RData
.Minfo
.RMailBox
:=
1099 LabelsToDomainName(RPacket
, sIdx
);
1100 if sIdx
> fRPackSize
then
1102 // raise EIdDnsResolverError.Create(GetErrorStr(2, 19));
1104 DNSResponse
.RData
.MinFo
.EMailBox
:=
1105 LabelsToDomainName(RPacket
, sIdx
);
1106 if sIdx
> fRPackSize
then
1108 // raise EIdDnsResolverError.Create(GetErrorStr(2, 20));
1112 procedure DoMXRData
;
1114 if sIdx
+ 2 > fRPackSize
then
1116 // raise EIdDnsResolverError.Create(GetErrorStr(2, 21));
1118 DNSResponse
.RData
.MX
.Preference
:=
1119 TwoCharToWord(RPacket
[sIdx
], RPacket
[sIdx
+ 1]);
1121 if sIdx
+ 2 > fRPackSize
then
1123 // raise EIdDnsResolverError.Create(GetErrorStr(2, 22));
1125 DNSResponse
.RData
.Mx
.Exchange
:= LabelsToDomainName(RPacket
, sIdx
);
1128 procedure DoMailBRdata
;
1130 // raise EIdDnsResolverError.Create(RSDNSMailBNotImplemented);
1134 case DnsResponse
.AType
of
1136 cNS
: DoDomainNameRData
;
1137 // cMD: raise EIdDnsResolverError.Create(RSDNSMDISObsolete);
1138 // cMF: raise EIdDnsResolverError.Create(RSDNSMFIsObsolete);
1139 cName
: DoDomainNameRData
;
1141 cMB
: DoDomainNameRData
;
1142 cMG
: DoDomainNameRData
;
1143 cMR
: DoDomainNameRData
;
1145 DnsResponse
.StarData
:=
1146 Copy(RPacket
, RDataStartIdx
, DnsResponse
.RdLength
);
1148 cPTR
: DoDomainNameRData
;
1149 cHINFO
: DoHInfoRdata
;
1150 cMINFO
: DoMInfoRdata
;
1153 DnsResponse
.StarData
:=
1154 Copy(RPacket
, RDataStartIdx
, DnsResponse
.RdLength
);
1156 DnsResponse
.StarData
:=
1157 Copy(RPacket
, RDataStartIdx
, DnsResponse
.RdLength
);
1158 cMAILB
: DoMailBRData
;
1159 // cMailA: raise EIdDnsResolverError.Create(RSDNSMFIsObsolete);
1161 DnsResponse
.StarData
:=
1162 Copy(RPacket
, RDataStartIdx
, DnsResponse
.RdLength
);
1170 for Idx
:= 1 to NumItems
do
1172 DnsResponse
:= DnsList
.Add
;
1173 DnsResponse
.Name
:= LabelsToDomainName(RPacket
, StrIdx
);
1174 if StrIdx
+ 10 > fRPackSize
then
1176 // raise EIdDnsResolverError.Create(GetErrorStr(2, 23));
1178 DnsResponse
.aType
:=
1179 TwoCharToWord(RPacket
[StrIdx
], RPacket
[StrIdx
+ 1]);
1181 DnsResponse
.aClass
:=
1182 TwoCharToWord(RPacket
[StrIdx
], RPacket
[StrIdx
+ 1]);
1185 FourCharToCardinal(RPacket
[StrIdx
], RPacket
[StrIdx
+ 1],
1186 RPacket
[StrIdx
+ 2], RPacket
[StrIdx
+ 3]);
1188 DnsResponse
.RdLength
:=
1189 TwoCharToWord(RPacket
[StrIdx
], RPacket
[StrIdx
+ 1]);
1191 if ((StrIdx
+ DnsResponse
.RdLength
) - 1) > fRPackSize
then
1193 // raise EIdDnsResolverError.Create(GetErrorStr(2, 23));
1195 RDataStartIdx
:= StrIdx
;
1196 ProcessRdata(StrIdx
);
1197 Inc(StrIdx
, DnsResponse
.RdLength
);
1200 if StrIdx
>= Length(RPacket
) then
1213 fRPackSize
:= Length(RPacket
);
1214 if fRPackSize
< 4 then
1216 // raise EIdDnsResolverError.Create(GetErrorStr(3, 28));
1219 ReplyId
:= TwoCharToWord(RPacket
[1], RPacket
[2]);
1220 if ReplyId
<> fDNSHeader
.fid
then
1222 // raise EIdDnsResolverError.Create(GetErrorStr(4, fDNSHeader.Fid));
1225 fDNSHeader
.fBitCode
:= TwoCharToWord(RPacket
[3], RPacket
[4]);
1226 // if FDNSHeader.RCode <> 0 then
1228 // raise EIdDnsResolverError.Create(GetRCodeStr(FDNSHeader.RCode));
1230 if fRPackSize
< 12 then
1232 // raise EIdDnsResolverError.Create(GetErrorStr(5, 29));
1234 fDNSHeader
.fQdCount
:= TwoCharToWord(RPacket
[5], RPacket
[6]);
1235 fDNSHeader
.fAnCount
:= TwoCharToWord(RPacket
[7], RPacket
[8]);
1236 fDNSHeader
.fNsCount
:= TwoCharToWord(RPacket
[9], RPacket
[10]);
1237 fDNSHeader
.fArCount
:= TwoCharToWord(RPacket
[11], RPacket
[12]);
1238 if (fRPackSize
< FQPackSize
) then
1240 // raise EIdDnsResolverError.Create(GetErrorStr(5, 30));
1242 for Idx
:= 1 to fDNSHeader
.fQdCount
do
1244 CharCount
:= ParseQuestions(13);
1246 if (Charcount
>= fRPackSize
) and ((fDNSHeader
.fAnCount
> 0) or
1247 (fDNSHeader
.fNsCount
> 0) or
1248 (fDNSHeader
.fArCount
> 0)) then
1250 // raise EIdDnsResolverError.Create(GetErrorStr(6, 31));
1252 if fDNSHeader
.fAnCount
> 0 then
1254 CharCount
:= ParseResource(fDNSHeader
.fAnCount
, CharCount
, fDnsAnList
);
1256 if (Charcount
>= fRPackSize
) and ((fDNSHeader
.fNsCount
> 0) or
1257 (fDNSHeader
.fArCount
> 0)) then
1259 // raise EIdDnsResolverError.Create(GetErrorStr(6, 32));
1261 if fDNSHeader
.fNsCount
> 0 then
1263 CharCount
:= ParseResource(fDNSHeader
.fNsCount
, CharCount
, fDnsNsList
);
1265 if (Charcount
>= fRPackSize
) and (fDNSHeader
.fArCount
> 0) then
1267 // raise EIdDnsResolverError.Create(GetErrorStr(6, 33));
1269 if fDNSHeader
.fArCount
> 0 then
1271 CharCount
:= ParseResource(fDNSHeader
.fArCount
, CharCount
, fDnsArList
);
1273 fRPackSize
:= CharCount
;
1276 procedure TIdDNSResolver
.ResolveDomain(const ADomain
: string);
1279 Rec
: TRequestedRecord
;
1283 // DNSHeader.ID := DNSHeader.Id + 1;
1284 DNSHeader
.Qr
:= False;
1285 // DNSHeader.Opcode := cResQuery;
1286 DNSHeader
.RD
:= True;
1287 for Rec
:= Low(TRequestedRecord
) to High(TRequestedRecord
) do
1289 if Rec
in FRequestedRecords
then
1291 // DNSHeader.QdCount := DNSHEader.QdCount + 1;
1292 with DNSQDList
.Add
do
1303 { for i := 0 to DNSAnList.Count - 1 do
1305 LRData := DNSAnList.Items[i].RData;
1306 case DNSAnList.Items[i].AType of
1308 with TARecord.Create(Answers) do
1310 FDomainName := LRData.DomainName;
1313 with TMXRecord.Create(Answers) do
1315 FExchange := LRData.MX.Exchange;
1316 FPreference := LRData.MX.Preference;
1319 with TNameRecord.Create(Answers) do
1321 FDomainName := LRData.DomainName;
1324 with TSOARecord.Create(Answers) do
1326 FExpire := LRData.SOA.Expire;
1327 FMinimum := LRData.SOA.Minimum;
1328 FMName := LRData.SOA.MName;
1329 FRefresh := LRData.SOA.Refresh;
1330 FRetry := LRData.SOA.Retry;
1331 FRName := LRData.SOA.RName;
1332 FSerial := LRData.SOA.Serial;
1335 with TWKSRecord.Create(Answers) do
1337 FAddress := LRData.WKS.Address;
1338 FBits := LRData.WKS.Bits;
1339 FProtocol := LRData.WKS.Protocol;
1342 with TPTRRecord.Create(Answers) do
1344 FDomainName := LRData.HostAddrStr;
1347 with THInfoRecord.Create(Answers) do
1349 FCPUStr := LRData.HInfo.CPUStr;
1350 FOsStr := LRData.HInfo.OsStr;
1353 with TMInfoRecord.Create(Answers) do
1355 FEMmailBox := LRData.MInfo.EMailBox;
1356 FRMailBox := LRData.MInfo.RMailBox;
1362 function TWKSRecord
.GetBits(AIndex
: Integer): Byte;
1364 Result
:= FBits
[Index
];
1367 function NewQuestionItem
:PQuestionItem
;
1369 New( Result
, Create
);
1372 function NewIdDNSResourceItem
:PIdDNSResourceItem
;
1374 New( Result
, Create
);
1377 function NewMXRecord
:PMXRecord
;
1379 New( Result
, Create
);
1382 function NewARecord
:PARecord
;
1384 New( Result
, Create
);
1387 function NewNameRecord
:PNameRecord
;
1389 New( Result
, Create
);
1392 function NewPTRRecord
:PPTRRecord
;
1394 New( Result
, Create
);
1397 function NewHInfoRecord
:PHInfoRecord
;
1399 New( Result
, Create
);
1402 function NewMInfoRecord
:PMInfoRecord
;
1404 New( Result
, Create
);
1407 function NewMRecord
:PMRecord
;
1409 New( Result
, Create
);
1412 function NewSOARecord
:PSOARecord
;
1414 New( Result
, Create
);
1417 function NewTWKSRecord
:PWKSRecord
;
1419 New( Result
, Create
);