From a5c99d16cf791c28e94c75812d21bb5e376cc0a0 Mon Sep 17 00:00:00 2001 From: cedar10bits Date: Fri, 21 Jul 2017 03:04:31 +0900 Subject: [PATCH 1/7] Add isNoHost function and add "no host" check for Go 1.7.6 on Windows --- resolver_std.go | 38 +++++++++++++++++--------------------- 1 file changed, 17 insertions(+), 21 deletions(-) diff --git a/resolver_std.go b/resolver_std.go index 000a33c..7ebb034 100644 --- a/resolver_std.go +++ b/resolver_std.go @@ -8,10 +8,7 @@ import ( // DNSResolver implements Resolver using local DNS type DNSResolver struct{} -func errDNS(e error) error { - if e == nil { - return nil - } +func isNoHost(e error) bool { if dnsErr, ok := e.(*net.DNSError); ok { // That is the most reliable way I found to detect Permerror // https://github.com/golang/go/blob/master/src/net/dnsclient.go#L43 @@ -25,8 +22,21 @@ func errDNS(e error) error { // the mechanism continues as if the server returned no error (RCODE // 0) and zero answer records. if dnsErr.Err == "no such host" { - return nil + return true } + if dnsErr.Err == "dnsquery: DNS name does not exist" { + return true + } + } + return false +} + +func errDNS(e error) error { + if e == nil { + return nil + } + if isNoHost(e) { + return nil } return ErrDNSTemperror } @@ -36,23 +46,9 @@ func errDNS(e error) error { func (r *DNSResolver) LookupTXTStrict(name string) ([]string, error) { txts, err := net.LookupTXT(name) - if dnsErr, ok := err.(*net.DNSError); ok { - // That is the most reliable way I found to detect Permerror - // https://github.com/golang/go/blob/master/src/net/dnsclient.go#L43 - // Upon RCODE 3 return code we should return None result and pretend no - // From RFC7208: - // Several mechanisms rely on information fetched from the DNS. For - // these DNS queries, except where noted, if the DNS server returns an - // error (RCODE other than 0 or 3) or the query times out, the - // mechanism stops and the topmost check_host() returns "temperror". - // If the server returns "Name Error" (RCODE 3), then evaluation of - // the mechanism continues as if the server returned no error (RCODE - // 0) and zero answer records. - if dnsErr.Err == "no such host" { - return nil, ErrDNSPermerror - } + if isNoHost(err) { + return nil, ErrDNSPermerror } - err = errDNS(err) if err != nil { return nil, err From 1cb32a4d3407995c98f7b76d3e3995ca15c30b12 Mon Sep 17 00:00:00 2001 From: cedar10bits Date: Mon, 24 Jul 2017 13:07:24 +0900 Subject: [PATCH 2/7] add dot --- resolver_std.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resolver_std.go b/resolver_std.go index 7ebb034..1770b27 100644 --- a/resolver_std.go +++ b/resolver_std.go @@ -24,7 +24,7 @@ func isNoHost(e error) bool { if dnsErr.Err == "no such host" { return true } - if dnsErr.Err == "dnsquery: DNS name does not exist" { + if dnsErr.Err == "dnsquery: DNS name does not exist." { return true } } From 3f6fe14ec24ffa66a68756257b35ea4bd49d1e5d Mon Sep 17 00:00:00 2001 From: cedar10bits Date: Fri, 11 Aug 2017 01:21:08 +0900 Subject: [PATCH 3/7] Add other "no host" cases for Win --- resolver_std.go | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/resolver_std.go b/resolver_std.go index 1770b27..0160b44 100644 --- a/resolver_std.go +++ b/resolver_std.go @@ -27,6 +27,12 @@ func isNoHost(e error) bool { if dnsErr.Err == "dnsquery: DNS name does not exist." { return true } + if dnsErr.Err == "dnsquery: DNS record does not exist." { + return true + } + if dnsErr.Err == "dnsquery: No records found for given DNS query." { + return true + } } return false } From 8fe3a01a26fcde60fec72bc6b642631268382f8a Mon Sep 17 00:00:00 2001 From: Marek Denis Date: Fri, 11 Aug 2017 12:01:29 +0100 Subject: [PATCH 4/7] Remove testing for Go 1.6 It fails due to miekg's dns package requirements. --- .travis.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 320fe40..bbed3a3 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,6 +1,5 @@ language: go go: - - 1.6 - 1.7 - 1.8 - master From daddfcbc8d02913c6488bc5f6c4197d9657fcd5f Mon Sep 17 00:00:00 2001 From: Dmitry Motylev Date: Thu, 10 Aug 2017 12:35:26 +0100 Subject: [PATCH 5/7] goroutines leak fixed --- resolver_miekg.go | 7 ++++--- resolver_std.go | 2 +- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/resolver_miekg.go b/resolver_miekg.go index 1ca0f7f..f4d66f3 100644 --- a/resolver_miekg.go +++ b/resolver_miekg.go @@ -134,9 +134,10 @@ func matchIP(rrs []dns.RR, matcher IPMatcherFunc) (bool, error) { // If any address matches, the mechanism matches func (r *MiekgDNSResolver) MatchIP(name string, matcher IPMatcherFunc) (bool, error) { var wg sync.WaitGroup - hits := make(chan hit) + qTypes := []uint16{dns.TypeA, dns.TypeAAAA} + hits := make(chan hit, len(qTypes)) - for _, qType := range []uint16{dns.TypeA, dns.TypeAAAA} { + for _, qType := range qTypes { wg.Add(1) go func(qType uint16) { defer wg.Done() @@ -184,7 +185,7 @@ func (r *MiekgDNSResolver) MatchMX(name string, matcher IPMatcherFunc) (bool, er } var wg sync.WaitGroup - hits := make(chan hit) + hits := make(chan hit, len(res.Answer)) for _, rr := range res.Answer { mx, ok := rr.(*dns.MX) diff --git a/resolver_std.go b/resolver_std.go index 0160b44..55b3f83 100644 --- a/resolver_std.go +++ b/resolver_std.go @@ -119,7 +119,7 @@ func (r *DNSResolver) MatchMX(name string, matcher IPMatcherFunc) (bool, error) } var wg sync.WaitGroup - hits := make(chan hit) + hits := make(chan hit, len(mxs)) for _, mx := range mxs { wg.Add(1) From e5bf1461b77e49f64d50623a3a9ac1ddaef243bf Mon Sep 17 00:00:00 2001 From: Dmitry Motylev Date: Mon, 14 Aug 2017 19:13:27 +0100 Subject: [PATCH 6/7] fixed syntax error on multiline TXT record --- resolver_miekg.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/resolver_miekg.go b/resolver_miekg.go index f4d66f3..62a27fa 100644 --- a/resolver_miekg.go +++ b/resolver_miekg.go @@ -5,6 +5,7 @@ import ( "sync" "github.com/miekg/dns" + "strings" ) // NewMiekgDNSResolver returns new instance of Resolver @@ -66,7 +67,7 @@ func (r *MiekgDNSResolver) LookupTXT(name string) ([]string, error) { txts := make([]string, 0, len(res.Answer)) for _, a := range res.Answer { if r, ok := a.(*dns.TXT); ok { - txts = append(txts, r.Txt...) + txts = append(txts, strings.Join(r.Txt,"")) } } return txts, nil @@ -91,7 +92,7 @@ func (r *MiekgDNSResolver) LookupTXTStrict(name string) ([]string, error) { txts := make([]string, 0, len(res.Answer)) for _, a := range res.Answer { if r, ok := a.(*dns.TXT); ok { - txts = append(txts, r.Txt...) + txts = append(txts, strings.Join(r.Txt,"")) } } return txts, nil From b0fafbd022933b6195251109396cf79c813435f6 Mon Sep 17 00:00:00 2001 From: Dmitry Motylev Date: Tue, 15 Aug 2017 11:52:35 +0100 Subject: [PATCH 7/7] tests for multiline txt lookup by miekgdns added --- resolver_miekg_test.go | 44 +++++++++++++++++++++++++++++++++++++++++- 1 file changed, 43 insertions(+), 1 deletion(-) diff --git a/resolver_miekg_test.go b/resolver_miekg_test.go index ea86d70..aba259e 100644 --- a/resolver_miekg_test.go +++ b/resolver_miekg_test.go @@ -1,6 +1,10 @@ package spf -import "testing" +import ( + "testing" + + "github.com/miekg/dns" +) func TestMiekgDNSResolver(t *testing.T) { _, e := NewMiekgDNSResolver("8.8.8.8") // invalid TCP address, no port specified @@ -8,3 +12,41 @@ func TestMiekgDNSResolver(t *testing.T) { t.Errorf(`want "address 8.8.8.8: missing port in address"`) } } + +func TestMiekgDNSResolver_LookupTXTStrict_Multiline(t *testing.T) { + dns.HandleFunc("multiline.test.", zone(map[uint16][]string{ + dns.TypeTXT: { + `multiline.test. 0 IN TXT "v=spf1 ip4:10.0.0.1 ip4:10.0.0" ".2 -all"`, + }, + })) + defer dns.HandleRemove("multiline.test.") + + r, e := testResolver.LookupTXTStrict("multiline.test.") + + if e != nil { + t.Fatal(e) + } + + if len(r) != 1 { + t.Errorf("want 1 got %d", len(r)) + } +} + +func TestMiekgDNSResolver_LookupTXT_Multiline(t *testing.T) { + dns.HandleFunc("multiline.test.", zone(map[uint16][]string{ + dns.TypeTXT: { + `multiline.test. 0 IN TXT "v=spf1 ip4:10.0.0.1 ip4:10.0.0" ".2 -all"`, + }, + })) + defer dns.HandleRemove("multiline.test.") + + r, e := testResolver.LookupTXT("multiline.test.") + + if e != nil { + t.Fatal(e) + } + + if len(r) != 1 { + t.Errorf("want 1 got %d", len(r)) + } +}