diff --git a/gestion/ipt.py b/gestion/ipt.py new file mode 100755 index 00000000..d84c8da8 --- /dev/null +++ b/gestion/ipt.py @@ -0,0 +1,722 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# +# IPT.PY -- Gestion du firewall +# +# Copyright (C) 2010 Olivier Huber +# Authors: Olivier Huber +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + + +import os, re, syslog, cPickle + +from ldap_crans import crans_ldap, hostname +from commands import getstatusoutput +from config import NETs, role, prefix, mid, output_file, filter_policy +from config import blacklist_sanctions, file_pickle +from iptools import AddrInNet +from midtools import Mid +import subprocess +import netaddr + +Mangle_policy = """ +*mangle +:PREROUTING ACCEPT [0:0] +:INPUT ACCEPT [0:0] +:FORWARD ACCEPT [0:0] +:OUTPUT ACCEPT [0:0] +:POSTROUTING ACCEPT [0:0] +""" + +Raw_policy = """ +*raw +:PREROUTING ACCEPT [0:0] +:OUTPUT ACCEPT [0:0] +""" + +Filter_policy_template = """ +*filter +:INPUT %(policy_input)s [0:0] +:FORWARD %(policy_forward)s [0:0] +:OUTPUT %(policy_output)s [0:0] +""" + +dprefix = { 'fil' : 'fil', 'fil-v6' : 'fil', 'adm' : 'adm', 'wifi' : 'wifi', + 'wifi-v6' : 'wifi' } + +default_chains = [ 'PREROUTING', 'INPUT', 'FORWARD', 'OUTPUT', 'POSTROUTING' ] + +# On ouvre une connexion avec la base +db = crans_ldap() + +############################################################################## +# +# Déclaration des classes pour les règles du firewall +# +############################################################################## + + +class Chain(object): + ''' Classe regroupant toutes les règles du firewall ''' + def __init__(self): + self.items = [] + def __call__(self, cmd): + self.items.append(cmd) + +class Table(object): + ''' Classe contenant toutes les chaînes du firewall ''' + # TODO voir si on peut pas créer dynamiquement les méthodes + def __init__(self): + self.prerouting = Chain() + self.input = Chain() + self.forward = Chain() + self.output = Chain() + self.postrouting = Chain() + self.mac = Chain() + self.macfil = Chain() + self.macfilv6 = Chain() + self.macadm = Chain() + self.extfil = Chain() + self.extfilv6 = Chain() + self.extwifi = Chain() + self.extwifiv6 = Chain() + self.cransfil = Chain() + self.cransfilv6 = Chain() + self.cranswifi = Chain() + self.cranswifiv6 = Chain() + self.ieui64 = Chain() + self.feui64 = Chain() + self.blacklist_src = Chain() + self.blacklist_dst = Chain() + self.srv_out_adm = Chain() + +class Ip6tables(object): + ''' Classe pour ''' + def __init__(self): + self.filter = Table() + self.mangle = Table() + self.raw = Table() + + def macip(self, mac, type_m): + '''Fait la correspondance MAC-IP''' + type_mm = re.sub('-', '', type_m) + eval('self.filter.mac' + type_mm)(" ".join(['-m mac --mac-source', mac, + '-j RETURN'])) +# self.filter.mac(" ".join(['-m mac --mac-source', mac, +# '-j RETURN'])) + + def extcrans(self, type_machine, ports, mac, dev): + '''Ouverture des ports de l'extérieur vers la zone crans''' + tab = { 'fil' : 'self.filter.extfil', 'fil-v6' : 'self.filter.extfilv6', + 'wifi' : 'self.filter.extwifi', + 'wifi-v6' : 'self.filter.extwifiv6' } + ip = ipv6_addr(mac, type_machine) + for proto in ['tcp', 'udp']: + for port in ports[proto]: + if port != ':': + eval(tab[type_machine])('-i %s -p %s -d %s --dport %s -j \ +ACCEPT' % (dev, proto, ip, port)) + else: + eval(tab[type_machine])('-i %s -p %s -s %s -j ACCEPT' % + (dev, proto, ip)) + + def cransext(self, type_machine, ports, mac, dev): + '''Ouverture des ports de la zone crans vers l'extérieur''' + tab = { 'fil' : 'self.filter.cransfil', 'fil-v6' : + 'self.filter.cransfilv6', 'wifi' : 'self.filter.cranswifi', + 'wifi-v6' : 'self.filter.cranswifiv6' } + ip = ipv6_addr(mac, type_machine) + for proto in ['tcp', 'udp']: + for port in ports[proto]: + if port != ':': + eval(tab[type_machine])('-i %s -p %s -s %s --sport %s -j \ +ACCEPT' % (dev, proto, ip, port)) + else: + eval(tab[type_machine])('-i %s -p %s -s %s -j ACCEPT' % + (dev, proto, ip)) + + def blacklist(self, machine): + ''' Met des règles empêchant toute communication + vers et à partir de la machine considérée ''' + ident = int(machine.id()) + ip = "" + for type_m in mid.keys(): + if ident in range(mid[type_m][0], mid[type_m][1]): + ip = ipv6_addr(machine.mac(), type_m) + break + if ip: + self.filter.blacklist_src('-s %s -j REJECT --reject-with \ +icmp6-adm-prohibited' % ip) + self.filter.blacklist_dst('-d %s -j REJECT --reject-with \ +icmp6-adm-prohibited' % ip) + + + def version(self): + ''' methode retournant la version du protocole ip + pour l'instance de la classe ''' + return 6 + +class Update(object): + ''' Cette classe comprend toutes les méthodes nécessaires + à une mise-à-jour ou un régénération partielle du firewall''' + def ports(self, mids, ip_proto = 4): + ''' Met à jour les autorisations par machine sur l'ouverture des ports. + Prend en argument une liste de mid (entier(s)) de machines à changer''' + check_ip_proto(ip_proto) + ipt_p = open_pickle(ip_proto) + dev_crans = iface6('fil') + if ip_proto == 4: + dev_ext = iface('ens') + elif ip_proto == 6: + dev_ext = iface6('sixxs2') + net = "" + for m in mids: + for type_m in mid.keys(): + if int(m) in range(mid[type_m][0], mid[type_m][1]): + net = type_m + if net == "": + raise MidError("Il n'y a pas de réseau associé au mid %i" % m) + if '-v6' in net and ip_proto == 4: + raise MismatchMidIpProto(m, ip_proto, net) + machine = db.search('mid=%i' % m)['machine'] + if len(machine) != 1: + msg = "Il y a %i machines associée(s) au mid %i" % ( + len(machine), m) + raise MidError(msg) + else: + if ip_proto == 4: + ip = Mid(int(m)).to_ipv4() + elif ip_proto == 6: + ip = ipv6_addr(machine[0].mac(), net) + # On vérifie si la machine a déjà des entrées dans les chaînes + # On est un peu sous optimal ici + for sens in ['crans', 'ext']: + items = eval('ipt_p.filter.%s.items' % (sens + re.sub('-', '', + net))) + i = 0 + while i < len(items): + if ip in items[i] or 'REJECT' in items[i]: + del items[i] + else: + i = i + 1 + ports_io(ipt_p, machine[0], net, dev_ext, dev_crans) + eval('ipt_p.filter.ext' + re.sub('-', '', net))('-j \ +REJECT --reject-with icmp6-port-unreachable') + eval('ipt_p.filter.crans' + re.sub('-', '', net))('-j \ +REJECT --reject-with icmp6-port-unreachable') + # On écrit et applique les règles + write_rules(ipt_p) + apply_rules(ip_proto) + + os.remove(file_pickle[ip_proto]) + + # On sauve les chaînes + + save_pickle(ipt_p) + return 0 + + def blacklist(self, ip_proto = 4): + ''' Permet de regénérer les diverses blacklistes ''' + #TODO vérifier que la fonctionn est _vraiement_ ipv4 aware + check_ip_proto(ip_proto) + ipt_p = open_pickle(ip_proto) + blacklist(ipt_p) + # On écrit et applique les règles + write_rules(ipt_p) + apply_rules(ip_proto) + + os.remove(file_pickle[ip_proto]) + + # On sauve les chaînes + save_pickle(ipt_p) + return 0 + + def macs(self, macs, ip_proto = 4): + ''' Méthode temporaire le temps de trouver une solution plus élégante + l'interface devrait être la même que pour la fonction finale''' + check_ip_proto(ip_proto) + ipt_p = open_pickle(ip_proto) + for type_m in ['fil', 'fil-v6', 'adm']: + type_mm = re.sub('-', '', type_m) + eval('ipt_p.filter.mac%s.items' % type_mm)[:] = [] + machines = db.all_machines(graphic = True) + macips(ipt_p, machines, ['fil', 'fil-v6', 'adm']) + + write_rules(ipt_p) + apply_rules(ip_proto) + os.remove(file_pickle[ip_proto]) + save_pickle(ipt_p) + return 0 +# Il faut voir comment passer les mac en argument +# def macs(self, macs, ip_proto = 4): +# ''' Fonction pour mettre à jour les adresses mac acceptées sur le réseau. +# Prend comme argument un dictionnaire ayant pour clé 'remove' et 'add', +# contenant respectivement les adresses mac a ôter et celles à ajouter''' +# #TODO vérifier que la fonctionn est _vraiement_ ipv4 aware +# ipt_p = open_pickle(ip_proto) +# # On modifie la chaîne mac +# nb = len(ipt_p.filter.mac.items) +# for mac in macs['remove']: +# for i in range(1, nb): +# if mac in ipt_p.filter.mac.items[i]: +# ipt_p.filter.mac.items.remove[i] +# break +# print "Erreur, la mac " + mac + " n'est pas dans la chaîne." +# +# for mac in macs['add']: +# ipt_p.macip(mac) +# +# # On écrit et applique les règles +# write_rules(ipt_p) +# apply_rules(6) +# +# os.remove(file_pickle[ip_proto]) +# +# # On sauve les chaînes +# save_pickle(ipt_p) +# return 0 +# +############################################################################## +# +# Déclaration des exceptions +# +############################################################################## + +class NoIface(Exception): + ''' Exception invoquée lorsqu'il n'y a pas + d'interface associé à un réseau''' + def __init__(self, msg): + self.msg = msg + syslog.syslog(syslog.LOG_ERR,"Pas d'interface associé à %s" + % self.msg) + def __str__(self): + return "Pas d'interface associé à %s" % self.msg + +class Iproute2Error(Exception): + ''' Exception invoquée lorsqu'un appel à iproute2 renvoie une erreur''' + def __init__(self, cmd, code, msg): + self.cmd = cmd + self.code = code + self.msg = msg + syslog.syslog(syslog.LOG_ERR,"%s : %s %s" % (self.cmd, self.code, + self.msg)) + def __str__(self): + return "%s: %s %s" % ( self.cmd, self.code, self.msg) + +class NoRtTable(Exception): + ''' Exception invoquée lorsqu'une table de routage n'existe pas''' + def __init__(self, msg): + self.msg = msg + syslog.syslog(syslog.LOG_ERR,"La table donnée n'existe pas : %s" % + self.msg) + def __str__(self): + return "La table donnée n'existe pas : %s" % self.msg + +class ApplyRulesError(Exception): + ''' Exception invoquée lorsque l'application des règles par + ip(6|)tables-restore échoue ''' + def __init__(self, cmd, code, msg): + self.cmd = cmd + self.code = code + self.msg = msg + syslog.syslog(syslog.LOG_ERR,"%s : %s \n %s" % + (self.cmd, self.code, self.msg)) + def __str__(self): + return "%s : %s \n %s" % (self.cmd, self.code, self.msg) + +class SysctlError(Exception): + ''' Exception invoquée lorsque la modification d'un état dans /proc/sys + échoue ''' + def __init__(self, cmd, code, msg): + self.cmd = cmd + self.code = code + self.msg = msg + syslog.syslog(syslog.LOG_ERR,"%s : %s %s" % (self.cmd, self.code, + self.msg)) + def __str__(self): + return "%s: %s %s" % ( self.cmd, self.code, self.msg) + +class Ip6tablesError(Exception): + def __init__(self, cmd, code, msg): + self.cmd = cmd + self.code = code + self.msg = msg + syslog.syslog(syslog.LOG_ERR,"%s : %s %s" % (self.cmd, self.code, + self.msg)) + def __str__(self): + return "%s: %s %s" % ( self.cmd, self.code, self.msg) + +class MidError(Exception): + ''' Exception invoquée lorsqu'il y a un soucis avec un mid fourni ''' + def __init__(self, msg): + self.msg = msg + syslog.syslog(syslog.LOG_ERR,"%s" % self.msg) + def __str__(self): + return "%s" % self.msg + +class MismatchMidIpProto(Exception): + ''' Exception invoquée lorsqu'il y a un défaut d'appariement entre le mid + et le protocole ip concerné''' + def __init__(self, mmid, ip_proto, net): + self.mmid = mmid + self.ip_proto = ip_proto + self.net = net + self.msg = "Défaut d'appariement entre le mid %i (%s) \ +et le protocole ip %i" % (self.mmid, self.net, self.ip_proto) + syslog.syslog(syslog.LOG_ERR, self.msg) + def __str__(self): + return self.msg + +class IpProtoError(Exception): + ''' Exception quand le protocole ip fourni est inconnu ''' + def __init__(self, proto): + self.msg = "Le protocole ip %i est inconnu" % proto + syslog.syslog(syslog.LOG_ERR,"%s" % self.msg) + def __str__(self): + return "%s" % self.msg + +class UnknowUserError(Exception): + ''' Exception quand l'utilisateur demandé n'existe pas sur la machine ''' + def __init__(self, user): + self.msg = "L'utilisateur %s est inconnu" % user + syslog.syslog(syslog.LOG_ERR,"%s" % self.msg) + def __str__(self): + return "%s" % self.msg + + +############################################################################## +# +# Déclaration des fonctions +# +############################################################################## + +def check_ip_proto(ip_proto): + ''' Vérifie que le protocole ip fourni est valide ''' + if ip_proto != 4 and ip_proto != 6: + raise IpProtoError(ip_proto) + +def ipv6_addr(mac, net): + ''' Renvoie l'adresse ipv6 d'auto-configuration de la mac sur le réseau ''' + mac_s = mac.split(':') + eui = '2'+':'.join(mac_s[1:3])+'ff:fe'+':'.join(mac_s[3:5])+mac_s[5] + return re.sub(':/64', eui , prefix[dprefix[net]][0]) + +# TODO Fusionner les deux fonctions. +def iface(net): + '''Retourne l'interface réseau associée à un certain type de réseau + Pour l'instant on se base sur l'ipv4 pour identifier l'interface''' + if net == 'fil-v6': + net = 'fil' + if net == 'wifi-v6': + net = 'wifi' + cmd = "ip a show| egrep 'inet[^6]'" + code, msg = getstatusoutput(cmd) + if code: + raise Iproute2Error(cmd, code, msg) + output = msg.splitlines() + for line in output: + if AddrInNet(line.split()[1].split('/')[0], NETs[net]): + return line.split()[-1] + + raise NoIface(net) + +def iface6(net): + '''Retourne l'interface réseau associée à + un certain type de réseau ipv6''' + cmd = "ip -6 a show" + code, msg = getstatusoutput(cmd) + if code: + raise Iproute2Error(cmd, code, msg) + output = msg.splitlines() + subnet = netaddr.IPNetwork(prefix[net][0]) + i = 0 + while i < len(output): + if re.match('^[0-9]:', output[i]): + dev = re.sub('(@.*|:)', '', output[i].split()[1]) + i = i + 1 + while (i < len(output)) and ('inet6' in output[i]): + if netaddr.IPNetwork(output[i].split()[1]) == subnet: + return dev + else: + i = i + 2 + else: + i = i + 1 + + raise NoIface(net) + + +def check_table(table): + ''' Vérifie que la table existe bien ''' + ctables = open('/etc/iproute2/rt_tables', 'r') + rt_tables = ctables.readlines() + tables = [item for item in rt_tables if not re.match('#', item)] + if any(re.search(table, elt) for elt in tables): + return 0 + else: + raise NoRtTable(table) + +def custom_default_route(table, default, net, ip_proto = 4): + ''' Permet de créer une route par default personnalisée''' + check_ip_proto(ip_proto) + check_table(table) + dev = iface(net) + cmd = "ip -%i route add table %s default via %s dev %s" % (ip_proto, table, + default, dev) + code, msg = getstatusoutput(cmd) + if code: + raise Iproute2Error(cmd, code, msg) + +def custom_subnet_route(table, subnet, net, ip_proto = 4): + ''' Permet de créer une route personnalisée''' + check_ip_proto(ip_proto) + check_table(table) + dev = iface(net) + cmd = "ip -%i route add table %s from %s dev %s" % (ip_proto, table, subnet, + dev) + code, msg = getstatusoutput(cmd) + if code: + raise Iproute2Error(cmd, code, msg) + +def custom_subnet_via_route(table, subnet, net, via, ip_proto = 4): + ''' Permet de créer une route personnalisée''' + check_ip_proto(ip_proto) + check_table(table) + dev = iface(net) + cmd = "ip -%i route add table %s from %s via %s dev %s" % (ip_proto, table, + subnet, via, dev) + code, msg = getstatusoutput(cmd) + if code: + raise Iproute2Error(cmd, code, msg) + +def custom_ip_rule(table, subnet, ip_proto = 4): + ''' Ajout d'un règle de routage personnalisée basée + sur un sous-reseaux de provenance''' + check_ip_proto(ip_proto) + check_table(table) + cmd = "ip -%i rule add from %s table %s" % (ip_proto, subnet, table) + code, msg = getstatusoutput(cmd) + if code: + raise Iproute2Error(cmd, code, msg) + + +def custom_mark_rule(table, fw_mark, ip_proto = 4): + ''' Ajout d'une règle de routage personnalisée basée sur une marque''' + check_ip_proto(ip_proto) + check_table(table) + cmd = "ip -%i rule add fwmark %s table %s" % (ip_proto, fw_mark, table) + code, msg = getstatusoutput(cmd) + if code: + raise Iproute2Error(cmd, code, msg) + +def srv(attribute): + ''' Renvoie le (ou les) serveur(s) qui possède l'attribut ''' + return [ server for server, attr in role.iteritems() if (attribute in attr)] + +def ip_attribut(attribute, cl, ip_proto = 4): + ''' Renvoie l'ip du serveur qui possède l'attribut ''' + check_ip_proto(ip_proto) + host = srv(attribute)[0] + #Gestion erreur ? + # Autre net que fil ? + if ip_proto == 4: + return cl.search('host=%s.crans.org' % host)['machine'][0].ip() + elif ip_proto == 6: + mac = cl.search('host=%s.crans.org' % host)['machine'][0].mac() + if mac: + return ipv6_addr(mac, 'fil') + else: + print "Error" + " host=%s.crans.org" % name + +def apply_rules(ip_proto = 4): + ''' Applique les règles fournies dans le fichier passé en arguement ''' + check_ip_proto(ip_proto) + f = open(output_file[ip_proto], 'r') + if ip_proto == 4: + cmd = '/sbin/iptables-restore' + elif ip_proto == 6: + cmd = '/sbin/ip6tables-restore' + try: + p1 = subprocess.Popen(cmd, stdin=f, stdout=subprocess.PIPE) + except OSError: + syslog.syslog(syslog.LOG_ERR,"Le fichier %s n'existe pas" % f.name) + print "Le fichier %s n'existe pas" % f.name + stdout, stderr = p1.communicate() + if p1.returncode < 0: + raise ApplyRulesError(cmd, -p1.returncode, 'STDOUT\n' + stdout + + 'STDERR\n' + stderr ) + +def enable_forwarding(ip_proto = 4): + ''' Autorise le forwarding sur la machine considérée ''' + check_ip_proto(ip_proto) + cmd = 'echo 1 > /proc/sys/net/ipv%i/conf/all/forwarding' % ip_proto + code, msg = getstatusoutput(cmd) + if code: + raise SysctlError(cmd, code, msg) + +def disable_forwarding(ip_proto = 4): + ''' Désactive le forwarding sur la machine considérée ''' + check_ip_proto(ip_proto) + cmd = 'echo 0 > /proc/sys/net/ipv%i/conf/all/forwarding' % ip_proto + code, msg = getstatusoutput(cmd) + if code: + raise SysctlError(cmd, code, msg) + + +def not_private(arg): + ''' Retourne un boolén suivant que la fonction passé en argument + est privée ou non''' + if re.match('^_.*', str(arg)): + return False + else: + return True + +def open_pickle(ip_proto = 4): + ''' Cette fonction ouvre un fichier contenant un dump d'une classe + Ip(|6)tables''' + check_ip_proto(ip_proto) + try: + f = open(file_pickle[ip_proto], 'r') + except OSError: + syslog.syslog(syslog.LOG_ERR,"Le fichier %s n'existe pas" % + file_pickle[ip_proto]) + print "Le fichier %s n'existe pas" % file_pickle[ip_proto] + #XXX gestion des erreurs + return cPickle.load(f) + +def save_pickle(ipt): + ''' Cette fonction sauvegarde une instance de Ip(|6)tables''' + fout = open(file_pickle[ipt.version()], 'w') + cPickle.dump(ipt, fout) + fout.close() + +def write_rules(ipt): + ''' Cette fonction écrit les règles dans un fichier ''' + # TODO vérifier que la fonctionn est _vraiement_ ipv4 aware + ip_proto = ipt.version() + fout = open(output_file[ip_proto], 'w') + + # On recherche si la machine a des politiques particulières + if hostname in filter_policy.keys(): + key = hostname + else: + key = 'default' + + # On applique les politiques par défaut sur les chaînes canoniques + output = { 'filter' : Filter_policy_template % filter_policy[key], + 'mangle' : Mangle_policy, + 'raw' : Raw_policy + } + + # On parcours une première fois l'instance pour initialiser correctement + # nos chaînes + for itables in ['filter', 'mangle', 'raw']: + for ichain in filter(not_private, + dir(ipt.__getattribute__(itables))): + if ichain.upper() not in default_chains: + if ipt.__getattribute__(itables).__getattribute__(ichain).items: + output[itables] += ":%s - [0:0]\n" % ichain.upper() + + # On ajoute maintenant les règles + for itables in ['filter', 'mangle', 'raw']: + for ichain in filter(not_private, + dir(ipt.__getattribute__(itables))): + for rule in ipt.__getattribute__(itables).__getattribute__(ichain).items: + output[itables] += '-A ' + ichain.upper() + ' ' + rule + '\n' + + # Ecriture dans le fichier + fout.writelines(output['filter']) + fout.write('COMMIT\n') + fout.write('') + fout.writelines(output['mangle']) + fout.write('COMMIT\n') + fout.write('') + fout.writelines(output['raw']) + fout.write('COMMIT\n') + + fout.close() + + +def blacklist(ipt): + ''' Permet de peupler les chaînes concernant les diverses blacklistes ''' + + blcklst = [] + + s = db.search('ablacklist=*&paiement=ok') + + for target in s['adherent'] + s['club']: + sanctions = target.blacklist_actif() + if [x for x in sanctions if x in blacklist_sanctions]: + blcklst.extend(target.machines()) + + s = db.search('mblacklist=*&paiement=ok') + + for target in s['machine']: + sanctions = target.blacklist_actif() + if [x for x in sanctions if x in blacklist_sanctions]: + blcklst.append(target) + + if ipt.filter.blacklist_src.items: + ipt.filter.blacklist_src.items[:] = [] + if ipt.filter.blacklist_dst.items: + ipt.filter.blacklist_dst.items[:] = [] + + for machine in blcklst: + ipt.blacklist(machine) + + return 0 + +def ports_io(ipt, machine, type_machine, dev_ext, dev_crans): + ''' Fonction ouvrant les ports d'une machine selon le contenu de la base + LDAP''' + ports_in = { 'tcp' : machine.portTCPin(), + 'udp' : machine.portUDPin() } + ports_out = { 'tcp' : machine.portTCPout(), + 'udp' : machine.portUDPout() } + if ports_in.values() != [[], []]: + ipt.extcrans(type_machine, ports_in, machine.mac(), + dev_ext) + if ports_out.values() != [[], []]: + ipt.cransext(type_machine, ports_out, machine.mac(), + dev_crans) + +def mac_ip(ipt, machines, types_machines): + '''Réalise une correspondance MAC-IP pour un réseau considéré + On vérifie d'abord que la MAC est connue et ensuite on n'accepte que les + adresses en eui64''' + macips(ipt, machines, types_machines) + # TODO Il faut raffiner avant de rajouter le wifi + for type_m in types_machines: + if not '-v6' in type_m: + dev = iface6(type_m) + ipt.filter.input('-i %s -s %s -j %s' % (dev, prefix[type_m][0], + 'MAC' + type_m.upper())) + ipt.filter.input('-i %s -j IEUI64' % dev) + ipt.filter.ieui64('-i %s -s %s -m eui64 -j RETURN' % (dev, + prefix[type_m][0])) + + ipt.filter.ieui64('-s fe80::/64 -m eui64 -j RETURN') + ipt.filter.ieui64('-j DROP') + +def macips(ipt, machines, types_machines): + ''' Construit la chaîne MAC ''' + for machine in machines: + for type_m in types_machines: + if int(machine.id()) in range(mid[type_m][0], mid[type_m][1]): + ipt.macip(machine.mac(), type_m) + break + for type_m in types_machines: + type_mm = re.sub('-', '', type_m) + eval('ipt.filter.mac' + type_mm)('-j DROP') + return 0