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  classes and functions representing supported network addresses and associated 
   9  aggregation options. 
  10  """ 
  11  from netaddr.strategy import AT_UNSPEC, AT_LINK, AT_INET, AT_INET6, \ 
  12                               AT_EUI64, ST_IPV4, ST_IPV6, ST_EUI48, ST_EUI64 
  13   
  14  #----------------------------------------------------------------------------- 
  15  _TRANSLATE_STR = ''.join([chr(_i) for _i in range(256)]) 
  16   
  17  #----------------------------------------------------------------------------- 
18 -class Addr(object):
19 """ 20 A class whose objects represent network addresses of different types based 21 on arguments passed to the constructor. 22 23 The address type can either be auto-detected from the string form of the 24 address or specified explicitly via the second argument. 25 26 The behaviour of this class varies depending on the type of address that 27 it represents. 28 """
29 - def __init__(self, addr, addr_type=AT_UNSPEC):
30 """ 31 Constructor. 32 33 addr - the string form of a network address, or a network byte order 34 int/long value within the supported range for the address type. 35 36 addr_type - (optional) the network address type. If addr is an int or 37 long, this argument becomes mandatory. 38 """ 39 if not isinstance(addr, (str, unicode, int, long)): 40 raise Exception("addr must be an address in string form or a " \ 41 "positive int/long!") 42 43 if isinstance(addr, (int, long)) and addr_type is None: 44 raise Exception("addr_type must be provided with int/long " \ 45 "address values!") 46 47 self.value = None 48 self.strategy = None 49 50 if addr_type is AT_UNSPEC: 51 # Auto-detect address type. 52 for strategy in (ST_IPV4, ST_IPV6, ST_EUI48, ST_EUI64): 53 if strategy.valid_str(addr): 54 self.strategy = strategy 55 break 56 elif addr_type == AT_INET: 57 self.strategy = ST_IPV4 58 elif addr_type == AT_INET6: 59 self.strategy = ST_IPV6 60 elif addr_type == AT_LINK: 61 self.strategy = ST_EUI48 62 elif addr_type == AT_EUI64: 63 self.strategy = ST_EUI64 64 65 if self.strategy is None: 66 # Whoops - we fell through and didn't match anything! 67 raise Exception("Failed to detect address type from %r!" % addr) 68 69 if addr is None: 70 addr = 0 71 72 self.addr_type = self.strategy.addr_type 73 self.setvalue(addr)
74
75 - def setvalue(self, addr):
76 """ 77 Sets the value of this address. 78 79 addr - the string form of a network address, or a network byte order 80 int/long value within the supported range for the address type. 81 82 Raises a TypeError if addr is of an unsupported type. 83 84 Raises an OverflowError if addr is an int/long value that is is out of 85 bounds for the address type this instance represents. 86 """ 87 if isinstance(addr, (str, unicode)): 88 self.value = self.strategy.str_to_int(addr) 89 elif isinstance(addr, (int, long)): 90 if self.strategy.valid_int(addr): 91 self.value = addr 92 else: 93 raise OverflowError('%r cannot be represented in %r bits!' \ 94 % (addr, self.strategy.width)) 95 else: 96 raise TypeError('%r is an unsupported type!')
97
98 - def __int__(self):
99 """ 100 Returns the value of this address as an network byte order int, if 101 possible. 102 103 If the value of int is greater than 2 ** 31 - 1, a long is returned 104 instead of an int (standard Python behaviour). 105 """ 106 return self.value
107
108 - def __long__(self):
109 """ 110 Returns the value of this address as a network byte order long int. 111 112 If the value of int is less than 2 ** 31 - 1, an int is returned 113 instead of a long (standard Python behaviour). 114 """ 115 return self.value
116
117 - def __str__(self):
118 """ 119 Return the string representation for this address. Format varies 120 dependent on address type. 121 """ 122 return self.strategy.int_to_str(self.value)
123
124 - def bits(self):
125 """ 126 Return a human-readable binary digit string representation of this 127 address. 128 """ 129 return self.strategy.int_to_bits(self.value)
130
131 - def __len__(self):
132 """ 133 Return the size of this address (in bits). 134 """ 135 return self.strategy.width
136
137 - def __iter__(self):
138 """ 139 Provide an iterator over words (based on word_size) in this address. 140 """ 141 return iter(self.strategy.int_to_words(self.value))
142
143 - def __getitem__(self, index):
144 """ 145 Return the integer value of the word indicated by index. Raises an 146 IndexError exception if index is wrong size for address type 147 148 Full slicing support is also available. 149 """ 150 if isinstance(index, (int, long)): 151 # Indexing, including negative indexing goodness. 152 word_count = self.strategy.word_count 153 if not (-word_count) <= index <= (word_count - 1): 154 raise IndexError('index out range for address type!') 155 return self.strategy.int_to_words(self.value)[index] 156 elif isinstance(index, slice): 157 # Slicing baby! 158 words = self.strategy.int_to_words(self.value) 159 return [words[i] for i in range(*index.indices(len(words)))] 160 else: 161 raise TypeError('unsupported type %r!' % index)
162 163
164 - def __setitem__(self, index, value):
165 """ 166 Set the value of the word of this address indicated by index. 167 """ 168 if isinstance(index, slice): 169 # TODO - settable slices. 170 raise NotImplementedError 171 172 if not isinstance(index, (int, long)): 173 raise TypeError('index not an integer!') 174 175 if not 0 <= index <= (self.strategy.word_count - 1): 176 raise IndexError('index %d outside address type boundary!' % index) 177 178 if not isinstance(value, (int, long)): 179 raise TypeError('value not an integer!') 180 181 if not 0 <= value <= (2 ** self.strategy.word_size - 1): 182 raise IndexError('value %d outside word size maximum of %d bits!' 183 % (value, self.strategy.word_size)) 184 185 words = list(self.strategy.int_to_words(self.value)) 186 words[index] = value 187 self.setvalue(self.strategy.words_to_int(words))
188
189 - def __hex__(self):
190 """ 191 Returns the value of this address as a network byte order hexadecimal 192 string. 193 """ 194 return hex(self.value).rstrip('L').lower()
195
196 - def __iadd__(self, increment):
197 """ 198 Increment the value of this network address by the specified value. 199 200 If the result exceeds maximum value for the address type, it rolls 201 around the minimum boundary value. 202 """ 203 try: 204 new_value = self.value + increment 205 if new_value > self.strategy.max_int: 206 # Roll around on integer boundaries. 207 self.value = new_value - (self.strategy.max_int + 1) 208 else: 209 self.value = new_value 210 except TypeError: 211 raise Exception('Increment requires int or long!') 212 213 return self
214
215 - def __isub__(self, decrement):
216 """ 217 Decrement the value of this network address by specified value. 218 219 If the result is lower than the address type mininum value it rolls 220 around the maximum boundary value. 221 """ 222 try: 223 new_value = self.value - decrement 224 if new_value < self.strategy.min_int: 225 # Roll around on integer boundaries. 226 self.value = new_value + (self.strategy.max_int + 1) 227 else: 228 self.value = new_value 229 except TypeError: 230 raise Exception('Decrement requires int or long!') 231 232 return self
233
234 - def __eq__(self, other):
235 """ 236 True if this network address instance has the same numerical value as 237 another, False otherwise. 238 """ 239 if int(self) == int(other): 240 return True 241 return False
242
243 - def __lt__(self, other):
244 """ 245 True if this network address instance has a lower numerical value than 246 another, False otherwise. 247 """ 248 if int(self) < int(other): 249 return True 250 return False
251
252 - def __le__(self, other):
253 """ 254 True if this network address instance has a lower or equivalent 255 numerical value than another, False otherwise. 256 """ 257 if int(self) <= int(other): 258 return True 259 return False
260
261 - def __gt__(self, other):
262 """ 263 True if this network address instance has a higher numerical value 264 than another, False otherwise. 265 """ 266 if int(self) > int(other): 267 return True 268 return False
269
270 - def __ge__(self, other):
271 """ 272 True if this network address instance has a higher or equivalent 273 numerical value than another, False otherwise. 274 """ 275 if int(self) >= int(other): 276 return True 277 return False
278 279 280 #-----------------------------------------------------------------------------
281 -class EUI(Addr):
282 """ 283 A class whose objects represent IEEE Extended Unique Identifiers. Supports 284 EUI-48 (along with common MAC flavours) and EUI-64. 285 """
286 - def __init__(self, addr, addr_type=AT_UNSPEC):
287 """ 288 Constructor. 289 290 addr - the string form of an EUI-48/64 address or a network byte 291 order int/long value. 292 293 addr_type - (optional) the EUI address type (AT_LINK or AT_EUI64). If 294 addr is an int or long, this argument becomes mandatory. 295 """ 296 if not isinstance(addr, (str, unicode, int, long)): 297 raise Exception("addr must be an address in string form or a " \ 298 "positive int/long!") 299 300 if isinstance(addr, (int, long)) and addr_type is None: 301 raise Exception("addr_type must be provided with int/long " \ 302 "address values!") 303 304 self.value = None 305 self.strategy = None 306 307 if addr_type is AT_UNSPEC: 308 # Auto-detect address type. 309 for strategy in (ST_EUI48, ST_EUI64): 310 if strategy.valid_str(addr): 311 self.strategy = strategy 312 break 313 elif addr_type == AT_LINK: 314 self.strategy = ST_EUI48 315 elif addr_type == AT_EUI64: 316 self.strategy = ST_EUI64 317 318 if self.strategy is None: 319 # Whoops - we fell through and didn't match anything! 320 raise Exception("Failed to detect EUI type from %r!" % addr) 321 322 if addr is None: 323 addr = 0 324 325 self.addr_type = self.strategy.addr_type 326 self.setvalue(addr)
327
328 - def oui(self):
329 """ 330 Returns the OUI (Organisationally Unique Identifier for this 331 EUI-48/MAC address. 332 """ 333 return '-'.join(["%02x" % i for i in self[0:3]]).upper()
334
335 - def ei(self):
336 """ 337 Returns the EI (Extension Identifier) for this EUI-48 address. 338 """ 339 if self.strategy == ST_EUI48: 340 return '-'.join(["%02x" % i for i in self[3:6]]).upper() 341 elif self.strategy == ST_EUI64: 342 return '-'.join(["%02x" % i for i in self[3:8]]).upper()
343
344 - def to_eui64(self):
345 """ 346 Returns the value of this EUI object as a new EUI address initialised 347 as a 64-bit EUI. 348 349 So if this address represents an EUI-48 address it converts the value 350 of this address to EUI-64 as per the standard. 351 352 If this class is already and EUI-64 address, it just returns a new 353 object that is numerically equivalent to itself. 354 """ 355 if self.addr_type == AT_LINK: 356 eui64_words = ["%02x" % i for i in self[0:3]] + ['ff', 'fe'] + \ 357 ["%02x" % i for i in self[3:6]] 358 359 return self.__class__('-'.join(eui64_words)) 360 else: 361 return EUI(str(self))
362
389 390 391 #-----------------------------------------------------------------------------
392 -class IP(Addr):
393 """ 394 A class whose objects represent Internet Protocol network addresses that 395 can be either IPv4 or IPv6. 396 """
397 - def __init__(self, addr, addr_type=AT_UNSPEC):
398 """ 399 Constructor. 400 401 addr - the string form of a IPv4 or IPv6 address, or a network byte 402 order int/long value. 403 404 addr_type - (optional) the IP address type (AT_INET or AT_INET6). If 405 addr is an int or long, this argument becomes mandatory. 406 """ 407 if not isinstance(addr, (str, unicode, int, long)): 408 raise Exception("addr must be an address in string form or a " \ 409 "positive int/long!") 410 411 if isinstance(addr, (int, long)) and addr_type is None: 412 raise Exception("addr_type must be provided with int/long " \ 413 "address values!") 414 415 self.value = None 416 self.strategy = None 417 418 if addr_type is AT_UNSPEC: 419 # Auto-detect address type. 420 for strategy in (ST_IPV4, ST_IPV6): 421 if strategy.valid_str(addr): 422 self.strategy = strategy 423 break 424 elif addr_type == AT_INET: 425 self.strategy = ST_IPV4 426 elif addr_type == AT_INET6: 427 self.strategy = ST_IPV6 428 429 if self.strategy is None: 430 # Whoops - we fell through and didn't match anything! 431 raise Exception("Failed to detect IP version from %r!" % addr) 432 433 if addr is None: 434 addr = 0 435 436 self.addr_type = self.strategy.addr_type 437 self.setvalue(addr)
438
439 - def is_netmask(self):
440 """ 441 Returns True if this addr is a mask that would return a host id, 442 False otherwise. 443 """ 444 # There is probably a better way to do this. 445 # Change at will, just don't break the unit tests :-) 446 bits = self.strategy.int_to_bits(self.value).replace('.', '') 447 448 if bits[0] != '1': 449 # Fail fast, if possible. 450 return False 451 452 # Trim our search a bit. 453 bits = bits.lstrip('1') 454 455 seen_zero = False 456 for i in bits: 457 if i == '0' and seen_zero is False: 458 seen_zero = True 459 elif i == '1' and seen_zero is True: 460 return False 461 462 return True
463
464 - def prefixlen(self):
465 """ 466 Returns the number of bits set to 1 if this address is a netmask, zero 467 otherwise. 468 """ 469 if not self.is_netmask(): 470 return self.strategy.width 471 472 bits = self.strategy.int_to_bits(self.value) 473 mask_bits = bits.translate(_TRANSLATE_STR, '.0') 474 mask_length = len(mask_bits) 475 476 if not 1 <= mask_length <= self.strategy.width: 477 raise Exception('Unexpected mask length %d for address type!' \ 478 % mask_length) 479 480 return mask_length
481
482 - def reverse_dns(self):
483 """ 484 Returns the reverse DNS lookup string for this IP address. 485 """ 486 return self.strategy.int_to_arpa(self.value)
487
488 - def is_hostmask(self):
489 """ 490 Returns True if this address is a mask that would return a network id, 491 False otherwise. 492 """ 493 # There is probably a better way to do this. 494 # Change at will, just don't break the unit tests :-) 495 bits = self.strategy.int_to_bits(self.value).replace('.', '') 496 497 if bits[0] != '0': 498 # Fail fast, if possible. 499 return False 500 501 # Trim our search a bit. 502 bits = bits.lstrip('0') 503 504 seen_one = False 505 for i in bits: 506 if i == '1' and seen_one is False: 507 seen_one = True 508 elif i == '0' and seen_one is True: 509 return False 510 511 return True
512 513 #-----------------------------------------------------------------------------
514 -def nrange(start, stop, step=1, klass=None):
515 """ 516 A generator producing sequences of addresses based on start and stop 517 values, in intervals of step. 518 519 start - first network address as string or instance of Addr (sub)class. 520 521 stop - last network address as string or instance of Addr (sub)class. 522 523 step - (optional) size of step between addresses in range. Default is 1. 524 525 klass - (optional) a class used to create each object returned. 526 Default: Addr objects. 527 528 a) str returns string representation of network address 529 530 b) int, long and hex return actual values 531 532 c) Addr (sub)class or duck type(*) return objects of that class. 533 534 (*) - if you use your own duck class, make sure you handle 2 arguments 535 passed in (addr_value, addr_type) to avoid frustration. 536 """ 537 if not issubclass(start.__class__, Addr): 538 if isinstance(start, (str, unicode)): 539 start = Addr(start) 540 else: 541 raise TypeError('start is not recognised address in string ' \ 542 'format or an that is a (sub)class of Addr!') 543 else: 544 # Make klass the same class as start object. 545 if klass is None: 546 klass = start.__class__ 547 548 if not issubclass(stop.__class__, Addr): 549 if isinstance(stop, (str, unicode)): 550 stop = Addr(stop) 551 else: 552 raise TypeError('stop is not recognised address in string ' \ 553 'format or an that is a (sub)class of Addr!') 554 555 if not isinstance(step, (int, long)): 556 raise TypeError('step must be type int|long, not %s!' % type(step)) 557 558 if start.addr_type != stop.addr_type: 559 raise TypeError('start and stop are not the same address type!') 560 561 if step == 0: 562 raise ValueError('step argument cannot be zero') 563 564 negative_step = False 565 addr_type = start.addr_type 566 567 if step < 0: 568 negative_step = True 569 570 index = int(start) - step 571 572 # Set default klass value. 573 if klass is None: 574 klass = Addr 575 576 if klass in (int, long, hex): 577 # Yield raw value of iterator. 578 while True: 579 index += step 580 if negative_step: 581 if not index >= int(stop): 582 return 583 else: 584 if not index <= int(stop): 585 return 586 yield klass(index) 587 588 elif klass in (str, unicode): 589 # Yield string representation of address type. 590 while True: 591 index += step 592 if negative_step: 593 if not index >= int(stop): 594 return 595 else: 596 if not index <= int(stop): 597 return 598 599 yield str(start.__class__(index, addr_type)) 600 else: 601 # Yield network address object. 602 while True: 603 index += step 604 if negative_step: 605 if not index >= int(stop): 606 return 607 else: 608 if not index <= int(stop): 609 return 610 611 yield klass(index, addr_type)
612 613 #-----------------------------------------------------------------------------
614 -class AddrRange(object):
615 """ 616 Represents a block of contiguous network addresses bounded by an arbitrary 617 start and stop address. There is no requirement that they fall on strict 618 bit mask boundaries. 619 620 This is the only network address aggregate class that supports all network 621 address types (essentially Addr (sub)class objects). Most if not all 622 subclasses of AddrRange tend towards support for only a subset of address 623 types. 624 """
625 - def __init__(self, start_addr, stop_addr, klass=None):
626 """ 627 Constructor. 628 629 start_addr - start address for this network address range. 630 631 stop_addr - stop address for this network address range. 632 633 klass - (optional) class used to create each return object. 634 Default: Addr objects. See nrange() documentations for 635 additional details on options. 636 """ 637 # Set start address. 638 if not issubclass(start_addr.__class__, Addr): 639 if isinstance(start_addr, (str, unicode)): 640 self.start_addr = Addr(start_addr) 641 else: 642 raise TypeError('start_addr is not recognised address in ' \ 643 'string format or an that is a (sub)class of Addr!') 644 else: 645 self.start_addr = start_addr 646 647 # Make klass the same class as start_addr object. 648 if klass is None: 649 klass = start_addr.__class__ 650 651 # Assign default klass. 652 if klass is None: 653 self.klass = Addr 654 else: 655 self.klass = klass 656 657 # Set stop address. 658 if not issubclass(stop_addr.__class__, Addr): 659 if isinstance(stop_addr, (str, unicode)): 660 self.stop_addr = Addr(stop_addr) 661 else: 662 raise TypeError('stop_addr is not recognised address in ' \ 663 'string format or an that is a (sub)class of Addr!') 664 else: 665 self.stop_addr = stop_addr 666 667 if self.start_addr.addr_type != self.stop_addr.addr_type: 668 raise TypeError('start_addr and stop_addr are not the same ' \ 669 'address type!') 670 671 self.addr_type = self.start_addr.addr_type 672 673 if self.stop_addr < self.start_addr: 674 raise IndexError('stop_addr must be greater than start_addr!')
675
676 - def _retval(self, addr):
677 """ 678 Protected method. Not for public use! 679 """ 680 # Decides on the flavour of a value to be return based on klass 681 # setting. 682 if self.klass in (str, unicode): 683 return str(addr) 684 elif self.klass in (int, long, hex): 685 return self.klass(int(addr)) 686 else: 687 return self.klass(int(addr), self.addr_type)
688
689 - def first(self):
690 """ 691 Returns the Addr instance for the lower boundary of this network 692 address range. 693 """ 694 return self._retval(self.start_addr)
695
696 - def last(self):
697 """ 698 Returns the Addr instance for the upper boundary of this network 699 address range. 700 """ 701 return self._retval(self.stop_addr)
702
703 - def __len__(self):
704 """ 705 Return total number of addresses to be found in this address range. 706 707 NB - Use this method only for ranges that contain less than 2 ** 31 708 addresses. Raises an IndexError if size is exceeded. 709 """ 710 size = self.size() 711 if size > (2 ** 31): 712 # Use size() method in this class instead as len() will b0rk! 713 raise IndexError("AddrRange contains more than 2^31 addresses! " \ 714 "Try using size() method instead.") 715 return size
716
717 - def size(self):
718 """ 719 Return total number of addresses to be found in this address range. 720 721 NB - Use this method in preference to __len__() when size of ranges 722 exceeds 2 ** 31 addresses. 723 """ 724 return int(self.stop_addr) - int(self.start_addr) + 1
725
726 - def __getitem__(self, index):
727 """ 728 Return the Addr instance from this address range indicated by index 729 or slice. 730 731 Raises an IndexError exception if index is out of bounds in relation 732 to size of address range. 733 734 Slicing objects of this class can potentially produce truly massive 735 sequences so generators are returned in preference to sequences. The 736 extra step of wrapping a raw slice with list() or tuple() may be 737 required dependent on context. 738 """ 739 if isinstance(index, (int, long)): 740 if (- self.size()) <= index < 0: 741 # negative index. 742 addr_type = self.stop_addr.addr_type 743 index_addr = Addr(int(self.stop_addr), addr_type) 744 index_addr += (index + 1) 745 return self._retval(index_addr) 746 elif 0 <= index <= (self.size() - 1): 747 # Positive index or zero index. 748 addr_type = self.start_addr.addr_type 749 index_addr = Addr(int(self.start_addr), addr_type) 750 index_addr += index 751 return self._retval(index_addr) 752 else: 753 raise IndexError('index out range for address range size!') 754 elif isinstance(index, slice): 755 # slices 756 addr_type = self.start_addr.addr_type 757 int_start_addr = int(self.start_addr) 758 #FIXME: IPv6 breaks the .indices() method on the slice object 759 # spectacularly. We'll have to work out the start, stop and 760 # step ourselves :-( 761 # 762 # see PySlice_GetIndicesEx function in Python SVN repository for 763 # implementation details :- 764 # http://svn.python.org/view/python/trunk/Objects/sliceobject.c 765 (start, stop, step) = index.indices(self.size()) 766 767 return nrange(Addr(int_start_addr + start, addr_type), 768 Addr(int_start_addr + stop - step, addr_type), 769 step, klass=self.klass) 770 else: 771 raise TypeError('unsupported type %r!' % index)
772
773 - def __iter__(self):
774 """ 775 Returns an iterator object providing lazily evaluated access to all 776 Addr() instances within this network address range. 777 """ 778 return nrange(self.start_addr, self.stop_addr, klass=self.klass)
779
780 - def __contains__(self, addr):
781 """ 782 Returns True if given address or address range falls within the 783 boundary of this network address False otherwise. 784 785 addr - object of (sub)class Addr/AddrRange or string based address to 786 be compared. 787 """ 788 if isinstance(addr, (str, unicode)): 789 # string address or address range. 790 if self.start_addr <= Addr(addr) <= self.stop_addr: 791 return True 792 elif issubclass(addr.__class__, Addr): 793 # Single value check. 794 if self.start_addr <= addr <= self.stop_addr: 795 return True 796 elif issubclass(addr.__class__, AddrRange): 797 # Range value check. 798 if (addr.start_addr >= self.start_addr) \ 799 and (addr.stop_addr <= self.stop_addr): 800 return True 801 else: 802 raise Exception('%r is an unsupported object/type!' % addr) 803 804 return False
805
806 - def __eq__(self, other):
807 """ 808 True if the boundary addresses of this address range are the same as 809 those of the other and the address types they represent are the same, 810 False otherwise. 811 """ 812 if self.start_addr.addr_type != other.start_addr.addr_type: 813 raise TypeError('comparison failure due to type mismatch!') 814 815 if int(self.start_addr) == int(other.start_addr): 816 if int(self.stop_addr) == int(other.stop_addr): 817 return True 818 819 return False
820
821 - def __ne__(self, other):
822 """ 823 True if the boundary addresses of this address range are not the same 824 as those of the other, False otherwise. 825 826 Raises a TypeError if address type of other is not the same as self. 827 """ 828 if self.start_addr.addr_type != other.start_addr.addr_type: 829 raise TypeError('comparison failure due to type mismatch!') 830 831 if int(self.start_addr) != int(other.start_addr): 832 return True 833 834 return False
835
836 - def __lt__(self, other):
837 """ 838 True if the lower boundary address of this address range is less than 839 that of the other and the address types they represent are the same, 840 False otherwise. 841 """ 842 if self.start_addr.addr_type != other.start_addr.addr_type: 843 raise TypeError('comparison failure due to type mismatch!') 844 845 if int(self.start_addr) < int(other.start_addr): 846 return True 847 848 return False
849
850 - def __le__(self, other):
851 """ 852 True if the lower boundary address of this address range is less than 853 or equal to that of the other and the address types they represent 854 are the same, False otherwise. 855 """ 856 if self.start_addr.addr_type != other.start_addr.addr_type: 857 raise TypeError('comparison failure due to type mismatch!') 858 859 if int(self.start_addr) <= int(other.start_addr): 860 return True 861 862 return False
863
864 - def __gt__(self, other):
865 """ 866 True if the lower boundary address of this address range is greater 867 than that of the other and the address types they represent are the 868 same, False otherwise. 869 """ 870 if self.start_addr.addr_type != other.start_addr.addr_type: 871 raise TypeError('comparison failure due to type mismatch!') 872 873 if int(self.start_addr) > int(other.start_addr): 874 return True 875 876 return False
877
878 - def __ge__(self, other):
879 """ 880 True if the lower boundary address of this address range is greater 881 than or equal to that of the other and the address types they 882 represent are the same, False otherwise. 883 """ 884 if self.start_addr.addr_type != other.start_addr.addr_type: 885 raise TypeError('comparison failure due to type mismatch!') 886 887 if int(self.start_addr) >= int(other.start_addr): 888 return True 889 890 return False
891
892 - def __str__(self):
893 return "%s-%s" % (self.start_addr, self.stop_addr)
894 895 #-----------------------------------------------------------------------------
896 -class CIDR(AddrRange):
897 """ 898 Represents a block of contiguous IPv4/IPv6 network addresses defined by an 899 IP address prefix and either a prefix mask measured in bits or 900 alternatively a traditional subnet mask in IP address format. 901 902 Examples of supported formats :- 903 904 1) CIDR address format - <address>/<mask_length> 905 906 192.168.0.0/16 907 908 2) Address and subnet mask combo :- 909 910 192.168.0.0/255.255.0.0 911 """
912 - def __init__(self, addr_mask, klass=IP):
913 """ 914 Constructor. 915 916 addr_mask - a valid CIDR address (IPv4 and IPv6 types supported). 917 918 klass - (optional) class used to create each return object. 919 Default: IP objects. See nrange() documentations for 920 additional details on options. 921 """ 922 tokens = addr_mask.split('/') 923 924 if len(tokens) != 2: 925 raise Exception('%r is not a recognised CIDR format!' \ 926 % addr_mask) 927 928 addr = IP(tokens[0]) 929 930 try: 931 # Try int value. 932 prefixlen = int(tokens[1]) 933 except ValueError: 934 # Try subnet mask. 935 mask = IP(tokens[1]) 936 if not mask.is_netmask(): 937 raise Exception('%r does not contain a valid subnet mask!' \ 938 % addr_mask) 939 prefixlen = mask.prefixlen() 940 if mask.addr_type != addr.addr_type: 941 raise Exception('Address and netmask types do not match!') 942 943 self._addr = addr 944 945 if not 0 <= prefixlen <= self._addr.strategy.width: 946 raise IndexError('CIDR prefix is out of bounds for %s addresses' \ 947 % self._addr.strategy.name) 948 949 self.mask_len = prefixlen 950 width = self._addr.strategy.width 951 self.addr_type = self._addr.strategy.addr_type 952 953 int_hostmask = (1 << (width - self.mask_len)) - 1 954 int_stop = int(self._addr) | int_hostmask 955 int_start = int_stop - int_hostmask 956 int_netmask = self._addr.strategy.max_int ^ int_hostmask 957 958 start_addr = IP(int_start, self.addr_type) 959 stop_addr = IP(int_stop, self.addr_type) 960 961 super(self.__class__, self).__init__(start_addr, stop_addr, 962 klass=klass) 963 964 self.netmask_addr = IP(int_netmask, self.addr_type) 965 self.hostmask_addr = IP(int_hostmask, self.addr_type)
966
967 - def addr(self):
968 """ 969 Returns the network address used to initialize this CIDR range. 970 """ 971 if self.klass in (str, unicode): 972 return str(self._addr) 973 elif self.klass in (int, long, hex): 974 return self.klass(int(self._addr)) 975 else: 976 return self.klass(int(self._addr), self.addr_type)
977
978 - def netmask(self):
979 """ 980 Returns the subnet mask address for this CIDR range. 981 """ 982 return self._retval(self.netmask_addr)
983
984 - def hostmask(self):
985 """ 986 Returns the host mask address for this CIDR range. 987 """ 988 return self._retval(self.hostmask_addr)
989
990 - def prefixlen(self):
991 """ 992 Returns size of mask (in bits) for this CIDR range. 993 """ 994 return self.mask_len
995
996 - def __str__(self):
997 return "%s/%d" % (self.start_addr, self.mask_len)
998 999 #-----------------------------------------------------------------------------
1000 -class Wildcard(AddrRange):
1001 """ 1002 Represents a block of contiguous IPv4 network addresses defined using a 1003 wildcard/glob style syntax. 1004 1005 Individual octets can be represented using the following shortcuts :- 1006 1007 1) The asterisk '*' octet. 1008 1009 This represents the values 0 through 255. 1010 1011 2) The hyphenated octet 'x-y' 1012 1013 This represents a range of values between x and y. 1014 1015 x must always be greater than y, therefore :- 1016 1017 values of x are 0 through 254 1018 values of y are 1 through 255 1019 1020 NB - only one hyphenated octet per wildcard is allowed. 1021 1022 Example wildcards :- 1023 1024 '192.168.0.1' # a single address 1025 '192.168.0.0-31' # 32 addresses 1026 '192.168.0.*' # 256 addresses 1027 '192.168.0-1.*' # 512 addresses 1028 '192.168-169.*.*' # 131,072 addresses 1029 '*.*.*.*' # the whole IPv4 address space 1030 1031 Aside: Wildcard ranges are not directly equivalent to CIDR ranges as they 1032 can represent address ranges that do not conform to bit mask boundaries. 1033 All CIDR ranges can be represented as wilcard ranges but the reverse isn't 1034 always true. 1035 """
1036 - def __init__(self, wildcard, klass=IP):
1037 """ 1038 Constructor. 1039 1040 wildcard - a valid wildcard address (only IPv4 is supported). 1041 1042 klass - (optional) class used to create each return object. 1043 Default: IP objects. See nrange() documentations for 1044 additional details on options. 1045 """ 1046 if not self.is_wildcard(wildcard): 1047 raise Exception('Invalid wildcard address range %r!' \ 1048 % wildcard) 1049 1050 l_tokens = [] 1051 u_tokens = [] 1052 1053 for octet in wildcard.split('.'): 1054 if '-' in octet: 1055 oct_tokens = octet.split('-') 1056 l_tokens += [oct_tokens[0]] 1057 u_tokens += [oct_tokens[1]] 1058 elif octet == '*': 1059 l_tokens += ['0'] 1060 u_tokens += ['255'] 1061 else: 1062 l_tokens += [octet] 1063 u_tokens += [octet] 1064 1065 start_addr = IP('.'.join(l_tokens)) 1066 stop_addr = IP('.'.join(u_tokens)) 1067 1068 if start_addr.addr_type != AT_INET: 1069 raise Exception('%s is an invalid IPv4 wildcard!' % start_addr) 1070 1071 super(self.__class__, self).__init__(start_addr, stop_addr, 1072 klass=klass)
1073
1074 - def is_wildcard(self, wildcard):
1075 """ 1076 True if wildcard address is valid, False otherwise. 1077 """ 1078 seen_hyphen = False 1079 seen_asterisk = False 1080 1081 try: 1082 octets = wildcard.split('.') 1083 if len(octets) != 4: 1084 return False 1085 for octet in octets: 1086 if '-' in octet: 1087 if seen_hyphen: 1088 return False 1089 seen_hyphen = True 1090 1091 if seen_asterisk: 1092 # Asterisks cannot precede hyphenated octets. 1093 return False 1094 (oct1, oct2) = map(lambda x: int(x), octet.split('-')) 1095 if oct1 >= oct2: 1096 return False 1097 if not 0 <= oct1 <= 254: 1098 return False 1099 if not 1 <= oct2 <= 255: 1100 return False 1101 elif octet == '*': 1102 seen_asterisk = True 1103 elif octet != '*': 1104 if not 0 <= int(octet) <= 255: 1105 return False 1106 except AttributeError: 1107 return False 1108 except ValueError: 1109 return False 1110 return True
1111
1112 - def __str__(self):
1113 t1 = tuple(self.start_addr) 1114 t2 = tuple(self.stop_addr) 1115 1116 tokens = [] 1117 1118 seen_hyphen = False 1119 seen_asterisk = False 1120 1121 for i in range(4): 1122 if t1[i] == t2[i]: 1123 # A normal octet. 1124 tokens.append(str(t1[i])) 1125 elif (t1[i] == 0) and (t2[i] == 255): 1126 # An asterisk octet. 1127 tokens.append('*') 1128 seen_asterisk = True 1129 else: 1130 # Create a hyphenated octet - only one allowed per wildcard. 1131 if not seen_asterisk: 1132 if not seen_hyphen: 1133 tokens.append('%s-%s' % (t1[i], t2[i])) 1134 seen_hyphen = True 1135 else: 1136 raise Exception('only one hyphenated octet ' \ 1137 ' per wildcard allowed!') 1138 else: 1139 raise Exception('asterisks not permitted before ' \ 1140 'hyphenated octets!') 1141 1142 return '.'.join(tokens)
1143 1144 #----------------------------------------------------------------------------- 1145 if __name__ == '__main__': 1146 pass 1147