summaryrefslogtreecommitdiff
path: root/src/mailman/rules/docs/dmarc-mitigation.rst
blob: 9a6fa5b9b195f6a9a9965e9bd65274f03ad08fbd (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
================
DMARC mitigation
================

This rule only matches in order to jump to the moderation chain to reject
or discard the message.  The rule looks at the list's dmarc_mitigate_action
and if it is other than 'no_mitigation', it checks the domain of the From:
address for a DMARC policy and depending on settings may reject or discard
the message or just flag it for the dmarc handler to apply DMARC mitigations
to the message.

    >>> mlist = create_list('_xtest@example.com')
    >>> rule = config.rules['dmarc-mitigation']
    >>> print(rule.name)
    dmarc-mitigation

First we set up a mock patcher to return predictable responses to DNS lookups.
This returns p=reject for the example.biz domain and not for any others.

    >>> from mailman.rules.tests.test_dmarc import get_dns_resolver
    >>> patcher = get_dns_resolver()

And we do a similar thing to mock the organizational domain data.

    >>> from mailman.rules.tests.test_dmarc import get_org_data
    >>> patcher2 = get_org_data()


A message From: a domain without a DMARC policy does not set any flags.

    >>> from mailman.interfaces.mailinglist import DMARCMitigateAction
    >>> mlist.dmarc_mitigate_action = DMARCMitigateAction.munge_from
    >>> msg = message_from_string("""\
    ... From: aperson@example.org
    ... To: _xtest@example.com
    ... Subject: A posted message
    ...
    ... """)
    >>> msgdata = {}
    >>> with patcher as Resolver, patcher2 as urlopen:
    ...     rule.check(mlist, msg, msgdata)
    False
    >>> msgdata == {}
    True

Even if the From: domain publishes p=reject, no flags are set if the list's
action is no_mitigation.

    >>> mlist.dmarc_mitigate_action = DMARCMitigateAction.no_mitigation
    >>> msg = message_from_string("""\
    ... From: aperson@example.biz
    ... To: _xtest@example.com
    ... Subject: A posted message
    ...
    ... """)
    >>> msgdata = {}
    >>> with patcher as Resolver, patcher2 as urlopen:
    ...     rule.check(mlist, msg, msgdata)
    False
    >>> msgdata == {}
    True

But with a different list setting, the message is flagged.

    >>> mlist.dmarc_mitigate_action = DMARCMitigateAction.munge_from
    >>> msg = message_from_string("""\
    ... From: aperson@example.biz
    ... To: _xtest@example.com
    ... Subject: A posted message
    ...
    ... """)
    >>> msgdata = {}
    >>> with patcher as Resolver, patcher2 as urlopen:
    ...     rule.check(mlist, msg, msgdata)
    False
    >>> msgdata['dmarc']
    True

Subdomains which don't have a policy will check the organizational domain.

    >>> msg = message_from_string("""\
    ... From: aperson@sub.domain.example.biz
    ... To: _xtest@example.com
    ... Subject: A posted message
    ...
    ... """)
    >>> msgdata = {}
    >>> with patcher as Resolver, patcher2 as urlopen:
    ...     rule.check(mlist, msg, msgdata)
    False
    >>> msgdata['dmarc']
    True

The list's action can also be set to immediately discard or reject the
message.

    >>> mlist.dmarc_mitigate_action = DMARCMitigateAction.discard
    >>> msg = message_from_string("""\
    ... From: aperson@example.biz
    ... To: _xtest@example.com
    ... Subject: A posted message
    ... Message-ID: <xxx_message_id@example.biz>
    ...
    ... """)
    >>> msgdata = {}
    >>> with patcher as Resolver, patcher2 as urlopen:
    ...     rule.check(mlist, msg, msgdata)
    True
    >>> msgdata['dmarc']
    True
    >>> msgdata['moderation_action']
    'discard'

We can reject the message with a default reason.

    >>> mlist.dmarc_mitigate_action = DMARCMitigateAction.reject
    >>> msg = message_from_string("""\
    ... From: aperson@example.biz
    ... To: _xtest@example.com
    ... Subject: A posted message
    ... Message-ID: <xxx_message_id@example.biz>
    ...
    ... """)
    >>> msgdata = {}
    >>> with patcher as Resolver, patcher2 as urlopen:
    ...     rule.check(mlist, msg, msgdata)
    True
    >>> msgdata['dmarc']
    True
    >>> msgdata['moderation_action']
    'reject'
    >>> msgdata['moderation_reasons']
    ['You are not allowed to post to this mailing list From: a domain ...

And, we can reject with a custom message.

    >>> mlist.dmarc_moderation_notice = 'A silly reason'
    >>> msg = message_from_string("""\
    ... From: aperson@example.biz
    ... To: _xtest@example.com
    ... Subject: A posted message
    ... Message-ID: <xxx_message_id@example.biz>
    ...
    ... """)
    >>> msgdata = {}
    >>> with patcher as Resolver, patcher2 as urlopen:
    ...     rule.check(mlist, msg, msgdata)
    True
    >>> msgdata['dmarc']
    True
    >>> msgdata['moderation_action']
    'reject'
    >>> msgdata['moderation_reasons']
    ['A silly reason']