反向 SSH 实现内网穿透

发布于 2025-01-21 12:36:10 字数 7692 浏览 1 评论 0

最近实验室又配置了一台新的计算平台,噪声堪比飞机起飞,再加上本校区不允许实验过夜, 只能将其安置在学校外面。但从学校到计算平台车程 40 Km,每次都过去做计算显然不现实, 如果能从学校直接远程连接是最好的。

通过相关资料的查询及对专业人士的请教,找到如下几种解决方法:

  1. 联系网络运营商将动态 IP 转为静态的公网 IP,这样就可以直接从学校的内网连接到计算平台,是最完美的解决方案。但是查询资费后发现,价钱不那么完美,一个月 6000 块大洋怎么负担得起啊!
  2. 主机 A 使用 TeamViewer 连接至计算平台局域网下的另一台主机 B,再控制 B 使用 SSH 连接至计算平台。这种方法包含几个明显的弊端:
    1. 操作麻烦,需要经过两层的文件传输及控制;
    2. 虽然 TeamViewer 有个人的免费使用许可,但最近审查日益严格,经常使用几分钟就被强制下线;
    3. TeamViewer 基于 GUI 远程控制,对网络要求很高;
    4. 最重要的一点,一个好的解决方案应该形成一个"黑箱",而不应该把内部细节暴露给用户;
  3. 从计算平台使用反向 SSH 连接到云服务器,从而建立起从云服务器到计算平台的隧道连接。这种方法传输的速度上限在于云服务器的带宽,最大的优点在于实现了一个“鸭子类型”,使用 SSH 连接计算平台与连接局域网内的主机无异。

0.1SSH 协议与应用

SSH 为 Secure Shell 的缩写,由 IETF 的网络小组(Network Working Group)所制定; SSH 为建立在应用层基础上的安全协议。SSH 是目前较可靠,专为远程登录会话和其他网 络服务提供安全性的协议。利用 SSH 协议可以有效防止远程管理过程中的信息泄露问题。 SSH 最初是 UNIX 系统上的一个程序,后来又迅速扩展到其他操作平台。SSH 在正确使用 时可弥补网络中的漏洞。SSH 客户端适用于多种平台。几乎所有 UNIX 平台---包括 HP-UX、Linux、AIX、Solaris、Digital UNIX、Irix,以及其他平台,都可运行 SSH。

以上对 SSH 的解释来自 百度百科 ,别问我为什么不用 Wikipedia。从中我们看到,SSH 是 建立在应用层基础上的一种安全协议,可以用来进行远程控制,或在计算机之间传送文件, 比传统的 telnet 或 ftp 协议要更安全。Linux 下最常使用的就是 OpenSSH。OpenSSH 是 SSH 协议的免费开源实现,提供了服务端后台程序(SSH Daemon)和客户端工具(SSH Client)。主机可以通过 SSH 客户端连接运行了 SSH 服务端的主机。

0.2 网络拓扑分析

互联网是一张巨大的网,其中所有的主机都由有线或无线的方式相连,但并不代表任意两台 主机都能互相可见。网络是有方向的,与其说是网我觉得更像一棵树。网络在向下进行传输 时,会经过 NAT(Network Address Translation 网络地址转换),因此外网的主机无法直接 访问内网的主机。

在我们本次遇到的问题中,网络连接可表示为如下的拓扑结构。

各个主机的 IP 地址如下表所示

主机名IP用户名备注
计算平台 A10.0.0.100cal目标主机,处于内网
控制端 B192.168.1.100client控制主机,处于内网
云服务器 O123.123.123.123server公网服务器,起桥梁作用

其中 A、B 能够访问 O,但 O 不能访问 A、B,并且 A、B 之间不能直接互相访问。我们最 后要实现的目标就是使用 B 访问 A。

0.3 解决方法

通俗地说:就是在主机 A 上做到 O 的反向代理;然后在 O 上做正向的代理实现本地端口 的转发。

0.3.1 准备工作

