Skip to content

Instantly share code, notes, and snippets.

@malfaux
Last active December 21, 2015 14:08
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save malfaux/6317110 to your computer and use it in GitHub Desktop.
Save malfaux/6317110 to your computer and use it in GitHub Desktop.
backport of ipaddress.py from python3 to python2
--- /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