Exemple #1
0
    def process_dns_message(self,
                            dns_cb,
                            cb_args,
                            dst_id,
                            r_cesid="",
                            naptr_list=[]):
        """ Enforce rate limit on DNS NAPTRs served by CETP Engine """
        try:
            if not self.dns_threshold_exceeded():

                dns_q, addr = cb_args
                src_ip, src_port = addr
                key = (host.KEY_HOST_IPV4, src_ip)

                if not self.host_table.has(key):
                    self._logger.error(
                        "Sender IP '{}' is not a registered host".format(
                            src_ip))
                    return

                host_obj = self.host_table.get(key)
                src_id = host_obj.fqdn
                #self._logger.info("Connection from '{}'->'{}'".format(src_id, dst_id))

                if self.has_connection(src_id, dst_id):
                    conn = self.get_connection(src_id, dst_id)
                    lpip = conn.lpip
                    response = dnsutils.make_response_answer_rr(
                        dns_q,
                        dst_id,
                        dns.rdatatype.A,
                        lpip,
                        rdclass=1,
                        ttl=120,
                        recursion_available=True)
                    dns_cb(dns_q, addr, response)
                else:
                    self._execute_cetp_policies(dns_cb, cb_args, src_id,
                                                dst_id, r_cesid, naptr_list)

        except Exception as ex:
            self._logger.info(
                "Exception in process_dns_message(): '{}' ".format(ex))
            return
Exemple #2
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)
Exemple #3
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)