Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code | Sign in
(48)

Delta Between Two Patch Sets: ipaddr.py

Issue 67107: collapse_address_list is too slow SVN Base: http://ipaddr-py.googlecode.com/svn/trunk/
Left Patch Set: removed range notation Created 6 months, 1 week ago
Right Patch Set: Fixes for comments on Patch Set 6 Created 3 months, 2 weeks ago
Use n/p to move between diff chunks; N/P to move between comments. Please Sign in to add in-line comments.
Jump to:
Left: Side by side diff | Download
Right: Side by side diff | Download
LEFTRIGHT
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
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
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
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
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
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