[svn] commit: r1851 - in /branches/trac185/src/bin/xfrin: tests/xfrin_test.py xfrin.py.in

BIND 10 source code commits bind10-changes at lists.isc.org
Wed May 19 01:34:56 UTC 2010


Author: jinmei
Date: Wed May 19 01:34:56 2010
New Revision: 1851

Log:
 - fixed a bug that xfrin doesn't support IPv6 master address.
 - used getaddrinfo instead of inet_pton as part of it (so we can even support IPv8:-)
 - existing unit tests confirmed there shouldn't be regression

Modified:
    branches/trac185/src/bin/xfrin/tests/xfrin_test.py
    branches/trac185/src/bin/xfrin/xfrin.py.in

Modified: branches/trac185/src/bin/xfrin/tests/xfrin_test.py
==============================================================================
--- branches/trac185/src/bin/xfrin/tests/xfrin_test.py (original)
+++ branches/trac185/src/bin/xfrin/tests/xfrin_test.py Wed May 19 01:34:56 2010
@@ -26,7 +26,13 @@
 TEST_RRCLASS = rr_class.IN()
 TEST_DB_FILE = 'db_file'
 TEST_MASTER_IPV4_ADDRESS = '127.0.0.1'
+TEST_MASTER_IPV4_ADDRINFO = (socket.AF_INET, socket.SOCK_STREAM,
+                             socket.IPPROTO_TCP, '',
+                             (TEST_MASTER_IPV4_ADDRESS, 53))
 TEST_MASTER_IPV6_ADDRESS = '::1'
+TEST_MASTER_IPV6_ADDRINFO = (socket.AF_INET6, socket.SOCK_STREAM,
+                             socket.IPPROTO_TCP, '',
+                             (TEST_MASTER_IPV6_ADDRESS, 53))
 # XXX: This should be a non priviledge port that is unlikely to be used.
 # If some other process uses this port test will fail.
 TEST_MASTER_PORT = '53535'
@@ -132,7 +138,7 @@
             os.remove(TEST_DB_FILE)
         self.conn = MockXfrinConnection('example.com.', TEST_DB_FILE,
                                         threading.Event(),
-                                        TEST_MASTER_IPV4_ADDRESS)
+                                        TEST_MASTER_IPV4_ADDRINFO)
 
     def tearDown(self):
         self.conn.close()
@@ -147,9 +153,8 @@
         # uncovers such a bug.
         c = MockXfrinConnection('example.com.', TEST_DB_FILE,
                                 threading.Event(),
-                                TEST_MASTER_IPV6_ADDRESS)
-        #This test currently fails.  Fix the code, then enable it
-        #c.bind(('::', 0))
+                                TEST_MASTER_IPV6_ADDRINFO)
+        c.bind(('::', 0))
         c.close()
 
     def test_response_with_invalid_msg(self):
@@ -310,19 +315,21 @@
         return self.xfr._parse_cmd_params(self.args)
 
     def test_parse_cmd_params(self):
-        name, master, port, db_file = self._do_parse()
-        self.assertEqual(port, int(TEST_MASTER_PORT))
+        name, master_addrinfo, db_file = self._do_parse()
+        self.assertEqual(master_addrinfo[4][1], int(TEST_MASTER_PORT))
         self.assertEqual(name, TEST_ZONE_NAME)
-        self.assertEqual(master, TEST_MASTER_IPV4_ADDRESS)
+        self.assertEqual(master_addrinfo[4][0], TEST_MASTER_IPV4_ADDRESS)
         self.assertEqual(db_file, TEST_DB_FILE)
 
     def test_parse_cmd_params_default_port(self):
         del self.args['port']
-        self.assertEqual(self._do_parse()[2], 53)
+        master_addrinfo = self._do_parse()[1]
+        self.assertEqual(master_addrinfo[4][1], 53)
 
     def test_parse_cmd_params_ip6master(self):
         self.args['master'] = TEST_MASTER_IPV6_ADDRESS
-        self.assertEqual(self._do_parse()[1], TEST_MASTER_IPV6_ADDRESS)
+        master_addrinfo = self._do_parse()[1]
+        self.assertEqual(master_addrinfo[4][0], TEST_MASTER_IPV6_ADDRESS)
 
     def test_parse_cmd_params_nozone(self):
         # zone name is mandatory.
@@ -347,6 +354,9 @@
         self.assertRaises(XfrinException, self._do_parse)
 
         self.args['port'] = '65536'
+        self.assertRaises(XfrinException, self._do_parse)
+
+        self.args['port'] = 'http'
         self.assertRaises(XfrinException, self._do_parse)
 
     def test_command_handler_shutdown(self):

Modified: branches/trac185/src/bin/xfrin/xfrin.py.in
==============================================================================
--- branches/trac185/src/bin/xfrin/xfrin.py.in (original)
+++ branches/trac185/src/bin/xfrin/xfrin.py.in Wed May 19 01:34:56 2010
@@ -51,6 +51,8 @@
 # define xfrin rcode
 XFRIN_OK = 0
 
+DEFAULT_MASTER_PORT = '53'
+
 def log_error(msg):
     sys.stderr.write("[b10-xfrin] ")
     sys.stderr.write(str(msg))
@@ -63,15 +65,15 @@
     '''Do xfrin in this class. '''    
 
     def __init__(self, 
-                 zone_name, db_file, shutdown_event, master_addr, 
-                 port = 53, verbose = False, idle_timeout = 60): 
+                 zone_name, db_file, shutdown_event, master_addrinfo, 
+                 verbose = False, idle_timeout = 60): 
         ''' idle_timeout: max idle time for read data from socket.
             db_file: specify the data source file.
             check_soa: when it's true, check soa first before sending xfr query
         '''
 
         asyncore.dispatcher.__init__(self)
