@@ -42,6 +42,7 @@ import (
42
42
"tailscale.com/net/netns"
43
43
"tailscale.com/net/portmapper"
44
44
"tailscale.com/net/stun"
45
+ "tailscale.com/net/tsaddr"
45
46
"tailscale.com/syncs"
46
47
"tailscale.com/tailcfg"
47
48
"tailscale.com/tstime"
@@ -233,6 +234,7 @@ type Conn struct {
233
234
idleFunc func () time.Duration // nil means unknown
234
235
testOnlyPacketListener nettype.PacketListener
235
236
noteRecvActivity func (key.NodePublic ) // or nil, see Options.NoteRecvActivity
237
+ linkMon * monitor.Mon // or nil
236
238
237
239
// ================================================================
238
240
// No locking required to access these fields, either because
@@ -549,6 +551,7 @@ func NewConn(opts Options) (*Conn, error) {
549
551
if opts .LinkMonitor != nil {
550
552
c .portMapper .SetGatewayLookupFunc (opts .LinkMonitor .GatewayAndSelfIP )
551
553
}
554
+ c .linkMon = opts .LinkMonitor
552
555
553
556
if err := c .initialBind (); err != nil {
554
557
return nil , err
@@ -2393,14 +2396,61 @@ func (c *Conn) closeAllDerpLocked(why string) {
2393
2396
c .logActiveDerpLocked ()
2394
2397
}
2395
2398
2399
+ // maybeCloseDERPsOnRebind, in response to a rebind, closes all
2400
+ // DERP connections that don't have a local address in okayLocalIPs
2401
+ // and pings all those that do.
2402
+ func (c * Conn ) maybeCloseDERPsOnRebind (okayLocalIPs []netaddr.IPPrefix ) {
2403
+ c .mu .Lock ()
2404
+ defer c .mu .Unlock ()
2405
+ for regionID , ad := range c .activeDerp {
2406
+ la , err := ad .c .LocalAddr ()
2407
+ if err != nil {
2408
+ c .closeOrReconectDERPLocked (regionID , "rebind-no-localaddr" )
2409
+ continue
2410
+ }
2411
+ if ! tsaddr .PrefixesContainsIP (okayLocalIPs , la .IP ()) {
2412
+ c .closeOrReconectDERPLocked (regionID , "rebind-default-route-change" )
2413
+ continue
2414
+ }
2415
+ regionID := regionID
2416
+ dc := ad .c
2417
+ go func () {
2418
+ ctx , cancel := context .WithTimeout (context .Background (), 3 * time .Second )
2419
+ defer cancel ()
2420
+ if err := dc .Ping (ctx ); err != nil {
2421
+ c .mu .Lock ()
2422
+ defer c .mu .Unlock ()
2423
+ c .closeOrReconectDERPLocked (regionID , "rebind-ping-fail" )
2424
+ return
2425
+ }
2426
+ c .logf ("post-rebind ping of DERP region %d okay" , regionID )
2427
+ }()
2428
+ }
2429
+ c .logActiveDerpLocked ()
2430
+ }
2431
+
2432
+ // closeOrReconectDERPLocked closes the DERP connection to the
2433
+ // provided regionID and starts reconnecting it if it's our current
2434
+ // home DERP.
2435
+ //
2436
+ // why is a reason for logging.
2437
+ //
2438
+ // c.mu must be held.
2439
+ func (c * Conn ) closeOrReconectDERPLocked (regionID int , why string ) {
2440
+ c .closeDerpLocked (regionID , why )
2441
+ if ! c .privateKey .IsZero () && c .myDerp == regionID {
2442
+ c .startDerpHomeConnectLocked ()
2443
+ }
2444
+ }
2445
+
2396
2446
// c.mu must be held.
2397
2447
// It is the responsibility of the caller to call logActiveDerpLocked after any set of closes.
2398
- func (c * Conn ) closeDerpLocked (node int , why string ) {
2399
- if ad , ok := c .activeDerp [node ]; ok {
2400
- c .logf ("magicsock: closing connection to derp-%v (%v), age %v" , node , why , time .Since (ad .createTime ).Round (time .Second ))
2448
+ func (c * Conn ) closeDerpLocked (regionID int , why string ) {
2449
+ if ad , ok := c .activeDerp [regionID ]; ok {
2450
+ c .logf ("magicsock: closing connection to derp-%v (%v), age %v" , regionID , why , time .Since (ad .createTime ).Round (time .Second ))
2401
2451
go ad .c .Close ()
2402
2452
ad .cancel ()
2403
- delete (c .activeDerp , node )
2453
+ delete (c .activeDerp , regionID )
2404
2454
metricNumDERPConns .Set (int64 (len (c .activeDerp )))
2405
2455
}
2406
2456
}
@@ -2831,13 +2881,15 @@ func (c *Conn) Rebind() {
2831
2881
return
2832
2882
}
2833
2883
2834
- c .mu .Lock ()
2835
- c .closeAllDerpLocked ("rebind" )
2836
- if ! c .privateKey .IsZero () {
2837
- c .startDerpHomeConnectLocked ()
2884
+ var ifIPs []netaddr.IPPrefix
2885
+ if c .linkMon != nil {
2886
+ st := c .linkMon .InterfaceState ()
2887
+ defIf := st .DefaultRouteInterface
2888
+ ifIPs = st .InterfaceIPs [defIf ]
2889
+ c .logf ("Rebind; defIf=%q, ips=%v" , defIf , ifIPs )
2838
2890
}
2839
- c .mu .Unlock ()
2840
2891
2892
+ c .maybeCloseDERPsOnRebind (ifIPs )
2841
2893
c .resetEndpointStates ()
2842
2894
}
2843
2895
0 commit comments