diff --git a/scapy/pton_ntop.py b/scapy/pton_ntop.py
index 76e2dc874e22677cb9dde839722bb9104d8c1626..8e6e82039e68d8dfd31bff4fad9dba50e77cce83 100644
--- a/scapy/pton_ntop.py
+++ b/scapy/pton_ntop.py
@@ -14,79 +14,115 @@ import socket
 import re
 
 _IP6_ZEROS = re.compile('(?::|^)(0(?::0)+)(?::|$)')
+_INET6_PTON_EXC = socket.error("illegal IP address string passed to inet_pton")
 
-def inet_pton(af, addr):
-    """Convert an IP address from text representation into binary form"""
-    if af == socket.AF_INET:
-        return socket.inet_aton(addr)
-    elif af == socket.AF_INET6:
-        # Use inet_pton if available
-        try:
-            return socket.inet_pton(af, addr)
-        except AttributeError:
-            pass
-        joker_pos = None
-        result = ""
-        parts = addr.split(":")
-        nparts = len(parts)
-        for i, part in enumerate(parts):
-            if not part:
-                # "::" indicates one or more groups of 2 null bytes
-                if joker_pos is None:
-                    joker_pos = len(result)
-                else:
-                    # Wildcard is only allowed once
-                    raise Exception("Illegal syntax for IP address")
-            elif i + 1 == nparts and '.' in part:
-                # The last part of an IPv6 address can be an IPv4 address
-                try:
-                    result += socket.inet_aton(part)
-                except socket.error:
-                    raise Exception("Illegal syntax for IP address")
+def _inet6_pton(addr):
+    """Convert an IPv6 address from text representation into binary form,
+used when socket.inet_pton is not available.
+
+    """
+    joker_pos = None
+    result = ""
+    if addr == '::':
+        return '\x00' * 16
+    if addr.startswith('::'):
+        addr = addr[1:]
+    if addr.endswith('::'):
+        addr = addr[:-1]
+    parts = addr.split(":")
+    nparts = len(parts)
+    for i, part in enumerate(parts):
+        if not part:
+            # "::" indicates one or more groups of 2 null bytes
+            if joker_pos is None:
+                joker_pos = len(result)
             else:
-                # Each part must be 16bit. Add missing zeroes before decoding. 
-                try:
-                    result += part.rjust(4, "0").decode("hex")
-                except TypeError:
-                    raise Exception("Illegal syntax for IP address")
-        # If there's a wildcard, fill up with zeros to reach 128bit (16 bytes) 
-        if joker_pos is not None:
-            result = (result[:joker_pos] + "\x00" * (16 - len(result))
-                      + result[joker_pos:])
-        if len(result) != 16:
-            raise Exception("Illegal syntax for IP address")
-        return result 
-    else:
-        raise Exception("Address family not supported")
+                # Wildcard is only allowed once
+                raise _INET6_PTON_EXC
+        elif i + 1 == nparts and '.' in part:
+            # The last part of an IPv6 address can be an IPv4 address
+            if part.count('.') != 3:
+                # we have to do this since socket.inet_aton('1.2') ==
+                # '\x01\x00\x00\x02'
+                raise _INET6_PTON_EXC
+            try:
+                result += socket.inet_aton(part)
+            except socket.error:
+                raise _INET6_PTON_EXC
+        else:
+            # Each part must be 16bit. Add missing zeroes before decoding.
+            try:
+                result += part.rjust(4, "0").decode("hex")
+            except TypeError:
+                raise _INET6_PTON_EXC
+    # If there's a wildcard, fill up with zeros to reach 128bit (16 bytes)
+    if joker_pos is not None:
+        if len(result) == 16:
+            raise _INET6_PTON_EXC
+        result = (result[:joker_pos] + "\x00" * (16 - len(result))
+                  + result[joker_pos:])
+    if len(result) != 16:
+        raise _INET6_PTON_EXC
+    return result
 
 
-def inet_ntop(af, addr):
-    """Convert an IP address from binary form into text representation"""
-    if af == socket.AF_INET:
-        return socket.inet_ntoa(addr)
-    elif af == socket.AF_INET6:
-        # Use inet_ntop if available
+_INET_PTON = {
+    socket.AF_INET: socket.inet_aton,
+    socket.AF_INET6: _inet6_pton,
+}
+
+
+def inet_pton(af, addr):
+    """Convert an IP address from text representation into binary form."""
+    # Use inet_pton if available
+    try:
+        return socket.inet_pton(af, addr)
+    except AttributeError:
         try:
