我正在编写一个CLI,用于在Go 1.9.2中通过SSH通过思科无线控制器配置思科接入点。我正在使用golang.org/x/crypto/ssh
包处理连接到无线控制器。我能够成功SSH到所需的控制器,但在尝试向控制器发送命令时遇到了问题。我知道问题是由于控制器的提示和输出到Stdout。手动连接到控制器时,这是输出:
$ ssh <controller_ip>
(Cisco Controller)
User: username
Password:****************
(Cisco Controller) >
我读过的所有内容以及我遇到的类似问题的所有代码示例都使用bufio
包来创建一个处理器来处理提示/输出。我可以让它部分工作,但程序在用户名提示符之前打印行(Cisco Controller)
后挂起,如下所示:
$ go run main.go
(Cisco Controller)
# infinite blinking cursor
我知道这是因为控制器希望传递用户名。
那么,我的问题是如何正确处理解析输出并向控制器发送命令?我是GO和网络编程的新手,所以任何帮助都会受到赞赏。这是我到目前为止的完整代码:
const (
HOST = "hostname"
)
func main() {
hostKey, err := HostKeyCheck(HOST)
if err != nil {
log.Fatal(err)
}
key, err := ioutil.ReadFile("/Users/user/.ssh/id_rsa")
if err != nil {
log.Fatalf("unable to read private key: %v", err)
}
// Create the Signer for this private key.
signer, err := ssh.ParsePrivateKey(key)
if err != nil {
log.Fatalf("unable to parse private key: %v", err)
}
// Create client config
config := &ssh.ClientConfig{
User: "username",
Auth: []ssh.AuthMethod{
ssh.Password("password"),
// Use the PublicKeys method for remote authentication.
ssh.PublicKeys(signer),
},
HostKeyCallback: ssh.FixedHostKey(hostKey),
Timeout: time.Second * 5,
}
// Connect to the remote server and perform the SSH handshake.
client, err := ssh.Dial("tcp", HOST+":22", config)
if err != nil {
log.Fatalf("unable to connect: %v", err)
}
defer client.Close()
// Create a session
session, err := client.NewSession()
if err != nil {
log.Fatal("Failed to create session: ", err)
}
defer session.Close()
// Error occurs after this point
var b bytes.Buffer
session.Stdout = &b
if err := session.Run("show"); err != nil {
log.Fatalf("%v", err)
}
fmt.Println(b.String())
}
func HostKeyCheck(host string) (ssh.PublicKey, error) {
file, err := os.Open(filepath.Join(os.Getenv("HOME"), ".ssh", "known_hosts"))
if err != nil {
return nil, err
}
defer file.Close()
scanner := bufio.NewScanner(file)
var hostKey ssh.PublicKey
for scanner.Scan() {
fields := strings.Split(scanner.Text(), " ")
if len(fields) != 3 {
continue
}
if strings.Contains(fields[0], host) {
hostKey, _, _, _, err = ssh.ParseAuthorizedKey(scanner.Bytes())
if err != nil {
return nil, errors.New(fmt.Sprintf("error parsing %q: %v", fields[2], err))
}
break
}
}
if hostKey == nil {
return nil, errors.New(fmt.Sprintf("no hostkey for %s", host))
}
return hostKey, nil
}
这是我在运行程序时得到的输出:
$ go run main.go
2017/12/28 14:13:28 ssh: command show failed
exit status 1
答案 0 :(得分:-2)
以下是一个示例:https://github.com/Scalingo/go-ssh-examples/blob/master/client.go
您是否不需要启动新会话来启动命令?
希望它有所帮助。
func connectToHost(user, host string) (*ssh.Client, *ssh.Session, error) {
var pass string
fmt.Print("Password: ")
fmt.Scanf("%s\n", &pass)
sshConfig := &ssh.ClientConfig{
User: user,
Auth: []ssh.AuthMethod{ssh.Password(pass)},
}
sshConfig.HostKeyCallback = ssh.InsecureIgnoreHostKey()
client, err := ssh.Dial("tcp", host, sshConfig)
if err != nil {
return nil, nil, err
}
session, err := client.NewSession()
if err != nil {
client.Close()
return nil, nil, err
}
return client, session, nil
}