forked from things-go/go-socks5
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmessage.go
197 lines (183 loc) · 6.01 KB
/
message.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
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
package statute
import (
"encoding/binary"
"fmt"
"io"
"net"
)
// Request represents the SOCKS5 request, it contains everything that is not payload
// The SOCKS5 request is formed as follows:
//
// +-----+-----+-------+------+----------+----------+
// | VER | CMD | RSV | ATYP | DST.ADDR | DST.PORT |
// +-----+-----+-------+------+----------+----------+
// | 1 | 1 | X'00' | 1 | Variable | 2 |
// +-----+-----+-------+------+----------+----------+
type Request struct {
// Version of socks protocol for message
Version byte
// Socks Command "connect","bind","associate"
Command byte
// Reserved byte
Reserved byte
// DstAddr in socks message
DstAddr AddrSpec
}
// ParseRequest to request from io.Reader
func ParseRequest(r io.Reader) (req Request, err error) {
// Read the version and command
tmp := []byte{0, 0}
if _, err = io.ReadFull(r, tmp); err != nil {
return req, fmt.Errorf("failed to get request version and command, %v", err)
}
req.Version, req.Command = tmp[0], tmp[1]
if req.Version != VersionSocks5 {
return req, fmt.Errorf("unrecognized SOCKS version[%d]", req.Version)
}
// Read reserved and address type
if _, err = io.ReadFull(r, tmp); err != nil {
return req, fmt.Errorf("failed to get request RSV and address type, %v", err)
}
req.Reserved, req.DstAddr.AddrType = tmp[0], tmp[1]
switch req.DstAddr.AddrType {
case ATYPIPv4:
addr := make([]byte, net.IPv4len+2)
if _, err = io.ReadFull(r, addr); err != nil {
return req, fmt.Errorf("failed to get request, %v", err)
}
req.DstAddr.IP = net.IPv4(addr[0], addr[1], addr[2], addr[3])
req.DstAddr.Port = int(binary.BigEndian.Uint16(addr[net.IPv4len:]))
case ATYPIPv6:
addr := make([]byte, net.IPv6len+2)
if _, err = io.ReadFull(r, addr); err != nil {
return req, fmt.Errorf("failed to get request, %v", err)
}
req.DstAddr.IP = addr[:net.IPv6len]
req.DstAddr.Port = int(binary.BigEndian.Uint16(addr[net.IPv6len:]))
case ATYPDomain:
if _, err = io.ReadFull(r, tmp[:1]); err != nil {
return req, fmt.Errorf("failed to get request, %v", err)
}
domainLen := int(tmp[0])
addr := make([]byte, domainLen+2)
if _, err = io.ReadFull(r, addr); err != nil {
return req, fmt.Errorf("failed to get request, %v", err)
}
req.DstAddr.FQDN = string(addr[:domainLen])
req.DstAddr.Port = int(binary.BigEndian.Uint16(addr[domainLen:]))
default:
return req, ErrUnrecognizedAddrType
}
return req, nil
}
// Bytes returns a slice of request
func (h Request) Bytes() (b []byte) {
var addr []byte
length := 6
if h.DstAddr.AddrType == ATYPIPv4 {
length += net.IPv4len
addr = h.DstAddr.IP.To4()
} else if h.DstAddr.AddrType == ATYPIPv6 {
length += net.IPv6len
addr = h.DstAddr.IP.To16()
} else { // ATYPDomain
length += 1 + len(h.DstAddr.FQDN)
addr = []byte(h.DstAddr.FQDN)
}
b = make([]byte, 0, length)
b = append(b, h.Version, h.Command, h.Reserved, h.DstAddr.AddrType)
if h.DstAddr.AddrType == ATYPDomain {
b = append(b, byte(len(h.DstAddr.FQDN)))
}
b = append(b, addr...)
b = append(b, byte(h.DstAddr.Port>>8), byte(h.DstAddr.Port))
return b
}
// Reply represents the SOCKS5 reply, it contains everything that is not payload
// The SOCKS5 reply is formed as follows:
//
// +-----+-----+-------+------+----------+-----------+
// | VER | REP | RSV | ATYP | BND.ADDR | BND].PORT |
// +-----+-----+-------+------+----------+-----------+
// | 1 | 1 | X'00' | 1 | Variable | 2 |
// +-----+-----+-------+------+----------+-----------+
type Reply struct {
// Version of socks protocol for message
Version byte
// Socks Response status"
Response byte
// Reserved byte
Reserved byte
// Bind Address in socks message
BndAddr AddrSpec
}
// Bytes returns a slice of request
func (sf Reply) Bytes() (b []byte) {
var addr []byte
length := 6
if sf.BndAddr.AddrType == ATYPIPv4 {
length += net.IPv4len
addr = sf.BndAddr.IP.To4()
} else if sf.BndAddr.AddrType == ATYPIPv6 {
length += net.IPv6len
addr = sf.BndAddr.IP.To16()
} else { // ATYPDomain
length += 1 + len(sf.BndAddr.FQDN)
addr = []byte(sf.BndAddr.FQDN)
}
b = make([]byte, 0, length)
b = append(b, sf.Version, sf.Response, sf.Reserved, sf.BndAddr.AddrType)
if sf.BndAddr.AddrType == ATYPDomain {
b = append(b, byte(len(sf.BndAddr.FQDN)))
}
b = append(b, addr...)
b = append(b, byte(sf.BndAddr.Port>>8), byte(sf.BndAddr.Port))
return b
}
// ParseReply parse to reply from io.Reader
func ParseReply(r io.Reader) (rep Reply, err error) {
// Read the version and command
tmp := []byte{0, 0}
if _, err = io.ReadFull(r, tmp); err != nil {
return rep, fmt.Errorf("failed to get reply version and command, %v", err)
}
rep.Version, rep.Response = tmp[0], tmp[1]
if rep.Version != VersionSocks5 {
return rep, fmt.Errorf("unrecognized SOCKS version[%d]", rep.Version)
}
// Read reserved and address type
if _, err = io.ReadFull(r, tmp); err != nil {
return rep, fmt.Errorf("failed to get reply RSV and address type, %v", err)
}
rep.Reserved, rep.BndAddr.AddrType = tmp[0], tmp[1]
switch rep.BndAddr.AddrType {
case ATYPDomain:
if _, err = io.ReadFull(r, tmp[:1]); err != nil {
return rep, fmt.Errorf("failed to get reply, %v", err)
}
domainLen := int(tmp[0])
addr := make([]byte, domainLen+2)
if _, err = io.ReadFull(r, addr); err != nil {
return rep, fmt.Errorf("failed to get reply, %v", err)
}
rep.BndAddr.FQDN = string(addr[:domainLen])
rep.BndAddr.Port = int(binary.BigEndian.Uint16(addr[domainLen:]))
case ATYPIPv4:
addr := make([]byte, net.IPv4len+2)
if _, err = io.ReadFull(r, addr); err != nil {
return rep, fmt.Errorf("failed to get reply, %v", err)
}
rep.BndAddr.IP = net.IPv4(addr[0], addr[1], addr[2], addr[3])
rep.BndAddr.Port = int(binary.BigEndian.Uint16(addr[net.IPv4len:]))
case ATYPIPv6:
addr := make([]byte, net.IPv6len+2)
if _, err = io.ReadFull(r, addr); err != nil {
return rep, fmt.Errorf("failed to get reply, %v", err)
}
rep.BndAddr.IP = addr[:net.IPv6len]
rep.BndAddr.Port = int(binary.BigEndian.Uint16(addr[net.IPv6len:]))
default:
return rep, ErrUnrecognizedAddrType
}
return rep, nil
}