diff --git a/tunnel.go b/tunnel.go index 5e384eb..ba171ae 100644 --- a/tunnel.go +++ b/tunnel.go @@ -1,158 +1,160 @@ package sshtunnel import ( "net" "golang.org/x/crypto/ssh" "golang.org/x/crypto/ssh/agent" "fmt" "io" "os" "log" "sync" "time" ) type SSHtunnel struct { Local []Endpoint Server *Endpoint Remote []Endpoint ErrorChans []chan error ServerClient *ssh.Client Config *ssh.ClientConfig ServerConnection *ssh.ServerConfig ExecPath string sync.Mutex } func (tunnel *SSHtunnel) Listen(localE Endpoint, remoteE Endpoint, errorChan chan error) { log.Printf("LocalEndpoint: %v, RemoteEndpoint: %v", localE, remoteE) listener, err := net.Listen("tcp", localE.String()) if err != nil { return } for { conn, err := listener.Accept() if err != nil { log.Println("Cannot listen.") errorChan <- err } defer listener.Close() log.Printf("Localhost listen %s, Remote Connection: %s \n", localE.String(), remoteE.String()) go tunnel.forward(conn, remoteE) } } func (tunnel *SSHtunnel) Start() error { var err error tunnel.ErrorChans = make([]chan error, len(tunnel.Local)) // tunnel.ServerClient, err = ssh.Dial("tcp", tunnel.Server.String(), tunnel.Config) if err != nil { fmt.Printf("Server dial error: %s\n", err) //log.Println("Sever dial error occurred. No Internet connection. Program exited.") // if err == "ssh: handshake failed: ssh: unable to authenticate, attempted methods [password none], no supported methods remain" { // fmt.Println(" Incorrect Password entered.") os.Exit(1) return err } //Keep alive done := make(chan bool) go tunnel.keepalive(done) // for i, _ := range tunnel.Local { //defer listener.Close() log.Printf("Main - LocalEndpoint: %v, RemoteEndpoint: %v", tunnel.Local[i], tunnel.Remote[i]) go tunnel.Listen(tunnel.Local[i], tunnel.Remote[i], tunnel.ErrorChans[i]) } for { for _, c := range tunnel.ErrorChans { select { case msg := <-c: log.Printf("\n in tunnel.errorschans : %v", msg) // case msg2:= <- done: // log.Printf("%v", msg2) // os.Exit(1) default: //fmt.Println("No message received") } } time.Sleep(time.Second * 1) - //TODO run ExecPath } return err } func (tunnel *SSHtunnel) keepalive(done chan bool) { for { - + var session *ssh.Session // Create a session. It is one session per command. session, err := tunnel.ServerClient.NewSession() if err != nil { log.Print("Unable to open keep alive session.") } else { log.Print("Keep alive session opened.") } - session.Close() select { case message := <-done: if message == true { break } default: } + + if session != nil { + session.Close() + } + time.Sleep(20000 * time.Millisecond) } } -//TODO refactor to accept remoteEndpoint func (tunnel *SSHtunnel) forward(localConn net.Conn, remoteEndpoint Endpoint) { var err error log.Printf("Connect with client. %s \n", remoteEndpoint.String()) remoteConn, err := tunnel.ServerClient.Dial("tcp", remoteEndpoint.String()) if err != nil { fmt.Printf("Remote dial error: %s\n", err) log.Println("Remote dial error occurred. Trying to establish a new server connection.") tunnel.ServerClient, err = ssh.Dial("tcp", tunnel.Server.String(), tunnel.Config) return } log.Printf("Remote connection: %v", remoteConn) copyConn := func(writer, reader net.Conn) { _, err := io.Copy(writer, reader) if err != nil { log.Printf("%s io.Copy error: %s \n", remoteEndpoint.String(), err) } } go copyConn(localConn, remoteConn) go copyConn(remoteConn, localConn) } func SSHAgent() ssh.AuthMethod { if sshAgent, err := net.Dial("unix", os.Getenv("SSH_AUTH_SOCK")); err == nil { return ssh.PublicKeysCallback(agent.NewClient(sshAgent).Signers) } return nil } func check(e error) { if e != nil { panic(e) } }