#! /usr/bin/env python # -*- coding: utf-8 -*- """ Manipulation d'IPv4 Copyright (C) Frédéric Pauget Licence : GPLv2 """ import re, netaddr from config import NETs_regexp, prefix # Pour accélérer QuadToDec... __QuadToDecDone = {} def QuadToDec(ip) : """ Retourne la représentation décimale d'une ip ip est de la forme xxx.xxx.xxx.xxx """ if ip in __QuadToDecDone: return __QuadToDecDone[ip] test = ip.split('.') if len(test)!=4 : raise ValueError('IP Invalide') ip_dec = 0 for z in range(0,4) : n = int(test[z]) if n<0 or n>255 : raise ValueError('IP Invalide') ip_dec += n * ( 256**(3-z) ) __QuadToDecDone[ip] = ip_dec return ip_dec # Pour accélérer DecToQuad __DecToQuadDone = {} def DecToQuad(ip_dec) : """ Retourne la représentation habituelle d'une ip (xxx.xxx.xxx.xxx) ip_dec est l'IP en base 10 """ if ip_dec in __DecToQuadDone: return __DecToQuadDone[ip_dec] try : result = "%d.%d.%d.%d" % ( \ ip_dec/(256**3) , (ip_dec%(256**3)) / (256**2) , ( (ip_dec%(256**3)) % (256**2) ) / 256 , ( (ip_dec%(256**3)) % (256**2) ) % 256 ) __DecToQuadDone[ip_dec] = result return result except : raise ValueError('IP Invalide') __paramDone = {} def param(net, raw=False) : """ net est un résau fourni sous la forme xxx.xxx.xxx.xxx/yy si donnée valide retourne un dictionnaire : { 'network' : xxx.xxx.xxx.xxx , 'netmask' : yyy.yyy.yyy.yyy , 'broadcast' : zzz.zzz.zzz.zzz } sinon retourne {} Si raw = False, alors, on ne convertit pas les résultats sous forme pointée. Ils restent sous forme d'un entier. """ if raw and net in __paramDone: return __paramDone[net] reseau = {} ip, mask = net.split('/') try : mask = int(mask) dec_ip = QuadToDec(ip) if dec_ip == -1 : raise except : return {} # Calcul du netmask non_dec_netmask = netmask(mask, dec=False) dec_netmask = netmask(mask) reseau = { 'netmask' : dec_netmask, 'network' : dec_ip & dec_netmask, 'broadcast' : dec_ip | non_dec_netmask } if not raw: for i in reseau.keys(): reseau[i] = DecToQuad(reseau[i]) else: __paramDone[net] = reseau return reseau def AddrInNet(ip,net) : """ ip est de la forme xxx.xxx.xxx.xxx net est de la forme xxx.xxx.xxx.xxx/yy net peut être une liste de chaînes ci-dessus Retourne True si l'ip est dans un des réseaux. Note : retourne False si l'IP est une adresse de réseau ou broadcast """ if type(net)==str : net = [ net ] r = False ip = QuadToDec(ip) for ne in net : n = param(ne, raw=True) if ip == n['broadcast'] or ip == n['network'] : return False r = r or n['netmask'] & ip == n['network'] return r def AddrInNets(ip,nets) : """ Vérifie si l'ip est au moins dans un des réseaux de la liste nets (voir AddrInNet) """ for net in nets : if AddrInNet(ip,net) : return net return '' def NetInNet(net1, net2) : """ net1 est de la forme xxx.xxx.xxx.xxx/yy net2 est de la forme xxx.xxx.xxx.xxx/yy Retourne True si net1 est un sous-réseaux de net2 """ n1 = param(net1, raw=True) n2 = param(net2, raw=True) s1 = net1.split('/')[1] s2 = net1.split('/')[1] return s1<=s2 and (n1['network'] == n2['network'] or AddrInNet(DecToQuad(n1['network']), net2)) def NetInNets(net1, nets): """ Vérifie si le premier paramètre est un sous-réseau des réseaux de la liste du second paramètre""" for net in nets: if NetInNet(net1, net) : return net return '' def is_crans(ip): """ Vérifie que l'ip est dans le réseau CRANS """ # Pour titanic ip = netaddr.IPAddress(ip) if str(ip) in [ '138.231.136.14', '2a01:240:fe3d:4:a873:65ff:fe63:6f75']: return False if re.match(NETs_regexp['all'], str(ip)) or ip in netaddr.IPNetwork(prefix['subnet'][0]): return True return False def netmask(mask, dec=True) : """ On génère le sous réseau /bits """ non_dec_netmask = (1L<<(32-mask)) - 1 dec_netmask = (1L<<32) - 1 - non_dec_netmask if dec : return dec_netmask else : return non_dec_netmask def IpSubnet(ip, mask) : dec_mask = netmask(mask) dec_ip = QuadToDec(ip) start_ip = DecToQuad(dec_ip & dec_mask) subnet = start_ip + "/%s" % mask return subnet def NetSubnets(net, subnet_mask) : """ On construit une liste des sous réseaux /subnet_mask compris dans le sous réseau /mask comprenant l'ip ip """ subnets = [] # On récupère une ip du réseau indiqué ip = net.split('/')[0] # On récupère la valeur du masque mask = int(net.split('/')[1]) # On transforme les valeurs d'entrées en valeurs décimales # On définit la valeur du sous réseau initial dec_netmask = netmask(mask) dec_ip = QuadToDec(ip) dec_subnet_netmask = netmask(subnet_mask) # On calcule la première ip du sous réseau indiqué start_ip = dec_ip & dec_netmask seq_ip = start_ip # On fait une itération sur toutes les ip du sous réseau while (seq_ip & dec_netmask) == start_ip: # On récupère le sous réseau de la taille demandée subnet = DecToQuad(seq_ip & dec_subnet_netmask) + "/%s" % subnet_mask if not subnets.count(subnet) : subnets.append(subnet) seq_ip += 1 return subnets if __name__ == '__main__' : import sys print param(sys.argv[1])