Просмотр исходного кода

net/tsdial: be smarter about when to close SystemDial conns

It was too aggressive before, as it only had the ill-defined "Major"
bool to work with. Now it can check more precisely.

Updates #9040

Change-Id: I20967283b64af6a9cad3f8e90cff406de91653b8
Signed-off-by: Brad Fitzpatrick <[email protected]>
Brad Fitzpatrick 2 лет назад
Родитель
Сommit
8b3ea13af0
2 измененных файлов с 38 добавлено и 12 удалено
  1. 1 2
      net/interfaces/interfaces.go
  2. 37 10
      net/tsdial/tsdial.go

+ 1 - 2
net/interfaces/interfaces.go

@@ -364,10 +364,9 @@ func (s *State) HasIP(ip netip.Addr) bool {
 	if s == nil {
 		return false
 	}
-	want := netip.PrefixFrom(ip, ip.BitLen())
 	for _, pv := range s.InterfaceIPs {
 		for _, p := range pv {
-			if p == want {
+			if p.Contains(ip) {
 				return true
 			}
 		}

+ 37 - 10
net/tsdial/tsdial.go

@@ -139,15 +139,40 @@ func (d *Dialer) SetNetMon(netMon *netmon.Monitor) {
 }
 
 func (d *Dialer) linkChanged(delta *netmon.ChangeDelta) {
-	if !delta.Major {
-		return
-	}
 	d.mu.Lock()
 	defer d.mu.Unlock()
 	for id, c := range d.activeSysConns {
-		go c.Close()
-		delete(d.activeSysConns, id)
+		if changeAffectsConn(delta, c) {
+			d.logf("tsdial: closing system connection %v->%v due to link change", c.LocalAddr(), c.RemoteAddr())
+			go c.Close()
+			delete(d.activeSysConns, id)
+		}
+	}
+}
+
+// changeAffectsConn reports whether the network change delta affects
+// the provided connection.
+func changeAffectsConn(delta *netmon.ChangeDelta, conn net.Conn) bool {
+	la, _ := conn.LocalAddr().(*net.TCPAddr)
+	ra, _ := conn.RemoteAddr().(*net.TCPAddr)
+	if la == nil || ra == nil {
+		return false // not TCP
+	}
+	lip, rip := la.AddrPort().Addr(), ra.AddrPort().Addr()
+
+	if delta.Old == nil {
+		return false
+	}
+	if delta.Old.DefaultRouteInterface != delta.New.DefaultRouteInterface ||
+		delta.Old.HTTPProxy != delta.New.HTTPProxy {
+		return true
 	}
+	if !delta.New.HasIP(lip) && delta.Old.HasIP(lip) {
+		// Our interface with this source IP went away.
+		return true
+	}
+	_ = rip // TODO(bradfitz): use the remote IP?
+	return false
 }
 
 func (d *Dialer) closeSysConn(id int) {
@@ -263,6 +288,12 @@ func ipNetOfNetwork(n string) string {
 	return "ip"
 }
 
+func (d *Dialer) logf(format string, args ...any) {
+	if d.Logf != nil {
+		d.Logf(format, args...)
+	}
+}
+
 // SystemDial connects to the provided network address without going over
 // Tailscale. It prefers going over the default interface and closes existing
 // connections if the default interface changes. It is used to connect to
@@ -276,11 +307,7 @@ func (d *Dialer) SystemDial(ctx context.Context, network, addr string) (net.Conn
 	}
 
 	d.netnsDialerOnce.Do(func() {
-		logf := d.Logf
-		if logf == nil {
-			logf = logger.Discard
-		}
-		d.netnsDialer = netns.NewDialer(logf, d.netMon)
+		d.netnsDialer = netns.NewDialer(d.logf, d.netMon)
 	})
 	c, err := d.netnsDialer.DialContext(ctx, network, addr)
 	if err != nil {