Dns解析(下)

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

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

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

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

Constant.DNSUDPLEN);

ID_Socket.receive(ID_Packet);

这里的变量已在上篇中定义了,Constant.DNSUDPLEN为512。

接下来就只要将这数据解压缩就可以了。这里就涉及了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;

TYPE:question中的QTYPE;

CLASS:question中的QCLASS;

RDLENGTH:RDATA的长度;

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。

文章不免有错,请各位多指点[email protected]

 

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