23/01/2025

Configurer le NAT sous NFtables

Nous allons maintenant apprendre à mettre en place et gérer du NAT dans nftables, cela peut être particulièrement utile dans le cas ou le système en question est un routeur. En effet, le principe du NAT est de modifier les adresses IP sources des paquets qui passent au travers notre routeur.

Note : Dans le cadre d'un NAT, il faut bien sûr que votre système Linux soit un routeur. Pour cela, pensez à activer l'IP forwarding qui permet d'autoriser le passage des paquets réseau d'une interface vers une autre : echo 1 > /proc/sys/net/ipv4/ip_forward

I. NAT MASQUERADE

Pour gérer correctement le NAT, il va falloir créer une chaine, dans une table déjà existante que nous nommerons ici mon_filtreIPv4. Ces chaines s'appliqueront sur les hook PREROUTING et POSTROUTING.

Note : Cette fonctionnalité de nftables n'est disponible que depuis la version 3.18 du kernel Linux

Si vous avez du mal à comprendre ce dernier paragraphe, je vous propose de retourner voir le chapitre 1 du module 2 qui présente le fonctionnement de NetFilter et de nftables.

root@debian# nft add table mon_filtreIPv4
root@debian# nft add chain mon_filtreIPv4 prerouting { type nat hook prerouting priority 0 \; }
root@debian# nft add chain mon_filtreIPv4 postrouting { type nat hook postrouting priority 0 \; }

Bien entendu, cela peut se faire en plus des règles que nous avons mises en place dans les cours précédents. Pour rappel, une table contient des chaines qui s'appliquent chacune sur un hook précis.

Nous allons commencer par faire le cas le plus basique de NAT : le NAT Source. Le fonctionnement est très simple. Pour chaque paquet qui va sortir d'une interface (qui passe donc par le hook POSTROUTING ;)), nous allons remplacer l'adresse IP source de ce paquet par l'adresse IP de l'interface par laquelle il sort.

Exemple pratique :

nftables-linux-nat-01

Dans cet exemple. Si le client A communique avec le client B, l'IP source des paquets arrivant sur le client B sera 192.168.1.100 (l'IP du client A). Le problème que l'on rencontre souvent lorsque l'on aborde le routage est le fait que la route retour n'est pas opérationnelle.

