[gestion/gen_confs/firewall6.py] Ajout du script de génération du firewall ipv6
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
This commit is contained in:
parent
e63dfbccd1
commit
3ac1a04e06
1 changed files with 289 additions and 0 deletions
289
gestion/gen_confs/firewall6.py
Executable file
289
gestion/gen_confs/firewall6.py
Executable file
|
@ -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 <huber@crans.org>
|
||||
#
|
||||
# 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 <http://www.gnu.org/licenses/>.
|
||||
|
||||
|
||||
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)
|
Loading…
Add table
Add a link
Reference in a new issue