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)。

這是在rfc文檔中定義的RR格式。

NAME:就是在question中的QNAME

TYPEquestion中的QTYPE

CLASSquestion中的QCLASS

RDLENGTHRDATA的長度;

RDATA:返回的數據,這纔是真正有用的數據,也是我們要解析的東西。

 

因爲其數據是被壓縮的,所以得想知道他的壓縮格式:

他的壓縮方式是將在數據中重複出現的字符放在一起,然後再字符出現的地方加上一個偏移位置,即如上圖所示,16位的數據以11開頭,後跟偏移量。偏移量是從信息的頭部開始算得。下面是一個rfc文檔中的例子:

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

 

這個結果是:在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


  
發佈了4 篇原創文章 · 獲贊 0 · 訪問量 3萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章