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 <bradfitz@tailscale.com>
pull/9193/merge
Brad Fitzpatrick 1 year ago committed by Brad Fitzpatrick
parent f7b7ccf835
commit 8b3ea13af0

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

@ -139,16 +139,41 @@ func (d *Dialer) SetNetMon(netMon *netmon.Monitor) {
} }
func (d *Dialer) linkChanged(delta *netmon.ChangeDelta) { func (d *Dialer) linkChanged(delta *netmon.ChangeDelta) {
if !delta.Major {
return
}
d.mu.Lock() d.mu.Lock()
defer d.mu.Unlock() defer d.mu.Unlock()
for id, c := range d.activeSysConns { for id, c := range d.activeSysConns {
if changeAffectsConn(delta, c) {
d.logf("tsdial: closing system connection %v->%v due to link change", c.LocalAddr(), c.RemoteAddr())
go c.Close() go c.Close()
delete(d.activeSysConns, id) 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) { func (d *Dialer) closeSysConn(id int) {
d.mu.Lock() d.mu.Lock()
@ -263,6 +288,12 @@ func ipNetOfNetwork(n string) string {
return "ip" 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 // SystemDial connects to the provided network address without going over
// Tailscale. It prefers going over the default interface and closes existing // Tailscale. It prefers going over the default interface and closes existing
// connections if the default interface changes. It is used to connect to // 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() { d.netnsDialerOnce.Do(func() {
logf := d.Logf d.netnsDialer = netns.NewDialer(d.logf, d.netMon)
if logf == nil {
logf = logger.Discard
}
d.netnsDialer = netns.NewDialer(logf, d.netMon)
}) })
c, err := d.netnsDialer.DialContext(ctx, network, addr) c, err := d.netnsDialer.DialContext(ctx, network, addr)
if err != nil { if err != nil {

Loading…
Cancel
Save