Neeke

伪全栈攻城狮

python dnslib dnsproxy

一直有个想法就是在路由器上收集DNS记录,但是一直没搞,人有时候吧,就是太懒了!然后呢,最近感觉用python写点小玩意效率上比java高多了,而且部署起来方便,尤其是在linux系统上,不像java还得安装配置环境什么的,python直接就是系统内置的。

搜索了一下,发现python有一个dnslib模块,然后在想这玩意怎么用?怎么做DNS代理呢,本来打算从头来呢,结果没想到人家本来就带了一个完整的实现“ProxyResolver”,我需要做的只是把它的日志记录方式改成数据库的,这个开发效率确实挺快的。

# -*- coding: utf-8 -*-

from __future__ import print_function

import binascii,socket,struct

from dnslib import DNSRecord,RCODE, QTYPE
from dnslib.server import DNSServer,DNSHandler,BaseResolver,DNSLogger
import pymysql


class ProxyResolver(BaseResolver):

    def __init__(self,address,port,timeout=0):
        self.address = address
        self.port = port
        self.timeout = timeout

    def resolve(self,request,handler):
        try:
            if handler.protocol == 'udp':
                proxy_r = request.send(self.address,self.port,
                                timeout=self.timeout)
            else:
                proxy_r = request.send(self.address,self.port,
                                tcp=True,timeout=self.timeout)
            reply = DNSRecord.parse(proxy_r)
        except socket.timeout:
            reply = request.reply()
            reply.header.rcode = getattr(RCODE,'NXDOMAIN')

        return reply

class PassthroughDNSHandler(DNSHandler):
    """
        Modify DNSHandler logic (get_reply method) to send directly to 
        upstream DNS server rather then decoding/encoding packet and
        passing to Resolver (The request/response packets are still
        parsed and logged but this is not inline)
    """
    def get_reply(self,data):
        host,port = self.server.resolver.address,self.server.resolver.port

        request = DNSRecord.parse(data)
        self.log_request(request)

        if self.protocol == 'tcp':
            data = struct.pack("!H",len(data)) + data
            response = send_tcp(data,host,port)
            response = response[2:]
        else:
            response = send_udp(data,host,port)

        reply = DNSRecord.parse(response)
        self.log_reply(reply)

        return response

def send_tcp(data,host,port):

    sock = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
    sock.connect((host,port))
    sock.sendall(data)
    response = sock.recv(8192)
    length = struct.unpack("!H",bytes(response[:2]))[0]
    while len(response) - 2 < length:
        response += sock.recv(8192)
    sock.close()
    return response

def send_udp(data,host,port):

    sock = socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
    sock.sendto(data,(host,port))
    response,server = sock.recvfrom(8192)
    sock.close()
    return response

class MysqlLogger():
    def log_data(self, dnsobj):
        pass

    def log_error(self, handler, e):
        pass

    def log_pass(self, *args):
        pass

    def log_prefix(self, handler):
        pass

    def log_recv(self, handler, data):
        pass

    def log_reply(self, handler, reply):
        pass

    def log_request(self, handler, request):
        try:
            domain = request.q.qname.__str__()
            type = QTYPE[request.q.qtype]
            conn = pymysql.connect(host='192.168.0.229', user='user_dnslog', passwd='hXolZPWc5ywXFDD7kH7V', db='dnslog')
            with conn.cursor() as cursor:
                cursor.execute('SELECT COUNT(1) FROM dnslog WHERE domain =%s AND type = %s', (domain, type))
                if cursor.fetchone()[0] == 0:
                    cursor.execute('INSERT INTO dnslog(domain, type) VALUES (%s,%s)', (domain, type))
            conn.commit()
            conn.close()
        except Exception as e:
            print(e)

    def log_send(self, handler, data):
        pass

    def log_truncated(self, handler, reply):
        pass

if __name__ == '__main__':

    import argparse,sys,time

    p = argparse.ArgumentParser(description="DNS Proxy")
    p.add_argument("--port","-p",type=int,default=53,
                    metavar="<port>",
                    help="Local proxy port (default:53)")
    p.add_argument("--address","-a",default="",
                    metavar="<address>",
                    help="Local proxy listen address (default:all)")
    p.add_argument("--upstream","-u",default="119.29.29.29:53",
            metavar="<dns server:port>",
                    help="Upstream DNS server:port (default:119.29.29.29:53)")
    p.add_argument("--tcp",action='store_true',default=False,
                    help="TCP proxy (default: UDP only)")
    p.add_argument("--timeout","-o",type=float,default=5,
                    metavar="<timeout>",
                    help="Upstream timeout (default: 5s)")
    p.add_argument("--passthrough",action='store_true',default=False,
                    help="Dont decode/re-encode request/response (default: off)")
    p.add_argument("--log",default="request,reply,truncated,error",
                    help="Log hooks to enable (default: +request,+reply,+truncated,+error,-recv,-send,-data)")
    p.add_argument("--log-prefix",action='store_true',default=False,
                    help="Log prefix (timestamp/handler/resolver) (default: False)")
    args = p.parse_args()

    args.dns,_,args.dns_port = args.upstream.partition(':')
    args.dns_port = int(args.dns_port or 53)

    print("Starting Proxy Resolver (%s:%d -> %s:%d) [%s]" % (
                        args.address or "*",args.port,
                        args.dns,args.dns_port,
                        "UDP/TCP" if args.tcp else "UDP"))

    resolver = ProxyResolver(args.dns,args.dns_port,args.timeout)
    handler = PassthroughDNSHandler if args.passthrough else DNSHandler
    logger = MysqlLogger()
    udp_server = DNSServer(resolver,
                           port=args.port,
                           address=args.address,
                           logger=logger,
                           handler=handler)
    udp_server.start_thread()

    if args.tcp:
        tcp_server = DNSServer(resolver,
                               port=args.port,
                               address=args.address,
                               tcp=True,
                               logger=logger,
                               handler=handler)
        tcp_server.start_thread()

    while udp_server.isAlive():
        time.sleep(1)

然后把路由器的默认DNS改成了我搭的这个代理跑了几天,效果还可以。

1.PNG

发表评论:

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。

«   2016年11月   »
123456
78910111213
14151617181920
21222324252627
282930
网站分类
搜索
最新留言
文章归档
友情链接

Powered By Z-BlogPHP 1.5 Zero

Copyright Your WebSite.Some Rights Reserved.