mirror of
https://github.com/tailscale/tailscale.git
synced 2025-12-03 02:21:58 +00:00
net/dns: don't send on closed channel when message too large
Previously, if a DNS-over-TCP message was received while there were existing queries in-flight, and it was over the size limit, we'd close the 'responses' channel. This would cause those in-flight queries to send on the closed channel and panic. Instead, don't close the channel at all and rely on s.ctx being canceled, which will ensure that in-flight queries don't hang. Fixes #6725 Signed-off-by: Andrew Dunham <andrew@du.nham.ca> Change-Id: I8267728ac37ed7ae38ddd09ce2633a5824320097
This commit is contained in:
@@ -447,9 +447,17 @@ type dnsTCPSession struct {
|
||||
|
||||
func (s *dnsTCPSession) handleWrites() {
|
||||
defer s.conn.Close()
|
||||
defer close(s.responses)
|
||||
defer s.closeCtx()
|
||||
|
||||
// NOTE(andrew): we explicitly do not close the 'responses' channel
|
||||
// when this function exits. If we hit an error and return, we could
|
||||
// still have outstanding 'handleQuery' goroutines running, and if we
|
||||
// closed this channel they'd end up trying to send on a closed channel
|
||||
// when they finish.
|
||||
//
|
||||
// Because we call closeCtx, those goroutines will not hang since they
|
||||
// select on <-s.ctx.Done() as well as s.responses.
|
||||
|
||||
for {
|
||||
select {
|
||||
case <-s.readClosing:
|
||||
@@ -476,6 +484,7 @@ func (s *dnsTCPSession) handleQuery(q []byte) {
|
||||
return
|
||||
}
|
||||
|
||||
// See note in handleWrites (above) regarding this select{}
|
||||
select {
|
||||
case <-s.ctx.Done():
|
||||
case s.responses <- resp:
|
||||
@@ -483,6 +492,7 @@ func (s *dnsTCPSession) handleQuery(q []byte) {
|
||||
}
|
||||
|
||||
func (s *dnsTCPSession) handleReads() {
|
||||
defer s.conn.Close()
|
||||
defer close(s.readClosing)
|
||||
|
||||
for {
|
||||
@@ -515,6 +525,11 @@ func (s *dnsTCPSession) handleReads() {
|
||||
case <-s.ctx.Done():
|
||||
return
|
||||
default:
|
||||
// NOTE: by kicking off the query handling in a
|
||||
// new goroutine, it is possible that we'll
|
||||
// deliver responses out-of-order. This is
|
||||
// explicitly allowed by RFC7766, Section
|
||||
// 6.2.1.1 ("Query Pipelining").
|
||||
go s.handleQuery(buf)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user