package sshhop import ( "fmt" "golang.org/x/crypto/ssh" "golang.org/x/crypto/ssh/agent" "log" "net" "os" "sync" "bytes" ) type SSHtunnel struct { Server *Endpoint Remote []string ErrorChans []chan error ServerClient *ssh.Client Config *ssh.ClientConfig ServerConnection *ssh.ServerConfig TargetClients []*ssh.Client sync.Mutex } func (tunnel *SSHtunnel) Start() error { var err error tunnel.ErrorChans = make([]chan error, len(tunnel.Remote)) tunnel.TargetClients = make([]*ssh.Client, 0) tunnel.ServerClient, err = ssh.Dial("tcp", tunnel.Server.String(), tunnel.Config) if err != nil { fmt.Printf("Server dial error: %s\n", err) os.Exit(1) return err } // for i, _ := range tunnel.Remote { conn, err := tunnel.ServerClient.Dial("tcp", tunnel.Remote[i]) if err != nil { return err } ncc, chans, reqs, err := ssh.NewClientConn(conn, tunnel.Remote[i], tunnel.Config) if err != nil { log.Fatalf("New client connection error: %s\n", err) return err } client := ssh.NewClient(ncc, chans, reqs) //Keep clients in array tunnel.TargetClients = append(tunnel.TargetClients, client) //Execute a command //Ideally this would be done in a go routine for concurrency session, _ := client.NewSession() defer session.Close() var stdoutBuf bytes.Buffer session.Stdout = &stdoutBuf session.Run("hostname") log.Printf("Target Hostname: %s", stdoutBuf.String()) } return err } 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) } }