SSHTunnel/Tunnel/Forward.go

98 lines
2.5 KiB
Go
Raw Permalink Normal View History

2015-09-28 13:28:11 +00:00
package Tunnel
import (
"golang.org/x/crypto/ssh"
"log"
"net"
"time"
)
func forward(localConn net.Conn, config *ssh.ClientConfig, serverAddrString, remoteAddrString string) {
defer localConn.Close()
currentRetriesServer := 0
currentRetriesRemote := 0
var sshClientConnection *ssh.Client = nil
// Loop for retries:
for {
// Try to connect to the SSH server:
if sshClientConn, err := ssh.Dial(`tcp`, serverAddrString, config); err != nil {
// Failed:
currentRetriesServer++
log.Printf("Was not able to connect with the SSH server %s: %s\n", serverAddrString, err.Error())
// Is a retry alowed?
if currentRetriesServer < maxRetriesServer {
log.Println(`Retry...`)
time.Sleep(1 * time.Second)
} else {
// After the return, this thread is closed down. The client can try it again...
log.Println(`No more retries for connecting the SSH server.`)
return
}
} else {
// Success:
log.Println(`Connected to the SSH server ` + serverAddrString)
sshClientConnection = sshClientConn
defer sshClientConnection.Close()
break
}
}
// Loop for retries:
for {
// Try to create the remote end-point:
if sshConn, err := sshClientConnection.Dial(`tcp`, remoteAddrString); err != nil {
// Failed:
currentRetriesRemote++
log.Printf("Was not able to create the remote end-point %s: %s\n", remoteAddrString, err.Error())
// Is another retry allowed?
if currentRetriesRemote < maxRetriesRemote {
log.Println(`Retry...`)
time.Sleep(1 * time.Second)
} else {
// After the return, this thread is closed down. The client can try it again...
log.Println(`No more retries for connecting the remote end-point.`)
return
}
} else {
// Fine, the connections are up and ready :-)
log.Printf("The remote end-point %s is connected.\n", remoteAddrString)
defer sshConn.Close()
// To be able to close down both transfer threads, we create a channel:
quit := make(chan bool)
// Create the transfers to/from both sides (two new threads are created for this):
go transfer(localConn, sshConn, `Local => Remote`, quit)
go transfer(sshConn, localConn, `Remote => Local`, quit)
// Wait and look if any of the two transfer theads are down:
isRunning := true
for isRunning {
select {
case <-quit:
log.Println(`At least one transfer was stopped.`)
isRunning = false
break
}
}
// Now, close all the channels and therefore, force the other / second thread to go down:
log.Println(`Close now all connections.`)
return
}
}
}