diff --git a/cmd/tailscale/cli/up.go b/cmd/tailscale/cli/up.go index a1b9a65fe..409571128 100644 --- a/cmd/tailscale/cli/up.go +++ b/cmd/tailscale/cli/up.go @@ -28,15 +28,6 @@ import ( "tailscale.com/wgengine/router" ) -// globalStateKey is the ipn.StateKey that tailscaled loads on -// startup. -// -// We have to support multiple state keys for other OSes (Windows in -// particular), but right now Unix daemons run with a single -// node-global state. To keep open the option of having per-user state -// later, the global state key doesn't look like a username. -const globalStateKey = "_daemon" - var upCmd = &ffcli.Command{ Name: "up", ShortUsage: "up [flags]", @@ -239,7 +230,7 @@ func runUp(ctx context.Context, args []string) error { bc.SetPrefs(prefs) opts := ipn.Options{ - StateKey: globalStateKey, + StateKey: ipn.GlobalDaemonStateKey, AuthKey: upArgs.authKey, Notify: func(n ipn.Notify) { if n.ErrMessage != nil { diff --git a/ipn/backend.go b/ipn/backend.go index abfd7a778..031e3d830 100644 --- a/ipn/backend.go +++ b/ipn/backend.go @@ -81,14 +81,12 @@ type Notify struct { // shared by several consecutive users. Ideally we would just use the // username of the connected frontend as the StateKey. // -// However, on Windows, there seems to be no safe way to figure out -// the owning user of a process connected over IPC mechanisms -// (sockets, named pipes). So instead, on Windows, we use a -// capability-oriented system where the frontend generates a random -// identifier for itself, and uses that as the StateKey when talking -// to the backend. That way, while we can't identify an OS user by -// name, we can tell two different users apart, because they'll have -// different opaque state keys (and no access to each others's keys). +// Various platforms currently set StateKey in different ways: +// +// * the macOS/iOS GUI apps set it to "ipn-go-bridge" +// * the Android app sets it to "ipn-android" +// * on Windows, it's always the the empty string +// * on Linux/etc, it's always "_daemon" (ipn.GlobalDaemonStateKey) type StateKey string type Options struct { diff --git a/ipn/store.go b/ipn/store.go index 7f6f31a60..66824d773 100644 --- a/ipn/store.go +++ b/ipn/store.go @@ -7,6 +7,7 @@ package ipn import ( "encoding/json" "errors" + "fmt" "io/ioutil" "os" "path/filepath" @@ -19,6 +20,17 @@ import ( // requested state ID doesn't exist. var ErrStateNotExist = errors.New("no state with given ID") +const ( + // GlobalDaemonStateKey is the ipn.StateKey that tailscaled + // loads on startup. + // + // We have to support multiple state keys for other OSes (Windows in + // particular), but right now Unix daemons run with a single + // node-global state. To keep open the option of having per-user state + // later, the global state key doesn't look like a username. + GlobalDaemonStateKey = StateKey("_daemon") +) + // StateStore persists state, and produces it back on request. type StateStore interface { // ReadState returns the bytes associated with ID. Returns (nil, @@ -34,6 +46,8 @@ type MemoryStore struct { cache map[StateKey][]byte } +func (s *MemoryStore) String() string { return "MemoryStore" } + // ReadState implements the StateStore interface. func (s *MemoryStore) ReadState(id StateKey) ([]byte, error) { s.mu.Lock() @@ -67,6 +81,8 @@ type FileStore struct { cache map[StateKey][]byte } +func (s *FileStore) String() string { return fmt.Sprintf("FileStore(%q)", s.path) } + // NewFileStore returns a new file store that persists to path. func NewFileStore(path string) (*FileStore, error) { bs, err := ioutil.ReadFile(path)