redirection de port vers l'application dans l'espace de noms réseau avec vpn

13

J'ai pu mettre en place un espace de noms réseau, établir un tunnel avec openvpn et démarrer une application qui utilise ce tunnel à l'intérieur de l'espace de noms. Jusqu'ici tout va bien, mais cette application est accessible via une interface Web et je n'arrive pas à comprendre comment acheminer les demandes vers l'interface Web à l'intérieur de mon réseau local.

J'ai suivi un guide de @schnouki expliquant comment configurer un espace de noms réseau et exécuter OpenVPN à l'intérieur de celui-ci

ip netns add myvpn
ip netns exec myvpn ip addr add 127.0.0.1/8 dev lo
ip netns exec myvpn ip link set lo up
ip link add vpn0 type veth peer name vpn1
ip link set vpn0 up
ip link set vpn1 netns myvpn up
ip addr add 10.200.200.1/24 dev vpn0
ip netns exec myvpn ip addr add 10.200.200.2/24 dev vpn1
ip netns exec myvpn ip route add default via 10.200.200.1 dev vpn1
iptables -A INPUT \! -i vpn0 -s 10.200.200.0/24 -j DROP
iptables -t nat -A POSTROUTING -s 10.200.200.0/24 -o en+ -j MASQUERADE
sysctl -q net.ipv4.ip_forward=1
mkdir -p /etc/netns/myvpn
echo 'nameserver 8.8.8.8' > /etc/netns/myvpn/resolv.conf

Après cela, je peux vérifier mon adresse IP externe et obtenir des résultats différents à l'intérieur et à l'extérieur de l'espace de noms, comme prévu:

curl -s ipv4.icanhazip.com
<my-isp-ip>
ip netns exec myvpn curl -s ipv4.icanhazip.com
<my-vpn-ip>

L'application est lancée, j'utilise déluge pour cet exemple. J'ai essayé plusieurs applications avec une interface web pour m'assurer que ce n'était pas un problème spécifique au déluge.

ip netns exec myvpn sudo -u <my-user> /usr/bin/deluged
ip netns exec myvpn sudo -u <my-user> /usr/bin/deluge-web -f
ps $(ip netns pids myvpn)
 PID TTY      STAT   TIME COMMAND
1468 ?        Ss     0:13 openvpn --config /etc/openvpn/myvpn/myvpn.conf
9302 ?        Sl    10:10 /usr/bin/python /usr/bin/deluged
9707 ?        S      0:37 /usr/bin/python /usr/bin/deluge-web -f

Je peux accéder à l'interface Web sur le port 8112 à partir de l'espace de noms et de l'extérieur si je spécifie l'ip de veth vpn1.

ip netns exec myvpn curl -Is localhost:8112 | head -1
HTTP/1.1 200 OK
ip netns exec myvpn curl -Is 10.200.200.2:8112 | head -1
HTTP/1.1 200 OK
curl -Is 10.200.200.2:8112 | head -1
HTTP/1.1 200 OK

Mais je veux rediriger le port 8112 de mon serveur vers l'application dans l'espace de noms. Le but est d'ouvrir un navigateur sur un ordinateur à l'intérieur de mon réseau local et d'obtenir l'interface Web avec http: // mon-serveur-ip: 8112 (mon-serveur-ip étant l'ip statique du serveur qui a instancié l'interface réseau)

EDIT: J'ai supprimé mes tentatives de création de règles iptables. Ce que j'essaie de faire est expliqué ci-dessus et les commandes suivantes devraient générer un HTTP 200:

curl -I localhost:8112
curl: (7) Failed to connect to localhost port 8112: Connection refused
curl -I <my-server-ip>:8112
curl: (7) Failed to connect to <my-server-ip> port 8112: Connection refused

J'ai essayé les règles DNAT et SNAT et jeté une MASQUERADE pour faire bonne mesure, mais comme je ne sais pas ce que je fais, mes tentatives sont vaines. Peut-être que quelqu'un peut m'aider à construire cette construction.

EDIT: La sortie tcpdump de tcpdump -nn -q tcp port 8112. Sans surprise, la première commande renvoie un HTTP 200 et la deuxième commande se termine avec une connexion refusée.

curl -Is 10.200.200.2:8112 | head -1
listening on vpn0, link-type EN10MB (Ethernet), capture size 262144 bytes
IP 10.200.200.1.36208 > 10.200.200.2.8112: tcp 82
IP 10.200.200.2.8112 > 10.200.200.1.36208: tcp 145

curl -Is <my-server-ip>:8112 | head -1
listening on lo, link-type EN10MB (Ethernet), capture size 262144 bytes
IP <my-server-ip>.58228 > <my-server-ip>.8112: tcp 0
IP <my-server-ip>.8112 > <my-server-ip>.58228: tcp 0

