segunda-feira, 1 de julho de 2013

Balanceamento de Links Fácil com IPTables

Você já esteve em uma situação onde você teve um link de backup não-utilizado? Em algumas situações, ter dois (ou mais) links é necessário, mas com certeza seria melhor se nós pudéssemos usar ambos em vez de deixar um parado esperando que o outro falhe. Adivinhe, nós podemos fazer isso!
Primeiramente, um aviso: ISTO NÃO É UM TUTORIAL DE IPTABLES. Leitores deste artigo devem ter, pelo menos, familiaridade com iptables para compreendê-lo. Entendimento básico de como funciona roteamento ajuda bastante também.
Para balancear os links, nós vamos usar duas ferramentas do Linux que são muito comuns e cujos pacotes pré-compilados estão disponíveis para muitas (se não todas) distribuições. Os pacotes são iptables e iproute2. Saiba, entretanto, que para usar o método aqui descrito, você precisará de um kernel novo (ou compilar um que suporte o statistic match você mesmo) já que isto só foi incorporado no kernel 2.6.18.
Quem estiver usando Debian Etch (4.0) deve poder usar as regras sem nenhuma alteração do kernel. Se você estiver usando Ubuntu (pelo menos a versão 7.10), você provavelmente não poderá usar estas regras. Ubuntu tem um bug conhecido que irá impedir você de usar o statical match.
Você deve instalar o pacote iproute2 antes de começarmos, o qual nos permite configurar roteamento avançado do kernel baseado em regras. Se você está usando Debian, você pode instalar este pacote usando o seguinte comando:
# apt-get install iproute
Depois de instalá-lo, nós precisamos criar algumas tabelas que irão conter informações de roteamento. Edite o arquivo /etc/iproute2/rt_tables e adicione duas linhas como a seguir:
200 link1
201 link2
No final você provavelmente terá um arquivo assim:
255 local
254 main
253 default
0 unspec
200 link1
201 link2
Os números não são realmente importantes, desde que sejam únicos e compreendidos entre 0 e 255. Se você quer entender um pouco mais sobre como isso funciona exatamente (e você deveria querer), você pode ler esta excelente documentação.
Agora nós precisamos configurar os gateways que nossos links usam, na tabela apropriada. Vamos assumir que o gateway padrão do link 1 é “1.1.1.1” e o do link 2 é “2.2.2.2”. Geralmente nós adicionamos o gateway padrão no nosso sistema usando “route add default gw [algum endereço IP aqui]”, e o que nós faremos é quase a mesma coisa:
# ip route add default via 1.1.1.1 table link1
# ip route add default via 2.2.2.2 table link2
Basicamente, todo pacote que chegar na tabela “link1” será roteado para 1.1.1.1 e todo pacote que chegar na tabela “link2” irá para 2.2.2.2.
A seguir, temos que especificar quais pacotes devem ir para qual tabela, do contrário tudo o que acabamos de fazer seria totalmente inútil.
# ip rule add fwmark 1 table link1
# ip rule add fwmark 2 table link2
Isto é como dizer “tudo o que tem o firewall mark 1 deve ir para a tabela link 1 e tudo o que tem o firewall mark 2 deve ir para o link2”. Nós falaremos de firewall marks mais para frente; agora, vamos ter certeza que nós entendemos o que acabamos de fazer:
  1. Determinamos duas tabelas de roteamento chamadas “link1” e “link2”
  2. Configuramos para que tudo o que chegar na tabela “link1” vá para o gateway do nosso Link #1
  3. Configuramos para que tudo o que chegar na tabela “link2” vá para o gateway do nosso Link #2
  4. Dissemos que todo pacote que tenha firewall mark “1” vá para a tabela “link1”. Dessa forma, tudo o que tenha firewall mark “1” será roteado para o gateway do Link #1 (1.1.1.1)
  5. Da mesma forma todo pacote que tenha firewall mark “2” irá para a tabela “link2”, então irá para o gateway do Link #2 (2.2.2.2)
Se você entendeu tudo isso, legal. Se não, sinta-se a vontade para me mandar um e-mail (diego [arroba] diegolima [ponto] org). Agora vamos à melhor parte. Se nós queremos usar aquelas regras de roteamento, nós vamos precisar marcar os pacotes de alguma forma.
É possível fazer isso com iptables usando o target MARK. Então, se nós desejamos direcionar todo o nosso tráfego para o link #1, nós faremos isso:
# iptables -t mangle -A PREROUTING -j MARK –set-mark 1
Pronto! Agora todos os nossos pacotes terão firewall mark “1”. Note que está mark só existe para o sistema e você não poderá lê-la depois que o pacote tenha sido enviado para fora. Se nós quiséssemos direcionar todo o nosso tráfego para nosso outro link, nós teriamos que determinar o firewall mark como 2.
Mas nós não queremos direcionar todo o nosso tráfego para um dos links. O que nós queremos é direcionar parte do tráfego para um link e parte para o outro. Para fazer isto nós podemos usar o não-tão-conhecido statistic match. Ele nos permite “casar” pacotes, bem, estatisticamente:
# iptables -t mangle -A PREROUTING -m state –state new -j MARK –set-mark 2
# iptables -t mangle -A PREROUTING -m state –state new -m statistic –mode random –probability 0,5 -j MARK –set-mark 1
Com isso, nós fizemos o seguinte:
  1. Marcar TODOS os pacotes que iniciarem novas conexões com o mark 2
  2. Depois de fazer isso, existe 50% de chance de os pacotes iniciando novas conexões serem marcados com o mark 1; Se nós quisermos 30% de chance, nós teríamos usado 0,3 em vez de 0,5. Os pacotes que não forem casados por esta regra irão continuar com seu mark anterior (“2”).
É realmente muito importante que nós marquemos somente pacotes que iniciem novas conexões para evitar quebrar conexões já existentes. As conexões já estabelecidas devem ser tratadas corretamente pelo kernel sem necessidade de maiores intervenções.
É também importante notar que este tipo de tratamento deve ser feito na tabela PREROUTING. Isto significa que os pacotes serão tratados antes do kernel decidir para onde mandá-los. Você pode ver esta imagem para entender melhor sobre quando cada tabela é chamada durante a filtragem.
Seus pacotes agora devem estar roteados apropriadamente pelo kernel. Você ainda precisa adicionar um SNAT (ou MASQUERADE) regra para fazer as coisas funcionarem devidamente:
# iptables -t nat -A POSTROUTING -o $LINK1_WAN_INTERFACE -j SNAT –to $LINK1_WAN_IP
# iptables -t nat -A POSTROUTING -o $LINK2_WAN_INTERFACE -j SNAT –to $LINK2_WAN_IP
Isso deve cuidar de tudo. Agora vamos dar uma olhada rápida no que acontece durante todo esse processo:
[pacote] -> iptables PREROUTING -> decisão de roteamento do kernel -> iptables POSTROUTING -> internet
  1. No PREROUTING, o pacote tem 50% de chance de ser marcado com 1 e 50% de chance de ser marcado com 2
  2. Na decisão do roteamento, o pacote irá para o link 1 se tem mark 1 ou para o link 2 se tem mark 2
  3. Depois de ser roteado, irá receber um endereço IP externo apropriado da interface de saída
Eu espero que você possa fazer bom uso disto. Se alguém tiver problemas sinta-se a vontade para entrar em contato comigo (sim, eu leio e respondo os comentários) e eu irei ajudar/corrigir qualquer erro que eu tenha cometido neste artigo.

Fontes: http://www.diegolima.org/wordpress/?p=38, visualizado em 01/07/2013

Nenhum comentário:

Postar um comentário