Files
parsedmarc/dashboards/splunk/dmarc_aggregate_dashboard.xml
T
a421747a79 Add a Domain policy dropdown filter to the Splunk aggregate dashboard (#854) (#855)
Adds a dropdown that filters every panel on the published DMARC policy
(published_policy.p) or subdomain policy (published_policy.sp), mirroring
the Message disposition dropdown's choices and default and sitting
immediately before it, per the issue spec. Both fields are always present
on parsedmarc-written events (sp defaults to p in the parser), so the
wildcard default matches everything, consistent with the other raw-search
filters.

Also fixes the Splunk docs page's XML-files link, which still pointed at
the pre-#736 splunk/ path and 404ed.

Closes #854

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-07-25 20:48:44 -04:00

373 lines
16 KiB
XML

<form theme="dark" version="1.1">
<label>Aggregate DMARC data</label>
<description>A summary of aggregate DMARC report data</description>
<search id="base_search">
<query>
index="email" sourcetype="dmarc:aggregate" spf_aligned=$spf_aligned$ dkim_aligned=$dkim_aligned$ passed_dmarc=$passed_dmarc$ org_name=$org_name$ source_reverse_dns=$source_reverse_dns$ header_from=$header_from$ envelope_from=$envelope_from$ (published_policy.p=$domain_policy$ OR published_policy.sp=$domain_policy$) disposition=$disposition$ source_ip_address=$source_ip_address$ source_base_domain=$source_base_domain$ source_country=$source_country$
| rename spf_results{}.domain as envelope_domain spf_results{}.result as spf_result spf_results{}.scope as spf_scope dkim_results{}.selector as dkim_selector dkim_results{}.domain as dkim_domain dkim_results{}.result as dkim_result
| fillnull value=null source_reverse_dns source_base_domain dkim_selector dkim_domain dkim_result source_type source_name source_as_name
| search dkim_selector=$dkim_selector$ dkim_domain=$dkim_domain$ source_type="$source_type$" source_name="$source_name$" source_as_name="$source_as_name$"
| table *
</query>
<earliest>$time_range.earliest$</earliest>
<latest>$time_range.latest$</latest>
</search>
<fieldset submitButton="false" autoRun="true">
<input type="dropdown" token="spf_aligned" searchWhenChanged="true">
<label>SPF alignment</label>
<choice value="*">any</choice>
<choice value="true">true</choice>
<choice value="false">false</choice>
<default>*</default>
</input>
<input type="dropdown" token="dkim_aligned" searchWhenChanged="true">
<label>DKIM alignment</label>
<choice value="*">any</choice>
<choice value="true">true</choice>
<choice value="false">false</choice>
<default>*</default>
</input>
<input type="dropdown" token="passed_dmarc" searchWhenChanged="true">
<label>Passed DMARC</label>
<choice value="*">any</choice>
<choice value="true">true</choice>
<choice value="false">false</choice>
<default>*</default>
</input>
<input type="text" token="org_name" searchWhenChanged="true">
<label>Reporting organization</label>
<default>*</default>
</input>
<input type="text" token="header_from" searchWhenChanged="true">
<label>Message header from</label>
<default>*</default>
</input>
<input type="text" token="envelope_from" searchWhenChanged="true">
<label>Envelope from</label>
<default>*</default>
</input>
<input type="dropdown" token="domain_policy" searchWhenChanged="true">
<label>Domain policy</label>
<choice value="*">any</choice>
<choice value="none">none</choice>
<choice value="quarantine">quarantine</choice>
<choice value="reject">reject</choice>
<default>*</default>
</input>
<input type="dropdown" token="disposition" searchWhenChanged="true">
<label>Message disposition</label>
<choice value="*">any</choice>
<choice value="none">none</choice>
<choice value="quarantine">quarantine</choice>
<choice value="reject">reject</choice>
<default>*</default>
</input>
<input type="dropdown" token="source_name" searchWhenChanged="true">
<label>Source name</label>
<default>*</default>
<choice value="*">any</choice>
<initialValue>*</initialValue>
<fieldForLabel>source_name</fieldForLabel>
<fieldForValue>source_name</fieldForValue>
<search>
<query>index="email" sourcetype="dmarc:aggregate" source_type="$source_type$"
| stats count by source_name</query>
</search>
</input>
<input type="dropdown" token="source_type" searchWhenChanged="true">
<label>Source type</label>
<default>*</default>
<initialValue>*</initialValue>
<choice value="*">any</choice>
<fieldForLabel>source_type</fieldForLabel>
<fieldForValue>source_type</fieldForValue>
<search>
<query>index="email" sourcetype="dmarc:aggregate"
| stats count by source_type</query>
</search>
</input>
<input type="dropdown" token="source_as_name" searchWhenChanged="true">
<label>Source AS name</label>
<choice value="*">any</choice>
<default>*</default>
<initialValue>*</initialValue>
<fieldForLabel>source_as_name</fieldForLabel>
<fieldForValue>source_as_name</fieldForValue>
<search>
<query>index="email" sourcetype="dmarc:aggregate"
| stats count by source_as_name</query>
<earliest>0</earliest>
<latest></latest>
</search>
</input>
<input type="text" token="source_ip_address" searchWhenChanged="true">
<label>Source IP address</label>
<default>*</default>
</input>
<input type="text" token="source_reverse_dns" searchWhenChanged="true">
<label>Source reverse DNS</label>
<default>*</default>
</input>
<input type="text" token="source_base_domain" searchWhenChanged="true">
<label>Source base domain</label>
<default>*</default>
</input>
<input type="text" token="source_country" searchWhenChanged="true">
<label>Source country ISO code</label>
<default>*</default>
</input>
<input type="text" token="dkim_selector" searchWhenChanged="true">
<label>DKIM selector</label>
<default>*</default>
</input>
<input type="text" token="dkim_domain" searchWhenChanged="true">
<label>DKIM domain</label>
<default>*</default>
</input>
<input type="time" token="time_range" searchWhenChanged="true">
<label>Time range</label>
<default>
<earliest>-7d@h</earliest>
<latest>now</latest>
</default>
</input>
</fieldset>
<row>
<panel>
<title>SPF alignment</title>
<chart>
<search base="base_search">
<query>| stats sum(message_count) as message_count by spf_aligned</query>
</search>
<option name="charting.chart">pie</option>
<option name="charting.drilldown">none</option>
<option name="charting.fieldColors">{"true":0x65a637,"false":0xd93f3c}</option>
</chart>
</panel>
<panel>
<title>DKIM alignment</title>
<chart>
<search base="base_search">
<query> | stats sum(message_count) by dkim_aligned</query>
</search>
<option name="charting.chart">pie</option>
<option name="charting.drilldown">none</option>
<option name="charting.fieldColors">{"true":0x65a637,"false":0xd93f3c}</option>
<option name="height">250</option>
</chart>
</panel>
<panel>
<title>Passed DMARC</title>
<chart>
<search base="base_search">
<query>| stats sum(message_count) by passed_dmarc</query>
</search>
<option name="charting.chart">pie</option>
<option name="charting.drilldown">none</option>
<option name="charting.fieldColors">{"true":0x65a637,"false":0xd93f3c}</option>
</chart>
</panel>
</row>
<row>
<panel>
<title>Reporting organizations</title>
<table>
<search base="base_search">
<query>| stats sum(message_count) as message_count by org_name | sort -message_count</query>
</search>
<option name="drilldown">none</option>
<option name="refresh.display">progressbar</option>
<format type="number" field="sum(message_count)">
<option name="precision">0</option>
</format>
</table>
</panel>
<panel>
<title>Message sources by reverse DNS</title>
<table>
<search base="base_search">
<query>| fillnull value="none" | stats sum(message_count) as message_count by source_base_domain | sort -message_count</query>
</search>
<option name="drilldown">none</option>
<option name="refresh.display">progressbar</option>
<format type="number" field="sum(message_count)">
<option name="precision">0</option>
</format>
</table>
</panel>
<panel>
<title>Message volume and DMARC compliance by from domain</title>
<table>
<search base="base_search">
<query>| stats sum(message_count) as Messages, sum(eval(if(passed_dmarc="true", message_count, 0))) as passed by header_from | eval "% DMARC Compliant"=if(Messages>0, round(passed/Messages*100, 1), null()) | fields - passed | rename header_from as "From Domain" | sort -Messages</query>
</search>
<option name="drilldown">none</option>
<option name="refresh.display">progressbar</option>
<format type="number" field="Messages">
<option name="precision">0</option>
</format>
<format type="number" field="% DMARC Compliant">
<option name="precision">1</option>
</format>
</table>
</panel>
</row>
<row>
<panel>
<title>Message sources by name and type</title>
<table>
<search base="base_search">
<query> | stats sum(message_count) as message_count by source_name, source_type | sort -message_count</query>
</search>
<option name="drilldown">none</option>
<option name="refresh.display">progressbar</option>
<format type="number" field="message_count">
<option name="precision">0</option>
</format>
</table>
</panel>
</row>
<row>
<panel>
<title>Message sources by Autonomous System</title>
<table>
<search base="base_search">
<query>| stats sum(message_count) as message_count by source_asn, source_as_name, source_as_domain
| eval source_asn = if(isnotnull(source_asn) AND source_asn!="", "AS" . source_asn, source_asn)
| sort -message_count</query>
</search>
<option name="drilldown">none</option>
<option name="refresh.display">progressbar</option>
<format type="number" field="message_count">
<option name="precision">0</option>
</format>
</table>
</panel>
</row>
<row>
<panel>
<title>DMARC passage over time</title>
<chart>
<search base="base_search">
<query>| timechart span=1d sum(message_count) as message_count by passed_dmarc</query>
</search>
<option name="charting.axisTitleX.text">Time</option>
<option name="charting.axisTitleX.visibility">visible</option>
<option name="charting.axisTitleY.text">Messages</option>
<option name="charting.axisTitleY.visibility">visible</option>
<option name="charting.axisTitleY2.visibility">visible</option>
<option name="charting.chart">line</option>
<option name="charting.drilldown">none</option>
<option name="charting.fieldColors">{"true":0x65a637,"false":0xd93f3c}</option>
<option name="charting.legend.placement">right</option>
<option name="height">280</option>
<option name="refresh.display">progressbar</option>
</chart>
</panel>
</row>
<row>
<panel>
<title>Message disposition over time</title>
<chart>
<search base="base_search">
<query>| timechart span=1d sum(message_count) as message_count by disposition</query>
</search>
<option name="charting.axisTitleX.text">Time</option>
<option name="charting.axisTitleY.text">Messages</option>
<option name="charting.chart">line</option>
<option name="charting.chart.nullValueMode">zero</option>
<option name="charting.chart.showDataLabels">none</option>
<option name="charting.drilldown">none</option>
<option name="charting.fieldColors">{"none":0x65a637,"quarantine":0xf2b134,"reject":0xd93f3c}</option>
<option name="refresh.display">progressbar</option>
</chart>
</panel>
</row>
<row>
<panel>
<title>Map of message sources by country</title>
<map>
<search base="base_search">
<query> | iplocation source_ip_address | stats sum(message_count) as message_count by Country | geom geo_countries featureIdField="Country"</query>
</search>
<option name="drilldown">none</option>
<option name="height">566</option>
<option name="mapping.type">choropleth</option>
</map>
</panel>
<panel>
<title>Message sources by country</title>
<table>
<search base="base_search">
<query>| stats sum(message_count) as message_count by source_country | sort -message_count</query>
</search>
<option name="count">20</option>
<option name="drilldown">none</option>
<option name="percentagesRow">false</option>
<option name="refresh.display">progressbar</option>
<format type="number" field="sum(message_count)">
<option name="precision">0</option>
</format>
</table>
</panel>
</row>
<row>
<panel>
<title>Message sources by IP address</title>
<table>
<search base="base_search">
<query>| fillnull value="none" source_reverse_dns source_base_domain | fillnull value="unknown" source_country | stats sum(message_count) as message_count by source_ip_address,source_reverse_dns,source_base_domain,source_country | sort -message_count</query>
</search>
<option name="drilldown">none</option>
<option name="refresh.display">progressbar</option>
<format type="number" field="message_count">
<option name="precision">0</option>
</format>
</table>
</panel>
</row>
<row>
<panel>
<title>SPF details</title>
<table>
<search base="base_search">
<query>| fillnull value="none" source_base_domain envelope_domain spf_scope spf_result
| eval spf_signature=mvzip(mvzip(spf_scope, envelope_domain, " / "), spf_result, " / ")
| mvexpand spf_signature
| stats sum(message_count) as message_count by header_from, envelope_from, spf_signature, source_base_domain, spf_aligned
| eval parts=split(spf_signature, " / "), spf_scope=mvindex(parts, 0), spf_domain=mvindex(parts, 1), spf_result=mvindex(parts, 2)
| table header_from, envelope_from, spf_scope, spf_domain, spf_result, spf_aligned, source_base_domain, message_count
| sort -message_count</query>
</search>
<option name="drilldown">none</option>
<option name="refresh.display">progressbar</option>
<format type="number" field="message_count">
<option name="precision">0</option>
</format>
</table>
</panel>
</row>
<row>
<panel>
<title>DKIM details</title>
<table>
<search base="base_search">
<query>| fillnull value="none" source_base_domain
| eval dkim_signature=mvzip(mvzip(dkim_selector, dkim_domain, " / "), dkim_result, " / ")
| mvexpand dkim_signature
| stats sum(message_count) as message_count by header_from, dkim_signature, dkim_aligned, source_base_domain
| eval parts=split(dkim_signature, " / "), dkim_selector=mvindex(parts, 0), dkim_domain=mvindex(parts, 1), dkim_result=mvindex(parts, 2)
| eval dkim_selector=if(dkim_selector=="null", "none", dkim_selector), dkim_domain=if(dkim_domain=="null", "none", dkim_domain), dkim_result=if(dkim_result=="null", "none", dkim_result)
| table header_from, dkim_selector, dkim_domain, dkim_result, dkim_aligned, source_base_domain, message_count
| sort -message_count</query>
</search>
<option name="drilldown">none</option>
<option name="refresh.display">progressbar</option>
<format type="number" field="message_count">
<option name="precision">0</option>
</format>
</table>
</panel>
</row>
</form>