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