author | Alberto Bertogli
<albertito@blitiri.com.ar> 2019-10-14 11:38:06 UTC |
committer | Alberto Bertogli
<albertito@blitiri.com.ar> 2019-10-14 12:35:33 UTC |
parent | a1b76d0b512ea7d50ffe27b5f85f8655e902ba7e |
spf.go | +20 | -4 |
spf_test.go | +6 | -1 |
diff --git a/spf.go b/spf.go index 760ed9e..8b8d940 100644 --- a/spf.go +++ b/spf.go @@ -369,6 +369,7 @@ func (r *resolution) ptrField(res Result, field, domain string) (bool, Result, e } if r.ipNames == nil { + r.ipNames = []string{} r.count++ ns, err := lookupAddr(r.ip.String()) if err != nil { @@ -379,15 +380,30 @@ func (r *resolution) ptrField(res Result, field, domain string) (bool, Result, e return false, "", err } for _, n := range ns { - // Append the lower-case variants so we do a case-insensitive - // lookup below. - r.ipNames = append(r.ipNames, strings.ToLower(n)) + // Validate the record by doing a forward resolution: it has to + // have some A/AAAA. + // https://tools.ietf.org/html/rfc7208#section-5.5 + if r.count > 10 { + return false, "", errLookupLimitReached + } + r.count++ + addrs, err := lookupIP(n) + if err != nil { + // RFC explicitly says to skip domains which error here. + continue + } + trace("ptr forward resolution %q -> %q", n, addrs) + if len(addrs) > 0 { + // Append the lower-case variants so we do a case-insensitive + // lookup below. + r.ipNames = append(r.ipNames, strings.ToLower(n)) + } } } + trace("ptr evaluating %q in %q", ptrDomain, r.ipNames) ptrDomain = strings.ToLower(ptrDomain) for _, n := range r.ipNames { - trace("ptr evaluating %q in %q", n, ptrDomain) if strings.HasSuffix(n, ptrDomain+".") { return true, res, errMatchedPTR } diff --git a/spf_test.go b/spf_test.go index bbe3f42..f4c8065 100644 --- a/spf_test.go +++ b/spf_test.go @@ -66,7 +66,9 @@ func TestBasic(t *testing.T) { dns.ip["d1111"] = []net.IP{ip1111} dns.ip["d1110"] = []net.IP{ip1110} dns.mx["d1110"] = []*net.MX{{"d1110", 5}, {"nothing", 10}} - dns.addr["1.1.1.1"] = []string{"lalala.", "domain.", "d1111."} + dns.addr["1.1.1.1"] = []string{"lalala.", "xx.domain.", "d1111."} + dns.ip["lalala"] = []net.IP{ip1111} + dns.ip["xx.domain"] = []net.IP{ip1111} for _, c := range cases { dns.txt["domain"] = []string{c.txt} @@ -109,12 +111,15 @@ func TestIPv6(t *testing.T) { {"v=spf1 ptr -all", Pass, errMatchedPTR}, {"v=spf1 ptr:d6666 -all", Pass, errMatchedPTR}, {"v=spf1 ptr:sonlas6 -all", Pass, errMatchedPTR}, + {"v=spf1 ptr:sonlas7 -all", Fail, errMatchedAll}, } dns.ip["d6666"] = []net.IP{ip6666} dns.ip["d6660"] = []net.IP{ip6660} dns.mx["d6660"] = []*net.MX{{"d6660", 5}, {"nothing", 10}} dns.addr["2001:db8::68"] = []string{"sonlas6.", "domain.", "d6666."} + dns.ip["domain"] = []net.IP{ip1111} + dns.ip["sonlas6"] = []net.IP{ip6666} for _, c := range cases { dns.txt["domain"] = []string{c.txt}