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