mirror of
https://github.com/asterisk/asterisk.git
synced 2025-09-04 20:04:50 +00:00
res_pjsip_endpoint_identifier_ip: Endpoint identifier request URI
Add ability to match against PJSIP request URI.
UserNote: this new feature let users match endpoints based on the
indound SIP requests' URI. To do so, add 'request_uri' to the
endpoint's 'identify_by' option. The 'match_request_uri' option of
the identify can be an exact match for the entire request uri, or a
regular expression (between slashes). It's quite similar to the
header identifer.
Fixes: #599
(cherry picked from commit 83f1317eb4
)
This commit is contained in:
committed by
Asterisk Development Team
parent
b85c9d80ca
commit
779755527a
@@ -686,6 +686,7 @@
|
|||||||
; "auth_username": Identify by the Authorization username and realm
|
; "auth_username": Identify by the Authorization username and realm
|
||||||
; "ip": Identify by the source IP address
|
; "ip": Identify by the source IP address
|
||||||
; "header": Identify by a configured SIP header value.
|
; "header": Identify by a configured SIP header value.
|
||||||
|
; "request_uri": Identify by the configured SIP request URI.
|
||||||
; In the username and auth_username cases, if an exact match
|
; In the username and auth_username cases, if an exact match
|
||||||
; on both username and domain/realm fails, the match is
|
; on both username and domain/realm fails, the match is
|
||||||
; retried with just the username.
|
; retried with just the username.
|
||||||
|
@@ -0,0 +1,20 @@
|
|||||||
|
"""add match_request_uri attribute to identify
|
||||||
|
|
||||||
|
Revision ID: cf150a175fd3
|
||||||
|
Revises: 8fce8496f03e
|
||||||
|
Create Date: 2024-03-28 14:19:15.033869
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
# revision identifiers, used by Alembic.
|
||||||
|
revision = 'cf150a175fd3'
|
||||||
|
down_revision = '8fce8496f03e'
|
||||||
|
|
||||||
|
from alembic import op
|
||||||
|
import sqlalchemy as sa
|
||||||
|
|
||||||
|
def upgrade():
|
||||||
|
op.add_column('ps_endpoint_id_ips', sa.Column('match_request_uri', sa.String(255)))
|
||||||
|
|
||||||
|
def downgrade():
|
||||||
|
op.drop_column('ps_endpoint_id_ips', 'match_request_uri')
|
@@ -615,6 +615,8 @@ enum ast_sip_endpoint_identifier_type {
|
|||||||
AST_SIP_ENDPOINT_IDENTIFY_BY_IP = (1 << 2),
|
AST_SIP_ENDPOINT_IDENTIFY_BY_IP = (1 << 2),
|
||||||
/*! Identify based on arbitrary headers */
|
/*! Identify based on arbitrary headers */
|
||||||
AST_SIP_ENDPOINT_IDENTIFY_BY_HEADER = (1 << 3),
|
AST_SIP_ENDPOINT_IDENTIFY_BY_HEADER = (1 << 3),
|
||||||
|
/*! Identify based on request uri */
|
||||||
|
AST_SIP_ENDPOINT_IDENTIFY_BY_REQUEST_URI = (1 << 4),
|
||||||
};
|
};
|
||||||
AST_VECTOR(ast_sip_identify_by_vector, enum ast_sip_endpoint_identifier_type);
|
AST_VECTOR(ast_sip_identify_by_vector, enum ast_sip_endpoint_identifier_type);
|
||||||
|
|
||||||
|
@@ -559,6 +559,14 @@
|
|||||||
endpoint identification.
|
endpoint identification.
|
||||||
</para>
|
</para>
|
||||||
</enum>
|
</enum>
|
||||||
|
<enum name="request_uri">
|
||||||
|
<para>Matches the endpoint based on the configured SIP
|
||||||
|
request uri.
|
||||||
|
</para>
|
||||||
|
<para>This method of identification is not configured here
|
||||||
|
but simply allowed by this configuration option.
|
||||||
|
</para>
|
||||||
|
</enum>
|
||||||
</enumlist>
|
</enumlist>
|
||||||
</description>
|
</description>
|
||||||
</configOption>
|
</configOption>
|
||||||
|
@@ -423,6 +423,9 @@ static const char *sip_endpoint_identifier_type2str(enum ast_sip_endpoint_identi
|
|||||||
case AST_SIP_ENDPOINT_IDENTIFY_BY_HEADER:
|
case AST_SIP_ENDPOINT_IDENTIFY_BY_HEADER:
|
||||||
str = "header";
|
str = "header";
|
||||||
break;
|
break;
|
||||||
|
case AST_SIP_ENDPOINT_IDENTIFY_BY_REQUEST_URI:
|
||||||
|
str = "request_uri";
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
return str;
|
return str;
|
||||||
}
|
}
|
||||||
@@ -448,6 +451,8 @@ static int sip_endpoint_identifier_str2type(const char *str)
|
|||||||
method = AST_SIP_ENDPOINT_IDENTIFY_BY_IP;
|
method = AST_SIP_ENDPOINT_IDENTIFY_BY_IP;
|
||||||
} else if (!strcasecmp(str, "header")) {
|
} else if (!strcasecmp(str, "header")) {
|
||||||
method = AST_SIP_ENDPOINT_IDENTIFY_BY_HEADER;
|
method = AST_SIP_ENDPOINT_IDENTIFY_BY_HEADER;
|
||||||
|
} else if (!strcasecmp(str, "request_uri")) {
|
||||||
|
method = AST_SIP_ENDPOINT_IDENTIFY_BY_REQUEST_URI;
|
||||||
} else {
|
} else {
|
||||||
method = -1;
|
method = -1;
|
||||||
}
|
}
|
||||||
|
@@ -110,6 +110,20 @@
|
|||||||
</para></note>
|
</para></note>
|
||||||
</description>
|
</description>
|
||||||
</configOption>
|
</configOption>
|
||||||
|
<configOption name="match_request_uri">
|
||||||
|
<synopsis>Request URI to match against.</synopsis>
|
||||||
|
<description>
|
||||||
|
<para>The SIP request URI is used to match against.
|
||||||
|
</para>
|
||||||
|
<para>The specified SIP request URI can be a regular
|
||||||
|
expression if the value is of the form
|
||||||
|
/<replaceable>regex</replaceable>/.
|
||||||
|
</para>
|
||||||
|
<note><para>Use of a regex is expensive so be sure you need
|
||||||
|
to use a regex to match your endpoint.
|
||||||
|
</para></note>
|
||||||
|
</description>
|
||||||
|
</configOption>
|
||||||
<configOption name="type">
|
<configOption name="type">
|
||||||
<synopsis>Must be of type 'identify'.</synopsis>
|
<synopsis>Must be of type 'identify'.</synopsis>
|
||||||
</configOption>
|
</configOption>
|
||||||
@@ -129,6 +143,8 @@ struct ip_identify_match {
|
|||||||
AST_DECLARE_STRING_FIELDS(
|
AST_DECLARE_STRING_FIELDS(
|
||||||
/*! The name of the endpoint */
|
/*! The name of the endpoint */
|
||||||
AST_STRING_FIELD(endpoint_name);
|
AST_STRING_FIELD(endpoint_name);
|
||||||
|
/*! If matching by request, the value to match against */
|
||||||
|
AST_STRING_FIELD(match_request_uri);
|
||||||
/*! If matching by header, the header/value to match against */
|
/*! If matching by header, the header/value to match against */
|
||||||
AST_STRING_FIELD(match_header);
|
AST_STRING_FIELD(match_header);
|
||||||
/*! SIP header name of the match_header string */
|
/*! SIP header name of the match_header string */
|
||||||
@@ -136,16 +152,20 @@ struct ip_identify_match {
|
|||||||
/*! SIP header value of the match_header string */
|
/*! SIP header value of the match_header string */
|
||||||
AST_STRING_FIELD(match_header_value);
|
AST_STRING_FIELD(match_header_value);
|
||||||
);
|
);
|
||||||
/*! Compiled match_header regular expression when is_regex is non-zero */
|
/*! Compiled match_header regular expression when is_header_regex is non-zero */
|
||||||
regex_t regex_buf;
|
regex_t regex_header_buf;
|
||||||
|
/*! Compiled match_request_uri regular expression when is_request_uri_regex is non-zero */
|
||||||
|
regex_t regex_request_uri_buf;
|
||||||
/*! \brief Networks or addresses that should match this */
|
/*! \brief Networks or addresses that should match this */
|
||||||
struct ast_ha *matches;
|
struct ast_ha *matches;
|
||||||
/*! \brief Hosts to be resolved when applying configuration */
|
/*! \brief Hosts to be resolved when applying configuration */
|
||||||
struct ao2_container *hosts;
|
struct ao2_container *hosts;
|
||||||
/*! \brief Perform SRV resolution of hostnames */
|
/*! \brief Perform SRV resolution of hostnames */
|
||||||
unsigned int srv_lookups;
|
unsigned int srv_lookups;
|
||||||
/*! Non-zero if match_header has a regular expression (i.e., regex_buf is valid) */
|
/*! Non-zero if match_header has a regular expression (i.e., regex_header_buf is valid) */
|
||||||
unsigned int is_regex:1;
|
unsigned int is_header_regex:1;
|
||||||
|
/*! Non-zero if match_header or match_request has a regular expression (i.e., regex_request_uri_buf is valid) */
|
||||||
|
unsigned int is_request_uri_regex:1;
|
||||||
};
|
};
|
||||||
|
|
||||||
/*! \brief Destructor function for a matching object */
|
/*! \brief Destructor function for a matching object */
|
||||||
@@ -156,8 +176,11 @@ static void ip_identify_destroy(void *obj)
|
|||||||
ast_string_field_free_memory(identify);
|
ast_string_field_free_memory(identify);
|
||||||
ast_free_ha(identify->matches);
|
ast_free_ha(identify->matches);
|
||||||
ao2_cleanup(identify->hosts);
|
ao2_cleanup(identify->hosts);
|
||||||
if (identify->is_regex) {
|
if (identify->is_header_regex) {
|
||||||
regfree(&identify->regex_buf);
|
regfree(&identify->regex_header_buf);
|
||||||
|
}
|
||||||
|
if (identify->is_request_uri_regex) {
|
||||||
|
regfree(&identify->regex_request_uri_buf);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -219,8 +242,8 @@ static int header_identify_match_check(void *obj, void *arg, int flags)
|
|||||||
pos = ast_strip(pos + 1);
|
pos = ast_strip(pos + 1);
|
||||||
|
|
||||||
/* Does header value match what we are looking for? */
|
/* Does header value match what we are looking for? */
|
||||||
if (identify->is_regex) {
|
if (identify->is_header_regex) {
|
||||||
if (!regexec(&identify->regex_buf, pos, 0, NULL, 0)) {
|
if (!regexec(&identify->regex_header_buf, pos, 0, NULL, 0)) {
|
||||||
return CMP_MATCH;
|
return CMP_MATCH;
|
||||||
}
|
}
|
||||||
} else if (!strcmp(identify->match_header_value, pos)) {
|
} else if (!strcmp(identify->match_header_value, pos)) {
|
||||||
@@ -241,6 +264,41 @@ static int header_identify_match_check(void *obj, void *arg, int flags)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*! \brief Comparator function for matching an object by request URI */
|
||||||
|
static int request_identify_match_check(void *obj, void *arg, int flags)
|
||||||
|
{
|
||||||
|
struct ip_identify_match *identify = obj;
|
||||||
|
struct pjsip_rx_data *rdata = arg;
|
||||||
|
int len;
|
||||||
|
char buf[PJSIP_MAX_URL_SIZE];
|
||||||
|
|
||||||
|
if (ast_strlen_zero(identify->match_request_uri)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Print request URI to req_buf */
|
||||||
|
len = pjsip_uri_print(PJSIP_URI_IN_REQ_URI, rdata->msg_info.msg->line.req.uri, buf, sizeof(buf) - 1);
|
||||||
|
if (len < 0) {
|
||||||
|
/* Buffer not large enough or no pj uri vptr! */
|
||||||
|
ast_assert(0);
|
||||||
|
} else {
|
||||||
|
/* Terminate the pj_str */
|
||||||
|
buf[len] = '\0';
|
||||||
|
/* Does request URI match what we are looking for? */
|
||||||
|
if (identify->is_request_uri_regex) {
|
||||||
|
if (!regexec(&identify->regex_request_uri_buf, buf, 0, NULL, 0)) {
|
||||||
|
return CMP_MATCH;
|
||||||
|
}
|
||||||
|
} else if (!strcmp(identify->match_request_uri, buf)) {
|
||||||
|
return CMP_MATCH;
|
||||||
|
}
|
||||||
|
ast_debug(3, "Identify '%s': request URI not match '%s' (value='%s').\n",
|
||||||
|
ast_sorcery_object_get_id(identify), identify->match_request_uri, buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/*! \brief Comparator function for matching an object by IP address */
|
/*! \brief Comparator function for matching an object by IP address */
|
||||||
static int ip_identify_match_check(void *obj, void *arg, int flags)
|
static int ip_identify_match_check(void *obj, void *arg, int flags)
|
||||||
{
|
{
|
||||||
@@ -314,10 +372,19 @@ static struct ast_sip_endpoint *header_identify(pjsip_rx_data *rdata)
|
|||||||
return common_identify(header_identify_match_check, rdata);
|
return common_identify(header_identify_match_check, rdata);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static struct ast_sip_endpoint *request_identify(pjsip_rx_data *rdata)
|
||||||
|
{
|
||||||
|
return common_identify(request_identify_match_check, rdata);
|
||||||
|
}
|
||||||
|
|
||||||
static struct ast_sip_endpoint_identifier header_identifier = {
|
static struct ast_sip_endpoint_identifier header_identifier = {
|
||||||
.identify_endpoint = header_identify,
|
.identify_endpoint = header_identify,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static struct ast_sip_endpoint_identifier request_identifier = {
|
||||||
|
.identify_endpoint = request_identify,
|
||||||
|
};
|
||||||
|
|
||||||
/*! \brief Helper function which performs a host lookup and adds result to identify match */
|
/*! \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)
|
static int ip_identify_match_host_lookup(struct ip_identify_match *identify, const char *host)
|
||||||
{
|
{
|
||||||
@@ -453,6 +520,7 @@ static int ip_identify_apply(const struct ast_sorcery *sorcery, void *obj)
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
if (ast_strlen_zero(identify->match_header) /* No header to match */
|
if (ast_strlen_zero(identify->match_header) /* No header to match */
|
||||||
|
&& ast_strlen_zero(identify->match_request_uri) /* and no request to match */
|
||||||
/* and no static IP addresses with a mask */
|
/* and no static IP addresses with a mask */
|
||||||
&& !identify->matches
|
&& !identify->matches
|
||||||
/* and no addresses to resolve */
|
/* and no addresses to resolve */
|
||||||
@@ -501,12 +569,38 @@ static int ip_identify_apply(const struct ast_sorcery *sorcery, void *obj)
|
|||||||
c_value[len - 1] = '\0';
|
c_value[len - 1] = '\0';
|
||||||
++c_value;
|
++c_value;
|
||||||
|
|
||||||
if (regcomp(&identify->regex_buf, c_value, REG_EXTENDED | REG_NOSUB)) {
|
if (regcomp(&identify->regex_header_buf, c_value, REG_EXTENDED | REG_NOSUB)) {
|
||||||
ast_log(LOG_ERROR, "Identify '%s' failed to compile match_header regex '%s'.\n",
|
ast_log(LOG_ERROR, "Identify '%s' failed to compile match_request_uri regex '%s'.\n",
|
||||||
ast_sorcery_object_get_id(identify), c_value);
|
ast_sorcery_object_get_id(identify), c_value);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
identify->is_regex = 1;
|
identify->is_header_regex = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!ast_strlen_zero(identify->match_request_uri)) {
|
||||||
|
char *c_string;
|
||||||
|
int len;
|
||||||
|
|
||||||
|
len = strlen(identify->match_request_uri);
|
||||||
|
c_string = ast_strdupa(identify->match_request_uri);
|
||||||
|
|
||||||
|
if (!strcmp(c_string, "//")) {
|
||||||
|
/* An empty regex is the same as an empty literal string. */
|
||||||
|
c_string = "";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (2 < len && c_string[0] == '/' && c_string[len - 1] == '/') {
|
||||||
|
/* Make "/regex/" into "regex" */
|
||||||
|
c_string[len - 1] = '\0';
|
||||||
|
++c_string;
|
||||||
|
|
||||||
|
if (regcomp(&identify->regex_request_uri_buf, c_string, REG_EXTENDED | REG_NOSUB)) {
|
||||||
|
ast_log(LOG_ERROR, "Identify '%s' failed to compile match_header regex '%s'.\n",
|
||||||
|
ast_sorcery_object_get_id(identify), c_string);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
identify->is_request_uri_regex = 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -788,10 +882,17 @@ static int cli_print_body(void *obj, void *arg, int flags)
|
|||||||
if (!ast_strlen_zero(ident->match_header)) {
|
if (!ast_strlen_zero(ident->match_header)) {
|
||||||
ast_str_append(&context->output_buffer, 0, "%*s: %s\n",
|
ast_str_append(&context->output_buffer, 0, "%*s: %s\n",
|
||||||
indent,
|
indent,
|
||||||
"Match",
|
"Header",
|
||||||
ident->match_header);
|
ident->match_header);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!ast_strlen_zero(ident->match_request_uri)) {
|
||||||
|
ast_str_append(&context->output_buffer, 0, "%*s: %s\n",
|
||||||
|
indent,
|
||||||
|
"RequestURI",
|
||||||
|
ident->match_request_uri);
|
||||||
|
}
|
||||||
|
|
||||||
context->indent_level--;
|
context->indent_level--;
|
||||||
|
|
||||||
if (context->indent_level == 0) {
|
if (context->indent_level == 0) {
|
||||||
@@ -851,11 +952,13 @@ static int load_module(void)
|
|||||||
ast_sorcery_object_field_register(ast_sip_get_sorcery(), "identify", "endpoint", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ip_identify_match, endpoint_name));
|
ast_sorcery_object_field_register(ast_sip_get_sorcery(), "identify", "endpoint", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ip_identify_match, endpoint_name));
|
||||||
ast_sorcery_object_field_register_custom(ast_sip_get_sorcery(), "identify", "match", "", ip_identify_match_handler, match_to_str, match_to_var_list, 0, 0);
|
ast_sorcery_object_field_register_custom(ast_sip_get_sorcery(), "identify", "match", "", ip_identify_match_handler, match_to_str, match_to_var_list, 0, 0);
|
||||||
ast_sorcery_object_field_register(ast_sip_get_sorcery(), "identify", "match_header", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ip_identify_match, match_header));
|
ast_sorcery_object_field_register(ast_sip_get_sorcery(), "identify", "match_header", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ip_identify_match, match_header));
|
||||||
|
ast_sorcery_object_field_register(ast_sip_get_sorcery(), "identify", "match_request_uri", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ip_identify_match, match_request_uri));
|
||||||
ast_sorcery_object_field_register(ast_sip_get_sorcery(), "identify", "srv_lookups", "yes", OPT_BOOL_T, 1, FLDSET(struct ip_identify_match, srv_lookups));
|
ast_sorcery_object_field_register(ast_sip_get_sorcery(), "identify", "srv_lookups", "yes", OPT_BOOL_T, 1, FLDSET(struct ip_identify_match, srv_lookups));
|
||||||
ast_sorcery_load_object(ast_sip_get_sorcery(), "identify");
|
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(&ip_identifier, "ip");
|
||||||
ast_sip_register_endpoint_identifier_with_name(&header_identifier, "header");
|
ast_sip_register_endpoint_identifier_with_name(&header_identifier, "header");
|
||||||
|
ast_sip_register_endpoint_identifier_with_name(&request_identifier, "request_uri");
|
||||||
ast_sip_register_endpoint_formatter(&endpoint_identify_formatter);
|
ast_sip_register_endpoint_formatter(&endpoint_identify_formatter);
|
||||||
|
|
||||||
cli_formatter = ao2_alloc(sizeof(struct ast_sip_cli_formatter_entry), NULL);
|
cli_formatter = ao2_alloc(sizeof(struct ast_sip_cli_formatter_entry), NULL);
|
||||||
@@ -890,6 +993,7 @@ static int unload_module(void)
|
|||||||
ast_sip_unregister_cli_formatter(cli_formatter);
|
ast_sip_unregister_cli_formatter(cli_formatter);
|
||||||
ast_sip_unregister_endpoint_formatter(&endpoint_identify_formatter);
|
ast_sip_unregister_endpoint_formatter(&endpoint_identify_formatter);
|
||||||
ast_sip_unregister_endpoint_identifier(&header_identifier);
|
ast_sip_unregister_endpoint_identifier(&header_identifier);
|
||||||
|
ast_sip_unregister_endpoint_identifier(&request_identifier);
|
||||||
ast_sip_unregister_endpoint_identifier(&ip_identifier);
|
ast_sip_unregister_endpoint_identifier(&ip_identifier);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
Reference in New Issue
Block a user