Fidèle utilisateur de l’operating système FreeBSD pour toutes les fonctions réseaux (notamment les Firewall), je suis tombé il y a quelques temps sur un problème d’interopérabilité entre l’utilisation du couple CARP/PFSYNC (le truc pour faire de la redondance de Firewall) avec IPFW.
J’ai donc décidé de switcher de IPFW vers PF. Je vais donc abordé dans ce billet les quelques choses à avoir en tête si vous suivez le même chemin… Si vous souhaitez vous formez sur PF, je vous conseille la lecture de l’excellent article paru dans Linux Magazine HS n°29, dont vous trouverez une version électronique ici.
Un peu d’histoire
IPFW (IPFireWall) est un module logiciel permettant de faire du filtrage de paquets réseau sous BSD (c’est actuellement le module de firewall utilisé par défaut sous Mac OS X).
Jusqu’à la version 3.0 de OpenBSD, ce module était intégré par défaut au noyau du système, mais de sombres histoires de licences et de batailles interne entre Darren Reed (l’auteur de IPFW) et les développeurs d’OpenBSD ont débouché par son remplacement par PF (Packet Filter).
PF est maintenant fourni en standard sur l’OS FreeBSD (depuis la version 5.3).
Les principales différences entre IPFW et PF
Voici une liste non-exhaustive:
- le fichier de configuration unique (/etc/pf.conf) comprend, la définition des règles (comme sous IPFW) mais aussi la configuration du NAT et du PAT (délégué au processus IPNAT avec IPFW)
- comportement atomique du chargement de la configuration: si une erreur est détectée dans le fichier de configuration, aucune règle n’est appliquée
- l’interprétation des règles est de type “last matching rules wins”: la dernière règle qui correspond au paquet est appliquée
- le suivi de connexions complexes comme FTP se fait via un module externe (ftp-proxy)
- il est possible de rediriger les paquets en fonction de l’OS émetteur (ne marche pas dans tout les cas de figures)
- assure une compatibilité native avec CARP et PFSYNC pour faire de la redondance active de Firewall
Architecture du fichier de configuration /etc/pf.conf
Le fichier comporte plusieurs sections (l’ordre est important).
1) Définition des macros, listes et des tables
En plus des listes (comme sous IPFW), il est possible d’utiliser des tables pour stocker des adresses IP. L’avantage des tables par rapport aux listes est la rapidité d’accès à l’information. En effet, basées sur des tables de hachage, le temps pour accéder à une information est constant quel que soit la taille de la table. De plus il est possible de modifier dynamiquement ces tables (à l’aide de la commande “pfctl -t …”) sans avoir à recharger les règles.
Quelques exemples de macros:
Définition
ip_interne=”192.168.1.254”
ip_externe=”80.80.80.80”
Utilisation dans les règles
pass quick proto tcp from $ip_interne to any port 80
pass quick from $lan_interne to any keep state
Quelques exemples de listes:
Définition
lan_interne=”{ 192.168.1.0/24 192.168.2.0.24 }”
lan_interne_saufdmz=”{ 192.168.1.0/24 192.168.2.0.24 !192.168.2.0/29 }”
web_ports=”{ http https ftp }”
Utilisation dans les règles
pass quick from $lan_interne to any keep state
Quelques exemples de tables:
Définition
table <ip_clients> “{ 192.168.1.10 192.168.1.100 }”
Utilisation
pass quick from <ip_clients> to any keep state
Modification de la table
pfctl -t ip_clients -T add 192.168.1.101
pfctl -t ip_clients -T delete 192.168.1.101
2) Options et normalisation des paquets
Personnellement, j’utilise les options suivantes:
# On ne filtre pas sur l’interface locale
set skip on lo
# En cas de blocage, on envoie un RST sur les paquets TCP
# et UNREACHABLE sur les ICMP
set block-policy return
# On normalise les paquets avec gestion de la fragmentation
scrub in all fragment reassemble
3) Gestion des queues pour la QoS
Permet de faire de la qualité de service: CBQ, Priorité et HFSC. Il faut cependant passer par un module externe: altq.
Je reviendrai sûrement sur ces fonctions 12c4.
4) Translation d’adresse (NAT) et re-direction de ports (PAT)
Contrairement à IPFW qui ne gérait pas la translation d’adresse et de port (il fallait utiliser IPNAT), PF s’acquitte parfaitement de ces taches. La syntaxe est très proche de celle utilisée par IPNAT.
Exemple de NAT:
nat pass on eth0 from eth1:network to any -> $ip_externe
On notera l’utilisation de la macro eth1:network qui donne le réseau associé à l’interface réseau eth1
binat on $if_externe from 192.168.1.100 to any -> 80.80.80.81
Exemple de PAT:
rdr on $if_externe from any to $ip_externe port 8080 -> $ip_serveur port 80
5) Règles de filtrage
On entre (enfin ?) dans le vif du sujet avec l’adaptation des règles de IPFW vers PF.
La première chose à se rappeler est que l’interprétation des règles est de type “last matching rules wins”: la dernière règle qui correspond au paquet est appliquée. C’est le contraire de la logique que l’on suivait avec IPFW. Cependant, si comme moi vous avez du mal à réfléchir à l’envers, il reste la possibilité d’utiliser l’option quick. Quand cette dernière est présente dans une règle, PF arrête l’interprétation des règles suivantes.
L’option permettant de faire du suivi de connexion (sur TCP mais aussi sur UDP ou tout autre protocole IP) est “keep state” (attention c’était “keep-state” avec un - sous IPFW…). Cette option est maintenant ajouté par défaut sur les OS BSD (depuis OpenBSD 4.0 et FreeBSD 7.0).
Exemple de filtres:
pass in on $int_if from $internal_net to any
pass out on $ext_if proto tcp all modulate state flags S/SA
pass out on $ext_if proto { udp, icmp } all keep state
pass in on $ext_if inet proto tcp from any to $webserver port 80 flags S/SA synproxy state
Gestion de votre nouveau Firewall PF
La gestion de la configuration de votre Firewall PF se fait via l’utilitaire pfctl.
Quelques commandes utiles:
Vérification de la syntaxe du fichier /etc/pf.conf
pfctl -n -f /etc/pf.conf
Activation du filtrage:
pfctl -e
Dés-activation du filtrage:
pfctl -d
Rechargement des règles:
pfctl -f /etc/pf.conf
Affichage des règles de filtrage:
pfctl -s rules
Affichage des NAT et PAT:
pfctl -s nat
Affichage l’état des sessions existantes (connections):
pfctl -s state
Affichage du fichier de log (pour voir les paquets rejetés):
tcpdump -r /var/log/pflog
ou bien:
tcpdump -i pflog0 -qea -ttt
Conclusion
Je dois vous avouer que j’étais très réticent pour ce passage de IPFW et PF mais après quelques heures d’utilisations je pense que ce système de filtrage est très bon et aussi facile à administrer (en tout cas beaucoup plus simple que l’usine à gaz IPTABLES… je sais je troll…).