Dns解析(上)

Dns解析()


DnsDomain 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)表示服务器是否支持递归方式查询,只在回复中有效。

QDCOUNT16位数据表示要查询的问题个数。

ANCOUNT16位数据表示回复结果的个数,只在回复中有效。

 


其他几个请参考rfc文档,在这里我们只用这些,并将其他参数设为0


 


Question

     0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F
    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
    |                                               |
    /                     QNAME                     /
    /                                               /
    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
    |                     QTYPE                     |
    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
    |                     QCLASS                    |
    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+

   
     
   
QNAME: 要求查询的域名地址比如有这样一个邮件地址XXX@163.net,
    我们将@后面的地址提取出来,即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的返回包。

   
     
   
文章不免有错,请各位多指点craks@263.net
<script> window.open=NS_ActualOpen; </script>
  • 0
    点赞
  • 1
    评论
  • 0
    收藏
  • 一键三连
    一键三连
  • 扫一扫,分享海报

相关推荐
<p> <span style="font-size:14px;color:#337FE5;">【为什么学爬虫?】</span> </p> <p> <span style="font-size:14px;">       1、爬虫入手容易,但是深入较难,如何写出高效率的爬虫,如何写出灵活性高可扩展的爬虫都是一项技术活。另外在爬虫过程中,经常容易遇到被反爬虫,比如字体反爬、IP识别、验证码等,如何层层攻克难点拿到想要的数据,这门课程,你都能学到!</span> </p> <p> <span style="font-size:14px;">       2、如果是作为一个其他行业的开发者,比如app开发,web开发,学习爬虫能让你加强对技术的认知,能够开发出更加安全的软件和网站</span> </p> <p> <br /> </p> <span style="font-size:14px;color:#337FE5;">【课程设计】</span> <p class="ql-long-10663260"> <span> </span> </p> <p class="ql-long-26664262" style="font-size:11pt;color:#494949;"> 一个完整的爬虫程序,无论大小,总体来说可以分成三个步骤,分别是: </p> <ol> <li class="" style="font-size:11pt;color:#494949;"> 网络请求:模拟浏览器的行为从网抓取数据。 </li> <li class="" style="font-size:11pt;color:#494949;"> 数据解析:将请求下来的数据进行过滤,提取我们想要的数据。 </li> <li class="" style="font-size:11pt;color:#494949;"> 数据存储:将提取到的数据存储到硬盘或者内存中。比如用mysql数据库或者redis等。 </li> </ol> <p class="ql-long-26664262" style="font-size:11pt;color:#494949;"> 那么本课程也是按照这几个步骤循序渐进的进行讲解,带领学生完整的掌握每个步骤的技术。另外,因为爬虫的多样性,在爬取的过程中可能会发生被反爬、效率低下等。因此我们又增加了两个章节用来提高爬虫程序的灵活性,分别是: </p> <ol> <li class="" style="font-size:11pt;color:#494949;"> 爬虫进阶:包括IP代理,多线程爬虫,图形验证码识别、JS加密解密、动态网页爬虫、字体反爬识别等。 </li> <li class="" style="font-size:11pt;color:#494949;"> Scrapy和分布式爬虫:Scrapy框架、Scrapy-redis组件、分布式爬虫等。 </li> </ol> <p class="ql-long-26664262" style="font-size:11pt;color:#494949;"> 通过爬虫进阶的知识点我们能应付大量的反爬网站,而Scrapy框架作为一个专业的爬虫框架,使用他可以快速提高我们编写爬虫程序的效率和速度。另外如果一台机器不能满足你的需求,我们可以用分布式爬虫让多台机器帮助你快速爬取数据。 </p> <p style="font-size:11pt;color:#494949;">   </p> <p class="ql-long-26664262" style="font-size:11pt;color:#494949;"> 从基础爬虫到商业化应用爬虫,本套课程满足您的所有需求! </p> <p class="ql-long-26664262" style="font-size:11pt;color:#494949;"> <br /> </p> <p> <br /> </p> <p> <span style="font-size:14px;background-color:#FFFFFF;color:#337FE5;">【课程服务】</span> </p> <p> <span style="font-size:14px;">专属付费社群+定期答疑</span> </p> <p> <br /> </p> <p class="ql-long-24357476"> <span style="font-size:16px;"><br /> </span> </p> <p> <br /> </p> <p class="ql-long-24357476"> <span style="font-size:16px;"></span> </p>
©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值