lalahop

Ce billet relate la mise en œuvre d'un pare-feu redondant en utilisant OpenBSD, Packet Filter, CARP et pfsync.

Même si cette mise en œuvre se situe dans un cadre scolaire (« bouh c'est nul, on ne fait pas comme ça en vrai ! » diront certains), je pense qu'elle vaut la peine d'être partagée. La partie installation d'OpenBSD est un peu bête mais quand c'est exigé ... L'installation d'un pare-feu redondant n'était qu'une partie d'un travail plus vaste, cela explique certaines choses (adressage IP, CPE, ...).

Ce travail a été réalisé avec Hamza Hmama et Frédéric Deveaux.

Il y a déjà une masse de tutoriels concernant une telle mise en œuvre sur le web. Celui-ci se démarquera en montrant, de manière assez précise, comment valider le bon fonctionnement du pare-feu.

Table des matières

Présentation détaillée

L'objectif est de déployer un pare-feu hautement disponible pour protéger des serveurs publics qui se situent dans une DMZ.

Le firewall est un service indispensable dans un réseau pour assurer la sécurité des connexions entrantes et sortantes. Utiliser un firewall redondant permet de diminuer énormément le risque que celui-ci soit hors service. En effet, il faut que toutes les machines physiques qui composent le cluster du firewall soient hors service (panne, maintenance, ...) à un instant précis, ce qui est moins probable qu'une seule machine.

Quelques exemples de déploiements d'une solution de ce type en entrée de gros sites : université de Rennes 1 (500 Mbps en entrée) et École normale supérieure. Voir : présentation « OpenBSD/Packet-Filter retour d'expérience » par Patrick LAMAIZIERE aux JRES 2013.

Pour ce faire, nous allons utiliser deux PC, sur lesquelles nous allons installer OpenBSD et configurer CARP et pfsync.

CARP est un protocole réseau qui autorise plusieurs machines à se partager un groupe d'IP dites virtuelles. Cela permet la haute disponibilité : pour que le service ne soit plus accessible, il faut que l'intégralité des machines qui se partagent le groupe d'IP soit hors service. CARP peut aussi servir à faire du partage de charge entre plusieurs machines (mode actif/actif (voir 4.2.2) en utilisant plusieurs groupes de redondance qui se partagent une même VIP). Nous n'utiliserons pas cette fonctionnalité mais resterons en mode actif/attente). CARP est l'équivalent du protocole propriétaire HSRP de Cisco et du protocole VRRP publié à l'IETF.

Pfsync permet de synchroniser les états de Packet Filter entre toutes les machines du cluster. Ainsi, une connexion qui a commencé en passant par FW1 n'est pas interrompue quand FW1 tombe (panne) et que FW2 prend la main.

Il n'existe aucun outil pour effectuer la synchronisation des règles du pare-feu entre les différentes machines du cluster. Un simple transfert sécurisé (scp) du jeu de règles puis un chargement des règles sur chaque machine avec ssh suffit amplement et s'automatise avec un simple script shell. Des scripts shell plus complets peuvent être trouvés sur le web. Exemple : Script to sync pf rules for CARP fws .

L'équivalent GNU/Linux serait keepalived (démon VRRP) ou ucarp (implémentation de CARP pour GNU/Linux) et conntrackd (équivalent pfsync). Exemple de mise en pratique : Firewall HA with conntrackd and keepalived.

Voici un schéma de l'infrastructure que nous allons déployer :

Schéma de notre pare-feu hautement disponible

Schéma de notre pare-feu hautement disponible.

Nous utilisons un préfixe d'interconnexion /30 entre FW1 et FW2 pour le trafic pfsync. Le CPE est tout bêtement un PC qui exécute Dynamips. Derrière lui se trouve le réseau des utilisateurs.

Mise en œuvre

Il existe plusieurs manières de faire à chaque étape, plusieurs valeurs sont possibles pour chaque paramètre, ... Référez-vous à la documentation OpenBSD pour plus d'informations.

