-
Notifications
You must be signed in to change notification settings - Fork 4
/
Copy pathsocks5Handler.go
189 lines (147 loc) · 4.83 KB
/
socks5Handler.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
package main
import (
"bufio"
"context"
"io"
"net"
)
type socks5Handler struct{}
// connHandle handles the connection of a client on the input SOCKS5 listener.
// It parses the SOCKS command, establishes a connection to the requested host through the right chain (found in routingtable table),
// transfers data between the established connecion socket and the clien socket, and finally closes evetything on errors or at the end.
func (h socks5Handler) connHandle(client net.Conn, table string, ctx context.Context, cancel context.CancelFunc) {
gMetaLogger.Debugf("Entering socks5Handler connHandle for connection %v", &client)
defer func() { gMetaLogger.Debugf("Leavings socks5Handler connHandle for connection %v", &client) }()
defer client.Close()
// ***** BEGIN SOCKS5 input parsing *****
// Parse SOCKS5 input to retrieve command, target host and target port (see RFC 1928)
reader := bufio.NewReader(client)
// Read version and number of methods
buff := make([]byte, 2)
_, err := io.ReadFull(reader, buff)
if err != nil {
gMetaLogger.Errorf("could not read on client socket: %v", err)
return
}
if buff[0] != 5 {
gMetaLogger.Error("only SOCKS5 is supported")
return
}
gMetaLogger.Debugf("received SOCKS %v connection with %v proposed methods", buff[0], buff[1])
// Read methods
buff = make([]byte, buff[1])
_, err = io.ReadFull(reader, buff)
if err != nil {
gMetaLogger.Errorf("could not read on client socket: %v", err)
return
}
gMetaLogger.Debugf("Following methods are proposed: %v", buff)
method := byte(255)
for _, m := range buff {
if m == 0 {
method = 0
}
}
if method == 255 {
gMetaLogger.Error("no accepted methods proposed by the client")
return
}
// Send selected method
_, err = client.Write([]byte{5, method})
if err != nil {
gMetaLogger.Error(err)
return
}
gMetaLogger.Debugf("sending SOCKS answer, accepting method %v", method)
// Read version, cmd, rsv and atyp
buff = make([]byte, 4)
_, err = io.ReadFull(reader, buff)
if err != nil {
gMetaLogger.Error(err)
return
}
cmd := buff[1]
atyp := buff[3]
// Only connect command is supported
if cmd != cmdConnect {
gMetaLogger.Errorf("only CONNECT (0x01) SOCKS command is supported, not 0x0%v", cmd)
client.Write([]byte{5, 7})
return
}
addr, err := addrToString(reader, atyp)
if err != nil {
gMetaLogger.Error(err)
client.Write([]byte{5, 1})
return
}
gMetaLogger.Debugf("received SOCKS CMD packet : cmd=%v - atype=%v - addr=%s\n", cmd, atyp, addr)
// ***** END SOCKS5 input parsing *****
// ***** BEGIN Routing decision *****
// Decide which chain to use based on the target address
var chainStr string
if gArgPACPath != "" {
// -pac flag defined, use PAC to find the chain
chainStr, err = getRouteWithPAC(addr)
if err != nil {
gMetaLogger.Errorf("error getting route PAC: %v", err)
client.Write([]byte{5, 1})
return
}
} else {
// use JSON config to find the chain
gRoutingConf.mu.RLock()
table, ok := gRoutingConf.routing[table]
if !ok {
gMetaLogger.Errorf("table %v not defined in routing configuration", table)
client.Write([]byte{5, 1})
gRoutingConf.mu.RUnlock()
return
}
chainStr, err = table.getRoute(addr)
gRoutingConf.mu.RUnlock()
if err != nil {
gMetaLogger.Errorf("error getting route with JSON conf: %v", err)
client.Write([]byte{5, 1})
return
}
}
gMetaLogger.Debugf("chain to use for %v: %v\n", addr, chainStr)
if chainStr == "drop" {
gMetaLogger.Debugf("dropping connection to %v", addr)
gMetaLogger.Auditf("| DROPPED\t| %v\t| %v\t| %v\n", &client, chainStr, addr)
client.Write([]byte{5, 2})
return
}
gChainsConf.mu.RLock()
chain, ok := gChainsConf.proxychains[chainStr]
gChainsConf.mu.RUnlock()
if !ok {
gMetaLogger.Errorf("chain '%v' is not declared in configuration", chainStr)
client.Write([]byte{5, 1})
return
}
// ***** END Routing decision *****
// ***** BEGIN Connection to target host *****
//Connect to chain
target, chainRepresentation, err := chain.connect(ctx, addr)
if err != nil {
gMetaLogger.Error(err)
gMetaLogger.Auditf("| ERROR\t| %v\t| %v\t| %v\t| %v\n", &client, chainStr, addr, chainRepresentation)
client.Write([]byte{5, 1})
return
}
defer target.Close()
gMetaLogger.Debugf("Client %v connected to host %v through chain %v", client, addr, chainStr)
// Create auditing trace for connection opening and defering closing trace
gMetaLogger.Auditf("| OPEN\t| %v\t| %v\t| %v\t| %v\n", &client, chainStr, addr, chainRepresentation)
defer gMetaLogger.Auditf("| CLOSE\t| %v\t| %v\t| %v\t| %v\n", &client, chainStr, addr, chainRepresentation)
//Terminate SOCKS5 handshake with client
_, err = client.Write([]byte{5, 0, 0, 1, 0, 0, 0, 0, 0, 0})
if err != nil {
gMetaLogger.Error(err)
return
}
gMetaLogger.Debugf("sent SOCKS success response")
// ***** END Connection to target host *****
relay(client, target)
}