go - 使用 golang crypto/ssh 在 Cisco 上运行多个命令

标签 go ssh

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

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

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,请添加它。

最佳答案

这可能不是地道的go,我还在学习中。我刚才写了这篇文章来关闭交换机的备份,但我认为它可以满足您的要求:

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
}

关于go - 使用 golang crypto/ssh 在 Cisco 上运行多个命令,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35513125/

相关文章:

go - 我是否正确关闭了这个功能?

ssh - 如何在 SSH 盒上手动安装 VSCode 扩展?

hadoop - 我们在 hadoop 中使用 RPC 还是 SSH 进行进程间通信?

linux - SSH 服务器以不接受连接的系统帐户启动

go - 无人机日志存储在哪里?

go - 如何在 http goroutines 之间共享 mysql 连接?

json - 如何将 jsonb 编码为 golang 中 http 响应的一部分

字符串错误 : unknown escape sequence:/

c# - 如何确定文件是否在 SSH.NET 中完成下载

linux - 无法连接到远程机器 'ssh_exchange_identification: read: Connection reset by peer'