#!/usr/local/bin/perl # written by Damien Mascord # # =============================================================== # # Script for turning a nmslog (Cisco Router Log) into a database readable form (CSV) # Usage: router2csv [-s ] [-e ] [-o ] filename[s] # Example Usage: # router2csv -s "Jan 7 19:05:38" -e "Mar 7 00:00" /var/adm/router.log # the "'s are important and will not work without them. # # =============================================================== # RCS $Header: /export/CVS/router2csv/router2csv.pl,v 1.5 2000/01/19 03:22:36 damien Exp $ # $Log: router2csv.pl,v $ # Revision 1.5 2000/01/19 03:22:36 damien # fixed date checking for 01 vs 1 # # Revision 1.4 2000/01/19 01:40:26 damien # converted over to CVS # # Revision 1.3 2000/01/18 23:52:15 damien # adding support for "Non-matching address" error for ftp ip masqing # cleaned up the code a little # # Revision 1.2 2000/01/18 23:34:10 damien # fixed RCS header info # # Revision 1.1 2000/01/18 23:32:14 damien # Initial revision # hash of months in Number, and three letter format for easy conversion. %NUM_MONTH = ( 'Jan' => '01', 'Feb' => '02', 'Mar' => '03', 'Apr' => '04', 'May' => '05', 'Jun' => '06', 'Jul' => '07', 'Aug' => '08', 'Sep' => '09', 'Oct' => '10', 'Nov' => '11', 'Dec' => '12' ); if ($ARGV[0]) { # works out what files are on the command line aswell as options (this section can be # copy/pasted very easily to have the same type of command line options. foreach (@ARGV){ # if it detects a - as the first part of a argument, it switches a toggle # so that the next time round it will catch the argument after the -[a-z] if ($_ =~ /^-/){ $opt_toggle=1;$toggle=$_; next; } # catches the argument after the switch (namely here a date field in "") if ($opt_toggle){ if ($toggle=~/-s/) { $start_time=&date2num ($_); } elsif ($toggle=~/-e/) { $end_time=&date2num ($_); } elsif ($toggle=~/-o/) { $output_file=$_; } elsif ($toggle=~/-W/) { $write_over=1; } $opt_toggle=0; next; } else { $files[$i++]=$_; } } #look at logs from STDIN if there are no files on the command line. unless ($i) { # if an output file is defined it will open it for writing. # you actually do have a choice whether to append or destroy! (-W) if ($write_over) { open OUTPUT, ">$output_file" if ($output_file); } else { open OUTPUT, ">>$output_file" if ($output_file); } # while loop for while (){ # convert the date field to a number for comparison. $comp_time=&date2num($_); if (/(\%SEC|\%FW)/) { &do_the_stuff } } # and for those of you who wanted it to output somewhere other than STDOUT, here is the close of your file... close OUTPUT if ($output_file); } #look at logs from the command line foreach $filename (@files) { # open each file from the list on the command line... open LOG, "<$filename"; # you actually do have a choice whether to append or destroy! (-W) if ($write_over) { open OUTPUT, ">$output_file" if ($output_file); } else { open OUTPUT, ">>$output_file" if ($output_file); } while (){ # convert the date field to a number for comparison. $comp_time=&date2num($_); if (/(\%SEC|\%FW)/) { &do_the_stuff } } # here we go again... closing the necessary files. close OUTPUT if ($output_file); close LOG; } } else { print ".o0[ $0 ]0o.\n"; print "Usage: $0 [-s ] [-e ] [-o ] filename[s]\n"; print " eg Jan 7 19:05:38"; print " -W for writing over the output file.\n"; print; print " Written by Damien Mascord\n"; } # good ole subroutine to convert the date field in the log file into something machine comparable. sub date2num { $date_time=@_[0]; my ( $month, $day, $hour, $min, $sec) = ($date_time =~/(\w+)\s+(\d+)\s+(\d{2}):(\d{2}):(\d{2})/); ## $day = "0$day" if ($day < 10 && $#day==1); $day = sprintf "%02d", $day; $date_time="$NUM_MONTH{$month}$day$hour$min$sec"; return $date_time; } # big horrible subroutine to do the processing of the conversion from log format to csv format. sub do_the_stuff { # pull out all the relavent fields my ($date1, $date2, $date3, $machine_name, $errno1, $errno2, $errno3, $error_message1, $error_message2, $error_message3, $protocol, $source, $arrow, $dest, $java_field, $extra1, $extra2, $extra3, $extra4, $extra5, $extra6 ) = split /\s+/; # check to see for icmp as the log file format is slightly different and needs modification if ($protocol=~/icmp/){ $source_ip=$source; $source_port=""; $dest_ip=$dest; $dest_port=""; # java errors put "blocked" in the same field as $protocol... # so we amend this, and make it sensible. } elsif ($protocol=~/blocked/){ $error_message3.=" $protocol"; $protocol="java"; $source=$arrow; $dest=$java_field; ($source_ip, $source_port)=( $source=~/\(([^:]+):([^\)]+)\)/); ($dest_ip, $dest_port)= ( $dest=~/\(([^:]+):([^\)]+)\)/); # and for standard tcp and udp, we have the following regex to grab the ip and port. } elsif ($protocol=~/used/){ $protocol="ftp"; $source_ip=$extra3;$source_port=""; $dest_ip=$extra6;$dest_port=""; } else { ($source_ip,$source_port)=( $source=~/([^\(]+)\(([^\)]+)\)/ ); ($dest_ip,$dest_port)=( $dest=~/([^\(]+)\(([^\)]+)\)/ ); } # create the csv record from the data pulled from the file. $csv_line="\"$date1 $date2 $date3\",\"$error_message1 $error_message2 $error_message3\",\"$protocol\",\"$source_ip\",\"$source_port\",\"$dest_ip\",\"$dest_port\"\n"; # now to do some comparisons on the numerical date field if ($end_time) { if ($comp_time >= $start_time && $comp_time <= $end_time){ if ($output_file) { print OUTPUT $csv_line; } else { print $csv_line; } } } else { if ($comp_time >= $start_time){ if ($output_file) { print OUTPUT $csv_line; } else { print $csv_line; } } } }