Hi Andrew
well, the RURI of remote ACK has proxy IP address 10.200.70.100 so proxy thinks that previous hop was a strict router.
Aha, that makes sense. But why would that make Kamailio apply strict routing?
Now I understand this! Kamailio is not copying the *next* Route URI into the R-URI because it is strict routing itself, but copying the *last* Route URI into the R-URI because it thinks the previous hop is a strict router. The fact that the next Route URI is the last one is what confused me. Thanks for helping me get to the bottom of it!
Interestingly the previous hop is not really a strict router, it's just badly behaved in that it takes the user part of the R-URI from the Contact header and the domain part from the next hop. I won't name the vendor but I am very surprised by this. I can only assume it's some type of NAT traversal that is tuned on.
W.r.t. the Kamailio's strict routing behaviour, I wanted to point something out. Here's the relevant bit from the RFC:
The proxy MUST inspect the Request-URI of the request. If the Request-URI of the request contains a value this proxy previously placed into a Record-Route header field (see Section 16.6 item 4), the proxy MUST replace the Request-URI in the request with the last value from the Route header field, and remove that value from the Route header field.
So what is meant here by "a value"? In my case this R-URI has the same IP as the proxy but contains a user part and parameters which were not inserted by the proxy into a Record-Route header so I don't think this test should pass, but because is_myself() is being used in loose_route() it does.
I can't think of any workaround that would not be an ugly hack at the moment, though.
I thought encode_contact() and decode() contact were designed exactly for this? Except I can't get them to work so I believe you!
The main issue with these is that loose_route() and decode_contact() do not play nicely together. Ideally you would want to call decode_contact() and then loose_route() which could look $ru / new_uri, but it will only ever inspect $ou /parsed_uri. So you can't put decode_contact() before loose_route().
Then on the other hand decode_contact() will only read from $ou if $ru is not set, and because loos_route() sets $ru in after_strict(), you also can't put decode_contact() after loose_route().
Unless you reset some of what loose_route() set, which is what I did get this working:
if (loose_route()) { if($ou =~ "^sip:natted_contact") { $ru = $ou; decode_contact(); $du = $ru; $fs = $null; } ... }
What would be really useful would be if loose_route() used new_uri where available or, to preserve backward compatibility, you could call loose_route($ru).
Richard