/**//*
*DNSTools.java
*
*Createdon2003-9-24,13:56:09
*
*Tochangethistemplate,chooseTools|Templates
*andopenthetemplateintheeditor.
*/
packagetest;
/***//**
*
*@authoraxman
*/
importjava.io.*;
importjava.net.*;
importjava.util.*;
publicclassDNSTools...{
publicstaticfinalbyteTYPE_A=1;//A记录
publicstaticfinalbyteTYPE_CNAME=5;//CNAME记录
publicstaticfinalbyteTYPE_MX=15;//X记录
privatestaticintPORT=53;//DNS服务的端口
publicstaticString[]getQueryRecords(StringNameServer,StringdomainName,bytetype)...{
byte[]buf=newbyte[512];
makeQueryData(buf,domainName,type);//封装DNS请求
//以下获取DNS服务器的响应内容
DatagramSocketudpSocket=null;
try...{
InetAddressdnsIP=InetAddress.getByName(NameServer);
DatagramPacketsendPack=newDatagramPacket(buf,buf.length,dnsIP,PORT);
udpSocket=newDatagramSocket(PORT);
udpSocket.send(sendPack);
DatagramPacketreceivePack=newDatagramPacket(buf,buf.length);
udpSocket.receive(receivePack);
buf=receivePack.getData();
}catch(Exceptione)...{
returnnull;
}
finally...{try...{if(udpSocket!=null&&!udpSocket.isClosed())udpSocket.close();}catch(Exceptione)...{}}
//以下对DNS响应内容做分析
intqCount=((buf[4]&0xff)<<8)|(buf[5]&0xFF);//获得请求数
if(qCount<0)returnnull;
intaCount=((buf[6]&0xff)<<8)|(buf[7]&0xff);//获得响应数
if(aCount<0)returnnull;
intposition=12;//起始位置
for(inti=0;i<qCount;i++)...{
StringBufferdmBuffer=newStringBuffer();
position=analyzer(buf,dmBuffer,position);
position+=4;//增加长度字节部分
}
ArrayList<String>al=newArrayList<String>();
for(inti=0;i<aCount;i++)...{
StringBufferdmBuffer=newStringBuffer();
position=analyzer(buf,dmBuffer,position);
position+=10;
intpref=(buf[position++]<<8)|(buf[position++]&0xff);//获得基数
dmBuffer=newStringBuffer();
dmBuffer.append(pref).append("");
position=analyzer(buf,dmBuffer,position);
al.add(dmBuffer.toString());
}
returnal.toArray(newString[al.size()]);
}
privatestaticintanalyzer(byte[]receiveBytes,StringBufferdmBuffer,intposition)...{
intlen=receiveBytes[position++]&0xff;//取得将要处理的部分的长度
if(len==0)...{
returnposition;
}
intoffset;//偏移
do...{
if((len&0xc0)==0xc0)...{//压缩格式
if(position>=receiveBytes.length)...{//超过包的大小
return-1;
}
offset=((len&0x3f)<<8)|(receiveBytes[position++]&0xff);
analyzer(receiveBytes,dmBuffer,offset);//再一次递归调用获得压缩前的名称
returnposition;
}else...{//非压缩格式
if((position+len)>receiveBytes.length)...{//超过长度
return-1;
}
dmBuffer.append(newString(receiveBytes,position,len));
position+=len;
}
if(position>receiveBytes.length)...{
return-1;
}
len=receiveBytes[position++]&0xff;
if(len!=0)...{
dmBuffer.append(".");//加上.构成完整域名
}
}while(len!=0);
returnposition;
}
privatestaticvoidmakeQueryData(byte[]sendBytes,StringdomainName,bytetype)...{
intid=137*(newjava.util.Random()).nextInt(65535);
sendBytes[0]=(byte)(id>>8);
sendBytes[1]=(byte)(id&0xff);
sendBytes[2]=(byte)1;
sendBytes[3]=(byte)0;
sendBytes[4]=(byte)0;
sendBytes[5]=(byte)1;
sendBytes[6]=(byte)0;
sendBytes[7]=(byte)0;
sendBytes[8]=(byte)0;
sendBytes[9]=(byte)0;
sendBytes[10]=(byte)0;
sendBytes[11]=(byte)0;
String[]cols=domainName.split("//.");
intposition=12;
for(inti=0;i<cols.length;i++)...{
sendBytes[position++]=(byte)(cols[i].length()&0xFF);//转换为字节
byte[]b=cols[i].getBytes();
for(intj=0;j<b.length;j++)...{
sendBytes[position++]=b[j];
}
}
sendBytes[position++]=(byte)0;
sendBytes[position++]=(byte)0;
sendBytes[position++]=type;
sendBytes[position++]=(byte)0;
sendBytes[position++]=(byte)1;
}
publicstaticvoidmain(String[]args)throwsException...{
String[]s=DNSTools.getQueryRecords("202.106.0.20","sina.com.cn",DNSTools.TYPE_MX);
for(inti=0;i<s.length;i++)
System.out.println(s[i]);
}
}
/**
| 2字节的标识 | 2字节的标志 | 2字节的请求个数 | 2字节的资源记录数 | 2字节的授权资源记录个数
| 2字节额外的资源记录数 | 查询的域名(不固定长度) | 针对请求的应答资源记录(长度不固定)
| 授权资源记录(长度不固定) | 额外记录信息(长度不固定)
标识字段用于指出报文的编号,一般由客户指定,DNS服务器返回信息时带上此标识,告诉客户端回答
的是哪一个请求。
标志字段的16比特划分为8个子字段,从左至右(高位到低位)分别为:
QR 1 bit :0 查询报文 1 响应报文
Opcode 4 bit :通常为0,表示标准查询 ,1 反向查询,2 服务器状态查询
AA 1 bit :用于服务器返回报文,表示是否是授权回答
TC 1 bit :由于UDP自身长度限制,往往会截断512字节后的内容,该位表示是否可截断
RD 1 bit :该为用于在查询报文中设置,并由服务器响应报文中返回。该位告诉服务器必须处理此查询,
如果该位为0,且服务器返回的授权回答个数为0,那么服务器必须返回一个能够解答该查询的其他服务器的列表
RA 1 bit :如果服务器支持递归,那么服务器在响应报文中设定该位。
随后的3bit必须为0
rcode 4 bit :最后为返回码,0 无差错,3 名字差错,即在服务器上不存在要查询的域名的记录,一般用于从最终的授权名
字服务器返回。
查询请求部分由查询名字 查询类型 查询类组成。查询名字由多个标识符的序列组成,每一个标识首字节说明该标识符的长度,
最终由字节0表示名字结束。譬如cn.yahoo.com由2 c n 5 y a h o o 3 c o m 0组成。如果此域名后面还用到,一般在后面采用
压缩格式,那么首字节不是长度了,而是一个最高位为1的字节,一般是0xc0,因为不会出现长度超过64的标识符。压缩格式的
标志字节后是该域名的原标识的偏移值。查询类型为2字节,1 表示A记录查询 5 表示CNAME记录查询 15 表示MX记录查询。类表
示是否是Internet数据。
应答报文中的应答记录由域名(长度不固定) 类型(2字节) 类(2字节) 生存时间(4字节,秒数) 资源数据长度(2字节)
资源数据(不固定)。域名的格式同查询域名格式相同。类型、类的解释同查询请求部分。资源数据根据记录类型不同而不同。
*/
分享到:
相关推荐
23个设计模式之一的备忘录模式-极客学院-java-课件代码,
java课设--个人备忘录管理系统
java设计模式-备忘录模式源代码, 源码中为设计模式的工程源文件,已经测试过,没有问题。
java课设--个人备忘录管理系统.doc
javaMD5加密及登录验证(备忘) - Hibernate - Java - ITeye论坛.mhtjavaMD5加密及登录验证(备忘) - Hibernate - Java - ITeye论坛.mhtjavaMD5加密及登录验证(备忘
实现备忘录基本功能,可以显示年月日日历,点击任意一日期可以写备忘录,写完保存后在点这个日期则跳出窗口说该日期有备忘录
备忘录模式的示例代码和文档,学习备忘录模式的参考资料。
JAVA课设--个人备忘录管理系统
美国交通设施的六大主要经济事实-汉密尔顿工程 -政策备忘录-2015.5-外文-报告资料.pdf
用java实现备忘时钟,适合初学者,用java实现备忘时钟,适合初学者,
java记事簿管理系统_备忘录管理系统_通讯录_记账本-源码+数据库+论文or文档.zip
java课程设计--用java写的个人备忘录管理系统
基础知识 基础知识设计模式概述 从招式与内功谈起——设计模式概述(一) 从招式与内功谈起——设计模式概述(二) 从招式与内功谈起——设计模式概述(三) 面向对象设计原则 面向对象设计原则之单一职责原则 面向...
基于java的备忘录软件开发,还有日程管理的功能
微信小程序源码-备忘录.zip微信小程序源码-备忘录.zip微信小程序源码-备忘录.zip微信小程序源码-备忘录.zip微信小程序源码-备忘录.zip微信小程序源码-备忘录.zip微信小程序源码-备忘录.zip微信小程序源码-备忘录.zip...
java-备忘录编写源代码及运行界面截图.docx
这是一款经典的代码备忘录软件,对于程序员来说,可以随时保存必要的代码是非常重要的,本软件有很强大的功能,方便使用。
微信小程序-备忘录示例代码.zip 小程序模板代码,可以直接从源码里粘贴复制过来,虽然这样做不利于自己独立编写代码。
在备忘录模式里,一个备忘录是一个对象,它存储另一个对象(备忘录的原发器)在某个瞬间的内部状态。备忘的目的就是为了以后在需要的时候,可以将原发器对象的状态恢复(undo/rollback)到备忘录所保存的状态。 备忘...
备忘录源码.zip