为了账号安全,请及时绑定邮箱和手机立即绑定

如何使用 Go 通过 SSH 发送终端转义序列?

如何使用 Go 通过 SSH 发送终端转义序列?

Go
繁星淼淼 2021-09-20 14:41:26
我正在编写一个 Go 程序,该程序将使用本机x/crypto/ssh库通过 SSH 连接到主机并删除交互式 shell。我正在使用RequestPty(),但远程端的 (bash) shell 与控制代码的行为不一样。当我输入各种控制字符时,它们会被我的终端回显:$ ^[[A从某种意义上说,字符仍然有效,如果我在按向上箭头后按 Enter,则运行上一个命令 - 但控制字符输出会破坏应该在那里显示的内容。选项卡也是如此。有没有一些简单的方法可以让它发挥作用?当我过去实施过类似的系统时,这不是问题,因为我刚刚投入到openssh,并且进程组的语义将其全部解决。我已经研究过“ The TTY Demystified ”,尽管它很棒,但不清楚从哪里开始。我想调查的几件事:在我的终端使原始模式-但我并不想这样做,不理解为什么,它不似乎做正确的事摆弄终端模式标志openssh 本身必须正确地完成这项工作,但它是一个真正最好的代码库研究。我实际上不清楚这个打印是由我的本地终端仿真器或外壳程序完成的,还是由远程主机上的代码完成的。我从哪开始呢?这是我的代码示例:conf := ssh.ClientConfig{    User: myuser,    Auth: []ssh.AuthMethod{ssh.Password(my_password)}}conn, err := ssh.Dial("tcp", myhost, conf)if err != nil {    return err}defer conn.Close()session, err := conn.NewSession()if err != nil {    return err}defer session.Close()session.Stdout = os.Stdoutsession.Stderr = os.Stderrsession.Stdin = os.Stdinmodes := ssh.TerminalModes{    ssh.ECHO: 0    ssh.TTY_OP_ISPEED: 14400,    ssh.TTY_OP_OSPEED: 14400}if err := session.RequestPty("xterm", 80, 40, modes); err != nil {    return err}if err = session.Shell(); err != nil {    return err}return session.Wait()我已经尝试过使用xterm:screen-256color和以外的术语值进行此操作vt100。为了记录 - 在真实的代码中session.Wait(),我有一个for/select循环,它可以捕获到进程的各种信号并将它们发送到Session.
查看完整描述

2 回答

?
回首忆惘然

TA贡献1847条经验 获得超11个赞

在ssh.ECHO: 0与ssh.ECHOCTL: 0设置并没有为我工作。对于遇到此问题的其他人,以下是使用 Go ssh 库获得完全工作的交互式终端所需的粗略代码:


config := return &ssh.ClientConfig{

    User: "username",

    Auth: []ssh.AuthMethod{ssh.Password("password")},

}


client, err := ssh.Dial("tcp", "12.34.56.78:22", config)

if err != nil { ... }

defer client.Close()


session, err := client.NewSession()

if err != nil { ... }

defer session.Close()


session.Stdout = os.Stdout

session.Stderr = os.Stderr

session.Stdin = os.Stdin


modes := ssh.TerminalModes{

    ssh.ECHO:          1,     // enable echoing

    ssh.TTY_OP_ISPEED: 14400, // input speed = 14.4kbaud

    ssh.TTY_OP_OSPEED: 14400, // output speed = 14.4kbaud

}


fileDescriptor := int(os.Stdin.Fd())


if terminal.IsTerminal(fileDescriptor) {

    originalState, err := terminal.MakeRaw(fileDescriptor)

    if err != nil { ... }

    defer terminal.Restore(fileDescriptor, originalState)


    termWidth, termHeight, err := terminal.GetSize(fileDescriptor)

    if err != nil { ... }


    err = session.RequestPty("xterm-256color", termHeight, termWidth, modes) 

    if err != nil { ... }

}


err = session.Shell()

if err != nil { ... }


// You should now be connected via SSH with a fully-interactive terminal

// This call blocks until the user exits the session (e.g. via CTRL + D)

session.Wait()

请注意,所有键盘功能(制表符完成、向上箭头)和信号处理 ( CTRL + C, CTRL + D) 在上述设置中都能正常工作。


查看完整回答
反对 回复 2021-09-20
?
弑天下

TA贡献1818条经验 获得超8个赞

禁用ECHOCTL终端模式。


modes := ssh.TerminalModes{

    ssh.ECHO: 0,

    ssh.ECHOCTL: 0,

    ssh.TTY_OP_ISPEED: 14400,

    ssh.TTY_OP_OSPEED: 14400

}


查看完整回答
反对 回复 2021-09-20
  • 2 回答
  • 0 关注
  • 281 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信