Merge "res_pjsip_endpoint_identifier_ip: Add support for SRV lookups." into 14

changes/09/4709/1
zuul 8 years ago committed by Gerrit Code Review
commit b08037cd8f

@ -44,6 +44,12 @@ res_pjsip
ID, AuthenticateQualify, OutboundProxy, Path, QualifyFrequency and
QualifyTimeout. Existing fields have not been disturbed.
res_pjsip_endpoint_identifier_ip
------------------
* SRV lookups can now be done on provided hostnames to determine additional
source IP addresses for requests. This is configurable using the
"srv_lookups" option on the identify and defaults to "yes".
------------------------------------------------------------------------------
--- Functionality changes from Asterisk 14.1.0 to Asterisk 14.2.0 ------------
------------------------------------------------------------------------------

@ -0,0 +1,31 @@
"""add srv_lookups to identify
Revision ID: 28ab27a7826d
Revises: 4468b4a91372
Create Date: 2017-01-06 14:53:38.829655
"""
# revision identifiers, used by Alembic.
revision = '28ab27a7826d'
down_revision = '4468b4a91372'
from alembic import op
import sqlalchemy as sa
from sqlalchemy.dialects.postgresql import ENUM
YESNO_NAME = 'yesno_values'
YESNO_VALUES = ['yes', 'no']
def upgrade():
############################# Enums ##############################
# yesno_values have already been created, so use postgres enum object
# type to get around "already created" issue - works okay with mysql
yesno_values = ENUM(*YESNO_VALUES, name=YESNO_NAME, create_type=False)
op.add_column('ps_endpoint_id_ips', sa.Column('srv_lookups', yesno_values))
def downgrade():
op.drop_column('ps_endpoint_id_ips', 'srv_lookups')

@ -51,6 +51,13 @@
mask with a slash ('/')
</para></description>
</configOption>
<configOption name="srv_lookups" default="yes">
<synopsis>Perform SRV lookups for provided hostnames.</synopsis>
<description><para>When enabled, <replaceable>srv_lookups</replaceable> will
perform SRV lookups for _sip._udp, _sip._tcp, and _sips._tcp of the given
hostnames to determine additional addresses that traffic may originate from.
</para></description>
</configOption>
<configOption name="type">
<synopsis>Must be of type 'identify'.</synopsis>
</configOption>
@ -70,6 +77,8 @@ struct ip_identify_match {
);
/*! \brief Networks or addresses that should match this */
struct ast_ha *matches;
/*! \brief Perform SRV resolution of hostnames */
unsigned int srv_lookups;
};
/*! \brief Destructor function for a matching object */
@ -153,6 +162,72 @@ static struct ast_sip_endpoint_identifier ip_identifier = {
.identify_endpoint = ip_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)
{
struct ast_sockaddr *addrs;
int num_addrs = 0, error = 0, i;
int results = 0;
num_addrs = ast_sockaddr_resolve(&addrs, host, PARSE_PORT_FORBID, AST_AF_UNSPEC);
if (!num_addrs) {
return -1;
}
for (i = 0; i < num_addrs; ++i) {
/* Check if the address is already in the list, if so don't bother adding it again */
if (identify->matches && (ast_apply_ha(identify->matches, &addrs[i]) != AST_SENSE_ALLOW)) {
continue;
}
/* We deny what we actually want to match because there is an implicit permit all rule for ACLs */
identify->matches = ast_append_ha("d", ast_sockaddr_stringify_addr(&addrs[i]), identify->matches, &error);
if (!identify->matches || error) {
results = -1;
break;
}
results += 1;
}
ast_free(addrs);
return results;
}
/*! \brief Helper function which performs an SRV lookup and then resolves the hostname */
static int ip_identify_match_srv_lookup(struct ip_identify_match *identify, const char *prefix, const char *host)
{
char service[NI_MAXHOST];
struct srv_context *context = NULL;
int srv_ret;
const char *srvhost;
unsigned short srvport;
int results = 0;
snprintf(service, sizeof(service), "%s.%s", prefix, host);
while (!(srv_ret = ast_srv_lookup(&context, service, &srvhost, &srvport))) {
int hosts;
/* In the case of the SRV lookup we don't care if it fails, we will output a log message
* when we fallback to a normal lookup.
*/
hosts = ip_identify_match_host_lookup(identify, srvhost);
if (hosts == -1) {
results = -1;
break;
} else {
results += hosts;
}
}
ast_srv_cleanup(&context);
return results;
}
/*! \brief Custom handler for match field */
static int ip_identify_match_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
{
@ -165,9 +240,9 @@ static int ip_identify_match_handler(const struct aco_option *opt, struct ast_va
}
while ((current_string = ast_strip(strsep(&input_string, ",")))) {
struct ast_sockaddr *addrs;
int num_addrs = 0, error = 0, i;
char *mask = strrchr(current_string, '/');
struct ast_sockaddr address;
int error, results = 0;
if (ast_strlen_zero(current_string)) {
continue;
@ -185,28 +260,28 @@ static int ip_identify_match_handler(const struct aco_option *opt, struct ast_va
continue;
}
num_addrs = ast_sockaddr_resolve(&addrs, current_string, PARSE_PORT_FORBID, AST_AF_UNSPEC);
if (!num_addrs) {
ast_log(LOG_ERROR, "Address '%s' provided on ip endpoint identifier '%s' did not resolve to any address\n",
var->value, ast_sorcery_object_get_id(obj));
return -1;
}
for (i = 0; i < num_addrs; ++i) {
/* We deny what we actually want to match because there is an implicit permit all rule for ACLs */
identify->matches = ast_append_ha("d", ast_sockaddr_stringify_addr(&addrs[i]), identify->matches, &error);
if (!identify->matches || error) {
ast_log(LOG_ERROR, "Failed to add address '%s' to ip endpoint identifier '%s'\n",
ast_sockaddr_stringify_addr(&addrs[i]), ast_sorcery_object_get_id(obj));
error = -1;
break;
/* If the provided string is not an IP address perform SRV resolution on it */
if (identify->srv_lookups && !ast_sockaddr_parse(&address, current_string, 0)) {
results = ip_identify_match_srv_lookup(identify, "_sip._udp", current_string);
if (results != -1) {
results += ip_identify_match_srv_lookup(identify, "_sip._tcp", current_string);
}
if (results != -1) {
results += ip_identify_match_srv_lookup(identify, "_sips._tcp", current_string);
}
}
ast_free(addrs);
/* If SRV falls fall back to a normal lookup on the host itself */
if (!results) {
results = ip_identify_match_host_lookup(identify, current_string);
}
if (error) {
if (results == 0) {
ast_log(LOG_ERROR, "Address '%s' provided on ip endpoint identifier '%s' did not resolve to any address\n",
current_string, ast_sorcery_object_get_id(obj));
} else if (results == -1) {
ast_log(LOG_ERROR, "An error occurred when adding resolution results of '%s' on '%s'\n",
current_string, ast_sorcery_object_get_id(obj));
return -1;
}
}
@ -469,6 +544,7 @@ static int load_module(void)
ast_sorcery_object_field_register(ast_sip_get_sorcery(), "identify", "type", "", OPT_NOOP_T, 0, 0);
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(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_sip_register_endpoint_identifier_with_name(&ip_identifier, "ip");

Loading…
Cancel
Save