2040 lines
59 KiB
Plaintext
2040 lines
59 KiB
Plaintext
{
|
|
$Project$
|
|
$Workfile$
|
|
$Revision$
|
|
$DateUTC$
|
|
$Id$
|
|
|
|
This file is part of the Indy (Internet Direct) project, and is offered
|
|
under the dual-licensing agreement described on the Indy website.
|
|
(http://www.indyproject.org/)
|
|
|
|
Copyright:
|
|
(c) 1993-2005, Chad Z. Hower and the Indy Pit Crew. All rights reserved.
|
|
}
|
|
{
|
|
$Log$
|
|
|
|
Rev 1.29 1/31/2005 9:02:44 PM JPMugaas
|
|
Should compile again. OOPS!!
|
|
|
|
|
|
Rev 1.28 1/28/2005 8:06:08 PM JPMugaas
|
|
Bug with MINFO, it was not returning the responsible E-Mail address.
|
|
|
|
|
|
Rev 1.27 1/28/2005 7:12:34 PM JPMugaas
|
|
Minor formatting adjustments.
|
|
|
|
|
|
Rev 1.26 1/28/2005 3:46:18 PM JPMugaas
|
|
Should compile.
|
|
|
|
|
|
Rev 1.25 2005/1/28 ¤U¤È 12:40:08 DChang
|
|
Add a new method for TIdTextModeResourceRecord to clean the created FAnswer,
|
|
then while the record updated, new data can be used in the FAnswer.
|
|
|
|
|
|
Rev 1.23 2005/1/25 ¤U¤È 12:24:14 DChang
|
|
For speeding up the query, one private variable is added into all TIdRR_
|
|
series object, only first time query will generate the binary codes, the
|
|
others will read the result form the first time generated.
|
|
|
|
|
|
Rev 1.22 2004/12/15 ¤W¤È 11:12:18 DChang Version: 1.22
|
|
Fix all BinQueryRecord method of TIdRR_*,
|
|
TIdRR_TXT.BinQueryRecord is completed,
|
|
and remark the comment of TIdTextModeResourceRecord.BinQueryRecord,
|
|
it's should be empty.
|
|
|
|
|
|
Rev 1.21 10/26/2004 9:06:30 PM JPMugaas
|
|
Updated references.
|
|
|
|
|
|
Rev 1.20 9/15/2004 4:59:34 PM DSiders
|
|
Added localization comments.
|
|
|
|
|
|
Rev 1.19 2004/7/19 ¤U¤È 09:43:40 DChang
|
|
1. Move the TIdTextModeResourceRecords which was defined in
|
|
IdDNSServer.pas to here.
|
|
2. Add a QueryType (DqtIXFR) in TDNSQueryRecordTypes.
|
|
|
|
|
|
Rev 1.18 6/29/04 1:22:32 PM RLebeau
|
|
Updated NormalStrToDNSStr() to use CopyTIdBytes() instead of AppendBytes()
|
|
|
|
|
|
Rev 1.17 2/11/2004 5:21:12 AM JPMugaas
|
|
Vladimir Vassiliev changes for removal of byte flipping. Network conversion
|
|
order conversion functions are used instead.
|
|
IPv6 addresses are returned in the standard form.
|
|
In WKS records, Address was changed to IPAddress to be consistant with other
|
|
record types. Address can also imply a hostname.
|
|
|
|
|
|
Rev 1.16 2/7/2004 7:18:30 PM JPMugaas
|
|
Moved some functions out of IdDNSCommon so we can use them elsewhere.
|
|
|
|
|
|
Rev 1.15 2004.02.07 5:45:10 PM czhower
|
|
Fixed compile error in D7.
|
|
|
|
|
|
Rev 1.14 2004.02.07 5:03:26 PM czhower
|
|
.net fixes.
|
|
|
|
|
|
Rev 1.13 2004.02.03 5:45:56 PM czhower
|
|
Name changes
|
|
|
|
|
|
Rev 1.12 12/7/2003 8:07:24 PM VVassiliev
|
|
string -> TIdBytes
|
|
|
|
|
|
Rev 1.11 11/15/2003 1:16:06 PM VVassiliev
|
|
Move AppendByte from IdDNSCommon to IdCoreGlobal
|
|
|
|
|
|
Rev 1.10 11/13/2003 5:46:04 PM VVassiliev
|
|
DotNet
|
|
|
|
|
|
Rev 1.9 10/25/2003 06:51:50 AM JPMugaas
|
|
Updated for new API changes and tried to restore some functionality.
|
|
|
|
|
|
Rev 1.8 10/19/2003 11:56:12 AM DSiders
|
|
Added localization comments.
|
|
|
|
|
|
Rev 1.7 2003.10.12 3:50:38 PM czhower
|
|
Compile todos
|
|
|
|
|
|
Rev 1.6 2003/5/8 ¤U¤È 08:07:12 DChang
|
|
Add several constants for IdDNSServer
|
|
|
|
|
|
Rev 1.5 4/28/2003 03:34:56 PM JPMugaas
|
|
Illiminated constant for the service path. IFDEF's for platforms are only
|
|
allowed in designated units. Besides, the location of the services file is
|
|
different in Win9x operating systems than NT operating systems.
|
|
|
|
|
|
Rev 1.4 4/28/2003 02:30:46 PM JPMugaas
|
|
reverted back to the old one as the new one checked will not compile, has
|
|
problametic dependancies on Contrs and Dialogs (both not permitted).
|
|
|
|
|
|
Rev 1.2 4/28/2003 07:00:04 AM JPMugaas
|
|
Should now compile.
|
|
|
|
|
|
Rev 1.0 11/14/2002 02:18:20 PM JPMugaas
|
|
Rev 1.3 04/28/2003 01:15:20 AM DenniesChang
|
|
|
|
|
|
// Add iRCode mode constants in May 4, 2003.
|
|
// Modify all DNS relative header in IdDNSCommon.pas
|
|
// Apr. 28, 2003
|
|
|
|
// Jun. 03, 2002.
|
|
// Add AXFR function
|
|
Duplicate some varible and constants in DNSCommon,
|
|
because Indy change version very frequently, these
|
|
varlibles and objects are isolated.
|
|
|
|
I had added some methods into IdDNSResolver of Indy 9.02,
|
|
for parsing DN record directly and skip some check actions
|
|
from original query, but this modification will not relfect
|
|
the action of DN Query.
|
|
|
|
Original Programmer: Dennies Chang <dennies@ms4.hinet.net>
|
|
No Copyright. Code is given to the Indy Pit Crew.
|
|
|
|
Started: Jan. 20, 2002.
|
|
Finished:
|
|
}
|
|
|
|
unit IdDNSCommon;
|
|
|
|
interface
|
|
|
|
{$i IdCompilerDefines.inc}
|
|
|
|
uses
|
|
Classes,
|
|
IdContainers,
|
|
IdException,
|
|
IdGlobal,
|
|
IdResourceStrings,
|
|
IdResourceStringsProtocols;
|
|
|
|
const
|
|
IdDNSServerVersion = 'Indy DNSServer 20040121301'; {do not localize}
|
|
cRCodeNoError = 0;
|
|
cRCodeFormatErr = 1;
|
|
cRCodeServerErr = 2;
|
|
cRCodeNameErr = 3;
|
|
cRCodeNotImplemented = 4;
|
|
cRCodeRefused = 5;
|
|
|
|
iRCodeQueryNotImplement = 0;
|
|
iRCodeQueryReturned = 1;
|
|
iRCodeQueryOK = 2;
|
|
iRCodeQueryNotFound = 3;
|
|
|
|
iRCodeNoError = 0;
|
|
iRCodeFormatError = 1;
|
|
iRCodeServerFailure = 2;
|
|
iRCodeNameError = 3;
|
|
iRCodeNotImplemented = 4;
|
|
iRCodeRefused = 5;
|
|
|
|
iQr_Question = 0;
|
|
iQr_Answer = 1;
|
|
|
|
iAA_NotAuthoritative = 0;
|
|
iAA_Authoritative = 1;
|
|
|
|
cRCodeQueryNotImplement = 'NA'; {do not localize}
|
|
cRCodeQueryReturned = 'RC'; // Return Completed. {do not localize}
|
|
cRCodeQueryOK = 'OK'; {do not localize}
|
|
cRCodeQueryCacheOK = 'COK'; {do not localize}
|
|
cRCodeQueryNotFound = 'NOTFOUND'; {do not localize}
|
|
cRCodeQueryCacheFindError = 'CFoundError'; {do not localize}
|
|
|
|
RSDNSServerAXFRError_QuerySequenceError = 'First record must be SOA!'; {do not localize}
|
|
RSDNSServerSettingError_MappingHostError = 'Host must be an IP address'; {do not localize}
|
|
|
|
cOrigin = '$ORIGIN'; {do not localize}
|
|
cInclude = '$INCLUDE'; {do not localize}
|
|
cAAAA = 'AAAA'; {do not localize}
|
|
cAt = '@'; {do not localize}
|
|
cA = 'A'; {do not localize}
|
|
cNS = 'NS'; {do not localize}
|
|
cMD = 'MD'; {do not localize}
|
|
cMF = 'MF'; {do not localize}
|
|
cCName = 'CNAME'; {do not localize}
|
|
cSOA = 'SOA'; {do not localize}
|
|
cMB = 'MB'; {do not localize}
|
|
cMG = 'MG'; {do not localize}
|
|
cMR = 'MR'; {do not localize}
|
|
cNULL = 'NULL'; {do not localize}
|
|
cWKS = 'WKS'; {do not localize}
|
|
cPTR = 'PTR'; {do not localize}
|
|
cHINFO = 'HINFO'; {do not localize}
|
|
cMINFO = 'MINFO'; {do not localize}
|
|
cMX = 'MX'; {do not localize}
|
|
cTXT = 'TXT'; {do not localize}
|
|
cNSAP = 'NSAP'; {do not localize}
|
|
cNSAP_PTR = 'NSAP-PTR'; {do not localize}
|
|
cLOC = 'LOC'; {do not localize}
|
|
cAXFR = 'AXFR'; {do not localize}
|
|
cIXFR = 'IXFR'; {do not localize}
|
|
cSTAR = 'STAR'; {do not localize}
|
|
|
|
cRCodeStrs : Array[cRCodeNoError..cRCodeRefused] Of String =
|
|
(RSCodeNoError,
|
|
RSCodeQueryFormat,
|
|
RSCodeQueryServer,
|
|
RSCodeQueryName,
|
|
RSCodeQueryNotImplemented,
|
|
RSCodeQueryQueryRefused);
|
|
|
|
Class_IN = 1;
|
|
Class_CHAOS = 3;
|
|
|
|
TypeCode_A = 1;
|
|
TypeCode_NS = 2;
|
|
TypeCode_MD = 3;
|
|
TypeCode_MF = 4;
|
|
TypeCode_CName = 5;
|
|
TypeCode_SOA = 6;
|
|
TypeCode_MB = 7;
|
|
TypeCode_MG = 8;
|
|
TypeCode_MR = 9;
|
|
TypeCode_NULL = 10;
|
|
TypeCode_WKS = 11;
|
|
TypeCode_PTR = 12;
|
|
TypeCode_HINFO = 13;
|
|
TypeCode_MINFO = 14;
|
|
TypeCode_MX = 15;
|
|
TypeCode_TXT = 16;
|
|
TypeCode_RP = 17;
|
|
TypeCode_AFSDB = 18;
|
|
TypeCode_X25 = 19;
|
|
TypeCode_ISDN = 20;
|
|
TypeCode_RT = 21;
|
|
TypeCode_NSAP = 22;
|
|
TypeCode_NSAP_PTR = 23;
|
|
TypeCode_SIG = 24;
|
|
TypeCode_KEY = 25;
|
|
TypeCode_PX = 26;
|
|
TypeCode_QPOS = 27;
|
|
TypeCode_AAAA = 28;
|
|
TypeCode_LOC = 29;
|
|
TypeCode_NXT = 30;
|
|
TypeCode_R31 = 31;
|
|
TypeCode_R32 = 32;
|
|
TypeCode_Service = 33;
|
|
TypeCode_R34 = 34;
|
|
TypeCode_NAPTR = 35;
|
|
TypeCode_KX = 36;
|
|
TypeCode_CERT = 37;
|
|
TypeCode_V6Addr = 38;
|
|
TypeCode_DNAME = 39;
|
|
TypeCode_R40 = 40;
|
|
TypeCode_OPTIONAL = 41;
|
|
TypeCode_IXFR = 251;
|
|
TypeCode_AXFR = 252;
|
|
TypeCode_STAR = 255;
|
|
TypeCode_Error = 0;
|
|
|
|
type
|
|
{NormalTags = (cA, cNS, cMD, cMF, cCName, cSOA, cMB, cMG, cMR, cNULL, cWKS, cPTR,
|
|
cHINFO, cMINFO, cMX, cTXT); }
|
|
TDNSQueryRecordTypes = (DqtA, DqtNS, DqtMD, DqtMF, DqtName, DqtSOA, DqtMB,
|
|
DqtMG, DqtMR, DqtNull, DqtWKS, DqtPTR, DqtHINFO, DqtMINFO, DqtMX, DqtTXT,
|
|
DqtNSAP, DqtNSAP_PTR, DqtLOC, DqtIXFR, DqtAXFR, DqtSTAR, DqtAAAA);
|
|
|
|
TDNSServerTypes = (stPrimary, stSecondary);
|
|
|
|
EIdDNSServerSyncException = class(EIdSilentException);
|
|
EIdDNSServerSettingException = class(EIdSilentException);
|
|
|
|
// TODO: enable AD and CD properties. Those fields are reserved in RFC 1035, but defined in RFC 6895
|
|
TDNSHeader = class
|
|
private
|
|
FID: UInt16;
|
|
FBitCode: UInt16;
|
|
FQDCount: UInt16;
|
|
FANCount: UInt16;
|
|
FNSCount: UInt16;
|
|
FARCount: UInt16;
|
|
function GetAA: UInt16;
|
|
//function GetAD: UInt16;
|
|
//function GetCD: UInt16;
|
|
function GetOpCode: UInt16;
|
|
function GetQr: UInt16;
|
|
function GetRA: UInt16;
|
|
function GetRCode: UInt16;
|
|
function GetRD: UInt16;
|
|
function GetTC: UInt16;
|
|
procedure SetAA(const Value: UInt16);
|
|
//procedure SetAD(const Value: UInt16);
|
|
//procedure SetCD(const Value: UInt16);
|
|
procedure SetOpCode(const Value: UInt16);
|
|
procedure SetQr(const Value: UInt16);
|
|
procedure SetRA(const Value: UInt16);
|
|
procedure SetRCode(const Value: UInt16);
|
|
procedure SetRD(const Value: UInt16);
|
|
procedure SetTC(const Value: UInt16);
|
|
procedure SetBitCode(const Value: UInt16);
|
|
public
|
|
constructor Create;
|
|
procedure ClearByteCode;
|
|
function ParseQuery(Data : TIdBytes) : integer;
|
|
function GenerateBinaryHeader : TIdBytes;
|
|
|
|
property ID: UInt16 read FID write FID;
|
|
property Qr: UInt16 read GetQr write SetQr;
|
|
property OpCode: UInt16 read GetOpCode write SetOpCode;
|
|
property AA: UInt16 read GetAA write SetAA;
|
|
//property AD: UInt16 get GetAD write SetAD;
|
|
//property CD: UInt16 get GetCD write SetCD;
|
|
property TC: UInt16 read GetTC write SetTC;
|
|
property RD: UInt16 read GetRD write SetRD;
|
|
property RA: UInt16 read GetRA write SetRA;
|
|
property RCode: UInt16 read GetRCode write SetRCode;
|
|
property BitCode: UInt16 read FBitCode write SetBitCode;
|
|
property QDCount: UInt16 read FQDCount write FQDCount;
|
|
property ANCount: UInt16 read FANCount write FANCount;
|
|
property NSCount: UInt16 read FNSCount write FNSCount;
|
|
property ARCount: UInt16 read FARCount write FARCount;
|
|
end;
|
|
|
|
TIdTextModeResourceRecord = class(TObject)
|
|
protected
|
|
FAnswer : TIdBytes;
|
|
FRRName: string;
|
|
FRRDatas: TStrings; //TODO Should not be TIdStrings
|
|
FTTL: Int32;
|
|
FTypeCode: Integer;
|
|
FTimeOut: string;
|
|
function FormatQName(const AFullName: string): string; overload;
|
|
function FormatQName(const AName, AFullName: string): string; overload;
|
|
function FormatQNameFull(const AFullName: string): string;
|
|
function FormatRecord(const AFullName: String; const ARRData: TIdBytes): TIdBytes;
|
|
procedure SetRRDatas(const Value: TStrings);
|
|
procedure SetTTL(const Value: Int32);
|
|
public
|
|
constructor CreateInit(const ARRName: String; ATypeCode: Integer);
|
|
destructor Destroy; override;
|
|
property TypeCode : Integer read FTypeCode;
|
|
property RRName : string read FRRName write FRRName;
|
|
property RRDatas : TStrings read FRRDatas write SetRRDatas;
|
|
property TTL : integer read FTTL write SetTTL;
|
|
property TimeOut : string read FTimeOut write FTimeOut;
|
|
function ifAddFullName(AFullName: string; AGivenName: string = ''): boolean;
|
|
function GetValue(const AName: String): String;
|
|
procedure SetValue(const AName: String; const AValue: String);
|
|
function ItemCount : Integer;
|
|
function BinQueryRecord(AFullName: string): TIdBytes; virtual;
|
|
function TextRecord(AFullName: string): string; virtual;
|
|
procedure ClearAnswer;
|
|
end;
|
|
|
|
TIdTextModeRRs = class(TIdObjectList{$IFDEF HAS_GENERICS_TObjectList}<TIdTextModeResourceRecord>{$ENDIF})
|
|
private
|
|
FItemNames : TStrings;
|
|
{$IFNDEF HAS_GENERICS_TObjectList}
|
|
function GetItem(Index: Integer): TIdTextModeResourceRecord;
|
|
procedure SetItem(Index: Integer; const Value: TIdTextModeResourceRecord);
|
|
{$ENDIF}
|
|
procedure SetItemNames(const Value: TStrings);
|
|
public
|
|
constructor Create;
|
|
destructor Destroy; override;
|
|
|
|
property ItemNames : TStrings read FItemNames write SetItemNames;
|
|
{$IFNDEF HAS_GENERICS_TObjectList}
|
|
property Items[Index: Integer]: TIdTextModeResourceRecord read GetItem write SetItem; default;
|
|
{$ENDIF}
|
|
end;
|
|
|
|
|
|
TIdRR_CName = class(TIdTextModeResourceRecord)
|
|
protected
|
|
function GetCName: String;
|
|
procedure SetCName(const Value: String);
|
|
public
|
|
constructor Create;
|
|
property CName : String read GetCName write SetCName;
|
|
function BinQueryRecord(AFullName: string): TIdBytes; override;
|
|
function TextRecord(AFullName : string) : string; override;
|
|
end;
|
|
|
|
|
|
TIdRR_HINFO = class(TIdTextModeResourceRecord)
|
|
protected
|
|
procedure SetCPU(const Value: String);
|
|
function GetCPU: String;
|
|
function GetOS: String;
|
|
procedure SetOS(const Value: String);
|
|
public
|
|
constructor Create;
|
|
property CPU : String read GetCPU write SetCPU;
|
|
property OS : String read GetOS write SetOS;
|
|
function BinQueryRecord(AFullName : string): TIdBytes; override;
|
|
function TextRecord(AFullName : string) : string; override;
|
|
end;
|
|
|
|
|
|
TIdRR_MB = class(TIdTextModeResourceRecord)
|
|
protected
|
|
function GetMADName: String;
|
|
procedure SetMADName(const Value: String);
|
|
public
|
|
constructor Create;
|
|
property MADName : String read GetMADName write SetMADName;
|
|
function BinQueryRecord(AFullName : string) : TIdBytes; override;
|
|
function TextRecord(AFullName : string) : string; override;
|
|
end;
|
|
|
|
|
|
TIdRR_MG = class(TIdTextModeResourceRecord)
|
|
protected
|
|
function GetMGMName: String;
|
|
procedure SetMGMName(const Value: String);
|
|
public
|
|
constructor Create;
|
|
property MGMName : String read GetMGMName write SetMGMName;
|
|
function BinQueryRecord(AFullName : string) : TIdBytes; override;
|
|
function TextRecord(AFullName : string) : string; override;
|
|
end;
|
|
|
|
|
|
TIdRR_MINFO = class(TIdTextModeResourceRecord)
|
|
protected
|
|
procedure SetErrorHandle_Mail(const Value: String);
|
|
procedure SetResponsible_Mail(const Value: String);
|
|
function GetEMail: String;
|
|
function GetRMail: String;
|
|
public
|
|
constructor Create;
|
|
property Responsible_Mail : String read GetRMail write SetResponsible_Mail;
|
|
property ErrorHandle_Mail : String read GetEMail write SetErrorHandle_Mail;
|
|
function BinQueryRecord(AFullName : string) : TIdBytes; override;
|
|
function TextRecord(AFullName : string) : string; override;
|
|
end;
|
|
|
|
|
|
TIdRR_MR = class(TIdTextModeResourceRecord)
|
|
protected
|
|
function GetNewName: String;
|
|
procedure SetNewName(const Value: String);
|
|
public
|
|
constructor Create;
|
|
property NewName : String read GetNewName write SetNewName;
|
|
function BinQueryRecord(AFullName : string) : TIdBytes; override;
|
|
function TextRecord(AFullName : string) : string; override;
|
|
end;
|
|
|
|
|
|
TIdRR_MX = class(TIdTextModeResourceRecord)
|
|
protected
|
|
function GetExchang: String;
|
|
procedure SetExchange(const Value: String);
|
|
function GetPref: String;
|
|
procedure SetPref(const Value: String);
|
|
public
|
|
constructor Create;
|
|
property Exchange : String read GetExchang write SetExchange;
|
|
property Preference : String read GetPref write SetPref;
|
|
function BinQueryRecord(AFullName : string) : TIdBytes; override;
|
|
function TextRecord(AFullName : string) : string; override;
|
|
end;
|
|
|
|
|
|
TIdRR_NS = class(TIdTextModeResourceRecord)
|
|
protected
|
|
function GetNS: String;
|
|
procedure SetNS(const Value: String);
|
|
public
|
|
constructor Create;
|
|
property NSDName : String read GetNS write SetNS;
|
|
function BinQueryRecord(AFullName : string): TIdBytes; override;
|
|
function TextRecord(AFullName : string) : string; override;
|
|
end;
|
|
|
|
|
|
TIdRR_PTR = class(TIdTextModeResourceRecord)
|
|
protected
|
|
function GetPTRName: String;
|
|
procedure SetPTRName(const Value: String);
|
|
public
|
|
constructor Create;
|
|
property PTRDName : String read GetPTRName write SetPTRName;
|
|
function BinQueryRecord(AFullName : string): TIdBytes; override;
|
|
function TextRecord(AFullName : string) : string; override;
|
|
end;
|
|
|
|
|
|
TIdRR_SOA = class(TIdTextModeResourceRecord)
|
|
protected
|
|
function GetName(const CLabel : String): String;
|
|
procedure SetName(const CLabel: String; const Value : String);
|
|
function GetMName: String;
|
|
function GetRName: String;
|
|
procedure SetMName(const Value: String);
|
|
procedure SetRName(const Value: String);
|
|
function GetMin: String;
|
|
function GetRefresh: String;
|
|
function GetRetry: String;
|
|
function GetSerial: String;
|
|
procedure SetMin(const Value: String);
|
|
procedure SetRefresh(const Value: String);
|
|
procedure SetRetry(const Value: String);
|
|
procedure SetSerial(const Value: String);
|
|
function GetExpire: String;
|
|
procedure SetExpire(const Value: String);
|
|
public
|
|
constructor Create;
|
|
property MName : String read GetMName write SetMName;
|
|
property RName : String read GetRName write SetRName;
|
|
property Serial : String read GetSerial write SetSerial;
|
|
property Refresh : String read GetRefresh write SetRefresh;
|
|
property Retry : String read GetRetry write SetRetry;
|
|
property Expire : String read GetExpire write SetExpire;
|
|
property Minimum : String read GetMin write SetMin;
|
|
function BinQueryRecord(AFullName : string) : TIdBytes; override;
|
|
function TextRecord(AFullName : string) : string; override;
|
|
end;
|
|
|
|
|
|
TIdRR_A = class(TIdTextModeResourceRecord)
|
|
protected
|
|
function GetA: String;
|
|
procedure SetA(const Value: String);
|
|
public
|
|
constructor Create;
|
|
property Address : String read GetA write SetA;
|
|
function BinQueryRecord(AFullName : string) : TIdBytes; override;
|
|
function TextRecord(AFullName : string) : string; override;
|
|
end;
|
|
|
|
TIdRR_AAAA = class(TIdTextModeResourceRecord)
|
|
protected
|
|
function GetA: String;
|
|
procedure SetA(const Value: String);
|
|
public
|
|
constructor Create;
|
|
property Address : String read GetA write SetA;
|
|
function BinQueryRecord(AFullName : string) : TIdBytes; override;
|
|
function TextRecord(AFullName : string) : string; override;
|
|
end;
|
|
|
|
{ TODO : implement WKS record class }
|
|
TIdRR_WKS = class(TIdTextModeResourceRecord)
|
|
public
|
|
constructor Create;
|
|
end;
|
|
|
|
TIdRR_TXT = class(TIdTextModeResourceRecord)
|
|
protected
|
|
function GetTXT: String;
|
|
procedure SetTXT(const Value: String);
|
|
public
|
|
constructor Create;
|
|
property TXT : String read GetTXT write SetTXT;
|
|
function BinQueryRecord(AFullName : string) : TIdBytes; override;
|
|
function TextRecord(AFullName : string) : string; override;
|
|
end;
|
|
|
|
TIdRR_Error = class(TIdTextModeResourceRecord)
|
|
public
|
|
constructor Create;
|
|
end;
|
|
|
|
function DomainNameToDNSStr(const ADomain : String): TIdBytes;
|
|
function NormalStrToDNSStr(const Str : String): TIdBytes;
|
|
function IPAddrToDNSStr(const IPAddress : String): TIdBytes;
|
|
function IsValidIPv6(const v6Address : String): Boolean;
|
|
function ConvertToValidv6IP(const OrgIP : String) : string;
|
|
function ConvertToCanonical6IP(const OrgIP : String) : string;
|
|
function IPv6AAAAToDNSStr(const AIPv6Address : String): TIdBytes;
|
|
function GetErrorStr(const Code, Id: Integer): String;
|
|
function GetRCodeStr(RCode : Integer): String;
|
|
function ReplaceSpecString(Source, Target, NewString : string; ReplaceAll : boolean = True) : string;
|
|
function IsBig5(ch1, ch2: Char) : Boolean;
|
|
|
|
implementation
|
|
|
|
uses
|
|
{$IFDEF VCL_XE3_OR_ABOVE}
|
|
{$IFNDEF NEXTGEN}
|
|
System.Contnrs,
|
|
{$ENDIF}
|
|
{$ENDIF}
|
|
{$IFDEF HAS_UNIT_DateUtils}
|
|
DateUtils,
|
|
{$ENDIF}
|
|
IdGlobalProtocols,
|
|
IdStack, SysUtils;
|
|
|
|
const
|
|
ValidHexChars = '0123456789ABCDEFabcdef';
|
|
|
|
procedure IdBytesCopyBytes(const ASource: TIdBytes; var VDest: TIdBytes; var VDestIndex: Integer);
|
|
begin
|
|
CopyTIdBytes(ASource, 0, VDest, VDestIndex, Length(ASource));
|
|
Inc(VDestIndex, Length(ASource));
|
|
end;
|
|
|
|
procedure IdBytesCopyUInt16(const ASource: UInt16; var VDest: TIdBytes; var VDestIndex: Integer);
|
|
begin
|
|
CopyTIdUInt16(ASource, VDest, VDestIndex);
|
|
Inc(VDestIndex, SizeOf(UInt16));
|
|
end;
|
|
|
|
procedure IdBytesCopyUInt32(const ASource: UInt32; var VDest: TIdBytes; var VDestIndex: Integer);
|
|
begin
|
|
CopyTIdUInt32(ASource, VDest, VDestIndex);
|
|
Inc(VDestIndex, SizeOf(UInt32));
|
|
end;
|
|
|
|
function DomainNameToDNSStr(const ADomain : string): TIdBytes;
|
|
var
|
|
BufStr, LDomain : String;
|
|
LIdx : Integer;
|
|
LLen: Byte;
|
|
begin
|
|
if Length(ADomain) = 0 then begin
|
|
SetLength(Result, 0);
|
|
end else begin
|
|
// TODO: ned to re-write this...
|
|
SetLength(Result, Length(ADomain)+1);
|
|
LIdx := 0;
|
|
LDomain := ADomain;
|
|
repeat
|
|
BufStr := Fetch(LDomain, '.');
|
|
LLen := Length(BufStr);
|
|
Result[LIdx] := LLen;
|
|
CopyTIdString(BufStr, Result, LIdx+1, LLen);
|
|
Inc(LIdx, LLen+1);
|
|
until LDomain = '';
|
|
Result[LIdx] := 0;
|
|
SetLength(Result, LIdx+1);
|
|
end;
|
|
end;
|
|
|
|
function NormalStrToDNSStr(const Str : String): TIdBytes;
|
|
var
|
|
LLen: Byte;
|
|
LStr: TIdBytes;
|
|
begin
|
|
LStr := ToBytes(Str);
|
|
LLen := IndyMin(Length(LStr), $FF);
|
|
SetLength(Result, 1 + LLen);
|
|
Result[0] := LLen;
|
|
CopyTIdBytes(LStr, 0, Result, 1, LLen);
|
|
end;
|
|
|
|
function IPAddrToDNSStr(const IPAddress : String): TIdBytes;
|
|
Var
|
|
j, i: Integer;
|
|
s : string;
|
|
begin
|
|
SetLength(Result, 0);
|
|
if IsValidIP(IPAddress) then begin
|
|
s := Trim(IPAddress);
|
|
SetLength(Result, 4);
|
|
for i := 0 to 3 do begin
|
|
j := IndyStrToInt(Fetch(s, '.'), -1); {do not localize}
|
|
if (j < 0) or (j > 255) then begin
|
|
Result := ToBytes('Error IP'); {do not localize}
|
|
Exit;
|
|
end;
|
|
Result[I] := Byte(j);
|
|
end;
|
|
end else begin
|
|
Result := ToBytes('Error IP'); {do not localize}
|
|
end;
|
|
end;
|
|
|
|
procedure IdHexToBin(const AText: TIdBytes; var Buffer: TIdBytes; const BufSize: Integer);
|
|
const
|
|
Convert: array['0'..'f'] of Int16 = {do not localize}
|
|
( 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,-1,-1,-1,-1,-1,-1,
|
|
-1,10,11,12,13,14,15,-1,-1,-1,-1,-1,-1,-1,-1,-1,
|
|
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
|
|
-1,10,11,12,13,14,15);
|
|
var
|
|
BufferPos, TextPos: Integer;
|
|
ValidChars: TIdBytes;
|
|
begin
|
|
ValidChars := ToBytes(ValidHexChars);
|
|
BufferPos := 0;
|
|
TextPos := 0;
|
|
repeat
|
|
if (not ByteIsInSet(AText, TextPos, ValidChars)) or
|
|
(not ByteIsInSet(AText, TextPos+1, ValidChars)) then
|
|
begin
|
|
Break;
|
|
end;
|
|
Buffer[BufferPos] := (Convert[Char(AText[TextPos])] shl 4) + Convert[Char(AText[TextPos + 1])];
|
|
Inc(BufferPos);
|
|
Inc(TextPos, 2);
|
|
until False;
|
|
end;
|
|
|
|
function IPv6AAAAToDNSStr(const AIPv6Address : String): TIdBytes;
|
|
var
|
|
LAddr : TIdIPv6Address;
|
|
begin
|
|
IPv6ToIdIPv6Address(AIPv6Address, LAddr);
|
|
SetLength(Result, 16);
|
|
CopyTIdIPV6Address(LAddr, Result, 0);
|
|
end;
|
|
|
|
function IsValidIPv6(const v6Address : String): boolean;
|
|
var
|
|
Temps : TStrings;
|
|
Apart, All: String;
|
|
Count, Loc, Goal : integer;
|
|
begin
|
|
All := v6Address;
|
|
Temps := TStringList.Create;
|
|
try
|
|
// Check Double Colon existence, but only single.
|
|
Count := 0;
|
|
|
|
repeat
|
|
Loc := IndyPos('::', All); {do not localize}
|
|
if Loc > 0 then begin
|
|
Count := Count + 1;
|
|
IdDelete(All, Loc, 2);
|
|
end;
|
|
until Loc = 0;
|
|
|
|
if Count <= 1 then begin
|
|
// Convert Double colon into compatible format.
|
|
All := ReplaceSpecString(v6Address, '::', ':Multi:'); {do not localize}
|
|
repeat
|
|
Apart := Fetch(All, ':'); {do not localize}
|
|
Temps.Add(Apart);
|
|
until All = ''; {do not localize}
|
|
|
|
Loc := Temps.IndexOf('Multi'); {do not localize}
|
|
if Loc > -1 then begin
|
|
Goal := 8 - Temps.Count;
|
|
Temps.Strings[Loc] := '0000'; {do not localize}
|
|
for Count := 0 to Goal -1 do begin
|
|
Temps.Insert(Loc, '0000'); {do not localize}
|
|
end;
|
|
if Temps.Strings[0] = '' then begin {do not localize}
|
|
Temps.Strings[0] := '0000'; {do not localize}
|
|
end;
|
|
end;
|
|
|
|
All := ReplaceSpecString(Temps.CommaText, ',', ':'); {do not localize}
|
|
Result := True;
|
|
Temps.Clear;
|
|
|
|
repeat
|
|
Apart := Trim(Fetch(All, ':')); {do not localize}
|
|
if Length(Apart) <= 4 then begin
|
|
Apart := '0000' + Apart; {do not localize}
|
|
Apart := Copy(Apart, Length(Apart)-3, 4);
|
|
Temps.Add(Apart);
|
|
end else begin
|
|
Result := False;
|
|
end;
|
|
until (All = '') or (not Result); {do not localize}
|
|
|
|
if (not Result) or (Temps.Count > 8) then begin
|
|
Result := False;
|
|
end else begin
|
|
for Count := 0 to Temps.Count -1 do begin
|
|
All := All + Temps.Strings[Count];
|
|
end;
|
|
Result := Length(All) > 0;
|
|
for Count := 1 to Length(All) do begin
|
|
Result := CharIsInSet(All, Count, ValidHexChars);
|
|
if not Result then begin
|
|
Break;
|
|
end;
|
|
end;
|
|
end;
|
|
end else begin
|
|
// mulitple Double colon, it's an incorrect IPv6 address.
|
|
Result := False;
|
|
end;
|
|
finally
|
|
FreeAndNil(Temps);
|
|
end;
|
|
end;
|
|
|
|
function ConvertToValidv6IP(const OrgIP : String) : string;
|
|
var
|
|
All, Apart : string;
|
|
Temps : TStrings;
|
|
Count, Loc, Goal : integer;
|
|
begin
|
|
Result := '';
|
|
All := OrgIP;
|
|
Temps := TStringList.Create;
|
|
try
|
|
// Check Double Colon existence, but only single.
|
|
// Count := 0;
|
|
|
|
repeat
|
|
Loc := IndyPos('::', All); {do not localize}
|
|
if Loc > 0 then begin
|
|
// Count := Count + 1;
|
|
IdDelete(All, Loc, 2);
|
|
end;
|
|
until Loc = 0;
|
|
|
|
// Convert Double colon into compatible format.
|
|
All := ReplaceSpecString(OrgIP, '::', ':Multi:'); {do not localize}
|
|
repeat
|
|
Apart := Fetch(All, ':'); {do not localize}
|
|
Temps.Add(Apart);
|
|
until All = ''; {do not localize}
|
|
|
|
Loc := Temps.IndexOf('Multi'); {do not localize}
|
|
if Loc > -1 then begin
|
|
Goal := 8 - Temps.Count;
|
|
Temps.Strings[Loc] := '0000'; {do not localize}
|
|
for Count := 0 to Goal -1 do begin
|
|
Temps.Insert(Loc, '0000'); {do not localize}
|
|
end;
|
|
if Temps.Strings[0] = '' then begin
|
|
Temps.Strings[0] := '0000'; {do not localize}
|
|
end;
|
|
end;
|
|
Result := ReplaceSpecString(Temps.CommaText, ',', ':'); {do not localize}
|
|
finally
|
|
FreeAndNil(Temps);
|
|
end;
|
|
end;
|
|
|
|
function ConvertToCanonical6IP(const OrgIP : String) : string;
|
|
var
|
|
All, Apart: string;
|
|
begin
|
|
{Supposed OrgIP is valid IPV6 string}
|
|
Result := ''; {do not localize}
|
|
All := ConvertToValidv6IP(OrgIP);
|
|
repeat
|
|
Apart := Trim(Fetch(All, ':')); {do not localize}
|
|
if Length(Apart) < 4 then
|
|
begin
|
|
Apart := '0000' + Apart; {do not localize}
|
|
Apart := Copy(Apart, Length(Apart)-3, 4);
|
|
end;
|
|
Result := Result + Apart + ':'; {do not localize}
|
|
until (All = ''); {do not localize}
|
|
SetLength(Result, Length(Result) - 1); //Remove last :
|
|
end;
|
|
|
|
{ TODO : Move these to member }
|
|
function GetErrorStr(const Code, Id: Integer): String;
|
|
begin
|
|
case Code of
|
|
1 : Result := IndyFormat(RSQueryInvalidQueryCount, [Id]);
|
|
2 : Result := IndyFormat(RSQueryInvalidPacketSize, [Id]);
|
|
3 : Result := IndyFormat(RSQueryLessThanFour, [Id]);
|
|
4 : Result := IndyFormat(RSQueryInvalidHeaderID, [Id] );
|
|
5 : Result := IndyFormat(RSQueryLessThanTwelve, [Id]);
|
|
6 : Result := IndyFormat(RSQueryPackReceivedTooSmall, [Id]);
|
|
else
|
|
Result := IndyFormat(RSQueryUnknownError, [Code, Id]);
|
|
end; //case code Of
|
|
end;
|
|
|
|
function GetRCodeStr(RCode : Integer): String;
|
|
begin
|
|
if Rcode in [cRCodeNoError..cRCodeRefused] then begin
|
|
Result := cRCodeStrs[Rcode];
|
|
end else begin // if Rcode in [cRCodeNoError..cRCodeRefused] then
|
|
Result := RSCodeQueryUnknownError;
|
|
end; //else.. if Rcode in [cRCodeNoError..cRCodeRefused] then
|
|
end;
|
|
|
|
|
|
{ TDNSHeader }
|
|
|
|
procedure TDNSHeader.ClearByteCode;
|
|
begin
|
|
FBitCode := 0;
|
|
end;
|
|
|
|
constructor TDNSHeader.Create;
|
|
begin
|
|
inherited Create;
|
|
Randomize;
|
|
FId := Random(65535);
|
|
end;
|
|
|
|
function TDNSHeader.GenerateBinaryHeader: TIdBytes;
|
|
{
|
|
|
|
|
|
The header contains the following fields:
|
|
|
|
1 1 1 1 1 1
|
|
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
|
|
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|
|
| ID |
|
|
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|
|
|QR| Opcode |AA|TC|RD|RA| Z|AD|CD| RCODE |
|
|
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|
|
| QDCOUNT/ZOCOUNT |
|
|
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|
|
| ANCOUNT/PRCOUNT |
|
|
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|
|
| NSCOUNT/UPCOUNT |
|
|
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|
|
| ARCOUNT |
|
|
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|
|
|
|
where:
|
|
|
|
ID A 16 bit identifier assigned by the program that
|
|
generates any kind of query. This identifier is copied
|
|
the corresponding reply and can be used by the requester
|
|
to match up replies to outstanding queries.
|
|
|
|
QR A one bit field that specifies whether this message is a
|
|
query (0), or a response (1).
|
|
|
|
OPCODE A four bit field that specifies kind of query in this
|
|
message. This value is set by the originator of a query
|
|
and copied into the response. The values are:
|
|
|
|
0 a standard query (QUERY)
|
|
|
|
1 an inverse query (IQUERY)
|
|
|
|
2 a server status request (STATUS)
|
|
|
|
3-15 reserved for future use
|
|
|
|
AA Authoritative Answer - this bit is valid in responses,
|
|
and specifies that the responding name server is an
|
|
authority for the domain name in question section.
|
|
|
|
Note that the contents of the answer section may have
|
|
multiple owner names because of aliases. The AA bit
|
|
|
|
corresponds to the name which matches the query name, or
|
|
the first owner name in the answer section.
|
|
|
|
TC TrunCation - specifies that this message was truncated
|
|
due to length greater than that permitted on the
|
|
transmission channel.
|
|
|
|
RD Recursion Desired - this bit may be set in a query and
|
|
is copied into the response. If RD is set, it directs
|
|
the name server to pursue the query recursively.
|
|
Recursive query support is optional.
|
|
|
|
RA Recursion Available - this be is set or cleared in a
|
|
response, and denotes whether recursive query support is
|
|
available in the name server.
|
|
|
|
Z Reserved for future use. Must be zero in all queries
|
|
and responses.
|
|
|
|
AD Authentic Data - signal indicating that the requester
|
|
understands and is interested in the value of the AD bit
|
|
in the response. This allows a requester to indicate that
|
|
it understands the AD bit without also requesting DNSSEC
|
|
data via the DO bit.
|
|
|
|
CD Checking Disabled
|
|
|
|
RCODE Response code - this 4 bit field is set as part of
|
|
responses. The values have the following
|
|
interpretation:
|
|
|
|
0 No error condition
|
|
|
|
1 Format error - The name server was
|
|
unable to interpret the query.
|
|
|
|
2 Server failure - The name server was
|
|
unable to process this query due to a
|
|
problem with the name server.
|
|
|
|
3 Name Error - Meaningful only for
|
|
responses from an authoritative name
|
|
server, this code signifies that the
|
|
domain name referenced in the query does
|
|
not exist.
|
|
|
|
4 Not Implemented - The name server does
|
|
not support the requested kind of query.
|
|
|
|
5 Refused - The name server refuses to
|
|
perform the specified operation for
|
|
policy reasons. For example, a name
|
|
server may not wish to provide the
|
|
information to the particular requester,
|
|
or a name server may not wish to perform
|
|
a particular operation (e.g., zone
|
|
|
|
transfer) for particular data.
|
|
|
|
6-15 Reserved for future use.
|
|
|
|
QDCOUNT an unsigned 16 bit integer specifying the number of
|
|
entries in the question section.
|
|
|
|
ANCOUNT an unsigned 16 bit integer specifying the number of
|
|
resource records in the answer section.
|
|
|
|
NSCOUNT an unsigned 16 bit integer specifying the number of name
|
|
server resource records in the authority records
|
|
section.
|
|
|
|
ARCOUNT an unsigned 16 bit integer specifying the number of
|
|
resource records in the additional records section.
|
|
}
|
|
begin
|
|
SetLength(Result, 12);
|
|
UInt16ToTwoBytes(GStack.HostToNetwork(ID), Result, 0);
|
|
UInt16ToTwoBytes(GStack.HostToNetwork(BitCode), Result, 2);
|
|
UInt16ToTwoBytes(GStack.HostToNetwork(QDCount), Result, 4);
|
|
UInt16ToTwoBytes(GStack.HostToNetwork(ANCount), Result, 6);
|
|
UInt16ToTwoBytes(GStack.HostToNetwork(NSCount), Result, 8);
|
|
UInt16ToTwoBytes(GStack.HostToNetwork(ARCount), Result, 10);
|
|
end;
|
|
|
|
function TDNSHeader.GetAA: UInt16;
|
|
begin
|
|
Result := (FBitCode shr 10) and $0001;
|
|
end;
|
|
|
|
{
|
|
function TDNSHeader.GetAD: UInt16;
|
|
begin
|
|
Result := (FBitCode shr 5) and $0001;
|
|
end;
|
|
|
|
function TDNSHeader.GetCD: UInt16;
|
|
begin
|
|
Result := (FBitCode shr 4) and $0001;
|
|
end;
|
|
}
|
|
|
|
function TDNSHeader.GetOpCode: UInt16;
|
|
begin
|
|
Result := (FBitCode shr 11) and $000F;
|
|
end;
|
|
|
|
function TDNSHeader.GetQr: UInt16;
|
|
begin
|
|
Result := (FBitCode shr 15) and $0001;
|
|
end;
|
|
|
|
function TDNSHeader.GetRA: UInt16;
|
|
begin
|
|
Result := (FBitCode shr 7) and $0001;
|
|
end;
|
|
|
|
function TDNSHeader.GetRCode: UInt16;
|
|
begin
|
|
Result := FBitCode and $000F;
|
|
end;
|
|
|
|
function TDNSHeader.GetRD: UInt16;
|
|
begin
|
|
Result := (FBitCode shr 8) and $0001;
|
|
end;
|
|
|
|
function TDNSHeader.GetTC: UInt16;
|
|
begin
|
|
Result := (FBitCode shr 9) and $0001;
|
|
end;
|
|
|
|
function TDNSHeader.ParseQuery(Data: TIdBytes): integer;
|
|
begin
|
|
Result := -1;
|
|
if Length(Data) >= 12 then begin
|
|
try
|
|
ID := GStack.NetworkToHost(BytesToUInt16(Data, 0));
|
|
BitCode := GStack.NetworkToHost(BytesToUInt16(Data, 2));
|
|
QDCount := GStack.NetworkToHost(BytesToUInt16(Data, 4));
|
|
ANCount := GStack.NetworkToHost(BytesToUInt16(Data, 6));
|
|
NSCount := GStack.NetworkToHost(BytesToUInt16(Data, 8));
|
|
ARCount := GStack.NetworkToHost(BytesToUInt16(Data, 10));
|
|
Result := 0;
|
|
except
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TDNSHeader.SetAA(const Value: UInt16);
|
|
begin
|
|
if Value = 0 then begin
|
|
FBitCode := FBitCode and $FBFF;
|
|
end else begin
|
|
FBitCode := FBitCode or $0400;
|
|
end;
|
|
end;
|
|
|
|
{
|
|
procedure TDNSHeader.SetAD(const Value: UInt16);
|
|
begin
|
|
if Value = 0 then begin
|
|
FBitCode := FBitCode and $FFDF;
|
|
end else begin
|
|
FBitCode := FBitCode or $0020;
|
|
end;
|
|
end;
|
|
}
|
|
|
|
procedure TDNSHeader.SetBitCode(const Value: UInt16);
|
|
begin
|
|
FBitCode := Value;
|
|
end;
|
|
|
|
{
|
|
procedure TDNSHeader.SetCD(const Value: UInt16);
|
|
begin
|
|
if Value = 0 then begin
|
|
FBitCode := FBitCode and $FFEF;
|
|
end else begin
|
|
FBitCode := FBitCode or $0010;
|
|
end;
|
|
end;
|
|
}
|
|
|
|
procedure TDNSHeader.SetOpCode(const Value: UInt16);
|
|
begin
|
|
FBitCode := (FBitCode and $87FF) or ((Value and $000F) shl 11);
|
|
end;
|
|
|
|
procedure TDNSHeader.SetQr(const Value: UInt16);
|
|
begin
|
|
if Value = 0 then begin
|
|
FBitCode := FBitCode and $7FFF;
|
|
end else begin
|
|
FBitCode := FBitCode or $8000;
|
|
end;
|
|
end;
|
|
|
|
procedure TDNSHeader.SetRA(const Value: UInt16);
|
|
begin
|
|
if Value = 0 then begin
|
|
FBitCode := FBitCode and $FF7F;
|
|
end else begin
|
|
FBitCode := FBitCode or $0080;
|
|
end;
|
|
end;
|
|
|
|
procedure TDNSHeader.SetRCode(const Value: UInt16);
|
|
begin
|
|
FBitCode := (FBitCode and $FFF0) or (Value and $000F);
|
|
end;
|
|
|
|
procedure TDNSHeader.SetRD(const Value: UInt16);
|
|
begin
|
|
if Value = 0 then begin
|
|
FBitCode := FBitCode and $FEFF;
|
|
end else begin
|
|
FBitCode := FBitCode or $0100;
|
|
end;
|
|
end;
|
|
|
|
procedure TDNSHeader.SetTC(const Value: UInt16);
|
|
begin
|
|
if Value = 0 then begin
|
|
FBitCode := FBitCode and $FDFF;
|
|
end else begin
|
|
FBitCode := FBitCode or $0200;
|
|
end;
|
|
end;
|
|
|
|
|
|
{ TIdTextModeResourceRecord }
|
|
|
|
function TIdTextModeResourceRecord.BinQueryRecord(AFullName: string): TIdBytes;
|
|
begin
|
|
// This was empty? Where did it go?
|
|
//todo;
|
|
// Explain by Dennies : No, here must be empty, it's only a
|
|
// virtual method, for child class to implement.
|
|
Result := nil;
|
|
end;
|
|
|
|
procedure TIdTextModeResourceRecord.ClearAnswer;
|
|
begin
|
|
SetLength(FAnswer, 0);
|
|
end;
|
|
|
|
constructor TIdTextModeResourceRecord.CreateInit(const ARRName: String; ATypeCode: Integer);
|
|
begin
|
|
inherited Create;
|
|
SetLength(FAnswer, 0);
|
|
FRRName := ARRName;
|
|
FTypeCode := ATypeCode;
|
|
FRRDatas := TStringList.Create;
|
|
TTL := 0;
|
|
end;
|
|
|
|
destructor TIdTextModeResourceRecord.Destroy;
|
|
begin
|
|
FreeAndNil(FRRDatas);
|
|
inherited Destroy;
|
|
end;
|
|
|
|
function TIdTextModeResourceRecord.FormatQName(const AFullName: string): string;
|
|
begin
|
|
Result := FormatQName(FRRName, AFullName);
|
|
end;
|
|
|
|
function TIdTextModeResourceRecord.FormatQName(const AName, AFullName: string): string;
|
|
begin
|
|
if Copy(AName, Length(AName), 1) <> '.' then begin
|
|
Result := AName + '.' + AFullName;
|
|
end else begin
|
|
Result := AName;
|
|
end;
|
|
end;
|
|
|
|
function TIdTextModeResourceRecord.FormatQNameFull(const AFullName: string): string;
|
|
var
|
|
LQName: string;
|
|
begin
|
|
LQName := FRRName + '.';
|
|
if LQName <> AFullName then begin
|
|
LQName := FormatQName(AFullName);
|
|
end;
|
|
if LQName = AFullName then begin
|
|
Result := '@';
|
|
end else begin
|
|
Result := LQName;
|
|
end;
|
|
end;
|
|
|
|
function TIdTextModeResourceRecord.FormatRecord(const AFullName: String; const ARRData: TIdBytes): TIdBytes;
|
|
var
|
|
LDomain: TIdBytes;
|
|
LIdx: Integer;
|
|
begin
|
|
LDomain := DomainNameToDNSStr(FormatQName(AFullName));
|
|
SetLength(Result, Length(LDomain)+(SizeOf(UInt16)*3)+SizeOf(UInt32)+Length(ARRData));
|
|
LIdx := 0;
|
|
IdBytesCopyBytes(LDomain, Result, LIdx);
|
|
IdBytesCopyUInt16(GStack.HostToNetwork(UInt16(TypeCode)), Result, LIdx);
|
|
IdBytesCopyUInt16(GStack.HostToNetwork(UInt16(Class_IN)), Result, LIdx);
|
|
IdBytesCopyUInt32(GStack.HostToNetwork(UInt32(TTL)), Result, LIdx);
|
|
IdBytesCopyUInt16(GStack.HostToNetwork(UInt16(Length(ARRData))), Result, LIdx);
|
|
IdBytesCopyBytes(ARRData, Result, LIdx);
|
|
end;
|
|
|
|
function TIdTextModeResourceRecord.GetValue(const AName: String): String;
|
|
begin
|
|
Result := RRDatas.Values[AName];
|
|
end;
|
|
|
|
procedure TIdTextModeResourceRecord.SetValue(const AName: String; const AValue: String);
|
|
begin
|
|
RRDatas.Values[AName] := AValue;
|
|
end;
|
|
|
|
function TIdTextModeResourceRecord.ifAddFullName(AFullName, AGivenName: string): boolean;
|
|
var
|
|
LTailString, LBackString, LDestination : string;
|
|
LTS, LRR : integer;
|
|
begin
|
|
if AGivenName = '' then begin
|
|
LDestination := RRName;
|
|
end else begin
|
|
LDestination := AGivenName;
|
|
end;
|
|
|
|
if TextEndsWith(LDestination, '.') then begin
|
|
Result := False;
|
|
end else begin
|
|
if TextEndsWith(AFullName, '.') then begin
|
|
LTailString := Copy(AFullName, 1, Length(AFullName) - 1);
|
|
end else begin
|
|
LTailString := AFullName;
|
|
end;
|
|
|
|
LTS := Length(LTailString);
|
|
LRR := Length(LDestination);
|
|
|
|
if LRR >= LTS then begin
|
|
LBackString := Copy(LDestination, LRR - LTS + 1 , LTS);
|
|
Result := not (LBackString = LTailString);
|
|
end else begin
|
|
Result := True;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
function TIdTextModeResourceRecord.ItemCount: integer;
|
|
begin
|
|
Result := RRDatas.Count;
|
|
end;
|
|
|
|
procedure TIdTextModeResourceRecord.SetRRDatas(const Value: TStrings);
|
|
begin
|
|
FRRDatas.Assign(Value);
|
|
end;
|
|
|
|
procedure TIdTextModeResourceRecord.SetTTL(const Value: integer);
|
|
begin
|
|
FTTL := Value;
|
|
FTimeOut := DateTimeToStr(AddMSecToTime(Now, Value * 1000));
|
|
end;
|
|
|
|
function TIdTextModeResourceRecord.TextRecord(AFullName: string): string;
|
|
begin
|
|
Result := '';
|
|
end;
|
|
|
|
{ TIdTextModeRRs }
|
|
|
|
constructor TIdTextModeRRs.Create;
|
|
begin
|
|
inherited Create;
|
|
FItemNames := TStringList.Create;
|
|
end;
|
|
|
|
destructor TIdTextModeRRs.Destroy;
|
|
begin
|
|
FreeAndNil(FItemNames);
|
|
inherited Destroy;
|
|
end;
|
|
|
|
{$IFNDEF HAS_GENERICS_TObjectList}
|
|
function TIdTextModeRRs.GetItem(Index: Integer): TIdTextModeResourceRecord;
|
|
begin
|
|
Result := TIdTextModeResourceRecord(inherited GetItem(Index));
|
|
end;
|
|
|
|
procedure TIdTextModeRRs.SetItem(Index: Integer; const Value: TIdTextModeResourceRecord);
|
|
begin
|
|
inherited SetItem(Index, Value);
|
|
end;
|
|
{$ENDIF}
|
|
|
|
procedure TIdTextModeRRs.SetItemNames(const Value: TStrings);
|
|
begin
|
|
FItemNames.Assign(Value);
|
|
end;
|
|
|
|
{ TIdRR_CName }
|
|
|
|
function TIdRR_CName.BinQueryRecord(AFullName: string): TIdBytes;
|
|
var
|
|
RRData: TIdBytes;
|
|
begin
|
|
RRData := nil; // keep the compiler happy
|
|
if Length(FAnswer) = 0 then begin
|
|
RRData := DomainNameToDNSStr(CName);
|
|
FAnswer := FormatRecord(AFullName, RRData);
|
|
end;
|
|
Result := ToBytes(FAnswer, Length(FAnswer));
|
|
end;
|
|
|
|
constructor TIdRR_CName.Create;
|
|
begin
|
|
inherited CreateInit('CName', TypeCode_CName); {do not localize}
|
|
CName := '';
|
|
end;
|
|
|
|
function TIdRR_CName.GetCName: String;
|
|
begin
|
|
Result := GetValue('CName'); {do not localize}
|
|
end;
|
|
|
|
procedure TIdRR_CName.SetCName(const Value: String);
|
|
begin
|
|
SetValue('CName', Value); {do not localize}
|
|
end;
|
|
|
|
function TIdRR_CName.TextRecord(AFullName: string): string;
|
|
begin
|
|
Result := FormatQNameFull(AFullName) + Chr(9) + 'IN' + Chr(9) + 'CNAME' + Chr(9) + CName + EOL; {do not localize}
|
|
end;
|
|
|
|
{ TIdRR_HINFO }
|
|
|
|
function TIdRR_HINFO.BinQueryRecord(AFullName: string): TIdBytes;
|
|
var
|
|
RRData: TIdBytes;
|
|
begin
|
|
if Length(FAnswer) = 0 then begin
|
|
RRData := NormalStrToDNSStr(CPU);
|
|
AppendBytes(RRData, NormalStrToDNSStr(OS));
|
|
FAnswer := FormatRecord(AFullName, RRData);
|
|
end;
|
|
Result := ToBytes(FAnswer, Length(FAnswer));
|
|
end;
|
|
|
|
constructor TIdRR_HINFO.Create;
|
|
begin
|
|
inherited CreateInit('HINFO', TypeCode_HINFO); {do not localize}
|
|
CPU := '';
|
|
OS := '';
|
|
end;
|
|
|
|
function TIdRR_HINFO.GetCPU: String;
|
|
begin
|
|
Result := GetValue('CPU'); {do not localize}
|
|
end;
|
|
|
|
function TIdRR_HINFO.GetOS: String;
|
|
begin
|
|
Result := GetValue('OS'); {do not localize}
|
|
end;
|
|
|
|
procedure TIdRR_HINFO.SetCPU(const Value: String);
|
|
begin
|
|
SetValue('CPU', Value); {do not localize}
|
|
end;
|
|
|
|
procedure TIdRR_HINFO.SetOS(const Value: String);
|
|
begin
|
|
SetValue('OS', Value); {do not localize}
|
|
end;
|
|
|
|
function TIdRR_HINFO.TextRecord(AFullName: string): string;
|
|
begin
|
|
Result := FormatQNameFull(AFullName) + Chr(9) + 'IN' + Chr(9) + 'HINFO' + Chr(9)
|
|
+ '"' + CPU + '" "' + OS + '"' + EOL; {do not localize}
|
|
end;
|
|
|
|
{ TIdRR_MB }
|
|
|
|
function TIdRR_MB.BinQueryRecord(AFullName: string): TIdBytes;
|
|
var
|
|
RRData: TIdBytes;
|
|
begin
|
|
RRData := nil; // keep the compiler happy
|
|
if Length(FAnswer) = 0 then begin
|
|
RRData := DomainNameToDNSStr(MADName);
|
|
FAnswer := FormatRecord(AFullName, RRData);
|
|
end;
|
|
Result := ToBytes(FAnswer, Length(FAnswer));
|
|
end;
|
|
|
|
constructor TIdRR_MB.Create;
|
|
begin
|
|
inherited CreateInit('MB', TypeCode_MB); {do not localize}
|
|
MADName := '';
|
|
end;
|
|
|
|
function TIdRR_MB.GetMADName: String;
|
|
begin
|
|
Result := GetValue('MADNAME'); {do not localize}
|
|
end;
|
|
|
|
procedure TIdRR_MB.SetMADName(const Value: String);
|
|
begin
|
|
SetValue('MADNAME', Value); {do not localize}
|
|
end;
|
|
|
|
function TIdRR_MB.TextRecord(AFullName: string): string;
|
|
begin
|
|
Result := FormatQNameFull(AFullName) + Chr(9) + 'IN' + Chr(9) + 'MB' + Chr(9) + MADName + EOL; {do not localize}
|
|
end;
|
|
|
|
{ TIdRR_MG }
|
|
|
|
function TIdRR_MG.BinQueryRecord(AFullName: string): TIdBytes;
|
|
var
|
|
RRData: TIdBytes;
|
|
begin
|
|
RRData := nil; // keep the compiler happy
|
|
if Length(FAnswer) = 0 then begin
|
|
RRData := DomainNameToDNSStr(MGMName);
|
|
FAnswer := FormatRecord(AFullName, RRData);
|
|
end;
|
|
Result := ToBytes(FAnswer, Length(FAnswer));
|
|
end;
|
|
|
|
constructor TIdRR_MG.Create;
|
|
begin
|
|
inherited CreateInit('MG', TypeCode_MG); {do not localize}
|
|
MGMName := '';
|
|
end;
|
|
|
|
function TIdRR_MG.GetMGMName: String;
|
|
begin
|
|
Result := GetValue('MGMNAME'); {do not localize}
|
|
end;
|
|
|
|
procedure TIdRR_MG.SetMGMName(const Value: String);
|
|
begin
|
|
SetValue('MGMNAME', Value); {do not localize}
|
|
end;
|
|
|
|
function TIdRR_MG.TextRecord(AFullName: string): string;
|
|
begin
|
|
Result := FormatQNameFull(AFullName) + Chr(9) + 'IN' + Chr(9) + 'MG' + Chr(9) + MGMName + EOL; {do not localize}
|
|
end;
|
|
|
|
{ TIdRR_MINFO }
|
|
|
|
function TIdRR_MINFO.BinQueryRecord(AFullName: string): TIdBytes;
|
|
var
|
|
RRData: TIdBytes;
|
|
{
|
|
From: http://www.its.uq.edu.au/DMT/RFC/rfc1035.html#MINFO_RR
|
|
3.3.7. MINFO RDATA format (EXPERIMENTAL)
|
|
|
|
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|
|
/ RMAILBX /
|
|
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|
|
/ EMAILBX /
|
|
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|
|
}
|
|
begin
|
|
if Length(FAnswer) = 0 then begin
|
|
RRData := DomainNameToDNSStr(Responsible_Mail);
|
|
AppendBytes(RRData, DomainNameToDNSStr(ErrorHandle_Mail));
|
|
FAnswer := FormatRecord(AFullName, RRData);
|
|
end;
|
|
Result := ToBytes(FAnswer, Length(FAnswer));
|
|
end;
|
|
|
|
constructor TIdRR_MINFO.Create;
|
|
begin
|
|
inherited CreateInit('MINFO', TypeCode_MINFO); {do not localize}
|
|
Responsible_Mail := '';
|
|
ErrorHandle_Mail := '';
|
|
end;
|
|
|
|
function TIdRR_MINFO.GetEMail: String;
|
|
begin
|
|
Result := GetValue('EMAILBX'); {do not localize}
|
|
end;
|
|
|
|
function TIdRR_MINFO.GetRMail: String;
|
|
begin
|
|
Result := GetValue('RMAILBX'); {do not localize}
|
|
end;
|
|
|
|
procedure TIdRR_MINFO.SetErrorHandle_Mail(const Value: String);
|
|
begin
|
|
SetValue('EMAILBX', Value); {do not localize}
|
|
end;
|
|
|
|
procedure TIdRR_MINFO.SetResponsible_Mail(const Value: String);
|
|
begin
|
|
SetValue('RMAILBX', Value); {do not localize}
|
|
end;
|
|
|
|
function TIdRR_MINFO.TextRecord(AFullName: string): string;
|
|
begin
|
|
Result := FormatQNameFull(AFullName) + Chr(9) + 'IN' + Chr(9) + 'MINFO' + Chr(9) {do not localize}
|
|
+ Responsible_Mail + ' ' + ErrorHandle_Mail + EOL; {do not localize}
|
|
end;
|
|
|
|
{ TIdRR_MR }
|
|
|
|
function TIdRR_MR.BinQueryRecord(AFullName: string): TIdBytes;
|
|
var
|
|
RRData: TIdBytes;
|
|
begin
|
|
RRData := nil; // keep the compiler happy
|
|
if Length(FAnswer) = 0 then begin
|
|
RRData := DomainNameToDNSStr(NewName);
|
|
FAnswer := FormatRecord(AFullName, RRData);
|
|
end;
|
|
Result := ToBytes(FAnswer, Length(FAnswer));
|
|
end;
|
|
|
|
constructor TIdRR_MR.Create;
|
|
begin
|
|
inherited CreateInit('MR', TypeCode_MR); {do not localize}
|
|
NewName := '';
|
|
end;
|
|
|
|
function TIdRR_MR.GetNewName: String;
|
|
begin
|
|
Result := GetValue('NewName'); {do not localize}
|
|
end;
|
|
|
|
procedure TIdRR_MR.SetNewName(const Value: String);
|
|
begin
|
|
SetValue('NewName', Value); {do not localize}
|
|
end;
|
|
|
|
function TIdRR_MR.TextRecord(AFullName: string): string;
|
|
begin
|
|
Result := FormatQNameFull(AFullName) + Chr(9) + 'IN' + Chr(9) + 'MR' + Chr(9) + NewName + EOL; {do not localize}
|
|
end;
|
|
|
|
{ TIdRR_MX }
|
|
|
|
function TIdRR_MX.BinQueryRecord(AFullName: string): TIdBytes;
|
|
var
|
|
RRData, Tmp: TIdBytes;
|
|
Pref : UInt16;
|
|
begin
|
|
Tmp := nil; // keep the compiler happy
|
|
if Length(FAnswer) = 0 then begin
|
|
Pref := IndyStrToInt(Preference);
|
|
RRData := ToBytes(GStack.HostToNetwork(Pref));
|
|
Tmp := DomainNameToDNSStr(FormatQName(Exchange,AFullName));
|
|
AppendBytes(RRData, Tmp);
|
|
FAnswer := FormatRecord(AFullName, RRData);
|
|
end;
|
|
Result := ToBytes(FAnswer, Length(FAnswer));
|
|
end;
|
|
|
|
constructor TIdRR_MX.Create;
|
|
begin
|
|
inherited CreateInit('MX', TypeCode_MX); {do not localize}
|
|
Exchange := '';
|
|
end;
|
|
|
|
function TIdRR_MX.GetExchang: String;
|
|
begin
|
|
Result := GetValue('EXCHANGE'); {do not localize}
|
|
end;
|
|
|
|
function TIdRR_MX.GetPref: String;
|
|
begin
|
|
Result := GetValue('PREF'); {do not localize}
|
|
end;
|
|
|
|
procedure TIdRR_MX.SetExchange(const Value: String);
|
|
begin
|
|
SetValue('EXCHANGE', Value); {do not localize}
|
|
end;
|
|
|
|
procedure TIdRR_MX.SetPref(const Value: String);
|
|
begin
|
|
SetValue('PREF', Value); {do not localize}
|
|
end;
|
|
|
|
function TIdRR_MX.TextRecord(AFullName: string): string;
|
|
begin
|
|
Result := FormatQNameFull(AFullName) + Chr(9) + 'IN' + Chr(9) + 'MX' + Chr(9) {do not localize}
|
|
+ Preference + ' ' + Exchange + EOL; {do not localize}
|
|
end;
|
|
|
|
{ TIdRR_NS }
|
|
|
|
function TIdRR_NS.BinQueryRecord(AFullName: string): TIdBytes;
|
|
var
|
|
RRData: TIdBytes;
|
|
begin
|
|
RRData := nil; // keep the compiler happy
|
|
if Length(FAnswer) = 0 then begin
|
|
RRData := DomainNameToDNSStr(NSDName);
|
|
FAnswer := FormatRecord(AFullName, RRData);
|
|
end;
|
|
Result := ToBytes(FAnswer, Length(FAnswer));
|
|
end;
|
|
|
|
constructor TIdRR_NS.Create;
|
|
begin
|
|
inherited CreateInit('NS', TypeCode_NS); {do not localize}
|
|
NSDName := '';
|
|
end;
|
|
|
|
function TIdRR_NS.GetNS: String;
|
|
begin
|
|
Result := GetValue('NSDNAME'); {do not localize}
|
|
end;
|
|
|
|
procedure TIdRR_NS.SetNS(const Value: String);
|
|
begin
|
|
SetValue('NSDNAME', Value); {do not localize}
|
|
end;
|
|
|
|
function TIdRR_NS.TextRecord(AFullName: string): string;
|
|
begin
|
|
Result := FormatQNameFull(AFullName) + Chr(9) + 'IN' + Chr(9) + 'NS' + Chr(9) + NSDName + EOL; {do not localize}
|
|
end;
|
|
|
|
{ TIdRR_PTR }
|
|
|
|
function TIdRR_PTR.BinQueryRecord(AFullName: string): TIdBytes;
|
|
var
|
|
RRData: TIdBytes;
|
|
begin
|
|
RRData := nil; // keep the compiler happy
|
|
if Length(FAnswer) = 0 then begin
|
|
RRData := DomainNameToDNSStr(PTRDName);
|
|
FAnswer := FormatRecord(AFullName, RRData);
|
|
end;
|
|
Result := ToBytes(FAnswer, Length(FAnswer));
|
|
end;
|
|
|
|
constructor TIdRR_PTR.Create;
|
|
begin
|
|
inherited CreateInit('PTR', TypeCode_PTR); {do not localize}
|
|
PTRDName := '';
|
|
end;
|
|
|
|
function TIdRR_PTR.GetPTRName: String;
|
|
begin
|
|
Result := GetValue('PTRDNAME'); {do not localize}
|
|
end;
|
|
|
|
procedure TIdRR_PTR.SetPTRName(const Value: String);
|
|
begin
|
|
SetValue('PTRDNAME', Value); {do not localize}
|
|
end;
|
|
|
|
function TIdRR_PTR.TextRecord(AFullName: string): string;
|
|
begin
|
|
Result := FormatQNameFull(AFullName) + Chr(9) + 'IN' + Chr(9) + 'PTR' + Chr(9) + PTRDName + EOL; {do not localize}
|
|
end;
|
|
|
|
{ TIdRR_SOA }
|
|
|
|
function TIdRR_SOA.BinQueryRecord(AFullName: string): TIdBytes;
|
|
var
|
|
LMName, LRName, RRData: TIdBytes;
|
|
LIdx: Integer;
|
|
begin
|
|
// keep the compiler happy
|
|
LMName := nil;
|
|
LRName := nil;
|
|
RRData := nil;
|
|
|
|
if Length(FAnswer) = 0 then begin
|
|
LMName := DomainNameToDNSStr(MName);
|
|
LRName := DomainNameToDNSStr(RName);
|
|
|
|
SetLength(RRData, Length(LMName)+Length(LRName)+(SizeOf(UInt32)*5));
|
|
|
|
LIdx := 0;
|
|
IdBytesCopyBytes(LMName, RRData, LIdx);
|
|
IdBytesCopyBytes(LRName, RRData, LIdx);
|
|
|
|
IdBytesCopyUInt32(GStack.HostToNetwork(UInt32(IndyStrToInt(Serial))), RRData, LIdx);
|
|
IdBytesCopyUInt32(GStack.HostToNetwork(UInt32(IndyStrToInt(Refresh))), RRData, LIdx);
|
|
IdBytesCopyUInt32(GStack.HostToNetwork(UInt32(IndyStrToInt(Retry))), RRData, LIdx);
|
|
IdBytesCopyUInt32(GStack.HostToNetwork(UInt32(IndyStrToInt(Expire))), RRData, LIdx);
|
|
IdBytesCopyUInt32(GStack.HostToNetwork(UInt32(IndyStrToInt(Minimum))), RRData, LIdx);
|
|
|
|
FAnswer := FormatRecord(AFullName, RRData);
|
|
end;
|
|
Result := ToBytes(FAnswer, Length(FAnswer));
|
|
end;
|
|
|
|
constructor TIdRR_SOA.Create;
|
|
begin
|
|
inherited CreateInit('SOA', TypeCode_SOA); {do not localize}
|
|
MName := '';
|
|
RName := '';
|
|
Serial := '';
|
|
Refresh := '';
|
|
Retry := '';
|
|
Expire := '';
|
|
Minimum := '';
|
|
end;
|
|
|
|
function TIdRR_SOA.GetExpire: String;
|
|
begin
|
|
Result := GetName('EXPIRE'); {do not localize}
|
|
end;
|
|
|
|
function TIdRR_SOA.GetMin: String;
|
|
begin
|
|
Result := GetName('MINIMUM'); {do not localize}
|
|
end;
|
|
|
|
function TIdRR_SOA.GetMName: String;
|
|
begin
|
|
Result := GetName('MNAME'); {do not localize}
|
|
end;
|
|
|
|
function TIdRR_SOA.GetName(const CLabel: String): String;
|
|
begin
|
|
Result := GetValue(CLabel);
|
|
end;
|
|
|
|
function TIdRR_SOA.GetRefresh: String;
|
|
begin
|
|
Result := GetName('REFRESH'); {do not localize}
|
|
end;
|
|
|
|
function TIdRR_SOA.GetRetry: String;
|
|
begin
|
|
Result := GetName('RETRY'); {do not localize}
|
|
end;
|
|
|
|
function TIdRR_SOA.GetRName: String;
|
|
begin
|
|
Result := GetName('RNAME'); {do not localize}
|
|
end;
|
|
|
|
function TIdRR_SOA.GetSerial: String;
|
|
begin
|
|
Result := GetName('SERIAL'); {do not localize}
|
|
end;
|
|
|
|
procedure TIdRR_SOA.SetExpire(const Value: String);
|
|
begin
|
|
SetName('EXPIRE', Value); {do not localize}
|
|
end;
|
|
|
|
procedure TIdRR_SOA.SetMin(const Value: String);
|
|
begin
|
|
SetName('MINIMUM', Value); {do not localize}
|
|
end;
|
|
|
|
procedure TIdRR_SOA.SetMName(const Value: String);
|
|
begin
|
|
SetName('MNAME', Value); {do not localize}
|
|
end;
|
|
|
|
procedure TIdRR_SOA.SetName(const CLabel: String; const Value: String);
|
|
begin
|
|
SetValue(CLabel, Value);
|
|
end;
|
|
|
|
procedure TIdRR_SOA.SetRefresh(const Value: String);
|
|
begin
|
|
SetName('REFRESH', Value); {do not localize}
|
|
end;
|
|
|
|
procedure TIdRR_SOA.SetRetry(const Value: String);
|
|
begin
|
|
SetName('RETRY', Value); {do not localize}
|
|
end;
|
|
|
|
procedure TIdRR_SOA.SetRName(const Value: String);
|
|
begin
|
|
SetName('RNAME', Value); {do not localize}
|
|
end;
|
|
|
|
procedure TIdRR_SOA.SetSerial(const Value: String);
|
|
begin
|
|
SetName('SERIAL', Value); {do not localize}
|
|
end;
|
|
|
|
function TIdRR_SOA.TextRecord(AFullName: string): string;
|
|
begin
|
|
Result := FormatQNameFull(AFullName) + Chr(9) + 'IN' + Chr(9) + 'SOA' + Chr(9) {do not localize}
|
|
+ MName + ' ' + RName + ' ' + Serial + ' ' + Refresh + ' ' + Retry + ' ' {do not localize}
|
|
+ Expire + ' ' + Minimum + EOL; {do not localize}
|
|
end;
|
|
|
|
{ TIdRR_A }
|
|
|
|
function TIdRR_A.BinQueryRecord(AFullName: string): TIdBytes;
|
|
var
|
|
RRData: TIdBytes;
|
|
begin
|
|
RRData := nil; // keep the compiler happy
|
|
if Length(Self.FAnswer) = 0 then begin
|
|
RRData := IPAddrToDNSStr(Address);
|
|
FAnswer := FormatRecord(AFullName, RRData);
|
|
end;
|
|
Result := ToBytes(FAnswer, Length(FAnswer));
|
|
end;
|
|
|
|
constructor TIdRR_A.Create;
|
|
begin
|
|
inherited CreateInit('A', TypeCode_A); {do not localize}
|
|
Address := '';
|
|
end;
|
|
|
|
function TIdRR_A.GetA: String;
|
|
begin
|
|
Result := GetValue('A'); {do not localize}
|
|
end;
|
|
|
|
procedure TIdRR_A.SetA(const Value: String);
|
|
begin
|
|
SetValue('A', Value); {do not localize}
|
|
end;
|
|
|
|
function TIdRR_A.TextRecord(AFullName: string): string;
|
|
begin
|
|
Result := FormatQNameFull(AFullName) + Chr(9) + 'IN' + Chr(9) + 'A' + Chr(9) + Address + EOL; {do not localize}
|
|
end;
|
|
|
|
{ TIdRR_AAAA }
|
|
|
|
function TIdRR_AAAA.BinQueryRecord(AFullName: string): TIdBytes;
|
|
var
|
|
RRData: TIdBytes;
|
|
begin
|
|
RRData := nil; // keep the compiler happy
|
|
if Length(FAnswer) = 0 then begin
|
|
RRData := IPv6AAAAToDNSStr(Address);
|
|
FAnswer := FormatRecord(AFullName, RRData);
|
|
end;
|
|
Result := ToBytes(FAnswer, Length(FAnswer));
|
|
end;
|
|
|
|
constructor TIdRR_AAAA.Create;
|
|
begin
|
|
inherited CreateInit('AAAA', TypeCode_AAAA); {do not localize}
|
|
Address := '';
|
|
end;
|
|
|
|
function TIdRR_AAAA.GetA: String;
|
|
begin
|
|
Result := GetValue('AAAA'); {do not localize}
|
|
end;
|
|
|
|
procedure TIdRR_AAAA.SetA(const Value: String);
|
|
begin
|
|
SetValue('AAAA', Value); {do not localize}
|
|
end;
|
|
|
|
function TIdRR_AAAA.TextRecord(AFullName: string): string;
|
|
begin
|
|
Result := FormatQNameFull(AFullName) + Chr(9) + 'IN' + Chr(9) + 'AAAA' + Chr(9) + Address + EOL; {do not localize}
|
|
end;
|
|
|
|
{ TIdRR_TXT }
|
|
|
|
function TIdRR_TXT.BinQueryRecord(AFullName: string): TIdBytes;
|
|
var
|
|
RRData: TIdBytes;
|
|
begin
|
|
RRData := nil; // keep the compiler happy
|
|
if Length(FAnswer) = 0 then begin
|
|
//Fix here, make the RRData being DNSStr.
|
|
//Fixed in 2005 Jan 25.
|
|
RRData := NormalStrToDNSStr(TXT);
|
|
FAnswer := FormatRecord(AFullName, RRData);
|
|
end;
|
|
Result := ToBytes(FAnswer, Length(FAnswer));
|
|
end;
|
|
|
|
constructor TIdRR_TXT.Create;
|
|
begin
|
|
inherited CreateInit('TXT', TypeCode_TXT); {do not localize}
|
|
TXT := '';
|
|
end;
|
|
|
|
function TIdRR_TXT.GetTXT: String;
|
|
begin
|
|
Result := GetValue('TXT'); {do not localize}
|
|
end;
|
|
|
|
procedure TIdRR_TXT.SetTXT(const Value: String);
|
|
begin
|
|
SetValue('TXT', Value); {do not localize}
|
|
end;
|
|
|
|
function TIdRR_TXT.TextRecord(AFullName: string): string;
|
|
begin
|
|
Result := FormatQNameFull(AFullName) + Chr(9) + 'IN' + Chr(9) + 'TXT' + Chr(9) {do not localize}
|
|
+ '"' + TXT + '"' + EOL; {do not localize}
|
|
end;
|
|
|
|
{ TIdRR_WKS }
|
|
|
|
constructor TIdRR_WKS.Create;
|
|
begin
|
|
inherited CreateInit('WKS', TypeCode_WKS); {do not localize}
|
|
end;
|
|
|
|
{ TIdRR_Error }
|
|
|
|
constructor TIdRR_Error.Create;
|
|
begin
|
|
inherited CreateInit('', TypeCode_Error); {do not localize}
|
|
end;
|
|
|
|
function ReplaceSpecString(Source, Target, NewString : string; ReplaceAll : boolean = True) : string;
|
|
var
|
|
FixingString, MiddleString, FixedString : string;
|
|
begin
|
|
if Target = NewString then begin
|
|
Result := Source;
|
|
end else begin
|
|
FixingString := Source;
|
|
MiddleString := ''; {do not localize}
|
|
FixedString := ''; {do not localize}
|
|
|
|
if Pos(Target, Source) > 0 then begin
|
|
repeat
|
|
MiddleString := Fetch(FixingString, Target);
|
|
FixedString := FixedString + MiddleString + NewString;
|
|
until (Pos(Target, FixingString) = 0) or (not ReplaceAll);
|
|
Result := FixedString + FixingString;
|
|
end else begin
|
|
Result := Source;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
function IsBig5(ch1, ch2:char) : boolean;
|
|
begin
|
|
// RLebeau 1/7/09: using Char() for #128-#255 because in D2009, the compiler
|
|
// may change characters >= #128 from their Ansi codepage value to their true
|
|
// Unicode codepoint value, depending on the codepage used for the source code.
|
|
// For instance, #128 may become #$20AC...
|
|
|
|
if (not (((ch1 >= Char(161)) and (ch1 <= Char(254))) or
|
|
((ch1 >= Char(142)) and (ch1 <= Char(160))) or
|
|
((ch1 >= Char(129)) and (ch1 <= Char(141)))) ) or
|
|
(not (((ch2 >= #64) and (ch2 <= #126)) or
|
|
((ch2 >= Char(161)) and (ch2 <= Char(254)))) ) then
|
|
begin
|
|
Result := False;
|
|
end else begin
|
|
Result := True;
|
|
end;
|
|
end;
|
|
|
|
end.
|