
pour grer le cas o il reste des machines l'adhrent. Il reste faire la suppression des classes inutilise (faite aprs le traitement de toutes les IP, pour viter du travail inutile dans le cas d'un simple changement d'IP). darcs-hash:20060617132759-68412-8ce058abb59956f609dae8e935e8d1177dfbbea9.gz
1189 lines
47 KiB
Python
Executable file
1189 lines
47 KiB
Python
Executable file
#!/usr/bin/env python
|
|
# -*- coding: iso-8859-1 -*-
|
|
# The authors of this code are
|
|
# Manuel Sabban <manu@feyd-rautha.org>
|
|
# Frédéric Pauget <pauget@crans.ens-cachan.fr>
|
|
# Mathieu Segaud <matt@minas-morgul.org>
|
|
# Nicolas Salles <salles@crans.org>
|
|
#
|
|
# Rewritten as inherited classes from firewall_crans
|
|
# by Mathieu Segaud <matt@minas-morgul.org>
|
|
#
|
|
# Copyright (c) 2004 Manuel Sabban, Frédéric Pauget
|
|
# Copyright (c) 2005 Mathieu Segaud
|
|
# Copyright (c) 2006 Nicolas Salles
|
|
#
|
|
# Permission to use, copy, and modify this software with or without fee
|
|
# is hereby granted, provided that this entire notice is included in
|
|
# all source code copies of any software which is or includes a copy or
|
|
# modification of this software.
|
|
#
|
|
# THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRSS OR
|
|
# IMPLIED WARRANTY. IN PARTICULAR, NONE OF THE AUTHORS MAKES ANY
|
|
# REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE
|
|
# MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR
|
|
# PURPOSE.
|
|
|
|
import sys
|
|
sys.path.append('/usr/scripts/gestion')
|
|
|
|
import syslog
|
|
import pwd
|
|
from lock import *
|
|
from ldap_crans import crans_ldap, ann_scol, hostname
|
|
from ldap_crans import AssociationCrans, Machine, MachineWifi
|
|
from affich_tools import *
|
|
from commands import getstatusoutput
|
|
from iptools import AddrInNet, NetSubnets, IpSubnet
|
|
from config import NETs, mac_komaz, mac_wifi, conf_fw, p2p
|
|
syslog.openlog('firewall')
|
|
|
|
debug = 1
|
|
db = crans_ldap()
|
|
|
|
class IptablesError(Exception):
|
|
""" Gestion des erreurs d'iptables """
|
|
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)
|
|
|
|
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)
|
|
status,output=getstatusoutput("/sbin/iptables "+cmd)
|
|
if status:
|
|
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)
|
|
if status:
|
|
raise TcError(cmd, status, output)
|
|
return output
|
|
|
|
def redirect_chain(table, chain_in, chain_out, ip) :
|
|
try:
|
|
iptables("-t %s -N %s" % (table, chain_out))
|
|
except IptablesError:
|
|
iptables("-t %s -F %s" % (table, chain_out))
|
|
# On redirige les paquets de la chaîne in dans la chaîne out
|
|
iptables("-t %s -A %s -o ens -s %s -j %s" % (table, chain_in, ip, chain_out))
|
|
iptables("-t %s -A %s -o crans -d %s -j %s" % (table, chain_in, ip, chain_out))
|
|
|
|
|
|
class firewall_crans :
|
|
"""
|
|
Classe parente pour les firewalls du crans
|
|
Implémentée directement à partir du firewall de komaz, initialement
|
|
écrit par Manuel Sabban et Frédéric Pauget.
|
|
|
|
* les méthodes à surcharger pour l'implémentation eme des firewall
|
|
sont mangle_table, nat_table, filter_table, pour la préparation
|
|
du fw, start_fw_funcs pour la mise en place du filtrage.
|
|
|
|
* serveurs_maj, adh_maj_list_to_do et serveurs_maj_list_to_do,
|
|
pour la mise en place de la MAC-IP.
|
|
en particulier, adh_maj_list_to_do et serveurs_maj_list_to_do
|
|
sont factorisées pour la simple et bonne raison que les sources
|
|
de la liste to_do originale ne seront pas forcément identiques
|
|
(c'est un peu sale...)
|
|
|
|
* la classe parente contient à peu de choses prés tout ce qu'il
|
|
faut pour mettre en place un fw basique n'effectuant que la
|
|
verif MAC-IP.
|
|
"""
|
|
zone_serveur = NETs['serveurs'][0]
|
|
vlan_adm = NETs['vlan-adm'][0]
|
|
|
|
adm_users = [ "root", "identd", "daemon", "postfix", "freerad", "amavis", "nut", "respbats", "list", "sqlgrey", "ntpd" ]
|
|
|
|
limit = " -m limit --limit 10/s --limit-burst 10 "
|
|
log_template = '-m limit --limit 1/s --limit-burst 1 -j LOG --log-level notice --log-prefix '
|
|
filtre_flood = '-m hashlimit --hashlimit 20 --hashlimit-mode srcip --hashlimit-name flood'
|
|
|
|
machines = []
|
|
debug = 1
|
|
|
|
def exception_catcher(self,tache) :
|
|
""" Exécute la tache founie en gérant les diverses exceptions
|
|
pouvant survenir
|
|
Retourne 1 en cas d'erreur et 0 sinon """
|
|
try :
|
|
tache()
|
|
return 0
|
|
except IptablesError, c :
|
|
self.anim.reinit()
|
|
print ERREUR
|
|
if self.debug : print c
|
|
except :
|
|
self.anim.reinit()
|
|
print ERREUR
|
|
import traceback
|
|
if self.debug : traceback.print_exc()
|
|
return 1
|
|
|
|
def __machines(self) :
|
|
""" Liste des machines du crans """
|
|
return db.all_machines(graphic=True)
|
|
|
|
def __init__(self) :
|
|
""" Pose un lock """
|
|
make_lock('firewall')
|
|
|
|
def __del__(self) :
|
|
""" Destruction du lock """
|
|
# Comprend pas pourquoi il faut réimporter ici -- Fred
|
|
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
|
|
|
|
def filter_table(self) :
|
|
""" Remplit la table filter """
|
|
self.anim = anim('\tStructure de la table filter')
|
|
print OK
|
|
|
|
def filter_table_tweaks(self) :
|
|
""" Complete la table filter """
|
|
return
|
|
|
|
def start_fw_funcs(self) :
|
|
""" Ordonnance la construction du firewall """
|
|
self.exception_catcher(self.test_mac_ip)
|
|
|
|
def post_start_hook(self) :
|
|
""" Hook de fin de demarrage """
|
|
return
|
|
|
|
def pre_stop_hook(self) :
|
|
""" Hook de debut d'arret """
|
|
return
|
|
|
|
def restart(self):
|
|
""" Rédémarrage du firewall """
|
|
cprint(u'Redémarrage firewall', 'gras')
|
|
self.start(False)
|
|
|
|
def start(self,aff_txt_intro=True) :
|
|
""" Construction du firewall
|
|
aff_txt_intro s'occupe uniquement de l'esthétisme
|
|
"""
|
|
if aff_txt_intro: cprint(u'Démarrage firewall', 'gras')
|
|
# Préliminaires
|
|
if not self.__machines() or self.exception_catcher(self.__stop) :
|
|
cprint(u"Abandon", 'rouge')
|
|
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)
|
|
|
|
# Remplissage
|
|
self.start_fw_funcs()
|
|
|
|
# On peux router
|
|
self.post_start_hook()
|
|
cprint(u"\t -> fin de la procédure de démarrage",'vert')
|
|
|
|
def stop(self):
|
|
""" Arrête le firewall """
|
|
cprint(u"Arrêt du firewall", 'gras')
|
|
self.pre_stop_hook()
|
|
self.exception_catcher(self.__stop)
|
|
cprint(u"\t -> fin de la procédure d'arrêt",'vert')
|
|
|
|
def __stop(self) :
|
|
self.anim = anim("\tSuppression des règles")
|
|
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('\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()
|
|
|
|
def procedure() :
|
|
for machine in self.__machines() :
|
|
self.__test_mac_ip(machine)
|
|
self.anim.cycle()
|
|
iptables("-t nat -A TEST_MAC-IP -j DROP")
|
|
iptables("-t nat -P PREROUTING ACCEPT")
|
|
self.anim.reinit()
|
|
print OK
|
|
|
|
self.exception_catcher(procedure)
|
|
|
|
|
|
def __test_mac_ip(self,machine):
|
|
ip=machine.ip()
|
|
mac=machine.mac()
|
|
|
|
insert = '-I'
|
|
if isinstance(machine, MachineWifi):
|
|
# Machine wifi, c'est la mac de Nectaris
|
|
iptables("-t nat %s TEST_MAC-IP -s "%(insert)+\
|
|
"%s -m mac --mac-source %s -j RETURN"%(ip, mac_wifi))
|
|
else:
|
|
# Machine fixe
|
|
iptables("-t nat %s TEST_MAC-IP -s "%(insert)+\
|
|
"%s -m mac --mac-source %s -j RETURN"%(ip,mac))
|
|
|
|
def serveurs_maj(self):
|
|
pass
|
|
|
|
def serveurs_maj_list_to_do(self) :
|
|
pass
|
|
|
|
def adh_maj_list_to_do(self) :
|
|
pass
|
|
|
|
def port_maj(self,ip_list) :
|
|
""" Mise à jour des ports pour les ip fournies """
|
|
# Note : système bourrin (on efface les chaînes et on refait)
|
|
# mais rapide et efficace (si qqn veut se casser le cul à
|
|
# un système aussi délicat que pour la correspondance MAC-IP...)
|
|
# -- Fred
|
|
serveur_maj = False
|
|
adh_maj = False
|
|
for ip in ip_list :
|
|
if AddrInNet(ip,self.zone_serveur) :
|
|
serveur_maj = True
|
|
else :
|
|
adh_maj = True
|
|
if serveur_maj and adh_maj :
|
|
break
|
|
to_do=[]
|
|
if serveur_maj :
|
|
self.exception_catcher(self.serveurs_maj_list_to_do)
|
|
|
|
if adh_maj :
|
|
self.exception_catcher(self.adh_maj_list_to_do)
|
|
|
|
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 du travail à effectuer')
|
|
if ip_list == [''] :
|
|
print OK + ' (rien à faire)'
|
|
return
|
|
|
|
mac_ip_maj = {}
|
|
serveur_maj = False
|
|
for ip in ip_list :
|
|
machine = db.search('ip=%s'% ip)['machine']
|
|
if not machine :
|
|
# Destruction des occurences
|
|
if AddrInNet(ip,self.zone_serveur) :
|
|
serveur_maj = True
|
|
else :
|
|
mac_ip_maj[ip] = None
|
|
|
|
elif len(machine) == 1 :
|
|
# Mise à jour de la machine
|
|
if AddrInNet(ip,self.zone_serveur) :
|
|
serveur_maj = True
|
|
# Il faut avoir payé ou être une machine du crans
|
|
if db.search('paiement=ok&ip=%s'% ip)['machine'] or \
|
|
machine[0].proprietaire().__class__ == AssociationCrans:
|
|
mac_ip_maj[ip] = machine[0]
|
|
else :
|
|
mac_ip_maj[ip] = None
|
|
else :
|
|
print WARNING
|
|
if debug :
|
|
sys.stderr.write("Plusieurs machines avec l'IP %s\n" % ip)
|
|
|
|
print OK
|
|
|
|
## Traitement
|
|
# Serveurs
|
|
if serveur_maj :
|
|
self.serveurs_maj()
|
|
|
|
# Correspondance MAC-IP
|
|
if mac_ip_maj or serveur_maj :
|
|
def procedure() :
|
|
warn = ''
|
|
self.anim = anim('\tActualisation TEST_MAC-IP')
|
|
for regle in iptables("-t nat -L TEST_MAC-IP -n").split('\n')[2:] :
|
|
regle = regle.split()
|
|
if regle[0] == 'DROP':
|
|
# On est arrivé à la fin de la liste
|
|
break
|
|
ip = regle[3]
|
|
mac = regle[6].lower()
|
|
if ip in mac_ip_maj.keys() :
|
|
# La règle correspond à une ip à mettre à jour
|
|
machine = mac_ip_maj[ip]
|
|
try:
|
|
if not machine :
|
|
# Il faut détruire cette entrée
|
|
iptables("-t nat -D TEST_MAC-IP -s %s -m mac --mac-source %s -j RETURN" % (ip, mac))
|
|
else :
|
|
if (isinstance(machine, MachineWifi) and mac != mac_wifi) \
|
|
or (not isinstance(machine, MachineWifi) and mac != machine.mac()):
|
|
# La correspondance MAC-IP est fausse => on ajoute la bonne règle
|
|
self.__test_mac_ip(machine)
|
|
# Supression de l'ancienne ligne
|
|
iptables("-t nat -D TEST_MAC-IP -s %s -m mac --mac-source %s -j RETURN" % (ip, mac))
|
|
|
|
# Toutes les autres occurences devront être détruites
|
|
mac_ip_maj[ip]=None
|
|
|
|
except IptablesError, c:
|
|
warn += str(c) + '\n'
|
|
|
|
# Ajout des machines qui n'étaient pas dans le firewall
|
|
for machine in mac_ip_maj.values() :
|
|
if machine :
|
|
self.__test_mac_ip(machine)
|
|
if warn :
|
|
print WARNING
|
|
sys.stdout.write(warn)
|
|
else :
|
|
print OK
|
|
|
|
self.exception_catcher(procedure)
|
|
|
|
def build_chaine_adherent(self,chaine,methode) :
|
|
# On construit d'abord les autorisations particulières
|
|
if not self.build_chaine(chaine, methode) :
|
|
# Puis si pas de problèmes les autorisations par défaut
|
|
self.anim.reinit()
|
|
for proto in [ 'tcp' , 'udp' ] :
|
|
for port in self.ports_default["%s_%s" % ( proto, chaine) ] :
|
|
self.anim.cycle()
|
|
iptables("-I %s -p %s --dport %s -j ACCEPT" % (chaine, proto,port) )
|
|
self.anim.reinit()
|
|
print OK
|
|
|
|
def build_chaine(self,chaine, methode) :
|
|
self.anim = anim('\tChaîne %s' % chaine,len(self.__machines())+1)
|
|
iptables("-F %s" % chaine)
|
|
self.anim.cycle()
|
|
def procedure() :
|
|
for machine in self.__machines() :
|
|
methode(machine)
|
|
self.anim.cycle()
|
|
iptables("-A %s -j REJECT" % chaine)
|
|
return self.exception_catcher(procedure)
|
|
|
|
|
|
"""
|
|
Komaz
|
|
"""
|
|
|
|
class firewall_komaz(firewall_crans) :
|
|
"""
|
|
Structure du firewall :
|
|
table mangle :
|
|
PREROUTING (policy par défaut : ACCEPT)
|
|
1) proxy transparent
|
|
2) marquage des paquets bittorrent
|
|
|
|
POSTROUTING (policy par défaut : ACCEPT)
|
|
1) passage dans un sous-réseau de l'ip crans : SUBNET
|
|
|
|
SUBNET classe pour chaque ip de son réseau dans la classe htb correspondante
|
|
table nat :
|
|
PREROUTING (policy par défaut : ACCEPT)
|
|
1) passage par TEST_VIRUS_FLOOD pour tout ce qui n'est pas dans zone_serveur
|
|
2) passage dans RESEAUX_NON_ROUTABLES_DST
|
|
3) passage est paquets venant de l'extérieur dans RESEAUX_NON_ROUTABLES_SRC
|
|
4) on laisse passer vers filter les paquets suivants :
|
|
source ou destination les serveurs de serveurs_crans
|
|
ce qui vient de l'extérieur
|
|
5) passage par TEST_MAC-IP
|
|
|
|
TEST_VIRUS_FLOOD droppe les paquets contenant des virus ou les paquets de flood
|
|
RESEAUX_NON_ROUTABLES_DST droppe les paquets dont la destination est non routable
|
|
RESEAUX_NON_ROUTABLES_SRC droppe les paquets dont la source est non routable
|
|
TEST_MAC-IP envoi les bon paquets vers CRANS_VERS_EXT
|
|
|
|
table filter :
|
|
FORWARD (policy par défaut : ACCEPT)
|
|
1) passage par BLACKLIST
|
|
2) passage pas FILTRE_P2P (ACCEPT sur le trafic p2p, sanction gérées par déconnexion.py)
|
|
3) ce qui a pour source les serveurs de serveurs_crans est dirigé vers SERVEURS_VERS_EXT
|
|
4) ce qui a pour destination les serveurs de serveurs_crans est dirigé EXT_VERS_SERVEURS
|
|
5) tout ce qui vient de l'interface externe est dirigé vers EXT_VERS_CRANS
|
|
6) ce qui a pour source les serveurs de serveurs_crans est dirigé vers EXT_VERS_CRANS
|
|
|
|
BLACKLIST fitre des ip blacklistées (REJECT)
|
|
FILTRE_P2P filtre le traffic de p2p
|
|
EXT_VERS_CRANS et CRANS_VERS_EXT
|
|
ACCEPT pour les paquets vers les machines du crans (test port-ip)
|
|
REJECT pour le reste
|
|
EXT_VERS_SERVEURS et SERVEURS_VERS_EXT
|
|
ACCEPT pour bon mac-ip-port
|
|
REJECT pour le reste
|
|
"""
|
|
|
|
# interfaces physiques
|
|
eth_ext = "ens"
|
|
eth_int = "crans"
|
|
|
|
# Ports ouverts
|
|
ports_default = { 'tcp_EXT_VERS_CRANS' : [ '22' ],
|
|
'tcp_CRANS_VERS_EXT': [ ':79', '81:134', '136', '140:444', '446:'],
|
|
'udp_EXT_VERS_CRANS' : [ ],
|
|
'udp_CRANS_VERS_EXT': [ ':136','140:'] }
|
|
|
|
|
|
ports_virus = { 'tcp' : [ 135, 445 ] , 'udp' : [] }
|
|
|
|
# Filtrage du peer to peer
|
|
filtres_p2p = [ ('bit', 'Bittorrent'),
|
|
('apple', 'AppleJuice'),
|
|
('soul', 'SoulSeek'),
|
|
('winmx', 'WinMX'),
|
|
('edk', 'eDonkey'),
|
|
('dc', 'DirectConnect'),
|
|
('kazaa', 'KaZaa'),
|
|
('ares', 'Ares'),
|
|
('gnu', 'GNUtella') ]
|
|
ports_p2p = [ '412', '1214', '4662:4665' , '6346:6347', '6699', '6881:6889' ]
|
|
|
|
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']
|
|
|
|
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))
|
|
for reseau in self.liste_reseaux_non_routables :
|
|
iptables("-t nat -A RESEAUX_NON_ROUTABLES_DST -d %s -j DROP" % reseau)
|
|
iptables("-t nat -A RESEAUX_NON_ROUTABLES_SRC -s %s -j DROP" % reseau)
|
|
self.anim.cycle()
|
|
self.anim.reinit()
|
|
print OK
|
|
|
|
def mangle_table(self):
|
|
self.anim = anim('\tStructure de la table mangle')
|
|
|
|
# On vide complètement la table
|
|
iptables("-t mangle -F")
|
|
iptables("-t mangle -X")
|
|
|
|
# Proxy transparent
|
|
iptables("-t mangle -A PREROUTING -s %s -j RETURN" % self.zone_serveur)
|
|
iptables("-t mangle -A PREROUTING -p tcp --destination-port 80 "
|
|
"-s %s -d ! %s -j MARK --set-mark %s" %
|
|
(NETs['fil'][0], NETs['wifi'][0], conf_fw.mark['proxy']))
|
|
iptables("-t mangle -A PREROUTING -m mark --mark %s -j ACCEPT" %
|
|
conf_fw.mark['proxy'])
|
|
|
|
# Parametres pour iptables/tc
|
|
mark = conf_fw.mark['bittorrent']
|
|
debit_adh = p2p.debit_adh
|
|
debit_max = p2p.debit_max
|
|
eth_ext = self.eth_ext
|
|
eth_int = self.eth_int
|
|
|
|
# On ne va pas plus loin si il ne s'agit pas de bittorrent
|
|
iptables("-t mangle -A POSTROUTING -m mark ! --mark %s -j ACCEPT" % mark)
|
|
|
|
# On marque les paquets bittorrent uniquement
|
|
iptables("-t mangle -A PREROUTING -p tcp -j CONNMARK --restore-mark")
|
|
iptables("-t mangle -A PREROUTING -p tcp -m mark ! --mark 0x0 -j ACCEPT")
|
|
iptables("-t mangle -A PREROUTING -p tcp -m ipp2p --bit "
|
|
"-j MARK --set-mark %s" % mark)
|
|
iptables("-t mangle -A PREROUTING -p tcp -m mark --mark %s "
|
|
"-j CONNMARK --save-mark" % mark)
|
|
|
|
warn = ''
|
|
|
|
# Par défaut, on envoit les paquets dans la classe 9998
|
|
for net in NETs['all']:
|
|
iptables("-t mangle -A POSTROUTING -o %(eth_int)s -d %(net)s "
|
|
"-j CLASSIFY --set-class 1:9998" % locals())
|
|
iptables("-t mangle -A POSTROUTING -o %(eth_ext)s -s %(net)s "
|
|
"-j CLASSIFY --set-class 1:9998" % locals())
|
|
|
|
# On crée les chaînes de sous-réseaux
|
|
for net in NETs['all']:
|
|
for mask in conf_fw.mask:
|
|
for subnet in NetSubnets(net, mask):
|
|
index = conf_fw.mask.index(mask)
|
|
if index == 0:
|
|
prev_chain = "POSTROUTING"
|
|
else:
|
|
ip = subnet.split('/')[0]
|
|
prev_subnet = IpSubnet(ip, conf_fw.mask[index-1])
|
|
prev_chain = "SUBNET-%s" % prev_subnet
|
|
next_chain = "SUBNET-%s" % subnet
|
|
redirect_chain('mangle', prev_chain, next_chain, subnet)
|
|
print OK
|
|
|
|
adherents = db.search('paiement=ok')['adherent']
|
|
self.anim = anim('\tGénération des classes de filtrage p2p', len(adherents))
|
|
|
|
# Création des classes et qdisc
|
|
for interface in [eth_ext, 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 %(interface)s root handle 1: htb r2q 1" % locals())
|
|
tc("class add dev %(interface)s parent 1: classid 1:1 "
|
|
"htb rate %(debit_max)s ceil %(debit_max)s" % locals())
|
|
tc("class add dev %(interface)s parent 1:1 classid 1:9998 "
|
|
"htb rate %(debit_adh)s ceil %(debit_adh)s" % locals())
|
|
tc("qdisc add dev %(interface)s parent 1:9998 "
|
|
"handle 9999: sfq perturb 10" % locals())
|
|
|
|
# On construit ensuite les classes et qdisc pour chaque adhérent
|
|
for adherent in adherents:
|
|
self.anim.cycle()
|
|
# On ne peut pas reprendre le numéro 1
|
|
class_id = int(adherent.id()) + 1
|
|
# Il nous faut un n° inférieur à 9998 unique
|
|
qdisc_id = class_id + 5000
|
|
for interface in [self.eth_ext, self.eth_int]:
|
|
tc("class add dev %(interface)s parent 1:1 classid 1:%(class_id)d "
|
|
"htb rate %(debit_adh)s ceil %(debit_max)s" % locals())
|
|
tc("qdisc add dev %(interface)s parent 1:%(class_id)d "
|
|
"handle %(qdisc_id)d: sfq perturb 10" % locals())
|
|
|
|
# Classification des adhérents dans leur classe respective
|
|
for machine in adherent.machines():
|
|
ip = machine.ip()
|
|
subnet = IpSubnet(machine.ip(), conf_fw.mask[-1])
|
|
iptables("-t mangle -A SUBNET-%(subnet)s -o crans -d %(ip)s "
|
|
"-j CLASSIFY --set-class 1:%(class_id)s" % locals())
|
|
iptables("-t mangle -A SUBNET-%(subnet)s -o ens -s %(ip)s "
|
|
"-j CLASSIFY --set-class 1:%(class_id)s" % locals())
|
|
self.anim.reinit()
|
|
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' ] :
|
|
iptables('-t nat -N %s' % chaine)
|
|
|
|
iptables("-t nat -P PREROUTING ACCEPT")
|
|
iptables("-t nat -A PREROUTING -i lo -j ACCEPT")
|
|
iptables("-t nat -A PREROUTING -d 224.0.0.0/4 -j DROP")
|
|
iptables("-t nat -A PREROUTING -s ! %s -j TEST_VIRUS_FLOOD" % self.zone_serveur)
|
|
iptables("-t nat -A PREROUTING -j RESEAUX_NON_ROUTABLES_DST")
|
|
iptables("-t nat -A PREROUTING -i %s -j RESEAUX_NON_ROUTABLES_SRC" % self.eth_ext )
|
|
iptables("-t nat -A PREROUTING -i %s -p udp --destination 138.231.136.1 --destination-port 53 -j DNAT --to-destination 138.231.136.3" % self.eth_ext)
|
|
iptables("-t nat -A PREROUTING -i %s -j ACCEPT" % self.eth_ext )
|
|
iptables("-t nat -A PREROUTING -s %s -j ACCEPT" % self.zone_serveur )
|
|
iptables("-t nat -A PREROUTING -d %s -j ACCEPT" % self.zone_serveur )
|
|
# iptables("-t nat -A PREROUTING -i %s -p tcp --dport 80 -s ! %s -j DNAT --to-destination 138.231.136.3:81" % (self.eth_int, self.zone_serveur) )
|
|
# iptables("-t nat -A POSTROUTING -o %s -p tcp --dport 81 -s 138.231.136.0/21 -d 138.231.136.3 -j SNAT --to-source 138.231.136.4" % self.eth_int )
|
|
iptables("-t nat -A PREROUTING -j TEST_MAC-IP")
|
|
iptables("-t nat -P PREROUTING ACCEPT")
|
|
iptables("-t nat -P OUTPUT ACCEPT")
|
|
|
|
# Proxy transparent
|
|
iptables("-t nat -A PREROUTING -p tcp -m mark --mark %s " % conf_fw.mark['proxy'] +
|
|
"-j DNAT --to-destination 138.231.144.10:3128")
|
|
print OK
|
|
|
|
def filter_table_tweaks(self) :
|
|
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")
|
|
iptables("-A FORWARD -p icmp -j ACCEPT")
|
|
iptables("-A FORWARD -i %s -d %s -j REJECT" % (self.eth_ext, self.vlan_adm) )
|
|
iptables("-A FORWARD -i %s -j BLACKLIST_DST" % self.eth_ext )
|
|
iptables("-A FORWARD -o %s -j BLACKLIST_SRC" % self.eth_ext )
|
|
iptables("-A FORWARD -s ! %s -d ! %s -j FILTRE_P2P" % (self.zone_serveur, self.zone_serveur) )
|
|
iptables("-A FORWARD -m state --state ESTABLISHED,RELATED -j ACCEPT")
|
|
iptables("-A FORWARD -i %s -d %s -j ADMIN_VLAN" % (self.eth_int, self.vlan_adm) )
|
|
iptables("-A FORWARD -i %s -d %s -j EXT_VERS_SERVEURS" % (self.eth_ext, self.zone_serveur) )
|
|
iptables("-A FORWARD -o %s -s %s -j SERVEURS_VERS_EXT" % (self.eth_ext, self.zone_serveur) )
|
|
iptables("-A FORWARD -i %s -j EXT_VERS_CRANS" % self.eth_ext )
|
|
iptables("-A FORWARD -o %s -j CRANS_VERS_EXT" % self.eth_ext )
|
|
|
|
# Proxy transparent
|
|
iptables("-I FORWARD -m mark --mark %s -j ACCEPT" % conf_fw.mark['proxy'])
|
|
print OK
|
|
|
|
def classes_p2p_maj(self, ip_list):
|
|
""" 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
|
|
|
|
print OK
|
|
|
|
## Traitement
|
|
# MAJ des règles de classification de l'IP
|
|
def procedure():
|
|
self.anim = anim('\tMise à jour des classes p2p')
|
|
|
|
# Liste des classes candidates a la suppression
|
|
scheduled_del = []
|
|
warn = ''
|
|
|
|
# Parametres pour iptables/tc
|
|
mark = conf_fw.mark['bittorrent']
|
|
debit_adh = p2p.debit_adh
|
|
debit_max = p2p.debit_max
|
|
eth_ext = self.eth_ext
|
|
eth_int = self.eth_int
|
|
|
|
try:
|
|
for ip in ip_list:
|
|
recherche = db.search('ip=%s&paiement=ok' % ip)
|
|
# Si l'ip n'appartient pas à un adhérent,
|
|
# on ne cherche pas plus loin
|
|
if not recherche['adherent']:
|
|
continue
|
|
machines = recherche['machine']
|
|
if not machines:
|
|
# Il faut supprimer cette entrée
|
|
iptables_option = '-D'
|
|
subnet = IpSubnet(ip, conf_fw.mask[-1])
|
|
regles = iptables("-t mangle -L SUBNET-%(subnet)s -n | "
|
|
"tee `tempfile -s _firewall`date -u +%y%m%d%H%M%S``"
|
|
"| grep %(ip)s" % locals()).split('\n')
|
|
# On sélectionne la première qui doit contenir ce que l'on veut
|
|
regle = regles[0].split()
|
|
class_id = int(regle[7].split(':')[1])
|
|
# On marque la classe comme candidate a la suppression
|
|
scheduled_del.append(class_id)
|
|
elif len(machines) == 1:
|
|
# Il faut ajouter cette entrée
|
|
iptables_option = '-A'
|
|
machine = machines[0]
|
|
adherent = machine.proprietaire()
|
|
ip = machine.ip()
|
|
subnet = IpSubnet(ip, conf_fw.mask[-1])
|
|
# On ne peut pas reprendre le numéro 1
|
|
class_id = int(adherent.id()) + 1
|
|
# On cree la classe et la qdisc s'il elles n'existent pas deja
|
|
qdisc_id = class_id + 5000
|
|
try:
|
|
for interface in [eth_ext, eth_int]:
|
|
tc("class add dev %(interface)s "
|
|
"parent 1:1 classid 1:%(class_id)d htb "
|
|
"rate %(debit_adh)s ceil %(debit_max)s" % locals())
|
|
tc("qdisc add dev %(interface)s "
|
|
"parent 1:%(class_id)d handle %(qdisc_id)d: "
|
|
"sfq perturb 10" % locals())
|
|
except TcError, e:
|
|
if "File exists" in e.output:
|
|
# La classe existe deja
|
|
pass
|
|
else:
|
|
raise e
|
|
else:
|
|
warn += "Plusieurs machines avec l'IP %s\n" % ip
|
|
# Il nous faut un n° inférieur à 9998 unique
|
|
iptables("-t mangle %(iptables_option)s SUBNET-%(subnet)s "
|
|
"-o %(eth_int)s -d %(ip)s -m mark --mark %(mark)s "
|
|
"-j CLASSIFY --set-class 1:%(class_id)s" % locals())
|
|
iptables("-t mangle %(iptables_option)s SUBNET-%(subnet)s "
|
|
"-o %(eth_ext)s -s %(ip)s -m mark --mark %(mark)s "
|
|
"-j CLASSIFY --set-class 1:%(class_id)s" % locals())
|
|
except IptablesError, c:
|
|
warn += str(c) + '\n'
|
|
|
|
for class_id in scheduled_del:
|
|
# TODO: supprimer les classes qui sont vraiment vides
|
|
pass
|
|
|
|
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 du routage")
|
|
warn = ''
|
|
for cmd in [ 'echo 1 > /proc/sys/net/ipv4/ip_forward' ,
|
|
'echo 65536 > /proc/sys/net/ipv4/ip_conntrack_max' ,
|
|
'modprobe ip_conntrack_ftp' ,
|
|
'modprobe ip_conntrack_irc' ] :
|
|
status,output=getstatusoutput(cmd)
|
|
if status :
|
|
warn += output + '\n'
|
|
if warn :
|
|
print WARNING
|
|
if self.debug :
|
|
print warn
|
|
else :
|
|
print OK
|
|
|
|
def pre_stop_hook(self) :
|
|
self.anim = anim("\tArrêt du routage")
|
|
status,output=getstatusoutput('echo 0 > /proc/sys/net/ipv4/ip_forward')
|
|
if status :
|
|
print ERREUR
|
|
else :
|
|
print OK
|
|
|
|
def start_fw_funcs(self) :
|
|
self.exception_catcher(self.log_chaines)
|
|
self.exception_catcher(self.test_virus_flood)
|
|
self.exception_catcher(self.reseaux_non_routables)
|
|
self.exception_catcher(self.blacklist)
|
|
self.exception_catcher(self.admin_vlan)
|
|
self.exception_catcher(self.serveurs_vers_ext)
|
|
self.exception_catcher(self.ext_vers_serveurs)
|
|
self.exception_catcher(self.crans_vers_ext)
|
|
self.exception_catcher(self.ext_vers_crans)
|
|
self.exception_catcher(self.test_mac_ip)
|
|
self.exception_catcher(self.filtre_p2p)
|
|
|
|
def serveurs_maj_list_to_do(self) :
|
|
self.exception_catcher(self.serveurs_vers_ext)
|
|
self.exception_catcher(self.ext_vers_serveurs)
|
|
|
|
def adh_maj_list_to_do(self) :
|
|
self.exception_catcher(self.crans_vers_ext)
|
|
self.exception_catcher(self.ext_vers_crans)
|
|
|
|
def log_chaines(self) :
|
|
""" Construction des chaînes de log (LOG_VIRUS et LOG_FLOOD) """
|
|
self.anim = anim('\tCréation des chaînes de log')
|
|
for filtre in [ 'VIRUS', 'FLOOD' ] :
|
|
# Vidage de la chaîne
|
|
iptables('-t nat -F LOG_%s' % filtre)
|
|
iptables('-t nat -A LOG_%s %s %s:' % (filtre, self.log_template, filtre.capitalize()) )
|
|
iptables('-t nat -A LOG_%s -j DROP' % filtre )
|
|
self.anim.cycle()
|
|
self.anim.reinit()
|
|
print OK
|
|
|
|
def test_virus_flood(self) :
|
|
""" Construction de la chaîne TEST_VIRUS """
|
|
iptables('-t nat -F TEST_VIRUS_FLOOD')
|
|
self.anim = anim('\tFiltrage virus et floods')
|
|
|
|
for proto, ports in self.ports_virus.items() :
|
|
for port in ports :
|
|
iptables('-t nat -A TEST_VIRUS_FLOOD -p %s --dport %s -j LOG_VIRUS' % (proto, port) )
|
|
self.anim.cycle()
|
|
|
|
iptables('-t nat -A TEST_VIRUS_FLOOD %s -j RETURN' % self.filtre_flood) # Les limites en négatif ca ne marche pas.
|
|
self.anim.cycle()
|
|
iptables('-t nat -A TEST_VIRUS_FLOOD -j LOG_FLOOD')
|
|
self.anim.reinit()
|
|
print OK
|
|
|
|
def serveurs_vers_ext(self) :
|
|
""" Reconstruit la chaîne SERVEURS_VERS_EXT """
|
|
if not self.build_chaine('SERVEURS_VERS_EXT', self.__serveurs_vers_ext) :
|
|
self.anim.reinit()
|
|
print OK
|
|
|
|
def ext_vers_serveurs(self) :
|
|
""" Reconstruit la chaîne EXT_VERS_SERVEURS """
|
|
if not self.build_chaine('EXT_VERS_SERVEURS', self.__ext_vers_serveurs) :
|
|
self.anim.reinit()
|
|
print OK
|
|
|
|
def crans_vers_ext(self) :
|
|
""" Reconstruit la chaîne CRANS_VERS_EXT """
|
|
self.build_chaine_adherent('CRANS_VERS_EXT',self.__crans_vers_ext)
|
|
|
|
def ext_vers_crans(self) :
|
|
""" Reconstruit la chaîne EXT_VERS_CRANS """
|
|
self.build_chaine_adherent('EXT_VERS_CRANS',self.__ext_vers_crans)
|
|
|
|
def admin_vlan(self) :
|
|
""" Reconstruit la chaîne ADMIN_VLAN """
|
|
iptables("-F ADMIN_VLAN")
|
|
nounou_machines = []
|
|
for adherent in db.search('droits=Nounou')['adherent'] :
|
|
for machine in adherent.machines() :
|
|
nounou_machines.append(machine.ip())
|
|
|
|
iptables("-A ADMIN_VLAN -j REJECT")
|
|
self.anim = anim('\tChaîne ADMIN_VLAN', len(nounou_machines))
|
|
for machine in nounou_machines :
|
|
self.anim.cycle()
|
|
iptables("-I ADMIN_VLAN -p tcp -s %s --dport ssh -j ACCEPT" % machine)
|
|
iptables("-I ADMIN_VLAN -p tcp -s %s --dport https -j ACCEPT" % machine)
|
|
self.anim.reinit()
|
|
print OK
|
|
|
|
def __serveurs_vers_ext(self,machine):
|
|
ip=machine.ip()
|
|
if not AddrInNet(ip,self.zone_serveur):
|
|
# C'est une machine adhérent, rien à faire ici
|
|
return
|
|
|
|
mac = machine.mac()
|
|
ports = { 'tcp' : machine.portTCPout(),
|
|
'udp' : machine.portUDPout() }
|
|
|
|
for proto in [ 'tcp', 'udp' ] :
|
|
for port in ports[proto]:
|
|
iptables("-I SERVEURS_VERS_EXT -s %s -p %s --dport %s -m mac --mac-source %s -j ACCEPT" \
|
|
%(ip,proto,port,mac))
|
|
|
|
def __ext_vers_serveurs(self,machine):
|
|
ip=machine.ip()
|
|
if not AddrInNet(ip,self.zone_serveur):
|
|
# C'est une machine adhérent, rien à faire ici
|
|
return
|
|
|
|
ports = { 'tcp' : machine.portTCPin(),
|
|
'udp' : machine.portUDPin() }
|
|
|
|
for proto in [ 'tcp', 'udp' ] :
|
|
for port in ports[proto]:
|
|
iptables("-I EXT_VERS_SERVEURS -d %s -p %s --dport %s -j ACCEPT"\
|
|
%(ip,proto,port))
|
|
|
|
def __crans_vers_ext(self,machine):
|
|
ip=machine.ip()
|
|
if AddrInNet(ip,self.zone_serveur):
|
|
# C'est un serveur, rien à faire ici
|
|
return
|
|
|
|
ports = { 'tcp' : machine.portTCPout(),
|
|
'udp' : machine.portUDPout() }
|
|
|
|
for proto in [ 'tcp', 'udp' ] :
|
|
for port in ports[proto]:
|
|
iptables("-I CRANS_VERS_EXT -s %s -p %s --dport %s -j ACCEPT" \
|
|
%(ip,proto,port))
|
|
|
|
def __ext_vers_crans(self,machine):
|
|
ip=machine.ip()
|
|
if AddrInNet(ip,self.zone_serveur):
|
|
# C'est un serveur, rien à faire ici
|
|
return
|
|
|
|
ports = { 'tcp' : machine.portTCPin(),
|
|
'udp' : machine.portUDPin() }
|
|
|
|
for proto in [ 'tcp', 'udp' ] :
|
|
for port in ports[proto]:
|
|
iptables("-I EXT_VERS_CRANS -d %s -p %s --dport %s -j ACCEPT" \
|
|
%(ip,proto,port))
|
|
|
|
def blacklist(self):
|
|
""" Construit les chaînes de blackliste (BLACKLIST_{DST,SRC}) """
|
|
iptables('-F BLACKLIST_DST')
|
|
iptables('-F BLACKLIST_SRC')
|
|
|
|
# Peut-être à mettre dans config.py ?
|
|
blacklist_sanctions = ('upload', 'warez', 'p2p', 'autodisc_p2p', 'autodisc_upload', 'bloq')
|
|
|
|
blacklist = []
|
|
|
|
# Recherche sur le champ ablacklist (clubs compris)
|
|
search = db.search('ablacklist=*&paiement=%s' % ann_scol)
|
|
self.anim = anim("\tBlackliste adhérents+clubs", len(search['adherent']+search['club']))
|
|
for entite in search['adherent'] + search['club']:
|
|
self.anim.cycle()
|
|
sanctions = entite.blacklist_actif()
|
|
for s in blacklist_sanctions:
|
|
if s in sanctions:
|
|
blacklist.extend(entite.machines())
|
|
break
|
|
self.anim.reinit()
|
|
print OK
|
|
|
|
# Recherche sur le champ mblacklist
|
|
search = db.search('mblacklist=*&paiement=%s' % ann_scol)
|
|
self.anim = anim("\tBlackliste machines", len(search['machine']))
|
|
for entite in search['machine']:
|
|
self.anim.cycle()
|
|
sanctions = entite.blacklist_actif()
|
|
for s in blacklist_sanctions:
|
|
if s in sanctions:
|
|
blacklist.append(entite)
|
|
break
|
|
self.anim.reinit()
|
|
print OK
|
|
|
|
self.anim = anim("\tChaînes BLACKLISTE", len(blacklist))
|
|
for machine in blacklist:
|
|
self.anim.cycle()
|
|
iptables("-A BLACKLIST_DST -d %s -j REJECT --reject-with icmp-host-prohibited" % machine.ip())
|
|
iptables("-A BLACKLIST_SRC -s %s -j REJECT --reject-with icmp-host-prohibited" % machine.ip())
|
|
self.anim.reinit()
|
|
print OK
|
|
|
|
def filtre_p2p(self):
|
|
""" Construit la chaînes de filtrage du p2p (FILTRE_P2P) """
|
|
self.anim = anim("\tFiltrage p2p")
|
|
iptables('-F FILTRE_P2P')
|
|
|
|
# On ne filtre que ce qui passe sur l'interface externe
|
|
iptables('-A FILTRE_P2P -i %s -o %s -j RETURN' % (self.eth_int, self.eth_int) )
|
|
|
|
|
|
for filtre in self.filtres_p2p :
|
|
iptables('-A FILTRE_P2P -m ipp2p --%s -j LOG --log-prefix "IPP2P=%s "' % (filtre[0],
|
|
filtre[1]))
|
|
#iptables('-A FILTRE_P2P -m ipp2p --%s -j REJECT --reject-with icmp-admin-prohibited' % filtre[0])
|
|
iptables('-A FILTRE_P2P -m ipp2p --%s -j RETURN' % filtre[0])
|
|
self.anim.cycle()
|
|
|
|
self.anim.reinit()
|
|
print OK
|
|
|
|
def serveurs_maj(self) :
|
|
self.exception_catcher(self.serveurs_vers_ext)
|
|
|
|
"""
|
|
Zamok
|
|
"""
|
|
|
|
class firewall_zamok(firewall_crans) :
|
|
"""
|
|
Structure du firewall :
|
|
table nat :
|
|
SERV_OUT_ADM
|
|
TEST_MAC-IP
|
|
table filter :
|
|
FORWARD (policy par défaut : DROP)
|
|
rien ne passe pas la chaîne FORWARD
|
|
INPUT (policy par défaut : ACCEPT)
|
|
|
|
"""
|
|
|
|
# interfaces physiques
|
|
eth_pub = "crans"
|
|
eth_adm = "crans.2"
|
|
|
|
def serv_out_adm(self) :
|
|
self.anim = anim('\tOutput vers VLAN adm', len(self.adm_users))
|
|
# Supression des éventuelles règles
|
|
iptables("-t filter -F SERV_OUT_ADM")
|
|
|
|
for user in self.adm_users :
|
|
self.anim.cycle()
|
|
try:
|
|
iptables("-A SERV_OUT_ADM -m owner --uid-owner %d -j ACCEPT" % pwd.getpwnam(user)[2])
|
|
except KeyError:
|
|
continue
|
|
|
|
# LDAP et DNS toujours joignable
|
|
iptables("-A SERV_OUT_ADM -p tcp --dport ldap -j ACCEPT")
|
|
iptables("-A SERV_OUT_ADM -p tcp --dport domain -j ACCEPT")
|
|
iptables("-A SERV_OUT_ADM -p udp --dport domain -j ACCEPT")
|
|
|
|
# Pour le nfs (le paquet à laisser passer n'a pas d'owner)
|
|
iptables("-A SERV_OUT_ADM -d nfs.adm.crans.org -m owner ! --uid-owner 0 -j REJECT --reject-with icmp-net-prohibited")
|
|
iptables("-A SERV_OUT_ADM -d nfs.adm.crans.org -j ACCEPT")
|
|
|
|
# Rien d'autre ne passe
|
|
iptables("-A SERV_OUT_ADM -j REJECT --reject-with icmp-net-prohibited")
|
|
|
|
self.anim.reinit()
|
|
print OK
|
|
|
|
def nat_table(self) :
|
|
self.anim = anim('\tStructure de la table nat')
|
|
iptables('-t nat -N TEST_MAC-IP')
|
|
iptables('-t filter -N SERV_OUT_ADM')
|
|
|
|
iptables("-t nat -P PREROUTING ACCEPT")
|
|
iptables("-t nat -A PREROUTING -i lo -j ACCEPT")
|
|
iptables("-t nat -A PREROUTING -d 224.0.0.0/4 -j DROP")
|
|
|
|
for net in NETs['fil'] + NETs['vlan-adm'] + NETs['wifi'] :
|
|
iptables("-t nat -A PREROUTING -s %s -j TEST_MAC-IP" % net)
|
|
iptables("-t filter -A OUTPUT -o lo -j ACCEPT")
|
|
|
|
# pour une connection entrante venant du VLAN adm, il faut que le ACK
|
|
# puisse passer (interaction avec pam, uid de l'utilisateur en OUTPUT)
|
|
# on accepte donc les paquets si la connection est
|
|
# en RELATED et ESTABLISHED
|
|
iptables("-t filter -A OUTPUT -m state --state RELATED,ESTABLISHED -j ACCEPT")
|
|
iptables("-t filter -A OUTPUT -o %s -j SERV_OUT_ADM" % self.eth_adm)
|
|
|
|
iptables("-t nat -P PREROUTING ACCEPT")
|
|
iptables("-t filter -P OUTPUT ACCEPT")
|
|
print OK
|
|
|
|
def start_fw_funcs(self) :
|
|
self.exception_catcher(self.test_mac_ip)
|
|
self.serv_out_adm()
|
|
|
|
def filter_table_tweaks(self) :
|
|
self.anim = anim('\tRègles spécifiques à zamok')
|
|
iptables("-P INPUT ACCEPT")
|
|
iptables("-P FORWARD DROP")
|
|
print OK
|
|
|
|
"""
|
|
Rouge
|
|
"""
|
|
|
|
class firewall_rouge(firewall_crans) :
|
|
"""
|
|
Structure du firewall :
|
|
table nat :
|
|
SERV_OUT_ADM
|
|
TEST_MAC-IP
|
|
table filter :
|
|
FORWARD (policy par défaut : DROP)
|
|
rien ne passe pas la chaîne FORWARD
|
|
INPUT (policy par défaut : ACCEPT)
|
|
|
|
"""
|
|
|
|
# interfaces physiques
|
|
eth_pub = "eth0"
|
|
eth_adm = "eth0.2"
|
|
|
|
def nat_table(self) :
|
|
self.anim = anim('\tStructure de la table nat')
|
|
iptables('-t nat -N TEST_MAC-IP')
|
|
|
|
iptables("-t nat -P PREROUTING ACCEPT")
|
|
iptables("-t nat -A PREROUTING -i lo -j ACCEPT")
|
|
iptables("-t nat -A PREROUTING -d 224.0.0.0/4 -j DROP")
|
|
|
|
for net in NETs['fil'] + NETs['vlan-adm'] + NETs['wifi'] :
|
|
iptables("-t nat -A PREROUTING -s %s -j TEST_MAC-IP" % net)
|
|
|
|
iptables("-t nat -P PREROUTING ACCEPT")
|
|
iptables("-t nat -P OUTPUT ACCEPT")
|
|
print OK
|
|
|
|
def filter_table_tweaks(self) :
|
|
self.anim = anim('\tRègles spécifiques à rouge')
|
|
iptables("-P INPUT ACCEPT")
|
|
iptables("-P FORWARD DROP")
|
|
print OK
|
|
|
|
|
|
"""
|
|
Vert
|
|
"""
|
|
|
|
class firewall_vert(firewall_crans) :
|
|
"""
|
|
Structure du firewall :
|
|
table nat :
|
|
MAC-IP
|
|
table filter :
|
|
FORWARD (policy par défaut : DROP)
|
|
rien ne passe pas la chaîne FORWARD
|
|
INPUT (policy par défaut : ACCEPT)
|
|
|
|
"""
|
|
|
|
# interfaces physiques
|
|
eth_crans = "crans"
|
|
|
|
def nat_table(self) :
|
|
self.anim = anim('\tStructure de la table nat')
|
|
iptables('-t nat -N TEST_MAC-IP')
|
|
|
|
iptables("-t nat -P PREROUTING ACCEPT")
|
|
iptables("-t nat -A PREROUTING -i lo -j ACCEPT")
|
|
iptables("-t nat -A PREROUTING -d 224.0.0.0/4 -j DROP")
|
|
|
|
for net in NETs['fil'] + NETs['vlan-adm'] + NETs['wifi'] :
|
|
iptables("-t nat -A PREROUTING -s %s -j TEST_MAC-IP" % net)
|
|
|
|
iptables("-t nat -P PREROUTING ACCEPT")
|
|
iptables("-t nat -P OUTPUT ACCEPT")
|
|
print OK
|
|
|
|
def filter_table_tweaks(self) :
|
|
self.anim = anim('\tRègles spécifiques à vert')
|
|
iptables("-P INPUT ACCEPT")
|
|
iptables("-P FORWARD DROP")
|
|
print OK
|
|
|
|
class firewall_sila(firewall_rouge):
|
|
"""Comme pour rouge, avec le proxy transparent en plus"""
|
|
|
|
def mangle_table(self):
|
|
# Pour le proxy transparent
|
|
iptables("-t mangle -F PREROUTING")
|
|
iptables("-t mangle -i crans.2 -A PREROUTING -p tcp --destination-port 3128 " +
|
|
"--destination 138.231.144.10 " +
|
|
"-m mac --mac-source %s " % mac_komaz +
|
|
"-j MARK --set-mark %s" % conf_fw.mark['proxy'])
|
|
iptables("-t mangle -A PREROUTING -m mark --mark %s -j ACCEPT" % conf_fw.mark['proxy'])
|
|
|
|
def nat_table(self):
|
|
firewall_rouge.nat_table(self)
|
|
# Pour le proxy transparent
|
|
iptables("-t nat -I PREROUTING -i crans.2 -m mark --mark %s -j ACCEPT" % conf_fw.mark['proxy'])
|
|
|
|
firewall_bleu = firewall_zamok
|
|
|
|
if __name__ == '__main__' :
|
|
# 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', 'mangle_table', 'classes_p2p_maj' ] :
|
|
chaines.append(nom)
|
|
|
|
def __usage(txt=None) :
|
|
if txt!=None : cprint(txt,'gras')
|
|
|
|
print """Usage:
|
|
%(p)s start : Construction du firewall.
|
|
%(p)s restart : Reconstruction du firewall.
|
|
%(p)s stop : Arrêt du firewall.
|
|
%(p)s <noms de chaînes> : reconstruit les chaînes
|
|
Les chaînes pouvant être reconstruites sont :
|
|
%(chaines)s
|
|
Pour reconfiguration d'IPs particulières, utiliser generate. """ % \
|
|
{ 'p' : sys.argv[0].split('/')[-1] , 'chaines' : '\n '.join(chaines) }
|
|
sys.exit(-1)
|
|
|
|
# Bons arguments ?
|
|
if len(sys.argv) == 1 :
|
|
__usage()
|
|
for arg in sys.argv[1:] :
|
|
if arg in [ 'stop', 'restart', 'start' ] and len(sys.argv) != 2 :
|
|
__usage("L'argument %s ne peut être employé que seul." % arg)
|
|
|
|
if arg not in [ 'stop', 'restart', 'start' ] + chaines :
|
|
__usage("L'argument %s est inconnu." % arg)
|
|
|
|
for arg in sys.argv[1:] :
|
|
eval('fw.%s()' % arg )
|