Merge "res_pjsip: Split type=identify to IP address and SIP header matching priorities" into 13

certified/13.21
Jenkins2 8 years ago committed by Gerrit Code Review
commit 16f211c647

@ -8,6 +8,31 @@
===
==============================================================================
------------------------------------------------------------------------------
--- Functionality changes from Asterisk 13.19.0 to Asterisk 13.20.0 ----------
------------------------------------------------------------------------------
res_pjsip
------------------
* Users who are matching endpoints by SIP header need to reevaluate their
global "endpoint_identifier_order" option in light of the "ip" endpoint
identifier method split into the "ip" and "header" endpoint identifier
methods.
res_pjsip_endpoint_identifier_ip
------------------
* The endpoint identifier "ip" method previously recognized endpoints either
by IP address or a matching SIP header. The "ip" endpoint identifier method
is now split into the "ip" and "header" endpoint identifier methods. The
"ip" endpoint identifier method only matches by IP address and the "header"
endpoint identifier method only matches by SIP header. The split allows the
user to control the relative priority of the IP address and the SIP header
identification methods in the global "endpoint_identifier_order" option.
e.g., If you have two type=identify sections where one matches by IP address
for endpoint alice and the other matches by SIP header for endpoint bob then
you can now predict which endpoint is matched when a request comes in that
matches both.
------------------------------------------------------------------------------
--- Functionality changes from Asterisk 13.18.0 to Asterisk 13.19.0 ----------
------------------------------------------------------------------------------

@ -21,6 +21,29 @@
=== UPGRADE-12.txt -- Upgrade info for 11 to 12
===========================================================
From 13.19.0 to 13.20.0:
res_pjsip
------------------
* Users who are matching endpoints by SIP header need to reevaluate their
global "endpoint_identifier_order" option in light of the "ip" endpoint
identifier method split into the "ip" and "header" endpoint identifier
methods.
res_pjsip_endpoint_identifier_ip
------------------
* The endpoint identifier "ip" method previously recognized endpoints either
by IP address or a matching SIP header. The "ip" endpoint identifier method
is now split into the "ip" and "header" endpoint identifier methods. The
"ip" endpoint identifier method only matches by IP address and the "header"
endpoint identifier method only matches by SIP header. The split allows the
user to control the relative priority of the IP address and the SIP header
identification methods in the global "endpoint_identifier_order" option.
e.g., If you have two type=identify sections where one matches by IP address
for endpoint alice and the other matches by SIP header for endpoint bob then
you can now predict which endpoint is matched when a request comes in that
matches both.
From 13.17.0 to 13.18.0:
Core:

@ -635,6 +635,7 @@
; "username": Identify by the From or To username and domain
; "auth_username": Identify by the Authorization username and realm
; "ip": Identify by the source IP address
; "header": Identify by a configured SIP header value.
; In the username and auth_username cases, if an exact match
; on both username and domain/realm fails, the match is
; retried with just the username.
@ -967,11 +968,11 @@
; (default: "no")
;endpoint_identifier_order=ip,username,anonymous
; The order by which endpoint identifiers are given priority.
; Currently, "ip", "username", "auth_username" and "anonymous" are valid
; identifiers as registered by the res_pjsip_endpoint_identifier_* modules.
; Some modules like res_pjsip_endpoint_identifier_user register more than
; one identifier. Use the CLI command "pjsip show identifiers" to see the
; identifiers currently available.
; Currently, "ip", "header", "username", "auth_username" and "anonymous"
; are valid identifiers as registered by the res_pjsip_endpoint_identifier_*
; modules. Some modules like res_pjsip_endpoint_identifier_user register
; more than one identifier. Use the CLI command "pjsip show identifiers"
; to see the identifiers currently available.
; (default: ip,username,anonymous)
;max_initial_qualify_time=4 ; The maximum amount of time (in seconds) from
; startup that qualifies should be attempted on all

