Golang SSH到Cisco无线控制器并运行命令 [英] Golang SSH to Cisco Wireless Controller and Run Commands

查看:82
本文介绍了Golang SSH到Cisco无线控制器并运行命令的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试使用Go的golang.org/x/crypto/ssh库通过Go SSH到Cisco无线控制器,以编程方式配置访问点.我遇到的问题是正确解析Go中的控制器CLI.例如,这是到控制器的典型SSH登录:

I am trying to SSH to a Cisco wireless controller through Go, using Go's golang.org/x/crypto/ssh library, to programmatically configure access points. The problem I'm running into is correctly parsing the controller CLI in Go. For example, this is the typical SSH login to the controller:

$ ssh <controller_ip>


(Cisco Controller)
User: username
Password:****************
(Cisco Controller) >

在Go中建立SSH会话后,我试图弄清楚如何发送用户名和密码.到目前为止,我已经能够成功通过SSH到控制器,但是程序会在用户名提示符下退出,如下所示:

I am trying to figure out how to send the username and then the password after the SSH session is established in Go. So far, I am able to successfully SSH to the controller, but the program exits at the username prompt, like this:

$ go run main.go 


(Cisco Controller) 
User: 

如何在提示时发送用户名,然后在提示输入密码时重复输入用户名?

没有引发错误或给出了退出代码,所以我不确定为什么程序会在用户名提示符下立即退出.但是,即使不是那样,我仍然不确定在控制器的CLI期望时如何发送用户名和密码.

No errors are being thrown or exit codes are being given, so I'm not sure why the program is exiting immediately at the username prompt. But Even if it wasn't exiting that way, I'm still unsure of how to send the username and password when the controller's CLI is expecting it.

这是我的代码:

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\r")); 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
}

推荐答案

最后使它正常工作.这是我的新代码,灵感来自这篇文章:

Finally got it working. Here is my new code inspired by 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 + "\n"))
    }

    stdin.Write([]byte("logout\n"))
    stdin.Write([]byte("N\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到Cisco无线控制器并运行命令的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