Golangでターミナル接続できるsshクライアントコマンドを作成する(制御キー対応)
Pocket

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

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

Sponsored Links

■ 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コマンドを実行してしまってるので修正しようかな。

 

Pocket

Written by blacknon

インフラエンジニア(…のつもり)。 仕事で使うならクライアントはWindowsよりはUNIXの方が好き。 大体いつも眠い。

Leave a Comment

メールアドレスが公開されることはありません。

*