quinta-feira, 6 de setembro de 2012

Fazendo Mágica com NAT no iptables

O GNU/Linux é um sistema operacional tão poderoso que nos permite interferir no tráfego da interface de rede de forma simplesmente mágica através de ferramentas de rede como iptables.

O iptables é muito conhecido na implementação de firewalls no Linux. Todavia, ele oferece muitos outros recursos, e dentre eles o redirecionamento de pacotes.

Para demonstrar esse potencial, ilustraremos duas situações interessantes:

  1. redirecionar a porta TCP 81 para a 80 na mesma máquina
  2. redirecionar a porta TCP 5436 local para a 5432 de máquina em outra rede

Serão considerados 10.220.10.62/16 como endereço IP local e 10.1.2.71/16 como endereço IP remoto. Atenção: a maioria das instruções citadas neste artigo deve ser executada pelo "root" ou outro usuário com poderes de super-vaca!

Antes de qualquer coisa, devemos nos certificar de que as regras existentes do NAT no iptables tenham sido reinicializadas. Para limpar as tabelas e cadeias (chains) e zerar os respectivos contadores, executamos as instruções a seguir:

iptables -t nat -F
iptables -t nat -X
iptables -t nat -Z

O redirecionamento de portas locais pode ser feito com o alvo (target) REDIRECT.

O REDIRECT redireciona o pacote para a própria máquina alterando o IP de destino para o endereço primário da interface de entrada (pacotes gerados localmente são mapeados para o endereço 127.0.0.1).

Assim, afim de redirecionar a porta TCP 81 para a 80 na mesma máquina, executamos:

iptables -t nat -A PREROUTING -p tcp --dport 81 -j REDIRECT --to-port 80

É interessante analisar se o tráfego está chegando à essa porta 81. Para isso, podemos usar o alvo LOG, o qual provocará a inclusão de uma entrada no /var/log/syslog a cada requisição.

O alvo LOG liga o registro dos pacotes que se encaixam em determinado critério pelo log do kernel (o qual pode ser lido com dmesg ou syslogd). É extremamente útil para ser usado em conjunto com regras que descartam o pacote (i.e., alvos DROP ou REJECT).

Para o nosso caso, basta executar a instrução a seguir para habilitar o log:

iptables -t nat -A PREROUTING -p tcp --dport 81 -j LOG --log-prefix "[Porta 81] "

Executamos o comando abaixo para verificar as regras aplicadas à tabela NAT do iptables:

iptables -t nat -L -n -v

Para testar se o redirecionamento está acontecendo como esperado, abra um novo terminal e execute a instrução a seguir para acompanhar no log do Linux as requisições que chegam à porta 81:

tail -f /var/log/syslog | grep 'Porta 81'

Para este caso, o teste deve ser disparado de uma máquina externa, digamos, do endereço 10.220.8.250/16. Podemos usar o telnet executando essa instrução:

telnet 10.220.10.62 81

Como se trata de um serviço Web, outra opção é usar o próprio protocolo HTTP, através da ferramenta curl. Eis um exemplo:

curl -v http://10.220.10.62:81/

Fácil, não?! Vejamos agora a segunda situação, um pouco mais complicada.

O redirecionamento de IPs precisa ser habilitado no kernel do Linux. Para fazer isso, basta executar esse comando:

echo 1 > /proc/sys/net/ipv4/ip_forward

Para garantir que esse parâmetro do kernel esteja ligado durante uma possível reinicialização da máquina, uma sugestão é adicionar tal configuração no sysctl.conf:

echo "net.ipv4.ip_forward = 1" >> /etc/sysctl.conf

Voltando ao iptables, usaremos um outro alvo, o DNAT.

O DNAT determina que o endereço de destino deve ser modificado (assim como todos os demais pacotes da respectiva conexão) e as regras devem parar de ser examinadas.

Assim, para redirecionar a porta 5436 local (10.220.10.62) para a 5432 de outra máquina (10.1.2.71), executamos:

iptables -t nat -A PREROUTING -s 10.220.0.0/16 -p tcp --dport 5436 -j DNAT --to-destination 10.1.2.71:5432

A opção "-s" restringe a origem dos pacotes à subrede da máquina local. Como estamos redirecionando o pacote para uma máquina em outra subrede, precisamos usar o alvo MASQUERADE.

iptables -t nat -A POSTROUTING -j MASQUERADE

Da mesma forma que no caso anterior, podemos ligar o log do Linux para capturar as requisições nessa porta TCP:

iptables -t nat -A PREROUTING -p tcp --dport 5436 -j LOG --log-prefix "[Porta 5436] "

E em seguida acompanhar as mudanças através desse comando:

tail -f /var/log/syslog | grep 'Porta 5436'

Para testar essa nova regra, abra um terminal em outra máquina na mesma subrede e use o telnet:

telnet 10.220.10.62 5436

Como trata-se de um serviço do SGBD PostgreSQL, podemos testar definitivamente usando o cliente psql:

psql -h 10.220.10.62 -p 5436 -U usuario banco

Uma alternativa para acompanhar o tráfego de rede nessas regras de NAT no iptables é a ferramenta tcpdump. Através dela podemos visualizar os IPs com setas mostrando a direção do tráfego, e com isso verificar se as requisições estão chegando e se as respectivas respostas estão voltando.

Por exemplo, para analisar o tráfego que chega à porta 5436 local, podemos usar:

tcpdump -n -i eth0 port 5436

Já para verificar as requisições entre a máquina local e a máquina remota, uma opção seria:

tcpdump -n -i eth0 host 10.1.2.71

Muito simples e prático!