diff options
-rw-r--r-- | CHANGES | 7 | ||||
-rw-r--r-- | channels/chan_sip.c | 7 | ||||
-rw-r--r-- | configs/samples/http.conf.sample | 20 | ||||
-rw-r--r-- | configs/samples/rtp.conf.sample | 27 | ||||
-rw-r--r-- | include/asterisk/tcptls.h | 10 | ||||
-rw-r--r-- | main/http.c | 7 | ||||
-rw-r--r-- | main/tcptls.c | 30 | ||||
-rw-r--r-- | main/udptl.c | 15 | ||||
-rw-r--r-- | res/res_rtp_asterisk.c | 81 | ||||
-rw-r--r-- | res/res_stasis_device_state.c | 10 | ||||
-rw-r--r-- | res/res_xmpp.c | 16 |
11 files changed, 207 insertions, 23 deletions
@@ -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; } |