|
|
|
@ -147,7 +147,7 @@ type LocalBackend struct {
|
|
|
|
|
ccAuto *controlclient.Auto // if cc is of type *controlclient.Auto
|
|
|
|
|
stateKey ipn.StateKey // computed in part from user-provided value
|
|
|
|
|
userID string // current controlling user ID (for Windows, primarily)
|
|
|
|
|
prefs *ipn.Prefs
|
|
|
|
|
prefs ipn.PrefsView // may not be Valid.
|
|
|
|
|
inServerMode bool
|
|
|
|
|
machinePrivKey key.MachinePrivate
|
|
|
|
|
nlPrivKey key.NLPrivate
|
|
|
|
@ -496,7 +496,7 @@ func (b *LocalBackend) Shutdown() {
|
|
|
|
|
func (b *LocalBackend) Prefs() *ipn.Prefs {
|
|
|
|
|
b.mu.Lock()
|
|
|
|
|
defer b.mu.Unlock()
|
|
|
|
|
p := b.prefs.Clone()
|
|
|
|
|
p := b.prefs.AsStruct()
|
|
|
|
|
if p != nil && p.Persist != nil {
|
|
|
|
|
p.Persist.LegacyFrontendPrivateMachineKey = key.MachinePrivate{}
|
|
|
|
|
p.Persist.PrivateNodeKey = key.NodePrivate{}
|
|
|
|
@ -559,14 +559,14 @@ func (b *LocalBackend) updateStatus(sb *ipnstate.StatusBuilder, extraLocked func
|
|
|
|
|
s.CurrentTailnet.MagicDNSSuffix = b.netMap.MagicDNSSuffix()
|
|
|
|
|
s.CurrentTailnet.MagicDNSEnabled = b.netMap.DNS.Proxied
|
|
|
|
|
s.CurrentTailnet.Name = b.netMap.Domain
|
|
|
|
|
if b.prefs != nil && !b.prefs.ExitNodeID.IsZero() {
|
|
|
|
|
if exitPeer, ok := b.netMap.PeerWithStableID(b.prefs.ExitNodeID); ok {
|
|
|
|
|
if b.prefs.Valid() && !b.prefs.ExitNodeID().IsZero() {
|
|
|
|
|
if exitPeer, ok := b.netMap.PeerWithStableID(b.prefs.ExitNodeID()); ok {
|
|
|
|
|
var online = false
|
|
|
|
|
if exitPeer.Online != nil {
|
|
|
|
|
online = *exitPeer.Online
|
|
|
|
|
}
|
|
|
|
|
s.ExitNodeStatus = &ipnstate.ExitNodeStatus{
|
|
|
|
|
ID: b.prefs.ExitNodeID,
|
|
|
|
|
ID: b.prefs.ExitNodeID(),
|
|
|
|
|
Online: online,
|
|
|
|
|
TailscaleIPs: exitPeer.Addresses,
|
|
|
|
|
}
|
|
|
|
@ -648,7 +648,7 @@ func (b *LocalBackend) populatePeerStatusLocked(sb *ipnstate.StatusBuilder) {
|
|
|
|
|
LastSeen: lastSeen,
|
|
|
|
|
Online: p.Online != nil && *p.Online,
|
|
|
|
|
ShareeNode: p.Hostinfo.ShareeNode(),
|
|
|
|
|
ExitNode: p.StableID != "" && p.StableID == b.prefs.ExitNodeID,
|
|
|
|
|
ExitNode: p.StableID != "" && p.StableID == b.prefs.ExitNodeID(),
|
|
|
|
|
ExitNodeOption: exitNodeOption,
|
|
|
|
|
SSH_HostKeys: p.Hostinfo.SSH_HostKeys().AsSlice(),
|
|
|
|
|
})
|
|
|
|
@ -777,7 +777,7 @@ func (b *LocalBackend) setClientStatus(st controlclient.Status) {
|
|
|
|
|
b.e.SetNetworkMap(new(netmap.NetworkMap))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
prefs := b.prefs
|
|
|
|
|
prefs := b.prefs.AsStruct()
|
|
|
|
|
stateKey := b.stateKey
|
|
|
|
|
netMap := b.netMap
|
|
|
|
|
interact := b.interact
|
|
|
|
@ -792,9 +792,9 @@ func (b *LocalBackend) setClientStatus(st controlclient.Status) {
|
|
|
|
|
prefsChanged = true
|
|
|
|
|
}
|
|
|
|
|
if st.Persist != nil {
|
|
|
|
|
if !b.prefs.Persist.Equals(st.Persist) {
|
|
|
|
|
if !prefs.Persist.Equals(st.Persist) {
|
|
|
|
|
prefsChanged = true
|
|
|
|
|
b.prefs.Persist = st.Persist.Clone()
|
|
|
|
|
prefs.Persist = st.Persist.Clone()
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if st.NetMap != nil {
|
|
|
|
@ -807,7 +807,7 @@ func (b *LocalBackend) setClientStatus(st controlclient.Status) {
|
|
|
|
|
if !envknob.TKASkipSignatureCheck() {
|
|
|
|
|
b.tkaFilterNetmapLocked(st.NetMap)
|
|
|
|
|
}
|
|
|
|
|
if b.findExitNodeIDLocked(st.NetMap) {
|
|
|
|
|
if findExitNodeIDLocked(prefs, st.NetMap) {
|
|
|
|
|
prefsChanged = true
|
|
|
|
|
}
|
|
|
|
|
b.setNetMapLocked(st.NetMap)
|
|
|
|
@ -820,18 +820,18 @@ func (b *LocalBackend) setClientStatus(st controlclient.Status) {
|
|
|
|
|
// Interactive login finished successfully (URL visited).
|
|
|
|
|
// After an interactive login, the user always wants
|
|
|
|
|
// WantRunning.
|
|
|
|
|
if !b.prefs.WantRunning || b.prefs.LoggedOut {
|
|
|
|
|
if !prefs.WantRunning || prefs.LoggedOut {
|
|
|
|
|
prefsChanged = true
|
|
|
|
|
}
|
|
|
|
|
b.prefs.WantRunning = true
|
|
|
|
|
b.prefs.LoggedOut = false
|
|
|
|
|
prefs.WantRunning = true
|
|
|
|
|
prefs.LoggedOut = false
|
|
|
|
|
}
|
|
|
|
|
// Prefs will be written out; this is not safe unless locked or cloned.
|
|
|
|
|
if prefsChanged {
|
|
|
|
|
prefs = b.prefs.Clone()
|
|
|
|
|
b.prefs = prefs.View()
|
|
|
|
|
}
|
|
|
|
|
if st.NetMap != nil {
|
|
|
|
|
b.updateFilterLocked(st.NetMap, prefs)
|
|
|
|
|
b.updateFilterLocked(st.NetMap, b.prefs)
|
|
|
|
|
}
|
|
|
|
|
b.mu.Unlock()
|
|
|
|
|
|
|
|
|
@ -842,7 +842,7 @@ func (b *LocalBackend) setClientStatus(st controlclient.Status) {
|
|
|
|
|
b.logf("Failed to save new controlclient state: %v", err)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
b.send(ipn.Notify{Prefs: prefs})
|
|
|
|
|
b.send(ipn.Notify{Prefs: prefs.View()})
|
|
|
|
|
}
|
|
|
|
|
if st.NetMap != nil {
|
|
|
|
|
if netMap != nil {
|
|
|
|
@ -874,9 +874,9 @@ func (b *LocalBackend) setClientStatus(st controlclient.Status) {
|
|
|
|
|
b.authReconfig()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// findExitNodeIDLocked updates b.prefs to reference an exit node by ID,
|
|
|
|
|
// rather than by IP. It returns whether prefs was mutated.
|
|
|
|
|
func (b *LocalBackend) findExitNodeIDLocked(nm *netmap.NetworkMap) (prefsChanged bool) {
|
|
|
|
|
// findExitNodeIDLocked updates prefs to reference an exit node by ID, rather
|
|
|
|
|
// than by IP. It returns whether prefs was mutated.
|
|
|
|
|
func findExitNodeIDLocked(prefs *ipn.Prefs, nm *netmap.NetworkMap) (prefsChanged bool) {
|
|
|
|
|
if nm == nil {
|
|
|
|
|
// No netmap, can't resolve anything.
|
|
|
|
|
return false
|
|
|
|
@ -884,30 +884,30 @@ func (b *LocalBackend) findExitNodeIDLocked(nm *netmap.NetworkMap) (prefsChanged
|
|
|
|
|
|
|
|
|
|
// If we have a desired IP on file, try to find the corresponding
|
|
|
|
|
// node.
|
|
|
|
|
if !b.prefs.ExitNodeIP.IsValid() {
|
|
|
|
|
if !prefs.ExitNodeIP.IsValid() {
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// IP takes precedence over ID, so if both are set, clear ID.
|
|
|
|
|
if b.prefs.ExitNodeID != "" {
|
|
|
|
|
b.prefs.ExitNodeID = ""
|
|
|
|
|
if prefs.ExitNodeID != "" {
|
|
|
|
|
prefs.ExitNodeID = ""
|
|
|
|
|
prefsChanged = true
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for _, peer := range nm.Peers {
|
|
|
|
|
for _, addr := range peer.Addresses {
|
|
|
|
|
if !addr.IsSingleIP() || addr.Addr() != b.prefs.ExitNodeIP {
|
|
|
|
|
if !addr.IsSingleIP() || addr.Addr() != prefs.ExitNodeIP {
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
// Found the node being referenced, upgrade prefs to
|
|
|
|
|
// reference it directly for next time.
|
|
|
|
|
b.prefs.ExitNodeID = peer.StableID
|
|
|
|
|
b.prefs.ExitNodeIP = netip.Addr{}
|
|
|
|
|
prefs.ExitNodeID = peer.StableID
|
|
|
|
|
prefs.ExitNodeIP = netip.Addr{}
|
|
|
|
|
return true
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return false
|
|
|
|
|
return prefsChanged
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// setWgengineStatus is the callback by the wireguard engine whenever it posts a new status.
|
|
|
|
@ -1114,8 +1114,8 @@ func (b *LocalBackend) Start(opts ipn.Options) error {
|
|
|
|
|
|
|
|
|
|
if opts.UpdatePrefs != nil {
|
|
|
|
|
newPrefs := opts.UpdatePrefs
|
|
|
|
|
newPrefs.Persist = b.prefs.Persist
|
|
|
|
|
b.prefs = newPrefs
|
|
|
|
|
newPrefs.Persist = b.prefs.Persist()
|
|
|
|
|
b.prefs = newPrefs.View()
|
|
|
|
|
|
|
|
|
|
if opts.StateKey != "" {
|
|
|
|
|
if err := b.store.WriteState(opts.StateKey, b.prefs.ToBytes()); err != nil {
|
|
|
|
@ -1125,7 +1125,7 @@ func (b *LocalBackend) Start(opts ipn.Options) error {
|
|
|
|
|
b.setAtomicValuesFromPrefs(b.prefs)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
wantRunning := b.prefs.WantRunning
|
|
|
|
|
wantRunning := b.prefs.WantRunning()
|
|
|
|
|
if wantRunning {
|
|
|
|
|
if err := b.initMachineKeyLocked(); err != nil {
|
|
|
|
|
return fmt.Errorf("initMachineKeyLocked: %w", err)
|
|
|
|
@ -1135,9 +1135,9 @@ func (b *LocalBackend) Start(opts ipn.Options) error {
|
|
|
|
|
return fmt.Errorf("initNLKeyLocked: %w", err)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
loggedOut := b.prefs.LoggedOut
|
|
|
|
|
loggedOut := b.prefs.LoggedOut()
|
|
|
|
|
|
|
|
|
|
b.inServerMode = b.prefs.ForceDaemon
|
|
|
|
|
b.inServerMode = b.prefs.ForceDaemon()
|
|
|
|
|
b.serverURL = b.prefs.ControlURLOrDefault()
|
|
|
|
|
if b.inServerMode || runtime.GOOS == "windows" {
|
|
|
|
|
b.logf("Start: serverMode=%v", b.inServerMode)
|
|
|
|
@ -1145,8 +1145,8 @@ func (b *LocalBackend) Start(opts ipn.Options) error {
|
|
|
|
|
b.applyPrefsToHostinfo(hostinfo, b.prefs)
|
|
|
|
|
|
|
|
|
|
b.setNetMapLocked(nil)
|
|
|
|
|
persistv := b.prefs.Persist
|
|
|
|
|
b.updateFilterLocked(nil, nil)
|
|
|
|
|
persistv := b.prefs.Persist()
|
|
|
|
|
b.updateFilterLocked(nil, ipn.PrefsView{})
|
|
|
|
|
b.mu.Unlock()
|
|
|
|
|
|
|
|
|
|
if b.portpoll != nil {
|
|
|
|
@ -1230,7 +1230,7 @@ func (b *LocalBackend) Start(opts ipn.Options) error {
|
|
|
|
|
b.e.SetNetInfoCallback(b.setNetInfo)
|
|
|
|
|
|
|
|
|
|
b.mu.Lock()
|
|
|
|
|
prefs := b.prefs.Clone()
|
|
|
|
|
prefs := b.prefs
|
|
|
|
|
b.mu.Unlock()
|
|
|
|
|
|
|
|
|
|
blid := b.backendLogID
|
|
|
|
@ -1252,7 +1252,7 @@ func (b *LocalBackend) Start(opts ipn.Options) error {
|
|
|
|
|
// given netMap and user preferences.
|
|
|
|
|
//
|
|
|
|
|
// b.mu must be held.
|
|
|
|
|
func (b *LocalBackend) updateFilterLocked(netMap *netmap.NetworkMap, prefs *ipn.Prefs) {
|
|
|
|
|
func (b *LocalBackend) updateFilterLocked(netMap *netmap.NetworkMap, prefs ipn.PrefsView) {
|
|
|
|
|
// NOTE(danderson): keep change detection as the first thing in
|
|
|
|
|
// this function. Don't try to optimize by returning early, more
|
|
|
|
|
// likely than not you'll just end up breaking the change
|
|
|
|
@ -1264,7 +1264,7 @@ func (b *LocalBackend) updateFilterLocked(netMap *netmap.NetworkMap, prefs *ipn.
|
|
|
|
|
packetFilter []filter.Match
|
|
|
|
|
localNetsB netipx.IPSetBuilder
|
|
|
|
|
logNetsB netipx.IPSetBuilder
|
|
|
|
|
shieldsUp = prefs == nil || prefs.ShieldsUp // Be conservative when not ready
|
|
|
|
|
shieldsUp = !prefs.Valid() || prefs.ShieldsUp() // Be conservative when not ready
|
|
|
|
|
)
|
|
|
|
|
// Log traffic for Tailscale IPs.
|
|
|
|
|
logNetsB.AddPrefix(tsaddr.CGNATRange())
|
|
|
|
@ -1277,8 +1277,10 @@ func (b *LocalBackend) updateFilterLocked(netMap *netmap.NetworkMap, prefs *ipn.
|
|
|
|
|
}
|
|
|
|
|
packetFilter = netMap.PacketFilter
|
|
|
|
|
}
|
|
|
|
|
if prefs != nil {
|
|
|
|
|
for _, r := range prefs.AdvertiseRoutes {
|
|
|
|
|
if prefs.Valid() {
|
|
|
|
|
ar := prefs.AdvertiseRoutes()
|
|
|
|
|
for i := 0; i < ar.Len(); i++ {
|
|
|
|
|
r := ar.At(i)
|
|
|
|
|
if r.Bits() == 0 {
|
|
|
|
|
// When offering a default route to the world, we
|
|
|
|
|
// filter out locally reachable LANs, so that the
|
|
|
|
@ -1687,8 +1689,8 @@ func (b *LocalBackend) initMachineKeyLocked() (err error) {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var legacyMachineKey key.MachinePrivate
|
|
|
|
|
if b.prefs.Persist != nil {
|
|
|
|
|
legacyMachineKey = b.prefs.Persist.LegacyFrontendPrivateMachineKey
|
|
|
|
|
if b.prefs.Persist() != nil {
|
|
|
|
|
legacyMachineKey = b.prefs.Persist().LegacyFrontendPrivateMachineKey
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
keyText, err := b.store.ReadState(ipn.MachineKeyStateKey)
|
|
|
|
@ -1736,6 +1738,7 @@ func (b *LocalBackend) initMachineKeyLocked() (err error) {
|
|
|
|
|
// initNLKeyLocked is called to initialize b.nlPrivKey.
|
|
|
|
|
//
|
|
|
|
|
// b.prefs must already be initialized.
|
|
|
|
|
//
|
|
|
|
|
// b.stateKey should be set too, but just for nicer log messages.
|
|
|
|
|
// b.mu must be held.
|
|
|
|
|
func (b *LocalBackend) initNLKeyLocked() (err error) {
|
|
|
|
@ -1776,12 +1779,12 @@ func (b *LocalBackend) initNLKeyLocked() (err error) {
|
|
|
|
|
// user and prefs. If userID is blank or prefs is blank, no work is done.
|
|
|
|
|
//
|
|
|
|
|
// b.mu may either be held or not.
|
|
|
|
|
func (b *LocalBackend) writeServerModeStartState(userID string, prefs *ipn.Prefs) {
|
|
|
|
|
if userID == "" || prefs == nil {
|
|
|
|
|
func (b *LocalBackend) writeServerModeStartState(userID string, prefs ipn.PrefsView) {
|
|
|
|
|
if userID == "" || !prefs.Valid() {
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if prefs.ForceDaemon {
|
|
|
|
|
if prefs.ForceDaemon() {
|
|
|
|
|
stateKey := ipn.StateKey("user-" + userID)
|
|
|
|
|
if err := b.store.WriteState(ipn.ServerModeStartKey, []byte(stateKey)); err != nil {
|
|
|
|
|
b.logf("WriteState error: %v", err)
|
|
|
|
@ -1826,7 +1829,7 @@ func (b *LocalBackend) loadStateLocked(key ipn.StateKey, prefs *ipn.Prefs) (err
|
|
|
|
|
// optional/legacy machine key then it's used as the
|
|
|
|
|
// value instead of making up a new one.
|
|
|
|
|
b.logf("using frontend prefs: %s", prefs.Pretty())
|
|
|
|
|
b.prefs = prefs.Clone()
|
|
|
|
|
b.prefs = prefs.Clone().View()
|
|
|
|
|
b.writeServerModeStartState(b.userID, b.prefs)
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
@ -1843,14 +1846,15 @@ func (b *LocalBackend) loadStateLocked(key ipn.StateKey, prefs *ipn.Prefs) (err
|
|
|
|
|
bs, err := b.store.ReadState(key)
|
|
|
|
|
switch {
|
|
|
|
|
case errors.Is(err, ipn.ErrStateNotExist):
|
|
|
|
|
b.prefs = ipn.NewPrefs()
|
|
|
|
|
b.prefs.WantRunning = false
|
|
|
|
|
b.logf("using backend prefs; created empty state for %q: %s", key, b.prefs.Pretty())
|
|
|
|
|
prefs := ipn.NewPrefs()
|
|
|
|
|
prefs.WantRunning = false
|
|
|
|
|
b.logf("using backend prefs; created empty state for %q: %s", key, prefs.Pretty())
|
|
|
|
|
b.prefs = prefs.View()
|
|
|
|
|
return nil
|
|
|
|
|
case err != nil:
|
|
|
|
|
return fmt.Errorf("backend prefs: store.ReadState(%q): %v", key, err)
|
|
|
|
|
}
|
|
|
|
|
b.prefs, err = ipn.PrefsFromBytes(bs)
|
|
|
|
|
prefs, err = ipn.PrefsFromBytes(bs)
|
|
|
|
|
if err != nil {
|
|
|
|
|
b.logf("using backend prefs for %q", key)
|
|
|
|
|
return fmt.Errorf("PrefsFromBytes: %v", err)
|
|
|
|
@ -1862,13 +1866,14 @@ func (b *LocalBackend) loadStateLocked(key ipn.StateKey, prefs *ipn.Prefs) (err
|
|
|
|
|
// This makes sure that mobile clients go through the new
|
|
|
|
|
// frontends where we're (2021-10-02) doing battery
|
|
|
|
|
// optimization work ahead of turning down the old backends.
|
|
|
|
|
if b.prefs != nil && b.prefs.ControlURL != "" &&
|
|
|
|
|
b.prefs.ControlURL != ipn.DefaultControlURL &&
|
|
|
|
|
ipn.IsLoginServerSynonym(b.prefs.ControlURL) {
|
|
|
|
|
b.prefs.ControlURL = ""
|
|
|
|
|
if prefs != nil && prefs.ControlURL != "" &&
|
|
|
|
|
prefs.ControlURL != ipn.DefaultControlURL &&
|
|
|
|
|
ipn.IsLoginServerSynonym(prefs.ControlURL) {
|
|
|
|
|
prefs.ControlURL = ""
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
b.logf("using backend prefs for %q: %s", key, b.prefs.Pretty())
|
|
|
|
|
b.logf("using backend prefs for %q: %s", key, prefs.Pretty())
|
|
|
|
|
b.prefs = prefs.View()
|
|
|
|
|
|
|
|
|
|
b.setAtomicValuesFromPrefs(b.prefs)
|
|
|
|
|
|
|
|
|
@ -1877,13 +1882,13 @@ func (b *LocalBackend) loadStateLocked(key ipn.StateKey, prefs *ipn.Prefs) (err
|
|
|
|
|
|
|
|
|
|
// setAtomicValuesFromPrefs populates sshAtomicBool and containsViaIPFuncAtomic
|
|
|
|
|
// from the prefs p, which may be nil.
|
|
|
|
|
func (b *LocalBackend) setAtomicValuesFromPrefs(p *ipn.Prefs) {
|
|
|
|
|
b.sshAtomicBool.Store(p != nil && p.RunSSH && envknob.CanSSHD())
|
|
|
|
|
func (b *LocalBackend) setAtomicValuesFromPrefs(p ipn.PrefsView) {
|
|
|
|
|
b.sshAtomicBool.Store(p.Valid() && p.RunSSH() && envknob.CanSSHD())
|
|
|
|
|
|
|
|
|
|
if p == nil {
|
|
|
|
|
if !p.Valid() {
|
|
|
|
|
b.containsViaIPFuncAtomic.Store(tsaddr.NewContainsIPFunc(nil))
|
|
|
|
|
} else {
|
|
|
|
|
b.containsViaIPFuncAtomic.Store(tsaddr.NewContainsIPFunc(tsaddr.FilterPrefixesCopy(p.AdvertiseRoutes, tsaddr.IsViaPrefix)))
|
|
|
|
|
b.containsViaIPFuncAtomic.Store(tsaddr.NewContainsIPFunc(p.AdvertiseRoutes().Filter(tsaddr.IsViaPrefix)))
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -2039,10 +2044,10 @@ func (b *LocalBackend) shouldUploadServices() bool {
|
|
|
|
|
b.mu.Lock()
|
|
|
|
|
defer b.mu.Unlock()
|
|
|
|
|
|
|
|
|
|
if b.prefs == nil || b.netMap == nil {
|
|
|
|
|
if !b.prefs.Valid() || b.netMap == nil {
|
|
|
|
|
return false // default to safest setting
|
|
|
|
|
}
|
|
|
|
|
return !b.prefs.ShieldsUp && b.netMap.CollectServices
|
|
|
|
|
return !b.prefs.ShieldsUp() && b.netMap.CollectServices
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (b *LocalBackend) SetCurrentUserID(uid string) {
|
|
|
|
@ -2111,7 +2116,7 @@ func (b *LocalBackend) checkSSHPrefsLocked(p *ipn.Prefs) error {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (b *LocalBackend) sshOnButUnusableHealthCheckMessageLocked() (healthMessage string) {
|
|
|
|
|
if b.prefs == nil || !b.prefs.RunSSH {
|
|
|
|
|
if !b.prefs.Valid() || !b.prefs.RunSSH() {
|
|
|
|
|
return ""
|
|
|
|
|
}
|
|
|
|
|
if envknob.SSHIgnoreTailnetPolicy() || envknob.SSHPolicyFile() != "" {
|
|
|
|
@ -2137,35 +2142,35 @@ func (b *LocalBackend) sshOnButUnusableHealthCheckMessageLocked() (healthMessage
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (b *LocalBackend) isDefaultServerLocked() bool {
|
|
|
|
|
if b.prefs == nil {
|
|
|
|
|
if !b.prefs.Valid() {
|
|
|
|
|
return true // assume true until set otherwise
|
|
|
|
|
}
|
|
|
|
|
return b.prefs.ControlURLOrDefault() == ipn.DefaultControlURL
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (b *LocalBackend) EditPrefs(mp *ipn.MaskedPrefs) (*ipn.Prefs, error) {
|
|
|
|
|
func (b *LocalBackend) EditPrefs(mp *ipn.MaskedPrefs) (ipn.PrefsView, error) {
|
|
|
|
|
b.mu.Lock()
|
|
|
|
|
if mp.EggSet {
|
|
|
|
|
mp.EggSet = false
|
|
|
|
|
b.egg = true
|
|
|
|
|
go b.doSetHostinfoFilterServices(b.hostinfo.Clone())
|
|
|
|
|
}
|
|
|
|
|
p0 := b.prefs.Clone()
|
|
|
|
|
p1 := b.prefs.Clone()
|
|
|
|
|
p0 := b.prefs
|
|
|
|
|
p1 := b.prefs.AsStruct()
|
|
|
|
|
p1.ApplyEdits(mp)
|
|
|
|
|
if err := b.checkPrefsLocked(p1); err != nil {
|
|
|
|
|
b.mu.Unlock()
|
|
|
|
|
b.logf("EditPrefs check error: %v", err)
|
|
|
|
|
return nil, err
|
|
|
|
|
return ipn.PrefsView{}, err
|
|
|
|
|
}
|
|
|
|
|
if p1.RunSSH && !envknob.CanSSHD() {
|
|
|
|
|
b.mu.Unlock()
|
|
|
|
|
b.logf("EditPrefs requests SSH, but disabled by envknob; returning error")
|
|
|
|
|
return nil, errors.New("Tailscale SSH server administratively disabled.")
|
|
|
|
|
return ipn.PrefsView{}, errors.New("Tailscale SSH server administratively disabled.")
|
|
|
|
|
}
|
|
|
|
|
if p1.Equals(p0) {
|
|
|
|
|
if p1.View().Equals(p0) {
|
|
|
|
|
b.mu.Unlock()
|
|
|
|
|
return p1, nil
|
|
|
|
|
return p1.View(), nil
|
|
|
|
|
}
|
|
|
|
|
b.logf("EditPrefs: %v", mp.Pretty())
|
|
|
|
|
b.setPrefsLockedOnEntry("EditPrefs", p1) // does a b.mu.Unlock
|
|
|
|
@ -2173,7 +2178,7 @@ func (b *LocalBackend) EditPrefs(mp *ipn.MaskedPrefs) (*ipn.Prefs, error) {
|
|
|
|
|
// Note: don't perform any actions for the new prefs here. Not
|
|
|
|
|
// every prefs change goes through EditPrefs. Put your actions
|
|
|
|
|
// in setPrefsLocksOnEntry instead.
|
|
|
|
|
return p1, nil
|
|
|
|
|
return p1.View(), nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// SetPrefs saves new user preferences and propagates them throughout
|
|
|
|
@ -2191,23 +2196,22 @@ func (b *LocalBackend) SetPrefs(newp *ipn.Prefs) {
|
|
|
|
|
func (b *LocalBackend) setPrefsLockedOnEntry(caller string, newp *ipn.Prefs) {
|
|
|
|
|
netMap := b.netMap
|
|
|
|
|
stateKey := b.stateKey
|
|
|
|
|
|
|
|
|
|
b.setAtomicValuesFromPrefs(newp)
|
|
|
|
|
|
|
|
|
|
oldp := b.prefs
|
|
|
|
|
newp.Persist = oldp.Persist // caller isn't allowed to override this
|
|
|
|
|
b.prefs = newp
|
|
|
|
|
newp.Persist = oldp.Persist() // caller isn't allowed to override this
|
|
|
|
|
|
|
|
|
|
// findExitNodeIDLocked returns whether it updated b.prefs, but
|
|
|
|
|
// everything in this function treats b.prefs as completely new
|
|
|
|
|
// anyway. No-op if no exit node resolution is needed.
|
|
|
|
|
b.findExitNodeIDLocked(netMap)
|
|
|
|
|
b.inServerMode = newp.ForceDaemon
|
|
|
|
|
findExitNodeIDLocked(newp, netMap)
|
|
|
|
|
b.prefs = newp.View()
|
|
|
|
|
|
|
|
|
|
b.setAtomicValuesFromPrefs(b.prefs)
|
|
|
|
|
b.inServerMode = b.prefs.ForceDaemon()
|
|
|
|
|
// We do this to avoid holding the lock while doing everything else.
|
|
|
|
|
newp = b.prefs.Clone()
|
|
|
|
|
|
|
|
|
|
oldHi := b.hostinfo
|
|
|
|
|
newHi := oldHi.Clone()
|
|
|
|
|
b.applyPrefsToHostinfo(newHi, newp)
|
|
|
|
|
b.applyPrefsToHostinfo(newHi, b.prefs)
|
|
|
|
|
b.hostinfo = newHi
|
|
|
|
|
hostInfoChanged := !oldHi.Equal(newHi)
|
|
|
|
|
userID := b.userID
|
|
|
|
@ -2215,41 +2219,42 @@ func (b *LocalBackend) setPrefsLockedOnEntry(caller string, newp *ipn.Prefs) {
|
|
|
|
|
|
|
|
|
|
// [GRINDER STATS LINE] - please don't remove (used for log parsing)
|
|
|
|
|
if caller == "SetPrefs" {
|
|
|
|
|
b.logf("SetPrefs: %v", newp.Pretty())
|
|
|
|
|
b.logf("SetPrefs: %v", b.prefs.Pretty())
|
|
|
|
|
}
|
|
|
|
|
b.updateFilterLocked(netMap, newp)
|
|
|
|
|
b.updateFilterLocked(netMap, b.prefs)
|
|
|
|
|
|
|
|
|
|
if oldp.ShouldSSHBeRunning() && !newp.ShouldSSHBeRunning() {
|
|
|
|
|
if oldp.ShouldSSHBeRunning() && !b.prefs.ShouldSSHBeRunning() {
|
|
|
|
|
if b.sshServer != nil {
|
|
|
|
|
go b.sshServer.Shutdown()
|
|
|
|
|
b.sshServer = nil
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
prefs := b.prefs // We can grab the view before unlocking. It can't be mutated.
|
|
|
|
|
b.mu.Unlock()
|
|
|
|
|
|
|
|
|
|
if stateKey != "" {
|
|
|
|
|
if err := b.store.WriteState(stateKey, newp.ToBytes()); err != nil {
|
|
|
|
|
if err := b.store.WriteState(stateKey, prefs.ToBytes()); err != nil {
|
|
|
|
|
b.logf("failed to save new controlclient state: %v", err)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
b.writeServerModeStartState(userID, newp)
|
|
|
|
|
b.writeServerModeStartState(userID, prefs)
|
|
|
|
|
|
|
|
|
|
if netMap != nil {
|
|
|
|
|
if login := netMap.UserProfiles[netMap.User].LoginName; login != "" {
|
|
|
|
|
if newp.Persist == nil {
|
|
|
|
|
if prefs.Persist() == nil {
|
|
|
|
|
b.logf("active login: %s", login)
|
|
|
|
|
} else if newp.Persist.LoginName != login {
|
|
|
|
|
} else if prefs.Persist().LoginName != login {
|
|
|
|
|
// Corp issue 461: sometimes the wrong prefs are
|
|
|
|
|
// logged; the frontend isn't always getting
|
|
|
|
|
// notified (to update its prefs/persist) on
|
|
|
|
|
// account switch. Log this while we figure it
|
|
|
|
|
// out.
|
|
|
|
|
b.logf("active login: %q ([unexpected] corp#461, not %q)", newp.Persist.LoginName, login)
|
|
|
|
|
b.logf("active login: %q ([unexpected] corp#461, not %q)", prefs.Persist().LoginName, login)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if oldp.ShieldsUp != newp.ShieldsUp || hostInfoChanged {
|
|
|
|
|
if oldp.ShieldsUp() != prefs.ShieldsUp() || hostInfoChanged {
|
|
|
|
|
b.doSetHostinfoFilterServices(newHi)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -2257,18 +2262,18 @@ func (b *LocalBackend) setPrefsLockedOnEntry(caller string, newp *ipn.Prefs) {
|
|
|
|
|
b.e.SetDERPMap(netMap.DERPMap)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if !oldp.WantRunning && newp.WantRunning {
|
|
|
|
|
if !oldp.WantRunning() && prefs.WantRunning() {
|
|
|
|
|
b.logf("transitioning to running; doing Login...")
|
|
|
|
|
cc.Login(nil, controlclient.LoginDefault)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if oldp.WantRunning != newp.WantRunning {
|
|
|
|
|
if oldp.WantRunning() != prefs.WantRunning() {
|
|
|
|
|
b.stateMachine()
|
|
|
|
|
} else {
|
|
|
|
|
b.authReconfig()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
b.send(ipn.Notify{Prefs: newp})
|
|
|
|
|
b.send(ipn.Notify{Prefs: prefs})
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// GetPeerAPIPort returns the port number for the peerapi server
|
|
|
|
@ -2409,16 +2414,16 @@ func (b *LocalBackend) authReconfig() {
|
|
|
|
|
b.logf("[v1] authReconfig: netmap not yet valid. Skipping.")
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
if !prefs.WantRunning {
|
|
|
|
|
if !prefs.WantRunning() {
|
|
|
|
|
b.logf("[v1] authReconfig: skipping because !WantRunning.")
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var flags netmap.WGConfigFlags
|
|
|
|
|
if prefs.RouteAll {
|
|
|
|
|
if prefs.RouteAll() {
|
|
|
|
|
flags |= netmap.AllowSubnetRoutes
|
|
|
|
|
}
|
|
|
|
|
if prefs.AllowSingleHosts {
|
|
|
|
|
if prefs.AllowSingleHosts() {
|
|
|
|
|
flags |= netmap.AllowSingleHosts
|
|
|
|
|
}
|
|
|
|
|
if hasPAC && disableSubnetsIfPAC {
|
|
|
|
@ -2431,13 +2436,13 @@ func (b *LocalBackend) authReconfig() {
|
|
|
|
|
// Keep the dialer updated about whether we're supposed to use
|
|
|
|
|
// an exit node's DNS server (so SOCKS5/HTTP outgoing dials
|
|
|
|
|
// can use it for name resolution)
|
|
|
|
|
if dohURL, ok := exitNodeCanProxyDNS(nm, prefs.ExitNodeID); ok {
|
|
|
|
|
if dohURL, ok := exitNodeCanProxyDNS(nm, prefs.ExitNodeID()); ok {
|
|
|
|
|
b.dialer.SetExitDNSDoH(dohURL)
|
|
|
|
|
} else {
|
|
|
|
|
b.dialer.SetExitDNSDoH("")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
cfg, err := nmcfg.WGCfg(nm, b.logf, flags, prefs.ExitNodeID)
|
|
|
|
|
cfg, err := nmcfg.WGCfg(nm, b.logf, flags, prefs.ExitNodeID())
|
|
|
|
|
if err != nil {
|
|
|
|
|
b.logf("wgcfg: %v", err)
|
|
|
|
|
return
|
|
|
|
@ -2493,7 +2498,7 @@ func shouldUseOneCGNATRoute(nm *netmap.NetworkMap, logf logger.Logf, versionOS s
|
|
|
|
|
//
|
|
|
|
|
// The versionOS is a Tailscale-style version ("iOS", "macOS") and not
|
|
|
|
|
// a runtime.GOOS.
|
|
|
|
|
func dnsConfigForNetmap(nm *netmap.NetworkMap, prefs *ipn.Prefs, logf logger.Logf, versionOS string) *dns.Config {
|
|
|
|
|
func dnsConfigForNetmap(nm *netmap.NetworkMap, prefs ipn.PrefsView, logf logger.Logf, versionOS string) *dns.Config {
|
|
|
|
|
dcfg := &dns.Config{
|
|
|
|
|
Routes: map[dnsname.FQDN][]*dnstype.Resolver{},
|
|
|
|
|
Hosts: map[dnsname.FQDN][]netip.Addr{},
|
|
|
|
@ -2565,7 +2570,7 @@ func dnsConfigForNetmap(nm *netmap.NetworkMap, prefs *ipn.Prefs, logf logger.Log
|
|
|
|
|
dcfg.Hosts[fqdn] = append(dcfg.Hosts[fqdn], ip)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if !prefs.CorpDNS {
|
|
|
|
|
if !prefs.CorpDNS() {
|
|
|
|
|
return dcfg
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -2590,7 +2595,7 @@ func dnsConfigForNetmap(nm *netmap.NetworkMap, prefs *ipn.Prefs, logf logger.Log
|
|
|
|
|
|
|
|
|
|
// If we're using an exit node and that exit node is new enough (1.19.x+)
|
|
|
|
|
// to run a DoH DNS proxy, then send all our DNS traffic through it.
|
|
|
|
|
if dohURL, ok := exitNodeCanProxyDNS(nm, prefs.ExitNodeID); ok {
|
|
|
|
|
if dohURL, ok := exitNodeCanProxyDNS(nm, prefs.ExitNodeID()); ok {
|
|
|
|
|
addDefault([]*dnstype.Resolver{{Addr: dohURL}})
|
|
|
|
|
return dcfg
|
|
|
|
|
}
|
|
|
|
@ -2624,7 +2629,7 @@ func dnsConfigForNetmap(nm *netmap.NetworkMap, prefs *ipn.Prefs, logf logger.Log
|
|
|
|
|
switch {
|
|
|
|
|
case len(dcfg.DefaultResolvers) != 0:
|
|
|
|
|
// Default resolvers already set.
|
|
|
|
|
case !prefs.ExitNodeID.IsZero():
|
|
|
|
|
case !prefs.ExitNodeID().IsZero():
|
|
|
|
|
// When using exit nodes, it's very likely the LAN
|
|
|
|
|
// resolvers will become unreachable. So, force use of the
|
|
|
|
|
// fallback resolvers until we implement DNS forwarding to
|
|
|
|
@ -2890,16 +2895,16 @@ func ipPrefixLess(ri, rj netip.Prefix) bool {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// routerConfig produces a router.Config from a wireguard config and IPN prefs.
|
|
|
|
|
func (b *LocalBackend) routerConfig(cfg *wgcfg.Config, prefs *ipn.Prefs, oneCGNATRoute bool) *router.Config {
|
|
|
|
|
func (b *LocalBackend) routerConfig(cfg *wgcfg.Config, prefs ipn.PrefsView, oneCGNATRoute bool) *router.Config {
|
|
|
|
|
singleRouteThreshold := 10_000
|
|
|
|
|
if oneCGNATRoute {
|
|
|
|
|
singleRouteThreshold = 1
|
|
|
|
|
}
|
|
|
|
|
rs := &router.Config{
|
|
|
|
|
LocalAddrs: unmapIPPrefixes(cfg.Addresses),
|
|
|
|
|
SubnetRoutes: unmapIPPrefixes(prefs.AdvertiseRoutes),
|
|
|
|
|
SNATSubnetRoutes: !prefs.NoSNAT,
|
|
|
|
|
NetfilterMode: prefs.NetfilterMode,
|
|
|
|
|
SubnetRoutes: unmapIPPrefixes(prefs.AdvertiseRoutes().AsSlice()),
|
|
|
|
|
SNATSubnetRoutes: !prefs.NoSNAT(),
|
|
|
|
|
NetfilterMode: prefs.NetfilterMode(),
|
|
|
|
|
Routes: peerRoutes(cfg.Peers, singleRouteThreshold),
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -2914,7 +2919,7 @@ func (b *LocalBackend) routerConfig(cfg *wgcfg.Config, prefs *ipn.Prefs, oneCGNA
|
|
|
|
|
// likely to break some functionality, but if the user expressed a
|
|
|
|
|
// preference for routing remotely, we want to avoid leaking
|
|
|
|
|
// traffic at the expense of functionality.
|
|
|
|
|
if prefs.ExitNodeID != "" || prefs.ExitNodeIP.IsValid() {
|
|
|
|
|
if prefs.ExitNodeID() != "" || prefs.ExitNodeIP().IsValid() {
|
|
|
|
|
var default4, default6 bool
|
|
|
|
|
for _, route := range rs.Routes {
|
|
|
|
|
switch route {
|
|
|
|
@ -2939,7 +2944,7 @@ func (b *LocalBackend) routerConfig(cfg *wgcfg.Config, prefs *ipn.Prefs, oneCGNA
|
|
|
|
|
}
|
|
|
|
|
if runtime.GOOS == "linux" || runtime.GOOS == "darwin" || runtime.GOOS == "windows" {
|
|
|
|
|
rs.LocalRoutes = internalIPs // unconditionally allow access to guest VM networks
|
|
|
|
|
if prefs.ExitNodeAllowLANAccess {
|
|
|
|
|
if prefs.ExitNodeAllowLANAccess() {
|
|
|
|
|
rs.LocalRoutes = append(rs.LocalRoutes, externalIPs...)
|
|
|
|
|
} else {
|
|
|
|
|
// Explicitly add routes to the local network so that we do not
|
|
|
|
@ -2971,16 +2976,16 @@ func unmapIPPrefixes(ippsList ...[]netip.Prefix) (ret []netip.Prefix) {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Warning: b.mu might be held. Currently (2022-02-17) both callers hold it.
|
|
|
|
|
func (b *LocalBackend) applyPrefsToHostinfo(hi *tailcfg.Hostinfo, prefs *ipn.Prefs) {
|
|
|
|
|
if h := prefs.Hostname; h != "" {
|
|
|
|
|
func (b *LocalBackend) applyPrefsToHostinfo(hi *tailcfg.Hostinfo, prefs ipn.PrefsView) {
|
|
|
|
|
if h := prefs.Hostname(); h != "" {
|
|
|
|
|
hi.Hostname = h
|
|
|
|
|
}
|
|
|
|
|
hi.RoutableIPs = append(prefs.AdvertiseRoutes[:0:0], prefs.AdvertiseRoutes...)
|
|
|
|
|
hi.RequestTags = append(prefs.AdvertiseTags[:0:0], prefs.AdvertiseTags...)
|
|
|
|
|
hi.ShieldsUp = prefs.ShieldsUp
|
|
|
|
|
hi.RoutableIPs = prefs.AdvertiseRoutes().AsSlice()
|
|
|
|
|
hi.RequestTags = prefs.AdvertiseTags().AsSlice()
|
|
|
|
|
hi.ShieldsUp = prefs.ShieldsUp()
|
|
|
|
|
|
|
|
|
|
var sshHostKeys []string
|
|
|
|
|
if prefs.RunSSH && envknob.CanSSHD() {
|
|
|
|
|
if prefs.RunSSH() && envknob.CanSSHD() {
|
|
|
|
|
// TODO(bradfitz): this is called with b.mu held. Not ideal.
|
|
|
|
|
// If the filesystem gets wedged or something we could block for
|
|
|
|
|
// a long time. But probably fine.
|
|
|
|
@ -3016,7 +3021,7 @@ func (b *LocalBackend) enterState(newState ipn.State) {
|
|
|
|
|
|
|
|
|
|
// prefs may change irrespective of state; WantRunning should be explicitly
|
|
|
|
|
// set before potential early return even if the state is unchanged.
|
|
|
|
|
health.SetIPNState(newState.String(), prefs.WantRunning)
|
|
|
|
|
health.SetIPNState(newState.String(), prefs.WantRunning())
|
|
|
|
|
if oldState == newState {
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
@ -3057,10 +3062,9 @@ func (b *LocalBackend) enterState(newState ipn.State) {
|
|
|
|
|
func (b *LocalBackend) hasNodeKey() bool {
|
|
|
|
|
// we can't use b.Prefs(), because it strips the keys, oops!
|
|
|
|
|
b.mu.Lock()
|
|
|
|
|
p := b.prefs
|
|
|
|
|
b.mu.Unlock()
|
|
|
|
|
defer b.mu.Unlock()
|
|
|
|
|
|
|
|
|
|
return p.Persist != nil && !p.Persist.PrivateNodeKey.IsZero()
|
|
|
|
|
return b.prefs.Valid() && b.prefs.Persist() != nil && !b.prefs.Persist().PrivateNodeKey.IsZero()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// nextState returns the state the backend seems to be in, based on
|
|
|
|
@ -3073,8 +3077,8 @@ func (b *LocalBackend) nextState() ipn.State {
|
|
|
|
|
netMap = b.netMap
|
|
|
|
|
state = b.state
|
|
|
|
|
blocked = b.blocked
|
|
|
|
|
wantRunning = b.prefs.WantRunning
|
|
|
|
|
loggedOut = b.prefs.LoggedOut
|
|
|
|
|
wantRunning = b.prefs.WantRunning()
|
|
|
|
|
loggedOut = b.prefs.LoggedOut()
|
|
|
|
|
st = b.engineStatus
|
|
|
|
|
keyExpired = b.keyExpired
|
|
|
|
|
)
|
|
|
|
@ -3191,12 +3195,12 @@ func (b *LocalBackend) ResetForClientDisconnect() {
|
|
|
|
|
b.stateKey = ""
|
|
|
|
|
b.userID = ""
|
|
|
|
|
b.setNetMapLocked(nil)
|
|
|
|
|
b.prefs = new(ipn.Prefs)
|
|
|
|
|
b.prefs = new(ipn.Prefs).View()
|
|
|
|
|
b.keyExpired = false
|
|
|
|
|
b.authURL = ""
|
|
|
|
|
b.authURLSticky = ""
|
|
|
|
|
b.activeLogin = ""
|
|
|
|
|
b.setAtomicValuesFromPrefs(nil)
|
|
|
|
|
b.setAtomicValuesFromPrefs(b.prefs)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (b *LocalBackend) ShouldRunSSH() bool { return b.sshAtomicBool.Load() && envknob.CanSSHD() }
|
|
|
|
@ -3357,22 +3361,16 @@ func (b *LocalBackend) setNetMapLocked(nm *netmap.NetworkMap) {
|
|
|
|
|
func (b *LocalBackend) operatorUserName() string {
|
|
|
|
|
b.mu.Lock()
|
|
|
|
|
defer b.mu.Unlock()
|
|
|
|
|
if b.prefs == nil {
|
|
|
|
|
if !b.prefs.Valid() {
|
|
|
|
|
return ""
|
|
|
|
|
}
|
|
|
|
|
return b.prefs.OperatorUser
|
|
|
|
|
return b.prefs.OperatorUser()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// OperatorUserID returns the current pref's OperatorUser's ID (in
|
|
|
|
|
// os/user.User.Uid string form), or the empty string if none.
|
|
|
|
|
func (b *LocalBackend) OperatorUserID() string {
|
|
|
|
|
b.mu.Lock()
|
|
|
|
|
if b.prefs == nil {
|
|
|
|
|
b.mu.Unlock()
|
|
|
|
|
return ""
|
|
|
|
|
}
|
|
|
|
|
opUserName := b.prefs.OperatorUser
|
|
|
|
|
b.mu.Unlock()
|
|
|
|
|
opUserName := b.operatorUserName()
|
|
|
|
|
if opUserName == "" {
|
|
|
|
|
return ""
|
|
|
|
|
}
|
|
|
|
@ -3393,12 +3391,12 @@ func (b *LocalBackend) TestOnlyPublicKeys() (machineKey key.MachinePublic, nodeK
|
|
|
|
|
machinePrivKey := b.machinePrivKey
|
|
|
|
|
b.mu.Unlock()
|
|
|
|
|
|
|
|
|
|
if prefs == nil || machinePrivKey.IsZero() {
|
|
|
|
|
if !prefs.Valid() || machinePrivKey.IsZero() {
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
mk := machinePrivKey.Public()
|
|
|
|
|
nk := prefs.Persist.PrivateNodeKey.Public()
|
|
|
|
|
nk := prefs.Persist().PrivateNodeKey.Public()
|
|
|
|
|
return mk, nk
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -3507,8 +3505,8 @@ func (b *LocalBackend) SetDNS(ctx context.Context, name, value string) error {
|
|
|
|
|
|
|
|
|
|
b.mu.Lock()
|
|
|
|
|
cc := b.ccAuto
|
|
|
|
|
if prefs := b.prefs; prefs != nil {
|
|
|
|
|
req.NodeKey = prefs.Persist.PrivateNodeKey.Public()
|
|
|
|
|
if b.prefs.Valid() {
|
|
|
|
|
req.NodeKey = b.prefs.Persist().PrivateNodeKey.Public()
|
|
|
|
|
}
|
|
|
|
|
b.mu.Unlock()
|
|
|
|
|
if cc == nil {
|
|
|
|
@ -3620,11 +3618,13 @@ func (b *LocalBackend) DERPMap() *tailcfg.DERPMap {
|
|
|
|
|
func (b *LocalBackend) OfferingExitNode() bool {
|
|
|
|
|
b.mu.Lock()
|
|
|
|
|
defer b.mu.Unlock()
|
|
|
|
|
if b.prefs == nil {
|
|
|
|
|
if !b.prefs.Valid() {
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
var def4, def6 bool
|
|
|
|
|
for _, r := range b.prefs.AdvertiseRoutes {
|
|
|
|
|
ar := b.prefs.AdvertiseRoutes()
|
|
|
|
|
for i := 0; i < ar.Len(); i++ {
|
|
|
|
|
r := ar.At(i)
|
|
|
|
|
if r.Bits() != 0 {
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
@ -3767,10 +3767,7 @@ func (b *LocalBackend) DoNoiseRequest(req *http.Request) (*http.Response, error)
|
|
|
|
|
func (b *LocalBackend) tailscaleSSHEnabled() bool {
|
|
|
|
|
b.mu.Lock()
|
|
|
|
|
defer b.mu.Unlock()
|
|
|
|
|
if b.prefs == nil {
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
return b.prefs.RunSSH
|
|
|
|
|
return b.prefs.Valid() && b.prefs.RunSSH()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (b *LocalBackend) sshServerOrInit() (_ SSHServer, err error) {
|
|
|
|
|