通过SCP

时间:2017-06-30 19:19:11

标签: go ssh scp

我想用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的片段,因为项目很大,并且不容易复制和粘贴在这里:

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模拟文件传递(使用字符串作为文件的内容)。

提前致谢!

1 个答案:

答案 0 :(得分:0)

好的,发现自己是解决方案,虽然很小但是这使代码工作了:

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

我在准备变量后遗漏了一个空格,长度没有正确转换,关闭" \ x00"这种方式工作得更好。现在我能够收到一个包含内容的假文件:)