SSH 隧道转发——筑梦之路

SSH
简介
SSH 会自动加密和解密所有 SSH 客户端与服务端之间的网络数据。但是,SSH 还同时提供了一个非常有用的功能,这就是端口转发

优点:linux自带,传输加密,支持socks代理

用法示例
相关参数:
-C :压缩数据传输。
-f :后台认证用户/密码,通常和-N连用,不用登录到远程主机。
-N :不执行脚本或命令,通常与-f连用。
-g :在-L/-R/-D参数中,允许远程主机连接到建立的转发的端口,如果不加这个参数,只允许本地主机建立连接。
-L :本地转发
-R :远程转发
-D :动态转发,即socks代理
本地转发(本地建立监听)
ssh -C -f -N -g -L <本地监听ip>:<本地端口>:<远程ip>:<远程端口> 用户名@目标IP -p <ssh端口>
ssh -C -f -N -g -L 0.0.0.0:1234:192.168.1.100:3389 root@192.168.2.101 -p 22
远程转发(远端建立监听)
ssh -C -f -N -g -R <远程ip>:<远程端口>:<本地ip>:<本地端口> 用户名@目标IP -p <ssh端口>
ssh -C -f -N -g -R 0.0.0.0:1234:192.168.5.2:3389 root@192.168.2.101 -p 22
注:如果远端不能监听0.0.0.0,以下两个方法:

1. 需要修改 ssh 配置/etc/ssh/sshd_config
   GatewayPorts 项写为 yes 
   重启ssh后即可监听0.0.0.0

2. 使用rinetd把监听在127.0.0.1转发到0.0.0.0上
动态转发(socks)
ssh -C -f -N -g -D <本地ip>:<本地端口> 用户名@目标IP -p <ssh端口>
ssh -C -f -N -g -D 0.0.0.0:1080 root@192.168.2.101 -p 22
socks代理上本地的1080端口,即可访问192.168.2.101的内网环境
#本地端口转发

如果应用程序的客户端和 SSH 的客户端位于 SSH 隧道的同一侧,而应用程序的服务器和 SSH 服务器位于 SSH 隧道的另一侧,那么这种端口转发类型就是本地端口转发。需要使用 -L 选项来创建。

命令格式:ssh -L [local_bind_addr:]local_port:remote:remote_port middle_host

ssh -L 10025:localhost:25 HostB

运行上面的命令后,SSH 客户端程序在主机 A 上监听了 localhost:10025(你可以用 1024 - 65535 之间的任意端口代替 10025,只要不与已有端口冲突就行)。所有在主机 A 上发往 10025 端口的消息都会通过 SSH 隧道转发到主机 B 上的 25 端口。接下来需要配置主机 A 上的邮件客户端程序,让它把消息发送到 localhost:10025。完成之后主机 A 上的邮件客户端就可以通过主机 B 上的 smtp 服务器收发邮件了。具体的数据包的流向为:

1 邮件客户端把数据包发送到 localhost(主机 A) 的 10025 端口

2 SSH 客户端把数据包加密并从主机 A 发送到主机 B 的 SSH 服务器

3 SSH 服务器把数据包解密并发送到 localhost(主机 B) 的 25 端口

从 smtp 服务器返回的数据包则是沿着原路返回以完成数据的双向传递。

#真实场景的本地转发

应用程序的客户端和 SSH 客户端分别位于 SSH 隧道同一侧的两台不同的主机上,而应用的服务器端和 SSH 服务器分别位于 SSH 隧道另一侧的两台不同的主机上。

ssh -g -L P:HostS:W HostB

应用 -g 选项后主机 A 不仅会监听 localhost 的 P 端口,还能够监听所有网络接口的 P 端口,所以主机 C 上的应用客户端就可以把消息发送到主机 A 的 P 端口。

#命令格式

ssh -L ::

SSH server host 是 SSH 服务器所在的主机, remote host 和 remote port 则分别指应用程序服务器所在主机和监听端口。如果 remote host 指定为 localhost 则认为应用程序服务器和 SSH 服务器在同一台主机上。

在结束本地端口转发之前还需要介绍另外两个选项,它们是 f 和 N。上面的命令在创建隧道的同时登录到远程主机,一般情况下我们不需要这个登录。况且一旦这个登录退出,隧道也会随之关闭。我们更期望的是能够创建在后台运行的隧道,这时就需要添加 f 和 N 选项

#远程端口转发

如果应用程序的客户端和 SSH 的服务器位于 SSH 隧道的同一侧,而应用程序的服务器和 SSH 的客户端位于 SSH 隧道的另一侧,那么这种端口转发类型就是远程端口转发。

所以,区分本地端口转发和远程端口转发主要是看 SSH 客户端与应用程序的哪一部分在 SSH 隧道的同一侧!远程端口转发的命令格式为:ssh -R [bind_addr:]remote1_port:host:port remote1

ssh -R ::

其它的细节两者基本也是一样的。但是远程端口转发不支持 -g 参数,这让我们很难实现类似下面的用例:

内网中主机 A 上运行 Jenkins 服务器监听本机 8080 端口,并运行 SSH 客户端。

外网中的主机 B 上运行 SSH 服务器。

希望可以通过远程端口转发的方式在主机 A 和 B 之间建立隧道,

然后外网的 Bitbucket 等代码管理服务可以通过 Webhook 的方式访问主机 B 从而触发 Jenkins 服务器中的 Build。

这个问题的根源在于我们执行下面的远程端口转发命令后:

$ ssh -R 18080:localhost:8080 HostB

主机 B 只能监听 localhost 的 18080 端口:

如何让 HostB 监听本机所有网络接口的 18080 端口呢? 需要通过修改 SSH 服务器的配置来实现这个功能!在 SSH 服务器的配置文件 /etc/ssh/sshd_config 中添加一行:

GatewayPorts yes

保存后重启 SSH 服务器,然后重新建立隧道:

此时主机 B 已经可以接受外部 webhook 的调用了。

#动态转发

相对于动态端口转发,前面介绍的端口转发类型都叫静态端口转发。所谓的 "静态" 是指应用程序服务器端的 IP 地址和监听的端口是固定的。试想另外一类应用场景:设置浏览器通过端口转发访问不同网络中的网站(比如在家里连接公司内网中的站点,哈哈)。这类应用的特点是目标服务器的 IP 和端口是未知的并且总是在变化,创建端口转发时不可能知道这些信息。只有在发送 HTTP 请求时才能确定目标服务器的 IP 和端口。在这种场景下静态端口转发的方式是搞不定的,因而需要一种专门的端口转发方式支持即 "动态端口转发"。SSH 动态端口转发是通过 Socks 协议实现的,创建动态端口转发时 SSH 服务器就类似一个 Socks 代理服务器,所以这种转发方式也叫 Socks 转发。

动态端口转发的命令格式为:ssh -D [bind_addr:]port remote 

$ ssh -D

例如:

$ ssh -D 11080 nick@xxx.xxx.xxx.xxx

注意,命令中不需要指定目标服务器和端口号。执行上面的命令后 SSH 客户端就开始监听本机 localhost 的 11080 端口。你可以把本机上浏览器网络配置中的 Socks 服务器指定为 localhost:11080。然后浏览器中的请求会被转发到 SSH 服务器端,并从SSH 服务器端与目标站点建立连接进行通信。

参考资料:

SSH隧道:端口转发功能详解 - 骏马金龙 - 博客园

ssh隧道使用 - micr067 - 博客园

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值