domingo, novembro 09, 2008

Roteamento de Entrada/SaÍda com iproute e iptables

Bom pessoal depois de muito estudo em cima do iproute e iptables para fazer funcionar o roteamento avançado de entrada e saída para redirecionamento de portas por mais de um link de internet resolvi postar a solução.

Na Internet tem muita documentação relacionada com o balanceamento de saída com 2 ou mais links de internet. Mas nenhuma documentação relacionada quando você quer ter seus servidores ( email, web, terminal service e etc) respondendo para a Internet por todos seus links disponíveis.

Essa solução resolve seu problema da seguinte maneira:

- Sua empresa tem 2 link de Internet ou mais
- Você tem servidores disponibilizando recursos para a Internet como (smtp,pop3,web, rdp e etc)
- Quer que seja transparente para todos quando um link de Internet parar de funcionar, você pode via dns round-robin fazer que um host responda por 2 IPs válidos ou mais. Isso seria ótimo para seu servidor de email. São 2 IPs respondendo por smtp e pop3 e caso um link caia o outro fica respondendo normalmente. O DNS é nosso amigo.

Veja a topologia abaixo que iremos nos basear para criar as regras de iptables e iproute:



Na topologia acima temos 3 servidores em nossa rede disponibilizando serviços web,pop3,smtp e terminal service a Internet.
Na configuração da zona de Dns do dominio utilizamos round-robin para todos os serviços. Cada serviço tem um nome e 2 IPs válidos respondendo por esse nome de Dns.

Abaixo está o script que usa iptables e iproute, qualquer problema encontrado com ele por favor relatem para ser corrigido. Estou trabalhando em uma outra versão desse script para ficar transparente até a navegação da rede interna caso o link principal de comunicação dela com a Internet sai do ar.

#!/bin/bash

# Por tiagonux
# Script que faz um servidor GNU/Linux com mais de um link de internet
# rotear os pacotes destinados a sua DMZ. Sua DMZ ficará respondendo
# a partir da Internet pela quantidade de links que tiver.
# Envolve os softwares iproute e iptables
# O script não cobre regras de mascaramento de pacotes e nem redirecionamento
# de portas.
# Esse script pode ser chamado pelo script de firewall atual do seu sistema, sendo
# que as regras da tabela mangle são resetadas.
# Variáveis
#
# Gateways de cada link
LINK1_GW="200.200.xx.1"
LINK2_GW="189.40.xx.1"
#
# Interface de rede ligada aos Links e Interface ligada a DMZ e Rede Interna
#
LINK_WAN1="eth1"
LINK_INT1="eth0"
#
# Ips de cada Link. Lembrando se estiver usando apenas uma placa de rede conectada
# em um switch que está os 2 links(ou mais) deve-se configurar os IPs válidos
# virtualmente na mesma placa de rede.
#
LINK1_IP="200.200.xx.2"
LINK2_IP="189.40.xx.2"
#
IPTABLES=`which iptables`
#
# Você pode chamar esse script de dentro do seu script de firewall atual, mas fazendo
# as devidas alterações de redirecioamento de portas.
# Regras de marcação de pacotes com iptables e seu módulo CONNMARK
#
# Reseto tudo da tabela Mangle
$IPTABLES -t mangle -F
$IPTABLES -t mangle -X
$IPTABLES -t mangle -Z
#
# Você deve ter um redirecionamento de portas para cada pacote entrando em cada link
# para seu servidor especifico.
# Aqui marco o pacote que entrar pelo link1 com o mark 1 com destino ao IP do LINK1_IP
# e a porta 25 .
$IPTABLES -t mangle -A PREROUTING -i $LINK_WAN1 -p tcp --dport 25 -d $LINK1_IP \
-m conntrack --ctorigdst $LINK1_IP -j MARK --set-mark 1 -m mark --mark 0
#
# Aqui marco o pacote que entrar pelo link2 com mark 2 com destino ao IP do LINK2_IP
# e a porta 25 .
$IPTABLES -t mangle -A PREROUTING -i $LINK_WAN2 -p tcp --dport 25 -d $LINK2_IP \
-m conntrack --ctorigdst $LINK2_IP -j MARK --set-mark 2 -m mark --mark 0
#
# Aqui marco o pacote que entrar pelo link1 com mark 3 com destino ao IP do LINK1_IP
# e a porta 110 .
$IPTABLES -t mangle -A PREROUTING -i $LINK_WAN1 -p tcp --dport 110 -d $LINK1_IP \
-m conntrack --ctorigdst $LINK1_IP -j MARK --set-mark 3 -m mark --mark 0
#
# Aqui marco o pacote que entrar pelo link2 com mark 4 com destino ao IP do LINK2_IP
# e a porta 110 .
$IPTABLES -t mangle -A PREROUTING -i $LINK_WAN1 -p tcp --dport 110 -d $LINK2_IP \
-m conntrack --ctorigdst $LINK2_IP -j MARK --set-mark 4 -m mark --mark
#
# Aqui marco o pacote que entrar pelo link1 com mark 5 com destino ao IP do LINK1_IP
# e a porta 80 .
$IPTABLES -t mangle -A PREROUTING -i $LINK_WAN1 -p tcp --dport 80 -d $LINK1_IP \
-m conntrack --ctorigdst $LINK1_IP -j MARK --set-mark 5 -m mark --mark 0
#
# Aqui marco o pacote que entrar pelo link2 com mark 6 com destino ao IP do LINK2_IP
# e a porta 80 .
$IPTABLES -t mangle -A PREROUTING -i $LINK_WAN1 -p tcp --dport 80 -d $LINK2_IP \
-m conntrack --ctorigdst $LINK2_IP -j MARK --set-mark 6 -m mark --mark 0
#
# Aqui marco o pacote que entrar pelo link1 com mark 7 com destino ao IP do LINK1_IP
# e a porta 3389 .
$IPTABLES -t mangle -A PREROUTING -i $LINK_WAN1 -p tcp --dport 3389 -d $LINK1_IP \
-m conntrack --ctorigdst $LINK1_IP -j MARK --set-mark 7 -m mark --mark 0
#
# Aqui marco o pacote que entrar pelo link2 com mark 8 com destino ao IP do LINK2_IP
# e a porta 3389 .
$IPTABLES -t mangle -A PREROUTING -i $LINK_WAN1 -p tcp --dport 3389 -d $LINK2_IP \
-m conntrack --ctorigdst $LINK2_IP -j MARK --set-mark 8 -m mark --mark 0
#

