Package netaddr :: Module address
[frames] | no frames]

Source Code for Module netaddr.address

   1  #!/usr/bin/env python 
   2  #----------------------------------------------------------------------------- 
   3  #   Copyright (c) 2008, David P. D. Moss. All rights reserved. 
   4  # 
   5  #   Released under the BSD license. See the LICENSE file for details. 
   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  #: Address type to strategy object lookup dict. 
  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  #   Descriptor protocol classes. 
  31  #----------------------------------------------------------------------------- 
  32   
33 -class AddrTypeDescriptor(object):
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 """
38 - def __init__(self, addr_types):
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 #-----------------------------------------------------------------------------
55 -class AddrValueDescriptor(object):
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 """
64 - def __init__(self, name):
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):
73 if issubclass(value.__class__, Addr): 74 if instance.strategy is None: 75 instance.strategy = value.strategy 76 value = int(value) 77 else: 78 if instance.addr_type == AT_UNSPEC: 79 # Select a strategy object for this address. 80 for strategy in instance.__class__.STRATEGIES: 81 if strategy.valid_str(value): 82 instance.strategy = strategy 83 break 84 85 # Make sure we picked up a strategy object. 86 if instance.strategy is None: 87 raise AddrFormatError('%r is not a recognised address ' \ 88 'format!' % value) 89 90 if isinstance(value, (str, unicode)): 91 # Calculate the integer value for this address. 92 value = instance.strategy.str_to_int(value) 93 elif isinstance(value, (int, long)): 94 if not instance.strategy.valid_int(value): 95 raise OverflowError('value %r cannot be represented ' \ 96 'in %d bit(s)!' % (value, instance.strategy.width)) 97 else: 98 raise TypeError('%r is an unsupported type!' % value) 99 100 instance.__dict__[self.name] = value
101 102 #-----------------------------------------------------------------------------
103 -class StrategyDescriptor(object):
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 """
108 - def __init__(self, strategies):
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 #-----------------------------------------------------------------------------
124 -class PrefixLenDescriptor(object):
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):
131 try: 132 # Basic integer subnet prefix. 133 prefixlen = int(value) 134 except ValueError: 135 # Convert possible subnet mask to integer subnet prefix. 136 ip = IP(value) 137 if instance.addr_type != ip.addr_type: 138 raise ValueError('address and netmask type mismatch!') 139 if not ip.is_netmask(): 140 raise ValueError('%s is not a valid netmask!' % ip) 141 prefixlen = ip.netmask_bits() 142 143 # Validate subnet prefix. 144 if not 0 <= prefixlen <= instance.strategy.width: 145 raise ValueError('%d is an invalid prefix for an %s CIDR!' \ 146 % (prefixlen, AT_NAMES[instance.addr_type])) 147 148 # Make sure instance is not a subnet mask trying to set a prefix! 149 if isinstance(instance, IP): 150 if instance.is_netmask() and instance.addr_type == AT_INET \ 151 and prefixlen != 32: 152 raise ValueError('IPv4 netmasks must have a prefix of /32!') 153 154 instance.__dict__['prefixlen'] = prefixlen
155 156 #-----------------------------------------------------------------------------
157 -class KlassDescriptor(object):
158 """ 159 A descriptor that checks klass (data flavour) property assignments for 160 validity. 161 """
162 - def __init__(self, default_klass):
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 # hex() is a BIF, not a type, so do a separate check for it. 181 pass 182 elif value is None: 183 # Use default class in None is specified. 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 # Address classes. 193 #----------------------------------------------------------------------------- 194
195 -class Addr(object):
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 # Descriptor registrations. 213 value = AddrValueDescriptor('value') 214 strategy = StrategyDescriptor(STRATEGIES) 215 addr_type = AddrTypeDescriptor(ADDR_TYPES) 216
217 - def __init__(self, addr, addr_type=AT_UNSPEC):
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
230 - def __hash__(self):
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
237 - def __int__(self):
238 """ 239 @return: The value of this address as an network byte order integer. 240 """ 241 return self.value
242
243 - def __long__(self):
244 """ 245 @return: The value of this address as an network byte order integer. 246 """ 247 return self.value
248
249 - def __str__(self):
250 """ 251 @return: The common string representation for this address type. 252 """ 253 return self.strategy.int_to_str(self.value)
254
255 - def __repr__(self):
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
262 - def bits(self):
263 """ 264 @return: A human-readable binary digit string for this address type. 265 """ 266 return self.strategy.int_to_bits(self.value)
267
268 - def __len__(self):
269 """ 270 @return: The size of this address (in bits). 271 """ 272 return self.strategy.width
273
274 - def __iter__(self):
275 """ 276 @return: An iterator over individual words in this address. 277 """ 278 return iter(self.strategy.int_to_words(self.value))
279
280 - def __getitem__(self, index):
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 # Indexing, including negative indexing goodness. 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 # Slicing baby! 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
299 - def __setitem__(self, index, value):
300 """ 301 Sets the value of the word of this address indicated by index. 302 """ 303 if isinstance(index, slice): 304 # TODO - settable slices. 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
324 - def __hex__(self):
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
331 - def __iadd__(self, i):
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
348 - def __isub__(self, i):
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
365 - def __eq__(self, other):
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
378 - def __ne__(self, other):
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
391 - def __lt__(self, other):
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
404 - def __le__(self, other):
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
417 - def __gt__(self, other):
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
430 - def __ge__(self, other):
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 #-----------------------------------------------------------------------------
444 -class EUI(Addr):
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 # Descriptor registrations. 454 strategy = StrategyDescriptor(STRATEGIES) 455 addr_type = AddrTypeDescriptor(ADDR_TYPES) 456
457 - def __init__(self, addr, addr_type=AT_UNSPEC):
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
469 - def oui(self):
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
475 - def ei(self):
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
484 - def eui64(self):
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
527 528 #-----------------------------------------------------------------------------
529 -class IP(Addr):
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 # Descriptor registrations. 551 strategy = StrategyDescriptor(STRATEGIES) 552 addr_type = AddrTypeDescriptor(ADDR_TYPES) 553 prefixlen = PrefixLenDescriptor() 554
555 - def __init__(self, addr, addr_type=AT_UNSPEC):
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 # Check for prefix in address and split it out. 567 try: 568 if '/' in addr: 569 (addr, prefixlen) = addr.split('/', 1) 570 except TypeError: 571 # addr is an int - let it pass through. 572 pass 573 574 # Call superclass constructor before processing subnet prefix to 575 # assign the strategyn object. 576 super(IP, self).__init__(addr, addr_type) 577 578 # Set the subnet prefix. 579 if prefixlen is None: 580 self.prefixlen = self.strategy.width 581 else: 582 self.prefixlen = prefixlen
583
584 - def is_netmask(self):
585 """ 586 @return: C{True} if this addr is a mask that would return a host id, 587 C{False} otherwise. 588 """ 589 # There is probably a better way to do this. 590 # Change at will, just don't break the unit tests :-) 591 bits = self.strategy.int_to_bits(self.value).replace('.', '') 592 593 if bits[0] != '1': 594 # Fail fast, if possible. 595 return False 596 597 # Trim our search a bit. 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
609 - def netmask_bits(self):
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
628 - def reverse_dns(self):
629 """ 630 @return: The reverse DNS lookup string for this IP address. 631 """ 632 return self.strategy.int_to_arpa(self.value)
633
634 - def is_hostmask(self):
635 """ 636 @return: C{True} if this address is a mask that would return a host 637 id, C{False} otherwise. 638 """ 639 # There is probably a better way to do this. 640 # Change at will, just don't break the unit tests :-) 641 bits = self.strategy.int_to_bits(self.value).replace('.', '') 642 643 if bits[0] != '0': 644 # Fail fast, if possible. 645 return False 646 647 # Trim our search a bit. 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
659 - def hostname(self):
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
666 - def cidr(self):
667 """ 668 @return: A valid L{CIDR} object for this IP address. 669 """ 670 hostmask = (1 << (self.strategy.width - self.prefixlen)) - 1 671 start = (self.value | hostmask) - hostmask 672 network = self.strategy.int_to_str(start) 673 return CIDR("%s/%d" % (network, self.prefixlen))
674
675 - def ipv4(self):
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
698 - def ipv6(self):
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
716 - def is_unicast(self):
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
724 - def is_multicast(self):
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
737 - def __str__(self):
738 """ 739 @return: The common string representation for this IP address. 740 """ 741 return self.strategy.int_to_str(self.value)
742
743 - def __repr__(self):
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 # Address aggregate classes. 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 # Make klass the same class as start object. 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 # We don't need objects from here onwards. Basic integer values will do 813 # just fine. 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 # Set default klass value. 824 if klass is None: 825 klass = Addr 826 827 if klass in (int, long, hex): 828 # Yield network address integer values. 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 # Yield address string values. 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 # Yield network address objects. 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 #-----------------------------------------------------------------------------
863 -class AddrRange(object):
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 # Descriptor registrations. 881 strategy = StrategyDescriptor(STRATEGIES) 882 addr_type = AddrTypeDescriptor(ADDR_TYPES) 883 first = AddrValueDescriptor('first') 884 last = AddrValueDescriptor('last') 885 klass = KlassDescriptor(Addr) 886
887 - def __init__(self, first, last, klass=Addr):
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
906 - def __hash__(self):
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
913 - def __len__(self):
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 # Use size() method in this class instead as len() will b0rk! 923 raise IndexError("range contains more than 2^31 addresses! " \ 924 "Use size() method instead.") 925 return size
926
927 - def size(self):
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
935 - def data_flavour(self, int_addr):
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
949 - def __getitem__(self, index):
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 # negative index. 961 return self.data_flavour(self.last + index + 1) 962 elif 0 <= index <= (self.size() - 1): 963 # Positive index or zero index. 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 # slices 969 #FIXME: IPv6 breaks the .indices() method on the slice object 970 # spectacularly. We'll have to work out the start, stop and 971 # step ourselves :-( 972 # 973 # see PySlice_GetIndicesEx function in Python SVN repository for 974 # implementation details :- 975 # http://svn.python.org/view/python/trunk/Objects/sliceobject.c 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
984 - def __iter__(self):
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
993 - def __contains__(self, addr):
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 # string address or address range. 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 # Single value check. 1009 if self.first <= int(addr) <= self.last: 1010 return True 1011 elif issubclass(addr.__class__, AddrRange): 1012 # Range value check. 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
1020 - def __eq__(self, other):
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
1036 - def __ne__(self, other):
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
1052 - def __lt__(self, other):
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
1068 - def __le__(self, other):
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
1084 - def __gt__(self, other):
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
1100 - def __ge__(self, other):
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
1116 - def __iadd__(self, i):
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
1137 - def __isub__(self, i):
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
1157 - def __str__(self):
1158 return "%s;%s" % (self.strategy.int_to_str(self.first), 1159 self.strategy.int_to_str(self.last))
1160
1161 - def __repr__(self):
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 # Descriptor registrations. 1220 strategy = StrategyDescriptor(STRATEGIES) 1221 addr_type = AddrTypeDescriptor(ADDR_TYPES) 1222 prefixlen = PrefixLenDescriptor() 1223 klass = KlassDescriptor(IP) 1224
1225 - def abbrev_to_verbose(abbrev_cidr):
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 # Internal function that returns a prefix value based on the old IPv4 1250 # classful network scheme that has been superseded (almost) by CIDR. 1251 def classful_prefix(octet): 1252 octet = int(octet) 1253 prefix = 32 # Host address default. 1254 if not 0 <= octet <= 255: 1255 raise IndexError('Invalid octet: %r!' % octet) 1256 if 0 <= octet <= 127: 1257 # Class A 1258 prefix = 8 1259 elif 128 <= octet <= 191: 1260 # Class B 1261 prefix = 16 1262 elif 192 <= octet <= 223: 1263 # Class C 1264 prefix = 24 1265 elif octet == 224: 1266 # Class D (multicast) 1267 prefix = 4 1268 elif 225 <= octet <= 239: 1269 prefix = 8 1270 return prefix
1271 1272 start = '' 1273 tokens = [] 1274 prefix = None 1275 1276 #FIXME: # Check for IPv4 mapped IPv6 addresses. 1277 if isinstance(abbrev_cidr, (str, unicode)): 1278 ################ 1279 # Don't support IPv6 for now... 1280 if ':' in abbrev_cidr: 1281 return None 1282 ################ 1283 #FIXME: if abbrev_cidr.startswith('::ffff:'): 1284 #FIXME: abbrev_cidr = abbrev_cidr.replace('::ffff:', '') 1285 #FIXME: start = '::ffff:' 1286 #FIXME: if '/' not in abbrev_cidr: 1287 #FIXME: prefix = 128 1288 #FIXME: elif abbrev_cidr.startswith('::'): 1289 #FIXME: abbrev_cidr = abbrev_cidr.replace('::', '') 1290 #FIXME: start = '::' 1291 #FIXME: if '/' not in abbrev_cidr: 1292 #FIXME: prefix = 128 1293 ################ 1294 1295 try: 1296 # Single octet partial integer or string address. 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 # Multi octet partial string address with optional prefix. 1303 part_addr = abbrev_cidr 1304 tokens = [] 1305 1306 if part_addr == '': 1307 # Not a recognisable format. 1308 return None 1309 1310 if '/' in part_addr: 1311 (part_addr, prefix) = part_addr.split('/', 1) 1312 1313 # Check prefix for validity. 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 # Not a recognisable format. 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 # Not a recognisable format. 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 # Keep a copy of original argument. 1367 1368 # Replace an abbreviation with a verbose CIDR. 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 # Check for prefix in address and extract it. 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 # Enable on strict CIDR checking. 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 # Loose CIDR checking. 1404 first.value = strategy.int_to_str(int(last) - hostmask) 1405 1406 super(CIDR, self).__init__(first, last, klass)
1407
1408 - def __sub__(self, other):
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 # Fail fast. Nothing to do in this case. 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 # Return string based CIDR address values at user's request. 1461 if self.klass is str: 1462 return [str(cidr) for cidr in cidrs] 1463 1464 return cidrs
1465 1466 #TODO def __add__(self, other): 1467 #TODO """ 1468 #TODO Add another CIDR to this one, but only if it is adjacent and of 1469 #TODO equitable size. 1470 #TODO 1471 #TODO @param other: a CIDR object that is of equal size to C{self}. 1472 #TODO 1473 #TODO @return: A new CIDR object that is double the size of C{self}. 1474 #TODO """ 1475 #TODO # Undecided about how to implement this. 1476 #TODO raise NotImplementedError('TODO') 1477
1478 - def netmask(self):
1479 """ 1480 @return: The subnet mask address of this CIDR range. 1481 """ 1482 hostmask = (1 << (strategy.width - self.prefixlen)) - 1 1483 netmask = strategy.max_int ^ hostmask 1484 return self.data_flavour(netmask)
1485
1486 - def hostmask(self):
1487 """ 1488 @return: The host mask address of this CIDR range. 1489 """ 1490 hostmask = (1 << (strategy.width - self.prefixlen)) - 1 1491 return self.data_flavour(hostmask)
1492
1493 - def __str__(self):
1494 return "%s/%s" % (self.strategy.int_to_str(self.first), self.prefixlen)
1495
1496 - def __repr__(self):
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
1504 - def wildcard(self):
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 # A normal octet. 1526 tokens.append(str(t1[i])) 1527 elif (t1[i] == 0) and (t2[i] == 255): 1528 # An asterisk octet. 1529 tokens.append('*') 1530 seen_asterisk = True 1531 else: 1532 # Create a hyphenated octet - only one allowed per wildcard. 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 #-----------------------------------------------------------------------------
1552 -class Wildcard(AddrRange):
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 # Descriptor registrations. 1594 strategy = StrategyDescriptor(STRATEGIES) 1595 addr_type = AddrTypeDescriptor(ADDR_TYPES) 1596 klass = KlassDescriptor(IP) 1597
1598 - def is_valid(wildcard):
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 #TODO: Add support for partial wildcards 1607 #TODO: e.g. 192.168.*.* == 192.168.* 1608 #TODO: *.*.*.* == * 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 # Asterisks cannot precede hyphenated octets. 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
1647 - def __init__(self, wildcard, klass=IP):
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
1682 - def cidr(self):
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 # The check below is only valid up to around 2^53 after which 1697 # rounding on +1 or -1 starts to bite and would cause this logic to 1698 # fail. Fine for our purposes here as we only envisage supporting 1699 # values up to 2^32 (IPv4), for now at least. 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
1717 - def __str__(self):
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 # A normal octet. 1729 tokens.append(str(t1[i])) 1730 elif (t1[i] == 0) and (t2[i] == 255): 1731 # An asterisk octet. 1732 tokens.append('*') 1733 seen_asterisk = True 1734 else: 1735 # Create a hyphenated octet - only one allowed per wildcard. 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
1749 - def __repr__(self):
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