EDIT: @schnouki lui-même m'a montré un article de l'administration Debian expliquant un proxy TCP iptables générique . Appliqué au problème en question, leur script ressemblerait à ceci:

YourIP=<my-server-ip>
YourPort=8112
TargetIP=10.200.200.2
TargetPort=8112

iptables -t nat -A PREROUTING --dst $YourIP -p tcp --dport $YourPort -j DNAT \
--to-destination $TargetIP:$TargetPort
iptables -t nat -A POSTROUTING -p tcp --dst $TargetIP --dport $TargetPort -j SNAT \
--to-source $YourIP
iptables -t nat -A OUTPUT --dst $YourIP -p tcp --dport $YourPort -j DNAT \
--to-destination $TargetIP:$TargetPort

Malheureusement, le trafic entre les interfaces veth s'est saisi et rien d'autre ne s'est produit. Cependant, @schnouki a également suggéré l'utilisation de socatcomme proxy TCP et cela fonctionne parfaitement.

curl -Is <my-server-ip>:8112 | head -1
IP 10.200.200.1.43384 > 10.200.200.2.8112: tcp 913
IP 10.200.200.2.8112 > 10.200.200.1.43384: tcp 1495

Je n'ai pas encore compris l'étrange brassage de port pendant que le trafic traverse les interfaces veth, mais mon problème est résolu maintenant.

pskiebe
la source
Avis de non-responsabilité: je n'ai aucune expérience avec les vethappareils (trouver cela très intéressant, cependant ... ;-)). Avez-vous utilisé tcpdumppour vérifier jusqu'où les paquets entrants arrivent? Si tcpdump -i veth0rien ne s'affiche, cela tcpdumo -i lopeut être nécessaire.
Hauke ​​Laging du
J'ai ajouté la sortie non verbeuse de tcpdump
pskiebe

Réponses:

9

J'ai toujours eu des problèmes avec les redirections iptables (probablement ma faute, je suis presque sûr que c'est faisable). Mais pour un cas comme le vôtre, il est plus facile de le faire dans un pays utilisateur sans iptables.

Fondamentalement, vous devez avoir un démon dans votre espace de travail "par défaut" écoutant sur le port TCP 8112 et redirigeant tout le trafic vers le port 10.200.200.2 8112. Il s'agit donc d'un simple proxy TCP.

Voici comment le faire avec socat :

socat tcp-listen:8112,reuseaddr,fork tcp-connect:10.200.200.2:8112

(L' forkoption est nécessaire pour éviter socatde s'arrêter après la fermeture de la première connexion proxy).

EDIT : ajouté reuseaddrcomme suggéré dans les commentaires.

Si vous voulez absolument le faire avec iptables, il y a un guide sur le site d' administration Debian . Mais je préfère toujours socatdes choses plus avancées - comme le proxy IPv4 en IPv6, ou le dépouillement de SSL pour permettre aux anciens programmes Java de se connecter à des services sécurisés ...

Sachez cependant que toutes les connexions dans Deluge se feront à partir de l'IP de votre serveur au lieu de l'IP client réel. Si vous voulez éviter cela, vous devrez utiliser un véritable proxy inverse HTTP qui ajoute l'IP client d'origine à la demande mandatée dans un en-tête HTTP.

Schnouki
la source
1
Vous venez de faire ma journée! Je ne suis jamais tombé sur socatet cela accomplit exactement ce que j'essayais de faire avec iptables depuis un certain temps maintenant. J'ai testé plusieurs applications et elles fonctionnent toutes parfaitement, se connectant au monde extérieur via tun0, tout en fournissant un accès à leur interface web via veth1.
pskiebe
1
Après avoir fait quelques tests, j'ai ajouté le reuseaddrdrapeau. Cela évite les port already in useerreurs lors du démarrage et de l'arrêt de socat en succession rapide:socat -4 TCP-LISTEN:8112,reuseaddr,fork TCP:10.200.200.2:8112
pskiebe
8

L'interconnexion de l'espace de noms du réseau avec l'espace de noms principal me dérange toujours. La raison pour laquelle je crée généralement un espace de noms est que je veux qu'il soit isolé. Selon ce que vous essayez de réaliser avec des espaces de noms, la création d'interconnexions peut aller à l'encontre de cet objectif.

Mais même isolé, je veux toujours le pousser sur le réseau, pour plus de commodité.

Cette solution vous permet de conserver l'isolement et de lui transmettre certaines connexions de toute façon. Vous n'avez pas besoin de créer tout ce réseau entre les deux espaces de noms de réseau juste pour transférer un port. Exécutez-le dans l'espace de noms où vous souhaitez accepter les connexions. Doit être exécuté en tant que root pour ip netns execfonctionner.

socat tcp-listen:8112,fork,reuseaddr \
  exec:'ip netns exec myvpn socat STDIO tcp-connect\:127.0.0.1\:8112',nofork

