diff --git a/common/dialer/conntrack/conn.go b/common/conntrack/conn.go similarity index 97% rename from common/dialer/conntrack/conn.go rename to common/conntrack/conn.go index a36d4701..4773d6a8 100644 --- a/common/dialer/conntrack/conn.go +++ b/common/conntrack/conn.go @@ -17,7 +17,7 @@ func NewConn(conn net.Conn) (net.Conn, error) { element := openConnection.PushBack(conn) connAccess.Unlock() if KillerEnabled { - err := killerCheck() + err := KillerCheck() if err != nil { conn.Close() return nil, err diff --git a/common/dialer/conntrack/killer.go b/common/conntrack/killer.go similarity index 63% rename from common/dialer/conntrack/killer.go rename to common/conntrack/killer.go index 40224462..e0a71e5c 100644 --- a/common/dialer/conntrack/killer.go +++ b/common/conntrack/killer.go @@ -1,20 +1,20 @@ package conntrack import ( - "runtime" runtimeDebug "runtime/debug" "time" E "github.com/sagernet/sing/common/exceptions" + "github.com/sagernet/sing/common/memory" ) var ( KillerEnabled bool - MemoryLimit int64 + MemoryLimit uint64 killerLastCheck time.Time ) -func killerCheck() error { +func KillerCheck() error { if !KillerEnabled { return nil } @@ -23,10 +23,7 @@ func killerCheck() error { return nil } killerLastCheck = nowTime - var memStats runtime.MemStats - runtime.ReadMemStats(&memStats) - inuseMemory := int64(memStats.StackInuse + memStats.HeapInuse + memStats.HeapIdle - memStats.HeapReleased) - if inuseMemory > MemoryLimit { + if memory.Total() > MemoryLimit { Close() go func() { time.Sleep(time.Second) diff --git a/common/dialer/conntrack/packet_conn.go b/common/conntrack/packet_conn.go similarity index 97% rename from common/dialer/conntrack/packet_conn.go rename to common/conntrack/packet_conn.go index 6e2d925b..c7274637 100644 --- a/common/dialer/conntrack/packet_conn.go +++ b/common/conntrack/packet_conn.go @@ -18,7 +18,7 @@ func NewPacketConn(conn net.PacketConn) (net.PacketConn, error) { element := openConnection.PushBack(conn) connAccess.Unlock() if KillerEnabled { - err := killerCheck() + err := KillerCheck() if err != nil { conn.Close() return nil, err diff --git a/common/dialer/conntrack/track.go b/common/conntrack/track.go similarity index 100% rename from common/dialer/conntrack/track.go rename to common/conntrack/track.go diff --git a/common/dialer/conntrack/track_disable.go b/common/conntrack/track_disable.go similarity index 100% rename from common/dialer/conntrack/track_disable.go rename to common/conntrack/track_disable.go diff --git a/common/dialer/conntrack/track_enable.go b/common/conntrack/track_enable.go similarity index 100% rename from common/dialer/conntrack/track_enable.go rename to common/conntrack/track_enable.go diff --git a/common/dialer/default.go b/common/dialer/default.go index 4bf51997..f8546fa6 100644 --- a/common/dialer/default.go +++ b/common/dialer/default.go @@ -6,7 +6,7 @@ import ( "time" "github.com/sagernet/sing-box/adapter" - "github.com/sagernet/sing-box/common/dialer/conntrack" + "github.com/sagernet/sing-box/common/conntrack" C "github.com/sagernet/sing-box/constant" "github.com/sagernet/sing-box/option" "github.com/sagernet/sing/common/control" diff --git a/common/humanize/bytes.go b/common/humanize/bytes.go new file mode 100644 index 00000000..6ee4d268 --- /dev/null +++ b/common/humanize/bytes.go @@ -0,0 +1,158 @@ +package humanize + +import ( + "fmt" + "math" + "strconv" + "strings" + "unicode" +) + +// IEC Sizes. +// kibis of bits +const ( + Byte = 1 << (iota * 10) + KiByte + MiByte + GiByte + TiByte + PiByte + EiByte +) + +// SI Sizes. +const ( + IByte = 1 + KByte = IByte * 1000 + MByte = KByte * 1000 + GByte = MByte * 1000 + TByte = GByte * 1000 + PByte = TByte * 1000 + EByte = PByte * 1000 +) + +var defaultSizeTable = map[string]uint64{ + "b": Byte, + "kib": KiByte, + "kb": KByte, + "mib": MiByte, + "mb": MByte, + "gib": GiByte, + "gb": GByte, + "tib": TiByte, + "tb": TByte, + "pib": PiByte, + "pb": PByte, + "eib": EiByte, + "eb": EByte, + // Without suffix + "": Byte, + "ki": KiByte, + "k": KByte, + "mi": MiByte, + "m": MByte, + "gi": GiByte, + "g": GByte, + "ti": TiByte, + "t": TByte, + "pi": PiByte, + "p": PByte, + "ei": EiByte, + "e": EByte, +} + +var memorysSizeTable = map[string]uint64{ + "b": Byte, + "kb": KiByte, + "mb": MiByte, + "gb": GiByte, + "tb": TiByte, + "pb": PiByte, + "eb": EiByte, + "": Byte, + "k": KiByte, + "m": MiByte, + "g": GiByte, + "t": TiByte, + "p": PiByte, + "e": EiByte, +} + +var ( + defaultSizes = []string{"B", "kB", "MB", "GB", "TB", "PB", "EB"} + iSizes = []string{"B", "KiB", "MiB", "GiB", "TiB", "PiB", "EiB"} +) + +func Bytes(s uint64) string { + return humanateBytes(s, 1000, defaultSizes) +} + +func MemoryBytes(s uint64) string { + return humanateBytes(s, 1024, defaultSizes) +} + +func IBytes(s uint64) string { + return humanateBytes(s, 1024, iSizes) +} + +func logn(n, b float64) float64 { + return math.Log(n) / math.Log(b) +} + +func humanateBytes(s uint64, base float64, sizes []string) string { + if s < 10 { + return fmt.Sprintf("%d B", s) + } + e := math.Floor(logn(float64(s), base)) + suffix := sizes[int(e)] + val := math.Floor(float64(s)/math.Pow(base, e)*10+0.5) / 10 + f := "%.0f %s" + if val < 10 { + f = "%.1f %s" + } + + return fmt.Sprintf(f, val, suffix) +} + +func ParseBytes(s string) (uint64, error) { + return parseBytes0(s, defaultSizeTable) +} + +func ParseMemoryBytes(s string) (uint64, error) { + return parseBytes0(s, memorysSizeTable) +} + +func parseBytes0(s string, sizeTable map[string]uint64) (uint64, error) { + lastDigit := 0 + hasComma := false + for _, r := range s { + if !(unicode.IsDigit(r) || r == '.' || r == ',') { + break + } + if r == ',' { + hasComma = true + } + lastDigit++ + } + + num := s[:lastDigit] + if hasComma { + num = strings.Replace(num, ",", "", -1) + } + + f, err := strconv.ParseFloat(num, 64) + if err != nil { + return 0, err + } + + extra := strings.ToLower(strings.TrimSpace(s[lastDigit:])) + if m, ok := sizeTable[extra]; ok { + f *= float64(m) + if f >= math.MaxUint64 { + return 0, fmt.Errorf("too large: %v", s) + } + return uint64(f), nil + } + + return 0, fmt.Errorf("unhandled size name: %v", extra) +} diff --git a/debug_go118.go b/debug_go118.go index 4fe97325..bb132efb 100644 --- a/debug_go118.go +++ b/debug_go118.go @@ -5,7 +5,7 @@ package box import ( "runtime/debug" - "github.com/sagernet/sing-box/common/dialer/conntrack" + "github.com/sagernet/sing-box/common/conntrack" "github.com/sagernet/sing-box/option" ) @@ -28,7 +28,7 @@ func applyDebugOptions(options option.DebugOptions) { } if options.MemoryLimit != 0 { // debug.SetMemoryLimit(int64(options.MemoryLimit)) - conntrack.MemoryLimit = int64(options.MemoryLimit) + conntrack.MemoryLimit = uint64(options.MemoryLimit) } if options.OOMKiller != nil { conntrack.KillerEnabled = *options.OOMKiller diff --git a/debug_go119.go b/debug_go119.go index ef90da6d..a7814613 100644 --- a/debug_go119.go +++ b/debug_go119.go @@ -5,7 +5,7 @@ package box import ( "runtime/debug" - "github.com/sagernet/sing-box/common/dialer/conntrack" + "github.com/sagernet/sing-box/common/conntrack" "github.com/sagernet/sing-box/option" ) @@ -28,7 +28,7 @@ func applyDebugOptions(options option.DebugOptions) { } if options.MemoryLimit != 0 { debug.SetMemoryLimit(int64(options.MemoryLimit)) - conntrack.MemoryLimit = int64(options.MemoryLimit) + conntrack.MemoryLimit = uint64(options.MemoryLimit) } if options.OOMKiller != nil { conntrack.KillerEnabled = *options.OOMKiller diff --git a/debug_http.go b/debug_http.go index 30134592..7c675eba 100644 --- a/debug_http.go +++ b/debug_http.go @@ -7,12 +7,12 @@ import ( "runtime/debug" "github.com/sagernet/sing-box/common/badjson" + "github.com/sagernet/sing-box/common/humanize" "github.com/sagernet/sing-box/common/json" "github.com/sagernet/sing-box/log" "github.com/sagernet/sing-box/option" E "github.com/sagernet/sing/common/exceptions" - "github.com/dustin/go-humanize" "github.com/go-chi/chi/v5" ) @@ -37,9 +37,9 @@ func applyDebugListenOption(options option.DebugOptions) { runtime.ReadMemStats(&memStats) var memObject badjson.JSONObject - memObject.Put("heap", humanize.IBytes(memStats.HeapInuse)) - memObject.Put("stack", humanize.IBytes(memStats.StackInuse)) - memObject.Put("idle", humanize.IBytes(memStats.HeapIdle-memStats.HeapReleased)) + memObject.Put("heap", humanize.MemoryBytes(memStats.HeapInuse)) + memObject.Put("stack", humanize.MemoryBytes(memStats.StackInuse)) + memObject.Put("idle", humanize.MemoryBytes(memStats.HeapIdle-memStats.HeapReleased)) memObject.Put("goroutines", runtime.NumGoroutine()) memObject.Put("rss", rusageMaxRSS()) diff --git a/experimental/libbox/command_conntrack.go b/experimental/libbox/command_conntrack.go index dbc7738a..cf8389a6 100644 --- a/experimental/libbox/command_conntrack.go +++ b/experimental/libbox/command_conntrack.go @@ -6,7 +6,7 @@ import ( runtimeDebug "runtime/debug" "time" - "github.com/sagernet/sing-box/common/dialer/conntrack" + "github.com/sagernet/sing-box/common/conntrack" ) func (c *CommandClient) CloseConnections() error { diff --git a/experimental/libbox/command_status.go b/experimental/libbox/command_status.go index d7438fae..dbf1ad2e 100644 --- a/experimental/libbox/command_status.go +++ b/experimental/libbox/command_status.go @@ -6,13 +6,15 @@ import ( "runtime" "time" - "github.com/sagernet/sing-box/common/dialer/conntrack" + "github.com/sagernet/sing-box/common/conntrack" "github.com/sagernet/sing-box/experimental/clashapi" E "github.com/sagernet/sing/common/exceptions" + "github.com/sagernet/sing/common/memory" ) type StatusMessage struct { Memory int64 + MemoryInuse int64 Goroutines int32 ConnectionsIn int32 ConnectionsOut int32 @@ -24,10 +26,8 @@ type StatusMessage struct { } func (s *CommandServer) readStatus() StatusMessage { - var memStats runtime.MemStats - runtime.ReadMemStats(&memStats) var message StatusMessage - message.Memory = int64(memStats.StackInuse + memStats.HeapInuse + memStats.HeapIdle - memStats.HeapReleased) + message.Memory = int64(memory.Inuse()) message.Goroutines = int32(runtime.NumGoroutine()) message.ConnectionsOut = int32(conntrack.Count()) diff --git a/experimental/libbox/memory.go b/experimental/libbox/memory.go index b3c72570..b10c6701 100644 --- a/experimental/libbox/memory.go +++ b/experimental/libbox/memory.go @@ -4,14 +4,15 @@ import ( "math" runtimeDebug "runtime/debug" - "github.com/sagernet/sing-box/common/dialer/conntrack" + "github.com/sagernet/sing-box/common/conntrack" ) func SetMemoryLimit(enabled bool) { - const memoryLimit = 30 * 1024 * 1024 + const memoryLimit = 45 * 1024 * 1024 + const memoryLimitGo = memoryLimit / 1.5 if enabled { runtimeDebug.SetGCPercent(10) - runtimeDebug.SetMemoryLimit(memoryLimit) + runtimeDebug.SetMemoryLimit(memoryLimitGo) conntrack.KillerEnabled = true conntrack.MemoryLimit = memoryLimit } else { diff --git a/experimental/libbox/setup.go b/experimental/libbox/setup.go index e028151f..8204a968 100644 --- a/experimental/libbox/setup.go +++ b/experimental/libbox/setup.go @@ -5,9 +5,8 @@ import ( "os/user" "strconv" + "github.com/sagernet/sing-box/common/humanize" C "github.com/sagernet/sing-box/constant" - - "github.com/dustin/go-humanize" ) var ( @@ -46,7 +45,11 @@ func Version() string { } func FormatBytes(length int64) string { - return humanize.IBytes(uint64(length)) + return humanize.Bytes(uint64(length)) +} + +func FormatMemoryBytes(length int64) string { + return humanize.MemoryBytes(uint64(length)) } func ProxyDisplayType(proxyType string) string { diff --git a/go.mod b/go.mod index bf77c4df..2158c5c4 100644 --- a/go.mod +++ b/go.mod @@ -8,7 +8,6 @@ require ( github.com/caddyserver/certmagic v0.19.2 github.com/cloudflare/circl v1.3.3 github.com/cretz/bine v0.2.0 - github.com/dustin/go-humanize v1.0.1 github.com/fsnotify/fsnotify v1.6.0 github.com/go-chi/chi/v5 v5.0.10 github.com/go-chi/cors v1.2.1 @@ -28,14 +27,14 @@ require ( github.com/sagernet/gvisor v0.0.0-20230627031050-1ab0276e0dd2 github.com/sagernet/quic-go v0.0.0-20230919101909-0cc6c5dcecee github.com/sagernet/reality v0.0.0-20230406110435-ee17307e7691 - github.com/sagernet/sing v0.2.10-0.20230912050851-1453c7c8c20d + github.com/sagernet/sing v0.2.10-0.20230920060554-3c4a2b06a988 github.com/sagernet/sing-dns v0.1.9-0.20230919110447-d24aeae07601 github.com/sagernet/sing-mux v0.1.3-0.20230908032617-759a1886a400 github.com/sagernet/sing-quic v0.0.0-20230919102644-5874c56aae1c github.com/sagernet/sing-shadowsocks v0.2.5-0.20230907005610-126234728ca0 github.com/sagernet/sing-shadowsocks2 v0.1.4-0.20230907005906-5d2917b29248 github.com/sagernet/sing-shadowtls v0.1.4 - github.com/sagernet/sing-tun v0.1.12-0.20230821065522-7545dc2d5641 + github.com/sagernet/sing-tun v0.1.12-0.20230920060816-9c933ea55308 github.com/sagernet/sing-vmess v0.1.8-0.20230907010359-161fb0ac716b github.com/sagernet/smux v0.0.0-20230312102458-337ec2a5af37 github.com/sagernet/tfo-go v0.0.0-20230816093905-5a5c285d44a6 @@ -58,7 +57,6 @@ require ( ) //replace github.com/sagernet/sing => ../sing - require ( github.com/Dreamacro/protobytes v0.0.0-20230617041236-6500a9f4f158 // indirect github.com/ajg/form v1.5.1 // indirect diff --git a/go.sum b/go.sum index 740e83ab..c77e0a64 100644 --- a/go.sum +++ b/go.sum @@ -22,8 +22,6 @@ github.com/cretz/bine v0.2.0/go.mod h1:WU4o9QR9wWp8AVKtTM1XD5vUHkEqnf2vVSo6dBqbe github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= -github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY= github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= github.com/go-chi/chi/v5 v5.0.10 h1:rLz5avzKpjqxrYwXNfmjkrYYXOyLJd37pz53UFHC6vk= @@ -116,8 +114,8 @@ github.com/sagernet/reality v0.0.0-20230406110435-ee17307e7691 h1:5Th31OC6yj8byL github.com/sagernet/reality v0.0.0-20230406110435-ee17307e7691/go.mod h1:B8lp4WkQ1PwNnrVMM6KyuFR20pU8jYBD+A4EhJovEXU= github.com/sagernet/sing v0.0.0-20220817130738-ce854cda8522/go.mod h1:QVsS5L/ZA2Q5UhQwLrn0Trw+msNd/NPGEhBKR/ioWiY= github.com/sagernet/sing v0.1.8/go.mod h1:jt1w2u7lJQFFSGLiRrRIs5YWmx4kAPfWuOejuDW9qMk= -github.com/sagernet/sing v0.2.10-0.20230912050851-1453c7c8c20d h1:dWUNsHDX8EMeGj1XCnrVtydy5C+5D+Orc5JjZP7myHg= -github.com/sagernet/sing v0.2.10-0.20230912050851-1453c7c8c20d/go.mod h1:9uOZwWkhT2Z2WldolLxX34s+1svAX4i4vvz5hy8u1MA= +github.com/sagernet/sing v0.2.10-0.20230920060554-3c4a2b06a988 h1:Z2jW5Y03JBDgXHkCoxlO4+kDfHKMKjVVV8wu8BmNKEM= +github.com/sagernet/sing v0.2.10-0.20230920060554-3c4a2b06a988/go.mod h1:9uOZwWkhT2Z2WldolLxX34s+1svAX4i4vvz5hy8u1MA= github.com/sagernet/sing-dns v0.1.9-0.20230919110447-d24aeae07601 h1:UJYRkncWVpNdNIXeJV/eBilTc3Rga9G1SDBWjKSxL4w= github.com/sagernet/sing-dns v0.1.9-0.20230919110447-d24aeae07601/go.mod h1:Kg98PBJEg/08jsNFtmZWmPomhskn9Ausn50ecNm4M+8= github.com/sagernet/sing-mux v0.1.3-0.20230908032617-759a1886a400 h1:LtpYd5c5AJtUSxjyH4KjUS8HT+2XgilyozjbCq/x3EM= @@ -130,8 +128,8 @@ github.com/sagernet/sing-shadowsocks2 v0.1.4-0.20230907005906-5d2917b29248 h1:JT github.com/sagernet/sing-shadowsocks2 v0.1.4-0.20230907005906-5d2917b29248/go.mod h1:DOhJc/cLeqRv0wuePrQso+iUmDxOnWF4eT/oMcRzYFw= github.com/sagernet/sing-shadowtls v0.1.4 h1:aTgBSJEgnumzFenPvc+kbD9/W0PywzWevnVpEx6Tw3k= github.com/sagernet/sing-shadowtls v0.1.4/go.mod h1:F8NBgsY5YN2beQavdgdm1DPlhaKQlaL6lpDdcBglGK4= -github.com/sagernet/sing-tun v0.1.12-0.20230821065522-7545dc2d5641 h1:a8lktNrCWZJisB+nPraW+qB73ZofgPtGmlfqNYcO79g= -github.com/sagernet/sing-tun v0.1.12-0.20230821065522-7545dc2d5641/go.mod h1:+YImslQMLgMQcVgZZ9IK4ue1o/605VSU90amHUcp4hA= +github.com/sagernet/sing-tun v0.1.12-0.20230920060816-9c933ea55308 h1:v94hR0DSnqvkk8GYOgN3UytXZGA2KSpkNrt3y3CBWsA= +github.com/sagernet/sing-tun v0.1.12-0.20230920060816-9c933ea55308/go.mod h1:+YImslQMLgMQcVgZZ9IK4ue1o/605VSU90amHUcp4hA= github.com/sagernet/sing-vmess v0.1.8-0.20230907010359-161fb0ac716b h1:2ezfJtH5JosiEwJhVa+rimQ6ps/t2+7h+mOzMoiaZnA= github.com/sagernet/sing-vmess v0.1.8-0.20230907010359-161fb0ac716b/go.mod h1:1qkC1L1T2sxnS/NuO6HU72S8TkltV+EXoKGR29m/Yss= github.com/sagernet/smux v0.0.0-20230312102458-337ec2a5af37 h1:HuE6xSwco/Xed8ajZ+coeYLmioq0Qp1/Z2zczFaV8as= diff --git a/option/debug.go b/option/debug.go index 68b6f79b..17fb05d0 100644 --- a/option/debug.go +++ b/option/debug.go @@ -3,7 +3,7 @@ package option import ( "encoding/json" - "github.com/dustin/go-humanize" + "github.com/sagernet/sing-box/common/humanize" ) type DebugOptions struct { @@ -13,21 +13,21 @@ type DebugOptions struct { MaxThreads *int `json:"max_threads,omitempty"` PanicOnFault *bool `json:"panic_on_fault,omitempty"` TraceBack string `json:"trace_back,omitempty"` - MemoryLimit BytesLength `json:"memory_limit,omitempty"` + MemoryLimit MemoryBytes `json:"memory_limit,omitempty"` OOMKiller *bool `json:"oom_killer,omitempty"` } -type BytesLength int64 +type MemoryBytes uint64 -func (l BytesLength) MarshalJSON() ([]byte, error) { - return json.Marshal(humanize.IBytes(uint64(l))) +func (l MemoryBytes) MarshalJSON() ([]byte, error) { + return json.Marshal(humanize.MemoryBytes(uint64(l))) } -func (l *BytesLength) UnmarshalJSON(bytes []byte) error { +func (l *MemoryBytes) UnmarshalJSON(bytes []byte) error { var valueInteger int64 err := json.Unmarshal(bytes, &valueInteger) if err == nil { - *l = BytesLength(valueInteger) + *l = MemoryBytes(valueInteger) return nil } var valueString string @@ -35,10 +35,10 @@ func (l *BytesLength) UnmarshalJSON(bytes []byte) error { if err != nil { return err } - parsedValue, err := humanize.ParseBytes(valueString) + parsedValue, err := humanize.ParseMemoryBytes(valueString) if err != nil { return err } - *l = BytesLength(parsedValue) + *l = MemoryBytes(parsedValue) return nil } diff --git a/route/router.go b/route/router.go index c34c5368..9b302d5e 100644 --- a/route/router.go +++ b/route/router.go @@ -12,8 +12,8 @@ import ( "time" "github.com/sagernet/sing-box/adapter" + "github.com/sagernet/sing-box/common/conntrack" "github.com/sagernet/sing-box/common/dialer" - "github.com/sagernet/sing-box/common/dialer/conntrack" "github.com/sagernet/sing-box/common/geoip" "github.com/sagernet/sing-box/common/geosite" "github.com/sagernet/sing-box/common/mux" @@ -602,6 +602,7 @@ func (r *Router) RouteConnection(ctx context.Context, conn net.Conn, metadata ad } return nil } + conntrack.KillerCheck() metadata.Network = N.NetworkTCP switch metadata.Destination.Fqdn { case mux.Destination.Fqdn: @@ -738,6 +739,7 @@ func (r *Router) RoutePacketConnection(ctx context.Context, conn N.PacketConn, m } return nil } + conntrack.KillerCheck() metadata.Network = N.NetworkUDP if r.fakeIPStore != nil && r.fakeIPStore.Contains(metadata.Destination.Addr) { @@ -915,13 +917,21 @@ func (r *Router) AutoDetectInterfaceFunc() control.Func { if r.platformInterface != nil && r.platformInterface.UsePlatformAutoDetectInterfaceControl() { return r.platformInterface.AutoDetectInterfaceControl() } else { - return control.BindToInterfaceFunc(r.InterfaceFinder(), func(network string, address string) (interfaceName string, interfaceIndex int) { + return control.BindToInterfaceFunc(r.InterfaceFinder(), func(network string, address string) (interfaceName string, interfaceIndex int, err error) { remoteAddr := M.ParseSocksaddr(address).Addr if C.IsLinux { - return r.InterfaceMonitor().DefaultInterfaceName(remoteAddr), -1 + interfaceName = r.InterfaceMonitor().DefaultInterfaceName(remoteAddr) + interfaceIndex = -1 + if interfaceName == "" { + err = tun.ErrNoRoute + } } else { - return "", r.InterfaceMonitor().DefaultInterfaceIndex(remoteAddr) + interfaceIndex = r.InterfaceMonitor().DefaultInterfaceIndex(remoteAddr) + if interfaceIndex == -1 { + err = tun.ErrNoRoute + } } + return }) } } diff --git a/test/go.mod b/test/go.mod index 18d34d41..ace29a13 100644 --- a/test/go.mod +++ b/test/go.mod @@ -12,7 +12,7 @@ require ( github.com/docker/docker v24.0.5+incompatible github.com/docker/go-connections v0.4.0 github.com/gofrs/uuid/v5 v5.0.0 - github.com/sagernet/sing v0.2.10-0.20230912050851-1453c7c8c20d + github.com/sagernet/sing v0.2.10-0.20230920060554-3c4a2b06a988 github.com/sagernet/sing-quic v0.0.0-20230919102644-5874c56aae1c github.com/sagernet/sing-shadowsocks v0.2.5-0.20230907005610-126234728ca0 github.com/sagernet/sing-shadowsocks2 v0.1.4-0.20230907005906-5d2917b29248 @@ -79,7 +79,7 @@ require ( github.com/sagernet/sing-dns v0.1.9-0.20230919110447-d24aeae07601 // indirect github.com/sagernet/sing-mux v0.1.3-0.20230908032617-759a1886a400 // indirect github.com/sagernet/sing-shadowtls v0.1.4 // indirect - github.com/sagernet/sing-tun v0.1.12-0.20230821065522-7545dc2d5641 // indirect + github.com/sagernet/sing-tun v0.1.12-0.20230920060816-9c933ea55308 // indirect github.com/sagernet/sing-vmess v0.1.8-0.20230907010359-161fb0ac716b // indirect github.com/sagernet/smux v0.0.0-20230312102458-337ec2a5af37 // indirect github.com/sagernet/tfo-go v0.0.0-20230816093905-5a5c285d44a6 // indirect diff --git a/test/go.sum b/test/go.sum index 69204a23..f18d830e 100644 --- a/test/go.sum +++ b/test/go.sum @@ -133,6 +133,8 @@ github.com/sagernet/sing v0.0.0-20220817130738-ce854cda8522/go.mod h1:QVsS5L/ZA2 github.com/sagernet/sing v0.1.8/go.mod h1:jt1w2u7lJQFFSGLiRrRIs5YWmx4kAPfWuOejuDW9qMk= github.com/sagernet/sing v0.2.10-0.20230912050851-1453c7c8c20d h1:dWUNsHDX8EMeGj1XCnrVtydy5C+5D+Orc5JjZP7myHg= github.com/sagernet/sing v0.2.10-0.20230912050851-1453c7c8c20d/go.mod h1:9uOZwWkhT2Z2WldolLxX34s+1svAX4i4vvz5hy8u1MA= +github.com/sagernet/sing v0.2.10-0.20230920054954-313025d13dea/go.mod h1:9uOZwWkhT2Z2WldolLxX34s+1svAX4i4vvz5hy8u1MA= +github.com/sagernet/sing v0.2.10-0.20230920060554-3c4a2b06a988/go.mod h1:9uOZwWkhT2Z2WldolLxX34s+1svAX4i4vvz5hy8u1MA= github.com/sagernet/sing-dns v0.1.9-0.20230919110447-d24aeae07601 h1:UJYRkncWVpNdNIXeJV/eBilTc3Rga9G1SDBWjKSxL4w= github.com/sagernet/sing-dns v0.1.9-0.20230919110447-d24aeae07601/go.mod h1:Kg98PBJEg/08jsNFtmZWmPomhskn9Ausn50ecNm4M+8= github.com/sagernet/sing-mux v0.1.3-0.20230908032617-759a1886a400 h1:LtpYd5c5AJtUSxjyH4KjUS8HT+2XgilyozjbCq/x3EM= @@ -145,6 +147,7 @@ github.com/sagernet/sing-shadowtls v0.1.4 h1:aTgBSJEgnumzFenPvc+kbD9/W0PywzWevnV github.com/sagernet/sing-shadowtls v0.1.4/go.mod h1:F8NBgsY5YN2beQavdgdm1DPlhaKQlaL6lpDdcBglGK4= github.com/sagernet/sing-tun v0.1.12-0.20230821065522-7545dc2d5641 h1:a8lktNrCWZJisB+nPraW+qB73ZofgPtGmlfqNYcO79g= github.com/sagernet/sing-tun v0.1.12-0.20230821065522-7545dc2d5641/go.mod h1:+YImslQMLgMQcVgZZ9IK4ue1o/605VSU90amHUcp4hA= +github.com/sagernet/sing-tun v0.1.12-0.20230920060816-9c933ea55308/go.mod h1:+YImslQMLgMQcVgZZ9IK4ue1o/605VSU90amHUcp4hA= github.com/sagernet/sing-vmess v0.1.8-0.20230907010359-161fb0ac716b h1:2ezfJtH5JosiEwJhVa+rimQ6ps/t2+7h+mOzMoiaZnA= github.com/sagernet/sing-vmess v0.1.8-0.20230907010359-161fb0ac716b/go.mod h1:1qkC1L1T2sxnS/NuO6HU72S8TkltV+EXoKGR29m/Yss= github.com/sagernet/smux v0.0.0-20230312102458-337ec2a5af37 h1:HuE6xSwco/Xed8ajZ+coeYLmioq0Qp1/Z2zczFaV8as= diff --git a/transport/dhcp/server.go b/transport/dhcp/server.go index 85c7a0d6..7288b94d 100644 --- a/transport/dhcp/server.go +++ b/transport/dhcp/server.go @@ -174,9 +174,7 @@ func (t *Transport) interfaceUpdated(int) { func (t *Transport) fetchServers0(ctx context.Context, iface *net.Interface) error { var listener net.ListenConfig - listener.Control = control.Append(listener.Control, control.BindToInterfaceFunc(t.router.InterfaceFinder(), func(network string, address string) (interfaceName string, interfaceIndex int) { - return iface.Name, iface.Index - })) + listener.Control = control.Append(listener.Control, control.BindToInterface(t.router.InterfaceFinder(), iface.Name, iface.Index)) listener.Control = control.Append(listener.Control, control.ReuseAddr()) packetConn, err := listener.ListenPacket(t.ctx, "udp4", "0.0.0.0:68") if err != nil {