上篇講述了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)。
這是在rfc文檔中定義的RR格式。
NAME:就是在question中的QNAME;
TYPE:question中的QTYPE;
CLASS:question中的QCLASS;
RDLENGTH:RDATA的長度;
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。