• [python网络编程]DNSserver


    在上一篇中,使用scrapy改动源IP发送请求的最后我们提到因为hosts文件不支持正则,会导致我们的随机域名DNS查询失败。

    使用DNS代理服务器能够解决问题,

    以下是我用gevent写的小工具。非常easy。我们仅仅拦截匹配的A记录。然后发送DNS Response,假设不匹配,那么我们服务器就是一个DNS代理,转发请求。

    # -*- coding=utf-8 -*-
    import struct
    from cStringIO import StringIO
    from collections import namedtuple
    from gevent import socket
    from gevent.server import DatagramServer
    
    Hex = lambda x : '0x{0:04x}'.format(x) # Hex(256) => "0x0100"
    
    QueryResult = namedtuple("DnsQuery",
                     "transactionID,flags,questions,answerRrs 
                     authorityRrs,additionalRrs,qname,qtype,qclass"
    )
    
    LOCALDNS = ("114.114.114.114",53)
    
    Hosts = {
        "*.ttt.com":"173.194.127.144", # google ip
    }
    
    def preg_match(preg,real):
        """
        only support '*'
        >>>preg_match("www.*.test*.com","www.python.test.com")
        True
        >>>preg_match("www.*.test*.com","www.python.tes.com")
        False
        """
        pre = 0
        for s in preg.split('*'):
            now = real.find(s)
            if now < pre:
                return False
            pre = now +len(s)
        return True
    
    def udp_send(address,data):
        sock = socket.socket(type=socket.SOCK_DGRAM)
        sock.connect(address)
        sock.send(data)
        response, address = sock.recvfrom(8192*4)
        return response,address
    
    class DnsParser:
        
        @classmethod
        def parseQuery(self,query):
            """
                   6a 02 01 00 00 01                         j.....
            00 00 00 00 00 00 03 77 77 77 03 61 61 61 03 63  .......www.aaa.c
            6f 6d 00 00 01 00 01                             om.....
    
            dns query package like above
            03 77 77 77 : three www
    
            """
            transactionID,flags,questions,answerRrs,authorityRrs,additionalRrs = map(Hex,struct.unpack("!6H",query[:12]))
            quries = StringIO(query[12:])
            c = struct.unpack("!c",quries.read(1))[0]
            domain = []
            while  c != 'x00':
                n = ord(c)
                domain.append(''.join(struct.unpack("!%sc" % n,quries.read(ord(c)))))
                c = struct.unpack("!c",quries.read(1))[0]
            domain = '.'.join(domain)
            qtype,qclass = map(Hex,struct.unpack("!2H",quries.read()))
            return QueryResult(transactionID,flags,questions,answerRrs,
                                authorityRrs,additionalRrs,domain,qtype,qclass)
    
        @classmethod
        def generateReqponse(self,queryData,ip):
            """
            only support ipv4
            """
            return ''.join([queryData[:2],"x81x80x00x01x00x02x00x00x00x00",
              queryData[12:],"xc0x0c","x00x01","x00x01","x00x00x00x1e","x00x04",
              struct.pack('BBBB',*map(int,ip.split('.')))
              ])
    
    class DnsServer(DatagramServer):
        def handle(self,data,address):
            query = DnsParser.parseQuery(data)
            print "get dns query from %s,query:%s" %(str(address),str(query))
            find = False
            for preg,ip in Hosts.iteritems():
                if preg_match(preg,query.qname):
                    find = True
                    break
            if find and query.qtype == "0x0001": #only handle A record
                print 'domain:%s in hosts' % query.qname
                response = DnsParser.generateReqponse(data,ip)
                self.socket.sendto(response,address)
            else:
                print 'transfer for %s' % query.qname
                response,serveraddress = udp_send(LOCALDNS,data)
                self.socket.sendto(response,address)
    
    
    if __name__ == "__main__":
        DnsServer("192.168.9.178:53").serve_forever()

    哈哈,刚好100行,不得不说python的强大。

    来个截图:



    功能有限。各位童鞋能够扩展,代码已经放到github,https://github.com/Skycrab/PyDnsProxy,有兴趣的童鞋一起完好。






  • 相关阅读:
    手机号码 正则表达式
    邮政编码的正则表达式
    对象为null,调用非静态方法产生空指针异常
    文件找不到异常(FileNotFoundException)
    数组下标越界异常解决方法
    空指针异常的解决方法
    需求:打印九九乘法表
    创建简单线程
    ·博客作业06--图
    博客作业05--查找
  • 原文地址:https://www.cnblogs.com/zfyouxi/p/5182334.html
Copyright © 2020-2023  润新知