Autrement dit, le client B ne connait pas obligatoirement la route à prendre pour répondre à cette plage IP (192.168.1.0/24) et peut donc envoyer ses réponses à la mauvaise passerelle. Un des objectifs du NAT est de contourner ce problème en faisant en sorte qu'à chaque fois que le client A envoie un paquet vers l'extérieur (un paquet qui sortira de l'interface 192.168.2.1 de notre routeur), celui-ci remplace l'adresse IP source des paquets par l'adresse IP de l'interface de sortie (192.168.1.100 sera donc remplacé par 192.168.2.1). Ainsi, le client B saura répondre à ces paquets, car l'adresse IP 192.168.2.1 est dans son LAN, sur ce que l'on appelle une route directe.

Quand les paquets reviendrons, notre routeur effectuera l'opération inverse et retrouvera, grâce à un système de port, à qui est destiné ce paquet, c’est-à-dire au client A. Il faut, pour comprendre cette partie, avoir déjà quelques connaissances au niveau du routage et de la façon dont transitent les paquets sur un réseau.

Pour mettre en place du source NAT, rien de plus simple. Nous allons commencer par créer une chaine postrouting que l'on attachera au hook et une chaine prerouting suivant le même principe dans notre table mon_filtreIPv4 :

root@debian# nft add table mon_filtreIPv4
root@debian# nft add chain mon_filtreIPv4 prerouting { type nat hook prerouting priority 0 \; }
root@debian# nft add chain mon_filtreIPv4 postrouting { type nat hook postrouting priority 0 \; }

Nous allons ensuite simplement ajouter une règle qui permettra de faire du masquerade :

root@debian# nft add rule mon_filtreIPv4 postrouting masquerade

À ce stade, votre client A et votre client B pourront se pinguer dans les deux sens. Et je le précise bien, car ce n'est pas un NAT comme tout le monde pourrait s'y attendre. En effet, la source NAT que nous venons de faire marche dans les deux sens et ne protège en aucun cas un réseau d'en voir un autre.

Pour que le réseau du client A soit totalement injoignable depuis le réseau du client B, il faut que nous mettions en place un autre type de source NAT, qui sera, lui, unidirectionnel. Les clients B ne pourront communiquer avec les clients A que si ces derniers les ont sollicités. Cela apporte de la sécurité, car le réseau A est "caché". Même si ce n'est pas pour cela que le NAT a été créé à la base ;).

II. Source NAT unidirectionnel

Pour effectuer un source NAT qui ne fonctionne que dans un sens, il faut de nouveau créer notre structure avec une chaine liée au hook prerouting et une chaine liée au hook postrouting.

Ensuite, nous allons faire en sorte que tous les paquets qui viennent de la plage IP du réseau de notre client A (192.168.1.0/24) et sortant par l'interface eth1 (celle qui se trouve du côté du réseau B) auront leur adresse IP source réécrite en 192.168.2.1, l'adresse IP de l'interface du réseau B :

root@debian# nft add rule mon_filtreIPv4 postrouting ip saddr 192.168.1.0/24 oif eth1 snat 192.168.2.1

Ici, nous précisons donc bien dans la chaine postrouting que tous les paquets ayant comme adresse IP source une adresse dans la plage IP 192.168.1.0/24 et qui sortent par l'interface eth1 (oif pour output interface en opposition a iif pour input interface) verront leur IP source remplacée par 192.168.2.1.

 Note : Vous avez peut être remarqué que nous avons créé la chaine prerouting liée au hook PREROUTING mais que nous n'avons rien mis dedans. Cependant, il ne faut pas la supprimer et son existence est importante pour le bon fonctionnement du NAT. En effet, si la chaine postrouting est utilisée pour les paquets sortants, la chaine prerouting est utile pour effectuer l'opération inverse quand les paquets reviennent, et cela de façon implicite.

III. Destination NAT

Maintenant que nous avons vu comment faire du NAT, nous allons voir comment créer une exception dans ce NAT. En effet, il arrive que l'on ait besoin de faire du destination NAT. Plus clairement, dans un contexte de NAT comme mis en place précédemment, nous voulons créer des exceptions et dire que si l'adresse IP externe de notre routeur reçoit des paquets sur le port 21, il faudra les rediriger vers une machine qui est dans le LAN ("cachée" derrière le NAT). C'est ce qui est appelé le destination NAT.

C'est en fin de compte l'opération inverse de ce que nous venons de faire. Ici, on remplace l'adresse IP de destination des paquets qui arrivent. Un exemple pratique :

Dans ce schéma suivant, le client B veut se rendre sur le serveur FTP qui est dans le réseau "naté". Il va donc communiquer avec le "représentant" de ce réseau qui est le routeur Linux, sur son port 21 :

nftables-linux-nat-02

Grâce au destination NAT, les paquets arrivant sur le routeur Linux avec pour port destination le port 21 auront l'IP de destination 192.168.2.1. Nous allons donc créer une règle qui dit que quand l'IP de destination est 192.168.2.1 et que le port visé est le port 21, nous allons rediriger ces paquets vers l'IP 192.168.1.102, toujours sur le port 21.

Ainsi, le client B parviendra à joindre le serveur FTP dans le réseau "naté" (car nous l'avons décidé ;)). Pour mettre en place un destination NAT, nous avons toujours besoin de nos chaines prerouting et postrouting.

root@debian# nft add table mon_filtreIPv4
root@debian# nft add chain mon_filtreIPv4 prerouting { type nat hook prerouting priority 0 \; }
root@debian# nft add chain mon_filtreIPv4 postrouting { type nat hook postrouting priority 0 \; }

Sur la chaine prerouting cette fois, nous allons appliquer notre règle de destination NAT :

root@debian# nft add rule mon_filtreIPv4 prerouting iif eth1 tcp dport 21 dnat 192.168.1.102

On précise donc bien que, tous les paquets arrivant sur l'interface eth1 et avec pour port de destination le port 21 seront modifiés pour que leur adresse IP de destination devienne 192.168.1.102.

Encore une fois, nous créons la chaine postrouting sans ajouter de règle à l'intérieur, mais sa création est une condition du bon fonctionnement du DNAT, car elle permet de traiter les paquets durant leur retour.

Avez-vous noté la différence dans le paramétrage du DNAT et du SNAT ? Dans le DNAT, on configure la chaine prerouting, liée au hook PREROUTING, car on souhaite réécrire les paquets avant qu'ils ne soient traités par les systèmes de filtrage. En revanche dans le SNAT, on réécrit les paquets après qu'ils soient passés dans le système de filtrage. Nous n'utilisons d'ailleurs pas les hooks OUTPUT et INPUT, car les paquets ne sont, notamment dans le cadre du SNAT, pas destinés à la machine "Linux Routeur" par laquelle ils transitent. On utilise donc la chaine postrouting liée au hook POSTROUTING

Et si je veux rediriger ce qui arrive sur le port 2121 du routeur vers le port 21 de mon serveur LAN, c'est possible ?

Eh bien oui, voici la syntaxe à utiliser :

root@debian# nft add rule mon_filtreIPv4 prerouting iif eth1 tcp dport 2121 dnat 192.168.240.131:21

Ici, on rajoute simplement le port de destination en plus de l'IP pour le serveur LAN.

author avatar
Mickael Dorigny Co-founder
Co-fondateur d'IT-Connect.fr. Auditeur/Pentester chez Orange Cyberdéfense.
Partagez cet article Partager sur Twitter Partager sur Facebook Partager sur Linkedin Envoyer par mail