I am trying to start an interactive SSH session with a remote computer using Golang. I was able to get that without any problems, but the pseudo terminal doesn't seem to be capturing all of the keyboard i/o correctly.
For example, if I run a regular SSH command like,
ssh -i ~/.ssh/some-key.pem username@1.1.1.1
I can exit with a simple Ctrl+d
, but for some reason when I run the interactive shell started with Golang it's not working and only prints the actual key characters ^D
. Same goes for trying to use the arrow keys. If I run a Ctrl+c
it exits the original Golang process and kills the interactive shell rather than executing on the remote machine.
Below is my code for setting up the shell,
func StartInteractiveShell(sshConfig *ssh.ClientConfig, network string, host string, port string) error {
var (
session *ssh.Session
conn *ssh.Client
err error
)
if conn, err = getSshConnection(sshConfig, network, host, port); err != nil {
fmt.Printf("Failed to dial: %s", err)
return err
}
if session, err = getSshSession(conn); err != nil {
fmt.Printf("Failed to create session: %s", err)
return err
}
defer session.Close()
if err = setupPty(session); err != nil {
fmt.Printf("Failed to set up pseudo terminal: %s", err)
return err
}
session.Stdout = os.Stdout
session.Stdin = os.Stdin
session.Stderr = os.Stderr
if err = session.Shell(); err != nil {
fmt.Printf("Failed to start interactive shell: %s", err)
return err
}
return session.Wait()
}
func getSshConnection(config *ssh.ClientConfig, network string, host string, port string) (*ssh.Client, error) {
addr := host + ":" + port
return ssh.Dial(network, addr, config)
}
func getSshSession(clientConnection *ssh.Client) (*ssh.Session, error) {
return clientConnection.NewSession()
}
// pty = pseudo terminal
func setupPty(session *ssh.Session) error {
modes := ssh.TerminalModes{
ssh.ECHO: 0, // disable echoing
ssh.TTY_OP_ISPEED: 14400, // input speed = 14.4kbaud
ssh.TTY_OP_OSPEED: 14400, // output speed = 14.4kbaud
}
if err := session.RequestPty("xterm", 80, 40, modes); err != nil {
session.Close()
fmt.Printf("request for pseudo terminal failed: %s", err)
return err
}
return nil
}
Am I missing something there?