Socket DNS查询之实现

类别:Delphi 点击:0 评论:0 推荐:
        昨天突然无法访问任何网站了,可是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竟然大都不能用~~~~~~~

本文地址:http://com.8s8s.com/it/it4236.htm