def dns_process_rgw_lan_nosoa(self, query, addr, cback): """ Process DNS query from private network of a name not in a SOA zone """ # Forward or continue to DNS resolver q = query.question[0] key = (query.id, q.name, q.rdtype, addr) fqdn = q.name rdtype = q.rdtype self._logger.info('LAN !SOA: {} ({}) from {}/{}'.format(fqdn, dns.rdatatype.to_text(rdtype), addr[0], query.transport)) if key in self.activequeries: # Continue ongoing resolution resolver = self.activequeries[key] resolver.do_continue(query) return # Create factory for new resolution raddr = self.dns_get_resolver() resolver = uDNSResolver() self.activequeries[key] = resolver try: response = yield from resolver.do_resolve(query, raddr, timeouts=self.dns_get_timeout(rdtype)) except ConnectionRefusedError: # Failed to resolve DNS query - Drop DNS Query self._logger.warning('ConnectionRefusedError: Resolving {} via {}:{}'.format(fqdn, raddr[0], raddr[1])) response = dnsutils.make_response_rcode(query, dns.rcode.REFUSED) if not response: # Failed to resolve DNS query - Drop DNS Query self._logger.warning('ResolutionFailure: Failed to resolve address for {} via {}:{}'.format(fqdn, raddr[0], raddr[1])) response = dnsutils.make_response_rcode(query, dns.rcode.SERVFAIL) # Resolution ended, send generated response del self.activequeries[key] cback(query, addr, response)
def dns_process_rgw_lan_nosoa(self, query, addr, cback): """ Process DNS query from private network of a name not in a SOA zone """ # Forward or continue to DNS resolver q = query.question[0] key = (query.id, q.name, q.rdtype, addr) fqdn = q.name rdtype = q.rdtype self._logger.info('LAN !SOA: {} ({}) from {}/{}'.format( fqdn, dns.rdatatype.to_text(rdtype), addr[0], query.transport)) if key in self.activequeries: # Continue ongoing resolution resolver = self.activequeries[key] resolver.do_continue(query) return # Changing the A or AAAA queries to NAPTR queries to check if destination is served by a CES/CETP service if rdtype in [dns.rdatatype.A, dns.rdatatype.AAAA, dns.rdatatype.PTR]: self._logger.info( "Forwarding the {} query as NAPTR query for domain '{}'". format(dns.rdatatype.to_text(rdtype), fqdn)) cb_args = (query, addr) cb = (cback, cb_args) fwd_query = dns.message.make_query(fqdn, dns.rdatatype.NAPTR) answer = yield from self._forward_naptr_query(fwd_query, fqdn, key) response = self._pre_process_naptr(answer) if response is None: self._logger.info( " Failed to resolved NAPTR query for the domain '{}'.. Revert to the original host query" .format(fqdn)) else: self._process_naptr_response(response, cb) del self.activequeries[key] return # Create factory for new resolution raddr = self.dns_get_resolver() resolver = uDNSResolver() self.activequeries[key] = resolver try: response = yield from resolver.do_resolve( query, raddr, timeouts=self.dns_get_timeout(rdtype)) except ConnectionRefusedError: # Failed to resolve DNS query - Drop DNS Query self._logger.warning( 'ConnectionRefusedError: Resolving {} via {}:{}'.format( fqdn, raddr[0], raddr[1])) response = dnsutils.make_response_rcode(query, dns.rcode.REFUSED) if not response: # Failed to resolve DNS query - Drop DNS Query self._logger.warning( 'ResolutionFailure: Failed to resolve address for {} via {}:{}' .format(fqdn, raddr[0], raddr[1])) response = dnsutils.make_response_rcode(query, dns.rcode.SERVFAIL) # Resolution ended, send generated response del self.activequeries[key] cback(query, addr, response)
def ddns_process(self, query, addr, cback): """ Process DDNS query from DHCP server """ self._logger.debug('process_update') try: #Filter hostname and operation for rr in query.authority: #Filter out non A record types if rr.rdtype == dns.rdatatype.A and rr.ttl != 0: yield from self.ddns_register_user(format(rr.name), rr.rdtype, rr[0].address) elif rr.rdtype == dns.rdatatype.A and rr.ttl == 0: yield from self.ddns_deregister_user(format(rr.name), rr.rdtype, rr[0].address) except Exception as e: self._logger.warning('Failed to process UPDATE DNS message {}'.format(e)) finally: # Send generic DDNS Response NOERROR response = dnsutils.make_response_rcode(query) self._logger.debug('Sent DDNS response to {}:{}'.format(addr[0],addr[1])) cback(query, addr, response)
def dns_error_response(self, query, addr, cback, rcode=dns.rcode.REFUSED): # Create error response response = dnsutils.make_response_rcode(query, rcode=rcode, recursion_available=True) cback(query, addr, response)
def dns_process_rgw_wan_soa(self, query, addr, cback): """ Process DNS query from public network of a name in a SOA zone """ fqdn = query.fqdn rdtype = query.question[0].rdtype # Initialize to None to prevent AttributeError query.reputation_resolver = None query.reputation_requestor = None self._logger.debug('WAN SOA: {} ({}) from {}/{}'.format(fqdn, dns.rdatatype.to_text(rdtype), addr[0], query.transport)) if self.hosttable.has((host.KEY_HOST_SERVICE, fqdn)): # The service exists in RGW host_obj = self.hosttable.get((host.KEY_HOST_SERVICE, fqdn)) service_data = host_obj.get_service_sfqdn(fqdn) self._logger.debug('Found service: {} / {}'.format(fqdn, service_data)) elif self.hosttable.has_carriergrade(fqdn): # There is a host with CarrierGrade service in RGW host_obj, service_data = self.hosttable.get_carriergrade(fqdn) self._logger.debug('Found CarrierGrade service: {} / {}'.format(fqdn, service_data)) elif fqdn in self.soa_list: # Querying the RGW domain itself self._logger.debug('Use NS address: {}'.format(fqdn)) host_obj = self.hosttable.get((host.KEY_HOST_FQDN, fqdn)) # Create DNS Response response = dnsutils.make_response_answer_rr(query, fqdn, dns.rdatatype.A, host_obj.ipv4, rdclass=1, ttl=DNSRR_TTL_DEFAULT) self._logger.debug('Send DNS response to {}:{}'.format(addr[0],addr[1])) cback(query, addr, response) return else: # FQDN not found! Answer NXDOMAIN self._logger.debug('Answer {} with NXDOMAIN'.format(fqdn)) response = dnsutils.make_response_rcode(query, dns.rcode.NXDOMAIN) cback(query, addr, response) return # Pre-process request with PBRA. Quick return response if pre-emptive actions are required due to policy response = yield from self.pbra.pbra_dns_preprocess_rgw_wan_soa(query, addr, host_obj, service_data) if response is not None: self._logger.debug('Preprocessing DNS response\n{}'.format(response)) cback(query, addr, response) return self._logger.debug('Continue after pre-processing query / {}'.format(service_data)) # Process only type A/SRV/TXT queries for servicepool domains if rdtype not in (dns.rdatatype.A, dns.rdatatype.SRV, dns.rdatatype.TXT): self._logger.debug('Answer with empty records for public domain {} type {}'.format(fqdn, dns.rdatatype.to_text(rdtype))) response = dnsutils.make_response_rcode(query, rcode=dns.rcode.NOERROR, recursion_available=False) cback(query, addr, response) return # If the service is carriergrade, resolve it first before allocating our own address _ipv4, _service_data = host_obj.ipv4, service_data if service_data['carriergrade'] is True: _carriergrade_fqdn = fqdn if service_data['alias'] is True: # Use original FQDN in carriergrade resolutions, instead of the alias CNAMEd FQDN _carriergrade_fqdn = service_data['_fqdn'] self._logger.debug('CarrierGrade resolution using original fqdn={} instead of alias fqdn={}'.format(_carriergrade_fqdn, fqdn)) _rcode, _ipv4, _service_data = yield from self._dns_resolve_circularpool_carriergrade(host_obj, _carriergrade_fqdn, addr, service_data) if _ipv4 is None: # Propagate rcode value response = dnsutils.make_response_rcode(query, rcode=_rcode, recursion_available=False) cback(query, addr, response) return # Use PBRA to allocate an address according to policy allocated_ipv4 = yield from self.pbra.pbra_dns_process_rgw_wan_soa(query, addr, host_obj, _service_data, _ipv4) if not allocated_ipv4 and query.transport == 'tcp': # Failed to allocate an address - hold and reattempt after T ms to bridge the gap with UDP queries rtx_t = 0.50 self._logger.debug('Failed to allocate an address for {} via TCP, reattempting in {} msec'.format(fqdn, rtx_t*1000)) yield from asyncio.sleep(rtx_t) allocated_ipv4 = yield from self.pbra.pbra_dns_process_rgw_wan_soa(query, addr, host_obj, _service_data, _ipv4) if not allocated_ipv4 and query.transport == 'tcp': # Failed to allocate an address - Answer with empty records to avoid stalling the TCP transaction self._logger.warning('Failed to allocate an address for {} via TCP'.format(fqdn)) response = dnsutils.make_response_rcode(query, rcode=dns.rcode.NOERROR, recursion_available=False) cback(query, addr, response) return if not allocated_ipv4 and query.transport == 'udp': # Failed to allocate an address - Drop DNS Query to trigger reattempt return # Create DNS response based on received query type if rdtype == dns.rdatatype.A: # Create DNS Response type A response = dnsutils.make_response_answer_rr(query, fqdn, dns.rdatatype.A, allocated_ipv4, rdclass=1, ttl=DNSRR_TTL_CIRCULARPOOL) self._logger.debug('Send DNS response to {}:{}'.format(addr[0],addr[1])) cback(query, addr, response) elif rdtype == dns.rdatatype.SRV: # Create DNS Response type SRV # Check service data and build SFQDN for SRV response, then add SFQDN A record to additional records sfqdn = '_{}._{}.{}'.format(_service_data['port'], _service_data['protocol'], fqdn) # Build SRV data response - SRV answer with encoded SFQDN and additional with A record for encoded SFQDN priority, weight, port, target = 10, 100, _service_data['port'], sfqdn srv_rrset = '{} {} {} {}'.format(priority, weight, port, target) response = dnsutils.make_response_answer_rr(query, fqdn, dns.rdatatype.SRV, srv_rrset, rdclass=1, ttl=DNSRR_TTL_CIRCULARPOOL) _foo = dnsutils.make_response_answer_rr(query, sfqdn, dns.rdatatype.A, allocated_ipv4, rdclass=1, ttl=DNSRR_TTL_CIRCULARPOOL) response.additional = _foo.answer self._logger.debug('Send DNS response to {}:{}'.format(addr[0],addr[1])) cback(query, addr, response) elif rdtype == dns.rdatatype.TXT: # Create DNS Response type TXT # Build TXT data response - TXT answer with encoded data service and additional with A record for IP address txt_rrset = 'proxy_{}.port_{}.protocol_{}.{}'.format(_service_data['proxy_required'], _service_data['port'], _service_data['protocol'], fqdn) response = dnsutils.make_response_answer_rr(query, fqdn, dns.rdatatype.TXT, txt_rrset, rdclass=1, ttl=DNSRR_TTL_CIRCULARPOOL) _foo = dnsutils.make_response_answer_rr(query, fqdn, dns.rdatatype.A, allocated_ipv4, rdclass=1, ttl=DNSRR_TTL_CIRCULARPOOL) response.additional = _foo.answer self._logger.debug('Send DNS response to {}:{}'.format(addr[0],addr[1])) cback(query, addr, response)
def dns_process_rgw_lan_soa(self, query, addr, cback): """ Process DNS query from private network of a name in a SOA zone """ # Forward or continue to DNS resolver fqdn = query.fqdn rdtype = query.question[0].rdtype self._logger.debug('LAN SOA: {} ({}) from {}/{}'.format(fqdn, dns.rdatatype.to_text(rdtype), addr[0], query.transport)) if self.hosttable.has((host.KEY_HOST_SERVICE, fqdn)): # The service exists in RGW host_obj = self.hosttable.get((host.KEY_HOST_SERVICE, fqdn)) service_data = host_obj.get_service_sfqdn(fqdn) self._logger.debug('Found service: {} / {}'.format(fqdn, service_data)) elif self.hosttable.has_carriergrade(fqdn): # There is a host with CarrierGrade service in RGW host_obj, service_data = self.hosttable.get_carriergrade(fqdn) self._logger.debug('Found CarrierGrade service: {} / {}'.format(fqdn, service_data)) elif fqdn in self.soa_list: # Querying the RGW domain itself self._logger.debug('Use NS address: {}'.format(fqdn)) host_obj = self.hosttable.get((host.KEY_HOST_FQDN, fqdn)) # Create DNS Response response = dnsutils.make_response_answer_rr(query, fqdn, dns.rdatatype.A, host_obj.ipv4, rdclass=1, ttl=DNSRR_TTL_DEFAULT, recursion_available=True) self._logger.debug('Send DNS response to {}:{}'.format(addr[0],addr[1])) cback(query, addr, response) return else: # FQDN not found! Answer NXDOMAIN self._logger.debug('Answer {} with NXDOMAIN'.format(fqdn)) response = dnsutils.make_response_rcode(query, dns.rcode.NXDOMAIN, recursion_available=True) cback(query, addr, response) return # TODO: Modify this to propagate original queries if carriergrade, and only override certain types, e.g. dns.rdatatype.A, # Evaluate host and service if service_data['carriergrade'] is True: # Resolve via CarrierGrade # Answer with empty records for other types not A if rdtype != dns.rdatatype.A: response = dnsutils.make_response_rcode(query, dns.rcode.NOERROR, recursion_available=True) cback(query, addr, response) return self._logger.debug('Process {} with CarrierGrade resolution'.format(fqdn)) _rcode, _ipv4, _service_data = yield from self._dns_resolve_circularpool_carriergrade(host_obj, fqdn, addr, service_data) if not _ipv4: # Propagate rcode value response = dnsutils.make_response_rcode(query, rcode=_rcode, recursion_available=True) cback(query, addr, response) return self._logger.debug('Completed LAN CarrierGrade resolution: {} @ {}'.format(fqdn, _ipv4)) # Answer query with A type and answer with IPv4 address of the host response = dnsutils.make_response_answer_rr(query, fqdn, dns.rdatatype.A, _ipv4, rdclass=1, ttl=DNSRR_TTL_DEFAULT, recursion_available=True) cback(query, addr, response) elif rdtype == dns.rdatatype.A: # Resolve A type and answer with IPv4 address of the host response = dnsutils.make_response_answer_rr(query, fqdn, rdtype, host_obj.ipv4, rdclass=1, ttl=DNSRR_TTL_DEFAULT, recursion_available=True) cback(query, addr, response) elif rdtype == dns.rdatatype.PTR: # Resolve PTR type and answer with FQDN of the host response = dnsutils.make_response_answer_rr(query, fqdn, rdtype, host_obj.fqdn, rdclass=1, ttl=DNSRR_TTL_DEFAULT, recursion_available=True) cback(query, addr, response) else: # Answer with empty records for other types response = dnsutils.make_response_rcode(query, dns.rcode.NOERROR, recursion_available=True) cback(query, addr, response)