Skip to content

Commit c5c692f

Browse files
committed
Implementation read waiter for socks5 UDP and UoT
1 parent d0cb357 commit c5c692f

4 files changed

Lines changed: 97 additions & 1 deletion

File tree

common/uot/conn.go

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import (
44
"encoding/binary"
55
"io"
66
"net"
7+
"os"
78

89
"github.com/sagernet/sing/common"
910
"github.com/sagernet/sing/common/buf"
@@ -13,11 +14,17 @@ import (
1314
N "github.com/sagernet/sing/common/network"
1415
)
1516

17+
var (
18+
_ N.NetPacketConn = (*Conn)(nil)
19+
_ N.PacketReadWaiter = (*Conn)(nil)
20+
)
21+
1622
type Conn struct {
1723
net.Conn
1824
isConnect bool
1925
destination M.Socksaddr
2026
writer N.VectorisedWriter
27+
newBuffer func() *buf.Buffer
2128
}
2229

2330
func NewConn(conn net.Conn, request Request) *Conn {
@@ -141,6 +148,36 @@ func (c *Conn) WritePacket(buffer *buf.Buffer, destination M.Socksaddr) error {
141148
return c.writer.WriteVectorised([]*buf.Buffer{header, buffer})
142149
}
143150

151+
func (c *Conn) InitializeReadWaiter(newBuffer func() *buf.Buffer) {
152+
c.newBuffer = newBuffer
153+
}
154+
155+
func (c *Conn) WaitReadPacket() (buffer *buf.Buffer, destination M.Socksaddr, err error) {
156+
if c.newBuffer == nil {
157+
return nil, M.Socksaddr{}, os.ErrInvalid
158+
}
159+
if c.isConnect {
160+
destination = c.destination
161+
} else {
162+
destination, err = AddrParser.ReadAddrPort(c.Conn)
163+
if err != nil {
164+
return
165+
}
166+
}
167+
var length uint16
168+
err = binary.Read(c.Conn, binary.BigEndian, &length)
169+
if err != nil {
170+
return
171+
}
172+
buffer = c.newBuffer()
173+
_, err = buffer.ReadFullFrom(c.Conn, int(length))
174+
if err != nil {
175+
buffer.Release()
176+
return nil, M.Socksaddr{}, E.Cause(err, "UoT read")
177+
}
178+
return
179+
}
180+
144181
func (c *Conn) NeedAdditionalReadDeadline() bool {
145182
return true
146183
}

protocol/socks/client.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import (
77
"os"
88
"strings"
99

10+
"github.com/sagernet/sing/common/bufio"
1011
E "github.com/sagernet/sing/common/exceptions"
1112
M "github.com/sagernet/sing/common/metadata"
1213
N "github.com/sagernet/sing/common/network"
@@ -147,7 +148,7 @@ func (c *Client) DialContext(ctx context.Context, network string, address M.Sock
147148
tcpConn.Close()
148149
return nil, err
149150
}
150-
return NewAssociateConn(udpConn, address, tcpConn), nil
151+
return NewAssociatePacketConn(bufio.NewUnbindPacketConn(udpConn), address, tcpConn), nil
151152
}
152153
return nil, os.ErrInvalid
153154
}

protocol/socks/packet.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import (
77
"github.com/sagernet/sing/common"
88
"github.com/sagernet/sing/common/buf"
99
"github.com/sagernet/sing/common/bufio"
10+
E "github.com/sagernet/sing/common/exceptions"
1011
M "github.com/sagernet/sing/common/metadata"
1112
N "github.com/sagernet/sing/common/network"
1213
)
@@ -17,6 +18,8 @@ import (
1718
// | 2 | 1 | 1 | Variable | 2 | Variable |
1819
// +----+------+------+----------+----------+----------+
1920

21+
var ErrInvalidPacket = E.New("socks5: invalid packet")
22+
2023
type AssociatePacketConn struct {
2124
N.NetPacketConn
2225
remoteAddr M.Socksaddr
@@ -31,6 +34,7 @@ func NewAssociatePacketConn(conn net.PacketConn, remoteAddr M.Socksaddr, underly
3134
}
3235
}
3336

37+
// Deprecated: NewAssociatePacketConn(bufio.NewUnbindPacketConn(conn), remoteAddr, underlying) instead.
3438
func NewAssociateConn(conn net.Conn, remoteAddr M.Socksaddr, underlying net.Conn) *AssociatePacketConn {
3539
return &AssociatePacketConn{
3640
NetPacketConn: bufio.NewUnbindPacketConn(conn),
@@ -49,6 +53,9 @@ func (c *AssociatePacketConn) ReadFrom(p []byte) (n int, addr net.Addr, err erro
4953
if err != nil {
5054
return
5155
}
56+
if n < 3 {
57+
return 0, nil, ErrInvalidPacket
58+
}
5259
c.remoteAddr = M.SocksaddrFromNet(addr)
5360
reader := bytes.NewReader(p[3:n])
5461
destination, err := M.SocksaddrSerializer.ReadAddrPort(reader)
@@ -92,6 +99,9 @@ func (c *AssociatePacketConn) ReadPacket(buffer *buf.Buffer) (destination M.Sock
9299
if err != nil {
93100
return M.Socksaddr{}, err
94101
}
102+
if buffer.Len() < 3 {
103+
return M.Socksaddr{}, ErrInvalidPacket
104+
}
95105
c.remoteAddr = destination
96106
buffer.Advance(3)
97107
destination, err = M.SocksaddrSerializer.ReadAddrPort(buffer)

protocol/socks/packet_wait.go

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
package socks
2+
3+
import (
4+
"github.com/sagernet/sing/common/buf"
5+
"github.com/sagernet/sing/common/bufio"
6+
M "github.com/sagernet/sing/common/metadata"
7+
N "github.com/sagernet/sing/common/network"
8+
)
9+
10+
var _ N.PacketReadWaitCreator = (*AssociatePacketConn)(nil)
11+
12+
func (c *AssociatePacketConn) CreateReadWaiter() (N.PacketReadWaiter, bool) {
13+
readWaiter, isReadWaiter := bufio.CreatePacketReadWaiter(c.NetPacketConn)
14+
if !isReadWaiter {
15+
return nil, false
16+
}
17+
return &AssociatePacketReadWaiter{c, readWaiter}, true
18+
}
19+
20+
var _ N.PacketReadWaiter = (*AssociatePacketReadWaiter)(nil)
21+
22+
type AssociatePacketReadWaiter struct {
23+
conn *AssociatePacketConn
24+
readWaiter N.PacketReadWaiter
25+
}
26+
27+
func (w *AssociatePacketReadWaiter) InitializeReadWaiter(newBuffer func() *buf.Buffer) {
28+
w.readWaiter.InitializeReadWaiter(newBuffer)
29+
}
30+
31+
func (w *AssociatePacketReadWaiter) WaitReadPacket() (buffer *buf.Buffer, destination M.Socksaddr, err error) {
32+
buffer, destination, err = w.readWaiter.WaitReadPacket()
33+
if err != nil {
34+
return
35+
}
36+
if buffer.Len() < 3 {
37+
buffer.Release()
38+
return nil, M.Socksaddr{}, ErrInvalidPacket
39+
}
40+
w.conn.remoteAddr = destination
41+
buffer.Advance(3)
42+
destination, err = M.SocksaddrSerializer.ReadAddrPort(buffer)
43+
if err != nil {
44+
buffer.Release()
45+
return nil, M.Socksaddr{}, err
46+
}
47+
return
48+
}

0 commit comments

Comments
 (0)