ipn/ipnlocal: lazily connect to control, lazily generate machine key

Fixes #1573

Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
This commit is contained in:
Brad Fitzpatrick 2021-04-02 08:21:40 -07:00
parent d50406f185
commit 9b57cd53ba
2 changed files with 50 additions and 29 deletions

View File

@ -18,6 +18,7 @@
"strconv" "strconv"
"strings" "strings"
"sync" "sync"
"sync/atomic"
"time" "time"
"inet.af/netaddr" "inet.af/netaddr"
@ -567,6 +568,13 @@ func (b *LocalBackend) Start(opts ipn.Options) error {
return fmt.Errorf("loading requested state: %v", err) return fmt.Errorf("loading requested state: %v", err)
} }
wantRunning := b.prefs.WantRunning
if wantRunning {
if err := b.initMachineKeyLocked(); err != nil {
return fmt.Errorf("initMachineKeyLocked: %w", err)
}
}
b.inServerMode = b.prefs.ForceDaemon b.inServerMode = b.prefs.ForceDaemon
b.serverURL = b.prefs.ControlURL b.serverURL = b.prefs.ControlURL
hostinfo.RoutableIPs = append(hostinfo.RoutableIPs, b.prefs.AdvertiseRoutes...) hostinfo.RoutableIPs = append(hostinfo.RoutableIPs, b.prefs.AdvertiseRoutes...)
@ -579,7 +587,6 @@ func (b *LocalBackend) Start(opts ipn.Options) error {
b.notify = opts.Notify b.notify = opts.Notify
b.setNetMapLocked(nil) b.setNetMapLocked(nil)
persistv := b.prefs.Persist persistv := b.prefs.Persist
machinePrivKey := b.machinePrivKey
b.mu.Unlock() b.mu.Unlock()
b.updateFilter(nil, nil) b.updateFilter(nil, nil)
@ -616,23 +623,18 @@ func (b *LocalBackend) Start(opts ipn.Options) error {
persistv = &persist.Persist{} persistv = &persist.Persist{}
} }
cli, err := controlclient.New(controlclient.Options{ cli, err := controlclient.New(controlclient.Options{
GetMachinePrivateKey: func() (wgkey.Private, error) { GetMachinePrivateKey: b.createGetMachinePrivateKeyFunc(),
// TODO(bradfitz): finish pushing this laziness further; see Logf: logger.WithPrefix(b.logf, "control: "),
// https://github.com/tailscale/tailscale/issues/1573 Persist: *persistv,
// For now this is only lazy-ified in controlclient. ServerURL: b.serverURL,
return machinePrivKey, nil AuthKey: opts.AuthKey,
}, Hostinfo: hostinfo,
Logf: logger.WithPrefix(b.logf, "control: "), KeepAlive: true,
Persist: *persistv, NewDecompressor: b.newDecompressor,
ServerURL: b.serverURL, HTTPTestClient: opts.HTTPTestClient,
AuthKey: opts.AuthKey, DiscoPublicKey: discoPublic,
Hostinfo: hostinfo, DebugFlags: controlDebugFlags,
KeepAlive: true, LinkMonitor: b.e.GetLinkMonitor(),
NewDecompressor: b.newDecompressor,
HTTPTestClient: opts.HTTPTestClient,
DiscoPublicKey: discoPublic,
DebugFlags: controlDebugFlags,
LinkMonitor: b.e.GetLinkMonitor(),
// Don't warn about broken Linux IP forwading when // Don't warn about broken Linux IP forwading when
// netstack is being used. // netstack is being used.
@ -664,7 +666,9 @@ func (b *LocalBackend) Start(opts ipn.Options) error {
b.send(ipn.Notify{BackendLogID: &blid}) b.send(ipn.Notify{BackendLogID: &blid})
b.send(ipn.Notify{Prefs: prefs}) b.send(ipn.Notify{Prefs: prefs})
cli.Login(nil, controlclient.LoginDefault) if wantRunning {
cli.Login(nil, controlclient.LoginDefault)
}
return nil return nil
} }
@ -924,6 +928,31 @@ func (b *LocalBackend) popBrowserAuthNow() {
} }
} }
// For testing lazy machine key generation.
var panicOnMachineKeyGeneration, _ = strconv.ParseBool(os.Getenv("TS_DEBUG_PANIC_MACHINE_KEY"))
func (b *LocalBackend) createGetMachinePrivateKeyFunc() func() (wgkey.Private, error) {
var cache atomic.Value
return func() (wgkey.Private, error) {
if panicOnMachineKeyGeneration {
panic("machine key generated")
}
if v, ok := cache.Load().(wgkey.Private); ok {
return v, nil
}
b.mu.Lock()
defer b.mu.Unlock()
if v, ok := cache.Load().(wgkey.Private); ok {
return v, nil
}
if err := b.initMachineKeyLocked(); err != nil {
return wgkey.Private{}, err
}
cache.Store(b.machinePrivKey)
return b.machinePrivKey, nil
}
}
// initMachineKeyLocked is called to initialize b.machinePrivKey. // initMachineKeyLocked is called to initialize b.machinePrivKey.
// //
// b.prefs must already be initialized. // b.prefs must already be initialized.
@ -1041,9 +1070,6 @@ func (b *LocalBackend) loadStateLocked(key ipn.StateKey, prefs *ipn.Prefs, legac
// value instead of making up a new one. // value instead of making up a new one.
b.logf("using frontend prefs: %s", prefs.Pretty()) b.logf("using frontend prefs: %s", prefs.Pretty())
b.prefs = prefs.Clone() b.prefs = prefs.Clone()
if err := b.initMachineKeyLocked(); err != nil {
return fmt.Errorf("initMachineKeyLocked: %w", err)
}
b.writeServerModeStartState(b.userID, b.prefs) b.writeServerModeStartState(b.userID, b.prefs)
return nil return nil
} }
@ -1076,11 +1102,9 @@ func (b *LocalBackend) loadStateLocked(key ipn.StateKey, prefs *ipn.Prefs, legac
} }
if !loaded { if !loaded {
b.prefs = ipn.NewPrefs() b.prefs = ipn.NewPrefs()
b.prefs.WantRunning = false
b.logf("created empty state for %q: %s", key, b.prefs.Pretty()) b.logf("created empty state for %q: %s", key, b.prefs.Pretty())
} }
if err := b.initMachineKeyLocked(); err != nil {
return fmt.Errorf("initMachineKeyLocked: %w", err)
}
return nil return nil
case err != nil: case err != nil:
return fmt.Errorf("store.ReadState(%q): %v", key, err) return fmt.Errorf("store.ReadState(%q): %v", key, err)
@ -1090,9 +1114,6 @@ func (b *LocalBackend) loadStateLocked(key ipn.StateKey, prefs *ipn.Prefs, legac
return fmt.Errorf("PrefsFromBytes: %v", err) return fmt.Errorf("PrefsFromBytes: %v", err)
} }
b.logf("backend prefs for %q: %s", key, b.prefs.Pretty()) b.logf("backend prefs for %q: %s", key, b.prefs.Pretty())
if err := b.initMachineKeyLocked(); err != nil {
return fmt.Errorf("initMachineKeyLocked: %w", err)
}
return nil return nil
} }

View File

@ -335,7 +335,7 @@ func NewPrefs() *Prefs {
RouteAll: true, RouteAll: true,
AllowSingleHosts: true, AllowSingleHosts: true,
CorpDNS: true, CorpDNS: true,
WantRunning: true, WantRunning: false,
NetfilterMode: preftype.NetfilterOn, NetfilterMode: preftype.NetfilterOn,
} }
} }