diff --git a/adapter/outbound/shadowsocks.go b/adapter/outbound/shadowsocks.go index 3b183b7c..98932f0c 100644 --- a/adapter/outbound/shadowsocks.go +++ b/adapter/outbound/shadowsocks.go @@ -20,6 +20,7 @@ import ( restlsC "github.com/3andne/restls-client-go" shadowsocks "github.com/metacubex/sing-shadowsocks2" + "github.com/sagernet/sing/common/bufio" M "github.com/sagernet/sing/common/metadata" "github.com/sagernet/sing/common/uot" ) @@ -187,7 +188,7 @@ func (ss *ShadowSocks) ListenPacketWithDialer(ctx context.Context, dialer C.Dial if err != nil { return nil, err } - pc = ss.method.DialPacketConn(N.NewBindPacketConn(pc, addr)) + pc = ss.method.DialPacketConn(bufio.NewBindPacketConn(pc, addr)) return newPacketConn(pc, ss), nil } diff --git a/common/net/deadline/conn.go b/common/net/deadline/conn.go new file mode 100644 index 00000000..e8446ce2 --- /dev/null +++ b/common/net/deadline/conn.go @@ -0,0 +1,149 @@ +package deadline + +import ( + "net" + "os" + "time" + + "github.com/metacubex/mihomo/common/atomic" + + "github.com/sagernet/sing/common/buf" + "github.com/sagernet/sing/common/bufio" + "github.com/sagernet/sing/common/network" +) + +type connReadResult struct { + buffer []byte + err error +} + +type Conn struct { + network.ExtendedConn + deadline atomic.TypedValue[time.Time] + pipeDeadline pipeDeadline + disablePipe atomic.Bool + inRead atomic.Bool + resultCh chan *connReadResult +} + +func NewConn(conn net.Conn) *Conn { + c := &Conn{ + ExtendedConn: bufio.NewExtendedConn(conn), + pipeDeadline: makePipeDeadline(), + resultCh: make(chan *connReadResult, 1), + } + c.resultCh <- nil + return c +} + +func (c *Conn) Read(p []byte) (n int, err error) { + select { + case result := <-c.resultCh: + if result != nil { + n = copy(p, result.buffer) + err = result.err + if n >= len(result.buffer) { + c.resultCh <- nil // finish cache read + } else { + result.buffer = result.buffer[n:] + c.resultCh <- result // push back for next call + } + return + } else { + c.resultCh <- nil + break + } + case <-c.pipeDeadline.wait(): + return 0, os.ErrDeadlineExceeded + } + + if c.disablePipe.Load() { + return c.ExtendedConn.Read(p) + } else if c.deadline.Load().IsZero() { + c.inRead.Store(true) + defer c.inRead.Store(false) + return c.ExtendedConn.Read(p) + } + + <-c.resultCh + go c.pipeRead(len(p)) + + return c.Read(p) +} + +func (c *Conn) pipeRead(size int) { + buffer := make([]byte, size) + n, err := c.ExtendedConn.Read(buffer) + buffer = buffer[:n] + c.resultCh <- &connReadResult{ + buffer: buffer, + err: err, + } +} + +func (c *Conn) ReadBuffer(buffer *buf.Buffer) (err error) { + select { + case result := <-c.resultCh: + if result != nil { + n, _ := buffer.Write(result.buffer) + err = result.err + + if n >= len(result.buffer) { + c.resultCh <- nil // finish cache read + } else { + result.buffer = result.buffer[n:] + c.resultCh <- result // push back for next call + } + return + } else { + c.resultCh <- nil + break + } + case <-c.pipeDeadline.wait(): + return os.ErrDeadlineExceeded + } + + if c.disablePipe.Load() { + return c.ExtendedConn.ReadBuffer(buffer) + } else if c.deadline.Load().IsZero() { + c.inRead.Store(true) + defer c.inRead.Store(false) + return c.ExtendedConn.ReadBuffer(buffer) + } + + <-c.resultCh + go c.pipeRead(buffer.FreeLen()) + + return c.ReadBuffer(buffer) +} + +func (c *Conn) SetReadDeadline(t time.Time) error { + if c.disablePipe.Load() { + return c.ExtendedConn.SetReadDeadline(t) + } else if c.inRead.Load() { + c.disablePipe.Store(true) + return c.ExtendedConn.SetReadDeadline(t) + } + c.deadline.Store(t) + c.pipeDeadline.set(t) + return nil +} + +func (c *Conn) ReaderReplaceable() bool { + select { + case result := <-c.resultCh: + c.resultCh <- result + if result != nil { + return false // cache reading + } else { + break + } + default: + return false // pipe reading + } + return c.disablePipe.Load() || c.deadline.Load().IsZero() +} + +func (c *Conn) Upstream() any { + return c.ExtendedConn +} diff --git a/common/net/deadline/packet_sing.go b/common/net/deadline/packet_sing.go index 65db1b8f..d54748b0 100644 --- a/common/net/deadline/packet_sing.go +++ b/common/net/deadline/packet_sing.go @@ -5,6 +5,7 @@ import ( "runtime" "github.com/metacubex/mihomo/common/net/packet" + "github.com/sagernet/sing/common/buf" "github.com/sagernet/sing/common/bufio" M "github.com/sagernet/sing/common/metadata" @@ -121,17 +122,18 @@ type singPacketReadWaiter struct { type singWaitReadResult singReadResult -func (c *singPacketReadWaiter) InitializeReadWaiter(newBuffer func() *buf.Buffer) { - c.packetReadWaiter.InitializeReadWaiter(newBuffer) +func (c *singPacketReadWaiter) InitializeReadWaiter(options N.ReadWaitOptions) (needCopy bool) { + return c.packetReadWaiter.InitializeReadWaiter(options) } -func (c *singPacketReadWaiter) WaitReadPacket() (destination M.Socksaddr, err error) { +func (c *singPacketReadWaiter) WaitReadPacket() (buffer *buf.Buffer, destination M.Socksaddr, err error) { FOR: for { select { case result := <-c.netPacketConn.resultCh: if result != nil { if result, ok := result.(*singWaitReadResult); ok { + buffer = result.buffer destination = result.destination err = result.err c.netPacketConn.resultCh <- nil // finish cache read @@ -145,7 +147,7 @@ FOR: break FOR } case <-c.netPacketConn.pipeDeadline.wait(): - return M.Socksaddr{}, os.ErrDeadlineExceeded + return nil, M.Socksaddr{}, os.ErrDeadlineExceeded } } @@ -154,8 +156,7 @@ FOR: } else if c.netPacketConn.deadline.Load().IsZero() { c.netPacketConn.inRead.Store(true) defer c.netPacketConn.inRead.Store(false) - destination, err = c.packetReadWaiter.WaitReadPacket() - return + return c.packetReadWaiter.WaitReadPacket() } <-c.netPacketConn.resultCh @@ -165,8 +166,9 @@ FOR: } func (c *singPacketReadWaiter) pipeWaitReadPacket() { - destination, err := c.packetReadWaiter.WaitReadPacket() + buffer, destination, err := c.packetReadWaiter.WaitReadPacket() result := &singWaitReadResult{} + result.buffer = buffer result.destination = destination result.err = err c.netPacketConn.resultCh <- result diff --git a/common/net/packet/packet_sing.go b/common/net/packet/packet_sing.go index cfcf5ed0..6e25eb4d 100644 --- a/common/net/packet/packet_sing.go +++ b/common/net/packet/packet_sing.go @@ -24,16 +24,16 @@ type enhanceSingPacketConn struct { func (c *enhanceSingPacketConn) WaitReadFrom() (data []byte, put func(), addr net.Addr, err error) { var buff *buf.Buffer var dest M.Socksaddr - newBuffer := func() *buf.Buffer { - buff = buf.NewPacket() // do not use stack buffer - return buff - } + rwOptions := N.ReadWaitOptions{} if c.packetReadWaiter != nil { - c.packetReadWaiter.InitializeReadWaiter(newBuffer) - defer c.packetReadWaiter.InitializeReadWaiter(nil) - dest, err = c.packetReadWaiter.WaitReadPacket() + c.packetReadWaiter.InitializeReadWaiter(rwOptions) + buff, dest, err = c.packetReadWaiter.WaitReadPacket() } else { - dest, err = c.SingPacketConn.ReadPacket(newBuffer()) + buff = rwOptions.NewPacketBuffer() + dest, err = c.SingPacketConn.ReadPacket(buff) + if buff != nil { + rwOptions.PostReturn(buff) + } } if dest.IsFqdn() { addr = dest @@ -41,9 +41,7 @@ func (c *enhanceSingPacketConn) WaitReadFrom() (data []byte, put func(), addr ne addr = dest.UDPAddr() } if err != nil { - if buff != nil { - buff.Release() - } + buff.Release() return } if buff == nil { diff --git a/common/net/sing.go b/common/net/sing.go index c92008ba..f8698620 100644 --- a/common/net/sing.go +++ b/common/net/sing.go @@ -5,9 +5,10 @@ import ( "net" "runtime" + "github.com/metacubex/mihomo/common/net/deadline" + "github.com/sagernet/sing/common" "github.com/sagernet/sing/common/bufio" - "github.com/sagernet/sing/common/bufio/deadline" "github.com/sagernet/sing/common/network" ) @@ -19,8 +20,10 @@ type ExtendedConn = network.ExtendedConn type ExtendedWriter = network.ExtendedWriter type ExtendedReader = network.ExtendedReader +var WriteBuffer = bufio.WriteBuffer + func NewDeadlineConn(conn net.Conn) ExtendedConn { - return deadline.NewFallbackConn(conn) + return deadline.NewConn(conn) } func NeedHandshake(conn any) bool { diff --git a/go.mod b/go.mod index 95bf96fa..a3ca754f 100644 --- a/go.mod +++ b/go.mod @@ -21,12 +21,12 @@ require ( github.com/mdlayher/netlink v1.7.2 github.com/metacubex/gopacket v1.1.20-0.20230608035415-7e2f98a3e759 github.com/metacubex/quic-go v0.40.1-0.20231130135418-0c1b47cf9394 - github.com/metacubex/sing-quic v0.0.0-20231130141855-0022295e524b + github.com/metacubex/sing-quic v0.0.0-20231207122758-cc17b154daa8 github.com/metacubex/sing-shadowsocks v0.2.5 - github.com/metacubex/sing-shadowsocks2 v0.1.4 - github.com/metacubex/sing-tun v0.1.15-0.20231103033938-170591e8d5bd - github.com/metacubex/sing-vmess v0.1.9-0.20230921005247-a0488d7dac74 - github.com/metacubex/sing-wireguard v0.0.0-20231001110902-321836559170 + github.com/metacubex/sing-shadowsocks2 v0.1.5-0.20231207115048-3abf19378f0d + github.com/metacubex/sing-tun v0.1.15-0.20231207115657-1aa1d8cadd9a + github.com/metacubex/sing-vmess v0.1.9-0.20231207122118-72303677451f + github.com/metacubex/sing-wireguard v0.0.0-20231207123053-1367f0b8f173 github.com/miekg/dns v1.1.57 github.com/mroth/weightedrand/v2 v2.1.0 github.com/openacid/low v0.1.21 @@ -34,8 +34,8 @@ require ( github.com/puzpuzpuz/xsync/v3 v3.0.2 github.com/sagernet/bbolt v0.0.0-20231014093535-ea5cb2fe9f0a github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97 - github.com/sagernet/sing v0.2.18-0.20231108041402-4fbbd193203c - github.com/sagernet/sing-mux v0.1.5-0.20231109075101-6b086ed6bb07 + github.com/sagernet/sing v0.2.19-0.20231207034108-445cd4f41e3f + github.com/sagernet/sing-mux v0.1.6-0.20231207143704-9f6c20fb5266 github.com/sagernet/sing-shadowtls v0.1.4 github.com/sagernet/tfo-go v0.0.0-20230816093905-5a5c285d44a6 github.com/sagernet/utls v0.0.0-20230309024959-6732c2ab36f2 @@ -49,7 +49,7 @@ require ( go.uber.org/automaxprocs v1.5.3 golang.org/x/crypto v0.16.0 golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa - golang.org/x/net v0.18.0 + golang.org/x/net v0.19.0 golang.org/x/sync v0.5.0 golang.org/x/sys v0.15.0 google.golang.org/protobuf v1.31.0 @@ -105,11 +105,11 @@ require ( github.com/yusufpapurcu/wmi v1.2.3 // indirect gitlab.com/yawning/bsaes.git v0.0.0-20190805113838-0a714cd429ec // indirect go.uber.org/mock v0.3.0 // indirect - go4.org/netipx v0.0.0-20230824141953-6213f710f925 // indirect + go4.org/netipx v0.0.0-20231129151722-fdeea329fbba // indirect golang.org/x/mod v0.14.0 // indirect golang.org/x/text v0.14.0 // indirect - golang.org/x/time v0.3.0 // indirect + golang.org/x/time v0.4.0 // indirect golang.org/x/tools v0.15.0 // indirect ) -replace github.com/sagernet/sing => github.com/metacubex/sing v0.0.0-20231118023733-957d84f17d2c +replace github.com/sagernet/sing => github.com/metacubex/sing v0.0.0-20231207144554-52b6f9095d02 diff --git a/go.sum b/go.sum index caab0d23..e63025bf 100644 --- a/go.sum +++ b/go.sum @@ -107,20 +107,20 @@ github.com/metacubex/gvisor v0.0.0-20231206145044-b6960a648d8b h1:xJHepHYyQ7NOpU github.com/metacubex/gvisor v0.0.0-20231206145044-b6960a648d8b/go.mod h1:rhBU9tD5ktoGPBtXUquhWuGJ4u+8ZZzBMi2cAdv9q8Y= github.com/metacubex/quic-go v0.40.1-0.20231130135418-0c1b47cf9394 h1:dIT+KB2hknBCrwVAXPeY9tpzzkOZP5m40yqUteRT6/Y= github.com/metacubex/quic-go v0.40.1-0.20231130135418-0c1b47cf9394/go.mod h1:F/t8VnA47xoia8ABlNA4InkZjssvFJ5p6E6jKdbkgAs= -github.com/metacubex/sing v0.0.0-20231118023733-957d84f17d2c h1:SZwaf42NVCIDaHw5X2HOnNcEiK9ao6yO+N4zYyKfXe8= -github.com/metacubex/sing v0.0.0-20231118023733-957d84f17d2c/go.mod h1:OL6k2F0vHmEzXz2KW19qQzu172FDgSbUSODylighuVo= -github.com/metacubex/sing-quic v0.0.0-20231130141855-0022295e524b h1:7XXoEePvxfkQN9b2wB8UXU3uzb9uL8syEFF7A9VAKKQ= -github.com/metacubex/sing-quic v0.0.0-20231130141855-0022295e524b/go.mod h1:Gu5/zqZDd5G1AUtoV2yjAPWOEy7zwbU2DBUjdxJh0Kw= +github.com/metacubex/sing v0.0.0-20231207144554-52b6f9095d02 h1:gB2vNdDTaOfko9z9WJXQkNn+rbdSEMTM7s61V4TaKhI= +github.com/metacubex/sing v0.0.0-20231207144554-52b6f9095d02/go.mod h1:Ce5LNojQOgOiWhiD8pPD6E9H7e2KgtOe3Zxx4Ou5u80= +github.com/metacubex/sing-quic v0.0.0-20231207122758-cc17b154daa8 h1:gmZb7M2Z4y6BQSWljJORGVGZlKaYWEpoIJlVMg9naEY= +github.com/metacubex/sing-quic v0.0.0-20231207122758-cc17b154daa8/go.mod h1:E1e1Uu6YaJddD+c0DtJlSOkfMI0NLdOVhM60KAlcssY= github.com/metacubex/sing-shadowsocks v0.2.5 h1:O2RRSHlKGEpAVG/OHJQxyHqDy8uvvdCW/oW2TDBOIhc= github.com/metacubex/sing-shadowsocks v0.2.5/go.mod h1:Xz2uW9BEYGEoA8B4XEpoxt7ERHClFCwsMAvWaruoyMo= -github.com/metacubex/sing-shadowsocks2 v0.1.4 h1:OOCf8lgsVcpTOJUeaFAMzyKVebaQOBnKirDdUdBoKIE= -github.com/metacubex/sing-shadowsocks2 v0.1.4/go.mod h1:Qz028sLfdY3qxGRm9FDI+IM2Ae3ty2wR7HIzD/56h/k= -github.com/metacubex/sing-tun v0.1.15-0.20231103033938-170591e8d5bd h1:k0+92eARqyTAovGhg2AxdsMWHjUsdiGCnR5NuXF3CQY= -github.com/metacubex/sing-tun v0.1.15-0.20231103033938-170591e8d5bd/go.mod h1:Q7zmpJ+qOvMMXyUoYlxGQuWkqALUpXzFSSqO+KLPyzA= -github.com/metacubex/sing-vmess v0.1.9-0.20230921005247-a0488d7dac74 h1:FtupiyFkaVjFvRa7B/uDtRWg5BNsoyPC9MTev3sDasY= -github.com/metacubex/sing-vmess v0.1.9-0.20230921005247-a0488d7dac74/go.mod h1:8EWBZpc+qNvf5gmvjAtMHK1/DpcWqzfcBL842K00BsM= -github.com/metacubex/sing-wireguard v0.0.0-20231001110902-321836559170 h1:DBGA0hmrP4pVIwLiXUONdphjcppED+plmVaKf1oqkwk= -github.com/metacubex/sing-wireguard v0.0.0-20231001110902-321836559170/go.mod h1:/VbJfbdLnANE+SKXyMk/96sTRrD4GdFLh5mkegqqFcY= +github.com/metacubex/sing-shadowsocks2 v0.1.5-0.20231207115048-3abf19378f0d h1:hMs2isnO6198XaBwqbPff5bYt3uz1498osDC0sVe/dA= +github.com/metacubex/sing-shadowsocks2 v0.1.5-0.20231207115048-3abf19378f0d/go.mod h1:Y7Dm/rJpieN2xkU/pnxJCQxqmFptUCYiGd8oJhiHd0w= +github.com/metacubex/sing-tun v0.1.15-0.20231207115657-1aa1d8cadd9a h1:uVDQ9vdp9MXzaX0GUf5sTqCYkf3P3v+vNcddR84F7F4= +github.com/metacubex/sing-tun v0.1.15-0.20231207115657-1aa1d8cadd9a/go.mod h1:c/FrkpUp2emectVh3getHn5BxvvaEiNuEVrBdonw8U8= +github.com/metacubex/sing-vmess v0.1.9-0.20231207122118-72303677451f h1:QjXrHKbTMBip/C+R79bvbfr42xH1gZl3uFb0RELdZiQ= +github.com/metacubex/sing-vmess v0.1.9-0.20231207122118-72303677451f/go.mod h1:olVkD4FChQ5gKMHG4ZzuD7+fMkJY1G8vwOKpRehjrmY= +github.com/metacubex/sing-wireguard v0.0.0-20231207123053-1367f0b8f173 h1:q5wu7tynMlhGPsRXgZ2+a16vDo6uOe9cwz483n7MRwM= +github.com/metacubex/sing-wireguard v0.0.0-20231207123053-1367f0b8f173/go.mod h1:swI5NYmpSOavsMyKnxSLikD9CvnCUcpjzwLdaWPNS9g= github.com/miekg/dns v1.1.57 h1:Jzi7ApEIzwEPLHWRcafCN9LZSBbqQpxjt/wpgvg7wcM= github.com/miekg/dns v1.1.57/go.mod h1:uqRjCRUuEAA6qsOiJvDd+CFo/vW+y5WR6SNmHE55hZk= github.com/mroth/weightedrand/v2 v2.1.0 h1:o1ascnB1CIVzsqlfArQQjeMy1U0NcIbBO5rfd5E/OeU= @@ -158,8 +158,8 @@ github.com/sagernet/go-tun2socks v1.16.12-0.20220818015926-16cb67876a61 h1:5+m7c github.com/sagernet/go-tun2socks v1.16.12-0.20220818015926-16cb67876a61/go.mod h1:QUQ4RRHD6hGGHdFMEtR8T2P6GS6R3D/CXKdaYHKKXms= github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97 h1:iL5gZI3uFp0X6EslacyapiRz7LLSJyr4RajF/BhMVyE= github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97/go.mod h1:xLnfdiJbSp8rNqYEdIW/6eDO4mVoogml14Bh2hSiFpM= -github.com/sagernet/sing-mux v0.1.5-0.20231109075101-6b086ed6bb07 h1:ncKb5tVOsCQgCsv6UpsA0jinbNb5OQ5GMPJlyQP3EHM= -github.com/sagernet/sing-mux v0.1.5-0.20231109075101-6b086ed6bb07/go.mod h1:u/MZf32xPG8jEKe3t+xUV67EBnKtDtCaPhsJQOQGUYU= +github.com/sagernet/sing-mux v0.1.6-0.20231207143704-9f6c20fb5266 h1:QqwwUyEfmOuoGVTZ2cYvUJEeSWlzunvQLRmv+9B41uk= +github.com/sagernet/sing-mux v0.1.6-0.20231207143704-9f6c20fb5266/go.mod h1:uxpcXa8JqSR+ufC1sGAPsCs027wpE7v1ltnhuJKqyBQ= 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/smux v0.0.0-20230312102458-337ec2a5af37 h1:HuE6xSwco/Xed8ajZ+coeYLmioq0Qp1/Z2zczFaV8as= @@ -221,8 +221,8 @@ go.uber.org/automaxprocs v1.5.3 h1:kWazyxZUrS3Gs4qUpbwo5kEIMGe/DAvi5Z4tl2NW4j8= go.uber.org/automaxprocs v1.5.3/go.mod h1:eRbA25aqJrxAbsLO0xy5jVwPt7FQnRgjW+efnwa1WM0= go.uber.org/mock v0.3.0 h1:3mUxI1No2/60yUYax92Pt8eNOEecx2D3lcXZh2NEZJo= go.uber.org/mock v0.3.0/go.mod h1:a6FSlNadKUHUa9IP5Vyt1zh4fC7uAwxMutEAscFbkZc= -go4.org/netipx v0.0.0-20230824141953-6213f710f925 h1:eeQDDVKFkx0g4Hyy8pHgmZaK0EqB4SD6rvKbUdN3ziQ= -go4.org/netipx v0.0.0-20230824141953-6213f710f925/go.mod h1:PLyyIXexvUFg3Owu6p/WfdlivPbZJsZdgWZlrGope/Y= +go4.org/netipx v0.0.0-20231129151722-fdeea329fbba h1:0b9z3AuHCjxk0x/opv64kcgZLBseWJUpBw5I82+2U4M= +go4.org/netipx v0.0.0-20231129151722-fdeea329fbba/go.mod h1:PLyyIXexvUFg3Owu6p/WfdlivPbZJsZdgWZlrGope/Y= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.16.0 h1:mMMrFzRSCF0GvB7Ne27XVtVAaXLrPmgPC7/v0tkwHaY= @@ -235,8 +235,8 @@ golang.org/x/mod v0.14.0 h1:dGoOF9QVLYng8IHTm7BAyWqCqSheQ5pYWGhzW00YJr0= golang.org/x/mod v0.14.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.18.0 h1:mIYleuAkSbHh0tCv7RvjL3F6ZVbLjq4+R7zbOn3Kokg= -golang.org/x/net v0.18.0/go.mod h1:/czyP5RqHAH4odGYxBJ1qz0+CE5WZ+2j1YgoEo8F2jQ= +golang.org/x/net v0.19.0 h1:zTwKpTd2XuCqf8huc7Fo2iSy+4RHPd10s4KzeTnVr1c= +golang.org/x/net v0.19.0/go.mod h1:CfAk/cbD4CthTvqiEl8NpboMuiuOYsAr/7NOjZJtv1U= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.5.0 h1:60k92dhOjHxJkrqnwsfl8KuaHbn/5dl0lUPUklKo3qE= golang.org/x/sync v0.5.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= @@ -256,14 +256,13 @@ golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc= golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= -golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4= -golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.4.0 h1:Z81tqI5ddIoXDPvVQ7/7CC9TnLM7ubaFG2qXYd5BbYY= +golang.org/x/time v0.4.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.15.0 h1:zdAyfUGbYmuVokhzVmghFl2ZJh5QhcfebBgmVPFYA+8= golang.org/x/tools v0.15.0/go.mod h1:hpksKq4dtpQWS1uQ61JkdqWM3LscIS6Slf+VVkm+wQk= diff --git a/listener/sing/sing.go b/listener/sing/sing.go index 65c42b6a..4e31faeb 100644 --- a/listener/sing/sing.go +++ b/listener/sing/sing.go @@ -138,41 +138,36 @@ func (h *ListenerHandler) NewConnection(ctx context.Context, conn net.Conn, meta } func (h *ListenerHandler) NewPacketConnection(ctx context.Context, conn network.PacketConn, metadata M.Metadata) error { - if deadline.NeedAdditionalReadDeadline(conn) { - conn = deadline.NewFallbackPacketConn(bufio.NewNetPacketConn(conn)) // conn from sing should check NeedAdditionalReadDeadline - } defer func() { _ = conn.Close() }() mutex := sync.Mutex{} - conn2 := conn // a new interface to set nil in defer + conn2 := bufio.NewNetPacketConn(conn) // a new interface to set nil in defer defer func() { mutex.Lock() // this goroutine must exit after all conn.WritePacket() is not running defer mutex.Unlock() conn2 = nil }() - var buff *buf.Buffer - newBuffer := func() *buf.Buffer { - buff = buf.NewPacket() // do not use stack buffer - return buff - } + rwOptions := network.ReadWaitOptions{} readWaiter, isReadWaiter := bufio.CreatePacketReadWaiter(conn) if isReadWaiter { - readWaiter.InitializeReadWaiter(newBuffer) + readWaiter.InitializeReadWaiter(rwOptions) } for { var ( + buff *buf.Buffer dest M.Socksaddr err error ) - buff = nil // clear last loop status, avoid repeat release if isReadWaiter { - dest, err = readWaiter.WaitReadPacket() + buff, dest, err = readWaiter.WaitReadPacket() } else { - dest, err = conn.ReadPacket(newBuffer()) + buff = rwOptions.NewPacketBuffer() + dest, err = conn.ReadPacket(buff) + if buff != nil { + rwOptions.PostReturn(buff) + } } if err != nil { - if buff != nil { - buff.Release() - } + buff.Release() if ShouldIgnorePacketError(err) { break } @@ -212,7 +207,7 @@ func ShouldIgnorePacketError(err error) bool { } type packet struct { - conn *network.PacketConn + conn *network.NetPacketConn mutex *sync.Mutex rAddr net.Addr lAddr net.Addr @@ -238,18 +233,7 @@ func (c *packet) WriteBack(b []byte, addr net.Addr) (n int, err error) { return } - buff := buf.NewPacket() - defer buff.Release() - n, err = buff.Write(b) - if err != nil { - return - } - - err = conn.WritePacket(buff, M.SocksaddrFromNet(addr)) - if err != nil { - return - } - return + return conn.WriteTo(b, addr) } // LocalAddr returns the source IP/Port of UDP Packet diff --git a/listener/sing_shadowsocks/server.go b/listener/sing_shadowsocks/server.go index 1760e43c..bd5002a4 100644 --- a/listener/sing_shadowsocks/server.go +++ b/listener/sing_shadowsocks/server.go @@ -23,6 +23,7 @@ import ( "github.com/sagernet/sing/common/buf" "github.com/sagernet/sing/common/bufio" M "github.com/sagernet/sing/common/metadata" + "github.com/sagernet/sing/common/network" ) type Listener struct { @@ -96,30 +97,33 @@ func New(config LC.ShadowsocksServer, tunnel C.Tunnel, additions ...inbound.Addi go func() { conn := bufio.NewPacketConn(ul) - var buff *buf.Buffer - newBuffer := func() *buf.Buffer { - buff = buf.NewPacket() // do not use stack buffer - return buff + rwOptions := network.ReadWaitOptions{ + FrontHeadroom: network.CalculateFrontHeadroom(sl.service), + RearHeadroom: network.CalculateRearHeadroom(sl.service), + MTU: network.CalculateMTU(conn, sl.service), } readWaiter, isReadWaiter := bufio.CreatePacketReadWaiter(conn) if isReadWaiter { - readWaiter.InitializeReadWaiter(newBuffer) + readWaiter.InitializeReadWaiter(rwOptions) } for { var ( + buff *buf.Buffer dest M.Socksaddr err error ) buff = nil // clear last loop status, avoid repeat release if isReadWaiter { - dest, err = readWaiter.WaitReadPacket() + buff, dest, err = readWaiter.WaitReadPacket() } else { - dest, err = conn.ReadPacket(newBuffer()) + buff = rwOptions.NewPacketBuffer() + dest, err = conn.ReadPacket(buff) + if buff != nil { + rwOptions.PostReturn(buff) + } } if err != nil { - if buff != nil { - buff.Release() - } + buff.Release() if sl.closed { break } diff --git a/listener/sing_tun/dns.go b/listener/sing_tun/dns.go index 122f5a32..4fd38e1d 100644 --- a/listener/sing_tun/dns.go +++ b/listener/sing_tun/dns.go @@ -109,29 +109,29 @@ func (h *ListenerHandler) NewPacketConnection(ctx context.Context, conn network. defer mutex.Unlock() conn2 = nil }() - - var buff *buf.Buffer - newBuffer := func() *buf.Buffer { - // safe size which is 1232 from https://dnsflagday.net/2020/. - // so 2048 is enough - buff = buf.NewSize(2 * 1024) - return buff + rwOptions := network.ReadWaitOptions{ + MTU: 2 * 1024, // safe size which is 1232 from https://dnsflagday.net/2020/, so 2048 is enough } readWaiter, isReadWaiter := bufio.CreatePacketReadWaiter(conn) if isReadWaiter { - readWaiter.InitializeReadWaiter(newBuffer) + readWaiter.InitializeReadWaiter(rwOptions) } for { var ( + buff *buf.Buffer dest M.Socksaddr err error ) _ = conn.SetReadDeadline(time.Now().Add(DefaultDnsReadTimeout)) buff = nil // clear last loop status, avoid repeat release if isReadWaiter { - dest, err = readWaiter.WaitReadPacket() + buff, dest, err = readWaiter.WaitReadPacket() } else { - dest, err = conn.ReadPacket(newBuffer()) + buff = rwOptions.NewPacketBuffer() + dest, err = conn.ReadPacket(buff) + if buff != nil { + rwOptions.PostReturn(buff) + } } if err != nil { if buff != nil { @@ -142,7 +142,7 @@ func (h *ListenerHandler) NewPacketConnection(ctx context.Context, conn network. } return err } - go func(buff *buf.Buffer) { + go func() { ctx, cancel := context.WithTimeout(ctx, DefaultDnsRelayTimeout) defer cancel() inData := buff.Bytes() @@ -167,7 +167,7 @@ func (h *ListenerHandler) NewPacketConnection(ctx context.Context, conn network. if err != nil { return } - }(buff) // catch buff at goroutine create, avoid next loop change buff + }() } return nil } diff --git a/transport/vless/vision/conn.go b/transport/vless/vision/conn.go index 79c77835..5ad28134 100644 --- a/transport/vless/vision/conn.go +++ b/transport/vless/vision/conn.go @@ -157,14 +157,7 @@ func (vc *Conn) ReadBuffer(buffer *buf.Buffer) error { func (vc *Conn) Write(p []byte) (int, error) { if vc.writeFilterApplicationData { - buffer := buf.New() - defer buffer.Release() - buffer.Write(p) - err := vc.WriteBuffer(buffer) - if err != nil { - return 0, err - } - return len(p), nil + return N.WriteBuffer(vc, buf.As(p)) } return vc.ExtendedWriter.Write(p) } @@ -266,6 +259,10 @@ func (vc *Conn) FrontHeadroom() int { return PaddingHeaderLen - uuid.Size } +func (vc *Conn) RearHeadroom() int { + return 500 + 900 +} + func (vc *Conn) NeedHandshake() bool { return vc.needHandshake } diff --git a/tunnel/tunnel.go b/tunnel/tunnel.go index c37b0c7d..2454fd9a 100644 --- a/tunnel/tunnel.go +++ b/tunnel/tunnel.go @@ -375,7 +375,6 @@ func handleUDPConn(packet C.PacketAdapter) { cond.Broadcast() }() - pCtx := icontext.NewPacketConnContext(metadata) proxy, rule, err := resolveMetadata(metadata) if err != nil { log.Warnln("[UDP] Parse metadata failed: %s", err.Error()) @@ -402,7 +401,6 @@ func handleUDPConn(packet C.PacketAdapter) { if err != nil { return } - pCtx.InjectPacketConn(rawPc) pc := statistic.NewUDPTracker(rawPc, statistic.DefaultManager, metadata, rule, 0, 0, true)