
Ignore-this: 16f86d33fe0e98057fd9533abc25aa88 TOujours effectué sur squid, elles était alors simplement ignoré puisque la connection au web est maintemant directe. On ajoute donc des blacklistes soft "virtuelle" pour carte et chambre invalide dans ldap_crans, ce qui a pour effet de faire que le pare-feu redirige vers sable (et squid) les machines consernées. On dit à générate de recharger les blackliste du pare-feu lorsque l'on coche une carte étudiant dans gest_crans ou quand le status chambre invalide change. btw, on reporte aussi les modifications de crans_ldap dans lc_ldap. darcs-hash:20121104020449-3a55a-78f73e677e75e8eaa087fd9bd6f8c1aec2b593ea.gz
1562 lines
64 KiB
Python
Executable file
1562 lines
64 KiB
Python
Executable file
#!/usr/bin/env python
|
|
# -*- coding: utf-8 -*-
|
|
# 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')
|
|
sys.path.append('/usr/scripts/lc_ldap')
|
|
|
|
import syslog
|
|
import pwd
|
|
import commands
|
|
from lock import *
|
|
from ldap_crans import crans_ldap, ann_scol, hostname
|
|
from ldap_crans import AssociationCrans, Machine, MachineWifi, BorneWifi
|
|
from affich_tools import *
|
|
from commands import getstatusoutput
|
|
from iptools import AddrInNet, NetSubnets, IpSubnet
|
|
from config import NETs, mac_komaz, mac_wifi, mac_titanic, mac_g, conf_fw, p2p, vlans, debit_max_radin, adm_users, accueil_route
|
|
from ipset import IpsetError, Ipset
|
|
from lc_ldap import lc_ldap
|
|
syslog.openlog('firewall')
|
|
|
|
debug = 1
|
|
db = crans_ldap()
|
|
QUERY=lc_ldap(uri='ldap://ldap.adm.crans.org/')
|
|
|
|
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 iptables_save():
|
|
""" Sauvegarde d'ipatbles """
|
|
status,output=getstatusoutput("mkdir -p /var/log/firewall/")
|
|
if status:
|
|
raise IptablesError(cmd,status,output)
|
|
status,output=getstatusoutput("/sbin/iptables-save > /var/log/firewall/backup-firewall_`date +%Y-%m-%d_%H:%M:%S`.log" )
|
|
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['adm'][0]
|
|
|
|
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 100/second --hashlimit-mode srcip,dstip,dstport --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')
|
|
self.mac_ip_set = Ipset("MAC-IP","macipmap","--from 138.231.136.0 --to 138.231.151.255")
|
|
self.mac_ip_adm_set = Ipset("MAC-IP-ADM","macipmap","--from 10.231.136.0 --to 10.231.136.255")
|
|
try:
|
|
self.mac_ip_set.list()
|
|
except IpsetError:
|
|
self.mac_ip_set.create()
|
|
try:
|
|
self.mac_ip_adm_set.list()
|
|
except IpsetError:
|
|
self.mac_ip_adm_set.create()
|
|
|
|
def __del__(self) :
|
|
""" Destruction du lock """
|
|
# Comprend pas pourquoi il faut réimporter ici -- Fred
|
|
from lock import remove_lock
|
|
remove_lock('firewall')
|
|
|
|
def reload_qos(self):
|
|
"""Recherche la QoS"""
|
|
return
|
|
|
|
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) :
|
|
iptables_save()
|
|
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):
|
|
iptables('-t filter -F TEST_MAC-IP')
|
|
self.mac_ip_gen()
|
|
iptables('-t filter -A TEST_MAC-IP -m set --match-set %s src -j RETURN' % self.mac_ip_set.set)
|
|
iptables('-t filter -A TEST_MAC-IP -m set --match-set %s src -j RETURN' % self.mac_ip_adm_set.set)
|
|
|
|
# Proxy ARP de Komaz et Titanic pour OVH
|
|
ip_ovh = db.search('host=ovh.adm.crans.org')['machineCrans'][0].ip()
|
|
iptables('-t filter -A TEST_MAC-IP -m mac -s %s --mac-source %s -j RETURN' % (ip_ovh, mac_komaz))
|
|
iptables('-t filter -A TEST_MAC-IP -m mac -s %s --mac-source %s -j RETURN' % (ip_ovh, mac_titanic))
|
|
|
|
iptables('-t filter -A TEST_MAC-IP -j DROP')
|
|
|
|
def __test_mac_ip(self, machine, flushed = False):
|
|
ip = machine.ip()
|
|
if ip.startswith("138.231.1"):
|
|
if not flushed:
|
|
try:
|
|
self.mac_ip_set.delete(ip)
|
|
except IpsetError:
|
|
pass
|
|
if machine.__class__.__name__ == "MachineWifi" and hostname != 'gordon':
|
|
# Machine Wifi, c'est la mac de gordon
|
|
self.mac_ip_set.add("%s,%s" % (ip,mac_wifi))
|
|
else:
|
|
# Machine fixe
|
|
self.mac_ip_set.add("%s,%s" % (ip,machine.mac()))
|
|
elif ip.startswith("10.231.136."):
|
|
if not flushed:
|
|
try:
|
|
self.mac_ip_adm_set.delete(ip)
|
|
except IpsetError:
|
|
pass
|
|
self.mac_ip_adm_set.add("%s,%s" % (ip,machine.mac()))
|
|
|
|
def __test_mac_ip_delete(self, ip):
|
|
if ip.startswith("138.231.1"):
|
|
try:
|
|
self.mac_ip_set.delete(ip)
|
|
except IpsetError:
|
|
pass
|
|
elif ip.startswith("10.231.136."):
|
|
try:
|
|
self.mac_ip_adm_set.delete(ip)
|
|
except IpsetError:
|
|
pass
|
|
|
|
|
|
def mac_ip_maj(self, ip_list):
|
|
for ip in ip_list:
|
|
machines=db.search("ip=%s" % ip)['machine']
|
|
if not machines:
|
|
self.__test_mac_ip_delete(ip)
|
|
else:
|
|
try:
|
|
#~ self.mac_ip_set.add("%s,%s" % (ip, machines[0].mac()))
|
|
self.__test_mac_ip(machines[0])
|
|
except IpsetError:
|
|
pass
|
|
|
|
def mac_ip_gen(self):
|
|
self.anim = anim('\tChaîne TEST_MAC-IP', len(self.__machines()))
|
|
self.mac_ip_set.flush()
|
|
self.mac_ip_adm_set.flush()
|
|
|
|
self.anim.reinit()
|
|
for machine in self.__machines():
|
|
self.anim.cycle()
|
|
self.__test_mac_ip(machine, flushed = True)
|
|
self.anim.reinit()
|
|
print OK
|
|
|
|
|
|
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 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 par FILTRE_P2P (ACCEPT sur le trafic de filtres_p2p, REJECT sur le trafic de
|
|
filtres_p2p_bloq, sanctions 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 : logging des paquets matchés par les protocoles de filtres_p2p
|
|
rejet des paquets matchés par les protocoles de filtres_p2p_bloq au dessus de la limite
|
|
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
|
|
INGRESS_FILTERING : ne laisse sortir que les paquets dont l'adresse IP source appartient au crans
|
|
"""
|
|
|
|
# interfaces physiques
|
|
eth_ext = "ens"
|
|
eth_int = "crans"
|
|
eth_adm = "crans.2"
|
|
|
|
# Ports ouverts
|
|
ports_default = { 'tcp_EXT_VERS_CRANS' : [ '22' ],
|
|
'tcp_CRANS_VERS_EXT': [ ':24', '26:79', '80: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
|
|
# Apple et WinMX desactives car possibilite de fausse detection par ipp2p
|
|
filtres_p2p = [ #('apple', 'AppleJuice'),
|
|
('soul', 'SoulSeek'),
|
|
#('winmx', 'WinMX'),
|
|
('edk', 'eDonkey'),
|
|
('dc', 'DirectConnect'),
|
|
('kazaa', 'KaZaa'),
|
|
('ares', 'Ares'),
|
|
('bit', 'Bittorrent'),
|
|
('gnu', 'GNUtella') ]
|
|
|
|
filtres_p2p_bloq = [
|
|
]
|
|
|
|
udp_torrent_tracker={
|
|
'tracker.openbittorrent.com':[['95.215.62.26',80],['95.215.62.5',80]],
|
|
'tracker.ccc.de':[['195.54.164.83',80]],
|
|
'tracker.istole.it':[['192.121.121.30',80]],
|
|
'tracker.publicbt.com':[['95.211.88.54',80],['95.211.88.49',80],['95.211.88.51',80]],
|
|
}
|
|
|
|
|
|
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', '100.64.0.0/10']
|
|
|
|
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))
|
|
iptables("-t filter -A RESEAUX_NON_ROUTABLES_DST -d 10.231.136.0/24 -j RETURN")
|
|
iptables("-t filter -A RESEAUX_NON_ROUTABLES_SRC -d 10.231.136.0/24 -j RETURN")
|
|
iptables("-t filter -A RESEAUX_NON_ROUTABLES_DST -d %s -j RETURN" % NETs['personnel-ens'][0])
|
|
iptables("-t filter -A RESEAUX_NON_ROUTABLES_SRC -s %s -j RETURN" % NETs['personnel-ens'][0])
|
|
for reseau in self.liste_reseaux_non_routables :
|
|
iptables("-t filter -A RESEAUX_NON_ROUTABLES_DST -d %s -j DROP" % reseau)
|
|
iptables("-t filter -A RESEAUX_NON_ROUTABLES_SRC -s %s -j DROP" % reseau)
|
|
self.anim.cycle()
|
|
self.anim.reinit()
|
|
print OK
|
|
|
|
|
|
def reload_qos(self):
|
|
self.mangle_table()
|
|
self.qos()
|
|
|
|
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")
|
|
|
|
#Log de paquets
|
|
iptables('-t mangle -A PREROUTING -i %s -m state --state NEW -j LOG --log-prefix "LOG_ALL "' % self.eth_int)
|
|
iptables('-t mangle -A PREROUTING -i %s -m state --state NEW -j LOG --log-prefix "LOG_ALL "' % self.eth_ext)
|
|
|
|
# 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'])
|
|
iptables("-t mangle -N BLACKLIST_SOFT")
|
|
iptables("-t mangle -A PREROUTING -p tcp --destination-port 80 "
|
|
"-s %s -d ! %s -j BLACKLIST_SOFT" %
|
|
(NETs['fil'][0], NETs['wifi'][0]))
|
|
iptables("-t mangle -A PREROUTING -m mark --mark %s -j ACCEPT" % conf_fw.mark['proxy'])
|
|
|
|
|
|
#connection de secours
|
|
iptables("-t mangle -A PREROUTING -p tcp -s 138.231.136.0/16 ! -d 138.231.136.0/16 --destination-port 80 -m condition --condition secours -j MARK --set-mark %s" % (conf_fw.mark['secours']))
|
|
iptables("-t mangle -A PREROUTING -m mark --mark %s -j ACCEPT" % conf_fw.mark['secours'])
|
|
|
|
# Parametres pour iptables/tc
|
|
mark = conf_fw.mark['bittorrent']
|
|
debit_max = conf_fw.debit_max
|
|
debit_max_semi=debit_max/2
|
|
eth_ext = self.eth_ext
|
|
eth_int = self.eth_int
|
|
|
|
# Classification du traffic : extérieur <-> ftp
|
|
iptables("-t mangle -A POSTROUTING -o %(eth_int)s -d 138.231.136.98 "
|
|
"-j CLASSIFY --set-class 1:9997" % locals())
|
|
iptables("-t mangle -A POSTROUTING -o %(eth_ext)s -s 138.231.136.98 "
|
|
"-j CLASSIFY --set-class 1:9997" % locals())
|
|
|
|
# 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 = ''
|
|
|
|
# pas de QoS pour la zone ens
|
|
iptables("-t mangle -A POSTROUTING -d 138.231.0.0/16 -s 138.231.0.0/16 -j RETURN")
|
|
# 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())
|
|
|
|
for net in NETs['personnel-ens']:
|
|
# pas de limitation en download
|
|
#iptables("-t mangle -A POSTROUTING -d %(net)s "
|
|
# "-j CLASSIFY --set-class 1:9998" % locals())
|
|
iptables("-t mangle -A POSTROUTING -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
|
|
|
|
|
|
self.anim = anim('\tLimitation du debit')
|
|
adherents = db.search('paiement=ok')['adherent']
|
|
self.adherents=adherents
|
|
debit_adh = int(debit_max / float(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)skbps ceil %(debit_max)skbps" % locals())
|
|
tc("class add dev %(interface)s parent 1:1 classid 1:9999 "
|
|
"htb rate %(debit_adh)skbps ceil %(debit_adh)skbps" % locals())
|
|
tc("qdisc add dev %(interface)s parent 1:9999 "
|
|
"handle 9999: sfq perturb 10" % locals())
|
|
debit_ftp = 1000 # kbps
|
|
tc("class add dev %(interface)s parent 1:1 classid 1:9997 "
|
|
"htb rate %(debit_ftp)skbps ceil %(debit_max_semi)skbps prio 1" % locals())
|
|
tc("qdisc add dev %(interface)s parent 1:9997 "
|
|
"handle 9997: sfq perturb 10" % locals())
|
|
|
|
tc("class add dev %(interface)s parent 1:1 classid 1:9998 "
|
|
"htb rate %(debit_max_semi)skbps ceil %(debit_max)skbps prio 1" % locals())
|
|
tc("qdisc add dev %(interface)s parent 1:9998 "
|
|
"handle 9998: sfq perturb 10" % locals())
|
|
|
|
for interface in ["crans.21"]:
|
|
# 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 128kbps ceil 128kbps" % locals())
|
|
tc("class add dev %(interface)s parent 1:1 classid 1:9998 "
|
|
"htb rate 128kbps ceil 128kbps prio 1" % locals())
|
|
tc("qdisc add dev %(interface)s parent 1:9998 "
|
|
"handle 9998: sfq perturb 10" % locals())
|
|
print OK
|
|
|
|
def qos(self):
|
|
|
|
if len(self.adherents) == 0 :
|
|
self.mangle_table()
|
|
|
|
# Parametres pour iptables/tc
|
|
mark = conf_fw.mark['bittorrent']
|
|
debit_max = conf_fw.debit_max
|
|
debit_max_semi=debit_max/2
|
|
eth_ext = self.eth_ext
|
|
eth_int = self.eth_int
|
|
|
|
adherents = self.adherents
|
|
debit_adh = int(debit_max / float(len(adherents)))
|
|
|
|
|
|
self.anim = anim('\tGénération des classes de QoS', len(adherents))
|
|
# 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 à 9999 unique
|
|
qdisc_id = class_id
|
|
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)skbps ceil %(debit_max)skbps prio 0" % 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()
|
|
if not AddrInNet(ip, NETs['all']):
|
|
# Cas particulier d'une machine ayant une IP non CRANS
|
|
continue
|
|
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())
|
|
|
|
# +-----------------+
|
|
# | QOS pour le ftp |
|
|
# +-----------------+
|
|
|
|
# On ne veut pas que les gens à l'éxtérieur bouffe toute la
|
|
# bande passante.
|
|
|
|
# Classification des paquets à destination du ftp
|
|
iptables("-t mangle -A POSTROUTING -o %(eth_int)s -p tcp -d 138.231.136.98 --dport 21 "
|
|
"-j CLASSIFY --set-class 1:9997" % locals())
|
|
|
|
self.anim.reinit()
|
|
print OK
|
|
|
|
def nat_table(self) :
|
|
self.anim = anim('\tStructure de la table nat')
|
|
|
|
iptables("-t nat -P PREROUTING ACCEPT")
|
|
iptables("-t nat -P OUTPUT ACCEPT")
|
|
iptables("-t nat -A PREROUTING -p tcp -d 138.231.136.2 --dport 22 -j DNAT --to-destination 138.231.136.1:22") # redirection du ssh vers zamok
|
|
iptables("-t nat -A PREROUTING -p tcp -d 138.231.136.2 --dport 443 -j DNAT --to-destination 138.231.136.1:22") # redirection du ssh vers zamok (pour passer dans un proxy, avec corkscrew)
|
|
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 )
|
|
|
|
# Proxy transparent
|
|
iptables("-t nat -A PREROUTING -p tcp -m mark --mark %s " % conf_fw.mark['proxy'] +
|
|
"-j DNAT --to-destination 10.231.136.9:3128")
|
|
|
|
# Appartement ENS
|
|
iptables("-t nat -A POSTROUTING -o ens -s %s -j SNAT --to 138.231.136.44" % NETs['personnel-ens'][0])
|
|
iptables("-t nat -A POSTROUTING -o crans -s %s -j SNAT --to 138.231.136.44" % NETs['personnel-ens'][0])
|
|
|
|
#Connection de secours
|
|
iptables("-t nat -A PREROUTING -p tcp -m mark --mark %s " % conf_fw.mark['secours'] +
|
|
"-j DNAT --to-destination 10.231.136.9:3128")
|
|
print OK
|
|
|
|
def filter_table(self) :
|
|
self.anim = anim('\tStructure de la table filter')
|
|
for chaine in [ 'TEST_MAC-IP', 'RESEAUX_NON_ROUTABLES_SRC', 'RESEAUX_NON_ROUTABLES_DST' ] :
|
|
iptables('-t filter -N %s' % chaine)
|
|
|
|
|
|
iptables("-A FORWARD -i lo -j ACCEPT")
|
|
iptables("-A FORWARD -p icmp -j ACCEPT")
|
|
iptables("-A FORWARD -i tun-ovh -j ACCEPT")
|
|
iptables("-A FORWARD -d 224.0.0.0/4 -j DROP")
|
|
#iptables("-A FORWARD -m state --state ESTABLISHED,RELATED -j ACCEPT")
|
|
for net in NETs['fil'] + NETs['wifi']:
|
|
iptables("-A FORWARD -s %s -i %s -j TEST_MAC-IP" % (net, self.eth_int))
|
|
for net in NETs['adm']:
|
|
iptables("-A FORWARD -s %s -i %s -j TEST_MAC-IP" % (net, self.eth_adm))
|
|
|
|
iptables("-A FORWARD -j RESEAUX_NON_ROUTABLES_DST")
|
|
iptables("-A FORWARD -i %s -j RESEAUX_NON_ROUTABLES_SRC" % self.eth_ext )
|
|
|
|
|
|
# Proxy transparent, pour les deconnexion soft
|
|
iptables("-A FORWARD -m mark --mark %s -j ACCEPT" % conf_fw.mark['proxy'])
|
|
|
|
#Connection de secours
|
|
# on ne peut pas faire passer https dans un proxy transparent sans faire de man in the middle et sans recompiler squid
|
|
iptables("-A FORWARD -p tcp -s 138.231.136.0/16 ! -d 138.231.136.0/16 --destination-port 443 -m condition --condition secours -j REJECT")
|
|
iptables("-A FORWARD -m mark --mark %s -j ACCEPT" % conf_fw.mark['secours'])
|
|
|
|
iptables("-P FORWARD ACCEPT")
|
|
|
|
for net in NETs['fil'] + NETs['wifi']:
|
|
iptables("-A INPUT -s %s -i %s -j TEST_MAC-IP" % (net, self.eth_int))
|
|
for net in NETs['adm']:
|
|
iptables("-A INPUT -s %s -i %s -j TEST_MAC-IP" % (net, self.eth_adm))
|
|
iptables("-P INPUT ACCEPT")
|
|
|
|
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', 'INGRESS_FILTERING',
|
|
'TEST_VIRUS_FLOOD', 'LOG_VIRUS', 'LOG_FLOOD','LOG_TRACKER','TRACKER_FILTER' ] :
|
|
iptables('-N %s' % chaine)
|
|
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 -s %s -j ACCEPT" % NETs['personnel-ens'][0])
|
|
iptables("-A FORWARD -d %s -j ACCEPT" % NETs['personnel-ens'][0])
|
|
iptables("-A FORWARD -m state --state ESTABLISHED,RELATED -j ACCEPT")
|
|
iptables("-A FORWARD -j INGRESS_FILTERING")
|
|
# on ne route pas les paquets n'appartenant pas à notre plage ip -- xhub
|
|
for net in NETs['all']:
|
|
iptables("-A INGRESS_FILTERING -o ens -s %s -j RETURN" % net)
|
|
iptables("-A INGRESS_FILTERING -o ens -j LOG --log-prefix BAD_ROUTE ")
|
|
iptables("-A INGRESS_FILTERING -o ens -j DROP")
|
|
# protection contre un certain type de spoof
|
|
# cf http://travaux.ovh.net/?do=details&id=5183 -- xhub
|
|
for net_d in NETs['all']:
|
|
for net in NETs['all']:
|
|
iptables("-A INGRESS_FILTERING -i ens -s ! %s -d %s -j RETURN" % (net,net_d))
|
|
iptables("-A INGRESS_FILTERING -i ens -j LOG --log-prefix BAD_SRC ")
|
|
iptables("-A INGRESS_FILTERING -i ens -j DROP")
|
|
iptables("-A FORWARD -i %s -d %s -j ADMIN_VLAN" % (self.eth_int, self.vlan_adm) )
|
|
iptables("-A FORWARD -i %s -d %s -j REJECT" % (self.eth_ext, self.vlan_adm) )
|
|
iptables("-A FORWARD -s ! %s -j TEST_VIRUS_FLOOD" % self.zone_serveur)
|
|
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 )
|
|
|
|
|
|
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_max = conf_fw.debit_max
|
|
debit_adh = int(conf_fw.debit_max / 1200.) # XXX: guesstimate
|
|
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])
|
|
all_regles = iptables("-t mangle -L SUBNET-%(subnet)s -n" % locals()).split('\n')
|
|
regles = [line for line in all_regles if ip in line]
|
|
# 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
|
|
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 à 9999 unique
|
|
iptables("-t mangle %(iptables_option)s SUBNET-%(subnet)s "
|
|
"-o %(eth_int)s -d %(ip)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 "
|
|
"-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/netfilter/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)
|
|
self.exception_catcher(self.qos)
|
|
|
|
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('-F LOG_%s' % filtre)
|
|
iptables('-A LOG_%s %s %s:' % (filtre, self.log_template, filtre.capitalize()) )
|
|
iptables('-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('-F TEST_VIRUS_FLOOD')
|
|
self.anim = anim('\tFiltrage virus et floods')
|
|
|
|
ip_vers = ('65.19.154.90', '208.72.168.52', '66.109.25.121', '193.37.152.88', '89.149.202.101')
|
|
for ip in ip_vers:
|
|
iptables('-A TEST_VIRUS_FLOOD -s %s -j LOG_VIRUS' % ip)
|
|
iptables('-A TEST_VIRUS_FLOOD -d %s -j LOG_VIRUS' % ip)
|
|
|
|
for proto, ports in self.ports_virus.items() :
|
|
for port in ports :
|
|
iptables('-A TEST_VIRUS_FLOOD -p %s --dport %s -j LOG_VIRUS' % (proto, port) )
|
|
self.anim.cycle()
|
|
|
|
iptables('-A TEST_VIRUS_FLOOD %s -j RETURN' % self.filtre_flood) # Les limites en négatif ca ne marche pas.
|
|
self.anim.cycle()
|
|
iptables('-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
|
|
# Attention les règles sont à l'envers. Hint '-I'
|
|
iptables("-I EXT_VERS_SERVEURS -p tcp --dport ssh -m state --state NEW\
|
|
-m recent --name SSH --update --seconds 60 --hitcount 4 --rttl -j DROP")
|
|
iptables("-I EXT_VERS_SERVEURS -p tcp --dport ssh -m state --state NEW\
|
|
-m recent --name SSH --set")
|
|
|
|
def crans_vers_ext(self) :
|
|
""" Reconstruit la chaîne CRANS_VERS_EXT """
|
|
self.build_chaine_adherent('CRANS_VERS_EXT',self.__crans_vers_ext)
|
|
# Protocole GRE pour les VPN
|
|
iptables("-I CRANS_VERS_EXT -p gre -j ACCEPT")
|
|
|
|
def ext_vers_crans(self) :
|
|
""" Reconstruit la chaîne EXT_VERS_CRANS """
|
|
self.build_chaine_adherent('EXT_VERS_CRANS',self.__ext_vers_crans)
|
|
# Attention les règles sont à l'envers. Hint '-I'
|
|
iptables("-I EXT_VERS_CRANS -p tcp --dport ssh -m state --state NEW -j ACCEPT")
|
|
iptables("-I EXT_VERS_CRANS -p tcp --dport ssh -m state --state NEW\
|
|
-m recent --name SSH --update --seconds 60 --hitcount 4 --rttl -j DROP")
|
|
iptables("-I EXT_VERS_CRANS -p tcp --dport ssh -m state --state NEW\
|
|
-m recent --name SSH --set")
|
|
|
|
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')
|
|
iptables('-t mangle -F BLACKLIST_SOFT')
|
|
|
|
# Peut-être à mettre dans config.py ?
|
|
blacklist_sanctions = ('upload', 'warez', 'p2p', 'autodisc_p2p', 'autodisc_upload', 'bloq')
|
|
blacklist_sanctions_soft = ('autodisc_virus','ipv6_ra','mail_invalide','virus',
|
|
'upload', 'warez', 'p2p', 'autodisc_p2p', 'autodisc_upload', 'bloq','carte_etudiant','chambre_invalide')
|
|
|
|
|
|
blacklist = []
|
|
blacklist_soft = []
|
|
|
|
# Recherche sur le champ ablacklist (clubs compris)
|
|
search = db.search('ablacklist=*&paiement=ok')
|
|
self.anim = anim("\tBlackliste adhérents+clubs", 2*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
|
|
for entite in search['adherent'] + search['club']:
|
|
self.anim.cycle()
|
|
sanctions = entite.blacklist_actif()
|
|
for s in blacklist_sanctions_soft:
|
|
if s in sanctions:
|
|
blacklist_soft.extend(entite.machines())
|
|
break
|
|
self.anim.reinit()
|
|
print OK
|
|
|
|
# Recherche sur le champ mblacklist
|
|
search = db.search('mblacklist=*&paiement=ok')
|
|
self.anim = anim("\tBlackliste machines", 2*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
|
|
for entite in search['machine']:
|
|
self.anim.cycle()
|
|
sanctions = entite.blacklist_actif()
|
|
for s in blacklist_sanctions_soft:
|
|
if s in sanctions:
|
|
blacklist_soft.append(entite)
|
|
break
|
|
self.anim.reinit()
|
|
print OK
|
|
|
|
self.anim = anim("\tChaînes BLACKLIST", 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
|
|
self.anim = anim("\tMarquage des machines pour blacklist soft", len(blacklist_soft))
|
|
for machine in blacklist_soft:
|
|
self.anim.cycle()
|
|
iptables("-t mangle -I BLACKLIST_SOFT -s %s -j MARK --set-mark %s" % (machine.ip(), conf_fw.mark['proxy']))
|
|
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')
|
|
iptables('-F TRACKER_FILTER')
|
|
|
|
# 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()
|
|
|
|
for filtre in self.filtres_p2p_bloq:
|
|
iptables('-A FILTRE_P2P -m ipp2p --%s -j LOG --log-prefix "IPP2P=%s "' % (filtre[0],
|
|
filtre[1]))
|
|
iptables('-A FILTRE_P2P -m ipp2p -m limit --%s --limit=%d/hour -j RETURN' % (filtre[0], p2p.limite[filtre[1]]/2))
|
|
iptables('-A FILTRE_P2P -m ipp2p --%s -j REJECT --reject-with icmp-admin-prohibited' % filtre[0])
|
|
self.anim.cycle()
|
|
#on rejetes les trackeur udp les plus connus
|
|
for tracker in self.udp_torrent_tracker.values():
|
|
for dest in tracker:
|
|
iptables('-A FILTRE_P2P -p udp -d %s --dport %s -j REJECT --reject-with icmp-admin-prohibited' % (dest[0],dest[1]))
|
|
|
|
#On log les requetes a des trackers torrents puis on les rejetes
|
|
iptables("-A TRACKER_FILTER -m string --algo kmp ! --string \"info_hash=\" -j ACCEPT")
|
|
iptables("-A TRACKER_FILTER -m string --algo kmp --string \"/scrape?\" -j LOG_TRACKER")
|
|
iptables("-A TRACKER_FILTER -m string --algo kmp ! --string \"peer_id=\" -j ACCEPT")
|
|
iptables("-A TRACKER_FILTER -m string --algo kmp ! --string \"port=\" -j ACCEPT")
|
|
iptables("-A TRACKER_FILTER -m string --algo kmp ! --string \"uploaded=\" -j ACCEPT")
|
|
iptables("-A TRACKER_FILTER -m string --algo kmp ! --string \"downloaded=\" -j ACCEPT")
|
|
iptables("-A TRACKER_FILTER -m string --algo kmp ! --string \"left=\" -j ACCEPT")
|
|
iptables("-A TRACKER_FILTER -j LOG_TRACKER")
|
|
|
|
#On analyse que les requetes http
|
|
iptables("-A FILTRE_P2P -i %s -p tcp -m string --algo kmp --string \"GET \" -j TRACKER_FILTER" % self.eth_int)
|
|
iptables("-A FILTRE_P2P -i %s -p tcp -m string --algo kmp --string \"get \" -j TRACKER_FILTER" % self.eth_int)
|
|
|
|
# fait bcp de faux positif, peux servir a detecter de nouveau trackers
|
|
iptables("-A FILTRE_P2P -i %s -p udp -m string --from 0 --to 65 --algo kmp --hex-string \"|4500002c00004000|\" -j LOG --log-level notice --log-prefix \"TRACKER_TORRENT: \"" % self.eth_int)
|
|
|
|
iptables('-A LOG_TRACKER -j LOG --log-level notice --log-prefix "TRACKER_TORRENT: "')
|
|
iptables('-A LOG_TRACKER -j REJECT --reject-with icmp-admin-prohibited')
|
|
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"
|
|
nfs_ports = ["111", "2049", "32765:32769"]
|
|
|
|
def serv_out_adm(self) :
|
|
self.anim = anim('\tOutput vers VLAN adm', len(adm_users))
|
|
# Supression des éventuelles règles
|
|
iptables("-t filter -F SERV_OUT_ADM")
|
|
|
|
for user in 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 fx.adm.crans.org -j ACCEPT")
|
|
iptables("-A SERV_OUT_ADM -d daath.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 -P PREROUTING ACCEPT")
|
|
iptables("-t nat -A PREROUTING -i lo -j ACCEPT")
|
|
|
|
iptables("-t nat -P PREROUTING ACCEPT")
|
|
print OK
|
|
|
|
def filter_table(self):
|
|
self.anim = anim('\tStructure de la table filter')
|
|
iptables('-t filter -N SERV_OUT_ADM')
|
|
iptables('-t filter -N TEST_MAC-IP')
|
|
iptables("-t filter -A OUTPUT -d 224.0.0.0/4 -j DROP")
|
|
|
|
# <!> à placer dans filter
|
|
#for net in NETs['fil'] + NETs['adm'] + NETs['wifi'] :
|
|
# iptables("-t nat -A PREROUTING -s %s -j TEST_MAC-IP" % net)
|
|
iptables("-t filter -A OUTPUT -d 10.231.136.1 -j SERV_OUT_ADM") # moche mais visiblement ont avait acces a l'interface adm de zamok depuis zamok
|
|
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 filter -P OUTPUT ACCEPT")
|
|
print OK
|
|
|
|
def start_fw_funcs(self) :
|
|
self.exception_catcher(self.test_mac_ip)
|
|
self.serv_out_adm()
|
|
|
|
def blacklist(self):
|
|
"""Fondamentalement, bloque l'accès internet sur zamok aux
|
|
adhérents sanctionnés"""
|
|
iptables("-F OUTPUT")
|
|
|
|
# Règles OUTPUT de nat_table() à remettre en place
|
|
iptables("-t filter -A OUTPUT -o lo -j ACCEPT")
|
|
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)
|
|
|
|
self.filter_table()
|
|
|
|
blacklist_sanctions = ('upload', 'warez', 'p2p', 'autodisc_p2p', 'autodisc_upload', 'bloq')
|
|
|
|
# Recherche sur le champ ablacklist (clubs compris)
|
|
search = db.search('ablacklist=*&paiement=ok')
|
|
self.anim = anim("\tBlackliste des comptes Crans", len(search['adherent']))
|
|
for adh in search['adherent']:
|
|
self.anim.cycle()
|
|
sanctions = adh.blacklist_actif()
|
|
for s in blacklist_sanctions:
|
|
if s in sanctions:
|
|
try:
|
|
uid = adh.uidNumber()
|
|
iptables("-A OUTPUT -m owner --uid-owner %s -d 127.0.0.1/8 -j ACCEPT" % uid)
|
|
iptables("-A OUTPUT -m owner --uid-owner %s -d 138.231.136.1/21 -j ACCEPT" % uid)
|
|
iptables("-A OUTPUT -m owner --uid-owner %s -d 138.231.144.1/21 -j ACCEPT" % uid)
|
|
iptables("-A OUTPUT -m owner --uid-owner %s -j REJECT" % uid)
|
|
finally:
|
|
break
|
|
self.anim.reinit()
|
|
print OK
|
|
|
|
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_redisdead(firewall_crans) :
|
|
"""
|
|
Structure du firewall :
|
|
table filter :
|
|
TEST_MAC-IP pour les paquets en INPUT
|
|
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 = "eth1"
|
|
|
|
def filter_table(self) :
|
|
self.anim = anim('\tStructure de la table filter')
|
|
iptables('-N TEST_MAC-IP')
|
|
for net in NETs['fil'] + NETs['wifi']:
|
|
iptables("-A INPUT -s %s -i %s -j TEST_MAC-IP" % (net, self.eth_pub))
|
|
for net in NETs['adm']:
|
|
iptables("-A INPUT -s %s -i %s -j TEST_MAC-IP" % (net, self.eth_adm))
|
|
iptables("-P INPUT ACCEPT")
|
|
iptables("-P OUTPUT ACCEPT")
|
|
print OK
|
|
|
|
def filter_table_tweaks(self) :
|
|
self.anim = anim('\tRègles spécifiques à redisdead')
|
|
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['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_sable(firewall_redisdead):
|
|
"""Comme pour rouge, avec le proxy transparent en plus"""
|
|
|
|
def filter_table_tweaks(self) :
|
|
iptables("-P INPUT ACCEPT")
|
|
iptables("-P FORWARD DROP")
|
|
for ip in accueil_route.keys():
|
|
for port in accueil_route[ip]:
|
|
iptables("-A FORWARD -p tcp -d %s --dport %s -j ACCEPT" % (ip,port))
|
|
iptables("-A FORWARD -p tcp -s %s --sport %s -j ACCEPT" % (ip,port))
|
|
|
|
def mangle_table(self):
|
|
iptables("-t mangle -F PREROUTING")
|
|
|
|
# Pour le transparent
|
|
iptables("-t mangle -i eth0.2 -A PREROUTING -p tcp --destination-port 3128 " +
|
|
"--destination 10.231.136.9 " +
|
|
"-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_redisdead.nat_table(self)
|
|
# Proxy transparent pour le filiaire
|
|
iptables("-t nat -A PREROUTING -i eth0.2 -m mark --mark %s -j ACCEPT" % conf_fw.mark['proxy'])
|
|
if_defaut = "eth0"
|
|
if_radin = "eth0.%d" % vlans["radin"]
|
|
if_accueil = "eth0.%d" % vlans["accueil"]
|
|
if_isolement = "eth0.%d" % vlans["isolement"]
|
|
|
|
#intranet et wiki pour le vlan accueil
|
|
for ip in accueil_route.keys():
|
|
for port in accueil_route[ip]:
|
|
iptables("-t nat -A PREROUTING -i eth0.7 -p tcp -d %s --dport %s -j ACCEPT" % (ip,port))
|
|
iptables("-t nat -A POSTROUTING -p tcp -s %s -d %s --dport %s -j MASQUERADE" % (NETs['accueil'][0],ip,port))
|
|
|
|
# Proxy transparent pour le wifi
|
|
iptables("-t nat -A PREROUTING -i %s -p tcp --dport 80" %if_defaut +
|
|
" -d ! 138.231.136.0/24 -j DNAT --to-destination" +
|
|
" 138.231.136.9:3128")
|
|
|
|
# Proxy transparent pour les vlans radin et accueil
|
|
for interface in [if_accueil, if_isolement]:
|
|
iptables("-t nat -i %s -A PREROUTING -p tcp --destination-port 80 -j DNAT --to-destination 10.51.0.1:3128" % interface)
|
|
iptables("-t nat -i %s -A PREROUTING -p tcp --destination-port 3128 -j ACCEPT" % interface)
|
|
iptables("-t nat -i %s -A PREROUTING -p tcp --destination-port 443 -j ACCEPT" % interface)
|
|
|
|
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/netfilter/ip_conntrack_max' ] :
|
|
status,output=getstatusoutput(cmd)
|
|
if status :
|
|
warn += output + '\n'
|
|
if warn :
|
|
print WARNING
|
|
if self.debug :
|
|
print warn
|
|
else :
|
|
print OK
|
|
|
|
firewall_bleu = firewall_zamok
|
|
|
|
"""
|
|
Gordon
|
|
"""
|
|
|
|
class firewall_gordon(firewall_crans) :
|
|
"""
|
|
Structure du firewall :
|
|
table nat :
|
|
table filter :
|
|
MAC-IP
|
|
FORWARD (policy par défaut : ACCEPT)
|
|
INPUT (policy par défaut : ACCEPT)
|
|
table mangle :
|
|
POSTROUTING : le proxy transparent
|
|
|
|
"""
|
|
|
|
# interfaces physiques
|
|
eth_crans = "eth0"
|
|
eth_wifi = "eth0.3"
|
|
|
|
def filter_table(self) :
|
|
self.anim = anim('\tStructure de la table filter')
|
|
iptables('-t filter -N TEST_MAC-IP')
|
|
|
|
iptables("-t filter -P FORWARD ACCEPT")
|
|
iptables("-t filter -A FORWARD -i lo -j ACCEPT")
|
|
iptables("-t filter -A FORWARD -d 224.0.0.0/4 -j DROP")
|
|
|
|
for net in NETs['fil'] + NETs['adm'] + NETs['wifi'] :
|
|
iptables("-t filter -A FORWARD -s %s -j TEST_MAC-IP" % net)
|
|
|
|
iptables("-t filter -P FORWARD ACCEPT")
|
|
iptables("-t filter -P OUTPUT ACCEPT")
|
|
print OK
|
|
|
|
def filter_table_tweaks(self) :
|
|
self.anim = anim('\tRègles spécifiques à gordon')
|
|
iptables("-P INPUT ACCEPT")
|
|
iptables("-P FORWARD ACCEPT")
|
|
print OK
|
|
|
|
def mangle_table(self):
|
|
self.anim = anim('\tRègles spécifiques à gordon')
|
|
#~ iptables("-t mangle -A PREROUTING " +
|
|
#~ "-d ! 138.231.136.0/21 " +
|
|
#~ ("-i %s " % self.eth_wifi) +
|
|
#~ "-p tcp -m tcp --dport 80 " +
|
|
#~ "-j MARK --set-xmark %s/0xffffffff" % conf_fw.mark['proxy'])
|
|
print OK
|
|
|
|
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/netfilter/ip_conntrack_max' ] :
|
|
status,output=getstatusoutput(cmd)
|
|
if status :
|
|
warn += output + '\n'
|
|
if warn :
|
|
print WARNING
|
|
if self.debug :
|
|
print warn
|
|
else :
|
|
print OK
|
|
|
|
|
|
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','reload_qos' ] :
|
|
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 )
|