Dns解析(上)

类别:Java 点击:0 评论:0 推荐:
Dns解析(上)

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


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


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


    |        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: 要求查询的域名地址。比如有这样一个邮件地址[email protected],

    我们将@后面的地址提取出来,即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的返回包。

 

文章不免有错,请各位多指点[email protected] window.open=NS_ActualOpen;

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