Documentation ¶
Overview ¶
Package ipn implements the interactions between the Tailscale cloud control plane and the local network stack.
IPN is the abbreviated name for a Tailscale network. What's less clear is what it's an abbreviation for: Identified Private Network? IP Network? Internet Private Network? I Privately Network?
Index ¶
- Constants
- Variables
- func ReadMsg(r io.Reader) ([]byte, error)
- func SavePrefs(filename string, p *Prefs)
- func WriteMsg(w io.Writer, b []byte) error
- type Backend
- type BackendClient
- func (bc *BackendClient) FakeExpireAfter(x time.Duration)
- func (bc *BackendClient) GotNotifyMsg(b []byte)
- func (bc *BackendClient) Login(token *oauth2.Token)
- func (bc *BackendClient) Logout()
- func (bc *BackendClient) Quit() error
- func (bc *BackendClient) RequestEngineStatus()
- func (bc *BackendClient) RequestStatus()
- func (bc *BackendClient) SetNotifyCallback(fn func(Notify))
- func (bc *BackendClient) SetPrefs(new *Prefs)
- func (bc *BackendClient) Start(opts Options) error
- func (bc *BackendClient) StartLoginInteractive()
- type BackendServer
- type Command
- type EngineStatus
- type FakeExpireAfterArgs
- type FileStore
- type Handle
- func (h *Handle) AdminPageURL() string
- func (h *Handle) EngineStatus() EngineStatus
- func (h *Handle) Expiry() time.Time
- func (h *Handle) FakeExpireAfter(x time.Duration)
- func (h *Handle) LocalAddrs() []wgcfg.CIDR
- func (h *Handle) Login(token *oauth2.Token)
- func (h *Handle) Logout()
- func (h *Handle) NetMap() *controlclient.NetworkMap
- func (h *Handle) Prefs() *Prefs
- func (h *Handle) RequestEngineStatus()
- func (h *Handle) RequestStatus()
- func (h *Handle) Reset()
- func (h *Handle) Start(opts Options) error
- func (h *Handle) StartLoginInteractive()
- func (h *Handle) State() State
- func (h *Handle) UpdatePrefs(updateFn func(p *Prefs))
- type LocalBackend
- func (b *LocalBackend) FakeExpireAfter(x time.Duration)
- func (b *LocalBackend) Login(token *oauth2.Token)
- func (b *LocalBackend) Logout()
- func (b *LocalBackend) NetMap() *controlclient.NetworkMap
- func (b *LocalBackend) RequestEngineStatus()
- func (b *LocalBackend) RequestStatus()
- func (b *LocalBackend) SetDecompressor(fn func() (controlclient.Decompressor, error))
- func (b *LocalBackend) SetPrefs(new *Prefs)
- func (b *LocalBackend) Shutdown()
- func (b *LocalBackend) Start(opts Options) error
- func (b *LocalBackend) StartLoginInteractive()
- func (b *LocalBackend) State() State
- func (b *LocalBackend) Status() *ipnstate.Status
- func (b *LocalBackend) TestOnlyPublicKeys() (machineKey tailcfg.MachineKey, nodeKey tailcfg.NodeKey)
- func (b *LocalBackend) UpdateStatus(sb *ipnstate.StatusBuilder)
- type MemoryStore
- type NoArgs
- type Notify
- type Options
- type Prefs
- type SetPrefsArgs
- type StartArgs
- type State
- type StateKey
- type StateStore
Constants ¶
const ( NoState = State(iota) NeedsLogin NeedsMachineAuth Stopped Starting Running )
const GoogleIDTokenType = "ts_android_google_login"
GoogleIDToken Type is the oauth2.Token.TokenType for the Google ID tokens used by the Android client.
const MaxMessageSize = 1 << 20
MaxMessageSize is the maximum message size, in bytes.
Variables ¶
var ErrStateNotExist = errors.New("no state with given ID")
ErrStateNotExist is returned by StateStore.ReadState when the requested state ID doesn't exist.
Functions ¶
Types ¶
type Backend ¶
type Backend interface { // Start starts or restarts the backend, typically when a // frontend client connects. Start(Options) error // StartLoginInteractive requests to start a new interactive login // flow. This should trigger a new BrowseToURL notification // eventually. StartLoginInteractive() // Login logs in with an OAuth2 token. Login(token *oauth2.Token) // Logout terminates the current login session and stops the // wireguard engine. Logout() // SetPrefs installs a new set of user preferences, including // WantRunning. This may cause the wireguard engine to // reconfigure or stop. SetPrefs(*Prefs) // RequestEngineStatus polls for an update from the wireguard // engine. Only needed if you want to display byte // counts. Connection events are emitted automatically without // polling. RequestEngineStatus() // RequestStatus requests that a full Status update // notification is sent. RequestStatus() // FakeExpireAfter pretends that 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) }
Backend is the interface between Tailscale frontends (e.g. cmd/tailscale, iOS/MacOS/Windows GUIs) and the tailscale backend (e.g. cmd/tailscaled) running on the same machine. (It has nothing to do with the interface between the backends and the cloud control plane.)
type BackendClient ¶
type BackendClient struct { // AllowVersionSkew controls whether to allow mismatched // frontend & backend versions. AllowVersionSkew bool // contains filtered or unexported fields }
func NewBackendClient ¶
func NewBackendClient(logf logger.Logf, sendCommandMsg func(jsonb []byte)) *BackendClient
func (*BackendClient) FakeExpireAfter ¶
func (bc *BackendClient) FakeExpireAfter(x time.Duration)
func (*BackendClient) GotNotifyMsg ¶
func (bc *BackendClient) GotNotifyMsg(b []byte)
func (*BackendClient) Login ¶ added in v1.0.0
func (bc *BackendClient) Login(token *oauth2.Token)
func (*BackendClient) Logout ¶
func (bc *BackendClient) Logout()
func (*BackendClient) Quit ¶
func (bc *BackendClient) Quit() error
func (*BackendClient) RequestEngineStatus ¶
func (bc *BackendClient) RequestEngineStatus()
func (*BackendClient) RequestStatus ¶ added in v0.98.0
func (bc *BackendClient) RequestStatus()
func (*BackendClient) SetNotifyCallback ¶ added in v0.98.0
func (bc *BackendClient) SetNotifyCallback(fn func(Notify))
func (*BackendClient) SetPrefs ¶
func (bc *BackendClient) SetPrefs(new *Prefs)
func (*BackendClient) Start ¶
func (bc *BackendClient) Start(opts Options) error
func (*BackendClient) StartLoginInteractive ¶
func (bc *BackendClient) StartLoginInteractive()
type BackendServer ¶
type BackendServer struct { GotQuit bool // a Quit command was received // contains filtered or unexported fields }
func NewBackendServer ¶
func NewBackendServer(logf logger.Logf, b Backend, sendNotifyMsg func(b []byte)) *BackendServer
func (*BackendServer) GotCommand ¶
func (bs *BackendServer) GotCommand(cmd *Command) error
func (*BackendServer) GotCommandMsg ¶
func (bs *BackendServer) GotCommandMsg(b []byte) error
GotCommandMsg parses the incoming message b as a JSON Command and calls GotCommand with it.
func (*BackendServer) GotFakeCommand ¶ added in v0.98.1
func (bs *BackendServer) GotFakeCommand(cmd *Command) error
func (*BackendServer) Reset ¶
func (bs *BackendServer) Reset() error
func (*BackendServer) SendErrorMessage ¶ added in v1.0.0
func (bs *BackendServer) SendErrorMessage(msg string)
type Command ¶
type Command struct { // Version is the binary version of the frontend (the client). Version string // AllowVersionSkew controls whether it's permitted for the // client and server to have a different version. The default // (false) means to be strict. AllowVersionSkew bool // Exactly one of the following must be non-nil. Quit *NoArgs Start *StartArgs StartLoginInteractive *NoArgs Login *oauth2.Token Logout *NoArgs SetPrefs *SetPrefsArgs RequestEngineStatus *NoArgs RequestStatus *NoArgs FakeExpireAfter *FakeExpireAfterArgs // contains filtered or unexported fields }
Command is a command message that is JSON encoded and sent by a frontend to a backend.
type EngineStatus ¶
type EngineStatus struct {
RBytes, WBytes wgengine.ByteCount
NumLive int
LiveDERPs int // number of active DERP connections
LivePeers map[tailcfg.NodeKey]wgengine.PeerStatus
}
EngineStatus contains WireGuard engine stats.
type FakeExpireAfterArgs ¶
type FileStore ¶
type FileStore struct {
// contains filtered or unexported fields
}
FileStore is a StateStore that uses a JSON file for persistence.
func NewFileStore ¶
NewFileStore returns a new file store that persists to path.
type Handle ¶
type Handle struct {
// contains filtered or unexported fields
}
func (*Handle) AdminPageURL ¶
func (*Handle) EngineStatus ¶
func (h *Handle) EngineStatus() EngineStatus
func (*Handle) FakeExpireAfter ¶
func (*Handle) LocalAddrs ¶
func (*Handle) NetMap ¶
func (h *Handle) NetMap() *controlclient.NetworkMap
func (*Handle) RequestEngineStatus ¶
func (h *Handle) RequestEngineStatus()
func (*Handle) RequestStatus ¶ added in v0.98.0
func (h *Handle) RequestStatus()
func (*Handle) StartLoginInteractive ¶
func (h *Handle) StartLoginInteractive()
func (*Handle) UpdatePrefs ¶
type LocalBackend ¶
type LocalBackend struct {
// contains filtered or unexported fields
}
LocalBackend is the glue between the major pieces of the Tailscale network software: the cloud control plane (via controlclient), the network data plane (via wgengine), and the user-facing UIs and CLIs (collectively called "frontends", via LocalBackend's implementation of the Backend interface).
LocalBackend implements the overall state machine for the Tailscale application. Frontends, controlclient and wgengine can feed events into LocalBackend to advance the state machine, and advancing the state machine generates events back out to zero or more components.
func NewLocalBackend ¶
func NewLocalBackend(logf logger.Logf, logid string, store StateStore, e wgengine.Engine) (*LocalBackend, error)
NewLocalBackend returns a new LocalBackend that is ready to run, but is not actually running.
func (*LocalBackend) FakeExpireAfter ¶
func (b *LocalBackend) FakeExpireAfter(x time.Duration)
FakeExpireAfter implements Backend.
func (*LocalBackend) Login ¶ added in v1.0.0
func (b *LocalBackend) Login(token *oauth2.Token)
Login implements Backend.
func (*LocalBackend) Logout ¶
func (b *LocalBackend) Logout()
Logout tells the controlclient that we want to log out, and transitions the local engine to the logged-out state without waiting for controlclient to be in that state.
TODO(danderson): controlclient Logout does nothing useful, and we shouldn't be transitioning to a state based on what we believe controlclient may have done.
NOTE(apenwarr): No easy way to persist logged-out status.
Maybe that's for the better; if someone logs out accidentally, rebooting will fix it.
func (*LocalBackend) NetMap ¶
func (b *LocalBackend) NetMap() *controlclient.NetworkMap
NetMap returns the latest cached network map received from controlclient, or nil if no network map was received yet.
func (*LocalBackend) RequestEngineStatus ¶
func (b *LocalBackend) RequestEngineStatus()
RequestEngineStatus implements Backend.
func (*LocalBackend) RequestStatus ¶ added in v0.98.0
func (b *LocalBackend) RequestStatus()
RequestStatus implements Backend.
func (*LocalBackend) SetDecompressor ¶
func (b *LocalBackend) SetDecompressor(fn func() (controlclient.Decompressor, error))
SetDecompressor sets a decompression function, which must be a zstd reader.
This exists because the iOS/Mac NetworkExtension is very resource constrained, and the zstd package is too heavy to fit in the constrained RSS limit.
func (*LocalBackend) SetPrefs ¶
func (b *LocalBackend) SetPrefs(new *Prefs)
SetPrefs saves new user preferences and propagates them throughout the system. Implements Backend.
func (*LocalBackend) Shutdown ¶
func (b *LocalBackend) Shutdown()
Shutdown halts the backend and all its sub-components. The backend can no longer be used after Shutdown returns.
func (*LocalBackend) Start ¶
func (b *LocalBackend) Start(opts Options) error
Start applies the configuration specified in opts, and starts the state machine.
TODO(danderson): this function is trying to do too many things at once: it loads state, or imports it, or updates prefs sometimes, contains some settings that are one-shot things done by `tailscale up` because we had nowhere else to put them, and there's no clear guarantee that switching from one user's state to another is actually a supported operation (it should be, but it's very unclear from the following whether or not that is a safe transition).
func (*LocalBackend) StartLoginInteractive ¶
func (b *LocalBackend) StartLoginInteractive()
StartLoginInteractive implements Backend. It requests a new interactive login from controlclient, unless such a flow is already in progress, in which case StartLoginInteractive attempts to pick up the in-progress flow where it left off.
func (*LocalBackend) State ¶
func (b *LocalBackend) State() State
State returns the backend state machine's current state.
func (*LocalBackend) Status ¶ added in v0.98.0
func (b *LocalBackend) Status() *ipnstate.Status
Status returns the latest status of the backend and its sub-components.
func (*LocalBackend) TestOnlyPublicKeys ¶ added in v0.98.1
func (b *LocalBackend) TestOnlyPublicKeys() (machineKey tailcfg.MachineKey, nodeKey tailcfg.NodeKey)
TestOnlyPublicKeys returns the current machine and node public keys. Used in tests only to facilitate automated node authorization in the test harness.
func (*LocalBackend) UpdateStatus ¶ added in v0.98.0
func (b *LocalBackend) UpdateStatus(sb *ipnstate.StatusBuilder)
UpdateStatus implements ipnstate.StatusUpdater.
type MemoryStore ¶
type MemoryStore struct {
// contains filtered or unexported fields
}
MemoryStore is a store that keeps state in memory only.
func (*MemoryStore) ReadState ¶
func (s *MemoryStore) ReadState(id StateKey) ([]byte, error)
ReadState implements the StateStore interface.
func (*MemoryStore) WriteState ¶
func (s *MemoryStore) WriteState(id StateKey, bs []byte) error
WriteState implements the StateStore interface.
type Notify ¶
type Notify struct { Version string // version number of IPN backend ErrMessage *string // critical error message, if any LoginFinished *empty.Message // event: non-nil when login process succeeded State *State // current IPN state has changed Prefs *Prefs // preferences were changed NetMap *controlclient.NetworkMap // new netmap received Engine *EngineStatus // wireguard engine stats Status *ipnstate.Status // full status BrowseToURL *string // UI should open a browser right now BackendLogID *string // public logtail id used by backend // LocalTCPPort, if non-nil, informs the UI frontend which // (non-zero) localhost TCP port it's listening on. // This is currently only used by Tailscale when run in the // macOS Network Extension. LocalTCPPort *uint16 `json:",omitempty"` // contains filtered or unexported fields }
Notify is a communication from a backend (e.g. tailscaled) to a frontend (cmd/tailscale, iOS, macOS, Win Tasktray). In any given notification, any or all of these may be nil, meaning that they have not changed. They are JSON-encoded on the wire, despite the lack of struct tags.
type Options ¶
type Options struct { // FrontendLogID is the public logtail id used by the frontend. FrontendLogID 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 // AuthKey is an optional node auth key used to authorize a // new node key without user interaction. AuthKey string // LegacyConfigPath optionally specifies the old-style relaynode // relay.conf location. If both LegacyConfigPath and StateKey are // specified and the requested state doesn't exist in the backend // store, the backend migrates the config from LegacyConfigPath. // // TODO(danderson): remove some time after the transition to // tailscaled is done. LegacyConfigPath string // Notify is called when backend events happen. Notify func(Notify) `json:"-"` // HTTPTestClient is an optional HTTP client to pass to controlclient // (for tests only). HTTPTestClient *http.Client }
type Prefs ¶
type Prefs struct { // ControlURL is the URL of the control server to use. ControlURL string // RouteAll specifies whether to accept subnet and default routes // advertised by other nodes on the Tailscale network. RouteAll bool // AllowSingleHosts specifies whether to install routes for each // node IP on the tailscale network, in addition to a route for // the whole network. // // TODO(danderson): why do we have this? It dumps a lot of stuff // into the routing table, and a single network route _should_ be // all that we need. But when I turn this off in my tailscaled, // packets stop flowing. What's up with that? AllowSingleHosts bool // CorpDNS specifies whether to install the Tailscale network's // DNS configuration, if it exists. CorpDNS bool // WantRunning indicates whether networking should be active on // this node. WantRunning bool // ShieldsUp indicates whether to block all incoming connections, // regardless of the control-provided packet filter. If false, we // use the packet filter as provided. If true, we block incoming // connections. ShieldsUp bool // AdvertiseTags specifies groups that this node wants to join, for // purposes of ACL enforcement. These can be referenced from the ACL // security policy. Note that advertising a tag doesn't guarantee that // the control server will allow you to take on the rights for that // tag. AdvertiseTags []string // Hostname is the hostname to use for identifying the node. If // not set, os.Hostname is used. Hostname string // OSVersion overrides tailcfg.Hostinfo's OSVersion. OSVersion string // DeviceModel overrides tailcfg.Hostinfo's DeviceModel. DeviceModel string // NotepadURLs is a debugging setting that opens OAuth URLs in // notepad.exe on Windows, rather than loading them in a browser. // // apenwarr 2020-04-29: Unfortunately this is still needed sometimes. // Windows' default browser setting is sometimes screwy and this helps // users narrow it down a bit. NotepadURLs bool // DisableDERP prevents DERP from being used. DisableDERP bool // AdvertiseRoutes specifies CIDR prefixes to advertise into the // Tailscale network as reachable through the current // node. AdvertiseRoutes []wgcfg.CIDR // NoSNAT specifies whether to source NAT traffic going to // destinations in AdvertiseRoutes. The default is to apply source // NAT, which makes the traffic appear to come from the router // machine rather than the peer's Tailscale IP. // // Disabling SNAT requires additional manual configuration in your // network to route Tailscale traffic back to the subnet relay // machine. // // Linux-only. NoSNAT bool // NetfilterMode specifies how much to manage netfilter rules for // Tailscale, if at all. NetfilterMode router.NetfilterMode // The Persist field is named 'Config' in the file for backward // compatibility with earlier versions. // TODO(apenwarr): We should move this out of here, it's not a pref. // We can maybe do that once we're sure which module should persist // it (backend or frontend?) Persist *controlclient.Persist `json:"Config"` }
Prefs are the user modifiable settings of the Tailscale node agent.
func LoadPrefs ¶
LoadPrefs loads a legacy relaynode config file into Prefs with sensible migration defaults set.
func PrefsFromBytes ¶
PrefsFromBytes deserializes Prefs from a JSON blob. If enforceDefaults is true, Prefs.RouteAll and Prefs.AllowSingleHosts are forced on.
type SetPrefsArgs ¶
type SetPrefsArgs struct {
New *Prefs
}
type StateKey ¶
type StateKey string
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).
type StateStore ¶
type StateStore interface { // ReadState returns the bytes associated with ID. Returns (nil, // ErrStateNotExist) if the ID doesn't have associated state. ReadState(id StateKey) ([]byte, error) // WriteState saves bs as the state associated with ID. WriteState(id StateKey, bs []byte) error }
StateStore persists state, and produces it back on request.
Source Files ¶
Directories ¶
Path | Synopsis |
---|---|
Package ipnstate captures the entire state of the Tailscale network.
|
Package ipnstate captures the entire state of the Tailscale network. |
Package policy contains various policy decisions that need to be shared between the node client & control server.
|
Package policy contains various policy decisions that need to be shared between the node client & control server. |