【问题标题】:Run multiple commands on Cisco using golang crypto/ssh使用 golang crypto/ssh 在 Cisco 上运行多个命令
【发布时间】:2016-02-19 19:11:32
【问题描述】:

我将以下代码拼凑在一起,可以让我向 Cisco 机器的 ssh 控制台发送读写操作,但我目前不确定如何在同一个会话中发送多个命令。

我将整个程序包括在内,以便将服务器作为其他人将来尝试相同事情的起点,我找不到专门针对 GolangCisco 的工作示例。

package main

import (
    "fmt"
    "io"
    "io/ioutil"
    "net"
    "os"
    //"strings"

    "golang.org/x/crypto/ssh"
    "golang.org/x/crypto/ssh/agent"
)

type SSHCommand struct {
    Stdin  io.Reader
    Stdout io.Writer
    Stderr io.Writer
}

type SSHClient struct {
    Config *ssh.ClientConfig
    Host   string
    Port   int
}

func (client *SSHClient) RunCommand(cmd *SSHCommand) error {
    var (
        session *ssh.Session
        err     error
    )

    if session, err = client.newSession(); err != nil {
        return err
    }
    defer session.Close()

    if err = client.prepareCommand(session, cmd); err != nil {
        return err
    }

    err = session.Run("en\r")


    return err
}

func (client *SSHClient) prepareCommand(session *ssh.Session, cmd *SSHCommand) error {

    if cmd.Stdin != nil {
        stdin, err := session.StdinPipe()
        if err != nil {
            return fmt.Errorf("Unable to setup stdin for session: %v", err)
        }
        go io.Copy(stdin, cmd.Stdin)
    }

    if cmd.Stdout != nil {
        stdout, err := session.StdoutPipe()
        if err != nil {
            return fmt.Errorf("Unable to setup stdout for session: %v", err)
        }
        go io.Copy(cmd.Stdout, stdout)
    }

    if cmd.Stderr != nil {
        stderr, err := session.StderrPipe()
        if err != nil {
            return fmt.Errorf("Unable to setup stderr for session: %v", err)
        }
        go io.Copy(cmd.Stderr, stderr)
    }

    return nil
}

func (client *SSHClient) newSession() (*ssh.Session, error) {
    connection, err := ssh.Dial("tcp", fmt.Sprintf("%s:%d", client.Host, client.Port), client.Config)
    if err != nil {
        return nil, fmt.Errorf("Failed to dial: %s", err)
    }

    session, err := connection.NewSession()
    if err != nil {
        return nil, fmt.Errorf("Failed to create session: %s", err)
    }

    modes := ssh.TerminalModes{
        // ssh.ECHO:          0,     // disable echoing
        ssh.TTY_OP_ISPEED: 14400, // input speed = 14.4kbaud
        ssh.TTY_OP_OSPEED: 14400, // output speed = 14.4kbaud
    }

    if err := session.RequestPty("xterm", 0, 200, modes); err != nil {
        session.Close()
        return nil, fmt.Errorf("request for pseudo terminal failed: %s", err)
    }

    return session, nil
}

func SSHAgent() ssh.AuthMethod {
    if sshAgent, err := net.Dial("unix", os.Getenv("SSH_AUTH_SOCK")); err == nil {
        return ssh.PublicKeysCallback(agent.NewClient(sshAgent).Signers)
    }
    return nil
}

func main() {

    sshConfig := &ssh.ClientConfig{
        User: "admin",
        Auth: []ssh.AuthMethod{
            ssh.Password("password"),
        },
    }
    sshConfig.Ciphers = []string{"aes128-cbc"}

    client := &SSHClient{
        Config: sshConfig,
        Host:   "10.10.10.10",
        Port:   22,
    }

    cmd := &SSHCommand{
        Stdin:  os.Stdin,
        Stdout: os.Stdout,
        Stderr: os.Stderr,
    }

    fmt.Printf("Running commands\n")
    if err := client.RunCommand(cmd); err != nil {
        fmt.Fprintf(os.Stderr, "command run error: %s\n", err)
        os.Exit(1)
    }

}

如您所见,我在 session.Run() 中硬编码了“en”命令。 如果我通过简单地添加一个命令:

err = session.Run("en\r")
err = session.Run("password\r")

它被忽略了。阅读https://godoc.org/golang.org/x/crypto/ssh#Session.Shell 告诉我这是设计使然。所以我的问题是:如何设置一些东西,让我输入命令、读取输出、解析它并根据该输出输入更多命令?

一旦我解决了这个问题,我计划解析路由表并发出命令作为响应。 IE,如果缺少路由X,添加它。

【问题讨论】:

  • 为什么不能打开多个会话,每个命令一个?
  • 我的印象是新会话不会保持上下文。即,我需要在同一个“线程”中以特定顺序输入一组特定的命令,即:命令二取决于命令一。我将上下文等同于会话,这是不正确的吗?
  • 一个 ssh 会话只能运行一个命令。这就是 ssh 协议的工作原理。保持“状态”的唯一方法是打开一个shell(这种情况下需要交互解析cli),或者执行一个脚本(只能在脚本执行过程中保持状态)。

标签: go ssh


【解决方案1】:

这可能不是惯用的,我还在学习。我前段时间写了这个来关闭备份,但我认为它可以满足您的要求:

https://github.com/plod/goSwitchBackup/blob/master/main.go

func writeBuff(command string, sshIn io.WriteCloser) (int, error) {
    returnCode, err := sshIn.Write([]byte(command + "\r"))
    return returnCode, err
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-10-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-07-08
    • 2015-10-22
    相关资源
    最近更新 更多