def _handle_create(self, request): response = dns.message.make_response(request) question = request.question[0] requester = request.environ['addr'][0] zone_name = question.name.to_text() if not self._allowed(request, requester, "CREATE", zone_name): response.set_rcode(dns.rcode.from_text("REFUSED")) return response serial = self.backend.find_zone_serial(zone_name) if serial is not None: LOG.warn(_LW("Not creating %(name)s, zone already exists") % {'name': zone_name}) # Provide an authoritative answer response.flags |= dns.flags.AA return response LOG.debug("Received %(verb)s for %(name)s from %(host)s" % {'verb': "CREATE", 'name': zone_name, 'host': requester}) try: zone = dnsutils.do_axfr(zone_name, self.masters, source=self.transfer_source) self.backend.create_zone(zone) except Exception: response.set_rcode(dns.rcode.from_text("SERVFAIL")) return response # Provide an authoritative answer response.flags |= dns.flags.AA return response
def _handle_create(self, request): response = dns.message.make_response(request) question = request.question[0] requester = request.environ['addr'][0] zone_name = question.name.to_text() if not self._allowed(request, requester, "CREATE", zone_name): response.set_rcode(dns.rcode.from_text("REFUSED")) return response serial = self.backend.find_zone_serial(zone_name) if serial is not None: LOG.warning(_LW("Not creating %(name)s, zone already exists") % {'name': zone_name}) # Provide an authoritative answer response.flags |= dns.flags.AA return response LOG.debug("Received %(verb)s for %(name)s from %(host)s", {'verb': "CREATE", 'name': zone_name, 'host': requester}) try: zone = dnsutils.do_axfr(zone_name, self.masters, source=self.transfer_source) self.backend.create_zone(zone) except Exception: response.set_rcode(dns.rcode.from_text("SERVFAIL")) return response # Provide an authoritative answer response.flags |= dns.flags.AA return response
def _handle_notify(self, request): """ Constructs the response to a NOTIFY and acts accordingly on it. * Decodes the NOTIFY * Checks if the master sending the NOTIFY is allowed to notify * Does a serial check to see if further action needs to be taken * Kicks off an AXFR and returns a valid response """ response = dns.message.make_response(request) question = request.question[0] requester = request.environ['addr'][0] zone_name = question.name.to_text().decode('utf-8') if not self._allowed(request, requester, "NOTIFY", zone_name): response.set_rcode(dns.rcode.from_text("REFUSED")) return response serial = self.backend.find_zone_serial(zone_name) if serial is None: LOG.warning( _LW("Refusing NOTIFY for %(name)s, doesn't exist") % {'name': zone_name}) response.set_rcode(dns.rcode.from_text("REFUSED")) return response LOG.debug("Received %(verb)s for %(name)s from %(host)s", { 'verb': "NOTIFY", 'name': zone_name, 'host': requester }) # According to RFC we should query the server that sent the NOTIFY # TODO(Tim): Reenable this when it makes more sense # resolver = dns.resolver.Resolver() # resolver.nameservers = [requester] # This assumes that the Master is running on port 53 # soa_answer = resolver.query(zone_name, 'SOA') # Check that the serial is < serial above try: zone = dnsutils.do_axfr(zone_name, self.masters, source=self.transfer_source) self.backend.update_zone(zone) except Exception: response.set_rcode(dns.rcode.from_text("SERVFAIL")) return response # Provide an authoritative answer response.flags |= dns.flags.AA return response
def _handle_notify(self, request): """ Constructs the response to a NOTIFY and acts accordingly on it. * Decodes the NOTIFY * Checks if the master sending the NOTIFY is allowed to notify * Does a serial check to see if further action needs to be taken * Kicks off an AXFR and returns a valid response """ response = dns.message.make_response(request) question = request.question[0] requester = request.environ['addr'][0] zone_name = question.name.to_text() if six.PY3 and isinstance(zone_name, bytes): zone_name = zone_name.decode('utf-8') if not self._allowed(request, requester, "NOTIFY", zone_name): response.set_rcode(dns.rcode.from_text("REFUSED")) return response serial = self.backend.find_zone_serial(zone_name) if serial is None: LOG.warning("Refusing NOTIFY for %(name)s, doesn't exist", {'name': zone_name}) response.set_rcode(dns.rcode.from_text("REFUSED")) return response LOG.debug("Received %(verb)s for %(name)s from %(host)s", {'verb': "NOTIFY", 'name': zone_name, 'host': requester}) # According to RFC we should query the server that sent the NOTIFY # TODO(Tim): Reenable this when it makes more sense # resolver = dns.resolver.Resolver() # resolver.nameservers = [requester] # This assumes that the Master is running on port 53 # soa_answer = resolver.query(zone_name, 'SOA') # Check that the serial is < serial above try: zone = dnsutils.do_axfr(zone_name, self.masters, source=self.transfer_source) self.backend.update_zone(zone) except Exception: response.set_rcode(dns.rcode.from_text("SERVFAIL")) return response # Provide an authoritative answer response.flags |= dns.flags.AA return response
def _handle_create(self, request): response = dns.message.make_response(request) question = request.question[0] requester = request.environ['addr'][0] zone_name = question.name.to_text().decode('utf-8') if not self._allowed(request, requester, "CREATE", zone_name): response.set_rcode(dns.rcode.from_text("REFUSED")) return response serial = self.backend.find_zone_serial(zone_name) if serial is not None: # Does this warrant a warning? # There is a race condition between checking if the zone exists # and creating it. LOG.warning(_LW("Not creating %(name)s, zone already exists"), {'name': zone_name}) # Provide an authoritative answer response.flags |= dns.flags.AA return response LOG.debug("Received %(verb)s for %(name)s from %(host)s", { 'verb': "CREATE", 'name': zone_name, 'host': requester }) try: # Receive an AXFR from MiniDNS to populate the zone zone = dnsutils.do_axfr(zone_name, self.masters, source=self.transfer_source) self.backend.create_zone(zone) except Exception as e: # TODO(Federico) unknown exceptions should be logged with a full # traceback. Same in the other methods. LOG.error(_LE("Exception while creating zone %r"), e) response.set_rcode(dns.rcode.from_text("SERVFAIL")) return response # Provide an authoritative answer response.flags |= dns.flags.AA return response
def zone_sync(self, context, zone, servers=None): servers = servers or zone.masters servers = servers.to_list() timeout = cfg.CONF["service:mdns"].xfr_timeout try: dnspython_zone = dnsutils.do_axfr(zone.name, servers, timeout=timeout) except exceptions.XFRFailure as e: LOG.warning(e) return zone.update(dnsutils.from_dnspython_zone(dnspython_zone)) zone.transferred_at = timeutils.utcnow() self.central_api.update_zone(context, zone, increment_serial=False)
def domain_sync(self, context, domain, servers=None): servers = servers or domain.masters servers = dnsutils.expand_servers(servers) timeout = cfg.CONF["service:mdns"].xfr_timeout try: dnspython_zone = dnsutils.do_axfr(domain.name, servers, timeout=timeout) except exceptions.XFRFailure as e: LOG.warning(e.message) return zone = dnsutils.from_dnspython_zone(dnspython_zone) domain.update(zone) domain.transferred_at = timeutils.utcnow() self.central_api.update_domain(context, domain, increment_serial=False)
def _handle_create(self, request): response = dns.message.make_response(request) question = request.question[0] requester = request.environ['addr'][0] zone_name = question.name.to_text() if six.PY3 and isinstance(zone_name, bytes): zone_name = zone_name.decode('utf-8') if not self._allowed(request, requester, "CREATE", zone_name): response.set_rcode(dns.rcode.from_text("REFUSED")) return response serial = self.backend.find_zone_serial(zone_name) if serial is not None: # Does this warrant a warning? # There is a race condition between checking if the zone exists # and creating it. LOG.warning("Not creating %(name)s, zone already exists", {'name': zone_name}) # Provide an authoritative answer response.flags |= dns.flags.AA return response LOG.debug("Received %(verb)s for %(name)s from %(host)s", {'verb': "CREATE", 'name': zone_name, 'host': requester}) try: # Receive an AXFR from MiniDNS to populate the zone zone = dnsutils.do_axfr(zone_name, self.masters, source=self.transfer_source) self.backend.create_zone(zone) except Exception as e: # TODO(Federico) unknown exceptions should be logged with a full # traceback. Same in the other methods. LOG.error("Exception while creating zone %r", e) response.set_rcode(dns.rcode.from_text("SERVFAIL")) return response # Provide an authoritative answer response.flags |= dns.flags.AA return response
def test_do_afxr(self, mock_from_xfr_impl, mock_xfr): mock_from_xfr = mock.MagicMock() mock_from_xfr_impl.return_value = mock_from_xfr mock_from_xfr.origin.to_text.return_value = 'raw_zone' mock_from_xfr.return_value = 'raw_zone' masters = [ { 'host': '192.168.0.1', 'port': 53 }, { 'host': '192.168.0.2', 'port': 53 }, ] self.assertEqual(mock_from_xfr, dnsutils.do_axfr('example.com', masters)) self.assertTrue(mock_xfr.called) self.assertTrue(mock_from_xfr_impl.called)
def zone_sync(self, context, zone, servers=None): start_time = time.time() try: servers = servers or zone.masters servers = servers.to_list() timeout = cfg.CONF["service:mdns"].xfr_timeout try: dnspython_zone = dnsutils.do_axfr(zone.name, servers, timeout=timeout) except exceptions.XFRFailure as e: LOG.warning(e) return zone.update(dnsutils.from_dnspython_zone(dnspython_zone)) zone.transferred_at = timeutils.utcnow() zone.obj_reset_changes(["name"]) self.central_api.update_zone(context, zone, increment_serial=False) finally: metrics.timing('mdns.xfr.zone_sync', time.time() - start_time)