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 树莓派与pix飞控通信
  • ¥15 自动转发微信群信息到另外一个微信群
  • ¥15 outlook无法配置成功
  • ¥30 这是哪个作者做的宝宝起名网站
  • ¥60 版本过低apk如何修改可以兼容新的安卓系统
  • ¥25 由IPR导致的DRIVER_POWER_STATE_FAILURE蓝屏
  • ¥50 有数据,怎么建立模型求影响全要素生产率的因素
  • ¥50 有数据,怎么用matlab求全要素生产率
  • ¥15 TI的insta-spin例程
  • ¥15 完成下列问题完成下列问题