-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathtunnel.go
executable file
·101 lines (83 loc) · 2.45 KB
/
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
97
98
99
100
101
package main
import (
"io"
"log"
"net"
"github.com/jedib0t/go-pretty/text"
"golang.org/x/crypto/ssh"
)
type Tunnel struct {
Alias string `yaml:"alias"`
Source string `yaml:"source"`
Auth struct {
User string `yaml:"user"`
Password string `yaml:"password"`
Key string `yaml:"key"`
} `yaml:"auth"`
Remote string `yaml:"remote"`
Destination string `yaml:"destination"`
Disabled bool `yaml:"disabled"`
Status string
ClientConfig *ssh.ClientConfig
Listener net.Listener
}
func (tunnel *Tunnel) Spawn() error {
if tunnel.Listener != nil {
tunnel.Listener.Close()
}
sshConn, err := ssh.Dial("tcp", tunnel.Remote, tunnel.ClientConfig)
if err != nil {
log.Printf("An error occurred establishing the SSH connection with %s. Error: %s\r\n", tunnel.Alias, err)
tunnel.Disable()
return err
}
// Start accepting connections
listener, err := net.Listen("tcp", tunnel.Source)
tunnel.Listener = listener
if err != nil {
log.Printf("An error occurred while connecting to %s. Error: %s\r\n", tunnel.Alias, err)
return err
}
defer listener.Close()
tunnel.Status = text.FgGreen.Sprint("ONLINE")
log.Printf("Tunnel %s active and listening on %s => %s => %s\r\n", tunnel.Alias, tunnel.Source, tunnel.Remote, tunnel.Destination)
for tunnel.Disabled == false {
conn, err := listener.Accept()
if tunnel.Disabled == true {
return nil
}
if err != nil && err != io.EOF {
log.Printf("An error occurred while accepting a connection on %s. Error: %s\r\n", tunnel.Alias, err)
return err
}
go tunnel.Flow(conn, sshConn)
}
return nil
}
func (tunnel *Tunnel) Flow(conn net.Conn, sshConn *ssh.Client) error {
destConn, err := sshConn.Dial("tcp", tunnel.Destination)
if err != nil {
log.Printf("An error occurred establishing the SSH connection with the destination of %s. Error: %s\r\n", tunnel.Alias, err)
tunnel.Disable()
return err
}
go tunnel.ProxyData(conn, destConn)
go tunnel.ProxyData(destConn, conn)
return nil
}
func (tunnel *Tunnel) ProxyData(legA, legB net.Conn) {
_, err := io.Copy(legA, legB)
if err != nil {
log.Printf("An error occurred while forwarding connections between endpoints on %s. Error: %s\r\n", tunnel.Alias, err)
}
}
func (tunnel *Tunnel) Enable() {
tunnel.Status = text.FgYellow.Sprint("CONNECTING")
tunnel.Disabled = false
go tunnel.Spawn()
}
func (tunnel *Tunnel) Disable() {
tunnel.Status = text.FgRed.Sprint("OFFLINE")
tunnel.Disabled = true
tunnel.Listener.Close()
}