通过中间主机进行 scp 传输

通过中间主机进行 scp 传输

我有 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 之间存在对称性。为了能够通过调用scpC 在 A 和 C 之间复制文件,只需在上述解决方案中交换 A 和 C 即可。


scp在 A 或 C 上调用的基本设置

您可以合并上述两个解决方案,因此可以通过调用scpA 或 C 来复制文件。终止(Ctrl+ cssh我们之前使用的所有命令并重新开始:

# 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)。理论上,这应该足以让scpB 轻松地将文件从 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

(也可以在配置中指定端口转发,LocalForwardRemoteForward参阅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 作为传输的工具,尤其是在您将详细信息移动到配置文件之后。

相关内容