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

# Source Code for Module netaddr.address

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