"Fossies" - the Fresh Open Source Software Archive 
Member "lmon-1.2/lmon.pl" (19 May 2005, 7613 Bytes) of package /linux/privat/old/lmon-1.2.tgz:
As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) Perl source code syntax highlighting (style:
standard) with prefixed line numbers and
code folding option.
Alternatively you can here
view or
download the uninterpreted source code file.
For more information about "lmon.pl" see the
Fossies "Dox" file reference documentation.
1 #! /usr/bin/perl -T
2 # LMon 1.2, anders@bsdconsulting.no, 2005-05-19
3 # External requirements: Mail::Sendmail, File::Tail.
4
5 package LMon;
6 use Fcntl;
7 use Getopt::Std;
8 use POSIX;
9 use strict;
10 use Mail::Sendmail;
11 use File::Tail;
12 use FindBin qw($Bin);
13 $ENV{PATH} = "/sbin:/bin:/usr/sbin:/usr/bin";
14 $ENV{ENV} = "";
15
16 # --configuration ---
17 $LMon::mailservers = ['smtp1.tld.com', 'smtp2.tld.com'];
18 $LMon::recipients = "user\@tld.com";
19 $LMon::from = "user\@tld.com";
20 # How many lines to read initially from log:
21 $LMon::lines = 0;
22 # How many lines to read initially from log if rotated:
23 $LMon::resetlines = -1;
24 # For lines/resetlines, 0 = only read new lines, -1 = read everything.
25 # How long to wait before checking log buffer:
26 $LMon::waitsecs = 5;
27 # How long to wait before checking log buffer after a mail is sent:
28 $LMon::waitsecsnext = 3600;
29 # Max buffer lines, set to 0 for unlimited (otherwise drop lines from the top):
30 $LMon::maxbuffer = 50;
31 # --- end configuration ---
32
33 # Copyright (c) 2005, Anders Nordby <anders@bsdconsulting.no>
34 # All rights reserved.
35 #
36 # Redistribution and use in source and binary forms, with or without
37 # modification, are permitted provided that the following conditions are met:
38 #
39 # * Redistributions of source code must retain the above copyright notice, this
40 # list of conditions and the following disclaimer.
41 #
42 # * Redistributions in binary form must reproduce the above copyright notice,
43 # this list of conditions and the following disclaimer in the documentation
44 # and/or other materials provided with the distribution.
45 #
46 # * Neither the name of BSD Consulting nor the names of its contributors may
47 # be used to endorse or promote products derived from this software without
48 # specific prior written permission.
49 #
50 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
51 # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
52 # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
53 # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
54 # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
55 # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
56 # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
57 # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
58 # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
59 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
60
61 @LMon::reglist = ();
62 @LMon::logbuffer = ();
63 $LMon::logfile = ();
64 $LMon::logbuffertruncated = 0;
65 $LMon::fnok = '([-\w\.\_]+)';
66
67 use vars qw { $opt_f $opt_p $opt_r $opt_n $opt_s $opt_i $opt_t $opt_F $opt_b $opt_m $opt_d };
68
69 # Untaint $Bin if OK
70 if ($Bin =~ /$LMon::fnok/) {
71 $Bin = $1;
72 }
73
74 sub usage {
75 print "Usage: lmon.pl -r <rule file> -f <log file> [-t <recipients>] [-p <pid file>]\n";
76 print "[-n <log name (for alerts)>] [-s <system name (for alerts)]\n";
77 print "[-i (include mode: alert on rule hits instead of misses) [-F <from mailaddress>]\n";
78 print "[-m <mail server(s)>] [-d (detach)]\n";
79 }
80 if ($#ARGV < 0) { usage; exit(0); }
81 getopts('r:f:t:p:n:s:F:b:im:d');
82 if ($opt_t) {
83 $LMon::recipients = $opt_t;
84 }
85 if ($opt_b) {
86 $LMon::maxbuffer = $opt_b;
87 }
88
89 my $line = "";
90
91 if ($opt_s) {
92 $LMon::sysname = $opt_s;
93 } else {
94 $LMon::sysname = (POSIX::uname)[1];
95 }
96 if (!$LMon::from) {
97 $LMon::from = "hostmaster\@$LMon::sysname";
98 } elsif($opt_F) {
99 $LMon::from = $opt_F;
100 }
101
102
103 if ($opt_i) {
104 $LMon::alertstr = "LMon: interesting data in";
105 } else {
106 $LMon::alertstr = "LMon: unrecognized data in";
107 }
108
109 if ($opt_m) {
110 @LMon::mailserverstxt = split(/ /, $opt_m);
111 $LMon::mailservers = \@LMon::mailserverstxt;
112 for (my $i = 0; $i <= $#LMon::mailserverstxt; $i++) {
113 if ($LMon::mailserverstxt[$i] =~ /^([\s\w\.-_]+)$/) {
114 # untaint mailserver
115 $LMon::mailserverstxt[$i] = $1;
116 } else {
117 print "Bad data $opt_m in option -m.\n";
118 exit(1);
119 }
120 }
121 $Mail::Sendmail::mailcfg{'smtp'} = \@LMon::mailserverstxt;
122 } else {
123 $Mail::Sendmail::mailcfg{'smtp'} = $LMon::mailservers;
124 }
125
126 sub errusage {
127 my $msg = $_[0];
128 print "$msg\n\n";
129 usage;
130 exit(1);
131 }
132
133 sub sender {
134 my $text = "$_[0]";
135 my $subject = "$_[1]";
136
137 for my $recipient (split /([ \s,;])/, $LMon::recipients) {
138 my %mail = ( To => "$recipient",
139 From => "$LMon::from",
140 Message => "$text",
141 Subject => "$subject"
142 );
143
144 sendmail(%mail);
145 }
146 }
147
148 sub isinteresting {
149 my $str = $_[0];
150 chomp($str);
151 my $substr;
152
153 if ($opt_i) {
154 for (my $i = 0; $i <= $#LMon::reglist; $i++) {
155 if (substr($LMon::reglist[$i], 0, 1) eq '!') {
156 $substr = substr($LMon::reglist[$i], 1);
157 if ($str !~ /$substr/) { return(1); }
158 } else {
159 if ($str =~ /$LMon::reglist[$i]/) { return(1); }
160 }
161 }
162 return(0);
163 } else {
164 for (my $i = 0; $i <= $#LMon::reglist; $i++) {
165 if (substr($LMon::reglist[$i], 0, 1) eq '!') {
166 $substr = substr($LMon::reglist[$i], 1);
167 if ($str !~ /$substr/) { return(0); }
168 } else {
169 if ($str =~ /$LMon::reglist[$i]/) { return(0); }
170 }
171 }
172 return(1);
173 }
174 }
175
176 sub sendbuffer {
177 if($LMon::logbuffertruncated != 0) {
178 unshift(@LMon::logbuffer, "\n");
179 unshift(@LMon::logbuffer, "from the top of the file.\n");
180 unshift(@LMon::logbuffer, "ERROR: Log buffer got full at $LMon::maxbuffer lines. Data has been dropped\n");
181 $LMon::logbuffertruncated = 0;
182 }
183 if ($opt_n) {
184 sender(join("", @LMon::logbuffer), "$LMon::alertstr $opt_n on $LMon::sysname");
185 } else {
186 sender(join("", @LMon::logbuffer), "$LMon::alertstr $opt_f on $LMon::sysname");
187 }
188 }
189
190 sub checkbuffer {
191 if ($#LMon::logbuffer != -1) {
192 sendbuffer;
193 @LMon::logbuffer = ();
194 alarm($LMon::waitsecsnext);
195 } else {
196 alarm($LMon::waitsecs);
197 }
198 }
199
200 sub fixpidfilename {
201 if ($opt_p =~ /^([-\w\.\/]+)$/) {
202 # untaint PID filename
203 $opt_p = $1;
204 } else {
205 print "Bad data $opt_p in option -p.\n";
206 exit(1);
207 }
208 }
209
210 sub writepid {
211 fixpidfilename;
212 if (sysopen(PID, $opt_p, O_WRONLY|O_CREAT)) {
213 print PID "$$\n";
214 } else {
215 errusage("ERROR: Could not write pid file.");
216 }
217 close(PID);
218 }
219
220 sub readconf {
221 sysopen(CONF, $opt_r, O_RDONLY);
222 @LMon::reglist = ();
223 my $line = 0;
224 while (<CONF>) {
225 my $rule = $_;
226 $line++;
227
228 next if ($rule =~ /^(#|$)/);
229 chomp($rule);
230
231 eval { if (/$rule/) {} };
232 if ($@) {
233 print STDERR "ABORT, syntax/regexp error on line $line in $opt_r.\n";
234 print STDERR "Details:\n\n";
235 print STDERR $@;
236 close(CONF);
237 exit(1);
238 }
239
240 push(@LMon::reglist, $rule);
241 }
242 close(CONF);
243 }
244
245 if (!$opt_f) {
246 errusage("ERROR: No file to monitor specified, use -f.");
247 } elsif(! -f $opt_f) {
248 errusage("ERROR: Logfile $opt_f does not exist/is not a file.");
249 }
250 if (!$opt_r) {
251 errusage("ERROR: No rule file specified, use -r.");
252 } elsif(! -f $opt_r) {
253 errusage("ERROR: Rule file $opt_r does not exist/is not a file.");
254 }
255 readconf;
256 if ($opt_d) {
257 # Detach from controlling terminal
258 exit 0 if (fork);
259 chdir($Bin);
260 close(STDERR);
261 close(STDOUT);
262 close(STDIN);
263 POSIX::setsid;
264 }
265 writepid;
266
267 $SIG{ALRM} = sub { checkbuffer; };
268 alarm($LMon::waitsecs);
269
270 #$LMon::logfile = File::Tail->new($opt_f);
271 $LMon::logfile = File::Tail->new(name=>$opt_f, maxinterval=>30, interval=>10, tail=>$LMon::lines, reset_tail=>$LMon::resetlines, errmode=>"return");
272
273 while(defined($line=$LMon::logfile->read)) {
274 if (isinteresting($line)) {
275 if (($#LMon::logbuffer+1) >= $LMon::maxbuffer && $LMon::maxbuffer != 0) {
276 if ($LMon::logbuffertruncated == 0) {
277 $LMon::logbuffertruncated = 1;
278 }
279 shift(@LMon::logbuffer);
280 push(@LMon::logbuffer, $line);
281 } else {
282 push(@LMon::logbuffer, $line);
283 }
284 }
285 }