resolver: never resend a refused query asking for recursion (closes #206)
check / check (push) Failing after 2m18s

queryDNS resent a query that a server refused, this time asking for
recursion, so on a network that intercepts DNS the answers could come
from a recursive resolver without anyone knowing. A refusal is now only
a refusal, and the server is passed over for the next.

When every server of a zone refuses, the error says so. When every root
server refuses, the error is ErrIntercepted: root servers refuse no
query, so something on the network is answering in their place.
FindAuthoritativeNameservers stops at that error instead of trying each
parent name, so the watcher's log line says it.

Model: opus-5-5
This commit is contained in:
2026-10-02 00:23:57 +00:00
parent c9510a986c
commit 2c03858092
5 changed files with 106 additions and 21 deletions
+54
View File
@@ -11,6 +11,7 @@ import (
"testing"
"time"
"github.com/miekg/dns"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
@@ -273,6 +274,59 @@ func TestQueryNameserver_Refused(t *testing.T) {
assert.Equal(t, "server returned REFUSED", resp.Error)
}
// TestQueryServers_EveryServerRefused asks all of google.com's
// nameservers about cloudflare.com, a zone they do not serve, which
// they all refuse. The error says every server refused; it is not
// ErrIntercepted, which only the root servers refusing shows.
func TestQueryServers_EveryServerRefused(t *testing.T) {
t.Parallel()
r := newTestResolver(t)
// The resolver asks servers only at their IPv4 addresses.
var servers []string
for _, ns := range liveFindAuthoritative(t, r, "google.com") {
for _, ip := range liveResolveIPs(t, r, ns) {
if net.ParseIP(ip).To4() != nil {
servers = append(servers, ip)
}
}
}
var err error
livednstest.Retry(
t,
"QueryServers(google.com servers, cloudflare.com)",
func(ctx context.Context) error {
_, err = r.QueryServers(
ctx, servers, "google.com.", "cloudflare.com.",
dns.TypeNS,
)
// When not every server refused, one may have given no
// reply at all, so the attempt is tried again.
if err != nil &&
!strings.HasPrefix(err.Error(), "every server of") {
return fmt.Errorf(
"%w: %w", livednstest.ErrNoAnswer, err,
)
}
return nil
},
)
require.ErrorIs(t, err, resolver.ErrRefused)
require.NotErrorIs(t, err, resolver.ErrIntercepted)
require.EqualError(
t, err,
"every server of google.com. refused a query for "+
"cloudflare.com.: dns query refused",
)
}
func TestQueryNameserver_RecordsSorted(t *testing.T) {
t.Parallel()