#!/usr/bin/perl # $Id: check_traceroute.pl,v 1.1 2005/01/27 10:34:16 stanleyhopcroft Exp $ # $Log: check_traceroute.pl,v $ # Revision 1.1 2005/01/27 10:34:16 stanleyhopcroft # Jon Meek's check_traceroute for Mon hacked by YT for Nagios. Prob pretty weak # use strict ; use vars qw(%ERRORS $TIMEOUT) ; use utils qw(%ERRORS $TIMEOUT &print_revision &support &usage) ; sub print_help (); sub print_usage (); $ENV{'PATH'}='/bin:/usr/bin:/usr/sbin'; my $PROGNAME = 'check_traceroute' ; # delay units are millisecs. my $MAX_INTERHOP_DELAY = 200 ; my $MAX_HOPS = 30 ; use Getopt::Std; use vars qw($opt_H $opt_N $opt_r $opt_R $opt_T $opt_d $opt_h $opt_i $opt_v $opt_V) ; getopts('i:H:N:R:T:dhrvV'); # H, N, R, T, and i take parms, others are flags do { print_help ; exit $ERRORS{OK}; } if $opt_h ; do { print_revision($PROGNAME, '$Revision: 1.1 $'); exit $ERRORS{OK}; } if $opt_V ; do { print_help; exit $ERRORS{OK}; } unless $opt_R || $opt_r ; do { print_help; exit $ERRORS{OK}; } unless $opt_R =~ m| (?:\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}-)+ \d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3} |x || $opt_r ; my $should_be = $opt_R ; # Set default timeout in seconds my $TimeOut = $opt_T || $TIMEOUT; my $max_interhop_delay = $opt_i || $MAX_INTERHOP_DELAY ; my $max_hops = $opt_N || $MAX_HOPS ; my $TRACEROUTE = '/usr/sbin/traceroute'; my $TargetHost = $opt_H ; print_help unless $TargetHost ; my ($route, $pid, $rta_list) = ( '', '', '' ); my %ResultString = () ; $SIG{ALRM} = sub { die "timeout" }; eval { alarm($TimeOut); # XXXX Discarding STDERR _should_ reduce the risk # of unexpected output but consequently, results for # non existent hosts are stupid. However, why would you # specify a route to a NX host, other than a typo ... $pid = open(TR, "$TRACEROUTE -n $TargetHost 2>/dev/null |") or do { "Failed. Cannot fork \"$TRACEROUTE\": $!" ; $ERRORS{UNKNOWN} ; } ; my $hops = 0 ; while () { print $_ if $opt_d; if ( m|#\*\s+\*\s+\*| ) { # Get * * * then give up $route .= '*'; # 13 = PIPE, prevents Broken Pipe Error, at least on Solaris kill 13, $pid; last; } # We will only pick up the first IP address listed on a line for now # traceroute to csg.citec.com.au (203.9.184.12), 64 hops max, 44 byte packets # 1 10.254.254.254 0.868 ms 0.728 ms 0.705 ms # 2 192.168.9.1 1.240 ms 1.165 ms 1.191 ms my ($ThisHopIP) = m|\s+(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})\s+|; my ($max_rta) = m|\d{1,3}\.\d{1,3}\.\d{1,3}\s+ (\d+\.\d+) ms| ; $route .= $ThisHopIP . '-'; $rta_list .= sprintf("%.1f", $max_rta) . '-' ; if ( $opt_v ) { chomp $_ ; print $_, ' ' x (58 - length), $route, "\n"; } $hops++ ; if ( ($hops >= $max_hops) && ! $opt_r ) { kill 13, $pid ; print qq(Failed. Max hops ($max_hops) exceeeded: incomplete after $hops hops, "$route".\n) ; exit $ERRORS{CRITICAL} ; } if ( ($hops %2 == 0) && ($hops >= 4) && ! $opt_r ) { # Check for 2 cycles at end of path ie -(a-b)-(a-b)$ # where a and b are IP v4 addresses of IS (routers). my ($last_2_is) = $route =~ /(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}-\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})-$/ ; if ( $route =~ /$last_2_is-$last_2_is-$/ ) { kill 13, $pid ; print qq(Failed. Last 2 routers ($last_2_is) repeated, "$route".\n) ; exit $ERRORS{CRITICAL} ; } } } }; alarm(0); if ( $@ and $@ =~ /timeout/ ) { $route .= '*'; # It was a traceroute timeout kill 13, $pid; } elsif ( $@ and $@ !~ /timeout/ ) { close TR ; print "Failed. Somethings gone wrong with \"$TRACEROUTE\": $!" ; exit $ERRORS{UNKNOWN} ; } close TR; # Remove trailing '-'s # $route =~ s/\-$//; chop($route) ; chop($rta_list) ; print "$route\n" if $opt_d; if ( $opt_r ) { print qq(Ok. Traceroute to host "$TargetHost" via route "$route".\n) ; exit $ERRORS{OK}; } if ( &RouteEqual($should_be, $route) ) { print qq(Ok. Traceroute to "$TargetHost" via expected route "$route" ($rta_list).\n) ; exit $ERRORS{OK}; } else { print qq(Failed. Route "$route" ne expected "$should_be".\n) ; exit $ERRORS{CRITICAL}; } sub RouteEqual { my ($current_route, $prev_route) = @_; return $current_route eq $prev_route ; } sub print_usage () { print "Usage: $PROGNAME [ -R |-r ] [ -d -T timeout -v -h -i ] -H \n"; } sub print_help () { print_revision($PROGNAME, '$Revision: 1.1 $') ; print "Copyright (c) 2004 J Meek/Karl DeBisschop This plugin checks whether traceroute to the destination succeeds and if so that the route string option (-R) matches the list of routers returned by traceroute. "; print_usage(); print " -d Debug -h Help -i _TODO_ Max inter-hop delay (msec). -H Host. -N Max number of hops. -r Record current route (and output to STDOUT). Useful for getting the value of -R option ... -v Greater verbosity. -R Mandatory route string ie r1-r2-... where ri is the ip address of the ith router. -T Maximum time (seconds) to wait for the traceroute command to complete. Defaults to $TIMEOUT seconds. "; support(); }