A、B、O 上都要安装 SSH Client,A、O 上需要安装 SSH Daemon。

需要用到的 ssh 参数

  # 反向代理
  ssh -fCNR
  # 正向代理
  ssh -fCNL
  -f 后台执行 ssh 指令
  -C 允许压缩数据
  -N 不执行远程指令
  -R 将远程主机(服务器)的某个端口转发到本地端指定主机的指定端口
  -L 将本地机(客户机)的某个端口转发到远端指定主机的指定端口
  -p 指定远程主机的端口

0.3.2 反向代理

首先在 A 主机上操作,建立 A 到 O 的反向代理,具体命令为

  ssh -fCNR [O 主机 IP 或省略]:[O 主机端口]:[A 主机 IP ]:[A 主机端口] [O 主机的用户名 @O 主机 IP]

在这里我使用了 O 主机的 3333 端口,以及 A 主机的 22 端口,按照以上命令即为

  ssh -fCNR 3333:localhost:22 server@123.123.123.123

此时我们就将 O 的 3333 端口映射到了 A 的 22 端口,也就是说访问 O 的 3333 端口与 访问 A 的 22 端口效果相同。

使用 ps aux | grep 3333 命令来查看反向代理是否运行成功。

0.3.3 正向代理

接下来在 O 主机上操作。完成上一步的反向代理后,在主机 O 上运行如下命令应该就可以 登陆 A 主机。

  ssh -p 3333 cal@localhost

该命令的含义为,使用 cal 用户登陆本机的 3333 端口。上面已经说过,访问 O 的 3333 端口与访问 A 的 22 端口效果相同,那么我们就成功从 O 主机登陆了 A 主机。

但此时我们仍只能从 O 主机本机上登陆 A 主机,无法从其他主机登陆,因此需要再对 3333 端口进行一次端口转发,使其他主机可以访问。具体命令为

  ssh -fCNL [O 主机 IP 或省略]:[转发端口]:[O 主机 IP]:[被转发端口] [登陆 O 主机的用户名 @O 主机的 IP]

此处我们想要将 3333 端口转发到 2222 端口,因此转发端口为 2222,被转发端口为 3333。

  ssh -fCNL *:2222:localhost:3333 localhost

此处 * 表示允许任意其他主机访问,本机的用户名可省略。使用 ps aux | grep 2222 命 令来查看正向代理是否运行成功。此处 2222 端口为本地转发端口,负责与外网进行通信, 并将数据转发到 3333 端口,实现了可以从其他主机访问的功能。

0.3.4 展现奇迹的时候到了

到次为至,我们已经配置好了 A O 主机,那么我们可以从任意可联网的设备登录到计算平 台中去啦。指令为

  ssh -p 2222 cal@123.123.123.123

我们实现了从任意地方连入内网计算平台的连接!

0.3.5 这种反向代理是不稳定的

不幸的是这种 ssh 连接会因为超时和网络堵塞等原因而关闭,那么从的外网连通内网的通 道就无法维持了,为此我们需要维持稳定 ssh 反向代理隧道的方法。

0.3.5.1 配置 ssh key 实现免密登陆

在使用 ssh 进行连接时,每次都需要输入密码,一方面不安全,另一方面也为我们接下来 使用的自动化工具带来了阻碍。

首先登陆 A 主机,并运行如下命令生成公钥私钥对。中间的配置过程一路回车即可。

  ssh-keygen -t rsa -C "youremail@example.com"

此时就在 A 主机的 ~/.ssh/ 目录下生成了公钥与私钥对,接下来我们需要将公钥传到 O 主机上作为我们登陆的一个比对凭证

  ssh-copy-id server@123.123.123.123

此时,我们再使用 ssh server@123.123.123.123 登陆路 O 主机就不再需要密码了。

0.3.5.2 用 autossh 建立稳定隧道

