Documentation ¶
Overview ¶
Package controlclient implements the client for the Tailscale control plane.
It handles authentication, port picking, and collects the local network configuration.
Index ¶
- Constants
- Variables
- func DERPRouteFlag() opt.Bool
- func HashRegisterRequest(version tailcfg.SignatureType, ts time.Time, serverURL string, ...) ([]byte, error)
- func TrimWGConfig() opt.Bool
- type Auto
- func (c *Auto) AuthCantContinue() bool
- func (c *Auto) Direct() *Direct
- func (c *Auto) DoNoiseRequest(req *http.Request) (*http.Response, error)
- func (c *Auto) Expiry() *time.Time
- func (c *Auto) GetSingleUseNoiseRoundTripper(ctx context.Context) (http.RoundTripper, *tailcfg.EarlyNoise, error)
- func (c *Auto) Login(t *tailcfg.Oauth2Token, flags LoginFlags)
- func (c *Auto) Logout(ctx context.Context) error
- func (c *Auto) SetDNS(ctx context.Context, req *tailcfg.SetDNSRequest) error
- func (c *Auto) SetExpirySooner(ctx context.Context, expiry time.Time) error
- func (c *Auto) SetHostinfo(hi *tailcfg.Hostinfo)
- func (c *Auto) SetNetInfo(ni *tailcfg.NetInfo)
- func (c *Auto) SetPaused(paused bool)
- func (c *Auto) SetTKAHead(headHash string)
- func (c *Auto) Shutdown()
- func (c *Auto) Start()
- func (c *Auto) StartLogout()
- func (c *Auto) TestOnlyNodePublicKey() key.NodePublic
- func (c *Auto) TestOnlySetAuthKey(authkey string)
- func (c *Auto) TestOnlyTimeNow() time.Time
- func (c *Auto) UpdateEndpoints(endpoints []tailcfg.Endpoint)
- type Client
- type ControlDialPlanner
- type Decompressor
- type Direct
- func (c *Direct) Close() error
- func (c *Direct) DoNoiseRequest(req *http.Request) (*http.Response, error)
- func (c *Direct) FetchNetMap(ctx context.Context) (*netmap.NetworkMap, error)
- func (c *Direct) GetPersist() persist.Persist
- func (c *Direct) GetSingleUseNoiseRoundTripper(ctx context.Context) (http.RoundTripper, *tailcfg.EarlyNoise, error)
- func (c *Direct) PollNetMap(ctx context.Context, cb func(*netmap.NetworkMap)) error
- func (c *Direct) ReportHealthChange(sys health.Subsystem, sysErr error)
- func (c *Direct) SendLiteMapUpdate(ctx context.Context) error
- func (c *Direct) SetDNS(ctx context.Context, req *tailcfg.SetDNSRequest) (err error)
- func (c *Direct) SetEndpoints(endpoints []tailcfg.Endpoint) (changed bool)
- func (c *Direct) SetExpirySooner(ctx context.Context, expiry time.Time) error
- func (c *Direct) SetHostinfo(hi *tailcfg.Hostinfo) bool
- func (c *Direct) SetNetInfo(ni *tailcfg.NetInfo) bool
- func (c *Direct) SetTKAHead(tkaHead string) bool
- func (c *Direct) TryLogin(ctx context.Context, t *tailcfg.Oauth2Token, flags LoginFlags) (url string, err error)
- func (c *Direct) TryLogout(ctx context.Context) error
- func (c *Direct) WaitLoginURL(ctx context.Context, url string) (newURL string, err error)
- type LoginFlags
- type LoginGoal
- type NoiseClient
- type Options
- type Pinger
- type State
- type Status
- type UserVisibleError
Constants ¶
const ( LoginDefault = LoginFlags(0) LoginInteractive = LoginFlags(1 << iota) // force user login and key refresh LoginEphemeral // set RegisterRequest.Ephemeral )
const ( StateNew = State(iota) StateNotAuthenticated StateAuthenticating StateURLVisitRequired StateAuthenticated StateSynchronized // connected and received map update )
Variables ¶
var DevKnob = initDevKnob()
DevKnob contains temporary internal-only debug knobs. They're unexported to not draw attention to them.
Functions ¶
func DERPRouteFlag ¶
DERPRouteFlag reports the last reported value from control for whether DERP route optimization (Issue 150) should be enabled.
func HashRegisterRequest ¶
func HashRegisterRequest( version tailcfg.SignatureType, ts time.Time, serverURL string, deviceCert []byte, serverPubKey, machinePubKey key.MachinePublic) ([]byte, error)
HashRegisterRequest generates the hash required sign or verify a tailcfg.RegisterRequest.
func TrimWGConfig ¶
TrimWGConfig reports the last reported value from control for whether we should do lazy wireguard configuration.
Types ¶
type Auto ¶
type Auto struct {
// contains filtered or unexported fields
}
Auto connects to a tailcontrol server for a node. It's a concrete implementation of the Client interface.
func NewNoStart ¶
NewNoStart creates a new Auto, but without calling Start on it.
func (*Auto) AuthCantContinue ¶
func (*Auto) DoNoiseRequest ¶
func (*Auto) Expiry ¶
Expiry returns the credential expiration time, or the zero time if the expiration time isn't known. Used in tests only.
func (*Auto) GetSingleUseNoiseRoundTripper ¶
func (c *Auto) GetSingleUseNoiseRoundTripper(ctx context.Context) (http.RoundTripper, *tailcfg.EarlyNoise, error)
GetSingleUseNoiseRoundTripper returns a RoundTripper that can be only be used once (and must be used once) to make a single HTTP request over the noise channel to the coordination server.
In addition to the RoundTripper, it returns the HTTP/2 channel's early noise payload, if any.
func (*Auto) Login ¶
func (c *Auto) Login(t *tailcfg.Oauth2Token, flags LoginFlags)
func (*Auto) SetDNS ¶
SetDNS sends the SetDNSRequest request to the control plane server, requesting a DNS record be created or updated.
func (*Auto) SetExpirySooner ¶
func (*Auto) SetHostinfo ¶
func (*Auto) SetNetInfo ¶
func (*Auto) SetPaused ¶
SetPaused controls whether HTTP activity should be paused.
The client can be paused and unpaused repeatedly, unlike Start and Shutdown, which can only be used once.
func (*Auto) SetTKAHead ¶
SetTKAHead updates the TKA head hash that map-request infrastructure sends.
func (*Auto) Start ¶
func (c *Auto) Start()
Start starts the client's goroutines.
It should only be called for clients created by NewNoStart.
func (*Auto) StartLogout ¶
func (c *Auto) StartLogout()
func (*Auto) TestOnlyNodePublicKey ¶
func (c *Auto) TestOnlyNodePublicKey() key.NodePublic
NodePublicKey returns the node public key currently in use. This is used exclusively in tests.
func (*Auto) TestOnlySetAuthKey ¶
func (*Auto) TestOnlyTimeNow ¶
func (*Auto) UpdateEndpoints ¶
UpdateEndpoints sets the client's discovered endpoints and sends them to the control server if they've changed.
It does not retain the provided slice.
type Client ¶
type Client interface { // Shutdown closes this session, which should not be used any further // afterwards. Shutdown() // Login begins an interactive or non-interactive login process. // Client will eventually call the Status callback with either a // LoginFinished flag (on success) or an auth URL (if further // interaction is needed). Login(*tailcfg.Oauth2Token, LoginFlags) // StartLogout starts an asynchronous logout process. // When it finishes, the Status callback will be called while // AuthCantContinue()==true. StartLogout() // Logout starts a synchronous logout process. It doesn't return // until the logout operation has been completed. Logout(context.Context) error // SetPaused pauses or unpauses the controlclient activity as much // as possible, without losing its internal state, to minimize // unnecessary network activity. // TODO: It might be better to simply shutdown the controlclient and // make a new one when it's time to unpause. SetPaused(bool) // AuthCantContinue returns whether authentication is blocked. If it // is, you either need to visit the auth URL (previously sent in a // Status callback) or call the Login function appropriately. // TODO: this probably belongs in the Status itself instead. AuthCantContinue() bool // SetHostinfo changes the Hostinfo structure that will be sent in // subsequent node registration requests. // TODO: a server-side change would let us simply upload this // in a separate http request. It has nothing to do with the rest of // the state machine. SetHostinfo(*tailcfg.Hostinfo) // SetNetinfo changes the NetIinfo structure that will be sent in // subsequent node registration requests. // TODO: a server-side change would let us simply upload this // in a separate http request. It has nothing to do with the rest of // the state machine. SetNetInfo(*tailcfg.NetInfo) // SetTKAHead changes the TKA head hash value that will be sent in // subsequent netmap requests. SetTKAHead(headHash string) // UpdateEndpoints changes the Endpoint structure that will be sent // in subsequent node registration requests. // TODO: a server-side change would let us simply upload this // in a separate http request. It has nothing to do with the rest of // the state machine. UpdateEndpoints(endpoints []tailcfg.Endpoint) }
Client represents a client connection to the control server. Currently this is done through a pair of polling https requests in the Auto client, but that might change eventually.
type ControlDialPlanner ¶
type ControlDialPlanner interface { // Load returns the current plan for how to connect to control. // // The returned plan can be nil. If so, connections should be made by // resolving the control URL using DNS. Load() *tailcfg.ControlDialPlan // Store updates the dial plan with new directions from the control // server. // // The dial plan can span multiple connections to the control server. // That is, a dial plan received when connected over Wi-Fi is still // valid for a subsequent connection over LTE after a network switch. Store(*tailcfg.ControlDialPlan) }
ControlDialPlanner is the interface optionally supplied when creating a control client to control exactly how TCP connections to the control plane are dialed.
It is usually implemented by an atomic.Pointer.
type Decompressor ¶
type Direct ¶
type Direct struct {
// contains filtered or unexported fields
}
Direct is the client that connects to a tailcontrol server for a node.
func (*Direct) DoNoiseRequest ¶
func (*Direct) FetchNetMap ¶
FetchNetMap fetches the netmap once.
func (*Direct) GetPersist ¶
func (*Direct) GetSingleUseNoiseRoundTripper ¶
func (c *Direct) GetSingleUseNoiseRoundTripper(ctx context.Context) (http.RoundTripper, *tailcfg.EarlyNoise, error)
GetSingleUseNoiseRoundTripper returns a RoundTripper that can be only be used once (and must be used once) to make a single HTTP request over the noise channel to the coordination server.
In addition to the RoundTripper, it returns the HTTP/2 channel's early noise payload, if any.
func (*Direct) PollNetMap ¶
PollNetMap makes a /map request to download the network map, calling cb with each new netmap.
func (*Direct) ReportHealthChange ¶
ReportHealthChange reports to the control plane a change to this node's health.
func (*Direct) SendLiteMapUpdate ¶
SendLiteMapUpdate makes a /map request to update the server of our latest state, but does not fetch anything. It returns an error if the server did not return a successful 200 OK response.
func (*Direct) SetDNS ¶
SetDNS sends the SetDNSRequest request to the control plane server, requesting a DNS record be created or updated.
func (*Direct) SetEndpoints ¶
SetEndpoints updates the list of locally advertised endpoints. It won't be replicated to the server until a *fresh* call to PollNetMap(). You don't need to restart PollNetMap if we return changed==false.
func (*Direct) SetExpirySooner ¶
SetExpirySooner attempts to shorten the expiry to the specified time.
func (*Direct) SetHostinfo ¶
SetHostinfo clones the provided Hostinfo and remembers it for the next update. It reports whether the Hostinfo has changed.
func (*Direct) SetNetInfo ¶
SetNetInfo clones the provided NetInfo and remembers it for the next update. It reports whether the NetInfo has changed.
func (*Direct) SetTKAHead ¶
SetNetInfo stores a new TKA head value for next update. It reports whether the TKA head changed.
func (*Direct) TryLogin ¶
func (c *Direct) TryLogin(ctx context.Context, t *tailcfg.Oauth2Token, flags LoginFlags) (url string, err error)
type LoginFlags ¶
type LoginFlags int
type NoiseClient ¶
type NoiseClient struct { // Client is an HTTP client to talk to the coordination server. // It automatically makes a new Noise connection as needed. // It does not support node key proofs. To do that, call // noiseClient.getConn instead to make a connection. *http.Client // contains filtered or unexported fields }
NoiseClient provides a http.Client to connect to tailcontrol over the ts2021 protocol.
func NewNoiseClient ¶
func NewNoiseClient(privKey key.MachinePrivate, serverPubKey key.MachinePublic, serverURL string, dialer *tsdial.Dialer, dialPlan func() *tailcfg.ControlDialPlan) (*NoiseClient, error)
NewNoiseClient returns a new noiseClient for the provided server and machine key. serverURL is of the form https://<host>:<port> (no trailing slash).
dialPlan may be nil
func (*NoiseClient) Close ¶
func (nc *NoiseClient) Close() error
Close closes all the underlying noise connections. It is a no-op and returns nil if the connection is already closed.
func (*NoiseClient) GetSingleUseRoundTripper ¶
func (nc *NoiseClient) GetSingleUseRoundTripper(ctx context.Context) (http.RoundTripper, *tailcfg.EarlyNoise, error)
GetSingleUseRoundTripper returns a RoundTripper that can be only be used once (and must be used once) to make a single HTTP request over the noise channel to the coordination server.
In addition to the RoundTripper, it returns the HTTP/2 channel's early noise payload, if any.
type Options ¶
type Options struct { Persist persist.Persist // initial persistent data GetMachinePrivateKey func() (key.MachinePrivate, error) // returns the machine key to use ServerURL string // URL of the tailcontrol server AuthKey string // optional node auth key for auto registration TimeNow func() time.Time // time.Now implementation used by Client Hostinfo *tailcfg.Hostinfo // non-nil passes ownership, nil means to use default using os.Hostname, etc DiscoPublicKey key.DiscoPublic NewDecompressor func() (Decompressor, error) KeepAlive bool Logf logger.Logf HTTPTestClient *http.Client // optional HTTP client to use (for tests only) NoiseTestClient *http.Client // optional HTTP client to use for noise RPCs (tests only) DebugFlags []string // debug settings to send to control LinkMonitor *monitor.Mon // optional link monitor PopBrowserURL func(url string) // optional func to open browser Dialer *tsdial.Dialer // non-nil C2NHandler http.Handler // or nil // GetNLPrivateKey specifies an optional function to use // Network Lock. If nil, it's not used. GetNLPrivateKey func() (key.NLPrivate, error) // Status is called when there's a change in status. Status func(Status) // understands Node.Sharer. If false, the Sharer is mapped to the User. KeepSharerAndUserSplit bool // SkipIPForwardingCheck declares that the host's IP // forwarding works and should not be double-checked by the // controlclient package. SkipIPForwardingCheck bool // Pinger optionally specifies the Pinger to use to satisfy // MapResponse.PingRequest queries from the control plane. // If nil, PingRequest queries are not answered. Pinger Pinger // DialPlan contains and stores a previous dial plan that we received // from the control server; if nil, we fall back to using DNS. // // If we receive a new DialPlan from the server, this value will be // updated. DialPlan ControlDialPlanner }
type Pinger ¶
type Pinger interface { // Ping is a request to do a ping with the peer handling the given IP. Ping(ctx context.Context, ip netip.Addr, pingType tailcfg.PingType) (*ipnstate.PingResult, error) }
Pinger is the LocalBackend.Ping method.
type State ¶
type State int
State is the high-level state of the client. It is used only in unit tests for proper sequencing, don't depend on it anywhere else.
TODO(apenwarr): eliminate the state, as it's now obsolete.
apenwarr: Historical note: controlclient.Auto was originally intended to be the state machine for the whole tailscale client, but that turned out to not be the right abstraction layer, and it moved to ipn.Backend. Since ipn.Backend now has a state machine, it would be much better if controlclient could be a simple stateless API. But the current server-side API (two interlocking polling https calls) makes that very hard to implement. A server side API change could untangle this and remove all the statefulness.
func (State) MarshalText ¶
type Status ¶
type Status struct { LoginFinished *empty.Message // nonempty when login finishes LogoutFinished *empty.Message // nonempty when logout finishes Err error URL string // interactive URL to visit to finish logging in NetMap *netmap.NetworkMap // server-pushed configuration // The internal state should not be exposed outside this // package, but we have some automated tests elsewhere that need to // use them. Please don't use these fields. // TODO(apenwarr): Unexport or remove these. State State Persist *persist.Persist // locally persisted configuration // contains filtered or unexported fields }
type UserVisibleError ¶
type UserVisibleError string
UserVisibleError is an error that should be shown to users.
func (UserVisibleError) Error ¶
func (e UserVisibleError) Error() string
func (UserVisibleError) UserVisibleError ¶
func (e UserVisibleError) UserVisibleError() string