aboutsummaryrefslogtreecommitdiffstats
path: root/Mailman
diff options
context:
space:
mode:
authorMark Sapiro <mark@msapiro.net>2016-02-24 23:24:26 -0800
committerMark Sapiro <mark@msapiro.net>2016-02-24 23:24:26 -0800
commitda9d83cf1291701261bec4a9faafbe01b60a72a4 (patch)
tree7bbc1a617db09216e56d4a23ef9cec90e8240ddc /Mailman
parent3c78c57cc88877f701a935ce009efd39d31925e6 (diff)
downloadmailman2-da9d83cf1291701261bec4a9faafbe01b60a72a4.tar.gz
mailman2-da9d83cf1291701261bec4a9faafbe01b60a72a4.tar.xz
mailman2-da9d83cf1291701261bec4a9faafbe01b60a72a4.zip
If DMARC lookup fails to find a policy, also try the Organizational Domain.
Diffstat (limited to 'Mailman')
-rw-r--r--Mailman/Utils.py29
1 files changed, 25 insertions, 4 deletions
diff --git a/Mailman/Utils.py b/Mailman/Utils.py
index 1aa49954..0344ef58 100644
--- a/Mailman/Utils.py
+++ b/Mailman/Utils.py
@@ -1170,7 +1170,28 @@ def IsDMARCProhibited(mlist, email):
at_sign = email.find('@')
if at_sign < 1:
return False
- dmarc_domain = '_dmarc.' + email[at_sign+1:]
+ dparts = email[at_sign+1:].split('.')
+ # The following is a way of testing the "Organizational Domain" for DMARC
+ # policy if the From: domain doesn't publish a policy. What we're doing
+ # is clearly wrong. I.e., if the From: domain is a.b.c.example.com, we
+ # should lookup _dmarc.a.b.c.example.com and if no DMARC policy there,
+ # we should look up only _dmarc.example.com. The problem is not all
+ # Organizational Domains are two "words" and determining any particular
+ # Organizational Domain requires applying a non-trivial algorithm to a
+ # large, somewhat dynamic data set. What we do is look up all the
+ # intermediate domains on the theory that if _dmarc.a.b.c.example.com has
+ # no valid DMARC policy then the intermediates won't either. We will also
+ # err with a domain like x.y.x.co.uk. Here we will go to far and also look
+ # up _dmarc.co.uk which is also wrong but hopefully won't return a policy.
+ # This is clearly a flawed approach, but hopefully good enough.
+ while len(dparts) > 1:
+ x = _DMARCProhibited(mlist, email, '_dmarc.' + '.'.join(dparts))
+ if x != 'continue':
+ return x
+ dparts = dparts[1:]
+ return False
+
+def _DMARCProhibited(mlist, email, dmarc_domain):
try:
resolver = dns.resolver.Resolver()
@@ -1178,12 +1199,12 @@ def IsDMARCProhibited(mlist, email):
resolver.lifetime = float(mm_cfg.DMARC_RESOLVER_LIFETIME)
txt_recs = resolver.query(dmarc_domain, dns.rdatatype.TXT)
except (dns.resolver.NXDOMAIN, dns.resolver.NoAnswer):
- return False
+ return 'continue'
except DNSException, e:
syslog('error',
'DNSException: Unable to query DMARC policy for %s (%s). %s',
email, dmarc_domain, e.__class__)
- return False
+ return 'continue'
else:
# people are already being dumb, don't trust them to provide honest DNS
# where the answer section only contains what was asked for, nor to include
@@ -1223,7 +1244,7 @@ def IsDMARCProhibited(mlist, email):
dmarcs = filter(lambda n: n.startswith('v=DMARC1;'),
results_by_name[name])
if len(dmarcs) == 0:
- return False
+ return 'continue'
if len(dmarcs) > 1:
syslog('error',
"""RRset of TXT records for %s has %d v=DMARC1 entries;