Featured image of post stun协议要点纪要

stun协议要点纪要

stun协议介绍

stun协议提供了一种机制, 用于发现和定位客户端在NAT后的IP地址和端口号。 可以检查两个节点的连接并保活NAT的绑定。它不提供NAT穿透功能, 只能用于发现和定位NAT后的IP地址和端口号。

最新的stun协议版本是RFC 8489,已经过时: RFC 5389

stun配合使用的场景有两个:

  1. ICE

  2. sip oubound

要点

stun是客户端-服务端协议, 支持两种事务:

  1. 客户端发送请求,服务端响应
  2. 客户端发送不需要服务端响应的消息

STUN消息结构

stun Message采用网络字节序编码, 即大端字节序。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
 0                   1                   2                   3
 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|0 0|     STUN Message Type     |         Message Length        |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                         Magic Cookie                          |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                                                               |
|                     Transaction ID (96 bits)                  |
|                                                               |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

最高的两位字节必须为0,当stun和其他协议在同一个端口上复用时,可以使用这两位来区分协议。

Message Type: 用来定义message classmessage methodmessage methodBinding(0b000000000001), message class主要分为:

  1. request 客户端发送请求, 服务端响应
  2. response 服务端发送响应, 客户端接收
  3. error response 服务端发送错误响应, 客户端接收
  4. indication 客户端发送通知, 服务端不响应

Magic Cookie: 必须包括0x2112A442,它是Transaction ID的一部分.

对于通过UDP或者DTLS-over-UDP发送的stun消息,大小必须小于MTU。 如果不知道MTU, 使用udp发送, ipv4情况下,stun的udp包必须小于548

request/response这样的事务, 发送中如果丢包,会间隔初始值RTO(500ms)时间重传, indication这样的事务, 发送中如果丢包, 不会重传。 默认最大重传次数为7次。

STUN URL

当客户端希望使用TLS/DTLS加密,那么stun serverURIscheme为:stuns,否则为:stun

stunURI的hostip, stunsURI的host必须为域名,ip会报错。

默认的stun端口为3478, stuns端口为5349

当使用TLS-over-TCP或者DTLS-over-UDP时, TLS_DHE_RSA_WITH_AES_128_GCM_SHA256TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256必须有。

request/response关于未知attributes的处理

  1. 如果request中包含未知的attributes, 服务端报错420(Unkown Attribute)。 对于错误的response,错误码必须有,错误信息要和错误码匹配。
  2. 如果indication请求包括未知的attributes, 服务端会丢弃此命令,处理停止。
  3. 如果成功的response中带有未知的attributes, 客户端会丢弃此response,并认为事务处理失败。
  4. 如果错误的response中包含未知的attributes或者未带错误码,客户端初步认为事务处理失败。需要再结合错误码来判断: 300-499: 客户端认为事务处理失败。 500-599: 客户端可能会重新发送请求,重试的次数应该被限制到4。

FINGERPRINT 机制

FINGERPRINT机制是为了和其他的消息进行区分,stun Header头有时候不够用,所以需要添加FINGERPRINT属性。

认证机制主要有两种: 短期凭证机制长期凭证机制

  1. 短期凭证机制

    在进行事务之前,客户端和服务端已使用其他协议交换了用户名和密码形式的凭证,此凭证是有时效的, 此凭证主要用在每个请求和多个响应中形成消息完整性检查。

    1. 对于request或者indication消息,必须有USERNAME, MESSAGE-INTERGITY-SHA256,MESSAGE-INTERGRITY。 除非双方已通过其他方式知道了对方支持的完整性算法,这种情况下,MESSAGE-INTERGITY-SHA256MESSAGE-INTERGRITY必须有一个。 密码一定不能在消息中。

    2. 服务端收到request或者indication消息, 必须验证USERNAMEMESSAGE-INTERGITY-SHA256或者MESSAGE-INTERGRITY

      • 消息中不包括USERNAME或者MESSAGE-INTERGITY-SHA256MESSAGE-INTERGRITY中的一个, 服务端必须返回400(Bad Request)错误响应。
      • 如果USERNAME或者MESSAGE-INTERGITY-SHA256MESSAGE-INTERGRITY中的一个验证失败, 服务端必须返回401(Unauthorized)错误响应。
    3. 客户端收到response之后,检查参数MESSAGE-INTEGRITY或者MESSAGE-INTEGRITY-SHA256, 如果不匹配,response丢弃。 然后,客户端使用和请求相同的密码,根据MESSAGE-INTEGRITY或者MESSAGE-INTEGRITY-SHA256response的消息完整性计算, 如果结果和MESSAGE-INTEGRITY或者MESSAGE-INTEGRITY-SHA256的内容一致,就认为匹配.

    4. 后续的其他的请求都要带MESSAGE-INTEGRITY-SHA256或者MESSAGE-INTEGRITY属性.

  2. 长期凭证机制 客户端和服务端共享用户名和密码,长期有效,直到用户不再是系统订阅者或者凭证改变。 它的认证过程为:

    1. 客户端发送不带任何凭证的request或者indication消息到服务端
    2. 服务端拒绝请求并带上realm(引导用户选择用户名和密码)nonce(服务端cookie)
    3. 客户端会重新发送请求带上username,realmnonce
    4. 服务端验证nonce和消息完整性.
    5. 之后的其他请求客户端都要带上username,realmnonce,直到服务端的nonce失效。

    第一个请求必须包括: USERNAME, USERHASH,MESSAGE-INTEGRITY, MESSAGE-INTEGRITY-SHA256, REALM, NONCE, PASSWORD-ALGORITHMS, PASSWORD-ALGORITHM 一旦服务端验证了nonce和消息完整性, 后续的请求都必须包括USERNAMEorUSERHASH,REALM,NONCE, PASSWORD-ALGORITHM,MESSAGE-INTEGRITYorMESSAGE-INTEGRITY-SHA256

备用服务器 机制

服务端返回错误码300(Try Alternate)并带ALTERNATE-SERVER属性。

stun的部分参数

MAPPED-ADDRESS

1
2
3
4
5
6
7
8
9
 0                   1                   2                   3
 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|0 0 0 0 0 0 0 0|    Family     |           Port                |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                                                               |
|                 Address (32 bits or 128 bits)                 |
|                                                               |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

客户端nat的地址, 包括8位family和16位port, 32位ipv4或者128位ipv6

XOR-MAPPED-ADDRESS

1
2
3
4
5
6
7
 0                   1                   2                   3
 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|0 0 0 0 0 0 0 0|    Family     |         X-Port                |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                X-Address (Variable)
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

反传输的地址,和MAPPED-ADDRESS差别在于传输地址的编码, XOR-MAPPED-ADDRESS通过和magic cookie按位异或来编码地址, MAPPED-ADDRESS直接以二进制形式编码地址.

USERNAME

用于标识消息完整性检查使用用户名和密码的方式. 必须是utf-8并且少于509个字节。

USERHASH

当支持用户名匿名时,使用此字段替换USERNAME,32个字节。

FINGERPRINT

如果有该字段,那么此字段必须在MESSAGE-INTEGRITYandMESSAGE-INTEGRITY-SHA256后面.

PASSWORD-ALGORITHMS

包括服务端可以使用的算法列表。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
 0                   1                   2                   3
 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|         Algorithm 1           | Algorithm 1 Parameters Length |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                    Algorithm 1 Parameters (variable)
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|         Algorithm 2           | Algorithm 2 Parameters Length |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                    Algorithm 2 Parameters (variable)
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                                                             ...

PASSWORD-ALGORITHM

服务端要用的算法

1
2
3
4
5
6
7
 0                   1                   2                   3
 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|          Algorithm           |  Algorithm Parameters Length   |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                    Algorithm Parameters (variable)
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
本博客已稳定运行
发表了60篇文章 · 总计103.84k字
本站总访问量 次 · 您是本站第 位访问者
粤ICP备2025368587号-1| 使用 Hugo 构建
主题 StackJimmy 设计