一段代码备忘,放在这里,我以前好象没有发表过,CN-JAVA竟然有人原文COPY了说是他的原创.发个修改版的.

/*
 * DNSTools.java
 * 
 * Created on 2003-9-24, 13:56:09
 * 
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 
*/


package  test;

/**
 *
 * 
@author axman
 
*/

import  java.io. * ;
import  java.net. * ;
import  java.util. * ;

public   class  DNSTools  {
   

    
public static final byte TYPE_A = 1;            //A记录
    public static final byte TYPE_CNAME = 5;        //CNAME记录
    public static final byte TYPE_MX = 15;          //X记录
    
    
private static int PORT = 53;                   //DNS服务的端口
    public static String[] getQueryRecords(String NameServer,String domainName,byte type){
        
        
byte[] buf = new byte[512];
        makeQueryData(buf,domainName,type);         
//封装DNS请求

        
//以下获取DNS服务器的响应内容
        DatagramSocket udpSocket = null;
        
try{
            InetAddress dnsIP 
= InetAddress.getByName(NameServer);
            DatagramPacket sendPack 
= new DatagramPacket(buf, buf.length, dnsIP, PORT);
            udpSocket 
= new DatagramSocket(PORT);
            udpSocket.send(sendPack);
            DatagramPacket receivePack 
= new DatagramPacket(buf, buf.length);
            udpSocket.receive(receivePack);
            buf 
= receivePack.getData();
        }
catch(Exception e){
            
return null;
        }

        
finally{try{if(udpSocket != null && !udpSocket.isClosed()) udpSocket.close();}catch(Exception e){}}

        
//以下对DNS响应内容做分析
        
        
int qCount = ( (buf[4& 0xff<< 8| (buf[5& 0xFF); //获得请求数
        if (qCount < 0return null;
        
int aCount = ( (buf[6& 0xff<< 8| (buf[7& 0xff); //获得响应数
        if (aCount < 0return null;
        
int position = 12//起始位置
        
        
for (int i = 0; i < qCount; i++{
            StringBuffer dmBuffer  
= new StringBuffer();
            position 
= analyzer(buf,dmBuffer,position);
            position 
+= 4;                                      //增加长度字节部分
        }

        ArrayList
<String> al = new ArrayList<String>();
        
for (int i = 0; i < aCount; i++{
            StringBuffer dmBuffer  
= new StringBuffer();
            position 
= analyzer(buf,dmBuffer,position);
            position 
+= 10;
            
int pref = (buf[position++<< 8| (buf[position++& 0xff); //获得基数
            dmBuffer  = new StringBuffer();
            dmBuffer.append(pref).append(
" ");
            position 
= analyzer(buf,dmBuffer,position);
            al.add(dmBuffer.toString());
        }

        
return al.toArray(new String[al.size()]);
    }


    
    
private static int analyzer(byte[] receiveBytes, StringBuffer dmBuffer, int position) {
        
int len = receiveBytes[position++& 0xff;            //取得将要处理的部分的长度
        if (len == 0{
            
return position;
        }

        
int offset;                                     //偏移
        do {
            
if ((len & 0xc0== 0xc0{                 //压缩格式
                if (position >= receiveBytes.length) {        //超过包的大小
                    return -1;
                }

                offset 
= ((len & 0x3f<< 8| (receiveBytes[position++& 0xff);
                analyzer(receiveBytes, dmBuffer, offset);       
//再一次递归调用获得压缩前的名称
                return position;
            }
 else {                                      //非压缩格式
                if ((position + len) > receiveBytes.length) {   //超过长度
                    return -1;
                }

                dmBuffer.append(
new String(receiveBytes, position, len));
                position 
+= len;
            }

            
            
if (position > receiveBytes.length) {
                
return -1;
            }

            len 
= receiveBytes[position++& 0xff;
            
if (len != 0{
                dmBuffer.append(
"."); //加上.构成完整域名
            }

        }
while (len != 0);
        
return position;
    }

    
    
    
private static void makeQueryData(byte[] sendBytes,String domainName,byte type){
        
int id = 137 * (new java.util.Random()).nextInt(65535);
        sendBytes[
0= (byte) (id >> 8);
        sendBytes[
1= (byte) (id & 0xff);
        sendBytes[
2= (byte1;
        sendBytes[
3= (byte0;
        sendBytes[
4= (byte0;
        sendBytes[
5= (byte1;
        sendBytes[
6= (byte0;
        sendBytes[
7= (byte0;
        sendBytes[
8= (byte0;
        sendBytes[
9= (byte0;
        sendBytes[
10= (byte0;
        sendBytes[
11= (byte0;
        String[] cols 
= domainName.split("//.");
        
int position = 12;
        
for(int i=0;i<cols.length;i++{
            sendBytes[position
++= (byte) (cols[i].length() & 0xFF); //转换为字节
            byte[] b = cols[i].getBytes();
            
for (int j = 0; j < b.length; j++{
                sendBytes[position
++= b[j];
            }

        }

        sendBytes[position
++= (byte0;
        sendBytes[position
++= (byte0;
        sendBytes[position
++= type;
        sendBytes[position
++= (byte0;
        sendBytes[position
++= (byte1;
    }

    
    
public static void main(String[] args) throws Exception {
        String[] s 
= DNSTools.getQueryRecords("202.106.0.20""sina.com.cn", DNSTools.TYPE_MX);
       
for(int i=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字节)
资源数据(不固定)。域名的格式同查询域名格式相同。类型、类的解释同查询请求部分。资源数据根据记录类型不同而不同。

*/

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值