Commit 703bf964 authored by Valentin Samir's avatar Valentin Samir
Browse files

[firewall4, generate] Documentation

parent fcda8784
......@@ -4,7 +4,7 @@
""" Variables de configuration pour le firewall """
import datetime
#: Interfaces réseaux des machines ayant un pare-feu particulié
dev = {
'komaz': {
'out' : 'ens',
......@@ -51,12 +51,13 @@ else:
#: Est-ce qu'on est en connexion de jour ou de nuit/week-end ?
debit_jour = False
#: Liste des réseaux non routables
reseaux_non_routables = [ '10.0.0.0/8', '172.16.0.0/12','198.18.0.0/15',
'169.254.0.0/16', '192.168.0.0/16', '224.0.0.0/4', '100.64.0.0/10',
'0.0.0.0/8','127.0.0.0/8','192.0.2.0/24','198.51.100.0/24','203.0.113.0/24',
]
#: Ports ouverts à défaut pour les adhérents dans le pare-feu
ports_default = {
'tcp' : {
'input' : [ '22' ],
......
......@@ -7,11 +7,6 @@ import sys
sys.path.append('/usr/scripts/gestion')
sys.path.append('/usr/scripts/lc_ldap')
if os.getuid() != 0:
from affich_tools import coul
sys.stderr.write(coul("Il faut être root pour utiliser le firewall\n", 'gras'))
sys.exit(1)
from config import NETs, blacklist_sanctions, blacklist_sanctions_soft, mac_komaz, mac_titanic, adm_users, accueil_route
import pwd
......@@ -26,15 +21,21 @@ from affich_tools import anim, OK, cprint
squeeze = os.uname()[2] < '3'
#: Connection à labase ldap
conn = lc_ldap.lc_ldap_admin()
#: Nom de la machine exécutant le script
hostname = socket.gethostname()
#: Chaines par défaut d'iptables
default_chains = ['INPUT', 'OUTPUT', 'FORWARD', 'PREROUTING', 'POSTROUTING']
#: Tables d'iptables
tables = ['raw', 'mangle', 'filter', 'nat']
#: Association des interfaces de ``hostname``
dev = hostname in config.firewall.dev.keys() and config.firewall.dev[hostname] or {}
def pretty_print(table, chain):
"""Affiche quelle chaine est en train d'être construite dans quelle table de NetFilter"""
anim('\t%s dans %s' % (chain, table))
......@@ -61,14 +62,17 @@ def tc(cmd, block=True):
return stdoutdata + stderrdata
class firewall_base(object) :
"""Classe de base du pare-feu implémentant l'association mac-ip (pour les machines filaires) et les blacklists hard"""
def machines(self):
"""Renvois la liste de toutes les machines"""
if self._machines:
return self._machines
self._machines, self._adherents = conn.allMachinesAdherents()
return self._machines
def adherents(self):
"""Renvois la liste de tous les adhérents"""
if self._adherents:
return self._adherents
self._machines, self._adherents = conn.allMachinesAdherents()
......@@ -76,6 +80,7 @@ class firewall_base(object) :
return self._adherents
def blacklisted_machines(self):
"""Renvois la liste de toutes les machines ayant une blackliste actives"""
if self._blacklisted_machines:
return self._blacklisted_machines
if self._machines:
......@@ -93,18 +98,21 @@ class firewall_base(object) :
return self._blacklisted_machines
def blacklisted_adherents(self):
"""Renvois la liste de tous les adhérents ayant une blackliste active"""
if self._blacklisted_adherents:
return self._blacklisted_adherents
self._blacklisted_adherents = filter(lambda adh: adh.blacklist_actif(), self.adherents())
return self._blacklisted_adherents
def add(self, table, chain, rule):
"""Ajoute la règle ``rule`` à la chaine ``chain`` dans la table ``table``"""
if not chain in self.chain_list[table]:
self.chain_list[table].append(chain)
self.rules_list[table][chain]=[]
self.rules_list[table][chain].append(rule)
def delete(self, table=None, chain=None):
"""Supprime ``chain`` de ``table`` si fournis, sinon supprime ``table``, sinon toutes les tables"""
if not table:
for table in tables:
self.delete(table, chain)
......@@ -121,6 +129,8 @@ class firewall_base(object) :
self.rules_list[table][chain]=[]
def flush(self, table=None, chain=None):
"""Vide ``chain`` dans ``table`` si fournis, sinon vide toutes
les chaines de ``table``, sinon vide toutes les chaines de toutes les tables"""
if not table:
for table in tables:
self.flush(table, chain)
......@@ -132,6 +142,9 @@ class firewall_base(object) :
self.rules_list[table][chain]=[]
def restore(self, table=None, chains=[], noflush=False):
"""Restores les règles du pare-feu dans le noyau en appelant ``iptables-restore``.
Si ``table`` est fournis, on ne restore que table.
Si ``noflush`` n'est pas à ``True`` tout le contenu précédent est supprimé"""
str=self.format(chains)
f=open('/tmp/ipt_rules', 'w')
f.write(str)
......@@ -146,12 +159,14 @@ class firewall_base(object) :
p.communicate(input=str)
def apply(self, table, chain):
"""Applique les règles de ``chain`` dans ``table``"""
if not chain in self.chain_list[table]:
return
self.restore(table, [chain], noflush=True)
self.delete(table, chain)
def format(self, chains=[]):
"""Transforme la structure interne des règles du pare-feu en celle comprise par ``iptables-restore``"""
str = ''
for table in self.chain_list.keys():
str += '*%s\n' % table
......@@ -167,6 +182,11 @@ class firewall_base(object) :
def __init__(self):
#initialisation des structures communes : récupération des ipset
if os.getuid() != 0:
from affich_tools import coul
sys.stderr.write(coul("Il faut être root pour utiliser le firewall\n", 'gras'))
sys.exit(1)
self.reloadable = {
'blacklist_hard' : self.blacklist_hard,
......@@ -210,7 +230,7 @@ class firewall_base(object) :
def start(self):
# On precache avant tout la liste des machines et des adhérents, on en aura besoin
"""Démarre le pare-feu : génère les règles, puis les restore"""
anim('\tChargement des machines')
self.machines()
print OK
......@@ -231,27 +251,32 @@ class firewall_base(object) :
return
def stop(self):
"""Vide les règles du pare-feu"""
fw.delete()
fw.restore()
return
def restart(self):
"""Alias de :py:func:`start`"""
self.start()
return
def blacklist_maj(self, ips):
"""Met à jours les blacklists pour les ip présentent dans la liste ``ips``"""
self.blacklist_hard_maj(ips)
def raw_table(self):
"""Génère les règles pour la table ``raw`` et remplis les chaines de la table"""
table = 'raw'
return
def mangle_table(self):
"""Génère les règles pour la table ``mangle`` et remplis les chaines de la table"""
table = 'mangle'
return
def filter_table(self):
"""Génère les règles pour la table ``filter`` et remplis les chaines de la table"""
table = 'filter'
mac_ip_chain = self.test_mac_ip(table, fill_ipset=True)
......@@ -271,6 +296,7 @@ class firewall_base(object) :
return
def nat_table(self):
"""Génère les règles pour la table ``nat`` et remplis les chaines de la table"""
table = 'nat'
return
......@@ -278,6 +304,7 @@ class firewall_base(object) :
def blacklist_hard_maj(self, ip_list):
"""Met à jour les blacklists hard, est appelée par :py:func:`blacklist_maj`"""
for ip in ip_list:
machine = conn.search("ipHostNumber=%s" % ip)
# Est-ce qu'il y a des blacklists hard parmis les blacklists de la machine
......@@ -289,6 +316,9 @@ class firewall_base(object) :
except IpsetError: pass
def blacklist_hard(self, table=None, fill_ipset=False, apply=False):
"""Génère la chaine ``BLACKLIST_HARD``.
Si ``fill_ipset`` est à ``True``, remplis l'ipset ``BLACKLIST-HARD``.
Si ``apply`` est à True, applique directement les règles"""
chain = 'BLACKLIST_HARD'
if fill_ipset:
......@@ -317,7 +347,7 @@ class firewall_base(object) :
return chain
def test_mac_ip_dispatch(self, func, machine):
"""Détermine à quel set de mac-ip appliquer la fonction func (add, delete, append, ...)"""
"""Détermine à quel set de mac-ip appliquer la fonction ``func`` (add, delete, append, ...)"""
ips = machine['ipHostNumber']
for ip in ips:
# Si la machines est sur le réseau des adhérents
......@@ -331,6 +361,9 @@ class firewall_base(object) :
func('adm', "%s,%s" % (ip, machine['macAddress'][0]))
def test_mac_ip(self, table=None, fill_ipset=False, apply=False):
"""Génère la chaine ``TEST_MAC-IP``.
Si ``fill_ipset`` est à ``True``, remplis les ipsets ``MAC-IP-ADH``, ``MAC-IP-ADM``, ``MAC-IP-ADM``.
Si ``apply`` est à True, applique directement les règles"""
chain = 'TEST_MAC-IP'
if fill_ipset:
......@@ -369,6 +402,7 @@ class firewall_base(object) :
return chain
def mac_ip_maj(self, ip_list):
"""Met à jour la correspondance mac-ip"""
for ip in ip_list:
machine = conn.search("ipHostNumber=%s" % ip)
if machine:
......@@ -523,6 +557,7 @@ class firewall_komaz(firewall_base):
return
def clamp_mss(self, table=None, apply=False):
"""Force la MSS (Max Segment Size) TCP à rentrer dans la MTU (Max Transfert Unit)"""
chain = 'CLAMP-MSS'
if table == 'mangle':
pretty_print(table, chain)
......@@ -535,10 +570,8 @@ class firewall_komaz(firewall_base):
return chain
def ingress_filtering(self, table=None, apply=False):
"""
Pour ne pas router les paquêtes n'appartenant pas à notre plage ip voulant sortir de notre réseau
et empêcher certain type de spoof (cf http://travaux.ovh.net/?do=details&id=5183)
"""
"""Pour ne pas router les paquêtes n'appartenant pas à notre plage ip voulant sortir de notre réseau
et empêcher certain type de spoof (cf http://travaux.ovh.net/?do=details&id=5183)"""
chain = 'INGRESS_FILTERING'
if table == 'filter':
pretty_print(table, chain)
......@@ -559,6 +592,7 @@ class firewall_komaz(firewall_base):
return chain
def ssh_on_https(self, table=None, apply=False):
"""Pour faire fonctionner ssh2.crans.org"""
chain = 'SSH2'
if table == 'nat':
......@@ -572,6 +606,7 @@ class firewall_komaz(firewall_base):
return chain
def connexion_secours(self, table=None, apply=False):
"""Redirige les paquets vers un proxy lorsqu'on est en connexion de secours"""
chain = 'CONNEXION-SECOURS'
if table == 'mangle':
......@@ -596,6 +631,7 @@ class firewall_komaz(firewall_base):
return chain
def connexion_appartement(self, table=None, apply=False):
"""PNAT les appartements derrière appartement.crans.org"""
chain = 'CONNEXION-APPARTEMENT'
if table == 'nat':
......@@ -628,6 +664,7 @@ class firewall_komaz(firewall_base):
except IpsetError: pass
def blacklist_soft(self, table=None, fill_ipset=False, apply=False):
"""Redirige les gens blacklisté vers le portail captif"""
chain = 'BLACKLIST_SOFT'
if fill_ipset:
......@@ -670,6 +707,7 @@ class firewall_komaz(firewall_base):
return chain
def reseaux_non_routable(self, table=None, fill_ipset=False, apply=False):
"""Bloque les réseaux non routables autres que ceux utilisés par le crans"""
chain = 'RESEAUX_NON_ROUTABLES'
if fill_ipset:
......@@ -695,6 +733,7 @@ class firewall_komaz(firewall_base):
self.filtrage_ports('filter', apply=True)
def filtrage_ports(self, table=None, apply=False):
"""Ouvre les ports vers et depuis les machines du réseau crans"""
chain = 'FILTRAGE-PORTS'
def format_port(port):
......@@ -745,6 +784,7 @@ class firewall_komaz(firewall_base):
return chain
def limitation_debit(self, table=None, run_tc=False, apply=False):
"""Limite le débit de la connexion selon l'agréement avec l'ENS"""
chain = 'LIMITATION-DEBIT'
debit_max = config.firewall.debit_max
......@@ -896,7 +936,8 @@ class firewall_zamok(firewall_base):
print OK
def blacklist_output(self, table=None, apply=False):
chain='BLACKLIST'
"""Empêche les gens blacklisté d'utiliser zamok comme relaie"""
chain='BLACKLIST-OUTPUT'
if table == 'filter':
self.add(table, chain, '-d 127.0.0.1/8 -j ACCEPT')
......@@ -954,6 +995,7 @@ class firewall_routeur(firewall_base):
return
def portail_captif_route(self, table=None, apply=False):
"""PNAT les (ip,port) à laisser passer à travers le portail captif"""
chain = 'CAPTIF-ROUTE'
if table == 'filter':
......@@ -979,6 +1021,7 @@ class firewall_routeur(firewall_base):
return chain
def portail_captif(self, table=None, apply=False):
"""Redirige vers le portail captif"""
chain = 'PORTAIL-CAPTIF'
if table == 'nat':
......
......@@ -4,14 +4,14 @@
# Copyright (C) Frdric Pauget
# Licence : GPLv2
"""Ce script permet de lancer la reconfiguration des divers services
Usage: %(prog)s options
Les options possibles sont :
\t%(options)s
Les options avec = doivent tre suivies d'un argument. Plusieurs
arguments peuvent tre founis pour une mme option, les sparer par &
"""
#"""Ce script permet de lancer la reconfiguration des divers services
#
#Usage: %(prog)s options
#Les options possibles sont :
#\t%(options)s
#Les options avec = doivent tre suivies d'un argument. Plusieurs
#arguments peuvent tre founis pour une mme option, les sparer par &
#"""
import sys, signal, os, getopt
......@@ -27,11 +27,6 @@ from syslog import *
import platform
openlog("generate")
# On vrifie que l'on est root
if os.getuid() != 0:
sys.stderr.write("Il faut tre root\n")
sys.exit(1)
signal.signal(signal.SIGINT, signal.SIG_IGN) # Pas de Ctrl-C
db = crans_ldap()
......@@ -73,6 +68,11 @@ class base_reconfigure:
def __init__(self, to_do=None):
# On vrifie que l'on est root
if os.getuid() != 0:
sys.stderr.write("Il faut tre root\n")
sys.exit(1)
if not to_do:
if debug:
print 'Lecture des services redmarrer dans la base LDAP...'
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment