Parcourir la source

[1372] ignore SOA in IXFR's authority section with a different RR class

JINMEI Tatuya il y a 13 ans
Parent
commit
35556de064
2 fichiers modifiés avec 40 ajouts et 25 suppressions
  1. 28 17
      src/bin/xfrout/tests/xfrout_test.py.in
  2. 12 8
      src/bin/xfrout/xfrout.py.in

+ 28 - 17
src/bin/xfrout/tests/xfrout_test.py.in

@@ -218,7 +218,8 @@ class TestXfroutSessionBase(unittest.TestCase):
         return msg.get_tsig_record() is not None
 
     def create_request_data(self, with_question=True, with_tsig=False,
-                            zone_name=TEST_ZONE_NAME, ixfr=None):
+                            zone_name=TEST_ZONE_NAME, ixfr=None,
+                            soa_class=TEST_RRCLASS):
         '''Create a commonly used XFR request data.
 
         By default the request type is AXFR; if 'ixfr' is an integer,
@@ -236,9 +237,9 @@ class TestXfroutSessionBase(unittest.TestCase):
         if with_question:
             msg.add_question(Question(zone_name, RRClass.IN(), req_type))
         if req_type == RRType.IXFR():
-            soa = RRset(zone_name, RRClass.IN(), RRType.SOA(), RRTTL(0))
+            soa = RRset(zone_name, soa_class, RRType.SOA(), RRTTL(0))
             # In the RDATA only the serial matters.
-            soa.add_rdata(Rdata(RRType.SOA(), RRClass.IN(),
+            soa.add_rdata(Rdata(RRType.SOA(), soa_class,
                                 'm r ' + str(ixfr) + ' 1 1 1 1'))
             msg.add_rrset(Message.SECTION_AUTHORITY, soa)
 
@@ -680,16 +681,19 @@ class TestXfroutSession(TestXfroutSessionBase):
         self.xfrsess.ClientClass = MockDataSrcClient
         # Successful case.  A zone iterator should be set up.
         self.assertEqual(self.xfrsess._xfrout_setup(
-                self.getmsg(), Name('example.com')), Rcode.NOERROR())
+                self.getmsg(), TEST_ZONE_NAME, TEST_RRCLASS), Rcode.NOERROR())
         self.assertNotEqual(None, self.xfrsess._iterator)
 
         # Failure cases
         self.assertEqual(self.xfrsess._xfrout_setup(
-                self.getmsg(), Name('notauth.example.com')), Rcode.NOTAUTH())
+                self.getmsg(), Name('notauth.example.com'), TEST_RRCLASS),
+                         Rcode.NOTAUTH())
         self.assertEqual(self.xfrsess._xfrout_setup(
-                self.getmsg(), Name('nosoa.example.com')), Rcode.SERVFAIL())
+                self.getmsg(), Name('nosoa.example.com'), TEST_RRCLASS),
+                         Rcode.SERVFAIL())
         self.assertEqual(self.xfrsess._xfrout_setup(
-                self.getmsg(), Name('multisoa.example.com')), Rcode.SERVFAIL())
+                self.getmsg(), Name('multisoa.example.com'), TEST_RRCLASS),
+                         Rcode.SERVFAIL())
 
     def test_xfrout_ixfr_setup(self):
         self.xfrsess.ClientClass = MockDataSrcClient
@@ -699,14 +703,14 @@ class TestXfroutSession(TestXfroutSessionBase):
         # up.
         self.mdata = self.create_request_data(ixfr=IXFR_OK_VERSION)
         self.assertEqual(self.xfrsess._xfrout_setup(
-                self.getmsg(), TEST_ZONE_NAME), Rcode.NOERROR())
+                self.getmsg(), TEST_ZONE_NAME, TEST_RRCLASS), Rcode.NOERROR())
         self.assertNotEqual(None, self.xfrsess._jnl_reader)
 
         # Successful case, but as a result of falling back to AXFR-style
         # IXFR.  A zone iterator should be set up instead of a journal reader.
         self.mdata = self.create_request_data(ixfr=IXFR_NG_VERSION)
         self.assertEqual(self.xfrsess._xfrout_setup(
-                self.getmsg(), TEST_ZONE_NAME), Rcode.NOERROR())
+                self.getmsg(), TEST_ZONE_NAME, TEST_RRCLASS), Rcode.NOERROR())
         self.assertNotEqual(None, self.xfrsess._iterator)
         self.assertEqual(None, self.xfrsess._jnl_reader)
 
@@ -715,7 +719,7 @@ class TestXfroutSession(TestXfroutSessionBase):
         self.mdata = self.create_request_data(ixfr=IXFR_OK_VERSION,
                                               zone_name=zone_name)
         self.assertEqual(self.xfrsess._xfrout_setup(
-                self.getmsg(), zone_name), Rcode.NOERROR())
+                self.getmsg(), zone_name, TEST_RRCLASS), Rcode.NOERROR())
         self.assertNotEqual(None, self.xfrsess._iterator)
 
         # Failure cases
@@ -723,29 +727,36 @@ class TestXfroutSession(TestXfroutSessionBase):
         self.mdata = self.create_request_data(ixfr=IXFR_OK_VERSION,
                                               zone_name=zone_name)
         self.assertEqual(self.xfrsess._xfrout_setup(
-                self.getmsg(), zone_name), Rcode.NOTAUTH())
+                self.getmsg(), zone_name, TEST_RRCLASS), Rcode.NOTAUTH())
         # this is a strange case: zone's SOA will be found but the journal
         # reader won't be created due to 'no such zone'.
         zone_name = Name('notauth2.example.com')
         self.mdata = self.create_request_data(ixfr=IXFR_OK_VERSION,
                                               zone_name=zone_name)
         self.assertEqual(self.xfrsess._xfrout_setup(
-                self.getmsg(), zone_name), Rcode.NOTAUTH())
+                self.getmsg(), zone_name, TEST_RRCLASS), Rcode.NOTAUTH())
         zone_name = Name('nosoa.example.com')
         self.mdata = self.create_request_data(ixfr=IXFR_OK_VERSION,
                                               zone_name=zone_name)
         self.assertEqual(self.xfrsess._xfrout_setup(
-                self.getmsg(), zone_name), Rcode.SERVFAIL())
+                self.getmsg(), zone_name, TEST_RRCLASS), Rcode.SERVFAIL())
         zone_name = Name('multisoa.example.com')
         self.mdata = self.create_request_data(ixfr=IXFR_OK_VERSION,
                                               zone_name=zone_name)
         self.assertEqual(self.xfrsess._xfrout_setup(
-                self.getmsg(), zone_name), Rcode.SERVFAIL())
+                self.getmsg(), zone_name, TEST_RRCLASS), Rcode.SERVFAIL())
 
         # query name doesn't match the SOA's owner
         self.mdata = self.create_request_data(ixfr=IXFR_OK_VERSION)
         self.assertEqual(self.xfrsess._xfrout_setup(
-                self.getmsg(), zone_name), Rcode.FORMERR())
+                self.getmsg(), zone_name, TEST_RRCLASS), Rcode.FORMERR())
+
+        # query's RR class doesn't match the SOA's class
+        zone_name = TEST_ZONE_NAME # make sure the name matches this time
+        self.mdata = self.create_request_data(ixfr=IXFR_OK_VERSION,
+                                              soa_class=RRClass.CH())
+        self.assertEqual(self.xfrsess._xfrout_setup(
+                self.getmsg(), zone_name, TEST_RRCLASS), Rcode.FORMERR())
 
     def test_dns_xfrout_start_formerror(self):
         # formerror
@@ -757,7 +768,7 @@ class TestXfroutSession(TestXfroutSessionBase):
         return "example.com"
 
     def test_dns_xfrout_start_notauth(self):
-        def notauth(msg, name):
+        def notauth(msg, name, rrclass):
             return Rcode.NOTAUTH()
         self.xfrsess._xfrout_setup = notauth
         self.xfrsess.dns_xfrout_start(self.sock, self.mdata)
@@ -772,7 +783,7 @@ class TestXfroutSession(TestXfroutSessionBase):
         self.assertEqual(self.sock.read_msg().get_rcode(), Rcode.SERVFAIL())
 
     def test_dns_xfrout_start_noerror(self):
-        def noerror(msg, name):
+        def noerror(msg, name, rrclass):
             return Rcode.NOERROR()
         self.xfrsess._xfrout_setup = noerror
 

+ 12 - 8
src/bin/xfrout/xfrout.py.in

@@ -364,7 +364,7 @@ class XfroutSession():
 
         return Rcode.NOERROR()
 
-    def __ixfr_setup(self, request_msg, zone_name):
+    def __ixfr_setup(self, request_msg, zone_name, zone_class):
         '''Setup a zone journal reader for IXFR.
 
         If the underlying data source does not know the requested range
