Roteadores Linux redundantes de baixo custo

Um pouco de história

Recentemente me vi na obrigação de dividir um servidor Linux em dois pois nele coincidiam duas linhas de acesso à internet concentrando o tráfego e distribuindo o mesmo conforme necessário entre as duas linhas de acesso.

Quem me conhece sabe que sou pão duro com dinheiro alheio. Relutei bastante em dividir o servidor já que não fazia sentido ter dois quando um só dava conta do serviço. Então desde meados de 2008 até final de 2014 estamos trabalhando com o mesmo servidor que herdamos de um outro técnico e por sinal estava muito bem feito.

Bem, o caso é que um ataque, um vírus, uma TPM atrasada, seja lá o que for, pode deixar o roteador fora de combate e é nessas horas que você almejaria ter a simplicidade de funcionamento de uma tomada em que simplesmente tirar de um lado e colocar no outro resolveria todo o problema e seus clientes nem saberiam da sua existência (ou da existência da sua mãe, o que é pior)

Então, contrario a tudo o que tenho feito, decidi que é melhor ter dois do que um mesmo que isso me duplique o serviço de manutenção e cuidados.

Atenção

Isto é só um relato de experiência muito particular que deu certo em um ambiente muito especifico. Disponibilizo esta informação de forma gratuita e livre no intuito de ajudar tecnicamente qualquer colega mas não sugiro a colocação deste script em ambiente de produção.

Propósito

Como sou um ser humano comum e almejo sombra e água fresca quase que constantemente, decidi fazer um par de scripts configuráveis que disponibilizo para quem queira utilizar. O que procuro é que sem andar mexendo muito, os dois servidores se virem para alternarem a posição de roteador da rede. Quero chegar num ponto em que possa por telefone dizer para o técnico do outro lado alguma coisa como “Só arranca o cabo amarelo do micro B que o A assume tudo” ou alguma coisa assim.

Ingredientes necessários

Eu construí o que lhes vou passar usando máquinas equipadas com Ubuntu e CentOS, mas qualquer coisa que seja herdeira de Debian e Red Hat tem que funcionar. A quantidade de memória e o espaço em HD não são importantes a não ser para o SQUID e outros serviços.

Os dois micros tem que estar conectados sobre uma mesma rede física. Preferivelmente cada um dos micros deve ter uma placa de rede dedicada para o ISP (o provedor de acesso à internet). Depois vou trabalhar numa versão com switchs; por enquanto está bem assim.

Em cada um deles, devemos ter o servidor ssh configurado e operacional. Demais está dizer que precisamos liberar no firewall o porto 22 (ou qualquer outro que você deseje para seu servidor ssh)

Ubuntu
# se já tem o UFW instalado, pode pular esta parte até a liberação do porto 22
$ apt-get update
$ apt-get install ufw
$ ufw enable

# libere o porto 22
$ ufw allow 22
CentOS (Até a versão 6)
nano /etc/sysconfig/iptables
# verifique que haja uma linha assim:
iptables -A INPUT -p tcp --dport 22 -j ACCEPT
# depois volte ao console com ctrl-x e garanta o serviço
chkconfig iptables on
service iptables restart

Então, resumindo: Duas pequenas máquinas Linux com duas placas de rede. E – obviamente – os scripts que podem ser pegos aqui: http://www.inovacaosistemas.com.br/downloads/testes/route-sentry.zip

Formando a irmandade

Antes de mais nada, você precisa fazer com que os dois micros se conheçam mutuamente. Aos efeitos do nosso teste, assumiremos que a eth0 tem acesso à internet enquanto que a eth1 é a placa de acesso interno, ou seja a que fica exposta para nossa rede conforme a seguinte tabela:

Micro A Micro B
Função Roteador Principal Roteador Alternativo
eth0 201.b.c.d 197.b.c.d
eth1:monitor 10.0.0.1 10.0.0.2
eth1:interna* 192.168.0.100 192.168.0.100

A placa eth0 e a eth1:monitor estão configuradas como é costume no seu servidor. Ou seja, o script não vai mexer com elas. A única coisa que ele vai fazer é alterar a configuração do eth1:interna que é o roteador para toda sua rede interna. Em outras palavras, ora o Micro A assumirá o papel de roteador da rede ora o Micro B. Repare que se você colocar a configuração do eth1:interna fixa em sua configuração, a sua rede não vai funcionar como esperado, já que terá um IP conflitante

