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