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