Como fazer com que todo o tráfego passe por uma interface no Linux

Como fazer com que todo o tráfego passe por uma interface no Linux

eu tenho uminterface autoescrita tun0(TUN/TAPbaseado) que produz o que recebe.
Preciso que todo o tráfego do sistema flua através desta interface.
A função da interface é:

  1. Para descobrir pacotes que provavelmente serão censurados e tunelá-los.
  2. Passe todos os outros tráfegos intactos.

Como você deve imaginar, estou tentando construir uma ferramenta anticensura.
A decisão sobre o tunelamento deve ser tomada dentro do processo tun0
porque somente aí podemos usar DNS confiável.

Preciso da sua ajuda para me mostrar como fazer todo o tráfego fluir por meio de uma interface autoescrita tun0. Se o tun0 precisar de alterações, peço que você forneça essas alterações.

Abaixo está como tentei fazer todo o tráfego passar por tun0 e falhar (falha nos pings).

Compilando

  1. gcc tun0.c
  2. sudo ./a.out

Configurando

  1. sudo ip addr add 10.0.0.1/24 dev tun0
  2. criar mesa João

    $ cat /etc/iproute2/rt_tables 
    #
    # reserved values
    #
    255     local
    254     main
    253     default
    0       unspec
    #
    # local
    #
    #1      inr.ruhep
    
    200 John
    

A ordem é importante:

  1. sudo ip rule add from all lookup John
  2. sudo ip route add default dev tun0 table John
  3. sudo ip rule add iif tun0 lookup main priority 500

    $ ip rule
    0:      from all lookup local 
    500:    from all iif tun0 lookup main 
    32765:  from all lookup John 
    32766:  from all lookup main 
    35000:  from all lookup default 
    

Solução de problemas

  1. sudo tcpdump -i wlp2s0 -qtln icmpe então ping -I tun0 8.8.8.8não mostra nenhum pacote capturado, significa que nenhum pacote é transmitido de tun0 para wlp2s0 via iif tun0 lookup mainregra.

  2. Quando substituí tun0por lotodos os lugares, funcionou para mim.

Também tentei

  1. Desativando a filtragem de caminho reverso, rp_filter=0em/etc/sysctl.conf

Solução de problemas de resposta

iptables -I FORWARD -j LOG --log-prefix "filter/FORWARD " 
iptables -t nat -I OUTPUT -j LOG --log-prefix "nat/OUTPUT " 
iptables -t nat -I PREROUTING -j LOG --log-prefix "nat/PREROUTING " 
iptables -t nat -I POSTROUTING -j LOG --log-prefix "nat/POSTROUTNG "
tail -f /var/log/syslog

Fontes modificadas da resposta também sãoaqui.

Responder1

Portanto, na sua configuração, todos os pacotes que você tenta enviar para a rede inicialmente originados 10.0.0.1(porque estão passando pela tun0interface e seu endereço local é 10.0.0.1). Você captura os pacotes, está tudo bem até agora.
Agora, tun0envia os pacotes ainda mais.Endereço de Origemé 10.0.0.1e você deseja que os pacotes saiam por uma interface diferente ( wlp2s0no seu caso). Isso éroteamentoentão vamos ativar o roteamento primeiro:

sysctl -w net.ipv4.ip_forward=1

Depois disso, se você observar, tcpdumppoderá wlp2s0notar que os pacotes saem com o endereço de origem 10.0.0.1e não com o endereço de origem da interface wlan (o que você esperaria, eu acho). Então precisamos mudar o endereço de origem e ele se chamafonte NAT. No Linux é fácil com a ajuda defiltro de rede/iptables:

iptables -t nat -A POSTROUTING -o wlp2s0 -s 10.0.0.1 -j MASQUERADE

Verifique também se sua FORWARDrede possui ACCEPTuma política ou você precisarápermitir encaminhamentocom algo como:

iptables -A FORWARD -i tun0 -o wlp2s0 -s 10.0.0.1 -j ACCEPT
iptables -A FORWARD -i wlp2s0 -o tun0 -d 10.0.0.1 -j ACCEPT

Tudo deve funcionar agora:núcleo do Linuxfaz o roteamento, está movendo pacotes da tun0interface para wlp2s0.filtro de rededeve alterar o IP de origem 10.0.0.1para wlp2s0o endereço atribuído à sua interface para pacotes de saída. Ele memoriza todas as conexões e quando os pacotes de resposta retornam (se retornarem) ele altera o endereço de destino do wlp2s0endereço atribuído à interface 10.0.0.1(o recurso "conntrack").
Bem, deveria, mas não acontece. Parece,filtro de redefica confuso com essa complicada configuração de roteamento e com o fato de que o mesmo pacote passa primeiro pela OUTPUTcadeia e depois é roteado e chega à PREROUTINGcadeia. Pelo menos na caixa do Debian 8 não funciona.
A melhor maneira de solucionar problemasfiltro de redeé o TRACErecurso:

