Compare commits

...

12 Commits

Author SHA1 Message Date
世界
8e2baf40f1
Bump version 2025-03-11 20:18:34 +08:00
世界
c24c40dfee
platform: Fix android start 2025-03-11 20:18:34 +08:00
世界
32e52ce1ed
Fix udp nat for fakeip 2025-03-11 19:09:27 +08:00
世界
ed46438359
release: Use nightly goreleaser to fix rpm bug 2025-03-11 13:29:08 +08:00
世界
0b5490d5a3
Fix resolve domain for WireGuard 2025-03-11 12:02:25 +08:00
Tal Rasha
2d73ef511d
Fix grpclite memory leak
Co-authored-by: talrasha007 <talrasha007@gmail.om>
2025-03-10 14:48:02 +08:00
Mahdi
63e6c85f6f
Fix shadowsocks UoT 2025-03-10 14:47:59 +08:00
世界
8946a6d2d0
release: Use latest goreleaser 2025-03-09 15:27:04 +08:00
世界
d3132645fb
documentation: Fix description of the UoT protocol 2025-03-09 15:26:42 +08:00
世界
373f158fe0
Fix download external ui with query params 2025-03-09 15:26:36 +08:00
世界
ce36835fab
Fix override destination 2025-03-09 15:25:06 +08:00
世界
619fa671d7
Skip binding to the default interface as it will fail on some Android devices 2025-02-26 07:25:35 +08:00
17 changed files with 91 additions and 44 deletions

View File

@ -159,7 +159,7 @@ jobs:
uses: goreleaser/goreleaser-action@v6 uses: goreleaser/goreleaser-action@v6
with: with:
distribution: goreleaser-pro distribution: goreleaser-pro
version: 2.5.1 version: nightly
install-only: true install-only: true
- name: Extract signing key - name: Extract signing key
run: |- run: |-

View File

@ -95,10 +95,12 @@ archives:
builds: builds:
- main - main
- android - android
format: tar.gz formats:
- tar.gz
format_overrides: format_overrides:
- goos: windows - goos: windows
format: zip formats:
- zip
wrap_in_directory: true wrap_in_directory: true
files: files:
- LICENSE - LICENSE

13
box.go
View File

