严格路由 vs 松散路由
Kamailio 里的“严格路由”和“松散路由”本质上是 SIP Route/Record-Route 机制的两种模式分别来自较老的 RFC 2543 和较新的 RFC 3261。现在实际生产中几乎都使用松散路由。1. 核心区别对比项严格路由 Strict Routing松散路由 Loose Routing标准来源旧 RFC 2543RFC 3261Route URI 标识没有;lr参数有;lr参数Request-URI会被改成下一个代理的 URI保持为最终目标 URIRoute 头作用通过不断改写 R-URI 实现路由Route 头明确表示下一跳是否推荐不推荐主要为了兼容老设备推荐现代 SIP 标准方式Kamailio 常用处理函数一般不主动使用loose_route()复杂度高容易和 NAT、转发逻辑冲突简单清晰2. 松散路由 Loose Routing松散路由是现代 SIP 的标准做法。典型 Record-Route 头类似Record-Route: sip:proxy.example.com;lr关键点是 URI 里有;lrlr代表 loose routing。松散路由下的请求示例假设 Kamailio 在初始 INVITE 中插入了Record-Route: sip:kamailio.example.com;lr后续 BYE、ACK、re-INVITE 等 in-dialog 请求会带上Route: sip:kamailio.example.com;lr但 Request-URI 仍然是最终目标例如BYE sip:alice192.168.1.100 SIP/2.0 Route: sip:kamailio.example.com;lr也就是说Request-URI 最终目标 Route 经过哪些代理Kamailio 收到后通常这样处理if (has_totag()) { if (loose_route()) { route(RELAY); exit; } }loose_route()会检查 Route 头如果发现自己在 Route 头里就消费掉对应 Route然后继续转发。3. 严格路由 Strict Routing严格路由是旧 SIP 规范里的方式。Record-Route 头里没有;lrRecord-Route: sip:proxy.example.com这种情况下后续请求的 Request-URI 会被改成下一个代理地址而真正的目标 URI 会被放到 Route 头的末尾。严格路由下的请求示例可能变成BYE sip:kamailio.example.com SIP/2.0 Route: sip:alice192.168.1.100也就是说Request-URI 下一个代理 Route 最终目标或后续路由集合这种方式的问题是Request-URI 不再表示最终目标代理需要反复改写 Request-URI和 NAT、注册 Contact、负载均衡逻辑更容易冲突配置和排错更复杂现代 SIP 设备基本不推荐这样用。4. Kamailio 中怎么体现Kamailio 里通常通过rr模块处理 Record-Route 和 Route。常见配置loadmodule rr.so modparam(rr, enable_full_lr, 0) modparam(rr, append_fromtag, 1)初始 INVITE 时让 Kamailio 留在信令路径中if (is_method(INVITE|SUBSCRIBE)) { record_route(); }后续 in-dialog 请求if (has_totag()) { if (loose_route()) { route(RELAY); exit; } if (is_method(ACK)) { exit; } sl_send_reply(404, Not here); exit; }这里的重点是loose_route()虽然名字叫loose_route()但 Kamailio 的rr模块在一定程度上也能兼容一些严格路由场景。不过在现代配置中一般只需要按松散路由设计。5. Record-Route 里的;lr这是判断松散路由的核心。松散路由Record-Route: sip:1.2.3.4;lr或者Record-Route: sip:proxy.example.com;transportudp;lr严格路由Record-Route: sip:1.2.3.4没有;lr就可能被对端当成严格路由。6. Kamailio 的enable_full_lrKamailio 的rr模块有一个参数modparam(rr, enable_full_lr, 0)默认情况下Record-Route 可能类似Record-Route: sip:proxy.example.com;lr如果设置为modparam(rr, enable_full_lr, 1)可能生成Record-Route: sip:proxy.example.com;lron这是为了兼容某些有问题的 SIP 设备它们可能不正确识别没有值的;lr参数。一般情况下保持默认即可除非遇到特定终端或运营商兼容性问题。7. 实际使用建议在 Kamailio 生产环境中建议使用松散路由使用record_route()插入带;lr的 Record-Route使用loose_route()处理后续 in-dialog 请求不要主动生成没有;lr的 Record-Route严格路由只作为兼容旧设备考虑。典型配置结构request_route { if (is_method(INVITE|SUBSCRIBE)) { record_route(); } if (has_totag()) { if (loose_route()) { route(RELAY); exit; } if (is_method(ACK)) { exit; } sl_send_reply(404, Not here); exit; } route(RELAY); } route[RELAY] { if (!t_relay()) { sl_reply_error(); } exit; }8. 一句话总结严格路由是旧式 SIP 路由方式会通过改写 Request-URI 控制下一跳松散路由是现代标准方式通过Route头和;lr参数控制路由Request-URI 保持最终目标。Kamailio 生产环境中基本都应该使用record_route()loose_route()的松散路由模式。