Installation d'OpenBSD

D'abord, on crée un médium d'installation. Malgré le fait d'avoir suivi plusieurs tutoriels disponibles sur le web (sauf ceux impliquant l'utilisation d'une machine virtuelle et/ou une première installation sur la clé elle-même, manque de temps), nous n'avons pas réussis à obtenir une clé USB bootable d'installation d'OpenBSD. Dans ce cas, il faut récupérer et graver l'ISO du CD d'installation de la dernière version stable d'OpenBSD. À l'heure actuelle, elle est disponible à cette URL : ftp://ftp.fr.openbsd.org/pub/OpenBSD/5.4/amd64/install54.iso.

Ensuite, il faut installer OpenBSD sur FW1 et FW2. On peut aussi effectuer une seule installation puis cloner le disque dur sur la deuxième machine, via le réseau, en utilisant Clonezilla. Ci-dessous, la procédure d'installation d'OpenBSD :

  1. Il faut aller dans le BIOS pour configurer le boot à partir du CD d'installation. Ce réglage dépend du type de BIOS, de la version, ... Dans notre cas, pour accéder à l'interface de configuration, il faut appuyer sur la touche « Suppr » du clavier au début de la procédure de démarrage du PC. Il faut ensuite se déplacer dans « Advanced BIOS Features » puis positionner la valeur « USB-CDROM » pour le paramètre « First Boot Device ». Il faut vérifier que le paramètre « Second Boot Device » est bien configuré à la valeur « Hard Disk ». Enfin, il faut revenir au menu principal à l'aide de la touche « Echap » et choisir « Save & Exit Setup ». Au reboot automatique, la machine démarrera sur le CD d'installation OpenBSD.
  2. À l'invite « boot> », il faut appuyer sur la touche « Entrée » du clavier.
  3. « (I)nstall, (U)pgrade or (S)hell? » : Choisir « Install » en tapant « I » et « Entrée ».
  4. « Choose your keyboard layout » : taper « fr » et « Entrée ».
  5. « System hostname? » : taper « FW1 » ou « FW2 » et « Entrée ».
  6. Configuration réseau :
    • « Which one do you wish to configure? » : « done » et « Entrée ».
    • « DNS domain name? » : accepter la proposition par défaut en appuyant sur « Entrée ».
    • « DNS nameservers? » : accepter la proposition par défaut en appuyant sur « Entrée ».
  7. « Password for root account? » : taper le mot de passe de votre choix (ici : « toor ») et « Entrée ». « again » : retaper votre mot de passe et « Entrée ».
  8. « Start sshd by default? » : accepter la proposition par défaut (yes) en appuyant sur « Entrée ».
  9. « Start ntpd by default? » : accepter la proposition par défaut (no) en appuyant sur « Entrée ». La synchronisation de l'horloge est importante, notamment pour la cohérence des logs mais comme notre maquette n'est pas connectée à Internet, nous ne pouvons accéder à aucun serveur de temps.
  10. « Do you expect to run the X Window System ? » : « no » et « Entrée ».
  11. « Setup a user? » : accepter la proposition par défaut (no) en appuyant sur « Entrée ».
  12. Configuration des disques durs/partitionnement :
    • « Which disk is the root disk? » : accepter la proposition par défaut en appuyant sur « Entrée ».
    • « Use DUIDs in fstab? » : accepter la proposition par défaut (yes) en appuyant sur « Entrée ».
    • « Whole disk or edit the MBR? » : accepter la proposition par défaut (whole) en appuyant sur « Entrée ».
    • « (A)uto layout, (E)dit auto layout, or create (C)ustome layout? » : accepter la proposition par défaut (auto layout) en appuyant sur « Entrée ».
  13. Source de l'installation :
    • « Location of sets? » : accepter la proposition par défaut (cd) en appuyant sur « Entrée ».
    • « Which one contains the install media? » : accepter la proposition par défaut (cd0) en appuyant sur « Entrée ».
    • « Pathname to the sets? » : accepter la proposition par défaut (5.4/amd64) en appuyant sur « Entrée ».
    • « Set name(s)? » : accepter la proposition par défaut (done) en appuyant sur « Entrée ».
  14. L'installation s'effectue ...
  15. « Location of sets » : nous ne voulons rien installer de plus donc accepter la proposition par défaut (done) en appuyant sur « Entrée ».
  16. « What timezone are you in? » : taper « Europe/Paris » puis « Entrée ».
  17. Taper « reboot » puis « Entrée ».

Configuration réseau

Configuration des interfaces réseau de FW1
echo "inet 170.16.3.129 255.255.255.248 NONE" > /etc/hostname.em0
echo "inet 170.16.3.193 255.255.255.192 NONE" > /etc/hostname.em1
echo "inet 192.168.1.1 255.255.255.252 NONE" > /etc/hostname.em2
Configuration des interfaces réseau de FW2
echo "inet 170.16.3.130 255.255.255.248 NONE" > /etc/hostname.em0
echo "inet 170.16.3.194 255.255.255.192 NONE" > /etc/hostname.em1
echo "inet 192.168.1.2 255.255.255.252 NONE" > /etc/hostname.em2
Configuration de la route par défaut sur FW1 et FW2

On configure une route par défaut via le CPE :

echo "170.16.3.132" > /etc/mygate
Activation de l'IP forwarding sur FW1 et FW2

On active l'ip forwarding en décommentant la ligne « net.inet.ip.forwarding=1 » dans le fichier /etc/sysctl.conf.

Configuration de l'interface réseau du CPE
conf t
  int fastEthernet 0/3
    ip address 170.16.3.132 255.255.255.248
    no sh
Ajout d'une route sur le CPE

Sur le CPE, on ajoute une route pour joindre le réseau des serveurs (170.16.3.192/26) via les FW

conf t
  ip route 170.16.3.192 255.255.255.192 170.16.3.131
Configuration de l'interface de notre serveur de test

Pour cela, on ajoute les lignes suivantes au fichier /etc/network/interfaces :

iface eth0 inet static
  address 170.16.3.196
  netmask 26
  gateway 170.16.3.195

CARP

Configuration des paramètres généraux de CARP sur FW1 et FW2

Pour cela, il faut rajouter les lignes suivantes dans le fichier /etc/sysctl.conf :

net.inet.carp.allow=1
net.inet.carp.preempt=1

« net.inet.carp.allow=1 » permet d'accepter les paquets du protocole CARP qui arrivent par le réseau.

« net.inet.carp.preempt=1 » permet d'optimiser l'élection du maître dans un groupe de redondance. Cela permet également de basculer toutes les interfaces d'un même groupe de redondance sur un même hôte en même temps.

Configuration des deux interfaces CARP sur FW1
echo "inet 170.16.3.131 255.255.255.248 170.16.3.135 vhid 1 carpdev em0 advskew 1 pass toor" > /etc/hostname.carp0
echo "inet 170.16.3.195 255.255.255.192 170.16.3.255 vhid 2 carpdev em1 advskew 1 pass toor" > /etc/hostname.carp1

« vidh X » : Virtual Host ID. C'est un numéro unique par réseau qui permet d'identifier un groupe de redondance CARP sur ce réseau. Les valeurs possibles sont comprises dans l'intervalle [1,255].

« carpdev » permet de spécifier l'interface réseau physique à utiliser pour ce groupe de redondance CARP.

« advskew X » permet d'introduire un biais pour forcer le choix lors de l'élection du maître du groupe de redondance. Plus la valeur de ce paramètre est élevée, moindre sont les chances de cet hôte de devenir le maître. Dans notre cas, c'est utile pour que les deux IP virtuelles (une sur le réseau d'interconnexion, l'autre sur le réseau des serveurs) soient attribuées au même hôte.

« pass <mot_de_passe> » est le mot de passe à utiliser lors de la communication avec les autres machines du même groupe de redondance. Évidemment, ce mot de passe doit être identifique sur toutes les machines d'un même groupe de redondance.

Configuration des interfaces CARP sur FW2
echo "inet 170.16.3.131 255.255.255.248 170.16.3.135 vhid 1 carpdev em0 advskew 100 pass toor" > /etc/hostname.carp0
echo "inet 170.16.3.195 255.255.255.192 170.16.3.255 vhid 2 carpdev em1 advskew 100 pass toor" > /etc/hostname.carp1

Configuration de Packet Filter

Règles de filtrage

On crée notre propre jeu de règles de filtrage minimaliste puis on l'insère dans le fichier /etc/pf.conf (en supprimant l'existant) de FW1 et FW2 afin qu'il soit appliqué automatiquement à chaque démarrage des deux machines :

# On bloque tout sauf ce qui passe sur la loopback
block
set skip on lo
 
# CARP
pass on { em0 em1 } proto carp keep state
 
# SSH depuis le réseau utilisateur vers les serveurs
pass in on em0 inet proto tcp from 170.16.3.0/24 to 170.16.3.196 port 22 keep state
 
# ICMP partout
pass inet proto icmp from any to any keep state

pfsync

Configuration de l'interface pfsync sur FW1
echo "up syncpeer 192.168.1.2 syncdev em2" > /etc/hostname.pfsync0

Par défaut, les mises à jour des états se font en multicast. Le paramètre « syncpeer » permet de faire les mises à jour d'état en unicast avec uniquement l'hôte spécifié.

« syncdev » permet de spécifier l'interface réseau physique à utiliser pour envoyer/recevoir le trafic pfsync.

Il faut noter que pfsync est assez gourmand en fonction de l'usage et donc du type de trafic qui passe par le pare-feu redondant, c'est pour cela qu'on conseille un lien réseau dédié à pfsync. Dans l'exemple de l'université de Rennes 1 cité plus haut, ils ont une majorité de trafic web. Rappel : pour une même page web, il faut établir XX connexions pour récupérer le contenu (js (comme jquery) stocké ailleurs, polices stockées ailleurs, pubs, ...). Cela génère des états au niveau des firewall et donc, du trafic pfsync pour échanger ces états. En pointe, ils observent 150 Mbps de trafic sur leur lien dédié pfsync.

Configuration de l'interface pfsync sur FW2
echo "up syncpeer 192.168.1.1 syncdev em2" > /etc/hostname.pfsync0
On autorise le protocole pfsync dans Packet Filter, sur FW1 et FW2

Pour cela, on ajoute la règle suivante aux fichiers /etc/pf.conf :

# pfsync
pass on em2 proto pfsync keep state

Valider le bon fonctionnement de notre pare-feu redondant

Il suffit de rebooter toutes les machines (FW1, FW2, serveur de test) pour que la configuration soit appliquée. Ou, de manière plus pragmatique, on peut appliquer les changements à chaud. Sur FW1 et FW2 :

# Recharger le réseau
sh /etc/netstart
 
# IP forwarding et CARP
sysctl -w net.inet.ip.forwarding=1
sysctl -w net.inet.carp.allow=1
sysctl -w net.inet.carp.preempt=1 
 
# Charger le jeu de règles dans PF et activer PF
pfctl -f /etc/pf.conf 
pfctl -e

Sur la machine de test :

ifup eth0

On peut ensuite vérifier que tout fonctionne comme attendu.

Connectivité

On vérifie que le réseau est fonctionnel en faisant passer un ping depuis une machine de test dans le réseau des utilisateurs vers notre serveur de test :

toto@client: # ping 170.16.3.196
PING 170.16.3.196 (170.16.3.196) 56(84) bytes of data.
64 bytes from 170.16.3.196: icmp_req=1 ttl=63 time=1.99 ms
64 bytes from 170.16.3.196: icmp_req=2 ttl=63 time=1.45 ms
64 bytes from 170.16.3.196: icmp_req=3 ttl=63 time=1.16 ms
64 bytes from 170.16.3.196: icmp_req=4 ttl=63 time=1.45 ms

CARP

On constate que CARP est fonctionnel en regardant la sortie de l'outil ifconfig.

Sur FW1 :

# ifconfig carp
carp0: flags=8843<UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST> mtu 1500
        lladdr 00:00:5e:00:01:01
        priority: 0
        carp: MASTER carpdev em0 vhid 1 advbase 1 advskew 1
        groups: carp
        status: master
        inet6 fe80::200:5eff:fe00:101%carp0 prefixlen 64 scopeid 0x6
        inet 170.16.3.131 netmask 0xfffffff8 broadcast 170.16.3.135
carp1: flags=8843<UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST> mtu 1500
        lladdr 00:00:5e:00:01:02
        priority: 0
        carp: MASTER carpdev em1 vhid 2 advbase 1 advskew 1
        groups: carp
        status: master
        inet6 fe80::200:5eff:fe00:102%carp1 prefixlen 64 scopeid 0x7
        inet 170.16.3.195 netmask 0xffffffc0 broadcast 170.16.3.255

On constate que FW1 est bien le maître des deux groupes de redondances (« carp: MASTER »).

Sur FW2 :

# ifconfig carp
carp0: flags=8843<UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST> mtu 1500
    lladdr 00:00:5e:00:01:01
    priority: 0
    carp: BACKUP carpdev em0 vhid 1 advbase 1 advskew 100
    groups: carp
    status: backup
    inet6 fe80::200:5eff:fe00:101%carp0 prefixlen 64 scopeid 0x6
    inet 170.16.3.131 netmask 0xfffffff8 broadcast 170.16.3.135
carp1: flags=8843<UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST> mtu 1500
    lladdr 00:00:5e:00:01:02
    priority: 0
    carp: BACKUP carpdev em1 vhid 2 advbase 1 advskew 100
    groups: carp
    status: backup
    inet6 fe80::200:5eff:fe00:102%carp1 prefixlen 64 scopeid 0x7
    inet 170.16.3.195 netmask 0xffffffc0 broadcast 170.16.3.255

On constate que FW2 est bien en backup sur les deux groupes de redondances (« carp: BACKUP »).

Une capture réseau depuis FW2 nous montre que FW1 est le maître sur l'IP virtuelle 170.16.3.131 et qu'en conséquence, il diffuse des messages « CARP advertisement » à fréquence régulière (ici : 1 seconde, paramétrable en changeant la valeur du paramètre « advbase ») :

# tcpdump -tttttvvni em0
tcpdump: listening on em0, link-type EN10MB
1.019374 carp 170.16.3.129 > 224.0.0.18: CARPv2-advertise 36: vhid=1 advbase=1 advskew=1 demote=0 (DF) [tos 0x10] (ttl 255, id 10529, len 56)
2.040085 carp 170.16.3.129 > 224.0.0.18: CARPv2-advertise 36: vhid=1 advbase=1 advskew=1 demote=0 (DF) [tos 0x10] (ttl 255, id 19703, len 56)
3.060098 carp 170.16.3.129 > 224.0.0.18: CARPv2-advertise 36: vhid=1 advbase=1 advskew=1 demote=0 (DF) [tos 0x10] (ttl 255, id 41787, len 56)
4.080206 carp 170.16.3.129 > 224.0.0.18: CARPv2-advertise 36: vhid=1 advbase=1 advskew=1 demote=0 (DF) [tos 0x10] (ttl 255, id 55471, len 56)

Si nous coupons l'interface carp0 sur FW1, celui-ci cesse d'émettre, les FW restants émettent des advertisement, une nouvelle élection a lieu entre les FW restants (dans notre cas : uniquement FW2) et FW2 devient le nouveau maître pour l'IP virtuelle 170.16.3.131 :

# tcpdump -tttttvvni em0
tcpdump: listening on em0, link-type EN10MB
5.099795 carp 170.16.3.129 > 224.0.0.18: CARPv2-advertise 36: vhid=1 advbase=1 advskew=1 demote=0 (DF) [tos 0x10] (ttl 255, id 16645, len 56)
6.119458 carp 170.16.3.129 > 224.0.0.18: CARPv2-advertise 36: vhid=1 advbase=1 advskew=1 demote=0 (DF) [tos 0x10] (ttl 255, id 20322, len 56)
7.4294686187 carp 170.16.3.129 > 224.0.0.18: CARPv2-advertise 36: vhid=1 advbase=255 advskew=255 demote=0 (DF) [tos 0x10] (ttl 255, id 33756, len 56)
7.4294688491 carp 170.16.3.130 > 224.0.0.18: CARPv2-advertise 36: vhid=1 advbase=1 advskew=100 demote=0 (DF) [tos 0x10] (ttl 255, id 22655, len 56)
8.129407 carp 170.16.3.130 > 224.0.0.18: CARPv2-advertise 36: vhid=1 advbase=1 advskew=100 demote=0 (DF) [tos 0x10] (ttl 255, id 31522, len 56)
10.4294507802 carp 170.16.3.130 > 224.0.0.18: CARPv2-advertise 36: vhid=1 advbase=1 advskew=100 demote=0 (DF) [tos 0x10] (ttl 255, id 35522, len 56)
11.4294916715 carp 170.16.3.130 > 224.0.0.18: CARPv2-advertise 36: vhid=1 advbase=1 advskew=100 demote=0 (DF) [tos 0x10] (ttl 255, id 35096, len 56)
12.359366 carp 170.16.3.130 > 224.0.0.18: CARPv2-advertise 36: vhid=1 advbase=1 advskew=100 demote=0 (DF) [tos 0x10] (ttl 255, id 63215, len 56)
14.4294736635 carp 170.16.3.130 > 224.0.0.18: CARPv2-advertise 36: vhid=1 advbase=1 advskew=100 demote=0 (DF) [tos 0x10] (ttl 255, id 17132, len 56)
15.179471 carp 170.16.3.130 > 224.0.0.18: CARPv2-advertise 36: vhid=1 advbase=1 advskew=100 demote=0 (DF) [tos 0x10] (ttl 255, id 32836, len 56)

Les logs (/var/log/messages) de FW2 nous montrent également la transition :

fw2 /bsd: carp0: state transition: BACKUP -> MASTER
fw2 /bsd: carp1: state transition: BACKUP -> MASTER

Quand FW1 est remis en état, il reprend la main et, dans les logs de FW2, nous lisons :

fw2 /bsd: carp1: state transition: MASTER -> BACKUP
fw2 /bsd: carp0: state transition: MASTER -> BACKUP

Pfsync

On vérifie que les interfaces pfsync sont up.

Sur FW1 :

# ifconfig pfsync0
pfsync0: flags=41<UP,RUNNING> mtu 1500
        priority: 0
        pfsync: syncdev: em2 syncpeer: 192.168.1.2 maxupd: 128 defer: off
        groups: carp pfsync

Note : « defer » est un paramètre qui peut être positionné à la valeur « on » pour faire en sorte qu'une connexion n'est réellement acceptée que si le pair pfsync a acquitté la modification de la table des états ou que le délai d'attente pour cet acquittement a expiré. Cela permet une plus grande cohérence entre les pare-feu et est indispensable lorsque plus d'un pare-feu doit s'occuper activement des paquets (typiquement : répartition de la charge).

Sur FW2 :

# ifconfig pfsync0
pfsync0: flags=41<UP,RUNNING> mtu 1500
        priority: 0
        pfsync: syncdev: em2 syncpeer: 192.168.1.1 maxupd: 128 defer: off
        groups: carp pfsync

On constate aussi l'existence d'un trafic réseau pfsync sur le lien d'interconnexion entre les deux pare-feux :

# tcpdump -tttttvvni em2
tcpdump: listening on em2, link-type EN10MB
0.007794 192.168.1.1 > 192.168.1.2: PFSYNCv6 len 276
    act UPD ST COMP count 3
    ...
 (DF) [tos 0x10] (ttl 255, id 38708, len 296)
0.410334 192.168.1.2 > 192.168.1.1: PFSYNCv6 len 276
    act UPD ST COMP count 3
    ...
 (DF) [tos 0x10] (ttl 255, id 22377, len 296)
0.410597 192.168.1.2 > 192.168.1.1: PFSYNCv6 len 108
    act UPD ST COMP count 1
    ...
 (DF) [tos 0x10] (ttl 255, id 51022, len 128)
0.410692 192.168.1.2 > 192.168.1.1: PFSYNCv6 len 108
    act UPD ST COMP count 1
    ...
 (DF) [tos 0x10] (ttl 255, id 40898, len 128)
0.410730 192.168.1.1 > 192.168.1.2: PFSYNCv6 len 276
    act UPD ST COMP count 3
    ...
 (DF) [tos 0x10] (ttl 255, id 65488, len 296)
0.410774 192.168.1.2 > 192.168.1.1: PFSYNCv6 len 108
    act UPD ST COMP count 1
    ...
 (DF) [tos 0x10] (ttl 255, id 24885, len 128)

Enfin, en établissant une session SSH depuis le réseau des utilisateurs vers notre serveur de test, alors que FW1 est le maître sur les deux interfaces CARP, nous constatons que les tables d'états des deux pare-feux sont synchronisées.

Sur FW1 :

# pfctl -ss
all carp 170.16.3.129 -> 224.0.0.18       SINGLE:NO_TRAFFIC
all carp 170.16.3.193 -> 224.0.0.18       SINGLE:NO_TRAFFIC
all pfsync 192.168.1.1 -> 192.168.1.2       MULTIPLE:MULTIPLE
all carp 224.0.0.18 <- 170.16.3.129       NO_TRAFFIC:SINGLE
all carp 224.0.0.18 <- 170.16.3.193       NO_TRAFFIC:SINGLE
all tcp 170.16.3.196:22 <- 170.16.3.132:33607       ESTABLISHED:ESTABLISHED
all tcp 170.16.3.132:33607 -> 170.16.3.196:22       ESTABLISHED:ESTABLISHED

Sur FW2 :

# pfctl -ss
all carp 170.16.3.129 -> 224.0.0.18       SINGLE:NO_TRAFFIC
all carp 170.16.3.193 -> 224.0.0.18       SINGLE:NO_TRAFFIC
all pfsync 192.168.1.2 <- 192.168.1.1       MULTIPLE:MULTIPLE
all carp 224.0.0.18 <- 170.16.3.129       NO_TRAFFIC:SINGLE
all carp 224.0.0.18 <- 170.16.3.193       NO_TRAFFIC:SINGLE
all tcp 170.16.3.196:22 <- 170.16.3.42:33607       ESTABLISHED:ESTABLISHED
all tcp 170.16.3.42:33607 -> 170.16.3.196:22       ESTABLISHED:ESTABLISHED

Si l'on coupe brutalement les interfaces réseau de FW1 (ou FW1 lui-même), on constate que FW2 prend le relais et que la session SSH n'est pas interrompue car les états des deux pare-feux sont cohérents et synchronisés.

Sources

  1. Je trouve tes sources particulièrement bonnes :p
    Excellent billet en tout cas, bien complet comme il faut 🙂

    • Je te comprends. You made my day ! 😀

  2. Merci pour ce tuto tres bien fait 😉

  3. très bon tuto complet et bien expliqué, grace a toi j’ai compris plein de chose.