这张图描述的是TURN Client、PeerA、PeerB三方会议之间,网络报文互相通讯的场景。其中:
1、TURN Client客户端、PeerA分别连接到两个内网中,并且通过一个或者多个NAT到达公网。
2、TURN服务器架设在公网中,不同的客户端以TURN服务器为中继和其他peer进行通信。如上图所示:TURN Client客户端通过中继和其他peer进行通讯;PeerB没有NAT,可直接通过自己的IP地址与其他peer进行通讯;这里是假设PeerA网络是全锥型网络,也是可直接通过自己的reflex IP地址与其他peer进行通讯。
TURN Client客户端通过中继和其他peer进行通讯的流程描述如下:
1、TURN Client是位于NAT后面的一个客户端(内网地址是10.1.1.2:49721),连接公网的TURN服务器(默认端口3478)后, 服务器会得到一个Client的反射地址(Reflexive Transport Address)192.0.2.1:7000。
2、TURN Client通过TURN命令创建或管理ALLOCATION,allocation是服务器上的一个数据结构,包含了中继地址的信息。 服务器随后会给Client分配一个中继地址,即图中的192.0.2.15:50000。
3、另外两个对等端若要通过TURN协议和TURN Client进行通信, 可以直接往中继地址收发数据即可,TURN服务器会把发往指定中继地址的数据转发到对应的Client,这里是其反射地址。
4、Server上的每一个allocation都唯一对应一个client,并且只有一个中继地址,因此当数据包到达某个中继地址时,服务器总是知道应该将其转发到什么地方。
但值得一提的是,一个Client可能在同一时间在一个Server上会有多个allocation,这和上述规则是并不矛盾的。
整理实际应用中Turn协议的工作主要有四个阶段:绑定(binding)、分配(Allocation)、转发(Relay)和信道(Channel)
binging request:client向server发送的reflex地址请求命令
binging response:server将client公网地址并server的局域网地址发送给client端。
一般只要部署turn服务器,就不用另外部署stun服务器,turn服务器已经兼容了stun功能。
客户端想要在服务器端获得一个中继分配,客户端需要在中继服务器上申请一个中继事务。客户端发送分配请求(Allocate request)到服务器,然后服务器为用户开启一个relay端口后返回分配成功响应,并包含了分配的地址信息。客户端可以在属性字段描述其想要的分配类型:UDP or TCP。
上图中,turn服务器的turn port是配置文件中配置的监听地址,默认是3478;A的Relay是Client向服务器发送allocation request,turn服务器动态分配的relay地址。
a)客户端A向turn Port发送Allocate请求(图中绿色部分)。
b)turn服务器接收到客户端A的Allocate请求,服务器一看是Allocate请求,则根据relay端口分配策略为A分配一个端口。
c)服务器发送response成功响应。在该response中包含XOR-RELAYED-ADDRESS属性。该属性值就是A的relay端口。
d)客户端接收到response后,就知道了自己的relay地址。该relay地址是个公网地址,可以看作是客户端A在公网上的一个代理,任何想要联系A的客户端,只要将数据发送到A的relay地址就可以了
一旦中继传输地址分配好,客户端必须要将其保活。通常的方法是发送刷新请求(Refresh request)到服务端。这在TURN 中是一个标准的方法,刷新频率取决于分配的生命期,默认为10分钟。客户端也可以在刷新请求里指定一个更长的生命期,而服务器会返回一个实际上分配的时间。当客户端想终止通信时,可以发送一个生命期为0的刷新请求。
client和peer之间有两种方法通过turn server交换应用信息:
第一种:使用Send和Data转发机制
第二种:使用channels信道机制
两种方法都通过某种方式告知服务器哪个peer应该接收数据,以及服务器告知client数据来自哪个peer。
转发机制使用Send和Data指令(Indication)。其中Send指令用来把数据从client发送到server,而Data指令用来把数据从server发送到client。当使用Send指令时,客户端发送一个Send Indication到服务端,其中包含:
1、XOR-PEER-ADDRESS属性:指定对等端的(服务器反射)地址。
2、DATA属性:包含要传给对等端的信息。
当服务器收到Send Indication之后,会将DATA部分的数据解析出来,并将其以UDP的格式转发到对应的端点去,并且在封装数据包的时候把client的中继地址作为源地址,从而从对等端发送到中继地址的数据也会被服务器转发到client上。
值得一提的是,Send/Data Indication是不支持验证的,因为长效验证机制不支持对indication的验证,因此为了防止攻击,TURN要求client在给对等端发送indication之前先安装一个到对等端的许可(permission)。
如下图所示,client到Peer B 没有安装许可,导致其indication数据包将被服务器丢弃,对于peer B也是同样。
1)create permission request&response
CreatePermission Request示例:
CreatePermission Response示例:
2)send indicate(stun ping)&data indicate
webrtc中使用send&data indicate数据包,主要是用来做连通性测试使用,代码实现函数是:
P2PTransportChannel::SortConnectionsAndUpdateState
->P2PTransportChannel::MaybeStartPinging
->P2PTransportChannel::OnCheckAndPing
->P2PTransportChannel::PingConnection
->Connection::Ping
Send Indicate示例:
Data Indicate示例:
音视频数据转发场景中,使用Send/Data Indication转发机制,会多加的36字节格式信息,加重客户端和服务端之间的带宽压力。为改善这种情况,turn提供channeldata message信道机制。channeldata message不使用stun头部,而使用一个4字节的头部,包含一个称为信道号的值(channel number)。每一个使用中的信道号都与一个特定的peer绑定,即作为对等端地址的一个记号。要将一个信道与对等端绑定,客户端首先发送一个信道绑定请求(channelbind request)到服务器,并且指定一个未绑定的信道号以及对等端的地址信息。绑定后client和server都能通过channeldata message来发送和转发数据。信道绑定默认持续10分钟,并且可以通过重新发送channelbind request来刷新持续时间。和Allocation不同的是,并没有直接删除绑定的方法,只能等待其超时自动失效。
上图中0x4001为信道号,即channeldata message的头部中头2字节,值得一提的是信道号的选取有如下要求:
0x0000-0x3FFF :这一段的值不能用来作为信道号
0x4000-0x7FFF :这一段是可以作为信道号的值,一共有16383种不同值在目前来看是足够用的
0x8000-0xFFFF :这一段是保留值,留给以后使用
1)channel bind request&response
channel bind request示例:
channel bind response示例:
2)Channel Data Turn Message
TURN ChannelData Message示例:
https://zhuanlan.zhihu.com/p/71025431
https://zhuanlan.zhihu.com/p/26797422
RFC5766