@ -165,7 +165,15 @@ func New(options Options) (*Box, error) {
} else { } else {
tag = F.ToString(i) tag = F.ToString(i)
} }
err = endpointManager.Create(ctx, endpointCtx := ctx
if tag != "" {
// TODO: remove this
endpointCtx = adapter.WithContext(endpointCtx, &adapter.InboundContext{
Outbound: tag,
})
}
err = endpointManager.Create(
endpointCtx,
router, router,
logFactory.NewLogger(F.ToString("endpoint/", endpointOptions.Type, "[", tag, "]")), logFactory.NewLogger(F.ToString("endpoint/", endpointOptions.Type, "[", tag, "]")),
tag, tag,
@ -183,7 +191,8 @@ func New(options Options) (*Box, error) {
} else { } else {
tag = F.ToString(i) tag = F.ToString(i)
} }
err = inboundManager.Create(ctx, err = inboundManager.Create(
ctx,
router, router,
logFactory.NewLogger(F.ToString("inbound/", inboundOptions.Type, "[", tag, "]")), logFactory.NewLogger(F.ToString("inbound/", inboundOptions.Type, "[", tag, "]")),
tag, tag,

@ -1 +1 @@
Subproject commit 0576fd75a67e56048c29d00ef539b4f8f05aec2a Subproject commit aefe3c029096ddac5189a20a8203a68858152f0a

@ -1 +1 @@
Subproject commit a828bb3a93b57d0c1b13d74246f0675c5244466d Subproject commit ae5818ee5a24af965dc91f80bffa16e1e6c109c1

View File

@ -18,6 +18,7 @@ func (d *DefaultDialer) dialParallelInterface(ctx context.Context, dialer net.Di
if len(primaryInterfaces)+len(fallbackInterfaces) == 0 { if len(primaryInterfaces)+len(fallbackInterfaces) == 0 {
return nil, false, E.New("no available network interface") return nil, false, E.New("no available network interface")
} }
defaultInterface := d.networkManager.InterfaceMonitor().DefaultInterface()
if fallbackDelay == 0 { if fallbackDelay == 0 {
fallbackDelay = N.DefaultFallbackDelay fallbackDelay = N.DefaultFallbackDelay
} }
@ -31,7 +32,9 @@ func (d *DefaultDialer) dialParallelInterface(ctx context.Context, dialer net.Di
results := make(chan dialResult) // unbuffered results := make(chan dialResult) // unbuffered
startRacer := func(ctx context.Context, primary bool, iif adapter.NetworkInterface) { startRacer := func(ctx context.Context, primary bool, iif adapter.NetworkInterface) {
perNetDialer := dialer perNetDialer := dialer
perNetDialer.Control = control.Append(perNetDialer.Control, control.BindToInterface(nil, iif.Name, iif.Index)) if defaultInterface == nil || iif.Index != defaultInterface.Index {
perNetDialer.Control = control.Append(perNetDialer.Control, control.BindToInterface(nil, iif.Name, iif.Index))
}
conn, err := perNetDialer.DialContext(ctx, network, addr) conn, err := perNetDialer.DialContext(ctx, network, addr)
if err != nil { if err != nil {
select { select {
@ -89,6 +92,7 @@ func (d *DefaultDialer) dialParallelInterfaceFastFallback(ctx context.Context, d
if len(primaryInterfaces)+len(fallbackInterfaces) == 0 { if len(primaryInterfaces)+len(fallbackInterfaces) == 0 {
return nil, false, E.New("no available network interface") return nil, false, E.New("no available network interface")
} }
defaultInterface := d.networkManager.InterfaceMonitor().DefaultInterface()
if fallbackDelay == 0 { if fallbackDelay == 0 {
fallbackDelay = N.DefaultFallbackDelay fallbackDelay = N.DefaultFallbackDelay
} }
@ -103,7 +107,9 @@ func (d *DefaultDialer) dialParallelInterfaceFastFallback(ctx context.Context, d
results := make(chan dialResult) // unbuffered results := make(chan dialResult) // unbuffered
startRacer := func(ctx context.Context, primary bool, iif adapter.NetworkInterface) { startRacer := func(ctx context.Context, primary bool, iif adapter.NetworkInterface) {
perNetDialer := dialer perNetDialer := dialer
perNetDialer.Control = control.Append(perNetDialer.Control, control.BindToInterface(nil, iif.Name, iif.Index)) if defaultInterface == nil || iif.Index != defaultInterface.Index {
perNetDialer.Control = control.Append(perNetDialer.Control, control.BindToInterface(nil, iif.Name, iif.Index))
}
conn, err := perNetDialer.DialContext(ctx, network, addr) conn, err := perNetDialer.DialContext(ctx, network, addr)
if err != nil { if err != nil {
select { select {
@ -149,10 +155,13 @@ func (d *DefaultDialer) listenSerialInterfacePacket(ctx context.Context, listene
if len(primaryInterfaces)+len(fallbackInterfaces) == 0 { if len(primaryInterfaces)+len(fallbackInterfaces) == 0 {
return nil, E.New("no available network interface") return nil, E.New("no available network interface")
} }
defaultInterface := d.networkManager.InterfaceMonitor().DefaultInterface()
var errors []error var errors []error
for _, primaryInterface := range primaryInterfaces { for _, primaryInterface := range primaryInterfaces {
perNetListener := listener perNetListener := listener
perNetListener.Control = control.Append(perNetListener.Control, control.BindToInterface(nil, primaryInterface.Name, primaryInterface.Index)) if defaultInterface == nil || primaryInterface.Index != defaultInterface.Index {
perNetListener.Control = control.Append(perNetListener.Control, control.BindToInterface(nil, primaryInterface.Name, primaryInterface.Index))
}
conn, err := perNetListener.ListenPacket(ctx, network, addr) conn, err := perNetListener.ListenPacket(ctx, network, addr)
if err == nil { if err == nil {
return conn, nil return conn, nil
@ -161,7 +170,9 @@ func (d *DefaultDialer) listenSerialInterfacePacket(ctx context.Context, listene
} }
for _, fallbackInterface := range fallbackInterfaces { for _, fallbackInterface := range fallbackInterfaces {
perNetListener := listener perNetListener := listener
perNetListener.Control = control.Append(perNetListener.Control, control.BindToInterface(nil, fallbackInterface.Name, fallbackInterface.Index)) if defaultInterface == nil || fallbackInterface.Index != defaultInterface.Index {
perNetListener.Control = control.Append(perNetListener.Control, control.BindToInterface(nil, fallbackInterface.Name, fallbackInterface.Index))
}
conn, err := perNetListener.ListenPacket(ctx, network, addr) conn, err := perNetListener.ListenPacket(ctx, network, addr)
if err == nil { if err == nil {
return conn, nil return conn, nil

View File

@ -2,6 +2,12 @@
icon: material/alert-decagram icon: material/alert-decagram
--- ---
### 1.11.5
* 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.4 ### 1.11.4
* Fixes and improvements * Fixes and improvements

View File

@ -7,6 +7,10 @@ icon: material/apple
SFI/SFM/SFT allows users to manage and run local or remote sing-box configuration files, and provides SFI/SFM/SFT allows users to manage and run local or remote sing-box configuration files, and provides
platform-specific function implementation, such as TUN transparent proxy implementation. platform-specific function implementation, such as TUN transparent proxy implementation.
!!! failure ""
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).
## :material-graph: Requirements ## :material-graph: Requirements
* iOS 15.0+ / macOS 13.0+ / Apple tvOS 17.0+ * iOS 15.0+ / macOS 13.0+ / Apple tvOS 17.0+

View File

@ -31,12 +31,11 @@ The protocol version, `1` or `2`.
### Application support ### Application support
| Project | UoT v1 | UoT v2 | | Project | UoT v1 | UoT v2 |
|--------------|----------------------|-------------------------------------------------------------------------------------------------------------------| |--------------|----------------------|----------------------|
| sing-box | v0 (2022/08/11) | v1.2-beta9 | | sing-box | v0 (2022/08/11) | v1.2-beta9 |
| Xray-core | v1.5.7 (2022/06/05) | [f57ec13](https://github.com/XTLS/Xray-core/commit/f57ec1388084df041a2289bacab14e446bf1b357) (Not released) | | Clash.Meta | v1.12.0 (2022/07/02) | v1.14.3 (2023/03/31) |
| Clash.Meta | v1.12.0 (2022/07/02) | [8cb67b6](https://github.com/MetaCubeX/Clash.Meta/commit/8cb67b6480649edfa45dcc9ac89ce0789651e8b3) (Not released) | | Shadowrocket | v2.2.12 (2022/08/13) | / |
| Shadowrocket | v2.2.12 (2022/08/13) | / |
### Protocol details ### Protocol details
@ -50,7 +49,13 @@ The client requests the magic address to the upper layer proxy protocol to indic
|------|----------|-------|--------|----------| |------|----------|-------|--------|----------|
| u8 | variable | u16be | u16be | variable | | u8 | variable | u16be | u16be | variable |
**ATYP / address / port**: Uses the SOCKS address format. **ATYP / address / port**: Uses the SOCKS address format, but with different address types:
| ATYP | Address type |
|--------|--------------|
| `0x00` | IPv4 Address |
| `0x01` | IPv6 Address |
| `0x02` | Domain Name |
#### Protocol version 2 #### Protocol version 2

View File

@ -71,15 +71,15 @@ func (s *Server) downloadExternalUI() error {
if response.StatusCode != http.StatusOK { if response.StatusCode != http.StatusOK {
return E.New("download external ui failed: ", response.Status) return E.New("download external ui failed: ", response.Status)
} }
err = s.downloadZIP(filepath.Base(downloadURL), response.Body, s.externalUI) err = s.downloadZIP(response.Body, s.externalUI)
if err != nil { if err != nil {
removeAllInDirectory(s.externalUI) removeAllInDirectory(s.externalUI)
} }
return err return err
} }
func (s *Server) downloadZIP(name string, body io.Reader, output string) error { func (s *Server) downloadZIP(body io.Reader, output string) error {
tempFile, err := filemanager.CreateTemp(s.ctx, name) tempFile, err := filemanager.CreateTemp(s.ctx, "external-ui.zip")
if err != nil { if err != nil {
return err return err
} }

View File

@ -56,7 +56,12 @@ func (m *platformDefaultInterfaceMonitor) UnregisterCallback(element *list.Eleme
func (m *platformDefaultInterfaceMonitor) UpdateDefaultInterface(interfaceName string, interfaceIndex32 int32, isExpensive bool, isConstrained bool) { func (m *platformDefaultInterfaceMonitor) UpdateDefaultInterface(interfaceName string, interfaceIndex32 int32, isExpensive bool, isConstrained bool) {
if sFixAndroidStack { if sFixAndroidStack {
go m.updateDefaultInterface(interfaceName, interfaceIndex32, isExpensive, isConstrained) done := make(chan struct{})
go func() {
m.updateDefaultInterface(interfaceName, interfaceIndex32, isExpensive, isConstrained)
close(done)
}()
<-done
} else { } else {
m.updateDefaultInterface(interfaceName, interfaceIndex32, isExpensive, isConstrained) m.updateDefaultInterface(interfaceName, interfaceIndex32, isExpensive, isConstrained)
} }

2
go.mod
View File

@ -26,7 +26,7 @@ require (
github.com/sagernet/gvisor v0.0.0-20241123041152-536d05261cff github.com/sagernet/gvisor v0.0.0-20241123041152-536d05261cff
github.com/sagernet/quic-go v0.49.0-beta.1 github.com/sagernet/quic-go v0.49.0-beta.1
github.com/sagernet/reality v0.0.0-20230406110435-ee17307e7691 github.com/sagernet/reality v0.0.0-20230406110435-ee17307e7691
github.com/sagernet/sing v0.6.1 github.com/sagernet/sing v0.6.3
github.com/sagernet/sing-dns v0.4.0 github.com/sagernet/sing-dns v0.4.0
github.com/sagernet/sing-mux v0.3.1 github.com/sagernet/sing-mux v0.3.1
github.com/sagernet/sing-quic v0.4.0 github.com/sagernet/sing-quic v0.4.0

4
go.sum
View File

@ -119,8 +119,8 @@ github.com/sagernet/quic-go v0.49.0-beta.1/go.mod h1:uesWD1Ihrldq1M3XtjuEvIUqi8W
github.com/sagernet/reality v0.0.0-20230406110435-ee17307e7691 h1:5Th31OC6yj8byLGkEnIYp6grlXfo1QYUfiYFGjewIdc= 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/reality v0.0.0-20230406110435-ee17307e7691/go.mod h1:B8lp4WkQ1PwNnrVMM6KyuFR20pU8jYBD+A4EhJovEXU=
github.com/sagernet/sing v0.2.18/go.mod h1:OL6k2F0vHmEzXz2KW19qQzu172FDgSbUSODylighuVo= github.com/sagernet/sing v0.2.18/go.mod h1:OL6k2F0vHmEzXz2KW19qQzu172FDgSbUSODylighuVo=
github.com/sagernet/sing v0.6.1 h1:mJ6e7Ir2wtCoGLbdnnXWBsNJu5YHtbXmv66inoE0zFA= github.com/sagernet/sing v0.6.3 h1:J1spMc6LMlqUvRjWjvNMAcbvACDneqxB9zxfLuS0UTE=
github.com/sagernet/sing v0.6.1/go.mod h1:ARkL0gM13/Iv5VCZmci/NuoOlePoIsW0m7BWfln/Hak= github.com/sagernet/sing v0.6.3/go.mod h1:ARkL0gM13/Iv5VCZmci/NuoOlePoIsW0m7BWfln/Hak=
github.com/sagernet/sing-dns v0.4.0 h1:+mNoOuR3nljjouCH+qMg4zHI1+R9T2ReblGFkZPEndc= github.com/sagernet/sing-dns v0.4.0 h1:+mNoOuR3nljjouCH+qMg4zHI1+R9T2ReblGFkZPEndc=
github.com/sagernet/sing-dns v0.4.0/go.mod h1:dweQs54ng2YGzoJfz+F9dGuDNdP5pJ3PLeggnK5VWc8= github.com/sagernet/sing-dns v0.4.0/go.mod h1:dweQs54ng2YGzoJfz+F9dGuDNdP5pJ3PLeggnK5VWc8=
github.com/sagernet/sing-mux v0.3.1 h1:kvCc8HyGAskDHDQ0yQvoTi/7J4cZPB/VJMsAM3MmdQI= github.com/sagernet/sing-mux v0.3.1 h1:kvCc8HyGAskDHDQ0yQvoTi/7J4cZPB/VJMsAM3MmdQI=

View File

@ -12,6 +12,7 @@ import (
"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/buf" "github.com/sagernet/sing/common/buf"
"github.com/sagernet/sing/common/bufio"
M "github.com/sagernet/sing/common/metadata" M "github.com/sagernet/sing/common/metadata"
N "github.com/sagernet/sing/common/network" N "github.com/sagernet/sing/common/network"
"github.com/sagernet/sing/common/udpnat2" "github.com/sagernet/sing/common/udpnat2"
@ -80,7 +81,7 @@ func (i *Inbound) Close() error {
} }
func (i *Inbound) NewPacketEx(buffer *buf.Buffer, source M.Socksaddr) { func (i *Inbound) NewPacketEx(buffer *buf.Buffer, source M.Socksaddr) {
i.udpNat.NewPacket([][]byte{buffer.Bytes()}, source, M.Socksaddr{}, nil) i.udpNat.NewPacket([][]byte{buffer.Bytes()}, source, i.listener.UDPAddr(), nil)
} }
func (i *Inbound) NewConnectionEx(ctx context.Context, conn net.Conn, metadata adapter.InboundContext, onClose N.CloseHandlerFunc) { func (i *Inbound) NewConnectionEx(ctx context.Context, conn net.Conn, metadata adapter.InboundContext, onClose N.CloseHandlerFunc) {
@ -104,7 +105,6 @@ func (i *Inbound) NewConnectionEx(ctx context.Context, conn net.Conn, metadata a
func (i *Inbound) NewPacketConnectionEx(ctx context.Context, conn N.PacketConn, source M.Socksaddr, destination M.Socksaddr, onClose N.CloseHandlerFunc) { func (i *Inbound) NewPacketConnectionEx(ctx context.Context, conn N.PacketConn, source M.Socksaddr, destination M.Socksaddr, onClose N.CloseHandlerFunc) {
i.logger.InfoContext(ctx, "inbound packet connection from ", source) i.logger.InfoContext(ctx, "inbound packet connection from ", source)
i.logger.InfoContext(ctx, "inbound packet connection to ", destination)
var metadata adapter.InboundContext var metadata adapter.InboundContext
metadata.Inbound = i.Tag() metadata.Inbound = i.Tag()
metadata.InboundType = i.Type() metadata.InboundType = i.Type()
@ -123,8 +123,11 @@ func (i *Inbound) NewPacketConnectionEx(ctx context.Context, conn N.PacketConn,
destination.Port = i.overrideDestination.Port destination.Port = i.overrideDestination.Port
default: default:
} }
i.logger.InfoContext(ctx, "inbound packet connection to ", destination)
metadata.Destination = destination metadata.Destination = destination
metadata.OriginDestination = i.listener.UDPAddr() if i.overrideOption != 0 {
conn = bufio.NewDestinationNATPacketConn(bufio.NewNetPacketConn(conn), i.listener.UDPAddr(), destination)
}
i.router.RoutePacketConnectionEx(ctx, conn, metadata, onClose) i.router.RoutePacketConnectionEx(ctx, conn, metadata, onClose)
} }

View File

@ -61,7 +61,7 @@ func newInbound(ctx context.Context, router adapter.Router, logger log.ContextLo
logger: logger, logger: logger,
} }
var err error var err error
inbound.router, err = mux.NewRouterWithOptions(router, logger, common.PtrValueOrDefault(options.Multiplex)) inbound.router, err = mux.NewRouterWithOptions(inbound.router, logger, common.PtrValueOrDefault(options.Multiplex))
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@ -149,22 +149,17 @@ func (m *ConnectionManager) NewPacketConnection(ctx context.Context, this N.Dial
} else { } else {
originDestination = metadata.Destination originDestination = metadata.Destination
} }
if metadata.Destination != M.SocksaddrFrom(destinationAddress, metadata.Destination.Port) { if natConn, loaded := common.Cast[bufio.NATPacketConn](conn); loaded {
natConn.UpdateDestination(destinationAddress)
} else if metadata.Destination != M.SocksaddrFrom(destinationAddress, metadata.Destination.Port) {
if metadata.UDPDisableDomainUnmapping { if metadata.UDPDisableDomainUnmapping {
remotePacketConn = bufio.NewUnidirectionalNATPacketConn(bufio.NewPacketConn(remotePacketConn), M.SocksaddrFrom(destinationAddress, metadata.Destination.Port), originDestination) remotePacketConn = bufio.NewUnidirectionalNATPacketConn(bufio.NewPacketConn(remotePacketConn), M.SocksaddrFrom(destinationAddress, metadata.Destination.Port), originDestination)
} else { } else {
remotePacketConn = bufio.NewNATPacketConn(bufio.NewPacketConn(remotePacketConn), M.SocksaddrFrom(destinationAddress, metadata.Destination.Port), originDestination) remotePacketConn = bufio.NewNATPacketConn(bufio.NewPacketConn(remotePacketConn), M.SocksaddrFrom(destinationAddress, metadata.Destination.Port), originDestination)
} }
} }
if natConn, loaded := common.Cast[bufio.NATPacketConn](conn); loaded {
natConn.UpdateDestination(destinationAddress)
}
} else if metadata.RouteOriginalDestination.IsValid() && metadata.RouteOriginalDestination != metadata.Destination { } else if metadata.RouteOriginalDestination.IsValid() && metadata.RouteOriginalDestination != metadata.Destination {
if metadata.UDPDisableDomainUnmapping { remotePacketConn = bufio.NewDestinationNATPacketConn(bufio.NewPacketConn(remotePacketConn), metadata.Destination, metadata.RouteOriginalDestination)
remotePacketConn = bufio.NewUnidirectionalNATPacketConn(bufio.NewPacketConn(remotePacketConn), metadata.Destination, metadata.RouteOriginalDestination)
} else {
remotePacketConn = bufio.NewNATPacketConn(bufio.NewPacketConn(remotePacketConn), metadata.Destination, metadata.RouteOriginalDestination)
}
} }
var udpTimeout time.Duration var udpTimeout time.Duration
if metadata.UDPTimeout > 0 { if metadata.UDPTimeout > 0 {
@ -279,13 +274,17 @@ func (m *ConnectionManager) connectionCopy(ctx context.Context, source io.Reader
func (m *ConnectionManager) packetConnectionCopy(ctx context.Context, source N.PacketReader, destination N.PacketWriter, direction bool, done *atomic.Bool, onClose N.CloseHandlerFunc) { func (m *ConnectionManager) packetConnectionCopy(ctx context.Context, source N.PacketReader, destination N.PacketWriter, direction bool, done *atomic.Bool, onClose N.CloseHandlerFunc) {
_, err := bufio.CopyPacket(destination, source) _, err := bufio.CopyPacket(destination, source)
if !direction { if !direction {
if E.IsClosedOrCanceled(err) { if err == nil {
m.logger.DebugContext(ctx, "packet upload finished")
} else if E.IsClosedOrCanceled(err) {
m.logger.TraceContext(ctx, "packet upload closed") m.logger.TraceContext(ctx, "packet upload closed")
} else { } else {
m.logger.DebugContext(ctx, "packet upload closed: ", err) m.logger.DebugContext(ctx, "packet upload closed: ", err)
} }
} else { } else {
if E.IsClosedOrCanceled(err) { if err == nil {
m.logger.DebugContext(ctx, "packet download finished")
} else if E.IsClosedOrCanceled(err) {
m.logger.TraceContext(ctx, "packet download closed") m.logger.TraceContext(ctx, "packet download closed")
} else { } else {
m.logger.DebugContext(ctx, "packet download closed: ", err) m.logger.DebugContext(ctx, "packet download closed: ", err)

View File

@ -21,6 +21,7 @@ import (
var _ net.Conn = (*GunConn)(nil) var _ net.Conn = (*GunConn)(nil)
type GunConn struct { type GunConn struct {
rawReader io.Reader
reader *std_bufio.Reader reader *std_bufio.Reader
writer io.Writer writer io.Writer
flusher http.Flusher flusher http.Flusher
@ -31,9 +32,10 @@ type GunConn struct {
func newGunConn(reader io.Reader, writer io.Writer, flusher http.Flusher) *GunConn { func newGunConn(reader io.Reader, writer io.Writer, flusher http.Flusher) *GunConn {
return &GunConn{ return &GunConn{
reader: std_bufio.NewReader(reader), rawReader: reader,
writer: writer, reader: std_bufio.NewReader(reader),
flusher: flusher, writer: writer,
flusher: flusher,
} }
} }
@ -46,6 +48,7 @@ func newLateGunConn(writer io.Writer) *GunConn {
func (c *GunConn) setup(reader io.Reader, err error) { func (c *GunConn) setup(reader io.Reader, err error) {
if reader != nil { if reader != nil {
c.rawReader = reader
c.reader = std_bufio.NewReader(reader) c.reader = std_bufio.NewReader(reader)
} }
c.err = err c.err = err
@ -138,7 +141,7 @@ func (c *GunConn) FrontHeadroom() int {
} }
func (c *GunConn) Close() error { func (c *GunConn) Close() error {
return common.Close(c.reader, c.writer) return common.Close(c.rawReader, c.writer)
} }
func (c *GunConn) LocalAddr() net.Addr { func (c *GunConn) LocalAddr() net.Addr {