# Aqui é onde acontece a mágia. Quando simplesmente marcamos um pacote que entra
# por um link de Internet ele perde sua marca quando passa pela tabela NAT. É nesse
# ponto que todo mundo fica perdido, pois em todos os foruns que li a dúvida maior é
# essa, o porque do pacote não retorna pelo link que ele entrou se eu marquei ele na
# sua entrada.
# Acontece que ao passar de uma tabela (mangle) para outra (nat) ele perde a marca.
# Descobri isso lendo a documentação do iptables e com ajuda do tcpdump conclui isso.
# Mas sempre tem uma maneira de resolver esse problema.
# Simplesmente vamos dizer que queremos que seja lembrado a marca anterior do
# pacote.
# Como pode ser visto na regra abaixo, na chain PREROUTING da mangle salvo a marca
# do pacote jogando para o ALVO CONNMARK
#
$IPTABLES -t mangle -A PREROUTING -i $LINK_WAN1 -j CONNMARK --save-mark
#
# E quando o pacote retorna entrando pela interface interna é lembrado sua marca
# anterior.
# Isso tudo ocorre pela --save-mark da regra anterior e --restore-mark da regra abaixo.
#
$IPTABLES -t mangle -A PREROUTING -i $LINK_INT1 -p tcp -m state --state \
ESTABLISHED,RELATED -j CONNMARK --restore-mark
#
# Regras de roteamento com iproute
#
# Deletando as regras atuais de roteamento
#
ip route del default
ip rule del prio 10 table main
ip rule del prio 19 fwmark 1 from 192.168.1.3 table link1
ip rule del prio 20 fwmark 2 from 192.168.1.3 table link2
ip rule del prio 21 fwmark 3 from 192.168.1.3 table link1
ip rule del prio 22 fwmark 4 from 192.168.1.3 table link2
ip rule del prio 23 fwmark 5 from 192.168.1.2 table link1
ip rule del prio 24 fwmark 6 from 192.168.1.2 table link2
ip rule del prio 25 fwmark 7 from 192.168.1.4 table link1
ip rule del prio 26 fwmark 8 from 192.168.1.4 table link2
ip rule add prio 30 table link1
#
# Configurando se necessário o /etc/iproute2/rt_tables com as tabelas de cada link.
#
if ! cat /etc/iproute2/rt_tables | grep -q '^250'
then
echo "250 link1" >> /etc/iproute2/rt_tables
fi
#
if ! cat /etc/iproute2/rt_tables | grep -q '^251'
then
echo "251 link2" >> /etc/iproute2/rt_tables
fi
#
# Flush nas tabelas
ip route flush table link1
ip route flush table link2
#
# Falo que prioridade a tabela main tem.
ip rule add prio 10 table main
#
# Falo quem é o gateway da tabela link1
ip route add default proto static via $LINK1_GW src $LINK1_IP table link1
#
# Falo quem é o gateway da tabela link2
ip route add default proto static via $LINK2_GW src $LINK1_IP table link2
#
# Crio a regra de roteamento para cada tabela de acordo com a marcação do pacote
#
# pacotes smtp que entraram pela tabela link1
ip rule add fwmark 1 from 192.168.1.3 table link1 prio 19
#
# pacotes smtp que entraram pela tabela link2
ip rule add fwmark 2 from 192.168.1.3 table link2 prio 20
#
# pacotes pop3 que entraram pela tabela link1
ip rule add fwmark 3 from 192.168.1.3 table link1 prio 21
#
# pacotes pop3 que entraram pela tabela link2
ip rule add fwmark 4 from 192.168.1.3 table link2 prio 22
#
# pacotes web que entraram pela tabela link1
ip rule add fwmark 5 from 192.168.1.2 table link1 prio 23
#
# pacotes web que entraram pela tabela link2
ip rule add fwmark 6 from 192.168.1.2 table link2 prio 24
#
# pacotes rdp que entraram pela tabela link1
ip rule add fwmark 7 from 192.168.1.4 table link1 prio 25
#
# pacotes rdp que entraram pela tabela link2
ip rule add fwmark 8 from 192.168.1.4 table link2 prio 26
#
# Caso você queira que o resto da rede interna se comunique com a internet pela
# tabela link1
ip rule add prio 30 table link1
#
# Atualizando o cache de roteamento
ip route flush cache

