diff --git a/clients/android b/clients/android index cec05bf6..320170a1 160000 --- a/clients/android +++ b/clients/android @@ -1 +1 @@ -Subproject commit cec05bf6935eca219a722883212ae8880d2e863e +Subproject commit 320170a1077ea5c93872b3e055b96b8836615ef0 diff --git a/docs/changelog.md b/docs/changelog.md index e1aa7942..71f261c9 100644 --- a/docs/changelog.md +++ b/docs/changelog.md @@ -2,6 +2,13 @@ icon: material/alert-decagram --- +### 1.11.13 + +* Fixes and improvements + +_We are temporarily unable to update sing-box apps on the App Store because the reviewer mistakenly found that we +violated the rules (TestFlight users are not affected)._ + ### 1.11.11 * Fixes and improvements diff --git a/docs/configuration/inbound/tun.zh.md b/docs/configuration/inbound/tun.zh.md index b3b561f1..391097eb 100644 --- a/docs/configuration/inbound/tun.zh.md +++ b/docs/configuration/inbound/tun.zh.md @@ -398,11 +398,11 @@ UDP NAT 过期时间。 TCP/IP 栈。 -| 栈 | 描述 | -|--------|------------------------------------------------------------------| -| system | 基于系统网络栈执行 L3 到 L4 转换 | -| gVisor | 基于 [gVisor](https://github.com/google/gvisor) 虚拟网络栈执行 L3 到 L4 转换 | -| mixed | 混合 `system` TCP 栈与 `gvisor` UDP 栈 | +| 栈 | 描述 | +|----------|-------------------------------------------------------------------------------------------------------| +| `system` | 基于系统网络栈执行 L3 到 L4 转换 | +| `gvisor` | 基于 [gVisor](https://github.com/google/gvisor) 虚拟网络栈执行 L3 到 L4 转换 | +| `mixed` | 混合 `system` TCP 栈与 `gvisor` UDP 栈 | 默认使用 `mixed` 栈如果 gVisor 构建标记已启用,否则默认使用 `system` 栈。 diff --git a/go.mod b/go.mod index 6f34cf6f..3720ce6a 100644 --- a/go.mod +++ b/go.mod @@ -29,15 +29,15 @@ require ( github.com/sagernet/gvisor v0.0.0-20241123041152-536d05261cff github.com/sagernet/quic-go v0.49.0-beta.1 github.com/sagernet/reality v0.0.0-20230406110435-ee17307e7691 - github.com/sagernet/sing v0.6.9 - github.com/sagernet/sing-dns v0.4.3 + github.com/sagernet/sing v0.6.10 + github.com/sagernet/sing-dns v0.4.5 github.com/sagernet/sing-mux v0.3.2 - github.com/sagernet/sing-quic v0.4.1-0.20250423030647-0eb05f373a76 - github.com/sagernet/sing-shadowsocks v0.2.7 - github.com/sagernet/sing-shadowsocks2 v0.2.0 + github.com/sagernet/sing-quic v0.4.3 + github.com/sagernet/sing-shadowsocks v0.2.8 + github.com/sagernet/sing-shadowsocks2 v0.2.1 github.com/sagernet/sing-shadowtls v0.2.0 github.com/sagernet/sing-tun v0.6.5 - github.com/sagernet/sing-vmess v0.2.1 + github.com/sagernet/sing-vmess v0.2.3 github.com/sagernet/smux v1.5.34-mod.2 github.com/sagernet/utls v1.6.7 github.com/sagernet/wireguard-go v0.0.1-beta.7 diff --git a/go.sum b/go.sum index 60754528..f5fcf5c1 100644 --- a/go.sum +++ b/go.sum @@ -130,24 +130,25 @@ github.com/sagernet/quic-go v0.49.0-beta.1 h1:3LdoCzVVfYRibZns1tYWSIoB65fpTmrwy+ github.com/sagernet/quic-go v0.49.0-beta.1/go.mod h1:uesWD1Ihrldq1M3XtjuEvIUqi8WHNsRs71b3Lt1+p/U= github.com/sagernet/reality v0.0.0-20230406110435-ee17307e7691 h1:5Th31OC6yj8byLGkEnIYp6grlXfo1QYUfiYFGjewIdc= github.com/sagernet/reality v0.0.0-20230406110435-ee17307e7691/go.mod h1:B8lp4WkQ1PwNnrVMM6KyuFR20pU8jYBD+A4EhJovEXU= -github.com/sagernet/sing v0.6.9 h1:y/XJH17oyBd6hxgQtKnIdLXu7TsOHxO5i1JeVfVmjXw= github.com/sagernet/sing v0.6.9/go.mod h1:ARkL0gM13/Iv5VCZmci/NuoOlePoIsW0m7BWfln/Hak= -github.com/sagernet/sing-dns v0.4.3 h1:R6X9oWYbdZ0Mm+8PkdqrBkqx3JwiAbnETUZGOpEdY4E= -github.com/sagernet/sing-dns v0.4.3/go.mod h1:dweQs54ng2YGzoJfz+F9dGuDNdP5pJ3PLeggnK5VWc8= +github.com/sagernet/sing v0.6.10 h1:Jey1tePgH9bjFuK1fQI3D9T+bPOQ4SdHMjuS4sYjDv4= +github.com/sagernet/sing v0.6.10/go.mod h1:ARkL0gM13/Iv5VCZmci/NuoOlePoIsW0m7BWfln/Hak= +github.com/sagernet/sing-dns v0.4.5 h1:D9REN14qx2FTrZRBrtFLL99f2CuFzQ9S7mIf8uV5hZI= +github.com/sagernet/sing-dns v0.4.5/go.mod h1:dweQs54ng2YGzoJfz+F9dGuDNdP5pJ3PLeggnK5VWc8= github.com/sagernet/sing-mux v0.3.2 h1:meZVFiiStvHThb/trcpAkCrmtJOuItG5Dzl1RRP5/NE= github.com/sagernet/sing-mux v0.3.2/go.mod h1:pht8iFY4c9Xltj7rhVd208npkNaeCxzyXCgulDPLUDA= -github.com/sagernet/sing-quic v0.4.1-0.20250423030647-0eb05f373a76 h1:iwpCX6H3nZEOGUGwx0q5azcgYOA9f6v9YssihXoRKHk= -github.com/sagernet/sing-quic v0.4.1-0.20250423030647-0eb05f373a76/go.mod h1:tqPa0/Wqa19MkkSlKVZZX5sHxtiDR9BROcn4ufcbVdY= -github.com/sagernet/sing-shadowsocks v0.2.7 h1:zaopR1tbHEw5Nk6FAkM05wCslV6ahVegEZaKMv9ipx8= -github.com/sagernet/sing-shadowsocks v0.2.7/go.mod h1:0rIKJZBR65Qi0zwdKezt4s57y/Tl1ofkaq6NlkzVuyE= -github.com/sagernet/sing-shadowsocks2 v0.2.0 h1:wpZNs6wKnR7mh1wV9OHwOyUr21VkS3wKFHi+8XwgADg= -github.com/sagernet/sing-shadowsocks2 v0.2.0/go.mod h1:RnXS0lExcDAovvDeniJ4IKa2IuChrdipolPYWBv9hWQ= +github.com/sagernet/sing-quic v0.4.3 h1:OZ/kGvSzjtYg+t0DY3F606hlT5LeiQQXDxfBopcRryQ= +github.com/sagernet/sing-quic v0.4.3/go.mod h1:tqPa0/Wqa19MkkSlKVZZX5sHxtiDR9BROcn4ufcbVdY= +github.com/sagernet/sing-shadowsocks v0.2.8 h1:PURj5PRoAkqeHh2ZW205RWzN9E9RtKCVCzByXruQWfE= +github.com/sagernet/sing-shadowsocks v0.2.8/go.mod h1:lo7TWEMDcN5/h5B8S0ew+r78ZODn6SwVaFhvB6H+PTI= +github.com/sagernet/sing-shadowsocks2 v0.2.1 h1:dWV9OXCeFPuYGHb6IRqlSptVnSzOelnqqs2gQ2/Qioo= +github.com/sagernet/sing-shadowsocks2 v0.2.1/go.mod h1:RnXS0lExcDAovvDeniJ4IKa2IuChrdipolPYWBv9hWQ= github.com/sagernet/sing-shadowtls v0.2.0 h1:cLKe4OAOFwuhmAIuPLj//CIL7Q9js+pIDardhJ+/osk= github.com/sagernet/sing-shadowtls v0.2.0/go.mod h1:agU+Fw5X+xnWVyRHyFthoZCX3MfWKCFPm4JUf+1oaxo= github.com/sagernet/sing-tun v0.6.5 h1:nGfD6GNq/r0tEjdZHOV3BS6fydSmd4kBAokU5rffssg= github.com/sagernet/sing-tun v0.6.5/go.mod h1:fisFCbC4Vfb6HqQNcwPJi2CDK2bf0Xapyz3j3t4cnHE= -github.com/sagernet/sing-vmess v0.2.1 h1:6izHC2+B68aQCxTagki6eZZc+g5eh4dYwxOV5a2Lhug= -github.com/sagernet/sing-vmess v0.2.1/go.mod h1:jDAZ0A0St1zVRkyvhAPRySOFfhC+4SQtO5VYyeFotgA= +github.com/sagernet/sing-vmess v0.2.3 h1:z6Ym8dnZG7k1fP3+54vz8G0tvRVJeOoTFFeUPwXTD44= +github.com/sagernet/sing-vmess v0.2.3/go.mod h1:jDAZ0A0St1zVRkyvhAPRySOFfhC+4SQtO5VYyeFotgA= github.com/sagernet/smux v1.5.34-mod.2 h1:gkmBjIjlJ2zQKpLigOkFur5kBKdV6bNRoFu2WkltRQ4= github.com/sagernet/smux v1.5.34-mod.2/go.mod h1:0KW0+R+ycvA2INW4gbsd7BNyg+HEfLIAxa5N02/28Zc= github.com/sagernet/utls v1.6.7 h1:Ep3+aJ8FUGGta+II2IEVNUc3EDhaRCZINWkj/LloIA8= diff --git a/protocol/tun/inbound.go b/protocol/tun/inbound.go index 70f78c0a..ff026553 100644 --- a/protocol/tun/inbound.go +++ b/protocol/tun/inbound.go @@ -214,7 +214,6 @@ func NewInbound(ctx context.Context, router adapter.Router, logger log.ContextLo if !loaded { return nil, E.New("parse route_address_set: rule-set not found: ", routeAddressSet) } - ruleSet.IncRef() inbound.routeRuleSet = append(inbound.routeRuleSet, ruleSet) } for _, routeExcludeAddressSet := range options.RouteExcludeAddressSet { @@ -222,7 +221,6 @@ func NewInbound(ctx context.Context, router adapter.Router, logger log.ContextLo if !loaded { return nil, E.New("parse route_exclude_address_set: rule-set not found: ", routeExcludeAddressSet) } - ruleSet.IncRef() inbound.routeExcludeRuleSet = append(inbound.routeExcludeRuleSet, ruleSet) } if options.AutoRedirect { @@ -312,7 +310,7 @@ func (t *Inbound) Start(stage adapter.StartStage) error { if len(ipSets) == 0 { t.logger.Warn("route_address_set: no destination IP CIDR rules found in rule-set: ", routeRuleSet.Name()) } - routeRuleSet.DecRef() + routeRuleSet.IncRef() t.routeAddressSet = append(t.routeAddressSet, ipSets...) if t.autoRedirect != nil { t.routeRuleSetCallback = append(t.routeRuleSetCallback, routeRuleSet.RegisterCallback(t.updateRouteAddressSet)) @@ -324,7 +322,7 @@ func (t *Inbound) Start(stage adapter.StartStage) error { if len(ipSets) == 0 { t.logger.Warn("route_address_set: no destination IP CIDR rules found in rule-set: ", routeExcludeRuleSet.Name()) } - routeExcludeRuleSet.DecRef() + routeExcludeRuleSet.IncRef() t.routeExcludeAddressSet = append(t.routeExcludeAddressSet, ipSets...) if t.autoRedirect != nil { t.routeExcludeRuleSetCallback = append(t.routeExcludeRuleSetCallback, routeExcludeRuleSet.RegisterCallback(t.updateRouteAddressSet)) diff --git a/route/route.go b/route/route.go index f3e7a983..d0f93e0b 100644 --- a/route/route.go +++ b/route/route.go @@ -176,8 +176,6 @@ func (r *Router) RoutePacketConnectionEx(ctx context.Context, conn N.PacketConn, } else { r.logger.ErrorContext(ctx, err) } - } else if onClose != nil { - onClose(nil) } } @@ -498,7 +496,9 @@ func (r *Router) actionSniff( return } if inputConn != nil { - sniffBuffer := buf.NewPacket() + if len(action.StreamSniffers) == 0 && len(action.PacketSniffers) > 0 { + return + } var streamSniffers []sniff.StreamSniffer if len(action.StreamSniffers) > 0 { streamSniffers = action.StreamSniffers @@ -512,6 +512,7 @@ func (r *Router) actionSniff( sniff.RDP, } } + sniffBuffer := buf.NewPacket() err := sniff.PeekStream( ctx, metadata, @@ -543,10 +544,25 @@ func (r *Router) actionSniff( sniffBuffer.Release() } } else if inputPacketConn != nil { - if metadata.PacketSniffError != nil && !errors.Is(metadata.PacketSniffError, sniff.ErrNeedMoreData) { + if len(action.PacketSniffers) == 0 && len(action.StreamSniffers) > 0 { + return + } else if metadata.PacketSniffError != nil && !errors.Is(metadata.PacketSniffError, sniff.ErrNeedMoreData) { r.logger.DebugContext(ctx, "packet sniff skipped due to previous error: ", metadata.PacketSniffError) return } + var packetSniffers []sniff.PacketSniffer + if len(action.PacketSniffers) > 0 { + packetSniffers = action.PacketSniffers + } else { + packetSniffers = []sniff.PacketSniffer{ + sniff.DomainNameQuery, + sniff.QUICClientHello, + sniff.STUNMessage, + sniff.UTP, + sniff.UDPTracker, + sniff.DTLSRecord, + } + } for { var ( sniffBuffer = buf.NewPacket() @@ -586,19 +602,6 @@ func (r *Router) actionSniff( sniff.QUICClientHello, ) } else { - var packetSniffers []sniff.PacketSniffer - if len(action.PacketSniffers) > 0 { - packetSniffers = action.PacketSniffers - } else { - packetSniffers = []sniff.PacketSniffer{ - sniff.DomainNameQuery, - sniff.QUICClientHello, - sniff.STUNMessage, - sniff.UTP, - sniff.UDPTracker, - sniff.DTLSRecord, - } - } err = sniff.PeekPacket( ctx, metadata, sniffBuffer.Bytes(), diff --git a/transport/v2rayhttp/server.go b/transport/v2rayhttp/server.go index dd2bc9a2..c74e59aa 100644 --- a/transport/v2rayhttp/server.go +++ b/transport/v2rayhttp/server.go @@ -47,6 +47,7 @@ func NewServer(ctx context.Context, logger logger.ContextLogger, options option. server := &Server{ ctx: ctx, tlsConfig: tlsConfig, + logger: logger, handler: handler, h2Server: &http2.Server{ IdleTimeout: time.Duration(options.IdleTimeout), diff --git a/transport/v2raywebsocket/conn.go b/transport/v2raywebsocket/conn.go index f9099764..7f347dc9 100644 --- a/transport/v2raywebsocket/conn.go +++ b/transport/v2raywebsocket/conn.go @@ -3,6 +3,7 @@ package v2raywebsocket import ( "context" "encoding/base64" + "errors" "io" "net" "os" @@ -67,9 +68,10 @@ func (c *WebsocketConn) Read(b []byte) (n int, err error) { return } if !E.IsMulti(err, io.EOF, wsutil.ErrNoFrameAdvance) { + err = wrapWsError(err) return } - header, err = c.reader.NextFrame() + header, err = wrapWsError0(c.reader.NextFrame()) if err != nil { return } @@ -78,14 +80,14 @@ func (c *WebsocketConn) Read(b []byte) (n int, err error) { err = wsutil.ErrFrameTooLarge return } - err = c.controlHandler(header, c.reader) + err = wrapWsError(c.controlHandler(header, c.reader)) if err != nil { return } continue } if header.OpCode&ws.OpBinary == 0 { - err = c.reader.Discard() + err = wrapWsError(c.reader.Discard()) if err != nil { return } @@ -95,7 +97,7 @@ func (c *WebsocketConn) Read(b []byte) (n int, err error) { } func (c *WebsocketConn) Write(p []byte) (n int, err error) { - err = wsutil.WriteMessage(c.Conn, c.state, ws.OpBinary, p) + err = wrapWsError(wsutil.WriteMessage(c.Conn, c.state, ws.OpBinary, p)) if err != nil { return } @@ -146,7 +148,7 @@ func (c *EarlyWebsocketConn) Read(b []byte) (n int, err error) { return 0, c.err } } - return c.conn.Read(b) + return wrapWsError0(c.conn.Read(b)) } func (c *EarlyWebsocketConn) writeRequest(content []byte) error { @@ -191,7 +193,7 @@ func (c *EarlyWebsocketConn) writeRequest(content []byte) error { func (c *EarlyWebsocketConn) Write(b []byte) (n int, err error) { if c.conn != nil { - return c.conn.Write(b) + return wrapWsError0(c.conn.Write(b)) } c.access.Lock() defer c.access.Unlock() @@ -199,7 +201,7 @@ func (c *EarlyWebsocketConn) Write(b []byte) (n int, err error) { return 0, c.err } if c.conn != nil { - return c.conn.Write(b) + return wrapWsError0(c.conn.Write(b)) } err = c.writeRequest(b) c.err = err @@ -212,12 +214,12 @@ func (c *EarlyWebsocketConn) Write(b []byte) (n int, err error) { func (c *EarlyWebsocketConn) WriteBuffer(buffer *buf.Buffer) error { if c.conn != nil { - return c.conn.WriteBuffer(buffer) + return wrapWsError(c.conn.WriteBuffer(buffer)) } c.access.Lock() defer c.access.Unlock() if c.conn != nil { - return c.conn.WriteBuffer(buffer) + return wrapWsError(c.conn.WriteBuffer(buffer)) } if c.err != nil { return c.err @@ -272,3 +274,23 @@ func (c *EarlyWebsocketConn) Upstream() any { func (c *EarlyWebsocketConn) LazyHeadroom() bool { return c.conn == nil } + +func wrapWsError(err error) error { + if err == nil { + return nil + } + var closedErr wsutil.ClosedError + if errors.As(err, &closedErr) { + if closedErr.Code == ws.StatusNormalClosure { + err = io.EOF + } + } + return err +} + +func wrapWsError0[T any](value T, err error) (T, error) { + if err == nil { + return value, nil + } + return value, wrapWsError(err) +} diff --git a/transport/v2raywebsocket/deadline.go b/transport/v2raywebsocket/deadline.go deleted file mode 100644 index 195565aa..00000000 --- a/transport/v2raywebsocket/deadline.go +++ /dev/null @@ -1,22 +0,0 @@ -package v2raywebsocket - -import ( - "net" - "time" -) - -type deadConn struct { - net.Conn -} - -func (c *deadConn) SetDeadline(t time.Time) error { - return nil -} - -func (c *deadConn) SetReadDeadline(t time.Time) error { - return nil -} - -func (c *deadConn) SetWriteDeadline(t time.Time) error { - return nil -} diff --git a/transport/v2raywebsocket/writer.go b/transport/v2raywebsocket/writer.go index 5bd0d0a1..c08a654f 100644 --- a/transport/v2raywebsocket/writer.go +++ b/transport/v2raywebsocket/writer.go @@ -66,7 +66,7 @@ func (w *Writer) WriteBuffer(buffer *buf.Buffer) error { ws.Cipher(data, *(*[4]byte)(header[1+payloadBitLength:]), 0) } - return w.writer.WriteBuffer(buffer) + return wrapWsError(w.writer.WriteBuffer(buffer)) } func (w *Writer) FrontHeadroom() int {