Go SSH服务器通过SCP接受文件传输

I would like to create a server process with Go which can receive or send files via scp, like:

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


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

With help of this gist I was already able to create an interactive ssh server which is able to accpet connections/commands via

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

and works nicely.

I understood that the payload contains "scp -f /test" for the first shown scp request. I am stuck in how to return actual content from the server, I tried in replying with a string (as with a normal ssh reply) but I get no file back.

Here my output of 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

When I am trying with a propper server I get following lines

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
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

So I guess I am missing some protocol / flow parameters or commands in Go.

Only the snippet of Go Code, as project is huge and is not easy to copy and paste here:

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")

I know that the code is not right for scp, but it works fine for normal ssh. I don't know how to handle the connection, and what exactly to return so that a correct file transfer is done.

Googling for a while led me to this question on stack overflow which is nearly the same but got not completely answered, as I am exactly looking for the part

 runYourCommand(msg.Command, ch)

which I guess contains the logic :)

Update: I am looking not for external ressources any more, I got some more input from this java snippet

It looks like they are emulating the scp protocol and I would perfectly be fine to have someone helping me to translate it to Go:

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


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

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

I tried this so far, but didn't help

o:="Some content of a faked file"
connection.Write([]byte("C0644 "+string(len(o))+"test.txt

To clarify: I would not like to serve a real file, rather then Go simulating a file delivery over scp (using a string as the content of the file).

Thanks in advance!

dqzg62440 scp不是ssh协议的一部分,它是一个外部程序。ssh服务器对scp并没有做任何特别的事情,它只是执行客户端发送的scp命令。
大约 3 年之前 回复
dqxz96998 我发现这个问题既有趣又写得很好,但实际上,应该将其关闭,因为它是作为对外部资源的请求而编写的,SO不允许这样做。是否可以重写以符合准则?
大约 3 年之前 回复


好,找到了自己的解决方案,虽然很小,但可以使代码正常工作:</ p>

  prep:=“ C0644” + strconv.Itoa(len(o))+“ test.txt 

connection.Write([] byte(prep))
connection.Write([] byte(o))\ nconnection.Write([] byte(“ \ x00”))
</ code> </ pre>

长度后,我在prep变量中缺少空格,长度未正确转换,并且 关闭“ \ x00”可以更好地工作。 现在,我可以收到包含内容的假文件了:)</ p>
</ div>



Ok, found myself the solution, small but that made the code work:

prep := "C0644 " + strconv.Itoa(len(o)) + " test.txt

I was missing a space in prep variable after length, the length was not converted correctly and the closing "\x00" is working better this way. Now I am able to receive a fake file with content :)

Csdn user default icon