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

Source Code for Module netaddr.address

   1  #!/usr/bin/env python 
   2  #----------------------------------------------------------------------------- 
   3  #   Copyright (c) 2008-2009, 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  Wildcard and IPRange). 
  10  """ 
  11  import math as _math 
  12  import socket as _socket 
  13  import re as _re 
  14   
  15  from netaddr import AddrFormatError, AddrConversionError, AT_UNSPEC, \ 
  16      AT_INET, AT_INET6, AT_LINK, AT_EUI64, AT_NAMES 
  17   
  18  from netaddr.strategy import ST_IPV4, ST_IPV6, ST_EUI48, ST_EUI64, \ 
  19      AddrStrategy 
  20   
  21  from netaddr.eui import OUI, IAB 
  22   
  23  from netaddr.util import num_bits 
  24   
  25  #: Address type to strategy object lookup dict. 
  26  AT_STRATEGIES = { 
  27      AT_UNSPEC   : None, 
  28      AT_INET     : ST_IPV4, 
  29      AT_INET6    : ST_IPV6, 
  30      AT_LINK     : ST_EUI48, 
  31      AT_EUI64    : ST_EUI64, 
  32  } 
33 34 #----------------------------------------------------------------------------- 35 -class AddrTypeDescriptor(object):
36 """ 37 A descriptor that checks addr_type property assignments for validity and 38 also keeps the strategy property in sync with any changes made. 39 """
40 - def __init__(self, addr_types):
41 """ 42 Constructor. 43 44 @param addr_types: a list of address types constants that are 45 acceptable for assignment to the addr_type property. 46 """ 47 self.addr_types = addr_types
48
49 - def __set__(self, instance, value):
50 if value not in self.addr_types: 51 raise ValueError('addr_type %r is invalid for objects of ' \ 52 'the %s() class!' % (value, instance.__class__.__name__)) 53 instance.__dict__['addr_type'] = value 54 instance.__dict__['strategy'] = AT_STRATEGIES[value]
55
56 #----------------------------------------------------------------------------- 57 -class AddrValueDescriptor(object):
58 """ 59 A descriptor that checks assignments to the named parameter passed to the 60 constructor. 61 62 It accepts network addresses in either strings format or as unsigned 63 integers. String based addresses are converted to their integer 64 equivalents before assignment to the named parameter. Also ensures that 65 addr_type and strategy are set correctly when parsing string based 66 addresses. 67 """
68 - def __init__(self, name):
69 """ 70 Descriptor constructor. 71 72 @param name: the name of attribute which will be assigned the value. 73 """ 74 self.name = name
75
76 - def __set__(self, instance, value):
77 if issubclass(value.__class__, Addr): 78 if instance.strategy is None: 79 instance.strategy = value.strategy 80 value = int(value) 81 else: 82 if instance.addr_type == AT_UNSPEC: 83 # Select a strategy object for this address. 84 for strategy in instance.__class__.STRATEGIES: 85 if strategy.valid_str(value): 86 instance.strategy = strategy 87 break 88 89 # Make sure we picked up a strategy object. 90 if instance.strategy is None: 91 raise AddrFormatError('%r is not a supported address ' \ 92 'format!' % value) 93 94 if isinstance(value, (str, unicode)): 95 # Calculate the integer value for this address. 96 value = instance.strategy.str_to_int(value) 97 elif isinstance(value, (int, long)): 98 if not instance.strategy.valid_int(value): 99 raise OverflowError('value %r cannot be represented ' \ 100 'in %d bit(s)!' % (value, instance.strategy.width)) 101 else: 102 raise AddrFormatError('%r is an unsupported type!' % value) 103 104 instance.__dict__[self.name] = value
105
106 #----------------------------------------------------------------------------- 107 -class StrategyDescriptor(object):
108 """ 109 A descriptor that checks strategy property assignments for validity and 110 also keeps the addr_type property in sync with any changes made. 111 """
112 - def __init__(self, strategies):
113 """ 114 Constructor. 115 116 @param strategies: a list of valid strategy objects that are suitable 117 for assignment to the strategy property. 118 """ 119 self.strategies = strategies
120
121 - def __set__(self, instance, value):
122 if value not in self.strategies: 123 raise ValueError('%r is not a supported strategy!' % value) 124 new_strategy = value 125 instance.__dict__['strategy'] = new_strategy 126 instance.__dict__['addr_type'] = new_strategy.addr_type
127
128 #----------------------------------------------------------------------------- 129 -class PrefixLenDescriptor(object):
130 """ 131 A descriptor that checks prefixlen property assignments for validity based 132 on address type. Also accepts netmasks and hostmasks which can easily be 133 converted to the equivalent prefixlen integer. 134 """
135 - def __init__(self, class_id=None):
136 """ 137 Constructor. 138 139 @param class_id: (optional) the name of the class that uses this 140 descriptor. 141 """ 142 self.class_id = class_id
143
144 - def __set__(self, instance, value):
145 try: 146 # Basic integer subnet prefix. 147 prefixlen = int(value) 148 except ValueError: 149 # Convert possible subnet mask to integer subnet prefix. 150 ip = IP(value) 151 152 if ip.is_netmask(): 153 # prefixlen is a netmask address. 154 prefixlen = ip.netmask_bits() 155 elif ip.is_hostmask(): 156 # prefixlen is an ACL (hostmask) address. 157 netmask = IP(ip.strategy.max_int ^ int(ip), ip.addr_type) 158 prefixlen = netmask.netmask_bits() 159 else: 160 raise ValueError('%s is not a valid netmask/hostmask!' % ip) 161 162 # Validate subnet prefix. 163 if not 0 <= prefixlen <= instance.strategy.width: 164 raise ValueError('%d is an invalid prefix for an %s CIDR!' \ 165 % (prefixlen, AT_NAMES[instance.addr_type])) 166 167 instance.__dict__['prefixlen'] = prefixlen 168 169 # Don't run this on a CIDR that is initialising itself. 170 if self.class_id == 'CIDR' and 'first' in instance.__dict__: 171 first = instance.__dict__['first'] 172 strategy = instance.__dict__['strategy'] 173 hostmask = (1 << (strategy.width - prefixlen)) - 1 174 instance.__dict__['first'] = (first | hostmask) - hostmask 175 instance.__dict__['last'] = first | hostmask
176
177 #----------------------------------------------------------------------------- 178 -class FormatDescriptor(object):
179 """ 180 A descriptor that checks formatter property assignments for validity. 181 """
182 - def __init__(self, default):
183 """ 184 Constructor. 185 186 @param default: the default callable to use if the formatter 187 property is None. 188 """ 189 self.default = default
190
191 - def __set__(self, instance, value):
192 if callable(value) and \ 193 value in (str, int, Addr, IP, long, unicode, hex): 194 pass 195 elif value is None: 196 # Use default. 197 value = self.default 198 else: 199 raise TypeError("unsupported formatter callable: %r!" % value) 200 201 instance.__dict__['fmt'] = value
202
203 #----------------------------------------------------------------------------- 204 -class Addr(object):
205 """ 206 The base class containing common functionality for all subclasses 207 representing various network address types. 208 209 It is a fully functioning class (as opposed to a virtual class) with a 210 heuristic constructor that detects the type of address via the first 211 argument if it is a string and sets itself up accordingly. If the first 212 argument is an integer, then a constant must be provided via the second 213 argument indicating the address type explicitly. 214 215 Objects of this class behave differently dependent upon the type of address 216 they represent. 217 """ 218 STRATEGIES = (ST_IPV4, ST_IPV6, ST_EUI48, ST_EUI64) 219 ADDR_TYPES = (AT_UNSPEC, AT_INET, AT_INET6, AT_LINK, AT_EUI64) 220 221 # Descriptor registrations. 222 value = AddrValueDescriptor('value') 223 strategy = StrategyDescriptor(STRATEGIES) 224 addr_type = AddrTypeDescriptor(ADDR_TYPES) 225
226 - def __init__(self, addr, addr_type=AT_UNSPEC):
227 """ 228 Constructor. 229 230 @param addr: the string form of a network address, or a network byte 231 order integer within the supported range for the address type. 232 233 @param addr_type: (optional) the network address type. If addr is an 234 integer, this argument becomes mandatory. 235 """ 236 self.addr_type = addr_type 237 self.value = addr
238
239 - def __hash__(self):
240 """@return: hash of this address suitable for dict keys, sets etc""" 241 return hash((self.addr_type, self.value))
242
243 - def __int__(self):
244 """@return: value of this address as an unsigned integer""" 245 return self.value
246
247 - def __long__(self):
248 """@return: value of this address as an unsigned integer""" 249 return self.value
250
251 - def __str__(self):
252 """@return: common string representation of this address""" 253 return self.strategy.int_to_str(self.value)
254
255 - def __repr__(self):
256 """@return: executable Python string to recreate equivalent object""" 257 return "%s(%r)" % (self.__class__.__name__, str(self))
258
259 - def bits(self, word_sep=None):
260 """ 261 @param word_sep: (optional) the separator to insert between words. 262 Default: None - use default separator for address type. 263 264 @return: human-readable binary digit string of this address""" 265 return self.strategy.int_to_bits(self.value, word_sep)
266
267 - def packed(self):
268 """@return: binary packed string of this address""" 269 return self.strategy.int_to_packed(self.value)
270
271 - def bin(self):
272 """ 273 @return: standard Python binary representation of this address. A back 274 port of the format provided by the builtin bin() type available in 275 Python 2.6.x and higher.""" 276 return self.strategy.int_to_bin(self.value)
277
278 - def __len__(self):
279 """@return: The size (width) of this address in bits""" 280 return self.strategy.width
281
282 - def __iter__(self):
283 """@return: An iterator over individual words in this address""" 284 return iter(self.strategy.int_to_words(self.value))
285
286 - def __getitem__(self, index):
287 """ 288 @return: The integer value of the word referenced by index (both 289 positive and negative). Raises C{IndexError} if index is out 290 of bounds. Also supports Python list slices for accessing 291 word groups. 292 """ 293 if isinstance(index, (int, long)): 294 # Indexing, including negative indexing goodness. 295 num_words = self.strategy.num_words 296 if not (-num_words) <= index <= (num_words - 1): 297 raise IndexError('index out range for address type!') 298 return self.strategy.int_to_words(self.value)[index] 299 elif isinstance(index, slice): 300 # Slicing baby! 301 words = self.strategy.int_to_words(self.value) 302 return [words[i] for i in range(*index.indices(len(words)))] 303 else: 304 raise TypeError('unsupported type %r!' % index)
305
306 - def __setitem__(self, index, value):
307 """Sets the value of the word referenced by index in this address""" 308 if isinstance(index, slice): 309 # TODO - settable slices. 310 raise NotImplementedError('settable slices not yet supported!') 311 312 if not isinstance(index, (int, long)): 313 raise TypeError('index not an integer!') 314 315 if not 0 <= index <= (self.strategy.num_words - 1): 316 raise IndexError('index %d outside address type boundary!' % index) 317 318 if not isinstance(value, (int, long)): 319 raise TypeError('value not an integer!') 320 321 if not 0 <= value <= self.strategy.max_word: 322 raise ValueError('value %d outside word size maximum of %d bits!' 323 % (value, self.strategy.word_size)) 324 325 words = list(self.strategy.int_to_words(self.value)) 326 words[index] = value 327 self.value = self.strategy.words_to_int(words)
328
329 - def __hex__(self):
330 """ 331 @return: hexadecimal string representation of this address (in network 332 byte order). 333 """ 334 return hex(self.value).rstrip('L').lower()
335
336 - def __iadd__(self, num):
337 """ 338 Increment value of network address by specified amount. Behaves like 339 an unsigned integer, rolling over to zero when it reaches the maximum 340 value threshold. 341 342 @param num: size of increment 343 """ 344 try: 345 new_value = self.value + num 346 if new_value > self.strategy.max_int: 347 self.value = new_value - (self.strategy.max_int + 1) 348 else: 349 self.value = new_value 350 except TypeError: 351 raise TypeError('Increment value must be an integer!') 352 return self
353
354 - def __isub__(self, num):
355 """ 356 Decrement value of network address by specified amount. Behaves like 357 an unsigned integer, rolling over to maximum value when it goes below 358 zero. 359 360 @param num: size of decrement 361 """ 362 try: 363 new_value = self.value - num 364 if new_value < 0: 365 self.value = new_value + (self.strategy.max_int + 1) 366 else: 367 self.value = new_value 368 except TypeError: 369 raise TypeError('Decrement value must be an integer!') 370 return self
371
372 - def __add__(self, other):
373 """ 374 @param other: an integer or int-like object. 375 376 @return: A new (potentially larger) Addr class/subclass instance. 377 """ 378 return self.__class__(self.value + int(other), self.addr_type)
379
380 - def __sub__(self, other):
381 """ 382 @param other: an integer or int-like object. 383 384 @return: A new (potentially smaller) Addr class/subclass instance. 385 """ 386 return self.__class__(self.value - int(other), self.addr_type)
387
388 - def __eq__(self, other):
389 """ 390 @return: C{True} if this address is numerically the same as other, 391 C{False} otherwise. 392 """ 393 try: 394 return (self.addr_type, self.value) == (other.addr_type, 395 other.value) 396 except AttributeError: 397 return False
398
399 - def __ne__(self, other):
400 """ 401 @return: C{False} if this address is numerically the same as the 402 other, C{True} otherwise. 403 """ 404 try: 405 return (self.addr_type, self.value) != (other.addr_type, 406 other.value) 407 except AttributeError: 408 return True
409
410 - def __lt__(self, other):
411 """ 412 @return: C{True} if this address is numerically lower in value than 413 other, C{False} otherwise. 414 """ 415 try: 416 return (self.addr_type, self.value) < (other.addr_type, 417 other.value) 418 except AttributeError: 419 return False
420
421 - def __le__(self, other):
422 """ 423 @return: C{True} if this address is numerically lower or equal in 424 value to other, C{False} otherwise. 425 """ 426 try: 427 return (self.addr_type, self.value) <= (other.addr_type, 428 other.value) 429 except AttributeError: 430 return False
431
432 - def __gt__(self, other):
433 """ 434 @return: C{True} if this address is numerically greater in value than 435 other, C{False} otherwise. 436 """ 437 try: 438 return (self.addr_type, self.value) > (other.addr_type, 439 other.value) 440 except AttributeError: 441 return False
442
443 - def __ge__(self, other):
444 """ 445 @return: C{True} if this address is numerically greater or equal in 446 value to other, C{False} otherwise. 447 """ 448 try: 449 return (self.addr_type, self.value) >= (other.addr_type, 450 other.value) 451 except AttributeError: 452 return False
453
454 - def __or__(self, other):
455 """ 456 @param other: An Addr (sub)class instance (or int-like object). 457 458 @return: bitwise OR (x | y) between the integer value of this IP 459 address and another. 460 """ 461 return self.__class__(self.value | other.value, self.addr_type)
462
463 - def __and__(self, other):
464 """ 465 @param other: An Addr (sub)class instance (or int-like object). 466 467 @return: bitwise AND (x & y) between the integer value of this 468 address and another. 469 """ 470 return self.__class__(self.value & other.value, self.addr_type)
471
472 - def __xor__(self, other):
473 """ 474 @param other: An Addr (sub)class instance (or int-like object). 475 476 @return: bitwise exclusive OR (x ^ y) between the integer value of 477 this address and another. 478 """ 479 return self.__class__(self.value ^ other.value, self.addr_type)
480
481 - def __lshift__(self, numbits):
482 """ 483 @param numbits: size of bitwise shift. 484 485 @return: an address based on this one with its integer value 486 left shifted by x bits. 487 """ 488 return self.__class__(self.value << numbits, self.addr_type)
489
490 - def __rshift__(self, numbits):
491 """ 492 @param numbits: size of bitwise shift. 493 494 @return: an address based on this one with its integer value 495 right shifted by x bits. 496 """ 497 return self.__class__(self.value >> numbits, self.addr_type)
498
499 - def __nonzero__(self):
500 """ 501 @return: True if the numerical value of this address is not zero, 502 False otherwise. 503 """ 504 return bool(self.value)
505
506 #----------------------------------------------------------------------------- 507 -class EUI(Addr):
508 """ 509 Represents an IEEE EUI (Extended Unique Identifier) indentifier. 510 511 Input parser is flexible, supporting EUI-48 (including the many Media 512 Access Control variants) and EUI-64. 513 """ 514 STRATEGIES = (ST_EUI48, ST_EUI64) 515 ADDR_TYPES = (AT_UNSPEC, AT_LINK, AT_EUI64) 516 517 # Descriptor registrations. 518 strategy = StrategyDescriptor(STRATEGIES) 519 addr_type = AddrTypeDescriptor(ADDR_TYPES) 520
521 - def __init__(self, addr, addr_type=AT_UNSPEC):
522 """ 523 Constructor. 524 525 @param addr: an EUI-48 (MAC) or EUI-64 address in string format or as 526 an unsigned integer. 527 528 @param addr_type: (optional) the specific EUI address type (C{AT_LINK} 529 or C{AT_EUI64}). This argument is used mainly to differentiate 530 EUI48 and EUI48 identifiers that may be numerically equivalent. 531 """ 532 # Choose a sensible default when addr is an integer and addr_type is 533 # not specified. 534 if addr_type == AT_UNSPEC: 535 if 0 <= addr <= 0xffffffffffff: 536 addr_type = AT_LINK 537 elif 0xffffffffffff < addr <= 0xffffffffffffffff: 538 addr_type = AT_EUI64 539 540 super(EUI, self).__init__(addr, addr_type)
541
542 - def oui(self, fmt=OUI):
543 """ 544 @param fmt: callable used on return values. Default: L{OUI} object. 545 Also Supports str(), unicode(), int() and long(). 546 547 @return: The OUI (Organisationally Unique Identifier) for this EUI. 548 """ 549 if callable(fmt) and fmt in (OUI, int, long): 550 return fmt(self.value >> 24) 551 elif callable(fmt) and fmt in (str, unicode, None): 552 return '-'.join(["%02x" % i for i in self[0:3]]).upper() 553 else: 554 raise TypeError("unsupported formatter callable: %r!" % fmt)
555
556 - def ei(self):
557 """@return: The EI (Extension Identifier) for this EUI""" 558 if self.strategy == ST_EUI48: 559 return '-'.join(["%02x" % i for i in self[3:6]]).upper() 560 elif self.strategy == ST_EUI64: 561 return '-'.join(["%02x" % i for i in self[3:8]]).upper()
562
563 - def isiab(self):
564 """@return: True if this EUI is an IAB address, False otherwise""" 565 return 0x50c2000 <= (self.value >> 12) <= 0x50c2fff
566
567 - def iab(self, fmt=IAB):
568 """ 569 @param fmt: callable used on return values. Default: L{IAB} object. 570 Also Supports str(), unicode(), int() and long(). 571 572 @return: If isiab() is True, the IAB (Individual Address Block) 573 is returned, None otherwise. 574 """ 575 if self.isiab(): 576 if callable(fmt) and fmt in (IAB, int, long): 577 return fmt(self.value >> 12) 578 elif callable(fmt) and fmt in (str, unicode, None): 579 usermask = (1 << (self.strategy.width - 36)) - 1 580 last_eui = self.value | usermask 581 first_eui = last_eui - usermask 582 iab_words = self.strategy.int_to_words(first_eui) 583 return '-'.join(["%02x" % i for i in iab_words]).upper() 584 else: 585 raise TypeError("unsupported formatter callable: %r!" % fmt)
586
587 - def eui64(self):
588 """ 589 @return: The value of this EUI object as a new 64-bit EUI object. 590 - If this object represents an EUI-48 it is converted to EUI-64 591 as per the standard. 592 - If this object is already and EUI-64, it just returns a new, 593 numerically equivalent object is returned instead. 594 """ 595 if self.addr_type == AT_LINK: 596 eui64_words = ["%02x" % i for i in self[0:3]] + ['ff', 'fe'] + \ 597 ["%02x" % i for i in self[3:6]] 598 599 return self.__class__('-'.join(eui64_words)) 600 else: 601 return EUI(str(self))
602 631
632 - def info(self):
633 """ 634 @return: A record dict containing IEEE registration details for this 635 EUI (MAC-48) if available, None otherwise. 636 """ 637 data = {'OUI': self.oui().registration()} 638 if self.isiab(): 639 data['IAB'] = self.iab().registration() 640 return data
641
642 #----------------------------------------------------------------------------- 643 -class IP(Addr):
644 """ 645 Represents B{individual} IPv4 and IPv6 addresses. 646 647 B{Please Note:} this class is intended to provide low-level functionality 648 to individual IP addresses such as octet/hextet access, integer/hex/binary 649 conversions, etc. If you are coming from other libraries you may expect to 650 find much higher level networking operations here. While the inclusion of 651 a bitmask prefix or netmask to indicate subnet membership is permitted by 652 the class constructor they are provided only as a convenience to the user. 653 654 All higher level subnet and network operations can be found in objects of 655 classes L{CIDR}, L{IPRange} and L{Wildcard}. There are handy helper methods 656 here, (C{.cidr()}, C{.iprange()} and C{.wildcard()}) that return pre-initialised 657 objects of those classes without you having to call them explicitly. 658 659 Example usage :: 660 661 >>> ip = IP('10.0.0.1') 662 >>> list(ip) == [10, 0, 0, 1] 663 True 664 >>> ip += 1 665 >>> str(ip) == '10.0.0.2' 666 True 667 668 >>> IP('10.0.0.0/28').iprange() 669 IPRange('10.0.0.0', '10.0.0.15') 670 671 >>> IP('10.0.0.64/24').cidr() 672 CIDR('10.0.0.0/24') 673 674 >>> IP('192.168.0.1/255.255.253.0').wildcard() 675 Wildcard('192.168.0-1.*') 676 677 >>> ipv6 = IP('fe80::20f:1fff:fe12:e733') 678 >>> ipv6[0:4] 679 [65152, 0, 0, 0] 680 681 >>> IP('fe80::20f:1fff:fe12:e733/64').cidr() 682 CIDR('fe80::/64') 683 684 See those classes for details on the functionality they provide. 685 """ 686 STRATEGIES = (ST_IPV4, ST_IPV6) 687 ADDR_TYPES = (AT_UNSPEC, AT_INET, AT_INET6) 688 TRANSLATE_STR = ''.join([chr(_) for _ in range(256)]) #FIXME: replace this 689 690 # Descriptor registrations. 691 strategy = StrategyDescriptor(STRATEGIES) 692 addr_type = AddrTypeDescriptor(ADDR_TYPES) 693 prefixlen = PrefixLenDescriptor() 694
695 - def __init__(self, addr, addr_type=AT_UNSPEC):
696 """ 697 Constructor. 698 699 @param addr: an IPv4 or IPv6 address string with an optional subnet 700 prefix or an unsigned integer. 701 702 @param addr_type: (optional) the IP address type (C{AT_INET} or 703 C{AT_INET6}). This argument is used mainly to differentiate IPv4 704 and IPv6 addresses that may be numerically equivalent. 705 """ 706 prefixlen = None 707 # Check for prefix in address and split it out. 708 try: 709 if '/' in addr: 710 (addr, prefixlen) = addr.split('/', 1) 711 except TypeError: 712 # addr is an int - let it pass through. 713 pass 714 715 # Choose a sensible default when addr is an integer and addr_type is 716 # not specified. 717 if addr_type == AT_UNSPEC: 718 if 0 <= addr <= 0xffffffff: 719 addr_type = AT_INET 720 elif 0xffffffff < addr <= 0xffffffffffffffffffffffffffffffff: 721 addr_type = AT_INET6 722 723 # Call superclass constructor before processing subnet prefix to 724 # assign the strategyn object. 725 super(IP, self).__init__(addr, addr_type) 726 727 # Set the subnet prefix. 728 if prefixlen is None: 729 self.__dict__['prefixlen'] = self.strategy.width 730 else: 731 self.prefixlen = prefixlen
732
733 - def is_netmask(self):
734 """ 735 @return: C{True} if this addr is a mask that would return a host id, 736 C{False} otherwise. 737 """ 738 int_val = (self.value ^ self.strategy.max_int) + 1 739 return (int_val & (int_val - 1) == 0)
740
741 - def netmask_bits(self): #FIXME: replace this
742 """ 743 @return: If this address is a valid netmask, the number of non-zero 744 bits are returned, otherwise it returns the width in bits for 745 based on the version, 32 for IPv4 and 128 for IPv6. 746 """ 747 if not self.is_netmask(): 748 return self.strategy.width 749 750 bits = self.strategy.int_to_bits(self.value) 751 mask_bits = bits.translate(IP.TRANSLATE_STR, ':.0') 752 mask_length = len(mask_bits) 753 754 if not 0 <= mask_length <= self.strategy.width: 755 raise ValueError('Unexpected mask length %d for address type!' \ 756 % mask_length) 757 758 return mask_length
759
760 - def reverse_dns(self):
761 """@return: The reverse DNS lookup string for this IP address""" 762 return self.strategy.int_to_arpa(self.value)
763
764 - def is_hostmask(self):
765 """ 766 @return: C{True} if this address is a mask that would return a host 767 id, C{False} otherwise. 768 """ 769 int_val = self.value + 1 770 return (int_val & (int_val-1) == 0)
771
772 - def hostname(self):
773 """ 774 @return: Returns the FQDN for this IP address via a DNS query 775 using gethostbyaddr() Python's socket module. 776 """ 777 try: 778 return _socket.gethostbyaddr(str(self))[0] 779 except: 780 return
781
782 - def cidr(self, strict=True):
783 """ 784 @param strict: (optional) If True and non-zero bits are found to the 785 right of the subnet mask/prefix a ValueError is raised. If False, 786 CIDR returned has these bits automatically truncated. 787 (default: True) 788 789 @return: A L{CIDR} object based on this IP address 790 """ 791 hostmask = (1 << (self.strategy.width - self.prefixlen)) - 1 792 start = (self.value | hostmask) - hostmask 793 network = self.strategy.int_to_str(start) 794 return CIDR("%s/%d" % (network, self.prefixlen), strict=strict)
795
796 - def wildcard(self):
797 """@return: A L{Wildcard} object based on this IP address""" 798 if self.addr_type == AT_INET6: 799 raise AddrConversionError('wildcards not support by IPv6!') 800 return self.iprange().wildcard()
801
802 - def iprange(self):
803 """@return: A L{CIDR} object based on this IP address""" 804 hostmask = (1 << (self.strategy.width - self.prefixlen)) - 1 805 netmask = self.strategy.max_int ^ hostmask 806 first = (self.value | hostmask) - hostmask 807 last = first | hostmask 808 return IPRange(self.strategy.int_to_str(first), 809 self.strategy.int_to_str(last))
810
811 - def ipv4(self):
812 """ 813 @return: A new version 4 L{IP} object numerically equivalent this 814 address. If this object is already IPv4 then a copy is returned. If 815 this object is IPv6 and its value is compatible with IPv4, a new IPv4 816 L{IP} object is returned. 817 818 Raises an L{AddrConversionError} is IPv6 address cannot be converted. 819 """ 820 ip_addr = None 821 if self.addr_type == AT_INET: 822 ip_addr = IP(self.value, AT_INET) 823 ip_addr.prefixlen = self.prefixlen 824 elif self.addr_type == AT_INET6: 825 words = self.strategy.int_to_words(self.value) 826 #TODO: Replace these with bit shifts. 827 if words[0:6] == (0, 0, 0, 0, 0, 0): 828 ip_addr = IP(self.value, AT_INET) 829 ip_addr.prefixlen = self.prefixlen - 96 830 #TODO: Replace these with bit shifts. 831 elif words[0:6] == (0, 0, 0, 0, 0, 0xffff): 832 ip_addr = IP(self.value - 0xffff00000000, AT_INET) 833 ip_addr.prefixlen = self.prefixlen - 96 834 else: 835 raise AddrConversionError('IPv6 address %s not suitable for' \ 836 'IPv4 conversion!' % self) 837 return ip_addr
838
839 - def ipv6(self, ipv4_compatible=False):
840 """ 841 B{Please Note:} the IPv4-Mapped IPv6 address format is now considered 842 deprecated. Reference: RFC 4291 843 844 @param ipv4_compatible: If C{True} returns an IPv4-Mapped address 845 (::ffff:x.x.x.x), an IPv4-Compatible (::x.x.x.x) address 846 otherwise. Default: False (IPv4-Mapped). 847 848 @return: A new L{IP} version 6 object that is numerically equivalent 849 this address. If this object is already IPv6 then a copy of this 850 object is returned. If this object is IPv4, a new version 6 L{IP} 851 object is returned. 852 """ 853 ip_addr = None 854 if self.addr_type == AT_INET6: 855 ip_addr = IP(self.value, AT_INET6) 856 ip_addr.prefixlen = self.prefixlen - 96 857 elif self.addr_type == AT_INET: 858 ip_addr = IP(self.value, AT_INET6) 859 if ipv4_compatible: 860 # IPv4-Compatible IPv6 address 861 ip_addr[5] = 0 862 else: 863 # IPv4-Mapped IPv6 address 864 ip_addr[5] = 0xffff 865 ip_addr.prefixlen = self.prefixlen + 96 866 return ip_addr
867
868 - def is_unicast(self):
869 """@return: C{True} if this IP is unicast, C{False} otherwise""" 870 return not self.is_multicast()
871
872 - def is_loopback(self):
873 """ 874 @return: C{True} if this IP is loopback address (not for network 875 transmission), C{False} otherwise. 876 References: RFC 3330 and 4291. 877 """ 878 if self.addr_type == AT_INET: 879 return self in CIDR('127/8') 880 elif self.addr_type == AT_INET6: 881 return self == IP('::1')
882
883 - def is_multicast(self):
884 """@return: C{True} if this IP is multicast, C{False} otherwise""" 885 if self.addr_type == AT_INET: 886 return self in CIDR('224/4') 887 elif self.addr_type == AT_INET6: 888 return self in CIDR('ff00::/8')
889
890 - def is_private(self):
891 """ 892 @return: C{True} if this IP is for internal/private use only 893 (i.e. non-public), C{False} otherwise. Reference: RFCs 1918, 894 3330, 4193, 3879 and 2365. 895 """ 896 if self.addr_type == AT_INET: 897 for cidr in (CIDR('192.168/16'), CIDR('10/8'),CIDR('172.16/12'), 898 CIDR('192.0.2.0/24'), CIDR('239.192/14')): 899 if self in cidr: 900 return True 901 elif self.addr_type == AT_INET6: 902 # Please Note: FEC0::/10 has been deprecated! See RFC 3879. 903 return self in CIDR('fc00::/7') # ULAs - Unique Local Addresses 904 905 if self.is_link_local(): 906 return True 907 908 return False
909 919
920 - def is_reserved(self):
921 """ 922 @return: C{True} if this IP is in IANA reserved range, C{False} 923 otherwise. Reference: RFCs 3330 and 3171. 924 """ 925 if self.addr_type == AT_INET: 926 # Use of wildcards here much more concise than CIDR... 927 for cidr in (CIDR('240/4'), CIDR('234/7'), CIDR('236/7'), 928 Wildcard('225-231.*.*.*'), Wildcard('234-238.*.*.*')): 929 if self in cidr: 930 return True 931 if self.addr_type == AT_INET6: 932 for cidr in (CIDR('ff00::/12'),CIDR('::/8'), CIDR('0100::/8'), 933 CIDR('0200::/7'), CIDR('0400::/6'), CIDR('0800::/5'), 934 CIDR('1000::/4'), CIDR('4000::/3'), CIDR('6000::/3'), 935 CIDR('8000::/3'), CIDR('A000::/3'), CIDR('C000::/3'), 936 CIDR('E000::/4'), CIDR('F000::/5'), CIDR('F800::/6'), 937 CIDR('FE00::/9')): 938 if self in cidr: 939 return True 940 return False
941
942 - def is_ipv4_mapped(self):
943 """ 944 @return: C{True} if this IP is IPv4-compatible IPv6 address, C{False} 945 otherwise. 946 """ 947 return self.addr_type == AT_INET6 and (self.value >> 32) == 0xffff
948
949 - def is_ipv4_compat(self):
950 """ 951 @return: C{True} if this IP is IPv4-mapped IPv6 address, C{False} 952 otherwise. 953 """ 954 return self.addr_type == AT_INET6 and (self.value >> 32) == 0
955
956 - def info(self):
957 """ 958 @return: A record dict containing IANA registration details for this 959 IP address if available, None otherwise. 960 """ 961 # This import is placed here for efficiency. If you don't call this 962 # method, you don't take the (small), one time, import start up 963 # penalty. Also gets around a nasty module dependency issue. 964 # Two birds, one stone ... 965 import netaddr.ip 966 return netaddr.ip.query(self)
967
968 - def __str__(self):
969 """@return: common string representation for this IP address""" 970 return self.strategy.int_to_str(self.value)
971
972 - def __repr__(self):
973 """@return: executable Python string to recreate equivalent object.""" 974 if self.prefixlen == self.strategy.width: 975 return "%s('%s')" % (self.__class__.__name__, str(self)) 976 977 return "%s('%s/%d')" % (self.__class__.__name__, str(self), 978 self.prefixlen)
979
980 #----------------------------------------------------------------------------- 981 -def nrange(start, stop, step=1, fmt=None):
982 """ 983 An xrange work alike generator that produces sequences of IP addresses 984 based on start and stop addresses, in intervals of step size. 985 986 @param start: first IP address string or L{IP} object in range. 987 988 @param stop: last IP address string or L{IP} object in range 989 990 @param step: (optional) size of step between address in range. 991 (Default: 1) 992 993 @param fmt: (optional) callable used on addresses returned. 994 (Default: None - L{IP} objects). Supported options :- 995 - C{str} - IP address in string format 996 - C{int}, C{long} - IP address as an unsigned integer 997 - C{hex} - IP address as a hexadecimal number 998 - L{IP} class/subclass or callable that accepts C{addr_value} and 999 C{addr_type} arguments. 1000 """ 1001 if not isinstance(start, IP): 1002 if isinstance(start, (str, unicode)): 1003 start = IP(start) 1004 else: 1005 raise TypeError('start is not recognised address in string ' \ 1006 'format or IP class/subclass instance!') 1007 else: 1008 # Use start object's constructor as formatter. 1009 if fmt is None: 1010 fmt = start.__class__ 1011 1012 if not isinstance(stop, IP): 1013 if isinstance(stop, (str, unicode)): 1014 stop = IP(stop) 1015 else: 1016 raise TypeError('stop is not recognised address string ' \ 1017 'or IP class/subclass instance!') 1018 1019 if not isinstance(step, (int, long)): 1020 raise TypeError('step must be type int|long, not %s!' % type(step)) 1021 1022 if start.addr_type != stop.addr_type: 1023 raise TypeError('start and stop are not the same address type!') 1024 1025 if step == 0: 1026 raise ValueError('step argument cannot be zero') 1027 1028 negative_step = False 1029 addr_type = start.addr_type 1030 1031 # We don't need objects from here onwards. Basic integer values will do 1032 # just fine. 1033 start_fmt = start.__class__ 1034 start = int(start) 1035 stop = int(stop) 1036 1037 if step < 0: 1038 negative_step = True 1039 1040 index = start - step 1041 1042 # Default formatter. 1043 if fmt is None: 1044 fmt = IP 1045 1046 if fmt in (int, long, hex): 1047 # Yield network address integer values. 1048 while True: 1049 index += step 1050 if negative_step: 1051 if not index >= stop: 1052 return 1053 else: 1054 if not index <= stop: 1055 return 1056 yield fmt(index) 1057 elif fmt in (str, unicode): 1058 # Yield address string values. 1059 while True: 1060 index += step 1061 if negative_step: 1062 if not index >= stop: 1063 return 1064 else: 1065 if not index <= stop: 1066 return 1067 yield str(start_fmt(index, addr_type)) 1068 else: 1069 # Yield network address objects. 1070 while True: 1071 index += step 1072 if negative_step: 1073 if not index >= stop: 1074 return 1075 else: 1076 if not index <= stop: 1077 return 1078 1079 yield fmt(index, addr_type)
1080
1081 #----------------------------------------------------------------------------- 1082 -class IPRange(object):
1083 """ 1084 Represents arbitrary contiguous blocks of IPv4 and IPv6 addresses using 1085 only a lower and upper bound IP address. 1086 1087 It is the base class for more specialised block types such as L{CIDR()} 1088 and L{Wildcard()}. There is no requirement that the boundary IP addresses 1089 fall on strict bitmask boundaries. 1090 1091 The sort order for sequence of mixed version L{IPRange} objects is IPv4 1092 followed by IPv6, based on the range's magnitude (size). 1093 """ 1094 STRATEGIES = (ST_IPV4, ST_IPV6) 1095 ADDR_TYPES = (AT_UNSPEC, AT_INET, AT_INET6) 1096 1097 # Descriptor registrations. 1098 strategy = StrategyDescriptor(STRATEGIES) 1099 addr_type = AddrTypeDescriptor(ADDR_TYPES) 1100 first = AddrValueDescriptor('first') 1101 last = AddrValueDescriptor('last') 1102 fmt = FormatDescriptor(IP) 1103
1104 - def __init__(self, first, last, fmt=IP):
1105 """ 1106 Constructor. 1107 1108 @param first: start address for this IP address range. 1109 1110 @param last: stop address for this IP address range. 1111 1112 @param fmt: (optional) callable used to create return values. 1113 Default: L{IP()} objects. See L{nrange()} documentations for 1114 more details on the various options. 1115 """ 1116 #TODO: this can be optimised, consider accepting addr_type via the 1117 #TODO: constructor. 1118 self.addr_type = AT_UNSPEC 1119 self.first = first 1120 self.last = last 1121 if self.last < self.first: 1122 raise IndexError('start address is greater than stop address!') 1123 self.fmt = fmt
1124
1125 - def __hash__(self):
1126 """ 1127 @return: The hash of this address range. Allow them to be used in sets 1128 and as keys in dictionaries. 1129 """ 1130 return hash((self.addr_type, self.first, self.last))
1131
1132 - def tuple(self):
1133 """ 1134 @return: A 3-element tuple (first, last, addr_type) which represent 1135 the basic details of this IPRange object. 1136 """ 1137 return self.first, self.last, self.addr_type
1138
1139 - def __len__(self):
1140 """ 1141 @return: The total number of network addresses in this range. 1142 - Use this method only for ranges that contain less than 1143 C{2^31} addresses or try the L{size()} method. Raises an 1144 C{IndexError} if size is exceeded. 1145 """ 1146 size = self.size() 1147 if size > (2 ** 31): 1148 # Use size() method in this class instead as len() will b0rk! 1149 raise IndexError("range contains greater than 2^31 addresses! " \ 1150 "Use obj.size() instead.") 1151 return size
1152
1153 - def size(self):
1154 """ 1155 @return: The total number of network addresses in this range. 1156 - Use this method in preference to L{__len__()} when size of 1157 ranges potentially exceeds C{2^31} addresses. 1158 """ 1159 return self.last - self.first + 1
1160
1161 - def format(self, int_addr, fmt=None):
1162 """ 1163 @param int_addr: a network address as an unsigned integer. 1164 1165 @param fmt: (optional) a callable used on return values. 1166 Default: None. If set to None, this method uses the self.fmt 1167 setting instead. The argument is provided as an override option. 1168 1169 @return: a network address in the format returned after passing it 1170 through this object's fmt property callable. 1171 """ 1172 if fmt is None: 1173 fmt = self.fmt 1174 1175 if fmt in (str, unicode): 1176 return self.strategy.int_to_str(int_addr) 1177 elif fmt in (int, long, hex): 1178 return fmt(int_addr) 1179 else: 1180 return fmt(int_addr, self.addr_type)
1181
1182 - def __getitem__(self, index):
1183 """ 1184 @return: The IP address(es) in this address range referenced by 1185 index/slice. Slicing objects can produce large sequences so 1186 generator objects are returned instead of a list. Wrapping a slice 1187 with C{list()} or C{tuple()} may be required dependent on context 1188 in which it is called. 1189 """ 1190 1191 if isinstance(index, (int, long)): 1192 if (- self.size()) <= index < 0: 1193 # negative index. 1194 return self.format(self.last + index + 1) 1195 elif 0 <= index <= (self.size() - 1): 1196 # Positive index or zero index. 1197 return self.format(self.first + index) 1198 else: 1199 raise IndexError('index out range for address range size!') 1200 elif isinstance(index, slice): 1201 # slices 1202 #FIXME: IPv6 breaks the .indices() method on the slice object 1203 #FIXME: spectacularly. We'll have to work out the start, stop and 1204 #FIXME: step ourselves :-( 1205 # 1206 #FIXME: see PySlice_GetIndicesEx function in Python SVN 1207 #FIXME: repository for implementation details :- 1208 # http://svn.python.org/view/python/trunk/Objects/sliceobject.c 1209 (start, stop, step) = index.indices(self.size()) 1210 1211 start_addr = IP(self.first + start, self.addr_type) 1212 end_addr = IP(self.first + stop - step, self.addr_type) 1213 return nrange(start_addr, end_addr, step, fmt=self.fmt) 1214 else: 1215 raise TypeError('unsupported type %r!' % index)
1216
1217 - def __iter__(self):
1218 """ 1219 @return: An iterator object providing access to all network addresses 1220 within this range. 1221 """ 1222 start_addr = IP(self.first, self.addr_type) 1223 end_addr = IP(self.last, self.addr_type) 1224 return nrange(start_addr, end_addr, fmt=self.fmt)
1225
1226 - def __contains__(self, addr):
1227 """ 1228 @param addr: and IP/IPRange class/subclass instance or IP string value 1229 to be compared. 1230 1231 @return: C{True} if given address or range falls within this range, 1232 C{False} otherwise. 1233 """ 1234 if isinstance(addr, (str, unicode)): 1235 # string address or address range. 1236 c_addr = IP(addr) 1237 if c_addr.addr_type == self.addr_type: 1238 if self.first <= int(c_addr) <= self.last: 1239 return True 1240 elif isinstance(addr, IP): 1241 # Single value check. 1242 if self.first <= int(addr) <= self.last: 1243 return True 1244 elif issubclass(addr.__class__, IPRange): 1245 # Range value check. 1246 if addr.first >= self.first and addr.last <= self.last: 1247 return True 1248 else: 1249 raise TypeError('%r is an unsupported type or class!' % addr) 1250 1251 return False
1252
1253 - def __eq__(self, other):
1254 """ 1255 @param other: an address object of the same address type as C{self}. 1256 1257 @return: C{True} if the boundaries of this range are the same as 1258 other, C{False} otherwise. 1259 """ 1260 try: 1261 return (self.addr_type, self.first, self.last) == \ 1262 (other.addr_type, other.first, other.last) 1263 except AttributeError: 1264 return False
1265
1266 - def __ne__(self, other):
1267 """ 1268 @param other: an address object of the same address type as C{self}. 1269 1270 @return: C{False} if the boundaries of this range are the same as 1271 other, C{True} otherwise. 1272 """ 1273 try: 1274 return (self.addr_type, self.first, self.last) != \ 1275 (other.addr_type, other.first, other.last) 1276 except AttributeError: 1277 return True
1278
1279 - def __lt__(self, other):
1280 """ 1281 @param other: an address object of the same address type as C{self}. 1282 1283 @return: C{True} if the boundaries of this range are less than other, 1284 C{False} otherwise. 1285 """ 1286 try: 1287 # A sort key is essentially a CIDR prefixlen value. 1288 # Required as IPRange (and subclasses other than CIDR) do not 1289 # calculate it. 1290 s_sortkey = self.strategy.width - num_bits(self.size()) 1291 o_sortkey = other.strategy.width - num_bits(other.size()) 1292 1293 return (self.addr_type, self.first, s_sortkey) < \ 1294 (other.addr_type, other.first, o_sortkey) 1295 except AttributeError: 1296 return False
1297
1298 - def __le__(self, other):
1299 """ 1300 @param other: an address object of the same address type as C{self}. 1301 1302 @return: C{True} if the boundaries of this range are less or equal to 1303 other, C{False} otherwise. 1304 """ 1305 try: 1306 # A sort key is essentially a CIDR prefixlen value. 1307 # Required as IPRange (and subclasses other than CIDR) do not 1308 # calculate it. 1309 s_sortkey = self.strategy.width - num_bits(self.size()) 1310 o_sortkey = other.strategy.width - num_bits(other.size()) 1311 1312 return (self.addr_type, self.first, s_sortkey) <= \ 1313 (other.addr_type, other.first, o_sortkey) 1314 except AttributeError: 1315 return False
1316
1317 - def __gt__(self, other):
1318 """ 1319 @param other: an address object of the same address type as C{self}. 1320 1321 @return: C{True} if the boundaries of this range are greater than 1322 other, C{False} otherwise. 1323 """ 1324 try: 1325 # A sort key is essentially a CIDR prefixlen value. 1326 # Required as IPRange (and subclasses other than CIDR) do not 1327 # calculate it. 1328 s_sortkey = self.strategy.width - num_bits(self.size()) 1329 o_sortkey = other.strategy.width - num_bits(other.size()) 1330 1331 return (self.addr_type, self.first, s_sortkey) > \ 1332 (other.addr_type, other.first, o_sortkey) 1333 except AttributeError: 1334 return False
1335
1336 - def __ge__(self, other):
1337 """ 1338 @param other: an address object of the same address type as C{self}. 1339 1340 @return: C{True} if the boundaries of this range are greater or equal 1341 to other, C{False} otherwise. 1342 """ 1343 try: 1344 # A sort key is essentially a CIDR prefixlen value. 1345 # Required as IPRange (and subclasses other than CIDR) do not 1346 # calculate it. 1347 s_sortkey = self.strategy.width - num_bits(self.size()) 1348 o_sortkey = other.strategy.width - num_bits(other.size()) 1349 1350 return (self.addr_type, self.first, s_sortkey) >= \ 1351 (other.addr_type, other.first, o_sortkey) 1352 except AttributeError: 1353 return False
1354
1355 - def __iadd__(self, i):
1356 """ 1357 Increments start and end addresses of this range by the current size. 1358 1359 Raises IndexError if the result exceeds address range maximum. 1360 """ 1361 try: 1362 new_first = self.first + (self.size() * i) 1363 new_last = self.last + (self.size() * i) 1364 except TypeError: 1365 raise TypeError('Increment value must be an integer!') 1366 1367 if new_last > self.strategy.max_int: 1368 raise IndexError('Invalid increment is outside address boundary!') 1369 1370 self.first = new_first 1371 self.last = new_last 1372 1373 return self
1374
1375 - def __isub__(self, i):
1376 """ 1377 Decrements start and end addresses of this range by the current size. 1378 1379 Raises IndexError if the result is less than zero. 1380 """ 1381 try: 1382 new_first = self.first - (self.size() * i) 1383 new_last = self.last - (self.size() * i) 1384 except TypeError: 1385 raise TypeError('Decrement value must be an integer!') 1386 1387 if new_last < 0: 1388 raise IndexError('Invalid decrement is outside address boundary!') 1389 1390 self.first = new_first 1391 self.last = new_last 1392 1393 return self
1394
1395 - def iprange(self):
1396 """ 1397 @return: A valid L{IPRange} object for this address range. 1398 """ 1399 #TODO: this can be optimised. 1400 ip_range = IPRange(self.strategy.int_to_str(self.first), 1401 self.strategy.int_to_str(self.last)) 1402 if self.fmt == str: 1403 return str(ip_range) 1404 return ip_range
1405
1406 - def cidrs(self):
1407 """ 1408 @return: A list of one or more L{CIDR} objects covering this address 1409 range. B{Please Note:} a list is returned even if this range maps 1410 to a single CIDR because arbitrary ranges may not be aligned with 1411 base 2 subnet sizes and will therefore return multiple CIDRs. 1412 """ 1413 # This can probably be tidied up a bit but I'm really proud of this 1414 # method. It is one seriously sweet piece of code!!! 1415 cidr_list = [] 1416 1417 # Get spanning CIDR covering both addresses. 1418 start = IP(self.first, self.addr_type) 1419 end = IP(self.last, self.addr_type) 1420 1421 cidr_span = CIDR.span([start, end]) 1422 1423 if cidr_span.first == self.first and cidr_span.last == self.last: 1424 # Spanning CIDR matches start and end exactly. 1425 cidr_list = [cidr_span] 1426 elif cidr_span.last == self.last: 1427 # Spanning CIDR matches end exactly. 1428 ip = IP(start) 1429 first_int_val = int(ip) 1430 ip -= 1 1431 cidr_remainder = cidr_span - ip 1432 1433 first_found = False 1434 for cidr in cidr_remainder: 1435 if cidr.first == first_int_val: 1436 first_found = True 1437 if first_found: 1438 cidr_list.append(cidr) 1439 elif cidr_span.first == self.first: 1440 # Spanning CIDR matches start exactly. 1441 ip = IP(end) 1442 last_int_val = int(ip) 1443 ip += 1 1444 cidr_remainder = cidr_span - ip 1445 1446 last_found = False 1447 for cidr in cidr_remainder: 1448 cidr_list.append(cidr) 1449 if cidr.last == last_int_val: 1450 break 1451 elif cidr_span.first <= self.first and cidr_span.last >= self.last: 1452 # Spanning CIDR overlaps start and end. 1453 ip = IP(start) 1454 first_int_val = int(ip) 1455 ip -= 1 1456 cidr_remainder = cidr_span - ip 1457 1458 # Fix start. 1459 first_found = False 1460 for cidr in cidr_remainder: 1461 if cidr.first == first_int_val: 1462 first_found = True 1463 if first_found: 1464 cidr_list.append(cidr) 1465 1466 # Fix end. 1467 ip = IP(end) 1468 last_int_val = int(ip) 1469 ip += 1 1470 cidr_remainder = cidr_list.pop() - ip 1471 1472 last_found = False 1473 for cidr in cidr_remainder: 1474 cidr_list.append(cidr) 1475 if cidr.last == last_int_val: 1476 break 1477 1478 # Return address list in requested format. 1479 if self.fmt in (str, unicode): 1480 cidr_list = [self.fmt(c) for c in cidr_list] 1481 1482 return cidr_list
1483
1484 - def wildcard(self):
1485 """ 1486 @return: A L{Wildcard} object equivalent to this CIDR. 1487 - If CIDR was initialised with C{fmt=str}, a wildcard string 1488 is returned, in all other cases a L{Wildcard} object is 1489 returned. 1490 - Only supports IPv4 CIDR addresses. 1491 """ 1492 t1 = self.strategy.int_to_words(self.first) 1493 t2 = self.strategy.int_to_words(self.last) 1494 1495 if self.addr_type != AT_INET: 1496 raise AddrConversionError('wildcards only suitable for IPv4 ' \ 1497 'ranges!') 1498 1499 tokens = [] 1500 1501 seen_hyphen = False 1502 seen_asterisk = False 1503 1504 for i in range(4): 1505 if t1[i] == t2[i]: 1506 # A normal octet. 1507 tokens.append(str(t1[i])) 1508 elif (t1[i] == 0) and (t2[i] == 255): 1509 # An asterisk octet. 1510 tokens.append('*') 1511 seen_asterisk = True 1512 else: 1513 # Create a hyphenated octet - only one allowed per wildcard. 1514 if not seen_asterisk: 1515 if not seen_hyphen: 1516 tokens.append('%s-%s' % (t1[i], t2[i])) 1517 seen_hyphen = True 1518 else: 1519 raise SyntaxError('only one hyphenated octet per ' \ 1520 'wildcard permitted!') 1521 else: 1522 raise SyntaxError("* chars aren't permitted before ' \ 1523 'hyphenated octets!") 1524 1525 wildcard = '.'.join(tokens) 1526 1527 if self.fmt == str: 1528 return wildcard 1529 1530 return Wildcard(wildcard)
1531
1532 - def issubnet(self, other):
1533 """ 1534 @return: True if other's boundary is equal to or within this range. 1535 False otherwise. 1536 """ 1537 if isinstance(other, (str, unicode)): 1538 other = CIDR(other) 1539 1540 if not hasattr(other, 'addr_type'): 1541 raise TypeError('%r is an unsupported argument type!' % other) 1542 1543 if self.addr_type != other.addr_type: 1544 raise TypeError('Ranges must be the same address type!') 1545 1546 return self.first >= other.first and self.last <= other.last
1547
1548 - def issupernet(self, other):
1549 """ 1550 @return: True if other's boundary is equal to or contains this range. 1551 False otherwise. 1552 """ 1553 if isinstance(other, (str, unicode)): 1554 other = CIDR(other) 1555 1556 if not hasattr(other, 'addr_type'): 1557 raise TypeError('%r is an unsupported argument type!' % other) 1558 1559 if self.addr_type != other.addr_type: 1560 raise TypeError('Ranges must be the same address type!') 1561 1562 return self.first <= other.first and self.last >= other.last
1563
1564 - def adjacent(self, other):
1565 """ 1566 @return: True if other's boundary touches the boundary of this 1567 address range, False otherwise. 1568 """ 1569 if isinstance(other, (str, unicode)): 1570 other = CIDR(other) 1571 1572 if not hasattr(other, 'addr_type'): 1573 raise TypeError('%r is an unsupported argument type!' % other) 1574 1575 if self.addr_type != other.addr_type: 1576 raise TypeError('addresses must be of the same type!') 1577 1578 if isinstance(other, IPRange): 1579 # Left hand side of this address range. 1580 if self.first == (other.last + 1): 1581 return True 1582 1583 # Right hand side of this address range. 1584 if self.last == (other.first - 1): 1585 return True 1586 elif isinstance(other, IP): 1587 # Left hand side of this address range. 1588 if self.first == (other.value + 1): 1589 return True 1590 1591 # Right hand side of this address range. 1592 if self.last == (other.value - 1): 1593 return True 1594 else: 1595 raise TypeError('unexpected error for argument: %r!') 1596 1597 return False
1598
1599 - def overlaps(self, other):
1600 """ 1601 @return: True if other's boundary crosses the boundary of this address 1602 range, False otherwise. 1603 """ 1604 if isinstance(other, (str, unicode)): 1605 other = CIDR(other) 1606 1607 if not hasattr(other, 'addr_type'): 1608 raise TypeError('%r is an unsupported argument type!' % other) 1609 1610 if self.addr_type != other.addr_type: 1611 raise TypeError('Ranges must be the same address type!') 1612 1613 # Left hand side of this address range. 1614 if self.first <= other.last <= self.last: 1615 return True 1616 1617 # Right hand side of this address range. 1618 if self.first <= other.first <= self.last: 1619 return True 1620 1621 return False
1622
1623 - def __str__(self):
1624 return "%s-%s" % (self.strategy.int_to_str(self.first), 1625 self.strategy.int_to_str(self.last))
1626
1627 - def __repr__(self):
1628 """@return: executable Python string to recreate equivalent object.""" 1629 return "%s(%r, %r)" % (self.__class__.__name__, 1630 self.strategy.int_to_str(self.first), 1631 self.strategy.int_to_str(self.last))
1632
1633 #----------------------------------------------------------------------------- 1634 -def cidr_to_bits(cidr):
1635 """ 1636 @param cidr: a CIDR object or CIDR string value (acceptable by CIDR class 1637 constructor). 1638 1639 @return: a tuple containing CIDR in binary string format and addr_type. 1640 """ 1641 if not hasattr(cidr, 'network'): 1642 cidr = CIDR(cidr, strict=False) 1643 1644 bits = cidr.network.bits(word_sep='') 1645 return (bits[0:cidr.prefixlen], cidr.addr_type)
1646
1647 #----------------------------------------------------------------------------- 1648 -def bits_to_cidr(bits, addr_type=AT_UNSPEC, fmt=None):
1649 """ 1650 @param bits: a CIDR in binary string format. 1651 1652 @param addr_type: (optional) CIDR address type (IP version). 1653 (Default: AT_UNSPEC - auto-select) If not specified AT_INET (IPv4) is 1654 assumed if length of binary string is <= /32. If binary string 1655 is > /32 and <= /128 AT_INET6 (IPv6) is assumed. Useful when you have 1656 IPv6 addresses with a prefixlen of /32 or less. 1657 1658 @param fmt: (optional) callable invoked on return CIDR. 1659 (Default: None - CIDR object). Also accepts str() and unicode(). 1660 1661 @return: a CIDR object or string (determined by fmt). 1662 """ 1663 if _re.match('^[01]+$', bits) is None: 1664 raise ValueError('%r is an invalid bit string!' % bits) 1665 1666 num_bits = len(bits) 1667 strategy = None 1668 if addr_type == AT_UNSPEC: 1669 if 0 <= num_bits <= 32: 1670 strategy = ST_IPV4 1671 elif 33 < num_bits <= 128: 1672 strategy = ST_IPV6 1673 else: 1674 raise ValueError('Invalid number of bits: %s!' % bits) 1675 elif addr_type == AT_INET: 1676 strategy = ST_IPV4 1677 elif addr_type == AT_INET6: 1678 strategy = ST_IPV6 1679 else: 1680 raise ValueError('strategy auto-select failure for %r!' % bits) 1681 1682 if bits == '': 1683 return CIDR('%s/0' % strategy.int_to_str(0)) 1684 1685 cidr = None 1686 bits = bits + '0' * (strategy.width - num_bits) 1687 ip = strategy.int_to_str(strategy.bits_to_int(bits)) 1688 cidr = CIDR('%s/%d' % (ip, num_bits)) 1689 1690 if fmt is not None: 1691 return fmt(cidr) 1692 1693 return cidr
1694
1695 #----------------------------------------------------------------------------- 1696 -class CIDR(IPRange):
1697 """ 1698 Represents blocks of IPv4 and IPv6 addresses using CIDR (Classless 1699 Inter-Domain Routing) notation. 1700 1701 CIDR is a method of categorising contiguous blocks of both IPv4 and IPv6 1702 addresses. It is very scalable allowing for the optimal usage of the IP 1703 address space. It permits the aggregation of networks via route 1704 summarisation (supernetting) where adjacent routes can be combined into a 1705 single route easily. This greatly assists in the reduction of routing 1706 table sizes and improves network router efficiency. 1707 1708 CIDR blocks are represented by a base network address and a prefix 1709 indicating the size of the (variable length) subnet mask. These are 1710 separated by a single '/' character. Subnet sizes increase in powers of 1711 base 2 aligning to bit boundaries. 1712 1713 It is technically invalid to have non-zero bits in a CIDR address to the 1714 right of the implied netmask. For user convenience this is however 1715 configurable and can be disabled using a constructor argument. 1716 1717 The constructor accepts CIDRs expressed in one of 4 different ways :- 1718 1719 A) Standard CIDR format :- 1720 1721 IPv4:: 1722 1723 x.x.x.x/y -> 192.0.2.0/24 1724 1725 where the x's represent the network address and y is the netmask 1726 prefix between 0 and 32. 1727 1728 IPv6:: 1729 1730 x::/y -> fe80::/10 1731 1732 where the x's represent the network address and y is the netmask 1733 prefix between 0 and 128. 1734 1735 B) Abbreviated CIDR format (IPv4 only):: 1736 1737 x -> 192 1738 x/y -> 10/8 1739 x.x/y -> 192.168/16 1740 x.x.x/y -> 192.168.0/24 1741 1742 which are equivalent to:: 1743 1744 x.0.0.0/y -> 192.0.0.0/24 1745 x.0.0.0/y -> 10.0.0.0/8 1746 x.x.0.0/y -> 192.168.0.0/16 1747 x.x.x.0/y -> 192.168.0.0/24 1748 1749 - The trailing zeros are implicit. 1750 - Old classful IP address rules apply if y is omitted. 1751 1752 C) Hybrid CIDR format (prefix replaced by netmask) :- 1753 1754 IPv4:: 1755 1756 x.x.x.x/y.y.y.y -> 192.0.2.0/255.255.255.0 1757 1758 IPv6:: 1759 1760 x::/y:: -> fe80::/ffc0:: 1761 1762 where the y's represent a valid netmask. 1763 1764 D) ACL-style CIDR format (prefix is replaced by a hostmask) :- 1765 1766 Akin to Cisco's ACL (Access Control List) bitmasking (reverse 1767 netmasks). 1768 1769 IPv4:: 1770 1771 x.x.x.x/y.y.y.y -> 192.0.2.0/0.0.0.255 1772 1773 IPv6:: 1774 1775 x::/y:: -> fe80::/3f:ffff:ffff:ffff:ffff:ffff:ffff:ffff 1776 1777 where the y's represent a valid hostmask. 1778 1779 Reference: RFCs 1338 and 4632. 1780 """ 1781 STRATEGIES = (ST_IPV4, ST_IPV6) 1782 ADDR_TYPES = (AT_UNSPEC, AT_INET, AT_INET6) 1783 1784 # Descriptor registrations. 1785 strategy = StrategyDescriptor(STRATEGIES) 1786 addr_type = AddrTypeDescriptor(ADDR_TYPES) 1787 prefixlen = PrefixLenDescriptor('CIDR') 1788 fmt = FormatDescriptor(IP) 1789 1790 @staticmethod
1791 - def abbrev_to_verbose(abbrev_cidr):
1792 """ 1793 A static method that converts abbreviated IPv4 CIDRs to their more 1794 verbose equivalent. 1795 1796 @param abbrev_cidr: an abbreviated CIDR. 1797 1798 Uses the old-style classful IP address rules to decide on a default 1799 subnet prefix if one is not explicitly provided. 1800 1801 Only supports IPv4 addresses. 1802 1803 Examples :: 1804 1805 10 - 10.0.0.0/8 1806 10/16 - 10.0.0.0/16 1807 128 - 128.0.0.0/16 1808 128/8 - 128.0.0.0/8 1809 192.168 - 192.168.0.0/16 1810 1811 @return: A verbose CIDR from an abbreviated CIDR or old-style classful 1812 network address, C{None} if format provided was not recognised or 1813 supported. 1814 """ 1815 # Internal function that returns a prefix value based on the old IPv4 1816 # classful network scheme that has been superseded (almost) by CIDR. 1817 def classful_prefix(octet): 1818 octet = int(octet) 1819 if not 0 <= octet <= 255: 1820 raise IndexError('Invalid octet: %r!' % octet) 1821 if 0 <= octet <= 127: # Legacy class 'A' classification. 1822 return 8 1823 elif 128 <= octet <= 191: # Legacy class 'B' classification. 1824 return 16 1825 elif 192 <= octet <= 223: # Legacy class 'C' classification. 1826 return 24 1827 elif octet == 224: # Multicast address range. 1828 return 4 1829 elif 225 <= octet <= 239: # Reserved. 1830 return 8 1831 return 32 # Default.
1832 1833 start = '' 1834 tokens = [] 1835 prefix = None 1836 1837 if isinstance(abbrev_cidr, (str, unicode)): 1838 # Don't support IPv6 for now... 1839 if ':' in abbrev_cidr: 1840 return None 1841 try: 1842 # Single octet partial integer or string address. 1843 i = int(abbrev_cidr) 1844 tokens = [str(i), '0', '0', '0'] 1845 return "%s%s/%s" % (start, '.'.join(tokens), classful_prefix(i)) 1846 1847 except ValueError: 1848 # Multi octet partial string address with optional prefix. 1849 part_addr = abbrev_cidr 1850 tokens = [] 1851 1852 if part_addr == '': 1853 # Not a recognisable format. 1854 return None 1855 1856 if '/' in part_addr: 1857 (part_addr, prefix) = part_addr.split('/', 1) 1858 1859 # Check prefix for validity. 1860 if prefix is not None: 1861 try: 1862 if not 0 <= int(prefix) <= 32: 1863 return None 1864 except ValueError: 1865 return None 1866 1867 if '.' in part_addr: 1868 tokens = part_addr.split('.') 1869 else: 1870 tokens = [part_addr] 1871 1872 if 1 <= len(tokens) <= 4: 1873 for i in range(4 - len(tokens)): 1874 tokens.append('0') 1875 else: 1876 # Not a recognisable format. 1877 return None 1878 1879 if prefix is None: 1880 try: 1881 prefix = classful_prefix(tokens[0]) 1882 except ValueError: 1883 return None 1884 1885 return "%s%s/%s" % (start, '.'.join(tokens), prefix) 1886 1887 except TypeError: 1888 pass 1889 except IndexError: 1890 pass 1891 1892 # Not a recognisable format. 1893 return None
1894 1895 @staticmethod
1896 - def span(addrs, fmt=None):
1897 """ 1898 Static method that accepts a sequence of IP addresses and/or CIDRs, 1899 Wildcards and IPRanges returning a single CIDR that is large enough 1900 to span the lowest and highest IP addresses in the sequence (with 1901 a possible overlap on either end). 1902 1903 @param addrs: a sequence of IP, CIDR, Wildcard or IPRange objects 1904 and/or their string representations. 1905 1906 @param fmt: (optional) callable used on return values. 1907 (Default: None - L{CIDR} object) Also accepts str() and unicode(). 1908 1909 @return: a single CIDR object spanning all addresses. 1910 """ 1911 if not isinstance(addrs, (list, tuple)): # Required - DO NOT CHANGE! 1912 raise TypeError('expected address sequence is not iterable!') 1913 1914 if not len(addrs) > 1: 1915 raise ValueError('sequence must contain 2 or more elements!') 1916 1917 if fmt not in (None, str, unicode): 1918 raise ValueError('unsupported formatter %r!' % fmt) 1919 1920 # List is required. 1921 if not isinstance(addrs, list): 1922 addrs = list(addrs) 1923 1924 # Detect type of string address or address range and create the 1925 # equivalent instance. 1926 for (i, addr) in enumerate(addrs): 1927 if isinstance(addr, (str, unicode)): 1928 try: 1929 obj = IP(addr) 1930 addrs[i] = obj 1931 continue 1932 except: 1933 pass 1934 try: 1935 obj = CIDR(addr) 1936 addrs[i] = obj 1937 continue 1938 except: 1939 pass 1940 try: 1941 obj = Wildcard(addr) 1942 addrs[i] = obj 1943 continue 1944 except: 1945 pass 1946 1947 # Find lowest and highest IP objects in address list. 1948 addrs.sort() 1949 lowest = addrs[0] 1950 highest = addrs[-1] 1951 1952 if isinstance(lowest, IPRange): 1953 # Create new IP as user may be returning address strings. 1954 lowest = IP(lowest.first, lowest.addr_type) 1955 1956 if isinstance(highest, IPRange): 1957 # Create new IP as user may be returning address strings. 1958 highest = IP(highest.last, highest.addr_type) 1959 1960 if lowest.addr_type != highest.addr_type: 1961 raise TypeError('address types are not the same!') 1962 1963 cidr = highest.cidr() 1964 1965 while cidr.prefixlen > 0: 1966 if highest in cidr and lowest not in cidr: 1967 cidr.prefixlen -= 1 1968 else: 1969 break 1970 1971 # Return address in string format. 1972 if fmt is not None: 1973 return fmt(cidr) 1974 1975 return cidr
1976 1977 @staticmethod
1978 - def summarize(cidrs, fmt=None):
1979 """ 1980 Static method that accepts a sequence of IP addresses and/or CIDRs 1981 returning a summarized sequence of merged CIDRs where possible. This 1982 method doesn't create any CIDR that are inclusive of any addresses 1983 other than those found in the original sequence provided. 1984 1985 @param cidrs: a list or tuple of IP and/or CIDR objects. 1986 1987 @param fmt: callable used on return values. 1988 (Default: None - L{CIDR} objects). str() and unicode() supported. 1989 1990 @return: a possibly smaller list of CIDRs covering sequence passed in. 1991 """ 1992 if not hasattr(cidrs, '__iter__'): 1993 raise ValueError('A sequence or iterable is expected!') 1994 1995 # Start off using set as we'll remove any duplicates at the start. 1996 ipv4_bit_cidrs = set() 1997 ipv6_bit_cidrs = set() 1998 1999 # Convert CIDRs into bit strings separating IPv4 from IPv6 2000 # (required). 2001 for cidr in cidrs: 2002 (bits, addr_type) = cidr_to_bits(cidr) 2003 if addr_type == AT_INET: 2004 ipv4_bit_cidrs.add(bits) 2005 elif addr_type == AT_INET6: 2006 ipv6_bit_cidrs.add(bits) 2007 else: 2008 raise ValueError('Unknown address type found!') 2009 2010 # Merge binary CIDRs into their smallest equivalents. 2011 def _reduce_bit_cidrs(cidrs): 2012 new_cidrs = [] 2013 2014 cidrs.sort() 2015 2016 # Multiple passes are required to obtain precise results. 2017 while 1: 2018 finished = True 2019 while len(cidrs) > 0: 2020 if len(new_cidrs) == 0: 2021 new_cidrs.append(cidrs.pop(0)) 2022 if len(cidrs) == 0: 2023 break 2024 # lhs and rhs are same size and adjacent. 2025 (new_cidr, subs) = _re.subn(r'^([01]+)0 \1[1]$', 2026 r'\1', '%s %s' % (new_cidrs[-1], cidrs[0])) 2027 if subs: 2028 # merge lhs with rhs. 2029 new_cidrs[-1] = new_cidr 2030 cidrs.pop(0) 2031 finished = False 2032 else: 2033 # lhs contains rhs. 2034 (new_cidr, subs) = _re.subn(r'^([01]+) \1[10]+$', 2035 r'\1', '%s %s' % (new_cidrs[-1], cidrs[0])) 2036 if subs: 2037 # keep lhs, discard rhs. 2038 new_cidrs[-1] = new_cidr 2039 cidrs.pop(0) 2040 finished = False 2041 else: 2042 # no matches - accept rhs. 2043 new_cidrs.append(cidrs.pop(0)) 2044 if finished: 2045 break 2046 else: 2047 # still seeing matches, reset. 2048 cidrs = new_cidrs 2049 new_cidrs = [] 2050 2051 return new_cidrs
2052 2053 new_cidrs = [] 2054 2055 # Reduce and format IPv4 CIDRs. 2056 for bit_cidr in _reduce_bit_cidrs(list(ipv4_bit_cidrs)): 2057 new_cidrs.append(bits_to_cidr(bit_cidr, fmt=fmt)) 2058 2059 # Reduce and format IPv6 CIDRs. 2060 for bit_cidr in _reduce_bit_cidrs(list(ipv6_bit_cidrs)): 2061 new_cidrs.append(bits_to_cidr(bit_cidr, fmt=fmt)) 2062 2063 return new_cidrs 2064
2065 - def __init__(self, cidr, fmt=IP, strict=True, expand_abbrev=True):
2066 """ 2067 Constructor. 2068 2069 @param cidr: a valid IPv4/IPv6 CIDR address or abbreviated IPv4 2070 network address. 2071 2072 @param fmt: (optional) callable used on return values. 2073 Default: L{IP} class. See L{nrange()} documentations for 2074 more details on the various options. 2075 2076 @param strict: (optional) If True and non-zero bits are found to the 2077 right of the subnet mask/prefix a ValueError is raised. If False, 2078 CIDR returned has these bits automatically truncated. 2079 (default: True) 2080 2081 @param expand_abbrev: (optional) If True, enables the abbreviated CIDR 2082 expansion routine. If False, abbreviated CIDRs will be considered 2083 invalid addresses, raising an AddrFormatError exception. 2084 (default: True) 2085 """ 2086 cidr_arg = cidr # Keep a copy of original argument. 2087 2088 if expand_abbrev: 2089 # Replace an abbreviation with a verbose CIDR. 2090 verbose_cidr = CIDR.abbrev_to_verbose(cidr) 2091 if verbose_cidr is not None: 2092 cidr = verbose_cidr 2093 2094 if not isinstance(cidr, (str, unicode)): 2095 raise TypeError('%r is not a valid CIDR!' % cidr) 2096 2097 # Check for prefix in address and extract it. 2098 try: 2099 (network, mask) = cidr.split('/', 1) 2100 except ValueError: 2101 network = cidr 2102 mask = None 2103 2104 #FIXME: Are IP objects for first and last really necessary? 2105 #FIXME: Should surely just be integer values. 2106 first = IP(network) 2107 self.strategy = first.strategy 2108 2109 if mask is None: 2110 # If no mask is specified, assume maximum CIDR prefix. 2111 self.__dict__['prefixlen'] = first.strategy.width 2112 else: 2113 self.prefixlen = mask 2114 2115 strategy = first.strategy 2116 addr_type = strategy.addr_type 2117 2118 hostmask = (1 << (strategy.width - self.prefixlen)) - 1 2119 2120 last = IP(first.value | hostmask, addr_type) 2121 2122 if strict: 2123 # Strict CIDRs enabled. 2124 netmask = strategy.max_int ^ hostmask 2125 host = (first.value | netmask) - netmask 2126 if host != 0: 2127 raise ValueError('%s contains non-zero bits right of the ' \ 2128 '%d-bit mask! Did you mean %s instead?' \ 2129 % (first, self.prefixlen, 2130 strategy.int_to_str(int(last) - hostmask))) 2131 else: 2132 # Strict CIDRs disabled. 2133 first.value = strategy.int_to_str(int(last) - hostmask) 2134 2135 super(CIDR, self).__init__(first, last, fmt)
2136
2137 - def __sub__(self, other):
2138 """ 2139 Subtract another CIDR from this one. 2140 2141 @param other: a CIDR object that is greater than or equal to C{self}. 2142 2143 @return: A list of CIDR objects than remain after subtracting C{other} 2144 from C{self}. 2145 """ 2146 cidrs = [] 2147 2148 if hasattr(other, 'value'): 2149 # Convert IP object to its CIDR object equivalent. 2150 other = other.cidr() 2151 2152 if other.last < self.first: 2153 # Other CIDR's upper bound is less than this CIDR's lower bound. 2154 if self.fmt is str: 2155 return [str(self.cidrs()[0])] 2156 else: 2157 return [self.cidrs()[0]] 2158 elif self.last < other.first: 2159 # Other CIDR's lower bound is greater than this CIDR's upper 2160 # bound. 2161 if self.fmt is str: 2162 return [str(self.cidrs()[0])] 2163 else: 2164 return [self.cidrs()[0]] 2165 2166 new_prefixlen = self.prefixlen + 1 2167 2168 if new_prefixlen <= self.strategy.width: 2169 i_lower = self.first 2170 i_upper = self.first + (2 ** (self.strategy.width - new_prefixlen)) 2171 2172 lower = CIDR('%s/%d' % (self.strategy.int_to_str(i_lower), 2173 new_prefixlen)) 2174 upper = CIDR('%s/%d' % (self.strategy.int_to_str(i_upper), 2175 new_prefixlen)) 2176 2177 while other.prefixlen >= new_prefixlen: 2178 if other in lower: 2179 matched = i_lower 2180 unmatched = i_upper 2181 elif other in upper: 2182 matched = i_upper 2183 unmatched = i_lower 2184 else: 2185 # Other CIDR not within self. 2186 cidrs.append(self.cidrs()[0]) 2187 break 2188 2189 cidr = CIDR('%s/%d' % (self.strategy.int_to_str(unmatched), 2190 new_prefixlen)) 2191 2192 cidrs.append(cidr) 2193 2194 new_prefixlen += 1 2195 2196 if new_prefixlen > self.strategy.width: 2197 break 2198 2199 i_lower = matched 2200 i_upper = matched + (2 ** (self.strategy.width - new_prefixlen)) 2201 2202 lower = CIDR('%s/%d' % (self.strategy.int_to_str(i_lower), 2203 new_prefixlen)) 2204 upper = CIDR('%s/%d' % (self.strategy.int_to_str(i_upper), 2205 new_prefixlen)) 2206 2207 cidrs.sort() 2208 2209 # Return string based CIDR address values at user's request. 2210 if self.fmt is str: 2211 return [str(cidr) for cidr in cidrs] 2212 2213 return cidrs
2214
2215 - def __add__(self, other):
2216 """ 2217 Add another CIDR to this one returning a CIDR supernet that will 2218 contain both in the smallest possible sized range. 2219 2220 @param other: a CIDR object. 2221 2222 @return: A new (potentially larger) CIDR object. 2223 """ 2224 cidr = CIDR.span([self, other]) 2225 if self.fmt is str: 2226 return str(cidr) 2227 return cidr
2228 2229 @property
2230 - def network(self):
2231 """@return: The network (first) address in this CIDR block.""" 2232 return self[0]
2233 2234 @property
2235 - def broadcast(self):
2236 """ 2237 B{Please Note:} although IPv6 doesn't actually recognise the concept of 2238 broadcast addresses per se (as in IPv4), so many other libraries do 2239 this that it isn't worth trying to resist the trend just for the sake 2240 of making a theoretical point. 2241 2242 @return: The broadcast (last) address in this CIDR block. 2243 """ 2244 return self[-1]
2245 2246 @property
2247 - def netmask(self):
2248 """@return: The subnet mask address of this CIDR block.""" 2249 hostmask = (1 << (self.strategy.width - self.prefixlen)) - 1 2250 netmask = self.strategy.max_int ^ hostmask 2251 return self.format(netmask)
2252 2253 @property
2254 - def hostmask(self):
2255 """@return: The host mask address of this CIDR block.""" 2256 hostmask = (1 << (self.strategy.width - self.prefixlen)) - 1 2257 return self.format(hostmask)
2258
2259 - def previous(self, step=1):
2260 """ 2261 @param step: the number of CIDRs between this CIDR and the expected 2262 one. Default: 1 - the preceding CIDR. 2263 2264 @return: The immediate (adjacent) predecessor of this CIDR. 2265 """ 2266 cidr_copy = CIDR('%s/%d' % (self.strategy.int_to_str(self.first), 2267 self.prefixlen)) 2268 cidr_copy -= step 2269 # Respect formatting. 2270 if self.fmt in (str, unicode): 2271 return self.fmt(cidr_copy) 2272 return cidr_copy
2273
2274 - def next(self, step=1):
2275 """ 2276 @param step: the number of CIDRs between this CIDR and the expected 2277 one. Default: 1 - the succeeding CIDR. 2278 2279 @return: The immediate (adjacent) successor of this CIDR. 2280 """ 2281 cidr_copy = CIDR('%s/%d' % (self.strategy.int_to_str(self.first), 2282 self.prefixlen)) 2283 cidr_copy += step 2284 # Respect formatting. 2285 if self.fmt in (str, unicode): 2286 return self.fmt(cidr_copy) 2287 return cidr_copy
2288
2289 - def iter_host_addrs(self):
2290 """ 2291 @return: An iterator object providing access to all valid host IP 2292 addresses within the specified CIDR block. 2293 - with IPv4 the network and broadcast addresses are always 2294 excluded. Any smaller than 4 hosts yields an emtpy list. 2295 - with IPv6 only the unspecified address '::' is excluded from 2296 the yielded list. 2297 """ 2298 if self.addr_type == AT_INET: 2299 # IPv4 2300 if self.size() >= 4: 2301 return nrange( IP(self.first+1, self.addr_type), 2302 IP(self.last-1, self.addr_type), fmt=self.fmt) 2303 else: 2304 return iter([]) 2305 elif self.addr_type == AT_INET6: 2306 # IPv6 2307 if self.first == 0: 2308 # Don't return '::'. 2309 return nrange(IP(self.first+1, self.addr_type), 2310 IP(self.last, self.addr_type), fmt=self.fmt) 2311 else: 2312 return iter(self)
2313
2314 - def supernet(self, prefixlen=0, fmt=None):
2315 """ 2316 Provides a list of supernet CIDRs for the current CIDR between the size 2317 of the current prefix and (if specified) the end CIDR prefix. 2318 2319 @param prefixlen: (optional) a CIDR prefix for the maximum supernet. 2320 Default: 0 - returns all possible supernets. 2321 2322 @param fmt: callable used on return values. 2323 Default: None - L{CIDR} objects. str() and unicode() supported. 2324 2325 @return: an tuple containing CIDR supernets that contain this one. 2326 """ 2327 if not 0 <= prefixlen <= self.strategy.width: 2328 raise ValueError('prefixlen %r invalid for IP version!' \ 2329 % prefixlen) 2330 2331 # Use a copy of self as we'll be editing it. 2332 cidr = self.cidrs()[0] 2333 cidr.fmt = fmt 2334 2335 supernets = [] 2336 while cidr.prefixlen > prefixlen: 2337 cidr.prefixlen -= 1 2338 supernets.append(cidr.cidrs()[0]) 2339 2340 return list(reversed(supernets))
2341
2342 - def subnet(self, prefixlen, count=None, fmt=None):
2343 """ 2344 A generator that returns CIDR subnets based on the current network 2345 base address and provided CIDR prefix and count. 2346 2347 @param prefixlen: a CIDR prefix. 2348 2349 @param count: number of consecutive CIDRs to be returned. 2350 2351 @param fmt: callable used on return values. 2352 Default: None - L{CIDR} objects. str() and unicode() supported. 2353 2354 @return: an iterator (as lists could potentially be very large) 2355 containing CIDR subnets below this CIDR's base address. 2356 """ 2357 if not 0 <= self.prefixlen <= self.strategy.width: 2358 raise ValueError('prefixlen %d out of bounds for address type!' \ 2359 % prefixlen) 2360 2361 if not self.prefixlen <= prefixlen: 2362 raise ValueError('prefixlen less than current CIDR prefixlen!') 2363 2364 # Calculate number of subnets to be returned. 2365 width = self.strategy.width 2366 max_count = 2 ** (width - self.prefixlen) / 2 ** (width - prefixlen) 2367 2368 if count is None: 2369 count = max_count 2370 2371 if not 1 <= count <= max_count: 2372 raise ValueError('count not within current CIDR boundaries!') 2373 2374 base_address = self.strategy.int_to_str(self.first) 2375 2376 # Respect self.fmt value if one wasn't passed to the method. 2377 if fmt is None and self.fmt in (str, unicode): 2378 fmt = self.fmt 2379 2380 if fmt is None: 2381 # Create new CIDR instances for each subnet returned. 2382 for i in xrange(count): 2383 cidr = CIDR('%s/%d' % (base_address, prefixlen)) 2384 cidr.first += cidr.size() * i 2385 cidr.prefixlen = prefixlen 2386 yield cidr 2387 elif fmt in (str, unicode): 2388 # Keep the same CIDR and just modify it. 2389 for i in xrange(count): 2390 cidr = CIDR('%s/%d' % (base_address, prefixlen)) 2391 cidr.first += cidr.size() * i 2392 cidr.prefixlen = prefixlen 2393 yield fmt(cidr) 2394 else: 2395 raise TypeError('unsupported fmt callable %r' % fmt)
2396
2397 - def cidrs(self):
2398 """ 2399 @return: A list of a copy of this L{CIDR} object. This method is here 2400 mainly for compatibility with IPRange interface. 2401 """ 2402 cidr_copy = CIDR('%s/%d' % (self.strategy.int_to_str(self.first), 2403 self.prefixlen)) 2404 2405 # Respect formatting. 2406 if self.fmt in (str, unicode): 2407 return [self.fmt(cidr_copy)] 2408 2409 return [cidr_copy]
2410
2411 - def __str__(self):
2412 return "%s/%s" % (self.strategy.int_to_str(self.first), self.prefixlen)
2413
2414 - def __repr__(self):
2415 """@return: executable Python string to recreate equivalent object.""" 2416 return "%s('%s/%d')" % (self.__class__.__name__, 2417 self.strategy.int_to_str(self.first), self.prefixlen)
2418
2419 #----------------------------------------------------------------------------- 2420 -class Wildcard(IPRange):
2421 """ 2422 Represents blocks of IPv4 addresses using a wildcard or glob style syntax. 2423 2424 Individual octets can be represented using the following shortcuts : 2425 2426 1. C{*} - the asterisk octet (represents values 0 through 255) 2427 2. C{'x-y'} - the hyphenated octet (represents values x through y) 2428 2429 A few basic rules also apply : 2430 2431 1. x must always be greater than y, therefore : 2432 2433 - x can only be 0 through 254 2434 - y can only be 1 through 255 2435 2436 2. only one hyphenated octet per wildcard is allowed 2437 3. only asterisks are permitted after a hyphenated octet 2438 2439 Example wildcards :: 2440 2441 '192.168.0.1' # a single address 2442 '192.168.0.0-31' # 32 addresses 2443 '192.168.0.*' # 256 addresses 2444 '192.168.0-1.*' # 512 addresses 2445 '192.168-169.*.*' # 131,072 addresses 2446 '*.*.*.*' # the whole IPv4 address space 2447 2448 Aside 2449 ===== 2450 I{Wildcard ranges are not directly equivalent to CIDR blocks as they 2451 can represent address ranges that do not fall on strict bit mask 2452 boundaries. They are very suitable in configuration files being more 2453 obvious and readable than their CIDR equivalents, especially for admins 2454 and users without much networking knowledge or experience.} 2455 2456 I{All CIDR blocks can always be represented as wildcard ranges but the 2457 reverse is not true. Wildcards are almost but not quite as flexible 2458 as IPRange objects.} 2459 """ 2460 STRATEGIES = (ST_IPV4,) 2461 ADDR_TYPES = (AT_UNSPEC, AT_INET) 2462 2463 # Descriptor registrations. 2464 strategy = StrategyDescriptor(STRATEGIES) 2465 addr_type = AddrTypeDescriptor(ADDR_TYPES) 2466 fmt = FormatDescriptor(IP) 2467 2468 @staticmethod
2469 - def is_valid(wildcard):
2470 """ 2471 A static method that validates wildcard address ranges. 2472 2473 @param wildcard: an IPv4 wildcard address. 2474 2475 @return: True if wildcard address is valid, False otherwise. 2476 """ 2477 #TODO: Add support for abbreviated wildcards 2478 #TODO: e.g. 192.168.*.* == 192.168.* 2479 #TODO: *.*.*.* == * 2480 #TODO: Add strict flag to enable verbose wildcard checking. 2481 seen_hyphen = False 2482 seen_asterisk = False 2483 try: 2484 octets = wildcard.split('.') 2485 if len(octets) != 4: 2486 return False 2487 for o in octets: 2488 if '-' in o: 2489 if seen_hyphen: 2490 return False 2491 seen_hyphen = True 2492 if seen_asterisk: 2493 # Asterisks cannot precede hyphenated octets. 2494 return False 2495 (o1, o2) = [int(i) for i in o.split('-')] 2496 if o1 >= o2: 2497 return False 2498 if not 0 <= o1 <= 254: 2499 return False 2500 if not 1 <= o2 <= 255: 2501 return False 2502 elif o == '*': 2503 seen_asterisk = True 2504 else: 2505 if seen_hyphen is True: 2506 return False 2507 if seen_asterisk is True: 2508 return False 2509 if not 0 <= int(o) <= 255: 2510 return False 2511 except AttributeError: 2512 return False 2513 except ValueError: 2514 return False 2515 return True
2516
2517 - def __init__(self, wildcard, fmt=IP):
2518 """ 2519 Constructor. 2520 2521 @param wildcard: a valid IPv4 wildcard address 2522 2523 @param fmt: (optional) callable used on return values. 2524 Default: L{IP} objects. See L{nrange()} documentations for 2525 more details on the various options.. 2526 """ 2527 if not Wildcard.is_valid(wildcard): 2528 raise AddrFormatError('%r is not a recognised wildcard address!' \ 2529 % wildcard) 2530 t1 = [] 2531 t2 = [] 2532 2533 for octet in wildcard.split('.'): 2534 if '-' in octet: 2535 oct_tokens = octet.split('-') 2536 t1 += [oct_tokens[0]] 2537 t2 += [oct_tokens[1]] 2538 elif octet == '*': 2539 t1 += ['0'] 2540 t2 += ['255'] 2541 else: 2542 t1 += [octet] 2543 t2 += [octet] 2544 2545 first = '.'.join(t1) 2546 last = '.'.join(t2) 2547 super(Wildcard, self).__init__(first, last, fmt=fmt) 2548 2549 if self.addr_type != AT_INET: 2550 raise AddrFormatError('Wildcard syntax only supports IPv4!')
2551
2552 - def __str__(self):
2553 t1 = self.strategy.int_to_words(self.first) 2554 t2 = self.strategy.int_to_words(self.last) 2555 2556 tokens = [] 2557 2558 seen_hyphen = False 2559 seen_asterisk = False 2560 2561 for i in range(4): 2562 if t1[i] == t2[i]: 2563 # A normal octet. 2564 tokens.append(str(t1[i])) 2565 elif (t1[i] == 0) and (t2[i] == 255): 2566 # An asterisk octet. 2567 tokens.append('*') 2568 seen_asterisk = True 2569 else: 2570 # Create a hyphenated octet - only one allowed per wildcard. 2571 if not seen_asterisk: 2572 if not seen_hyphen: 2573 tokens.append('%s-%s' % (t1[i], t2[i])) 2574 seen_hyphen = True 2575 else: 2576 raise AddrFormatError('only one hyphenated octet ' \ 2577 ' per wildcard allowed!') 2578 else: 2579 raise AddrFormatError('asterisks not permitted before ' \ 2580 'hyphenated octets!') 2581 2582 return '.'.join(tokens)
2583
2584 - def __repr__(self):
2585 """@return: executable Python string to recreate equivalent object.""" 2586 return "%s(%r)" % (self.__class__.__name__, str(self))
2587
2588 2589 #----------------------------------------------------------------------------- 2590 -class IPRangeSet(set):
2591 """ 2592 B{*EXPERIMENTAL*} A customised Python set class that deals with collections 2593 of IPRange class and subclass instances. 2594 """
2595 - def __init__(self, addrs):
2596 """ 2597 Constructor. 2598 2599 @param addrs: A sequence of IPRange class/subclass instances used to 2600 pre-populate the set. Individual CIDR objects can be added and 2601 removed after instantiation with the usual set methods, add() and 2602 remove(). 2603 """ 2604 for addr in addrs: 2605 if isinstance(addr, IP): 2606 self.add(addr.cidr()) 2607 if isinstance(addr, str): 2608 try: 2609 self.add(CIDR(addr)) 2610 except: 2611 pass 2612 try: 2613 ip = IP(addr) 2614 self.add(ip.cidr()) 2615 except: 2616 pass 2617 try: 2618 wildcard = Wildcard(addr) 2619 try: 2620 self.add(wildcard.cidr()) 2621 except: 2622 self.add(wildcard) 2623 except: 2624 pass 2625 else: 2626 self.add(addr)
2627
2628 - def __contains__(self, other):
2629 """ 2630 @return: True if C{other} IP or IPRange class/subclass instance 2631 matches any of the members in this IPRangeSet, False otherwise. 2632 """ 2633 for addr in self: 2634 if other in addr: 2635 return True
2636
2637 - def any_match(self, other):
2638 """ 2639 @param other: An IP or IPRange class/subclass instance. 2640 2641 @return: The first IP or IPRange class/subclass instance object that 2642 matches C{other} from any of the members in this IPRangeSet, None 2643 otherwise. 2644 """ 2645 for addr in self: 2646 if other in addr: 2647 return addr
2648
2649 - def all_matches(self, other):
2650 """ 2651 @param other: An IP or IPRange class/subclass instance. 2652 2653 @return: All IP or IPRange class/subclass instances matching C{other} 2654 from this IPRangeSet, an empty list otherwise. 2655 """ 2656 addrs = [] 2657 for addr in self: 2658 if other in addr: 2659 addrs.append(addr) 2660 return addrs
2661
2662 - def min_match(self, other):
2663 """ 2664 @param other: An IP or IPRange class/subclass instance. 2665 2666 @return: The smallest IP or IPRange class/subclass instance matching 2667 C{other} from this IPRangeSet, None otherwise. 2668 """ 2669 addrs = self.all_matches(other) 2670 addrs.sort() 2671 return addrs[0]
2672
2673 - def max_match(self, other):
2674 """ 2675 @param other: An IP or IPRange class/subclass instance. 2676 2677 @return: The largest IP or IPRange class/subclass instance matching 2678 C{other} from this IPRangeSet, None otherwise. 2679 """ 2680 addrs = self.all_matches(other) 2681 addrs.sort() 2682 return addrs[-1]
2683