2010-01-16 05:58:48 +0000 2010-01-16 05:58:48 +0000
354
354

一个通过多个端口的SSH隧道

通过SSH隧道传输数据是相当直接的: ssh -D9999 username@example.com

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

  • 我在本地工作的是localhost
  • host1可以访问到localhost
  • host2只接受来自host1 的连接 - 我需要创建一个从localhost

的隧道,实际上,我想创建一个 “多跳 "的SSH隧道。我如何才能做到这一点?理想情况下,我想在不需要任何一台机器上的超级用户的情况下实现这个目的。

答案 (15)

341
341
341
2010-01-17 21:31:56 +0000

你基本上有三种可能:

  1. localhosthost1的隧道:

  2. localhosthost1的隧道和从host1host2的隧道:

  3. localhosthost1的隧道和从localhosthost2的隧道:

通常情况下,我会选择方案一。如果从host1host2之间的连接需要保证安全,就选方案2。选项3主要是为了访问host2上的服务,而这些服务只能从host2本身到达。

158
158
158
2010-08-01 17:10:27 +0000

有一个很好的答案解释了ProxyCommand配置指令在SSH中的使用:

添加到你的~/.ssh/config中(详情请看man 5 ssh_config):

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

然后ssh host2会自动通过host1进行隧道(也适用于X11转发等)。

这也适用于一整类的主机,例如:

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

更新

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

Host host2
  ProxyJump host1
35
35
35
2016-08-10 09:11:34 +0000

OpenSSH v7.3以后的版本支持-J切换和ProxyJump选项,允许一个或多个逗号分隔的跳转主机,所以,你现在可以简单的这样做:

ssh -J jumpuser1@jumphost1,jumpuser2@jumphost2,...,jumpuserN@jumphostN user@host
20
20
20
2010-01-24 18:47:37 +0000

我们有一个SSH网关进入我们的私有网络。如果我在外面,想在私有网络内的机器上安装一个远程shell,我必须将ssh接入到网关,然后从那里到私有机器。为 ssh 协议(端口 22)建立一个到私有机器的隧道。

  1. 只有在成功的情况下,使用该隧道进入私人机器的ssh。由&&&操作者确保)。在关闭私有的ssh会话后,我想让ssh隧道也关闭。这是通过 “sleep 10 "技巧来完成的。通常情况下,第一个ssh命令会在10秒后关闭,但在这段时间内,第二个ssh命令会使用隧道建立连接。因此,第一条ssh命令会保持隧道开放,直到满足以下两个条件:睡眠10结束,隧道不再使用。
18
18
18
2012-01-11 11:02:06 +0000

看完上面的内容,把所有的东西都粘在一起后,我创建了下面的Perl脚本(保存为mssh在/usr/bin中,并使其可执行):

#!/usr/bin/perl

$iport = 13021;
$first = 1;

foreach (@ARGV) {
  if (/^-/) {
    $args .= " $_";
  }
  elsif (/^((.+)@)?([^:]+):?(\d+)?$/) {
    $user = $1;
    $host = $3;
    $port = $4 || 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(同一用户)。通过HOSTA和HOSTB访问HOSTC,使用非默认的SSH端口号和不同的用户:

mssh HOSTA HOSTB HOSTC
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
8
8
8
2013-03-13 09:57:28 +0000

这个答案和kynan类似,因为它涉及到使用ProxyCommand。 找到后我就发个链接。

6
6
6
2017-11-21 11:06:21 +0000

我做了我认为你想要的

ssh -D 9999 -J host1 host2

我被提示了两个密码,然后我可以用localhost:9999做一个SOCKS代理到host2。这是我能想到的最接近于你当初的例子。

4
4
4
2010-01-19 02:03:35 +0000
ssh -L 9999:host2:80 -R 9999:localhost:9999 host1

-L 9999:host2:80

-L 9999:host2:80

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

-R 9999:localhost:9999

意味着host1:9999收到的任何数据包都会转发回localhost:9999

2
2
2
2010-01-16 06:34:17 +0000

你应该可以使用端口转发来访问host2上的服务。好的指南位于 这里 。摘录:

端口转发有两种:本地转发和远程转发。它们也分别被称为出站隧道和入站隧道。本地端口转发是将来自本地端口的流量转发到指定的远程端口。注意,在连接建立后,localhost将由 sshdserver解析。在这种情况下,localhost因此指的是服务器(主机)本身。

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

例如,如果你发出命令

ssh2 -L 1234:localhost:23 username@host

所有来自服务器(主机)端口1234的流量将被转发到客户端(localhost)的端口23。

1
1
1
2019-12-18 04:08:37 +0000

我的答案其实和这里的其他答案都一样,但是,我想说明一下~/.ssh/config和ProxyJump的用处,

假设我需要分3次跳转到一个目的地,而且,每一次跳转,我都需要特定的用户名、主机、端口和身份。由于身份条件的限制,这只能通过~/.ssh/config配置文件来完成:

Host hop1
    User user1
    HostName host1
    Port 22
    IdentityFile ~/.ssh/pem/identity1.pem

Host hop2
    User user2
    HostName host2
    Port 22
    IdentityFile ~/.ssh/pem/identity2.pem
    ProxyJump hop1

Host hop3
    User user3
    HostName host3
    Port 22
    IdentityFile ~/.ssh/pem/identity3.pem
    ProxyJump hop2

从你的电脑上,你可以单独测试每一次跳转,即

$ ssh hop1 # will go from your PC to the host1 in a single step
$ ssh hop2 # will go from your PC to host1, then from host1 to host2, i.e. in two steps
$ ssh hop3 # will go from your PC to host1, then to host2, then to host3, i.e. in three steps

另一个很酷的地方是,这个文件还可以实现~/.ssh/config文件传输,比如

$ sftp hop1 # will connect your PC to host1 (i.e. file transfer between your PC and host1)
$ sftp hop2 # will connect your PC to host1 to host2 (i.e. file transfer between your PC and host2)
$ sftp hop3 # will connect your PC to host1 to host2 to host3 (i.e. file transfer between your PC and host3)
1
1
1
2017-03-18 20:13:02 +0000

在这个回答中,我将通过一个具体的例子来说明。你只需要把电脑的主机名、用户名和密码都换成你的即可。

问题陈述

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

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

为了具体化,假设我们有以下计算机的主机名、用户名和密码。

LocalPC <---> hostname: mit.edu <---> hec.edu
                          username: bob username: john 
                          password: dylan123 password: doe456
Host HEC
    HostName hec.edu
    User john
    ProxyCommand ssh bob@mit.edu -W %h:%p

目标:我们要设置一个SOCKS代理,在9991LocalPC端口上监听,这样每次从LocalPC端口发起的连接都要经过9991,然后再经过mit.edu

用例:为了安全起见,hec.edu有一个HTTP服务器,只在 http://127.0.0.1:8001 上访问。我们希望通过在hec.edu上打开网页浏览器,可以访问http://127.0.0.1:8001


配置

LocalPC中,在LocalPC中添加:

ssh -D9991 HEC

然后在~/.ssh/config的终端中运行: &001

,它会询问你LocalPC上的密码(即:。bob),然后在mit.edu上询问dylan123的密码(即。

这时,SOCKS代理服务器就在johnhec.edu端口上运行了。

例如,如果你想使用SOCKS代理访问doe456上的网页,在Firefox中可以这样做:

一些备注:

  • 9991中,LocalPC是连接名:你可以把它改成任何你想要的名字。
0
0
0
2020-02-22 07:13:01 +0000

只有这个在两个以上的主机上帮了我的忙:

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

会提示你有三个密码。
0
0
0
2018-07-26 05:24:38 +0000

在我的案例中,我做了

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

,其中host2:8890运行在Jupyter笔记本上。

然后我将Firefox配置为localhost:9999作为SOCKS主机。

0
0
0
2017-10-05 08:43:30 +0000

最佳答案](https://superuser.com/a/97007/72337)中的选项2可以使用不同的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
```。
0
0
0
2019-08-20 19:09:55 +0000

受け入れられた回答に記載されている3つのオプションは、私のために全く動作しませんでした。私は両方のホストにあまり権限を持っていないので、私たちのDevOpsチームは認証に来るときにかなり厳格なルールを持っているように見えるし、MFAを行っています。

状況は上記の回答と似ていますが、本番サーバに直接sshすることができず、ジャンプサーバを使って1ホップしなければなりません。

  1. 1. ジャンプサーバに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番ポートでのリクエストがジャンプサーバーに転送されます。それから順番に、私たちは前のステップで設定したので、ジャンプサーバーは再び保護された宛先サーバー上のポート2222にポート6969のリクエストを転送します。

あなたはいくつかのメッセージを印刷した後、そこにコマンドが “ハングアップ "するのが表示されるはずです - それは彼らが働いていることを意味しています! 一つの例外 - Could not request local forwarding. のようなエラーメッセージは表示されないはずですが、もし表示された場合は、まだ動作していません。あなたは今、あなたのラップトップからポート6969にリクエストを発射してみて、それが動作しているかどうかを確認することができます。