Record DMARC report errors, allow additional options for DKIM policy override.

This commit is contained in:
David Baer
2020-01-23 12:50:28 -05:00
parent 00a988744e
commit 9491d5d25d
3 changed files with 21 additions and 9 deletions

View File

@@ -24,13 +24,15 @@ def parse_metadata(tree):
date_begin = datetime.fromtimestamp(int(date_begin)) date_begin = datetime.fromtimestamp(int(date_begin))
date_end, = tree.xpath('date_range/end/text()') date_end, = tree.xpath('date_range/end/text()')
date_end = datetime.fromtimestamp(int(date_end)) date_end = datetime.fromtimestamp(int(date_end))
errors = [ ReportError(txt) for txt in tree.xpath('errors/text()') ]
return Report( return Report(
org_name=org_name, org_name=org_name,
email=email, email=email,
extra_contact_info=extra_contact_info, extra_contact_info=extra_contact_info,
report_id=report_id, report_id=report_id,
date_begin=date_begin, date_begin=date_begin,
date_end=date_end date_end=date_end,
errors=errors
) )
def scoop_elements(obj, tree, *elements): def scoop_elements(obj, tree, *elements):
@@ -64,10 +66,7 @@ def parse_report(f):
scoop_elements(record, record_node.xpath('./identifiers')[0], 'envelope_to', 'header_from') scoop_elements(record, record_node.xpath('./identifiers')[0], 'envelope_to', 'header_from')
for dkim_node in record_node.xpath('./auth_results/dkim'): for dkim_node in record_node.xpath('./auth_results/dkim'):
dkim = DKIMResult() dkim = DKIMResult()
scoop_elements(dkim, dkim_node, 'domain', 'result', 'human_result') scoop_elements(dkim, dkim_node, 'domain', 'selector', 'result', 'human_result')
t = dkim_node.xpath('./selector/text()')
if len(t) > 0:
dkim.human_result = t[0]
record.dkim_results.append(dkim) record.dkim_results.append(dkim)
for spf_node in record_node.xpath('./auth_results/spf'): for spf_node in record_node.xpath('./auth_results/spf'):
spf = SPFResult() spf = SPFResult()

View File

@@ -24,9 +24,19 @@ def init_model():
Alignment = Enum('r', 's', name='alignment') Alignment = Enum('r', 's', name='alignment')
Disposition = Enum('none', 'quarantine', 'reject', name='disposition') Disposition = Enum('none', 'quarantine', 'reject', name='disposition')
DMARCResult = Enum('pass', 'fail', name='dmarc_result') DMARCResult = Enum('pass', 'fail', name='dmarc_result')
PolicyOverride = Enum('forwarded', 'sampled_out', 'trusted_forwarder', 'other', name='policy_override') PolicyOverride = Enum(
SPFResultType = Enum('none', 'neutral', 'pass', 'fail', 'softfail', 'temperror', 'permerror', name='spf_result') 'forwarded', 'sampled_out', 'trusted_forwarder',
DKIMResultType = Enum('none', 'pass', 'fail', 'policy', 'neutral', 'temperror', 'permerror', name='dkim_result') 'mailing_list', 'local_policy', 'other',
name='policy_override'
)
SPFResultType = Enum(
'none', 'neutral', 'pass', 'fail', 'softfail', 'temperror', 'permerror',
name='spf_result'
)
DKIMResultType = Enum(
'none', 'pass', 'fail', 'policy', 'neutral', 'temperror', 'permerror',
name='dkim_result'
)
class INET(satypes.TypeDecorator): class INET(satypes.TypeDecorator):
impl = satypes.CHAR impl = satypes.CHAR
@@ -59,6 +69,8 @@ class ReportError(DeclarativeBase):
report_id = Column(Integer, ForeignKey(Report.id, onupdate='CASCADE', ondelete='CASCADE'), nullable=False) report_id = Column(Integer, ForeignKey(Report.id, onupdate='CASCADE', ondelete='CASCADE'), nullable=False)
error = Column(String, nullable=False) error = Column(String, nullable=False)
report = relationship(Report, backref='errors')
class ReportRecord(DeclarativeBase): class ReportRecord(DeclarativeBase):
__tablename__ = 'report_records' __tablename__ = 'report_records'
id = Column(Integer, primary_key=True) id = Column(Integer, primary_key=True)
@@ -87,6 +99,7 @@ class DKIMResult(DeclarativeBase):
id = Column(Integer, primary_key=True) id = Column(Integer, primary_key=True)
record_id = Column(Integer, ForeignKey(ReportRecord.id, onupdate='CASCADE', ondelete='CASCADE'), nullable=False) record_id = Column(Integer, ForeignKey(ReportRecord.id, onupdate='CASCADE', ondelete='CASCADE'), nullable=False)
domain = Column(String, nullable=False) domain = Column(String, nullable=False)
selector = Column(String, nullable=True)
result = Column(DKIMResultType, nullable=False) result = Column(DKIMResultType, nullable=False)
human_result = Column(String, nullable=True) human_result = Column(String, nullable=True)

View File

@@ -16,7 +16,7 @@ install_requires=[
setup( setup(
name='DMARCReceiver', name='DMARCReceiver',
version='1.0', version='1.1',
description='Receive DMARC reports', description='Receive DMARC reports',
author='David Baer', author='David Baer',
author_email='david@amyanddavid.net', author_email='david@amyanddavid.net',