[Mimedefang] Possible NAI uvscan enhancement
Josh Kelley
josh at jbc.edu
Wed Jan 7 13:34:12 EST 2004
While playing around with uvscan, I found that if you give it
command-line options of "-f -", it accepts a list of files or directory
to be scanned as input. A mimedefang.pl process can use this to keep
one copy of uvscan running and give uvscan its working directory as
input whenever it has a message to be scanned. This should speed up
virus scanning by a fair bit, since MIMEDefang would no longer have to
start a new copy of uvscan for every message received. (In a test from
the command line, scanning a 284kB test directory with a pre-spawned
copy of uvscan was about twice as fast as starting a new copy of uvscan
just to scan the directory.)
I wrote this up using Perl's Expect module, which handles the details of
bidirectional communication with a child. Here's the routine to
initialize the Expect object and the uvscan child:
sub initialize_nai_expect() {
$NAIExpect = new Expect;
$NAIExpect->raw_pty(1);
if (!$NAIExpect->spawn($Features{'Virus:NAI'} . " --noboot --secure
--allole -f - 2>&1")) {
# Expect failed. Give up on it and stick with the conventional
# method of running uvscan (which will probably fail too, but it
# has better error handling).
$Features{'Expect'} = 0;
undef $NAIExpect;
md_syslog('err', "$MsgID: Failed to initialize Expect with NAI
Virus Scan");
return;
}
$NAIExpect->log_stdout(0);
}
And here's a replacement for run_virus_scanner in
message_contains_virus_nai and entity_contains_virus_nai:
sub item_contains_virus_nai_expect($) {
my($path) = @_;
my($msg);
$NAIExpect->send("$path\nCHECKPOINT\n");
$NAIExpect->expect(undef, '-re', "No file or directory found
matching .*/CHECKPOINT\n");
foreach (split(/\n/, $NAIExpect->before)) {
$msg .= "$_\n" if /^\s+Found/;
}
$VirusScannerMessages .= $msg;
$CurrentVirusScannerMessage = $msg;
# If NAI child died, return that error code, and discard current Expect
if (defined($NAIExpect->exitstatus())) {
my($retcode) = $NAIExpect->exitstatus();
undef $NAIExpect;
return ($retcode, 'ok', 'proceed');
# Otherwise, fake a return code. uvscan returns 0 on clean, 13 on virus
} else {
my($retcode) = $CurrentVirusScannerMessage ? 13 : 0;
return ($retcode, 'ok', 'proceed');
}
}
I can provide a full patch if anyone's interested.
These modifications seem to work on my test server. MIMEDefang still
catches Eicar, and it still accepts legitimate mail, and I can confirm
that each used mimedefang.pl slave has a uvscan child. I don't know of
a way to test how much this actually helps the speed of mail delivery.
Am I missing anything?
Josh Kelley
More information about the MIMEDefang
mailing list