DMARC / Spamassassin / Qmail
There are a lot of articles regarding DMARC so i will not start again about what it is and what is useful for. Also i will not talk about the drawbacks when it’s implemented. I will instead give you a hint about where to generate a DMARC policy and where to verify it.
Until you understand the essence please also be very conservative about the policies that you apply. The example of deployment found it on google it provides the way you should do it as well. More exactly:
- p=none pct=100
- p=quarantine pct=1
- p=quarantine pct=5
- p=quarantine pct=10
- p=quarantine pct=25
- p=quarantine pct=50
- p=quarantine pct=100
- p=reject pct=1
- p=reject pct=5
- p=reject pct=10
- p=reject pct=25
- p=reject pct=50
- p=reject pct=100
Now that you already implemented it you might receive reports(if you provided rua/ruf) about what is happening with your domains.
But what about implementing DMARC in your MTA? Usually the straight answer will be opendmarc but depending your MTA the installation will not be very easy. Since here we will talk about Qmail the solutions found by me in this moment are:
1) Qpsmtpd and opendmarc. Please also see.
2) A perl plugin written for spam-assassin.
3) Using AskDNS plugin already available in spamassasin like this:
ifplugin Mail::SpamAssassin::Plugin::AskDNS askdns __DMARC_POLICY_NONE _dmarc._AUTHORDOMAIN_ TXT /^v=DMARC1;.*\bp=none;/ askdns __DMARC_POLICY_QUAR _dmarc._AUTHORDOMAIN_ TXT /^v=DMARC1;.*\bp=quarantine;/ askdns __DMARC_POLICY_REJECT _dmarc._AUTHORDOMAIN_ TXT /^v=DMARC1;.*\bp=reject;/ meta DMARC_REJECT !(DKIM_VALID_AU || SPF_PASS) && __DMARC_POLICY_REJECT score DMARC_REJECT 10 meta DMARC_QUAR !(DKIM_VALID_AU || SPF_PASS) && __DMARC_POLICY_QUAR score DMARC_QUAR 5 meta DMARC_NONE !(DKIM_VALID_AU || SPF_PASS) && __DMARC_POLICY_NONE score DMARC_NONE 0.1 endif
Obviously edit the scores according to you needs.
4) After this article was written I’ve found out from here (btw great blog about qmail) there is another tool to use it. You can find it here.
So, what was your solution for Qmail and DMARC ? What do you use ? How do you use it ?
Later edit(17/09/2020): A plugin for spamassassin was created. This is maintained and i believe it will introduced in core in the next releases. You can find references here and here.
8 Replies to “DMARC / Spamassassin / Qmail”
Hi, I’ve just tested askDNS as recommended above and it just works! Thank you, I think I’m going to add a note about it on my blog as well and refer to this page for additional info
meta DMARC_REJECT !(DKIM_VALID_AU || SPF_PASS) && __DMARC_POLICY_REJECT
this check is invalid, this -OR- logic in the () reads:
if not (DKIM_VALID_AU -OR- SPF_PASS) AND theres a policy for the domain then reject
which means an email with assuming a policy exists (1):
!DKIM_VALID_AU and !SPF_PASS == if !(0 || 0) && 1 == 1 && 1 == 1 == ACTION (GOOD)
DKIM_VALID_AU and !SPF_PASS == if !(1 || 0) && 1 == 0 && 1 == 0 == NO ACTION (BAD)
!DKIM_VALID_AU and SPF_PASS == if !(0 || 1) && 1 == 0 && 1 == 0 == NO ACTION (BAD)
DKIM_VALID_AU and SPF_PASS == if !(1 || 1) && 1 == 0 && 1 == 0 == NO ACTION (GOOD)
if no policy exists (0) we are always NO ACTION (GOOD)
Basically its not failing out and runing the domain’s policy for a failure of individual parts.
Test with a quick perl script (play with the 3 variables up top):
#!/usr/bin/perl
$DKIM_VALID_AU = 1;
$SPF_PASS = 1;
$POLICY = 1;
$PRES = int( !($DKIM_VALID_AU || $SPF_PASS) );
$RES = int ( !($DKIM_VALID_AU || $SPF_PASS) && $POLICY );
print “DKIM_VALID_AU=$DKIM_VALID_AU SPF_PASS=$SPF_PASS PAREN RESULT=$PRES RESULT=$RES AKA: “;
if ($RES) {
print “ACTION\n”;
} else {
print “NO ACTION\n”;
}
POLICY=1 DKIM_VALID_AU=0 SPF_PASS=0 PAREN RESULT=1 RESULT=1 AKA: ACTION
POLICY=1 DKIM_VALID_AU=0 SPF_PASS=1 PAREN RESULT=0 RESULT=0 AKA: NO ACTION
POLICY=1 DKIM_VALID_AU=1 SPF_PASS=0 PAREN RESULT=0 RESULT=0 AKA: NO ACTION
POLICY=1 DKIM_VALID_AU=1 SPF_PASS=1 PAREN RESULT=0 RESULT=0 AKA: NO ACTION
The following will actually work (tested for all cases):
meta DMARC_REJECT !(DKIM_VALID_AU && SPF_PASS) && __DMARC_POLICY_REJECT
if not (DKIM_VALID_AU -AND- SPF_PASS) AND theres a policy for the domain then REJECT
Validate by changing that perl script logic to match:
#!/usr/bin/perl
$DKIM_VALID_AU = 1;
$SPF_PASS = 1;
$POLICY = 1;
$PRES = int( !($DKIM_VALID_AU && $SPF_PASS) );
$RES = int ( !($DKIM_VALID_AU && $SPF_PASS) && $POLICY );
print “DKIM_VALID_AU=$DKIM_VALID_AU SPF_PASS=$SPF_PASS PAREN RESULT=$PRES RESULT=$RES AKA: “;
if ($RES) {
print “ACTION\n”;
} else {
print “NO ACTION\n”;
}
POLICY=1 DKIM_VALID_AU=1 SPF_PASS=1 PAREN RESULT=0 RESULT=0 AKA: NO ACTION
POLICY=1 DKIM_VALID_AU=0 SPF_PASS=1 PAREN RESULT=1 RESULT=1 AKA: ACTION
POLICY=1 DKIM_VALID_AU=1 SPF_PASS=0 PAREN RESULT=1 RESULT=1 AKA: ACTION
POLICY=1 DKIM_VALID_AU=0 SPF_PASS=0 PAREN RESULT=1 RESULT=1 AKA: ACTION
POLICY=0 DKIM_VALID_AU=1 SPF_PASS=1 PAREN RESULT=0 RESULT=0 AKA: NO ACTION
POLICY=0 DKIM_VALID_AU=0 SPF_PASS=0 PAREN RESULT=1 RESULT=0 AKA: NO ACTION
If any of the conditions are 0 (fail) then the policy is enforced. If everything checks out its ignored. No policy means no action.
Thanks so much for the information about how to set the DMARC check up via AskDNS. Hopefully this correction helps make this method even better.
Unfortunately you started from the assumption that you need to configure either DKIM or SPF in order to have DMARC working properly.
I want that both SPF and DKIM to fail especially when it’s about such a punitive action as REJECT. Moreover SPF and DKIM may be altered during transit(forward for example) and we don’t want to discard a perfect valid email because of that.
For the above reasons when you start to deploy DMARC you start with “p=none”. In this way no punitive action will be made when errors are occurring in SPF or DKIM.
Please see other details on: https://dmarc.org/wiki/FAQ#How_does_DMARC_work.2C_briefly.2C_and_in_non-technical_terms.3F
Well setting p=none is your outbound policy, what you expect others to do. What we are talking about here is what you will do with email you’re receiving given another domains policy instruction. The DMARC spec reads if EITHER fails you should do what the domain instructs you to do. but if you’d like to make it so BOTH must fail you can, the beauty of the comment above is the explanation of the logic and therefor choice, but to be compliant with what should be happening it should be if either one fails. so the && logic. If you want to take into account the domain alignment and such this method wont work, but it’s quick and dirty and will work for most email.
It was never about the math.
You math is fine and i understand your point but you started your investigation from the fact that in order for DMARC to pass you should have DKIM OR(and not AND) SPF to pass.
Actually the DMARC specs ( if you read RFC7489) is leaving a lot of space for interpretation. Plus this is not a standard but an informational RFC.
Just two examples:
1) is actually is enforcing that DMARC should not replace local policy.
I quote: “Mail Receivers MAY choose to reject or quarantine email even if email passes the DMARC mechanism check. The DMARC mechanism does not inform Mail Receivers whether an email stream is “good”. Mail Receivers are encouraged to maintain anti-abuse technologies to combat the possibility of DMARC-enabled criminal campaigns.”
2) is saying that “different treatment of messages that are not authenticated versus those that fail authentication” is not in the scope of this RFC.
It was never about “&& ||” but about how sure i am when i want to reject. Since both DKIM and SPF have their own flows which can be exploited in the benefit of a rogue actor i want to be very sure when i REJECT that message. Moreover my approach(which you might think is more relaxed) is also covering the situation when you don’t have the correct information about a DKIM/SPF due to a DNS issue at that time.
Long story short i prefer to build on a scoring mechanism and double check the info(in my case DKIM and SPF must fail for a DMARC rejection) rather than immediately rejecting based on only one of them.
In an ideal world where all the e-mail/domain administrator will correctly cover DKIM/SPF/DMARC than you might think to put && instead ||. In this world where false positive can be easily created due to unmaintained/incorrectly configuration i prefer to double check. Hope that make more sense now.
Am I right that these rules don’t work correctly (and might be quite easy to avoid by spammers) when it comes to mails that use different domains in the “From” header address and the envelope sender?
Ordinary SPF (and therefore the spamassassin SPF_PASS test) only works with the envelope sender, which is often not visible to users. DKIM and DMARC are supposed to check the “From” header address, however the rules in this blog post will ignore this address if only the envelope sender address passes the SPF checks.
Sorry but i don’t get your point. This post is not about what is visible to end-user but more about combining different technologies ( SPF, DKIM and DMARC) in such way to add more value to Spammassassin.
Since DMARC was not present in Spammassasin by default trough a plugin this was/is a technique to bring also DMARC in equation. It doesn’t mean that you don’t check anymore anything else.