Email Anti Spoofing - DMARC

DMARC, defined in RFC 7489, is in simple terms an alignment test using DKIM and SPF, so it's important that you first configure both SPF and DKIM.
DMARC isn't on it's own a magic bullet, but another tool that helps protect you from those seeking to impersonate you or do you harm, it also provides for an overview of what's happening courtesy of daily reports remote servers send you, and in some cases aid in inbox deliverability with some of the larger providers starting to use visual signs for users to indicate if the message is authenticated using DMARC (waves at Google).
DMARC (in its recommended configuration) still passes a message that is good for one method, but fails the other, so one of the two, SPF or DKIM, must exist and pass, but reporting covered later, may differ.
DMARC checks alignments by applying two tests, against the From, and Return-path headers of each message, then using those results it forms a decision based on the policy setting, if DMARC policies are set strict, the fields must be an exact match, if they are set relaxed, then it will be more lenient, allowing sub-domains such as mail.yourdomain.
Remember that DMARC SPF decisions differ somewhat from MTA based SPF checks that are more concerned about the sending Mail Servers I.P. address being allowed to send for your domain, where with DMARC it's message headers based checking.
OpenDMARC - the most commonly used program and the one we are concerned with configuring here, can be configured to immediately generate forensic reports to the senders domain admins for failures, thus alerting the admins that someone is trying to impersonate their domain, or that they have an erroneously configured machine on their network. We can also send the more generalised daily activity reports to all domains that sent us DMARC enabled messages, this requires some extra work, and we'll cover that later on. If you use RspamD, it too can be configured for DMARC, see the DMARC modules documentation.
You don't have to configure sending reports in order to receive them, but it's good netiquette to send them, especially the forensic reports. To receive DMARC reports, we enable some options in our _dmarc DNS record.
The daily reports are in XML format designed to be read by automation, not very human friendly, but there are services you can use that will sift through all that for you, most are subscription based with lots of statistics, but some are free and send you a basic weekly human readable report, but beware that the support for free users from some is next to non existent, more later on.
To get started you'll need to download and install the latest version of OpenDMARC, at time of writing, version 1.4.2 is current.
Now you've built and installed OpenDMARC, move opendmarc.conf into /etc/opendkim, then open it in your favourite editor, the following options are the ones you need to be concerned with, note that RejectFailures only rejects messages that fail DMARC and have the p=reject policy set, it does not apply if the policy is set to quarantine.
Now add a line in your Mail Servers startup script to run opendmarc, if you followed our DKIM article, right after where you added the command to start that, add the following startup command, and reload
As with SPF and DKIM, DMARC records are also TXT type, so we start with the special hostname _dmarc then the resource record type TXT and finally the DATA field, which contains options, separated by a semicolon all contained within inverted commas, an example will follow shortly
The DATA field first starts with v=DMARC1 which says this is DMARC, then we set our policy so the receiver knows how you want them to handle a failure, this one's important, so start out with p=none for a week, this ensures no Email is lost whilst you're in the setup and testing phase, it gives you a safe period of time to make sure everything's working correctly by receiving and checking your DMARC reports looking out for any failures that shouldn't be, before moving to enforcement.
Once you're sure everything is working as intended, I strongly recommend enabling enforcement by moving from p=none to p=quarantine at a minimum, this in most cases allows a failed message to be accepted by the receiver, but likely marked as Junk. An alternative is to outright reject with p=reject, this is the preferred method (combined with aspf and adkim both set to strict), for e-commerce businesses, financial bodies, enterprises, legal and government sectors. With just p= set, any subdomains will use the same policy if you do not specify a DMARC record for that subdomain, so you could set p= on your top level so failed messages are rejected, and set tag sp=quarantine, where foo.example.com will be accepted but likely treated as junk, p= and sp= are how to treat failures, this differs from aspf and adkim policies, omitting sp= inherits p=.
Next we state how we want to enforce SPF by using aspf=, as previously touched on we have two possibilities, r being relaxed, and s being strict. As an example in relaxed mode, if a published signature is the domain of example.com and the From address is hello@sub.example.com, it will pass as it's considered to be aligned.
However in strict mode, this would fail, since the published signed domain example.com does not match the From domain of sub.example.com. Where we ordinarily would see example.com as the domain and anything else, eg: sub.example.com as a hostname, DMARC does not look at it that way, it treats the hostname as a sub domain in its own right. For most of us - unless you're in one of the above mentioned sectors I mentioned earlier that really should run the highest of Email security style options, it's safe enough to run in relaxed mode, so I recommend you set aspf=r.
Now we set how we want to enforce DKIM by use of adkim=, apply the same rationale as above in determining use of relaxed or strict, so for the average domain, running relaxed is safe enough, set adkim=r.
If you do not include aspf or adkim, they are assumed by default as relaxed, but I like to set them anyway, you never know what a default option might be changed to in the future.
Moving on to our notifications, this is where we tell others where to send us some stats, we have two options, rua and ruf, because these are Email fields, both of these must be formatted mailto:email@address, eg ruf=mailto:dmarc_reports@yourdomain, lastly a third and final but closely related option fo, this says how to handle the forensic notifications.
When setting these up, it is imperative that not only the RUA and RUF addresses exist, but are accurate, and that you keep them current at all times, this is especially important to remember if you change hosting or mail providers, or use stupid hosting/mail providers that delete accounts if you don't "use" that account. If you get fed up with receiving notices, do not just delete the address or alias on your mail server, you must remove the rua/ruf entry entirely from the DMARC DNS record (don't forget to reload the zone to take affect) if you don't, your mail server will bounce messages, so you'll be pissing off a lot of system administrators, which can, and has, led to mail servers and even domains being placed into blacklists.
DMARC will continue to work happily without RUA and RUF entries in the DNS record, it's not ideal to do so, since you'll never know if it's really working - stopping impersonaters.
rua is the report address for general aggregate information, ie your daily reports in XML format, this does not have to be, in fact should not be, a real persons Email address, this is where you have them sent to a service that processes your daily XML reports and send you one weekly human readable report.
One such service, dmarcian, give you access to a web portal with overviews where you can get better insights into how your fairing, they have a 14 day free trial, and if your volume is low and have just one or two domains, you may qualify for an ongoing free personal account. Another such service, postmarkapp, has a free service where you don't have to sign up and has no apparent limits, but the drawback is you only get that one weekly Email report, you don't get a portal login, nor in-depth statistics, but it's another option to look at if dmarcian doesn't suite your needs.
ruf= is the forensic address you want immediate Email notifications sent to when someone using your domain sends email that fails DMARC, it's the human readable failure report, I suggest creating an Email alias and forward it to an account you read, eg: dmarc_reports@yourdomain, then in your Mail Server, set an alias dmarc_reports@yourdomain to forward to your actual address, this avoids putting your private Email address in DNS for all to see (and spam the crap out of you)
fo= defines forensic reporting, the most common of the four options are 0 and 1.
fo=0 generates a failure report if both SPF and DKIM fail.
fo=1 generates a failure report if either SPF or DKIM fail, making fo=1 more strict.
Which to use depends, if you are requiring high security, like corporate only Email, financial, e-commerce or related industry, law, accountancy, or government, then you should use fo=1. If you're a SOHO where users may also use mailing lists and for personal Email, then you should probably use fo=0 which still gives you good security when using both DKIM and SFP since it will pass if at least one of these aligns. fo=0 is the current default if not specified.
When we put all of the above together for your zone file RR, each option separated by a semi colon, we would end up with something like this in strict modes for Enterprise, E-comm, Govt, Financial, Legal etc...
Now you're set with DNS declaring your DMARC policies so all Mail Servers that check DMARC who receive messages from, or claiming to be from your domain will now be validated, and either accepted, quarantined/marked as spam, or rejected - based on your DMARC policy.
You can check your DMARC record so you see how others see it, by running
If you operate a Mailman based Mailing List, it is highly advisable to set a couple options under Privacy options -> Sender Filters
does tcpserver even know what these are? probably not.
Moving along... edit /etc/postfix/main.cf, find the smtpd_milters line, this is where we previously added our socket for DKIM, this time we add in our socket as declared in opendmarc.conf, which is 127.0.0.1:8893, so we add this to our existing line, eg:
Remember that we recommend setting DMARC's policy to quarantine once you have it working happily, but it also means your Mail Server will not act on policies of quarantine, opendmarc itself only acts on p=reject, so it requires your Anti Spam systems to be configured to act on quarantine and mark the message as Junk/Spam.
We use amavisd which utilises the very popular SpamAssassin, it's fairly simple to setup rules to deal with DMARC failures, an example of these rules that include some leniency for Mailing Lists, SA-dmarc.cf, can be downloaded here, place SA-dmarc.cf into /etc/mail/spamassasin and edit it where it says YOURDOMAIN, reload SpamAssassin (or amavisd if you use SpamAssassin via it instead) and you're good to go, and in-case you didn't tell opendmarc.conf to reject on p=reject, the SA rules will catch them too
We need to set-up the database, to do this we first have to edit the OpenDMARC schema.mysql file, this can be found by changing into OpenDMARC's source directory, then the db directory, the second last line has the database useradd command, you need to change the password where it says changeme, make a note of it as you'll need it in the next steps, then as the database root user, load the schema.mysql file, it will create the database opendmarc and set up its tables then add the opendmarc user, once done reload the user privileges
To put all this into practice we need a cron job to import our history from our dat file (akin to a temp file that we set earlier in opendmarc.conf) into the SQL database, then we have another process that runs only once a day sending our aggregate reports.
To accomplish this I use a bash script in /etc/cron.d (which executes every five minutes) called dmarc_reports.sh - I know, very original
that does everything, and to stop this article being longer than war and peace I'll just link to the script instead, besides, serendipity will probably get the formatting out of whack - just be sure to read the in-line comments on what to change, you'll need the database password you just set too, download dmarc_reports.sh here, upon every run it processes the dat file into the database and clears it, then at around five minutes past midnight it runs another sub routine that processes and sends the daily reports, it also once a month cleans up the database avoiding growing bloat.
Note: Not all Linux distros are equal, so check the executables paths in the script match yours, also, as I mentioned my /etc/cron.d's scripts are run every five minutes, some distros may run them every minute, you do not want that so you'll need to set up a user cron job to call dmarc_reports.sh ever five or ten minutes instead.
Congrats, you now have SPF, DKIM, and DMARC all working to help protect you, and others, from spoofing vermin.
DMARC (in its recommended configuration) still passes a message that is good for one method, but fails the other, so one of the two, SPF or DKIM, must exist and pass, but reporting covered later, may differ.
DMARC checks alignments by applying two tests, against the From, and Return-path headers of each message, then using those results it forms a decision based on the policy setting, if DMARC policies are set strict, the fields must be an exact match, if they are set relaxed, then it will be more lenient, allowing sub-domains such as mail.yourdomain.
Remember that DMARC SPF decisions differ somewhat from MTA based SPF checks that are more concerned about the sending Mail Servers I.P. address being allowed to send for your domain, where with DMARC it's message headers based checking.
OpenDMARC - the most commonly used program and the one we are concerned with configuring here, can be configured to immediately generate forensic reports to the senders domain admins for failures, thus alerting the admins that someone is trying to impersonate their domain, or that they have an erroneously configured machine on their network. We can also send the more generalised daily activity reports to all domains that sent us DMARC enabled messages, this requires some extra work, and we'll cover that later on. If you use RspamD, it too can be configured for DMARC, see the DMARC modules documentation.
You don't have to configure sending reports in order to receive them, but it's good netiquette to send them, especially the forensic reports. To receive DMARC reports, we enable some options in our _dmarc DNS record.
The daily reports are in XML format designed to be read by automation, not very human friendly, but there are services you can use that will sift through all that for you, most are subscription based with lots of statistics, but some are free and send you a basic weekly human readable report, but beware that the support for free users from some is next to non existent, more later on.
To get started you'll need to download and install the latest version of OpenDMARC, at time of writing, version 1.4.2 is current.
tar xvf rel-opendmarc-VERSION.tar.gz cd rel-opendmarc-VERSION ./configure make && make installThis will install to /usr/local, now we need to edit opendmarc.conf, you can put opendmarc.conf anywhere since we run the program with the -c option which tells opendmarc where it can find its config file, I like to keep it simple and keep it in with opendkim's files in /etc/opendkim, so that's where my examples below will point to.
Now you've built and installed OpenDMARC, move opendmarc.conf into /etc/opendkim, then open it in your favourite editor, the following options are the ones you need to be concerned with, note that RejectFailures only rejects messages that fail DMARC and have the p=reject policy set, it does not apply if the policy is set to quarantine.
FailureReports true FailureReportsOnNone true RejectFailures true FailureReportsSentBy dmarc_reports@yourdomain HistoryFile /var/run/opendmarc.dat IgnoreAuthenticatedClients true PidFile /var/run/opendmarc.pid Socket inet:8893@127.0.0.1 Syslog true SyslogFacility mail TrustedAuthservIDs mailserver.yourdomainThat's it for opendmarc.conf, If your curious as to what each of those options do, the config file has in-line comments that are very clear, so I see no point in reproducing them here.
Now add a line in your Mail Servers startup script to run opendmarc, if you followed our DKIM article, right after where you added the command to start that, add the following startup command, and reload
/usr/local/sbin/opendmarc -c /etc/opendkim/opendmarc.confNext we move onto editing your DNS zone file.
As with SPF and DKIM, DMARC records are also TXT type, so we start with the special hostname _dmarc then the resource record type TXT and finally the DATA field, which contains options, separated by a semicolon all contained within inverted commas, an example will follow shortly

