En raison de la complexité à manipuler les règles iptables
dans un script
shell, on a décidé de doter bulbe (et
ensuite les nœuds Tor) d'un pare-feu à l'interface un peu moins rustique,
les contraintes principales étant:
- le support pour IPv6
- la possibilité de modifier le comportement du pare-feu à l'aide d'une commande et/ou de fichiers de configuration simples.
Parmi les candidats, c'est ferm qui a été retenu et installé.
Fichiers
/etc/default/ferm
- Ce fichier est sourcé par le script de démarrage. Ses valeurs par défaut conviennent dans la plupart des cas.
/etc/ferm/ferm.conf
- Il s'agit du fichier de configuration principal, celui qu'il faut modifier
pour obtenir un réglage sur mesure. D'autres fichiers peuvent être créés
dans ce répertoire et appelés à partir du fichier principal à l'aide de la
directive
@include 'fichier.ferm';
par exemple. /etc/ferm/*.ferm
- Fichiers de configuration pouvant être appelés depuis
ferm.conf
au moyen de la fonction interne@include fichier.ferm
. Ces fichiers peuvent par exemple contenir des fonctions un peu longues qu'on ne veut pas mettre dans le fichier principal pour des raisons de lisibilité, ou des définitions de variables dont la valeur est spécifique à l'hôte, etc. /usr/share/doc/ferm/examples/*.ferm
- Exemples de fichiers de configuration complets et pouvant être utilisés
tels quels, en fonction de l'utilisation de la machine (workstation,
fileserver, dmz_router, etc). Un exemple intéressant est
antiddos.ferm
.
Configuration
Le fichier /etc/ferm/ferm.conf
est en fait un script. ferm
n'est ni plus
ni moins qu'un langage interprété par un programme lui-même écrit en Perl,
et adapté à sa tâche: la simplification de l'écriture de règles complexes
pour netfilter.
Politique
bulbe.nos-oignons.net
- Trafic entrant (chaîne
INPUT
) - Configuration en liste blanche: tout ce qui n'est pas explicitement
autorisé est interdit et mis silencieusement à la poubelle (
DROP
).
Le trafic autorisé est celui qui permet d'accéder aux services de bulbe et le traffic ICMP (incluantping
). - Les services exposés le sont au travers d'un filtre limitant le nombre de connexions par seconde et par client.
- Configuration en liste blanche: tout ce qui n'est pas explicitement
autorisé est interdit et mis silencieusement à la poubelle (
- Trafic sortant (chaîne
OUTPUT
) - Actuellement tout est autorisé en sortie, à l'exception des paquets invalides (le plus souvent en raison d'un débordement de la mémoire, ou d'erreurs ICMP).
- Trafic redirigé (chaîne
FORWARD
) - Aucun trafic ne peut être redirigé.
Nœuds Tor
- Mode stateless
- Afin de ne pas surcharger le noyau, on ne tient pas compte du critère temporel dans le filtrage des paquets.
- Trafic entrant (chaîne
INPUT
) - Configuration en liste noire: tout ce qui n'est pas explicitement interdit est autorisé.
- Sur le port SSH, un ensemble restreint d'adresses IP est autorisé.
- Trafic sortant (chaîne
OUTPUT
) - Tout est autorisé.
- Trafic redirigé (chaîne
FORWARD
) - Aucun trafic ne peut être redirigé.
Moyens
Ferm(8) est scriptable. Il offre la possibilité d'utiliser et de combiner entre eux:
- des blocs et sous-blocs imbriqués (
{... {...} }
) - des ensembles associatifs, ou arrays (
domain (ip ip6) protocol (tcp udp)...
) - des structures de contrôle conditionnelles (
@if... @else...
) - des variables prédéfinies (
$DOMAIN
,$CHAIN
) - des variables de l'user (
@def $FOOBAR = ...;
) - des fonctions internes (
@resolve(adresse.com)
,@basename(path)
) - des fonctions de l'user (
@def &FOOBAR(a, b) = {...}
) - des substitutions de commandes du shell
De ce point de vue, il est facile à prendre en main, et permet d'écrire à peu
de frais des règles faciles à maintenir. Par exemple, domain (ip ip6) {...}
permet d'écrire un ensemble de règles pour IPv4 et IPv6, et une
modification de ces règles sera prise en compte par les deux protocoles, ce
qui permet de rester toujours homogène.
Configuration avancée
Déni de service
Sur le trafic entrant, plusieurs règles dites anti déni de service sont appliquées sur les ports ssh (22), http (80) et https (443), domain (53), smtp (25).
Elles font appel au module recent
dont le but est de garder en mémoire
des informations sur les paquets précédents (nombre, provenance, timestamp)
de manière à pouvoir appliquer une politique particulière aux nouveaux
paquets en fonction des informations recueillies sur leurs prédécesseurs.
Concrètement, sur bulbe, cela donne:
Si plus de N
paquets en provenance d'une même IP ont été traités en t
secondes, alors on refuse les suivants (en provenance de cette même IP)
pendant un temps T
. Si un paquet se présente durant cette période de
bannissement, non seulement il est jeté à la poubelle, mais la période
de bannissement T
est réinitialisée. Ainsi les paquets en provenance de
l'IP bannie ne peuvent être acceptés qu'après un temps de silence complet
au moins égal à T
, ce qui rend très difficile pour un attaquant de
savoir quand il peut revenir à la charge.
Pour pouvoir utiliser ce type de règles avec des valeurs de N
assez
élevées, appliquées à suffisamment d'IP différentes pour oser parler de
déni de service distribué, il a aussi été nécessaire de modifier les
paramètres ip_list_tot
et ip_pkt_list_tot
du module recent
(dont
les valeurs par défaut sont respectivement 100
et 20
), en créant un
fichier /etc/modprobe.d/xt_recent.conf
avec le contenu suivant:
options xt_recent ip_list_tot=8096 ip_pkt_list_tot=128
Les commandes qui vont bien
sudo ferm --interactive /home/libellule/test.ferm
Permet d'appliquer les règles de /home/libellule/test.ferm
et ensuite seulement,
de demander confirmation. Si cette confirmation n'est pas obtenue dans
les trente secondes, ferm revient aux règles précédentes. C'est pratique
quand les règles qu'on veut tester risquent de nous laisser enfermés
dehors.
sudo ferm --noexec --lines --slow /home/libellule/test.ferm
Permet de vérifier la validité (syntaxique) du script donné en argument et
d'afficher l'ensemble des commandes iptables
et ip6tables
correspondantes.
sudo service ferm restart
Permet d'actualiser les règles après une modification d'un fichier de configuration.