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

# Source Code for Module netaddr.address

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