reenvío de puertos a la aplicación en el espacio de nombres de red con vpn

13

Pude configurar un espacio de nombres de red, establecer un túnel con openvpn e iniciar una aplicación que usa este túnel dentro del espacio de nombres. Hasta ahora todo bien, pero se puede acceder a esta aplicación a través de una interfaz web y no puedo entender cómo enrutar las solicitudes a la interfaz web dentro de mi LAN.

Seguí una guía de @schnouki que explicaba cómo configurar un espacio de nombres de red y ejecutar OpenVPN dentro de él.

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

Después de eso, puedo verificar mi ip externa y obtener diferentes resultados dentro y fuera del espacio de nombres, tal como estaba previsto:

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

La aplicación se inició, estoy usando diluvio para este ejemplo. Probé varias aplicaciones con una interfaz web para asegurarme de que no sea un problema específico de diluvio.

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

Puedo acceder a la interfaz web en el puerto 8112 desde dentro del espacio de nombres y desde afuera si especifico la 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

Pero sí quiero redirigir el puerto 8112 desde mi servidor a la aplicación en el espacio de nombres. El objetivo es abrir un navegador en una computadora dentro de mi LAN y obtener la interfaz web con http: // my-server-ip: 8112 (my-server-ip es la ip estática del servidor que instancia la interfaz de red)

EDITAR: eliminé mis intentos de crear reglas de iptables. Lo que intento hacer se explica anteriormente y los siguientes comandos deberían generar 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

Intenté las reglas DNAT y SNAT y agregué una MASQUERADA por si acaso, pero como no sé lo que estoy haciendo, mis intentos son inútiles. Quizás alguien pueda ayudarme a armar esta construcción.

EDITAR: la salida de tcpdump de tcpdump -nn -q tcp port 8112. Como era de esperar, el primer comando devuelve un HTTP 200 y el segundo comando termina con una conexión rechazada.

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

EDITAR: @schnouki mismo me señaló un artículo de la Administración de Debian que explica un proxy TCP genérico de iptables . Aplicado al problema en cuestión, su script se vería así:

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

Desafortunadamente, el tráfico entre las interfaces veth se detuvo y no sucedió nada más. Sin embargo, @schnouki también sugirió el uso de socatun proxy TCP y esto funciona perfectamente.

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

Todavía tengo que entender el extraño desplazamiento de puertos mientras el tráfico atraviesa las interfaces veth, pero mi problema está resuelto ahora.

pskiebe
fuente
Descargo de responsabilidad: no tengo experiencia con vethdispositivos en absoluto (aunque esto es muy interesante ... ;-)). ¿Ha utilizado tcpdumppara verificar qué tan lejos llegan los paquetes entrantes? Si tcpdump -i veth0no muestra nada, entonces tcpdumo -i lopuede ser necesario.
Hauke ​​Laging
Agregué la

Respuestas:

9

Siempre he tenido problemas con las redirecciones de iptables (probablemente es mi culpa, estoy bastante seguro de que es factible). Pero para un caso como el suyo, es IMO más fácil hacerlo en tierra de usuario sin iptables.

Básicamente, necesita tener un demonio en su espacio de trabajo "predeterminado" que escuche en el puerto TCP 8112 y redirija todo el tráfico al puerto 10.200.200.2 8112. Por lo tanto, es un proxy TCP simple.

Aquí se explica cómo hacerlo con socat :

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

(La forkopción es necesaria para evitar socatdetenerse después de que se cierra la primera conexión proxy).

EDITAR : agregado reuseaddrcomo se sugiere en los comentarios.

Si quiere hacerlo con iptables, hay una guía en el sitio de Administración de Debian . Pero aún prefiero socatcosas más avanzadas, como proxy de IPv4 a IPv6, o quitar SSL para permitir que los viejos programas Java se conecten a servicios seguros ...

Sin embargo, tenga en cuenta que todas las conexiones en Deluge serán desde la IP de su servidor en lugar de la IP real del cliente. Si desea evitar eso, necesitará usar un proxy inverso HTTP real que agregue la IP del cliente original a la solicitud proxy en un encabezado HTTP.

Schnouki
fuente
1
¡Usted acaba de hacer mi día! Nunca me encontré socaty hace exactamente lo que estaba tratando de hacer con iptables desde hace bastante tiempo. Probé varias aplicaciones y todas funcionan sin problemas, conectándose al mundo exterior a través de tun0, al tiempo que proporcionan acceso a su interfaz web a través de veth1.
pskiebe 01 de
1
Después de hacer algunas pruebas, agregué la reuseaddrbandera. Esto evita port already in useerrores al iniciar y detener socat en rápida sucesión:socat -4 TCP-LISTEN:8112,reuseaddr,fork TCP:10.200.200.2:8112
pskiebe
8

