[firewall4] Séparation en plusieurs fichiers

En gros, un par pare feu
This commit is contained in:
Valentin Samir 2013-11-08 20:00:10 +01:00
parent 964abdd565
commit 2d2cbf2d9f
8 changed files with 1335 additions and 1268 deletions

View file

@ -0,0 +1,251 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import os
import sys
if '/usr/scripts/' not in sys.path:
sys.path.append('/usr/scripts/')
import syslog
import subprocess
from gestion.affich_tools import anim, OK, cprint
from gestion.iptools import AddrInNet, NetSubnets, IpSubnet, NetInNets
import lc_ldap.shortcuts
import lc_ldap.objets
import lc_ldap.attributs
squeeze = os.uname()[2] < '3'
#: Chaines par défaut d'iptables
default_chains = ['INPUT', 'OUTPUT', 'FORWARD', 'PREROUTING', 'POSTROUTING']
#: Tables d'iptables
tables = ['raw', 'mangle', 'filter', 'nat']
def pretty_print(table, chain):
"""Affiche quelle chaine est en train d'être construite dans quelle table de NetFilter"""
anim('\t%s dans %s' % (chain, table))
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 tc(cmd, block=True):
""" Interface de tc """
params = ['/sbin/tc']
params.extend(cmd.split())
p = subprocess.Popen(params , stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
if block:
status = p.wait()
stdoutdata, stderrdata = p.communicate()
if status:
raise TcError(' '.join(params), status, stdoutdata + stderrdata)
return stdoutdata + stderrdata
class firewall_tools(object) :
"""Classe de base du pare-feu implémentant l'association mac-ip (pour les machines filaires) et les blacklists hard"""
def machines(self):
"""Renvois la liste de toutes les machines"""
if self._machines:
return self._machines
self._machines, self._adherents = self.conn.allMachinesAdherents()
return self._machines
def adherents(self):
"""Renvois la liste de tous les adhérents"""
if self._adherents:
return self._adherents
self._machines, self._adherents = self.conn.allMachinesAdherents()
self._adherents = [ adh for adh in self._adherents if adh.paiement_ok ]
return self._adherents
def blacklisted_machines(self):
"""Renvois la liste de toutes les machines ayant une blackliste actives"""
if self._blacklisted_machines:
return self._blacklisted_machines
self._blacklisted_machines = [ machine for machine in self.machines() if machine.blacklist_actif() ]
return self._blacklisted_machines
def blacklisted_adherents(self, excepts=[]):
"""Renvois la liste de tous les adhérents ayant une blackliste active"""
if self._blacklisted_adherents and self._blacklisted_adherents_type == set(excepts):
return self._blacklisted_adherents
self._blacklisted_adherents = filter(lambda adh: adh.blacklist_actif(excepts), self.adherents())
self._blacklisted_adherents_type = set(excepts)
return self._blacklisted_adherents
def add(self, table, chain, rule):
"""Ajoute la règle ``rule`` à la chaine ``chain`` dans la table ``table``"""
if not chain in self.chain_list[table]:
self.chain_list[table].append(chain)
self.rules_list[table][chain]=[]
self.rules_list[table][chain].append(rule)
def delete(self, table=None, chain=None):
"""Supprime ``chain`` de ``table`` si fournis, sinon supprime ``table``, sinon toutes les tables"""
if not table:
for table in tables:
self.delete(table, chain)
if not chain:
for chain in self.chain_list[table]:
self.delete(table, chain)
if not chain in self.chain_list[table]:
return
if not chain in default_chains:
self.chain_list[table].remove(chain)
del(self.rules_list[table][chain])
else:
self.rules_list[table][chain]=[]
def flush(self, table=None, chain=None):
"""Vide ``chain`` dans ``table`` si fournis, sinon vide toutes
les chaines de ``table``, sinon vide toutes les chaines de toutes les tables"""
if not table:
for table in tables:
self.flush(table, chain)
if not chain:
for chain in self.chain_list[table]:
self.flush(table, chain)
if not chain in self.chain_list[table]:
self.chain_list[table].append(chain)
self.rules_list[table][chain]=[]
def restore(self, table=None, chains=[], noflush=False):
"""Restores les règles du pare-feu dans le noyau en appelant ``iptables-restore``.
Si ``table`` est fournis, on ne restore que table.
Si ``noflush`` n'est pas à ``True`` tout le contenu précédent est supprimé"""
str=self.format(chains)
f=open('/tmp/ipt_rules', 'w')
f.write(str)
f.close()
params = ['/sbin/iptables-restore']
if noflush:
params.append('--noflush')
if table and table in ['raw', 'mangle', 'filter', 'nat']:
params.append('--table')
params.append(table)
p = subprocess.Popen(params , stdin=subprocess.PIPE)
p.communicate(input=str)
def apply(self, table, chain):
"""Applique les règles de ``chain`` dans ``table``"""
if not chain in self.chain_list[table]:
return
self.restore(table, [chain], noflush=True)
self.delete(table, chain)
def format(self, chains=[]):
"""Transforme la structure interne des règles du pare-feu en celle comprise par ``iptables-restore``"""
str = ''
for table in self.chain_list.keys():
str += '*%s\n' % table
for chain in self.chain_list[table]:
if not chains or chain in chains or chain in default_chains:
str += ':%s %s [0:0]\n' % (chain, chain in default_chains and 'ACCEPT' or '-')
for chain in self.chain_list[table]:
if not chains or chain in chains :
for rule in self.rules_list[table][chain]:
str += '-A %s %s\n' % (chain, rule)
str += 'COMMIT\n'
return str
def reload(self, func_name):
if squeeze and self.reloadable[func_name] in self.use_ipset:
anim('\tVidage de %s' % self.reloadable[func_name]())
for table in ['raw', 'mangle', 'filter', 'nat']:
self.flush(table, self.reloadable[func_name]())
self.restore(noflush=True)
print OK
for table in ['raw', 'mangle', 'filter', 'nat']:
self.reloadable[func_name](table)
if self.reloadable[func_name] in self.use_ipset:
self.reloadable[func_name](fill_ipset=True)
if self.reloadable[func_name] in self.use_tc:
self.reloadable[func_name](run_tc=True)
anim('\tRestoration d\'iptables')
self.restore(noflush=True)
print OK
def __init__(self):
#initialisation des structures communes : récupération des ipset
if os.getuid() != 0:
from affich_tools import coul
sys.stderr.write(coul("Il faut être root pour utiliser le firewall\n", 'gras'))
sys.exit(1)
# Connection à la base ldap
self.conn = lc_ldap.shortcuts.lc_ldap_admin(user=u'firewall')
self.reloadable = {}
self.use_ipset = []
self.use_tc = []
self._machines = None
self._adherents = None
self._blacklisted_machines = None
self._blacklisted_adherents = None
self.chain_list={
'raw':['OUTPUT', 'PREROUTING'],
'mangle':['INPUT', 'OUTPUT', 'FORWARD', 'PREROUTING', 'POSTROUTING'],
'filter':['INPUT', 'OUTPUT', 'FORWARD'],
'nat':['OUTPUT', 'PREROUTING', 'POSTROUTING']
}
self.rules_list = {
'raw': { 'OUTPUT':[], 'PREROUTING':[] },
'mangle':{'INPUT':[], 'OUTPUT':[], 'FORWARD':[], 'PREROUTING':[], 'POSTROUTING':[]},
'filter':{'INPUT':[], 'OUTPUT':[], 'FORWARD':[]},
'nat':{'OUTPUT':[], 'PREROUTING':[], 'POSTROUTING':[]}
}
self.ipset={}
def start(self):
"""Démarre le pare-feu : génère les règles, puis les restore"""
anim('\tChargement des machines')
self.machines()
self.blacklisted_machines()
print OK
if squeeze:
anim('\tVidage du pare-feu')
self.restore()
print OK
self.raw_table()
self.mangle_table()
self.filter_table()
self.nat_table()
anim('\tRestoration d\'iptables')
self.restore()
print OK
return
def stop(self):
"""Vide les règles du pare-feu"""
self.delete()
self.restore()
return
def restart(self):
"""Alias de :py:func:`start`"""
self.start()
return