Redondance entre FAI et lignes ADSL multiples

avril 21, 2007  |   Blog   |     |   Commentaires fermés sur Redondance entre FAI et lignes ADSL multiples

AiguillageNous installons assez souvent de multiples lignes Internet chez nos clients en réalisant du partage de charge sortant pour la navigation web.

Je me suis retrouvé dernièrement dans le cas d’une architecture sous contraintes.

Un proxy Linux 2.4.x Squid disposant de 2 interfaces Ethernet vers une ligne ADSL, via un routeur bas de gamme.
Le réseau interne et sa ligne institutionnelle (= historique). Par défaut, le trafic de navigation web doit sortir par l’ADSL: en cas de coupure du service (au niveau du routeur, de la ligne ADSL, du FAI, etc..) , le proxy doit alors utiliser l’ancienne ligne avec une remontée d’alerte.

J’aurais pu utiliser les fonctionnalités avancées de iproute2 (lien supprimé depuis la rédaction de l’article) et nano : il existe une abondante littérature à ce sujet (je vous conseille d’ailleurs cette introduction), mais cela était rendu difficile par la vieille version du noyau, l’impossibilité de le patcher (système en production) et ….. le temps compté.

Je me suis donc contenté d’écrire un script Perl réalisant un test HTTP sur 5 sites majeurs, basculant si besoin (en détectant l’état actuel : nominal ou backup) par manipulation de la table de routage et générant un mail d’alarme en cas de bascule. C’est ma façon de réaliser un système supportant la Dead gateway detection (DGD) dans un cas actif/passif (master/backup) !

Je vous livre ici « brut de fonderie » ce script Perl.
Si les modules Net::Ping et Net::SNMP ne sont pas installés, le faire ainsi à partir du shell :
perl -MCPAN -e shell
puis
install Net::Ping
install Net::SNMP

#!/usr/bin/perl -w
# Auteur : SR
# 20 Avril 2007
use Net::Ping;
use Net::SMTP;

my @hosts=("www.yahoo.fr",
"www.google.fr",
"www.tf1.fr",
"www.free.fr",
"www.randco.fr");

# Renseigner ci-dessous les @IP de vos 2 passerelles
# nominale et secours
my $backup_gw="10.0.a.b";
my $main_gw="10.0.c.d";

# Renseigner ci-dessous les paramètres pour l email d'alerte
my ($smtp_server,$mail_dest,$mail_cc)=("smtp.mycompany.fr",
"user1@mycompany.fr" ,
"user2@mycompany.fr , user3@mycompany.fr");

# Activer debug a 1 pour obtenir des messages de debug
my $debug=0;

my ($success,$fail)=(0,0);
my $p = Net::Ping->new("syn");
$p->{port_num} = getservbyname("http", "tcp");

foreach $host (@hosts) {
sleep(5);
if ($p->ping($host)) {
while (($host,$rtt,$ip) = $p->ack) {
print "HOST: $host [$ip] a répondu en $rtt secondes n" if ($debug);
};
$success++;

} else {
$fail++;
print "$host est injoignable n" if ($debug);
}
};

$p->close();

if ($success > $fail) {
# On determine les routes par defaut a modifier
my $failover_cmd = parse_route_table($main_gw,$backup_gw);
## on verifie s'il existe des routes à effacer
if ($failover_cmd=~/routesdeletes/) {
$msg="Basculement sur la passerelle de backup $backup_gw !!n";
print $msg;
print $failover_cmd;
system($failover_cmd);
mail($smtp_server,$mail_dest,$mail_cc,$msg)
} else {
print "On est déja sur la passerelle de backup $backup_gw !!n";
};
};

#-- Contenu des fonctions ------------------------
sub parse_route_table {

# on recupere en variables les gw main et backup
my ($mgw,$bgw)=@_;
my $cmd="";
open (TABLE, "/sbin/route -n |") or
die "Impossible d'obtenir la table de routage n";

while ($l=<TABLE>) {
## on ne traite que les routes par defaut
next unless ($l=~/^(0.0.0.0)s*([0-9.]*)s*(0.0.0.0)/);
## on verifie qu'on est pas deja sur le secours !!
next if $2=~/^$bgw$/;
$cmd.="/sbin/route delete default gw $2;" if defined $2;
};

close TABLE;
# on applique la nouvelle route par defaut

$cmd.="/sbin/route add default gw $backup_gwn";
return $cmd;
}

sub mail {

my ($smtp_server,$mail_dest,$mail_cc,$msg)=@_;
my $smtp = Net::SMTP->new($smtp_server);

$smtp->mail("shipper@mycompany.fr");
$smtp->to($mail_dest);
$smtp->cc($mail_cc);
$smtp->data();
$smtp->datasend("From: $mail_destn");
$smtp->datasend("To: $mail_destn");
$smtp->datasend("Cc: $mail_ccn");
$smtp->datasend("Subject: ADSL: Script Bascule FAI n $msgn");
$smtp->datasend("n");
$smtp->datasend($msg);
$smtp->dataend();
$smtp->quit;

print "Mail parti...n";
}

Il ne reste plus qu’à insérer ceci dans la crontab pour effectuer un test toutes les 5 minutes de 7h à 23h tous les jours de semaine :


*/5 7-23 * * 2-5 /chemin/complet/ISP_test.pl

Les commentaires sont fermés.