The DATA field first starts with v=DMARC1 which says this is DMARC, then we set our policy so the receiver knows how you want them to handle a failure, this one's important, so start out with p=none for a week, this ensures no Email is lost whilst you're in the setup and testing phase, it gives you a safe period of time to make sure everything's working correctly by receiving and checking your DMARC reports looking out for any failures that shouldn't be, before moving to enforcement.
Once you're sure everything is working as intended, I strongly recommend enabling enforcement by moving from p=none to p=quarantine at a minimum, this in most cases allows a failed message to be accepted by the receiver, but likely marked as Junk. An alternative is to outright reject with p=reject, this is the preferred method (combined with aspf and adkim both set to strict), for e-commerce businesses, financial bodies, enterprises, legal and government sectors. With just p= set, any subdomains will use the same policy if you do not specify a DMARC record for that subdomain, so you could set p= on your top level so failed messages are rejected, and set tag sp=quarantine, where foo.example.com will be accepted but likely treated as junk, p= and sp= are how to treat failures, this differs from aspf and adkim policies, omitting sp= inherits p=.
Next we state how we want to enforce SPF by using aspf=, as previously touched on we have two possibilities, r being relaxed, and s being strict. As an example in relaxed mode, if a published signature is the domain of example.com and the From address is hello@sub.example.com, it will pass as it's considered to be aligned.
However in strict mode, this would fail, since the published signed domain example.com does not match the From domain of sub.example.com. Where we ordinarily would see example.com as the domain and anything else, eg: sub.example.com as a hostname, DMARC does not look at it that way, it treats the hostname as a sub domain in its own right. For most of us - unless you're in one of the above mentioned sectors I mentioned earlier that really should run the highest of Email security style options, it's safe enough to run in relaxed mode, so I recommend you set aspf=r.
Now we set how we want to enforce DKIM by use of adkim=, apply the same rationale as above in determining use of relaxed or strict, so for the average domain, running relaxed is safe enough, set adkim=r.
If you do not include aspf or adkim, they are assumed by default as relaxed, but I like to set them anyway, you never know what a default option might be changed to in the future.
Moving on to our notifications, this is where we tell others where to send us some stats, we have two options, rua and ruf, because these are Email fields, both of these must be formatted mailto:email@address, eg ruf=mailto:dmarc_reports@yourdomain, lastly a third and final but closely related option fo, this says how to handle the forensic notifications.

