Skip to content

Commit b7d396f

Browse files
committed
net: use DNS over TCP when use-vc is set in resolv.conf
Fixes #29358
1 parent 7e1ec1e commit b7d396f

File tree

5 files changed

+53
-6
lines changed

5 files changed

+53
-6
lines changed

src/net/dnsclient_unix.go

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -131,13 +131,19 @@ func dnsStreamRoundTrip(c Conn, id uint16, query dnsmessage.Question, b []byte)
131131
}
132132

133133
// exchange sends a query on the connection and hopes for a response.
134-
func (r *Resolver) exchange(ctx context.Context, server string, q dnsmessage.Question, timeout time.Duration) (dnsmessage.Parser, dnsmessage.Header, error) {
134+
func (r *Resolver) exchange(ctx context.Context, server string, q dnsmessage.Question, timeout time.Duration, usetcp bool) (dnsmessage.Parser, dnsmessage.Header, error) {
135135
q.Class = dnsmessage.ClassINET
136136
id, udpReq, tcpReq, err := newRequest(q)
137137
if err != nil {
138138
return dnsmessage.Parser{}, dnsmessage.Header{}, errCannotMarshalDNSMessage
139139
}
140-
for _, network := range []string{"udp", "tcp"} {
140+
var networks []string
141+
if usetcp {
142+
networks = []string{"tcp"}
143+
} else {
144+
networks = []string{"udp", "tcp"}
145+
}
146+
for _, network := range networks {
141147
ctx, cancel := context.WithDeadline(ctx, time.Now().Add(timeout))
142148
defer cancel()
143149

@@ -241,7 +247,7 @@ func (r *Resolver) tryOneName(ctx context.Context, cfg *dnsConfig, name string,
241247
for j := uint32(0); j < sLen; j++ {
242248
server := cfg.servers[(serverOffset+j)%sLen]
243249

244-
p, h, err := r.exchange(ctx, server, q, cfg.timeout)
250+
p, h, err := r.exchange(ctx, server, q, cfg.timeout, cfg.usetcp)
245251
if err != nil {
246252
dnsErr := &DNSError{
247253
Err: err.Error(),

src/net/dnsclient_unix_test.go

Lines changed: 29 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ func TestDNSTransportFallback(t *testing.T) {
8080
for _, tt := range dnsTransportFallbackTests {
8181
ctx, cancel := context.WithCancel(context.Background())
8282
defer cancel()
83-
_, h, err := r.exchange(ctx, tt.server, tt.question, time.Second)
83+
_, h, err := r.exchange(ctx, tt.server, tt.question, time.Second, false)
8484
if err != nil {
8585
t.Error(err)
8686
continue
@@ -136,7 +136,7 @@ func TestSpecialDomainName(t *testing.T) {
136136
for _, tt := range specialDomainNameTests {
137137
ctx, cancel := context.WithCancel(context.Background())
138138
defer cancel()
139-
_, h, err := r.exchange(ctx, server, tt.question, 3*time.Second)
139+
_, h, err := r.exchange(ctx, server, tt.question, 3*time.Second, false)
140140
if err != nil {
141141
t.Error(err)
142142
continue
@@ -1563,7 +1563,7 @@ func TestDNSDialTCP(t *testing.T) {
15631563
}
15641564
r := Resolver{PreferGo: true, Dial: fake.DialContext}
15651565
ctx := context.Background()
1566-
_, _, err := r.exchange(ctx, "0.0.0.0", mustQuestion("com.", dnsmessage.TypeALL, dnsmessage.ClassINET), time.Second)
1566+
_, _, err := r.exchange(ctx, "0.0.0.0", mustQuestion("com.", dnsmessage.TypeALL, dnsmessage.ClassINET), time.Second, false)
15671567
if err != nil {
15681568
t.Fatal("exhange failed:", err)
15691569
}
@@ -1621,3 +1621,29 @@ func TestTXTRecordTwoStrings(t *testing.T) {
16211621
t.Errorf("txt[1], got %q, want %q", txt[1], want)
16221622
}
16231623
}
1624+
// Issue 29358. Add configuration knob to force TCP-only DNS requests in the pure Go resolver.
1625+
func TestDNSUseTCP(t *testing.T) {
1626+
fake := fakeDNSServer{
1627+
rh: func(n, _ string, q dnsmessage.Message, _ time.Time) (dnsmessage.Message, error) {
1628+
r := dnsmessage.Message{
1629+
Header: dnsmessage.Header{
1630+
ID: q.Header.ID,
1631+
Response: true,
1632+
RCode: dnsmessage.RCodeSuccess,
1633+
},
1634+
Questions: q.Questions,
1635+
}
1636+
if n == "udp" {
1637+
t.Fatal("udp protocol was used instead of tcp")
1638+
}
1639+
return r, nil
1640+
},
1641+
}
1642+
r := Resolver{PreferGo: true, Dial: fake.DialContext}
1643+
ctx, cancel := context.WithCancel(context.Background())
1644+
defer cancel()
1645+
_, _, err := r.exchange(ctx, "0.0.0.0", mustQuestion("com.", dnsmessage.TypeALL, dnsmessage.ClassINET), time.Second, true)
1646+
if err != nil {
1647+
t.Fatal("exchange failed:", err)
1648+
}
1649+
}

src/net/dnsconfig_unix.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ type dnsConfig struct {
3232
err error // any error that occurs during open of resolv.conf
3333
mtime time.Time // time of resolv.conf modification
3434
soffset uint32 // used by serverOffset
35+
usetcp bool // force usage of TCP for DNS resolutions
3536
}
3637

3738
// See resolv.conf(5) on a Linux machine.
@@ -115,6 +116,8 @@ func dnsReadConfig(filename string) *dnsConfig {
115116
conf.attempts = n
116117
case s == "rotate":
117118
conf.rotate = true
119+
case s == "use-vc":
120+
conf.usetcp = true
118121
default:
119122
conf.unknownOpt = true
120123
}

src/net/dnsconfig_unix_test.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,17 @@ var dnsReadConfigTests = []struct {
102102
search: []string{"c.symbolic-datum-552.internal."},
103103
},
104104
},
105+
{
106+
name: "testdata/use-vc-resolv.conf",
107+
want: &dnsConfig{
108+
servers: defaultNS,
109+
ndots: 1,
110+
usetcp: true,
111+
timeout: 5 * time.Second,
112+
attempts: 2,
113+
search: []string{"domain.local."},
114+
},
115+
},
105116
}
106117

107118
func TestDNSReadConfig(t *testing.T) {

src/net/testdata/use-vc-resolv.conf

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
options use-vc

0 commit comments

Comments
 (0)