Simple SSH port forward in Golang

前端 未结 4 879
忘掉有多难
忘掉有多难 2020-12-28 09:45

I\'m trying to create (and later close) a simple TCP port forward over SSH with Go. I\'m new to Golang and statically typed languages. (Coming from Ruby.)

In a termi

相关标签:
4条回答
  • 2020-12-28 10:09

    I'v finished a simple SSH port forward tool called mallory. It provides HTTP proxy instead of SOCKS proxy, which is really similar to ssh -D.

    The core code is similar to damick's answer.

    1. Create ClientConfig
    2. ssh.Dial to remote SSH server with the config and return Client
    3. Now you can use Client.Dial to forward anything you like.

      Dial initiates a connection to the addr from the remote host. The resulting connection has a zero LocalAddr() and RemoteAddr().

    4. If you want to serve a SOCKS proxy server, use Client.Dial to connect to the remote server.

    0 讨论(0)
  • 2020-12-28 10:19

    I finally figured out how to do this, I got hints from schmichael in an IRC channel. Thanks to all!

    EDIT: A little explanation: A big part of the problem I was having was that I did not realize a local net.Listener (not just a local net.Conn) needed setup to receive a local request and create the net.Conn before forwarding the bytes. Also, there exist both port forwards and reverse port forwards and I hadn't previously thought in detail about the fact that a regular port forward also sends bytes back, so copying the remote reader to local writer was not something I had implemented, yet it's very much needed. Here is an attempt to relate the essence of what this code does:

    • Listen on local port 9000.
    • Upon attempted read from local port 9000: (listener.Accept()),
    • Accept connection and return a local io.Reader and io.Writer and,
    • Connect to remote server and,
    • Connect to remote port 9999 returning a io.Reader and io.Writer.
    • Continually copy local io.Reader bytes to remote io.Writer,
    • Continually copy remote io.Reader bytes to local io.Writer.

    Here is the code:

    package main
    
    // Forward from local port 9000 to remote port 9999
    
    import (
        "io"
        "log"
        "net"
        "golang.org/x/crypto/ssh"
    )
    
    var (
        username         = "root"
        password         = "password"
        serverAddrString = "192.168.1.100:22"
        localAddrString  = "localhost:9000"
        remoteAddrString = "localhost:9999"
    )
    
    func forward(localConn net.Conn, config *ssh.ClientConfig) {
        // Setup sshClientConn (type *ssh.ClientConn)
        sshClientConn, err := ssh.Dial("tcp", serverAddrString, config)
        if err != nil {
            log.Fatalf("ssh.Dial failed: %s", err)
        }
    
        // Setup sshConn (type net.Conn)
        sshConn, err := sshClientConn.Dial("tcp", remoteAddrString)
    
        // Copy localConn.Reader to sshConn.Writer
        go func() {
            _, err = io.Copy(sshConn, localConn)
            if err != nil {
                log.Fatalf("io.Copy failed: %v", err)
            }
        }()
    
        // Copy sshConn.Reader to localConn.Writer
        go func() {
            _, err = io.Copy(localConn, sshConn)
            if err != nil {
                log.Fatalf("io.Copy failed: %v", err)
            }
        }()
    }
    
    func main() {
        // Setup SSH config (type *ssh.ClientConfig)
        config := &ssh.ClientConfig{
            User: username,
            Auth: []ssh.AuthMethod{
                ssh.Password(password),
            },
        }
    
        // Setup localListener (type net.Listener)
        localListener, err := net.Listen("tcp", localAddrString)
        if err != nil {
            log.Fatalf("net.Listen failed: %v", err)
        }
    
        for {
            // Setup localConn (type net.Conn)
            localConn, err := localListener.Accept()
            if err != nil {
                log.Fatalf("listen.Accept failed: %v", err)
            }
            go forward(localConn, config)
        }
    }
    
    0 讨论(0)
  • 2020-12-28 10:20

    I have used your (damick) example code to build a tiny open source tool: SSHTunnel https://github.com/SommerEngineering/SSHTunnel

    Therefore, the code is freely available at GitHub for anyone: Please feel free to use it for learning purposes or for anything else :) I have mentioned your nickname and also linked to this question.

    Best regards, Thorsten.

    0 讨论(0)
  • 2020-12-28 10:29

    I Wrote a tool,Called gosshtool,with this tool,you can easy to create a simple TCP port forward over SSH with Go.https://github.com/scottkiss/gosshtool

    I use this tool implemented a port forward server example project: https://github.com/scottkiss/gooverssh

    0 讨论(0)
提交回复
热议问题