Skip to content

feat: add DMARCbis walk mode selection (RFC 9989 DNS Tree Walk)#430

Merged
thegushi merged 5 commits into
trusteddomainproject:developfrom
thegushi:feat/dmarcbis-walk-modes
Jun 21, 2026
Merged

feat: add DMARCbis walk mode selection (RFC 9989 DNS Tree Walk)#430
thegushi merged 5 commits into
trusteddomainproject:developfrom
thegushi:feat/dmarcbis-walk-modes

Conversation

@thegushi

Copy link
Copy Markdown
Collaborator

Summary

  • feat: add DMARCbis walk mode selection (RFC 9989 DNS Tree Walk) - lets the org-domain/policy lookup choose between classic RFC 7489 label-walk, PSL-only, RFC 9989 tree-walk, or auto (PSL first, falls back to RFC 7489 walk) via a configurable walk_mode
  • fix: discard multiple DMARC records at one name (RFC 7489 S 6.6.3, RFC 9989 S 4.10)
  • feat(survey): check RFC 7489 S 7.1 external reporting consent in pct-survey
  • fix: resolve pointer-sign warnings in DMARCbis walk-mode helpers
  • docs: record AUTO-mode fallback scope decision in DMARCbis walk notes

See DMARCBIS-WALK-NOTES.txt for open RFC 9989 interpretation questions and the rationale behind AUTO mode's fallback scope (item 6).

Test plan

  • make check in libopendmarc passes (11/11 tests)
  • Clean build, no compiler warnings

Dan Mahoney and others added 5 commits June 21, 2026 14:07
Refactor organizational domain discovery in libopendmarc into three
independently-callable walk strategies selectable at runtime via a new
DMARCbisWalkMode config option in opendmarc.conf.

- Add OPENDMARC_WALK_MODE_{AUTO,PSL,RFC7489,RFC9989} constants and walk_mode
  field to OPENDMARC_LIB_T (dmarc.h.in)
- Add np= and psd= fields to DMARC_POLICY_T (opendmarc_internal.h)
- Extract dmarc_query_at(), psd_from_record(), query_dmarc_psl(),
  query_dmarc_rfc7489_walk(), and query_dmarc_rfc9989_walk() from the
  monolithic opendmarc_policy_query_dmarc(); dispatch by walk_mode
- Parse np= and psd= tags in opendmarc_policy_parse_dmarc()
- Wire DMARCbisWalkMode config key in opendmarc-config.h and opendmarc.c
- Document DMARCbisWalkMode in opendmarc.conf.sample and opendmarc.conf.5.in
- Add DMARCBIS-WALK-NOTES.txt capturing RFC 9989 open questions

AUTO mode preserves pre-DMARCbis behaviour (PSL if configured, label-strip
walk otherwise). No #ifdef compile-time gates.
…C 9989 S 4.10)

dmarc_dns_get_record() previously returned the first "v=DMARC" TXT record
found without checking for duplicates, silently violating the rule in both
RFCs that multiple valid DMARC records at a single DNS name must all be
discarded.

- Scan all TXT records in the answer before returning; count those
  containing "v=DMARC".  Return the record only when exactly one is found;
  return NULL/NO_DATA when zero or more than one are found.
- Fix the fake DNS table path with the same count-before-returning logic.
- Fix a pre-existing cursor advancement bug: the non-DMARC TXT branch was
  adding the already-consumed dn_expand name length a second time.  Replace
  ad-hoc cur_ptr arithmetic with an rdata_end pointer set from RDLENGTH.
- Add a fake-DNS test case: two v=DMARC1 entries for the same name must
  yield DMARC_DNS_ERROR_NO_RECORD.
…survey

For every rua= and ruf= URI whose destination domain differs from the
policy domain, query {policy-domain}._report._dmarc.{dest-domain} and
flag any that lack a v=DMARC1 consent record.

- New output columns rua_bad / ruf_bad: comma-separated list of external
  URIs missing consent, or "-" if none problematic
- Async consent-check phase after the main DNS loop, at full concurrency
- Same-domain and subdomain URIs skipped (no check needed)
- Output buffered until consent phase completes; then written in one pass
- Summary log gains rua_ext_bad / ruf_ext_bad columns for trend tracking
Casts strdup() results back to u_char * for organizational_domain
assignments in query_dmarc_psl, query_dmarc_rfc7489_walk, and
query_dmarc_rfc9989_walk, matching the cast convention applied
elsewhere in trusteddomainproject#426.
Documents that AUTO mode's fallback to the RFC 7489 walk applies
whenever the PSL path fails, not only when no PSL boundary was found,
which is a deliberate broadening versus pre-refactor behavior.
@thegushi thegushi merged commit d3a63b0 into trusteddomainproject:develop Jun 21, 2026
3 of 4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant