2023-01-30 16:27:06 +03:00
|
|
|
package smtpserver
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
|
|
|
|
|
|
|
"github.com/mjl-/mox/dkim"
|
|
|
|
"github.com/mjl-/mox/dns"
|
2023-12-05 15:35:58 +03:00
|
|
|
"github.com/mjl-/mox/mlog"
|
2023-01-30 16:27:06 +03:00
|
|
|
"github.com/mjl-/mox/publicsuffix"
|
|
|
|
"github.com/mjl-/mox/spf"
|
|
|
|
"github.com/mjl-/mox/store"
|
|
|
|
)
|
|
|
|
|
|
|
|
// Alignment compares the msgFromDomain with the dkim and spf results, and returns
|
|
|
|
// a validation, one of: Strict, Relaxed, None.
|
2023-12-05 15:35:58 +03:00
|
|
|
func alignment(ctx context.Context, log mlog.Log, msgFromDomain dns.Domain, dkimResults []dkim.Result, spfStatus spf.Status, spfIdentity *dns.Domain) store.Validation {
|
2023-01-30 16:27:06 +03:00
|
|
|
var strict, relaxed bool
|
2023-12-05 15:35:58 +03:00
|
|
|
msgFromOrgDomain := publicsuffix.Lookup(ctx, log.Logger, msgFromDomain)
|
2023-01-30 16:27:06 +03:00
|
|
|
|
|
|
|
// todo: should take temperror and permerror into account.
|
|
|
|
for _, dr := range dkimResults {
|
|
|
|
if dr.Status != dkim.StatusPass || dr.Sig == nil {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
if dr.Sig.Domain == msgFromDomain {
|
|
|
|
strict = true
|
|
|
|
break
|
|
|
|
} else {
|
2023-12-05 15:35:58 +03:00
|
|
|
relaxed = relaxed || msgFromOrgDomain == publicsuffix.Lookup(ctx, log.Logger, dr.Sig.Domain)
|
2023-01-30 16:27:06 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
if !strict && spfStatus == spf.StatusPass {
|
|
|
|
strict = msgFromDomain == *spfIdentity
|
2023-12-05 15:35:58 +03:00
|
|
|
relaxed = relaxed || msgFromOrgDomain == publicsuffix.Lookup(ctx, log.Logger, *spfIdentity)
|
2023-01-30 16:27:06 +03:00
|
|
|
}
|
|
|
|
if strict {
|
|
|
|
return store.ValidationStrict
|
|
|
|
}
|
|
|
|
if relaxed {
|
|
|
|
return store.ValidationRelaxed
|
|
|
|
}
|
|
|
|
return store.ValidationNone
|
|
|
|
}
|