这篇文章主要介绍了如何利用SSH 反向隧道穿透NAT,并演示了如何维持一条稳定的SSH 隧道。
假设有机器A 和B,A 有公网IP,B 位于NAT 之后并无可用的端口转发,现在想由A 主动向B 发起SSH 连接。由于B 在NAT 后端,无可用公网IP + 端口 这样一个组合,所以A 无法穿透NAT,这篇文章应对的就是这种情况。
这里默认你的系统init 程序为systemd
首先有如下约定,因为很重要所以放在前面:
机器代号 | 机器位置 | 地址 | 账号 | sshd/ssh端口 | 是否需要运行sshd |
A | 位于公网 | abc.cn | usera | 20000 | 是 |
B(需要被访问的机器) | 位于NAT之后 | localhost | userb | 22 | 是 |
C(客户端) | 客户端 | localhost | userc | 不需要 | 否 |
SSH 反向隧道
这种手段实质上是由B 向A 主动地建立一个SSH 隧道,将A 的 20002 端口转发到B 的 22 端口上,只要这条隧道不关闭,这个转发就是有效的。有了这个端口转发,只需要访问A 的 20002 端口反向连接B 即可。
首先在A公网机器上面创建用户 usera,并配置密码为 redhat
A $ useradd usera $ echo "redhat" |passwd usera --stdin
在B 上机器上建立一个 SSH 隧道,将 A 的 20002 端口转发到 B 的 22 端口上:
B $ ssh -p 20000 -qngfNTR 20002:localhost:22 usera@abc.cn 然后输入密码 B机器执行进程查看命令就有以下进程 ssh -p 20000 -qngfNTR 20002:localhost:22 usera@abc.cn
然后在A 上利用 20000 端口反向 SSH 到 B:这里其实还是 B 机器和 A 机器的 20000 端口在通信,20002 端口是为了客户端可以连接,如果是本地连接,防火墙不用放开
A $ ssh -p 20002 userb@localhost
要做的事情其实就是这么简单。A 机器就可以连接到 B 机器了
隧道的维持,稳定性维持
然而不幸的是 SSH 连接是会超时关闭的,如果连接关闭,隧道无法维持,那么 A 就无法利用反向隧道穿透 B 所在的 NAT 了,为此我们需要一种方案来提供一条稳定的 SSH 反向隧道。
一个最简单的方法就是 autossh,这个软件会在超时之后自动重新建立 SSH 隧道,这样就解决了隧道的稳定性问题
下面在 B 上做之前类似的事情,不同的是该隧道会由 autossh 来维持:
-M 参数指定的端口用来监听隧道的状态,与端口转发无关,可以忽略。下面的没有使用密码,而是事先将 B 的公钥添加到 A 主机的 usera 用户下面
B $ /bin/autossh -p 20000 -M 30002 -NR '*:20002:localhost:22' usera@abc.cn
之后你可以在 A 上通过 20002 端口访问 B 了:
A $ ssh -p 20002 userb@localhost
整合方案
在 A 上创建 usera 用户,看上面
如果 B 重启隧道就会消失。因此将 B 上服务制作成systemd服务
首先在A 上编辑sshd 的配置文件 /etc/ssh/sshd_config,将GatewayPorts 开关打开,只有打开这个,20002 端口才可以被外面的机器访问,监听地址为 0.0.0.0。如果只在 A 机器访问,则不用:
GatewayPorts yes
然后重启sshd:
A $ systemctl restart sshd
紧接着在B 上创建SSH 密钥,并上传到A:
B $ ssh-keygen B $ ssh-copy-id usera@abc.cn
注意该密钥不要设置密码,也就是运行ssh-keygen 指令时尽管一路回车,不要输入额外的字符。
然后在 B 上创建将下面文本写入到文件 /etc/systemd/system:
cat autossh.service [Unit] Description=Auto SSH Tunnel After=network-online.target [Service] Type=simple ExecStart=/bin/autossh -p 20000 -M 30002 -NR '*:20002:localhost:22' usera@abc.cn ExecReload=/bin/kill -HUP $MAINPID KillMode=process Restart=always [Install] WantedBy=multi-user.target
然后设置该服务自动启动:
B $ systemctl daemon-reload && systemctl enable autossh && systemctl start autossh
A节点防火墙放行
cat /etc/sysconfig/iptables -A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT -A INPUT -p tcp -m multiport --dports 20000,20002 -m state --state NEW -j ACCEPT
然后你可以在 A 上使用这条反向隧道穿透 B 所在的NAT SSH 连接到 B:
A $ ssh -p 20002 userb@localhost
或者是在 C 上直接穿透两层 NAT SSH 连接到B:
C $ ssh -p 20002 userb@abc.cn
参考文档:http://arondight.me/2016/02/17/%E4%BD%BF%E7%94%A8SSH%E5%8F%8D%E5%90%91%E9%9A%A7%E9%81%93%E8%BF%9B%E8%A1%8C%E5%86%85%E7%BD%91%E7%A9%BF%E9%80%8F/
–
–
–
评论前必须登录!
注册