duanjianxiu9400 2017-12-28 05:24
浏览 90

发送SSH命令以配置网络设备

I am writing a CLI for configuring Cisco access points through Cisco wireless controllers over SSH in Go 1.9.2. I am using the golang.org/x/crypto/ssh package to handle connecting to the wireless controllers. I am able to successfully SSH to the desired controller, but I'm running into problems when attempting to send commands to the controller. I know the problem is due to the controller's prompt and output to Stdout. When manually connecting to a controller, this is the output:

$ ssh <controller_ip>


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

Everything I have read and all the code examples I have seen of similar problems use the bufio package to create a reader to deal with the prompts/output. I can get that to partially work, but the program hangs after printing the line (Cisco Controller) before the username prompt, like this:

$ go run main.go


(Cisco Controller)
# infinite blinking cursor

I know this is because the controller is expecting a username to be passed.

My question, then, is how do I correctly handle parsing the output and send commands to the controller? I'm new to GO and network programming in general, so any help is appreciated. Here is my full code so far:

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
}

This is the output I get when running the program:

$ go run main.go
2017/12/28 14:13:28 ssh: command show failed
exit status 1
  • 写回答

1条回答 默认 最新

  • douhong4452 2017-12-29 00:30
    关注

    Here is an example: https://github.com/Scalingo/go-ssh-examples/blob/master/client.go

    Shouldn't you need to start a new session to initiate commands?

    Hope it helps.

    func connectToHost(user, host string) (*ssh.Client, *ssh.Session, error) {
        var pass string
        fmt.Print("Password: ")
        fmt.Scanf("%s
    ", &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
    }
    
    评论

报告相同问题?

悬赏问题

  • ¥15 多电路系统共用电源的串扰问题
  • ¥15 shape_predictor_68_face_landmarks.dat
  • ¥15 slam rangenet++配置
  • ¥15 有没有研究水声通信方面的帮我改俩matlab代码
  • ¥15 对于相关问题的求解与代码
  • ¥15 ubuntu子系统密码忘记
  • ¥15 信号傅里叶变换在matlab上遇到的小问题请求帮助
  • ¥15 保护模式-系统加载-段寄存器
  • ¥15 电脑桌面设定一个区域禁止鼠标操作
  • ¥15 求NPF226060磁芯的详细资料