Table of Contents
Replacing SpamAssassin with Rspamd
Reference system: Debian GNU/Linux 12 Bookworm.
Install the Debian packages rspamd and redis-server (the latter is installed by dependency). Using the Systemd's tool systemctl, we can enable/disable/start/stop the services by referring to rspamd.service and redis-server.service, eg:
systemctl restart rspamd.service
The rspamd daemon is listening only on localhost:11333, it does not listen on external interfaces.
Using the Milter protocol with the self-scan option
The Milter protocol is a mail filter protocol used e.g. by the Postfix MTA to filter messages using an external program. The external program return a “success” or “failed” status to the MTA.
Only success or failed? How are handled greylisted messages?
Default options are configured into /etc/rspamd/worker-proxy.inc, the self-scan mode is configured by the following snippet:
milter = yes; # Enable milter mode timeout = 120s; # Needed for Milter usually upstream "local" { default = yes; hosts = "localhost"; } count = 1; # Do not spawn too many processes of this type max_retries = 5; # How many times master is queried in case of failure discard_on_reject = false; # Discard message instead of rejection quarantine_on_reject = false; # Tell MTA to quarantine rejected messages spam_header = "X-Spam"; # Use the specific spam header reject_message = "Spam message rejected"; # Use custom rejection message
What is the self-scan mode? What are the alternatives?
Suppose we want to spawn at least 5 processes for scanning messages, we can change only the count option by creating a local configuration file /etc/rspamd/local.d/worker-proxy.inc, putting a single line in it:
count = 5;
That option will be merged into the worker ⇒ rspamd_proxy section of the configuration. To check if the file is properly parsed you can execute
rspamadm configdump
and search the output for the worker ⇒ rspamd_proxy definition:
worker { rspamd_proxy { count = 5; max_retries = 5; discard_on_reject = false; quarantine_on_reject = false; spam_header = "X-Spam"; milter = true; bind_socket = "localhost:11332"; timeout = 120; reject_message = "Spam message rejected"; upstream { local { hosts = "localhost"; default = true; } } } }
The Redis database backend
After the installation of the redis-server Debian package, the daemon is listening on 127.0.0.1:6379. Execute the client redis-cli to check the connection:
127.0.0.1:6379> PING PONG
The default Debian configuration prepares 16 databases, you can select the second one (starting to count from zero) with:
127.0.0.1:6379> SELECT 1 OK 127.0.0.1:6379[1]>
The Redis database backend can be used by several Rspamd modules, e.g. greylist, ratelimit, etc. Place the settings common to all the modules into /etc/rspamd/local.d/redis.conf:
servers = "127.0.0.1";
Once you configured the use of Redis, check that the depending modules are actually enabled using rspamadm configdump -m
.
Test the daemon
Using the rspamc client it is possible to ask the rspamd daemon about a mail message. The result includes the rules triggered by the message and the scores associated to each of them:
rspamc < message.txt Results for file: stdin (0.36 seconds) [Metric: default] Action: greylist Spam: false Score: 5.50 / 15.00 Symbol: ASN (0.00)[asn:8677, ipnet:193.201.76.0/24, country:FR] Symbol: CTYPE_MIXED_BOGUS (1.00) Symbol: INVALID_DATE (1.50) Symbol: MIME_GOOD (-0.10)[multipart/mixed, text/plain] Symbol: MIME_TRACE (0.00)[0:+, 1:+] Symbol: PREVIOUSLY_DELIVERED (0.00)[...] Symbol: R_BAD_CTE_7BIT (3.50)[7bit] ...
The most importan rows are Action, Spam and Score: here it is the result for a good message:
Results for file: stdin (0.228 seconds) [Metric: default] Action: no action Spam: false Score: -0.29 / 15.00
Every message scan is logged into /var/log/rspamd/rspamd.log.
Configure Postfix to filter with Rspamd
The simplest configuration is to add the Rspamd milter to the smtpd_milters option in /etc/postfix/main.cf. In our example we add it to the existing DKIM filter:
# Mails received via SMTP protocol are filtered with: # * opendkim localhost:8891 # * Rspamd localhost:11332 smtpd_milters = inet:localhost:8891, inet:localhost:11332 # If some Milters are broken, accept messages without checks. milter_default_action = accept
With the default configuration, a message with SPAM score of 15 or above will be rejected by Postfix (the receiving MTA) and the sender MTA will generate a sender non-delivery notification.
Rspamd modules
To get the list of enabled and disabled modules:
rspamadm configdump -m
Interesting modules:
rbl | Checks a message’s sender IP address against Realtime Blackhole Lists (RBLs), etc. |
---|---|
spf | Checks the proclaimed sender domain’s Sender Policy Framework (SPF) policy. |
dkim | Verifies/Adds Domain Keys Identified Mail (DKIM) signatures to validate a mail really comes from the proclaimed domain. |
antivirus | Passes the message to external virus scanners such as clamav. |
regexp | This module is responsible for checking messages against regexp rules; if you create custom regexp rules you need this module enabled. |
redis | This is a database backend, required e.g. by the greylist or antivirus modules. |
greylist | Implements greylisting (temporarily refusing messages so a legitimate sender has to retry later) as an action. |
multimap | Can be used to add custom symbols or force actions upon match on a list of regexp. |
milter_headers | |
reputation | |
rspamd_update | This modules was responsible for backporting of new rules and score changes (similar to the sa-update tool for SpamAssassin), but it was disabled in version 1.8.2 (2018). |
Customize actions on SPAM score
The default configuration provided by Debian is stored into the file /etc/rspamd/actions.conf. The greylisting means that the message is rejected with soft reject action, this means that a legitimate MTA should retry the message after a while.
actions { reject = 15; add_header = 6; greylist = 4; }
If you want to customize the score, create a file /etc/rspamd/local.d/actions.conf and define the options you want to override (do not declare the actions section, just put the options):
# Reject when reaching this score. reject = 18.0; # Rewrite the subject when reaching this score. rewrite_subject = 6.0; # Add header "X-Spam: Yes" when reaching this score. add_header = 5.0; # Apply greylisting when reaching this score (will emit "soft reject action"). greylist = 4.0; # Set rewrite subject to this value (%s is replaced by the original subject). subject = "***** SPAM ***** %s"
The action add_header means adding the header X-Spam: Yes to the message.
NOTICE: Each action must have the correct score order, e.g. add_header must have lower score than action rewrite_subject.
NOTICE: Each action is mutually exclusive. This is obvious e.g. for greylist and reject, but it is also true for add_header and rewrite_subject. This means that you cannot have both the header added and the subject rewritten, only the action with the nearest score is selected.
Customize the score
Rspamd attaches symbols to messages. Each symbol has a score (or weight), which is a floating point number (negative or positive); per default its value is 1.0.
If several symbols are attacched to a message, their scores are summed up, forming the overall metric of the message.
If you want to define or override the scores of symbols, create the file local.d/metrics.conf and declare the symbols, one by one or in groups:
symbol "TEST_SPAM_STRING" { description = "My test Rspamd rule"; score = 6.50; } group "antivirus" { symbol "CLAM_VIRUS" { description = "Virus detected"; score = 20.00; } }
NOTICE: You must to reload the rspamd.service in order to make the new metrics effective.
WARNING: The keywords score and weight are synonyms and can be used interchangeably into the symbol definition, but score prevails if both are used.
Configure the blacklists
The RBL module can check each message against the Runtime Black Lists (RBL) typically provided through dedicated DNS zones.
Several RBLs are listed into the default configuration file modules.d/rbl.conf. You can find the definition of each RBL as a symbol, eventually using two different syntax: Why two syntax forms?
rbl { rbls { ... dnswl { symbol = "RCVD_IN_DNSWL"; ... } "RSPAMD_URIBL" { } ... } ... }
Local configuration must go into local.d/rbl.conf, here it is an example on how to add a custom RBL:
# Map containing additional IPv4/IPv6 addresses/subnets that should # be excluded from checks where exclude_local is true (the default). local_exclude_ip_map = "${LOCAL_CONFDIR}/maps.d/rbl_local_exclude_ip.map"; # Add a custom RBL. rbls { zen_rigacci { # Checks to enable for this RBL. # from: the sending IP that sent the message. checks = ["from"]; # Address used for RBL-testing. rbl = "zen.rigacci.org"; ipv4 = true; ipv6 = true; exclude_local = true; local_exclude_ip_map = "${LOCAL_CONFDIR}/maps.d/zen_rigacci_exclude_ip.map"; # Symbol to yeld. symbol = "ZEN_RIGACCI"; returncodes = { # Apply a specific symbol instead of the generic one. "ZEN_RIGACCI_CODE_1" = "127.0.0.1"; "ZEN_RIGACCI_CODE_2" = "127.0.0.2"; "ZEN_RIGACCI_CODE_3" = "127.0.0.3"; } } }
The file pointed by the local_exclude_ip_map option can be updated (adding or removing IP addresses or subnets) without the need to reload any service.
A custom score can be defined into local.d/rbl_group.conf:
symbols = { "ZEN_RIGACCI" { weight = 6.2; description = "From address is listed in ZEN Rigacci.Org"; groups = ["zen_rigacci"]; } } symbols = { "ZEN_RIGACCI_CODE_1" { weight = 6.8; description = "From address is listed in ZEN Rigacci.Org, code 1"; groups = ["zen_rigacci"]; } }
Several RBLs are enabled per default in the Debian 12 install. if you want to disable some, just add the symbol into the rbls list with the option enabled = false:
rbls { dnswl { symbol = "RCVD_IN_DNSWL"; enabled = false; } }
Antivirus scanning
The antivirus function is accomplished by the specific antivirus module. Local configuration should go into the local.d/antivirus.conf file; here it is an example to use the ClamAV daemon listening on the TCP port:
# local.d/antivirus.conf clamav { # The antivirus engine to use. type = "clamav"; servers = "127.0.0.1:3310"; # If set, force this action if any virus is found (default unset: no action is forced). action = "reject"; message = 'Forbidden: virus found: "${VIRUS}"'; # If `max_size` is set, messages > n bytes in size are not scanned max_size = 20000000; # Symbol to add (add it to metrics if you want non-zero weight). # You can use this if you want to apply default actions based on score. symbol = "CLAM_VIRUS"; # Prefix used for caching in Redis: scanner-specific defaults are used. # If Redis is enabled and multiple scanners of the same type are present, # it is important to set prefix to something unique. prefix = "rs_cl_"; # 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-Signature$'; } }
If the action option is not set, the action based on the overall SPAM score is taken. In the example above we forced the reject action and using the message option we will create a specific SMTP 554 5.7.1 message for the virus found case.
NOTICE: The optional section patterns: if one the patterns matches (the ones on the right of the equal sign), the specified symbol is added to the message, instead of the one specified at the module level.
A custom score for the symbols can be defined into local.d/metrics.conf:
group "antivirus" { symbol "CLAM_VIRUS" { description = "Virus detected"; score = 2.92; } symbol "JUST_EICAR" { description = "Only a virus test"; score = -6.00; } }
SPF check
The spf module is enable per default in Debian 12 Bookworm. Local configuration goes into local.d/spf.conf, here e.g. we add a whitelist of IP addresses that will be exempted from SPF check:
# whitelist IPs from checks. whitelist = "${LOCAL_CONFDIR}/maps.d/spf_whitelist.inc";
The symbol that can be attached by the module are into the spf group, defined into scores.d/policies_group.conf:
VIOLATED_DIRECT_SPF(3.50) R_SPF_SOFTFAIL(0.0) R_SPF_FAIL(1.00) R_SPF_NEUTRAL(0.0) R_SPF_ALLOW(-0.2) R_SPF_DNSFAIL(0.0) R_SPF_NA(0.0) R_SPF_PERMFAIL(0.0)
The VIOLATED_DIRECT_SPF
is a composite symbol, it combines an SPF (soft) fail and has no Received or no trusted received relays. As you can see from the log below, an SPF fail does not trigger a significative SPAM score using the default metrics: only 0.90/18.00:
#1251327(normal) <47b9f4>; task; rspamd_task_write_log: id: <ZU4+2ohp+7i+JeIU@mail.rigacci.org>, qid: <6A3AD3FF39>, ip: 2a01:4f8:2a36:8743::1, from: <niccolo@forged.tld>, (default: F (no action): [0.90/18.00] [R_SPF_FAIL(1.00){-all;}, MIME_GOOD(-0.10){text/plain;},ARC_NA(0.00){},ASN(0.00){asn:24940, ipnet:2a01:4f8::/32, country:DE;},DMARC_NA(0.00){rigacci.org;}, FROM_EQ_ENVFROM(0.00){},FROM_HAS_DN(0.00){},MIME_TRACE(0.00){0:+;}, RCPT_COUNT_ONE(0.00){1;},RCVD_COUNT_TWO(0.00){2;},RCVD_TLS_LAST(0.00){}, R_DKIM_NA(0.00){},TO_DN_NONE(0.00){},TO_MATCH_ENVRCPT_ALL(0.00){}]), len: 541, time: 143.467ms, dns req: 33, digest: <9aee68ee8076d6dc6887c0d88cb4f4d1>, rcpts: <niccolo@test-mail.rigacci.org>, mime_rcpts: <niccolo@test-mail.rigacci.org>
If you want to customize the score, just create a file local.d/policies_group.conf containing only the differences from the default file:
symbols = { "R_SPF_FAIL" { weight = 4.80; } }
NOTICE: We used the keyword weight to replace the same keyword declared into scores.d/policies_group.conf
. Alternatively it is possibile to define the keyword score that will take precedence over weight.
Greylist
Greylisting is provided by the greylist module, which in turn requires that the Redis database engine is enabled. Once the redis module is enabled, the greylist module should also be enabled; verify using the rspamadm configdump -m
command.
You can test that greylisting is working by sending a message that will trigger a metric that results in greylisting (see e.g. the multimap module to add a custom score to a message based on regexp, default score for greylisting is 4 in Debian 12 Bookworm).
This is what will be logged in mail.log when the message is temporary rejected:
postfix/smtpd[521074]: connect from test.rigacci.org[188.21.172.134] postfix/smtpd[521074]: 0D00641ACD: client=test.rigacci.org[188.21.172.134] postfix/cleanup[521078]: 0D00641ACD: milter-reject: END-OF-MESSAGE from test.rigacci.org[188.21.172.134]: 4.7.1 Try again later; from=<user1@rigacci.org> to=<user2@rigacci.org> proto=ESMTP helo=<test>
This is greylist log in rspamd/rspamd.log, you can search for the keywords greylisted until:
#1223676(normal) <8003ac>; lua; greylist.lua:430: greylisted until "Fri, 10 Nov 2023 08:39:31 GMT", new record #1223676(normal) <8003ac>; task; rspamd_add_passthrough_result: <ZU3rFzOe1qz+ksrt@mail.rigacci.org>: set pre-result to 'soft reject' (no score): 'Try again later' from greylist(1) #1223676(normal) <8003ac>; task; rspamd_task_write_log: id: <ZU3rFzOe1qz+ksrt@mail.rigacci.org>, qid: <4891841B4C>, ip: 2a01:4f8:2c28:8646::1, from: <niccolo@rigacci.org>, (default: F (soft reject): [4.28/18.00] [TEST_SPAM_STRING(4.58){},R_SPF_ALLOW(-0.20){+a:mail.rigacci.org;}, MIME_GOOD(-0.10){text/plain;},ARC_NA(0.00){}, ASN(0.00){asn:24940, ipnet:2a01:4f8::/32, country:DE;}, DMARC_NA(0.00){rigacci.org;},FROM_EQ_ENVFROM(0.00){}, FROM_HAS_DN(0.00){},GREYLIST(0.00) {greylisted;Fri, 10 Nov 2023 08:39:31 GMT;new record;}, MID_RHS_MATCH_FROMTLD(0.00){},MIME_TRACE(0.00){0:+;}, RCPT_COUNT_ONE(0.00){1;},RCVD_COUNT_TWO(0.00){2;}, RCVD_TLS_LAST(0.00){},R_DKIM_NA(0.00){},TO_DN_NONE(0.00){}, TO_MATCH_ENVRCPT_ALL(0.00){},URIBL_BLOCKED(0.00) {rigacci.net:url;santorini.rigacci.org:rdns;mail.rigacci.org:helo;}]), len: 530, time: 198.906ms, dns req: 31, digest: <cad01ede372e5ecce0f54b67d52198a7>, rcpts: <niccolo@test-mail.rigacci.org>, mime_rcpts: <niccolo@test-mail.rigacci.org>, forced: soft reject "Try again later"; score=nan (set by greylist)
The sender can retry after the default timeout = 5min and should succeed. When the greylisting period expired, the logging will be something like this (keywords greylisting pass):
#1235394(normal) <7b0b7f>; lua; greylist.lua:404: greylisting pass (body) until Sat, 11 Nov 2023 10:27:37 GMT
It is possible to whitelist some sender domains, listing them one per line into the local file local.d/greylist-whitelist-domains.inc
The Redis database entries
Two hashes will be recorded into the Redis database: the meta one is based on the from:to:ip triplet, the data one is based on the message body. The keys stored into the database have a key_prefix, which is “rg” per default in Debian 12 Bookworm. The keys contain the Unix timestamp of the time when greylisting happened.
You can use the redis-cli tool to view or delete keys in the database:
127.0.0.1:6379> KEYS rg* 1) "rgm9hy6nondu18enp5xfn7e" 2) "rgme18xdtyoa4scg7eeiqmr" 127.0.0.1:6379> GET rgm9hy6nondu18enp5xfn7e "1699610557" 127.0.0.1:6379> DEL rgm9hy6nondu18enp5xfn7e (integer) 1
Custom regexp rule with multimap
To add a custom rule using some regular expressions, we will use the multimap module, which is enabled per default in Debian. We can create a file called /etc/rspamd/local.d/multimap.conf and write a symbol (rule name) in it:
TEST_SPAM_STRING { description = "Test SPAM rule"; type = "content"; filter = "body"; regexp = true; map = "${LOCAL_CONFDIR}/maps.d/test_spam.map"; prefilter = true; # Action can be: "accept", "greylist", "add_header", "rewrite_subject" and "reject". # If no action is specified, the generic score-based one will be applied. action = "reject"; # Score is eventually overridden/defined in local.d/metrics.conf. score = 20.0; # Message returned to MTA on reject action. message = "The message contains a knwon SPAM test"; }
The type content means that we are considering the mail content (headers and/or body), alternatively you can consider the from, hostname, ip, attachment filename, etc.
The filter body means that we are searching the message body, not the headers.
If regexp is set to true it means that the map contains regular expressions (one per line).
The map in this case is a local file, it can be and URL, etc. If the file is changed, no reload of the daemon is required. Here it is an example of configuration file named maps.d/test_spam.map, containing just two regexp:
/first test string/gi /second example string/gi
If the map file is updated, it will be reloaded automatically.
If prefilter is true, we have to define the action. In case of match the action is executed and no filters will be applied.
If an action is specified and the message matches, process the message accordingly. In this case the score specified in the rule is summed to the overall score, but it does not contribute in determining the action.
accept | Accept the message (no action), regardless the score added by this rule. |
---|---|
add_header | Add a header X-Spam: Yes to the message, but the message is eccepted for delivery. |
rewrite_subject | The message is accepted, but the Subject: header is modified according to the global actions ⇒ subject setting. |
soft reject | The message is rejected with a 451 SMTP status code, meaning a temporary problem. The sender MTA is notified with a temporary failure message and it should retry later. Notice that this action is not a greylisting: when the message is retried the same rule applies again. |
reject | The message is reject witha 554 SMTP status code. The default message generated by the Postfix MTA is 554 5.7.1 Matched map: TEST_SPAM_STRING . The sender MTA should create a sender non-delivery notification. |
If specified, the score is added to the metric of the message; otherwise the value 0.0 is used. If a score for this symbol is defined also into the local.d/metrics.conf file, the latter will take precedence. Here it is an example on how to define the score into local.d/metrics.conf:
symbol "TEST_SPAM_STRING" { description = "My test Rspamd rule"; score = 4.58; }
The message is eventually used if the mail matches this rule and the action is set to reject or soft reject. In this case the sender MTA will be notified with this message in reply to end of DATA command. The SMTP message code will be 554 for reject or 451 for soft reject.
Whitelist-From using the multimap module
It is possibile replicate the whitelist_from option found in SpamAssassin using the multimap module of rspamd. In the /etc/rspamd/local.d/multimap.conf we create a symbol called e.g. WHITELIST_FROM:
WHITELIST_FROM { description = "Whitelist From regex"; type = "from"; regexp = true; map = "${LOCAL_CONFDIR}/maps.d/whitelist_from.map"; prefilter = true; action = "accept"; score = -100; }
In the file /etc/rspamd/maps.d/whitelist_from.map it is possibile to add one regex per line to mach the From header. The header content is cleaned of extra data, e.g. Niccolo Rigacci <niccolo@rigacci.org>
will be pruned to niccolo@rigacci.org
.
Standard regex meta-characters can be used, e.g. (see man grep
for a full list):
^ | Matches the start of the line. |
---|---|
$ | Matches the end of the line. |
. | Matches a single character. |
\. | Matches a single dot. |
\b | Matches the empty string at the edge of a word. |
The regex must be enclosed into a pair of / chars and the standard flags can be used:
i | Case insensitive match. |
---|
Here are an example to whitelist a single email address and an entire mail domain (NOTICE: if the map is updated, it will be reloaded automatically):
/^niccolo@texnet\.it$/i /@domain\.org$/i
Customizing the headers
Rspamd generally does not add headers to the email messages unless the action selected is add header. If you want more control on customizing the headers, you can use the milter headers module.
Local configuration must be into local.d/milter_headers.conf:
# Add the X-Spamd-Result header to all the messages. use = ["x-spamd-result", "x-spam-status", "x-spam-level"]; # Implies X-Spamd-Result and add X-Rspamd-Queue-Id, X-Rspamd-Server and X-Rspamd-Action. extended_spam_headers = true;
The use option is the only one required to activate the module: we should list what routines must be applied to the messages. Here some of the routines available:
x-spamd-result | Add the header X-Spamd-Result with details on the total score. |
---|---|
x-spam-status | Add an header like X-Spam-Status: No, score=-0.30 . The status becomes Yes on reaching at least the add_header level. |
x-spam-level | Add an header like X-Spam-Level: ****** if the message scores at least the add_header level. |
The extended_spam_headers option will add some headers to all the messages, regardless the spam score:
X-Spamd-Result: default: False [-0.30 / 18.00]; R_SPF_ALLOW(-0.20)[+a:mail.rigacci.org]; MIME_GOOD(-0.10)[text/plain]; FROM_EQ_ENVFROM(0.00)[]; MID_RHS_MATCH_FROMTLD(0.00)[]; ARC_NA(0.00)[]; R_DKIM_NA(0.00)[]; RCVD_TLS_LAST(0.00)[]; ASN(0.00)[asn:24940, ipnet:2a01:4f8::/32, country:DE]; URIBL_BLOCKED(0.00)[mail.rigacci.org:rdns,mail.rigacci.org:helo,rigacci.net:url]; RCPT_COUNT_ONE(0.00)[1]; DMARC_NA(0.00)[rigacci.org]; RCVD_IN_DNSWL_FAIL(0.00)[2a01:4f8:2a36:8743::1:server fail]; MIME_TRACE(0.00)[0:+]; FROM_HAS_DN(0.00)[]; TO_DN_NONE(0.00)[]; TO_MATCH_ENVRCPT_ALL(0.00)[]; RCVD_COUNT_TWO(0.00)[2] X-Rspamd-Server: mail-test X-Rspamd-Action: no action X-Rspamd-Queue-Id: 08D4341B21
In the following example we used a multimap rule associated to the symbol TEST_SPAM_STRING to reach the add_header score:
X-Spamd-Result: default: False [5.28 / 18.00]; TEST_SPAM_STRING(5.58)[]; ... X-Rspamd-Server: test-mail X-Rspamd-Action: add header X-Rspamd-Queue-Id: 4C9E742AE5 X-Spam: Yes
Changing the multimap rule we reached the rewrite_subject score (notice that the X-Spam:
header is not added in this case, despite the rewrite_subject is considered greather in SPAM score than add_header):
X-Spamd-Result: default: False [6.28 / 18.00]; TEST_SPAM_STRING(6.58)[]; ... X-Rspamd-Queue-Id: D87FC41B3A X-Rspamd-Server: test-mail X-Rspamd-Action: rewrite subject
With the following example we add a custom X-Virus header if a symbol was added, e.g. by the antivirus module. In this case the antivirus module should not apply its own reject action, otherwise it is pointless to mangle the headers.
# Add the X-Spamd-Result header and others to all the messages. use = ["x-spamd-result", "x-spam-level", "x-spam-status", "x-virus"]; # Implies X-Spamd-Result and add X-Rspamd-Queue-Id, X-Rspamd-Server and X-Rspamd-Action. extended_spam_headers = true; # Special routine to add custon a X-Virus header upon specific symbols. routines { x-virus { header = "X-Virus"; remove = 0; # The following setting is an empty list by default and required to be set. # These are user-defined symbols added by the antivirus module. symbols = ["CLAM_VIRUS", "JUST_EICAR"]; } }
Logging
Example to enable logging for the milter and the rbl modules: create the file /etc/rspamd/local.d/logging.inc with:
debug_modules = ["milter", "rbl"]
ClamAV on TCP socket in Debian 12
BEWARE of the Debian bug #1042377 which prevents the ClamAV daemon to listen on the TCP socket, even if you run the dpkg-reconfigure clamav-daemon procedure on a clean system.
The problem is reported into /var/log/clamav/clamav.log:
TCP: No tcp AF_INET/AF_INET6 SOCK_STREAM socket received from systemd.
This means that the Systemd unit must create the socket and pass it to the daemon, so any TCPSocket and TCPAddr configurationin /etc/clamav/clamd.conf is useless.
The workaround is contained into the bug report, create a new Systemd unit /etc/systemd/system/clamav-daemon.socket.d/tcp-socket.conf and declare the socket into it:
[Socket] ListenStream=127.0.0.1:3310
systemctl daemon-reload systemctl restart clamav-daemon.socket systemctl restart clamav-daemon.service