Update
This commit is contained in:
94
vendor/tailscale.com/wgengine/netstack/netstack.go
generated
vendored
94
vendor/tailscale.com/wgengine/netstack/netstack.go
generated
vendored
@@ -33,11 +33,13 @@ import (
|
||||
"gvisor.dev/gvisor/pkg/tcpip/transport/udp"
|
||||
"gvisor.dev/gvisor/pkg/waiter"
|
||||
"tailscale.com/envknob"
|
||||
"tailscale.com/feature/buildfeatures"
|
||||
"tailscale.com/ipn/ipnlocal"
|
||||
"tailscale.com/metrics"
|
||||
"tailscale.com/net/dns"
|
||||
"tailscale.com/net/ipset"
|
||||
"tailscale.com/net/netaddr"
|
||||
"tailscale.com/net/netx"
|
||||
"tailscale.com/net/packet"
|
||||
"tailscale.com/net/tsaddr"
|
||||
"tailscale.com/net/tsdial"
|
||||
@@ -208,7 +210,7 @@ type Impl struct {
|
||||
// TCP connection to another host (e.g. in subnet router mode).
|
||||
//
|
||||
// This is currently only used in tests.
|
||||
forwardDialFunc func(context.Context, string, string) (net.Conn, error)
|
||||
forwardDialFunc netx.DialFunc
|
||||
|
||||
// forwardInFlightPerClientDropped is a metric that tracks how many
|
||||
// in-flight TCP forward requests were dropped due to the per-client
|
||||
@@ -326,10 +328,15 @@ func Create(logf logger.Logf, tundev *tstun.Wrapper, e wgengine.Engine, mc *magi
|
||||
if tcpipErr != nil {
|
||||
return nil, fmt.Errorf("could not disable TCP RACK: %v", tcpipErr)
|
||||
}
|
||||
cubicOpt := tcpip.CongestionControlOption("cubic")
|
||||
tcpipErr = ipstack.SetTransportProtocolOption(tcp.ProtocolNumber, &cubicOpt)
|
||||
// gVisor defaults to reno at the time of writing. We explicitly set reno
|
||||
// congestion control in order to prevent unexpected changes. Netstack
|
||||
// has an int overflow in sender congestion window arithmetic that is more
|
||||
// prone to trigger with cubic congestion control.
|
||||
// See https://github.com/google/gvisor/issues/11632
|
||||
renoOpt := tcpip.CongestionControlOption("reno")
|
||||
tcpipErr = ipstack.SetTransportProtocolOption(tcp.ProtocolNumber, &renoOpt)
|
||||
if tcpipErr != nil {
|
||||
return nil, fmt.Errorf("could not set cubic congestion control: %v", tcpipErr)
|
||||
return nil, fmt.Errorf("could not set reno congestion control: %v", tcpipErr)
|
||||
}
|
||||
err := setTCPBufSizes(ipstack)
|
||||
if err != nil {
|
||||
@@ -337,7 +344,7 @@ func Create(logf logger.Logf, tundev *tstun.Wrapper, e wgengine.Engine, mc *magi
|
||||
}
|
||||
supportedGSOKind := stack.GSONotSupported
|
||||
supportedGROKind := groNotSupported
|
||||
if runtime.GOOS == "linux" {
|
||||
if runtime.GOOS == "linux" && buildfeatures.HasGRO {
|
||||
// TODO(jwhited): add Windows support https://github.com/tailscale/corp/issues/21874
|
||||
supportedGROKind = tcpGROSupported
|
||||
supportedGSOKind = stack.HostGSOSupported
|
||||
@@ -571,9 +578,16 @@ func (ns *Impl) decrementInFlightTCPForward(tei stack.TransportEndpointID, remot
|
||||
}
|
||||
}
|
||||
|
||||
// LocalBackend is a fake name for *ipnlocal.LocalBackend to avoid an import cycle.
|
||||
type LocalBackend = any
|
||||
|
||||
// Start sets up all the handlers so netstack can start working. Implements
|
||||
// wgengine.FakeImpl.
|
||||
func (ns *Impl) Start(lb *ipnlocal.LocalBackend) error {
|
||||
func (ns *Impl) Start(b LocalBackend) error {
|
||||
if b == nil {
|
||||
panic("nil LocalBackend interface")
|
||||
}
|
||||
lb := b.(*ipnlocal.LocalBackend)
|
||||
if lb == nil {
|
||||
panic("nil LocalBackend")
|
||||
}
|
||||
@@ -637,13 +651,15 @@ func (ns *Impl) UpdateNetstackIPs(nm *netmap.NetworkMap) {
|
||||
var selfNode tailcfg.NodeView
|
||||
var serviceAddrSet set.Set[netip.Addr]
|
||||
if nm != nil {
|
||||
vipServiceIPMap := nm.GetVIPServiceIPMap()
|
||||
serviceAddrSet = make(set.Set[netip.Addr], len(vipServiceIPMap)*2)
|
||||
for _, addrs := range vipServiceIPMap {
|
||||
serviceAddrSet.AddSlice(addrs)
|
||||
}
|
||||
ns.atomicIsLocalIPFunc.Store(ipset.NewContainsIPFunc(nm.GetAddresses()))
|
||||
ns.atomicIsVIPServiceIPFunc.Store(serviceAddrSet.Contains)
|
||||
if buildfeatures.HasServe {
|
||||
vipServiceIPMap := nm.GetVIPServiceIPMap()
|
||||
serviceAddrSet = make(set.Set[netip.Addr], len(vipServiceIPMap)*2)
|
||||
for _, addrs := range vipServiceIPMap {
|
||||
serviceAddrSet.AddSlice(addrs)
|
||||
}
|
||||
ns.atomicIsVIPServiceIPFunc.Store(serviceAddrSet.Contains)
|
||||
}
|
||||
selfNode = nm.SelfNode
|
||||
} else {
|
||||
ns.atomicIsLocalIPFunc.Store(ipset.FalseContainsIPFunc())
|
||||
@@ -1026,6 +1042,9 @@ func (ns *Impl) isLocalIP(ip netip.Addr) bool {
|
||||
// isVIPServiceIP reports whether ip is an IP address that's
|
||||
// assigned to a VIP service.
|
||||
func (ns *Impl) isVIPServiceIP(ip netip.Addr) bool {
|
||||
if !buildfeatures.HasServe {
|
||||
return false
|
||||
}
|
||||
return ns.atomicIsVIPServiceIPFunc.Load()(ip)
|
||||
}
|
||||
|
||||
@@ -1068,7 +1087,7 @@ func (ns *Impl) shouldProcessInbound(p *packet.Parsed, t *tstun.Wrapper) bool {
|
||||
return true
|
||||
}
|
||||
}
|
||||
if isService {
|
||||
if buildfeatures.HasServe && isService {
|
||||
if p.IsEchoRequest() {
|
||||
return true
|
||||
}
|
||||
@@ -1429,6 +1448,13 @@ func (ns *Impl) acceptTCP(r *tcp.ForwarderRequest) {
|
||||
}
|
||||
}
|
||||
|
||||
// tcpCloser is an interface to abstract around various TCPConn types that
|
||||
// allow closing of the read and write streams independently of each other.
|
||||
type tcpCloser interface {
|
||||
CloseRead() error
|
||||
CloseWrite() error
|
||||
}
|
||||
|
||||
func (ns *Impl) forwardTCP(getClient func(...tcpip.SettableSocketOption) *gonet.TCPConn, clientRemoteIP netip.Addr, wq *waiter.Queue, dialAddr netip.AddrPort) (handled bool) {
|
||||
dialAddrStr := dialAddr.String()
|
||||
if debugNetstack() {
|
||||
@@ -1457,7 +1483,7 @@ func (ns *Impl) forwardTCP(getClient func(...tcpip.SettableSocketOption) *gonet.
|
||||
}()
|
||||
|
||||
// Attempt to dial the outbound connection before we accept the inbound one.
|
||||
var dialFunc func(context.Context, string, string) (net.Conn, error)
|
||||
var dialFunc netx.DialFunc
|
||||
if ns.forwardDialFunc != nil {
|
||||
dialFunc = ns.forwardDialFunc
|
||||
} else {
|
||||
@@ -1495,18 +1521,48 @@ func (ns *Impl) forwardTCP(getClient func(...tcpip.SettableSocketOption) *gonet.
|
||||
}
|
||||
defer client.Close()
|
||||
|
||||
// As of 2025-07-03, backend is always either a net.TCPConn
|
||||
// from stdDialer.DialContext (which has the requisite functions),
|
||||
// or nil from hangDialer in tests (in which case we would have
|
||||
// errored out by now), so this conversion should always succeed.
|
||||
backendTCPCloser, backendIsTCPCloser := backend.(tcpCloser)
|
||||
connClosed := make(chan error, 2)
|
||||
go func() {
|
||||
_, err := io.Copy(backend, client)
|
||||
if err != nil {
|
||||
err = fmt.Errorf("client -> backend: %w", err)
|
||||
}
|
||||
connClosed <- err
|
||||
err = nil
|
||||
if backendIsTCPCloser {
|
||||
err = backendTCPCloser.CloseWrite()
|
||||
}
|
||||
err = errors.Join(err, client.CloseRead())
|
||||
if err != nil {
|
||||
ns.logf("client -> backend close connection: %v", err)
|
||||
}
|
||||
}()
|
||||
go func() {
|
||||
_, err := io.Copy(client, backend)
|
||||
if err != nil {
|
||||
err = fmt.Errorf("backend -> client: %w", err)
|
||||
}
|
||||
connClosed <- err
|
||||
err = nil
|
||||
if backendIsTCPCloser {
|
||||
err = backendTCPCloser.CloseRead()
|
||||
}
|
||||
err = errors.Join(err, client.CloseWrite())
|
||||
if err != nil {
|
||||
ns.logf("backend -> client close connection: %v", err)
|
||||
}
|
||||
}()
|
||||
err = <-connClosed
|
||||
if err != nil {
|
||||
ns.logf("proxy connection closed with error: %v", err)
|
||||
// Wait for both ends of the connection to close.
|
||||
for range 2 {
|
||||
err = <-connClosed
|
||||
if err != nil {
|
||||
ns.logf("proxy connection closed with error: %v", err)
|
||||
}
|
||||
}
|
||||
ns.logf("[v2] netstack: forwarder connection to %s closed", dialAddrStr)
|
||||
return
|
||||
@@ -1849,7 +1905,6 @@ func (ns *Impl) ExpVar() expvar.Var {
|
||||
{"option_unknown_received", ipStats.OptionUnknownReceived},
|
||||
}
|
||||
for _, metric := range ipMetrics {
|
||||
metric := metric
|
||||
m.Set("counter_ip_"+metric.name, expvar.Func(func() any {
|
||||
return readStatCounter(metric.field)
|
||||
}))
|
||||
@@ -1876,7 +1931,6 @@ func (ns *Impl) ExpVar() expvar.Var {
|
||||
{"errors", fwdStats.Errors},
|
||||
}
|
||||
for _, metric := range fwdMetrics {
|
||||
metric := metric
|
||||
m.Set("counter_ip_forward_"+metric.name, expvar.Func(func() any {
|
||||
return readStatCounter(metric.field)
|
||||
}))
|
||||
@@ -1920,7 +1974,6 @@ func (ns *Impl) ExpVar() expvar.Var {
|
||||
{"forward_max_in_flight_drop", tcpStats.ForwardMaxInFlightDrop},
|
||||
}
|
||||
for _, metric := range tcpMetrics {
|
||||
metric := metric
|
||||
m.Set("counter_tcp_"+metric.name, expvar.Func(func() any {
|
||||
return readStatCounter(metric.field)
|
||||
}))
|
||||
@@ -1947,7 +2000,6 @@ func (ns *Impl) ExpVar() expvar.Var {
|
||||
{"checksum_errors", udpStats.ChecksumErrors},
|
||||
}
|
||||
for _, metric := range udpMetrics {
|
||||
metric := metric
|
||||
m.Set("counter_udp_"+metric.name, expvar.Func(func() any {
|
||||
return readStatCounter(metric.field)
|
||||
}))
|
||||
|
||||
Reference in New Issue
Block a user