完整SIP/SDP媒体协商概论-ICE概览

在前面的章节中,我们完整介绍了SIP中SDP的offer/answer交互流程。接下来,我们重点介绍关于SDP在WebRTC中的交互方式以及使用ICE来支持NAT处理的内容。一些读者可能注意到了,WebRTC技术虽然具有非常大的市场前景,但是因为本身和浏览器等其他工具的兼容性问题,发展的速度仍然没有想象的那么快,一些应用场景也不是太完善。很多针对ICE的规范也快速进行更迭。最近的一次更迭就是针对ICE的RFC5245规范已废除,使用了RFC8445。因为,RFC8445是2018年发布的最新的规范,因此,可能一些厂家的产品还没有完全实现对此规范版本的支持。所以,我们的讨论尽量按照RFC5245的规范来进行,也同时兼顾RFC8445的框架。提前说明,WebRTC中关于ICE的规范流程非常庞杂,笔者需要分成多个章节来解释。所以,在WebRTC/ICE章节需要花费一定的时间,如果读者对ICE没有兴趣的话或者暂时没有使用WebRTC技术的话,可以跳过关于WebRTC/ICE的介绍直接阅读SIP/SDP的部分内容


在本章节和后续章节的讨论中,笔者将根据RFC5245/RFC8445的规范架构,结合笔者的这篇历史文章来讨论WebRTC/ICE的技术内容。希望通过笔者完整的讨论,读者可以非常清楚了解WebRTC的流程,特别是关于ICE的处理。笔者在文章中使用的一些本规范的专有名词(例如,check 或者check list,事实上,在本规范中它具有特定的含义),可能没有直接以中文的名称来介绍,这样做的目的是为了保证不会产生歧义,所以笔者尽量使用规范中的专有名词来解释。所以,请读者在阅读时一定要注意。


说明:1)一些专有名词以前的章节中已经发布,这里不再介绍。2)笔者本人水平有限,文章中所使用的专有名词中文命名或解释可能和其他网上的的有所不同,建议读者参考RFC原文理解或者发邮件给规范起草人获得支持。


笔者会在接下来的章节中重点讨论关于ICE的背景介绍,ICE概览,ICE使用/ICE候选对象采集交互,ICE候选对象流程处理,执行连接性检查,结束ICE流程,ICE启动/选项等话题。


在前面的章节中,我们完整介绍了SIP中SDP的offer/answer交互流程。接下来,我们重点介绍关于SDP在WebRTC中的交互方式以及使用ICE来支持NAT处理的内容。一些读者可能注意到了,WebRTC技术虽然具有非常大的市场前景,但是因为本身和浏览器等其他工具的兼容性问题,发展的速度仍然没有想象的那么快,一些应用场景也不是太完善。很多针对ICE的规范也快速进行更迭。最近的一次更迭就是针对ICE的RFC5245规范已废除,使用了RFC8445。因为,RFC8445是2018年发布的最新的规范,因此,可能一些厂家的产品还没有完全实现对此规范版本的支持。所以,我们的讨论尽量按照RFC5245的规范来进行,也同时兼顾RFC8445的框架。提前说明,WebRTC中关于ICE的规范流程非常庞杂,笔者需要分成多个章节来解释。所以,在WebRTC/ICE章节需要花费一定的时间,如果读者对ICE没有兴趣的话或者暂时没有使用WebRTC技术的话,可以跳过关于WebRTC/ICE的介绍直接阅读SIP/SDP的部分内容,或者,如果读者仅想了解WebRTC技术和基本的工作原理的话,可以阅读:

完整WebRTC技术及应用概要

在本章节和后续章节的讨论中,笔者将根据RFC5245/RFC8445的规范架构,结合笔者的这篇历史文章来讨论WebRTC/ICE的技术内容。希望通过笔者完整的讨论,读者可以非常清楚了解WebRTC的流程,特别是关于ICE的处理。笔者在文章中使用的一些本规范的专有名词(例如,check 或者check list,事实上,在本规范中它具有特定的含义),可能没有直接以中文的名称来介绍,这样做的目的是为了保证不会产生歧义,所以笔者尽量使用规范中的专有名词来解释。所以,请读者在阅读时一定要注意。


说明:1)一些专有名词以前的章节中已经发布,这里不再介绍。2)笔者本人水平有限,文章中所使用的专有名词中文命名或解释可能和其他网上的的有所不同,建议读者参考RFC原文理解或者发邮件给规范起草人获得支持。


