RSTunnel
GitHub: JayGoldberg/RSTunnel 是一个可靠的SSH Tunnel的持续维护,但是它不需要 autossh 就可以工作。这个 RSTunnel
(可靠 SSH Tunnel)是一组 纯shell脚本 (兼容 /bin/sh
)用于维护从客户端到服务器的安全隧道。
autossh 的麻烦之处是它是 C 程序,需要为不同的架构平台编译,而获取交叉编译工具链并非易事,所以最好依赖大多数操作系统内置的二进制文件。 RSTunnel
目标是只使用 Shell ,而且兼容最简单的 ash
,以及能够兼容像dropbear SSH这种不常用的客户端。
简单查看一下
rstunnel
脚本,就可以看到关键的一句检查SSH Tunnel是否正常工作的语句:
nc
工具检查SSH Tunnel是否工作...
echo "test data" | timeout $NET_CONNECT_TIMEOUT nc localhost $CHECKPORT 2>&1 >/dev/null
if [ "$?" -ne 0 ]; then
ErrMsg ">> [ F A I L E D ]"
ErrMsg ">> Do you have a check port defined in your SSH config?"
InfoMsg "===> Attempting to restart tunnel"
TunKill; ErrorCheck "killing tunnel"
TunRun; ErrorCheck "starting tunnel"
MailUser
else
InfoMsg "===> Tunnel is up and running ()"
fi
...
脚本写得很精简,阅读可以理解原理以及辅助逻辑
CTunnel
备注
我比较习惯使用SSH config来控制SSH,所以我fork了RSTunnel改写了一个 CTunnel(持久化Tunnel) (还比较粗糙,待改进)
随脚本提供了一个
install
工具,用于通过交互方式完成安装,实际上就是生成一个rstunnel.conf
运行依赖
nc
命令,是通过netcat
工具包提供,所以需要确保安装:
netcat
来获得 nc
apt-get install netcat
nc 返回124状态码
我在主机上配置了每分钟执行一次 ctunnel
,发现没有正常检测出SSH tunnel的异常: 从外部访问NGINX显示 502 Bad Gateway
,说明SSH tunnel异常了。
登陆服务器检查,发现ssh进程存在(但应该是不工作了):
admin 616610 0.0 0.0 14968 5428 ? Ss 11:56 0:01 ssh: /home/admin/.ssh/47.116.4.160-22-admin [mux]
而是,确实是可以正常 ssh
进入服务器(速度很快),这说明SSH连接是正常的。
但是,根据我的配置,SSH端口转发却无法工作了:
从远端NGINX服务器上反向访问代理端口
127.0.0.1:24180
端口,这里使用telnet
模拟访问,显示立即被断开:
$ telnet 127.0.0.1 24180
Trying 127.0.0.1...
telnet: connect to address 127.0.0.1: Connection refused
telnet: Unable to connect to remote host
手工执行了一次 timeout 3 nc localhost 3128
,然后检查 echo $?
发现返回码是 124
我搞错了,原来通过 timeout 3
来执行,按照 man timeout
解释,如果命令超时,并且 --preserve-status
没有设置,就会返回退出码 124
。由于 nc localhost 3128
实际上成功以后是不结束的,通过 timeout 3
来结束,那么正常情况下拿到的就是 124
。
实际上脚本是通过如下检测:
NET_CONNECT_TIMEOUT=3
CHECKPORT=3128
echo "test data" | timeout $NET_CONNECT_TIMEOUT nc -v localhost $CHECKPORT 2>&1 >/dev/null
我检查发现这种只检查正向端口转发并不能反映反向端口转发的状态。例如,这里检查 ssh 登陆服务器是正常的,正向端口转发 3128 也是正常的,但是反向端口转发就是失败的。
所以脚本要修订为先远程登陆到服务器执行反向端口转发检查:
TUNNEL=aliyun
NET_CONNECT_TIMEOUT=3
CHECKPORT=24180
ssh $TUNNEL "echo 'test data' | timeout $NET_CONNECT_TIMEOUT nc -v localhost $CHECKPORT 2>&1 >/dev/null"
此时,如果远程服务器反向端口转发异常,会返回:
nc: connect to localhost port 24180 (tcp) failed: Connection refused
nc: connect to localhost port 24180 (tcp) failed: Connection refused
$ echo $?
1
修订了 ctunnel
,在上述失败情况下杀掉ssh进程重连。
不过,我发现一个问题,ssh登陆到远程服务器上检查,如果网络联通,会有两个返回值,一个失败一个成功:
nc: connect to localhost port 24180 (tcp) failed: Connection refused
Connection to localhost 24180 port [tcp/*] succeeded
为什么ssh反向 RemoteForward
端口明明是打开的,为何会有两条记录,一个失败一个成功?
我验证发现,似乎这种SSH端口转发情况下,都会出现一条失败( (tcp) failed: Connection refused
),然后接下来就是成功记录( port [tcp/*] succeeded!
),不过不影响最后的检查结果( $?=0
)