jjzjj

go - 输入 ssh 提示数据

coder 2024-07-10 原文

所以我可以通过 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 类型时造成混淆。

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

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/

有关go - 输入 ssh 提示数据的更多相关文章

  1. ruby - 解析 RDFa、微数据等的最佳方式是什么,使用统一的模式/词汇(例如 schema.org)存储和显示信息 - 2

    我主要使用Ruby来执行此操作,但到目前为止我的攻击计划如下:使用gemsrdf、rdf-rdfa和rdf-microdata或mida来解析给定任何URI的数据。我认为最好映射到像schema.org这样的统一模式,例如使用这个yaml文件,它试图描述数据词汇表和opengraph到schema.org之间的转换:#SchemaXtoschema.orgconversion#data-vocabularyDV:name:namestreet-address:streetAddressregion:addressRegionlocality:addressLocalityphoto:i

  2. ruby - Capistrano 3 在任务中更改 ssh_options - 2

    我尝试使用不同的ssh_options在同一阶段运行capistranov.3任务。我的production.rb说:set:stage,:productionset:user,'deploy'set:ssh_options,{user:'deploy'}通过此配置,capistrano与用户deploy连接,这对于其余的任务是正确的。但是我需要将它连接到服务器中配置良好的an_other_user以完成一项特定任务。然后我的食谱说:...taskswithoriginaluser...task:my_task_with_an_other_userdoset:user,'an_othe

  3. ruby - Ruby 有 `Pair` 数据类型吗? - 2

    有时我需要处理键/值数据。我不喜欢使用数组,因为它们在大小上没有限制(很容易不小心添加超过2个项目,而且您最终需要稍后验证大小)。此外,0和1的索引变成了魔数(MagicNumber),并且在传达含义方面做得很差(“当我说0时,我的意思是head...”)。散列也不合适,因为可能会不小心添加额外的条目。我写了下面的类来解决这个问题:classPairattr_accessor:head,:taildefinitialize(h,t)@head,@tail=h,tendend它工作得很好并且解决了问题,但我很想知道:Ruby标准库是否已经带有这样一个类? 最佳

  4. ruby - 我如何添加二进制数据来遏制 POST - 2

    我正在尝试使用Curbgem执行以下POST以解析云curl-XPOST\-H"X-Parse-Application-Id:PARSE_APP_ID"\-H"X-Parse-REST-API-Key:PARSE_API_KEY"\-H"Content-Type:image/jpeg"\--data-binary'@myPicture.jpg'\https://api.parse.com/1/files/pic.jpg用这个:curl=Curl::Easy.new("https://api.parse.com/1/files/lion.jpg")curl.multipart_form_

  5. 世界前沿3D开发引擎HOOPS全面讲解——集3D数据读取、3D图形渲染、3D数据发布于一体的全新3D应用开发工具 - 2

    无论您是想搭建桌面端、WEB端或者移动端APP应用,HOOPSPlatform组件都可以为您提供弹性的3D集成架构,同时,由工业领域3D技术专家组成的HOOPS技术团队也能为您提供技术支持服务。如果您的客户期望有一种在多个平台(桌面/WEB/APP,而且某些客户端是“瘦”客户端)快速、方便地将数据接入到3D应用系统的解决方案,并且当访问数据时,在各个平台上的性能和用户体验保持一致,HOOPSPlatform将帮助您完成。利用HOOPSPlatform,您可以开发在任何环境下的3D基础应用架构。HOOPSPlatform可以帮您打造3D创新型产品,HOOPSSDK包含的技术有:快速且准确的CAD

  6. FOHEART H1数据手套驱动Optitrack光学动捕双手运动(Unity3D) - 2

    本教程将在Unity3D中混合Optitrack与数据手套的数据流,在人体运动的基础上,添加双手手指部分的运动。双手手背的角度仍由Optitrack提供,数据手套提供双手手指的角度。 01  客户端软件分别安装MotiveBody与MotionVenus并校准人体与数据手套。MotiveBodyMotionVenus数据手套使用、校准流程参照:https://gitee.com/foheart_1/foheart-h1-data-summary.git02  数据转发打开MotiveBody软件的Streaming,开始向Unity3D广播数据;MotionVenus中设置->选项选择Unit

  7. 使用canal同步MySQL数据到ES - 2

    文章目录一、概述简介原理模块二、配置Mysql使用版本环境要求1.操作系统2.mysql要求三、配置canal-server离线下载在线下载上传解压修改配置单机配置集群配置分库分表配置1.修改全局配置2.实例配置垂直分库水平分库3.修改group-instance.xml4.启动监听四、配置canal-adapter1修改启动配置2配置映射文件3启动ES数据同步查询所有订阅同步数据同步开关启动4.验证五、配置canal-admin一、概述简介canal是Alibaba旗下的一款开源项目,Java开发。基于数据库增量日志解析,提供增量数据订阅&消费。Git地址:https://github.co

  8. ruby-on-rails - 创建 ruby​​ 数据库时惰性符号绑定(bind)失败 - 2

    我正在尝试在Rails上安装ruby​​,到目前为止一切都已安装,但是当我尝试使用rakedb:create创建数据库时,我收到一个奇怪的错误:dyld:lazysymbolbindingfailed:Symbolnotfound:_mysql_get_client_infoReferencedfrom:/Library/Ruby/Gems/1.8/gems/mysql2-0.3.11/lib/mysql2/mysql2.bundleExpectedin:flatnamespacedyld:Symbolnotfound:_mysql_get_client_infoReferencedf

  9. STM32读取串口传感器数据(颗粒物传感器,主动上传) - 2

    文章目录1.开发板选择*用到的资源2.串口通信(个人理解)3.代码分析(注释比较详细)1.主函数2.串口1配置3.串口2配置以及中断函数4.注意问题5.源码链接1.开发板选择我用的是STM32F103RCT6的板子,不过代码大概在F103系列的板子上都可以运行,我试过在野火103的霸道板上也可以,主要看一下串口对应的引脚一不一样就行了,不一样的就更改一下。*用到的资源keil5软件这里用到了两个串口资源,采集数据一个,串口通信一个,板子对应引脚如下:串口1,TX:PA9,RX:PA10串口2,TX:PA2,RX:PA32.串口通信(个人理解)我就从串口采集传感器数据这个过程说一下我自己的理解,

  10. SPI接收数据异常问题总结 - 2

    SPI接收数据左移一位问题目录SPI接收数据左移一位问题一、问题描述二、问题分析三、探究原理四、经验总结最近在工作在学习调试SPI的过程中遇到一个问题——接收数据整体向左移了一位(1bit)。SPI数据收发是数据交换,因此接收数据时从第二个字节开始才是有效数据,也就是数据整体向右移一个字节(1byte)。请教前辈之后也没有得到解决,通过在网上查阅前人经验终于解决问题,所以写一个避坑经验总结。实际背景:MCU与一款芯片使用spi通信,MCU作为主机,芯片作为从机。这款芯片采用的是它规定的六线SPI,多了两根线:RDY和INT,这样从机就可以主动请求主机给主机发送数据了。一、问题描述根据从机芯片手

随机推荐