forked from elliotchance/sshtunnel
/
ssh_tunnel.go
96 lines (79 loc) 路 1.96 KB
/
ssh_tunnel.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
package sshtunnel
import (
"golang.org/x/crypto/ssh"
"io"
"log"
"net"
)
type SSHTunnel struct {
Local *Endpoint
Server *Endpoint
Remote *Endpoint
Config *ssh.ClientConfig
Log *log.Logger
}
func (tunnel *SSHTunnel) logf(fmt string, args ...interface{}) {
if tunnel.Log != nil {
tunnel.Log.Printf(fmt, args...)
}
}
func (tunnel *SSHTunnel) Start() error {
listener, err := net.Listen("tcp", tunnel.Local.String())
if err != nil {
return err
}
defer listener.Close()
tunnel.Local.Port = listener.Addr().(*net.TCPAddr).Port
for {
conn, err := listener.Accept()
if err != nil {
return err
}
tunnel.logf("accepted connection")
go tunnel.forward(conn)
}
}
func (tunnel *SSHTunnel) forward(localConn net.Conn) {
serverConn, err := ssh.Dial("tcp", tunnel.Server.String(), tunnel.Config)
if err != nil {
tunnel.logf("server dial error: %s", err)
return
}
tunnel.logf("connected to %s (1 of 2)\n", tunnel.Server.String())
remoteConn, err := serverConn.Dial("tcp", tunnel.Remote.String())
if err != nil {
tunnel.logf("remote dial error: %s", err)
return
}
tunnel.logf("connected to %s (2 of 2)\n", tunnel.Remote.String())
copyConn := func(writer, reader net.Conn) {
_, err := io.Copy(writer, reader)
if err != nil {
tunnel.logf("io.Copy error: %s", err)
}
}
go copyConn(localConn, remoteConn)
go copyConn(remoteConn, localConn)
}
func NewSSHTunnel(tunnel string, auth ssh.AuthMethod, destination string) *SSHTunnel {
// A random port will be chosen for us.
localEndpoint := NewEndpoint("localhost:0")
server := NewEndpoint(tunnel)
if server.Port == 0 {
server.Port = 22
}
sshTunnel := &SSHTunnel{
Config: &ssh.ClientConfig{
User: server.User,
Auth: []ssh.AuthMethod{auth},
HostKeyCallback: func(hostname string, remote net.Addr, key ssh.PublicKey) error {
// Always accept key.
return nil
},
},
Local: localEndpoint,
Server: server,
Remote: NewEndpoint(destination),
}
return sshTunnel
}