J'essaierai de répondre et de compléter Réponse de travail de l'OP et d'autres commentaires, y compris quelques questions en suspens :
- pourquoi
net.ipv4.conf.eth0.route_localnet=1
nécessaires ?
- Pourquoi le port 3000 doit-il être autorisé sur eth0 plutôt que lo ?
et répondra également à une préoccupation mineure en matière de sécurité.
Tout d'abord, voici un schéma obligatoire sur le flux de paquets dans Netfilter et le réseau général :
Ce schéma a été réalisé avec iptables à l'esprit, mais nftables peut (et c'est le cas dans la plupart des ensembles de règles par défaut) utiliser les mêmes crochets aux mêmes endroits.
Lorsqu'un paquet arrive dans la couche réseau (couche IP 3), il est traité par différents sous-systèmes. Normalement, il n'y a que la pile de routage, mais ici, il s'agit de la pile de routage. Netfilter fournit des crochets pour lui-même ( conntrack (y compris la gestion du NAT après le paquet initial) ou pour les nftables .
Netfilter ( conntrack ) ou nftables ne se préoccupe pas du routage (sauf si par exemple nftables utilise des expressions spécialisées liées à rou ting ), ils s'en remettent à la pile de routage : ils manipulent les adresses et les ports et les nftables vérifie ensuite les propriétés disponibles telles que les interfaces, les adresses et les ports.
Ainsi :
-
un paquet dans une nouvelle connexion (traversant ainsi également ip nat prerouting ) arrive de eth0 avec (par exemple) l'adresse source 192.0.2.2 et le port 45678 la destination 192.168.0.1 et le port 80 (ou 443).
-
les ip nat prerouting dnat correspond à la règle et indique à netfilter (son conntrack ) pour changer l'adresse de destination en 127.0.0.1 et le port de destination en 3000. Cela ne modifie aucune autre propriété du paquet. En particulier, le paquet arrive toujours de eth0 .
-
la pile de routage (décision de routage dans le schéma) ne dépend pas de l'état de la pile de routage. Netfilter Il est donc logiquement indépendant de lui et n'est pas conscient de l'altération précédente. Il doit maintenant traiter un paquet en provenance de 192.0.2.2 et à destination de 127.0.0.1.
Il s'agit d'une anomalie : elle permettrait à une plage d'adresses réservée au bouclage d'être visible "sur l'internet", comme le stipule le règlement sur l'accès à l'internet. RFC 1122 :
(g) { 127, <any> }
Adresse de bouclage de l'hôte interne. Les adresses de cette forme NE DOIVENT PAS apparaître à l'extérieur d'un hôte.
qui est traité de manière explicite dans le noyau Linux pile de routage : le traiter comme destination martienne (c'est-à-dire qu'il laisse tomber le paquet), sauf si assoupli par l'utilisation de route_localnet=1
sur l'interface correspondante. C'est pourquoi, dans ce cas précis net.ipv4.conf.eth0.route_localnet=1
doit être défini.
-
de même, le prochain nftables Cette fois-ci, la règle du filtre d'entrée voit un paquet dont l'interface d'entrée est toujours en cours de traitement. eth0 mais le port de destination est maintenant 3000. Il doit donc autoriser le port de destination 3000, et n'a plus besoin d'autoriser 80 (ou 443) pour l'accepter. La règle devrait donc être raccourcie comme suit :
iifname "eth0" tcp dport {4489, 3000} counter accept
car il ne verra jamais de paquets provenant de eth0 avec le port tcp de destination 80 ou 443 : ils ont tous été changés en port 3000 dans le crochet de pré-routage nat précédent. De plus, pour les besoins de l'explication, en supposant que de tels paquets soient vus, ils seraient acceptés mais comme il n'y aurait pas de processus d'écoute sur les ports 80 ou 443 (il écoute sur le port 3000), la pile tcp renverrait une réinitialisation TCP pour rejeter la connexion.
De même, alors que le pile de routage impose certaines relations entre 127.0.0.0/8 et le serveur lo (assouplie par l'utilisation de l'interface route_localnet=1
), comme nous l'avons dit plus haut, cela ne concerne pas les netfilter o nftables qui ne se soucient pas de l'acheminement. En outre, si tel était le cas, pour les entrée il s'agirait de l'interface source qui n'a pas changé, et non l'adresse destination qui se rapporterait à l'adresse sortie qui n'a même pas de signification réelle dans l'interface entrée chemin : oif
o oifname
ne peut pas être utilisé ici. Le simple fait d'être dans la crochet d'entrée du filtre signifie déjà que le paquet évalué arrive sur l'hôte pour un local comme le montre le schéma.
MISE À JOUR : En fait, la règle donnée précédemment devrait être modifiée pour des raisons de sécurité : le port 3000 est autorisé, mais pas seulement pour la destination 127.0.0.1. Une connexion à 192.168.0.1:3000 peut donc recevoir un TCP RST qui indique qu'il y a quelque chose de spécial ici, plutôt que de ne pas recevoir de réponse. Pour résoudre ce problème :
-
soit utiliser ceci (qui comprend une 2e règle très étrange) :
iifname "eth0" tcp dport 4489 counter accept
iifname "eth0" ip daddr 127.0.0.1 tcp dport 3000 counter accept
qui, parce que route_localnet=1
En revanche, un système modifié dans le même réseau local 192.168.0.0/24 peut toujours accéder au service sans utiliser la NAT, en envoyant des paquets avec 127.0.0.1 sur le câble, même si cela n'apporte probablement aucun avantage. Par exemple, un autre système Linux, avec ces 4 commandes :
sysctl -w net.ipv4.conf.eth0.route_localnet=1
ip address delete 127.0.0.1/8 dev lo # can't have 127.0.0.1 also local
ip route add 127.0.0.1/32 via 192.168.0.1 # via, that way no suspicious ARP *broadcast* for 127.0.0.1 will be seen elsewhere.
socat tcp4:127.0.0.1:3000 -
-
ou à la place, protégeant également pour le cas ci-dessus, beaucoup plus générique et à préférer :
iifname "eth0" tcp dport 4489 counter accept
ct status dnat counter accept
- le port non lié 4489/tcp reste autorisé comme auparavant
-
ct status dnat
correspondances si le paquet a été précédemment DNATé par l'hôte : il acceptera donc toute modification antérieure sans avoir à réaffirmer explicitement de quel port il s'agissait (il est toujours possible de l'indiquer également ou tout autre élément pour restreindre davantage la portée de ce qui est accepté) : maintenant la valeur du port 3000 également n'a plus besoin d'être explicitement mentionnée.
- il n'autorisera donc pas non plus les connexions directes au port 3000 puisque ce cas n'aurait pas fait l'objet d'une DNAT.
-
pour être complet : la même chose se produit dans l'ordre (pas tout à fait) inverse pour les sorties et les réponses. net.ipv4.conf.eth0.route_localnet=1
permet aux paquets sortants initialement générés entre 127.0.0.1 et 192.0.2.2 de ne pas être traités comme des paquets de type sources martiennes (=> drop) dans le chemin de sortie décision de routage avant d'avoir la possibilité d'être "dé-nattés" vers l'adresse source originale prévue (192.168.0.1) par netfilter ( conntrack ).
Bien entendu, l'utilisation de route_localnet=1
est une sorte d'assouplissement de la sécurité (pas vraiment pertinent avec des règles de pare-feu adéquates, mais tous les systèmes n'utilisent pas de pare-feu) et nécessite des connaissances associées sur son utilisation (par exemple : copier le fichier nftables seul ailleurs ne fonctionnera plus sans l'ensemble de règles route_localnet=1
).
Maintenant que les problèmes de sécurité ont été abordés dans les explications ci-dessus (voir "MISE À JOUR"), si l'application était autorisée à écouter 192.168.0.1 (ou n'importe quelle adresse) plutôt que seulement 127.0.0.1, une configuration équivalente pourrait être réalisée sans activer l'option route_localnet=1
en changeant en ip nat prerouting
:
iif eth0 tcp dport { 80, 443 } counter dnat 127.0.0.1:3000
à :
iif eth0 tcp dport { 80, 443 } counter dnat to 192.168.0.1:3000
ou tout simplement à :
iif eth0 tcp dport { 80, 443 } counter redirect to :3000
qui ne diffèrent pas beaucoup : redirect
change la destination en adresse IP primaire de l'hôte sur l'interface eth0 qui est 192.168.0.1, de sorte que la plupart des cas se comporteront de la même manière.