ClamAV with Rspamd and ISPConfig on Ubuntu

Howto setup ClamAV as antivirus mailfilter for Rspamd and Monit monitoring.

Versions used for this tutorial: Ubuntu 20.04, ISPConfig 3.2.7p1, Rspamd 3.1, Dovecot 3.2.7.2, ClamAV 0.103.2, Monit 5.26.0.

Rspamd

Set permissions

The permission of the _rspamd user is required for the clamav group, otherwise Rspamd can’t connect to ClamAV over Unix socket

usermod -a -G clamav _rspamd
chown -R clamav:clamav /var/run/clamav

If the permissions are not set the following error occurs:

CLAM_VIRUS_FAIL (0) [failed to scan and retransmits exceed]

ClamAV

vi /etc/clamav/clamd.conf
PidFile /var/run/clamav/clamd.pid
LocalSocket /var/run/clamav/clamd.ctl
TCPSocket 3310
TCPAddr localhost

# https://betatim.github.io/posts/clamav-memory-usage/
ConcurrentDatabaseReload no

Check configfile

egrep -v '(^.*#|^$)' /etc/clamav/clamd.conf
PidFile /var/run/clamav/clamd.pid
LocalSocket /var/run/clamav/clamd.ctl
TCPSocket 3310
TCPAddr localhost
ConcurrentDatabaseReload no
Debug false
FixStaleSocket true
LocalSocketGroup clamav
LocalSocketMode 666
User clamav
ScanMail true
ScanArchive true
DatabaseDirectory /var/lib/clamav
LogFile /var/log/clamav/clamav.log
.
.
.

Restart ClamAV

Can take about 20 seconds to restart until all signatures are loaded.

service clamav-daemon restart

ClamAV logfile

tail -f /var/log/clamav/clamav.log
Wed Dec  8 14:58:29 2021 -> --- Stopped at Wed Dec  8 14:58:29 2021
Wed Dec  8 14:58:29 2021 -> +++ Started at Wed Dec  8 14:58:29 2021
Wed Dec  8 14:58:29 2021 -> Received 0 file descriptor(s) from systemd.
Wed Dec  8 14:58:29 2021 -> clamd daemon 0.103.2 (OS: linux-gnu, ARCH: x86_64, CPU: x86_64)
Wed Dec  8 14:58:29 2021 -> Log file size limited to 4294967295 bytes.
Wed Dec  8 14:58:29 2021 -> Reading databases from /var/lib/clamav
Wed Dec  8 14:58:29 2021 -> Not loading PUA signatures.
Wed Dec  8 14:58:29 2021 -> Bytecode: Security mode set to "TrustSigned".
Wed Dec  8 14:58:48 2021 -> Loaded 8581819 signatures.
Wed Dec  8 14:58:53 2021 -> TCP: Bound to [127.0.0.1]:3310
Wed Dec  8 14:58:53 2021 -> TCP: Setting connection queue length to 15
Wed Dec  8 14:58:53 2021 -> LOCAL: Unix socket file /var/run/clamav/clamd.ctl
Wed Dec  8 14:58:53 2021 -> LOCAL: Setting connection queue length to 15
Wed Dec  8 14:58:53 2021 -> Limits: Global time limit set to 120000 milliseconds.
Wed Dec  8 14:58:53 2021 -> Limits: Global size limit set to 104857600 bytes.
Wed Dec  8 14:58:53 2021 -> Limits: File size limit set to 26214400 bytes.
Wed Dec  8 14:58:53 2021 -> Limits: Recursion level limit set to 16.
Wed Dec  8 14:58:53 2021 -> Limits: Files limit set to 10000.
Wed Dec  8 14:58:53 2021 -> Limits: MaxEmbeddedPE limit set to 10485760 bytes.
Wed Dec  8 14:58:53 2021 -> Limits: MaxHTMLNormalize limit set to 10485760 bytes.
Wed Dec  8 14:58:53 2021 -> Limits: MaxHTMLNoTags limit set to 2097152 bytes.
Wed Dec  8 14:58:53 2021 -> Limits: MaxScriptNormalize limit set to 5242880 bytes.
Wed Dec  8 14:58:53 2021 -> Limits: MaxZipTypeRcg limit set to 1048576 bytes.
Wed Dec  8 14:58:53 2021 -> Limits: MaxPartitions limit set to 50.
Wed Dec  8 14:58:53 2021 -> Limits: MaxIconsPE limit set to 100.
Wed Dec  8 14:58:53 2021 -> Limits: MaxRecHWP3 limit set to 16.
Wed Dec  8 14:58:53 2021 -> Limits: PCREMatchLimit limit set to 10000.
Wed Dec  8 14:58:53 2021 -> Limits: PCRERecMatchLimit limit set to 5000.
Wed Dec  8 14:58:53 2021 -> Limits: PCREMaxFileSize limit set to 26214400.
Wed Dec  8 14:58:53 2021 -> Archive support enabled.
Wed Dec  8 14:58:53 2021 -> AlertExceedsMax heuristic detection disabled.
Wed Dec  8 14:58:53 2021 -> Heuristic alerts enabled.
Wed Dec  8 14:58:53 2021 -> Portable Executable support enabled.
Wed Dec  8 14:58:53 2021 -> ELF support enabled.
Wed Dec  8 14:58:53 2021 -> Mail files support enabled.
Wed Dec  8 14:58:53 2021 -> OLE2 support enabled.
Wed Dec  8 14:58:53 2021 -> PDF support enabled.
Wed Dec  8 14:58:53 2021 -> SWF support enabled.
Wed Dec  8 14:58:53 2021 -> HTML support enabled.
Wed Dec  8 14:58:53 2021 -> XMLDOCS support enabled.
Wed Dec  8 14:58:53 2021 -> HWP3 support enabled.
Wed Dec  8 14:58:53 2021 -> Self checking every 3600 seconds.

Ports needed for ClamAV and Rspamd

egrep "3310/tcp|1133./tcp" /etc/services
clamd              3310/tcp
rspamd-proxy       11332/tcp
rspamd-worker      11333/tcp
rspamd-controller  11334/tcp
rspamd-fuzzy       11335/tcp

Ports listening

netstat -unplet|egrep "rspamd|clamd"
tcp    0    0 127.0.0.1:3310     0.0.0.0:*    LISTEN    116    25296614    3832209/clamd
tcp    0    0 127.0.0.1:11332    0.0.0.0:*    LISTEN    121    24594822    3792817/rspamd: mai
tcp    0    0 127.0.0.1:11333    0.0.0.0:*    LISTEN    121    24594832    3792817/rspamd: mai
tcp    0    0 127.0.0.1:11334    0.0.0.0:*    LISTEN    121    24594827    3792817/rspamd: mai

Monit

ClamAV should be monitored by Monit and restarted if it crashes just because there is not enough memory available for ClamAV. If this is the case, an oom-kill („Out of memory“) is logged in the syslog file.

grep clamav /var/log/syslog | grep kernel | grep oom-kill
Dec 02 19:41:27 ispconfig-server kernel: [1067957.981524] oom-kill:constraint=CONSTRAINT_NONE,nodemask=(null),cpuset=/,mems_allowed=0,global_oom,task_memcg=/system.slice/clamav-daemon.service,task=clamd,pid=1598671,uid=116

Create configfile

vi /etc/monit/conf-available/clamd
check process clamd with pidfile /var/run/clamav/clamd.pid
  group virus
  start program = "/etc/init.d/clamav-daemon start"
  stop program = "/etc/init.d/clamav-daemon stop"
  if failed unixsocket /var/run/clamav/clamd.ctl then restart
  if 5 restarts within 5 cycles then timeout

Enable monitoring for ClamAV daemon

ln -s /etc/monit/conf-available/clamd /etc/monit/conf-enabled/

Check control file syntax

monit -t
Control file syntax OK

Restart Monit

service monit restart

Monit logfile

tail -f /var/log/monit.log
[CET Dec 12 21:46:34] info     : Monit daemon with pid [1598641] stopped
[CET Dec 12 21:46:34] info     : 'ispconfig.server.xx' Monit 5.26.0 stopped
[CET Dec 12 21:46:34] info     : Starting Monit 5.26.0 daemon with http interface at [localhost]:2812
[CET Dec 12 21:46:34] info     : 'ispconfig.server.xx' Monit 5.26.0 started

Monit ist now configured for ClamAV and will restart the daemon automatically if it is not running anymore.

Monit summary

monit summary
Monit 5.26.0 uptime: 4m
┌─────────────────────────────────┬────────────────────────────┬───────────────┐
│ Service Name                    │ Status                     │ Type          │
├─────────────────────────────────┼────────────────────────────┼───────────────┤
│ clamd                           │ OK                         │ Process       │
├─────────────────────────────────┼────────────────────────────┼───────────────┤

Monit status

monit status
Process 'clamd'
  status                       OK
  monitoring status            Monitored
  monitoring mode              active
  on reboot                    start
  pid                          1610658
  parent pid                   1
  uid                          116
  effective uid                116
  gid                          124
  uptime                       3h 12m
  threads                      2
  children                     0
  cpu                          0.0%
  cpu total                    0.0%
  memory                       30.8% [1.2 GB]
  memory total                 30.8% [1.2 GB]
  security attribute           unconfined
  disk read                    0 B/s [619.0 MB total]
  disk write                   0 B/s [584 kB total]
  unix socket response time    0.102 ms to /var/run/clamav/clamd.ctl type TCP protocol DEFAULT
  data collected               Sun, 05 Dec 2021 22:56:21

Rspamd antivirus configuration for ClamAV

vi /etc/rspamd/local.d/antivirus.conf
servers = "127.0.0.1:3310";
#servers = "/var/run/clamav/clamd.ctl";

Restart Rspamd

service rspamd restart

Rspamd Logfile

tail -f /var/log/rspamd/rspamd.log | grep clamav
2021-12-08 15:21:58 #3838455(main) <whndhf>; lua; antivirus.lua:185: added antivirus engine clamav -> CLAM_VIRUS

ISPConfig

