Sunday, August 13, 2006

Perl Script that Alerts on Clam Anti-Virus Errors

One of the reasons I like Perl so much is CPAN, and how easy it makes writing scripts for system administration. One of my clients uses Clam AV to screen incoming mail for viruses. The updater, called 'freshclam', runs periodically and updates the virus definitions database, and also checks to see that the installed version of Clam AV is not out-of-date with respect to the database. If it is, the freshclam log file fills with messages that start like this:

ClamAV update process started at Sat May 6 04:02:09 2006
WARNING: Your ClamAV installation is OUTDATED!
WARNING: Local version: 0.88 Recommended version: 0.88.2

It turns out the messages also get returned by the Clam AV daemon when it is scanning mail. This isn't usually a big deal, but in this case, the client was using a home-grown mail system that died if the Clam AV daemon returned this error while scanning mail. As a temporary workaround (until the MTA could be fixed), to alert me whenever this happened, I put the following Perl script together and had it tested and installed within an hour. When run from the command line, it automatically daemonizes itself and scans the freshclam logfile for the above message. If found, it sends an email alert (most cell phones have an email-to-SMS gateway address, which is what I use to get text alerts sent to my cell phone). It does not need to be run as root (and shouldn't), it only needs enough permission to read the freshclam log file.

You will need to edit the variables 'logfile' and 'recipient' at the top of the script, and you probably want to add it to your target system's startup sequence. You can download it here:

Perl script to check for and alert on freshclam errors

It's worth mentioning that there are quite a few projects that handle parsing of logfiles for certain patterns (logcheck and swatch come to mind), but they are very general, and in this case I felt a targeted solution was preferable (and faster to implement).

#!/usr/bin/perl -wT # # $Id:,v 1.3 2006/08/13 17:19:42 dmaxwell Exp $ # # Parses the freshclam updater log, looking for messages like this # one: # # -------------------------------------- # ClamAV update process started at Sat May 6 04:02:09 2006 # WARNING: Your ClamAV installation is OUTDATED! # WARNING: Local version: 0.88 Recommended version: 0.88.2 # -------------------------------------- # # If found, it sends an alert via email. # # Copyright (c) 2006, Doug Maxwell # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 # USA # use strict; use File::Tail; use Mail::Mailer; use Proc::Daemon; use Unix::Syslog qw(:subs); use Unix::Syslog qw(:macros); # Fork Proc::Daemon::Init; # Clean up our environment for taint mode delete @ENV{qw(IFS CDPATH ENV BASH_ENV)}; $ENV{PATH} = "/bin:/usr/bin"; # The logfile we are monitoring my $logfile = "/var/log/clamav/freshclam.log"; # The regex we will test against each new line my $pattern = qr/Recommended version:/o; # Where to send alerts my $recipient = ''; my $file = File::Tail->new(name=>$logfile, maxinterval=>120, adjustafter=>3) or die; while (defined(my $line = $file->read)) { send_alert($recipient,$line) if ($line =~ /$pattern/); } sub send_alert { my ($recipient,$body) = @_; my $from = ''; my $subject = "Clam AV is outdated!"; my $mailer = Mail::Mailer->new("sendmail"); $mailer->open({ From => $from, To => $recipient, Subject => $subject, }) or log_error($!); print $mailer $body or log_error($!); $mailer->close( ); return; } sub log_error { my $text = shift; openlog ("", LOG_PERROR|LOG_CONS , LOG_LOCAL7); syslog (LOG_INFO, "$text"); closelog(); return; }
Technorati tags: , ,

No comments: