summaryrefslogtreecommitdiff
path: root/res/res_pjsip_endpoint_identifier_ip.c
diff options
context:
space:
mode:
authorJoshua Colp <jcolp@digium.com>2017-01-05 12:11:43 +0000
committerJoshua Colp <jcolp@digium.com>2017-01-06 09:00:22 -0600
commita7d856cd96eb1e1f02fcde6b3e6bef35e1715bd5 (patch)
tree9991d4d01fef6097451ef959793f3b2eb1e7f1ea /res/res_pjsip_endpoint_identifier_ip.c
parent6962a13466c5e5b42e029f6d79da5262565317b3 (diff)
res_pjsip_endpoint_identifier_ip: Add support for SRV lookups.
This change implements SRV support for the IP based endpoint identifier module. All possible addresses through SRV are looked up and added as matches. If no SRV records are available a fallback to normal host resolution is done. If an IP address is provided then no SRV lookup occurs. This is configured using the "srv_lookups" option on the identify section and defaults to "yes". ASTERISK-26693 Change-Id: I6b641e275bf96629320efa8b479737062aed82ac
Diffstat (limited to 'res/res_pjsip_endpoint_identifier_ip.c')
-rw-r--r--res/res_pjsip_endpoint_identifier_ip.c116
1 files changed, 96 insertions, 20 deletions
diff --git a/res/res_pjsip_endpoint_identifier_ip.c b/res/res_pjsip_endpoint_identifier_ip.c
index 7a7af0b4e..e095a9630 100644
--- a/res/res_pjsip_endpoint_identifier_ip.c
+++ b/res/res_pjsip_endpoint_identifier_ip.c
@@ -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");