Hello all,
I've been working on the implementation of SPF/DKIM/DMARC policies in
the configuration of Exim on CentOS 8 (8.1). It turns out that
everything is there (i.e. all functionality is compiled in in the
package that comes with the repository), but there are no policies at
all defined in '/etc/exim/exim.conf'.
(there are some 'dkim_disable_verify' and 'dmarc_disable_verify'
statements where DKIM/DMARC-validation should not take place, i.e. for
local/relayed/authenticated hosts; and SPF and DKIM are validated as
part of the (external) spam scan)
Please find below the policies that I've created and tested (checking
logs and headers of validating and non-validating messages in a test
environment that is, not in a volume/operational environment yet).
Any feedback on the polices themselves would be great. And maybe these
would be a good starting point to get some policies into the Exim
configuration that comes with CentOS, probably best with an on/off
switch variable.
Tnx, Adrian
________
For SPF validation:
acl_check_mail:
# Hosts are required to say HELO (or EHLO) before sending mail.
# So don't allow them to use the MAIL command if they haven't
# done so.
deny condition = ${if eq{$sender_helo_name}{} {1}}
message = Nice boys say HELO first
# reject messages from senders listed in these DNSBLs
deny dnslists = zen.spamhaus.org
# SPF validation
deny spf = fail : softfail
message = SPF validation failed: \
$sender_host_address is not allowed to send mail from \
${if def:sender_address_domain \
{$sender_address_domain}{$sender_helo_name}}
log_message = SPF validation failed\
${if eq{$spf_result}{softfail} { (softfail)}{}}: \
$sender_host_address is not allowed to send mail from \
${if def:sender_address_domain \
{$sender_address_domain}{$sender_helo_name}}
deny spf = permerror
message = SPF validation failed: \
syntax error in SPF record(s) for \
${if def:sender_address_domain \
{$sender_address_domain}{$sender_helo_name}}
log_message = SPF validation failed (permerror): \
syntax error in SPF record(s) for \
${if def:sender_address_domain \
{$sender_address_domain}{$sender_helo_name}}
defer spf = temperror
message = temporary error during SPF validation; \
please try again later
log_message = SPF validation failed temporary; deferred
# Log SPF none/neutral result
warn spf = none : neutral
log_message = SPF validation none/neutral
# Use the lack of reverse DNS to trigger greylisting. Some people
# even reject for it but that would be a little excessive.
warn condition = ${if eq{$sender_host_name}{} {1}}
set acl_m_greylistreasons = Host $sender_host_address \
lacks reverse DNS\n$acl_m_greylistreasons
accept
# Add an SPF-Received header to the message
add_header = :at_start: $spf_received
logwrite = SPF validation passed
________
For DKIM validation:
acl_smtp_dkim = acl_check_dkim
acl_check_dkim:
deny dkim_status = fail
message = DKIM validation failed: $dkim_verify_status
log_message = DKIM validation failed: $dkim_verify_status \
(address=$sender_address, domain=$dkim_cur_signer), \
signature is bad
defer dkim_status = invalid
message = DKIM signature invalid: $dkim_verify_status
log_message = DKIM signature invalid: $dkim_verify_status \
(address=$sender_address, domain=$dkim_cur_signer), \
invalid signature
# NOTE: dkim_status = none should never happen in this ACL
accept
# Add an X-DKIM header to the message
add_header = :at_start: X-DKIM: DKIM validation passed: \
(address=$sender_address domain=$dkim_cur_signer), \
signature is good
logwrite = DKIM validation passed
________
For DMARC validation:
global:
# DMARC
dmarc_tld_file=/usr/share/publicsuffix/public_suffix_list.dat
dmarc_history_file=/var/spool/exim/opendmarc/history.dat
dmarc_forensic_sender=postmaster@???
added to acl_check_data:
# DMARC
warn dmarc_status = quarantine
!authenticated = *
log_message = Message from $dmarc_used_domain failed sender's
DMARC policy; QUARANTINE
control = dmarc_enable_forensic
set acl_m_quarantine = 1
# this variable to use in a router/transport
deny dmarc_status = reject
!authenticated = *
message = Message from $dmarc_used_domain failed sender's DMARC
policy; REJECT
control = dmarc_enable_forensic
warn add_header = :at_start: ${authresults {$primary_hostname}}
changed in 'localuser' router:
#transport = local_delivery
transport = ${if =={$acl_m_quarantine}{1}
{local_delivery_quarantine}{local_delivery}}
added a new transport:
local_delivery_quarantine:
driver = appendfile
#file = /var/mail/$local_part
directory = /home/mail-quarantine/Maildir
user = mail-quarantine
home_directory = /home/mail-quarantine
current_directory = /home/mail-quarantine
maildir_format
delivery_date_add
envelope_to_add
return_path_add
group = mail
mode = 0660