summaryrefslogtreecommitdiff
path: root/res
diff options
context:
space:
mode:
authorJoshua Colp <jcolp@digium.com>2017-01-09 12:47:51 -0600
committerGerrit Code Review <gerrit2@gerrit.digium.api>2017-01-09 12:47:52 -0600
commitac4d6828f5b99ff7de8e14bf33013725c029e248 (patch)
tree580d3a47c06facc4af39d3cee5a823652dad4a4a /res
parentd30bef1de915db70646c3359373244226cbd566a (diff)
parent37aaaa2da24ee7f3631a63b26c96fd3586cedbcb (diff)
Merge "res_pjsip_endpoint_identifier_ip: Add support for SRV lookups." into 13
Diffstat (limited to 'res')
-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 b1ffd2cc3..cf950ea18 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");