douguio0185 2015-05-26 08:06
浏览 767

Golang:通过WebSocket转发SSH

I've been able to forward telnet over a websocket using golang, using something like

func forwardtcp(wsconn *websocket.Conn, conn *telnet.Conn) {
    connbuf := bufio.NewReader(conn)
    tcpbuffer := make([]byte, 128)

    for {
        n, err := connbuf.Read(tcpbuffer)

        if err != nil {
            log.Println("TCP Read failed")
            break
        }
        if err == nil {
            wsconn.WriteMessage(websocket.BinaryMessage, tcpbuffer[:n])
        }
    }
}

However I'm unable to do similar with an SSH or shell session. I'm not understanding a fundamental concept with the using the

targetStdout, _ := session.StdoutPipe()
targetStdin, _ := session.StdinPipe()

pieces.

I am able to use io.Copy, but not sure how to format these into a datagram that can be sent with the websocket connection.

Is it possible to treat the targetStdin and targetStdout pipes in a manner that they can be read and written to with bytes, such as those received from the websocket connection? Or is there a better approach to get io from the SSH connection?

  • 写回答

2条回答 默认 最新

  • dtf54486 2015-05-26 13:02
    关注

    If you want to use SSH for a remote shell session you should not use the websocket package but the golang.org/x/crypto/ssh package. There is an excellent example at godoc.org which I repeat here:

    // An SSH client is represented with a ClientConn. Currently only
    // the "password" authentication method is supported.
    //
    // To authenticate with the remote server you must pass at least one
    // implementation of AuthMethod via the Auth field in ClientConfig.
    config := &ssh.ClientConfig{
        User: "username",
        Auth: []ssh.AuthMethod{
            ssh.Password("yourpassword"),
        },
    }
    client, err := ssh.Dial("tcp", "yourserver.com:22", config)
    if err != nil {
        panic("Failed to dial: " + err.Error())
    }
    
    // Each ClientConn can support multiple interactive sessions,
    // represented by a Session.
    session, err := client.NewSession()
    if err != nil {
        panic("Failed to create session: " + err.Error())
    }
    defer session.Close()
    
    // Once a Session is created, you can execute a single command on
    // the remote side using the Run method.
    var b bytes.Buffer
    session.Stdout = &b
    if err := session.Run("/usr/bin/whoami"); err != nil {
        panic("Failed to run: " + err.Error())
    }
    fmt.Println(b.String())
    

    You probably want to use the fields of the ssh.Session struct instead of using StdoutPipe().

    type Session struct {
        Stdin io.Reader
        Stdout io.Writer
        Stderr io.Writer
    }
    

    The line in the example session.Stdout = &b means that the stdout from the remote process will be written to b. Likewise, you can assign any io.Reader to session.Stdin which will be read as stdin by the remote process. The detailed behavior of ssh.Session can be found at godoc.org

    评论

报告相同问题?

悬赏问题

  • ¥15 Python输入字符串转化为列表排序具体见图,严格按照输入
  • ¥20 XP系统在重新启动后进不去桌面,一直黑屏。
  • ¥15 opencv图像处理,需要四个处理结果图
  • ¥15 无线移动边缘计算系统中的系统模型
  • ¥15 深度学习中的画图问题
  • ¥15 java报错:使用mybatis plus查询一个只返回一条数据的sql,却报错返回了1000多条
  • ¥15 Python报错怎么解决
  • ¥15 simulink如何调用DLL文件
  • ¥15 关于用pyqt6的项目开发该怎么把前段后端和业务层分离
  • ¥30 线性代数的问题,我真的忘了线代的知识了