author | Alberto Bertogli
<albertito@blitiri.com.ar> 2019-10-13 14:42:13 UTC |
committer | Alberto Bertogli
<albertito@blitiri.com.ar> 2019-10-14 12:18:21 UTC |
parent | 8ae8b8e9ee5028d6bafac3b037989c78dc334fd2 |
spf.go | +19 | -0 |
spf_test.go | +11 | -0 |
yml_test.go | +2 | -0 |
diff --git a/spf.go b/spf.go index a1f88a3..f4d45a1 100644 --- a/spf.go +++ b/spf.go @@ -44,6 +44,7 @@ var ( lookupMX = net.LookupMX lookupIP = net.LookupIP lookupAddr = net.LookupAddr + trace = func(f string, a ...interface{}) {} ) // The Result of an SPF check. Note the values have meaning, we use them in @@ -109,6 +110,7 @@ var ( // to determine if `ip` is permitted to send mail for it. // Reference: https://tools.ietf.org/html/rfc7208#section-4 func CheckHost(ip net.IP, domain string) (Result, error) { + trace("check host %q %q", ip, domain) r := &resolution{ip, 0, "", nil} return r.Check(domain) } @@ -123,6 +125,7 @@ func CheckHostWithSender(ip net.IP, helo, sender string) (Result, error) { domain = helo } + trace("check host with sender %q %q %q (%q)", ip, helo, sender, domain) r := &resolution{ip, 0, sender, nil} return r.Check(domain) } @@ -149,19 +152,23 @@ type resolution struct { func (r *resolution) Check(domain string) (Result, error) { r.count++ + trace("check %s %d", domain, r.count) txt, err := getDNSRecord(domain) if err != nil { if isTemporary(err) { + trace("dns temp error: %v", err) return TempError, err } // Could not resolve the name, it may be missing the record. // https://tools.ietf.org/html/rfc7208#section-2.6.1 + trace("dns perm error: %v", err) return None, err } if txt == "" { // No record => None. // https://tools.ietf.org/html/rfc7208#section-4.6 + trace("no txt record") return None, nil } @@ -187,6 +194,7 @@ func (r *resolution) Check(domain string) (Result, error) { // Limit the number of resolutions to 10 // https://tools.ietf.org/html/rfc7208#section-4.6.4 if r.count > 10 { + trace("lookup limit reached") return PermError, errLookupLimitReached } @@ -205,32 +213,41 @@ func (r *resolution) Check(domain string) (Result, error) { if field == "all" { // https://tools.ietf.org/html/rfc7208#section-5.1 + trace("%v matched all", result) return result, errMatchedAll } else if strings.HasPrefix(field, "include:") { if ok, res, err := r.includeField(result, field); ok { + trace("include ok, %v %v", res, err) return res, err } } else if strings.HasPrefix(field, "a") { if ok, res, err := r.aField(result, field, domain); ok { + trace("a ok, %v %v", res, err) return res, err } } else if strings.HasPrefix(field, "mx") { if ok, res, err := r.mxField(result, field, domain); ok { + trace("mx ok, %v %v", res, err) return res, err } } else if strings.HasPrefix(field, "ip4:") || strings.HasPrefix(field, "ip6:") { if ok, res, err := r.ipField(result, field); ok { + trace("ip ok, %v %v", res, err) return res, err } } else if strings.HasPrefix(field, "ptr") { if ok, res, err := r.ptrField(result, field, domain); ok { + trace("ptr ok, %v %v", res, err) return res, err } } else if strings.HasPrefix(field, "exists") { + trace("exists, neutral / not supported") return Neutral, errExistsNotSupported } else if strings.HasPrefix(field, "exp=") { + trace("exp=, neutral / not supported") return Neutral, errExpNotSupported } else if strings.HasPrefix(field, "redirect=") { + trace("redirect, %q", field) // https://tools.ietf.org/html/rfc7208#section-6.1 result, err := r.Check(field[len("redirect="):]) if result == None { @@ -239,12 +256,14 @@ func (r *resolution) Check(domain string) (Result, error) { return result, err } else { // http://www.openspf.org/SPF_Record_Syntax + trace("permerror, unknown field") return PermError, errUnknownField } } // Got to the end of the evaluation without a result => Neutral. // https://tools.ietf.org/html/rfc7208#section-4.7 + trace("fallback to neutral") return Neutral, nil } diff --git a/spf_test.go b/spf_test.go index 54383ec..c5c482a 100644 --- a/spf_test.go +++ b/spf_test.go @@ -13,6 +13,7 @@ var ip6660 = net.ParseIP("2001:db8::0") func TestBasic(t *testing.T) { dns = NewDNS() + trace = t.Logf cases := []struct { txt string @@ -78,6 +79,7 @@ func TestBasic(t *testing.T) { func TestIPv6(t *testing.T) { dns = NewDNS() + trace = t.Logf cases := []struct { txt string @@ -121,6 +123,7 @@ func TestIPv6(t *testing.T) { } func TestNotSupported(t *testing.T) { + trace = t.Logf cases := []struct { txt string err error @@ -145,6 +148,7 @@ func TestInclude(t *testing.T) { // If we got a match on 1.1.1.1, is because include:domain2 did not match. dns = NewDNS() dns.txt["domain"] = []string{"v=spf1 include:domain2 ip4:1.1.1.1"} + trace = t.Logf cases := []struct { txt string @@ -172,6 +176,7 @@ func TestInclude(t *testing.T) { func TestRecursionLimit(t *testing.T) { dns = NewDNS() dns.txt["domain"] = []string{"v=spf1 include:domain ~all"} + trace = t.Logf res, err := CheckHost(ip1111, "domain") if res != PermError || err != errLookupLimitReached { @@ -183,6 +188,7 @@ func TestRedirect(t *testing.T) { dns = NewDNS() dns.txt["domain"] = []string{"v=spf1 redirect=domain2"} dns.txt["domain2"] = []string{"v=spf1 ip4:1.1.1.1 -all"} + trace = t.Logf res, err := CheckHost(ip1111, "domain") if res != Pass { @@ -196,6 +202,7 @@ func TestInvalidRedirect(t *testing.T) { // https://tools.ietf.org/html/rfc7208#section-6.1 dns = NewDNS() dns.txt["domain"] = []string{"v=spf1 redirect=doesnotexist"} + trace = t.Logf res, err := CheckHost(ip1111, "doesnotexist") if res != None { @@ -213,6 +220,7 @@ func TestRedirectOrder(t *testing.T) { // redirect modifier appears before them. dns = NewDNS() dns.txt["faildom"] = []string{"v=spf1 -all"} + trace = t.Logf dns.txt["domain"] = []string{"v=spf1 redirect=faildom"} res, err := CheckHost(ip1111, "domain") @@ -232,6 +240,7 @@ func TestNoRecord(t *testing.T) { dns.txt["d1"] = []string{""} dns.txt["d2"] = []string{"loco", "v=spf2"} dns.errors["nospf"] = fmt.Errorf("no such domain") + trace = t.Logf for _, domain := range []string{"d1", "d2", "d3", "nospf"} { res, err := CheckHost(ip1111, domain) @@ -252,6 +261,7 @@ func TestDNSTemporaryErrors(t *testing.T) { dns.errors["tmperr"] = dnsError dns.errors["1.1.1.1"] = dnsError dns.mx["tmpmx"] = []*net.MX{{"tmperr", 10}} + trace = t.Logf cases := []struct { txt string @@ -285,6 +295,7 @@ func TestDNSPermanentErrors(t *testing.T) { dns.errors["tmperr"] = dnsError dns.errors["1.1.1.1"] = dnsError dns.mx["tmpmx"] = []*net.MX{{"tmperr", 10}} + trace = t.Logf cases := []struct { txt string diff --git a/yml_test.go b/yml_test.go index 48c20a8..e68cd6b 100644 --- a/yml_test.go +++ b/yml_test.go @@ -146,6 +146,8 @@ func testRFC(t *testing.T, fname string) { suites = append(suites, s) } + trace = t.Logf + for _, suite := range suites { t.Logf("suite: %v", suite.Description)