1、STUN协议概述
STUN(Session Traversal Utilities for NAT)NAT会话穿透工具,STUN是一个Client/Server协议,支持请求/响应类型、指示类型两种类型。STUN作为ICE(Interactive Connectivity Establishment,交互式连接建立)解决方案的一种工具使用,STUN协议本身没有穿透等能力,只是为穿透提供反射地址,穿透不成功时,需要使用TURN协议。
1.1 请求/响应类型(request/response)
由客户端给服务器发送请求,并等待服务端返回响应,用于确定一个NAT给客户端分配的具体绑定。客户端通过事务ID将请求响应连接起来。
1.2 指示类型(indication transaction)
由服务器或者客户端发送指示,另一方不产生响应,用于保持绑定的激活状态。
2、STUN交互过程
2.1 交互过程
(1)在WebRTC中,STUN客户端内置在浏览器用户代理中,在会话建立之前,先发送stun测试报文,以便浏览器确定其是否位于NAT之后并发现映射地址和端口。
(2)当STUN服务器收到STUN Binding请求时,它会记录Binding请求来自哪个IP地址和端口号,此地址和端口号随后将以STUN Binding响应的形式返回客户端。(通过XOR-MAPPED-ADDRESS属性)。
(3)客户端将响应中发来的IP地址和端口与其发送的IP地址和端口进行比较,以此来判断客户端和服务器之间有没有NAT,若不同,则说明至少有一个NAT,客户端能够识别由最外层的NAT分配的IP地址和端口。存在多个NAT时,STUN只能识别最外层NAT的相关信息。
(4)STUN服务器将源传输地址复制到STUN Binding响应中XOR-MAPPED-ADDRESS属性中,并将绑定响应发送回STUN客户端。当这个数据包通过NAT返回时,NAT将修改IP报头中的目的传输地址,但是STUN响应主体中XOR-MAPPED-ADDRESS属性中的传输地址将保持不变。通过这种方式,客户端可以了解最外面的NAT相对于STUN服务器分配的反射传输地址。
2.2 保活机制
在ICE中,STUN协议用于连通性检查和ICE保活,客户端需要按固定间隔以指示形式发送STUN Binding请求,防止NAT映射超时,指示型请求可使NAT重置其UDP定时器,发送间隔短于NAT UDP定时器设置,就可以保持NAT映射。
2.3 身份验证机制
2.3.1 短期身份验证
短期身份验证采用用户名/密码方式,此机制适用于单个会话。ICE使用此方法对每组连接检查应用不同的身份验证。短期身份验证机制假设在STUN事务之前,客户端和服务器已经使用了其他协议来交换了证书,以username和password形式。这个证书是有时间限制的。在WebRTC中通过SDP进行相关信息的交互。
2.3.2长期身份验证
长期身份验证采用质询/响应机制,允许使用长期凭据。长期身份验证机制依赖于一个长期证书,username和password在客户端和服务器中是共用的。这个证书从它提供给用户开始将一直是有效的,直到该用户不再是该系统的用户。
3、STUN报文格式详解
3.1 STUN包头格式
最高两位:为0,在STUN协议与其他协议端口复用时,用于区分STUN和其他数据包,如RTP数据包。
STUN Message Type(16bits):消息类型。定义消息类型如下:
Message Type后14bits可进一步分解为如下结构:
(1)C1-C0两位表示类编码
0b00:request
0b01:indication
0b10:success response
0b11:error response
(2)M11-M0表示方法
STUN目前定义了一个绑定方法,Binding方法可以用于请求/响应类型和指示类型。method=0b000000000001 (Binding)
Message Length:(16bits),消息长度,不包含STUN Header的20个字节。所有的STUN属性都是20字节对齐的。
Magic Cookie:(32bits),固定值0x2112A442,用于反射地址的异或(XOR)运算。
Transaction ID:(96bits),事务ID标识符,请求对应的响应具有相同的标识符。
3.2 STUN属性
STUN 消息头后跟着多个属性,每个属性都采用 TLV 编码,type 为 16 位的类型、lenght 为 16 位的长度、value 为属性值。每个 STUN 属性必须是 4 字节对齐。lenght 字段的值只表示 TLV 中 V(Value) 的长度,既不包括 T(Type) 和 L(length),又不包括 padding 填充数据的长度。具体如下所示:
STUN 请求和响应都包含消息属性。消息属性分为强制理解属性和可选理解属性,具体如下所示:
在ICE中,包含STUN用到的几个属性,具体如下所示:
MAPPED-ADDRESS:NAT客户端的反射地址,具体如下所示:
Family:IP类型,0x01-IPV4、0x02-IPV6
Port:端口
Address:IP地址
XOR-MAPPED-ADDRESS:与MAPPED-ADDRESS属性基本相同,区别在于反射地址经过一次异或(XOR)处理,异或运算是其自身的逆运算,客户端经过一次异或运算获得真实的反射地址。解决ALG篡改地址和端口的问题。
USERNAME:用户名,用于消息完整性,在webrtc中的规则为 “对端的ice-ufrag:自己的ice-ufrag”,其中ice-ufrag已通过提议/应答的SDP信息进行交互。
MESSAGE-INTEGRITY:STUN 消息的 HMAC-SHA1 值,长度 20 字节,用于消息完整性认证。详细的计算方式后续进行举例说明。
FINGERPRINT:指纹认证,此属性可以出现在所有的 STUN 消息中,该属性用于区分 STUN 数据包与其他协议的包。属性的值为采用 CRC32 方式计算 STUN 消息直到但不包括FINGERPRINT 属性的的结果,并与 32 位的值 0x5354554e 异或。
ERROR-CODE:属性用于error response报文中。其中包含了300-699表示的错误码,以及一个UTF-8格式的文字出错信息(Reason phrase)。
REALM:此属性可能出现在请求和响应中。在请求中表示长期资格将在认证中使用。当在错误响应中出现表示服务器希望客户使用长期资格来进行认证。
NONCE:出现在请求和响应消息中的一段字符串。
UNKNOWN-ATTRIBUTES:此属性只在错误代码为420的的错误响应中出现。
SOFTWARE:此属性用于代理发送消息时包含版本的描述。它用于客户端和服务器。它的值包括制造商和版本号。该属性对于协议的运行没有任何影响,仅为诊断和调试目的提供服务。SOFTWARE属性是个可变长度的,采用UTF-8编码的小于128个字符的序列号
ALTERNATE-SERVER:属性表示 STUN 客户可以尝试的不同的 STUN 服务器地址。属性格式与 MAPPED-ADDRESS 相同。
在Binding请求中通常需要包含一些特殊的属性,以在ICE进行连接性检查的时候提供必要信息,详细的属性如下所示:
PRIORITY 和 USE-CANDIDATE:终端必须在其request中包含PRIORITY属性,指明其优先级,优先级由公式计算而得。如果有需要也可以给出特别指定的候选(即USE-CANDIDATE属性)。
ICE-CONTROLLED和ICE-CONTROLLING: ICE流程中定义了两种角色:controlling和controlled。不同的角色在candidate pair优先级的计算,pair nominate的决策上有所不同。一般流程下,会话的双发各自的角色选择是与会话协商的流程相关的。offerer是controlling,answerer是controlled。
ICE-CONTROLLED或者是ICE-CONTROLLING,这两个属性都会携带一个Tie breaker这样的字段,其中包含 一个本机产生的随机值。收到该bind request的一方会检查这两个字段,如果和当前本机的role冲突,则检查本机的tie breaker值和消息中携带的tie breaker值进行判定本机合适的role。判定的方法为Tie breaker值大的一方为controlling。如果判定本端变更角色,这直接修改;如果判定对端变更角色,则对此bind request发送487错误响应,收到此错误响应的一方变更角色即可。
4、STUN报文示例
4.1 Binding Request
4.1.1 USENAME
USENAME 组成格式为对端ice-ufrag:自己ice-ufrag,其中对端ice-ufrag为webrtc中的answer sdp,其中属性a=ice-ufrag:2g25ql32,自己ice-ufrag为offer sdp,其中属性a=ice-ufrag:cVN4。
STUN属性采用4字节对齐,不足的用00填充。
4.1.2 ICE-CONTROLLING
Tie breaker:64bits的随机值,用于解决角色冲突。
4.1.3 PRIORITY
4.1.4 MESSAGE-INTEGRITY
详细的计算过程后续进行详述。
4.1.5 FINGERPRINT
输入:FINGERPRINT属性之前的STUN数据
00 01 00 50 21 12 a4 42 67 33 45 6e 4a 4b 48 56
32 43 32 7a 00 06 00 0d 32 67 32 35 71 6c 33 32
3a 63 56 4e 34 00 00 00 c0 57 00 04 00 00 03 e7
80 2a 00 08 3e e8 21 cb d9 f4 4a d7 00 24 00 04
6e 00 1e ff 00 08 00 14 ba 64 89 fa 5b 93 71 c4
d6 3d bf 20 8c a1 b2 ac 25 8b bd 75
CRC-32运算:获得以下输出
输出:0x5B6D336D
XOR运算:0x5B6D336D XOR 0x5354554E
输出:0x 08 39 66 23即FINGERPRINT的值。
4.2 Binding Response
4.2.1 XOR-MAPPED-ADDRESS
Port:与Magic cookie的网络字节序前16位进行异或
0xc1a6 = 57524 XOR 0x2112
IP:与Magic cookie进行异或运算
0x8d06a50b = (172.20.1.73)XOR 0x2112a442
5、参考
https://tools.ietf.org/html/rfc3489
https://tools.ietf.org/html/rfc5389