[Asterisk-code-review] res rtp asterisk: Allow ICE host candidates to be overriden. (asterisk[13])

Sean Bright asteriskteam at digium.com
Wed Jan 27 10:49:36 CST 2016


Sean Bright has uploaded a new change for review.

  https://gerrit.asterisk.org/2101

Change subject: res_rtp_asterisk: Allow ICE host candidates to be overriden.
......................................................................

res_rtp_asterisk: Allow ICE host candidates to be overriden.

During ICE negotiation the IPs of the local interfaces are sent to the remote
peer as host candidates. In many cases Asterisk is behind a static NAT, so
these host addresses will be internal IP addresses.

To help in hiding the topology of the internal network, this patch adds the
ability to override the host candidates be replacing matching them against
a user-defined list of replacements.

Change-Id: I1c9541af97b83a4c690c8150d19bf7202c8bff1f
---
M configs/samples/rtp.conf.sample
M res/res_rtp_asterisk.c
2 files changed, 105 insertions(+), 0 deletions(-)


  git pull ssh://gerrit.asterisk.org:29418/asterisk refs/changes/01/2101/1

diff --git a/configs/samples/rtp.conf.sample b/configs/samples/rtp.conf.sample
index c22acaa..43194c3 100644
--- a/configs/samples/rtp.conf.sample
+++ b/configs/samples/rtp.conf.sample
@@ -58,3 +58,25 @@
 ;
 ; Password used to authenticate with TURN relay server.
 ; turnpassword=
+;
+[ice_host_candidates]
+;
+; When Asterisk is behind a static NAT and ICE is in use, ICE will expose the
+; server's internal IP address as one of the host candidates. Although using
+; STUN (see the 'stunaddr' configuration option) will provide a publicly
+; accessible IP, the internal IP will still be sent to the remote peer. To
+; help hide the topology of your internal network, you can override the host
+; candidates that Asterisk will send to the remote peer.
+;
+; The format for these overrides is:
+;
+;    interface <local address> => <advertised address>
+;
+; The following will replace 192.168.1.10 with 1.2.3.4 during ICE
+; negoitation:
+;
+;interface 192.168.1.10 => 1.2.3.4
+;
+; You can define an override for more than 1 interface if you have a multihomed
+; server. Any local interface that is not matched will be passed through
+; unaltered. Both IPv4 and IPv6 addresses are supported.
diff --git a/res/res_rtp_asterisk.c b/res/res_rtp_asterisk.c
index f6bf342..fb5085d 100644
--- a/res/res_rtp_asterisk.c
+++ b/res/res_rtp_asterisk.c
@@ -182,6 +182,16 @@
 /*! \brief List of ioqueue threads */
 static AST_LIST_HEAD_STATIC(ioqueues, ast_rtp_ioqueue_thread);
 
+/*! \brief Structure which contains ICE host candidate mapping information */
+struct ast_ice_host_candidate {
+	pj_sockaddr local;
+	pj_sockaddr advertised;
+	AST_RWLIST_ENTRY(ast_ice_host_candidate) next;
+};
+
+/*! \brief List of ICE host candidate mappings */
+static AST_RWLIST_HEAD_STATIC(host_candidates, ast_ice_host_candidate);
+
 #endif
 
 #define FLAG_3389_WARNING               (1 << 0)
@@ -451,6 +461,38 @@
 static int __rtp_sendto(struct ast_rtp_instance *instance, void *buf, size_t size, int flags, struct ast_sockaddr *sa, int rtcp, int *ice, int use_srtp);
 
 #ifdef HAVE_PJPROJECT
+/*! \brief Helper function which clears the ICE host candidate mapping */
+static void host_candidate_overrides_clear(void)
+{
+	struct ast_ice_host_candidate *candidate;
+
+	AST_RWLIST_WRLOCK(&host_candidates);
+	AST_RWLIST_TRAVERSE_SAFE_BEGIN(&host_candidates, candidate, next) {
+		AST_RWLIST_REMOVE_CURRENT(next);
+		ast_free(candidate);
+	}
+	AST_RWLIST_TRAVERSE_SAFE_END;
+	AST_RWLIST_UNLOCK(&host_candidates);
+}
+
+/*! \brief Applies the ICE host candidate mapping */
+static void host_candidate_overrides_apply(unsigned int count, pj_sockaddr addrs[])
+{
+	int pos;
+	struct ast_ice_host_candidate *candidate;
+
+	AST_RWLIST_RDLOCK(&host_candidates);
+	for (pos = 0; pos < count; pos++) {
+		AST_LIST_TRAVERSE(&host_candidates, candidate, next) {
+			if (!pj_sockaddr_cmp(&candidate->local, &addrs[pos])) {
+				pj_sockaddr_copy_addr(&addrs[pos], &candidate->advertised);
+				break;
+			}
+		}
+	}
+	AST_RWLIST_UNLOCK(&host_candidates);
+}
+
 /*! \brief Helper function which updates an ast_sockaddr with the candidate used for the component */
 static void update_address_with_ice_candidate(struct ast_rtp *rtp, enum ast_rtp_ice_component_type component,
 	struct ast_sockaddr *cand_address)
