📄 dnsquery.pas
字号:
var
I, J : Integer;
begin
Result := '';
if Length(IP) = 0 then
Exit;
J := Length(IP);
I := J;
while I >= 0 do begin
if (I = 0) or (IP[I] = '.') then begin
Result := Result + '.' + Copy(IP, I + 1, J - I);
J := I - 1;
end;
Dec(I);
end;
if Result[1] = '.' then
Delete(Result, 1, 1);
end;
{* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
procedure Register;
begin
RegisterComponents('FPiette', [TDnsQuery]);
end;
{* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
constructor TDnsQuery.Create(AOwner : TComponent);
begin
inherited Create(AOwner);
FWSocket := TWSocket.Create(nil);
FPort := '53';
end;
{* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
destructor TDnsQuery.Destroy;
begin
if Assigned(FWSocket) then begin
FWSocket.Destroy;
FWSocket := nil;
end;
inherited Destroy;
end;
{* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
procedure TDnsQuery.Notification(AComponent: TComponent; operation: TOperation);
begin
inherited Notification(AComponent, operation);
if operation = opRemove then begin
if AComponent = FWSocket then
FWSocket := nil;
end;
end;
{* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
function TDnsQuery.GetMXPreference(nIndex : Integer) : Integer;
begin
{ Silently ignore index out of bounds error }
if (nIndex < Low(FMXPreferenceArray)) or
(nIndex > High(FMXPreferenceArray)) then
Result := 0
else
Result := FMXPreferenceArray[nIndex];
end;
{* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
function TDnsQuery.GetMXExchange(nIndex : Integer) : String;
begin
{ Silently ignore index out of bounds error }
if (nIndex < Low(FMXExchangeArray)) or
(nIndex > High(FMXExchangeArray)) then
Result := ''
else
Result := FMXExchangeArray[nIndex];
end;
{* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
function TDnsQuery.GetAnswerName(nIndex : Integer) : String;
begin
{ Silently ignore index out of bounds error }
if (nIndex < Low(FAnswerNameArray)) or
(nIndex > High(FAnswerNameArray)) then
Result := ''
else
Result := FAnswerNameArray[nIndex];
end;
{* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
function TDnsQuery.GetAnswerType(nIndex : Integer) : Integer;
begin
{ Silently ignore index out of bounds error }
if (nIndex < Low(FAnswerTypeArray)) or
(nIndex > High(FAnswerTypeArray)) then
Result := 0
else
Result := FAnswerTypeArray[nIndex];
end;
{* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
function TDnsQuery.GetAnswerClass(nIndex : Integer) : Integer;
begin
{ Silently ignore index out of bounds error }
if (nIndex < Low(FAnswerClassArray)) or
(nIndex > High(FAnswerClassArray)) then
Result := 0
else
Result := FAnswerClassArray[nIndex];
end;
{* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
function TDnsQuery.GetAnswerTTL(nIndex : Integer) : LongInt;
begin
{ Silently ignore index out of bounds error }
if (nIndex < Low(FAnswerTTLArray)) or
(nIndex > High(FAnswerTTLArray)) then
Result := 0
else
Result := FAnswerTTLArray[nIndex];
end;
{* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
function TDnsQuery.GetAnswerTag(nIndex : Integer) : Integer;
begin
{ Silently ignore index out of bounds error }
if (nIndex < Low(FAnswerTagArray)) or
(nIndex > High(FAnswerTagArray)) then
Result := 0
else
Result := FAnswerTagArray[nIndex];
end;
{* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
function TDnsQuery.GetAddress(nIndex : Integer) : TInAddr;
begin
{ Silently ignore index out of bounds error }
if (nIndex < Low(FAddressArray)) or
(nIndex > High(FAddressArray)) then
Result.S_addr := 0
else
Result := FAddressArray[nIndex];
end;
{* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
function TDnsQuery.GetHostname(nIndex : Integer) : String;
begin
{ Silently ignore index out of bounds error }
if (nIndex < Low(FHostnameArray)) or
(nIndex > High(FHostnameArray)) then
Result := ''
else
Result := FHostnameArray[nIndex];
end;
{* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
function TDnsQuery.GetResponseBuf : PChar;
begin
Result := @FResponseBuf;
end;
{* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
function TDnsQuery.MXLookup(Domain : String) : Integer;
begin
Inc(FIDCount);
BuildRequestHeader(PDnsRequestHeader(@FQueryBuf), FIDCount, DnsOpCodeQuery, TRUE, 1, 0, 0, 0);
FQueryLen := BuildQuestionSection(@FQueryBuf[SizeOf(TDnsRequestHeader)], Domain, DnsQueryMX, DnsClassIN);
FQueryLen := FQueryLen + SizeOf(TDnsRequestHeader);
Result := FIDCount;
SendQuery;
end;
{* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
function TDnsQuery.ALookup(Host : String) : Integer;
begin
Inc(FIDCount);
BuildRequestHeader(PDnsRequestHeader(@FQueryBuf), FIDCount, DnsOpCodeQuery, TRUE, 1, 0, 0, 0);
FQueryLen := BuildQuestionSection(@FQueryBuf[SizeOf(TDnsRequestHeader)], Host, DnsQueryA, DnsClassIN);
FQueryLen := FQueryLen + SizeOf(TDnsRequestHeader);
Result := FIDCount;
SendQuery;
end;
{* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
{ !!KAP!! }
function TDnsQuery.QueryAny(Host : String; QNumber : integer) : Integer;
begin
Inc(FIDCount);
BuildRequestHeader(PDnsRequestHeader(@FQueryBuf), FIDCount, DnsOpCodeQuery, TRUE, 1, 0, 0, 0);
FQueryLen := BuildQuestionSection(@FQueryBuf[SizeOf(TDnsRequestHeader)], Host, QNumber, DnsClassIN);
FQueryLen := FQueryLen + SizeOf(TDnsRequestHeader);
Result := FIDCount;
SendQuery;
end;
{* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
function TDnsQuery.PTRLookup(IP : String) : Integer;
begin
Inc(FIDCount);
BuildRequestHeader(PDnsRequestHeader(@FQueryBuf), FIDCount, DnsOpCodeQuery, TRUE, 1, 0, 0, 0);
FQueryLen := BuildQuestionSection(@FQueryBuf[SizeOf(TDnsRequestHeader)],
ReverseIP(IP) + '.in-addr.arpa',
DnsQueryPTR, DnsClassIN);
FQueryLen := FQueryLen + SizeOf(TDnsRequestHeader);
Result := FIDCount;
SendQuery;
end;
{* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
procedure TDnsQuery.SendQuery;
begin
FResponseLen := -1;
FWSocket.OnDataAvailable := nil;
FWSocket.Abort;
FWSocket.OnDataAvailable := WSocketDataAvailable;
FWSocket.Proto := 'udp';
FWSocket.Port := FPort;
FWSocket.Addr := FAddr;
FWSocket.Connect;
FWSocket.Send(@FQueryBuf, FQueryLen);
end;
{* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
function TDnsQuery.BuildQuestionSection(
Dst : PChar;
const QName : String;
QType : WORD;
QClass : WORD) : Integer;
var
I : Integer;
p : PChar;
Ptr : PChar;
begin
Ptr := Dst;
if Ptr = nil then begin
Result := 0;
Exit;
end;
I := 1;
while I <= Length(QName) do begin
p := Ptr;
Inc(Ptr);
while (I <= Length(QName)) and (QName[I] <> '.') do begin
Ptr^ := QName[I];
Inc(Ptr);
Inc(I);
end;
p^ := Chr(Ptr - p - 1);
Inc(I);
end;
Ptr^ := #0;
Inc(Ptr);
PWORD(Ptr)^ := WSocket_htons(QType);
Inc(Ptr, 2);
PWORD(Ptr)^ := WSocket_htons(QClass);
Inc(Ptr, 2);
Result := Ptr - Dst;
end;
{* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
procedure TDnsQuery.BuildRequestHeader(
Dst : PDnsRequestHeader;
ID : WORD;
OPCode : BYTE;
Recursion : Boolean;
QDCount : WORD;
ANCount : WORD;
NSCount : WORD;
ARCount : WORD);
begin
if Dst = nil then
Exit;
Dst^.ID := WSocket_htons(ID);
Dst^.Flags := WSocket_htons((OpCode shl 11) + (Ord(Recursion) shl 8));
Dst^.QDCount := WSocket_htons(QDCount);
Dst^.ANCount := WSocket_htons(ANCount);
Dst^.NSCount := WSocket_htons(NSCount);
Dst^.ARCount := WSocket_htons(ARCount);
end;
{* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
procedure TDnsQuery.TriggerRequestDone(Error: WORD);
begin
if Assigned(FOnRequestDone) then
FOnRequestDone(Self, Error);
end;
{* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
procedure TDnsQuery.WSocketDataAvailable(Sender: TObject; Error: WORD);
var
Len : Integer;
Ans : PDnsRequestHeader;
Flags : Integer;
P : PChar;
RDataPtr : Pointer;
RDataLen : Integer;
I : Integer;
begin
Ans := PDnsRequestHeader(@FResponseBuf);
Len := FWSocket.Receive(Ans, SizeOf(FResponseBuf));
if Error <> 0 then begin
TriggerRequestDone(Error);
Exit;
end;
{ Check for minimum response length }
if Len < SizeOf(TDnsRequestHeader) then
Exit;
Flags := WSocket_ntohs(Ans^.Flags);
{ Check if we got a response }
if (Flags and $8000) = 0 then
Exit;
FResponseLen := Len;
{ Decode response header }
FResponseID := WSocket_ntohs(Ans^.ID);
FResponseCode := Flags and $000F;
FResponseOpCode := (Flags shr 11) and $000F;
FResponseAuthoritative := (Flags and $0400) = $0400;
FResponseTruncation := (Flags and $0200) = $0200;
FResponseRecursionAvailable := (Flags and $0080) = $0080;
FResponseQDCount := WSocket_ntohs(Ans^.QDCount);
FResponseANCount := WSocket_ntohs(Ans^.ANCount);
FResponseNSCount := WSocket_ntohs(Ans^.NSCount);
FResponseARCount := WSocket_ntohs(Ans^.ARCount);
P := @ResponseBuf[SizeOf(TDnsRequestHeader)];
if FResponseQDCount = 0 then begin
{ I don't think we could receive 0 questions }
FQuestionName := '';
FQuestionType := 0;
FQuestionClass := 0;
end
else begin
{ Should never be greater than 1 because we sent only one question }
P := DecodeQuestion(@FResponseBuf, P,
FQuestionName, FQuestionType, FQuestionClass);
end;
if FResponseANCount = 0 then begin
RDataPtr := nil;
RDataLen := 0;
FMXRecordCount := 0;
FARecordCount := 0;
FPTRRecordCount := 0;
end
else begin
FMXRecordCount := 0;
FARecordCount := 0;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -