

官方详解图:https://kamailio.org/docs/modules/5.7.x/modules/rr.html
UAC Kamailio PROXY UAS
---- INVITE ------> record_route() ----- INVITE ---->
add_rr_param(";foo=true")
--- reINVITE -----> loose_route() ---- reINVITE --->
check_route_param(";foo=true")
<-- reINVITE ------ loose_route() <--- reINVITE ----
check_route_param(";foo=true")
<------ BYE ------- loose_route() <----- BYE -------
check_route_param(";foo=true")这意思就是说,UAC 和 UAS 之间所有的 SIP 消息都要经过 Kamailio,包括 Request 消息和 Reply 消息。
rr 模块函数很少,但不容易理解,能参考的路由脚本不多。笔者根据自己的经验整理此文,希望对读者有所裨益。
同网段路由
UAC、Kamailio 以及 UAS 都在同一个网段,这种情况下的路由非常简单,调用 record_route() 之后,Kamailio 自动加上自己的 IP 地址和端口。
listen=udp:KAM_IP:KAM_PORT双网卡路由
最典型的属于一个网卡在内,另外一个网卡对公网。这种情况的路由也比较简单,调用 record_route() 之后,Kamailio 自动加上双 rr 头。
listen=udp:eth0:5060
listen=udp:eth1:5060但需要注意下面几个要点:
单网卡1:1NAT
阿里云的网络就是典型的1:1 NAT,只有一个网卡。
listen=udp:内网地址:SIP端口 advertise 公网地址:SIP端口VOS-----Kamailio-----FreeSWITCH比较典型的是:VOS 看到 Kamailio 的公网地址,FreeSWITCH 看到 Kamailio 的内网地址。
这里一般有二种处理办法,一种是单 rr,另外一种是双 rr。
我们一个一个讲。
单 rr 显然只能给 Kamailio 的公网地址,但 FreeSWITCH 虽然通常跟 Kamailio 同在一个内网网段,这就需要 FreeSWITCH 能访问 Kamaialio 的外网地址。
那有没有变通方法,让 FreeSWITCH 只访问 kamailio 的内网地址呢?
当然有!
就是做一条iptables nat规则,似外实内。
下面是一个例子:
iptables -t nat -A OUTPUT -d 113.11.22.33 -p udp --dport 5060 -j DNAT --to-destination 10.167.82.4:5060另外一个办法是使能双 rr,可以这样定义 Kamailio 网络拓扑:
listen=udp:KAM_IP4_PRIVATE_ADDR:KAM_SIP_LAN_PORT
listen=udp:KAM_IP4_PRIVATE_ADDR:KAM_SIP_WAN_PORT advertise MY_IP4_PUBLIC_ADDR:KAM_SIP_WAN_PORT也就是定义二个不同的 SIP 端口
路由里面调用record_route, Kamaiilio 能理解上面的网络拓扑,自动加上双 rr
要避免这样定义:
listen=udp:KAM_IP4_PRIVATE_ADDR:KAM_SIP_LAN_PORT
listen=udp:KAM_IP4_PRIVATE_ADDR:KAM_SIP_WAN_PORT
advertise=MY_IP4_PUBLIC_ADDR一般看到这里就可以收工了。
下面讲特别场景下的 rr。
MS Teams
Kamailio 可以作为微软 MS Teams 的 Direct Routing。
但微软 MS Teams 对 rr 头有特别的要求,只能用域名,不能用 IP 地址,那怎么办呢?
可参考下面的代码:
route[RECORD_ROUTE] {
if (isflagset(FLT_SRC_MS_TEAMS)) {
record_route_preset("KAM_IP4_ADDR:KAM_SIP_PORT;transport=tcp", "KAM_DOMAIN:KAM_SIPS_PORT;transport=tls");
add_rr_param(";r2=on");
} else if isflagset(FLT_DST_MS_TEAMS) {
record_route_preset("KAM_DOMAIN:KAM_SIPS_PORT;transport=tls", "KAM_IP4_ADDR:KAM_SIP_PORT;transport=tcp");
add_rr_param(";r2=on");
} else {
record_route();
}
return;
}特殊网络拓扑下的rr
下面讲到的更加特别。
Kamailio 单网卡。
IMS -------------- Kamailio ------------ FreeSWITCH
10.2.3.4 listen 192.168.1.100 172.16.1.99
外网地址 10.2.3.5
外网地址 172.16.1.100对于 IMS 来说,只能用 10.2.3.5 访问 Kamailio
对于 FreeSWITCH 来说, 只能用 172.16.1.100 访问 Kamailio
Kamailio 配置如下:
listen=udp:192.168.1.100:5060
alias=10.2.3.5:5060
alias=172.16.1.100:5060路由脚本需要特别处理:
如果 INVITE 来自 IMS ,设置分支标志 FLB_SRC_IMS_DST_FreeSWITCH,不能调用 record_route(Kamailio 理解不了这种网络拓扑),而是 route(rr)。
如果 INVITE 来自 FreeSWITCH, 设置分支标志 FLB_SRC_FreeSWITCH_DST_IMS,同理,需要 route(rr)。
下面是 route[rr] 的具体实现:
route[rr] {
if (isflagset(FLT_SRC_FreeSWITCH_DST_IMS)) {
record_route_preset("10.2.3.5:5060", "172.16.1.100:5060");
add_rr_param(";r2=on");
else if (isflagset(FLT_SRC_IMS_DST_FreeSWITCH)){
record_route_preset("172.16.1.100:5060", "10.2.3.5:5060");
add_rr_param(";r2=on");
} else {
record_route();
}
return;
}rtpengine 要怎么处理呢?
可以这样定义 rtpengine 的 interface:
interface=IMS/192.168.1.100!10.2.3.5;FreeSWITCH/192.168.1.100!172.16.1.100对应的路由为:
route[NATMANAGE] {
...
$xavp(r=>$T_branch_idx) = "replace-origin replace-session-connection";
if (is_request() && !has_totag()) {
if (isflagset(FLT_SRC_FreeSWITCH_DST_IMS)) {
$xavp(r=>$T_branch_idx) = $xavp(r=>$T_branch_idx) + ”direction=FreeSWITCH direction=IMS"
} else if (isflagset(FLT_SRC_IMS_DST_FreeSWITCH)){
$xavp(r=>$T_branch_idx) = $xavp(r=>$T_branch_idx) + ”direction=IMS direction=FreeSWITCH"
}
}
rtpengine_manage($xavp(r=>$T_branch_idx));
...
}参考资料:
https://kb.smartvox.co.uk/opensips/contact-and-record-route-headers-explained/
本文分享自 FreeSWITCH中文社区 微信公众号,前往查看
如有侵权,请联系 cloudcommunity@tencent.com 删除。
本文参与 腾讯云自媒体同步曝光计划 ,欢迎热爱写作的你一起参与!