perl - How do I print a computed score for all input in a file? -
here perl code takes 2 files input. files contain tcp packets. trains normal packets using packets in first file , prints anomalous packets in second file.
while (<>) { if (($time, $to, $port, $from, $duration, $flags, $length, $text) = /(.{19}) (.{15}):(\d+) (.{15}):\d+ \+(\d+) (\s+) (\d+) (.*)/) { $text =~ s/\^m//g; $text =~ s/\^ /\n/g; if (($port == 25 || $port == 80) && $text =~ /\n\n/) {$text = "$`\n";} $text =~ s/^\^@//; if ($time =~ /(\d\d)\/(\d\d)\/\d\d\d\d (\d\d):(\d\d):(\d\d)/) { $now = ((($1 * 31 + $2) * 24 + $3) * 60 + $4) * 60 + $5; } foreach ($text =~ /.*\n/g) { if (($k, $v) = /(\s*)(.*)/) { $k = substr($k, 0, 30); $v = substr($v, 0, 100); $score = 0; $comment = ""; &alarm($port, $k); &alarm($to, $flags); &alarm("to", "$to:$port"); &alarm($to, $from); &alarm("$to:$port", $from); if ($score > 30000) { $score = log($score) / (10 * log(10)); printf(" # 0 $time $to %8.6f \#%s\n", $score, substr($comment, 0, 300)); } } } } } sub alarm { local ($key, $val, $sc) = @_; if ($now < 10300000) { ++$n{$key}; if (++$v{$key . $val} == 1) { ++$r{$key}; $t{$key} = $now; } } elsif ($n{$key} > 0 && !$v{$key . $val}) { $score += ($now - $t{$key}) * $n{$key} / $r{$key}; $comment .= " $key=$val"; $t{$key} = $now; } } exit;
i new perl , small part project needs anomaly score printed packets in second file. can tell how modify code?
from can see here, looks if code (as now) looks packets before cutoff time, , stores whether or not has seen conditions in %n
, %v
hashes.
why not give flag alarm
function called $training
. if true, account packet values, otherwise, calculate score anomaly (if one), , return value. if there no anomaly, or if you're in training mode, return zero:
sub alarm { ($key, $val, $training) = @_; $score = 0; if ( $training ) { ...do accounting... } else { ...do comparisons & set score accordingly... } return $score; }
throw big while
subroutine, , have subroutine take filename , whether in training mode or not.
sub examine { ($file, $training) = @_; if ( open $fh, '<', $file ) { while (<$fh>) { ...this big while loop... ...pass $training along alarm() calls... } } else { die "failed open $file: $!\n'; } }
your main program now:
use constant training => 1; examine('file1', training); examine('file2', !training);
more notes:
- use
my()
instead oflocal
, though doesn't materially affect program, it's habit into. - don't use known function name
alarm
when isn't doing of kind, instead namecheck_packet_values
-- or makes sense , team. stop using magic numbers
use constant { cutoff_time => 10300000, anomaly_score => 30000 };
use real date/time parser values have meaning.
str2time
date::parse
give time in epoch seconds (seconds since jan 1, 1970).- use variable names mean something.
%n
,%v
hard understand in code,%n_seen
,%value_seen
(as%first_seen_time
instead of%t
). remember, code doesn't run faster if use shorter variable names. stop using global variables when feasible. counters can global, comment should built in routine initializing , printing comment. so, instead of doing doing, how about:
$to_score = check_packet_value($to, $flags) , push @comments, "$to=$flags"; ... $score = $to_score + $from_score + ... if ( !$training && $score > anomaly_threshold ) { print "blah blah blah @comments\n"; }
also, never, ever use $` -- causes huge performance penalties in entire script (even if never calls function). instead of:
if ( $text =~ /\n\n/ ) { $text = $` }
use
if ( $text =~ /(.*)\n\n/ ) { $text = $1; }
(edit: added warning $`)
Comments
Post a Comment