gpt4 book ai didi

go - 输入 ssh 提示数据

转载 作者:数据小太阳 更新时间:2023-10-29 03:25:00 27 4
gpt4 key购买 nike

所以我可以通过 ssh 进入机器,但是我无法在提示符中输入数据。

...
sshConfig := &ssh.ClientConfig{
User: user,
Auth: []ssh.AuthMethod{
ssh.Password(password),
},
HostKeyCallback: KeyPrint,
}

connection, err := ssh.Dial("tcp", connStr, sshConfig)
if err != nil {

log.Fatalln(err)
}

session, err := connection.NewSession()
if err != nil {
log.Fatalln(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", 80, 40, modes); err != nil {
session.Close()
log.Fatalf("request for pseudo terminal failed: %s", err)
}

stdin, err := session.StdinPipe()
if err != nil {
log.Fatalf("Unable to setup stdin for session: %v", err)
}
go io.Copy(stdin, os.Stdin)

stdout, err := session.StdoutPipe()
if err != nil {
log.Fatalf("Unable to setup stdout for session: %v", err)
}
go io.Copy(os.Stdout, stdout)

stderr, err := session.StderrPipe()
if err != nil {
log.Fatalf("Unable to setup stderr for session: %v", err)
}
go io.Copy(os.Stderr, stderr)

// err = session.Run("1")

session.Run("") // running it allows me to interact with the remote machines terminal in my own terminal.. session.Start("") exits and session.Wait() doesn't display the Welcome screen that normally greats users, and the prompt doesn't appear.

stdin.Write([]byte("10000"))

os.Stdin.WriteString("110000")

// log.Fatalln(n, err)
// os.Stdin.WriteString("1")
// for {
// session.Run("1")
// go os.Stdin.WriteString("1")
// go stdin.Write([]byte("10000"))

// }
...

上面的代码片段让我进入机器,机器的提示显示在我的屏幕上,就像我手动 ssh 进入一样。我可以在 shell 中输入...但我需要能够为我在 shell 中输入 Go。我正在与之交互的提示是一个基于文本的游戏,所以我不能只发出命令,例如 no(ls、echo、grep 等),我唯一允许传入的是数字。如何将输入发送到 ssh session ?我尝试了很多方法,但似乎没有任何输入通过。

我还附上了提示的屏幕截图,以防上面的描述在试图描述 session 类型时造成混淆。

ssh session screen

更新:我想我已经找到了发送数据的方法,至少发送一次。

session, err := connection.NewSession()
if err != nil {
log.Fatalln(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", 80, 40, modes); err != nil {
session.Close()
log.Fatalf("request for pseudo terminal failed: %s", err)
}

stdin, err := session.StdinPipe()
if err != nil {
log.Fatalf("Unable to setup stdin for session: %v", err)
}
go io.Copy(stdin, os.Stdin)

stdout, err := session.StdoutPipe()
if err != nil {
log.Fatalf("Unable to setup stdout for session: %v", err)
}
go io.Copy(os.Stdout, stdout)

stderr, err := session.StderrPipe()
if err != nil {
log.Fatalf("Unable to setup stderr for session: %v", err)
}
go io.Copy(os.Stderr, stderr)

go session.Start("")
for {
stdin.Write([]byte("10000000\n"))
break
}
session.Wait()

我使用 go session.Start("") 开始 session 请记住,传递命令没有意义,因为我所做的只是输入数据以响应提示。然后,我在 for 循环的末尾使用 session.Wait() ...有点像使用 channel 和 WaitGroup 时所做的那样。在 for 循环内,我使用 stdin.Write 发送数据([]byte("10000000\n")) 需要注意的重要一点是添加 \n 分隔符以模拟在键盘上输入 ..

如果有任何更好的方法可以实现我想要实现的目标,请随意。接下来的步骤是解析响应的标准输出并相应地回复。

最佳答案

空的 Start 可以工作,但是在 ssh 包中,Start、Run 和 Shell 基本上都是对同一事物的调用。 Start("cmd") 在 shell 中执行命令,Run("cmd") 是对 Start("cmd") 的简单调用,然后为您调用 Wait()(给人一种没有并发执行的感觉),而 Shell打开一个 shell(如开始),但没有传递命令。它是一个中的六个,另一个中的六个,真的,但是使用 Shell() 可能是最干净的方法。

此外,请记住 Start() 和 Shell() 都可以利用并发性而无需显式调用“go”。它可能会释放额外的毫秒左右时间来手动调用并发,但如果这对你来说不重要,那么你应该能够放弃它。 Start 和 Shell 的自动并发是 Wait() 和 Run("cmd") 方法的原因。

如果您不需要解释您的输出 (stdout/err),那么您可以在不调用 pipe() 或 io.Copy() 的情况下映射它们,这样更容易也更高效。我在下面的示例中这样做了,但请记住,如果您确实要解释输出,使用 Pipe() 可能会更容易。在大多数情况下,您可以连续发送多个命令(或数字)而无需阅读提示,但有些东西(如密码提示)会清除输入缓冲区。如果您遇到这种情况,那么您需要阅读 Stdout 以找到您的提示或利用像 goexpect (https://github.com/google/goexpect) 这样的 expect 工具。有几个用于 Go 的类似 expect 的包,但这个来自 Google,并且(截至本文发布时)最近还在维护。

StdinPipe() 公开了一个可以在没有 io.Copy() 的情况下使用的 writeCloser,这应该更有效。

写入 StdinPipe() 的 for 循环应该允许您输入多个命令(或者在您的情况下,输入数字集)...例如,我有来自 os 的读取命令(数字等)。 Args 并遍历它们。

最后,您可能应该添加一个 session.Close() 以健康完成(您已经调用了错误)。也就是说,这是我推荐的(基于你的最后一个例子):

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", 80, 40, modes); err != nil {
session.Close()
log.Fatalf("request for pseudo terminal failed: %s", err)
}
defer session.Close()

stdin, err := session.StdinPipe()
if err != nil {
log.Fatalf("Unable to setup stdin for session: %v", err)
}

session.Stdout = os.Stdout
session.Stderr = os.Stderr

err = session.Shell()
if err != nil {
log.Fatalf("Unable to setup stdin for session: %v", err)
}
for _, cmd := range os.Args {
stdin.Write([]byte(cmd + "\n"))
}

session.Wait()

哦,还有一项要注意的是 Wait() 方法依赖于一个未检查的 channel ,该 channel 从您的命令中检索 exitStatus,这在极少数情况下确实会挂起(连接到思科设备时尤其有问题,但可以也发生在其他人身上)。如果您发现遇到这种情况(或者您只是想小心点),您可能希望将 Wait() 包装在某种超时方法中,例如通过并发调用 Wait() 并通过 channel 读取响应可以与 time.After() 一起使用(如果有帮助,我可以提供一个示例)。

关于go - 输入 ssh 提示数据,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44449543/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com