fix: Deadlock in TCP resolver

This commit is contained in:
Alexandr Stelnykovych
2025-05-07 17:33:55 +03:00
parent 03da033cd2
commit 6c98755c77

View File

@@ -107,15 +107,21 @@ func (tr *TCPResolver) UseTLS() *TCPResolver {
}
func (tr *TCPResolver) getOrCreateResolverConn(ctx context.Context) (*tcpResolverConn, error) {
var existingConn *tcpResolverConn
// Minimize the time we hold the lock to avoid blocking other threads.
tr.Lock()
defer tr.Unlock()
if tr.resolverConn != nil && tr.resolverConn.abandoned.IsNotSet() {
existingConn = tr.resolverConn
}
tr.Unlock()
// Check if we have a resolver.
if tr.resolverConn != nil && tr.resolverConn.abandoned.IsNotSet() {
if existingConn != nil {
// If there is one, check if it's alive!
select {
case tr.resolverConn.heartbeat <- struct{}{}:
return tr.resolverConn, nil
case existingConn.heartbeat <- struct{}{}:
return existingConn, nil
case <-time.After(heartbeatTimeout):
log.Warningf("resolver: heartbeat for dns client %s failed", tr.resolver.Info.DescriptiveName())
case <-ctx.Done():
@@ -162,6 +168,10 @@ func (tr *TCPResolver) getOrCreateResolverConn(ctx context.Context) (*tcpResolve
tr.resolver.Info.DescriptiveName(),
)
// Thread-safe resolverConn creation.
tr.Lock()
defer tr.Unlock()
// Create resolver connection.
tr.resolverConnInstanceID++
resolverConn := &tcpResolverConn{