Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
SSH tunnelling in Golang
package main
import (
"log"
"bufio"
"time"
"os"
"fmt"
"io"
"net"
"golang.org/x/crypto/ssh"
"golang.org/x/crypto/ssh/agent"
)
type Endpoint struct {
Host string
Port int
}
func (endpoint *Endpoint) String() string {
return fmt.Sprintf("%s:%d", endpoint.Host, endpoint.Port)
}
type SSHtunnel struct {
Local *Endpoint
Server *Endpoint
Remote *Endpoint
Config *ssh.ClientConfig
}
func (tunnel *SSHtunnel) Start() error {
listener, err := net.Listen("tcp", tunnel.Local.String())
if err != nil {
return err
}
defer listener.Close()
for {
conn, err := listener.Accept()
if err != nil {
return err
}
go tunnel.forward(conn)
}
}
func (tunnel *SSHtunnel) forward(localConn net.Conn) {
serverConn, err := ssh.Dial("tcp", tunnel.Server.String(), tunnel.Config)
if err != nil {
fmt.Printf("Server dial error: %s\n", err)
return
}
remoteConn, err := serverConn.Dial("tcp", tunnel.Remote.String())
if err != nil {
fmt.Printf("Remote dial error: %s\n", err)
return
}
copyConn:=func(writer, reader net.Conn) {
defer writer.Close()
defer reader.Close()
_, err:= io.Copy(writer, reader)
if err != nil {
fmt.Printf("io.Copy error: %s", err)
}
}
go copyConn(localConn, remoteConn)
go copyConn(remoteConn, localConn)
}
func SSHAgent() ssh.AuthMethod {
if sshAgent, err := net.Dial("unix", os.Getenv("SSH_AUTH_SOCK")); err == nil {
return ssh.PublicKeysCallback(agent.NewClient(sshAgent).Signers)
}
return nil
}
func main() {
localEndpoint := &Endpoint{
Host: "localhost",
Port: 9000,
}
serverEndpoint := &Endpoint{
Host: "example.com",
Port: 22,
}
remoteEndpoint := &Endpoint{
Host: "localhost",
Port: 8080,
}
sshConfig := &ssh.ClientConfig{
User: "vcap",
Auth: []ssh.AuthMethod{
SSHAgent(),
},
}
tunnel := &SSHtunnel{
Config: sshConfig,
Local: localEndpoint,
Server: serverEndpoint,
Remote: remoteEndpoint,
}
tunnel.Start()
}
@cvvs

This comment has been minimized.

Copy link

cvvs commented Dec 23, 2015

Svett, thanks for the sample code. Under which license, if any, is this released?

@kevinpostal

This comment has been minimized.

Copy link

kevinpostal commented Nov 21, 2016

This code does not work?

@netmiller

This comment has been minimized.

Copy link

netmiller commented Jan 22, 2017

Works for me: OS X 10.12 -> Ubuntu 16.04 with OpenSSH.
Modified sshConfig/AuthMethod :

sshConfig := &ssh.ClientConfig{
        User: "testusr",
        Auth: []ssh.AuthMethod{ PublicKeyFile("./test_rsa") },
        // Auth: []ssh.AuthMethod{
        //     SSHAgent(),
        // },
    }

Nice work.

@tkandal

This comment has been minimized.

Copy link

tkandal commented Sep 24, 2017

Excuse me, but if one use this code as general ssh-forwarder it will eventually exhaust the connetion-pool,- because it will dial a new ssh-connection every time it accepts a new connection on the local port.
I would instead have tested if it has a ssh-connection already and re-use that one,- and that is a very easy and simple solution.
Also I would have added reader.Close(), writer.Close() in copyConn, and a Close()-method for gracefully shutting down the listener and server-connection.
That said,- thank You very much for the code! I learned that I could use ssh and ssh-forwarding very easily in Go!

@yefriddavid

This comment has been minimized.

Copy link

yefriddavid commented Oct 7, 2019

Excuse me, but if one use this code as general ssh-forwarder it will eventually exhaust the connetion-pool,- because it will dial a new ssh-connection every time it accepts a new connection on the local port.
I would instead have tested if it has a ssh-connection already and re-use that one,- and that is a very easy and simple solution.
Also I would have added reader.Close(), writer.Close() in copyConn, and a Close()-method for gracefully shutting down the listener and server-connection.
That said,- thank You very much for the code! I learned that I could use ssh and ssh-forwarding very easily in Go!

yeah, this was a huge bug for me, now is fixed here elliotchance/sshtunnel#1

@svett

This comment has been minimized.

Copy link
Owner Author

svett commented Oct 14, 2019

I updated the copyConn to close the connections when the function finishes its job. Thanks for the feedback.

@svett

This comment has been minimized.

Copy link
Owner Author

svett commented Oct 14, 2019

Svett, thanks for the sample code. Under which license, if any, is this released?

MIT

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.