Code

Fix for regex input of '|', being output causing problems with Nagios' parsing of
[nagiosplug.git] / contrib / check_traceroute.pl
1 #!/usr/bin/perl
3 # $Id: check_traceroute.pl 1115 2005-01-27 10:34:16Z stanleyhopcroft $
5 # Revision 1.1  2005/01/27 10:34:16  stanleyhopcroft
6 # Jon Meek's check_traceroute for Mon hacked by YT for Nagios. Prob pretty weak
7 #
9 use strict ;
11 use vars qw(%ERRORS $TIMEOUT) ;
12 use utils qw(%ERRORS  $TIMEOUT &print_revision &support &usage) ;
14 sub print_help ();
15 sub print_usage ();
17 $ENV{'PATH'}='/bin:/usr/bin:/usr/sbin';
19 my $PROGNAME                    = 'check_traceroute' ;
20                                                                                 # delay units are millisecs.
21 my $MAX_INTERHOP_DELAY  = 200 ;
22 my $MAX_HOPS                    = 30 ;
24 use Getopt::Std;
26 use vars qw($opt_H $opt_N $opt_r $opt_R $opt_T $opt_d $opt_h $opt_i $opt_v $opt_V) ;
28 getopts('i:H:N:R:T:dhrvV');
29                                                                                 # H, N, R, T, and i take parms, others are flags
31 do { print_help ; exit $ERRORS{OK}; }
32         if $opt_h ;
34 do { print_revision($PROGNAME, '$Revision: 1115 $'); exit $ERRORS{OK}; }
35         if $opt_V ;
37 do { print_help; exit $ERRORS{OK}; }
38         unless $opt_R || $opt_r ;
40 do { print_help; exit $ERRORS{OK}; }
41         unless $opt_R =~        m|
42                                                         (?:\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}-)+
43                                                         \d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}
44                                                 |x 
45         || $opt_r ;
47 my $should_be           = $opt_R ;
48                                                                                 # Set default timeout in seconds
49 my $TimeOut                     = $opt_T || $TIMEOUT;
51 my $max_interhop_delay  = $opt_i || $MAX_INTERHOP_DELAY ;
52 my $max_hops            = $opt_N || $MAX_HOPS ;
54 my $TRACEROUTE          = '/usr/sbin/traceroute';
56 my $TargetHost          = $opt_H ; 
58 print_help 
59         unless $TargetHost ;
61 my ($route, $pid, $rta_list) = ( '', '', '' );
62 my %ResultString = () ;
63  
64 $SIG{ALRM} = sub { die "timeout" };
66 eval {
68         alarm($TimeOut);
69                                                                                 # XXXX Discarding STDERR _should_ reduce the risk
70                                                                                 # of unexpected output but consequently, results for
71                                                                                 # non existent hosts are stupid. However, why would you
72                                                                                 # specify a route to a NX host, other than a typo ...
74         $pid = open(TR, "$TRACEROUTE -n $TargetHost 2>/dev/null |") 
75                 or do   {
76                                          "Failed. Cannot fork \"$TRACEROUTE\": $!" ;
77                                          $ERRORS{UNKNOWN} ;
78                                 } ;
80         my $hops = 0 ;
81         while (<TR>) {
83                 print $_
84                         if $opt_d;
86                 if ( m|#\*\s+\*\s+\*| ) {
87                                                                                 # Get * * * then give up
88                         $route .= '*';
89                                                                                 # 13 = PIPE, prevents Broken Pipe Error, at least on Solaris
90                         kill 13, $pid;
91                         last;
92                 }
93                                                                                 # We will only pick up the first IP address listed on a line for now
94                                                                                 # traceroute to csg.citec.com.au (203.9.184.12), 64 hops max, 44 byte packets
95                                                                                 # 1  10.254.254.254  0.868 ms  0.728 ms  0.705 ms
96                                                                                 # 2  192.168.9.1  1.240 ms  1.165 ms  1.191 ms
98                 my ($ThisHopIP) = m|\s+(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})\s+|;
99                 my ($max_rta)   = m|\d{1,3}\.\d{1,3}\.\d{1,3}\s+ (\d+\.\d+) ms| ; 
101                 $route          .= $ThisHopIP . '-';
102                 $rta_list       .= sprintf("%.1f", $max_rta) . '-' ; 
104                 if ( $opt_v ) {
105                         chomp $_ ;
106                         print $_, ' ' x (58 - length), $route, "\n";
107                 }
109                 $hops++ ;
111                 if ( ($hops >= $max_hops) && ! $opt_r ) {
112                                 kill 13, $pid ;
113                                 print qq(Failed. Max hops ($max_hops) exceeeded: incomplete after $hops hops, "$route".\n) ;
114                                 exit $ERRORS{CRITICAL} ;
115                 }
116                 if ( ($hops %2 == 0) && ($hops >= 4)  && ! $opt_r ) {
118                                                                                 # Check for 2 cycles at end of path ie -(a-b)-(a-b)$
119                                                                                 # where a and b are IP v4 addresses of IS (routers).
121                         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})-$/ ;
122                         if ( $route =~ /$last_2_is-$last_2_is-$/ ) {
123                                 kill 13, $pid ;
124                                 print qq(Failed. Last 2 routers ($last_2_is) repeated, "$route".\n) ;
125                                 exit $ERRORS{CRITICAL} ;
126                         }
128                 } 
130         }
131 };
133 alarm(0);
135 if ( $@ and $@ =~ /timeout/ ) {
136                 $route .= '*';
137                                                                                 # It was a traceroute timeout
138                 kill 13, $pid;
139 } elsif ( $@ and $@ !~ /timeout/ ) {
140                 close TR ;
141                 print "Failed. Somethings gone wrong with \"$TRACEROUTE\": $!" ;
142                 exit $ERRORS{UNKNOWN} ;
145 close TR;
146                                                                                 # Remove trailing '-'s
147 # $route =~ s/\-$//;
148 chop($route) ;
149 chop($rta_list) ;
151 print "$route\n"
152         if $opt_d;
154 if ( $opt_r ) {
155         print qq(Ok. Traceroute to host "$TargetHost" via route "$route".\n) ;
156         exit $ERRORS{OK};
159 if ( &RouteEqual($should_be, $route) ) {
160         print qq(Ok. Traceroute to "$TargetHost" via expected route "$route" ($rta_list).\n) ;
161         exit $ERRORS{OK};
162 } else {
163         print qq(Failed. Route "$route" ne expected "$should_be".\n) ;
164         exit $ERRORS{CRITICAL};
168 sub RouteEqual {
169         my ($current_route, $prev_route) = @_;
170         return $current_route eq $prev_route ; 
173 sub print_usage () {
174         print "Usage: $PROGNAME [ -R <route_string>|-r ] [ -d  -T timeout -v -h -i ] -H <host>\n";
177 sub print_help () {
178         print_revision($PROGNAME, '$Revision: 1115 $') ;
179         print "Copyright (c) 2004 J Meek/Karl DeBisschop
181 This plugin checks whether traceroute to the destination succeeds and if so that the route string option (-R) matches the list of routers
182 returned by traceroute.
184 ";
185 print_usage();
186         print "
187 -d
188    Debug
189 -h
190    Help
191 -i
192    _TODO_
193    Max inter-hop delay (msec).
194 -H
195    Host.
196 -N
197    Max number of hops.
198 -r
199    Record current route (and output to STDOUT). Useful for getting the value of -R option ...
200 -v
201    Greater verbosity.
202 -R
203    Mandatory route string ie r1-r2-... where ri is the ip address of the ith router.
204 -T
205    Maximum time (seconds) to wait for the traceroute command to complete. Defaults to $TIMEOUT seconds.
207 ";
208         support();