| LEFT | RIGHT |
|---|---|
| 1 #!/usr/bin/python | 1 #!/usr/bin/python |
| 2 # | 2 # |
| 3 # Copyright 2007 Google Inc. | 3 # Copyright 2007 Google Inc. |
| 4 # Licensed to PSF under a Contributor Agreement. | 4 # Licensed to PSF under a Contributor Agreement. |
| 5 # | 5 # |
| 6 # Licensed under the Apache License, Version 2.0 (the "License"); | 6 # Licensed under the Apache License, Version 2.0 (the "License"); |
| 7 # you may not use this file except in compliance with 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 | 8 # You may obtain a copy of the License at |
| 9 # | 9 # |
| 10 # http://www.apache.org/licenses/LICENSE-2.0 | 10 # http://www.apache.org/licenses/LICENSE-2.0 |
| 11 # | 11 # |
| 12 # Unless required by applicable law or agreed to in writing, software | 12 # Unless required by applicable law or agreed to in writing, software |
| 13 # distributed under the License is distributed on an "AS IS" BASIS, | 13 # distributed under the License is distributed on an "AS IS" BASIS, |
| 14 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or | 14 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or |
| 15 # implied. See the License for the specific language governing | 15 # implied. See the License for the specific language governing |
| 16 # permissions and limitations under the License. | 16 # permissions and limitations under the License. |
| 17 | 17 |
| 18 """An IPv4/IPv6 manipulation library in Python. | 18 """An IPv4/IPv6 manipulation library in Python. |
| 19 | 19 |
| 20 This library is used to create/poke/manipulate IPv4 and IPv6 addresses | 20 This library is used to create/poke/manipulate IPv4 and IPv6 addresses |
| 21 and prefixes. | 21 and networks. |
| 22 | 22 |
| 23 """ | 23 """ |
| 24 | 24 |
| 25 __version__ = '1.0.2' | 25 __version__ = 'trunk' |
| 26 | 26 |
| 27 import struct | 27 import struct |
| 28 | 28 |
| 29 class Error(Exception): | 29 class Error(Exception): |
| 30 | 30 |
| 31 """Base class for exceptions.""" | 31 """Base class for exceptions.""" |
| 32 | 32 |
| 33 | 33 |
| 34 class IPTypeError(Error): | 34 class IPTypeError(Error): |
| 35 | 35 |
| 36 """Tried to perform a v4 action on v6 object or vice versa.""" | 36 """Tried to perform a v4 action on v6 object or vice versa.""" |
| 37 | 37 |
| 38 | 38 |
| 39 class IPAddressExclusionError(Error): | 39 class IPAddressExclusionError(Error): |
| 40 | 40 |
| 41 """An Error we should never see occurred in address exclusion.""" | 41 """An Error we should never see occurred in address exclusion.""" |
| 42 | 42 |
| 43 | 43 |
| 44 class IPv4IpValidationError(Error): | 44 class IPAddressIPValidationError(Error): |
| 45 | 45 |
| 46 """Raised when an IPv4 address is invalid.""" | 46 """Raised when a single address (v4 or v6) was given a network.""" |
| 47 | 47 |
| 48 def __init__(self, ip): | 48 def __init__(self, ip): |
| 49 Error.__init__(self) | 49 Error.__init__(self) |
| 50 self.ip = ip | 50 self._ip = ip |
| 51 | 51 |
| 52 def __str__(self): | 52 def __str__(self): |
| 53 return repr(self.ip) + ' is not a valid IPv4 address' | 53 return "%s is not a valid address (hint, it's probably a network)" % ( |
| 54 | 54 repr(self._ip)) |
| 55 | |
| 56 class IPv4IpValidationError(Error): | |
| 57 | |
| 58 """Raised when an IPv4 address is invalid.""" | |
| 59 | |
| 60 def __init__(self, ip): | |
| 61 Error.__init__(self) | |
| 62 self._ip = ip | |
| 63 | |
| 64 def __str__(self): | |
| 65 return repr(self._ip) + ' is not a valid IPv4 address' | |
| 55 | 66 |
| 56 class IPv4NetmaskValidationError(Error): | 67 class IPv4NetmaskValidationError(Error): |
| 57 | 68 |
| 58 """Raised when a netmask is invalid.""" | 69 """Raised when a netmask is invalid.""" |
| 59 | 70 |
| 60 def __init__(self, netmask): | 71 def __init__(self, netmask): |
| 61 Error.__init__(self) | 72 Error.__init__(self) |
| 62 self.netmask = netmask | 73 self.netmask = netmask |
| 63 | 74 |
| 64 def __str__(self): | 75 def __str__(self): |
| 65 return repr(self.netmask) + ' is not a valid IPv4 netmask' | 76 return repr(self.netmask) + ' is not a valid IPv4 netmask' |
| 66 | 77 |
| 67 | 78 |
| 68 class IPv6IpValidationError(Error): | 79 class IPv6IpValidationError(Error): |
| 69 | 80 |
| 70 """Raised when an IPv6 address is invalid.""" | 81 """Raised when an IPv6 address is invalid.""" |
| 71 | 82 |
| 72 def __init__(self, ip): | 83 def __init__(self, ip): |
| 73 Error.__init__(self) | 84 Error.__init__(self) |
| 74 self.ip = ip | 85 self._ip = ip |
| 75 | 86 |
| 76 def __str__(self): | 87 def __str__(self): |
| 77 return repr(self.ip) + ' is not a valid IPv6 address' | 88 return repr(self._ip) + ' is not a valid IPv6 network' |
| 78 | 89 |
| 79 | 90 |
| 80 class IPv6NetmaskValidationError(Error): | 91 class IPv6NetmaskValidationError(Error): |
| 81 | 92 |
| 82 """Raised when an IPv6 netmask is invalid.""" | 93 """Raised when an IPv6 netmask is invalid.""" |
| 83 | 94 |
| 84 def __init__(self, netmask): | 95 def __init__(self, netmask): |
| 85 Error.__init__(self) | 96 Error.__init__(self) |
| 86 self.netmask = netmask | 97 self.netmask = netmask |
| 87 | 98 |
| 88 def __str__(self): | 99 def __str__(self): |
| 89 return repr(self.netmask) + ' is not a valid IPv6 netmask' | 100 return repr(self.netmask) + ' is not a valid IPv6 netmask' |
| 90 | 101 |
| 91 | 102 |
| 92 class PrefixlenDiffInvalidError(Error): | 103 class PrefixlenDiffInvalidError(Error): |
| 93 | 104 |
| 94 """Raised when Sub/Supernets is called with a bad prefixlen_diff.""" | 105 """Raised when Sub/Supernets is called with a bad prefixlen_diff.""" |
| 95 | 106 |
| 96 def __init__(self, error_str): | 107 def __init__(self, error_str): |
| 97 Error.__init__(self) | 108 Error.__init__(self) |
| 98 self.error_str = error_str | 109 self.error_str = error_str |
| 99 | 110 |
| 100 | 111 |
| 101 def IP(ipaddr): | 112 def IP(address, host=False, version=None): |
| 102 """Take an IP string/int and return an object of the correct type. | 113 """Take an IP string/int and return an object of the correct type. |
| 103 | 114 |
| 104 Args: | 115 Args: |
| 105 ipaddr: A string or integer, the IP address. Either IPv4 or | 116 address: A string or integer, the IP address. Either IPv4 or |
| 106 IPv6 addresses may be supplied; integers less than 2**32 will | 117 IPv6 addresses may be supplied; integers less than 2**32 will |
| 107 be considered to be IPv4. | 118 be considered to be IPv4. |
| 119 host: A bool indicating that a host rather than the default network | |
| 120 object should be created. | |
| 121 version: An Integer, if set, don't try to automatically | |
| 122 determine what the IP address type is. important for things | |
| 123 like IP(1), which could be IPv4 or IPv6. | |
| 108 | 124 |
| 109 Returns: | 125 Returns: |
| 110 An IPv4 or IPv6 object. | 126 An IPv4 or IPv6 object. |
| 111 | 127 |
| 112 Raises: | 128 Raises: |
| 113 ValueError: if the string passed isn't either a v4 or a v6 | 129 ValueError: if the string passed isn't either a v4 or a v6 |
| 114 address. | 130 address. |
| 115 | 131 |
| 116 """ | 132 """ |
| 133 if version: | |
| 134 if version == 4: | |
| 135 return IPv4(address, host=host) | |
| 136 elif version == 6: | |
| 137 return IPv6(address, host=host) | |
| 117 | 138 |
| 118 try: | 139 try: |
| 119 return IPv4(ipaddr) | 140 return IPv4(address, host=host) |
| 120 except (IPv4IpValidationError, IPv4NetmaskValidationError): | 141 except (IPv4IpValidationError, IPv4NetmaskValidationError): |
| 121 pass | 142 pass |
| 122 | 143 |
| 123 try: | 144 try: |
| 124 return IPv6(ipaddr) | 145 return IPv6(address, host=host) |
| 125 except (IPv6IpValidationError, IPv6NetmaskValidationError): | 146 except (IPv6IpValidationError, IPv6NetmaskValidationError): |
| 126 pass | 147 pass |
| 127 | 148 |
| 128 raise ValueError('%r does not appear to be an IPv4 or IPv6 address' % | 149 raise ValueError('%r does not appear to be an IPv4 or IPv6 address' % |
| 129 ipaddr) | 150 address) |
| 151 | |
| 152 | |
| 153 def IPv4(address, host=False): | |
| 154 """Generic IPv4 Factory function.. | |
| 155 | |
| 156 Return an IPv4 address or network. | |
| 157 """ | |
| 158 if host: | |
| 159 return IPv4Address(address) | |
| 160 return IPv4Network(address) | |
| 161 | |
| 162 | |
| 163 def IPv6(address, host=False): | |
| 164 """Generic IPv6 Factory function.. | |
| 165 | |
| 166 Return an IPv6 address or network. | |
| 167 """ | |
| 168 if host: | |
| 169 return IPv6Address(address) | |
| 170 return IPv6Network(address) | |
| 130 | 171 |
| 131 | 172 |
| 132 def _find_address_range(addresses): | 173 def _find_address_range(addresses): |
| 133 """Find a sequence of addresses.""" | 174 """Find a sequence of addresses. |
| 175 | |
| 176 Args: | |
| 177 addresses: a list of IPv4 or IPv6 addresses. | |
| 178 | |
| 179 Returns: | |
| 180 A tuple containing the first and last IP addresses in the sequence. | |
| 181 | |
| 182 """ | |
| 134 first = last = addresses[0] | 183 first = last = addresses[0] |
| 135 for ip in addresses[1:]: | 184 for ip in addresses[1:]: |
| 136 if ip.ip == last.ip + 1: | 185 if ip._ip == last._ip + 1: |
| 137 last = ip | 186 last = ip |
| 138 else: | 187 else: |
| 139 break | 188 break |
| 140 return (first, last) | 189 return (first, last) |
| 141 | 190 |
| 142 def _get_prefix_length(number1, number2, bits): | 191 def _get_prefix_length(number1, number2, bits): |
| 143 """Get the number of leading bits that are same for two numbers.""" | 192 """Get the number of leading bits that are same for two numbers. |
| 193 | |
| 194 Args: | |
| 195 number1: an integer. | |
| 196 number2: another integer. | |
| 197 bits: the maximum number of bits to compare. | |
| 198 | |
| 199 Returns: | |
| 200 The number of leading bits that are the same for two numbers. | |
| 201 | |
| 202 """ | |
| 144 for i in range(bits): | 203 for i in range(bits): |
| 145 if number1 >> i == number2 >> i: | 204 if number1 >> i == number2 >> i: |
| 146 return bits - i | 205 return bits - i |
| 147 return 0 | 206 return 0 |
| 148 | 207 |
| 149 def _count_righthand_zero_bits(integer, bits): | 208 def _count_righthand_zero_bits(number, bits): |
| 150 """Count the number of zero bits on the right hand side.""" | 209 """Count the number of zero bits on the right hand side. |
| 151 if integer == 0: | 210 |
| 211 Args: | |
| 212 number: an integer. | |
| 213 bits: maximum number of bits to count. | |
| 214 | |
| 215 Returns: | |
| 216 The number of zero bits on the right hand side of the number. | |
| 217 | |
| 218 """ | |
| 219 if number == 0: | |
| 152 return bits | 220 return bits |
| 153 for i in range(bits): | 221 for i in range(bits): |
| 154 if (integer >> i) % 2: | 222 if (number >> i) % 2: |
| 155 return i | 223 return i |
| 156 | 224 |
| 157 def summarize_address_range(first, last): | 225 def summarize_address_range(first, last): |
| 158 """Summarize a network range given the first and last IP addresses.""" | 226 """Summarize a network range given the first and last IP addresses. |
| 159 | 227 |
| 228 Example: | |
| 229 >>> summarize_address_range(IPv4Address('1.1.1.0'), | |
| 230 IPv4Address('1.1.1.130')) | |
| 231 [IPv4Network('1.1.1.0/25'), IPv4Network('1.1.1.128/31'), | |
| 232 IPv4Network('1.1.1.130/32')] | |
| 233 | |
| 234 Args: | |
| 235 first: the first IPv4 or IPv6 address in the range. | |
| 236 last: the last IPv4 or IPv6 address in the range. | |
| 237 | |
| 238 Returns: | |
| 239 The address range collapsed to a list of IPv4 or IPv6 networks. | |
| 240 | |
| 241 Raise: | |
| 242 IPTypeError: | |
| 243 If the first and last objects are not IP addresses. | |
| 244 If the first and last objects are not the same version. | |
| 245 ValueError: | |
| 246 If the last object is not greater than the first. | |
| 247 If the version is not 4 or 6. | |
| 248 | |
| 249 """ | |
| 250 | |
| 251 if not (isinstance(first, BaseIP) and isinstance(last, BaseIP)): | |
| 252 raise IPTypeError("first and last must be IP addresses, not networks") | |
| 160 if first.version != last.version: | 253 if first.version != last.version: |
| 161 raise ValueError("IP addresses must be same version") | 254 raise IPTypeError("IP addresses must be same version") |
| 162 if first > last: | 255 if first > last: |
| 163 raise ValueError("last IP address must be greater than first") | 256 raise ValueError("last IP address must be greater than first") |
| 164 | 257 |
| 165 networks = [] | 258 networks = [] |
| 166 | 259 |
| 167 if first.version == 4: | 260 if first.version == 4: |
| 168 ip = IPv4 | 261 ip = IPv4Network |
| 169 elif first.version == 6: | 262 elif first.version == 6: |
| 170 ip = IPv6 | 263 ip = IPv6Network |
| 171 else: | 264 else: |
| 172 raise ValueError("unknown IP version") | 265 raise ValueError("unknown IP version") |
| 173 | 266 |
| 174 ip_bits = first.max_prefixlen | 267 ip_bits = first._max_prefixlen |
| 268 first = first._ip | |
| 269 last = last._ip | |
| 175 while first <= last: | 270 while first <= last: |
| 176 nbits = _count_righthand_zero_bits(first.ip, ip_bits) | 271 nbits = _count_righthand_zero_bits(first, ip_bits) |
| 177 current = None | 272 current = None |
| 178 while True: | 273 while nbits >= 0: |
| 179 addend = 2**nbits - 1 | 274 addend = 2**nbits - 1 |
| 180 current = first.ip + addend | 275 current = first + addend |
| 181 nbits -= 1 | 276 nbits -= 1 |
| 182 if ip(current) <= last: | 277 if current <= last: |
| 183 break | 278 break |
| 184 prefix = _get_prefix_length(first.ip, current, ip_bits) | 279 prefix = _get_prefix_length(first, current, ip_bits) |
| 185 networks.append(ip('%s/%s' % (first.ip_ext, prefix))) | 280 net = ip(first) |
| 281 net.prefixlen = prefix | |
| 282 networks.append(net) | |
| 186 if current == ip._ALL_ONES: | 283 if current == ip._ALL_ONES: |
| 187 break | 284 break |
| 188 first = ip(current + 1) | 285 first = current + 1 |
| 189 return networks | 286 return networks |
| 190 | 287 |
| 191 def _collapse_address_list_recursive(addresses): | 288 def _collapse_address_list_recursive(addresses): |
| 192 """Loops through the addresses, collapsing concurrent netblocks. | 289 """Loops through the addresses, collapsing concurrent netblocks. |
| 193 | 290 |
| 194 Example: | 291 Example: |
| 195 | 292 |
| 196 ip1 = IPv4('1.1.0.0/24') | 293 ip1 = IPv4('1.1.0.0/24') |
| 197 ip2 = IPv4('1.1.1.0/24') | 294 ip2 = IPv4('1.1.1.0/24') |
| 198 ip3 = IPv4('1.1.2.0/24') | 295 ip3 = IPv4('1.1.2.0/24') |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 241 collapse_address_list([IPv4('1.1.0.0/24'), IPv4('1.1.1.0/24')]) -> | 338 collapse_address_list([IPv4('1.1.0.0/24'), IPv4('1.1.1.0/24')]) -> |
| 242 [IPv4('1.1.0.0/23')] | 339 [IPv4('1.1.0.0/23')] |
| 243 | 340 |
| 244 Args: | 341 Args: |
| 245 addresses: A list of IPv4 or IPv6 objects. | 342 addresses: A list of IPv4 or IPv6 objects. |
| 246 | 343 |
| 247 Returns: | 344 Returns: |
| 248 A list of IPv4 or IPv6 objects depending on what we were passed. | 345 A list of IPv4 or IPv6 objects depending on what we were passed. |
| 249 | 346 |
| 250 """ | 347 """ |
| 251 _addresses = [] | |
| 252 i = 0 | 348 i = 0 |
| 253 ip_bits = addresses[0].max_prefixlen | 349 addrs = [] |
|
Peter Moody
2009/06/02 21:05:19
for internal access, I usually end up using the pr
| |
| 254 # filter out IP addresses, dedup, and sort | 350 ips = [] |
| 255 addrs = sorted(set([ip for ip in addresses if ip.prefixlen == ip_bits]), | 351 nets = [] |
| 256 key=BaseIP._get_networks_key) | 352 # split IP addresses and networks |
| 257 nets = [ip for ip in addresses if ip.prefixlen < ip_bits] | 353 for ip in addresses: |
| 258 | 354 if isinstance(ip, BaseIP): |
| 259 while i < len(addrs): | 355 ips.append(ip) |
| 260 (first, last) = _find_address_range(addrs[i:]) | 356 elif ip._prefixlen == ip._max_prefixlen: |
| 261 i = addrs.index(last) + 1 | 357 ips.append(ip.ip) |
| 262 _addresses.extend( | 358 else: |
| 263 [IP(ip) for ip in summarize_address_range(first, last)]) | 359 nets.append(ip) |
| 360 # sort and dedup | |
| 361 ips = sorted(set(ips)) | |
| 362 nets = sorted(set(nets)) | |
| 363 | |
| 364 while i < len(ips): | |
| 365 (first, last) = _find_address_range(ips[i:]) | |
| 366 i = ips.index(last) + 1 | |
| 367 addrs.extend(summarize_address_range(first, last)) | |
| 264 | 368 |
| 265 return _collapse_address_list_recursive( | 369 return _collapse_address_list_recursive( |
| 266 sorted(_addresses + nets, key=BaseIP._get_networks_key)) | 370 sorted(addrs + nets, key=BaseNet._get_networks_key)) |
| 267 | 371 |
| 268 # backwards compatibility | 372 # backwards compatibility |
| 269 CollapseAddrList = collapse_address_list | 373 CollapseAddrList = collapse_address_list |
| 270 | 374 |
| 271 # Test whether this Python implementation supports byte objects that | 375 # Test whether this Python implementation supports byte objects that |
| 272 # are not identical to str ones. | 376 # are not identical to str ones. |
| 273 # We need to exclude platforms where bytes == str so that we can | 377 # We need to exclude platforms where bytes == str so that we can |
| 274 # distinguish between packed representations and strings, for example | 378 # distinguish between packed representations and strings, for example |
| 275 # b'12::' (the IPv4 address 49.50.58.58) and '12::' (an IPv6 address). | 379 # b'12::' (the IPv4 address 49.50.58.58) and '12::' (an IPv6 address). |
| 276 try: | 380 try: |
| 277 _compat_has_real_bytes = bytes != str | 381 _compat_has_real_bytes = bytes != str |
| 278 except NameError: # <Python2.6 | 382 except NameError: # <Python2.6 |
| 279 _compat_has_real_bytes = False | 383 _compat_has_real_bytes = False |
| 280 | 384 |
| 281 class BaseIP(object): | 385 |
| 386 class IPAddrBase(object): | |
| 387 | |
| 388 """The mother class.""" | |
| 389 | |
| 390 def __index__(self): | |
| 391 return self._ip | |
| 392 | |
| 393 def __int__(self): | |
| 394 return self._ip | |
| 395 | |
| 396 def __hex__(self): | |
| 397 return hex(self._ip) | |
| 398 | |
| 399 | |
| 400 class BaseIP(IPAddrBase): | |
| 282 | 401 |
| 283 """A generic IP object. | 402 """A generic IP object. |
| 284 | 403 |
| 285 This IP class contains most of the methods which are used by | 404 This IP class contains the version independent methods which are |
| 286 the IPv4 and IPv6 classes. | 405 used by single IP addresses. |
| 287 | 406 |
| 288 """ | 407 """ |
| 289 | 408 |
| 290 def __getitem__(self, n): | 409 @property |
| 291 if n >= 0: | 410 def exploded(self): |
| 292 if self.network + n > self.broadcast: | 411 return self._explode_shorthand_ip_string() |
| 293 raise IndexError | 412 |
| 294 return self._string_from_ip_int(self.network + n) | 413 @property |
| 295 else: | 414 def compressed(self): |
| 296 n += 1 | 415 return str(self) |
| 297 if self.broadcast + n < self.network: | 416 |
| 298 raise IndexError | 417 def __init__(self, address): |
| 299 return self._string_from_ip_int(self.broadcast + n) | 418 if '/' in str(address): |
| 300 | 419 raise IPAddressIPValidationError(address) |
| 301 def __lt__(self, other): | |
| 302 try: | |
| 303 return (self.version < other.version | |
| 304 or self.ip < other.ip | |
| 305 or self.netmask < other.netmask) | |
| 306 except AttributeError: | |
| 307 return NotImplemented | |
| 308 | |
| 309 def __gt__(self, other): | |
| 310 try: | |
| 311 return (self.version > other.version | |
| 312 or self.ip > other.ip | |
| 313 or self.netmask > other.netmask) | |
| 314 except AttributeError: | |
| 315 return NotImplemented | |
| 316 | 420 |
| 317 def __eq__(self, other): | 421 def __eq__(self, other): |
| 318 try: | 422 try: |
| 319 return (self.version == other.version | 423 return not (self._ip != other._ip |
| 320 and self.ip == other.ip | 424 or self._version != other._version) |
| 321 and self.netmask == other.netmask) | |
| 322 except AttributeError: | 425 except AttributeError: |
| 323 return NotImplemented | 426 return NotImplemented |
| 324 | 427 |
| 325 def __ne__(self, other): | 428 def __ne__(self, other): |
| 326 eq = self.__eq__(other) | 429 eq = self.__eq__(other) |
| 327 if eq is NotImplemented: | 430 if eq is NotImplemented: |
| 328 return NotImplemented | 431 return NotImplemented |
| 329 return not eq | 432 return not eq |
| 330 | 433 |
| 331 def __le__(self, other): | 434 def __le__(self, other): |
| 332 gt = self.__gt__(other) | 435 gt = self.__gt__(other) |
| 333 if gt is NotImplemented: | 436 if gt is NotImplemented: |
| 334 return NotImplemented | 437 return NotImplemented |
| 335 return not gt | 438 return not gt |
| 336 | 439 |
| 337 def __ge__(self, other): | 440 def __ge__(self, other): |
| 338 lt = self.__lt__(other) | 441 lt = self.__lt__(other) |
| 339 if lt is NotImplemented: | 442 if lt is NotImplemented: |
| 340 return NotImplemented | 443 return NotImplemented |
| 341 return not lt | 444 return not lt |
| 342 | 445 |
| 446 def __lt__(self, other): | |
| 447 if self._version != other._version: | |
| 448 return self._version < other._version | |
| 449 if self._ip != other._ip: | |
| 450 return self._ip < other._ip | |
| 451 return False | |
| 452 | |
| 453 def __gt__(self, other): | |
| 454 if self._version != other._version: | |
| 455 return self._version > other._version | |
| 456 if self._ip != other._ip: | |
| 457 return self._ip > other._ip | |
| 458 return False | |
| 459 | |
| 343 def __repr__(self): | 460 def __repr__(self): |
| 344 return '%s(%r)' % (self.__class__.__name__, str(self)) | 461 return '%s(%r)' % (self.__class__.__name__, str(self)) |
| 345 | 462 |
| 346 def __index__(self): | 463 def __str__(self): |
| 347 return self.ip | 464 return '%s' % self._string_from_ip_int(self._ip) |
| 348 | 465 |
| 349 def __int__(self): | 466 def __hash__(self): |
| 350 return self.ip | 467 return hash(self._ip) |
| 351 | 468 |
| 352 def __hex__(self): | 469 @property |
| 353 return hex(int(self)) | 470 def version(self): |
| 471 raise NotImplementedError('BaseIP has no version') | |
| 472 | |
| 473 | |
| 474 class BaseNet(IPAddrBase): | |
| 475 | |
| 476 """A generic IP object. | |
| 477 | |
| 478 This IP class contains the version independent methods which are | |
| 479 used by networks. | |
| 480 | |
| 481 """ | |
| 482 | |
| 483 def __init__(self, address): | |
| 484 self._cache = {} | |
| 485 | |
| 486 def __repr__(self): | |
| 487 return '%s(%r)' % (self.__class__.__name__, str(self)) | |
| 488 | |
| 489 def iterhosts(self): | |
| 490 """Generate Iterator over hosts in a network.""" | |
| 491 cur = int(self.network) | |
| 492 bcast = int(self.broadcast) | |
| 493 while cur <= bcast: | |
| 494 cur += 1 | |
| 495 yield IP(cur - 1, host=True, version=self._version) | |
| 496 | |
| 497 def __iter__(self): | |
| 498 self._cur = int(self.network) | |
| 499 return self | |
| 500 | |
| 501 def next(self): | |
| 502 if self._cur > int(self.broadcast): | |
| 503 raise StopIteration | |
| 504 self._cur += 1 | |
| 505 return IP(self._cur - 1, host=True, version=self._version) | |
| 506 | |
| 507 def __getitem__(self, n): | |
| 508 network = int(self.network) | |
| 509 broadcast = int(self.broadcast) | |
| 510 if n >= 0: | |
| 511 if network + n > broadcast: | |
| 512 raise IndexError | |
| 513 return IP(network + n, host=True, version=self._version) | |
| 514 else: | |
| 515 n += 1 | |
| 516 if broadcast + n < network: | |
| 517 raise IndexError | |
| 518 return IP(broadcast + n, host=True, | |
| 519 version=self._version) | |
| 520 | |
| 521 def __lt__(self, other): | |
| 522 try: | |
| 523 if self._version != other._version: | |
| 524 return self._version < other._version | |
| 525 if self._ip != other._ip: | |
| 526 return self._ip < other._ip | |
| 527 if self.netmask != other.netmask: | |
| 528 return self.netmask < other.netmask | |
| 529 return False | |
| 530 except AttributeError: | |
| 531 return NotImplemented | |
| 532 | |
| 533 def __gt__(self, other): | |
| 534 try: | |
| 535 if self._version != other._version: | |
| 536 return self._version > other._version | |
| 537 if self._ip != other._ip: | |
| 538 return self._ip > other._ip | |
| 539 if self.netmask != other.netmask: | |
| 540 return self.netmask > other.netmask | |
| 541 return False | |
| 542 except AttributeError: | |
| 543 return NotImplemented | |
| 544 | |
| 545 def __eq__(self, other): | |
| 546 try: | |
| 547 return (self._version == other._version | |
| 548 and self._ip == other._ip | |
| 549 and int(self.netmask) == int(other.netmask)) | |
| 550 except AttributeError: | |
| 551 return NotImplemented | |
| 552 | |
| 553 def __ne__(self, other): | |
| 554 eq = self.__eq__(other) | |
| 555 if eq is NotImplemented: | |
| 556 return NotImplemented | |
| 557 return not eq | |
| 558 | |
| 559 def __str__(self): | |
| 560 return '%s/%s' % (str(self.ip), | |
| 561 str(self._prefixlen)) | |
| 562 | |
| 563 def __hash__(self): | |
| 564 return hash(self._ip ^ int(self.netmask)) | |
| 565 | |
| 566 def __contains__(self, other): | |
| 567 # Easy case, dealing with networks. | |
| 568 if isinstance(other, BaseNet): | |
| 569 return (int(self.network) <= int(other._ip) and | |
| 570 int(self.broadcast) >= int(other.broadcast)) | |
| 571 elif isinstance(other, BaseIP): | |
| 572 # Check if we've got an Address | |
| 573 return (int(self.network) <= int(other._ip) <= | |
| 574 int(self.broadcast)) | |
| 575 else: | |
| 576 return IP(other) in self | |
| 577 | |
| 578 @property | |
| 579 def network(self): | |
| 580 x = self._cache.get('network') | |
| 581 if x is None: | |
| 582 x = IP(self._ip & int(self.netmask), host=True, | |
| 583 version=self._version) | |
| 584 self._cache['network'] = x | |
| 585 return x | |
| 586 | |
| 587 @property | |
| 588 def broadcast(self): | |
| 589 x = self._cache.get('broadcast') | |
| 590 if x is None: | |
| 591 x = IP(self._ip | int(self.hostmask), host=True, | |
| 592 version=self._version) | |
| 593 self._cache['broadcast'] = x | |
| 594 return x | |
| 595 | |
| 596 @property | |
| 597 def hostmask(self): | |
| 598 x = self._cache.get('hostmask') | |
| 599 if x is None: | |
| 600 x = IP(int(self.netmask) ^ self._ALL_ONES, host=True, | |
| 601 version=self._version) | |
| 602 self._cache['hostmask'] = x | |
| 603 return x | |
| 604 | |
| 605 @property | |
| 606 def with_prefixlen(self): | |
| 607 return '%s/%d' % (str(self.ip), self._prefixlen) | |
| 608 | |
| 609 @property | |
| 610 def with_netmask(self): | |
| 611 return '%s/%s' % (str(self.ip), str(self.netmask)) | |
| 612 | |
| 613 @property | |
| 614 def with_hostmask(self): | |
| 615 return '%s/%s' % (str(self.ip), str(self.hostmask)) | |
| 616 | |
| 617 @property | |
| 618 def numhosts(self): | |
| 619 """Number of hosts in the current subnet.""" | |
| 620 return int(self.broadcast) - int(self.network) + 1 | |
| 621 | |
| 622 @property | |
| 623 def version(self): | |
| 624 raise NotImplementedError('BaseNet has no version') | |
| 625 | |
| 626 prefixlen = property( | |
| 627 fget=lambda self: self._prefixlen, | |
| 628 fset=lambda self, prefixlen: self._set_prefix(prefixlen)) | |
| 354 | 629 |
| 355 def address_exclude(self, other): | 630 def address_exclude(self, other): |
| 356 """Remove an address from a larger block. | 631 """Remove an address from a larger block. |
| 357 | 632 |
| 358 For example: | 633 For example: |
| 359 | 634 |
| 360 addr1 = IP('10.1.1.0/24') | 635 addr1 = IP('10.1.1.0/24') |
| 361 addr2 = IP('10.1.1.0/26') | 636 addr2 = IP('10.1.1.0/26') |
| 362 addr1.address_exclude(addr2) = | 637 addr1.address_exclude(addr2) = |
| 363 [IP('10.1.1.64/26'), IP('10.1.1.128/25')] | 638 [IP('10.1.1.64/26'), IP('10.1.1.128/25')] |
| (...skipping 18 matching lines...) Expand all Loading... | |
| 382 | 657 |
| 383 Raises: | 658 Raises: |
| 384 IPTypeError: If self and other are of difffering address | 659 IPTypeError: If self and other are of difffering address |
| 385 versions. | 660 versions. |
| 386 IPAddressExclusionError: There was some unknown error in the | 661 IPAddressExclusionError: There was some unknown error in the |
| 387 address exclusion process. This likely points to a bug | 662 address exclusion process. This likely points to a bug |
| 388 elsewhere in this code. | 663 elsewhere in this code. |
| 389 ValueError: If other is not completely contained by self. | 664 ValueError: If other is not completely contained by self. |
| 390 | 665 |
| 391 """ | 666 """ |
| 392 if not self.version == other.version: | 667 if not self._version == other._version: |
| 393 raise IPTypeError("%s and %s aren't of the same version" % ( | 668 raise IPTypeError("%s and %s aren't of the same version" % ( |
| 394 str(self), str(other))) | 669 str(self), str(other))) |
| 395 | 670 |
| 396 if other not in self: | 671 if other not in self: |
| 397 raise ValueError('%s not contained in %s' % (str(other), | 672 raise ValueError('%s not contained in %s' % (str(other), |
| 398 str(self))) | 673 str(self))) |
| 399 | |
| 400 ret_addrs = [] | 674 ret_addrs = [] |
| 401 | 675 |
| 402 # Make sure we're comparing the network of other. | 676 # Make sure we're comparing the network of other. |
| 403 other = IP(other.network_ext + '/' + str(other.prefixlen)) | 677 other = IP('%s/%s' % (str(other.network), str(other.prefixlen)), |
| 678 version=other._version) | |
| 404 | 679 |
| 405 s1, s2 = self.subnet() | 680 s1, s2 = self.subnet() |
| 406 while s1 != other and s2 != other: | 681 while s1 != other and s2 != other: |
| 407 if other in s1: | 682 if other in s1: |
| 408 ret_addrs.append(s2) | 683 ret_addrs.append(s2) |
| 409 s1, s2 = s1.subnet() | 684 s1, s2 = s1.subnet() |
| 410 elif other in s2: | 685 elif other in s2: |
| 411 ret_addrs.append(s1) | 686 ret_addrs.append(s1) |
| 412 s1, s2 = s2.subnet() | 687 s1, s2 = s2.subnet() |
| 413 else: | 688 else: |
| 414 # If we got here, there's a bug somewhere. | 689 # If we got here, there's a bug somewhere. |
| 415 raise IPAddressExclusionError('Error performing exclusion: ' | 690 raise IPAddressExclusionError('Error performing exclusion: ' |
| 416 's1: %s s2: %s other: %s' % | 691 's1: %s s2: %s other: %s' % |
| 417 (str(s1), str(s2), str(other))) | 692 (str(s1), str(s2), str(other))) |
| 418 if s1 == other: | 693 if s1 == other: |
| 419 ret_addrs.append(s2) | 694 ret_addrs.append(s2) |
| 420 elif s2 == other: | 695 elif s2 == other: |
| 421 ret_addrs.append(s1) | 696 ret_addrs.append(s1) |
| 422 else: | 697 else: |
| 423 # If we got here, there's a bug somewhere. | 698 # If we got here, there's a bug somewhere. |
| 424 raise IPAddressExclusionError('Error performing exclusion: ' | 699 raise IPAddressExclusionError('Error performing exclusion: ' |
| 425 's1: %s s2: %s other: %s' % | 700 's1: %s s2: %s other: %s' % |
| 426 (str(s1), str(s2), str(other))) | 701 (str(s1), str(s2), str(other))) |
| 427 | 702 |
| 428 return sorted(ret_addrs, key=BaseIP._get_networks_key) | 703 return sorted(ret_addrs, key=BaseNet._get_networks_key) |
| 429 | 704 |
| 430 def compare_networks(self, other): | 705 def compare_networks(self, other): |
| 431 """Compare two IP objects. | 706 """Compare two IP objects. |
| 432 | 707 |
| 433 This is only concerned about the comparison of the integer | 708 This is only concerned about the comparison of the integer |
| 434 representation of the network addresses. This means that the | 709 representation of the network addresses. This means that the |
| 435 host bits aren't considered at all in this method. If you want | 710 host bits aren't considered at all in this method. If you want |
| 436 to compare host bits, you can easily enough do a | 711 to compare host bits, you can easily enough do a |
| 437 'HostA.ip < HostB.ip' | 712 'HostA._ip < HostB._ip' |
| 438 | 713 |
| 439 Args: | 714 Args: |
| 440 other: An IP object. | 715 other: An IP object. |
| 441 | 716 |
| 442 Returns: | 717 Returns: |
| 443 If the IP versions of self and other are the same, returns: | 718 If the IP versions of self and other are the same, returns: |
| 444 | 719 |
| 445 -1 if self < other: | 720 -1 if self < other: |
| 446 eg: IPv4('1.1.1.0/24') < IPv4('1.1.2.0/24') | 721 eg: IPv4('1.1.1.0/24') < IPv4('1.1.2.0/24') |
| 447 IPv6('1080::200C:417A') < IPv6('1080::200B:417B') | 722 IPv6('1080::200C:417A') < IPv6('1080::200B:417B') |
| 448 0 if self == other | 723 0 if self == other |
| 449 eg: IPv4('1.1.1.1/24') == IPv4('1.1.1.2/24') | 724 eg: IPv4('1.1.1.1/24') == IPv4('1.1.1.2/24') |
| 450 IPv6('1080::200C:417A/96') == IPv6('1080::200C:417B/96') | 725 IPv6('1080::200C:417A/96') == IPv6('1080::200C:417B/96') |
| 451 1 if self > other | 726 1 if self > other |
| 452 eg: IPv4('1.1.1.0/24') > IPv4('1.1.0.0/24') | 727 eg: IPv4('1.1.1.0/24') > IPv4('1.1.0.0/24') |
| 453 IPv6('1080::1:200C:417A/112') > | 728 IPv6('1080::1:200C:417A/112') > |
| 454 IPv6('1080::0:200C:417A/112') | 729 IPv6('1080::0:200C:417A/112') |
| 455 | 730 |
| 456 If the IP versions of self and other are different, returns: | 731 If the IP versions of self and other are different, returns: |
| 457 | 732 |
| 458 -1 if self.version < other.version | 733 -1 if self._version < other._version |
| 459 eg: IPv4('10.0.0.1/24') < IPv6('::1/128') | 734 eg: IPv4('10.0.0.1/24') < IPv6('::1/128') |
| 460 1 if self.version > other.version | 735 1 if self._version > other._version |
| 461 eg: IPv6('::1/128') > IPv4('255.255.255.0/24') | 736 eg: IPv6('::1/128') > IPv4('255.255.255.0/24') |
| 462 | 737 |
| 463 """ | 738 """ |
| 464 if self.version < other.version: | 739 if self._version < other._version: |
| 465 return -1 | 740 return -1 |
| 466 if self.version > other.version: | 741 if self._version > other._version: |
| 467 return 1 | 742 return 1 |
| 468 # self.version == other.version below here: | 743 # self._version == other._version below here: |
| 469 if self.network < other.network: | 744 if self.network < other.network: |
| 470 return -1 | 745 return -1 |
| 471 if self.network > other.network: | 746 if self.network > other.network: |
| 472 return 1 | 747 return 1 |
| 473 # self.network == other.network below here: | 748 # self.network == other.network below here: |
| 474 if self.netmask < other.netmask: | 749 if self.netmask < other.netmask: |
| 475 return -1 | 750 return -1 |
| 476 if self.netmask > other.netmask: | 751 if self.netmask > other.netmask: |
| 477 return 1 | 752 return 1 |
| 478 # self.network == other.network and self.netmask == other.netmask | 753 # self.network == other.network and self.netmask == other.netmask |
| 479 return 0 | 754 return 0 |
| 480 | 755 |
| 481 def _get_networks_key(self): | 756 def _get_networks_key(self): |
| 482 """Network-only key function. | 757 """Network-only key function. |
| 483 | 758 |
| 484 Returns an object that identifies this address' network and | 759 Returns an object that identifies this address' network and |
| 485 netmask. This function is a suitable "key" argument for sorted() | 760 netmask. This function is a suitable "key" argument for sorted() |
| 486 and list.sort(). | 761 and list.sort(). |
| 487 | 762 |
| 488 """ | 763 """ |
| 489 return (self.version, self.network, self.netmask) | 764 return (self._version, self.network, self.netmask) |
| 490 | |
| 491 prefixlen = property( | |
| 492 fget=lambda self: self._prefixlen, | |
| 493 fset=lambda self, prefixlen: self._set_prefix(prefixlen)) | |
| 494 | |
| 495 def __str__(self): | |
| 496 return '%s/%s' % (self._string_from_ip_int(self.ip), | |
| 497 str(self.prefixlen)) | |
| 498 | |
| 499 def __hash__(self): | |
| 500 return hash(self.ip ^ self.netmask) | |
| 501 | |
| 502 def __contains__(self, other): | |
| 503 return self.network <= other.ip and self.broadcast >= other.broadcast | |
| 504 | |
| 505 @property | |
| 506 def ip_ext(self): | |
| 507 """Dotted decimal or colon string version of the IP address.""" | |
| 508 return self._string_from_ip_int(self.ip) | |
| 509 | |
| 510 @property | |
| 511 def ip_ext_full(self): | |
| 512 """Canonical string version of the IP address.""" | |
| 513 return self.ip_ext | |
| 514 | |
| 515 @property | |
| 516 def broadcast(self): | |
| 517 """Integer representation of the broadcast address.""" | |
| 518 return self.ip | self.hostmask | |
| 519 | |
| 520 @property | |
| 521 def broadcast_ext(self): | |
| 522 """Dotted decimal or colon string version of the broadcast.""" | |
| 523 return self._string_from_ip_int(self.broadcast) | |
| 524 | |
| 525 @property | |
| 526 def hostmask(self): | |
| 527 """Integer representation of the hostmask.""" | |
| 528 return self.netmask ^ self._ALL_ONES | |
| 529 | |
| 530 @property | |
| 531 def hostmask_ext(self): | |
| 532 """Dotted decimal or colon string version of the hostmask.""" | |
| 533 return self._string_from_ip_int(self.hostmask) | |
| 534 | |
| 535 @property | |
| 536 def network(self): | |
| 537 """Integer representation of the network.""" | |
| 538 return self.ip & self.netmask | |
| 539 | |
| 540 @property | |
| 541 def network_ext(self): | |
| 542 """Dotted decimal or colon string version of the network.""" | |
| 543 return self._string_from_ip_int(self.network) | |
| 544 | |
| 545 @property | |
| 546 def netmask_ext(self): | |
| 547 """Dotted decimal or colon string version of the netmask.""" | |
| 548 return self._string_from_ip_int(self.netmask) | |
| 549 | |
| 550 @property | |
| 551 def numhosts(self): | |
| 552 """Number of hosts in the current subnet.""" | |
| 553 return self.broadcast - self.network + 1 | |
| 554 | |
| 555 @property | |
| 556 def version(self): | |
| 557 raise NotImplementedError('BaseIP has no version') | |
| 558 | 765 |
| 559 def _ip_int_from_prefix(self, prefixlen=None): | 766 def _ip_int_from_prefix(self, prefixlen=None): |
| 560 """Turn the prefix length netmask into a int for comparison. | 767 """Turn the prefix length netmask into a int for comparison. |
| 561 | 768 |
| 562 Args: | 769 Args: |
| 563 prefixlen: An integer, the prefix length. | 770 prefixlen: An integer, the prefix length. |
| 564 | 771 |
| 565 Returns: | 772 Returns: |
| 566 An integer. | 773 An integer. |
| 567 | 774 |
| 568 """ | 775 """ |
| 569 if not prefixlen and prefixlen != 0: | 776 if not prefixlen and prefixlen != 0: |
| 570 prefixlen = self.prefixlen | 777 prefixlen = self._prefixlen |
| 571 return self._ALL_ONES ^ (self._ALL_ONES >> prefixlen) | 778 return self._ALL_ONES ^ (self._ALL_ONES >> prefixlen) |
| 572 | 779 |
| 573 def _prefix_from_ip_int(self, ip_int, mask=32): | 780 def _prefix_from_ip_int(self, ip_int, mask=32): |
| 574 """Return prefix length from the decimal netmask. | 781 """Return prefix length from the decimal netmask. |
| 575 | 782 |
| 576 Args: | 783 Args: |
| 577 ip_int: An integer, the IP address. | 784 ip_int: An integer, the IP address. |
| 578 mask: The netmask. Defaults to 32. | 785 mask: The netmask. Defaults to 32. |
| 579 | 786 |
| 580 Returns: | 787 Returns: |
| (...skipping 12 matching lines...) Expand all Loading... | |
| 593 """Turn a prefix length into a dotted decimal string. | 800 """Turn a prefix length into a dotted decimal string. |
| 594 | 801 |
| 595 Args: | 802 Args: |
| 596 prefixlen: An integer, the netmask prefix length. | 803 prefixlen: An integer, the netmask prefix length. |
| 597 | 804 |
| 598 Returns: | 805 Returns: |
| 599 A string, the dotted decimal netmask string. | 806 A string, the dotted decimal netmask string. |
| 600 | 807 |
| 601 """ | 808 """ |
| 602 if not prefixlen: | 809 if not prefixlen: |
| 603 prefixlen = self.prefixlen | 810 prefixlen = self._prefixlen |
| 604 return self._string_from_ip_int(self._ip_int_from_prefix(prefixlen)) | 811 return self._string_from_ip_int(self._ip_int_from_prefix(prefixlen)) |
| 605 | 812 |
| 606 # backwards compatibility | 813 # backwards compatibility |
| 607 AddressExclude = address_exclude | 814 AddressExclude = address_exclude |
| 608 CompareNetworks = compare_networks | 815 CompareNetworks = compare_networks |
| 609 Contains = __contains__ | 816 Contains = __contains__ |
| 610 def set_prefix(self, prefixlen): self.prefixlen = prefixlen | 817 def set_prefix(self, prefixlen): self.prefixlen = prefixlen |
| 611 SetPrefix = set_prefix | 818 SetPrefix = set_prefix |
| 612 def get_prefix(self): return self.prefixlen | 819 def get_prefix(self): return self.prefixlen |
| 613 | 820 |
| 614 | 821 |
| 615 class IPv4(BaseIP): | 822 class BaseV4(object): |
| 616 | 823 |
| 617 """This class represents and manipulates 32-bit IPv4 addresses. | 824 """Base IPv4 object. |
| 618 | 825 |
| 619 Attributes: [examples for IPv4('1.2.3.4/27')] | 826 The following methods are used by IPv4 objects in both single IP |
| 620 .ip: 16909060 | 827 addresses and networks. |
| 621 .ip_ext: '1.2.3.4' | |
| 622 .ip_ext_full: '1.2.3.4' | |
| 623 .network: 16909056L | |
| 624 .network_ext: '1.2.3.0' | |
| 625 .hostmask: 31L (0x1F) | |
| 626 .hostmask_ext: '0.0.0.31' | |
| 627 .broadcast: 16909087L (0x102031F) | |
| 628 .broadcast_ext: '1.2.3.31' | |
| 629 .netmask: 4294967040L (0xFFFFFFE0) | |
| 630 .netmask_ext: '255.255.255.224' | |
| 631 .prefixlen: 27 | |
| 632 | 828 |
| 633 """ | 829 """ |
| 634 | 830 |
| 635 # Equivalent to 255.255.255.255 or 32 bits of 1's. | 831 # Equivalent to 255.255.255.255 or 32 bits of 1's. |
| 636 _ALL_ONES = (2**32) - 1 | 832 _ALL_ONES = (2**32) - 1 |
| 637 | 833 |
| 638 def __init__(self, ipaddr): | 834 def __init__(self, address): |
| 639 """Instantiate a new IPv4 object. | 835 self._version = 4 |
| 640 | 836 self._max_prefixlen = 32 |
| 641 Args: | 837 |
| 642 ipaddr: A string or integer representing the IP [& network]. | 838 def _explode_shorthand_ip_string(self, ip_str=None): |
| 839 if not ip_str: | |
| 840 ip_str = str(self) | |
| 841 return ip_str | |
| 842 | |
| 843 def _ip_int_from_string(self, ip_str): | |
| 844 """Turn the given IP string into an integer for comparison. | |
| 845 | |
| 846 Args: | |
| 847 ip_str: A string, the IP ip_str. | |
| 848 | |
| 849 Returns: | |
| 850 The IP ip_str as an integer. | |
| 851 | |
| 852 """ | |
| 853 packed_ip = 0 | |
| 854 for oc in ip_str.split('.'): | |
| 855 packed_ip = (packed_ip << 8) | int(oc) | |
| 856 return packed_ip | |
| 857 | |
| 858 def _string_from_ip_int(self, ip_int): | |
| 859 """Turns a 32-bit integer into dotted decimal notation. | |
| 860 | |
| 861 Args: | |
| 862 ip_int: An integer, the IP address. | |
| 863 | |
| 864 Returns: | |
| 865 The IP address as a string in dotted decimal notation. | |
| 866 | |
| 867 """ | |
| 868 octets = [] | |
| 869 for _ in xrange(4): | |
| 870 octets.insert(0, str(ip_int & 0xFF)) | |
| 871 ip_int >>= 8 | |
| 872 return '.'.join(octets) | |
| 873 | |
| 874 def _is_valid_ip(self, ip_str): | |
| 875 """Validate the dotted decimal notation IP/netmask string. | |
| 876 | |
| 877 Args: | |
| 878 ip_str: A string, the IP ip_str. | |
| 879 | |
| 880 Returns: | |
| 881 A boolean, True if the string is a valid dotted decimal IP | |
| 882 string. | |
| 883 | |
| 884 """ | |
| 885 octets = ip_str.split('.') | |
| 886 if len(octets) == 1: | |
| 887 # We have an integer rather than a dotted decimal IP. | |
| 888 try: | |
| 889 return int(ip_str) >= 0 and int(ip_str) <= self._ALL_ONES | |
| 890 except ValueError: | |
| 891 return False | |
| 892 | |
| 893 if len(octets) != 4: | |
| 894 return False | |
| 895 | |
| 896 for octet in octets: | |
| 897 try: | |
| 898 if not 0 <= int(octet) <= 255: | |
| 899 return False | |
| 900 except ValueError: | |
| 901 return False | |
| 902 return True | |
| 903 | |
| 904 @property | |
| 905 def max_prefixlen(self): | |
| 906 return self._max_prefixlen | |
| 907 | |
| 908 @property | |
| 909 def packed(self): | |
| 910 """The binary representation of this address.""" | |
| 911 return struct.pack('!I', self._ip) | |
| 912 | |
| 913 @property | |
| 914 def version(self): | |
| 915 return self._version | |
| 916 | |
| 917 | |
| 918 class IPv4Address(BaseV4, BaseIP): | |
| 919 | |
| 920 """Represent and manipulate single IPv4 Addresses.""" | |
| 921 | |
| 922 def __init__(self, address): | |
| 923 | |
| 924 """ | |
| 925 Args: | |
| 926 address: A string or integer representing the IP | |
| 927 '192.168.1.1' | |
| 928 | |
| 929 Additionally, an integer can be passed, so | |
| 930 IPv4Address('192.168.1.1') == IPv4Address(3232235777). | |
| 931 or, more generally | |
| 932 IPv4Address(int(IPv4Address('192.168.1.1'))) == | |
| 933 IPv4Address('192.168.1.1') | |
| 934 | |
| 935 Raises: | |
| 936 IPv4IpValidationError: If ipaddr isn't a valid IPv4 address. | |
| 937 IPv4NetmaskValidationError: If the netmask isn't valid for | |
| 938 an IPv4 address. | |
| 939 | |
| 940 """ | |
| 941 BaseIP.__init__(self, address) | |
| 942 BaseV4.__init__(self, address) | |
| 943 | |
| 944 # Efficient constructor from integer. | |
| 945 if isinstance(address, int) or isinstance(address, long): | |
| 946 self._ip = address | |
| 947 if address < 0 or address > self._ALL_ONES: | |
| 948 raise IPv4IpValidationError(address) | |
| 949 return | |
| 950 | |
| 951 # Constructing from a packed address | |
| 952 if _compat_has_real_bytes: | |
| 953 if isinstance(address, bytes) and len(address) == 4: | |
| 954 self._ip = struct.unpack('!I', address)[0] | |
| 955 return | |
| 956 | |
| 957 # we have a string | |
| 958 if not self._is_valid_ip(address): | |
| 959 raise IPv4IpValidationError(address) | |
| 960 | |
| 961 self._ip = self._ip_int_from_string(address) | |
| 962 | |
| 963 | |
| 964 class IPv4Network(BaseV4, BaseNet): | |
| 965 | |
| 966 """This class represents and manipulates 32-bit IPv4 networks. | |
| 967 | |
| 968 Attributes: [examples for IPv4Network('1.2.3.4/27')] | |
| 969 ._ip: 16909060 | |
| 970 .ip: IPv4Address('1.2.3.4') | |
| 971 .network: IPv4Address('1.2.3.0') | |
| 972 .hostmask: IPv4Address('0.0.0.31') | |
| 973 .broadcast: IPv4Address('1.2.3.31') | |
| 974 .netmask: IPv4Address('255.255.255.224') | |
| 975 .prefixlen: 27 | |
| 976 | |
| 977 """ | |
| 978 | |
| 979 def __init__(self, address): | |
| 980 """Instantiate a new IPv4 network object. | |
| 981 | |
| 982 Args: | |
| 983 address: A string or integer representing the IP [& network]. | |
| 643 '192.168.1.1/32' | 984 '192.168.1.1/32' |
| 644 '192.168.1.1/255.255.255.255' | 985 '192.168.1.1/255.255.255.255' |
| 645 '192.168.1.1/0.0.0.255' | 986 '192.168.1.1/0.0.0.255' |
| 646 '192.168.1.1' | 987 '192.168.1.1' |
| 647 are all functionally the same in IPv4. That is to say, | 988 are all functionally the same in IPv4. That is to say, |
| 648 failing to provide a subnetmask will create an object with | 989 failing to provide a subnetmask will create an object with |
| 649 a mask of /32. A netmask of '255.255.255.255' is assumed | 990 a mask of /32. A netmask of '255.255.255.255' is assumed |
| 650 to be /32 and '0.0.0.0' is assumed to be /0, even though | 991 to be /32 and '0.0.0.0' is assumed to be /0, even though |
| 651 other netmasks can be expressed both as host- and | 992 other netmasks can be expressed both as host- and |
| 652 net-masks. (255.0.0.0 == 0.255.255.255) | 993 net-masks. (255.0.0.0 == 0.255.255.255) |
| 653 | 994 |
| 654 Additionally, an integer can be passed, so | 995 Additionally, an integer can be passed, so |
| 655 IPv4('192.168.1.1') == IPv4(3232235777). | 996 IPv4Network('192.168.1.1') == IPv4Network(3232235777). |
| 656 or, more generally | 997 or, more generally |
| 657 IPv4(IPv4('192.168.1.1').ip) == IPv4('192.168.1.1') | 998 IPv4Network(int(IPv4Network('192.168.1.1'))) == |
| 999 IPv4Network('192.168.1.1') | |
| 658 | 1000 |
| 659 Raises: | 1001 Raises: |
| 660 IPv4IpValidationError: If ipaddr isn't a valid IPv4 address. | 1002 IPv4IpValidationError: If ipaddr isn't a valid IPv4 address. |
| 661 IPv4NetmaskValidationError: If the netmask isn't valid for | 1003 IPv4NetmaskValidationError: If the netmask isn't valid for |
| 662 an IPv4 address. | 1004 an IPv4 address. |
| 663 | 1005 |
| 664 """ | 1006 """ |
| 665 BaseIP.__init__(self) | 1007 BaseNet.__init__(self, address) |
| 666 self._version = 4 | 1008 BaseV4.__init__(self, address) |
| 667 self._max_prefixlen = 32 | |
| 668 | 1009 |
| 669 # Efficient constructor from integer. | 1010 # Efficient constructor from integer. |
| 670 if isinstance(ipaddr, int) or isinstance(ipaddr, long): | 1011 if isinstance(address, int) or isinstance(address, long): |
| 671 self.ip = ipaddr | 1012 self._ip = address |
| 1013 self.ip = IPv4Address(self._ip) | |
| 672 self._prefixlen = 32 | 1014 self._prefixlen = 32 |
| 673 self.netmask = self._ALL_ONES | 1015 self.netmask = IPv4Address(self._ALL_ONES) |
| 674 if ipaddr < 0 or ipaddr > self._ALL_ONES: | 1016 if address < 0 or address > self._ALL_ONES: |
| 675 raise IPv4IpValidationError(ipaddr) | 1017 raise IPv4IpValidationError(address) |
| 676 return | 1018 return |
| 677 | 1019 |
| 678 # Constructing from a packed address | 1020 # Constructing from a packed address |
| 679 if _compat_has_real_bytes: | 1021 if _compat_has_real_bytes: |
| 680 if isinstance(ipaddr, bytes) and len(ipaddr) == 4: | 1022 if isinstance(address, bytes) and len(address) == 4: |
| 681 self.ip = struct.unpack('!I', ipaddr)[0] | 1023 self._ip = struct.unpack('!I', address)[0] |
| 1024 self.ip = IPv4Address(self._ip) | |
| 682 self._prefixlen = 32 | 1025 self._prefixlen = 32 |
| 683 self.netmask = self._ALL_ONES | 1026 self.netmask = IPv4Address(self._ALL_ONES) |
| 684 return | 1027 return |
| 685 | 1028 |
| 686 # Assume input argument to be string or any object representation | 1029 # Assume input argument to be string or any object representation |
| 687 # which converts into a formatted IP prefix string. | 1030 # which converts into a formatted IP prefix string. |
| 688 addr = str(ipaddr).split('/') | 1031 addr = str(address).split('/') |
| 689 | 1032 |
| 690 if len(addr) > 2: | 1033 if len(addr) > 2: |
| 691 raise IPv4IpValidationError(ipaddr) | 1034 raise IPv4IpValidationError(address) |
| 692 | 1035 |
| 693 if not self._is_valid_ip(addr[0]): | 1036 if not self._is_valid_ip(addr[0]): |
| 694 raise IPv4IpValidationError(addr[0]) | 1037 raise IPv4IpValidationError(addr[0]) |
| 695 | 1038 |
| 696 self.ip = self._ip_int_from_string(addr[0]) | 1039 self._ip = self._ip_int_from_string(addr[0]) |
| 1040 self.ip = IPv4Address(self._ip) | |
| 697 | 1041 |
| 698 if len(addr) == 2: | 1042 if len(addr) == 2: |
| 699 mask = addr[1].split('.') | 1043 mask = addr[1].split('.') |
| 700 if len(mask) == 4: | 1044 if len(mask) == 4: |
| 701 # We have dotted decimal netmask. | 1045 # We have dotted decimal netmask. |
| 702 if not self._is_valid_netmask(addr[1]): | 1046 if not self._is_valid_netmask(addr[1]): |
| 703 raise IPv4NetmaskValidationError(addr[1]) | 1047 raise IPv4NetmaskValidationError(addr[1]) |
| 704 if self._is_hostmask(addr[1]): | 1048 if self._is_hostmask(addr[1]): |
| 705 self.netmask = ( | 1049 self.netmask = IPv4Address( |
| 706 self._ip_int_from_string(addr[1]) ^ self._ALL_ONES) | 1050 self._ip_int_from_string(addr[1]) ^ self._ALL_ONES) |
| 707 else: | 1051 else: |
| 708 self.netmask = self._ip_int_from_string(addr[1]) | 1052 self.netmask = IPv4Address(self._ip_int_from_string( |
| 709 self._prefixlen = self._prefix_from_ip_int(self.netmask) | 1053 addr[1])) |
| 1054 | |
| 1055 self._prefixlen = self._prefix_from_ip_int(int(self.netmask)) | |
| 710 else: | 1056 else: |
| 711 # We have a netmask in prefix length form. | 1057 # We have a netmask in prefix length form. |
| 712 if not self._is_valid_netmask(addr[1]): | 1058 if not self._is_valid_netmask(addr[1]): |
| 713 raise IPv4NetmaskValidationError(addr[1]) | 1059 raise IPv4NetmaskValidationError(addr[1]) |
| 714 self._prefixlen = int(addr[1]) | 1060 self._prefixlen = int(addr[1]) |
| 715 self.netmask = self._ip_int_from_prefix(self._prefixlen) | 1061 self.netmask = IPv4Address(self._ip_int_from_prefix( |
| 1062 self._prefixlen)) | |
| 716 else: | 1063 else: |
| 717 self._prefixlen = 32 | 1064 self._prefixlen = 32 |
| 718 self.netmask = self._ip_int_from_prefix(self._prefixlen) | 1065 self.netmask = IPv4Address(self._ip_int_from_prefix( |
| 1066 self._prefixlen)) | |
| 1067 | |
| 719 | 1068 |
| 720 def _set_prefix(self, prefixlen): | 1069 def _set_prefix(self, prefixlen): |
| 721 """Change the prefix length. | 1070 """Change the prefix length of an IPv4 network object. |
| 722 | 1071 |
| 723 Args: | 1072 Args: |
| 724 prefixlen: An integer, the new prefix length. | 1073 prefixlen: An integer, the new prefix length. |
| 725 | 1074 |
| 726 Raises: | 1075 Raises: |
| 727 IPv4NetmaskValidationError: If prefixlen is out of bounds. | 1076 IPv4NetmaskValidationError: If prefixlen is out of bounds. |
| 728 | 1077 |
| 729 """ | 1078 """ |
| 730 if not 0 <= prefixlen <= 32: | 1079 if not 0 <= prefixlen <= 32: |
| 731 raise IPv4NetmaskValidationError(prefixlen) | 1080 raise IPv4NetmaskValidationError(prefixlen) |
| 732 self._prefixlen = prefixlen | 1081 self._prefixlen = prefixlen |
| 733 self.netmask = self._ip_int_from_prefix(self._prefixlen) | 1082 self.netmask = IPv4Address(self._ip_int_from_prefix(self._prefixlen)) |
| 1083 # invalidate the element cache | |
| 1084 self._cache['network'] = None | |
| 1085 self._cache['hostmask'] = None | |
| 1086 self._cache['broadcast'] = None | |
| 734 | 1087 |
| 735 def subnet(self, prefixlen_diff=1): | 1088 def subnet(self, prefixlen_diff=1): |
| 736 """The subnets which join to make the current subnet. | 1089 """The subnets which join to make the current subnet. |
| 737 | 1090 |
| 738 In the case that self contains only one IP | 1091 In the case that self contains only one IP |
| 739 (self._prefixlen == 32), return a list with just ourself. | 1092 (self._prefixlen == 32), return a list with just ourself. |
| 740 | 1093 |
| 741 Args: | 1094 Args: |
| 742 prefixlen_diff: An integer, the amount the prefix length | 1095 prefixlen_diff: An integer, the amount the prefix length |
| 743 should be increased by. Given a /24 network and a | 1096 should be increased by. Given a /24 network and a |
| 744 prefixlen_diff of 3, for example, 8 subnets of size /27 | 1097 prefixlen_diff of 3, for example, 8 subnets of size /27 |
| 745 will be returned. The default value of 1 splits the | 1098 will be returned. The default value of 1 splits the |
| 746 current network into two halves. | 1099 current network into two halves. |
| 747 | 1100 |
| 748 Returns: | 1101 Returns: |
| 749 A list of IPv4 objects. | 1102 A list of IPv4 network objects. |
| 750 | 1103 |
| 751 Raises: | 1104 Raises: |
| 752 PrefixlenDiffInvalidError: The prefixlen_diff is too small | 1105 PrefixlenDiffInvalidError: The prefixlen_diff is too small |
| 753 or too large. | 1106 or too large. |
| 754 | 1107 |
| 755 """ | 1108 """ |
| 756 if self._prefixlen == 32: | 1109 if self._prefixlen == 32: |
| 757 return [self] | 1110 return [self] |
| 758 | 1111 |
| 759 if prefixlen_diff < 0: | 1112 if prefixlen_diff < 0: |
| 760 raise PrefixlenDiffInvalidError('prefix length diff must be > 0') | 1113 raise PrefixlenDiffInvalidError('prefix length diff must be > 0') |
| 761 new_prefixlen = self.prefixlen + prefixlen_diff | 1114 new_prefixlen = self._prefixlen + prefixlen_diff |
| 762 | 1115 |
| 763 if not self._is_valid_netmask(str(new_prefixlen)): | 1116 if not self._is_valid_netmask(str(new_prefixlen)): |
| 764 raise PrefixlenDiffInvalidError( | 1117 raise PrefixlenDiffInvalidError( |
| 765 'prefix length diff %d is invalid for netblock %s' % ( | 1118 'prefix length diff %d is invalid for netblock %s' % ( |
| 766 new_prefixlen, str(self))) | 1119 new_prefixlen, str(self))) |
| 767 | 1120 |
| 768 first = IPv4( | 1121 first = IPv4('%s/%s' % (str(self.network), |
| 769 self._string_from_ip_int(self.network) + '/' + | 1122 str(self._prefixlen + prefixlen_diff))) |
| 770 str(self._prefixlen + prefixlen_diff)) | |
| 771 subnets = [first] | 1123 subnets = [first] |
| 772 current = first | 1124 current = first |
| 773 while True: | 1125 while True: |
| 774 broadcast = current.broadcast | 1126 broadcast = current.broadcast |
| 775 if broadcast == self.broadcast: | 1127 if broadcast == self.broadcast: |
| 776 break | 1128 break |
| 777 current = IPv4(self._string_from_ip_int(broadcast + 1) + '/' + | 1129 current = IPv4('%d/%s' % (int(broadcast) + 1, str(new_prefixlen))) |
| 778 str(new_prefixlen)) | |
| 779 subnets.append(current) | 1130 subnets.append(current) |
| 780 | 1131 |
| 781 return subnets | 1132 return subnets |
| 782 | 1133 |
| 783 def supernet(self, prefixlen_diff=1): | 1134 def supernet(self, prefixlen_diff=1): |
| 784 """The supernet containing the current network. | 1135 """The supernet containing the current network. |
| 785 | 1136 |
| 786 Args: | 1137 Args: |
| 787 prefixlen_diff: An integer, the amount the prefix length of | 1138 prefixlen_diff: An integer, the amount the prefix length of |
| 788 the network should be decreased by. For example, given a | 1139 the network should be decreased by. For example, given a |
| 789 /24 network and a prefixlen_diff of 3, a supernet with a | 1140 /24 network and a prefixlen_diff of 3, a supernet with a |
| 790 /21 netmask is returned. | 1141 /21 netmask is returned. |
| 791 | 1142 |
| 792 Returns: | 1143 Returns: |
| 793 An IPv4 object. | 1144 An IPv4 network object. |
| 794 | 1145 |
| 795 Raises: | 1146 Raises: |
| 796 PrefixlenDiffInvalidError: If | 1147 PrefixlenDiffInvalidError: If |
| 797 self.prefixlen - prefixlen_diff < 0. I.e., you have a | 1148 self.prefixlen - prefixlen_diff < 0. I.e., you have a |
| 798 negative prefix length. | 1149 negative prefix length. |
| 799 | 1150 |
| 800 """ | 1151 """ |
| 801 if self.prefixlen == 0: | 1152 if self._prefixlen == 0: |
| 802 return self | 1153 return self |
| 803 if self.prefixlen - prefixlen_diff < 0: | 1154 if self.prefixlen - prefixlen_diff < 0: |
| 804 raise PrefixlenDiffInvalidError( | 1155 raise PrefixlenDiffInvalidError( |
| 805 'current prefixlen is %d, cannot have a prefixlen_diff of %d' % | 1156 'current prefixlen is %d, cannot have a prefixlen_diff of %d' % |
| 806 (self.prefixlen, prefixlen_diff)) | 1157 (self.prefixlen, prefixlen_diff)) |
| 807 return IPv4(self.ip_ext + '/' + str(self.prefixlen - prefixlen_diff)) | 1158 return IPv4('%s/%s' % (str(self.network), |
| 1159 str(self.prefixlen - prefixlen_diff))) | |
| 808 | 1160 |
| 809 @property | 1161 @property |
| 810 def is_private(self): | 1162 def is_private(self): |
| 811 """Test if this address is allocated for private networks. | 1163 """Test if this address is allocated for private networks. |
| 812 | 1164 |
| 813 Returns: | 1165 Returns: |
| 814 A boolean, True if the address is reserved per RFC 1918. | 1166 A boolean, True if the address is reserved per RFC 1918. |
| 815 | 1167 |
| 816 """ | 1168 """ |
| 817 return (self in IPv4('10.0.0.0/8') or | 1169 return (self in IPv4('10.0.0.0/8') or |
| (...skipping 23 matching lines...) Expand all Loading... | |
| 841 | 1193 |
| 842 @property | 1194 @property |
| 843 def is_link_local(self): | 1195 def is_link_local(self): |
| 844 """Test if the address is reserved for link-local. | 1196 """Test if the address is reserved for link-local. |
| 845 | 1197 |
| 846 Returns: | 1198 Returns: |
| 847 A boolean, True if the address is link-local per RFC 3927. | 1199 A boolean, True if the address is link-local per RFC 3927. |
| 848 | 1200 |
| 849 """ | 1201 """ |
| 850 return self in IPv4('169.254.0.0/16') | 1202 return self in IPv4('169.254.0.0/16') |
| 851 | |
| 852 @property | |
| 853 def version(self): | |
| 854 return self._version | |
| 855 | |
| 856 @property | |
| 857 def max_prefixlen(self): | |
|
Peter Moody
2009/06/02 21:05:19
this could be a property of BaseIP
| |
| 858 return self._max_prefixlen | |
| 859 | |
| 860 @property | |
| 861 def packed(self): | |
| 862 """The binary representation of this address.""" | |
| 863 return struct.pack('!I', self.ip) | |
| 864 | 1203 |
| 865 def _is_hostmask(self, ip_str): | 1204 def _is_hostmask(self, ip_str): |
| 866 """Test if the IP string is a hostmask (rather than a netmask). | 1205 """Test if the IP string is a hostmask (rather than a netmask). |
| 867 | 1206 |
| 868 Args: | 1207 Args: |
| 869 ip_str: A string, the potential hostmask. | 1208 ip_str: A string, the potential hostmask. |
| 870 | 1209 |
| 871 Returns: | 1210 Returns: |
| 872 A boolean, True if the IP string is a hostmask. | 1211 A boolean, True if the IP string is a hostmask. |
| 873 | 1212 |
| 874 """ | 1213 """ |
| 875 parts = [int(x) for x in ip_str.split('.')] | 1214 parts = [int(x) for x in ip_str.split('.')] |
| 876 if parts[0] < parts[-1]: | 1215 if parts[0] < parts[-1]: |
| 877 return True | 1216 return True |
| 878 return False | 1217 return False |
| 879 | |
| 880 def _ip_int_from_string(self, ip_str): | |
| 881 """Turn the given IP string into an integer for comparison. | |
| 882 | |
| 883 Args: | |
| 884 ip_str: A string, the IP address. | |
| 885 | |
| 886 Returns: | |
| 887 The IP address as an integer. | |
| 888 | |
| 889 """ | |
| 890 packed_ip = 0 | |
| 891 for oc in ip_str.split('.'): | |
| 892 packed_ip = (packed_ip << 8) | int(oc) | |
| 893 return packed_ip | |
| 894 | |
| 895 def _string_from_ip_int(self, ip_int): | |
| 896 """Turns a 32-bit integer into dotted decimal notation. | |
| 897 | |
| 898 Args: | |
| 899 ip_int: An integer, the IP address. | |
| 900 | |
| 901 Returns: | |
| 902 The IP address as a string in dotted decimal notation. | |
| 903 | |
| 904 """ | |
| 905 octets = [] | |
| 906 for _ in xrange(4): | |
| 907 octets.insert(0, str(ip_int & 0xFF)) | |
| 908 ip_int >>= 8 | |
| 909 return '.'.join(octets) | |
| 910 | |
| 911 def _is_valid_ip(self, ip_str): | |
| 912 """Validate the dotted decimal notation IP/netmask string. | |
| 913 | |
| 914 Args: | |
| 915 ip_str: A string, the IP address. | |
| 916 | |
| 917 Returns: | |
| 918 A boolean, True if the string is a valid dotted decimal IP | |
| 919 string. | |
| 920 | |
| 921 """ | |
| 922 octets = ip_str.split('.') | |
| 923 if len(octets) == 1: | |
| 924 # We have an integer rather than a dotted decimal IP. | |
| 925 try: | |
| 926 return int(ip_str) >= 0 and int(ip_str) <= self._ALL_ONES | |
| 927 except ValueError: | |
| 928 return False | |
| 929 | |
| 930 if len(octets) != 4: | |
| 931 return False | |
| 932 | |
| 933 for octet in octets: | |
| 934 try: | |
| 935 if not 0 <= int(octet) <= 255: | |
| 936 return False | |
| 937 except ValueError: | |
| 938 return False | |
| 939 return True | |
| 940 | 1218 |
| 941 def _is_valid_netmask(self, netmask): | 1219 def _is_valid_netmask(self, netmask): |
| 942 """Verify that the netmask is valid. | 1220 """Verify that the netmask is valid. |
| 943 | 1221 |
| 944 Args: | 1222 Args: |
| 945 netmask: A string, either a prefix or dotted decimal | 1223 netmask: A string, either a prefix or dotted decimal |
| 946 netmask. | 1224 netmask. |
| 947 | 1225 |
| 948 Returns: | 1226 Returns: |
| 949 A boolean, True if the prefix represents a valid IPv4 | 1227 A boolean, True if the prefix represents a valid IPv4 |
| 950 netmask. | 1228 netmask. |
| 951 | 1229 |
| 952 """ | 1230 """ |
| 953 if len(netmask.split('.')) == 4: | 1231 if len(netmask.split('.')) == 4: |
| 954 return self._is_valid_ip(netmask) | 1232 return self._is_valid_ip(netmask) |
| 955 try: | 1233 try: |
| 956 netmask = int(netmask) | 1234 netmask = int(netmask) |
| 957 except ValueError: | 1235 except ValueError: |
| 958 return False | 1236 return False |
| 959 return 0 <= netmask <= 32 | 1237 return 0 <= netmask <= 32 |
| 960 | 1238 |
| 961 # backwards compatibility | 1239 # backwards compatibility |
| 962 Subnet = subnet | 1240 Subnet = subnet |
| 963 Supernet = supernet | 1241 Supernet = supernet |
| 964 IsRFC1918 = lambda self: self.is_private | 1242 IsRFC1918 = lambda self: self.is_private |
| 965 IsMulticast = lambda self: self.is_multicast | 1243 IsMulticast = lambda self: self.is_multicast |
| 966 IsLoopback = lambda self: self.is_loopback | 1244 IsLoopback = lambda self: self.is_loopback |
| 967 IsLinkLocal = lambda self: self.is_link_local | 1245 IsLinkLocal = lambda self: self.is_link_local |
| 968 | 1246 |
| 969 class IPv6(BaseIP): | 1247 |
| 970 | 1248 class BaseV6(object): |
| 971 """This class respresents and manipulates 128-bit IPv6 addresses. | 1249 |
| 972 | 1250 """Base IPv6 object. |
| 973 Attributes: [examples for IPv6('2001:658:22A:CAFE:200::1/64')] | 1251 |
| 974 .ip: 42540616829182469433547762482097946625L | 1252 The following methods are used by IPv6 objects in both single IP |
| 975 .ip_ext: '2001:658:22a:cafe:200::1' | 1253 addresses and networks. |
| 976 .ip_ext_full: '2001:0658:022a:cafe:0200:0000:0000:0001' | |
| 977 .network: 42540616829182469433403647294022090752L | |
| 978 .network_ext: '2001:658:22a:cafe::' | |
| 979 .hostmask: 18446744073709551615L | |
| 980 .hostmask_ext: '::ffff:ffff:ffff:ffff' | |
| 981 .broadcast: 42540616829182469451850391367731642367L | |
| 982 .broadcast_ext: '2001:658:22a:cafe:ffff:ffff:ffff:ffff' | |
| 983 .netmask: 340282366920938463444927863358058659840L | |
| 984 .netmask_ext: 64 | |
| 985 .prefixlen: 64 | |
| 986 | 1254 |
| 987 """ | 1255 """ |
| 988 | 1256 |
| 989 _ALL_ONES = (2**128) - 1 | 1257 _ALL_ONES = (2**128) - 1 |
| 990 | 1258 |
| 991 def __init__(self, ipaddr): | 1259 def __init__(self, address): |
| 992 """Instantiate a new IPv6 object. | |
| 993 | |
| 994 Args: | |
| 995 ipaddr: A string or integer representing the IP or the IP | |
| 996 and prefix/netmask. | |
| 997 '2001:4860::/128' | |
| 998 '2001:4860:0000:0000:0000:0000:0000:0000/128' | |
| 999 '2001:4860::' | |
| 1000 are all functionally the same in IPv6. That is to say, | |
| 1001 failing to provide a subnetmask will create an object with | |
| 1002 a mask of /128. | |
| 1003 | |
| 1004 Additionally, an integer can be passed, so | |
| 1005 IPv6('2001:4860::') == | |
| 1006 IPv6(42541956101370907050197289607612071936L). | |
| 1007 or, more generally | |
| 1008 IPv6(IPv6('2001:4860::').ip) == IPv6('2001:4860::') | |
| 1009 | |
| 1010 Raises: | |
| 1011 IPv6IpValidationError: If ipaddr isn't a valid IPv6 address. | |
| 1012 IPv6NetmaskValidationError: If the netmask isn't valid for | |
| 1013 an IPv6 address. | |
| 1014 | |
| 1015 """ | |
| 1016 BaseIP.__init__(self) | |
| 1017 self._version = 6 | 1260 self._version = 6 |
| 1018 self._max_prefixlen = 128 | 1261 self._max_prefixlen = 128 |
| 1019 | 1262 |
| 1020 # Efficient constructor from integer. | 1263 def _ip_int_from_string(self, ip_str=None): |
| 1021 if isinstance(ipaddr, long) or isinstance(ipaddr, int): | 1264 """Turn an IPv6 ip_str into an integer. |
| 1022 self.ip = ipaddr | 1265 |
| 1023 self._prefixlen = 128 | 1266 Args: |
| 1024 self.netmask = self._ALL_ONES | 1267 ip_str: A string, the IPv6 ip_str. |
| 1025 if ipaddr < 0 or ipaddr > self._ALL_ONES: | 1268 |
| 1026 raise IPv6IpValidationError(ipaddr) | 1269 Returns: |
| 1027 return | 1270 A long, the IPv6 ip_str. |
| 1028 | |
| 1029 # Constructing from a packed address | |
| 1030 if _compat_has_real_bytes: | |
| 1031 if isinstance(ipaddr, bytes) and len(ipaddr) == 16: | |
| 1032 tmp = struct.unpack('!QQ', ipaddr) | |
| 1033 self.ip = (tmp[0] << 64) | tmp[1] | |
| 1034 self._prefixlen = 128 | |
| 1035 self.netmask = self._ALL_ONES | |
| 1036 return | |
| 1037 | |
| 1038 # Assume input argument to be string or any object representation | |
| 1039 # which converts into a formatted IP prefix string. | |
| 1040 addr_str = str(ipaddr) | |
| 1041 if not addr_str: | |
| 1042 raise IPv6IpValidationError('') | |
| 1043 addr = addr_str.split('/') | |
| 1044 if len(addr) > 1: | |
| 1045 if self._is_valid_netmask(addr[1]): | |
| 1046 self._prefixlen = int(addr[1]) | |
| 1047 else: | |
| 1048 raise IPv6NetmaskValidationError(addr[1]) | |
| 1049 else: | |
| 1050 self._prefixlen = 128 | |
| 1051 | |
| 1052 self.netmask = self._ip_int_from_prefix(self._prefixlen) | |
| 1053 | |
| 1054 if not self._is_valid_ip(addr[0]): | |
| 1055 raise IPv6IpValidationError(addr[0]) | |
| 1056 | |
| 1057 self.ip = self._ip_int_from_string(addr[0]) | |
| 1058 | |
| 1059 @property | |
| 1060 def ip_ext_full(self): | |
| 1061 """Returns the expanded version of the IPv6 string.""" | |
| 1062 return self._explode_shorthand_ip_string(self.ip_ext) | |
| 1063 | |
| 1064 def _set_prefix(self, prefixlen): | |
| 1065 """Change the prefix length. | |
| 1066 | |
| 1067 Args: | |
| 1068 prefixlen: An integer, the new prefix length. | |
| 1069 | |
| 1070 Raises: | |
| 1071 IPv6NetmaskValidationError: If prefixlen is out of bounds. | |
| 1072 | |
| 1073 """ | |
| 1074 if not 0 <= prefixlen <= 128: | |
| 1075 raise IPv6NetmaskValidationError(prefixlen) | |
| 1076 self._prefixlen = prefixlen | |
| 1077 self.netmask = self._ip_int_from_prefix(self.prefixlen) | |
| 1078 | |
| 1079 def subnet(self, prefixlen_diff=1): | |
| 1080 """The subnets which join to make the current subnet. | |
| 1081 | |
| 1082 In the case that self contains only one IP | |
| 1083 (self._prefixlen == 128), return a list with just ourself. | |
| 1084 | |
| 1085 Args: | |
| 1086 prefixlen_diff: An integer, the amount the prefix length | |
| 1087 should be increased by. | |
| 1088 | |
| 1089 Returns: | |
| 1090 A list of IPv6 objects. | |
| 1091 | |
| 1092 Raises: | |
| 1093 PrefixlenDiffInvalidError: The prefixlen_diff is too small | |
| 1094 or too large. | |
| 1095 | |
| 1096 """ | |
| 1097 # Preserve original functionality (return [self] if | |
| 1098 # self.prefixlen == 128). | |
| 1099 if self.prefixlen == 128: | |
| 1100 return [self] | |
| 1101 | |
| 1102 if prefixlen_diff < 0: | |
| 1103 raise PrefixlenDiffInvalidError('Prefix length diff must be > 0') | |
| 1104 new_prefixlen = self.prefixlen + prefixlen_diff | |
| 1105 if not self._is_valid_netmask(str(new_prefixlen)): | |
| 1106 raise PrefixlenDiffInvalidError( | |
| 1107 'Prefix length diff %d is invalid for netblock %s' % ( | |
| 1108 new_prefixlen, str(self))) | |
| 1109 first = IPv6( | |
| 1110 self._string_from_ip_int(self.network) + '/' + | |
| 1111 str(self._prefixlen + prefixlen_diff)) | |
| 1112 subnets = [first] | |
| 1113 current = first | |
| 1114 while True: | |
| 1115 broadcast = current.broadcast | |
| 1116 if current.broadcast == self.broadcast: | |
| 1117 break | |
| 1118 current = IPv6(self._string_from_ip_int(broadcast + 1) + '/' + | |
| 1119 str(new_prefixlen)) | |
| 1120 subnets.append(current) | |
| 1121 | |
| 1122 return subnets | |
| 1123 | |
| 1124 def supernet(self, prefixlen_diff=1): | |
| 1125 """The supernet containing the current network. | |
| 1126 | |
| 1127 Args: | |
| 1128 prefixlen_diff: An integer, the amount the prefix length of the | |
| 1129 network should be decreased by. For example, given a /96 | |
| 1130 network and a prefixlen_diff of 3, a supernet with a /93 | |
| 1131 netmask is returned. | |
| 1132 | |
| 1133 Returns: | |
| 1134 An IPv6 object. | |
| 1135 | |
| 1136 Raises: | |
| 1137 PrefixlenDiffInvalidError: If | |
| 1138 self._prefixlen - prefixlen_diff < 0. I.e., you have a | |
| 1139 negative prefix length. | |
| 1140 | |
| 1141 """ | |
| 1142 if self.prefixlen == 0: | |
| 1143 return self | |
| 1144 if self.prefixlen - prefixlen_diff < 0: | |
| 1145 raise PrefixlenDiffInvalidError( | |
| 1146 'current prefixlen is %d, cannot have a prefixlen_diff of %d' % | |
| 1147 (self.prefixlen, prefixlen_diff)) | |
| 1148 return IPv6(self.ip_ext + '/' + str(self.prefixlen - prefixlen_diff)) | |
| 1149 | |
| 1150 @property | |
| 1151 def is_multicast(self): | |
| 1152 """Test if the address is reserved for multicast use. | |
| 1153 | |
| 1154 Returns: | |
| 1155 A boolean, True if the address is a multicast address. | |
| 1156 See RFC 2373 2.7 for details. | |
| 1157 | |
| 1158 """ | |
| 1159 return self in IPv6('ff00::/8') | |
| 1160 | |
| 1161 @property | |
| 1162 def is_unspecified(self): | |
| 1163 """Test if the address is unspecified. | |
| 1164 | |
| 1165 Returns: | |
| 1166 A boolean, True if this is the unspecified address as defined in | |
| 1167 RFC 2373 2.5.2. | |
| 1168 | |
| 1169 """ | |
| 1170 return self == IPv6('::') | |
| 1171 | |
| 1172 @property | |
| 1173 def is_loopback(self): | |
| 1174 """Test if the address is a loopback adddress. | |
| 1175 | |
| 1176 Returns: | |
| 1177 A boolean, True if the address is a loopback address as defined in | |
| 1178 RFC 2373 2.5.3. | |
| 1179 | |
| 1180 """ | |
| 1181 return self == IPv6('::1') | |
| 1182 | |
| 1183 @property | |
| 1184 def is_link_local(self): | |
| 1185 """Test if the address is reserved for link-local. | |
| 1186 | |
| 1187 Returns: | |
| 1188 A boolean, True if the address is reserved per RFC 4291. | |
| 1189 | |
| 1190 """ | |
| 1191 return self in IPv6('fe80::/10') | |
| 1192 | |
| 1193 @property | |
| 1194 def is_site_local(self): | |
| 1195 """Test if the address is reserved for site-local. | |
| 1196 | |
| 1197 Note that the site-local address space has been deprecated by RFC 3879. | |
| 1198 Use is_private to test if this address is in the space of unique local | |
| 1199 addresses as defined by RFC 4193. | |
| 1200 | |
| 1201 Returns: | |
| 1202 A boolean, True if the address is reserved per RFC 3513 2.5.6. | |
| 1203 | |
| 1204 """ | |
| 1205 return self in IPv6('fec0::/10') | |
| 1206 | |
| 1207 @property | |
| 1208 def is_private(self): | |
| 1209 """Test if this address is allocated for private networks. | |
| 1210 | |
| 1211 Returns: | |
| 1212 A boolean, True if the address is reserved per RFC 4193. | |
| 1213 | |
| 1214 """ | |
| 1215 return self in IPv6('fc00::/7') | |
| 1216 | |
| 1217 @property | |
| 1218 def version(self): | |
| 1219 return self._version | |
| 1220 | |
| 1221 @property | |
| 1222 def max_prefixlen(self): | |
| 1223 return self._max_prefixlen | |
| 1224 | |
| 1225 @property | |
| 1226 def packed(self): | |
| 1227 """The binary representation of this address.""" | |
| 1228 return struct.pack('!QQ', self.ip >> 64, self.ip & (2**64 - 1)) | |
| 1229 | |
| 1230 def _is_shorthand_ip(self, ip_str=None): | |
| 1231 """Determine if the address is shortened. | |
| 1232 | |
| 1233 Args: | |
| 1234 ip_str: A string, the IPv6 address. | |
| 1235 | |
| 1236 Returns: | |
| 1237 A boolean, True if the address is shortened. | |
| 1238 | |
| 1239 """ | |
| 1240 if ip_str.count('::') == 1: | |
| 1241 return True | |
| 1242 return False | |
| 1243 | |
| 1244 def _explode_shorthand_ip_string(self, ip_str): | |
| 1245 """Expand a shortened IPv6 address. | |
| 1246 | |
| 1247 Args: | |
| 1248 ip_str: A string, the IPv6 address. | |
| 1249 | |
| 1250 Returns: | |
| 1251 A string, the expanded IPv6 address. | |
| 1252 | |
| 1253 """ | |
| 1254 if self._is_shorthand_ip(ip_str): | |
| 1255 new_ip = [] | |
| 1256 hextet = ip_str.split('::') | |
| 1257 sep = len(hextet[0].split(':')) + len(hextet[1].split(':')) | |
| 1258 new_ip = hextet[0].split(':') | |
| 1259 | |
| 1260 for _ in xrange(8 - sep): | |
| 1261 new_ip.append('0000') | |
| 1262 new_ip += hextet[1].split(':') | |
| 1263 | |
| 1264 # Now need to make sure every hextet is 4 lower case characters. | |
| 1265 # If a hextet is < 4 characters, we've got missing leading 0's. | |
| 1266 ret_ip = [] | |
| 1267 for hextet in new_ip: | |
| 1268 ret_ip.append(('0' * (4 - len(hextet)) + hextet).lower()) | |
| 1269 return ':'.join(ret_ip) | |
| 1270 # We've already got a longhand ip_str. | |
| 1271 return ip_str | |
| 1272 | |
| 1273 def _is_valid_ip(self, ip_str=None): | |
| 1274 """Ensure we have a valid IPv6 address. | |
| 1275 | |
| 1276 Probably not as exhaustive as it should be. | |
| 1277 | |
| 1278 Args: | |
| 1279 ip_str: A string, the IPv6 address. | |
| 1280 | |
| 1281 Returns: | |
| 1282 A boolean, True if this is a valid IPv6 address. | |
| 1283 | 1271 |
| 1284 """ | 1272 """ |
| 1285 if not ip_str: | 1273 if not ip_str: |
| 1286 ip_str = self.ip_ext | 1274 ip_str = str(self.ip) |
| 1287 | |
| 1288 # We need to have at least one ':'. | |
| 1289 if ':' not in ip_str: | |
| 1290 return False | |
| 1291 | |
| 1292 # We can only have one '::' shortener. | |
| 1293 if ip_str.count('::') > 1: | |
| 1294 return False | |
| 1295 | |
| 1296 # '::' should be encompassed by start, digits or end. | |
| 1297 if ':::' in ip_str: | |
| 1298 return False | |
| 1299 | |
| 1300 # A single colon can neither start nor end an address. | |
| 1301 if ((ip_str.startswith(':') and not ip_str.startswith('::')) or | |
| 1302 (ip_str.endswith(':') and not ip_str.endswith('::'))): | |
| 1303 return False | |
| 1304 | |
| 1305 # If we have no concatenation, we need to have 8 fields with 7 ':'. | |
| 1306 if '::' not in ip_str and ip_str.count(':') != 7: | |
| 1307 # We might have an IPv4 mapped address. | |
| 1308 if ip_str.count('.') != 3: | |
| 1309 return False | |
| 1310 | |
| 1311 ip_str = self._explode_shorthand_ip_string(ip_str) | |
| 1312 | |
| 1313 # Now that we have that all squared away, let's check that each of the | |
| 1314 # hextets are between 0x0 and 0xFFFF. | |
| 1315 for hextet in ip_str.split(':'): | |
| 1316 if hextet.count('.') == 3: | |
| 1317 # If we have an IPv4 mapped address, the IPv4 portion has to be | |
| 1318 # at the end of the IPv6 portion. | |
| 1319 if not ip_str.split(':')[-1] == hextet: | |
| 1320 return False | |
| 1321 try: | |
| 1322 IPv4(hextet) | |
| 1323 except IPv4IpValidationError: | |
| 1324 return False | |
| 1325 elif int(hextet, 16) < 0x0 or int(hextet, 16) > 0xFFFF: | |
| 1326 return False | |
| 1327 return True | |
| 1328 | |
| 1329 def _is_valid_netmask(self, prefixlen): | |
| 1330 """Verify that the netmask/prefixlen is valid. | |
| 1331 | |
| 1332 Args: | |
| 1333 prefixlen: A string, the netmask in prefix length format. | |
| 1334 | |
| 1335 Returns: | |
| 1336 A boolean, True if the prefix represents a valid IPv6 | |
| 1337 netmask. | |
| 1338 | |
| 1339 """ | |
| 1340 try: | |
| 1341 prefixlen = int(prefixlen) | |
| 1342 except ValueError: | |
| 1343 return False | |
| 1344 return 0 <= prefixlen <= 128 | |
| 1345 | |
| 1346 def _ip_int_from_string(self, ip_str=None): | |
| 1347 """Turn an IPv6 address into an integer. | |
| 1348 | |
| 1349 Args: | |
| 1350 ip_str: A string, the IPv6 address. | |
| 1351 | |
| 1352 Returns: | |
| 1353 A long, the IPv6 address. | |
| 1354 | |
| 1355 """ | |
| 1356 if not ip_str: | |
| 1357 ip_str = self.ip_ext | |
| 1358 | 1275 |
| 1359 ip_int = 0 | 1276 ip_int = 0 |
| 1360 | 1277 |
| 1361 fields = self._explode_shorthand_ip_string(ip_str).split(':') | 1278 fields = self._explode_shorthand_ip_string(ip_str).split(':') |
| 1362 | 1279 |
| 1363 # Do we have an IPv4 mapped (::ffff:a.b.c.d) or compact (::a.b.c.d) | 1280 # Do we have an IPv4 mapped (::ffff:a.b.c.d) or compact (::a.b.c.d) |
| 1364 # address? | 1281 # ip_str? |
| 1365 if fields[-1].count('.') == 3: | 1282 if fields[-1].count('.') == 3: |
| 1366 ipv4_string = fields.pop() | 1283 ipv4_string = fields.pop() |
| 1367 ipv4_int = IPv4(ipv4_string).ip | 1284 ipv4_int = IPv4(ipv4_string)._ip |
| 1368 octets = [] | 1285 octets = [] |
| 1369 for _ in xrange(2): | 1286 for _ in xrange(2): |
| 1370 octets.append(hex(ipv4_int & 0xFFFF).lstrip('0x').rstrip('L')) | 1287 octets.append(hex(ipv4_int & 0xFFFF).lstrip('0x').rstrip('L')) |
| 1371 ipv4_int >>= 16 | 1288 ipv4_int >>= 16 |
| 1372 fields.extend(reversed(octets)) | 1289 fields.extend(reversed(octets)) |
| 1373 | 1290 |
| 1374 for field in fields: | 1291 for field in fields: |
| 1375 ip_int = (ip_int << 16) + int(field, 16) | 1292 ip_int = (ip_int << 16) + int(field, 16) |
| 1376 | 1293 |
| 1377 return ip_int | 1294 return ip_int |
| (...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1430 ip_int: An integer, the IP address. | 1347 ip_int: An integer, the IP address. |
| 1431 | 1348 |
| 1432 Returns: | 1349 Returns: |
| 1433 A string, the hexadecimal representation of the address. | 1350 A string, the hexadecimal representation of the address. |
| 1434 | 1351 |
| 1435 Raises: | 1352 Raises: |
| 1436 ValueError: The address is bigger than 128 bits of all ones. | 1353 ValueError: The address is bigger than 128 bits of all ones. |
| 1437 | 1354 |
| 1438 """ | 1355 """ |
| 1439 if not ip_int and ip_int != 0: | 1356 if not ip_int and ip_int != 0: |
| 1440 ip_int = self.ip | 1357 ip_int = int(self._ip) |
| 1441 | 1358 |
| 1442 if ip_int > self._ALL_ONES: | 1359 if ip_int > self._ALL_ONES: |
| 1443 raise ValueError('IPv6 address is too large') | 1360 raise ValueError('IPv6 address is too large') |
| 1444 | 1361 |
| 1445 hex_str = '%032x' % ip_int | 1362 hex_str = '%032x' % ip_int |
| 1446 hextets = [] | 1363 hextets = [] |
| 1447 for x in range(0, 32, 4): | 1364 for x in range(0, 32, 4): |
| 1448 hextets.append('%x' % int(hex_str[x:x+4], 16)) | 1365 hextets.append('%x' % int(hex_str[x:x+4], 16)) |
| 1449 | 1366 |
| 1450 hextets = self._compress_hextets(hextets) | 1367 hextets = self._compress_hextets(hextets) |
| 1451 return ':'.join(hextets) | 1368 return ':'.join(hextets) |
| 1452 | 1369 |
| 1453 @property | 1370 def _explode_shorthand_ip_string(self, ip_str=None): |
| 1454 def netmask_ext(self): | 1371 """Expand a shortened IPv6 address. |
| 1455 """IPv6 extended netmask. | 1372 |
| 1456 | 1373 Args: |
| 1457 We don't deal with netmasks in IPv6 like we do in IPv4. This is | 1374 ip_str: A string, the IPv6 address. |
| 1458 here strictly for IPv4 compatibility. We simply return the | 1375 |
| 1459 prefix length. | 1376 Returns: |
| 1460 | 1377 A string, the expanded IPv6 address. |
| 1461 Returns: | 1378 |
| 1462 An integer. | 1379 """ |
| 1463 | 1380 if not ip_str: |
| 1464 """ | 1381 ip_str = str(self) |
| 1465 return self.prefixlen | 1382 |
| 1383 if self._is_shorthand_ip(ip_str): | |
| 1384 new_ip = [] | |
| 1385 hextet = ip_str.split('::') | |
| 1386 sep = len(hextet[0].split(':')) + len(hextet[1].split(':')) | |
| 1387 new_ip = hextet[0].split(':') | |
| 1388 | |
| 1389 for _ in xrange(8 - sep): | |
| 1390 new_ip.append('0000') | |
| 1391 new_ip += hextet[1].split(':') | |
| 1392 | |
| 1393 # Now need to make sure every hextet is 4 lower case characters. | |
| 1394 # If a hextet is < 4 characters, we've got missing leading 0's. | |
| 1395 ret_ip = [] | |
| 1396 for hextet in new_ip: | |
| 1397 ret_ip.append(('0' * (4 - len(hextet)) + hextet).lower()) | |
| 1398 return ':'.join(ret_ip) | |
| 1399 # We've already got a longhand ip_str. | |
| 1400 return ip_str | |
| 1401 | |
| 1402 def _is_valid_ip(self, ip_str): | |
| 1403 """Ensure we have a valid IPv6 address. | |
| 1404 | |
| 1405 Probably not as exhaustive as it should be. | |
| 1406 | |
| 1407 Args: | |
| 1408 ip_str: A string, the IPv6 address. | |
| 1409 | |
| 1410 Returns: | |
| 1411 A boolean, True if this is a valid IPv6 address. | |
| 1412 | |
| 1413 """ | |
| 1414 # We need to have at least one ':'. | |
| 1415 if ':' not in ip_str: | |
| 1416 return False | |
| 1417 | |
| 1418 # We can only have one '::' shortener. | |
| 1419 if ip_str.count('::') > 1: | |
| 1420 return False | |
| 1421 | |
| 1422 # '::' should be encompassed by start, digits or end. | |
| 1423 if ':::' in ip_str: | |
| 1424 return False | |
| 1425 | |
| 1426 # A single colon can neither start nor end an address. | |
| 1427 if ((ip_str.startswith(':') and not ip_str.startswith('::')) or | |
| 1428 (ip_str.endswith(':') and not ip_str.endswith('::'))): | |
| 1429 return False | |
| 1430 | |
| 1431 # If we have no concatenation, we need to have 8 fields with 7 ':'. | |
| 1432 if '::' not in ip_str and ip_str.count(':') != 7: | |
| 1433 # We might have an IPv4 mapped address. | |
| 1434 if ip_str.count('.') != 3: | |
| 1435 return False | |
| 1436 | |
| 1437 ip_str = self._explode_shorthand_ip_string(ip_str) | |
| 1438 | |
| 1439 # Now that we have that all squared away, let's check that each of the | |
| 1440 # hextets are between 0x0 and 0xFFFF. | |
| 1441 for hextet in ip_str.split(':'): | |
| 1442 if hextet.count('.') == 3: | |
| 1443 # If we have an IPv4 mapped address, the IPv4 portion has to be | |
| 1444 # at the end of the IPv6 portion. | |
| 1445 if not ip_str.split(':')[-1] == hextet: | |
| 1446 return False | |
| 1447 try: | |
| 1448 IPv4(hextet) | |
| 1449 except IPv4IpValidationError: | |
| 1450 return False | |
| 1451 elif int(hextet, 16) < 0x0 or int(hextet, 16) > 0xFF | |