-        self.create_socket(socket.AF_INET, socket.SOCK_STREAM)
+        self.create_socket(master_addrinfo[0], master_addrinfo[1])
         self._zone_name = zone_name
         self._db_file = db_file
         self._soa_rr_count = 0
@@ -79,17 +81,17 @@
         self.setblocking(1)
         self._shutdown_event = shutdown_event
         self._verbose = verbose
-        self._master_addr = master_addr
-        self._port = port
+        self._master_address = master_addrinfo[4]
 
     def connect_to_master(self):
         '''Connect to master in TCP.'''
 
         try:
-            self.connect((self._master_addr, self._port))
+            self.connect(self._master_address)
             return True
         except socket.error as e:
-            self.log_msg('Failed to connect:(%s:%d), %s' % (self._master_addr, self._port, str(e)))
+            self.log_msg('Failed to connect:(%s), %s' % (self._master_address,
+                                                            str(e)))
             return False
 
     def _create_query(self, query_type):
@@ -287,11 +289,10 @@
 
 
 def process_xfrin(xfrin_recorder, zone_name, db_file, 
-                  shutdown_event, master_addr, port, check_soa, verbose):
-    port = int(port)
+                  shutdown_event, master_addrinfo, check_soa, verbose):
     xfrin_recorder.increment(zone_name)
     conn = XfrinConnection(zone_name, db_file, shutdown_event, 
-                           master_addr, port, verbose)
+                           master_addrinfo, verbose)
     if conn.connect_to_master():
         conn.do_xfrin(check_soa)
 
@@ -376,13 +377,14 @@
                 self._shutdown_event.set()
 
             elif cmd == 'retransfer':
-                zone_name, master, port, db_file = self._parse_cmd_params(args)
-                ret = self.xfrin_start(zone_name, db_file, master, port, False)
+                zone_name, master_addrinfo, db_file = self._parse_cmd_params(args)
+                ret = self.xfrin_start(zone_name, db_file, master_addrinfo,
+                                       False)
                 answer = create_answer(ret[0], ret[1])
 
             elif cmd == 'refresh':
-                zone_name, master, port, db_file = self._parse_cmd_params(args)
-                ret = self.xfrin_start(zone_name, db_file, master, port)
+                zone_name, master_addrinfo, db_file = self._parse_cmd_params(args)
+                ret = self.xfrin_start(zone_name, db_file, master_addrinfo)
                 answer = create_answer(ret[0], ret[1])
 
         except XfrinException as err:
@@ -399,27 +401,23 @@
         if not master:
             raise XfrinException('master address should be provided')
 
-        check_addr(master)
-        port = 53
         port_str = args.get('port')
-        if port_str:
-            port = int(port_str)
-            check_port(port)
+        if not port_str:
+            port_str = DEFAULT_MASTER_PORT
+        master_addrinfo = check_addr_port(master, port_str)
 
         db_file = args.get('db_file')
         if not db_file:
             #TODO, the db file path should be got in auth server's configuration
             db_file = '@@LOCALSTATEDIR@@/@PACKAGE@/zone.sqlite3'
 
-        return (zone_name, master, port, db_file)
-            
+        return (zone_name, master_addrinfo, db_file)
 
     def startup(self):
         while not self._shutdown_event.is_set():
             self._cc_check_command()
 
-    def xfrin_start(self, zone_name, db_file, master_addr, 
-                    port = 53, 
+    def xfrin_start(self, zone_name, db_file, master_addrinfo,
                     check_soa = True):
         if "bind10_dns" not in sys.modules:
             return (1, "xfrin failed, can't load dns message python library: 'bind10_dns'")
@@ -436,8 +434,8 @@
                                                 zone_name,
                                                 db_file,
                                                 self._shutdown_event,
-                                                master_addr,
-                                                port, check_soa, self._verbose))
+                                                master_addrinfo, check_soa,
+                                                self._verbose))
 
         xfrin_thread.start()
         return (0, 'zone xfrin is started')
@@ -454,20 +452,20 @@
     signal.signal(signal.SIGTERM, signal_handler)
     signal.signal(signal.SIGINT, signal_handler)
 
-def check_port(value):
-    if (value < 0) or (value > 65535):
-        raise XfrinException('requires a port number (0-65535)')
-
-def check_addr(ipstr):
-    ip_family = socket.AF_INET
-    if (ipstr.find(':') != -1):
-        ip_family = socket.AF_INET6
-
+def check_addr_port(addrstr, portstr):
     try:
-        socket.inet_pton(ip_family, ipstr)
-    except:
-        raise XfrinException("%s invalid ip address" % ipstr)
-
+        addrinfo = socket.getaddrinfo(addrstr, portstr, socket.AF_UNSPEC,
+                                      socket.SOCK_STREAM, socket.IPPROTO_TCP,
+                                      socket.AI_NUMERICHOST|
+                                      socket.AI_NUMERICSERV)
+    except socket.gaierror as err:
+        raise XfrinException("failed to resolve master address/port=%s/%s: %s" %
+                             (addrstr, portstr, str(err)))
+    if len(addrinfo) != 1:
+        # with the parameters above the result must be uniquely determined.
+        errmsg = "unexpected result for address/port resolution for %s:%s"
+        raise XfrinException(errmsg % (addrstr, portstr))
+    return addrinfo[0]
 
 def set_cmd_options(parser):
     parser.add_option("-v", "--verbose", dest="verbose", action="store_true",




More information about the bind10-changes mailing list