mirror of
https://github.com/tailscale/tailscale.git
synced 2025-04-20 13:41:41 +00:00
cmd/tailscale,ipn: add relay-server-port "tailscale set" flag and Prefs field (#15594)
This flag is currently no-op and hidden. The flag does round trip through the related pref. Subsequent commits will tie them to net/udprelay.Server. There is no corresponding "tailscale up" flag, enabling/disabling of the relay server will only be supported via "tailscale set". This is a string flag in order to support disablement via empty string as a port value of 0 means "enable the server and listen on a random unused port". Disablement via empty string also follows existing flag convention, e.g. advertise-routes. Early internal discussions settled on "tailscale set --relay="<port>", but the author felt this was too ambiguous around client vs server, and may cause confusion in the future if we add related flags. Updates tailscale/corp#27502 Signed-off-by: Jordan Whited <jordan@tailscale.com>
This commit is contained in:
parent
7e296923ab
commit
e17abbf461
@ -11,6 +11,7 @@ import (
|
|||||||
"net/netip"
|
"net/netip"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"runtime"
|
"runtime"
|
||||||
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/peterbourgon/ff/v3/ffcli"
|
"github.com/peterbourgon/ff/v3/ffcli"
|
||||||
@ -22,6 +23,7 @@ import (
|
|||||||
"tailscale.com/net/tsaddr"
|
"tailscale.com/net/tsaddr"
|
||||||
"tailscale.com/safesocket"
|
"tailscale.com/safesocket"
|
||||||
"tailscale.com/types/opt"
|
"tailscale.com/types/opt"
|
||||||
|
"tailscale.com/types/ptr"
|
||||||
"tailscale.com/types/views"
|
"tailscale.com/types/views"
|
||||||
"tailscale.com/version"
|
"tailscale.com/version"
|
||||||
)
|
)
|
||||||
@ -62,6 +64,7 @@ type setArgsT struct {
|
|||||||
snat bool
|
snat bool
|
||||||
statefulFiltering bool
|
statefulFiltering bool
|
||||||
netfilterMode string
|
netfilterMode string
|
||||||
|
relayServerPort string
|
||||||
}
|
}
|
||||||
|
|
||||||
func newSetFlagSet(goos string, setArgs *setArgsT) *flag.FlagSet {
|
func newSetFlagSet(goos string, setArgs *setArgsT) *flag.FlagSet {
|
||||||
@ -82,6 +85,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.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.postureChecking, "posture-checking", false, hidden+"allow management plane to gather device posture information")
|
||||||
setf.BoolVar(&setArgs.runWebClient, "webclient", false, "expose the web interface for managing this node over Tailscale at port 5252")
|
setf.BoolVar(&setArgs.runWebClient, "webclient", false, "expose the web interface for managing this node over Tailscale at port 5252")
|
||||||
|
setf.StringVar(&setArgs.relayServerPort, "relay-server-port", "", hidden+"UDP port number (0 will pick a random unused port) for the relay server to bind to, on all interfaces, or empty string to disable relay server functionality")
|
||||||
|
|
||||||
ffcomplete.Flag(setf, "exit-node", func(args []string) ([]string, ffcomplete.ShellCompDirective, error) {
|
ffcomplete.Flag(setf, "exit-node", func(args []string) ([]string, ffcomplete.ShellCompDirective, error) {
|
||||||
st, err := localClient.Status(context.Background())
|
st, err := localClient.Status(context.Background())
|
||||||
@ -233,6 +237,15 @@ func runSet(ctx context.Context, args []string) (retErr error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if setArgs.relayServerPort != "" {
|
||||||
|
uport, err := strconv.ParseUint(setArgs.relayServerPort, 10, 16)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to set relay server port: %v", err)
|
||||||
|
}
|
||||||
|
maskedPrefs.Prefs.RelayServerPort = ptr.To(int(uport))
|
||||||
|
}
|
||||||
|
|
||||||
checkPrefs := curPrefs.Clone()
|
checkPrefs := curPrefs.Clone()
|
||||||
checkPrefs.ApplyEdits(maskedPrefs)
|
checkPrefs.ApplyEdits(maskedPrefs)
|
||||||
if err := localClient.CheckPrefs(ctx, checkPrefs); err != nil {
|
if err := localClient.CheckPrefs(ctx, checkPrefs); err != nil {
|
||||||
|
@ -773,6 +773,7 @@ func init() {
|
|||||||
addPrefFlagMapping("auto-update", "AutoUpdate.Apply")
|
addPrefFlagMapping("auto-update", "AutoUpdate.Apply")
|
||||||
addPrefFlagMapping("advertise-connector", "AppConnector")
|
addPrefFlagMapping("advertise-connector", "AppConnector")
|
||||||
addPrefFlagMapping("posture-checking", "PostureChecking")
|
addPrefFlagMapping("posture-checking", "PostureChecking")
|
||||||
|
addPrefFlagMapping("relay-server-port", "RelayServerPort")
|
||||||
}
|
}
|
||||||
|
|
||||||
func addPrefFlagMapping(flagName string, prefNames ...string) {
|
func addPrefFlagMapping(flagName string, prefNames ...string) {
|
||||||
|
@ -61,6 +61,9 @@ func (src *Prefs) Clone() *Prefs {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if dst.RelayServerPort != nil {
|
||||||
|
dst.RelayServerPort = ptr.To(*src.RelayServerPort)
|
||||||
|
}
|
||||||
dst.Persist = src.Persist.Clone()
|
dst.Persist = src.Persist.Clone()
|
||||||
return dst
|
return dst
|
||||||
}
|
}
|
||||||
@ -96,6 +99,7 @@ var _PrefsCloneNeedsRegeneration = Prefs(struct {
|
|||||||
PostureChecking bool
|
PostureChecking bool
|
||||||
NetfilterKind string
|
NetfilterKind string
|
||||||
DriveShares []*drive.Share
|
DriveShares []*drive.Share
|
||||||
|
RelayServerPort *int
|
||||||
AllowSingleHosts marshalAsTrueInJSON
|
AllowSingleHosts marshalAsTrueInJSON
|
||||||
Persist *persist.Persist
|
Persist *persist.Persist
|
||||||
}{})
|
}{})
|
||||||
|
@ -166,6 +166,10 @@ func (v PrefsView) NetfilterKind() string { return v.ж.Netfilte
|
|||||||
func (v PrefsView) DriveShares() views.SliceView[*drive.Share, drive.ShareView] {
|
func (v PrefsView) DriveShares() views.SliceView[*drive.Share, drive.ShareView] {
|
||||||
return views.SliceOfViews[*drive.Share, drive.ShareView](v.ж.DriveShares)
|
return views.SliceOfViews[*drive.Share, drive.ShareView](v.ж.DriveShares)
|
||||||
}
|
}
|
||||||
|
func (v PrefsView) RelayServerPort() views.ValuePointer[int] {
|
||||||
|
return views.ValuePointerOf(v.ж.RelayServerPort)
|
||||||
|
}
|
||||||
|
|
||||||
func (v PrefsView) AllowSingleHosts() marshalAsTrueInJSON { return v.ж.AllowSingleHosts }
|
func (v PrefsView) AllowSingleHosts() marshalAsTrueInJSON { return v.ж.AllowSingleHosts }
|
||||||
func (v PrefsView) Persist() persist.PersistView { return v.ж.Persist.View() }
|
func (v PrefsView) Persist() persist.PersistView { return v.ж.Persist.View() }
|
||||||
|
|
||||||
@ -200,6 +204,7 @@ var _PrefsViewNeedsRegeneration = Prefs(struct {
|
|||||||
PostureChecking bool
|
PostureChecking bool
|
||||||
NetfilterKind string
|
NetfilterKind string
|
||||||
DriveShares []*drive.Share
|
DriveShares []*drive.Share
|
||||||
|
RelayServerPort *int
|
||||||
AllowSingleHosts marshalAsTrueInJSON
|
AllowSingleHosts marshalAsTrueInJSON
|
||||||
Persist *persist.Persist
|
Persist *persist.Persist
|
||||||
}{})
|
}{})
|
||||||
|
25
ipn/prefs.go
25
ipn/prefs.go
@ -246,6 +246,14 @@ type Prefs struct {
|
|||||||
// by name.
|
// by name.
|
||||||
DriveShares []*drive.Share
|
DriveShares []*drive.Share
|
||||||
|
|
||||||
|
// RelayServerPort is the UDP port number for the relay server to bind to,
|
||||||
|
// on all interfaces. A non-nil zero value signifies a random unused port
|
||||||
|
// should be used. A nil value signifies relay server functionality
|
||||||
|
// should be disabled. This field is currently experimental, and therefore
|
||||||
|
// no guarantees are made about its current naming and functionality when
|
||||||
|
// non-nil/enabled.
|
||||||
|
RelayServerPort *int `json:",omitempty"`
|
||||||
|
|
||||||
// AllowSingleHosts was a legacy field that was always true
|
// AllowSingleHosts was a legacy field that was always true
|
||||||
// for the past 4.5 years. It controlled whether Tailscale
|
// for the past 4.5 years. It controlled whether Tailscale
|
||||||
// peers got /32 or /127 routes for each other.
|
// peers got /32 or /127 routes for each other.
|
||||||
@ -337,6 +345,7 @@ type MaskedPrefs struct {
|
|||||||
PostureCheckingSet bool `json:",omitempty"`
|
PostureCheckingSet bool `json:",omitempty"`
|
||||||
NetfilterKindSet bool `json:",omitempty"`
|
NetfilterKindSet bool `json:",omitempty"`
|
||||||
DriveSharesSet bool `json:",omitempty"`
|
DriveSharesSet bool `json:",omitempty"`
|
||||||
|
RelayServerPortSet bool `json:",omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetsInternal reports whether mp has any of the Internal*Set field bools set
|
// SetsInternal reports whether mp has any of the Internal*Set field bools set
|
||||||
@ -555,6 +564,9 @@ func (p *Prefs) pretty(goos string) string {
|
|||||||
}
|
}
|
||||||
sb.WriteString(p.AutoUpdate.Pretty())
|
sb.WriteString(p.AutoUpdate.Pretty())
|
||||||
sb.WriteString(p.AppConnector.Pretty())
|
sb.WriteString(p.AppConnector.Pretty())
|
||||||
|
if p.RelayServerPort != nil {
|
||||||
|
fmt.Fprintf(&sb, "relayServerPort=%d ", *p.RelayServerPort)
|
||||||
|
}
|
||||||
if p.Persist != nil {
|
if p.Persist != nil {
|
||||||
sb.WriteString(p.Persist.Pretty())
|
sb.WriteString(p.Persist.Pretty())
|
||||||
} else {
|
} else {
|
||||||
@ -616,7 +628,8 @@ func (p *Prefs) Equals(p2 *Prefs) bool {
|
|||||||
p.AppConnector == p2.AppConnector &&
|
p.AppConnector == p2.AppConnector &&
|
||||||
p.PostureChecking == p2.PostureChecking &&
|
p.PostureChecking == p2.PostureChecking &&
|
||||||
slices.EqualFunc(p.DriveShares, p2.DriveShares, drive.SharesEqual) &&
|
slices.EqualFunc(p.DriveShares, p2.DriveShares, drive.SharesEqual) &&
|
||||||
p.NetfilterKind == p2.NetfilterKind
|
p.NetfilterKind == p2.NetfilterKind &&
|
||||||
|
compareIntPtrs(p.RelayServerPort, p2.RelayServerPort)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (au AutoUpdatePrefs) Pretty() string {
|
func (au AutoUpdatePrefs) Pretty() string {
|
||||||
@ -636,6 +649,16 @@ func (ap AppConnectorPrefs) Pretty() string {
|
|||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func compareIntPtrs(a, b *int) bool {
|
||||||
|
if (a == nil) != (b == nil) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if a == nil {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return *a == *b
|
||||||
|
}
|
||||||
|
|
||||||
// NewPrefs returns the default preferences to use.
|
// NewPrefs returns the default preferences to use.
|
||||||
func NewPrefs() *Prefs {
|
func NewPrefs() *Prefs {
|
||||||
// Provide default values for options which might be missing
|
// Provide default values for options which might be missing
|
||||||
|
@ -65,6 +65,7 @@ func TestPrefsEqual(t *testing.T) {
|
|||||||
"PostureChecking",
|
"PostureChecking",
|
||||||
"NetfilterKind",
|
"NetfilterKind",
|
||||||
"DriveShares",
|
"DriveShares",
|
||||||
|
"RelayServerPort",
|
||||||
"AllowSingleHosts",
|
"AllowSingleHosts",
|
||||||
"Persist",
|
"Persist",
|
||||||
}
|
}
|
||||||
@ -73,6 +74,9 @@ func TestPrefsEqual(t *testing.T) {
|
|||||||
have, prefsHandles)
|
have, prefsHandles)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
relayServerPort := func(port int) *int {
|
||||||
|
return &port
|
||||||
|
}
|
||||||
nets := func(strs ...string) (ns []netip.Prefix) {
|
nets := func(strs ...string) (ns []netip.Prefix) {
|
||||||
for _, s := range strs {
|
for _, s := range strs {
|
||||||
n, err := netip.ParsePrefix(s)
|
n, err := netip.ParsePrefix(s)
|
||||||
@ -341,6 +345,16 @@ func TestPrefsEqual(t *testing.T) {
|
|||||||
&Prefs{AdvertiseServices: []string{"svc:tux", "svc:amelie"}},
|
&Prefs{AdvertiseServices: []string{"svc:tux", "svc:amelie"}},
|
||||||
false,
|
false,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
&Prefs{RelayServerPort: relayServerPort(0)},
|
||||||
|
&Prefs{RelayServerPort: nil},
|
||||||
|
false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
&Prefs{RelayServerPort: relayServerPort(0)},
|
||||||
|
&Prefs{RelayServerPort: relayServerPort(1)},
|
||||||
|
false,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
for i, tt := range tests {
|
for i, tt := range tests {
|
||||||
got := tt.a.Equals(tt.b)
|
got := tt.a.Equals(tt.b)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user