Skip to content

Commit 4818222

Browse files
committed
socks: add loopback detection
1 parent b3d51e1 commit 4818222

File tree

1 file changed

+30
-4
lines changed

1 file changed

+30
-4
lines changed

handler/socks.go

Lines changed: 30 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import (
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

1516
func 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

Comments
 (0)