git » spf » commit 32d5fc8

In MX lookups, continue on DNS NXDOMAIN errors

author Matthias Schneider
2022-07-04 10:15:15 UTC
committer Alberto Bertogli
2022-08-01 20:45:19 UTC
parent 54e4d8f10a44e2d3dd03de042456bd96f4445b5e

In MX lookups, continue on DNS NXDOMAIN errors

The RFC is clear that NXDOMAIN errors should be treated as if the server
returned zero answers.

https://datatracker.ietf.org/doc/html/rfc7208#section-5

But today, when an MX record doesn't exist, we break with an error.
This was reported in https://github.com/albertito/spf/issues/5.

This patch fixes this problem by skipping MX records which return
NXDOMAIN.

Amended-by: Alberto Bertogli <albertito@blitiri.com.ar>
  Updated commit message, renamed variable for consistency, replaced Go
  tests with yaml tests for consistency with the (newly added) other
  similar test cases.

spf.go +10 -0
testdata/blitirispf-tests.yml +11 -0

diff --git a/spf.go b/spf.go
index be9d585..3adbd5e 100644
--- a/spf.go
+++ b/spf.go
@@ -483,6 +483,11 @@ func isTemporary(err error) bool {
 	return ok && derr.Temporary()
 }
 
+func isNotFound(err error) bool {
+	derr, ok := err.(*net.DNSError)
+	return ok && derr.IsNotFound
+}
+
 // Check if the given DNS error is a "void lookup" (0 answers, or nxdomain),
 // and if so increment the void lookup counter.
 func (r *resolution) checkVoidLookup(nanswers int, err error) {
@@ -779,7 +784,11 @@ func (r *resolution) mxField(res Result, field, domain string) (bool, Result, er
 	for _, mx := range mxs {
 		ips, err := r.resolver.LookupIPAddr(r.ctx, mx.Host)
 		if err != nil {
+			// If the address of the MX record was not found, we just skip it.
 			// https://tools.ietf.org/html/rfc7208#section-5
+			if isNotFound(err) {
+				continue
+			}
 			if isTemporary(err) {
 				return true, TempError, err
 			}
@@ -789,6 +798,7 @@ func (r *resolution) mxField(res Result, field, domain string) (bool, Result, er
 			mxips = append(mxips, ipaddr.IP)
 		}
 	}
+
 	for _, ip := range mxips {
 		if ipMatch(r.ip, ip, masks) {
 			r.trace("mx matched %v, %v, %v", r.ip, ip, masks)
diff --git a/testdata/blitirispf-tests.yml b/testdata/blitirispf-tests.yml
index 5da8fa4..d0cf364 100644
--- a/testdata/blitirispf-tests.yml
+++ b/testdata/blitirispf-tests.yml
@@ -260,6 +260,13 @@ zonedata:
 ---
 description: NXDOMAIN tests
 tests:
+  one-mx-not-found:
+    description: |
+      Check that if one of the MXs is not found, we continue evaluating the
+      rest.
+    mailfrom: "foo@d00"
+    host: 1.2.3.4
+    result: pass
   all-mx-not-found:
     description: |
       Check that if none of the MXs is not found, we continue evaluating the
@@ -289,6 +296,10 @@ tests:
     host: 1.2.3.4
     result: permerror
 zonedata:
+  d00:
+    - SPF: v=spf1 mx -all
+    - MX: [10, "doesnotexist"]
+    - MX: [20, "sender"]
   d01:
     - SPF: v=spf1 mx ip4:1.2.3.4 -all
     - MX: [10, "doesnotexist"]