Skip to content

Commit 97332c7

Browse files
committed
stdio connection handler
1 parent 6ec158f commit 97332c7

File tree

3 files changed

+103
-6
lines changed

3 files changed

+103
-6
lines changed

dialer/dto/dto.go

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,10 @@ type filterContextParams struct {
3232
}
3333

3434
func FilterParamsFromContext(ctx context.Context) (*http.Request, string) {
35-
params := ctx.Value(filterContextKey{}).(filterContextParams)
36-
return params.req, params.username
35+
if params, ok := ctx.Value(filterContextKey{}).(filterContextParams); ok {
36+
return params.req, params.username
37+
}
38+
return nil, ""
3739
}
3840

3941
func FilterParamsToContext(ctx context.Context, req *http.Request, username string) context.Context {

handler/stdio.go

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
package handler
2+
3+
import (
4+
"context"
5+
"fmt"
6+
"io"
7+
"net"
8+
"sync"
9+
10+
clog "github.com/SenseUnit/dumbproxy/log"
11+
)
12+
13+
func StdIOHandler(dialer HandlerDialer, logger *clog.CondLogger, forward ForwardFunc) func(ctx context.Context, reader io.Reader, writer io.Writer, dstAddress string) error {
14+
return func(ctx context.Context, reader io.Reader, writer io.Writer, dstAddress string) error {
15+
logger.Debug("Request: %v => %v %q %v %v %v", "<stdio>", "<stdio>", "", "STDIO", "CONNECT", dstAddress)
16+
target, err := dialer.DialContext(ctx, "tcp", dstAddress)
17+
if err != nil {
18+
return fmt.Errorf("connect to %q failed: %w", dstAddress, err)
19+
}
20+
defer target.Close()
21+
22+
return forward(ctx, "", wrapSOCKS(reader, writer), target)
23+
}
24+
}
25+
26+
type DummyAddress struct {
27+
network string
28+
address string
29+
}
30+
31+
func (a DummyAddress) Network() string {
32+
return a.network
33+
}
34+
35+
func (a DummyAddress) String() string {
36+
return a.address
37+
}
38+
39+
type DummyListener struct {
40+
address DummyAddress
41+
closed chan struct{}
42+
closeOnce sync.Once
43+
}
44+
45+
// Accept waits for and returns the next connection to the listener.
46+
func (l *DummyListener) Accept() (net.Conn, error) {
47+
<-l.closed
48+
return nil, net.ErrClosed
49+
}
50+
51+
// Close closes the listener.
52+
// Any blocked Accept operations will be unblocked and return errors.
53+
func (l *DummyListener) Close() error {
54+
l.closeOnce.Do(func() {
55+
close(l.closed)
56+
})
57+
return nil
58+
}
59+
60+
// Addr returns the listener's network address.
61+
func (l *DummyListener) Addr() net.Addr {
62+
return l.address
63+
}
64+
65+
func DummyListen(network, address string) (net.Listener, error) {
66+
return &DummyListener{
67+
address: DummyAddress{
68+
network: network,
69+
address: address,
70+
},
71+
closed: make(chan struct{}),
72+
}, nil
73+
}

main.go

Lines changed: 26 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -217,6 +217,7 @@ const (
217217
_ proxyMode = iota
218218
proxyModeHTTP
219219
proxyModeSOCKS5
220+
proxyModeStdIO
220221
)
221222

222223
type proxyModeArg struct {
@@ -230,6 +231,8 @@ func (a *proxyModeArg) Set(arg string) error {
230231
val = proxyModeHTTP
231232
case "socks", "socks5":
232233
val = proxyModeSOCKS5
234+
case "stdio":
235+
val = proxyModeStdIO
233236
default:
234237
return fmt.Errorf("unrecognized proxy mode %q", arg)
235238
}
@@ -243,6 +246,8 @@ func (a *proxyModeArg) String() string {
243246
return "http"
244247
case proxyModeSOCKS5:
245248
return "socks5"
249+
case proxyModeStdIO:
250+
return "stdio"
246251
default:
247252
return fmt.Sprintf("proxyMode(%d)", int(a.value))
248253
}
@@ -510,9 +515,16 @@ func run() int {
510515
return 0
511516
}
512517

513-
// we don't expect positional arguments in the main operation mode
514-
if len(args.positionalArgs) > 0 {
515-
arg_fail("Unexpected positional arguments! Check your command line.")
518+
if args.mode.value == proxyModeStdIO {
519+
// expect exactly two positional arguments
520+
if len(args.positionalArgs) != 2 {
521+
arg_fail("Exactly two positional arguments are expected in this mode: host and port")
522+
}
523+
} else {
524+
// we don't expect positional arguments in the main operation mode
525+
if len(args.positionalArgs) > 0 {
526+
arg_fail("Unexpected positional arguments! Check your command line.")
527+
}
516528
}
517529

518530
// setup logging
@@ -640,7 +652,10 @@ func run() int {
640652
mainLogger.Info("Starting proxy server...")
641653

642654
listenerFactory := net.Listen
643-
if args.bindReusePort {
655+
switch {
656+
case args.mode.value == proxyModeStdIO:
657+
listenerFactory = handler.DummyListen
658+
case args.bindReusePort:
644659
if reuseport.Available() {
645660
listenerFactory = reuseport.Listen
646661
} else {
@@ -872,6 +887,13 @@ func run() int {
872887
mainLogger.Info("Reached normal server termination.")
873888
}
874889
return 0
890+
case proxyModeStdIO:
891+
handler := handler.StdIOHandler(dialerRoot, proxyLogger, forwarder)
892+
address := net.JoinHostPort(args.positionalArgs[0], args.positionalArgs[1])
893+
if err := handler(stopContext, os.Stdin, os.Stdout, address); err != nil {
894+
mainLogger.Error("Connection interrupted: %v", err)
895+
}
896+
return 0
875897
}
876898

877899
mainLogger.Critical("unknown proxy mode")

0 commit comments

Comments
 (0)