我有 3 台服务器:A、B、C,需要将文件从 A 传输到 C。
ssh
仅可从 A 到 B 和从 C 到 B(见下文),因为 A 和 C 在 2 个不同的 VPN 上。
A→B
丙→丙
SSH 是不可能的:从 B 到 C,从 B 到 A 也不可能从 A 到 C。
我在网上找到的所有例子都是“跳转主机”或像这样跳跃:A→B→C;但它在我的情况下不起作用,因为B→C是不可能的。
在这种情况下,从 A 传输到 C 的最佳方法是什么(最好使用scp
)?
我认为唯一的方法是使用某种反向 SSH 隧道,但无法使其工作。
答案1
初步说明
我假设您可以ssh userB@B_seen_from_A
从 A 到达 B;并且您可以ssh userB@B_seen_from_C
从 C 到达 B。我还假设 A 和 C 上也有 SSH 服务器(尽管现在您无法从外部访问它们)。
scp
直接使用ssh
,我的意思是它制作一个ssh …
命令(这并不像我们想要的那么干净,请参阅“一些见解”我的这个答案)。做准备意味着首先scp
要做准备。ssh
按照此答案操作时,如果遇到错误或意外消息,请参阅下面的“注释”。其中一些解决了一些可能的障碍。
scp
调用A 的基本设置
当您“无法使其工作”时,您没有告诉我们您尝试建立“某种反向 SSH 隧道”。我不知道您尝试了什么以及失败的原因。您可能可以这样做:
# on C
ssh -R 1111:localhost:22 -N userB@B_seen_from_C
(注意localhost
会在C处解决,所以隧道会通向C。)
这是您需要的远程隧道。数字1111
是任意的(您很可能不允许使用低于 1024 的端口你可能想避免临时端口;当然端口必须可用)。22
是 SSH 的标准端口(使用 C 上的 SSH 服务器使用的端口)。如果您正确执行此操作,则ssh -p 1111 userC@localhost
在 B 上调用将允许您访问 C。
但是你仍然无法从 A 使用这个隧道。如果你在 C 上使用… -R :1111:localhost:22 …
(注意额外的冒号),那么你可能或不可能ssh -p 1111 userC@B_seen_from_A
从 A 到达 C,这取决于防火墙和 B 上 SSH 服务器的设置(比较我的这个答案)我们不要这样做。让我们创造其他隧道,从 A 到 B,可以让你从 A 到达第一条隧道。这是另一条隧道:
# on A
ssh -L 2222:localhost:1111 -N userB@B_seen_from_A
(注意这localhost
将在 B 上得到解决,因此隧道将通向 B。)
现在,您可以通过两个链接的隧道从 A 到达 C:
# on A
ssh -p 2222 userC@localhost
(这localhost
在 A 上得到解决,它通向 A;我们连接到链式隧道的 A 端,另一端在 C。)
然后您可以通过scp
在 A 上调用以下命令在 A 和 C 之间复制文件:
# on A
# copying from A to C
scp -P 2222 /local/path/to/file userC@localhost:/remote/destination
# or copying from C to A
scp -P 2222 userC@localhost:/remote/path/to/file /local/destination
(注意,使用scp
您需要-P
指定端口,而使用ssh
您需要-p
。)
scp
在 C 上调用的基本设置
在您的原始设置中,A 和 C 之间存在对称性。为了能够通过调用scp
C 在 A 和 C 之间复制文件,只需在上述解决方案中交换 A 和 C 即可。
scp
在 A 或 C 上调用的基本设置
您可以合并上述两个解决方案,因此可以通过调用scp
A 或 C 来复制文件。终止(Ctrl+ c)ssh
我们之前使用的所有命令并重新开始:
# on C
ssh -L 3333:localhost:3333 -R 1111:localhost:22 -N userB@B_seen_from_C
# on A
ssh -L 1111:localhost:1111 -R 3333:localhost:22 -N userB@B_seen_from_A
请注意,它位于1111
我们之前所用的位置2222
。这个想法是使用相同的端口号从 A 或 B 到达 C(端口号为1111
);使用另一个端口号从 C 或 B 到达 A(端口号为3333
)。因此,1111
与一个方向的两个链接隧道相关联,3333
与相反方向的两个链接隧道相关联。B 上的 SSH 服务器将侦听两个端口,因此端口号必须不同。
然后在 A 上使用scp -P 1111 …
并将 C 称为userC@localhost
;或者在 C 上使用scp -P 3333 …
并将 A 称为userA@localhost
。
scp
在 B 上调用怎么样?
上一节中的两个ssh
命令将允许您从 B 到达 C(通过连接到 B 的localhost
端口1111
)并从 B 到达 A(通过连接到 B 的localhost
端口3333
)。理论上,这应该足以让scp
B 轻松地将文件从 A 传输到 C。实际上scp
有些受限。
一般来说,当scp
要在两个远程主机之间复制文件时,有两种方法:
传统上,
scp
告诉一个主机到达另一个主机并传输文件。调用的机器scp
可能无法到达另一个主机,但只要第一个主机可以到达另一个主机,该方法仍将有效。调用的scp
可执行文件不充当中继。和
scp -3
被调用的scp
可执行文件充当中继。调用的机器scp
需要能够访问两台主机,但两台主机之间不需要互相可达。
不管怎样,如果您需要指定两个不同的端口(并且在我们的设置中这样做),那么它将不起作用,scp -P
因为scp -P
允许您指定单个值。
如果你通过端口,它应该可以工作以不同的方式。 例子:
# on B
# copying from A to C
scp -3 scp://userA@localhost:3333//A_path/to/file \
scp://userC@localhost:1111//C_path/to/destination
还有另一种解决方案,请阅读下一节。
更加优雅和强大的设置
ssh
(和相关工具)查阅配置文件(~/.ssh/config
针对用户和/etc/ssh/ssh_config
服务器范围的配置)。不要在命令行上指定内容,而是在配置中指定它们(注意:接近开始的时候)。
在 A:
Host B
Hostname B_seen_from_A
User userB
Host C
Hostname localhost
Port 1111
User userC
在 B 上:
Host A
Hostname localhost
Port 3333
User userA
Host C
Hostname localhost
Port 1111
User userC
在 C 上:
Host A
Hostname localhost
Port 3333
User userA
Host B
Hostname B_seen_from_C
User userB
创建隧道的命令简化为:
# on C
ssh -L 3333:localhost:3333 -R 1111:localhost:22 -N B
# on A
ssh -L 1111:localhost:1111 -R 3333:localhost:22 -N B
(也可以在配置中指定端口转发,LocalForward
请RemoteForward
参阅man 5 ssh_config
;但这会影响任何人ssh … B …
,而您可能不希望这样。)
A 上的示例scp
命令很简单:
# on A
scp /path/to/file C:/some/destination
现在你也可以从 B 执行此操作:
# on B
scp A:/path/to/file C:/some/destination
# or
scp -3 A:/path/to/file C:/some/destination
或者从 C:
# on C
scp A:/path/to/file /some/destination
重点是现在 A 和 B 可以解析C
,每个地址都不同,但每个地址在相应客户端的上下文中都是正确的。同样,B 和 C 可以解析A
。如果您另外确保 A 识别A
为自己,C 识别C
为自己,那么此命令:
scp A:/path/to/file C:/some/destination
应该努力任何三个主机之一。如果在 A 或 C 上调用,它将建立一些不必要的连接(例如从 A 到 A),但原则上它会起作用;那么它是一个通用命令。
可能存在一些问题,请参见下文。
笔记
- 如果你
administratively prohibited: open failed
在创建隧道时遇到此问题:SSH 隧道错误:channel 1: open failed: administratively prohibited: open failed
。 ExitOnForwardFailure
可能会方便。- 而不是
ssh -L … -R … -N …
考虑autossh
或服务保持隧道畅通;C 也一样。 scp
在 B 上使用时无需-3
密码验证可能会破坏事情. 更喜欢基于密钥的身份验证。- 有六到八种可能的客户端-服务器对(A→B、A→C、B→A、B→C、C→A、C→B;如果您希望“通用命令”具有通用性,则还有 A→A 和 C→C)。如果您仅为其中几个设置基于密钥的身份验证,则某些命令将失败或要求输入密码。注意哪个客户端需要向哪个服务器进行身份验证,或者简单地为所有可能的对设置基于密钥的身份验证。
- 您打开的端口(即隧道的监听端)至少对相应系统(A、B 或 C)的其他本地用户可用。每个隧道最终都会通向需要进行身份验证的 SSH 服务器。即使恶意用户劫持了端口(只需在您之前绑定端口即可),并且您的隧道通向他们的 SSH 服务器,你将能够分辨在您发送宝贵的文件或请求可能存在危险的文件之前,请先检查端口是否被占用。但是,只要保持端口被占用,恶意程序就可能会阻止您进行设置(特别是如果您的设置是自动的且不受监督)。在 B 上使用 Unix 套接字而不是 TCP 端口可能会有所帮助,但我不会详细说明。
- 在我看来,这
scp
是一个快速而肮脏的黑客攻击,它坚持了下来(参见这个已经链接的答案)。隧道应该允许您使用任何使用 SSH 作为传输的工具,尤其是在您将详细信息移动到配置文件之后。