<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>