mirror of
https://github.com/tailscale/tailscale.git
synced 2025-08-12 13:48:01 +00:00
ipnlocal: accept a new opts.UpdatePrefs field.
This is needed because the original opts.Prefs field was at some point subverted for use in frontend->backend state migration for backward compatibility on some platforms. We still need that feature, but we also need the feature of providing the full set of prefs from `tailscale up`, *not* including overwriting the prefs.Persist keys, so we can't use the original field from `tailscale up`. `tailscale up` had attempted to compensate for that by doing SetPrefs() before Start(), but that violates the ipn.Backend contract, which says you should call Start() before anything else (that's why it's called Start()). As a result, doing SetPrefs({ControlURL=..., WantRunning=true}) would cause a connection to the *previous* control server (because WantRunning=true), and then connect to the *new* control server only after running Start(). This problem may have been avoided before, but only by pure luck. It turned out to be relatively harmless since the connection to the old control server was immediately closed and replaced anyway, but it created a race condition that could have caused spurious notifications or rejected keys if the server responded quickly. As already covered by existing TODOs, a better fix would be to have Start() get out of the business of state migration altogether. But we're approaching a release so I want to make the minimum possible fix. Fixes #1840. Signed-off-by: Avery Pennarun <apenwarr@tailscale.com>
This commit is contained in:
@@ -633,16 +633,18 @@ func (b *LocalBackend) getNewControlClientFunc() clientGen {
|
||||
//
|
||||
// b.mu must be held.
|
||||
func (b *LocalBackend) startIsNoopLocked(opts ipn.Options) bool {
|
||||
// Options has 4 fields; check all of them:
|
||||
// Options has 5 fields; check all of them:
|
||||
// * FrontendLogID
|
||||
// * StateKey
|
||||
// * Prefs
|
||||
// * UpdatePrefs
|
||||
// * AuthKey
|
||||
return b.state == ipn.Running &&
|
||||
b.hostinfo != nil &&
|
||||
b.hostinfo.FrontendLogID == opts.FrontendLogID &&
|
||||
b.stateKey == opts.StateKey &&
|
||||
opts.Prefs == nil &&
|
||||
opts.UpdatePrefs == nil &&
|
||||
opts.AuthKey == ""
|
||||
}
|
||||
|
||||
@@ -717,6 +719,12 @@ func (b *LocalBackend) Start(opts ipn.Options) error {
|
||||
return fmt.Errorf("loading requested state: %v", err)
|
||||
}
|
||||
|
||||
if opts.UpdatePrefs != nil {
|
||||
newPrefs := opts.UpdatePrefs
|
||||
newPrefs.Persist = b.prefs.Persist
|
||||
b.prefs = newPrefs
|
||||
}
|
||||
|
||||
wantRunning := b.prefs.WantRunning
|
||||
if wantRunning {
|
||||
if err := b.initMachineKeyLocked(); err != nil {
|
||||
@@ -779,6 +787,10 @@ func (b *LocalBackend) Start(opts ipn.Options) error {
|
||||
debugFlags = append([]string{"netstack"}, debugFlags...)
|
||||
}
|
||||
|
||||
// TODO(apenwarr): The only way to change the ServerURL is to
|
||||
// re-run b.Start(), because this is the only place we create a
|
||||
// new controlclient. SetPrefs() allows you to overwrite ServerURL,
|
||||
// but it won't take effect until the next Start().
|
||||
cc, err := b.getNewControlClientFunc()(controlclient.Options{
|
||||
GetMachinePrivateKey: b.createGetMachinePrivateKeyFunc(),
|
||||
Logf: logger.WithPrefix(b.logf, "control: "),
|
||||
|
Reference in New Issue
Block a user