Go SSH 服务器通过 SCP 接受文件传输
Go SSH server accepting file transfers via 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 服务器,它能够通过
访问 connections/commands
ssh -i ssh/tester_rsa foo@localhost -p 2200 'somecommand'
并且工作得很好。
我了解到有效负载包含第一个显示的 scp 请求的 "scp -f /test"。我被困在如何 return 来自服务器的实际内容上,我尝试用字符串回复(就像普通的 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
...
当我尝试使用适当的服务器时,我得到以下几行
...
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代码的片段,因为项目很大,不容易复制粘贴到这里:
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。我不知道如何处理连接,也不知道 return 究竟要做什么才能完成正确的文件传输。
谷歌搜索了一段时间后,我找到了 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 模拟文件传输(使用字符串作为文件内容)。
提前致谢!
好的,我自己找到了解决方案,虽然很小但是使代码有效:
prep := "C0644 " + strconv.Itoa(len(o)) + " test.txt\n"
connection.Write([]byte(prep))
connection.Write([]byte(o))
connection.Write([]byte("\x00"))
我在长度后的准备变量中遗漏了一个 space,长度没有正确转换,关闭的“\x00”以这种方式工作得更好。现在我可以收到一个包含内容的假文件:)
我想用 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 服务器,它能够通过
访问 connections/commandsssh -i ssh/tester_rsa foo@localhost -p 2200 'somecommand'
并且工作得很好。
我了解到有效负载包含第一个显示的 scp 请求的 "scp -f /test"。我被困在如何 return 来自服务器的实际内容上,我尝试用字符串回复(就像普通的 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
...
当我尝试使用适当的服务器时,我得到以下几行
...
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代码的片段,因为项目很大,不容易复制粘贴到这里:
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。我不知道如何处理连接,也不知道 return 究竟要做什么才能完成正确的文件传输。
谷歌搜索了一段时间后,我找到了 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 模拟文件传输(使用字符串作为文件内容)。
提前致谢!
好的,我自己找到了解决方案,虽然很小但是使代码有效:
prep := "C0644 " + strconv.Itoa(len(o)) + " test.txt\n"
connection.Write([]byte(prep))
connection.Write([]byte(o))
connection.Write([]byte("\x00"))
我在长度后的准备变量中遗漏了一个 space,长度没有正确转换,关闭的“\x00”以这种方式工作得更好。现在我可以收到一个包含内容的假文件:)