通过SSH隧道传输数据非常简单:

ssh -D9999 username@example.com

localhost上设置端口9999作为通往example.com的隧道,但是我有一个更具体的需求:


我正在localhost上本地工作


host1可以访问localhost


host2仅接受来自host1

我需要创建一个从localhosthost2的隧道


有效地,我想创建一个“多跳” SSH隧道。我怎样才能做到这一点?理想情况下,我想执行此操作而无需成为任何计算机上的超级用户。

评论

你是用来干什么的?我想将其用于袜子代理。能行吗?

是的,除非host2拒绝转发
,否则您应该能够将隧道连接用作SOCKS代理。
我当时正在考虑通过SSH创建包装器,该包装器将通过多次使用ProxyCommand进行设置。

@prongs(所有年前)您是否已将其用于SOCKS代理?

#1 楼

您基本上有以下三种可能性:



localhosthost1的隧道:

ssh -L 9999:host2:1234 -N host1


如上所述,从host1host2的连接将无法固定。


localhosthost1以及从host1host2的隧道:

ssh -L 9999:localhost:9999 host1 ssh -L 9999:localhost:1234 -N host2


这将打开从localhosthost1的隧道,以及另一个从host1host2的隧道。但是,9999上的任何人都可以使用端口host2:1234host1。这可能是问题,也可能不是问题。



localhosthost1以及从localhosthost2的隧道:

ssh -L 9998:host2:22 -N host1
ssh -L 9999:localhost:1234 -N -p 9998 localhost


此将打开从localhosthost1的隧道,通过该隧道可以使用host2上的SSH服务。然后从第一个隧道打开从localhosthost2的第二个隧道。


通常,我会选择选项1。如果需要保护从host1host2的连接,请转到带有选项2。选项3主要用于访问host2上只能从host2本身访问的服务。

评论


选项3是我一直在寻找的东西,谢谢!

–马拉
2010-1-25的1:38

我想以这种方式浏览。哪一个最好?我尝试了第一个,但是没有用。我在浏览器localhost:1234中设置了一个袜子代理,但是没有运气。 :( 请帮忙..

– rong
2012年2月29日在13:54

@prongs尝试选项3

–马拉
2012年5月3日在6:49

@Noli如果使用ssh-agent(应使用),则可以使用ssh的-A选项通过连接转发它。

– Mika Fischer
2012-12-19 11:36

@musically_ut-正确的是,第二个ssh命令在host1上处于后台,因此,如果要在本地重新连接它,则只需再次运行第一部分。如果添加-f,它将立即在本地后台运行,因此,如果在第一种情况下按ctrl-c,则ssh -f -L 9999:localhost:9999 host1将重新连接。或在首次运行它以立即使所有背景后台运行时,将-f添加到原始double ssh命令中。

–马克·费舍尔
17-2-25在15:10

#2 楼

有一个很好的答案说明了如何将ProxyCommand配置指令用于SSH:

将其添加到您的~/.ssh/config(有关详细信息,请参见man 5 ssh_config): br />然后ssh host2将自动通过host1进行隧道传输(也适用于X11转发等)。通过域标识:

Host host2
  ProxyCommand ssh host1 -W %h:%p


更新

OpenSSH 7.3引入了ProxyJump指令,将第一个示例简化为

Host *.mycompany.com
  ProxyCommand ssh gateway.mycompany.com -W %h:%p


评论


有条件的方法吗?有时候我只想这样做。另外,这是专门针对命令的,但是我正在为22端口(ssh,sftp等)寻找所有东西。

– Stephane
2013年9月11日15:08

@Stephane专门用于命令是什么意思?使用ssh的任何人都可以使用您的SSH配置,包括git,sftp等afaik。

– kynan
2013年9月11日20:58



@Stephane我不知道有条件地启用此功能的方法(例如,仅当您不在目标主机的网络范围内时)。我在配置块中为所有有问题的主机设置了此选项,然后根据需要(取消)注释该行。并不完美,但是可以。

– kynan
2013年9月11日20:58在

@Stephane确保:ssh -F / path / to / altconfig。请注意,这将忽略系统范围内的/ etc / ssh / ssh_config。

– kynan
2013年9月12日上午11:39

一种使设置“有条件”的简单方法是在.ssh / config中定义两个具有相同HostName的不同主机。当需要隧道时,连接到host2-tunnel,而当不需要隧道时,连接到host2。

–史蒂夫·贝内特(Steve Bennett)
2013年9月23日下午6:55

#3 楼

OpenSSH v7.3及更高版本支持-J开关和ProxyJump选项,它们允许一个或多个逗号分隔的跳转主机,因此,您现在就可以轻松执行以下操作:

ssh -J jumpuser1@jumphost1,jumpuser2@jumphost2,...,jumpuserN@jumphostN user@host


评论


ssh -J user1 @ host1 -YC4c arcfour,blowfish-cbc user2 @ host2 firefox -no-remote这将加快将firefox从host2获取到本地主机的速度。

– Jaur
18年5月21日在16:28

我不知道你可以这样做。感谢分享!

–Stephen Quan
19/12/11在23:35

#4 楼

我们有一个进入我们专用网络的ssh网关。如果我在外面,并且想要在专用网络内部的计算机上安装远程Shell,则必须ssh进入网关,然后从那里进入专用计算机。

要使此过程自动化,请使用以下脚本:

#!/bin/bash
ssh -f -L some_port:private_machine:22 user@gateway "sleep 10" && ssh -p some_port private_user@localhost


发生了什么事情:


建立用于ssh协议(端口22)到专用端口的隧道
只有成功,才可以使用隧道将其SSH到专用计算机中。 (&&操作员确保这一点。)
关闭私有ssh会话后,我也希望ssh隧道也关闭。这是通过“睡眠10”技巧完成的。通常,第一个ssh命令将在10秒后关闭,但是在此期间,第二个ssh命令将使用隧道建立连接。结果,第一个ssh命令使隧道保持打开状态,直到满足以下两个条件:sleep 10完成并且不再使用隧道。


评论


非常聪明!!!爱它!

–亨拉·爱侣湾
2012年5月6日在6:37

#5 楼

阅读以上内容并将所有内容粘合在一起之后,我创建了以下Perl脚本(将其保存为/ sh / usr中的mssh并使其可执行):

#!/usr/bin/perl

$iport = 13021;
$first = 1;

foreach (@ARGV) {
  if (/^-/) {
    $args .= " $_";
  }
  elsif (/^((.+)@)?([^:]+):?(\d+)?$/) {
    $user = ;
    $host = ;
    $port =  || 22;
    if ($first) {
      $cmd = "ssh ${user}${host} -p $port -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no";
      $args = '';
      $first = 0;
    }
    else {
      $cmd .= " -L $iport:$host:$port";
      push @cmds, "$cmd -f sleep 10 $args";
      $cmd = "ssh ${user}localhost -p $iport -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no";
      $args = '';
      $iport ++;
    }
  }
}
push @cmds, "$cmd $args";

foreach (@cmds) {
  print "$_\n";
  system($_);
}


用法:

通过HOSTA和HOSTB(同一用户)访问HOSTC:

mssh HOSTA HOSTB HOSTC


通过HOSTA和HOSTB访问HOSTC并使用非默认SSH端口号和不同的用户:

mssh user1@HOSTA:1234 user2@HOSTB:1222 user3@HOSTC:78231


要通过HOSTA和HOSTB访问HOSTC并使用X转发:

mssh HOSTA HOSTB HOSTC -X


通过HOSTA和HOSTB访问HOSTC上的端口8080:

mssh HOSTA HOSTB -L8080:HOSTC:8080


评论


这太棒了

–马拉
2012年3月25日在1:20

我真的很感谢您,此脚本每天使我的生活更加轻松。我唯一更改的是将int(rand(1000))添加到iport,以允许多个实例同时运行。我绝对欠你一杯啤酒。

–马拉
2012年5月3日在7:20

这真的很好。进一步的改进是使用本地主机的/ etc / hosts和〜/ .ssh / config来解析HOSTB,HOSTC等

–史蒂夫·贝内特(Steve Bennett)
2013年9月23日在7:03

我也赞同马拉的评论。如果没有随机端口,那么如果您尝试使用mssh HOSTA HOSTD,您实际上将以HOSTB结尾(也许不会意识到..)

–史蒂夫·贝内特(Steve Bennett)
2013年9月24日下午2:39

#6 楼

这个答案与kynan相似,因为它涉及到ProxyCommand的使用。但是使用IMO更为方便。

如果您的跃点计算机中安装了netcat,则可以将此代码段添加到〜/ .ssh / config中:

Host *+*
    ProxyCommand ssh $(echo %h | sed 's/+[^+]*$//;s/\([^+%%]*\)%%\([^+]*\)$/ -l /;s/:/ -p /') nc $(echo %h | sed 's/^.*+//;/:/!s/$/ %p/;s/:/ /')


然后

ssh -D9999 host1+host2 -l username


会按照您的要求做。招。找到链接后,我会发布一个链接。

评论


我相信这是技巧的起源:wiki.gentoo.org/wiki/SSH_jump_host

–slm
2014年3月28日21:00

#7 楼

我做了我认为您想使用的操作

ssh -D 9999 -J host1 host2


我都提示输入两个密码,然后可以使用localhost:9999作为host2的SOCKS代理。这是我想到的最接近您首先显示的示例的内容。

评论


这很好用!

– Arthur Silva
19年6月28日在11:03

不适用于三位房东

–弗拉基米尔·伊辛(Vladimir Iashin)
2月22日6:44

#8 楼

我的答案与这里的所有其他答案确实相同,但是,我想澄清一下~/.ssh/config和ProxyJump的用处。

说我需要3跳才能到达目的地。每跳,我需要一个特定的用户名,主机,端口和身份。由于身份标准,只能使用~/.ssh/config配置文件来完成此操作:
 [yourpc] $ ssh hop1 # will go from your PC to host1 in a single step
[host1] $ exit
[yourpc] $ ssh hop2 # will go from your PC to host2 via host1 (i.e. two steps)
[host2] $ exit
[yourpc] $ ssh hop3 # will go from your PC to host3 via host1 and host2 (i.e. three steps)
[host3] $ exit
[yourpc] $ 
 


关于~/.ssh/config文件的另一个很酷的事情是,这还将使sftp可以通过以下任何方式进行文件传输:啤酒花,例如

 [yourpc] $ sftp hop1 # for file transfers between your PC and host1
Connected to hop1.
sftp> quit
[yourpc] $ sftp hop2 # for file transfers between your PC and host2
Connected to hop2.
sftp> quit
[yourpc] $ sftp hop3 # for file transfers between your PC and host3
Connected to hop3.
sftp> quit
 


#9 楼

ssh -L 9999:host2:80 -R 9999:localhost:9999 host1



-L 9999:host2:80


意味着绑定到localhost:9999,并且发送到localhost:9999的任何数据包都将其转发到host2 :80


-R 9999:localhost:9999


表示host1:9999收到的任何数据包将其转发回localhost:9999

评论


创建隧道的出色且最简单的答案,因此您可以直接从localhost:9999访问host2上的应用程序

– dvtoever
16年7月8日在15:45

按照此答案,我得到一个频道3:打开失败:在管理上被禁止:打开失败的错误消息。

–弗朗克·德农库尔
17年3月18日在18:16

#10 楼

您应该能够使用端口转发从host2访问localhost上的服务。好的指南位于此处。摘录:


端口转发有两种:本地转发和远程转发。它们也分别称为传出隧道和传入隧道。本地端口转发将进入本地端口的流量转发到指定的远程端口。例如,如果发出命令

ssh2 -L 1234:localhost:23 username@host


all客户端上到达端口1234的流量将转发到服务器(主机)上的端口23。请注意,建立连接后,sshdserver将解析localhost。因此,在这种情况下,本地主机是指服务器(主机)本身。

远程端口转发的作用与此相反:它将来自远程端口的流量转发到指定的本地端口。

例如,如果发出命令

ssh2 -R 1234:localhost:23 username@host


服务器(主机)上到达端口1234的所有流量都将转发到客户端(本地主机)上的端口23 )。


在您的演员表中,将示例中的localhost替换为host2,将host替换为host1

评论


根据该文章,连接将仅在中间机器(host1)之前得到保护。有没有办法确保整个事情安全?

–马拉
2010-1-16的7:21

我从来没有尝试过,但是如果host1和host2都是ssh服务器,则您可以设置从host1到host2的隧道,然后为相同的服务设置从localhost到host1的隧道(获取本地和远程)端口正确)。我不知道在本地主机的一个命令中是否可行。

– fideli
2010-1-16的16:13

#11 楼

在这个答案中,我将举一个具体的例子。您只需将计算机的主机名,用户名和密码替换为您的主机名,用户名和密码。

问题声明

假设我们具有以下网络拓扑:

our local computer <---> server 1 <---> server 2


为具体起见,我们假设我们具有以下计算机的主机名,用户名和密码:

LocalPC            <--->  hostname: mit.edu         <---> hec.edu
                          username: bob                   username: john 
                          password: dylan123              password: doe456


目标:我们想要设置一个侦听9991的端口LocalPC的SOCKS代理,以便每次从端口LocalPC启动9991上的连接时,该连接都先经过mit.edu,然后再经过hec.edu

用例示例:hec.edu具有HTTP出于安全原因,只能在http://127.0.0.1:8001上访问的服务器。我们希望能够通过在LocalPC上打开Web浏览器来访问http://127.0.0.1:8001。


配置

LocalPC中,添加在~/.ssh/config中:

Host HEC
    HostName hec.edu
    User john
    ProxyCommand ssh bob@mit.edu -W %h:%p


然后在LocalPC的终端中,运行:

ssh -D9991 HEC


它会问你bob(即mit.edu)上的dylan123的密码,那么它将询问您john(即hec.edu)上的doe456的密码。

此时,SOCKS代理现在在端口9991上运行例如,如果您想使用SOCKS代理访问LocalPC上的网页,则可以在Firefox中进行:



一些说明:


LocalPC中,~/.ssh/config是连接名称:您可以将其更改为所需的任何名称。
HEC告诉-D9991在端口上设置SOCKS4代理ssh


评论


ssh -D9991 HEC只是在这里sshs到hec.edu

–olejorgenb
3月12日19:57

#12 楼

如果可以同时在两台计算机上使用SSH,请查看ssh的ProxyCommand指令。这将使您直接从localhost进入host2(如果使用公共密钥,只需一个简单的命令!)。然后,您可以对host2做任何您想做的事情。

http://www.statusq.org/archives/2008/07/03/1916/

#13 楼

最佳答案的选项2可以用于与当前aka用户不同的ssh用户:user @ host

    export local_host_port=30000
    export host1_user=xyz
    export host1=mac-host
    export host1_port=30000
    export host2=192.168.56.115
    export host2_user=ysg
    export host2_port=13306

    # Tunnel from localhost to host1 and from host1 to host2
    # you could chain those as well to host3 ... hostn
    ssh -tt -L $local_host_port:localhost:$host1_port $host1_user@$host1 \
    ssh -tt -L $host1_port:localhost:$host2_port $host2_user@$host2


#14 楼

就我而言,我确实做到了

localhost$ ssh -D 9999 host1
host1$ ssh -L 8890:localhost:8890 host2


其中host2:8890在Jupyter Notebook上运行。 。

所以现在我的笔记本在localhost:9999上运行了,可通过Firefox在我的机器上通过host2进行访问。

#15 楼

接受的答案中提到的三个选项对我根本不起作用。由于我对这两个主机的权限均不大,并且看来我们的DevOps团队在进行身份验证和执行MFA时拥有非常严格的规则。某种程度上,上面的命令不能很好地与我们的身份验证配合使用。 />
还有另一种解决方案-天真的一个解决方案

我最终以一种非常幼稚的方式做到了这一点:我没有尝试在笔记本电脑上运行所有命令,而是在每个笔记本上运行命令如下所示:


SSH进入您的跳转服务器,然后运行ssh -v -L 6969:localhost:2222 -N your-protected.dest.server。如果提示您输入任何密码,请键入。
现在在笔记本电脑上,运行ssh -v -L 6969:localhost:6969 -N your-jump-server.host.name。这会将您在笔记本电脑上端口6969上的任何请求转发到跳转服务器。然后,依次,由于我们在上一步中进行了配置,跳转服务器将再次将端口6969的请求转发到受保护的目标服务器上的端口2222。

打印后您应该看到命令“挂起”一些消息-这意味着他们正在工作!一个例外-您应该不会看到类似Could not request local forwarding.的错误消息,如果看到该错误消息,则它仍然不起作用:(。您现在可以尝试从笔记本电脑向端口6969发出请求,并查看它是否起作用。
< br希望如果您未能通过上述所有方法,也许可以尝试一下。

#16 楼

只有这样,才能在超过两个主机上帮助我:

ssh -L 6010:localhost:6010 user1@host1 \
-t ssh -L 6010:localhost:6010 user2@host2 \
-t ssh -L 6010:localhost:6010 user3@host3


它将提示您输入三个密码。

受此答案启发>