1
2
3
4
5
6
7 """
8 network address classes (IP, EUI) and associated aggregate classes (CIDR,
9 Wildcard and IPRange).
10 """
11 import math as _math
12 import socket as _socket
13 import re as _re
14
15 from netaddr import AddrFormatError, AddrConversionError, AT_UNSPEC, \
16 AT_INET, AT_INET6, AT_LINK, AT_EUI64, AT_NAMES
17
18 from netaddr.strategy import ST_IPV4, ST_IPV6, ST_EUI48, ST_EUI64, \
19 AddrStrategy
20
21 from netaddr.eui import OUI, IAB
22
23 from netaddr.util import num_bits
24
25
26 AT_STRATEGIES = {
27 AT_UNSPEC : None,
28 AT_INET : ST_IPV4,
29 AT_INET6 : ST_IPV6,
30 AT_LINK : ST_EUI48,
31 AT_EUI64 : ST_EUI64,
32 }
36 """
37 A descriptor that checks addr_type property assignments for validity and
38 also keeps the strategy property in sync with any changes made.
39 """
41 """
42 Constructor.
43
44 @param addr_types: a list of address types constants that are
45 acceptable for assignment to the addr_type property.
46 """
47 self.addr_types = addr_types
48
49 - def __set__(self, instance, value):
50 if value not in self.addr_types:
51 raise ValueError('addr_type %r is invalid for objects of ' \
52 'the %s() class!' % (value, instance.__class__.__name__))
53 instance.__dict__['addr_type'] = value
54 instance.__dict__['strategy'] = AT_STRATEGIES[value]
55
58 """
59 A descriptor that checks assignments to the named parameter passed to the
60 constructor.
61
62 It accepts network addresses in either strings format or as unsigned
63 integers. String based addresses are converted to their integer
64 equivalents before assignment to the named parameter. Also ensures that
65 addr_type and strategy are set correctly when parsing string based
66 addresses.
67 """
69 """
70 Descriptor constructor.
71
72 @param name: the name of attribute which will be assigned the value.
73 """
74 self.name = name
75
76 - def __set__(self, instance, value):
105
108 """
109 A descriptor that checks strategy property assignments for validity and
110 also keeps the addr_type property in sync with any changes made.
111 """
113 """
114 Constructor.
115
116 @param strategies: a list of strategy objects that are acceptable for
117 assignment to the strategy property.
118 """
119 self.strategies = strategies
120
121 - def __set__(self, instance, value):
122 if value not in self.strategies:
123 raise Exception('%r is not a supported strategy!' % value)
124 instance.__dict__['strategy'] = value
125 instance.__dict__['addr_type'] = instance.strategy.addr_type
126
129 """
130 A descriptor that checks prefixlen property assignments for validity based
131 on address type. Also accepts netmasks and hostmasks which can easily be
132 converted to the equivalent prefixlen integer.
133 """
135 """
136 Constructor.
137
138 @param class_id: (optional) the name of the class that uses this
139 descriptor.
140 """
141 self.class_id = class_id
142
143 - def __set__(self, instance, value):
184
210
211
212 -class Addr(object):
213 """
214 The base class containing common functionality for all subclasses
215 representing various network address types.
216
217 It is a fully functioning class (as opposed to a virtual class) with a
218 heuristic constructor that detects the type of address via the first
219 argument if it is a string and sets itself up accordingly. If the first
220 argument is an integer, then a constant must be provided via the second
221 argument indicating the address type explicitly.
222
223 Objects of this class behave differently dependent upon the type of address
224 they represent.
225 """
226 STRATEGIES = (ST_IPV4, ST_IPV6, ST_EUI48, ST_EUI64)
227 ADDR_TYPES = (AT_UNSPEC, AT_INET, AT_INET6, AT_LINK, AT_EUI64)
228
229
230 value = AddrValueDescriptor('value')
231 strategy = StrategyDescriptor(STRATEGIES)
232 addr_type = AddrTypeDescriptor(ADDR_TYPES)
233
235 """
236 Constructor.
237
238 @param addr: the string form of a network address, or a network byte
239 order integer within the supported range for the address type.
240
241 @param addr_type: (optional) the network address type. If addr is an
242 integer, this argument becomes mandatory.
243 """
244 self.addr_type = addr_type
245 self.value = addr
246
248 """@return: hash of this address suitable for dict keys, sets etc"""
249 return hash((self.value, self.addr_type))
250
252 """@return: value of this address as an unsigned integer"""
253 return self.value
254
256 """@return: value of this address as an unsigned integer"""
257 return self.value
258
262
264 """@return: executable Python string to recreate equivalent object"""
265 return "%s(%r)" % (self.__class__.__name__, str(self))
266
267 - def bits(self, word_sep=None):
268 """
269 @param word_sep: (optional) the separator to insert between words.
270 Default: None - use default separator for address type.
271
272 @return: human-readable binary digit string of this address"""
273 return self.strategy.int_to_bits(self.value, word_sep)
274
278
280 """
281 @return: standard Python binary representation of this address. A back
282 port of the format provided by the builtin bin() type available in
283 Python 2.6.x and higher."""
284 return self.strategy.int_to_bin(self.value)
285
287 """@return: The size (width) of this address in bits"""
288 return self.strategy.width
289
293
295 """
296 @return: The integer value of the word referenced by index (both
297 positive and negative). Raises C{IndexError} if index is out
298 of bounds. Also supports Python list slices for accessing
299 word groups.
300 """
301 if isinstance(index, (int, long)):
302
303 num_words = self.strategy.num_words
304 if not (-num_words) <= index <= (num_words - 1):
305 raise IndexError('index out range for address type!')
306 return self.strategy.int_to_words(self.value)[index]
307 elif isinstance(index, slice):
308
309 words = self.strategy.int_to_words(self.value)
310 return [words[i] for i in range(*index.indices(len(words)))]
311 else:
312 raise TypeError('unsupported type %r!' % index)
313
315 """Sets the value of the word referenced by index in this address"""
316 if isinstance(index, slice):
317
318 raise NotImplementedError('settable slices not yet supported!')
319
320 if not isinstance(index, (int, long)):
321 raise TypeError('index not an integer!')
322
323 if not 0 <= index <= (self.strategy.num_words - 1):
324 raise IndexError('index %d outside address type boundary!' % index)
325
326 if not isinstance(value, (int, long)):
327 raise TypeError('value not an integer!')
328
329 if not 0 <= value <= self.strategy.max_word:
330 raise IndexError('value %d outside word size maximum of %d bits!'
331 % (value, self.strategy.word_size))
332
333 words = list(self.strategy.int_to_words(self.value))
334 words[index] = value
335 self.value = self.strategy.words_to_int(words)
336
338 """
339 @return: hexadecimal string representation of this address (in network
340 byte order).
341 """
342 return hex(self.value).rstrip('L').lower()
343
345 """
346 Increment value of network address by specified amount. Behaves like
347 an unsigned integer, rolling over to zero when it reaches the maximum
348 value threshold.
349
350 @param num: size of increment
351 """
352 try:
353 new_value = self.value + num
354 if new_value > self.strategy.max_int:
355 self.value = new_value - (self.strategy.max_int + 1)
356 else:
357 self.value = new_value
358 except TypeError:
359 raise TypeError('Increment value must be an integer!')
360 return self
361
363 """
364 Decrement value of network address by specified amount. Behaves like
365 an unsigned integer, rolling over to maximum value when it goes below
366 zero.
367
368 @param num: size of decrement
369 """
370 try:
371 new_value = self.value - num
372 if new_value < 0:
373 self.value = new_value + (self.strategy.max_int + 1)
374 else:
375 self.value = new_value
376 except TypeError:
377 raise TypeError('Decrement value must be an integer!')
378 return self
379
381 """
382 @param other: an integer or int-like object.
383
384 @return: A new (potentially larger) Addr class/subclass instance.
385 """
386 return self.__class__(self.value + int(other), self.addr_type)
387
389 """
390 @param other: an integer or int-like object.
391
392 @return: A new (potentially smaller) Addr class/subclass instance.
393 """
394 return self.__class__(self.value - int(other), self.addr_type)
395
397 """
398 @return: C{True} if this address is numerically the same as other,
399 C{False} otherwise.
400 """
401 try:
402 return (self.addr_type, self.value) == (other.addr_type, other.value)
403 except AttributeError:
404 return False
405
407 """
408 @return: C{True} if this address is not numerically the same other,
409 C{False} otherwise.
410 """
411 try:
412 return (self.addr_type, self.value) != (other.addr_type, other.value)
413 except AttributeError:
414 return False
415
417 """
418 @return: C{True} if this address is numerically lower in value than
419 other, C{False} otherwise.
420 """
421 try:
422 return (self.addr_type, self.value) < (other.addr_type, other.value)
423 except AttributeError:
424 return False
425
427 """
428 @return: C{True} if this address is numerically lower or equal in
429 value to other, C{False} otherwise.
430 """
431 try:
432 return (self.addr_type, self.value) <= (other.addr_type, other.value)
433 except AttributeError:
434 return False
435
437 """
438 @return: C{True} if this address is numerically greater in value than
439 other, C{False} otherwise.
440 """
441 try:
442 return (self.addr_type, self.value) > (other.addr_type, other.value)
443 except AttributeError:
444 return False
445
447 """
448 @return: C{True} if this address is numerically greater or equal in
449 value to other, C{False} otherwise.
450 """
451 try:
452 return (self.addr_type, self.value) >= (other.addr_type, other.value)
453 except AttributeError:
454 return False
455
457 """
458 @param other: an integer or int-like object.
459
460 @return: bitwise OR (x | y) of self.value with other.value.
461 """
462 return self.__class__(self.value | other.value, self.addr_type)
463
465 """
466 @param other: an integer or int-like object.
467
468 @return: bitwise AND (x & y) of self.value with other.value.
469 """
470 return self.__class__(self.value | other.value, self.addr_type)
471
473 """
474 @param other: an integer or int-like object.
475
476 @return: bitwise exclusive OR (x ^ y) of self.value with other.value.
477 """
478 return self.__class__(self.value ^ other.value, self.addr_type)
479
481 """
482 @param numbits: size of shift (in bits).
483
484 @return: integer value of this IP address shifted left by x bits.
485 """
486 return self.__class__(self.value << numbits, self.addr_type)
487
489 """
490 @param numbits: size of shift (in bits).
491
492 @return: integer value of this IP address right shifted by x bits.
493 """
494 return self.__class__(self.value >> numbits, self.addr_type)
495
497 """
498 @param other: an integer or int-like object.
499
500 @return: inversion (~x) of self.value.
501 """
502 return self.__class__(~self.value)
503
504
505 -class EUI(Addr):
506 """
507 Represents an IEEE EUI (Extended Unique Identifier) indentifier.
508
509 Input parser is flexible, supporting EUI-48 (including the many Media
510 Access Control variants) and EUI-64.
511 """
512 STRATEGIES = (ST_EUI48, ST_EUI64)
513 ADDR_TYPES = (AT_UNSPEC, AT_LINK, AT_EUI64)
514
515
516 strategy = StrategyDescriptor(STRATEGIES)
517 addr_type = AddrTypeDescriptor(ADDR_TYPES)
518
520 """
521 Constructor.
522
523 @param addr: an EUI-48 (MAC) or EUI-64 address in string format or as
524 an unsigned integer.
525
526 @param addr_type: (optional) the specific EUI address type (C{AT_LINK}
527 or C{AT_EUI64}). This argument is used mainly to differentiate
528 EUI48 and EUI48 identifiers that may be numerically equivalent.
529 """
530
531
532 if addr_type == AT_UNSPEC:
533 if 0 <= addr <= 0xffffffffffff:
534 addr_type = AT_LINK
535 elif 0xffffffffffff < addr <= 0xffffffffffffffff:
536 addr_type = AT_EUI64
537
538 super(EUI, self).__init__(addr, addr_type)
539
541 """
542 @param fmt: callable used on return values. Default: L{OUI} object.
543 Also Supports str(), unicode(), int() and long().
544
545 @return: The OUI (Organisationally Unique Identifier) for this EUI.
546 """
547 if callable(fmt) and fmt in (OUI, int, long):
548 return fmt(self.value >> 24)
549 elif callable(fmt) and fmt in (str, unicode, None):
550 return '-'.join(["%02x" % i for i in self[0:3]]).upper()
551 else:
552 raise TypeError("unsupported formatter callable: %r!" % fmt)
553
555 """@return: The EI (Extension Identifier) for this EUI"""
556 if self.strategy == ST_EUI48:
557 return '-'.join(["%02x" % i for i in self[3:6]]).upper()
558 elif self.strategy == ST_EUI64:
559 return '-'.join(["%02x" % i for i in self[3:8]]).upper()
560
562 """@return: True if this EUI is an IAB address, False otherwise"""
563 return 0x50c2000 <= (self.value >> 12) <= 0x50c2fff
564
566 """
567 @param fmt: callable used on return values. Default: L{IAB} object.
568 Also Supports str(), unicode(), int() and long().
569
570 @return: If isiab() is True, the IAB (Individual Address Block)
571 is returned, None otherwise.
572 """
573 if self.isiab():
574 if callable(fmt) and fmt in (IAB, int, long):
575 return fmt(self.value >> 12)
576 elif callable(fmt) and fmt in (str, unicode, None):
577 usermask = (1 << (self.strategy.width - 36)) - 1
578 last_eui = self.value | usermask
579 first_eui = last_eui - usermask
580 iab_words = self.strategy.int_to_words(first_eui)
581 return '-'.join(["%02x" % i for i in iab_words]).upper()
582 else:
583 raise TypeError("unsupported formatter callable: %r!" % fmt)
584
586 """
587 @return: The value of this EUI object as a new 64-bit EUI object.
588 - If this object represents an EUI-48 it is converted to EUI-64
589 as per the standard.
590 - If this object is already and EUI-64, it just returns a new,
591 numerically equivalent object is returned instead.
592 """
593 if self.addr_type == AT_LINK:
594 eui64_words = ["%02x" % i for i in self[0:3]] + ['ff', 'fe'] + \
595 ["%02x" % i for i in self[3:6]]
596
597 return self.__class__('-'.join(eui64_words))
598 else:
599 return EUI(str(self))
600
602 """
603 @return: new link local IPv6 L{IP} object based on this L{EUI} using
604 technique described in RFC 4291. B{Please Note:} this technique
605 poses security risks in certain scenarios. Please read RFC 4941 for
606 details. Reference: RFCs 4291 and 4941.
607 """
608 prefix = 'fe80:0000:0000:0000:'
609
610
611 self[0] += 2
612
613 if self.addr_type == AT_LINK:
614
615 suffix = ["%02x" % i for i in self[0:3]] + ['ff', 'fe'] + \
616 ["%02x" % i for i in self[3:6]]
617 else:
618 suffix = ["%02x" % i for i in list(self)]
619
620 suffix = ["%02x%02x" % (int(x[0], 16), int(x[1], 16)) for x in \
621 zip(suffix[::2], suffix[1::2])]
622
623
624 self[0] -= 2
625
626 eui64 = ':'.join(suffix)
627 addr = prefix + eui64 + '/64'
628 return IP(addr)
629
631 """
632 @return: A record dict containing IEEE registration details for this
633 EUI (MAC-48) if available, None otherwise.
634 """
635 data = {'OUI': self.oui().registration()}
636 if self.isiab():
637 data['IAB'] = self.iab().registration()
638 return data
639
642 """
643 Represents B{individual} IPv4 and IPv6 addresses.
644
645 B{Please Note:} this class is intended to provide low-level functionality
646 to individual IP addresses such as octet/hextet access, integer/hex/binary
647 conversions, etc. If you are coming from other libraries you may expect to
648 find much higher level networking operations here. While the inclusion of
649 a bitmask prefix or netmask to indicate subnet membership is permitted by
650 the class constructor they are provided only as a convenience to the user.
651
652 All higher level subnet and network operations can be found in objects of
653 classes L{CIDR}, L{IPRange} and L{Wildcard}. There are handy helper methods
654 here, (C{.cidr()}, C{.iprange()} and C{.wildcard()}) that return pre-initialised
655 objects of those classes without you having to call them explicitly.
656
657 Example usage ::
658
659 >>> ip = IP('10.0.0.1')
660 >>> list(ip) == [10, 0, 0, 1]
661 True
662 >>> ip += 1
663 >>> str(ip) == '10.0.0.2'
664 True
665
666 >>> IP('10.0.0.0/28').iprange()
667 IPRange('10.0.0.0', '10.0.0.15')
668
669 >>> IP('10.0.0.64/24').cidr()
670 CIDR('10.0.0.0/24')
671
672 >>> IP('192.168.0.1/255.255.253.0').wildcard()
673 Wildcard('192.168.0-1.*')
674
675 >>> ipv6 = IP('fe80::20f:1fff:fe12:e733')
676 >>> ipv6[0:4]
677 [65152, 0, 0, 0]
678
679 >>> IP('fe80::20f:1fff:fe12:e733/64').cidr()
680 CIDR('fe80::/64')
681
682 See those classes for details on the functionality they provide.
683 """
684 STRATEGIES = (ST_IPV4, ST_IPV6)
685 ADDR_TYPES = (AT_UNSPEC, AT_INET, AT_INET6)
686 TRANSLATE_STR = ''.join([chr(_) for _ in range(256)])
687
688
689 strategy = StrategyDescriptor(STRATEGIES)
690 addr_type = AddrTypeDescriptor(ADDR_TYPES)
691 prefixlen = PrefixLenDescriptor()
692
694 """
695 Constructor.
696
697 @param addr: an IPv4 or IPv6 address string with an optional subnet
698 prefix or an unsigned integer.
699
700 @param addr_type: (optional) the IP address type (C{AT_INET} or
701 C{AT_INET6}). This argument is used mainly to differentiate IPv4
702 and IPv6 addresses that may be numerically equivalent.
703 """
704 prefixlen = None
705
706 try:
707 if '/' in addr:
708 (addr, prefixlen) = addr.split('/', 1)
709 except TypeError:
710
711 pass
712
713
714
715 if addr_type == AT_UNSPEC:
716 if 0 <= addr <= 0xffffffff:
717 addr_type = AT_INET
718 elif 0xffffffff < addr <= 0xffffffffffffffffffffffffffffffff:
719 addr_type = AT_INET6
720
721
722
723 super(IP, self).__init__(addr, addr_type)
724
725
726 if prefixlen is None:
727 self.__dict__['prefixlen'] = self.strategy.width
728 else:
729 self.prefixlen = prefixlen
730
732 """
733 @return: C{True} if this addr is a mask that would return a host id,
734 C{False} otherwise.
735 """
736 int_val = (self.value ^ self.strategy.max_int) + 1
737 return (int_val & (int_val - 1) == 0)
738
740 """
741 @return: If this address is a valid netmask, the number of non-zero
742 bits are returned, otherwise it returns the width in bits for
743 based on the version, 32 for IPv4 and 128 for IPv6.
744 """
745 if not self.is_netmask():
746 return self.strategy.width
747
748 bits = self.strategy.int_to_bits(self.value)
749 mask_bits = bits.translate(IP.TRANSLATE_STR, ':.0')
750 mask_length = len(mask_bits)
751
752 if not 1 <= mask_length <= self.strategy.width:
753 raise ValueError('Unexpected mask length %d for address type!' \
754 % mask_length)
755
756 return mask_length
757
761
763 """
764 @return: C{True} if this address is a mask that would return a host
765 id, C{False} otherwise.
766 """
767 int_val = self.value + 1
768 return (int_val & (int_val-1) == 0)
769
771 """
772 @return: Returns the FQDN for this IP address via a DNS query
773 using gethostbyaddr() Python's socket module.
774 """
775 try:
776 return _socket.gethostbyaddr(str(self))[0]
777 except:
778 return
779
780 - def cidr(self, strict=True):
781 """
782 @param strict: (optional) If True and non-zero bits are found to the
783 right of the subnet mask/prefix a ValueError is raised. If False,
784 CIDR returned has these bits automatically truncated.
785 (default: True)
786
787 @return: A L{CIDR} object based on this IP address
788 """
789 hostmask = (1 << (self.strategy.width - self.prefixlen)) - 1
790 start = (self.value | hostmask) - hostmask
791 network = self.strategy.int_to_str(start)
792 return CIDR("%s/%d" % (network, self.prefixlen), strict=strict)
793
799
808
810 """
811 @return: A new version 4 L{IP} object numerically equivalent this
812 address. If this object is already IPv4 then a copy is returned. If
813 this object is IPv6 and its value is compatible with IPv4, a new IPv4
814 L{IP} object is returned.
815
816 Raises an L{AddrConversionError} is IPv6 address cannot be converted.
817 """
818 ip_addr = None
819 if self.addr_type == AT_INET:
820 ip_addr = IP(self.value, AT_INET)
821 ip_addr.prefixlen = self.prefixlen
822 elif self.addr_type == AT_INET6:
823 words = self.strategy.int_to_words(self.value)
824
825 if words[0:6] == (0, 0, 0, 0, 0, 0):
826 ip_addr = IP(self.value, AT_INET)
827 ip_addr.prefixlen = self.prefixlen - 96
828
829 elif words[0:6] == (0, 0, 0, 0, 0, 0xffff):
830 ip_addr = IP(self.value - 0xffff00000000, AT_INET)
831 ip_addr.prefixlen = self.prefixlen - 96
832 else:
833 raise AddrConversionError('IPv6 address %s not suitable for' \
834 'IPv4 conversion!' % self)
835 return ip_addr
836
837 - def ipv6(self, ipv4_compatible=False):
838 """
839 B{Please Note:} the IPv4-Mapped IPv6 address format is now considered
840 deprecated. Reference: RFC 4291
841
842 @param ipv4_compatible: If C{True} returns an IPv4-Mapped address
843 (::ffff:x.x.x.x), an IPv4-Compatible (::x.x.x.x) address
844 otherwise. Default: False (IPv4-Mapped).
845
846 @return: A new L{IP} version 6 object that is numerically equivalent
847 this address. If this object is already IPv6 then a copy of this
848 object is returned. If this object is IPv4, a new version 6 L{IP}
849 object is returned.
850 """
851 ip_addr = None
852 if self.addr_type == AT_INET6:
853 ip_addr = IP(self.value, AT_INET6)
854 ip_addr.prefixlen = self.prefixlen - 96
855 elif self.addr_type == AT_INET:
856 ip_addr = IP(self.value, AT_INET6)
857 if ipv4_compatible:
858
859 ip_addr[5] = 0
860 else:
861
862 ip_addr[5] = 0xffff
863 ip_addr.prefixlen = self.prefixlen + 96
864 return ip_addr
865
867 """@return: C{True} if this IP is unicast, C{False} otherwise"""
868 return not self.is_multicast()
869
871 """
872 @return: C{True} if this IP is loopback address (not for network
873 transmission), C{False} otherwise.
874 References: RFC 3330 and 4291.
875 """
876 if self.addr_type == AT_INET:
877 return self in CIDR('127/8')
878 elif self.addr_type == AT_INET6:
879 return self == IP('::1')
880
882 """@return: C{True} if this IP is multicast, C{False} otherwise"""
883 if self.addr_type == AT_INET:
884 return self in CIDR('224/4')
885 elif self.addr_type == AT_INET6:
886 return self in CIDR('ff00::/8')
887
889 """
890 @return: C{True} if this IP is for internal/private use only
891 (i.e. non-public), C{False} otherwise. Reference: RFCs 1918,
892 3330, 4193, 3879 and 2365.
893 """
894 if self.addr_type == AT_INET:
895 for cidr in (CIDR('192.168/16'), CIDR('10/8'),CIDR('172.16/12'),
896 CIDR('192.0.2.0/24'), CIDR('239.192/14')):
897 if self in cidr:
898 return True
899 elif self.addr_type == AT_INET6:
900
901 return self in CIDR('fc00::/7')
902
903 if self.is_link_local():
904 return True
905
906 return False
907
909 """
910 @return: C{True} if this IP is link-local address C{False} otherwise.
911 Reference: RFCs 3927 and 4291.
912 """
913 if self.addr_type == AT_INET:
914 return self in CIDR('169.254/16')
915 elif self.addr_type == AT_INET6:
916 return self in CIDR('fe80::/10')
917
919 """
920 @return: C{True} if this IP is in IANA reserved range, C{False}
921 otherwise. Reference: RFCs 3330 and 3171.
922 """
923 if self.addr_type == AT_INET:
924
925 for cidr in (CIDR('240/4'), CIDR('234/7'), CIDR('236/7'),
926 Wildcard('225-231.*.*.*'), Wildcard('234-238.*.*.*')):
927 if self in cidr:
928 return True
929 if self.addr_type == AT_INET6:
930 for cidr in (CIDR('ff00::/12'),CIDR('::/8'), CIDR('0100::/8'),
931 CIDR('0200::/7'), CIDR('0400::/6'), CIDR('0800::/5'),
932 CIDR('1000::/4'), CIDR('4000::/3'), CIDR('6000::/3'),
933 CIDR('8000::/3'), CIDR('A000::/3'), CIDR('C000::/3'),
934 CIDR('E000::/4'), CIDR('F000::/5'), CIDR('F800::/6'),
935 CIDR('FE00::/9')):
936 if self in cidr:
937 return True
938 return False
939
941 """
942 @return: C{True} if this IP is IPv4-compatible IPv6 address, C{False}
943 otherwise.
944 """
945 return self.addr_type == AT_INET6 and (self.value >> 32) == 0xffff
946
948 """
949 @return: C{True} if this IP is IPv4-mapped IPv6 address, C{False}
950 otherwise.
951 """
952 return self.addr_type == AT_INET6 and (self.value >> 32) == 0
953
955 """
956 @return: A record dict containing IANA registration details for this
957 IP address if available, None otherwise.
958 """
959
960
961
962
963 import netaddr.ip
964 return netaddr.ip.query(self)
965
967 """@return: common string representation for this IP address"""
968 return self.strategy.int_to_str(self.value)
969
971 """@return: executable Python string to recreate equivalent object."""
972 if self.prefixlen == self.strategy.width:
973 return "%s('%s')" % (self.__class__.__name__, str(self))
974
975 return "%s('%s/%d')" % (self.__class__.__name__, str(self),
976 self.prefixlen)
977
978
979 -def nrange(start, stop, step=1, fmt=None):
980 """
981 An xrange work alike generator that produces sequences of IP addresses
982 based on start and stop addresses, in intervals of step size.
983
984 @param start: first IP address string or L{IP} object in range.
985
986 @param stop: last IP address string or L{IP} object in range
987
988 @param step: (optional) size of step between address in range.
989 (Default: 1)
990
991 @param fmt: (optional) callable used on addresses returned.
992 (Default: None - L{IP} objects). Supported options :-
993 - C{str} - IP address in string format
994 - C{int}, C{long} - IP address as an unsigned integer
995 - C{hex} - IP address as a hexadecimal number
996 - L{IP} class/subclass or callable that accepts C{addr_value} and
997 C{addr_type} arguments.
998 """
999 if not isinstance(start, IP):
1000 if isinstance(start, (str, unicode)):
1001 start = IP(start)
1002 else:
1003 raise TypeError('start is not recognised address in string ' \
1004 'format or IP class/subclass instance!')
1005 else:
1006
1007 if fmt is None:
1008 fmt = start.__class__
1009
1010 if not isinstance(stop, IP):
1011 if isinstance(stop, (str, unicode)):
1012 stop = IP(stop)
1013 else:
1014 raise TypeError('stop is not recognised address string ' \
1015 'or IP class/subclass instance!')
1016
1017 if not isinstance(step, (int, long)):
1018 raise TypeError('step must be type int|long, not %s!' % type(step))
1019
1020 if start.addr_type != stop.addr_type:
1021 raise TypeError('start and stop are not the same address type!')
1022
1023 if step == 0:
1024 raise ValueError('step argument cannot be zero')
1025
1026 negative_step = False
1027 addr_type = start.addr_type
1028
1029
1030
1031 start_fmt = start.__class__
1032 start = int(start)
1033 stop = int(stop)
1034
1035 if step < 0:
1036 negative_step = True
1037
1038 index = start - step
1039
1040
1041 if fmt is None:
1042 fmt = IP
1043
1044 if fmt in (int, long, hex):
1045
1046 while True:
1047 index += step
1048 if negative_step:
1049 if not index >= stop:
1050 return
1051 else:
1052 if not index <= stop:
1053 return
1054 yield fmt(index)
1055 elif fmt in (str, unicode):
1056
1057 while True:
1058 index += step
1059 if negative_step:
1060 if not index >= stop:
1061 return
1062 else:
1063 if not index <= stop:
1064 return
1065 yield str(start_fmt(index, addr_type))
1066 else:
1067
1068 while True:
1069 index += step
1070 if negative_step:
1071 if not index >= stop:
1072 return
1073 else:
1074 if not index <= stop:
1075 return
1076
1077 yield fmt(index, addr_type)
1078
1081 """
1082 Represents arbitrary contiguous blocks of IPv4 and IPv6 addresses using
1083 only a lower and upper bound IP address.
1084
1085 It is the base class for more specialised block types such as L{CIDR()}
1086 and L{Wildcard()}. There is no requirement that the boundary IP addresses
1087 fall on strict bitmask boundaries.
1088
1089 The sort order for sequence of mixed version L{IPRange} objects is IPv4
1090 followed by IPv6, based on the range's magnitude (size).
1091 """
1092 STRATEGIES = (ST_IPV4, ST_IPV6)
1093 ADDR_TYPES = (AT_UNSPEC, AT_INET, AT_INET6)
1094
1095
1096 strategy = StrategyDescriptor(STRATEGIES)
1097 addr_type = AddrTypeDescriptor(ADDR_TYPES)
1098 first = AddrValueDescriptor('first')
1099 last = AddrValueDescriptor('last')
1100 fmt = FormatDescriptor(IP)
1101
1103 """
1104 Constructor.
1105
1106 @param first: start address for this IP address range.
1107
1108 @param last: stop address for this IP address range.
1109
1110 @param fmt: (optional) callable used to create return values.
1111 Default: L{IP()} objects. See L{nrange()} documentations for
1112 more details on the various options.
1113 """
1114
1115
1116 self.addr_type = AT_UNSPEC
1117 self.first = first
1118 self.last = last
1119 if self.last < self.first:
1120 raise IndexError('start address is greater than stop address!')
1121 self.fmt = fmt
1122
1124 """
1125 @return: The hash of this address range. Allow them to be used in sets
1126 and as keys in dictionaries.
1127 """
1128 return hash((self.first, self.last, self.addr_type))
1129
1131 """
1132 @return: A 3-element tuple (first, last, addr_type) which represent
1133 the basic details of this IPRange object.
1134 """
1135 return self.first, self.last, self.addr_type
1136
1138 """
1139 @return: The total number of network addresses in this range.
1140 - Use this method only for ranges that contain less than
1141 C{2^31} addresses or try the L{size()} method. Raises an
1142 C{IndexError} if size is exceeded.
1143 """
1144 size = self.size()
1145 if size > (2 ** 31):
1146
1147 raise IndexError("range contains greater than 2^31 addresses! " \
1148 "Use obj.size() instead.")
1149 return size
1150
1152 """
1153 @return: The total number of network addresses in this range.
1154 - Use this method in preference to L{__len__()} when size of
1155 ranges potentially exceeds C{2^31} addresses.
1156 """
1157 return self.last - self.first + 1
1158
1179
1181 """
1182 @return: The IP address(es) in this address range referenced by
1183 index/slice. Slicing objects can produce large sequences so
1184 generator objects are returned instead of a list. Wrapping a slice
1185 with C{list()} or C{tuple()} may be required dependent on context
1186 in which it is called.
1187 """
1188
1189 if isinstance(index, (int, long)):
1190 if (- self.size()) <= index < 0:
1191
1192 return self.format(self.last + index + 1)
1193 elif 0 <= index <= (self.size() - 1):
1194
1195 return self.format(self.first + index)
1196 else:
1197 raise IndexError('index out range for address range size!')
1198 elif isinstance(index, slice):
1199
1200
1201
1202
1203
1204
1205
1206
1207 (start, stop, step) = index.indices(self.size())
1208
1209 start_addr = IP(self.first + start, self.addr_type)
1210 end_addr = IP(self.first + stop - step, self.addr_type)
1211 return nrange(start_addr, end_addr, step, fmt=self.fmt)
1212 else:
1213 raise TypeError('unsupported type %r!' % index)
1214
1216 """
1217 @return: An iterator object providing access to all network addresses
1218 within this range.
1219 """
1220 start_addr = IP(self.first, self.addr_type)
1221 end_addr = IP(self.last, self.addr_type)
1222 return nrange(start_addr, end_addr, fmt=self.fmt)
1223
1225 """
1226 @param addr: and IP/IPRange class/subclass instance or IP string value
1227 to be compared.
1228
1229 @return: C{True} if given address or range falls within this range,
1230 C{False} otherwise.
1231 """
1232 if isinstance(addr, (str, unicode)):
1233
1234 c_addr = IP(addr)
1235 if c_addr.addr_type == self.addr_type:
1236 if self.first <= int(c_addr) <= self.last:
1237 return True
1238 elif isinstance(addr, IP):
1239
1240 if self.first <= int(addr) <= self.last:
1241 return True
1242 elif issubclass(addr.__class__, IPRange):
1243
1244 if addr.first >= self.first and addr.last <= self.last:
1245 return True
1246 else:
1247 raise TypeError('%r is an unsupported type or class!' % addr)
1248
1249 return False
1250
1252 """
1253 @param other: an address object of the same address type as C{self}.
1254
1255 @return: C{True} if the boundaries of this range are the same as
1256 other, C{False} otherwise.
1257 """
1258 try:
1259 return (self.addr_type, self.first, self.last) == \
1260 (other.addr_type, other.first, other.last)
1261 except AttributeError:
1262 return False
1263
1265 """
1266 @param other: an address object of the same address type as C{self}.
1267
1268 @return: C{True} if the boundaries of this range are not the same as
1269 other, C{False} otherwise.
1270 """
1271 try:
1272 return (self.addr_type, self.first, self.last) != \
1273 (other.addr_type, other.first, other.last)
1274 except AttributeError:
1275 return False
1276
1278 """
1279 @param other: an address object of the same address type as C{self}.
1280
1281 @return: C{True} if the boundaries of this range are less than other,
1282 C{False} otherwise.
1283 """
1284 try:
1285
1286
1287
1288 s_sortkey = self.strategy.width - num_bits(self.size())
1289 o_sortkey = other.strategy.width - num_bits(other.size())
1290
1291 return (self.addr_type, self.first, s_sortkey) < \
1292 (other.addr_type, other.first, o_sortkey)
1293 except AttributeError:
1294 return False
1295
1297 """
1298 @param other: an address object of the same address type as C{self}.
1299
1300 @return: C{True} if the boundaries of this range are less or equal to
1301 other, C{False} otherwise.
1302 """
1303 try:
1304
1305
1306
1307 s_sortkey = self.strategy.width - num_bits(self.size())
1308 o_sortkey = other.strategy.width - num_bits(other.size())
1309
1310 return (self.addr_type, self.first, s_sortkey) <= \
1311 (other.addr_type, other.first, o_sortkey)
1312 except AttributeError:
1313 return False
1314
1316 """
1317 @param other: an address object of the same address type as C{self}.
1318
1319 @return: C{True} if the boundaries of this range are greater than
1320 other, C{False} otherwise.
1321 """
1322 try:
1323
1324
1325
1326 s_sortkey = self.strategy.width - num_bits(self.size())
1327 o_sortkey = other.strategy.width - num_bits(other.size())
1328
1329 return (self.addr_type, self.first, s_sortkey) > \
1330 (other.addr_type, other.first, o_sortkey)
1331 except AttributeError:
1332 return False
1333
1335 """
1336 @param other: an address object of the same address type as C{self}.
1337
1338 @return: C{True} if the boundaries of this range are greater or equal
1339 to other, C{False} otherwise.
1340 """
1341 try:
1342
1343
1344
1345 s_sortkey = self.strategy.width - num_bits(self.size())
1346 o_sortkey = other.strategy.width - num_bits(other.size())
1347
1348 return (self.addr_type, self.first, s_sortkey) >= \
1349 (other.addr_type, other.first, o_sortkey)
1350 except AttributeError:
1351 return False
1352
1354 """
1355 Increments start and end addresses of this range by the current size.
1356
1357 Raises IndexError if the result exceeds address range maximum.
1358 """
1359 try:
1360 new_first = self.first + (self.size() * i)
1361 new_last = self.last + (self.size() * i)
1362 except TypeError:
1363 raise TypeError('Increment value must be an integer!')
1364
1365 if new_last > self.strategy.max_int:
1366 raise IndexError('Invalid increment is outside address boundary!')
1367
1368 self.first = new_first
1369 self.last = new_last
1370
1371 return self
1372
1374 """
1375 Decrements start and end addresses of this range by the current size.
1376
1377 Raises IndexError if the result is less than zero.
1378 """
1379 try:
1380 new_first = self.first - (self.size() * i)
1381 new_last = self.last - (self.size() * i)
1382 except TypeError:
1383 raise TypeError('Decrement value must be an integer!')
1384
1385 if new_last < 0:
1386 raise IndexError('Invalid decrement is outside address boundary!')
1387
1388 self.first = new_first
1389 self.last = new_last
1390
1391 return self
1392
1403
1405 """
1406 @return: A list of one or more L{CIDR} objects covering this address
1407 range. B{Please Note:} a list is returned even if this range maps
1408 to a single CIDR because arbitrary ranges may not be aligned with
1409 base 2 subnet sizes and will therefore return multiple CIDRs.
1410 """
1411
1412
1413 cidr_list = []
1414
1415
1416 start = IP(self.first, self.addr_type)
1417 end = IP(self.last, self.addr_type)
1418
1419 cidr_span = CIDR.span([start, end])
1420
1421 if cidr_span.first == self.first and cidr_span.last == self.last:
1422
1423 cidr_list = [cidr_span]
1424 elif cidr_span.last == self.last:
1425
1426 ip = IP(start)
1427 first_int_val = int(ip)
1428 ip -= 1
1429 cidr_remainder = cidr_span - ip
1430
1431 first_found = False
1432 for cidr in cidr_remainder:
1433 if cidr.first == first_int_val:
1434 first_found = True
1435 if first_found:
1436 cidr_list.append(cidr)
1437 elif cidr_span.first == self.first:
1438
1439 ip = IP(end)
1440 last_int_val = int(ip)
1441 ip += 1
1442 cidr_remainder = cidr_span - ip
1443
1444 last_found = False
1445 for cidr in cidr_remainder:
1446 cidr_list.append(cidr)
1447 if cidr.last == last_int_val:
1448 break
1449 elif cidr_span.first <= self.first and cidr_span.last >= self.last:
1450
1451 ip = IP(start)
1452 first_int_val = int(ip)
1453 ip -= 1
1454 cidr_remainder = cidr_span - ip
1455
1456
1457 first_found = False
1458 for cidr in cidr_remainder:
1459 if cidr.first == first_int_val:
1460 first_found = True
1461 if first_found:
1462 cidr_list.append(cidr)
1463
1464
1465 ip = IP(end)
1466 last_int_val = int(ip)
1467 ip += 1
1468 cidr_remainder = cidr_list.pop() - ip
1469
1470 last_found = False
1471 for cidr in cidr_remainder:
1472 cidr_list.append(cidr)
1473 if cidr.last == last_int_val:
1474 break
1475
1476
1477 if self.fmt in (str, unicode):
1478 cidr_list = [self.fmt(c) for c in cidr_list]
1479
1480 return cidr_list
1481
1483 """
1484 @return: A L{Wildcard} object equivalent to this CIDR.
1485 - If CIDR was initialised with C{fmt=str}, a wildcard string
1486 is returned, in all other cases a L{Wildcard} object is
1487 returned.
1488 - Only supports IPv4 CIDR addresses.
1489 """
1490 t1 = self.strategy.int_to_words(self.first)
1491 t2 = self.strategy.int_to_words(self.last)
1492
1493 if self.addr_type != AT_INET:
1494 raise AddrConversionError('wildcards only suitable for IPv4 ' \
1495 'ranges!')
1496
1497 tokens = []
1498
1499 seen_hyphen = False
1500 seen_asterisk = False
1501
1502 for i in range(4):
1503 if t1[i] == t2[i]:
1504
1505 tokens.append(str(t1[i]))
1506 elif (t1[i] == 0) and (t2[i] == 255):
1507
1508 tokens.append('*')
1509 seen_asterisk = True
1510 else:
1511
1512 if not seen_asterisk:
1513 if not seen_hyphen:
1514 tokens.append('%s-%s' % (t1[i], t2[i]))
1515 seen_hyphen = True
1516 else:
1517 raise SyntaxError('only one hyphenated octet per ' \
1518 'wildcard permitted!')
1519 else:
1520 raise SyntaxError("* chars aren't permitted before ' \
1521 'hyphenated octets!")
1522
1523 wildcard = '.'.join(tokens)
1524
1525 if self.fmt == str:
1526 return wildcard
1527
1528 return Wildcard(wildcard)
1529
1531 """
1532 @return: True if other's boundary is equal to or within this range.
1533 False otherwise.
1534 """
1535 if isinstance(other, (str, unicode)):
1536 other = CIDR(other)
1537
1538 if not hasattr(other, 'addr_type'):
1539 raise TypeError('%r is an unsupported argument type!' % other)
1540
1541 if self.addr_type != other.addr_type:
1542 raise TypeError('Ranges must be the same address type!')
1543
1544 return self.first >= other.first and self.last <= other.last
1545
1547 """
1548 @return: True if other's boundary is equal to or contains this range.
1549 False otherwise.
1550 """
1551 if isinstance(other, (str, unicode)):
1552 other = CIDR(other)
1553
1554 if not hasattr(other, 'addr_type'):
1555 raise TypeError('%r is an unsupported argument type!' % other)
1556
1557 if self.addr_type != other.addr_type:
1558 raise TypeError('Ranges must be the same address type!')
1559
1560 return self.first <= other.first and self.last >= other.last
1561
1563 """
1564 @return: True if other's boundary touches the boundary of this
1565 address range, False otherwise.
1566 """
1567 if isinstance(other, (str, unicode)):
1568 other = CIDR(other)
1569
1570 if not hasattr(other, 'addr_type'):
1571 raise TypeError('%r is an unsupported argument type!' % other)
1572
1573 if self.addr_type != other.addr_type:
1574 raise TypeError('addresses must be of the same type!')
1575
1576 if isinstance(other, IPRange):
1577
1578 if self.first == (other.last + 1):
1579 return True
1580
1581
1582 if self.last == (other.first - 1):
1583 return True
1584 elif isinstance(other, IP):
1585
1586 if self.first == (other.value + 1):
1587 return True
1588
1589
1590 if self.last == (other.value - 1):
1591 return True
1592 else:
1593 raise TypeError('unexpected error for argument: %r!')
1594
1595 return False
1596
1598 """
1599 @return: True if other's boundary crosses the boundary of this address
1600 range, False otherwise.
1601 """
1602 if isinstance(other, (str, unicode)):
1603 other = CIDR(other)
1604
1605 if not hasattr(other, 'addr_type'):
1606 raise TypeError('%r is an unsupported argument type!' % other)
1607
1608 if self.addr_type != other.addr_type:
1609 raise TypeError('Ranges must be the same address type!')
1610
1611
1612 if self.first <= other.last <= self.last:
1613 return True
1614
1615
1616 if self.first <= other.first <= self.last:
1617 return True
1618
1619 return False
1620
1624
1630
1633 """
1634 @param cidr: a CIDR object or CIDR string value (acceptable by CIDR class
1635 constructor).
1636
1637 @return: a tuple containing CIDR in binary string format and addr_type.
1638 """
1639 if not hasattr(cidr, 'network'):
1640 cidr = CIDR(cidr, strict=False)
1641
1642 bits = cidr.network.bits(word_sep='')
1643 return (bits[0:cidr.prefixlen], cidr.addr_type)
1644
1647 """
1648 @param bits: a CIDR in binary string format.
1649
1650 @param addr_type: (optional) CIDR address type (IP version).
1651 (Default: AT_UNSPEC - auto-select) If not specified AT_INET (IPv4) is
1652 assumed if length of binary string is <= /32. If binary string
1653 is > /32 and <= /128 AT_INET6 (IPv6) is assumed. Useful when you have
1654 IPv6 addresses with a prefixlen of /32 or less.
1655
1656 @param fmt: (optional) callable invoked on return CIDR.
1657 (Default: None - CIDR object). Also accepts str() and unicode().
1658
1659 @return: a CIDR object or string (determined by fmt).
1660 """
1661 if _re.match('^[01]+$', bits) is None:
1662 raise ValueError('%r is an invalid bit string!' % bits)
1663
1664 num_bits = len(bits)
1665 strategy = None
1666 if addr_type == AT_UNSPEC:
1667 if 0 <= num_bits <= 32:
1668 strategy = ST_IPV4
1669 elif 33 < num_bits <= 128:
1670 strategy = ST_IPV6
1671 else:
1672 raise ValueError('Invalid number of bits: %s!' % bits)
1673 elif addr_type == AT_INET:
1674 strategy = ST_IPV4
1675 elif addr_type == AT_INET6:
1676 strategy = ST_IPV6
1677 else:
1678 raise ValueError('strategy auto-select failure for %r!' % bits)
1679
1680 if bits == '':
1681 return CIDR('%s/0' % strategy.int_to_str(0))
1682
1683 cidr = None
1684 bits = bits + '0' * (strategy.width - num_bits)
1685 ip = strategy.int_to_str(strategy.bits_to_int(bits))
1686 cidr = CIDR('%s/%d' % (ip, num_bits))
1687
1688 if fmt is not None:
1689 return fmt(cidr)
1690
1691 return cidr
1692
1693
1694 -class CIDR(IPRange):
1695 """
1696 Represents blocks of IPv4 and IPv6 addresses using CIDR (Classless
1697 Inter-Domain Routing) notation.
1698
1699 CIDR is a method of categorising contiguous blocks of both IPv4 and IPv6
1700 addresses. It is very scalable allowing for the optimal usage of the IP
1701 address space. It permits the aggregation of networks via route
1702 summarisation (supernetting) where adjacent routes can be combined into a
1703 single route easily. This greatly assists in the reduction of routing
1704 table sizes and improves network router efficiency.
1705
1706 CIDR blocks are represented by a base network address and a prefix
1707 indicating the size of the (variable length) subnet mask. These are
1708 separated by a single '/' character. Subnet sizes increase in powers of
1709 base 2 aligning to bit boundaries.
1710
1711 It is technically invalid to have non-zero bits in a CIDR address to the
1712 right of the implied netmask. For user convenience this is however
1713 configurable and can be disabled using a constructor argument.
1714
1715 The constructor accepts CIDRs expressed in one of 4 different ways :-
1716
1717 A) Standard CIDR format :-
1718
1719 IPv4::
1720
1721 x.x.x.x/y -> 192.0.2.0/24
1722
1723 where the x's represent the network address and y is the netmask
1724 prefix between 0 and 32.
1725
1726 IPv6::
1727
1728 x::/y -> fe80::/10
1729
1730 where the x's represent the network address and y is the netmask
1731 prefix between 0 and 128.
1732
1733 B) Abbreviated CIDR format (IPv4 only)::
1734
1735 x -> 192
1736 x/y -> 10/8
1737 x.x/y -> 192.168/16
1738 x.x.x/y -> 192.168.0/24
1739
1740 which are equivalent to::
1741
1742 x.0.0.0/y -> 192.0.0.0/24
1743 x.0.0.0/y -> 10.0.0.0/8
1744 x.x.0.0/y -> 192.168.0.0/16
1745 x.x.x.0/y -> 192.168.0.0/24
1746
1747 - The trailing zeros are implicit.
1748 - Old classful IP address rules apply if y is omitted.
1749
1750 C) Hybrid CIDR format (prefix replaced by netmask) :-
1751
1752 IPv4::
1753
1754 x.x.x.x/y.y.y.y -> 192.0.2.0/255.255.255.0
1755
1756 IPv6::
1757
1758 x::/y:: -> fe80::/ffc0::
1759
1760 where the y's represent a valid netmask.
1761
1762 D) ACL-style CIDR format (prefix is replaced by a hostmask) :-
1763
1764 Akin to Cisco's ACL (Access Control List) bitmasking (reverse
1765 netmasks).
1766
1767 IPv4::
1768
1769 x.x.x.x/y.y.y.y -> 192.0.2.0/0.0.0.255
1770
1771 IPv6::
1772
1773 x::/y:: -> fe80::/3f:ffff:ffff:ffff:ffff:ffff:ffff:ffff
1774
1775 where the y's represent a valid hostmask.
1776
1777 Reference: RFCs 1338 and 4632.
1778 """
1779 STRATEGIES = (ST_IPV4, ST_IPV6)
1780 ADDR_TYPES = (AT_UNSPEC, AT_INET, AT_INET6)
1781
1782
1783 strategy = StrategyDescriptor(STRATEGIES)
1784 addr_type = AddrTypeDescriptor(ADDR_TYPES)
1785 prefixlen = PrefixLenDescriptor('CIDR')
1786 fmt = FormatDescriptor(IP)
1787
1788 @staticmethod
1790 """
1791 A static method that converts abbreviated IPv4 CIDRs to their more
1792 verbose equivalent.
1793
1794 @param abbrev_cidr: an abbreviated CIDR.
1795
1796 Uses the old-style classful IP address rules to decide on a default
1797 subnet prefix if one is not explicitly provided.
1798
1799 Only supports IPv4 addresses.
1800
1801 Examples ::
1802
1803 10 - 10.0.0.0/8
1804 10/16 - 10.0.0.0/16
1805 128 - 128.0.0.0/16
1806 128/8 - 128.0.0.0/8
1807 192.168 - 192.168.0.0/16
1808
1809 @return: A verbose CIDR from an abbreviated CIDR or old-style classful
1810 network address, C{None} if format provided was not recognised or
1811 supported.
1812 """
1813
1814
1815 def classful_prefix(octet):
1816 octet = int(octet)
1817 if not 0 <= octet <= 255:
1818 raise IndexError('Invalid octet: %r!' % octet)
1819 if 0 <= octet <= 127:
1820 return 8
1821 elif 128 <= octet <= 191:
1822 return 16
1823 elif 192 <= octet <= 223:
1824 return 24
1825 elif octet == 224:
1826 return 4
1827 elif 225 <= octet <= 239:
1828 return 8
1829 return 32
1830
1831 start = ''
1832 tokens = []
1833 prefix = None
1834
1835 if isinstance(abbrev_cidr, (str, unicode)):
1836
1837 if ':' in abbrev_cidr:
1838 return None
1839 try:
1840
1841 i = int(abbrev_cidr)
1842 tokens = [str(i), '0', '0', '0']
1843 return "%s%s/%s" % (start, '.'.join(tokens), classful_prefix(i))
1844
1845 except ValueError:
1846
1847 part_addr = abbrev_cidr
1848 tokens = []
1849
1850 if part_addr == '':
1851
1852 return None
1853
1854 if '/' in part_addr:
1855 (part_addr, prefix) = part_addr.split('/', 1)
1856
1857
1858 if prefix is not None:
1859 try:
1860 if not 0 <= int(prefix) <= 32:
1861 return None
1862 except ValueError:
1863 return None
1864
1865 if '.' in part_addr:
1866 tokens = part_addr.split('.')
1867 else:
1868 tokens = [part_addr]
1869
1870 if 1 <= len(tokens) < 4:
1871 for i in range(4 - len(tokens)):
1872 tokens.append('0')
1873 elif len(tokens) == 4:
1874 if prefix is None:
1875
1876 prefix = 32
1877 else:
1878
1879 return None
1880
1881 if prefix is None:
1882 try:
1883 prefix = classful_prefix(tokens[0])
1884 except ValueError:
1885 return None
1886
1887 return "%s%s/%s" % (start, '.'.join(tokens), prefix)
1888
1889 except TypeError:
1890 pass
1891 except IndexError:
1892 pass
1893
1894
1895 return None
1896
1897 @staticmethod
1898 - def span(addrs, fmt=None):
1899 """
1900 Static method that accepts a sequence of IP addresses and/or CIDRs,
1901 Wildcards and IPRanges returning a single CIDR that is large enough
1902 to span the lowest and highest IP addresses in the sequence (with
1903 a possible overlap on either end).
1904
1905 @param addrs: a sequence of IP, CIDR, Wildcard or IPRange objects
1906 and/or their string representations.
1907
1908 @param fmt: (optional) callable used on return values.
1909 (Default: None - L{CIDR} object) Also accepts str() and unicode().
1910
1911 @return: a single CIDR object spanning all addresses.
1912 """
1913 if not isinstance(addrs, (list, tuple)):
1914 raise TypeError('expected address sequence is not iterable!')
1915
1916 if not len(addrs) > 1:
1917 raise ValueError('sequence must contain 2 or more elements!')
1918
1919 if fmt not in (None, str, unicode):
1920 raise ValueError('unsupported formatter %r!' % fmt)
1921
1922
1923 if not isinstance(addrs, list):
1924 addrs = list(addrs)
1925
1926
1927
1928 for (i, addr) in enumerate(addrs):
1929 if isinstance(addr, (str, unicode)):
1930 try:
1931 obj = IP(addr)
1932 addrs[i] = obj
1933 continue
1934 except:
1935 pass
1936 try:
1937 obj = CIDR(addr)
1938 addrs[i] = obj
1939 continue
1940 except:
1941 pass
1942 try:
1943 obj = Wildcard(addr)
1944 addrs[i] = obj
1945 continue
1946 except:
1947 pass
1948
1949
1950 addrs.sort()
1951 lowest = addrs[0]
1952 highest = addrs[-1]
1953
1954 if isinstance(lowest, IPRange):
1955
1956 lowest = IP(lowest.first, lowest.addr_type)
1957
1958 if isinstance(highest, IPRange):
1959
1960 highest = IP(highest.last, highest.addr_type)
1961
1962 if lowest.addr_type != highest.addr_type:
1963 raise TypeError('address types are not the same!')
1964
1965 cidr = highest.cidr()
1966
1967 while cidr.prefixlen > 0:
1968 if highest in cidr and lowest not in cidr:
1969 cidr.prefixlen -= 1
1970 else:
1971 break
1972
1973
1974 if fmt is not None:
1975 return fmt(cidr)
1976
1977 return cidr
1978
1979 @staticmethod
1981 """
1982 Static method that accepts a sequence of IP addresses and/or CIDRs
1983 returning a summarized sequence of merged CIDRs where possible. This
1984 method doesn't create any CIDR that are inclusive of any addresses
1985 other than those found in the original sequence provided.
1986
1987 @param cidrs: a list or tuple of IP and/or CIDR objects.
1988
1989 @param fmt: callable used on return values.
1990 (Default: None - L{CIDR} objects). str() and unicode() supported.
1991
1992 @return: a possibly smaller list of CIDRs covering sequence passed in.
1993 """
1994 if not hasattr(cidrs, '__iter__'):
1995 raise ValueError('A sequence or iterable is expected!')
1996
1997
1998 ipv4_bit_cidrs = set()
1999 ipv6_bit_cidrs = set()
2000
2001
2002
2003 for cidr in cidrs:
2004 (bits, addr_type) = cidr_to_bits(cidr)
2005 if addr_type == AT_INET:
2006 ipv4_bit_cidrs.add(bits)
2007 elif addr_type == AT_INET6:
2008 ipv6_bit_cidrs.add(bits)
2009 else:
2010 raise ValueError('Unknown address type found!')
2011
2012
2013 def _reduce_bit_cidrs(cidrs):
2014 new_cidrs = []
2015
2016 cidrs.sort()
2017
2018
2019 while 1:
2020 finished = True
2021 while len(cidrs) > 0:
2022 if len(new_cidrs) == 0:
2023 new_cidrs.append(cidrs.pop(0))
2024 if len(cidrs) == 0:
2025 break
2026
2027 (new_cidr, subs) = _re.subn(r'^([01]+)0 \1[1]$',
2028 r'\1', '%s %s' % (new_cidrs[-1], cidrs[0]))
2029 if subs:
2030
2031 new_cidrs[-1] = new_cidr
2032 cidrs.pop(0)
2033 finished = False
2034 else:
2035
2036 (new_cidr, subs) = _re.subn(r'^([01]+) \1[10]+$',
2037 r'\1', '%s %s' % (new_cidrs[-1], cidrs[0]))
2038 if subs:
2039
2040 new_cidrs[-1] = new_cidr
2041 cidrs.pop(0)
2042 finished = False
2043 else:
2044
2045 new_cidrs.append(cidrs.pop(0))
2046 if finished:
2047 break
2048 else:
2049
2050 cidrs = new_cidrs
2051 new_cidrs = []
2052
2053 return new_cidrs
2054
2055 new_cidrs = []
2056
2057
2058 for bit_cidr in _reduce_bit_cidrs(list(ipv4_bit_cidrs)):
2059 new_cidrs.append(bits_to_cidr(bit_cidr, fmt=fmt))
2060
2061
2062 for bit_cidr in _reduce_bit_cidrs(list(ipv6_bit_cidrs)):
2063 new_cidrs.append(bits_to_cidr(bit_cidr, fmt=fmt))
2064
2065 return new_cidrs
2066
2067 - def __init__(self, cidr, fmt=IP, strict=True, expand_abbrev=True):
2068 """
2069 Constructor.
2070
2071 @param cidr: a valid IPv4/IPv6 CIDR address or abbreviated IPv4
2072 network address.
2073
2074 @param fmt: (optional) callable used on return values.
2075 Default: L{IP} class. See L{nrange()} documentations for
2076 more details on the various options.
2077
2078 @param strict: (optional) If True and non-zero bits are found to the
2079 right of the subnet mask/prefix a ValueError is raised. If False,
2080 CIDR returned has these bits automatically truncated.
2081 (default: True)
2082
2083 @param expand_abbrev: (optional) If True, enables the abbreviated CIDR
2084 expansion routine. If False, abbreviated CIDRs will be considered
2085 invalid addresses, raising an AddrFormatError exception.
2086 (default: True)
2087 """
2088 cidr_arg = cidr
2089
2090 if expand_abbrev:
2091
2092 verbose_cidr = CIDR.abbrev_to_verbose(cidr)
2093 if verbose_cidr is not None:
2094 cidr = verbose_cidr
2095
2096 if not isinstance(cidr, (str, unicode)):
2097 raise TypeError('%r is not a valid CIDR!' % cidr)
2098
2099
2100 try:
2101 (network, mask) = cidr.split('/', 1)
2102 except ValueError:
2103 network = cidr
2104 mask = None
2105
2106
2107
2108 first = IP(network)
2109 self.strategy = first.strategy
2110
2111 if mask is None:
2112
2113 self.__dict__['prefixlen'] = first.strategy.width
2114 else:
2115 self.prefixlen = mask
2116
2117 strategy = first.strategy
2118 addr_type = strategy.addr_type
2119
2120 hostmask = (1 << (strategy.width - self.prefixlen)) - 1
2121
2122 last = IP(first.value | hostmask, addr_type)
2123
2124 if strict:
2125
2126 netmask = strategy.max_int ^ hostmask
2127 host = (first.value | netmask) - netmask
2128 if host != 0:
2129 raise ValueError('%s contains non-zero bits right of the ' \
2130 '%d-bit mask! Did you mean %s instead?' \
2131 % (first, self.prefixlen,
2132 strategy.int_to_str(int(last) - hostmask)))
2133 else:
2134
2135 first.value = strategy.int_to_str(int(last) - hostmask)
2136
2137 super(CIDR, self).__init__(first, last, fmt)
2138
2140 """
2141 Subtract another CIDR from this one.
2142
2143 @param other: a CIDR object that is greater than or equal to C{self}.
2144
2145 @return: A list of CIDR objects than remain after subtracting C{other}
2146 from C{self}.
2147 """
2148 cidrs = []
2149
2150 if self.prefixlen == self.strategy.width:
2151
2152 return cidrs
2153
2154 new_prefixlen = self.prefixlen + 1
2155 i_lower = self.first
2156 i_upper = self.first + (2 ** (self.strategy.width - new_prefixlen))
2157
2158 lower = CIDR('%s/%d' % (self.strategy.int_to_str(i_lower),
2159 new_prefixlen))
2160 upper = CIDR('%s/%d' % (self.strategy.int_to_str(i_upper),
2161 new_prefixlen))
2162
2163 while other.prefixlen >= new_prefixlen:
2164 if other in lower:
2165 matched = i_lower
2166 unmatched = i_upper
2167 elif other in upper:
2168 matched = i_upper
2169 unmatched = i_lower
2170
2171 cidr = CIDR('%s/%d' % (self.strategy.int_to_str(unmatched),
2172 new_prefixlen))
2173
2174 cidrs.append(cidr)
2175
2176 new_prefixlen += 1
2177
2178 if new_prefixlen > self.strategy.width:
2179 break
2180
2181 i_lower = matched
2182 i_upper = matched + (2 ** (self.strategy.width - new_prefixlen))
2183
2184 lower = CIDR('%s/%d' % (self.strategy.int_to_str(i_lower),
2185 new_prefixlen))
2186 upper = CIDR('%s/%d' % (self.strategy.int_to_str(i_upper),
2187 new_prefixlen))
2188
2189 cidrs.sort()
2190
2191
2192 if self.fmt is str:
2193 return [str(cidr) for cidr in cidrs]
2194
2195 return cidrs
2196
2198 """
2199 Add another CIDR to this one returning a CIDR supernet that will
2200 contain both in the smallest possible sized range.
2201
2202 @param other: a CIDR object.
2203
2204 @return: A new (potentially larger) CIDR object.
2205 """
2206 cidr = CIDR.span([self, other])
2207 if self.fmt is str:
2208 return str(cidr)
2209 return cidr
2210
2211 @property
2213 """@return: The network (first) address in this CIDR block."""
2214 return self[0]
2215
2216 @property
2218 """
2219 B{Please Note:} although IPv6 doesn't actually recognise the concept of
2220 broadcast addresses per se (as in IPv4), so many other libraries do
2221 this that it isn't worth trying to resist the trend just for the sake
2222 of making a theoretical point.
2223
2224 @return: The broadcast (last) address in this CIDR block.
2225 """
2226 return self[-1]
2227
2228 @property
2234
2235 @property
2240
2242 """
2243 @param step: the number of CIDRs between this CIDR and the expected
2244 one. Default: 1 - the preceding CIDR.
2245
2246 @return: The immediate (adjacent) predecessor of this CIDR.
2247 """
2248 cidr_copy = CIDR('%s/%d' % (self.strategy.int_to_str(self.first),
2249 self.prefixlen))
2250 cidr_copy -= step
2251
2252 if self.fmt in (str, unicode):
2253 return self.fmt(cidr_copy)
2254 return cidr_copy
2255
2256 - def next(self, step=1):
2257 """
2258 @param step: the number of CIDRs between this CIDR and the expected
2259 one. Default: 1 - the succeeding CIDR.
2260
2261 @return: The immediate (adjacent) successor of this CIDR.
2262 """
2263 cidr_copy = CIDR('%s/%d' % (self.strategy.int_to_str(self.first),
2264 self.prefixlen))
2265 cidr_copy += step
2266
2267 if self.fmt in (str, unicode):
2268 return self.fmt(cidr_copy)
2269 return cidr_copy
2270
2272 """
2273 @return: An iterator object providing access to all valid host IP
2274 addresses within the specified CIDR block.
2275 - with IPv4 the network and broadcast addresses are always
2276 excluded. Any smaller than 4 hosts yields an emtpy list.
2277 - with IPv6 only the unspecified address '::' is excluded from
2278 the yielded list.
2279 """
2280 if self.addr_type == AT_INET:
2281
2282 if self.size() >= 4:
2283 return nrange( IP(self.first+1, self.addr_type),
2284 IP(self.last-1, self.addr_type), fmt=self.fmt)
2285 else:
2286 return iter([])
2287 elif self.addr_type == AT_INET6:
2288
2289 if self.first == 0:
2290
2291 return nrange(IP(self.first+1, self.addr_type),
2292 IP(self.last, self.addr_type), fmt=self.fmt)
2293 else:
2294 return iter(self)
2295
2296 - def supernet(self, prefixlen=0, fmt=None):
2297 """
2298 Provides a list of supernet CIDRs for the current CIDR between the size
2299 of the current prefix and (if specified) the end CIDR prefix.
2300
2301 @param prefixlen: (optional) a CIDR prefix for the maximum supernet.
2302 Default: 0 - returns all possible supernets.
2303
2304 @param fmt: callable used on return values.
2305 Default: None - L{CIDR} objects. str() and unicode() supported.
2306
2307 @return: an tuple containing CIDR supernets that contain this one.
2308 """
2309 if not 0 <= prefixlen <= self.strategy.width:
2310 raise ValueError('prefixlen %r invalid for IP version!' \
2311 % prefixlen)
2312
2313
2314 cidr = self.cidrs()[0]
2315 cidr.fmt = fmt
2316
2317 supernets = []
2318 while cidr.prefixlen > prefixlen:
2319 cidr.prefixlen -= 1
2320 supernets.append(cidr.cidrs()[0])
2321
2322 return list(reversed(supernets))
2323
2324 - def subnet(self, prefixlen, count=None, fmt=None):
2325 """
2326 A generator that returns CIDR subnets based on the current network
2327 base address and provided CIDR prefix and count.
2328
2329 @param prefixlen: a CIDR prefix.
2330
2331 @param count: number of consecutive CIDRs to be returned.
2332
2333 @param fmt: callable used on return values.
2334 Default: None - L{CIDR} objects. str() and unicode() supported.
2335
2336 @return: an iterator (as lists could potentially be very large)
2337 containing CIDR subnets below this CIDR's base address.
2338 """
2339 if not 0 <= self.prefixlen <= self.strategy.width:
2340 raise ValueError('prefixlen %d out of bounds for address type!' \
2341 % prefixlen)
2342
2343 if not self.prefixlen <= prefixlen:
2344 raise ValueError('prefixlen less than current CIDR prefixlen!')
2345
2346
2347 width = self.strategy.width
2348 max_count = 2 ** (width - self.prefixlen) / 2 ** (width - prefixlen)
2349
2350 if count is None:
2351 count = max_count
2352
2353 if not 1 <= count <= max_count:
2354 raise ValueError('count not within current CIDR boundaries!')
2355
2356 base_address = self.strategy.int_to_str(self.first)
2357
2358
2359 if fmt is None and self.fmt in (str, unicode):
2360 fmt = self.fmt
2361
2362 if fmt is None:
2363
2364 for i in xrange(count):
2365 cidr = CIDR('%s/%d' % (base_address, prefixlen))
2366 cidr.first += cidr.size() * i
2367 cidr.prefixlen = prefixlen
2368 yield cidr
2369 elif fmt in (str, unicode):
2370
2371 for i in xrange(count):
2372 cidr = CIDR('%s/%d' % (base_address, prefixlen))
2373 cidr.first += cidr.size() * i
2374 cidr.prefixlen = prefixlen
2375 yield fmt(cidr)
2376 else:
2377 raise TypeError('unsupported fmt callable %r' % fmt)
2378
2380 """
2381 @return: A list of a copy of this L{CIDR} object. This method is here
2382 mainly for compatibility with IPRange interface.
2383 """
2384 cidr_copy = CIDR('%s/%d' % (self.strategy.int_to_str(self.first),
2385 self.prefixlen))
2386
2387
2388 if self.fmt in (str, unicode):
2389 return [self.fmt(cidr_copy)]
2390
2391 return [cidr_copy]
2392
2395
2397 """@return: executable Python string to recreate equivalent object."""
2398 return "%s('%s/%d')" % (self.__class__.__name__,
2399 self.strategy.int_to_str(self.first), self.prefixlen)
2400
2403 """
2404 Represents blocks of IPv4 addresses using a wildcard or glob style syntax.
2405
2406 Individual octets can be represented using the following shortcuts :
2407
2408 1. C{*} - the asterisk octet (represents values 0 through 255)
2409 2. C{'x-y'} - the hyphenated octet (represents values x through y)
2410
2411 A few basic rules also apply :
2412
2413 1. x must always be greater than y, therefore :
2414
2415 - x can only be 0 through 254
2416 - y can only be 1 through 255
2417
2418 2. only one hyphenated octet per wildcard is allowed
2419 3. only asterisks are permitted after a hyphenated octet
2420
2421 Example wildcards ::
2422
2423 '192.168.0.1' # a single address
2424 '192.168.0.0-31' # 32 addresses
2425 '192.168.0.*' # 256 addresses
2426 '192.168.0-1.*' # 512 addresses
2427 '192.168-169.*.*' # 131,072 addresses
2428 '*.*.*.*' # the whole IPv4 address space
2429
2430 Aside
2431 =====
2432 I{Wildcard ranges are not directly equivalent to CIDR blocks as they
2433 can represent address ranges that do not fall on strict bit mask
2434 boundaries. They are very suitable in configuration files being more
2435 obvious and readable than their CIDR equivalents, especially for admins
2436 and users without much networking knowledge or experience.}
2437
2438 I{All CIDR blocks can always be represented as wildcard ranges but the
2439 reverse is not true. Wildcards are almost but not quite as flexible
2440 as IPRange objects.}
2441 """
2442 STRATEGIES = (ST_IPV4,)
2443 ADDR_TYPES = (AT_UNSPEC, AT_INET)
2444
2445
2446 strategy = StrategyDescriptor(STRATEGIES)
2447 addr_type = AddrTypeDescriptor(ADDR_TYPES)
2448 fmt = FormatDescriptor(IP)
2449
2451 """
2452 A static method that validates wildcard address ranges.
2453
2454 @param wildcard: an IPv4 wildcard address.
2455
2456 @return: True if wildcard address is valid, False otherwise.
2457 """
2458
2459
2460
2461
2462 seen_hyphen = False
2463 seen_asterisk = False
2464 try:
2465 octets = wildcard.split('.')
2466 if len(octets) != 4:
2467 return False
2468 for o in octets:
2469 if '-' in o:
2470 if seen_hyphen:
2471 return False
2472 seen_hyphen = True
2473 if seen_asterisk:
2474
2475 return False
2476 (o1, o2) = [int(i) for i in o.split('-')]
2477 if o1 >= o2:
2478 return False
2479 if not 0 <= o1 <= 254:
2480 return False
2481 if not 1 <= o2 <= 255:
2482 return False
2483 elif o == '*':
2484 seen_asterisk = True
2485 else:
2486 if seen_hyphen is True:
2487 return False
2488 if seen_asterisk is True:
2489 return False
2490 if not 0 <= int(o) <= 255:
2491 return False
2492 except AttributeError:
2493 return False
2494 except ValueError:
2495 return False
2496 return True
2497
2498 is_valid = staticmethod(is_valid)
2499
2501 """
2502 Constructor.
2503
2504 @param wildcard: a valid IPv4 wildcard address
2505
2506 @param fmt: (optional) callable used on return values.
2507 Default: L{IP} objects. See L{nrange()} documentations for
2508 more details on the various options..
2509 """
2510 if not Wildcard.is_valid(wildcard):
2511 raise AddrFormatError('%r is not a recognised wildcard address!' \
2512 % wildcard)
2513 t1 = []
2514 t2 = []
2515
2516 for octet in wildcard.split('.'):
2517 if '-' in octet:
2518 oct_tokens = octet.split('-')
2519 t1 += [oct_tokens[0]]
2520 t2 += [oct_tokens[1]]
2521 elif octet == '*':
2522 t1 += ['0']
2523 t2 += ['255']
2524 else:
2525 t1 += [octet]
2526 t2 += [octet]
2527
2528 first = '.'.join(t1)
2529 last = '.'.join(t2)
2530 super(Wildcard, self).__init__(first, last, fmt=fmt)
2531
2532 if self.addr_type != AT_INET:
2533 raise AddrFormatError('Wildcard syntax only supports IPv4!')
2534
2536 t1 = self.strategy.int_to_words(self.first)
2537 t2 = self.strategy.int_to_words(self.last)
2538
2539 tokens = []
2540
2541 seen_hyphen = False
2542 seen_asterisk = False
2543
2544 for i in range(4):
2545 if t1[i] == t2[i]:
2546
2547 tokens.append(str(t1[i]))
2548 elif (t1[i] == 0) and (t2[i] == 255):
2549
2550 tokens.append('*')
2551 seen_asterisk = True
2552 else:
2553
2554 if not seen_asterisk:
2555 if not seen_hyphen:
2556 tokens.append('%s-%s' % (t1[i], t2[i]))
2557 seen_hyphen = True
2558 else:
2559 raise AddrFormatError('only one hyphenated octet ' \
2560 ' per wildcard allowed!')
2561 else:
2562 raise AddrFormatError('asterisks not permitted before ' \
2563 'hyphenated octets!')
2564
2565 return '.'.join(tokens)
2566
2568 """@return: executable Python string to recreate equivalent object."""
2569 return "%s(%r)" % (self.__class__.__name__, str(self))
2570
2574 """
2575 B{*EXPERIMENTAL*} A customised Python set class that deals with collections
2576 of IPRange class and subclass instances.
2577 """
2579 """
2580 Constructor.
2581
2582 @param addrs: A sequence of IPRange class/subclass instances used to
2583 pre-populate the set. Individual CIDR objects can be added and
2584 removed after instantiation with the usual set methods, add() and
2585 remove().
2586 """
2587 for addr in addrs:
2588 if isinstance(addr, IP):
2589 self.add(addr.cidr())
2590 if isinstance(addr, str):
2591 try:
2592 self.add(CIDR(addr))
2593 except:
2594 pass
2595 try:
2596 ip = IP(addr)
2597 self.add(ip.cidr())
2598 except:
2599 pass
2600 try:
2601 wildcard = Wildcard(addr)
2602 try:
2603 self.add(wildcard.cidr())
2604 except:
2605 self.add(wildcard)
2606 except:
2607 pass
2608 else:
2609 self.add(addr)
2610
2612 """
2613 @return: True if C{other} IP or IPRange class/subclass instance
2614 matches any of the members in this IPRangeSet, False otherwise.
2615 """
2616 for addr in self:
2617 if other in addr:
2618 return True
2619
2621 """
2622 @param other: An IP or IPRange class/subclass instance.
2623
2624 @return: The first IP or IPRange class/subclass instance object that
2625 matches C{other} from any of the members in this IPRangeSet, None
2626 otherwise.
2627 """
2628 for addr in self:
2629 if other in addr:
2630 return addr
2631
2633 """
2634 @param other: An IP or IPRange class/subclass instance.
2635
2636 @return: All IP or IPRange class/subclass instances matching C{other}
2637 from this IPRangeSet, an empty list otherwise.
2638 """
2639 addrs = []
2640 for addr in self:
2641 if other in addr:
2642 addrs.append(addr)
2643 return addrs
2644
2646 """
2647 @param other: An IP or IPRange class/subclass instance.
2648
2649 @return: The smallest IP or IPRange class/subclass instance matching
2650 C{other} from this IPRangeSet, None otherwise.
2651 """
2652 addrs = self.all_matches(other)
2653 addrs.sort()
2654 return addrs[0]
2655
2657 """
2658 @param other: An IP or IPRange class/subclass instance.
2659
2660 @return: The largest IP or IPRange class/subclass instance matching
2661 C{other} from this IPRangeSet, None otherwise.
2662 """
2663 addrs = self.all_matches(other)
2664 addrs.sort()
2665 return addrs[-1]
2666