dmarc: implement RFC 7489 org-domain fallback and RFC 9091 PSD DMARC
DMARC lookup now follows the full RFC 7489 §6.6.3 fallback chain: exact From domain → organizational domain (eTLD+1 via PSL) → public suffix domain (RFC 9091, only when psd=y is present). DNS errors abort immediately without triggering fallback; NXDOMAIN and missing v=DMARC1 records do trigger it. The found domain is exposed in the new DMARCRecord.domain field for reporting purposes. Also promote getOrganizationalDomain to a package-level function so both HeaderAnalyzer and DNSAnalyzer can share it, and fix pre-existing rbl_test.go compilation errors and stale score expectations. Closes: #98
This commit is contained in:
parent
0de67af847
commit
1516991057
7 changed files with 295 additions and 57 deletions
|
|
@ -388,7 +388,7 @@ func (h *HeaderAnalyzer) analyzeDomainAlignment(email *EmailMessage, authResults
|
|||
if domain != "" {
|
||||
alignment.FromDomain = &domain
|
||||
// Extract organizational domain
|
||||
orgDomain := h.getOrganizationalDomain(domain)
|
||||
orgDomain := getOrganizationalDomain(domain)
|
||||
alignment.FromOrgDomain = &orgDomain
|
||||
}
|
||||
}
|
||||
|
|
@ -400,7 +400,7 @@ func (h *HeaderAnalyzer) analyzeDomainAlignment(email *EmailMessage, authResults
|
|||
if domain != "" {
|
||||
alignment.ReturnPathDomain = &domain
|
||||
// Extract organizational domain
|
||||
orgDomain := h.getOrganizationalDomain(domain)
|
||||
orgDomain := getOrganizationalDomain(domain)
|
||||
alignment.ReturnPathOrgDomain = &orgDomain
|
||||
}
|
||||
}
|
||||
|
|
@ -411,7 +411,7 @@ func (h *HeaderAnalyzer) analyzeDomainAlignment(email *EmailMessage, authResults
|
|||
for _, dkim := range *authResults.Dkim {
|
||||
if dkim.Domain != nil && *dkim.Domain != "" {
|
||||
domain := *dkim.Domain
|
||||
orgDomain := h.getOrganizationalDomain(domain)
|
||||
orgDomain := getOrganizationalDomain(domain)
|
||||
dkimDomains = append(dkimDomains, model.DKIMDomainInfo{
|
||||
Domain: domain,
|
||||
OrgDomain: orgDomain,
|
||||
|
|
@ -542,7 +542,7 @@ func (h *HeaderAnalyzer) extractDomain(emailAddr string) string {
|
|||
// getOrganizationalDomain extracts the organizational domain from a fully qualified domain name
|
||||
// using the Public Suffix List (PSL) to correctly handle multi-level TLDs.
|
||||
// For example: mail.example.com -> example.com, mail.example.co.uk -> example.co.uk
|
||||
func (h *HeaderAnalyzer) getOrganizationalDomain(domain string) string {
|
||||
func getOrganizationalDomain(domain string) string {
|
||||
domain = strings.ToLower(strings.TrimSpace(domain))
|
||||
|
||||
// Use golang.org/x/net/publicsuffix to get the eTLD+1 (organizational domain)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue