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 addresses and associated aggregates (CIDR, Wilcard, etc). 
   9  """ 
  10  import math as _math 
  11  from netaddr import AddrFormatError, AddrConversionError 
  12  from netaddr.strategy import AT_UNSPEC, AT_LINK, AT_INET, AT_INET6, \ 
  13                               AT_EUI64, ST_IPV4, ST_IPV6, ST_EUI48, ST_EUI64 
  14   
  15  #----------------------------------------------------------------------------- 
16 -class Addr(object):
17 """ 18 The base class containing common functionality for all subclasses 19 representing various network address types. 20 21 It is a fully functioning class (as opposed to a virtual class) with a 22 heuristic constructor that detects the type of address via the first 23 argument if it is a string and sets itself up accordingly. If the first 24 argument is an integer, then a constant must be provided via the second 25 argument indicating the address type explicitly. 26 27 Objects of this class behave differently dependent upon the type of address 28 they represent. 29 """
30 - def __init__(self, addr, addr_type=AT_UNSPEC):
31 """ 32 Constructor. 33 34 @param addr: the string form of a network address, or a network byte 35 order integer within the supported range for the address type. 36 37 @param addr_type: (optional) the network address type. If addr is an 38 integer, this argument becomes mandatory. 39 """ 40 if not isinstance(addr, (str, unicode, int, long)): 41 raise TypeError("addr must be an network address string or a " \ 42 "positive integer!") 43 44 if isinstance(addr, (int, long)) and addr_type is None: 45 raise ValueError("addr_type must be provided with int/long " \ 46 "address values!") 47 48 self.value = None 49 self.strategy = None 50 51 if addr_type is AT_UNSPEC: 52 # Auto-detect address type. 53 for strategy in (ST_IPV4, ST_IPV6, ST_EUI48, ST_EUI64): 54 if strategy.valid_str(addr): 55 self.strategy = strategy 56 break 57 elif addr_type == AT_INET: 58 self.strategy = ST_IPV4 59 elif addr_type == AT_INET6: 60 self.strategy = ST_IPV6 61 elif addr_type == AT_LINK: 62 self.strategy = ST_EUI48 63 elif addr_type == AT_EUI64: 64 self.strategy = ST_EUI64 65 66 if self.strategy is None: 67 # Whoops - we fell through and didn't match anything! 68 raise AddrFormatError("%r is not a recognised address format!" \ 69 % addr) 70 71 if addr is None: 72 addr = 0 73 74 self.addr_type = self.strategy.addr_type 75 self.setvalue(addr)
76 77 #TODO: replace this method with __setattr__() instead.
78 - def setvalue(self, addr):
79 """ 80 Sets the value of this address. 81 82 @param addr: the string form of a network address, or a network byte 83 order integer value within the supported range for the address type. 84 - Raises a C{TypeError} if addr is of an unsupported type. 85 - Raises an C{OverflowError} if addr is an integer outside the 86 bounds for this address type. 87 """ 88 if isinstance(addr, (str, unicode)): 89 self.value = self.strategy.str_to_int(addr) 90 elif isinstance(addr, (int, long)): 91 if self.strategy.valid_int(addr): 92 self.value = addr 93 else: 94 raise OverflowError('%r cannot be represented in %r bits!' \ 95 % (addr, self.strategy.width)) 96 else: 97 raise TypeError('%r is an unsupported type!')
98
99 - def __int__(self):
100 """ 101 @return: The value of this address as an network byte order integer. 102 """ 103 return self.value
104
105 - def __long__(self):
106 """ 107 @return: The value of this address as an network byte order integer. 108 """ 109 return self.value
110
111 - def __str__(self):
112 """ 113 @return: The common string representation for this address type. 114 """ 115 return self.strategy.int_to_str(self.value)
116
117 - def __repr__(self):
118 """ 119 @return: An executable Python statement that can recreate an object 120 with an equivalent state. 121 """ 122 return "netaddr.address.%s(%r)" % (self.__class__.__name__, str(self))
123
124 - def bits(self):
125 """ 126 @return: A human-readable binary digit string for this address type. 127 """ 128 return self.strategy.int_to_bits(self.value)
129
130 - def __len__(self):
131 """ 132 @return: The size of this address (in bits). 133 """ 134 return self.strategy.width
135
136 - def __iter__(self):
137 """ 138 @return: An iterator over individual words in this address. 139 """ 140 return iter(self.strategy.int_to_words(self.value))
141
142 - def __getitem__(self, index):
143 """ 144 @return: The integer value of the word indicated by index. Raises an 145 C{IndexError} if index is wrong size for address type. Full 146 slicing is also supported. 147 """ 148 if isinstance(index, (int, long)): 149 # Indexing, including negative indexing goodness. 150 word_count = self.strategy.word_count 151 if not (-word_count) <= index <= (word_count - 1): 152 raise IndexError('index out range for address type!') 153 return self.strategy.int_to_words(self.value)[index] 154 elif isinstance(index, slice): 155 # Slicing baby! 156 words = self.strategy.int_to_words(self.value) 157 return [words[i] for i in range(*index.indices(len(words)))] 158 else: 159 raise TypeError('unsupported type %r!' % index)
160 161
162 - def __setitem__(self, index, value):
163 """ 164 Sets the value of the word of this address indicated by index. 165 """ 166 if isinstance(index, slice): 167 # TODO - settable slices. 168 raise NotImplementedError('settable slices not yet supported!') 169 170 if not isinstance(index, (int, long)): 171 raise TypeError('index not an integer!') 172 173 if not 0 <= index <= (self.strategy.word_count - 1): 174 raise IndexError('index %d outside address type boundary!' % index) 175 176 if not isinstance(value, (int, long)): 177 raise TypeError('value not an integer!') 178 179 if not 0 <= value <= (2 ** self.strategy.word_size - 1): 180 raise IndexError('value %d outside word size maximum of %d bits!' 181 % (value, self.strategy.word_size)) 182 183 words = list(self.strategy.int_to_words(self.value)) 184 words[index] = value 185 self.setvalue(self.strategy.words_to_int(words))
186
187 - def __hex__(self):
188 """ 189 @return: The value of this address as a network byte order hexadecimal 190 number. 191 """ 192 return hex(self.value).rstrip('L').lower()
193
194 - def __iadd__(self, i):
195 """ 196 Increments network address by specified value. 197 198 If the result exceeds address type maximum, it rolls around the 199 minimum boundary. 200 """ 201 try: 202 new_value = self.value + i 203 if new_value > self.strategy.max_int: 204 self.value = new_value - (self.strategy.max_int + 1) 205 else: 206 self.value = new_value 207 except TypeError: 208 raise TypeError('Increment value must be an integer!') 209 return self
210
211 - def __isub__(self, i):
212 """ 213 Decrements network address by specified value. 214 215 If the result exceeds address type minimum, it rolls around the 216 maximum boundary. 217 """ 218 try: 219 new_value = self.value - i 220 if new_value < self.strategy.min_int: 221 self.value = new_value + (self.strategy.max_int + 1) 222 else: 223 self.value = new_value 224 except TypeError: 225 raise TypeError('Decrement value must be an integer!') 226 return self
227
228 - def __eq__(self, other):
229 """ 230 @return: C{True} if this network address instance has the same 231 numerical value as another, C{False} otherwise. 232 """ 233 if int(self) == int(other): 234 return True 235 return False
236
237 - def __lt__(self, other):
238 """ 239 @return: C{True} if this network address instance has a lower 240 numerical value than another, C{False} otherwise. 241 """ 242 if int(self) < int(other): 243 return True 244 return False
245
246 - def __le__(self, other):
247 """ 248 @return: C{True} if this network address instance has a lower or 249 equivalent numerical value than another, C{False} otherwise. 250 """ 251 if int(self) <= int(other): 252 return True 253 return False
254
255 - def __gt__(self, other):
256 """ 257 @return: C{True} if this network address instance has a higher 258 numerical value than another, C{False} otherwise. 259 """ 260 if int(self) > int(other): 261 return True 262 return False
263
264 - def __ge__(self, other):
265 """ 266 @return: C{True} if this network address instance has a higher or 267 equivalent numerical value than another, C{False} otherwise. 268 """ 269 if int(self) >= int(other): 270 return True 271 return False
272
273 - def family(self):
274 """ 275 @return: The integer constant identifying this object's address type. 276 """ 277 return self.strategy.addr_type
278 279 #-----------------------------------------------------------------------------
280 -class EUI(Addr):
281 """ 282 EUI objects represent IEEE Extended Unique Identifiers. Input parsing is 283 flexible, supporting EUI-48, EUI-64 and all MAC (Media Access Control) 284 address flavours. 285 """
286 - def __init__(self, addr, addr_type=AT_UNSPEC):
287 """ 288 Constructor. 289 290 @param addr: an EUI/MAC address string or a network byte order 291 integer. 292 293 @param addr_type: (optional) the specific EUI address type (C{AT_LINK} 294 or C{AT_EUI64}). If addr is an integer, this argument is mandatory. 295 """ 296 if not isinstance(addr, (str, unicode, int, long)): 297 raise TypeError("addr must be an EUI/MAC network address " \ 298 "string or a positive integer!") 299 300 if isinstance(addr, (int, long)) and addr_type is None: 301 raise ValueError("addr_type must be provided with integer " \ 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 AddrFormatError("%r is not a recognised EUI or MAC " \ 321 "address format!" % addr) 322 323 if addr is None: 324 addr = 0 325 326 self.addr_type = self.strategy.addr_type 327 self.setvalue(addr)
328
329 - def oui(self):
330 """ 331 @return: The OUI (Organisationally Unique Identifier) for this EUI. 332 """ 333 return '-'.join(["%02x" % i for i in self[0:3]]).upper()
334
335 - def ei(self):
336 """ 337 @return: The EI (Extension Identifier) for this EUI. 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 eui64(self):
345 """ 346 @return: The value of this EUI object as a new 64-bit EUI object. 347 - If this object represents an EUI-48 it is converted to EUI-64 as 348 per the standard. 349 - If this object is already and EUI-64, it just returns a new, 350 numerically equivalent object is returned instead. 351 """ 352 if self.addr_type == AT_LINK: 353 eui64_words = ["%02x" % i for i in self[0:3]] + ['ff', 'fe'] + \ 354 ["%02x" % i for i in self[3:6]] 355 356 return self.__class__('-'.join(eui64_words)) 357 else: 358 return EUI(str(self))
359
387 388 389 #-----------------------------------------------------------------------------
390 -class IP(Addr):
391 """ 392 A class whose objects represent Internet Protocol network addresses. Both 393 IPv4 and IPv6 are fully supported and include an optional subnet bit mask 394 prefix, for example :: 395 396 192.168.0.1/24 397 fe80::20f:1fff:fe12:e733/64 398 399 This class B{does not make a requirement to omit non-zero bits to the 400 right of the subnet prefix} when it is applied to the address. 401 402 See the L{CIDR()} class if you require B{*strict*} subnet prefix checking. 403 """
404 - def __init__(self, addr, addr_type=AT_UNSPEC):
405 """ 406 Constructor. 407 408 @param addr: an IPv4 or IPv6 address string with an optional subnet 409 prefix or a network byte order integer. 410 411 @param addr_type: (optional) the IP address type (C{AT_INET} or 412 C{AT_INET6}). If L{addr} is an integer, this argument is mandatory. 413 """ 414 if not isinstance(addr, (str, unicode, int, long)): 415 raise TypeError("addr must be an network address string or a " \ 416 "positive integer!") 417 418 if isinstance(addr, (int, long)) and addr_type is AT_UNSPEC: 419 raise ValueError("addr_type must be provided with int/long " \ 420 "address values!") 421 422 self.value = None 423 self.strategy = None 424 self.prefix = None 425 426 if addr_type == AT_UNSPEC: 427 pass 428 elif addr_type == AT_INET: 429 self.strategy = ST_IPV4 430 elif addr_type == AT_INET6: 431 self.strategy = ST_IPV6 432 else: 433 raise ValueError('%r is an unsupported address type!') 434 435 if addr is None: 436 addr = 0 437 438 self.setvalue(addr)
439 440 #TODO: replace this method with __setattr__() instead.
441 - def setvalue(self, addr):
442 """ 443 Sets the value of this address. 444 445 @param addr: the string form of an IP address, or a network byte order 446 int/long value within the supported range for the address type. 447 - Raises a C{TypeError} if addr is of an unsupported type. 448 - Raises an C{OverflowError} if addr is an integer outside the 449 bounds for this address type. 450 """ 451 if isinstance(addr, (str, unicode)): 452 # String address. 453 if '/' in addr: 454 (addr, masklen) = addr.split('/', 1) 455 self.prefix = int(masklen) 456 457 # Auto-detect address type. 458 for strategy in (ST_IPV4, ST_IPV6): 459 if strategy.valid_str(addr): 460 self.strategy = strategy 461 break 462 463 if self.strategy is None: 464 raise AddrFormatError('%r is not a valid IPv4/IPv6 address!' \ 465 % addr) 466 467 self.addr_type = self.strategy.addr_type 468 self.value = self.strategy.str_to_int(addr) 469 470 elif isinstance(addr, (int, long)): 471 if self.strategy.valid_int(addr): 472 self.addr_type = self.strategy.addr_type 473 self.value = addr 474 else: 475 raise OverflowError('%r cannot be represented in %r bits!' \ 476 % (addr, self.strategy.width)) 477 else: 478 raise TypeError('%r is an unsupported type!') 479 480 # Set default prefix. 481 if self.prefix == None: 482 self.prefix = self.strategy.width
483
484 - def is_netmask(self):
485 """ 486 @return: C{True} if this addr is a mask that would return a host id, 487 C{False} otherwise. 488 """ 489 # There is probably a better way to do this. 490 # Change at will, just don't break the unit tests :-) 491 bits = self.strategy.int_to_bits(self.value).replace('.', '') 492 493 if bits[0] != '1': 494 # Fail fast, if possible. 495 return False 496 497 # Trim our search a bit. 498 bits = bits.lstrip('1') 499 500 seen_zero = False 501 for i in bits: 502 if i == '0' and seen_zero is False: 503 seen_zero = True 504 elif i == '1' and seen_zero is True: 505 return False 506 507 return True
508
509 - def prefixlen(self):
510 """ 511 @return: The number of bits set to one in this address if it is a 512 netmask, zero otherwise. 513 """ 514 if not self.is_netmask(): 515 return self.strategy.width 516 517 bits = self.strategy.int_to_bits(self.value) 518 translate_str = ''.join([chr(_i) for _i in range(256)]) 519 mask_bits = bits.translate(translate_str, '.0') 520 mask_length = len(mask_bits) 521 522 if not 1 <= mask_length <= self.strategy.width: 523 raise ValueError('Unexpected mask length %d for address type!' \ 524 % mask_length) 525 526 return mask_length
527
528 - def reverse_dns(self):
529 """ 530 @return: The reverse DNS lookup string for this IP address. 531 """ 532 return self.strategy.int_to_arpa(self.value)
533
534 - def is_hostmask(self):
535 """ 536 @return: C{True} if this address is a mask that would return a host 537 id, C{False} otherwise. 538 """ 539 # There is probably a better way to do this. 540 # Change at will, just don't break the unit tests :-) 541 bits = self.strategy.int_to_bits(self.value).replace('.', '') 542 543 if bits[0] != '0': 544 # Fail fast, if possible. 545 return False 546 547 # Trim our search a bit. 548 bits = bits.lstrip('0') 549 550 seen_one = False 551 for i in bits: 552 if i == '1' and seen_one is False: 553 seen_one = True 554 elif i == '0' and seen_one is True: 555 return False 556 557 return True
558
559 - def cidr(self):
560 """ 561 @return: A valid L{CIDR} object for this IP address. 562 """ 563 hostmask = (1 << (self.strategy.width - self.prefix)) - 1 564 start = (self.value | hostmask) - hostmask 565 network = self.strategy.int_to_str(start) 566 return CIDR("%s/%s" % (network, self.prefix))
567
568 - def masklen(self):
569 """ 570 @return: The subnet prefix of this IP address. 571 """ 572 return int(self.prefix)
573
574 - def __str__(self):
575 """ 576 @return: The common string representation for this IP address. 577 """ 578 return self.strategy.int_to_str(self.value)
579
580 - def __repr__(self):
581 """ 582 @return: An executable Python statement that can recreate an object 583 with an equivalent state. 584 """ 585 return "netaddr.address.%s('%s/%d')" % (self.__class__.__name__, 586 str(self), self.prefix)
587 588 #-----------------------------------------------------------------------------
589 -def nrange(start, stop, step=1, klass=None):
590 """ 591 A generator producing sequences of network addresses based on start and 592 stop values, in intervals of step. 593 594 @param start: first network address as string or instance of L{Addr} 595 (sub)class. 596 597 @param stop: last network address as string or instance of L{Addr} 598 (sub)class. 599 600 @param step: (optional) size of step between addresses in range. 601 Default is 1. 602 603 @param klass: (optional) the class used to create objects returned. 604 Default: L{Addr} class. 605 606 - C{str} returns string representation of network address 607 - C{int}, C{long} and C{hex} return expected values 608 - L{Addr} (sub)class or duck type* return objects of that class. If 609 you use your own duck class, make sure you handle both arguments 610 C{(addr_value, addr_type)} passed to the constructor. 611 """ 612 if not issubclass(start.__class__, Addr): 613 if isinstance(start, (str, unicode)): 614 start = Addr(start) 615 else: 616 raise TypeError('start is not recognised address in string ' \ 617 'format or an that is a (sub)class of Addr!') 618 else: 619 # Make klass the same class as start object. 620 if klass is None: 621 klass = start.__class__ 622 623 if not issubclass(stop.__class__, Addr): 624 if isinstance(stop, (str, unicode)): 625 stop = Addr(stop) 626 else: 627 raise TypeError('stop is not recognised address in string ' \ 628 'format or an that is a (sub)class of Addr!') 629 630 if not isinstance(step, (int, long)): 631 raise TypeError('step must be type int|long, not %s!' % type(step)) 632 633 if start.addr_type != stop.addr_type: 634 raise TypeError('start and stop are not the same address type!') 635 636 if step == 0: 637 raise ValueError('step argument cannot be zero') 638 639 negative_step = False 640 addr_type = start.addr_type 641 642 if step < 0: 643 negative_step = True 644 645 index = int(start) - step 646 647 # Set default klass value. 648 if klass is None: 649 klass = Addr 650 651 if klass in (int, long, hex): 652 # Yield network address integer values. 653 while True: 654 index += step 655 if negative_step: 656 if not index >= int(stop): 657 return 658 else: 659 if not index <= int(stop): 660 return 661 yield klass(index) 662 663 elif klass in (str, unicode): 664 # Yield address string values. 665 while True: 666 index += step 667 if negative_step: 668 if not index >= int(stop): 669 return 670 else: 671 if not index <= int(stop): 672 return 673 674 yield str(start.__class__(index, addr_type)) 675 else: 676 # Yield network address objects. 677 while True: 678 index += step 679 if negative_step: 680 if not index >= int(stop): 681 return 682 else: 683 if not index <= int(stop): 684 return 685 686 yield klass(index, addr_type)
687 688 #-----------------------------------------------------------------------------
689 -class AddrRange(object):
690 """ 691 A block of contiguous network addresses bounded by an arbitrary start and 692 stop address. There is no requirement that they fall on strict bit mask 693 boundaries, unlike L{CIDR} addresses. 694 695 The only network address aggregate supporting all network address types. 696 Most AddrRange subclasses only support a subset of address types. 697 """
698 - def __init__(self, start_addr, stop_addr, klass=None):
699 """ 700 Constructor. 701 702 @param start_addr: start address for this network address range. 703 704 @param stop_addr: stop address for this network address range. 705 706 @param klass: (optional) class used to create each object returned. 707 Default: L{Addr()} objects. See L{nrange()} documentations for 708 additional details on options. 709 """ 710 # Set start address. 711 if not issubclass(start_addr.__class__, Addr): 712 if isinstance(start_addr, (str, unicode)): 713 self.start_addr = Addr(start_addr) 714 else: 715 raise TypeError('start_addr is not recognised address in ' \ 716 'string format or an that is a (sub)class of Addr!') 717 else: 718 self.start_addr = start_addr 719 720 # Make klass the same as start_addr object. 721 if klass is None: 722 klass = start_addr.__class__ 723 724 # Assign default klass. 725 if klass is None: 726 self.klass = Addr 727 else: 728 self.klass = klass 729 730 # Set stop address. 731 if not issubclass(stop_addr.__class__, Addr): 732 if isinstance(stop_addr, (str, unicode)): 733 self.stop_addr = Addr(stop_addr) 734 else: 735 raise TypeError('stop_addr is not recognised address in ' \ 736 'string format or an that is a (sub)class of Addr!') 737 else: 738 self.stop_addr = stop_addr 739 740 if self.start_addr.addr_type != self.stop_addr.addr_type: 741 raise TypeError('start_addr and stop_addr are not the same ' \ 742 'address type!') 743 744 self.addr_type = self.start_addr.addr_type 745 746 if self.stop_addr < self.start_addr: 747 raise IndexError('stop_addr must be greater than start_addr!')
748
749 - def __setattr__(self, name, value):
750 """ 751 Police assignments to various class attributes to ensure nothing gets 752 broken accidentally. 753 """ 754 if name == 'klass': 755 if isinstance(value, type): 756 if value in (str, int, long, unicode): 757 pass 758 elif issubclass(value, Addr): 759 pass 760 else: 761 raise TypeError("unsupported type %r for klass!" % value) 762 elif value is hex: 763 # hex() is a BIF, not a type. 764 pass 765 else: 766 raise ValueError("unsupported value %r for klass!" % value) 767 768 self.__dict__[name] = value
769
770 - def _retval(self, addr):
771 """ 772 Protected method. B{*** Not intended for public use ***} 773 """ 774 # Decides on the flavour of a value to be return based on klass 775 # property. 776 if self.klass in (str, unicode): 777 return str(addr) 778 elif self.klass in (int, long, hex): 779 return self.klass(int(addr)) 780 else: 781 return self.klass(int(addr), self.addr_type)
782
783 - def first(self):
784 """ 785 @return: The lower boundary network address of this range. 786 """ 787 return self._retval(self.start_addr)
788
789 - def last(self):
790 """ 791 @return: The upper boundary network address of this range. 792 """ 793 return self._retval(self.stop_addr)
794
795 - def __len__(self):
796 """ 797 @return: The total number of network addresses in this range. 798 - Use this method only for ranges that contain less than 799 C{2^31} addresses or try the L{size()} method. Raises an 800 C{IndexError} if size is exceeded. 801 """ 802 size = self.size() 803 if size > (2 ** 31): 804 # Use size() method in this class instead as len() will b0rk! 805 raise IndexError("range contains more than 2^31 addresses! " \ 806 "Use size() method instead.") 807 return size
808
809 - def size(self):
810 """ 811 @return: The total number of network addresses in this range. 812 - Use this method in preference to L{__len__()} when size of 813 ranges exceeds C{2^31} addresses. 814 """ 815 return int(self.stop_addr) - int(self.start_addr) + 1
816
817 - def __getitem__(self, index):
818 """ 819 @return: The network address(es) in this address range indicated by 820 index/slice. Slicing objects can produce large sequences so 821 generator objects are returned instead to the usual sequences. 822 Wrapping a raw slice with C{list()} or C{tuple()} may be required 823 dependent on context. 824 """ 825 if isinstance(index, (int, long)): 826 if (- self.size()) <= index < 0: 827 # negative index. 828 addr_type = self.stop_addr.addr_type 829 index_addr = Addr(int(self.stop_addr), addr_type) 830 index_addr += (index + 1) 831 return self._retval(index_addr) 832 elif 0 <= index <= (self.size() - 1): 833 # Positive index or zero index. 834 addr_type = self.start_addr.addr_type 835 index_addr = Addr(int(self.start_addr), addr_type) 836 index_addr += index 837 return self._retval(index_addr) 838 else: 839 raise IndexError('index out range for address range size!') 840 elif isinstance(index, slice): 841 # slices 842 addr_type = self.start_addr.addr_type 843 int_start_addr = int(self.start_addr) 844 #FIXME: IPv6 breaks the .indices() method on the slice object 845 # spectacularly. We'll have to work out the start, stop and 846 # step ourselves :-( 847 # 848 # see PySlice_GetIndicesEx function in Python SVN repository for 849 # implementation details :- 850 # http://svn.python.org/view/python/trunk/Objects/sliceobject.c 851 (start, stop, step) = index.indices(self.size()) 852 853 return nrange(Addr(int_start_addr + start, addr_type), 854 Addr(int_start_addr + stop - step, addr_type), 855 step, klass=self.klass) 856 else: 857 raise TypeError('unsupported type %r!' % index)
858
859 - def __iter__(self):
860 """ 861 @return: An iterator object providing access to all network addresses 862 within this range. 863 """ 864 return nrange(self.start_addr, self.stop_addr, klass=self.klass)
865
866 - def __contains__(self, addr):
867 """ 868 @param addr: object of Addr/AddrRange (sub)class or a network address 869 string to be compared. 870 871 @return: C{True} if given address or range falls within this range, 872 C{False} otherwise. 873 """ 874 if isinstance(addr, (str, unicode)): 875 # string address or address range. 876 if self.start_addr <= Addr(addr) <= self.stop_addr: 877 return True 878 elif issubclass(addr.__class__, Addr): 879 # Single value check. 880 if self.start_addr <= addr <= self.stop_addr: 881 return True 882 elif issubclass(addr.__class__, AddrRange): 883 # Range value check. 884 if (addr.start_addr >= self.start_addr) \ 885 and (addr.stop_addr <= self.stop_addr): 886 return True 887 else: 888 raise TypeError('%r is an unsupported class or type!' % addr) 889 890 return False
891
892 - def __eq__(self, other):
893 """ 894 @param other: an address object of the same address type as C{self}. 895 896 @return: C{True} if the boundary of this range is the same as other, 897 C{False} otherwise. 898 """ 899 if self.start_addr.addr_type != other.start_addr.addr_type: 900 raise TypeError('comparison failure due to type mismatch!') 901 902 if int(self.start_addr) == int(other.start_addr): 903 if int(self.stop_addr) == int(other.stop_addr): 904 return True 905 906 return False
907
908 - def __ne__(self, other):
909 """ 910 @param other: an address object of the same address type as C{self}. 911 912 @return: C{True} if the boundary of this range is not the same as 913 other, C{False} otherwise. 914 """ 915 if self.start_addr.addr_type != other.start_addr.addr_type: 916 raise TypeError('comparison failure due to type mismatch!') 917 918 if int(self.start_addr) != int(other.start_addr): 919 return True 920 921 return False
922
923 - def __lt__(self, other):
924 """ 925 @param other: an address object of the same address type as C{self}. 926 927 @return: C{True} if the lower boundary of this range is less than 928 other, C{False} otherwise. 929 """ 930 if self.start_addr.addr_type != other.start_addr.addr_type: 931 raise TypeError('comparison failure due to type mismatch!') 932 933 if int(self.start_addr) < int(other.start_addr): 934 return True 935 936 return False
937
938 - def __le__(self, other):
939 """ 940 @param other: an address object of the same address type as C{self}. 941 942 @return: C{True} if the lower boundary of this range is less or equal 943 to other, C{False} otherwise. 944 """ 945 if self.start_addr.addr_type != other.start_addr.addr_type: 946 raise TypeError('comparison failure due to type mismatch!') 947 948 if int(self.start_addr) <= int(other.start_addr): 949 return True 950 951 return False
952
953 - def __gt__(self, other):
954 """ 955 @param other: an address object of the same address type as C{self}. 956 957 @return: C{True} if the lower boundary of this range is greater than 958 other, C{False} otherwise. 959 """ 960 if self.start_addr.addr_type != other.start_addr.addr_type: 961 raise TypeError('comparison failure due to type mismatch!') 962 963 if int(self.start_addr) > int(other.start_addr): 964 return True 965 966 return False
967
968 - def __ge__(self, other):
969 """ 970 @param other: an address object of the same address type as C{self}. 971 972 @return: C{True} if the lower boundary of this range is greater or 973 equal to other, C{False} otherwise. 974 """ 975 if self.start_addr.addr_type != other.start_addr.addr_type: 976 raise TypeError('comparison failure due to type mismatch!') 977 978 if int(self.start_addr) >= int(other.start_addr): 979 return True 980 981 return False
982
983 - def __str__(self):
984 return "%s-%s" % (self.start_addr, self.stop_addr)
985
986 - def __repr__(self):
987 """ 988 @return: An executable Python statement that can recreate an object 989 with an equivalent state. 990 """ 991 return "netaddr.address.%s(%r, %r)" % (self.__class__.__name__, 992 str(self.start_addr), str(self.stop_addr))
993 994 #-----------------------------------------------------------------------------
995 -def abbrev_to_cidr(addr):
996 """ 997 @param addr: an abbreviated CIDR network address. 998 999 Uses the old-style classful IP address rules to decide on a default subnet 1000 prefix if one is not explicitly provided. 1001 1002 Only supports IPv4 and IPv4 mapped IPv6 addresses. 1003 1004 Examples :: 1005 1006 10 - 10.0.0.0/8 1007 10/16 - 10.0.0.0/16 1008 128 - 128.0.0.0/16 1009 128/8 - 128.0.0.0/8 1010 192.168 - 192.168.0.0/16 1011 ::192.168 - ::192.168.0.0/128 1012 ::ffff:192.168/120 - ::ffff:192.168.0.0/120 1013 1014 @return: A verbose CIDR from an abbreviated CIDR or old-style classful 1015 network address, C{None} if format provided was not recognised or 1016 supported. 1017 """ 1018 # Internal function that returns a prefix value based on the old IPv4 1019 # classful network scheme that has been superseded (almost) by CIDR. 1020 def classful_prefix(octet): 1021 octet = int(octet) 1022 prefix = 32 # Host address default. 1023 if not 0 <= octet <= 255: 1024 raise IndexError('Invalid octet: %r!' % octet) 1025 if 0 <= octet <= 127: 1026 # Class A 1027 prefix = 8 1028 elif 128 <= octet <= 191: 1029 # Class B 1030 prefix = 16 1031 elif 192 <= octet <= 223: 1032 # Class C 1033 prefix = 24 1034 elif 224 <= octet <= 239: 1035 # Class D (multicast) 1036 prefix = 8 1037 return prefix
1038 1039 start = '' 1040 tokens = [] 1041 prefix = None 1042 1043 #FIXME: # Check for IPv4 mapped IPv6 addresses. 1044 if isinstance(addr, (str, unicode)): 1045 ################ 1046 # Don't support IPv6 for now... 1047 if ':' in addr: 1048 return None 1049 ################ 1050 #FIXME: if addr.startswith('::ffff:'): 1051 #FIXME: addr = addr.replace('::ffff:', '') 1052 #FIXME: start = '::ffff:' 1053 #FIXME: if '/' not in addr: 1054 #FIXME: prefix = 128 1055 #FIXME: elif addr.startswith('::'): 1056 #FIXME: addr = addr.replace('::', '') 1057 #FIXME: start = '::' 1058 #FIXME: if '/' not in addr: 1059 #FIXME: prefix = 128 1060 ################ 1061 1062 try: 1063 # Single octet partial integer or string address. 1064 i = int(addr) 1065 tokens = [str(i), '0', '0', '0'] 1066 return "%s%s/%s" % (start, '.'.join(tokens), classful_prefix(i)) 1067 1068 except ValueError: 1069 # Multi octet partial string address with optional prefix. 1070 part_addr = addr 1071 tokens = [] 1072 1073 if part_addr == '': 1074 # Not a recognisable format. 1075 return None 1076 1077 if '/' in part_addr: 1078 (part_addr, prefix) = part_addr.split('/', 1) 1079 1080 if '.' in part_addr: 1081 tokens = part_addr.split('.') 1082 else: 1083 tokens = [part_addr] 1084 1085 if 1 <= len(tokens) <= 4: 1086 for i in range(4 - len(tokens)): 1087 tokens.append('0') 1088 else: 1089 # Not a recognisable format. 1090 return None 1091 1092 if prefix is None: 1093 prefix = classful_prefix(tokens[0]) 1094 1095 return "%s%s/%s" % (start, '.'.join(tokens), prefix) 1096 1097 except TypeError: 1098 pass 1099 except IndexError: 1100 pass 1101 1102 # Not a recognisable format. 1103 return None 1104 1105 #-----------------------------------------------------------------------------
1106 -class CIDR(AddrRange):
1107 """ 1108 A block of contiguous IPv4 or IPv6 network addresses defined by a base 1109 network address and a bitmask prefix or subnet mask address indicating the 1110 size/extent of the subnet. 1111 1112 This class B{does not accept any non zero bits to be set right of the 1113 bitmask} (unlike the L{IP} class which is less strict). Doing so raises an 1114 L{AddrFormatError} exception. 1115 1116 Examples of supported formats :- 1117 1118 1. CIDR address format - C{<address>/<mask_length>}:: 1119 1120 192.168.0.0/16 1121 1122 2. Address and subnet mask combo :: 1123 1124 192.168.0.0/255.255.0.0 == 192.168.0.0/16 1125 1126 3. Partial or abbreviated formats. Prefixes may be omitted and in this 1127 case old classful default prefixes apply :: 1128 1129 10 == 10.0.0.0/8 1130 10.0 == 10.0.0.0/8 1131 10/8 == 10.0.0.0/8 1132 1133 128 == 128.0.0.0/16 1134 128.0 == 128.0.0.0/16 1135 128/16 == 128.0.0.0/16 1136 1137 192 == 10.0.0.0/24 1138 192.168.0 == 192.168.0.0/24 1139 192.168/16 == 192.168.0.0/16 1140 """
1141 - def __init__(self, addr_mask, klass=IP):
1142 """ 1143 Constructor. 1144 1145 @param addr_mask: a valid IPv4/IPv6 CIDR address or abbreviated 1146 IPv4 network address 1147 1148 @param klass: (optional) type, BIF or class used to create each 1149 object returned. Default: L{IP} class. See L{nrange()} 1150 documentations for additional details on options. 1151 """ 1152 verbose_addr_mask = abbrev_to_cidr(addr_mask) 1153 if verbose_addr_mask is not None: 1154 addr_mask = verbose_addr_mask 1155 1156 tokens = addr_mask.split('/') 1157 1158 if len(tokens) != 2: 1159 raise AddrFormatError('%r is not a recognised CIDR ' \ 1160 'format!' % addr_mask) 1161 1162 addr = IP(tokens[0]) 1163 1164 try: 1165 # Try int value. 1166 prefixlen = int(tokens[1]) 1167 except ValueError: 1168 # Try subnet mask. 1169 mask = IP(tokens[1]) 1170 if not mask.is_netmask(): 1171 raise AddrFormatError('%r does not contain a valid ' \ 1172 'subnet mask!' % addr_mask) 1173 prefixlen = mask.prefixlen() 1174 if mask.addr_type != addr.addr_type: 1175 raise AddrFormatError('Address and netmask types do ' \ 1176 'not match!') 1177 1178 if not 0 <= prefixlen <= addr.strategy.width: 1179 raise IndexError('CIDR prefix out of bounds for %s addresses!' \ 1180 % addr.strategy.name) 1181 1182 self.mask_len = prefixlen 1183 width = addr.strategy.width 1184 self.addr_type = addr.strategy.addr_type 1185 1186 int_hostmask = (1 << (width - self.mask_len)) - 1 1187 int_stop = int(addr) | int_hostmask 1188 int_start = int_stop - int_hostmask 1189 int_netmask = addr.strategy.max_int ^ int_hostmask 1190 1191 start_addr = IP(int_start, self.addr_type) 1192 stop_addr = IP(int_stop, self.addr_type) 1193 1194 super(self.__class__, self).__init__(start_addr, stop_addr, 1195 klass=klass) 1196 1197 self.netmask_addr = IP(int_netmask, self.addr_type) 1198 self.hostmask_addr = IP(int_hostmask, self.addr_type) 1199 1200 # Make cidr() stricter than inet() ... 1201 host = (int(addr) | int_netmask) - int_netmask 1202 if host != 0: 1203 raise TypeError('non-zero bits to the right of netmask! ' \ 1204 'Try %s instead.' % str(self))
1205
1206 - def netmask(self):
1207 """ 1208 @return: The subnet mask address of this CIDR range. 1209 """ 1210 return self._retval(self.netmask_addr)
1211
1212 - def hostmask(self):
1213 """ 1214 @return: The host mask address of this CIDR range. 1215 """ 1216 return self._retval(self.hostmask_addr)
1217
1218 - def prefixlen(self):
1219 """ 1220 @return: Size of mask (in bits) of this CIDR range. 1221 """ 1222 return self.mask_len
1223
1224 - def __str__(self):
1225 return "%s/%s" % (self.start_addr, self.mask_len)
1226
1227 - def __repr__(self):
1228 """ 1229 @return: An executable Python statement that can recreate an object 1230 with an equivalent state. 1231 """ 1232 return "netaddr.address.%s('%s/%d')" % (self.__class__.__name__, 1233 str(self.start_addr), self.mask_len)
1234
1235 - def wildcard(self):
1236 """ 1237 @return: A L{Wildcard} object equivalent to this CIDR. 1238 - If CIDR was initialised with C{klass=str} a wildcard string is 1239 returned, in all other cases a L{Wildcard} object is returned. 1240 - Only supports IPv4 CIDR addresses. 1241 """ 1242 t1 = tuple(self.start_addr) 1243 t2 = tuple(self.stop_addr) 1244 1245 if self.addr_type != AT_INET: 1246 raise AddrConversionError('IPv6 CIDR addresses are invalid!') 1247 1248 tokens = [] 1249 1250 seen_hyphen = False 1251 seen_asterisk = False 1252 1253 for i in range(4): 1254 if t1[i] == t2[i]: 1255 # A normal octet. 1256 tokens.append(str(t1[i])) 1257 elif (t1[i] == 0) and (t2[i] == 255): 1258 # An asterisk octet. 1259 tokens.append('*') 1260 seen_asterisk = True 1261 else: 1262 # Create a hyphenated octet - only one allowed per wildcard. 1263 if not seen_asterisk: 1264 if not seen_hyphen: 1265 tokens.append('%s-%s' % (t1[i], t2[i])) 1266 seen_hyphen = True 1267 else: 1268 raise SyntaxError('only one hyphenated octet per ' \ 1269 'wildcard permitted!') 1270 else: 1271 raise SyntaxError("* chars aren't permitted before ' \ 1272 'hyphenated octets!") 1273 1274 wildcard = '.'.join(tokens) 1275 1276 if self.klass == str: 1277 return wildcard 1278 1279 return Wildcard(wildcard)
1280 1281 #-----------------------------------------------------------------------------
1282 -class Wildcard(AddrRange):
1283 """ 1284 A block of contiguous IPv4 network addresses defined using a wildcard 1285 style syntax. 1286 1287 Individual octets can be represented using the following shortcuts : 1288 1289 1. C{*} - the asterisk octet (represents values 0 through 255) 1290 2. C{'x-y'} - the hyphenated octet (represents values x through y) 1291 1292 A few basic rules also apply : 1293 1294 1. x must always be greater than y, therefore : 1295 1296 - x can only be 0 through 254 1297 - y can only be 1 through 255 1298 1299 2. only one hyphenated octet per wildcard is allowed 1300 3. only asterisks are permitted after a hyphenated octet 1301 1302 Example wildcards :: 1303 1304 '192.168.0.1' # a single address 1305 '192.168.0.0-31' # 32 addresses 1306 '192.168.0.*' # 256 addresses 1307 '192.168.0-1.*' # 512 addresses 1308 '192.168-169.*.*' # 131,072 addresses 1309 '*.*.*.*' # the whole IPv4 address space 1310 1311 Aside 1312 ===== 1313 I{Wildcard ranges are not directly equivalent to CIDR ranges as they 1314 can represent address ranges that do not fall on strict bit mask 1315 boundaries.} 1316 1317 I{All CIDR ranges can be represented as wildcard ranges but the reverse 1318 isn't always true.} 1319 """
1320 - def __init__(self, wildcard, klass=IP):
1321 """ 1322 Constructor. 1323 1324 @param wildcard: a valid IPv4 wildcard address 1325 1326 @param klass: (optional) class used to create each return object. 1327 Default: L{IP} objects. See L{nrange()} documentations for 1328 additional details on options. 1329 """ 1330 #--------------------------------------------------------------------- 1331 #TODO: Add support for partial wildcards 1332 #TODO: e.g. 192.168.*.* == 192.168.* 1333 #TODO: *.*.*.* == * 1334 def _is_wildcard(wildcard): 1335 """ 1336 True if wildcard address is valid, False otherwise. 1337 """ 1338 seen_hyphen = False 1339 seen_asterisk = False 1340 1341 try: 1342 octets = wildcard.split('.') 1343 if len(octets) != 4: 1344 return False 1345 for o in octets: 1346 if '-' in o: 1347 if seen_hyphen: 1348 return False 1349 seen_hyphen = True 1350 if seen_asterisk: 1351 # Asterisks cannot precede hyphenated octets. 1352 return False 1353 (o1, o2) = [int(i) for i in o.split('-')] 1354 if o1 >= o2: 1355 return False 1356 if not 0 <= o1 <= 254: 1357 return False 1358 if not 1 <= o2 <= 255: 1359 return False 1360 elif o == '*': 1361 seen_asterisk = True 1362 else: 1363 if seen_hyphen is True: 1364 return False 1365 if seen_asterisk is True: 1366 return False 1367 if not 0 <= int(o) <= 255: 1368 return False 1369 except AttributeError: 1370 return False 1371 except ValueError: 1372 return False 1373 1374 return True
1375 #--------------------------------------------------------------------- 1376 1377 if not _is_wildcard(wildcard): 1378 raise AddrFormatError('%r is not a recognised wildcard address!' \ 1379 % wildcard) 1380 1381 t1 = [] 1382 t2 = [] 1383 1384 for octet in wildcard.split('.'): 1385 if '-' in octet: 1386 oct_tokens = octet.split('-') 1387 t1 += [oct_tokens[0]] 1388 t2 += [oct_tokens[1]] 1389 elif octet == '*': 1390 t1 += ['0'] 1391 t2 += ['255'] 1392 else: 1393 t1 += [octet] 1394 t2 += [octet] 1395 1396 start_addr = IP('.'.join(t1)) 1397 stop_addr = IP('.'.join(t2)) 1398 1399 if start_addr.addr_type != AT_INET: 1400 raise AddrFormatError('%s is an invalid IPv4 wildcard!' \ 1401 % start_addr) 1402 1403 super(self.__class__, self).__init__(start_addr, stop_addr, 1404 klass=klass)
1405
1406 - def cidr(self):
1407 """ 1408 @return: A valid L{CIDR} object for this wildcard. If conversion fails 1409 an L{AddrConversionError} is raised as not all wildcards ranges are 1410 valid CIDR ranges. 1411 """ 1412 size = self.size() 1413 1414 if size & (size - 1) != 0: 1415 raise AddrConversionError('%s cannot be represented with CIDR' \ 1416 % str(self)) 1417 1418 (mantissa, exponent) = _math.frexp(size) 1419 1420 # The check below is only valid up to around 2^53 after which 1421 # rounding on +1 or -1 starts to bite and would cause this logic to 1422 # fail. Fine for our purposes here as we only envisage going up to 1423 # 2^32, for now at least. 1424 if mantissa != 0.5: 1425 raise AddrConversionError('%s cannot be represented with CIDR' \ 1426 % str(self)) 1427 1428 prefix = 32 - int(exponent - 1) 1429 network = str(self.start_addr) 1430 try: 1431 cidr = CIDR("%s/%d" % (network, prefix)) 1432 except: 1433 raise AddrConversionError('%s cannot be represented with CIDR' \ 1434 % str(self)) 1435 1436 if self.klass == str: 1437 return str(cidr) 1438 1439 return cidr
1440
1441 - def __str__(self):
1442 t1 = tuple(self.start_addr) 1443 t2 = tuple(self.stop_addr) 1444 1445 tokens = [] 1446 1447 seen_hyphen = False 1448 seen_asterisk = False 1449 1450 for i in range(4): 1451 if t1[i] == t2[i]: 1452 # A normal octet. 1453 tokens.append(str(t1[i])) 1454 elif (t1[i] == 0) and (t2[i] == 255): 1455 # An asterisk octet. 1456 tokens.append('*') 1457 seen_asterisk = True 1458 else: 1459 # Create a hyphenated octet - only one allowed per wildcard. 1460 if not seen_asterisk: 1461 if not seen_hyphen: 1462 tokens.append('%s-%s' % (t1[i], t2[i])) 1463 seen_hyphen = True 1464 else: 1465 #FIXME: police properties with __setattr__ instead... 1466 raise AddrFormatError('only one hyphenated octet ' \ 1467 ' per wildcard allowed!') 1468 else: 1469 #FIXME: police properties with __setattr__ instead... 1470 raise AddrFormatError('asterisks not permitted before ' \ 1471 'hyphenated octets!') 1472 1473 return '.'.join(tokens)
1474
1475 - def __repr__(self):
1476 """ 1477 @return: An executable Python statement that can recreate an object 1478 with an equivalent state. 1479 """ 1480 return "netaddr.address.%s(%r)" % (self.__class__.__name__, str(self))
1481 1482 if __name__ == '__main__': 1483 pass 1484