Update
This commit is contained in:
2
vendor/tailscale.com/wgengine/netstack/gro/gro.go
generated
vendored
2
vendor/tailscale.com/wgengine/netstack/gro/gro.go
generated
vendored
@@ -1,6 +1,8 @@
|
||||
// Copyright (c) Tailscale Inc & AUTHORS
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
//go:build !ts_omit_netstack
|
||||
|
||||
// Package gro implements GRO for the receive (write) path into gVisor.
|
||||
package gro
|
||||
|
||||
|
||||
2
vendor/tailscale.com/wgengine/netstack/gro/gro_default.go
generated
vendored
2
vendor/tailscale.com/wgengine/netstack/gro/gro_default.go
generated
vendored
@@ -1,7 +1,7 @@
|
||||
// Copyright (c) Tailscale Inc & AUTHORS
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
//go:build !ios
|
||||
//go:build !ios && !ts_omit_gro
|
||||
|
||||
package gro
|
||||
|
||||
|
||||
@@ -1,22 +1,27 @@
|
||||
// Copyright (c) Tailscale Inc & AUTHORS
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
//go:build ios
|
||||
//go:build ios || ts_omit_gro
|
||||
|
||||
package gro
|
||||
|
||||
import (
|
||||
"gvisor.dev/gvisor/pkg/tcpip/stack"
|
||||
"runtime"
|
||||
|
||||
"tailscale.com/net/packet"
|
||||
)
|
||||
|
||||
type GRO struct{}
|
||||
|
||||
func NewGRO() *GRO {
|
||||
panic("unsupported on iOS")
|
||||
if runtime.GOOS == "ios" {
|
||||
panic("unsupported on iOS")
|
||||
}
|
||||
panic("GRO disabled in build")
|
||||
|
||||
}
|
||||
|
||||
func (g *GRO) SetDispatcher(_ stack.NetworkDispatcher) {}
|
||||
func (g *GRO) SetDispatcher(any) {}
|
||||
|
||||
func (g *GRO) Enqueue(_ *packet.Parsed) {}
|
||||
|
||||
10
vendor/tailscale.com/wgengine/netstack/gro/netstack_disabled.go
generated
vendored
Normal file
10
vendor/tailscale.com/wgengine/netstack/gro/netstack_disabled.go
generated
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
// Copyright (c) Tailscale Inc & AUTHORS
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
//go:build ts_omit_netstack
|
||||
|
||||
package gro
|
||||
|
||||
func RXChecksumOffload(any) any {
|
||||
panic("unreachable")
|
||||
}
|
||||
113
vendor/tailscale.com/wgengine/netstack/link_endpoint.go
generated
vendored
113
vendor/tailscale.com/wgengine/netstack/link_endpoint.go
generated
vendored
@@ -10,6 +10,7 @@ import (
|
||||
"gvisor.dev/gvisor/pkg/tcpip"
|
||||
"gvisor.dev/gvisor/pkg/tcpip/header"
|
||||
"gvisor.dev/gvisor/pkg/tcpip/stack"
|
||||
"tailscale.com/feature/buildfeatures"
|
||||
"tailscale.com/net/packet"
|
||||
"tailscale.com/types/ipproto"
|
||||
"tailscale.com/wgengine/netstack/gro"
|
||||
@@ -125,24 +126,24 @@ func newLinkEndpoint(size int, mtu uint32, linkAddr tcpip.LinkAddress, supported
|
||||
return le
|
||||
}
|
||||
|
||||
// gro attempts to enqueue p on g if l supports a GRO kind matching the
|
||||
// gro attempts to enqueue p on g if ep supports a GRO kind matching the
|
||||
// transport protocol carried in p. gro may allocate g if it is nil. gro can
|
||||
// either return the existing g, a newly allocated one, or nil. Callers are
|
||||
// responsible for calling Flush() on the returned value if it is non-nil once
|
||||
// they have finished iterating through all GRO candidates for a given vector.
|
||||
// If gro allocates a *gro.GRO it will have l's stack.NetworkDispatcher set via
|
||||
// If gro allocates a *gro.GRO it will have ep's stack.NetworkDispatcher set via
|
||||
// SetDispatcher().
|
||||
func (l *linkEndpoint) gro(p *packet.Parsed, g *gro.GRO) *gro.GRO {
|
||||
if l.supportedGRO == groNotSupported || p.IPProto != ipproto.TCP {
|
||||
func (ep *linkEndpoint) gro(p *packet.Parsed, g *gro.GRO) *gro.GRO {
|
||||
if !buildfeatures.HasGRO || ep.supportedGRO == groNotSupported || p.IPProto != ipproto.TCP {
|
||||
// IPv6 may have extension headers preceding a TCP header, but we trade
|
||||
// for a fast path and assume p cannot be coalesced in such a case.
|
||||
l.injectInbound(p)
|
||||
ep.injectInbound(p)
|
||||
return g
|
||||
}
|
||||
if g == nil {
|
||||
l.mu.RLock()
|
||||
d := l.dispatcher
|
||||
l.mu.RUnlock()
|
||||
ep.mu.RLock()
|
||||
d := ep.dispatcher
|
||||
ep.mu.RUnlock()
|
||||
g = gro.NewGRO()
|
||||
g.SetDispatcher(d)
|
||||
}
|
||||
@@ -153,40 +154,40 @@ func (l *linkEndpoint) gro(p *packet.Parsed, g *gro.GRO) *gro.GRO {
|
||||
// Close closes l. Further packet injections will return an error, and all
|
||||
// pending packets are discarded. Close may be called concurrently with
|
||||
// WritePackets.
|
||||
func (l *linkEndpoint) Close() {
|
||||
l.mu.Lock()
|
||||
l.dispatcher = nil
|
||||
l.mu.Unlock()
|
||||
l.q.Close()
|
||||
l.Drain()
|
||||
func (ep *linkEndpoint) Close() {
|
||||
ep.mu.Lock()
|
||||
ep.dispatcher = nil
|
||||
ep.mu.Unlock()
|
||||
ep.q.Close()
|
||||
ep.Drain()
|
||||
}
|
||||
|
||||
// Read does non-blocking read one packet from the outbound packet queue.
|
||||
func (l *linkEndpoint) Read() *stack.PacketBuffer {
|
||||
return l.q.Read()
|
||||
func (ep *linkEndpoint) Read() *stack.PacketBuffer {
|
||||
return ep.q.Read()
|
||||
}
|
||||
|
||||
// ReadContext does blocking read for one packet from the outbound packet queue.
|
||||
// It can be cancelled by ctx, and in this case, it returns nil.
|
||||
func (l *linkEndpoint) ReadContext(ctx context.Context) *stack.PacketBuffer {
|
||||
return l.q.ReadContext(ctx)
|
||||
func (ep *linkEndpoint) ReadContext(ctx context.Context) *stack.PacketBuffer {
|
||||
return ep.q.ReadContext(ctx)
|
||||
}
|
||||
|
||||
// Drain removes all outbound packets from the channel and counts them.
|
||||
func (l *linkEndpoint) Drain() int {
|
||||
return l.q.Drain()
|
||||
func (ep *linkEndpoint) Drain() int {
|
||||
return ep.q.Drain()
|
||||
}
|
||||
|
||||
// NumQueued returns the number of packets queued for outbound.
|
||||
func (l *linkEndpoint) NumQueued() int {
|
||||
return l.q.Num()
|
||||
func (ep *linkEndpoint) NumQueued() int {
|
||||
return ep.q.Num()
|
||||
}
|
||||
|
||||
func (l *linkEndpoint) injectInbound(p *packet.Parsed) {
|
||||
l.mu.RLock()
|
||||
d := l.dispatcher
|
||||
l.mu.RUnlock()
|
||||
if d == nil {
|
||||
func (ep *linkEndpoint) injectInbound(p *packet.Parsed) {
|
||||
ep.mu.RLock()
|
||||
d := ep.dispatcher
|
||||
ep.mu.RUnlock()
|
||||
if d == nil || !buildfeatures.HasNetstack {
|
||||
return
|
||||
}
|
||||
pkt := gro.RXChecksumOffload(p)
|
||||
@@ -199,35 +200,35 @@ func (l *linkEndpoint) injectInbound(p *packet.Parsed) {
|
||||
|
||||
// Attach saves the stack network-layer dispatcher for use later when packets
|
||||
// are injected.
|
||||
func (l *linkEndpoint) Attach(dispatcher stack.NetworkDispatcher) {
|
||||
l.mu.Lock()
|
||||
defer l.mu.Unlock()
|
||||
l.dispatcher = dispatcher
|
||||
func (ep *linkEndpoint) Attach(dispatcher stack.NetworkDispatcher) {
|
||||
ep.mu.Lock()
|
||||
defer ep.mu.Unlock()
|
||||
ep.dispatcher = dispatcher
|
||||
}
|
||||
|
||||
// IsAttached implements stack.LinkEndpoint.IsAttached.
|
||||
func (l *linkEndpoint) IsAttached() bool {
|
||||
l.mu.RLock()
|
||||
defer l.mu.RUnlock()
|
||||
return l.dispatcher != nil
|
||||
func (ep *linkEndpoint) IsAttached() bool {
|
||||
ep.mu.RLock()
|
||||
defer ep.mu.RUnlock()
|
||||
return ep.dispatcher != nil
|
||||
}
|
||||
|
||||
// MTU implements stack.LinkEndpoint.MTU.
|
||||
func (l *linkEndpoint) MTU() uint32 {
|
||||
l.mu.RLock()
|
||||
defer l.mu.RUnlock()
|
||||
return l.mtu
|
||||
func (ep *linkEndpoint) MTU() uint32 {
|
||||
ep.mu.RLock()
|
||||
defer ep.mu.RUnlock()
|
||||
return ep.mtu
|
||||
}
|
||||
|
||||
// SetMTU implements stack.LinkEndpoint.SetMTU.
|
||||
func (l *linkEndpoint) SetMTU(mtu uint32) {
|
||||
l.mu.Lock()
|
||||
defer l.mu.Unlock()
|
||||
l.mtu = mtu
|
||||
func (ep *linkEndpoint) SetMTU(mtu uint32) {
|
||||
ep.mu.Lock()
|
||||
defer ep.mu.Unlock()
|
||||
ep.mtu = mtu
|
||||
}
|
||||
|
||||
// Capabilities implements stack.LinkEndpoint.Capabilities.
|
||||
func (l *linkEndpoint) Capabilities() stack.LinkEndpointCapabilities {
|
||||
func (ep *linkEndpoint) Capabilities() stack.LinkEndpointCapabilities {
|
||||
// We are required to offload RX checksum validation for the purposes of
|
||||
// GRO.
|
||||
return stack.CapabilityRXChecksumOffload
|
||||
@@ -241,8 +242,8 @@ func (*linkEndpoint) GSOMaxSize() uint32 {
|
||||
}
|
||||
|
||||
// SupportedGSO implements stack.GSOEndpoint.
|
||||
func (l *linkEndpoint) SupportedGSO() stack.SupportedGSO {
|
||||
return l.SupportedGSOKind
|
||||
func (ep *linkEndpoint) SupportedGSO() stack.SupportedGSO {
|
||||
return ep.SupportedGSOKind
|
||||
}
|
||||
|
||||
// MaxHeaderLength returns the maximum size of the link layer header. Given it
|
||||
@@ -252,22 +253,22 @@ func (*linkEndpoint) MaxHeaderLength() uint16 {
|
||||
}
|
||||
|
||||
// LinkAddress returns the link address of this endpoint.
|
||||
func (l *linkEndpoint) LinkAddress() tcpip.LinkAddress {
|
||||
l.mu.RLock()
|
||||
defer l.mu.RUnlock()
|
||||
return l.linkAddr
|
||||
func (ep *linkEndpoint) LinkAddress() tcpip.LinkAddress {
|
||||
ep.mu.RLock()
|
||||
defer ep.mu.RUnlock()
|
||||
return ep.linkAddr
|
||||
}
|
||||
|
||||
// SetLinkAddress implements stack.LinkEndpoint.SetLinkAddress.
|
||||
func (l *linkEndpoint) SetLinkAddress(addr tcpip.LinkAddress) {
|
||||
l.mu.Lock()
|
||||
defer l.mu.Unlock()
|
||||
l.linkAddr = addr
|
||||
func (ep *linkEndpoint) SetLinkAddress(addr tcpip.LinkAddress) {
|
||||
ep.mu.Lock()
|
||||
defer ep.mu.Unlock()
|
||||
ep.linkAddr = addr
|
||||
}
|
||||
|
||||
// WritePackets stores outbound packets into the channel.
|
||||
// Multiple concurrent calls are permitted.
|
||||
func (l *linkEndpoint) WritePackets(pkts stack.PacketBufferList) (int, tcpip.Error) {
|
||||
func (ep *linkEndpoint) WritePackets(pkts stack.PacketBufferList) (int, tcpip.Error) {
|
||||
n := 0
|
||||
// TODO(jwhited): evaluate writing a stack.PacketBufferList instead of a
|
||||
// single packet. We can split 2 x 64K GSO across
|
||||
@@ -277,7 +278,7 @@ func (l *linkEndpoint) WritePackets(pkts stack.PacketBufferList) (int, tcpip.Err
|
||||
// control MTU (and by effect TCP MSS in gVisor) we *shouldn't* expect to
|
||||
// ever overflow 128 slots (see wireguard-go/tun.ErrTooManySegments usage).
|
||||
for _, pkt := range pkts.AsSlice() {
|
||||
if err := l.q.Write(pkt); err != nil {
|
||||
if err := ep.q.Write(pkt); err != nil {
|
||||
if _, ok := err.(*tcpip.ErrNoBufferSpace); !ok && n == 0 {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
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)
|
||||
}))
|
||||
|
||||
5
vendor/tailscale.com/wgengine/netstack/netstack_userping.go
generated
vendored
5
vendor/tailscale.com/wgengine/netstack/netstack_userping.go
generated
vendored
@@ -13,6 +13,7 @@ import (
|
||||
"runtime"
|
||||
"time"
|
||||
|
||||
"tailscale.com/feature/buildfeatures"
|
||||
"tailscale.com/version/distro"
|
||||
)
|
||||
|
||||
@@ -20,7 +21,7 @@ import (
|
||||
// CAP_NET_RAW from tailscaled's binary.
|
||||
var setAmbientCapsRaw func(*exec.Cmd)
|
||||
|
||||
var isSynology = runtime.GOOS == "linux" && distro.Get() == distro.Synology
|
||||
var isSynology = runtime.GOOS == "linux" && buildfeatures.HasSynology && distro.Get() == distro.Synology
|
||||
|
||||
// sendOutboundUserPing sends a non-privileged ICMP (or ICMPv6) ping to dstIP with the given timeout.
|
||||
func (ns *Impl) sendOutboundUserPing(dstIP netip.Addr, timeout time.Duration) error {
|
||||
@@ -61,7 +62,7 @@ func (ns *Impl) sendOutboundUserPing(dstIP netip.Addr, timeout time.Duration) er
|
||||
ping = "/bin/ping"
|
||||
}
|
||||
cmd := exec.Command(ping, "-c", "1", "-W", "3", dstIP.String())
|
||||
if isSynology && os.Getuid() != 0 {
|
||||
if buildfeatures.HasSynology && isSynology && os.Getuid() != 0 {
|
||||
// On DSM7 we run as non-root and need to pass
|
||||
// CAP_NET_RAW if our binary has it.
|
||||
setAmbientCapsRaw(cmd)
|
||||
|
||||
Reference in New Issue
Block a user