Merge pull request #122 from michaeldavie/handle_bad_data

Handle invalid aggregate reports
This commit is contained in:
Sean Whalen
2019-11-06 12:40:05 -05:00
committed by GitHub
5 changed files with 100 additions and 7 deletions
+18 -6
View File
@@ -24,6 +24,7 @@ import mailbox
import mailparser
from expiringdict import ExpiringDict
import xmltodict
from lxml import etree
from mailsuite.imap import IMAPClient
from mailsuite.smtp import send_email
@@ -133,7 +134,10 @@ def _parse_report_record(record, offline=False, nameservers=None,
new_record["policy_evaluated"] = new_policy_evaluated
new_record["identifiers"] = record["identifiers"].copy()
new_record["auth_results"] = OrderedDict([("dkim", []), ("spf", [])])
lowered_from = new_record["identifiers"]["header_from"].lower()
if type(new_record["identifiers"]["header_from"]) == str:
lowered_from = new_record["identifiers"]["header_from"].lower()
else:
lowered_from = ''
new_record["identifiers"]["header_from"] = lowered_from
if record["auth_results"] is not None:
auth_results = record["auth_results"].copy()
@@ -215,10 +219,13 @@ def parse_aggregate_report_xml(xml, offline=False, nameservers=None,
"""
errors = []
# Parse XML and recover from errors
try:
xmltodict.parse(xml)["feedback"]
except Exception as e:
errors.append(e.__str__())
tree = etree.parse(BytesIO(xml.encode('utf-8')),
etree.XMLParser(recover=True))
xml = etree.tostring(tree).decode('utf-8')
try:
# Replace XML header (sometimes they are invalid)
@@ -355,11 +362,11 @@ def extract_xml(input_):
file_object.seek(0)
if header.startswith(MAGIC_ZIP):
_zip = zipfile.ZipFile(file_object)
xml = _zip.open(_zip.namelist()[0]).read().decode()
xml = _zip.open(_zip.namelist()[0]).read().decode(errors='ignore')
elif header.startswith(MAGIC_GZIP):
xml = GzipFile(fileobj=file_object).read().decode()
xml = GzipFile(fileobj=file_object).read().decode(errors='ignore')
elif header.startswith(MAGIC_XML):
xml = file_object.read().decode()
xml = file_object.read().decode(errors='ignore')
else:
file_object.close()
raise InvalidAggregateReport("Not a valid zip, gzip, or xml file")
@@ -419,7 +426,7 @@ def parsed_aggregate_reports_to_csv_rows(reports):
return str(obj).lower()
if type(reports) == OrderedDict:
reports = [reports]
reports = [reports['report']]
rows = []
@@ -497,6 +504,11 @@ def parsed_aggregate_reports_to_csv_rows(reports):
row["spf_results"] = ",".join(map(to_str, dkim_results))
rows.append(row)
for r in rows:
for k, v in r.items():
if type(v) is not str:
r[k] = ''
return rows
+1
View File
@@ -29,3 +29,4 @@ sphinx>=1.0.5
sphinx_rtd_theme>=0.4.3
wheel>=0.33.6
codecov>=2.0.15
lxml>=4.4.1
+40
View File
@@ -0,0 +1,40 @@
<?xml version="1.0" encoding="UTF-8" ?>
<feedback>
<report_metadata>
<org_name></org_name>
<email>administrator@accurateplastics.com</email>
<report_id>example.com:1538463741</report_id>
<date_range>
<begin>1538413632</begin>
<end>1538413632</end>
</date_range>
</report_metadata>
<policy_published>
<domain>example.com</domain>
<adkim>r</adkim>
<aspf>r</aspf>
<p>none</p>
<sp>reject</sp>
<pct>100</pct>
</policy_published>
<record>
<row>
<source_ip>12.20.127.122</source_ip>
<count>1</count>
<policy_evaluated>
<disposition>none</disposition>
<dkim>fail</dkim>
<spf>fail</spf>
</policy_evaluated>
</row>
<identifiers>
<header_from>bad_byte</header_from>
</identifiers>
<auth_results>
<spf>
<domain></domain>
<result>none</result>
</spf>
</auth_results>
</record>
</feedback>
+40
View File
@@ -0,0 +1,40 @@
<?xml version="1.0" encoding="UTF-8" ?>
<feedback>
<report_metadata>
<org_name>veeam.com</org_name>
<email><bad-xml@bad-xml.net></email>
<report_id>sonexushealth.com:1530233361</report_id>
<date_range>
<begin>1530133200</begin>
<end>1530219600</end>
</date_range>
</report_metadata>
<policy_published>
<domain>example.com</domain>
<adkim>r</adkim>
<aspf>r</aspf>
<p>none</p>
<sp>none</sp>
<pct>100</pct>
</policy_published>
<record>
<row>
<source_ip>199.230.200.36</source_ip>
<count>1</count>
<policy_evaluated>
<disposition>none</disposition>
<dkim>fail</dkim>
<spf>fail</spf>
</policy_evaluated>
</row>
<identifiers>
<header_from>bad<xml.net</header_from>
</identifiers>
<auth_results>
<spf>
<domain></domain>
<result>none</result>
</spf>
</auth_results>
</record>
</feedback>
+1 -1
View File
@@ -104,7 +104,7 @@ setup(
'elasticsearch>=6.3.1,<7.0.0',
'elasticsearch-dsl>=6.3.1,<7.0.0',
'kafka-python>=1.4.4',
'tqdm>=4.31.1'
'tqdm>=4.31.1', 'lxml>=4.4.1'
],
entry_points={