Skip to content

Commit 80b45f1

Browse files
authored
fix: Buffer tailnet nodes from connection initialization (coder#4159)
* fix: Don't use StatusAbnormalClosure This is reserved for WASM use, and might be the cause of some weird leaks. * Add close to provisioner logs
1 parent a7ee8b3 commit 80b45f1

File tree

1 file changed

+66
-50
lines changed

1 file changed

+66
-50
lines changed

tailnet/conn.go

Lines changed: 66 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -188,6 +188,25 @@ func NewConn(options *Options) (*Conn, error) {
188188
},
189189
wireguardEngine: wireguardEngine,
190190
}
191+
wireguardEngine.SetStatusCallback(func(s *wgengine.Status, err error) {
192+
if err != nil {
193+
return
194+
}
195+
server.lastMutex.Lock()
196+
server.lastEndpoints = make([]string, 0, len(s.LocalAddrs))
197+
for _, addr := range s.LocalAddrs {
198+
server.lastEndpoints = append(server.lastEndpoints, addr.Addr.String())
199+
}
200+
server.lastMutex.Unlock()
201+
server.sendNode()
202+
})
203+
wireguardEngine.SetNetInfoCallback(func(ni *tailcfg.NetInfo) {
204+
server.lastMutex.Lock()
205+
server.lastPreferredDERP = ni.PreferredDERP
206+
server.lastDERPLatency = ni.DERPLatency
207+
server.lastMutex.Unlock()
208+
server.sendNode()
209+
})
191210
netStack.ForwardTCPIn = server.forwardTCP
192211
return server, nil
193212
}
@@ -225,12 +244,15 @@ type Conn struct {
225244
listeners map[listenKey]*listener
226245
forwardTCPCallback func(conn net.Conn, listenerExists bool) net.Conn
227246

228-
lastMutex sync.Mutex
247+
lastMutex sync.Mutex
248+
nodeSending bool
249+
nodeChanged bool
229250
// It's only possible to store these values via status functions,
230251
// so the values must be stored for retrieval later on.
231252
lastEndpoints []string
232253
lastPreferredDERP int
233254
lastDERPLatency map[string]float64
255+
nodeCallback func(node *Node)
234256
}
235257

236258
// SetForwardTCPCallback is called every time a TCP connection is initiated inbound.
@@ -244,56 +266,11 @@ func (c *Conn) SetForwardTCPCallback(callback func(conn net.Conn, listenerExists
244266
c.forwardTCPCallback = callback
245267
}
246268

247-
// SetNodeCallback is triggered when a network change occurs and peer
248-
// renegotiation may be required. Clients should constantly be emitting
249-
// node changes.
250269
func (c *Conn) SetNodeCallback(callback func(node *Node)) {
251-
makeNode := func() *Node {
252-
return &Node{
253-
ID: c.netMap.SelfNode.ID,
254-
Key: c.netMap.SelfNode.Key,
255-
Addresses: c.netMap.SelfNode.Addresses,
256-
AllowedIPs: c.netMap.SelfNode.AllowedIPs,
257-
DiscoKey: c.magicConn.DiscoPublicKey(),
258-
Endpoints: c.lastEndpoints,
259-
PreferredDERP: c.lastPreferredDERP,
260-
DERPLatency: c.lastDERPLatency,
261-
}
262-
}
263-
// A send queue must be used so nodes are sent in order.
264-
queue := make(chan *Node, 16)
265-
go func() {
266-
for {
267-
select {
268-
case <-c.closed:
269-
return
270-
case node := <-queue:
271-
c.logger.Debug(context.Background(), "send node callback", slog.F("node", node))
272-
callback(node)
273-
}
274-
}
275-
}()
276-
c.wireguardEngine.SetNetInfoCallback(func(ni *tailcfg.NetInfo) {
277-
c.lastMutex.Lock()
278-
c.lastPreferredDERP = ni.PreferredDERP
279-
c.lastDERPLatency = ni.DERPLatency
280-
node := makeNode()
281-
queue <- node
282-
c.lastMutex.Unlock()
283-
})
284-
c.wireguardEngine.SetStatusCallback(func(s *wgengine.Status, err error) {
285-
if err != nil {
286-
return
287-
}
288-
c.lastMutex.Lock()
289-
c.lastEndpoints = make([]string, 0, len(s.LocalAddrs))
290-
for _, addr := range s.LocalAddrs {
291-
c.lastEndpoints = append(c.lastEndpoints, addr.Addr.String())
292-
}
293-
node := makeNode()
294-
queue <- node
295-
c.lastMutex.Unlock()
296-
})
270+
c.lastMutex.Lock()
271+
c.nodeCallback = callback
272+
c.lastMutex.Unlock()
273+
c.sendNode()
297274
}
298275

299276
// SetDERPMap updates the DERPMap of a connection.
@@ -361,6 +338,9 @@ func (c *Conn) UpdateNodes(nodes []*Node) error {
361338
}
362339
err = c.wireguardEngine.Reconfig(cfg, c.wireguardRouter, &dns.Config{}, &tailcfg.Debug{})
363340
if err != nil {
341+
if c.isClosed() {
342+
return nil
343+
}
364344
return xerrors.Errorf("reconfig: %w", err)
365345
}
366346
return nil
@@ -416,6 +396,42 @@ func (c *Conn) isClosed() bool {
416396
}
417397
}
418398

399+
func (c *Conn) sendNode() {
400+
c.lastMutex.Lock()
401+
defer c.lastMutex.Unlock()
402+
if c.nodeSending {
403+
c.nodeChanged = true
404+
return
405+
}
406+
node := &Node{
407+
ID: c.netMap.SelfNode.ID,
408+
Key: c.netMap.SelfNode.Key,
409+
Addresses: c.netMap.SelfNode.Addresses,
410+
AllowedIPs: c.netMap.SelfNode.AllowedIPs,
411+
DiscoKey: c.magicConn.DiscoPublicKey(),
412+
Endpoints: c.lastEndpoints,
413+
PreferredDERP: c.lastPreferredDERP,
414+
DERPLatency: c.lastDERPLatency,
415+
}
416+
nodeCallback := c.nodeCallback
417+
if nodeCallback == nil {
418+
return
419+
}
420+
c.nodeSending = true
421+
go func() {
422+
nodeCallback(node)
423+
c.lastMutex.Lock()
424+
c.nodeSending = false
425+
if c.nodeChanged {
426+
c.nodeChanged = false
427+
c.lastMutex.Unlock()
428+
c.sendNode()
429+
return
430+
}
431+
c.lastMutex.Unlock()
432+
}()
433+
}
434+
419435
// This and below is taken _mostly_ verbatim from Tailscale:
420436
// https://github.com/tailscale/tailscale/blob/c88bd53b1b7b2fcf7ba302f2e53dd1ce8c32dad4/tsnet/tsnet.go#L459-L494
421437

0 commit comments

Comments
 (0)