blob: 77c21f58d5b25a414c9ede144b6ee2b0ee6f8510 [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
266 def __hex__(self):
267 return hex(int(self))
268
269 def address_exclude(self, other):
270 """Remove an address from a larger block.
271
272 For example:
273
274 addr1 = IP('10.1.1.0/24')
275 addr2 = IP('10.1.1.0/26')
276 addr1.address_exclude(addr2) =
277 [IP('10.1.1.64/26'), IP('10.1.1.128/25')]
278
279 or IPv6:
280
281 addr1 = IP('::1/32')
282 addr2 = IP('::1/128')
283 addr1.address_exclude(addr2) = [IP('::0/128'),
284 IP('::2/127'),
285 IP('::4/126'),
286 IP('::8/125'),
287 ...
288 IP('0:0:8000::/33')]
289
290 Args:
291 other: An IP object of the same type.
292
293 Returns:
294 A sorted list of IP objects addresses which is self minus
295 other.
296
297 Raises:
298 IPTypeError: If self and other are of difffering address
299 versions.
300 IPAddressExclusionError: There was some unknown error in the
301 address exclusion process. This likely points to a bug
302 elsewhere in this code.
303 ValueError: If other is not completely contained by self.
304
305 """
306 if not self.version == other.version:
307 raise IPTypeError("%s and %s aren't of the same version" % (
308 str(self), str(other)))
309
310 if other not in self:
311 raise ValueError('%s not contained in %s' % (str(other),
312 str(self)))
313
314 ret_addrs = []
315
316 # Make sure we're comparing the network of other.
317 other = IP(other.network_ext + '/' + str(other.prefixlen))
318
319 s1, s2 = self.subnet()
320 while s1 != other and s2 != other:
321 if other in s1:
322 ret_addrs.append(s2)
323 s1, s2 = s1.subnet()
324 elif other in s2:
325 ret_addrs.append(s1)
326 s1, s2 = s2.subnet()
327 else:
328 # If we got here, there's a bug somewhere.
329 raise IPAddressExclusionError('Error performing exclusion: '
330 's1: %s s2: %s other: %s' %
331 (str(s1), str(s2), str(other)))
332 if s1 == other:
333 ret_addrs.append(s2)
334 elif s2 == other:
335 ret_addrs.append(s1)
336 else:
337 # If we got here, there's a bug somewhere.
338 raise IPAddressExclusionError('Error performing exclusion: '
339 's1: %s s2: %s other: %s' %
340 (str(s1), str(s2), str(other)))
341
342 return sorted(ret_addrs, key=BaseIP._get_networks_key)
343
344 def compare_networks(self, other):
345 """Compare two IP objects.
346
347 This is only concerned about the comparison of the integer
348 representation of the network addresses. This means that the
349 host bits aren't considered at all in this method. If you want
350 to compare host bits, you can easily enough do a
351 'HostA.ip < HostB.ip'
352
353 Args:
354 other: An IP object.
355
356 Returns:
357 If the IP versions of self and other are the same, returns:
358
359 -1 if self < other:
360 eg: IPv4('1.1.1.0/24') < IPv4('1.1.2.0/24')
361 IPv6('1080::200C:417A') < IPv6('1080::200B:417B')
362 0 if self == other
363 eg: IPv4('1.1.1.1/24') == IPv4('1.1.1.2/24')
364 IPv6('1080::200C:417A/96') == IPv6('1080::200C:417B/96')
365 1 if self > other
366 eg: IPv4('1.1.1.0/24') > IPv4('1.1.0.0/24')
367 IPv6('1080::1:200C:417A/112') >
368 IPv6('1080::0:200C:417A/112')
369
370 If the IP versions of self and other are different, returns:
371
372 -1 if self.version < other.version
373 eg: IPv4('10.0.0.1/24') < IPv6('::1/128')
374 1 if self.version > other.version
375 eg: IPv6('::1/128') > IPv4('255.255.255.0/24')
376
377 """
378 if self.version < other.version:
379 return -1
380 if self.version > other.version:
381 return 1
382 # self.version == other.version below here:
383 if self.network < other.network:
384 return -1
385 if self.network > other.network:
386 return 1
387 # self.network == other.network below here:
388 if self.netmask < other.netmask:
389 return -1
390 if self.netmask > other.netmask:
391 return 1
392 # self.network == other.network and self.netmask == other.netmask
393 return 0
394
395 def _get_networks_key(self):
396 """Network-only key function.
397
398 Returns an object that identifies this address' network and
399 netmask. This function is a suitable "key" argument for sorted()
400 and list.sort().
401
402 """
403 return (self.version, self.network, self.netmask)
404
405 prefixlen = property(
406 fget=lambda self: self._prefixlen,
407 fset=lambda self, prefixlen: self._set_prefix(prefixlen))
408
409 def __str__(self):
410 return '%s/%s' % (self._string_from_ip_int(self.ip),
411 str(self.prefixlen))
412
413 def __hash__(self):
414 return hash(self.ip ^ self.netmask)
415
416 def __contains__(self, other):
417 return self.network <= other.ip and self.broadcast >= other.broadcast
418
419 @property
420 def ip_ext(self):
421 """Dotted decimal or colon string version of the IP address."""
422 return self._string_from_ip_int(self.ip)
423
424 @property
425 def ip_ext_full(self):
426 """Canonical string version of the IP address."""
427 return self.ip_ext
428
429 @property
430 def broadcast(self):
431 """Integer representation of the broadcast address."""
432 return self.ip | self.hostmask
433
434 @property
435 def broadcast_ext(self):
436 """Dotted decimal or colon string version of the broadcast."""
437 return self._string_from_ip_int(self.broadcast)
438
439 @property
440 def hostmask(self):
441 """Integer representation of the hostmask."""
442 return self.netmask ^ self._ALL_ONES
443
444 @property
445 def hostmask_ext(self):
446 """Dotted decimal or colon string version of the hostmask."""
447 return self._string_from_ip_int(self.hostmask)
448
449 @property
450 def network(self):
451 """Integer representation of the network."""
452 return self.ip & self.netmask
453
454 @property
455 def network_ext(self):
456 """Dotted decimal or colon string version of the network."""
457 return self._string_from_ip_int(self.network)
458
459 @property
460 def netmask_ext(self):
461 """Dotted decimal or colon string version of the netmask."""
462 return self._string_from_ip_int(self.netmask)
463
464 @property
465 def numhosts(self):
466 """Number of hosts in the current subnet."""
467 return self.broadcast - self.network + 1
468
469 @property
470 def version(self):
471 raise NotImplementedError('BaseIP has no version')
472
473 def _ip_int_from_prefix(self, prefixlen=None):
474 """Turn the prefix length netmask into a int for comparison.
475
476 Args:
477 prefixlen: An integer, the prefix length.
478
479 Returns:
480 An integer.
481
482 """
483 if not prefixlen and prefixlen != 0:
484 prefixlen = self.prefixlen
485 return self._ALL_ONES ^ (self._ALL_ONES >> prefixlen)
486
487 def _prefix_from_ip_int(self, ip_int, mask=32):
488 """Return prefix length from the decimal netmask.
489
490 Args:
491 ip_int: An integer, the IP address.
492 mask: The netmask. Defaults to 32.
493
494 Returns:
495 An integer, the prefix length.
496
497 """
498 while mask:
499 if ip_int & 1 == 1:
500 break
501 ip_int >>= 1
502 mask -= 1
503
504 return mask
505
506 def _ip_string_from_prefix(self, prefixlen=None):
507 """Turn a prefix length into a dotted decimal string.
508
509 Args:
510 prefixlen: An integer, the netmask prefix length.
511
512 Returns:
513 A string, the dotted decimal netmask string.
514
515 """
516 if not prefixlen:
517 prefixlen = self.prefixlen
518 return self._string_from_ip_int(self._ip_int_from_prefix(prefixlen))
519
520
521class IPv4(BaseIP):
522
523 """This class represents and manipulates 32-bit IPv4 addresses.
524
525 Attributes: [examples for IPv4('1.2.3.4/27')]
526 .ip: 16909060
527 .ip_ext: '1.2.3.4'
528 .ip_ext_full: '1.2.3.4'
529 .network: 16909056L
530 .network_ext: '1.2.3.0'
531 .hostmask: 31L (0x1F)
532 .hostmask_ext: '0.0.0.31'
533 .broadcast: 16909087L (0x102031F)
534 .broadcast_ext: '1.2.3.31'
535 .netmask: 4294967040L (0xFFFFFFE0)
536 .netmask_ext: '255.255.255.224'
537 .prefixlen: 27
538
539 """
540
541 # Equivalent to 255.255.255.255 or 32 bits of 1's.
542 _ALL_ONES = 0xffffffff
543
544 def __init__(self, ipaddr):
545 """Instantiate a new IPv4 object.
546
547 Args:
548 ipaddr: A string or integer representing the IP [& network].
549 '192.168.1.1/32'
550 '192.168.1.1/255.255.255.255'
551 '192.168.1.1/0.0.0.255'
552 '192.168.1.1'
553 are all functionally the same in IPv4. That is to say,
554 failing to provide a subnetmask will create an object with
555 a mask of /32. A netmask of '255.255.255.255' is assumed
556 to be /32 and '0.0.0.0' is assumed to be /0, even though
557 other netmasks can be expressed both as host- and
558 net-masks. (255.0.0.0 == 0.255.255.255)
559
560 Additionally, an integer can be passed, so
561 IPv4('192.168.1.1') == IPv4(3232235777).
562 or, more generally
563 IPv4(IPv4('192.168.1.1').ip) == IPv4('192.168.1.1')
564
565 Raises:
566 IPv4IpValidationError: If ipaddr isn't a valid IPv4 address.
567 IPv4NetmaskValidationError: If the netmask isn't valid for
568 an IPv4 address.
569
570 """
571 BaseIP.__init__(self)
572 self._version = 4
573
574 # Efficient constructor from integer.
575 if isinstance(ipaddr, int) or isinstance(ipaddr, int):
576 self.ip = ipaddr
577 self._prefixlen = 32
578 self.netmask = self._ALL_ONES
579 if ipaddr < 0 or ipaddr > self._ALL_ONES:
580 raise IPv4IpValidationError(ipaddr)
581 return
582
Benjamin Petersonb83819f2009-05-02 18:10:37 +0000583 if isinstance(ipaddr, bytes) and len(ipaddr) == 4:
584 self.ip = struct.unpack('!I', ipaddr)[0]
585 self._prefixlen = 32
586 self.netmask = self._ALL_ONES
587 return
Gregory P. Smithe54dff52009-05-01 22:13:48 +0000588
589 # Assume input argument to be string or any object representation
590 # which converts into a formatted IP prefix string.
591 addr = str(ipaddr).split('/')
592
593 if len(addr) > 2:
594 raise IPv4IpValidationError(ipaddr)
595
596 if not self._is_valid_ip(addr[0]):
597 raise IPv4IpValidationError(addr[0])
598
599 self.ip = self._ip_int_from_string(addr[0])
600
601 if len(addr) == 2:
602 mask = addr[1].split('.')
603 if len(mask) == 4:
604 # We have dotted decimal netmask.
605 if not self._is_valid_netmask(addr[1]):
606 raise IPv4NetmaskValidationError(addr[1])
607 if self._is_hostmask(addr[1]):
608 self.netmask = (
609 self._ip_int_from_string(addr[1]) ^ self._ALL_ONES)
610 else:
611 self.netmask = self._ip_int_from_string(addr[1])
612 self._prefixlen = self._prefix_from_ip_int(self.netmask)
613 else:
614 # We have a netmask in prefix length form.
615 if not self._is_valid_netmask(addr[1]):
616 raise IPv4NetmaskValidationError(addr[1])
617 self._prefixlen = int(addr[1])
618 self.netmask = self._ip_int_from_prefix(self._prefixlen)
619 else:
620 self._prefixlen = 32
621 self.netmask = self._ip_int_from_prefix(self._prefixlen)
622
623 def _set_prefix(self, prefixlen):
624 """Change the prefix length.
625
626 Args:
627 prefixlen: An integer, the new prefix length.
628
629 Raises:
630 IPv4NetmaskValidationError: If prefixlen is out of bounds.
631
632 """
633 if not 0 <= prefixlen <= 32:
634 raise IPv4NetmaskValidationError(prefixlen)
635 self._prefixlen = prefixlen
636 self.netmask = self._ip_int_from_prefix(self._prefixlen)
637
638 def subnet(self, prefixlen_diff=1):
639 """The subnets which join to make the current subnet.
640
641 In the case that self contains only one IP
642 (self._prefixlen == 32), return a list with just ourself.
643
644 Args:
645 prefixlen_diff: An integer, the amount the prefix length
646 should be increased by. Given a /24 network and a
647 prefixlen_diff of 3, for example, 8 subnets of size /27
648 will be returned. The default value of 1 splits the
649 current network into two halves.
650
651 Returns:
652 A list of IPv4 objects.
653
654 Raises:
655 PrefixlenDiffInvalidError: The prefixlen_diff is too small
656 or too large.
657
658 """
659 if self._prefixlen == 32:
660 return [self]
661
662 if prefixlen_diff < 0:
663 raise PrefixlenDiffInvalidError('prefix length diff must be > 0')
664 new_prefixlen = self.prefixlen + prefixlen_diff
665
666 if not self._is_valid_netmask(str(new_prefixlen)):
667 raise PrefixlenDiffInvalidError(
668 'prefix length diff %d is invalid for netblock %s' % (
669 new_prefixlen, str(self)))
670
671 first = IPv4(
672 self._string_from_ip_int(self.network) + '/' +
673 str(self._prefixlen + prefixlen_diff))
674 subnets = [first]
675 current = first
676 while True:
677 broadcast = current.broadcast
678 if broadcast == self.broadcast:
679 break
680 current = IPv4(self._string_from_ip_int(broadcast + 1) + '/' +
681 str(new_prefixlen))
682 subnets.append(current)
683
684 return subnets
685
686 def supernet(self, prefixlen_diff=1):
687 """The supernet containing the current network.
688
689 Args:
690 prefixlen_diff: An integer, the amount the prefix length of
691 the network should be decreased by. For example, given a
692 /24 network and a prefixlen_diff of 3, a supernet with a
693 /21 netmask is returned.
694
695 Returns:
696 An IPv4 object.
697
698 Raises:
699 PrefixlenDiffInvalidError: If
700 self.prefixlen - prefixlen_diff < 0. I.e., you have a
701 negative prefix length.
702
703 """
704 if self.prefixlen == 0:
705 return self
706 if self.prefixlen - prefixlen_diff < 0:
707 raise PrefixlenDiffInvalidError(
708 'current prefixlen is %d, cannot have a prefixlen_diff of %d' %
709 (self.prefixlen, prefixlen_diff))
710 return IPv4(self.ip_ext + '/' + str(self.prefixlen - prefixlen_diff))
711
712 @property
713 def is_private(self):
714 """Test if this address is allocated for private networks.
715
716 Returns:
717 A boolean, True if the address is reserved per RFC 1918.
718
719 """
720 return (self in IPv4('10.0.0.0/8') or
721 self in IPv4('172.16.0.0/12') or
722 self in IPv4('192.168.0.0/16'))
723
724 @property
725 def is_multicast(self):
726 """Test if the address is reserved for multicast use.
727
728 Returns:
729 A boolean, True if the address is multicast.
730 See RFC 3171 for details.
731
732 """
733 return self in IPv4('224.0.0.0/4')
734
735 @property
736 def is_loopback(self):
737 """Test if the address is a loopback adddress.
738
739 Returns:
740 A boolean, True if the address is a loopback per RFC 3330.
741
742 """
743 return self in IPv4('127.0.0.0/8')
744
745 @property
746 def is_link_local(self):
747 """Test if the address is reserved for link-local.
748
749 Returns:
750 A boolean, True if the address is link-local per RFC 3927.
751
752 """
753 return self in IPv4('169.254.0.0/16')
754
755 @property
756 def version(self):
757 return self._version
758
759 @property
760 def packed(self):
761 """The binary representation of this address."""
762 return struct.pack('!I', self.ip)
763
764 def _is_hostmask(self, ip_str):
765 """Test if the IP string is a hostmask (rather than a netmask).
766
767 Args:
768 ip_str: A string, the potential hostmask.
769
770 Returns:
771 A boolean, True if the IP string is a hostmask.
772
773 """
774 parts = [int(x) for x in ip_str.split('.')]
775 if parts[0] < parts[-1]:
776 return True
777 return False
778
779 def _ip_int_from_string(self, ip_str):
780 """Turn the given IP string into an integer for comparison.
781
782 Args:
783 ip_str: A string, the IP address.
784
785 Returns:
786 The IP address as an integer.
787
788 """
789 packed_ip = 0
790 for oc in ip_str.split('.'):
791 packed_ip = (packed_ip << 8) | int(oc)
792 return packed_ip
793
794 def _string_from_ip_int(self, ip_int):
795 """Turns a 32-bit integer into dotted decimal notation.
796
797 Args:
798 ip_int: An integer, the IP address.
799
800 Returns:
801 The IP address as a string in dotted decimal notation.
802
803 """
804 octets = []
805 for _ in range(4):
806 octets.insert(0, str(ip_int & 0xFF))
807 ip_int >>= 8
808 return '.'.join(octets)
809
810 def _is_valid_ip(self, ip_str):
811 """Validate the dotted decimal notation IP/netmask string.
812
813 Args:
814 ip_str: A string, the IP address.
815
816 Returns:
817 A boolean, True if the string is a valid dotted decimal IP
818 string.
819
820 """
821 octets = ip_str.split('.')
822 if len(octets) == 1:
823 # We have an integer rather than a dotted decimal IP.
824 try:
825 return int(ip_str) >= 0 and int(ip_str) <= self._ALL_ONES
826 except ValueError:
827 return False
828
829 if len(octets) != 4:
830 return False
831
832 for octet in octets:
833 try:
834 if not 0 <= int(octet) <= 255:
835 return False
836 except ValueError:
837 return False
838 return True
839
840 def _is_valid_netmask(self, netmask):
841 """Verify that the netmask is valid.
842
843 Args:
844 netmask: A string, either a prefix or dotted decimal
845 netmask.
846
847 Returns:
848 A boolean, True if the prefix represents a valid IPv4
849 netmask.
850
851 """
852 if len(netmask.split('.')) == 4:
853 return self._is_valid_ip(netmask)
854 try:
855 netmask = int(netmask)
856 except ValueError:
857 return False
858 return 0 <= netmask <= 32
859
860
861class IPv6(BaseIP):
862
863 """This class respresents and manipulates 128-bit IPv6 addresses.
864
865 Attributes: [examples for IPv6('2001:658:22A:CAFE:200::1/64')]
866 .ip: 42540616829182469433547762482097946625L
867 .ip_ext: '2001:658:22a:cafe:200::1'
868 .ip_ext_full: '2001:0658:022a:cafe:0200:0000:0000:0001'
869 .network: 42540616829182469433403647294022090752L
870 .network_ext: '2001:658:22a:cafe::'
871 .hostmask: 18446744073709551615L
872 .hostmask_ext: '::ffff:ffff:ffff:ffff'
873 .broadcast: 42540616829182469451850391367731642367L
874 .broadcast_ext: '2001:658:22a:cafe:ffff:ffff:ffff:ffff'
875 .netmask: 340282366920938463444927863358058659840L
876 .netmask_ext: 64
877 .prefixlen: 64
878
879 """
880
881 _ALL_ONES = (2**128) - 1
882
883 def __init__(self, ipaddr):
884 """Instantiate a new IPv6 object.
885
886 Args:
887 ipaddr: A string or integer representing the IP or the IP
888 and prefix/netmask.
889 '2001:4860::/128'
890 '2001:4860:0000:0000:0000:0000:0000:0000/128'
891 '2001:4860::'
892 are all functionally the same in IPv6. That is to say,
893 failing to provide a subnetmask will create an object with
894 a mask of /128.
895
896 Additionally, an integer can be passed, so
897 IPv6('2001:4860::') ==
898 IPv6(42541956101370907050197289607612071936L).
899 or, more generally
900 IPv6(IPv6('2001:4860::').ip) == IPv6('2001:4860::')
901
902 Raises:
903 IPv6IpValidationError: If ipaddr isn't a valid IPv6 address.
904 IPv6NetmaskValidationError: If the netmask isn't valid for
905 an IPv6 address.
906
907 """
908 BaseIP.__init__(self)
909 self._version = 6
910
911 # Efficient constructor from integer.
912 if isinstance(ipaddr, int) or isinstance(ipaddr, int):
913 self.ip = ipaddr
914 self._prefixlen = 128
915 self.netmask = self._ALL_ONES
916 if ipaddr < 0 or ipaddr > self._ALL_ONES:
917 raise IPv6IpValidationError(ipaddr)
918 return
919
Benjamin Petersonb83819f2009-05-02 18:10:37 +0000920 if isinstance(ipaddr, bytes) and len(ipaddr) == 16:
921 tmp = struct.unpack('!QQ', ipaddr)
922 self.ip = (tmp[0] << 64) | tmp[1]
923 self._prefixlen = 128
924 self.netmask = self._ALL_ONES
925 return
Gregory P. Smithe54dff52009-05-01 22:13:48 +0000926
927 # Assume input argument to be string or any object representation
928 # which converts into a formatted IP prefix string.
929 addr_str = str(ipaddr)
930 if not addr_str:
931 raise IPv6IpValidationError('')
932 addr = addr_str.split('/')
933 if len(addr) > 1:
934 if self._is_valid_netmask(addr[1]):
935 self._prefixlen = int(addr[1])
936 else:
937 raise IPv6NetmaskValidationError(addr[1])
938 else:
939 self._prefixlen = 128
940
941 self.netmask = self._ip_int_from_prefix(self._prefixlen)
942
943 if not self._is_valid_ip(addr[0]):
944 raise IPv6IpValidationError(addr[0])
945
946 self.ip = self._ip_int_from_string(addr[0])
947
948 @property
949 def ip_ext_full(self):
950 """Returns the expanded version of the IPv6 string."""
951 return self._explode_shorthand_ip_string(self.ip_ext)
952
953 def _set_prefix(self, prefixlen):
954 """Change the prefix length.
955
956 Args:
957 prefixlen: An integer, the new prefix length.
958
959 Raises:
960 IPv6NetmaskValidationError: If prefixlen is out of bounds.
961
962 """
963 if not 0 <= prefixlen <= 128:
964 raise IPv6NetmaskValidationError(prefixlen)
965 self._prefixlen = prefixlen
966 self.netmask = self._ip_int_from_prefix(self.prefixlen)
967
968 def subnet(self, prefixlen_diff=1):
969 """The subnets which join to make the current subnet.
970
971 In the case that self contains only one IP
972 (self._prefixlen == 128), return a list with just ourself.
973
974 Args:
975 prefixlen_diff: An integer, the amount the prefix length
976 should be increased by.
977
978 Returns:
979 A list of IPv6 objects.
980
981 Raises:
982 PrefixlenDiffInvalidError: The prefixlen_diff is too small
983 or too large.
984
985 """
986 # Preserve original functionality (return [self] if
987 # self.prefixlen == 128).
988 if self.prefixlen == 128:
989 return [self]
990
991 if prefixlen_diff < 0:
992 raise PrefixlenDiffInvalidError('Prefix length diff must be > 0')
993 new_prefixlen = self.prefixlen + prefixlen_diff
994 if not self._is_valid_netmask(str(new_prefixlen)):
995 raise PrefixlenDiffInvalidError(
996 'Prefix length diff %d is invalid for netblock %s' % (
997 new_prefixlen, str(self)))
998 first = IPv6(
999 self._string_from_ip_int(self.network) + '/' +
1000 str(self._prefixlen + prefixlen_diff))
1001 subnets = [first]
1002 current = first
1003 while True:
1004 broadcast = current.broadcast
1005 if current.broadcast == self.broadcast:
1006 break
1007 current = IPv6(self._string_from_ip_int(broadcast + 1) + '/' +
1008 str(new_prefixlen))
1009 subnets.append(current)
1010
1011 return subnets
1012
1013 def supernet(self, prefixlen_diff=1):
1014 """The supernet containing the current network.
1015
1016 Args:
1017 prefixlen_diff: An integer, the amount the prefix length of the
1018 network should be decreased by. For example, given a /96
1019 network and a prefixlen_diff of 3, a supernet with a /93
1020 netmask is returned.
1021
1022 Returns:
1023 An IPv6 object.
1024
1025 Raises:
1026 PrefixlenDiffInvalidError: If
1027 self._prefixlen - prefixlen_diff < 0. I.e., you have a
1028 negative prefix length.
1029
1030 """
1031 if self.prefixlen == 0:
1032 return self
1033 if self.prefixlen - prefixlen_diff < 0:
1034 raise PrefixlenDiffInvalidError(
1035 'current prefixlen is %d, cannot have a prefixlen_diff of %d' %
1036 (self.prefixlen, prefixlen_diff))
1037 return IPv6(self.ip_ext + '/' + str(self.prefixlen - prefixlen_diff))
1038
1039 @property
1040 def is_multicast(self):
1041 """Test if the address is reserved for multicast use.
1042
1043 Returns:
1044 A boolean, True if the address is a multicast address.
1045 See RFC 2373 2.7 for details.
1046
1047 """
1048 return self in IPv6('ff00::/8')
1049
1050 @property
1051 def is_unspecified(self):
1052 """Test if the address is unspecified.
1053
1054 Returns:
1055 A boolean, True if this is the unspecified address as defined in
1056 RFC 2373 2.5.2.
1057
1058 """
1059 return self == IPv6('::')
1060
1061 @property
1062 def is_loopback(self):
1063 """Test if the address is a loopback adddress.
1064
1065 Returns:
1066 A boolean, True if the address is a loopback address as defined in
1067 RFC 2373 2.5.3.
1068
1069 """
1070 return self == IPv6('::1')
1071
1072 @property
1073 def is_link_local(self):
1074 """Test if the address is reserved for link-local.
1075
1076 Returns:
1077 A boolean, True if the address is reserved per RFC 4291.
1078
1079 """
1080 return self in IPv6('fe80::/10')
1081
1082 @property
1083 def is_site_local(self):
1084 """Test if the address is reserved for site-local.
1085
1086 Note that the site-local address space has been deprecated by RFC 3879.
1087 Use is_private to test if this address is in the space of unique local
1088 addresses as defined by RFC 4193.
1089
1090 Returns:
1091 A boolean, True if the address is reserved per RFC 3513 2.5.6.
1092
1093 """
1094 return self in IPv6('fec0::/10')
1095
1096 @property
1097 def is_private(self):
1098 """Test if this address is allocated for private networks.
1099
1100 Returns:
1101 A boolean, True if the address is reserved per RFC 4193.
1102
1103 """
1104 return self in IPv6('fc00::/7')
1105
1106 @property
1107 def version(self):
1108 return self._version
1109
1110 @property
1111 def packed(self):
1112 """The binary representation of this address."""
1113 return struct.pack('!QQ', self.ip >> 64, self.ip & (2**64 - 1))
1114
1115 def _is_shorthand_ip(self, ip_str=None):
1116 """Determine if the address is shortened.
1117
1118 Args:
1119 ip_str: A string, the IPv6 address.
1120
1121 Returns:
1122 A boolean, True if the address is shortened.
1123
1124 """
1125 if ip_str.count('::') == 1:
1126 return True
1127 return False
1128
1129 def _explode_shorthand_ip_string(self, ip_str):
1130 """Expand a shortened IPv6 address.
1131
1132 Args:
1133 ip_str: A string, the IPv6 address.
1134
1135 Returns:
1136 A string, the expanded IPv6 address.
1137
1138 """
1139 if self._is_shorthand_ip(ip_str):
1140 new_ip = []
1141 hextet = ip_str.split('::')
1142 sep = len(hextet[0].split(':')) + len(hextet[1].split(':'))
1143 new_ip = hextet[0].split(':')
1144
1145 for _ in range(8 - sep):
1146 new_ip.append('0000')
1147 new_ip += hextet[1].split(':')
1148
1149 # Now need to make sure every hextet is 4 lower case characters.
1150 # If a hextet is < 4 characters, we've got missing leading 0's.
1151 ret_ip = []
1152 for hextet in new_ip:
1153 ret_ip.append(('0' * (4 - len(hextet)) + hextet).lower())
1154 return ':'.join(ret_ip)
1155 # We've already got a longhand ip_str.
1156 return ip_str
1157
1158 def _is_valid_ip(self, ip_str=None):
1159 """Ensure we have a valid IPv6 address.
1160
1161 Probably not as exhaustive as it should be.
1162
1163 Args:
1164 ip_str: A string, the IPv6 address.
1165
1166 Returns:
1167 A boolean, True if this is a valid IPv6 address.
1168
1169 """
1170 if not ip_str:
1171 ip_str = self.ip_ext
1172
1173 # We need to have at least one ':'.
1174 if ':' not in ip_str:
1175 return False
1176
1177 # We can only have one '::' shortener.
1178 if ip_str.count('::') > 1:
1179 return False
1180
1181 # '::' should be encompassed by start, digits or end.
1182 if ':::' in ip_str:
1183 return False
1184
1185 # A single colon can neither start nor end an address.
1186 if ((ip_str.startswith(':') and not ip_str.startswith('::')) or
1187 (ip_str.endswith(':') and not ip_str.endswith('::'))):
1188 return False
1189
1190 # If we have no concatenation, we need to have 8 fields with 7 ':'.
1191 if '::' not in ip_str and ip_str.count(':') != 7:
1192 # We might have an IPv4 mapped address.
1193 if ip_str.count('.') != 3:
1194 return False
1195
1196 ip_str = self._explode_shorthand_ip_string(ip_str)
1197
1198 # Now that we have that all squared away, let's check that each of the
1199 # hextets are between 0x0 and 0xFFFF.
1200 for hextet in ip_str.split(':'):
1201 if hextet.count('.') == 3:
1202 # If we have an IPv4 mapped address, the IPv4 portion has to be
1203 # at the end of the IPv6 portion.
1204 if not ip_str.split(':')[-1] == hextet:
1205 return False
1206 try:
1207 IPv4(hextet)
1208 except IPv4IpValidationError:
1209 return False
1210 elif int(hextet, 16) < 0x0 or int(hextet, 16) > 0xFFFF:
1211 return False
1212 return True
1213
1214 def _is_valid_netmask(self, prefixlen):
1215 """Verify that the netmask/prefixlen is valid.
1216
1217 Args:
1218 prefixlen: A string, the netmask in prefix length format.
1219
1220 Returns:
1221 A boolean, True if the prefix represents a valid IPv6
1222 netmask.
1223
1224 """
1225 try:
1226 prefixlen = int(prefixlen)
1227 except ValueError:
1228 return False
1229 return 0 <= prefixlen <= 128
1230
1231 def _ip_int_from_string(self, ip_str=None):
1232 """Turn an IPv6 address into an integer.
1233
1234 Args:
1235 ip_str: A string, the IPv6 address.
1236
1237 Returns:
1238 A long, the IPv6 address.
1239
1240 """
1241 if not ip_str:
1242 ip_str = self.ip_ext
1243
1244 ip_int = 0
1245
1246 fields = self._explode_shorthand_ip_string(ip_str).split(':')
1247
1248 # Do we have an IPv4 mapped (::ffff:a.b.c.d) or compact (::a.b.c.d)
1249 # address?
1250 if fields[-1].count('.') == 3:
1251 ipv4_string = fields.pop()
1252 ipv4_int = IPv4(ipv4_string).ip
1253 octets = []
1254 for _ in range(2):
1255 octets.append(hex(ipv4_int & 0xFFFF).lstrip('0x').rstrip('L'))
1256 ipv4_int >>= 16
1257 fields.extend(reversed(octets))
1258
1259 for field in fields:
1260 ip_int = (ip_int << 16) + int(field, 16)
1261
1262 return ip_int
1263
1264 def _compress_hextets(self, hextets):
1265 """Compresses a list of hextets.
1266
1267 Compresses a list of strings, replacing the longest continuous
1268 sequence of "0" in the list with "" and adding empty strings at
1269 the beginning or at the end of the string such that subsequently
1270 calling ":".join(hextets) will produce the compressed version of
1271 the IPv6 address.
1272
1273 Args:
1274 hextets: A list of strings, the hextets to compress.
1275
1276 Returns:
1277 A list of strings.
1278
1279 """
1280 best_doublecolon_start = -1
1281 best_doublecolon_len = 0
1282 doublecolon_start = -1
1283 doublecolon_len = 0
1284 for index in range(len(hextets)):
1285 if hextets[index] == '0':
1286 doublecolon_len += 1
1287 if doublecolon_start == -1:
1288 # Start of a sequence of zeros.
1289 doublecolon_start = index
1290 if doublecolon_len > best_doublecolon_len:
1291 # This is the longest sequence of zeros so far.
1292 best_doublecolon_len = doublecolon_len
1293 best_doublecolon_start = doublecolon_start
1294 else:
1295 doublecolon_len = 0
1296 doublecolon_start = -1
1297
1298 if best_doublecolon_len > 1:
1299 best_doublecolon_end = (best_doublecolon_start +
1300 best_doublecolon_len)
1301 # For zeros at the end of the address.
1302 if best_doublecolon_end == len(hextets):
1303 hextets += ['']
1304 hextets[best_doublecolon_start:best_doublecolon_end] = ['']
1305 # For zeros at the beginning of the address.
1306 if best_doublecolon_start == 0:
1307 hextets = [''] + hextets
1308
1309 return hextets
1310
1311 def _string_from_ip_int(self, ip_int=None):
1312 """Turns a 128-bit integer into hexadecimal notation.
1313
1314 Args:
1315 ip_int: An integer, the IP address.
1316
1317 Returns:
1318 A string, the hexadecimal representation of the address.
1319
1320 Raises:
1321 ValueError: The address is bigger than 128 bits of all ones.
1322
1323 """
1324 if not ip_int and ip_int != 0:
1325 ip_int = self.ip
1326
1327 if ip_int > self._ALL_ONES:
1328 raise ValueError('IPv6 address is too large')
1329
1330 hex_str = '%032x' % ip_int
1331 hextets = []
1332 for x in range(0, 32, 4):
1333 hextets.append('%x' % int(hex_str[x:x+4], 16))
1334
1335 hextets = self._compress_hextets(hextets)
1336 return ':'.join(hextets)
1337
1338 @property
1339 def netmask_ext(self):
1340 """IPv6 extended netmask.
1341
1342 We don't deal with netmasks in IPv6 like we do in IPv4. This is
1343 here strictly for IPv4 compatibility. We simply return the
1344 prefix length.
1345
1346 Returns:
1347 An integer.
1348
1349 """
1350 return self.prefixlen