port forwarding para aplicação em namespace de rede com vpn

12

Consegui configurar um namespace de rede, estabelecer um túnel com o openvpn e iniciar um aplicativo que use esse túnel dentro do namespace. Até aí tudo bem, mas este aplicativo pode ser acessado através de uma interface web e não consigo descobrir como encaminhar solicitações para a interface web dentro da minha LAN.

Eu segui um guia do @schnouki explicando como configurar um namespace de rede e executar o OpenVPN dentro dele

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

Depois disso, posso verificar meu ip externo e obter resultados diferentes dentro e fora do namespace, como pretendido:

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

O aplicativo é iniciado, estou usando o deluge para este exemplo. Eu tentei vários aplicativos com uma interface da web para garantir que não seja um problema específico de inundação.

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

Consigo acessar a interface da web na porta 8112 de dentro do namespace e do lado de fora se eu especificar o 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

Mas eu quero redirecionar a porta 8112 do meu servidor para o aplicativo no namespace. O objetivo é abrir um navegador em um computador dentro da minha LAN e obter a interface web com link (meu-servidor-ip é o ip estático do servidor que instanciava a interface de rede)

EDIT: Eu removi minhas tentativas de criar regras do iptables. O que estou tentando fazer é explicado acima e os seguintes comandos devem gerar um 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

Eu tentei regras DNAT e SNAT e joguei um MASQUERADE para uma boa medida, mas desde que eu não sei o que estou fazendo, minhas tentativas são fúteis. Talvez alguém possa me ajudar a montar esse constructo.

EDIT: A saída do tcpdump de tcpdump -nn -q tcp port 8112 . Não é novidade que o primeiro comando retorna um HTTP 200 e o segundo comando termina com uma conexão recusada.

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: o próprio @schnouki me indicou um artigo da Administração Debian explicando um proxy TCP genérico do iptables . Aplicado ao problema em questão, o script deles ficaria assim:

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

Infelizmente, o tráfego entre as interfaces veth foi tomado e nada mais aconteceu. No entanto, @schnouki também sugeriu o uso de socat como um proxy TCP e isso está funcionando perfeitamente.

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

Eu ainda não entendi a estranha porta embaralhada enquanto o tráfego está passando pelas interfaces veth, mas meu problema está resolvido agora.

    
por pskiebe 25.01.2016 / 13:17

4 respostas

8

Eu sempre tive problemas com redirecionamentos do iptables (provavelmente minha culpa, eu tenho certeza que é possível). Mas, para um caso como o seu, é mais fácil para o OMI fazê-lo no user-land sem o iptables.

Basicamente, você precisa ter um daemon em seu espaço de trabalho "padrão", escutando na porta TCP 8112 e redirecionando todo o tráfego para a porta 10.0.200.200.2 8112. Portanto, é um proxy TCP simples.

Veja como fazer isso com socat :

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

(A opção fork é necessária para evitar que socat pare depois que a primeira conexão com proxy for fechada).

EDITAR : adicionado reuseaddr como sugerido nos comentários.

Se você quer fazer isso com o iptables, há um guia no site Debian Administration . Mas eu ainda prefiro o socat para coisas mais avançadas - como o proxy do IPv4 para o IPv6, ou remover o SSL para permitir que programas Java antigos se conectem a serviços seguros ...

Cuidado, no entanto, que todas as conexões no Deluge serão do IP do seu servidor em vez do IP do cliente real. Se você quiser evitar isso, você precisará usar um proxy reverso HTTP real que adicione o IP do cliente original à solicitação com proxy em um cabeçalho HTTP.

    
por 01.02.2016 / 01:26
5

O namespace de rede de interconexão com o namespace principal sempre me incomoda. A razão pela qual eu geralmente crio um namespace é porque eu quero isolá-lo. Dependendo do que você está tentando alcançar com namespaces, criar interconexões pode derrotar esse propósito.

