@@ -217,6 +217,7 @@ const (
217217 _ proxyMode = iota
218218 proxyModeHTTP
219219 proxyModeSOCKS5
220+ proxyModeStdIO
220221)
221222
222223type 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 }
@@ -379,7 +384,7 @@ func parse_args() *CLIArgs {
379384 })
380385 flag .BoolVar (& args .unixSockUnlink , "unix-sock-unlink" , true , "delete file object located at Unix domain socket bind path before binding" )
381386 flag .Var (& args .unixSockMode , "unix-sock-mode" , "set file mode for bound unix socket" )
382- flag .Var (& args .mode , "mode" , "proxy operation mode (http/socks5)" )
387+ flag .Var (& args .mode , "mode" , "proxy operation mode (http/socks5/stdio )" )
383388 flag .StringVar (& args .auth , "auth" , "none://" , "auth parameters" )
384389 flag .IntVar (& args .verbosity , "verbosity" , 20 , "logging verbosity " +
385390 "(10 - debug, 20 - info, 30 - warning, 40 - error, 50 - critical)" )
@@ -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