ipn

package
v0.97.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Mar 17, 2020 License: BSD-3-Clause Imports: 23 Imported by: 91

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

View Source
const (
	NoState = State(iota)
	NeedsLogin
	NeedsMachineAuth
	Stopped
	Starting
	Running
)
View Source
const MaxMessageSize = 1 << 20

MaxMessageSize is the maximum message size, in bytes.

Variables

View Source
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 ReadMsg

func ReadMsg(r io.Reader) ([]byte, error)

TODO(apenwarr): incremental json decode?

That would let us avoid storing the whole byte array uselessly in RAM.

func SavePrefs

func SavePrefs(filename string, p *Prefs)

func WriteMsg

func WriteMsg(w io.Writer, b []byte) error

TODO(apenwarr): incremental json encode?

That would save RAM, at the expense of having to encode once so that
we can produce the initial byte count.

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()
	// 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)
}

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 {
	// 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) Logout

func (bc *BackendClient) Logout()

func (*BackendClient) Quit

func (bc *BackendClient) Quit() error

func (*BackendClient) RequestEngineStatus

func (bc *BackendClient) RequestEngineStatus()

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) Reset

func (bs *BackendServer) Reset() error

type Command

type Command struct {
	Version string

	// Exactly one of the following must be non-nil.
	Quit                  *NoArgs
	Start                 *StartArgs
	StartLoginInteractive *NoArgs
	Logout                *NoArgs
	SetPrefs              *SetPrefsArgs
	RequestEngineStatus   *NoArgs
	FakeExpireAfter       *FakeExpireAfterArgs
}

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
	LivePeers      map[tailcfg.NodeKey]wgengine.PeerStatus
}

EngineStatus contains WireGuard engine stats.

type FakeBackend

type FakeBackend struct {
	// contains filtered or unexported fields
}

func (*FakeBackend) FakeExpireAfter

func (b *FakeBackend) FakeExpireAfter(x time.Duration)

func (*FakeBackend) Logout

func (b *FakeBackend) Logout()

func (*FakeBackend) RequestEngineStatus

func (b *FakeBackend) RequestEngineStatus()

func (*FakeBackend) SetPrefs

func (b *FakeBackend) SetPrefs(new *Prefs)

func (*FakeBackend) Start

func (b *FakeBackend) Start(opts Options) error

func (*FakeBackend) StartLoginInteractive

func (b *FakeBackend) StartLoginInteractive()

type FakeExpireAfterArgs

type FakeExpireAfterArgs struct {
	Duration time.Duration
}

type FileStore

type FileStore struct {
	// contains filtered or unexported fields
}

FileStore is a StateStore that uses a JSON file for persistence.

func NewFileStore

func NewFileStore(path string) (*FileStore, error)

NewFileStore returns a new file store that persists to path.

func (*FileStore) ReadState

func (s *FileStore) ReadState(id StateKey) ([]byte, error)

ReadState implements the StateStore interface.

func (*FileStore) WriteState

func (s *FileStore) WriteState(id StateKey, bs []byte) error

WriteState implements the StateStore interface.

type Handle

type Handle struct {
	// contains filtered or unexported fields
}

func NewHandle

func NewHandle(b Backend, logf logger.Logf, opts Options) (*Handle, error)

func (*Handle) AdminPageURL

func (h *Handle) AdminPageURL() string

func (*Handle) EngineStatus

func (h *Handle) EngineStatus() EngineStatus

func (*Handle) Expiry

func (h *Handle) Expiry() time.Time

func (*Handle) FakeExpireAfter

func (h *Handle) FakeExpireAfter(x time.Duration)

func (*Handle) LocalAddrs

func (h *Handle) LocalAddrs() []wgcfg.CIDR

func (*Handle) Logout

func (h *Handle) Logout()

func (*Handle) NetMap

func (h *Handle) NetMap() *NetworkMap

func (*Handle) Prefs

func (h *Handle) Prefs() *Prefs

func (*Handle) RequestEngineStatus

func (h *Handle) RequestEngineStatus()

func (*Handle) Reset

func (h *Handle) Reset()

func (*Handle) Start

func (h *Handle) Start(opts Options) error

