55 "fmt"
66 "io"
77 "strings"
8+ "sync"
89
910 ddto "github.com/SenseUnit/dumbproxy/dialer/dto"
1011 clog "github.com/SenseUnit/dumbproxy/log"
@@ -13,15 +14,32 @@ import (
1314)
1415
1516func SOCKSHandler (dialer HandlerDialer , logger * clog.CondLogger , forward ForwardFunc ) func (ctx context.Context , writer io.Writer , request * socks5.Request ) error {
17+ var (
18+ outboundMux sync.RWMutex
19+ )
20+ outbound := make (map [string ]string )
21+ isLoopback := func (addr string ) (string , bool ) {
22+ outboundMux .RLock ()
23+ defer outboundMux .RUnlock ()
24+ originator , ok := outbound [addr ]
25+ return originator , ok
26+ }
1627 return func (ctx context.Context , writer io.Writer , request * socks5.Request ) error {
28+ if originator , isLoopback := isLoopback (request .RemoteAddr .String ()); isLoopback {
29+ logger .Critical ("Loopback tunnel detected: %s is an outbound " +
30+ "address for another request from %s" , request .RemoteAddr .String (), originator )
31+ socks5 .SendReply (writer , statute .RepConnectionRefused , nil )
32+ return fmt .Errorf ("Loopback tunnel detected: %s is an outbound " +
33+ "address for another request from %s" , request .RemoteAddr .String (), originator )
34+ }
1735 username := ""
1836 if request .AuthContext != nil {
1937 username = request .AuthContext .Payload ["username" ]
2038 }
2139 localAddr := request .LocalAddr .String ()
2240 ctx = ddto .BoundDialerParamsToContext (ctx , nil , trimAddrPort (localAddr ))
2341 ctx = ddto .FilterParamsToContext (ctx , nil , username )
24- // TODO: add request logging
42+ logger . Info ( "Request: %v => %v %q %v %v %v" , request . RemoteAddr , localAddr , username , "SOCKS5" , "CONNECT" , request . DestAddr )
2543 target , err := dialer .DialContext (ctx , "tcp" , request .DestAddr .String ())
2644 if err != nil {
2745 msg := err .Error ()
@@ -32,11 +50,19 @@ func SOCKSHandler(dialer HandlerDialer, logger *clog.CondLogger, forward Forward
3250 resp = statute .RepNetworkUnreachable
3351 }
3452 if err := socks5 .SendReply (writer , resp , nil ); err != nil {
35- return fmt .Errorf ("failed to send reply, %v " , err )
53+ return fmt .Errorf ("failed to send reply: %w " , err )
3654 }
37- return fmt .Errorf ("connect to %v failed, %v " , request .RawDestAddr , err )
55+ return fmt .Errorf ("connect to %v failed: %w " , request .RawDestAddr , err )
3856 }
39- defer target .Close () // nolint: errcheck
57+ outboundMux .Lock ()
58+ outbound [target .LocalAddr ().String ()] = request .RemoteAddr .String ()
59+ outboundMux .Unlock ()
60+ defer func () {
61+ target .Close () // nolint: errcheck
62+ outboundMux .Lock ()
63+ delete (outbound , localAddr )
64+ outboundMux .Unlock ()
65+ }()
4066
4167 // Send success
4268 if err := socks5 .SendReply (writer , statute .RepSuccess , target .LocalAddr ()); err != nil {
0 commit comments