mirror of
https://github.com/retspen/webvirtcloud
synced 2024-11-01 03:54:15 +00:00
update IPy.py to handle python3.10 and update readme
This commit is contained in:
parent
9e832c2612
commit
e0767f4145
2 changed files with 268 additions and 273 deletions
|
@ -32,7 +32,7 @@ WebVirtCloud is a virtualization web interface for admins and users. It can dele
|
||||||
|
|
||||||
## Quick Install with Installer (Beta)
|
## Quick Install with Installer (Beta)
|
||||||
|
|
||||||
Install an OS and run specified commands. Installer supported OSes: Ubuntu 18.04, Debian 10, Centos/OEL/RHEL 8.
|
Install an OS and run specified commands. Installer supported OSes: Ubuntu 18.04/20.04, Debian 10/11, Centos/OEL/RHEL 8.
|
||||||
It can be installed on a virtual machine, physical host or on a KVM host.
|
It can be installed on a virtual machine, physical host or on a KVM host.
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
|
|
|
@ -6,27 +6,29 @@ Further Information might be available at:
|
||||||
https://github.com/haypo/python-ipy
|
https://github.com/haypo/python-ipy
|
||||||
"""
|
"""
|
||||||
|
|
||||||
__version__ = "1.00"
|
__version__ = '1.01'
|
||||||
|
|
||||||
import bisect
|
import bisect
|
||||||
import collections
|
|
||||||
import sys
|
|
||||||
import types
|
import types
|
||||||
|
try:
|
||||||
|
import collections.abc as collections_abc
|
||||||
|
except ImportError:
|
||||||
|
import collections as collections_abc
|
||||||
|
|
||||||
# Definition of the Ranges for IPv4 IPs
|
# Definition of the Ranges for IPv4 IPs
|
||||||
# this should include www.iana.org/assignments/ipv4-address-space
|
# this should include www.iana.org/assignments/ipv4-address-space
|
||||||
# and www.iana.org/assignments/multicast-addresses
|
# and www.iana.org/assignments/multicast-addresses
|
||||||
IPv4ranges = {
|
IPv4ranges = {
|
||||||
"0": "PUBLIC", # fall back
|
'0': 'PUBLIC', # fall back
|
||||||
"00000000": "PRIVATE", # 0/8
|
'00000000': 'PRIVATE', # 0/8
|
||||||
"00001010": "PRIVATE", # 10/8
|
'00001010': 'PRIVATE', # 10/8
|
||||||
"0110010001": "CARRIER_GRADE_NAT", # 100.64/10
|
'0110010001': 'CARRIER_GRADE_NAT', #100.64/10
|
||||||
"01111111": "LOOPBACK", # 127.0/8
|
'01111111': 'LOOPBACK', # 127.0/8
|
||||||
"1": "PUBLIC", # fall back
|
'1': 'PUBLIC', # fall back
|
||||||
"1010100111111110": "PRIVATE", # 169.254/16
|
'1010100111111110': 'PRIVATE', # 169.254/16
|
||||||
"101011000001": "PRIVATE", # 172.16/12
|
'101011000001': 'PRIVATE', # 172.16/12
|
||||||
"1100000010101000": "PRIVATE", # 192.168/16
|
'1100000010101000': 'PRIVATE', # 192.168/16
|
||||||
"111": "RESERVED", # 224/3
|
'111': 'RESERVED', # 224/3
|
||||||
}
|
}
|
||||||
|
|
||||||
# Definition of the Ranges for IPv6 IPs
|
# Definition of the Ranges for IPv6 IPs
|
||||||
|
@ -34,100 +36,101 @@ IPv4ranges = {
|
||||||
# http://www.iana.org/assignments/ipv6-unicast-address-assignments/
|
# http://www.iana.org/assignments/ipv6-unicast-address-assignments/
|
||||||
# http://www.iana.org/assignments/ipv6-multicast-addresses/
|
# http://www.iana.org/assignments/ipv6-multicast-addresses/
|
||||||
IPv6ranges = {
|
IPv6ranges = {
|
||||||
"00000000": "RESERVED", # ::/8
|
'00000000' : 'RESERVED', # ::/8
|
||||||
"0" * 96: "RESERVED", # ::/96 Formerly IPV4COMP [RFC4291]
|
'0' * 96 : 'RESERVED', # ::/96 Formerly IPV4COMP [RFC4291]
|
||||||
"0" * 128: "UNSPECIFIED", # ::/128
|
'0' * 128 : 'UNSPECIFIED', # ::/128
|
||||||
"0" * 127 + "1": "LOOPBACK", # ::1/128
|
'0' * 127 + '1' : 'LOOPBACK', # ::1/128
|
||||||
"0" * 80 + "1" * 16: "IPV4MAP", # ::ffff:0:0/96
|
'0' * 80 + '1' * 16 : 'IPV4MAP', # ::ffff:0:0/96
|
||||||
"00000000011001001111111110011011" + "0" * 64: "WKP46TRANS", # 0064:ff9b::/96 Well-Known-Prefix [RFC6052]
|
'00000000011001001111111110011011' + '0' * 64 : 'WKP46TRANS', # 0064:ff9b::/96 Well-Known-Prefix [RFC6052]
|
||||||
"00000001": "UNASSIGNED", # 0100::/8
|
'00000001' : 'UNASSIGNED', # 0100::/8
|
||||||
"0000001": "RESERVED", # 0200::/7 Formerly NSAP [RFC4048]
|
'0000001' : 'RESERVED', # 0200::/7 Formerly NSAP [RFC4048]
|
||||||
"0000010": "RESERVED", # 0400::/7 Formerly IPX [RFC3513]
|
'0000010' : 'RESERVED', # 0400::/7 Formerly IPX [RFC3513]
|
||||||
"0000011": "RESERVED", # 0600::/7
|
'0000011' : 'RESERVED', # 0600::/7
|
||||||
"00001": "RESERVED", # 0800::/5
|
'00001' : 'RESERVED', # 0800::/5
|
||||||
"0001": "RESERVED", # 1000::/4
|
'0001' : 'RESERVED', # 1000::/4
|
||||||
"001": "GLOBAL-UNICAST", # 2000::/3 [RFC4291]
|
'001' : 'GLOBAL-UNICAST', # 2000::/3 [RFC4291]
|
||||||
"00100000000000010000000": "SPECIALPURPOSE", # 2001::/23 [RFC4773]
|
'00100000000000010000000' : 'SPECIALPURPOSE', # 2001::/23 [RFC4773]
|
||||||
"00100000000000010000000000000000": "TEREDO", # 2001::/32 [RFC4380]
|
'00100000000000010000000000000000' : 'TEREDO', # 2001::/32 [RFC4380]
|
||||||
"00100000000000010000000000000010" + "0" * 16: "BMWG", # 2001:0002::/48 Benchmarking [RFC5180]
|
'00100000000000010000000000000010' + '0' * 16 : 'BMWG', # 2001:0002::/48 Benchmarking [RFC5180]
|
||||||
"0010000000000001000000000001": "ORCHID", # 2001:0010::/28 (Temp until 2014-03-21) [RFC4843]
|
'0010000000000001000000000001' : 'ORCHID', # 2001:0010::/28 (Temp until 2014-03-21) [RFC4843]
|
||||||
"00100000000000010000001": "ALLOCATED APNIC", # 2001:0200::/23
|
'00100000000000010000001' : 'ALLOCATED APNIC', # 2001:0200::/23
|
||||||
"00100000000000010000010": "ALLOCATED ARIN", # 2001:0400::/23
|
'00100000000000010000010' : 'ALLOCATED ARIN', # 2001:0400::/23
|
||||||
"00100000000000010000011": "ALLOCATED RIPE NCC", # 2001:0600::/23
|
'00100000000000010000011' : 'ALLOCATED RIPE NCC', # 2001:0600::/23
|
||||||
"00100000000000010000100": "ALLOCATED RIPE NCC", # 2001:0800::/23
|
'00100000000000010000100' : 'ALLOCATED RIPE NCC', # 2001:0800::/23
|
||||||
"00100000000000010000101": "ALLOCATED RIPE NCC", # 2001:0a00::/23
|
'00100000000000010000101' : 'ALLOCATED RIPE NCC', # 2001:0a00::/23
|
||||||
"00100000000000010000110": "ALLOCATED APNIC", # 2001:0c00::/23
|
'00100000000000010000110' : 'ALLOCATED APNIC', # 2001:0c00::/23
|
||||||
"00100000000000010000110110111000": "DOCUMENTATION", # 2001:0db8::/32 [RFC3849]
|
'00100000000000010000110110111000' : 'DOCUMENTATION', # 2001:0db8::/32 [RFC3849]
|
||||||
"00100000000000010000111": "ALLOCATED APNIC", # 2001:0e00::/23
|
'00100000000000010000111' : 'ALLOCATED APNIC', # 2001:0e00::/23
|
||||||
"00100000000000010001001": "ALLOCATED LACNIC", # 2001:1200::/23
|
'00100000000000010001001' : 'ALLOCATED LACNIC', # 2001:1200::/23
|
||||||
"00100000000000010001010": "ALLOCATED RIPE NCC", # 2001:1400::/23
|
'00100000000000010001010' : 'ALLOCATED RIPE NCC', # 2001:1400::/23
|
||||||
"00100000000000010001011": "ALLOCATED RIPE NCC", # 2001:1600::/23
|
'00100000000000010001011' : 'ALLOCATED RIPE NCC', # 2001:1600::/23
|
||||||
"00100000000000010001100": "ALLOCATED ARIN", # 2001:1800::/23
|
'00100000000000010001100' : 'ALLOCATED ARIN', # 2001:1800::/23
|
||||||
"00100000000000010001101": "ALLOCATED RIPE NCC", # 2001:1a00::/23
|
'00100000000000010001101' : 'ALLOCATED RIPE NCC', # 2001:1a00::/23
|
||||||
"0010000000000001000111": "ALLOCATED RIPE NCC", # 2001:1c00::/22
|
'0010000000000001000111' : 'ALLOCATED RIPE NCC', # 2001:1c00::/22
|
||||||
"00100000000000010010": "ALLOCATED RIPE NCC", # 2001:2000::/20
|
'00100000000000010010' : 'ALLOCATED RIPE NCC', # 2001:2000::/20
|
||||||
"001000000000000100110": "ALLOCATED RIPE NCC", # 2001:3000::/21
|
'001000000000000100110' : 'ALLOCATED RIPE NCC', # 2001:3000::/21
|
||||||
"0010000000000001001110": "ALLOCATED RIPE NCC", # 2001:3800::/22
|
'0010000000000001001110' : 'ALLOCATED RIPE NCC', # 2001:3800::/22
|
||||||
"0010000000000001001111": "RESERVED", # 2001:3c00::/22 Possible future allocation to RIPE NCC
|
'0010000000000001001111' : 'RESERVED', # 2001:3c00::/22 Possible future allocation to RIPE NCC
|
||||||
"00100000000000010100000": "ALLOCATED RIPE NCC", # 2001:4000::/23
|
'00100000000000010100000' : 'ALLOCATED RIPE NCC', # 2001:4000::/23
|
||||||
"00100000000000010100001": "ALLOCATED AFRINIC", # 2001:4200::/23
|
'00100000000000010100001' : 'ALLOCATED AFRINIC', # 2001:4200::/23
|
||||||
"00100000000000010100010": "ALLOCATED APNIC", # 2001:4400::/23
|
'00100000000000010100010' : 'ALLOCATED APNIC', # 2001:4400::/23
|
||||||
"00100000000000010100011": "ALLOCATED RIPE NCC", # 2001:4600::/23
|
'00100000000000010100011' : 'ALLOCATED RIPE NCC', # 2001:4600::/23
|
||||||
"00100000000000010100100": "ALLOCATED ARIN", # 2001:4800::/23
|
'00100000000000010100100' : 'ALLOCATED ARIN', # 2001:4800::/23
|
||||||
"00100000000000010100101": "ALLOCATED RIPE NCC", # 2001:4a00::/23
|
'00100000000000010100101' : 'ALLOCATED RIPE NCC', # 2001:4a00::/23
|
||||||
"00100000000000010100110": "ALLOCATED RIPE NCC", # 2001:4c00::/23
|
'00100000000000010100110' : 'ALLOCATED RIPE NCC', # 2001:4c00::/23
|
||||||
"00100000000000010101": "ALLOCATED RIPE NCC", # 2001:5000::/20
|
'00100000000000010101' : 'ALLOCATED RIPE NCC', # 2001:5000::/20
|
||||||
"0010000000000001100": "ALLOCATED APNIC", # 2001:8000::/19
|
'0010000000000001100' : 'ALLOCATED APNIC', # 2001:8000::/19
|
||||||
"00100000000000011010": "ALLOCATED APNIC", # 2001:a000::/20
|
'00100000000000011010' : 'ALLOCATED APNIC', # 2001:a000::/20
|
||||||
"00100000000000011011": "ALLOCATED APNIC", # 2001:b000::/20
|
'00100000000000011011' : 'ALLOCATED APNIC', # 2001:b000::/20
|
||||||
"0010000000000010": "6TO4", # 2002::/16 "6to4" [RFC3056]
|
'0010000000000010' : '6TO4', # 2002::/16 "6to4" [RFC3056]
|
||||||
"001000000000001100": "ALLOCATED RIPE NCC", # 2003::/18
|
'001000000000001100' : 'ALLOCATED RIPE NCC', # 2003::/18
|
||||||
"001001000000": "ALLOCATED APNIC", # 2400::/12
|
'001001000000' : 'ALLOCATED APNIC', # 2400::/12
|
||||||
"001001100000": "ALLOCATED ARIN", # 2600::/12
|
'001001100000' : 'ALLOCATED ARIN', # 2600::/12
|
||||||
"00100110000100000000000": "ALLOCATED ARIN", # 2610::/23
|
'00100110000100000000000' : 'ALLOCATED ARIN', # 2610::/23
|
||||||
"00100110001000000000000": "ALLOCATED ARIN", # 2620::/23
|
'00100110001000000000000' : 'ALLOCATED ARIN', # 2620::/23
|
||||||
"001010000000": "ALLOCATED LACNIC", # 2800::/12
|
'001010000000' : 'ALLOCATED LACNIC', # 2800::/12
|
||||||
"001010100000": "ALLOCATED RIPE NCC", # 2a00::/12
|
'001010100000' : 'ALLOCATED RIPE NCC', # 2a00::/12
|
||||||
"001011000000": "ALLOCATED AFRINIC", # 2c00::/12
|
'001011000000' : 'ALLOCATED AFRINIC', # 2c00::/12
|
||||||
"00101101": "RESERVED", # 2d00::/8
|
'00101101' : 'RESERVED', # 2d00::/8
|
||||||
"0010111": "RESERVED", # 2e00::/7
|
'0010111' : 'RESERVED', # 2e00::/7
|
||||||
"0011": "RESERVED", # 3000::/4
|
'0011' : 'RESERVED', # 3000::/4
|
||||||
"010": "RESERVED", # 4000::/3
|
'010' : 'RESERVED', # 4000::/3
|
||||||
"011": "RESERVED", # 6000::/3
|
'011' : 'RESERVED', # 6000::/3
|
||||||
"100": "RESERVED", # 8000::/3
|
'100' : 'RESERVED', # 8000::/3
|
||||||
"101": "RESERVED", # a000::/3
|
'101' : 'RESERVED', # a000::/3
|
||||||
"110": "RESERVED", # c000::/3
|
'110' : 'RESERVED', # c000::/3
|
||||||
"1110": "RESERVED", # e000::/4
|
'1110' : 'RESERVED', # e000::/4
|
||||||
"11110": "RESERVED", # f000::/5
|
'11110' : 'RESERVED', # f000::/5
|
||||||
"111110": "RESERVED", # f800::/6
|
'111110' : 'RESERVED', # f800::/6
|
||||||
"1111110": "ULA", # fc00::/7 [RFC4193]
|
'1111110' : 'ULA', # fc00::/7 [RFC4193]
|
||||||
"111111100": "RESERVED", # fe00::/9
|
'111111100' : 'RESERVED', # fe00::/9
|
||||||
"1111111010": "LINKLOCAL", # fe80::/10
|
'1111111010' : 'LINKLOCAL', # fe80::/10
|
||||||
"1111111011": "RESERVED", # fec0::/10 Formerly SITELOCAL [RFC4291]
|
'1111111011' : 'RESERVED', # fec0::/10 Formerly SITELOCAL [RFC4291]
|
||||||
"11111111": "MULTICAST", # ff00::/8
|
'11111111' : 'MULTICAST', # ff00::/8
|
||||||
"1111111100000001": "NODE-LOCAL MULTICAST", # ff01::/16
|
'1111111100000001' : 'NODE-LOCAL MULTICAST', # ff01::/16
|
||||||
"1111111100000010": "LINK-LOCAL MULTICAST", # ff02::/16
|
'1111111100000010' : 'LINK-LOCAL MULTICAST', # ff02::/16
|
||||||
"1111111100000100": "ADMIN-LOCAL MULTICAST", # ff04::/16
|
'1111111100000100' : 'ADMIN-LOCAL MULTICAST', # ff04::/16
|
||||||
"1111111100000101": "SITE-LOCAL MULTICAST", # ff05::/16
|
'1111111100000101' : 'SITE-LOCAL MULTICAST', # ff05::/16
|
||||||
"1111111100001000": "ORG-LOCAL MULTICAST", # ff08::/16
|
'1111111100001000' : 'ORG-LOCAL MULTICAST', # ff08::/16
|
||||||
"1111111100001110": "GLOBAL MULTICAST", # ff0e::/16
|
'1111111100001110' : 'GLOBAL MULTICAST', # ff0e::/16
|
||||||
"1111111100001111": "RESERVED MULTICAST", # ff0f::/16
|
'1111111100001111' : 'RESERVED MULTICAST', # ff0f::/16
|
||||||
"111111110011": "PREFIX-BASED MULTICAST", # ff30::/12 [RFC3306]
|
'111111110011' : 'PREFIX-BASED MULTICAST', # ff30::/12 [RFC3306]
|
||||||
"111111110111": "RP-EMBEDDED MULTICAST", # ff70::/12 [RFC3956]
|
'111111110111' : 'RP-EMBEDDED MULTICAST', # ff70::/12 [RFC3956]
|
||||||
}
|
}
|
||||||
|
|
||||||
MAX_IPV4_ADDRESS = 0xFFFFFFFF
|
MAX_IPV4_ADDRESS = 0xffffffff
|
||||||
MAX_IPV6_ADDRESS = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
|
MAX_IPV6_ADDRESS = 0xffffffffffffffffffffffffffffffff
|
||||||
IPV6_TEST_MAP = 0xFFFFFFFFFFFFFFFFFFFFFFFF00000000
|
IPV6_TEST_MAP = 0xffffffffffffffffffffffff00000000
|
||||||
IPV6_MAP_MASK = 0x00000000000000000000FFFF00000000
|
IPV6_MAP_MASK = 0x00000000000000000000ffff00000000
|
||||||
|
|
||||||
if sys.version_info >= (3,):
|
try:
|
||||||
|
INT_TYPES = (int, long)
|
||||||
|
STR_TYPES = (str, unicode)
|
||||||
|
xrange
|
||||||
|
except NameError:
|
||||||
INT_TYPES = (int,)
|
INT_TYPES = (int,)
|
||||||
STR_TYPES = (str,)
|
STR_TYPES = (str,)
|
||||||
xrange = range
|
xrange = range
|
||||||
else:
|
|
||||||
INT_TYPES = (int, long)
|
|
||||||
STR_TYPES = (str, unicode)
|
|
||||||
|
|
||||||
|
|
||||||
class IPint(object):
|
class IPint(object):
|
||||||
|
@ -202,7 +205,7 @@ class IPint(object):
|
||||||
elif isinstance(data, STR_TYPES):
|
elif isinstance(data, STR_TYPES):
|
||||||
# TODO: refactor me!
|
# TODO: refactor me!
|
||||||
# splitting of a string into IP and prefixlen et. al.
|
# splitting of a string into IP and prefixlen et. al.
|
||||||
x = data.split("-")
|
x = data.split('-')
|
||||||
if len(x) == 2:
|
if len(x) == 2:
|
||||||
# a.b.c.0-a.b.c.255 specification ?
|
# a.b.c.0-a.b.c.255 specification ?
|
||||||
(ip, last) = x
|
(ip, last) = x
|
||||||
|
@ -219,10 +222,10 @@ class IPint(object):
|
||||||
# make sure the broadcast is the same as the last ip
|
# make sure the broadcast is the same as the last ip
|
||||||
# otherwise it will return /16 for something like:
|
# otherwise it will return /16 for something like:
|
||||||
# 192.168.0.0-192.168.191.255
|
# 192.168.0.0-192.168.191.255
|
||||||
if IP("%s/%s" % (ip, 32 - netbits)).broadcast().int() != last:
|
if IP('%s/%s' % (ip, 32-netbits)).broadcast().int() != last:
|
||||||
raise ValueError("the range %s is not on a network boundary." % data)
|
raise ValueError("the range %s is not on a network boundary." % data)
|
||||||
elif len(x) == 1:
|
elif len(x) == 1:
|
||||||
x = data.split("/")
|
x = data.split('/')
|
||||||
# if no prefix is given use defaults
|
# if no prefix is given use defaults
|
||||||
if len(x) == 1:
|
if len(x) == 1:
|
||||||
ip = x[0]
|
ip = x[0]
|
||||||
|
@ -231,7 +234,7 @@ class IPint(object):
|
||||||
raise ValueError("only one '/' allowed in IP Address")
|
raise ValueError("only one '/' allowed in IP Address")
|
||||||
else:
|
else:
|
||||||
(ip, prefixlen) = x
|
(ip, prefixlen) = x
|
||||||
if prefixlen.find(".") != -1:
|
if prefixlen.find('.') != -1:
|
||||||
# check if the user might have used a netmask like
|
# check if the user might have used a netmask like
|
||||||
# a.b.c.d/255.255.255.0
|
# a.b.c.d/255.255.255.0
|
||||||
(netmask, vers) = parseAddress(prefixlen)
|
(netmask, vers) = parseAddress(prefixlen)
|
||||||
|
@ -255,7 +258,8 @@ class IPint(object):
|
||||||
if make_net:
|
if make_net:
|
||||||
self.ip = self.ip & _prefixlenToNetmask(self._prefixlen, self._ipversion)
|
self.ip = self.ip & _prefixlenToNetmask(self._prefixlen, self._ipversion)
|
||||||
|
|
||||||
if not _checkNetaddrWorksWithPrefixlen(self.ip, self._prefixlen, self._ipversion):
|
if not _checkNetaddrWorksWithPrefixlen(self.ip,
|
||||||
|
self._prefixlen, self._ipversion):
|
||||||
raise ValueError("%s has invalid prefix length (%s)" % (repr(self), self._prefixlen))
|
raise ValueError("%s has invalid prefix length (%s)" % (repr(self), self._prefixlen))
|
||||||
else:
|
else:
|
||||||
raise TypeError("Unsupported data type: %s" % type(data))
|
raise TypeError("Unsupported data type: %s" % type(data))
|
||||||
|
@ -313,12 +317,13 @@ class IPint(object):
|
||||||
want == 3 -lastip 1.2.3.0-1.2.3.255
|
want == 3 -lastip 1.2.3.0-1.2.3.255
|
||||||
"""
|
"""
|
||||||
|
|
||||||
if (self._ipversion == 4 and self._prefixlen == 32) or (self._ipversion == 6 and self._prefixlen == 128):
|
if (self._ipversion == 4 and self._prefixlen == 32) or \
|
||||||
|
(self._ipversion == 6 and self._prefixlen == 128):
|
||||||
if self.NoPrefixForSingleIp:
|
if self.NoPrefixForSingleIp:
|
||||||
want = 0
|
want = 0
|
||||||
if want is None:
|
if want == None:
|
||||||
want = self.WantPrefixLen
|
want = self.WantPrefixLen
|
||||||
if want is None:
|
if want == None:
|
||||||
want = 1
|
want = 1
|
||||||
if want:
|
if want:
|
||||||
if want == 2:
|
if want == 2:
|
||||||
|
@ -333,7 +338,7 @@ class IPint(object):
|
||||||
# default
|
# default
|
||||||
return "/%d" % (self._prefixlen)
|
return "/%d" % (self._prefixlen)
|
||||||
else:
|
else:
|
||||||
return ""
|
return ''
|
||||||
|
|
||||||
# We have different flavours to convert to:
|
# We have different flavours to convert to:
|
||||||
# strFullsize 127.0.0.1 2001:0658:022a:cafe:0200:c0ff:fe8d:08fa
|
# strFullsize 127.0.0.1 2001:0658:022a:cafe:0200:c0ff:fe8d:08fa
|
||||||
|
@ -352,10 +357,10 @@ class IPint(object):
|
||||||
"""
|
"""
|
||||||
|
|
||||||
bits = _ipVersionToLen(self._ipversion)
|
bits = _ipVersionToLen(self._ipversion)
|
||||||
if self.WantPrefixLen is None and wantprefixlen is None:
|
if self.WantPrefixLen == None and wantprefixlen == None:
|
||||||
wantprefixlen = 0
|
wantprefixlen = 0
|
||||||
ret = _intToBin(self.ip)
|
ret = _intToBin(self.ip)
|
||||||
return "0" * (bits - len(ret)) + ret + self._printPrefix(wantprefixlen)
|
return '0' * (bits - len(ret)) + ret + self._printPrefix(wantprefixlen)
|
||||||
|
|
||||||
def strCompressed(self, wantprefixlen = None):
|
def strCompressed(self, wantprefixlen = None):
|
||||||
"""Return a string representation in compressed format using '::' Notation.
|
"""Return a string representation in compressed format using '::' Notation.
|
||||||
|
@ -368,18 +373,18 @@ class IPint(object):
|
||||||
'ffff:ffff:ffff:ffff:ffff:f:f:fffc/127'
|
'ffff:ffff:ffff:ffff:ffff:f:f:fffc/127'
|
||||||
"""
|
"""
|
||||||
|
|
||||||
if self.WantPrefixLen is None and wantprefixlen is None:
|
if self.WantPrefixLen == None and wantprefixlen == None:
|
||||||
wantprefixlen = 1
|
wantprefixlen = 1
|
||||||
|
|
||||||
if self._ipversion == 4:
|
if self._ipversion == 4:
|
||||||
return self.strFullsize(wantprefixlen)
|
return self.strFullsize(wantprefixlen)
|
||||||
else:
|
else:
|
||||||
if self.ip >> 32 == 0xFFFF:
|
if self.ip >> 32 == 0xffff:
|
||||||
ipv4 = intToIp(self.ip & MAX_IPV4_ADDRESS, 4)
|
ipv4 = intToIp(self.ip & MAX_IPV4_ADDRESS, 4)
|
||||||
text = "::ffff:" + ipv4 + self._printPrefix(wantprefixlen)
|
text = "::ffff:" + ipv4 + self._printPrefix(wantprefixlen)
|
||||||
return text
|
return text
|
||||||
# find the longest sequence of '0'
|
# find the longest sequence of '0'
|
||||||
hextets = [int(x, 16) for x in self.strFullsize(0).split(":")]
|
hextets = [int(x, 16) for x in self.strFullsize(0).split(':')]
|
||||||
# every element of followingzeros will contain the number of zeros
|
# every element of followingzeros will contain the number of zeros
|
||||||
# following the corresponding element of hextets
|
# following the corresponding element of hextets
|
||||||
followingzeros = [0] * 8
|
followingzeros = [0] * 8
|
||||||
|
@ -390,15 +395,15 @@ class IPint(object):
|
||||||
if max(followingzeros) > 1:
|
if max(followingzeros) > 1:
|
||||||
# genererate string with the longest number of zeros cut out
|
# genererate string with the longest number of zeros cut out
|
||||||
# now we need hextets as strings
|
# now we need hextets as strings
|
||||||
hextets = [x for x in self.strNormal(0).split(":")]
|
hextets = [x for x in self.strNormal(0).split(':')]
|
||||||
while compressionpos < len(hextets) and hextets[compressionpos] == "0":
|
while compressionpos < len(hextets) and hextets[compressionpos] == '0':
|
||||||
del hextets[compressionpos]
|
del(hextets[compressionpos])
|
||||||
hextets.insert(compressionpos, "")
|
hextets.insert(compressionpos, '')
|
||||||
if compressionpos + 1 >= len(hextets):
|
if compressionpos + 1 >= len(hextets):
|
||||||
hextets.append("")
|
hextets.append('')
|
||||||
if compressionpos == 0:
|
if compressionpos == 0:
|
||||||
hextets = [""] + hextets
|
hextets = [''] + hextets
|
||||||
return ":".join(hextets) + self._printPrefix(wantprefixlen)
|
return ':'.join(hextets) + self._printPrefix(wantprefixlen)
|
||||||
else:
|
else:
|
||||||
return self.strNormal(0) + self._printPrefix(wantprefixlen)
|
return self.strNormal(0) + self._printPrefix(wantprefixlen)
|
||||||
|
|
||||||
|
@ -411,16 +416,18 @@ class IPint(object):
|
||||||
2001:658:22a:cafe:200:0:0:1
|
2001:658:22a:cafe:200:0:0:1
|
||||||
"""
|
"""
|
||||||
|
|
||||||
if self.WantPrefixLen is None and wantprefixlen is None:
|
if self.WantPrefixLen == None and wantprefixlen == None:
|
||||||
wantprefixlen = 1
|
wantprefixlen = 1
|
||||||
|
|
||||||
if self._ipversion == 4:
|
if self._ipversion == 4:
|
||||||
ret = self.strFullsize(0)
|
ret = self.strFullsize(0)
|
||||||
elif self._ipversion == 6:
|
elif self._ipversion == 6:
|
||||||
ret = ":".join(["%x" % x for x in [int(x, 16) for x in self.strFullsize(0).split(":")]])
|
ret = ':'.join(["%x" % x for x in [int(x, 16) for x in self.strFullsize(0).split(':')]])
|
||||||
else:
|
else:
|
||||||
raise ValueError("only IPv4 and IPv6 supported")
|
raise ValueError("only IPv4 and IPv6 supported")
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
return ret + self._printPrefix(wantprefixlen)
|
return ret + self._printPrefix(wantprefixlen)
|
||||||
|
|
||||||
def strFullsize(self, wantprefixlen = None):
|
def strFullsize(self, wantprefixlen = None):
|
||||||
|
@ -432,7 +439,7 @@ class IPint(object):
|
||||||
2001:0658:022a:cafe:0200:0000:0000:0001
|
2001:0658:022a:cafe:0200:0000:0000:0001
|
||||||
"""
|
"""
|
||||||
|
|
||||||
if self.WantPrefixLen is None and wantprefixlen is None:
|
if self.WantPrefixLen == None and wantprefixlen == None:
|
||||||
wantprefixlen = 1
|
wantprefixlen = 1
|
||||||
|
|
||||||
return intToIp(self.ip, self._ipversion) + self._printPrefix(wantprefixlen)
|
return intToIp(self.ip, self._ipversion) + self._printPrefix(wantprefixlen)
|
||||||
|
@ -446,10 +453,10 @@ class IPint(object):
|
||||||
0x20010658022acafe0200000000000001
|
0x20010658022acafe0200000000000001
|
||||||
"""
|
"""
|
||||||
|
|
||||||
if self.WantPrefixLen is None and wantprefixlen is None:
|
if self.WantPrefixLen == None and wantprefixlen == None:
|
||||||
wantprefixlen = 0
|
wantprefixlen = 0
|
||||||
|
|
||||||
x = "0x%x" % self.ip
|
x = '0x%x' % self.ip
|
||||||
return x + self._printPrefix(wantprefixlen)
|
return x + self._printPrefix(wantprefixlen)
|
||||||
|
|
||||||
def strDec(self, wantprefixlen = None):
|
def strDec(self, wantprefixlen = None):
|
||||||
|
@ -461,10 +468,10 @@ class IPint(object):
|
||||||
42540616829182469433547762482097946625
|
42540616829182469433547762482097946625
|
||||||
"""
|
"""
|
||||||
|
|
||||||
if self.WantPrefixLen is None and wantprefixlen is None:
|
if self.WantPrefixLen == None and wantprefixlen == None:
|
||||||
wantprefixlen = 0
|
wantprefixlen = 0
|
||||||
|
|
||||||
x = "%d" % self.ip
|
x = '%d' % self.ip
|
||||||
return x + self._printPrefix(wantprefixlen)
|
return x + self._printPrefix(wantprefixlen)
|
||||||
|
|
||||||
def iptype(self):
|
def iptype(self):
|
||||||
|
@ -499,6 +506,7 @@ class IPint(object):
|
||||||
return iprange[bits[:i]]
|
return iprange[bits[:i]]
|
||||||
return "unknown"
|
return "unknown"
|
||||||
|
|
||||||
|
|
||||||
def netmask(self):
|
def netmask(self):
|
||||||
"""Return netmask as an integer.
|
"""Return netmask as an integer.
|
||||||
|
|
||||||
|
@ -512,6 +520,7 @@ class IPint(object):
|
||||||
|
|
||||||
return ((2 ** self._prefixlen) - 1) << locallen
|
return ((2 ** self._prefixlen) - 1) << locallen
|
||||||
|
|
||||||
|
|
||||||
def strNetmask(self):
|
def strNetmask(self):
|
||||||
"""Return netmask as an string. Mostly useful for IPv6.
|
"""Return netmask as an string. Mostly useful for IPv6.
|
||||||
|
|
||||||
|
@ -543,6 +552,7 @@ class IPint(object):
|
||||||
locallen = bits - self._prefixlen
|
locallen = bits - self._prefixlen
|
||||||
return 2 ** locallen
|
return 2 ** locallen
|
||||||
|
|
||||||
|
|
||||||
def __nonzero__(self):
|
def __nonzero__(self):
|
||||||
"""All IPy objects should evaluate to true in boolean context.
|
"""All IPy objects should evaluate to true in boolean context.
|
||||||
Ordinarily they do, but if handling a default route expressed as
|
Ordinarily they do, but if handling a default route expressed as
|
||||||
|
@ -579,8 +589,10 @@ class IPint(object):
|
||||||
raise ValueError("Only adjacent networks can be added together.")
|
raise ValueError("Only adjacent networks can be added together.")
|
||||||
ret = IP(self.int(), ipversion=self._ipversion)
|
ret = IP(self.int(), ipversion=self._ipversion)
|
||||||
ret._prefixlen = self.prefixlen() - 1
|
ret._prefixlen = self.prefixlen() - 1
|
||||||
if not _checkNetaddrWorksWithPrefixlen(ret.ip, ret._prefixlen, ret._ipversion):
|
if not _checkNetaddrWorksWithPrefixlen(ret.ip, ret._prefixlen,
|
||||||
raise ValueError("The resulting %s has invalid prefix length (%s)" % (repr(ret), ret._prefixlen))
|
ret._ipversion):
|
||||||
|
raise ValueError("The resulting %s has invalid prefix length (%s)"
|
||||||
|
% (repr(ret), ret._prefixlen))
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
def __sub__(self, other):
|
def __sub__(self, other):
|
||||||
|
@ -619,6 +631,8 @@ class IPint(object):
|
||||||
|
|
||||||
return self.ip + int(key)
|
return self.ip + int(key)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def __contains__(self, item):
|
def __contains__(self, item):
|
||||||
"""Called to implement membership test operators.
|
"""Called to implement membership test operators.
|
||||||
|
|
||||||
|
@ -645,6 +659,7 @@ class IPint(object):
|
||||||
else:
|
else:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
def overlaps(self, item):
|
def overlaps(self, item):
|
||||||
"""Check if two IP address ranges overlap.
|
"""Check if two IP address ranges overlap.
|
||||||
|
|
||||||
|
@ -670,6 +685,7 @@ class IPint(object):
|
||||||
else:
|
else:
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
"""Dispatch to the prefered String Representation.
|
"""Dispatch to the prefered String Representation.
|
||||||
|
|
||||||
|
@ -677,6 +693,7 @@ class IPint(object):
|
||||||
|
|
||||||
return self.strCompressed()
|
return self.strCompressed()
|
||||||
|
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
"""Print a representation of the Object.
|
"""Print a representation of the Object.
|
||||||
|
|
||||||
|
@ -688,7 +705,8 @@ class IPint(object):
|
||||||
IP('10.0.0.0/24')
|
IP('10.0.0.0/24')
|
||||||
"""
|
"""
|
||||||
|
|
||||||
return "IPint('%s')" % (self.strCompressed(1))
|
return("IPint('%s')" % (self.strCompressed(1)))
|
||||||
|
|
||||||
|
|
||||||
def __cmp__(self, other):
|
def __cmp__(self, other):
|
||||||
"""Called by comparison operations.
|
"""Called by comparison operations.
|
||||||
|
@ -773,7 +791,7 @@ class IPint(object):
|
||||||
thehash = int(-1)
|
thehash = int(-1)
|
||||||
ip = self.ip
|
ip = self.ip
|
||||||
while ip > 0:
|
while ip > 0:
|
||||||
thehash = thehash ^ (ip & 0x7FFFFFFF)
|
thehash = thehash ^ (ip & 0x7fffffff)
|
||||||
ip = ip >> 32
|
ip = ip >> 32
|
||||||
thehash = thehash ^ self._prefixlen
|
thehash = thehash ^ self._prefixlen
|
||||||
return int(thehash)
|
return int(thehash)
|
||||||
|
@ -813,11 +831,11 @@ class IP(IPint):
|
||||||
def _getIPv4Map(self):
|
def _getIPv4Map(self):
|
||||||
if self._ipversion != 6:
|
if self._ipversion != 6:
|
||||||
return None
|
return None
|
||||||
if (self.ip >> 32) != 0xFFFF:
|
if (self.ip >> 32) != 0xffff:
|
||||||
return None
|
return None
|
||||||
ipv4 = self.ip & MAX_IPV4_ADDRESS
|
ipv4 = self.ip & MAX_IPV4_ADDRESS
|
||||||
if self._prefixlen != 128:
|
if self._prefixlen != 128:
|
||||||
ipv4 = "%s/%s" % (ipv4, 32 - (128 - self._prefixlen))
|
ipv4 = '%s/%s' % (ipv4, 32-(128-self._prefixlen))
|
||||||
return IP(ipv4, ipversion=4)
|
return IP(ipv4, ipversion=4)
|
||||||
|
|
||||||
def reverseNames(self):
|
def reverseNames(self):
|
||||||
|
@ -868,7 +886,7 @@ class IP(IPint):
|
||||||
raise NotImplementedError("can't create IPv6 reverse names at sub nibble level")
|
raise NotImplementedError("can't create IPv6 reverse names at sub nibble level")
|
||||||
s = list(s)
|
s = list(s)
|
||||||
s.reverse()
|
s.reverse()
|
||||||
s = ".".join(s)
|
s = '.'.join(s)
|
||||||
first_nibble_index = int(32 - (self._prefixlen // 4)) * 2
|
first_nibble_index = int(32 - (self._prefixlen // 4)) * 2
|
||||||
return ["%s.ip6.arpa." % s[first_nibble_index:]]
|
return ["%s.ip6.arpa." % s[first_nibble_index:]]
|
||||||
else:
|
else:
|
||||||
|
@ -893,34 +911,31 @@ class IP(IPint):
|
||||||
|
|
||||||
if self._ipversion == 4:
|
if self._ipversion == 4:
|
||||||
s = self.strFullsize(0)
|
s = self.strFullsize(0)
|
||||||
s = s.split(".")
|
s = s.split('.')
|
||||||
s.reverse()
|
s.reverse()
|
||||||
first_byte_index = int(4 - (self._prefixlen // 8))
|
first_byte_index = int(4 - (self._prefixlen // 8))
|
||||||
if self._prefixlen % 8 != 0:
|
if self._prefixlen % 8 != 0:
|
||||||
nibblepart = "%s-%s" % (
|
nibblepart = "%s-%s" % (s[3-(self._prefixlen // 8)], intToIp(self.ip + self.len() - 1, 4).split('.')[-1])
|
||||||
s[3 - (self._prefixlen // 8)],
|
nibblepart += '.'
|
||||||
intToIp(self.ip + self.len() - 1, 4).split(".")[-1],
|
|
||||||
)
|
|
||||||
nibblepart += "."
|
|
||||||
else:
|
else:
|
||||||
nibblepart = ""
|
nibblepart = ""
|
||||||
|
|
||||||
s = ".".join(s[first_byte_index:])
|
s = '.'.join(s[first_byte_index:])
|
||||||
return "%s%s.in-addr.arpa." % (nibblepart, s)
|
return "%s%s.in-addr.arpa." % (nibblepart, s)
|
||||||
|
|
||||||
elif self._ipversion == 6:
|
elif self._ipversion == 6:
|
||||||
ipv4 = self._getIPv4Map()
|
ipv4 = self._getIPv4Map()
|
||||||
if ipv4 is not None:
|
if ipv4 is not None:
|
||||||
return ipv4.reverseName()
|
return ipv4.reverseName()
|
||||||
s = "%032x" % self.ip
|
s = '%032x' % self.ip
|
||||||
if self._prefixlen % 4 != 0:
|
if self._prefixlen % 4 != 0:
|
||||||
nibblepart = "%s-%x" % (s[self._prefixlen:], self.ip + self.len() - 1)
|
nibblepart = "%s-%x" % (s[self._prefixlen:], self.ip + self.len() - 1)
|
||||||
nibblepart += "."
|
nibblepart += '.'
|
||||||
else:
|
else:
|
||||||
nibblepart = ""
|
nibblepart = ""
|
||||||
s = list(s)
|
s = list(s)
|
||||||
s.reverse()
|
s.reverse()
|
||||||
s = ".".join(s)
|
s = '.'.join(s)
|
||||||
first_nibble_index = int(32 - (self._prefixlen // 4)) * 2
|
first_nibble_index = int(32 - (self._prefixlen // 4)) * 2
|
||||||
return "%s%s.ip6.arpa." % (nibblepart, s[first_nibble_index:])
|
return "%s%s.ip6.arpa." % (nibblepart, s[first_nibble_index:])
|
||||||
else:
|
else:
|
||||||
|
@ -935,9 +950,9 @@ class IP(IPint):
|
||||||
>>> print(IP('127.0.0.1').make_net('255.0.0.0'))
|
>>> print(IP('127.0.0.1').make_net('255.0.0.0'))
|
||||||
127.0.0.0/8
|
127.0.0.0/8
|
||||||
"""
|
"""
|
||||||
if "/" in str(netmask):
|
if '/' in str(netmask):
|
||||||
raise ValueError("invalid netmask (%s)" % netmask)
|
raise ValueError("invalid netmask (%s)" % netmask)
|
||||||
return IP("%s/%s" % (self, netmask), make_net=True)
|
return IP('%s/%s' % (self, netmask), make_net=True)
|
||||||
|
|
||||||
def __getitem__(self, key):
|
def __getitem__(self, key):
|
||||||
"""Called to implement evaluation of self[key].
|
"""Called to implement evaluation of self[key].
|
||||||
|
@ -966,7 +981,7 @@ class IP(IPint):
|
||||||
IP('10.0.0.0/8')
|
IP('10.0.0.0/8')
|
||||||
"""
|
"""
|
||||||
|
|
||||||
return "IP('%s')" % (self.strCompressed(1))
|
return("IP('%s')" % (self.strCompressed(1)))
|
||||||
|
|
||||||
def get_mac(self):
|
def get_mac(self):
|
||||||
"""
|
"""
|
||||||
|
@ -978,15 +993,15 @@ class IP(IPint):
|
||||||
"""
|
"""
|
||||||
if self._ipversion != 6:
|
if self._ipversion != 6:
|
||||||
return None
|
return None
|
||||||
if (self.ip & 0x20000FFFF000000) != 0x20000FFFE000000:
|
if (self.ip & 0x20000ffff000000) != 0x20000fffe000000:
|
||||||
return None
|
return None
|
||||||
return "%02x:%02x:%02x:%02x:%02x:%02x" % (
|
return '%02x:%02x:%02x:%02x:%02x:%02x' % (
|
||||||
(((self.ip >> 56) & 0xFF) & 0xFD),
|
(((self.ip >> 56) & 0xff) & 0xfd),
|
||||||
(self.ip >> 48) & 0xFF,
|
(self.ip >> 48) & 0xff,
|
||||||
(self.ip >> 40) & 0xFF,
|
(self.ip >> 40) & 0xff,
|
||||||
(self.ip >> 16) & 0xFF,
|
(self.ip >> 16) & 0xff,
|
||||||
(self.ip >> 8) & 0xFF,
|
(self.ip >> 8) & 0xff,
|
||||||
self.ip & 0xFF,
|
self.ip & 0xff,
|
||||||
)
|
)
|
||||||
|
|
||||||
def v46map(self):
|
def v46map(self):
|
||||||
|
@ -1001,23 +1016,25 @@ class IP(IPint):
|
||||||
IP('192.168.1.1')
|
IP('192.168.1.1')
|
||||||
"""
|
"""
|
||||||
if self._ipversion == 4:
|
if self._ipversion == 4:
|
||||||
return IP(str(IPV6_MAP_MASK + self.ip) + "/%s" % (self._prefixlen + 96))
|
return IP(str(IPV6_MAP_MASK + self.ip) +
|
||||||
|
"/%s" % (self._prefixlen + 96))
|
||||||
else:
|
else:
|
||||||
if self.ip & IPV6_TEST_MAP == IPV6_MAP_MASK:
|
if self.ip & IPV6_TEST_MAP == IPV6_MAP_MASK:
|
||||||
return IP(str(self.ip - IPV6_MAP_MASK) + "/%s" % (self._prefixlen - 96))
|
return IP(str(self.ip - IPV6_MAP_MASK) +
|
||||||
raise ValueError("%s cannot be converted to an IPv4 address." % repr(self))
|
"/%s" % (self._prefixlen - 96))
|
||||||
|
raise ValueError("%s cannot be converted to an IPv4 address."
|
||||||
|
% repr(self))
|
||||||
|
|
||||||
|
class IPSet(collections_abc.MutableSet):
|
||||||
class IPSet(collections.MutableSet):
|
|
||||||
def __init__(self, iterable=[]):
|
def __init__(self, iterable=[]):
|
||||||
# Make sure it's iterable, otherwise wrap
|
# Make sure it's iterable, otherwise wrap
|
||||||
if not isinstance(iterable, collections.Iterable):
|
if not isinstance(iterable, collections_abc.Iterable):
|
||||||
raise TypeError("'%s' object is not iterable" % type(iterable).__name__)
|
raise TypeError("'%s' object is not iterable" % type(iterable).__name__)
|
||||||
|
|
||||||
# Make sure we only accept IP objects
|
# Make sure we only accept IP objects
|
||||||
for prefix in iterable:
|
for prefix in iterable:
|
||||||
if not isinstance(prefix, IP):
|
if not isinstance(prefix, IP):
|
||||||
raise ValueError("Only IP objects can be added to an IPSet")
|
raise ValueError('Only IP objects can be added to an IPSet')
|
||||||
|
|
||||||
# Store and optimize
|
# Store and optimize
|
||||||
self.prefixes = iterable[:]
|
self.prefixes = iterable[:]
|
||||||
|
@ -1078,20 +1095,20 @@ class IPSet(collections.MutableSet):
|
||||||
return IPSet(result)
|
return IPSet(result)
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return "%s([" % self.__class__.__name__ + ", ".join(map(repr, self.prefixes)) + "])"
|
return '%s([' % self.__class__.__name__ + ', '.join(map(repr, self.prefixes)) + '])'
|
||||||
|
|
||||||
def len(self):
|
def len(self):
|
||||||
return sum(prefix.len() for prefix in self.prefixes)
|
return sum(prefix.len() for prefix in self.prefixes)
|
||||||
|
|
||||||
def add(self, value):
|
def add(self, value):
|
||||||
# Make sure it's iterable, otherwise wrap
|
# Make sure it's iterable, otherwise wrap
|
||||||
if not isinstance(value, collections.Iterable):
|
if not isinstance(value, collections_abc.Iterable):
|
||||||
value = [value]
|
value = [value]
|
||||||
|
|
||||||
# Check type
|
# Check type
|
||||||
for prefix in value:
|
for prefix in value:
|
||||||
if not isinstance(prefix, IP):
|
if not isinstance(prefix, IP):
|
||||||
raise ValueError("Only IP objects can be added to an IPSet")
|
raise ValueError('Only IP objects can be added to an IPSet')
|
||||||
|
|
||||||
# Append and optimize
|
# Append and optimize
|
||||||
self.prefixes.extend(value)
|
self.prefixes.extend(value)
|
||||||
|
@ -1099,7 +1116,7 @@ class IPSet(collections.MutableSet):
|
||||||
|
|
||||||
def discard(self, value):
|
def discard(self, value):
|
||||||
# Make sure it's iterable, otherwise wrap
|
# Make sure it's iterable, otherwise wrap
|
||||||
if not isinstance(value, collections.Iterable):
|
if not isinstance(value, collections_abc.Iterable):
|
||||||
value = [value]
|
value = [value]
|
||||||
|
|
||||||
# This is much faster than iterating over the addresses
|
# This is much faster than iterating over the addresses
|
||||||
|
@ -1109,7 +1126,7 @@ class IPSet(collections.MutableSet):
|
||||||
# Remove
|
# Remove
|
||||||
for del_prefix in value:
|
for del_prefix in value:
|
||||||
if not isinstance(del_prefix, IP):
|
if not isinstance(del_prefix, IP):
|
||||||
raise ValueError("Only IP objects can be removed from an IPSet")
|
raise ValueError('Only IP objects can be removed from an IPSet')
|
||||||
|
|
||||||
# First check if this prefix contains anything in our list
|
# First check if this prefix contains anything in our list
|
||||||
found = False
|
found = False
|
||||||
|
@ -1207,7 +1224,6 @@ class IPSet(collections.MutableSet):
|
||||||
except KeyError:
|
except KeyError:
|
||||||
self.prefixtable[address._prefixlen] = [address]
|
self.prefixtable[address._prefixlen] = [address]
|
||||||
|
|
||||||
|
|
||||||
def _parseAddressIPv6(ipstr):
|
def _parseAddressIPv6(ipstr):
|
||||||
"""
|
"""
|
||||||
Internal function used by parseAddress() to parse IPv6 address with ':'.
|
Internal function used by parseAddress() to parse IPv6 address with ':'.
|
||||||
|
@ -1274,7 +1290,7 @@ def _parseAddressIPv6(ipstr):
|
||||||
fill_pos = len(items)
|
fill_pos = len(items)
|
||||||
index += 2
|
index += 2
|
||||||
continue
|
continue
|
||||||
pos = text.find(":")
|
pos = text.find(':')
|
||||||
if pos == 0:
|
if pos == 0:
|
||||||
# Invalid IPv6, eg. '1::2:'
|
# Invalid IPv6, eg. '1::2:'
|
||||||
raise ValueError("%r: Invalid IPv6 address" % ipstr)
|
raise ValueError("%r: Invalid IPv6 address" % ipstr)
|
||||||
|
@ -1292,13 +1308,13 @@ def _parseAddressIPv6(ipstr):
|
||||||
items.append(text)
|
items.append(text)
|
||||||
break
|
break
|
||||||
|
|
||||||
if items and "." in items[-1]:
|
if items and '.' in items[-1]:
|
||||||
# IPv6 ending with IPv4 like '::ffff:192.168.0.1'
|
# IPv6 ending with IPv4 like '::ffff:192.168.0.1'
|
||||||
if (fill_pos is not None) and not (fill_pos <= len(items)-1):
|
if (fill_pos is not None) and not (fill_pos <= len(items)-1):
|
||||||
# Invalid IPv6: 'ffff:192.168.0.1::'
|
# Invalid IPv6: 'ffff:192.168.0.1::'
|
||||||
raise ValueError("%r: Invalid IPv6 address: '::' after IPv4" % ipstr)
|
raise ValueError("%r: Invalid IPv6 address: '::' after IPv4" % ipstr)
|
||||||
value = parseAddress(items[-1])[0]
|
value = parseAddress(items[-1])[0]
|
||||||
items = items[:-1] + ["%04x" % (value >> 16), "%04x" % (value & 0xFFFF)]
|
items = items[:-1] + ["%04x" % (value >> 16), "%04x" % (value & 0xffff)]
|
||||||
|
|
||||||
# Expand fill_pos to fill with '0'
|
# Expand fill_pos to fill with '0'
|
||||||
# ['1','2'] with fill_pos=1 => ['1', '0', '0', '0', '0', '0', '0', '2']
|
# ['1','2'] with fill_pos=1 => ['1', '0', '0', '0', '0', '0', '0', '2']
|
||||||
|
@ -1306,7 +1322,7 @@ def _parseAddressIPv6(ipstr):
|
||||||
diff = 8 - len(items)
|
diff = 8 - len(items)
|
||||||
if diff <= 0:
|
if diff <= 0:
|
||||||
raise ValueError("%r: Invalid IPv6 address: '::' is not needed" % ipstr)
|
raise ValueError("%r: Invalid IPv6 address: '::' is not needed" % ipstr)
|
||||||
items = items[:fill_pos] + ["0"] * diff + items[fill_pos:]
|
items = items[:fill_pos] + ['0']*diff + items[fill_pos:]
|
||||||
|
|
||||||
# Here we have a list of 8 strings
|
# Here we have a list of 8 strings
|
||||||
if len(items) != 8:
|
if len(items) != 8:
|
||||||
|
@ -1319,7 +1335,7 @@ def _parseAddressIPv6(ipstr):
|
||||||
for item in items:
|
for item in items:
|
||||||
try:
|
try:
|
||||||
item = int(item, 16)
|
item = int(item, 16)
|
||||||
error = not (0 <= item <= 0xFFFF)
|
error = not(0 <= item <= 0xffff)
|
||||||
except ValueError:
|
except ValueError:
|
||||||
error = True
|
error = True
|
||||||
if error:
|
if error:
|
||||||
|
@ -1328,7 +1344,6 @@ def _parseAddressIPv6(ipstr):
|
||||||
index += 1
|
index += 1
|
||||||
return value
|
return value
|
||||||
|
|
||||||
|
|
||||||
def parseAddress(ipstr, ipversion=0):
|
def parseAddress(ipstr, ipversion=0):
|
||||||
"""
|
"""
|
||||||
Parse a string and return the corresponding IP address (as integer)
|
Parse a string and return the corresponding IP address (as integer)
|
||||||
|
@ -1383,7 +1398,7 @@ def parseAddress(ipstr, ipversion=0):
|
||||||
except ValueError:
|
except ValueError:
|
||||||
intval = None
|
intval = None
|
||||||
|
|
||||||
if ipstr.startswith("0x") and hexval is not None:
|
if ipstr.startswith('0x') and hexval is not None:
|
||||||
if hexval > MAX_IPV6_ADDRESS:
|
if hexval > MAX_IPV6_ADDRESS:
|
||||||
raise ValueError("IP Address can't be larger than %x: %x" % (MAX_IPV6_ADDRESS, hexval))
|
raise ValueError("IP Address can't be larger than %x: %x" % (MAX_IPV6_ADDRESS, hexval))
|
||||||
if hexval <= MAX_IPV4_ADDRESS:
|
if hexval <= MAX_IPV4_ADDRESS:
|
||||||
|
@ -1391,19 +1406,19 @@ def parseAddress(ipstr, ipversion=0):
|
||||||
else:
|
else:
|
||||||
return (hexval, 6)
|
return (hexval, 6)
|
||||||
|
|
||||||
if ipstr.find(":") != -1:
|
if ipstr.find(':') != -1:
|
||||||
return (_parseAddressIPv6(ipstr), 6)
|
return (_parseAddressIPv6(ipstr), 6)
|
||||||
|
|
||||||
elif len(ipstr) == 32 and hexval is not None:
|
elif len(ipstr) == 32 and hexval is not None:
|
||||||
# assume IPv6 in pure hexadecimal notation
|
# assume IPv6 in pure hexadecimal notation
|
||||||
return (hexval, 6)
|
return (hexval, 6)
|
||||||
|
|
||||||
elif ipstr.find(".") != -1 or (intval is not None and intval < 256 and ipversion != 6):
|
elif ipstr.find('.') != -1 or (intval is not None and intval < 256 and ipversion != 6):
|
||||||
# assume IPv4 ('127' gets interpreted as '127.0.0.0')
|
# assume IPv4 ('127' gets interpreted as '127.0.0.0')
|
||||||
bytes = ipstr.split(".")
|
bytes = ipstr.split('.')
|
||||||
if len(bytes) > 4:
|
if len(bytes) > 4:
|
||||||
raise ValueError("IPv4 Address with more than 4 bytes")
|
raise ValueError("IPv4 Address with more than 4 bytes")
|
||||||
bytes += ["0"] * (4 - len(bytes))
|
bytes += ['0'] * (4 - len(bytes))
|
||||||
bytes = [int(x) for x in bytes]
|
bytes = [int(x) for x in bytes]
|
||||||
for x in bytes:
|
for x in bytes:
|
||||||
if x > 255 or x < 0:
|
if x > 255 or x < 0:
|
||||||
|
@ -1433,12 +1448,12 @@ def intToIp(ip, version):
|
||||||
if ip < 0:
|
if ip < 0:
|
||||||
raise ValueError("IPs can't be negative: %d" % (ip))
|
raise ValueError("IPs can't be negative: %d" % (ip))
|
||||||
|
|
||||||
ret = ""
|
ret = ''
|
||||||
if version == 4:
|
if version == 4:
|
||||||
if ip > MAX_IPV4_ADDRESS:
|
if ip > MAX_IPV4_ADDRESS:
|
||||||
raise ValueError("IPv4 Address can't be larger than %x: %x" % (MAX_IPV4_ADDRESS, ip))
|
raise ValueError("IPv4 Address can't be larger than %x: %x" % (MAX_IPV4_ADDRESS, ip))
|
||||||
for l in xrange(4):
|
for l in xrange(4):
|
||||||
ret = str(ip & 0xFF) + "." + ret
|
ret = str(ip & 0xff) + '.' + ret
|
||||||
ip = ip >> 8
|
ip = ip >> 8
|
||||||
ret = ret[:-1]
|
ret = ret[:-1]
|
||||||
elif version == 6:
|
elif version == 6:
|
||||||
|
@ -1448,14 +1463,13 @@ def intToIp(ip, version):
|
||||||
for x in xrange(1, 33):
|
for x in xrange(1, 33):
|
||||||
ret = l[-x] + ret
|
ret = l[-x] + ret
|
||||||
if x % 4 == 0:
|
if x % 4 == 0:
|
||||||
ret = ":" + ret
|
ret = ':' + ret
|
||||||
ret = ret[1:]
|
ret = ret[1:]
|
||||||
else:
|
else:
|
||||||
raise ValueError("only IPv4 and IPv6 supported")
|
raise ValueError("only IPv4 and IPv6 supported")
|
||||||
|
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
|
|
||||||
def _ipVersionToLen(version):
|
def _ipVersionToLen(version):
|
||||||
"""Return number of bits in address for a certain IP version.
|
"""Return number of bits in address for a certain IP version.
|
||||||
|
|
||||||
|
@ -1489,25 +1503,10 @@ def _countFollowingZeros(l):
|
||||||
return 1 + _countFollowingZeros(l[1:])
|
return 1 + _countFollowingZeros(l[1:])
|
||||||
|
|
||||||
|
|
||||||
_BitTable = {
|
_BitTable = {'0': '0000', '1': '0001', '2': '0010', '3': '0011',
|
||||||
"0": "0000",
|
'4': '0100', '5': '0101', '6': '0110', '7': '0111',
|
||||||
"1": "0001",
|
'8': '1000', '9': '1001', 'a': '1010', 'b': '1011',
|
||||||
"2": "0010",
|
'c': '1100', 'd': '1101', 'e': '1110', 'f': '1111'}
|
||||||
"3": "0011",
|
|
||||||
"4": "0100",
|
|
||||||
"5": "0101",
|
|
||||||
"6": "0110",
|
|
||||||
"7": "0111",
|
|
||||||
"8": "1000",
|
|
||||||
"9": "1001",
|
|
||||||
"a": "1010",
|
|
||||||
"b": "1011",
|
|
||||||
"c": "1100",
|
|
||||||
"d": "1101",
|
|
||||||
"e": "1110",
|
|
||||||
"f": "1111",
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
def _intToBin(val):
|
def _intToBin(val):
|
||||||
"""Return the binary representation of an integer as string."""
|
"""Return the binary representation of an integer as string."""
|
||||||
|
@ -1515,15 +1514,14 @@ def _intToBin(val):
|
||||||
if val < 0:
|
if val < 0:
|
||||||
raise ValueError("Only positive values allowed")
|
raise ValueError("Only positive values allowed")
|
||||||
s = "%x" % val
|
s = "%x" % val
|
||||||
ret = ""
|
ret = ''
|
||||||
for x in s:
|
for x in s:
|
||||||
ret += _BitTable[x]
|
ret += _BitTable[x]
|
||||||
# remove leading zeros
|
# remove leading zeros
|
||||||
while ret[0] == "0" and len(ret) > 1:
|
while ret[0] == '0' and len(ret) > 1:
|
||||||
ret = ret[1:]
|
ret = ret[1:]
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
|
|
||||||
def _count1Bits(num):
|
def _count1Bits(num):
|
||||||
"""Find the highest bit set to 1 in an integer."""
|
"""Find the highest bit set to 1 in an integer."""
|
||||||
ret = 0
|
ret = 0
|
||||||
|
@ -1532,7 +1530,6 @@ def _count1Bits(num):
|
||||||
ret += 1
|
ret += 1
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
|
|
||||||
def _count0Bits(num):
|
def _count0Bits(num):
|
||||||
"""Find the highest bit set to 0 in an integer."""
|
"""Find the highest bit set to 0 in an integer."""
|
||||||
|
|
||||||
|
@ -1604,7 +1601,7 @@ def _checkNetmask(netmask, masklen):
|
||||||
def _checkNetaddrWorksWithPrefixlen(net, prefixlen, version):
|
def _checkNetaddrWorksWithPrefixlen(net, prefixlen, version):
|
||||||
"""Check if a base addess of a network is compatible with a prefixlen"""
|
"""Check if a base addess of a network is compatible with a prefixlen"""
|
||||||
try:
|
try:
|
||||||
return net & _prefixlenToNetmask(prefixlen, version) == net
|
return (net & _prefixlenToNetmask(prefixlen, version) == net)
|
||||||
except ValueError:
|
except ValueError:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
@ -1646,8 +1643,8 @@ def _remove_subprefix(prefix, subprefix):
|
||||||
|
|
||||||
# Start cutting in half, recursively
|
# Start cutting in half, recursively
|
||||||
prefixes = [
|
prefixes = [
|
||||||
IP("%s/%d" % (prefix[0], prefix._prefixlen + 1)),
|
IP('%s/%d' % (prefix[0], prefix._prefixlen + 1)),
|
||||||
IP("%s/%d" % (prefix[int(prefix.len() / 2)], prefix._prefixlen + 1)),
|
IP('%s/%d' % (prefix[int(prefix.len() / 2)], prefix._prefixlen + 1)),
|
||||||
]
|
]
|
||||||
if subprefix in prefixes[0]:
|
if subprefix in prefixes[0]:
|
||||||
return _remove_subprefix(prefixes[0], subprefix) + IPSet([prefixes[1]])
|
return _remove_subprefix(prefixes[0], subprefix) + IPSet([prefixes[1]])
|
||||||
|
@ -1657,9 +1654,7 @@ def _remove_subprefix(prefix, subprefix):
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
import doctest
|
import doctest
|
||||||
|
|
||||||
failure, nbtest = doctest.testmod()
|
failure, nbtest = doctest.testmod()
|
||||||
if failure:
|
if failure:
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
Loading…
Reference in a new issue