笔者会在接下来的章节中重点讨论关于ICE的背景介绍,ICE概览,ICE使用/ICE候选对象采集交互,ICE候选对象流程处理,执行连接性检查,结束ICE流程,ICE启动/选项等话题。


1

背景介绍

如果读者看过前面的SDP全解的读者可能已经了解,SIP使用了offer/answer结合模式,通过SDP消息来实现媒体传输,其最终目的是实现媒体流之间的创建和完整传输。ICE英文全名是Interactive Connectivity Establishment。RFC5245(更新的RFC6336)对ICE做了规定。一般简单的定义是:ICE=STUN+TURN+协商机制+协商路径


但是,因为网络越来越复杂,终端的环境也发生了根本变化,因此NAT问题也越来越多。RFC3235规范针对NAT(地址转换)发布了一个指导。很多相关的协议希望通过媒体流之间的点对点传输解决媒体本身的问题(例如,低时延,降低丢包,降低部署成本),但是在涉及到NAT环境时,通常会遇到一些问题,导致实际部署的难度大大增加。为了解决NAT的问题,很多针对性的技术规范增加了对NAT环境的支持,常见的规范如:

  • Application Layer Gateways (ALGs)
  • Middlebox Control Protocol (RFC 3303)
  • STUN(RFC 3489)
  • Realm Specific IP(RFCs 3102和3103)
  • SDP拓展支持(RFC 4566和RFC 3605)


随着技术本身的不断发展,这些针对NAT支持的规范也带来了很多突出的问题,它们都存在各自的优缺点。这样的话,网络管理就会增加很多的不确定性,给系统管理带来很多问题。为了解决这些问题,一些相关规范组织希望使用一种统一的解决方式或规范,并且这种协议可以提供灵活性来满足目前网络环境对NAT的支持。目前,市场上一致的

共识就是使用ICE技术(Interactive Connectivity Establishment)。此规范通过offer/answer模式定义ICE来支持基于UDP的媒体流NAT问题(当然,ICE也可以通过拓展支持ICE-TCP传输协议)。

技术进步的动力就是为了解决目前存在的问题。


ICE是offer/answer模式的一种拓展形式,通过在SDP的offer/answer消息中包含多个地址和端口,使用这些地址端口和其交互消息来检测点对点的连接性。在SDP中的地址和端口,以及其连接性检测是通过STUN来完成。注意,关于STUN的最新规范已经再次更新(更新时间为2020年),如果读者有兴趣做进一步研究,可参考RFC5389和RFC8489。除了STUN以外,ICE也使用了STUN的另外一个拓展协议-TURN(RFC5766)实现穿越转发。另外,因为ICE对每个媒体流进行了多地址和端口交互,它也允许地址选择支持多宿主和双栈主机(IPv4/IPv6),因此也不再支持RFC4091和RFC4092。


2

ICE概览

在一个比较典型的ICE部署环境中,至少需要两个终端需要互相进行通信。终端之间可以通过一些信令结合SDP的offer/answer模式来实现,例如,我们前面讲的SIP协议。读者需要注意,ICE的目的不是为了某些协议(例如SIP)的NAT穿越,关于SIP相关的NAT穿越是通过RFC5626规定的,如果读者有兴趣的话,可以查阅此规范。这里,ICE假设终端之间可以创建协议连接。具体来说,在ICE流程处理开始阶段,agents就忽略了它们本身技术属性。终端也可能在或不在NAT后,ICE允许终端获取到技术属性的足够信息,然后找到一个或多个潜在的路径,创建数据会话实现相互

图片均来自于互联网资源


联网资源


在以上示例是一个非常典型的ICE部署场景示例。两个终端分别标识为L(左边)和R(右边)。两个终端都有各自的NAT环境,双方也不清楚对端NAT的状态属性,左右双方终端都有意愿通过ICE候选对象交互实现通信。很多时候,双方的交互可能都使用SIP协议。对于双方终端,SIP服务器和NAT来说,在网络中,ICE经常使用STUN和TURN来保证所有对象的协同。每个终端agents可以支持自己独立的STUN和TRUN服务器,也可以同一STUN和TURN同一服务器。基本的ICE工作理念是: 针对传输协议(这里重点讨论UDP)每个agent都有各种候选地址(绑定了IP地址和端口),通过这种候选地址和对端agent实现通信。候选地址可能包括:附加到网络接口的传输地址(server reflexive 地址),NAT中公网侧的转换后的传输地址,从TURN分配到的传输地址(转发地址)。客观上存在这种可能,任何L侧的候选传输地址都用来和任何R侧的候选传输地址进行通信。但是,在实际场景中,过多的候选传输地址组合可能不能工作。例如,如果L侧和R侧双方都在NAT后的话,直接附加的网络接口地址可能不会直接通信,因此这里需要ICE介入。这里,ICE的目的是发现何种候选地址配对可以工作。ICE的工作方式是通过系统地尝试所有可能的候选配对(排序处理后),直到ICE找到一组或者多组可以工作的候选配对。ICE对Peers的检测配对需要经过六个步骤:


3

采集候选地址

如果需要执行ICE的话,agent首先需要确认候选地址。候选地址是一种特别的地址,它是由IP地址和端口的组合构成,其目的是支持传输协议(我们这里仅讨论UDP)。RFC8445定义了三种候选地址,一种是来自于物理网络接口,另外一种来自于网络的逻辑接口,还有一种是通过STURN或者TURN发现的候选地址。第一种类别的候选地址支持的传输地址直接从本地网络接口获得。这样的候选地址我们称之为“host candidate”,这样类型的本地地址可以从本地网络,WIFI,远端网络或者VPN的方式获得。对agent来说,这样的地址都可以通过分配获得,并且作为本地接口来使用。如果agent是一个多宿主主机的话,它可以从不同的IP地址获得候选地址。具体的候选地址如何获得取决于网络中peer(会话中另外一个agent)的位置。例如,如果agent支持了两个不同的IP地址的话(一个是内网地址,一个是外网地址),不同的peer就可以通过不同的地址和agent通信。


另外一种候选地址是agent使用STUN或TURN获得的额外的候选地址,这些候选地址主要表现为两种地址形式:NAT公网侧的已转换地址(server-reflexive 候选地址),TURN服务器分配的转发地址(relayed 候选地址)。这里读者一定要注意两种地址的获取方式。当使用TURN服务器时,以上两种候选地址都来自于TURN服务器分配地址;当仅使用了STURN服务器的话,agent只能获取到server reflexive地址。以下是候选地址的关系示例图:


候选地址关系


在以上关系图中,两种类型的候选地址都是通过TURN服务器发现获得的。这里的地址端口配对中,大写X表示IP地址,小写x表示UDP端口。当agent对IP地址和端口发送一个(X:x)TURN地址分配请求时,NAT(假设这里有NAT)就会创建一个绑定关系X1':x1',映射server-reflexive地址到主机候选地址。从本地主机候选地址发送出去的数据包将会通过NAT地址转换变成一个server-reflexive候选地址。同样的道理,从server-reflexive候选地址进入到主机候选地址的数据也是通过NAT地址转换完成。这里,base是一个比较重要的概念,需要读者明确,“base"是一个本地主机候选地址,它关联一个给定的server-reflexive候选地址。base指的是一个agent为指定的候选地址发出数据的地址。因此,有时存在一个比较极端的场景,主机候选地址也可以有自己的base地址,这个base 地址和主机候选地址相同。


当agent和TURN服务器存在多个NAT穿越时,TRUN请求会为每个NAT创建一个绑定,但是agent仅发现最外部的server-reflexive候选地址(距离TRUN服务器最近的候选地址)。如果agent不在NAT后的话,base 候选地址和server-reflexive候选地址相同,server-reflexive候选地址就会被移除。


Agent发出的分配请求到达TURN服务器端后,TURN服务器将会从它的本地IP地址Y中分配一个端口y,并且生成一个分配响应,分配响应通知一个agent的转发候选地址。TRUN服务器也会通知一个agent的server-reflexive候选地址X1':x1',通知的方式是把分配请求中的源传输地址拷贝到分配响应中来实现。TRUN服务器的工作角色类似于一个在L侧和R侧之间的数据转发。如果R侧想对L侧发送数据的话,R侧需要发送数据到Y:y 地址,然后TRUN服务器端前转到X1':x1'候选地址,然后经过NAT后映射到L侧agent。


当仅使用了STUN服务器时,agent发送一个STUN绑定请求给它的STUN服务器,STUN将会通知一个agent的server-reflexive候选地址X1':x1',其通知的方式是绑定请求中的源传输地址拷贝到绑定响应中。


Connectivity Checks

一旦L侧agent采集到它所有的后续地址后,它会把这些地址重新安装从最高到最低的排序,然后通过信令通道发送给R侧agent。这些候选地址通过SDP的offer消息的属性参数发送到R侧agent(开始使用offer/answer交互模式)。当R侧agent收到offer消息后,R侧的agent也会执行一个同样的流程来采集候选地址,然后通过响应消息返回自己的候选地址。双方采集发送流程完成以后,每个agent都有自己的完整的候选地址和对待peer的完整候选地址。通过双方候选地址的配对处理,最后产生一个候选配对。候选地址配对产生以后,agent首先需要知道哪个候选地址配对是可以工作的,每个agent会按时设定一系列的检查。每个检查是一个STUN请求响应的事务,每个终端都会执行具体的候选地址配对流程,配对流程检查通过本地候选地址对远端候选地址发送一个STUN请求。连接性检查(Connectivity Checks)的基本原理非常简单:

  1. 对候选地址配对进行优先级排序
  2. 按照优先级排序顺序对候选配对发送检查请求
  3. 确认从其他agent

因此,在执行候选配对检查时需要一个四次握手的处理:


基本候选地址配对检查四次握手处理流程


这里一定要注意,发送STUN请求的目的地和接收源的IP地址和端口,这是完全相同的IP地址和端口,使用此IP地址和端口来传输媒体流(包括RTP和RTCP)。因此,agent会通过数据内容多路分解STUN/RTP/RTCP相关数据,而不使用其接收端口来分解STUN/RTP/RTCP数据。相当于使用端口的方式来说,多路分解方式会更容易处理检查状态,特别是针对RTP和RTCP的数据。因为,STUN绑定请求是用来执行连接检查的,在STUN响应中包含了agent的已转译的传输地址,这个地址是agent和对端peer之间的NAT公网侧地址。如果这个传输地址和agent已学习过的候选地址不同的话,agent就会知道这个候选地址是一个新的地址(PEER REFLEXIVE CANDIDATE),这个新地址和其他候选地址一样,也是ICE测试过的地址。


他候选地址一样,也是ICE测试过的地址。


作为一种优化方式,只要R侧获得了L侧的检查消息,R侧会在同一候选配对中按时对L侧发送一个连接检查消息。这样的话,ICE就会加快发现有效候选流程处理时间,这个过程也称之为“TRIGGERED CHECK”。在双方握手完成以后,双方都知道对对端可以接收或者发送端对端消息

根据连接检查的介绍,读者可能已经注意到了,前面我们讨论的候选配对查询算法还有一定的问题,假设候选配对存在的话,无论查询方式是何种顺序,查询流程会一直查询直到找到这一代候选配对。显然,查询的顺序肯定影响候选配对的查询结果。因此,为了快速生成候选配对结果,候选地址需要经过排序处理,最后,排序后的候选配对结果就是一个check list。关于排序算法笔者在发送初始offer的章节进行讨论。基本上,排序算法需要遵守两个基本原则

章节进行讨论。基本上,排序算法需要遵守两个基本原则:


  1. 每个agent给它的候选地址一个优先级数字标识,此优先级标识会随候选地址发送到对端peer。
  2. 本地和远端优先

其中,第二个原则非常重要。如果双方L侧agent和R侧agent的都在NAT后的话,如果确保ICE工作,必须特别注意第二个原则。我们经常可以看到,NAT是不会允许一台外部主机发送数据进入到NAT后的网络环境中,只有在NAT后的agent通过NAT发送数据给这台主机后才被允许交互,外部数据才能进入到NAT后的环境中。这里要注意,直到agent双方都已通过自己相关的NAT穿越发送check信息后,双向的ICE check才能最终成功。agent需要通过check list才能启动工作,所以,它需要周期性地发送一个STUN请求获得列表中的候选配对。这个处理过程称之为 “ORDINARY CHECKS”。


通常情况下,优先级算法的设计是为了同类候选地址直接获得同样的优先级,和一些非直接处理的方式相比,优先级算法在处理候选配对是可能更加高效。因此,通过优先级算法的处理流程可以快速高效地实现直接路由访问,路由处理路径中仅需要几个媒体转发和几个NAT转发。如果采用非直接处理的方式的话,候选配对可能需要更多媒体转发和NAT转发,经过越多的转发就会导致越多的不可控因素。所以,这样的方式不是一种好

越多的转发就会导致越多的不可控因素。所以,这样的方式不是一种好的推荐发送。


https://anyconnect.com/stun-turn-ice/

https://tools.ietf.org/id/draft-ietf-ice-rfc5245bis-13.html

https://tools.ietf.org/html/rfc8445

https://en.wikipedia.org/wiki/Interactive_Connectivity_Establishment

https://www.ietfjournal.org/interactive-connectivity-establishment/

https://ietf.org/documents/144/IETF_ICE_intro_92.pdf



分享到:


相關文章: