| Left: | ||
| Right: |
| LEFT | RIGHT |
|---|---|
| 1 #!/usr/bin/python3 | |
| 2 # | |
| 3 # Copyright 2007 Google Inc. | 1 # Copyright 2007 Google Inc. |
| 4 # Licensed to PSF under a Contributor Agreement. | 2 # Licensed to PSF under a Contributor Agreement. |
| 5 # | |
| 6 # Licensed under the Apache License, Version 2.0 (the "License"); | |
| 7 # you may not use this file except in compliance with the License. | |
| 8 # You may obtain a copy of the License at | |
| 9 # | |
| 10 # http://www.apache.org/licenses/LICENSE-2.0 | |
| 11 # | |
| 12 # Unless required by applicable law or agreed to in writing, software | |
| 13 # distributed under the License is distributed on an "AS IS" BASIS, | |
| 14 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or | |
| 15 # implied. See the License for the specific language governing | |
| 16 # permissions and limitations under the License. | |
| 17 | 3 |
| 18 """A fast, lightweight IPv4/IPv6 manipulation library in Python. | 4 """A fast, lightweight IPv4/IPv6 manipulation library in Python. |
| 19 | 5 |
| 20 This library is used to create/poke/manipulate IPv4 and IPv6 addresses | 6 This library is used to create/poke/manipulate IPv4 and IPv6 addresses |
| 21 and networks. | 7 and networks. |
| 22 | 8 |
| 23 """ | 9 """ |
| 24 | 10 |
| 25 __version__ = '1.0' | 11 __version__ = '1.0' |
| 26 | 12 |
| 13 | |
| 27 import struct | 14 import struct |
| 15 | |
| 28 | 16 |
| 29 IPV4LENGTH = 32 | 17 IPV4LENGTH = 32 |
| 30 IPV6LENGTH = 128 | 18 IPV6LENGTH = 128 |
| 31 | 19 |
| 32 | 20 |
| 33 class AddressValueError(ValueError): | 21 class AddressValueError(ValueError): |
| 34 """A Value Error related to the address.""" | 22 """A Value Error related to the address.""" |
| 35 | 23 |
| 36 | 24 |
| 37 class NetmaskValueError(ValueError): | 25 class NetmaskValueError(ValueError): |
| 38 """A Value Error related to the netmask.""" | 26 """A Value Error related to the netmask.""" |
| 39 | 27 |
| 40 | 28 |
| 41 def ip_address(address, version=None): | 29 def ip_address(address): |
| 42 """Take an IP string/int and return an object of the correct type. | 30 """Take an IP string/int and return an object of the correct type. |
| 43 | 31 |
| 44 Args: | 32 Args: |
| 45 address: A string or integer, the IP address. Either IPv4 or | 33 address: A string or integer, the IP address. Either IPv4 or |
| 46 IPv6 addresses may be supplied; integers less than 2**32 will | 34 IPv6 addresses may be supplied; integers less than 2**32 will |
| 47 be considered to be IPv4 by default. | 35 be considered to be IPv4 by default. |
| 48 version: An integer, 4 or 6. If set, don't try to automatically | |
| 49 determine what the IP address type is. Important for things | |
| 50 like ip_address(1), which could be IPv4, '192.0.2.1', or IPv6, | |
| 51 '2001:db8::1'. | |
| 52 | 36 |
| 53 Returns: | 37 Returns: |
| 54 An IPv4Address or IPv6Address object. | 38 An IPv4Address or IPv6Address object. |
| 55 | 39 |
| 56 Raises: | 40 Raises: |
| 57 ValueError: if the *address* passed isn't either a v4 or a v6 | 41 ValueError: if the *address* passed isn't either a v4 or a v6 |
| 58 address, or if the version is not None, 4, or 6. | 42 address |
| 59 | 43 |
| 60 """ | 44 """ |
| 61 if version is not None: | |
| 62 if version == 4: | |
| 63 return IPv4Address(address) | |
| 64 elif version == 6: | |
| 65 return IPv6Address(address) | |
| 66 else: | |
| 67 raise ValueError() | |
|
ezio.melotti
2012/05/23 01:37:15
Shouldn't this have a message?
| |
| 68 | |
| 69 try: | 45 try: |
| 70 return IPv4Address(address) | 46 return IPv4Address(address) |
| 71 except (AddressValueError, NetmaskValueError): | 47 except (AddressValueError, NetmaskValueError): |
| 72 pass | 48 pass |
| 73 | 49 |
| 74 try: | 50 try: |
| 75 return IPv6Address(address) | 51 return IPv6Address(address) |
| 76 except (AddressValueError, NetmaskValueError): | 52 except (AddressValueError, NetmaskValueError): |
| 77 pass | 53 pass |
| 78 | 54 |
| 79 raise ValueError('%r does not appear to be an IPv4 or IPv6 address' % | 55 raise ValueError('%r does not appear to be an IPv4 or IPv6 address' % |
| 80 address) | 56 address) |
| 81 | 57 |
| 82 | 58 |
| 83 def ip_network(address, version=None, strict=True): | 59 def ip_network(address, strict=True): |
| 84 """Take an IP string/int and return an object of the correct type. | 60 """Take an IP string/int and return an object of the correct type. |
| 85 | 61 |
| 86 Args: | 62 Args: |
| 87 address: A string or integer, the IP network. Either IPv4 or | 63 address: A string or integer, the IP network. Either IPv4 or |
| 88 IPv6 networks may be supplied; integers less than 2**32 will | 64 IPv6 networks may be supplied; integers less than 2**32 will |
| 89 be considered to be IPv4 by default. | 65 be considered to be IPv4 by default. |
| 90 version: An integer, 4 or 6. If set, don't try to automatically | |
|
ezio.melotti
2012/05/23 01:37:15
Ditto for the comma.
| |
| 91 determine what the IP address type is. Important for things | |
| 92 like ip_network(1), which could be IPv4, '192.0.2.1/32', or IPv6, | |
| 93 '2001:db8::1/128'. | |
|
ezio.melotti
2012/05/23 01:37:15
The strict arg is not documented.
| |
| 94 | 66 |
| 95 Returns: | 67 Returns: |
| 96 An IPv4Network or IPv6Network object. | 68 An IPv4Network or IPv6Network object. |
| 97 | 69 |
| 98 Raises: | 70 Raises: |
| 99 ValueError: if the string passed isn't either a v4 or a v6 | 71 ValueError: if the string passed isn't either a v4 or a v6 |
| 100 address. Or if the network has host bits set. Or if the version | 72 address. Or if the network has host bits set. |
| 101 is not None, 4, or 6. | |
| 102 | 73 |
| 103 """ | 74 """ |
| 104 if version is not None: | |
| 105 if version == 4: | |
| 106 return IPv4Network(address, strict) | |
| 107 elif version == 6: | |
| 108 return IPv6Network(address, strict) | |
| 109 else: | |
| 110 raise ValueError() | |
| 111 | |
| 112 try: | 75 try: |
| 113 return IPv4Network(address, strict) | 76 return IPv4Network(address, strict) |
| 114 except (AddressValueError, NetmaskValueError): | 77 except (AddressValueError, NetmaskValueError): |
| 115 pass | 78 pass |
| 116 | 79 |
| 117 try: | 80 try: |
| 118 return IPv6Network(address, strict) | 81 return IPv6Network(address, strict) |
| 119 except (AddressValueError, NetmaskValueError): | 82 except (AddressValueError, NetmaskValueError): |
| 120 pass | 83 pass |
| 121 | 84 |
| 122 raise ValueError('%r does not appear to be an IPv4 or IPv6 network' % | 85 raise ValueError('%r does not appear to be an IPv4 or IPv6 network' % |
| 123 address) | 86 address) |
| 124 | 87 |
| 125 | 88 |
| 126 def ip_interface(address, version=None): | 89 def ip_interface(address): |
| 127 """Take an IP string/int and return an object of the correct type. | 90 """Take an IP string/int and return an object of the correct type. |
| 128 | 91 |
| 129 Args: | 92 Args: |
| 130 address: A string or integer, the IP address. Either IPv4 or | 93 address: A string or integer, the IP address. Either IPv4 or |
| 131 IPv6 addresses may be supplied; integers less than 2**32 will | 94 IPv6 addresses may be supplied; integers less than 2**32 will |
| 132 be considered to be IPv4 by default. | 95 be considered to be IPv4 by default. |
| 133 version: An integer, 4 or 6. If set, don't try to automatically | |
| 134 determine what the IP address type is. Important for things | |
| 135 like ip_interface(1), which could be IPv4, '192.0.2.1/32', or IPv6, | |
| 136 '2001:db8::1/128'. | |
| 137 | 96 |
| 138 Returns: | 97 Returns: |
| 139 An IPv4Interface or IPv6Interface object. | 98 An IPv4Interface or IPv6Interface object. |
| 140 | 99 |
| 141 Raises: | 100 Raises: |
| 142 ValueError: if the string passed isn't either a v4 or a v6 | 101 ValueError: if the string passed isn't either a v4 or a v6 |
| 143 address. Or if the version is not None, 4, or 6. | 102 address. |
| 144 | 103 |
| 145 Notes: | 104 Notes: |
| 146 The IPv?Interface classes describe an Address on a particular | 105 The IPv?Interface classes describe an Address on a particular |
| 147 Network, so they're basically a combination of both the Address | 106 Network, so they're basically a combination of both the Address |
| 148 and Network classes. | 107 and Network classes. |
| 108 | |
| 149 """ | 109 """ |
| 150 if version is not None: | |
| 151 if version == 4: | |
| 152 return IPv4Interface(address) | |
| 153 elif version == 6: | |
| 154 return IPv6Interface(address) | |
| 155 else: | |
| 156 raise ValueError() | |
| 157 | |
| 158 try: | 110 try: |
| 159 return IPv4Interface(address) | 111 return IPv4Interface(address) |
| 160 except (AddressValueError, NetmaskValueError): | 112 except (AddressValueError, NetmaskValueError): |
| 161 pass | 113 pass |
| 162 | 114 |
| 163 try: | 115 try: |
| 164 return IPv6Interface(address) | 116 return IPv6Interface(address) |
| 165 except (AddressValueError, NetmaskValueError): | 117 except (AddressValueError, NetmaskValueError): |
| 166 pass | 118 pass |
| 167 | 119 |
| 168 raise ValueError('%r does not appear to be an IPv4 or IPv6 network' % | 120 raise ValueError('%r does not appear to be an IPv4 or IPv6 network' % |
| 169 address) | 121 address) |
| 170 | 122 |
| 171 | 123 |
| 172 def v4_int_to_packed(address): | 124 def v4_int_to_packed(address): |
| 173 """Represent an address as 4 packed bytes in network (big-endian) order. | 125 """Represent an address as 4 packed bytes in network (big-endian) order. |
| 174 | 126 |
| 175 Args: | 127 Args: |
| 176 address: An integer representation of an IPv4 IP address. | 128 address: An integer representation of an IPv4 IP address. |
| 177 | 129 |
| 178 Returns: | 130 Returns: |
| 179 The integer address packed as 4 bytes in network (big-endian) order. | 131 The integer address packed as 4 bytes in network (big-endian) order. |
| 180 | 132 |
| 181 Raises: | 133 Raises: |
| 182 ValueError: If the integer is is negative or too large to be an | 134 ValueError: If the integer is negative or too large to be an |
| 183 IPv4 IP address. | 135 IPv4 IP address. |
| 136 | |
| 184 """ | 137 """ |
| 185 try: | 138 try: |
| 186 return struct.pack('!I', address) | 139 return struct.pack('!I', address) |
| 187 except: | 140 except: |
| 188 raise ValueError("Address negative or too large for IPv4") | 141 raise ValueError("Address negative or too large for IPv4") |
|
ezio.melotti
2012/05/23 01:37:15
I don't like the bare except too much. Isn't the
| |
| 189 | 142 |
| 190 | 143 |
| 191 def v6_int_to_packed(address): | 144 def v6_int_to_packed(address): |
| 192 """Represent an address as 16 packed bytes in network (big-endian) order. | 145 """Represent an address as 16 packed bytes in network (big-endian) order. |
| 193 | 146 |
| 194 Args: | 147 Args: |
| 195 address: An integer representation of an IPv4 IP address. | 148 address: An integer representation of an IPv6 IP address. |
| 196 | 149 |
| 197 Returns: | 150 Returns: |
| 198 The integer address packed as 16 bytes in network (big-endian) order. | 151 The integer address packed as 16 bytes in network (big-endian) order. |
| 152 | |
| 199 """ | 153 """ |
| 200 try: | 154 try: |
| 201 return struct.pack('!QQ', address >> 64, address & (2**64 - 1)) | 155 return struct.pack('!QQ', address >> 64, address & (2**64 - 1)) |
| 202 except: | 156 except: |
| 203 raise ValueError("Address negative or too large for IPv6") | 157 raise ValueError("Address negative or too large for IPv6") |
| 204 | 158 |
| 205 | 159 |
| 206 def _find_address_range(addresses): | 160 def _find_address_range(addresses): |
| 207 """Find a sequence of IPv#Address. | 161 """Find a sequence of IPv#Address. |
| 208 | 162 |
| 209 Args: | 163 Args: |
| 210 addresses: a list of IPv#Address objects. | 164 addresses: a list of IPv#Address objects. |
|
ezio.melotti
2012/05/23 01:37:15
I prefer "IPv4Address or IPv6Address"
| |
| 211 | 165 |
| 212 Returns: | 166 Returns: |
| 213 A tuple containing the first and last IP addresses in the sequence. | 167 A tuple containing the first and last IP addresses in the sequence. |
| 214 | 168 |
| 215 """ | 169 """ |
| 216 first = last = addresses[0] | 170 first = last = addresses[0] |
| 217 for ip in addresses[1:]: | 171 for ip in addresses[1:]: |
| 218 if ip._ip == last._ip + 1: | 172 if ip._ip == last._ip + 1: |
| 219 last = ip | 173 last = ip |
| 220 else: | 174 else: |
| 221 break | 175 break |
| 222 return (first, last) | 176 return (first, last) |
| 223 | 177 |
| 178 | |
| 224 def _get_prefix_length(number1, number2, bits): | 179 def _get_prefix_length(number1, number2, bits): |
| 225 """Get the number of leading bits that are same for two numbers. | 180 """Get the number of leading bits that are same for two numbers. |
| 226 | 181 |
| 227 Args: | 182 Args: |
| 228 number1: an integer. | 183 number1: an integer. |
| 229 number2: another integer. | 184 number2: another integer. |
| 230 bits: the maximum number of bits to compare. | 185 bits: the maximum number of bits to compare. |
| 231 | 186 |
| 232 Returns: | 187 Returns: |
| 233 The number of leading bits that are the same for two numbers. | 188 The number of leading bits that are the same for two numbers. |
| 234 | 189 |
| 235 """ | 190 """ |
| 236 for i in range(bits): | 191 for i in range(bits): |
| 237 if number1 >> i == number2 >> i: | 192 if number1 >> i == number2 >> i: |
| 238 return bits - i | 193 return bits - i |
| 239 return 0 | 194 return 0 |
| 195 | |
| 240 | 196 |
| 241 def _count_righthand_zero_bits(number, bits): | 197 def _count_righthand_zero_bits(number, bits): |
| 242 """Count the number of zero bits on the right hand side. | 198 """Count the number of zero bits on the right hand side. |
| 243 | 199 |
| 244 Args: | 200 Args: |
| 245 number: an integer. | 201 number: an integer. |
| 246 bits: maximum number of bits to count. | 202 bits: maximum number of bits to count. |
| 247 | 203 |
| 248 Returns: | 204 Returns: |
| 249 The number of zero bits on the right hand side of the number. | 205 The number of zero bits on the right hand side of the number. |
| (...skipping 21 matching lines...) Expand all Loading... | |
| 271 | 227 |
| 272 Returns: | 228 Returns: |
| 273 An iterator of the summarized IPv(4|6) network objects. | 229 An iterator of the summarized IPv(4|6) network objects. |
| 274 | 230 |
| 275 Raise: | 231 Raise: |
| 276 TypeError: | 232 TypeError: |
| 277 If the first and last objects are not IP addresses. | 233 If the first and last objects are not IP addresses. |
| 278 If the first and last objects are not the same version. | 234 If the first and last objects are not the same version. |
| 279 ValueError: | 235 ValueError: |
| 280 If the last object is not greater than the first. | 236 If the last object is not greater than the first. |
| 281 If the version is not 4 or 6. | 237 If the version of the first address is not 4 or 6. |
| 282 | 238 |
| 283 """ | 239 """ |
| 284 if not (isinstance(first, _BaseAddress) and isinstance(last, _BaseAddress)): | 240 if (not (isinstance(first, _BaseAddress) and |
| 241 isinstance(last, _BaseAddress))): | |
| 285 raise TypeError('first and last must be IP addresses, not networks') | 242 raise TypeError('first and last must be IP addresses, not networks') |
| 286 if first.version != last.version: | 243 if first.version != last.version: |
| 287 raise TypeError("%s and %s are not of the same version" % ( | 244 raise TypeError("%s and %s are not of the same version" % ( |
| 288 str(first), str(last))) | 245 str(first), str(last))) |
| 289 if first > last: | 246 if first > last: |
| 290 raise ValueError('last IP address must be greater than first') | 247 raise ValueError('last IP address must be greater than first') |
| 291 | |
| 292 networks = [] | |
| 293 | 248 |
| 294 if first.version == 4: | 249 if first.version == 4: |
| 295 ip = IPv4Network | 250 ip = IPv4Network |
| 296 elif first.version == 6: | 251 elif first.version == 6: |
| 297 ip = IPv6Network | 252 ip = IPv6Network |
| 298 else: | 253 else: |
| 299 raise ValueError('unknown IP version') | 254 raise ValueError('unknown IP version') |
| 300 | 255 |
| 301 ip_bits = first._max_prefixlen | 256 ip_bits = first._max_prefixlen |
| 302 first_int = first._ip | 257 first_int = first._ip |
| 303 last_int = last._ip | 258 last_int = last._ip |
| 304 while first_int <= last_int: | 259 while first_int <= last_int: |
| 305 nbits = _count_righthand_zero_bits(first_int, ip_bits) | 260 nbits = _count_righthand_zero_bits(first_int, ip_bits) |
| 306 current = None | 261 current = None |
| 307 while nbits >= 0: | 262 while nbits >= 0: |
| 308 addend = 2**nbits - 1 | 263 addend = 2**nbits - 1 |
| 309 current = first_int + addend | 264 current = first_int + addend |
| 310 nbits -= 1 | 265 nbits -= 1 |
| 311 if current <= last_int: | 266 if current <= last_int: |
| 312 break | 267 break |
| 313 prefix = _get_prefix_length(first_int, current, ip_bits) | 268 prefix = _get_prefix_length(first_int, current, ip_bits) |
| 314 net = ip('%s/%d' % (str(first), prefix)) | 269 net = ip('%s/%d' % (str(first), prefix)) |
| 315 yield net | 270 yield net |
| 316 #networks.append(net) | |
| 317 if current == ip._ALL_ONES: | 271 if current == ip._ALL_ONES: |
| 318 break | 272 break |
| 319 first_int = current + 1 | 273 first_int = current + 1 |
| 320 first = ip_address(first_int, version=first._version) | 274 first = first.__class__(first_int) |
| 275 | |
| 321 | 276 |
| 322 def _collapse_addresses_recursive(addresses): | 277 def _collapse_addresses_recursive(addresses): |
| 323 """Loops through the addresses, collapsing concurrent netblocks. | 278 """Loops through the addresses, collapsing concurrent netblocks. |
| 324 | 279 |
| 325 Example: | 280 Example: |
| 326 | 281 |
| 327 ip1 = IPv4Network('192.0.2.0/26') | 282 ip1 = IPv4Network('192.0.2.0/26') |
| 328 ip2 = IPv4Network('192.0.2.64/26') | 283 ip2 = IPv4Network('192.0.2.64/26') |
| 329 ip3 = IPv4Network('192.0.2.128/26') | 284 ip3 = IPv4Network('192.0.2.128/26') |
| 330 ip4 = IPv4Network('192.0.2.192/26') | 285 ip4 = IPv4Network('192.0.2.192/26') |
| (...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 399 if ips and ips[-1]._version != ip._version: | 354 if ips and ips[-1]._version != ip._version: |
| 400 raise TypeError("%s and %s are not of the same version" % ( | 355 raise TypeError("%s and %s are not of the same version" % ( |
| 401 str(ip), str(ips[-1]))) | 356 str(ip), str(ips[-1]))) |
| 402 try: | 357 try: |
| 403 ips.append(ip.ip) | 358 ips.append(ip.ip) |
| 404 except AttributeError: | 359 except AttributeError: |
| 405 ips.append(ip.network_address) | 360 ips.append(ip.network_address) |
| 406 else: | 361 else: |
| 407 if nets and nets[-1]._version != ip._version: | 362 if nets and nets[-1]._version != ip._version: |
| 408 raise TypeError("%s and %s are not of the same version" % ( | 363 raise TypeError("%s and %s are not of the same version" % ( |
| 409 str(ip), str(ips[-1]))) | 364 str(ip), str(nets[-1]))) |
| 410 nets.append(ip) | 365 nets.append(ip) |
| 411 | 366 |
| 412 # sort and dedup | 367 # sort and dedup |
| 413 ips = sorted(set(ips)) | 368 ips = sorted(set(ips)) |
| 414 nets = sorted(set(nets)) | 369 nets = sorted(set(nets)) |
| 415 | 370 |
| 416 while i < len(ips): | 371 while i < len(ips): |
| 417 (first, last) = _find_address_range(ips[i:]) | 372 (first, last) = _find_address_range(ips[i:]) |
| 418 i = ips.index(last) + 1 | 373 i = ips.index(last) + 1 |
| 419 addrs.extend(summarize_address_range(first, last)) | 374 addrs.extend(summarize_address_range(first, last)) |
| (...skipping 20 matching lines...) Expand all Loading... | |
| 440 appropriate key. | 395 appropriate key. |
| 441 | 396 |
| 442 """ | 397 """ |
| 443 if isinstance(obj, _BaseNetwork): | 398 if isinstance(obj, _BaseNetwork): |
| 444 return obj._get_networks_key() | 399 return obj._get_networks_key() |
| 445 elif isinstance(obj, _BaseAddress): | 400 elif isinstance(obj, _BaseAddress): |
| 446 return obj._get_address_key() | 401 return obj._get_address_key() |
| 447 return NotImplemented | 402 return NotImplemented |
| 448 | 403 |
| 449 | 404 |
| 450 class _IPAddressBase(object): | 405 class _IPAddressBase: |
| 451 | 406 |
| 452 """The mother class.""" | 407 """The mother class.""" |
| 453 | 408 |
| 454 @property | 409 @property |
| 455 def exploded(self): | 410 def exploded(self): |
| 456 """Return the longhand version of the IP address as a string.""" | 411 """Return the longhand version of the IP address as a string.""" |
| 457 return self._explode_shorthand_ip_string() | 412 return self._explode_shorthand_ip_string() |
| 458 | 413 |
| 459 @property | 414 @property |
| 460 def compressed(self): | 415 def compressed(self): |
| 461 """Return the shorthand version of the IP address as a string.""" | 416 """Return the shorthand version of the IP address as a string.""" |
| 462 return str(self) | 417 return str(self) |
| 463 | 418 |
| 419 @property | |
| 420 def version(self): | |
| 421 msg = '%200s has no version specified' % (type(self),) | |
| 422 raise NotImplementedError(msg) | |
| 423 | |
| 464 def _ip_int_from_prefix(self, prefixlen=None): | 424 def _ip_int_from_prefix(self, prefixlen=None): |
| 465 """Turn the prefix length netmask into a int for comparison. | 425 """Turn the prefix length netmask into a int for comparison. |
| 466 | 426 |
| 467 Args: | 427 Args: |
| 468 prefixlen: An integer, the prefix length. | 428 prefixlen: An integer, the prefix length. |
| 469 | 429 |
| 470 Returns: | 430 Returns: |
| 471 An integer. | 431 An integer. |
| 472 | 432 |
| 473 """ | 433 """ |
| 474 if not prefixlen and prefixlen != 0: | 434 if prefixlen is None: |
| 475 prefixlen = self._prefixlen | 435 prefixlen = self._prefixlen |
| 476 return self._ALL_ONES ^ (self._ALL_ONES >> prefixlen) | 436 return self._ALL_ONES ^ (self._ALL_ONES >> prefixlen) |
| 477 | 437 |
| 478 def _prefix_from_ip_int(self, ip_int, mask=32): | 438 def _prefix_from_ip_int(self, ip_int, mask=32): |
| 479 """Return prefix length from the decimal netmask. | 439 """Return prefix length from the decimal netmask. |
| 480 | 440 |
| 481 Args: | 441 Args: |
| 482 ip_int: An integer, the IP address. | 442 ip_int: An integer, the IP address. |
| 483 mask: The netmask. Defaults to 32. | 443 mask: The netmask. Defaults to 32. |
| 484 | 444 |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 521 def __init__(self, address): | 481 def __init__(self, address): |
| 522 if (not isinstance(address, bytes) | 482 if (not isinstance(address, bytes) |
| 523 and '/' in str(address)): | 483 and '/' in str(address)): |
| 524 raise AddressValueError(address) | 484 raise AddressValueError(address) |
| 525 | 485 |
| 526 def __index__(self): | 486 def __index__(self): |
| 527 return self._ip | 487 return self._ip |
| 528 | 488 |
| 529 def __int__(self): | 489 def __int__(self): |
| 530 return self._ip | 490 return self._ip |
| 531 | |
| 532 def __hex__(self): | |
| 533 return hex(self._ip) | |
| 534 | 491 |
| 535 def __eq__(self, other): | 492 def __eq__(self, other): |
| 536 try: | 493 try: |
| 537 return (self._ip == other._ip | 494 return (self._ip == other._ip |
| 538 and self._version == other._version) | 495 and self._version == other._version) |
| 539 except AttributeError: | 496 except AttributeError: |
| 540 return NotImplemented | 497 return NotImplemented |
| 541 | 498 |
| 542 def __ne__(self, other): | 499 def __ne__(self, other): |
| 543 eq = self.__eq__(other) | 500 eq = self.__eq__(other) |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 577 str(self), str(other))) | 534 str(self), str(other))) |
| 578 if self._ip != other._ip: | 535 if self._ip != other._ip: |
| 579 return self._ip > other._ip | 536 return self._ip > other._ip |
| 580 return False | 537 return False |
| 581 | 538 |
| 582 # Shorthand for Integer addition and subtraction. This is not | 539 # Shorthand for Integer addition and subtraction. This is not |
| 583 # meant to ever support addition/subtraction of addresses. | 540 # meant to ever support addition/subtraction of addresses. |
| 584 def __add__(self, other): | 541 def __add__(self, other): |
| 585 if not isinstance(other, int): | 542 if not isinstance(other, int): |
| 586 return NotImplemented | 543 return NotImplemented |
| 587 return ip_address(int(self) + other, version=self._version) | 544 return self.__class__(int(self) + other) |
| 588 | 545 |
| 589 def __sub__(self, other): | 546 def __sub__(self, other): |
| 590 if not isinstance(other, int): | 547 if not isinstance(other, int): |
| 591 return NotImplemented | 548 return NotImplemented |
| 592 return ip_address(int(self) - other, version=self._version) | 549 return self.__class__(int(self) - other) |
| 593 | 550 |
| 594 def __repr__(self): | 551 def __repr__(self): |
| 595 return '%s(%r)' % (self.__class__.__name__, str(self)) | 552 return '%s(%r)' % (self.__class__.__name__, str(self)) |
| 596 | 553 |
| 597 def __str__(self): | 554 def __str__(self): |
| 598 return '%s' % self._string_from_ip_int(self._ip) | 555 return str(self._string_from_ip_int(self._ip)) |
| 599 | 556 |
| 600 def __hash__(self): | 557 def __hash__(self): |
| 601 return hash(hex(int(self._ip))) | 558 return hash(hex(int(self._ip))) |
| 602 | 559 |
| 603 def _get_address_key(self): | 560 def _get_address_key(self): |
| 604 return (self._version, self) | 561 return (self._version, self) |
| 605 | 562 |
| 606 @property | |
| 607 def version(self): | |
| 608 raise NotImplementedError('BaseIP has no version') | |
| 609 | |
| 610 | 563 |
| 611 class _BaseNetwork(_IPAddressBase): | 564 class _BaseNetwork(_IPAddressBase): |
| 612 | 565 |
| 613 """A generic IP object. | 566 """A generic IP network object. |
| 614 | 567 |
| 615 This IP class contains the version independent methods which are | 568 This IP class contains the version independent methods which are |
| 616 used by networks. | 569 used by networks. |
| 617 | 570 |
| 618 """ | 571 """ |
| 619 | |
| 620 def __init__(self, address): | 572 def __init__(self, address): |
| 621 self._cache = {} | 573 self._cache = {} |
| 622 | 574 |
| 623 def __index__(self): | 575 def __index__(self): |
| 624 return int(self.network_address) ^ self.prefixlen | 576 return int(self.network_address) ^ self.prefixlen |
| 625 | 577 |
| 626 def __int__(self): | 578 def __int__(self): |
| 627 return int(self.network_address) | 579 return int(self.network_address) |
| 628 | 580 |
| 629 def __repr__(self): | 581 def __repr__(self): |
| 630 return '%s(%r)' % (self.__class__.__name__, str(self)) | 582 return '%s(%r)' % (self.__class__.__name__, str(self)) |
| 631 | 583 |
| 584 def __str__(self): | |
| 585 return '%s/%d' % (str(self.network_address), | |
| 586 self.prefixlen) | |
| 587 | |
| 632 def hosts(self): | 588 def hosts(self): |
| 633 """Generate Iterator over usable hosts in a network. | 589 """Generate Iterator over usable hosts in a network. |
| 634 | 590 |
| 635 This is like __iter__ except it doesn't return the network | 591 This is like __iter__ except it doesn't return the network |
| 636 or broadcast addresses. | 592 or broadcast addresses. |
| 637 | 593 |
| 638 """ | 594 """ |
| 639 cur = int(self.network_address) + 1 | 595 cur = int(self.network_address) + 1 |
| 640 bcast = int(self.broadcast_address) - 1 | 596 bcast = int(self.broadcast_address) - 1 |
| 641 while cur <= bcast: | 597 while cur <= bcast: |
| 642 cur += 1 | 598 cur += 1 |
| 643 yield ip_address(cur - 1, version=self._version) | 599 yield self._address_class(cur - 1) |
| 644 | 600 |
| 645 def __iter__(self): | 601 def __iter__(self): |
| 646 cur = int(self.network_address) | 602 cur = int(self.network_address) |
| 647 bcast = int(self.broadcast_address) | 603 bcast = int(self.broadcast_address) |
| 648 while cur <= bcast: | 604 while cur <= bcast: |
| 649 cur += 1 | 605 cur += 1 |
| 650 yield ip_address(cur - 1, version=self._version) | 606 yield self._address_class(cur - 1) |
| 651 | 607 |
| 652 def __getitem__(self, n): | 608 def __getitem__(self, n): |
| 653 network = int(self.network_address) | 609 network = int(self.network_address) |
| 654 broadcast = int(self.broadcast_address) | 610 broadcast = int(self.broadcast_address) |
| 655 if n >= 0: | 611 if n >= 0: |
| 656 if network + n > broadcast: | 612 if network + n > broadcast: |
| 657 raise IndexError | 613 raise IndexError |
| 658 return ip_address(network + n, version=self._version) | 614 return self._address_class(network + n) |
| 659 else: | 615 else: |
| 660 n += 1 | 616 n += 1 |
| 661 if broadcast + n < network: | 617 if broadcast + n < network: |
| 662 raise IndexError | 618 raise IndexError |
| 663 return ip_address(broadcast + n, version=self._version) | 619 return self._address_class(broadcast + n) |
| 664 | 620 |
| 665 def __lt__(self, other): | 621 def __lt__(self, other): |
| 666 if self._version != other._version: | 622 if self._version != other._version: |
| 667 raise TypeError('%s and %s are not of the same version' % ( | 623 raise TypeError('%s and %s are not of the same version' % ( |
| 668 str(self), str(other))) | 624 str(self), str(other))) |
| 669 if not isinstance(other, _BaseNetwork): | 625 if not isinstance(other, _BaseNetwork): |
| 670 raise TypeError('%s and %s are not of the same type' % ( | 626 raise TypeError('%s and %s are not of the same type' % ( |
| 671 str(self), str(other))) | 627 str(self), str(other))) |
| 672 if self.network_address != other.network_address: | 628 if self.network_address != other.network_address: |
| 673 return self.network_address < other.network_address | 629 return self.network_address < other.network_address |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 707 return (self._version == other._version and | 663 return (self._version == other._version and |
| 708 self.network_address == other.network_address and | 664 self.network_address == other.network_address and |
| 709 int(self.netmask) == int(other.netmask)) | 665 int(self.netmask) == int(other.netmask)) |
| 710 | 666 |
| 711 def __ne__(self, other): | 667 def __ne__(self, other): |
| 712 eq = self.__eq__(other) | 668 eq = self.__eq__(other) |
| 713 if eq is NotImplemented: | 669 if eq is NotImplemented: |
| 714 return NotImplemented | 670 return NotImplemented |
| 715 return not eq | 671 return not eq |
| 716 | 672 |
| 717 def __str__(self): | |
| 718 return '%s/%s' % (str(self.ip), | |
| 719 str(self._prefixlen)) | |
| 720 | |
| 721 def __hash__(self): | 673 def __hash__(self): |
| 722 return hash(int(self.network_address) ^ int(self.netmask)) | 674 return hash(int(self.network_address) ^ int(self.netmask)) |
| 723 | 675 |
| 724 def __contains__(self, other): | 676 def __contains__(self, other): |
| 725 # always false if one is v4 and the other is v6. | 677 # always false if one is v4 and the other is v6. |
| 726 if self._version != other._version: | 678 if self._version != other._version: |
| 727 return False | 679 return False |
| 728 # dealing with another network. | 680 # dealing with another network. |
| 729 if isinstance(other, _BaseNetwork): | 681 if isinstance(other, _BaseNetwork): |
| 730 return False | 682 return False |
| 731 # dealing with another address | 683 # dealing with another address |
| 732 else: | 684 else: |
| 733 # address | 685 # address |
| 734 return (int(self.network_address) <= int(other._ip) <= | 686 return (int(self.network_address) <= int(other._ip) <= |
| 735 int(self.broadcast_address)) | 687 int(self.broadcast_address)) |
| 736 | 688 |
| 737 def overlaps(self, other): | 689 def overlaps(self, other): |
| 738 """Tell if self is partly contained in other.""" | 690 """Tell if self is partly contained in other.""" |
| 739 return self.network_address in other or ( | 691 return self.network_address in other or ( |
| 740 self.broadcast_address in other or ( | 692 self.broadcast_address in other or ( |
| 741 other.network_address in self or ( | 693 other.network_address in self or ( |
| 742 other.broadcast_address in self))) | 694 other.broadcast_address in self))) |
| 743 | 695 |
| 744 @property | 696 @property |
| 745 def broadcast_address(self): | 697 def broadcast_address(self): |
| 746 x = self._cache.get('broadcast_address') | 698 x = self._cache.get('broadcast_address') |
| 747 if x is None: | 699 if x is None: |
| 748 x = ip_address(int(self.network_address) | int(self.hostmask), | 700 x = self._address_class(int(self.network_address) | |
| 749 version=self._version) | 701 int(self.hostmask)) |
| 750 self._cache['broadcast_address'] = x | 702 self._cache['broadcast_address'] = x |
| 751 return x | 703 return x |
| 752 | 704 |
| 753 @property | 705 @property |
| 754 def hostmask(self): | 706 def hostmask(self): |
| 755 x = self._cache.get('hostmask') | 707 x = self._cache.get('hostmask') |
| 756 if x is None: | 708 if x is None: |
| 757 x = ip_address(int(self.netmask) ^ self._ALL_ONES, | 709 x = self._address_class(int(self.netmask) ^ self._ALL_ONES) |
| 758 version=self._version) | |
| 759 self._cache['hostmask'] = x | 710 self._cache['hostmask'] = x |
| 760 return x | 711 return x |
| 761 | 712 |
| 762 @property | 713 @property |
| 763 def network(self): | |
| 764 return ip_network('%s/%d' % (str(self.network_address), | |
| 765 self.prefixlen)) | |
| 766 | |
| 767 @property | |
| 768 def with_prefixlen(self): | 714 def with_prefixlen(self): |
| 769 return '%s/%d' % (str(self.ip), self._prefixlen) | 715 return '%s/%d' % (str(self.network_address), self._prefixlen) |
| 770 | 716 |
| 771 @property | 717 @property |
| 772 def with_netmask(self): | 718 def with_netmask(self): |
| 773 return '%s/%s' % (str(self.ip), str(self.netmask)) | 719 return '%s/%s' % (str(self.network_address), str(self.netmask)) |
| 774 | 720 |
| 775 @property | 721 @property |
| 776 def with_hostmask(self): | 722 def with_hostmask(self): |
| 777 return '%s/%s' % (str(self.ip), str(self.hostmask)) | 723 return '%s/%s' % (str(self.network_address), str(self.hostmask)) |
| 778 | 724 |
| 779 @property | 725 @property |
| 780 def num_addresses(self): | 726 def num_addresses(self): |
| 781 """Number of hosts in the current subnet.""" | 727 """Number of hosts in the current subnet.""" |
| 782 return int(self.broadcast_address) - int(self.network_address) + 1 | 728 return int(self.broadcast_address) - int(self.network_address) + 1 |
| 783 | 729 |
| 784 @property | 730 @property |
| 785 def version(self): | 731 def _address_class(self): |
| 786 raise NotImplementedError('BaseNet has no version') | 732 # Returning bare address objects (rather than interfaces) allows for |
| 733 # more consistent behaviour across the network address, broadcast | |
| 734 # address and individual host addresses. | |
| 735 msg = '%200s has no associated address class' % (type(self),) | |
| 736 raise NotImplementedError(msg) | |
| 787 | 737 |
| 788 @property | 738 @property |
| 789 def prefixlen(self): | 739 def prefixlen(self): |
| 790 return self._prefixlen | 740 return self._prefixlen |
| 791 | 741 |
| 792 def address_exclude(self, other): | 742 def address_exclude(self, other): |
| 793 """Remove an address from a larger block. | 743 """Remove an address from a larger block. |
| 794 | 744 |
| 795 For example: | 745 For example: |
| 796 | 746 |
| (...skipping 30 matching lines...) Expand all Loading... | |
| 827 """ | 777 """ |
| 828 if not self._version == other._version: | 778 if not self._version == other._version: |
| 829 raise TypeError("%s and %s are not of the same version" % ( | 779 raise TypeError("%s and %s are not of the same version" % ( |
| 830 str(self), str(other))) | 780 str(self), str(other))) |
| 831 | 781 |
| 832 if not isinstance(other, _BaseNetwork): | 782 if not isinstance(other, _BaseNetwork): |
| 833 raise TypeError("%s is not a network object" % str(other)) | 783 raise TypeError("%s is not a network object" % str(other)) |
| 834 | 784 |
| 835 if not (other.network_address >= self.network_address and | 785 if not (other.network_address >= self.network_address and |
| 836 other.broadcast_address <= self.broadcast_address): | 786 other.broadcast_address <= self.broadcast_address): |
| 837 raise ValueError('%s not contained in %s' % (str(other), str(self))) | 787 raise ValueError('%s not contained in %s' % (other, self)) |
| 838 | |
| 839 if other == self: | 788 if other == self: |
| 840 raise StopIteration | 789 raise StopIteration |
| 841 | 790 |
| 842 ret_addrs = [] | |
| 843 | |
| 844 # Make sure we're comparing the network of other. | 791 # Make sure we're comparing the network of other. |
| 845 other = ip_network('%s/%s' % (str(other.network_address), | 792 other = other.__class__('%s/%s' % (str(other.network_address), |
| 846 str(other.prefixlen)), | 793 str(other.prefixlen))) |
| 847 version=other._version) | |
| 848 | 794 |
| 849 s1, s2 = self.subnets() | 795 s1, s2 = self.subnets() |
| 850 while s1 != other and s2 != other: | 796 while s1 != other and s2 != other: |
| 851 if (other.network_address >= s1.network_address and | 797 if (other.network_address >= s1.network_address and |
| 852 other.broadcast_address <= s1.broadcast_address): | 798 other.broadcast_address <= s1.broadcast_address): |
| 853 yield s2 | 799 yield s2 |
| 854 s1, s2 = s1.subnets() | 800 s1, s2 = s1.subnets() |
| 855 elif (other.network_address >= s2.network_address and | 801 elif (other.network_address >= s2.network_address and |
| 856 other.broadcast_address <= s2.broadcast_address): | 802 other.broadcast_address <= s2.broadcast_address): |
| 857 yield s1 | 803 yield s1 |
| (...skipping 110 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 968 | 914 |
| 969 if prefixlen_diff < 0: | 915 if prefixlen_diff < 0: |
| 970 raise ValueError('prefix length diff must be > 0') | 916 raise ValueError('prefix length diff must be > 0') |
| 971 new_prefixlen = self._prefixlen + prefixlen_diff | 917 new_prefixlen = self._prefixlen + prefixlen_diff |
| 972 | 918 |
| 973 if not self._is_valid_netmask(str(new_prefixlen)): | 919 if not self._is_valid_netmask(str(new_prefixlen)): |
| 974 raise ValueError( | 920 raise ValueError( |
| 975 'prefix length diff %d is invalid for netblock %s' % ( | 921 'prefix length diff %d is invalid for netblock %s' % ( |
| 976 new_prefixlen, str(self))) | 922 new_prefixlen, str(self))) |
| 977 | 923 |
| 978 first = ip_network('%s/%s' % (str(self.network_address), | 924 first = self.__class__('%s/%s' % |
| 979 str(self._prefixlen + prefixlen_diff)), | 925 (str(self.network_address), |
| 980 version=self._version) | 926 str(self._prefixlen + prefixlen_diff))) |
| 981 | 927 |
| 982 yield first | 928 yield first |
| 983 current = first | 929 current = first |
| 984 while True: | 930 while True: |
| 985 broadcast = current.broadcast_address | 931 broadcast = current.broadcast_address |
| 986 if broadcast == self.broadcast_address: | 932 if broadcast == self.broadcast_address: |
| 987 return | 933 return |
| 988 new_addr = ip_address(int(broadcast) + 1, version=self._version) | 934 new_addr = self._address_class(int(broadcast) + 1) |
| 989 current = ip_network('%s/%s' % (str(new_addr), str(new_prefixlen)), | 935 current = self.__class__('%s/%s' % (str(new_addr), |
| 990 version=self._version) | 936 str(new_prefixlen))) |
| 991 | 937 |
| 992 yield current | 938 yield current |
| 993 | |
| 994 def masked(self): | |
| 995 """Return the network object with the host bits masked out.""" | |
| 996 return ip_network('%s/%d' % (self.network_address, self._prefixlen), | |
| 997 version=self._version) | |
| 998 | 939 |
| 999 def supernet(self, prefixlen_diff=1, new_prefix=None): | 940 def supernet(self, prefixlen_diff=1, new_prefix=None): |
| 1000 """The supernet containing the current network. | 941 """The supernet containing the current network. |
| 1001 | 942 |
| 1002 Args: | 943 Args: |
| 1003 prefixlen_diff: An integer, the amount the prefix length of | 944 prefixlen_diff: An integer, the amount the prefix length of |
| 1004 the network should be decreased by. For example, given a | 945 the network should be decreased by. For example, given a |
| 1005 /24 network and a prefixlen_diff of 3, a supernet with a | 946 /24 network and a prefixlen_diff of 3, a supernet with a |
| 1006 /21 netmask is returned. | 947 /21 netmask is returned. |
| 1007 | 948 |
| 1008 Returns: | 949 Returns: |
| 1009 An IPv4 network object. | 950 An IPv4 network object. |
| 1010 | 951 |
| 1011 Raises: | 952 Raises: |
| 1012 ValueError: If self.prefixlen - prefixlen_diff < 0. I.e., you have a | 953 ValueError: If self.prefixlen - prefixlen_diff < 0. I.e., you have |
| 1013 negative prefix length. | 954 a negative prefix length. |
| 1014 OR | 955 OR |
| 1015 If prefixlen_diff and new_prefix are both set or new_prefix is a | 956 If prefixlen_diff and new_prefix are both set or new_prefix is a |
| 1016 larger number than the current prefix (larger number means a | 957 larger number than the current prefix (larger number means a |
| 1017 smaller network) | 958 smaller network) |
| 1018 | 959 |
| 1019 """ | 960 """ |
| 1020 if self._prefixlen == 0: | 961 if self._prefixlen == 0: |
| 1021 return self | 962 return self |
| 1022 | 963 |
| 1023 if new_prefix is not None: | 964 if new_prefix is not None: |
| 1024 if new_prefix > self._prefixlen: | 965 if new_prefix > self._prefixlen: |
| 1025 raise ValueError('new prefix must be shorter') | 966 raise ValueError('new prefix must be shorter') |
| 1026 if prefixlen_diff != 1: | 967 if prefixlen_diff != 1: |
| 1027 raise ValueError('cannot set prefixlen_diff and new_prefix') | 968 raise ValueError('cannot set prefixlen_diff and new_prefix') |
| 1028 prefixlen_diff = self._prefixlen - new_prefix | 969 prefixlen_diff = self._prefixlen - new_prefix |
| 1029 | 970 |
| 1030 | |
| 1031 if self.prefixlen - prefixlen_diff < 0: | 971 if self.prefixlen - prefixlen_diff < 0: |
| 1032 raise ValueError( | 972 raise ValueError( |
| 1033 'current prefixlen is %d, cannot have a prefixlen_diff of %d' % | 973 'current prefixlen is %d, cannot have a prefixlen_diff of %d' % |
| 1034 (self.prefixlen, prefixlen_diff)) | 974 (self.prefixlen, prefixlen_diff)) |
| 1035 # TODO (pmoody): optimize this. | 975 # TODO (pmoody): optimize this. |
| 1036 t = ip_network('%s/%d' % (str(self.network_address), | 976 t = self.__class__('%s/%d' % (str(self.network_address), |
| 1037 self.prefixlen - prefixlen_diff), | 977 self.prefixlen - prefixlen_diff), |
| 1038 version=self._version, strict=False) | 978 strict=False) |
| 1039 return ip_network('%s/%d' % (str(t.network_address), t.prefixlen), | 979 return t.__class__('%s/%d' % (str(t.network_address), t.prefixlen)) |
| 1040 version=t._version) | 980 |
| 1041 | 981 |
| 1042 | 982 class _BaseV4: |
| 1043 class _BaseV4(object): | |
| 1044 | 983 |
| 1045 """Base IPv4 object. | 984 """Base IPv4 object. |
| 1046 | 985 |
| 1047 The following methods are used by IPv4 objects in both single IP | 986 The following methods are used by IPv4 objects in both single IP |
| 1048 addresses and networks. | 987 addresses and networks. |
| 1049 | 988 |
| 1050 """ | 989 """ |
| 1051 | 990 |
| 1052 # Equivalent to 255.255.255.255 or 32 bits of 1's. | 991 # Equivalent to 255.255.255.255 or 32 bits of 1's. |
| 1053 _ALL_ONES = (2**IPV4LENGTH) - 1 | 992 _ALL_ONES = (2**IPV4LENGTH) - 1 |
| 1054 _DECIMAL_DIGITS = frozenset('0123456789') | 993 _DECIMAL_DIGITS = frozenset('0123456789') |
| 994 | |
| 995 # the valid octets for host and netmasks. only useful for IPv4. | |
| 996 _valid_mask_octets = set((255, 254, 252, 248, 240, 224, 192, 128, 0)) | |
| 1055 | 997 |
| 1056 def __init__(self, address): | 998 def __init__(self, address): |
| 1057 self._version = 4 | 999 self._version = 4 |
| 1058 self._max_prefixlen = IPV4LENGTH | 1000 self._max_prefixlen = IPV4LENGTH |
| 1059 | 1001 |
| 1060 def _explode_shorthand_ip_string(self): | 1002 def _explode_shorthand_ip_string(self): |
| 1061 return str(self) | 1003 return str(self) |
| 1062 | 1004 |
| 1063 def _ip_int_from_string(self, ip_str): | 1005 def _ip_int_from_string(self, ip_str): |
| 1064 """Turn the given IP string into an integer for comparison. | 1006 """Turn the given IP string into an integer for comparison. |
| (...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1116 | 1058 |
| 1117 Returns: | 1059 Returns: |
| 1118 The IP address as a string in dotted decimal notation. | 1060 The IP address as a string in dotted decimal notation. |
| 1119 | 1061 |
| 1120 """ | 1062 """ |
| 1121 octets = [] | 1063 octets = [] |
| 1122 for _ in range(4): | 1064 for _ in range(4): |
| 1123 octets.insert(0, str(ip_int & 0xFF)) | 1065 octets.insert(0, str(ip_int & 0xFF)) |
| 1124 ip_int >>= 8 | 1066 ip_int >>= 8 |
| 1125 return '.'.join(octets) | 1067 return '.'.join(octets) |
| 1068 | |
| 1069 def _is_valid_netmask(self, netmask): | |
| 1070 """Verify that the netmask is valid. | |
| 1071 | |
| 1072 Args: | |
| 1073 netmask: A string, either a prefix or dotted decimal | |
| 1074 netmask. | |
| 1075 | |
| 1076 Returns: | |
| 1077 A boolean, True if the prefix represents a valid IPv4 | |
| 1078 netmask. | |
| 1079 | |
| 1080 """ | |
| 1081 mask = netmask.split('.') | |
| 1082 if len(mask) == 4: | |
| 1083 if [x for x in mask if int(x) not in self._valid_mask_octets]: | |
| 1084 return False | |
| 1085 if [y for idx, y in enumerate(mask) if idx > 0 and | |
| 1086 y > mask[idx - 1]]: | |
| 1087 return False | |
| 1088 return True | |
| 1089 try: | |
| 1090 netmask = int(netmask) | |
| 1091 except ValueError: | |
| 1092 return False | |
| 1093 return 0 <= netmask <= self._max_prefixlen | |
| 1094 | |
| 1095 def _is_hostmask(self, ip_str): | |
| 1096 """Test if the IP string is a hostmask (rather than a netmask). | |
| 1097 | |
| 1098 Args: | |
| 1099 ip_str: A string, the potential hostmask. | |
| 1100 | |
| 1101 Returns: | |
| 1102 A boolean, True if the IP string is a hostmask. | |
| 1103 | |
| 1104 """ | |
| 1105 bits = ip_str.split('.') | |
| 1106 try: | |
| 1107 parts = [int(x) for x in bits if int(x) in self._valid_mask_octets] | |
| 1108 except ValueError: | |
| 1109 return False | |
| 1110 if len(parts) != len(bits): | |
| 1111 return False | |
| 1112 if parts[0] < parts[-1]: | |
| 1113 return True | |
| 1114 return False | |
| 1126 | 1115 |
| 1127 @property | 1116 @property |
| 1128 def max_prefixlen(self): | 1117 def max_prefixlen(self): |
| 1129 return self._max_prefixlen | 1118 return self._max_prefixlen |
| 1130 | 1119 |
| 1131 @property | 1120 @property |
| 1132 def version(self): | 1121 def version(self): |
| 1133 return self._version | 1122 return self._version |
| 1134 | 1123 |
| 1135 @property | 1124 @property |
| (...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1188 def is_unspecified(self): | 1177 def is_unspecified(self): |
| 1189 """Test if the address is unspecified. | 1178 """Test if the address is unspecified. |
| 1190 | 1179 |
| 1191 Returns: | 1180 Returns: |
| 1192 A boolean, True if this is the unspecified address as defined in | 1181 A boolean, True if this is the unspecified address as defined in |
| 1193 RFC 5735 3. | 1182 RFC 5735 3. |
| 1194 | 1183 |
| 1195 """ | 1184 """ |
| 1196 unspecified_address = IPv4Address('0.0.0.0') | 1185 unspecified_address = IPv4Address('0.0.0.0') |
| 1197 if isinstance(self, _BaseAddress): | 1186 if isinstance(self, _BaseAddress): |
| 1198 return self in unspecified_address | 1187 return self == unspecified_address |
| 1199 return (self.network_address == self.broadcast_address == | 1188 return (self.network_address == self.broadcast_address == |
| 1200 unspecified_address) | 1189 unspecified_address) |
| 1201 | 1190 |
| 1202 @property | 1191 @property |
| 1203 def is_loopback(self): | 1192 def is_loopback(self): |
| 1204 """Test if the address is a loopback address. | 1193 """Test if the address is a loopback address. |
| 1205 | 1194 |
| 1206 Returns: | 1195 Returns: |
| 1207 A boolean, True if the address is a loopback per RFC 3330. | 1196 A boolean, True if the address is a loopback per RFC 3330. |
| 1208 | 1197 |
| (...skipping 30 matching lines...) Expand all Loading... | |
| 1239 Args: | 1228 Args: |
| 1240 address: A string or integer representing the IP | 1229 address: A string or integer representing the IP |
| 1241 | 1230 |
| 1242 Additionally, an integer can be passed, so | 1231 Additionally, an integer can be passed, so |
| 1243 IPv4Address('192.0.2.1') == IPv4Address(3221225985). | 1232 IPv4Address('192.0.2.1') == IPv4Address(3221225985). |
| 1244 or, more generally | 1233 or, more generally |
| 1245 IPv4Address(int(IPv4Address('192.0.2.1'))) == | 1234 IPv4Address(int(IPv4Address('192.0.2.1'))) == |
| 1246 IPv4Address('192.0.2.1') | 1235 IPv4Address('192.0.2.1') |
| 1247 | 1236 |
| 1248 Raises: | 1237 Raises: |
| 1249 AddressValueError: If ipaddressisn't a valid IPv4 address. | 1238 AddressValueError: If ipaddress isn't a valid IPv4 address. |
| 1250 | 1239 |
| 1251 """ | 1240 """ |
| 1252 _BaseAddress.__init__(self, address) | 1241 _BaseAddress.__init__(self, address) |
| 1253 _BaseV4.__init__(self, address) | 1242 _BaseV4.__init__(self, address) |
| 1254 | 1243 |
| 1255 # Efficient constructor from integer. | 1244 # Efficient constructor from integer. |
| 1256 if isinstance(address, int): | 1245 if isinstance(address, int): |
| 1257 self._ip = address | 1246 self._ip = address |
| 1258 if address < 0 or address > self._ALL_ONES: | 1247 if address < 0 or address > self._ALL_ONES: |
| 1259 raise AddressValueError(address) | 1248 raise AddressValueError(address) |
| 1260 return | 1249 return |
| 1261 | 1250 |
| 1262 # Constructing from a packed address | 1251 # Constructing from a packed address |
| 1263 if isinstance(address, bytes) and len(address) == 4: | 1252 if (not isinstance(address, str) and |
| 1253 isinstance(address, bytes) and len(address) == 4): | |
| 1264 self._ip = struct.unpack('!I', address)[0] | 1254 self._ip = struct.unpack('!I', address)[0] |
| 1265 return | 1255 return |
| 1266 | 1256 |
| 1267 # Assume input argument to be string or any object representation | 1257 # Assume input argument to be string or any object representation |
| 1268 # which converts into a formatted IP string. | 1258 # which converts into a formatted IP string. |
| 1269 addr_str = str(address) | 1259 addr_str = str(address) |
| 1270 self._ip = self._ip_int_from_string(addr_str) | 1260 self._ip = self._ip_int_from_string(addr_str) |
| 1271 | 1261 |
| 1272 @property | 1262 @property |
| 1273 def packed(self): | 1263 def packed(self): |
| 1274 """The binary representation of this address.""" | 1264 """The binary representation of this address.""" |
| 1275 return v4_int_to_packed(self._ip) | 1265 return v4_int_to_packed(self._ip) |
| 1276 | 1266 |
| 1277 | 1267 |
| 1278 class IPv4Interface(IPv4Address): | 1268 class IPv4Interface(IPv4Address): |
| 1279 | |
| 1280 # the valid octets for host and netmasks. only useful for IPv4. | |
| 1281 _valid_mask_octets = set((255, 254, 252, 248, 240, 224, 192, 128, 0)) | |
| 1282 | 1269 |
| 1283 def __init__(self, address): | 1270 def __init__(self, address): |
| 1284 if isinstance(address, (bytes, int)): | 1271 if isinstance(address, (bytes, int)): |
| 1285 IPv4Address.__init__(self, address) | 1272 IPv4Address.__init__(self, address) |
| 1286 self.network = IPv4Network(self._ip) | 1273 self.network = IPv4Network(self._ip) |
| 1287 self._prefixlen = self._max_prefixlen | 1274 self._prefixlen = self._max_prefixlen |
| 1288 return | 1275 return |
| 1289 | 1276 |
| 1290 addr = str(address).split('/') | 1277 addr = str(address).split('/') |
| 1291 if len(addr) > 2: | 1278 if len(addr) > 2: |
| 1292 raise AddressValueError(address) | 1279 raise AddressValueError(address) |
| 1293 IPv4Address.__init__(self, addr[0]) | 1280 IPv4Address.__init__(self, addr[0]) |
| 1294 | 1281 |
| 1295 self.network = IPv4Network(address, strict=False) | 1282 self.network = IPv4Network(address, strict=False) |
| 1296 self._prefixlen = self.network._prefixlen | 1283 self._prefixlen = self.network._prefixlen |
| 1297 | 1284 |
| 1298 self.netmask = self.network.netmask | 1285 self.netmask = self.network.netmask |
| 1299 self.hostmask = self.network.hostmask | 1286 self.hostmask = self.network.hostmask |
| 1300 | 1287 |
| 1301 | |
| 1302 def __str__(self): | 1288 def __str__(self): |
| 1303 return '%s/%d' % (self._string_from_ip_int(self._ip), | 1289 return '%s/%d' % (self._string_from_ip_int(self._ip), |
| 1304 self.network.prefixlen) | 1290 self.network.prefixlen) |
| 1305 | 1291 |
| 1306 def __eq__(self, other): | 1292 def __eq__(self, other): |
| 1307 try: | 1293 try: |
| 1308 return (IPv4Address.__eq__(self, other) and | 1294 return (IPv4Address.__eq__(self, other) and |
| 1309 self.network == other.network) | 1295 self.network == other.network) |
| 1310 except AttributeError: | 1296 except AttributeError: |
| 1311 return NotImplemented | 1297 return NotImplemented |
| 1312 | 1298 |
| 1313 def __hash__(self): | 1299 def __hash__(self): |
| 1314 return self._ip ^ self._prefixlen ^ int(self.network.network_address) | 1300 return self._ip ^ self._prefixlen ^ int(self.network.network_address) |
| 1315 | 1301 |
| 1316 def _is_valid_netmask(self, netmask): | |
| 1317 """Verify that the netmask is valid. | |
| 1318 | |
| 1319 Args: | |
| 1320 netmask: A string, either a prefix or dotted decimal | |
| 1321 netmask. | |
| 1322 | |
| 1323 Returns: | |
| 1324 A boolean, True if the prefix represents a valid IPv4 | |
| 1325 netmask. | |
| 1326 | |
| 1327 """ | |
| 1328 mask = netmask.split('.') | |
| 1329 if len(mask) == 4: | |
| 1330 if [x for x in mask if int(x) not in self._valid_mask_octets]: | |
| 1331 return False | |
| 1332 if [y for idx, y in enumerate(mask) if idx > 0 and | |
| 1333 y > mask[idx - 1]]: | |
| 1334 return False | |
| 1335 return True | |
| 1336 try: | |
| 1337 netmask = int(netmask) | |
| 1338 except ValueError: | |
| 1339 return False | |
| 1340 return 0 <= netmask <= self._max_prefixlen | |
| 1341 | |
| 1342 def _is_hostmask(self, ip_str): | |
| 1343 """Test if the IP string is a hostmask (rather than a netmask). | |
| 1344 | |
| 1345 Args: | |
| 1346 ip_str: A string, the potential hostmask. | |
| 1347 | |
| 1348 Returns: | |
| 1349 A boolean, True if the IP string is a hostmask. | |
| 1350 | |
| 1351 """ | |
| 1352 bits = ip_str.split('.') | |
| 1353 try: | |
| 1354 parts = [int(x) for x in bits if int(x) in self._valid_mask_octets] | |
| 1355 except ValueError: | |
| 1356 return False | |
| 1357 if len(parts) != len(bits): | |
| 1358 return False | |
| 1359 if parts[0] < parts[-1]: | |
| 1360 return True | |
| 1361 return False | |
| 1362 | |
| 1363 | |
| 1364 @property | 1302 @property |
| 1365 def prefixlen(self): | 1303 def prefixlen(self): |
| 1366 return self._prefixlen | 1304 return self._prefixlen |
| 1367 | 1305 |
| 1368 @property | 1306 @property |
| 1369 def ip(self): | 1307 def ip(self): |
| 1370 return IPv4Address(self._ip) | 1308 return IPv4Address(self._ip) |
| 1371 | 1309 |
| 1372 @property | 1310 @property |
| 1373 def with_prefixlen(self): | 1311 def with_prefixlen(self): |
| 1374 return self | 1312 return self |
| 1375 | 1313 |
| 1376 @property | 1314 @property |
| 1377 def with_netmask(self): | 1315 def with_netmask(self): |
| 1378 return '%s/%s' % (self._string_from_ip_int(self._ip), | 1316 return '%s/%s' % (self._string_from_ip_int(self._ip), |
| 1379 self.netmask) | 1317 self.netmask) |
| 1318 | |
| 1380 @property | 1319 @property |
| 1381 def with_hostmask(self): | 1320 def with_hostmask(self): |
| 1382 return '%s/%s' % (self._string_from_ip_int(self._ip), | 1321 return '%s/%s' % (self._string_from_ip_int(self._ip), |
| 1383 self.hostmask) | 1322 self.hostmask) |
| 1384 | 1323 |
| 1385 | 1324 |
| 1386 class IPv4Network(_BaseV4, _BaseNetwork): | 1325 class IPv4Network(_BaseV4, _BaseNetwork): |
| 1387 | 1326 |
| 1388 """This class represents and manipulates 32-bit IPv4 network + addresses.. | 1327 """This class represents and manipulates 32-bit IPv4 network + addresses.. |
| 1389 | 1328 |
| 1390 Attributes: [examples for IPv4Network('192.0.2.0/27')] | 1329 Attributes: [examples for IPv4Network('192.0.2.0/27')] |
| 1391 .network_address: IPv4Address('192.0.2.0') | 1330 .network_address: IPv4Address('192.0.2.0') |
| 1392 .hostmask: IPv4Address('0.0.0.31') | 1331 .hostmask: IPv4Address('0.0.0.31') |
| 1393 .broadcast_address: IPv4Address('192.0.2.32') | 1332 .broadcast_address: IPv4Address('192.0.2.32') |
| 1394 .netmask: IPv4Address('255.255.255.224') | 1333 .netmask: IPv4Address('255.255.255.224') |
| 1395 .prefixlen: 27 | 1334 .prefixlen: 27 |
| 1396 | 1335 |
| 1397 """ | 1336 """ |
| 1398 | 1337 # Class to use when creating address objects |
| 1399 # the valid octets for host and netmasks. only useful for IPv4. | 1338 _address_class = IPv4Address |
| 1400 _valid_mask_octets = set((255, 254, 252, 248, 240, 224, 192, 128, 0)) | |
| 1401 | 1339 |
| 1402 def __init__(self, address, strict=True): | 1340 def __init__(self, address, strict=True): |
| 1403 | 1341 |
| 1404 """Instantiate a new IPv4 network object. | 1342 """Instantiate a new IPv4 network object. |
| 1405 | 1343 |
| 1406 Args: | 1344 Args: |
| 1407 address: A string or integer representing the IP [& network]. | 1345 address: A string or integer representing the IP [& network]. |
| 1408 '192.0.2.0/24' | 1346 '192.0.2.0/24' |
| 1409 '192.0.2.0/255.255.255.0' | 1347 '192.0.2.0/255.255.255.0' |
| 1410 '192.0.0.2/0.0.0.255' | 1348 '192.0.0.2/0.0.0.255' |
| (...skipping 11 matching lines...) Expand all Loading... | |
| 1422 single exception of an all-zero mask which is treated as a | 1360 single exception of an all-zero mask which is treated as a |
| 1423 netmask == /0. If no mask is given, a default of /32 is used. | 1361 netmask == /0. If no mask is given, a default of /32 is used. |
| 1424 | 1362 |
| 1425 Additionally, an integer can be passed, so | 1363 Additionally, an integer can be passed, so |
| 1426 IPv4Network('192.0.2.1') == IPv4Network(3221225985) | 1364 IPv4Network('192.0.2.1') == IPv4Network(3221225985) |
| 1427 or, more generally | 1365 or, more generally |
| 1428 IPv4Interface(int(IPv4Interface('192.0.2.1'))) == | 1366 IPv4Interface(int(IPv4Interface('192.0.2.1'))) == |
| 1429 IPv4Interface('192.0.2.1') | 1367 IPv4Interface('192.0.2.1') |
| 1430 | 1368 |
| 1431 Raises: | 1369 Raises: |
| 1432 AddressValueError: If ipaddressisn't a valid IPv4 address. | 1370 AddressValueError: If ipaddress isn't a valid IPv4 address. |
| 1433 NetmaskValueError: If the netmask isn't valid for | 1371 NetmaskValueError: If the netmask isn't valid for |
| 1434 an IPv4 address. | 1372 an IPv4 address. |
| 1435 ValueError: If strict was True and a network address was not | 1373 ValueError: If strict is True and a network address is not |
| 1436 supplied. | 1374 supplied. |
| 1437 | 1375 |
| 1438 """ | 1376 """ |
| 1439 | 1377 |
| 1440 _BaseV4.__init__(self, address) | 1378 _BaseV4.__init__(self, address) |
| 1441 _BaseNetwork.__init__(self, address) | 1379 _BaseNetwork.__init__(self, address) |
| 1442 | 1380 |
| 1443 # Constructing from a packed address | 1381 # Constructing from a packed address |
| 1444 if isinstance(address, bytes) and len(address) == 4: | 1382 if isinstance(address, bytes) and len(address) == 4: |
| 1445 self.network_address = IPv4Address( | 1383 self.network_address = IPv4Address( |
| (...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1498 if strict: | 1436 if strict: |
| 1499 if (IPv4Address(int(self.network_address) & int(self.netmask)) != | 1437 if (IPv4Address(int(self.network_address) & int(self.netmask)) != |
| 1500 self.network_address): | 1438 self.network_address): |
| 1501 raise ValueError('%s has host bits set' % self) | 1439 raise ValueError('%s has host bits set' % self) |
| 1502 self.network_address = IPv4Address(int(self.network_address) & | 1440 self.network_address = IPv4Address(int(self.network_address) & |
| 1503 int(self.netmask)) | 1441 int(self.netmask)) |
| 1504 | 1442 |
| 1505 if self._prefixlen == (self._max_prefixlen - 1): | 1443 if self._prefixlen == (self._max_prefixlen - 1): |
| 1506 self.hosts = self.__iter__ | 1444 self.hosts = self.__iter__ |
| 1507 | 1445 |
| 1508 @property | 1446 |
| 1509 def packed(self): | 1447 class _BaseV6: |
| 1510 """The binary representation of this address.""" | |
| 1511 return v4_int_to_packed(self.network_address) | |
| 1512 | |
| 1513 def __str__(self): | |
| 1514 return '%s/%d' % (str(self.network_address), | |
| 1515 self.prefixlen) | |
| 1516 | |
| 1517 def _is_valid_netmask(self, netmask): | |
| 1518 """Verify that the netmask is valid. | |
| 1519 | |
| 1520 Args: | |
| 1521 netmask: A string, either a prefix or dotted decimal | |
| 1522 netmask. | |
| 1523 | |
| 1524 Returns: | |
| 1525 A boolean, True if the prefix represents a valid IPv4 | |
| 1526 netmask. | |
| 1527 | |
| 1528 """ | |
| 1529 mask = netmask.split('.') | |
| 1530 if len(mask) == 4: | |
| 1531 if [x for x in mask if int(x) not in self._valid_mask_octets]: | |
| 1532 return False | |
| 1533 if [y for idx, y in enumerate(mask) if idx > 0 and | |
| 1534 y > mask[idx - 1]]: | |
| 1535 return False | |
| 1536 return True | |
| 1537 try: | |
| 1538 netmask = int(netmask) | |
| 1539 except ValueError: | |
| 1540 return False | |
| 1541 return 0 <= netmask <= self._max_prefixlen | |
| 1542 | |
| 1543 def _is_hostmask(self, ip_str): | |
| 1544 """Test if the IP string is a hostmask (rather than a netmask). | |
| 1545 | |
| 1546 Args: | |
| 1547 ip_str: A string, the potential hostmask. | |
| 1548 | |
| 1549 Returns: | |
| 1550 A boolean, True if the IP string is a hostmask. | |
| 1551 | |
| 1552 """ | |
| 1553 bits = ip_str.split('.') | |
| 1554 try: | |
| 1555 parts = [int(x) for x in bits if int(x) in self._valid_mask_octets] | |
| 1556 except ValueError: | |
| 1557 return False | |
| 1558 if len(parts) != len(bits): | |
| 1559 return False | |
| 1560 if parts[0] < parts[-1]: | |
| 1561 return True | |
| 1562 return False | |
| 1563 | |
| 1564 @property | |
| 1565 def with_prefixlen(self): | |
| 1566 return '%s/%d' % (str(self.network_address), self._prefixlen) | |
| 1567 | |
| 1568 @property | |
| 1569 def with_netmask(self): | |
| 1570 return '%s/%s' % (str(self.network_address), str(self.netmask)) | |
| 1571 | |
| 1572 @property | |
| 1573 def with_hostmask(self): | |
| 1574 return '%s/%s' % (str(self.network_address), str(self.hostmask)) | |
| 1575 | |
| 1576 | |
| 1577 class _BaseV6(object): | |
| 1578 | 1448 |
| 1579 """Base IPv6 object. | 1449 """Base IPv6 object. |
| 1580 | 1450 |
| 1581 The following methods are used by IPv6 objects in both single IP | 1451 The following methods are used by IPv6 objects in both single IP |
| 1582 addresses and networks. | 1452 addresses and networks. |
| 1583 | 1453 |
| 1584 """ | 1454 """ |
| 1585 | 1455 |
| 1586 _ALL_ONES = (2**IPV6LENGTH) - 1 | 1456 _ALL_ONES = (2**IPV6LENGTH) - 1 |
| 1587 _HEXTET_COUNT = 8 | 1457 _HEXTET_COUNT = 8 |
| (...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1641 if parts_hi: | 1511 if parts_hi: |
| 1642 raise AddressValueError(ip_str) # ^: requires ^:: | 1512 raise AddressValueError(ip_str) # ^: requires ^:: |
| 1643 if not parts[-1]: | 1513 if not parts[-1]: |
| 1644 parts_lo -= 1 | 1514 parts_lo -= 1 |
| 1645 if parts_lo: | 1515 if parts_lo: |
| 1646 raise AddressValueError(ip_str) # :$ requires ::$ | 1516 raise AddressValueError(ip_str) # :$ requires ::$ |
| 1647 parts_skipped = self._HEXTET_COUNT - (parts_hi + parts_lo) | 1517 parts_skipped = self._HEXTET_COUNT - (parts_hi + parts_lo) |
| 1648 if parts_skipped < 1: | 1518 if parts_skipped < 1: |
| 1649 raise AddressValueError(ip_str) | 1519 raise AddressValueError(ip_str) |
| 1650 else: | 1520 else: |
| 1651 # Otherwise, allocate the entire address to parts_hi. The endpoints | 1521 # Otherwise, allocate the entire address to parts_hi. The |
| 1652 # could still be empty, but _parse_hextet() will check for that. | 1522 # endpoints could still be empty, but _parse_hextet() will check |
| 1523 # for that. | |
| 1653 if len(parts) != self._HEXTET_COUNT: | 1524 if len(parts) != self._HEXTET_COUNT: |
| 1654 raise AddressValueError(ip_str) | 1525 raise AddressValueError(ip_str) |
| 1655 parts_hi = len(parts) | 1526 parts_hi = len(parts) |
| 1656 parts_lo = 0 | 1527 parts_lo = 0 |
| 1657 parts_skipped = 0 | 1528 parts_skipped = 0 |
| 1658 | 1529 |
| 1659 try: | 1530 try: |
| 1660 # Now, parse the hextets into a 128-bit integer. | 1531 # Now, parse the hextets into a 128-bit integer. |
| 1661 ip_int = 0 | 1532 ip_int = 0 |
| 1662 for i in range(parts_hi): | 1533 for i in range(parts_hi): |
| (...skipping 10 matching lines...) Expand all Loading... | |
| 1673 def _parse_hextet(self, hextet_str): | 1544 def _parse_hextet(self, hextet_str): |
| 1674 """Convert an IPv6 hextet string into an integer. | 1545 """Convert an IPv6 hextet string into an integer. |
| 1675 | 1546 |
| 1676 Args: | 1547 Args: |
| 1677 hextet_str: A string, the number to parse. | 1548 hextet_str: A string, the number to parse. |
| 1678 | 1549 |
| 1679 Returns: | 1550 Returns: |
| 1680 The hextet as an integer. | 1551 The hextet as an integer. |
| 1681 | 1552 |
| 1682 Raises: | 1553 Raises: |
| 1683 ValueError: if the input isn't strictly a hex number from [0..FFFF]. | 1554 ValueError: if the input isn't strictly a hex number from |
| 1555 [0..FFFF]. | |
| 1684 | 1556 |
| 1685 """ | 1557 """ |
| 1686 # Whitelist the characters, since int() allows a lot of bizarre stuff. | 1558 # Whitelist the characters, since int() allows a lot of bizarre stuff. |
| 1687 if not self._HEX_DIGITS.issuperset(hextet_str): | 1559 if not self._HEX_DIGITS.issuperset(hextet_str): |
| 1560 raise ValueError | |
| 1561 if len(hextet_str) > 4: | |
| 1688 raise ValueError | 1562 raise ValueError |
| 1689 hextet_int = int(hextet_str, 16) | 1563 hextet_int = int(hextet_str, 16) |
| 1690 if hextet_int > 0xFFFF: | 1564 if hextet_int > 0xFFFF: |
| 1691 raise ValueError | 1565 raise ValueError |
| 1692 return hextet_int | 1566 return hextet_int |
| 1693 | 1567 |
| 1694 def _compress_hextets(self, hextets): | 1568 def _compress_hextets(self, hextets): |
| 1695 """Compresses a list of hextets. | 1569 """Compresses a list of hextets. |
| 1696 | 1570 |
| 1697 Compresses a list of strings, replacing the longest continuous | 1571 Compresses a list of strings, replacing the longest continuous |
| (...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1744 Args: | 1618 Args: |
| 1745 ip_int: An integer, the IP address. | 1619 ip_int: An integer, the IP address. |
| 1746 | 1620 |
| 1747 Returns: | 1621 Returns: |
| 1748 A string, the hexadecimal representation of the address. | 1622 A string, the hexadecimal representation of the address. |
| 1749 | 1623 |
| 1750 Raises: | 1624 Raises: |
| 1751 ValueError: The address is bigger than 128 bits of all ones. | 1625 ValueError: The address is bigger than 128 bits of all ones. |
| 1752 | 1626 |
| 1753 """ | 1627 """ |
| 1754 if not ip_int and ip_int != 0: | 1628 if ip_int is None: |
| 1755 ip_int = int(self._ip) | 1629 ip_int = int(self._ip) |
| 1756 | 1630 |
| 1757 if ip_int > self._ALL_ONES: | 1631 if ip_int > self._ALL_ONES: |
| 1758 raise ValueError('IPv6 address is too large') | 1632 raise ValueError('IPv6 address is too large') |
| 1759 | 1633 |
| 1760 hex_str = '%032x' % ip_int | 1634 hex_str = '%032x' % ip_int |
| 1761 hextets = [] | 1635 hextets = [] |
| 1762 for x in range(0, 32, 4): | 1636 for x in range(0, 32, 4): |
| 1763 hextets.append('%x' % int(hex_str[x:x+4], 16)) | 1637 hextets.append('%x' % int(hex_str[x:x+4], 16)) |
| 1764 | 1638 |
| (...skipping 25 matching lines...) Expand all Loading... | |
| 1790 parts.reverse() | 1664 parts.reverse() |
| 1791 if isinstance(self, (_BaseNetwork, IPv6Interface)): | 1665 if isinstance(self, (_BaseNetwork, IPv6Interface)): |
| 1792 return '%s/%d' % (':'.join(parts), self.prefixlen) | 1666 return '%s/%d' % (':'.join(parts), self.prefixlen) |
| 1793 return ':'.join(parts) | 1667 return ':'.join(parts) |
| 1794 | 1668 |
| 1795 @property | 1669 @property |
| 1796 def max_prefixlen(self): | 1670 def max_prefixlen(self): |
| 1797 return self._max_prefixlen | 1671 return self._max_prefixlen |
| 1798 | 1672 |
| 1799 @property | 1673 @property |
| 1800 def packed(self): | |
| 1801 """The binary representation of this address.""" | |
| 1802 return v6_int_to_packed(self._ip) | |
| 1803 | |
| 1804 @property | |
| 1805 def version(self): | 1674 def version(self): |
| 1806 return self._version | 1675 return self._version |
| 1807 | 1676 |
| 1808 @property | 1677 @property |
| 1809 def is_multicast(self): | 1678 def is_multicast(self): |
| 1810 """Test if the address is reserved for multicast use. | 1679 """Test if the address is reserved for multicast use. |
| 1811 | 1680 |
| 1812 Returns: | 1681 Returns: |
| 1813 A boolean, True if the address is a multicast address. | 1682 A boolean, True if the address is a multicast address. |
| 1814 See RFC 2373 2.7 for details. | 1683 See RFC 2373 2.7 for details. |
| (...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1882 Returns: | 1751 Returns: |
| 1883 A boolean, True if the address is reserved per RFC 4193. | 1752 A boolean, True if the address is reserved per RFC 4193. |
| 1884 | 1753 |
| 1885 """ | 1754 """ |
| 1886 private_network = IPv6Network('fc00::/7') | 1755 private_network = IPv6Network('fc00::/7') |
| 1887 if isinstance(self, _BaseAddress): | 1756 if isinstance(self, _BaseAddress): |
| 1888 return self in private_network | 1757 return self in private_network |
| 1889 return (self.network_address in private_network and | 1758 return (self.network_address in private_network and |
| 1890 self.broadcast_address in private_network) | 1759 self.broadcast_address in private_network) |
| 1891 | 1760 |
| 1892 | |
| 1893 @property | 1761 @property |
| 1894 def ipv4_mapped(self): | 1762 def ipv4_mapped(self): |
| 1895 """Return the IPv4 mapped address. | 1763 """Return the IPv4 mapped address. |
| 1896 | 1764 |
| 1897 Returns: | 1765 Returns: |
| 1898 If the IPv6 address is a v4 mapped address, return the | 1766 If the IPv6 address is a v4 mapped address, return the |
| 1899 IPv4 mapped address. Return None otherwise. | 1767 IPv4 mapped address. Return None otherwise. |
| 1900 | 1768 |
| 1901 """ | 1769 """ |
| 1902 if (self._ip >> 32) != 0xFFFF: | 1770 if (self._ip >> 32) != 0xFFFF: |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1948 @property | 1816 @property |
| 1949 def is_loopback(self): | 1817 def is_loopback(self): |
| 1950 """Test if the address is a loopback address. | 1818 """Test if the address is a loopback address. |
| 1951 | 1819 |
| 1952 Returns: | 1820 Returns: |
| 1953 A boolean, True if the address is a loopback address as defined in | 1821 A boolean, True if the address is a loopback address as defined in |
| 1954 RFC 2373 2.5.3. | 1822 RFC 2373 2.5.3. |
| 1955 | 1823 |
| 1956 """ | 1824 """ |
| 1957 if isinstance(self, IPv6Network): | 1825 if isinstance(self, IPv6Network): |
| 1958 return int(self.network) == 1 and getattr( | 1826 return int(self) == 1 and getattr( |
| 1959 self, '_prefixlen', 128) == 128 | 1827 self, '_prefixlen', 128) == 128 |
| 1960 elif isinstance(self, IPv6Interface): | 1828 elif isinstance(self, IPv6Interface): |
| 1961 return int(self.network.network_address) == 1 and getattr( | 1829 return int(self.network.network_address) == 1 and getattr( |
| 1962 self, '_prefixlen', 128) == 128 | 1830 self, '_prefixlen', 128) == 128 |
| 1963 return self._ip == 1 | 1831 return self._ip == 1 |
| 1964 | 1832 |
| 1965 | 1833 |
| 1966 class IPv6Address(_BaseV6, _BaseAddress): | 1834 class IPv6Address(_BaseV6, _BaseAddress): |
| 1967 | 1835 |
| 1968 """Represent and manipulate single IPv6 Addresses. | 1836 """Represent and manipulate single IPv6 Addresses.""" |
| 1969 """ | |
| 1970 | 1837 |
| 1971 def __init__(self, address): | 1838 def __init__(self, address): |
| 1972 """Instantiate a new IPv6 address object. | 1839 """Instantiate a new IPv6 address object. |
| 1973 | 1840 |
| 1974 Args: | 1841 Args: |
| 1975 address: A string or integer representing the IP | 1842 address: A string or integer representing the IP |
| 1976 | 1843 |
| 1977 Additionally, an integer can be passed, so | 1844 Additionally, an integer can be passed, so |
| 1978 IPv6Address('2001:db8::') == | 1845 IPv6Address('2001:db8::') == |
| 1979 IPv6Address(42540766411282592856903984951653826560) | 1846 IPv6Address(42540766411282592856903984951653826560) |
| 1980 or, more generally | 1847 or, more generally |
| 1981 IPv6Address(int(IPv6Address('2001:db8::'))) == | 1848 IPv6Address(int(IPv6Address('2001:db8::'))) == |
| 1982 IPv6Address('2001:db8::') | 1849 IPv6Address('2001:db8::') |
| 1983 | 1850 |
| 1984 Raises: | 1851 Raises: |
| 1985 AddressValueError: If address isn't a valid IPv6 address. | 1852 AddressValueError: If address isn't a valid IPv6 address. |
| 1986 | 1853 |
| 1987 """ | 1854 """ |
| 1988 _BaseAddress.__init__(self, address) | 1855 _BaseAddress.__init__(self, address) |
| 1989 _BaseV6.__init__(self, address) | 1856 _BaseV6.__init__(self, address) |
| 1990 | 1857 |
| 1991 # Efficient constructor from integer. | 1858 # Efficient constructor from integer. |
| 1992 if isinstance(address, int): | 1859 if isinstance(address, int): |
| 1993 self._ip = address | 1860 self._ip = address |
| 1994 if address < 0 or address > self._ALL_ONES: | 1861 if address < 0 or address > self._ALL_ONES: |
| 1995 raise AddressValueError(address) | 1862 raise AddressValueError(address) |
| 1996 return | 1863 return |
| 1997 | 1864 |
| 1998 # Constructing from a packed address | 1865 # Constructing from a packed address |
| 1999 if isinstance(address, bytes) and len(address) == 16: | 1866 if (not isinstance(address, str) and |
| 1867 isinstance(address, bytes) and len(address) == 16): | |
| 2000 tmp = struct.unpack('!QQ', address) | 1868 tmp = struct.unpack('!QQ', address) |
| 2001 self._ip = (tmp[0] << 64) | tmp[1] | 1869 self._ip = (tmp[0] << 64) | tmp[1] |
| 2002 return | 1870 return |
| 2003 | 1871 |
| 2004 # Assume input argument to be string or any object representation | 1872 # Assume input argument to be string or any object representation |
| 2005 # which converts into a formatted IP string. | 1873 # which converts into a formatted IP string. |
| 2006 addr_str = str(address) | 1874 addr_str = str(address) |
| 2007 if not addr_str: | 1875 if not addr_str: |
| 2008 raise AddressValueError('') | 1876 raise AddressValueError('') |
| 2009 | 1877 |
| 2010 self._ip = self._ip_int_from_string(addr_str) | 1878 self._ip = self._ip_int_from_string(addr_str) |
| 1879 | |
| 1880 @property | |
| 1881 def packed(self): | |
| 1882 """The binary representation of this address.""" | |
| 1883 return v6_int_to_packed(self._ip) | |
| 2011 | 1884 |
| 2012 | 1885 |
| 2013 class IPv6Interface(IPv6Address): | 1886 class IPv6Interface(IPv6Address): |
| 2014 | 1887 |
| 2015 def __init__(self, address): | 1888 def __init__(self, address): |
| 2016 if isinstance(address, (bytes, int)): | 1889 if isinstance(address, (bytes, int)): |
| 2017 IPv6Address.__init__(self, address) | 1890 IPv6Address.__init__(self, address) |
| 2018 self.network = IPv6Network(self._ip) | 1891 self.network = IPv6Network(self._ip) |
| 2019 self._prefixlen = self._max_prefixlen | 1892 self._prefixlen = self._max_prefixlen |
| 2020 return | 1893 return |
| 2021 | 1894 |
| 2022 addr = str(address).split('/') | 1895 addr = str(address).split('/') |
| 2023 IPv6Address.__init__(self, addr[0]) | 1896 IPv6Address.__init__(self, addr[0]) |
| 2024 self.network = IPv6Network(address, strict=False) | 1897 self.network = IPv6Network(address, strict=False) |
| 2025 self.netmask = self.network.netmask | 1898 self.netmask = self.network.netmask |
| 2026 self._prefixlen = self.network._prefixlen | 1899 self._prefixlen = self.network._prefixlen |
| 2027 self.hostmask = self.network.hostmask | 1900 self.hostmask = self.network.hostmask |
| 2028 | 1901 |
| 2029 | |
| 2030 def __str__(self): | 1902 def __str__(self): |
| 2031 return '%s/%d' % (self._string_from_ip_int(self._ip), | 1903 return '%s/%d' % (self._string_from_ip_int(self._ip), |
| 2032 self.network.prefixlen) | 1904 self.network.prefixlen) |
| 2033 | 1905 |
| 2034 def __eq__(self, other): | 1906 def __eq__(self, other): |
| 2035 try: | 1907 try: |
| 2036 return (IPv6Address.__eq__(self, other) and | 1908 return (IPv6Address.__eq__(self, other) and |
| 2037 self.network == other.network) | 1909 self.network == other.network) |
| 2038 except AttributeError: | 1910 except AttributeError: |
| 2039 return NotImplemented | 1911 return NotImplemented |
| 2040 | 1912 |
| 2041 def __hash__(self): | 1913 def __hash__(self): |
| 2042 return self._ip ^ self._prefixlen ^ int(self.network.network_address) | 1914 return self._ip ^ self._prefixlen ^ int(self.network.network_address) |
| 2043 | 1915 |
| 2044 @property | 1916 @property |
| 2045 def prefixlen(self): | 1917 def prefixlen(self): |
| 2046 return self._prefixlen | 1918 return self._prefixlen |
| 1919 | |
| 2047 @property | 1920 @property |
| 2048 def ip(self): | 1921 def ip(self): |
| 2049 return IPv6Address(self._ip) | 1922 return IPv6Address(self._ip) |
| 2050 | 1923 |
| 2051 @property | 1924 @property |
| 2052 def with_prefixlen(self): | 1925 def with_prefixlen(self): |
| 2053 return self | 1926 return self |
| 2054 | 1927 |
| 2055 @property | 1928 @property |
| 2056 def with_netmask(self): | 1929 def with_netmask(self): |
| 2057 return self.with_prefixlen | 1930 return self.with_prefixlen |
| 1931 | |
| 2058 @property | 1932 @property |
| 2059 def with_hostmask(self): | 1933 def with_hostmask(self): |
| 2060 return '%s/%s' % (self._string_from_ip_int(self._ip), | 1934 return '%s/%s' % (self._string_from_ip_int(self._ip), |
| 2061 self.hostmask) | 1935 self.hostmask) |
| 2062 | 1936 |
| 2063 | 1937 |
| 2064 class IPv6Network(_BaseV6, _BaseNetwork): | 1938 class IPv6Network(_BaseV6, _BaseNetwork): |
| 2065 | 1939 |
| 2066 """This class represents and manipulates 128-bit IPv6 networks. | 1940 """This class represents and manipulates 128-bit IPv6 networks. |
| 2067 | 1941 |
| 2068 Attributes: [examples for IPv6('2001:db8::1000/124')] | 1942 Attributes: [examples for IPv6('2001:db8::1000/124')] |
| 2069 .network_address: IPv6Address('2001:db8::1000') | 1943 .network_address: IPv6Address('2001:db8::1000') |
| 2070 .hostmask: IPv6Address('::f') | 1944 .hostmask: IPv6Address('::f') |
| 2071 .broadcast_address: IPv6Address('2001:db8::100f') | 1945 .broadcast_address: IPv6Address('2001:db8::100f') |
| 2072 .netmask: IPv6Address('ffff:ffff:ffff:ffff:ffff:ffff:ffff:fff0') | 1946 .netmask: IPv6Address('ffff:ffff:ffff:ffff:ffff:ffff:ffff:fff0') |
| 2073 .prefixlen: 124 | 1947 .prefixlen: 124 |
| 2074 | 1948 |
| 2075 """ | 1949 """ |
| 2076 | 1950 |
| 1951 # Class to use when creating address objects | |
| 1952 _address_class = IPv6Address | |
| 1953 | |
| 2077 def __init__(self, address, strict=True): | 1954 def __init__(self, address, strict=True): |
| 2078 """Instantiate a new IPv6 Network object. | 1955 """Instantiate a new IPv6 Network object. |
| 2079 | 1956 |
| 2080 Args: | 1957 Args: |
| 2081 address: A string or integer representing the IPv6 network or the IP | 1958 address: A string or integer representing the IPv6 network or the |
| 2082 and prefix/netmask. | 1959 IP and prefix/netmask. |
| 2083 '2001:db8::/128' | 1960 '2001:db8::/128' |
| 2084 '2001:db8:0000:0000:0000:0000:0000:0000/128' | 1961 '2001:db8:0000:0000:0000:0000:0000:0000/128' |
| 2085 '2001:db8::' | 1962 '2001:db8::' |
| 2086 are all functionally the same in IPv6. That is to say, | 1963 are all functionally the same in IPv6. That is to say, |
| 2087 failing to provide a subnetmask will create an object with | 1964 failing to provide a subnetmask will create an object with |
| 2088 a mask of /128. | 1965 a mask of /128. |
| 2089 | 1966 |
| 2090 Additionally, an integer can be passed, so | 1967 Additionally, an integer can be passed, so |
| 2091 IPv6Network('2001:db8::') == | 1968 IPv6Network('2001:db8::') == |
| 2092 IPv6Network(42540766411282592856903984951653826560) | 1969 IPv6Network(42540766411282592856903984951653826560) |
| (...skipping 16 matching lines...) Expand all Loading... | |
| 2109 _BaseV6.__init__(self, address) | 1986 _BaseV6.__init__(self, address) |
| 2110 _BaseNetwork.__init__(self, address) | 1987 _BaseNetwork.__init__(self, address) |
| 2111 | 1988 |
| 2112 # Efficient constructor from integer. | 1989 # Efficient constructor from integer. |
| 2113 if isinstance(address, int): | 1990 if isinstance(address, int): |
| 2114 if address < 0 or address > self._ALL_ONES: | 1991 if address < 0 or address > self._ALL_ONES: |
| 2115 raise AddressValueError(address) | 1992 raise AddressValueError(address) |
| 2116 self.network_address = IPv6Address(address) | 1993 self.network_address = IPv6Address(address) |
| 2117 self._prefixlen = self._max_prefixlen | 1994 self._prefixlen = self._max_prefixlen |
| 2118 self.netmask = IPv6Address(self._ALL_ONES) | 1995 self.netmask = IPv6Address(self._ALL_ONES) |
| 2119 if strict: | |
| 2120 if (IPv6Address(int(self.network_address) & | |
| 2121 int(self.netmask)) != self.network_address): | |
| 2122 raise ValueError('%s has host bits set' % str(self)) | |
| 2123 self.network_address = IPv6Address(int(self.network_address) & | |
| 2124 int(self.netmask)) | |
| 2125 return | 1996 return |
| 2126 | 1997 |
| 2127 # Constructing from a packed address | 1998 # Constructing from a packed address |
| 2128 if isinstance(address, bytes) and len(address) == 16: | 1999 if isinstance(address, bytes) and len(address) == 16: |
| 2129 tmp = struct.unpack('!QQ', address) | 2000 tmp = struct.unpack('!QQ', address) |
| 2130 self.network_address = IPv6Address((tmp[0] << 64) | tmp[1]) | 2001 self.network_address = IPv6Address((tmp[0] << 64) | tmp[1]) |
| 2131 self._prefixlen = self._max_prefixlen | 2002 self._prefixlen = self._max_prefixlen |
| 2132 self.netmask = IPv6Address(self._ALL_ONES) | 2003 self.netmask = IPv6Address(self._ALL_ONES) |
| 2133 if strict: | 2004 return |
| 2134 if (IPv6Address(int(self.network_address) & | |
| 2135 int(self.netmask)) != self.network_address): | |
| 2136 raise ValueError('%s has host bits set' % str(self)) | |
| 2137 self.network_address = IPv6Address(int(self.network_address) & | |
| 2138 int(self.netmask)) | |
| 2139 return | |
| 2140 | 2005 |
| 2141 # Assume input argument to be string or any object representation | 2006 # Assume input argument to be string or any object representation |
| 2142 # which converts into a formatted IP prefix string. | 2007 # which converts into a formatted IP prefix string. |
| 2143 addr = str(address).split('/') | 2008 addr = str(address).split('/') |
| 2144 | 2009 |
| 2145 if len(addr) > 2: | 2010 if len(addr) > 2: |
| 2146 raise AddressValueError(address) | 2011 raise AddressValueError(address) |
| 2147 | 2012 |
| 2148 self.network_address = IPv6Address(self._ip_int_from_string(addr[0])) | 2013 self.network_address = IPv6Address(self._ip_int_from_string(addr[0])) |
| 2149 | 2014 |
| 2150 if len(addr) == 2: | 2015 if len(addr) == 2: |
| 2151 if self._is_valid_netmask(addr[1]): | 2016 if self._is_valid_netmask(addr[1]): |
| 2152 self._prefixlen = int(addr[1]) | 2017 self._prefixlen = int(addr[1]) |
| 2153 else: | 2018 else: |
| 2154 raise NetmaskValueError(addr[1]) | 2019 raise NetmaskValueError(addr[1]) |
| 2155 else: | 2020 else: |
| 2156 self._prefixlen = self._max_prefixlen | 2021 self._prefixlen = self._max_prefixlen |
| 2157 | 2022 |
| 2158 self.netmask = IPv6Address(self._ip_int_from_prefix(self._prefixlen)) | 2023 self.netmask = IPv6Address(self._ip_int_from_prefix(self._prefixlen)) |
| 2159 if strict: | 2024 if strict: |
| 2160 if (IPv6Address(int(self.network_address) & int(self.netmask)) != | 2025 if (IPv6Address(int(self.network_address) & int(self.netmask)) != |
| 2161 self.network_address): | 2026 self.network_address): |
| 2162 raise ValueError('%s has host bits set' % str(self)) | 2027 raise ValueError('%s has host bits set' % str(self)) |
| 2163 self.network_address = IPv6Address(int(self.network_address) & | 2028 self.network_address = IPv6Address(int(self.network_address) & |
| 2164 int(self.netmask)) | 2029 int(self.netmask)) |
| 2165 | 2030 |
| 2166 if self._prefixlen == (self._max_prefixlen - 1): | 2031 if self._prefixlen == (self._max_prefixlen - 1): |
| 2167 self.hosts = self.__iter__ | 2032 self.hosts = self.__iter__ |
| 2168 | 2033 |
| 2169 def __str__(self): | |
| 2170 return '%s/%d' % (str(self.network_address), | |
| 2171 self.prefixlen) | |
| 2172 | |
| 2173 def _is_valid_netmask(self, prefixlen): | 2034 def _is_valid_netmask(self, prefixlen): |
| 2174 """Verify that the netmask/prefixlen is valid. | 2035 """Verify that the netmask/prefixlen is valid. |
| 2175 | 2036 |
| 2176 Args: | 2037 Args: |
| 2177 prefixlen: A string, the netmask in prefix length format. | 2038 prefixlen: A string, the netmask in prefix length format. |
| 2178 | 2039 |
| 2179 Returns: | 2040 Returns: |
| 2180 A boolean, True if the prefix represents a valid IPv6 | 2041 A boolean, True if the prefix represents a valid IPv6 |
| 2181 netmask. | 2042 netmask. |
| 2182 | 2043 |
| 2183 """ | 2044 """ |
| 2184 try: | 2045 try: |
| 2185 prefixlen = int(prefixlen) | 2046 prefixlen = int(prefixlen) |
| 2186 except ValueError: | 2047 except ValueError: |
| 2187 return False | 2048 return False |
| 2188 return 0 <= prefixlen <= self._max_prefixlen | 2049 return 0 <= prefixlen <= self._max_prefixlen |
| 2189 | |
| 2190 @property | |
| 2191 def with_netmask(self): | |
| 2192 return self.with_prefixlen | |
| 2193 | |
| 2194 @property | |
| 2195 def with_prefixlen(self): | |
| 2196 return '%s/%d' % (str(self.network_address), self._prefixlen) | |
| 2197 | |
| 2198 @property | |
| 2199 def with_netmask(self): | |
| 2200 return '%s/%s' % (str(self.network_address), str(self.netmask)) | |
| 2201 | |
| 2202 @property | |
| 2203 def with_hostmask(self): | |
| 2204 return '%s/%s' % (str(self.network_address), str(self.hostmask)) | |
| LEFT | RIGHT |