首页 > 解决方案 > 如何进行简单的 SSH x11 转发

问题描述

我正在尝试在 Go 中实现 ssh x11 转发,参考 Paramiko 的源代码,但效果不佳。

x11-req 请求似乎成功,但 OpenChannel 失败。没有更好的办法吗?

https://www.rfc-editor.org/rfc/rfc4254#section-6.3.2

完整的代码在这里。

https://gist.github.com/blacknon/6e2e6e2c0ebcd64c381925f0e3e86e42

package main

(omit)

func main() {
    // Create sshClientConfig
    sshConfig := &ssh.ClientConfig{
        User: user,
        Auth: []ssh.AuthMethod{
            ssh.Password(pass),
        },
        HostKeyCallback: ssh.InsecureIgnoreHostKey(),
    }

    // SSH connect.
    client, err := ssh.Dial("tcp", host+":"+port, sshConfig)

    // Create Session
    session, err := client.NewSession()
    defer session.Close()

    // NOTE:
    // x11-req Payload
    payload := x11request{
        SingleConnection: false,
        AuthProtocol:     string("MIT-MAGIC-COOKIE-1"),
        AuthCookie:       string("d92c30482cc3d2de61888961deb74c08"),
        ScreenNumber:     uint32(0),
    }

    // NOTE:
    // send x11-req Request
    ok, err := session.SendRequest("x11-req", true, ssh.Marshal(payload))
    if err == nil && !ok {
        fmt.Println(errors.New("ssh: x11-req failed"))
    }
    fmt.Printf("x11-req: %v\n", ok)
    fmt.Println("-----")

    // x11 OpenChannel (Not working...)
    x11Data := x11channel{
        Host: "localhost",
        Port: uint32(6000),
    }

    sshChan, req, x11err := client.OpenChannel("x11", ssh.Marshal(x11Data))
    fmt.Println(sshChan) // DEBUG
    fmt.Println(req)     // DEBUG
    fmt.Println(x11err)  // DEBUG

    (omit)
}

我添加了 sshd 端调试日志。

sshd[1811]: debug1: server_input_channel_req: channel 0 request x11-req reply 1
sshd[1811]: debug1: session_by_channel: session 0 channel 0
sshd[1811]: debug1: session_input_channel_req: session 0 req x11-req
sshd[1811]: debug1: channel 1: new [X11 inet listener]
sshd[1811]: debug1: channel 2: new [X11 inet listener]
sshd[1811]: debug1: server_input_channel_open: ctype x11 rchan 1 win 2097152 max 32768
sshd[1811]: debug1: server_input_channel_open: failure x11

多谢你们!多亏了它,我才能安全地实施它。有一个工作代码。

https://gist.github.com/blacknon/9eca2e2b5462f71474e1101179847d2a

标签: gosshx11x11-forwarding

解决方案


// x11 OpenChannel (Not working...)
x11Data := x11channel{
    Host: "localhost",
    Port: uint32(6000),
}

sshChan, req, x11err := client.OpenChannel("x11", ssh.Marshal(x11Data))

这里的根本问题是 X11 转发通道是从 SSH 服务器启动到 SSH 客户端的。您正在尝试打开从客户端到服务器的 X11 通道。您的服务器不支持此功能,并且这不是使用 X 转发的常用方法。

我不是围棋程序员。但是在查看文档之后,在您发送 x11-req 之后,您似乎会调用client.HandleChannelOpen()来接收来自服务器的 X11 通道请求。

更多背景:为了清楚起见,从术语开始。您的程序是一个ssh 客户端,它连接到一个ssh 服务器。对于 X,服务器是控制显示器、键盘和鼠标的程序。X 客户端是 xterm 和 xeyes 之类的程序,它们连接到服务器以显示窗口并执行类似的操作。

当你想通过 SSH 转发 X11 时,ssh 客户端会向 ssh 服务器发送一个 X11 请求。这告诉服务器客户端需要 X11 转发连接。服务器将执行一些设置并打开一个 TCP 侦听端口以接收来自 X 客户端的连接。

当一个 X 客户端连接到 ssh 服务器的 X11 监听端口时,ssh 服务器会打开一个通道返回给 ssh 客户端。ssh 客户端将连接到本地 X 服务器,并且 ssh 客户端和 ssh 服务器将在 X 服务器(本地到 ssh 客户端主机)和 X 客户端(本地到 ssh 服务器主机)之间中继数据。每个通道处理一个 X 客户端。

所以像你这样的程序必须向服务器发送一个请求,表明你的程序想要通过 ssh 连接转发 X11。当 X 客户端尝试使用转发的 X11 服务时,实际的 x11 通道将根据需要从 ssh 服务器打开到 ssh 客户端。


推荐阅读