Para que a mágica funcione, devemos dar a cada nodo um arquivo de configuração que permita ao script saber do seu parceiro e de como proceder.

Para o Micro A, uma configuração válida seria a seguinte:

[config]
logfile=/var/log/rs.log

[main]
target=8.8.4.4 208.67.222.222
interface=eth0
ip=201.b.c.d
mask=255.255.255.224
gateway=201.b.c.x

[internet]
host=http://www.msftncsi.com/ncsi.txt
expectedReturn=Microsoft NCSI

[helmet]
interface=eth1
sibling=10.0.0.2
sshport=22
sshuser=root
ip1=192.168.0.100

Já para o Micro B, precisaríamos indicar uma configuração parecida com a seguinte:

[config]
logfile=/var/log/rs.log

[main]
target=8.8.4.4 208.67.222.222
interface=eth0
ip=197.b.c.d
mask=255.255.255.224
gateway=197.b.c.x

[internet]
host=http://www.msftncsi.com/ncsi.txt
expectedReturn=Microsoft NCSI

[helmet]
interface=eth1
sibling=10.0.0.1Nor
sshport=22
sshuser=root
ip1=192.168.0.100

Marquei em negrito o que muda de uma para outra no exemplo. Em resumo, cada um dos .ini tem a configuração do roteador real mais a do roteador irmão. Essa é a razão dos campos diferentes.
Marquei em verde a linha IP1=192.168.0.100 pois esse IP é o compartilhado entre os dois. É esse o IP que o script fará o micro assumir quando perceber que o irmão dele não é o roteador padrão da rede.

Repare também que para detectarmos se estamos conectados à internet, estamos utilizando o mesmo mecanismo que o Windows7 utiliza mas nada lhe impede de utilizar um outro serviço ou criar o seu próprio.  Isto aqui são só dois exemplos.

Serviço Resultado
http://www.msftncsi.com/ncsi.txt
Microsoft NCSI
http://www.inovacaosistemas.com.br/internetAlive.txt
Internet Alive

Para que os dois micros conversem, você deve compartilhar uma chave pública com o parceiro. Os passos são bem simples e são idênticos para cada um dos micros.

1) Primeiro crie um par de chaves no Micro A

$ sudo ssh-keygen 
Generating public/private rsa key pair.
Enter file in which to save the key (/home/root/.ssh/id_rsa): [enter]
Enter passphrase (empty for no passphrase): [enter]
Enter same passphrase again: [enter]
Your identification has been saved in /home/root/.ssh/id_rsa.
Your public key has been saved in /home/root/.ssh/id_rsa.pub.
The key fingerprint is:
f4:91:ba:e0:be:dd:4d:df:2a:f2:1e:1e:e0:c4:03:d9 root@inovacaosistemas

2) Agora copie sua identidade para o Micro B

$ sudo ssh-copy-id root@10.0.0.2

Ele irá pedir a senha do root no micro B e se estiver certa (e seu firewall liberar e o serviço de ssh estiver rodando no micro B) a sua identidade terá sido copiada para o micro B. Você pode conferir que foi com sucesso acessando o micro B sem senha como segue:

$ ssh root@10.0.0.2 ls /root/

3) Ele deverá mostrar o conteúdo da pasta /root/ do micro B. Sem pedir a senha.

Repita os passos sobre o Micro B voltando ao passo 1. E a partir de esse momento seus micros conversarão sem necessidade de senha.

Instalando os scripts

A instalação consiste na simples descompactação do arquivo de distribuição sobre a raiz da sua árvore de diretórios. O conteúdo é o seguinte:

.
├── etc
│   └── route-sentry.ini
└── usr
    └── sbin
        ├── rscmd
        ├── rsd
        ├── rs-lib.sh
        └── rstest

Você pode ver se está tudo ok, utilizando o rstest como no exemplo seguinte:

$ rstest
isHostOnline 127.0.0.1 = 1
Current GW = 192.168.42.129
isMyGatewayAlive = 0
isCommonGWReachable = 1
amIRouter = 0
isSiblingAlive = 1
isOutsideWorldReachable = 1
isSiblingRouting =

