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。
stunURI的host为ip, stunsURI的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和消息完整性, 后续的请求都必须包括USERNAMEorUSERHASH,REALM,NONCE,PASSWORD-ALGORITHM,MESSAGE-INTEGRITYorMESSAGE-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-INTEGRITYandMESSAGE-INTEGRITY-SHA256后面.
PASSWORD-ALGORITHMS
包括服务端可以使用的算法列表。
|
|
PASSWORD-ALGORITHM
服务端要用的算法
|
|