@@ -29,7 +29,6 @@ import (
29
29
"github.com/Jigsaw-Code/outline-ss-server/service/metrics"
30
30
ss "github.com/Jigsaw-Code/outline-ss-server/shadowsocks"
31
31
logging "github.com/op/go-logging"
32
-
33
32
"github.com/shadowsocks/go-shadowsocks2/socks"
34
33
)
35
34
@@ -149,34 +148,21 @@ func (s *tcpService) SetTargetIPValidator(targetIPValidator onet.TargetIPValidat
149
148
s .targetIPValidator = targetIPValidator
150
149
}
151
150
152
- // proxyConnection will route the clientConn according to the address read from the connection.
153
- func proxyConnection (clientConn onet.DuplexConn , proxyMetrics * metrics.ProxyMetrics , checkAllowedIP onet.TargetIPValidator ) * onet.ConnectionError {
154
- tgtAddr , err := socks .ReadAddr (clientConn )
155
- if err != nil {
156
- return onet .NewConnectionError ("ERR_READ_ADDRESS" , "Failed to get target address" , err )
157
- }
151
+ func dialTarget (tgtAddr socks.Addr , proxyMetrics * metrics.ProxyMetrics , targetIPValidator onet.TargetIPValidator ) (onet.DuplexConn , * onet.ConnectionError ) {
158
152
tgtTCPAddr , err := net .ResolveTCPAddr ("tcp" , tgtAddr .String ())
159
153
if err != nil {
160
- return onet .NewConnectionError ("ERR_RESOLVE_ADDRESS" , fmt .Sprintf ("Failed to resolve target address %v" , tgtAddr .String ()), err )
154
+ return nil , onet .NewConnectionError ("ERR_RESOLVE_ADDRESS" , fmt .Sprintf ("Failed to resolve target address %v" , tgtAddr .String ()), err )
161
155
}
162
- if err := checkAllowedIP (tgtTCPAddr .IP ); err != nil {
163
- return err
156
+ if err := targetIPValidator (tgtTCPAddr .IP ); err != nil {
157
+ return nil , err
164
158
}
165
159
166
160
tgtTCPConn , err := net .DialTCP ("tcp" , nil , tgtTCPAddr )
167
161
if err != nil {
168
- return onet .NewConnectionError ("ERR_CONNECT" , "Failed to connect to target" , err )
162
+ return nil , onet .NewConnectionError ("ERR_CONNECT" , "Failed to connect to target" , err )
169
163
}
170
- defer tgtTCPConn .Close ()
171
164
tgtTCPConn .SetKeepAlive (true )
172
- tgtConn := metrics .MeasureConn (tgtTCPConn , & proxyMetrics .ProxyTarget , & proxyMetrics .TargetProxy )
173
-
174
- logger .Debugf ("proxy %s <-> %s" , clientConn .RemoteAddr ().String (), tgtConn .RemoteAddr ().String ())
175
- _ , _ , err = onet .Relay (clientConn , tgtConn )
176
- if err != nil {
177
- return onet .NewConnectionError ("ERR_RELAY" , "Failed to relay traffic" , err )
178
- }
179
- return nil
165
+ return metrics .MeasureConn (tgtTCPConn , & proxyMetrics .ProxyTarget , & proxyMetrics .TargetProxy ), nil
180
166
}
181
167
182
168
func (s * tcpService ) Serve (listener * net.TCPListener ) error {
@@ -196,7 +182,7 @@ func (s *tcpService) Serve(listener *net.TCPListener) error {
196
182
197
183
defer s .running .Done ()
198
184
for {
199
- clientConn , err := listener .AcceptTCP ()
185
+ clientTCPConn , err := listener .AcceptTCP ()
200
186
if err != nil {
201
187
s .mu .RLock ()
202
188
stopped := s .stopped
@@ -216,26 +202,26 @@ func (s *tcpService) Serve(listener *net.TCPListener) error {
216
202
logger .Errorf ("Panic in TCP handler: %v" , r )
217
203
}
218
204
}()
219
- s .handleConnection (listener .Addr ().(* net.TCPAddr ).Port , clientConn )
205
+ s .handleConnection (listener .Addr ().(* net.TCPAddr ).Port , clientTCPConn )
220
206
}()
221
207
}
222
208
}
223
209
224
- func (s * tcpService ) handleConnection (listenerPort int , clientConn onet. DuplexConn ) {
225
- clientLocation , err := s .m .GetLocation (clientConn .RemoteAddr ())
210
+ func (s * tcpService ) handleConnection (listenerPort int , clientTCPConn * net. TCPConn ) {
211
+ clientLocation , err := s .m .GetLocation (clientTCPConn .RemoteAddr ())
226
212
if err != nil {
227
213
logger .Warningf ("Failed location lookup: %v" , err )
228
214
}
229
- logger .Debugf ("Got location \" %v\" for IP %v" , clientLocation , clientConn .RemoteAddr ().String ())
215
+ logger .Debugf ("Got location \" %v\" for IP %v" , clientLocation , clientTCPConn .RemoteAddr ().String ())
230
216
s .m .AddOpenTCPConnection (clientLocation )
231
217
232
218
connStart := time .Now ()
233
- clientConn .( * net. TCPConn ) .SetKeepAlive (true )
234
- // Set a deadline for connection authentication
235
- clientConn .SetReadDeadline (connStart .Add (s .readTimeout ))
219
+ clientTCPConn .SetKeepAlive (true )
220
+ // Set a deadline to receive the address to the target.
221
+ clientTCPConn .SetReadDeadline (connStart .Add (s .readTimeout ))
236
222
var proxyMetrics metrics.ProxyMetrics
237
- clientConn = metrics .MeasureConn (clientConn , & proxyMetrics .ProxyClient , & proxyMetrics .ClientProxy )
238
- cipherEntry , clientReader , clientSalt , timeToCipher , keyErr := findAccessKey (clientConn , remoteIP (clientConn ), s .ciphers )
223
+ clientConn : = metrics .MeasureConn (clientTCPConn , & proxyMetrics .ProxyClient , & proxyMetrics .ClientProxy )
224
+ cipherEntry , clientReader , clientSalt , timeToCipher , keyErr := findAccessKey (clientConn , remoteIP (clientTCPConn ), s .ciphers )
239
225
240
226
connError := func () * onet.ConnectionError {
241
227
if keyErr != nil {
@@ -255,17 +241,58 @@ func (s *tcpService) handleConnection(listenerPort int, clientConn onet.DuplexCo
255
241
status = "ERR_REPLAY_CLIENT"
256
242
}
257
243
s .absorbProbe (listenerPort , clientConn , clientLocation , status , & proxyMetrics )
258
- logger .Debugf (status + ": %v in %s sent %d bytes" , clientConn .RemoteAddr (), clientLocation , proxyMetrics .ClientProxy )
244
+ logger .Debugf (status + ": %v in %s sent %d bytes" , clientTCPConn .RemoteAddr (), clientLocation , proxyMetrics .ClientProxy )
259
245
return onet .NewConnectionError (status , "Replay detected" , nil )
260
246
}
261
- // Clear the authentication deadline
262
- clientConn .SetReadDeadline (time.Time {})
263
247
264
248
ssr := ss .NewShadowsocksReader (clientReader , cipherEntry .Cipher )
249
+ tgtAddr , err := socks .ReadAddr (ssr )
250
+ // Clear the deadline for the target address
251
+ clientTCPConn .SetReadDeadline (time.Time {})
252
+ if err != nil {
253
+ // Drain to prevent a close on cipher error.
254
+ io .Copy (ioutil .Discard , clientConn )
255
+ return onet .NewConnectionError ("ERR_READ_ADDRESS" , "Failed to get target address" , err )
256
+ }
257
+
258
+ tgtConn , dialErr := dialTarget (tgtAddr , & proxyMetrics , s .targetIPValidator )
259
+ if dialErr != nil {
260
+ // We don't drain so dial errors and invalid addresses are communicated quickly.
261
+ return dialErr
262
+ }
263
+ defer tgtConn .Close ()
264
+
265
+ logger .Debugf ("proxy %s <-> %s" , clientTCPConn .RemoteAddr ().String (), tgtConn .RemoteAddr ().String ())
265
266
ssw := ss .NewShadowsocksWriter (clientConn , cipherEntry .Cipher )
266
267
ssw .SetSaltGenerator (cipherEntry .SaltGenerator )
267
- clientConn = onet .WrapConn (clientConn , ssr , ssw )
268
- return proxyConnection (clientConn , & proxyMetrics , s .targetIPValidator )
268
+
269
+ fromClientErrCh := make (chan error )
270
+ go func () {
271
+ _ , fromClientErr := ssr .WriteTo (tgtConn )
272
+ if fromClientErr != nil {
273
+ // Drain to prevent a close in the case of a cipher error.
274
+ io .Copy (ioutil .Discard , clientConn )
275
+ }
276
+ clientConn .CloseRead ()
277
+ // Send FIN to target.
278
+ // We must do this after the drain is completed, otherwise the target will close its
279
+ // connection with the proxy, which will, in turn, close the connection with the client.
280
+ tgtConn .CloseWrite ()
281
+ fromClientErrCh <- fromClientErr
282
+ }()
283
+ _ , fromTargetErr := ssw .ReadFrom (tgtConn )
284
+ // Send FIN to client.
285
+ clientConn .CloseWrite ()
286
+ tgtConn .CloseRead ()
287
+
288
+ fromClientErr := <- fromClientErrCh
289
+ if fromClientErr != nil {
290
+ return onet .NewConnectionError ("ERR_RELAY_CLIENT" , "Failed to relay traffic from client" , fromClientErr )
291
+ }
292
+ if fromTargetErr != nil {
293
+ return onet .NewConnectionError ("ERR_RELAY_TARGET" , "Failed to relay traffic from target" , fromTargetErr )
294
+ }
295
+ return nil
269
296
}()
270
297
271
298
connDuration := time .Now ().Sub (connStart )
0 commit comments