Browse Source

[1512] covered some more invalid zone section cases.

also bit refactored the code to reduce duplicates.
JINMEI Tatuya 13 years ago
parent
commit
75fa2da75c
2 changed files with 58 additions and 12 deletions
  1. 36 6
      src/lib/python/isc/ddns/session.py
  2. 22 6
      src/lib/python/isc/ddns/tests/session_tests.py

+ 36 - 6
src/lib/python/isc/ddns/session.py

@@ -24,6 +24,11 @@ SECTION_ZONE = isc.dns.Message.SECTION_QUESTION
 SECTION_PREREQUISITE = isc.dns.Message.SECTION_ANSWER
 SECTION_UPDATE = isc.dns.Message.SECTION_AUTHORITY
 
+class ZoneError(Exception):
+    def __init__(self, msg, rcode):
+        Exception(msg)
+        self.rcode = rcode
+
 class UpdateSession:
     '''Protocol handling for a single dynamic update request.
 
@@ -50,10 +55,35 @@ class UpdateSession:
                 to be taken.
 
         '''
-        # Interpret the zone section.  It must contain exactly one
-        # "question", and it must be of type SOA.
-        if self.__message.get_rr_count(SECTION_ZONE) == 0:
-            self.__message.make_response()
-            self.__message.set_rcode(isc.dns.Rcode.FORMERR())
-            return UPDATE_DONE
+        try:
+            zone_record = self.__get_update_zone()
+        except ZoneError as e:
+            self.__make_response(e.rcode)
         return UPDATE_DONE
+
+    def __get_update_zone(self):
+        '''Interpret the zone section and return it as a Question object.
+
+        It must contain exactly one question, and it must be of type SOA.
+
+        '''
+        if self.__message.get_rr_count(SECTION_ZONE) != 1:
+            raise ZoneError('Invalid number of records in zone section: ' +
+                            str(1), isc.dns.Rcode.FORMERR())
+        zone_record = self.__message.get_question()[0]
+        if zone_record.get_type() != isc.dns.RRType.SOA():
+            raise ZoneError('update zone section contains non-SOA',
+                            isc.dns.Rcode.FORMERR())
+        return zone_record
+
+    def __make_response(self, rcode):
+        '''Transform the internal message to the update response.
+
+        According RFC2136 Section 3.8, the zone section will be cleared
+        as well as other sections.  The response Rcode will be set to the
+        given value.
+
+        '''
+        self.__message.make_response()
+        self.__message.clear_section(SECTION_ZONE)
+        self.__message.set_rcode(rcode)

+ 22 - 6
src/lib/python/isc/ddns/tests/session_tests.py

@@ -19,17 +19,18 @@ from isc.dns import *
 from isc.ddns.session import *
 
 # Some common test parameters
-TEST_ZONE = Name('example.com')
+TEST_ZONE_NAME = Name('example.com')
 UPDATE_RRTYPE = RRType.SOA()
 TEST_RRCLASS = RRClass.IN()
+TEST_ZONE_RECORD = Question(TEST_ZONE_NAME, TEST_RRCLASS, UPDATE_RRTYPE)
 
-def create_update_msg(zone_name=TEST_ZONE):
+def create_update_msg(zones=[TEST_ZONE_RECORD]):
     msg = Message(Message.RENDER)
     msg.set_qid(5353)           # arbitrary chosen
     msg.set_opcode(Opcode.UPDATE())
     msg.set_rcode(Rcode.NOERROR())
-    if zone_name is not None:
-        msg.add_question(Question(zone_name, TEST_RRCLASS, UPDATE_RRTYPE))
+    for z in zones:
+        msg.add_question(z)
 
     renderer = MessageRenderer()
     msg.to_wire(renderer)
@@ -44,7 +45,7 @@ class SessionTest(unittest.TestCase):
     '''Session tests'''
     def setUp(self):
         self.__client_addr = ('192.0.2.1', 53)
-        self.__update_msgdata, self.__update_msg = create_update_msg(TEST_ZONE)
+        self.__update_msgdata, self.__update_msg = create_update_msg()
         self.__session = UpdateSession(self.__update_msg,
                                        self.__update_msgdata,
                                        self.__client_addr, None)
@@ -62,7 +63,22 @@ class SessionTest(unittest.TestCase):
 
     def test_broken_request(self):
         # Zone section is empty
-        msg_data, msg = create_update_msg(zone_name=None)
+        msg_data, msg = create_update_msg(zones=[])
+        session = UpdateSession(msg, msg_data, None, None)
+        self.assertEqual(UPDATE_DONE, session.handle())
+        self.check_response(session.get_message(), Rcode.FORMERR())
+
+        # Zone section contains multiple records
+        msg_data, msg = create_update_msg(zones=[TEST_ZONE_RECORD,
+                                                 TEST_ZONE_RECORD])
+        session = UpdateSession(msg, msg_data, None, None)
+        self.assertEqual(UPDATE_DONE, session.handle())
+        self.check_response(session.get_message(), Rcode.FORMERR())
+
+        # Zone section's type is not SOA
+        msg_data, msg = create_update_msg(zones=[Question(TEST_ZONE_NAME,
+                                                          TEST_RRCLASS,
+                                                          RRType.A())])
         session = UpdateSession(msg, msg_data, None, None)
         self.assertEqual(UPDATE_DONE, session.handle())
         self.check_response(session.get_message(), Rcode.FORMERR())