all: implement PingRequest for node connectivity checking
Implement tailcfg.PingRequest support so the control server can verify whether a connected node is still reachable. This is the foundation for faster offline detection (currently ~16min due to Go HTTP/2 TCP retransmit behavior) and future C2N communication. The server sends a PingRequest via MapResponse with a unique callback URL. The Tailscale client responds with a HEAD request to that URL, proving connectivity. Round-trip latency is measured. Wire PingRequest through the Change → Batcher → MapResponse pipeline, add a ping tracker on State for correlating requests with responses, add ResolveNode for looking up nodes by ID/IP/hostname, and expose a /debug/ping page (elem-go form UI) and /machine/ping-response endpoint. Updates #2902 Updates #2129
This commit is contained in:
parent
32e1d77663
commit
b113655b71
9 changed files with 478 additions and 0 deletions
|
|
@ -39,6 +39,11 @@ type Change struct {
|
|||
// must be computed at runtime per-node. Used for policy changes
|
||||
// where each node may have different peer visibility.
|
||||
RequiresRuntimePeerComputation bool
|
||||
|
||||
// PingRequest, if non-nil, is a ping request to send to the node.
|
||||
// Used by the debug ping endpoint to verify node connectivity.
|
||||
// PingRequest is always targeted to a specific node via TargetNode.
|
||||
PingRequest *tailcfg.PingRequest
|
||||
}
|
||||
|
||||
// boolFieldNames returns all boolean field names for exhaustive testing.
|
||||
|
|
@ -93,6 +98,11 @@ func (r Change) Merge(other Change) Change {
|
|||
merged.TargetNode = other.TargetNode
|
||||
}
|
||||
|
||||
// Preserve PingRequest (first wins).
|
||||
if merged.PingRequest == nil {
|
||||
merged.PingRequest = other.PingRequest
|
||||
}
|
||||
|
||||
if r.Reason != "" && other.Reason != "" && r.Reason != other.Reason {
|
||||
merged.Reason = r.Reason + "; " + other.Reason
|
||||
} else if other.Reason != "" {
|
||||
|
|
@ -112,6 +122,10 @@ func (r Change) IsEmpty() bool {
|
|||
return false
|
||||
}
|
||||
|
||||
if r.PingRequest != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
return len(r.PeersChanged) == 0 &&
|
||||
len(r.PeersRemoved) == 0 &&
|
||||
len(r.PeerPatches) == 0
|
||||
|
|
@ -168,6 +182,10 @@ func (r Change) Type() string {
|
|||
return "config"
|
||||
}
|
||||
|
||||
if r.PingRequest != nil {
|
||||
return "ping"
|
||||
}
|
||||
|
||||
return "unknown"
|
||||
}
|
||||
|
||||
|
|
@ -454,6 +472,16 @@ func UserRemoved() Change {
|
|||
return c
|
||||
}
|
||||
|
||||
// PingNode creates a Change that sends a PingRequest to a specific node.
|
||||
// The node will respond to the PingRequest URL to prove connectivity.
|
||||
func PingNode(nodeID types.NodeID, pr *tailcfg.PingRequest) Change {
|
||||
return Change{
|
||||
Reason: "ping node",
|
||||
TargetNode: nodeID,
|
||||
PingRequest: pr,
|
||||
}
|
||||
}
|
||||
|
||||
// ExtraRecords returns a Change for when DNS extra records change.
|
||||
func ExtraRecords() Change {
|
||||
c := DNSConfig()
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue