PMG 6.1 how to add antivirus?

Hello all,

I just wanted to provide another example code to integrate F-Secure Atlant via Icap. as this utilizes the icap protocol it should be easy to adapt to any other icap-compatible anti-virus-solution.

For better understanding: "atlant" is the product name of the F-Secure Icap Service. You may want to adapt this matching to your product.

Prereqesites:
  • Installed c-icap-client on pmg (apt install c-icap)
  • Up and running icap service (either on localhost or elsewhere)
  • /etc/hosts entry having the name "atlant" pointing to your atlant-server (just in case of this example. If you run another icap system just adapt the script)
Change pmg.cfg:
In the admin-section add:
Code:
pmg.admin.custom_check = 1

Build /usr/local/bin/pmg-custom-check :
I adapted the following code from the official proxmox example I found in the documentatioin. So you may also want to look there.
As usual this code comes without any warranty. it is not the most sophisticated piece of software and also has NOT been heavily tested. Read it. Understand it. Use it on your own risk. Improve it and post your improvements here ;)

It is a bit hacky as c-icap-client is not meant to do this job and is posting it's headers to stderr. (thats why 2 ist redirected to 1 in order to capture those headers containing infection-information)

Again: USE AT OWN RISK AND GOOD LUCK :)

Bash:
#!/bin/sh

if [ "$#" -ne 2 ]; then
  echo "usage: $0 APIVERSION QUEUEFILENAME" 1>&2
  exit 1
fi

apiver="$1"
shift

if [ "$apiver" != "v1" ]; then
  echo "wrong APIVERSION: $apiver" 1>&2
  exit 2
fi

queue_file="$1"

echo "v1"

ATLANT="atlant"

result="$(c-icap-client -i "$ATLANT" -v -f "$queue_file" 2>&1 | grep -F 'X-FSecure-Infection-Name')"
infected=$?

if [ "$infected" = "1" ]; then
    echo OK
else
    echo "VIRUS: $(echo $result | awk '{ print $2 }' )"
fi

put the executable flag (chmod +x) and test test:
Code:
# /usr/local/bin/pmg-custom-check v1 testfile
v1
VIRUS: "Malware.Eicar-Test-Signature"

Code:
# /usr/local/bin/pmg-custom-check v1 /etc/hosts
v1
OK

Have fun.

Regards
Matthias
Using remote exploration ICAP service from Eset File Security for linux v8, I can handle virus detection for PMG using this code with some adjustment:

be sure to use

custom_check 1

in pmg.cfg


/usr/local/bin/pmg-custom-check
Code:
#!/bin/sh

if [ "$#" -ne 2 ]; then
  echo "usage: $0 APIVERSION QUEUEFILENAME" 1>&2
  exit 1
fi

apiver="$1"
shift

if [ "$apiver" != "v1" ]; then
  echo "wrong APIVERSION: $apiver" 1>&2
  exit 2
fi

queue_file="$1"

echo "v1"

SERVER="127.0.0.1"

result="$(c-icap-client -i "$SERVER" -v -f "$queue_file" 2>&1 | grep -F 'X-Infection-Found')"
infected=$?

if [ "$infected" = "1" ]; then
    echo OK
else
    echo "VIRUS: $(echo $result | awk -F= '{ print $4 }' )"
fi

Be sure to config "NO ACTION" at ESET File Security for ICAP THREATSENSE. PMG will take care of infected email.
 
Hello,

i am using the script also since some month and it is working fine - I THOUGHT!!!

some viruses are detected by Clam, some by eset but I noticed some viruses are passed also to the clients and the eset outlook scanner is detecting them!

How can the virus pass through the script, the detection engine between the server and the client is the same.

Catched an contaminated eml file and passing it through with SMTP Diag Tool:

Code:
Nov 23 14:38:01 mx02 root[568811]: DEBUG:
Nov 23 14:38:01 mx02 root[568811]: DEBUG:ECLS Command-line scanner, version 1.1.1.0, Copyright © 1992-2021 ESET, spol. s r. o. All rights reserved.
Nov 23 14:38:01 mx02 root[568811]: DEBUG:Module loader, version 1077 (20200622), build 1140
Nov 23 14:38:01 mx02 root[568811]: DEBUG:Module perseus, version 1581.3 (20211015), build 2251
Nov 23 14:38:01 mx02 root[568811]: DEBUG:Module scanner, version 24338 (20211123), build 51592
Nov 23 14:38:01 mx02 root[568811]: DEBUG:Module archiver, version 1324 (20211011), build 1394
Nov 23 14:38:01 mx02 root[568811]: DEBUG:Module advheur, version 1211.1 (20211105), build 1215
Nov 23 14:38:01 mx02 root[568811]: DEBUG:
Nov 23 14:38:01 mx02 root[568811]: DEBUG:Command line: --base-dir=/var/opt/eset/efs/lib --clean-mode=none /var/spool/pmg/active/2A184C619CEEB336470
Nov 23 14:38:01 mx02 root[568811]: DEBUG:
Nov 23 14:38:01 mx02 root[568811]: DEBUG:Scan started at:   Tue Nov 23 14:38:00 2021
Nov 23 14:38:01 mx02 root[568811]: DEBUG:
Nov 23 14:38:01 mx02 root[568811]: DEBUG:Scan completed at: Tue Nov 23 14:38:01 2021
Nov 23 14:38:01 mx02 root[568811]: DEBUG:Scan time:         1 sec (0:00:01)
Nov 23 14:38:01 mx02 root[568811]: DEBUG:Total:             files - 1, objects 10
Nov 23 14:38:01 mx02 root[568811]: DEBUG:Detected:          files - 0, objects 0
Nov 23 14:38:01 mx02 root[568811]: DEBUG:Cleaned:           files - 0, objects 0
Nov 23 14:38:01 mx02 root[568811]: DEBUG:
Nov 23 14:38:01 mx02 root[568811]: pmg-custom-check OK /var/spool/pmg/active/2A18xxxxxxxxx6470

File comes to my outlook - my eset endpoint security immediately detects this virus.

Code:
root@mx01:~# /opt/eset/efs/sbin/cls/cls -v
/opt/eset/efs/sbin/cls/cls 1.1.1.0
root@mx01:~#

my pmg custom checks:
Code:
#!/usr/bin/perl -w
use strict;
use warnings;
use Data::Dumper qw(Dumper);
use File::Copy "cp";

my $av_name    = "Eset";
my $av_version = "0.0";

## V4.X
my $esets_bin = "/opt/eset/esets/sbin/esets_scan";
my $esets_arg = "--clean-mode=none";

## V7.X
my $efs_bin  = "/opt/eset/efs/sbin/cls/cls";
my $efs_arg  = "--clean-mode=none";
my $efs_bdir = "--base-dir=/var/opt/eset/efs/lib";


## logger to /var/log/syslog
my $logger_bin = "/usr/bin/logger";
my $logger_arg = "-i";

## debug files under ...
my $debug     = 1;
my $debug_dir = "/tmp/debug/";

## block passwd-protected / damaged archive ?
my $strict = 0;
mkdir $debug_dir;
my $cmd;

open( my $logger, "| $logger_bin $logger_arg " );

$av_version = "4.X" if ( -e $esets_bin );
$av_version = "7.X" if ( -e $efs_bin );

my $apiversion = shift || die 'APIVERSION required.';
my $filename   = shift || die 'QUEUEFILENAME required.';

die "Wrong AV Version."   if ( $av_version eq "0.0" );
die "Wrong API Version."  if ( $apiversion ne "v1" );
die "FILENAME not found." if ( !-e $filename );
if ( $av_version eq "4.X" ) { open( $cmd, '-|', $esets_bin, $esets_arg, $filename ) || die "can't exec esets scan: $! : ERROR"; }
if ( $av_version eq "7.X" ) { open( $cmd, '-|', $efs_bin, $efs_bdir, $efs_arg, $filename ) || die "can't exec esets scan: $! : ERROR"; }

my $vinfo = "OK";

while ( defined( my $line = <$cmd> ) ) {
    chomp $line;

    print $logger "DEBUG:" . $line, "\n" if ( $debug > 0 );
    $line =~ s/result=/threat=/g if ( $av_version eq "7.X" );
    if ( $line =~ m/^name=\"(.*)\".*threat=\"(.*)\".*action=\"(.*)\".*info=\"(.*)\"$/ ) {
        next if ( ( $strict < 1 ) && ( $4 =~ m/password-protected/g || $4 =~ m/archive damaged/g ) );
        $vinfo = "VIRUS: " . $2 . " " . $4 . "($av_name)";
        next if $2;

        print $logger "DEBUG: " . $vinfo, "\n" if ( $debug > 0 );
    }
}
cp( $filename, $debug_dir )
  if ( $vinfo ne "OK" && not -e $debug_dir . $filename && $debug > 1 );
print join( "\n", "v1", $vinfo );
print $logger join( " ", "pmg-custom-check", $vinfo, $filename ) . "\n" if ( $debug > 0 );
close($logger);
exit 0;

I have no idea what is wrong

Thx

Dirk


edit:

a manual scan of the eml file:

Code:
root@mx01:/tmp/debug# /opt/eset/efs/sbin/cls/cls --clean-mode=none /tmp/C0Rxxxxxxx925.eml

