Turn Client 和 Server交互简单流程

文章目录


参考文章:
1.RFC3489
https://www.rfc-editor.org/info/rfc3489
2.RFC5389
https://www.rfc-editor.org/info/rfc5389
3.RFC5766
https://www.rfc-editor.org/rfc/rfc5766.html
4.RFC6062
https://www.rfc-editor.org/rfc/rfc6062.html
5.P2P通信标准协议(一)之Stun
https://www.cnblogs.com/pannengzhi/p/5041546.html
6.P2P通信标准协议(二)之Turn
https://www.cnblogs.com/pannengzhi/p/5048965.html

 

1简介

前面的参考文章详细介绍了Turn的定义、结构以及流程。

Turn Client和Turn Server简单流程描述如下:Turn Client的内网IP:PORT(A1),通过路由的公网IP:PORT(A2), 通过Turn命令向Turn Server IP:PORT(B1) 创建ALLOCATION。Turn serve随后会给Turn Client分配一个中继地址IP:PORT(B2)。若Peer要向这个Turn Client发送数据,只要直接向这个Turn Client的中继地址B2发送数据即可,然后Turn Server会把发给B2的数据转发给A2。

Turn Client和Turn Server通信以及通过中继转发数据时候可以使用UDP/TCP/TLS over TCP。但是,Turn Server和Peer通信是基于UDP的,所以若Turn Client和Turn Server通过TCP进行交互,会在Turn Server端进行协议转换,RFC5766中画图如下:
在这里插入图片描述

2 报文结构

在开始分析Client 和 Server 交互流程之前,需要先对Turn的报文结构做个简单梳理,Turn是Stun的一个扩展,所以Turn的报文结构遵循Stun的报文结构规范。

2.1 Message Header

所有的Turn 报文都有20个字节的头部信息,并且采用大端模式。
在RFC3489中,头部结构如下:
在这里插入图片描述
在RFC5389中,为了兼容RFC3489,将头部结构定义如下:
在这里插入图片描述

2.1.1 头部2bits

在上面头部的两个字节必须为0。

2.1.2 Stun Message Type

关于Message Type,在RFC8389中描述如下:

消息类型定义了Stun消息的消息类别(请求,成功响应,失败响应或指示)和消息方法(主要功能)。 尽管有四种消息类别,但Stun中只有两种事务类型:请求/响应事务(由请求消息和响应消息组成)和指示事务(由单个指示消息组成)。 响应类别分为错误响应和成功响应,以帮助快速处理Stun消息。

这个字段又可以分为如下结构:
在这里插入图片描述
可以看到上面有M0 ~ M11 C0 ~ C1这两种类型。
M0 ~ M11代表 message type,而C0 ~ C11代表message class。
message class有如下定义:

0b00:   Requeset
0b01:   Indication
0b10:   Success response
0b11:   Error response
  • 1
  • 2
  • 3
  • 4

message type 有如下定义:

0x003 :  Allocate          (only request/response semantics defined)
0x004 :  Refresh           (only request/response semantics defined)
0x006 :  Send              (only indication semantics defined)
0x007 :  Data              (only indication semantics defined)
0x008 :  CreatePermission  (only request/response semantics defined
0x009 :  ChannelBind       (only request/response semantics defined)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

2.1.3 Message Length

message length 表示信息的长度,不包含20字节的头部。另外,Stun的属性都为4字节对齐,因此最后两位始终为0。

2.1.4 Magic Cookie

固定为0x2112A442。

2.1.5 Transaction ID (96bits)

是一个96个字节的标识符,用于区分Stun传输事务。详细介绍见RFC5389。

2.2 Stun Attributes

在头部之后,会有0个或多个Stun属性。每一个Stun属性必须是TLV结构。
T:Type 16bit L:Length 16bit V:Value 32bit对齐, 结构图如下:
在这里插入图片描述

2.2.1 Type

属性的类型,0x0000-0x7FFF之间的属性被指定为强制理解,意思是Stun终端必须要理解此属性,否则将返回错误信息;而0x8000-0xFFFF之间的属性为选择性理解,即如果Stun终端不识别此属性则将其忽略。
Type部分取值如下:

0x0000: (Reserved)
0x0001: MAPPED-ADDRESS
0x0002: (Reserved; was RESPONSE-ADDRESS)
0x0003: (Reserved; was CHANGE-ADDRESS)
0x0004: (Reserved; was SOURCE-ADDRESS)
0x0005: (Reserved; was CHANGED-ADDRESS)
0x0006: USERNAME
0x0007: (Reserved; was PASSWORD)
0x0008: MESSAGE-INTEGRITY
0x0009: ERROR-CODE
0x000A: UNKNOWN-ATTRIBUTES
0x000B: (Reserved; was REFLECTED-FROM)
0x0014: REALM
0x0015: NONCE
0x0020: XOR-MAPPED-ADDRESS
0x8022: SOFTWARE
0x8023: ALTERNATE-Server
0x8028: FINGERPRINT
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

2.2.2 Length

value的长度,因为是4字节对齐,所以若属性的长度不是4字节,会被补数据,而长度也会加上补数据的长度,所以最终长度一定是4字节的倍数。

2.2.3 Value

下面几个是比较常见的(不做详细介绍,详细介绍见RFC5389):

2.2.3.1 MAPPED-ADDRESS

结构如下:
在这里插入图片描述
Family表示使用的是IPv4(0x01)或者IPv6(0x02)
Port表示端口号
Address表示IP地址

2.2.3.2 XOR-MAPPED-ADDRESS

结构如下:
在这里插入图片描述
和上面的MAPPED-ADDRESS类似,只不过将Port和Address进行了异或。

2.2.3.3 USERNAME

用于message integrity,它标识在message integrity检查中使用的用户名和密码组合。

2.2.3.4 MESSAGE-INTEGRITY

message integrity可以出现在任何Stun消息类型中。它是由 username:realm:password进行MD5加密得到的数据。

2.2.3.5 REALM

可以出现在请求和响应中,在请求中存在REALM属性表示正在使用长期凭证进行身份验证。

2.2.3.6 NONCE

可以出现在请求和响应中,是由服务器创建的。

2.2.3.7 ERROR-CODE

用于error response报文中。其包含了300-699表示的错误代码,以及一个UTF-8格式的文字出错信息,部分错误类型如下:

300:  尝试替代
400:  错误请求
401:  未授权
420:  未知属性
438:  过期Nonce
500:  服务器错误
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

下面对Turn Server和Turn Client整个交互过程做个简单分析。

3 分配

Client会向Server发送allocate请求,但是没有携带验证信息,Server会返回error信息。然后,Client会解析error信息中的有效信息,添加进验证信息中,再次给Server发送allocate请求,Server解析到验证信息并进行验证,会返回成功信息。所以, Client会向Server发送两次allocate请求。
流程如下:
在这里插入图片描述
抓取的包如下:
在这里插入图片描述

3.1 Client —> Server Allocate

报文如下:
在这里插入图片描述
Client使用TCP和Server通信,从上面可以看到,Client第一次向Server发送allocate请求,没有携带任何的Stun属性,只是携带了头部信息,并且type值为0x03。

3.2 Server —> Client Error

报文如下:
在这里插入图片描述
Server返回401错误,并返回了几个Turn属性,其中我们需要使用NONCE再次向Server发送allocate请求。

同时,需要注意服务器返回的头部信息中的Transaction ID和Client发送出去的一致。

3.3 Client —> Server Allocate

报文如下:
在这里插入图片描述
Client再次向Server发送allocate请求,并携带一些Stun属性信息。NONCE为Server上次传递过来的。

3.4 Server —> Client Success

报文如下:
在这里插入图片描述
在Server返回的报文信息中,XOR-RELAYED-ADDRESS表示的Client的路由公网IP:PORT(A2),XOR-MAPPED-ADDRESS表示的是Server为Client分配的中继地址IP:PORT(B2)。

至此,Client已经申请到了中继地址。

4 刷新

在上面的3.3 和 3.4中,我们可以看到有个字段:LIFETIME。
这个属性标识在没有刷新情况下Server将维持分配的持续时间,单位为秒。若在这个时间之内,Client没有向Server发送refresh请求,那么Client被分配的IP:PORT将会被回收,因此我们需要定时在LIFETIME之内向Server发送refresh请求。
流程如下:
在这里插入图片描述
报文如下:
在这里插入图片描述

4.1 Client —> Server Refresh

报文如下:
在这里插入图片描述
在上面的报文中,Client向Server发出了refersh请求,刷新时间是600s。

4.2 Server —> Client Success

报文如下:
在这里插入图片描述
Server返回成功,并且给出LIFETIME为300s。

5 CreatePermission

在RFC5766中,Send Mechanism章节介绍到,当Client发送数据给Server时候,如果Client的Send indications没有被验证, 会被Server当做攻击,这些数据会被丢弃。因此在向Server发送数据前,先向Server发送CreatePermission 请求,请求中包含了要发送的Peer的IP地址。

如下,如果Client没有向Server发送Peer B的CreatePermission 请求,数据就会被丢弃。
在这里插入图片描述
报文如下:
在这里插入图片描述

5.1 Client —> Server CreatePermission

报文如下:
在这里插入图片描述
上面报文的XOR-Peer-ADDRESS便是Client要发送Peer的IP地址。

5.2 Server —> Client Success

报文如下:
在这里插入图片描述
Server返回成功。

6 连接Peer

当Client向Server 发送allocate请求成功后,并且定时进行refresh。此时,Client就会等待Server发送Peer的信息,然后Client会向Server发送ConnectionBind请求,和Peer建立连接,然后就可以正常和Peer进行通信。

注意:以下的流程,只是根据测试现象得出的,可能有些服务器因为功能不同或者参考的RFC不同导致交互和下面的不一致,下面的仅供参考

在RFC6062中,这样描述:

Server成功处理了分配请求后,当一个Peer和Client的中继地址建立连接时,Client都会接收Server发送的ConnectionAttempt indication。这个indication包含了CONNECTION-ID和XOR-Peer-ADDRESS属性。如果Client希望接收这个连接,就会重新创建一个新的socket,和Server建立新的连接,并使用新的socket向Server发送ConnectionBind请求,这个请求包含了Server发送ConnectionAttempt 时候的CONNECTION-ID。

后续Client和Peer通信都会使用新的socket,而原有的socket则会继续等待新的Peer连接,等到Server的ConnectionAttempt indication。

报文如下:
在这里插入图片描述

6.1 Server —> Client ConnectionAttempt

报文如下:
在这里插入图片描述
Server发送过来的请求携带了CONNECTION-ID和XOR-Peer-ADDRESS这两个重要的属性。

6.2 Client —> Server ConnectionBind

报文如下:
在这里插入图片描述
上面的报文中,SRC PORT是8507,和以前的端口不一致,说明Client已经使用新的socket向Server发送ConnectionBind请求,并且携带了一些必要的属性。

6.3 Server —>Client Error

在这里插入图片描述
由于是新的连接,使用的NONCE为原有的NONCE,服务器可能会返回401,并且携带新的NONCE。

6.4 Client —> Server ConnectionBind

报文如下:
在这里插入图片描述
Client使用新的NONCE重新向Server发送ConnectionBind请求。

6.5 Server —>Client Success

报文如下:
在这里插入图片描述
服务器返回success请求。

至此,Client已经和Peer建立了连接,后续就可以使用这个新的socket进行数据收发。

7 一些记录

7.1 多路复用时候,如何判断是Turn包?

可以通过以下进行判断
Turn头部最高两位必需是0;
Turn头部的Magic Cookie 为固定值;
Turn头部的Message Length以字节为单位,因为所有的Stun是4字节对齐的,所以这个字段的最后两位恒等于0。

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值