diff --git a/cmd/cmd.go b/cmd/cmd.go index 1cb7d7a..005e41b 100644 --- a/cmd/cmd.go +++ b/cmd/cmd.go @@ -13,11 +13,12 @@ import ( ) var ( - command string - proxyPort uint16 - proxyPid uint64 - pids []string - ipStr string + command string + proxyPort uint16 + proxyPid uint64 + pids []string + ipStr string + socks5ProxyAddr string ) var rootCmd = &cobra.Command{ @@ -45,7 +46,7 @@ var rootCmd = &cobra.Command{ Options.Ip4 = ip if proxyPid == 0 { - StartProxy(proxyPort) + StartProxy() } for _, pid := range pids { pidInt, err := strconv.ParseUint(pid, 10, 64) @@ -92,4 +93,5 @@ func init() { rootCmd.PersistentFlags().Uint64Var(&proxyPid, "p-pid", 0, "The process ID of the proxy. If not provided, the program will automatically start a forwarding proxy.") rootCmd.PersistentFlags().StringSliceVar(&pids, "pids", []string{}, "The pid to be proxied, seperate by ','") rootCmd.PersistentFlags().StringVar(&ipStr, "ip", "", "The ip to be proxied,only support ipv4") + rootCmd.PersistentFlags().StringVar(&socks5ProxyAddr, "socks5", "", "The socks5 proxyAddr.") } diff --git a/cmd/tcpProxy.go b/cmd/tcpProxy.go index c582065..1d60f9e 100644 --- a/cmd/tcpProxy.go +++ b/cmd/tcpProxy.go @@ -9,9 +9,11 @@ import ( "syscall" "time" "unsafe" + + "golang.org/x/net/proxy" ) -func StartProxy(proxyPort uint16) { +func StartProxy() { // log.Printf("Proxy server with PID %d listening on %s", options.ProxyPid, proxyAddr) proxyAddr := fmt.Sprintf("127.0.0.1:%d", proxyPort) // Start the proxy server on the localhost @@ -49,13 +51,33 @@ func getsockopt(s int, level int, optname int, optval unsafe.Pointer, optlen *ui func handleConnection(conn net.Conn) { defer conn.Close() + targetConn, err := getTargetConnection(conn) + if err != nil { + log.Printf("Connection error: %v", err) + return + } + + go func() { + _, err = io.Copy(targetConn, conn) + if err != nil { + log.Printf("Failed copying data to target: %v", err) + } + }() + _, err = io.Copy(conn, targetConn) + if err != nil { + log.Printf("Failed copying data from target: %v", err) + } +} + +func getTargetConnection(conn net.Conn) (net.Conn, error) { + // Using RawConn is necessary to perform low-level operations on the underlying socket file descriptor in Go. // This allows us to use getsockopt to retrieve the original destination address set by the SO_ORIGINAL_DST option, // which isn't directly accessible through Go's higher-level networking API. rawConn, err := conn.(*net.TCPConn).SyscallConn() if err != nil { log.Printf("Failed to get raw connection: %v", err) - return + return nil, err } var originalDst SockAddrIn @@ -74,27 +96,22 @@ func handleConnection(conn net.Conn) { fmt.Printf("Original destination: %s:%d\n", targetAddr, targetPort) - // Check that the original destination address is reachable from the proxy - targetConn, err := net.DialTimeout("tcp", fmt.Sprintf("%s:%d", targetAddr, targetPort), 5*time.Second) - if err != nil { - log.Printf("Failed to connect to original destination: %v", err) - return + if socks5ProxyAddr == "" { + targetConn, err := net.DialTimeout("tcp", fmt.Sprintf("%s:%d", targetAddr, targetPort), 5*time.Second) + if err != nil { + return nil, fmt.Errorf("failed to connect to destination: %w", err) + } + return targetConn, nil } - defer targetConn.Close() - fmt.Printf("Proxying connection from %s to %s\n", conn.RemoteAddr(), targetConn.RemoteAddr()) + dialer, err := proxy.SOCKS5("tcp", socks5ProxyAddr, nil, proxy.Direct) + if err != nil { + return nil, fmt.Errorf("cannot create SOCKS5 dialer: %w", err) + } - // The following code creates two data transfer channels: - // - From the client to the target server (handled by a separate goroutine). - // - From the target server to the client (handled by the main goroutine). - go func() { - _, err = io.Copy(targetConn, conn) - if err != nil { - log.Printf("Failed copying data to target: %v", err) - } - }() - _, err = io.Copy(conn, targetConn) + targetConn, err := dialer.Dial("tcp", fmt.Sprintf("%s:%d", targetAddr, targetPort)) if err != nil { - log.Printf("Failed copying data from target: %v", err) + return nil, fmt.Errorf("failed to connect via SOCKS5: %w", err) } + return targetConn, nil } diff --git a/go.mod b/go.mod index b9ad38b..f786d5c 100644 --- a/go.mod +++ b/go.mod @@ -5,10 +5,11 @@ go 1.24.4 require ( github.com/cilium/ebpf v0.19.0 github.com/spf13/cobra v1.9.1 + golang.org/x/net v0.38.0 + golang.org/x/sys v0.31.0 ) require ( github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/spf13/pflag v1.0.6 // indirect - golang.org/x/sys v0.31.0 // indirect )