1
2
3
4
5
6
7 """
8 network address classes (IP, EUI) and associated aggregate classes (CIDR,
9 Wilcard, etc).
10 """
11 import math as _math
12 import socket as _socket
13
14 from netaddr import AddrFormatError, AddrConversionError, AT_UNSPEC, \
15 AT_INET, AT_INET6, AT_LINK, AT_EUI64, AT_NAMES
16
17 from netaddr.strategy import ST_IPV4, ST_IPV6, ST_EUI48, ST_EUI64, \
18 AddrStrategy
19
20
21 AT_STRATEGIES = {
22 AT_UNSPEC : None,
23 AT_INET : ST_IPV4,
24 AT_INET6 : ST_IPV6,
25 AT_LINK : ST_EUI48,
26 AT_EUI64 : ST_EUI64,
27 }
28
29
30
31
32
34 """
35 A descriptor that checks addr_type property assignments for validity and
36 also keeps the strategy property in sync with any changes made.
37 """
39 """
40 Constructor.
41
42 @param addr_types: a list of address types constants that are
43 acceptable for assignment to the addr_type property.
44 """
45 self.addr_types = addr_types
46
47 - def __set__(self, instance, value):
48 if value not in self.addr_types:
49 raise ValueError('addr_type %r is invalid for objects of ' \
50 'the %s() class!' % (value, instance.__class__.__name__))
51 instance.__dict__['addr_type'] = value
52 instance.__dict__['strategy'] = AT_STRATEGIES[value]
53
54
56 """
57 A descriptor that checks assignments to the named parameter passed to the
58 constructor. It accepts network addresses in either string format or as
59 network byte order integers. String based addresses are converted to their
60 integer equivalents before assignment to the named parameter. Also ensures
61 that addr_type and strategy are set correctly when parsing string based
62 addresses.
63 """
65 """
66 Descriptor constructor.
67
68 @param name: the name of attribute which will be assigned the value.
69 """
70 self.name = name
71
72 - def __set__(self, instance, value):
101
102
104 """
105 A descriptor that checks strategy property assignments for validity and
106 also keeps the addr_type property in sync with any changes made.
107 """
109 """
110 Constructor.
111
112 @param strategies: a list of strategy objects that are acceptable for
113 assignment to the strategy property.
114 """
115 self.strategies = strategies
116
117 - def __set__(self, instance, value):
118 if value not in self.strategies:
119 raise Exception('%r is not a supported strategy!' % value)
120 instance.__dict__['strategy'] = value
121 instance.__dict__['addr_type'] = instance.strategy.addr_type
122
123
125 """
126 A descriptor that checks prefixlen property assignments for validity based
127 on address type. Also accepts subnet masks which can easily be converted
128 to the equivalent prefixlen integer.
129 """
130 - def __set__(self, instance, value):
155
156
158 """
159 A descriptor that checks klass (data flavour) property assignments for
160 validity.
161 """
163 """
164 Constructor.
165
166 @param default_klass: the default class to use if klass property is
167 set to None.
168 """
169 self.default_klass = default_klass
170
171 - def __set__(self, instance, value):
172 if isinstance(value, type):
173 if value in (str, int, long, unicode):
174 pass
175 elif issubclass(value, Addr):
176 pass
177 else:
178 raise TypeError("%r is an unsupported klass type!" % value)
179 elif value is hex:
180
181 pass
182 elif value is None:
183
184 value = self.default_klass
185 else:
186 raise ValueError("%r is not a supported type, BIF or class!" \
187 % value)
188
189 instance.__dict__['klass'] = value
190
191
192
193
194
196 """
197 The base class containing common functionality for all subclasses
198 representing various network address types.
199
200 It is a fully functioning class (as opposed to a virtual class) with a
201 heuristic constructor that detects the type of address via the first
202 argument if it is a string and sets itself up accordingly. If the first
203 argument is an integer, then a constant must be provided via the second
204 argument indicating the address type explicitly.
205
206 Objects of this class behave differently dependent upon the type of address
207 they represent.
208 """
209 STRATEGIES = (ST_IPV4, ST_IPV6, ST_EUI48, ST_EUI64)
210 ADDR_TYPES = (AT_UNSPEC, AT_INET, AT_INET6, AT_LINK, AT_EUI64)
211
212
213 value = AddrValueDescriptor('value')
214 strategy = StrategyDescriptor(STRATEGIES)
215 addr_type = AddrTypeDescriptor(ADDR_TYPES)
216
218 """
219 Constructor.
220
221 @param addr: the string form of a network address, or a network byte
222 order integer within the supported range for the address type.
223
224 @param addr_type: (optional) the network address type. If addr is an
225 integer, this argument becomes mandatory.
226 """
227 self.addr_type = addr_type
228 self.value = addr
229
231 """
232 @return: The hash of this address. Allows it to be used in sets and
233 as a key in dictionaries.
234 """
235 return hash((self.value, self.addr_type))
236
238 """
239 @return: The value of this address as an network byte order integer.
240 """
241 return self.value
242
244 """
245 @return: The value of this address as an network byte order integer.
246 """
247 return self.value
248
250 """
251 @return: The common string representation for this address type.
252 """
253 return self.strategy.int_to_str(self.value)
254
256 """
257 @return: An executable Python statement that can recreate an object
258 with an equivalent state.
259 """
260 return "netaddr.address.%s(%r)" % (self.__class__.__name__, str(self))
261
263 """
264 @return: A human-readable binary digit string for this address type.
265 """
266 return self.strategy.int_to_bits(self.value)
267
269 """
270 @return: The size of this address (in bits).
271 """
272 return self.strategy.width
273
275 """
276 @return: An iterator over individual words in this address.
277 """
278 return iter(self.strategy.int_to_words(self.value))
279
281 """
282 @return: The integer value of the word indicated by index. Raises an
283 C{IndexError} if index is wrong size for address type. Full
284 slicing is also supported.
285 """
286 if isinstance(index, (int, long)):
287
288 word_count = self.strategy.word_count
289 if not (-word_count) <= index <= (word_count - 1):
290 raise IndexError('index out range for address type!')
291 return self.strategy.int_to_words(self.value)[index]
292 elif isinstance(index, slice):
293
294 words = self.strategy.int_to_words(self.value)
295 return [words[i] for i in range(*index.indices(len(words)))]
296 else:
297 raise TypeError('unsupported type %r!' % index)
298
300 """
301 Sets the value of the word of this address indicated by index.
302 """
303 if isinstance(index, slice):
304
305 raise NotImplementedError('settable slices not yet supported!')
306
307 if not isinstance(index, (int, long)):
308 raise TypeError('index not an integer!')
309
310 if not 0 <= index <= (self.strategy.word_count - 1):
311 raise IndexError('index %d outside address type boundary!' % index)
312
313 if not isinstance(value, (int, long)):
314 raise TypeError('value not an integer!')
315
316 if not 0 <= value <= (2 ** self.strategy.word_size - 1):
317 raise IndexError('value %d outside word size maximum of %d bits!'
318 % (value, self.strategy.word_size))
319
320 words = list(self.strategy.int_to_words(self.value))
321 words[index] = value
322 self.value = self.strategy.words_to_int(words)
323
325 """
326 @return: The value of this address as a network byte order hexadecimal
327 number.
328 """
329 return hex(self.value).rstrip('L').lower()
330
332 """
333 Increments network address by specified value.
334
335 If the result exceeds address type maximum, it rolls around the
336 minimum boundary.
337 """
338 try:
339 new_value = self.value + i
340 if new_value > self.strategy.max_int:
341 self.value = new_value - (self.strategy.max_int + 1)
342 else:
343 self.value = new_value
344 except TypeError:
345 raise TypeError('Increment value must be an integer!')
346 return self
347
349 """
350 Decrements network address by specified value.
351
352 If the result exceeds address type minimum, it rolls around the
353 maximum boundary.
354 """
355 try:
356 new_value = self.value - i
357 if new_value < self.strategy.min_int:
358 self.value = new_value + (self.strategy.max_int + 1)
359 else:
360 self.value = new_value
361 except TypeError:
362 raise TypeError('Decrement value must be an integer!')
363 return self
364
366 """
367 @return: C{True} if this network address instance has the same
368 numerical value as another, C{False} otherwise.
369 """
370 try:
371 if (self.addr_type, self.value) == (other.addr_type, other.value):
372 return True
373 except AttributeError:
374 pass
375
376 return False
377
379 """
380 @return: C{True} if this network address instance does not have the
381 same numerical value as another, C{False} otherwise.
382 """
383 try:
384 if (self.addr_type, self.value) != (other.addr_type, other.value):
385 return True
386 except AttributeError:
387 pass
388
389 return False
390
392 """
393 @return: C{True} if this network address instance has a lower
394 numerical value than another, C{False} otherwise.
395 """
396 try:
397 if (self.addr_type, self.value) < (other.addr_type, other.value):
398 return True
399 except AttributeError:
400 pass
401
402 return False
403
405 """
406 @return: C{True} if this network address instance has a lower or
407 equivalent numerical value than another, C{False} otherwise.
408 """
409 try:
410 if (self.addr_type, self.value) <= (other.addr_type, other.value):
411 return True
412 except AttributeError:
413 pass
414
415 return False
416
418 """
419 @return: C{True} if this network address instance has a higher
420 numerical value than another, C{False} otherwise.
421 """
422 try:
423 if (self.addr_type, self.value) > (other.addr_type, other.value):
424 return True
425 except AttributeError:
426 pass
427
428 return False
429
431 """
432 @return: C{True} if this network address instance has a higher or
433 equivalent numerical value than another, C{False} otherwise.
434 """
435 try:
436 if (self.addr_type, self.value) >= (other.addr_type, other.value):
437 return True
438 except AttributeError:
439 pass
440
441 return False
442
443
445 """
446 EUI objects represent IEEE Extended Unique Identifiers. Input parsing is
447 flexible, supporting EUI-48, EUI-64 and all MAC (Media Access Control)
448 address flavours.
449 """
450 STRATEGIES = (ST_EUI48, ST_EUI64)
451 ADDR_TYPES = (AT_UNSPEC, AT_LINK, AT_EUI64)
452
453
454 strategy = StrategyDescriptor(STRATEGIES)
455 addr_type = AddrTypeDescriptor(ADDR_TYPES)
456
458 """
459 Constructor.
460
461 @param addr: an EUI/MAC address string or a network byte order
462 integer.
463
464 @param addr_type: (optional) the specific EUI address type (C{AT_LINK}
465 or C{AT_EUI64}). If addr is an integer, this argument is mandatory.
466 """
467 super(EUI, self).__init__(addr, addr_type)
468
470 """
471 @return: The OUI (Organisationally Unique Identifier) for this EUI.
472 """
473 return '-'.join(["%02x" % i for i in self[0:3]]).upper()
474
476 """
477 @return: The EI (Extension Identifier) for this EUI.
478 """
479 if self.strategy == ST_EUI48:
480 return '-'.join(["%02x" % i for i in self[3:6]]).upper()
481 elif self.strategy == ST_EUI64:
482 return '-'.join(["%02x" % i for i in self[3:8]]).upper()
483
485 """
486 @return: The value of this EUI object as a new 64-bit EUI object.
487 - If this object represents an EUI-48 it is converted to EUI-64 as
488 per the standard.
489 - If this object is already and EUI-64, it just returns a new,
490 numerically equivalent object is returned instead.
491 """
492 if self.addr_type == AT_LINK:
493 eui64_words = ["%02x" % i for i in self[0:3]] + ['ff', 'fe'] + \
494 ["%02x" % i for i in self[3:6]]
495
496 return self.__class__('-'.join(eui64_words))
497 else:
498 return EUI(str(self))
499
501 """
502 @return: An IPv6 L{IP} object initialised using the value of this
503 L{EUI}.
504 - B{See RFC 4921 for details}.
505 """
506 prefix = 'fe80:0000:0000:0000:'
507
508
509 self[0] += 2
510
511 if self.addr_type == AT_LINK:
512
513 suffix = ["%02x" % i for i in self[0:3]] + ['ff', 'fe'] + \
514 ["%02x" % i for i in self[3:6]]
515 else:
516 suffix = ["%02x" % i for i in list(self)]
517
518 suffix = ["%02x%02x" % (int(x[0], 16), int(x[1], 16)) for x in \
519 zip(suffix[::2], suffix[1::2])]
520
521
522 self[0] -= 2
523
524 eui64 = ':'.join(suffix)
525 addr = prefix + eui64
526 return IP(addr)
527
528
530 """
531 A class whose objects represent Internet Protocol network addresses. Both
532 IPv4 and IPv6 are fully supported and also permit the inclusion of bitmask
533 prefix or subnet mask address indicating the size/extent of the subnet,
534 for example ::
535
536 IPv4
537
538 192.168.0.1/24
539 192.168.0.1/255.255.255.0
540
541 IPv6
542
543 fe80::20f:1fff:fe12:e733/64
544 """
545 STRATEGIES = (ST_IPV4, ST_IPV6)
546 ADDR_TYPES = (AT_UNSPEC, AT_INET, AT_INET6)
547 TRANSLATE_STR = ''.join([chr(i) for i in range(256)])
548 del i
549
550
551 strategy = StrategyDescriptor(STRATEGIES)
552 addr_type = AddrTypeDescriptor(ADDR_TYPES)
553 prefixlen = PrefixLenDescriptor()
554
556 """
557 Constructor.
558
559 @param addr: an IPv4 or IPv6 address string with an optional subnet
560 prefix or a network byte order integer.
561
562 @param addr_type: (optional) the IP address type (C{AT_INET} or
563 C{AT_INET6}). If L{addr} is an integer, this argument is mandatory.
564 """
565 prefixlen = None
566
567 try:
568 if '/' in addr:
569 (addr, prefixlen) = addr.split('/', 1)
570 except TypeError:
571
572 pass
573
574
575
576 super(IP, self).__init__(addr, addr_type)
577
578
579 if prefixlen is None:
580 self.prefixlen = self.strategy.width
581 else:
582 self.prefixlen = prefixlen
583
585 """
586 @return: C{True} if this addr is a mask that would return a host id,
587 C{False} otherwise.
588 """
589
590
591 bits = self.strategy.int_to_bits(self.value).replace('.', '')
592
593 if bits[0] != '1':
594
595 return False
596
597
598 bits = bits.lstrip('1')
599
600 seen_zero = False
601 for i in bits:
602 if i == '0' and seen_zero is False:
603 seen_zero = True
604 elif i == '1' and seen_zero is True:
605 return False
606
607 return True
608
610 """
611 @return: If this address is a valid netmask, the number of non-zero
612 bits are returned, otherwise it returns the width (in bits) for the
613 given address type (IPv4: 32, IPv6: 128).
614 """
615 if not self.is_netmask():
616 return self.strategy.width
617
618 bits = self.strategy.int_to_bits(self.value)
619 mask_bits = bits.translate(IP.TRANSLATE_STR, ':.0')
620 mask_length = len(mask_bits)
621
622 if not 1 <= mask_length <= self.strategy.width:
623 raise ValueError('Unexpected mask length %d for address type!' \
624 % mask_length)
625
626 return mask_length
627
629 """
630 @return: The reverse DNS lookup string for this IP address.
631 """
632 return self.strategy.int_to_arpa(self.value)
633
635 """
636 @return: C{True} if this address is a mask that would return a host
637 id, C{False} otherwise.
638 """
639
640
641 bits = self.strategy.int_to_bits(self.value).replace('.', '')
642
643 if bits[0] != '0':
644
645 return False
646
647
648 bits = bits.lstrip('0')
649
650 seen_one = False
651 for i in bits:
652 if i == '1' and seen_one is False:
653 seen_one = True
654 elif i == '0' and seen_one is True:
655 return False
656
657 return True
658
660 """
661 @return: Returns the FQDN for this IP address via a DNS query
662 using gethostbyaddr() Python's socket module.
663 """
664 return _socket.gethostbyaddr(str(self))[0]
665
674
676 """
677 @return: A new L{IP} object numerically equivalent this address.
678 - If its address type is IPv4.
679 - If object's address type is IPv6 and its value is mappable to
680 IPv4, a new IPv4 L{IP} object is returned instead.
681 - Raises an L{AddrConversionError} if IPv6 address is not mappable
682 to IPv4.
683 """
684 ip_addr = None
685 if self.addr_type == AT_INET:
686 ip_addr = IP(self.value, AT_INET)
687 elif self.addr_type == AT_INET6:
688 words = self.strategy.int_to_words(self.value)
689 if words[0:6] == (0,0,0,0,0,0):
690 ip_addr = IP(self.value, AT_INET)
691 elif words[0:6] == (0,0,0,0,0,65535):
692 ip_addr = IP(self.value - 0xffff00000000, AT_INET)
693 else:
694 raise AddrConversionError('IPv6 address %s too large for ' \
695 'conversion to IPv4!' % self)
696 return ip_addr
697
699 """
700 @return: A new L{IP} object numerically equivalent this address.
701 - If object's address type is IPv6.
702 - If object's address type is IPv4 a new IPv6 L{IP} object, as a
703 IPv4 mapped address is returned instead. Uses the preferred IPv4
704 embedded in IPv6 form - C{::ffff:x.x.x.x} ('mapped' address) over
705 the (now deprecated) form - C{::x.x.x.x} ('compatible' address).
706 B{See RFC 4921 for details}.
707 """
708 ip_addr = None
709 if self.addr_type == AT_INET6:
710 ip_addr = IP(self.value, AT_INET6)
711 elif self.addr_type == AT_INET:
712 ip_addr = IP(self.value, AT_INET6)
713 ip_addr[5] = 0xffff
714 return ip_addr
715
717 """
718 @return: C{True} if this address is unicast, C{False} otherwise.
719 """
720 if self.is_multicast():
721 return False
722 return True
723
725 """
726 @return: C{True} if this address is multicast, C{False} otherwise.
727 """
728 if self.addr_type == AT_INET:
729 if 0xe0000000 <= self.value <= 0xefffffff:
730 return True
731 elif self.addr_type == AT_INET6:
732 if 0xff000000000000000000000000000000 <= self.value <= \
733 0xffffffffffffffffffffffffffffffff:
734 return True
735 return False
736
738 """
739 @return: The common string representation for this IP address.
740 """
741 return self.strategy.int_to_str(self.value)
742
744 """
745 @return: An executable Python statement that can recreate an object
746 with an equivalent state.
747 """
748 if self.prefixlen == self.strategy.width:
749 return "netaddr.address.%s('%s')" % (self.__class__.__name__,
750 str(self))
751
752 return "netaddr.address.%s('%s/%d')" % (self.__class__.__name__,
753 str(self), self.prefixlen)
754
755
756
757
758
759 -def nrange(start, stop, step=1, klass=None):
760 """
761 A generator producing sequences of network addresses based on start and
762 stop values, in intervals of step.
763
764 @param start: first network address as string or instance of L{Addr}
765 (sub)class.
766
767 @param stop: last network address as string or instance of L{Addr}
768 (sub)class.
769
770 @param step: (optional) size of step between addresses in range.
771 Default is 1.
772
773 @param klass: (optional) the class used to create objects returned.
774 Default: L{Addr} class.
775
776 - C{str} returns string representation of network address
777 - C{int}, C{long} and C{hex} return expected values
778 - L{Addr} (sub)class or duck type* return objects of that class. If
779 you use your own duck class, make sure you handle both arguments
780 C{(addr_value, addr_type)} passed to the constructor.
781 """
782 if not issubclass(start.__class__, Addr):
783 if isinstance(start, (str, unicode)):
784 start = Addr(start)
785 else:
786 raise TypeError('start is not recognised address in string ' \
787 'format or an that is a (sub)class of Addr!')
788 else:
789
790 if klass is None:
791 klass = start.__class__
792
793 if not issubclass(stop.__class__, Addr):
794 if isinstance(stop, (str, unicode)):
795 stop = Addr(stop)
796 else:
797 raise TypeError('stop is not recognised address in string ' \
798 'format or an that is a (sub)class of Addr!')
799
800 if not isinstance(step, (int, long)):
801 raise TypeError('step must be type int|long, not %s!' % type(step))
802
803 if start.addr_type != stop.addr_type:
804 raise TypeError('start and stop are not the same address type!')
805
806 if step == 0:
807 raise ValueError('step argument cannot be zero')
808
809 negative_step = False
810 addr_type = start.addr_type
811
812
813
814 start_klass = start.__class__
815 start = int(start)
816 stop = int(stop)
817
818 if step < 0:
819 negative_step = True
820
821 index = start - step
822
823
824 if klass is None:
825 klass = Addr
826
827 if klass in (int, long, hex):
828
829 while True:
830 index += step
831 if negative_step:
832 if not index >= stop:
833 return
834 else:
835 if not index <= stop:
836 return
837 yield klass(index)
838 elif klass in (str, unicode):
839
840 while True:
841 index += step
842 if negative_step:
843 if not index >= stop:
844 return
845 else:
846 if not index <= stop:
847 return
848 yield str(start_klass(index, addr_type))
849 else:
850
851 while True:
852 index += step
853 if negative_step:
854 if not index >= stop:
855 return
856 else:
857 if not index <= stop:
858 return
859
860 yield klass(index, addr_type)
861
862
864 """
865 A block of contiguous network addresses bounded by an arbitrary start and
866 stop address. There is no requirement that they fall on strict bit mask
867 boundaries, unlike L{CIDR} addresses.
868
869 This is the only network address aggregate supporting all network address
870 types. Most AddrRange subclasses usually only support a subset of address
871 types.
872
873 A sequence of address ranges sort first by address type then by magnitude.
874 So for a list containing ranges of all currently supported address types,
875 IPv4 ranges come first, then IPv6, EUI-48 and lastly EUI-64.
876 """
877 STRATEGIES = (ST_IPV4, ST_IPV6, ST_EUI48, ST_EUI64)
878 ADDR_TYPES = (AT_UNSPEC, AT_INET, AT_INET6, AT_LINK, AT_EUI64)
879
880
881 strategy = StrategyDescriptor(STRATEGIES)
882 addr_type = AddrTypeDescriptor(ADDR_TYPES)
883 first = AddrValueDescriptor('first')
884 last = AddrValueDescriptor('last')
885 klass = KlassDescriptor(Addr)
886
888 """
889 Constructor.
890
891 @param first: start address for this network address range.
892
893 @param last: stop address for this network address range.
894
895 @param klass: (optional) class used to create each object returned.
896 Default: L{Addr()} objects. See L{nrange()} documentations for
897 additional details on options.
898 """
899 self.addr_type = AT_UNSPEC
900 self.first = first
901 self.last = last
902 if self.last < self.first:
903 raise IndexError('start address is greater than stop address!')
904 self.klass = klass
905
907 """
908 @return: The hash of this address range. Allow them to be used in sets
909 and as keys in dictionaries.
910 """
911 return hash((self.first, self.last, self.addr_type))
912
914 """
915 @return: The total number of network addresses in this range.
916 - Use this method only for ranges that contain less than
917 C{2^31} addresses or try the L{size()} method. Raises an
918 C{IndexError} if size is exceeded.
919 """
920 size = self.size()
921 if size > (2 ** 31):
922
923 raise IndexError("range contains more than 2^31 addresses! " \
924 "Use size() method instead.")
925 return size
926
928 """
929 @return: The total number of network addresses in this range.
930 - Use this method in preference to L{__len__()} when size of
931 ranges exceeds C{2^31} addresses.
932 """
933 return self.last - self.first + 1
934
936 """
937 @param int_addr: an network address as a network byte order integer.
938
939 @return: a network address in whatever 'flavour' is required based on
940 the value of the klass property.
941 """
942 if self.klass in (str, unicode):
943 return self.strategy.int_to_str(int_addr)
944 elif self.klass in (int, long, hex):
945 return self.klass(int_addr)
946 else:
947 return self.klass(int_addr, self.addr_type)
948
950 """
951 @return: The network address(es) in this address range indicated by
952 index/slice. Slicing objects can produce large sequences so
953 generator objects are returned instead to the usual sequences.
954 Wrapping a raw slice with C{list()} or C{tuple()} may be required
955 dependent on context.
956 """
957
958 if isinstance(index, (int, long)):
959 if (- self.size()) <= index < 0:
960
961 return self.data_flavour(self.last + index + 1)
962 elif 0 <= index <= (self.size() - 1):
963
964 return self.data_flavour(self.first + index)
965 else:
966 raise IndexError('index out range for address range size!')
967 elif isinstance(index, slice):
968
969
970
971
972
973
974
975
976 (start, stop, step) = index.indices(self.size())
977
978 start_addr = Addr(self.first + start, self.addr_type)
979 end_addr = Addr(self.first + stop - step, self.addr_type)
980 return nrange(start_addr, end_addr, step, klass=self.klass)
981 else:
982 raise TypeError('unsupported type %r!' % index)
983
985 """
986 @return: An iterator object providing access to all network addresses
987 within this range.
988 """
989 start_addr = Addr(self.first, self.addr_type)
990 end_addr = Addr(self.last, self.addr_type)
991 return nrange(start_addr, end_addr, klass=self.klass)
992
994 """
995 @param addr: object of Addr/AddrRange (sub)class or a network address
996 string to be compared.
997
998 @return: C{True} if given address or range falls within this range,
999 C{False} otherwise.
1000 """
1001 if isinstance(addr, (str, unicode)):
1002
1003 c_addr = Addr(addr)
1004 if c_addr.addr_type == self.addr_type:
1005 if self.first <= int(c_addr) <= self.last:
1006 return True
1007 elif issubclass(addr.__class__, Addr):
1008
1009 if self.first <= int(addr) <= self.last:
1010 return True
1011 elif issubclass(addr.__class__, AddrRange):
1012
1013 if addr.first >= self.first and addr.last <= self.last:
1014 return True
1015 else:
1016 raise TypeError('%r is an unsupported type or class!' % addr)
1017
1018 return False
1019
1021 """
1022 @param other: an address object of the same address type as C{self}.
1023
1024 @return: C{True} if the boundaries of this range are the same as
1025 other, C{False} otherwise.
1026 """
1027 try:
1028 if (self.addr_type, self.first, self.last) == \
1029 (other.addr_type, other.first, other.last):
1030 return True
1031 except AttributeError:
1032 pass
1033
1034 return False
1035
1037 """
1038 @param other: an address object of the same address type as C{self}.
1039
1040 @return: C{True} if the boundaries of this range are not the same as
1041 other, C{False} otherwise.
1042 """
1043 try:
1044 if (self.addr_type, self.first, self.last) != \
1045 (other.addr_type, other.first, other.last):
1046 return True
1047 except AttributeError:
1048 pass
1049
1050 return False
1051
1053 """
1054 @param other: an address object of the same address type as C{self}.
1055
1056 @return: C{True} if the boundaries of this range are less than other,
1057 C{False} otherwise.
1058 """
1059 try:
1060 if (self.addr_type, self.first, self.last) < \
1061 (other.addr_type, other.first, other.last):
1062 return True
1063 except AttributeError:
1064 pass
1065
1066 return False
1067
1069 """
1070 @param other: an address object of the same address type as C{self}.
1071
1072 @return: C{True} if the boundaries of this range are less or equal to
1073 other, C{False} otherwise.
1074 """
1075 try:
1076 if (self.addr_type, self.first, self.last) <= \
1077 (other.addr_type, other.first, other.last):
1078 return True
1079 except AttributeError:
1080 pass
1081
1082 return False
1083
1085 """
1086 @param other: an address object of the same address type as C{self}.
1087
1088 @return: C{True} if the boundaries of this range are greater than
1089 other, C{False} otherwise.
1090 """
1091 try:
1092 if (self.addr_type, self.first, self.last) > \
1093 (other.addr_type, other.first, other.last):
1094 return True
1095 except AttributeError:
1096 pass
1097
1098 return False
1099
1101 """
1102 @param other: an address object of the same address type as C{self}.
1103
1104 @return: C{True} if the boundaries of this range are greater or equal
1105 to other, C{False} otherwise.
1106 """
1107 try:
1108 if (self.addr_type, self.first, self.last) >= \
1109 (other.addr_type, other.first, other.last):
1110 return True
1111 except AttributeError:
1112 pass
1113
1114 return False
1115
1117 """
1118 Increments start and end addresses of this range by the current size.
1119
1120 If the result exceeds address type range for the address type an
1121 IndexError is raised.
1122 """
1123 try:
1124 new_first = self.first + (self.size() * i)
1125 new_last = self.last + (self.size() * i)
1126 except TypeError:
1127 raise TypeError('Increment value must be an integer!')
1128
1129 if new_last > self.strategy.max_int:
1130 raise IndexError('Invalid increment is outside address boundary!')
1131
1132 self.first = new_first
1133 self.last = new_last
1134
1135 return self
1136
1138 """
1139 Decrements start and end addresses of this range by the current size.
1140
1141 If the result less than zero an IndexError is raised.
1142 """
1143 try:
1144 new_first = self.first - (self.size() * i)
1145 new_last = self.last - (self.size() * i)
1146 except TypeError:
1147 raise TypeError('Decrement value must be an integer!')
1148
1149 if new_last < self.strategy.min_int:
1150 raise IndexError('Invalid decrement is outside address boundary!')
1151
1152 self.first = new_first
1153 self.last = new_last
1154
1155 return self
1156
1160
1162 """
1163 @return: An executable Python statement that can recreate an object
1164 with an equivalent state.
1165 """
1166 return "netaddr.address.%s(%r, %r)" % (self.__class__.__name__,
1167 self.strategy.int_to_str(self.first),
1168 self.strategy.int_to_str(self.last))
1169
1170
1171 -class CIDR(AddrRange):
1172 """
1173 A block of contiguous IPv4 or IPv6 network addresses defined by a base
1174 network address and a bitmask prefix or subnet mask address indicating the
1175 size/extent of the subnet.
1176
1177 By default, this class does not allow any non-zero bits to be set right
1178 of the bitmask when it is applied to the supplied base address. Doing so
1179 raises an L{AddrFormatError} exception. However, it is now configurable
1180 and will allow a less strict base address if you ask for one. Be aware
1181 though that the bitmask will be applied to the base address and and
1182 trailing non-zero bits removed losing the original address. It will *not*
1183 be preserved!
1184
1185 Contrast this behaviour with the L{IP} class which is less strict and has
1186 a cidr() method for returning CIDR objects without any loss of
1187 information.
1188
1189 Examples of supported formats :-
1190
1191 1. CIDR address format - C{<address>/<mask_length>}::
1192
1193 192.168.0.0/16
1194 fe80::/64
1195
1196 2. Address and subnet mask combo ::
1197
1198 192.168.0.0/255.255.0.0 == 192.168.0.0/16
1199 fe80::/ffff:ffff:ffff:ffff:: == fe80::/64
1200
1201 3. Partial or abbreviated formats (IPv4 only). Prefixes may be omitted
1202 and in this case older class-based default prefixes apply ::
1203
1204 10 == 10.0.0.0/8
1205 10.0 == 10.0.0.0/8
1206 10/8 == 10.0.0.0/8
1207
1208 128 == 128.0.0.0/16
1209 128.0 == 128.0.0.0/16
1210 128/16 == 128.0.0.0/16
1211
1212 192 == 10.0.0.0/24
1213 192.168.0 == 192.168.0.0/24
1214 192.168/16 == 192.168.0.0/16
1215 """
1216 STRATEGIES = (ST_IPV4, ST_IPV6)
1217 ADDR_TYPES = (AT_UNSPEC, AT_INET, AT_INET6)
1218
1219
1220 strategy = StrategyDescriptor(STRATEGIES)
1221 addr_type = AddrTypeDescriptor(ADDR_TYPES)
1222 prefixlen = PrefixLenDescriptor()
1223 klass = KlassDescriptor(IP)
1224
1226 """
1227 A statis method that converts abbreviated CIDR addresses into their
1228 verbose form.
1229
1230 @param abbrev_cidr: an abbreviated CIDR network address.
1231
1232 Uses the old-style classful IP address rules to decide on a default
1233 subnet prefix if one is not explicitly provided.
1234
1235 Only supports IPv4 addresses.
1236
1237 Examples ::
1238
1239 10 - 10.0.0.0/8
1240 10/16 - 10.0.0.0/16
1241 128 - 128.0.0.0/16
1242 128/8 - 128.0.0.0/8
1243 192.168 - 192.168.0.0/16
1244
1245 @return: A verbose CIDR from an abbreviated CIDR or old-style classful
1246 network address, C{None} if format provided was not recognised or
1247 supported.
1248 """
1249
1250
1251 def classful_prefix(octet):
1252 octet = int(octet)
1253 prefix = 32
1254 if not 0 <= octet <= 255:
1255 raise IndexError('Invalid octet: %r!' % octet)
1256 if 0 <= octet <= 127:
1257
1258 prefix = 8
1259 elif 128 <= octet <= 191:
1260
1261 prefix = 16
1262 elif 192 <= octet <= 223:
1263
1264 prefix = 24
1265 elif octet == 224:
1266
1267 prefix = 4
1268 elif 225 <= octet <= 239:
1269 prefix = 8
1270 return prefix
1271
1272 start = ''
1273 tokens = []
1274 prefix = None
1275
1276
1277 if isinstance(abbrev_cidr, (str, unicode)):
1278
1279
1280 if ':' in abbrev_cidr:
1281 return None
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295 try:
1296
1297 i = int(abbrev_cidr)
1298 tokens = [str(i), '0', '0', '0']
1299 return "%s%s/%s" % (start, '.'.join(tokens), classful_prefix(i))
1300
1301 except ValueError:
1302
1303 part_addr = abbrev_cidr
1304 tokens = []
1305
1306 if part_addr == '':
1307
1308 return None
1309
1310 if '/' in part_addr:
1311 (part_addr, prefix) = part_addr.split('/', 1)
1312
1313
1314 if prefix is not None:
1315 try:
1316 if not 0 <= int(prefix) <= 32:
1317 return None
1318 except ValueError:
1319 return None
1320
1321 if '.' in part_addr:
1322 tokens = part_addr.split('.')
1323 else:
1324 tokens = [part_addr]
1325
1326 if 1 <= len(tokens) <= 4:
1327 for i in range(4 - len(tokens)):
1328 tokens.append('0')
1329 else:
1330
1331 return None
1332
1333 if prefix is None:
1334 try:
1335 prefix = classful_prefix(tokens[0])
1336 except ValueError:
1337 return None
1338
1339 return "%s%s/%s" % (start, '.'.join(tokens), prefix)
1340
1341 except TypeError:
1342 pass
1343 except IndexError:
1344 pass
1345
1346
1347 return None
1348
1349 abbrev_to_verbose = staticmethod(abbrev_to_verbose)
1350
1351 - def __init__(self, cidr, klass=IP, strict_bitmask=True):
1352 """
1353 Constructor.
1354
1355 @param cidr: a valid IPv4/IPv6 CIDR address or abbreviated IPv4
1356 network address.
1357
1358 @param klass: (optional) type, BIF or class used to create each
1359 object returned. Default: L{IP} class. See L{nrange()}
1360 documentations for additional details on options.
1361
1362 @param strict_bitmask: (optional) performs a test to ensure
1363 there are no non-zero bits to the right of the subnet mask or
1364 prefix when it is applied to the base address. (default: True)
1365 """
1366 cidr_arg = cidr
1367
1368
1369 verbose_cidr = CIDR.abbrev_to_verbose(cidr)
1370 if verbose_cidr is not None:
1371 cidr = verbose_cidr
1372
1373 if not isinstance(cidr, str):
1374 raise TypeError('%r is not a valid CIDR!' % cidr)
1375
1376
1377 try:
1378 (network, mask) = cidr.split('/', 1)
1379 except ValueError:
1380 raise AddrFormatError('%r is not a recognised CIDR!' % cidr_arg)
1381
1382 first = IP(network)
1383 self.strategy = first.strategy
1384 self.prefixlen = mask
1385
1386 strategy = first.strategy
1387 addr_type = strategy.addr_type
1388
1389 hostmask = (1 << (strategy.width - self.prefixlen)) - 1
1390 netmask = strategy.max_int ^ hostmask
1391
1392 last = IP(first.value | hostmask, addr_type)
1393
1394 if strict_bitmask:
1395
1396 host = (first.value | netmask) - netmask
1397 if host != 0:
1398 raise ValueError('%s contains non-zero bits right of the ' \
1399 '%d-bit mask! Did you mean %s instead?' \
1400 % (first, self.prefixlen,
1401 strategy.int_to_str(int(last) - hostmask)))
1402 else:
1403
1404 first.value = strategy.int_to_str(int(last) - hostmask)
1405
1406 super(CIDR, self).__init__(first, last, klass)
1407
1409 """
1410 Subtract another CIDR from this one.
1411
1412 @param other: a CIDR object that is greater than or equal to C{self}.
1413
1414 @return: A list of CIDR objects than remain after subtracting C{other}
1415 from C{self}.
1416 """
1417 cidrs = []
1418
1419 if self.prefixlen == self.strategy.width:
1420
1421 return cidrs
1422
1423 new_prefixlen = self.prefixlen + 1
1424 i_lower = self.first
1425 i_upper = self.first + (2 ** (self.strategy.width - new_prefixlen))
1426
1427 lower = CIDR('%s/%d' % (self.strategy.int_to_str(i_lower),
1428 new_prefixlen))
1429 upper = CIDR('%s/%d' % (self.strategy.int_to_str(i_upper),
1430 new_prefixlen))
1431
1432 while other.prefixlen >= new_prefixlen:
1433 if other in lower:
1434 matched = i_lower
1435 unmatched = i_upper
1436 elif other in upper:
1437 matched = i_upper
1438 unmatched = i_lower
1439
1440 cidr = CIDR('%s/%d' % (self.strategy.int_to_str(unmatched),
1441 new_prefixlen))
1442
1443 cidrs.append(cidr)
1444
1445 new_prefixlen += 1
1446
1447 if new_prefixlen > self.strategy.width:
1448 break
1449
1450 i_lower = matched
1451 i_upper = matched + (2 ** (self.strategy.width - new_prefixlen))
1452
1453 lower = CIDR('%s/%d' % (self.strategy.int_to_str(i_lower),
1454 new_prefixlen))
1455 upper = CIDR('%s/%d' % (self.strategy.int_to_str(i_upper),
1456 new_prefixlen))
1457
1458 cidrs.sort()
1459
1460
1461 if self.klass is str:
1462 return [str(cidr) for cidr in cidrs]
1463
1464 return cidrs
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1485
1492
1495
1497 """
1498 @return: An executable Python statement that can recreate an object
1499 with an equivalent state.
1500 """
1501 return "netaddr.address.%s('%s/%d')" % (self.__class__.__name__,
1502 self.strategy.int_to_str(self.first), self.prefixlen)
1503
1505 """
1506 @return: A L{Wildcard} object equivalent to this CIDR.
1507 - If CIDR was initialised with C{klass=str} a wildcard string is
1508 returned, in all other cases a L{Wildcard} object is returned.
1509 - Only supports IPv4 CIDR addresses.
1510 """
1511 t1 = self.strategy.int_to_words(self.first)
1512 t2 = self.strategy.int_to_words(self.last)
1513
1514 if self.addr_type != AT_INET:
1515 raise AddrConversionError('wildcards only suitable for IPv4 ' \
1516 'ranges!')
1517
1518 tokens = []
1519
1520 seen_hyphen = False
1521 seen_asterisk = False
1522
1523 for i in range(4):
1524 if t1[i] == t2[i]:
1525
1526 tokens.append(str(t1[i]))
1527 elif (t1[i] == 0) and (t2[i] == 255):
1528
1529 tokens.append('*')
1530 seen_asterisk = True
1531 else:
1532
1533 if not seen_asterisk:
1534 if not seen_hyphen:
1535 tokens.append('%s-%s' % (t1[i], t2[i]))
1536 seen_hyphen = True
1537 else:
1538 raise SyntaxError('only one hyphenated octet per ' \
1539 'wildcard permitted!')
1540 else:
1541 raise SyntaxError("* chars aren't permitted before ' \
1542 'hyphenated octets!")
1543
1544 wildcard = '.'.join(tokens)
1545
1546 if self.klass == str:
1547 return wildcard
1548
1549 return Wildcard(wildcard)
1550
1551
1553 """
1554 A block of contiguous IPv4 network addresses defined using a wildcard
1555 style syntax.
1556
1557 Individual octets can be represented using the following shortcuts :
1558
1559 1. C{*} - the asterisk octet (represents values 0 through 255)
1560 2. C{'x-y'} - the hyphenated octet (represents values x through y)
1561
1562 A few basic rules also apply :
1563
1564 1. x must always be greater than y, therefore :
1565
1566 - x can only be 0 through 254
1567 - y can only be 1 through 255
1568
1569 2. only one hyphenated octet per wildcard is allowed
1570 3. only asterisks are permitted after a hyphenated octet
1571
1572 Example wildcards ::
1573
1574 '192.168.0.1' # a single address
1575 '192.168.0.0-31' # 32 addresses
1576 '192.168.0.*' # 256 addresses
1577 '192.168.0-1.*' # 512 addresses
1578 '192.168-169.*.*' # 131,072 addresses
1579 '*.*.*.*' # the whole IPv4 address space
1580
1581 Aside
1582 =====
1583 I{Wildcard ranges are not directly equivalent to CIDR ranges as they
1584 can represent address ranges that do not fall on strict bit mask
1585 boundaries.}
1586
1587 I{All CIDR ranges can always be represented as wildcard ranges but the
1588 reverse isn't true in every case.}
1589 """
1590 STRATEGIES = (ST_IPV4, ST_IPV6)
1591 ADDR_TYPES = (AT_UNSPEC, AT_INET, AT_INET6)
1592
1593
1594 strategy = StrategyDescriptor(STRATEGIES)
1595 addr_type = AddrTypeDescriptor(ADDR_TYPES)
1596 klass = KlassDescriptor(IP)
1597
1599 """
1600 A static method that validates wildcard address ranges.
1601
1602 @param wildcard: an IPv4 wildcard address.
1603
1604 @return: True if wildcard address is valid, False otherwise.
1605 """
1606
1607
1608
1609 seen_hyphen = False
1610 seen_asterisk = False
1611 try:
1612 octets = wildcard.split('.')
1613 if len(octets) != 4:
1614 return False
1615 for o in octets:
1616 if '-' in o:
1617 if seen_hyphen:
1618 return False
1619 seen_hyphen = True
1620 if seen_asterisk:
1621
1622 return False
1623 (o1, o2) = [int(i) for i in o.split('-')]
1624 if o1 >= o2:
1625 return False
1626 if not 0 <= o1 <= 254:
1627 return False
1628 if not 1 <= o2 <= 255:
1629 return False
1630 elif o == '*':
1631 seen_asterisk = True
1632 else:
1633 if seen_hyphen is True:
1634 return False
1635 if seen_asterisk is True:
1636 return False
1637 if not 0 <= int(o) <= 255:
1638 return False
1639 except AttributeError:
1640 return False
1641 except ValueError:
1642 return False
1643 return True
1644
1645 is_valid = staticmethod(is_valid)
1646
1648 """
1649 Constructor.
1650
1651 @param wildcard: a valid IPv4 wildcard address
1652
1653 @param klass: (optional) class used to create each return object.
1654 Default: L{IP} objects. See L{nrange()} documentations for
1655 additional details on options.
1656 """
1657 if not Wildcard.is_valid(wildcard):
1658 raise AddrFormatError('%r is not a recognised wildcard address!' \
1659 % wildcard)
1660 t1 = []
1661 t2 = []
1662
1663 for octet in wildcard.split('.'):
1664 if '-' in octet:
1665 oct_tokens = octet.split('-')
1666 t1 += [oct_tokens[0]]
1667 t2 += [oct_tokens[1]]
1668 elif octet == '*':
1669 t1 += ['0']
1670 t2 += ['255']
1671 else:
1672 t1 += [octet]
1673 t2 += [octet]
1674
1675 first = '.'.join(t1)
1676 last = '.'.join(t2)
1677 super(self.__class__, self).__init__(first, last, klass=klass)
1678
1679 if self.addr_type != AT_INET:
1680 raise AddrFormatError('Wildcard syntax only supports IPv4!')
1681
1683 """
1684 @return: A valid L{CIDR} object for this wildcard. If conversion fails
1685 an L{AddrConversionError} is raised as not all wildcards ranges are
1686 valid CIDR ranges.
1687 """
1688 size = self.size()
1689
1690 if size & (size - 1) != 0:
1691 raise AddrConversionError('%s cannot be represented with CIDR' \
1692 % str(self))
1693
1694 (mantissa, exponent) = _math.frexp(size)
1695
1696
1697
1698
1699
1700 if mantissa != 0.5:
1701 raise AddrConversionError('%s cannot be represented with CIDR' \
1702 % str(self))
1703
1704 prefix = 32 - int(exponent - 1)
1705 network = self.strategy.int_to_str(self.first)
1706 try:
1707 cidr = CIDR("%s/%d" % (network, prefix))
1708 except:
1709 raise AddrConversionError('%s cannot be represented with CIDR' \
1710 % str(self))
1711
1712 if self.klass == str:
1713 return str(cidr)
1714
1715 return cidr
1716
1718 t1 = self.strategy.int_to_words(self.first)
1719 t2 = self.strategy.int_to_words(self.last)
1720
1721 tokens = []
1722
1723 seen_hyphen = False
1724 seen_asterisk = False
1725
1726 for i in range(4):
1727 if t1[i] == t2[i]:
1728
1729 tokens.append(str(t1[i]))
1730 elif (t1[i] == 0) and (t2[i] == 255):
1731
1732 tokens.append('*')
1733 seen_asterisk = True
1734 else:
1735
1736 if not seen_asterisk:
1737 if not seen_hyphen:
1738 tokens.append('%s-%s' % (t1[i], t2[i]))
1739 seen_hyphen = True
1740 else:
1741 raise AddrFormatError('only one hyphenated octet ' \
1742 ' per wildcard allowed!')
1743 else:
1744 raise AddrFormatError('asterisks not permitted before ' \
1745 'hyphenated octets!')
1746
1747 return '.'.join(tokens)
1748
1750 """
1751 @return: An executable Python statement that can recreate an object
1752 with an equivalent state.
1753 """
1754 return "netaddr.address.%s(%r)" % (self.__class__.__name__, str(self))
1755
1756
1757 if __name__ == '__main__':
1758 pass
1759