当前位置: 首页 > news >正文

Kamailio uac_replace和uac_restore

uac模块包含的内容很多,本文仅讨论uac_replace和uac_restore

先比较二段路由代码:

# 路由1
$fU = "alice";
$tU = "bob";
$du = ...;
t_relay();
exit;# OpenSIPS3.2 似乎不允许这样修改主被叫,不清楚是出于什么样的考虑
# 路由2
uac_replace_from('"alice"', "sip:" + "alice" + "@" + $fd);
uac_replace_to('"bob"', "sip:" + "bob" + "@" + $td);
$du = ...;
t_relay();
exit;

路由2修改了主被叫,同时还保留了原始主被叫,就这就是二个路由的区别

示意如下:

uac                   kamailio                 uas<----->                      <----->原始主被叫保持不变             新的主叫和被叫

那么问题是原始主被叫保存到哪里呢?

回答是有二个选择:

  • rr头
  • 对话(dialog)变量

下面是二个完整的kamailio路由:

第一个路由是把原始主被叫保存到rr头,并且restore_mode配置为auto

测试的方法非常简单:一个sip ua以1001注册到kamailio(不认证),另外一个sip ua以1002注册到kamailio,1001呼叫1002,用sngrep抓包。

debug=2
log_stderror=no
log_facility=LOG_LOCAL0
log_prefix="{$mt $hdr(CSeq) $ci} "
enable_sctp=nolisten=udp:192.168.100.200:5060# mpath="/usr/local/lib/kamailio/modules/"loadmodule "kex.so"
loadmodule "corex.so"
loadmodule "tm.so"
loadmodule "tmx.so"
loadmodule "sl.so"
loadmodule "rr.so"
loadmodule "pv.so"
loadmodule "maxfwd.so"
loadmodule "usrloc.so"
loadmodule "registrar.so"
loadmodule "textops.so"
loadmodule "textopsx.so"
loadmodule "siputils.so"
loadmodule "xlog.so"
loadmodule "sanity.so"
loadmodule "ctl.so"
loadmodule "cfg_rpc.so"loadmodule "uac.so"modparam("sanity", "autodrop", 0)modparam("tm", "failure_reply_mode", 3)
modparam("tm", "fr_timer", 30000)
modparam("tm", "fr_inv_timer", 120000)modparam("rr", "enable_full_lr", 0)
modparam("rr", "append_fromtag", 1) /*vip*/
modparam("tm", "auto_inv_100", 0)modparam("registrar", "method_filtering", 1)
/* uncomment the next line to disable parallel forking via location */
# modparam("registrar", "append_branches", 0)
modparam("registrar", "max_expires", 3600)
modparam("registrar", "gruu_enabled", 0)
modparam("registrar", "use_path", 1)
modparam("registrar", "path_mode", 0)modparam("usrloc", "timer_interval", 60)
modparam("usrloc", "timer_procs", 1)
modparam("usrloc", "use_domain", 0)
modparam("usrloc", "db_mode", 0)modparam("uac", "rr_from_store_param", "vsf")
modparam("uac", "rr_to_store_param", "vst")
modparam("uac", "restore_mode", "auto")
modparam("uac", "restore_dlg", 0)
modparam("uac", "restore_passwd", "my_secret_passwd")request_route {xinfo("$rm|$fU!$tU|$ci from $si:$sp\n");route(REQINIT);route(NATDETECT);if (is_method("CANCEL")) {if (t_check_trans()) {route(RELAY);}exit;}if (!is_method("ACK")) {if(t_precheck_trans()) {t_check_trans();exit;}t_check_trans();}route(WITHINDLG);route(AUTH);remove_hf("Route");if (is_method("INVITE|SUBSCRIBE")) {record_route();}route(REGISTRAR);route(LOCATION);return;
}route[RELAY] {if (is_method("INVITE|BYE|SUBSCRIBE|UPDATE")) {if(!t_is_set("branch_route")) t_on_branch("MANAGE_BRANCH");}if (is_method("INVITE|SUBSCRIBE|UPDATE")) {if(!t_is_set("onreply_route")) t_on_reply("MANAGE_REPLY");}if (is_method("INVITE")) {if(!t_is_set("failure_route")) t_on_failure("MANAGE_FAILURE");}if (!t_relay()) {sl_reply_error();}exit;
}route[REQINIT] {set_reply_no_connect();force_rport();if (!mf_process_maxfwd_header("10")) {sl_send_reply("483", "Too Many Hops");exit;}if(is_method("OPTIONS")) {sl_send_reply("200", "OK");exit;}if(is_method("SUBSCRIBE")) {sl_send_reply("200", "OK");exit;}if(!sanity_check("17895", "7")) {xlog("Malformed SIP request from $si:$sp\n");exit;}
}route[WITHINDLG] {if (!has_totag()) return;if (loose_route()) {if (is_method("BYE")) {;} else if ( is_method("ACK") ) {route(NATMANAGE);} else if ( is_method("NOTIFY") ) {record_route();}route(RELAY);exit;}if ( is_method("ACK") ) {if ( t_check_trans() ) {route(RELAY);exit;} else {exit;}}sl_send_reply("404", "Not here");exit;
}route[REGISTRAR] {if (!is_method("REGISTER")) return;if (!save("location")) {sl_reply_error();}exit;
}route[LOCATION] {if (!lookup("location")) {$var(rc) = $rc;t_newtran();switch ($var(rc)) {case -1:case -3:send_reply("404", "Not Found");exit;case -2:send_reply("405", "Method Not Allowed");exit;}}uac_replace_from('"alice"', "sip:" + "alice" + "@" + $fd);uac_replace_to('"bob"', "sip:" + "bob" + "@" + $td);route(RELAY);exit;
}route[AUTH] {return;
}route[NATDETECT] {return;
}route[NATMANAGE] {return;
}branch_route[MANAGE_BRANCH] {xinfo("new branch [$T_branch_idx] to $ru\n");route(NATMANAGE);return;
}reply_route {if(!sanity_check("17604", "6")) {xlog("Malformed SIP response from $si:$sp\n");drop;}return;
}onreply_route[MANAGE_REPLY] {xinfo("incoming reply\n");return;
}failure_route[MANAGE_FAILURE] {route(NATMANAGE);if (t_is_canceled()) exit;return;
}

这是kamailio收到的invite:

INVITE sip:1002@192.168.100.200 SIP/2.0
Via: SIP/2.0/UDP 192.168.100.172:58116;branch=z9hG4bK-d87543-1e0d1449a250ef06-1--d87543-;rport
Max-Forwards: 70
Contact: <sip:1001@192.168.100.172:58116>
To: "1002"<sip:1002@192.168.100.200>
From: <sip:1001@192.168.100.200>;tag=dc79041f
Call-ID: YjlhMzAyZGJlMWFhMjRkOTYyNzY1YzY5ZWFiOTg1MzE.
CSeq: 1 INVITE
Allow: INVITE, ACK, CANCEL, OPTIONS, BYE, REFER, NOTIFY, MESSAGE, SUBSCRIBE, INFO
Content-Type: application/sdp
User-Agent: eyeBeam release 1011d stamp 40820
Content-Length: 292

kamailio t_relay()出去是这样:

INVITE sip:1002@192.168.100.172:11806 SIP/2.0
Record-Route: <sip:192.168.100.200;lr;ftag=dc79041f;vsf=bXlfczU/KzdRLnhqb2xwantmXnN7f3BlRA--;vst=bXlfczY8IBcFV3t9bHR5cnJ4X215YXJV>
Via: SIP/2.0/UDP 192.168.100.200;branch=z9hG4bK10d9.6654b4ffba5da6fea3cd3f80b89690c4.0
Via: SIP/2.0/UDP 192.168.100.172:58116;received=192.168.100.172;branch=z9hG4bK-d87543-1e0d1449a250ef06-1--d87543-;rport=58116
Max-Forwards: 69
Contact: <sip:1001@192.168.100.172:58116>
To: "bob"<sip:bob@192.168.100.200>
From: "alice" <sip:alice@192.168.100.200>;tag=dc79041f
Call-ID: YjlhMzAyZGJlMWFhMjRkOTYyNzY1YzY5ZWFiOTg1MzE.
CSeq: 1 INVITE
Allow: INVITE, ACK, CANCEL, OPTIONS, BYE, REFER, NOTIFY, MESSAGE, SUBSCRIBE, INFO
Content-Type: application/sdp
User-Agent: eyeBeam release 1011d stamp 40820
Content-Length: 292

请注意rr头里面的vsf和vst参数,就是经过加密处理后的原始主被叫

这是另外一段kamailio路由,把原始主被叫保存到对话变量

debug=2
log_stderror=no
log_facility=LOG_LOCAL0
log_prefix="{$mt $hdr(CSeq) $ci} "
enable_sctp=nolisten=udp:192.168.100.200:5060# mpath="/usr/local/lib/kamailio/modules/"loadmodule "kex.so"
loadmodule "corex.so"
loadmodule "tm.so"
loadmodule "tmx.so"
loadmodule "sl.so"
loadmodule "rr.so"
loadmodule "pv.so"
loadmodule "maxfwd.so"
loadmodule "usrloc.so"
loadmodule "registrar.so"
loadmodule "textops.so"
loadmodule "textopsx.so"
loadmodule "siputils.so"
loadmodule "xlog.so"
loadmodule "sanity.so"
loadmodule "ctl.so"
loadmodule "cfg_rpc.so"loadmodule "dialog.so"
loadmodule "uac.so"modparam("sanity", "autodrop", 0)modparam("tm", "failure_reply_mode", 3)
modparam("tm", "fr_timer", 30000)
modparam("tm", "fr_inv_timer", 120000)modparam("rr", "enable_full_lr", 0)
modparam("rr", "append_fromtag", 1) /*vip*/
modparam("tm", "auto_inv_100", 0)modparam("registrar", "method_filtering", 1)
/* uncomment the next line to disable parallel forking via location */
# modparam("registrar", "append_branches", 0)
modparam("registrar", "max_expires", 3600)
modparam("registrar", "gruu_enabled", 0)
modparam("registrar", "use_path", 1)
modparam("registrar", "path_mode", 0)modparam("usrloc", "timer_interval", 60)
modparam("usrloc", "timer_procs", 1)
modparam("usrloc", "use_domain", 0)
modparam("usrloc", "db_mode", 0)modparam("dialog", "db_mode", 0)modparam("uac", "restore_mode", "auto")
modparam("uac", "restore_dlg", 1)request_route {xinfo("$rm|$fU!$tU|$ci from $si:$sp\n");route(REQINIT);route(NATDETECT);if (is_method("CANCEL")) {if (t_check_trans()) {route(RELAY);}exit;}if (!is_method("ACK")) {if(t_precheck_trans()) {t_check_trans();exit;}t_check_trans();}route(WITHINDLG);route(AUTH);remove_hf("Route");if (is_method("INVITE|SUBSCRIBE")) {record_route();}route(REGISTRAR);if (is_method("INVITE")) {dlg_manage();}route(LOCATION);return;
}route[RELAY] {if (is_method("INVITE|BYE|SUBSCRIBE|UPDATE")) {if(!t_is_set("branch_route")) t_on_branch("MANAGE_BRANCH");}if (is_method("INVITE|SUBSCRIBE|UPDATE")) {if(!t_is_set("onreply_route")) t_on_reply("MANAGE_REPLY");}if (is_method("INVITE")) {if(!t_is_set("failure_route")) t_on_failure("MANAGE_FAILURE");}if (!t_relay()) {sl_reply_error();}exit;
}route[REQINIT] {set_reply_no_connect();force_rport();if (!mf_process_maxfwd_header("10")) {sl_send_reply("483", "Too Many Hops");exit;}if(is_method("OPTIONS")) {sl_send_reply("200", "OK");exit;}if(is_method("SUBSCRIBE")) {sl_send_reply("200", "OK");exit;}if(!sanity_check("17895", "7")) {xlog("Malformed SIP request from $si:$sp\n");exit;}
}route[WITHINDLG] {if (!has_totag()) return;if (loose_route()) {if (is_method("BYE")) {;} else if ( is_method("ACK") ) {route(NATMANAGE);} else if ( is_method("NOTIFY") ) {record_route();}route(RELAY);exit;}if ( is_method("ACK") ) {if ( t_check_trans() ) {route(RELAY);exit;} else {exit;}}sl_send_reply("404", "Not here");exit;
}route[REGISTRAR] {if (!is_method("REGISTER")) return;if (!save("location")) {sl_reply_error();}exit;
}route[LOCATION] {if (!lookup("location")) {$var(rc) = $rc;t_newtran();switch ($var(rc)) {case -1:case -3:send_reply("404", "Not Found");exit;case -2:send_reply("405", "Method Not Allowed");exit;}}uac_replace_from('"alice"', "sip:" + "alice" + "@" + $fd);uac_replace_to('"bob"', "sip:" + "bob" + "@" + $td);route(RELAY);exit;
}route[AUTH] {return;
}route[NATDETECT] {return;
}route[NATMANAGE] {return;
}branch_route[MANAGE_BRANCH] {xinfo("new branch [$T_branch_idx] to $ru\n");route(NATMANAGE);return;
}reply_route {if(!sanity_check("17604", "6")) {xlog("Malformed SIP response from $si:$sp\n");drop;}return;
}onreply_route[MANAGE_REPLY] {xinfo("incoming reply\n");return;
}failure_route[MANAGE_FAILURE] {route(NATMANAGE);if (t_is_canceled()) exit;return;
}

现在1001呼叫1002,接着执行`kamcmd dlg.list`,输出如下:

