Edge脚本
# VERSION=20.05.06.1#-------------------------------------------------# variables# - CF_INNER_IP x.x.x.x# - CF_PUBLIC_IP x.x.x.x# - CF_DB mysql://root@xxx:3306/db# - CF_HOMER x.x.x.x:9060# - CF_INFLUXDB_URL http://x.x.x.x:port/write?db=dbName#------------------------------------------------log_level=3 #log输出等级log_stderror=no #将opensips的标准错误写入日志yes nolog_facility=LOG_LOCAL0 #控制记录工具 默认工具LOG_LOCAL0children=4 #定义UDP 或者SCTP接口工作子进程dns_try_ipv6=no #对ipv6进行查找auto_aliases=no #自动别名 默认值onserver_header="Server:WSS" #公司的sip代理user_agent_header="User-Agent:WSS" #以UAC发送请求时生成的User-Agent标头字段的主体listen=udp:192.168.60.101:18627 as 192.168.60.101:18627listen=tcp:192.168.60.101:18627 as 192.168.60.101:18627listen=hep_udp:192.168.60.101:9061#监听以上端口#设置模块默认加载地址mpath="/usr/local/lib64/opensips/modules/"#基于TCP的SIP通信传输模块,仅提供tcp读取和写入loadmodule "proto_tcp.so"#基于udp的sip通信传输模块,仅提供udploadmodule="proto_udp.so"#对数据库进行连接loadmodule="db_mysql.so"#SIP信令模块loadmodule="signaling.so"#无状态回复loadmodule="sl.so"#事务loadmodule="tm.so"#如果没有最终的请求答复或否定的INVITE答复的ACK到达,则触发超时modparam("tm", "fr_timeout", 2)#记录路由和路由模块loadmodule "rr.so"#允许插入两条record-route 默认值1modparam("rr", "enable_double_rr", 1)#如果打开,则请求的from-tag会附加到record-route 默认值1modparam("rr", "append_fromtag", 1)#通过uri操作模块loadmodule "uri.so"#对话框支持模块loadmodule "dialog.so"#将对话框的信息从内存中推入数据库 0-no_db ,1-实时任何对话信息更爱理科反映到数据库中,2-延时基于定时器返回数据库,3-仅对话框关闭时才刷新到dbmodparam("dialog", "db_mode", 0)#读取数据库modparam("dialog", "db_url", "mysql://root:wellcloud@192.168.60.132:3306/core_2_4")#设置与对话框匹配,0-仅基于DID进行匹配,1-先根据DID尝试匹配,2-基于SIP元素匹配modparam("dialog","dlg_match_mode",1)#默认对话框超时时间,毫秒modparam("dialog","default_timeout",21600)#设置名称列表默认值为空modparam("dialog","profiles_with_value","domain")#最大转接处理器模块loadmodule "maxfwd.so"#文本操作模块loadmodule "textops.so"#管理接口fifo支持loadmodule "mi_fifo.so"#创建用于监听和读取外部命令的FIFO文件名称modparam("mi_fifo", "fifo_name", "/tmp/opensips_fifo")#分发器模块loadmodule "dispatcher.so"#设置数据库modparam("dispatcher", "db_url", "mysql://root:wellcloud@192.168.60.132:3306/core_2_4")#ping的方式,默认值optionsmodparam("dispatcher", "ds_ping_method", "OPTIONS")#定义将请求发送到故障网关的时间间隔modparam("dispatcher", "ds_ping_interval", 5)#网关设置探测模式时的探测次数modparam("dispatcher", "ds_probing_threshhold", 2)#控制测试哪些网关以查看它们是否可访问modparam("dispatcher", "ds_probing_mode", 1)#SIP操作模块loadmodule "sipmsgops.so"#NAT遍历help模块loadmodule "nathelper.so"#AVP操作模块loadmodule "avpops.so"#设置avp数据库modparam("avpops", "db_url", "mysql://root:wellcloud@192.168.60.132:3306/core_2_4")#设置avp所在表名modparam("avpops", "avp_table", "dbaliases")#rtp代理模块#loadmodule "rtpproxy.so"#modparam("rtpproxy","rtpproxy_sock","udp:CF_INNER_IP:7890")#rtpengine外部rtp继电器连接器loadmodule "rtpengine.so"#连接rtp代理套接字定义modparam("rtpengine", "rtpengine_sock", "udp:192.168.60.101:7890")#SIP前端路径支持loadmodule "path.so"#评估第一个Route URI 默认值0modparam("path", "use_received", 1)#嵌入式HTTP服务器loadmodule "httpd.so"#管理接口的http支持loadmodule "mi_http.so"#多域支持模块loadmodule "domain.so"#数据库支持modparam("domain", "db_url","mysql://root:wellcloud@192.168.60.132:3306/core_2_4")#数据库模式:0表示不缓存,1表示缓存 默认值0modparam("domain", "db_mode", 0)#动态路由loadmodule "drouting.so"#是否使用域匹配,默认值是1modparam("drouting", "use_domain", 1)#数据库支持modparam("drouting", "db_url","mysql://root:wellcloud@192.168.60.132:3306/core_2_4")#HTTP客户端实现loadmodule "rest_client.so"#允许最长时间(秒),默认20modparam("rest_client", "curl_timeout", 5)#最大连接时间(秒),默认20modparam("rest_client", "connection_timeout", 3)#emmm,没找到该模块?loadmodule "statistics.so"#HEP协议模块loadmodule "proto_hep.so"#指定HEP数据包的目的地和所使用的HEP协议的版本modparam("proto_hep", "hep_id","[hep_dst] 192.168.40.79:9060;transport=udp;version=3")#SIPTrace模块loadmodule "siptrace.so"#指定跟踪的目的地modparam("siptrace", "trace_id","[tid]uri=hep:hep_dst")#设置use_domain域是1modparam("auth_db|usrloc|uri", "use_domain", 1)route[r_invite_to_core]{if(is_method("INVITE")){#$cfg_line当前脚本运行行;$cs CSeq number;$rm request method;$fu From Uri,$tu To Urixlog("$cfg_line-$cs $rm $fu->$tu r_invite_from_out");#该函数为当前处理的请求创建对话框。该请求必须是初始请求。B是超时再见#如果创建失败,返回500,超时发送byeif(!create_dialog("B")){xlog("$cfg_line-$cs $rm $fu->$tu exec send_reply 500 Internal Server Error");send_reply("500","Internal Server Error");exit;}#如果含有sdpif(has_body("application/sdp")){xlog("$cfg_line-$cs $rm $fu->$tu exec rtpproxy_offer!");#rtpproxy_offer("oc","CF_INNER_IP");#重写sdp,使媒体能通过rtp传递。ICE=remove丢弃并且不插入任何ice值rtpengine_offer("ICE=remove");#记录rtp流rtpengine_start_recording();t_on_reply();}#为当前处理的消息设置一个标志setflag(10);#通过dispatch查找组1,运用0的计算方法if(!ds_select_dst("1","0")){send_reply("502","Service Unavailable");exit;}}#判断invite请求是否来自coreroute[r_invite_from_core]{if(ds_is_in_list("$si","$sp","1")){xlog(" enter in fs callout >>>");#just select gateway by request_urlif(is_method("INVITE") && has_body("appkication/sdp")){xlog("exec rtpproxy_offer!");#rtpproxy_offer("ro","CF_PUBLIC_IP");#重写sdp,使媒体能通过rtp传递。ICE=remove丢弃并且不插入任何ice值rtpengine_offer("ICE=remove");#记录rtprtpengine_start_recording();t_on_reply("r_rw_sdp");}#交由opensips处理t_relay();exit;}}#这部分有点问题route[r_seq_request]{#是否有tag标签,是否不是notify 通知所有用户if(has_totag()&&!is_method("NOtIFY")){#失去了route,不清楚if(loose_route()){#没找到,有application/sdpif(has_body("application/sdp")){#通过dispatch判断if(ds_is_in_list("$si","$sp","1")){#rtpproxy_offer("ro","CF_PUBLIC_IP");rtpengine_offer("ICE=remove");}else{#rtpproxy_offer("oc","CF_INNER_IP");#重写sdp,使媒体能通过rtp传递。ICE=remove丢弃并且不插入任何ice值rtpengine_offer("ICE_reomver");}#记录rtpengine_start_recording();if(is_method("INVITE")){t_on_reply("r_rw_sdp");}}#如果是bye,结束rtp代理if(is_method("BYE")){#rtpproxy_unforce();rtpengine_delete();}#该功能对照其所属的对话框(内部数据)检查当前收到的请求。#$DLG_status==null说明没有dialog。if($DLG_status!=NULL && !validate_dialog()){xlog("In-Dialog $rm from $si (callid=$ci) is not valid according to dialog\n")#该函数强制对话框中的SIP消息包含ruri,路由头和dst_uri,防止虚假注入的恶意请求如byefix_route_dialog();}t_relay();exit;}else{#ACK|BYE方法判段;判段当前是否与事务关联if(is_method("ACK|BYE") && t_check_trans()){t_relay();exit;}#stateless无状态回复sl_send_reply("404","Not here");}exit;}}route[r_fix_nat_contact]{#19表示1+2+16,其中1、2、16分别代表了不同的NAT检测条件,重要参考地址#https://www.yuque.com/wangdd/opensips/olt40x#测试请求是否源于natif(nat_uac_test("19")){xlog("find a NAT address,fix it...si=$si sp=$sp rm=$rm");#重写URI Contact HF以包含请求的源地址#Rewrites the URI Contact HF to contain request's source addressfix_nated_contact();}route[r_check_ip]{#对invite判断;是否来自domain表;if(is_method("INVITE")&&!is_from_local()&&!ds_is_in_list("$si","$sp","1")){#是否来自某个网关 gateway,-1全部检查,n忽略端口if(!is_from_gw("-1","n")){xlog("L_ERR","caller is not local and Not in whrite list!");#SIP信令模块发送reply,403send_reply("403","Forbidden IP");}}}route[r_cancel]{#对cancel方法进行判断if(is_method("CANCEL")){#判断当前是否与事物transaction关联if(t_check_trans()){#交由opensips处理t_relay();}exit;}}route[r_notify]{#方法为notify,通知所有用户事件;根据domain表查询;通过dispatcher表查询source IP,source port,组号if(is_method("NOTIFY")&&!is_from_local()&&!ds_is_in_list("$si","$sp","1")){#是否来自某个网关 gateway,-1全部检查,n忽略端口if(!is_from_gw("-1","n")){xlog("L_ERR","caller is not local and Not in whrite list!");#SIP信令模块发送reply,403send_reply("403","Forbidden IP");}}}#对options进行判断,查询服务器的能力route[r_options]{if(is_method("OPTIONS")){#stateless 无状态回复sl_send_reply("200","ok");exit();}}#修改User-Agent防止被攻击route[r_hide_fs_ua]{#User-Agent headerif($ua=~'^FreeSWITCH'){#remove head fromremove_hf("User-Agent");#添加头append_hf("User-Agent:WSS\r\n","CSeq");}}route[r_check_maxfwd]{#判断最大转接数if(!mf_prcess_maxfwd_head("10")){#483 过多转接退出opensipssl_send_reply("483","Too Many Hops");exit;}}#对确定地址的数据进行写入数据库操作rout[r_homer_capture]{if(is_method("INVITE|ACK|BYE")){xlog("<<<<<<<<<<welcome new request>>>>>>>>>>>>>>");#$rm request method, $fu from uri,$tu to uri,$cs Csq numberxlog("$rm $fu->$tu $cs");#sip capture$var(enableHomer)="192.168.40.79:9060";#has_totag确定是否有头,是否为初始请求if($var(enableHomer) && !has_totag()){#https://opensips.org/docs/modules/2.4.x/siptrace.html#func_sip_trace#在数据库中存储或重新部署当前已处理的SIP消息,事务或对话框#指定跟踪位置 的trace_id的名称,#d'/'D'跟踪对话框(m'/'M'跟踪消息,'t'/'T'跟踪交易。),#sip-启用sip消息跟踪;xlog-启用在当前范围内(日志,事务或消息)的xlog消息跟踪;休息-启用休息消息跟踪;sip_trace("tid","d,"sip|xlog|rest");}}}#回复路由onreply_route[r_rw_sdp]{#修复nat contact头fix_nated_contact();#如果是bye或者cancel 卸下rtp代理if(is_method("BYE|CANCEL")){#rtpproxy_unforce();rtpengine_delete();}#如果带有sdp信息if(has_body("application/sdp")){xlog("onreply_route1 rtpproxy_answer----si=$si");#如果源地址在记录中if(ds_is_in_list("$si","$sp","1")){#rtpproxy_answer("ro","CF_PUBLIC_IP");#重写sdp头,使信息能通过rtp代理rtpengine_answer();#这句代码不知道什么意义replace_all("sip:192.168.60.101","sip:192.168.60.101");}else{#rtpproxy_answer("oc","CF_INNER_IP");#这里ifelse好像没什么意义rtpengine_answer();replace_all("sip:192.168.60.101","sip:192.168.60.101");}}}onreply_route{route(r_hide_fs_ua);}route{#将rport参数添加到第一个Via标头(使sip消息能够正确返回)force_rport();#对确定的地址进行消息跟踪route(r_homer_capture);#确定转接是否超过界限,是,退出opensips主机route(r_check_maxfwd);#修改User-Agent防止被攻击route(r_hide_fs_ua);#对options进行无状态回复route(r_options);#通知所有事件route(r_notify);#对cancel(取消任何悬而未决的请求)route(r_cancel);#对invite请求判断是否来自fsroute(r_check_ip);#修复contact头,实现sip信息的nat穿透route(r_fix_nat_contact);#请求判断?route(r_seq_request);#记录返回地址record_route();#判断invite请求是否来自coreroute(r_invite_from_core);#处理发送core的invite请求route(r_invite_to_core);#route(r_register);#是否进入opensips操作if(!t_relay()){xlog("L_ERROR","reply error!!");#stateless无协议回复错误sl_reply_error();}}
core脚本问题
# VERSION=core-2.4.7.21log_level=3log_stderror=yeslog_facility=LOG_LOCAL0children=4auto_aliases=noserver_header="Server:WSS"user_agent_header="User-Agent:WMS"listen=udp:192.168.40.20:18627listen=hep_udp:192.168.40.20:9060mpath="/usr/local/lib64/opensips/modules/"loadmodule "proto_udp.so"loadmodule "proto_tcp.so"loadmodule "signaling.so"loadmodule "regex.so"loadmodule "sl.so"loadmodule "tm.so"loadmodule "rr.so"loadmodule "uac.so"loadmodule "maxfwd.so"loadmodule "sipmsgops.so"loadmodule "mi_fifo.so"loadmodule "dispatcher.so"loadmodule "rest_client.so"loadmodule "uri.so"loadmodule "db_mysql.so"loadmodule "textops.so"loadmodule "usrloc.so"loadmodule "registrar.so"loadmodule "acc.so"loadmodule "auth.so"loadmodule "auth_db.so"loadmodule "alias_db.so"loadmodule "domain.so"loadmodule "topology_hiding.so"loadmodule "dialog.so"loadmodule "nathelper.so"loadmodule "carrierroute.so"loadmodule "avpops.so"loadmodule "dialplan.so"loadmodule "permissions.so"loadmodule "drouting.so"loadmodule "group.so"loadmodule "load_balancer.so"loadmodule "httpd.so"loadmodule "mi_http.so"loadmodule "mi_json.so"loadmodule "path.so"loadmodule "exec.so"loadmodule "statistics.so"loadmodule "cachedb_local.so"#loadmodule "cachedb_redis.so"loadmodule "proto_hep.so"loadmodule "siptrace.so"modparam("tm", "fr_timeout", 5)modparam("tm", "fr_inv_timeout", 60)modparam("tm", "restart_fr_on_each_reply", 0)modparam("tm", "onreply_avp_mode", 1)modparam("dispatcher", "db_url", "mysql://root:111111@192.168.40.191:3306/core_2_4")modparam("dispatcher", "ds_ping_method", "OPTIONS")modparam("dispatcher", "ds_ping_interval", 5)modparam("dispatcher", "ds_probing_threshhold", 2)modparam("dispatcher", "hash_pvar", "$avp(select_fs_strategy_hash)")modparam("dispatcher", "ds_probing_mode", 1)modparam("rr", "append_fromtag", 1)modparam("mi_fifo", "fifo_name", "/tmp/opensips_fifo")modparam("mi_fifo", "fifo_mode", 0666)modparam("uri", "use_uri_table", 0)modparam("uri", "db_url","mysql://root:111111@192.168.40.191:3306/core_2_4")modparam("usrloc", "nat_bflag", "NAT")modparam("usrloc", "working_mode_preset","sql-only")modparam("usrloc", "db_url","mysql://root:111111@192.168.40.191:3306/core_2_4") # CUSTOMIZE MEmodparam("registrar", "tcp_persistent_flag", "TCP_PERSISTENT")modparam("registrar", "received_avp", "$avp(received_nh)")modparam("registrar", "max_contacts", 1)modparam("registrar", "min_expires", 120)modparam("registrar", "max_expires", 180)modparam("registrar", "default_expires", 150)modparam("registrar", "attr_avp", "$avp(attr)")modparam("acc", "early_media", 0)modparam("acc", "report_cancels", 1)modparam("acc", "detect_direction", 1)modparam("acc", "db_url","mysql://root:111111@192.168.40.191:3306/core_2_4") # CUSTOMIZE MEmodparam("auth_db", "calculate_ha1", yes)modparam("auth_db", "password_column", "password")modparam("auth_db", "db_url","mysql://root:111111@192.168.40.191:3306/core_2_4") # CUSTOMIZE MEmodparam("auth_db", "load_credentials", "")modparam("alias_db", "db_url","mysql://root:111111@192.168.40.191:3306/core_2_4") # CUSTOMIZE MEmodparam("domain", "db_url","mysql://root:111111@192.168.40.191:3306/core_2_4") # CUSTOMIZE MEmodparam("domain", "db_mode", 0) # 0: witchout cache, 1: Use cachingmodparam("auth_db|usrloc|uri", "use_domain", 1)modparam("dialog", "dlg_match_mode", 1)modparam("dialog", "default_timeout", 7200)modparam("dialog", "db_mode", 0) # 0:no_db, 1:realtime, 2:delayed, 3:shutdownmodparam("dialog", "profiles_with_value", "domain")modparam("dialog", "db_url","mysql://root:111111@192.168.40.191:3306/core_2_4") # CUSTOMIZE ME#modparam("dialog", "cachedb_url", "redis://CF_REDIS_DB/")modparam("nathelper", "natping_interval", 10)modparam("nathelper", "ping_nated_only", 1)modparam("nathelper", "received_avp", "$avp(received_nh)")modparam("carrierroute", "db_url", "mysql://root:111111@192.168.40.191:3306/core_2_4")modparam("carrierroute", "config_source", "db")modparam("carrierroute", "use_domain", 1)modparam("carrierroute", "db_failure_table", "carrierfailureroute")modparam("avpops", "db_url", "mysql://root:111111@192.168.40.191:3306/core_2_4")modparam("avpops", "avp_table", "dbaliases")modparam("dialplan", "db_url", "mysql://root:111111@192.168.40.191:3306/core_2_4")modparam("drouting", "use_domain", 1)modparam("drouting", "db_url","mysql://root:111111@192.168.40.191:3306/core_2_4")modparam("group", "use_domain", 1)modparam("group", "db_url", "mysql://root:111111@192.168.40.191:3306/core_2_4")modparam("load_balancer", "db_url", "mysql://root:111111@192.168.40.191:3306/core_2_4")modparam("load_balancer", "probing_reply_codes", "501, 403")modparam("load_balancer", "probing_interval", 30)modparam("rr", "enable_double_rr", 1)modparam("path", "use_received", 1)modparam("exec", "time_to_kill", 10)modparam("rest_client", "curl_timeout", 5)modparam("statistics", "stat_groups", "wj")modparam("proto_hep", "hep_id","[hep_dst] 192.168.60.228:9060;transport=udp;version=3")modparam("siptrace", "trace_id","[tid]uri=hep:hep_dst")modparam("cachedb_local", "cachedb_url", "local://")modparam("cachedb_local", "cache_clean_period", 120)route{#在Via头中添加rport参数使sip消息能够正确返回force_rport();#跟踪记录注册的sip信息route(r_siphub_capture);#不支持PUBLISH|SUBSCRIBE方法进行route(r_not_support);#内存溢出提示route(r_options);#修复notify请求下$rU request username 为空的情况route(r_fix_notify);#修复nat问题,route(r_nat_uac_test);#过滤回环route(r_max_fwd);#匹配现有对话,如果存在对话使用t_repley并结束route(r_fix_route_dialog);xlog("$cfg_line-$cs $rm $fu->$tu processing \n");#处理消息route(r_relay_seq_request);#为cancel方法,if (is_method("CANCEL")) {if (t_check_trans())t_relay();exit;}#如果过是重传请求则中断脚本t_check_trans();if (!is_method("REGISTER")) {if (is_from_local()) {#使用子路由,本地请求入口route(r_author_request_from_edge);} else {# is not from fs, may be from edge#非本地请求,调用子路由if (!lb_is_destination("$si","$sp","1") ) {route(r_did);}}}#抛弃表头loose_route();#方法是REGISTER|MESSAGE记录返回地址if (!is_method("REGISTER|MESSAGE")){record_route();}#方法是INVITE发送消息退出if (is_method("INVITE")) {if ( !create_dialog("B") ) {xlog("create dialog Error \n");send_reply("500","Internal Server Error");exit;}route(r_do_accounting);}#方法是PUBLIST|SUBSCRIBEif (is_method("PUBLISH|SUBSCRIBE")){sl_send_reply("503", "Service Unavailable");exit;}# handle registerr_registerr_registerroute(r_register);if ($rU==NULL) {xlog("rU is null \n");sl_send_reply("484","Address Incomplete");exit;}#是本地domain表if (is_from_local()){avp_db_query("SELECT limit_num,trunk_group FROM domain WHERE domain='$fd'","$avp(t_limit);$avp(t_trunk_group)");if(is_avp_set("$avp(t_limit)") && $avp(t_limit)>0 ){xlog("$fd limit $avp(t_limit) !\n");$var(t_domain) = $fd;route(r_do_limit, $var(t_domain), $avp(t_limit));}#记录返回头if (is_method("INVITE") && has_body("application/sdp")){record_route();}#回复路由t_on_reply("r_delete_trunk_info");#平衡配置if (!load_balance("1","trunk")) {xlog("load_balance failed: check fs is ok\n");#无状发送消息sl_send_reply("500","Service full.");exit;}t_relay();} else {$rd = $td;#查询本地路由if (!lookup("location","m")) {#判断数据库中是否存在if (!db_does_uri_exist()) {# -1 outbound reg: [56789][0-9]*if($rU=~'^[56789][0-9]+$'){$avp(call_origin_rU)=$rU;route(r_query_route);if(!is_avp_set("$avp(trunk_group)")) {sl_send_reply("402", "no trunk group");exit();}#移除标头remove_hf("P-Preferred-Identity");remove_hf("P-Asserted-Identity");xlog("begin route... carrier=$avp(carrier) trunk_group=$avp(trunk_group) request_username=$rU host=$avp(host)\n");#通过在初始请求上调用此函数,模块将隐藏拓扑,这意味着它将剥离并还原所有Via,Record-Route和Route标头,并将联系人替换为请求所在接口的IP地址。收到。topology_hiding();#将所有"WSS"替换为Freeswitchreplace_all("FreeSWITCH", "WMS");#此函数在给定的载波树中的给定域中搜索在prefix_matching中给定的用户的最长匹配项if(!cr_route("carrier1","$avp(trunk_group)", "$rU", "$rU", "call_id", "$avp(host)")){xlog("L_ERR","cr_route failed! send reply 485.\n");sl_send_reply("485", "route ambiguous!");}else {#setflag(ACC_DO);#setflag(ACC_MISSED);# In case of failure, re-route the request$avp(outbound_rU) = $rU;route(r_find_real_rU);$var(new_to_same) = "sip:"+ $rU + "@" + $td;#替换to标头中的uriuac_replace_to("$rU", "$var(new_to_same)");#使用failure,reply的分支路由t_on_failure("missed_call");t_on_reply("r_add_trunk_info");route(r_set_edge_ip);t_relay();}exit;}else{xlog("L_WARN","send reply 420 Bad Extension ! $ru\n");send_reply("420","Bad Extension");exit;}}else{if (is_method("INVITE")) {route(r_ext_bind_phone);}#为当前处理的SIP请求创建SIP事务t_newtran();xlog("L_WARN","404 not found !\n");t_reply("404", "Not Found");exit;}}#if (isbflagset(10))setflag(10);#如果没有tagif(!has_totag() && is_method("INVITE")) {#隐藏拓扑topology_hiding();}replace_all("FreeSWITCH", "WMS");route(relay);}}onreply_route[r_add_trunk_info]{if($avp(trunk_group)){append_hf("X-trunk-name: $avp(trunk_group)\r\n");append_hf("X-calltype: callout\r\n");}if($avp(host)){append_hf("X-th: $avp(host)\r\n");}if($avp(outbound_tU)){append_hf("X-tu: $avp(outbound_tU)\r\n");}if($avp(x_r_rU)){append_hf("X-ru: $avp(x_r_rU)\r\n");}}route[r_fix_notify]{#request Uri usernameif (is_method("NOTIFY") && $rU==NULL) {$rU=$tU;}}route[r_options]{#内存超过10M,返回503提示if(is_method("OPTIONS")) {if ($stat(free_size) < 10240000) {sl_send_reply("503", "free_size_limit");} else {sl_send_reply("200", "ok");}exit();}}route[r_nat_uac_test]{#解决信令问题,符合1、2、16情况,参考https://www.yuque.com/wangdd/opensips/olt40xif (nat_uac_test("19")) {if (is_method("REGISTER")) {fix_nated_register();setbflag(10);} else {# this function will cause ext cannot drop# fix_nated_contact();setflag(10);}}}route [r_fix_route_dialog] {#是否含有tag标签,是否是本地,是否属于以下方法if (has_totag() && is_myself("$rd") && is_method("INFO|INVITE|ACK|BYE|UPDATE|REFER")){#匹配现有对话if(match_dialog()){#会话存在且合法if ( $DLG_status!=NULL && !validate_dialog() ){#强制对话框,防止虚假注入的对话请求fix_route_dialog();}#发送请求t_relay();exit;}}}#判断数据跳过多route [r_max_fwd] {if (!mf_process_maxfwd_header("10")) {sl_send_reply("483","Too Many Hops");exit;}}route [r_relay_seq_request] {#是否有tag标签,并且不是notify请求if (has_totag() && !is_method("NOTIFY")) {#将所有WMS替换为FreeSwitchreplace_all("FreeSWITCH", "WMS");#判断route请求是否丢失if (loose_route()) {xlog("L_INFO","r_relay_seq_request: $rm $ru enter loose route");if (is_method("INVITE")) {record_route();} else {t_relay();exit;}#检查route头是否与给定正则表达式匹配,判断nat是否开启,开启设置flag为10if (check_route_param("nat=yes")){setflag(10);}#调用relay子路由route(relay);} else {#判断是否存在invite事务,且方法为ACK和BYE,发送请求if(t_check_trans() && is_method("ACK|BYE")){t_relay();} else {exit;}sl_send_reply("404","Not here");}exit;}}#route[r_author_request_from_edge]{route(r_not_register_h5);#检查给定的IP和PORT是否属于负载均衡器列表中配置的目标if(!lb_is_destination("$si","0","1")){if (!proxy_authorize("", "subscriber")) {xlog("$cfg_line-$cs $rm $fu->$tu start authorize\n");proxy_challenge("", "0");exit;}#Auth whole usernameif($aU =~'^gateway'){#删除认证头consume_credentials();if (!load_balance("1","trunk")) {xlog("L_ERR","load_balance:1,trunk is failed !!,exec sl_send_reply:500 Service full\n");sl_send_reply("500","Service full");exit;}record_route();t_relay();exit();}else{if (!db_check_from()) {sl_send_reply("403","Forbidden auth ID");exit;}consume_credentials();}}}route[r_did]{#对数据库进行查询赋值给三个数据avp_db_query("SELECT username,domain,select_fs_strategy FROM dbaliases WHERE alias_username='$rU'","$avp(t_username);$avp(t_domain);$avp(select_fs_strategy)");# is did number from edge#检查是否设置了t_usernameif(is_avp_set("$avp(t_username)")){# this will exit#赋值$avp(select_fs_strategy_hash) = $rU;$rU = $avp(t_username);xlog("find did corrt_username $avp(t_username) $avp(t_domain) $fu $tu ru=$ru\n");#$ru request uri设置该地址$ru = "sip:"+$avp(t_username) + "@" + $avp(t_domain) + ";transport="+ $pr;xlog("repair after: ru=$ru\n");$avp(from_ru) = "sip:"+ $fU + "@" + $avp(t_domain);$avp(to_ru) = "sip:"+ $tU + "@" + $avp(t_domain);xlog("from_ru=$avp(from_ru) to_ru=$avp(to_ru)\n");#替换from标头中的uri部分uac_replace_from("$fU" , "$avp(from_ru)");#替换to标头红的uri部分uac_replace_to("$tU" , "$avp(to_ru)");# ces user x-trunkgroup header to set calltype for inbound# so do't remove it#添加表头append_hf("X-trunk-name: $si\r\n");append_hf("X-calltype: callin\r\n");#记录返回地址record_route();if ($avp(select_fs_strategy) == "d") {# 3 meaning fs group# 7 hash over hash_pvarxlog("$cfg_line <r_did> $rm $fu->$tu selec fs use dispatcher\n");#dispatch查找组名中为3的地址if (!ds_select_dst("3","7")) {send_reply("502","Service Unavailable");exit;}t_relay();exit;}xlog("$cfg_line <r_did> $rm $fu->$tu selec fs use load_balance\n");#平衡配置if (!load_balance("1","trunk")) {xlog("L_ERR","load_balance:1,trunk is failed !!,exec sl_send_reply:500 Service full\n");sl_send_reply("500","Service full");exit;}t_relay();exit();}# invite from fs will continue route}route [r_register] {if (is_method("REGISTER")){#?route(r_register_h5);#认证auth_code$var(auth_code) = www_authorize("", "subscriber");if ( $var(auth_code) == -1 || $var(auth_code) == -2 ) {xlog("L_NOTICE","Auth error for $fU@$fd from $si cause $var(auth_code)\n");}if ( $var(auth_code) < 0 ) {www_challenge("", "0");exit;}#根据uri表检查数据库if (!db_check_to()) {xlog("exec sl_send_reply:403 Forbidden auth ID\n");sl_send_reply("403","Forbidden auth ID");exit;}#设置一个标签if ( $pr=="TCP" || 0 ) setflag(TCP_PERSISTENT);$avp(attr)="sip:"+$si+":"+$sp;#如果一个文件中存在邮箱presentif(is_present_hf("X-Enable-Kickout")){#移除head fromremove_hf("X-Enable-Kickout");#保存于location表中if (!save("location","p1vf")){xlog("exec sl_reply_error\n");sl_send_reply("503","too many registered");}}#如果过注册了来自某个AOR的联系人else if (is_contact_registered("location","$fu",,"$ci")) {xlog("[r_register] $fu is already, use force register");if (!save("location","p1vf")){sl_send_reply("503","failed");}}else{if (!save("location","p1v")){xlog("exec sl_reply_error\n");sl_send_reply("503","too many registered");}}#$fU ffrom URI usernameif($fU =~"^gateway"){xlog("gateway>> update , $ct.fields(uri) si=$si sp=$sp fu=$fu tu=$tu ru=$ru\n");$var(rw_uri)=$ct.fields(uri);$var(ipstr)=$(var(rw_uri){s.select,1,@});$avp(ctip)=$(var(ipstr){s.select,0,;});xlog("gateway>> SELECT id, rewrite_host FROM carrierroute WHERE uri_username='$fU' and uri_domain='$fd' and rewrite_host!='$avp(ctip)'\n");#数据库查询语句avp_db_query("SELECT id, rewrite_host FROM carrierroute WHERE uri_username='$fU' and uri_domain='$fd' and rewrite_host!='$avp(ctip)'","$avp(lid);$avp(old_rh)");xlog("gateway>> update $avp(ctip) fU=$fU uri_domain=$fd lid=$avp(lid), $var(old_rh)\n");#avp是否设置if(is_avp_set("$avp(lid)")){xlog("gateway>> update rewrite_host : $avp(old_rh) > $avp(ctip)\n");avp_db_query("update carrierroute set rewrite_host='$avp(ctip)' WHERE uri_username='$fU' and uri_domain='$fd' ");update_stat("wj:update_gateway_count", "+1");}}exit;}}route[r_do_limit] {#将当前对话框插入配置文件set_dlg_profile("domain","$param(1)");#返回属于配置文件的对话框数get_profile_size("domain","$param(1)","$var(domain)");xlog("L_INFO","r_do_limit: User $param(1) has $var(domain) ongoing calls so far, limit is $param(2)\n");# check within limitif( $var(domain)>$param(2) ) {xlog("L_WARN","do_limit: user $param(1) exceeded number of calls [$var(domain)/$param(2)]\n");sl_send_reply("487", "Request Terminated: Channel limit exceeded\n");exit;# terminating this call will automatically remove the call from the profile}# call was added to the profile without exceeding the limit, simply continue}route[r_query_route]{xlog("L_INFO","query route fU=$fU rd=$rd\n");$var(extNumber)="";$var(extRE)="^8[0-9]{3,7}$";if ($fU=~$var(extRE)) {$var(extNumber)=$fU;} else if ($tU=~$var(extRE)) {$var(extNumber)=$tU;# fix no condition transfer 302 aws vos#uac_replace_to("$tU" , "$rU");}if ($var(extNumber)) {avp_db_query("SELECT id,caller_id_dpid,callee_id_dpid,trunk_group FROM wj_v_exten_route WHERE username='$var(extNumber)' and domain='$rd'","$avp(r_id);$avp(caller_id_dpid);$avp(callee_id_dpid);$avp(trunk_group)");}# query ext routexlog("db_query_ext_route_result: $var(extNumber) $avp(r_id);$avp(caller_id_dpid);$avp(callee_id_dpid);$avp(trunk_group)\n");# query ext route by tu@tif(!is_avp_set("$avp(r_id)")){#对数据库进行查询avp_db_query("SELECT id,caller_id_dpid,callee_id_dpid,trunk_group FROM wj_v_domain_route WHERE domain='$rd'","$avp(r_id);$avp(caller_id_dpid);$avp(callee_id_dpid);$avp(trunk_group)");xlog("db_query_domain_route_result: $avp(r_id);$avp(caller_id_dpid);$avp(callee_id_dpid);$avp(trunk_group)\n");}xlog("db_query_route_result : $avp(r_id);$avp(caller_id_dpid);$avp(callee_id_dpid);$avp(trunk_group)\n");if(is_avp_set("$avp(r_id)")){$var(nto)="";$var(nfrom)="";# change to headerif ($hdr(bindPhone)) {#将尝试根据拨号规则ID等于id的转换规则将src字符串转换为dest字符串dp_translate("$avp(callee_id_dpid)","$hdr(bindPhone)/$var(nto)");} else if ($tU=~$var(extRE)) {dp_translate("$avp(callee_id_dpid)", "$rU/$var(nto)");}else {dp_translate("$avp(callee_id_dpid)","$tU/$var(nto)");}xlog("$cfg_line-$cs $rm $fu->$tu in request nto=$var(nto)\n");if($var(nto)){$var(new_to) = "sip:"+ $var(nto) + "@" + $rd;$avp(outbound_tU) = $var(nto);xlog("$cfg_line-$cs $rm $fu->$tu in request outbound_tU=$avp(outbound_tU)\n");#uac_replace_to("$tU" , "$var(new_to)");}# change from headerif ($hdr(displayOrigin)) {$var(nfrom)=$hdr(displayOrigin);} else {dp_translate("$avp(caller_id_dpid)","$fU/$var(nfrom)");}if($var(nfrom)){$var(new_uri) = "sip:" +$var(nfrom)+ "@" + $fd;#对from的uri进行替换uac_replace_from("$var(nfrom)" , "$var(new_uri)");}remove_hf("Remote-Party-ID");remove_hf("displayOrigin");remove_hf("bindPhone");}}route [r_set_edge_ip] {#该函数从类似于存储器高速缓存的存储系统中获取属性的值cache_fetch("local","cache_$avp(host)", $avp(edge));#是否判断函数是否存在if(is_avp_set("$avp(edge)")){xlog("L_INFO","cache_fetch find host $avp(host) $avp(edge), no need sql query");}else {xlog("L_INFO","cache_fetch host not find, need sql query");avp_db_query("SELECT edge_ip FROM carrierroute WHERE rewrite_host='$avp(host)' and edge_ip is not null order by rand() limit 1","$avp(edge)");}if(is_avp_set("$avp(edge)")){xlog("L_INFO","r_set_edge_ip $ci edge addr is $avp(edge)");cache_store("local","cache_$avp(host)", "$avp(edge)");if ($avp(edge)=~'^sip') {$du=$avp(edge);} else {# use dispatcher send to edge just for trunkxlog("L_INFO", "r_set_edge_ip $ci use dipatcher to select edge");if (!ds_select_dst("$avp(edge)","0")) {send_reply("502","Service Unavailable");cache_remove("loacal","cache_$avp(host)");exit;}}}else{avp_db_query("SELECT attr FROM location WHERE username='$fU' and domain='$td'","$avp(edge)");if(is_avp_set("$avp(edge)")){$du=$avp(edge);}else{xlog("L_ERR","$fU@$td is Not Registed!!\n");}}}route[r_ext_bind_phone]{$avp(transfer_num) = $hdr(bindPhone);if (!$avp(transfer_num)) {avp_db_query("SELECT bind_mobile,bind_mobile_type from subscriber WHERE username='$tU' and domain='$td'","$avp(transfer_num);$avp(bmt)");xlog("L_INFO","r_ext_bind_phone bind_mobile=$avp(transfer_num)\n");}if($avp(bmt)=="disabled"){$avp(transfer_num):="";}if($avp(transfer_num) != "" ){$du="sip:"+$si+":"+$sp;$ru="sip:"+$avp(transfer_num)+"@"+$Ri+":"+$Rp;sl_send_reply("302","LCR Redirect");exit;}}route[relay] {xlog("L_INFO","$cfg_line-$cs $rm $fu->$tu: enter route relay \n");replace_all("FreeSWITCH", "WMS");if(is_present_hf("Remote-Party-ID")){remove_hf("Remote-Party-ID");}if (is_method("INVITE")) {t_on_reply("handle_nat");t_on_failure("missed_call");}if (isflagset(10)) {add_rr_param(";nat=yes");}if ($avp(attr)) {$du=$avp(attr);xlog("L_INFO","$cfg_line-$cs $rm $fu->$tu: get edge address from attr\n");} else {xlog("L_INFO", "$cfg_line-$cs $rm $fu->$tu: get edge address from database\n");avp_db_query("SELECT attr FROM location WHERE username='$tU' and domain='$td'","$avp(edge)");if ($avp(edge)) {$du=$avp(edge);} else {xlog("$cfg_line-$cs $rm $fu->$tu: can not get edge address\n");}}if (!t_relay()) {xlog("send reply 500 Internal Error!\n");send_reply("500","Internal Error");};exit;}onreply_route[handle_nat] {route(r_delete_sip_header_to_ext);if($rs==302){remove_hf("contact");$var(movedNum)=$(ct.fields(uri){uri.user});$var(new_contact)=$var(movedNum)+"@"+"192.168.40.20:18627";append_hf("Contact: <sip:$var(new_contact)>\r\n", "Call-ID");exit;}}failure_route[missed_call] {if (t_was_cancelled()) {exit;}xlog("L_ERR","failure_route reply $(err.rcode) - $(err.rreason) -$(err.info) -$(err.class) \n");if (isflagset(12)) {xlog("L_ERR","t_reply: 503 Service not available, no more gateways\n");t_reply("503", "Service not available, no more gateways");exit;}}local_route {if (is_method("BYE") && $DLG_dir=="UPSTREAM") {#根据请求进行报告acc_db_request("200 Dialog Timeout", "acc");}}route [r_not_support] {if (is_method("PUBLISH|SUBSCRIBE")){sl_send_reply("503", "Service Unavailable");exit;}}#记录消息route[r_do_accounting] {$var(enableAcc)=0;if($var(enableAcc)){do_accounting("db|log", "cdr|missed");}}route[r_find_real_rU]{xlog("L_INFO","r_find_real_rU $avp(ru_strip)\n");$avp(ru_strip)=$(ru{uri.param,s});switch ($avp(ru_strip)) {case "1":$avp(x_r_rU)=$(avp(call_origin_rU){s.substr,1,0});break;case "2":$avp(x_r_rU)=$(avp(call_origin_rU){s.substr,2,0});break;case "3":$avp(x_r_rU)=$(avp(call_origin_rU){s.substr,3,0});break;case "4":$avp(x_r_rU)=$(avp(call_origin_rU){s.substr,4,0});break;case "5":$avp(x_r_rU)=$(avp(call_origin_rU){s.substr,5,0});break;case "6":$avp(x_r_rU)=$(avp(call_origin_rU){s.substr,6,0});break;case "7":$avp(x_r_rU)=$(avp(call_origin_rU){s.substr,7,0});break;case "8":$avp(x_r_rU)=$(avp(call_origin_rU){s.substr,8,0});break;case "9":$avp(x_r_rU)=$(avp(call_origin_rU){s.substr,9,0});break;default:xlog("strip $avp(ru_strip) it not support\n");}}timer_route[wj_cr_reload, 600]{if (0 && $stat(wj:update_gateway_count) > 0) {xlog("L_INFO", "update_gateway_count: $stat(wj:update_gateway_count)\n");#执行外部命令exec("opensipsctl fifo cr_reload_routes");$stat(wj:update_gateway_count) = 0;}}timer_route[r_influxdb_monitor, 5] {$var(db_url)="";if ($var(db_url)) {$var(reqbody)="opensips,type=core,ip=192.168.40.20 real_used_size=" + $stat(real_used_size)+ ",active_dialogs=" + $stat(active_dialogs)+ ",inuse_transactions=" + $stat(inuse_transactions)+ ",waiting_udp=" + $stat(waiting_udp)+ ",cps_all=" + $stat(wj:cps_all) + ",cps_trunk=" + $stat(wj:cps_trunk);$var(rc) = rest_post("","$var(reqbody)","text/plain","$var(body)","$var(ct)","$var(rcode)");if (!$var(rc)) {xlog("L_ERR", "write to influx db error, please check the influxdb url\n");}$stat(wj:cps_all) = 0;$stat(wj:cps_trunk) = 0;}}route [r_delete_sip_header_to_ext] {remove_hf("X-trunk-name");remove_hf("X-trunk-direction");remove_hf("X-calltype");remove_hf("X-th");remove_hf("X-ru");remove_hf("X-tu");remove_hf("Remote-Party-ID");}onreply_route[r_delete_trunk_info]{route(r_delete_sip_header_to_ext);}#对register表头进行记录route[r_siphub_capture]{if(!is_method("REGISTER") && !has_totag()){sip_trace("tid", "d", "sip");}}#使用route[r_register_h5]{#如果邮件中存在标头字段,则返回true &&名称和副名称if (is_present_hf("Authorization") && $hdr(Authorization)=~"^webview") {if ($hdr(Authorization) == "webview2020") {$avp(attr)="sip:"+$si+":"+$sp;#没有保存在本地if (!save("location","p1vf")){sl_send_reply("401","Auth h5 failed");}} else {sl_send_reply("401","Auth h5 failed");}exit;}}route[r_not_register_h5]{if (is_present_hf("Authorization") && $hdr(Authorization) == "webview2020") {remove_hf("Authorization");# hand inviteif (is_method("INVITE") && has_body("application/sdp")){xlog("L_INFO", "$cfg_line enter h5 invite $ru");record_route();# go to fsif (!load_balance("1","trunk")) {xlog("L_INFO", "load_balance failed: check fs is ok\n");sl_send_reply("500","service full");exit;}t_relay();exit;}# hand message# todoelse if (is_method("MESSAGE")) {xlog("L_INFO", "$cfg_line enter h5 message $ru");route(r_message);}exit;}}route[r_message]{xlog("$cfg_line $rm $fu $tu $rb \n");$avp(message_body) = $rb;avp_db_query("select contact,attr from location where username='$rU' AND domain='$rd'","$avp(i_contact);$avp(i_attr)");xlog("$rm $fU $tU db query result $avp(i_contact) $avp(i_attr) \n");if (!is_avp_set("$avp(i_contact)")) {route(r_save_msg_to_db, "404");xlog("$cfg_line $rm $fu $tu: status of lookup is $avp(sql_re) \n");t_reply("404", "Not Found");exit;}t_on_reply("r_save_msg_record");$ru=$avp(i_contact);$du=$avp(i_attr);if (!t_relay()) {send_reply("500","Internal Error");}exit;}onreply_route[r_save_msg_record]{route(r_save_msg_to_db, $rs);}route[r_save_msg_to_db]{$var(sip_callid) = $(ci{s.escape.common});$var(fs_callid) = $(hdr(fs_callid){s.escape.common});$var(fu) = $(fU{s.escape.common}) + "@" + $(fd{s.escape.common});$var(tu) = $(tU{s.escape.common}) + "@" + $(td{s.escape.common});$var(msg) = $(avp(message_body){s.escape.common});xlog("$var(sip_callid), $var(fs_callid), $var(fu), $var(tu), $var(msg)");avp_db_query("insert into message_record(sip_callid,fs_callid,time,fu,tu,status,msg) values('$var(sip_callid)','$var(fs_callid)',now(),'$var(fu)','$var(tu)','$param(1)','$var(msg)')");xlog("message insert db message_record result: $rc");}
1.is_from_local()判断是否来自domain表
2.t_check_trans()判断事务
3.t_on_relay和sl_send_reply,send_reply
