[Asterisk-code-review] res pjsip nat: Rewrite route set when required. (asterisk[13])

Matt Jordan asteriskteam at digium.com
Fri Jun 26 10:59:20 CDT 2015


Matt Jordan has submitted this change and it was merged.

Change subject: res_pjsip_nat: Rewrite route set when required.
......................................................................


res_pjsip_nat: Rewrite route set when required.

When performing some provider testing, the rewrite_contact option was
interfering with proper construction of a route set when sending an ACK
after receiving a 200 OK response to an INVITE.

The initial INVITE was sent to address sip:foo. The 200 OK had a Contact
header with URI sip:bar. In addition, the 200 OK had Record-Route
headers for sip:baz and sip:foo, in that order. Since the Record-Route
headers had the lr parameter, the result should have been:

* Set R-URI of the ACK to sip:bar.
* Add Route headers for sip:foo and sip:baz, in that order.

However, the rewrite_contact option resulted in our rewriting the
Contact header on the 200 OK to sip:foo. The result was:

* R-URI remained sip:foo.
* We added Route headers for sip:foo and sip:baz, in that order.

The result was that sip:bar was not indicated in the ACK at all, so the
far end never received our ACK. The call eventually dropped.

The intention of rewrite_contact is to rewrite the most immediate
destination of our SIP request to be the same address on which we
received a request or response. In the case of processing a SIP response
with Record-Route headers, this means that instead of rewriting the
Contact header, we should instead rewrite the bottom-most Record-Route
header. In the case of processing a SIP request with Record-Route
headers, this means we rewrite the top-most Record-route header.
Like when we rewrite the Contact header, we also ensure to update
the dialog's route set if it exists.

ASTERISK-25196 #close
Reported by Mark Michelson

Change-Id: I9702157c3603a2d0bd8a8215ac27564d366b666f
---
M res/res_pjsip.c
M res/res_pjsip_nat.c
2 files changed, 78 insertions(+), 24 deletions(-)

Approvals:
  Matt Jordan: Looks good to me, approved; Verified
  Joshua Colp: Looks good to me, but someone else must approve



diff --git a/res/res_pjsip.c b/res/res_pjsip.c
index 27e3f81..5389087 100644
--- a/res/res_pjsip.c
+++ b/res/res_pjsip.c
@@ -302,9 +302,9 @@
 				<configOption name="rewrite_contact">
 					<synopsis>Allow Contact header to be rewritten with the source IP address-port</synopsis>
 					<description><para>
-						On inbound SIP messages from this endpoint, the Contact header will be changed to have the
-						source IP address and port. This option does not affect outbound messages send to this
-						endpoint.
+						On inbound SIP messages from this endpoint, the Contact header or an appropriate Record-Route
+						header will be changed to have the source IP address and port. This option does not affect
+						outbound messages sent to this endpoint.
 					</para></description>
 				</configOption>
 				<configOption name="rtp_ipv6" default="no">
diff --git a/res/res_pjsip_nat.c b/res/res_pjsip_nat.c
index 6e093ab..e47dd54 100644
--- a/res/res_pjsip_nat.c
+++ b/res/res_pjsip_nat.c
@@ -32,34 +32,88 @@
 #include "asterisk/module.h"
 #include "asterisk/acl.h"
 
