[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