SSH端口转发详解

SSH端口转发(隧道)可以建立SSH通道,并将TCP链接放到这个通道中。

man ssh

选项及参数解释

首先我们通过man命令来查看一下ssh关于转发部分的说明,然后再详细讲解不同的转发方式是什么意思。

  1. 本地转发

image-20210110224549253

本地转发通过-L选项指定

-L选项后可跟多种形式的参数

1
2
3
4
-L [绑定地址:]端口:主机:主机端口
-L [绑定地址:]端口:远端Socket
-L 本地Socket:主机:主机端口
-L 本地socket:远端socket

链接到本地(ssh客户端)主机上的给定的TCP端口(unix socket)将被转发到**远端的给定的主机和端口(unix socket)**。这一过程指定了本地这一侧的TCP端口(同时可以指定绑定的地址),或unix socket。

​ (译注:就是指定[绑定地址:]端口这个参数,要么只提供端口,要么既提供地址也提供端口)

一旦有连接到本地端口或socket的链接,这个链接就会通过安全的通道进行转发,相当于作用在远端主机对应的端口或socket上。

​ (译注:前两个参数( [绑定地址:]端口)指定本地的地址和端口,后两个参数指定远端的地址和端口(主机:主机端口),对本地这个端口的访问,相当于作用在了远端的相应的端口上)

端口转发同样也可以在配置文件中指定。只有超级用户可以转发特权端口。IPv6地址可以用方括号括起来指定。

默认情况下,本地端口按照GatewayPorts设置进行绑定。但是,可以使用显示的绑定地址将链接绑定到特定的地址。使用localhost这个绑定地址表示监听的端口仅能本地使用,而不指定地址或使用*则表示监听的端口可以被所有接口所访问。

​ (译注:使用localhost仅能本地访问,相当于127.0.0.1,不指定或使用*,则相当于0.0.0.0)

  1. 远程转发

    image-20210110224639362

    远程转发通过-R选项指定

    -R选项后可接多种形式的参数

    1
    2
    3
    4
    5
    -R [绑定地址:]端口:主机:主机端口
    -R [绑定地址:]端口:本地socket
    -R 远端socket:主机:主机端口
    -R 远端socket:本地socket
    -R [绑定地址:]端口

    连接到远端(服务端)主机上给定TCP端口的链接会本转发到本地这一侧。这一过程分配了一个socket来在远端监听给定的TCP端口或unix socket。一旦有访问这个端口的链接,这个链接便会通过安全通道进行转发至本地这一侧,本地这一侧可以显示的指定主机主机端口或本地socket,或者如果没有显示指定本地这一侧的主机的话,ssh将充当socks 4/5代理,并将链接转发到远程socks客户机请求的目的地址

    ​ (译注:最后一句话如何使用暂不解释)。

    端口转发同样可以在配置文件中指定。特权端口只能登录远端机器的root用户进行转发。IPv6地址可以用方括号括起来指定。

    默认情况下,TCP仅监听本地环回接口的sockets。这一情况可以通过绑定地址来进行覆盖,空的绑定地址*,表示远端socket应该监听所有接口。只有远端服务的GatewayPorts选项打开,才可以指定远端的绑定地址

    如果端口参数是0,将会在服务端动态分配监听的端口,然后将端口返回客户端。如果同时使用-O选项,返回分配的端口将会输出在标准输出。

  2. 动态转发

    image-20210111144331152

    动态转发通过 -D选项指定

    -D选项后可跟如下形式的参数

    1
    -D [绑定地址:]端口

    本地动态应用级端口转发。这一过程会分配一个socket来监听本地侧的端口,可选是否指定绑定地址。一旦有链接访问这个端口,这个链接将会通过安全通道进行转发,并且应用协议决定了随后访问远端机器的哪个端口。目前支持SOCKS4SOCKS5,并且ssh将作为SOCKS服务端。

    只有root用户可以转发特权端口。动态端口转发可以通过配置文件指定。

    IPv6地址可以用方括号括起来指定。只有超级用户可以转发特权端口。

    默认情况下,本地端口受限于GatewayPorts的设置。但是显示的指定绑定地址可以用来指定具体的地址。使用localhost这个绑定地址表示监听的端口仅能本地使用,而不指定地址或使用*则表示监听的端口可以被所有接口所访问。

TCP FORWARDING

image-20210111145707861

可以通过命令行或配置文件通过安全通道转发任意TCP链接。一个可能的TCP转发应用场景是通过安全链接访问邮件服务或穿透防火墙。

在下面的例子中,我们看一下IRC客户端与服务器之间的加密通信,即便IRC服务器不直接支持加密通信。

这一工作流程如下:用户通过ssh指定了一个端口用来转发链接到远程主机,随后,在客户端机器开启了一个被加密的服务,链接到相同的本地端口(译注:这个本地端口就是上一句话提到的通过ssh指定了一个端口),ssh将会加密并转发链接

