diff --git a/gestion/gen_confs/firewall.py b/gestion/gen_confs/firewall.py index a9768b8b..32bc0872 100755 --- a/gestion/gen_confs/firewall.py +++ b/gestion/gen_confs/firewall.py @@ -49,6 +49,16 @@ class IptablesError(Exception): def __str__(self): return "%s\n status : %s\n %s" % (self.cmd,self.err_code,self.output) +class TcError(Exception): + """ Gestion des erreurs de tc """ + def __init__(self,cmd,err_code,output): + self.cmd=cmd + self.err_code=err_code + self.output=output + syslog.syslog(syslog.LOG_ERR,"%s : status %s,%s" % (cmd,err_code,output)) + def __str__(self): + return "%s\n status : %s\n %s" % (self.cmd,self.err_code,self.output) + def iptables(cmd): """ Interface d'iptables """ syslog.syslog(syslog.LOG_INFO,cmd) @@ -57,6 +67,15 @@ def iptables(cmd): raise IptablesError(cmd,status,output) return output +def tc(cmd): + """ Interface de tc """ + syslog.syslog(syslog.LOG_INFO,cmd) + status,output=getstatusoutput("/sbin/tc "+cmd) + #print cmd + if status: + raise TcError(cmd,status,output) + return output + class firewall_crans : """ @@ -125,6 +144,10 @@ class firewall_crans : from lock import remove_lock remove_lock('firewall') + def mangle_table(self) : + """ Remplit la table mangle """ + return + def nat_table(self) : """ Remplit la table nat """ return @@ -166,6 +189,7 @@ class firewall_crans : return # Initialisation + #self.exception_catcher(self.mangle_table) self.exception_catcher(self.nat_table) self.exception_catcher(self.filter_table) self.exception_catcher(self.filter_table_tweaks) @@ -189,14 +213,16 @@ class firewall_crans : iptables("-t nat -P PREROUTING ACCEPT") iptables("-F") iptables("-t nat -F") + iptables("-t mangle -F") iptables("-X") iptables("-t nat -X") + iptables("-t mangle -X") print OK def test_mac_ip(self) : """ Reconstruit la correspondance MAC-IP des machines des adhérents """ - self.anim = anim('\tChaine TEST_MAC-IP',len(self.__machines())+1) + self.anim = anim('\tChaîne TEST_MAC-IP',len(self.__machines())+1) iptables("-t nat -P PREROUTING ACCEPT") iptables("-t nat -F TEST_MAC-IP") self.anim.cycle() @@ -261,7 +287,7 @@ class firewall_crans : def mac_ip_maj(self,ip_list) : """ Mise à jour de la correspondance MAC-IP pour les ip fournies """ ## Que faut-il faire ? - self.anim = anim('\tAnalyse travail à effectuer') + self.anim = anim('\tAnalyse du travail à effectuer') if ip_list == [''] : print OK + ' (rien à faire)' return @@ -436,6 +462,12 @@ class firewall_komaz(firewall_crans) : liste_reseaux_non_routables = [ '10.0.0.0/8', '172.16.0.0/12', '169.254.0.0/16', '192.168.0.0/16', '224.0.0.0/4'] + # Valeur des débits autorisés pour le p2p + machines = db.search('*')['machine'] + debit_p2p_max = 1000000 #"1mbit" + debit_p2p_adh = debit_p2p_max/(len(machines)+1) + + def reseaux_non_routables(self) : """ Construction de RESEAUX_NON_ROUTABLES_{DST,SRC} """ self.anim = anim('\tFiltrage ip non routables',len(self.liste_reseaux_non_routables)) @@ -446,6 +478,59 @@ class firewall_komaz(firewall_crans) : self.anim.reinit() print OK + def mangle_table(self) : + from affich_tools import anim, cprint, OK + self.anim = anim('\tStructure de la table mangle') + iptables("-t mangle -F POSTROUTING") + # On crée les chaines de sous-réseaux + for subnet in range(136,145)+range(148,152) : + try : + iptables("-t mangle -N SUBNET-%s_24" % subnet) + except IptablesError : + iptables("-t mangle -F SUBNET-%s_24" % subnet) + # On redirige les paquets dans la chaine appropriée + iptables("-t mangle -A POSTROUTING -o ens -s 138.231.%s.0/24 -j SUBNET-%s_24" % (subnet, subnet)) + iptables("-t mangle -A POSTROUTING -o crans -d 138.231.%s.0/24 -j SUBNET-%s_24" % (subnet, subnet)) + print OK + + adherents = db.search('paiement=ok')['adherent'] + + a = anim('\tGénération des classes de filtrage p2p', len(adherents)) + warn = '' + # Création des classes et qdisc + for interface in [self.eth_ext, self.eth_int] : + # On vide les classes et qdisc + try : + tc("qdisc del dev %s root" % interface) + except TcError, c: + warn += str(c) + '\n' + # On construit les classes et qdisc de base + # La partie principale qui définit le comportement par défaut + tc("qdisc add dev %s root handle 1: htb" % interface) + tc("class add dev %s parent 1: classid 1:1 htb rate %s ceil %s" % (interface, self.debit_p2p_max, self.debit_p2p_max)) + tc("class add dev %s parent 1:1 classid 1:9998 htb rate %s ceil %s" % (interface, self.debit_p2p_adh, self.debit_p2p_max)) + tc("qdisc add dev %s parent 1:9998 handle 9999: sfq perturb 10" % interface) + # On construit ensuite les classes et qdisc pour chaque adhérent + for adherent in adherents : + a.cycle() + class_id = int(adherent.id())+1 # On ne peut pas reprendre le numéro 1 + qdisc_id = class_id+5000 # Il nous faut un n° inférieur à 9998 unique + for interface in [self.eth_ext, self.eth_int] : + tc("class add dev %s parent 1:1 classid 1:%d htb rate %s ceil %s" % (interface, class_id, self.debit_p2p_adh, self.debit_p2p_max)) + tc("qdisc add dev %s parent 1:%d handle %d: sfq perturb 10" % (interface, class_id, qdisc_id)) + + # Classification des adhérents dans leur classe respective + for machine in adherent.machines() : + ip = machine.ip() + subnet = machine.ip().split('.')[2] + iptables("-t mangle -A SUBNET-%s_24 -o crans -d %s -m mark --mark 1 -j CLASSIFY --set-class 1:%s" % (subnet, ip, class_id)) + iptables("-t mangle -A SUBNET-%s_24 -o ens -s %s -m mark --mark 1 -j CLASSIFY --set-class 1:%s" % (subnet, ip, class_id)) + # Par défaut on envoit les paquets dans la classe 9998 + iptables("-t mangle -A POSTROUTING -o crans -m mark --mark 1 -j CLASSIFY --set-class 1:9998") + iptables("-t mangle -A POSTROUTING -o ens -m mark --mark 1 -j CLASSIFY --set-class 1:9998") + + print OK + def nat_table(self) : self.anim = anim('\tStructure de la table nat') for chaine in [ 'TEST_MAC-IP', 'RESEAUX_NON_ROUTABLES_SRC', 'RESEAUX_NON_ROUTABLES_DST', 'TEST_VIRUS_FLOOD', 'LOG_VIRUS', 'LOG_FLOOD' ] : @@ -477,7 +562,7 @@ class firewall_komaz(firewall_crans) : print OK def filter_table_tweaks(self) : - self.anim = anim('\trègles spécifiques à komaz') + self.anim = anim('\tRègles spécifiques à komaz') for chaine in [ 'ADMIN_VLAN', 'EXT_VERS_SERVEURS', 'SERVEURS_VERS_EXT' , 'EXT_VERS_CRANS', 'CRANS_VERS_EXT', 'BLACKLIST_SRC', 'BLACKLIST_DST' , 'FILTRE_P2P' ] : iptables('-N %s' % chaine) iptables("-A FORWARD -i lo -j ACCEPT") @@ -497,8 +582,67 @@ class firewall_komaz(firewall_crans) : iptables("-I FORWARD -m mark --mark 2 -j ACCEPT") print OK + def classe_p2p_maj(self,ip_list=['138.231.137.170']) : + """ Mise à jour de la classification pour les ip fournies + On ne crée que les règles iptables pour classer les paquets, les + classes correspondantes ne sont à créer que toutes à la fois """ + ## Que faut-il faire ? + self.anim = anim('\tAnalyse du travail à effectuer') + if ip_list == [''] : + print OK + ' (rien à faire)' + return + + maj = {} + for ip in ip_list : + machine = db.search('ip=%s'% ip)['machine'] + if not machine : + # Suppression de la règle associée à la machine + maj[machine[0]] = '-' + + elif len(machine) == 1 : + # Ajout de la machine + maj[machine[0]] = '+' + else : + print WARNING + if debug : + sys.stderr.write("Plusieurs machines avec l'IP %s\n" % ip) + + print OK + + ## Traitement + # MAJ des règles de classification de l'IP + def procedure() : + self.anim = anim('\tMise à jour des classes p2p') + warn = '' + try : + for machine in maj.keys() : + adherent = machine.proprietaire() + ip = machine.ip() + subnet = ip.split('.')[2] + class_id = int(adherent.id())+1 # On ne peut pas reprendre le numéro 1 + if maj[machine] == '+' : + # Il faut ajouter cette entrée + option = '-A' + else : + # Il faut supprimer cette entrée + option = '-D' + iptables("-t mangle %s SUBNET-%s_24 -o ens -s %s -m mark --mark 1 -j CLASSIFY --set-class 1:%s" % (option, subnet, ip, class_id)) + iptables("-t mangle %s SUBNET-%s_24 -o crans -d %s -m mark --mark 1 -j CLASSIFY --set-class 1:%s" % (option, subnet, ip, class_id)) + except IptablesError, c: + warn += str(c) + '\n' + except KeyError : + print OK + + if warn : + print WARNING + sys.stdout.write(warn) + else : + print OK + + self.exception_catcher(procedure) + def post_start_hook(self) : - self.anim = anim("\tMise en place routage") + self.anim = anim("\tMise en place du routage") warn = '' for cmd in [ 'echo 1 > /proc/sys/net/ipv4/ip_forward' , 'echo 65536 > /proc/sys/net/ipv4/ip_conntrack_max' , @@ -515,7 +659,7 @@ class firewall_komaz(firewall_crans) : print OK def pre_stop_hook(self) : - self.anim = anim("\tArret routage") + self.anim = anim("\tArrêt du routage") status,output=getstatusoutput('echo 0 > /proc/sys/net/ipv4/ip_forward') if status : print ERREUR @@ -523,6 +667,7 @@ class firewall_komaz(firewall_crans) : print OK def start_fw_funcs(self) : + self.exception_catcher(self.classe_p2p_maj) self.exception_catcher(self.log_chaines) self.exception_catcher(self.test_virus_flood) self.exception_catcher(self.reseaux_non_routables) @@ -803,7 +948,7 @@ class firewall_zamok(firewall_crans) : self.serv_out_adm() def filter_table_tweaks(self) : - self.anim = anim('\tRegles specifiques a zamok') + self.anim = anim('\tRègles spécifiques à zamok') iptables("-P INPUT ACCEPT") iptables("-P FORWARD DROP") print OK @@ -846,7 +991,7 @@ class firewall_rouge(firewall_crans) : print OK def filter_table_tweaks(self) : - self.anim = anim('\tRegles specifiques a rouge') + self.anim = anim('\tRègles spécifiques à rouge') iptables("-P INPUT ACCEPT") iptables("-P FORWARD DROP") print OK @@ -888,7 +1033,7 @@ class firewall_vert(firewall_crans) : print OK def filter_table_tweaks(self) : - self.anim = anim('\tRegles specifiques a vert') + self.anim = anim('\tRègles spécifiques à vert') iptables("-P INPUT ACCEPT") iptables("-P FORWARD DROP") print OK @@ -908,11 +1053,11 @@ class firewall_sila(firewall_rouge): firewall_bleu = firewall_zamok if __name__ == '__main__' : - # Chaines pouvant être recontruites + # Chaînes pouvant être recontruites fw = eval('firewall_%s()' % hostname) chaines = [] for nom in dir(fw) : - if nom in [ 'log_chaines' , 'test_virus_flood', 'reseaux_non_routables', 'test_mac_ip' , 'blacklist' , 'ext_vers_serveurs' , 'serveurs_vers_ext', 'ext_vers_crans', 'crans_vers_ext' , 'filtre_p2p', 'admin_vlan' , 'serv_out_adm'] : + if nom in [ 'log_chaines' , 'test_virus_flood', 'reseaux_non_routables', 'test_mac_ip' , 'blacklist' , 'ext_vers_serveurs' , 'serveurs_vers_ext', 'ext_vers_crans', 'crans_vers_ext' , 'filtre_p2p', 'admin_vlan' , 'serv_out_adm', 'mangle_table', 'classe_p2p_maj'] : chaines.append(nom) def __usage(txt=None) :