通过分析ngrok日志推测其实现原理和方式

通过分析ngrok日志推测其实现原理和方式

https://bob.kim/articles/2018/05/09/1525819680566.html

grok 是一个代理服务器,提供网络代理功能,例如:

    +---------------+

    |  ngrok server |

    +---------------+

         /          \

        /             \

+---------------+     \

|  ngrok client |      \

+---------------+        \

    |                       \

+---------------+       +---------------+ 

|     A app |       |      B app    |

+---------------+       +---------------+

有如下的条件:

1 A, B 是 2 个 应用程序,运行在内网中;

2 ngrok server 运行在公网服务器中;

3 ngrok client 与 A 运行在同一个系统中;

//========================================================================

如果 B 想与 A 进行交互,有如下的流程:

1 B 把数据发给 ngrok server;

2 ngrok server 把数据转发给 ngrok client;

3 ngrok client 把数据转发给 A;

4 A 处理数据,把需要返回给 B 的数据,返回给 ngrok client;

5 ngrok client 把数据转发给 ngrok server;

6 ngrok server 把数据转发给 B;

最终,A, B 就通过 ngrok 的转发,完成数据的交互;

//========================================================================

我们可以认为,ngrok 代理了 A 对象对外提供的业务,当 B 对象向与 A 交互的时候,只需要与 A 对象的代理 ngrok 交互就可以了;

那么,这一切交互过程,存在一定的“协议”通信;

下面讲解在交互过程中,涉及到的“协议”:

下面简称: client == ngrok client, server == ngrok server;

//========================================================================

(1) CMD = Auth

authentication --- 认证

client 向 server 进行认证注册;

client 启动,发送 CMD = Auth 命令给 server; 告诉服务器,我这个客户端需要连接到该服务器,进行“认证”; 例如:

{"Type":"Auth","Payload":{"Version":"2","MmVersion":"1.7","User":"","Password": "","OS":"darwin","Arch":"amd64","ClientId":""}}

//========================================================================

(2) CMD = AuthResp

authentication response --- 认证回应

server 给 client 回应 CMD = Auth 命令;例如:

{"Type":"AuthResp","Payload":{"Version":"2","MmVersion":"1.7","ClientId":"c53d9a89c0ff87c37f14be30ff1f0ecb","Error":""}}

//========================================================================

(3) CMD = ReqTunnel


request tunnel --- 请求隧道

client 向 server 请求隧道的建立;例如:

{"Type":"ReqTunnel","Payload":{"Protocol":"http","ReqId":"NWLRB","Hostname": "","Subdomain":"wkf168","HttpAuth":"","RemotePort":0,"authtoken":""}

client 把自己的信息发送给 server,请求 server 建立隧道;

Protocol --- 请求的协议
ReqId --- Client 的一个 ID 信息;
Subdomain --- 子域名


//========================================================================

(4) CMD = ReqProxy

request proxy --- 请求代理

server 发送给 client,请求 client 进行“代理业务”;例如:

{"Type":"ReqProxy","Payload":{}}

此时,client 创建一个 socket fd 连接到 server,server 就把 accept 到的 socket fd 作为“隧道”;

//========================================================================

(5) CMD = RegProxy

register proxy --- 注册代理

当 client 收到 server 的“请求代理”命令之后,可以给服务器发送“注册代理”命令,例如:

{"Type":"RegProxy","Payload":{"ClientId":"c53d9a89c0ff87c37f14be30ff1f0ecb"}}

其中,Client ID 是当前 client 的一个认证ID,是服务器携带 AuthResp 命令的时候,返回的信息;

此时,client 把这个 ID 发送给 sever,携带 RegProxy 命令,表示要注册成为一个代理;

//========================================================================

(6) CMD = NewTunnel

new tunnel --- 新建一个隧道;

server 收到 client 的注册代理命令之后,给 client 注册了一个代理的身份;

同时,把 client 在 server 的代理身份信息返回,例如:

{"Type":"NewTunnel","Payload":{"ReqId":"NWLRB","Url":"http://wkf168.ngrok.bob.kim","Protocol":"http","Error":""}}

此时,client 已经在 server 端完成了“代理身份”的创建,返回:

RegId --- 是 client 发送 ReqTunnel 命令时携带的一个 ID 信息;
Url --- 是 server 为当前这个 client 代理分配的一个 URL;

那么,当其他应用程序访问 Url 的时候,就把请求的数据,转发给当前的 client;

//========================================================================

此时,经过上面的这几个步骤,完成了“隧道”的建立;

那么,当有其他应用程序访问 Url 的时候,就有如下的命令交互:

//========================================================================

(7) CMD = StartProxy

start proxy --- 开始启动代理

例如:

{"Type":"StartProxy","Payload":{"Url":"http://wkf168.ngrok.bob.kim","ClientAddr":"183.14.133.76:49127"}}

当有应用程序访问 Url 的时候,ngrok server 接收到数据;然后,给 client 发送 StartProxy 命令,要求 client 开始启动代理服务;

那么,在 ReqProxy 命令中,server 给 client 发送该命令之后,client 就创建了一个 socket fd 连接到 server;

那么,我们定义这个 socket fd 为 fdA;

此时,这个 fdA 就作为一个“隧道”接口;

此时,client 也是从这个 fdA 隧道接口,接收到 “StartProxy” 命令;

那么,client 就新建一个 socket fd,连接到本地的 IP + PORT; 我们定义这个 socket fd 为 fdB;

最终,fdA 与 fdB 形成一个映射的关系对,有:

1 fdA 接收到的数据,转发给 fdB;

2 fdB 接收到的数据,转发给 fdA;

//========================================================================

(8) CMD = Ping --- 作为心跳包使用
(9) CMD = Pong --- 是 Ping 命令的回复

//========================================================================

如同 RTSP 协议一样,有:

1 Client 与 Server 之间,有一条 socket fd 作为“协议交互”使用的通道;

是收发上面提到的这个 CMD 指令;

2 Client 与 Server 再传输音视频数据的时候,需要建立新的 socket fd 来交互数据;

同理,在 ngrok 中,也是一样,ngrok client 开始的时候,创建一条 socket fd 与 ngrok server 连接,交互通信命令;

当 ngrok client 接收到 CMD = ReqProxy 命令的时候,就创建一条新的 socket fd,连接到 ngrok server,作为“数据交互”的隧道接口;

//========================================================================

所以,ngrok client 与 ngrok server 在进行隧道数据转发的时候,有如下的流程:

1 client 开始建立一条 socket fd 连接到 server,作为 CMD 命令交互通道;定义该 socket fd 为 fdA;

2 server 通过 fdA 给 client 发送 CMD = ReqProxy 命令; 请求 client 进行代理活动;

那么,client 就新建一条 socket fd 连接到 server,定义该 socket fdB;

3 server 接收到 fdB 的连接之后,给该接口发送 CMD = StartProxy 命令,要求该 fdB 接口开始进行代理活动;

最终,这条 fdB 就作为 client 与 server 交互转发数据的“隧道”接口;

 

更详细的源码级别的分析参考:https://blog.csdn.net/lyb3290/article/details/80239890

附件:
[ngrok客户端windows 64版_bob.rar]


如有疑问或同行交流欢迎加群讨论:铂金信息技术交流群 151258054

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值