diff --git a/Forward.go b/Forward.go new file mode 100644 index 0000000..a21a78f --- /dev/null +++ b/Forward.go @@ -0,0 +1,23 @@ +package main + +import ( + "golang.org/x/crypto/ssh" + "log" + "net" +) + +func forward(localConn net.Conn, config *ssh.ClientConfig) { + + sshClientConn, err := ssh.Dial("tcp", serverAddrString, config) + if err != nil { + log.Printf("ssh.Dial failed: %s\n", err) + return + } + + if sshConn, err := sshClientConn.Dial("tcp", remoteAddrString); err != nil { + log.Println(`Was not able to create the tunnel: ` + err.Error()) + } else { + go transfer(localConn, sshConn) + go transfer(sshConn, localConn) + } +} diff --git a/KeyboardInteractiveChallenge.go b/KeyboardInteractiveChallenge.go new file mode 100644 index 0000000..7292e53 --- /dev/null +++ b/KeyboardInteractiveChallenge.go @@ -0,0 +1,25 @@ +package main + +import ( + "log" +) + +func keyboardInteractiveChallenge(user, instruction string, questions []string, echos []bool) (answers []string, err error) { + + log.Println(`User: ` + user) + log.Println(`Instruction: ` + instruction) + log.Println(`Questions:`) + for q := range questions { + log.Println(q) + } + + countQuestions := len(questions) + answers = make([]string, countQuestions, countQuestions) + + if countQuestions > 0 { + answers[0] = password + } + + err = nil + return +} diff --git a/Main.go b/Main.go new file mode 100644 index 0000000..961d9f3 --- /dev/null +++ b/Main.go @@ -0,0 +1,37 @@ +package main + +import ( + "golang.org/x/crypto/ssh" + "log" + "net" +) + +func main() { + + readFlags() + config := &ssh.ClientConfig{ + User: username, + Auth: []ssh.AuthMethod{ + ssh.Password(password), + ssh.PasswordCallback(passwordCallback), + ssh.KeyboardInteractive(keyboardInteractiveChallenge), + }, + } + + localListener, err := net.Listen(`tcp`, localAddrString) + if err != nil { + log.Printf("net.Listen failed: %v\n", err) + } else { + log.Println(`Listen to local address.`) + } + + for { + localConn, err := localListener.Accept() + if err != nil { + log.Printf("listen.Accept failed: %v\n", err) + } else { + log.Println(`Accepted a client.`) + go forward(localConn, config) + } + } +} diff --git a/PasswordCallback.go b/PasswordCallback.go new file mode 100644 index 0000000..f7bef9d --- /dev/null +++ b/PasswordCallback.go @@ -0,0 +1,5 @@ +package main + +func passwordCallback() (string, error) { + return password, nil +} diff --git a/ReadFlags.go b/ReadFlags.go new file mode 100644 index 0000000..453527d --- /dev/null +++ b/ReadFlags.go @@ -0,0 +1,14 @@ +package main + +import ( + "flag" +) + +func readFlags() { + flag.StringVar(&serverAddrString, `server`, `127.0.0.1:22`, `The (remote) SSH server, e.g. 'my.host.com', 'my.host.com:22', '127.0.0.1:22', 'localhost:22'.`) + flag.StringVar(&localAddrString, `local`, `127.0.0.1:50000`, `The local end-point of the tunnel, e.g. '127.0.0.1:50000', 'localhost:50000'.`) + flag.StringVar(&remoteAddrString, `remote`, `127.0.0.1:27017`, `The remote side end-point (e.g. on the machine with the SSH server), e.g. a MongoDB (port 27017) '127.0.0.1:27017', a web server '127.0.0.1:80'`) + flag.StringVar(&username, `user`, `username`, `The user's name for the SSD server.`) + flag.StringVar(&password, `pwd`, `password`, `The user's password for the SSD server.`) + flag.Parse() +} diff --git a/Transfer.go b/Transfer.go new file mode 100644 index 0000000..e5f9912 --- /dev/null +++ b/Transfer.go @@ -0,0 +1,15 @@ +package main + +import ( + "io" + "log" +) + +func transfer(fromReader io.Reader, toWriter io.Writer) { + + if _, err := io.Copy(toWriter, fromReader); err != nil { + log.Printf("io.Copy failed: %v\n", err) + } else { + log.Println(`Transfer closed.`) + } +} diff --git a/Variables.go b/Variables.go new file mode 100644 index 0000000..9bb1c67 --- /dev/null +++ b/Variables.go @@ -0,0 +1,9 @@ +package main + +var ( + username = "name" + password = "pwd" + serverAddrString = "server:22" + localAddrString = "localhost:53001" + remoteAddrString = "localhost:27017" +)