示例#1
0
    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)
示例#3
0
 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)
示例#4
0
 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)
示例#5
0
    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)
示例#6
0
    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)