scripts/gestion/ipt.py
Pierre-Elliott Bécue 2a7dd72069 [Scripts] On rajoute un champ rid qui fait le lien avec les plages d'ip, et on rend le mid strictement croissant.
Ignore-this: 199e9ff5f09e1fe600c1066179f4e47b
Ce patch est un test, il ne restera en prod que si ça fonctionne. L'idée est qu'on souhaiterait conserver les vieilles machines comme les vieux adhérents, sauf demande explicite de suppression, par ailleurs, l'association mid <=> ip est très utile pour pas mal de choses. Pour la conserver, on crée un identifiant rid, qui supplante le mid, qui est lui choisi comme l'aid ou le fid, en incrémentant.

Ce patch vise à implémenter cela. S'il génère des bugs, il subira un rollback.

darcs-hash:20130123021650-b6762-347428d75f066f7f4821ca067d8c9bb6a4396bf5.gz
2013-01-23 03:16:50 +01:00

777 lines
28 KiB
Python
Executable file

#!/usr/bin/python
# -*- coding: utf-8 -*-
#
# IPT.PY -- Gestion du firewall
#
# Copyright (C) 2010 Olivier Huber
# Authors: Olivier Huber <huber@crans.org>
#
# 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 <http://www.gnu.org/licenses/>.
import os, re, syslog, cPickle, socket
from ldap_crans import crans_ldap, hostname
from commands import getstatusoutput
from config import NETs, role, prefix, rid, output_file, filter_policy
from config import blacklist_sanctions, blacklist_sanctions_soft, file_pickle, ann_scol, periode_transitoire
from iptools import AddrInNet
from ridtools import Rid
import subprocess
import netaddr
blacklist_sanctions.extend(blacklist_sanctions_soft)
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','personnel-ens':'personnel-ens' }
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.macwifi = Chain()
self.macwifiv6 = 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()
self.ingress_filtering = Chain()
self.tracker_torrent = 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)
getattr(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' : 'extfil', 'fil-v6' : 'extfilv6',
'wifi' : 'extwifi',
'wifi-v6' : 'extwifiv6' }
ip = ipv6_addr(mac, type_machine)
for proto in ['tcp', 'udp']:
for port in ports[proto]:
if port != ':':
getattr(self.filter,tab[type_machine])('-i %s -p %s -d %s --dport %s -j \
ACCEPT' % (dev, proto, ip, port))
else:
getattr(self.filter,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' : 'cransfil', 'fil-v6' :
'cransfilv6', 'wifi' : 'cranswifi',
'wifi-v6' : 'cranswifiv6' }
ip = ipv6_addr(mac, type_machine)
for proto in ['tcp', 'udp']:
for port in ports[proto]:
if port != ':':
getattr(self.filter,tab[type_machine])('-i %s -p %s -s %s --sport %s -j \
ACCEPT' % (dev, proto, ip, port))
else:
getattr(self.filter,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 rid.keys():
if ident in range(rid[type_m][0], rid[type_m][1]):
ip = ipv6_addr(machine.mac(), type_m)
mac=machine.mac()
break
if ip:
self.filter.blacklist_src('-m mac --mac-source %s -j REJECT --reject-with icmp6-port-unreachable' % mac)
#~ 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, rids, ip_proto = 4):
''' Met à jour les autorisations par machine sur l'ouverture des ports.
Prend en argument une liste de rid (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 r in rids:
for type_m in rid.keys():
if int(r) in range(rid[type_m][0], rid[type_m][1]):
net = type_m
if net == "":
raise RidError("Il n'y a pas de réseau associé au rid %i" % m)
if '-v6' in net and ip_proto == 4:
raise MismatchRidIpProto(r, ip_proto, net)
machine = db.search('rid=%i' % r)['machine']
if len(machine) != 1:
msg = "Il y a %i machines associée(s) au rid %i" % (
len(machine), r)
raise RidError(msg)
else:
if ip_proto == 4:
ip = Rid(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 = getattr(ipt_p.filter,sens + re.sub('-', '',net)).items
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)
getattr(ipt_p.filter,'ext' + re.sub('-', '', net))('-j \
REJECT --reject-with icmp6-port-unreachable')
getattr(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)
getattr(ipt_p.filter,'mac%s' % type_mm).items[:] = []
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, net, msg):
self.net = net
self.msg = msg
syslog.syslog(syslog.LOG_ERR,"Pas d'interface associé à %s"
% self.net)
syslog.syslog(syslog.LOG_ERR,"Résultat de la commande : \n %s"
% self.msg)
def __str__(self):
txt = "Pas d'interface associé à %s \n \
Résultat de la commande : \n %s" % (self.net, self.msg)
return txt
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 RidError(Exception):
''' Exception invoquée lorsqu'il y a un soucis avec un rid fourni '''
def __init__(self, msg):
self.msg = msg
syslog.syslog(syslog.LOG_ERR,"%s" % self.msg)
def __str__(self):
return "%s" % self.msg
class MismatchRidIpProto(Exception):
''' Exception invoquée lorsqu'il y a un défaut d'appariement entre le rid
et le protocole ip concerné'''
def __init__(self, mrid, ip_proto, net):
self.mrid = mrid
self.ip_proto = ip_proto
self.net = net
self.msg = "Défaut d'appariement entre le rid %i (%s) \
et le protocole ip %i" % (self.mrid, 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 gethostbyname(hostname):
hosts4=[]
hosts6=[]
try :
for host in socket.getaddrinfo(hostname,None,socket.AF_INET,socket.IPPROTO_IP,socket.AI_CANONNAME):
hosts4.append(host[4][0])
except(socket.gaierror): pass
try :
for host in socket.getaddrinfo(hostname,None,socket.AF_INET6,socket.IPPROTO_IP,socket.AI_CANONNAME):
hosts6.append(host[4][0])
except(socket.gaierror): pass
return (hosts4,hosts6)
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, msg)
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, msg)
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 hasattr(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'
output['filter'] += '-A FORWARD -j REJECT\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('paiement=%s' % ann_scol)
if periode_transitoire:
tmp=db.search('paiement=%s' % ann_scol-1)
s['adherent'].entend(tmp['adherent'])
s['club'].entend(tmp['club'])
del tmp
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=%s' % ann_scol)
if periode_transitoire:
s['machine'].entend(db.s('mblacklist=*&paiement=%s' % ann_scol-1)['machine'])
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 REJECT')
#ipt.filter.ieui64('-j REJECT')
def macips(ipt, machines, types_machines):
''' Construit la chaîne MAC '''
for machine in machines:
for type_m in types_machines:
if int(machine.rid()) in range(rid[type_m][0], rid[type_m][1]):
ipt.macip(machine.mac(), type_m)
break
for type_m in types_machines:
type_mm = re.sub('-', '', type_m)
getattr(ipt.filter,'mac' + type_mm)('-j REJECT')
#eval('ipt.filter.mac' + type_mm)('-j REJECT')
return 0
def ingress_filtering(ipt):
''' Réalise un filtre sur les plages d'IP susceptibles d'être routées '''
ip_proto = ipt.version()
if ip_proto == 6:
dev_ext = iface6('sixxs2')
# d'abord sur l'interface sur le réseau Cr@ns, on ne route que les
# paquet dans le bon subnet.
ipt.filter.ingress_filtering('-o %s -s %s -j RETURN' % (dev_ext,
prefix['subnet'][0]))
ipt.filter.ingress_filtering('-o %s -j LOG --log-prefix "BAD ROUTE "' %
dev_ext)
ipt.filter.ingress_filtering('-o %s -j REJECT' % dev_ext)
# de l'extérieur, on ne veut que des paquet ne provenant pas de notre
# réseau à destination de notre réseau
ipt.filter.ingress_filtering('-i %s ! -s %s -d %s -j RETURN' %
(dev_ext, prefix['subnet'][0], prefix['subnet'][0]))
ipt.filter.ingress_filtering('-i %s -j LOG --log-prefix "BAD SRC "' %
dev_ext)
ipt.filter.ingress_filtering('-i %s -j REJECT' % dev_ext)