modprobe ipt_LOG
iptables -t raw -A OUTPUT -p icmp -j TRACE
iptables -t raw -A PREROUTING -p icmp -j TRACE

Eu habilito apenas o rastreamento para pacotes ICMP, você pode usar outro filtro para depurar.
Ele mostrará por quais tabelas e cadeias o pacote passa. E posso ver que o pacote não avança na FORWARDcadeia (e não está sendo capturado pela nat/POSTROUTINGcadeia que realmente o faz SNAT).
Abaixo estão várias abordagens para fazer isso funcionar.

ABORDAGEM #1

A melhor maneira de desfazer a confusãofiltro de redeé alterar o endereço IP de origem dos pacotes no tun0.caplicativo. É também a maneira mais natural. Precisamosmude 10.0.0.1 para 10.0.0.2no caminho para fora e10.0.0.2 a 10.0.0.1no caminho de volta.
Modifiquei tun0.ccom o código de alteração do endereço de origem.Aqui está o novo arquivoeaqui está o arquivo de patchPara o seu tun0.c. Mudanças no cabeçalho IP também envolvemcorreção de soma de verificação, então peguei um código deProjeto OpenVPN. Aqui está a lista completa de comandos que executo após uma reinicialização e tun0_changeip.cinicialização limpas:

ifconfig tun0 inet 10.0.0.1/30 up
sysctl -w net.ipv4.ip_forward=1
ip route add default dev tun0 table John
ip rule add from all lookup John
ip rule add from 10.0.0.2 lookup main priority 500
iptables -t nat -A POSTROUTING -o wlp2s0 -s 10.0.0.2 -j MASQUERADE

Observe que você não precisa desligar ofiltragem de caminho reversonesse caso, porque tudo é legal - tun0só recebe e envia pacotes que pertencem à sua sub-rede. Além disso, você pode fazer um roteamento baseado na origem em vez de baseado na interface.

ABORDAGEM #2

É possível fazer isso SNATantes que o pacote alcance tun0a interface. Mas não é muito correto. Você definitivamente precisará desligar ofiltragem de caminho reversonesse caso:

sysctl -w net.ipv4.conf.tun0.rp_filter=0
# It won't work without also changing the "all" value
sysctl -w net.ipv4.conf.all.rp_filter=0

Agora faça SNAT: iptables -t nat -A POSTROUTING -o tun0 -s 10.0.0.1 -j SNAT --to-source ip.address.of.your.wlan.interface

Aqui mudamos o endereço de origem apenasantesos pacotes chegam ao tun0dispositivo. tun0.co código reenvia esses pacotes "como estão" (com endereço de origem alterado) e eles são roteados com sucesso através da interface wlan. Mas você pode ter um IP dinâmico na interface wlan e querer usar MASQUERADE(para não especificar explicitamente o endereço da interface). Veja como você pode usar MASQUERADE:

iptables -t nat -A POSTROUTING -o tun0 -s 10.0.0.1 -j SNAT --to-source 10.0.55.1
iptables -t nat -A POSTROUTING -o wlp2s0 -s 10.0.55.1 -j MASQUERADE

Observe o " 10.0.55.1" endereço IP - é diferente. Você pode usar qualquer IP aqui, não importa. Os pacotes alcançam nat/POSTROUTINGa cadeia na wlp2s0interface se alterarmos o IP de origem antes. E agora não depende de um IP estático para interface wlan.

ABORDAGEM #3

Você também pode usar fwmark. Dessa forma você não precisa SNAT, mas irá capturar apenas pacotes de saída:
Primeiro precisamos desabilitarfiltragem de caminho reversopois tun0encaminhará pacotes que pertencem a outra rede:

sysctl -w net.ipv4.conf.tun0.rp_filter=0
# It won't work without also changing the "all" value
sysctl -w net.ipv4.conf.all.rp_filter=0

Now let's alter the routing rules a bit:
# Delete old rules
ip rule del iif tun0 lookup main
ip rule del from all lookup John

# Packets will start going from wlan interface so they will have source address of it
iptables -t mangle -A OUTPUT -o wlp2s0 -j MARK --set-mark 1
ip rule add fwmark 0x1 lookup John

Esse é outro "hack" pararoteamentoefiltro de redeisso funciona na minha caixa Debian 8, mas ainda assim recomendo adotar a primeira abordagem, pois é mais natural e não usa nenhum hacks.


Você também pode considerar construir seu aplicativo como umproxy transparente. Acho que seria muito mais fácil em vez de analisar pacotes do dispositivo tun.

informação relacionada