iptables - Alvo para rotear pacotes para uma interface específica?

25

Meu servidor doméstico possui duas interfaces principais eth1(uma conexão padrão à Internet) e tun0(um túnel OpenVPN). Eu gostaria de usar iptablespara forçar a saída de todos os pacotes gerados por um processo local pertencente ao UID 1002 e a saída de tun0todos os outros pacotes eth1.

Posso marcar facilmente pacotes correspondentes:

iptables -A OUTPUT -m owner --uid-owner 1002 -j MARK --set-mark 11

Agora, gostaria de colocar alguma regra na cadeia POSTROUTING (provavelmente da tabela mangle) para corresponder aos pacotes marcados com 11 e enviá-los para tun0, seguidos por uma regra que corresponda a todos os pacotes e enviá-los para eth1.

Encontrei o destino ROUTE, mas isso parece reescrever a interface de origem (a menos que eu esteja lendo incorretamente).

O iptables é capaz disso? Tenho que mexer com a tabela de roteamento (via ip routeou apenas os routecomandos herdados )?

Edit: Eu pensei que talvez eu deveria fornecer mais informações. No momento, não tenho outras regras do iptables (embora eu possa criar algumas regras para executar tarefas não relacionadas no futuro). Além disso, a saída de ip routeé:

default via 192.168.1.254 dev eth1  metric 203
10.32.0.49 dev tun0  proto kernel  scope link  src 10.32.0.50
85.17.27.71 via 192.168.1.254 dev eth1
192.168.1.0/24 dev eth1  proto kernel  scope link  src 192.168.1.73  metric 203

Eu não toquei na tabela de roteamento - é assim que é atualmente (embora pareça bastante suja). Sinto muito, mas não tenho o routecomando legado instalado nesta máquina.

E a saída de ip addr(é claro, eth0 e eth2 pode ser ignorada - são NICs que não estão sendo usadas no momento):

1: lo: <LOOPBACK,UP,LOWER_UP> mtu 16436 qdisc noqueue state UNKNOWN
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
    inet6 ::1/128 scope host
       valid_lft forever preferred_lft forever
2: eth0: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN qlen 1000
    link/ether 1c:6f:65:2a:73:3f brd ff:ff:ff:ff:ff:ff
3: eth1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast     state UP qlen 1000
    link/ether 00:1b:21:9d:4e:bb brd ff:ff:ff:ff:ff:ff
    inet 192.168.1.73/24 brd 192.168.1.255 scope global eth1
    inet6 fe80::21b:21ff:fe9d:4ebb/64 scope link
       valid_lft forever preferred_lft forever
4: eth2: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN qlen 1000
    link/ether 00:1b:21:6a:c0:4b brd ff:ff:ff:ff:ff:ff
5: tun0: <POINTOPOINT,MULTICAST,NOARP,UP,LOWER_UP> mtu 1500 qdisc     pfifo_fast state UNKNOWN qlen 100
    link/none
    inet 10.32.0.50 peer 10.32.0.49/32 scope global tun0

Edit: Eu consegui algo meio que funcionando, mas não está encaminhando pacotes marcados para tun0. Basicamente, adicionei uma tabela (11) e usei:

ip route add table 11 via 10.32.0.49 dev tun0
ip rule add priority 10000 fwmark 11 table 11

Quando eu apenas sudo -u user1000 wget -qO- whatismyip.orgrecebo o endereço IP externo da minha casa, mas, se o faço sudo -u user1002 wget -qO- whatismyip.org, também recebo o endereço IP da minha casa (mas eu deveria estar recebendo o IP na outra extremidade do túnel OpenVPN).

A execução iptables -vLconfirma que os pacotes estão sendo correspondidos pela regra de marcação, mas eles não parecem estar seguindo a regra de roteamento.

EDIT: Passei muito tempo nisso e, embora ainda não funcione, acho que estou um pouco mais perto.

A regra iptables deve estar na manglecadeia OUTPUT da tabela. Eu acho que também preciso de uma regra MASQUERADE na natcadeia POSTROUTING da tabela, para definir o endereço de origem. No entanto, o redirecionamento que ocorre após o mangle da OUTPUT não está funcionando corretamente.

