Forum Linux.debian/ubuntu NAT loopback: a pas compris :(

Posté par  . Licence CC By‑SA.
Étiquettes : aucune
2
10
jan.
2022

Hello,

Je m'arrache les cheveux !
Impossible de trouver une solution à un problème qui me parait pourtant simple.

J'ai une machine avec un interface eth0 et une IP publique A.B.C.D.
Cette machine est protégée par des règles iptables gérée avec ferm (oui je sais, nftables mieux qu'iptables tout ça, mais ça sera pour l'étape d'après).
Cette machine héberge des VMs qui gèrent différents services, NATés sans problème pour être accessibles de l'extérieur, chacune ayant une ip 192.168.0.X.
Un bridge vm-bridge relie A.B.C.D à l'IP 192.168.0.1

Pour chaque forward de l'extérieur vers mes VM, les règles iptables sont établies via cette fonction:

@def &FORWARD($proto, $port, $dest) = {
    table nat chain PREROUTING interface eth0 daddr A.B.C.D proto $proto dport $port DNAT to $dest;
    table filter chain FORWARD interface eth0 outerface vm-bridge daddr $dest proto $proto dport $port ACCEPT;   
}

/proc/sys/net/ipv4/ip_forward est bien à 1

J'ai bien activé le masquerading pour permettre aux VMs d'avoir accès à l'extérieur.

table nat {
    chain POSTROUTING {
        source 192.168.0.0/24 MASQUERADE;
    }
}

Tout fonctionne parfaitement de l’extérieur vers les VMs, et des VMs vers l'extérieur.
Mais entre VMs ou depuis la machine hôte vers les VMs ça ne passe pas: la connexion est refusée.

J'ai beau avoir écumé tous les résultats de recherche sur NAT loopback et SNAT, impossible de trouver une solution qui me permette de communiquer entre VMs ou de l'hôte vers une VM.

Je suis certain de ne pas avoir compris un détail basique, mais impossible de mettre le doigt dessus.

Merci d'éclairer mes lanternes avec une explication limpide de mon égarement qui me permettra d'avancer.

  • # parce que c'est pas une question de forward

    Posté par  . Évalué à 4.

    tu arrives de tn reseau local via l'interface eth1 probablement
    et tu demandes à joindre une IP cachée derriere le eth0 (publique puis privée/VM)

    il te faut donc faire des regles qui autorise ton LAN (eth1) à communiquer avec tout (ou partie) de ton eth0

    si par contre ton serveur qui héberge les VM n'a qu'une seule interface (eth0)
    que les VMs sont sur le LAN 192.168.0.x/24

    et que le NAT 'ip publique' -> 'machine' est géré par la box de l'opérateur,
    alors c'est bien le 'NAT loopback' qui n'est pas géré par ta box => changer de box, installer un routeur derriere ta box (en DMZ) et renvoyer tout le trafic externe -> routeur
    et ton lan vers le routeur

    • [^] # Re: parce que c'est pas une question de forward

      Posté par  . Évalué à 3.

      si par contre ton serveur qui héberge les VM n'a qu'une seule interface (eth0)
      que les VMs sont sur le LAN 192.168.0.x/24

      c'est ça !

      et que le NAT 'ip publique' -> 'machine' est géré par la box de l'opérateur,

      ah non c'est plus ça :)
      Il s'agit d'un dédié.

      • [^] # Re: parce que c'est pas une question de forward

        Posté par  . Évalué à 4. Dernière modification le 10 janvier 2022 à 12:25.

        les machines entre elles peuvent se voir ?
        car ca pourrait etre une isolation lié au bridge qui ne tolère que les flux
        VM -> Bridge -> Exterieur et exterieur->bridge->vm

        dans tes regles tu n'autorise que le forward de eth0 vers vm-bridge
        mais quand tu viens de l'intérieur, c'est un flux

        VM1 -> bridge -> SNAT publique -> IP Publique -> DNAT -> bridge -> VM2

        mais je ne suis pas sur que cela passe réellement sur l'interface eth0 puisqu'on enchaine le SNAT puis le DNAT dans la foulée sans vraiment ressortir

        de memoire il y peut-etre un flag à mettre à 1 pour mettre à la carte "interne" de parler à la carte externe par son coté 'interne' mais je me souviens plus lequel

        en gros ca permet de parler à eth0 sans sortir puisqu'on est deja dedans

        VM1 -> bridge -> intérieur (eth0) intérieur -> bridge -> VM2

        • [^] # Re: parce que c'est pas une question de forward

          Posté par  . Évalué à 2. Dernière modification le 10 janvier 2022 à 13:08.

          les machines entre elles peuvent se voir ?

          les VMs se voient entre elles si elles se ping via leur adresse 192.168.0.X

          Par contre si, dans une VM, je fais un telnet nom-de.domaine 443, le nom de domaine est résolu mais la connexion ne se fait pas, alors que, sur l'hôte, le port 443 est bien redirigé vers la bonne VM et accessible depuis l'extérieur.

  • # c'est pas un pb de bridge plutôt?

    Posté par  . Évalué à 5.

    Selon le type de virtualisation le bridge peut se comporter plus ou moins différemment. Cf:

    https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/6/html/virtualization_host_configuration_and_guest_installation_guide/app_macvtap

    'traffic into that bridge from the guests that is forwarded to the physical interface cannot be bounced back up to the host's IP stack. '

  • # ca ne résoudra peut-etre rien mais...

    Posté par  . Évalué à 5.

    chez moi, j'ai fait mon bridge sur une carte DUMMY
    j'ai mis une IP a la machine physique sur cette carte dummy

    ainsi j'ai bien 2 interfaces distinctes
    une qui gere les VMs en interne

    et une pour le WAN

    le tout avec les regles entrées/sorties/nat qui vont bien

  • # début de réponse

    Posté par  . Évalué à 2. Dernière modification le 10 janvier 2022 à 23:06.

    j'ai trouvé un début de réponse qui me permet de contacter les service de mes VMs depuis l'hôte.

    Here is what I do specifically for localhost forwarding:
    
    iptables -t nat -A OUTPUT -m addrtype --src-type LOCAL --dst-type LOCAL -p tcp --dport 3306 -j DNAT --to-destination ip.ip.ip.ip
    iptables -t nat -A POSTROUTING -m addrtype --src-type LOCAL --dst-type UNICAST -j MASQUERADE
    
    sysctl -w net.ipv4.conf.all.route_localnet=1
    
    Make sure you substitute ip.ip.ip.ip for your real public IP and also the --dport 3306 for the port you want to forward.
    
    Finally run the sysctl command and also update your /etc/sysctl.conf
    
    You can update sysctl.ctl to allow the routing of localhost with the following command:
    
    echo "net.ipv4.conf.all.route_localnet=1" >> /etc/sysctl.conf
    
    Now this all seems simple and good but it did take some research and hunting down. Be warned and understand that forwarding localhost/127.0.0.1 requires this method and the typical other examples do not work. Some examples of solutions that do not work with localhost:
    
    iptables -t nat -A PREROUTING -p tcp --dport 3306 -j DNAT --to ip.ip.ip.ip:3306
    iptables -t nat -A POSTROUTING -d ip.ip.ip.ip -j MASQUERADE
    
    http://realtechtalk.com/iptables_how_to_forward_localhost_port_to_remote_public_IP-1788-articles
    

    En utilisant l'IP de ma VM pour ip.ip.ip.ip

    Maintenant, je n'ai aucune idée des conséquences en terme de sécurité.

    Je continue de chercher pour l'utilisation d'un service d'une VM par une autre VM.

    • [^] # Re: début de réponse

      Posté par  . Évalué à 2.

      le route_localnet n'est peut-etre pas ce que tu cherches
      car il rend routable les reseaux 127.x.y.z alors qu'il ne devrait pas

      https://github.com/kubernetes/kubernetes/issues/90259

      par contre, ce qui te sauve, c'est peut-etre le MASQ en SORTIE de ton bridge vers les VMs quand ca vient du local et evite alors le routage asymétrique

      car dans ta communication, de memoire, le paquet VM1 -> IP publique:port (vers VM2) devient
      - preroute/dnat : VM1 -> VM2
      - forward : pas vue l'autorisation spécifique
      - postroute (SNAT ou MASQ) : pas de NAT prévu

      la VM2 reçoit le paquet comme venant de VM1 et lui répond directement
      => routage asymétrique, souvent cassé dans les échanges car la réponse ne vient tout simplement pas de la machine à qui on a fait la demande

  • # Manque t'il des règles ?

    Posté par  . Évalué à 2.

    Bonjour,

    @def &FORWARD($proto, $port, $dest) = {
    table nat chain PREROUTING interface eth0 daddr A.B.C.D proto $proto dport $port DNAT to $dest;
    table filter chain FORWARD interface eth0 outerface vm-bridge daddr $dest proto $proto dport $port ACCEPT;

    }

    J'ai l'impression qu'il faudrait doubler ces règles en remplaçant eth0 par l'interface de ton bridge (ou supprimer "interface eth0" des règles si c'est possible).
    Les 2 règles existantes ne concertent pas les flux qui viennent de vm-bridge et vont vers A.B.C.D.

    A titre perso, j'utilise le nom local des machines pour accéder à leur service avec un paramétrage via le fichier hosts.

Suivre le flux des commentaires

Note : les commentaires appartiennent à celles et ceux qui les ont postés. Nous n’en sommes pas responsables.