【问题标题】:Go SSH server accepting file transfers via SCPGo SSH 服务器通过 SCP 接受文件传输
【发布时间】:2017-12-04 19:54:43
【问题描述】:

我想用 Go 创建一个服务器进程,它可以通过 scp 接收或发送文件,例如:

scp -P 2200 -i ssh/tester_rsa  foo@localhost:/test output.txt

scp -P 2200 -i ssh/tester_rsa  input.txt foo@localhost:/test

this gist 的帮助下,我已经能够创建一个交互式 ssh 服务器,它能够通过以下方式接收连接/命令

ssh -i ssh/tester_rsa foo@localhost -p 2200 'somecommand'

而且效果很好。

我了解到,对于第一个显示的 scp 请求,有效负载包含“scp -f /test”。我被困在如何从服务器返回实际内容,我尝试用一​​个字符串回复(就像普通的 ssh 回复一样),但我没有得到任何文件。

这是我的 scp -vv 输出

...
debug2: callback done
debug2: channel 0: open confirm rwindow 2097152 rmax 32768
debug2: channel_input_status_confirm: type 99 id 0
debug2: exec request accepted on channel 0
debug1: client_input_channel_req: channel 0 rtype exit-status reply 0
debug2: channel 0: rcvd close
debug2: channel 0: output open -> drain
debug2: channel 0: close_read
...

当我尝试使用 propper 服务器时,我得到以下几行

...
debug2: exec request accepted on channel 0
debug2: channel 0: rcvd ext data 43
Sending file modes: C0644 98 output.txt
debug2: channel 0: written 43 to efd 7
Sink: C0644 98 output.txt
output.txt           
debug1: client_input_channel_req: channel 0 rtype exit-status reply 0
debug1: client_input_channel_req: channel 0 rtype eow@openssh.com     reply 0
debug2: channel 0: rcvd eow
debug2: channel 0: close_read
...

所以我想我在 Go 中缺少一些协议/流参数或命令。

只有 Go Code 的 sn-p,因为项目很大,这里不容易复制粘贴:

func (a *Shell) handleExec(connection ssh.Channel, payload []byte) {
...
for _, c := range a.ExecCmds {
    if matchCmds(str, c.Cmd) {
        connection.Write([]byte("Here comes the file content")
    }
}
...

我知道该代码不适用于 scp,但它适用于普通 ssh。我不知道如何处理连接,以及究竟要返回什么才能完成正确的文件传输。

谷歌搜索了一会儿,我找到了this question on stack overflow,这几乎是一样的,但没有得到完全的回答,因为我正在寻找这个部分

 runYourCommand(msg.Command, ch)

我猜其中包含逻辑:)

更新:我不再寻找外部资源,我从 this java snippet 获得了更多信息

看起来他们正在模拟 scp 协议,如果有人帮我把它翻译成 Go,我会很好:

  StringBuilder params = new StringBuilder("C0").append(perms);
  params.append(" ").append(data.length).append(" ");
  params.append(remoteFileName).append("\n");

  out.write(params.toString().getBytes());
  out.flush();

  if (!waitForInputStream(logger, in)) {
     cleanup(logger, out, channel);
     logger.log(Level.SEVERE, "Error before writing SCP bytes");
     return UNKNOWN_ERROR;           /* TODO: Improve */
  }

  out.write(data);
  out.write(new byte[]{0}, 0, 1);
  out.flush();

到目前为止我尝试过,但没有帮助

o:="Some content of a faked file"
connection.Write([]byte("C0644 "+string(len(o))+"test.txt\n"))
connection.Write([]byte(o))
connection.Write([]byte{0,0,1})

澄清一下:我不想提供真实的文件,而是通过 scp 模拟文件传递(使用字符串作为文件的内容)。

提前致谢!

【问题讨论】:

  • 我发现这个问题既引人入胜又写得很好,但实际上它应该被关闭,因为它是作为对 SO 上不允许的外部资源的请求而编写的。可以改写成meet the guidelines吗?
  • scp 不是 ssh 协议的一部分,它是一个外部程序。 ssh 服务器并没有特别针对scp 做任何事情,它只是执行客户端发送的scp 命令。

标签: go ssh scp


【解决方案1】:

好的,我自己找到了解决方案,虽然很小,但代码可以工作:

prep := "C0644 " + strconv.Itoa(len(o)) + " test.txt\n"
connection.Write([]byte(prep))
connection.Write([]byte(o))
connection.Write([]byte("\x00"))

我在长度后的 prep 变量中缺少一个空格,长度未正确转换,并且关闭“\x00”以这种方式工作得更好。现在我可以收到一个包含内容的假文件了:)

【讨论】:

    猜你喜欢
    • 2023-01-11
    • 2011-11-17
    • 2011-04-15
    • 2014-07-30
    • 2011-01-31
    • 2016-09-07
    • 2015-07-30
    • 2016-11-22
    • 2015-04-08
    相关资源
    最近更新 更多