这个例子将从本地机器(127.0.0.1)到远程服务器(server.example.com)的IRC会话装入隧道。

1
2
$ ssh -f -L 1234:localhost:6667 server.example.com sleep 10
$ irc -c '#users' -p 1234 pinky 127.0.0.1

这个隧道连接到IRC服务器“server.example.com”,加入通道“#users”,昵称“pinky”,使用端口1234。使用哪个端口无所谓,只要大于1023(只有root用户可以使用特权端口),并且不能和其他已用的端口冲突。这个链接被转发到远程服务器的6667端口,这是IRC服务的标准端口

-f选项在后台运行ssh,并且远端执行命令sleep 10指定了被装入隧道中的服务开启的时间。如果在指定时间内没有链接,ssh将会退出。

自定义用例

  1. 本地转发

    本地转发示例如下。

    场景1

    考虑这样一个场景,主机A需要访问主机C上的一些服务,但由于安全问题主机C仅将主机B的IP加入了白名单中,而这时我们又已知可以在主机A上通过ssh链接到主机B。这时我们在主机A上可以通过主机B去访问主机C上的一些服务。

    我们在主机A上执行如下操作:

    1
    $ ssh -L 12345:ip_c:service_port user@ip_b

    其中,ip_c表示主机C的ip地址,service_port表示在主机C上运行的服务的访问端口,user表示主机B上你用的用户名,ip_b表示主机B的ip地址,12345表示主机A上的端口。这时,你访问ip_a:12345便相当于访问了ip_c:service_port

    场景2

    当然,有的时候我们可能只是想穿透防火墙,如下图所示,主机B的防火墙仅打开了22端口,但主机B上运行着许多服务,在防火墙外的主机A无法直接访问。这时我们也可以通过本地转发的方式来访问主机B上的一些服务。

    主机A上执行如下操作:

    1
    $ ssh -L 12345:localhost:80 user@ip_b

    这样访问主机A的12345端口,便相当于访问主机B的80端口,从而达到了穿透防火墙的目的。

  2. 远程转发

    在使用远程转发时,我们考虑这样一个场景,主机C上运行着一个服务,但是主机C没有公网ip,主机A无法直接访问服务。而主机B则有公网IP,这时又不想将主机C上的服务转移到主机B上。这时我们就可以考虑使用远程转发。

我们在**主机C**上执行以下操作:

1
ssh -R [ip_b:]port_b:ip_c:port_c user@ip_b

这样我们从主机A访问主机B的port_b端口,就相当于访问了主机Cport_c端口。

所以,通过这种方式也意味着,只要你有个公网ip的服务器,并不一定要将服务部署在服务器上,只要做好转发你就可以做很多事情。

其他选项

持久化ssh链接(ssh保活)

以下两种方式均可,推荐使用客户端配置

服务端配置

编辑服务器上/etc/ssh/sshd_config文件,增加如下内容,设置完成后需要重启sshd服务

1
2
3
4
# 服务器每隔60秒发送一次请求给客户端,实现保活
ClientAliveInterval 60
# 服务端发出请求后,客户端如果3次都没有响应,则自动断开连接
ClientAliveCountMax 3

客户端配置

编辑客户端上的/etc/ssh/ssh_config文件,注意与服务端不是同一个文件

1
2
3
4
# 客户端每隔60秒发送一次请求给服务端,实现保活
ServerAliveInterval 60
# 客户端发出请求后,如果服务端3次都没有响应,则自动断开连接
ServerAliveCountMax 3

其他参数

  • -N

    image-20210112202116993

    不执行远程命令,表示仅用来进行端口转发,常常与-T结合使用

  • -T

    image-20210112202204575

    不分配伪终端,

  • -f

    image-20210112202347594

    请求ssh在命令执行之前转到后台,如果ssh要求输入密码或密码短语,但用户希望在后台输入密码,那么这是非常有用的。这表示-n,在远程站点启动X11程序的推荐方法是使用ssh -f host xterm之类的工具。

    如果ExitOnForwardFailure选项被设置成yes,使用-f选项开启的客户端会等待所有远程端口转发成功建立链接后在将程序转入后台。

    要关闭这个后台链接,只能用kill命令去杀掉。

  • -C

    image-20210112204811052

    请求压缩所有数据,压缩算法和gzip相同,压缩在调制解调器线路和其他慢速连接上是可取的,但在高速网络上只会减慢速度。默认值可以在配置文件中按主机设置;请参阅压缩选项。

后台持久化执行端口转发

  • 修改/etc/ssh_config文件,设置保活时间

  • 使用下面命令执行端口转发

    1
    2
    # 以下ip和端口均为示例
    $ ssh -f -NTC -L 12345:192.168.2.123:12345 user@192.168.1.10