本文转载自微信公众号「小姐姐味道」,作者小姐姐养的狗 。转载本文请联系小姐姐味道公众号。
最近,有位像诗一样的朋友,充满了罗曼蒂克一样的堕落主义思想。他不想上班,不想工作,就想翘着腿躺在床上刷手机。作为又一个被优美的生活所摧残的青年,我深刻理解他的想法,他爱上了远程办公。他的电脑在公司,人在家,可以用类似TeamView一类的软件去做。另外,他还精通网络打洞技术,能够远程控制很多网络环境很复杂的机器。
什么叫打洞呢?其实就是内网穿透。
你可能有这样的需求:
- 调试一些支付回调接口,但是又想在本地的Idea中接受请求进行debug;
- 家里有一台性能非常霸道的机器,想要在上班时能够连上它,做一些不可告人的操作
- 手里有一大批broiler chicken,但对方在各种防火墙之内,你想要集中控制它
- 廉价的远程办公
- 远程控制手机打卡签到!
- 给客户做演示,懒得再搭建环境,想要直接访问自己机器上的程序...
不要着急,你所能想到的这些,看完本篇文章,都可以搞定。而且,不需要你亲自动手编码。
这些需求,有的是正当的,有的是邪恶的,这也体现了技术的两面性。工具在不同的人手里,会有不同的功效。比如到了xjjdog手里,它仅仅变成了一篇水文。
重回正题,为了让你能够上手应用这种内网穿透技术,你需要一台能够上网的云主机。要最便宜的那种就可以,它将作为我们的流量转发中枢。
1. 这是什么原理
?我们当然要拿一个比较正当的用途,来说明一下它的基本原理。打洞方式有很多,我们只介绍一种最直观、最简单的(严格来说,下面的介绍只属于隧道,为了描述方便,我们统称为打洞)。
要明白一个事实:“网络连接,是双向的。” 请铭记这个看起来再自然不过的特点,它将是我们接下来介绍的这种方式的根本。
拿支付例子来说。程序调用了微信或者支付宝的api进行支付后,平台会将支付结果通过回调地址通知我。
由于我的386机器在内网中,加上层层的路由器和交换机防火墙,再加上ipv4的珍贵性,微信根本找不到我。大隐隐于市,也不过如此吧。
幸运的是,我能上网!这可以说是公司对我的最大恩赐了。
遇到网络问题,最好的解决方式就是加上一个中间层。这和nginx有异曲同工之处。nginx通过加入一个配置,就可以把服务端的资源暴露到公网上。我们也使用类似的思路去解决,但这次,我希望的是把自己本地的386,暴露到公网上。
不能用nginx做反向代理,因为nginx同样访问不了处于墙内的我(淦)。
这时候,我们上面提到的基本事实,就起作用了。
加入一个中间层墙内翻译,再加入一个中间层墙外翻译。一旦它们连接上,不管是谁连接上谁,都能够相互进行流量转发。注意我们的箭头,正向的数据流动,和反向的数据流动,对于一个连接来说,并没有什么区别。
为了更明白的看一下这个过程。我画了两组端口图。红色防火墙左边的,就是本地机器;右边的,就是转发服务器。
刚开始的时候,转发服务器监听在7000端口。在本地机器上,进行了一个配置,告诉服务端:麻烦您再监听一个9090端口,当有数据请求到来的时候,麻烦通过你的客户端,转发到我的8080端口上。
这就是整个内网穿透的基本思路。
2. 实践一下
原理,只是赠送给对内网穿透有好奇心的同学。对于大部分人来说,直接用就对了! 谁有闲工夫去搞明白为啥发动机是怎么设计的。
需求催生工具。目前常用的开源工具,有很多比如zerotier、ngrok、frp等。下面以frp为例,来说明一下它的使用方式。
- https://github.com/fatedier/frp/
如果你看过上面的原理,就会发现它的配置,实在是很简单的。
首先,准备一台云主机。我们叫它server。
在server上,下载frp,解压。然后配置frps.ini。好家伙,只有两行,就是一个绑定端口。这证明了我们要在客户端的配置上下点功夫。
- [common]
- bind_port = 14000
接下来,在本地机器上操作,我们记做386。
在386上,下载相应平台版本的frp,解压。这次要修改的是frpc.ini文件。
- [common]
- server_addr = 139.202.186.135
- server_port = 14000
- [springboot-1]
- type = tcp
- local_ip = 127.0.0.1
- local_port = 8080
- remote_port = 9090
在这里,我们指定连上了server的14000。并告诉它,启动一个9090端口。当有请求的时候,转发到我386的8080端口。
在386上,已经用idea启动了一个springboot项目。当微信的支付回调,调到server的9090端口时,我就可以在idea里打断点进行调试了。
3. 两个小案例
我们再来看两种常见的操作系统完全控制。
对于Linux服务器来说,对外开放的一般是22端口。我们可以通过ssh来连接它。
- [ssh]
- type = tcp
- local_ip = 127.0.0.1
- local_port = 22
- remote_port = 6000
在本地,通过下面命令即可连接放在家里的机器。
- ssh -oPort=6000 test@x.x.x.x
同样的,要想远程控制windows,还是得首先把远程连接功能给打开。
在windows机器上,简单的配置一下端口就可以。因为它是通用的tcp连接,所以我们并不需要配置什么额外的东东。
- [RDP]
- type = tcp
- local_ip = 127.0.0.1
- local_port = 3389
- remote_port = 33891
可以看到,由于22和3389都是基于tcp协议的,所以这种转发配置,也简单的像是吃饭一样。
市面上的一些打洞软件,难的并不是技术,而是从业资格证书。毕竟,别人用你的服务,向外传输的内容,都是不得而知的。这时候如果没有运营证书或者严格的内容审查,就只能背锅。
讲完了打洞的原理和简单使用案例,我们有必要着重提一下它的安全性。
温馨提示:打洞请尤其注意它的安全。如果你是打通的ssh或者3389,请确保打了相关的补丁,并且采用了强密码。一般公司会采用方式管理远程访问,打洞可以说是直接绕过,是非常危险的行为。
如果你打的洞,被其他别有用心的人获得,通常会造成内网的崩溃。如果你的公司并不允许这种行为,就不要把公司内网的服务暴露到外面。
打洞还通常与泄密有关。一个被严格保密的内网系统,由于其中的一台机器能够上网,就可以把服务暴露出去供外部人员访问参考。
建议在打洞之前,先了解一下什么叫做“面向法律编程”。演示一类的打洞,需要经过公司授权;拒绝一切公司内网类的ssh和3389打洞。
否则,出了事情,被请到局子里喝茶去,就不太好了。
作者简介:小姐姐味道 (xjjdog),一个不允许程序员走弯路的公众号。聚焦基础架构和Linux。十年架构,日百亿流量,与你探讨高并发世界,给你不一样的味道。我的个人微信xjjdog0,欢迎添加好友,进一步交流。