tailscale/ipn/handle.go

181 lines
3.1 KiB
Go
Raw Normal View History

// 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 (
"sync"
"time"
"inet.af/netaddr"
"tailscale.com/tailcfg"
"tailscale.com/types/logger"
"tailscale.com/types/netmap"
)
type Handle struct {
b Backend
logf logger.Logf
// Mutex protects everything below
mu sync.Mutex
xnotify func(Notify)
frontendLogID string
netmapCache *netmap.NetworkMap
engineStatusCache EngineStatus
stateCache State
prefsCache *Prefs
}
func NewHandle(b Backend, logf logger.Logf, notify func(Notify), opts Options) (*Handle, error) {
h := &Handle{
b: b,
logf: logf,
}
h.SetNotifyCallback(notify)
err := h.Start(opts)
if err != nil {
return nil, err
}
return h, nil
}
func (h *Handle) SetNotifyCallback(notify func(Notify)) {
h.mu.Lock()
h.xnotify = notify
h.mu.Unlock()
h.b.SetNotifyCallback(h.notify)
}
func (h *Handle) Start(opts Options) error {
h.mu.Lock()
h.frontendLogID = opts.FrontendLogID
h.netmapCache = nil
h.engineStatusCache = EngineStatus{}
h.stateCache = NoState
if opts.Prefs != nil {
h.prefsCache = opts.Prefs.Clone()
}
h.mu.Unlock()
return h.b.Start(opts)
}
func (h *Handle) Reset() {
st := NoState
h.notify(Notify{State: &st})
}
func (h *Handle) notify(n Notify) {
h.mu.Lock()
if n.BackendLogID != nil {
h.logf("Handle: logs: be:%v fe:%v",
*n.BackendLogID, h.frontendLogID)
}
if n.State != nil {
h.stateCache = *n.State
}
if n.Prefs != nil {
h.prefsCache = n.Prefs.Clone()
}
if n.NetMap != nil {
h.netmapCache = n.NetMap
}
if n.Engine != nil {
h.engineStatusCache = *n.Engine
}
h.mu.Unlock()
if h.xnotify != nil {
// Forward onward to our parent's notifier
h.xnotify(n)
}
}
func (h *Handle) Prefs() *Prefs {
h.mu.Lock()
defer h.mu.Unlock()
return h.prefsCache.Clone()
}
func (h *Handle) UpdatePrefs(updateFn func(p *Prefs)) {
h.mu.Lock()
defer h.mu.Unlock()
new := h.prefsCache.Clone()
updateFn(new)
h.prefsCache = new
h.b.SetPrefs(new)
}
func (h *Handle) State() State {
h.mu.Lock()
defer h.mu.Unlock()
return h.stateCache
}
func (h *Handle) EngineStatus() EngineStatus {
h.mu.Lock()
defer h.mu.Unlock()
return h.engineStatusCache
}
func (h *Handle) LocalAddrs() []netaddr.IPPrefix {
h.mu.Lock()
defer h.mu.Unlock()
nm := h.netmapCache
if nm != nil {
return nm.Addresses
}
return []netaddr.IPPrefix{}
}
func (h *Handle) NetMap() *netmap.NetworkMap {
h.mu.Lock()
defer h.mu.Unlock()
return h.netmapCache
}
func (h *Handle) Expiry() time.Time {
h.mu.Lock()
defer h.mu.Unlock()
nm := h.netmapCache
if nm != nil {
return nm.Expiry
}
return time.Time{}
}
func (h *Handle) AdminPageURL() string {
ipn{,/ipnlocal}, cmd/tailscale/cli: don't check pref reverts on initial up The ipn.NewPrefs func returns a populated ipn.Prefs for historical reasons. It's not used or as important as it once was, but it hasn't yet been removed. Meanwhile, it contains some default values that are used on some platforms. Notably, for this bug (#1725), Windows/Mac use its Prefs.RouteAll true value (to accept subnets), but Linux users have always gotten a "false" value for that, because that's what cmd/tailscale's CLI default flag is _for all operating systems_. That meant that "tailscale up" was rightfully reporting that the user was changing an implicit setting: RouteAll was changing from true with false with the user explicitly saying so. An obvious fix might be to change ipn.NewPrefs to return Prefs.RouteAll == false on some platforms, but the logic is complicated by darwin: we want RouteAll true on windows, android, ios, and the GUI mac app, but not the CLI tailscaled-on-macOS mode. But even if we used build tags (e.g. the "redo" build tag) to determine what the default is, that then means we have duplicated and differing "defaults" between both the CLI up flags and ipn.NewPrefs. Furthering that complication didn't seem like a good idea. So, changing the NewPrefs defaults is too invasive at this stage of the release, as is removing the NewPrefs func entirely. Instead, tweak slightly the semantics of the ipn.Prefs.ControlURL field. This now defines that a ControlURL of the empty string means both "we're uninitialized" and also "just use the default". Then, once we have the "empty-string-means-unintialized" semantics, use that to suppress "tailscale up"'s recent implicit-setting-revert checking safety net, if we've never initialized Tailscale yet. And update/add tests. Fixes #1725 Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
2021-04-18 05:50:58 +00:00
return h.prefsCache.ControlURLOrDefault() + "/admin/machines"
}
func (h *Handle) StartLoginInteractive() {
h.b.StartLoginInteractive()
}
func (h *Handle) Login(token *tailcfg.Oauth2Token) {
h.b.Login(token)
}
func (h *Handle) Logout() {
h.b.Logout()
}
func (h *Handle) RequestEngineStatus() {
h.b.RequestEngineStatus()
}
func (h *Handle) FakeExpireAfter(x time.Duration) {
h.b.FakeExpireAfter(x)
}