sourcecode
cleen
<code>
#!/usr/bin/perl
use strict;
use Getopt::Std;
use Net::Telnet;
my %globhash;
my %subhash;
my %args = ();
getopts("fksdu:p:i:c:h", \%args);
my @ips;
my $IP_FILE;
my $CONF_FILE;
my $debug = 0;
my $USER = '';
my $PASS = '';
$debug = 1 if $args{d};
$USER = $args{u} if $args{u};
$PASS = $args{p} if $args{p};
$IP_FILE = $args{i};
$CONF_FILE = $args{c};
if ($args{h}) {
&showhelp;
}
die "usage: $0 [-dupicskhf] -u <user> -p <pass> -i <ipfile> -c <conf file>" unless ($IP_FILE && $CONF_FILE);
open(IPS, "$IP_FILE");
while(<IPS>) {
chomp;
push @ips,$_;
}
close(IPS);
foreach my $ip (@ips) {
doaudit($ip);
unlink "$ip.tmp" if !$args{k};
}
sub showhelp {
print <<EOF
-u <user>: username of the juniper routers
-p <pass>: password of the juniper routers
-i <ipfile>: file of ip juniper ip address's
-c <config>: the audit configuration file (see README)
-d : debugging information (mucho text)
-s : show matched information also
(Not just the not matched)
-h : this help screen ;)
-k : keep a copy of the juniper's config file in <hostname>.tmp
-f : show stuff that was left over that was in the juniper.conf
but not in the audit configuration file (stuff that was in
the juniper.conf but not in the template
EOF
}
sub getconfig {
my($host) = @_;
my $t;
my $CMD = 'show configuration | no-more';
$t = new Net::Telnet (Timeout => 10);
$t->open("$host");
$t->login($USER, $PASS);
my @lines = $t->cmd($CMD);
open(TMP, ">$host.tmp");
foreach my $line (@lines) {
print TMP "$line";
}
close(TMP);
}
sub getintnames {
# usage getintnames(IP, TYPE(OC-3));
# returns array
my (@cardz,$slotcounter,$slot,$cardtype,$pic,$ports);
my($ip,$type) = @_;
my $t;
my $CMD = 'show chassis fpc pic-status';
$t = new Net::Telnet (Timeout => 10);
$t->open("$ip");
$t->login($USER, $PASS);
my @lines = $t->cmd($CMD);
foreach my $fpc (@lines) {
if ($fpc =~ /Slot (\d+?).*$/) {
$slotcounter = 1;
$slot = $1;
next;
}
if ($slotcounter eq 1) {
my $knownthing = 0;
if ($fpc =~ /PIC (\d+?)\s+(.*?)\,.*$/) {
$cardtype = $2;
$pic = $1;
if($cardtype =~ /$type/) {
$ports = $cardtype;
$ports =~ /^(\d)x.*/;
$ports = $1;
$knownthing = 1;
for (my $i = 0; $i < $ports; $i++) {
my $card = "so-$slot/$pic/$i";
push @cardz,$card;
}
}
}
}
}
return @cardz;
}
sub parsit {
my (@matched,@body);
my ($host,$where) = @_;
open(FILE, "$host.tmp");
my $inside = "";
my %hash = ();
while (<FILE>) {
chomp;
push @body,$_;
}
close(FILE);
while (my $line = shift @body) {
if($line =~ /^([^\{]+)\{/) {
my $start = $1;
$start =~ s/^\s+//g;
$start =~ s/\s+$//g;
if($inside) {
$inside .= ":$start";
}
else {
$inside = $start;
}
next;
}
elsif ($line =~ /\}/) {
push @{$hash{$inside}},undef;
if ($inside =~ /\w+(\:\w+)+/) {
my @tmp = split ':', $inside;
$#tmp--;
$inside = join ':', @tmp;
}
else {
$inside = "";
next;
}
}
else {
$line =~ s/^\s+//g;
$line =~ s/\s+$//g;
push @{$hash{$inside}},$line;
}
}
foreach my $thingy ( keys %hash ) {
foreach my $blah (@{ $hash{$thingy} }) {
$blah =~ s/^\s+//g;
push @matched,$blah if $thingy eq $where;
}
}
return @matched;
}
sub doaudit {
my($host) = @_;
my (@all);
getconfig($host);
open(FILE, "$CONF_FILE");
while(<FILE>) {
chomp;
s/^\#.*$//g; # i want comments damnit
s/\n$//g;
s/\s+$//g;
s/^\s+//g;
print "DEBUG: while(<FILE>) {: pushing $_ into \@all\n"
if $debug eq 1;
push @all, $_;
}
close(FILE);
print "\n\n"
if $debug eq 1;
my $startgroup = 0;
my $brackets = 0;
my $globalcounter = 0;
my $subcounter = 0;
my $group;
my $sub;
my %globhash = ();
my %subhash = ();
foreach my $line (@all) {
if ($line =~ /^GROUP: (\S+?)\s+\{$/) {
$group = $1;
$startgroup = 1;
print "DEBUG: \$line matched GROUP: $group\n"
if $debug eq 1;
next;
}
if ($startgroup eq 1) {
if ($line =~ /GLOBAL {$/) {
print "DEBUG: Matched GLOBAL for \"$line\"\n"
if $debug eq 1;
$globalcounter = 1;
next;
}
if ($globalcounter eq 1) {
print "DEBUG: \$globalcounter ='s 1\n"
if $debug eq 1;
if ($line =~ /}/) {
print "DEBUG: \$line matched }\n"
if $debug eq 1;
$globalcounter = 0;
next;
}
else {
print "DEBUG: \$line isnt }\n"
if $debug eq 1;
if ($globhash{$group} eq "") {
$globhash{$group} = "$line";
print "DEBUG globhash \$globhash{$group} = \"$line\"\n"
if $debug eq 1;
next;
}
else {
$globhash{$group} .= "!:!$line";
print "DEBUG globhash \$globhash\{$group\} = \"!:!$line\"\n"
if $debug eq 1;
next;
}
}
}
if ($line =~ /SUB: (.*?)\s+{$/) {
$sub = $1;
$subcounter = 1;
print "DEBUG \$line matched SUB: $line\n"
if $debug eq 1;
next;
}
if ($subcounter eq 1) {
print "DEBUG \$subcounter ='s 1: $line\n"
if $debug eq 1;
if ($line =~ /}/) {
$subcounter = 0;
print "DEBUG found } so \$subcounter ='s 0 now\n"
if $debug eq 1;
next;
}
else {
my $both = "$group:$sub";
if ($subhash{$both} eq "") {
$subhash{$both} = "$line";
print "DEBUG subhash \{$both\} = \"$line\"\n"
if $debug eq 1;
next;
}
else {
$subhash{$both} .= "!:!$line";
print "DEBUG subhash \{$both\} = \"!:!$line\"\n"
if $debug eq 1;
next;
}
}
}
}
}
my $type;
print "\n$host audit\n----------------------------\n";
print "GLOBALS\n";
while(my($k,$v) = each %globhash) {
my @stuff = split(/!:!/,$v);
my $worde;
my @matched = parsit($host,$k);
for (my $j=0; $j < @stuff; $j++) {
$stuff[$j] =~ /(.*?):(.*?)$/;
$type = $1;
$worde = $2;
my $knownthing = 0;
for (my $i=0; $i < @matched; $i++) {
$worde =~ s/^\s+//g;
$matched[$i] =~ s/^\s+//g;
$matched[$i] =~ s/\s+$//g;
if ($type eq "EXACT") {
if ($worde eq $matched[$i]) {
print "\tMATCHED EXACT: $k -- $matched[$i]\n" if $args{s};
splice(@matched, $i, 1);
splice(@stuff, $j, 1);
$j--;
$i--;
$knownthing = 1;
}
}
if ($type eq "INCLUDE") {
if ($matched[$i] =~ /$worde/) {
print "\tMATCHED REGEX: $k -- $matched[$i]\n" if $args{s};
splice(@matched, $i, 1);
splice(@stuff, $j, 1);
$j--;
$i--;
$knownthing = 1;
}
}
}
}
if ($args{f}) {
print "\tNOT IN TEMPLATE:\n";
foreach my $crap (@matched) {
next if $crap =~ /^\s+$/;
print "\t\t$crap\n";
}
}
print "\tNOT IN HOSTS JUNIPER.CONF:\n";
foreach my $crap (@stuff) {
next if $crap =~ /^\s+$/;
print "\t\t$crap\n";
}
}
print "\nSUBS\n";
my @stuff;
while(my($k,$v) = each %subhash) {
my ($intmatch) = 0;
my ($worde);
my ($ktmp);
my $haveint = 0;
@stuff = split(/!:!/,$v);
if ($k =~ /MATCH-INTERFACES (.*?)($|:(.*))/) {
my $devtype = $1;
my $whatelse = $2;
my @intnames = getintnames($host,$devtype);
foreach my $int (@intnames) {
$ktmp = $k;
$ktmp =~ s/MATCH-INTERFACES.*?($|:)/$int:/g;
getsubs(\@stuff,$host,$ktmp);
}
next;
}
else {
$ktmp = $k;
getsubs(\@stuff,$host,$ktmp);
next;
}
sub getsubs {
my ($stuff,$host,$k) = @_;
my @matched = parsit($host,$k);
for (my $j=0; $j < @$stuff; $j++) {
$stuff->[$j] =~ /(.*?):(.*?)$/;
$type = $1;
$worde = $2;
my $knownthing = 0;
for (my $i=0; $i < @matched; $i++) {
$worde =~ s/^\s+//g;
$matched[$i] =~ s/^\s+//g;
$matched[$i] =~ s/\s+$//g;
if ($type eq "EXACT") {
if ($worde eq $matched[$i]) {
print "\t\t\tMATCHED EXACT: $k -- $matched[$i]\n" if $args{s};
splice(@matched, $i, 1);
$i--;
$knownthing = 1;
}
}
if ($type eq "INCLUDE") {
if ($matched[$i] =~ /$worde/) {
print "\t\t\tMATCHED REGEX: $k -- $matched[$i]\n" if $args{s};
splice(@matched, $i, 1);
$i--;
$knownthing = 1;
}
}
}
print "\tNOT IN JUNIPER.CONF: $k -- $worde\n" if !$knownthing;
}
if ($args{f}) {
foreach my $crap (@matched) {
next if $crap =~ /^\s+$/;
next if $crap eq "";
print "\t\tNOT IN TEMPLATE $k -- $crap\n";
}
}
}
}
}
</CODE>
Juniper (www.juniper.net) is a provider of high-end routing equipment, even the lower-end
juniper equipment (m20) can out-preform cisco's high-end 12k GSR's.
<br><br>
I needed a way to easily audit my juniper configurations on a ever expanding juniper-core
based network, thus this was born.
<br><br>
Writing the template configuration file:<br>
Writing the template configuration is a little on the complex side, and it takes a little bit of explaining, so I put the configuration readme at <a href="http://www.ackers.net/~mark/juniper-audit-readme.txt">juniper-audit-readme.txt</a><br><br>
Overall this code is in beta, and I know there are many things I could do much better, and I intend on doing so, any suggestions and comments would also be great!
Networking Code
Mark Thomas
mark@ackers.net