Looks out your network stack to see what's working and what's not.

I wrote this when my cat unplugged the router for the Nth time. (He likes to chew the little rubber boots on the premium patch cords.) I use this script so I don't have to type the usual mantra: ifconfig, netstat -rn, ping localhost, ping default, dig nameserver, etc.... I also have found it very usefull when The Commander yells over "Hon, why isn't Pogo working?" I just run this one script and yell back "It's not on our end."

I tried to make it robust and have inteligent error messages but here is more work to be done. Still, it's very useable nevertheless. I haven't spent much time on it lately so I thought I'd post it before it became completely dust covered.

The output looks like this:
1 interfaces down: plip0 3 interfaces up: rl0 fxp0 lo0 Checking localnet: 127.0.0.1 working. Checking "localhost" working. Checking interface rl0: 10.0.0.1 working. Checking interface fxp0: 192.168.1.11 working. 2 external interfaces found. Checking Default route: 192.168.1.10 working. Checking default router: 192.168.0.1 working. Checking DNS host: dns1.xxx.xxx.net. working. Checking DNS host: dns1.xxx.xxx.net. working.

Bugs:

  • Addresses for localhost, and router are hard coded.
  • Not portable.
  • No pod.
  • Would be nice to be able to specify your router from the command line.
  • Not portable.

    #!/usr/bin/perl -w # # peek.pl - walk up the IP stack looking for problems. # # 6/7/06 bet use strict; # Definitions my $localnet="127.0.0.1"; # Should get this from "hosts" file. my $router = "192.168.0.1"; # Your DSL gateway here. # # Files we need. my $resolv = "/etc/resolv.conf"; # To get the nameservers from. my $hosts = "/etc/hosts"; # To get "localhost" from. # # Commands my $short_ping = "ping -t1 -c1 -n "; my $dig_cmd = "dig"; my $dig_options = "+short +tries=1 +time=2"; my $config_cmd = "ifconfig"; my $status_cmd = "netstat -rn"; # # Hold found routes. my @net; my $token; my $host; # # Subroutines # sub check_interface { # ( -d|-u , "message" ) my $option = shift @_; my $message = shift @_; my $ifs=` $config_cmd $option | perl -lne '\$\\=" "; print \$1 if m/^([a-z]+[0-9])[:]/ +' `; my @ifs=split / /, $ifs; print scalar @ifs, $message; print "\t$_\n" foreach @ifs; return @ifs } sub ping_host { my $host = shift @_; `$short_ping $host`; print '', ($?==0)?'working.':'***FAILED***', "\n"; } # Abnomal exit point. Used for network errors. Use "die" for program +errors. sub bail { # Tell the user we can't continue. print shift @_; print "\nCan't continue tests.\n"; exit 1; } # # main - program starts here # `uname` =~ /FreeBSD/ or die "Program is for FreeBSD"; # Find any interfaces marked "down" check_interface( "-d", " interfaces down:\n" ); # Find any interfaces marked "up" my @ifs = check_interface( "-u", " interfaces up:\n" ); # Check localhost direct printf "%-26s%-15s", "Checking localnet:", $localnet; ping_host ( $localnet ); # Check local host via lookup printf "%-41s", 'Checking "localhost" '; ping_host( "localhost" ); # Find address of remaining interfaces. # Check it my $count=0; foreach my $ifs (@ifs) { do { @net = grep m/inet /, split /\n/, `$config_cmd $ifs`; if ( scalar @net != 1 ) { print "$ifs: No inet record found.\n"; next }; if ($net[0] =~ m/([0-9]+[.][0-9]+[.][0-9]+[.][0-9]+)/) + { printf "%-26s%-15s", "Checking interface $ifs:", $1; `$short_ping $1`; if ($?==0) { $count++; print "working.\n"; } else { print "***FAILED***\n"; } } } unless ( $ifs eq "lo0" ); } if($count == 0) { bail "No external interfaces!!!" }; print "$count external interface", ($count==1)?'':'s', " found.\n"; # Find default route and check @net = grep m/default/, split '\n', `$status_cmd`; if ( scalar @net == 0 ) { bail "No default route!" }; if ( scalar @net >= 2 ) { bail "Multiple default routes!" }; # Could be on different subnets?? ($token, $host) = split ' ', $net[0]; #awk compatible patter +n. printf "%-26s%-15s", "Checking Default route:", $host; ping_host ( $host ); # Ping router printf "%-26s%-15s", "Checking default router:", $router; ping_host ( $router ); # Could we maybe use TTL to resolve next hop? So we don't hardco +de it. # Otherwice we have to get it from the router. # "ping -m3 $DNS" works, but would break if ??. # lookup DNS in /etc/resolv.conf # Check DNS # -e $resolv or die "Resolv.conf file ***missing ***"; open FH, $resolv or die "Open $resolv failed: $!"; while (<FH>) { next if ( length $_ < 10 ); ($token, $host) = split ' '; #awk compatible patter +n. if ( $token eq "nameserver" ) { printf "%-26s", "Checking DNS host:"; `$dig_cmd \@$host -x $host $dig_options` =~ m/([\w]|[. +])+/; if ($?==0 ) { print "$& working.\n"; } else { print "$host ***FAILED***!\n"; } } } close FH; # Normal program termination. exit 0; __END__


  • s//----->\t/;$~="JAPH";s//\r<$~~/;{s|~$~-|-~$~|||s |-$~~|$~~-|||s,<$~~,<~$~,,s,~$~>,$~~>,, $|=1,select$,,$,,$,,1e-1;print;redo}

    Replies are listed 'Best First'.
    Re: [FreeBSD] Look out your (network) peephole.
    by parv (Parson) on Aug 19, 2006 at 05:19 UTC

      Slightly cleaned up version, namely -router option added to specify router and made the style self-consistent ...

      #!/usr/bin/perl -w # # peek.pl - walk up the IP stack looking for problems. # # 6/7/06 bet use strict ; use Getopt::Long qw(:config gnu_compat no_ignore_case no_debug) ; `uname` =~ /FreeBSD/ or die "Program is for FreeBSD" ; my %opt = ( 'router' => '192.168.2.1' ) ; GetOptions( 'r|router' => \$opt{ 'router' } ) or die ; # Definitions my $localnet = "127.0.0.1" ; # Should get this from "hosts" file. # Files we need. my $resolv = "/etc/resolv.conf" ; # To get the nameservers from. my $hosts = "/etc/hosts" ; # To get "localhost" from. # Commands my $short_ping = q(ping -t1 -c1 -n) ; my $dig_cmd = q(dig) ; my $dig_options = q(+short +tries=1 +time=2) ; my $config_cmd = q(ifconfig) ; my $status_cmd = q(netstat -rn) ; # Hold found routes. my @net ; my $token ; my $host ; # Subroutines # sub check_interface { # Options: -d interface down; -u: interface up my ( $option, $message ) = @_ ; my @ifs = qx{ $config_cmd $option } ; return unless scalar @ifs ; @ifs = map { m/^([a-z]+[0-9]):/ ? $1 : () } @ifs ; print scalar @ifs, $message ; print "\t$_\n" foreach @ifs ; return @ifs ; } sub ping_host { my ( $host, $show_msg ) = @_ ; my $cmd = join ' ', $short_ping, $host, '>/dev/null 2>&1' ; my $rc = system( $cmd ) == 0 ; printf "%s\n", $rc ? 'working.' : '***FAILED***' if $show_msg ; return $rc ; } # Abnomal exit point. Used for network errors. Use "die" for program +errors. sub bail { # Tell the user we can't continue. print shift @_ ; print "\nCan't continue tests.\n" ; exit 1 ; } sub print_check_msg { my ( $chk, $what ) = @_ ; printf '%-26s', 'Checking ' . $chk ; printf '%-14s', $what if defined $what ; } # Find any interfaces marked "down" check_interface( "-d", " interfaces down:\n" ) ; # Find any interfaces marked "up" my @ifs = check_interface( "-u", " interfaces up:\n" ) ; # Check localhost direct print_check_msg( "localnet:", $localnet ) ; ping_host( $localnet, 'print' ) ; # Check local host via lookup print_check_msg( '"localhost" ', '' ) ; ping_host( "localhost", 'print' ) ; # Find address of remaining interfaces. # Check it my $count = 0 ; foreach my $ifs ( @ifs ) { next if $ifs eq 'lo0' ; @net = grep m/inet /, split /\n/, qx{$config_cmd $ifs} ; unless ( scalar @net ) { print "$ifs: No inet record found.\n" ; next ; } if ( $net[0] =~ m/( (?:[0-9]+[.]){3} [0-9]+)/x ) { print_check_msg( "interface $ifs:", $1 ) ; ping_host( $1, 'print' ) and $count++; } } if ( $count == 0 ) { bail "No external interfaces!!!" } print "$count external interface", ( $count == 1 ) ? '' : 's', " found +.\n" ; # Find default route and check @net = grep m/default/, split '\n', `$status_cmd` ; if ( scalar @net == 0 ) { bail "No default route!" } if ( scalar @net >= 2 ) { bail "Multiple default routes!" } # Could be on different subnets?? ( $token, $host ) = split ' ', $net[ 0 ] ; #awk compatible pattern. print_check_msg( "Default route:", $host ) ; ping_host( $host, 'print' ) ; print_check_msg( "default router:", $opt{ 'router' } ) ; ping_host( $opt{ 'router' }, 'print' ) ; # Could we maybe use TTL to resolve next hop? So we don't hardco +de it. # Otherwice we have to get it from the router. # "ping -m3 $DNS" works, but would break if ??. # lookup DNS in /etc/resolv.conf # Check DNS # -e $resolv or die "$resolv file ***missing ***" ; open FH, '<' , $resolv or die "Open $resolv failed: $!" ; while ( <FH> ) { next if length $_ < 10 ; ( $token, $host ) = split ' ' ; #awk compatible pattern. next if $token ne "nameserver" ; print_check_msg( "DNS host:" ) ; qx{$dig_cmd \@$host -x $host $dig_options} =~ m/([\w.]+)/ ; printf "%s\n", $? == 0 ? "$1 working." : "$host ***FAILED***!" ; } close FH or die "Close $resolv failed: $!" ; # Normal program termination. exit 0 ; __END__