mirror of
https://github.com/domainaware/parsedmarc.git
synced 2026-06-06 10:49:44 +00:00
Store numbers as number_value; fix conditional guards to != ""
Two corrections confirmed against Google's official content-hub parsers
(content/parsers/third_party/community/*/cbn):
1. Numbers as numbers. count, source_asn, successful_session_count and
failed_session_count were being stored in additional.fields as string_value.
Store them as number_value instead (build string -> convert to uinteger ->
rename to number_value, the content-hub idiom), so SecOps can range-query and
sort them, per parsedmarc's "store numbers as numbers" rule. Booleans stay
string_value (content-hub never uses bool_value) and are still converted in
step 1b for the == "true"/"false" comparisons.
2. Conditional guards. Replaced bare `if [field] {` with `if [field] != "" {`
(76 guards + the detection cascade + policy_override). After 1a initializes
every tested field to "", a bare `if` is true for an empty field (Logstash/CBN
semantics), which would misfire detection and emit empty labels. content-hub
uses `!= ""` ~111x vs 2 bare (both flags); parser flags (no_json_payload,
not_json, *_nan) correctly stay bare.
Verified: braces balance, no stray bare field-guards, all if-tested fields
initialized, all four numeric fields emit number_value.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -48,17 +48,23 @@ DMARC types.
|
||||
## Caveats
|
||||
|
||||
1. **Unvalidated** — see [Status](#status).
|
||||
2. **JSON type handling** — parsedmarc emits `dmarc_aligned` / `spf_aligned` /
|
||||
`dkim_aligned` / `testing` / `normalized_timespan` as JSON booleans and
|
||||
`count` / `*_session_count` / `source_asn` as numbers. Chronicle's `json{}`
|
||||
filter **preserves the original JSON type**, so the parser explicitly
|
||||
converts these to strings (`mutate { convert => { … => "string" } }`) before
|
||||
any comparison — otherwise `[dmarc_aligned] == "false"` would never match.
|
||||
Relatedly, every field tested in an `if` is initialized to `""` *before* the
|
||||
`json` filter, because CBN raises `_failed_parsing_` on a conditional that
|
||||
references a field absent from the log. A DMARC-fail record
|
||||
(`dmarc_aligned=false`) should yield `security_result.category =
|
||||
AUTH_VIOLATION` — still worth confirming in the validation tool.
|
||||
2. **JSON types** — Chronicle's `json{}` filter **preserves the original JSON
|
||||
type**, so parsedmarc's booleans and numbers are handled differently:
|
||||
- **Booleans** (`dmarc_aligned` / `spf_aligned` / `dkim_aligned` / `testing`
|
||||
/ `normalized_timespan`) are converted to strings so `[dmarc_aligned] ==
|
||||
"false"` works, and stored as `string_value` (Google's content-hub parsers
|
||||
never use `bool_value`).
|
||||
- **Numbers** (`count` / `*_session_count` / `source_asn`) are stored as
|
||||
`number_value` — built as a string, `convert`-ed to `uinteger`, then
|
||||
renamed — so SecOps can range-query and sort them (parsedmarc's "store
|
||||
numbers as numbers" rule).
|
||||
|
||||
Every `if`-tested field is initialized to `""` *before* `json` and guarded
|
||||
with `!= ""`: CBN raises `_failed_parsing_` on a conditional referencing an
|
||||
absent field, and treats an initialized-but-empty field as present. A
|
||||
DMARC-fail record (`dmarc_aligned=false`) should yield
|
||||
`security_result.category = AUTH_VIOLATION` — worth confirming in the
|
||||
validation tool.
|
||||
3. **Aggregate count** — a DMARC aggregate record summarizes `count` messages
|
||||
from one source IP, not a single message. Each record becomes one
|
||||
`EMAIL_TRANSACTION` with `count` carried in `additional.fields`. There is no
|
||||
|
||||
@@ -50,11 +50,16 @@ filter {
|
||||
# run through the SecOps parser-validation tool against a live tenant.
|
||||
# Validate with the sample events in README.md before production use.
|
||||
# 2. JSON TYPES ARE PRESERVED. The CBN json{} filter keeps the original JSON
|
||||
# type (a JSON boolean stays a boolean, a number stays a number), so
|
||||
# parsedmarc's boolean *_aligned / testing / normalized_timespan and
|
||||
# numeric count / *_count would NOT match string comparisons. This parser
|
||||
# converts them to strings (step 1b) before any `== "true"` / `== "false"`
|
||||
# test or %{...} use -- as Google's official content-hub parsers do.
|
||||
# type (a JSON boolean stays a boolean, a number stays a number).
|
||||
# Booleans (*_aligned / testing / normalized_timespan) are converted to
|
||||
# strings (step 1b) so `== "true"` / `== "false"` tests work, and stored
|
||||
# as string_value (content-hub never uses bool_value). Numbers (count /
|
||||
# *_session_count / source_asn) are stored as number_value -- built as a
|
||||
# string, convert-ed to uinteger, then renamed to number_value -- so
|
||||
# SecOps can range-query and sort them. Matches the content-hub parsers.
|
||||
# 2b. CONDITIONALS. Every field tested in an `if` is initialized to "" in
|
||||
# step 1a, and guards use `if [field] != ""` (not bare `if [field]`,
|
||||
# which is true for an initialized-but-empty field). Matches content-hub.
|
||||
# 3. AGGREGATE COUNT. A DMARC aggregate record summarizes "count" messages
|
||||
# from one source IP, not a single message. Each becomes one
|
||||
# EMAIL_TRANSACTION with "count" carried in additional.fields; there is no
|
||||
@@ -184,11 +189,14 @@ filter {
|
||||
}
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# 1b. Convert parsedmarc's JSON booleans/numbers to strings. The json{} filter
|
||||
# PRESERVES the original JSON type, so without this, [dmarc_aligned] is a
|
||||
# boolean and `== "false"` never matches (and %{count} on an int is
|
||||
# unreliable). Fields left as "" by step 1a convert as a harmless no-op.
|
||||
# Google's official content-hub parsers use mutate{convert} the same way.
|
||||
# 1b. Convert parsedmarc's JSON booleans to strings so they can be compared.
|
||||
# The json{} filter PRESERVES the original JSON type, so without this
|
||||
# [dmarc_aligned] is a boolean and `== "false"` never matches. Booleans are
|
||||
# stored as string_value (matching Google's content-hub parsers, which
|
||||
# never use bool_value). Numeric fields are deliberately NOT converted
|
||||
# here -- they are stored as number_value (not string) in additional.fields
|
||||
# so SecOps can range-query and sort them; see the count / *_session_count
|
||||
# / source_asn blocks below.
|
||||
# ---------------------------------------------------------------------------
|
||||
mutate {
|
||||
convert => {
|
||||
@@ -197,10 +205,6 @@ filter {
|
||||
"dkim_aligned" => "string"
|
||||
"testing" => "string"
|
||||
"normalized_timespan" => "string"
|
||||
"count" => "string"
|
||||
"source_asn" => "string"
|
||||
"successful_session_count" => "string"
|
||||
"failed_session_count" => "string"
|
||||
}
|
||||
on_error => "convert_error"
|
||||
}
|
||||
@@ -218,11 +222,11 @@ filter {
|
||||
# (a generic name), and dmarc_aligned (a boolean that only becomes testable
|
||||
# after the convert in step 1b -- detection should not depend on that).
|
||||
# ---------------------------------------------------------------------------
|
||||
if [feedback_type] {
|
||||
if [feedback_type] != "" {
|
||||
mutate { replace => { "report_type" => "failure" } }
|
||||
} else if [policy_type] {
|
||||
} else if [policy_type] != "" {
|
||||
mutate { replace => { "report_type" => "smtp_tls" } }
|
||||
} else if [xml_schema] {
|
||||
} else if [xml_schema] != "" {
|
||||
mutate { replace => { "report_type" => "aggregate" } }
|
||||
}
|
||||
|
||||
@@ -238,7 +242,7 @@ filter {
|
||||
|
||||
mutate { replace => { "event_type" => "EMAIL_TRANSACTION" } }
|
||||
|
||||
if [report_id] {
|
||||
if [report_id] != "" {
|
||||
mutate {
|
||||
replace => {
|
||||
"event.idm.read_only_udm.metadata.product_log_id" => "%{report_id}"
|
||||
@@ -247,7 +251,7 @@ filter {
|
||||
}
|
||||
|
||||
# -- event timestamp: start of the record's reporting interval (UTC). --
|
||||
if [begin_date] {
|
||||
if [begin_date] != "" {
|
||||
date {
|
||||
match => ["begin_date", "yyyy-MM-dd HH:mm:ss"]
|
||||
timezone => "UTC"
|
||||
@@ -256,20 +260,20 @@ filter {
|
||||
}
|
||||
|
||||
# -- principal: the sending source (machine details only). --
|
||||
if [source_ip_address] {
|
||||
if [source_ip_address] != "" {
|
||||
mutate {
|
||||
merge => { "event.idm.read_only_udm.principal.ip" => "source_ip_address" }
|
||||
on_error => "agg_src_ip_error"
|
||||
}
|
||||
}
|
||||
if [source_reverse_dns] {
|
||||
if [source_reverse_dns] != "" {
|
||||
mutate {
|
||||
replace => {
|
||||
"event.idm.read_only_udm.principal.hostname" => "%{source_reverse_dns}"
|
||||
}
|
||||
}
|
||||
}
|
||||
if [source_country] {
|
||||
if [source_country] != "" {
|
||||
mutate {
|
||||
replace => {
|
||||
"event.idm.read_only_udm.principal.location.country_or_region" => "%{source_country}"
|
||||
@@ -278,7 +282,7 @@ filter {
|
||||
}
|
||||
|
||||
# -- target: the domain the report is about. --
|
||||
if [domain] {
|
||||
if [domain] != "" {
|
||||
mutate {
|
||||
replace => {
|
||||
"event.idm.read_only_udm.target.hostname" => "%{domain}"
|
||||
@@ -287,7 +291,7 @@ filter {
|
||||
}
|
||||
|
||||
# -- email: aggregate only carries the From domain (see caveat 4). --
|
||||
if [header_from] {
|
||||
if [header_from] != "" {
|
||||
mutate {
|
||||
replace => {
|
||||
"event.idm.read_only_udm.network.email.from" => "%{header_from}"
|
||||
@@ -325,73 +329,78 @@ filter {
|
||||
}
|
||||
|
||||
# -- additional.fields: DMARC dimensions a dashboard would filter on. --
|
||||
if [org_name] {
|
||||
if [org_name] != "" {
|
||||
mutate {
|
||||
replace => { "f_org_name.key" => "org_name" "f_org_name.value.string_value" => "%{org_name}" }
|
||||
merge => { "event.idm.read_only_udm.additional.fields" => "f_org_name" }
|
||||
}
|
||||
}
|
||||
if [org_email] {
|
||||
if [org_email] != "" {
|
||||
mutate {
|
||||
replace => { "f_org_email.key" => "org_email" "f_org_email.value.string_value" => "%{org_email}" }
|
||||
merge => { "event.idm.read_only_udm.additional.fields" => "f_org_email" }
|
||||
}
|
||||
}
|
||||
if [begin_date] {
|
||||
if [begin_date] != "" {
|
||||
mutate {
|
||||
replace => { "f_begin.key" => "begin_date" "f_begin.value.string_value" => "%{begin_date}" }
|
||||
merge => { "event.idm.read_only_udm.additional.fields" => "f_begin" }
|
||||
}
|
||||
}
|
||||
if [end_date] {
|
||||
if [end_date] != "" {
|
||||
mutate {
|
||||
replace => { "f_end.key" => "end_date" "f_end.value.string_value" => "%{end_date}" }
|
||||
merge => { "event.idm.read_only_udm.additional.fields" => "f_end" }
|
||||
}
|
||||
}
|
||||
if [count] {
|
||||
mutate {
|
||||
replace => { "f_count.key" => "count" "f_count.value.string_value" => "%{count}" }
|
||||
merge => { "event.idm.read_only_udm.additional.fields" => "f_count" }
|
||||
}
|
||||
mutate {
|
||||
replace => { "f_count.key" => "count" "f_count.value.string_value" => "%{count}" }
|
||||
}
|
||||
if [p] {
|
||||
mutate {
|
||||
convert => { "f_count.value.string_value" => "uinteger" }
|
||||
on_error => "count_nan"
|
||||
}
|
||||
if ![count_nan] {
|
||||
mutate { rename => { "f_count.value.string_value" => "f_count.value.number_value" } }
|
||||
mutate { merge => { "event.idm.read_only_udm.additional.fields" => "f_count" } }
|
||||
}
|
||||
if [p] != "" {
|
||||
mutate {
|
||||
replace => { "f_p.key" => "dmarc_policy" "f_p.value.string_value" => "%{p}" }
|
||||
merge => { "event.idm.read_only_udm.additional.fields" => "f_p" }
|
||||
}
|
||||
}
|
||||
if [sp] {
|
||||
if [sp] != "" {
|
||||
mutate {
|
||||
replace => { "f_sp.key" => "dmarc_subdomain_policy" "f_sp.value.string_value" => "%{sp}" }
|
||||
merge => { "event.idm.read_only_udm.additional.fields" => "f_sp" }
|
||||
}
|
||||
}
|
||||
if [np] {
|
||||
if [np] != "" {
|
||||
mutate {
|
||||
replace => { "f_np.key" => "dmarc_np_policy" "f_np.value.string_value" => "%{np}" }
|
||||
merge => { "event.idm.read_only_udm.additional.fields" => "f_np" }
|
||||
}
|
||||
}
|
||||
if [pct] {
|
||||
if [pct] != "" {
|
||||
mutate {
|
||||
replace => { "f_pct.key" => "dmarc_pct" "f_pct.value.string_value" => "%{pct}" }
|
||||
merge => { "event.idm.read_only_udm.additional.fields" => "f_pct" }
|
||||
}
|
||||
}
|
||||
if [fo] {
|
||||
if [fo] != "" {
|
||||
mutate {
|
||||
replace => { "f_fo.key" => "dmarc_fo" "f_fo.value.string_value" => "%{fo}" }
|
||||
merge => { "event.idm.read_only_udm.additional.fields" => "f_fo" }
|
||||
}
|
||||
}
|
||||
if [adkim] {
|
||||
if [adkim] != "" {
|
||||
mutate {
|
||||
replace => { "f_adkim.key" => "dkim_alignment_mode" "f_adkim.value.string_value" => "%{adkim}" }
|
||||
merge => { "event.idm.read_only_udm.additional.fields" => "f_adkim" }
|
||||
}
|
||||
}
|
||||
if [aspf] {
|
||||
if [aspf] != "" {
|
||||
mutate {
|
||||
replace => { "f_aspf.key" => "spf_alignment_mode" "f_aspf.value.string_value" => "%{aspf}" }
|
||||
merge => { "event.idm.read_only_udm.additional.fields" => "f_aspf" }
|
||||
@@ -403,7 +412,7 @@ filter {
|
||||
merge => { "event.idm.read_only_udm.additional.fields" => "f_testing" }
|
||||
}
|
||||
}
|
||||
if [discovery_method] {
|
||||
if [discovery_method] != "" {
|
||||
mutate {
|
||||
replace => { "f_disc.key" => "discovery_method" "f_disc.value.string_value" => "%{discovery_method}" }
|
||||
merge => { "event.idm.read_only_udm.additional.fields" => "f_disc" }
|
||||
@@ -435,7 +444,7 @@ filter {
|
||||
merge => { "event.idm.read_only_udm.additional.fields" => "f_dkima" }
|
||||
}
|
||||
}
|
||||
if [disposition] {
|
||||
if [disposition] != "" {
|
||||
mutate {
|
||||
replace => { "f_disp.key" => "disposition" "f_disp.value.string_value" => "%{disposition}" }
|
||||
merge => { "event.idm.read_only_udm.additional.fields" => "f_disp" }
|
||||
@@ -443,37 +452,37 @@ filter {
|
||||
}
|
||||
|
||||
# DKIM / SPF auth detail (comma-joined by parsedmarc).
|
||||
if [dkim_domains] {
|
||||
if [dkim_domains] != "" {
|
||||
mutate {
|
||||
replace => { "f_dkd.key" => "dkim_domains" "f_dkd.value.string_value" => "%{dkim_domains}" }
|
||||
merge => { "event.idm.read_only_udm.additional.fields" => "f_dkd" }
|
||||
}
|
||||
}
|
||||
if [dkim_selectors] {
|
||||
if [dkim_selectors] != "" {
|
||||
mutate {
|
||||
replace => { "f_dks.key" => "dkim_selectors" "f_dks.value.string_value" => "%{dkim_selectors}" }
|
||||
merge => { "event.idm.read_only_udm.additional.fields" => "f_dks" }
|
||||
}
|
||||
}
|
||||
if [dkim_results] {
|
||||
if [dkim_results] != "" {
|
||||
mutate {
|
||||
replace => { "f_dkr.key" => "dkim_results" "f_dkr.value.string_value" => "%{dkim_results}" }
|
||||
merge => { "event.idm.read_only_udm.additional.fields" => "f_dkr" }
|
||||
}
|
||||
}
|
||||
if [spf_domains] {
|
||||
if [spf_domains] != "" {
|
||||
mutate {
|
||||
replace => { "f_spd.key" => "spf_domains" "f_spd.value.string_value" => "%{spf_domains}" }
|
||||
merge => { "event.idm.read_only_udm.additional.fields" => "f_spd" }
|
||||
}
|
||||
}
|
||||
if [spf_scopes] {
|
||||
if [spf_scopes] != "" {
|
||||
mutate {
|
||||
replace => { "f_sps.key" => "spf_scopes" "f_sps.value.string_value" => "%{spf_scopes}" }
|
||||
merge => { "event.idm.read_only_udm.additional.fields" => "f_sps" }
|
||||
}
|
||||
}
|
||||
if [spf_results] {
|
||||
if [spf_results] != "" {
|
||||
mutate {
|
||||
replace => { "f_spr.key" => "spf_results" "f_spr.value.string_value" => "%{spf_results}" }
|
||||
merge => { "event.idm.read_only_udm.additional.fields" => "f_spr" }
|
||||
@@ -481,13 +490,13 @@ filter {
|
||||
}
|
||||
|
||||
# Policy overrides (parsedmarc writes the literal "none" when there are none).
|
||||
if [policy_override_reasons] and [policy_override_reasons] != "none" {
|
||||
if [policy_override_reasons] != "" and [policy_override_reasons] != "none" {
|
||||
mutate {
|
||||
replace => { "f_por.key" => "policy_override_reasons" "f_por.value.string_value" => "%{policy_override_reasons}" }
|
||||
merge => { "event.idm.read_only_udm.additional.fields" => "f_por" }
|
||||
}
|
||||
}
|
||||
if [policy_override_comments] and [policy_override_comments] != "none" {
|
||||
if [policy_override_comments] != "" and [policy_override_comments] != "none" {
|
||||
mutate {
|
||||
replace => { "f_poc.key" => "policy_override_comments" "f_poc.value.string_value" => "%{policy_override_comments}" }
|
||||
merge => { "event.idm.read_only_udm.additional.fields" => "f_poc" }
|
||||
@@ -495,37 +504,42 @@ filter {
|
||||
}
|
||||
|
||||
# Source enrichment from parsedmarc's reverse-DNS / MMDB maps.
|
||||
if [source_base_domain] {
|
||||
if [source_base_domain] != "" {
|
||||
mutate {
|
||||
replace => { "f_sbd.key" => "source_base_domain" "f_sbd.value.string_value" => "%{source_base_domain}" }
|
||||
merge => { "event.idm.read_only_udm.additional.fields" => "f_sbd" }
|
||||
}
|
||||
}
|
||||
if [source_name] {
|
||||
if [source_name] != "" {
|
||||
mutate {
|
||||
replace => { "f_sn.key" => "source_name" "f_sn.value.string_value" => "%{source_name}" }
|
||||
merge => { "event.idm.read_only_udm.additional.fields" => "f_sn" }
|
||||
}
|
||||
}
|
||||
if [source_type] {
|
||||
if [source_type] != "" {
|
||||
mutate {
|
||||
replace => { "f_st.key" => "source_type" "f_st.value.string_value" => "%{source_type}" }
|
||||
merge => { "event.idm.read_only_udm.additional.fields" => "f_st" }
|
||||
}
|
||||
}
|
||||
if [source_asn] {
|
||||
mutate {
|
||||
replace => { "f_asn.key" => "source_asn" "f_asn.value.string_value" => "%{source_asn}" }
|
||||
merge => { "event.idm.read_only_udm.additional.fields" => "f_asn" }
|
||||
}
|
||||
mutate {
|
||||
replace => { "f_asn.key" => "source_asn" "f_asn.value.string_value" => "%{source_asn}" }
|
||||
}
|
||||
if [source_as_name] {
|
||||
mutate {
|
||||
convert => { "f_asn.value.string_value" => "uinteger" }
|
||||
on_error => "asn_nan"
|
||||
}
|
||||
if ![asn_nan] {
|
||||
mutate { rename => { "f_asn.value.string_value" => "f_asn.value.number_value" } }
|
||||
mutate { merge => { "event.idm.read_only_udm.additional.fields" => "f_asn" } }
|
||||
}
|
||||
if [source_as_name] != "" {
|
||||
mutate {
|
||||
replace => { "f_asnm.key" => "source_as_name" "f_asnm.value.string_value" => "%{source_as_name}" }
|
||||
merge => { "event.idm.read_only_udm.additional.fields" => "f_asnm" }
|
||||
}
|
||||
}
|
||||
if [source_as_domain] {
|
||||
if [source_as_domain] != "" {
|
||||
mutate {
|
||||
replace => { "f_asd.key" => "source_as_domain" "f_asd.value.string_value" => "%{source_as_domain}" }
|
||||
merge => { "event.idm.read_only_udm.additional.fields" => "f_asd" }
|
||||
@@ -533,13 +547,13 @@ filter {
|
||||
}
|
||||
|
||||
# Envelope identifiers (usually empty in aggregate reports).
|
||||
if [envelope_from] {
|
||||
if [envelope_from] != "" {
|
||||
mutate {
|
||||
replace => { "f_ef.key" => "envelope_from" "f_ef.value.string_value" => "%{envelope_from}" }
|
||||
merge => { "event.idm.read_only_udm.additional.fields" => "f_ef" }
|
||||
}
|
||||
}
|
||||
if [envelope_to] {
|
||||
if [envelope_to] != "" {
|
||||
mutate {
|
||||
replace => { "f_et.key" => "envelope_to" "f_et.value.string_value" => "%{envelope_to}" }
|
||||
merge => { "event.idm.read_only_udm.additional.fields" => "f_et" }
|
||||
@@ -554,7 +568,7 @@ filter {
|
||||
|
||||
mutate { replace => { "event_type" => "EMAIL_TRANSACTION" } }
|
||||
|
||||
if [message_id] {
|
||||
if [message_id] != "" {
|
||||
mutate {
|
||||
replace => {
|
||||
"event.idm.read_only_udm.metadata.product_log_id" => "%{message_id}"
|
||||
@@ -563,7 +577,7 @@ filter {
|
||||
}
|
||||
|
||||
# -- event timestamp: message arrival time (UTC). --
|
||||
if [arrival_date_utc] {
|
||||
if [arrival_date_utc] != "" {
|
||||
date {
|
||||
match => ["arrival_date_utc", "yyyy-MM-dd HH:mm:ss"]
|
||||
timezone => "UTC"
|
||||
@@ -572,20 +586,20 @@ filter {
|
||||
}
|
||||
|
||||
# -- principal: the sending source. --
|
||||
if [source_ip_address] {
|
||||
if [source_ip_address] != "" {
|
||||
mutate {
|
||||
merge => { "event.idm.read_only_udm.principal.ip" => "source_ip_address" }
|
||||
on_error => "fail_src_ip_error"
|
||||
}
|
||||
}
|
||||
if [source_reverse_dns] {
|
||||
if [source_reverse_dns] != "" {
|
||||
mutate {
|
||||
replace => {
|
||||
"event.idm.read_only_udm.principal.hostname" => "%{source_reverse_dns}"
|
||||
}
|
||||
}
|
||||
}
|
||||
if [source_country] {
|
||||
if [source_country] != "" {
|
||||
mutate {
|
||||
replace => {
|
||||
"event.idm.read_only_udm.principal.location.country_or_region" => "%{source_country}"
|
||||
@@ -594,7 +608,7 @@ filter {
|
||||
}
|
||||
|
||||
# -- target: the reported (claimed) domain. --
|
||||
if [reported_domain] {
|
||||
if [reported_domain] != "" {
|
||||
mutate {
|
||||
replace => {
|
||||
"event.idm.read_only_udm.target.hostname" => "%{reported_domain}"
|
||||
@@ -603,14 +617,14 @@ filter {
|
||||
}
|
||||
|
||||
# -- email: failure reports carry full addresses + subject. --
|
||||
if [original_mail_from] {
|
||||
if [original_mail_from] != "" {
|
||||
mutate {
|
||||
replace => {
|
||||
"event.idm.read_only_udm.network.email.from" => "%{original_mail_from}"
|
||||
}
|
||||
}
|
||||
}
|
||||
if [original_rcpt_to] {
|
||||
if [original_rcpt_to] != "" {
|
||||
mutate {
|
||||
replace => {
|
||||
"event.idm.read_only_udm.network.email.to" => "%{original_rcpt_to}"
|
||||
@@ -618,14 +632,14 @@ filter {
|
||||
on_error => "fail_rcpt_error"
|
||||
}
|
||||
}
|
||||
if [subject] {
|
||||
if [subject] != "" {
|
||||
mutate {
|
||||
replace => {
|
||||
"event.idm.read_only_udm.network.email.subject" => "%{subject}"
|
||||
}
|
||||
}
|
||||
}
|
||||
if [message_id] {
|
||||
if [message_id] != "" {
|
||||
mutate {
|
||||
replace => {
|
||||
"event.idm.read_only_udm.network.email.mail_id" => "%{message_id}"
|
||||
@@ -649,7 +663,7 @@ filter {
|
||||
} else {
|
||||
mutate { replace => { "srf.action" => "UNKNOWN_ACTION" } }
|
||||
}
|
||||
if [auth_failure] {
|
||||
if [auth_failure] != "" {
|
||||
mutate {
|
||||
replace => {
|
||||
"srf.description" => "auth_failure=%{auth_failure} delivery_result=%{delivery_result}"
|
||||
@@ -662,49 +676,49 @@ filter {
|
||||
}
|
||||
|
||||
# -- additional.fields. --
|
||||
if [feedback_type] {
|
||||
if [feedback_type] != "" {
|
||||
mutate {
|
||||
replace => { "g_fb.key" => "feedback_type" "g_fb.value.string_value" => "%{feedback_type}" }
|
||||
merge => { "event.idm.read_only_udm.additional.fields" => "g_fb" }
|
||||
}
|
||||
}
|
||||
if [auth_failure] {
|
||||
if [auth_failure] != "" {
|
||||
mutate {
|
||||
replace => { "g_af.key" => "auth_failure" "g_af.value.string_value" => "%{auth_failure}" }
|
||||
merge => { "event.idm.read_only_udm.additional.fields" => "g_af" }
|
||||
}
|
||||
}
|
||||
if [delivery_result] {
|
||||
if [delivery_result] != "" {
|
||||
mutate {
|
||||
replace => { "g_dr.key" => "delivery_result" "g_dr.value.string_value" => "%{delivery_result}" }
|
||||
merge => { "event.idm.read_only_udm.additional.fields" => "g_dr" }
|
||||
}
|
||||
}
|
||||
if [authentication_results] {
|
||||
if [authentication_results] != "" {
|
||||
mutate {
|
||||
replace => { "g_ar.key" => "authentication_results" "g_ar.value.string_value" => "%{authentication_results}" }
|
||||
merge => { "event.idm.read_only_udm.additional.fields" => "g_ar" }
|
||||
}
|
||||
}
|
||||
if [authentication_mechanisms] {
|
||||
if [authentication_mechanisms] != "" {
|
||||
mutate {
|
||||
replace => { "g_am.key" => "authentication_mechanisms" "g_am.value.string_value" => "%{authentication_mechanisms}" }
|
||||
merge => { "event.idm.read_only_udm.additional.fields" => "g_am" }
|
||||
}
|
||||
}
|
||||
if [user_agent] {
|
||||
if [user_agent] != "" {
|
||||
mutate {
|
||||
replace => { "g_ua.key" => "user_agent" "g_ua.value.string_value" => "%{user_agent}" }
|
||||
merge => { "event.idm.read_only_udm.additional.fields" => "g_ua" }
|
||||
}
|
||||
}
|
||||
if [dkim_domain] {
|
||||
if [dkim_domain] != "" {
|
||||
mutate {
|
||||
replace => { "g_dd.key" => "dkim_domain" "g_dd.value.string_value" => "%{dkim_domain}" }
|
||||
merge => { "event.idm.read_only_udm.additional.fields" => "g_dd" }
|
||||
}
|
||||
}
|
||||
if [arrival_date] {
|
||||
if [arrival_date] != "" {
|
||||
mutate {
|
||||
replace => { "g_ad.key" => "arrival_date" "g_ad.value.string_value" => "%{arrival_date}" }
|
||||
merge => { "event.idm.read_only_udm.additional.fields" => "g_ad" }
|
||||
@@ -722,7 +736,7 @@ filter {
|
||||
|
||||
mutate { replace => { "event_type" => "GENERIC_EVENT" } }
|
||||
|
||||
if [report_id] {
|
||||
if [report_id] != "" {
|
||||
mutate {
|
||||
replace => {
|
||||
"event.idm.read_only_udm.metadata.product_log_id" => "%{report_id}"
|
||||
@@ -732,7 +746,7 @@ filter {
|
||||
|
||||
# -- event timestamp: start of the report window. SMTP TLS uses ISO 8601
|
||||
# with a trailing Z (e.g. 2025-12-07T19:00:00Z), unlike the other types. --
|
||||
if [begin_date] {
|
||||
if [begin_date] != "" {
|
||||
date {
|
||||
match => ["begin_date", "yyyy-MM-dd'T'HH:mm:ss'Z'"]
|
||||
timezone => "UTC"
|
||||
@@ -741,7 +755,7 @@ filter {
|
||||
}
|
||||
|
||||
# -- target: the reported policy domain (always present -> the noun). --
|
||||
if [policy_domain] {
|
||||
if [policy_domain] != "" {
|
||||
mutate {
|
||||
replace => {
|
||||
"event.idm.read_only_udm.target.hostname" => "%{policy_domain}"
|
||||
@@ -749,14 +763,14 @@ filter {
|
||||
}
|
||||
}
|
||||
# receiving MTA IP, when a per-session failure row carries it.
|
||||
if [receiving_ip] {
|
||||
if [receiving_ip] != "" {
|
||||
mutate {
|
||||
merge => { "event.idm.read_only_udm.target.ip" => "receiving_ip" }
|
||||
on_error => "tls_rcv_ip_error"
|
||||
}
|
||||
}
|
||||
# sending MTA IP, when present, is the principal.
|
||||
if [sending_mta_ip] {
|
||||
if [sending_mta_ip] != "" {
|
||||
mutate {
|
||||
merge => { "event.idm.read_only_udm.principal.ip" => "sending_mta_ip" }
|
||||
on_error => "tls_snd_ip_error"
|
||||
@@ -764,7 +778,7 @@ filter {
|
||||
}
|
||||
|
||||
# -- security_result only on failures (result_type present). --
|
||||
if [result_type] {
|
||||
if [result_type] != "" {
|
||||
mutate {
|
||||
replace => {
|
||||
"srt.summary" => "SMTP TLS report failure"
|
||||
@@ -780,85 +794,95 @@ filter {
|
||||
}
|
||||
|
||||
# -- additional.fields. --
|
||||
if [organization_name] {
|
||||
if [organization_name] != "" {
|
||||
mutate {
|
||||
replace => { "t_org.key" => "organization_name" "t_org.value.string_value" => "%{organization_name}" }
|
||||
merge => { "event.idm.read_only_udm.additional.fields" => "t_org" }
|
||||
}
|
||||
}
|
||||
if [begin_date] {
|
||||
if [begin_date] != "" {
|
||||
mutate {
|
||||
replace => { "t_begin.key" => "begin_date" "t_begin.value.string_value" => "%{begin_date}" }
|
||||
merge => { "event.idm.read_only_udm.additional.fields" => "t_begin" }
|
||||
}
|
||||
}
|
||||
if [end_date] {
|
||||
if [end_date] != "" {
|
||||
mutate {
|
||||
replace => { "t_end.key" => "end_date" "t_end.value.string_value" => "%{end_date}" }
|
||||
merge => { "event.idm.read_only_udm.additional.fields" => "t_end" }
|
||||
}
|
||||
}
|
||||
if [policy_domain] {
|
||||
if [policy_domain] != "" {
|
||||
mutate {
|
||||
replace => { "t_pd.key" => "policy_domain" "t_pd.value.string_value" => "%{policy_domain}" }
|
||||
merge => { "event.idm.read_only_udm.additional.fields" => "t_pd" }
|
||||
}
|
||||
}
|
||||
if [policy_type] {
|
||||
if [policy_type] != "" {
|
||||
mutate {
|
||||
replace => { "t_pt.key" => "policy_type" "t_pt.value.string_value" => "%{policy_type}" }
|
||||
merge => { "event.idm.read_only_udm.additional.fields" => "t_pt" }
|
||||
}
|
||||
}
|
||||
if [policy_strings] {
|
||||
if [policy_strings] != "" {
|
||||
mutate {
|
||||
replace => { "t_ps.key" => "policy_strings" "t_ps.value.string_value" => "%{policy_strings}" }
|
||||
merge => { "event.idm.read_only_udm.additional.fields" => "t_ps" }
|
||||
}
|
||||
}
|
||||
if [mx_host_patterns] {
|
||||
if [mx_host_patterns] != "" {
|
||||
mutate {
|
||||
replace => { "t_mx.key" => "mx_host_patterns" "t_mx.value.string_value" => "%{mx_host_patterns}" }
|
||||
merge => { "event.idm.read_only_udm.additional.fields" => "t_mx" }
|
||||
}
|
||||
}
|
||||
if [successful_session_count] {
|
||||
mutate {
|
||||
replace => { "t_ssc.key" => "successful_session_count" "t_ssc.value.string_value" => "%{successful_session_count}" }
|
||||
merge => { "event.idm.read_only_udm.additional.fields" => "t_ssc" }
|
||||
}
|
||||
mutate {
|
||||
replace => { "t_ssc.key" => "successful_session_count" "t_ssc.value.string_value" => "%{successful_session_count}" }
|
||||
}
|
||||
if [failed_session_count] {
|
||||
mutate {
|
||||
replace => { "t_fsc.key" => "failed_session_count" "t_fsc.value.string_value" => "%{failed_session_count}" }
|
||||
merge => { "event.idm.read_only_udm.additional.fields" => "t_fsc" }
|
||||
}
|
||||
mutate {
|
||||
convert => { "t_ssc.value.string_value" => "uinteger" }
|
||||
on_error => "ssc_nan"
|
||||
}
|
||||
if [result_type] {
|
||||
if ![ssc_nan] {
|
||||
mutate { rename => { "t_ssc.value.string_value" => "t_ssc.value.number_value" } }
|
||||
mutate { merge => { "event.idm.read_only_udm.additional.fields" => "t_ssc" } }
|
||||
}
|
||||
mutate {
|
||||
replace => { "t_fsc.key" => "failed_session_count" "t_fsc.value.string_value" => "%{failed_session_count}" }
|
||||
}
|
||||
mutate {
|
||||
convert => { "t_fsc.value.string_value" => "uinteger" }
|
||||
on_error => "fsc_nan"
|
||||
}
|
||||
if ![fsc_nan] {
|
||||
mutate { rename => { "t_fsc.value.string_value" => "t_fsc.value.number_value" } }
|
||||
mutate { merge => { "event.idm.read_only_udm.additional.fields" => "t_fsc" } }
|
||||
}
|
||||
if [result_type] != "" {
|
||||
mutate {
|
||||
replace => { "t_rt.key" => "result_type" "t_rt.value.string_value" => "%{result_type}" }
|
||||
merge => { "event.idm.read_only_udm.additional.fields" => "t_rt" }
|
||||
}
|
||||
}
|
||||
if [failure_reason_code] {
|
||||
if [failure_reason_code] != "" {
|
||||
mutate {
|
||||
replace => { "t_frc.key" => "failure_reason_code" "t_frc.value.string_value" => "%{failure_reason_code}" }
|
||||
merge => { "event.idm.read_only_udm.additional.fields" => "t_frc" }
|
||||
}
|
||||
}
|
||||
if [receiving_mx_hostname] {
|
||||
if [receiving_mx_hostname] != "" {
|
||||
mutate {
|
||||
replace => { "t_rmh.key" => "receiving_mx_hostname" "t_rmh.value.string_value" => "%{receiving_mx_hostname}" }
|
||||
merge => { "event.idm.read_only_udm.additional.fields" => "t_rmh" }
|
||||
}
|
||||
}
|
||||
if [receiving_mx_helo] {
|
||||
if [receiving_mx_helo] != "" {
|
||||
mutate {
|
||||
replace => { "t_rmhelo.key" => "receiving_mx_helo" "t_rmhelo.value.string_value" => "%{receiving_mx_helo}" }
|
||||
merge => { "event.idm.read_only_udm.additional.fields" => "t_rmhelo" }
|
||||
}
|
||||
}
|
||||
if [additional_info_uri] {
|
||||
if [additional_info_uri] != "" {
|
||||
mutate {
|
||||
replace => { "t_aiu.key" => "additional_info_uri" "t_aiu.value.string_value" => "%{additional_info_uri}" }
|
||||
merge => { "event.idm.read_only_udm.additional.fields" => "t_aiu" }
|
||||
@@ -876,7 +900,7 @@ filter {
|
||||
"event.idm.read_only_udm.metadata.product_name" => "parsedmarc"
|
||||
}
|
||||
}
|
||||
if [report_type] {
|
||||
if [report_type] != "" {
|
||||
mutate {
|
||||
replace => {
|
||||
"event.idm.read_only_udm.metadata.product_event_type" => "%{report_type}"
|
||||
|
||||
Reference in New Issue
Block a user