虽然现在办公PC大都是笔记本,轻便易携带,但是作为追求自由不希望有任何束缚的码农,就是希望下班之后双手插口袋,直接回家。不过有时回家后想看看办公PC上的文档,怎么办,难道要返回办公室或者拜托他人?本文讨论的方法,让你自己搞定不求人(虽然如此,但企业都有规章制度。。。另请大家遵纪守法)。
场景假设
- 办公PC处在防火墙后面,通过NAT路由访问互联网
- 普通员工,无权触碰防火墙和路由设置,管理员不会接受申请
目标
绝大多数同学应该符合上述场景的,现在目标就是在家远程连接办公室PC。
步骤
根据家庭网关的情况,有以下2种情况:
- 家庭网关有公网IP
- 家庭网关没有公网IP(现在有些运营商小区上网方式是NAT,不过你可以要求免费分配公网IP,但一般不固定,不过只要不重启网关,一般不会变)
本文讨论第一种情况,第二种情况另文讨论:家庭网关有公网IP
(请自行登陆家庭网关查看WAN侧IP,即公网IP)
步骤如下:
1, 家庭电脑上安装OpenSSH服务器并开启,准备好登陆用户名和密码(笔者使用Ubuntu16.04LTS,Windows也可以,安装设置方法不在此讨论)
2,家庭网关(带路由功能)设置端口转发:网关把WAN侧22端口请求转发到LAN的OpenSSH服务器(请设置固定IP),笔者使用的联通&烽火通信的HG220GS-U家庭网关,设置如下
3, 在办公室电脑上用SSH设置远端端口转发连接家庭OpenSSH服务器(SSH转发原理,见参考连接):办公电脑如果是Windows,可以用Putty(开源图形化SSH客户端),这里不具体介绍设置。笔者考虑到后续编写自动重连脚本方便,利用了办公室的另一台Linux机器作为转发平台
- 首先设置SSH客户端即使非Known Host也无需确认,直接连接,方便后续脚本自动执行,无需人工值守。
sudo vim /etc/ssh/ssh_config
找到并设置
StrictHostKeyChecking no
- 接下来,在该机器上运行命令如下:
sshpass -p 123 ssh -gfN -C -R 3389:10.100.99.207:3389 simon@1.2.3.4
上述sshpass是设置ssh登陆密码(123)以后续自动登陆不再提示输入密码(更好的做法是用公钥登陆)。
ssh后面R 3389:10.100.99.207:3389,表示远端机器在3389上监听,通过SSH通道到达本地后,转发到10.100.99.207:3389,也就是笔者的Windows PC(请提前设置后允许远程桌面,并开放防火墙端口)。
另外-gfN分别是g表示远端主机接受任何ip的转发请求,否则之接受本机的,f表示后台执行,N表示不执行远端命令,只是转发。
simon@1.2.3.4部分,请根据公网IP和自己ssh服务器用户设置。
- 好了,上述命令执行成功后,你就可以在家庭PC上连接办公室电脑了
如何查看是否与远程SSH服务器连接成功?
simon@jenkins:~$ netstat -an -t | grep :22
...省略...
tcp 0 0 192.168.1.102:44124 1.2.3.4:22 ESTABLISHED
...省略...
simon@jenkins:~$
发现本机(Linux)与远程1.2.3.4的tcp连接已经ESTABLISHED,就说明连接成功了。
在家庭电脑(笔者是Ubuntu)上打开Remmina(Linux桌面远程连接客户端,支持RDP,VNC,SSH等多种协议),编写连接
并点击连接,奇迹出现,办公室PC的桌面出现了
优化
- 考虑到办公室和家庭所在地的物理距离限制,本实验很难同时在办公室和家里操作,笔者写了段脚本运行在办公室的Linux机器上,思路时,如果与远程家庭SSH服务连接成功,则退出,否则尝试连接。然后设置cron每隔10分钟执行该脚本。
crontab设置
simon@jenkins:~$ crontab -l
*/10 * * * * ~/create_remote_foward_tun.sh 1.2.3.4 >> ~/create_remote_foward_tun.sh.log 2>&1
simon@jenkins:~$
create_remote_foward_tun.sh内容如下:
#!/bin/bash
#
#Usage:
# create_remote_foward_tun.sh remote_host_ip
# remote_host_ip - public ip where you want to connect from.
# Description:
# create a remote foward tunnel to connect pc in lan without special setting on firewall and router.
#
###########################################################################
if [[ -z $1 ]]; then
cat <<EOF
#Usage:
# create_remote_foward_tun.sh remote_host_ip
# remote_host_ip - public ip where you want to connect from.
EOF
exit 1
fi
#check route is ok
ping -n -c 2 $1 || { echo "no route to $1"; exit 2; }
is_connected=$(netstat -an -t | grep $1 | awk '{if(NR == 1) print $6}')
[[ $is_connected = "ESTABLISHED" ]] && { echo "already connected"; exit 3; }
sshpass -p 123 ssh -gfN -C -R 3389:10.100.99.207:3389 simon@$1
- 还可以,申请动态域名,这样就不用担心网关重启,公网IP变化了。
总结
通过SSH远端端口转发,实现了不需要安装特殊软件透明穿透公司防火墙即可在家连接办公室PC。注意是透明穿透哦,还可以把家里网关端口设置为80伪装成访问普通网站的样子,一般防火墙是无法检测到的,除非有异常长连接检测功能。有些软件如teamviewer,可以实现同样的功能,不过限制是只能在图形界面下使用,而且必须经过第3方服务器,管理员是很容易设置防火墙屏蔽到服务器之间的通讯,因为它是已知的。另外,对于喜欢折腾,爱好全手工打造的同学,不妨尝试也一下。最后为方便理解奉上网络拓扑如下:
通讯过程如下:
- 连接家庭SSH服务器,建立转发通道
A -> C -> D -> E - 连接办公室Windows PC,以及后续通讯
E -> D -> C -> A -> B
B -> A -> C -> D -> E
B和E的通讯,始终要经过A,为什么,因为只有A和E之间建立了通道,如果绕过A,则无法通讯,当然如果直接在B上连接SSH服务器,则没有A什么事了。
下一步
如果互联的2台终端都处在受保护的防火墙后面,都不能设置特权端口,还有没有办法呢?
答案是肯定的,不过也需要设置第3台服务器:
设置一台公网云服务器(VPS),客户端C(远程连接发起端)设置SSH本地转发连接到VPS,远程桌面R(远程连接接受端,也就是你的办公PC)设置远程转发连接到VPS。这样就实现 C -> VPS -> R
优化,C和R通过VPS建立通信之后,每次传输都要经过VPS,效率不高,可以通过VPS修改C和R的包头(目的IP:PORT,和源IP:PORT),让C和R后续直接通信(P2P)。估计不行,因为通道是SSH Over TCP/IP且加密的,VPS连接C和R是2个不同的加密通道,替换IP包的源和目的之后,即使C和R之间的包可以互相到达,但无法解密,依然无法通讯,需要VPS通知通讯双方采用某种一致的加密方式。。。慢慢研究。高人路过不吝赐教。
参考:
实战 SSH 端口转发