ipn/config: add RelayServerPort and RelayServerStaticEndpoints to config file (#18300)

This commit is contained in:
Raj Singh
2026-06-26 15:45:29 -05:00
committed by GitHub
parent 79e3bbbfa6
commit b64209b248
3 changed files with 211 additions and 0 deletions
+17
View File
@@ -52,6 +52,15 @@ type ConfigVAlpha struct {
// should advertise amongst its wireguard endpoints.
StaticEndpoints []netip.AddrPort `json:",omitempty"`
// RelayServerPort is the UDP port for the relay server to bind to.
// A value of 0 will pick a random unused port. Nil disables relay server.
RelayServerPort *uint16 `json:",omitzero"`
// RelayServerStaticEndpoints are static IP:port endpoints to advertise
// as candidates for relay connections. Only relevant when RelayServerPort
// is non-nil.
RelayServerStaticEndpoints []netip.AddrPort `json:",omitempty"`
// TODO(bradfitz,maisem): future something like:
// Profile map[string]*Config // keyed by alice@gmail.com, corp.com (TailnetSID)
}
@@ -166,5 +175,13 @@ func (c *ConfigVAlpha) ToPrefs() (MaskedPrefs, error) {
if c.AdvertiseServices != nil {
mp.AdvertiseServices = c.AdvertiseServices
}
mp.RelayServerPortSet = true
mp.RelayServerStaticEndpointsSet = true
if c.RelayServerPort != nil {
mp.RelayServerPort = c.RelayServerPort
}
if c.RelayServerStaticEndpoints != nil {
mp.RelayServerStaticEndpoints = c.RelayServerStaticEndpoints
}
return mp, nil
}
+122
View File
@@ -5,6 +5,8 @@ package ipn
import (
"net/netip"
"reflect"
"slices"
"testing"
)
@@ -64,3 +66,123 @@ func TestConfigVAlpha_ToPrefs_AdvertiseRoutes(t *testing.T) {
})
}
}
func TestConfigVAlphaToPrefs(t *testing.T) {
aps := func(t *testing.T, strs ...string) (ret []netip.AddrPort) {
t.Helper()
for _, s := range strs {
n, err := netip.ParseAddrPort(s)
if err != nil {
t.Fatalf("parse AddrPort %q: %v", s, err)
}
ret = append(ret, n)
}
return ret
}
tests := []struct {
name string
cfg *ConfigVAlpha
want MaskedPrefs
}{
{
name: "nil_config",
cfg: nil,
want: MaskedPrefs{},
},
{
name: "relay_server_port_and_static_endpoints",
cfg: &ConfigVAlpha{
RelayServerPort: new(uint16(12345)),
RelayServerStaticEndpoints: aps(t, "[2001:db8::1]:40000", "192.0.2.1:40000"),
},
want: MaskedPrefs{
Prefs: Prefs{
RelayServerPort: new(uint16(12345)),
RelayServerStaticEndpoints: aps(t, "[2001:db8::1]:40000", "192.0.2.1:40000"),
},
RelayServerPortSet: true,
RelayServerStaticEndpointsSet: true,
},
},
{
// Port 0 means "pick a random unused port"; it is
// distinct from a nil port which disables the relay
// server. The zero value must be propagated.
name: "relay_server_port_zero_is_random_not_disabled",
cfg: &ConfigVAlpha{
RelayServerPort: new(uint16(0)),
},
want: MaskedPrefs{
Prefs: Prefs{
RelayServerPort: new(uint16(0)),
},
RelayServerPortSet: true,
RelayServerStaticEndpointsSet: true,
},
},
{
name: "only_static_endpoints_set",
cfg: &ConfigVAlpha{
RelayServerStaticEndpoints: aps(t, "192.0.2.1:40000"),
},
want: MaskedPrefs{
Prefs: Prefs{
RelayServerStaticEndpoints: aps(t, "192.0.2.1:40000"),
},
RelayServerPortSet: true,
RelayServerStaticEndpointsSet: true,
},
},
{
// Both fields nil but masks set: the config file is the
// source of truth, so this disables any previously
// configured relay server.
name: "both_nil_disables_relay_server",
cfg: &ConfigVAlpha{},
want: MaskedPrefs{
RelayServerPortSet: true,
RelayServerStaticEndpointsSet: true,
},
},
{
// An empty (non-nil) static endpoints slice is treated as
// "advertise no static endpoints", disabling them.
name: "empty_static_endpoints_disables",
cfg: &ConfigVAlpha{
RelayServerStaticEndpoints: []netip.AddrPort{},
},
want: MaskedPrefs{
Prefs: Prefs{
RelayServerStaticEndpoints: []netip.AddrPort{},
},
RelayServerPortSet: true,
RelayServerStaticEndpointsSet: true,
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, err := tt.cfg.ToPrefs()
if err != nil {
t.Fatalf("ToPrefs() unexpected error: %v", err)
}
// Compare only the relay-server-related fields rather than
// the whole MaskedPrefs, since ToPrefs populates many
// unrelated default fields (e.g. WantRunning).
if got.RelayServerPortSet != tt.want.RelayServerPortSet {
t.Errorf("RelayServerPortSet = %v; want %v", got.RelayServerPortSet, tt.want.RelayServerPortSet)
}
if got.RelayServerStaticEndpointsSet != tt.want.RelayServerStaticEndpointsSet {
t.Errorf("RelayServerStaticEndpointsSet = %v; want %v", got.RelayServerStaticEndpointsSet, tt.want.RelayServerStaticEndpointsSet)
}
if !reflect.DeepEqual(got.RelayServerPort, tt.want.RelayServerPort) {
t.Errorf("RelayServerPort = %v; want %v", got.RelayServerPort, tt.want.RelayServerPort)
}
if !slices.Equal(got.RelayServerStaticEndpoints, tt.want.RelayServerStaticEndpoints) {
t.Errorf("RelayServerStaticEndpoints = %v; want %v", got.RelayServerStaticEndpoints, tt.want.RelayServerStaticEndpoints)
}
})
}
}
+72
View File
@@ -7490,6 +7490,78 @@ func TestConfigFileReload(t *testing.T) {
}
},
},
{
name: "enable_relay_server",
initial: &conffile.Config{
Parsed: ipn.ConfigVAlpha{
Version: "alpha0",
},
},
updated: &conffile.Config{
Parsed: ipn.ConfigVAlpha{
Version: "alpha0",
RelayServerPort: new(uint16(12345)),
RelayServerStaticEndpoints: []netip.AddrPort{netip.MustParseAddrPort("[2001:db8::1]:40000")},
},
},
checkFn: func(t *testing.T, b *LocalBackend) {
pv := b.Prefs()
if port, ok := pv.RelayServerPort().GetOk(); !ok || port != 12345 {
t.Errorf("RelayServerPort = (%d, %v); want (12345, true)", port, ok)
}
if got := pv.RelayServerStaticEndpoints().AsSlice(); !slices.Equal(got, []netip.AddrPort{netip.MustParseAddrPort("[2001:db8::1]:40000")}) {
t.Errorf("RelayServerStaticEndpoints = %v; want [[2001:db8::1]:40000]", got)
}
},
},
{
// Disabling: a config that omits the relay server fields
// must clear any previously configured values, because
// ToPrefs sets the masks unconditionally.
name: "disable_relay_server",
initial: &conffile.Config{
Parsed: ipn.ConfigVAlpha{
Version: "alpha0",
RelayServerPort: new(uint16(12345)),
RelayServerStaticEndpoints: []netip.AddrPort{netip.MustParseAddrPort("[2001:db8::1]:40000")},
},
},
updated: &conffile.Config{
Parsed: ipn.ConfigVAlpha{
Version: "alpha0",
},
},
checkFn: func(t *testing.T, b *LocalBackend) {
pv := b.Prefs()
if _, ok := pv.RelayServerPort().GetOk(); ok {
t.Errorf("RelayServerPort = %v; want disabled", pv.RelayServerPort())
}
if got := pv.RelayServerStaticEndpoints().AsSlice(); len(got) != 0 {
t.Errorf("RelayServerStaticEndpoints = %v; want empty", got)
}
},
},
{
name: "change_relay_server_port",
initial: &conffile.Config{
Parsed: ipn.ConfigVAlpha{
Version: "alpha0",
RelayServerPort: new(uint16(12345)),
},
},
updated: &conffile.Config{
Parsed: ipn.ConfigVAlpha{
Version: "alpha0",
RelayServerPort: new(uint16(54321)),
},
},
checkFn: func(t *testing.T, b *LocalBackend) {
pv := b.Prefs()
if port, ok := pv.RelayServerPort().GetOk(); !ok || port != 54321 {
t.Errorf("RelayServerPort = (%d, %v); want (54321, true)", port, ok)
}
},
},
}
for _, tc := range tests {