socket DNS查询之实现(Delphi)

本文介绍了一种手动实现DNS查询的方法,包括构造查询包并解析响应的过程。作者通过抓包了解了Windows向DNS服务器发送UDP包的细节,并用Delphi语言实现了DNS查询功能。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

socket DNS查询之实现

昨天突然无法访问任何网站了,可是QQ还在正常工作
~~~~~`嗯,肯定是DNS出了问题~~
       用自己做的TraceRoute察看了一下,6个网关都工作正常
~~~确实是DNS坏了~~
       烂铁通的DNS太差
~~~~~可是哪个DNS更好?
       自己做一个工具比较一下吧
~~可是还不懂DNS的工作原理^_^
       搜索百度,下载TCP
/IP 详解2卷~~竟然没有一个能下的了......还中了木马~~~~`晕倒!
       不过有收获!找到了全国的各大城市DNS列表!
      看来只有自己蒙了!好在还有IRIS。不过试用期只剩10天了!呵呵,抓包......原来是这样的:Windows向DNS发送了一个UDP包,这个包中当然有
'www.xxx.com',然后DNS服务器返回一个包含IP地址的UDP包,我们的工作就是分解这个包~~~~~
      
       DNS服务器的端口是53,接受的Query package格式如下:
       PDomainQuery 
= ^YDomainQuery;
       YDomainQuery 
= record
       u16id : word;
//任意
       u16flag : word;//$0100; //标准查询
       u16question : word;//1
       u16answer : word;//0
       u16author : word;//0
       u16addition : word;//0
       u8secB : byte;//section begin
       u8secE : byte;//section end
       u16type : word;//1
       u16class : word;//1
       end;
      
      我们这样填充这个包:
      procedure FillDomainQuery( pdq: PDomainQuery; sAddr: 
string );
      var
       pData, pTemp : PChar;
       i, cbLen : Integer;
       pu16 : PWord;
      begin
       FillChar( pdq
^sizeof(YDomainQuery) + Length(sAddr), 0 );
      
       pdq
^.u16id := htons( DNS_ID );
       pdq
^.u16flag := htons( DNS_STAND_QUERY );
       pdq
^.u16question := htons( DNS_QUESTION );
       
//pdq^.u16answer := 0; //pdq^.u16author := 0; //pdq^.u16addition := 0;
      
       
//初始化域名数据缓冲区
       cbLen := Length(sAddr) + 2;
       pData :
= AllocMem( cbLen );
       Inc( pData );
       Move( sAddr[
1], pData^, Length(sAddr) );
       Dec( pData );
      
       
//填充域名数据缓冲区
       pTemp := pData;
       i :
= Pos( '.', sAddr ); //www.baidu.com --- example
       while i > 0 do
       begin 
//i=4; i=6
       pTemp^ := Chr(i-1); // 3 5
       Inc( pTemp, i ); // ^ ^
       Delete( sAddr, 1, i ); //s='baidu.com'; s='com'
       i := Pos( '.', sAddr );
       end;
       pTemp
^ := Chr( Length(sAddr) ); //s='com'
       Inc( pTemp, Length(sAddr)+1 );
       pTemp
^ := #0;
      
       
//把域名数据拷贝到pdq^.u8secB
       pTemp := @pdq^.u8secB;
       Move( pData
^, pTemp^, cbLen );
       FreeMem( pData );
      
       
//最后填写Type/Class
       pu16 := PWord( pTemp + cbLen );
       pu16
^ := htons( DNS_TYPE_HOST );
       Inc( pu16 );
       pu16
^ := htons( DNS_CLASS_INET );
      end;
      
      
//把构造好的包发送出去
      var
       pdq : PDomainQuery;
       pdq :
= AllocMem( sizeof(YDomainQuery) + Length(edtDomain.text) );
       FillDomainQuery( pdq, edtDomain.text );
       udp.SendBuf( PChar(pdq), 
sizeof(YDomainQuery) + Length(edtDomain.text) );
      
      
//不过DNS返回的包更复杂~~~不给它定义什么结构了,直接整!!!
      function DecodeDomainAnwser( pbuf: PChar; len: Integer ):string;
      var
       p : PChar;
       w : Word;
       j : Integer;
       s1,s2,s3,s4: 
string;
      begin
       p :
= pbuf; j:=0;
       result :
= 'TransactionID: ' + IntToStr( PWord(p)^ ) +#13#10;
      
       Inc( p, 
2 ); Inc( j, 2 );
       result :
= result + 'Response Flag:' + Format('%x', [ntohs(PWord(p)^)]) +#13#10;
       
if ntohs( PWord(p)^ ) <> DNS_STAND_RES then
       begin
       result :
= result + 'Response error...' +#13#10;
       Exit;
       end;
      
       Inc( p, 
2 ); Inc( j, 2 );
       result :
= result + 'Question: ' +IntToStr( ntohs(PWord(p)^) )+ #13#10;
       Inc( p, 
2 ); Inc( j, 2 );
       result :
= result + 'Answer: ' +IntToStr( ntohs(PWord(p)^) )+ #13#10;
       Inc( p, 
2 ); Inc( j, 2 );
       result :
= result + 'Authority: ' +IntToStr( ntohs(PWord(p)^) )+ #13#10;
       Inc( p, 
2 ); Inc( j, 2 );
       result :
= result + 'Addition: ' +IntToStr( ntohs(PWord(p)^) )+ #13#10;
      
       Inc( p, 
2 ); Inc( j, 2 );
       w :
= Byte( p^ );
       
while w > 0 do //跳过DNS HOST返回的要查询的域名
       begin
       Inc( p, w 
+ 1 ); Inc( j, w+1 );
       w :
= Byte( p^ );
       end;
      
       Inc( p ); Inc( j );
       Inc( p, 
4 ); Inc( j, 4 );//type/class
       Inc( p, 6 ); Inc( j, 6 );//name/type/class
       Inc( p, 4 ); Inc( j, 4 );//time
      
       w :
= ntohs( PWord(p)^ ); //得到数据长度
       Inc( p, 2 ); Inc( j, 2 );//到达真正的数据地址
       Inc( p, w ); Inc( j, w );
       Inc( p, 
10 ); Inc( j, 10 );
       Inc( p, 
2 ); Inc( j, 2 );
       s1 :
= IntToStr( Byte(p^) ); Inc( p ); Inc( j );
       s2 :
= IntToStr( Byte(p^) ); Inc( p ); Inc( j );
       s3 :
= IntToStr( Byte(p^) ); Inc( p ); Inc( j );
       s4 :
= IntToStr( Byte(p^) ); Inc( p ); Inc( j );
       result :
= result + 'IP: ' + s1 + '.' + s2 + '.' + s3 + '.' + s4 + #13#10;
      
       
if len < j+32 then
       Exit;
      
       Inc( p, 
6 ); //+name/type/class
       Inc( p, 4 ); //+time
      
       Inc( p, 
2 ); //到达真正的数据地址
       s1 := IntToStr( Byte(p^) ); Inc( p );
       s2 :
= IntToStr( Byte(p^) ); Inc( p );
       s3 :
= IntToStr( Byte(p^) ); Inc( p );
       s4 :
= IntToStr( Byte(p^) );
       result :
= result + 'IP: ' + s1 + '.' + s2 + '.' + s3 + '.' + s4 +#13#10;
      end;
      
       呵呵,试验一下,全国的各大城市DNS列表中的Host竟然大都不能用
~~~~~~~
 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值