Site Logo
MBS - Yanis MERCIER
Cover Image

Actions Avancées sur NFTables

Posted on 7 mins

Nftables Administration

Pour l’un de mes derniers oraux à l’ESGI, j’ai créer un cours sur complet NFTables principalement ciblé pour les admins sys’ confirmés. J’aimerais refaire un point sur une poignée de ses actions intéressante

NFTables

En tant que remplaçant d’iptables, NFTables est devenu l’outil de filtrage de paquets par défaut sur la plupart des distributions Linux. Grâce à une syntaxe plus simple et une architecture flexible, il offre des possibilités avancées pour la gestion des règles de pare-feu. bla bla bla j’arrête mon prosélytisme sur NFTables

Pour rappel, voici un exemple de se que à quoi des règles NFTables ressemblent:

#!/usr/sbin/nft -f
flush ruleset

define eternet0 = eth0

define PC-Yanis = {192.168.1.20}
define Laptop-Yanis = {192.168.1.21}

table ip filtreIPv4 {
    chain input {
        type filter hook input priority 0; policy drop;
        # Relations établies
        ct state established,related accept
        # Autorisation de la loopback
        iifname lo accept
        # Accès SSH Yanis
        tcp dport 22 ip saddr {$PC-Yanis, $Laptop-Yanis} accept
    }
    chain output {
        type filter hook output priority 0; policy drop;
        # Relations établies
        ct state established,related accept
        # ICMP
        ip protocol icmp accept
        # DNS
        tcp dport 53 accept
        tcp dport 53 accept
        # Accès Web
        tcp dport {80, 443} accept
        # NTP
        udp dport 123 accept
    }
}

// Règles totalement fictives :p btw

Les deux actions principales de NFTables sont :

« Accept » : permet de laisse passer le paquet et d’omettre les règles suivantes. Le paquet passe simplement dans la machine. Équivalant direct du « Exempt » chez FortiGate.

« Drop » : permet de supprimer le paquet et d’omettre les règles suivantes. Le paquet est détruit et n’est pas traité dans la machine.

Mais NFTables ne s’arrête pas à ça (loin de là d’ailleurs).

Actions Avancées

Reject : le drop avec réponse

Le « reject » fonctionne comme le « drop » sauf que cette fonction peut renvoyer des paquets icmp personnalisés en cas de refus du firewall.

chain input {
	type filter hook input priority 0; policy drop;
	# Relations établies
	ct state established,related accept
	# Autorisation de la loopback
	iifname lo accept
	# Accès SSH
	tcp dport 22 accept
	# Rejet Wake-On-LAN
	udp dport 9 reject with icmp type net-unreachable
}

Ici, NFTables bloque la connexion sur le port 9 en UDP et renvoie un paquet ICMP avec l’info « net-unreachable ».

On peut choisir le message de rejet suivant la version de icmp :

ICMPX REASONICMPv6ICMPv4
admin-prohibitedadmin-prohibitedadmin-prohibited
port-unreachableport-unreachableport-unreachable
no-routeno-routenet-unreachable
host-unreachableaddr-unreachablehost-unreachable
Article complet sur le wiki NFTables

Log : comment générer des logs avec NFTables

« log » est une action qui vient dire à NFTables d’envoyé un log vers le journal du noyau Linux, qui sont ensuite gérés par le démon de journalisation du système (comme syslogd ou systemd-journald) et écrits dans un fichier journal du système.

ALT TEMP

Ici NFTables va loguer les paquets SSH puis les accepter. Cependant les paquets ICMP sont juste loguer puis « drop » grâce à la “policy” de notre chaine.

Voici un aperçu de ce que NFTables renvoie (avec journalctl -f): ALT TEMP Par défaut, on récupère toutes les infos de la couche 2 à 5 OSI (MAC, IP, transport et session). Et c’est paramétrable ! .

De base tous les logs NFTables sont considéré comme une entrée ‘warning’, on peut modifier cela aussi ! Grâce au paramètre level.

Sévérité“norme” syslog pour NFTABLES
Emergenciesemerg
Alertsalert
Criticalcritic
Errorserr
Warningswarn
Notificationsnotice
Informationalinfo
Debuggingdebug

Counter : les compteurs paramètrables

« counter » permet de compter le nombre de paquets passés par une règle. Tout comme le « log », le « counter » n’est pas forcément une action finale. Il existe deux type de « counter » :

Pour les compteur nommé, il faut tout d’abord créer les futurs compteurs au même niveau que les chaînes. Voici une implémentation simple:

ALT TEMP

Plusieurs commandes de manipulation:

nft list counter ip [TABLE] [COUNTER]
nft list counters
nft reset couter ip [TABLE] [COUNTER]

ALT TEMP

Limit : limitations sur une durée

Tout comme « log » et le « counter », « limit » est une action qui ne termine pas forcement la règle ! Il y a deux type de « limit » :

Exemple d’un paquet qui arrive sur une règle avec une limite : ALT TEMP Le paquet n°2 passe sur la règle mais ne correspond plus à la limite il passe donc à la suite. Dans ce cas la règle est final et la policy appliqué au paquet est donc « drop ».

« burst » est un paramètre de « limit » il définit le nombre maximal de paquets ou la quantité de données (en bytes/kilobytes…) pouvant dépasser temporairement la limite imposée par rate.

Le burst est utile pour éviter de bloquer immédiatement le trafic dès le franchissement de la limite de débit : il laisse passer de petites rafales, mais bloque si les excès persistent.

« limit » et « quota » utilise tous deux l’algorithme « token bucket » .

Si on n’indique pas explicitement de valeur burst, la valeur par défaut est de 5 paquets pour un limiteur basé sur les paquets. « burst 1 » force donc la limite à 1 paquet/minute. On peut aussi limiter la taille des paquets : ALT TEMP

Ici je limite les paquets DNS supérieur à 60 bytes par minute au total. plus de 60 secondes entre les deux paquets ALT TEMP moins de 60 secondes entres les deux paquets ALT TEMP

Quota : en résumé limit + counter

Le « quota » est un mélange de « limit » et de « counter ». Il permet de faire une action sur une règle seulement si un nombre de data est dépasser ou inversement. Tout comme « counter »; Il existe deux type de « quota ».

Exemple de quota nommé : ALT TEMP Le quota est le suivant : jusqu’à 100 bytes d’ICMP on accepte les paquets. ALT TEMP Ici j’ai déjà envoyé un ping de 60 octets.

Gestion des règles avec jump et goto

« jump » et « goto » sont là pour permettre d’aider à la gestion des tables qui commence sérieusement à être lourde en taille ! Ces deux actions permettent de changer de chaine NFTables depuis une chaîne “hooked” vers des chaines regulières (en gros des chaines sans “hook”). Voici directement un exemple concret :

Avec « jump » : ALT TEMP Avec « goto » : ALT TEMP

Voici la différence : Si vous utilisez « jump » pour faire traiter un paquet dans une autre chaîne, le paquet reviendra à la chaîne de la règle appelante une fois le traitement terminé.

En revanche, si vous utilisez « goto », les paquets seront traités dans une autre chaîne mais ne reviendront pas à la chaîne de la règle appelante. Dans ce cas, la politique par défaut appliquée au paquet sera celle de la chaîne de base d’origine qui a commencé à traiter le paquet.

Bonus : la coloration syntaxique sur NFTables

Pendant la rédaction de cette article je me suis pris à chercher comment colorer mes blocks de code en markdown -> plus simple à dire qu’à faire !

Le seul software que je connais qui comprend la fameuse “syntax high-lighting” compatible avec NFTables est GNU Nano :’). Merci Arturo Borrero González à jamais dans mon cœur 🧡.

## Syntax highlighting for the packet-filtering rules of Netfilter.

## Original author:  Arturo Borrero González <arturo@debian.org>
## License:  GPL version 3 or newer

syntax nftables "\.(nft|nftables)$"
header "^#!.*(nft|nftables)"
comment "#"

# Objects and operations
color green "\<(chain|hook|policy|priority|ruleset|set|table|type|v?map)\>"
color green "\<(define|include)\>"
color red "\<(add|delete|flush|insert|remove|replace)\>"

# Families
color yellow "\<(arp|bridge|inet|ingress|ip6?|netdev)\>"

# Terminal statements
color red "\<(drop|reject)\>"
color brightblue "\<(accept|continue|(d|s)nat|goto|jump|masquerade|return)\>"

# Comments
color cyan "(^|[[:blank:]])#.*"

# Trailing whitespace
color ,green "[[:space:]]+$"

# Strings
color yellow ""([^"\]|\\.)*"|'([^'\]|\\.)*'"

# Syntactic symbols
color green "[][{}():;|`$<>!=&\]"

# Basic variable names
color brightred "(\$|@)[[:alpha:]_-][[:alnum:]_.-]*"

Encore une raison de se servir de nano.

Avis différent détecté 🔫