2011-07-12 141 views
1

给定IP范围,代码如何从该范围中减去IP地址或IP地址范围?如何区分Python 2.x范围内的IP地址范围?

实施例1:

original_range = '10.182.110.0/24' 
# Same as '10.182.110.0-10.182.110.255' 
subtract_range = '10.182.110.51-10.182.254' 
> diff_range = '10.182.110.0-10.182.110.50, 10.182.110.255' 

实施例2:

original_range = '10.10.20.0-10.10.20.20' 
subtract_range = '10.10.20.16' 
> diff_range = '10.10.20.10-10.10.20.15, 10.10.20.17-10.10.20.20' 

实施例3:

original_range = '10.170.0.0/16' 
# Same as '10.170.0.0-10.170.31.255' 
subtract_range = '10.170.20.16' 
> diff_range = '10.170.0.0-10.170.20.15, 10.170.20.17-10.170.31.255' 
+0

Google有一个名为ipaddr-py(http://code.google.com/p/ipaddr-py/)的python库。这可以用来解决问题吗? – paragbaxi

回答

1

下面是我用于执行此操作的功能(来回移动Qualys的使用和格式之间通过IPADDR提供的对象的实例:

def is_valid_ip_address(address, version=None): 
    """ Check validity of address 
     Return True if 'address' is a valid ipv4 or ipv6 address. 
    """ 
    # Validate version: 
    if version: 
     if not isinstance(version, int): 
      raise TypeError, 'Version is not of type "int"' 
      return False 
     if not (version == 4 or version == 6): 
      raise ValueError, 'IP version is set to an invalid number: %s' % version 
      return False 
    try: 
     ipaddr.IPAddress(address.strip(),version) 
    except ValueError: 
     return False 
    return True 

def is_valid_ipv4_address(address): 
    """ Check validity of address 
     Return True if 'address' is a valid ipv4 address. 
    """ 
    return is_valid_ip_address(address,4) 

def is_valid_ipv6_address(address): 
    """ Check validity of address 
     Return True if 'address' is a valid ipv6 address. 
    """ 
    return is_valid_ip_address(address,6) 

def is_valid_ip_range(iprange, version=None): 
    """ Check validity of iprange 
     Return True if 'iprange' is a range of ip addresses in a format that Qulys's API will accept (i.e. "startip-endip" where startip < endip). 
    """ 
    # Validate version: 
    if version: 
     if not isinstance(version, int): 
      raise TypeError, 'Version is not of type "int"' 
      return False 
     if not (version == 4 or version == 6): 
      raise ValueError, 'IP version is set to an invalid number: %s' % version 
      return False 

    try: 
     (start_ip,end_ip) = iprange.split('-') 
     start_ip = start_ip.strip() 
     end_ip = end_ip.strip() 
     if ipaddr.IPAddress(start_ip) == ipaddr.IPAddress(end_ip): 
      logging.debug('%s/%s-%s, Error: %s' % (package,module,version,'Start and End IP Address in an IP Range can not be the same IP Address.')) 
      return False 
     # A valid range requires: 
     # 1) The start_ip must be a valid ip address. 
     # 2) The end_ip must be a valid ip address. 
     # 3) The start_ip must be less than the end_ip. 
     # Although socket operations (as are used in qualysconnect.util) are nice, it's not feasible to determine that the start_ip is less than the 
     # end_ip without considerable effort. We'll use the ipaddr.summarize_address_range function to test all three at one time. 
     ipaddr.summarize_address_range(ipaddr.IPAddress(start_ip,version),ipaddr.IPAddress(end_ip,version)) 
    except ipaddr.AddressValueError, e: 
     logging.debug('%s/%s-%s, Error: %s' % (package,module,version,e)) 
     return False 
    except ValueError, e: 
     logging.debug('%s/%s-%s, Error: %s' % (package,module,version,e)) 
     return False 
    return True 

def is_valid_ipv4_range(iprange): 
    """ Check validity of iprange 
     Return True if 'iprange' is a range of ipv4 addresses in a format that Qulys's API will accept (i.e. "startip-endip" where startip < endip). 
    """ 
    return is_valid_ip_range(iprange,4) 

def is_valid_ipv6_range(iprange): 
    """ Check validity of iprange 
     Return True if 'iprange' is a range of ipv4 addresses in a format that Qulys's API will accept (i.e. "startip-endip" where startip < endip). 
    """ 
    return is_valid_ip_range(iprange,6) 

def cidr_to_ip(cidr,version=None): 
    """ Convert an ip address or ip range provided in cidr notation (either bitmask or netmask notation) to the ip address or ip range format that is 
     accepted by Qualys's API. (e.g. cidr_to_ip('10.0.0.0/24') returns the string '10.0.0.0-10.0.0.255'. 
     Returns a String containing an ip address or ip range that can be provided to the Qualys API. 
    """ 
    # Validate version: 
    if version: 
     if not isinstance(version, int): 
      raise TypeError, 'Version is not of type "int"' 
      return False 
     if not (version == 4 or version == 6): 
      raise ValueError, 'IP version is set to an invalid number: %s' % version 
      return False 
    try: 
     cidr_net = ipaddr.IPNetwork(cidr,version) 
    except ValueError, e: 
     logging.debug('%s/%s-%s, Error: %s' % (package,module,version,e)) 
     raise ValueError, e 
    if cidr_net[0] == cidr_net[-1]: 
     return str(cidr_net[0]) 
    iprange = '%s-%s' % (cidr_net[0],cidr_net[-1]) 
    return iprange 

def cidr_to_ipv4(cidr): 
    """ Convert an ipv4 address or ipv4 range provided in cidr notation (either bitmask or netmask notation) to the ip address or ip range format that is 
     accepted by Qualys's API. (e.g. cidr_to_ip('192.0.2.0/24') returns the string '192.0.2.0-192.0.2.255'. 
     Returns a String containing an ip address or ip range that can be provided to the Qualys API. 
    """ 
    return cidr_to_ip(cidr,4) 

def cidr_to_ipv6(cidr): 
    """ Convert an ipv6 address or ipv6 range provided in cidr notation (either bitmask or netmask notation) to the ip address or ip range format that is 
     accepted by Qualys's API. (e.g. cidr_to_ip('2001:db8::fff/120') returns the string '2001:db8::f00-2001:db8::fff'. 
     Returns a String containing an ipv6 address or ipv6 range that can be provided to the Qualys API. 
    """ 
    return cidr_to_ip(cidr,4) 

def decode_ip_string(ipstring): 
    """ Validates ipstring is in a format that can be provided to the Qualys API, if it is not in a format that can be accepted by the Qualys API, it attempts 
     to put it in a format that is acceptable (e.g. converting cidr notation to the ip range notation that Qualys expects) 
     Returns a string that is valid to hand to the 'ips' key in the Qualys API. 
    """ 
    cml=[] 
    ip_list = ipstring.split(',') 
    # Should probably check for any repeated or overlapping IP addresses here, but skipping for now. 
    for i in ip_list: 
     # This is a kludge, but I couldn't come up with a good way to make the error report the string that generated the error, rather than the 
     # potentially modified version of the string that caused the error. 
     new_i=i 
     if '/' in i: 
      new_i = cidr_to_ip(i) 
     if (is_valid_ip_address(new_i) or is_valid_ip_range(new_i)): 
      cml.append(new_i) 
     else: 
      raise ValueError, "IP argument cannot be parsed, \'%s\' is not a valid IP Range or IP Address" % i 
    return ",".join(cml) 

def ip_string_to_cidr(ipstring): 
    """ Accepts ipstring - a string list of IPs in the format the Qualys expects or has provided (via API calls) and returns a list of ipaddr.IPNetwork objects.""" 
    ret_list = [] 
    ip_list = ipstring.split(',') 
    for i in ip_list: 
     if is_valid_ip_address(i): 
      ret_list.append(ipaddr.IPNetwork(i.strip())) 
     elif is_valid_ip_range(i.strip()): 
      (start_ip,end_ip) = i.split('-') 
      range_list = ipaddr.summarize_address_range(ipaddr.IPAddress(start_ip.strip()), ipaddr.IPAddress(end_ip.strip())) 
      for j in range_list: 
       ret_list.append(j) 
    return ipaddr.collapse_address_list(ret_list) 

def ip_list_to_ip_string(iplist):  
    return decode_ip_string(",".join([decode_ip_string(str(i)) for i in iplist])) 

对于你将使用上面的函数和ipaddr.IPNetwork对象实例中的'exclude_address'方法来编写一个新函数,该函数接受original_range和subtract_range输入,返回ipaddr对象列表(或Qualys预期格式的ip_string)使用上面的ip_list_to_ip_string函数)。唯一棘手的部分将运行'ip_string_to_cidr(exclude_list)'时,您将收到需要从'original_range'中减去的IPNetwork对象列表。

如果您需要更多帮助,我可能会将某种exclude_ips函数放在一起,因为在某个时候我需要它,请让我知道。

1

谷歌的ipaddr-py library有一个方法叫做address_exclude()。下面是一些示例从PEP 3144改性:

In [1]: ipaddr.IPNetwork('1.1.0.0/15').address_exclude(ipaddr.IPNetwork('1.1.1.0/24')) 
    Out[1]: 
    [IPv4Network('1.0.0.0/16'), 
    IPv4Network('1.1.0.0/24'), 
    IPv4Network('1.1.2.0/23'), 
    IPv4Network('1.1.4.0/22'), 
    IPv4Network('1.1.8.0/21'), 
    IPv4Network('1.1.16.0/20'), 
    IPv4Network('1.1.32.0/19'), 
    IPv4Network('1.1.64.0/18'), 
    IPv4Network('1.1.128.0/17')] 

    In [1]: ipaddr.IPNewtork('::1/96').address_exclude(ipaddr.IPNetwork('::1/112')) 
    Out[1]: 
    [IPv6Network('::1:0/112'), 
    IPv6Network('::2:0/111'), 
    IPv6Network('::4:0/110'), 
    IPv6Network('::8:0/109'), 
    IPv6Network('::10:0/108'), 
    IPv6Network('::20:0/107'), 
    IPv6Network('::40:0/106'), 
    IPv6Network('::80:0/105'), 
    IPv6Network('::100:0/104'), 
    IPv6Network('::200:0/103'), 
    IPv6Network('::400:0/102'), 
    IPv6Network('::800:0/101'), 
    IPv6Network('::1000:0/100'), 
    IPv6Network('::2000:0/99'), 
    IPv6Network('::4000:0/98'), 
    IPv6Network('::8000:0/97')]