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