5 comentários:

Thiago Guirotto disse...

nuuoossaaa....

Por isso q vc é meu chefe.

Unknown disse...

Aee tiagão, grande explanação... ainda não testei, mas testarei em breve.. já consegui conectar via 3G no slackware, porém a taxa de transferencia não está legal, assim que eu conseguir estabilizar a bagaça aqui, vou utilizar 2 links, um a cabo da net e outro por celular usando 3G.. ai sim vou poder testar esse script.. mas tá show.. valeu :D

Unknown disse...

Boa tarde Tiago, muito boa a sua explanação, estou me preparando para implementa-la.
Porem estou com uma duvida.
na linha:
"ip route del default"
vc deleta rota default, certo?
uma vez este script implementado, todas as outras vezes esta linha dará erro, pois nao existirá mais rota default, certo?

Rodrigo Macena disse...

Cra, legal a iniciativa, mas... nao rolou!!! Assim, eu criei uma tabela balance onde fazia load balance enteo os dois links com weight 1. Nao rolou.
Com teu script tb nao rolou. Por acso voce mdeixou o ip de algum dos dois links como default getaway?

Unknown disse...

Se for possivel tirar uma duvida que tenho e ainda não consegui sucesso referente.

Tenho um servidor firewall com 4 placas de rede.

firewall
eth0 = DMZ 200.x.x.x
eth1 = Modem 1 = default gw ( IP FIXO firewall 172.x.x.x
eth2 = Modem 2 (IP FIXO) 189.x.x.x
eth3 = Rede interna 192.168.x.x

Todas as maquinas estão saindo para esse "Modem 1", na verdade é assim que tem que ser mesmo. Eu preciso apenas direcionar todas as maquinas da "Rede interna" para chegar e sair desse "Modem 2".
Os dois modens são operadoras diferentes.

Pelo amor de Deus, tente me ajudar, preciso apenas maquinas Rede Interna com acesso Full todas as portas acessando apenas com esse Modem 2.

Obrigado.