<p>George Joseph <strong>submitted</strong> this change.</p><p><a href="https://gerrit.asterisk.org/c/asterisk/+/12825">View Change</a></p><div style="white-space:pre-wrap">Approvals:
  Joshua C. Colp: Looks good to me, but someone else must approve
  George Joseph: Looks good to me, approved; Approved for Submit

</div><pre style="font-family: monospace,monospace; white-space: pre-wrap;">res_pjsip_nat: Restore original contact for REGISTER responses<br><br>RFC3261 Section 10 "Registrations", specifically paragraph<br>"10.2.4: Refreshing Bindings", states that a user agent compares<br>each contact address (in a 200 REGISTER response) to see if it<br>created the contact.  If the Asterisk endpoint has the<br>rewrite_contact option set however, the contact host and port sent<br>back in the 200 response will be the rewritten one and not the<br>one sent by the user agent.  This prevents the user agent from<br>matching its own contact.  Some user agents get very upset when<br>this happens and will not consider the registration successful.<br>While this is rare, it is acceptable behavior especially if more<br>than 1 user agent is allowed to register to a single endpoint/aor.<br><br>This commit updates res_pjsip_nat (where rewrite_contact is<br>implemented) to store the original incoming Contact header in<br>a new "x-ast-orig-host" URI parameter before rewriting it, and to<br>restore the original host and port to the Contact headers in the<br>outgoing response.<br><br>This is only done if the request is a REGISTER and rewrite_contact<br>is enabled.<br><br>pjsip_message_filter was also updated to ensure that if a request<br>comes in with any existing x-ast-* URI parameters, we remove them<br>so they don't conflict.  Asterisk will never send a request<br>with those headers in it but someone might just decide to add them<br>to a request they craft and send to Asterisk.<br><br>NOTE: If a device changes its contact address and registers again,<br>it's a NEW registration.  If the device didn't unregister the<br>original registration then all existing behavior based<br>on aor/remove_existing and aor/max_contacts apply.<br><br>ASTERISK-28502<br>Reported-by: Ross Beer<br><br>Change-Id: Idc263ad2d2d7bd8faa047e5804d96a5fe1cd282e<br>---<br>M res/res_pjsip/pjsip_message_filter.c<br>M res/res_pjsip_nat.c<br>2 files changed, 122 insertions(+), 2 deletions(-)<br><br></pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;"><span>diff --git a/res/res_pjsip/pjsip_message_filter.c b/res/res_pjsip/pjsip_message_filter.c</span><br><span>index b70985b..1826ee2 100644</span><br><span>--- a/res/res_pjsip/pjsip_message_filter.c</span><br><span>+++ b/res/res_pjsip/pjsip_message_filter.c</span><br><span>@@ -400,6 +400,40 @@</span><br><span> #endif</span><br><span> }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+/*!</span><br><span style="color: hsl(120, 100%, 40%);">+ * /internal</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * We want to make sure that any incoming requests don't already</span><br><span style="color: hsl(120, 100%, 40%);">+ * have x-ast-* parameters in any URIs or we may get confused</span><br><span style="color: hsl(120, 100%, 40%);">+ * if symmetric transport (x-ast-txp) or rewrite_contact (x-ast-orig-host)</span><br><span style="color: hsl(120, 100%, 40%);">+ * is used later on.</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+static void remove_x_ast_params(pjsip_uri *header_uri){</span><br><span style="color: hsl(120, 100%, 40%);">+ pjsip_sip_uri *uri;</span><br><span style="color: hsl(120, 100%, 40%);">+   pjsip_param *param;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!header_uri) {</span><br><span style="color: hsl(120, 100%, 40%);">+            return;</span><br><span style="color: hsl(120, 100%, 40%);">+       }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   uri = pjsip_uri_get_uri(header_uri);</span><br><span style="color: hsl(120, 100%, 40%);">+  if (!uri) {</span><br><span style="color: hsl(120, 100%, 40%);">+           return;</span><br><span style="color: hsl(120, 100%, 40%);">+       }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   param = uri->other_param.next;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   while (param != &uri->other_param) {</span><br><span style="color: hsl(120, 100%, 40%);">+           /* We need to save off 'next' because pj_list_erase will remove it */</span><br><span style="color: hsl(120, 100%, 40%);">+         pjsip_param *next = param->next;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+         if (pj_strncmp2(&param->name, "x-ast-", 6) == 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+                   pj_list_erase(param);</span><br><span style="color: hsl(120, 100%, 40%);">+         }</span><br><span style="color: hsl(120, 100%, 40%);">+             param = next;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> static pj_bool_t on_rx_process_uris(pjsip_rx_data *rdata)</span><br><span> {</span><br><span>     pjsip_contact_hdr *contact = NULL;</span><br><span>@@ -414,6 +448,7 @@</span><br><span>                     PJSIP_SC_UNSUPPORTED_URI_SCHEME, NULL, NULL, NULL);</span><br><span>          return PJ_TRUE;</span><br><span>      }</span><br><span style="color: hsl(120, 100%, 40%);">+     remove_x_ast_params(rdata->msg_info.msg->line.req.uri);</span><br><span> </span><br><span>    if (!is_sip_uri(rdata->msg_info.from->uri)) {</span><br><span>          print_uri_debug(URI_TYPE_FROM, rdata, (pjsip_hdr *)rdata->msg_info.from);</span><br><span>@@ -421,6 +456,7 @@</span><br><span>                   PJSIP_SC_UNSUPPORTED_URI_SCHEME, NULL, NULL, NULL);</span><br><span>          return PJ_TRUE;</span><br><span>      }</span><br><span style="color: hsl(120, 100%, 40%);">+     remove_x_ast_params(rdata->msg_info.from->uri);</span><br><span> </span><br><span>    if (!is_sip_uri(rdata->msg_info.to->uri)) {</span><br><span>            print_uri_debug(URI_TYPE_TO, rdata, (pjsip_hdr *)rdata->msg_info.to);</span><br><span>@@ -428,7 +464,7 @@</span><br><span>                       PJSIP_SC_UNSUPPORTED_URI_SCHEME, NULL, NULL, NULL);</span><br><span>          return PJ_TRUE;</span><br><span>      }</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(120, 100%, 40%);">+     remove_x_ast_params(rdata->msg_info.to->uri);</span><br><span> </span><br><span>      contact = (pjsip_contact_hdr *) pjsip_msg_find_hdr(</span><br><span>          rdata->msg_info.msg, PJSIP_H_CONTACT, NULL);</span><br><span>@@ -448,6 +484,8 @@</span><br><span>                                PJSIP_SC_UNSUPPORTED_URI_SCHEME, NULL, NULL, NULL);</span><br><span>                  return PJ_TRUE;</span><br><span>              }</span><br><span style="color: hsl(120, 100%, 40%);">+             remove_x_ast_params(contact->uri);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>              contact = (pjsip_contact_hdr *) pjsip_msg_find_hdr(</span><br><span>                  rdata->msg_info.msg, PJSIP_H_CONTACT, contact->next);</span><br><span>  }</span><br><span>diff --git a/res/res_pjsip_nat.c b/res/res_pjsip_nat.c</span><br><span>index bbf3359..dc7d10b 100644</span><br><span>--- a/res/res_pjsip_nat.c</span><br><span>+++ b/res/res_pjsip_nat.c</span><br><span>@@ -32,8 +32,43 @@</span><br><span> #include "asterisk/module.h"</span><br><span> #include "asterisk/acl.h"</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+/*! URI parameter for original host/port */</span><br><span style="color: hsl(120, 100%, 40%);">+#define AST_SIP_X_AST_ORIG_HOST "x-ast-orig-host"</span><br><span style="color: hsl(120, 100%, 40%);">+#define AST_SIP_X_AST_ORIG_HOST_LEN 15</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static void save_orig_contact_host(pjsip_rx_data *rdata, pjsip_sip_uri *uri)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+     pjsip_param *x_orig_host;</span><br><span style="color: hsl(120, 100%, 40%);">+     pj_str_t p_value;</span><br><span style="color: hsl(120, 100%, 40%);">+#define COLON_LEN 1</span><br><span style="color: hsl(120, 100%, 40%);">+#define MAX_PORT_LEN 5</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      if (rdata->msg_info.msg->type != PJSIP_REQUEST_MSG ||</span><br><span style="color: hsl(120, 100%, 40%);">+           rdata->msg_info.msg->line.req.method.id != PJSIP_REGISTER_METHOD) {</span><br><span style="color: hsl(120, 100%, 40%);">+             return;</span><br><span style="color: hsl(120, 100%, 40%);">+       }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   ast_debug(1, "Saving contact '%.*s:%d'\n",</span><br><span style="color: hsl(120, 100%, 40%);">+          (int)uri->host.slen, uri->host.ptr, uri->port);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    x_orig_host = PJ_POOL_ALLOC_T(rdata->tp_info.pool, pjsip_param);</span><br><span style="color: hsl(120, 100%, 40%);">+   x_orig_host->name = pj_strdup3(rdata->tp_info.pool, AST_SIP_X_AST_ORIG_HOST);</span><br><span style="color: hsl(120, 100%, 40%);">+   p_value.slen = pj_strlen(&uri->host) + COLON_LEN + MAX_PORT_LEN;</span><br><span style="color: hsl(120, 100%, 40%);">+       p_value.ptr = (char*)pj_pool_alloc(rdata->tp_info.pool, p_value.slen + 1);</span><br><span style="color: hsl(120, 100%, 40%);">+ p_value.slen = snprintf(p_value.ptr, p_value.slen + 1, "%.*s:%d", (int)uri->host.slen, uri->host.ptr, uri->port);</span><br><span style="color: hsl(120, 100%, 40%);">+  pj_strassign(&x_orig_host->value, &p_value);</span><br><span style="color: hsl(120, 100%, 40%);">+       pj_list_insert_before(&uri->other_param, x_orig_host);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       return;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> static void rewrite_uri(pjsip_rx_data *rdata, pjsip_sip_uri *uri)</span><br><span> {</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      if (pj_strcmp2(&uri->host, rdata->pkt_info.src_name) != 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+                save_orig_contact_host(rdata, uri);</span><br><span style="color: hsl(120, 100%, 40%);">+   }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>  pj_cstr(&uri->host, rdata->pkt_info.src_name);</span><br><span>     uri->port = rdata->pkt_info.src_port;</span><br><span>  if (!strcasecmp("WSS", rdata->tp_info.transport->type_name)) {</span><br><span>@@ -264,7 +299,44 @@</span><br><span>        return 0;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-static pj_status_t nat_on_tx_message(pjsip_tx_data *tdata)</span><br><span style="color: hsl(120, 100%, 40%);">+static void restore_orig_contact_host(pjsip_tx_data *tdata)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+  pjsip_contact_hdr *contact;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ if (tdata->msg->type != PJSIP_RESPONSE_MSG) {</span><br><span style="color: hsl(120, 100%, 40%);">+           return;</span><br><span style="color: hsl(120, 100%, 40%);">+       }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   contact = pjsip_msg_find_hdr(tdata->msg, PJSIP_H_CONTACT, NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+   while (contact) {</span><br><span style="color: hsl(120, 100%, 40%);">+             pjsip_sip_uri *contact_uri = pjsip_uri_get_uri(contact->uri);</span><br><span style="color: hsl(120, 100%, 40%);">+              pj_str_t x_name = { AST_SIP_X_AST_ORIG_HOST, AST_SIP_X_AST_ORIG_HOST_LEN };</span><br><span style="color: hsl(120, 100%, 40%);">+           pjsip_param *x_orig_host = pjsip_param_find(&contact_uri->other_param, &x_name);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+         if (x_orig_host) {</span><br><span style="color: hsl(120, 100%, 40%);">+                    char host_port[x_orig_host->value.slen + 1];</span><br><span style="color: hsl(120, 100%, 40%);">+                       char *sep;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+                  ast_debug(1, "Restoring contact %.*s:%d  to %.*s\n", (int)contact_uri->host.slen,</span><br><span style="color: hsl(120, 100%, 40%);">+                                contact_uri->host.ptr, contact_uri->port,</span><br><span style="color: hsl(120, 100%, 40%);">+                               (int)x_orig_host->value.slen, x_orig_host->value.ptr);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+                        strncpy(host_port, x_orig_host->value.ptr, x_orig_host->value.slen);</span><br><span style="color: hsl(120, 100%, 40%);">+                    host_port[x_orig_host->value.slen] = '\0';</span><br><span style="color: hsl(120, 100%, 40%);">+                 sep = strchr(host_port, ':');</span><br><span style="color: hsl(120, 100%, 40%);">+                 if (sep) {</span><br><span style="color: hsl(120, 100%, 40%);">+                            *sep = '\0';</span><br><span style="color: hsl(120, 100%, 40%);">+                          sep++;</span><br><span style="color: hsl(120, 100%, 40%);">+                                pj_strdup2(tdata->pool, &contact_uri->host, host_port);</span><br><span style="color: hsl(120, 100%, 40%);">+                             contact_uri->port = strtol(sep, NULL, 10);</span><br><span style="color: hsl(120, 100%, 40%);">+                 }</span><br><span style="color: hsl(120, 100%, 40%);">+                     pj_list_erase(x_orig_host);</span><br><span style="color: hsl(120, 100%, 40%);">+           }</span><br><span style="color: hsl(120, 100%, 40%);">+             contact = pjsip_msg_find_hdr(tdata->msg, PJSIP_H_CONTACT, contact->next);</span><br><span style="color: hsl(120, 100%, 40%);">+       }</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static pj_status_t process_nat(pjsip_tx_data *tdata)</span><br><span> {</span><br><span>    RAII_VAR(struct ao2_container *, transport_states, NULL, ao2_cleanup);</span><br><span>       RAII_VAR(struct ast_sip_transport *, transport, NULL, ao2_cleanup);</span><br><span>@@ -364,6 +436,16 @@</span><br><span>   return PJ_SUCCESS;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+static pj_status_t nat_on_tx_message(pjsip_tx_data *tdata) {</span><br><span style="color: hsl(120, 100%, 40%);">+     pj_status_t rc;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     rc = process_nat(tdata);</span><br><span style="color: hsl(120, 100%, 40%);">+      restore_orig_contact_host(tdata);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   return rc;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> static pjsip_module nat_module = {</span><br><span>      .name = { "NAT", 3 },</span><br><span>      .id = -1,</span><br><span></span><br></pre><p>To view, visit <a href="https://gerrit.asterisk.org/c/asterisk/+/12825">change 12825</a>. To unsubscribe, or for help writing mail filters, visit <a href="https://gerrit.asterisk.org/settings">settings</a>.</p><div itemscope itemtype="http://schema.org/EmailMessage"><div itemscope itemprop="action" itemtype="http://schema.org/ViewAction"><link itemprop="url" href="https://gerrit.asterisk.org/c/asterisk/+/12825"/><meta itemprop="name" content="View Change"/></div></div>

<div style="display:none"> Gerrit-Project: asterisk </div>
<div style="display:none"> Gerrit-Branch: 16 </div>
<div style="display:none"> Gerrit-Change-Id: Idc263ad2d2d7bd8faa047e5804d96a5fe1cd282e </div>
<div style="display:none"> Gerrit-Change-Number: 12825 </div>
<div style="display:none"> Gerrit-PatchSet: 9 </div>
<div style="display:none"> Gerrit-Owner: George Joseph <gjoseph@digium.com> </div>
<div style="display:none"> Gerrit-Reviewer: Friendly Automation </div>
<div style="display:none"> Gerrit-Reviewer: George Joseph <gjoseph@digium.com> </div>
<div style="display:none"> Gerrit-Reviewer: Joshua C. Colp <jcolp@sangoma.com> </div>
<div style="display:none"> Gerrit-Reviewer: Kevin Harwell <kharwell@digium.com> </div>
<div style="display:none"> Gerrit-MessageType: merged </div>