Set up DMARC (verification) for Postfix on Debian server
What is DMARC
DMARC (Domain-based Message Authentication, Reporting and Conformance) is an Internet standard (RFC 7489 ) that allows domain owners to prevent their domain names from being used by email spoofers. Before DMARC is invented, it is very easy for bad actors to use other people’s domain name in the From address .
If a domain owner created DMARC DNS record for his/her domain name and a receiving email server implemented DMARC check, then bad actors need to pass SPF alignment or DKIM alignment in order to pass DMARC check. If DMARC check fails, the spoofed email could be rejected. Never to be seen by end-users. It’s difficult for the bad actor to pass SPF or DKIM , unless the domain owner’s email server is compromised.
Further reading: DMARC - Domain-based Message Authentication, Reporting and Conformance
What is OpenDmarc
OpenDMARC is an open source implementation of the Domain-based Message Authentication, Reporting and Conformance (DMARC) specification. opendmarc uses the milter interface , originally distributed as part of version 8.11 of sendmail(8) , to provide a DMARC processing service for mail transiting a milter-aware MTA.
Install OpenDMARC
OpenDMARC is an open-source software that can perform DMARC verification and reporting. It’s already in the Debian repository, so you can run the following command to install it.
~] apt-get install opendmarc
If you are asked to configure a database for OpenDMARC, you can safely choose No. You only need to configure a database for OpenDMARC if you want to generate DMARC reports for other mailbox providers. It’s not very useful for small mail server operators like us to generate DMARC reports, so we can skip it.
Once installed, it will be automatically started. Check its status with:
~] systemctl status opendmarc
● opendmarc.service - OpenDMARC Milter
Loaded: loaded (/lib/systemd/system/opendmarc.service; enabled; preset: enabled)
Active: active (running) since Thu 2024-04-04 11:02:44 CEST; 53s ago
Docs: man:opendmarc(8)
man:opendmarc.conf(5)
Process: 8975 ExecStart=/usr/sbin/opendmarc (code=exited, status=0/SUCCESS)
Main PID: 8976 (opendmarc)
Tasks: 6 (limit: 4646)
Memory: 2.3M
CPU: 13ms
CGroup: /system.slice/opendmarc.service
└─8976 /usr/sbin/opendmarc
Apr 04 11:02:44 mailin1 systemd[1]: Starting opendmarc.service - OpenDMARC Milter...
Apr 04 11:02:44 mailin1 systemd[1]: Started opendmarc.service - OpenDMARC Milter.
Apr 04 11:02:44 mailin1 opendmarc[8976]: OpenDMARC Filter v1.4.2 starting ()
Apr 04 11:02:44 mailin1 opendmarc[8976]: additional trusted authentication services: (none)
Note that auto-start at system boot time is disabled. We can enable it by:
~] systemctl enable opendmarc
Configure OpenDmarc
For our set-up, we'll modify the configuration in the file '/etc/opendmarc.conf' as follows:
AuthservID OpenDMARC-mailin1.secar.cz
TrustedAuthservIDs mailin1.secar.cz
PidFile /run/opendmarc/opendmarc.pid
PublicSuffixList /usr/share/publicsuffix/public_suffix_list.dat
Socket inet:8888@127.0.0.1
Syslog true
SyslogFacility mail
UMask 0000
UserID opendmarc
RejectFailures true
SPFIgnoreResults true
SPFSelfValidate true
IgnoreAuthenticatedClients true
IgnoreHosts /etc/opendmarc/ignore.hosts
ReportCommand /usr/sbin/sendmail -t
HistoryFile /run/opendmarc/opendmarc.dat
- AuthservID (string)
- Sets the "authserv-id" to use when generating the Authentication-Results: header field after verifying a message. The default is to use the name of the MTA processing the message. If the string "HOSTNAME" is provided, the name of the host running the filter (as returned by the gethostname(3) function) will be used.
- TrustedAuthservIDs (string)
- Provides a list of authserv-ids that are to be used to identify Authentication-Results header fields whose contents are to be assumed as valid input for the DMARC assessment. To provide a list, separate values by commas. If the string "HOSTNAME" is provided, the name of the host running the filter (as returned by the gethostname(3) function) will be used. Matching against this list is case-insensitive. The default is to use the value of AuthservID.
- PidFile (string)
- Specifies the path to a file that should be created at process start containing the process ID.
- PublicSuffixList (string)
- Specifies the path to a file that contains top-level domains (TLDs) that will be used to compute the Organizational Domain for a given domain name, as described in the DMARC specification. If not provided, the filter will not be able to determine the Organizational Domain and only the presented domain will be evaluated.
- Socket (string)
- Specifies the socket that should be established by the filter to receive connections from sendmail(8) in order to provide service. socketspec is in one of two forms: local:path, which creates a UNIX domain socket at the specified path, or inet:port[@host] or inet6:port[@host] which creates a TCP socket on the specified port for the appropriate protocol family. If the host is not given as either a hostname or an IP address, the socket will be listening on all interfaces. This option is mandatory either in the configuration file or on the command line. If an IP address is used, it must be enclosed in square brackets.
- UMask (integer)
- Requests a specific permissions mask to be used for file creation. This only really applies to creation of the socket when Socket specifies a UNIX domain socket, and to the PidFile (if any); temporary files are created by the mkstemp(3) function that enforces a specific file mode on creation regardless of the process umask. See umask(2) for more information.
- UserID (string)
- Attempts to become the specified userid before starting operations. The value is of the form userid[:group]. The process will be assigned all of the groups and primary group ID of the named userid unless an alternate group is specified.
- RejectFailures (Boolean)
- If set, messages will be rejected if they fail the DMARC evaluation, or temp-failed if evaluation could not be completed. By default, no message will be rejected or temp-failed regardless of the outcome of the DMARC evaluation of the message. Instead, an Authentication-Results header field will be added. The default is "false".
- SPFIgnoreResults (Boolean)
- Causes the filter to ignore any SPF results in the header of the message. This is useful if you want the filter to perfrom SPF checks itself, or because you don’t trust the arriving header. The default is "false".
- SPFSelfValidate (Boolean)
- Causes the filter to perform a fallback SPF check itself when it can find no SPF results in the message header. If SPFIgnoreResults is also set, it never looks for SPF results in headers and always performs the SPF check itself when this is set. The default is "false".
- IgnoreHosts (string)
- Specifies the path to a file that contains a list of hostnames, IP addresses, and/or CIDR expressions identifying hosts whose SMTP connections are to be ignored by the filter. If not specified, defaults to "127.0.0.1" only.
- IgnoreAuthenticatedClients (Boolean)
- If set, causes mail from authenticated clients (i.e., those that used SMTP AUTH) to be ignored by the filter. The default is "false".
- ReportCommand (string)
- Indicates the shell command to which failure reports should be passed for delivery when FailureReports is enabled. Defaults to /usr/sbin/sendmail.
Create files for OpenDMARC
Create OpenDmarc directory:
~] mkdir /etc/opendmarc
Create file /etc/opendmarc/ignore.hosts with content:
127.0.0.1
Restart opendmarc service:
~] systemctl restart opendmarc
Linking OpenDMARC to Postfix
Now that the configuration is complete, we can restart up our new OpenDMARC service as follows:
systemctl restart opendmarc.service
# check opendmarc status
systemctl status opendmarc.service
Check OpenDMARC listen on inet port 8888:
~] netstat -lnp | grep 8888
tcp 0 0 127.0.0.1:8888 0.0.0.0:* LISTEN 10916/opendmarc
Next, we add the service (now available on port 8888) to the milters listed for the Postfix smtp/25 service in the file /etc/postfix/master.cf:
-o smtpd_milters=inet:127.0.0.1:8888
Testing DMARC with Telnet
You can use telnet to spoof another domain name, such as paypal.com. First, run the following command on your local computer to connect to port 25 of your mail server.
# use domain name or ip address of your mail server
telnet mail.yourdomain.com 25
Then use the following steps to send a spoof email. (You type in the bold texts.)
EHELO mail.paypal.com 250 mail.yourdomain.com MAIL FROM:<help@paypal.com> 250 2.1.0 Ok RCPT TO:<someone@yourdomain.com> 250 2.1.5 Ok DATA 354 End data with. From: help@paypal.com To: someone@yourdomain.com Subject: Please update your password. Click this link to update your password. . 550 5.7.1 rejected by DMARC policy for paypal.com quit 221 2.0.0 Bye Connection closed by foreign host.
As you can see, my mail server rejected this email because it didn’t pass DMARC check and Paypal deployed a p=reject policy.
dns query to paypal.com dmarc txt record:
~] dig txt _dmarc.paypal.com
_dmarc.paypal.com. 3600 IN TXT "v=DMARC1; p=reject; rua=mailto:d@rua.agari.com; ruf=mailto:d@ruf.agari.com"
And here is output from postfix log file:
|
|
Test mail configuration
You can test your mail configuration via this portals: