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=no

listen=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:[email protected] SIP/2.0
Via: SIP/2.0/UDP 192.168.100.172:58116;branch=z9hG4bK-d87543-1e0d1449a250ef06-1--d87543-;rport
Max-Forwards: 70
Contact: 
To: "1002"
From: ;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:[email protected]:11806 SIP/2.0
Record-Route: 
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: 
To: "bob"
From: "alice" ;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=no

listen=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:[email protected]
    to_uri: sip:[email protected]
    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:[email protected]:58116
        cseq: 1
        route_set: 
        socket: udp:192.168.100.200:5060
    }
    callee: {
        tag: 1f0d4519
        contact: sip:[email protected]:11806
        cseq: 0
        route_set: 
        socket: udp:192.168.100.200:5060
    }
    profiles: {
    }
    variables: {
        {
            _uac_tdpnew: "bob"
        }
        {
            _uac_tdp: "1002"
        }
        {
            _uac_tonew: sip:[email protected]
        }
        {
            _uac_to: sip:[email protected]
        }
        {
            _uac_fdpnew: "alice"
        }
        {
            _uac_fdp: 
        }
        {
            _uac_funew: sip:[email protected]
        }
        {
            _uac_fu: sip:[email protected]
        }
    }
}

你可能感兴趣的:(Kamailio,uac_replace,uac_restore)