mox/dmarcrpt/feedback.go
Mechiel Lukkien e7699708ef
implement outgoing dmarc aggregate reporting
in smtpserver, we store dmarc evaluations (under the right conditions).
in dmarcdb, we periodically (hourly) send dmarc reports if there are
evaluations. for failed deliveries, we deliver the dsn quietly to a submailbox
of the postmaster mailbox.

this is on by default, but can be disabled in mox.conf.
2023-11-02 09:12:30 +01:00

165 lines
4.8 KiB
Go

package dmarcrpt
import (
"encoding/xml"
)
// Initially generated by xsdgen, then modified.
// Feedback is the top-level XML field returned.
type Feedback struct {
XMLName xml.Name `xml:"feedback" json:"-"` // todo: removing the json tag triggers bug in sherpadoc, should fix.
Version string `xml:"version"`
ReportMetadata ReportMetadata `xml:"report_metadata"`
PolicyPublished PolicyPublished `xml:"policy_published"`
Records []ReportRecord `xml:"record"`
}
type ReportMetadata struct {
OrgName string `xml:"org_name"`
Email string `xml:"email"`
ExtraContactInfo string `xml:"extra_contact_info,omitempty"`
ReportID string `xml:"report_id"`
DateRange DateRange `xml:"date_range"`
Errors []string `xml:"error,omitempty"`
}
type DateRange struct {
Begin int64 `xml:"begin"`
End int64 `xml:"end"`
}
// PolicyPublished is the policy as found in DNS for the domain.
type PolicyPublished struct {
// Domain is where DMARC record was found, not necessarily message From. Reports we
// generate use unicode names, incoming reports may have either ASCII-only or
// Unicode domains.
Domain string `xml:"domain"`
ADKIM Alignment `xml:"adkim,omitempty"`
ASPF Alignment `xml:"aspf,omitempty"`
Policy Disposition `xml:"p"`
SubdomainPolicy Disposition `xml:"sp"`
Percentage int `xml:"pct"`
ReportingOptions string `xml:"fo"`
}
// Alignment is the identifier alignment.
type Alignment string
const (
AlignmentRelaxed Alignment = "r" // Subdomains match the DMARC from-domain.
AlignmentStrict Alignment = "s" // Only exact from-domain match.
)
// Disposition is the requested action for a DMARC fail as specified in the
// DMARC policy in DNS.
type Disposition string
const (
DispositionNone Disposition = "none"
DispositionQuarantine Disposition = "quarantine"
DispositionReject Disposition = "reject"
)
type ReportRecord struct {
Row Row `xml:"row"`
Identifiers Identifiers `xml:"identifiers"`
AuthResults AuthResults `xml:"auth_results"`
}
type Row struct {
// SourceIP must match the pattern ((1?[0-9]?[0-9]|2[0-4][0-9]|25[0-5]).){3}
// (1?[0-9]?[0-9]|2[0-4][0-9]|25[0-5])|
// ([A-Fa-f0-9]{1,4}:){7}[A-Fa-f0-9]{1,4}
SourceIP string `xml:"source_ip"`
Count int `xml:"count"`
PolicyEvaluated PolicyEvaluated `xml:"policy_evaluated"`
}
type PolicyEvaluated struct {
Disposition Disposition `xml:"disposition"`
DKIM DMARCResult `xml:"dkim"`
SPF DMARCResult `xml:"spf"`
Reasons []PolicyOverrideReason `xml:"reason,omitempty"`
}
// DMARCResult is the final validation and alignment verdict for SPF and DKIM.
type DMARCResult string
const (
DMARCPass DMARCResult = "pass"
DMARCFail DMARCResult = "fail"
)
type PolicyOverrideReason struct {
Type PolicyOverride `xml:"type"`
Comment string `xml:"comment,omitempty"`
}
// PolicyOverride is a reason the requested DMARC policy from the DNS record
// was not applied.
type PolicyOverride string
const (
PolicyOverrideForwarded PolicyOverride = "forwarded"
PolicyOverrideSampledOut PolicyOverride = "sampled_out"
PolicyOverrideTrustedForwarder PolicyOverride = "trusted_forwarder"
PolicyOverrideMailingList PolicyOverride = "mailing_list"
PolicyOverrideLocalPolicy PolicyOverride = "local_policy"
PolicyOverrideOther PolicyOverride = "other"
)
type Identifiers struct {
EnvelopeTo string `xml:"envelope_to,omitempty"`
EnvelopeFrom string `xml:"envelope_from"`
HeaderFrom string `xml:"header_from"`
}
type AuthResults struct {
DKIM []DKIMAuthResult `xml:"dkim,omitempty"`
SPF []SPFAuthResult `xml:"spf"`
}
type DKIMAuthResult struct {
Domain string `xml:"domain"`
Selector string `xml:"selector,omitempty"`
Result DKIMResult `xml:"result"`
HumanResult string `xml:"human_result,omitempty"`
}
type DKIMResult string
const (
DKIMNone DKIMResult = "none"
DKIMPass DKIMResult = "pass"
DKIMFail DKIMResult = "fail"
DKIMPolicy DKIMResult = "policy"
DKIMNeutral DKIMResult = "neutral"
DKIMTemperror DKIMResult = "temperror"
DKIMPermerror DKIMResult = "permerror"
)
type SPFAuthResult struct {
Domain string `xml:"domain"`
Scope SPFDomainScope `xml:"scope"`
Result SPFResult `xml:"result"`
}
type SPFDomainScope string
const (
SPFDomainScopeHelo SPFDomainScope = "helo" // SMTP EHLO
SPFDomainScopeMailFrom SPFDomainScope = "mfrom" // SMTP "MAIL FROM".
)
type SPFResult string
const (
SPFNone SPFResult = "none"
SPFNeutral SPFResult = "neutral"
SPFPass SPFResult = "pass"
SPFFail SPFResult = "fail"
SPFSoftfail SPFResult = "softfail"
SPFTemperror SPFResult = "temperror"
SPFPermerror SPFResult = "permerror"
)