2. Overview of ICE (ICE概述)
在典型的ICE部署中, 有两个希望通信的端点 (ICE代理, ICE agents)。请注意, ICE不适用于信令协议 (signaling protocol) 的NAT穿越, 信令协议假定通过另一种机制提供。ICE假定代理能够在彼此之间建立信令连接。
最初, 代理不知道自己的拓扑结构。特别是, 代理可能在NAT后面, 也可能不在NAT后面 (或多层NAT后面)。ICE允许代理发现关于其拓扑的足够信息, 以潜在地找到一条或多条路径, 通过这些路径可以建立数据会话。
图1显示了典型的ICE部署场景。代理标记为L和R。L和R都在各自的NAT后面, 尽管它们可能不知道这一点。NAT的类型及其属性也是未知的。L和R能够参与候选交换 (candidate exchange) 过程, 其目的是在L和R之间建立数据会话。通常, 此交换将通过信令服务器 (例如SIP代理) 进行。
除了代理、信令服务器和NAT之外, ICE通常与网络中的STUN或TURN服务器协同使用。每个代理可以有自己的STUN或TURN服务器, 或者它们可以是相同的。
+---------+
+--------+ |Signaling| +--------+
| STUN | |Server | | STUN |
| Server | +---------+ | Server |
+--------+ / \ +--------+
/ \
/ \
/ <- Signaling -> \
/ \
+--------+ +--------+
| NAT | | NAT |
+--------+ +--------+
/ \
/ \
+-------+ +-------+
| Agent | | Agent |
| L | | R |
+-------+ +-------+
图1: ICE部署场景
ICE背后的基本思想如下: 每个代理都有多种候选传输地址 (candidate transport addresses) (特定传输协议的IP地址和端口的组合, 在本规范中始终是UDP), 可以用来与其他代理通信。这些可能包括:
- 直接附加网络接口上的传输地址
- NAT公共侧的转换传输地址 ("服务器反射地址 (server-reflexive address)")
- 从TURN服务器分配的传输地址 ("中继地址 (relayed address)")
潜在地, L的任何候选传输地址都可以用来与R的任何候选传输地址通信。然而, 在实践中, 许多组合将不起作用。例如, 如果L和R都在NAT后面, 它们直接附加的接口地址不太可能能够直接通信 (毕竟这就是需要ICE的原因!)。ICE的目的是发现哪些地址对将起作用。ICE的工作方式是系统地尝试所有可能的对 (按照仔细排序的顺序), 直到找到一个或多个有效的对。
2.1. Gathering Candidates (收集候选)
为了执行ICE, ICE代理识别并收集一个或多个地址候选。候选具有传输地址 (transport address) -- 特定传输协议 (此处仅指定UDP) 的IP地址和端口的组合。有不同类型的候选; 一些是从物理或逻辑网络接口派生的, 其他候选可通过STUN和TURN发现。
第一类候选是那些具有直接从本地接口获得的传输地址的候选。这样的候选称为"主机候选 (host candidate)"。本地接口可以是以太网或Wi-Fi, 也可以是通过隧道机制获得的接口, 例如虚拟专用网络 (Virtual Private Network, VPN) 或移动IP (Mobile IP, MIP)。在所有情况下, 这样的网络接口对代理来说都显示为本地接口, 从中可以分配端口 (因此也可以分配候选)。
接下来, 代理使用STUN或TURN来获得额外的候选。这些有两种类型: NAT公共侧的转换地址 (服务器反射候选, server-reflexive candidates) 和TURN服务器上的地址 (中继候选, relayed candidates)。当使用TURN服务器时, 两种类型的候选都从TURN服务器获得。如果仅使用STUN服务器, 则仅从它们获得服务器反射候选。这些候选与主机候选的关系如图2所示。在此图中, 两种类型的候选都使用TURN发现。在图中, 符号X:x表示IP地址X和UDP端口x。
To Internet
|
|
| /------------ Relayed
Y:y | / Address
+--------+
| |
| TURN |
| Server |
| |
+--------+
|
|
| /------------ Server
X1':x1'|/ Reflexive
+------------+ Address
| NAT |
+------------+
|
| /------------ Local
X:x |/ Address
+--------+
| |
| Agent |
| |
+--------+
图2: 候选关系
当代理从IP地址和端口X:x发送TURN Allocate请求时, NAT (假设有一个) 将创建一个绑定X1':x1', 将这个服务器反射候选映射到主机候选X:x。从主机候选发送的出站数据包将被NAT转换为服务器反射候选。发送到服务器反射候选的入站数据包将被NAT转换为主机候选并转发给代理。与给定服务器反射候选关联的主机候选是"基础 (base)"。
注意: "基础 (Base)" 是指代理为特定候选发送数据时使用的地址。因此, 作为退化情况, 主机候选也有一个基础, 但它与主机候选相同。
当代理和TURN服务器之间有多个NAT时, TURN请求将在每个NAT上创建一个绑定, 但只有最外层的服务器反射候选 (最接近TURN服务器的那个) 将被代理发现。如果代理不在NAT后面, 则基础候选将与服务器反射候选相同, 服务器反射候选是冗余的并将被消除。
然后Allocate请求到达TURN服务器。TURN服务器从其本地IP地址Y分配一个端口y, 并生成一个Allocate响应, 通知代理此中继候选。TURN服务器还通过将Allocate请求的源传输地址复制到Allocate响应中, 通知代理服务器反射候选X1':x1'。TURN服务器充当数据包中继, 在L和R之间转发流量。为了向L发送流量, R向TURN服务器在Y:y发送流量, TURN服务器将其转发到X1':x1', 通过NAT映射到X:x并传递给L。
当仅使用STUN服务器时, 代理向其STUN服务器发送STUN Binding请求 [RFC5389]。STUN服务器将通过将Binding请求的源传输地址复制到Binding响应中, 通知代理服务器反射候选X1':x1'。
2.2. Connectivity Checks (连通性检查)
一旦L收集了所有候选, 它按从最高优先级到最低优先级的顺序对它们进行排序, 并通过信令通道将它们发送给R。当R从L接收候选时, 它执行相同的收集过程并用自己的候选列表响应。在此过程结束时, 每个ICE代理都有一个包含其候选和其对等方候选的完整列表。它将它们配对, 形成候选对 (candidate pairs)。为了查看哪些对起作用, 每个代理调度一系列连通性检查。每次检查都是客户端将在特定候选对上执行的STUN请求/响应事务, 通过从本地候选向远程候选发送STUN请求。
连通性检查的基本原则很简单:
- 按优先级顺序对候选对进行排序。
- 按优先级顺序对每个候选对发送检查。
- 确认从其他代理接收的检查。
当两个代理都对一个候选对执行检查时, 结果是一个4次握手:
L R
- -
STUN request -> \ L的
<- STUN response / 检查
<- STUN request \ R的
STUN response -> / 检查
图3: 基本连通性检查
重要的是要注意, STUN请求发送到和来自将用于数据的完全相同的IP地址和端口 (例如, RTP、RTCP或其他协议)。因此, 代理使用数据包的内容而不是接收数据包的端口来解复用STUN和数据。
因为STUN Binding请求用于连通性检查, STUN Binding响应将包含代理在代理与其对等方之间的任何NAT的公共侧的转换传输地址。如果此传输地址与代理已经学习的其他候选的地址不同, 它表示一个新的候选 (对等反射候选, peer-reflexive candidate), 然后像任何其他候选一样由ICE测试。
因为上述算法搜索所有候选对, 如果存在有效对, 算法最终将找到它, 无论候选以何种顺序尝试。为了产生更快 (和更好) 的结果, 候选按指定顺序排序。排序后的候选对列表称为"检查列表 (checklist)"。
代理通过定期为列表上的下一个候选对发送STUN请求来处理检查列表。这些称为"普通检查 (ordinary checks)"。当STUN事务成功时, 一个或多个候选对将成为所谓的"有效对 (valid pairs)", 并将添加到称为"有效列表 (valid list)" 的候选对列表中。
作为优化, 一旦R获得L的检查消息, R就会调度一个连通性检查消息, 在相同的候选对上发送给L。这称为"触发检查 (triggered check)", 它加速了查找有效对的过程。
在此握手结束时, L和R都知道它们可以在两个方向上端到端地发送 (和接收) 消息。
通常, 优先级算法的设计使得相似类型的候选获得相似的优先级, 以便更直接的路由 (即没有数据中继或NAT的路由) 优于间接路由 (具有数据中继或NAT的路由)。然而, 在这些准则内, 代理在如何调整其算法方面有相当大的自由裁量权。
数据流可能由多个组件 (components) 组成 (需要其自己的候选集的数据流片段, 例如RTP和RTCP)。
2.3. Nominating Candidate Pairs and Concluding ICE (提名候选对并结束ICE)
ICE将其中一个ICE代理分配为控制代理 (controlling agent) 的角色, 将另一个分配为受控代理 (controlled agent) 的角色。对于数据流的每个组件, 控制代理提名一个有效对 (从有效列表中) 用于数据。提名的确切时间基于本地策略。
在提名时, 控制代理让检查继续进行, 直到为数据流的每个组件至少找到一个有效对, 然后它选择一个有效对并在该对上发送STUN请求, 使用属性向受控对等方指示它已被提名。如图4所示。
L R
- -
STUN request -> \ L的
<- STUN response / 检查
<- STUN request \ R的
STUN response -> / 检查
STUN request + attribute -> \ L的
<- STUN response / 检查
图4: 提名
一旦受控代理接收到带有属性的STUN请求, 它将检查 (除非检查已经完成) 相同的对。如果上述事务成功, 代理将为这些对设置提名标志, 并将取消该数据流组件的任何未来检查。一旦代理为数据流的每个组件设置了提名标志, 这些对就成为选定对 (selected pairs)。之后, 只有选定对将用于发送和接收与该数据流相关的数据。
2.4. ICE Restart (ICE重启)
一旦ICE结束, 它可以由任一ICE代理随时为一个或所有数据流重新启动。这是通过发送指示重启的更新候选信息来完成的。
2.5. Lite Implementations (Lite实现)
某些ICE代理将始终连接到公共Internet, 并具有可以从任何通信者接收数据包的公共IP地址。为了使这些设备更容易支持ICE, ICE定义了一种称为"lite"的特殊实现类型 (与正常的完整实现相反)。Lite代理仅使用主机候选, 不生成连通性检查或运行状态机, 尽管它们需要能够响应连通性检查。