Improve SPF check logic
Anirudh Oppiliappan x@icyphox.sh
Mon, 20 Sep 2021 11:01:47 +0530
1 files changed,
38 insertions(+),
11 deletions(-)
jump to
M
mail/check.go
→
mail/check.go
@@ -2,6 +2,7 @@ package mail
import ( "fmt" + "log" "net" "net/mail" "strings"@@ -10,6 +11,20 @@ "blitiri.com.ar/go/spf"
"golang.org/x/net/idna" ) +func verifySPF(ips []net.IP, domain string, from string) (passes []spf.Result, err error) { + passes = []spf.Result{} + for _, ip := range ips { + result, _ := spf.CheckHostWithSender(ip, domain, from) + // if err != nil { + // return nil, fmt.Errorf("check spf: %w\n", err) + // } + if result == spf.Pass { + passes = append(passes, result) + } + } + return passes, nil +} + func VerifySPF(email string) (bool, error) { e, err := mail.ParseAddress(email) if err != nil {@@ -27,24 +42,36 @@ if err != nil {
return false, fmt.Errorf("mx lookup: %w\n", err) } - passes := []spf.Result{} + mxPasses := []spf.Result{} + // Check MX IPs against SPF record. for _, mx := range mxs { ips, err := net.LookupIP(mx.Host) if err != nil { return false, fmt.Errorf("ip lookup: %w\n", err) } + passes, err := verifySPF(ips, domain, e.Address) + if err != nil { + return false, fmt.Errorf("mx spf: %w\n", err) + } + mxPasses = append(mxPasses, passes...) + } - for _, ip := range ips { - result, _ := spf.CheckHostWithSender(ip, domain, e.Address) - if result == spf.Pass { - passes = append(passes, result) - } + if len(mxPasses) == 0 { + // Check domain IP against SPF record. + ips, err := net.LookupIP(domain) + if err != nil { + return false, fmt.Errorf("ip lookup: %w\n", err) + } + passes, err := verifySPF(ips, domain, e.Address) + if err != nil { + return false, fmt.Errorf("domain spf: %w\n", err) + } + // If both MX IP and domain IP fail SPF, we return false. + if len(passes) == 0 { + return false, nil } } - if len(passes) > 0 { - return true, nil - } else { - return false, nil - } + log.Printf("spf passed: %s\n", email) + return true, nil }