Dns解析(上)

    技术2022-05-11  164

    Dns解析()

    DnsDomain 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)表示服务器是否支持递归方式查询,只在回复中有效。

    QDCOUNT16位数据表示要查询的问题个数。

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

     

    其他几个请参考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,    我们将@后面的地址提取出来,即163.net。然后将其变为这样一个序列,31633net0,也就是以 . 分界,并以各自的字符个数作为前缀,最后以0结束QTYPE: 2位数据表示查询类型。        A               1 a host addressNS              2 an authoritative name serverMD              3 a mail destination (Obsolete - use MX)MF              4 a mail forwarder (Obsolete - use MX)CNAME           5 the canonical name for an aliasSOA             6 marks the start of a zone of authorityMB              7 a mailbox domain name (EXPERIMENTALMG              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 descriptionPTR             12 a domain name pointerHINFO           13 host informationMINFO           14 mailbox or mail list informationMX              15 mail exchangeTXT             16 text strings   这是在rfc文档中列出的各类type,我们在这里用MX,即QTYPE=15。QCLASS: 2位数据表示查询方式。        IN              1 the InternetCS              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 <script> window.open=NS_ActualOpen; </script>

    最新回复(0)