Tu servicio funciona en la máquina, el túnel está activo y, aun así, el navegador de tu escritorio sigue esperando sin respuesta. Nada está roto en el sentido habitual: la aplicación escucha dentro de un espacio de nombres de red, y esa pila es invisible para la LAN. Su bucle local pertenece al espacio de nombres, así que un cliente en otra máquina no tiene ninguna dirección que llegue al puerto. Un salto deliberado, o un par veth, lo arregla sin mover el resto del host.

Por qué nada responde en la dirección de la LAN

Un espacio de nombres es una pila de red completa: interfaces, rutas, reglas de cortafuegos y un bucle local privado. Un proceso lanzado mediante ip netns exec ve esa pila y nada más, así que la dirección a la que se enlaza se resuelve solo dentro del espacio de nombres. El propio 127.0.0.1 del host es un bucle local completamente distinto.

Por eso curl falla en el host mientras el mismo comando dentro del espacio de nombres tiene éxito. La aplicación está sana; la dirección simplemente no existe en la pila del host.

Publica un solo puerto con un salto de socat

socat une las dos pilas en el espacio de usuario, lo que basta cuando tiene que cruzar un único puerto TCP. El lado del host escucha en la LAN y, por cada conexión aceptada, inicia un segundo socat dentro del espacio de nombres que se conecta al bucle local de la aplicación. El proceso interno llega a la aplicación exactamente como lo haría un cliente local. Nada del enrutamiento del espacio de nombres cambia, así que la aplicación sigue usando el túnel como única salida.

socat TCP-LISTEN:9100,reuseaddr,fork EXEC:'ip netns exec vpn socat STDIO tcp-connect:127.0.0.1:9100',nofork

El proceso externo necesita root o la capacidad de entrar en el espacio de nombres. Si la VPN cae, la aplicación pierde su camino y el puerto publicado falla cerrado, que es el comportamiento que quieres de una jaula.

Usa un par veth cuando cruza más de un puerto

Un par veth es la respuesta correcta cuando deben cruzar varios puertos o protocolos, o cuando otros hosts necesitan iniciar conexiones. Un extremo se queda en el host, el otro pasa al espacio de nombres, y un /30 pequeño da a ambos lados una dirección estable. Después, una ruta del host envía la dirección del espacio de nombres por el par.

ip link add veth0 type veth peer name veth1
ip link set veth1 netns vpn
ip addr add 10.77.0.1/30 dev veth0
ip link set veth0 up
ip netns exec vpn ip addr add 10.77.0.2/30 dev veth1
ip netns exec vpn ip link set veth1 up

No añadas una ruta por defecto a través del host a menos que quieras romper la jaula. El túnel debe seguir siendo la salida, así que por el par solo es accesible la dirección del servicio publicado. Da también al espacio de nombres su propio archivo de resolución, porque ip netns exec lee /etc/netns/vpn/resolv.conf y sin él la resolución de nombres dentro de la jaula queda vacía.

Prueba desde otra máquina, no desde el host

Ejecuta la prueba desde una segunda máquina, porque el host puede llegar a un receptor local por caminos que no dicen nada de la LAN. Comprueba primero a qué se enlazó realmente la aplicación dentro del espacio de nombres y luego conéctate a la dirección publicada desde fuera. Enlazarse a todas las direcciones allí no ensancha la jaula, porque el comodín sigue perteneciendo al espacio de nombres y la LAN no puede verlo.

ip netns exec vpn ss -lntp

Si la conexión desde el host funciona y la de la LAN no, la pieza que falta es el salto o la ruta, no la dirección de enlace. Inicia OpenVPN dentro del espacio de nombres en lugar de mover allí un dispositivo tun en vivo, ya que mover la interfaz lo desactiva y puede borrar rutas que después no podrás reparar desde fuera. Mantén los comandos de recuperación en la consola, no dentro de la jaula.

Artículos relacionados