#!/usr/bin/perl -w
#
# routewatch.pl by Pegasus Epsilon <pegasus@pimpninjas.org>
# Distribute Unmodified -- http://pegasus.pimpninjas.org/license
#
# Memorizes and monitors a portion of a route for changes over time.
# This includes nodes dropping AND traffic getting rerouted.
use strict;
use Socket;
select((select(STDOUT), $| = 1)[0]);
sub usage {
print "Usage: $0 <remote IP> [first TTL] [last TTL]\n";
exit 0;
}
my %dnscache;
sub ptr {
my $ip = shift;
defined $dnscache{$ip}
&& return $dnscache{$ip};
my $tmp = inet_aton($ip)
|| return $dnscache{$ip} = "NO_RESPONSE";
$tmp = gethostbyaddr($tmp, AF_INET)
|| return $dnscache{$ip} = "PTR_RECORD_NOT_FOUND";
return $dnscache{$ip} = $tmp;
}
sub routeping {
my ($f, $m, $ip) = @_;
my $N = $m - $f + 1;
my @route = map { s/^ *//; s/ +/ /; $_ } split /\n/,
`traceroute -n -f $f -m $m -w 1 -q 1 -N $N $ip`;
shift @route;
return @route;
}
my $ip = shift;
usage unless $ip;
my $first_ttl = shift || 1;
my $last_ttl = shift || 30;
print "memorizing hops $first_ttl to $last_ttl between here and $ip...\n";
my %route;
for my $i (routeping($first_ttl, $last_ttl, $ip)) {
my ($hop, $ip, $rtt) = split / /, $i;
print "$hop $ip ", ptr($route{$last_ttl = $hop} = $ip), "\n";
}
print "memorization complete, monitoring for changes...\n";
for (;;) {
print "sleeping...\r";
sleep 1;
print "polling... \r";
for my $i (routeping($first_ttl, $last_ttl, $ip)) {
my ($hop, $ip, $rtt) = split / /, $i;
if (not $route{$hop} or $route{$hop} ne $ip) {
print scalar localtime, ": route changed: $hop $route{$hop} ",
ptr($route{$hop}), " -> $ip ",
ptr($route{$hop} = $ip), "\n";
}
}
}