1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185
|
#!/usr/bin/perl
########################################################
# Please file all bug reports, patches, and feature
# requests under:
# https://sourceforge.net/p/logwatch/_list/tickets
# Help requests and discusion can be filed under:
# https://sourceforge.net/p/logwatch/discussion/
########################################################
##########################################################################
#
# Logwatch service for snort log
#
# Processes all messages and summarizes them
# Each message is given with a timestamp and RMS
#
########################################################
# (C) 2023 by MigOps Inc - https://www.migops.com/
# written by Gilles Darold.
#
########################################################
## Covered under the included MIT/X-Consortium License:
## http://www.opensource.org/licenses/mit-license.php
## All modifications and contributions by other persons to
## this script are assumed to have been donated to the
## Logwatch project and thus assume the above copyright
## and licensing terms. If you want to make contributions
## under your own copyright or a different license this
## must be explicitly stated in the contribution and the
## Logwatch project reserves the right to not accept such
## contributions. If you have made significant
## contributions to this script and want to claim
## copyright please contact logwatch-devel@lists.sourceforge.net.
########################################################
use strict;
use Logwatch ':dates';
use Time::Local;
use POSIX qw(strftime);
# Allow timestamp from two different logfile format: syslog and stderr
my $date_format1 = '%m/%d-%H:%M:%S';
my $filter1 = TimeFilter($date_format1);
# Allow summarization of WARNING and HINT too if wanted
my $detail = exists $ENV{'LOGWATCH_DETAIL_LEVEL'} ? $ENV{'LOGWATCH_DETAIL_LEVEL'} : 0;
# Used to replace the month trigram into the syslog timestamp
my %month2num = ( Jan => 0, Feb => 1, Mar => 2, Apr => 3,
May => 4, Jun => 5, Jul => 6, Aug => 7,
Sep => 8, Oct => 9, Nov => 10, Dec => 11 );
# Array of the relevant lines in the log file.
# First element: type of event
# Second element: matching regexp ($1 should contain the message)
# Third element: anonymous hash ref (stores message counts)
my @message_categories = (
['Priority 5', qr/\[\*\*\] \[\d+:\d+:\d+\] (.*?) \[\*\*\](?: \[(Classification: [^\]]+)\])? \[Priority: 5\] (?:\{([^\}]+)\})?/o, {}],
['Priority 4', qr/\[\*\*\] \[\d+:\d+:\d+\] (.*?) \[\*\*\](?: \[(Classification: [^\]]+)\])? \[Priority: 4\] (?:\{([^\}]+)\})?/o, {}],
['Priority 3', qr/\[\*\*\] \[\d+:\d+:\d+\] (.*?) \[\*\*\](?: \[(Classification: [^\]]+)\])? \[Priority: 3\] (?:\{([^\}]+)\})?/o, {}],
);
if ($detail)
{
# Add more log information
push(@message_categories,
['Priority 2', qr/\[\*\*\] \[\d+:\d+:\d+\] (.*?) \[\*\*\](?: \[(Classification: [^\]]+)\])? \[Priority: 2\] (?:\{([^\}]+)\})?/o, {}],
);
if ($detail > 5)
{
push(@message_categories,
['Priority 1', qr/\[\*\*\] \[\d+:\d+:\d+\] (.*?) \[\*\*\](?: \[(Classification: [^\]]+)\])? \[Priority: 1\] (?:\{([^\}]+)\})?/o, {}],
);
}
}
# Set the current year as syslog don't have this information.
my $cur_year = (localtime(time))[5];
# Parse messages from stdin
while (my $line = <>)
{
# skipping messages that are not within the requested range
next unless $line =~ /^($filter1)/o;
my $datetime = $1;
my $time = '';
# Date/time format differ following the log_destination (stderr or syslog)
if ($datetime =~ /(\d{2})\/(\d{2})-(\d+):(\d+):(\d+)/) {
$time = timelocal($5, $4, $3, $2, $1-1, $cur_year);
}
foreach my $cur_cat (@message_categories)
{
if ($line =~ /$cur_cat->[1]/)
{
my $msgs = $cur_cat->[2];
my $rule = $1;
my $class = $2;
my $priority = $3;
my $key = "$rule" || $priority;
$key .= ", $priority" if ($priority && $rule);
$msgs->{$key} = {
count => '0',
first_occurrence => $time,
sum => 0,
sqrsum => 0
} unless exists $msgs->{$key};
$msgs->{$key}->{'count'}++;
# summing up timestamps and squares of timestamps
# in order to calculate the rms
# using first occurrence of message as offset in calculation to
# prevent an integer overflow
$msgs->{$key}->{'sum'} += $time - $msgs->{$key}->{'first_occurrence'};
$msgs->{$key}->{'sqrsum'} += ($time - $msgs->{$key}->{'first_occurrence'}) ** 2;
last;
}
}
}
# generating summary
foreach my $cur_cat (@message_categories)
{
# skipping non-requested message types
next unless keys %{$cur_cat->[2]};
my ($name, undef, $msgs) = @{$cur_cat};
print $name, ":\n";
print '-' x (length($name)+1), "\n";
my $last_count = 0;
# sorting messages by count
my @sorted_msgs = sort { $msgs->{$b}->{'count'} <=> $msgs->{$a}->{'count'} } keys %{$msgs};
foreach my $msg (@sorted_msgs)
{
# grouping messages by number of occurrence
print "\n", $msgs->{$msg}->{'count'}, " times:\n" unless $last_count == $msgs->{$msg}->{'count'};
my $rms = 0;
# printing timestamp
print '[';
if($msgs->{$msg}->{'count'} > 1) {
# calculating rms
$rms = int(sqrt(
($msgs->{$msg}->{'count'} *
$msgs->{$msg}->{'sqrsum'} -
$msgs->{$msg}->{'sum'}) /
($msgs->{$msg}->{'count'} *
($msgs->{$msg}->{'count'} - 1))));
print strftime($date_format1, localtime($msgs->{$msg}->{'first_occurrence'}+int($rms/2)));
print ' +/-';
# printing rms
if($rms > 86400) {
print int($rms/86400) , ' day(s)';
} elsif($rms > 3600) {
print int($rms/3600) , ' hour(s)';
} elsif($rms > 60) {
print int($rms/60) , ' minute(s)';
} else {
print $rms, ' seconds';
}
}
else
{
# we have got this message a single time
print strftime($date_format1, localtime($msgs->{$msg}->{'first_occurrence'}));
}
print '] ', $msg, "\n";
$last_count = $msgs->{$msg}->{'count'};
}
print "\n";
}
|