2020-02-05 22:16:58 +00:00
|
|
|
// Copyright (c) 2020 Tailscale Inc & AUTHORS All rights reserved.
|
|
|
|
// Use of this source code is governed by a BSD-style
|
|
|
|
// license that can be found in the LICENSE file.
|
|
|
|
|
|
|
|
package ipn
|
|
|
|
|
|
|
|
import (
|
2020-02-03 18:57:34 +00:00
|
|
|
"time"
|
|
|
|
|
2020-02-05 22:16:58 +00:00
|
|
|
"tailscale.com/control/controlclient"
|
|
|
|
"tailscale.com/tailcfg"
|
|
|
|
"tailscale.com/wgengine"
|
|
|
|
)
|
|
|
|
|
|
|
|
type State int
|
|
|
|
|
|
|
|
const (
|
|
|
|
NoState = State(iota)
|
|
|
|
NeedsLogin
|
|
|
|
NeedsMachineAuth
|
|
|
|
Stopped
|
|
|
|
Starting
|
|
|
|
Running
|
|
|
|
)
|
|
|
|
|
|
|
|
func (s State) String() string {
|
|
|
|
return [...]string{"NoState", "NeedsLogin", "NeedsMachineAuth",
|
|
|
|
"Stopped", "Starting", "Running"}[s]
|
|
|
|
}
|
|
|
|
|
|
|
|
type EngineStatus struct {
|
|
|
|
RBytes, WBytes wgengine.ByteCount
|
|
|
|
NumLive int
|
|
|
|
LivePeers map[tailcfg.NodeKey]wgengine.PeerStatus
|
|
|
|
}
|
|
|
|
|
|
|
|
type NetworkMap = controlclient.NetworkMap
|
|
|
|
|
|
|
|
// In any given notification, any or all of these may be nil, meaning
|
|
|
|
// that they have not changed.
|
|
|
|
type Notify struct {
|
|
|
|
Version string // version number of IPN backend
|
|
|
|
ErrMessage *string // critical error message, if any
|
|
|
|
LoginFinished *struct{} // event: login process succeeded
|
|
|
|
State *State // current IPN state has changed
|
|
|
|
Prefs *Prefs // preferences were changed
|
|
|
|
NetMap *NetworkMap // new netmap received
|
|
|
|
Engine *EngineStatus // wireguard engine stats
|
|
|
|
BrowseToURL *string // UI should open a browser right now
|
|
|
|
BackendLogID *string // public logtail id used by backend
|
|
|
|
}
|
|
|
|
|
2020-02-03 18:35:52 +00:00
|
|
|
// StateKey is an opaque identifier for a set of LocalBackend state
|
|
|
|
// (preferences, private keys, etc.).
|
|
|
|
//
|
|
|
|
// The reason we need this is that the Tailscale agent may be running
|
|
|
|
// on a multi-user machine, in a context where a single daemon is
|
|
|
|
// 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).
|
|
|
|
//
|
|
|
|
// It would be much nicer if we could just figure out the OS user that
|
|
|
|
// owns the connected frontend, but here we are.
|
|
|
|
type StateKey string
|
|
|
|
|
2020-02-05 22:16:58 +00:00
|
|
|
type Options struct {
|
2020-02-03 18:35:52 +00:00
|
|
|
// Public logtail id used by frontend.
|
|
|
|
FrontendLogID string
|
|
|
|
// Base URL for the tailcontrol server to talk to.
|
|
|
|
ServerURL string
|
|
|
|
// StateKey and Prefs together define the state the backend should
|
|
|
|
// use:
|
|
|
|
// - StateKey=="" && Prefs!=nil: use Prefs for internal state,
|
|
|
|
// don't persist changes in the backend.
|
|
|
|
// - StateKey!="" && Prefs==nil: load the given backend-side
|
|
|
|
// state and use/update that.
|
|
|
|
// - StateKey!="" && Prefs!=nil: like the previous case, but do
|
|
|
|
// an initial overwrite of backend state with Prefs.
|
|
|
|
StateKey StateKey
|
|
|
|
Prefs *Prefs
|
|
|
|
// Callback for backend events.
|
|
|
|
Notify func(Notify) `json:"-"`
|
2020-02-05 22:16:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
type Backend interface {
|
|
|
|
// Start or restart the backend, because a new Handle has connected.
|
|
|
|
Start(opts Options) error
|
|
|
|
// Start a new interactive login. This should trigger a new
|
|
|
|
// BrowseToURL notification eventually.
|
|
|
|
StartLoginInteractive()
|
|
|
|
// Terminate the current login session and stop the wireguard engine.
|
|
|
|
Logout()
|
|
|
|
// Install a new set of user preferences, including WantRunning.
|
|
|
|
// This may cause the wireguard engine to reconfigure or stop.
|
|
|
|
SetPrefs(new Prefs)
|
|
|
|
// Poll for an update from the wireguard engine. Only needed if
|
|
|
|
// you want to display byte counts. Connection events are emitted
|
|
|
|
// automatically without polling.
|
|
|
|
RequestEngineStatus()
|
|
|
|
// Pretend the current key is going to expire after duration x.
|
|
|
|
// This is useful for testing GUIs to make sure they react properly
|
|
|
|
// with keys that are going to expire.
|
|
|
|
FakeExpireAfter(x time.Duration)
|
|
|
|
}
|