-
Notifications
You must be signed in to change notification settings - Fork 402
/
packet.go
127 lines (104 loc) · 2.82 KB
/
packet.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
package socks5
import (
"errors"
"net"
"github.com/nadoo/glider/pkg/pool"
"github.com/nadoo/glider/pkg/socks"
)
// PktConn .
type PktConn struct {
net.PacketConn
ctrlConn net.Conn // tcp control conn
writeTo net.Addr // write to and read from addr
target socks.Addr
}
// NewPktConn returns a PktConn, the writeAddr must be *net.UDPAddr or *net.UnixAddr.
func NewPktConn(c net.PacketConn, writeAddr net.Addr, targetAddr socks.Addr, ctrlConn net.Conn) *PktConn {
pc := &PktConn{
PacketConn: c,
writeTo: writeAddr,
target: targetAddr,
ctrlConn: ctrlConn,
}
if ctrlConn != nil {
go func() {
buf := pool.GetBuffer(1)
defer pool.PutBuffer(buf)
for {
_, err := ctrlConn.Read(buf)
if err, ok := err.(net.Error); ok && err.Timeout() {
continue
}
// log.F("[socks5] dialudp udp associate end")
return
}
}()
}
return pc
}
// ReadFrom overrides the original function from net.PacketConn.
func (pc *PktConn) ReadFrom(b []byte) (int, net.Addr, error) {
n, _, target, err := pc.readFrom(b)
return n, target, err
}
func (pc *PktConn) readFrom(b []byte) (int, net.Addr, net.Addr, error) {
buf := pool.GetBuffer(len(b))
defer pool.PutBuffer(buf)
n, raddr, err := pc.PacketConn.ReadFrom(buf)
if err != nil {
return n, raddr, nil, err
}
if n < 3 {
return n, raddr, nil, errors.New("not enough size to get addr")
}
// https://www.rfc-editor.org/rfc/rfc1928#section-7
// +----+------+------+----------+----------+----------+
// |RSV | FRAG | ATYP | DST.ADDR | DST.PORT | DATA |
// +----+------+------+----------+----------+----------+
// | 2 | 1 | 1 | Variable | 2 | Variable |
// +----+------+------+----------+----------+----------+
tgtAddr := socks.SplitAddr(buf[3:n])
if tgtAddr == nil {
return n, raddr, nil, errors.New("can not get target addr")
}
target, err := net.ResolveUDPAddr("udp", tgtAddr.String())
if err != nil {
return n, raddr, nil, errors.New("wrong target addr")
}
if pc.writeTo == nil {
pc.writeTo = raddr
}
if pc.target == nil {
pc.target = make([]byte, len(tgtAddr))
copy(pc.target, tgtAddr)
}
n = copy(b, buf[3+len(tgtAddr):n])
return n, raddr, target, err
}
// WriteTo overrides the original function from net.PacketConn.
func (pc *PktConn) WriteTo(b []byte, addr net.Addr) (int, error) {
target := pc.target
if addr != nil {
target = socks.ParseAddr(addr.String())
}
if target == nil {
return 0, errors.New("invalid addr")
}
buf := pool.GetBytesBuffer()
defer pool.PutBytesBuffer(buf)
buf.Write([]byte{0, 0, 0})
tgtLen, _ := buf.Write(target)
buf.Write(b)
n, err := pc.PacketConn.WriteTo(buf.Bytes(), pc.writeTo)
if n > tgtLen+3 {
return n - tgtLen - 3, err
}
return 0, err
}
// Close .
func (pc *PktConn) Close() error {
if pc.ctrlConn != nil {
pc.ctrlConn.Close()
}
return pc.PacketConn.Close()
}