@ -0,0 +1,57 @@
"""add pjsip identify by header
Revision ID: 52798ad97bdf
Revises: 20abce6d1e3c
Create Date: 2018-01-08 12:16:02.782277
"""
# revision identifiers, used by Alembic.
revision = '52798ad97bdf'
down_revision = '20abce6d1e3c'
from alembic import op
import sqlalchemy as sa
def column_upgrade(table_name, column_name, enum_name):
if op.get_context().bind.dialect.name != 'postgresql':
if op.get_context().bind.dialect.name == 'mssql':
op.drop_constraint('ck_ps_endpoints_identify_by_pjsip_identify_by_values',
table_name)
op.alter_column(table_name, column_name, type_=sa.String(80))
return
# Postgres requires a few more steps
op.execute('ALTER TABLE ' + table_name + ' ALTER COLUMN ' + column_name +
' TYPE varchar(80) USING identify_by::text::' + enum_name)
op.execute('DROP TYPE ' + enum_name)
def column_downgrade(table_name, column_name, enum_name, enum_values):
if op.get_context().bind.dialect.name != 'postgresql':
op.alter_column(table_name, column_name,
type_=sa.Enum(*enum_values, name=enum_name))
return
# Postgres requires a few more steps
updated = sa.Enum(*enum_values, name=enum_name)
updated.create(op.get_bind(), checkfirst=False)
op.execute('ALTER TABLE ' + table_name + ' ALTER COLUMN ' + column_name +
' TYPE ' + enum_name + ' USING identify_by::text::' + enum_name)
def upgrade():
# The ps_endpoints identify_by column has always been a comma separated
# list of enum values. This is better represented as a string anyway to
# avoid database compatibility issues. Also future changes are likely
# to allow loadable endpoint identifier names and negating fixed enum
# benefits.
column_upgrade('ps_endpoints', 'identify_by', 'pjsip_identify_by_values')
def downgrade():
column_downgrade('ps_endpoints', 'identify_by', 'pjsip_identify_by_values',
['username', 'auth_username', 'ip'])

@ -437,6 +437,8 @@ enum ast_sip_endpoint_identifier_type {
AST_SIP_ENDPOINT_IDENTIFY_BY_AUTH_USERNAME = (1 << 1),
/*! Identify based on source IP address */
AST_SIP_ENDPOINT_IDENTIFY_BY_IP = (1 << 2),
/*! Identify based on arbitrary headers */
AST_SIP_ENDPOINT_IDENTIFY_BY_HEADER = (1 << 3),
};
AST_VECTOR(ast_sip_identify_by_vector, enum ast_sip_endpoint_identifier_type);

@ -323,6 +323,17 @@
endpoint identification.
</para>
</enum>
<enum name="header">
<para>Matches the endpoint based on a configured SIP header
value.
</para>
<para>This method of identification is not configured here
but simply allowed by this configuration option. See the
documentation for the <literal>identify</literal>
configuration section for more details on this method of
endpoint identification.
</para>
</enum>
</enumlist>
</description>
</configOption>

@ -596,6 +596,9 @@ static const char *sip_endpoint_identifier_type2str(enum ast_sip_endpoint_identi
case AST_SIP_ENDPOINT_IDENTIFY_BY_IP:
str = "ip";
break;
case AST_SIP_ENDPOINT_IDENTIFY_BY_HEADER:
str = "header";
break;
}
return str;
}
@ -619,6 +622,8 @@ static int sip_endpoint_identifier_str2type(const char *str)
method = AST_SIP_ENDPOINT_IDENTIFY_BY_AUTH_USERNAME;
} else if (!strcasecmp(str, "ip")) {
method = AST_SIP_ENDPOINT_IDENTIFY_BY_IP;
} else if (!strcasecmp(str, "header")) {
method = AST_SIP_ENDPOINT_IDENTIFY_BY_HEADER;
} else {
method = -1;
}

