[LARTC] Perl script to adjust default routing on 2 Net connections

Linux Advanced Routing and Traffic Control

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Using a stock implementation of Christoph's and Julian's setup for
connecting to two lines (DSL from different ISPs in my case) I ran into
situations where a gateway was still up, but the ISP had systems down beyond
it. To deal with that, I've put together a perl script that I run from cron.
I have this running in production, but only for a few days, so it's not
thoroughly tested yet. Still, I'll include it here in case either it's
useful to someone, or someone has suggestions on how to improve it.

It should also be adaptable to similar setups, although if you're not using
Julian's patches you should search and replace "proto static" with nothing
first (not even sure it's doing any good in this context anyway, but not
sure it isn't).

Run it from the prompt to test before adding to cron.

Whit

--- cut ---
#!/usr/local/bin/perl

# checkroutes.pl version 0.04, 6 Feb. 2002, whit@transpect.com
# Extends stock Nano-Howto setup with upstream route accessibility checking
# See http://www.linuxvirtualserver.org/~julian/nano.txt and patches at
# http://www.linuxvirtualserver.org/~julian/#routes
# (if not using Julian's patchs, remove "proto static" occurrences below)

# Run from cron (set with "crontab -e")
# example: "0-59/2 * * * * /path/to/checkroutes.pl" runs this every 2 minutes

# Best IPs to test may be last IPs at ISP before routing out to Net

# If perl not at /usr/local/bin/perl change first line to point to it

# Before running install Net::Ping from http://freeware.roobik.com/netping/
# (untar, cd to directory, "perl Makefile.PL; make; make install")

use Net::Ping;

# User settings
# _____________

$ip	= "/usr/sbin/ip";	# Location of "ip" on system

$gw1 	= ""; # Gateway 1 IP
$dev1	= ""; # Device (e.g., eth1)
$tip1	= ""; # Upstream IP to test
$src1	= ""; # Source address for outgoing packets
$wei1	= "1"; # Weight

$gw2	= ""; # Gateway 2 IP
$dev2	= ""; # Device (e.g., eth2)
$tip2	= ""; # Upstream IP to test
$src2	= ""; # Source address for outgoing packets
$wei2	= "1"; # Weight

$tab	= "222"; # Table to set routes in

$logfile = "/var/log/checkroutes.log"; # File to log messages to 

# create timestamp for log
# ________________________

sub TimeStamp {

	# subroutine to create a "nice" looking timestamp
	# that doesn't rely on the system's 'date' command

	my @days = ('Sun','Mon','Tue','Wed','Thu','Fri','Sat');
	my @months = ('Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep',
		'Oct','Nov','Dec');

	my ($sec,$min,$hour,$dom,$mon,$year,$wday,$yday,$isd) = localtime(time);
	my $timestamp = sprintf("%3s %3s %02d %4d  %02d:%02d:%02d", $days[$wday],
		$months[$mon], $dom, $year+1900, $hour, $min, $sec);

	return $timestamp;
} 

# be sure routes are set via appropriate gateways to test IPs 
# ___________________________________________________________

$checkro = `$ip ro ls`;
if (!($checkro =~ /$tip1/)) {
	system ("$ip ro add to $tip1 via $gw1 src $src1 proto static")
		|| die ("failure adding route\n");
}
if (!($checkro =~ /$tip2/)) {
	system ("$ip ro add to $tip2 via $gw2 src $src2 proto static")
		|| die ("failure adding route\n");
}

# test if $gw1 and/or $gw2 currently in table $tab
# ________________________________________________

$checkgw = qx/$ip ro ls tab $tab/;

if ($checkgw =~ /$gw1/) {
	$check1 = 1;
} else {
	$check1 = 0;
}

if ($checkgw =~ /$gw2/) {
	$check2 = 1;
} else {
	$check2 = 0;
}

# ping the test IPs $tip1 and $tip2
# _________________________________

$p = Net::Ping->new("icmp");
if ($p->ping($tip1)) {
	$live1 = 1;
} else {
	$live1 = 0;
}
$p->close();
$p = Net::Ping->new("icmp");
if ($p->ping($tip2)) {
	$live2 = 1;
} else {
	$live2 = 0;
}
$p->close();

# If the current default in table $tab does not match the ping results then
# if only one route's test IP is pingable change the default to that route
# or if both test IPs are pingable change the default to use both
# or if neither test IPs are pingable change the default to use both 
# (might as well continue to try them, if we're not going anywhere anyway)
# _________________________________________________________________________

if (($check1 != $live1)||($check2 != $live2)) {
	if ((($live1 == 1)&&($live2 == 1))||(($live1 == 0)&&($live2 == 0))) {
		system ("$ip ro ap default tab $tab proto static nexthop via $gw1 dev $dev1 weight $wei1 nexthop via $gw2 dev $dev2 weight $wei2")
			|| die ("failure appending route\n");
	} elsif (($live1 == 1)&&($live2 == 0)) {
		system ("$ip ro ap default tab $tab proto static via $gw1 dev $dev1")
			|| die ("failure appending route\n");
	} elsif (($live1 == 0)&&($live2 == 1)) {
		system ("$ip ro ap default tab $tab proto static via $gw2 dev $dev2")
			|| die ("failure appending route\n");
	} else {
		die ("value out of bounds\n");
	}
	system ("$ip ro del default tab $tab")
		|| die ("failure deleting default route\n");
	system ("$ip ro flush cache")
		|| die ("failure flushing cache\n");
}

# log
# ___

if (($live1 == 1)&&($live2 == 1)) {
	$log = "both UP";
} elsif (($live1 == 0)&&($live2 == 0)) {
	$log = "both DOWN (set UP)";
} elsif (($live1 == 1)&&($live2 == 0)) {
	$log = "$gw1 up, $gw2 DOWN";
} elsif (($live1 == 0)&&($live2 == 1)) {
	$log = "$gw2 up, $gw1 DOWN";
}

open(LOG, ">>$logfile");
print LOG &TimeStamp . " - $log\n";
close(LOG);


[Index of Archives]     [LARTC Home Page]     [Netfilter]     [Netfilter Development]     [Network Development]     [Bugtraq]     [GCC Help]     [Yosemite News]     [Linux Kernel]     [Fedora Users]
  Powered by Linux