mirror of
https://github.com/domainaware/parsedmarc.git
synced 2026-08-17 20:53:18 +00:00
2.0.0
This commit is contained in:
+4
-4
@@ -8,7 +8,7 @@
|
||||
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
|
||||
<title>Overview: module code — parsedmarc 1.1.0 documentation</title>
|
||||
<title>Overview: module code — parsedmarc 2.0.0 documentation</title>
|
||||
|
||||
|
||||
|
||||
@@ -35,7 +35,7 @@
|
||||
<link rel="index" title="Index"
|
||||
href="../genindex.html"/>
|
||||
<link rel="search" title="Search" href="../search.html"/>
|
||||
<link rel="top" title="parsedmarc 1.1.0 documentation" href="../index.html"/>
|
||||
<link rel="top" title="parsedmarc 2.0.0 documentation" href="../index.html"/>
|
||||
|
||||
|
||||
<script src="../_static/js/modernizr.min.js"></script>
|
||||
@@ -64,7 +64,7 @@
|
||||
|
||||
|
||||
<div class="version">
|
||||
1.1.0
|
||||
2.0.0
|
||||
</div>
|
||||
|
||||
|
||||
@@ -187,7 +187,7 @@
|
||||
<script type="text/javascript">
|
||||
var DOCUMENTATION_OPTIONS = {
|
||||
URL_ROOT:'../',
|
||||
VERSION:'1.1.0',
|
||||
VERSION:'2.0.0',
|
||||
COLLAPSE_INDEX:false,
|
||||
FILE_SUFFIX:'.html',
|
||||
HAS_SOURCE: true,
|
||||
|
||||
+729
-65
@@ -8,7 +8,7 @@
|
||||
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
|
||||
<title>parsedmarc — parsedmarc 1.1.0 documentation</title>
|
||||
<title>parsedmarc — parsedmarc 2.0.0 documentation</title>
|
||||
|
||||
|
||||
|
||||
@@ -35,7 +35,7 @@
|
||||
<link rel="index" title="Index"
|
||||
href="../genindex.html"/>
|
||||
<link rel="search" title="Search" href="../search.html"/>
|
||||
<link rel="top" title="parsedmarc 1.1.0 documentation" href="../index.html"/>
|
||||
<link rel="top" title="parsedmarc 2.0.0 documentation" href="../index.html"/>
|
||||
<link rel="up" title="Module code" href="index.html"/>
|
||||
|
||||
|
||||
@@ -65,7 +65,7 @@
|
||||
|
||||
|
||||
<div class="version">
|
||||
1.1.0
|
||||
2.0.0
|
||||
</div>
|
||||
|
||||
|
||||
@@ -156,13 +156,13 @@
|
||||
<span></span><span class="ch">#!/usr/bin/env python</span>
|
||||
<span class="c1"># -*- coding: utf-8 -*-</span>
|
||||
|
||||
<span class="sd">"""A Python module and CLI for parsing aggregate DMARC reports"""</span>
|
||||
<span class="sd">"""A Python module and CLI for parsing DMARC reports"""</span>
|
||||
|
||||
<span class="kn">from</span> <span class="nn">__future__</span> <span class="k">import</span> <span class="n">unicode_literals</span><span class="p">,</span> <span class="n">print_function</span><span class="p">,</span> <span class="n">absolute_import</span>
|
||||
|
||||
<span class="kn">import</span> <span class="nn">logging</span>
|
||||
<span class="kn">from</span> <span class="nn">sys</span> <span class="k">import</span> <span class="n">version_info</span>
|
||||
<span class="kn">from</span> <span class="nn">os</span> <span class="k">import</span> <span class="n">path</span><span class="p">,</span> <span class="n">stat</span>
|
||||
<span class="kn">import</span> <span class="nn">os</span>
|
||||
<span class="kn">import</span> <span class="nn">json</span>
|
||||
<span class="kn">from</span> <span class="nn">datetime</span> <span class="k">import</span> <span class="n">datetime</span>
|
||||
<span class="kn">from</span> <span class="nn">collections</span> <span class="k">import</span> <span class="n">OrderedDict</span>
|
||||
@@ -172,9 +172,16 @@
|
||||
<span class="kn">import</span> <span class="nn">tarfile</span>
|
||||
<span class="kn">from</span> <span class="nn">zipfile</span> <span class="k">import</span> <span class="n">ZipFile</span>
|
||||
<span class="kn">from</span> <span class="nn">csv</span> <span class="k">import</span> <span class="n">DictWriter</span>
|
||||
<span class="kn">import</span> <span class="nn">re</span>
|
||||
<span class="kn">from</span> <span class="nn">base64</span> <span class="k">import</span> <span class="n">b64decode</span>
|
||||
<span class="kn">import</span> <span class="nn">shutil</span>
|
||||
<span class="kn">from</span> <span class="nn">argparse</span> <span class="k">import</span> <span class="n">ArgumentParser</span>
|
||||
<span class="kn">from</span> <span class="nn">glob</span> <span class="k">import</span> <span class="n">glob</span>
|
||||
<span class="kn">import</span> <span class="nn">email</span>
|
||||
<span class="kn">import</span> <span class="nn">tempfile</span>
|
||||
<span class="kn">import</span> <span class="nn">subprocess</span>
|
||||
<span class="kn">import</span> <span class="nn">socket</span>
|
||||
<span class="kn">from</span> <span class="nn">time</span> <span class="k">import</span> <span class="n">sleep</span>
|
||||
|
||||
<span class="kn">import</span> <span class="nn">publicsuffix</span>
|
||||
<span class="kn">import</span> <span class="nn">xmltodict</span>
|
||||
@@ -184,11 +191,15 @@
|
||||
<span class="kn">from</span> <span class="nn">requests</span> <span class="k">import</span> <span class="n">get</span>
|
||||
<span class="kn">import</span> <span class="nn">geoip2.database</span>
|
||||
<span class="kn">import</span> <span class="nn">geoip2.errors</span>
|
||||
<span class="kn">import</span> <span class="nn">imapclient</span>
|
||||
<span class="kn">import</span> <span class="nn">imapclient.exceptions</span>
|
||||
<span class="kn">import</span> <span class="nn">dateparser</span>
|
||||
<span class="kn">import</span> <span class="nn">mailparser</span>
|
||||
|
||||
<span class="n">__version__</span> <span class="o">=</span> <span class="s2">"1.1.0"</span>
|
||||
<span class="n">__version__</span> <span class="o">=</span> <span class="s2">"2.0.0"</span>
|
||||
|
||||
<span class="n">logger</span> <span class="o">=</span> <span class="n">logging</span><span class="o">.</span><span class="n">getLogger</span><span class="p">(</span><span class="vm">__name__</span><span class="p">)</span>
|
||||
<span class="n">logger</span><span class="o">.</span><span class="n">setLevel</span><span class="p">(</span><span class="n">logging</span><span class="o">.</span><span class="n">WARNING</span><span class="p">)</span>
|
||||
<span class="n">logger</span><span class="o">.</span><span class="n">setLevel</span><span class="p">(</span><span class="n">logging</span><span class="o">.</span><span class="n">INFO</span><span class="p">)</span>
|
||||
|
||||
|
||||
<span class="c1"># Python 2 comparability hack</span>
|
||||
@@ -196,10 +207,29 @@
|
||||
<span class="n">unicode</span> <span class="o">=</span> <span class="nb">str</span>
|
||||
|
||||
|
||||
<div class="viewcode-block" id="InvalidAggregateReport"><a class="viewcode-back" href="../index.html#parsedmarc.InvalidAggregateReport">[docs]</a><span class="k">class</span> <span class="nc">InvalidAggregateReport</span><span class="p">(</span><span class="ne">Exception</span><span class="p">):</span>
|
||||
<span class="n">feedback_report_regex</span> <span class="o">=</span> <span class="n">re</span><span class="o">.</span><span class="n">compile</span><span class="p">(</span><span class="sa">r</span><span class="s2">"^([\w\-]+): (.+)$"</span><span class="p">,</span> <span class="n">re</span><span class="o">.</span><span class="n">MULTILINE</span><span class="p">)</span>
|
||||
|
||||
|
||||
<div class="viewcode-block" id="ParserError"><a class="viewcode-back" href="../index.html#parsedmarc.ParserError">[docs]</a><span class="k">class</span> <span class="nc">ParserError</span><span class="p">(</span><span class="ne">RuntimeError</span><span class="p">):</span>
|
||||
<span class="sd">"""Raised whenever the parser fails for some reason"""</span></div>
|
||||
|
||||
|
||||
<div class="viewcode-block" id="IMAPError"><a class="viewcode-back" href="../index.html#parsedmarc.IMAPError">[docs]</a><span class="k">class</span> <span class="nc">IMAPError</span><span class="p">(</span><span class="ne">RuntimeError</span><span class="p">):</span>
|
||||
<span class="sd">"""Raised when an IMAP error occurs"""</span></div>
|
||||
|
||||
|
||||
<div class="viewcode-block" id="InvalidDMARCReport"><a class="viewcode-back" href="../index.html#parsedmarc.InvalidDMARCReport">[docs]</a><span class="k">class</span> <span class="nc">InvalidDMARCReport</span><span class="p">(</span><span class="n">ParserError</span><span class="p">):</span>
|
||||
<span class="sd">"""Raised when an invalid DMARC report is encountered"""</span></div>
|
||||
|
||||
|
||||
<div class="viewcode-block" id="InvalidAggregateReport"><a class="viewcode-back" href="../index.html#parsedmarc.InvalidAggregateReport">[docs]</a><span class="k">class</span> <span class="nc">InvalidAggregateReport</span><span class="p">(</span><span class="n">InvalidDMARCReport</span><span class="p">):</span>
|
||||
<span class="sd">"""Raised when an invalid DMARC aggregate report is encountered"""</span></div>
|
||||
|
||||
|
||||
<div class="viewcode-block" id="InvalidForensicReport"><a class="viewcode-back" href="../index.html#parsedmarc.InvalidForensicReport">[docs]</a><span class="k">class</span> <span class="nc">InvalidForensicReport</span><span class="p">(</span><span class="n">InvalidDMARCReport</span><span class="p">):</span>
|
||||
<span class="sd">"""Raised when an invalid DMARC forensic report is encountered"""</span></div>
|
||||
|
||||
|
||||
<span class="k">def</span> <span class="nf">_get_base_domain</span><span class="p">(</span><span class="n">domain</span><span class="p">):</span>
|
||||
<span class="sd">"""</span>
|
||||
<span class="sd"> Gets the base domain name for the given domain</span>
|
||||
@@ -222,16 +252,16 @@
|
||||
|
||||
<span class="k">def</span> <span class="nf">download_psl</span><span class="p">():</span>
|
||||
<span class="n">fresh_psl</span> <span class="o">=</span> <span class="n">publicsuffix</span><span class="o">.</span><span class="n">fetch</span><span class="p">()</span>
|
||||
<span class="k">with</span> <span class="nb">open</span><span class="p">(</span><span class="n">psl_path</span><span class="p">,</span> <span class="s2">"w"</span><span class="p">,</span> <span class="n">encoding</span><span class="o">=</span><span class="s2">"utf-8"</span><span class="p">)</span> <span class="k">as</span> <span class="n">fresh_psl_file</span><span class="p">:</span>
|
||||
<span class="k">with</span> <span class="nb">open</span><span class="p">(</span><span class="n">psl_path</span><span class="p">,</span> <span class="s2">"w"</span><span class="p">)</span> <span class="k">as</span> <span class="n">fresh_psl_file</span><span class="p">:</span>
|
||||
<span class="n">fresh_psl_file</span><span class="o">.</span><span class="n">write</span><span class="p">(</span><span class="n">fresh_psl</span><span class="o">.</span><span class="n">read</span><span class="p">())</span>
|
||||
|
||||
<span class="k">return</span> <span class="n">publicsuffix</span><span class="o">.</span><span class="n">PublicSuffixList</span><span class="p">(</span><span class="n">fresh_psl</span><span class="p">)</span>
|
||||
|
||||
<span class="k">if</span> <span class="ow">not</span> <span class="n">path</span><span class="o">.</span><span class="n">exists</span><span class="p">(</span><span class="n">psl_path</span><span class="p">):</span>
|
||||
<span class="k">if</span> <span class="ow">not</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">exists</span><span class="p">(</span><span class="n">psl_path</span><span class="p">):</span>
|
||||
<span class="n">psl</span> <span class="o">=</span> <span class="n">download_psl</span><span class="p">()</span>
|
||||
<span class="k">else</span><span class="p">:</span>
|
||||
<span class="n">psl_age</span> <span class="o">=</span> <span class="n">datetime</span><span class="o">.</span><span class="n">now</span><span class="p">()</span> <span class="o">-</span> <span class="n">datetime</span><span class="o">.</span><span class="n">fromtimestamp</span><span class="p">(</span>
|
||||
<span class="n">stat</span><span class="p">(</span><span class="n">psl_path</span><span class="p">)</span><span class="o">.</span><span class="n">st_mtime</span><span class="p">)</span>
|
||||
<span class="n">os</span><span class="o">.</span><span class="n">stat</span><span class="p">(</span><span class="n">psl_path</span><span class="p">)</span><span class="o">.</span><span class="n">st_mtime</span><span class="p">)</span>
|
||||
<span class="k">if</span> <span class="n">psl_age</span> <span class="o">></span> <span class="n">timedelta</span><span class="p">(</span><span class="n">hours</span><span class="o">=</span><span class="mi">24</span><span class="p">):</span>
|
||||
<span class="n">psl</span> <span class="o">=</span> <span class="n">download_psl</span><span class="p">()</span>
|
||||
<span class="k">else</span><span class="p">:</span>
|
||||
@@ -365,16 +395,16 @@
|
||||
<span class="n">db_path</span> <span class="o">=</span> <span class="s2">""</span>
|
||||
|
||||
<span class="k">for</span> <span class="n">system_path</span> <span class="ow">in</span> <span class="n">system_paths</span><span class="p">:</span>
|
||||
<span class="k">if</span> <span class="n">path</span><span class="o">.</span><span class="n">exists</span><span class="p">(</span><span class="n">system_path</span><span class="p">):</span>
|
||||
<span class="k">if</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">exists</span><span class="p">(</span><span class="n">system_path</span><span class="p">):</span>
|
||||
<span class="n">db_path</span> <span class="o">=</span> <span class="n">system_path</span>
|
||||
<span class="k">break</span>
|
||||
|
||||
<span class="k">if</span> <span class="n">db_path</span> <span class="o">==</span> <span class="s2">""</span><span class="p">:</span>
|
||||
<span class="k">if</span> <span class="ow">not</span> <span class="n">path</span><span class="o">.</span><span class="n">exists</span><span class="p">(</span><span class="n">db_filename</span><span class="p">):</span>
|
||||
<span class="k">if</span> <span class="ow">not</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">exists</span><span class="p">(</span><span class="n">db_filename</span><span class="p">):</span>
|
||||
<span class="n">download_country_database</span><span class="p">(</span><span class="n">db_filename</span><span class="p">)</span>
|
||||
<span class="k">else</span><span class="p">:</span>
|
||||
<span class="n">db_age</span> <span class="o">=</span> <span class="n">datetime</span><span class="o">.</span><span class="n">now</span><span class="p">()</span> <span class="o">-</span> <span class="n">datetime</span><span class="o">.</span><span class="n">fromtimestamp</span><span class="p">(</span>
|
||||
<span class="n">stat</span><span class="p">(</span><span class="n">db_filename</span><span class="p">)</span><span class="o">.</span><span class="n">st_mtime</span><span class="p">)</span>
|
||||
<span class="n">os</span><span class="o">.</span><span class="n">stat</span><span class="p">(</span><span class="n">db_filename</span><span class="p">)</span><span class="o">.</span><span class="n">st_mtime</span><span class="p">)</span>
|
||||
<span class="k">if</span> <span class="n">db_age</span> <span class="o">></span> <span class="n">timedelta</span><span class="p">(</span><span class="n">days</span><span class="o">=</span><span class="mi">60</span><span class="p">):</span>
|
||||
<span class="n">shutil</span><span class="o">.</span><span class="n">rmtree</span><span class="p">(</span><span class="n">db_path</span><span class="p">)</span>
|
||||
<span class="n">download_country_database</span><span class="p">()</span>
|
||||
@@ -392,6 +422,36 @@
|
||||
<span class="k">return</span> <span class="n">country</span>
|
||||
|
||||
|
||||
<span class="k">def</span> <span class="nf">_get_ip_address_info</span><span class="p">(</span><span class="n">ip_address</span><span class="p">,</span> <span class="n">nameservers</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span> <span class="n">timeout</span><span class="o">=</span><span class="mf">6.0</span><span class="p">):</span>
|
||||
<span class="sd">"""</span>
|
||||
<span class="sd"> Returns reverse DNS and country information for the given IP address</span>
|
||||
|
||||
<span class="sd"> Args:</span>
|
||||
<span class="sd"> ip_address: The IP address to check</span>
|
||||
<span class="sd"> nameservers (list): A list of one or more nameservers to use</span>
|
||||
<span class="sd"> timeout (float): Sets the DNS timeout in seconds</span>
|
||||
|
||||
<span class="sd"> Returns:</span>
|
||||
<span class="sd"> OrderedDict: ``ip_address``, ``reverse_dns``</span>
|
||||
|
||||
<span class="sd"> """</span>
|
||||
<span class="n">ip_address</span> <span class="o">=</span> <span class="n">ip_address</span><span class="o">.</span><span class="n">lower</span><span class="p">()</span>
|
||||
<span class="n">info</span> <span class="o">=</span> <span class="n">OrderedDict</span><span class="p">()</span>
|
||||
<span class="n">info</span><span class="p">[</span><span class="s2">"ip_address"</span><span class="p">]</span> <span class="o">=</span> <span class="n">ip_address</span>
|
||||
<span class="n">reverse_dns</span> <span class="o">=</span> <span class="n">_get_reverse_dns</span><span class="p">(</span><span class="n">ip_address</span><span class="p">,</span>
|
||||
<span class="n">nameservers</span><span class="o">=</span><span class="n">nameservers</span><span class="p">,</span>
|
||||
<span class="n">timeout</span><span class="o">=</span><span class="n">timeout</span><span class="p">)</span>
|
||||
<span class="n">country</span> <span class="o">=</span> <span class="n">_get_ip_address_country</span><span class="p">(</span><span class="n">ip_address</span><span class="p">)</span>
|
||||
<span class="n">info</span><span class="p">[</span><span class="s2">"country"</span><span class="p">]</span> <span class="o">=</span> <span class="n">country</span>
|
||||
<span class="n">info</span><span class="p">[</span><span class="s2">"reverse_dns"</span><span class="p">]</span> <span class="o">=</span> <span class="n">reverse_dns</span>
|
||||
<span class="n">info</span><span class="p">[</span><span class="s2">"base_domain"</span><span class="p">]</span> <span class="o">=</span> <span class="kc">None</span>
|
||||
<span class="k">if</span> <span class="n">reverse_dns</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span><span class="p">:</span>
|
||||
<span class="n">base_domain</span> <span class="o">=</span> <span class="n">_get_base_domain</span><span class="p">(</span><span class="n">reverse_dns</span><span class="p">)</span>
|
||||
<span class="n">info</span><span class="p">[</span><span class="s2">"base_domain"</span><span class="p">]</span> <span class="o">=</span> <span class="n">base_domain</span>
|
||||
|
||||
<span class="k">return</span> <span class="n">info</span>
|
||||
|
||||
|
||||
<span class="k">def</span> <span class="nf">_parse_report_record</span><span class="p">(</span><span class="n">record</span><span class="p">,</span> <span class="n">nameservers</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span> <span class="n">timeout</span><span class="o">=</span><span class="mf">6.0</span><span class="p">):</span>
|
||||
<span class="sd">"""</span>
|
||||
<span class="sd"> Converts a record from a DMARC aggregate report into a more consistent</span>
|
||||
@@ -407,18 +467,9 @@
|
||||
<span class="sd"> """</span>
|
||||
<span class="n">record</span> <span class="o">=</span> <span class="n">record</span><span class="o">.</span><span class="n">copy</span><span class="p">()</span>
|
||||
<span class="n">new_record</span> <span class="o">=</span> <span class="n">OrderedDict</span><span class="p">()</span>
|
||||
<span class="n">new_record</span><span class="p">[</span><span class="s2">"source"</span><span class="p">]</span> <span class="o">=</span> <span class="n">OrderedDict</span><span class="p">()</span>
|
||||
<span class="n">new_record</span><span class="p">[</span><span class="s2">"source"</span><span class="p">][</span><span class="s2">"ip_address"</span><span class="p">]</span> <span class="o">=</span> <span class="n">record</span><span class="p">[</span><span class="s2">"row"</span><span class="p">][</span><span class="s2">"source_ip"</span><span class="p">]</span>
|
||||
<span class="n">reverse_dns</span> <span class="o">=</span> <span class="n">_get_reverse_dns</span><span class="p">(</span><span class="n">new_record</span><span class="p">[</span><span class="s2">"source"</span><span class="p">][</span><span class="s2">"ip_address"</span><span class="p">],</span>
|
||||
<span class="n">nameservers</span><span class="o">=</span><span class="n">nameservers</span><span class="p">,</span>
|
||||
<span class="n">timeout</span><span class="o">=</span><span class="n">timeout</span><span class="p">)</span>
|
||||
<span class="n">country</span> <span class="o">=</span> <span class="n">_get_ip_address_country</span><span class="p">(</span><span class="n">new_record</span><span class="p">[</span><span class="s2">"source"</span><span class="p">][</span><span class="s2">"ip_address"</span><span class="p">])</span>
|
||||
<span class="n">new_record</span><span class="p">[</span><span class="s2">"source"</span><span class="p">][</span><span class="s2">"country"</span><span class="p">]</span> <span class="o">=</span> <span class="n">country</span>
|
||||
<span class="n">new_record</span><span class="p">[</span><span class="s2">"source"</span><span class="p">][</span><span class="s2">"reverse_dns"</span><span class="p">]</span> <span class="o">=</span> <span class="n">reverse_dns</span>
|
||||
<span class="n">new_record</span><span class="p">[</span><span class="s2">"source"</span><span class="p">][</span><span class="s2">"base_domain"</span><span class="p">]</span> <span class="o">=</span> <span class="kc">None</span>
|
||||
<span class="k">if</span> <span class="n">new_record</span><span class="p">[</span><span class="s2">"source"</span><span class="p">][</span><span class="s2">"reverse_dns"</span><span class="p">]</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span><span class="p">:</span>
|
||||
<span class="n">base_domain</span> <span class="o">=</span> <span class="n">_get_base_domain</span><span class="p">(</span><span class="n">new_record</span><span class="p">[</span><span class="s2">"source"</span><span class="p">][</span><span class="s2">"reverse_dns"</span><span class="p">])</span>
|
||||
<span class="n">new_record</span><span class="p">[</span><span class="s2">"source"</span><span class="p">][</span><span class="s2">"base_domain"</span><span class="p">]</span> <span class="o">=</span> <span class="n">base_domain</span>
|
||||
<span class="n">new_record</span><span class="p">[</span><span class="s2">"source"</span><span class="p">]</span> <span class="o">=</span> <span class="n">_get_ip_address_info</span><span class="p">(</span><span class="n">record</span><span class="p">[</span><span class="s2">"row"</span><span class="p">][</span><span class="s2">"source_ip"</span><span class="p">],</span>
|
||||
<span class="n">nameservers</span><span class="o">=</span><span class="n">nameservers</span><span class="p">,</span>
|
||||
<span class="n">timeout</span><span class="o">=</span><span class="n">timeout</span><span class="p">)</span>
|
||||
<span class="n">new_record</span><span class="p">[</span><span class="s2">"count"</span><span class="p">]</span> <span class="o">=</span> <span class="nb">int</span><span class="p">(</span><span class="n">record</span><span class="p">[</span><span class="s2">"row"</span><span class="p">][</span><span class="s2">"count"</span><span class="p">])</span>
|
||||
<span class="n">policy_evaluated</span> <span class="o">=</span> <span class="n">record</span><span class="p">[</span><span class="s2">"row"</span><span class="p">][</span><span class="s2">"policy_evaluated"</span><span class="p">]</span><span class="o">.</span><span class="n">copy</span><span class="p">()</span>
|
||||
<span class="n">new_policy_evaluated</span> <span class="o">=</span> <span class="n">OrderedDict</span><span class="p">([(</span><span class="s2">"disposition"</span><span class="p">,</span> <span class="s2">"none"</span><span class="p">),</span>
|
||||
@@ -583,24 +634,24 @@
|
||||
<span class="s2">"</span><span class="si">{0}</span><span class="s2">"</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">error</span><span class="o">.</span><span class="fm">__str__</span><span class="p">()))</span></div>
|
||||
|
||||
|
||||
<div class="viewcode-block" id="extract_xml"><a class="viewcode-back" href="../index.html#parsedmarc.extract_xml">[docs]</a><span class="k">def</span> <span class="nf">extract_xml</span><span class="p">(</span><span class="n">_input</span><span class="p">):</span>
|
||||
<div class="viewcode-block" id="extract_xml"><a class="viewcode-back" href="../index.html#parsedmarc.extract_xml">[docs]</a><span class="k">def</span> <span class="nf">extract_xml</span><span class="p">(</span><span class="n">input_</span><span class="p">):</span>
|
||||
<span class="sd">"""</span>
|
||||
<span class="sd"> Extracts xml from a zip or gzip file at the given path, file-like object,</span>
|
||||
<span class="sd"> or bytes.</span>
|
||||
|
||||
<span class="sd"> Args:</span>
|
||||
<span class="sd"> _input: A path to a file, a file like object, or bytes</span>
|
||||
<span class="sd"> input_: A path to a file, a file like object, or bytes</span>
|
||||
|
||||
<span class="sd"> Returns:</span>
|
||||
<span class="sd"> str: The extracted XML</span>
|
||||
|
||||
<span class="sd"> """</span>
|
||||
<span class="k">if</span> <span class="nb">type</span><span class="p">(</span><span class="n">_input</span><span class="p">)</span> <span class="o">==</span> <span class="nb">str</span> <span class="ow">or</span> <span class="nb">type</span><span class="p">(</span><span class="n">_input</span><span class="p">)</span> <span class="o">==</span> <span class="n">unicode</span><span class="p">:</span>
|
||||
<span class="n">file_object</span> <span class="o">=</span> <span class="nb">open</span><span class="p">(</span><span class="n">_input</span><span class="p">,</span> <span class="s2">"rb"</span><span class="p">)</span>
|
||||
<span class="k">elif</span> <span class="nb">type</span><span class="p">(</span><span class="n">_input</span><span class="p">)</span> <span class="o">==</span> <span class="nb">bytes</span><span class="p">:</span>
|
||||
<span class="n">file_object</span> <span class="o">=</span> <span class="n">BytesIO</span><span class="p">(</span><span class="n">_input</span><span class="p">)</span>
|
||||
<span class="k">if</span> <span class="nb">type</span><span class="p">(</span><span class="n">input_</span><span class="p">)</span> <span class="o">==</span> <span class="nb">str</span> <span class="ow">or</span> <span class="nb">type</span><span class="p">(</span><span class="n">input_</span><span class="p">)</span> <span class="o">==</span> <span class="n">unicode</span><span class="p">:</span>
|
||||
<span class="n">file_object</span> <span class="o">=</span> <span class="nb">open</span><span class="p">(</span><span class="n">input_</span><span class="p">,</span> <span class="s2">"rb"</span><span class="p">)</span>
|
||||
<span class="k">elif</span> <span class="nb">type</span><span class="p">(</span><span class="n">input_</span><span class="p">)</span> <span class="o">==</span> <span class="nb">bytes</span><span class="p">:</span>
|
||||
<span class="n">file_object</span> <span class="o">=</span> <span class="n">BytesIO</span><span class="p">(</span><span class="n">input_</span><span class="p">)</span>
|
||||
<span class="k">else</span><span class="p">:</span>
|
||||
<span class="n">file_object</span> <span class="o">=</span> <span class="n">_input</span>
|
||||
<span class="n">file_object</span> <span class="o">=</span> <span class="n">input_</span>
|
||||
<span class="k">try</span><span class="p">:</span>
|
||||
<span class="n">header</span> <span class="o">=</span> <span class="n">file_object</span><span class="o">.</span><span class="n">read</span><span class="p">(</span><span class="mi">6</span><span class="p">)</span>
|
||||
<span class="n">file_object</span><span class="o">.</span><span class="n">seek</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span>
|
||||
@@ -747,61 +798,674 @@
|
||||
<span class="k">return</span> <span class="n">csv_file_object</span><span class="o">.</span><span class="n">getvalue</span><span class="p">()</span></div>
|
||||
|
||||
|
||||
<div class="viewcode-block" id="parse_forensic_report"><a class="viewcode-back" href="../index.html#parsedmarc.parse_forensic_report">[docs]</a><span class="k">def</span> <span class="nf">parse_forensic_report</span><span class="p">(</span><span class="n">feedback_report</span><span class="p">,</span> <span class="n">sample</span><span class="p">,</span> <span class="n">sample_headers_only</span><span class="p">,</span>
|
||||
<span class="n">nameservers</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span> <span class="n">timeout</span><span class="o">=</span><span class="mf">6.0</span><span class="p">):</span>
|
||||
<span class="sd">"""</span>
|
||||
<span class="sd"> Converts a DMARC forensic report and sample to a ``OrderedDict``</span>
|
||||
|
||||
<span class="sd"> Args:</span>
|
||||
<span class="sd"> feedback_report: A message's feedback report as a string</span>
|
||||
<span class="sd"> sample: The RFC 822 headers or RFC 822 message sample</span>
|
||||
<span class="sd"> sample_headers_only (bool): Set true if the sample is only headers</span>
|
||||
<span class="sd"> nameservers (list): A list of one or more nameservers to use</span>
|
||||
<span class="sd"> timeout (float): Sets the DNS timeout in seconds</span>
|
||||
|
||||
<span class="sd"> Returns:</span>
|
||||
<span class="sd"> OrderedDict: An parsed report and sample</span>
|
||||
<span class="sd"> """</span>
|
||||
|
||||
<span class="k">def</span> <span class="nf">convert_address</span><span class="p">(</span><span class="n">original_address</span><span class="p">):</span>
|
||||
<span class="k">if</span> <span class="n">original_address</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">==</span> <span class="s2">""</span><span class="p">:</span>
|
||||
<span class="n">display_name</span> <span class="o">=</span> <span class="kc">None</span>
|
||||
<span class="k">else</span><span class="p">:</span>
|
||||
<span class="n">display_name</span> <span class="o">=</span> <span class="n">original_address</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span>
|
||||
<span class="n">address</span> <span class="o">=</span> <span class="n">original_address</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span>
|
||||
|
||||
<span class="k">return</span> <span class="n">OrderedDict</span><span class="p">([(</span><span class="s2">"display_name"</span><span class="p">,</span> <span class="n">display_name</span><span class="p">),</span>
|
||||
<span class="p">(</span><span class="s2">"address"</span><span class="p">,</span> <span class="n">address</span><span class="p">)])</span>
|
||||
|
||||
<span class="k">def</span> <span class="nf">get_filename_safe_subject</span><span class="p">(</span><span class="n">_subject</span><span class="p">):</span>
|
||||
<span class="sd">"""</span>
|
||||
<span class="sd"> Converts a message subject to a string that is safe for a filename</span>
|
||||
<span class="sd"> Args:</span>
|
||||
<span class="sd"> _subject: A message subject</span>
|
||||
|
||||
<span class="sd"> Returns:</span>
|
||||
<span class="sd"> A string safe for a filename</span>
|
||||
<span class="sd"> """</span>
|
||||
<span class="n">invalid_filename_chars</span> <span class="o">=</span> <span class="p">[</span><span class="s1">'</span><span class="se">\\</span><span class="s1">'</span><span class="p">,</span> <span class="s1">'/'</span><span class="p">,</span> <span class="s1">':'</span><span class="p">,</span> <span class="s1">'"'</span><span class="p">,</span> <span class="s1">'*'</span><span class="p">,</span> <span class="s1">'?'</span><span class="p">,</span> <span class="s1">'|'</span><span class="p">,</span> <span class="s1">'</span><span class="se">\n</span><span class="s1">'</span><span class="p">,</span>
|
||||
<span class="s1">'</span><span class="se">\r</span><span class="s1">'</span><span class="p">]</span>
|
||||
<span class="k">if</span> <span class="n">_subject</span> <span class="ow">is</span> <span class="kc">None</span><span class="p">:</span>
|
||||
<span class="n">_subject</span> <span class="o">=</span> <span class="s2">"No Subject"</span>
|
||||
<span class="k">for</span> <span class="n">char</span> <span class="ow">in</span> <span class="n">invalid_filename_chars</span><span class="p">:</span>
|
||||
<span class="n">_subject</span> <span class="o">=</span> <span class="n">_subject</span><span class="o">.</span><span class="n">replace</span><span class="p">(</span><span class="n">char</span><span class="p">,</span> <span class="s2">""</span><span class="p">)</span>
|
||||
<span class="n">_subject</span> <span class="o">=</span> <span class="n">_subject</span><span class="o">.</span><span class="n">rstrip</span><span class="p">(</span><span class="s2">"."</span><span class="p">)</span>
|
||||
|
||||
<span class="k">return</span> <span class="n">_subject</span>
|
||||
|
||||
<span class="k">try</span><span class="p">:</span>
|
||||
<span class="n">parsed_report</span> <span class="o">=</span> <span class="n">OrderedDict</span><span class="p">()</span>
|
||||
<span class="n">report_values</span> <span class="o">=</span> <span class="n">feedback_report_regex</span><span class="o">.</span><span class="n">findall</span><span class="p">(</span><span class="n">feedback_report</span><span class="p">)</span>
|
||||
<span class="k">for</span> <span class="n">report_value</span> <span class="ow">in</span> <span class="n">report_values</span><span class="p">:</span>
|
||||
<span class="n">key</span> <span class="o">=</span> <span class="n">report_value</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">.</span><span class="n">lower</span><span class="p">()</span><span class="o">.</span><span class="n">replace</span><span class="p">(</span><span class="s2">"-"</span><span class="p">,</span> <span class="s2">"_"</span><span class="p">)</span>
|
||||
<span class="n">parsed_report</span><span class="p">[</span><span class="n">key</span><span class="p">]</span> <span class="o">=</span> <span class="n">report_value</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span>
|
||||
<span class="k">if</span> <span class="n">key</span> <span class="o">==</span> <span class="s2">"arrival_date"</span><span class="p">:</span>
|
||||
<span class="n">arrival_utc</span> <span class="o">=</span> <span class="n">dateparser</span><span class="o">.</span><span class="n">parse</span><span class="p">(</span><span class="n">parsed_report</span><span class="p">[</span><span class="s2">"arrival_date"</span><span class="p">],</span>
|
||||
<span class="n">settings</span><span class="o">=</span><span class="p">{</span><span class="s2">"TO_TIMEZONE"</span><span class="p">:</span> <span class="s2">"UTC"</span><span class="p">})</span>
|
||||
<span class="n">arrival_utc</span> <span class="o">=</span> <span class="n">arrival_utc</span><span class="o">.</span><span class="n">strftime</span><span class="p">(</span><span class="s2">"%Y-%m-</span><span class="si">%d</span><span class="s2"> %H:%M:%S"</span><span class="p">)</span>
|
||||
<span class="n">parsed_report</span><span class="p">[</span><span class="s2">"arrival_date_utc"</span><span class="p">]</span> <span class="o">=</span> <span class="n">arrival_utc</span>
|
||||
|
||||
<span class="n">ip_address</span> <span class="o">=</span> <span class="n">parsed_report</span><span class="p">[</span><span class="s2">"source_ip"</span><span class="p">]</span>
|
||||
<span class="n">parsed_report</span><span class="p">[</span><span class="s2">"source"</span><span class="p">]</span> <span class="o">=</span> <span class="n">_get_ip_address_info</span><span class="p">(</span><span class="n">ip_address</span><span class="p">,</span>
|
||||
<span class="n">nameservers</span><span class="o">=</span><span class="n">nameservers</span><span class="p">,</span>
|
||||
<span class="n">timeout</span><span class="o">=</span><span class="n">timeout</span><span class="p">)</span>
|
||||
<span class="k">del</span> <span class="n">parsed_report</span><span class="p">[</span><span class="s2">"source_ip"</span><span class="p">]</span>
|
||||
|
||||
<span class="k">if</span> <span class="s2">"identity_alignment"</span> <span class="ow">not</span> <span class="ow">in</span> <span class="n">parsed_report</span><span class="p">:</span>
|
||||
<span class="n">parsed_report</span><span class="p">[</span><span class="s2">"authentication_mechanisms"</span><span class="p">]</span> <span class="o">=</span> <span class="p">[]</span>
|
||||
<span class="k">elif</span> <span class="n">parsed_report</span><span class="p">[</span><span class="s2">"identity_alignment"</span><span class="p">]</span> <span class="o">==</span> <span class="s2">"none"</span><span class="p">:</span>
|
||||
<span class="n">parsed_report</span><span class="p">[</span><span class="s2">"authentication_mechanisms"</span><span class="p">]</span> <span class="o">=</span> <span class="p">[]</span>
|
||||
<span class="k">del</span> <span class="n">parsed_report</span><span class="p">[</span><span class="s2">"identity_alignment"</span><span class="p">]</span>
|
||||
<span class="k">else</span><span class="p">:</span>
|
||||
<span class="n">auth_mechanisms</span> <span class="o">=</span> <span class="n">parsed_report</span><span class="p">[</span><span class="s2">"identity_alignment"</span><span class="p">]</span>
|
||||
<span class="n">auth_mechanisms</span> <span class="o">=</span> <span class="n">auth_mechanisms</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="s2">","</span><span class="p">)</span>
|
||||
<span class="n">parsed_report</span><span class="p">[</span><span class="s2">"authentication_mechanisms"</span><span class="p">]</span> <span class="o">=</span> <span class="n">auth_mechanisms</span>
|
||||
<span class="k">del</span> <span class="n">parsed_report</span><span class="p">[</span><span class="s2">"identity_alignment"</span><span class="p">]</span>
|
||||
|
||||
<span class="k">if</span> <span class="s2">"auth_failure"</span> <span class="ow">not</span> <span class="ow">in</span> <span class="n">parsed_report</span><span class="p">:</span>
|
||||
<span class="n">parsed_report</span><span class="p">[</span><span class="s2">"auth_failure"</span><span class="p">]</span> <span class="o">=</span> <span class="s2">"dmarc"</span>
|
||||
<span class="n">auth_failure</span> <span class="o">=</span> <span class="n">parsed_report</span><span class="p">[</span><span class="s2">"auth_failure"</span><span class="p">]</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="s2">","</span><span class="p">)</span>
|
||||
<span class="n">parsed_report</span><span class="p">[</span><span class="s2">"auth_failure"</span><span class="p">]</span> <span class="o">=</span> <span class="n">auth_failure</span>
|
||||
|
||||
<span class="n">optional_fields</span> <span class="o">=</span> <span class="p">[</span><span class="s2">"original_envelope_id"</span><span class="p">,</span> <span class="s2">"dkim_domain"</span><span class="p">,</span>
|
||||
<span class="s2">"original_mail_from"</span><span class="p">,</span> <span class="s2">"original_rcpt_to"</span><span class="p">]</span>
|
||||
<span class="k">for</span> <span class="n">optional_field</span> <span class="ow">in</span> <span class="n">optional_fields</span><span class="p">:</span>
|
||||
<span class="k">if</span> <span class="n">optional_field</span> <span class="ow">not</span> <span class="ow">in</span> <span class="n">parsed_report</span><span class="p">:</span>
|
||||
<span class="n">parsed_report</span><span class="p">[</span><span class="n">optional_field</span><span class="p">]</span> <span class="o">=</span> <span class="kc">None</span>
|
||||
|
||||
<span class="n">parsed_mail</span> <span class="o">=</span> <span class="n">mailparser</span><span class="o">.</span><span class="n">parse_from_string</span><span class="p">(</span><span class="n">sample</span><span class="p">)</span>
|
||||
<span class="n">parsed_headers</span> <span class="o">=</span> <span class="n">json</span><span class="o">.</span><span class="n">loads</span><span class="p">(</span><span class="n">parsed_mail</span><span class="o">.</span><span class="n">headers_json</span><span class="p">)</span>
|
||||
<span class="n">parsed_message</span> <span class="o">=</span> <span class="n">json</span><span class="o">.</span><span class="n">loads</span><span class="p">(</span><span class="n">parsed_mail</span><span class="o">.</span><span class="n">mail_json</span><span class="p">)</span>
|
||||
<span class="n">parsed_sample</span> <span class="o">=</span> <span class="n">OrderedDict</span><span class="p">([(</span><span class="s2">"headers"</span><span class="p">,</span> <span class="n">parsed_headers</span><span class="p">)])</span>
|
||||
<span class="k">for</span> <span class="n">key</span> <span class="ow">in</span> <span class="n">parsed_message</span><span class="p">:</span>
|
||||
<span class="n">parsed_sample</span><span class="p">[</span><span class="n">key</span><span class="p">]</span> <span class="o">=</span> <span class="n">parsed_message</span><span class="p">[</span><span class="n">key</span><span class="p">]</span>
|
||||
|
||||
<span class="n">parsed_sample</span><span class="p">[</span><span class="s2">"date"</span><span class="p">]</span> <span class="o">=</span> <span class="n">parsed_sample</span><span class="p">[</span><span class="s2">"date"</span><span class="p">]</span><span class="o">.</span><span class="n">replace</span><span class="p">(</span><span class="s2">"T"</span><span class="p">,</span> <span class="s2">" "</span><span class="p">)</span>
|
||||
<span class="k">if</span> <span class="s2">"received"</span> <span class="ow">in</span> <span class="n">parsed_message</span><span class="p">:</span>
|
||||
<span class="k">for</span> <span class="n">received</span> <span class="ow">in</span> <span class="n">parsed_message</span><span class="p">[</span><span class="s2">"received"</span><span class="p">]:</span>
|
||||
<span class="k">if</span> <span class="s2">"date_utc"</span> <span class="ow">in</span> <span class="n">received</span><span class="p">:</span>
|
||||
<span class="n">received</span><span class="p">[</span><span class="s2">"date_utc"</span><span class="p">]</span> <span class="o">=</span> <span class="n">received</span><span class="p">[</span><span class="s2">"date_utc"</span><span class="p">]</span><span class="o">.</span><span class="n">replace</span><span class="p">(</span><span class="s2">"T"</span><span class="p">,</span>
|
||||
<span class="s2">" "</span><span class="p">)</span>
|
||||
<span class="n">parsed_sample</span><span class="p">[</span><span class="s2">"from"</span><span class="p">]</span> <span class="o">=</span> <span class="n">convert_address</span><span class="p">(</span><span class="n">parsed_sample</span><span class="p">[</span><span class="s2">"from"</span><span class="p">][</span><span class="mi">0</span><span class="p">])</span>
|
||||
|
||||
<span class="k">if</span> <span class="s2">"reply_to"</span> <span class="ow">in</span> <span class="n">parsed_sample</span><span class="p">:</span>
|
||||
<span class="n">parsed_sample</span><span class="p">[</span><span class="s2">"reply_to"</span><span class="p">]</span> <span class="o">=</span> <span class="nb">list</span><span class="p">(</span><span class="nb">map</span><span class="p">(</span><span class="k">lambda</span> <span class="n">x</span><span class="p">:</span> <span class="n">convert_address</span><span class="p">(</span><span class="n">x</span><span class="p">),</span>
|
||||
<span class="n">parsed_sample</span><span class="p">[</span><span class="s2">"reply_to"</span><span class="p">]))</span>
|
||||
<span class="k">else</span><span class="p">:</span>
|
||||
<span class="n">parsed_sample</span><span class="p">[</span><span class="s2">"reply_to"</span><span class="p">]</span> <span class="o">=</span> <span class="p">[]</span>
|
||||
|
||||
<span class="n">parsed_sample</span><span class="p">[</span><span class="s2">"to"</span><span class="p">]</span> <span class="o">=</span> <span class="nb">list</span><span class="p">(</span><span class="nb">map</span><span class="p">(</span><span class="k">lambda</span> <span class="n">x</span><span class="p">:</span> <span class="n">convert_address</span><span class="p">(</span><span class="n">x</span><span class="p">),</span>
|
||||
<span class="n">parsed_sample</span><span class="p">[</span><span class="s2">"to"</span><span class="p">]))</span>
|
||||
<span class="k">if</span> <span class="s2">"cc"</span> <span class="ow">in</span> <span class="n">parsed_sample</span><span class="p">:</span>
|
||||
<span class="n">parsed_sample</span><span class="p">[</span><span class="s2">"cc"</span><span class="p">]</span> <span class="o">=</span> <span class="nb">list</span><span class="p">(</span><span class="nb">map</span><span class="p">(</span><span class="k">lambda</span> <span class="n">x</span><span class="p">:</span> <span class="n">convert_address</span><span class="p">(</span><span class="n">x</span><span class="p">),</span>
|
||||
<span class="n">parsed_sample</span><span class="p">[</span><span class="s2">"cc"</span><span class="p">]))</span>
|
||||
<span class="k">else</span><span class="p">:</span>
|
||||
<span class="n">parsed_sample</span><span class="p">[</span><span class="s2">"cc"</span><span class="p">]</span> <span class="o">=</span> <span class="p">[]</span>
|
||||
|
||||
<span class="k">if</span> <span class="s2">"bcc"</span> <span class="ow">in</span> <span class="n">parsed_sample</span><span class="p">:</span>
|
||||
<span class="n">parsed_sample</span><span class="p">[</span><span class="s2">"bcc"</span><span class="p">]</span> <span class="o">=</span> <span class="nb">list</span><span class="p">(</span><span class="nb">map</span><span class="p">(</span><span class="k">lambda</span> <span class="n">x</span><span class="p">:</span> <span class="n">convert_address</span><span class="p">(</span><span class="n">x</span><span class="p">),</span>
|
||||
<span class="n">parsed_sample</span><span class="p">[</span><span class="s2">"bcc"</span><span class="p">]))</span>
|
||||
<span class="k">else</span><span class="p">:</span>
|
||||
<span class="n">parsed_sample</span><span class="p">[</span><span class="s2">"bcc"</span><span class="p">]</span> <span class="o">=</span> <span class="p">[]</span>
|
||||
|
||||
<span class="k">if</span> <span class="s2">"delivered_to"</span> <span class="ow">in</span> <span class="n">parsed_sample</span><span class="p">:</span>
|
||||
<span class="n">parsed_sample</span><span class="p">[</span><span class="s2">"delivered_to"</span><span class="p">]</span> <span class="o">=</span> <span class="nb">list</span><span class="p">(</span>
|
||||
<span class="nb">map</span><span class="p">(</span><span class="k">lambda</span> <span class="n">x</span><span class="p">:</span> <span class="n">convert_address</span><span class="p">(</span><span class="n">x</span><span class="p">),</span>
|
||||
<span class="n">parsed_sample</span><span class="p">[</span><span class="s2">"delivered_to"</span><span class="p">])</span>
|
||||
<span class="p">)</span>
|
||||
|
||||
<span class="k">if</span> <span class="s2">"attachments"</span> <span class="ow">not</span> <span class="ow">in</span> <span class="n">parsed_sample</span><span class="p">:</span>
|
||||
<span class="n">parsed_sample</span><span class="p">[</span><span class="s2">"attachments"</span><span class="p">]</span> <span class="o">=</span> <span class="p">[]</span>
|
||||
|
||||
<span class="k">if</span> <span class="s2">"subject"</span> <span class="ow">not</span> <span class="ow">in</span> <span class="n">parsed_sample</span><span class="p">:</span>
|
||||
<span class="n">parsed_sample</span><span class="p">[</span><span class="s2">"subject"</span><span class="p">]</span> <span class="o">=</span> <span class="kc">None</span>
|
||||
|
||||
<span class="n">parsed_sample</span><span class="p">[</span><span class="s2">"filename_safe_subject"</span><span class="p">]</span> <span class="o">=</span> <span class="n">get_filename_safe_subject</span><span class="p">(</span>
|
||||
<span class="n">parsed_sample</span><span class="p">[</span><span class="s2">"subject"</span><span class="p">])</span>
|
||||
|
||||
<span class="k">if</span> <span class="s2">"body"</span> <span class="ow">not</span> <span class="ow">in</span> <span class="n">parsed_sample</span><span class="p">:</span>
|
||||
<span class="n">parsed_sample</span><span class="p">[</span><span class="s2">"body"</span><span class="p">]</span> <span class="o">=</span> <span class="kc">None</span>
|
||||
|
||||
<span class="k">if</span> <span class="n">sample_headers_only</span> <span class="ow">and</span> <span class="n">parsed_sample</span><span class="p">[</span><span class="s2">"has_defects"</span><span class="p">]:</span>
|
||||
<span class="k">del</span> <span class="n">parsed_sample</span><span class="p">[</span><span class="s2">"defects"</span><span class="p">]</span>
|
||||
<span class="k">del</span> <span class="n">parsed_sample</span><span class="p">[</span><span class="s2">"defects_categories"</span><span class="p">]</span>
|
||||
<span class="k">del</span> <span class="n">parsed_sample</span><span class="p">[</span><span class="s2">"has_defects"</span><span class="p">]</span>
|
||||
<span class="n">parsed_report</span><span class="p">[</span><span class="s2">"sample_headers_only"</span><span class="p">]</span> <span class="o">=</span> <span class="n">sample_headers_only</span>
|
||||
<span class="n">parsed_report</span><span class="p">[</span><span class="s2">"sample"</span><span class="p">]</span> <span class="o">=</span> <span class="n">sample</span>
|
||||
<span class="n">parsed_report</span><span class="p">[</span><span class="s2">"parsed_sample"</span><span class="p">]</span> <span class="o">=</span> <span class="n">parsed_sample</span>
|
||||
|
||||
<span class="k">return</span> <span class="n">parsed_report</span>
|
||||
|
||||
<span class="k">except</span> <span class="ne">KeyError</span> <span class="k">as</span> <span class="n">error</span><span class="p">:</span>
|
||||
<span class="k">raise</span> <span class="n">InvalidForensicReport</span><span class="p">(</span><span class="s2">"Missing value: </span><span class="si">{0}</span><span class="s2">"</span><span class="o">.</span><span class="n">format</span><span class="p">(</span>
|
||||
<span class="n">error</span><span class="o">.</span><span class="fm">__str__</span><span class="p">()))</span></div>
|
||||
|
||||
|
||||
<span class="k">def</span> <span class="nf">parsed_dmarc_forensic_reports_to_csv</span><span class="p">(</span><span class="n">report</span><span class="p">):</span>
|
||||
<span class="n">fields</span> <span class="o">=</span> <span class="p">[</span><span class="s2">"feedback_type"</span><span class="p">,</span> <span class="s2">"user_agent"</span><span class="p">,</span> <span class="s2">"version"</span><span class="p">,</span> <span class="s2">"original_envelope_id"</span><span class="p">,</span>
|
||||
<span class="s2">"original_mail_from"</span><span class="p">,</span> <span class="s2">"original_rcpt_to"</span><span class="p">,</span> <span class="s2">"arrival_date"</span><span class="p">,</span>
|
||||
<span class="s2">"arrival_date_utc"</span><span class="p">,</span> <span class="s2">"subject"</span><span class="p">,</span> <span class="s2">"message_id"</span><span class="p">,</span>
|
||||
<span class="s2">"authentication_results"</span><span class="p">,</span> <span class="s2">"dkim_domain"</span><span class="p">,</span> <span class="s2">"source_ip_address"</span><span class="p">,</span>
|
||||
<span class="s2">"source_country"</span><span class="p">,</span> <span class="s2">"source_reverse_dns"</span><span class="p">,</span> <span class="s2">"source_base_domain"</span><span class="p">,</span>
|
||||
<span class="s2">"delivery_result"</span><span class="p">,</span> <span class="s2">"auth_failure"</span><span class="p">,</span> <span class="s2">"reported_domain"</span><span class="p">,</span>
|
||||
<span class="s2">"authentication_mechanisms"</span><span class="p">,</span> <span class="s2">"sample_headers_only"</span><span class="p">]</span>
|
||||
|
||||
<span class="n">csv_file</span> <span class="o">=</span> <span class="n">StringIO</span><span class="p">()</span>
|
||||
<span class="n">csv_writer</span> <span class="o">=</span> <span class="n">DictWriter</span><span class="p">(</span><span class="n">csv_file</span><span class="p">,</span> <span class="n">fieldnames</span><span class="o">=</span><span class="n">fields</span><span class="p">)</span>
|
||||
<span class="n">csv_writer</span><span class="o">.</span><span class="n">writeheader</span><span class="p">()</span>
|
||||
<span class="k">for</span> <span class="n">row</span> <span class="ow">in</span> <span class="n">report</span><span class="p">:</span>
|
||||
<span class="n">row</span> <span class="o">=</span> <span class="n">row</span><span class="o">.</span><span class="n">copy</span><span class="p">()</span>
|
||||
<span class="n">row</span><span class="p">[</span><span class="s2">"source_ip_address"</span><span class="p">]</span> <span class="o">=</span> <span class="n">row</span><span class="p">[</span><span class="s2">"source"</span><span class="p">][</span><span class="s2">"ip_address"</span><span class="p">]</span>
|
||||
<span class="n">row</span><span class="p">[</span><span class="s2">"source_reverse_dns"</span><span class="p">]</span> <span class="o">=</span> <span class="n">row</span><span class="p">[</span><span class="s2">"source"</span><span class="p">][</span><span class="s2">"reverse_dns"</span><span class="p">]</span>
|
||||
<span class="n">row</span><span class="p">[</span><span class="s2">"source_base_domain"</span><span class="p">]</span> <span class="o">=</span> <span class="n">row</span><span class="p">[</span><span class="s2">"source"</span><span class="p">][</span><span class="s2">"base_domain"</span><span class="p">]</span>
|
||||
<span class="n">row</span><span class="p">[</span><span class="s2">"source_country"</span><span class="p">]</span> <span class="o">=</span> <span class="n">row</span><span class="p">[</span><span class="s2">"source"</span><span class="p">][</span><span class="s2">"country"</span><span class="p">]</span>
|
||||
<span class="k">del</span> <span class="n">row</span><span class="p">[</span><span class="s2">"source"</span><span class="p">]</span>
|
||||
<span class="n">row</span><span class="p">[</span><span class="s2">"subject"</span><span class="p">]</span> <span class="o">=</span> <span class="n">row</span><span class="p">[</span><span class="s2">"parsed_sample"</span><span class="p">][</span><span class="s2">"subject"</span><span class="p">]</span>
|
||||
<span class="n">row</span><span class="p">[</span><span class="s2">"auth_failure"</span><span class="p">]</span> <span class="o">=</span> <span class="s2">","</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">row</span><span class="p">[</span><span class="s2">"auth_failure"</span><span class="p">])</span>
|
||||
<span class="n">authentication_mechanisms</span> <span class="o">=</span> <span class="n">row</span><span class="p">[</span><span class="s2">"authentication_mechanisms"</span><span class="p">]</span>
|
||||
<span class="n">row</span><span class="p">[</span><span class="s2">"authentication_mechanisms"</span><span class="p">]</span> <span class="o">=</span> <span class="s2">","</span><span class="o">.</span><span class="n">join</span><span class="p">(</span>
|
||||
<span class="n">authentication_mechanisms</span><span class="p">)</span>
|
||||
<span class="k">del</span> <span class="n">row</span><span class="p">[</span><span class="s2">"sample"</span><span class="p">]</span>
|
||||
<span class="k">del</span> <span class="n">row</span><span class="p">[</span><span class="s2">"parsed_sample"</span><span class="p">]</span>
|
||||
<span class="n">csv_writer</span><span class="o">.</span><span class="n">writerow</span><span class="p">(</span><span class="n">row</span><span class="p">)</span>
|
||||
|
||||
<span class="k">return</span> <span class="n">csv_file</span><span class="o">.</span><span class="n">getvalue</span><span class="p">()</span>
|
||||
|
||||
|
||||
<div class="viewcode-block" id="parse_report_email"><a class="viewcode-back" href="../index.html#parsedmarc.parse_report_email">[docs]</a><span class="k">def</span> <span class="nf">parse_report_email</span><span class="p">(</span><span class="n">input_</span><span class="p">,</span> <span class="n">nameservers</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span> <span class="n">timeout</span><span class="o">=</span><span class="mf">6.0</span><span class="p">):</span>
|
||||
<span class="sd">"""</span>
|
||||
<span class="sd"> Parses a DMARC report from an email</span>
|
||||
|
||||
<span class="sd"> Args:</span>
|
||||
<span class="sd"> input_: An emailed DMARC report in RFC 822 format, as bytes or a string</span>
|
||||
<span class="sd"> nameservers (list): A list of one or more nameservers to use</span>
|
||||
<span class="sd"> timeout (float): Sets the DNS timeout in seconds</span>
|
||||
|
||||
<span class="sd"> Returns:</span>
|
||||
<span class="sd"> OrderedDict:</span>
|
||||
<span class="sd"> * ``report_type``: ``aggregate`` or ``forensic``</span>
|
||||
<span class="sd"> * ``report``: The parsed report</span>
|
||||
<span class="sd"> """</span>
|
||||
|
||||
<span class="k">def</span> <span class="nf">is_outlook_msg</span><span class="p">(</span><span class="n">suspect_bytes</span><span class="p">):</span>
|
||||
<span class="sd">"""Checks if the given content is a Outlook msg OLE file"""</span>
|
||||
<span class="k">return</span> <span class="n">suspect_bytes</span><span class="o">.</span><span class="n">startswith</span><span class="p">(</span><span class="sa">b</span><span class="s2">"</span><span class="se">\xD0\xCF\x11\xE0\xA1\xB1\x1A\xE1</span><span class="s2">"</span><span class="p">)</span>
|
||||
|
||||
<span class="k">def</span> <span class="nf">convert_outlook_msg</span><span class="p">(</span><span class="n">msg_bytes</span><span class="p">):</span>
|
||||
<span class="sd">"""</span>
|
||||
<span class="sd"> Uses the ``msgconvert`` Perl utility to convert an Outlook MS file to</span>
|
||||
<span class="sd"> standard RFC 822 format</span>
|
||||
|
||||
<span class="sd"> Args:</span>
|
||||
<span class="sd"> msg_bytes (bytes): the content of the .msg file</span>
|
||||
|
||||
<span class="sd"> Returns:</span>
|
||||
<span class="sd"> A RFC 822 string</span>
|
||||
<span class="sd"> """</span>
|
||||
<span class="k">if</span> <span class="ow">not</span> <span class="n">is_outlook_msg</span><span class="p">(</span><span class="n">msg_bytes</span><span class="p">):</span>
|
||||
<span class="k">raise</span> <span class="ne">ValueError</span><span class="p">(</span><span class="s2">"The supplied bytes are not an Outlook MSG file"</span><span class="p">)</span>
|
||||
<span class="n">orig_dir</span> <span class="o">=</span> <span class="n">os</span><span class="o">.</span><span class="n">getcwd</span><span class="p">()</span>
|
||||
<span class="n">tmp_dir</span> <span class="o">=</span> <span class="n">tempfile</span><span class="o">.</span><span class="n">mkdtemp</span><span class="p">()</span>
|
||||
<span class="n">os</span><span class="o">.</span><span class="n">chdir</span><span class="p">(</span><span class="n">tmp_dir</span><span class="p">)</span>
|
||||
<span class="k">with</span> <span class="nb">open</span><span class="p">(</span><span class="s2">"sample.msg"</span><span class="p">,</span> <span class="s2">"wb"</span><span class="p">)</span> <span class="k">as</span> <span class="n">msg_file</span><span class="p">:</span>
|
||||
<span class="n">msg_file</span><span class="o">.</span><span class="n">write</span><span class="p">(</span><span class="n">msg_bytes</span><span class="p">)</span>
|
||||
<span class="k">try</span><span class="p">:</span>
|
||||
<span class="n">subprocess</span><span class="o">.</span><span class="n">check_call</span><span class="p">([</span><span class="s2">"msgconvert"</span><span class="p">,</span> <span class="s2">"sample.msg"</span><span class="p">])</span>
|
||||
<span class="n">eml_path</span> <span class="o">=</span> <span class="s2">"sample.eml"</span>
|
||||
<span class="k">with</span> <span class="nb">open</span><span class="p">(</span><span class="n">eml_path</span><span class="p">,</span> <span class="s2">"rb"</span><span class="p">)</span> <span class="k">as</span> <span class="n">eml_file</span><span class="p">:</span>
|
||||
<span class="n">rfc822</span> <span class="o">=</span> <span class="n">eml_file</span><span class="o">.</span><span class="n">read</span><span class="p">()</span>
|
||||
<span class="k">except</span> <span class="ne">FileNotFoundError</span> <span class="k">as</span> <span class="n">e</span><span class="p">:</span>
|
||||
<span class="k">raise</span> <span class="ne">RuntimeError</span><span class="p">(</span>
|
||||
<span class="s2">"Error running msgconvert. Please ensure it is installed</span><span class="se">\n</span><span class="s2">"</span>
|
||||
<span class="s2">"sudo apt install libemail-outlook-message-perl</span><span class="se">\n</span><span class="s2">"</span>
|
||||
<span class="s2">"https://github.com/mvz/email-outlook-message-perl</span><span class="se">\n\n</span><span class="s2">"</span>
|
||||
<span class="s2">"</span><span class="si">{0}</span><span class="s2">"</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">e</span><span class="p">))</span>
|
||||
<span class="k">finally</span><span class="p">:</span>
|
||||
<span class="n">os</span><span class="o">.</span><span class="n">chdir</span><span class="p">(</span><span class="n">orig_dir</span><span class="p">)</span>
|
||||
<span class="n">shutil</span><span class="o">.</span><span class="n">rmtree</span><span class="p">(</span><span class="n">tmp_dir</span><span class="p">)</span>
|
||||
|
||||
<span class="k">return</span> <span class="n">rfc822</span>
|
||||
|
||||
<span class="k">def</span> <span class="nf">decode_header</span><span class="p">(</span><span class="n">header</span><span class="p">):</span>
|
||||
<span class="sd">"""Decodes a RFC 822 email header"""</span>
|
||||
<span class="n">header</span> <span class="o">=</span> <span class="n">header</span><span class="o">.</span><span class="n">replace</span><span class="p">(</span><span class="s2">"</span><span class="se">\r</span><span class="s2">"</span><span class="p">,</span> <span class="s2">""</span><span class="p">)</span><span class="o">.</span><span class="n">replace</span><span class="p">(</span><span class="s2">"</span><span class="se">\n</span><span class="s2">"</span><span class="p">,</span> <span class="s2">""</span><span class="p">)</span>
|
||||
<span class="n">decoded_header</span> <span class="o">=</span> <span class="n">email</span><span class="o">.</span><span class="n">header</span><span class="o">.</span><span class="n">decode_header</span><span class="p">(</span><span class="n">header</span><span class="p">)</span>
|
||||
<span class="n">header</span> <span class="o">=</span> <span class="s2">""</span>
|
||||
<span class="k">for</span> <span class="n">header_part</span> <span class="ow">in</span> <span class="n">decoded_header</span><span class="p">:</span>
|
||||
<span class="k">if</span> <span class="nb">type</span><span class="p">(</span><span class="n">header_part</span><span class="p">[</span><span class="mi">0</span><span class="p">])</span> <span class="o">==</span> <span class="nb">bytes</span><span class="p">:</span>
|
||||
<span class="n">encoding</span> <span class="o">=</span> <span class="n">header_part</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="ow">or</span> <span class="s2">"ascii"</span>
|
||||
<span class="n">header_part</span> <span class="o">=</span> <span class="n">header_part</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">.</span><span class="n">decode</span><span class="p">(</span><span class="n">encoding</span><span class="o">=</span><span class="n">encoding</span><span class="p">,</span>
|
||||
<span class="n">errors</span><span class="o">=</span><span class="s2">"replace"</span><span class="p">)</span>
|
||||
<span class="k">else</span><span class="p">:</span>
|
||||
<span class="n">header_part</span> <span class="o">=</span> <span class="n">header_part</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span>
|
||||
<span class="n">header</span> <span class="o">+=</span> <span class="n">header_part</span>
|
||||
<span class="n">header</span> <span class="o">=</span> <span class="n">header</span><span class="o">.</span><span class="n">replace</span><span class="p">(</span><span class="s2">"</span><span class="se">\r</span><span class="s2">"</span><span class="p">,</span> <span class="s2">" "</span><span class="p">)</span><span class="o">.</span><span class="n">replace</span><span class="p">(</span><span class="s2">"</span><span class="se">\n</span><span class="s2">"</span><span class="p">,</span> <span class="s2">" "</span><span class="p">)</span>
|
||||
|
||||
<span class="k">return</span> <span class="n">header</span>
|
||||
|
||||
<span class="k">if</span> <span class="nb">type</span><span class="p">(</span><span class="n">input_</span><span class="p">)</span> <span class="o">==</span> <span class="nb">bytes</span><span class="p">:</span>
|
||||
<span class="k">if</span> <span class="n">is_outlook_msg</span><span class="p">(</span><span class="n">input_</span><span class="p">):</span>
|
||||
<span class="n">input_</span> <span class="o">=</span> <span class="n">convert_outlook_msg</span><span class="p">(</span><span class="n">input_</span><span class="p">)</span>
|
||||
<span class="k">else</span><span class="p">:</span>
|
||||
<span class="n">input_</span> <span class="o">=</span> <span class="n">input_</span><span class="o">.</span><span class="n">decode</span><span class="p">(</span><span class="s2">"utf-8"</span><span class="p">,</span> <span class="n">errors</span><span class="o">=</span><span class="s2">"replace"</span><span class="p">)</span>
|
||||
<span class="n">result</span> <span class="o">=</span> <span class="kc">None</span>
|
||||
<span class="n">msg</span> <span class="o">=</span> <span class="n">email</span><span class="o">.</span><span class="n">message_from_string</span><span class="p">(</span><span class="n">input_</span><span class="p">)</span>
|
||||
<span class="n">subject</span> <span class="o">=</span> <span class="kc">None</span>
|
||||
<span class="n">feedback_report</span> <span class="o">=</span> <span class="kc">None</span>
|
||||
<span class="n">sample_headers_only</span> <span class="o">=</span> <span class="kc">False</span>
|
||||
<span class="n">sample</span> <span class="o">=</span> <span class="kc">None</span>
|
||||
<span class="k">if</span> <span class="s2">"subject"</span> <span class="ow">in</span> <span class="n">msg</span><span class="p">:</span>
|
||||
<span class="n">subject</span> <span class="o">=</span> <span class="n">decode_header</span><span class="p">(</span><span class="n">msg</span><span class="p">[</span><span class="s2">"subject"</span><span class="p">])</span>
|
||||
<span class="k">for</span> <span class="n">part</span> <span class="ow">in</span> <span class="n">msg</span><span class="o">.</span><span class="n">walk</span><span class="p">():</span>
|
||||
<span class="n">filename</span> <span class="o">=</span> <span class="n">part</span><span class="o">.</span><span class="n">get_filename</span><span class="p">()</span>
|
||||
<span class="k">if</span> <span class="n">filename</span> <span class="ow">is</span> <span class="kc">None</span><span class="p">:</span>
|
||||
<span class="n">filename</span> <span class="o">=</span> <span class="s2">""</span>
|
||||
<span class="n">filename</span> <span class="o">=</span> <span class="n">filename</span><span class="o">.</span><span class="n">lower</span><span class="p">()</span>
|
||||
<span class="n">content_type</span> <span class="o">=</span> <span class="n">part</span><span class="o">.</span><span class="n">get_content_type</span><span class="p">()</span>
|
||||
<span class="n">payload</span> <span class="o">=</span> <span class="n">part</span><span class="o">.</span><span class="n">get_payload</span><span class="p">()</span>
|
||||
<span class="k">if</span> <span class="nb">type</span><span class="p">(</span><span class="n">payload</span><span class="p">)</span> <span class="o">==</span> <span class="nb">list</span><span class="p">:</span>
|
||||
<span class="n">payload</span> <span class="o">=</span> <span class="n">payload</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">.</span><span class="fm">__str__</span><span class="p">()</span>
|
||||
<span class="k">if</span> <span class="n">content_type</span> <span class="o">==</span> <span class="s2">"message/feedback-report"</span><span class="p">:</span>
|
||||
<span class="n">feedback_report</span> <span class="o">=</span> <span class="n">payload</span>
|
||||
<span class="k">elif</span> <span class="n">content_type</span> <span class="o">==</span> <span class="s2">"text/rfc822-headers"</span><span class="p">:</span>
|
||||
<span class="n">sample</span> <span class="o">=</span> <span class="n">payload</span>
|
||||
<span class="n">sample_headers_only</span> <span class="o">=</span> <span class="kc">True</span>
|
||||
<span class="k">elif</span> <span class="n">content_type</span> <span class="o">==</span> <span class="s2">"message/rfc822"</span><span class="p">:</span>
|
||||
<span class="n">sample</span> <span class="o">=</span> <span class="n">payload</span>
|
||||
<span class="n">sample_headers_only</span> <span class="o">=</span> <span class="kc">False</span>
|
||||
<span class="k">if</span> <span class="n">feedback_report</span> <span class="ow">and</span> <span class="n">sample</span><span class="p">:</span>
|
||||
<span class="n">forensic_report</span> <span class="o">=</span> <span class="n">parse_forensic_report</span><span class="p">(</span><span class="n">feedback_report</span><span class="p">,</span>
|
||||
<span class="n">sample</span><span class="p">,</span>
|
||||
<span class="n">sample_headers_only</span><span class="p">,</span>
|
||||
<span class="n">nameservers</span><span class="o">=</span><span class="n">nameservers</span><span class="p">,</span>
|
||||
<span class="n">timeout</span><span class="o">=</span><span class="n">timeout</span><span class="p">)</span>
|
||||
|
||||
<span class="n">result</span> <span class="o">=</span> <span class="n">OrderedDict</span><span class="p">([(</span><span class="s2">"report_type"</span><span class="p">,</span> <span class="s2">"forensic"</span><span class="p">),</span>
|
||||
<span class="p">(</span><span class="s2">"report"</span><span class="p">,</span> <span class="n">forensic_report</span><span class="p">)])</span>
|
||||
|
||||
<span class="k">if</span> <span class="n">filename</span><span class="o">.</span><span class="n">endswith</span><span class="p">(</span><span class="s2">".gz"</span><span class="p">)</span> <span class="ow">or</span> <span class="n">filename</span><span class="o">.</span><span class="n">endswith</span><span class="p">(</span><span class="s2">".zip"</span><span class="p">):</span>
|
||||
<span class="n">ns</span> <span class="o">=</span> <span class="n">nameservers</span>
|
||||
<span class="n">xml</span> <span class="o">=</span> <span class="n">b64decode</span><span class="p">(</span><span class="n">part</span><span class="o">.</span><span class="n">get_payload</span><span class="p">())</span>
|
||||
<span class="n">aggregate_report</span> <span class="o">=</span> <span class="n">parse_aggregate_report_file</span><span class="p">(</span><span class="n">xml</span><span class="p">,</span>
|
||||
<span class="n">nameservers</span><span class="o">=</span><span class="n">ns</span><span class="p">,</span>
|
||||
<span class="n">timeout</span><span class="o">=</span><span class="n">timeout</span><span class="p">)</span>
|
||||
<span class="n">result</span> <span class="o">=</span> <span class="n">OrderedDict</span><span class="p">([(</span><span class="s2">"report_type"</span><span class="p">,</span> <span class="s2">"aggregate"</span><span class="p">),</span>
|
||||
<span class="p">(</span><span class="s2">"report"</span><span class="p">,</span> <span class="n">aggregate_report</span><span class="p">)])</span>
|
||||
<span class="k">if</span> <span class="n">result</span> <span class="ow">is</span> <span class="kc">None</span><span class="p">:</span>
|
||||
<span class="n">error</span> <span class="o">=</span> <span class="s1">'Message with subject "</span><span class="si">{0}</span><span class="s1">" is '</span> \
|
||||
<span class="s1">'not a valid DMARC report'</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">subject</span><span class="p">)</span>
|
||||
<span class="k">raise</span> <span class="n">InvalidDMARCReport</span><span class="p">(</span><span class="n">error</span><span class="p">)</span>
|
||||
|
||||
<span class="k">return</span> <span class="n">result</span></div>
|
||||
|
||||
|
||||
<div class="viewcode-block" id="parse_report_file"><a class="viewcode-back" href="../index.html#parsedmarc.parse_report_file">[docs]</a><span class="k">def</span> <span class="nf">parse_report_file</span><span class="p">(</span><span class="n">input_</span><span class="p">,</span> <span class="n">nameservers</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span> <span class="n">timeout</span><span class="o">=</span><span class="mf">6.0</span><span class="p">):</span>
|
||||
<span class="sd">"""Parses a DMARC aggregate or forensic file at the given path, a</span>
|
||||
<span class="sd"> file-like object. or bytes</span>
|
||||
|
||||
<span class="sd"> Args:</span>
|
||||
<span class="sd"> input_: A path to a file, a file like object, or bytes</span>
|
||||
<span class="sd"> nameservers (list): A list of one or more nameservers to use</span>
|
||||
<span class="sd"> timeout (float): Sets the DNS timeout in seconds</span>
|
||||
|
||||
<span class="sd"> Returns:</span>
|
||||
<span class="sd"> OrderedDict: The parsed DMARC report</span>
|
||||
<span class="sd"> """</span>
|
||||
<span class="k">if</span> <span class="nb">type</span><span class="p">(</span><span class="n">input_</span><span class="p">)</span> <span class="o">==</span> <span class="nb">str</span> <span class="ow">or</span> <span class="nb">type</span><span class="p">(</span><span class="n">input_</span><span class="p">)</span> <span class="o">==</span> <span class="n">unicode</span><span class="p">:</span>
|
||||
<span class="n">file_object</span> <span class="o">=</span> <span class="nb">open</span><span class="p">(</span><span class="n">input_</span><span class="p">,</span> <span class="s2">"rb"</span><span class="p">)</span>
|
||||
<span class="k">elif</span> <span class="nb">type</span><span class="p">(</span><span class="n">input_</span><span class="p">)</span> <span class="o">==</span> <span class="nb">bytes</span><span class="p">:</span>
|
||||
<span class="n">file_object</span> <span class="o">=</span> <span class="n">BytesIO</span><span class="p">(</span><span class="n">input_</span><span class="p">)</span>
|
||||
<span class="k">else</span><span class="p">:</span>
|
||||
<span class="n">file_object</span> <span class="o">=</span> <span class="n">input_</span>
|
||||
|
||||
<span class="n">content</span> <span class="o">=</span> <span class="n">file_object</span><span class="o">.</span><span class="n">read</span><span class="p">()</span>
|
||||
<span class="k">try</span><span class="p">:</span>
|
||||
<span class="n">report</span> <span class="o">=</span> <span class="n">parse_aggregate_report_file</span><span class="p">(</span><span class="n">content</span><span class="p">,</span> <span class="n">nameservers</span><span class="o">=</span><span class="n">nameservers</span><span class="p">,</span>
|
||||
<span class="n">timeout</span><span class="o">=</span><span class="n">timeout</span><span class="p">)</span>
|
||||
<span class="n">results</span> <span class="o">=</span> <span class="n">OrderedDict</span><span class="p">([(</span><span class="s2">"report_type"</span><span class="p">,</span> <span class="s2">"aggregate"</span><span class="p">),</span>
|
||||
<span class="p">(</span><span class="s2">"report"</span><span class="p">,</span> <span class="n">report</span><span class="p">)])</span>
|
||||
<span class="k">except</span> <span class="n">InvalidAggregateReport</span><span class="p">:</span>
|
||||
<span class="k">try</span><span class="p">:</span>
|
||||
<span class="n">results</span> <span class="o">=</span> <span class="n">parse_report_email</span><span class="p">(</span><span class="n">content</span><span class="p">,</span>
|
||||
<span class="n">nameservers</span><span class="o">=</span><span class="n">nameservers</span><span class="p">,</span>
|
||||
<span class="n">timeout</span><span class="o">=</span><span class="n">timeout</span><span class="p">)</span>
|
||||
<span class="k">except</span> <span class="n">InvalidDMARCReport</span><span class="p">:</span>
|
||||
<span class="k">raise</span> <span class="n">InvalidDMARCReport</span><span class="p">(</span><span class="s2">"Not a valid aggregate or forensic "</span>
|
||||
<span class="s2">"report"</span><span class="p">)</span>
|
||||
<span class="k">return</span> <span class="n">results</span></div>
|
||||
|
||||
|
||||
<div class="viewcode-block" id="get_dmarc_reports_from_inbox"><a class="viewcode-back" href="../index.html#parsedmarc.get_dmarc_reports_from_inbox">[docs]</a><span class="k">def</span> <span class="nf">get_dmarc_reports_from_inbox</span><span class="p">(</span><span class="n">host</span><span class="p">,</span> <span class="n">username</span><span class="p">,</span> <span class="n">password</span><span class="p">,</span>
|
||||
<span class="n">archive_folder</span><span class="o">=</span><span class="s2">"Archive"</span><span class="p">,</span>
|
||||
<span class="n">delete</span><span class="o">=</span><span class="kc">False</span><span class="p">,</span> <span class="n">test</span><span class="o">=</span><span class="kc">False</span><span class="p">,</span>
|
||||
<span class="n">nameservers</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span>
|
||||
<span class="n">dns_timeout</span><span class="o">=</span><span class="mf">6.0</span><span class="p">):</span>
|
||||
<span class="sd">"""</span>
|
||||
<span class="sd"> Fetches and parses DMARC reports from sn inbox</span>
|
||||
|
||||
<span class="sd"> Args:</span>
|
||||
<span class="sd"> host: The mail server hostname or IP address</span>
|
||||
<span class="sd"> username: The mail server username</span>
|
||||
<span class="sd"> password: The mail server password</span>
|
||||
<span class="sd"> archive_folder: The folder to move processed mail to</span>
|
||||
<span class="sd"> delete (bool): Delete messages after processing them</span>
|
||||
<span class="sd"> test (bool): Do not move or delete messages after processing them</span>
|
||||
<span class="sd"> nameservers (list): A list of DNS nameservers to query</span>
|
||||
<span class="sd"> dns_timeout (float): Set the DNS query timeout</span>
|
||||
|
||||
<span class="sd"> Returns:</span>
|
||||
<span class="sd"> OrderedDict: Lists of ``aggregate_reports`` and ``forensic_reports``</span>
|
||||
<span class="sd"> """</span>
|
||||
<span class="k">if</span> <span class="n">delete</span> <span class="ow">and</span> <span class="n">test</span><span class="p">:</span>
|
||||
<span class="k">raise</span> <span class="ne">ValueError</span><span class="p">(</span><span class="s2">"delete and test options are mutually exclusive"</span><span class="p">)</span>
|
||||
|
||||
<span class="n">aggregate_reports</span> <span class="o">=</span> <span class="p">[]</span>
|
||||
<span class="n">forensic_reports</span> <span class="o">=</span> <span class="p">[]</span>
|
||||
<span class="n">aggregate_report_msg_uids</span> <span class="o">=</span> <span class="p">[]</span>
|
||||
<span class="n">forensic_report_msg_uids</span> <span class="o">=</span> <span class="p">[]</span>
|
||||
<span class="n">aggregate_reports_folder</span> <span class="o">=</span> <span class="nb">bytes</span><span class="p">(</span><span class="s2">"</span><span class="si">{0}</span><span class="s2">/Aggregate"</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">archive_folder</span><span class="p">),</span>
|
||||
<span class="n">encoding</span><span class="o">=</span><span class="s2">"utf-8"</span><span class="p">)</span>
|
||||
<span class="n">forensic_reports_folder</span> <span class="o">=</span> <span class="nb">bytes</span><span class="p">(</span><span class="s2">"</span><span class="si">{0}</span><span class="s2">/Forensic"</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">archive_folder</span><span class="p">),</span>
|
||||
<span class="n">encoding</span><span class="o">=</span><span class="s2">"utf-8"</span><span class="p">)</span>
|
||||
<span class="n">archive_folder</span> <span class="o">=</span> <span class="nb">bytes</span><span class="p">(</span><span class="n">archive_folder</span><span class="p">,</span> <span class="n">encoding</span><span class="o">=</span><span class="s2">"utf-8"</span><span class="p">)</span>
|
||||
|
||||
<span class="k">try</span><span class="p">:</span>
|
||||
<span class="n">server</span> <span class="o">=</span> <span class="n">imapclient</span><span class="o">.</span><span class="n">IMAPClient</span><span class="p">(</span><span class="n">host</span><span class="p">,</span> <span class="n">use_uid</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
|
||||
<span class="n">server</span><span class="o">.</span><span class="n">login</span><span class="p">(</span><span class="n">username</span><span class="p">,</span> <span class="n">password</span><span class="p">)</span>
|
||||
<span class="n">server</span><span class="o">.</span><span class="n">select_folder</span><span class="p">(</span><span class="sa">b</span><span class="s1">'INBOX'</span><span class="p">)</span>
|
||||
<span class="k">if</span> <span class="ow">not</span> <span class="n">server</span><span class="o">.</span><span class="n">folder_exists</span><span class="p">(</span><span class="n">archive_folder</span><span class="p">):</span>
|
||||
<span class="n">server</span><span class="o">.</span><span class="n">create_folder</span><span class="p">(</span><span class="n">archive_folder</span><span class="p">)</span>
|
||||
<span class="k">if</span> <span class="ow">not</span> <span class="n">server</span><span class="o">.</span><span class="n">folder_exists</span><span class="p">(</span><span class="n">aggregate_reports_folder</span><span class="p">):</span>
|
||||
<span class="n">server</span><span class="o">.</span><span class="n">create_folder</span><span class="p">(</span><span class="n">aggregate_reports_folder</span><span class="p">)</span>
|
||||
<span class="k">if</span> <span class="ow">not</span> <span class="n">server</span><span class="o">.</span><span class="n">folder_exists</span><span class="p">(</span><span class="n">forensic_reports_folder</span><span class="p">):</span>
|
||||
<span class="n">server</span><span class="o">.</span><span class="n">create_folder</span><span class="p">(</span><span class="n">forensic_reports_folder</span><span class="p">)</span>
|
||||
<span class="n">messages</span> <span class="o">=</span> <span class="n">server</span><span class="o">.</span><span class="n">search</span><span class="p">()</span>
|
||||
<span class="k">for</span> <span class="n">message_uid</span> <span class="ow">in</span> <span class="n">messages</span><span class="p">:</span>
|
||||
<span class="n">raw_msg</span> <span class="o">=</span> <span class="n">server</span><span class="o">.</span><span class="n">fetch</span><span class="p">(</span><span class="n">message_uid</span><span class="p">,</span>
|
||||
<span class="p">[</span><span class="sa">b</span><span class="s1">'RFC822'</span><span class="p">])[</span><span class="n">message_uid</span><span class="p">][</span><span class="sa">b</span><span class="s1">'RFC822'</span><span class="p">]</span>
|
||||
<span class="n">msg_content</span> <span class="o">=</span> <span class="n">raw_msg</span><span class="o">.</span><span class="n">decode</span><span class="p">(</span><span class="s2">"utf-8"</span><span class="p">,</span> <span class="n">errors</span><span class="o">=</span><span class="s2">"replace"</span><span class="p">)</span>
|
||||
|
||||
<span class="k">try</span><span class="p">:</span>
|
||||
<span class="n">parsed_email</span> <span class="o">=</span> <span class="n">parse_report_email</span><span class="p">(</span><span class="n">msg_content</span><span class="p">,</span>
|
||||
<span class="n">nameservers</span><span class="o">=</span><span class="n">nameservers</span><span class="p">,</span>
|
||||
<span class="n">timeout</span><span class="o">=</span><span class="n">dns_timeout</span><span class="p">)</span>
|
||||
<span class="k">if</span> <span class="n">parsed_email</span><span class="p">[</span><span class="s2">"report_type"</span><span class="p">]</span> <span class="o">==</span> <span class="s2">"aggregate"</span><span class="p">:</span>
|
||||
<span class="n">aggregate_reports</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">parsed_email</span><span class="p">[</span><span class="s2">"report"</span><span class="p">])</span>
|
||||
<span class="n">aggregate_report_msg_uids</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">message_uid</span><span class="p">)</span>
|
||||
<span class="k">elif</span> <span class="n">parsed_email</span><span class="p">[</span><span class="s2">"report_type"</span><span class="p">]</span> <span class="o">==</span> <span class="s2">"forensic"</span><span class="p">:</span>
|
||||
<span class="n">forensic_reports</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">parsed_email</span><span class="p">[</span><span class="s2">"report"</span><span class="p">])</span>
|
||||
<span class="n">forensic_report_msg_uids</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">message_uid</span><span class="p">)</span>
|
||||
<span class="k">except</span> <span class="n">InvalidDMARCReport</span> <span class="k">as</span> <span class="n">error</span><span class="p">:</span>
|
||||
<span class="n">logger</span><span class="o">.</span><span class="n">warning</span><span class="p">(</span><span class="n">error</span><span class="o">.</span><span class="fm">__str__</span><span class="p">())</span>
|
||||
|
||||
<span class="k">if</span> <span class="ow">not</span> <span class="n">test</span><span class="p">:</span>
|
||||
<span class="k">if</span> <span class="n">delete</span><span class="p">:</span>
|
||||
<span class="n">processed_messages</span> <span class="o">=</span> <span class="n">aggregate_report_msg_uids</span> <span class="o">+</span> \
|
||||
<span class="n">forensic_report_msg_uids</span>
|
||||
<span class="n">server</span><span class="o">.</span><span class="n">add_flags</span><span class="p">(</span><span class="n">processed_messages</span><span class="p">,</span> <span class="p">[</span><span class="n">imapclient</span><span class="o">.</span><span class="n">DELETED</span><span class="p">])</span>
|
||||
<span class="n">server</span><span class="o">.</span><span class="n">expunge</span><span class="p">()</span>
|
||||
<span class="k">else</span><span class="p">:</span>
|
||||
<span class="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="n">aggregate_report_msg_uids</span><span class="p">)</span> <span class="o">></span> <span class="mi">0</span><span class="p">:</span>
|
||||
<span class="n">server</span><span class="o">.</span><span class="n">move</span><span class="p">(</span><span class="n">aggregate_report_msg_uids</span><span class="p">,</span>
|
||||
<span class="n">aggregate_reports_folder</span><span class="p">)</span>
|
||||
<span class="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="n">forensic_report_msg_uids</span><span class="p">)</span> <span class="o">></span> <span class="mi">0</span><span class="p">:</span>
|
||||
<span class="n">server</span><span class="o">.</span><span class="n">move</span><span class="p">(</span><span class="n">forensic_report_msg_uids</span><span class="p">,</span>
|
||||
<span class="n">forensic_reports_folder</span><span class="p">)</span>
|
||||
|
||||
<span class="n">results</span> <span class="o">=</span> <span class="n">OrderedDict</span><span class="p">([(</span><span class="s2">"aggregate_reports"</span><span class="p">,</span> <span class="n">aggregate_reports</span><span class="p">),</span>
|
||||
<span class="p">(</span><span class="s2">"forensic_reports"</span><span class="p">,</span> <span class="n">forensic_reports</span><span class="p">)])</span>
|
||||
|
||||
<span class="k">return</span> <span class="n">results</span>
|
||||
<span class="k">except</span> <span class="n">imapclient</span><span class="o">.</span><span class="n">exceptions</span><span class="o">.</span><span class="n">IMAPClientError</span> <span class="k">as</span> <span class="n">error</span><span class="p">:</span>
|
||||
<span class="n">error</span> <span class="o">=</span> <span class="n">error</span><span class="o">.</span><span class="fm">__str__</span><span class="p">()</span><span class="o">.</span><span class="n">lstrip</span><span class="p">(</span><span class="s2">"b'"</span><span class="p">)</span><span class="o">.</span><span class="n">rstrip</span><span class="p">(</span><span class="s2">"'"</span><span class="p">)</span><span class="o">.</span><span class="n">rstrip</span><span class="p">(</span><span class="s2">"."</span><span class="p">)</span>
|
||||
<span class="k">raise</span> <span class="n">IMAPError</span><span class="p">(</span><span class="n">error</span><span class="p">)</span>
|
||||
<span class="k">except</span> <span class="n">socket</span><span class="o">.</span><span class="n">gaierror</span><span class="p">:</span>
|
||||
<span class="k">raise</span> <span class="n">IMAPError</span><span class="p">(</span><span class="s2">"DNS resolution failed"</span><span class="p">)</span>
|
||||
<span class="k">except</span> <span class="ne">TimeoutError</span><span class="p">:</span>
|
||||
<span class="k">raise</span> <span class="n">IMAPError</span><span class="p">(</span><span class="s2">"The connection timed out"</span><span class="p">)</span></div>
|
||||
|
||||
|
||||
<div class="viewcode-block" id="save_output"><a class="viewcode-back" href="../index.html#parsedmarc.save_output">[docs]</a><span class="k">def</span> <span class="nf">save_output</span><span class="p">(</span><span class="n">results</span><span class="p">,</span> <span class="n">output_directory</span><span class="o">=</span><span class="s2">"output"</span><span class="p">):</span>
|
||||
<span class="sd">"""</span>
|
||||
<span class="sd"> Save report data in the given directory</span>
|
||||
|
||||
<span class="sd"> Args:</span>
|
||||
<span class="sd"> results (OrderedDict): Parsing results</span>
|
||||
<span class="sd"> output_directory: The patch to the directory to save in</span>
|
||||
<span class="sd"> """</span>
|
||||
|
||||
<span class="n">aggregate_reports</span> <span class="o">=</span> <span class="n">results</span><span class="p">[</span><span class="s2">"aggregate_reports"</span><span class="p">]</span>
|
||||
<span class="n">forensic_reports</span> <span class="o">=</span> <span class="n">results</span><span class="p">[</span><span class="s2">"forensic_reports"</span><span class="p">]</span>
|
||||
|
||||
<span class="k">if</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">exists</span><span class="p">(</span><span class="n">output_directory</span><span class="p">):</span>
|
||||
<span class="k">if</span> <span class="ow">not</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">isdir</span><span class="p">(</span><span class="n">output_directory</span><span class="p">):</span>
|
||||
<span class="k">raise</span> <span class="ne">ValueError</span><span class="p">(</span><span class="s2">"</span><span class="si">{0}</span><span class="s2"> is not a directory"</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">output_directory</span><span class="p">))</span>
|
||||
<span class="k">else</span><span class="p">:</span>
|
||||
<span class="n">os</span><span class="o">.</span><span class="n">makedirs</span><span class="p">(</span><span class="n">output_directory</span><span class="p">)</span>
|
||||
|
||||
<span class="k">with</span> <span class="nb">open</span><span class="p">(</span><span class="s2">"</span><span class="si">{0}</span><span class="s2">"</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">output_directory</span><span class="p">,</span> <span class="s2">"aggregate.json"</span><span class="p">)),</span>
|
||||
<span class="s2">"w"</span><span class="p">,</span> <span class="n">newline</span><span class="o">=</span><span class="s2">"</span><span class="se">\n</span><span class="s2">"</span><span class="p">,</span> <span class="n">encoding</span><span class="o">=</span><span class="s2">"utf-8"</span><span class="p">)</span> <span class="k">as</span> <span class="n">agg_json</span><span class="p">:</span>
|
||||
<span class="n">agg_json</span><span class="o">.</span><span class="n">write</span><span class="p">(</span><span class="n">json</span><span class="o">.</span><span class="n">dumps</span><span class="p">(</span><span class="n">aggregate_reports</span><span class="p">,</span> <span class="n">ensure_ascii</span><span class="o">=</span><span class="kc">False</span><span class="p">,</span>
|
||||
<span class="n">indent</span><span class="o">=</span><span class="mi">2</span><span class="p">))</span>
|
||||
|
||||
<span class="k">with</span> <span class="nb">open</span><span class="p">(</span><span class="s2">"</span><span class="si">{0}</span><span class="s2">"</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">output_directory</span><span class="p">,</span> <span class="s2">"aggregate.csv"</span><span class="p">)),</span>
|
||||
<span class="s2">"w"</span><span class="p">,</span> <span class="n">newline</span><span class="o">=</span><span class="s2">"</span><span class="se">\n</span><span class="s2">"</span><span class="p">,</span> <span class="n">encoding</span><span class="o">=</span><span class="s2">"utf-8"</span><span class="p">)</span> <span class="k">as</span> <span class="n">agg_csv</span><span class="p">:</span>
|
||||
<span class="n">csv</span> <span class="o">=</span> <span class="n">parsed_aggregate_report_to_csv</span><span class="p">(</span><span class="n">aggregate_reports</span><span class="p">)</span>
|
||||
<span class="n">agg_csv</span><span class="o">.</span><span class="n">write</span><span class="p">(</span><span class="n">csv</span><span class="p">)</span>
|
||||
|
||||
<span class="k">with</span> <span class="nb">open</span><span class="p">(</span><span class="s2">"</span><span class="si">{0}</span><span class="s2">"</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">output_directory</span><span class="p">,</span> <span class="s2">"forensic.json"</span><span class="p">)),</span>
|
||||
<span class="s2">"w"</span><span class="p">,</span> <span class="n">newline</span><span class="o">=</span><span class="s2">"</span><span class="se">\n</span><span class="s2">"</span><span class="p">,</span> <span class="n">encoding</span><span class="o">=</span><span class="s2">"utf-8"</span><span class="p">)</span> <span class="k">as</span> <span class="n">for_json</span><span class="p">:</span>
|
||||
<span class="n">for_json</span><span class="o">.</span><span class="n">write</span><span class="p">(</span><span class="n">json</span><span class="o">.</span><span class="n">dumps</span><span class="p">(</span><span class="n">forensic_reports</span><span class="p">,</span> <span class="n">ensure_ascii</span><span class="o">=</span><span class="kc">False</span><span class="p">,</span>
|
||||
<span class="n">indent</span><span class="o">=</span><span class="mi">2</span><span class="p">))</span>
|
||||
|
||||
<span class="k">with</span> <span class="nb">open</span><span class="p">(</span><span class="s2">"</span><span class="si">{0}</span><span class="s2">"</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">output_directory</span><span class="p">,</span> <span class="s2">"forensic.csv"</span><span class="p">)),</span>
|
||||
<span class="s2">"w"</span><span class="p">,</span> <span class="n">newline</span><span class="o">=</span><span class="s2">"</span><span class="se">\n</span><span class="s2">"</span><span class="p">,</span> <span class="n">encoding</span><span class="o">=</span><span class="s2">"utf-8"</span><span class="p">)</span> <span class="k">as</span> <span class="n">for_csv</span><span class="p">:</span>
|
||||
<span class="n">csv</span> <span class="o">=</span> <span class="n">parsed_dmarc_forensic_reports_to_csv</span><span class="p">(</span><span class="n">forensic_reports</span><span class="p">)</span>
|
||||
<span class="n">for_csv</span><span class="o">.</span><span class="n">write</span><span class="p">(</span><span class="n">csv</span><span class="p">)</span>
|
||||
|
||||
<span class="n">samples_directory</span> <span class="o">=</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">output_directory</span><span class="p">,</span> <span class="s2">"samples"</span><span class="p">)</span>
|
||||
<span class="k">if</span> <span class="ow">not</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">exists</span><span class="p">(</span><span class="n">samples_directory</span><span class="p">):</span>
|
||||
<span class="n">os</span><span class="o">.</span><span class="n">makedirs</span><span class="p">(</span><span class="n">samples_directory</span><span class="p">)</span>
|
||||
|
||||
<span class="n">sample_filenames</span> <span class="o">=</span> <span class="p">[]</span>
|
||||
<span class="k">for</span> <span class="n">forensic_report</span> <span class="ow">in</span> <span class="n">forensic_reports</span><span class="p">:</span>
|
||||
<span class="n">sample</span> <span class="o">=</span> <span class="n">forensic_report</span><span class="p">[</span><span class="s2">"sample"</span><span class="p">]</span>
|
||||
<span class="n">message_count</span> <span class="o">=</span> <span class="mi">0</span>
|
||||
<span class="n">parsed_sample</span> <span class="o">=</span> <span class="n">forensic_report</span><span class="p">[</span><span class="s2">"parsed_sample"</span><span class="p">]</span>
|
||||
<span class="n">subject</span> <span class="o">=</span> <span class="n">parsed_sample</span><span class="p">[</span><span class="s2">"filename_safe_subject"</span><span class="p">]</span>
|
||||
<span class="n">filename</span> <span class="o">=</span> <span class="n">subject</span>
|
||||
|
||||
<span class="k">while</span> <span class="n">filename</span> <span class="ow">in</span> <span class="n">sample_filenames</span><span class="p">:</span>
|
||||
<span class="n">message_count</span> <span class="o">+=</span> <span class="mi">1</span>
|
||||
<span class="n">filename</span> <span class="o">=</span> <span class="s2">"</span><span class="si">{0}</span><span class="s2"> (</span><span class="si">{1}</span><span class="s2">)"</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">subject</span><span class="p">,</span> <span class="n">message_count</span><span class="p">)</span>
|
||||
|
||||
<span class="n">sample_filenames</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">filename</span><span class="p">)</span>
|
||||
|
||||
<span class="n">filename</span> <span class="o">=</span> <span class="s2">"</span><span class="si">{0}</span><span class="s2">.eml"</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">filename</span><span class="p">)</span>
|
||||
<span class="n">path</span> <span class="o">=</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">samples_directory</span><span class="p">,</span> <span class="n">filename</span><span class="p">)</span>
|
||||
<span class="k">with</span> <span class="nb">open</span><span class="p">(</span><span class="n">path</span><span class="p">,</span> <span class="s2">"w"</span><span class="p">,</span> <span class="n">newline</span><span class="o">=</span><span class="s2">"</span><span class="se">\n</span><span class="s2">"</span><span class="p">,</span> <span class="n">encoding</span><span class="o">=</span><span class="s2">"utf-8"</span><span class="p">)</span> <span class="k">as</span> <span class="n">sample_file</span><span class="p">:</span>
|
||||
<span class="n">sample_file</span><span class="o">.</span><span class="n">write</span><span class="p">(</span><span class="n">sample</span><span class="p">)</span></div>
|
||||
|
||||
|
||||
<div class="viewcode-block" id="watch_inbox"><a class="viewcode-back" href="../index.html#parsedmarc.watch_inbox">[docs]</a><span class="k">def</span> <span class="nf">watch_inbox</span><span class="p">(</span><span class="n">host</span><span class="p">,</span> <span class="n">username</span><span class="p">,</span> <span class="n">password</span><span class="p">,</span> <span class="n">callback</span><span class="p">,</span> <span class="n">archive_folder</span><span class="o">=</span><span class="s2">"Archive"</span><span class="p">,</span>
|
||||
<span class="n">delete</span><span class="o">=</span><span class="kc">False</span><span class="p">,</span> <span class="n">test</span><span class="o">=</span><span class="kc">False</span><span class="p">,</span> <span class="n">wait</span><span class="o">=</span><span class="mi">30</span><span class="p">,</span> <span class="n">nameservers</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span>
|
||||
<span class="n">dns_timeout</span><span class="o">=</span><span class="mf">6.0</span><span class="p">):</span>
|
||||
<span class="sd">"""</span>
|
||||
<span class="sd"> Use an IDLE IMAP connection to parse incoming emails, and pass the results</span>
|
||||
<span class="sd"> to a callback function</span>
|
||||
|
||||
<span class="sd"> Args:</span>
|
||||
<span class="sd"> host: The mail server hostname or IP address</span>
|
||||
<span class="sd"> username: The mail server username</span>
|
||||
<span class="sd"> password: The mail server password</span>
|
||||
<span class="sd"> callback: The callback function to receive the parsing results</span>
|
||||
<span class="sd"> archive_folder: The folder to move processed mail to</span>
|
||||
<span class="sd"> delete (bool): Delete messages after processing them</span>
|
||||
<span class="sd"> test (bool): Do not move or delete messages after processing them</span>
|
||||
<span class="sd"> wait (int): Number of seconds to wait for a IMAP IDLE response</span>
|
||||
<span class="sd"> nameservers (list): A list of DNS nameservers to query</span>
|
||||
<span class="sd"> dns_timeout (float): Set the DNS query timeout</span>
|
||||
<span class="sd"> """</span>
|
||||
<span class="n">af</span> <span class="o">=</span> <span class="n">archive_folder</span>
|
||||
<span class="n">ns</span> <span class="o">=</span> <span class="n">nameservers</span>
|
||||
<span class="n">dt</span> <span class="o">=</span> <span class="n">dns_timeout</span>
|
||||
|
||||
<span class="n">server</span> <span class="o">=</span> <span class="n">imapclient</span><span class="o">.</span><span class="n">IMAPClient</span><span class="p">(</span><span class="n">host</span><span class="p">)</span>
|
||||
<span class="n">server</span><span class="o">.</span><span class="n">login</span><span class="p">(</span><span class="n">username</span><span class="p">,</span> <span class="n">password</span><span class="p">)</span>
|
||||
|
||||
<span class="n">server</span><span class="o">.</span><span class="n">select_folder</span><span class="p">(</span><span class="sa">b</span><span class="s1">'INBOX'</span><span class="p">)</span>
|
||||
|
||||
<span class="c1"># Start IDLE mode</span>
|
||||
<span class="n">server</span><span class="o">.</span><span class="n">idle</span><span class="p">()</span>
|
||||
|
||||
<span class="k">while</span> <span class="kc">True</span><span class="p">:</span>
|
||||
<span class="k">try</span><span class="p">:</span>
|
||||
<span class="n">responses</span> <span class="o">=</span> <span class="n">server</span><span class="o">.</span><span class="n">idle_check</span><span class="p">(</span><span class="n">timeout</span><span class="o">=</span><span class="n">wait</span><span class="p">)</span>
|
||||
<span class="k">if</span> <span class="n">responses</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span><span class="p">:</span>
|
||||
<span class="k">for</span> <span class="n">response</span> <span class="ow">in</span> <span class="n">responses</span><span class="p">:</span>
|
||||
<span class="k">if</span> <span class="n">response</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">==</span> <span class="sa">b</span><span class="s1">'RECENT'</span> <span class="ow">and</span> <span class="n">response</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">></span> <span class="mi">0</span><span class="p">:</span>
|
||||
<span class="n">res</span> <span class="o">=</span> <span class="n">get_dmarc_reports_from_inbox</span><span class="p">(</span><span class="n">host</span><span class="p">,</span> <span class="n">username</span><span class="p">,</span>
|
||||
<span class="n">password</span><span class="p">,</span>
|
||||
<span class="n">archive_folder</span><span class="o">=</span><span class="n">af</span><span class="p">,</span>
|
||||
<span class="n">delete</span><span class="o">=</span><span class="n">delete</span><span class="p">,</span>
|
||||
<span class="n">test</span><span class="o">=</span><span class="n">test</span><span class="p">,</span>
|
||||
<span class="n">nameservers</span><span class="o">=</span><span class="n">ns</span><span class="p">,</span>
|
||||
<span class="n">dns_timeout</span><span class="o">=</span><span class="n">dt</span><span class="p">)</span>
|
||||
<span class="n">callback</span><span class="p">(</span><span class="n">res</span><span class="p">)</span>
|
||||
|
||||
<span class="k">except</span> <span class="n">imapclient</span><span class="o">.</span><span class="n">exceptions</span><span class="o">.</span><span class="n">IMAPClientError</span> <span class="k">as</span> <span class="n">error</span><span class="p">:</span>
|
||||
<span class="n">error</span> <span class="o">=</span> <span class="n">error</span><span class="o">.</span><span class="fm">__str__</span><span class="p">()</span><span class="o">.</span><span class="n">lstrip</span><span class="p">(</span><span class="s2">"b'"</span><span class="p">)</span><span class="o">.</span><span class="n">rstrip</span><span class="p">(</span><span class="s2">"'"</span><span class="p">)</span><span class="o">.</span><span class="n">rstrip</span><span class="p">(</span><span class="s2">"."</span><span class="p">)</span>
|
||||
<span class="k">raise</span> <span class="n">IMAPError</span><span class="p">(</span><span class="n">error</span><span class="p">)</span>
|
||||
<span class="k">except</span> <span class="n">socket</span><span class="o">.</span><span class="n">gaierror</span><span class="p">:</span>
|
||||
<span class="k">raise</span> <span class="n">IMAPError</span><span class="p">(</span><span class="s2">"DNS resolution failed"</span><span class="p">)</span>
|
||||
<span class="k">except</span> <span class="ne">TimeoutError</span><span class="p">:</span>
|
||||
<span class="k">raise</span> <span class="n">IMAPError</span><span class="p">(</span><span class="s2">"The connection timed out"</span><span class="p">)</span>
|
||||
<span class="k">except</span> <span class="ne">KeyboardInterrupt</span><span class="p">:</span>
|
||||
<span class="k">break</span>
|
||||
|
||||
<span class="n">server</span><span class="o">.</span><span class="n">idle_done</span><span class="p">()</span>
|
||||
<span class="n">logger</span><span class="o">.</span><span class="n">info</span><span class="p">(</span><span class="s2">"</span><span class="se">\n</span><span class="s2">IDLE mode done"</span><span class="p">)</span>
|
||||
<span class="n">server</span><span class="o">.</span><span class="n">logout</span><span class="p">()</span></div>
|
||||
|
||||
|
||||
<span class="k">def</span> <span class="nf">_main</span><span class="p">():</span>
|
||||
<span class="sd">"""Called when the module in executed"""</span>
|
||||
<span class="n">arg_parser</span> <span class="o">=</span> <span class="n">ArgumentParser</span><span class="p">(</span><span class="n">description</span><span class="o">=</span><span class="s2">"Parses aggregate DMARC reports"</span><span class="p">)</span>
|
||||
<span class="n">arg_parser</span><span class="o">.</span><span class="n">add_argument</span><span class="p">(</span><span class="s2">"file_path"</span><span class="p">,</span> <span class="n">nargs</span><span class="o">=</span><span class="s2">"+"</span><span class="p">,</span>
|
||||
<span class="k">def</span> <span class="nf">print_results</span><span class="p">(</span><span class="n">results_</span><span class="p">):</span>
|
||||
<span class="sd">"""</span>
|
||||
<span class="sd"> Print results in human readable format</span>
|
||||
|
||||
<span class="sd"> Args:</span>
|
||||
<span class="sd"> results_ (OrderedDict): Parsing results</span>
|
||||
<span class="sd"> """</span>
|
||||
<span class="nb">print</span><span class="p">(</span><span class="n">json</span><span class="o">.</span><span class="n">dumps</span><span class="p">(</span><span class="n">results_</span><span class="p">,</span> <span class="n">ensure_ascii</span><span class="o">=</span><span class="kc">False</span><span class="p">,</span> <span class="n">indent</span><span class="o">=</span><span class="mi">2</span><span class="p">),</span> <span class="s2">"</span><span class="se">\n</span><span class="s2">"</span><span class="p">)</span>
|
||||
|
||||
<span class="n">arg_parser</span> <span class="o">=</span> <span class="n">ArgumentParser</span><span class="p">(</span><span class="n">description</span><span class="o">=</span><span class="s2">"Parses DMARC reports"</span><span class="p">)</span>
|
||||
<span class="n">arg_parser</span><span class="o">.</span><span class="n">add_argument</span><span class="p">(</span><span class="s2">"file_path"</span><span class="p">,</span> <span class="n">nargs</span><span class="o">=</span><span class="s2">"*"</span><span class="p">,</span>
|
||||
<span class="n">help</span><span class="o">=</span><span class="s2">"one or more paths of aggregate report "</span>
|
||||
<span class="s2">"files (compressed or uncompressed)"</span><span class="p">)</span>
|
||||
<span class="n">arg_parser</span><span class="o">.</span><span class="n">add_argument</span><span class="p">(</span><span class="s2">"-f"</span><span class="p">,</span> <span class="s2">"--format"</span><span class="p">,</span> <span class="n">default</span><span class="o">=</span><span class="s2">"json"</span><span class="p">,</span>
|
||||
<span class="n">help</span><span class="o">=</span><span class="s2">"specify JSON or CSV output format"</span><span class="p">)</span>
|
||||
<span class="n">arg_parser</span><span class="o">.</span><span class="n">add_argument</span><span class="p">(</span><span class="s2">"-o"</span><span class="p">,</span> <span class="s2">"--output"</span><span class="p">,</span>
|
||||
<span class="n">help</span><span class="o">=</span><span class="s2">"output to a file path rather than "</span>
|
||||
<span class="s2">"printing to the screen"</span><span class="p">)</span>
|
||||
<span class="n">arg_parser</span><span class="o">.</span><span class="n">add_argument</span><span class="p">(</span><span class="s2">"-n"</span><span class="p">,</span> <span class="s2">"--nameserver"</span><span class="p">,</span> <span class="n">nargs</span><span class="o">=</span><span class="s2">"+"</span><span class="p">,</span>
|
||||
<span class="n">help</span><span class="o">=</span><span class="s2">"Write output files to the given directory"</span><span class="p">)</span>
|
||||
<span class="n">arg_parser</span><span class="o">.</span><span class="n">add_argument</span><span class="p">(</span><span class="s2">"-n"</span><span class="p">,</span> <span class="s2">"--nameservers"</span><span class="p">,</span> <span class="n">nargs</span><span class="o">=</span><span class="s2">"+"</span><span class="p">,</span>
|
||||
<span class="n">help</span><span class="o">=</span><span class="s2">"nameservers to query"</span><span class="p">)</span>
|
||||
<span class="n">arg_parser</span><span class="o">.</span><span class="n">add_argument</span><span class="p">(</span><span class="s2">"-t"</span><span class="p">,</span> <span class="s2">"--timeout"</span><span class="p">,</span>
|
||||
<span class="n">help</span><span class="o">=</span><span class="s2">"number of seconds to wait for an answer "</span>
|
||||
<span class="s2">"from DNS (default 6.0)"</span><span class="p">,</span>
|
||||
<span class="nb">type</span><span class="o">=</span><span class="nb">float</span><span class="p">,</span>
|
||||
<span class="n">default</span><span class="o">=</span><span class="mf">6.0</span><span class="p">)</span>
|
||||
<span class="n">arg_parser</span><span class="o">.</span><span class="n">add_argument</span><span class="p">(</span><span class="s2">"-H"</span><span class="p">,</span> <span class="s2">"--host"</span><span class="p">,</span> <span class="n">help</span><span class="o">=</span><span class="s2">"IMAP hostname or IP address"</span><span class="p">)</span>
|
||||
<span class="n">arg_parser</span><span class="o">.</span><span class="n">add_argument</span><span class="p">(</span><span class="s2">"-U"</span><span class="p">,</span> <span class="s2">"--username"</span><span class="p">,</span> <span class="n">help</span><span class="o">=</span><span class="s2">"IMAP username"</span><span class="p">)</span>
|
||||
<span class="n">arg_parser</span><span class="o">.</span><span class="n">add_argument</span><span class="p">(</span><span class="s2">"-p"</span><span class="p">,</span> <span class="s2">"--password"</span><span class="p">,</span> <span class="n">help</span><span class="o">=</span><span class="s2">"IMAP password"</span><span class="p">)</span>
|
||||
<span class="n">arg_parser</span><span class="o">.</span><span class="n">add_argument</span><span class="p">(</span><span class="s2">"-a"</span><span class="p">,</span> <span class="s2">"--archive-folder"</span><span class="p">,</span>
|
||||
<span class="n">help</span><span class="o">=</span><span class="s2">"Specifies the IMAP folder to move "</span>
|
||||
<span class="s2">"messages to after processing them "</span>
|
||||
<span class="s2">"(default: Archive)"</span><span class="p">,</span>
|
||||
<span class="n">default</span><span class="o">=</span><span class="s2">"Archive"</span><span class="p">)</span>
|
||||
<span class="n">arg_parser</span><span class="o">.</span><span class="n">add_argument</span><span class="p">(</span><span class="s2">"-d"</span><span class="p">,</span> <span class="s2">"--delete"</span><span class="p">,</span>
|
||||
<span class="n">help</span><span class="o">=</span><span class="s2">"Delete the reports after processing them"</span><span class="p">,</span>
|
||||
<span class="n">action</span><span class="o">=</span><span class="s2">"store_true"</span><span class="p">,</span> <span class="n">default</span><span class="o">=</span><span class="kc">False</span><span class="p">)</span>
|
||||
<span class="n">arg_parser</span><span class="o">.</span><span class="n">add_argument</span><span class="p">(</span><span class="s2">"-i"</span><span class="p">,</span> <span class="s2">"--idle"</span><span class="p">,</span> <span class="n">action</span><span class="o">=</span><span class="s2">"store_true"</span><span class="p">,</span>
|
||||
<span class="n">help</span><span class="o">=</span><span class="s2">"Use an IMAP IDLE connection to process "</span>
|
||||
<span class="s2">"reports as they arrive in the inbox"</span><span class="p">)</span>
|
||||
<span class="n">arg_parser</span><span class="o">.</span><span class="n">add_argument</span><span class="p">(</span><span class="s2">"-T"</span><span class="p">,</span> <span class="s2">"--test"</span><span class="p">,</span>
|
||||
<span class="n">help</span><span class="o">=</span><span class="s2">"Do not move or delete IMAP messages"</span><span class="p">,</span>
|
||||
<span class="n">action</span><span class="o">=</span><span class="s2">"store_true"</span><span class="p">,</span> <span class="n">default</span><span class="o">=</span><span class="kc">False</span><span class="p">)</span>
|
||||
<span class="n">arg_parser</span><span class="o">.</span><span class="n">add_argument</span><span class="p">(</span><span class="s2">"-v"</span><span class="p">,</span> <span class="s2">"--version"</span><span class="p">,</span> <span class="n">action</span><span class="o">=</span><span class="s2">"version"</span><span class="p">,</span>
|
||||
<span class="n">version</span><span class="o">=</span><span class="n">__version__</span><span class="p">)</span>
|
||||
|
||||
<span class="n">aggregate_reports</span> <span class="o">=</span> <span class="p">[]</span>
|
||||
<span class="n">forensic_reports</span> <span class="o">=</span> <span class="p">[]</span>
|
||||
|
||||
<span class="n">args</span> <span class="o">=</span> <span class="n">arg_parser</span><span class="o">.</span><span class="n">parse_args</span><span class="p">()</span>
|
||||
<span class="n">file_paths</span> <span class="o">=</span> <span class="p">[]</span>
|
||||
<span class="k">for</span> <span class="n">file_path</span> <span class="ow">in</span> <span class="n">args</span><span class="o">.</span><span class="n">file_path</span><span class="p">:</span>
|
||||
<span class="n">file_paths</span> <span class="o">+=</span> <span class="n">glob</span><span class="p">(</span><span class="n">file_path</span><span class="p">)</span>
|
||||
<span class="n">file_paths</span> <span class="o">=</span> <span class="nb">list</span><span class="p">(</span><span class="nb">set</span><span class="p">(</span><span class="n">file_paths</span><span class="p">))</span>
|
||||
|
||||
<span class="n">parsed_reports</span> <span class="o">=</span> <span class="p">[]</span>
|
||||
<span class="k">for</span> <span class="n">file_path</span> <span class="ow">in</span> <span class="n">file_paths</span><span class="p">:</span>
|
||||
<span class="k">try</span><span class="p">:</span>
|
||||
<span class="n">report</span> <span class="o">=</span> <span class="n">parse_aggregate_report_file</span><span class="p">(</span><span class="n">file_path</span><span class="p">,</span>
|
||||
<span class="n">nameservers</span><span class="o">=</span><span class="n">args</span><span class="o">.</span><span class="n">nameserver</span><span class="p">,</span>
|
||||
<span class="n">timeout</span><span class="o">=</span><span class="n">args</span><span class="o">.</span><span class="n">timeout</span><span class="p">)</span>
|
||||
<span class="n">parsed_reports</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">report</span><span class="p">)</span>
|
||||
<span class="k">except</span> <span class="n">InvalidAggregateReport</span> <span class="k">as</span> <span class="n">error</span><span class="p">:</span>
|
||||
<span class="n">logger</span><span class="o">.</span><span class="n">error</span><span class="p">(</span><span class="s2">"Unable to parse </span><span class="si">{0}</span><span class="s2">: </span><span class="si">{1}</span><span class="s2">"</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">file_path</span><span class="p">,</span>
|
||||
<span class="n">error</span><span class="o">.</span><span class="fm">__str__</span><span class="p">()))</span>
|
||||
<span class="n">output</span> <span class="o">=</span> <span class="s2">""</span>
|
||||
<span class="k">if</span> <span class="n">args</span><span class="o">.</span><span class="n">format</span><span class="o">.</span><span class="n">lower</span><span class="p">()</span> <span class="o">==</span> <span class="s2">"json"</span><span class="p">:</span>
|
||||
<span class="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="n">parsed_reports</span><span class="p">)</span> <span class="o">==</span> <span class="mi">1</span><span class="p">:</span>
|
||||
<span class="n">parsed_reports</span> <span class="o">=</span> <span class="n">parsed_reports</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span>
|
||||
<span class="n">output</span> <span class="o">=</span> <span class="n">json</span><span class="o">.</span><span class="n">dumps</span><span class="p">(</span><span class="n">parsed_reports</span><span class="p">,</span>
|
||||
<span class="n">ensure_ascii</span><span class="o">=</span><span class="kc">False</span><span class="p">,</span>
|
||||
<span class="n">indent</span><span class="o">=</span><span class="mi">2</span><span class="p">)</span>
|
||||
<span class="k">elif</span> <span class="n">args</span><span class="o">.</span><span class="n">format</span><span class="o">.</span><span class="n">lower</span><span class="p">()</span> <span class="o">==</span> <span class="s2">"csv"</span><span class="p">:</span>
|
||||
<span class="n">output</span> <span class="o">=</span> <span class="n">parsed_aggregate_report_to_csv</span><span class="p">(</span><span class="n">parsed_reports</span><span class="p">)</span>
|
||||
<span class="k">else</span><span class="p">:</span>
|
||||
<span class="n">logger</span><span class="o">.</span><span class="n">error</span><span class="p">(</span><span class="s2">"Invalid output format: </span><span class="si">{0}</span><span class="s2">"</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">args</span><span class="o">.</span><span class="n">format</span><span class="p">))</span>
|
||||
<span class="n">exit</span><span class="p">(</span><span class="o">-</span><span class="mi">1</span><span class="p">)</span>
|
||||
<span class="n">file_results</span> <span class="o">=</span> <span class="n">parse_report_file</span><span class="p">(</span><span class="n">file_path</span><span class="p">,</span>
|
||||
<span class="n">nameservers</span><span class="o">=</span><span class="n">args</span><span class="o">.</span><span class="n">nameservers</span><span class="p">,</span>
|
||||
<span class="n">timeout</span><span class="o">=</span><span class="n">args</span><span class="o">.</span><span class="n">timeout</span><span class="p">)</span>
|
||||
<span class="k">if</span> <span class="n">file_results</span><span class="p">[</span><span class="s2">"report_type"</span><span class="p">]</span> <span class="o">==</span> <span class="s2">"aggregate"</span><span class="p">:</span>
|
||||
<span class="n">aggregate_reports</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">file_results</span><span class="p">[</span><span class="s2">"report"</span><span class="p">])</span>
|
||||
<span class="k">elif</span> <span class="n">file_results</span><span class="p">[</span><span class="s2">"report_type"</span><span class="p">]</span> <span class="o">==</span> <span class="s2">"forensic"</span><span class="p">:</span>
|
||||
<span class="n">forensic_reports</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">file_results</span><span class="p">[</span><span class="s2">"report"</span><span class="p">])</span>
|
||||
|
||||
<span class="k">except</span> <span class="n">ParserError</span> <span class="k">as</span> <span class="n">error</span><span class="p">:</span>
|
||||
<span class="n">logger</span><span class="o">.</span><span class="n">error</span><span class="p">(</span><span class="s2">"Failed to parse </span><span class="si">{0}</span><span class="s2"> - </span><span class="si">{1}</span><span class="s2">"</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">file_path</span><span class="p">,</span>
|
||||
<span class="n">error</span><span class="p">))</span>
|
||||
|
||||
<span class="k">if</span> <span class="n">args</span><span class="o">.</span><span class="n">host</span><span class="p">:</span>
|
||||
<span class="k">try</span><span class="p">:</span>
|
||||
<span class="k">if</span> <span class="n">args</span><span class="o">.</span><span class="n">username</span> <span class="ow">is</span> <span class="kc">None</span> <span class="ow">or</span> <span class="n">args</span><span class="o">.</span><span class="n">password</span> <span class="ow">is</span> <span class="kc">None</span><span class="p">:</span>
|
||||
<span class="n">logger</span><span class="o">.</span><span class="n">error</span><span class="p">(</span><span class="s2">"username and password must be specified if"</span>
|
||||
<span class="s2">"host is specified"</span><span class="p">)</span>
|
||||
|
||||
<span class="n">af</span> <span class="o">=</span> <span class="n">args</span><span class="o">.</span><span class="n">archive_folder</span>
|
||||
<span class="n">reports</span> <span class="o">=</span> <span class="n">get_dmarc_reports_from_inbox</span><span class="p">(</span><span class="n">args</span><span class="o">.</span><span class="n">host</span><span class="p">,</span>
|
||||
<span class="n">args</span><span class="o">.</span><span class="n">username</span><span class="p">,</span>
|
||||
<span class="n">args</span><span class="o">.</span><span class="n">password</span><span class="p">,</span>
|
||||
<span class="n">archive_folder</span><span class="o">=</span><span class="n">af</span><span class="p">,</span>
|
||||
<span class="n">delete</span><span class="o">=</span><span class="n">args</span><span class="o">.</span><span class="n">delete</span><span class="p">,</span>
|
||||
<span class="n">test</span><span class="o">=</span><span class="n">args</span><span class="o">.</span><span class="n">test</span><span class="p">)</span>
|
||||
|
||||
<span class="n">aggregate_reports</span> <span class="o">+=</span> <span class="n">reports</span><span class="p">[</span><span class="s2">"aggregate_reports"</span><span class="p">]</span>
|
||||
<span class="n">forensic_reports</span> <span class="o">+=</span> <span class="n">reports</span><span class="p">[</span><span class="s2">"forensic_reports"</span><span class="p">]</span>
|
||||
|
||||
<span class="k">except</span> <span class="n">IMAPError</span> <span class="k">as</span> <span class="n">error</span><span class="p">:</span>
|
||||
<span class="n">logger</span><span class="o">.</span><span class="n">error</span><span class="p">(</span><span class="s2">"IMAP Error: </span><span class="si">{0}</span><span class="s2">"</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">error</span><span class="o">.</span><span class="fm">__str__</span><span class="p">()))</span>
|
||||
<span class="n">exit</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span>
|
||||
|
||||
<span class="n">results</span> <span class="o">=</span> <span class="n">OrderedDict</span><span class="p">([(</span><span class="s2">"aggregate_reports"</span><span class="p">,</span> <span class="n">aggregate_reports</span><span class="p">),</span>
|
||||
<span class="p">(</span><span class="s2">"forensic_reports"</span><span class="p">,</span> <span class="n">forensic_reports</span><span class="p">)])</span>
|
||||
|
||||
<span class="k">if</span> <span class="n">args</span><span class="o">.</span><span class="n">output</span><span class="p">:</span>
|
||||
<span class="k">with</span> <span class="nb">open</span><span class="p">(</span><span class="n">args</span><span class="o">.</span><span class="n">output</span><span class="p">,</span> <span class="s2">"w"</span><span class="p">,</span> <span class="n">encoding</span><span class="o">=</span><span class="s2">"utf-8"</span><span class="p">,</span> <span class="n">newline</span><span class="o">=</span><span class="s2">"</span><span class="se">\n</span><span class="s2">"</span><span class="p">)</span> <span class="k">as</span> <span class="n">file</span><span class="p">:</span>
|
||||
<span class="n">file</span><span class="o">.</span><span class="n">write</span><span class="p">(</span><span class="n">output</span><span class="p">)</span>
|
||||
<span class="k">else</span><span class="p">:</span>
|
||||
<span class="nb">print</span><span class="p">(</span><span class="n">output</span><span class="p">)</span>
|
||||
<span class="n">save_output</span><span class="p">(</span><span class="n">results</span><span class="p">,</span> <span class="n">output_directory</span><span class="o">=</span><span class="n">args</span><span class="o">.</span><span class="n">output</span><span class="p">)</span>
|
||||
|
||||
<span class="n">print_results</span><span class="p">(</span><span class="n">results</span><span class="p">)</span>
|
||||
|
||||
<span class="k">if</span> <span class="n">args</span><span class="o">.</span><span class="n">host</span> <span class="ow">and</span> <span class="n">args</span><span class="o">.</span><span class="n">idle</span><span class="p">:</span>
|
||||
<span class="n">sleep</span><span class="p">(</span><span class="mi">2</span><span class="p">)</span>
|
||||
<span class="n">logger</span><span class="o">.</span><span class="n">warning</span><span class="p">(</span><span class="s2">"The IMAP Connection is now in IDLE mode. "</span>
|
||||
<span class="s2">"Send yourself an email, or quit with ^c"</span><span class="p">)</span>
|
||||
<span class="k">try</span><span class="p">:</span>
|
||||
<span class="n">watch_inbox</span><span class="p">(</span><span class="n">args</span><span class="o">.</span><span class="n">host</span><span class="p">,</span> <span class="n">args</span><span class="o">.</span><span class="n">username</span><span class="p">,</span> <span class="n">args</span><span class="o">.</span><span class="n">password</span><span class="p">,</span> <span class="n">print_results</span><span class="p">,</span>
|
||||
<span class="n">archive_folder</span><span class="o">=</span><span class="n">args</span><span class="o">.</span><span class="n">archive_folder</span><span class="p">,</span> <span class="n">delete</span><span class="o">=</span><span class="n">args</span><span class="o">.</span><span class="n">delete</span><span class="p">,</span>
|
||||
<span class="n">test</span><span class="o">=</span><span class="n">args</span><span class="o">.</span><span class="n">test</span><span class="p">,</span> <span class="n">nameservers</span><span class="o">=</span><span class="n">args</span><span class="o">.</span><span class="n">nameservers</span><span class="p">,</span>
|
||||
<span class="n">dns_timeout</span><span class="o">=</span><span class="n">args</span><span class="o">.</span><span class="n">timeout</span><span class="p">)</span>
|
||||
<span class="k">except</span> <span class="n">IMAPError</span> <span class="k">as</span> <span class="n">error</span><span class="p">:</span>
|
||||
<span class="n">logger</span><span class="o">.</span><span class="n">error</span><span class="p">(</span><span class="s2">"IMAP Error: </span><span class="si">{0}</span><span class="s2">"</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">error</span><span class="o">.</span><span class="fm">__str__</span><span class="p">()))</span>
|
||||
<span class="n">exit</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span>
|
||||
|
||||
|
||||
<span class="k">if</span> <span class="vm">__name__</span> <span class="o">==</span> <span class="s2">"__main__"</span><span class="p">:</span>
|
||||
@@ -842,7 +1506,7 @@
|
||||
<script type="text/javascript">
|
||||
var DOCUMENTATION_OPTIONS = {
|
||||
URL_ROOT:'../',
|
||||
VERSION:'1.1.0',
|
||||
VERSION:'2.0.0',
|
||||
COLLAPSE_INDEX:false,
|
||||
FILE_SUFFIX:'.html',
|
||||
HAS_SOURCE: true,
|
||||
|
||||
+49
-27
@@ -9,27 +9,29 @@ Welcome to parsedmarc's documentation!
|
||||
|
||||
|Build Status|
|
||||
|
||||
``pasedmarc`` is a Python module and CLI utility for parsing aggregate DMARC reports.
|
||||
``pasedmarc`` is a Python module and CLI utility for parsing DMARC reports.
|
||||
|
||||
Features
|
||||
========
|
||||
|
||||
* Parses draft and 1.0 standard aggregate reports
|
||||
* Parses forensic reports
|
||||
* Can parse reports from an inbox over IMAP
|
||||
* Transparently handles gzip or zip compressed reports
|
||||
* Consistent data structures
|
||||
* Simple JSON or CSV output
|
||||
* Python 2 and 3 support
|
||||
* Simple JSON and/or CSV output
|
||||
|
||||
CLI help
|
||||
========
|
||||
|
||||
::
|
||||
|
||||
usage: parsedmarc.py [-h] [-f FORMAT] [-o OUTPUT]
|
||||
[-n NAMESERVER [NAMESERVER ...]] [-t TIMEOUT] [-v]
|
||||
file_path [file_path ...]
|
||||
usage: parsedmarc [-h] [-o OUTPUT] [-n NAMESERVERS [NAMESERVERS ...]]
|
||||
[-t TIMEOUT] [-H HOST] [-U USERNAME] [-p PASSWORD]
|
||||
[-a ARCHIVE_FOLDER] [-d] [-i] [-T] [-v]
|
||||
[file_path [file_path ...]]
|
||||
|
||||
Parses aggregate DMARC reports
|
||||
Parses DMARC reports
|
||||
|
||||
positional arguments:
|
||||
file_path one or more paths of aggregate report files
|
||||
@@ -37,21 +39,29 @@ CLI help
|
||||
|
||||
optional arguments:
|
||||
-h, --help show this help message and exit
|
||||
-f FORMAT, --format FORMAT
|
||||
specify JSON or CSV output format
|
||||
-o OUTPUT, --output OUTPUT
|
||||
output to a file path rather than printing to the
|
||||
screen
|
||||
-n NAMESERVER [NAMESERVER ...], --nameserver NAMESERVER [NAMESERVER ...]
|
||||
Write output files to the given directory
|
||||
-n NAMESERVERS [NAMESERVERS ...], --nameservers NAMESERVERS [NAMESERVERS ...]
|
||||
nameservers to query
|
||||
-t TIMEOUT, --timeout TIMEOUT
|
||||
number of seconds to wait for an answer from DNS
|
||||
(default 6.0)
|
||||
-H HOST, --host HOST IMAP hostname or IP address
|
||||
-U USERNAME, --username USERNAME
|
||||
IMAP username
|
||||
-p PASSWORD, --password PASSWORD
|
||||
IMAP password
|
||||
-a ARCHIVE_FOLDER, --archive-folder ARCHIVE_FOLDER
|
||||
Specifies the IMAP folder to move messages to after
|
||||
processing them (default: Archive)
|
||||
-d, --delete Delete the reports after processing them
|
||||
-i, --idle Use an IMAP IDLE connection to process reports as they
|
||||
arrive in the inbox
|
||||
-T, --test Do not move or delete IMAP messages
|
||||
-v, --version show program's version number and exit
|
||||
|
||||
|
||||
Sample output
|
||||
=============
|
||||
Sample aggregate report output
|
||||
==============================
|
||||
|
||||
Here are the results from parsing the `example <https://dmarc.org/wiki/FAQ#I_need_to_implement_aggregate_reports.2C_what_do_they_look_like.3F>`_
|
||||
report from the dmarc.org wiki. It's actually an older draft of the the 1.0
|
||||
@@ -59,7 +69,8 @@ report schema standardized in
|
||||
`RFC 7480 Appendix C <https://tools.ietf.org/html/rfc7489#appendix-C>`_.
|
||||
This draft schema is still in wide use.
|
||||
|
||||
``parsedmarc`` produces consistent, normalized output, regardless of the report schema.
|
||||
``parsedmarc`` produces consistent, normalized output, regardless of the report
|
||||
schema.
|
||||
|
||||
JSON
|
||||
----
|
||||
@@ -134,16 +145,12 @@ CSV
|
||||
xml_schema,org_name,org_email,org_extra_contact_info,report_id,begin_date,end_date,errors,domain,adkim,aspf,p,sp,pct,fo,source_ip_address,source_country,source_reverse_dns,source_base_domain,count,disposition,dkim_alignment,spf_alignment,policy_override_reasons,policy_override_comments,envelope_from,header_from,envelope_to,dkim_domains,dkim_selectors,dkim_results,spf_domains,spf_scopes,spf_results
|
||||
draft,acme.com,noreply-dmarc-support@acme.com,http://acme.com/dmarc/support,9391651994964116463,2012-04-27 20:00:00,2012-04-28 19:59:59,,example.com,r,r,none,none,100,0,72.150.241.94,US,adsl-72-150-241-94.shv.bellsouth.net,bellsouth.net,2,none,fail,pass,,,example.com,example.com,,example.com,none,fail,example.com,mfrom,pass
|
||||
|
||||
What about forensic DMARC reports?
|
||||
==================================
|
||||
|
||||
Forensic DMARC reports are emails with an attached email sample that failed a
|
||||
DMARC check. You can parse them with any email message parser, such as
|
||||
`mail-parser <https://pypi.python.org/pypi/mail-parser/>`_.
|
||||
Sample forensic report output
|
||||
=============================
|
||||
|
||||
Very few recipients send forensic reports, and even those who do will often
|
||||
provide only the message headers, and not the message's content, for privacy
|
||||
reasons.
|
||||
I don't have a sample I can share for privacy reasons. If you have a sample
|
||||
forensic report that you can share publicly, please contact me!
|
||||
|
||||
Bug reports
|
||||
===========
|
||||
@@ -164,9 +171,11 @@ On Debian or Ubuntu systems, run:
|
||||
$ sudo apt-get install python3-pip
|
||||
|
||||
|
||||
Python 3 installers for Windows and macOS can be found at https://www.python.org/downloads/
|
||||
Python 3 installers for Windows and macOS can be found at
|
||||
https://www.python.org/downloads/
|
||||
|
||||
To install or upgrade to the latest stable release of ``parsedmarc`` on macOS or Linux, run
|
||||
To install or upgrade to the latest stable release of ``parsedmarc`` on
|
||||
macOS or Linux, run
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
@@ -181,7 +190,20 @@ Or, install the latest development release directly from GitHub:
|
||||
.. note::
|
||||
|
||||
On Windows, ``pip3`` is ``pip``, even with Python 3. So on Windows, simply
|
||||
substitute ``pip`` as an administrator in place of ``sudo pip3``, in the above commands.
|
||||
substitute ``pip`` as an administrator in place of ``sudo pip3``, in the
|
||||
above commands.
|
||||
|
||||
Optional dependencies
|
||||
---------------------
|
||||
|
||||
If you would like to be able to parse emails saved from Microsoft Outlook
|
||||
(i.e. OLE .msg files), install ``msgconvert``:
|
||||
|
||||
On Debian or Ubuntu systems, run:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ sudo apt-get install libemail-outlook-message-perl
|
||||
|
||||
API
|
||||
===
|
||||
|
||||
+47
-4
@@ -9,7 +9,7 @@
|
||||
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
|
||||
<title>Index — parsedmarc 1.1.0 documentation</title>
|
||||
<title>Index — parsedmarc 2.0.0 documentation</title>
|
||||
|
||||
|
||||
|
||||
@@ -36,7 +36,7 @@
|
||||
<link rel="index" title="Index"
|
||||
href="#"/>
|
||||
<link rel="search" title="Search" href="search.html"/>
|
||||
<link rel="top" title="parsedmarc 1.1.0 documentation" href="index.html"/>
|
||||
<link rel="top" title="parsedmarc 2.0.0 documentation" href="index.html"/>
|
||||
|
||||
|
||||
<script src="_static/js/modernizr.min.js"></script>
|
||||
@@ -65,7 +65,7 @@
|
||||
|
||||
|
||||
<div class="version">
|
||||
1.1.0
|
||||
2.0.0
|
||||
</div>
|
||||
|
||||
|
||||
@@ -155,9 +155,12 @@
|
||||
|
||||
<div class="genindex-jumpbox">
|
||||
<a href="#E"><strong>E</strong></a>
|
||||
| <a href="#G"><strong>G</strong></a>
|
||||
| <a href="#H"><strong>H</strong></a>
|
||||
| <a href="#I"><strong>I</strong></a>
|
||||
| <a href="#P"><strong>P</strong></a>
|
||||
| <a href="#S"><strong>S</strong></a>
|
||||
| <a href="#W"><strong>W</strong></a>
|
||||
|
||||
</div>
|
||||
<h2 id="E">E</h2>
|
||||
@@ -168,6 +171,14 @@
|
||||
</ul></td>
|
||||
</tr></table>
|
||||
|
||||
<h2 id="G">G</h2>
|
||||
<table style="width: 100%" class="indextable genindextable"><tr>
|
||||
<td style="width: 33%; vertical-align: top;"><ul>
|
||||
<li><a href="index.html#parsedmarc.get_dmarc_reports_from_inbox">get_dmarc_reports_from_inbox() (in module parsedmarc)</a>
|
||||
</li>
|
||||
</ul></td>
|
||||
</tr></table>
|
||||
|
||||
<h2 id="H">H</h2>
|
||||
<table style="width: 100%" class="indextable genindextable"><tr>
|
||||
<td style="width: 33%; vertical-align: top;"><ul>
|
||||
@@ -179,7 +190,15 @@
|
||||
<h2 id="I">I</h2>
|
||||
<table style="width: 100%" class="indextable genindextable"><tr>
|
||||
<td style="width: 33%; vertical-align: top;"><ul>
|
||||
<li><a href="index.html#parsedmarc.IMAPError">IMAPError</a>
|
||||
</li>
|
||||
<li><a href="index.html#parsedmarc.InvalidAggregateReport">InvalidAggregateReport</a>
|
||||
</li>
|
||||
</ul></td>
|
||||
<td style="width: 33%; vertical-align: top;"><ul>
|
||||
<li><a href="index.html#parsedmarc.InvalidDMARCReport">InvalidDMARCReport</a>
|
||||
</li>
|
||||
<li><a href="index.html#parsedmarc.InvalidForensicReport">InvalidForensicReport</a>
|
||||
</li>
|
||||
</ul></td>
|
||||
</tr></table>
|
||||
@@ -190,12 +209,36 @@
|
||||
<li><a href="index.html#parsedmarc.parse_aggregate_report_file">parse_aggregate_report_file() (in module parsedmarc)</a>
|
||||
</li>
|
||||
<li><a href="index.html#parsedmarc.parse_aggregate_report_xml">parse_aggregate_report_xml() (in module parsedmarc)</a>
|
||||
</li>
|
||||
<li><a href="index.html#parsedmarc.parse_forensic_report">parse_forensic_report() (in module parsedmarc)</a>
|
||||
</li>
|
||||
<li><a href="index.html#parsedmarc.parse_report_email">parse_report_email() (in module parsedmarc)</a>
|
||||
</li>
|
||||
</ul></td>
|
||||
<td style="width: 33%; vertical-align: top;"><ul>
|
||||
<li><a href="index.html#parsedmarc.parse_report_file">parse_report_file() (in module parsedmarc)</a>
|
||||
</li>
|
||||
<li><a href="index.html#parsedmarc.parsed_aggregate_report_to_csv">parsed_aggregate_report_to_csv() (in module parsedmarc)</a>
|
||||
</li>
|
||||
<li><a href="index.html#module-parsedmarc">parsedmarc (module)</a>
|
||||
</li>
|
||||
<li><a href="index.html#parsedmarc.ParserError">ParserError</a>
|
||||
</li>
|
||||
</ul></td>
|
||||
</tr></table>
|
||||
|
||||
<h2 id="S">S</h2>
|
||||
<table style="width: 100%" class="indextable genindextable"><tr>
|
||||
<td style="width: 33%; vertical-align: top;"><ul>
|
||||
<li><a href="index.html#parsedmarc.save_output">save_output() (in module parsedmarc)</a>
|
||||
</li>
|
||||
</ul></td>
|
||||
</tr></table>
|
||||
|
||||
<h2 id="W">W</h2>
|
||||
<table style="width: 100%" class="indextable genindextable"><tr>
|
||||
<td style="width: 33%; vertical-align: top;"><ul>
|
||||
<li><a href="index.html#parsedmarc.watch_inbox">watch_inbox() (in module parsedmarc)</a>
|
||||
</li>
|
||||
</ul></td>
|
||||
</tr></table>
|
||||
@@ -236,7 +279,7 @@
|
||||
<script type="text/javascript">
|
||||
var DOCUMENTATION_OPTIONS = {
|
||||
URL_ROOT:'./',
|
||||
VERSION:'1.1.0',
|
||||
VERSION:'2.0.0',
|
||||
COLLAPSE_INDEX:false,
|
||||
FILE_SUFFIX:'.html',
|
||||
HAS_SOURCE: true,
|
||||
|
||||
+240
-36
@@ -8,7 +8,7 @@
|
||||
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
|
||||
<title>Welcome to parsedmarc’s documentation! — parsedmarc 1.1.0 documentation</title>
|
||||
<title>Welcome to parsedmarc’s documentation! — parsedmarc 2.0.0 documentation</title>
|
||||
|
||||
|
||||
|
||||
@@ -35,7 +35,7 @@
|
||||
<link rel="index" title="Index"
|
||||
href="genindex.html"/>
|
||||
<link rel="search" title="Search" href="search.html"/>
|
||||
<link rel="top" title="parsedmarc 1.1.0 documentation" href="#"/>
|
||||
<link rel="top" title="parsedmarc 2.0.0 documentation" href="#"/>
|
||||
|
||||
|
||||
<script src="_static/js/modernizr.min.js"></script>
|
||||
@@ -64,7 +64,7 @@
|
||||
|
||||
|
||||
<div class="version">
|
||||
1.1.0
|
||||
2.0.0
|
||||
</div>
|
||||
|
||||
|
||||
@@ -93,14 +93,17 @@
|
||||
<li><a class="reference internal" href="#">Welcome to parsedmarc’s documentation!</a><ul>
|
||||
<li><a class="reference internal" href="#features">Features</a></li>
|
||||
<li><a class="reference internal" href="#cli-help">CLI help</a></li>
|
||||
<li><a class="reference internal" href="#sample-output">Sample output</a><ul>
|
||||
<li><a class="reference internal" href="#sample-aggregate-report-output">Sample aggregate report output</a><ul>
|
||||
<li><a class="reference internal" href="#json">JSON</a></li>
|
||||
<li><a class="reference internal" href="#csv">CSV</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a class="reference internal" href="#what-about-forensic-dmarc-reports">What about forensic DMARC reports?</a></li>
|
||||
<li><a class="reference internal" href="#sample-forensic-report-output">Sample forensic report output</a></li>
|
||||
<li><a class="reference internal" href="#bug-reports">Bug reports</a></li>
|
||||
<li><a class="reference internal" href="#installation">Installation</a></li>
|
||||
<li><a class="reference internal" href="#installation">Installation</a><ul>
|
||||
<li><a class="reference internal" href="#optional-dependencies">Optional dependencies</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a class="reference internal" href="#module-parsedmarc">API</a></li>
|
||||
<li><a class="reference internal" href="#indices-and-tables">Indices and tables</a></li>
|
||||
</ul>
|
||||
@@ -171,24 +174,26 @@
|
||||
<div class="section" id="welcome-to-parsedmarc-s-documentation">
|
||||
<h1>Welcome to parsedmarc’s documentation!<a class="headerlink" href="#welcome-to-parsedmarc-s-documentation" title="Permalink to this headline">¶</a></h1>
|
||||
<p><a class="reference external" href="https://travis-ci.org/domainaware/parsedmarc"><img alt="Build Status" src="https://travis-ci.org/domainaware/parsedmarc.svg?branch=master" /></a></p>
|
||||
<p><code class="docutils literal"><span class="pre">pasedmarc</span></code> is a Python module and CLI utility for parsing aggregate DMARC reports.</p>
|
||||
<p><code class="docutils literal"><span class="pre">pasedmarc</span></code> is a Python module and CLI utility for parsing DMARC reports.</p>
|
||||
<div class="section" id="features">
|
||||
<h2>Features<a class="headerlink" href="#features" title="Permalink to this headline">¶</a></h2>
|
||||
<ul class="simple">
|
||||
<li>Parses draft and 1.0 standard aggregate reports</li>
|
||||
<li>Parses forensic reports</li>
|
||||
<li>Can parse reports from an inbox over IMAP</li>
|
||||
<li>Transparently handles gzip or zip compressed reports</li>
|
||||
<li>Consistent data structures</li>
|
||||
<li>Simple JSON or CSV output</li>
|
||||
<li>Python 2 and 3 support</li>
|
||||
<li>Simple JSON and/or CSV output</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="section" id="cli-help">
|
||||
<h2>CLI help<a class="headerlink" href="#cli-help" title="Permalink to this headline">¶</a></h2>
|
||||
<div class="highlight-default"><div class="highlight"><pre><span></span><span class="n">usage</span><span class="p">:</span> <span class="n">parsedmarc</span><span class="o">.</span><span class="n">py</span> <span class="p">[</span><span class="o">-</span><span class="n">h</span><span class="p">]</span> <span class="p">[</span><span class="o">-</span><span class="n">f</span> <span class="n">FORMAT</span><span class="p">]</span> <span class="p">[</span><span class="o">-</span><span class="n">o</span> <span class="n">OUTPUT</span><span class="p">]</span>
|
||||
<span class="p">[</span><span class="o">-</span><span class="n">n</span> <span class="n">NAMESERVER</span> <span class="p">[</span><span class="n">NAMESERVER</span> <span class="o">...</span><span class="p">]]</span> <span class="p">[</span><span class="o">-</span><span class="n">t</span> <span class="n">TIMEOUT</span><span class="p">]</span> <span class="p">[</span><span class="o">-</span><span class="n">v</span><span class="p">]</span>
|
||||
<span class="n">file_path</span> <span class="p">[</span><span class="n">file_path</span> <span class="o">...</span><span class="p">]</span>
|
||||
<div class="highlight-default"><div class="highlight"><pre><span></span><span class="n">usage</span><span class="p">:</span> <span class="n">parsedmarc</span> <span class="p">[</span><span class="o">-</span><span class="n">h</span><span class="p">]</span> <span class="p">[</span><span class="o">-</span><span class="n">o</span> <span class="n">OUTPUT</span><span class="p">]</span> <span class="p">[</span><span class="o">-</span><span class="n">n</span> <span class="n">NAMESERVERS</span> <span class="p">[</span><span class="n">NAMESERVERS</span> <span class="o">...</span><span class="p">]]</span>
|
||||
<span class="p">[</span><span class="o">-</span><span class="n">t</span> <span class="n">TIMEOUT</span><span class="p">]</span> <span class="p">[</span><span class="o">-</span><span class="n">H</span> <span class="n">HOST</span><span class="p">]</span> <span class="p">[</span><span class="o">-</span><span class="n">U</span> <span class="n">USERNAME</span><span class="p">]</span> <span class="p">[</span><span class="o">-</span><span class="n">p</span> <span class="n">PASSWORD</span><span class="p">]</span>
|
||||
<span class="p">[</span><span class="o">-</span><span class="n">a</span> <span class="n">ARCHIVE_FOLDER</span><span class="p">]</span> <span class="p">[</span><span class="o">-</span><span class="n">d</span><span class="p">]</span> <span class="p">[</span><span class="o">-</span><span class="n">i</span><span class="p">]</span> <span class="p">[</span><span class="o">-</span><span class="n">T</span><span class="p">]</span> <span class="p">[</span><span class="o">-</span><span class="n">v</span><span class="p">]</span>
|
||||
<span class="p">[</span><span class="n">file_path</span> <span class="p">[</span><span class="n">file_path</span> <span class="o">...</span><span class="p">]]</span>
|
||||
|
||||
<span class="n">Parses</span> <span class="n">aggregate</span> <span class="n">DMARC</span> <span class="n">reports</span>
|
||||
<span class="n">Parses</span> <span class="n">DMARC</span> <span class="n">reports</span>
|
||||
|
||||
<span class="n">positional</span> <span class="n">arguments</span><span class="p">:</span>
|
||||
<span class="n">file_path</span> <span class="n">one</span> <span class="ow">or</span> <span class="n">more</span> <span class="n">paths</span> <span class="n">of</span> <span class="n">aggregate</span> <span class="n">report</span> <span class="n">files</span>
|
||||
@@ -196,28 +201,38 @@
|
||||
|
||||
<span class="n">optional</span> <span class="n">arguments</span><span class="p">:</span>
|
||||
<span class="o">-</span><span class="n">h</span><span class="p">,</span> <span class="o">--</span><span class="n">help</span> <span class="n">show</span> <span class="n">this</span> <span class="n">help</span> <span class="n">message</span> <span class="ow">and</span> <span class="n">exit</span>
|
||||
<span class="o">-</span><span class="n">f</span> <span class="n">FORMAT</span><span class="p">,</span> <span class="o">--</span><span class="nb">format</span> <span class="n">FORMAT</span>
|
||||
<span class="n">specify</span> <span class="n">JSON</span> <span class="ow">or</span> <span class="n">CSV</span> <span class="n">output</span> <span class="nb">format</span>
|
||||
<span class="o">-</span><span class="n">o</span> <span class="n">OUTPUT</span><span class="p">,</span> <span class="o">--</span><span class="n">output</span> <span class="n">OUTPUT</span>
|
||||
<span class="n">output</span> <span class="n">to</span> <span class="n">a</span> <span class="n">file</span> <span class="n">path</span> <span class="n">rather</span> <span class="n">than</span> <span class="n">printing</span> <span class="n">to</span> <span class="n">the</span>
|
||||
<span class="n">screen</span>
|
||||
<span class="o">-</span><span class="n">n</span> <span class="n">NAMESERVER</span> <span class="p">[</span><span class="n">NAMESERVER</span> <span class="o">...</span><span class="p">],</span> <span class="o">--</span><span class="n">nameserver</span> <span class="n">NAMESERVER</span> <span class="p">[</span><span class="n">NAMESERVER</span> <span class="o">...</span><span class="p">]</span>
|
||||
<span class="n">Write</span> <span class="n">output</span> <span class="n">files</span> <span class="n">to</span> <span class="n">the</span> <span class="n">given</span> <span class="n">directory</span>
|
||||
<span class="o">-</span><span class="n">n</span> <span class="n">NAMESERVERS</span> <span class="p">[</span><span class="n">NAMESERVERS</span> <span class="o">...</span><span class="p">],</span> <span class="o">--</span><span class="n">nameservers</span> <span class="n">NAMESERVERS</span> <span class="p">[</span><span class="n">NAMESERVERS</span> <span class="o">...</span><span class="p">]</span>
|
||||
<span class="n">nameservers</span> <span class="n">to</span> <span class="n">query</span>
|
||||
<span class="o">-</span><span class="n">t</span> <span class="n">TIMEOUT</span><span class="p">,</span> <span class="o">--</span><span class="n">timeout</span> <span class="n">TIMEOUT</span>
|
||||
<span class="n">number</span> <span class="n">of</span> <span class="n">seconds</span> <span class="n">to</span> <span class="n">wait</span> <span class="k">for</span> <span class="n">an</span> <span class="n">answer</span> <span class="kn">from</span> <span class="nn">DNS</span>
|
||||
<span class="p">(</span><span class="n">default</span> <span class="mf">6.0</span><span class="p">)</span>
|
||||
<span class="o">-</span><span class="n">H</span> <span class="n">HOST</span><span class="p">,</span> <span class="o">--</span><span class="n">host</span> <span class="n">HOST</span> <span class="n">IMAP</span> <span class="n">hostname</span> <span class="ow">or</span> <span class="n">IP</span> <span class="n">address</span>
|
||||
<span class="o">-</span><span class="n">U</span> <span class="n">USERNAME</span><span class="p">,</span> <span class="o">--</span><span class="n">username</span> <span class="n">USERNAME</span>
|
||||
<span class="n">IMAP</span> <span class="n">username</span>
|
||||
<span class="o">-</span><span class="n">p</span> <span class="n">PASSWORD</span><span class="p">,</span> <span class="o">--</span><span class="n">password</span> <span class="n">PASSWORD</span>
|
||||
<span class="n">IMAP</span> <span class="n">password</span>
|
||||
<span class="o">-</span><span class="n">a</span> <span class="n">ARCHIVE_FOLDER</span><span class="p">,</span> <span class="o">--</span><span class="n">archive</span><span class="o">-</span><span class="n">folder</span> <span class="n">ARCHIVE_FOLDER</span>
|
||||
<span class="n">Specifies</span> <span class="n">the</span> <span class="n">IMAP</span> <span class="n">folder</span> <span class="n">to</span> <span class="n">move</span> <span class="n">messages</span> <span class="n">to</span> <span class="n">after</span>
|
||||
<span class="n">processing</span> <span class="n">them</span> <span class="p">(</span><span class="n">default</span><span class="p">:</span> <span class="n">Archive</span><span class="p">)</span>
|
||||
<span class="o">-</span><span class="n">d</span><span class="p">,</span> <span class="o">--</span><span class="n">delete</span> <span class="n">Delete</span> <span class="n">the</span> <span class="n">reports</span> <span class="n">after</span> <span class="n">processing</span> <span class="n">them</span>
|
||||
<span class="o">-</span><span class="n">i</span><span class="p">,</span> <span class="o">--</span><span class="n">idle</span> <span class="n">Use</span> <span class="n">an</span> <span class="n">IMAP</span> <span class="n">IDLE</span> <span class="n">connection</span> <span class="n">to</span> <span class="n">process</span> <span class="n">reports</span> <span class="k">as</span> <span class="n">they</span>
|
||||
<span class="n">arrive</span> <span class="ow">in</span> <span class="n">the</span> <span class="n">inbox</span>
|
||||
<span class="o">-</span><span class="n">T</span><span class="p">,</span> <span class="o">--</span><span class="n">test</span> <span class="n">Do</span> <span class="ow">not</span> <span class="n">move</span> <span class="ow">or</span> <span class="n">delete</span> <span class="n">IMAP</span> <span class="n">messages</span>
|
||||
<span class="o">-</span><span class="n">v</span><span class="p">,</span> <span class="o">--</span><span class="n">version</span> <span class="n">show</span> <span class="n">program</span><span class="s1">'s version number and exit</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="section" id="sample-output">
|
||||
<h2>Sample output<a class="headerlink" href="#sample-output" title="Permalink to this headline">¶</a></h2>
|
||||
<div class="section" id="sample-aggregate-report-output">
|
||||
<h2>Sample aggregate report output<a class="headerlink" href="#sample-aggregate-report-output" title="Permalink to this headline">¶</a></h2>
|
||||
<p>Here are the results from parsing the <a class="reference external" href="https://dmarc.org/wiki/FAQ#I_need_to_implement_aggregate_reports.2C_what_do_they_look_like.3F">example</a>
|
||||
report from the dmarc.org wiki. It’s actually an older draft of the the 1.0
|
||||
report schema standardized in
|
||||
<a class="reference external" href="https://tools.ietf.org/html/rfc7489#appendix-C">RFC 7480 Appendix C</a>.
|
||||
This draft schema is still in wide use.</p>
|
||||
<p><code class="docutils literal"><span class="pre">parsedmarc</span></code> produces consistent, normalized output, regardless of the report schema.</p>
|
||||
<p><code class="docutils literal"><span class="pre">parsedmarc</span></code> produces consistent, normalized output, regardless of the report
|
||||
schema.</p>
|
||||
<div class="section" id="json">
|
||||
<h3>JSON<a class="headerlink" href="#json" title="Permalink to this headline">¶</a></h3>
|
||||
<div class="highlight-json"><div class="highlight"><pre><span></span><span class="p">{</span>
|
||||
@@ -290,14 +305,10 @@ This draft schema is still in wide use.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="section" id="what-about-forensic-dmarc-reports">
|
||||
<h2>What about forensic DMARC reports?<a class="headerlink" href="#what-about-forensic-dmarc-reports" title="Permalink to this headline">¶</a></h2>
|
||||
<p>Forensic DMARC reports are emails with an attached email sample that failed a
|
||||
DMARC check. You can parse them with any email message parser, such as
|
||||
<a class="reference external" href="https://pypi.python.org/pypi/mail-parser/">mail-parser</a>.</p>
|
||||
<p>Very few recipients send forensic reports, and even those who do will often
|
||||
provide only the message headers, and not the message’s content, for privacy
|
||||
reasons.</p>
|
||||
<div class="section" id="sample-forensic-report-output">
|
||||
<h2>Sample forensic report output<a class="headerlink" href="#sample-forensic-report-output" title="Permalink to this headline">¶</a></h2>
|
||||
<p>I don’t have a sample I can share for privacy reasons. If you have a sample
|
||||
forensic report that you can share publicly, please contact me!</p>
|
||||
</div>
|
||||
<div class="section" id="bug-reports">
|
||||
<h2>Bug reports<a class="headerlink" href="#bug-reports" title="Permalink to this headline">¶</a></h2>
|
||||
@@ -311,8 +322,10 @@ reasons.</p>
|
||||
<div class="highlight-bash"><div class="highlight"><pre><span></span>$ sudo apt-get install python3-pip
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>Python 3 installers for Windows and macOS can be found at <a class="reference external" href="https://www.python.org/downloads/">https://www.python.org/downloads/</a></p>
|
||||
<p>To install or upgrade to the latest stable release of <code class="docutils literal"><span class="pre">parsedmarc</span></code> on macOS or Linux, run</p>
|
||||
<p>Python 3 installers for Windows and macOS can be found at
|
||||
<a class="reference external" href="https://www.python.org/downloads/">https://www.python.org/downloads/</a></p>
|
||||
<p>To install or upgrade to the latest stable release of <code class="docutils literal"><span class="pre">parsedmarc</span></code> on
|
||||
macOS or Linux, run</p>
|
||||
<div class="highlight-bash"><div class="highlight"><pre><span></span>$ sudo -H pip3 install -U checkdmarc
|
||||
</pre></div>
|
||||
</div>
|
||||
@@ -323,28 +336,62 @@ reasons.</p>
|
||||
<div class="admonition note">
|
||||
<p class="first admonition-title">Note</p>
|
||||
<p class="last">On Windows, <code class="docutils literal"><span class="pre">pip3</span></code> is <code class="docutils literal"><span class="pre">pip</span></code>, even with Python 3. So on Windows, simply
|
||||
substitute <code class="docutils literal"><span class="pre">pip</span></code> as an administrator in place of <code class="docutils literal"><span class="pre">sudo</span> <span class="pre">pip3</span></code>, in the above commands.</p>
|
||||
substitute <code class="docutils literal"><span class="pre">pip</span></code> as an administrator in place of <code class="docutils literal"><span class="pre">sudo</span> <span class="pre">pip3</span></code>, in the
|
||||
above commands.</p>
|
||||
</div>
|
||||
<div class="section" id="optional-dependencies">
|
||||
<h3>Optional dependencies<a class="headerlink" href="#optional-dependencies" title="Permalink to this headline">¶</a></h3>
|
||||
<p>If you would like to be able to parse emails saved from Microsoft Outlook
|
||||
(i.e. OLE .msg files), install <code class="docutils literal"><span class="pre">msgconvert</span></code>:</p>
|
||||
<p>On Debian or Ubuntu systems, run:</p>
|
||||
<div class="highlight-bash"><div class="highlight"><pre><span></span>$ sudo apt-get install libemail-outlook-message-perl
|
||||
</pre></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="section" id="module-parsedmarc">
|
||||
<span id="api"></span><h2>API<a class="headerlink" href="#module-parsedmarc" title="Permalink to this headline">¶</a></h2>
|
||||
<p>A Python module and CLI for parsing aggregate DMARC reports</p>
|
||||
<p>A Python module and CLI for parsing DMARC reports</p>
|
||||
<dl class="exception">
|
||||
<dt id="parsedmarc.IMAPError">
|
||||
<em class="property">exception </em><code class="descclassname">parsedmarc.</code><code class="descname">IMAPError</code><a class="reference internal" href="_modules/parsedmarc.html#IMAPError"><span class="viewcode-link">[source]</span></a><a class="headerlink" href="#parsedmarc.IMAPError" title="Permalink to this definition">¶</a></dt>
|
||||
<dd><p>Raised when an IMAP error occurs</p>
|
||||
</dd></dl>
|
||||
|
||||
<dl class="exception">
|
||||
<dt id="parsedmarc.InvalidAggregateReport">
|
||||
<em class="property">exception </em><code class="descclassname">parsedmarc.</code><code class="descname">InvalidAggregateReport</code><a class="reference internal" href="_modules/parsedmarc.html#InvalidAggregateReport"><span class="viewcode-link">[source]</span></a><a class="headerlink" href="#parsedmarc.InvalidAggregateReport" title="Permalink to this definition">¶</a></dt>
|
||||
<dd><p>Raised when an invalid DMARC aggregate report is encountered</p>
|
||||
</dd></dl>
|
||||
|
||||
<dl class="exception">
|
||||
<dt id="parsedmarc.InvalidDMARCReport">
|
||||
<em class="property">exception </em><code class="descclassname">parsedmarc.</code><code class="descname">InvalidDMARCReport</code><a class="reference internal" href="_modules/parsedmarc.html#InvalidDMARCReport"><span class="viewcode-link">[source]</span></a><a class="headerlink" href="#parsedmarc.InvalidDMARCReport" title="Permalink to this definition">¶</a></dt>
|
||||
<dd><p>Raised when an invalid DMARC report is encountered</p>
|
||||
</dd></dl>
|
||||
|
||||
<dl class="exception">
|
||||
<dt id="parsedmarc.InvalidForensicReport">
|
||||
<em class="property">exception </em><code class="descclassname">parsedmarc.</code><code class="descname">InvalidForensicReport</code><a class="reference internal" href="_modules/parsedmarc.html#InvalidForensicReport"><span class="viewcode-link">[source]</span></a><a class="headerlink" href="#parsedmarc.InvalidForensicReport" title="Permalink to this definition">¶</a></dt>
|
||||
<dd><p>Raised when an invalid DMARC forensic report is encountered</p>
|
||||
</dd></dl>
|
||||
|
||||
<dl class="exception">
|
||||
<dt id="parsedmarc.ParserError">
|
||||
<em class="property">exception </em><code class="descclassname">parsedmarc.</code><code class="descname">ParserError</code><a class="reference internal" href="_modules/parsedmarc.html#ParserError"><span class="viewcode-link">[source]</span></a><a class="headerlink" href="#parsedmarc.ParserError" title="Permalink to this definition">¶</a></dt>
|
||||
<dd><p>Raised whenever the parser fails for some reason</p>
|
||||
</dd></dl>
|
||||
|
||||
<dl class="function">
|
||||
<dt id="parsedmarc.extract_xml">
|
||||
<code class="descclassname">parsedmarc.</code><code class="descname">extract_xml</code><span class="sig-paren">(</span><em>_input</em><span class="sig-paren">)</span><a class="reference internal" href="_modules/parsedmarc.html#extract_xml"><span class="viewcode-link">[source]</span></a><a class="headerlink" href="#parsedmarc.extract_xml" title="Permalink to this definition">¶</a></dt>
|
||||
<code class="descclassname">parsedmarc.</code><code class="descname">extract_xml</code><span class="sig-paren">(</span><em>input_</em><span class="sig-paren">)</span><a class="reference internal" href="_modules/parsedmarc.html#extract_xml"><span class="viewcode-link">[source]</span></a><a class="headerlink" href="#parsedmarc.extract_xml" title="Permalink to this definition">¶</a></dt>
|
||||
<dd><p>Extracts xml from a zip or gzip file at the given path, file-like object,
|
||||
or bytes.</p>
|
||||
<table class="docutils field-list" frame="void" rules="none">
|
||||
<col class="field-name" />
|
||||
<col class="field-body" />
|
||||
<tbody valign="top">
|
||||
<tr class="field-odd field"><th class="field-name">Parameters:</th><td class="field-body"><strong>_input</strong> – A path to a file, a file like object, or bytes</td>
|
||||
<tr class="field-odd field"><th class="field-name">Parameters:</th><td class="field-body"><strong>input</strong> – A path to a file, a file like object, or bytes</td>
|
||||
</tr>
|
||||
<tr class="field-even field"><th class="field-name">Returns:</th><td class="field-body">The extracted XML</td>
|
||||
</tr>
|
||||
@@ -354,6 +401,36 @@ or bytes.</p>
|
||||
</table>
|
||||
</dd></dl>
|
||||
|
||||
<dl class="function">
|
||||
<dt id="parsedmarc.get_dmarc_reports_from_inbox">
|
||||
<code class="descclassname">parsedmarc.</code><code class="descname">get_dmarc_reports_from_inbox</code><span class="sig-paren">(</span><em>host</em>, <em>username</em>, <em>password</em>, <em>archive_folder='Archive'</em>, <em>delete=False</em>, <em>test=False</em>, <em>nameservers=None</em>, <em>dns_timeout=6.0</em><span class="sig-paren">)</span><a class="reference internal" href="_modules/parsedmarc.html#get_dmarc_reports_from_inbox"><span class="viewcode-link">[source]</span></a><a class="headerlink" href="#parsedmarc.get_dmarc_reports_from_inbox" title="Permalink to this definition">¶</a></dt>
|
||||
<dd><p>Fetches and parses DMARC reports from sn inbox</p>
|
||||
<table class="docutils field-list" frame="void" rules="none">
|
||||
<col class="field-name" />
|
||||
<col class="field-body" />
|
||||
<tbody valign="top">
|
||||
<tr class="field-odd field"><th class="field-name">Parameters:</th><td class="field-body"><ul class="first simple">
|
||||
<li><strong>host</strong> – The mail server hostname or IP address</li>
|
||||
<li><strong>username</strong> – The mail server username</li>
|
||||
<li><strong>password</strong> – The mail server password</li>
|
||||
<li><strong>archive_folder</strong> – The folder to move processed mail to</li>
|
||||
<li><strong>delete</strong> (<em>bool</em>) – Delete messages after processing them</li>
|
||||
<li><strong>test</strong> (<em>bool</em>) – Do not move or delete messages after processing them</li>
|
||||
<li><strong>nameservers</strong> (<em>list</em>) – A list of DNS nameservers to query</li>
|
||||
<li><strong>dns_timeout</strong> (<em>float</em>) – Set the DNS query timeout</li>
|
||||
</ul>
|
||||
</td>
|
||||
</tr>
|
||||
<tr class="field-even field"><th class="field-name">Returns:</th><td class="field-body"><p class="first">Lists of <code class="docutils literal"><span class="pre">aggregate_reports</span></code> and <code class="docutils literal"><span class="pre">forensic_reports</span></code></p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr class="field-odd field"><th class="field-name">Return type:</th><td class="field-body"><p class="first last">OrderedDict</p>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</dd></dl>
|
||||
|
||||
<dl class="function">
|
||||
<dt id="parsedmarc.human_timestamp_to_datetime">
|
||||
<code class="descclassname">parsedmarc.</code><code class="descname">human_timestamp_to_datetime</code><span class="sig-paren">(</span><em>human_timestamp</em><span class="sig-paren">)</span><a class="reference internal" href="_modules/parsedmarc.html#human_timestamp_to_datetime"><span class="viewcode-link">[source]</span></a><a class="headerlink" href="#parsedmarc.human_timestamp_to_datetime" title="Permalink to this definition">¶</a></dt>
|
||||
@@ -423,6 +500,88 @@ aggregate DMARC report</p>
|
||||
</table>
|
||||
</dd></dl>
|
||||
|
||||
<dl class="function">
|
||||
<dt id="parsedmarc.parse_forensic_report">
|
||||
<code class="descclassname">parsedmarc.</code><code class="descname">parse_forensic_report</code><span class="sig-paren">(</span><em>feedback_report</em>, <em>sample</em>, <em>sample_headers_only</em>, <em>nameservers=None</em>, <em>timeout=6.0</em><span class="sig-paren">)</span><a class="reference internal" href="_modules/parsedmarc.html#parse_forensic_report"><span class="viewcode-link">[source]</span></a><a class="headerlink" href="#parsedmarc.parse_forensic_report" title="Permalink to this definition">¶</a></dt>
|
||||
<dd><p>Converts a DMARC forensic report and sample to a <code class="docutils literal"><span class="pre">OrderedDict</span></code></p>
|
||||
<table class="docutils field-list" frame="void" rules="none">
|
||||
<col class="field-name" />
|
||||
<col class="field-body" />
|
||||
<tbody valign="top">
|
||||
<tr class="field-odd field"><th class="field-name">Parameters:</th><td class="field-body"><ul class="first simple">
|
||||
<li><strong>feedback_report</strong> – A message’s feedback report as a string</li>
|
||||
<li><strong>sample</strong> – The RFC 822 headers or RFC 822 message sample</li>
|
||||
<li><strong>sample_headers_only</strong> (<em>bool</em>) – Set true if the sample is only headers</li>
|
||||
<li><strong>nameservers</strong> (<em>list</em>) – A list of one or more nameservers to use</li>
|
||||
<li><strong>timeout</strong> (<em>float</em>) – Sets the DNS timeout in seconds</li>
|
||||
</ul>
|
||||
</td>
|
||||
</tr>
|
||||
<tr class="field-even field"><th class="field-name">Returns:</th><td class="field-body"><p class="first">An parsed report and sample</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr class="field-odd field"><th class="field-name">Return type:</th><td class="field-body"><p class="first last">OrderedDict</p>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</dd></dl>
|
||||
|
||||
<dl class="function">
|
||||
<dt id="parsedmarc.parse_report_email">
|
||||
<code class="descclassname">parsedmarc.</code><code class="descname">parse_report_email</code><span class="sig-paren">(</span><em>input_</em>, <em>nameservers=None</em>, <em>timeout=6.0</em><span class="sig-paren">)</span><a class="reference internal" href="_modules/parsedmarc.html#parse_report_email"><span class="viewcode-link">[source]</span></a><a class="headerlink" href="#parsedmarc.parse_report_email" title="Permalink to this definition">¶</a></dt>
|
||||
<dd><p>Parses a DMARC report from an email</p>
|
||||
<table class="docutils field-list" frame="void" rules="none">
|
||||
<col class="field-name" />
|
||||
<col class="field-body" />
|
||||
<tbody valign="top">
|
||||
<tr class="field-odd field"><th class="field-name">Parameters:</th><td class="field-body"><ul class="first simple">
|
||||
<li><strong>input</strong> – An emailed DMARC report in RFC 822 format, as bytes or a string</li>
|
||||
<li><strong>nameservers</strong> (<em>list</em>) – A list of one or more nameservers to use</li>
|
||||
<li><strong>timeout</strong> (<em>float</em>) – Sets the DNS timeout in seconds</li>
|
||||
</ul>
|
||||
</td>
|
||||
</tr>
|
||||
<tr class="field-even field"><th class="field-name">Returns:</th><td class="field-body"><p class="first"><ul class="simple">
|
||||
<li><code class="docutils literal"><span class="pre">report_type</span></code>: <code class="docutils literal"><span class="pre">aggregate</span></code> or <code class="docutils literal"><span class="pre">forensic</span></code></li>
|
||||
<li><code class="docutils literal"><span class="pre">report</span></code>: The parsed report</li>
|
||||
</ul>
|
||||
</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr class="field-odd field"><th class="field-name">Return type:</th><td class="field-body"><p class="first last">OrderedDict</p>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</dd></dl>
|
||||
|
||||
<dl class="function">
|
||||
<dt id="parsedmarc.parse_report_file">
|
||||
<code class="descclassname">parsedmarc.</code><code class="descname">parse_report_file</code><span class="sig-paren">(</span><em>input_</em>, <em>nameservers=None</em>, <em>timeout=6.0</em><span class="sig-paren">)</span><a class="reference internal" href="_modules/parsedmarc.html#parse_report_file"><span class="viewcode-link">[source]</span></a><a class="headerlink" href="#parsedmarc.parse_report_file" title="Permalink to this definition">¶</a></dt>
|
||||
<dd><p>Parses a DMARC aggregate or forensic file at the given path, a
|
||||
file-like object. or bytes</p>
|
||||
<table class="docutils field-list" frame="void" rules="none">
|
||||
<col class="field-name" />
|
||||
<col class="field-body" />
|
||||
<tbody valign="top">
|
||||
<tr class="field-odd field"><th class="field-name">Parameters:</th><td class="field-body"><ul class="first simple">
|
||||
<li><strong>input</strong> – A path to a file, a file like object, or bytes</li>
|
||||
<li><strong>nameservers</strong> (<em>list</em>) – A list of one or more nameservers to use</li>
|
||||
<li><strong>timeout</strong> (<em>float</em>) – Sets the DNS timeout in seconds</li>
|
||||
</ul>
|
||||
</td>
|
||||
</tr>
|
||||
<tr class="field-even field"><th class="field-name">Returns:</th><td class="field-body"><p class="first">The parsed DMARC report</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr class="field-odd field"><th class="field-name">Return type:</th><td class="field-body"><p class="first last">OrderedDict</p>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</dd></dl>
|
||||
|
||||
<dl class="function">
|
||||
<dt id="parsedmarc.parsed_aggregate_report_to_csv">
|
||||
<code class="descclassname">parsedmarc.</code><code class="descname">parsed_aggregate_report_to_csv</code><span class="sig-paren">(</span><em>_input</em><span class="sig-paren">)</span><a class="reference internal" href="_modules/parsedmarc.html#parsed_aggregate_report_to_csv"><span class="viewcode-link">[source]</span></a><a class="headerlink" href="#parsedmarc.parsed_aggregate_report_to_csv" title="Permalink to this definition">¶</a></dt>
|
||||
@@ -442,6 +601,51 @@ headers</p>
|
||||
</table>
|
||||
</dd></dl>
|
||||
|
||||
<dl class="function">
|
||||
<dt id="parsedmarc.save_output">
|
||||
<code class="descclassname">parsedmarc.</code><code class="descname">save_output</code><span class="sig-paren">(</span><em>results</em>, <em>output_directory='output'</em><span class="sig-paren">)</span><a class="reference internal" href="_modules/parsedmarc.html#save_output"><span class="viewcode-link">[source]</span></a><a class="headerlink" href="#parsedmarc.save_output" title="Permalink to this definition">¶</a></dt>
|
||||
<dd><p>Save report data in the given directory</p>
|
||||
<table class="docutils field-list" frame="void" rules="none">
|
||||
<col class="field-name" />
|
||||
<col class="field-body" />
|
||||
<tbody valign="top">
|
||||
<tr class="field-odd field"><th class="field-name">Parameters:</th><td class="field-body"><ul class="first last simple">
|
||||
<li><strong>results</strong> (<em>OrderedDict</em>) – Parsing results</li>
|
||||
<li><strong>output_directory</strong> – The patch to the directory to save in</li>
|
||||
</ul>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</dd></dl>
|
||||
|
||||
<dl class="function">
|
||||
<dt id="parsedmarc.watch_inbox">
|
||||
<code class="descclassname">parsedmarc.</code><code class="descname">watch_inbox</code><span class="sig-paren">(</span><em>host</em>, <em>username</em>, <em>password</em>, <em>callback</em>, <em>archive_folder='Archive'</em>, <em>delete=False</em>, <em>test=False</em>, <em>wait=30</em>, <em>nameservers=None</em>, <em>dns_timeout=6.0</em><span class="sig-paren">)</span><a class="reference internal" href="_modules/parsedmarc.html#watch_inbox"><span class="viewcode-link">[source]</span></a><a class="headerlink" href="#parsedmarc.watch_inbox" title="Permalink to this definition">¶</a></dt>
|
||||
<dd><p>Use an IDLE IMAP connection to parse incoming emails, and pass the results
|
||||
to a callback function</p>
|
||||
<table class="docutils field-list" frame="void" rules="none">
|
||||
<col class="field-name" />
|
||||
<col class="field-body" />
|
||||
<tbody valign="top">
|
||||
<tr class="field-odd field"><th class="field-name">Parameters:</th><td class="field-body"><ul class="first last simple">
|
||||
<li><strong>host</strong> – The mail server hostname or IP address</li>
|
||||
<li><strong>username</strong> – The mail server username</li>
|
||||
<li><strong>password</strong> – The mail server password</li>
|
||||
<li><strong>callback</strong> – The callback function to receive the parsing results</li>
|
||||
<li><strong>archive_folder</strong> – The folder to move processed mail to</li>
|
||||
<li><strong>delete</strong> (<em>bool</em>) – Delete messages after processing them</li>
|
||||
<li><strong>test</strong> (<em>bool</em>) – Do not move or delete messages after processing them</li>
|
||||
<li><strong>wait</strong> (<em>int</em>) – Number of seconds to wait for a IMAP IDLE response</li>
|
||||
<li><strong>nameservers</strong> (<em>list</em>) – A list of DNS nameservers to query</li>
|
||||
<li><strong>dns_timeout</strong> (<em>float</em>) – Set the DNS query timeout</li>
|
||||
</ul>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</dd></dl>
|
||||
|
||||
<div class="toctree-wrapper compound">
|
||||
</div>
|
||||
</div>
|
||||
@@ -490,7 +694,7 @@ headers</p>
|
||||
<script type="text/javascript">
|
||||
var DOCUMENTATION_OPTIONS = {
|
||||
URL_ROOT:'./',
|
||||
VERSION:'1.1.0',
|
||||
VERSION:'2.0.0',
|
||||
COLLAPSE_INDEX:false,
|
||||
FILE_SUFFIX:'.html',
|
||||
HAS_SOURCE: true,
|
||||
|
||||
BIN
Binary file not shown.
+4
-4
@@ -8,7 +8,7 @@
|
||||
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
|
||||
<title>Python Module Index — parsedmarc 1.1.0 documentation</title>
|
||||
<title>Python Module Index — parsedmarc 2.0.0 documentation</title>
|
||||
|
||||
|
||||
|
||||
@@ -35,7 +35,7 @@
|
||||
<link rel="index" title="Index"
|
||||
href="genindex.html"/>
|
||||
<link rel="search" title="Search" href="search.html"/>
|
||||
<link rel="top" title="parsedmarc 1.1.0 documentation" href="index.html"/>
|
||||
<link rel="top" title="parsedmarc 2.0.0 documentation" href="index.html"/>
|
||||
|
||||
|
||||
<script type="text/javascript">
|
||||
@@ -71,7 +71,7 @@
|
||||
|
||||
|
||||
<div class="version">
|
||||
1.1.0
|
||||
2.0.0
|
||||
</div>
|
||||
|
||||
|
||||
@@ -209,7 +209,7 @@
|
||||
<script type="text/javascript">
|
||||
var DOCUMENTATION_OPTIONS = {
|
||||
URL_ROOT:'./',
|
||||
VERSION:'1.1.0',
|
||||
VERSION:'2.0.0',
|
||||
COLLAPSE_INDEX:false,
|
||||
FILE_SUFFIX:'.html',
|
||||
HAS_SOURCE: true,
|
||||
|
||||
+4
-4
@@ -8,7 +8,7 @@
|
||||
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
|
||||
<title>Search — parsedmarc 1.1.0 documentation</title>
|
||||
<title>Search — parsedmarc 2.0.0 documentation</title>
|
||||
|
||||
|
||||
|
||||
@@ -35,7 +35,7 @@
|
||||
<link rel="index" title="Index"
|
||||
href="genindex.html"/>
|
||||
<link rel="search" title="Search" href="#"/>
|
||||
<link rel="top" title="parsedmarc 1.1.0 documentation" href="index.html"/>
|
||||
<link rel="top" title="parsedmarc 2.0.0 documentation" href="index.html"/>
|
||||
|
||||
|
||||
<script src="_static/js/modernizr.min.js"></script>
|
||||
@@ -64,7 +64,7 @@
|
||||
|
||||
|
||||
<div class="version">
|
||||
1.1.0
|
||||
2.0.0
|
||||
</div>
|
||||
|
||||
|
||||
@@ -195,7 +195,7 @@
|
||||
<script type="text/javascript">
|
||||
var DOCUMENTATION_OPTIONS = {
|
||||
URL_ROOT:'./',
|
||||
VERSION:'1.1.0',
|
||||
VERSION:'2.0.0',
|
||||
COLLAPSE_INDEX:false,
|
||||
FILE_SUFFIX:'.html',
|
||||
HAS_SOURCE: true,
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
Search.setIndex({docnames:["index"],envversion:53,filenames:["index.rst"],objects:{"":{parsedmarc:[0,0,0,"-"]},parsedmarc:{InvalidAggregateReport:[0,1,1,""],extract_xml:[0,2,1,""],human_timestamp_to_datetime:[0,2,1,""],parse_aggregate_report_file:[0,2,1,""],parse_aggregate_report_xml:[0,2,1,""],parsed_aggregate_report_to_csv:[0,2,1,""]}},objnames:{"0":["py","module","Python module"],"1":["py","exception","Python exception"],"2":["py","function","Python function"]},objtypes:{"0":"py:module","1":"py:exception","2":"py:function"},terms:{"byte":0,"default":0,"float":0,"null":0,"return":0,DNS:0,The:0,_input:0,abov:0,acm:0,actual:0,adkim:0,administr:0,adsl:0,aggreg:0,ani:0,answer:0,appendix:0,apt:0,argument:0,aspf:0,attach:0,auth_result:0,base_domain:0,begin_d:0,bellsouth:0,can:0,check:0,checkdmarc:0,com:0,command:0,compress:0,consist:0,content:0,convert:0,count:0,countri:0,data:0,datetim:0,debian:0,develop:0,directli:0,disposit:0,dkim:0,dkim_align:0,dkim_domain:0,dkim_result:0,dkim_selector:0,domain:0,domainawar:0,download:0,draft:0,email:0,encount:0,end_dat:0,envelope_from:0,envelope_to:0,error:0,even:0,exampl:0,except:0,exit:0,extract:0,extract_xml:0,fail:0,few:0,file:0,file_path:0,flat:0,format:0,found:0,from:0,get:0,git:0,github:0,given:0,gzip:0,handl:0,header:0,header_from:0,here:0,http:0,human:0,human_timestamp:0,human_timestamp_to_datetim:0,identifi:0,includ:0,index:0,invalid:0,invalidaggregatereport:0,ip_address:0,issu:0,latest:0,like:0,linux:0,list:0,maco:0,mail:0,messag:0,mfrom:0,modul:0,more:0,nameserv:0,net:0,none:0,norepli:0,normal:0,number:0,object:0,often:0,older:0,one:0,onli:0,option:0,ordereddict:0,org:0,org_email:0,org_extra_contact_info:0,org_nam:0,page:0,paramet:0,pars:0,parse_aggregate_report_fil:0,parse_aggregate_report_xml:0,parsed_aggregate_report_to_csv:0,parser:0,pasedmarc:0,pass:0,path:0,pct:0,pip3:0,pip:0,place:0,pleas:0,policy_evalu:0,policy_override_com:0,policy_override_reason:0,policy_publish:0,posit:0,prefer:0,print:0,privaci:0,produc:0,program:0,provid:0,python3:0,python:0,queri:0,rais:0,rather:0,readabl:0,reason:0,recipi:0,record:0,regardless:0,releas:0,report_id:0,report_metadata:0,result:0,reverse_dn:0,rfc:0,run:0,schema:0,scope:0,screen:0,search:0,second:0,selector:0,send:0,set:0,show:0,shv:0,simpl:0,simpli:0,sourc:0,source_base_domain:0,source_countri:0,source_ip_address:0,source_reverse_dn:0,specifi:0,spf:0,spf_align:0,spf_domain:0,spf_result:0,spf_scope:0,stabl:0,standard:0,still:0,str:0,string:0,structur:0,substitut:0,sudo:0,support:0,system:0,than:0,them:0,thi:0,those:0,timeout:0,timestamp:0,tracker:0,transpar:0,type:0,ubuntu:0,uncompress:0,upgrad:0,usag:0,use:0,util:0,veri:0,version:0,wait:0,when:0,who:0,wide:0,wiki:0,window:0,work:0,www:0,xml:0,xml_schema:0,you:0,yyyi:0,zip:0},titles:["Welcome to parsedmarc\u2019s documentation!"],titleterms:{about:0,api:0,bug:0,cli:0,csv:0,dmarc:0,document:0,featur:0,forens:0,help:0,indic:0,instal:0,json:0,output:0,parsedmarc:0,report:0,sampl:0,tabl:0,welcom:0,what:0}})
|
||||
Search.setIndex({docnames:["index"],envversion:53,filenames:["index.rst"],objects:{"":{parsedmarc:[0,0,0,"-"]},parsedmarc:{IMAPError:[0,1,1,""],InvalidAggregateReport:[0,1,1,""],InvalidDMARCReport:[0,1,1,""],InvalidForensicReport:[0,1,1,""],ParserError:[0,1,1,""],extract_xml:[0,2,1,""],get_dmarc_reports_from_inbox:[0,2,1,""],human_timestamp_to_datetime:[0,2,1,""],parse_aggregate_report_file:[0,2,1,""],parse_aggregate_report_xml:[0,2,1,""],parse_forensic_report:[0,2,1,""],parse_report_email:[0,2,1,""],parse_report_file:[0,2,1,""],parsed_aggregate_report_to_csv:[0,2,1,""],save_output:[0,2,1,""],watch_inbox:[0,2,1,""]}},objnames:{"0":["py","module","Python module"],"1":["py","exception","Python exception"],"2":["py","function","Python function"]},objtypes:{"0":"py:module","1":"py:exception","2":"py:function"},terms:{"byte":0,"default":0,"float":0,"function":0,"int":0,"null":0,"return":0,"true":0,DNS:0,OLE:0,The:0,Use:0,_input:0,abl:0,abov:0,acm:0,actual:0,address:0,adkim:0,administr:0,adsl:0,after:0,aggreg:[],aggregate_report:0,ani:[],answer:0,appendix:0,apt:0,archiv:0,archive_fold:0,argument:0,arriv:0,aspf:0,attach:[],auth_result:0,base_domain:0,begin_d:0,bellsouth:0,bool:0,callback:0,can:0,check:[],checkdmarc:0,com:0,command:0,compress:0,connect:0,consist:0,contact:0,content:[],convert:0,count:0,countri:0,data:0,datetim:0,debian:0,delet:0,develop:0,directli:0,directori:0,disposit:0,dkim:0,dkim_align:0,dkim_domain:0,dkim_result:0,dkim_selector:0,dmarc:0,dns_timeout:0,domain:0,domainawar:0,don:0,download:0,draft:0,email:0,encount:0,end_dat:0,envelope_from:0,envelope_to:0,error:0,even:0,exampl:0,except:0,exit:0,extract:0,extract_xml:0,fail:0,fals:0,feedback:0,feedback_report:0,fetch:0,few:[],file:0,file_path:0,flat:0,folder:0,forensic_report:0,format:0,found:0,from:0,get:0,get_dmarc_reports_from_inbox:0,git:0,github:0,given:0,gzip:0,handl:0,have:0,header:0,header_from:0,here:0,host:0,hostnam:0,http:0,human:0,human_timestamp:0,human_timestamp_to_datetim:0,identifi:0,idl:0,imap:0,imaperror:0,inbox:0,includ:0,incom:0,index:0,input:0,input_:0,invalid:0,invalidaggregatereport:0,invaliddmarcreport:0,invalidforensicreport:0,ip_address:0,issu:0,latest:0,libemail:0,like:0,linux:0,list:0,maco:0,mail:0,messag:0,mfrom:0,microsoft:0,modul:0,more:0,move:0,msg:0,msgconvert:0,nameserv:0,net:0,none:0,norepli:0,normal:0,number:0,object:0,occur:0,often:[],older:0,one:0,onli:0,option:[],ordereddict:0,org:0,org_email:0,org_extra_contact_info:0,org_nam:0,outlook:0,output_directori:0,over:0,page:0,paramet:0,pars:0,parse_aggregate_report_fil:0,parse_aggregate_report_xml:0,parse_forensic_report:0,parse_report_email:0,parse_report_fil:0,parsed_aggregate_report_to_csv:0,parser:0,parsererror:0,pasedmarc:0,pass:0,password:0,patch:0,path:0,pct:0,perl:0,pip3:0,pip:0,place:0,pleas:0,policy_evalu:0,policy_override_com:0,policy_override_reason:0,policy_publish:0,posit:0,prefer:0,print:[],privaci:0,process:0,produc:0,program:0,provid:[],publicli:0,python3:0,python:0,queri:0,rais:0,rather:[],readabl:0,reason:0,receiv:0,recipi:[],record:0,regardless:0,releas:0,report_id:0,report_metadata:0,report_typ:0,respons:0,result:0,reverse_dn:0,rfc:0,run:0,sample_headers_onli:0,save:0,save_output:0,schema:0,scope:0,screen:[],search:0,second:0,selector:0,send:[],server:0,set:0,share:0,show:0,shv:0,simpl:0,simpli:0,some:0,sourc:0,source_base_domain:0,source_countri:0,source_ip_address:0,source_reverse_dn:0,specifi:0,spf:0,spf_align:0,spf_domain:0,spf_result:0,spf_scope:0,stabl:0,standard:0,still:0,str:0,string:0,structur:0,substitut:0,sudo:0,support:0,system:0,test:0,than:[],thei:0,them:0,thi:0,those:[],timeout:0,timestamp:0,tracker:0,transpar:0,type:0,ubuntu:0,uncompress:0,upgrad:0,usag:0,use:0,usernam:0,util:0,veri:[],version:0,wait:0,watch_inbox:0,when:0,whenev:0,who:[],wide:0,wiki:0,window:0,work:0,would:0,write:0,www:0,xml:0,xml_schema:0,you:0,yyyi:0,zip:0},titles:["Welcome to parsedmarc\u2019s documentation!"],titleterms:{about:[],aggreg:0,api:0,bug:0,cli:0,csv:0,depend:0,dmarc:[],document:0,featur:0,forens:0,help:0,indic:0,instal:0,json:0,option:0,output:0,parsedmarc:0,report:0,sampl:0,tabl:0,welcom:0,what:[]}})
|
||||
Reference in New Issue
Block a user