noise: make deleted-node expiry clock independent

Updates #3410
This commit is contained in:
Kristoffer Dalby
2026-09-04 10:31:21 +00:00
parent a91c0519c2
commit afb3020ef0
2 changed files with 10 additions and 6 deletions
+7 -4
View File
@@ -718,8 +718,11 @@ func (ns *noiseServer) PollNetMapHandler(
if errors.Is(err, errNodeNotInStore) && mapRequest.Stream {
expired := &tailcfg.MapResponse{
Node: &tailcfg.Node{
Key: mapRequest.NodeKey,
KeyExpiry: time.Now().Add(-time.Hour).UTC(),
Key: mapRequest.NodeKey,
// Zero means that the key does not expire. Use a fixed,
// ancient non-zero value so this remains expired even when
// the client's clock is substantially behind the server.
KeyExpiry: time.Unix(1, 0).UTC(),
Expired: true,
},
}
@@ -813,8 +816,8 @@ func (ns *noiseServer) RegistrationHandler(
// means the node is gone and its client should re-authenticate.
var errNodeNotInStore = errors.New("node not found")
// getAndValidateNode retrieves the node from the database using the NodeKey
// and validates that it matches the MachineKey from the Noise session.
// getAndValidateNode retrieves the node from the in-memory NodeStore using the
// NodeKey and validates that it matches the MachineKey from the Noise session.
func (ns *noiseServer) getAndValidateNode(mapRequest tailcfg.MapRequest) (types.NodeView, error) {
nv, ok := ns.headscale.state.GetNodeByNodeKey(mapRequest.NodeKey)
if !ok {
+3 -2
View File
@@ -618,8 +618,9 @@ func TestPollNetMapHandler_DeletedNodeGetsExpiredSelf(t *testing.T) {
resp := decodeMapResponse(t, compress, rec.Body.Bytes())
require.NotNil(t, resp.Node, "clients reject an initial map response without a node")
assert.Equal(t, node.NodeKey, resp.Node.Key)
assert.True(t, resp.Node.KeyExpiry.Before(time.Now()),
"a past KeyExpiry is what drives the client to NeedsLogin, got %v", resp.Node.KeyExpiry)
assert.Equal(t, time.Unix(1, 0).UTC(), resp.Node.KeyExpiry,
"a fixed ancient KeyExpiry must remain expired despite client clock skew")
assert.True(t, resp.Node.Expired)
})
}
}