diff options
| author | Avery Pennarun <apenwarr@tailscale.com> | 2021-04-28 09:41:55 -0400 |
|---|---|---|
| committer | Avery Pennarun <apenwarr@tailscale.com> | 2021-04-28 09:47:30 -0400 |
| commit | a8766815a43d8bd415032346f869f0ca54a35dbf (patch) | |
| tree | ae87cb25f0ab0cedd1478e69b0425ba78ceaccd7 /ipn | |
| parent | 306a094d4bde6c5f3f6369d570f68174e6fb7443 (diff) | |
| download | tailscale-apenwarr/ioslogin.tar.xz tailscale-apenwarr/ioslogin.zip | |
ipn: cc.Login(noninteractive) at start even if WantRunning=false.apenwarr/ioslogin
We were not properly initializing controlclient at startup, if
Prefs.WantRunning was initially false. This originally would cause the
state machine to get stuck in NewState, but an earlier erroneous change
tried to make it get stuck in NeedsLogin instead, which is incorrect;
NeedsLogin means we need *interactive* login, which is not true. The
correct fix is to not get it stuck.
While we're here:
- Add a bunch of comments to explain how these work.
- Unexport the Status.state var from controlclient. There has not been
any need for outsiders to inspect it for a long time; it's needed
only by unit tests.
- Remove a very suspicious check from AuthCantContinue that its self
pointer != nil.
- Remove an extremely suspicious "defer b.stateMachine()" from Start().
There is no need to run the state machine when nothing has happened
yet; any apparent need for this is a sign of some other bug.
Fixes tailscale/corp#1660 (iOS app startup bug)
Signed-off-by: Avery Pennarun <apenwarr@tailscale.com>
Diffstat (limited to 'ipn')
| -rw-r--r-- | ipn/backend.go | 14 | ||||
| -rw-r--r-- | ipn/ipnlocal/local.go | 10 | ||||
| -rw-r--r-- | ipn/ipnlocal/local_test.go | 42 |
3 files changed, 12 insertions, 54 deletions
diff --git a/ipn/backend.go b/ipn/backend.go index b5aa78c2d..89356c30b 100644 --- a/ipn/backend.go +++ b/ipn/backend.go @@ -17,13 +17,13 @@ import ( type State int const ( - NoState = State(iota) - InUseOtherUser - NeedsLogin - NeedsMachineAuth - Stopped - Starting - Running + NoState = State(iota) + InUseOtherUser // backend is in use by another user + NeedsLogin // an *interactive* user login is required; URL available + NeedsMachineAuth // logged in, but machine key needs approval + Stopped // user requested WantRunning=false + Starting // in transition from stopped to running + Running // network is connected ) // GoogleIDToken Type is the tailcfg.Oauth2Token.TokenType for the Google diff --git a/ipn/ipnlocal/local.go b/ipn/ipnlocal/local.go index b04061b7f..503df874d 100644 --- a/ipn/ipnlocal/local.go +++ b/ipn/ipnlocal/local.go @@ -627,7 +627,6 @@ func (b *LocalBackend) Start(opts ipn.Options) error { return errors.New("no state key or prefs provided") } - defer b.stateMachine() if opts.Prefs != nil { b.logf("Start: %v", opts.Prefs.Pretty()) } else { @@ -786,9 +785,10 @@ func (b *LocalBackend) Start(opts ipn.Options) error { b.send(ipn.Notify{BackendLogID: &blid}) b.send(ipn.Notify{Prefs: prefs}) - if wantRunning { - cc.Login(nil, controlclient.LoginDefault) - } + // Even if we don't want to be *connected* to tailscale right now, + // we can attempt the non-interactive login process right away, + // which will make connecting fast later. + cc.Login(nil, controlclient.LoginDefault) return nil } @@ -2105,7 +2105,7 @@ func (b *LocalBackend) nextState() ipn.State { switch { case netMap == nil: - if cc.AuthCantContinue() { + if cc.AuthCantContinue() && b.authURL != "" { // Auth was interrupted or waiting for URL visit, // so it won't proceed without human help. return ipn.NeedsLogin diff --git a/ipn/ipnlocal/local_test.go b/ipn/ipnlocal/local_test.go index fa2f7cef2..733a7a066 100644 --- a/ipn/ipnlocal/local_test.go +++ b/ipn/ipnlocal/local_test.go @@ -5,20 +5,15 @@ package ipnlocal import ( - "bytes" - "fmt" "net/http" "reflect" - "sync" "testing" "inet.af/netaddr" - "tailscale.com/ipn" "tailscale.com/net/interfaces" "tailscale.com/net/tsaddr" "tailscale.com/tailcfg" "tailscale.com/types/netmap" - "tailscale.com/wgengine" "tailscale.com/wgengine/wgcfg" ) @@ -433,40 +428,3 @@ func (panicOnUseTransport) RoundTrip(*http.Request) (*http.Response, error) { } var nl = []byte("\n") - -func TestStartsInNeedsLoginState(t *testing.T) { - var ( - mu sync.Mutex - logBuf bytes.Buffer - ) - logf := func(format string, a ...interface{}) { - mu.Lock() - defer mu.Unlock() - fmt.Fprintf(&logBuf, format, a...) - if !bytes.HasSuffix(logBuf.Bytes(), nl) { - logBuf.Write(nl) - } - } - store := new(ipn.MemoryStore) - eng, err := wgengine.NewFakeUserspaceEngine(logf, 0) - if err != nil { - t.Fatalf("NewFakeUserspaceEngine: %v", err) - } - lb, err := NewLocalBackend(logf, "logid", store, eng) - if err != nil { - t.Fatalf("NewLocalBackend: %v", err) - } - - lb.SetHTTPTestClient(&http.Client{ - Transport: panicOnUseTransport{}, // validate we don't send HTTP requests - }) - - if err := lb.Start(ipn.Options{ - StateKey: ipn.GlobalDaemonStateKey, - }); err != nil { - t.Fatalf("Start: %v", err) - } - if st := lb.State(); st != ipn.NeedsLogin { - t.Errorf("State = %v; want NeedsLogin", st) - } -} |
