From 3ac1a04e06130e37489cd6a8a2282572d5372b11 Mon Sep 17 00:00:00 2001 From: Olivier Huber Date: Fri, 26 Feb 2010 04:47:36 +0100 Subject: [PATCH] =?UTF-8?q?[gestion/gen=5Fconfs/firewall6.py]=20Ajout=20du?= =?UTF-8?q?=20script=20de=20g=C3=A9n=C3=A9ration=20du=20firewall=20ipv6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Le principe de la génération est que l'on applique des règles de base (principalement la correspondance MAC_IP) et ensuite suivant les attributs des serveurs qui sont définis dans config.py on exécute certaines fonctions. Il reste encore pas mal de fonctionnalités à coder pour que cela s'exécute sur tous les serveurs, mais la base est là et fonctionnelle. Il est prévu à moyen-terme (au niveau de la rentrée 2010) d'avoir un script pour la génération du firewall en ipv4. Une revue de code serait là aussi appréciée. darcs-hash:20100226034736-8fbb1-83545cbb9fab36be081da20b0c654d5aacffc7df.gz --- gestion/gen_confs/firewall6.py | 289 +++++++++++++++++++++++++++++++++ 1 file changed, 289 insertions(+) create mode 100755 gestion/gen_confs/firewall6.py diff --git a/gestion/gen_confs/firewall6.py b/gestion/gen_confs/firewall6.py new file mode 100755 index 00000000..bf361203 --- /dev/null +++ b/gestion/gen_confs/firewall6.py @@ -0,0 +1,289 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# +# FIREWALL6.PY -- Gestion du firewall pour l'ipv6 +# +# Copyright (C) 2010 Olivier Huber +# Authors: Olivier Huber +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + + +import sys, re, os, pwd + +sys.path.append('/usr/scripts/gestion') + +from ldap_crans import hostname +from config import conf_fw, mid, prefix, role, file_pickle +from config import authorized_icmpv6 +from ipt import * + +# On invoque Ip6tables +ip6tables = Ip6tables() + +def aide(): + ''' Affiche l'aide pour utiliser le script''' + print """ +Usage: +%(script)s start : Démarrage du firewall +%(script)s stop : Arrêt du firewall +%(script)s restart : Redémarrage du firewall +""" % { 'script' : sys.argv[0].split('/')[-1] } + + +def ports(dev_ip6, dev_crans): + ''' Ouvre les ports ''' + for machine in machines : + for type_machine in ['fil', 'fil-v6', 'wifi', 'wifi-v6']: + if int(machine.id()) in range(mid[type_machine][0], + mid[type_machine][1]): + ports_io(ip6tables, machine, type_machine, dev_ip6, dev_crans) + + #Protection contre les attaques brute-force + # XXX FIXIT !!! + # Il semble qu'il faille un kernel >= .29 et iptables >= 1.4.3 + # http://netfilter.org/projects/iptables/files/changes-iptables-1.4.3.txt + +# ip6tables.filter.forward('-i %s -p tcp --dport ssh -m state --state NEW -m \ +#recent --name SSH --set ' % dev_ip6) +# ip6tables.filter.forward('-i %s -p tcp --dport ssh -m state --state NEW -m \ +#recent --name SSH --update --seconds 60 --hitcount 4 --rttl -j DROP' % +# dev_ip6) +# ip6tables.filter.forward('-i %s -p tcp --dport ssh -m state --state NEW \ +#-j ACCEPT' % dev_ip6) + + + for type_machine in ['fil', 'fil-v6', 'wifi', 'wifi-v6']: + ip6tables.filter.forward('-i %s -d %s -j %s' % (dev_ip6, + prefix[dprefix[type_machine]][0], 'EXT' + re.sub('-', '', + type_machine.upper()))) + eval('ip6tables.filter.ext' + re.sub('-', '', type_machine))('-j \ +REJECT --reject-with icmp6-port-unreachable') + + # Port ouvert CRANS->EXT + ip6tables.filter.forward('-i %s -p udp -m multiport --dports \ +0:136,140:65535 -j ACCEPT' % dev_crans) + ip6tables.filter.forward('-i %s -p tcp -m multiport --dports \ +0:24,26:79,81:134,136,140:444,446:65535 -j ACCEPT' % dev_crans) + + for type_machine in ['fil', 'fil-v6', 'wifi', 'wifi-v6']: + ip6tables.filter.forward('-i %s -s %s -j %s' % (dev_crans, + prefix[dprefix[type_machine]][0], 'CRANS' + re.sub('-', '', + type_machine.upper()))) + eval('ip6tables.filter.crans' + re.sub('-', '', type_machine))('-j \ +REJECT --reject-with icmp6-port-unreachable') + + + + +def basic_fw(): + ''' Met en place un firewall de base commun à tous les serveurs''' + # On rejete les ra. + ip6tables.filter.input('-p icmpv6 -m icmp6 --icmpv6-type \ +router-advertisement -j DROP') + + # Correspondance MAC-IP + mac_ip(ip6tables, machines, ['fil', 'fil-v6', 'adm']) + +#wifi ? + +def main_router(): + ''' Firewall pour le router principal ''' + + #TODO : réseaux non routable, interaction avec generate + # il faut aussi voir les conditions pour passer la ctstate avant MAC-IP + # (normalement, il n'y a pas de problèmes. + # et peut être aussi avant blackliste (il faut prévoir un script qui + # enlève les entrées dans la conntract lors de la mise en place de la + # blackliste + + # route pour le proxy transparent + # Pour plus tard +# custom_default_route('proxy', ip_attribut('main-proxy', cl, 6), 'fil', 6) +# custom_mark_rule('proxy', conf_fw.mark['proxy'], 6) +# ip6tables.mangle.prerouting("-p tcp -d ! %s --dport 80 -j MARK --set-mark\ +# %s" % (prefix['fil'][0], conf_fw.mark['proxy'])) +# + dev_crans = iface6('fil') + dev_ip6 = iface6('sixxs2') + + # Les blacklistes + blacklist(ip6tables) + ip6tables.filter.forward('-o %s -j BLACKLIST_SRC' % dev_ip6) + ip6tables.filter.forward('-i %s -j BLACKLIST_DST' % dev_ip6) + + ip6tables.filter.forward('-m conntrack --ctstate RELATED,ESTABLISHED -j \ +ACCEPT') + + # Pour les autres connections + for type_m in [i for i in ['fil', 'fil-v6'] if not 'v6' in i]: + ip6tables.filter.mac('-s %s -j %s' % (prefix[type_m][0], 'MAC' + + type_m.upper())) + ip6tables.filter.forward('-i %s -j MAC' % dev_crans) + ip6tables.filter.forward('-i %s -j FEUI64' % dev_crans) + ip6tables.filter.feui64('-s %s -m eui64 -j RETURN' % prefix['fil'][0]) + ip6tables.filter.feui64('-j DROP') + + # Rien ne passe vers adm + # est ce que du local est gêné par le règle ? + ip6tables.filter.forward('-d %s -j REJECT --reject-with \ +icmp6-addr-unreachable' % (prefix['adm'][0])) + + # on accepte les ping + for icmpv6 in authorized_icmpv6: + ip6tables.filter.forward('-p icmpv6 -m icmp6 --icmpv6-type %s -j \ +ACCEPT' % icmpv6) + + # Ouverture des ports + ports(dev_ip6, dev_crans) + + # On met en place le forwarding + enable_forwarding(6) + +def wifi_router(): + ''' Firewall pour le router du wifi ''' +# pour plus tard +# custom_default_route('proxy', ip_attribut('main-proxy', cl, 6), 'wifi', 6) +# custom_mark_rule('proxy', conf_fw.mark['proxy'], 6) +# ip6tables.mangle.prerouting("-p tcp -d ! %s --dport 80 -j MARK --set-mark \ +#%s" % (prefix['fil'][0], conf_fw.mark['proxy'])) + dev_crans = iface6('fil') + dev_wifi = iface6('wifi') + + # Stop aux RA + ip6tables.filter.forward('-p icmpv6 -m icmp6 --icmpv6-type \ + router-advertisement -j DROP') + + mac_ip(ip6tables, machines, ['wifi', 'wifi-v6']) + + for type_m in [i for i in ['fil', 'fil-v6', 'wifi', 'wifi-v6'] + if not 'v6' in i]: + ip6tables.filter.mac('-s %s -j %s' % (prefix[type_m][0], 'MAC' + + type_m.upper())) + ip6tables.filter.feui64('-s %s -m eui64 -j RETURN' + % prefix[type_m][0]) + + ip6tables.filter.forward('-j MAC') + ip6tables.filter.forward('-j FEUI64') + + ip6tables.filter.feui64('-j DROP') + + # On met en place le forwarding + enable_forwarding(6) + +#def main_proxy(): + +def adherents_server(): + ''' Firewall pour le serveur des adhérents ''' + + dev_adm = iface6('adm') + # On fait attention à ce qui sort + ip6tables.filter.output('-i lo -j ACCEPT') + ip6tables.filter.output('-m conntrack --ctstate RELATED,ESTABLISHED -j \ +ACCEPT') + ip6tables.filter.output('-i %s -j SRV_OUT_ADM', dev_adm) + + # Chaîne SRV_OUT_ADM + # Seul certains users ont le droit de communiquer sur le vlan adm + for user in adm_users: + try: + u_uid = pwd.getpwnam(user)[2] + except KeyError: + raise UnknowUserError(user) + ip6tables.filter.srv_out_adm('-m owner --uid-owner %d -j ACCEPT' % + pwd.getpwnam(user)[2]) + + # LDAP et DNS toujours joignable + ip6tables.filter.srv_out_adm('-p tcp --dport ldap -j ACCEPT') + ip6tables.filter.srv_out_adm('-p tcp --dport domain -j ACCEPT') + ip6tables.filter.srv_out_adm('-p udp --dport domain -j ACCEPT') + # Pour le nfs (le paquet à laisser passer n'a pas d'owner) + ip6tables.filter.srv_out_adm('-d nfs.adm.crans.org -m owner ! \ +--uid-owner 0 -j REJECT --reject-with icmp-net-prohibited') + ip6tables.filter.srv_out_adm('-d nfs.adm.crans.org -j ACCEPT') + + # On arrête tout + ip6tables.filter.srv_out_adm('-j REJECT --reject-with icmp-net-prohibited') + +def start(): + ''' Démarre le firewall sur la machine considérée ''' + # On rempli machines + global machines + machines = db.all_machines(graphic = True) + print hostname + + # On supprime les anciennes règles si elles existent. + try: + os.remove(output_file[6]) + os.remove(file_pickle[6]) + except: + pass + + # On met en place le firewall basique + basic_fw() + + # On recherche si la machine a des attributs particuliers. + if hostname in role.keys(): + for func in role[hostname]: + eval(re.sub('-', '_', func))() + + # On écrit les données dans un fichier + write_rules(ip6tables) + + # On les applique + apply_rules(6) + + # Sauvegarde de l'instance + save_pickle(ip6tables) + return 0 + +def stop(): + ''' Vide les tables ''' + # TODO + # il manque une gestion des règles de routage spéciales réalisées à + # l'aide de ip rule et ip route + # idée faire une classe et la stocker en pickle pour savoir ce qui a été + # ajouté + + + # On fixe comme règle juste les déclarations de police par défaut + write_rules(ip6tables) + + # On les applique + apply_rules(6) + + disable_forwarding(6) + + return 0 + +def restart(): + ''' Redémarre le firewall ''' + # On ôte toutes les règles + stop() + + # On met les règles en place + start() + + return 0 + +if __name__ == '__main__': + if len(sys.argv) != 2: + aide() + sys.exit(-1) + + if sys.argv[1] in [ 'start', 'stop', 'restart' ]: + eval(sys.argv[1])() + else: + aide() + sys.exit(-1)