Accueil
Rechercher:
sur developpez.com sur les forums
Forums | Tutoriels | F.A.Q's | Participez | Hébergement | Contacts
Accueil Conception Java DotNET Visual Basic  C  C++ Delphi MS-Office SQL & SGBD Oracle  4D  Business Intelligence
Club Emploi Blogs   TV   Dév. Web PHP XML Python Autres 2D-3D-Jeux Sécurité Windows Linux PC Mac
ACCUEIL BSD FORUM BSD TUTORIELS BSD LIVRES BSD SYSTEMES BSD BSD TV UNIX

Packet Filter sur les systèmes BSD : les tables

Date de publication : 29/10/2007

Par julp (Autres articles)
 

Que sont les tables ? Pourquoi et comment les utiliser ?

Celles-ci sont utilisées par certains programmes externes pour interagir avec Packet Filter afin de traiter différemment de nouvelles adresses sans avoir à relire les règles. Vous vous rendrez vite compte de leur intérêt en les mettant à profit par exemple pour la constitution de listes noires (ou blanches) dynamiques.


1. Présentation
1.1. Une amélioration notable des listes et macros
1.2. Syntaxe
1.2.1. Déclaration d'une table
1.2.2. Utilisation dans les règles
2. Manipulation en ligne de commande avec pfctl
2.1. Limitations de pfctl
2.2. Lister les adresses d'une table
2.3. Ajouter des adresses à une table
2.4. Supprimer des adresses à une table
2.5. Recharger le contenu de la table
2.6. Remplacer l'ensemble des adresses
2.7. Tester si une adresse fait partie de la table
2.8. Les statistiques d'une table
2.9. Vider/Supprimer une table
3. Les différentes propriétés apposables aux tables
3.1. Les tables immuables
3.2. Les tables persistantes
3.3. Les tables dont le contenu réside dans un fichier
3.4. Combinaison de plusieurs propriétés
4. Autres éléments syntaxiques liés aux tables
4.1. Le mot-clé "self"
4.2. Les négations
4.3. Les listes
5. Utilitaires autour des tables
5.1. expiretable : supprimer des entrées obsolètes à intervalle régulier
6. Conclusion
6.1. Epilogue
6.2. Remerciements


1. Présentation


1.1. Une amélioration notable des listes et macros

Une table permet le regroupement d'adresses au sein d'une même entité. En quoi sont-elles différentes aux listes que l'on peut définir avec Packet Filter et que l'on peut réutiliser grâce aux macros (voir exemple ci-dessous) ?
##### Macros #####
me = "sis0"
tcpflags = "flags S/SFRA"
workstations = "{ 192.168.0.1 192.168.0.2 192.168.0.3 192.168.0.4 192.168.0.5 }"

##### Règles #####
block all
pass in quick inet proto tcp from $workstations to $me port ssh $tcpflags keep state
pass in quick inet proto tcp from $workstations to $me port http $tcpflags keep state
Les spécificités des tables par rapport aux listes standard sont les suivantes :
  • Utilisation directe et multiple dans les règles, comparable à une macro
  • Les recherches d'une adresse sont beaucoup plus rapides (utilise moins de mémoire et de temps CPU qu'une simple liste)
  • Existence qui va au-delà du fichier de configuration où elles sont définies puisqu'elles résident ensuite en mémoire ce qui permet de leur appliquer des modifications au niveau de leur contenu. Ces modifications sont immédiatement prises en compte par Packet Filter sans avoir à recharger les règles ou à procéder à une quelconque manipulation.

1.2. Syntaxe


1.2.1. Déclaration d'une table

Le contenu d'une table est sensiblement identique à celui que l'on peut fournir comme adresse source ou de destination dans les règles en temps normal. Il peut prendre les différentes formes suivantes :
  • Une adresse IP (version 4 comme 6), exemples : 192.168.0.1, 66.80.97.134
  • Une adresse en notation CIDR (version 4 comme 6) : 192.168.0.0/24
  • Un nom de machine, comme www.developpez.com, qui sera automatiquement remplacé par les adresses IP correspondantes (versions 4 et 6) à condition de pouvoir effectuer cette résolution (ne pas oublier de construire des règles visant à autoriser le trafic DNS)
  • Le nom d'une interface (sis1, lo0, etc), qui sera substituée par la liste des adresses qui lui sont attribuées
  • Le nom d'une interface suivie de la notation CIDR, exemple sis0/8
  • Le nom d'une interface suivie de :network, :broadcast, :peer ou :0 correspondant respectivement à l'adresse réseau, l'adresse de broadcast, l'adresse d'un pair sur un lien point à point ou l'adresse principale affectée à une carte réseau (ne tient pas compte des alias)
  • Le mot clé self
  • L'une des formes antérieures précédée d'une négation
Exemples de déclarations de quelques tables :
table <sites_http_autorises> { www.developpez.net, www.developpez.com, www.developpez.be }
table <serveurs_dns_internes> { 192.168.0.1, 192.168.0.101 }
table <blacklist> { 125.60.86.214 208.159.106.199 81.237.54.31 76.89.10.213 }
table <reseaux_internes> { sis1:network sis2:network }
Les signes < et > ne sont pas le résultat d'une erreur typographique et encadrent systématiquement le nom d'une table. On peut ainsi reconnaître d'un simple coup d'oeil qu'il s'agit d'une table, tout comme les macros sont précédées du signe dollar ($).

Les virgules séparant les différents éléments de la liste sont facultatives. Libre à vous donc de les omettre ou de les faire figurer.

warning L'utilisation des noms de machine (DNS) est à éviter autant que possible pour des raisons de sécurité.

L'utilisation d'adresses dynamiques (protocole DHCP) n'est ici pas gérée puisque les éléments d'une table sont systématiquement traduits en une adresse IP à leur intégration dans la table.

1.2.2. Utilisation dans les règles

Les tables peuvent être employées dans les différentes règles de manière quasi similaire à une adresse. Voici une liste exhaustive des emplacements où elles peuvent figurer :
  • Comme ensemble d'adresses source ou de destination dans les règles de filtrage (pass et block)
  • Comme ensemble d'adresses source ou de destination dans les règles de traduction d'adresse (nat et binat)
  • Comme ensemble d'adresses source ou de destination dans les règles de redirection (rdr)
  • Pour constituer une liste d'attaquants à l'aide du mot-clé overload suivant le comportement de l'hôte distant (la mesure est effectuée en nombre de connexions sur un certain laps de temps)
Lors de l'emploi d'une table dans une règle, il suffit de reprendre son nom à l'endroit souhaité sans oublier de l'encadrer de ses signes distinctifs < et >. Petit exemple pour illustrer :
##### Macros #####
if = "sis0"
tcpflags = "flags S/SFRA"

##### Tables #####
# Liste noire des machines dont l'activité est suspecte
table <blacklist> { 125.60.86.214 208.159.106.199 81.237.54.31 76.89.10.213 }
# Liste des serveurs web recencés
table <serveurs_http> { 192.168.0.102, 192.168.0.103 }

##### Règles #####
# Les paquets des machines blacklistées sont bloqués nets
block in quick on $if from <blacklist> to any
# Le trafic vers les serveurs Web est autorisé (ainsi que leurs réponses)
pass in quick on $if inet proto tcp from any \
	to <serveurs_http> port { http https } $tcpflags keep state
Les tables ne font l'objet d'aucune restriction au niveau de leur emplacement. Elles doivent cependant être "déclarées" avant une quelconque référence dans vos règles.


2. Manipulation en ligne de commande avec pfctl

info La commande pfctl accepte en paramètre exactement les mêmes types d'informations comme adresse (adresses IP, noms DNS, interfaces, ...) que cité précédemment. Ajoutons que celle-ci n'est d'ailleurs pas cantonnée à l'unique manipulation des tables.
Les exemples qui suivent seront basés sur la déclaration d'une table nommée blacklist visant à interdire les paquets de certaines adresses IP suite à des activités plus ou moins obscures :
table <blacklist> { 125.60.86.214 208.159.106.199 81.237.54.31 76.89.10.213 }

2.1. Limitations de pfctl

Il faut savoir que pfctl est soumis à certaines restrictions de la part du système et de l'implémentation de la commande elle-même :
  • La commande pfctl n'altère que le contenu des tables en mémoire et ne répercute en aucun cas les différents changements demandés sur un quelconque fichier de configuration. Si vous avez besoin de synchroniser ces modifications en vue de les réappliquer au prochain démarrage de Packet Filter vous devrez le faire manuellement ou éventuellement à l'aide d'un script.
  • Il vous sera impossible d'agir sur les tables à l'aide de pfctl si le niveau de sécurité du noyau atteint la valeur 2 sur NetBSD ou OpenBSD et la valeur 3 pour FreeBSD. Cette restriction concerne de manière plus générale les règles de filtrage qui sont ainsi chargées une bonne fois pour toutes avant le changement de ce niveau de sécurité.

2.2. Lister les adresses d'une table

Vous pouvez à tout moment consulter le contenu d'une table à l'aide de pfctl. Illustration avec notre table blacklist :
pfctl (-v) -t blacklist -T show
Qui produira la sortie suivante :
   76.89.10.213
   81.237.54.31
   125.60.86.214
   208.159.106.199

2.3. Ajouter des adresses à une table

Imaginons maintenant que nous voulions ajouter de nouvelles adresses à notre liste noire :
pfctl (-v) -t blacklist -T add 216.194.109.203 88.240.211.27
Notre table sera désormais composée des six adresses suivantes :
   76.89.10.213
   81.237.54.31
   88.240.211.27
   125.60.86.214
   208.159.106.199
   216.194.109.203
info La table sera créée si celle-ci n'existe pas déjà.

2.4. Supprimer des adresses à une table

Nous avons besoin de supprimer deux adresses de celle-ci :
pfctl (-v) -t blacklist -T delete 125.60.86.214 76.89.10.213
Cette table contiendra de nouveau quatre adresses :
   81.237.54.31
   88.240.211.27
   208.159.106.199
   216.194.109.203

2.5. Recharger le contenu de la table

Nous souhaitons réinitialiser une table à partir de sa déclaration :
pfctl (-v) -t blacklist -T load -f /root/pf.conf
L'option -f est nécessaire pour indiquer le fichier où est définie la table en question.

Nous obtenons bien le contenu tel que la table a été déclarée :
   76.89.10.213
   81.237.54.31
   125.60.86.214
   208.159.106.199

2.6. Remplacer l'ensemble des adresses

Il est possible d'aller un peu plus loin en remplaçant l'intégralité des adresses actuelles d'une liste par de nouvelles. Pour cela on utilise la sous-commande replace, exemple :
pfctl (-v) -t blacklist -T replace 115.79.79.48 143.59.174.112 139.102.183.50
Le contenu sera désormais le suivant :
   115.79.79.48
   139.102.183.50
   143.59.174.112
info La sous-commande replace, comme add, crée la table si cette dernière n'existe pas.

2.7. Tester si une adresse fait partie de la table

pfctl vous permet même de savoir si une adresse est actuellement définie dans la table donnée :
pfctl (-vv) -t blacklist -T test 115.79.79.48 www.developpez.com
Indiquera qu'il y a correspondance avec l'une des deux adresses (sur 115.79.79.48 et aucune avec www.developpez.com).


2.8. Les statistiques d'une table

Vous pouvez obtenir différentes informations (nombre de paquets bloqués ou passés) sur une table en particulier avec la commande suivante :
pfctl -vv -t blacklist -T show
Ou bien sur l'ensemble des tables avec :
pfctl -vv -s Tables
Pour réinitialiser les statistiques d'une table vous pouvez utiliser la sous-commande zero. Exemple avec notre table blacklist :
pfctl -t blacklist -T zero

2.9. Vider/Supprimer une table

Vous pouvez bien évidemment vider la table :
pfctl -t blacklist -T flush
Ou encore la supprimer mais celle-ci n'aura plus aucune existence en mémoire et ne sera plus, par conséquent, manipulable via pfctl :
pfctl -t blacklist -T kill
info Les règles faisant référence à une table supprimée subsistent mais deviennent donc, par conséquent, inutiles. Vous pouvez la recréer à tout moment à l'aide des commandes add ou replace (voir plus haut).

3. Les différentes propriétés apposables aux tables


3.1. Les tables immuables

Il est possible de rendre une table insensible à toute modification. Cet état est introduit par le mot-clé const. En effet, par défaut (en son absence) une table peut être modifiée par l'utilitaire pfctl, que nous avons étudié en détail ci-dessus.

Voici un exemple d'une telle table qu'il ne nous sera pas possible d'altérer même pour y ajouter une adresse :
table <serveurs_dns> const { 192.168.0.1 192.168.0.101 }

3.2. Les tables persistantes

Par défaut, le noyau se débarrasse automatiquement des tables inutilisées dans le sens où elles ne sont pas référencées par une quelconque règle. Cela peut s'avérer particulièrement gênant lorsque cette table est amenée à être utilisée par un programme externe et dont des règles sont ajoutées ou supprimées en fonction des besoins, bien souvent à l'aide du mécanisme appelé ancre (exemples courants : authpf ou encore certains mandataires FTP intégrés à pf).

La solution consiste à utiliser le mot-clé persist, rendant ainsi la table résidente en mémoire quoiqu'il advienne. Exemple de déclaration d'une table vide dont la persistance est assurée :
table <blacklist> persist
Cette table, blacklist, ici vide vous sera donc toujours accessible avec pfctl. Notez que vous pouvez également initialiser cette table à l'aide d'une ou plusieurs valeurs :
table <blacklist> persist { 67.80.122.54 67.80.122.55 }

3.3. Les tables dont le contenu réside dans un fichier

Packet Filter vous offre également la possibilité de stocker les adresses de votre table dans un fichier annexe, introduisant de ce fait un nouveau mot-clé : file. Voyons tout d'abord comment déclarer ce genre de tables quelque peu particulier à l'aide d'un exemple :
table <whitelist> file "/root/whitelist"
Puis on place les adresses, pouvant prendre l'une des formes citées lors de la présentation, à raison d'une adresse par ligne, dans le fichier indiqué. Ce dernier devra impérativement exister même vide sous peine de voir apparaître des erreurs fatales lors du chargement des règles. A noter, qu'il est même possible d'y insérer des commentaires, en les faisant précéder d'un caractère dièse (#). Voici le contenu de la table whitelist dont on prendra soin de mettre dans le fichier /root/whitelist tel que convenu :
/root/whitelist :
# Developpez
www.developpez.com
www.developpez.net
www.developpez.be
# Partenaires
43.204.225.199
75.186.215.37
Quand l'utilisation de ce type de table est-il justifié ? Lorsque le nombre d'adresses devient conséquent ou bien lorsque vous avez besoin d'ajouter ou de supprimer des adresses et de mémoriser ce changement d'état pour le prochain démarrage de Packet Filter, ce format étant fortement pratique pour des manipulations à l'aide de commandes shell par exemple. Ainsi pour ajouter une nouvelle adresse on pourrait utiliser un script semblable à celui-ci :
#!/bin/sh

# Partie concernant les paramètres du programme
progname=`basename $0`
args=`getopt t:f: $*`

usage() {
    echo "Usage: $progname -t table -f fichier adresse1 ... adresseN"
    exit 2
}

[ $? -eq 0 ] || usage

set -- $args

for i
do
    case "$i"
    in
        -t)
            table="$2"
            shift; shift;;
        -f)
            fichier="$2"
            shift; shift;;
        --)
            shift; break;;
    esac
done

