文章目录
- 1 背景
- 2 stun与turn 服务测试
- 3 ICE 收集测试[](https://webrtc.github.io/samples/src/content/peerconnection/trickle-ice/)
- 4 标准文档中的流程
- 5 结论
1 背景
今天在调试webrtc C++设备join webapp 建立的房间时,在交换ICE信息后,开始进行ICE打洞。
发现C++ 收到401 的响应 直接退出了。 很奇怪的现象。因为使用的coturn,配置好的情况下是不用去管coturn的行为。所以这里要调试一波coturn 401 错误。
考虑这里主要是考虑权限的问题。根据错误很明显是涉及到 访问coturn 服务器 权限出错。
但出错的地方看起来很奇怪,因为user为空。
启用use-auth-secret 及 static-auth-secret=north配置后 ,coturn接受的动态用户名和凭证**,**将直接对每个用户生成 username 及凭证。
这个行为与我们预设的动态账户密码机不符。turn 看起来是没有问题。所以我们找到 什么情况下才会出现,user 为空的情况。且user 为空的情况下 出现401错误。
coturn 原生log 在 /var/log 下
user <>: incoming packet message processed, error 401
具体的log如下:
86: handle_udp_packet: New UDP endpoint: local addr 172.31.111.111:3478, remote addr 101.111.111.110:62153
86: session 000000000000000003: realm <demo> user <>: incoming packet BINDING processed, success
86: session 001000000000000002: realm <demo> user <>: incoming packet message processed, error 401: Unauthorized
86: session 001000000000000002: new, realm=<demo>, username=<1570764028>, lifetime=600
86: session 001000000000000002: realm <demo> user <1570764028>: incoming packet ALLOCATE processed, success
86: IPv4. Local relay addr: 172.31.111.111:50809
这里截取段有代表性的代码。上面三行为 STUN的行为,下面三行为 TURN 行为的log。
2 stun与turn 服务测试
用测试stun 工具测试下 server看下log 的变化。
turnutils_stunclient -p 3478 xxxx.xxxx.xxxx.com
1407: handle_udp_packet: New UDP endpoint: local addr 172.31.30.111:3478, remote addr 101.111.111.117:44096
1407: session 000000000000000003: realm <demo> user <>: incoming packet BINDING processed, success
从log 可以看出 在stun 请求的情况下 user 为空。也就是单独stun时 会出现user 为空的情况,所以我们看log 时候不要被stun的log 所干扰。
这里在测试下turn
turnutils_uclient -u demo -w xxx -p 3478 xxxx.xxxx.xxxx.com
1534: handle_udp_packet: New UDP endpoint: local addr 172.31.111.111:3478, remote addr 101.204.111.111:56623
1534: session 001000000000000002: realm <demo> user <>: incoming packet BINDING processed, success
1534: session 001000000000000002: realm <demo> user <>: incoming packet message processed, error 401: Unauthorized
1581: session 001000000000000005: realm <demo> user <demo>: incoming packet CHANNEL_BIND processed, success
这里单独测试turn时 会发现 它耶好像先进行了一次stun服务。后续才跑的turn的流程。
这里可以看得出来 turn测试在turn 在relay地址分配之前,导致发生了401 错误。且后续turn务的行为看起来正常。
3 ICE 收集测试
那这里可以测试下收集ICE信息
https://webrtc.github.io/samples/src/content/peerconnection/trickle-ice/使用该网址 测试coturn server
在coturn log中看到如下信息:
1778: handle_udp_packet: New UDP endpoint: local addr 172.31.111.111:3478, remote addr 101.204.111.111:41891
1778: session 000000000000000012: realm <demo> user <>: incoming packet message processed, error 401: Unauthorized
1778: handle_udp_packet: New UDP endpoint: local addr 172.31.111.111:3478, remote addr 101.204.111.111:55573
1778: session 001000000000000009: realm <demo> user <>: incoming packet message processed, error 401: Unauthorized
1778: IPv4. Local relay addr: 172.31.111.111:55244
1778: session 000000000000000012: new, realm=<demo>, username=<demo>, lifetime=3600
1778: session 000000000000000012: realm <demo> user <demo>: incoming packet ALLOCATE processed, success
1778: IPv4. Local relay addr: 172.31.111.111:50538
1778: session 001000000000000009: new, realm=<demo>, username=<demo>, lifetime=3600
1778: session 001000000000000009: realm <demo> user <demo>: incoming packet ALLOCATE processed, success
1778: session 000000000000000012: refreshed, realm=<demo>, username=<demo>, lifetime=0
1778: session 000000000000000012: realm <demo> user <demo>: incoming packet REFRESH processed, success
1778: session 001000000000000009: refreshed, realm=<demo>, username=<demo>, lifetime=0
1778: session 001000000000000009: realm <demo> user <demo>: incoming packet REFRESH processed, success
1779: session 000000000000000012: usage: realm=<demo>, username=<demo>, rp=3, rb=244, sp=3, sb=316
1779: session 000000000000000012: closed (2nd stage), user <demo> realm <demo> origin <>, local 172.31.111.111:3478, remote 101.204.111.111:41891, reason: allocation timeout
1779: session 000000000000000012: delete: realm=<demo>, username=<demo>
1779: session 001000000000000009: usage: realm=<demo>, username=<demo>, rp=3, rb=244, sp=3, sb=316
1779: session 001000000000000009: closed (2nd stage), user <demo> realm <demo> origin <>, local 172.31.111.111:3478, remote 101.204.111.111:55573, reason: allocation timeout
1779: session 001000000000000009: delete: realm=<demo>, username=<demo>
可以很明显的看出ICE 收集过程中也出现了这个问题。所以401 错误出现ICE收集过程中。到这里也看不出为什么会出现401错误。所以下步开始阅读标准。
4 标准文档中的流程
RFC5766 ICE标准文档:
https://datatracker.ietf.org/doc/rfc5766/
第2.2 节 Turn服务器 分配流程
TURN TURN Peer Peer
client server A B
|-- Allocate request --------------->| | |
| | | |
|<--------------- Allocate failure --| | |
| (401 Unauthorized) | | |
| | | |
|-- Allocate request --------------->| | |
| | | |
|<---------- Allocate success resp --| | |
| (192.0.2.15:50000) | | |
// // // //
| | | |
|-- Refresh request ---------------->| | |
| | | |
|<----------- Refresh success resp --| | |
| | | |
客户端在没有凭据的情况下向服务器发送了分配请求。由于服务器要求使用STUN的长期凭证机制对所有请求进行身份验证,因此服务器拒绝该请求并显示401(未经授权)错误代码。客户端然后再次尝试,这次包括凭证(未显示)。这次,服务器接受分配请求,并返回分配成功响应,该响应包含(除其他事项外)分配给分配的relay传输地址。稍后,客户端决定刷新分配,因此发送刷新请求到服务器。刷新被接受,并且服务器以刷新成功响应进行回复。
PS:401(未经授权):如果客户端遵循了长期凭据机制的过程,但仍然收到此错误,则服务器不接受客户端的凭据。在这种情况下,客户认为当前交易失败,应该通知用户或操作员。除非客户端认为问题已解决,否则客户端不应向该服务器发送任何进一步的请求
所以问题原因找到了,按照标准文档中的行为描述,如果第一次不带凭证访问coturn 是后放回401错误,但后续立刻携带凭证则会正常分配 符合我们所预期行为。
按照说明 401 错误是开启长期凭证导致的? 那如何不开启长期凭证,长期凭证由lt-cred-mech属性控制,在coturn config中注释中说明的很清楚。 不启用该属性且不启用任何权限校验即可。所以正常情况下都会开启长期凭证,所以按照文档说明401错误就会出现。
#lt-cred-mech
# This option is opposite to lt-cred-mech.
# (TURN Server with no-auth option allows anonymous access).
# If neither option is defined, and no users are defined,
# then no-auth is default. If at least one user is defined,
# in this file or in command line or in usersdb file, then
# lt-cred-mech is default.
#
5 结论
coturn 地址分配 出现401 Unauthorized的 首先应该排查,是否使用静态用户名或密码。比如
turnutils_uclient -u demo -w xxx -p 3478 xxxx.xxxx.xxxx.com
u 和 w 填错了, 这个可以很容易从coturn 的log中看出来
第二个则则可能是SSL 证书配置问题。
第三个,在turn 过程中出现一次401 是正常流程因为按照文档中的默认行为第一次没有携带凭证访问,是户被拒绝,但第二次携带凭证拿到releay地址成功。则说明turn 服务仍然是正常的,符合标准的。所以这个401错误不用去处理。