2011-07-12 7 views
1

Étant donné une plage IP, comment le code peut-il soustraire une adresse IP ou une plage d'adresses IP de cette plage?Comment faire pour diff une plage d'adresses IP dans une plage dans Python 2.x?

Exemple 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' 

Exemple 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' 

Exemple 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 dispose d'une bibliothèque python appelée ipaddr-py (http://code.google.com/p/ipaddr-py/). Cela peut-il être utilisé pour résoudre le problème? – paragbaxi

Répondre

1

Voici les fonctions que j'utilise pour ce faire (qui va et vient entre le format Qualys utilise et instances des objets fournis par 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])) 

Pour vos exemples spécifiques, j'utiliserais les fonctions ci-dessus et la méthode 'exclude_address' dans les instances d'objets ipaddr.IPNetwork pour écrire une nouvelle fonction qui accepte les entrées original_range et subtract_range, renvoyant une liste d'objets ipaddr (ou une chaîne ip dans le format attendu de Qualys en utilisant la fonction ip_list_to_ip_string ci-dessus) .La seule partie délicate sera que lorsque vous exécutez 'ip_string_to_cidr (exclude_list)', vous recevrez une liste d'objets IPNetwork qui doivent être soustraits de 'original_range'.

Si vous avez besoin de plus d'aide, je peux probablement lancer une sorte de fonction exclude_ips, j'en aurai besoin à un moment donné, faites le moi savoir.

1

Google ipaddr-py library a une méthode appelée address_exclude(). Voici des exemples modifiés de 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')] 
Questions connexes