@@ -2367,6 +2409,8 @@
 	} else {
 		pj_enum_ip_interface(pj_AF_INET6(), &count, address);
 	}
+
+	host_candidate_overrides_apply(count, address);
 
 	for (pos = 0; pos < count; pos++) {
 		pj_sockaddr_set_port(&address[pos], port);
@@ -5257,6 +5301,11 @@
 	const char *s;
 	struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
 
+#ifdef HAVE_PJPROJECT
+	struct ast_variable *var;
+	struct ast_ice_host_candidate *candidate;
+#endif
+
 	cfg = ast_config_load2("rtp.conf", "rtp", config_flags);
 	if (cfg == CONFIG_STATUS_FILEMISSING || cfg == CONFIG_STATUS_FILEUNCHANGED || cfg == CONFIG_STATUS_FILEINVALID) {
 		return 0;
@@ -5283,6 +5332,7 @@
 	turnaddr = pj_str(NULL);
 	turnusername = pj_str(NULL);
 	turnpassword = pj_str(NULL);
+	host_candidate_overrides_clear();
 #endif
 
 	if (cfg) {
@@ -5362,6 +5412,38 @@
 		if ((s = ast_variable_retrieve(cfg, "general", "turnpassword"))) {
 			pj_strdup2_with_null(pool, &turnpassword, s);
 		}
+
+		AST_RWLIST_WRLOCK(&host_candidates);
+		for (var = ast_variable_browse(cfg, "ice_host_candidates"); var; var = var->next) {
+			if (!strncmp(var->name, "interface", sizeof("interface") - 1)) {
+				struct ast_sockaddr local_addr, advertised_addr;
+				char *local, *stripped;
+				pj_str_t address;
+
+				local = ast_strdupa(var->name + sizeof("interface") - 1);
+				stripped = ast_strip(local);
+
+				ast_sockaddr_setnull(&local_addr);
+				ast_sockaddr_setnull(&advertised_addr);
+
+				if (ast_parse_arg(stripped, PARSE_ADDR | PARSE_PORT_IGNORE, &local_addr)) {
+					ast_log(LOG_WARNING, "Invalid local ICE host address: %s\n", stripped);
+					continue;
+				}
+
+				if (ast_parse_arg(var->value, PARSE_ADDR | PARSE_PORT_IGNORE, &advertised_addr)) {
+					ast_log(LOG_WARNING, "Invalid advertised ICE host address: %s\n", var->value);
+					continue;
+				}
+
+				candidate = ast_calloc(1, sizeof(*candidate));
+				pj_sockaddr_parse(pj_AF_UNSPEC(), 0, pj_cstr(&address, ast_sockaddr_stringify(&local_addr)), &candidate->local);
+				pj_sockaddr_parse(pj_AF_UNSPEC(), 0, pj_cstr(&address, ast_sockaddr_stringify(&advertised_addr)), &candidate->advertised);
+
+				AST_RWLIST_INSERT_TAIL(&host_candidates, candidate, next);
+			}
+		}
+		AST_RWLIST_UNLOCK(&host_candidates);
 #endif
 		ast_config_destroy(cfg);
 	}
@@ -5464,6 +5546,7 @@
 	ast_cli_unregister_multiple(cli_rtp, ARRAY_LEN(cli_rtp));
 
 #ifdef HAVE_PJPROJECT
+	host_candidate_overrides_clear();
 	pj_thread_register_check();
 	rtp_terminate_pjproject();
 #endif

-- 
To view, visit https://gerrit.asterisk.org/2101
To unsubscribe, visit https://gerrit.asterisk.org/settings

Gerrit-MessageType: newchange
Gerrit-Change-Id: I1c9541af97b83a4c690c8150d19bf7202c8bff1f
Gerrit-PatchSet: 1
Gerrit-Project: asterisk
Gerrit-Branch: 13
Gerrit-Owner: Sean Bright <sean.bright at gmail.com>



More information about the asterisk-code-review mailing list