blob: e0966c6774a76cba76d2e071f2cc403e692d5ad6 [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
Gregory P. Smith75930f82009-05-03 19:38:29 +000029
Gregory P. Smithe54dff52009-05-01 22:13:48 +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. Smithe54dff52009-05-01 22:13:48 +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
Gregory P. Smithe54dff52009-05-01 22:13:48 +0000267 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. Smith75930f82009-05-03 19:38:29 +0000541 _version = 4
Gregory P. Smithe54dff52009-05-01 22:13:48 +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. Smithe54dff52009-05-01 22:13:48 +0000571
572 # Efficient constructor from integer.
Gregory P. Smith02953d22009-05-02 18:35:58 +0000573 if isinstance(ipaddr, int):
Gregory P. Smithe54dff52009-05-01 22:13:48 +0000574 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. Smith02953d22009-05-02 18:35:58 +0000581 # Constructing from a packed address
582 if isinstance(ipaddr, (bytes, bytearray)) and len(ipaddr) == 4:
Benjamin Petersonb83819f2009-05-02 18:10:37 +0000583 self.ip = struct.unpack('!I', ipaddr)[0]
584 self._prefixlen = 32
585 self.netmask = self._ALL_ONES
586 return
Gregory P. Smithe54dff52009-05-01 22:13:48 +0000587
588 # Assume input argument to be string or any object representation
589 # which converts into a formatted IP prefix string.
590 addr = str(ipaddr).split('/')
591
592 if len(addr) > 2:
593 raise IPv4IpValidationError(ipaddr)
594
595 if not self._is_valid_ip(addr[0]):
596 raise IPv4IpValidationError(addr[0])
597
598 self.ip = self._ip_int_from_string(addr[0])
599
600 if len(addr) == 2:
601 mask = addr[1].split('.')
602 if len(mask) == 4:
603 # We have dotted decimal netmask.
604 if not self._is_valid_netmask(addr[1]):
605 raise IPv4NetmaskValidationError(addr[1])
606 if self._is_hostmask(addr[1]):
607 self.netmask = (
608 self._ip_int_from_string(addr[1]) ^ self._ALL_ONES)
609 else:
610 self.netmask = self._ip_int_from_string(addr[1])
611 self._prefixlen = self._prefix_from_ip_int(self.netmask)
612 else:
613 # We have a netmask in prefix length form.
614 if not self._is_valid_netmask(addr[1]):
615 raise IPv4NetmaskValidationError(addr[1])
616 self._prefixlen = int(addr[1])
617 self.netmask = self._ip_int_from_prefix(self._prefixlen)
618 else:
619 self._prefixlen = 32
620 self.netmask = self._ip_int_from_prefix(self._prefixlen)
621
622 def _set_prefix(self, prefixlen):
623 """Change the prefix length.
624
625 Args:
626 prefixlen: An integer, the new prefix length.
627
628 Raises:
629 IPv4NetmaskValidationError: If prefixlen is out of bounds.
630
631 """
632 if not 0 <= prefixlen <= 32:
633 raise IPv4NetmaskValidationError(prefixlen)
634 self._prefixlen = prefixlen
635 self.netmask = self._ip_int_from_prefix(self._prefixlen)
636
637 def subnet(self, prefixlen_diff=1):
638 """The subnets which join to make the current subnet.
639
640 In the case that self contains only one IP
641 (self._prefixlen == 32), return a list with just ourself.
642
643 Args:
644 prefixlen_diff: An integer, the amount the prefix length
645 should be increased by. Given a /24 network and a
646 prefixlen_diff of 3, for example, 8 subnets of size /27
647 will be returned. The default value of 1 splits the
648 current network into two halves.
649
650 Returns:
651 A list of IPv4 objects.
652
653 Raises:
654 PrefixlenDiffInvalidError: The prefixlen_diff is too small
655 or too large.
656
657 """
658 if self._prefixlen == 32:
659 return [self]
660
661 if prefixlen_diff < 0:
662 raise PrefixlenDiffInvalidError('prefix length diff must be > 0')
663 new_prefixlen = self.prefixlen + prefixlen_diff
664
665 if not self._is_valid_netmask(str(new_prefixlen)):
666 raise PrefixlenDiffInvalidError(
667 'prefix length diff %d is invalid for netblock %s' % (
668 new_prefixlen, str(self)))
669
670 first = IPv4(
671 self._string_from_ip_int(self.network) + '/' +
672 str(self._prefixlen + prefixlen_diff))
673 subnets = [first]
674 current = first
675 while True:
676 broadcast = current.broadcast
677 if broadcast == self.broadcast:
678 break
679 current = IPv4(self._string_from_ip_int(broadcast + 1) + '/' +
680 str(new_prefixlen))
681 subnets.append(current)
682
683 return subnets
684
685 def supernet(self, prefixlen_diff=1):
686 """The supernet containing the current network.
687
688 Args:
689 prefixlen_diff: An integer, the amount the prefix length of
690 the network should be decreased by. For example, given a
691 /24 network and a prefixlen_diff of 3, a supernet with a
692 /21 netmask is returned.
693
694 Returns:
695 An IPv4 object.
696
697 Raises:
698 PrefixlenDiffInvalidError: If
699 self.prefixlen - prefixlen_diff < 0. I.e., you have a
700 negative prefix length.
701
702 """
703 if self.prefixlen == 0:
704 return self
705 if self.prefixlen - prefixlen_diff < 0:
706 raise PrefixlenDiffInvalidError(
707 'current prefixlen is %d, cannot have a prefixlen_diff of %d' %
708 (self.prefixlen, prefixlen_diff))
709 return IPv4(self.ip_ext + '/' + str(self.prefixlen - prefixlen_diff))
710
711 @property
712 def is_private(self):
713 """Test if this address is allocated for private networks.
714
715 Returns:
716 A boolean, True if the address is reserved per RFC 1918.
717
718 """
Gregory P. Smith75930f82009-05-03 19:38:29 +0000719 for network in _IPV4_RFC1918_NETWORKS:
720 if self in network:
721 return True
722 return False
Gregory P. Smithe54dff52009-05-01 22:13:48 +0000723
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 """
Gregory P. Smith75930f82009-05-03 19:38:29 +0000733 return self in _IPV4_RFC3171_MULTICAST
Gregory P. Smithe54dff52009-05-01 22:13:48 +0000734
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 """
Gregory P. Smith75930f82009-05-03 19:38:29 +0000743 return self in _IPV4_RFC3330_LOOPBACK
Gregory P. Smithe54dff52009-05-01 22:13:48 +0000744
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 """
Gregory P. Smith75930f82009-05-03 19:38:29 +0000753 return self in _IPV4_RFC3927_LINK_LOCAL
Gregory P. Smithe54dff52009-05-01 22:13:48 +0000754
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
Gregory P. Smith75930f82009-05-03 19:38:29 +0000882 _version = 6
Gregory P. Smithe54dff52009-05-01 22:13:48 +0000883
884 def __init__(self, ipaddr):
885 """Instantiate a new IPv6 object.
886
887 Args:
888 ipaddr: A string or integer representing the IP or the IP
889 and prefix/netmask.
890 '2001:4860::/128'
891 '2001:4860:0000:0000:0000:0000:0000:0000/128'
892 '2001:4860::'
893 are all functionally the same in IPv6. That is to say,
894 failing to provide a subnetmask will create an object with
895 a mask of /128.
896
897 Additionally, an integer can be passed, so
898 IPv6('2001:4860::') ==
899 IPv6(42541956101370907050197289607612071936L).
900 or, more generally
901 IPv6(IPv6('2001:4860::').ip) == IPv6('2001:4860::')
902
903 Raises:
904 IPv6IpValidationError: If ipaddr isn't a valid IPv6 address.
905 IPv6NetmaskValidationError: If the netmask isn't valid for
906 an IPv6 address.
907
908 """
909 BaseIP.__init__(self)
Gregory P. Smithe54dff52009-05-01 22:13:48 +0000910
911 # Efficient constructor from integer.
Gregory P. Smith02953d22009-05-02 18:35:58 +0000912 if isinstance(ipaddr, int):
Gregory P. Smithe54dff52009-05-01 22:13:48 +0000913 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
Gregory P. Smith02953d22009-05-02 18:35:58 +0000920 # Constructing from a packed address
921 if isinstance(ipaddr, (bytes, bytearray)) and len(ipaddr) == 16:
Benjamin Petersonb83819f2009-05-02 18:10:37 +0000922 tmp = struct.unpack('!QQ', ipaddr)
923 self.ip = (tmp[0] << 64) | tmp[1]
924 self._prefixlen = 128
925 self.netmask = self._ALL_ONES
926 return
Gregory P. Smithe54dff52009-05-01 22:13:48 +0000927
928 # Assume input argument to be string or any object representation
929 # which converts into a formatted IP prefix string.
930 addr_str = str(ipaddr)
931 if not addr_str:
932 raise IPv6IpValidationError('')
933 addr = addr_str.split('/')
934 if len(addr) > 1:
935 if self._is_valid_netmask(addr[1]):
936 self._prefixlen = int(addr[1])
937 else:
938 raise IPv6NetmaskValidationError(addr[1])
939 else:
940 self._prefixlen = 128
941
942 self.netmask = self._ip_int_from_prefix(self._prefixlen)
943
944 if not self._is_valid_ip(addr[0]):
945 raise IPv6IpValidationError(addr[0])
946
947 self.ip = self._ip_int_from_string(addr[0])
948
949 @property
950 def ip_ext_full(self):
951 """Returns the expanded version of the IPv6 string."""
952 return self._explode_shorthand_ip_string(self.ip_ext)
953
954 def _set_prefix(self, prefixlen):
955 """Change the prefix length.
956
957 Args:
958 prefixlen: An integer, the new prefix length.
959
960 Raises:
961 IPv6NetmaskValidationError: If prefixlen is out of bounds.
962
963 """
964 if not 0 <= prefixlen <= 128:
965 raise IPv6NetmaskValidationError(prefixlen)
966 self._prefixlen = prefixlen
967 self.netmask = self._ip_int_from_prefix(self.prefixlen)
968
969 def subnet(self, prefixlen_diff=1):
970 """The subnets which join to make the current subnet.
971
972 In the case that self contains only one IP
973 (self._prefixlen == 128), return a list with just ourself.
974
975 Args:
976 prefixlen_diff: An integer, the amount the prefix length
977 should be increased by.
978
979 Returns:
980 A list of IPv6 objects.
981
982 Raises:
983 PrefixlenDiffInvalidError: The prefixlen_diff is too small
984 or too large.
985
986 """
987 # Preserve original functionality (return [self] if
988 # self.prefixlen == 128).
989 if self.prefixlen == 128:
990 return [self]
991
992 if prefixlen_diff < 0:
993 raise PrefixlenDiffInvalidError('Prefix length diff must be > 0')
994 new_prefixlen = self.prefixlen + prefixlen_diff
995 if not self._is_valid_netmask(str(new_prefixlen)):
996 raise PrefixlenDiffInvalidError(
997 'Prefix length diff %d is invalid for netblock %s' % (
998 new_prefixlen, str(self)))
999 first = IPv6(
1000 self._string_from_ip_int(self.network) + '/' +
1001 str(self._prefixlen + prefixlen_diff))
1002 subnets = [first]
1003 current = first
1004 while True:
1005 broadcast = current.broadcast
1006 if current.broadcast == self.broadcast:
1007 break
1008 current = IPv6(self._string_from_ip_int(broadcast + 1) + '/' +
1009 str(new_prefixlen))
1010 subnets.append(current)
1011
1012 return subnets
1013
1014 def supernet(self, prefixlen_diff=1):
1015 """The supernet containing the current network.
1016
1017 Args:
1018 prefixlen_diff: An integer, the amount the prefix length of the
1019 network should be decreased by. For example, given a /96
1020 network and a prefixlen_diff of 3, a supernet with a /93
1021 netmask is returned.
1022
1023 Returns:
1024 An IPv6 object.
1025
1026 Raises:
1027 PrefixlenDiffInvalidError: If
1028 self._prefixlen - prefixlen_diff < 0. I.e., you have a
1029 negative prefix length.
1030
1031 """
1032 if self.prefixlen == 0:
1033 return self
1034 if self.prefixlen - prefixlen_diff < 0:
1035 raise PrefixlenDiffInvalidError(
1036 'current prefixlen is %d, cannot have a prefixlen_diff of %d' %
1037 (self.prefixlen, prefixlen_diff))
1038 return IPv6(self.ip_ext + '/' + str(self.prefixlen - prefixlen_diff))
1039
1040 @property
1041 def is_multicast(self):
1042 """Test if the address is reserved for multicast use.
1043
1044 Returns:
1045 A boolean, True if the address is a multicast address.
1046 See RFC 2373 2.7 for details.
1047
1048 """
Gregory P. Smith75930f82009-05-03 19:38:29 +00001049 return self in _IPV6_RFC2373_MULTICAST
Gregory P. Smithe54dff52009-05-01 22:13:48 +00001050
1051 @property
1052 def is_unspecified(self):
1053 """Test if the address is unspecified.
1054
1055 Returns:
1056 A boolean, True if this is the unspecified address as defined in
1057 RFC 2373 2.5.2.
1058
1059 """
Gregory P. Smith75930f82009-05-03 19:38:29 +00001060 return self == _IPV6_RFC2373_UNSPECIFIED
Gregory P. Smithe54dff52009-05-01 22:13:48 +00001061
1062 @property
1063 def is_loopback(self):
1064 """Test if the address is a loopback adddress.
1065
1066 Returns:
1067 A boolean, True if the address is a loopback address as defined in
1068 RFC 2373 2.5.3.
1069
1070 """
Gregory P. Smith75930f82009-05-03 19:38:29 +00001071 return self == _IPV6_RFC2373_LOOPBACK
Gregory P. Smithe54dff52009-05-01 22:13:48 +00001072
1073 @property
1074 def is_link_local(self):
1075 """Test if the address is reserved for link-local.
1076
1077 Returns:
1078 A boolean, True if the address is reserved per RFC 4291.
1079
1080 """
Gregory P. Smith75930f82009-05-03 19:38:29 +00001081 return self in _IPV6_RFC4291_LINK_LOCAL
Gregory P. Smithe54dff52009-05-01 22:13:48 +00001082
1083 @property
1084 def is_site_local(self):
1085 """Test if the address is reserved for site-local.
1086
1087 Note that the site-local address space has been deprecated by RFC 3879.
1088 Use is_private to test if this address is in the space of unique local
1089 addresses as defined by RFC 4193.
1090
1091 Returns:
1092 A boolean, True if the address is reserved per RFC 3513 2.5.6.
1093
1094 """
Gregory P. Smith75930f82009-05-03 19:38:29 +00001095 return self in _IPV6_RFC3513_SITE_LOCAL
Gregory P. Smithe54dff52009-05-01 22:13:48 +00001096
1097 @property
1098 def is_private(self):
1099 """Test if this address is allocated for private networks.
1100
1101 Returns:
1102 A boolean, True if the address is reserved per RFC 4193.
1103
1104 """
Gregory P. Smith75930f82009-05-03 19:38:29 +00001105 return self in _IPV6_RFC4193_PRIVATE
Gregory P. Smithe54dff52009-05-01 22:13:48 +00001106
1107 @property
1108 def version(self):
1109 return self._version
1110
1111 @property
1112 def packed(self):
1113 """The binary representation of this address."""
1114 return struct.pack('!QQ', self.ip >> 64, self.ip & (2**64 - 1))
1115
1116 def _is_shorthand_ip(self, ip_str=None):
1117 """Determine if the address is shortened.
1118
1119 Args:
1120 ip_str: A string, the IPv6 address.
1121
1122 Returns:
1123 A boolean, True if the address is shortened.
1124
1125 """
1126 if ip_str.count('::') == 1:
1127 return True
1128 return False
1129
1130 def _explode_shorthand_ip_string(self, ip_str):
1131 """Expand a shortened IPv6 address.
1132
1133 Args:
1134 ip_str: A string, the IPv6 address.
1135
1136 Returns:
1137 A string, the expanded IPv6 address.
1138
1139 """
1140 if self._is_shorthand_ip(ip_str):
1141 new_ip = []
1142 hextet = ip_str.split('::')
1143 sep = len(hextet[0].split(':')) + len(hextet[1].split(':'))
1144 new_ip = hextet[0].split(':')
1145
1146 for _ in range(8 - sep):
1147 new_ip.append('0000')
1148 new_ip += hextet[1].split(':')
1149
1150 # Now need to make sure every hextet is 4 lower case characters.
1151 # If a hextet is < 4 characters, we've got missing leading 0's.
1152 ret_ip = []
1153 for hextet in new_ip:
1154 ret_ip.append(('0' * (4 - len(hextet)) + hextet).lower())
1155 return ':'.join(ret_ip)
1156 # We've already got a longhand ip_str.
1157 return ip_str
1158
1159 def _is_valid_ip(self, ip_str=None):
1160 """Ensure we have a valid IPv6 address.
1161
1162 Probably not as exhaustive as it should be.
1163
1164 Args:
1165 ip_str: A string, the IPv6 address.
1166
1167 Returns:
1168 A boolean, True if this is a valid IPv6 address.
1169
1170 """
1171 if not ip_str:
1172 ip_str = self.ip_ext
1173
1174 # We need to have at least one ':'.
1175 if ':' not in ip_str:
1176 return False
1177
1178 # We can only have one '::' shortener.
1179 if ip_str.count('::') > 1:
1180 return False
1181
1182 # '::' should be encompassed by start, digits or end.
1183 if ':::' in ip_str:
1184 return False
1185
1186 # A single colon can neither start nor end an address.
1187 if ((ip_str.startswith(':') and not ip_str.startswith('::')) or
1188 (ip_str.endswith(':') and not ip_str.endswith('::'))):
1189 return False
1190
1191 # If we have no concatenation, we need to have 8 fields with 7 ':'.
1192 if '::' not in ip_str and ip_str.count(':') != 7:
1193 # We might have an IPv4 mapped address.
1194 if ip_str.count('.') != 3:
1195 return False
1196
1197 ip_str = self._explode_shorthand_ip_string(ip_str)
1198
1199 # Now that we have that all squared away, let's check that each of the
1200 # hextets are between 0x0 and 0xFFFF.
1201 for hextet in ip_str.split(':'):
1202 if hextet.count('.') == 3:
1203 # If we have an IPv4 mapped address, the IPv4 portion has to be
1204 # at the end of the IPv6 portion.
1205 if not ip_str.split(':')[-1] == hextet:
1206 return False
1207 try:
1208 IPv4(hextet)
1209 except IPv4IpValidationError:
1210 return False
1211 elif int(hextet, 16) < 0x0 or int(hextet, 16) > 0xFFFF:
1212 return False
1213 return True
1214
1215 def _is_valid_netmask(self, prefixlen):
1216 """Verify that the netmask/prefixlen is valid.
1217
1218 Args:
1219 prefixlen: A string, the netmask in prefix length format.
1220
1221 Returns:
1222 A boolean, True if the prefix represents a valid IPv6
1223 netmask.
1224
1225 """
1226 try:
1227 prefixlen = int(prefixlen)
1228 except ValueError:
1229 return False
1230 return 0 <= prefixlen <= 128
1231
1232 def _ip_int_from_string(self, ip_str=None):
1233 """Turn an IPv6 address into an integer.
1234
1235 Args:
1236 ip_str: A string, the IPv6 address.
1237
1238 Returns:
1239 A long, the IPv6 address.
1240
1241 """
1242 if not ip_str:
1243 ip_str = self.ip_ext
1244
1245 ip_int = 0
1246
1247 fields = self._explode_shorthand_ip_string(ip_str).split(':')
1248
1249 # Do we have an IPv4 mapped (::ffff:a.b.c.d) or compact (::a.b.c.d)
1250 # address?
1251 if fields[-1].count('.') == 3:
1252 ipv4_string = fields.pop()
1253 ipv4_int = IPv4(ipv4_string).ip
1254 octets = []
1255 for _ in range(2):
1256 octets.append(hex(ipv4_int & 0xFFFF).lstrip('0x').rstrip('L'))
1257 ipv4_int >>= 16
1258 fields.extend(reversed(octets))
1259
1260 for field in fields:
1261 ip_int = (ip_int << 16) + int(field, 16)
1262
1263 return ip_int
1264
1265 def _compress_hextets(self, hextets):
1266 """Compresses a list of hextets.
1267
1268 Compresses a list of strings, replacing the longest continuous
1269 sequence of "0" in the list with "" and adding empty strings at
1270 the beginning or at the end of the string such that subsequently
1271 calling ":".join(hextets) will produce the compressed version of
1272 the IPv6 address.
1273
1274 Args:
1275 hextets: A list of strings, the hextets to compress.
1276
1277 Returns:
1278 A list of strings.
1279
1280 """
1281 best_doublecolon_start = -1
1282 best_doublecolon_len = 0
1283 doublecolon_start = -1
1284 doublecolon_len = 0
1285 for index in range(len(hextets)):
1286 if hextets[index] == '0':
1287 doublecolon_len += 1
1288 if doublecolon_start == -1:
1289 # Start of a sequence of zeros.
1290 doublecolon_start = index
1291 if doublecolon_len > best_doublecolon_len:
1292 # This is the longest sequence of zeros so far.
1293 best_doublecolon_len = doublecolon_len
1294 best_doublecolon_start = doublecolon_start
1295 else:
1296 doublecolon_len = 0
1297 doublecolon_start = -1
1298
1299 if best_doublecolon_len > 1:
1300 best_doublecolon_end = (best_doublecolon_start +
1301 best_doublecolon_len)
1302 # For zeros at the end of the address.
1303 if best_doublecolon_end == len(hextets):
1304 hextets += ['']
1305 hextets[best_doublecolon_start:best_doublecolon_end] = ['']
1306 # For zeros at the beginning of the address.
1307 if best_doublecolon_start == 0:
1308 hextets = [''] + hextets
1309
1310 return hextets
1311
1312 def _string_from_ip_int(self, ip_int=None):
1313 """Turns a 128-bit integer into hexadecimal notation.
1314
1315 Args:
1316 ip_int: An integer, the IP address.
1317
1318 Returns:
1319 A string, the hexadecimal representation of the address.
1320
1321 Raises:
1322 ValueError: The address is bigger than 128 bits of all ones.
1323
1324 """
1325 if not ip_int and ip_int != 0:
1326 ip_int = self.ip
1327
1328 if ip_int > self._ALL_ONES:
1329 raise ValueError('IPv6 address is too large')
1330
1331 hex_str = '%032x' % ip_int
1332 hextets = []
1333 for x in range(0, 32, 4):
1334 hextets.append('%x' % int(hex_str[x:x+4], 16))
1335
1336 hextets = self._compress_hextets(hextets)
1337 return ':'.join(hextets)
1338
1339 @property
1340 def netmask_ext(self):
1341 """IPv6 extended netmask.
1342
1343 We don't deal with netmasks in IPv6 like we do in IPv4. This is
1344 here strictly for IPv4 compatibility. We simply return the
1345 prefix length.
1346
1347 Returns:
1348 An integer.
1349
1350 """
1351 return self.prefixlen
Gregory P. Smith75930f82009-05-03 19:38:29 +00001352
1353
1354# IPv4 constants.
1355_IPV4_RFC1918_NETWORKS = (IPv4('10.0.0.0/8'),
1356 IPv4('172.16.0.0/12'),
1357 IPv4('192.168.0.0/16'))
1358_IPV4_RFC3171_MULTICAST = IPv4('224.0.0.0/4')
1359_IPV4_RFC3330_LOOPBACK = IPv4('127.0.0.0/8')
1360_IPV4_RFC3927_LINK_LOCAL = IPv4('169.254.0.0/16')
1361
1362# IPv6 constants.
1363_IPV6_RFC2373_MULTICAST = IPv6('ff00::/8')
1364_IPV6_RFC2373_UNSPECIFIED = IPv6('::')
1365_IPV6_RFC2373_LOOPBACK = IPv6('::1')
1366_IPV6_RFC4291_LINK_LOCAL = IPv6('fe80::/10')
1367_IPV6_RFC3513_SITE_LOCAL = IPv6('fec0::/10') # Deprecated by RFC3879.
1368_IPV6_RFC4193_PRIVATE = IPv6('fc00::/7')