socket DNS查询之实现(Delphi)

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竟然大都不能用
~~~~~~~
 

你可能感兴趣的:(socket DNS查询之实现(Delphi))