Description

I noticed an issue regarding loose_route() when using Topos module.

My architecture is the following:

Client (behind NAT or not) ------>   Kamailio (Access SBC) -----------> Kamailio (Interconnect SBC) -----------> Carrier

Kamailio Access SBC is listening on 2 interfaces:

Public interface : udp:A.A.A.A:5060
Core interface   : udp:B.B.B.B:5060

Kamailio Interconnect SBC is listening on 2 interfaces:

Core interface           : udp:C.C.C.C:5060
Carrier-side interface   : udp:D.D.D.D:5060

TOPOS is configured only on second kamailio box (Interconnect SBC).
Record routing is used on both kamailios.

TOPOS module is configured as follows:

modparam("ndb_redis", "server", "name=srv1;addr=127.0.0.1;port=6379")
modparam("topos_redis", "serverid", "srv1")

modparam("topos", "storage", "redis")
modparam("topos", "contact_mode", 1)
modparam("topos", "cparam_name", "id")
modparam("topos", "rr_update", 1)

RR module is configured as follows:

modparam("rr", "enable_full_lr", 1)
modparam("rr", "append_fromtag", 1)
modparam("rr", "enable_double_rr", 1)

For an incomoing INVITE (direction: client to carrier) all is fine and topos can strip headers on bleg and insert the cookie on bleg contact as a param.

When Callee sends a BYE or re-INVITE, topos inserts route headers in aleg as shown in the next trace: (BYE as received from the carrier on the carrier-side interface D.D.D.D)

BYE sip:D.D.D.D:5060 SIP/2.0
Via: SIP/2.0/UDP x.x.x.x:5060;branch=z9hG4bKrdhsvc001omkvssqvfk0sd0185mt1.1
From: <sip:+33123456789@my-carrier-domain;transport=UDP;user=phone>;tag=SD69ao497-1472568650-1635329820043
To: <sip:+33987654321@my-own-domain;transport=UDP;user=phone>;tag=3ab10616
Call-ID: NjZjMDgyMGMxNzdkN2FhYmJlYzQyYjA5YWIzZThmZmI.
CSeq: 547381883 BYE
Max-Forwards: 64
Content-Length: 0
Route: <sip:D.D.D.D;r2=on;lr=on;ftag=3ab10616>,<sip:C.C.C.C;r2=on;lr=on;ftag=3ab10616>
Route: <sip:B.B.B.B;r2=on;lr=on;ftag=3ab10616;dlg_id=426.26c2>,<sip:A.A.A.A;r2=on;lr=on;ftag=3ab10616;dlg_id=426.26c2>
P-SR-XUID: atpsh-617925e5-82a5-1

Topos on the kamailio interconnect handles the BYE/re-INVITE and forward it to the second interface C.C.C.C as shown in the following trace:

BYE sip:A.A.A.A;r2=on;lr=on;ftag=3ab10616;dlg_id=426.26c2 SIP/2.0
Via: SIP/2.0/UDP 185.164.213.110;branch=z9hG4bKbd7.ab692eeb60369aa3a5e07f6b63cc9dd7.0
From: <sip:+33123456789@my-carrier-domain;transport=UDP;user=phone>;tag=SD69ao497-1472568650-1635329820043
To: <sip:+33987654321@my-own-domain;transport=UDP;user=phone>;tag=3ab10616
Call-ID: NjZjMDgyMGMxNzdkN2FhYmJlYzQyYjA5YWIzZThmZmI.
CSeq: 547381883 BYE
Max-Forwards: 63
Content-Length: 0
Route: <sip:C.C.C.C;r2=on;lr=on;ftag=3ab10616>
Route: <sip:B.B.B.B;r2=on;lr=on;ftag=3ab10616;dlg_id=426.26c2>
Contact: <sip:+33123456789@10.3.60.45;id=atpsh-617925e5-82a5-1>

When the BYE/re-INVITE request reaches the C.C.C.C interface, it is then forwarded directly to the ruri sip:A.A.A.A.

Or what I expect to receive in C.C.C.C interface is the following :

