[client] peer: re-arm the WireGuard watcher after a lazy wake

The Conn struct is reused across lazy-connection deactivate/activate. Close
cancels the WireGuard watcher (via wgWatcherCancel, and ctxCancel also tears
down its context) but left conn.wgWatcher pointing at the stopped instance.
enableWgWatcherIfNeeded skips while conn.wgWatcher is non-nil, so the next Open
never started a fresh watcher: once a lazy connection had idled and woken, the
peer ran with no watcher at all — no WireGuard handshake-timeout detection and
none of the escalation that depends on it.

Clear conn.wgWatcher and conn.wgWatcherCancel in Close so the next Open re-arms
a fresh watcher.
This commit is contained in:
riccardom
2026-08-07 09:42:27 +02:00
parent 9a05a1c698
commit 4daf7da383

View File

@@ -307,6 +307,14 @@ func (conn *Conn) Close(signalToRemote bool) {
if conn.wgWatcherCancel != nil {
conn.wgWatcherCancel()
// The Conn struct is reused across lazy deactivate/activate. ctxCancel above
// already stopped the watcher goroutine (its ctx derives from conn.ctx), but
// enableWgWatcherIfNeeded skips while conn.wgWatcher is non-nil — so a stale
// pointer here would leave the peer with no watcher after the next Open, and thus
// no WireGuard handshake-timeout detection once a lazy connection has idled and
// woken. Clear it so the next Open starts a fresh watcher.
conn.wgWatcher = nil
conn.wgWatcherCancel = nil
}
conn.workerRelay.CloseConn()
if conn.workerICE != nil {