ipn: drop unchanged network map updates

This should never happen. But it is, so defend against it while
I fix the bug elsewhere.

Signed-off-by: David Crawshaw <crawshaw@tailscale.com>
pull/158/head
David Crawshaw 2020-03-07 15:15:10 -05:00
parent bb93d7aaba
commit c9d2fb6d11
1 changed files with 132 additions and 97 deletions

View File

@ -5,6 +5,8 @@
package ipn
import (
"crypto/sha256"
"encoding/json"
"errors"
"fmt"
"log"
@ -199,7 +201,24 @@ func (b *LocalBackend) Start(opts Options) error {
cli.UpdateEndpoints(0, endpoints)
}
cli.SetStatusFunc(func(newSt controlclient.Status) {
cli.SetStatusFunc(b.controlStatusUpdate)
b.e.SetStatusCallback(b.engineStatusUpdate)
b.mu.Lock()
prefs := b.prefs.Clone()
b.mu.Unlock()
blid := b.backendLogID
b.logf("Backend: logs: be:%v fe:%v\n", blid, opts.FrontendLogID)
b.send(Notify{BackendLogID: &blid})
b.send(Notify{Prefs: prefs})
cli.Login(nil, controlclient.LoginDefault)
return nil
}
// controlStatusUpdate is passed as a callback to controlclient SetStatusFunc.
func (b *LocalBackend) controlStatusUpdate(newSt controlclient.Status) {
if newSt.LoginFinished != nil {
// Auth completed, unblock the engine
b.blockEngineUpdates(false)
@ -223,8 +242,19 @@ func (b *LocalBackend) Start(opts Options) error {
b.send(Notify{Prefs: prefs})
}
if newSt.NetMap != nil {
changed := true
b.mu.Lock()
if b.netMapCache != nil && b.cmpDiff != nil {
if b.netMapCache != nil {
hash1, err1 := jsonHash(newSt.NetMap)
hash2, err2 := jsonHash(b.netMapCache)
if err1 == nil && err2 == nil {
changed = hash1 != hash2
} else {
b.logf("[unexpected] netmap hash encode failed: %v, %v", err1, err2)
}
if changed && b.cmpDiff != nil {
s1 := strings.Split(b.netMapCache.Concise(), "\n")
s2 := strings.Split(newSt.NetMap.Concise(), "\n")
diff := b.cmpDiff(s1, s2)
@ -232,11 +262,21 @@ func (b *LocalBackend) Start(opts Options) error {
b.logf("netmap diff:\n%v\n", diff)
}
}
}
b.netMapCache = newSt.NetMap
b.mu.Unlock()
if changed {
b.send(Notify{NetMap: newSt.NetMap})
b.updateFilter(newSt.NetMap)
} else {
// This should never happen. A properly
// functioning CONTROL should skip sending
// equal netmaps. We detect and log here both
// as defense-in-depth and to give us warning
// (in the logs) that something is wrong.
b.logf("[unexpected] unchanged netmap, skipping")
}
}
if newSt.URL != "" {
b.logf("Received auth URL: %.20v...\n", newSt.URL)
@ -266,9 +306,10 @@ func (b *LocalBackend) Start(opts Options) error {
b.SetPrefs(prefs)
}
b.stateMachine()
})
}
b.e.SetStatusCallback(func(s *wgengine.Status, err error) {
// engineStatusUpdate is passed as a callback to wgengine SetStatusCallback.
func (b *LocalBackend) engineStatusUpdate(s *wgengine.Status, err error) {
if err != nil {
b.logf("wgengine status error: %#v", err)
return
@ -295,19 +336,13 @@ func (b *LocalBackend) Start(opts Options) error {
b.statusLock.Unlock()
b.send(Notify{Engine: &es})
})
}
b.mu.Lock()
prefs := b.prefs.Clone()
b.mu.Unlock()
blid := b.backendLogID
b.logf("Backend: logs: be:%v fe:%v\n", blid, opts.FrontendLogID)
b.send(Notify{BackendLogID: &blid})
b.send(Notify{Prefs: prefs})
cli.Login(nil, controlclient.LoginDefault)
return nil
func jsonHash(v interface{}) (hash [sha256.Size]byte, err error) {
h := sha256.New()
err = json.NewEncoder(h).Encode(v)
h.Sum(hash[:0])
return hash, err
}
func (b *LocalBackend) updateFilter(netMap *controlclient.NetworkMap) {