stun协议介绍
stun
协议提供了一种机制, 用于发现和定位客户端在NAT
后的IP地址和端口号。
可以检查两个节点的连接并保活NAT
的绑定。它不提供NAT穿透功能, 只能用于发现和定位NAT
后的IP地址和端口号。
最新的stun
协议版本是RFC 8489,已经过时: RFC 5389。
stun
配合使用的场景有两个:
要点
stun
是客户端-服务端协议, 支持两种事务:
- 客户端发送请求,服务端响应
- 客户端发送不需要服务端响应的消息
STUN消息结构
stun Message
采用网络字节序编码, 即大端字节序。
|
|
最高的两位字节必须为0,当stun
和其他协议在同一个端口上复用时,可以使用这两位来区分协议。
Message Type
: 用来定义message class
和message method
。message method
为Binding(0b000000000001)
, message class
主要分为:
request
客户端发送请求, 服务端响应response
服务端发送响应, 客户端接收error response
服务端发送错误响应, 客户端接收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 server
的URI
的scheme
为:stuns
,否则为:stun
。
stun
URI的host
为ip
, stuns
URI的host
必须为域名
,ip
会报错。
默认的stun
端口为3478
, stuns
端口为5349
。
当使用TLS-over-TCP
或者DTLS-over-UDP
时, TLS_DHE_RSA_WITH_AES_128_GCM_SHA256
和TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
必须有。
request/response关于未知attributes的处理
- 如果
request
中包含未知的attributes
, 服务端报错420(Unkown Attribute)
。 对于错误的response
,错误码必须有,错误信息要和错误码匹配。 - 如果
indication
请求包括未知的attributes
, 服务端会丢弃此命令,处理停止。 - 如果成功的
response
中带有未知的attributes
, 客户端会丢弃此response
,并认为事务处理失败。 - 如果错误的
response
中包含未知的attributes
或者未带错误码,客户端初步认为事务处理失败。需要再结合错误码来判断:300-499
: 客户端认为事务处理失败。500-599
: 客户端可能会重新发送请求,重试的次数应该被限制到4。
FINGERPRINT 机制
FINGERPRINT
机制是为了和其他的消息进行区分,stun Header
头有时候不够用,所以需要添加FINGERPRINT
属性。
认证机制主要有两种: 短期凭证机制
和长期凭证机制
。
-
短期凭证机制
在进行事务之前,客户端和服务端已使用其他协议交换了用户名和密码形式的凭证,此凭证是有时效的, 此凭证主要用在每个请求和多个响应中形成消息完整性检查。
-
对于
request
或者indication
消息,必须有USERNAME
,MESSAGE-INTERGITY-SHA256
,MESSAGE-INTERGRITY
。 除非双方已通过其他方式知道了对方支持的完整性算法,这种情况下,MESSAGE-INTERGITY-SHA256
和MESSAGE-INTERGRITY
必须有一个。 密码一定不能在消息中。 -
服务端收到
request
或者indication
消息, 必须验证USERNAME
和MESSAGE-INTERGITY-SHA256
或者MESSAGE-INTERGRITY
。- 消息中不包括
USERNAME
或者MESSAGE-INTERGITY-SHA256
和MESSAGE-INTERGRITY
中的一个, 服务端必须返回400(Bad Request)
错误响应。 - 如果
USERNAME
或者MESSAGE-INTERGITY-SHA256
和MESSAGE-INTERGRITY
中的一个验证失败, 服务端必须返回401(Unauthorized)
错误响应。
- 消息中不包括
-
客户端收到
response
之后,检查参数MESSAGE-INTEGRITY
或者MESSAGE-INTEGRITY-SHA256
, 如果不匹配,response
丢弃。 然后,客户端使用和请求相同的密码,根据MESSAGE-INTEGRITY
或者MESSAGE-INTEGRITY-SHA256
对response
的消息完整性计算, 如果结果和MESSAGE-INTEGRITY
或者MESSAGE-INTEGRITY-SHA256
的内容一致,就认为匹配. -
后续的其他的请求都要带
MESSAGE-INTEGRITY-SHA256
或者MESSAGE-INTEGRITY
属性.
-
-
长期凭证机制
客户端和服务端共享用户名和密码,长期有效,直到用户不再是系统订阅者或者凭证改变。 它的认证过程为:- 客户端发送不带任何凭证的
request
或者indication
消息到服务端 - 服务端拒绝请求并带上
realm(引导用户选择用户名和密码)
和nonce(服务端cookie)
- 客户端会重新发送请求带上
username
,realm
和nonce
- 服务端验证
nonce
和消息完整性. - 之后的其他请求客户端都要带上
username
,realm
和nonce
,直到服务端的nonce
失效。
第一个请求必须包括:
USERNAME
,USERHASH
,MESSAGE-INTEGRITY
,MESSAGE-INTEGRITY-SHA256
,REALM
,NONCE
,PASSWORD-ALGORITHMS
,PASSWORD-ALGORITHM
一旦服务端验证了nonce
和消息完整性, 后续的请求都必须包括USERNAME
orUSERHASH
,REALM
,NONCE
,PASSWORD-ALGORITHM
,MESSAGE-INTEGRITY
orMESSAGE-INTEGRITY-SHA256
- 客户端发送不带任何凭证的
备用服务器 机制
服务端返回错误码300(Try Alternate)
并带ALTERNATE-SERVER
属性。
stun的部分参数
MAPPED-ADDRESS
|
|
客户端nat
的地址, 包括8位family
和16位port
, 32位ipv4
或者128位ipv6
。
XOR-MAPPED-ADDRESS
|
|
反传输的地址,和MAPPED-ADDRESS
差别在于传输地址的编码,
XOR-MAPPED-ADDRESS
通过和magic cookie
按位异或来编码地址,
MAPPED-ADDRESS
直接以二进制形式编码地址.
USERNAME
用于标识消息完整性检查使用用户名和密码的方式. 必须是utf-8
并且少于509
个字节。
USERHASH
当支持用户名匿名时,使用此字段替换USERNAME
,32
个字节。
FINGERPRINT
如果有该字段,那么此字段必须在MESSAGE-INTEGRITY
andMESSAGE-INTEGRITY-SHA256
后面.
PASSWORD-ALGORITHMS
包括服务端可以使用的算法列表。
|
|
PASSWORD-ALGORITHM
服务端要用的算法
|
|