PF
PF, de Daniel Hartmeier, est le logiciel de firewalling IP d'OpenBSD. Il
est assez jeune; son prédécesseur, IPF de Darren Reed a été
retiré du système à la version 3.0 pour une histoire
de licence.
Malgré ou, grâce à sa jeunesse, PF progresse rapidement...[Encore
une fois, étant dans l'incapacité la plus totale d'analyser
le source de PF, j'en reste à voir évoluer ses fonctionnalités
et à lire les commentaires des spécialistes ]
PF sait faire plein de choses :
- C'est un Firewall de type filtre de paquet (Couches réseau
et transport)
- C'est un FireWall stateful (à états). C'est à
dire qu'il est capable de suivre les différents datagrammes (oui,
oui UDP aussi!!) ou segments TCP échangés par le client et le
serveur lors d'une requête quelconque et de savoir qu'ils font partie
d'une seule et même session; Avantage immédiat, si le premier
paquet est autorisé à passer, les suivants passeront automatiquement
sans repasser par les filtres. Avantages : Simplicité d'écriture
des règles (donc moins d'erreurs humaines), Charge CPU diminuée.
Il intègre les numéros de séquence
TCP dans la gestion des états. Ca parait simple, mais, apparemment,
des pointures du monde commercial comme CheckPoint FW1 en sont incapable,
bravo !
Quand il voit passer une séquence d'initialisation
de connexion TCP, il sait qu'il doit voir passer un SYN, puis un SYN/ACK
dans l'autre sens, en un ACK de retour. Point barre pour la séquence
d'initialisation! Et contrairement à d'autres (NetFilter, par ex..)
PF est intraitable sur ces flags TCP.
- Il intègre maintenant la fonction de NAT,
(Translation d'adresse réseau ) pour permettre à plusieurs
machines d'aller faire un tour sur Internet avec une seule adresse IPV4 publique.
- Désormais, il intègre la possibilité de faire
de l'allocation de bande passante ( trafic shaping) avec altq. Pour se réserver 10% de la bande passante,
ou alors interdire au téléchargement sauvage de manger toute
la bande passante.
- Il est capable de protéger la pile TCP/IP
un peu faiblarde de certains OS qui sont derrière lui, en réécrivant
au vol, le numéro de séquence TCP.
- Il peut, réassembler les paquets qui sont intentionnellement
fragmentés afin d'échapper aux IDS.(Systèmes
de détection d'intrusions)
- Il sait rendre aveugle les vilains qui voudraient savoir combien de machines sont translatées (nattées
?) dans votre LAN. Et oui, ça
existe.
- Il peut, désormais, faire du load balancing (répartition
de charge) entre plusieurs machines.On peut ainsi allèger la charge
d'une machine en en mettant plusieurs en parallèle.
PF ne sait pas encore faire ou ne fera jamais certaines choses :
- PF n'est pas et ne sera pas un Firewall applicatif; ie Squid,
fait très bien le proxy (mandataire), chacun son boulot.
- Quelques applis mal foutues , Netmeeting pour ne pas la citer,
utilisent des tas de ports qui ont la mauvaise idée d'être
à la fois dynamiques et de se trouver côtés clients
et serveurs...bref c'est un casse-tête pour un FireWall, qui va se
retrouver en pass all dans les 2 sens. Selon des sources bien informées,
PF ne gèrera jamais NetMeeting..Dommage, NetFilter sait faire.
- Table mangle mais altq.
Performances :
- Et, en plus avec tout ça, vous êtes en train de vous
dire que vous allez casser votre tirelire pour le dernier CPU gonflé
aux GHz ???
Que nenni, PF est très chiche en ressources. Avec, à peu
près tout d'activé ici, un P166 avec 32 Mo de RAM dépasse
rarement 5 % sur une ligne ADSL 512kb/s avec des requêtes nombreuses
et variées.
Quelques remarques néanmoins :
Les règles sont toutes chargées en mémoire et parcourues
sous une forme arborescente lors de l'évaluation des règles.
Vous pouvez atteindre une diminution de 20 % des ressources nécessaires
si vous écrivez en bloc les règles ayant des paramètres
identiques, cad :
- Par sens de passage (in/out)
- Par interface
- Par adresse
...
Lors du parcours de l'arbre, le logiciel éliminera en bloc toutes
les règles inutilisées; sinon, il doit les parcourir une par
une.
Les règles de base
Authpf : Le firewall avec authentification
Pour aller plus loin
Filtrage sur les flags
State modulation
Normaliser les paquets
ICMP
IPV6
Le problème du
FTP (ftp-proxy)
Exemple simple
La commande pfctl
Surveiller les logs
La translation d'adresse : Nat
L'ordre des règles dans pf.conf
Les modifications apportées depuis
la 3.0
nat.conf et altq.conf intègrent pf.conf. En fait nat.conf
a intégré pf.conf depuis la 3.2 et altq.conf depuis la 3.3.
Authpf
Vous voudriez bien, pouvoir utiliser des règles de firewall qui
seraient dépendantes de VOUS, utilisateur et de VOTRE IP, dans le
cas d'une connexion itinérante.
Vous voudriez éviter d'investir dans l'agent d'authentification
de Checkpoint FW-1 qui fait exactement ça.
Authpf est fait pour vous !
Il vous suffit d'avoir un compte et un shell valide sur la passerelle
ou le serveur. Vous vous connectez en SSH sur cette machine et des règles
spécifiques vous sont attribuées dans pf. Ces rèlgles
qui peuvent concerner les directives rdr, nat, pass ou block, entre autres,
sont détruites lors de la déconnexion de SSH.
Afin d'éviter que l'utilisateur ne se fasse des règles
un peu trop "ouvertes", celles-ci sont stockées à plusieurs
endroits possibles qui ne devraint pas être ouverts en RW à
l'utilisateur :
/etc/authpf/users/$USER/authpf.rules
Puis
/etc/authpf/authpf.rules
authpf.conf DOIT exister
Nous allons utiliser le merveilleux outil fourni par l'équipe
OpenBSD : authpf.
Ajoutez simplement la ligne suivante au fichier /etc/authpf/authpf.rules
:
pass in log quick on $interface_ext proto tcp from $user_ip/32
to IP_Publique_du serveur_POP3/32 port = 110 flags S/SA keep state
Attention, la variable $user_ip est d'usage
obligatoire, elle récupère l'adresse IP du client SSH..
Ensuite, vous fermez le port 110 et vous ouvrez le port 22 sur tout
l'internet :
pass in log quick on $interface_ext proto tcp from any to IP_Publique_du
serveur_POP3/32 port = 22 flags S/SA keep state
block in log on $interface_ext proto tcp from any to IP_Publique_du
serveur_POP3/32 port = 110
Attention, n'ajoutez pas le mot clef quick
à la fermeture du port 110, car authpf ajoute, par défaut,
les règles de filtrage à la fin du fichier de règle,
votre règle d'ouverture par authpf ne serait jamais lue.
Il est probable qu'utiliser le compte root pour récupérer
son courrier soit une assez mauvaise idée ;-); De plus, être
obligé de taper son mot de passe SSH à chaque relevé
de courrier risque de devenir vite pénible. Pour cela, créez
un compte utilisateur non-privilégié sur le serveur,
CLE PUB, PAS DE PHRASE DE PASS.....
Les règles
de base
- Tout d'abord, sa syntaxe est limpide quand on la compare à celle
d'un IPchains; ça limitera d'autant les erreurs humaines.
- PF ne s'arrête pas à la première règle correspondante
trouvée, il lit le fichier complètement du haut vers le bas
jusqu'au bout..
De fait la dernière trouvée l'emporte.
Comme l'indique la page de man : "last matching rule wins".
Attention, ceci est l'inverse des règles de NAT
!
Si aucune règle ne provoque de correspondance, l'action
par défaut est pass.Notez-le c'est important.
- Afin d'accélérer l'analyse on peut ajouter quick
dans une règle lorsque l'on veut que l'analyse des règles s'arrête
là, et que la règle soit immédiatement mise en oeuvre.
- Rappelons que pour optimiser pf, il est préférable
de ranger les règles dans un ordre donné, en commençant
par mettre à la suite toutes les règles qui portent sur la
même interface, puis par protocole, puis adresse et port source pour
finir par adresse et port destination.
- Il est possible d'utiliser dans les règles des variables que
l'on définit en début de fichier.
- Si vous utilisez NAT et pf gardez à l'esprit que NAT est
interprété le premier, puis pf.(Très important
pour débugger, NAT PUIS pf)
- Pour lancer pf au démarrage vous devez vérifier que vous
avez bien pf=YES dans /etc/rc.conf. Vous pouvez aussi
indiquer quel fichier de règles utiliser. Par défaut /etc/pf.conf
. Cela se modifie dans /etc/rc.conf.
La syntaxe des règles de filtrage est la suivante (pour les règles de translation):
Action Sens Paramètres
| Action | Signification |
| scrub | Le paquet suit la phase de normalisation/défragmentation. La directive scrub ne peut pas constituer une dernière règle. Les paquets IPV6 ne sont pas défragmentés. |
| pass | Le paquet est transmis. |
| block | Le paquet est bloqué. Une option permet de renvoyer un Paquet TCP RST ou un ICMP UNREACHABLE à l'expéditeur. Le paquet ICMP peut avoir un code indiqué par son nom ou son numéro. Le paquet TCP peut avoir un TTL déterminé. |
| Sens | Signification |
| in | |
| out |
| Parma | Signification |
| scrub | Le paquet suit la phase de normalisation/défragmentation. La directive scrub ne peut pas constituer une dernière règle. Les paquets IPV6 ne sont pas défragmentés. |
| pass | Le paquet est transmis. |
| block | Le paquet est bloqué. Une option permet de renvoyer un Paquet TCP RST ou un ICMP UNREACHABLE à l'expéditeur. Le paquet ICMP peut avoir un code indiqué par son nom ou son numéro. Le paquet TCP peut avoir un TTL déterminé. |
log : seulement le premier paquet en cas de keep state, sinon log-all...attention
aux D.o.S.
donc block in all et block out all en premier
|
block in all |
On bloque tout par defaut en entrée (si on veut bloquer en sortie mettre out à la place de in) |
|
pass out all |
On autorise tout en sortie |
|
pass in proto tcp from any to 195.98.248.1/32 port = 80 |
On autorise le monde entier à entrer sur cette machine (qui a comme adresse 195.98.246.1) sur le serveur Web. On peut utiliser www à la palce de 80 du moment que cela existe dans /etc/services |
|
pass in from 1.2.3.4/32 to 195.98.248.1/32 |
On autorise la machine 1.2.3.4 à venir sur notre machine sur tous les protocoles. |
|
pass in proto tcp from any to 195.98.248.1/32 port = 80 keep state |
On conserve l'état (voir la commande pfctl -ss), Ce qui permet d'accélérer les connexions. En fait il y a création d'une nouvelle table, dans laquelle est placée la règle. Si un autre paquet ayant la "même origine " se présente on utilise cette table. |
|
pass in quick proto tcp from any to 195.98.248.1/32 port = 80 |
On a "quick" en plus. En fait lorsque ce mot est rencontré, la règle est appliquée immédiatement. On ne continue pas à lire le fichier de règles. |
|
block in quick from 172.16.0.0/16 to 195.98.248.1/32 port = 80 |
On bloque toutes les machines qui se présentent avec
une adresse dans 172.16.0.0/16 et qui essayent de se connecter au
port 80 de notre machine. On peut imaginer que la ligne qui peut
suivre est : |
|
block in log quick from 10.0.0.0/8 to 195.98.248.1/32 port = www |
On bloque tous les paquets en provenance de 10.0.0.0/8 vers le serveur web en 195.98.248.1/32 et en plus on log les tentatives. Voir plus bas sur la lecture des logs. |
|
pass in quick on fxp0 proto tcp from any to 195.98.248.1/32 port = 80 |
On précise la carte réseau. fxp0 correspond au nom de ma carte, qui dépend de la marque de celle-ci. Si vous avez une deuxième carte vous allez avoir fxp1 à la place de fxp0. |
|
pass in proto tcp from {1.2.3.4/32 , 10.0.0.0/8 } to 195.98.248.1/32 port = 80 |
On autorise la machine 1.2.3.4 et le réseau 10.0.0.0 à venir sur le serveur Web de votre machine. On peut aussi écrire deux fois la ligne. |
|
pass in proto tcp from any to 195.98.248.1/32 port = { 80 , 22} |
On autorise tout le monde à venir sur votre machine
sur le serveur Web et en SSH. Un point de notation. On peut aussi
utiliser deux lignes pour faire la même chose: |
|
pass in on fxp0 proto tcp from any to fxp0 port > 50000 keep state |
On autorise tous les paquets à entrer sur le port
supérieur à 50000 vers la carte réseau fxp0. Ce nom dépend
de votre carte. |
L'expansion de variable:
Vous pouvez si vous avez une même règle qui s'applique sur
des IP identiques, utiliser l'expansion de variable afin de n'avoir qu'une
règle à écrire.
Ex : Vous voulez autoriser SSH uniquement depuis votre machine
d'administration (IP1), depuis une partie de votre LAN (10.0.0.0/24), et
depuis votre IP fixe perso (IPperso).
TRUST_IP="{ IP1/32, 10.0.0.0/24, IPperso/32 }"
##Attention aux virgules, accolades, .... c'est assez sensible à la
rédaction.
# Autorise SSH
pass in quick on xl0 proto tcp from $TRUST_IP to any port = 22 flags
S keep state
En revanche lors d'une visualisation
des stats de pf, vous aurez une ligne par variable (3 lignes dans notre
exemple)
Pour aller plus loin
Filtrage sur les drapeaux
la VO
Les paquets TCP échangés pendant
une connexion disposent de flags (drapeaux):
Rien n'interdit d'envoyer à une machine un paquet avec un flag,
puis de ne plus donner suite à l'échange. Cela est une façon
de savoir si cette machine répond. Les produits de scan utilisent ce
type de méthode, qui les rendent souvent plus difficiles à voir.
Afin de limiter ce type de scan et de forcer le "scanneur"
à utiliser des méthodes plus voyantes, vous pouvez bloquer
les scans qui utilisent certains types scans en utilisant les flags.
En fait, dans les règles de filtrage vous pouvez( ou devriez!)
Ce qui nous donne la règle suivante pass
in proto tcp from any to 195.98.250.1/32 port = ssh flags S/SA keep state.
Ce qui veut dire que seul les paquets qui disposent du flag S parmi les
paquets qui disposent du flag SA sont pris en compte ou s'ils disposent déjà
d'une entrée dans la table d'état. Ce cas laissera passer
les paquets ayant le un flag de FIN ou les autres.
NONONONONONNN S, mais pas SA......
Autre possibilité mettre le flag S/AUPRFS ce qui implique que
seul les paquets ayant le flag S (poignet de main comme étant le
premier paquet), ou les paquets disposants déjà d'un état
pourront passer. Ce qui dans ce cas donne la ligne :
pass in proto tcp from any to 195.98.250.1/32 port = ssh flags S/AUPRFS
keep state
Pour résumer, cette ligne veut donc dire : j'autorise les
paquets venant du monde entier à entrer sur la machine 195.98.250.1
sur le port tcp 22 (ssh) seulement si ce paquet se présente avec
le flag S ( première demande de connexion ou poignet de main), si
c'est le cas, alors cela est mis dans la table d'état, permettant
par la suite à tous les paquets venant de la même machine à
pouvoir continuer à envoyer des paquets, alors que les paquets envoyés
peuvent avoir n'importent quel flag.
State modulation
Lors de l'échange de paquets ceci disposent
d'un numéro (ISN) qui s'incrémente normalement en fonction
du temps et aléatoirement à chaque paquet échangé.
Toutefois certains OS (pas de nom ;-)) ne génèrent pas de numéros
aussi aléatoires que prévu, permettant ainsi de déterminer
les numéros des paquets, et donc éventuellement d'usurper
une connexion existante. On peut avec pf modifier cela en ajoutant modulate
state dans la règle.Très utile si vous protégez
derrière des OS pas costauds (les Win9X, en particulier) !
pass out quick on fxp0 from $INSIDE_IP to any modulate state
Un excellent
article sur les séquences TCP.
Normalisation des paquets mal formés
Certains paquets sont mal formés lorsqu'ils
arrivent sur votre machine; Ils représentent au mieux un système
mal configuré, au pire une attaque. Avec pf, il est possible de vérifier
cela est de les normaliser avant de les faire suivre à destination.
Pour cela ajouter simplement la ligne scrub in all avant les autres
règles. Attention toutefois cela nécessite des ressources machines.
scrub random-id deadly.org 9/2/3
ICMP
Mieux connu avec les pings, il peut être utile de les bloquer,
ou de les laisser passer (cas d'un serveur DNS par exemple), sans laisser
passer les autres ICMP.
Autoriser les pings sans autoriser les autres icmp
pass in quick on fxp0 inet proto icmp all icmp-type 8 code 0 keep
state (echo request )
pass in quick on fxp0 inet proto icmp all icmp-type 11keep state
(time exceeded)
Puis on bloque tous les autres
block in log quick on fxp0 proto icmp from any to any
Attention il faut tenir compte de l'ordre.
Bien sur on peut tous les bloquer en ne mettant que la dernière
ligne.
IPV 6
Pour le moment ipv6 est implémenté, mais pas couramment
utilisé. Par prudence, on ne sait jamais, le mieux est de le bloquer.
On peut aussi le désactiver en recompilant le noyau. La règle
est donc block in quick inet6 all à placer en début
du fichier de règles, en général pf.conf. On peut aussi
le faire pour les paquets sortants : block out quick inet6 all. (pour
ipv4 on utilise inet).
Exemples d'architectures réseau :
Client avec une seule carte réseau.
Serveur
avec une seule carte réseau.
Passerelle
filtrante avec deux cartes.
FireWall
dédié avec 3 cartes dont une pour la DMZ.
pfctl est la commande qui permet de contrôler les règles de filtrage. J'indique ici les options qu'il faut absolument connaître. Pour les autres reportez vous à man pfctl.
|
Commande |
Résultat |
|
pfctl -d |
Désactive les règles en place |
|
pfctl -e -f /etc/pf.conf |
Lance les règles qui se trouvent dans le fichier /etc/pf.conf (voir aussi rc.conf pour le lancement au démarrage de la machine) |
|
pfctl -s rules ou pfctl -sr |
Montre les règles de filtrage actives |
|
pfctl -s nat ou pfctl -sn |
Montre les règles de NAT actives |
|
pfctl -s info ou pfctl -si |
Montre les statistiques par paquet, par octet pour chaque interface |
|
pfctl -s state ou pfctl -ss |
Montre le contenu de la table des états. Il faut avoir un keep state (pour avoir une entrée dans la table des états!) |
|
pfctl -F rules |
Permet de flusher les règles de filtrage |
|
pfctl -F nat |
Permet de flusher les règles de NAT |
|
pfctl -f /etc/pf.conf |
Re force la lecture du fichier des règles |
Ajouter -v afin d'avoir plus d'information. par exemple pfctl -v -ss pour avoir plus d'information sur les états (state).
Un exemple de sortie de pfctl -sa sur une machine (toute seule, et
non reliée au réseau, ce qui rend l'analyse, pour le moins,
inexploitable...)
Surveiller les logs
Bloquer c'est bien. Surveiller les logs régulièrement
ce n'est pas mal non plus!!
Alors, attention : les logs de pf NE SONT PAS au format syslog,
mais au format tcpdump. d'où l'utilisation de ce dernier pour la
visualisation et ce, malgré les pbs que cela pose. un grand débat
ici ou
là..
Pour que cette surveillance soit active, plusieurs conditions doivent
etre réunies :
- Que la règle contienne le mot clé log, afin
qu'elle provoque lors de son action, une entrée dans les logs de
pf.
- Que l'interface des logs fonctionne : ifconfig pflog0 up
- Que le démon de log tourne : pflogd
|
tcpdump -n -e -ttt -r /var/log/pflog |
Affiche les logs du fichier /var/log/pflog. Surveillance après coup. |
|
tcpdump -i pflog0 |
Affiche les logs en temps réels |
|
tcpdump -e -i pflog0 port 80 |
Idem mais plus fin, puisque ne surveille les logs que sur le port 80. |
Par défaut les logs se placent dans /var/log/pf.log.
Ordre des règles dans pf.conf
Attention, l'intégration des règles de NAT à celles
de PF ne se fait pas n'importe comment, il y a un ordre à respecter
absolument :
- D'abord les options.(man pf.conf) de pf.conf.
- Puis la directive scrub
- Puis les règles de NAT.
- Enfin, les règles de filtrage .
La directive antispoof.
antispoof for interface [inet|inet6]
Elle limite le spoofing IP (IPV4 ou IPV6, au choix),
© philippe schwarz - Philippe Chadefaux - $Id: pf.htm,v 1.16 2003/01/19 20:36:14 phil Exp $ -