Hi,
I ran into an interesting scenario when experimenting with kamailio 3.1 as a stateless proxy (no tm module used):
There is an initial INVITE without to-tag and with pre-loaded Route header pointing to the external address of the lb. When I call loose_route for that, it returns false and the Route header is removed. That's what I expected, and it's documented in http://www.kamailio.org/docs/modules/3.1.x/modules_k/rr.html#loose-route-id.
However if a 407 is relayed back from the registrar via the lb to the UA, it sends an ACK, again with pre-loaded Route header like in the initial INVITE, this time with to-tag. In that case, loose_route() returns true, but the $du is $null and the R-URI is still the same. So the Route is consumed, but the URI is not used. Since it's a stateless proxy, this hop-by-hop ACK needs to be routed the same way as the initial INVITE, so what I'm doing is something like that:
if(loose_route()) { if($du == $null && $ru == $ou) { # skip loose-routing for such a request } }
Is this how it's supposed to work? And is there some documentation of how loose_route() detects whether Route points to itself or not? I'm not using auto_aliases, nor do I set any aliases manually. Does it determine internally whether the Route points to its local ip and port? If not, how come the $du is not set although loose_route returns true?
Andreas
On 29.02.2012 14:34, Andreas Granig wrote:
Hi,
I ran into an interesting scenario when experimenting with kamailio 3.1 as a stateless proxy (no tm module used):
There is an initial INVITE without to-tag and with pre-loaded Route header pointing to the external address of the lb. When I call loose_route for that, it returns false and the Route header is removed. That's what I expected, and it's documented in http://www.kamailio.org/docs/modules/3.1.x/modules_k/rr.html#loose-route-id.
However if a 407 is relayed back from the registrar via the lb to the UA, it sends an ACK, again with pre-loaded Route header like in the initial INVITE, this time with to-tag. In that case, loose_route() returns true, but the $du is $null and the R-URI is still the same.
What else should happen? $du will not be set as there is no more Route header. And R-URI is never changed (except with strict routers).
So the Route is consumed, but the URI is not used. Since it's a stateless proxy, this hop-by-hop ACK needs to be routed the same way as the initial INVITE, so what I'm doing is something like that:
if(loose_route()) { if($du == $null&& $ru == $ou) { # skip loose-routing for such a request } }
Is this how it's supposed to work? And is there some documentation of how loose_route() detects whether Route points to itself or not? I'm not using auto_aliases, nor do I set any aliases manually.
It uses the aliases to detect if the Route points to itself. The listen interfaces are automatically added to the aliases.
I think the problem is that the load balancer can not differentiate this ACK-after-407 from an ACK-after-200. In both cases the Route header points to the load-balancer and a to-tag is present.
Probably you need to add some additional functions which know how your environment looks like and knows to differ the ACKs. I guess $ru == $ou is always true, but for ACK-after-200 there is maybe a second Route header and thus $du is set.
regards Klaus
Does it determine internally whether the Route points to its local ip and port? If not, how come the $du is not set although loose_route returns true?
Andreas
SIP Express Router (SER) and Kamailio (OpenSER) - sr-users mailing list sr-users@lists.sip-router.org http://lists.sip-router.org/cgi-bin/mailman/listinfo/sr-users
Hi Klaus,
On 02/29/2012 03:53 PM, Klaus Darilion wrote:
However if a 407 is relayed back from the registrar via the lb to the UA, it sends an ACK, again with pre-loaded Route header like in the initial INVITE, this time with to-tag. In that case, loose_route() returns true, but the $du is $null and the R-URI is still the same.
What else should happen? $du will not be set as there is no more Route header. And R-URI is never changed (except with strict routers).
Well, I tried to reproduce my problem, now I have two problems :)
Proxy is running on 192.168.51.133:5060, and client (linphone-3) sends a header "Route: sip:foo@192.168.51.133:5060;lr" in the ACK after 407 (and it's the only Route header). For some reason (and I haven't figured it out yet), loose_route() now removes the Route header, puts it into $du and also puts it into $ru, so I end up with an ACK being sent to itself AND with a crippled $ru.
Here's a log right before and after the loose-route call of the scenario described above.
++ before loose-route, $du='<null>' - M=ACK R=sip:testuser3@192.168.51.133 ++ after successful loose-route, $du='sip:192.168.51.133;lr' - M=ACK R=sip:192.168.51.133;lr
To me, it seems like strict-routing is assumed, although there's an "lr" flag. This is by the way not what I've seen in my original problem, that's why I said that I've two problems now...
Andreas
On 02/29/2012 06:01 PM, Andreas Granig wrote:
Proxy is running on 192.168.51.133:5060, and client (linphone-3) sends a header "Route: sip:foo@192.168.51.133:5060;lr" in the ACK after 407
++ before loose-route, $du='<null>' - M=ACK R=sip:testuser3@192.168.51.133 ++ after successful loose-route, $du='sip:192.168.51.133;lr' - M=ACK R=sip:192.168.51.133;lr
$du and $ru are 'sip:foo@192.158.51.133:5060;lr' of course. Sorry, copy/paste error after experimenting with the Route header in linphone (tried to remove the user-part, didn't help).
Anyways, the Route header looks perfectly fine to me.
Andreas
On 29.02.2012 18:01, Andreas Granig wrote:
Hi Klaus,
On 02/29/2012 03:53 PM, Klaus Darilion wrote:
However if a 407 is relayed back from the registrar via the lb to the UA, it sends an ACK, again with pre-loaded Route header like in the initial INVITE, this time with to-tag. In that case, loose_route() returns true, but the $du is $null and the R-URI is still the same.
What else should happen? $du will not be set as there is no more Route header. And R-URI is never changed (except with strict routers).
Well, I tried to reproduce my problem, now I have two problems :)
Proxy is running on 192.168.51.133:5060, and client (linphone-3) sends a header "Route:sip:foo@192.168.51.133:5060;lr" in the ACK after 407 (and it's the only Route header). For some reason (and I haven't figured it out yet), loose_route() now removes the Route header, puts it into $du and also puts it into $ru, so I end up with an ACK being sent to itself AND with a crippled $ru.
That's really weird. It should not rewrite $ru. Maybe there is some special handling for ACK.
Anyway, if the Route header is consumed and pushed into $du it means that the "special behavior" which was done for the INVITE (loose-route==0) is not used here. IIRC these special behavior is only triggered if the request does not contain a to-tag.
If tm is used, it will take care of this by consuming the ACK and generating a new one. It seems that we need some fixes for stateless routing.
regards Klaus
On 02/29/2012 06:23 PM, Klaus Darilion wrote:
That's really weird. It should not rewrite $ru. Maybe there is some special handling for ACK.
Yeah, I'm going to check the source.
Anyway, if the Route header is consumed and pushed into $du it means that the "special behavior" which was done for the INVITE (loose-route==0) is not used here. IIRC these special behavior is only triggered if the request does not contain a to-tag.
Right, and this is explicitely stated in the docs.
If tm is used, it will take care of this by consuming the ACK and generating a new one. It seems that we need some fixes for stateless routing.
I already switched back to transaction stateful routing for now until I get a better idea about what's going on on my test machine.
Andreas
On 02/29/2012 06:35 PM, Andreas Granig wrote:
If tm is used, it will take care of this by consuming the ACK and generating a new one. It seems that we need some fixes for stateless routing.
I already switched back to transaction stateful routing for now until I get a better idea about what's going on on my test machine.
I'm slowly getting the problem :)
When you use the IP address of your kamailio as the domain part (e.g. sip:test@192.168.51.133), then the $ru of the INVITE and of the ACK is exactly that: sip:test@192.168.51.133. What happens in loose_route() is that there is a check called is_preloaded(), which simply checks if there's a To-tag, and if so, returns false back to the config file. However if there IS a To-tag like in the ACK, then is_preloaded() returns false, and it starts checking if $rd:$rp matches one of your sockets, which in this case returns true. Because of this, it assumes that the previous hop was a strict-router, and it sees that the next hop (actually itself) is a loose-router, and because of that it does a rewrite_uri() using the $du to "recover" from that scenario.
So it's actually a bit of a special case (using a pre-loaded route and an IP as $rd and a stateless logic), but a quite nasty and still valid one.
Andreas
Am 29.02.2012 19:12, schrieb Andreas Granig:
On 02/29/2012 06:35 PM, Andreas Granig wrote:
If tm is used, it will take care of this by consuming the ACK and generating a new one. It seems that we need some fixes for stateless routing.
I already switched back to transaction stateful routing for now until I get a better idea about what's going on on my test machine.
I'm slowly getting the problem :)
When you use the IP address of your kamailio as the domain part (e.g. sip:test@192.168.51.133), then the $ru of the INVITE and of the ACK is exactly that: sip:test@192.168.51.133. What happens in loose_route() is that there is a check called is_preloaded(), which simply checks if there's a To-tag, and if so, returns false back to the config file. However if there IS a To-tag like in the ACK, then is_preloaded() returns false, and it starts checking if $rd:$rp matches one of your sockets, which in this case returns true. Because of this, it assumes that the previous hop was a strict-router, and it sees that the next hop (actually itself) is a loose-router, and because of that it does a rewrite_uri() using the $du to "recover" from that scenario.
So it's actually a bit of a special case (using a pre-loaded route and an IP as $rd and a stateless logic), but a quite nasty and still valid one.
Maybe we should add a module parameter to disable strict-router support.
Maybe you can catch the ACK before loose_route check with if (ACK && has_totag() && uri=myself) { # use load-balancer logic ... }
klaus
regards Klaus
On 02/29/2012 09:34 PM, Klaus Darilion wrote:
Maybe you can catch the ACK before loose_route check with if (ACK && has_totag() && uri=myself) { # use load-balancer logic ... }
This, and an rr-param to manually distinguish between hop-by-hop and end-to-end messages in case the Route header holds an fqdn instead of an IP will hopefully do the trick (I'm not using aliases or a domain table on the lb, but I can put some hints into rr-headers and check for them after loose_route()).
Andreas
On 01.03.2012 00:44, Andreas Granig wrote:
On 02/29/2012 09:34 PM, Klaus Darilion wrote:
Maybe you can catch the ACK before loose_route check with if (ACK&& has_totag()&& uri=myself) { # use load-balancer logic ... }
This, and an rr-param to manually distinguish between hop-by-hop and end-to-end messages in case the Route header holds an fqdn instead of an IP will hopefully do the trick (I'm not using aliases or a domain table on the lb, but I can put some hints into rr-headers and check for them after loose_route()).
Indeed, using a RR cookie is a good idea.
klaus