<p>Richard Mudgett has uploaded this change for <strong>review</strong>.</p><p><a href="https://gerrit.asterisk.org/7935">View Change</a></p><pre style="font-family: monospace,monospace; white-space: pre-wrap;">res_pjsip: Split type=identify to IP address and SIP header matching priorities<br><br>The type=identify endpoint identification method can match by IP address<br>and by SIP header.  However, the SIP header matching has limited<br>usefulness because you cannot specify the SIP header matching priority<br>relative to the IP address matching.  All the matching happens at the same<br>priority and the order of evaluating the identify sections is<br>indeterminate.  e.g., If you had two type=identify sections where one<br>matches by IP address for endpoint alice and the other matches by SIP<br>header for endpoint bob then you couldn't predict which endpoint is<br>matched when a request comes in that matches both.<br><br>* Extract the SIP header matching criteria into its own "header" endpoint<br>identification method so the user can specify the relative priority of the<br>SIP header and the IP address matching criteria in the global<br>endpoint_identifier_order option.  The "ip" endpoint identification method<br>now only matches by IP address.<br><br>ASTERISK-27491<br><br>Change-Id: I9df142a575b7e1e3471b7cda5d3ea156cef08095<br>---<br>M CHANGES<br>M UPGRADE.txt<br>M configs/samples/pjsip.conf.sample<br>A contrib/ast-db-manage/config/versions/52798ad97bdf_add_pjsip_identify_by_header.py<br>M include/asterisk/res_pjsip.h<br>M res/res_pjsip.c<br>M res/res_pjsip/pjsip_configuration.c<br>M res/res_pjsip_endpoint_identifier_ip.c<br>8 files changed, 166 insertions(+), 31 deletions(-)<br><br></pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;">git pull ssh://gerrit.asterisk.org:29418/asterisk refs/changes/35/7935/1</pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;">diff --git a/CHANGES b/CHANGES<br>index 25e0a86..07bbce1 100644<br>--- a/CHANGES<br>+++ b/CHANGES<br>@@ -16,6 +16,27 @@<br> ------------------<br>  * Removed the unused and incomplete SDP processing modules.<br> <br>+res_pjsip<br>+------------------<br>+ * Users who are matching endpoints by SIP header need to reevaluate their<br>+   global "endpoint_identifier_order" option in light of the "ip" endpoint<br>+   identifier method split into the "ip" and "header" endpoint identifier<br>+   methods.<br>+<br>+res_pjsip_endpoint_identifier_ip<br>+------------------<br>+ * The endpoint identifier "ip" method previously recognized endpoints either<br>+   by IP address or a matching SIP header.  The "ip" endpoint identifier method<br>+   is now split into the "ip" and "header" endpoint identifier methods.  The<br>+   "ip" endpoint identifier method only matches by IP address and the "header"<br>+   endpoint identifier method only matches by SIP header.  The split allows the<br>+   user to control the relative priority of the IP address and the SIP header<br>+   identification methods in the global "endpoint_identifier_order" option.<br>+   e.g., If you have two type=identify sections where one matches by IP address<br>+   for endpoint alice and the other matches by SIP header for endpoint bob then<br>+   you can now predict which endpoint is matched when a request comes in that<br>+   matches both.<br>+<br> res_sdp_translator_pjmedia<br> ------------------<br>  * Removed the unused and incomplete SDP processing modules.<br>diff --git a/UPGRADE.txt b/UPGRADE.txt<br>index 30dc5d0..d47bbe3 100644<br>--- a/UPGRADE.txt<br>+++ b/UPGRADE.txt<br>@@ -23,6 +23,29 @@<br> === UPGRADE-14.txt  -- Upgrade info for 13 to 14<br> ===========================================================<br> <br>+From 15.2.0 to 15.3.0:<br>+<br>+res_pjsip<br>+------------------<br>+ * Users who are matching endpoints by SIP header need to reevaluate their<br>+   global "endpoint_identifier_order" option in light of the "ip" endpoint<br>+   identifier method split into the "ip" and "header" endpoint identifier<br>+   methods.<br>+<br>+res_pjsip_endpoint_identifier_ip<br>+------------------<br>+ * The endpoint identifier "ip" method previously recognized endpoints either<br>+   by IP address or a matching SIP header.  The "ip" endpoint identifier method<br>+   is now split into the "ip" and "header" endpoint identifier methods.  The<br>+   "ip" endpoint identifier method only matches by IP address and the "header"<br>+   endpoint identifier method only matches by SIP header.  The split allows the<br>+   user to control the relative priority of the IP address and the SIP header<br>+   identification methods in the global "endpoint_identifier_order" option.<br>+   e.g., If you have two type=identify sections where one matches by IP address<br>+   for endpoint alice and the other matches by SIP header for endpoint bob then<br>+   you can now predict which endpoint is matched when a request comes in that<br>+   matches both.<br>+<br> New in 15.0.0:<br> <br> Build System:<br>diff --git a/configs/samples/pjsip.conf.sample b/configs/samples/pjsip.conf.sample<br>index 8499320..a39a867 100644<br>--- a/configs/samples/pjsip.conf.sample<br>+++ b/configs/samples/pjsip.conf.sample<br>@@ -635,6 +635,7 @@<br>                         ; "username": Identify by the From or To username and domain<br>                         ; "auth_username": Identify by the Authorization username and realm<br>                         ; "ip": Identify by the source IP address<br>+                        ; "header": Identify by a configured SIP header value.<br>                         ; In the username and auth_username cases, if an exact match<br>                         ; on both username and domain/realm fails, the match is<br>                         ; retried with just the username.<br>@@ -993,11 +994,11 @@<br>             ; (default: "no")<br> ;endpoint_identifier_order=ip,username,anonymous<br>             ; The order by which endpoint identifiers are given priority.<br>-            ; Currently, "ip", "username", "auth_username" and "anonymous" are valid<br>-            ; identifiers as registered by the res_pjsip_endpoint_identifier_* modules.<br>-            ; Some modules like res_pjsip_endpoint_identifier_user register more than<br>-            ; one identifier. Use the CLI command "pjsip show identifiers" to see the<br>-            ; identifiers currently available.<br>+            ; Currently, "ip", "header", "username", "auth_username" and "anonymous"<br>+            ; are valid identifiers as registered by the res_pjsip_endpoint_identifier_*<br>+            ; modules.  Some modules like res_pjsip_endpoint_identifier_user register<br>+            ; more than one identifier.  Use the CLI command "pjsip show identifiers"<br>+            ; to see the identifiers currently available.<br>             ; (default: ip,username,anonymous)<br> ;max_initial_qualify_time=4 ; The maximum amount of time (in seconds) from<br>                             ; startup that qualifies should be attempted on all<br>diff --git a/contrib/ast-db-manage/config/versions/52798ad97bdf_add_pjsip_identify_by_header.py b/contrib/ast-db-manage/config/versions/52798ad97bdf_add_pjsip_identify_by_header.py<br>new file mode 100644<br>index 0000000..d67b277<br>--- /dev/null<br>+++ b/contrib/ast-db-manage/config/versions/52798ad97bdf_add_pjsip_identify_by_header.py<br>@@ -0,0 +1,57 @@<br>+"""add pjsip identify by header<br>+<br>+Revision ID: 52798ad97bdf<br>+Revises: 041c0d3d1857<br>+Create Date: 2018-01-08 12:16:02.782277<br>+<br>+"""<br>+<br>+# revision identifiers, used by Alembic.<br>+revision = '52798ad97bdf'<br>+down_revision = '041c0d3d1857'<br>+<br>+from alembic import op<br>+import sqlalchemy as sa<br>+<br>+<br>+def column_upgrade(table_name, column_name, enum_name):<br>+    if op.get_context().bind.dialect.name != 'postgresql':<br>+        if op.get_context().bind.dialect.name == 'mssql':<br>+            op.drop_constraint('ck_ps_endpoints_identify_by_pjsip_identify_by_values',<br>+                               table_name)<br>+        op.alter_column(table_name, column_name, type_=sa.String(80))<br>+        return<br>+<br>+    # Postgres requires a few more steps<br>+    op.execute('ALTER TABLE ' + table_name + ' ALTER COLUMN ' + column_name +<br>+               ' TYPE varchar(80) USING identify_by::text::' + enum_name)<br>+<br>+    op.execute('DROP TYPE ' + enum_name)<br>+<br>+<br>+def column_downgrade(table_name, column_name, enum_name, enum_values):<br>+    if op.get_context().bind.dialect.name != 'postgresql':<br>+        op.alter_column(table_name, column_name,<br>+                        type_=sa.Enum(*enum_values, name=enum_name))<br>+        return<br>+<br>+    # Postgres requires a few more steps<br>+    updated = sa.Enum(*enum_values, name=enum_name)<br>+    updated.create(op.get_bind(), checkfirst=False)<br>+<br>+    op.execute('ALTER TABLE ' + table_name + ' ALTER COLUMN ' + column_name +<br>+               ' TYPE ' + enum_name + ' USING identify_by::text::' + enum_name)<br>+<br>+<br>+def upgrade():<br>+    # The ps_endpoints identify_by column has always been a comma separated<br>+    # list of enum values.  This is better represented as a string anyway to<br>+    # avoid database compatibility issues.  Also future changes are likely<br>+    # to allow loadable endpoint identifier names and negating fixed enum<br>+    # benefits.<br>+    column_upgrade('ps_endpoints', 'identify_by', 'pjsip_identify_by_values')<br>+<br>+<br>+def downgrade():<br>+    column_downgrade('ps_endpoints', 'identify_by', 'pjsip_identify_by_values',<br>+                     ['username', 'auth_username', 'ip'])<br>diff --git a/include/asterisk/res_pjsip.h b/include/asterisk/res_pjsip.h<br>index 1c71957..330e49f 100644<br>--- a/include/asterisk/res_pjsip.h<br>+++ b/include/asterisk/res_pjsip.h<br>@@ -439,6 +439,8 @@<br>     AST_SIP_ENDPOINT_IDENTIFY_BY_AUTH_USERNAME = (1 << 1),<br>  /*! Identify based on source IP address */<br>    AST_SIP_ENDPOINT_IDENTIFY_BY_IP = (1 << 2),<br>+    /*! Identify based on arbitrary headers */<br>+   AST_SIP_ENDPOINT_IDENTIFY_BY_HEADER = (1 << 3),<br> };<br> AST_VECTOR(ast_sip_identify_by_vector, enum ast_sip_endpoint_identifier_type);<br> <br>diff --git a/res/res_pjsip.c b/res/res_pjsip.c<br>index 7988315..90a273c 100644<br>--- a/res/res_pjsip.c<br>+++ b/res/res_pjsip.c<br>@@ -323,6 +323,17 @@<br>                                                             endpoint identification.<br>                                                              </para><br>                                                         </enum><br>+                                                        <enum name="header"><br>+                                                         <para>Matches the endpoint based on a configured SIP header<br>+                                                            value.<br>+                                                               </para><br>+                                                                <para>This method of identification is not configured here<br>+                                                             but simply allowed by this configuration option.  See the<br>+                                                            documentation for the <literal>identify</literal><br>+                                                                configuration section for more details on this method of<br>+                                                             endpoint identification.<br>+                                                             </para><br>+                                                        </enum><br>                                                 </enumlist><br>                                     </description><br>                          </configOption><br>diff --git a/res/res_pjsip/pjsip_configuration.c b/res/res_pjsip/pjsip_configuration.c<br>index c79877a..d1bfdfe 100644<br>--- a/res/res_pjsip/pjsip_configuration.c<br>+++ b/res/res_pjsip/pjsip_configuration.c<br>@@ -594,6 +594,9 @@<br>       case AST_SIP_ENDPOINT_IDENTIFY_BY_IP:<br>                 str = "ip";<br>                 break;<br>+       case AST_SIP_ENDPOINT_IDENTIFY_BY_HEADER:<br>+            str = "header";<br>+            break;<br>        }<br>     return str;<br> }<br>@@ -617,6 +620,8 @@<br>          method = AST_SIP_ENDPOINT_IDENTIFY_BY_AUTH_USERNAME;<br>  } else if (!strcasecmp(str, "ip")) {<br>                method = AST_SIP_ENDPOINT_IDENTIFY_BY_IP;<br>+    } else if (!strcasecmp(str, "header")) {<br>+           method = AST_SIP_ENDPOINT_IDENTIFY_BY_HEADER;<br>         } else {<br>              method = -1;<br>  }<br>diff --git a/res/res_pjsip_endpoint_identifier_ip.c b/res/res_pjsip_endpoint_identifier_ip.c<br>index a672b33..1977ab7 100644<br>--- a/res/res_pjsip_endpoint_identifier_ip.c<br>+++ b/res/res_pjsip_endpoint_identifier_ip.c<br>@@ -186,7 +186,7 @@<br>               return 0;<br>     }<br> <br>- return CMP_MATCH | CMP_STOP;<br>+ return CMP_MATCH;<br> }<br> <br> /*! \brief Comparator function for matching an object by IP address */<br>@@ -201,7 +201,7 @@<br>                ast_debug(3, "Source address %s matches identify '%s'\n",<br>                           ast_sockaddr_stringify(addr),<br>                                 ast_sorcery_object_get_id(identify));<br>-                return CMP_MATCH | CMP_STOP;<br>+         return CMP_MATCH;<br>     } else {<br>              ast_debug(3, "Source address %s does not match identify '%s'\n",<br>                            ast_sockaddr_stringify(addr),<br>@@ -210,46 +210,60 @@<br>  }<br> }<br> <br>-static struct ast_sip_endpoint *ip_identify(pjsip_rx_data *rdata)<br>+static struct ast_sip_endpoint *common_identify(ao2_callback_fn *identify_match_cb, void *arg)<br> {<br>-    struct ast_sockaddr addr = { { 0, } };<br>        RAII_VAR(struct ao2_container *, candidates, NULL, ao2_cleanup);<br>-     RAII_VAR(struct ip_identify_match *, match, NULL, ao2_cleanup);<br>+      struct ip_identify_match *match;<br>      struct ast_sip_endpoint *endpoint;<br> <br>         /* If no possibilities exist return early to save some time */<br>-       if (!(candidates = ast_sorcery_retrieve_by_fields(ast_sip_get_sorcery(), "identify", AST_RETRIEVE_FLAG_MULTIPLE | AST_RETRIEVE_FLAG_ALL, NULL)) ||<br>-         !ao2_container_count(candidates)) {<br>+  candidates = ast_sorcery_retrieve_by_fields(ast_sip_get_sorcery(), "identify",<br>+             AST_RETRIEVE_FLAG_MULTIPLE | AST_RETRIEVE_FLAG_ALL, NULL);<br>+   if (!candidates || !ao2_container_count(candidates)) {<br>                ast_debug(3, "No identify sections to match against\n");<br>            return NULL;<br>  }<br> <br>+ match = ao2_callback(candidates, 0, identify_match_cb, arg);<br>+ if (!match) {<br>+                return NULL;<br>+ }<br>+<br>+ endpoint = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "endpoint",<br>+           match->endpoint_name);<br>+    if (endpoint) {<br>+              ast_debug(3, "Identify '%s' SIP message matched to endpoint %s\n",<br>+                 ast_sorcery_object_get_id(match), match->endpoint_name);<br>+  } else {<br>+             ast_log(LOG_WARNING, "Identify '%s' points to endpoint '%s' but endpoint could not be found\n",<br>+                    ast_sorcery_object_get_id(match), match->endpoint_name);<br>+  }<br>+<br>+ ao2_ref(match, -1);<br>+  return endpoint;<br>+}<br>+<br>+static struct ast_sip_endpoint *ip_identify(pjsip_rx_data *rdata)<br>+{<br>+      struct ast_sockaddr addr = { { 0, } };<br>+<br>     ast_sockaddr_parse(&addr, rdata->pkt_info.src_name, PARSE_PORT_FORBID);<br>        ast_sockaddr_set_port(&addr, rdata->pkt_info.src_port);<br> <br>-    match = ao2_callback(candidates, 0, ip_identify_match_check, &addr);<br>-     if (!match) {<br>-                ast_debug(3, "Identify checks by IP address failed to find match: '%s' did not match any identify section rules\n",<br>-                                ast_sockaddr_stringify(&addr));<br>-          match = ao2_callback(candidates, 0, header_identify_match_check, rdata);<br>-             if (!match) {<br>-                        return NULL;<br>-         }<br>-    }<br>-<br>- endpoint = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "endpoint", match->endpoint_name);<br>- if (endpoint) {<br>-              ast_debug(3, "Retrieved endpoint %s\n", ast_sorcery_object_get_id(endpoint));<br>-      } else {<br>-             ast_log(LOG_WARNING, "Identify section '%s' points to endpoint '%s' but endpoint could not be looked up\n",<br>-                                ast_sorcery_object_get_id(match), match->endpoint_name);<br>-  }<br>-<br>- return endpoint;<br>+     return common_identify(ip_identify_match_check, &addr);<br> }<br> <br> static struct ast_sip_endpoint_identifier ip_identifier = {<br>      .identify_endpoint = ip_identify,<br>+};<br>+<br>+static struct ast_sip_endpoint *header_identify(pjsip_rx_data *rdata)<br>+{<br>+        return common_identify(header_identify_match_check, rdata);<br>+}<br>+<br>+static struct ast_sip_endpoint_identifier header_identifier = {<br>+ .identify_endpoint = header_identify,<br> };<br> <br> /*! \brief Helper function which performs a host lookup and adds result to identify match */<br>@@ -720,6 +734,7 @@<br>     ast_sorcery_load_object(ast_sip_get_sorcery(), "identify");<br> <br>      ast_sip_register_endpoint_identifier_with_name(&ip_identifier, "ip");<br>+  ast_sip_register_endpoint_identifier_with_name(&header_identifier, "header");<br>   ast_sip_register_endpoint_formatter(&endpoint_identify_formatter);<br> <br>     cli_formatter = ao2_alloc(sizeof(struct ast_sip_cli_formatter_entry), NULL);<br></pre><p>To view, visit <a href="https://gerrit.asterisk.org/7935">change 7935</a>. To unsubscribe, 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/7935"/><meta itemprop="name" content="View Change"/></div></div>

<div style="display:none"> Gerrit-Project: asterisk </div>
<div style="display:none"> Gerrit-Branch: 15 </div>
<div style="display:none"> Gerrit-MessageType: newchange </div>
<div style="display:none"> Gerrit-Change-Id: I9df142a575b7e1e3471b7cda5d3ea156cef08095 </div>
<div style="display:none"> Gerrit-Change-Number: 7935 </div>
<div style="display:none"> Gerrit-PatchSet: 1 </div>
<div style="display:none"> Gerrit-Owner: Richard Mudgett <rmudgett@digium.com> </div>