Golang SSH到思科无线控制器和运行命令
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Golang SSH到思科无线控制器和运行命令相关的知识,希望对你有一定的参考价值。
我正在尝试使用Go的golang.org/x/crypto/ssh
库通过Go SSH连接思科无线控制器,以编程方式配置接入点。我遇到的问题是在Go中正确解析控制器CLI。例如,这是控制器的典型SSH登录:
$ ssh <controller_ip>
(Cisco Controller)
User: username
Password:****************
(Cisco Controller) >
我试图找出如何在Go中建立SSH会话后发送用户名和密码。到目前为止,我能够成功SSH到控制器,但该程序退出用户名提示符,如下所示:
$ go run main.go
(Cisco Controller)
User:
如何在提示时发送用户名,然后重复密码提示?
没有抛出任何错误或正在给出退出代码,所以我不确定为什么程序会在用户名提示符下立即退出。但即使它没有退出,我仍然不确定如何在控制器的CLI期望时发送用户名和密码。
这是我的代码:
package main
import (
"golang.org/x/crypto/ssh"
"log"
"io/ioutil"
"os"
"strings"
"path/filepath"
"bufio"
"fmt"
"errors"
"time"
)
const (
HOST = "host"
)
func main() {
hostKey, err := checkHostKey(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()
stdin, err := session.StdinPipe()
if err != nil {
log.Fatal(err)
}
stdout, err := session.StdoutPipe()
if err != nil {
log.Fatal(err)
}
modes := ssh.TerminalModes{
ssh.ECHO: 0,
ssh.TTY_OP_ISPEED: 9600,
ssh.TTY_OP_OSPEED: 9600,
}
if err := session.RequestPty("xterm", 0, 200, modes); err != nil {
log.Fatal(err)
}
if err := session.Shell(); err != nil {
log.Fatal(err)
}
buf := make([]byte, 1000)
n, err := stdout.Read(buf) //this reads the ssh terminal welcome message
loadStr := ""
if err == nil {
loadStr = string(buf[:n])
}
for (err == nil) && (!strings.Contains(loadStr, "(Cisco Controller)")) {
n, err = stdout.Read(buf)
loadStr += string(buf[:n])
}
fmt.Println(loadStr)
if _, err := stdin.Write([]byte("show ap summary
")); err != nil {
panic("Failed to run: " + err.Error())
}
}
func checkHostKey(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
}
答案
终于搞定了。这是我的新代码灵感来自this post:
package main
import (
"golang.org/x/crypto/ssh"
"log"
"io/ioutil"
"os"
"strings"
"path/filepath"
"bufio"
"fmt"
"errors"
"time"
)
func main() {
client, err := authenticate("10.4.112.11", "mwalto7", "lion$Tiger$Bear$")
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()
stdin, err := session.StdinPipe()
if err != nil {
log.Fatal(err)
}
session.Stdout = os.Stdout
session.Stderr = os.Stderr
if err := session.Shell(); err != nil {
log.Fatal(err)
}
for _, cmd := range os.Args[1:] {
stdin.Write([]byte(cmd + "
"))
}
stdin.Write([]byte("logout
"))
stdin.Write([]byte("N
"))
session.Wait()
}
func authenticate(host, username, password string) (ssh.Client, error) {
hostKey, err := checkHostKey(host)
if err != nil {
log.Fatal(err)
}
key, err := ioutil.ReadFile(filepath.Join(os.Getenv("HOME"), ".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)
return *client, err
}
func checkHostKey(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
}
以上是关于Golang SSH到思科无线控制器和运行命令的主要内容,如果未能解决你的问题,请参考以下文章