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

# Source Code for Module netaddr.address

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