net/dns{., resolver}: time out DNS queries after 10 seconds (#4690)
Fixes https://github.com/tailscale/corp/issues/5198 The upstream forwarder will block indefinitely on `udpconn.ReadFrom` if no reply is recieved, due to the lack of deadline on the connection object. There still isn't a deadline on the connection object, but the automatic closing of the context on deadline expiry will close the connection via `closeOnCtxDone`, unblocking the read and resulting in a normal teardown. Signed-off-by: Tom DNetto <tom@tailscale.com>pull/4709/head
parent
ec4c49a338
commit
acfe5bd33b
|
@ -331,6 +331,9 @@ func (m *Manager) NextPacket() ([]byte, error) {
|
||||||
return buf, nil
|
return buf, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Query executes a DNS query recieved from the given address. The query is
|
||||||
|
// provided in bs as a wire-encoded DNS query without any transport header.
|
||||||
|
// This method is called for requests arriving over UDP and TCP.
|
||||||
func (m *Manager) Query(ctx context.Context, bs []byte, from netaddr.IPPort) ([]byte, error) {
|
func (m *Manager) Query(ctx context.Context, bs []byte, from netaddr.IPPort) ([]byte, error) {
|
||||||
select {
|
select {
|
||||||
case <-m.ctx.Done():
|
case <-m.ctx.Done():
|
||||||
|
@ -460,7 +463,7 @@ func (m *Manager) HandleTCPConn(conn net.Conn, srcAddr netaddr.IPPort) {
|
||||||
responses: make(chan []byte),
|
responses: make(chan []byte),
|
||||||
readClosing: make(chan struct{}),
|
readClosing: make(chan struct{}),
|
||||||
}
|
}
|
||||||
s.ctx, s.closeCtx = context.WithCancel(context.Background())
|
s.ctx, s.closeCtx = context.WithCancel(m.ctx)
|
||||||
go s.handleReads()
|
go s.handleReads()
|
||||||
s.handleWrites()
|
s.handleWrites()
|
||||||
}
|
}
|
||||||
|
|
|
@ -256,6 +256,12 @@ func (r *Resolver) Close() {
|
||||||
r.forwarder.Close()
|
r.forwarder.Close()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// dnsQueryTimeout is not intended to be user-visible (the users
|
||||||
|
// DNS resolver will retry well before that), just put an upper
|
||||||
|
// bound on per-query resource usage.
|
||||||
|
const dnsQueryTimeout = 10 * time.Second
|
||||||
|
|
||||||
|
|
||||||
func (r *Resolver) Query(ctx context.Context, bs []byte, from netaddr.IPPort) ([]byte, error) {
|
func (r *Resolver) Query(ctx context.Context, bs []byte, from netaddr.IPPort) ([]byte, error) {
|
||||||
metricDNSQueryLocal.Add(1)
|
metricDNSQueryLocal.Add(1)
|
||||||
select {
|
select {
|
||||||
|
@ -268,7 +274,7 @@ func (r *Resolver) Query(ctx context.Context, bs []byte, from netaddr.IPPort) ([
|
||||||
out, err := r.respond(bs)
|
out, err := r.respond(bs)
|
||||||
if err == errNotOurName {
|
if err == errNotOurName {
|
||||||
responses := make(chan packet, 1)
|
responses := make(chan packet, 1)
|
||||||
ctx, cancel := context.WithCancel(ctx)
|
ctx, cancel := context.WithTimeout(ctx, dnsQueryTimeout)
|
||||||
defer close(responses)
|
defer close(responses)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
err = r.forwarder.forwardWithDestChan(ctx, packet{bs, from}, responses)
|
err = r.forwarder.forwardWithDestChan(ctx, packet{bs, from}, responses)
|
||||||
|
|
Loading…
Reference in New Issue