ECLS Command-line scanner, version 1.1.1.0, Copyright © 1992-2021 ESET, spol. s r. o. All rights reserved.
Module loader, version 1077 (20200622), build 1140
Module perseus, version 1581.3 (20211015), build 2251
Module scanner, version 24339 (20211123), build 51594
Module archiver, version 1324 (20211011), build 1394
Module advheur, version 1211.2 (20211118), build 1218

Command line: --clean-mode=none /tmp/C0R84301T61018925.eml

Scan started at:   Tue Nov 23 14:52:51 2021
name="/tmp/C0R84301T61018925.eml", result="a variant of Generik.DCZCEEP trojan", action="retained", info=""
name="/tmp/C0R84301T61018925.eml >> MIME >> Arrival Notice, CIA Awb Inv Form.pdf.img", result="a variant of Generik.DCZCEEP trojan", action="retained", info=""
name="/tmp/C0R84301T61018925.eml >> MIME >> Arrival Notice, CIA Awb Inv Form.pdf.img >> ISO >> Arrival Notice, CIA Awb Inv Form.pdf.exe", result="a variant of Generik.DCZCEEP trojan", action="retained", info=""

Scan completed at: Tue Nov 23 14:52:51 2021
Scan time:         0 sec (0:00:00)
Total:             files - 1, objects 6
Detected:          files - 1, objects 1
Cleaned:           files - 0, objects 0

root@mx01:/tmp/debug#
solved ? or do you still need help?
 
Hello everyone!
I noticed a bug in Eset cls behavior. This application does not check nested archives (for example: 7z -> 7z -> infected.exe), gives error "error reading archive". Is it possible to add in custom perl script an extra condition to check and unpack archives before scanning? Of course, we need nesting limit (e.g. up to 5 archives) to avoid zip bombs. How to do this write in perl? Thanks!

P.S
I also sent a report to ESET spol. s r.o. about this problem. Considering that cls has not been updated since 2020, I have doubts that this will be fixed
 
Last edited:
Using remote exploration ICAP service from Eset File Security for linux v8, I can handle virus detection for PMG using this code with some adjustment:

be sure to use

custom_check 1

in pmg.cfg


/usr/local/bin/pmg-custom-check
Code:
#!/bin/sh

if [ "$#" -ne 2 ]; then
  echo "usage: $0 APIVERSION QUEUEFILENAME" 1>&2
  exit 1
fi

apiver="$1"
shift

if [ "$apiver" != "v1" ]; then
  echo "wrong APIVERSION: $apiver" 1>&2
  exit 2
fi

queue_file="$1"

echo "v1"

SERVER="127.0.0.1"

result="$(c-icap-client -i "$SERVER" -v -f "$queue_file" 2>&1 | grep -F 'X-Infection-Found')"
infected=$?

if [ "$infected" = "1" ]; then
    echo OK
else
    echo "VIRUS: $(echo $result | awk -F= '{ print $4 }' )"
fi

Be sure to config "NO ACTION" at ESET File Security for ICAP THREATSENSE. PMG will take care of infected email.

Could be good to include into installing tutorials at forum.
It's a good starting point, most of linux antivirus suports ICAP
 
  • Like
Reactions: zolthar
Hello everyone!
I noticed a bug in Eset cls behavior. This application does not check nested archives (for example: 7z -> 7z -> infected.exe), gives error "error reading archive". Is it possible to add in custom perl script an extra condition to check and unpack archives before scanning? Of course, we need nesting limit (e.g. up to 5 archives) to avoid zip bombs. How to do this write in perl? Thanks!

P.S
I also sent a report to ESET spol. s r.o. about this problem. Considering that cls has not been updated since 2020, I have doubts that this will be fixed
UPD
Eset acknowledged the problem.This error occurs in nested archives with BCJ compression.
They promise to fix the issue in ~ middle of the March 2022.
I can attach a correspondence with the eset support if anyone is interested
 
Last edited:
I'm new to Mail Gateway.
I've installed and running v 7.1.3 (as Proxmox VM) and I would like to ad additional Antivirus scanners.
On the previous mail server I'm using ClamAV, Dr. Web and Sophos (that for Linux was announced EOL) integrated by MailScanner .
I've searched for Avast built-in script inside the filesystem with no luck.
Does there is an updated custom check script somewhere to use a good start to integrate additional virus scanners on version 7.1 ?

Thank you.
 

About

The Proxmox community has been around for many years and offers help and support for Proxmox VE, Proxmox Backup Server, and Proxmox Mail Gateway.
We think our community is one of the best thanks to people like you!

Get your subscription!

The Proxmox team works very hard to make sure you are running the best software and getting stable updates and security enhancements, as well as quick enterprise support. Tens of thousands of happy customers have a Proxmox subscription. Get yours easily in our online shop.

Buy now!