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