Add db migration and DNS dmarc entries
This commit is contained in:
+66
-4
@@ -62,6 +62,60 @@ def _merge_details(existing: str, incoming: dict[str, Any]) -> str:
|
||||
return json.dumps(data, sort_keys=True)
|
||||
|
||||
|
||||
def _domain_equal(a: str | None, b: str | None) -> bool:
|
||||
return (a or "").lower().rstrip(".") == (b or "").lower().rstrip(".")
|
||||
|
||||
|
||||
def _is_subdomain(child: str | None, parent: str | None) -> bool:
|
||||
child_norm = (child or "").lower().rstrip(".")
|
||||
parent_norm = (parent or "").lower().rstrip(".")
|
||||
return bool(child_norm and parent_norm and child_norm.endswith(f".{parent_norm}"))
|
||||
|
||||
|
||||
def _published_policy(record: Record, report: Report) -> dict[str, Any]:
|
||||
effective_source = "p"
|
||||
effective = report.policy_p
|
||||
if _is_subdomain(record.header_from, report.domain) and report.policy_sp:
|
||||
effective_source = "sp"
|
||||
effective = report.policy_sp
|
||||
elif not _domain_equal(record.header_from, report.domain) and record.header_from:
|
||||
effective_source = "p"
|
||||
effective = report.policy_p
|
||||
return {
|
||||
"domain": report.domain,
|
||||
"header_from": record.header_from,
|
||||
"p": report.policy_p,
|
||||
"sp": report.policy_sp,
|
||||
"pct": report.policy_pct,
|
||||
"effective": effective,
|
||||
"effective_source": effective_source,
|
||||
"adkim": report.adkim,
|
||||
"aspf": report.aspf,
|
||||
"fo": report.fo,
|
||||
}
|
||||
|
||||
|
||||
def _receiver_action(record: Record) -> dict[str, Any]:
|
||||
return {
|
||||
"disposition": record.disposition,
|
||||
"override_type": record.reason_type,
|
||||
"override_comment": record.reason_comment,
|
||||
}
|
||||
|
||||
|
||||
def _policy_context_sentence(record: Record, report: Report) -> str:
|
||||
published = _published_policy(record, report)
|
||||
receiver = _receiver_action(record)
|
||||
effective = published.get("effective") or "unspecified"
|
||||
source = published.get("effective_source") or "p"
|
||||
disposition = receiver.get("disposition") or "none"
|
||||
pct = published.get("pct")
|
||||
pct_text = f"; pct={pct}" if pct is not None else ""
|
||||
override = receiver.get("override_type")
|
||||
override_text = f" with override {override}" if override else ""
|
||||
return f"Published DMARC policy was {source}={effective}{pct_text}; receiver disposition was {disposition}{override_text}."
|
||||
|
||||
|
||||
def create_or_update_alert(
|
||||
session: Session,
|
||||
*,
|
||||
@@ -112,6 +166,11 @@ def _record_details(record: Record, report: Report) -> dict[str, Any]:
|
||||
"dkim_aligned": record.dkim_aligned,
|
||||
"dmarc_pass": record.dmarc_pass,
|
||||
"disposition": record.disposition,
|
||||
"policy_p": report.policy_p,
|
||||
"policy_sp": report.policy_sp,
|
||||
"policy_pct": report.policy_pct,
|
||||
"published_policy": _published_policy(record, report),
|
||||
"receiver_action": _receiver_action(record),
|
||||
"known_sender": record.is_known_sender,
|
||||
"known_sender_id": record.known_sender_id,
|
||||
"reporting_orgs": [report.org_name] if report.org_name else [],
|
||||
@@ -204,6 +263,7 @@ def analyze_report(session: Session, settings: Settings, report: Report, llm: LL
|
||||
for record in report.records:
|
||||
details = _record_details(record, report)
|
||||
if not record.is_known_sender and not record.spf_aligned and not record.dkim_aligned and record.count >= thresholds.unknown_source_fail_count:
|
||||
policy_context = _policy_context_sentence(record, report)
|
||||
created.append(
|
||||
create_or_update_alert(
|
||||
session,
|
||||
@@ -213,11 +273,12 @@ def analyze_report(session: Session, settings: Settings, report: Report, llm: LL
|
||||
alert_type="unknown_source_failed_both",
|
||||
key=record.source_ip,
|
||||
title=f"Unknown source failed SPF and DKIM for {report.domain}",
|
||||
summary=f"{record.source_ip} sent {record.count} messages that failed SPF and DKIM alignment.",
|
||||
summary=f"{record.source_ip} sent {record.count} messages that failed SPF and DKIM alignment. {policy_context}",
|
||||
details=details,
|
||||
)
|
||||
)
|
||||
if record.is_known_sender and not record.dmarc_pass and record.count >= thresholds.min_messages_for_rate_alert:
|
||||
policy_context = _policy_context_sentence(record, report)
|
||||
created.append(
|
||||
create_or_update_alert(
|
||||
session,
|
||||
@@ -227,11 +288,12 @@ def analyze_report(session: Session, settings: Settings, report: Report, llm: LL
|
||||
alert_type="known_sender_dmarc_failure",
|
||||
key=record.known_sender_id or record.source_ip,
|
||||
title=f"Known sender failed DMARC for {report.domain}",
|
||||
summary=f"{record.known_sender_name or record.source_ip} failed DMARC for {record.count} messages.",
|
||||
summary=f"{record.known_sender_name or record.source_ip} failed DMARC for {record.count} messages. {policy_context}",
|
||||
details=details,
|
||||
)
|
||||
)
|
||||
if record.disposition in {"quarantine", "reject"} and record.count > 0:
|
||||
policy_context = _policy_context_sentence(record, report)
|
||||
created.append(
|
||||
create_or_update_alert(
|
||||
session,
|
||||
@@ -241,7 +303,7 @@ def analyze_report(session: Session, settings: Settings, report: Report, llm: LL
|
||||
alert_type="quarantine_or_reject_seen",
|
||||
key=f"{record.disposition}:{record.source_ip}",
|
||||
title=f"{record.disposition.title()} disposition seen for {report.domain}",
|
||||
summary=f"Receiver applied {record.disposition} to {record.count} messages.",
|
||||
summary=f"Receiver applied {record.disposition} to {record.count} messages. {policy_context}",
|
||||
details=details,
|
||||
)
|
||||
)
|
||||
@@ -260,7 +322,7 @@ def analyze_report(session: Session, settings: Settings, report: Report, llm: LL
|
||||
alert_type="new_unknown_source",
|
||||
key=record.source_ip,
|
||||
title=f"New unknown failing source for {report.domain}",
|
||||
summary=f"{record.source_ip} is newly observed and failed DMARC.",
|
||||
summary=f"{record.source_ip} is newly observed and failed DMARC. {_policy_context_sentence(record, report)}",
|
||||
details=details,
|
||||
)
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user