天天看點

Dns解析(上)Dns解析(上)

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]      

<script> window.open=NS_ActualOpen; </script>