DMARC will continue to work happily without RUA and RUF entries in the DNS record, it's not ideal to do so, since you'll never know if it's really working - stopping impersonaters.
rua is the report address for general aggregate information, ie your daily reports in XML format, this does not have to be, in fact should not be, a real persons Email address, this is where you have them sent to a service that processes your daily XML reports and send you one weekly human readable report.
One such service, dmarcian, give you access to a web portal with overviews where you can get better insights into how your fairing, they have a 14 day free trial, and if your volume is low and have just one or two domains, you may qualify for an ongoing free personal account. Another such service, postmarkapp, has a free service where you don't have to sign up and has no apparent limits, but the drawback is you only get that one weekly Email report, you don't get a portal login, nor in-depth statistics, but it's another option to look at if dmarcian doesn't suite your needs.
ruf= is the forensic address you want immediate Email notifications sent to when someone using your domain sends email that fails DMARC, it's the human readable failure report, I suggest creating an Email alias and forward it to an account you read, eg: dmarc_reports@yourdomain, then in your Mail Server, set an alias dmarc_reports@yourdomain to forward to your actual address, this avoids putting your private Email address in DNS for all to see (and spam the crap out of you)

fo= defines forensic reporting, the most common of the four options are 0 and 1.
fo=0 generates a failure report if both SPF and DKIM fail.
fo=1 generates a failure report if either SPF or DKIM fail, making fo=1 more strict.
Which to use depends, if you are requiring high security, like corporate only Email, financial, e-commerce or related industry, law, accountancy, or government, then you should use fo=1. If you're a SOHO where users may also use mailing lists and for personal Email, then you should probably use fo=0 which still gives you good security when using both DKIM and SFP since it will pass if at least one of these aligns. fo=0 is the current default if not specified.
When we put all of the above together for your zone file RR, each option separated by a semi colon, we would end up with something like this in strict modes for Enterprise, E-comm, Govt, Financial, Legal etc...
_dmarc TXT "v=DMARC1; p=reject; aspf=s; adkim=s rua=mailto:uniqueqwerty@dmarc.processing.address; ruf=mailto:dmarc_reports@yourdomain; fo=1;"But for the rest of us, we can safely use the relaxed methods like this...
_dmarc TXT "v=DMARC1; p=quarantine; aspf=r; adkim=r; rua=mailto:uniqueqwerty@dmarc.processing.address; ruf=mailto:dmarc_reports@yourdomain; fo=0;"
Now you're set with DNS declaring your DMARC policies so all Mail Servers that check DMARC who receive messages from, or claiming to be from your domain will now be validated, and either accepted, quarantined/marked as spam, or rejected - based on your DMARC policy.
You can check your DMARC record so you see how others see it, by running
opendmarc-check yourdomainYou should see output similar to
DMARC record for xxxxxx.au: Sample percentage: 100 DKIM alignment: strict SPF alignment: strict Domain policy: reject Subdomain policy: unspecified Aggregate report URIs: mailto:xxxx@xxxxxx.dmarcian.com Failure report URIs: mailto:dmarc_reports@xxxxxxx.au

