Discuta este tópico no fórum

Se este conteúdo te ajudou, deixe um presente!

sexta-feira, 29 de julho de 2011

Arranhando roteamento avançado em Linux

Esse é para as pessoas que algum dia já conectaram duas placas de redes em um equipamento Linux e nada funcionou direito...

O Linux é um sistema operacional versátil. Opera desde celulares a grandes computadores. Dentro deste espectro, ele também é muito utilizado como o coração de uma gama enorme de roteadores. Um Linux não faz feio frente a um roteador Cisco, só talvez não com o mesmo desempenho. Enfim, com Linux, qualquer computador se torna um roteador avançado. Basta adicionar mais interfaces de rede.

Um dos problemas comuns de conectar 2 placas de rede a um computador é em relação ao roteador padrão. Sempre existe apenas um roteador padrão. Para uma única interface, o que em geral é encontrado em um computador convencional, temos as seguintes rotas:

# ip route
192.168.1.0/24 dev eth0  proto kernel  scope link  src 192.168.1.11
127.0.0.0/8 dev lo  scope link
default via 192.168.1.1 dev eth0

A primeira é da rede diretamente conectada pela eth0, a segunda, o mesmo da primeira para a interface de loopback. E a última é a rota para as outras redes (o roteador padrão). Quando adicionamos uma segunda interface de rede, aparece mais uma rota diretamente conectada:

# ip route
192.168.1.0/24 dev eth0  proto kernel  scope link  src 192.168.1.11
192.168.2.0/24 dev eth1  proto kernel  scope link  src 192.168.2.22
127.0.0.0/8 dev lo  scope link
default via 192.168.1.1 dev eth0

Em geral, a segunda interface de rede conecta uma rede isolada, acessível apenas através do próprio Linux (como roteador ou não).

Agora, quando a máquina que está conectada em duas redes não é a única forma de acessar a subrede, o que acontece? Imagine um cenário onde um Linux está conectado em duas redes. Simples não?

Rede A(192.168.1.0/24)              Rede B(192.168.2.0/24) 
       |............Roteador (R)...........|
   X...|                                   |....Y
       |........eth0 Linux (L) eth1........|                  
       |                                   |

Nem tanto. Se o equipamento X, conectado na rede A tenta falar com a eth0 do servidor Linux, ele responde sem problemas (pois está diretamente conectado). O mesmo ocorre quando o equipamento Y tenta falar com o servidor Linux pela interface eth1. Agora, se X precisa falar com o endereço da interface eth1? O que acontece?
  1. X prepara um pacote para 192.168.2.22
  2. X envia para o roteador pois o IP 192.168.2.22 não está nas suas redes locais
  3. Roteador recebe o pacote da rede A e repassa para a rede B
  4. O servidor Linux recebe o pacote pela interface eth1
O caminho de ida foi sem problemas. Agora a resposta:
  1. O servidor Linux prepara resposta para X
  2. X está em uma rede diretamente conectada (interface eth0). O pacote é enviado diretamente.
Olha que interessante! O pacote chegou pela interface eth1 mas saiu pela eth0 (e com o MAC dela). O roteador, se quisesse, não teria como restringir a resposta do servidor Linux.

Vamos a outro cenário. Uma máquina Z fora das duas redes, tenta falar com a a interface eth0.
  1. Roteador recebe o pacote vindo de Z, pela rede C, e repassa para a rede A
  2. O servidor Linux recebe o pacote pela interface eth0
  3. O servidor Linux prepara a resposta de Z 
  4. Como Z não é uma interface diretamente conectada, ele envia ao roteador padrão (192.168.1.1).
  5. O Roteador recebe o pacote vindo de (192.168.1.11) vindo da rede A e o repassa para Z
Sem problemas. Agora se Z estivesse falando com a eth1?
  1. Roteador recebe o pacote vindo de Z, pela rede C, e repassa para a rede B
  2. O servidor Linux recebe o pacote pela interface eth1
  3. O servidor Linux prepara a resposta de Z
  4. Como Z não é uma interface diretamente conectada, ele envia ao roteador padrão (192.168.1.1).
  5. O Roteador recebe o pacote de (192.168.2.22) vindo da rede A e REJEITA!. Como o pacote da rede B pode surgir dentro da rede A?
O problema é que a tabela de roteamento não faz distinção quanto ao ip de origem (ou interface de origem). Ele apenas observa o destino. Como o destino é fora da rede local, ele envia pelo roteador padrão. Não existe 2 roteadores "padrão". Como resolver esta questão?

O Linux permite que seja criada mais de uma tabela de roteamento. Basta acrescentar a qual tabela estamos nos referenciando no comando "ip route". Exemplo:

# ip route show table main
192.168.1.0/24 dev eth0  proto kernel  scope link  src 192.168.1.11
192.168.2.0/24 dev eth1  proto kernel  scope link  src 192.168.2.22
127.0.0.0/8 dev lo  scope link
default via 192.168.1.1 dev eth0

As tabelas "local" e "0" também são bem interessantes para quem só usava até agora o comando "route".

O que precisamos fazer é criar uma nova tabela. Primeiro, cadastre um nome (para não usar números)

echo "1 redeB" >>/etc/iproute2/rt_tables

Isto permite que redeB seja usada nos comandos ao invés de apenas números.

Agora, a nova tabela de roteamento pode ser recriada.

ip route add 192.168.2.0/24 dev eth1 table redeB
ip route add default via 192.168.2.1 dev eth1 table redeB

 Mas quando que esta tabela nova vai ser usada? Isto pode ser definido por regras. Esta regra faz com que todos os pacotes que chegam pela interface eth1 utilizem a tabela de rotas redeB ao invés das regras padrão.

ip rule add from 192.168.2.2/32 lookup redeB

E pode ser necessário (em geral é) limpar o cache de rotas:

ip route flush cache

Como sempre, toda esta configuração (exceto pelo cadastro do nome) é volátil e se perde ao derrubar a rede ou reiniciar o computador. Por isto, deve ser carregada em script junto ao processo de configuração da rede.

Um outro cenário onde a configuração de tabelas de roteamento distintas pode ser útil é o caso de uma VPN quando até o tráfego Internet da rede interna deve ser roteado para a VPN. O roteador VPN deve utilizar uma rota padrão que aponte para a Internet, para operar a VPN, mas os pacotes vindos da rede interna devem ser todos roteados pela VPN.

Outro caso seria em laptops com interface WLAN e LAN. Se as duas estiverem conectadas em segmentos distintos da rede local, para algumas máquinas uma das interfaces não será acessível.

Este é só um caso onde é necessário o roteamento avançado. Porém, roteamento avançado pode ser usado em uma infinidade de casos como múltiplas conexões para a Internet. Vale a pena buscar no Google...

Ah, se alguém sentiu falta dos comandos "ifconfig", "route", ta mais do que na hora de aprender o comando "ip". Ele é mais limpo, mais fácil e toda a saída pode ser usada como entrada, basta prefixar com "ip <modulo> add/del". Talvez eu escreva sobre isto no futuro...

Atualização: pode ocorrer casos de pacotes de "origem marciana", os "martian source". Por que isto? O Linux possui uma filtragem que bloqueia pacotes estranhos que chegam por uma interface mas seriam roteados por outra, chamado de "Reverse Path Filtering" (rp_filter). Ex: pacotes com IPs da intranet chegando pela interface conectada na internet ou vice-versa. Porém, para casos onde as duas redes podem se comunicar, esta filtragem não faz sentido desta forma. Por isto, é necessário mudar o modo de "1" ("Strict Reverse Path filtering") para "2" ("Loose Reverse Path filtering"). Isto deve ser definido nos parâmetros: net.ipv4.conf.default.rp_filter, net.ipv4.conf.all.rp_filter e/ou net.ipv4.conf.<interface>.rp_filter.

11 comentários:

  1. Parabéns pelo post, bastante útil e bem escrito.

    ResponderExcluir
  2. Sensacional. Texto didático, bem escrito, com um português impecável e de conteúdo técnico de altíssima qualidade, com ótimos exemplos. Fazia tempo que eu não lia um artigo assim em português.

    ResponderExcluir
  3. Obrigado pelos elogios. Vou tentar escrever outros artigos similares quando me deparar com tecnologias interessante.

    ResponderExcluir
  4. Parabéns pelo artigo bem escrito e abordado de forma técnica.

    PS: Vou ser sincero, até eu ler o artigo a dupla ifconfig e route, foram comando do meu dia-a-dia. Eu trabalhava mais e não sabia. :|

    ResponderExcluir
  5. Prezado Luiz Angelo! Parabéns pelo ótimo artigo! Bela contribuição para a comunidade GNU/Linux. Porém, acredito que não há hora de se aprender um comando ou tecnologia. Isso vai da necessidade de cada um. Eu posso passar minha vida toda utilizando os comandos ifconfig e route, resolvendo os meus problemas, é o que me importa. Será que é errado eu utilizar tais comandos? Acredito que não. Utilizo o comando ip para fazer tantas coisas: desde criação de rotas, listagem, configuração de interfaces, entre outras. O que é mais vantajoso? Utilizar os comandos ifconfig e route, ou o ip? Certamente te digo que é o ip, e por um simples fato: com o ip aprendo somente um comando com várias sintaxes. Mas o que será mais benéfico para as outras pessoas? Acho que isso já é uma resposta muito particular.

    PS: Uma andorinha me falou que o projeto ifconfig está atualmente só em modo de manutenção. O projeto ip está sendo o substituto do ifconfig.

    Atenciosamente,

    Kirkup.

    ResponderExcluir
  6. Olá Kirkup,

    Obrigado pelas críticas. Sim, ainda sou usuário frequente do ifconfig/route. Entretanto, tenho notado com o tempo que algumas novas informações/configurações simplesmente não aparecem no ifconfig, como por exemplo estas configurações de rota do artigo. Outro ponto onde o ifconfig/route começam a perder espaço é na configuração de IPv6. Logo os usuários exclusivos de ifconfig irão se deparar com um problema de configuração que somente está visível pelo comando ip.

    Outra área onde o comando ip é imbatível é na sua manupulação por script. Qualquer um que buscou o endereço da interface de rede pelo ifconfig e pelo ip sabe do que eu falo.

    Não digo para esquecer o ifconfig, mas para buscar o uso do ip sempre que possível. Apesar de necessitar de alguns caracteres a mais, vai facilitar a migração no futuro.

    ResponderExcluir
  7. Luiz vc salvou o meu estagio...kkkk.
    Me deparei com esse problema a alguns dias, precisava direcionar o trafego do site e trafego da navegação entre 2 links distintos, como sou iniciante em linux e um pouco "legume" uso o fwbuilder para criar as minhas regras, mas não consegui configurar uma rota default para cada link só consegui fazer com o seu tutorial.

    Como sou iniciante sinto que os mais experientes em GNU/Linux insistem em postar tutoriais muito complexos para nós iniciantes, gostaria que mais pessoas da comunidade colocasem materias sobre roteamento avançado, controle e banda entre otros temas com linguagem mais leve e de facil entendimento "linguagem para legumes" valeu pelo tutorial!!!

    ResponderExcluir
  8. Olá Manuel,

    Fico feliz em ajudar. Tento colocar as soluções de problemas interessantes que encontro ao longo do meu trabalho.

    Quanto a controle de banda outras coisas mais complexas, acho que é muito trabalho para ser desenvolvido "manualmente". O melhor seria adotar uma ferramenta que te auxilie na configuração. Existe algumas distribuições desenvolvidas para este fim.

    Mas deixar um computador exclusivo para roteador? E com diversas placas de rede? Hoje em dia isto não é mais necessário. Você pode simplesmente usar uma solução de virtualização de pc (kvm, virtualbox, xen, vmware) e a solução de virtualização de rede (vlan com tags 802.1Q). Inclusive, pode utilizar a mesma distribuição para o firmware do seu roteador wireless e de uma VM roteadora: openwrt.org. Devo blogar sobre logo, agora que saiu a versão estável 10.03.1.

    ResponderExcluir
  9. Este comentário foi removido pelo autor.

    ResponderExcluir
  10. Ou...
    net.ipv4.conf.default.rp_filter = 1
    ... para solucionar o problema. Claro, eu sei que o problema fui usado como exemplo para roteamento avançado em Linux. :)

    Aqui é o André da adm_rede. Fui ver sua solução para GPT e acabei olhando quase todos seus artigos. :P

    ResponderExcluir
    Respostas
    1. Olá André,

      Já que você leu quase todos os artigos, espero que tenha gostado :-)

      Até fui estudar novamente o rp_filter ("Reverse Path Filtering"). Pelo que vi, ele funciona como uma proteção de ip spoofing. Por padrão, o Linux ignora pacotes recebidos em uma interface se o endereço de rede de origem é o mesmo de outra interface (martian source). O rp_filter expande este teste para ignorar também os pacotes que seriam roteáveis por outra interface.

      No problema do artigo, o problema não é a falta de rejeições. O problema é que um pacote vai para o caminho errado. Realmente não testei se o rp_filter também implicitamente faz este tipo de modificação no comportamento do roteador.

      Abs,

      Excluir