-            return socket.inet_ntop(af, addr)
-        except AttributeError:
-            return _ipv6_bin_to_str(addr)
-    else:
-        raise Exception("Address family not supported yet")
+            return _INET_PTON[af](addr)
+        except KeyError:
+            raise socket.error("Address family not supported by protocol")
 
 
-def _ipv6_bin_to_str(addr):
+def _inet6_ntop(addr):
+    """Convert an IPv6 address from binary form into text representation,
+used when socket.inet_pton is not available.
+
+    """
     # IPv6 addresses have 128bits (16 bytes)
     if len(addr) != 16:
         raise ValueError("invalid length of packed IP address string")
 
     # Decode to hex representation
-    address = ":".join(addr[idx:idx + 2].encode('hex').lstrip('0') or '0' for idx in xrange(0, 16, 2))
+    address = ":".join(addr[idx:idx + 2].encode('hex').lstrip('0') or '0'
+                       for idx in xrange(0, 16, 2))
 
     try:
-        # Get the longest set of zero blocks
-        # Actually we need to take a look at group 1 regarding the length as 0:0:1:0:0:2:3:4 would have two matches:
-        # 0:0: and :0:0: where the latter is longer, though the first one should be taken. Group 1 is in both cases 0:0.
-        match = max(_IP6_ZEROS.finditer(address), key=lambda m: m.end(1) - m.start(1))
+        # Get the longest set of zero blocks. We need to take a look
+        # at group 1 regarding the length, as 0:0:1:0:0:2:3:4 would
+        # have two matches: 0:0: and :0:0: where the latter is longer,
+        # though the first one should be taken. Group 1 is in both
+        # cases 0:0.
+        match = max(_IP6_ZEROS.finditer(address),
+                    key=lambda m: m.end(1) - m.start(1))
         return '{}::{}'.format(address[:match.start()], address[match.end():])
     except ValueError:
         return address
+
+
+_INET_NTOP = {
+    socket.AF_INET: socket.inet_ntoa,
+    socket.AF_INET6: _inet6_ntop,
+}
+
+
+def inet_ntop(af, addr):
+    """Convert an IP address from binary form into text representation."""
+    # Use inet_ntop if available
+    try:
+        return socket.inet_ntop(af, addr)
+    except AttributeError:
+        try:
+            return _INET_NTOP[af](addr)
+        except KeyError:
+            raise ValueError("unknown address family %d" % af)
diff --git a/test/regression.uts b/test/regression.uts
index 36d2fef2af0b996c88269c90e646e6f57f1cedf9..c74e5379460ddd200a4c0f9184ee6516041a5613 100644
--- a/test/regression.uts
+++ b/test/regression.uts
@@ -7253,78 +7253,55 @@ assert(re.match(r'^.*bit 2.*$', x) is not None)
 ############
 + Test correct conversion from binary to string of IPv6 addresses
 
-= IPv6 bin to string conversion - all zero bytes
-from scapy.pton_ntop import _ipv6_bin_to_str, inet_ntop
+= IPv6 bin to string conversion
+from scapy.pton_ntop import _inet6_ntop, inet_ntop
 import socket
