resolver: ask again over TCP when a reply offers recursion (closes #300)
check / check (push) Canceled after 0s

dnswatcher never asks for recursion, so a reply marked recursion
available comes from a resolver on the network answering in the
server's place, as on a network that sends all DNS to one resolver.
Such a resolver answers only from its cache, or with SERVFAIL or
REFUSED, which made make check fail there.

A reply over UDP marked so is now asked again over TCP, which many such
networks leave alone, and the TCP reply is used. A reply from a root
server's address still marked so is not used, and when every root
server refuses or gives one, the error is the existing "this network
intercepts DNS queries".

Model: opus-5-5
This commit is contained in:
2026-10-16 07:44:24 +00:00
parent adc8131191
commit d1024b2b20
5 changed files with 128 additions and 15 deletions
+49
View File
@@ -850,6 +850,55 @@ func TestQueryServers_NotEveryRootServerRefused(t *testing.T) {
require.NotContains(t, err.Error(), "refused a query for")
}
// TestQueryServers_RecursiveResolversAsRootServers passes public
// recursive resolvers of four operators to QueryServers as the servers
// of the root zone, as a network that sends every DNS query to a
// resolver would. Over UDP and over TCP alike, they mark every reply
// recursion available, which no root server does. Each refuses the
// query, replies SERVFAIL, or answers from its cache, as 1.1.1.1 does
// for com.: a reply that would be used if a root server gave it. Either
// way the error is ErrIntercepted, and since 1.1.1.1 and 8.8.8.8 refuse
// no such query, it says a reply was marked recursion available.
func TestQueryServers_RecursiveResolversAsRootServers(t *testing.T) {
t.Parallel()
r := newTestResolver(t)
resolvers := []string{
"1.1.1.1", "8.8.8.8", "9.9.9.9", "208.67.222.222",
}
for _, name := range []string{"com.", "desec.io."} {
var err error
livednstest.Retry(
t,
"QueryServers(public recursive resolvers as root servers, "+
name+")",
func(ctx context.Context) error {
_, err = r.QueryServers(ctx, resolvers, ".", name, dns.TypeNS)
// When the error is another, one resolver may have given
// no reply at all, so the attempt is tried again.
if err != nil && !errors.Is(err, resolver.ErrIntercepted) {
return fmt.Errorf(
"%w: %w", livednstest.ErrNoAnswer, err,
)
}
return nil
},
)
require.ErrorIs(t, err, resolver.ErrIntercepted)
require.EqualError(
t, err,
"every root server refused a query for "+name+" or gave a "+
"reply marked recursion available: "+
"this network intercepts DNS queries",
)
}
}
func TestQueryNameserver_RecordsSorted(t *testing.T) {
t.Parallel()