-static pj_bool_t handle_rx_message(struct ast_sip_endpoint *endpoint, pjsip_rx_data *rdata)
+static void rewrite_uri(pjsip_rx_data *rdata, pjsip_sip_uri *uri)
+{
+	pj_cstr(&uri->host, rdata->pkt_info.src_name);
+	if (strcasecmp("udp", rdata->tp_info.transport->type_name)) {
+		uri->transport_param = pj_str(rdata->tp_info.transport->type_name);
+	} else {
+		uri->transport_param.slen = 0;
+	}
+	uri->port = rdata->pkt_info.src_port;
+}
+
+static int rewrite_route_set(pjsip_rx_data *rdata, pjsip_dialog *dlg)
+{
+	pjsip_rr_hdr *rr = NULL;
+	pjsip_sip_uri *uri;
+
+	if (rdata->msg_info.msg->type == PJSIP_RESPONSE_MSG) {
+		pjsip_hdr *iter;
+		for (iter = rdata->msg_info.msg->hdr.prev; iter != &rdata->msg_info.msg->hdr; iter = iter->prev) {
+			if (iter->type == PJSIP_H_RECORD_ROUTE) {
+				rr = (pjsip_rr_hdr *)iter;
+				break;
+			}
+		}
+	} else {
+		rr = pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_RECORD_ROUTE, NULL);
+	}
+
+	if (rr) {
+		uri = pjsip_uri_get_uri(&rr->name_addr);
+		rewrite_uri(rdata, uri);
+		if (dlg && dlg->route_set.next && !dlg->route_set_frozen) {
+			pjsip_routing_hdr *route = dlg->route_set.next;
+			uri = pjsip_uri_get_uri(&route->name_addr);
+			rewrite_uri(rdata, uri);
+		}
+
+		return 0;
+	}
+
+	return -1;
+}
+
+static int rewrite_contact(pjsip_rx_data *rdata, pjsip_dialog *dlg)
 {
 	pjsip_contact_hdr *contact;
+
+	contact = pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_CONTACT, NULL);
+	if (contact && !contact->star && (PJSIP_URI_SCHEME_IS_SIP(contact->uri) || PJSIP_URI_SCHEME_IS_SIPS(contact->uri))) {
+		pjsip_sip_uri *uri = pjsip_uri_get_uri(contact->uri);
+
+		rewrite_uri(rdata, uri);
+
+		if (dlg && !dlg->route_set_frozen && (!dlg->remote.contact
+			|| pjsip_uri_cmp(PJSIP_URI_IN_REQ_URI, dlg->remote.contact->uri, contact->uri))) {
+			dlg->remote.contact = (pjsip_contact_hdr*)pjsip_hdr_clone(dlg->pool, contact);
+			dlg->target = dlg->remote.contact->uri;
+		}
+		return 0;
+	}
+
+	return -1;
+}
+
+static pj_bool_t handle_rx_message(struct ast_sip_endpoint *endpoint, pjsip_rx_data *rdata)
+{
+	pjsip_dialog *dlg = pjsip_rdata_get_dlg(rdata);
 
 	if (!endpoint) {
 		return PJ_FALSE;
 	}
 
-	if (endpoint->nat.rewrite_contact && (contact = pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_CONTACT, NULL)) &&
-		!contact->star && (PJSIP_URI_SCHEME_IS_SIP(contact->uri) || PJSIP_URI_SCHEME_IS_SIPS(contact->uri))) {
-		pjsip_sip_uri *uri = pjsip_uri_get_uri(contact->uri);
-		pjsip_dialog *dlg = pjsip_rdata_get_dlg(rdata);
-
-		pj_cstr(&uri->host, rdata->pkt_info.src_name);
-		if (strcasecmp("udp", rdata->tp_info.transport->type_name)) {
-			uri->transport_param = pj_str(rdata->tp_info.transport->type_name);
-		} else {
-			uri->transport_param.slen = 0;
-		}
-		uri->port = rdata->pkt_info.src_port;
-		ast_debug(4, "Re-wrote Contact URI host/port to %.*s:%d\n",
-			(int)pj_strlen(&uri->host), pj_strbuf(&uri->host), uri->port);
-
-		/* rewrite the session target since it may have already been pulled from the contact header */
-		if (dlg && (!dlg->remote.contact
-			|| pjsip_uri_cmp(PJSIP_URI_IN_REQ_URI, dlg->remote.contact->uri, contact->uri))) {
-			dlg->remote.contact = (pjsip_contact_hdr*)pjsip_hdr_clone(dlg->pool, contact);
-			dlg->target = dlg->remote.contact->uri;
+	if (endpoint->nat.rewrite_contact) {
+		/* rewrite_contact is intended to ensure we send requests/responses to
+		 * a routeable address when NAT is involved. The URI that dictates where
+		 * we send requests/responses can be determined either by Record-Route
+		 * headers or by the Contact header if no Record-Route headers are present.
+		 * We therefore will attempt to rewrite a Record-Route header first, and if
+		 * none are present, we fall back to rewriting the Contact header instead.
+		 */
+		if (rewrite_route_set(rdata, dlg)) {
+			rewrite_contact(rdata, dlg);
 		}
 	}
 

-- 
To view, visit https://gerrit.asterisk.org/723
To unsubscribe, visit https://gerrit.asterisk.org/settings

Gerrit-MessageType: merged
Gerrit-Change-Id: I9702157c3603a2d0bd8a8215ac27564d366b666f
Gerrit-PatchSet: 2
Gerrit-Project: asterisk
Gerrit-Branch: 13
Gerrit-Owner: Mark Michelson <mmichelson at digium.com>
Gerrit-Reviewer: Joshua Colp <jcolp at digium.com>
Gerrit-Reviewer: Matt Jordan <mjordan at digium.com>



More information about the asterisk-code-review mailing list