mirror of
https://github.com/tailscale/tailscale.git
synced 2026-07-14 17:43:03 -04:00
Add a new Prefs.RemoteConfig bool. When true, a c2n endpoint at
/remoteapi/localapi/* proxies into this node's LocalAPI at
/localapi/* with full read/write permission, giving the tailnet
admin the same API surface a local root/admin user has via the
tailscale CLI. All LocalAPI versions (v0, v1, ...) proxy through.
RemoteConfig is an alternative to Tailscale's default per-feature
double opt-in, in which both the tailnet admin and the local machine
owner must consent to each individual setting change. It is a single
client-side "I trust the tailnet admin" switch that, once on, hands
over full remote management of this node's settings and LocalAPI
without any further local prompt or confirmation.
This is only appropriate when the tailnet admin already owns the
machine (e.g. a corporate fleet device) or the local user has
explicitly delegated full control. It should never be enabled on a
personal/BYOD device with an untrusted tailnet admin. The trust
model is documented on the pref, on the hidden --remote-config CLI
flag, and on the feature/remoteconfig package.
The node advertises its RemoteConfig state to the control plane via
a new Hostinfo.RemoteConfig bool. This is only true when the feature
is both compiled in (buildfeatures.HasRemoteConfig) and its init
actually ran (feature.IsRegistered("remoteconfig")); tsnet builds
have the former but not the latter and correctly report false.
The handler lives in feature/remoteconfig and can be omitted with the
ts_omit_remoteconfig build tag. tsnet's TestDeps guards against
accidentally pulling it in.
Updates tailscale/corp#18043
Change-Id: I72ce10a90a0e4e738c72c940af3af64c986160b2
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
279 lines
7.4 KiB
Go
279 lines
7.4 KiB
Go
// Copyright (c) Tailscale Inc & contributors
|
|
// SPDX-License-Identifier: BSD-3-Clause
|
|
|
|
// Code generated by tailscale.com/cmd/cloner; DO NOT EDIT.
|
|
|
|
package ipn
|
|
|
|
import (
|
|
"maps"
|
|
"net/netip"
|
|
"time"
|
|
|
|
"tailscale.com/drive"
|
|
"tailscale.com/tailcfg"
|
|
"tailscale.com/types/opt"
|
|
"tailscale.com/types/persist"
|
|
"tailscale.com/types/preftype"
|
|
)
|
|
|
|
// Clone makes a deep copy of LoginProfile.
|
|
// The result aliases no memory with the original.
|
|
func (src *LoginProfile) Clone() *LoginProfile {
|
|
if src == nil {
|
|
return nil
|
|
}
|
|
dst := new(LoginProfile)
|
|
*dst = *src
|
|
dst.UserProfile = *src.UserProfile.Clone()
|
|
return dst
|
|
}
|
|
|
|
// A compilation failure here means this code must be regenerated, with the command at the top of this file.
|
|
var _LoginProfileCloneNeedsRegeneration = LoginProfile(struct {
|
|
ID ProfileID
|
|
Name string
|
|
NetworkProfile NetworkProfile
|
|
Key StateKey
|
|
UserProfile tailcfg.UserProfile
|
|
NodeID tailcfg.StableNodeID
|
|
LocalUserID WindowsUserID
|
|
ControlURL string
|
|
Created time.Time
|
|
}{})
|
|
|
|
// Clone makes a deep copy of Prefs.
|
|
// The result aliases no memory with the original.
|
|
func (src *Prefs) Clone() *Prefs {
|
|
if src == nil {
|
|
return nil
|
|
}
|
|
dst := new(Prefs)
|
|
*dst = *src
|
|
dst.AdvertiseTags = append(src.AdvertiseTags[:0:0], src.AdvertiseTags...)
|
|
dst.AdvertiseRoutes = append(src.AdvertiseRoutes[:0:0], src.AdvertiseRoutes...)
|
|
dst.AdvertiseServices = append(src.AdvertiseServices[:0:0], src.AdvertiseServices...)
|
|
if src.DriveShares != nil {
|
|
dst.DriveShares = make([]*drive.Share, len(src.DriveShares))
|
|
for i := range dst.DriveShares {
|
|
if src.DriveShares[i] == nil {
|
|
dst.DriveShares[i] = nil
|
|
} else {
|
|
dst.DriveShares[i] = src.DriveShares[i].Clone()
|
|
}
|
|
}
|
|
}
|
|
if dst.RelayServerPort != nil {
|
|
dst.RelayServerPort = new(*src.RelayServerPort)
|
|
}
|
|
dst.RelayServerStaticEndpoints = append(src.RelayServerStaticEndpoints[:0:0], src.RelayServerStaticEndpoints...)
|
|
dst.Persist = src.Persist.Clone()
|
|
return dst
|
|
}
|
|
|
|
// A compilation failure here means this code must be regenerated, with the command at the top of this file.
|
|
var _PrefsCloneNeedsRegeneration = Prefs(struct {
|
|
ControlURL string
|
|
RouteAll bool
|
|
ExitNodeID tailcfg.StableNodeID
|
|
ExitNodeIP netip.Addr
|
|
AutoExitNode ExitNodeExpression
|
|
InternalExitNodePrior tailcfg.StableNodeID
|
|
ExitNodeAllowLANAccess bool
|
|
CorpDNS bool
|
|
RunSSH bool
|
|
RunWebClient bool
|
|
WantRunning bool
|
|
LoggedOut bool
|
|
ShieldsUp bool
|
|
AdvertiseTags []string
|
|
Hostname string
|
|
NotepadURLs bool
|
|
ForceDaemon bool
|
|
Egg bool
|
|
AdvertiseRoutes []netip.Prefix
|
|
AdvertiseServices []string
|
|
Sync opt.Bool
|
|
NoSNAT bool
|
|
NoStatefulFiltering opt.Bool
|
|
NetfilterMode preftype.NetfilterMode
|
|
OperatorUser string
|
|
ProfileName string
|
|
AutoUpdate AutoUpdatePrefs
|
|
AppConnector AppConnectorPrefs
|
|
PostureChecking bool
|
|
NetfilterKind string
|
|
RemoteConfig bool
|
|
DriveShares []*drive.Share
|
|
RelayServerPort *uint16
|
|
RelayServerStaticEndpoints []netip.AddrPort
|
|
Persist *persist.Persist
|
|
}{})
|
|
|
|
// Clone makes a deep copy of ServeConfig.
|
|
// The result aliases no memory with the original.
|
|
func (src *ServeConfig) Clone() *ServeConfig {
|
|
if src == nil {
|
|
return nil
|
|
}
|
|
dst := new(ServeConfig)
|
|
*dst = *src
|
|
if dst.TCP != nil {
|
|
dst.TCP = map[uint16]*TCPPortHandler{}
|
|
for k, v := range src.TCP {
|
|
if v == nil {
|
|
dst.TCP[k] = nil
|
|
} else {
|
|
dst.TCP[k] = new(*v)
|
|
}
|
|
}
|
|
}
|
|
if dst.Web != nil {
|
|
dst.Web = map[HostPort]*WebServerConfig{}
|
|
for k, v := range src.Web {
|
|
if v == nil {
|
|
dst.Web[k] = nil
|
|
} else {
|
|
dst.Web[k] = v.Clone()
|
|
}
|
|
}
|
|
}
|
|
if dst.Services != nil {
|
|
dst.Services = map[tailcfg.ServiceName]*ServiceConfig{}
|
|
for k, v := range src.Services {
|
|
if v == nil {
|
|
dst.Services[k] = nil
|
|
} else {
|
|
dst.Services[k] = v.Clone()
|
|
}
|
|
}
|
|
}
|
|
dst.AllowFunnel = maps.Clone(src.AllowFunnel)
|
|
if dst.Foreground != nil {
|
|
dst.Foreground = map[string]*ServeConfig{}
|
|
for k, v := range src.Foreground {
|
|
if v == nil {
|
|
dst.Foreground[k] = nil
|
|
} else {
|
|
dst.Foreground[k] = v.Clone()
|
|
}
|
|
}
|
|
}
|
|
return dst
|
|
}
|
|
|
|
// A compilation failure here means this code must be regenerated, with the command at the top of this file.
|
|
var _ServeConfigCloneNeedsRegeneration = ServeConfig(struct {
|
|
TCP map[uint16]*TCPPortHandler
|
|
Web map[HostPort]*WebServerConfig
|
|
Services map[tailcfg.ServiceName]*ServiceConfig
|
|
AllowFunnel map[HostPort]bool
|
|
Foreground map[string]*ServeConfig
|
|
ETag string
|
|
}{})
|
|
|
|
// Clone makes a deep copy of ServiceConfig.
|
|
// The result aliases no memory with the original.
|
|
func (src *ServiceConfig) Clone() *ServiceConfig {
|
|
if src == nil {
|
|
return nil
|
|
}
|
|
dst := new(ServiceConfig)
|
|
*dst = *src
|
|
if dst.TCP != nil {
|
|
dst.TCP = map[uint16]*TCPPortHandler{}
|
|
for k, v := range src.TCP {
|
|
if v == nil {
|
|
dst.TCP[k] = nil
|
|
} else {
|
|
dst.TCP[k] = new(*v)
|
|
}
|
|
}
|
|
}
|
|
if dst.Web != nil {
|
|
dst.Web = map[HostPort]*WebServerConfig{}
|
|
for k, v := range src.Web {
|
|
if v == nil {
|
|
dst.Web[k] = nil
|
|
} else {
|
|
dst.Web[k] = v.Clone()
|
|
}
|
|
}
|
|
}
|
|
return dst
|
|
}
|
|
|
|
// A compilation failure here means this code must be regenerated, with the command at the top of this file.
|
|
var _ServiceConfigCloneNeedsRegeneration = ServiceConfig(struct {
|
|
TCP map[uint16]*TCPPortHandler
|
|
Web map[HostPort]*WebServerConfig
|
|
Tun bool
|
|
}{})
|
|
|
|
// Clone makes a deep copy of TCPPortHandler.
|
|
// The result aliases no memory with the original.
|
|
func (src *TCPPortHandler) Clone() *TCPPortHandler {
|
|
if src == nil {
|
|
return nil
|
|
}
|
|
dst := new(TCPPortHandler)
|
|
*dst = *src
|
|
return dst
|
|
}
|
|
|
|
// A compilation failure here means this code must be regenerated, with the command at the top of this file.
|
|
var _TCPPortHandlerCloneNeedsRegeneration = TCPPortHandler(struct {
|
|
HTTPS bool
|
|
HTTP bool
|
|
TCPForward string
|
|
TerminateTLS string
|
|
ProxyProtocol int
|
|
}{})
|
|
|
|
// Clone makes a deep copy of HTTPHandler.
|
|
// The result aliases no memory with the original.
|
|
func (src *HTTPHandler) Clone() *HTTPHandler {
|
|
if src == nil {
|
|
return nil
|
|
}
|
|
dst := new(HTTPHandler)
|
|
*dst = *src
|
|
dst.AcceptAppCaps = append(src.AcceptAppCaps[:0:0], src.AcceptAppCaps...)
|
|
return dst
|
|
}
|
|
|
|
// A compilation failure here means this code must be regenerated, with the command at the top of this file.
|
|
var _HTTPHandlerCloneNeedsRegeneration = HTTPHandler(struct {
|
|
Path string
|
|
Proxy string
|
|
Text string
|
|
AcceptAppCaps []tailcfg.PeerCapability
|
|
Redirect string
|
|
}{})
|
|
|
|
// Clone makes a deep copy of WebServerConfig.
|
|
// The result aliases no memory with the original.
|
|
func (src *WebServerConfig) Clone() *WebServerConfig {
|
|
if src == nil {
|
|
return nil
|
|
}
|
|
dst := new(WebServerConfig)
|
|
*dst = *src
|
|
if dst.Handlers != nil {
|
|
dst.Handlers = map[string]*HTTPHandler{}
|
|
for k, v := range src.Handlers {
|
|
if v == nil {
|
|
dst.Handlers[k] = nil
|
|
} else {
|
|
dst.Handlers[k] = v.Clone()
|
|
}
|
|
}
|
|
}
|
|
return dst
|
|
}
|
|
|
|
// A compilation failure here means this code must be regenerated, with the command at the top of this file.
|
|
var _WebServerConfigCloneNeedsRegeneration = WebServerConfig(struct {
|
|
Handlers map[string]*HTTPHandler
|
|
}{})
|