Dns解析(下)

    技术2022-05-11  109

    Dns解析()

    上篇讲述了Dns的查询包和发送,本文将分析Dns的返回包。

    下面这段程序是从Dns服务器上得到dns的返回包:

    ID_Packet=new DatagramPacket(new byte[Constant.DNSUDPLEN],

    Constant.DNSUDPLEN);

    ID_Socket.receive(ID_Packet);

    这里的变量已在上篇中定义了,Constant.DNSUDPLEN512

    接下来就只要将这数据解压缩就可以了。这里就涉及了RR的格式了(Resource Record Format)。

         0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F     +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+     |                                               |     /                                               /     /                      NAME                     /     |                                               |     +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+     |                      TYPE                     |     +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+     |                     CLASS                     |     +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+     |                      TTL                      |     |                                               |     +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+    |                   RDLENGTH                    |     +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--|     /                     RDATA                     /     /                                               /     +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+

    这是在rfc文档中定义的RR格式。

    NAME:就是在question中的QNAME

    TYPEquestion中的QTYPE

    CLASSquestion中的QCLASS

    RDLENGTHRDATA的长度;

    RDATA:返回的数据,这才是真正有用的数据,也是我们要解析的东西。

     

    因为其数据是被压缩的,所以得想知道他的压缩格式:

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

    他的压缩方式是将在数据中重复出现的字符放在一起,然后再字符出现的地方加上一个偏移位置,即如上图所示,16位的数据以11开头,后跟偏移量。偏移量是从信息的头部开始算得。下面是一个rfc文档中的例子:

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

           +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+     20 |           1           |           F           |        +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+     22 |           3           |           I           |        +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+     24 |           S           |           I           |        +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+     26 |           4           |           A           |        +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+     28 |           R           |           P           |        +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+     30 |           A           |           0           |        +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+          +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+     40 |           3           |           F           |        +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+     42 |           O           |           O           |        +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+     44 | 1  1|                20                       |        +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+   

    这个结果是:在40位置的域名是FOO.F.ISI.ARPA

    了解了他的压缩方式,解析就简单了。

    上篇中在Header中我们已提到ANCOUNT这个字段,他表示的是回复中结果的数目,我们相见他解析出来:

    public int getAnswerCount()

        {

            int INDEX=6;

            byte[] AnCountArray=new byte[2];

           

            System.arraycopy(message,INDEX,AnCountArray,0,2);

            return DnsTool.BytesToInt(AnCountArray);//byte[]变为int

        }

    得到了ANCOUNT,就可以解释结果了:

    public Vector parseAnswer()

        {

            int theOffset=8;

            int pos=thePosOfAnswer;(thePosOfAnswer是你发得dns包的长度)

            int i=0,p;

            int RDlength;

            byte[] tmp;

            String Name="";

    Vector IV_ Answer=new Vector();

           

            //get return name from message

            while(i<getAnswerCount())

            {

                Name="";

                //get type

                pos+=2;

                tmp=new byte[2];

                System.arraycopy(message,pos,tmp,0,2);

               

                if(DnsTool.BytesToInt(tmp)==Constant.TYPE_MX)//check the type

                {

                    pos+=theOffset;

                    //get RDlength

                    tmp=new byte[2];

                    System.arraycopy(message,pos,tmp,0,2);

                    RDlength=DnsTool.BytesToInt(tmp);

                   

                    pos+=4;

                    p=pos;

                    while((pos-p)<RDlength-2)

                    {

                        if((message[pos]&0xC0)==0xC0)

                        {

                            //this is a offset

                            Name+=getPrior((message[pos]&0x3F)

    |(message[pos+1]&0xFF));

                            pos+=2;

                        }

                        else

                        {

                            //not offset

                            tmp=new byte[message[pos]];

                            System.arraycopy(message,pos+1,tmp,0,tmp.length);

                            pos+=message[pos]+1;

                           

                            if(message[pos]!=0)

                                Name+=new String(tmp)+".";

                            else

                                Name+=new String(tmp);

                        }

                    }

                }

             IV_Answer.addElement(Name);  

             i++;  

            }

        }

    函数Stirng getPrior(int)是根据其偏移量等到所要的字符串,这是一个递归函数:

    private String getPrior(int j)

        {

            byte[] tmp;

            String Name="";

           

            while(message[j]!=0)

            {

                if((message[j]&0xC0)==0xC0)

                {

                    String mid=getPrior((message[j]&0x3F)|(message[j+1]&0xFF));

                    Name+=mid;

                    j+=mid.length()+1;

                }

                else

                {

                    tmp=new byte[message[j]];

                    System.arraycopy(message,j+1,tmp,0,tmp.length);

                    j+=message[j]+1;

                    if(message[j]!=0)

                        Name+=new String(tmp)+".";

                    else

                        Name+=new String(tmp);

                }

            }

            return Name;

        }

    我们只介绍了mail地址的dns解析,其他几类都大同小异,如需要可参考rfc1035

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

     


    最新回复(0)