SSH 的正向代理和反向代理

场景

  1. 波波(技术实施人员)在客户处实施项目
  2. 能 SSH 访问客户服务器
  3. 能访问外网(包括咱公司公网服务器)
  4. 没有外网 IP,不能通过 SSH 被直接连接到
  5. 霸哥(研发人员)在公司内部局域网内,但是需要连接客户局域网内的客户服务器,进行调试

方案

  1. 波波使用 XShell(SSH)做两次代理:
  2. 将波波笔记本上的本地指定端口 9999 正向代理到客户服务器的 SSH 服务端口
  3. 将咱公司公网服务器远端指定端口 9527 反向代理到波波笔记本上的本地指定端口 9999
  4. 霸哥登录咱公司公网服务器,SSH 连接本地 9527 端口,经过波波的代理,连接到客户服务器的 SSH 服务端口

提示:HTTP 服务也可以通过类似步骤实现中转,通过访问我们本地指定端口,经过对方网络内的某一台机器中转,访问客户局域网内的 Web 服务。

步骤

  1. XShell 建立两个连接
  2. 客户服务器
  3. 咱公司公网服务器
  4. 切换到客户服务器连接的那个界面
  5. 点击界面上的查看 -> 隧道窗格
  6. 下面新出现的那一栏中切换到转移规则标签
  7. 鼠标右击,选择添加
  8. 类型:Local(Outgoing)
    源主机:localhost
    侦听端口:9999
    目标主机:localhost
    目标端口:客户服务器 SSH 端口,比如 22
    确定
  9. 切换到咱公司公网服务器连接的那个界面
  10. 点击界面上的查看 -> 隧道窗格
  11. 下面新出现的那一栏中切换到转移规则标签
  12. 鼠标右击,选择添加
  13. 类型:Remote(Outgoing)
    源主机:localhost
    侦听端口:9527
    目标主机:localhost
    目标端口:9999
    确定
  14. 在咱公司公网服务器上,通过以下命令实现对客户服务器 SSH 服务的访问:ssh <USER>@localhost -p 9527
    说明:<USER> 是客户服务器的用户名

原理

原理我并不清楚,不过我猜,可能是这样:

正向代理

  1. A 机器发起 SSH 连接(隧道 0),连接到 B 机器
  2. A 机器复制一个 SSH 连接(隧道 1)
    并且告诉 B 机器,建立一个指向你 22 端口的连接,然后:
  3. 将来自 SSH 连接(隧道 1)的数据都通过这个连接发出去
  4. 将来自这个连接的数据都通过 SSH 连接(隧道 1)发给 A 机器
  5. A 机器监听一个本地端口 9999,如果有程序连接到 9999 端口的话:
  6. 将来自 SSH 连接(隧道 1)的数据都通过这个连接发出去
  7. 将来自这个连接的数据都通过 SSH 连接(隧道 1)发给 B 机器

说明:

  1. A 机器,实际上是 A 机器上的 ssh 程序
  2. B 机器,实际上是 B 机器上的 sshd 程序

Linux 命令:

# -Nf 参数作用:连接连接之后不执行命令(通过 login 程序登录虚拟终端),关闭隧道 0,保持隧道 1,然后转入后台运行
ssh -NfL 9999:<B 机器>:22 localhost

反向代理

  1. A 机器发起 SSH 连接(隧道 0),连接到 C 机器
  2. A 机器复制一个 SSH 连接(隧道 1)
    并且告诉 C 机器,监听你的 9527 端口,然后,如果有程序连接到 9527 端口的话:
  3. 将来自 SSH 连接(隧道 1)的数据都通过这个连接发出去
  4. 将来自这个连接的数据都通过 SSH 连接(隧道 1)发给我(A 机器)
  5. A 机器建立一个指向本地端口 9999 的连接
  6. 将来自 SSH 连接(隧道 1)的数据都通过这个连接发出去
  7. 将来自这个连接的数据都通过 SSH 连接(隧道 1)发给 C 机器

Linux 命令

ssh -NfR 9527:localhost:9999 <C 机器>