[ -z "$fichier" -o -z "$table" -o $# -lt 1 ] && usage

# On ajoute les adresses à la table et au fichier correspondant
pfctl -t $table -T add $*
[ $? -eq 0 ] || exit $?
for arg in $*
do
    echo "$arg" >> $fichier
done

3.4. Combinaison de plusieurs propriétés

Il est parfaitement possible de combiner plusieurs voir les trois états (persist, const et file) abordés dans cette partie à la fois. Ainsi, l'exemple qui présente le plus d'intérêt serait de réaliser une table dont le contenu est chargé à partir d'un fichier annexe et déclarée constante pour qu'elle ne puisse pas être modifiée par l'utilitaire pfctl :
# En plaçant const avant file
table <blackist> const file "/root/blacklist"
# En plaçant const après file
table <blacklist> file "/root/blacklist" const

4. Autres éléments syntaxiques liés aux tables


4.1. Le mot-clé "self"

Ce mot-clé particulier est substitué par l'ensemble des adresses IP utilisées par votre machine. Ceci inclut également votre interface réseau de bouclage (également appelée loopback sous l'identifiant lo0 ou lo). Exemple, soit la configuration réseau suivante :
[root@freebsd ~]# ifconfig
de0: flags=8843<UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST> mtu 1500
        inet 192.168.0.1 netmask 0xffffff00 broadcast 192.168.0.255
        ether 00:03:ff:3d:94:f9
        media: Ethernet autoselect (100baseTX)
        status: active
lo0: flags=8049<UP,LOOPBACK,RUNNING,MULTICAST> mtu 16384
        inet6 ::1 prefixlen 128
        inet 127.0.0.1 netmask 0xff000000
self retournera les adresses suivantes :
  • l'adresse IP attribuée à la carte réseau de0 : 192.168.0.1
  • les adresses IP respectivement en version 4 et 6 affectées à la boucle locale : 127.0.0.1 et ::1

4.2. Les négations

Les négations sont utilisées pour exclure un sous-ensemble (adresse ou sous-réseau) d'un ensemble plus important (réseau) qui peut éventuellement figurer dans la même table. Afin d'exclure une adresse ou un ensemble (notation CIDR), il suffit de faire précéder cet élément d'un point d'exclamation (!). Prenons un exemple pour y voir plus clair :

On dispose d'un important réseau interne privé (rfc1918) découpé en plusieurs sous-réseaux dont un exclusivement destiné au service comptabilité dont on souhaite interdire l'accès à Internet, en ayant recours à une table, à l'exception d'un serveur situé dans ce service. Les affectations sont les suivantes :
  • 192.168.0.0/16 : le réseau interne dans son intégralité
  • 192.168.2.0/24 : le réseau interne réservé à la comptabilité
  • 192.168.2.1 : un serveur (dans la partie comptabilité) effectuant des transferts programmés avec l'extérieur
La table qui découle de cette politique est alors la suivante :
table <internet_autorise> { 192.168.0.0/16 !192.168.2.0/24 192.168.2.1 }
Et les règles semblables à celles-ci :
##### Macros #####
# Interface interne
int_if = "sis0"
tcpflags = "flags S/SFRA"

# Bloquer par défaut
block all
# Autorise les paquets TCP sortants vers Internet, ainsi que leurs réponses
pass in quick on $int_if inet proto tcp from <internet_autorise> \
	to any port { http https ... } $tcpflags keep state
La correspondance se fera sur l'adresse la plus spécifique. Examinons quelques cas :
  • 192.168.3.63 : la correspondance sera établie sur l'entrée 192.168.0.0/16 de la table, le paquet sera autorisé à passer
  • 192.168.2.47 : aucune correspondance car toute la tranche 192.168.2.X est exclue à l'aide de la négation, le paquet sera bloqué
  • 192.168.2.1 : la correspondance aura lieu sur 192.168.2.1 - la négation du sous-réseau 192.168.2 sera ignoré car son poids est moins important que celui de l'adresse elle-même, le paquet passera
Vous pouvez procéder à ces tests en utilisant la commande présentée dans Tester si une adresse fait partie de la table en faisant apparaître l'option de verbosité maximale (-vv).


4.3. Les listes

Ces mêmes listes qui nous ont permis d'introduire les tables peuvent parfaitement contenir une ou plusieurs tables comme éléments. Encore mieux elles peuvent contenir à la fois des tables et des adresses. En voici un exemple :
ext_if = "de0"
maison = "83.241.141.246"

