git » spf » commit 4f26c7a

tests: Share DNS test helpers between go and fuzz tests

author Alberto Bertogli
2021-05-09 10:14:27 UTC
committer Alberto Bertogli
2021-05-09 11:39:48 UTC
parent 3cf50bb3c147715bd48893eac048eb645b5001a5

tests: Share DNS test helpers between go and fuzz tests

We need to update the fuzz tests to use the new DNS helpers;
unfortunately, the fuzzing infrastructure ignores _test.go files and
can't be reasonably made to include them.

To avoid duplicating or complicating things more, this patch moves the
dns test helpers to its own package, renaming functions and fields
accordingly.

In the future, once fuzz support is part of the standard testing
infrastructure and we can include _test.go files, we can rename the file
again and exclude it completely from the default build.

fuzz.go +21 -39
dns_test.go => internal/dnstest/dns.go +26 -30
spf_test.go +84 -69
testdata/fuzz/corpus/da39a3ee5e6b4b0d3255bfef95601890afd80709 +0 -0
yml_test.go +9 -9

diff --git a/fuzz.go b/fuzz.go
index aa86346..1103b99 100644
--- a/fuzz.go
+++ b/fuzz.go
@@ -10,7 +10,11 @@
 
 package spf
 
-import "net"
+import (
+	"net"
+
+	"blitiri.com.ar/go/spf/internal/dnstest"
+)
 
 // Parsed IP addresses, for convenience.
 var (
@@ -20,51 +24,29 @@ var (
 	ip6660 = net.ParseIP("2001:db8::0")
 )
 
-// Results for TXT lookups. This one is global as the values will be set by
-// the fuzzer. The other lookup types are static and configured in init, see
-// below).
-var txtResults = map[string][]string{}
+// DNS resolver to use. Will be initialized once with the expected fixtures,
+// and then reused on each fuzz run.
+var dns = dnstest.NewResolver()
 
 func init() {
-	// Make the resolving functions return our test data.
-	// The test data is fixed, the fuzzer doesn't change it.
-	// TODO: Once go-fuzz can run functions from _test.go files, move this to
-	// spf_test.go to avoid duplicating all this boilerplate.
-	var (
-		mxResults   = map[string][]*net.MX{}
-		ipResults   = map[string][]net.IP{}
-		addrResults = map[string][]string{}
-	)
-
-	lookupTXT = func(domain string) (txts []string, err error) {
-		return txtResults[domain], nil
-	}
-	lookupMX = func(domain string) (mxs []*net.MX, err error) {
-		return mxResults[domain], nil
-	}
-	lookupIP = func(host string) (ips []net.IP, err error) {
-		return ipResults[host], nil
-	}
-	lookupAddr = func(host string) (addrs []string, err error) {
-		return addrResults[host], nil
-	}
-
-	ipResults["d1111"] = []net.IP{ip1111}
-	ipResults["d1110"] = []net.IP{ip1110}
-	mxResults["d1110"] = []*net.MX{{"d1110", 5}, {"nothing", 10}}
-	ipResults["d6666"] = []net.IP{ip6666}
-	ipResults["d6660"] = []net.IP{ip6660}
-	mxResults["d6660"] = []*net.MX{{"d6660", 5}, {"nothing", 10}}
-	addrResults["2001:db8::68"] = []string{"sonlas6.", "domain.", "d6666."}
-	addrResults["1.1.1.1"] = []string{"lalala.", "domain.", "d1111."}
+	dns.Ip["d1111"] = []net.IP{ip1111}
+	dns.Ip["d1110"] = []net.IP{ip1110}
+	dns.Mx["d1110"] = []*net.MX{{"d1110", 5}, {"nothing", 10}}
+	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.Addr["1.1.1.1"] = []string{"lalala.", "domain.", "d1111."}
 }
 
 func Fuzz(data []byte) int {
 	// The domain's TXT record comes from the fuzzer.
-	txtResults["domain"] = []string{string(data)}
+	dns.Txt["domain"] = []string{string(data)}
 
-	v4result, _ := CheckHost(ip1111, "domain") // IPv4
-	v6result, _ := CheckHost(ip6666, "domain") // IPv6
+	v4result, _ := CheckHostWithSender(
+		ip1111, "helo", "domain", WithResolver(dns))
+	v6result, _ := CheckHostWithSender(
+		ip6666, "helo", "domain", WithResolver(dns))
 
 	// Raise priority if any of the results was something other than
 	// PermError, as it means the data was better formed.
diff --git a/dns_test.go b/internal/dnstest/dns.go
similarity index 56%
rename from dns_test.go
rename to internal/dnstest/dns.go
index da6d320..8892a83 100644
--- a/dns_test.go
+++ b/internal/dnstest/dns.go
@@ -1,4 +1,10 @@
-package spf
+// DNS resolver for testing purposes.
+//
+// In the future, when go fuzz can make use of _test.go files, we can rename
+// this file dns_test.go and remove this extra package entirely.
+// Until then, unfortunately this is the most reasonable way to share these
+// helpers between go and fuzz tests.
+package dnstest
 
 import (
 	"context"
@@ -6,39 +12,36 @@ import (
 	"strings"
 )
 
-// DNS overrides for testing.
-
+// Testing DNS resolver.
+//
+// Not exported since this is not part of the public API and only used
+// internally on tests.
+//
 type TestResolver struct {
-	txt    map[string][]string
-	mx     map[string][]*net.MX
-	ip     map[string][]net.IP
-	addr   map[string][]string
-	errors map[string]error
+	Txt    map[string][]string
+	Mx     map[string][]*net.MX
+	Ip     map[string][]net.IP
+	Addr   map[string][]string
+	Errors map[string]error
 }
 
 func NewResolver() *TestResolver {
 	return &TestResolver{
-		txt:    map[string][]string{},
-		mx:     map[string][]*net.MX{},
-		ip:     map[string][]net.IP{},
-		addr:   map[string][]string{},
-		errors: map[string]error{},
+		Txt:    map[string][]string{},
+		Mx:     map[string][]*net.MX{},
+		Ip:     map[string][]net.IP{},
+		Addr:   map[string][]string{},
+		Errors: map[string]error{},
 	}
 }
 
-func NewDefaultResolver() *TestResolver {
-	dns := NewResolver()
-	defaultResolver = dns
-	return dns
-}
-
 func (r *TestResolver) LookupTXT(ctx context.Context, domain string) (txts []string, err error) {
 	if ctx.Err() != nil {
 		return nil, ctx.Err()
 	}
 	domain = strings.ToLower(domain)
 	domain = strings.TrimRight(domain, ".")
-	return r.txt[domain], r.errors[domain]
+	return r.Txt[domain], r.Errors[domain]
 }
 
 func (r *TestResolver) LookupMX(ctx context.Context, domain string) (mxs []*net.MX, err error) {
@@ -47,7 +50,7 @@ func (r *TestResolver) LookupMX(ctx context.Context, domain string) (mxs []*net.
 	}
 	domain = strings.ToLower(domain)
 	domain = strings.TrimRight(domain, ".")
-	return r.mx[domain], r.errors[domain]
+	return r.Mx[domain], r.Errors[domain]
 }
 
 func (r *TestResolver) LookupIPAddr(ctx context.Context, host string) (as []net.IPAddr, err error) {
@@ -56,7 +59,7 @@ func (r *TestResolver) LookupIPAddr(ctx context.Context, host string) (as []net.
 	}
 	host = strings.ToLower(host)
 	host = strings.TrimRight(host, ".")
-	return ipsToAddrs(r.ip[host]), r.errors[host]
+	return ipsToAddrs(r.Ip[host]), r.Errors[host]
 }
 
 func ipsToAddrs(ips []net.IP) []net.IPAddr {
@@ -73,12 +76,5 @@ func (r *TestResolver) LookupAddr(ctx context.Context, host string) (addrs []str
 	}
 	host = strings.ToLower(host)
 	host = strings.TrimRight(host, ".")
-	return r.addr[host], r.errors[host]
-}
-
-func init() {
-	// Override the default resolver to make sure the tests are not using the
-	// one from net. Individual tests will override this as well, but just in
-	// case.
-	NewDefaultResolver()
+	return r.Addr[host], r.Errors[host]
 }
diff --git a/spf_test.go b/spf_test.go
index 6d76d04..9d7a9ea 100644
--- a/spf_test.go
+++ b/spf_test.go
@@ -5,8 +5,23 @@ import (
 	"fmt"
 	"net"
 	"testing"
+
+	"blitiri.com.ar/go/spf/internal/dnstest"
 )
 
+func NewDefaultResolver() *dnstest.TestResolver {
+	dns := dnstest.NewResolver()
+	defaultResolver = dns
+	return dns
+}
+
+func init() {
+	// Override the default resolver to make sure the tests are not using the
+	// one from net. Individual tests will override this as well, but just in
+	// case.
+	NewDefaultResolver()
+}
+
 var ip1110 = net.ParseIP("1.1.1.0")
 var ip1111 = net.ParseIP("1.1.1.1")
 var ip6666 = net.ParseIP("2001:db8::68")
@@ -65,15 +80,15 @@ func TestBasic(t *testing.T) {
 		{"v=spf1 redirect=", PermError, errInvalidDomain},
 	}
 
-	dns.ip["d1111"] = []net.IP{ip1111}
-	dns.ip["d1110"] = []net.IP{ip1110}
-	dns.mx["d1110"] = []*net.MX{mx("d1110", 5), mx("nothing", 10)}
-	dns.addr["1.1.1.1"] = []string{"lalala.", "xx.domain.", "d1111."}
-	dns.ip["lalala"] = []net.IP{ip1111}
-	dns.ip["xx.domain"] = []net.IP{ip1111}
+	dns.Ip["d1111"] = []net.IP{ip1111}
+	dns.Ip["d1110"] = []net.IP{ip1110}
+	dns.Mx["d1110"] = []*net.MX{mx("d1110", 5), mx("nothing", 10)}
+	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}
+		dns.Txt["domain"] = []string{c.txt}
 		res, err := CheckHost(ip1111, "domain")
 		if (res == TempError || res == PermError) && (err == nil) {
 			t.Errorf("%q: expected error, got nil", c.txt)
@@ -116,15 +131,15 @@ func TestIPv6(t *testing.T) {
 		{"v=spf1 ptr:sonlas7 -all", Fail, errMatchedAll},
 	}
 
-	dns.ip["d6666"] = []net.IP{ip6666}
-	dns.ip["d6660"] = []net.IP{ip6660}
-	dns.mx["d6660"] = []*net.MX{mx("d6660", 5), mx("nothing", 10)}
-	dns.addr["2001:db8::68"] = []string{"sonlas6.", "domain.", "d6666."}
-	dns.ip["domain"] = []net.IP{ip1111}
-	dns.ip["sonlas6"] = []net.IP{ip6666}
+	dns.Ip["d6666"] = []net.IP{ip6666}
+	dns.Ip["d6660"] = []net.IP{ip6660}
+	dns.Mx["d6660"] = []*net.MX{mx("d6660", 5), mx("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}
+		dns.Txt["domain"] = []string{c.txt}
 		res, err := CheckHost(ip6666, "domain")
 		if (res == TempError || res == PermError) && (err == nil) {
 			t.Errorf("%q: expected error, got nil", c.txt)
@@ -142,7 +157,7 @@ func TestInclude(t *testing.T) {
 	// Test that the include is doing a recursive lookup.
 	// If we got a match on 1.1.1.1, is because include:domain2 did not match.
 	dns := NewDefaultResolver()
-	dns.txt["domain"] = []string{"v=spf1 include:domain2 ip4:1.1.1.1"}
+	dns.Txt["domain"] = []string{"v=spf1 include:domain2 ip4:1.1.1.1"}
 	trace = t.Logf
 
 	cases := []struct {
@@ -159,7 +174,7 @@ func TestInclude(t *testing.T) {
 	}
 
 	for _, c := range cases {
-		dns.txt["domain2"] = []string{c.txt}
+		dns.Txt["domain2"] = []string{c.txt}
 		res, err := CheckHost(ip1111, "domain")
 		if res != c.res || err != c.err {
 			t.Errorf("%q: expected [%v/%v], got [%v/%v]",
@@ -170,7 +185,7 @@ func TestInclude(t *testing.T) {
 
 func TestRecursionLimit(t *testing.T) {
 	dns := NewDefaultResolver()
-	dns.txt["domain"] = []string{"v=spf1 include:domain ~all"}
+	dns.Txt["domain"] = []string{"v=spf1 include:domain ~all"}
 	trace = t.Logf
 
 	res, err := CheckHost(ip1111, "domain")
@@ -181,8 +196,8 @@ func TestRecursionLimit(t *testing.T) {
 
 func TestRedirect(t *testing.T) {
 	dns := NewDefaultResolver()
-	dns.txt["domain"] = []string{"v=spf1 redirect=domain2"}
-	dns.txt["domain2"] = []string{"v=spf1 ip4:1.1.1.1 -all"}
+	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")
@@ -196,7 +211,7 @@ func TestInvalidRedirect(t *testing.T) {
 	// to the redirection, this lookup should return PermError.
 	// https://tools.ietf.org/html/rfc7208#section-6.1
 	dns := NewDefaultResolver()
-	dns.txt["domain"] = []string{"v=spf1 redirect=doesnotexist"}
+	dns.Txt["domain"] = []string{"v=spf1 redirect=doesnotexist"}
 	trace = t.Logf
 
 	res, err := CheckHost(ip1111, "doesnotexist")
@@ -214,16 +229,16 @@ func TestRedirectOrder(t *testing.T) {
 	// We should only check redirects after all mechanisms, even if the
 	// redirect modifier appears before them.
 	dns := NewDefaultResolver()
-	dns.txt["faildom"] = []string{"v=spf1 -all"}
+	dns.Txt["faildom"] = []string{"v=spf1 -all"}
 	trace = t.Logf
 
-	dns.txt["domain"] = []string{"v=spf1 redirect=faildom"}
+	dns.Txt["domain"] = []string{"v=spf1 redirect=faildom"}
 	res, err := CheckHost(ip1111, "domain")
 	if res != Fail || err != errMatchedAll {
 		t.Errorf("expected fail, got %v (%v)", res, err)
 	}
 
-	dns.txt["domain"] = []string{"v=spf1 redirect=faildom all"}
+	dns.Txt["domain"] = []string{"v=spf1 redirect=faildom all"}
 	res, err = CheckHost(ip1111, "domain")
 	if res != Pass || err != errMatchedAll {
 		t.Errorf("expected pass, got %v (%v)", res, err)
@@ -232,9 +247,9 @@ func TestRedirectOrder(t *testing.T) {
 
 func TestNoRecord(t *testing.T) {
 	dns := NewDefaultResolver()
-	dns.txt["d1"] = []string{""}
-	dns.txt["d2"] = []string{"loco", "v=spf2"}
-	dns.errors["nospf"] = fmt.Errorf("no such domain")
+	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"} {
@@ -253,9 +268,9 @@ func TestDNSTemporaryErrors(t *testing.T) {
 	}
 
 	// Domain "tmperr" will fail resolution with a temporary error.
-	dns.errors["tmperr"] = dnsError
-	dns.errors["1.1.1.1"] = dnsError
-	dns.mx["tmpmx"] = []*net.MX{mx("tmperr", 10)}
+	dns.Errors["tmperr"] = dnsError
+	dns.Errors["1.1.1.1"] = dnsError
+	dns.Mx["tmpmx"] = []*net.MX{mx("tmperr", 10)}
 	trace = t.Logf
 
 	cases := []struct {
@@ -270,7 +285,7 @@ func TestDNSTemporaryErrors(t *testing.T) {
 	}
 
 	for _, c := range cases {
-		dns.txt["domain"] = []string{c.txt}
+		dns.Txt["domain"] = []string{c.txt}
 		res, err := CheckHost(ip1111, "domain")
 		if res != c.res {
 			t.Errorf("%q: expected %v, got %v (%v)",
@@ -287,9 +302,9 @@ func TestDNSPermanentErrors(t *testing.T) {
 	}
 
 	// Domain "tmperr" will fail resolution with a temporary error.
-	dns.errors["tmperr"] = dnsError
-	dns.errors["1.1.1.1"] = dnsError
-	dns.mx["tmpmx"] = []*net.MX{mx("tmperr", 10)}
+	dns.Errors["tmperr"] = dnsError
+	dns.Errors["1.1.1.1"] = dnsError
+	dns.Mx["tmpmx"] = []*net.MX{mx("tmperr", 10)}
 	trace = t.Logf
 
 	cases := []struct {
@@ -304,7 +319,7 @@ func TestDNSPermanentErrors(t *testing.T) {
 	}
 
 	for _, c := range cases {
-		dns.txt["domain"] = []string{c.txt}
+		dns.Txt["domain"] = []string{c.txt}
 		res, err := CheckHost(ip1111, "domain")
 		if res != c.res {
 			t.Errorf("%q: expected %v, got %v (%v)",
@@ -337,13 +352,13 @@ func TestMacros(t *testing.T) {
 		{"v=spf1 +a:ooo-%{o7}-ooo", Pass, errMatchedA},
 	}
 
-	dns.ip["sss-user@domain-sss"] = []net.IP{ip6666}
-	dns.ip["ooo-domain-ooo"] = []net.IP{ip6666}
-	dns.ip["ppp-unknown-ppp"] = []net.IP{ip6666}
-	dns.ip["vvv-ip6-vvv"] = []net.IP{ip6666}
+	dns.Ip["sss-user@domain-sss"] = []net.IP{ip6666}
+	dns.Ip["ooo-domain-ooo"] = []net.IP{ip6666}
+	dns.Ip["ppp-unknown-ppp"] = []net.IP{ip6666}
+	dns.Ip["vvv-ip6-vvv"] = []net.IP{ip6666}
 
 	for _, c := range cases {
-		dns.txt["domain"] = []string{c.txt}
+		dns.Txt["domain"] = []string{c.txt}
 		res, err := CheckHostWithSender(ip6666, "helo", "user@domain")
 		if (res == TempError || res == PermError) && (err == nil) {
 			t.Errorf("%q: expected error, got nil", c.txt)
@@ -377,15 +392,15 @@ func TestMacrosV4(t *testing.T) {
 		{"v=spf1 +a:vvv-%{v}-vvv", Pass, errMatchedA},
 	}
 
-	dns.ip["sr-com.user@domain-sr"] = []net.IP{ip1111}
-	dns.ip["sra-com.user@domain-sra"] = []net.IP{ip1111}
-	dns.ip["o7-domain.com-o7"] = []net.IP{ip1111}
-	dns.ip["o1-com-o1"] = []net.IP{ip1111}
-	dns.ip["o1r-domain-o1r"] = []net.IP{ip1111}
-	dns.ip["vvv-in-addr-vvv"] = []net.IP{ip1111}
+	dns.Ip["sr-com.user@domain-sr"] = []net.IP{ip1111}
+	dns.Ip["sra-com.user@domain-sra"] = []net.IP{ip1111}
+	dns.Ip["o7-domain.com-o7"] = []net.IP{ip1111}
+	dns.Ip["o1-com-o1"] = []net.IP{ip1111}
+	dns.Ip["o1r-domain-o1r"] = []net.IP{ip1111}
+	dns.Ip["vvv-in-addr-vvv"] = []net.IP{ip1111}
 
 	for _, c := range cases {
-		dns.txt["domain.com"] = []string{c.txt}
+		dns.Txt["domain.com"] = []string{c.txt}
 		res, err := CheckHostWithSender(ip1111, "helo", "user@domain.com")
 		if (res == TempError || res == PermError) && (err == nil) {
 			t.Errorf("%q: expected error, got nil", c.txt)
@@ -461,8 +476,8 @@ func TestNullTrace(t *testing.T) {
 	dns := NewDefaultResolver()
 	trace = nullTrace
 
-	dns.txt["domain1"] = []string{"v=spf1 include:domain2"}
-	dns.txt["domain2"] = []string{"v=spf1 +all"}
+	dns.Txt["domain1"] = []string{"v=spf1 include:domain2"}
+	dns.Txt["domain2"] = []string{"v=spf1 +all"}
 
 	// Do a normal resolution, check it passes.
 	res, err := CheckHostWithSender(ip1111, "helo", "user@domain1")
@@ -475,10 +490,10 @@ func TestOverrideLookupLimit(t *testing.T) {
 	dns := NewDefaultResolver()
 	trace = t.Logf
 
-	dns.txt["domain1"] = []string{"v=spf1 include:domain2"}
-	dns.txt["domain2"] = []string{"v=spf1 include:domain3"}
-	dns.txt["domain3"] = []string{"v=spf1 include:domain4"}
-	dns.txt["domain4"] = []string{"v=spf1 +all"}
+	dns.Txt["domain1"] = []string{"v=spf1 include:domain2"}
+	dns.Txt["domain2"] = []string{"v=spf1 include:domain3"}
+	dns.Txt["domain3"] = []string{"v=spf1 include:domain4"}
+	dns.Txt["domain4"] = []string{"v=spf1 +all"}
 
 	// The default of 10 should be enough.
 	res, err := CheckHostWithSender(ip1111, "helo", "user@domain1")
@@ -506,8 +521,8 @@ func TestWithContext(t *testing.T) {
 	dns := NewDefaultResolver()
 	trace = t.Logf
 
-	dns.txt["domain1"] = []string{"v=spf1 include:domain2"}
-	dns.txt["domain2"] = []string{"v=spf1 +all"}
+	dns.Txt["domain1"] = []string{"v=spf1 include:domain2"}
+	dns.Txt["domain2"] = []string{"v=spf1 +all"}
 
 	// With a normal context.
 	ctx := context.Background()
@@ -529,12 +544,12 @@ func TestWithContext(t *testing.T) {
 
 func TestWithResolver(t *testing.T) {
 	// Use a custom resolver, making sure it's different from the default.
-	defaultResolver = NewResolver()
-	dns := NewResolver()
+	defaultResolver = dnstest.NewResolver()
+	dns := dnstest.NewResolver()
 	trace = t.Logf
 
-	dns.txt["domain1"] = []string{"v=spf1 include:domain2"}
-	dns.txt["domain2"] = []string{"v=spf1 +all"}
+	dns.Txt["domain1"] = []string{"v=spf1 include:domain2"}
+	dns.Txt["domain2"] = []string{"v=spf1 +all"}
 
 	res, err := CheckHostWithSender(ip1111, "helo", "user@domain1",
 		WithResolver(dns))
@@ -546,12 +561,12 @@ func TestWithResolver(t *testing.T) {
 // Test some corner cases when resolver.LookupIPAddr returns an invalid
 // address. This can happen if using a buggy custom resolver.
 func TestBadResolverResponse(t *testing.T) {
-	dns := NewResolver()
+	dns := dnstest.NewResolver()
 	trace = t.Logf
 
 	// When LookupIPAddr returns an invalid ip, for an "a" field.
-	dns.ip["domain1"] = []net.IP{nil}
-	dns.txt["domain1"] = []string{"v=spf1 a:domain1 -all"}
+	dns.Ip["domain1"] = []net.IP{nil}
+	dns.Txt["domain1"] = []string{"v=spf1 a:domain1 -all"}
 	res, err := CheckHostWithSender(ip1111, "helo", "user@domain1",
 		WithResolver(dns))
 	if res != Fail {
@@ -559,8 +574,8 @@ func TestBadResolverResponse(t *testing.T) {
 	}
 
 	// Same as above, except the field has a mask.
-	dns.ip["domain1"] = []net.IP{nil}
-	dns.txt["domain1"] = []string{"v=spf1 a:domain1//24 -all"}
+	dns.Ip["domain1"] = []net.IP{nil}
+	dns.Txt["domain1"] = []string{"v=spf1 a:domain1//24 -all"}
 	res, err = CheckHostWithSender(ip1111, "helo", "user@domain1",
 		WithResolver(dns))
 	if res != Fail {
@@ -568,9 +583,9 @@ func TestBadResolverResponse(t *testing.T) {
 	}
 
 	// When LookupIPAddr returns an invalid ip, for an "mx" field.
-	dns.ip["mx.domain1"] = []net.IP{nil}
-	dns.mx["domain1"] = []*net.MX{mx("mx.domain1", 5)}
-	dns.txt["domain1"] = []string{"v=spf1 mx:domain1 -all"}
+	dns.Ip["mx.domain1"] = []net.IP{nil}
+	dns.Mx["domain1"] = []*net.MX{mx("mx.domain1", 5)}
+	dns.Txt["domain1"] = []string{"v=spf1 mx:domain1 -all"}
 	res, err = CheckHostWithSender(ip1111, "helo", "user@domain1",
 		WithResolver(dns))
 	if res != Fail {
@@ -578,9 +593,9 @@ func TestBadResolverResponse(t *testing.T) {
 	}
 
 	// Same as above, except the field has a mask.
-	dns.ip["mx.domain1"] = []net.IP{nil}
-	dns.mx["domain1"] = []*net.MX{mx("mx.domain1", 5)}
-	dns.txt["domain1"] = []string{"v=spf1 mx:domain1//24 -all"}
+	dns.Ip["mx.domain1"] = []net.IP{nil}
+	dns.Mx["domain1"] = []*net.MX{mx("mx.domain1", 5)}
+	dns.Txt["domain1"] = []string{"v=spf1 mx:domain1//24 -all"}
 	res, err = CheckHostWithSender(ip1111, "helo", "user@domain1",
 		WithResolver(dns))
 	if res != Fail {
diff --git a/testdata/fuzz/corpus/da39a3ee5e6b4b0d3255bfef95601890afd80709 b/testdata/fuzz/corpus/da39a3ee5e6b4b0d3255bfef95601890afd80709
new file mode 100644
index 0000000..e69de29
diff --git a/yml_test.go b/yml_test.go
index c52baf2..e617006 100644
--- a/yml_test.go
+++ b/yml_test.go
@@ -166,7 +166,7 @@ func testRFC(t *testing.T, fname string) {
 						Err:       "test timeout error",
 						IsTimeout: true,
 					}
-					dns.errors[domain] = err
+					dns.Errors[domain] = err
 				}
 				if record.SERVFAIL {
 					err := &net.DNSError{
@@ -174,19 +174,19 @@ func testRFC(t *testing.T, fname string) {
 						IsTimeout:   false,
 						IsTemporary: false,
 					}
-					dns.errors[domain] = err
+					dns.Errors[domain] = err
 				}
 				for _, s := range record.A {
-					dns.ip[domain] = append(dns.ip[domain], net.ParseIP(s))
+					dns.Ip[domain] = append(dns.Ip[domain], net.ParseIP(s))
 				}
 				for _, s := range record.AAAA {
-					dns.ip[domain] = append(dns.ip[domain], net.ParseIP(s))
+					dns.Ip[domain] = append(dns.Ip[domain], net.ParseIP(s))
 				}
 				for _, s := range record.TXT {
-					dns.txt[domain] = append(dns.txt[domain], s)
+					dns.Txt[domain] = append(dns.Txt[domain], s)
 				}
 				if record.MX != nil {
-					dns.mx[domain] = append(dns.mx[domain],
+					dns.Mx[domain] = append(dns.Mx[domain],
 						mx(record.MX.Host, record.MX.Prio))
 				}
 				for _, s := range record.PTR {
@@ -201,7 +201,7 @@ func testRFC(t *testing.T, fname string) {
 						s += "."
 					}
 					ip := reverseDNS(t, domain).String()
-					dns.addr[ip] = append(dns.addr[ip], s)
+					dns.Addr[ip] = append(dns.Addr[ip], s)
 				}
 				// TODO: CNAME
 			}
@@ -214,12 +214,12 @@ func testRFC(t *testing.T, fname string) {
 			// only adding records from SPF if there is no TXT already.
 			// We need to do this in a separate step because order of
 			// appearance is not guaranteed.
-			if len(dns.txt[domain]) == 0 {
+			if len(dns.Txt[domain]) == 0 {
 				for _, record := range records {
 					if len(record.SPF) > 0 {
 						// The test suite expect a single-line SPF record to be
 						// concatenated without spaces.
-						dns.txt[domain] = append(dns.txt[domain],
+						dns.Txt[domain] = append(dns.Txt[domain],
 							strings.Join(record.SPF, ""))
 					}
 				}