@@ -188,6 +188,25 @@ func NewConn(options *Options) (*Conn, error) {
188
188
},
189
189
wireguardEngine : wireguardEngine ,
190
190
}
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
+ })
191
210
netStack .ForwardTCPIn = server .forwardTCP
192
211
return server , nil
193
212
}
@@ -225,12 +244,15 @@ type Conn struct {
225
244
listeners map [listenKey ]* listener
226
245
forwardTCPCallback func (conn net.Conn , listenerExists bool ) net.Conn
227
246
228
- lastMutex sync.Mutex
247
+ lastMutex sync.Mutex
248
+ nodeSending bool
249
+ nodeChanged bool
229
250
// It's only possible to store these values via status functions,
230
251
// so the values must be stored for retrieval later on.
231
252
lastEndpoints []string
232
253
lastPreferredDERP int
233
254
lastDERPLatency map [string ]float64
255
+ nodeCallback func (node * Node )
234
256
}
235
257
236
258
// 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
244
266
c .forwardTCPCallback = callback
245
267
}
246
268
247
- // SetNodeCallback is triggered when a network change occurs and peer
248
- // renegotiation may be required. Clients should constantly be emitting
249
- // node changes.
250
269
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 ()
297
274
}
298
275
299
276
// SetDERPMap updates the DERPMap of a connection.
@@ -361,6 +338,9 @@ func (c *Conn) UpdateNodes(nodes []*Node) error {
361
338
}
362
339
err = c .wireguardEngine .Reconfig (cfg , c .wireguardRouter , & dns.Config {}, & tailcfg.Debug {})
363
340
if err != nil {
341
+ if c .isClosed () {
342
+ return nil
343
+ }
364
344
return xerrors .Errorf ("reconfig: %w" , err )
365
345
}
366
346
return nil
@@ -416,6 +396,42 @@ func (c *Conn) isClosed() bool {
416
396
}
417
397
}
418
398
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
+
419
435
// This and below is taken _mostly_ verbatim from Tailscale:
420
436
// https://github.com/tailscale/tailscale/blob/c88bd53b1b7b2fcf7ba302f2e53dd1ce8c32dad4/tsnet/tsnet.go#L459-L494
421
437
0 commit comments