%PDF- %PDF-
Direktori : /lib/python3/dist-packages/dnslib/ |
Current File : //lib/python3/dist-packages/dnslib/intercept.py |
# -*- coding: utf-8 -*- """ InterceptResolver - proxy requests to upstream server (optionally intercepting) """ from __future__ import print_function import binascii,copy,socket,struct,sys from dnslib import DNSRecord,RR,QTYPE,RCODE,parse_time from dnslib.server import DNSServer,DNSHandler,BaseResolver,DNSLogger from dnslib.label import DNSLabel class InterceptResolver(BaseResolver): """ Intercepting resolver Proxy requests to upstream server optionally intercepting requests matching local records """ def __init__(self,address,port,ttl,intercept,skip,nxdomain,forward,all_qtypes,timeout=0): """ address/port - upstream server ttl - default ttl for intercept records intercept - list of wildcard RRs to respond to (zone format) skip - list of wildcard labels to skip nxdomain - list of wildcard labels to return NXDOMAIN forward - list of wildcard labels to forward all_qtypes - intercept all qtypes if qname matches. timeout - timeout for upstream server(s) """ self.address = address self.port = port self.ttl = parse_time(ttl) self.skip = skip self.nxdomain = nxdomain self.forward = [] for i in forward: qname, _, upstream = i.partition(':') upstream_ip, _, upstream_port = upstream.partition(':') self.forward.append((qname, upstream_ip, int(upstream_port or '53'))) self.all_qtypes = all_qtypes self.timeout = timeout self.zone = [] for i in intercept: if i == '-': i = sys.stdin.read() for rr in RR.fromZone(i,ttl=self.ttl): self.zone.append((rr.rname,QTYPE[rr.rtype],rr)) def resolve(self,request,handler): matched = False reply = request.reply() qname = request.q.qname qtype = QTYPE[request.q.qtype] # Try to resolve locally unless on skip list if not any([qname.matchGlob(s) for s in self.skip]): for name,rtype,rr in self.zone: if qname.matchGlob(name): if qtype in (rtype,'ANY','CNAME'): a = copy.copy(rr) a.rname = qname reply.add_answer(a) matched = True # Check for NXDOMAIN if any([qname.matchGlob(s) for s in self.nxdomain]): reply.header.rcode = getattr(RCODE,'NXDOMAIN') return reply if matched and self.all_qtypes: return reply # Otherwise proxy, first checking forwards, then to upstream. upstream, upstream_port = self.address,self.port if not any([qname.matchGlob(s) for s in self.skip]): for name, ip, port in self.forward: if qname.matchGlob(name): upstream, upstream_port = ip, port if not reply.rr: try: if handler.protocol == 'udp': proxy_r = request.send(upstream,upstream_port, timeout=self.timeout) else: proxy_r = request.send(upstream,upstream_port, tcp=True,timeout=self.timeout) reply = DNSRecord.parse(proxy_r) except socket.timeout: reply.header.rcode = getattr(RCODE,'SERVFAIL') return reply if __name__ == '__main__': import argparse,sys,time p = argparse.ArgumentParser(description="DNS Intercept 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="8.8.8.8:53", metavar="<dns server:port>", help="Upstream DNS server:port (default:8.8.8.8:53)") p.add_argument("--tcp",action='store_true',default=False, help="TCP proxy (default: UDP only)") p.add_argument("--intercept","-i",action="append", metavar="<zone record>", help="Intercept requests matching zone record (glob) ('-' for stdin)") p.add_argument("--skip","-s",action="append", metavar="<label>", help="Don't intercept matching label (glob)") p.add_argument("--nxdomain","-x",action="append", metavar="<label>", help="Return NXDOMAIN (glob)") p.add_argument("--forward","-f",action="append", metavar="<label:dns server:port>", help="forward requests matching label (glob) to dns server") p.add_argument("--ttl","-t",default="60s", metavar="<ttl>", help="Intercept TTL (default: 60s)") p.add_argument("--timeout","-o",type=float,default=5, metavar="<timeout>", help="Upstream timeout (default: 5s)") p.add_argument("--all-qtypes",action='store_true',default=False, help="Return an empty response if qname matches, but qtype doesn't") 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) resolver = InterceptResolver(args.dns, args.dns_port, args.ttl, args.intercept or [], args.skip or [], args.nxdomain or [], args.forward or [], args.all_qtypes, args.timeout) logger = DNSLogger(args.log,args.log_prefix) print("Starting Intercept Proxy (%s:%d -> %s:%d) [%s]" % ( args.address or "*",args.port, args.dns,args.dns_port, "UDP/TCP" if args.tcp else "UDP")) for rr in resolver.zone: print(" | ",rr[2].toZone(),sep="") if resolver.nxdomain: print(" NXDOMAIN:",", ".join(resolver.nxdomain)) if resolver.skip: print(" Skipping:",", ".join(resolver.skip)) if resolver.forward: print(" Forwarding:") for i in resolver.forward: print(" | ","%s:%s:%s" % i,sep="") print() DNSHandler.log = { 'log_request', # DNS Request 'log_reply', # DNS Response 'log_truncated', # Truncated 'log_error', # Decoding error } udp_server = DNSServer(resolver, port=args.port, address=args.address, logger=logger) udp_server.start_thread() if args.tcp: tcp_server = DNSServer(resolver, port=args.port, address=args.address, tcp=True, logger=logger) tcp_server.start_thread() while udp_server.isAlive(): time.sleep(1)