@ -186,7 +186,7 @@ static int header_identify_match_check(void *obj, void *arg, int flags)
return 0;
}
return CMP_MATCH | CMP_STOP;
return CMP_MATCH;
}
/*! \brief Comparator function for matching an object by IP address */
@ -201,7 +201,7 @@ static int ip_identify_match_check(void *obj, void *arg, int flags)
ast_debug(3, "Source address %s matches identify '%s'\n",
ast_sockaddr_stringify(addr),
ast_sorcery_object_get_id(identify));
return CMP_MATCH | CMP_STOP;
return CMP_MATCH;
} else {
ast_debug(3, "Source address %s does not match identify '%s'\n",
ast_sockaddr_stringify(addr),
@ -210,48 +210,62 @@ static int ip_identify_match_check(void *obj, void *arg, int flags)
}
}
static struct ast_sip_endpoint *ip_identify(pjsip_rx_data *rdata)
static struct ast_sip_endpoint *common_identify(ao2_callback_fn *identify_match_cb, void *arg)
{
struct ast_sockaddr addr = { { 0, } };
RAII_VAR(struct ao2_container *, candidates, NULL, ao2_cleanup);
RAII_VAR(struct ip_identify_match *, match, NULL, ao2_cleanup);
struct ip_identify_match *match;
struct ast_sip_endpoint *endpoint;
/* If no possibilities exist return early to save some time */
if (!(candidates = ast_sorcery_retrieve_by_fields(ast_sip_get_sorcery(), "identify", AST_RETRIEVE_FLAG_MULTIPLE | AST_RETRIEVE_FLAG_ALL, NULL)) ||
!ao2_container_count(candidates)) {
candidates = ast_sorcery_retrieve_by_fields(ast_sip_get_sorcery(), "identify",
AST_RETRIEVE_FLAG_MULTIPLE | AST_RETRIEVE_FLAG_ALL, NULL);
if (!candidates || !ao2_container_count(candidates)) {
ast_debug(3, "No identify sections to match against\n");
return NULL;
}
ast_sockaddr_parse(&addr, rdata->pkt_info.src_name, PARSE_PORT_FORBID);
ast_sockaddr_set_port(&addr, rdata->pkt_info.src_port);
match = ao2_callback(candidates, 0, ip_identify_match_check, &addr);
match = ao2_callback(candidates, 0, identify_match_cb, arg);
if (!match) {
ast_debug(3, "Identify checks by IP address failed to find match: '%s' did not match any identify section rules\n",
ast_sockaddr_stringify(&addr));
match = ao2_callback(candidates, 0, header_identify_match_check, rdata);
if (!match) {
return NULL;
}
return NULL;
}
endpoint = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "endpoint", match->endpoint_name);
endpoint = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "endpoint",
match->endpoint_name);
if (endpoint) {
ast_debug(3, "Retrieved endpoint %s\n", ast_sorcery_object_get_id(endpoint));
ast_debug(3, "Identify '%s' SIP message matched to endpoint %s\n",
ast_sorcery_object_get_id(match), match->endpoint_name);
} else {
ast_log(LOG_WARNING, "Identify section '%s' points to endpoint '%s' but endpoint could not be looked up\n",
ast_sorcery_object_get_id(match), match->endpoint_name);
ast_log(LOG_WARNING, "Identify '%s' points to endpoint '%s' but endpoint could not be found\n",
ast_sorcery_object_get_id(match), match->endpoint_name);
}
ao2_ref(match, -1);
return endpoint;
}
static struct ast_sip_endpoint *ip_identify(pjsip_rx_data *rdata)
{
struct ast_sockaddr addr = { { 0, } };
ast_sockaddr_parse(&addr, rdata->pkt_info.src_name, PARSE_PORT_FORBID);
ast_sockaddr_set_port(&addr, rdata->pkt_info.src_port);
return common_identify(ip_identify_match_check, &addr);
}
static struct ast_sip_endpoint_identifier ip_identifier = {
.identify_endpoint = ip_identify,
};
static struct ast_sip_endpoint *header_identify(pjsip_rx_data *rdata)
{
return common_identify(header_identify_match_check, rdata);
}
static struct ast_sip_endpoint_identifier header_identifier = {
.identify_endpoint = header_identify,
};
/*! \brief Helper function which performs a host lookup and adds result to identify match */
static int ip_identify_match_host_lookup(struct ip_identify_match *identify, const char *host)
{
@ -720,6 +734,7 @@ static int load_module(void)
ast_sorcery_load_object(ast_sip_get_sorcery(), "identify");
ast_sip_register_endpoint_identifier_with_name(&ip_identifier, "ip");
ast_sip_register_endpoint_identifier_with_name(&header_identifier, "header");
ast_sip_register_endpoint_formatter(&endpoint_identify_formatter);
cli_formatter = ao2_alloc(sizeof(struct ast_sip_cli_formatter_entry), NULL);

Loading…
Cancel
Save