dongpu1331 2018-01-01 19:11
浏览 170
已采纳

Golang SSH到Cisco无线控制器并运行命令

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) >

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: 

How would I go about sending the username when prompted, then repeating that for the password prompt?

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.

Here is my code:

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
}
  • 写回答

1条回答 默认 最新

  • dswe30290 2018-01-02 22:51
    关注

    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 + "
    "))
        }
    
        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
    }
    
    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥15 如何在scanpy上做差异基因和通路富集?
  • ¥20 关于#硬件工程#的问题,请各位专家解答!
  • ¥15 关于#matlab#的问题:期望的系统闭环传递函数为G(s)=wn^2/s^2+2¢wn+wn^2阻尼系数¢=0.707,使系统具有较小的超调量
  • ¥15 FLUENT如何实现在堆积颗粒的上表面加载高斯热源
  • ¥30 截图中的mathematics程序转换成matlab
  • ¥15 动力学代码报错,维度不匹配
  • ¥15 Power query添加列问题
  • ¥50 Kubernetes&Fission&Eleasticsearch
  • ¥15 報錯:Person is not mapped,如何解決?
  • ¥15 c++头文件不能识别CDialog