mirror of
https://github.com/tailscale/tailscale.git
synced 2025-08-11 21:27:31 +00:00
control/controlclient, tailcfg: add Node.Expired field, set for expired nodes
Nodes that are expired, taking into account the time delta calculated from MapResponse.ControlTime have the newly-added Expired boolean set. For additional defense-in-depth, also replicate what control does and clear the Endpoints and DERP fields, and additionally set the node key to a bogus value. Updates #6932 Signed-off-by: Andrew Dunham <andrew@du.nham.ca> Change-Id: Ia2bd6b56064416feee28aef5699ca7090940662a
This commit is contained in:
@@ -308,26 +308,141 @@ func TestUndeltaPeers(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestFlagExpiredPeers(t *testing.T) {
|
||||
n := func(id tailcfg.NodeID, name string, expiry time.Time, mod ...func(*tailcfg.Node)) *tailcfg.Node {
|
||||
n := &tailcfg.Node{ID: id, Name: name, KeyExpiry: expiry}
|
||||
for _, f := range mod {
|
||||
f(n)
|
||||
}
|
||||
return n
|
||||
}
|
||||
|
||||
now := time.Unix(1673373129, 0)
|
||||
|
||||
oldClockNow := clockNow
|
||||
clockNow = func() time.Time { return now }
|
||||
t.Cleanup(func() { clockNow = oldClockNow })
|
||||
|
||||
timeInPast := now.Add(-1 * time.Hour)
|
||||
timeInFuture := now.Add(1 * time.Hour)
|
||||
|
||||
timeBeforeEpoch := flagExpiredPeersEpoch.Add(-1 * time.Second)
|
||||
if now.Before(timeBeforeEpoch) {
|
||||
panic("current time in test cannot be before epoch")
|
||||
}
|
||||
|
||||
var expiredKey key.NodePublic
|
||||
if err := expiredKey.UnmarshalText([]byte("nodekey:6da774d5d7740000000000000000000000000000000000000000000000000000")); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
mapRes *tailcfg.MapResponse
|
||||
want []*tailcfg.Node
|
||||
}{
|
||||
{
|
||||
name: "no_expiry",
|
||||
mapRes: &tailcfg.MapResponse{
|
||||
ControlTime: &now,
|
||||
Peers: []*tailcfg.Node{
|
||||
n(1, "foo", timeInFuture),
|
||||
n(2, "bar", timeInFuture),
|
||||
},
|
||||
},
|
||||
want: []*tailcfg.Node{
|
||||
n(1, "foo", timeInFuture),
|
||||
n(2, "bar", timeInFuture),
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "expiry",
|
||||
mapRes: &tailcfg.MapResponse{
|
||||
ControlTime: &now,
|
||||
Peers: []*tailcfg.Node{
|
||||
n(1, "foo", timeInFuture),
|
||||
n(2, "bar", timeInPast),
|
||||
},
|
||||
},
|
||||
want: []*tailcfg.Node{
|
||||
n(1, "foo", timeInFuture),
|
||||
n(2, "bar", timeInPast, func(n *tailcfg.Node) {
|
||||
n.Expired = true
|
||||
n.Key = expiredKey
|
||||
}),
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "bad_ControlTime",
|
||||
mapRes: &tailcfg.MapResponse{
|
||||
// ControlTime here is intentionally before our hardcoded epoch
|
||||
ControlTime: &timeBeforeEpoch,
|
||||
|
||||
Peers: []*tailcfg.Node{
|
||||
n(1, "foo", timeInFuture),
|
||||
n(2, "bar", timeBeforeEpoch.Add(-1*time.Hour)), // before ControlTime
|
||||
},
|
||||
},
|
||||
want: []*tailcfg.Node{
|
||||
n(1, "foo", timeInFuture),
|
||||
n(2, "bar", timeBeforeEpoch.Add(-1*time.Hour)), // should have expired, but ControlTime is before epoch
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "tagged_node",
|
||||
mapRes: &tailcfg.MapResponse{
|
||||
ControlTime: &now,
|
||||
Peers: []*tailcfg.Node{
|
||||
n(1, "foo", timeInFuture),
|
||||
n(2, "bar", time.Time{}), // tagged node; zero expiry
|
||||
},
|
||||
},
|
||||
want: []*tailcfg.Node{
|
||||
n(1, "foo", timeInFuture),
|
||||
n(2, "bar", time.Time{}), // not expired
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
ms := newTestMapSession(t)
|
||||
ms.flagExpiredPeers(tt.mapRes)
|
||||
if !reflect.DeepEqual(tt.mapRes.Peers, tt.want) {
|
||||
t.Errorf("wrong results\n got: %s\nwant: %s", formatNodes(tt.mapRes.Peers), formatNodes(tt.want))
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func formatNodes(nodes []*tailcfg.Node) string {
|
||||
var sb strings.Builder
|
||||
for i, n := range nodes {
|
||||
if i > 0 {
|
||||
sb.WriteString(", ")
|
||||
}
|
||||
var extra string
|
||||
fmt.Fprintf(&sb, "(%d, %q", n.ID, n.Name)
|
||||
|
||||
if n.Online != nil {
|
||||
extra += fmt.Sprintf(", online=%v", *n.Online)
|
||||
fmt.Fprintf(&sb, ", online=%v", *n.Online)
|
||||
}
|
||||
if n.LastSeen != nil {
|
||||
extra += fmt.Sprintf(", lastSeen=%v", n.LastSeen.Unix())
|
||||
fmt.Fprintf(&sb, ", lastSeen=%v", n.LastSeen.Unix())
|
||||
}
|
||||
fmt.Fprintf(&sb, "(%d, %q%s)", n.ID, n.Name, extra)
|
||||
if n.Key != (key.NodePublic{}) {
|
||||
fmt.Fprintf(&sb, ", key=%v", n.Key.String())
|
||||
}
|
||||
if n.Expired {
|
||||
fmt.Fprintf(&sb, ", expired=true")
|
||||
}
|
||||
sb.WriteString(")")
|
||||
}
|
||||
return sb.String()
|
||||
}
|
||||
|
||||
func newTestMapSession(t *testing.T) *mapSession {
|
||||
return newMapSession(key.NewNode())
|
||||
ms := newMapSession(key.NewNode())
|
||||
ms.logf = t.Logf
|
||||
return ms
|
||||
}
|
||||
|
||||
func TestNetmapForResponse(t *testing.T) {
|
||||
|
Reference in New Issue
Block a user