{
    h_entry: 3555
    h_id: 11955
    ref: 2
    call-id: MGQ2NTc4MGM0YzQ4MjI4MWJiMTI2NzViZjBhZmNiYjU.
    from_uri: sip:1001@192.168.100.200
    to_uri: sip:1002@192.168.100.200
    state: 4
    start_ts: 1698647274
    init_ts: 1698647272
    end_ts: 0
    duration: 15
    timeout: 1698690474
    lifetime: 43200
    dflags: 643
    sflags: 0
    iflags: 0
    caller: {
        tag: f56df00b
        contact: sip:1001@192.168.100.172:58116
        cseq: 1
        route_set: 
        socket: udp:192.168.100.200:5060
    }
    callee: {
        tag: 1f0d4519
        contact: sip:1002@192.168.100.172:11806
        cseq: 0
        route_set: 
        socket: udp:192.168.100.200:5060
    }
    profiles: {
    }
    variables: {
        {
            _uac_tdpnew: "bob"
        }
        {
            _uac_tdp: "1002"
        }
        {
            _uac_tonew: sip:bob@192.168.100.200
        }
        {
            _uac_to: sip:1002@192.168.100.200
        }
        {
            _uac_fdpnew: "alice"
        }
        {
            _uac_fdp: 
        }
        {
            _uac_funew: sip:alice@192.168.100.200
        }
        {
            _uac_fu: sip:1001@192.168.100.200
        }
    }
}

相关文章:

  • 电脑屏幕监控软件,能够帮助企业完成哪些事情?
  • C++ 单例模式
  • 学习redis之前的泛泛而谈(特性介绍,应用场景,Ubuntu安装与通用命令介绍)
  • KnowledgeGPT:利用检索和存储访问知识库上增强大型语言模型10.30
  • VMware虚拟网络连接的三种方式
  • 面试算法44:二叉树中每层的最大值
  • N-131基于jsp,ssm物流快递管理系统
  • 【C语言】字符串与指针
  • Mac/Linux类虚拟机_CrossOver虚拟机CrossOver 23.6正式发布2024全新功能解析
  • 实现基于 Azure DevOps 的数据库 CI/CD 最佳实践
  • Log4j-tag丢失
  • 力扣刷题 day61:10-31
  • 【10种排序算法总结】C++实现
  • AI:45-基于深度学习的声纹识别
  • Oracle数据库创建Sequence序列的基本使用
  • android 一些 utils
  • Cumulo 的 ClojureScript 模块已经成型
  • GitUp, 你不可错过的秀外慧中的git工具
  • HTTP请求重发
  • JavaScript设计模式系列一:工厂模式
  • MD5加密原理解析及OC版原理实现
  • nginx(二):进阶配置介绍--rewrite用法,压缩,https虚拟主机等
  • Python学习笔记 字符串拼接
  • SSH 免密登录
  • 前端每日实战:61# 视频演示如何用纯 CSS 创作一只咖啡壶
  • 如何使用Mybatis第三方插件--PageHelper实现分页操作
  • 小程序button引导用户授权
  • 一道面试题引发的“血案”
  • 原生js练习题---第五课
  • ​LeetCode解法汇总2182. 构造限制重复的字符串
  • ​LeetCode解法汇总2304. 网格中的最小路径代价
  • # C++之functional库用法整理
  • (+4)2.2UML建模图
  • (13)[Xamarin.Android] 不同分辨率下的图片使用概论
  • (2)(2.10) LTM telemetry
  • (2.2w字)前端单元测试之Jest详解篇
  • (JSP)EL——优化登录界面,获取对象,获取数据
  • (八)Spring源码解析:Spring MVC
  • (附源码)springboot课程在线考试系统 毕业设计 655127
  • (附源码)计算机毕业设计高校学生选课系统
  • (九)信息融合方式简介
  • (每日持续更新)jdk api之FileReader基础、应用、实战
  • (十五)使用Nexus创建Maven私服
  • (学习日记)2024.01.19
  • (一)SpringBoot3---尚硅谷总结
  • (转)关于如何学好游戏3D引擎编程的一些经验
  • .【机器学习】隐马尔可夫模型(Hidden Markov Model,HMM)
  • .NET Core引入性能分析引导优化
  • .NET LINQ 通常分 Syntax Query 和Syntax Method
  • .NET 事件模型教程(二)
  • .Net 中Partitioner static与dynamic的性能对比
  • .net 中viewstate的原理和使用
  • .NET/C# 反射的的性能数据,以及高性能开发建议(反射获取 Attribute 和反射调用方法)
  • .NET委托:一个关于C#的睡前故事
  • .NET学习全景图