Skip to content

Commit 52ecd35

Browse files
authored
fix(wsconncache): only allow one peer per connection (#5886)
If an agent went away and reconnected, the wsconncache connection would be polluted for about 10m because there would be two peers with the same IP. The old peer always had priority, which caused the dashboard to try and always dial the old peer until it was removed. Fixes: #5292
1 parent b0a1615 commit 52ecd35

File tree

2 files changed

+39
-6
lines changed

2 files changed

+39
-6
lines changed

coderd/workspaceagents.go

+14-6
Original file line numberDiff line numberDiff line change
@@ -402,11 +402,6 @@ func (api *API) workspaceAgentListeningPorts(rw http.ResponseWriter, r *http.Req
402402

403403
func (api *API) dialWorkspaceAgentTailnet(r *http.Request, agentID uuid.UUID) (*codersdk.AgentConn, error) {
404404
clientConn, serverConn := net.Pipe()
405-
go func() {
406-
<-r.Context().Done()
407-
_ = clientConn.Close()
408-
_ = serverConn.Close()
409-
}()
410405

411406
derpMap := api.DERPMap.Clone()
412407
for _, region := range derpMap.Regions {
@@ -453,7 +448,16 @@ func (api *API) dialWorkspaceAgentTailnet(r *http.Request, agentID uuid.UUID) (*
453448
}
454449

455450
sendNodes, _ := tailnet.ServeCoordinator(clientConn, func(node []*tailnet.Node) error {
456-
return conn.UpdateNodes(node)
451+
err := conn.RemoveAllPeers()
452+
if err != nil {
453+
return xerrors.Errorf("remove all peers: %w", err)
454+
}
455+
456+
err = conn.UpdateNodes(node)
457+
if err != nil {
458+
return xerrors.Errorf("update nodes: %w", err)
459+
}
460+
return nil
457461
})
458462
conn.SetNodeCallback(sendNodes)
459463
go func() {
@@ -465,6 +469,10 @@ func (api *API) dialWorkspaceAgentTailnet(r *http.Request, agentID uuid.UUID) (*
465469
}()
466470
return &codersdk.AgentConn{
467471
Conn: conn,
472+
CloseFunc: func() {
473+
_ = clientConn.Close()
474+
_ = serverConn.Close()
475+
},
468476
}, nil
469477
}
470478

tailnet/conn.go

+25
Original file line numberDiff line numberDiff line change
@@ -325,6 +325,31 @@ func (c *Conn) SetDERPMap(derpMap *tailcfg.DERPMap) {
325325
c.wireguardEngine.SetDERPMap(derpMap)
326326
}
327327

328+
func (c *Conn) RemoveAllPeers() error {
329+
c.mutex.Lock()
330+
defer c.mutex.Unlock()
331+
332+
c.netMap.Peers = []*tailcfg.Node{}
333+
c.peerMap = map[tailcfg.NodeID]*tailcfg.Node{}
334+
netMapCopy := *c.netMap
335+
c.wireguardEngine.SetNetworkMap(&netMapCopy)
336+
cfg, err := nmcfg.WGCfg(c.netMap, Logger(c.logger.Named("wgconfig")), netmap.AllowSingleHosts, "")
337+
if err != nil {
338+
return xerrors.Errorf("update wireguard config: %w", err)
339+
}
340+
err = c.wireguardEngine.Reconfig(cfg, c.wireguardRouter, &dns.Config{}, &tailcfg.Debug{})
341+
if err != nil {
342+
if c.isClosed() {
343+
return nil
344+
}
345+
if errors.Is(err, wgengine.ErrNoChanges) {
346+
return nil
347+
}
348+
return xerrors.Errorf("reconfig: %w", err)
349+
}
350+
return nil
351+
}
352+
328353
// UpdateNodes connects with a set of peers. This can be constantly updated,
329354
// and peers will continually be reconnected as necessary.
330355
func (c *Conn) UpdateNodes(nodes []*Node) error {

0 commit comments

Comments
 (0)