Eu gastei 5 horas nisso agora, então estou dando um tempo e provavelmente voltarei a ele mais tarde hoje à noite ou amanhã.

Ethan
fonte

Respostas:

26

Recentemente, encontrei um problema semelhante, embora um pouco diferente. Eu queria rotear apenas a porta TCP 25 (SMTP) em uma interface OpenVPN tap0, enquanto roteava todo o outro tráfego (mesmo para o mesmo host) pela interface padrão.

Para fazer isso, tive que marcar pacotes e estabelecer regras para lidar com isso. Primeiro, adicione uma regra que torne os pacotes de rota do kernel marcados com 2a tabela through 3(explicada mais adiante):

ip rule add fwmark 2 table 3

Você poderia ter adicionado um nome simbólico a /etc/iproute2/rt_tables, mas eu não me preocupei em fazê-lo. O número 2e 3são escolhidos aleatoriamente. De fato, eles podem ser os mesmos, mas para maior clareza, não o fiz neste exemplo (embora faça isso na minha própria configuração).

Adicione uma rota para redirecionar o tráfego por uma interface diferente, assumindo que o gateway seja 10.0.0.1:

ip route add default via 10.0.0.1 table 3

Muito importante! Lave o cache de roteamento, caso contrário você não receberá uma resposta e ficará sentado com as mãos nos cabelos por algumas horas:

ip route flush cache

Agora, defina uma regra de firewall para marcar pacotes designados:

iptables -t mangle -A OUTPUT -p tcp --dport 465 -j MARK --set-mark 2

A regra acima se aplica somente se os pacotes vierem da máquina local. Veja http://inai.de/images/nf-packet-flow.png . Ajuste-o às suas necessidades. Por exemplo, se você deseja rotear apenas o tráfego HTTP de saída pela tap0interface, altere 465 para 80.

Para impedir que os pacotes enviados tap0obtenham seu endereço de LAN como IP de origem, use a regra a seguir para alterá-lo para seu endereço de interface (assumindo 10.0.0.2como endereço IP da interface tap0):

iptables -t nat -A POSTROUTING -o tap0 -j SNAT --to-source 10.0.0.2

Por fim, relaxe a validação da fonte do caminho reverso. Alguns sugerem que você defina como 0, mas 2parece uma escolha melhor de acordo com https://www.kernel.org/doc/Documentation/networking/ip-sysctl.txt . Se você pular isso, receberá pacotes (isso pode ser confirmado usando tcpdump -i tap0 -n), mas os pacotes não são aceitos. O comando para alterar a configuração para que os pacotes sejam aceitos:

sysctl -w net.ipv4.conf.tap0.rp_filter=2
Lekensteyn
fonte
Por que você usa o SNAT em vez do MASQUERADE? O MASQUERADE não faz a mesma coisa, exceto que o endereço IP é coletado da interface no "tempo de execução" e não é codificado no arquivo de configuração?
Ethan
6
@ Ethan De man iptables: Ele deve ser usado apenas com conexões IP (discadas) atribuídas dinamicamente: se você possui um endereço IP estático, deve usar o destino SNAT. Mascarar é equivalente a especificar um mapeamento para o endereço IP da interface em que o pacote está saindo, mas também tem o efeito de que as conexões sejam esquecidas quando a interface cair. Você está certo, mas como meu IP nunca mudaria, decidi usar o SNAT por recomendação da página de manual.
Lekensteyn
Eu acho que (embora não testado) o último passo (validação da fonte de caminho reverso) não é necessário. Você pode simplesmente adicionar outra regra à PREROUTINGcadeia DNATpara o endereço de origem correto (de acordo com o gateway padrão).
Christian Wolf
7

Eu resolvi isso. O problema ocorreu com as regras de roteamento na tabela 11. A Tabela 11 foi atingida, mas as regras de roteamento o tornam inoperante. Esse script é o que eu uso agora e parece funcionar bem (embora seja obviamente específico da minha configuração). Além disso, criei uma nova tabela 21 dedicada ao uplink principal (eth1).

# Add relevant iptables entries.
iptables -t mangle -A OUTPUT -m owner --uid-owner 1002 -j MARK --set-mark 11
iptables -t nat -A POSTROUTING -o tun0 -j MASQUERADE

# Flush ALL THE THINGS.
ip route flush table main
ip route flush table 11
ip route flush table 21
ip rule flush

# Restore the basic rules and add our own.
ip rule add lookup default priority 32767
ip rule add lookup main priority 32766
ip rule add fwmark 11 priority 1000 table 11
# This next rule basically sends all other traffic down eth1.
ip rule add priority 2000 table 21

# Restore the main table.  I flushed it because OpenVPN does weird things to it.
ip route add 127.0.0.0/8 via 127.0.0.1 dev lo
ip route add 192.168.1.0/24 dev eth1 src 192.168.1.73
ip route add default via 192.168.1.254

# Set up table 21.  This sends all traffic to eth1.
ip route add 192.168.1.0/24 dev eth1 table 21
ip route add default via 192.168.1.254 dev eth1 table 21

# Set up table 11.  I honestly don't know why 'default' won't work, or
# why the second line here is needed.  But it works this way.
ip route add 10.32.0.49/32 dev tun0 table 11
ip route add 10.32.0.1 via 10.32.0.50 dev tun0 table 11
ip route add 0.0.0.0/1 via 10.32.0.50 dev tun0 table 11

ip route flush cache

## Edição de MeanderingCode (porque ainda não posso comentar)

Obrigado por esta resposta! Parece que isso pode ficar confuso, pois você precisaria manter as informações da rota aqui (possivelmente duplicando ou quebrando outras coisas que podem querer definir rotas).

Você pode estar enfrentando "coisas estranhas" em sua tabela de roteamento a partir do OpenVPN porque o servidor está configurado para "enviar" rotas, permitindo que todo o tráfego seja roteado pela interface de rede VPN, em vez da Internet "vazia". Ou sua configuração do OpenVPN ou qualquer script / aplicativo que esteja configurado está configurando rotas.

No primeiro caso, você pode editar sua configuração OpenVPN e colocar em uma linha contendo "route-nopull"
Neste último, a configuração de seleção para OpenVPN ou qualquer invólucro (network-manager-openvpn, por exemplo em muitas distros Linux Desktop atuais)
em nos dois casos, eliminar a configuração de roteamento onde está sendo definida é mais limpo e seguro do que liberar a tabela, dependendo de quando você executa esse script e o que mais o seu sistema está fazendo.

Felicidades!

Ethan
fonte
2

Eu acho que você quer:

/sbin/ip route add default via 10.32.0.49 dev tun0 table 11
/sbin/ip rule add priority 10000 fwmark 11 table 11

http://lartc.org/howto/lartc.netfilter.html

Mas eu não testei o acima.

mfarver
fonte
O primeiro comando retorna "Erro:" para "está duplicado ou" 10.32.0.49 "é um lixo."
Ethan
Desculpe esqueci a via entre o padrão e o IP.
Mfrver
Eu tentei. Parece ter o mesmo efeito que deixar a defaultpalavra-chave de fora.
Ethan
Para eliminar opções, você pode tentar capturar pacotes no tun0 e verificar se os pacotes estão terminando nessa interface. tcpdump -i tun0 .. como alternativa, você precisa basear-se no ID do usuário? Você poderia fazê-lo com base no endereço IP de destino (mais fácil)? route add <host remoto> via 10.32.0.49
mfarver
Não posso basear-me se estiver fora do endereço IP de destino - haveria muitos deles. Teoricamente, eu também poderia basear isso no pid, mas isso é ainda mais difícil, porque não conhecerei o pid até o (s) daemon (s) começarem.
Ethan
0

Isso pode ser feito sem o comando iptables Executar comando ip simples

Para o uid 1002:

ip rule add uidrange 1002-1002 table 502

Adicione a rota padrão para a tabela 502 na interface que você deseja dizer

eth0 ip rule add default via a.b.c.d dev eth0
jainendra
fonte
Testei esse comando e ele não funcionou:Error: argument "uidrange" is wrong: Failed to parse rule type
kasperd
@ Kasperd você deve estar fazendo errado, porque funciona bem para mim.
horseyguy