Goで golang.org/x/crypto/ssh
を使えばSSHクライアントが実装できるという事なので偉大なる先人様達のコードを参考(コピぺ)にしながら実装してみたメモです。
目的
GoでSSH接続してコマンド操作できるクライアントツールを作ってみる
ドキュメント
https://godoc.org/golang.org/x/crypto/ssh
ツール
ソース
main.go
package main
import (
"fmt"
"io/ioutil"
"log"
"os"
"syscall"
"github.com/urfave/cli"
"golang.org/x/crypto/ssh"
"golang.org/x/crypto/ssh/terminal"
)
func doMain(c *cli.Context) {
ce := func(err error, msg string) {
if err != nil {
log.Fatalf("%s error: %v", msg, err)
}
}
// check private key or password.
var passwd string
auth := []ssh.AuthMethod{}
if c.String("key") != "" {
key, err := ioutil.ReadFile(c.String("key"))
ce(err, "private key")
signer, err := ssh.ParsePrivateKey(key)
ce(err, "signer")
auth = append(auth, ssh.PublicKeys(signer))
} else {
// check password.
if c.String("password") != "" {
passwd = c.String("password")
} else {
fmt.Print("Password: ")
inPasswd, err := terminal.ReadPassword(int(syscall.Stdin))
ce(err, "password")
passwd = string(inPasswd)
}
auth = append(auth, ssh.Password(passwd))
}
// set ssh config.
sshConfig := &ssh.ClientConfig{
User: c.String("user"),
Auth: auth,
HostKeyCallback: ssh.InsecureIgnoreHostKey(),
}
// SSH connect.
client, err := ssh.Dial("tcp", c.String("host")+":"+c.String("port"), sshConfig)
ce(err, "dial")
session, err := client.NewSession()
ce(err, "new session")
defer session.Close()
session.Stdout = os.Stdout
session.Stderr = os.Stderr
session.Stdin = os.Stdin
modes := ssh.TerminalModes{
ssh.ECHO: 0,
ssh.TTY_OP_ISPEED: 14400,
ssh.TTY_OP_OSPEED: 14400,
}
term := os.Getenv("TERM")
err = session.RequestPty(term, 25, 80, modes)
ce(err, "request pty")
err = session.Shell()
ce(err, "start shell")
err = session.Wait()
ce(err, "return")
}
func main() {
app := cli.NewApp()
app.Name = "sshClient"
app.Usage = "SSh Client Tool"
app.Flags = []cli.Flag{
cli.StringFlag{
Name: "user, u",
Value: "root",
Usage: "SSH login user",
},
cli.StringFlag{
Name: "password, p",
Usage: "SSH login user password",
},
cli.StringFlag{
Name: "host",
Value: "localhost",
Usage: "SSH connect host",
},
cli.StringFlag{
Name: "port",
Value: "22",
Usage: "SSH connect port",
},
cli.StringFlag{
Name: "key, k",
Usage: "SSH private key",
},
}
app.Action = doMain
app.Run(os.Args)
}
使ってみる
パスワード認証
[root@localhost hoge5]# go run main.go --host 192.168.0.233
Password:
Last login: Mon Jan 22 20:37:54 2018 from 192.168.0.231
[root@localhost ~]# ls
anaconda-ks.cfg
[root@localhost ~]# exit
ログアウト
鍵認証
[root@localhost hoge5]# go run main.go --host 192.168.0.233 --key ../../id_rsa
Last login: Mon Jan 22 20:58:42 2018 from 192.168.0.231
[root@localhost ~]# ls
anaconda-ks.cfg
[root@localhost ~]# exit
ログアウト
課題
やりたいことのほとんどが出来ましたが、クライアントの標準入力を接続先へ送信しているので入力でタブ補完が効かない。。。