#!/usr/bin/perl # # *BSD route compare script by Petje < route_compare at painfullscratch.nl > # tested on FreeBSD # # Compares 'netstat -rn' and 'rc.conf' and outputs differences to stdout. # # Needs /usr/ports/net-mgmt/p5-NetAddr-IP, /usr/ports/devel/p5-Algorithm-Diff and Perl :) # my $rcconf = '/etc/rc.conf'; my $netstatrn = '/usr/bin/netstat -W -r -n -f inet'; # # # # use lib './lib'; # for those who install Algorithm::Diff and NetAddr::IP in '.' use strict; use NetAddr::IP; use Algorithm::Diff; my $VERSION = '0.3.1'; sub collect_active_array { my @active_array; my @activeroutes = `$netstatrn`; for my $line (@activeroutes) { next if ($line =~ /^127.0.0.1\s+/); $line =~ s!^default(\s+.*?)!0.0.0.0/0${1}!; if($line =~ /^([0-9\.\/]+)\s+(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})\s+.*?$/) { my $dest = $1; my $gateway = $2; push(@active_array,main::normalize_ip($1).' '.main::normalize_ip($2)); } } return sort(@active_array); } sub collect_config_array { my @config_array; my $configlines = main::read_file($rcconf); if($configlines =~ /^static_routes=["'](.+)["']\s*$/m) { for my $route (split(/\s+/,$1)) { if($configlines =~ /^route_$route=['"]-(host|net)\s+(.+?)\s+(.+?)['"]/m) { my $type = $1; my $dest = $2; my $gateway = $3; my $ip = main::normalize_ip($dest); if($type eq 'host' && $ip->num != 1) { print STDERR $ip." isn't a host-type\n"; } if($type eq 'net' && $ip->num <= 1) { print STDERR $ip." isn't a net-type\n"; } push(@config_array,$ip.' '.main::normalize_ip($gateway)); } else { print STDERR "There's something wrong with route \"$route\"\n"; } } } if($configlines =~ /^defaultrouter=["'](.+)["']\s*$/m) { my $gateway = $1; push(@config_array,'0.0.0.0/0 '.main::normalize_ip($gateway)); } return sort(@config_array); } sub normalize_ip { my $ip = shift; my $octets = '0'; $_ = $ip; if(! /.*\/\d{1,2}$/) { $octets = scalar(split(/\./,$ip)); for(my $i=scalar($octets); $i < 4; $i++) { $ip .= '.0'; } } if($octets > 0) { $ip .= '/'.($octets * 8); } my $nip = new NetAddr::IP $ip; return $nip; } sub read_file { my ($file) = @_; local($/) = wantarray ? $/ : undef; local(*F); my $r; my (@r); open(F, "<$file") || die "error opening $file: $!"; @r = ; close(F) || die "error closing $file: $!"; return $r[0] unless wantarray; return @r; } die('You must be root to run this program') unless($> == 0); my $reqversion = 1.19; # OO interface available since 1.19 if($Algorithm::Diff::VERSION < $reqversion) { die("I need at least version $reqversion of Algorithm::Diff"); } my @activerules = main::collect_active_array(); my @configrules = main::collect_config_array(); my $diff = Algorithm::Diff->new( \@activerules, \@configrules ); $diff->Base(1); my @output; while( $diff->Next() ) { next if $diff->Same(); my $sep = ''; if( ! $diff->Items(2) ) { push(@output,sprintf "%d,%dd%d", $diff->Get(qw( Min1 Max1 Max2 ))); } elsif( ! $diff->Items(1) ) { push(@output,sprintf "%da%d,%d", $diff->Get(qw( Max1 Min2 Max2 ))); } else { $sep = "---\n"; push(@output,sprintf "%d,%dc%d,%d", $diff->Get(qw( Min1 Max1 Min2 Max2 ))); } push(@output,"+ ${_}") for $diff->Items(1); push(@output,"- ${_}") for $diff->Items(2); } if(scalar(@output) > 0) { print '+++ active ('.$netstatrn.")\n"; print '--- config ('.$rcconf.")\n"; print join("\n",@output); print "\n"; }; exit(0);