encaminhamento de porta para aplicativo no namespace da rede com vpn

13

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

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 espaço para nome, da maneira que pretendemos:

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 dilúvio para este exemplo. Eu tentei vários aplicativos com uma interface da web para garantir que não seja um problema específico do dilúvio.

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 de fora se eu especificar o ip do 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 espaço para nome. O objetivo é abrir um navegador em um computador dentro da minha LAN e obter a interface da web com http: // my-server-ip: 8112 (my-server-ip é o ip estático do servidor que instancia a interface de rede)

Edição: Eu removi minhas tentativas de criar regras de 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

Tentei as regras DNAT e SNAT e instalei um MASQUERADE por uma boa medida, mas como não sei o que estou fazendo, minhas tentativas são inúteis. Talvez alguém possa me ajudar a montar essa construção.

EDIT: A saída tcpdump de tcpdump -nn -q tcp port 8112. Sem surpresa, 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 que explica 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 apreendeu e nada mais aconteceu. No entanto, o @schnouki também sugeriu o uso socatcomo proxy TCP e 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

Ainda não entendi o estranho embaralhamento de porta enquanto o tráfego atravessa as interfaces veth, mas meu problema está resolvido agora.

pskiebe
fonte
Isenção de responsabilidade: não tenho nenhuma experiência com vethdispositivos (acho isso muito interessante ... ;-)). Você já usou tcpdumppara verificar até onde os pacotes recebidos chegam? Se tcpdump -i veth0não mostrar nada, tcpdumo -i lopode ser necessário.
Hauke ​​Laging
Eu adicionei a saída não detalhado de tcpdump
pskiebe

Respostas:

8

Sempre tive problemas com os redirecionamentos do iptables (provavelmente minha culpa, tenho certeza de que é possível). Mas para um caso como o seu, é IMO mais fácil fazê-lo na terra do usuário sem o iptables.

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

Veja como fazer isso com o socat :

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

(A forkopção é necessária para evitar a socatinterrupção após o fechamento da primeira conexão com proxy).

EDIT : adicionado reuseaddrcomo sugerido nos comentários.

Se você absolutamente deseja fazê-lo com o iptables, há um guia no site de Administração Debian . Mas ainda prefiro socatcoisas mais avançadas - como proxy de IPv4 para IPv6 ou remoção de SSL para permitir que programas Java antigos se conectem a serviços seguros ...

Cuidado, porém, que todas as conexões no Deluge serão do IP do servidor em vez do IP do cliente real. Se você quiser evitar isso, precisará usar um proxy reverso HTTP real que inclua o IP do cliente original na solicitação em proxy em um cabeçalho HTTP.

Schnouki
fonte
1
Você fez meu dia! Eu nunca me deparei socate ele realiza exatamente o que eu estava tentando fazer com o iptables há algum tempo. Testei vários aplicativos e todos eles estão funcionando perfeitamente, conectando-se ao mundo exterior através do tun0, enquanto ainda fornece acesso à sua interface da web através do veth1.
Pskiebe
1
Depois de fazer alguns testes, adicionei a reuseaddrbandeira. Isso evita port already in useerros ao iniciar e parar o socat em rápida sucessão:socat -4 TCP-LISTEN:8112,reuseaddr,fork TCP:10.200.200.2:8112
pskiebe
7

Interconectar o namespace da rede com o namespace principal sempre me incomoda. O motivo pelo qual eu geralmente crio um espaço para nome é porque o quero isolado. Dependendo do que você está tentando obter com os namespaces, a criação de interconexões pode derrotar esse objetivo.

Mas, mesmo isolado, ainda quero cutucá-lo pela rede, por conveniência.

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

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 em que você o executa, na porta 8112, e o cliente conectado começa execa executar ip netns exec myvpn ...para executar o restante dentro do myvpnnamespace de rede e, uma vez dentro do myvpnnamespace de rede, cria a segunda conexão novamente com outra socat.

AnyDev
fonte
trabalhando como um encanto
aproximatenumber
Como eu não tenho muita experiência com administração de linux e me custou algum tempo para descobrir: certifique-se de escapar dos dois :caracteres entre aspas simples ou você pode encontrar um erro dizendo ... wrong number of parameters (2 instead of 1)(2 ou 3). Caso contrário: funciona muito bem! Muito obrigado!
Igor
2

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

  1. Inicie seu túnel openvpn
  2. Crie um espaço para nome e traga seu túnel openvpn para lá:
netns ip adicionam $ NS
# Aguarde o TUN aparecer
while [[$ (rota ip | grep $ TUN | wc -l) == 0]]; dorme 1; feito
MY_IP = $ (endereço IP mostra $ TUN | grep inet | cut -d '' -f6 | cut -d '/' -f1)
# A maneira como você extrai o IP do gateway pode ser diferente para sua conexão openvpn
GATEWAY_IP = $ MY_IP
# prende meu $ TUN (interface VPN) no espaço para nome
conjunto de links IP $ TUN netns $ NS
# Exiba a interface com uma sub-rede (equivalente à fornecida pelo servidor VPN)
exec netns ip $ NS ifconfig $ TUN $ MY_IP / 24 up
# Trazer loopback para cima
exec netns ip $ NS ifconfig lo 127.0.0.1/8 up
# Configure o gateway remoto (seu endereço IP da VPN pointtopoint)
rota net $ exec exec netns adicionar padrão gw $ GATEWAY_IP
  1. Estabeleça a conexão veth entre o espaço para nome padrão e o que você criou:
# Configurar veth interfaces para comunicação entre namespaces
link ip adicionar tipo veth0 nome do par veth veth1
# Mova o segundo veth para o seu espaço para nome
conjunto de links ip net veth1 $ NS
# fornece um IP do intervalo de IP não utilizado ao primeiro veth
ifconfig veth0 10.1.1.1/24 up
# E o segundo
exec netns ip $ NS ifconfig veth1 10.1.1.2/24 up
# TODO: configure uma ponte entre veth1 e a interface eth para permitir que ela se comunique com a LAN
# Configure o cliente DNS. ip netns emulará o /etc/resolv.conf usando este arquivo:
mkdir -p / etc / netns / $ NS
echo "nameserver 8.8.4.4"> /etc/netns/$NS/resolv.conf
  1. Execute seu deluged no $ NS e seu deluge-web no seu namespace padrão. Aponte deluge-web para o endereço IP 10.1.1.2 veth, onde deluged estará escutando sua conexão.

Voila! Você ficou protegido por trás da VPN enquanto a sua rede de dilúvio está disponível gratuitamente em sua rede doméstica

Vlad
fonte
2

A resposta de @ AndrDevEK é útil. Para expandir isso, você pode não querer instalar socat. Nesse caso, você pode conseguir o mesmo com uma configuração de encaminhamento de porta 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=$!

Limpar:

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

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

Deve-se observar que, para que isso funcione, ssho espaço para nome da rede precisará estar funcionando se ainda não estiver (e a operação pubkey sem senha é ú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
fonte