Browse Source

Use library function instead of regexp

* Fixes problem with strange IPv6 addresses (if they contain dots)
* Adds test for such address
* Adds workaround about MacOS bug

git-svn-id: svn://bind10.isc.org/svn/bind10/branches/trac353@3239 e5f2f494-b856-4b98-b285-d166d9295462
Michal Vaner 14 years ago
parent
commit
12e148d958
2 changed files with 16 additions and 19 deletions
  1. 7 18
      src/lib/python/isc/net/addr.py
  2. 9 1
      src/lib/python/isc/net/tests/parse_test.py

+ 7 - 18
src/lib/python/isc/net/addr.py

@@ -17,13 +17,6 @@
 import socket
 import re
 
-# These regular expressions are not validating. They are supposed to
-# guess which kind of address it is and throw away just obvious nonsense.
-# It is expected that inet_pton will complain if it isn't an address, so
-# they can have false positives.
-isv4 = re.compile(r'^([0-9]{1,3}\.){3}[0-9]{1,3}$')
-isv6 = re.compile(r'^([0-9a-f]{,4}:){,7}[0-9a-f]{,4}$', re.IGNORECASE)
-
 class InvalidAddress(ValueError):
     """Exception for invalid addresses."""
     pass
@@ -39,17 +32,13 @@ class IPAddr:
         an InvalidAddr exception if the provided string isn't valid address.
         """
         try:
-            if isv4.match(addr):
-                a = socket.inet_pton(socket.AF_INET, addr)
-                self.family = socket.AF_INET
-                self.addr = a
-            elif isv6.match(addr):
-                a = socket.inet_pton(socket.AF_INET6, addr)
-                self.family = socket.AF_INET6
-                self.addr = a
-            else:
-                raise InvalidAddress(addr +
-                    ' is not a valid IPv4 nor IPv6 address')
+            addrinfo = socket.getaddrinfo(addr, None, 0, 0, 0,
+                socket.AI_NUMERICHOST)[0]
+            self.family = addrinfo[0]
+            if not self.family in [socket.AF_INET, socket.AF_INET6]:
+                raise InvalidAddress(
+                    'IPAddr can hold only IPv4 or IPv6 address')
+            self.addr = socket.inet_pton(self.family, addr)
         except socket.error as e:
             raise InvalidAddress(str(e))
 

+ 9 - 1
src/lib/python/isc/net/tests/parse_test.py

@@ -15,6 +15,7 @@
 
 """Tests for isc.net.parse."""
 import unittest
+import socket
 from isc.net.parse import port_parse, addr_parse
 
 class TestCheckPort(unittest.TestCase):
@@ -50,7 +51,13 @@ class TestCheckIP(unittest.TestCase):
         self.assertRaises(ValueError, addr_parse, "123.0.0.")
         # Address range not allowed
         self.assertRaises(ValueError, addr_parse, "192.0.2.0/24")
-        self.assertRaises(ValueError, addr_parse, "0000.0.0.0")
+        try:
+            # XXX: MacOS X's inet_pton() doesn't reject this form, so we
+            # check the behavior of the underlying library implementation
+            # before the actual test
+            socket.inet_pton(socket.AF_INET, "0000.0.0.0")
+        except socket.error:
+            self.assertRaises(ValueError, addr_parse, "0000.0.0.0")
         self.assertRaises(ValueError, addr_parse, "bada:ddr0::")
         self.assertRaises(ValueError, addr_parse, "2001:db8::/32")
         # This should be one part too long (eg. 9 segments)
@@ -72,6 +79,7 @@ class TestCheckIP(unittest.TestCase):
         # It should strip the unnecesarry parts
         self.assertEqual("2001:bd8::", str(addr_parse("2001:bd8:0:0:0:0:0:0")))
         self.assertEqual("::", str(addr_parse("::")))
+        self.assertEqual("2001:bd8::", str(addr_parse("2001:bd8::0.0.0.0")))
 
 if __name__ == "__main__":
     unittest.main()