前にGolangでsshクライアントを作る際、どうにも制御キーをうまく渡せずに致し方なくsshコマンドを実行させるような処理を書いてたのだけど、ちょっと前に見かけたsshwというツールのソースを見てたところ、sshコマンドを実行せずにそのあたりが正常に動いていた。 で、なんでだろうと調べて見たところ、どうやら ssh/terminal.MakeRaw() 等を使ってうまくそのあたりを実装していたようだ。

こちらにもソースを上げてるのだけど、以下サンプル。

term_ssh.go
package main import ( "fmt" "os" "golang.org/x/crypto/ssh" "golang.org/x/crypto/ssh/terminal" ) func main() { host := "target.host.local" port := "22" user := "user" pass := "password" // Create sshClientConfig sshConfig := &ssh.ClientConfig{ User: user, Auth: []ssh.AuthMethod{ ssh.Password(pass), }, HostKeyCallback: ssh.InsecureIgnoreHostKey(), } // SSH connect. client, err := ssh.Dial("tcp", host+":"+port, sshConfig) // Create Session session, err := client.NewSession() defer session.Close() // キー入力を接続先が認識できる形式に変換する(ここがキモ) fd := int(os.Stdin.Fd()) state, err := terminal.MakeRaw(fd) if err != nil { fmt.Println(err) } defer terminal.Restore(fd, state) // ターミナルサイズの取得 w, h, err := terminal.GetSize(fd) if err != nil { fmt.Println(err) } modes := ssh.TerminalModes{ ssh.ECHO: 1, ssh.TTY_OP_ISPEED: 14400, ssh.TTY_OP_OSPEED: 14400, } err = session.RequestPty("xterm", h, w, modes) if err != nil { fmt.Println(err) } session.Stdout = os.Stdout session.Stderr = os.Stderr session.Stdin = os.Stdin err = session.Shell() if err != nil { fmt.Println(err) } err = session.Wait() if err != nil { fmt.Println(err) } }

Golang 1.08,1.10で確認したが、上記の記述で上下キーやタブでの補完、password入力時の入力内容の非表示に対応してる。 自前で作ってるツールについても、今現在はsshコマンドを実行してしまってるので修正しようかな。