WebRTC ICE 交互流程介绍

WebRTC P2P 打洞原理 中,我们大致了解了 P2P 的打洞原理。但实际情况比理论要复杂得多。经典的 NAT(NAPT)可分为完全圆锥型、受限圆锥型、端口受限圆锥型和对称型四种,需要借助 ICE(Interactive Connectivity Establishment,交互式连接建立)框架辅助连接。

之所以强调是经典的,是因为这四种类型最早由 RFC 3489 定义;但后来的实践证明市场上的 NAT 实现远不止这四种类,于是便在 RFC 5389 中做了修正。不过这并不妨碍我们简单理解 ICE 的交互过程。本文依然以经典的 NAT 类型为主。

完全圆锥型

WebRTC ICE 交互流程介绍

完全圆锥型满足:一旦内部地址 iAddr:iPort 映射到外部地址 eAddr:ePort ,所有发自 iAddr:iPort 的数据包都经由 eAddr:ePort 向外发送;且任意外部主机发送的数据包都能经由 eAddr:ePort 到达 iAddr:iPort 。

受限圆锥型

WebRTC ICE 交互流程介绍

受限圆锥型满足:一旦内部地址 iAddr:iPort 映射到外部地址 eAddr:ePort ,所有发自 iAddr:iPort 的数据包都经由 eAddr:ePort 向外发送;但只有曾经接收到 iAddr:iPort 发送的数据包的外部主机 nAddr:any 发送的数据包,才能经由 eAddr:ePort 到达 iAddr:iPort 。注意,这里的 any 指外部主机源端口不受限制。即受限圆锥型限制了可以发送数据包的外部主机的 IP,但没有限制外部主机的端口号。

端口受限圆锥型

WebRTC ICE 交互流程介绍

端口受限圆锥型在受限圆锥型的基础上,加上了对外部主机的端口号限制,即只有曾经接收到 iAddr:iPort 发送的数据包的外部主机 nAddr:nPort 发送的数据包,才能经由 eAddr:ePort 到达 iAddr:iPort 。

对称型

WebRTC ICE 交互流程介绍

对称型的场景比较复杂一些。我们将内部地址 iAddr:iPort 与外部主机 nAddr:nPort 的地址和端口号组成一个四元组 (iAddr, iPort, nAddr, nPort) ,对于四元组中的不同取值,NAT 都会对应分配一个外部地址 eAddr:ePort ;并且也只有曾经收到内部主机数据的对应的外部主机,才能够把数据包发回。

ICE

从上述描述可以看出,外部主机和位于 NAT 之后的设备进行通信的难度是逐步提升的,即「完全圆锥型 < 受限圆锥型 < 端口受限圆锥型 < 对称型」。

对于圆锥型,我们依然可以使用 上篇文章 中介绍的通过公网服务器做地址转发的方式打洞连接。但对于对称型,只能使用公网服务器做流量中继的方式进行连接,因为对于四元组中的不同取值,NAT 都会对应分配一个外部地址 eAddr:ePort ;所以对称型与公网服务器进行连接并被交换的外部地址,并不是对端能连接成功的外部地址。

所以正如本文开头提到的那样,对于不同的 NAT 类型,我们需要借助 ICE(Interactive Connectivity Establishment,交互式连接建立)框架使用不同的方式进行打洞,这个框架能让两端能够互相找到对方并建立连接。大致流程如下:

  1. TCP 直接连接时,通过 HTTP 端口或 HTTPS 端口。
  2. UDP 直连时,使用 STUN(Session Traversal Utilities for NAT)服务器做地址转发。
  3. 间接连接均使用 TURN(Traversal Using Relays around NAT)服务器做流量中继。

当然,NAT 自己不会告诉服务器它是什么类型的,我们需要一套交互式策略检测对应的类型,而检测工作一般是由 STUN 服务器完成的。

STUN

STUN(Session Traversal Utilities for NAT,NAT 会话穿越应用程序)是一种允许位于 NAT 之后的客户端找出自己的公网地址,并判断出 NAT 限制其直连的方法的协议。

下图是 RFC 3489 中给出的 STUN 工作流程。其中不可避免地涉及到了 STUN 协议的一些细节,但其实读者不需要对 STUN 协议特别了解也能大致理解该流程。

WebRTC ICE 交互流程介绍

在测试 1 中,客户端发送的 STUN Binding Req 既不需要设置 CHANGE-REQUEST 属性中的任何标志位,也不需要设置 RESPONSE-ADDRESS 属性;服务器会向 Req 对应的地址和端口号发送 Binding Resp。如果客户端没有收到 Resp,则说明所在网络禁用了 UDP;如果客户端收到了 Resp,则会检查 Resp 的 MAPPED-ADDRESS 属性,如果其中的地址和端口号与 Req 对应的地址和端口号相同,则说明此时客户端至少不在 NAT 之后。然后进行测试 2。

在测试 2 中,客户端发送的 STUN Binding Req 需要同时设置 CHANGE-REQUEST 属性中的「改变 IP」和「改变端口号」标志位。如果客户端没有收到 Resp,则说明此时客户端位于对称型 UDP 防火墙之后(一种类似对称型 NAT 的防火墙);如果客户端收到了 Resp,则说明此时客户端可以直接访问公网(或者,至少位于一个类似完全圆锥型 NAT 的防火墙之后)。这里防火墙与 NAT 的区别是,防火墙没有地址转换(translation)。

回到测试 1,如果客户端发现 Resp 的 MAPPED-ADDRESS 属性中的地址和端口号与 Req 对应的地址和端口号不同,则说明此时客户端位于 NAT 之后。然后进行测试 2,如果客户端收到了 Resp,则说明此时客户端位于完全圆锥型 NAT 之后;如果客户端没有收到 Resp,则再次进行测试 1,只不过这次客户端发送的目标地址和端口号取自之前测试 1 的 Resp 的 CHANGED-ADDRESS 属性中的地址和端口号。对比前后两次测试 1 返回的 Resp 的 MAPPED-ADDRESS 属性中的地址和端口号,如果存在不同,则说明此时客户端位于对称型 NAT 之后;否则位于受限圆锥型 NAT 或者端口受限圆锥型 NAT 之后,为了搞清楚具体是哪一种,我们还需要进行测试 3。

在测试 3 中,客户端发送的 STUN Binding Req 仅需要设置 CHANGE-REQUEST 属性中的「改变端口号」标志位。如果客户端没有收到 Resp,则说明此时客户端位于端口受限圆锥型 NAT 之后;如果客户端收到了 Resp,则说明此时客户端位于受限圆锥型 NAT 之后。

当然啦,如果客户端和服务器之间有多个 NAT,则上述 STUN 流程将会推断出整个链路中限制最严格的那个 NAT 类型。客户端也需要定期重试,检查网络状态是否发生了变化。

TURN

由于对称型 NAT(或防火墙)无法被穿越,我们需要一种名为 TURN(Traversal Using Relays around NAT,NAT 中继遍历程序)的服务器来转发流量。

位于对称型 NAT 之后的客户端需要先在 TURN 服务器上创建连接,然后告诉所有对端设备发包到这个服务器上,然后服务器再把包转发给这个客户端。并且 TURN 服务器通常是和 STUN 服务器成对出现的,当 STUN 判断 NAT 为对称型时,就会交由 TURN 处理。


以上就是对 ICE、STUN、TURN 的介绍了。实际的 ICE 过程要比本文介绍的复杂得多,感兴趣的读者可以自行阅读 RFC 5245。当然,我们也没有必要自己实现一套 ICE 框架,常用的第三方 RTC 框架比如 mediasoup 均已实现了 ICE,直接使用即可。

作者:mthli
原文链接:https://webrtc.mthli.com/basic/ice-stun-turn/

版权声明:本文内容转自互联网,本文观点仅代表作者本人。本站仅提供信息存储空间服务,所有权归原作者所有。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至1393616908@qq.com 举报,一经查实,本站将立刻删除。

(1)

相关推荐

发表回复

登录后才能评论