DNS/実装/python/dnslib/intercept.pyについて、ここに記述してください。
1 # -*- coding: utf-8 -*-
2
3 """
4 InterceptResolver - proxy requests to upstream server
5 (optionally intercepting)
6
7 """
8 from __future__ import print_function
9
10 import binascii,copy,socket,struct,sys
11
12 from dnslib import DNSRecord,RR,QTYPE,RCODE,parse_time
13 from dnslib.server import DNSServer,DNSHandler,BaseResolver,DNSLogger
14 from dnslib.label import DNSLabel
15
16 class InterceptResolver(BaseResolver):
17
18 """
19 Intercepting resolver
20
21 Proxy requests to upstream server optionally intercepting requests
22 matching local records
23 """
24
25 def __init__(self,address,port,ttl,intercept,skip,nxdomain,timeout=0):
26 """
27 address/port - upstream server
28 ttl - default ttl for intercept records
29 intercept - list of wildcard RRs to respond to (zone format)
30 skip - list of wildcard labels to skip
31 nxdomain - list of wildcard labels to retudn NXDOMAIN
32 timeout - timeout for upstream server
33 """
34 self.address = address
35 self.port = port
36 self.ttl = parse_time(ttl)
37 self.skip = skip
38 self.nxdomain = nxdomain
39 self.timeout = timeout
40 self.zone = []
41 for i in intercept:
42 if i == '-':
43 i = sys.stdin.read()
44 for rr in RR.fromZone(i,ttl=self.ttl):
45 self.zone.append((rr.rname,QTYPE[rr.rtype],rr))
46
47 def resolve(self,request,handler):
48 reply = request.reply()
49 qname = request.q.qname
50 qtype = QTYPE[request.q.qtype]
51 # Try to resolve locally unless on skip list
52 if not any([qname.matchGlob(s) for s in self.skip]):
53 for name,rtype,rr in self.zone:
54 if qname.matchGlob(name) and (qtype in (rtype,'ANY','CNAME')):
55 a = copy.copy(rr)
56 a.rname = qname
57 reply.add_answer(a)
58 # Check for NXDOMAIN
59 if any([qname.matchGlob(s) for s in self.nxdomain]):
60 reply.header.rcode = getattr(RCODE,'NXDOMAIN')
61 return reply
62 # Otherwise proxy
63 if not reply.rr:
64 try:
65 if handler.protocol == 'udp':
66 proxy_r = request.send(self.address,self.port,
67 timeout=self.timeout)
68 else:
69 proxy_r = request.send(self.address,self.port,
70 tcp=True,timeout=self.timeout)
71 reply = DNSRecord.parse(proxy_r)
72 except socket.timeout:
73 reply.header.rcode = getattr(RCODE,'NXDOMAIN')
74
75 return reply
76
77 if __name__ == '__main__':
78
79 import argparse,sys,time
80
81 p = argparse.ArgumentParser(description="DNS Intercept Proxy")
82 p.add_argument("--port","-p",type=int,default=53,
83 metavar="<port>",
84 help="Local proxy port (default:53)")
85 p.add_argument("--address","-a",default="",
86 metavar="<address>",
87 help="Local proxy listen address (default:all)")
88 p.add_argument("--upstream","-u",default="8.8.8.8:53",
89 metavar="<dns server:port>",
90 help="Upstream DNS server:port (default:8.8.8.8:53)")
91 p.add_argument("--tcp",action='store_true',default=False,
92 help="TCP proxy (default: UDP only)")
93 p.add_argument("--intercept","-i",action="append",
94 metavar="<zone record>",
95 help="Intercept requests matching zone record (glob) ('-' for stdin)")
96 p.add_argument("--skip","-s",action="append",
97 metavar="<label>",
98 help="Don't intercept matching label (glob)")
99 p.add_argument("--nxdomain","-x",action="append",
100 metavar="<label>",
101 help="Return NXDOMAIN (glob)")
102 p.add_argument("--ttl","-t",default="60s",
103 metavar="<ttl>",
104 help="Intercept TTL (default: 60s)")
105 p.add_argument("--timeout","-o",type=float,default=5,
106 metavar="<timeout>",
107 help="Upstream timeout (default: 5s)")
108 p.add_argument("--log",default="request,reply,truncated,error",
109 help="Log hooks to enable (default: +request,+reply,+truncated,+error,-recv,-send,-data)")
110 p.add_argument("--log-prefix",action='store_true',default=False,
111 help="Log prefix (timestamp/handler/resolver) (default: False)")
112 args = p.parse_args()
113
114 args.dns,_,args.dns_port = args.upstream.partition(':')
115 args.dns_port = int(args.dns_port or 53)
116
117 resolver = InterceptResolver(args.dns,
118 args.dns_port,
119 args.ttl,
120 args.intercept or [],
121 args.skip or [],
122 args.nxdomain or [],
123 args.timeout)
124 logger = DNSLogger(args.log,args.log_prefix)
125
126 print("Starting Intercept Proxy (%s:%d -> %s:%d) [%s]" % (
127 args.address or "*",args.port,
128 args.dns,args.dns_port,
129 "UDP/TCP" if args.tcp else "UDP"))
130
131 for rr in resolver.zone:
132 print(" | ",rr[2].toZone(),sep="")
133 if resolver.nxdomain:
134 print(" NXDOMAIN:",", ".join(resolver.nxdomain))
135 if resolver.skip:
136 print(" Skipping:",", ".join(resolver.skip))
137 print()
138
139
140 DNSHandler.log = {
141 'log_request', # DNS Request
142 'log_reply', # DNS Response
143 'log_truncated', # Truncated
144 'log_error', # Decoding error
145 }
146
147 udp_server = DNSServer(resolver,
148 port=args.port,
149 address=args.address,
150 logger=logger)
151 udp_server.start_thread()
152
153 if args.tcp:
154 tcp_server = DNSServer(resolver,
155 port=args.port,
156 address=args.address,
157 tcp=True,
158 logger=logger)
159 tcp_server.start_thread()
160
161 while udp_server.isAlive():
162 time.sleep(1)