ngrok内网穿透原理浅析

2020年9月8日
ngrok内网穿透原理浅析插图

本文出自明月工作室:https://www.freebytes.net/it/network/ngrok%e5%86%85%e7%bd%91%e7%a9%bf%e9%80%8f%e5%8e%9f%e7%90%86%e6%b5%85%e6%9e%90.html

注:本文对ngrok实现内网穿透的原理的浅析,仅仅只是个人根据所学知识,所做的一些推论,并无任何官方认证。如有不同意见,欢迎评论。

第一次使用ngrok实现在公网下访问本地服务的时候,还是挺惊讶的。就很好奇是怎么实现的。查了一些资料,根据自己所学,结合分析了一下,推导出大致的流程。

NAPT原理

在内网中,对外只有一个公网IP。那么外网的信息是如何正确抵达到内网中的特定主机的呢?其实在NAT网关上会有一张映射表,表上记录了内网哪个主机向公网哪个IP和端口发起了请求,然后等公网主机发回了响应包之后,再根据响应包里面的目的IP地址和目的端口去映射表里面找到这个内网主机。

NAT网关所做的事情其实就是映射,在外部主机和内部主机之间做一个映射。但这种实现是被动的。也就是说,只要我本地主机不向公网某个ip发送消息,它就无法向我响应消息(或者说发起请求)。

ngrok的实现

但是ngrok,它却做到了由公网主动向内网主机发起请求。我运行了ngrok软件之后,它分配给我一个域名 https://5bf0cf5dd531.ngrok.io/ ,我在本地跑了80端口的服务之后,按这个域名访问,果然能访问到我本地。

这个域名很明显是个是泛域名,主域名是ngrok.io,也就是ngrok服务器的域名。所以我其实是访问到了ngrok的主服务器,再由ngrok反向代理到我本地服务的,并不是由域名直接访问到我的本地服务。

那么,ngrok的服务器上,就一定先得有一个映射表(原理类似于nat网关的映射),映射这个泛域名跟我的内网主机的关系。但问题就在于,我的内网主机是没有公网ip的,它如果想要直接跟我的主机ip做一个绑定,是行不通的。所以,这个泛域名,一定不是直接跟我的主机ip做映射的。

那要怎么办呢?它的服务器怎样才能访问到我的内网主机呢?

我们在使用ngrok的时候,要先运行一条指令:ngrok.exe http 80。一看就明白,这个指令的作用,无疑就是启动了一个服务,监听本地的80端口。是不是有点像nginx?但是它肯定比nginx多做了一件事——主动向ngrok的服务器发起请求,建立连接通道(类似socket通道)。

然后,在ngrok的服务器,只要将泛域名与这个通道做好映射,但凡接收到来自该域名的信息,都可以将其转发到这个通道,到达我的本机服务。

这样看起来,就好像是,直接打通了公网和内网主机的通道,所以叫内网穿透,之所以用80端口,是因为防火墙对它的流量进入管理很是宽松。不过归根到底,其实还是绕不开NAT网关的,即时是socket通道也是要经过这一层的。