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竟然大都不能用 ~~~~~~~
昨天突然无法访问任何网站了,可是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竟然大都不能用 ~~~~~~~