Interconectar el espacio de nombres de red con el espacio de nombres principal siempre me molesta. La razón por la que generalmente creo un espacio de nombres es porque lo quiero aislado. Dependiendo de lo que esté tratando de lograr con espacios de nombres, la creación de interconexiones puede vencer ese propósito.

Pero incluso aislado, todavía quiero meterlo en la red, por conveniencia.

Esta solución le permite mantener el aislamiento y reenviarle algunas conexiones de todos modos. No necesita crear toda esa red entre los dos espacios de nombres de red solo para reenviar un puerto. Ejecute esto en el espacio de nombres donde desea aceptar conexiones. Debe ejecutarse como root para ip netns exectrabajar.

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

Escucha las conexiones en un espacio de nombres de red donde lo ejecuta, en el puerto 8112, luego el cliente conectado se execejecuta ip netns exec myvpn ...para ejecutar el resto dentro del myvpnespacio de nombres de la red, luego, una vez dentro del myvpnespacio de nombres de la red, crea una segunda conexión nuevamente con otro socat.

AnyDev
fuente
trabajando como un encanto
aproximado
Como no tengo mucha experiencia con la administración de Linux y me costó un tiempo averiguarlo: asegúrese de escapar de ambos :caracteres dentro de las comillas simples o de lo contrario podría encontrar un error que dice ... wrong number of parameters (2 instead of 1)(2 o 3). De lo contrario: funciona muy bien! Enormes gracias!
Igor
2

Para diluvio aquí es mi solución. No hay necesidad de iptables. Aquí están los pasos:

  1. Comience su túnel openvpn
  2. Crea un espacio de nombres y trae tu túnel openvpn allí:
ip netns agregar $ NS
# Espera a que aparezca el TUN
while [[$ (ruta ip | grep $ TUN | wc -l) == 0]]; duerme 1; hecho
MY_IP = $ (ip addr show $ TUN | grep inet | cut -d '' -f6 | cut -d '/' -f1)
# La forma en que extrae la puerta de enlace IP puede ser diferente para su conexión openvpn
GATEWAY_IP = $ MY_IP
# encarcelar mi $ TUN (interfaz VPN) en el espacio de nombres
conjunto de enlaces ip $ TUN netns $ NS
# Levante la interfaz con una subred (equivalente a la que me dio el servidor VPN)
ip netns exec $ NS ifconfig $ TUN $ MY_IP / 24 up
# Trae loopback hacia arriba
ip netns exec $ NS ifconfig lo 127.0.0.1/8 arriba
# Configure la puerta de enlace remota (su dirección IP VPN punto a punto)
ip netns exec $ NS route add default gw $ GATEWAY_IP
  1. Establezca una conexión veth entre su espacio de nombres predeterminado y el que ha creado:
# Configurar interfaces veth para la comunicación entre espacios de nombres
enlace ip agregar veth0 tipo veth nombre de compañero veth1
# Mueva la segunda vista a su espacio de nombres
conjunto de enlaces ip veth1 netns $ NS
# dar una IP del rango de IP no utilizado a la primera veth
ifconfig veth0 10.1.1.1/24 arriba
# Y el segundo
ip netns exec $ NS ifconfig veth1 10.1.1.2/24 arriba
# TODO: configure un puente entre veth1 y la interfaz eth para permitir que se comunique con LAN
# Configurar cliente DNS. ip netns emulará /etc/resolv.conf usando este archivo:
mkdir -p / etc / netns / $ NS
echo "servidor de nombres 8.8.4.4"> /etc/netns/$NS/resolv.conf
  1. Ejecute su diluido en $ NS y su deluge-web en su espacio de nombres predeterminado. Apunte deluge-web a la dirección IP 10.1.1.2 veth, donde dilucida escuchará su conexión.

Voila! Te has inundado de forma segura detrás de la VPN mientras tu web de diluvio es accesible libremente en tu red doméstica

Vlad
fuente
2

La respuesta de @ AndrDevEK es útil. Para ampliar eso, es posible que no desee instalar socat. En ese caso, puede lograr lo mismo con una configuración de reenvío de puerto SSH ligeramente enrevesada. En particular, la característica de reenvío de puertos a / desde un socket de dominio unix es útil aquí, porque los sockets de dominio unix operan independientemente de los espacios de nombres de red:

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=$!

Limpiar:

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

El primero ssh -N -Lse inicia dentro del espacio de nombres myvpn. Esto crea un socket de dominio unix /tmp/myunixsocky lo escucha. Las conexiones entrantes se reenvían a localhost: 8112 (dentro del espacio de nombres myvpn). El segundo ssh -N -Lse inicia en el espacio de nombres predeterminado. Esto crea un puerto TCP de escucha y reenvía las conexiones entrantes al socket de dominio unix.

Debe tenerse en cuenta que para que esto funcione, sshdentro del espacio de nombres de su red tendrá que funcionar si aún no lo está (y la operación de clave pública sin contraseña es útil):

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
Trauma digital
fuente