-address=b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' # All zero
-compressed1, compressed2 = _ipv6_bin_to_str(address), inet_ntop(socket.AF_INET6, address)
-assert(compressed1 == compressed2 == '::')
-
-= IPv6 bin to string conversion - non-compressable
-from scapy.pton_ntop import _ipv6_bin_to_str, inet_ntop
-import socket
-address=b'\x11\x11\x22\x22\x33\x33\x44\x44\x55\x55\x66\x66\x77\x77\x88\x88' # Not compressable
-compressed1, compressed2 = _ipv6_bin_to_str(address), inet_ntop(socket.AF_INET6, address)
-assert(compressed1 == compressed2 == '1111:2222:3333:4444:5555:6666:7777:8888')
-
-= IPv6 bin to string conversion - Zero-block right
-from scapy.pton_ntop import _ipv6_bin_to_str, inet_ntop
-import socket
-address=b'\x11\x11\x22\x22\x33\x33\x44\x44\x55\x55\x00\x00\x00\x00\x00\x00' # Zeroblock right
-compressed1, compressed2 = _ipv6_bin_to_str(address), inet_ntop(socket.AF_INET6, address)
-assert(compressed1 == compressed2 == '1111:2222:3333:4444:5555::')
-
-= IPv6 bin to string conversion - Zero-block left
-from scapy.pton_ntop import _ipv6_bin_to_str, inet_ntop
-import socket
-address=b'\x00\x00\x00\x00\x00\x00\x44\x44\x55\x55\x66\x66\x77\x77\x88\x88' # Zeroblock left
-compressed1, compressed2 = _ipv6_bin_to_str(address), inet_ntop(socket.AF_INET6, address)
-assert(compressed1 == compressed2 == '::4444:5555:6666:7777:8888')
-
-= IPv6 bin to string conversion - Two zero-block with different length
-from scapy.pton_ntop import _ipv6_bin_to_str, inet_ntop
-import socket
-address=b'\x00\x00\x00\x00\x33\x33\x44\x44\x00\x00\x00\x00\x00\x00\x88\x88' # Short and long zero block
-compressed1, compressed2 = _ipv6_bin_to_str(address), inet_ntop(socket.AF_INET6, address)
-assert(compressed1 == compressed2 == '0:0:3333:4444::8888')
-
-= IPv6 bin to string conversion - Address 1::
-from scapy.pton_ntop import _ipv6_bin_to_str, inet_ntop
-import socket
-address=b'\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' # only 1 on the left
-compressed1, compressed2 = _ipv6_bin_to_str(address), inet_ntop(socket.AF_INET6, address)
-assert(compressed1 == compressed2 == '1::')
-
-= IPv6 bin to string conversion - Address ::1
-from scapy.pton_ntop import _ipv6_bin_to_str, inet_ntop
-import socket
-address=b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01' # loopback
-compressed1, compressed2 = _ipv6_bin_to_str(address), inet_ntop(socket.AF_INET6, address)
-assert(compressed1 == compressed2 == '::1')
+for binfrm, address in [
+        ('\x00' * 16, '::'),
+        ('\x11\x11\x22\x22\x33\x33\x44\x44\x55\x55\x66\x66\x77\x77\x88\x88',
+         '1111:2222:3333:4444:5555:6666:7777:8888'),
+        ('\x11\x11\x22\x22\x33\x33\x44\x44\x55\x55\x00\x00\x00\x00\x00\x00',
+         '1111:2222:3333:4444:5555::'),
+        ('\x00\x00\x00\x00\x00\x00\x44\x44\x55\x55\x66\x66\x77\x77\x88\x88',
+         '::4444:5555:6666:7777:8888'),
+        ('\x00\x00\x00\x00\x33\x33\x44\x44\x00\x00\x00\x00\x00\x00\x88\x88',
+         '0:0:3333:4444::8888'),
+        ('\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
+         '1::'),
+        ('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01',
+         '::1'),
+        ('\x11\x11\x00\x00\x00\x00\x44\x44\x00\x00\x00\x00\x77\x77\x88\x88',
+         '1111::4444:0:0:7777:8888'),
+        ('\x10\x00\x02\x00\x00\x30\x00\x04\x00\x05\x00\x60\x07\x00\x80\x00',
+         '1000:200:30:4:5:60:700:8000'),
+]:
+    addr1 = inet_ntop(socket.AF_INET6, binfrm)
+    addr2 = _inet6_ntop(binfrm)
+    assert address == addr1 == addr2
 
 = IPv6 bin to string conversion - Zero-block of length 1
-from scapy.pton_ntop import _ipv6_bin_to_str, inet_ntop
-import socket
-address=b'\x11\x11\x22\x22\x33\x33\x44\x44\x55\x55\x66\x66\x00\x00\x88\x88' # only one zero block
-compressed1, compressed2 = _ipv6_bin_to_str(address), inet_ntop(socket.AF_INET6, address)
-assert(compressed1 == '1111:2222:3333:4444:5555:6666:0:8888')
-# On Mac OS socket.inet_ntop is not fully compliant with RFC 5952 and shortens the single zero block to '::'. Still
-# this is a valid IPv6 address representation.
-assert(compressed2 in ('1111:2222:3333:4444:5555:6666:0:8888', '1111:2222:3333:4444:5555:6666::8888'))
-
-= IPv6 bin to string conversion - Two zero-blocks with equal length
-from scapy.pton_ntop import _ipv6_bin_to_str, inet_ntop
-import socket
-address=b'\x11\x11\x00\x00\x00\x00\x44\x44\x00\x00\x00\x00\x77\x77\x88\x88' # two zero blocks of equal length
-compressed1, compressed2 = _ipv6_bin_to_str(address), inet_ntop(socket.AF_INET6, address)
-assert(compressed1 == compressed2 == '1111::4444:0:0:7777:8888')
-
-= IPv6 bin to string conversion - Leading zero suppression
-from scapy.pton_ntop import _ipv6_bin_to_str, inet_ntop
-import socket
-address=b'\x10\x00\x02\x00\x00\x30\x00\x04\x00\x05\x00\x60\x07\x00\x80\x00' # Leading zero suppression
-compressed1, compressed2 = _ipv6_bin_to_str(address), inet_ntop(socket.AF_INET6, address)
-assert(compressed1 == compressed2 == '1000:200:30:4:5:60:700:8000')
+binfrm = '\x11\x11\x22\x22\x33\x33\x44\x44\x55\x55\x66\x66\x00\x00\x88\x88'
+addr1, addr2 = inet_ntop(socket.AF_INET6, binfrm), _inet6_ntop(binfrm)
+# On Mac OS socket.inet_ntop is not fully compliant with RFC 5952 and
+# shortens the single zero block to '::'. This is a valid IPv6 address
+# representation anyway.
+assert(addr1 in ['1111:2222:3333:4444:5555:6666:0:8888',
+                 '1111:2222:3333:4444:5555:6666::8888'])
+assert(addr2 == '1111:2222:3333:4444:5555:6666:0:8888')
+
+= IPv6 bin to string conversion - Illegal sizes
+for binfrm in ["\x00" * 15, "\x00" * 17]:
+    rc = False
+    try:
+        inet_ntop(socket.AF_INET6, binfrm)
+    except Exception as exc1:
+        rc = True
+    assert rc
+    try:
+        _inet6_ntop(binfrm)
+    except Exception as exc2:
+        rc = isinstance(exc2, type(exc1))
+    assert rc
 
 
 ############
@@ -7466,31 +7443,46 @@ in6_getscope("::1") == IPV6_ADDR_LOOPBACK
 
 = inet_pton()
 
+from scapy.pton_ntop import _inet6_pton, inet_pton
 import socket
 
 ip6_bad_addrs = ["fe80::2e67:ef2d:7eca::ed8a",
                  "fe80:1234:abcd::192.168.40.12:abcd",
                  "fe80:1234:abcd::192.168.40",
-                 "fe80:1234:abcd::192.168.400.12"]
+                 "fe80:1234:abcd::192.168.400.12",
+		 "1234:5678:9abc:def0:1234:5678:9abc:def0:",
+		 "1234:5678:9abc:def0:1234:5678:9abc:def0:1234"]
 for ip6 in ip6_bad_addrs:
     rc = False
     try:
-        inet_pton(socket.AF_INET6, ip6)
-    except Exception, e:
+        res1 = inet_pton(socket.AF_INET6, ip6)
+    except Exception as exc1:
         rc = True
     assert rc
-
-ip6_good_addrs = ["fe80:1234:abcd::192.168.40.12",
-                 "fe80:1234:abcd::fe06",
-                 "fe80::2e67:ef2d:7ece:ed8a"]
-for ip6 in ip6_good_addrs:
-    rc = True
+    rc = False
     try:
-        inet_pton(socket.AF_INET6, ip6)
-    except Exception, e:
-        rc = False
+        res2 = _inet6_pton(ip6)
+    except Exception as exc2:
+        rc = isinstance(exc2, type(exc1))
     assert rc
 
+ip6_good_addrs = [("fe80:1234:abcd::192.168.40.12",
+                   '\xfe\x80\x124\xab\xcd\x00\x00\x00\x00\x00\x00\xc0\xa8(\x0c'),
+                  ("fe80:1234:abcd::fe06",
+                   '\xfe\x80\x124\xab\xcd\x00\x00\x00\x00\x00\x00\x00\x00\xfe\x06'),
+                  ("fe80::2e67:ef2d:7ece:ed8a",
+                   '\xfe\x80\x00\x00\x00\x00\x00\x00.g\xef-~\xce\xed\x8a'),
+		  ("::ffff",
+                   '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff'),
+		  ("ffff::",
+                   '\xff\xff\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'),
+		  ('::', '\x00' * 16)]
+for ip6, res in ip6_good_addrs:
+    res1 = inet_pton(socket.AF_INET6, ip6)
+    res2 = _inet6_pton(ip6)
+    assert res == res1 == res2
+
+
 ############
 ############
 + Test Route class