Skip to content

Commit 23bedfa

Browse files
committed
feat: vpn uses WorkspaceHostnameSuffix for DNS names
1 parent 6cee450 commit 23bedfa

File tree

5 files changed

+215
-153
lines changed

5 files changed

+215
-153
lines changed

codersdk/workspacesdk/workspacesdk.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -143,7 +143,7 @@ type AgentConnectionInfo struct {
143143
DERPMap *tailcfg.DERPMap `json:"derp_map"`
144144
DERPForceWebSockets bool `json:"derp_force_websockets"`
145145
DisableDirectConnections bool `json:"disable_direct_connections"`
146-
HostnameSuffix string `json:"hostname_suffix"`
146+
HostnameSuffix string `json:"hostname_suffix,omitempty"`
147147
}
148148

149149
func (c *Client) AgentConnectionInfoGeneric(ctx context.Context) (AgentConnectionInfo, error) {

tailnet/controllers.go

Lines changed: 25 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -863,11 +863,12 @@ func (r *basicResumeTokenRefresher) refresh() {
863863
}
864864

865865
type TunnelAllWorkspaceUpdatesController struct {
866-
coordCtrl *TunnelSrcCoordController
867-
dnsHostSetter DNSHostsSetter
868-
updateHandler UpdatesHandler
869-
ownerUsername string
870-
logger slog.Logger
866+
coordCtrl *TunnelSrcCoordController
867+
dnsHostSetter DNSHostsSetter
868+
dnsNameOptions DNSNameOptions
869+
updateHandler UpdatesHandler
870+
ownerUsername string
871+
logger slog.Logger
871872

872873
mu sync.Mutex
873874
updater *tunnelUpdater
@@ -882,37 +883,39 @@ type Workspace struct {
882883
agents map[uuid.UUID]*Agent
883884
}
884885

886+
type DNSNameOptions struct {
887+
Suffix string
888+
}
889+
885890
// updateDNSNames updates the DNS names for all agents in the workspace.
886891
// DNS hosts must be all lowercase, or the resolver won't be able to find them.
887892
// Usernames are globally unique & case-insensitive.
888893
// Workspace names are unique per-user & case-insensitive.
889894
// Agent names are unique per-workspace & case-insensitive.
890-
func (w *Workspace) updateDNSNames() error {
895+
func (w *Workspace) updateDNSNames(options DNSNameOptions) error {
891896
wsName := strings.ToLower(w.Name)
892897
username := strings.ToLower(w.ownerUsername)
893898
for id, a := range w.agents {
894899
agentName := strings.ToLower(a.Name)
895900
names := make(map[dnsname.FQDN][]netip.Addr)
896901
// TODO: technically, DNS labels cannot start with numbers, but the rules are often not
897902
// strictly enforced.
898-
fqdn, err := dnsname.ToFQDN(fmt.Sprintf("%s.%s.me.coder.", agentName, wsName))
903+
fqdn, err := dnsname.ToFQDN(fmt.Sprintf("%s.%s.me.%s.", agentName, wsName, options.Suffix))
899904
if err != nil {
900905
return err
901906
}
902907
names[fqdn] = []netip.Addr{CoderServicePrefix.AddrFromUUID(a.ID)}
903-
fqdn, err = dnsname.ToFQDN(fmt.Sprintf("%s.%s.%s.coder.", agentName, wsName, username))
908+
fqdn, err = dnsname.ToFQDN(fmt.Sprintf("%s.%s.%s.%s.", agentName, wsName, username, options.Suffix))
904909
if err != nil {
905910
return err
906911
}
907912
names[fqdn] = []netip.Addr{CoderServicePrefix.AddrFromUUID(a.ID)}
908913
if len(w.agents) == 1 {
909-
fqdn, err := dnsname.ToFQDN(fmt.Sprintf("%s.coder.", wsName))
914+
fqdn, err = dnsname.ToFQDN(fmt.Sprintf("%s.%s.", wsName, options.Suffix))
910915
if err != nil {
911916
return err
912917
}
913-
for _, a := range w.agents {
914-
names[fqdn] = []netip.Addr{CoderServicePrefix.AddrFromUUID(a.ID)}
915-
}
918+
names[fqdn] = []netip.Addr{CoderServicePrefix.AddrFromUUID(a.ID)}
916919
}
917920
a.Hosts = names
918921
w.agents[id] = a
@@ -949,6 +952,7 @@ func (t *TunnelAllWorkspaceUpdatesController) New(client WorkspaceUpdatesClient)
949952
logger: t.logger,
950953
coordCtrl: t.coordCtrl,
951954
dnsHostsSetter: t.dnsHostSetter,
955+
dnsNameOptions: t.dnsNameOptions,
952956
updateHandler: t.updateHandler,
953957
ownerUsername: t.ownerUsername,
954958
recvLoopDone: make(chan struct{}),
@@ -995,6 +999,7 @@ type tunnelUpdater struct {
995999
updateHandler UpdatesHandler
9961000
ownerUsername string
9971001
recvLoopDone chan struct{}
1002+
dnsNameOptions DNSNameOptions
9981003

9991004
sync.Mutex
10001005
workspaces map[uuid.UUID]*Workspace
@@ -1249,7 +1254,7 @@ func (t *tunnelUpdater) allAgentIDsLocked() []uuid.UUID {
12491254
func (t *tunnelUpdater) updateDNSNamesLocked() map[dnsname.FQDN][]netip.Addr {
12501255
names := make(map[dnsname.FQDN][]netip.Addr)
12511256
for _, w := range t.workspaces {
1252-
err := w.updateDNSNames()
1257+
err := w.updateDNSNames(t.dnsNameOptions)
12531258
if err != nil {
12541259
// This should never happen in production, because converting the FQDN only fails
12551260
// if names are too long, and we put strict length limits on agent, workspace, and user
@@ -1272,10 +1277,11 @@ type TunnelAllOption func(t *TunnelAllWorkspaceUpdatesController)
12721277

12731278
// WithDNS configures the tunnelAllWorkspaceUpdatesController to set DNS names for all workspaces
12741279
// and agents it learns about.
1275-
func WithDNS(d DNSHostsSetter, ownerUsername string) TunnelAllOption {
1280+
func WithDNS(d DNSHostsSetter, ownerUsername string, options DNSNameOptions) TunnelAllOption {
12761281
return func(t *TunnelAllWorkspaceUpdatesController) {
12771282
t.dnsHostSetter = d
12781283
t.ownerUsername = ownerUsername
1284+
t.dnsNameOptions = options
12791285
}
12801286
}
12811287

@@ -1291,7 +1297,11 @@ func WithHandler(h UpdatesHandler) TunnelAllOption {
12911297
func NewTunnelAllWorkspaceUpdatesController(
12921298
logger slog.Logger, c *TunnelSrcCoordController, opts ...TunnelAllOption,
12931299
) *TunnelAllWorkspaceUpdatesController {
1294-
t := &TunnelAllWorkspaceUpdatesController{logger: logger, coordCtrl: c}
1300+
t := &TunnelAllWorkspaceUpdatesController{
1301+
logger: logger,
1302+
coordCtrl: c,
1303+
dnsNameOptions: DNSNameOptions{"coder"},
1304+
}
12951305
for _, opt := range opts {
12961306
opt(t)
12971307
}

tailnet/controllers_test.go

Lines changed: 17 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1521,7 +1521,7 @@ func TestTunnelAllWorkspaceUpdatesController_Initial(t *testing.T) {
15211521
fUH := newFakeUpdateHandler(ctx, t)
15221522
fDNS := newFakeDNSSetter(ctx, t)
15231523
coordC, updateC, updateCtrl := setupConnectedAllWorkspaceUpdatesController(ctx, t, logger,
1524-
tailnet.WithDNS(fDNS, "testy"),
1524+
tailnet.WithDNS(fDNS, "testy", tailnet.DNSNameOptions{Suffix: "mctest"}),
15251525
tailnet.WithHandler(fUH),
15261526
)
15271527

@@ -1563,13 +1563,13 @@ func TestTunnelAllWorkspaceUpdatesController_Initial(t *testing.T) {
15631563

15641564
// Also triggers setting DNS hosts
15651565
expectedDNS := map[dnsname.FQDN][]netip.Addr{
1566-
"w1a1.w1.me.coder.": {ws1a1IP},
1567-
"w2a1.w2.me.coder.": {w2a1IP},
1568-
"w2a2.w2.me.coder.": {w2a2IP},
1569-
"w1a1.w1.testy.coder.": {ws1a1IP},
1570-
"w2a1.w2.testy.coder.": {w2a1IP},
1571-
"w2a2.w2.testy.coder.": {w2a2IP},
1572-
"w1.coder.": {ws1a1IP},
1566+
"w1a1.w1.me.mctest.": {ws1a1IP},
1567+
"w2a1.w2.me.mctest.": {w2a1IP},
1568+
"w2a2.w2.me.mctest.": {w2a2IP},
1569+
"w1a1.w1.testy.mctest.": {ws1a1IP},
1570+
"w2a1.w2.testy.mctest.": {w2a1IP},
1571+
"w2a2.w2.testy.mctest.": {w2a2IP},
1572+
"w1.mctest.": {ws1a1IP},
15731573
}
15741574
dnsCall := testutil.RequireRecvCtx(ctx, t, fDNS.calls)
15751575
require.Equal(t, expectedDNS, dnsCall.hosts)
@@ -1584,23 +1584,23 @@ func TestTunnelAllWorkspaceUpdatesController_Initial(t *testing.T) {
15841584
{
15851585
ID: w1a1ID, Name: "w1a1", WorkspaceID: w1ID,
15861586
Hosts: map[dnsname.FQDN][]netip.Addr{
1587-
"w1.coder.": {ws1a1IP},
1588-
"w1a1.w1.me.coder.": {ws1a1IP},
1589-
"w1a1.w1.testy.coder.": {ws1a1IP},
1587+
"w1.mctest.": {ws1a1IP},
1588+
"w1a1.w1.me.mctest.": {ws1a1IP},
1589+
"w1a1.w1.testy.mctest.": {ws1a1IP},
15901590
},
15911591
},
15921592
{
15931593
ID: w2a1ID, Name: "w2a1", WorkspaceID: w2ID,
15941594
Hosts: map[dnsname.FQDN][]netip.Addr{
1595-
"w2a1.w2.me.coder.": {w2a1IP},
1596-
"w2a1.w2.testy.coder.": {w2a1IP},
1595+
"w2a1.w2.me.mctest.": {w2a1IP},
1596+
"w2a1.w2.testy.mctest.": {w2a1IP},
15971597
},
15981598
},
15991599
{
16001600
ID: w2a2ID, Name: "w2a2", WorkspaceID: w2ID,
16011601
Hosts: map[dnsname.FQDN][]netip.Addr{
1602-
"w2a2.w2.me.coder.": {w2a2IP},
1603-
"w2a2.w2.testy.coder.": {w2a2IP},
1602+
"w2a2.w2.me.mctest.": {w2a2IP},
1603+
"w2a2.w2.testy.mctest.": {w2a2IP},
16041604
},
16051605
},
16061606
},
@@ -1632,7 +1632,7 @@ func TestTunnelAllWorkspaceUpdatesController_DeleteAgent(t *testing.T) {
16321632
fUH := newFakeUpdateHandler(ctx, t)
16331633
fDNS := newFakeDNSSetter(ctx, t)
16341634
coordC, updateC, updateCtrl := setupConnectedAllWorkspaceUpdatesController(ctx, t, logger,
1635-
tailnet.WithDNS(fDNS, "testy"),
1635+
tailnet.WithDNS(fDNS, "testy", tailnet.DNSNameOptions{Suffix: "coder"}),
16361636
tailnet.WithHandler(fUH),
16371637
)
16381638

@@ -1775,7 +1775,7 @@ func TestTunnelAllWorkspaceUpdatesController_DNSError(t *testing.T) {
17751775
fConn := &fakeCoordinatee{}
17761776
tsc := tailnet.NewTunnelSrcCoordController(logger, fConn)
17771777
uut := tailnet.NewTunnelAllWorkspaceUpdatesController(logger, tsc,
1778-
tailnet.WithDNS(fDNS, "testy"),
1778+
tailnet.WithDNS(fDNS, "testy", tailnet.DNSNameOptions{Suffix: "coder"}),
17791779
)
17801780

17811781
updateC := newFakeWorkspaceUpdateClient(ctx, t)

vpn/client.go

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,11 @@ func (*client) NewConn(initCtx context.Context, serverURL *url.URL, token string
107107
if err != nil {
108108
return nil, xerrors.Errorf("get connection info: %w", err)
109109
}
110+
// default to DNS suffix of "coder" if the server hasn't set it (might be too old).
111+
dnsNameOptions := tailnet.DNSNameOptions{Suffix: "coder"}
112+
if connInfo.HostnameSuffix != "" {
113+
dnsNameOptions.Suffix = connInfo.HostnameSuffix
114+
}
110115

111116
headers.Set(codersdk.SessionTokenHeader, token)
112117
dialer := workspacesdk.NewWebsocketDialer(options.Logger, rpcURL, &websocket.DialOptions{
@@ -148,7 +153,7 @@ func (*client) NewConn(initCtx context.Context, serverURL *url.URL, token string
148153
updatesCtrl := tailnet.NewTunnelAllWorkspaceUpdatesController(
149154
options.Logger,
150155
coordCtrl,
151-
tailnet.WithDNS(conn, me.Username),
156+
tailnet.WithDNS(conn, me.Username, dnsNameOptions),
152157
tailnet.WithHandler(options.UpdateHandler),
153158
)
154159
controller.WorkspaceUpdatesCtrl = updatesCtrl

0 commit comments

Comments
 (0)