-
Star
(102)
You must be signed in to star a gist -
Fork
(32)
You must be signed in to fork a gist
-
-
Save iamralch/5d695dcc4cc6ad5dd275 to your computer and use it in GitHub Desktop.
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() | |
} |
This code does not work?
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.
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!
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
I updated the copyConn
to close the connections when the function finishes its job. Thanks for the feedback.
Svett, thanks for the sample code. Under which license, if any, is this released?
MIT
work for me
Svett, thanks for the sample code. Under which license, if any, is this released?