http://pydoc.net/Python/dnslib/0.9.3/dnslib.proxy/
- log_request 周辺のエラー server.logging.log_request(self,request)
- reply も同様
-- ToshinoriMaeno 2017-04-16 10:57:46
1 # -*- coding: utf-8 -*-
2
3 from __future__ import print_function
4
5 import binascii,socket,struct
6
7 from dnslib import DNSRecord,RCODE
8 from dnslib.server import DNSServer,DNSHandler,BaseResolver,DNSLogger
9
10 class ProxyResolver(BaseResolver):
11 """
12 Proxy resolver - passes all requests to upstream DNS server and
13 returns response
14
15 Note that the request/response will be each be decoded/re-encoded
16 twice:
17
18 a) Request packet received by DNSHandler and parsed into DNSRecord
19 b) DNSRecord passed to ProxyResolver, serialised back into packet
20 and sent to upstream DNS server
21 c) Upstream DNS server returns response packet which is parsed into
22 DNSRecord
23 d) ProxyResolver returns DNSRecord to DNSHandler which re-serialises
24 this into packet and returns to client
25
26 In practice this is actually fairly useful for testing but for a
27 'real' transparent proxy option the DNSHandler logic needs to be
28 modified (see PassthroughDNSHandler)
29
30 """
31
32 def __init__(self,address,port,timeout=0):
33 self.address = address
34 self.port = port
35 self.timeout = timeout
36
37 def resolve(self,request,handler):
38 try:
39 if handler.protocol == 'udp':
40 proxy_r = request.send(self.address,self.port,timeout=self.timeout)
41 else:
42 proxy_r = request.send(self.address,self.port,tcp=True,timeout=self.timeout)
43 reply = DNSRecord.parse(proxy_r)
44 except socket.timeout:
45 reply = request.reply()
46 reply.header.rcode = getattr(RCODE,'NXDOMAIN')
47
48 return reply
49
50 class PassthroughDNSHandler(DNSHandler):
51 """
52 Modify DNSHandler logic (get_reply method) to send directly to
53 upstream DNS server rather then decoding/encoding packet and
54 passing to Resolver (The request/response packets are still
55 parsed and logged but this is not inline)
56 """
57 def get_reply(self,data):
58 host = self.server.resolver.address
59 port = self.server.resolver.port
60
61 request = DNSRecord.parse(data)
62 self.log_request(request)
63
64 if self.protocol == 'tcp':
65 data = struct.pack("!H",len(data)) + data
66 response = send_tcp(data,host,port)
67 response = response[2:]
68 else:
69 response = send_udp(data,host,port)
70
71 reply = DNSRecord.parse(response)
72 self.log_reply(reply)
73
74 return response
75
76 def send_tcp(data,host,port):
77 """
78 Helper function to send/receive DNS TCP request
79 (in/out packets will have prepended TCP length header)
80 """
81 sock = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
82 sock.connect((host,port))
83 sock.sendall(data)
84 response = sock.recv(8192)
85 length = struct.unpack("!H",bytes(response[:2]))[0]
86 while len(response) - 2 < length:
87 response += sock.recv(8192)
88 sock.close()
89 return response
90
91 def send_udp(data,host,port):
92 """
93 Helper function to send/receive DNS UDP request
94 """
95 sock = socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
96 sock.sendto(data,(host,port))
97 response,server = sock.recvfrom(8192)
98 sock.close()
99 return response
100
101 if __name__ == '__main__':
102
103 import argparse,sys,time
104
105 p = argparse.ArgumentParser(description="DNS Proxy")
106 p.add_argument("--port","-p",type=int,default=8053, metavar="<port>",
107 help="Local proxy port (default:8053)")
108 p.add_argument("--address","-a",default="", metavar="<address>",
109 help="Local proxy listen address (default:all)")
110 p.add_argument("--upstream","-u",default="8.8.8.8:53", metavar="<dns server:port>",
111 help="Upstream DNS server:port (default:8.8.8.8:53)")
112 p.add_argument("--tcp",action='store_true',default=False,
113 help="TCP proxy (default: UDP only)")
114 p.add_argument("--timeout","-o",type=float,default=5, metavar="<timeout>",
115 help="Upstream timeout (default: 5s)")
116 p.add_argument("--passthrough",action='store_true',default=False,
117 help="Dont decode/re-encode request/response (default: off)")
118 p.add_argument("--log",default="request,reply,truncated,error",
119 help="Log hooks to enable (default: +request,+reply,+truncated,+error,-recv,-send,-data)")
120 p.add_argument("--log-prefix",action='store_true',default=False,
121 help="Log prefix (timestamp/handler/resolver) (default: False)")
122 args = p.parse_args()
123
124 args.dns,_,args.dns_port = args.upstream.partition(':')
125 args.dns_port = int(args.dns_port or 53)
126
127 print("Starting Proxy Resolver (%s:%d -> %s:%d) [%s]" % (
128 args.address or "*",args.port,
129 args.dns,args.dns_port,
130 "UDP/TCP" if args.tcp else "UDP"))
131
132 resolver = ProxyResolver(args.dns,args.dns_port,args.timeout)
133 handler = PassthroughDNSHandler if args.passthrough else DNSHandler
134 logger = DNSLogger(args.log,args.log_prefix)
135 udp_server = DNSServer(resolver,
136 port=args.port,
137 address=args.address,
138 logger=logger,
139 handler=handler)
140 udp_server.start_thread()
141
142 if args.tcp:
143 tcp_server = DNSServer(resolver,
144 port=args.port,
145 address=args.address,
146 tcp=True,
147 logger=logger,
148 handler=handler)
149 tcp_server.start_thread()
150
151 while udp_server.isAlive():
152 time.sleep(1)