@@ -373,16 +373,21 @@ class XfroutSession():
 
         '''
         # TODO: more error case handling
+        # Check the authority section.  Look for a SOA record with
+        # the same name and class as the question.
         remote_soa = None
         for auth_rrset in request_msg.get_section(Message.SECTION_AUTHORITY):
-            if auth_rrset.get_name() != zone_name:
-                continue
-            if auth_rrset.get_type() != RRType.SOA():
+            # Ignore data whose owner name is not the zone apex, and
+            # ignore non-SOA or different class of records.
+            if auth_rrset.get_name() != zone_name or \
+                    auth_rrset.get_type() != RRType.SOA() or \
+                    auth_rrset.get_class() != zone_class:
                 continue
             remote_soa = auth_rrset
         if remote_soa is None:
             # TBD: log it.
             return Rcode.FORMERR()
+
         rcode, self._soa = self._get_zone_soa(zone_name)
         if rcode != Rcode.NOERROR():
             return rcode
@@ -408,7 +413,7 @@ class XfroutSession():
 
         return Rcode.NOERROR()
 
-    def _xfrout_setup(self, request_msg, zone_name):
+    def _xfrout_setup(self, request_msg, zone_name, zone_class):
         '''Setup a context for xfr responses according to the request type.
 
         This method identifies the most appropriate data source for the
@@ -432,7 +437,7 @@ class XfroutSession():
         if self._request_type == RRType.AXFR():
             return self.__axfr_setup(zone_name)
         else:
-            return self.__ixfr_setup(request_msg, zone_name)
+            return self.__ixfr_setup(request_msg, zone_name, zone_class)
 
     def dns_xfrout_start(self, sock_fd, msg_query, quota_ok=True):
         rcode_, msg = self._parse_query_message(msg_query)
@@ -456,9 +461,8 @@ class XfroutSession():
         zone_class = question.get_class()
         zone_str = format_zone_str(zone_name, zone_class) # for logging
 
-        # TODO: we should also include class in the check
         try:
-            rcode_ = self._xfrout_setup(msg, zone_name)
+            rcode_ = self._xfrout_setup(msg, zone_name, zone_class)
         except Exception as ex:
             logger.error(XFROUT_XFR_TRANSFER_CHECK_ERROR, self._request_typestr,
                          format_addrinfo(self._remote), zone_str, ex)