356 lines
14 KiB
Markdown
356 lines
14 KiB
Markdown
# NFTables
|
|
|
|
## Introduction
|
|
|
|
`NFTables` est un outil permettant de de gérer une partie de la gestion des
|
|
paquets réseaux dans une machine Linux. Cet outil supplante ses prédécesseurs
|
|
xtables (iptables, ip6tables, arptables, ...) et son support est inclus dans les
|
|
noyaux Linux modernes. Lorsqu'un paquet traverse, sort de ou entre sur votre
|
|
machine, il parcourt un certain chemin de prises de décisions afin de décider de
|
|
son sort (jeté, accepté (= intouché), modifié, ...).
|
|
|
|
## Structure de NFTables
|
|
|
|
NFTables permet d'organiser les règles définissant le comportement à avoir avec
|
|
un paquet en fonction de certains critères.
|
|
|
|
Les règles ne sont pas appliquées par NFTables à n'importe quel moment. En
|
|
effet, certaines règles ne concernent que les paquets issus de la machine,
|
|
d'autre les paquets sortant, ...
|
|
Afin de regrouper les règles agissant au même endroit, les règles de NFTables
|
|
sont regroupées en chaînes d'actions, lesquelles concernent un crochet de prise
|
|
de décision du noyau.
|
|
|
|
Là encore, on peut souhaiter avoir des chaînes différentes pour les paquets IP,
|
|
IPv6, arp, ... . Pour cette raison, les chaînes sont regroupées dans des tables,
|
|
chacune ne concernant un ou plusieurs type de protocole (généralement de couche
|
|
3).
|
|
|
|
La structure des règles NFTables ainsi obtenue devient :
|
|
|
|
```txt
|
|
+------------------------------------------------------------+
|
|
| Table concernant les paquets IP |
|
|
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
|
|
| |
|
|
| +----------------------------------------------------+ |
|
|
| | Chaîne concernant le crochet du filtre d'entrée | |
|
|
| | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | |
|
|
| | | |
|
|
| | +--------------------------+ | |
|
|
| | | Règle 1 | | |
|
|
| | | ~~~~~~~ | | |
|
|
| | | paquet TCP ? | | |
|
|
| | | à destination du port 53 | | |
|
|
| | | vient-il de a.b.c.d | | |
|
|
| | | action: rejeter | | |
|
|
| | +--------------------------+ | |
|
|
| | | |
|
|
| | +----------------------------------+ | |
|
|
| | | Règle 2 | | |
|
|
| | | ~~~~~~~ | | |
|
|
| | | paquet TCP ? | | |
|
|
| | | lié à une connexion déjà établie | | |
|
|
| | | action: accepter | | |
|
|
| | +----------------------------------+ | |
|
|
| | | |
|
|
| | ... | |
|
|
| +----------------------------------------------------+ |
|
|
| |
|
|
| +----------------------------------------------------+ |
|
|
| | Chaîne concernant le crochet du NAT en entrée | |
|
|
| | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | |
|
|
| | | |
|
|
| | +----------------------------------+ | |
|
|
| | | Règle 1 | | |
|
|
| | | ~~~~~~~ | | |
|
|
| | | paquet provenant de a.b.c.d/m | | |
|
|
| | | paquet sortant par l'interface x | | |
|
|
| | | action: snat to x.x.x.x | | |
|
|
| | +----------------------------------+ | |
|
|
| | | |
|
|
| | ... | |
|
|
| +----------------------------------------------------+ |
|
|
| |
|
|
+------------------------------------------------------------+
|
|
|
|
+----------+
|
|
| Table 2 |
|
|
| ~~~~~~~ |
|
|
| ... |
|
|
+----------+
|
|
|
|
...
|
|
```
|
|
|
|
Comme le décrit le schéma précédent, les tables sont juxtaposées les unes les
|
|
autres. Lorsqu'un paquet est traité, selon le protocole utilisé, aucune, une ou
|
|
plusieurs tables seront utilisées pour charger les règles à appliquer. À
|
|
chaque étape de traitement du paquet, les chaînes correspondant au paquet seront
|
|
alors appliquées.
|
|
|
|
Un paquet parcourt les règles d'une chaîne dans l'ordre de leur écriture.
|
|
Si une action est indiquée dans le corps d'une règle, elle sera exécutée si
|
|
toutes les conditions la précédant dans l'écriture de la règle sont vérifiées.
|
|
|
|
Le parcourt d'une chaîne s'arrête lorsqu'un verdict s'applique au paquet
|
|
considéré. Un verdict est une action particulière parmi peut être :
|
|
|
|
* l'abandon du paquet
|
|
|
|
* l'abandon du paquet avec choix du message retourné à l'émetteur
|
|
|
|
* L'acceptation du paquet
|
|
|
|
* Le saut à une autre chaîne (avec retour à la chaîne en cours ensuite)
|
|
|
|
* Le saut à une autre chaîne (sans retour à la chaîne en cours après)
|
|
|
|
## Table
|
|
|
|
Une table est caractérisée par :
|
|
|
|
* Un nom
|
|
|
|
* Un type de paquet : principalement ip (pour l'IPv4), ip6 (pour l'IPv6) et inet
|
|
(pour l'IPv4 et IPv6).
|
|
|
|
Une table peut être ajoutée avec la commande `nft add table <nom de la table>`
|
|
si vous souhaitez utiliser la commande `nft`, ou avec le morceau de
|
|
configuration suivant :
|
|
|
|
```txt
|
|
table <type> <nom de la table> {
|
|
[contenu de la table (chaînes)]
|
|
}
|
|
```
|
|
|
|
## Chaîne
|
|
|
|
Une chaîne est caractérisée par :
|
|
|
|
* La table dans laquelle la chaîne se trouve
|
|
|
|
* Le nom de la chaîne
|
|
|
|
Lors de la création / utilisation d'une chaîne, il faut aussi décider !
|
|
|
|
* Le crochet NFTables concerné par la chaîne (input, output, ...)
|
|
|
|
* Le type de la chaîne (filtre, nat, raw, mangle)
|
|
|
|
* La priorité de la chaîne (filter (=0), srcnat (=-100), dstnat (=100)).
|
|
|
|
Une chaîne peut aussi avoir un verdict par défaut sur les paquet (accept, drop,
|
|
reject [with MSG], ...).
|
|
|
|
Une chaîne peut être créée par la commande
|
|
|
|
```txt
|
|
nft add chain <type de la table> <nom de la table> <nom de la chaîne> '{ type <type> hook <crochet> priority <priorité>; [policy <verdict par défaut>;] }'
|
|
```
|
|
|
|
ou par le morceau de configuration textuelle suivant :
|
|
|
|
```txt
|
|
chain <nom de la chaîne> {
|
|
type <type> hook <crochet> priority <priorité> ; policy <verdict par défaut>;
|
|
[contenu de la chaîne]
|
|
}
|
|
```
|
|
|
|
## Règle
|
|
|
|
Une règle est caractérisée par la chaîne dans laquelle elle est contenue.
|
|
|
|
Dans la définition d'une règle, il est possible d'indiquer :
|
|
|
|
* des conditions écrites `<type> <valeur>`, où le type est un champ du
|
|
paquet et la valeur est la valeur du champ, comme par exemple `ip protocol
|
|
udp` (type : `ip protocol` représentant le champ du protocole de couche 4 dans
|
|
un paquet IPv4, valeur `tcp`).
|
|
|
|
Remarque: Il est possible de nier une condition.
|
|
Remarque': Il est possible d'utiliser des ensembles dans les conditions (voir
|
|
plus bas).
|
|
|
|
Les types peuvent être décrits par `nft describe <type>`.
|
|
|
|
* des actions, parmi lesquelles "compter les paquets" (`counter`), logger les
|
|
paquets (`log prefix ...`).
|
|
|
|
Pour ajouter une règle, il est possible d'utiliser
|
|
|
|
```txt
|
|
nft add rule <type de la table> <nom de la table> <nom de la chaîne> '<règle>'`
|
|
```
|
|
|
|
ou d'ajouter la règle sur une ligne dans la configuration textuelle.
|
|
|
|
## Ensembles et applications
|
|
|
|
### Ensembles
|
|
|
|
Il est courant d'utiliser des ensembles lors de la définition d'un pare-feu, non
|
|
seulement parce qu'ils permettent de réduire le nombre de règles à écrire, mais
|
|
aussi parce qu'ils sont plus efficaces, NFTables pouvant gérer les tests
|
|
sous-jacents luiel(de crapaud)-même.
|
|
|
|
Un ensemble peut être :
|
|
|
|
* anonyme (eg: `{A, B, C}`). Dans ce cas, l'ensemble est statique.
|
|
|
|
* nommé. Dans ce cas, l'ensemble peut être dynamique et avoir diverses options
|
|
et paramètres associés (eg: permettre de stocker des intervalles, associer
|
|
une durée de vie aux éléments (avec éventuellement un délai par défaut),
|
|
compter des paquets, une taille).
|
|
|
|
L'appartenance à un ensemble `E` est un critère valide noté `{...} @E` (sa
|
|
négation est notée `{...} != @E`).
|
|
L'ajout ou retrait d'un élément à un ensemble `E` est une action valide (si
|
|
l'ensemble n'est pas constant) et se note `(add|delete) @E {...}`.
|
|
|
|
Dans un fichier de configuration, un ensemble est déclaré (dans une table)
|
|
par :
|
|
|
|
```txt
|
|
set <nom de l'ensemble> {
|
|
type <type d'éléments>;
|
|
}
|
|
```
|
|
|
|
Le type des éléments peut être donné explicitement ou à l'aide de
|
|
`typeof ...`, ou `...` est un critère valide (eg:
|
|
`typeof tcp dport` est équivalent à `type inet_service`).
|
|
|
|
Il est également possible de réaliser des produits cartésiens de types. Par
|
|
exemple, le type `ipv4_addr . inet_service` est le type des pairs d'adresse
|
|
IPv4 et des ports.
|
|
|
|
Il y a de nombreuses options utiles lors de la déclaration d'un ensemble :
|
|
|
|
* Le nombre d'éléments max (`size <nombre>`). La valeur par défaut est 65536.
|
|
|
|
* Les drapeaux (`flags ...`), dont `timeout` ou `intervals`
|
|
|
|
* Les éléments initiaux (`elements = { e0, ..., en }`)
|
|
|
|
### Applications
|
|
|
|
TODO: `nft (add|...) map ...`
|
|
|
|
## Interaction avec le pare-feu
|
|
|
|
Il est souvent pratique d'ajuster les règles d'un pare-feu (ajout d'un service,
|
|
de règles, réordonnancement des règles, ...). Un moyen naïf pour faire cela est
|
|
de réinitialiser le pare-feu et de charger un nouveau fichier de configuration.
|
|
L'inconvénient est que cela :
|
|
|
|
* vide les ensembles et applications remplis dynamiquement
|
|
|
|
* permet à des intrus d'établir des connections illicites si elles sont
|
|
initialisées durant la remise à zéro (moins important car la recharge d'un
|
|
fichier de configuration est rapide).
|
|
|
|
### La commande `nft`
|
|
|
|
La commande `nft` permet certes d'ajouter des tables, des chaînes et des règles
|
|
dynamiquement, comme expliqué ci-dessus. Mais elle permet également de corriger
|
|
des erreurs, ce qui peut être pratique par moments.
|
|
|
|
* Suppression ou remplacement d'une règle par une autre :
|
|
|
|
* Pour la suppression :
|
|
|
|
```bash
|
|
nft delete rule <type de la table> <nom de la table> <nom de la chaîne> handle <numéro de la poignée (du handler en anglais)>
|
|
```
|
|
|
|
* Pour le remplacement :
|
|
|
|
```bash
|
|
nft replace rule <type de la table> <nom de la table> <nom de la chaîne> handle <numéro de la poignée (du handler en anglais)> <new_rule>
|
|
```
|
|
|
|
__Cas d'usage :__
|
|
|
|
* si vous utilisez un ensemble anonyme pour gérer quels ports
|
|
sont ouverts aux nouvelles connections TCP, vous pouvez le mettre à jour
|
|
facilement.
|
|
|
|
* si vous voulez qu'une règle filtrant les accès TCP permette aussi l'UDP,
|
|
vous pouvez par exemple souhaiter remplacer `tcp dport` par
|
|
`meta l4proto { tcp, udp} td dport`
|
|
|
|
* Ajout d'une règle à un endroit précis dans le pare-feu :
|
|
Cela peut être fait avec les règles
|
|
`nft <add|insert> rule <type table> <nom table> <nom chaîne> handle <numéro> <règle>`.
|
|
|
|
`add` permet d'insérer la règle après la poignée spécifiée. Si aucune poignée
|
|
n'est spécifiée, la règle est ajoutée à la fin de la chaîne.
|
|
|
|
`insert` permet d'insérer la règle avant la poignée spécifiée. Si aucune
|
|
poignée n'est spécifiée, la règle est ajoutée au début de la chaîne.
|
|
|
|
* Options pratiques (`nft -option_pratique ...`) :
|
|
|
|
* `-t` permet de ne pas afficher le contenu des ensembles et applications
|
|
dans la sortie de la commande qui suit
|
|
* `-a` permet d'afficher les numéros de poignée
|
|
* `-n` permet d'afficher les noms des services plutôt que les ports
|
|
(déconseillé car la fonction des ports dans les noms de service n'est pas
|
|
injective)
|
|
|
|
## Journalisation et surveillance
|
|
|
|
### Journalisation
|
|
|
|
Il peut être intéressant d'écrire des entrées dans le journal d'un routeur. Il
|
|
est d'usage au Cr@ns de noter toutes les nouvelles connections.
|
|
|
|
Cela peut être fait grâce à l'action `log prefix "..."`, ou `"..."` est le
|
|
préfixe à utiliser dans le journal du système.
|
|
|
|
### Surveillance
|
|
|
|
Il est possible de demander à NFTables d'afficher des messages de débogage,
|
|
liés entre autre aux changements, retraits ou ajouts de règles, de tables, ... à
|
|
l'aide de la commande `nft monitor`
|
|
|
|
* __Changements__
|
|
|
|
* Changements précis : `nft monotor ...
|
|
<rules|chains|ruleset|tables|sets|elements>`, où `...` peut être rien,
|
|
`destroy` ou `add` selon si l'on veut tout entendre, n'entendre que les
|
|
retraits ou les ajouts.
|
|
|
|
* Changements quelconques : `nft monotor` pour tout entendre (y compris les
|
|
parcours des paquets marqués décrits ci-dessous).
|
|
|
|
* __Débogage__
|
|
À des fins de débogage, il est parfois pratique de savoir par quelles règles
|
|
un paquet donné est passé et quelle verdict il a subit. À cette fin, NFTables
|
|
permet de marquer le paquet à l'aide de l'action `meta nftrace set 1`.
|
|
|
|
Les événements internes de NFTables concernant ce paquet peuvent ensuite être
|
|
affichés avec la commande `nft monitor trace`.
|
|
|
|
## Divers
|
|
|
|
* `nft flush ruleset` vide la table
|
|
|
|
* `nft -f <file>` lit la configuration d'un ficher et l'applique
|
|
|
|
* `systemctl reload nftables` a le même effet que `nft -f /etc/nftables.conf` si
|
|
le service existe.
|
|
|
|
* La famille d'une table peut être omise dans age de la commande `nft` s'il n'y
|
|
a pas d'ambigüité.
|
|
|
|
* Si aucune chaîne / table / règle n'est traversée, le paquet est accepté par
|
|
défaut (si on ne filtre pas, tout passe)
|
|
|
|
* Il est possible d'utiliser des variables dans un fichier de configuration.
|
|
Leur valeur sera substituée lors de la lecture du fichier. Un exemple est
|
|
donné dans le fichier `services/firewall.md`.
|