func (*Handle) StartLoginInteractive

func (h *Handle) StartLoginInteractive()

func (*Handle) State

func (h *Handle) State() State

func (*Handle) UpdatePrefs

func (h *Handle) UpdatePrefs(updateFn func(p *Prefs))

type LocalBackend

type LocalBackend struct {
	// contains filtered or unexported fields
}

LocalBackend is the scaffolding between the Tailscale cloud control plane and the local network stack, wiring up NetworkMap updates from the cloud to the local WireGuard engine.

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) AdminPageURL

func (b *LocalBackend) AdminPageURL() string

func (*LocalBackend) EngineStatus

func (b *LocalBackend) EngineStatus() EngineStatus

func (*LocalBackend) Expiry

func (b *LocalBackend) Expiry() time.Time

func (*LocalBackend) FakeExpireAfter

func (b *LocalBackend) FakeExpireAfter(x time.Duration)

func (*LocalBackend) LocalAddrs

func (b *LocalBackend) LocalAddrs() []wgcfg.CIDR

func (*LocalBackend) Logout

func (b *LocalBackend) Logout()

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

Note: return value may be nil, if we haven't received a netmap yet.

func (*LocalBackend) Prefs

func (b *LocalBackend) Prefs() *Prefs

func (*LocalBackend) RequestEngineStatus

func (b *LocalBackend) RequestEngineStatus()

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) SetNetInfo

func (b *LocalBackend) SetNetInfo(ni *tailcfg.NetInfo)

func (*LocalBackend) SetPrefs

func (b *LocalBackend) SetPrefs(new *Prefs)

func (*LocalBackend) Shutdown

func (b *LocalBackend) Shutdown()

func (*LocalBackend) Start

func (b *LocalBackend) Start(opts Options) error

func (*LocalBackend) StartLoginInteractive

func (b *LocalBackend) StartLoginInteractive()

func (*LocalBackend) State

func (b *LocalBackend) State() State

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 NetworkMap

type NetworkMap = controlclient.NetworkMap

type NoArgs

type NoArgs struct{}

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        *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

}

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
	// 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:"-"`
}

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
	// UsePacketFilter indicates whether to enforce centralized ACLs
	// on this node. If false, all traffic in and out of this node is
	// allowed.
	UsePacketFilter bool
	// AdvertiseRoutes specifies CIDR prefixes to advertise into the
	// Tailscale network as reachable through the current node.
	AdvertiseRoutes []wgcfg.CIDR

	// NotepadURLs is a debugging setting that opens OAuth URLs in
	// notepad.exe on Windows, rather than loading them in a browser.
	//
	// TODO(danderson): remove?
	NotepadURLs bool

	// DisableDERP prevents DERP from being used.
	DisableDERP bool

	// 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

func LoadPrefs(filename string, enforceDefaults bool) (*Prefs, error)

LoadLegacyPrefs loads a legacy relaynode config file into Prefs with sensible migration defaults set. If enforceDefaults is true, Prefs.RouteAll and Prefs.AllowSingleHosts are forced on.

func NewPrefs

func NewPrefs() *Prefs

func PrefsFromBytes

func PrefsFromBytes(b []byte, enforceDefaults bool) (*Prefs, error)

PrefsFromBytes deserializes Prefs from a JSON blob. If enforceDefaults is true, Prefs.RouteAll and Prefs.AllowSingleHosts are forced on.

func (*Prefs) Clone

func (p *Prefs) Clone() *Prefs

Clone returns a deep copy of p.

func (*Prefs) Equals

func (p *Prefs) Equals(p2 *Prefs) bool

func (*Prefs) IsEmpty

func (p *Prefs) IsEmpty() bool

IsEmpty reports whether p is nil or pointing to a Prefs zero value.

func (*Prefs) Pretty

func (p *Prefs) Pretty() string

func (*Prefs) ToBytes

func (p *Prefs) ToBytes() []byte

type SetPrefsArgs

type SetPrefsArgs struct {
	New *Prefs
}

type StartArgs

type StartArgs struct {
	Opts Options
}

type State

type State int

func (State) String

func (s State) String() string

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.

Directories

Path Synopsis

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL