class ArcTestResolver(object): def __init__(self, records, port=8053, verbose=False): self.records = records self.port = port self.verbose = verbose def __enter__(self): zones = [] for (domain, txt) in self.records.items(): n = 255 frags = [("'" + txt[i:i+n] + "'") for i in range(0, len(txt), n)] zones.append(domain + " IN TXT " + " ".join(frags)) resolver = ZoneResolver("\n".join(zones)) if self.verbose: logger = DNSLogger() else: logger = NullLogger() self.server = DNSServer(resolver, port=self.port, logger=logger) self.server.start_thread() def __exit__(self, type, value, traceback): self.server.stop()
class MyDNSServer: server = None @classmethod def start(self, address): my_resolver = MyResolver(address) logger = DNSLogger(prefix=False) self.server = DNSServer(my_resolver, port=10053, address=str(address), logger=logger) self.server.start_thread() print("DNS server is UP") # while server.isAlive(): # time.sleep(1) @classmethod def shut_down(self): print("shutting down the DNS server..\n") self.server.stop()
def http_01_challenge(self): self.logger.info("Performing http-01 challenge") for challenge in self.acme_challenges: token = challenge["token"] chall_url = challenge["url"] key_auth = crypto.get_key_authorization(token, self.jwk) zone = ". 60 IN A " + self.record_addr resolver = DnsResolver(zone) dns_server = DNSServer(resolver, address=self.record_addr, port=10053) dns_server.start_thread() challenge_server = ChallengeServer(token, key_auth, self.record_addr) challenge_server.start() r_dict = util.acme_server_request(self, chall_url, {}).json() self.logger.debug(r_dict) _dict = util.poll_acme_server(self, challenge['auth_url'], "", "valid") self.logger.debug(r_dict) challenge_server.terminate() challenge_server.join() dns_server.stop() return
def dns_01_challenge(self): self.logger.info("Performing dns-01 challenge") for challenge in self.acme_challenges: token = challenge["token"] chall_url = challenge["url"] key_auth = crypto.get_key_authorization(token, self.jwk) hashed_key_auth = hashlib.sha256(key_auth.encode('utf-8')).digest() hashed_key_auth = util.to_base64(hashed_key_auth) zone = ". 300 IN TXT " + hashed_key_auth resolver = DnsResolver(zone) dns_server = DNSServer(resolver, address=self.record_addr, port=10053) dns_server.start_thread() r_dict = util.acme_server_request(self, chall_url, {}).json() self.logger.debug(r_dict) r_dict = util.poll_acme_server(self, challenge['auth_url'], "", "valid") self.logger.debug(r_dict) dns_server.stop() return
class CatlogResolver(BaseResolver): def __init__(self): self.txtMap = {} self.udp_server = None def setTxt(self, domain: str, value: str) -> None: self.txtMap[domain.lower()] = value def clearTxt(self, domain: str) -> None: del self.txtMap[domain.lower()] def resolve(self, request, handler): """ Respond to DNS request - parameters are request packet & handler. Method is expected to return DNS response """ reply = request.reply() qname = request.q.qname.idna()[:-1].lower() qtype = QTYPE[request.q.qtype] if qtype == 'TXT' and qname in self.txtMap: reply.add_answer(*RR.fromZone('{} IN TXT "{}"'.format( qname, self.txtMap[qname]))) else: reply.header.rcode = RCODE.NXDOMAIN return reply def start(self): self.udp_server = DNSServer(self, port=53, logger=SilentLogger()) self.udp_server.start_thread() def stop(self): self.udp_server.stop()
class DnsSrvDiscoveryTest(TestCase): num_nodes = 3 def setUp(self): zone_file = ''' crate.internal. 600 IN SOA localhost localhost ( 2007120710 1d 2h 4w 1h ) crate.internal. 400 IN NS localhost crate.internal. 600 IN A 127.0.0.1''' transport_ports = [bind_port() for _ in range(self.num_nodes)] for port in transport_ports: zone_file += ''' _test._srv.crate.internal. 600 IN SRV 1 10 {port} 127.0.0.1.'''.format( port=port) dns_port = bind_port() self.dns_server = DNSServer(ZoneResolver(zone_file), port=dns_port) self.dns_server.start_thread() self.nodes = nodes = [] for i in range(self.num_nodes): settings = { 'node.name': f'node-{i}', 'cluster.name': 'crate-dns-discovery', 'psql.port': 0, 'transport.tcp.port': transport_ports[i], "discovery.seed_providers": "srv", "discovery.srv.query": "_test._srv.crate.internal.", "discovery.srv.resolver": "127.0.0.1:" + str(dns_port) } if i == 0: settings['cluster.initial_master_nodes'] = f'node-{i}' node = CrateNode(crate_dir=crate_path(), version=(4, 0, 0), settings=settings, env={ 'CRATE_HEAP_SIZE': '256M', 'CRATE_JAVA_OPTS': '-Dio.netty.leakDetection.level=paranoid', }) node.start() nodes.append(node) def tearDown(self): for node in self.nodes: node.stop() self.dns_server.server.server_close() self.dns_server.stop() def test_nodes_discover_each_other(self): with connect(self.nodes[0].http_url) as conn: c = conn.cursor() c.execute('''select count(*) from sys.nodes''') result = c.fetchone() self.assertEqual(result[0], self.num_nodes, 'Nodes must be able to join')
class DnsServer: def __init__(self, host: str, record: str, url: str): resolver = FixedResolver(record, url) self._server = DNSServer(resolver, port=10053, address=host) def start(self): self._server.start_thread() def shutDown(self): self._server.stop()
def start(self): server = DNSServer(resolver=HTTPResolver(query=import_query(), cache=SimpleCache()), address=ConfigParse.listen, port=ConfigParse.port, logger=DNSLogger()) server.start_thread() while self.running: time.sleep(5) server.stop()
class DnsSrvDiscoveryTest(TestCase): num_nodes = 3 def setUp(self): zone_file = ''' crate.internal. 600 IN SOA localhost localhost ( 2007120710 1d 2h 4w 1h ) crate.internal. 400 IN NS localhost crate.internal. 600 IN A 127.0.0.1''' transport_ports = [bind_port() for _ in range(self.num_nodes)] for port in transport_ports: zone_file += ''' _test._srv.crate.internal. 600 IN SRV 1 10 {port} 127.0.0.1.'''.format(port=port) dns_port = bind_port() self.dns_server = DNSServer(ZoneResolver(zone_file), port=dns_port) self.dns_server.start_thread() self.nodes = nodes = [] for i in range(self.num_nodes): settings = { 'node.name': f'node-{i}', 'cluster.name': 'crate-dns-discovery', 'psql.port': 0, 'transport.tcp.port': transport_ports[i], "discovery.seed_providers": "srv", "discovery.srv.query": "_test._srv.crate.internal.", "discovery.srv.resolver": "127.0.0.1:" + str(dns_port) } if i is 0: settings['cluster.initial_master_nodes'] = f'node-{i}' node = CrateNode( crate_dir=crate_path(), version=(4, 0, 0), settings=settings, env={ 'CRATE_HEAP_SIZE': '256M' } ) node.start() nodes.append(node) def tearDown(self): for node in self.nodes: node.stop() self.dns_server.server.server_close() self.dns_server.stop() def test_nodes_discover_each_other(self): with connect(self.nodes[0].http_url) as conn: c = conn.cursor() c.execute('''select count(*) from sys.nodes''') result = c.fetchone() self.assertEqual(result[0], self.num_nodes, 'Nodes must be able to join')
def main(): resolver = SocksResolver(REAL_SERVER, 53) logger = DNSLogger("request,reply,truncated,error", False) server = DNSServer( resolver, port=53, address=LISTEN_ADDR, logger=logger, ) try: server.start() except KeyboardInterrupt: server.stop()
class DNS(object): def __init__(self): self.default_ip = get_default_ip() self.resolver = None self.server = None self.base_zone_data = None self.reset() def wait_for_query(self, record_type, record_name, timeout): self.resolver.wait_for_query(record_type, record_name, timeout) def load_zone(self, api_version, api_protocol, zone_name, port_base): zone_file = open(zone_name).read() template = Template(zone_file) zone_data = template.render(ip_address=self.default_ip, api_ver=api_version, api_proto=api_protocol, domain=CONFIG.DNS_DOMAIN, port_base=port_base) self.resolver = WatchingResolver(self.base_zone_data + zone_data) self.stop() print(" * Loading DNS zone file '{}' with api_ver={}".format( zone_name, api_version)) self.start() def reset(self): zone_file = open("test_data/core/dns_base.zone").read() template = Template(zone_file) self.base_zone_data = template.render(ip_address=self.default_ip, domain=CONFIG.DNS_DOMAIN) self.resolver = WatchingResolver(self.base_zone_data) self.stop() print(" * Loading DNS zone base file") self.start() def start(self): if not self.server: print(" * Starting DNS server on {}:53".format(self.default_ip)) try: self.server = DNSServer(self.resolver, port=53, address=self.default_ip) self.server.start_thread() except Exception as e: print( " * ERROR: Unable to bind to port 53. DNS server could not start: {}" .format(e)) def stop(self): if self.server: print(" * Stopping DNS server on {}:53".format(self.default_ip)) self.server.stop() self.server = None
def main(): try: resolver = ZoneResolver(ZONE, True) logger = RedisLogger() _dns_logger.info(ZONE) _dns_logger.info("Starting Dns Server (*:53) [UDP]") dns_server = DNSServer(resolver, port=53, address='', logger=logger) dns_server.start() except KeyboardInterrupt: _dns_logger.info("Shutting Down Dns Server (*:53) [UDP]") dns_server.stop()
class DNSServerThread(QThread): """ Simple DNS server UDP resolver """ sendRequests = pyqtSignal(object) # I'll use this object in future feature def __init__(self, conf): super(DNSServerThread, self).__init__(parent=None) self.resolver = None self.conf = conf def run(self): port = int(os.getenv("PORT", 53)) upstream = os.getenv("UPSTREAM", "8.8.8.8") zone_file = Path(C.DNSHOSTS) self.logger_dns = LocalDNSLogger(self.sendRequests) self.resolver = Resolver(upstream, zone_file, self.sendRequests) self.udp_server = DNSServer(self.resolver, port=port, logger=self.logger_dns) self.tcp_server = DNSServer(self.resolver, port=port, logger=self.logger_dns, tcp=True) print( display_messages("starting {}".format(self.objectName()), info=True)) # logger.info('starting DNS server on port %d, upstream DNS server "%s"', port, upstream) self.udp_server.start_thread() self.tcp_server.start_thread() try: while self.udp_server.isAlive(): sleep(1) except KeyboardInterrupt: pass def getpid(self): """ return the pid of current process in background""" return "thread" def getID(self): """ return the name of process in background""" return self.objectName() def stop(self): self.udp_server.stop() self.tcp_server.stop() print( display_messages("thread {} successfully stopped".format( self.objectName()), info=True))
def main(): num_nodes = 3 node0_http_port = bind_port() dns_port = bind_port() transport_ports = [] zone_file = ''' crate.internal. 600 IN SOA localhost localhost ( 2007120710 1d 2h 4w 1h ) crate.internal. 400 IN NS localhost crate.internal. 600 IN A 127.0.0.1''' for i in range(0, num_nodes): port = bind_port() transport_ports.append(port) zone_file += ''' _test._srv.crate.internal. 600 IN SRV 1 10 {port} 127.0.0.1.'''.format( port=port) dns_server = DNSServer(ZoneResolver(zone_file), port=dns_port) dns_server.start_thread() crate_layers = [] for i in range(0, num_nodes): crate_layer = CrateLayer( 'node-' + str(i), cluster_name='crate-dns-discovery', crate_home=crate_path(), port=node0_http_port if i == 0 else bind_port(), transport_port=transport_ports[i], settings={ 'psql.port': bind_port(), "discovery.zen.hosts_provider": "srv", "discovery.srv.query": "_test._srv.crate.internal.", "discovery.srv.resolver": "127.0.0.1:" + str(dns_port) }) crate_layers.append(crate_layer) crate_layer.start() try: conn = connect('localhost:{}'.format(node0_http_port)) c = conn.cursor() c.execute('''select count() from sys.nodes''') result = c.fetchone() if result[0] != num_nodes: raise AssertionError( "Nodes could not join, expected number of nodes: " + str(num_nodes) + ", found: " + str(result[0])) finally: for crate_layer in crate_layers: crate_layer.stop() dns_server.stop()
def run_dns_proxy(self): resolver = HTTPSResolver() logger = DNSLogger() server = DNSServer(resolver, port=DNS_PORT, address='localhost', logger=logger) server.start_thread() while self.is_running: # this just keeps the thing alive... time.sleep(5) server.stop()
class DNS(object): def __init__(self): self.default_ip = get_default_ip() self.resolver = None self.server = None self.base_zone_data = None self.reset() def load_zone(self, api_version, api_protocol): zone_file = open("test_data/IS0401/dns_records.zone").read() template = Template(zone_file) zone_data = template.render(ip_address=self.default_ip, api_ver=api_version, api_proto=api_protocol, domain=DNS_DOMAIN) self.resolver = ZoneResolver(self.base_zone_data + zone_data) self.stop() print(" * Loading DNS zone file with api_ver={}".format(api_version)) self.start() def reset(self): zone_file = open("test_data/IS0401/dns_base.zone").read() template = Template(zone_file) self.base_zone_data = template.render(ip_address=self.default_ip, domain=DNS_DOMAIN) self.resolver = ZoneResolver(self.base_zone_data) self.stop() print(" * Loading DNS zone base file") self.start() def start(self): if not self.server: print(" * Starting DNS server on {}:53".format(self.default_ip)) try: self.server = DNSServer(self.resolver, port=53, address=self.default_ip) self.server.start_thread() except Exception as e: print( " * ERROR: Unable to bind to port 53. DNS server could not start: {}" .format(e)) def stop(self): if self.server: print(" * Stopping DNS server on {}:53".format(self.default_ip)) self.server.stop() self.server = None
class Authenticator(dns_common.DNSAuthenticator): """Standalone DNS Authenticator This Authenticator uses a standalone DNS server to fulfill a dns-01 challenge. """ description = ('Obtain certificates using an integrated DNS server') def __init__(self, *args, **kwargs): super(Authenticator, self).__init__(*args, **kwargs) self.resolver = None self.udp_server = None @classmethod def add_parser_arguments(cls, add): # pylint: disable=arguments-differ super(Authenticator, cls).add_parser_arguments(add, default_propagation_seconds=0) add('address', help='IP address to bind to.', default='0.0.0.0') def _setup_credentials(self): return def more_info(self): # pylint: disable=missing-docstring,no-self-use return 'This plugin uses a standalone DNS server to respond to a dns-01 challenge.' def _perform(self, domain, validation_name, validation): if self.resolver is None: self.resolver = _AcmeResolver() self.resolver.addToken(validation) if self.udp_server is None: try: self.udp_server = DNSServer(self.resolver, port=53, address=self.conf('address'), logger=dnsLogger) self.udp_server.start_thread() except Exception as e: raise errors.PluginError( 'Error starting DNS server: {0}'.format(e)) def _cleanup(self, domain, validation_name, validation): if self.udp_server: self.udp_server.stop()
def main(): """ 主函数 :return: """ zone = f"*.{DOMAIN}. IN A {NS_SERVER}" resolver = ZoneResolver(zone, True) dns_logger = MyLogger() logger.info("启动域名解析 %s:%d" % ("0.0.0.0", 53)) udp_server = DNSServer(resolver, port=53, address="0.0.0.0", logger=dns_logger) try: udp_server.start() except KeyboardInterrupt: logger.info("正在关闭域名解析……") udp_server.stop() logger.info("关闭域名解析完成")
def runDNSProxy(self): resolver = CustomDNSResolver() logger = DNSLogger() server = DNSServer(resolver, port=DNS_PORT, address=DNS_SERVER_IPV4_ADDRESS, logger=logger) server.start_thread() # Usage self.printUsage() while True: inputOption = input("[Input Number] ").strip() try: inputOption = inputOption.strip().lower() except ValueError: inputOption = 0 if 'q' == inputOption: break elif '1' == inputOption: resolver.enableCustomDNS(True) print("Custom DNS Server turned on.") elif '2' == inputOption: resolver.enableCustomDNS(False) print("Custom DNS Server turned off.") elif 'p' == inputOption: # Print Custom DNS Status print(" Feature #1 - Custom DNS Server turned ", end='') if resolver.isCustomDNSEnabled: print("on.") else: print("off.") print("") else: self.printUsage() server.stop()
class DNS(object): def __init__(self): default_gw_interface = netifaces.gateways()['default'][netifaces.AF_INET][1] default_ip = netifaces.ifaddresses(default_gw_interface)[netifaces.AF_INET][0]['addr'] self.default_ip = default_ip self.resolver = None self.server = None self.base_zone_data = None self.reset() def load_zone(self, api_version): zone_file = open("test_data/IS0401/dns_records.zone").read() template = Template(zone_file) zone_data = template.render(ip_address=self.default_ip, api_ver=api_version) self.resolver = ZoneResolver(self.base_zone_data + zone_data) self.stop() self.start() def reset(self): zone_file = open("test_data/IS0401/dns_base.zone").read() template = Template(zone_file) self.base_zone_data = template.render(ip_address=self.default_ip) self.resolver = ZoneResolver(self.base_zone_data) self.stop() self.start() def start(self): if not self.server: print(" * Starting DNS server on {}:53".format(self.default_ip)) try: self.server = DNSServer(self.resolver, port=53, address=self.default_ip) self.server.start_thread() except Exception as e: print(" * ERROR: Unable to bind to port 53. DNS server could not start: {}".format(e)) def stop(self): if self.server: self.server.stop() self.server = None
def handle(self, *args, **options): # map django command verbosity to logging options logger = DNSLogger(log={ '0': '-request,-reply,-truncated,-error', '1': '', '2': '+data', '3': '+recv,+send,+data' }[options['verbosity']]) udp_server = DNSServer( resolver=InterceptingResolver(), address=options['address'], port=options['port'], logger=logger ) udp_server.start_thread() try: while udp_server.isAlive(): time.sleep(1) except KeyboardInterrupt: udp_server.stop()
class FakeDNSServer: # pylint: disable=too-many-instance-attributes # pylint: disable=too-many-arguments def __init__(self, listen_addr=const.DEFAULT_LISTEN_ADDR, listen_port=const.DEFAULT_LISTEN_PORT, *, record_life=const.DEFAULT_CACHE_DURATION, subnet=const.DEFAULT_SUBNET, db_path=const.DEFAULT_DB_URI, remove_records=False, logger=None): self.logger = logger or DeliriumDNSLogger() self._addr = listen_addr self._port = listen_port self._resolver = DatabaseResolver(subnet, db_path=db_path, duration=record_life, remove=remove_records, logger=self.logger) self._dns_server = DNSServer(self._resolver, self._addr, self._port, logger=self.logger) @property def addr(self): return self._addr @property def port(self): return self._port @property def duration(self): return self._resolver.duration @duration.setter def duration(self, value): self.logger.debug('Setting cache duration to %s', value) self._resolver.duration = value @property def subnet(self): return self._resolver.subnet @subnet.setter def subnet(self, value): self.logger.debug('Setting cache subnet to %s', value) self._resolver.subnet = value def is_alive(self): return self._dns_server.isAlive() def start(self): self.logger.info('Starting Delirium DNS Server') self._dns_server.start() def start_thread(self): self._dns_server.start_thread() def stop(self): self.logger.info('Stopping Delerium DNS Server') self._resolver.close() self._dns_server.stop()
def main(): global OPTIONS, ARGS parser = OptionParser() parser.add_option("-b", "--bind", dest = "bind", \ type = "string", default = "127.0.0.7:53", \ help = "set bind address/port to IP[:PORT]. " \ "Default value is `127.0.0.7:53'.", \ metavar = "IP[:PORT]") parser.add_option("-t", "--timeout", dest = "timeout", \ type = "int", default = "5", \ help = "set DNS resolving timeout to SECONDS", \ metavar = "SECONDS") parser.add_option("-r", "--retry", dest = "retry", \ type = "int", default = "3", \ help = "set retry count to COUNT", metavar = "COUNT") parser.add_option("-i", "--invalid-resolve", dest = "invalid_resolve", \ type = "string", default = r"10\.10\.34\.\d+", \ help = "REGEX is a an IP address or a regular " \ "expression that will not be prefered on DNS " \ "resolving. Default value is `10.10.34.\\d+'.", \ metavar = "REGEX") parser.add_option("--request-bind", dest = "request_bind", \ type = "string", default = "", \ help = "bind to IP address before sending DNS " \ "requests.", metavar = "IP") parser.add_option("-q", "--quiet", dest = "quiet", \ action = "store_true", default = False, \ help = "do not print any log") parser.set_usage("%s [OPTION]... DNS_SERVER[:PORT]..." % \ sys.argv[0]) parser.set_description(__doc__) OPTIONS, ARGS = parser.parse_args() if len(ARGS) < 1: parser.print_help() exit(1) def get_address_port(arg): address_port = arg if ":" in arg else "%s:53" % arg address_port = address_port.split(":") return address_port[0], int(address_port[1]) bind_address, bind_port = get_address_port(OPTIONS.bind) dns_servers = [get_address_port(arg) for arg in ARGS] resolver = ProxyResolver(dns_servers, request_bind_address = \ (OPTIONS.request_bind or None)) logger = DNSLogger("request,reply,truncated,error", False) \ if not OPTIONS.quiet else \ DNSLogger("-request,-reply,-truncated,-error,-log_recv," \ "-log_send,-log_data", False) udp_server = DNSServer(resolver, port = bind_port, address = bind_address, logger = logger if not OPTIONS.quiet else None, handler = DNSHandler, server = UDPServer) udp_server.start_thread() try: while udp_server.isAlive(): time.sleep(1) except KeyboardInterrupt: if not OPTIONS.quiet: print("Shutting down the server with user request...") udp_server.stop() exit(0)
class ParentalControls(BaseResolver): """ Intercepting resolver Proxy requests to upstream server optionally intercepting requests matching local records """ def __init__(self): self.log = logging.getLogger('dnspc.dnspc.ParentalControls') self.rules = [] self.hosts = [] self.LOCAL_IP = settings.DNS['LOCAL_IP'] self.LOCAL_PORT = settings.DNS['LOCAL_PORT'] self.UP_IP = settings.DNS['UP_IP'] self.UP_PORT = settings.DNS['UP_PORT'] self.TCP = settings.DNS['TCP'] self.TTL = parse_time(settings.DNS['TTL']) self.store ={ 'rules': settings.DATA['RULES'], 'hosts': settings.DATA['HOSTS'] } self.load_rules() self.load_hosts() ## Rules def load_rules(self): stored_rules = self.store['rules'].loadRecords() uids = [r['_uid'] for r in self.rules] for sr in stored_rules: if sr['_uid'] in uids: continue rule = PCRule(**sr) self.rules.append(rule) self.log.debug("WTF:rules: {}".format(self.rules)) def update_rule(self,rule): uid = rule._uid idxs = [i for i,c in enumerate(self.rules) if c._uid == uid] if len(idxs) == 0: self.rules.append(rule) else: self.rules[idxs[0]] = rule return rule def save_rule(self,d=None,**kwargs): #print "save_rule({})".format(kwargs) ## Remove angularjs artifacts: kwargs.pop('$$hashKey',None) saved_rule = self.store['rules'].editRecord(kwargs) self.log.debug("WTF: saved_rule: {}".format(saved_rule)) rule = PCRule(**saved_rule) ## Not sure if I should update the rule, or just reload from disk. self.update_rule(rule) return rule def del_rule(self,uid): ''' del_rule(uid) returns: None: uid did not appear in list. True: success False: failure ''' #print "del_rule({})".format(uid) #pp([x._serialize() for x in self.rules]) self.store['rules'].deleteRecord({'_uid':uid}) if uid not in [x._uid for x in self.rules]: return None self.rules = [x for x in self.rules if x._uid != uid] if uid in [x._uid for x in self.rules]: return False return True def get_rules(self): return self.rules def get_matching_rules(self,src_ip,dst_str): rs = [ r for r in self.rules if r.is_match(src_ip,dst_str) ] return rs ## Hosts def load_hosts(self): stored_hosts = self.store['hosts'].loadRecords() uids = [r['_uid'] for r in self.hosts] for sr in stored_hosts: if sr['_uid'] in uids: continue rule = PCHost(**sr) self.hosts.append(rule) def update_host(self,host): uid = host._uid idxs = [i for i,c in enumerate(self.hosts) if c._uid == uid] if len(idxs) == 0: self.hosts.append(host) else: self.hosts[idxs[0]] = host return host def save_host(self,d=None,**kwargs): #print "save_host({})".format(kwargs) ## Key generated by filestore. ## Can't risk overlap. #key = self._genkey(self.hosts) #print "WTF: Created key:",key kwargs.pop('$$hashKey',None) saved_host = self.store['hosts'].editRecord(kwargs) self.log.debug("WTF: saved_host: {}".format(saved_host)) host = PCHost(**saved_host) self.update_host(host) #pp(self.hosts) return host def del_host(self,uid): ''' del_host(uid) returns: None: uid did not appear in list. True: success False: failure ''' #print "del_host({})".format(uid) #pp([x._serialize() for x in self.hosts]) self.store['hosts'].deleteRecord({'_uid':uid}) if uid not in [x._uid for x in self.hosts]: return None self.hosts = [x for x in self.hosts if x._uid != uid] if uid in [x._uid for x in self.hosts]: return False return True def get_hosts(self): return self.hosts def _genkey(self,st): #print "WTF: _genkey()" key = int(time.strftime('%Y%U%w000')) #print "WTF: My key:",key keys = [r._uid for r in st] #print "WTF: keys:",keys #while len([1 for r in st if int(r['_uid']) == key]) > 0: while key in keys: key = key + 1 return key ## DNS Server Methods def start(self): handler = DNSHandler # log options: "recv,send,request,reply,truncated,error,data" # log defaults: "request,reply,truncated,error" # It's just too much stuff! logger = DNSLogger("truncated,error",True) self.log.info("Starting UDP server") if 'udp_server' not in dir(self): self.udp_server = DNSServer(self, port=self.LOCAL_PORT, address=self.LOCAL_IP, logger=logger, handler=handler) self.udp_server.start_thread() if self.TCP: self.log.info("Starting TCP server") if 'tcp_server' not in dir(self): self.tcp_server = DNSServer(self, port=self.LOCAL_PORT, address=self.LOCAL_IP, tcp=True, logger=logger, handler=handler) self.tcp_server.start_thread() def stop(self): self.log.debug( dir(self) ) if 'udp_server' in dir(self): self.log.debug( " Stopping UDP server." ) self.udp_server.stop() if 'tcp_server' in dir(self) and self.TCP: self.log.debug( " Stopping TCP server." ) self.tcp_server.stop() def resolve(self,request,handler): client_ip = handler.client_address[0] #print "Request from IP: {}".format(client_ip) qname = request.q.qname qtype = QTYPE[request.q.qtype] reply = request.reply() self.log.debug("{} request for {} by {}".format(qtype,qname,client_ip)) #print "query: {}".format(qname) #print "query: {}".format(qname.matchGlob("*.yahoo.com")) # Try to resolve locally unless on skip list rules = self.get_matching_rules(client_ip,qname) self.log.debug("Matched rules: {}".format(rules)) if any(rules): ## Collecting info on match for logging match_time = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S') match_name = client_ip match_hosts = [h.name for h in self.hosts if h.ip == client_ip] if any(match_hosts): match_name = ",".join(match_hosts) for rule in rules: if rule.action == 'monitor': monitor.info({'time':match_time,'match_name':match_name,'client_ip':client_ip,'qname':str(qname)}) if rule.action == 'redirect': self.log.debug( "[{}] REDIRECT {}-->{} to {}".format(match_time,match_name,qname,rule.redirect) ) redir = rule.redirect reply.add_answer(*RR.fromZone("{} 3600 IN A {}".format(qname,redir))) return reply if rule.action == 'block': self.log.debug( "[{}] BLOCKED {}({})-->{}".format(match_time,match_name,client_ip,qname) ) return reply if rule.action == 'allow': self.log.debug( "[{}] ALLOWED {}({})-->{}".format(match_time,match_name,client_ip,qname) ) ## If no match or action == 'allow', then proxy the request to IP_UP if handler.protocol == 'udp': proxy_r = request.send(self.UP_IP,self.UP_PORT) else: proxy_r = request.send(self.UP_IP,self.UP_PORT,tcp=True) reply = DNSRecord.parse(proxy_r) return reply
class DnsServer(BaseCommand): name = "dns-server" aliases = ["dns"] description = "run dns server" add_log_level = True add_debug = True def __init__(self, *args, **kwargs): self.api_client = None self.resolver = None self.udp_server = None self.tcp_server = None super().__init__(*args, **kwargs) @classmethod def parser(cls, parser): parser.add_argument( "-a", "--api-url", default="http://127.0.0.1:8080", action="store", help="api url", ) parser.add_argument("-t", "--api-token", action="store", help="api token") parser.add_argument("-p", "--port", action="store", type=int, default=53, help="listen port") parser.add_argument("-l", "--listen", action="store", default="127.0.0.1", help="bind address") parser.add_argument("--no-sync", action="store_true", help="sync api token back to database") parser.add_argument( "--no-ssl-verify", action="store_true", help="skip ssl verify in the dns server's api client", ) parser.add_argument( "-r", "--refresh-ttl", type=int, default=3600, action="store", help="time to wait before polling for new records", ) return parser async def run(self): # TODO: thread issues? verify_ssl = True if bool(self.option("no_ssl_verify")): verify_ssl = False self.api_client = ApiClient(self.get_api_url(), self.get_api_token(), verify_ssl=verify_ssl) if not self.api_client.wait_for_up(): logger.critical( "run@dns_server.py - Could not connect to api. quitting") self.exit(1) if self.option("no_sync"): logger.info("run@dns_server.py - Skipping syncing api token") else: self.api_client.sync() self.boot() self.start_servers() try: count = 0 while self.udp_server.isAlive(): if count > 0 and count % self.option("refresh_ttl") == 0: if self.api_client.refresh_zones_if_needed(): logger.critical( "run@dns_server.py - API Client found new or changed zones. Stopping servers..." ) # TODO: figure out why "stop" does not release the address self.stop_servers() sleep(1) stop_count = 0 logger.critical( "run@dns_server.py - Waiting for UDP Server to stop..." ) while self.udp_server.thread and self.udp_server.isAlive( ): if stop_count > 30: logger.critical( "run@dns_server.py - UDP Server did not stop while reloading zones" ) raise Exception( "run@dns_server.py - UDP Server threads went rogue during zone reload" ) logger.info( "run@dns_server.py - Waiting for DNS Server to stop before reloading zones" ) stop_count = stop_count + 1 sleep(1) stop_count = 0 logger.critical( "run@dns_server.py - Waiting for TCP Server to stop..." ) while self.tcp_server.thread and self.tcp_server.isAlive( ): if stop_count > 30: logger.critical( "run@dns_server.py - TCP Server did not stop while reloading zones" ) raise Exception( "run@dns_server.py - TCP Server threads went rogue during zone reload" ) logger.info( "run@dns_server.py - Waiting for DNS Server to stop before reloading zones" ) stop_count = stop_count + 1 sleep(1) logger.critical( "run@dns_server.py - Rebooting server with fresh zones..." ) self.boot() self.start_servers() count = count + 1 sleep(1) except KeyboardInterrupt: pass def get_api_url(self): if os.environ.get("API_URL", None): return os.environ.get("API_URL") return self.option("api_url") def get_api_token(self): if os.environ.get("API_TOKEN", None): return os.environ.get("API_TOKEN") if self.option("api_token", None): return self.option("api_token") logger.critical("api token required") self.exit(1) def get_port(self): return self.option("port") def get_listen(self): return self.option("listen") def boot(self): port = self.get_port() listen = self.get_listen() self.resolver = Resolver(self.api_client) self.udp_server = DNSServer( self.resolver, address=listen, port=port, handler=DNSHandler, logger=DNSLogger(self.api_client), ) self.tcp_server = DNSServer( self.resolver, address=listen, port=port, tcp=True, handler=DNSHandler, logger=DNSLogger(self.api_client), ) logger.info("starting DNS server on port %d", port) def start_servers(self): self.udp_server.start_thread() self.tcp_server.start_thread() def stop_servers(self): self.udp_server.stop() self.udp_server.server.socket.close() self.udp_server.server.server_close() self.tcp_server.stop() self.tcp_server.server.socket.close() self.tcp_server.server.server_close()
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() try: while udp_server.isAlive(): time.sleep(1) except KeyboardInterrupt: pass finally: udp_server.stop() if args.tcp: tcp_server.stop()
class DNS(object): def __init__(self): self.default_ip = get_default_ip() self.resolver = None self.server = None self.base_zone_data = None self.reset() def wait_for_query(self, record_type, record_name, timeout): self.resolver.wait_for_query(record_type, record_name, timeout) def load_zone(self, api_version, api_protocol, api_authorization, zone_name, port_base): zone_file = open(zone_name).read() template = Template(zone_file) zone_data = template.render(ip_address=self.default_ip, api_ver=api_version, api_proto=api_protocol, api_auth=str(api_authorization).lower(), domain=CONFIG.DNS_DOMAIN, port_base=port_base) self.resolver = WatchingResolver(self.base_zone_data + zone_data) self.stop() print(" * Loading DNS zone file '{}' with api_ver={}".format( zone_name, api_version)) self.start() def reset(self): zone_file = open("test_data/core/dns_base.zone").read() template = Template(zone_file) extra_services = {} if CONFIG.ENABLE_AUTH: auth_proto = "https" if CONFIG.ENABLE_HTTPS else "http" extra_services["auth"] = { "host": CONFIG.AUTH_SERVER_HOSTNAME, "ip": CONFIG.AUTH_SERVER_IP, "port": CONFIG.AUTH_SERVER_PORT, "txt": ["api_ver=v1.0", "api_proto={}".format(auth_proto), "pri=0"] } if CONFIG.ENABLE_MQTT_BROKER: extra_services["mqtt"] = { "host": CONFIG.MQTT_BROKER_HOSTNAME, "ip": CONFIG.MQTT_BROKER_IP, "port": CONFIG.MQTT_BROKER_PORT, "txt": ["api_proto=mqtt", "api_auth=false"] } self.base_zone_data = template.render(ip_address=self.default_ip, domain=CONFIG.DNS_DOMAIN, extra_services=extra_services) self.resolver = WatchingResolver(self.base_zone_data) self.stop() print(" * Loading DNS zone base file") self.start() def start(self): if not self.server: print(" * Starting DNS server on {}:53".format(self.default_ip)) try: self.server = DNSServer(self.resolver, port=53, address=self.default_ip) self.server.start_thread() except Exception as e: print( " * ERROR: Unable to bind to port 53. DNS server could not start: {}" .format(e)) def stop(self): if self.server: print(" * Stopping DNS server on {}:53".format(self.default_ip)) self.server.stop() self.server = None
except Exception as e: # Needs sudo for 53 if "Permission denied" in e: print("Permission denied: use sudo for privileged ports such as 53") else: print("Error: {}".format(e)) exit() print("{} Server listening for {} on port {}, CTRL+C to shut down".format( strftime("%Y-%m-%d %H:%M:%S"), args.host, args.port)) sys.stdout.flush() # Server will maintain open connection until interrupted by Ctrl-C or SIGTERM try: server.start() while server.isAlive(): sleep(1) # Shut down on keyboard interrupt except KeyboardInterrupt: server.stop() print("{} Server exiting...".format(strftime("%Y-%m-%d %H:%M:%S"))) except Exception as e: print("Error: {}".format(e)) server.stop() exit() print("{} Exited successfully.".format(strftime("%Y-%m-%d %H:%M:%S"))) sys.stdout.flush()