table <partenaires> const { 73.184.228.146 24.1.3.149 186.220.104.61 88.240.211.27 }
table <collegues> { 142.80.125.240 131.254.222.237 }

# [...]

pass in quick on $ext_if from { <partenaires> $maison <collegues> } to $ext_if

# [...]
La règle pass pourrait très bien être écrite sous des formes moins condensées équivalentes :
pass in quick on $ext_if from { <partenaires> <collegues> } to $ext_if
pass in quick on $ext_if from $maison to $ext_if

# ou encore

pass in quick on $ext_if from <partenaires> to $ext_if
pass in quick on $ext_if from <collegues> to $ext_if
pass in quick on $ext_if from $maison to $ext_if

5. Utilitaires autour des tables


5.1. expiretable : supprimer des entrées obsolètes à intervalle régulier

Ce petit programme permet de retirer toutes les entrées qui ont passées plus d'un certain temps, que vous aurez fixé, au sein d'une table.

Son exécution requiert les droits de lecture et d'écriture sur le fichier spécial /dev/pf.

Installation :
  • FreeBSD, il ne nous sera pas nécessaire d'aller bien loin puisque vous pouvez trouver expiretable parmi les logiciels portés :
    cd /usr/ports/security/expiretable
    make install
    
  • Il en est de même pour OpenBSD :
    cd /usr/ports/sysutils/expiretable
    make install
    
  • En revanche il en est tout autrement sur NetBSD puisque ce logiciel ne figure pas parmi les paquetages :
    cd ~
    ftp http://expiretable.fnord.se/expiretable-0.6.tar.gz
    tar xzf expiretable-0.6.tar.gz
    ftp http://julp.developpez.com/bsd/packet-filter/tables/fichiers/netbsd-expiretable-0.6.patch
    patch < netbsd-expiretable-0.6.patch
    cd expiretable-0.6
    make
    make install
    
Options de lancement :
  • -a ancre : spécifie l'ancre contenant la table (privée).
  • -d : lancement en tâche de fond. Implique l'option -p.
  • -n : indique seulement les adresses qui vont être effacées sur la sortie standard mais ne procède pas à cette suppression.
  • -p : modifie le comportement normal du programme qui, par défaut, est de quitter. Il s'exécute ainsi périodiquement (fonction de la durée fournie).
  • -t durée : définit la durée de validité maximale d'une entrée dans cette table. Celle-ci peut être exprimée en secondes ou à l'aide de suffixes d (jour), h (heure), m (minute) ou s (seconde).
  • -v : sortie verbeuse. Doublez la pour obtenir un maximum d'informations.
Exemple d'utilisation : supprimer régulièrement (exécution en tâche de fond) toutes les entrées datant de plus d'une heure de la table utilisateurs_authpf.
expiretable -d -p -t 1h utilisateurs_authpf

6. Conclusion


6.1. Epilogue

Toutes les particularités liées de façon directe ou non aux tables ont été abordées par le présent article. Il ne vous reste qu'à mettre en pratique ces connaissances au sein de vos différentes règles et pourquoi pas rédiger des scripts pour profiter de toute leur dynamicité.

Liens Developpez :

6.2. Remerciements

J'adresse mes plus vifs remerciements à mon relecteur Biglo.

Sans oublier les membres de la section Linux pour leurs conseils avisés et leur soutien (ovh et Biglo).



Valid XHTML 1.1!Valid CSS!

Copyright © 2007 julp. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à 3 ans de prison et jusqu'à 300 000 E de dommages et intérêts. Cette page est déposée à la SACD.

Responsables bénévoles de la rubrique BSD : julp et Olivier Régnier - Contacter par EMail :
Vos questions techniques : forum d'entraide BSD - Publiez vos articles, tutoriels et cours
et rejoignez-nous dans l'équipe de rédaction du club d'entraide des développeurs francophones
Nous contacter - Copyright © 2000-2008 www.developpez.com - Legal informations.