def __init__(self, hostname: str, bind: TIfaceAddress, port: int = 53): super().__init__(bind.ip, port) self.hostname = DNSLabel(f'{hostname}.zerowire.') self.network = bind.network self.add_record( '_services._dns-sd._udp', QTYPE.PTR, dnslib.PTR( self.hostname.add('_services._dns-sd._udp'))) self.add_record( 'b._dns-sd._udp', QTYPE.PTR, dnslib.PTR(self.hostname)) self.add_record( 'lb._dns-sd._udp', QTYPE.PTR, dnslib.PTR(self.hostname))
def add_service(self, service: ServiceConfig) -> None: type = DNSLabel(service.type) name = type.add(DNSLabel(service.name)) type_suffixed = self.hostname.add(type) name_suffixed = self.hostname.add(name) port = service.port props_list = [] for key, value in (service.properties or {}).items(): prop = key if isinstance(value, bool): if not value: prop += '=' else: prop += '=' + str(value) if len(prop) > 255: self.logger.error('Property too large to add to txt record %s', key) continue props_list.append(prop) props = ''.join( chr(len(prop)) + prop for prop in props_list ) self.add_record( type, QTYPE.PTR, dnslib.PTR(name_suffixed)) self.add_record( '_services._dns-sd._udp', QTYPE.PTR, dnslib.PTR(type_suffixed)) self.add_record( name, QTYPE.SRV, dnslib.SRV(0, 0, port, self.hostname)) self.add_record( name, QTYPE.TXT, dnslib.TXT(props))
def add_answer_to_query(required_data, query): qtype = query.q.qtype q = query.q # Для каждого типа запроса добавляем интересующий ответ if qtype == dnslib.QTYPE.A: # Добавляем все A адреса for addr in required_data.addresses: query.add_answer( dnslib.RR(rname=q.qname, rclass=q.qclass, rtype=q.qtype, ttl=required_data.remain_ttl(), rdata=dnslib.A(addr))) if qtype == dnslib.QTYPE.AAAA: # Добавляем все AAAA адреса for addr in required_data.addresses: query.add_answer( dnslib.RR(rname=q.qname, rclass=q.qclass, rtype=q.qtype, ttl=required_data.remain_ttl(), rdata=dnslib.AAAA(addr))) if qtype == dnslib.QTYPE.NS: # Добавляем все NS серверы for addr in required_data.servers: query.add_answer( dnslib.RR(rname=q.qname, rclass=q.qclass, rtype=q.qtype, ttl=required_data.remain_ttl(), rdata=dnslib.NS(addr))) if qtype == dnslib.QTYPE.PTR: # Добавляем PTR query.add_answer( dnslib.RR(rname=q.qname, rclass=q.qclass, rtype=q.qtype, ttl=required_data.remain_ttl(), rdata=dnslib.PTR(required_data.name)))
def py3dns(serverip='', serverport=0): class DNSify(str): def __getattr__(self, item): return DNSify(item + '.' + self) def get_lan_ip4(forcelocalhost=False): if forcelocalhost: return '127.0.0.1' s = dnslib.socket.socket(dnslib.socket.AF_INET, dnslib.socket.SOCK_DGRAM) try: s.connect(('10.255.255.255', 0)) IP = s.getsockname()[0] except: IP = '127.0.0.1' finally: s.close() return IP def is_domain_blacklisted(sqname, domain_blacklist): for test_domain in domain_blacklist: if test_domain in sqname: return True return False # Init server settings killcommand = 'stop.py3dns.now' serve_forever = True udp_buffer_size = 1024 server_name = dnslib.socket.getfqdn() server_ip = get_lan_ip4() if serverip: server_ip = serverip reverse_server_ip = '.'.join(reversed( server_ip.split('.'))) + '.in-addr.arpa' server_port = 53 if serverport: server_port = int(serverport) server_protocol = 'UDP' public_dns_resolvers = [ '91.239.100.100', '89.233.43.71', '8.8.8.8', '8.8.4.4' ] # Init simple host cache host_cache = {} host_cache[server_ip] = server_name # Init blacklists use_blacklists = True domain_blacklist = make_domain_blacklist() ipaddr_blacklist = make_ipaddr_blacklist() rpz_domain = DNSify('getthefuckaway.net') rpz_ip4 = '10.20.30.40' rpz_ip6 = '10:20:30:40:50:60:70:80' # Init UDP socket server udpsrv = dnslib.socket.socket(dnslib.socket.AF_INET, dnslib.socket.SOCK_DGRAM) udpsrv.bind((server_ip, server_port)) udpsrv.setblocking(False) # Init external resolvers external_resolver = dns.resolver.Resolver() external_resolver_cache = dns.resolver.Cache(cleaning_interval=600.0) external_resolver.cache = external_resolver_cache external_resolver.nameservers = public_dns_resolvers external_resolver.retry_servfail = False external_resolver.port = 53 ##external_resolver.timeout = 1.0 ##external_resolver.lifetime = 2.0 # Timestamp UTC now = datetime.datetime.utcnow().strftime('%Y-%m-%d %H:%M:%S.%f') # App Header print('+' + ('-' * 71)) print('| PY3DNS v/1.0 by BikerDroid') print('+' + ('-' * 71)) print('| Server :', server_name) print('| Address :', server_ip) print('| Port Used :', server_port) print('| Protocol :', server_protocol) print('| Recv Size :', udp_buffer_size, 'bytes') print('| Solvers :', str(public_dns_resolvers).strip("[]").replace("'", "")) print('+' + ('-' * 71)) print('| Stop PY3DNS by sending "nslookup ' + killcommand + ' ' + server_ip + '"') print('+' + ('-' * 71)) print(now, ': Ready to serve...') # Main Loop while serve_forever: # Clear vars sres = sip4 = sip6 = smx = scname = sns = stxt = sptr = ssoa = sany = hostip = '' # Main: Get client request, add hostip and host name to host_cache try: data, addr = udpsrv.recvfrom(udp_buffer_size) hostip = str(addr[0]) if not hostip in host_cache: host_cache[hostip] = dnslib.socket.getfqdn( str(dnslib.socket.gethostbyaddr(hostip)[0])) now = datetime.datetime.utcnow().strftime( '%Y-%m-%d %H:%M:%S.%f') # UTC except: continue # Client request -> id, qname (domain), qtype (A,AAAA,MX etc) request = dnslib.DNSRecord.parse(data) qid = request.header.id qname = request.q.qname qtype = request.q.qtype slabel = str(qname.label) sqname = str(qname) sqtype = str(dnslib.QTYPE[qtype]) # Rem this line if rpz_domain is to overwrite # blacklisted domains with their real names. sdomain = sqname # Dirty trick to shut down server from commandline: # Syntax : nslookup stop.dns.srv <server_ip> # Example: nslookup stop.dns.srv 127.0.0.1 # Must be before external_resolver.query() if sqname.rstrip('.') == killcommand: serve_forever = False continue # Dirty Reverse Lookup of local server # Allows requesting client to get server_name if qtype == dnslib.QTYPE.PTR: if sqname.rstrip('.') == reverse_server_ip: reply = dnslib.DNSRecord(header=dnslib.DNSHeader(id=qid, qr=1, aa=1, ra=1, rcode=0), q=dnslib.DNSQuestion(sqname, qtype)).reply() reply.add_answer( dnslib.RR(sqname, dnslib.QTYPE.PTR, rdata=dnslib.PTR(server_name), ttl=3600)) udpsrv.sendto(reply.pack(), addr) print(now, ':', sqname, '|', sqtype, '=', qtype, '|', server_name, '|', hostip, '=', host_cache[hostip]) continue # Get DNS record from public_dns_resolvers. # This section can be changed to serve from # own database, stationary files or similar. try: if not sqname.rstrip('.') in domain_blacklist: external_resolver_result = external_resolver.query( sqname.rstrip('.'), sqtype) found = True except: print(now, '> qtype', sqtype, '(' + str(qtype) + ') was not found for', sqname) external_resolver_result = [] sres = sip4 = sip6 = '' found = False if not found: # Create DNSRecord Header reply: rcode = 5 (Query Refused). See RFC2136 for rcode's. reply = dnslib.DNSRecord(header=dnslib.DNSHeader(id=qid, qr=1, aa=1, ra=1, rcode=5), q=dnslib.DNSQuestion(sdomain, qtype)).reply() else: # Create DNSRecord Header reply: rcode = 0 (No Error) reply = dnslib.DNSRecord(header=dnslib.DNSHeader(id=qid, qr=1, aa=1, ra=1, rcode=0), q=dnslib.DNSQuestion(sdomain, qtype)).reply() # Add A record answer for domain and IP # Filter blacklisted IP4/6 addresses. if qtype == dnslib.QTYPE.A: if is_domain_blacklisted( sqname.rstrip('.'), domain_blacklist): # Simple domain blacklist check sres = sip4 = rpz_ip4 reply.add_answer( dnslib.RR(sdomain, dnslib.QTYPE.A, rdata=dnslib.A(sip4), ttl=60)) else: for data in external_resolver_result: sres = sip4 = str(data).strip() if sip4: if sip4 in ipaddr_blacklist: # Simple IP (4+6) blacklist check sres = sip4 = rpz_ip4 reply.add_answer( dnslib.RR(sdomain, dnslib.QTYPE.A, rdata=dnslib.A(sip4), ttl=60)) # Add AAAA record answer for domain and IP # Filter blacklisted IP4/6 addresses. elif qtype == dnslib.QTYPE.AAAA: if is_domain_blacklisted( sqname.rstrip('.'), domain_blacklist): # Simple domain blacklist check sres = sip6 = rpz_ip6 reply.add_answer( dnslib.RR(sdomain, dnslib.QTYPE.AAAA, rdata=dnslib.AAAA(sip6), ttl=60)) else: for data in external_resolver_result: sres = sip6 = str(data).strip() if sip6: if sip6 in ipaddr_blacklist: # Simple IP (4+6) blacklist check sres = sip6 = rpz_ip6 reply.add_answer( dnslib.RR(sdomain, dnslib.QTYPE.AAAA, rdata=dnslib.AAAA(sip6), ttl=60)) # Add NS record answer for domain elif qtype == dnslib.QTYPE.NS: for data in external_resolver_result: sres = sns = str(data).strip() if sns: reply.add_answer( dnslib.RR(sdomain, dnslib.QTYPE.NS, rdata=dnslib.NS(sns), ttl=60)) # Add MX record answer for domain and IP elif qtype == dnslib.QTYPE.MX: for data in external_resolver_result: sres = smx = str(data).strip() if smx: reply.add_answer( dnslib.RR(sdomain, dnslib.QTYPE.MX, rdata=dnslib.MX(smx), ttl=60)) # Add CNAME record answer for domain elif qtype == dnslib.QTYPE.CNAME: for data in external_resolver_result: sres = scname = str(data).strip() if scname: reply.add_answer( dnslib.RR(sdomain, dnslib.QTYPE.CNAME, rdata=dnslib.CNAME(scname), ttl=60)) # Add TXT record answer for domain elif qtype == dnslib.QTYPE.TXT: for data in external_resolver_result: sres = stxt = str(data).strip() if stxt: reply.add_answer( dnslib.RR(sdomain, dnslib.QTYPE.TXT, rdata=dnslib.TXT(stxt), ttl=60)) # Add PTR record answer for domain elif qtype == dnslib.QTYPE.PTR: for data in external_resolver_result: sres = sptr = str(data).strip() if sptr: reply.add_answer( dnslib.RR(sdomain, dnslib.QTYPE.PTR, rdata=dnslib.PTR(sptr), ttl=60)) # Add ANY record answer for domain elif qtype == dnslib.QTYPE.ANY: for data in external_resolver_result: sres = sany = str(data).strip() if sany: reply.add_answer( dnslib.RR(sdomain, dnslib.QTYPE.ANY, rdata=dnslib.ANY(sany), ttl=60)) # Add SOA record answer for domain elif qtype == dnslib.QTYPE.SOA: for data in external_resolver_result: if str(data).strip(): soa_data = str(data).strip().split(' ') soa_mname = soa_data[0] soa_rname = soa_data[1] soa_serial = soa_data[2] soa_refresh = soa_data[3] soa_retry = soa_data[4] soa_expire = soa_data[5] soa_minimum = soa_data[6] soa_time = (int(soa_serial), int(soa_refresh), int(soa_retry), int(soa_expire), int(soa_minimum)) sres = soa_mname + ',' + soa_rname + ',' + soa_serial + ',' + soa_refresh + ',' + soa_retry + ',' + soa_expire + ',' + soa_minimum reply.add_answer( dnslib.RR(sdomain, dnslib.QTYPE.SOA, rdata=dnslib.SOA(soa_mname, soa_rname, soa_time), ttl=60)) else: # Unknown qtype - add CNAME as answer :) reply.add_answer( dnslib.RR(qname, dnslib.QTYPE.CNAME, rdata=dnslib.CNAME(server_name), ttl=60)) # Send DNS reply to client address using UDP udpsrv.sendto(reply.pack(), addr) # Show status in console print(now, ':', sqname, '|', sqtype, '=', qtype, '|', sres, '|', hostip, '=', host_cache[hostip]) #,reply.pack() # Shutting down print(now, ': Shutting down...') udpsrv.shutdown(0) print(now, ': Done.')
def parse_server_config(server_config): import copy _server_config = copy.deepcopy(server_config) dns_servers = _server_config.get('dns_servers', []) for server in dns_servers: # parse url scheme, hostname, port = DNSServerLoader.parse_url(server['url']) server['scheme'] = scheme server['hostname'] = hostname server['port'] = port # parse rules for rule in server['rules']: rtype = rule['type'] if rule['domain-type'] in ('FQDN', 'PREFIX', 'SUFFIX'): rule['domain'] = DNSLabel(rule['domain']) if rtype == 'FORWARD': _scheme, _hostname, _port = DNSServerLoader.parse_url(rule['value']) rule['pvalue'] = { 'scheme': _scheme, 'hostname': _hostname, 'port': _port, 'url': _scheme + '://' + _hostname + ':' + str(_port) } elif rtype in ('A', 'CNAME', 'MX', 'NS', 'PTR', 'AAAA', 'SRV', 'SOA'): if isinstance(rule['value'], six.string_types): rule['value'] = [rule['value']] if rtype == 'A': rule['pvalue'] = [dnslib.A(item) for item in rule['value']] elif rtype == 'CNAME': rule['pvalue'] = [dnslib.CNAME(DNSLabel(item)) for item in rule['value']] elif rtype == 'MX': rule['pvalue'] = [dnslib.MX(DNSLabel(item)) for item in rule['value']] elif rtype == 'NS': rule['pvalue'] = [dnslib.NS(DNSLabel(item)) for item in rule['value']] elif rtype == 'PTR': rule['pvalue'] = [dnslib.PTR(DNSLabel(item)) for item in rule['value']] elif rtype == 'AAAA': rule['pvalue'] = [dnslib.AAAA(item) for item in rule['value']] elif rtype == 'SRV': srv_arr = [] for item in rule['value']: item_arr = item.split(' ') srv_arr.append(dnslib.SRV( priority=num.safe_int(item_arr[0]), weight=num.safe_int(item_arr[1]), port=num.safe_int(item_arr[2]), target=item_arr[3])) rule['pvalue'] = srv_arr elif rtype == 'SOA': soa_arr = [] for item in rule['value']: item_arr = item.split(' ') soa_arr.append(dnslib.SOA( mname=DNSLabel(item_arr[0]), rname=DNSLabel(item_arr[1]), times=(num.safe_int(t) for t in item_arr[2:]) # serial, refresh, retry, expire, minimun )) rule['pvalue'] = soa_arr return dns_servers