BYE <HERE SHOULD BE THE CALLER CONTACT URI> SIP/2.0
Via: SIP/2.0/UDP 80.10.231.173:5060;branch=z9hG4bKrdhsvc001omkvssqvfk0sd0185mt1.1
From: <sip:+33123456789@my-carrier-domain;transport=UDP;user=phone>;tag=SD69ao497-1472568650-1635329820043
To: <sip:+33987654321@my-own-domain;transport=UDP;user=phone>;tag=3ab10616
Call-ID: NjZjMDgyMGMxNzdkN2FhYmJlYzQyYjA5YWIzZThmZmI.
CSeq: 547381883 BYE
Max-Forwards: 64
Content-Length: 0
Route: <sip:D.D.D.D;r2=on;lr=on;ftag=3ab10616>
Route: <sip:C.C.C.C;r2=on;lr=on;ftag=3ab10616>
Route: <sip:B.B.B.B;r2=on;lr=on;ftag=3ab10616;dlg_id=426.26c2>
Route: <sip:A.A.A.A;r2=on;lr=on;ftag=3ab10616;dlg_id=426.26c2>
Contact: <sip:+33123456789@10.3.60.45;id=atpsh-617925e5-82a5-1>

I could work around this issue by doing the following :

  1. When receiving the BYE/re-INVITE on interface D.D.D.D, I explode the Route headers, delete old route headers and create new ones in order from the result of explode
  2. I update the ru with the contact uri which I stored in a htable when the initial INVITE was received
# Manage outgoing branches
branch_route[MANAGE_BRANCH] {
	xdbg("new branch [$T_branch_idx] to $ru\n");

	# TOPOS FIX
	if (is_method("INVITE")) {
		$sht(tpsindlg=>$ci) = $ci;
		$sht(tpsindlg=>$ci:ft) = $ft;
		$sht(tpsindlg=>$ci:ct) = $ct;
	}
}


route[WITHINDLG] {
	if (!has_totag()) return;

	# Fix bad Route Headers caused by TOPOS module
	if ($Ri == "D.D.D.D") {
		$var(rh0) = $(hdr(Route)[0]{s.select,0,,});
		$var(rh1) = $(hdr(Route)[0]{s.select,1,,});
		$var(rh2) = $(hdr(Route)[1]{s.select,0,,});
		$var(rh3) = $(hdr(Route)[1]{s.select,1,,});

		remove_hf_re("^Route$");

		append_hf("Route: $var(rh0)\r\n");
		append_hf("Route: $var(rh1)\r\n");
		append_hf("Route: $var(rh2)\r\n");
		append_hf("Route: $var(rh3)\r\n");
	}

	# sequential request within a dialog should
	# take the path determined by record-routing
	if (loose_route()) {

	  # Fix R-URI caused by TOPOS module
		if ($Ri == "D.D.D.D") {
			if ($ci == $sht(tpsindlg=>$ci) && $tt == $sht(tpsindlg=>$ci:ft)) {
				$ru = $(sht(tpsindlg=>$ci:ct){s.strip,1}{s.striptail,1});

				if (is_method("BYE")) {
					$sht(tpsindlg=>$ci) = $null;
					$sht(tpsindlg=>$ci:ft) = $null;
					$sht(tpsindlg=>$ci:ct) = $null;
				}
			}
		}

		route(RELAY);
		exit;
	}

	if (is_method("ACK")) {
		if ( t_check_trans() ) {
			# no loose-route, but stateful ACK;
			# must be an ACK after a 487
			# or e.g. 404 from upstream server
			route(RELAY);
			exit;
		} else {
			# ACK without matching transaction ... ignore and discard
			exit;
		}
	}

	sl_send_reply("404","Not here");
	exit;
}

Could you please tell if this is a normal behavior by TOPOS module or is it a bug?

Thank you.


You are receiving this because you are subscribed to this thread.
Reply to this email directly, view it on GitHub, or unsubscribe.
Triage notifications on the go with GitHub Mobile for iOS or Android.