mirror of
https://github.com/tailscale/tailscale.git
synced 2026-11-09 02:53:09 -05:00
Report when an active selected exit node has not answered disco messages for a minute. Include the node name and last response time in the warning. Evaluate responsiveness from existing magicsock heartbeats and clear the warning when the peer becomes idle or responds. Use changes to nonzero WireGuard RX and TX counters to suppress warnings when traffic is working. Keep observation history and warning evaluation in the exitnodehealth feature. WireGuard-only peers are excluded. Updates #tailscale/corp#33007 Signed-off-by: James Tucker <james@tailscale.com>
48 lines
1.7 KiB
Go
48 lines
1.7 KiB
Go
// Copyright (c) Tailscale Inc & contributors
|
|
// SPDX-License-Identifier: BSD-3-Clause
|
|
|
|
//go:build !ts_omit_exitnodehealth && !ts_omit_health && !ts_omit_useexitnode
|
|
|
|
package magicsock
|
|
|
|
import (
|
|
"time"
|
|
|
|
"tailscale.com/feature"
|
|
"tailscale.com/tstime/mono"
|
|
"tailscale.com/types/key"
|
|
"tailscale.com/wgengine/wgint"
|
|
)
|
|
|
|
// HookExitNodeHeartbeatStateLocked records idle state and disco pong responses
|
|
// for exit node health monitoring under magicsock locks. It must not acquire
|
|
// backend or magicsock locks or call WireGuard.
|
|
var HookExitNodeHeartbeatStateLocked feature.Hook[func(*Conn, key.NodePublic, mono.Time, bool, bool, time.Duration)]
|
|
|
|
// HookExitNodeCheckResponsiveness checks WireGuard traffic counters
|
|
// and updates exit node responsiveness warnings after endpoint.mu is released.
|
|
// Only the enabled feature looks up counters and retains history; magicsock has
|
|
// no payload/state.
|
|
var HookExitNodeCheckResponsiveness feature.Hook[func(*Conn, key.NodePublic, func(key.NodePublic) (wgint.Peer, bool))]
|
|
|
|
func (de *endpoint) reportExitNodeHeartbeatStateLocked() {
|
|
if report, ok := HookExitNodeHeartbeatStateLocked.GetOk(); ok {
|
|
now := mono.Now()
|
|
idle := de.heartbeatDisabled || de.lastSendExt.IsZero() || now.Sub(de.lastSendExt) > sessionActiveTimeout ||
|
|
!de.c.havePrivateKey.Load() || de.c.networkDown()
|
|
report(de.c, de.publicKey, now, idle, false, sessionActiveTimeout)
|
|
}
|
|
}
|
|
|
|
func (de *endpoint) checkExitNodeResponsiveness() {
|
|
if report, ok := HookExitNodeCheckResponsiveness.GetOk(); ok {
|
|
report(de.c, de.publicKey, de.c.getPeerByKey)
|
|
}
|
|
}
|
|
|
|
func (c *Conn) reportExitNodePong(k key.NodePublic, now mono.Time) {
|
|
if report, ok := HookExitNodeHeartbeatStateLocked.GetOk(); ok {
|
|
report(c, k, now, false, true, sessionActiveTimeout)
|
|
}
|
|
}
|