net: set AD bit in DNS queries when trust-ad in resolv.conf

Fixes #51152

Change-Id: Ib366e733434b4bb60ac93e6e622d9ba50bfe4e26
GitHub-Last-Rev: e98220d62f
GitHub-Pull-Request: golang/go#54921
Reviewed-on: https://go-review.googlesource.com/c/go/+/428955
Reviewed-by: Damien Neil <dneil@google.com>
Run-TryBot: Damien Neil <dneil@google.com>
Reviewed-by: Michael Knyszek <mknyszek@google.com>
Run-TryBot: Ian Lance Taylor <iant@golang.org>
Reviewed-by: Ian Lance Taylor <iant@golang.org>
Auto-Submit: Ian Lance Taylor <iant@golang.org>
TryBot-Result: Gopher Robot <gobot@golang.org>
This commit is contained in:
Mateusz Poliwczak 2022-09-09 06:40:57 +00:00 committed by Gopher Robot
parent a84f46a28a
commit 2d89bec2de
4 changed files with 77 additions and 9 deletions

View file

@ -51,9 +51,9 @@ var (
errServerTemporarilyMisbehaving = errors.New("server misbehaving")
)
func newRequest(q dnsmessage.Question) (id uint16, udpReq, tcpReq []byte, err error) {
func newRequest(q dnsmessage.Question, ad bool) (id uint16, udpReq, tcpReq []byte, err error) {
id = uint16(randInt())
b := dnsmessage.NewBuilder(make([]byte, 2, 514), dnsmessage.Header{ID: id, RecursionDesired: true})
b := dnsmessage.NewBuilder(make([]byte, 2, 514), dnsmessage.Header{ID: id, RecursionDesired: true, AuthenticData: ad})
if err := b.StartQuestions(); err != nil {
return 0, nil, nil, err
}
@ -157,9 +157,9 @@ func dnsStreamRoundTrip(c Conn, id uint16, query dnsmessage.Question, b []byte)
}
// exchange sends a query on the connection and hopes for a response.
func (r *Resolver) exchange(ctx context.Context, server string, q dnsmessage.Question, timeout time.Duration, useTCP bool) (dnsmessage.Parser, dnsmessage.Header, error) {
func (r *Resolver) exchange(ctx context.Context, server string, q dnsmessage.Question, timeout time.Duration, useTCP, ad bool) (dnsmessage.Parser, dnsmessage.Header, error) {
q.Class = dnsmessage.ClassINET
id, udpReq, tcpReq, err := newRequest(q)
id, udpReq, tcpReq, err := newRequest(q, ad)
if err != nil {
return dnsmessage.Parser{}, dnsmessage.Header{}, errCannotMarshalDNSMessage
}
@ -273,7 +273,7 @@ func (r *Resolver) tryOneName(ctx context.Context, cfg *dnsConfig, name string,
for j := uint32(0); j < sLen; j++ {
server := cfg.servers[(serverOffset+j)%sLen]
p, h, err := r.exchange(ctx, server, q, cfg.timeout, cfg.useTCP)
p, h, err := r.exchange(ctx, server, q, cfg.timeout, cfg.useTCP, cfg.trustAD)
if err != nil {
dnsErr := &DNSError{
Err: err.Error(),

View file

@ -79,7 +79,7 @@ func TestDNSTransportFallback(t *testing.T) {
for _, tt := range dnsTransportFallbackTests {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
_, h, err := r.exchange(ctx, tt.server, tt.question, time.Second, useUDPOrTCP)
_, h, err := r.exchange(ctx, tt.server, tt.question, time.Second, useUDPOrTCP, false)
if err != nil {
t.Error(err)
continue
@ -135,7 +135,7 @@ func TestSpecialDomainName(t *testing.T) {
for _, tt := range specialDomainNameTests {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
_, h, err := r.exchange(ctx, server, tt.question, 3*time.Second, useUDPOrTCP)
_, h, err := r.exchange(ctx, server, tt.question, 3*time.Second, useUDPOrTCP, false)
if err != nil {
t.Error(err)
continue
@ -1593,7 +1593,7 @@ func TestDNSDialTCP(t *testing.T) {
}
r := Resolver{PreferGo: true, Dial: fake.DialContext}
ctx := context.Background()
_, _, err := r.exchange(ctx, "0.0.0.0", mustQuestion("com.", dnsmessage.TypeALL, dnsmessage.ClassINET), time.Second, useUDPOrTCP)
_, _, err := r.exchange(ctx, "0.0.0.0", mustQuestion("com.", dnsmessage.TypeALL, dnsmessage.ClassINET), time.Second, useUDPOrTCP, false)
if err != nil {
t.Fatal("exhange failed:", err)
}
@ -1746,7 +1746,7 @@ func TestDNSUseTCP(t *testing.T) {
r := Resolver{PreferGo: true, Dial: fake.DialContext}
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
_, _, err := r.exchange(ctx, "0.0.0.0", mustQuestion("com.", dnsmessage.TypeALL, dnsmessage.ClassINET), time.Second, useTCPOnly)
_, _, err := r.exchange(ctx, "0.0.0.0", mustQuestion("com.", dnsmessage.TypeALL, dnsmessage.ClassINET), time.Second, useTCPOnly, false)
if err != nil {
t.Fatal("exchange failed:", err)
}
@ -2344,3 +2344,68 @@ func TestLongDNSNames(t *testing.T) {
}
}
}
func TestDNSTrustAD(t *testing.T) {
fake := fakeDNSServer{
rh: func(_, _ string, q dnsmessage.Message, _ time.Time) (dnsmessage.Message, error) {
if q.Questions[0].Name.String() == "notrustad.go.dev." && q.Header.AuthenticData {
t.Error("unexpected AD bit")
}
if q.Questions[0].Name.String() == "trustad.go.dev." && !q.Header.AuthenticData {
t.Error("expected AD bit")
}
r := dnsmessage.Message{
Header: dnsmessage.Header{
ID: q.Header.ID,
Response: true,
RCode: dnsmessage.RCodeSuccess,
},
Questions: q.Questions,
}
if q.Questions[0].Type == dnsmessage.TypeA {
r.Answers = []dnsmessage.Resource{
{
Header: dnsmessage.ResourceHeader{
Name: q.Questions[0].Name,
Type: dnsmessage.TypeA,
Class: dnsmessage.ClassINET,
Length: 4,
},
Body: &dnsmessage.AResource{
A: TestAddr,
},
},
}
}
return r, nil
}}
r := &Resolver{PreferGo: true, Dial: fake.DialContext}
conf, err := newResolvConfTest()
if err != nil {
t.Fatal(err)
}
defer conf.teardown()
err = conf.writeAndUpdate([]string{"nameserver 127.0.0.1"})
if err != nil {
t.Fatal(err)
}
if _, err := r.LookupIPAddr(context.Background(), "notrustad.go.dev"); err != nil {
t.Errorf("lookup failed: %v", err)
}
err = conf.writeAndUpdate([]string{"nameserver 127.0.0.1", "options trust-ad"})
if err != nil {
t.Fatal(err)
}
if _, err := r.LookupIPAddr(context.Background(), "trustad.go.dev"); err != nil {
t.Errorf("lookup failed: %v", err)
}
}

View file

@ -29,6 +29,7 @@ type dnsConfig struct {
soffset uint32 // used by serverOffset
singleRequest bool // use sequential A and AAAA queries instead of parallel queries
useTCP bool // force usage of TCP for DNS resolutions
trustAD bool // add AD flag to queries
}
// serverOffset returns an offset that can be used to determine

View file

@ -113,6 +113,8 @@ func dnsReadConfig(filename string) *dnsConfig {
// https://www.freebsd.org/cgi/man.cgi?query=resolv.conf&sektion=5&manpath=freebsd-release-ports
// https://man.openbsd.org/resolv.conf.5
conf.useTCP = true
case s == "trust-ad":
conf.trustAD = true
case s == "edns0":
// We use EDNS by default.
// Ignore this option.