Só isso já seria suficiente para montar seu próprio sistema de monitoramento, mas temos mais. Se o rstest não  devolve valores satisfatórios para a situação do micro de testes, revise o seguinte checklist antes de avançar:

1) O Firewall está corretamente configurado de ambos os lados?
2) Posso conectar-me desde o Micro A ao Micro B sem senha?
3) Posso conectar-me do Micro B ao Micro A sem senha?
4) Tenho o route-sentry.ini bem configurado em ambos os lados?

Se a resposta foi não para qualquer dos itens, então volte ao inicio e revise.

O miolo do assunto

O responsável por fazer a coisa toda funcionar é o seguinte script:

#!/bin/bash
#
# (C) 2014 Esteban Daniel Dortta
# Router Sentry Daemon
#

my_dir="$(dirname "$0")"
source "$my_dir/rs-lib.sh"

while [ 1 -gt 0 ]; do
  amIrouter
  if [ $? -lt 1 ]; then
    isSiblingRouting
    if [ $? -lt 1 ]; then
      holdRouterRole
    fi
  else
    isOutsideWorldReachable
    if [ $? -lt 1 ]; then
      isSiblingAlive
      if [ $? -lt 1 ]; then
        rslog "FATAL ERROR: Internet nor sibling are reachable"
      else
        releaseRouterRole
        sleep 30
      fi
    fi
  fi
  sleep 10
done

O algoritmo (que deve rodar concomitantemente desde nos dois micros)  não é exaustivo no sentido em que não testa todas as condições operacionais mas só as que são estritamente necessárias para que um ou outro Micro assuma a função de roteador na rede.

Em lugar de esperar para uma coisa dar errada, ele pergunta se as coisas estão certas. Ou seja, se está tudo ok, para que vou mexer? Isso – claro – deixa de lado a situação em que a rede está operacional mas haveria uma rota mais rápida melhor ou mais econômica a ser utilizada mas como esse não é o propósito desta primeira versão, deixaremos para uma possível segunda versão da solução.

Se o micro for o roteador, ele verifica se ele mesmo consegue acessar a internet. Novamente, se ele consegue acessar a internet, deixa tudo quieto.

Se ele não consegue acessar o mundo exterior, verifica se o parceiro está vivo. Se estiver, então ele libera os IPs e volta a esperar dando tempo suficiente para o irmão tentar assumir o controle. Se o irmão morreu e ele mesmo não tem acesso à internet, devolve uma mensagem de erro no arquivo indicado na configuração pois não tem como sair do bueiro.

Não me estenderei no algoritmo, só direi que ele assume as funções de roteador quando ele não é roteador e o irmão não está acessível ou não consegue navegar no mundo exterior.

Repare que não há ordens de um ao outro, só perguntas. Isso evita de termos um árbitro entre os dois Micros.  Dito de outra forma, os dois fazem o melhor esforço para manter a rede funcionando. Ganha o que chega primeiro.

Para testar, rode ele nos dois micros.

/usr/sbin/rsd

Se tudo estiver ok, coloque ele para rodar no /etc/rc.local ou onde sua distribuição goste acrescentando a seguinte linha nos dois micros:

/usr/sbin/rsd &

Deprecated: Creation of dynamic property WP_Term::$cat_ID is deprecated in /home/inovacao/public_html/yeapf.com/wp/wp-includes/category.php on line 378

Deprecated: Creation of dynamic property WP_Term::$category_count is deprecated in /home/inovacao/public_html/yeapf.com/wp/wp-includes/category.php on line 379

Deprecated: Creation of dynamic property WP_Term::$category_description is deprecated in /home/inovacao/public_html/yeapf.com/wp/wp-includes/category.php on line 380

Deprecated: Creation of dynamic property WP_Term::$cat_name is deprecated in /home/inovacao/public_html/yeapf.com/wp/wp-includes/category.php on line 381

Deprecated: Creation of dynamic property WP_Term::$category_nicename is deprecated in /home/inovacao/public_html/yeapf.com/wp/wp-includes/category.php on line 382

Deprecated: Creation of dynamic property WP_Term::$category_parent is deprecated in /home/inovacao/public_html/yeapf.com/wp/wp-includes/category.php on line 383
Posted in ServidoresTagged , , , , ,