dmarc_moderation_action Munge from dmarc_quarantine_moderation_action YesThere is no need to change the Mailman p=() option, but the other two will rewrite the From: as Some User via somelist@list_hostname and insert the actual sender (original From:) into the Reply-To: header, this aids in mostly preventing recipient MTA's not rejecting list posts from users that have DMARC enabled, and in case you didn't set it in our DKIM article, yes, you need to set another option in Mailman, "REMOVE_DKIM_HEADERS = Yes" in /etc/mailman/mm_cfg.py, this does what it says, removing the original senders DKIM headers, as they are no longer the sender, the list server is, and of course the list servers MTA would already have done SPF/DKIM checking and failed a forgery prior to passing it off to the likes of Mailman, you should probably use that option if you add in-line comments or footers.
Protecting You From Others
Next we add DMARC into your MTA, since 2008 we've used postfix, and at the time of writing is the most popular MTA in use, so this is what we are going to use here, those using sendmail or exim can adapt, and as for qmail, well, who knows
Moving along... edit /etc/postfix/main.cf, find the smtpd_milters line, this is where we previously added our socket for DKIM, this time we add in our socket as declared in opendmarc.conf, which is 127.0.0.1:8893, so we add this to our existing line, eg:
smtpd_milters = inet:127.0.0.1:8891,inet:127.0.0.1:8893then reload postfix.
Remember that we recommend setting DMARC's policy to quarantine once you have it working happily, but it also means your Mail Server will not act on policies of quarantine, opendmarc itself only acts on p=reject, so it requires your Anti Spam systems to be configured to act on quarantine and mark the message as Junk/Spam.
We use amavisd which utilises the very popular SpamAssassin, it's fairly simple to setup rules to deal with DMARC failures, an example of these rules that include some leniency for Mailing Lists, SA-dmarc.cf, can be downloaded here, place SA-dmarc.cf into /etc/mail/spamassasin and edit it where it says YOURDOMAIN, reload SpamAssassin (or amavisd if you use SpamAssassin via it instead) and you're good to go, and in-case you didn't tell opendmarc.conf to reject on p=reject, the SA rules will catch them too

Sending Daily Reports
We don't have to worry about immediate notification forensic reports as opendmarc handles that in real time since we previously set FailureReports true in opendmarc.conf, but sending daily aggregate reports needs a little setting up, as I mentioned earlier, this step is optional, but we really should do it anyway, this will require MariaDB (or MySQL) and the perl Switch module (cpan -i Switch).We need to set-up the database, to do this we first have to edit the OpenDMARC schema.mysql file, this can be found by changing into OpenDMARC's source directory, then the db directory, the second last line has the database useradd command, you need to change the password where it says changeme, make a note of it as you'll need it in the next steps, then as the database root user, load the schema.mysql file, it will create the database opendmarc and set up its tables then add the opendmarc user, once done reload the user privileges
mysql -u root -p opendmarc < schema.mysql mysqladmin flush-privilegesthat's it for SQL, let's move along to our script to process the reports sending.
To put all this into practice we need a cron job to import our history from our dat file (akin to a temp file that we set earlier in opendmarc.conf) into the SQL database, then we have another process that runs only once a day sending our aggregate reports.
To accomplish this I use a bash script in /etc/cron.d (which executes every five minutes) called dmarc_reports.sh - I know, very original

Note: Not all Linux distros are equal, so check the executables paths in the script match yours, also, as I mentioned my /etc/cron.d's scripts are run every five minutes, some distros may run them every minute, you do not want that so you'll need to set up a user cron job to call dmarc_reports.sh ever five or ten minutes instead.
Congrats, you now have SPF, DKIM, and DMARC all working to help protect you, and others, from spoofing vermin.
Comments
Display comments as Linear | Threaded
JYT on :
I'll be sure to share, thanks.
Simmo on :