Version 1.2.0

This commit is contained in:
Thorsten Sommer committed 2015-09-28 15:28:11 +02:00
1 parent aab3524082
commit a16b99af6e
11 files changed
+257 -246

No files matched your search

+28
View File
@@ -0,0 +1,28 @@
package Tunnel
import (
"golang.org/x/crypto/ssh"
"log"
"net"
)
func AcceptClients(connection net.Listener, config *ssh.ClientConfig, serverAddrString, remoteAddrString string) {
// Endless loop
for {
// Accept (another) client connection:
if localConn, err := connection.Accept(); err != nil {
// Fail
log.Printf("Accepting a client failed: %s\n", err.Error())
} else {
// Success
log.Println(`Client accepted.`)
// Start the forwarding:
go forward(localConn, config, serverAddrString, remoteAddrString)
}
}
}
+7
View File
@@ -0,0 +1,7 @@
package Tunnel
const (
maxRetriesLocal = 16 // How many retries are allowed to create the local end-point?
maxRetriesRemote = 16 // How many retries are allowed to create the remote end-point?
maxRetriesServer = 16 // How many retries are allowed to create the SSH server's connection?
)
+35
View File
@@ -0,0 +1,35 @@
package Tunnel
import (
"log"
"net"
"time"
)
func CreateLocalEndPoint(localAddrString string) (localListener net.Listener) {
// Loop for the necessary retries
for {
// Try to create the local end-point
if localListenerObj, err := net.Listen(`tcp`, localAddrString); err != nil {
// It was not able to create the end-point:
currentRetriesLocal++
log.Printf("Was not able to create the local end-point %s: %s\n", localAddrString, err.Error())
// Is another retry possible?
if currentRetriesLocal < maxRetriesLocal {
log.Println(`Retry...`)
time.Sleep(1 * time.Second)
} else {
log.Fatalln(`No more retries for the local end-point: ` + localAddrString) // => Exit
}
} else {
// Success!
log.Println(`Listen to local address ` + localAddrString)
localListener = localListenerObj
return
}
}
}
+97
View File
@@ -0,0 +1,97 @@
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
}
}
}
+35
View File
@@ -0,0 +1,35 @@
package Tunnel
import (
"log"
)
// Another auth. method.
func KeyboardInteractiveChallenge(user, instruction string, questions []string, echos []bool) (answers []string, err error) {
// Log all the provided data:
log.Println(`User: ` + user)
log.Println(`Instruction: ` + instruction)
log.Println(`Questions:`)
for q := range questions {
log.Println(q)
}
// How many questions are asked?
countQuestions := len(questions)
if countQuestions == 1 {
// We expect that in this case (only one question is asked), that the server want to know the password ;-)
answers = make([]string, countQuestions, countQuestions)
answers[0] = callbackPassword
} else if countQuestions > 1 {
// After logging, this call will exit the whole program:
log.Fatalln(`The SSH server is asking multiple questions! This program cannot handle this case.`)
}
err = nil
return
}
+10
View File
@@ -0,0 +1,10 @@
package Tunnel
// Just a callback function for the password request.
func PasswordCallback() (string, error) {
return callbackPassword, nil
}
func SetPassword4Callback(password string) {
callbackPassword = password
}
+27
View File
@@ -0,0 +1,27 @@
package Tunnel
import (
"io"
"log"
)
// The transfer function.
func transfer(fromReader io.Reader, toWriter io.Writer, name string, quit chan bool) {
log.Printf("%s transfer started.", name)
// This call blocks until the client or service will close the connection.
// Therefore, this call maybe takes hours or even longer. Concern, may this
// program will be used to connect multiple servers to make e.g. a database
// available...
if _, err := io.Copy(toWriter, fromReader); err != nil {
// In this case, we do not fail the whole program: Regarding how the client
// or the service was e.g. shut down, the error may only means 'client has been closed'.
log.Printf("%s transfer failed: %s\n", name, err.Error())
} else {
log.Printf("%s transfer closed.\n", name)
}
quit <- true
}
+6
View File
@@ -0,0 +1,6 @@
package Tunnel
var (
currentRetriesLocal = 0 // Check how many retries are occur for creating the local end-point
callbackPassword = ``
)