vi /usr/local/ispconfig/server/conf-custom/install/rspamd_antivirus.conf.master
#######################################################################################
# ISPConfig:
# vi /usr/local/ispconfig/server/conf-custom/install/rspamd_antivirus.conf.master
# ispconfig_update.sh --force
#######################################################################################

clamav {
    # If set force this action if any virus is found (default unset: no action is forced)
    action = "reject";

    # Scan mime_parts separately - otherwise the complete mail will be transferred to AV Scanner
    scan_mime_parts = true;

    # Scanning Text is suitable for some av scanner databases (e.g. Sanesecurity)
    scan_text_mime = true;
    scan_image_mime = true;

    # If `max_size` is set, messages > n bytes in size are not scanned
    #max_size = 20000000;

    # symbol to add (add it to metric if you want non-zero weight)
    symbol = "CLAM_VIRUS";

    # type of scanner: "clamav", "fprot", "sophos" or "savapi"
    type = "clamav";

    # For "savapi" you must also specify the following variable
    #product_id = 12345;

    # You can enable logging for clean messages
    log_clean = true;

    # servers to query (if port is unspecified, scanner-specific default is used)
    # can be specified multiple times to pool servers
    # can be set to a path to a unix socket
    # Enable this in local.d/antivirus.conf
    servers = "127.0.0.1:3310";
    #servers = "/var/run/clamav/clamd.ctl";

    # if `patterns` is specified virus name will be matched against provided regexes and the related
    # symbol will be yielded if a match is found. If no match is found, default symbol is yielded.
    patterns {
      # symbol_name = "pattern";
      JUST_EICAR = "^Eicar-Test-Signature$";
    }
    patterns_fail {
      # symbol_name = "pattern";
      CLAM_PROTOCOL_ERROR = '^unhandled response';
    }
    # `whitelist` points to a map of IP addresses. Mail from these addresses is not scanned.
    whitelist = "/etc/rspamd/antivirus.wl";
}

Reconfigure Rspamd and restart services

ispconfig_update.sh --force
.
.
.
Reconfigure Services? (yes,no,selected) [yes]: yes

The following custom templates were found:

/usr/local/ispconfig/server/conf-custom/install/rspamd_antivirus.conf.master

Do you want to rename these conf-custom templates now so the default templates are used? (yes,no) [no]: no
.
.
.
Restarting services ...
Update finished.

Check Rspamd antivirus config file

egrep -v '(^.*#|^$)' /etc/rspamd/local.d/antivirus.conf
clamav {
    action = "reject";
    scan_mime_parts = true;
    scan_text_mime = true;
    scan_image_mime = true;
    symbol = "CLAM_VIRUS";
    type = "clamav";
    log_clean = true;
    servers = "127.0.0.1:3310";
    patterns {
      JUST_EICAR = "^Eicar-Test-Signature$";
    }
    patterns_fail {
      CLAM_PROTOCOL_ERROR = '^unhandled response';
    }
    whitelist = "/etc/rspamd/antivirus.wl";
}

Finished!

Send yourself the EICAR test virus and watch the logfiles

Download EICAR test virus

 wget https://secure.eicar.org/eicar.com --no-check-certificate && gzip eicar.com

Send test virus

swaks --to [email protected] --from [email protected] --attach - --server localhost < eicar.com.gz

If swaks (Swiss Army Knife for SMTP) is not installed, make up for it

apt -y install swaks

rspamd.log

tail -f /var/log/rspamd/rspamd.log | grep clamav
2021-12-11 19:04:10 #1117948(normal) <beac17>; task; rspamd_task_write_log: id: ...  ... forced: reject "clamav: virus found: "Win.Test.EICAR_HDB-1""; score=nan (set by clamav), settings_id: ispc_spamfilter_user_6

clamav.log

tail -f /var/log/clamav/clamav.log | grep FOUND
Sat Dec 11 19:04:10 2021 -> instream(127.0.0.1@60986): Win.Test.EICAR_HDB-1(d3c03a1d552e6b7eed704e6e24d7b9d7:98) FOUND

syslog

tail -f /var/log/syslog | grep clamav
Dec 11 19:04:10 ispconfig-server postfix/cleanup[1119725]: 5B52180772: to=<[email protected]>, relay=none, delay=0.22, delays=0.22/0/0/0, dsn=5.7.1, status=bounced (clamav: virus found: "Win.Test.EICAR_HDB-1")

Rspamd GUI

swapfile

4 GB RAM seems to be not enough for ClamAV, so let’s create a swapfile

dd if=/dev/zero of=/swapfile bs=1M count=4096
chmod 0600 /swapfile
mkswap /swapfile
swapon /swapfile

swapfile is now active

swapon --show
NAME      TYPE SIZE   USED PRIO
/swapfile file   4G 310.7M   -2
free -h
              total        used        free      shared  buff/cache   available
Mem:          3.7Gi       2.2Gi       451Mi       485Mi       1.1Gi       823Mi
Swap:         4.0Gi       353Mi       3.7Gi

Make swapfile permanent after reboot

vi /etc/fstab
/swapfile    none    swap    sw      0 0

See also