9 votes

Comment rediriger les requêtes sur le port 80 vers localhost:3000 en utilisant nftables ?

Je voudrais que le trafic réseau qui arrive sur 192.168.0.1:80 soit redirigé vers 127.0.0.1:3000. Et j'aimerais que le mappage de la réponse soit également géré. Mes règles complètes de NAT et de table de filtrage sont collées ci-dessous.

Je peux recevoir des connexions sur le port 80. Cependant, je n'ai pas réussi à rediriger le trafic vers localhost:3000.

add table inet filter
add chain inet filter input { type filter hook input priority 0; policy accept; }
add chain inet filter forward { type filter hook forward priority 0; policy accept; }
add chain inet filter output { type filter hook output priority 0; policy accept; }
add rule inet filter input ct state related,established  counter accept
add rule inet filter input ip protocol icmp counter accept
add rule inet filter input iifname "lo" counter accept
add rule inet filter input ct state new  tcp dport 80 counter accept
add rule inet filter input ct state new  tcp dport 4489 counter accept
add rule inet filter input ct state new  tcp dport 8080 counter accept
add rule inet filter input iifname "tun0" ct state new  tcp dport 139 counter accept
add rule inet filter input iifname "tun0" ct state new  tcp dport 445 counter accept
add rule inet filter input ct state new  udp dport 1194 counter accept
add rule inet filter input counter reject with icmp type host-prohibited
add rule inet filter forward counter reject with icmp type host-prohibited
add table nat
add chain nat prerouting { type nat hook prerouting priority -100; }
add chain nat postrouting { type nat hook postrouting priority 100; }
add rule nat prerouting redirect
add rule nat prerouting tcp dport 80 redirect to 3000
add rule nat prerouting iifname eth0 tcp dport { 80, 443 } dnat 127.0.0.1:3000
add rule nat postrouting oifname eth0 snat to 192.168.0.1

11voto

A.B Points 7722

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 :

Packet flow in Netfilter and General Networking

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.

1voto

stackhatter Points 53

Pour que cela fonctionne, j'ai décidé de recourir à l'art ancestral de la lecture de la documentation. Lorsque cela n'a pas fonctionné, j'ai utilisé mes connaissances nouvellement acquises pour tout modifier suffisamment pour que cela fonctionne, mais je n'ai aucune idée de la raison pour laquelle cette configuration fonctionne.

Avec la configuration nftables suivante, et en entrant sysctl -w net.ipv4.conf.eth0.route_localnet=1 à l'invite Shell, je peux me connecter au service qui écoute sur localhost:3000 en me connectant à l'adresse IP externe hypothétique (192.168.0.1:80) qui est associée à eth0. Cependant, je ne comprends pas très bien pourquoi cela fonctionne.

Inclure le port 3000 dans la ligne iifname "eth0" tcp dport {4489, 80, 443, 3000} counter accept est nécessaire pour que cela fonctionne.

flush ruleset

table inet filter {
        chain input {
                type filter hook input priority 0; policy drop;

                ct state established,related accept

                iif lo counter accept

                icmp type echo-request counter accept

                iifname "eth0" tcp dport {4489, 80, 443, 3000} counter accept
  }
}

table ip nat {
        chain prerouting  {

                type nat hook prerouting priority -100;

                iif eth0 tcp dport { 80, 443 } counter dnat 127.0.0.1:3000
        }
}

0voto

Michael Hampton Points 232226

Vous pouvez utiliser iptables-translate si vous avez déjà une règle iptables qui fonctionne et que vous voulez voir son équivalent nftables.

Par exemple, une règle iptables fonctionnant pour cette redirection serait la suivante :

-t nat -A PREROUTING -p tcp -m tcp --dport 80 -j REDIRECT --to-ports 3000

Nourrissez-vous de cela iptables-translate et vous obtenez :

[root@vmtest-centos8 ~]# iptables-translate -t nat -A PREROUTING -p tcp -m tcp --dport 80 -j REDIRECT --to-ports 3000
nft add rule ip nat PREROUTING tcp dport 80 counter redirect to :3000

Aucune autre règle nat ne devrait être nécessaire pour cela, bien qu'il semble que vous ayez d'autres redirections à mettre en place. Faites la même chose pour eux.

SistemesEz.com

SystemesEZ est une communauté de sysadmins où vous pouvez résoudre vos problèmes et vos doutes. Vous pouvez consulter les questions des autres sysadmins, poser vos propres questions ou résoudre celles des autres.

Powered by:

X