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 IsLoginServerSynonym(val interface{}) bool
- func IsReadonlyContext(ctx context.Context) bool
- func ReadMsg(r io.Reader) ([]byte, error)
- func ReadonlyContextOf(ctx context.Context) context.Context
- 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 *tailcfg.Oauth2Token)
- func (bc *BackendClient) Logout()
- func (bc *BackendClient) Ping(ip string, useTSMP bool)
- 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() []netaddr.IPPrefix
- func (h *Handle) Login(token *tailcfg.Oauth2Token)
- func (h *Handle) Logout()
- func (h *Handle) NetMap() *netmap.NetworkMap
- func (h *Handle) Prefs() *Prefs
- func (h *Handle) RequestEngineStatus()
- func (h *Handle) Reset()
- func (h *Handle) SetNotifyCallback(notify func(Notify))
- 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 MaskedPrefs
- type MemoryStore
- type NoArgs
- type Notify
- type Options
- type PartialFile
- type PingArgs
- type Prefs
- type SetPrefsArgs
- type StartArgs
- type State
- type StateKey
- type StateStore
Constants ¶
const ( NoState = State(iota) InUseOtherUser NeedsLogin NeedsMachineAuth Stopped Starting Running )
const ( // MachineKeyStateKey is the key under which we store the machine key, // in its wgkey.Private.MarshalText representation. MachineKeyStateKey = StateKey("_machinekey") // 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") // ServerModeStartKey's value, if non-empty, is the value of a // StateKey containing the prefs to start with which to start the // server. // // For example, the value might be "user-1234", meaning the // the server should start with the Prefs JSON loaded from // StateKey "user-1234". ServerModeStartKey = StateKey("server-mode-start-key") )
const DefaultControlURL = "https://controlplane.tailscale.com"
DefaultControlURL is the URL base of the control plane ("coordination server") for use when no explicit one is configured. The default control plane is the hosted version run by Tailscale.com.
const ErrMsgPermissionDenied = "permission denied"
ErrMsgPermissionDenied is the Notify.ErrMessage value used an operation was done from a user/context that didn't have permission.
const GoogleIDTokenType = "ts_android_google_login"
GoogleIDToken Type is the tailcfg.Oauth2Token.TokenType for the Google ID tokens used by the Android client.
const MaxMessageSize = 10 << 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 ¶
func IsLoginServerSynonym ¶ added in v1.12.0
func IsLoginServerSynonym(val interface{}) bool
IsLoginServerSynonym reports whether a URL is a drop-in replacement for the primary Tailscale login server.
func IsReadonlyContext ¶ added in v1.4.0
IsReadonlyContext reports whether ctx is a read-only context, as currently used by Unix non-root users running the "tailscale" CLI command. They can run "status", but not much else.
func ReadMsg ¶
TODO(apenwarr): incremental json decode?
That would let us avoid storing the whole byte array uselessly in RAM.
func ReadonlyContextOf ¶ added in v1.4.0
ReadonlyContextOf returns ctx wrapped with a context value that will make IsReadonlyContext reports true.
Types ¶
type Backend ¶
type Backend interface { // SetNotifyCallback sets the callback to be called on updates // from the backend to the client. SetNotifyCallback(func(Notify)) // 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 *tailcfg.Oauth2Token) // 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() // 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) // Ping attempts to start connecting to the given IP and sends a Notify // with its PingResult. If the host is down, there might never // be a PingResult sent. The cmd/tailscale CLI client adds a timeout. Ping(ip string, useTSMP bool) }
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 *tailcfg.Oauth2Token)
func (*BackendClient) Logout ¶
func (bc *BackendClient) Logout()
func (*BackendClient) Ping ¶ added in v1.2.0
func (bc *BackendClient) Ping(ip string, useTSMP bool)
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(Notify)) *BackendServer
NewBackendServer creates a new BackendServer using b.
If sendNotifyMsg is non-nil, it additionally sets the Backend's notification callback to call the func with ipn.Notify messages in JSON form. If nil, it does not change the notification callback.
func (*BackendServer) GotCommand ¶
func (bs *BackendServer) GotCommand(ctx context.Context, cmd *Command) error
func (*BackendServer) GotCommandMsg ¶
func (bs *BackendServer) GotCommandMsg(ctx context.Context, b []byte) error
GotCommandMsg parses the incoming message b as a JSON Command and calls GotCommand with it.
func (*BackendServer) SendErrorMessage ¶ added in v1.0.0
func (bs *BackendServer) SendErrorMessage(msg string)
func (*BackendServer) SendInUseOtherUserErrorMessage ¶ added in v1.2.1
func (bs *BackendServer) SendInUseOtherUserErrorMessage(msg string)
SendInUseOtherUserErrorMessage sends a Notify message to the client that both sets the state to 'InUseOtherUser' and sets the associated reason to msg.
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 *tailcfg.Oauth2Token Logout *NoArgs SetPrefs *SetPrefsArgs RequestEngineStatus *NoArgs RequestStatus *NoArgs FakeExpireAfter *FakeExpireAfterArgs Ping *PingArgs // 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 int64
NumLive int
LiveDERPs int // number of active DERP connections
LivePeers map[tailcfg.NodeKey]ipnstate.PeerStatusLite
}
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) Login ¶ added in v1.0.0
func (h *Handle) Login(token *tailcfg.Oauth2Token)
func (*Handle) NetMap ¶
func (h *Handle) NetMap() *netmap.NetworkMap
func (*Handle) RequestEngineStatus ¶
func (h *Handle) RequestEngineStatus()
func (*Handle) SetNotifyCallback ¶ added in v1.8.0
func (*Handle) StartLoginInteractive ¶
func (h *Handle) StartLoginInteractive()
func (*Handle) UpdatePrefs ¶
type MaskedPrefs ¶ added in v1.8.0
type MaskedPrefs struct { Prefs ControlURLSet bool `json:",omitempty"` RouteAllSet bool `json:",omitempty"` AllowSingleHostsSet bool `json:",omitempty"` ExitNodeIDSet bool `json:",omitempty"` ExitNodeIPSet bool `json:",omitempty"` ExitNodeAllowLANAccessSet bool `json:",omitempty"` CorpDNSSet bool `json:",omitempty"` WantRunningSet bool `json:",omitempty"` LoggedOutSet bool `json:",omitempty"` ShieldsUpSet bool `json:",omitempty"` AdvertiseTagsSet bool `json:",omitempty"` HostnameSet bool `json:",omitempty"` OSVersionSet bool `json:",omitempty"` DeviceModelSet bool `json:",omitempty"` NotepadURLsSet bool `json:",omitempty"` ForceDaemonSet bool `json:",omitempty"` AdvertiseRoutesSet bool `json:",omitempty"` NoSNATSet bool `json:",omitempty"` NetfilterModeSet bool `json:",omitempty"` OperatorUserSet bool `json:",omitempty"` }
MaskedPrefs is a Prefs with an associated bitmask of which fields are set.
func (*MaskedPrefs) Pretty ¶ added in v1.8.0
func (m *MaskedPrefs) Pretty() string
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) String ¶ added in v1.2.0
func (s *MemoryStore) String() string
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, if non-nil, contains a critical error message. // For State InUseOtherUser, ErrMessage is not critical and just contains the details. ErrMessage *string LoginFinished *empty.Message // non-nil when/if the login process succeeded State *State // if non-nil, the new or current IPN state Prefs *Prefs // if non-nil, the new or current preferences NetMap *netmap.NetworkMap // if non-nil, the new or current netmap Engine *EngineStatus // if non-nil, the new or urrent wireguard stats BrowseToURL *string // if non-nil, UI should open a browser right now BackendLogID *string // if non-nil, the public logtail ID used by backend PingResult *ipnstate.PingResult // if non-nil, a ping response arrived // FilesWaiting if non-nil means that files are buffered in // the Tailscale daemon and ready for local transfer to the // user's preferred storage location. FilesWaiting *empty.Message `json:",omitempty"` // IncomingFiles, if non-nil, specifies which files are in the // process of being received. A nil IncomingFiles means this // Notify should not update the state of file transfers. A non-nil // but empty IncomingFiles means that no files are in the middle // of being transferred. IncomingFiles []PartialFile `json:",omitempty"` // 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, except for the machine key // for migration purposes. // - 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. // // NOTE(apenwarr): The above means that this Prefs field does not do // what you probably think it does. It will overwrite your encryption // keys. Do not use unless you know what you're doing. StateKey StateKey Prefs *Prefs // UpdatePrefs, if provided, overrides Options.Prefs *and* the Prefs // already stored in the backend state, *except* for the Persist // Persist member. If you just want to provide prefs, this is // probably what you want. // // UpdatePrefs.Persist is always ignored. Prefs.Persist will still // be used even if UpdatePrefs is provided. Other than Persist, // UpdatePrefs takes precedence over Prefs. // // This is intended as a purely temporary workaround for the // currently unexpected behaviour of Options.Prefs. // // TODO(apenwarr): Remove this, or rename Prefs to something else // and rename this to Prefs. Or, move Prefs.Persist elsewhere // entirely (as it always should have been), and then we wouldn't // need two separate fields at all. Or, move the fancy state // migration stuff out of Start(). UpdatePrefs *Prefs // AuthKey is an optional node auth key used to authorize a // new node key without user interaction. AuthKey string }
type PartialFile ¶ added in v1.8.0
type PartialFile struct { Name string // e.g. "foo.jpg" Started time.Time // time transfer started DeclaredSize int64 // or -1 if unknown Received int64 // bytes copied thus far // PartialPath is set non-empty in "direct" file mode to the // in-progress '*.partial' file's path when the peerapi isn't // being used; see LocalBackend.SetDirectFileRoot. PartialPath string `json:",omitempty"` // Done is set in "direct" mode when the partial file has been // closed and is ready for the caller to rename away the // ".partial" suffix. Done bool `json:",omitempty"` }
PartialFile represents an in-progress file transfer.
type Prefs ¶
type Prefs struct { // ControlURL is the URL of the control server to use. // // If empty, the default for new installs, DefaultControlURL // is used. It's set non-empty once the daemon has been started // for the first time. // // TODO(apenwarr): Make it safe to update this with SetPrefs(). // Right now, you have to pass it in the initial prefs in Start(), // which is the only code that actually uses the ControlURL value. // It would be more consistent to restart controlclient // automatically whenever this variable changes. // // Meanwhile, you have to provide this as part of Options.Prefs or // Options.UpdatePrefs when calling Backend.Start(). ControlURL string // RouteAll specifies whether to accept subnets advertised by // other nodes on the Tailscale network. Note that this does not // include default routes (0.0.0.0/0 and ::/0), those are // controlled by ExitNodeID/IP below. 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. // This corresponds to the "tailscale up --host-routes" value, // which defaults to true. // // 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 // ExitNodeID and ExitNodeIP specify the node that should be used // as an exit node for internet traffic. At most one of these // should be non-zero. // // The preferred way to express the chosen node is ExitNodeID, but // in some cases it's not possible to use that ID (e.g. in the // linux CLI, before tailscaled has a netmap). For those // situations, we allow specifying the exit node by IP, and // ipnlocal.LocalBackend will translate the IP into an ID when the // node is found in the netmap. // // If the selected exit node doesn't exist (e.g. it's not part of // the current tailnet), or it doesn't offer exit node services, a // blackhole route will be installed on the local system to // prevent any traffic escaping to the local network. ExitNodeID tailcfg.StableNodeID ExitNodeIP netaddr.IP // ExitNodeAllowLANAccess indicates whether locally accessible subnets should be // routed directly or via the exit node. ExitNodeAllowLANAccess 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 // LoggedOut indicates whether the user intends to be logged out. // There are other reasons we may be logged out, including no valid // keys. // We need to remember this state so that, on next startup, we can // generate the "Login" vs "Connect" buttons correctly, without having // to contact the server to confirm our nodekey status first. LoggedOut 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. This overrides tailcfg.Hostinfo's ShieldsUp. 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 // ForceDaemon specifies whether a platform that normally // operates in "client mode" (that is, requires an active user // logged in with the GUI app running) should keep running after the // GUI ends and/or the user logs out. // // The only current applicable platform is Windows. This // forced Windows to go into "server mode" where Tailscale is // running even with no users logged in. This might also be // used for macOS in the future. This setting has no effect // for Linux/etc, which always operate in daemon mode. ForceDaemon bool `json:"ForceDaemon,omitempty"` // AdvertiseRoutes specifies CIDR prefixes to advertise into the // Tailscale network as reachable through the current // node. AdvertiseRoutes []netaddr.IPPrefix // 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 preftype.NetfilterMode // OperatorUser is the local machine user name who is allowed to // operate tailscaled without being root or using sudo. OperatorUser string `json:",omitempty"` // 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 *persist.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.
func (*Prefs) AdminPageURL ¶ added in v1.12.0
AdminPageURL returns the admin web site URL for the current ControlURL.
func (*Prefs) ApplyEdits ¶ added in v1.8.0
func (p *Prefs) ApplyEdits(m *MaskedPrefs)
ApplyEdits mutates p, assigning fields from m.Prefs for each MaskedPrefs Set field that's true.
func (*Prefs) Clone ¶
Clone makes a deep copy of Prefs. The result aliases no memory with the original.
func (*Prefs) ControlURLOrDefault ¶ added in v1.8.0
ControlURLOrDefault returns the coordination server's URL base. If not configured, DefaultControlURL is returned instead.
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.
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 the empty string (in client mode) or, via LocalBackend.userID, a string like "user-$USER_ID" (used in server mode).
- on Linux/etc, it's always "_daemon" (ipn.GlobalDaemonStateKey)
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 localapi contains the HTTP server handlers for tailscaled's API server.
|
Package localapi contains the HTTP server handlers for tailscaled's API server. |
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. |