从 A 主机到 O 主机的反向代理连接是不稳定的,也就是说,我们需要一个工具来时刻监听 着这个连接。一但断开,再次自动重新建立连接即可。幸运的是,已经有人写出了这个工具, 那就是 autossh!感谢开源!

CentOS 的官方仓库中并没有这个软件包,我们需要从源码编译安装

  sudo yum install wget gcc make
  wget http://www.harding.motd.ca/autossh/autossh-1.4e.tgz 
  tar -xf autossh-1.4e.tgz
  cd autossh-1.4e
  ./configure
  make
  sudo make install

至此我们已经安装好了 autossh,利用下面的命令来启动守护进程。

  autossh -M 7200 -fCNR 3333:localhost:22 server@123.123.123.123

autossh 命令的参数与 ssh 一致,不同的是我们需要指出的 -M 参数,这个参数指定一个 端口,这个端口是外网的 O 主机用来接收内网 A 主机的信息,如果隧道不正常而返回给 A 主机让它实现重新连接。

0.3.5.3 配置自动启动

我们需要将 autossh 命令配置在开机自动启动脚本中,免去了每次开机都需要重新运行脚 本的麻烦。

我们需要在 A 主机的 /etc/rc.d/rc.local 文件中添加如下内容

  /bin/su -c '/usr/local/bin/autossh -M 7200 -fCNR 3333:localhost:22 server@123.123.123.123' - cal

此命令表示,以 cal 用户运行 autossh 命令,这样我们就能够使用 cal 用户反向连接到 A 主机。

为了保险起见,我们需要为自启动脚本添加执行权限

  sudo chmod +x /etc/rc.d/rc.local

至此我们就建立好了稳定的连接隧道。

0.3.6 进一步优化

0.3.6.1 保持活连接

在测试中发现,如果一个连接长时间空置,那么就会冻结。反向代理连接也是一样,此时便 只能通过重启 A 主机使连接重置。为保持一个活连接(Keep alive),需要服务端或客户 端定时发送心跳包来确保连接活跃,此处我们选择配置服务端的心跳。

在 A 和 O 的 /etc/ssh/sshd_config 文件中添加如下内容

  # server 每隔 60 秒发送一次请求给 client,然后 client 响应,从而保持连接
  ClientAliveInterval 60
  # server 发出请求后,客户端没有响应得次数达到 3,就自动断开连接,正常情况下,client 不会不响应
  ClientAliveCountMax 3

0.3.6.2 Windows SSH Client 连接提示错误

使用 Windows 的 SSH Client 连接 Linux 运行的 SSH 服务端时,会提示 "ssh algorithm negotiation failed" 错误,导致此问题的原因是 ssh 升级后,为了安全,默认不再采用原 来一些加密算法,我们手工添加进去即可。

在 O 主机的 /etc/ssh/sshd_config 文件中添加如下内容

  # add crypt format for window ssh client
  Ciphers aes128-cbc,aes192-cbc,aes256-cbc,aes128-ctr,aes192-ctr,aes256-ctr,3des-cbc,arcfour128,arcfour256,arcfour,blowfish-cbc,cast128-cbc
  MACs hmac-md5,hmac-sha1,umac-64@openssh.com,hmac-ripemd160,hmac-sha1-96,hmac-md5-96
  KexAlgorithms diffie-hellman-group1-sha1,diffie-hellman-group14-sha1,diffie-hellman-group-exchange-sha1,diffie-hellman-group-exchange-sha256,ecdh-sha2-nistp256,ecdh-sha2-nistp384,ecdh-sha2-nistp521,diffie-hellman-group1-sha1,curve25519-sha256@libssh.org

0.4 参考文献

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据

关于作者

梦幻之岛

暂无简介

文章
评论
28 人气
更多

推荐作者

白云不回头

文章 0 评论 0

糖粟与秋泊

文章 0 评论 0

洋豆豆

文章 0 评论 0

泛滥成性

文章 0 评论 0

mb_2YvjCLvt

文章 0 评论 0

夜光

文章 0 评论 0

    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文