summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CHANGES7
-rw-r--r--channels/chan_sip.c7
-rw-r--r--configs/samples/http.conf.sample20
-rw-r--r--configs/samples/rtp.conf.sample27
-rw-r--r--include/asterisk/tcptls.h10
-rw-r--r--main/http.c7
-rw-r--r--main/tcptls.c30
-rw-r--r--main/udptl.c15
-rw-r--r--res/res_rtp_asterisk.c81
-rw-r--r--res/res_stasis_device_state.c10
-rw-r--r--res/res_xmpp.c16
11 files changed, 207 insertions, 23 deletions
diff --git a/CHANGES b/CHANGES
index 925911189..4a5ae2cf3 100644
--- a/CHANGES
+++ b/CHANGES
@@ -69,6 +69,13 @@ res_pjsip_sdp_rtp
originate from the media address instead of the operating system's "primary"
ip address.
+res_rtp_asterisk
+------------------
+ * A new configuration section - ice_host_candidates - has been added to
+ rtp.conf, allowing automatically discovered ICE host candidates to be
+ overriden. This allows an Asterisk server behind a 1:1 NAT to send its
+ external IP as a host candidate rather than relying on STUN to discover it.
+
------------------------------------------------------------------------------
--- Functionality changes from Asterisk 13.6.0 to Asterisk 13.7.0 ------------
------------------------------------------------------------------------------
diff --git a/channels/chan_sip.c b/channels/chan_sip.c
index 60ff451c1..cc4fa88bd 100644
--- a/channels/chan_sip.c
+++ b/channels/chan_sip.c
@@ -3965,6 +3965,13 @@ static int retrans_pkt(const void *data)
}
/* For non-invites, a maximum of 4 secs */
+ if (INT_MAX / pkt->timer_a < pkt->timer_t1) {
+ /*
+ * Uh Oh, we will have an integer overflow.
+ * Recalculate previous timeout time instead.
+ */
+ pkt->timer_a = pkt->timer_a / 2;
+ }
siptimer_a = pkt->timer_t1 * pkt->timer_a; /* Double each time */
if (pkt->method != SIP_INVITE && siptimer_a > 4000) {
siptimer_a = 4000;
diff --git a/configs/samples/http.conf.sample b/configs/samples/http.conf.sample
index 1d23a67f6..342dff483 100644
--- a/configs/samples/http.conf.sample
+++ b/configs/samples/http.conf.sample
@@ -90,6 +90,26 @@ bindaddr=127.0.0.1
; private in same .pem file.
; openssl req -new -x509 -days 365 -nodes -out /tmp/foo.pem -keyout /tmp/foo.pem
;
+; tlscipher= ; The list of allowed ciphers
+; ; if none are specified the following cipher
+; ; list will be used instead:
+; ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:
+; ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:
+; kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:
+; ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:
+; ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:
+; DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:
+; AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:
+; AES:CAMELLIA:DES-CBC3-SHA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!aECDH:
+; !EDH-DSS-DES-CBC3-SHA:!EDH-RSA-DES-CBC3-SHA:!KRB5-DES-CBC3-SHA
+;
+; tlsdisablev1=yes ; Disable TLSv1 support - if not set this defaults to "yes"
+; tlsdisablev11=yes ; Disable TLSv1.1 support - if not set this defaults to "no"
+; tlsdisablev12=yes ; Disable TLSv1.2 support - if not set this defaults to "no"
+;
+; tlsservercipherorder=yes ; Use the server preference order instead of the client order
+; ; Defaults to "yes"
+;
; The post_mappings section maps URLs to real paths on the filesystem. If a
; POST is done from within an authenticated manager session to one of the
; configured POST mappings, then any files in the POST will be placed in the
diff --git a/configs/samples/rtp.conf.sample b/configs/samples/rtp.conf.sample
index c22acaa9f..2ef5dd28a 100644
--- a/configs/samples/rtp.conf.sample
+++ b/configs/samples/rtp.conf.sample
@@ -58,3 +58,30 @@ rtpend=20000
;
; Password used to authenticate with TURN relay server.
; turnpassword=
+;
+[ice_host_candidates]
+;
+; When Asterisk is behind a static one-to-one 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.
+;
+; IMPORTANT: Only use this functionality when your Asterisk server is behind a
+; one-to-one NAT and you know what you're doing. If you do define anything
+; here, you almost certainly will NOT want to specify 'stunaddr' or 'turnaddr'
+; above.
+;
+; The format for these overrides is:
+;
+; <local address> => <advertised address>
+;
+; The following will replace 192.168.1.10 with 1.2.3.4 during ICE
+; negotiation:
+;
+;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/include/asterisk/tcptls.h b/include/asterisk/tcptls.h
index 0e8d9d042..e1a632cca 100644
--- a/include/asterisk/tcptls.h
+++ b/include/asterisk/tcptls.h
@@ -86,7 +86,15 @@ enum ast_ssl_flags {
/*! Use SSLv3 for outgoing client connections */
AST_SSL_SSLV3_CLIENT = (1 << 4),
/*! Use TLSv1 for outgoing client connections */
- AST_SSL_TLSV1_CLIENT = (1 << 5)
+ AST_SSL_TLSV1_CLIENT = (1 << 5),
+ /*! Use server cipher order instead of the client order */
+ AST_SSL_SERVER_CIPHER_ORDER = (1 << 6),
+ /*! Disable TLSv1 support */
+ AST_SSL_DISABLE_TLSV1 = (1 << 7),
+ /*! Disable TLSv1.1 support */
+ AST_SSL_DISABLE_TLSV11 = (1 << 8),
+ /*! Disable TLSv1.2 support */
+ AST_SSL_DISABLE_TLSV12 = (1 << 9),
};
struct ast_tls_config {
diff --git a/main/http.c b/main/http.c
index 26e218ba0..c343cb236 100644
--- a/main/http.c
+++ b/main/http.c
@@ -2102,10 +2102,13 @@ static int __ast_http_load(int reload)
}
http_tls_cfg.pvtfile = ast_strdup("");
+ /* Apply modern intermediate settings according to the Mozilla OpSec team as of July 30th, 2015 but disable TLSv1 */
+ ast_set_flag(&http_tls_cfg.flags, AST_SSL_DISABLE_TLSV1 | AST_SSL_SERVER_CIPHER_ORDER);
+
if (http_tls_cfg.cipher) {
ast_free(http_tls_cfg.cipher);
}
- http_tls_cfg.cipher = ast_strdup("");
+ http_tls_cfg.cipher = ast_strdup("ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:AES:CAMELLIA:DES-CBC3-SHA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!aECDH:!EDH-DSS-DES-CBC3-SHA:!EDH-RSA-DES-CBC3-SHA:!KRB5-DES-CBC3-SHA");
AST_RWLIST_WRLOCK(&uri_redirects);
while ((redirect = AST_RWLIST_REMOVE_HEAD(&uri_redirects, entry))) {
@@ -2131,8 +2134,6 @@ static int __ast_http_load(int reload)
&& strcasecmp(v->name, "tlsdontverifyserver")
&& strcasecmp(v->name, "tlsclientmethod")
&& strcasecmp(v->name, "sslclientmethod")
- && strcasecmp(v->name, "tlscipher")
- && strcasecmp(v->name, "sslcipher")
&& !ast_tls_read_conf(&http_tls_cfg, &https_desc, v->name, v->value)) {
continue;
}
diff --git a/main/tcptls.c b/main/tcptls.c
index 1b0c26ad2..6f37724d9 100644
--- a/main/tcptls.c
+++ b/main/tcptls.c
@@ -759,7 +759,8 @@ static int __ssl_setup(struct ast_tls_config *cfg, int client)
return 0;
#else
int disable_ssl = 0;
-
+ long ssl_opts = 0;
+
if (!cfg->enabled) {
return 0;
}
@@ -807,11 +808,24 @@ static int __ssl_setup(struct ast_tls_config *cfg, int client)
* them. SSLv23_*_method supports TLSv1+.
*/
if (disable_ssl) {
- long ssl_opts;
+ ssl_opts |= SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3;
+ }
+
+ if (ast_test_flag(&cfg->flags, AST_SSL_SERVER_CIPHER_ORDER)) {
+ ssl_opts |= SSL_OP_CIPHER_SERVER_PREFERENCE;
+ }
- ssl_opts = SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3;
- SSL_CTX_set_options(cfg->ssl_ctx, ssl_opts);
+ if (ast_test_flag(&cfg->flags, AST_SSL_DISABLE_TLSV1)) {
+ ssl_opts |= SSL_OP_NO_TLSv1;
}
+ if (ast_test_flag(&cfg->flags, AST_SSL_DISABLE_TLSV11)) {
+ ssl_opts |= SSL_OP_NO_TLSv1_1;
+ }
+ if (ast_test_flag(&cfg->flags, AST_SSL_DISABLE_TLSV12)) {
+ ssl_opts |= SSL_OP_NO_TLSv1_2;
+ }
+
+ SSL_CTX_set_options(cfg->ssl_ctx, ssl_opts);
SSL_CTX_set_verify(cfg->ssl_ctx,
ast_test_flag(&cfg->flags, AST_SSL_VERIFY_CLIENT) ? SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT : SSL_VERIFY_NONE,
@@ -1164,6 +1178,14 @@ int ast_tls_read_conf(struct ast_tls_config *tls_cfg, struct ast_tcptls_session_
ast_clear_flag(&tls_cfg->flags, AST_SSL_TLSV1_CLIENT);
ast_clear_flag(&tls_cfg->flags, AST_SSL_SSLV3_CLIENT);
}
+ } else if (!strcasecmp(varname, "tlsservercipherorder")) {
+ ast_set2_flag(&tls_cfg->flags, ast_true(value), AST_SSL_SERVER_CIPHER_ORDER);
+ } else if (!strcasecmp(varname, "tlsdisablev1")) {
+ ast_set2_flag(&tls_cfg->flags, ast_true(value), AST_SSL_DISABLE_TLSV1);
+ } else if (!strcasecmp(varname, "tlsdisablev11")) {
+ ast_set2_flag(&tls_cfg->flags, ast_true(value), AST_SSL_DISABLE_TLSV11);
+ } else if (!strcasecmp(varname, "tlsdisablev12")) {
+ ast_set2_flag(&tls_cfg->flags, ast_true(value), AST_SSL_DISABLE_TLSV12);
} else {
return -1;
}
diff --git a/main/udptl.c b/main/udptl.c
index 4e878195c..e8410cc8b 100644
--- a/main/udptl.c
+++ b/main/udptl.c
@@ -305,16 +305,15 @@ static int decode_open_type(uint8_t *buf, unsigned int limit, unsigned int *len,
if (decode_length(buf, limit, len, &octet_cnt) != 0)
return -1;
- if (octet_cnt > 0) {
- /* Make sure the buffer contains at least the number of bits requested */
- if ((*len + octet_cnt) > limit)
- return -1;
-
- *p_num_octets = octet_cnt;
- *p_object = &buf[*len];
- *len += octet_cnt;
+ /* Make sure the buffer contains at least the number of bits requested */
+ if ((*len + octet_cnt) > limit) {
+ return -1;
}
+ *p_num_octets = octet_cnt;
+ *p_object = &buf[*len];
+ *len += octet_cnt;
+
return 0;
}
/*- End of function --------------------------------------------------------*/
diff --git a/res/res_rtp_asterisk.c b/res/res_rtp_asterisk.c
index f6bf34211..611920e80 100644
--- a/res/res_rtp_asterisk.c
+++ b/res/res_rtp_asterisk.c
@@ -182,6 +182,16 @@ struct ast_rtp_ioqueue_thread {
/*! \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 void dtls_srtp_stop_timeout_timer(struct ast_rtp_instance *instance, stru
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)
@@ -2368,6 +2410,8 @@ static void rtp_add_candidates_to_ice(struct ast_rtp_instance *instance, struct
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);
ast_rtp_ice_add_cand(rtp, component, transport, PJ_ICE_CAND_TYPE_HOST, 65535, &address[pos], &address[pos], NULL,
@@ -5257,6 +5301,11 @@ static int rtp_reload(int reload)
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 @@ static int rtp_reload(int reload)
turnaddr = pj_str(NULL);
turnusername = pj_str(NULL);
turnpassword = pj_str(NULL);
+ host_candidate_overrides_clear();
#endif
if (cfg) {
@@ -5362,6 +5412,36 @@ static int rtp_reload(int reload)
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) {
+ struct ast_sockaddr local_addr, advertised_addr;
+ pj_str_t address;
+
+ ast_sockaddr_setnull(&local_addr);
+ ast_sockaddr_setnull(&advertised_addr);
+
+ if (ast_parse_arg(var->name, PARSE_ADDR | PARSE_PORT_IGNORE, &local_addr)) {
+ ast_log(LOG_WARNING, "Invalid local ICE host address: %s\n", var->name);
+ 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;
+ }
+
+ if (!(candidate = ast_calloc(1, sizeof(*candidate)))) {
+ ast_log(LOG_ERROR, "Failed to allocate ICE host candidate mapping.\n");
+ break;
+ }
+
+ 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 +5544,7 @@ static int unload_module(void)
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
diff --git a/res/res_stasis_device_state.c b/res/res_stasis_device_state.c
index c0b6859ca..be082dcc8 100644
--- a/res/res_stasis_device_state.c
+++ b/res/res_stasis_device_state.c
@@ -303,6 +303,12 @@ static void device_state_cb(void *data, struct stasis_subscription *sub,
{
struct ast_device_state_message *device_state;
+ if (stasis_subscription_final_message(sub, msg)) {
+ /* Remove stasis subscription's reference to device_state_subscription */
+ ao2_ref(data, -1);
+ return;
+ }
+
if (ast_device_state_message_type() != stasis_message_type(msg)) {
return;
}
@@ -365,10 +371,12 @@ static int subscribe_device_state(struct stasis_app *app, void *obj)
ast_debug(3, "Subscribing to device %s\n", sub->device_name);
- sub->sub = stasis_subscribe_pool(topic, device_state_cb, sub);
+ sub->sub = stasis_subscribe_pool(topic, device_state_cb, ao2_bump(sub));
if (!sub->sub) {
ast_log(LOG_ERROR, "Unable to subscribe to device %s\n",
sub->device_name);
+ /* Reference we added when attempting to stasis_subscribe_pool */
+ ao2_ref(sub, -1);
return -1;
}
diff --git a/res/res_xmpp.c b/res/res_xmpp.c
index d9791431d..ed35cd169 100644
--- a/res/res_xmpp.c
+++ b/res/res_xmpp.c
@@ -3130,6 +3130,10 @@ done:
/*! \brief Internal function called when we authenticated as a component */
static int xmpp_component_authenticating(struct ast_xmpp_client *client, struct ast_xmpp_client_config *cfg, int type, iks *node)
{
+ if (!strcmp(iks_name(node), "stream:features")) {
+ return 0;
+ }
+
if (strcmp(iks_name(node), "handshake")) {
ast_log(LOG_ERROR, "Failed to authenticate component '%s'\n", client->name);
return -1;
@@ -3305,6 +3309,11 @@ static int xmpp_pak_presence(struct ast_xmpp_client *client, struct ast_xmpp_cli
int status = pak->show ? pak->show : STATUS_DISAPPEAR;
enum ast_device_state state = AST_DEVICE_UNAVAILABLE;
+ /* If this is a component presence probe request answer immediately with our presence status */
+ if (ast_test_flag(&cfg->flags, XMPP_COMPONENT) && !ast_strlen_zero(type) && !strcasecmp(type, "probe")) {
+ xmpp_client_set_presence(client, pak->from->full, iks_find_attrib(pak->x, "to"), cfg->status, cfg->statusmsg);
+ }
+
/* If no resource is available this is a general buddy presence update, which we will ignore */
if (!pak->from->resource) {
return 0;
@@ -3319,11 +3328,6 @@ static int xmpp_pak_presence(struct ast_xmpp_client *client, struct ast_xmpp_cli
return 0;
}
- /* If this is a component presence probe request answer immediately with our presence status */
- if (ast_test_flag(&cfg->flags, XMPP_COMPONENT) && !ast_strlen_zero(type) && !strcasecmp(type, "probe")) {
- xmpp_client_set_presence(client, pak->from->full, iks_find_attrib(pak->x, "to"), cfg->status, cfg->statusmsg);
- }
-
ao2_lock(buddy->resources);
if (!(resource = ao2_callback(buddy->resources, OBJ_NOLOCK, xmpp_resource_cmp, pak->from->resource))) {
@@ -3864,7 +3868,7 @@ static int xmpp_client_config_post_apply(void *obj, void *arg, int flags)
cfg->client->jid = iks_id_new(cfg->client->stack, cfg->user);
}
- if (!cfg->client->jid || ast_strlen_zero(cfg->client->jid->user)) {
+ if (!cfg->client->jid || (ast_strlen_zero(cfg->client->jid->user) && !ast_test_flag(&cfg->flags, XMPP_COMPONENT))) {
ast_log(LOG_ERROR, "Jabber identity '%s' could not be created for client '%s' - client not active\n", cfg->user, cfg->name);
return -1;
}