Il écoute les connexions dans un espace de noms réseau où vous l'exécutez, sur le port 8112, puis le client connecté execs'exécute ip netns exec myvpn ...pour exécuter le reste à l'intérieur de l' myvpnespace de noms réseau, puis une fois à l'intérieur de l' myvpnespace de noms réseau, il crée à nouveau une deuxième connexion avec un autre socat.

AnyDev
la source
travailler comme un charme
approximatif
Comme je n'ai pas trop d'expérience avec l'administration Linux et cela m'a pris du temps à découvrir: assurez-vous d'échapper les deux :caractères dans les guillemets simples, sinon vous pourriez rencontrer une erreur en disant ... wrong number of parameters (2 instead of 1)(2 ou 3). Sinon: fonctionne très bien! Un immense merci!
Igor
2

Pour déluge voici ma solution. Pas besoin d'iptables. Voici les étapes:

  1. Démarrez votre tunnel openvpn
  2. Créez un espace de noms et apportez votre tunnel openvpn là:
ip netns add $ NS
# Attendez que le TUN monte
while [[$ (ip route | grep $ TUN | wc -l) == 0]]; dors 1; terminé
MY_IP = $ (ip addr show $ TUN | grep inet | cut -d '' -f6 | cut -d '/' -f1)
# La façon dont vous extrayez l'IP de la passerelle peut être différente pour votre connexion openvpn
GATEWAY_IP = $ MY_IP
# emprisonner mon $ TUN (interface VPN) dans l'espace de noms
ensemble de liens IP $ TUN netns $ NS
# Apportez l'interface avec un sous-réseau (équivalent à celui qui m'a été donné par le serveur VPN)
ip netns exec $ NS ifconfig $ TUN $ MY_IP / 24 up
# Faire remonter la boucle
ip netns exec $ NS ifconfig lo 127.0.0.1/8 up
# Configurer une passerelle distante (votre adresse IP VPN point-point)
ip netns exec $ NS route add gw $ GATEWAY_IP par défaut
  1. Établissez une connexion veth entre votre espace de noms par défaut et celui que vous avez créé:
# Configurer des interfaces veth pour la communication entre les espaces de noms
lien ip ajouter veth0 type veth nom d'homologue veth1
# Déplacez le deuxième veth vers votre espace de noms
ensemble de liens ip veth1 netns $ NS
# donne une IP de la plage IP inutilisée au premier veth
ifconfig veth0 10.1.1.1/24 up
# Et le second
ip netns exec $ NS ifconfig veth1 10.1.1.2/24 up
# TODO: configurez un pont entre veth1 et l'interface eth pour lui permettre de communiquer avec le LAN
# Configurer le client DNS. ip netns émulera /etc/resolv.conf en utilisant ce fichier:
mkdir -p / etc / netns / $ NS
echo "nameserver 8.8.4.4"> /etc/netns/$NS/resolv.conf
  1. Exécutez votre déluge dans le $ NS et votre déluge-web dans votre espace de noms par défaut. Pointez deluge-web vers l'adresse IP 10.1.1.2 veth, où déluge écoutera sa connexion.

Voila! Vous avez sécurisé déluge derrière le VPN tandis que votre déluge-web est librement accessible sur votre réseau domestique

Vlad
la source
2

@ La réponse d'AndrDevEK est utile. Pour développer cela, vous pouvez ne pas vouloir installer socat. Dans ce cas, vous pouvez obtenir la même chose avec une configuration de transfert de port SSH légèrement alambiquée. En particulier, la fonction de redirection de port vers / depuis un socket de domaine unix est utile ici, car les sockets de domaine unix fonctionnent indépendamment des espaces de noms réseau:

sudo ip netns exec myvpn su -c "ssh -N -L /tmp/myunixsock:localhost:8112 localhost" $USER &
ssh_pid1=$!
ssh -N -L localhost:8112:/tmp/myunixsock localhost &
ssh_pid2=$!

Nettoyer:

sudo kill $ssh_pid1
kill $ssh_pid2
rm /tmp/myunixsock

Le premier ssh -N -Lest démarré dans l'espace de noms myvpn. Cela crée un socket de domaine Unix /tmp/myunixsocket l'écoute. Les connexions entrantes sont transmises à localhost: 8112 (à l'intérieur de l'espace de noms myvpn). Le second ssh -N -Lest démarré dans l'espace de noms par défaut. Cela crée un port TCP d'écoute et transfère les connexions entrantes au socket de domaine unix.

Il convient de noter que pour que cela fonctionne, l' sshintérieur de votre espace de noms réseau devra fonctionner s'il ne l'est pas déjà (et une opération de publication sans mot de passe est utile):

sudo ip netns exec myvpn ip link set up dev lo
sudo ip netns exec myvpn /usr/sbin/sshd -o PidFile=/run/sshd-myvpn.pid
ssh-copy-id localhost
Traumatisme numérique
la source