diff --git a/control/controlclient/direct.go b/control/controlclient/direct.go index 47283a673..99d1df992 100644 --- a/control/controlclient/direct.go +++ b/control/controlclient/direct.go @@ -8,6 +8,7 @@ import ( "bytes" "cmp" "context" + "crypto/sha256" "encoding/binary" "encoding/json" "errors" @@ -93,6 +94,7 @@ type Direct struct { mu sync.Mutex // mutex guards the following fields serverLegacyKey key.MachinePublic // original ("legacy") nacl crypto_box-based public key; only used for signRegisterRequest on Windows now serverNoiseKey key.MachinePublic + lastLiteHash [sha256.Size]byte // last hash of lite map request we sent to control for which we got a 200 OK sfGroup singleflight.Group[struct{}, *NoiseClient] // protects noiseClient creation. noiseClient *NoiseClient @@ -939,6 +941,12 @@ func (c *Direct) sendMapRequest(ctx context.Context, isStreaming bool, nu Netmap return err } + bodyHash := sha256.Sum256(bodyData) + if !isStreaming && nu == nil && c.lastLiteHashEquals(bodyHash) { + vlogf("netmap: skipping lite update; previous was identical and succeeded") + return nil + } + ctx, cancel := context.WithCancel(ctx) defer cancel() @@ -1000,6 +1008,10 @@ func (c *Direct) sendMapRequest(ctx context.Context, isStreaming bool, nu Netmap watchdogTimer.Reset(watchdogTimeout) if nu == nil { + c.mu.Lock() + c.lastLiteHash = bodyHash + c.mu.Unlock() + io.Copy(io.Discard, res.Body) return nil } @@ -1138,6 +1150,14 @@ func (c *Direct) sendMapRequest(ctx context.Context, isStreaming bool, nu Netmap return nil } +// lastLiteHashEquals reports whether the last sent lite map request hash +// is equal to the given hash. +func (c *Direct) lastLiteHashEquals(hash [sha256.Size]byte) bool { + c.mu.Lock() + defer c.mu.Unlock() + return c.lastLiteHash == hash +} + func (c *Direct) handleDebugMessage(ctx context.Context, debug *tailcfg.Debug) error { if code := debug.Exit; code != nil { c.logf("exiting process with status %v per controlplane", *code)