Dns解析(上) (转)

Dns解析(上) (转)[@more@]

dns解析(上)


Dns(domain Name Server)即域名服务器,在网络中承担着将域名转换为IP地址的工作。在很多编程中都要用到这种技术,就是使用域名解析。这篇文章将说明这项技术。


通过Dns服务器,可以查询很多地址,比如Mail服务器地址,FTP服务器等等,我在这里就以mail服务器为例,并以Java实现。


+---------------------+XML:namespace prefix = o ns = "urn:schemas-microsoft-com:Office:office" />


  |  Header  |


  +---------------------+


  |  Question  |


  +---------------------+


  |  Answer  |


  +---------------------+


  |  Authority  |


  +---------------------+


  |  Additional  |


+---------------------+


这个表是从rfc1035文档中拷出来的,大致说明了dns包的格式。


Header

   0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F

 
 

  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+

 
 

  |  ID  |

 
 

  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+

 
 

  |QR|  Opcode  |AA|TC|RD|RA|  Z  |  RCODE  |

 
 

  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+

 
 

  |  QDCOUNT  |

 
 

  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+

 
 

  |  ANCOUNT  |

 
 

  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+

 
 

  |  NSCOUNT  |

 
 

  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+

 
 

  |  ARCOUNT  |

 
 

  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+


 

  这个也是从rfc文档中拷出来的,只是我将其头部数字改成16进制了。



ID: 16位的一个标志,用以验证请求和回复消息的匹配。就实用程序产生一个16位的随机数。


QR: 1位数据表明这是一个请求,还是一个回复(0为请求,1为恢复)。


Opcode: 4位的数据表示查询的类型。


0   基本查找


1   反向查找


2   查询服务器情况


3-15  保留


RD:(recursion desired)即是否以递归方式的查询,RD=1为递归。

RA:(Recursion Available)表示服务器是否支持递归方式查询,只在回复中有效。

QDCOUNT:16位数据表示要查询的问题个数。

ANCOUNT:16位数据表示回复结果的个数,只在回复中有效。

 


其他几个请参考rfc文档,在这里我们只用这些,并将其他参数设为0。



Question

   0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F

 
 

  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+

 
 

  |  |

 
 

  /  QNAME  /

 
 

  /  /

 
 

  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+

 
 

  |  QTYPE  |

 
 

  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+

 
 

  |  QCLASS  |

 
 

  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+

 
 

 
 

QNAME: 要求查询的域名地址邮件地址XXX@163.NET">。比如有这样一个邮件地址XXX@163.net,

 
 

  我们将@后面的地址提取出来,即163.net。然后将其变为这样一个序列,31633net0,也就是以 . 分界,并以各自的字符个数作为前缀,最后以0结束

 
 

QTYPE: 2位数据表示查询类型。

 
 

  A  1 a host address

 
 

NS  2 an authoritative name server

 
 

MD  3 a mail destination (Obsolete - use MX)

 
 

MF  4 a mail forwarder (Obsolete - use MX)

 
 

CNAME  5 the canonical name for an alias

 
 

SOA  6 marks the start of a zone of authority

 
 

MB  7 a mailbox domain name (EXPERIMENTAL

 
 

MG  8 a mail group member (EXPERIMENTAL)

 
 

MR  9 a mail rename domain name (EXPERIMENTAL)

 
 

NULL  10 a null RR (EXPERIMENTAL)

 
 

WKS  11 a well known service description

 
 

PTR  12 a domain name pointer

 
 

HINFO  13 host information

 
 

MINFO  14 mailbox or mail list information

 
 

MX  15 mail Exchange

 
 

TXT  16 text strings

 
 

 
 

这是在rfc文档中列出的各类type,我们在这里用MX,即QTYPE=15。

 
 

QCLASS: 2位数据表示查询方式。

 
 

  IN  1 the Internet

 
 

CS  2 the CSNET class (Obsolete - used only for examples in some obsolete RFCs)

 
 

  CH   3 the CHAos class

 
 

HS   4 Hesiod [Dyer 87]

 
 

这是在rfc文档中列出的各类class,我们在这里用IN,即QCLASS=15。

 
 

 
 

下面使用JAVA实现的原码:

 
 

 
 

说明:DnsTool.IntToBytes(int,int)是将一个整数转换为几个8位数的组合。

 
 

  DnsTool.StringToBytes(String)是将一个字符串转换为QNAME需要的格式,并以BYTE[]的格式返回。

 
 

 
 

class DnsHeader {

 
 

 
 

  private int ID;

 
 

  private int Flags=0;

 
 

  private byte[] head=new byte[]{0,0,0,0,0,0,0,0,0,0,0,0};

 
 

 

 
 

 /** Creates new DnsHeader */

 
 

  public DnsHeader()

 
 

 {

 
 

  setID();

 
 

  setFlags(Flags);

 
 

  setAnswer(false);//does not an answer

 
 

  setRecursionDesired(true);

 
 

  }

 
 

 
 

  private void setID()

 
 

  {

 
 

  byte[] tmp=new byte[2];

 
 

  ID=new Random().nextInt(10);

 
 

  tmp=DnsTool.IntToBytes(ID,2);

 
 

  head[0]=tmp[0];

 
 

  head[1]=tmp[1]; 

 
 

 }

 
 

 

 
 

 public int getID()

 
 

  {

 
 

  return this.ID;

 
 

  }

 
 

 

 
 

 private void setFlags(int Flags)

 
 

 {

 
 

  byte[] tmp=new byte[2];

 
 

  tmp=DnsTool.IntToBytes(ID,2);

 
 

  head[2]=tmp[0];

 
 

  head[3]=tmp[1];

 
 

 

 
 

 }

 
 

 

 
 

 public void setAnswer(boolean isAnswer)

 
 

  {

 
 

  head[2]=isAnswer?(byte)(head[2]|0x80):(byte)

 
 

(head[2]&0x7f);

 
 

  }

 
 

 

 
 

 public void setRecursionDesired(boolean isRecursionDesired)

 
 

 {

 
 

  head[2]=isRecursionDesired?((byte)(head[2]|0x1))

 
 

:((byte)(head[2] & 0xFE));

 
 

  }

 
 

 

 
 

  public void setQDcount(int num)//set the number of question

 
 

  {

 
 

   byte[] tmp=new byte[2];

 
 

  tmp=DnsTool.IntToBytes(num,2);

 
 

  head[4]=tmp[0];

 
 

  head[5]=tmp[1];

 
 

 
 

  }

 
 

 
 

  public byte[] getBytes()

 
 

  {

 
 

  return head;

 
 

  }

 
 

}

 
 

 
 

class Question {

 
 

 
 

  private byte[] question;

 
 

  private int QuestionLength;

 
 

  /** Creates new Question */

 
 

  public Question(String questionLabel,int questionType,

 
 

int questionClass)

 
 

 {

 
 

  byte[] transName=DnsTool.StringToBytes(questionLabel);

 
 

  byte[] ty=DnsTool.IntToBytes(questionType,2);

 
 

  byte[] cl=DnsTool.IntToBytes(questionClass,2);

 
 

 

 
 

 QuestionLength=0;

 
 

  //transfer the QuestionLabel to the bytes

 
 

  question=new byte[transName.length+4];

 
 

  System.arraycopy(transName,0,question,QuestionLength,

 
 

transName.length);

 
 

  QuestionLength+=transName.length;

 
 

 

 
 

 //transfer the type to the bytes

 
 

  System.arraycopy(ty,0,question,QuestionLength,

 
 

ty.length);

 
 

  QuestionLength+=ty.length;

 
 

 

 
 

 //transfer the class to the bytes

 
 

  System.arraycopy(cl,0,question,QuestionLength,

 
 

cl.length);

 
 

  QuestionLength+=cl.length;

 
 

  }

 
 

 
 

  public byte[] getBytes()

 
 

 {

 
 

  return question;

 
 

  } 

 
 

}

 
 

这里实现了dns 的包头和要查询的question的数据,然后只要将它们组合在一起就成了dns包了,接下来就只要将它发出去就可以了,下面这段程序就实现了这一功能。

 
 

说明:

 
 

DNSSERVER:就是dns服务器的地址。

 
 

  DNSPORT:dns服务器的端口,即53。

 
 

  DnsQuery:这个是header 和 question 组合的数据。

 
 

 
 

DatagramPacket ID_Packet;

 
 

  DatagramSocket ID_Socket;

 
 

  byte[] query=DnsQuery.getBytes();

 
 

  int i;

 
 

 

 
 

 try

 
 

  {

 
 

  ID_Packet=new DatagramPacket(query,query.length,InetAddress.getByName

 
 

(DNSSERVER),Constant.DNSPORT);

 
 

  ID_Socket=new DatagramSocket();

 
 

 

 
 

 //send query

 
 

  ID_Socket.send(ID_Packet);

 
 

 

 
 

 //close socket

 
 

  ID_Socket.close();

 
 

 

 
 

 }

 
 

  catch(IOException e)

 
 

  {

 
 

  System.out.println(e);

 
 

  return null;

 
 

  } 

 
 

 }


 
 
 

这里只讲了Dns的查询包,下篇将讲述Dns的返回包。

 
 

 
 

文章不免有错,请各位多指点craks@263.net


 

来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/10752043/viewspace-991747/,如需转载,请注明出处,否则将追究法律责任。

转载于:http://blog.itpub.net/10752043/viewspace-991747/

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符  | 博主筛选后可见
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值