coturn 弃用 RFC 3489 后 --stun-backward-compatibility 与 --rfc3489-compatibility 怎么选?
【免费下载链接】coturncoturn TURN server project项目地址: https://gitcode.com/GitHub_Trending/co/coturn
如果你的 coturn 服务端历史上开启过--stun-backward-compatibility,现在就需要做一次决策:这个选项已经不能再同时承担两件事了。coturn 正在退役对 RFC 3489("classic" STUN)的支持,原来由单个--stun-backward-compatibility控制的两类行为被拆分成了两个独立开关:--stun-backward-compatibility只保留其中一类,另一类移到了新选项--rfc3489-compatibility下。本文说明两个开关各自控制什么、按你的实际用途该怎么选、如何用日志确认自己是否还依赖 classic STUN,以及弃用选项被删除后会发生什么。
完整依据见 RFC 3489 弃用说明。
为什么一个开关会拆成两个
RFC 3489 是 2003 年的 STUN 规范,消息头为type (2) | length (2) | transaction ID (16)。2008 年的 RFC 5389 把 transaction ID 的前 32 位固定为 magic cookie0x2112A442,只留 96 位真正的 transaction ID。classic-STUN 消息正是以不带cookie 来识别的,其响应必须把调用方原来的 32 位原样回显。RFC 8489(2020,取代 RFC 5389)则把向后兼容的机制整个删掉了,WebRTC 也从未使用 classic STUN,目前仍需要的只是少数遗留 SIP 硬话机、ATA 和 WebRTC 之前的软电话协议栈。
拆分的原因在于:历史上--stun-backward-compatibility一个开关同时控制两个互不相关的行为:
- 接受 RFC 3489 Binding 请求;
- 在现代 RFC 5389 Binding 响应中,除
XOR-MAPPED-ADDRESS外额外附加已弃用的MAPPED-ADDRESS属性。
其中只有 (1) 是过时的、要删除的。(2) 服务的是那些能正确说 RFC 5389、但解析不了XOR-MAPPED-ADDRESS的客户端,它带来真实的放大代价——每个 Binding 响应都变大,抬高了反射攻击可用的增益因子,这正是 docker/coturn/turnserver.conf 中放大攻击警告实际针对的内容。如果直接删掉老开关,(2) 会被连带静默移除,所以两者被拆开:
| 选项 | 控制内容 | 状态 |
|---|---|---|
--stun-backward-compatibility | 现代响应中的MAPPED-ADDRESS | 受支持 |
--rfc3489-compatibility | RFC 3489 请求处理 | 已弃用,下一个大版本删除 |
两个开关默认都是关闭的。一个两个都不设置的服务器不受这次变更的任何影响。
行为矩阵:两种请求在四种开关组合下的响应
Binding 响应中携带的地址属性,按开关组合区分如下(引自弃用文档):
| 开关 | 现代(RFC 5389)请求 | Classic(无 cookie)请求 |
|---|---|---|
| 都不开(默认) | XOR-MAPPED-ADDRESS | 无响应 |
--stun-backward-compatibility | XOR-MAPPED-ADDRESS+MAPPED-ADDRESS | 无响应 |
--rfc3489-compatibility | XOR-MAPPED-ADDRESS | MAPPED-ADDRESS,回显 cookie |
| 两者都开 | XOR-MAPPED-ADDRESS+MAPPED-ADDRESS | MAPPED-ADDRESS,回显 cookie |
矩阵里有两处不对称需要注意:
- classic 路径总是输出
MAPPED-ADDRESS,与--stun-backward-compatibility无关,因为这是 RFC 3489 定义的唯一地址属性,那个协议里没有XOR-MAPPED-ADDRESS可以回退。 - 现代路径上的
MAPPED-ADDRESS保持显式开启,原因就是上面说的放大代价。
怎么选择:按你当初开老开关的原因对号入座
拆分前,--stun-backward-compatibility同时启用两种行为。按你当初设置它的理由,选下面对应的一行:
| 你当初的用途 | 现在的设置 |
|---|---|
| 需要为 classic-STUN 客户端提供服务 | 设置--rfc3489-compatibility |
现代客户端需要MAPPED-ADDRESS(解析不了XOR-MAPPED-ADDRESS) | 保持--stun-backward-compatibility不变 |
| 不确定,或需要与之前完全一致的行为 | 两个都设置,精确复现老单开关的语义 |
命令行用带--前缀的完整选项名;同样的名字去掉前导连字符也可以直接作为配置文件键使用(例如 docker/coturn/turnserver.conf 中的stun-backward-compatibility与rfc3489-compatibility两处注释段):
# turnserver.conf 中(去掉前导 -- 的同名键) rfc3489-compatibility stun-backward-compatibility文档明确提醒:由于--rfc3489-compatibility最终会消失,"两个都设"只应视为过渡状态,尽快弄清你实际需要的是哪一半。
两个开关的完整说明也可在 README.turnserver 的选项列表中查到。
如何验证自己是否还依赖 classic STUN
--rfc3489-compatibility打开后才有 classic-STUN 请求会被应答,所以最省事的测试是把它关掉,观察哪些客户端开始失效。
要在关闭之前先定位这些客户端,在现有 turnserver 启动命令上追加诊断参数运行:
# 在你的 turnserver 启动命令后追加(--verbose 与 --log-binding 两者都要,缺一不可) --rfc3489-compatibility --verbose --log-binding此时被应答的 classic-STUN Binding 会以OLD BINDING记入日志。文档特别指出这两个参数必须同时给,只加--verbose看不到这条记录。
另外,--verbose单独还会报告 classic 请求走错误/拒绝路径时的几种日志,可用于判断线上实际出现过哪些 classic 流量形态:
OLD STUN message:classic 请求收到了错误应答;OLD STUN method ... ignored:非 Binding 的 classic 方法被忽略;Wrong OLD STUN message received:收到非请求类的 classic 消息。
启动层面的验证也很直接:--rfc3489-compatibility会在启动时打出一条弃用警告,其中指明删除所在的大版本;如果同时设置了--no-stun(此时它没有任何效果),会另外警告一次。看到这两条警告,说明开关确实被识别并生效。
如果确认自己仍依赖 classic STUN,文档建议把使用场景上报给上游——删除时间表取决于是否还有人真的在用。
弃用开关删除后会发生什么
文档给出了两步路线:
- 第一步(已完成):引入
--rfc3489-compatibility,把--stun-backward-compatibility收窄到现代响应行为,启动时发弃用警告,更新随包文档。默认行为不变。 - 第二步(下一个大版本):该开关将不能再打开,classic-STUN 代码变成不可达并被整体移除,约 300 行,涉及 ns_turn_server.c 的
handle_old_stun_command()及其分发分支、ns_turn_msg.c 的各old_stun_*构造函数与stun_set_binding_response_str()的cookie/old_stun参数、ns_turn_msg_defs.h 的OLD_STUN_ATTRIBUTE_*宏、dtls_listener.c 的UDP_PACKET_CLASS_OLD_STUN分类分支,以及fuzzing/、tests/中的 classic-STUN 测试装置。
对二次开发使用者,这是一次API 破坏,也是它必须放在大版本里的原因:old_stun_*函数与OLD_STUN_ATTRIBUTE_*宏声明在 ns_turn_msg.h 和ns_turn_msg_defs.h中,autotools 构建会把它们复制进include/turn/client/并随lib/libturnclient.a一起安装(见 Makefile.in)。链接libturnclient的第三方代码在删除后将无法编译,stun_set_binding_response_str()的签名变化影响同一批人。删除之后,无 cookie 的数据包会被归类为UDP_PACKET_CLASS_INVALID,在监听端口的早期报文校验处直接丢弃,这是文档认定的目标终态。
文档同时强调一个例外:OLD_STUN_ATTRIBUTE_PASSWORD(0x0007)会保留。它在handle_turn_binding()中作为跳过的属性处理,避免某个顺手带上该属性的现代客户端被回以420 Unknown Attribute;删掉这个分支会把"容忍并忽略"变成硬错误。
不受本次弃用影响的两件事
以下两项容易与本次弃用混淆,它们保持不变:
- RFC 5780 NAT 行为探测:
CHANGE-REQUEST属性(0x0003)为 RFC 3489 与 RFC 5780 共用,--rfc5780不受影响。消失的只是应答的 classic 写法(SOURCE-ADDRESS/CHANGED-ADDRESS),改用RESPONSE-ORIGIN/OTHER-ADDRESS。 - 现代响应中的
MAPPED-ADDRESS:仍通过--stun-backward-compatibility提供。
小结
选择的判断标准只有一个:你当初开老开关是为 classic-STUN 客户端,还是为需要MAPPED-ADDRESS的现代客户端。前者迁到--rfc3489-compatibility并把它当作临时开关,用--verbose --log-binding确认OLD BINDING流量后尽快收敛;后者保留--stun-backward-compatibility即可;拿不准就先两个都开,行为与旧版完全一致,再逐步确认。需要留意:--rfc3489-compatibility没有替代项、在下一个大版本删除,且删除是面向libturnclient的 API 破坏;两个开关都不设的服务器则完全不受影响。
【免费下载链接】coturncoturn TURN server project项目地址: https://gitcode.com/GitHub_Trending/co/coturn
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考