platform: Improve iOS OOM killer

This commit is contained in:
世界
2026-02-26 12:54:00 +08:00
parent 0bc66e5a56
commit cf4791f1ad
29 changed files with 458 additions and 357 deletions

View File

@@ -1 +1 @@
abd78bb191a815236485ad929716845ffb41465a 34ec1a064c64f274c4e70bf7a9c7de4bb12331f6

View File

@@ -9,6 +9,10 @@ import (
type ConnectionManager interface { type ConnectionManager interface {
Lifecycle Lifecycle
Count() int
CloseAll()
TrackConn(conn net.Conn) net.Conn
TrackPacketConn(conn net.PacketConn) net.PacketConn
NewConnection(ctx context.Context, this N.Dialer, conn net.Conn, metadata InboundContext, onClose N.CloseHandlerFunc) NewConnection(ctx context.Context, this N.Dialer, conn net.Conn, metadata InboundContext, onClose N.CloseHandlerFunc)
NewPacketConnection(ctx context.Context, this N.Dialer, conn N.PacketConn, metadata InboundContext, onClose N.CloseHandlerFunc) NewPacketConnection(ctx context.Context, this N.Dialer, conn N.PacketConn, metadata InboundContext, onClose N.CloseHandlerFunc)
} }

5
box.go
View File

@@ -125,7 +125,10 @@ func New(options Options) (*Box, error) {
ctx = pause.WithDefaultManager(ctx) ctx = pause.WithDefaultManager(ctx)
experimentalOptions := common.PtrValueOrDefault(options.Experimental) experimentalOptions := common.PtrValueOrDefault(options.Experimental)
applyDebugOptions(common.PtrValueOrDefault(experimentalOptions.Debug)) err := applyDebugOptions(common.PtrValueOrDefault(experimentalOptions.Debug))
if err != nil {
return nil, err
}
var needCacheFile bool var needCacheFile bool
var needClashAPI bool var needClashAPI bool
var needV2RayAPI bool var needV2RayAPI bool

View File

@@ -63,7 +63,7 @@ func init() {
sharedFlags = append(sharedFlags, "-ldflags", "-X github.com/sagernet/sing-box/constant.Version="+currentTag+" -X internal/godebug.defaultGODEBUG=multipathtcp=0 -s -w -buildid= -checklinkname=0") sharedFlags = append(sharedFlags, "-ldflags", "-X github.com/sagernet/sing-box/constant.Version="+currentTag+" -X internal/godebug.defaultGODEBUG=multipathtcp=0 -s -w -buildid= -checklinkname=0")
debugFlags = append(debugFlags, "-ldflags", "-X github.com/sagernet/sing-box/constant.Version="+currentTag+" -X internal/godebug.defaultGODEBUG=multipathtcp=0 -checklinkname=0") debugFlags = append(debugFlags, "-ldflags", "-X github.com/sagernet/sing-box/constant.Version="+currentTag+" -X internal/godebug.defaultGODEBUG=multipathtcp=0 -checklinkname=0")
sharedTags = append(sharedTags, "with_gvisor", "with_quic", "with_wireguard", "with_utls", "with_naive_outbound", "with_clash_api", "with_conntrack", "badlinkname", "tfogo_checklinkname0") sharedTags = append(sharedTags, "with_gvisor", "with_quic", "with_wireguard", "with_utls", "with_naive_outbound", "with_clash_api", "badlinkname", "tfogo_checklinkname0")
darwinTags = append(darwinTags, "with_dhcp", "grpcnotrace") darwinTags = append(darwinTags, "with_dhcp", "grpcnotrace")
// memcTags = append(memcTags, "with_tailscale") // memcTags = append(memcTags, "with_tailscale")
sharedTags = append(sharedTags, "with_tailscale", "ts_omit_logtail", "ts_omit_ssh", "ts_omit_drive", "ts_omit_taildrop", "ts_omit_webclient", "ts_omit_doctor", "ts_omit_capture", "ts_omit_kube", "ts_omit_aws", "ts_omit_synology", "ts_omit_bird") sharedTags = append(sharedTags, "with_tailscale", "ts_omit_logtail", "ts_omit_ssh", "ts_omit_drive", "ts_omit_taildrop", "ts_omit_webclient", "ts_omit_doctor", "ts_omit_capture", "ts_omit_kube", "ts_omit_aws", "ts_omit_synology", "ts_omit_bird")

View File

@@ -1,54 +0,0 @@
package conntrack
import (
"io"
"net"
"github.com/sagernet/sing/common/x/list"
)
type Conn struct {
net.Conn
element *list.Element[io.Closer]
}
func NewConn(conn net.Conn) (net.Conn, error) {
connAccess.Lock()
element := openConnection.PushBack(conn)
connAccess.Unlock()
if KillerEnabled {
err := KillerCheck()
if err != nil {
conn.Close()
return nil, err
}
}
return &Conn{
Conn: conn,
element: element,
}, nil
}
func (c *Conn) Close() error {
if c.element.Value != nil {
connAccess.Lock()
if c.element.Value != nil {
openConnection.Remove(c.element)
c.element.Value = nil
}
connAccess.Unlock()
}
return c.Conn.Close()
}
func (c *Conn) Upstream() any {
return c.Conn
}
func (c *Conn) ReaderReplaceable() bool {
return true
}
func (c *Conn) WriterReplaceable() bool {
return true
}

View File

@@ -1,35 +0,0 @@
package conntrack
import (
runtimeDebug "runtime/debug"
"time"
E "github.com/sagernet/sing/common/exceptions"
"github.com/sagernet/sing/common/memory"
)
var (
KillerEnabled bool
MemoryLimit uint64
killerLastCheck time.Time
)
func KillerCheck() error {
if !KillerEnabled {
return nil
}
nowTime := time.Now()
if nowTime.Sub(killerLastCheck) < 3*time.Second {
return nil
}
killerLastCheck = nowTime
if memory.Total() > MemoryLimit {
Close()
go func() {
time.Sleep(time.Second)
runtimeDebug.FreeOSMemory()
}()
return E.New("out of memory")
}
return nil
}

View File

@@ -1,55 +0,0 @@
package conntrack
import (
"io"
"net"
"github.com/sagernet/sing/common/bufio"
"github.com/sagernet/sing/common/x/list"
)
type PacketConn struct {
net.PacketConn
element *list.Element[io.Closer]
}
func NewPacketConn(conn net.PacketConn) (net.PacketConn, error) {
connAccess.Lock()
element := openConnection.PushBack(conn)
connAccess.Unlock()
if KillerEnabled {
err := KillerCheck()
if err != nil {
conn.Close()
return nil, err
}
}
return &PacketConn{
PacketConn: conn,
element: element,
}, nil
}
func (c *PacketConn) Close() error {
if c.element.Value != nil {
connAccess.Lock()
if c.element.Value != nil {
openConnection.Remove(c.element)
c.element.Value = nil
}
connAccess.Unlock()
}
return c.PacketConn.Close()
}
func (c *PacketConn) Upstream() any {
return bufio.NewPacketConn(c.PacketConn)
}
func (c *PacketConn) ReaderReplaceable() bool {
return true
}
func (c *PacketConn) WriterReplaceable() bool {
return true
}

View File

@@ -1,47 +0,0 @@
package conntrack
import (
"io"
"sync"
"github.com/sagernet/sing/common"
"github.com/sagernet/sing/common/x/list"
)
var (
connAccess sync.RWMutex
openConnection list.List[io.Closer]
)
func Count() int {
if !Enabled {
return 0
}
return openConnection.Len()
}
func List() []io.Closer {
if !Enabled {
return nil
}
connAccess.RLock()
defer connAccess.RUnlock()
connList := make([]io.Closer, 0, openConnection.Len())
for element := openConnection.Front(); element != nil; element = element.Next() {
connList = append(connList, element.Value)
}
return connList
}
func Close() {
if !Enabled {
return
}
connAccess.Lock()
defer connAccess.Unlock()
for element := openConnection.Front(); element != nil; element = element.Next() {
common.Close(element.Value)
element.Value = nil
}
openConnection.Init()
}

View File

@@ -1,5 +0,0 @@
//go:build !with_conntrack
package conntrack
const Enabled = false

View File

@@ -1,5 +0,0 @@
//go:build with_conntrack
package conntrack
const Enabled = true

View File

@@ -9,7 +9,6 @@ import (
"time" "time"
"github.com/sagernet/sing-box/adapter" "github.com/sagernet/sing-box/adapter"
"github.com/sagernet/sing-box/common/conntrack"
"github.com/sagernet/sing-box/common/listener" "github.com/sagernet/sing-box/common/listener"
C "github.com/sagernet/sing-box/constant" C "github.com/sagernet/sing-box/constant"
"github.com/sagernet/sing-box/option" "github.com/sagernet/sing-box/option"
@@ -37,6 +36,7 @@ type DefaultDialer struct {
udpAddr4 string udpAddr4 string
udpAddr6 string udpAddr6 string
netns string netns string
connectionManager adapter.ConnectionManager
networkManager adapter.NetworkManager networkManager adapter.NetworkManager
networkStrategy *C.NetworkStrategy networkStrategy *C.NetworkStrategy
defaultNetworkStrategy bool defaultNetworkStrategy bool
@@ -47,6 +47,7 @@ type DefaultDialer struct {
} }
func NewDefault(ctx context.Context, options option.DialerOptions) (*DefaultDialer, error) { func NewDefault(ctx context.Context, options option.DialerOptions) (*DefaultDialer, error) {
connectionManager := service.FromContext[adapter.ConnectionManager](ctx)
networkManager := service.FromContext[adapter.NetworkManager](ctx) networkManager := service.FromContext[adapter.NetworkManager](ctx)
platformInterface := service.FromContext[adapter.PlatformInterface](ctx) platformInterface := service.FromContext[adapter.PlatformInterface](ctx)
@@ -206,6 +207,7 @@ func NewDefault(ctx context.Context, options option.DialerOptions) (*DefaultDial
udpAddr4: udpAddr4, udpAddr4: udpAddr4,
udpAddr6: udpAddr6, udpAddr6: udpAddr6,
netns: options.NetNs, netns: options.NetNs,
connectionManager: connectionManager,
networkManager: networkManager, networkManager: networkManager,
networkStrategy: networkStrategy, networkStrategy: networkStrategy,
defaultNetworkStrategy: defaultNetworkStrategy, defaultNetworkStrategy: defaultNetworkStrategy,
@@ -238,7 +240,7 @@ func (d *DefaultDialer) DialContext(ctx context.Context, network string, address
return nil, E.New("domain not resolved") return nil, E.New("domain not resolved")
} }
if d.networkStrategy == nil { if d.networkStrategy == nil {
return trackConn(listener.ListenNetworkNamespace[net.Conn](d.netns, func() (net.Conn, error) { return d.trackConn(listener.ListenNetworkNamespace[net.Conn](d.netns, func() (net.Conn, error) {
switch N.NetworkName(network) { switch N.NetworkName(network) {
case N.NetworkUDP: case N.NetworkUDP:
if !address.IsIPv6() { if !address.IsIPv6() {
@@ -303,12 +305,12 @@ func (d *DefaultDialer) DialParallelInterface(ctx context.Context, network strin
if !fastFallback && !isPrimary { if !fastFallback && !isPrimary {
d.networkLastFallback.Store(time.Now()) d.networkLastFallback.Store(time.Now())
} }
return trackConn(conn, nil) return d.trackConn(conn, nil)
} }
func (d *DefaultDialer) ListenPacket(ctx context.Context, destination M.Socksaddr) (net.PacketConn, error) { func (d *DefaultDialer) ListenPacket(ctx context.Context, destination M.Socksaddr) (net.PacketConn, error) {
if d.networkStrategy == nil { if d.networkStrategy == nil {
return trackPacketConn(listener.ListenNetworkNamespace[net.PacketConn](d.netns, func() (net.PacketConn, error) { return d.trackPacketConn(listener.ListenNetworkNamespace[net.PacketConn](d.netns, func() (net.PacketConn, error) {
if destination.IsIPv6() { if destination.IsIPv6() {
return d.udpListener.ListenPacket(ctx, N.NetworkUDP, d.udpAddr6) return d.udpListener.ListenPacket(ctx, N.NetworkUDP, d.udpAddr6)
} else if destination.IsIPv4() && !destination.Addr.IsUnspecified() { } else if destination.IsIPv4() && !destination.Addr.IsUnspecified() {
@@ -360,23 +362,23 @@ func (d *DefaultDialer) ListenSerialInterfacePacket(ctx context.Context, destina
return nil, err return nil, err
} }
} }
return trackPacketConn(packetConn, nil) return d.trackPacketConn(packetConn, nil)
} }
func (d *DefaultDialer) WireGuardControl() control.Func { func (d *DefaultDialer) WireGuardControl() control.Func {
return d.udpListener.Control return d.udpListener.Control
} }
func trackConn(conn net.Conn, err error) (net.Conn, error) { func (d *DefaultDialer) trackConn(conn net.Conn, err error) (net.Conn, error) {
if !conntrack.Enabled || err != nil { if d.connectionManager == nil || err != nil {
return conn, err return conn, err
} }
return conntrack.NewConn(conn) return d.connectionManager.TrackConn(conn), nil
} }
func trackPacketConn(conn net.PacketConn, err error) (net.PacketConn, error) { func (d *DefaultDialer) trackPacketConn(conn net.PacketConn, err error) (net.PacketConn, error) {
if !conntrack.Enabled || err != nil { if d.connectionManager == nil || err != nil {
return conn, err return conn, err
} }
return conntrack.NewPacketConn(conn) return d.connectionManager.TrackPacketConn(conn), nil
} }

View File

@@ -30,6 +30,7 @@ const (
TypeSSMAPI = "ssm-api" TypeSSMAPI = "ssm-api"
TypeCCM = "ccm" TypeCCM = "ccm"
TypeOCM = "ocm" TypeOCM = "ocm"
TypeOOMKiller = "oom-killer"
) )
const ( const (

View File

@@ -7,10 +7,12 @@ import (
"github.com/sagernet/sing-box" "github.com/sagernet/sing-box"
"github.com/sagernet/sing-box/adapter" "github.com/sagernet/sing-box/adapter"
"github.com/sagernet/sing-box/common/urltest" "github.com/sagernet/sing-box/common/urltest"
C "github.com/sagernet/sing-box/constant"
"github.com/sagernet/sing-box/experimental/deprecated" "github.com/sagernet/sing-box/experimental/deprecated"
"github.com/sagernet/sing-box/include" "github.com/sagernet/sing-box/include"
"github.com/sagernet/sing-box/log" "github.com/sagernet/sing-box/log"
"github.com/sagernet/sing-box/option" "github.com/sagernet/sing-box/option"
"github.com/sagernet/sing/common"
E "github.com/sagernet/sing/common/exceptions" E "github.com/sagernet/sing/common/exceptions"
"github.com/sagernet/sing/common/json" "github.com/sagernet/sing/common/json"
"github.com/sagernet/sing/service" "github.com/sagernet/sing/service"
@@ -21,6 +23,7 @@ type Instance struct {
ctx context.Context ctx context.Context
cancel context.CancelFunc cancel context.CancelFunc
instance *box.Box instance *box.Box
connectionManager adapter.ConnectionManager
clashServer adapter.ClashServer clashServer adapter.ClashServer
cacheFile adapter.CacheFile cacheFile adapter.CacheFile
pauseManager pause.Manager pauseManager pause.Manager
@@ -84,6 +87,15 @@ func (s *StartedService) newInstance(profileContent string, overrideOptions *Ove
} }
} }
} }
if s.oomKiller && C.IsIos {
if !common.Any(options.Services, func(it option.Service) bool {
return it.Type == C.TypeOOMKiller
}) {
options.Services = append(options.Services, option.Service{
Type: C.TypeOOMKiller,
})
}
}
urlTestHistoryStorage := urltest.NewHistoryStorage() urlTestHistoryStorage := urltest.NewHistoryStorage()
ctx = service.ContextWithPtr(ctx, urlTestHistoryStorage) ctx = service.ContextWithPtr(ctx, urlTestHistoryStorage)
i := &Instance{ i := &Instance{
@@ -101,6 +113,7 @@ func (s *StartedService) newInstance(profileContent string, overrideOptions *Ove
return nil, err return nil, err
} }
i.instance = boxInstance i.instance = boxInstance
i.connectionManager = service.FromContext[adapter.ConnectionManager](ctx)
i.clashServer = service.FromContext[adapter.ClashServer](ctx) i.clashServer = service.FromContext[adapter.ClashServer](ctx)
i.pauseManager = service.FromContext[pause.Manager](ctx) i.pauseManager = service.FromContext[pause.Manager](ctx)
i.cacheFile = service.FromContext[adapter.CacheFile](ctx) i.cacheFile = service.FromContext[adapter.CacheFile](ctx)

View File

@@ -8,7 +8,6 @@ import (
"time" "time"
"github.com/sagernet/sing-box/adapter" "github.com/sagernet/sing-box/adapter"
"github.com/sagernet/sing-box/common/conntrack"
"github.com/sagernet/sing-box/common/urltest" "github.com/sagernet/sing-box/common/urltest"
"github.com/sagernet/sing-box/experimental/clashapi" "github.com/sagernet/sing-box/experimental/clashapi"
"github.com/sagernet/sing-box/experimental/clashapi/trafficontrol" "github.com/sagernet/sing-box/experimental/clashapi/trafficontrol"
@@ -36,6 +35,7 @@ type StartedService struct {
handler PlatformHandler handler PlatformHandler
debug bool debug bool
logMaxLines int logMaxLines int
oomKiller bool
// workingDirectory string // workingDirectory string
// tempDirectory string // tempDirectory string
// userID int // userID int
@@ -67,6 +67,7 @@ type ServiceOptions struct {
Handler PlatformHandler Handler PlatformHandler
Debug bool Debug bool
LogMaxLines int LogMaxLines int
OOMKiller bool
// WorkingDirectory string // WorkingDirectory string
// TempDirectory string // TempDirectory string
// UserID int // UserID int
@@ -81,6 +82,7 @@ func NewStartedService(options ServiceOptions) *StartedService {
handler: options.Handler, handler: options.Handler,
debug: options.Debug, debug: options.Debug,
logMaxLines: options.LogMaxLines, logMaxLines: options.LogMaxLines,
oomKiller: options.OOMKiller,
// workingDirectory: options.WorkingDirectory, // workingDirectory: options.WorkingDirectory,
// tempDirectory: options.TempDirectory, // tempDirectory: options.TempDirectory,
// userID: options.UserID, // userID: options.UserID,
@@ -409,10 +411,12 @@ func (s *StartedService) readStatus() *Status {
var status Status var status Status
status.Memory = memory.Inuse() status.Memory = memory.Inuse()
status.Goroutines = int32(runtime.NumGoroutine()) status.Goroutines = int32(runtime.NumGoroutine())
status.ConnectionsOut = int32(conntrack.Count())
s.serviceAccess.RLock() s.serviceAccess.RLock()
nowService := s.instance nowService := s.instance
s.serviceAccess.RUnlock() s.serviceAccess.RUnlock()
if nowService != nil && nowService.connectionManager != nil {
status.ConnectionsOut = int32(nowService.connectionManager.Count())
}
if nowService != nil { if nowService != nil {
if clashServer := nowService.clashServer; clashServer != nil { if clashServer := nowService.clashServer; clashServer != nil {
status.TrafficAvailable = true status.TrafficAvailable = true
@@ -993,7 +997,12 @@ func (s *StartedService) CloseConnection(ctx context.Context, request *CloseConn
} }
func (s *StartedService) CloseAllConnections(ctx context.Context, empty *emptypb.Empty) (*emptypb.Empty, error) { func (s *StartedService) CloseAllConnections(ctx context.Context, empty *emptypb.Empty) (*emptypb.Empty, error) {
conntrack.Close() s.serviceAccess.RLock()
nowService := s.instance
s.serviceAccess.RUnlock()
if nowService != nil && nowService.connectionManager != nil {
nowService.connectionManager.CloseAll()
}
return &emptypb.Empty{}, nil return &emptypb.Empty{}, nil
} }

View File

@@ -3,11 +3,11 @@ package box
import ( import (
"runtime/debug" "runtime/debug"
"github.com/sagernet/sing-box/common/conntrack"
"github.com/sagernet/sing-box/option" "github.com/sagernet/sing-box/option"
E "github.com/sagernet/sing/common/exceptions"
) )
func applyDebugOptions(options option.DebugOptions) { func applyDebugOptions(options option.DebugOptions) error {
applyDebugListenOption(options) applyDebugListenOption(options)
if options.GCPercent != nil { if options.GCPercent != nil {
debug.SetGCPercent(*options.GCPercent) debug.SetGCPercent(*options.GCPercent)
@@ -26,9 +26,9 @@ func applyDebugOptions(options option.DebugOptions) {
} }
if options.MemoryLimit.Value() != 0 { if options.MemoryLimit.Value() != 0 {
debug.SetMemoryLimit(int64(float64(options.MemoryLimit.Value()) / 1.5)) debug.SetMemoryLimit(int64(float64(options.MemoryLimit.Value()) / 1.5))
conntrack.MemoryLimit = options.MemoryLimit.Value()
} }
if options.OOMKiller != nil { if options.OOMKiller != nil {
conntrack.KillerEnabled = *options.OOMKiller return E.New("legacy oom_killer in debug options is removed, use oom-killer service instead")
} }
return nil
} }

View File

@@ -60,6 +60,7 @@ func NewCommandServer(handler CommandServerHandler, platformInterface PlatformIn
Handler: (*platformHandler)(server), Handler: (*platformHandler)(server),
Debug: sDebug, Debug: sDebug,
LogMaxLines: sLogMaxLines, LogMaxLines: sLogMaxLines,
OOMKiller: memoryLimitEnabled,
// WorkingDirectory: sWorkingPath, // WorkingDirectory: sWorkingPath,
// TempDirectory: sTempPath, // TempDirectory: sTempPath,
// UserID: sUserID, // UserID: sUserID,

View File

@@ -29,7 +29,6 @@
"with_utls", "with_utls",
"with_naive_outbound", "with_naive_outbound",
"with_clash_api", "with_clash_api",
"with_conntrack",
"badlinkname", "badlinkname",
"tfogo_checklinkname0", "tfogo_checklinkname0",
"with_tailscale", "with_tailscale",
@@ -59,7 +58,6 @@
"with_wireguard", "with_wireguard",
"with_utls", "with_utls",
"with_clash_api", "with_clash_api",
"with_conntrack",
"badlinkname", "badlinkname",
"tfogo_checklinkname0", "tfogo_checklinkname0",
"with_tailscale", "with_tailscale",
@@ -90,7 +88,6 @@
"with_utls", "with_utls",
"with_naive_outbound", "with_naive_outbound",
"with_clash_api", "with_clash_api",
"with_conntrack",
"badlinkname", "badlinkname",
"tfogo_checklinkname0", "tfogo_checklinkname0",
"with_dhcp", "with_dhcp",
@@ -134,7 +131,6 @@
"with_naive_outbound", "with_naive_outbound",
"with_purego", "with_purego",
"with_clash_api", "with_clash_api",
"with_conntrack",
"badlinkname", "badlinkname",
"tfogo_checklinkname0", "tfogo_checklinkname0",
"with_tailscale", "with_tailscale",

View File

@@ -4,20 +4,23 @@ import (
"math" "math"
runtimeDebug "runtime/debug" runtimeDebug "runtime/debug"
"github.com/sagernet/sing-box/common/conntrack" C "github.com/sagernet/sing-box/constant"
) )
var memoryLimitEnabled bool
func SetMemoryLimit(enabled bool) { func SetMemoryLimit(enabled bool) {
const memoryLimit = 45 * 1024 * 1024 memoryLimitEnabled = enabled
const memoryLimitGo = memoryLimit / 1.5 const memoryLimitGo = 45 * 1024 * 1024
if enabled { if enabled {
runtimeDebug.SetGCPercent(10) runtimeDebug.SetGCPercent(10)
runtimeDebug.SetMemoryLimit(memoryLimitGo) if C.IsIos {
conntrack.KillerEnabled = true runtimeDebug.SetMemoryLimit(memoryLimitGo)
conntrack.MemoryLimit = memoryLimit }
} else { } else {
runtimeDebug.SetGCPercent(100) runtimeDebug.SetGCPercent(100)
runtimeDebug.SetMemoryLimit(math.MaxInt64) if C.IsIos {
conntrack.KillerEnabled = false runtimeDebug.SetMemoryLimit(math.MaxInt64)
}
} }
} }

62
go.mod
View File

@@ -27,8 +27,8 @@ require (
github.com/sagernet/asc-go v0.0.0-20241217030726-d563060fe4e1 github.com/sagernet/asc-go v0.0.0-20241217030726-d563060fe4e1
github.com/sagernet/bbolt v0.0.0-20231014093535-ea5cb2fe9f0a github.com/sagernet/bbolt v0.0.0-20231014093535-ea5cb2fe9f0a
github.com/sagernet/cors v1.2.1 github.com/sagernet/cors v1.2.1
github.com/sagernet/cronet-go v0.0.0-20260221042137-abd78bb191a8 github.com/sagernet/cronet-go v0.0.0-20260226034600-34ec1a064c64
github.com/sagernet/cronet-go/all v0.0.0-20260221042137-abd78bb191a8 github.com/sagernet/cronet-go/all v0.0.0-20260226034600-34ec1a064c64
github.com/sagernet/fswatch v0.1.1 github.com/sagernet/fswatch v0.1.1
github.com/sagernet/gomobile v0.1.11 github.com/sagernet/gomobile v0.1.11
github.com/sagernet/gvisor v0.0.0-20250811.0-sing-box-mod.1 github.com/sagernet/gvisor v0.0.0-20250811.0-sing-box-mod.1
@@ -105,35 +105,35 @@ require (
github.com/prometheus-community/pro-bing v0.4.0 // indirect github.com/prometheus-community/pro-bing v0.4.0 // indirect
github.com/quic-go/qpack v0.6.0 // indirect github.com/quic-go/qpack v0.6.0 // indirect
github.com/safchain/ethtool v0.3.0 // indirect github.com/safchain/ethtool v0.3.0 // indirect
github.com/sagernet/cronet-go/lib/android_386 v0.0.0-20260221041448-e52d68fd87fe // indirect github.com/sagernet/cronet-go/lib/android_386 v0.0.0-20260226033953-5745aabe7717 // indirect
github.com/sagernet/cronet-go/lib/android_amd64 v0.0.0-20260221041448-e52d68fd87fe // indirect github.com/sagernet/cronet-go/lib/android_amd64 v0.0.0-20260226033953-5745aabe7717 // indirect
github.com/sagernet/cronet-go/lib/android_arm v0.0.0-20260221041448-e52d68fd87fe // indirect github.com/sagernet/cronet-go/lib/android_arm v0.0.0-20260226033953-5745aabe7717 // indirect
github.com/sagernet/cronet-go/lib/android_arm64 v0.0.0-20260221041448-e52d68fd87fe // indirect github.com/sagernet/cronet-go/lib/android_arm64 v0.0.0-20260226033953-5745aabe7717 // indirect
github.com/sagernet/cronet-go/lib/darwin_amd64 v0.0.0-20260221041448-e52d68fd87fe // indirect github.com/sagernet/cronet-go/lib/darwin_amd64 v0.0.0-20260226033953-5745aabe7717 // indirect
github.com/sagernet/cronet-go/lib/darwin_arm64 v0.0.0-20260221041448-e52d68fd87fe // indirect github.com/sagernet/cronet-go/lib/darwin_arm64 v0.0.0-20260226033953-5745aabe7717 // indirect
github.com/sagernet/cronet-go/lib/ios_amd64_simulator v0.0.0-20260221041448-e52d68fd87fe // indirect github.com/sagernet/cronet-go/lib/ios_amd64_simulator v0.0.0-20260226033953-5745aabe7717 // indirect
github.com/sagernet/cronet-go/lib/ios_arm64 v0.0.0-20260221041448-e52d68fd87fe // indirect github.com/sagernet/cronet-go/lib/ios_arm64 v0.0.0-20260226033953-5745aabe7717 // indirect
github.com/sagernet/cronet-go/lib/ios_arm64_simulator v0.0.0-20260221041448-e52d68fd87fe // indirect github.com/sagernet/cronet-go/lib/ios_arm64_simulator v0.0.0-20260226033953-5745aabe7717 // indirect
github.com/sagernet/cronet-go/lib/linux_386 v0.0.0-20260221041448-e52d68fd87fe // indirect github.com/sagernet/cronet-go/lib/linux_386 v0.0.0-20260226033953-5745aabe7717 // indirect
github.com/sagernet/cronet-go/lib/linux_386_musl v0.0.0-20260221041448-e52d68fd87fe // indirect github.com/sagernet/cronet-go/lib/linux_386_musl v0.0.0-20260226033953-5745aabe7717 // indirect
github.com/sagernet/cronet-go/lib/linux_amd64 v0.0.0-20260221041448-e52d68fd87fe // indirect github.com/sagernet/cronet-go/lib/linux_amd64 v0.0.0-20260226033953-5745aabe7717 // indirect
github.com/sagernet/cronet-go/lib/linux_amd64_musl v0.0.0-20260221041448-e52d68fd87fe // indirect github.com/sagernet/cronet-go/lib/linux_amd64_musl v0.0.0-20260226033953-5745aabe7717 // indirect
github.com/sagernet/cronet-go/lib/linux_arm v0.0.0-20260221041448-e52d68fd87fe // indirect github.com/sagernet/cronet-go/lib/linux_arm v0.0.0-20260226033953-5745aabe7717 // indirect
github.com/sagernet/cronet-go/lib/linux_arm64 v0.0.0-20260221041448-e52d68fd87fe // indirect github.com/sagernet/cronet-go/lib/linux_arm64 v0.0.0-20260226033953-5745aabe7717 // indirect
github.com/sagernet/cronet-go/lib/linux_arm64_musl v0.0.0-20260221041448-e52d68fd87fe // indirect github.com/sagernet/cronet-go/lib/linux_arm64_musl v0.0.0-20260226033953-5745aabe7717 // indirect
github.com/sagernet/cronet-go/lib/linux_arm_musl v0.0.0-20260221041448-e52d68fd87fe // indirect github.com/sagernet/cronet-go/lib/linux_arm_musl v0.0.0-20260226033953-5745aabe7717 // indirect
github.com/sagernet/cronet-go/lib/linux_loong64 v0.0.0-20260221041448-e52d68fd87fe // indirect github.com/sagernet/cronet-go/lib/linux_loong64 v0.0.0-20260226033953-5745aabe7717 // indirect
github.com/sagernet/cronet-go/lib/linux_loong64_musl v0.0.0-20260221041448-e52d68fd87fe // indirect github.com/sagernet/cronet-go/lib/linux_loong64_musl v0.0.0-20260226033953-5745aabe7717 // indirect
github.com/sagernet/cronet-go/lib/linux_mips64le v0.0.0-20260221041448-e52d68fd87fe // indirect github.com/sagernet/cronet-go/lib/linux_mips64le v0.0.0-20260226033953-5745aabe7717 // indirect
github.com/sagernet/cronet-go/lib/linux_mipsle v0.0.0-20260221041448-e52d68fd87fe // indirect github.com/sagernet/cronet-go/lib/linux_mipsle v0.0.0-20260226033953-5745aabe7717 // indirect
github.com/sagernet/cronet-go/lib/linux_mipsle_musl v0.0.0-20260221041448-e52d68fd87fe // indirect github.com/sagernet/cronet-go/lib/linux_mipsle_musl v0.0.0-20260226033953-5745aabe7717 // indirect
github.com/sagernet/cronet-go/lib/linux_riscv64 v0.0.0-20260221041448-e52d68fd87fe // indirect github.com/sagernet/cronet-go/lib/linux_riscv64 v0.0.0-20260226033953-5745aabe7717 // indirect
github.com/sagernet/cronet-go/lib/linux_riscv64_musl v0.0.0-20260221041448-e52d68fd87fe // indirect github.com/sagernet/cronet-go/lib/linux_riscv64_musl v0.0.0-20260226033953-5745aabe7717 // indirect
github.com/sagernet/cronet-go/lib/tvos_amd64_simulator v0.0.0-20260221041448-e52d68fd87fe // indirect github.com/sagernet/cronet-go/lib/tvos_amd64_simulator v0.0.0-20260226033953-5745aabe7717 // indirect
github.com/sagernet/cronet-go/lib/tvos_arm64 v0.0.0-20260221041448-e52d68fd87fe // indirect github.com/sagernet/cronet-go/lib/tvos_arm64 v0.0.0-20260226033953-5745aabe7717 // indirect
github.com/sagernet/cronet-go/lib/tvos_arm64_simulator v0.0.0-20260221041448-e52d68fd87fe // indirect github.com/sagernet/cronet-go/lib/tvos_arm64_simulator v0.0.0-20260226033953-5745aabe7717 // indirect
github.com/sagernet/cronet-go/lib/windows_amd64 v0.0.0-20260221041448-e52d68fd87fe // indirect github.com/sagernet/cronet-go/lib/windows_amd64 v0.0.0-20260226033953-5745aabe7717 // indirect
github.com/sagernet/cronet-go/lib/windows_arm64 v0.0.0-20260221041448-e52d68fd87fe // indirect github.com/sagernet/cronet-go/lib/windows_arm64 v0.0.0-20260226033953-5745aabe7717 // indirect
github.com/sagernet/netlink v0.0.0-20240612041022-b9a21c07ac6a // indirect github.com/sagernet/netlink v0.0.0-20240612041022-b9a21c07ac6a // indirect
github.com/sagernet/nftables v0.3.0-beta.4 // indirect github.com/sagernet/nftables v0.3.0-beta.4 // indirect
github.com/spf13/pflag v1.0.9 // indirect github.com/spf13/pflag v1.0.9 // indirect

124
go.sum
View File

@@ -152,68 +152,68 @@ github.com/sagernet/bbolt v0.0.0-20231014093535-ea5cb2fe9f0a h1:+NkI2670SQpQWvkk
github.com/sagernet/bbolt v0.0.0-20231014093535-ea5cb2fe9f0a/go.mod h1:63s7jpZqcDAIpj8oI/1v4Izok+npJOHACFCU6+huCkM= github.com/sagernet/bbolt v0.0.0-20231014093535-ea5cb2fe9f0a/go.mod h1:63s7jpZqcDAIpj8oI/1v4Izok+npJOHACFCU6+huCkM=
github.com/sagernet/cors v1.2.1 h1:Cv5Z8y9YSD6Gm+qSpNrL3LO4lD3eQVvbFYJSG7JCMHQ= github.com/sagernet/cors v1.2.1 h1:Cv5Z8y9YSD6Gm+qSpNrL3LO4lD3eQVvbFYJSG7JCMHQ=
github.com/sagernet/cors v1.2.1/go.mod h1:O64VyOjjhrkLmQIjF4KGRrJO/5dVXFdpEmCW/eISRAI= github.com/sagernet/cors v1.2.1/go.mod h1:O64VyOjjhrkLmQIjF4KGRrJO/5dVXFdpEmCW/eISRAI=
github.com/sagernet/cronet-go v0.0.0-20260221042137-abd78bb191a8 h1:XcZiLUXnYE74RvqVdsyxgIInBuFaZbABx2Hom5U6uuk= github.com/sagernet/cronet-go v0.0.0-20260226034600-34ec1a064c64 h1:2hcUvxlEbzs4hbt9l0oeBpUfet2PHzaV6X6zNTDMkvQ=
github.com/sagernet/cronet-go v0.0.0-20260221042137-abd78bb191a8/go.mod h1:hwFHBEjjthyEquDULbr4c4ucMedp8Drb6Jvm2kt/0Bw= github.com/sagernet/cronet-go v0.0.0-20260226034600-34ec1a064c64/go.mod h1:hwFHBEjjthyEquDULbr4c4ucMedp8Drb6Jvm2kt/0Bw=
github.com/sagernet/cronet-go/all v0.0.0-20260221042137-abd78bb191a8 h1:uaUy9opPmPYD+viUeUnBzT+lw5b19j6pC/iKew7u13I= github.com/sagernet/cronet-go/all v0.0.0-20260226034600-34ec1a064c64 h1:f5TU9VAbhtm/SMLKctjMiSNUoQso4S6kEPUm5yNglNo=
github.com/sagernet/cronet-go/all v0.0.0-20260221042137-abd78bb191a8/go.mod h1:Gn1d0D8adjp7mlgSv+/pVLJsG+engIMBp/R4+1MOhlk= github.com/sagernet/cronet-go/all v0.0.0-20260226034600-34ec1a064c64/go.mod h1:ohbVnfJvBzdv7R87Nz0fAmkLSTF9lCKrQC2rIqsQPY4=
github.com/sagernet/cronet-go/lib/android_386 v0.0.0-20260221041448-e52d68fd87fe h1:iKIZJsvD+D3sdAzAeeOodJBxnFL9OVs1LTq3xnmQ6wQ= github.com/sagernet/cronet-go/lib/android_386 v0.0.0-20260226033953-5745aabe7717 h1:vtE5zVWFQuNls2jHb5edFCFYJblGY9qrqTVpoW2V/h4=
github.com/sagernet/cronet-go/lib/android_386 v0.0.0-20260221041448-e52d68fd87fe/go.mod h1:XXDwdjX/T8xftoeJxQmbBoYXZp8MAPFR2CwbFuTpEtw= github.com/sagernet/cronet-go/lib/android_386 v0.0.0-20260226033953-5745aabe7717/go.mod h1:XXDwdjX/T8xftoeJxQmbBoYXZp8MAPFR2CwbFuTpEtw=
github.com/sagernet/cronet-go/lib/android_amd64 v0.0.0-20260221041448-e52d68fd87fe h1:/YhWKKVb3uQ5JmBQwFEOKg8QK2w0Ky6dxEb/UHrhQww= github.com/sagernet/cronet-go/lib/android_amd64 v0.0.0-20260226033953-5745aabe7717 h1:+d5efMdtHbizXb4Vuai/11uNpWXmwOCfVgQcICA3kgk=
github.com/sagernet/cronet-go/lib/android_amd64 v0.0.0-20260221041448-e52d68fd87fe/go.mod h1:iNiUGoLtnr8/JTuVNj7XJbmpOAp2C6+B81KDrPxwaZM= github.com/sagernet/cronet-go/lib/android_amd64 v0.0.0-20260226033953-5745aabe7717/go.mod h1:iNiUGoLtnr8/JTuVNj7XJbmpOAp2C6+B81KDrPxwaZM=
github.com/sagernet/cronet-go/lib/android_arm v0.0.0-20260221041448-e52d68fd87fe h1:h+XF746wRtYKavUeS8//Vro6s9f0F6+pI8VQFLMLg6E= github.com/sagernet/cronet-go/lib/android_arm v0.0.0-20260226033953-5745aabe7717 h1:6BYObS6w5sWnNLChKT1fOYJnJt/+p6du8fSyDb3DLwo=
github.com/sagernet/cronet-go/lib/android_arm v0.0.0-20260221041448-e52d68fd87fe/go.mod h1:19ILNUOGIzRdOqa2mq+iY0JoHxuieB7/lnjYeaA2vEc= github.com/sagernet/cronet-go/lib/android_arm v0.0.0-20260226033953-5745aabe7717/go.mod h1:19ILNUOGIzRdOqa2mq+iY0JoHxuieB7/lnjYeaA2vEc=
github.com/sagernet/cronet-go/lib/android_arm64 v0.0.0-20260221041448-e52d68fd87fe h1:yMs96D9ErwAG8gEHV6zaQ5cp9ZPNBHExxJ5+u8cZ644= github.com/sagernet/cronet-go/lib/android_arm64 v0.0.0-20260226033953-5745aabe7717 h1:UbgjfMai+duPsftAT94zr4KcnACuJhjaxQkpup6TWLk=
github.com/sagernet/cronet-go/lib/android_arm64 v0.0.0-20260221041448-e52d68fd87fe/go.mod h1:JxzGyQf94Cr6sBShKqODGDyRUlESfJK/Njcz9Lz6qMQ= github.com/sagernet/cronet-go/lib/android_arm64 v0.0.0-20260226033953-5745aabe7717/go.mod h1:JxzGyQf94Cr6sBShKqODGDyRUlESfJK/Njcz9Lz6qMQ=
github.com/sagernet/cronet-go/lib/darwin_amd64 v0.0.0-20260221041448-e52d68fd87fe h1:HUJtGjXcB+70W+YfeLgue6X1u69XLN0Ar56Ipg3gtvY= github.com/sagernet/cronet-go/lib/darwin_amd64 v0.0.0-20260226033953-5745aabe7717 h1:KRrzFzsWWgy8XPHfp2hEX7wTuc7ILQZiFKIATvuyCHU=
github.com/sagernet/cronet-go/lib/darwin_amd64 v0.0.0-20260221041448-e52d68fd87fe/go.mod h1:KN+9T9TBycGOLzmKU4QdcHAJEj6Nlx48ifnlTvvHMvs= github.com/sagernet/cronet-go/lib/darwin_amd64 v0.0.0-20260226033953-5745aabe7717/go.mod h1:KN+9T9TBycGOLzmKU4QdcHAJEj6Nlx48ifnlTvvHMvs=
github.com/sagernet/cronet-go/lib/darwin_arm64 v0.0.0-20260221041448-e52d68fd87fe h1:ivo7JwVqDTMf/qVfpKYdwcIc+NzKGyMJ/WLj/TTNYXg= github.com/sagernet/cronet-go/lib/darwin_arm64 v0.0.0-20260226033953-5745aabe7717 h1:bTp8j/GqUsS0P2aaTcbs7alSvUoywx+YIWyoCcVA05I=
github.com/sagernet/cronet-go/lib/darwin_arm64 v0.0.0-20260221041448-e52d68fd87fe/go.mod h1:kojvtUc29KKnk8hs2QIANynVR59921SnGWA9kXohHc0= github.com/sagernet/cronet-go/lib/darwin_arm64 v0.0.0-20260226033953-5745aabe7717/go.mod h1:kojvtUc29KKnk8hs2QIANynVR59921SnGWA9kXohHc0=
github.com/sagernet/cronet-go/lib/ios_amd64_simulator v0.0.0-20260221041448-e52d68fd87fe h1:HdWJLwa/Ie3jsueJ0O2mZd4V/NP1UJ6bamdcNHWsYEo= github.com/sagernet/cronet-go/lib/ios_amd64_simulator v0.0.0-20260226033953-5745aabe7717 h1:PKuCYfGpSfnzgRJjRR5em/yU5SoI4Yvx3r0C2k1Ksh4=
github.com/sagernet/cronet-go/lib/ios_amd64_simulator v0.0.0-20260221041448-e52d68fd87fe/go.mod h1:hkQzRE5GDbaH1/ioqYh0Taho4L6i0yLRCVEZ5xHz5M0= github.com/sagernet/cronet-go/lib/ios_amd64_simulator v0.0.0-20260226033953-5745aabe7717/go.mod h1:hkQzRE5GDbaH1/ioqYh0Taho4L6i0yLRCVEZ5xHz5M0=
github.com/sagernet/cronet-go/lib/ios_arm64 v0.0.0-20260221041448-e52d68fd87fe h1:A9PWi2xCI+TCr9ALr+BO76WCCk1JnRyjeEH0/+rdyRc= github.com/sagernet/cronet-go/lib/ios_arm64 v0.0.0-20260226033953-5745aabe7717 h1:w5ytvTm42ncUIFbLueN/ilp2ZaHrr5GC76Kc/Oxw4qI=
github.com/sagernet/cronet-go/lib/ios_arm64 v0.0.0-20260221041448-e52d68fd87fe/go.mod h1:tzVJFTOm66UxLxy6K0ZN5Ic2PC79e+sKKnt+V9puEa4= github.com/sagernet/cronet-go/lib/ios_arm64 v0.0.0-20260226033953-5745aabe7717/go.mod h1:tzVJFTOm66UxLxy6K0ZN5Ic2PC79e+sKKnt+V9puEa4=
github.com/sagernet/cronet-go/lib/ios_arm64_simulator v0.0.0-20260221041448-e52d68fd87fe h1:aMOUWbGjkPBFqObA+uAJOfVuBkHfvz2sibNgOJqjuBs= github.com/sagernet/cronet-go/lib/ios_arm64_simulator v0.0.0-20260226033953-5745aabe7717 h1:2BjQH02cCF6spz/WG8bJHBPhZtF4Or5D73L+n5fZbNE=
github.com/sagernet/cronet-go/lib/ios_arm64_simulator v0.0.0-20260221041448-e52d68fd87fe/go.mod h1:M/pN6m3j0HFU6/y83n0HU6GLYys3tYdr/xTE8hVEGMo= github.com/sagernet/cronet-go/lib/ios_arm64_simulator v0.0.0-20260226033953-5745aabe7717/go.mod h1:M/pN6m3j0HFU6/y83n0HU6GLYys3tYdr/xTE8hVEGMo=
github.com/sagernet/cronet-go/lib/linux_386 v0.0.0-20260221041448-e52d68fd87fe h1:CzE+sJ2iOvJwOuZhpiDV5VlQrBaNJAZhDCafly+TH9c= github.com/sagernet/cronet-go/lib/linux_386 v0.0.0-20260226033953-5745aabe7717 h1:N9KUwDODj5eP5uqdSmbMufml2nGPc7oX4H5NPAjADIs=
github.com/sagernet/cronet-go/lib/linux_386 v0.0.0-20260221041448-e52d68fd87fe/go.mod h1:cGh5hO6eljCo6KMQ/Cel8Xgq4+etL0awZLRBDVG1EZQ= github.com/sagernet/cronet-go/lib/linux_386 v0.0.0-20260226033953-5745aabe7717/go.mod h1:cGh5hO6eljCo6KMQ/Cel8Xgq4+etL0awZLRBDVG1EZQ=
github.com/sagernet/cronet-go/lib/linux_386_musl v0.0.0-20260221041448-e52d68fd87fe h1:2grC2CeyUiYVgqG7BGKpJvjFzYv0wL64QMoBqOHVZsI= github.com/sagernet/cronet-go/lib/linux_386_musl v0.0.0-20260226033953-5745aabe7717 h1:v2p6tqpQVI6RR1HamuJmkz01Ght4miQ79YhzQtOYowk=
github.com/sagernet/cronet-go/lib/linux_386_musl v0.0.0-20260221041448-e52d68fd87fe/go.mod h1:JFE0/cxaKkx0wqPMZU7MgaplQlU0zudv82dROJjClKU= github.com/sagernet/cronet-go/lib/linux_386_musl v0.0.0-20260226033953-5745aabe7717/go.mod h1:JFE0/cxaKkx0wqPMZU7MgaplQlU0zudv82dROJjClKU=
github.com/sagernet/cronet-go/lib/linux_amd64 v0.0.0-20260221041448-e52d68fd87fe h1:+N9/LauocInR5kxXU+L5bQe1bndCZUC+6L0FaozWZNI= github.com/sagernet/cronet-go/lib/linux_amd64 v0.0.0-20260226033953-5745aabe7717 h1:glPUIWUUAlOII+L0UI7/JAJ8o0wqAT7qVmWB4AcPyWs=
github.com/sagernet/cronet-go/lib/linux_amd64 v0.0.0-20260221041448-e52d68fd87fe/go.mod h1:vU8VftFeSt7fURCa3JXD6+k6ss1YAX+idQjPvHmJ2tI= github.com/sagernet/cronet-go/lib/linux_amd64 v0.0.0-20260226033953-5745aabe7717/go.mod h1:vU8VftFeSt7fURCa3JXD6+k6ss1YAX+idQjPvHmJ2tI=
github.com/sagernet/cronet-go/lib/linux_amd64_musl v0.0.0-20260221041448-e52d68fd87fe h1:mRJcjGtKG/eaPL4sZ4Ij+e7aLdg1AEXNI1PgRnxI6H8= github.com/sagernet/cronet-go/lib/linux_amd64_musl v0.0.0-20260226033953-5745aabe7717 h1:0QKgSc5nBrR6H1ImsOlaBbVQ7onoFhwxTBwiOnUn0es=
github.com/sagernet/cronet-go/lib/linux_amd64_musl v0.0.0-20260221041448-e52d68fd87fe/go.mod h1:vCe4OUuL+XOUge9v3MyTD45BnuAXiH+DkjN9quDXJzQ= github.com/sagernet/cronet-go/lib/linux_amd64_musl v0.0.0-20260226033953-5745aabe7717/go.mod h1:vCe4OUuL+XOUge9v3MyTD45BnuAXiH+DkjN9quDXJzQ=
github.com/sagernet/cronet-go/lib/linux_arm v0.0.0-20260221041448-e52d68fd87fe h1:UkWiTAxUAjTtsu7e52cvMrmbShz+ahTdGkhF9mEIIZU= github.com/sagernet/cronet-go/lib/linux_arm v0.0.0-20260226033953-5745aabe7717 h1:DsrfMoWf05lLrwdo0s/6wAC/4smeDgT4+t/iJtwGD+g=
github.com/sagernet/cronet-go/lib/linux_arm v0.0.0-20260221041448-e52d68fd87fe/go.mod h1:w9amBWrvjtohQzBGCKJ7LCh22LhTIJs4sE7cYaKQzM0= github.com/sagernet/cronet-go/lib/linux_arm v0.0.0-20260226033953-5745aabe7717/go.mod h1:w9amBWrvjtohQzBGCKJ7LCh22LhTIJs4sE7cYaKQzM0=
github.com/sagernet/cronet-go/lib/linux_arm64 v0.0.0-20260221041448-e52d68fd87fe h1:giJVex0bwZy+DwmPwfZ+NZmafBRTsaZ+QUaD2Fkacxs= github.com/sagernet/cronet-go/lib/linux_arm64 v0.0.0-20260226033953-5745aabe7717 h1:bYqI37NWgvxVBeWL50/ts23uGiyHv7QfH/Ylu5lvgLs=
github.com/sagernet/cronet-go/lib/linux_arm64 v0.0.0-20260221041448-e52d68fd87fe/go.mod h1:TqlsFtcYS/etTeck46kHBeT8Le0Igw1Q/AV88UnMS3s= github.com/sagernet/cronet-go/lib/linux_arm64 v0.0.0-20260226033953-5745aabe7717/go.mod h1:TqlsFtcYS/etTeck46kHBeT8Le0Igw1Q/AV88UnMS3s=
github.com/sagernet/cronet-go/lib/linux_arm64_musl v0.0.0-20260221041448-e52d68fd87fe h1:XkjAQkciY78eSMF/9VdaWRWb+OfPvoIxVKx5gHGfSIg= github.com/sagernet/cronet-go/lib/linux_arm64_musl v0.0.0-20260226033953-5745aabe7717 h1:zg8keyQA2sniD4gqMwbUVdf57M1cmGobumOtZy1CYJs=
github.com/sagernet/cronet-go/lib/linux_arm64_musl v0.0.0-20260221041448-e52d68fd87fe/go.mod h1:B6Qd0vys8sv9OKVRN6J9RqDzYRGE938Fb2zrYdBDyTQ= github.com/sagernet/cronet-go/lib/linux_arm64_musl v0.0.0-20260226033953-5745aabe7717/go.mod h1:B6Qd0vys8sv9OKVRN6J9RqDzYRGE938Fb2zrYdBDyTQ=
github.com/sagernet/cronet-go/lib/linux_arm_musl v0.0.0-20260221041448-e52d68fd87fe h1:8uDfbPXAL0MWqGI8bm6YJghRmGvK08z4jEIGoODKqTI= github.com/sagernet/cronet-go/lib/linux_arm_musl v0.0.0-20260226033953-5745aabe7717 h1:cgyVkTyccMGiCayGgcvfc+q0b5GdhqSk+3UMmGhlCi0=
github.com/sagernet/cronet-go/lib/linux_arm_musl v0.0.0-20260221041448-e52d68fd87fe/go.mod h1:3tXMMFY7AHugOVBZ5Al7cL7JKsnFOe5bMVr0hZPk3ow= github.com/sagernet/cronet-go/lib/linux_arm_musl v0.0.0-20260226033953-5745aabe7717/go.mod h1:3tXMMFY7AHugOVBZ5Al7cL7JKsnFOe5bMVr0hZPk3ow=
github.com/sagernet/cronet-go/lib/linux_loong64 v0.0.0-20260221041448-e52d68fd87fe h1:Ucs4htbATTdG7YGHCyQ4vMYRhltVvsapZ95THRNssr4= github.com/sagernet/cronet-go/lib/linux_loong64 v0.0.0-20260226033953-5745aabe7717 h1:anuE3B73oIvDOGJGvenfkQTm3NY2vL84aM062t8DZ4Y=
github.com/sagernet/cronet-go/lib/linux_loong64 v0.0.0-20260221041448-e52d68fd87fe/go.mod h1:Wt5uFdU3tnmm8YzobYewwdF7Mt6SucRQg6xeTNWC3Tk= github.com/sagernet/cronet-go/lib/linux_loong64 v0.0.0-20260226033953-5745aabe7717/go.mod h1:Wt5uFdU3tnmm8YzobYewwdF7Mt6SucRQg6xeTNWC3Tk=
github.com/sagernet/cronet-go/lib/linux_loong64_musl v0.0.0-20260221041448-e52d68fd87fe h1:oeQjTH4lveV4M7/hqOJFfwQ9UfWvkFZEXTc00R2acuk= github.com/sagernet/cronet-go/lib/linux_loong64_musl v0.0.0-20260226033953-5745aabe7717 h1:kYN/amWzLOZMm5evPwlmumnswBNPeFZiKINKP73AsuA=
github.com/sagernet/cronet-go/lib/linux_loong64_musl v0.0.0-20260221041448-e52d68fd87fe/go.mod h1:lyIF6wKBLwWa5ZXaAKbAoewewl+yCHo2iYev39Mbj4E= github.com/sagernet/cronet-go/lib/linux_loong64_musl v0.0.0-20260226033953-5745aabe7717/go.mod h1:lyIF6wKBLwWa5ZXaAKbAoewewl+yCHo2iYev39Mbj4E=
github.com/sagernet/cronet-go/lib/linux_mips64le v0.0.0-20260221041448-e52d68fd87fe h1:NWABhpSuXcN61hF0CUqwliJXxEbmHidoAHxtB61V3GA= github.com/sagernet/cronet-go/lib/linux_mips64le v0.0.0-20260226033953-5745aabe7717 h1:S7rlC1Knzs3+It2u6AnhGUgiLU1QUzvoV3JXWvwE4n8=
github.com/sagernet/cronet-go/lib/linux_mips64le v0.0.0-20260221041448-e52d68fd87fe/go.mod h1:H46PnSTTZNcZokLLiDeMDaHiS1l14PH3tzWi0eykjD8= github.com/sagernet/cronet-go/lib/linux_mips64le v0.0.0-20260226033953-5745aabe7717/go.mod h1:H46PnSTTZNcZokLLiDeMDaHiS1l14PH3tzWi0eykjD8=
github.com/sagernet/cronet-go/lib/linux_mipsle v0.0.0-20260221041448-e52d68fd87fe h1:+0VrQdlGR/zLjPzinXFqFR2sdzF2BXoXu7f8xaMuwtg= github.com/sagernet/cronet-go/lib/linux_mipsle v0.0.0-20260226033953-5745aabe7717 h1:FeyB5ZyFHAWkU1DETmUjLEM9GUFWoIndV8usT4AjGOk=
github.com/sagernet/cronet-go/lib/linux_mipsle v0.0.0-20260221041448-e52d68fd87fe/go.mod h1:RBhSUDAKWq7fswtV4nQUQhuaTLcX3ettR7teA7/yf2w= github.com/sagernet/cronet-go/lib/linux_mipsle v0.0.0-20260226033953-5745aabe7717/go.mod h1:RBhSUDAKWq7fswtV4nQUQhuaTLcX3ettR7teA7/yf2w=
github.com/sagernet/cronet-go/lib/linux_mipsle_musl v0.0.0-20260221041448-e52d68fd87fe h1:DYW55QJOZBI4Znjhc0IiusF+IMg4R2dHPX0KnZC6gSo= github.com/sagernet/cronet-go/lib/linux_mipsle_musl v0.0.0-20260226033953-5745aabe7717 h1:loU7PsyqI7dplbFGjQKoMT4IVYuzVyfW88FIq+7gbmY=
github.com/sagernet/cronet-go/lib/linux_mipsle_musl v0.0.0-20260221041448-e52d68fd87fe/go.mod h1:wRzoIOGG4xbpp3Gh3triLKwMwYriScXzFtunLYhY4w0= github.com/sagernet/cronet-go/lib/linux_mipsle_musl v0.0.0-20260226033953-5745aabe7717/go.mod h1:wRzoIOGG4xbpp3Gh3triLKwMwYriScXzFtunLYhY4w0=
github.com/sagernet/cronet-go/lib/linux_riscv64 v0.0.0-20260221041448-e52d68fd87fe h1:xbbZtyXOxYJMplsyv371ddQb7QrEnyXIIGdUK/3WNTE= github.com/sagernet/cronet-go/lib/linux_riscv64 v0.0.0-20260226033953-5745aabe7717 h1:XSVrZ18XauiYMf+G0CzZETteQF0r1NOoA1gVXlZWjUI=
github.com/sagernet/cronet-go/lib/linux_riscv64 v0.0.0-20260221041448-e52d68fd87fe/go.mod h1:LNiZXmWil1OPwKCheqQjtakZlJuKGFz+iv2eGF76Hhs= github.com/sagernet/cronet-go/lib/linux_riscv64 v0.0.0-20260226033953-5745aabe7717/go.mod h1:LNiZXmWil1OPwKCheqQjtakZlJuKGFz+iv2eGF76Hhs=
github.com/sagernet/cronet-go/lib/linux_riscv64_musl v0.0.0-20260221041448-e52d68fd87fe h1:YSH2lVT+Sn29lQQbwhDpxZvGjVSg80SUfW4JQ8vM3aA= github.com/sagernet/cronet-go/lib/linux_riscv64_musl v0.0.0-20260226033953-5745aabe7717 h1:oTRK4T5pQ1ZYQh7Avr5u3bsDnXkloSVqwBljRy8FHOY=
github.com/sagernet/cronet-go/lib/linux_riscv64_musl v0.0.0-20260221041448-e52d68fd87fe/go.mod h1:YFDGKTkpkJGc5+hnX/RYosZyTWg9h+68VB55fYRRLYc= github.com/sagernet/cronet-go/lib/linux_riscv64_musl v0.0.0-20260226033953-5745aabe7717/go.mod h1:YFDGKTkpkJGc5+hnX/RYosZyTWg9h+68VB55fYRRLYc=
github.com/sagernet/cronet-go/lib/tvos_amd64_simulator v0.0.0-20260221041448-e52d68fd87fe h1:gQ1veofYJr8Z1hBVM2PIrn4+EMKvwh+zWpYBr+mxgQ8= github.com/sagernet/cronet-go/lib/tvos_amd64_simulator v0.0.0-20260226033953-5745aabe7717 h1:J18xRmUa9lle+Y6pYkQ7OMq2B9eox5Bmm4MkbuQPQm0=
github.com/sagernet/cronet-go/lib/tvos_amd64_simulator v0.0.0-20260221041448-e52d68fd87fe/go.mod h1:aaX0YGl8nhGmfRWI8bc3BtDjY8Vzx6O0cS/e1uqxDq4= github.com/sagernet/cronet-go/lib/tvos_amd64_simulator v0.0.0-20260226033953-5745aabe7717/go.mod h1:aaX0YGl8nhGmfRWI8bc3BtDjY8Vzx6O0cS/e1uqxDq4=
github.com/sagernet/cronet-go/lib/tvos_arm64 v0.0.0-20260221041448-e52d68fd87fe h1:e2TMlbEottRCDfTWxUSw4Jl5dK8IInV02XIvLKVjLbM= github.com/sagernet/cronet-go/lib/tvos_arm64 v0.0.0-20260226033953-5745aabe7717 h1:PC9gKeDN3wmcFxwiBEM57W0YwEz1uFGqawwssEQe494=
github.com/sagernet/cronet-go/lib/tvos_arm64 v0.0.0-20260221041448-e52d68fd87fe/go.mod h1:EdzMKA96xITc42QEI+ct4SwqX8Dn3ltKK8wzdkLWpSc= github.com/sagernet/cronet-go/lib/tvos_arm64 v0.0.0-20260226033953-5745aabe7717/go.mod h1:EdzMKA96xITc42QEI+ct4SwqX8Dn3ltKK8wzdkLWpSc=
github.com/sagernet/cronet-go/lib/tvos_arm64_simulator v0.0.0-20260221041448-e52d68fd87fe h1:Cgh+DP/Ns1djisz+LFxA1nEhyF6EEU5ZdVxNTkiX2BI= github.com/sagernet/cronet-go/lib/tvos_arm64_simulator v0.0.0-20260226033953-5745aabe7717 h1:STlbMnsydaymby26m3wNfeYYI7HoiZ6+wxQ75Si1g8E=
github.com/sagernet/cronet-go/lib/tvos_arm64_simulator v0.0.0-20260221041448-e52d68fd87fe/go.mod h1:qix4kv1TTAJ5tY4lJ9vjhe9EY4mM+B7H5giOhbxDVcc= github.com/sagernet/cronet-go/lib/tvos_arm64_simulator v0.0.0-20260226033953-5745aabe7717/go.mod h1:qix4kv1TTAJ5tY4lJ9vjhe9EY4mM+B7H5giOhbxDVcc=
github.com/sagernet/cronet-go/lib/windows_amd64 v0.0.0-20260221041448-e52d68fd87fe h1:VCtjRmkI1IkKdWQ3Jh7j/ze5fhBQJZo1JR70cVKLaKw= github.com/sagernet/cronet-go/lib/windows_amd64 v0.0.0-20260226033953-5745aabe7717 h1:qWtpoBxmHyb49IRtMAFkJIRlL4KCYW5Fe6YptYhItpM=
github.com/sagernet/cronet-go/lib/windows_amd64 v0.0.0-20260221041448-e52d68fd87fe/go.mod h1:lm9w/oCCRyBiUa3G8lDQTT8x/ONUvgVR2iV9fVzUZB8= github.com/sagernet/cronet-go/lib/windows_amd64 v0.0.0-20260226033953-5745aabe7717/go.mod h1:lm9w/oCCRyBiUa3G8lDQTT8x/ONUvgVR2iV9fVzUZB8=
github.com/sagernet/cronet-go/lib/windows_arm64 v0.0.0-20260221041448-e52d68fd87fe h1:SKePXZMEPUY5zA1VFBPbPOxZsfb/wkMNZAvjPO7hL+I= github.com/sagernet/cronet-go/lib/windows_arm64 v0.0.0-20260226033953-5745aabe7717 h1:7ohuWJ0PswrU7Xw/xfL6OrIh7sXybGNOgh6DaL+urdY=
github.com/sagernet/cronet-go/lib/windows_arm64 v0.0.0-20260221041448-e52d68fd87fe/go.mod h1:n34YyLgapgjWdKa0IoeczjAFCwD3/dxbsH5sucKw0bw= github.com/sagernet/cronet-go/lib/windows_arm64 v0.0.0-20260226033953-5745aabe7717/go.mod h1:n34YyLgapgjWdKa0IoeczjAFCwD3/dxbsH5sucKw0bw=
github.com/sagernet/fswatch v0.1.1 h1:YqID+93B7VRfqIH3PArW/XpJv5H4OLEVWDfProGoRQs= github.com/sagernet/fswatch v0.1.1 h1:YqID+93B7VRfqIH3PArW/XpJv5H4OLEVWDfProGoRQs=
github.com/sagernet/fswatch v0.1.1/go.mod h1:nz85laH0mkQqJfaOrqPpkwtU1znMFNVTpT/5oRsVz/o= github.com/sagernet/fswatch v0.1.1/go.mod h1:nz85laH0mkQqJfaOrqPpkwtU1znMFNVTpT/5oRsVz/o=
github.com/sagernet/gomobile v0.1.11 h1:niMQAspvuThup5eRZQpsGcbM76zAvnsGr7RUIpnQMDQ= github.com/sagernet/gomobile v0.1.11 h1:niMQAspvuThup5eRZQpsGcbM76zAvnsGr7RUIpnQMDQ=

10
include/oom_killer.go Normal file
View File

@@ -0,0 +1,10 @@
package include
import (
"github.com/sagernet/sing-box/adapter/service"
"github.com/sagernet/sing-box/service/oomkiller"
)
func registerOOMKillerService(registry *service.Registry) {
oomkiller.RegisterService(registry)
}

View File

@@ -137,6 +137,7 @@ func ServiceRegistry() *service.Registry {
registerDERPService(registry) registerDERPService(registry)
registerCCMService(registry) registerCCMService(registry)
registerOCMService(registry) registerOCMService(registry)
registerOOMKillerService(registry)
return registry return registry
} }

3
option/oom_killer.go Normal file
View File

@@ -0,0 +1,3 @@
package option
type OOMKillerServiceOptions struct{}

View File

@@ -254,6 +254,10 @@ func (h *Outbound) ListenPacket(ctx context.Context, destination M.Socksaddr) (n
return h.uotClient.ListenPacket(ctx, destination) return h.uotClient.ListenPacket(ctx, destination)
} }
func (h *Outbound) InterfaceUpdated() {
h.client.Engine().CloseAllConnections()
}
func (h *Outbound) Close() error { func (h *Outbound) Close() error {
return h.client.Close() return h.client.Close()
} }

View File

@@ -44,16 +44,52 @@ func (m *ConnectionManager) Start(stage adapter.StartStage) error {
return nil return nil
} }
func (m *ConnectionManager) Close() error { func (m *ConnectionManager) Count() int {
return m.connections.Len()
}
func (m *ConnectionManager) CloseAll() {
m.access.Lock() m.access.Lock()
defer m.access.Unlock() var closers []io.Closer
for element := m.connections.Front(); element != nil; element = element.Next() { for element := m.connections.Front(); element != nil; {
common.Close(element.Value) nextElement := element.Next()
closers = append(closers, element.Value)
m.connections.Remove(element)
element = nextElement
} }
m.connections.Init() m.access.Unlock()
for _, closer := range closers {
common.Close(closer)
}
}
func (m *ConnectionManager) Close() error {
m.CloseAll()
return nil return nil
} }
func (m *ConnectionManager) TrackConn(conn net.Conn) net.Conn {
m.access.Lock()
element := m.connections.PushBack(conn)
m.access.Unlock()
return &trackedConn{
Conn: conn,
manager: m,
element: element,
}
}
func (m *ConnectionManager) TrackPacketConn(conn net.PacketConn) net.PacketConn {
m.access.Lock()
element := m.connections.PushBack(conn)
m.access.Unlock()
return &trackedPacketConn{
PacketConn: conn,
manager: m,
element: element,
}
}
func (m *ConnectionManager) NewConnection(ctx context.Context, this N.Dialer, conn net.Conn, metadata adapter.InboundContext, onClose N.CloseHandlerFunc) { func (m *ConnectionManager) NewConnection(ctx context.Context, this N.Dialer, conn net.Conn, metadata adapter.InboundContext, onClose N.CloseHandlerFunc) {
ctx = adapter.WithContext(ctx, &metadata) ctx = adapter.WithContext(ctx, &metadata)
var ( var (
@@ -92,14 +128,6 @@ func (m *ConnectionManager) NewConnection(ctx context.Context, this N.Dialer, co
if metadata.TLSFragment || metadata.TLSRecordFragment { if metadata.TLSFragment || metadata.TLSRecordFragment {
remoteConn = tf.NewConn(remoteConn, ctx, metadata.TLSFragment, metadata.TLSRecordFragment, metadata.TLSFragmentFallbackDelay) remoteConn = tf.NewConn(remoteConn, ctx, metadata.TLSFragment, metadata.TLSRecordFragment, metadata.TLSFragmentFallbackDelay)
} }
m.access.Lock()
element := m.connections.PushBack(conn)
m.access.Unlock()
onClose = N.AppendClose(onClose, func(it error) {
m.access.Lock()
defer m.access.Unlock()
m.connections.Remove(element)
})
var done atomic.Bool var done atomic.Bool
if m.kickWriteHandshake(ctx, conn, remoteConn, false, &done, onClose) { if m.kickWriteHandshake(ctx, conn, remoteConn, false, &done, onClose) {
return return
@@ -216,14 +244,6 @@ func (m *ConnectionManager) NewPacketConnection(ctx context.Context, this N.Dial
ctx, conn = canceler.NewPacketConn(ctx, conn, udpTimeout) ctx, conn = canceler.NewPacketConn(ctx, conn, udpTimeout)
} }
destination := bufio.NewPacketConn(remotePacketConn) destination := bufio.NewPacketConn(remotePacketConn)
m.access.Lock()
element := m.connections.PushBack(conn)
m.access.Unlock()
onClose = N.AppendClose(onClose, func(it error) {
m.access.Lock()
defer m.access.Unlock()
m.connections.Remove(element)
})
var done atomic.Bool var done atomic.Bool
go m.packetConnectionCopy(ctx, conn, destination, false, &done, onClose) go m.packetConnectionCopy(ctx, conn, destination, false, &done, onClose)
go m.packetConnectionCopy(ctx, destination, conn, true, &done, onClose) go m.packetConnectionCopy(ctx, destination, conn, true, &done, onClose)
@@ -242,7 +262,9 @@ func (m *ConnectionManager) connectionCopy(ctx context.Context, source net.Conn,
destination.Close() destination.Close()
} }
if done.Swap(true) { if done.Swap(true) {
onClose(err) if onClose != nil {
onClose(err)
}
common.Close(source, destination) common.Close(source, destination)
} }
if !direction { if !direction {
@@ -303,7 +325,9 @@ func (m *ConnectionManager) kickWriteHandshake(ctx context.Context, source net.C
return false return false
} }
if !done.Swap(true) { if !done.Swap(true) {
onClose(err) if onClose != nil {
onClose(err)
}
} }
common.Close(source, destination) common.Close(source, destination)
if !direction { if !direction {
@@ -334,7 +358,59 @@ func (m *ConnectionManager) packetConnectionCopy(ctx context.Context, source N.P
} }
} }
if !done.Swap(true) { if !done.Swap(true) {
onClose(err) if onClose != nil {
onClose(err)
}
} }
common.Close(source, destination) common.Close(source, destination)
} }
type trackedConn struct {
net.Conn
manager *ConnectionManager
element *list.Element[io.Closer]
}
func (c *trackedConn) Close() error {
c.manager.access.Lock()
c.manager.connections.Remove(c.element)
c.manager.access.Unlock()
return c.Conn.Close()
}
func (c *trackedConn) Upstream() any {
return c.Conn
}
func (c *trackedConn) ReaderReplaceable() bool {
return true
}
func (c *trackedConn) WriterReplaceable() bool {
return true
}
type trackedPacketConn struct {
net.PacketConn
manager *ConnectionManager
element *list.Element[io.Closer]
}
func (c *trackedPacketConn) Close() error {
c.manager.access.Lock()
c.manager.connections.Remove(c.element)
c.manager.access.Unlock()
return c.PacketConn.Close()
}
func (c *trackedPacketConn) Upstream() any {
return bufio.NewPacketConn(c.PacketConn)
}
func (c *trackedPacketConn) ReaderReplaceable() bool {
return true
}
func (c *trackedPacketConn) WriterReplaceable() bool {
return true
}

View File

@@ -13,7 +13,6 @@ import (
"time" "time"
"github.com/sagernet/sing-box/adapter" "github.com/sagernet/sing-box/adapter"
"github.com/sagernet/sing-box/common/conntrack"
"github.com/sagernet/sing-box/common/settings" "github.com/sagernet/sing-box/common/settings"
"github.com/sagernet/sing-box/common/taskmonitor" "github.com/sagernet/sing-box/common/taskmonitor"
C "github.com/sagernet/sing-box/constant" C "github.com/sagernet/sing-box/constant"
@@ -48,6 +47,7 @@ type NetworkManager struct {
powerListener winpowrprof.EventListener powerListener winpowrprof.EventListener
pauseManager pause.Manager pauseManager pause.Manager
platformInterface adapter.PlatformInterface platformInterface adapter.PlatformInterface
connectionManager adapter.ConnectionManager
endpoint adapter.EndpointManager endpoint adapter.EndpointManager
inbound adapter.InboundManager inbound adapter.InboundManager
outbound adapter.OutboundManager outbound adapter.OutboundManager
@@ -90,6 +90,7 @@ func NewNetworkManager(ctx context.Context, logger logger.ContextLogger, options
}, },
pauseManager: service.FromContext[pause.Manager](ctx), pauseManager: service.FromContext[pause.Manager](ctx),
platformInterface: service.FromContext[adapter.PlatformInterface](ctx), platformInterface: service.FromContext[adapter.PlatformInterface](ctx),
connectionManager: service.FromContext[adapter.ConnectionManager](ctx),
endpoint: service.FromContext[adapter.EndpointManager](ctx), endpoint: service.FromContext[adapter.EndpointManager](ctx),
inbound: service.FromContext[adapter.InboundManager](ctx), inbound: service.FromContext[adapter.InboundManager](ctx),
outbound: service.FromContext[adapter.OutboundManager](ctx), outbound: service.FromContext[adapter.OutboundManager](ctx),
@@ -450,7 +451,9 @@ func (r *NetworkManager) UpdateWIFIState() {
} }
func (r *NetworkManager) ResetNetwork() { func (r *NetworkManager) ResetNetwork() {
conntrack.Close() if r.connectionManager != nil {
r.connectionManager.CloseAll()
}
for _, endpoint := range r.endpoint.Endpoints() { for _, endpoint := range r.endpoint.Endpoints() {
listener, isListener := endpoint.(adapter.InterfaceUpdateListener) listener, isListener := endpoint.(adapter.InterfaceUpdateListener)

View File

@@ -9,7 +9,6 @@ import (
"time" "time"
"github.com/sagernet/sing-box/adapter" "github.com/sagernet/sing-box/adapter"
"github.com/sagernet/sing-box/common/conntrack"
"github.com/sagernet/sing-box/common/process" "github.com/sagernet/sing-box/common/process"
"github.com/sagernet/sing-box/common/sniff" "github.com/sagernet/sing-box/common/sniff"
C "github.com/sagernet/sing-box/constant" C "github.com/sagernet/sing-box/constant"
@@ -80,7 +79,6 @@ func (r *Router) routeConnection(ctx context.Context, conn net.Conn, metadata ad
injectable.NewConnectionEx(ctx, conn, metadata, onClose) injectable.NewConnectionEx(ctx, conn, metadata, onClose)
return nil return nil
} }
conntrack.KillerCheck()
metadata.Network = N.NetworkTCP metadata.Network = N.NetworkTCP
switch metadata.Destination.Fqdn { switch metadata.Destination.Fqdn {
case mux.Destination.Fqdn: case mux.Destination.Fqdn:
@@ -216,8 +214,6 @@ func (r *Router) routePacketConnection(ctx context.Context, conn N.PacketConn, m
injectable.NewPacketConnectionEx(ctx, conn, metadata, onClose) injectable.NewPacketConnectionEx(ctx, conn, metadata, onClose)
return nil return nil
} }
conntrack.KillerCheck()
// TODO: move to UoT // TODO: move to UoT
metadata.Network = N.NetworkUDP metadata.Network = N.NetworkUDP

View File

@@ -0,0 +1,138 @@
//go:build darwin && cgo
package oomkiller
/*
#include <dispatch/dispatch.h>
static dispatch_source_t memoryPressureSource;
extern void goMemoryPressureCallback(unsigned long status);
static void startMemoryPressureMonitor() {
memoryPressureSource = dispatch_source_create(
DISPATCH_SOURCE_TYPE_MEMORYPRESSURE,
0,
DISPATCH_MEMORYPRESSURE_WARN | DISPATCH_MEMORYPRESSURE_CRITICAL,
dispatch_get_global_queue(QOS_CLASS_DEFAULT, 0)
);
dispatch_source_set_event_handler(memoryPressureSource, ^{
unsigned long status = dispatch_source_get_data(memoryPressureSource);
goMemoryPressureCallback(status);
});
dispatch_activate(memoryPressureSource);
}
static void stopMemoryPressureMonitor() {
if (memoryPressureSource) {
dispatch_source_cancel(memoryPressureSource);
memoryPressureSource = NULL;
}
}
*/
import "C"
import (
"context"
runtimeDebug "runtime/debug"
"sync"
"github.com/sagernet/sing-box/adapter"
boxService "github.com/sagernet/sing-box/adapter/service"
boxConstant "github.com/sagernet/sing-box/constant"
"github.com/sagernet/sing-box/log"
"github.com/sagernet/sing-box/option"
"github.com/sagernet/sing/common/memory"
"github.com/sagernet/sing/service"
)
func RegisterService(registry *boxService.Registry) {
boxService.Register[option.OOMKillerServiceOptions](registry, boxConstant.TypeOOMKiller, NewService)
}
var (
globalAccess sync.Mutex
globalServices []*Service
)
type Service struct {
boxService.Adapter
logger log.ContextLogger
router adapter.Router
}
func NewService(ctx context.Context, logger log.ContextLogger, tag string, options option.OOMKillerServiceOptions) (adapter.Service, error) {
return &Service{
Adapter: boxService.NewAdapter(boxConstant.TypeOOMKiller, tag),
logger: logger,
router: service.FromContext[adapter.Router](ctx),
}, nil
}
func (s *Service) Start(stage adapter.StartStage) error {
if stage != adapter.StartStateStart {
return nil
}
globalAccess.Lock()
isFirst := len(globalServices) == 0
globalServices = append(globalServices, s)
globalAccess.Unlock()
if isFirst {
C.startMemoryPressureMonitor()
}
s.logger.Info("started memory pressure monitor")
return nil
}
func (s *Service) Close() error {
globalAccess.Lock()
for i, service := range globalServices {
if service == s {
globalServices = append(globalServices[:i], globalServices[i+1:]...)
break
}
}
isLast := len(globalServices) == 0
globalAccess.Unlock()
if isLast {
C.stopMemoryPressureMonitor()
}
return nil
}
//export goMemoryPressureCallback
func goMemoryPressureCallback(status C.ulong) {
globalAccess.Lock()
services := make([]*Service, len(globalServices))
copy(services, globalServices)
globalAccess.Unlock()
if len(services) == 0 {
return
}
criticalFlag := C.ulong(C.DISPATCH_MEMORYPRESSURE_CRITICAL)
warnFlag := C.ulong(C.DISPATCH_MEMORYPRESSURE_WARN)
isCritical := status&criticalFlag != 0
isWarning := status&warnFlag != 0
var level string
switch {
case isCritical:
level = "critical"
case isWarning:
level = "warning"
default:
level = "normal"
}
for _, s := range services {
if isCritical {
s.logger.Error("memory pressure: ", level, ", usage: ", memory.Total()/(1024*1024), " MiB, resetting network")
s.router.ResetNetwork()
} else if isWarning {
s.logger.Warn("memory pressure: ", level, ", usage: ", memory.Total()/(1024*1024), " MiB")
} else {
s.logger.Debug("memory pressure: ", level, ", usage: ", memory.Total()/(1024*1024), " MiB")
}
}
if isCritical {
runtimeDebug.FreeOSMemory()
}
}

View File

@@ -0,0 +1,39 @@
//go:build !darwin || !cgo
package oomkiller
import (
"context"
"github.com/sagernet/sing-box/adapter"
boxService "github.com/sagernet/sing-box/adapter/service"
C "github.com/sagernet/sing-box/constant"
"github.com/sagernet/sing-box/log"
"github.com/sagernet/sing-box/option"
E "github.com/sagernet/sing/common/exceptions"
)
func RegisterService(registry *boxService.Registry) {
boxService.Register[option.OOMKillerServiceOptions](registry, C.TypeOOMKiller, NewService)
}
type Service struct {
boxService.Adapter
}
func NewService(ctx context.Context, logger log.ContextLogger, tag string, options option.OOMKillerServiceOptions) (adapter.Service, error) {
return &Service{
Adapter: boxService.NewAdapter(C.TypeOOMKiller, tag),
}, nil
}
func (s *Service) Start(stage adapter.StartStage) error {
if stage != adapter.StartStateStart {
return nil
}
return E.New("memory pressure monitoring is not available on this platform")
}
func (s *Service) Close() error {
return nil
}