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