More information on script comments.
#!/usr/bin/perl # # (c) Daniel Hilst Selli, 2011, <danielhilst@gmail.com> # # IP FAIL OVER # # Desc: Provides a IP FAIL OVER environment by testing the current routing and # changing it to next route if it fails. "ip" utility is used to change # the routes. # # Usage: You need to configure the routes at @routes array. # /\_______update_the_comment_______________________/\ # # When ping fails on current route, the script searches for a new valid # route. That valid route will be the new default route. # # The entry 0 is the standard route. You can request the script to go back # to standar route by sending a SIGUSR to it. The standard route will be # checked, if is not yet valid the script will not change the current # route. # # $dest_host is the url that you will ping. I have setted it to # "www.google.com" but you can change it if needed. # # This script goes to background as soon as possible. As a service should # do. You can define the log of it on $daemon_log variable. Its default is # the name of the script followed by ".log". # use strict; use warnings; use Net::Ping; use POSIX qw(setsid); use Time::localtime; use Fcntl qw(:flock SEEK_END); # # START CONFIGURE HERE # my @routes = ( { # iface => "ppp0", source => "200.171.87.72", gateway => "dev ppp0", init => sub { print ctime() . " Rebooting ppp0\n"; `ifdown ppp0`; `ifup ppp0`; }, }, { iface => "eth2", source => undef, gateway => "via 192.168.5.1", }, ); my $dest_host = "www.google.com"; my $standard_route = 1; # Used as index to @routes. So $routes[0] is the # standard route my $daemon_log = $0 . ".log"; # # STOP CONFIGURE HERE # # # Initialization # my $continue = 1; my $pid; my $indx = undef; my $current_route = undef; my $pid_file = "$0.pid"; my $pid_fh = undef; my $file_lock_fh = undef; my $file_lock_fname = "$0.lck"; $| = 1; # unbuffered STDOUT $SIG{TERM} = sub { $continue = 0 }; $SIG{USR1} = sub { print ctime() . " Standard route requested\n"; if ($routes[$standard_route] == $current_route) { print ctime() . " the standard route is already". " being used, nothing to do\n"; } elsif ($routes[$standard_route]->{ping}->ping($dest_host)) { print ctime() . " Standard route is valid, ". "backing to it\n"; $indx = $standard_route; set_route(); } else { print ctime() . " Standard route offline, nothing to do\n"; } }; sub init_routes { for my $r (@routes) { if ($r->{source}) { $r->{ping} = Net::Ping->new("icmp", 1); $r->{ping}->bind($r->{source}); } elsif ($r->{iface}) { $r->{ping} = Net::Ping->new("icmp", 1, 64, $r->{iface}); } else { die "Route without source and iface member\n". "You need at least one of them\n"; } } die "\$standard_out setted to out of bounds of ". "\@routes array\n" if $standard_route > $#routes; $indx = $standard_route; set_route(); } sub do_flock { open($file_lock_fh, ">$file_lock_fname") or die "Can't open lock file". " $file_lock_fname"; unless(flock($file_lock_fh, LOCK_EX | LOCK_NB)) { die "Cannot obtain lock. If there is another instance of". "this running kill it and try again"; } } sub do_funlock { my ($fname) = @_; unless(flock($file_lock_fh, LOCK_UN)) { die "Cannot release lock, this shouldn't be happening"; } close($file_lock_fh); } sub set_route { $current_route = $routes[$indx]; print ctime() . " Changing route to ". "$current_route->{gateway}\n"; $current_route->{init}() if $current_route->{init}; my $error = `ip route del default`; print " Can't delete default route\n" if $error; $error = `ip route add default $current_route->{gateway}`; die " Can't add default route" if $error; print ctime() . " Route changed\n"; } # Args # 1 => Ref to global $indx variable # 2 => The limmit sub next_indx { my ($indx, $limit) = @_; $$indx++; if ($$indx > $limit) { $$indx = 0; } } sub on_fail { my $error; print ctime() . " Ping failed\n"; print ctime() . " Default route is $current_route->{gateway}. Adding new route\n"; $error = `ip route del default via $current_route->{gateway}`; die $! if $error; next_indx(\$indx, $#routes); set_route(); print ctime() . " New route $current_route->{gateway} added\n"; } sub daemonise { umask 0; open STDIN, '/dev/null' or die "Can't read /dev/null: $!"; open STDOUT, ">$daemon_log" or die "Can't write to log: $!"; open STDERR, ">$daemon_log" or die "Can't write to log: $!"; defined(my $pid = fork) or die "Can't fork: $!"; exit if $pid; setsid or die "Can't start a new session: $!"; } # # MAIN LOOP # do_flock(); daemonise(); init_routes(); while ($continue) { if ($current_route->{ping}->ping($dest_host)) { # print ctime(); # if ($current_route->{source}) { # print " $current_route->{source} live\n"; # } else { # print " $current_route->{iface} live\n"; # } sleep(3); } else { on_fail(); } } do_funlock(); # vim:ft=perl:tabstop=8:shiftwidth=4:smarttab:noexpandtab:softtabstop=4:ai:tw=80
Nenhum comentário:
Postar um comentário