summaryrefslogtreecommitdiff
path: root/Lib/ipaddress.py
diff options
context:
space:
mode:
Diffstat (limited to 'Lib/ipaddress.py')
-rw-r--r--Lib/ipaddress.py363
1 files changed, 235 insertions, 128 deletions
diff --git a/Lib/ipaddress.py b/Lib/ipaddress.py
index 54df39ae56..4f02d520f1 100644
--- a/Lib/ipaddress.py
+++ b/Lib/ipaddress.py
@@ -195,11 +195,7 @@ def _count_righthand_zero_bits(number, bits):
"""
if number == 0:
return bits
- for i in range(bits):
- if (number >> i) & 1:
- return i
- # All bits of interest were zero, even if there are more in the number
- return bits
+ return min(bits, (~number & (number-1)).bit_length())
def summarize_address_range(first, last):
@@ -250,15 +246,14 @@ def summarize_address_range(first, last):
while first_int <= last_int:
nbits = min(_count_righthand_zero_bits(first_int, ip_bits),
(last_int - first_int + 1).bit_length() - 1)
- net = ip('%s/%d' % (first, ip_bits - nbits))
+ net = ip((first_int, ip_bits - nbits))
yield net
first_int += 1 << nbits
if first_int - 1 == ip._ALL_ONES:
break
- first = first.__class__(first_int)
-def _collapse_addresses_recursive(addresses):
+def _collapse_addresses_internal(addresses):
"""Loops through the addresses, collapsing concurrent netblocks.
Example:
@@ -268,7 +263,7 @@ def _collapse_addresses_recursive(addresses):
ip3 = IPv4Network('192.0.2.128/26')
ip4 = IPv4Network('192.0.2.192/26')
- _collapse_addresses_recursive([ip1, ip2, ip3, ip4]) ->
+ _collapse_addresses_internal([ip1, ip2, ip3, ip4]) ->
[IPv4Network('192.0.2.0/24')]
This shouldn't be called directly; it is called via
@@ -282,28 +277,29 @@ def _collapse_addresses_recursive(addresses):
passed.
"""
- while True:
- last_addr = None
- ret_array = []
- optimized = False
-
- for cur_addr in addresses:
- if not ret_array:
- last_addr = cur_addr
- ret_array.append(cur_addr)
- elif (cur_addr.network_address >= last_addr.network_address and
- cur_addr.broadcast_address <= last_addr.broadcast_address):
- optimized = True
- elif cur_addr == list(last_addr.supernet().subnets())[1]:
- ret_array[-1] = last_addr = last_addr.supernet()
- optimized = True
- else:
- last_addr = cur_addr
- ret_array.append(cur_addr)
-
- addresses = ret_array
- if not optimized:
- return addresses
+ # First merge
+ to_merge = list(addresses)
+ subnets = {}
+ while to_merge:
+ net = to_merge.pop()
+ supernet = net.supernet()
+ existing = subnets.get(supernet)
+ if existing is None:
+ subnets[supernet] = net
+ elif existing != net:
+ # Merge consecutive subnets
+ del subnets[supernet]
+ to_merge.append(supernet)
+ # Then iterate over resulting networks, skipping subsumed subnets
+ last = None
+ for net in sorted(subnets.values()):
+ if last is not None:
+ # Since they are sorted, last.network_address <= net.network_address
+ # is a given.
+ if last.broadcast_address >= net.broadcast_address:
+ continue
+ yield net
+ last = net
def collapse_addresses(addresses):
@@ -352,15 +348,13 @@ def collapse_addresses(addresses):
# sort and dedup
ips = sorted(set(ips))
- nets = sorted(set(nets))
while i < len(ips):
(first, last) = _find_address_range(ips[i:])
i = ips.index(last) + 1
addrs.extend(summarize_address_range(first, last))
- return iter(_collapse_addresses_recursive(sorted(
- addrs + nets, key=_BaseNetwork._get_networks_key)))
+ return _collapse_addresses_internal(addrs + nets)
def get_mixed_type_key(obj):
@@ -436,6 +430,17 @@ class _IPAddressBase(_TotalOrderingMixin):
return str(self)
@property
+ def reverse_pointer(self):
+ """The name of the reverse DNS pointer for the IP address, e.g.:
+ >>> ipaddress.ip_address("127.0.0.1").reverse_pointer
+ '1.0.0.127.in-addr.arpa'
+ >>> ipaddress.ip_address("2001:db8::1").reverse_pointer
+ '1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.8.b.d.0.1.0.0.2.ip6.arpa'
+
+ """
+ return self._reverse_pointer()
+
+ @property
def version(self):
msg = '%200s has no version specified' % (type(self),)
raise NotImplementedError(msg)
@@ -456,7 +461,8 @@ class _IPAddressBase(_TotalOrderingMixin):
raise AddressValueError(msg % (address, address_len,
expected_len, self._version))
- def _ip_int_from_prefix(self, prefixlen):
+ @classmethod
+ def _ip_int_from_prefix(cls, prefixlen):
"""Turn the prefix length into a bitwise netmask
Args:
@@ -466,9 +472,10 @@ class _IPAddressBase(_TotalOrderingMixin):
An integer.
"""
- return self._ALL_ONES ^ (self._ALL_ONES >> prefixlen)
+ return cls._ALL_ONES ^ (cls._ALL_ONES >> prefixlen)
- def _prefix_from_ip_int(self, ip_int):
+ @classmethod
+ def _prefix_from_ip_int(cls, ip_int):
"""Return prefix length from the bitwise netmask.
Args:
@@ -481,22 +488,24 @@ class _IPAddressBase(_TotalOrderingMixin):
ValueError: If the input intermingles zeroes & ones
"""
trailing_zeroes = _count_righthand_zero_bits(ip_int,
- self._max_prefixlen)
- prefixlen = self._max_prefixlen - trailing_zeroes
+ cls._max_prefixlen)
+ prefixlen = cls._max_prefixlen - trailing_zeroes
leading_ones = ip_int >> trailing_zeroes
all_ones = (1 << prefixlen) - 1
if leading_ones != all_ones:
- byteslen = self._max_prefixlen // 8
+ byteslen = cls._max_prefixlen // 8
details = ip_int.to_bytes(byteslen, 'big')
msg = 'Netmask pattern %r mixes zeroes & ones'
raise ValueError(msg % details)
return prefixlen
- def _report_invalid_netmask(self, netmask_str):
+ @classmethod
+ def _report_invalid_netmask(cls, netmask_str):
msg = '%r is not a valid netmask' % netmask_str
raise NetmaskValueError(msg) from None
- def _prefix_from_prefix_string(self, prefixlen_str):
+ @classmethod
+ def _prefix_from_prefix_string(cls, prefixlen_str):
"""Return prefix length from a numeric string
Args:
@@ -511,16 +520,17 @@ class _IPAddressBase(_TotalOrderingMixin):
# int allows a leading +/- as well as surrounding whitespace,
# so we ensure that isn't the case
if not _BaseV4._DECIMAL_DIGITS.issuperset(prefixlen_str):
- self._report_invalid_netmask(prefixlen_str)
+ cls._report_invalid_netmask(prefixlen_str)
try:
prefixlen = int(prefixlen_str)
except ValueError:
- self._report_invalid_netmask(prefixlen_str)
- if not (0 <= prefixlen <= self._max_prefixlen):
- self._report_invalid_netmask(prefixlen_str)
+ cls._report_invalid_netmask(prefixlen_str)
+ if not (0 <= prefixlen <= cls._max_prefixlen):
+ cls._report_invalid_netmask(prefixlen_str)
return prefixlen
- def _prefix_from_ip_string(self, ip_str):
+ @classmethod
+ def _prefix_from_ip_string(cls, ip_str):
"""Turn a netmask/hostmask string into a prefix length
Args:
@@ -534,24 +544,24 @@ class _IPAddressBase(_TotalOrderingMixin):
"""
# Parse the netmask/hostmask like an IP address.
try:
- ip_int = self._ip_int_from_string(ip_str)
+ ip_int = cls._ip_int_from_string(ip_str)
except AddressValueError:
- self._report_invalid_netmask(ip_str)
+ cls._report_invalid_netmask(ip_str)
# Try matching a netmask (this would be /1*0*/ as a bitwise regexp).
# Note that the two ambiguous cases (all-ones and all-zeroes) are
# treated as netmasks.
try:
- return self._prefix_from_ip_int(ip_int)
+ return cls._prefix_from_ip_int(ip_int)
except ValueError:
pass
# Invert the bits, and try matching a /0+1+/ hostmask instead.
- ip_int ^= self._ALL_ONES
+ ip_int ^= cls._ALL_ONES
try:
- return self._prefix_from_ip_int(ip_int)
+ return cls._prefix_from_ip_int(ip_int)
except ValueError:
- self._report_invalid_netmask(ip_str)
+ cls._report_invalid_netmask(ip_str)
class _BaseAddress(_IPAddressBase):
@@ -933,20 +943,11 @@ class _BaseNetwork(_IPAddressBase):
'prefix length diff %d is invalid for netblock %s' % (
new_prefixlen, self))
- first = self.__class__('%s/%s' %
- (self.network_address,
- self._prefixlen + prefixlen_diff))
-
- yield first
- current = first
- while True:
- broadcast = current.broadcast_address
- if broadcast == self.broadcast_address:
- return
- new_addr = self._address_class(int(broadcast) + 1)
- current = self.__class__('%s/%s' % (new_addr,
- new_prefixlen))
-
+ start = int(self.network_address)
+ end = int(self.broadcast_address)
+ step = (int(self.hostmask) + 1) >> prefixlen_diff
+ for new_addr in range(start, end, step):
+ current = self.__class__((new_addr, new_prefixlen))
yield current
def supernet(self, prefixlen_diff=1, new_prefix=None):
@@ -980,15 +981,15 @@ class _BaseNetwork(_IPAddressBase):
raise ValueError('cannot set prefixlen_diff and new_prefix')
prefixlen_diff = self._prefixlen - new_prefix
- if self.prefixlen - prefixlen_diff < 0:
+ new_prefixlen = self.prefixlen - prefixlen_diff
+ if new_prefixlen < 0:
raise ValueError(
'current prefixlen is %d, cannot have a prefixlen_diff of %d' %
(self.prefixlen, prefixlen_diff))
- # TODO (pmoody): optimize this.
- t = self.__class__('%s/%d' % (self.network_address,
- self.prefixlen - prefixlen_diff),
- strict=False)
- return t.__class__('%s/%d' % (t.network_address, t.prefixlen))
+ return self.__class__((
+ int(self.network_address) & (int(self.netmask) << prefixlen_diff),
+ new_prefixlen
+ ))
@property
def is_multicast(self):
@@ -1089,14 +1090,43 @@ class _BaseV4:
# the valid octets for host and netmasks. only useful for IPv4.
_valid_mask_octets = frozenset((255, 254, 252, 248, 240, 224, 192, 128, 0))
+ _max_prefixlen = IPV4LENGTH
+ # There are only a handful of valid v4 netmasks, so we cache them all
+ # when constructed (see _make_netmask()).
+ _netmask_cache = {}
+
def __init__(self, address):
self._version = 4
- self._max_prefixlen = IPV4LENGTH
def _explode_shorthand_ip_string(self):
return str(self)
- def _ip_int_from_string(self, ip_str):
+ @classmethod
+ def _make_netmask(cls, arg):
+ """Make a (netmask, prefix_len) tuple from the given argument.
+
+ Argument can be:
+ - an integer (the prefix length)
+ - a string representing the prefix length (e.g. "24")
+ - a string representing the prefix netmask (e.g. "255.255.255.0")
+ """
+ if arg not in cls._netmask_cache:
+ if isinstance(arg, int):
+ prefixlen = arg
+ else:
+ try:
+ # Check for a netmask in prefix length form
+ prefixlen = cls._prefix_from_prefix_string(arg)
+ except NetmaskValueError:
+ # Check for a netmask or hostmask in dotted-quad form.
+ # This may raise NetmaskValueError.
+ prefixlen = cls._prefix_from_ip_string(arg)
+ netmask = IPv4Address(cls._ip_int_from_prefix(prefixlen))
+ cls._netmask_cache[arg] = netmask, prefixlen
+ return cls._netmask_cache[arg]
+
+ @classmethod
+ def _ip_int_from_string(cls, ip_str):
"""Turn the given IP string into an integer for comparison.
Args:
@@ -1117,11 +1147,12 @@ class _BaseV4:
raise AddressValueError("Expected 4 octets in %r" % ip_str)
try:
- return int.from_bytes(map(self._parse_octet, octets), 'big')
+ return int.from_bytes(map(cls._parse_octet, octets), 'big')
except ValueError as exc:
raise AddressValueError("%s in %r" % (exc, ip_str)) from None
- def _parse_octet(self, octet_str):
+ @classmethod
+ def _parse_octet(cls, octet_str):
"""Convert a decimal octet into an integer.
Args:
@@ -1137,7 +1168,7 @@ class _BaseV4:
if not octet_str:
raise ValueError("Empty octet not permitted")
# Whitelist the characters, since int() allows a lot of bizarre stuff.
- if not self._DECIMAL_DIGITS.issuperset(octet_str):
+ if not cls._DECIMAL_DIGITS.issuperset(octet_str):
msg = "Only decimal digits permitted in %r"
raise ValueError(msg % octet_str)
# We do the length check second, since the invalid character error
@@ -1157,7 +1188,8 @@ class _BaseV4:
raise ValueError("Octet %d (> 255) not permitted" % octet_int)
return octet_int
- def _string_from_ip_int(self, ip_int):
+ @classmethod
+ def _string_from_ip_int(cls, ip_int):
"""Turns a 32-bit integer into dotted decimal notation.
Args:
@@ -1221,6 +1253,15 @@ class _BaseV4:
return True
return False
+ def _reverse_pointer(self):
+ """Return the reverse DNS pointer name for the IPv4 address.
+
+ This implements the method described in RFC1035 3.5.
+
+ """
+ reverse_octets = str(self).split('.')[::-1]
+ return '.'.join(reverse_octets) + '.in-addr.arpa'
+
@property
def max_prefixlen(self):
return self._max_prefixlen
@@ -1369,6 +1410,18 @@ class IPv4Interface(IPv4Address):
self._prefixlen = self._max_prefixlen
return
+ if isinstance(address, tuple):
+ IPv4Address.__init__(self, address[0])
+ if len(address) > 1:
+ self._prefixlen = int(address[1])
+ else:
+ self._prefixlen = self._max_prefixlen
+
+ self.network = IPv4Network(address, strict=False)
+ self.netmask = self.network.netmask
+ self.hostmask = self.network.hostmask
+ return
+
addr = _split_optional_netmask(address)
IPv4Address.__init__(self, addr[0])
@@ -1484,20 +1537,28 @@ class IPv4Network(_BaseV4, _BaseNetwork):
_BaseV4.__init__(self, address)
_BaseNetwork.__init__(self, address)
- # Constructing from a packed address
- if isinstance(address, bytes):
+ # Constructing from a packed address or integer
+ if isinstance(address, (int, bytes)):
self.network_address = IPv4Address(address)
- self._prefixlen = self._max_prefixlen
- self.netmask = IPv4Address(self._ALL_ONES)
- #fixme: address/network test here
+ self.netmask, self._prefixlen = self._make_netmask(self._max_prefixlen)
+ #fixme: address/network test here.
return
- # Efficient constructor from integer.
- if isinstance(address, int):
- self.network_address = IPv4Address(address)
- self._prefixlen = self._max_prefixlen
- self.netmask = IPv4Address(self._ALL_ONES)
- #fixme: address/network test here.
+ if isinstance(address, tuple):
+ if len(address) > 1:
+ arg = address[1]
+ else:
+ # We weren't given an address[1]
+ arg = self._max_prefixlen
+ self.network_address = IPv4Address(address[0])
+ self.netmask, self._prefixlen = self._make_netmask(arg)
+ packed = int(self.network_address)
+ if packed & int(self.netmask) != packed:
+ if strict:
+ raise ValueError('%s has host bits set' % self)
+ else:
+ self.network_address = IPv4Address(packed &
+ int(self.netmask))
return
# Assume input argument to be string or any object representation
@@ -1506,16 +1567,10 @@ class IPv4Network(_BaseV4, _BaseNetwork):
self.network_address = IPv4Address(self._ip_int_from_string(addr[0]))
if len(addr) == 2:
- try:
- # Check for a netmask in prefix length form
- self._prefixlen = self._prefix_from_prefix_string(addr[1])
- except NetmaskValueError:
- # Check for a netmask or hostmask in dotted-quad form.
- # This may raise NetmaskValueError.
- self._prefixlen = self._prefix_from_ip_string(addr[1])
+ arg = addr[1]
else:
- self._prefixlen = self._max_prefixlen
- self.netmask = IPv4Address(self._ip_int_from_prefix(self._prefixlen))
+ arg = self._max_prefixlen
+ self.netmask, self._prefixlen = self._make_netmask(arg)
if strict:
if (IPv4Address(int(self.network_address) & int(self.netmask)) !=
@@ -1555,12 +1610,35 @@ class _BaseV6:
_ALL_ONES = (2**IPV6LENGTH) - 1
_HEXTET_COUNT = 8
_HEX_DIGITS = frozenset('0123456789ABCDEFabcdef')
+ _max_prefixlen = IPV6LENGTH
+
+ # There are only a bunch of valid v6 netmasks, so we cache them all
+ # when constructed (see _make_netmask()).
+ _netmask_cache = {}
def __init__(self, address):
self._version = 6
- self._max_prefixlen = IPV6LENGTH
- def _ip_int_from_string(self, ip_str):
+ @classmethod
+ def _make_netmask(cls, arg):
+ """Make a (netmask, prefix_len) tuple from the given argument.
+
+ Argument can be:
+ - an integer (the prefix length)
+ - a string representing the prefix length (e.g. "24")
+ - a string representing the prefix netmask (e.g. "255.255.255.0")
+ """
+ if arg not in cls._netmask_cache:
+ if isinstance(arg, int):
+ prefixlen = arg
+ else:
+ prefixlen = cls._prefix_from_prefix_string(arg)
+ netmask = IPv6Address(cls._ip_int_from_prefix(prefixlen))
+ cls._netmask_cache[arg] = netmask, prefixlen
+ return cls._netmask_cache[arg]
+
+ @classmethod
+ def _ip_int_from_string(cls, ip_str):
"""Turn an IPv6 ip_str into an integer.
Args:
@@ -1596,7 +1674,7 @@ class _BaseV6:
# An IPv6 address can't have more than 8 colons (9 parts).
# The extra colon comes from using the "::" notation for a single
# leading or trailing zero part.
- _max_parts = self._HEXTET_COUNT + 1
+ _max_parts = cls._HEXTET_COUNT + 1
if len(parts) > _max_parts:
msg = "At most %d colons permitted in %r" % (_max_parts-1, ip_str)
raise AddressValueError(msg)
@@ -1628,17 +1706,17 @@ class _BaseV6:
if parts_lo:
msg = "Trailing ':' only permitted as part of '::' in %r"
raise AddressValueError(msg % ip_str) # :$ requires ::$
- parts_skipped = self._HEXTET_COUNT - (parts_hi + parts_lo)
+ parts_skipped = cls._HEXTET_COUNT - (parts_hi + parts_lo)
if parts_skipped < 1:
msg = "Expected at most %d other parts with '::' in %r"
- raise AddressValueError(msg % (self._HEXTET_COUNT-1, ip_str))
+ raise AddressValueError(msg % (cls._HEXTET_COUNT-1, ip_str))
else:
# Otherwise, allocate the entire address to parts_hi. The
# endpoints could still be empty, but _parse_hextet() will check
# for that.
- if len(parts) != self._HEXTET_COUNT:
+ if len(parts) != cls._HEXTET_COUNT:
msg = "Exactly %d parts expected without '::' in %r"
- raise AddressValueError(msg % (self._HEXTET_COUNT, ip_str))
+ raise AddressValueError(msg % (cls._HEXTET_COUNT, ip_str))
if not parts[0]:
msg = "Leading ':' only permitted as part of '::' in %r"
raise AddressValueError(msg % ip_str) # ^: requires ^::
@@ -1654,16 +1732,17 @@ class _BaseV6:
ip_int = 0
for i in range(parts_hi):
ip_int <<= 16
- ip_int |= self._parse_hextet(parts[i])
+ ip_int |= cls._parse_hextet(parts[i])
ip_int <<= 16 * parts_skipped
for i in range(-parts_lo, 0):
ip_int <<= 16
- ip_int |= self._parse_hextet(parts[i])
+ ip_int |= cls._parse_hextet(parts[i])
return ip_int
except ValueError as exc:
raise AddressValueError("%s in %r" % (exc, ip_str)) from None
- def _parse_hextet(self, hextet_str):
+ @classmethod
+ def _parse_hextet(cls, hextet_str):
"""Convert an IPv6 hextet string into an integer.
Args:
@@ -1678,7 +1757,7 @@ class _BaseV6:
"""
# Whitelist the characters, since int() allows a lot of bizarre stuff.
- if not self._HEX_DIGITS.issuperset(hextet_str):
+ if not cls._HEX_DIGITS.issuperset(hextet_str):
raise ValueError("Only hex digits permitted in %r" % hextet_str)
# We do the length check second, since the invalid character error
# is likely to be more informative for the user
@@ -1688,7 +1767,8 @@ class _BaseV6:
# Length check means we can skip checking the integer value
return int(hextet_str, 16)
- def _compress_hextets(self, hextets):
+ @classmethod
+ def _compress_hextets(cls, hextets):
"""Compresses a list of hextets.
Compresses a list of strings, replacing the longest continuous
@@ -1735,7 +1815,8 @@ class _BaseV6:
return hextets
- def _string_from_ip_int(self, ip_int=None):
+ @classmethod
+ def _string_from_ip_int(cls, ip_int=None):
"""Turns a 128-bit integer into hexadecimal notation.
Args:
@@ -1749,15 +1830,15 @@ class _BaseV6:
"""
if ip_int is None:
- ip_int = int(self._ip)
+ ip_int = int(cls._ip)
- if ip_int > self._ALL_ONES:
+ if ip_int > cls._ALL_ONES:
raise ValueError('IPv6 address is too large')
hex_str = '%032x' % ip_int
hextets = ['%x' % int(hex_str[x:x+4], 16) for x in range(0, 32, 4)]
- hextets = self._compress_hextets(hextets)
+ hextets = cls._compress_hextets(hextets)
return ':'.join(hextets)
def _explode_shorthand_ip_string(self):
@@ -1784,6 +1865,15 @@ class _BaseV6:
return '%s/%d' % (':'.join(parts), self._prefixlen)
return ':'.join(parts)
+ def _reverse_pointer(self):
+ """Return the reverse DNS pointer name for the IPv6 address.
+
+ This implements the method described in RFC3596 2.5.
+
+ """
+ reverse_chars = self.exploded[::-1].replace(':', '')
+ return '.'.join(reverse_chars) + '.ip6.arpa'
+
@property
def max_prefixlen(self):
return self._max_prefixlen
@@ -2001,6 +2091,16 @@ class IPv6Interface(IPv6Address):
self.network = IPv6Network(self._ip)
self._prefixlen = self._max_prefixlen
return
+ if isinstance(address, tuple):
+ IPv6Address.__init__(self, address[0])
+ if len(address) > 1:
+ self._prefixlen = int(address[1])
+ else:
+ self._prefixlen = self._max_prefixlen
+ self.network = IPv6Network(address, strict=False)
+ self.netmask = self.network.netmask
+ self.hostmask = self.network.hostmask
+ return
addr = _split_optional_netmask(address)
IPv6Address.__init__(self, addr[0])
@@ -2118,18 +2218,26 @@ class IPv6Network(_BaseV6, _BaseNetwork):
_BaseV6.__init__(self, address)
_BaseNetwork.__init__(self, address)
- # Efficient constructor from integer.
- if isinstance(address, int):
+ # Efficient constructor from integer or packed address
+ if isinstance(address, (bytes, int)):
self.network_address = IPv6Address(address)
- self._prefixlen = self._max_prefixlen
- self.netmask = IPv6Address(self._ALL_ONES)
+ self.netmask, self._prefixlen = self._make_netmask(self._max_prefixlen)
return
- # Constructing from a packed address
- if isinstance(address, bytes):
- self.network_address = IPv6Address(address)
- self._prefixlen = self._max_prefixlen
- self.netmask = IPv6Address(self._ALL_ONES)
+ if isinstance(address, tuple):
+ if len(address) > 1:
+ arg = address[1]
+ else:
+ arg = self._max_prefixlen
+ self.netmask, self._prefixlen = self._make_netmask(arg)
+ self.network_address = IPv6Address(address[0])
+ packed = int(self.network_address)
+ if packed & int(self.netmask) != packed:
+ if strict:
+ raise ValueError('%s has host bits set' % self)
+ else:
+ self.network_address = IPv6Address(packed &
+ int(self.netmask))
return
# Assume input argument to be string or any object representation
@@ -2139,12 +2247,11 @@ class IPv6Network(_BaseV6, _BaseNetwork):
self.network_address = IPv6Address(self._ip_int_from_string(addr[0]))
if len(addr) == 2:
- # This may raise NetmaskValueError
- self._prefixlen = self._prefix_from_prefix_string(addr[1])
+ arg = addr[1]
else:
- self._prefixlen = self._max_prefixlen
+ arg = self._max_prefixlen
+ self.netmask, self._prefixlen = self._make_netmask(arg)
- self.netmask = IPv6Address(self._ip_int_from_prefix(self._prefixlen))
if strict:
if (IPv6Address(int(self.network_address) & int(self.netmask)) !=
self.network_address):