Mas, mesmo isolado, eu ainda quero colocá-lo na rede, por conveniência.

Esta solução permite manter o isolamento e encaminhar algumas conexões para ele de qualquer maneira. Você não precisa criar toda essa rede entre os dois namespaces da rede apenas para encaminhar uma porta. Execute isso no namespace onde você deseja aceitar conexões. Deve ser executado como root para que ip netns exec funcione.

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

Ele escuta conexões em um namespace de rede no qual você o executa, na porta 8112, em seguida, o cliente conectado obtém exec para executar ip netns exec myvpn ... para executar o restante dentro do espaço de nomes myvpn network e depois dentro do myvpn namespace de rede cria segunda conexão novamente com outro socat .

    
por 26.07.2016 / 18:08
2

Para o dilúvio, aqui está a minha solução. Não há necessidade de iptables. Aqui estão os passos:

  1. Inicie seu túnel openvpn
  2. Crie um namespace e traga seu túnel openvpn para lá:
ip netns add $NS
# Wait for the TUN to come up
while [[ $(ip route|grep $TUN|wc -l) == 0 ]]; do sleep 1; done
MY_IP=$(ip addr show $TUN|grep inet|cut -d' ' -f6|cut -d'/' -f1)
# The way you extract gateway IP might be different for your openvpn connection
GATEWAY_IP=$MY_IP
# jail my $TUN (VPN interface) into the namespace
ip link set $TUN netns $NS
# Bring the interface up with a subnet (equivalent to the one given to me by VPN server)
ip netns exec $NS ifconfig $TUN $MY_IP/24 up
# Bring loopback up
ip netns exec $NS ifconfig lo 127.0.0.1/8 up
# Set up remote gateway (your pointtopoint VPN IP address)
ip netns exec $NS route add default gw $GATEWAY_IP
  1. Estabeleça uma conexão veth entre o namespace padrão e o que você criou:
# Set up veth interfaces for communication between namespaces
ip link add veth0 type veth peer name veth1
# Move the second veth to your namespace
ip link set veth1 netns $NS
# give an IP from unused IP range to first veth
ifconfig veth0 10.1.1.1/24 up
# And the second one
ip netns exec $NS ifconfig veth1 10.1.1.2/24 up
# TODO: set up a bridge between veth1 and eth interface to let it communicate with LAN
# Set up DNS client. ip netns will emulate /etc/resolv.conf using this file:
mkdir -p /etc/netns/$NS
echo "nameserver 8.8.4.4" >/etc/netns/$NS/resolv.conf
  1. Execute sua inundação no $ NS e sua rede de dilúvio em seu namespace padrão. Aponte o deluge-web para o endereço IP 10.1.1.2 veth, onde o deluged estará escutando sua conexão.

Voila! Você foi inundado com segurança por trás da VPN, enquanto sua web de inundação é acessível gratuitamente em sua rede doméstica

    
por 19.03.2017 / 02:45
0

@ A resposta de AndrDevEK é útil. Para expandir isso, talvez você não queira instalar socat . Nesse caso, você pode conseguir a mesma coisa com uma configuração de porta-forward SSH levemente complicada. Em particular, o recurso de encaminhamento de porta para / de um soquete de domínio unix é útil aqui, porque os soquetes de domínio unix operam independentemente dos namespaces de rede:

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

Limpeza:

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

O primeiro ssh -N -L é iniciado dentro do namespace myvpn. Isso cria um soquete do domínio unix /tmp/myunixsock e escuta nele. Conexões de entrada são encaminhadas para localhost: 8112 (dentro do namespace myvpn). O segundo ssh -N -L é iniciado no namespace padrão. Isso cria uma porta TCP de escuta e encaminha conexões de entrada para o soquete do domínio unix.

Deve-se notar que, para que isso funcione, ssh dentro do namespace da sua rede precisará estar funcionando se ainda não estiver (e a operação pubkey sem senha for ú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
    
por 01.11.2018 / 00:28