Documentation
¶
Overview ¶
Package dmarc implements the receiver side of DMARC (RFC 7489): looking up and parsing a domain's published policy, evaluating identifier alignment, and generating aggregate (rua) report XML.
The package is deliberately free of any storage or scheduling concerns. A caller records per-message evaluations however it likes, then hands a slice of neutral AggregateRecord values to BuildReport to produce the RFC 7489 aggregate-report document. Policy discovery (Lookup, ParsePolicy) and alignment (Aligned) are exposed as standalone primitives so a mail pipeline can consult them per message.
Index ¶
- func Aligned(authDomain, fromDomain string) bool
- func BuildReport(meta ReportMetadata, policy PolicyPublished, records []AggregateRecord) ([]byte, error)
- func Gzip(data []byte) ([]byte, error)
- func Lookup(domain string, resolver TXTResolver) (string, error)
- func ParsePolicy(record string) string
- type AggregateRecord
- type AuthResults
- type DKIMResult
- type DateRange
- type Feedback
- type Identifiers
- type PolicyEvaluated
- type PolicyPublished
- type ReportMetadata
- type ReportRecord
- type Row
- type SPFResult
- type TXTResolver
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func Aligned ¶
Aligned reports whether an authenticated domain aligns with the From domain under DMARC relaxed alignment (RFC 7489 §3.1): the organizational domains must match. This uses the simple, registry-free rule that the two are equal or one is a subdomain of the other (case-insensitive).
func BuildReport ¶
func BuildReport(meta ReportMetadata, policy PolicyPublished, records []AggregateRecord) ([]byte, error)
BuildReport assembles an RFC 7489 aggregate report XML document (with the XML declaration prepended).
func Gzip ¶
Gzip compresses report bytes for the report attachment (reports are delivered as application/gzip per RFC 7489 §7.2.1).
func Lookup ¶
func Lookup(domain string, resolver TXTResolver) (string, error)
Lookup fetches and returns the raw DMARC record published at _dmarc.<domain>. It returns ("", nil) when the domain publishes no DMARC record (this is not an error: DMARC simply does not apply), and ("", err) when the underlying TXT lookup fails.
func ParsePolicy ¶
ParsePolicy extracts the requested policy (the p= tag) from a DMARC record. It returns "none" when no p= tag is present.
Types ¶
type AggregateRecord ¶
type AggregateRecord struct {
Domain string // header-From domain (the reported-on domain)
SourceIP string
HeaderFrom string
Disposition string // none|quarantine|reject (policy applied)
DKIMResult string // pass|fail|none
DKIMAligned bool
SPFResult string // pass|fail|none
SPFAligned bool
}
AggregateRecord is one message's DMARC evaluation, the neutral input to AggregateRecords and BuildReport. It carries only what the aggregate report needs, so the package depends on no particular storage model.
type AuthResults ¶
type AuthResults struct {
DKIM []DKIMResult `xml:"dkim,omitempty"`
SPF []SPFResult `xml:"spf,omitempty"`
}
type DKIMResult ¶
type Feedback ¶
type Feedback struct {
XMLName xml.Name `xml:"feedback"`
Version string `xml:"version,omitempty"`
ReportMetadata ReportMetadata `xml:"report_metadata"`
PolicyPublished PolicyPublished `xml:"policy_published"`
Records []ReportRecord `xml:"record"`
}
Feedback is the root element of an RFC 7489 aggregate report.
type Identifiers ¶
type Identifiers struct {
HeaderFrom string `xml:"header_from"`
}
type PolicyEvaluated ¶
type PolicyPublished ¶
type PolicyPublished struct {
Domain string `xml:"domain"`
ADKIM string `xml:"adkim,omitempty"`
ASPF string `xml:"aspf,omitempty"`
P string `xml:"p"`
SP string `xml:"sp,omitempty"`
PCT int `xml:"pct,omitempty"`
}
PolicyPublished is the DMARC record the reported-on domain published.
type ReportMetadata ¶
type ReportMetadata struct {
OrgName string `xml:"org_name"`
Email string `xml:"email"`
ReportID string `xml:"report_id"`
DateRange DateRange `xml:"date_range"`
}
ReportMetadata identifies the reporting organization and period.
type ReportRecord ¶
type ReportRecord struct {
Row Row `xml:"row"`
Identifiers Identifiers `xml:"identifiers"`
AuthResults AuthResults `xml:"auth_results"`
}
ReportRecord is one aggregated row: a source IP + evaluation + counts.
func AggregateRecords ¶
func AggregateRecords(records []AggregateRecord) []ReportRecord
AggregateRecords groups raw per-message evaluations into report rows by (source IP, disposition, evaluated dkim/spf), summing counts.
type Row ¶
type Row struct {
SourceIP string `xml:"source_ip"`
Count int `xml:"count"`
PolicyEvaluated PolicyEvaluated `xml:"policy_evaluated"`
}
type TXTResolver ¶
TXTResolver resolves the TXT records for a name. Its signature matches net.LookupTXT, so that (or a fake in tests) can be passed directly. A nil resolver passed to Lookup falls back to net.LookupTXT.