Last active
December 21, 2015 14:08
-
-
Save malfaux/6317110 to your computer and use it in GitHub Desktop.
backport of ipaddress.py from python3 to python2
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
--- /usr/lib/python3.3/ipaddress.py 2013-05-21 18:50:37.000000000 +0300 | |
+++ ipaddress.py 2013-08-23 13:22:40.310226926 +0300 | |
@@ -1,5 +1,8 @@ | |
# Copyright 2007 Google Inc. | |
# Licensed to PSF under a Contributor Agreement. | |
+# | |
+# backported to python 2.x by (malfaux) cia@mud.ro | |
+# | |
"""A fast, lightweight IPv4/IPv6 manipulation library in Python. | |
@@ -8,9 +11,16 @@ | |
""" | |
-__version__ = '1.0' | |
+#bumped minver to notify new features and bugfixes | |
+__version__ = '1.1' | |
+import sys | |
+if sys.version_info[0] > 2: | |
+ long = int | |
+ #TODO: fixbelow nastyhack | |
+ ord = lambda x: x | |
+ | |
import functools | |
IPV4LENGTH = 32 | |
@@ -24,6 +34,35 @@ | |
"""A Value Error related to the netmask.""" | |
+from struct import pack, unpack | |
+def to_bytes(num, length, byteorder = 'big'): | |
+ """ | |
+ dummy adaptation of python3 int.to_bytes | |
+ it accepts only 'big' endianess and only 4 and 16 byte lengths, | |
+ exactly what is needed for this module | |
+ """ | |
+ if length != 4 and length != 16: | |
+ raise ValueError("unacceptable length") | |
+ if byteorder != 'big': | |
+ raise ValueError("unacceptable endianess %s" % byteorder) | |
+ if length == 16: | |
+ return pack('>QQ',num>>64, num & 0xffffffffffffffff) | |
+ return pack('>I', num) | |
+ | |
+def from_bytes(bytestr, byteorder = 'big'): | |
+ """ | |
+ dummy adaptation of python3's int.from_bytes | |
+ it accepts only 'big' endianess and only 4 and 16 byte lengths, | |
+ exactly what is needed for this module | |
+ """ | |
+ if len(bytestr) == 16: | |
+ qords = unpack('>QQ', bytestr) | |
+ return qords[0] << 64 + qords[1] & 0xffffffffffffffff | |
+ elif len(bytestr) == 4: | |
+ return unpack('>I', bytestr)[0] | |
+ raise ValueError("bytestring must have a length of either 4 or 16 bytes") | |
+ | |
+ | |
def ip_address(address): | |
"""Take an IP string/int and return an object of the correct type. | |
@@ -53,6 +92,9 @@ | |
raise ValueError('%r does not appear to be an IPv4 or IPv6 address' % | |
address) | |
+def ip4to6(address): | |
+ """IPv4-mapped IPv6 addresses""" | |
+ return IPv6Address('::ffff:%s' % IPv4Address(address)) | |
def ip_network(address, strict=True): | |
"""Take an IP string/int and return an object of the correct type. | |
@@ -134,7 +176,7 @@ | |
""" | |
try: | |
- return address.to_bytes(4, 'big') | |
+ return to_bytes(address, 4, 'big') | |
except: | |
raise ValueError("Address negative or too large for IPv4") | |
@@ -150,9 +192,9 @@ | |
""" | |
try: | |
- return address.to_bytes(16, 'big') | |
- except: | |
- raise ValueError("Address negative or too large for IPv6") | |
+ return to_bytes(address, 16, 'big') | |
+ except Exception as e: | |
+ raise e | |
def _split_optional_netmask(address): | |
@@ -1048,11 +1090,13 @@ | |
octets = ip_str.split('.') | |
if len(octets) != 4: | |
raise AddressValueError("Expected 4 octets in %r" % ip_str) | |
- | |
try: | |
- return int.from_bytes(map(self._parse_octet, octets), 'big') | |
- except ValueError as exc: | |
- raise AddressValueError("%s in %r" % (exc, ip_str)) from None | |
+ parsed_octets = map(self._parse_octet, octets) | |
+ packedbytes = pack('BBBB', *tuple(parsed_octets)) | |
+ intfrombytes = from_bytes(packedbytes, 'big') | |
+ return intfrombytes | |
+ except Exception as e: | |
+ raise | |
def _parse_octet(self, octet_str): | |
"""Convert a decimal octet into an integer. | |
@@ -1100,7 +1144,8 @@ | |
The IP address as a string in dotted decimal notation. | |
""" | |
- return '.'.join(map(str, ip_int.to_bytes(4, 'big'))) | |
+ #BUG | |
+ return '.'.join(map(lambda x:str(ord(x)), to_bytes(ip_int, 4, 'big'))) | |
def _is_valid_netmask(self, netmask): | |
"""Verify that the netmask is valid. | |
@@ -1193,15 +1238,15 @@ | |
return | |
# Constructing from a packed address | |
- if isinstance(address, bytes): | |
+ #python 2.x conversion: in 2.x, str isinnstance of bytes | |
+ if len(address) == 4 and address.find('.', 0, 4) >= 0: | |
self._check_packed_address(address, 4) | |
- self._ip = int.from_bytes(address, 'big') | |
+ self._ip = from_bytes(address, 'big') | |
return | |
# Assume input argument to be string or any object representation | |
# which converts into a formatted IP string. | |
- addr_str = str(address) | |
- self._ip = self._ip_int_from_string(addr_str) | |
+ self._ip = self._ip_int_from_string(str(address)) | |
@property | |
def packed(self): | |
@@ -1407,7 +1452,8 @@ | |
_BaseNetwork.__init__(self, address) | |
# Constructing from a packed address | |
- if isinstance(address, bytes): | |
+ #if isinstance(address, bytes): | |
+ if len(address) == 4 and address.find('.', 0, 4) >= 0: | |
self.network_address = IPv4Address(address) | |
self._prefixlen = self._max_prefixlen | |
self.netmask = IPv4Address(self._ALL_ONES) | |
@@ -1511,9 +1557,9 @@ | |
# If the address has an IPv4-style suffix, convert it to hexadecimal. | |
if '.' in parts[-1]: | |
try: | |
- ipv4_int = IPv4Address(parts.pop())._ip | |
+ ipv4_int = long(IPv4Address(parts.pop())._ip) | |
except AddressValueError as exc: | |
- raise AddressValueError("%s in %r" % (exc, ip_str)) from None | |
+ raise AddressValueError("%s in %r" % (exc, ip_str)) | |
parts.append('%x' % ((ipv4_int >> 16) & 0xFFFF)) | |
parts.append('%x' % (ipv4_int & 0xFFFF)) | |
@@ -1575,7 +1621,7 @@ | |
try: | |
# Now, parse the hextets into a 128-bit integer. | |
- ip_int = 0 | |
+ ip_int = long(0) | |
for i in range(parts_hi): | |
ip_int <<= 16 | |
ip_int |= self._parse_hextet(parts[i]) | |
@@ -1585,7 +1631,7 @@ | |
ip_int |= self._parse_hextet(parts[i]) | |
return ip_int | |
except ValueError as exc: | |
- raise AddressValueError("%s in %r" % (exc, ip_str)) from None | |
+ raise AddressValueError("%s in %r" % (exc, ip_str)) | |
def _parse_hextet(self, hextet_str): | |
"""Convert an IPv6 hextet string into an integer. | |
@@ -1673,7 +1719,7 @@ | |
""" | |
if ip_int is None: | |
- ip_int = int(self._ip) | |
+ ip_int = long(self._ip) | |
if ip_int > self._ALL_ONES: | |
raise ValueError('IPv6 address is too large') | |
@@ -1742,15 +1788,19 @@ | |
_BaseV6.__init__(self, address) | |
# Efficient constructor from integer. | |
- if isinstance(address, int): | |
+ #backward-compatibility: in 2.x there's a long class | |
+ #if isinstance(address, int): | |
+ if isinstance(address, long): | |
self._check_int_address(address) | |
self._ip = address | |
return | |
# Constructing from a packed address | |
- if isinstance(address, bytes): | |
+ #if isinstance(address, bytes): | |
+ if len(address) == 16 and address.find(':', 0, 6) < 0: | |
self._check_packed_address(address, 16) | |
- self._ip = int.from_bytes(address, 'big') | |
+ #self._ip = int.from_bytes(address, 'big') | |
+ self._ip = from_bytes(address, 'big') | |
return | |
# Assume input argument to be string or any object representation | |
@@ -2022,14 +2072,18 @@ | |
_BaseNetwork.__init__(self, address) | |
# Efficient constructor from integer. | |
- if isinstance(address, int): | |
+ if isinstance(address, long): | |
self.network_address = IPv6Address(address) | |
self._prefixlen = self._max_prefixlen | |
self.netmask = IPv6Address(self._ALL_ONES) | |
return | |
# Constructing from a packed address | |
- if isinstance(address, bytes): | |
+ # bytes_instance | |
+ #if isinstance(address, bytes): | |
+ #if isinstance(address, bytes) and len(address) == 16 and | |
+ | |
+ if len(address) == 16 and address.find(':', 0, 6) < 0: | |
self.network_address = IPv6Address(address) | |
self._prefixlen = self._max_prefixlen | |
self.netmask = IPv6Address(self._ALL_ONES) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment