Compare commits
1 Commits
dsnet/sync
...
brafitz/re
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3570a10e90 |
@@ -56,6 +56,7 @@ type setArgsT struct {
|
||||
updateCheck bool
|
||||
updateApply bool
|
||||
postureChecking bool
|
||||
remoteConfig bool
|
||||
}
|
||||
|
||||
func newSetFlagSet(goos string, setArgs *setArgsT) *flag.FlagSet {
|
||||
@@ -76,6 +77,7 @@ func newSetFlagSet(goos string, setArgs *setArgsT) *flag.FlagSet {
|
||||
setf.BoolVar(&setArgs.updateApply, "auto-update", false, "automatically update to the latest available version")
|
||||
setf.BoolVar(&setArgs.postureChecking, "posture-checking", false, "HIDDEN: allow management plane to gather device posture information")
|
||||
setf.BoolVar(&setArgs.runWebClient, "webclient", false, "run a web interface for managing this node, served over Tailscale at port 5252")
|
||||
setf.BoolVar(&setArgs.remoteConfig, "remote-config", false, "HIDDEN: allow talinet admins to manage this node's settings")
|
||||
|
||||
if safesocket.GOOSUsesPeerCreds(goos) {
|
||||
setf.StringVar(&setArgs.opUser, "operator", "", "Unix username to allow to operate on tailscaled without sudo")
|
||||
@@ -116,6 +118,7 @@ func runSet(ctx context.Context, args []string) (retErr error) {
|
||||
Hostname: setArgs.hostname,
|
||||
OperatorUser: setArgs.opUser,
|
||||
ForceDaemon: setArgs.forceDaemon,
|
||||
RemoteConfig: setArgs.remoteConfig,
|
||||
AutoUpdate: ipn.AutoUpdatePrefs{
|
||||
Check: setArgs.updateCheck,
|
||||
Apply: opt.NewBool(setArgs.updateApply),
|
||||
@@ -148,6 +151,7 @@ func runSet(ctx context.Context, args []string) (retErr error) {
|
||||
advertiseRoutesSet = true
|
||||
}
|
||||
})
|
||||
|
||||
if maskedPrefs.IsEmpty() {
|
||||
return flag.ErrHelp
|
||||
}
|
||||
|
||||
@@ -723,6 +723,7 @@ func init() {
|
||||
addPrefFlagMapping("auto-update", "AutoUpdate.Apply")
|
||||
addPrefFlagMapping("advertise-connector", "AppConnector")
|
||||
addPrefFlagMapping("posture-checking", "PostureChecking")
|
||||
addPrefFlagMapping("remote-config", "RemoteConfig")
|
||||
}
|
||||
|
||||
func addPrefFlagMapping(flagName string, prefNames ...string) {
|
||||
|
||||
@@ -56,6 +56,7 @@ var _PrefsCloneNeedsRegeneration = Prefs(struct {
|
||||
AppConnector AppConnectorPrefs
|
||||
PostureChecking bool
|
||||
NetfilterKind string
|
||||
RemoteConfig bool
|
||||
Persist *persist.Persist
|
||||
}{})
|
||||
|
||||
|
||||
@@ -91,6 +91,7 @@ func (v PrefsView) AutoUpdate() AutoUpdatePrefs { return v.ж.AutoUpda
|
||||
func (v PrefsView) AppConnector() AppConnectorPrefs { return v.ж.AppConnector }
|
||||
func (v PrefsView) PostureChecking() bool { return v.ж.PostureChecking }
|
||||
func (v PrefsView) NetfilterKind() string { return v.ж.NetfilterKind }
|
||||
func (v PrefsView) RemoteConfig() bool { return v.ж.RemoteConfig }
|
||||
func (v PrefsView) Persist() persist.PersistView { return v.ж.Persist.View() }
|
||||
|
||||
// A compilation failure here means this code must be regenerated, with the command at the top of this file.
|
||||
@@ -121,6 +122,7 @@ var _PrefsViewNeedsRegeneration = Prefs(struct {
|
||||
AppConnector AppConnectorPrefs
|
||||
PostureChecking bool
|
||||
NetfilterKind string
|
||||
RemoteConfig bool
|
||||
Persist *persist.Persist
|
||||
}{})
|
||||
|
||||
|
||||
@@ -26,9 +26,13 @@ import (
|
||||
"tailscale.com/clientupdate"
|
||||
"tailscale.com/envknob"
|
||||
"tailscale.com/ipn"
|
||||
"tailscale.com/net/netmon"
|
||||
"tailscale.com/net/sockstats"
|
||||
"tailscale.com/posture"
|
||||
"tailscale.com/tailcfg"
|
||||
"tailscale.com/types/logger"
|
||||
"tailscale.com/types/logid"
|
||||
"tailscale.com/types/ptr"
|
||||
"tailscale.com/util/clientmetric"
|
||||
"tailscale.com/util/goroutines"
|
||||
"tailscale.com/util/set"
|
||||
@@ -72,6 +76,10 @@ var c2nHandlers = map[methodAndPath]c2nHandler{
|
||||
|
||||
// Linux netfilter.
|
||||
req("POST /netfilter-kind"): handleC2NSetNetfilterKind,
|
||||
|
||||
// Remote config
|
||||
req("/remote-config/prefs"): handleC2NRemoteConfigPrefs,
|
||||
// TODO(bradfitz): more (but not all) LocalAPI proxies for remote-config
|
||||
}
|
||||
|
||||
type c2nHandler func(*LocalBackend, http.ResponseWriter, *http.Request)
|
||||
@@ -569,3 +577,33 @@ func handleC2NTLSCertStatus(b *LocalBackend, w http.ResponseWriter, r *http.Requ
|
||||
|
||||
writeJSON(w, ret)
|
||||
}
|
||||
|
||||
// NewC2NLocalAPIHandler is initialized by the localapi package's init func.
|
||||
// It returns a new http.Handler that serves LocalAPI for c2n.
|
||||
var NewC2NLocalAPIHandler func(b *LocalBackend, logf logger.Logf, netMon *netmon.Monitor, logID logid.PublicID) http.Handler
|
||||
|
||||
func handleC2NRemoteConfigPrefs(b *LocalBackend, w http.ResponseWriter, r *http.Request) {
|
||||
prefs := b.Prefs()
|
||||
if !prefs.Valid() || !prefs.RemoteConfig() {
|
||||
http.Error(w, "remote config not enabled", http.StatusForbidden)
|
||||
return
|
||||
}
|
||||
if NewC2NLocalAPIHandler == nil {
|
||||
http.Error(w, "remote config not wired up", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
var newPath string
|
||||
switch r.URL.Path {
|
||||
case "/remote-config/prefs":
|
||||
newPath = "/localapi/v0/prefs"
|
||||
default:
|
||||
http.Error(w, "unsupported path", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
r2 := r.WithContext(r.Context())
|
||||
r2.URL = ptr.To(*r.URL) // shallow clone
|
||||
r2.URL.Path = newPath
|
||||
|
||||
h := NewC2NLocalAPIHandler(b, b.logf, b.sys.NetMon.Get(), b.backendLogID)
|
||||
h.ServeHTTP(w, r2)
|
||||
}
|
||||
|
||||
@@ -153,6 +153,16 @@ func NewHandler(b *ipnlocal.LocalBackend, logf logger.Logf, netMon *netmon.Monit
|
||||
return &Handler{b: b, logf: logf, netMon: netMon, backendLogID: logID, clock: tstime.StdClock{}}
|
||||
}
|
||||
|
||||
func init() {
|
||||
ipnlocal.NewC2NLocalAPIHandler = func(b *ipnlocal.LocalBackend, logf logger.Logf, netMon *netmon.Monitor, logID logid.PublicID) http.Handler {
|
||||
h := NewHandler(b, logf, netMon, logID)
|
||||
h.PermitRead, h.PermitWrite = true, true
|
||||
h.PermitCert = false
|
||||
h.ConnIdentity = &ipnauth.ConnIdentity{}
|
||||
return h
|
||||
}
|
||||
}
|
||||
|
||||
type Handler struct {
|
||||
// RequiredPassword, if non-empty, forces all HTTP
|
||||
// requests to have HTTP basic auth with this password.
|
||||
|
||||
@@ -222,6 +222,10 @@ type Prefs struct {
|
||||
// Linux-only.
|
||||
NetfilterKind string
|
||||
|
||||
// RemoteConfig specifies whether to allow the control server to
|
||||
// manage this node's settings.
|
||||
RemoteConfig 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.
|
||||
@@ -293,6 +297,7 @@ type MaskedPrefs struct {
|
||||
AppConnectorSet bool `json:",omitempty"`
|
||||
PostureCheckingSet bool `json:",omitempty"`
|
||||
NetfilterKindSet bool `json:",omitempty"`
|
||||
RemoteConfigSet bool `json:",omitempty"`
|
||||
}
|
||||
|
||||
type AutoUpdatePrefsMask struct {
|
||||
@@ -467,6 +472,9 @@ func (p *Prefs) pretty(goos string) string {
|
||||
if p.ShieldsUp {
|
||||
sb.WriteString("shields=true ")
|
||||
}
|
||||
if p.RemoteConfig {
|
||||
sb.WriteString("remoteconfig=true ")
|
||||
}
|
||||
if p.ExitNodeIP.IsValid() {
|
||||
fmt.Fprintf(&sb, "exit=%v lan=%t ", p.ExitNodeIP, p.ExitNodeAllowLANAccess)
|
||||
} else if !p.ExitNodeID.IsZero() {
|
||||
@@ -549,6 +557,7 @@ func (p *Prefs) Equals(p2 *Prefs) bool {
|
||||
p.OperatorUser == p2.OperatorUser &&
|
||||
p.Hostname == p2.Hostname &&
|
||||
p.ForceDaemon == p2.ForceDaemon &&
|
||||
p.RemoteConfig == p2.RemoteConfig &&
|
||||
compareIPNets(p.AdvertiseRoutes, p2.AdvertiseRoutes) &&
|
||||
compareStrings(p.AdvertiseTags, p2.AdvertiseTags) &&
|
||||
p.Persist.Equals(p2.Persist) &&
|
||||
|
||||
@@ -62,6 +62,7 @@ func TestPrefsEqual(t *testing.T) {
|
||||
"AppConnector",
|
||||
"PostureChecking",
|
||||
"NetfilterKind",
|
||||
"RemoteConfig",
|
||||
"Persist",
|
||||
}
|
||||
if have := fieldsOf(reflect.TypeFor[Prefs]()); !reflect.DeepEqual(have, prefsHandles) {
|
||||
@@ -435,6 +436,11 @@ func TestPrefsPretty(t *testing.T) {
|
||||
"windows",
|
||||
"Prefs{ra=false mesh=false dns=false want=false shields=true update=off Persist=nil}",
|
||||
},
|
||||
{
|
||||
Prefs{RemoteConfig: true},
|
||||
"windows",
|
||||
"Prefs{ra=false mesh=false dns=false want=false remoteconfig=true update=off Persist=nil}",
|
||||
},
|
||||
{
|
||||
Prefs{AllowSingleHosts: true},
|
||||
"windows",
|
||||
|
||||
@@ -129,7 +129,8 @@ type CapabilityVersion int
|
||||
// - 86: 2024-01-23: Client understands NodeAttrProbeUDPLifetime
|
||||
// - 87: 2024-02-11: UserProfile.Groups removed (added in 66)
|
||||
// - 88: 2024-03-05: Client understands NodeAttrSuggestExitNode
|
||||
const CurrentCapabilityVersion CapabilityVersion = 88
|
||||
// - 89: 2024-03-07: c2n remote config prefs
|
||||
const CurrentCapabilityVersion CapabilityVersion = 89
|
||||
|
||||
type StableID string
|
||||
|
||||
|
||||
Reference in New Issue
Block a user