Skip to content

DMARCbis: remove pct sampling, add t tag support (RFC 9989) #366

@thegushi

Description

@thegushi

RFC 9989 removes the pct tag entirely (now marked historic in the IANA registry) and replaces it with a binary t (testing) tag:

  • t=y -- testing/monitoring mode; analogous to the old pct=0. Receivers should apply monitoring but not enforce policy.
  • t=n (or absent) -- full enforcement; analogous to the old pct=100.

The rationale (RFC 9989 Appendix A.6) is that intermediate pct values were implemented inconsistently across receivers and rarely applied correctly in practice. RFC 9989 explicitly notes that only pct=0 and pct=100 were ever reliably implemented.

Backward compatibility with pct=

OpenDMARC will still parse pct= when present in a DMARC record, but:

  • pct=0 -> treated as t=y (monitoring only, no enforcement)
  • pct=100 -> treated as t=n (full enforcement; no behavior change)
  • pct=1-99 -> discarded; treat as full enforcement (t=n)
  • t= takes precedence over pct= when both are present

This means domain owners running pct=1-99 with p=reject or p=quarantine will see full enforcement from OpenDMARC once this is implemented. Per RFC 9989, those values were already being applied inconsistently across the ecosystem.

Required changes

Filter (opendmarc.c):

  • Remove the random() % 100 < pct sampling blocks in the DMARC_POLICY_REJECT and DMARC_POLICY_QUARANTINE cases
  • Parse and honor the t tag: when t=y, skip enforcement regardless of p= value (treat as monitoring-only)
  • Map pct=0 -> t=y during the transition

Library (libopendmarc):

  • opendmarc_policy_query_dmarc() needs to parse the t= tag from the DNS record and expose it via a new accessor (or extend an existing one)
  • Continue parsing pct= but normalize it to the two meaningful values (0 and 100) before exposing it; discard 1-99

Aggregate reports (opendmarc-reports.in):

  • RFC 9990 <policy_published> block: replace <pct> element with whatever RFC 9990 specifies for the t tag

Related

  • RFC 9989 Appendix A.6 (removal rationale)
  • Supersedes the old pct handling throughout the codebase

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions