Hi, Im'm cross-posting this from OpenSER-Devel because I am not 100% sure this is a bug.
I am trying to create openser configuration for proxy that connects private (VPN) network with public network. I started with a config similar to http://voipembedded.com/resources/openser_cr.cfg, added a call to force_send_socket() to send from public IP and rtpproxy/nathelper in bridge mode. As per config loose_route() is called from openser.cfg to route a sequential request within a dialog through record-routing. Now when a BYE from callee comes in, it contains two Route headers: Route: <a.b.c.d;r2=on;lr;ftag=...> where a.b.c.d is server's public IP, Route: <10.0.0.100;r2=on;lr;ftag=...> where 10.0.0.100 is a private IP and username@a.b.c.d in Request-URI.
Take a look at loose_route():
/* * Do loose routing as defined in RFC3261 */ int loose_route(struct sip_msg* _m, char* _s1, char* _s2) { int ret;
if (find_first_route(_m) != 0) { LM_DBG("There is no Route HF\n"); return -1; }
if (parse_sip_msg_uri(_m)<0) { LM_ERR("failed to parse Request URI\n"); return -1; }
ret = is_preloaded(_m); if (ret < 0) { return -1; } else if (ret == 1) { return after_loose(_m, 1); } else { #ifdef ENABLE_USER_CHECK if (is_myself(&_m->parsed_uri.user, &_m->parsed_uri.host, _m->parsed_uri.port_no)) { #else if (is_myself(&_m->parsed_uri.host, _m->parsed_uri.port_no)) { #endif return after_strict(_m); } else { return after_loose(_m, 0); } } }
Obviously, is_myself() check passes and after_strict() is called.
when after_strict() is called, it looks if the URI given in Route contains lr parameter which marks loose routers, if so this block of code is executed: { LM_DBG("Next hop: '%.*s' is loose router\n", uri.len, ZSW(uri.s));
if(get_maddr_uri(&uri, &puri)!=0) { LM_ERR("failed to check maddr\n"); return RR_ERROR; } if (set_dst_uri(_m, &uri) < 0) { LM_ERR("failed to set dst_uri\n"); return RR_ERROR; }
/* Next hop is a loose router - Which means that is is not endpoint yet * In This case we have to recover from previous strict routing, that * means we have to find the last Route URI and put in in R-URI and * remove the last Route URI. */ if (rt != hdr->parsed) { /* There is a previous route uri which was 2nd uri of mine * and must be removed here */ rem_off = hdr->body.s; rem_len = rt->nameaddr.name.s - hdr->body.s; if (!del_lump(_m, rem_off - _m->buf, rem_len, 0)) { LM_ERR("failed to remove Route HF\n"); return RR_ERROR; } }
res = find_rem_target(_m, &hdr, &rt, &prev); if (res < 0) { LM_ERR("searching for last Route URI failed\n"); return RR_ERROR; } else if (res > 0) { /* No remote target is an error */ return RR_ERROR; }
uri = rt->nameaddr.uri; if(get_maddr_uri(&uri, 0)!=0) { LM_ERR("checking maddr failed\n"); return RR_ERROR; } if (rewrite_uri(_m, &uri) < 0) { LM_ERR("failed to rewrite R-URI\n"); return RR_ERROR; }
/* The first character if uri will be either '<' when it is the * only URI in a Route header field or ',' if there is more than * one URI in the header field */ LM_DBG("The last route URI: '%.*s'\n", rt->nameaddr.uri.len, ZSW(rt->nameaddr.uri.s));
if (prev) { rem_off = prev->nameaddr.name.s + prev->len; rem_len = rt->nameaddr.name.s + rt->len - rem_off; } else { rem_off = hdr->name.s; rem_len = hdr->len; } if (!del_lump(_m, rem_off - _m->buf, rem_len, 0)) { LM_ERR("failed to remove Route HF\n"); return RR_ERROR; } }
Therefore recover from previous strict routing is triggered: contents of request line is destroyed and 10.0.0.100 is put instead: Apr 15 16:16:24 vpn-proxy oser[11027]: DBG:core:rewrite_uri: rewriting Request-URI with 'sip:10.0.0.100;r2=on;lr;ftag=aa40c2a5-54fb-1810-970d-0015c5bf2da5' Apr 15 16:16:24 vpn-proxy oser[11032]: [1] Got in dialog request not catched by loose_route(): BYE sip:10.0.0.100;r2=on;lr;ftag=aa40c2a5-54fb-1810-970d-0015c5bf2da5 SIP/2.0^M Via:...
And we respond with 404 to in-dialog requests not caught by loose_route(). Previous hop is SER and I don't know why OpenSER considered it a strict router. Looks like a peculiarity of ALG mode. Please advice what should I do to solve this problem. Is it a configuration issue or perhaps loose_route() should not call after_strict() in case of double record-routing?
-- Thank you, Andrew Pogrebennyk
Hi Andrew,
Just a short question - how comes that your BYE has proxy ips in RURI and Route ? where the end-device IP ??
Regards, Bogdan
Andrew Pogrebennyk wrote:
Hi, Im'm cross-posting this from OpenSER-Devel because I am not 100% sure this is a bug.
I am trying to create openser configuration for proxy that connects private (VPN) network with public network. I started with a config similar to http://voipembedded.com/resources/openser_cr.cfg, added a call to force_send_socket() to send from public IP and rtpproxy/nathelper in bridge mode. As per config loose_route() is called from openser.cfg to route a sequential request within a dialog through record-routing. Now when a BYE from callee comes in, it contains two Route headers: Route: <a.b.c.d;r2=on;lr;ftag=...> where a.b.c.d is server's public IP, Route: <10.0.0.100;r2=on;lr;ftag=...> where 10.0.0.100 is a private IP and username@a.b.c.d in Request-URI.
Take a look at loose_route():
/*
- Do loose routing as defined in RFC3261
*/ int loose_route(struct sip_msg* _m, char* _s1, char* _s2) { int ret;
if (find_first_route(_m) != 0) { LM_DBG("There is no Route HF\n"); return -1; } if (parse_sip_msg_uri(_m)<0) { LM_ERR("failed to parse Request URI\n"); return -1; } ret = is_preloaded(_m); if (ret < 0) { return -1; } else if (ret == 1) { return after_loose(_m, 1); } else {
#ifdef ENABLE_USER_CHECK if (is_myself(&_m->parsed_uri.user, &_m->parsed_uri.host, _m->parsed_uri.port_no)) { #else if (is_myself(&_m->parsed_uri.host, _m->parsed_uri.port_no)) { #endif return after_strict(_m); } else { return after_loose(_m, 0); } } }
Obviously, is_myself() check passes and after_strict() is called.
when after_strict() is called, it looks if the URI given in Route contains lr parameter which marks loose routers, if so this block of code is executed: { LM_DBG("Next hop: '%.*s' is loose router\n", uri.len, ZSW(uri.s));
if(get_maddr_uri(&uri, &puri)!=0) { LM_ERR("failed to check maddr\n"); return RR_ERROR; } if (set_dst_uri(_m, &uri) < 0) { LM_ERR("failed to set dst_uri\n"); return RR_ERROR; } /* Next hop is a loose router - Which means that is is not
endpoint yet * In This case we have to recover from previous strict routing, that * means we have to find the last Route URI and put in in R-URI and * remove the last Route URI. */ if (rt != hdr->parsed) { /* There is a previous route uri which was 2nd uri of mine * and must be removed here */ rem_off = hdr->body.s; rem_len = rt->nameaddr.name.s - hdr->body.s; if (!del_lump(_m, rem_off - _m->buf, rem_len, 0)) { LM_ERR("failed to remove Route HF\n"); return RR_ERROR; } }
res = find_rem_target(_m, &hdr, &rt, &prev); if (res < 0) { LM_ERR("searching for last Route URI failed\n"); return RR_ERROR; } else if (res > 0) { /* No remote target is an error */ return RR_ERROR; } uri = rt->nameaddr.uri; if(get_maddr_uri(&uri, 0)!=0) { LM_ERR("checking maddr failed\n"); return RR_ERROR; } if (rewrite_uri(_m, &uri) < 0) { LM_ERR("failed to rewrite R-URI\n"); return RR_ERROR; } /* The first character if uri will be either '<' when it is the * only URI in a Route header field or ',' if there is more than * one URI in the header field */ LM_DBG("The last route URI: '%.*s'\n", rt->nameaddr.uri.len, ZSW(rt->nameaddr.uri.s)); if (prev) { rem_off = prev->nameaddr.name.s + prev->len; rem_len = rt->nameaddr.name.s + rt->len - rem_off; } else { rem_off = hdr->name.s; rem_len = hdr->len; } if (!del_lump(_m, rem_off - _m->buf, rem_len, 0)) { LM_ERR("failed to remove Route HF\n"); return RR_ERROR; } }
Therefore recover from previous strict routing is triggered: contents of request line is destroyed and 10.0.0.100 is put instead: Apr 15 16:16:24 vpn-proxy oser[11027]: DBG:core:rewrite_uri: rewriting Request-URI with 'sip:10.0.0.100;r2=on;lr;ftag=aa40c2a5-54fb-1810-970d-0015c5bf2da5' Apr 15 16:16:24 vpn-proxy oser[11032]: [1] Got in dialog request not catched by loose_route(): BYE sip:10.0.0.100;r2=on;lr;ftag=aa40c2a5-54fb-1810-970d-0015c5bf2da5 SIP/2.0^M Via:...
And we respond with 404 to in-dialog requests not caught by loose_route(). Previous hop is SER and I don't know why OpenSER considered it a strict router. Looks like a peculiarity of ALG mode. Please advice what should I do to solve this problem. Is it a configuration issue or perhaps loose_route() should not call after_strict() in case of double record-routing?
-- Thank you, Andrew Pogrebennyk
Users mailing list Users@lists.openser.org http://lists.openser.org/cgi-bin/mailman/listinfo/users
Hi Bogdan, I'm a bit surprised by your question. OpenSER works in ALG mode - connects two disconnected networks. So it inserts 2 Record-Routes (enable_double_rr parameter of rr module is enabled by default). On the public side OpenSER talks to b2bua. b2bua memorizes Record-Routes and when it receives BYE that it must send further to OpenSER, it inserts Route headers with both IPs of OpenSER - those it originally got in Record-Routes.
To explain it further, end device 10.0.1.2 is connected to OpenSER ALG via VPN. OpenSER listens on the private IP 10.0.0.100 that is directly reachable for the client, and public IP a.b.c.d. Device is configured with IP address of proxy/b2bua as "domain" (let's call it w.x.y.z) and private IP address of OpenSER ALG 10.0.0.100 - as an outgoing proxy.
So when it calls it sends for example such INVITE to OpenSER 10.0.0.100:
INVITE sip:cld@w.x.y.z SIP/2.0 Via: SIP/2.0/UDP 10.0.1.2:8304;branch=z9hG4bK-d87543-e31904647634642f-1--d87543-;rport Max-Forwards: 70 Contact: sip:user@10.0.1.2:8304 To: sip:cld@w.x.y.z From: sip:user@w.x.y.z;tag=a1255825 ...
OpenSER proxies this INVITE from private to public interface and then to proxy/b2bua that it talks to. The latter receives it with such headers (I believe vias, from and to can be omitted):
INVITE sip:cld@w.x.y.z SIP/2.0 Record-Route: sip:a.b.c.d;r2=on;lr;ftag=6751d9e2-80fb-1810-8010-0015c5bf2da5 Record-Route: sip:10.0.0.100;r2=on;lr;ftag=6751d9e2-80fb-1810-8010-0015c5bf2da5 Contact: sip:user@a.b.c.d
The call eventually gets connected. Some time later the callee gets bored and sends BYE. Its contents are not relevant here - remember that it talks to b2bua. b2bua puts Route headers and finally sends the following request to OpenSER:
BYE sip:user@a.b.c.d SIP/2.0 Via: SIP/2.0/UDP w.x.y.z;branch=z9hG4bK4f44.b91363e99e6c107e32eda5c5526933be.0 Via: SIP/2.0/UDP w.x.y.z:5061;branch=z9hG4bK5bcae8426bb383dcf815d7db04dbaacf;rport=5061 Route: sip:a.b.c.d;r2=on;lr;ftag=6751d9e2-80fb-1810-8010-0015c5bf2da5 Route: sip:10.0.0.100;r2=on;lr;ftag=6751d9e2-80fb-1810-8010-0015c5bf2da5
And this particular BYE confuses OpenSER. Hope I've been clear enough. Now who's at fault? I can send OpenSER config and detailed log files to your private email if you deem it necessary.
Thanks,
Bogdan-Andrei Iancu wrote:
Hi Andrew,
Just a short question - how comes that your BYE has proxy ips in RURI and Route ? where the end-device IP ??
Regards, Bogdan
Andrew Pogrebennyk wrote:
Hi, Im'm cross-posting this from OpenSER-Devel because I am not 100% sure this is a bug.
I am trying to create openser configuration for proxy that connects private (VPN) network with public network. I started with a config similar to http://voipembedded.com/resources/openser_cr.cfg, added a call to force_send_socket() to send from public IP and rtpproxy/nathelper in bridge mode. As per config loose_route() is called from openser.cfg to route a sequential request within a dialog through record-routing. Now when a BYE from callee comes in, it contains two Route headers: Route: <a.b.c.d;r2=on;lr;ftag=...> where a.b.c.d is server's public IP, Route: <10.0.0.100;r2=on;lr;ftag=...> where 10.0.0.100 is a private IP and username@a.b.c.d in Request-URI.
Hi Andrew,
My question was about the BYE request - all the routing information (Route+RURI) are pointing to your server - I find this a bit strange as there is no information about the end device (where openser should send further the request).
If I understand correctly your scenario, it seams you change the contact IP from INVITE into the openser IP - this is not good as it will make impossible to make difference between loose route and strict route.
So your problem is that you put in INVITE's contact the server IP.
Regards, Bogdan
Andrew Pogrebennyk wrote:
Hi Bogdan, I'm a bit surprised by your question. OpenSER works in ALG mode - connects two disconnected networks. So it inserts 2 Record-Routes (enable_double_rr parameter of rr module is enabled by default). On the public side OpenSER talks to b2bua. b2bua memorizes Record-Routes and when it receives BYE that it must send further to OpenSER, it inserts Route headers with both IPs of OpenSER - those it originally got in Record-Routes.
To explain it further, end device 10.0.1.2 is connected to OpenSER ALG via VPN. OpenSER listens on the private IP 10.0.0.100 that is directly reachable for the client, and public IP a.b.c.d. Device is configured with IP address of proxy/b2bua as "domain" (let's call it w.x.y.z) and private IP address of OpenSER ALG 10.0.0.100 - as an outgoing proxy.
So when it calls it sends for example such INVITE to OpenSER 10.0.0.100:
INVITE sip:cld@w.x.y.z SIP/2.0 Via: SIP/2.0/UDP 10.0.1.2:8304;branch=z9hG4bK-d87543-e31904647634642f-1--d87543-;rport Max-Forwards: 70 Contact: sip:user@10.0.1.2:8304 To: sip:cld@w.x.y.z From: sip:user@w.x.y.z;tag=a1255825 ...
OpenSER proxies this INVITE from private to public interface and then to proxy/b2bua that it talks to. The latter receives it with such headers (I believe vias, from and to can be omitted):
INVITE sip:cld@w.x.y.z SIP/2.0 Record-Route: sip:a.b.c.d;r2=on;lr;ftag=6751d9e2-80fb-1810-8010-0015c5bf2da5 Record-Route: sip:10.0.0.100;r2=on;lr;ftag=6751d9e2-80fb-1810-8010-0015c5bf2da5 Contact: sip:user@a.b.c.d
The call eventually gets connected. Some time later the callee gets bored and sends BYE. Its contents are not relevant here - remember that it talks to b2bua. b2bua puts Route headers and finally sends the following request to OpenSER:
BYE sip:user@a.b.c.d SIP/2.0 Via: SIP/2.0/UDP w.x.y.z;branch=z9hG4bK4f44.b91363e99e6c107e32eda5c5526933be.0 Via: SIP/2.0/UDP w.x.y.z:5061;branch=z9hG4bK5bcae8426bb383dcf815d7db04dbaacf;rport=5061 Route: sip:a.b.c.d;r2=on;lr;ftag=6751d9e2-80fb-1810-8010-0015c5bf2da5 Route: sip:10.0.0.100;r2=on;lr;ftag=6751d9e2-80fb-1810-8010-0015c5bf2da5
And this particular BYE confuses OpenSER. Hope I've been clear enough. Now who's at fault? I can send OpenSER config and detailed log files to your private email if you deem it necessary.
Thanks,
Bogdan-Andrei Iancu wrote:
Hi Andrew,
Just a short question - how comes that your BYE has proxy ips in RURI and Route ? where the end-device IP ??
Regards, Bogdan
Andrew Pogrebennyk wrote:
Hi, Im'm cross-posting this from OpenSER-Devel because I am not 100% sure this is a bug.
I am trying to create openser configuration for proxy that connects private (VPN) network with public network. I started with a config similar to http://voipembedded.com/resources/openser_cr.cfg, added a call to force_send_socket() to send from public IP and rtpproxy/nathelper in bridge mode. As per config loose_route() is called from openser.cfg to route a sequential request within a dialog through record-routing. Now when a BYE from callee comes in, it contains two Route headers: Route: <a.b.c.d;r2=on;lr;ftag=...> where a.b.c.d is server's public IP, Route: <10.0.0.100;r2=on;lr;ftag=...> where 10.0.0.100 is a private IP and username@a.b.c.d in Request-URI.
Bogdan,
Thanks for clarifying, that's good to know the root cause. But I rewrite the contact IP from INVITE for a reason. As stated earlier, on the public internet side OpenSER talks to b2bua. So from INVITE b2bua learns remote target URI of the client. And when it's time to send BYE to the it, b2bua follows RFC 3261 rules regarding Request-URI:
The UAC uses the remote target and route set to build the Request-URI and Route header field of the request.
If the route set is empty, the UAC MUST place the remote target URI into the Request-URI. The UAC MUST NOT add a Route header field to the request.
If the route set is not empty, and the first URI in the route set contains the lr parameter (see Section 19.1.1), the UAC MUST place the remote target URI into the Request-URI and MUST include a Route header field containing the route set values in order, including all parameters.
Since all URIs in route set from OpenSER do contain lr parameter b2bua behaves as described in the last paragraph of the extract above. Therefore as long as b2bua can not reach the internal network (it is many hops away) and uses the remote target URI to send request to and client puts private IP into Contact header (which is the right thing for him to do) I do have to rewrite Contact header - otherwise request will never reach the destination. Any recommendations?
Bogdan-Andrei Iancu wrote:
Hi Andrew,
My question was about the BYE request - all the routing information (Route+RURI) are pointing to your server - I find this a bit strange as there is no information about the end device (where openser should send further the request).
If I understand correctly your scenario, it seams you change the contact IP from INVITE into the openser IP - this is not good as it will make impossible to make difference between loose route and strict route.
So your problem is that you put in INVITE's contact the server IP.
Regards, Bogdan
You shouldn't re-write the Contact header. Leave it as is (with the private IP address). If your B2BUA is rfc complaint, it will send the in-dilaog request to the public IP of OpenSER with the target being the private IP and then OpenSER will properly route the request. The B2BUA doesn't need to be able to route to the remote target, it needs to be able to route to the top SIP hop in the record-route header list.
Regards, Ovidiu Sas
On Thu, May 8, 2008 at 4:16 PM, Andrew Pogrebennyk andrew.pogrebennyk@portaone.com wrote:
Bogdan,
Thanks for clarifying, that's good to know the root cause. But I rewrite the contact IP from INVITE for a reason. As stated earlier, on the public internet side OpenSER talks to b2bua. So from INVITE b2bua learns remote target URI of the client. And when it's time to send BYE to the it, b2bua follows RFC 3261 rules regarding Request-URI:
The UAC uses the remote target and route set to build the Request-URI and Route header field of the request. If the route set is empty, the UAC MUST place the remote target URI into the Request-URI. The UAC MUST NOT add a Route header field to the request. If the route set is not empty, and the first URI in the route set contains the lr parameter (see Section 19.1.1), the UAC MUST place the remote target URI into the Request-URI and MUST include a Route header field containing the route set values in order, including all parameters.
Since all URIs in route set from OpenSER do contain lr parameter b2bua behaves as described in the last paragraph of the extract above. Therefore as long as b2bua can not reach the internal network (it is many hops away) and uses the remote target URI to send request to and client puts private IP into Contact header (which is the right thing for him to do) I do have to rewrite Contact header - otherwise request will never reach the destination. Any recommendations?
Bogdan-Andrei Iancu wrote:
Hi Andrew,
My question was about the BYE request - all the routing information (Route+RURI) are pointing to your server - I find this a bit strange as there is no information about the end device (where openser should send further the request).
If I understand correctly your scenario, it seams you change the contact IP from INVITE into the openser IP - this is not good as it will make impossible to make difference between loose route and strict route.
So your problem is that you put in INVITE's contact the server IP.
Regards, Bogdan
-- Sincerely, Andrew Pogrebennyk
Users mailing list Users@lists.openser.org http://lists.openser.org/cgi-bin/mailman/listinfo/users
Andrew,
logically speaking, your openser cannot be proxy (in Route hdr) and end point (in Contact) in the same time.
Regarding the Contact rewriting - I would say it is not necessary. According the RFC, the UAS (b2bua) will receive as route set the RR of openser and as remote target URI the private contact of the UAC. When building the BYE, it will put the UAC's contact (private) in RURI and all received RR in Route headers. The whole idea is that the Route hdrs will be used by b2bua to send out the request and not RURI - so this can be private as it will not be used for routing ;)...Only openser will start routing based on RURI as all the ROute headers will be consumed.
Regards, Bogdan
Andrew Pogrebennyk wrote:
Bogdan,
Thanks for clarifying, that's good to know the root cause. But I rewrite the contact IP from INVITE for a reason. As stated earlier, on the public internet side OpenSER talks to b2bua. So from INVITE b2bua learns remote target URI of the client. And when it's time to send BYE to the it, b2bua follows RFC 3261 rules regarding Request-URI:
The UAC uses the remote target and route set to build the Request-URI and Route header field of the request.
If the route set is empty, the UAC MUST place the remote target URI into the Request-URI. The UAC MUST NOT add a Route header field to the request.
If the route set is not empty, and the first URI in the route set contains the lr parameter (see Section 19.1.1), the UAC MUST place the remote target URI into the Request-URI and MUST include a Route header field containing the route set values in order, including all parameters.
Since all URIs in route set from OpenSER do contain lr parameter b2bua behaves as described in the last paragraph of the extract above. Therefore as long as b2bua can not reach the internal network (it is many hops away) and uses the remote target URI to send request to and client puts private IP into Contact header (which is the right thing for him to do) I do have to rewrite Contact header - otherwise request will never reach the destination. Any recommendations?
Bogdan-Andrei Iancu wrote:
Hi Andrew,
My question was about the BYE request - all the routing information (Route+RURI) are pointing to your server - I find this a bit strange as there is no information about the end device (where openser should send further the request).
If I understand correctly your scenario, it seams you change the contact IP from INVITE into the openser IP - this is not good as it will make impossible to make difference between loose route and strict route.
So your problem is that you put in INVITE's contact the server IP.
Regards, Bogdan
Bogdan, Ovidiu Sas Many thanks! It's perfectly clear now.
Bogdan-Andrei Iancu wrote:
Andrew,
logically speaking, your openser cannot be proxy (in Route hdr) and end point (in Contact) in the same time.
Regarding the Contact rewriting - I would say it is not necessary. According the RFC, the UAS (b2bua) will receive as route set the RR of openser and as remote target URI the private contact of the UAC. When building the BYE, it will put the UAC's contact (private) in RURI and all received RR in Route headers. The whole idea is that the Route hdrs will be used by b2bua to send out the request and not RURI - so this can be private as it will not be used for routing ;)...Only openser will start routing based on RURI as all the ROute headers will be consumed.
Regards, Bogdan