diff options
author | Dag-Erling Smørgrav <des@FreeBSD.org> | 2018-05-12 11:55:17 +0000 |
---|---|---|
committer | Dag-Erling Smørgrav <des@FreeBSD.org> | 2018-05-12 11:55:17 +0000 |
commit | a6c5280ea59f940be13fd6eb0f94ab8360d3d6c9 (patch) | |
tree | cbe088761a83cf2025bbdf36e1574f38c3e988f5 /daemon | |
parent | 8c2647a7dc721c8e5349bd194b8e8e178412057e (diff) |
Notes
Diffstat (limited to 'daemon')
-rw-r--r-- | daemon/daemon.c | 9 | ||||
-rw-r--r-- | daemon/remote.c | 85 | ||||
-rw-r--r-- | daemon/stats.c | 64 | ||||
-rw-r--r-- | daemon/unbound.c | 28 | ||||
-rw-r--r-- | daemon/worker.c | 20 |
5 files changed, 136 insertions, 70 deletions
diff --git a/daemon/daemon.c b/daemon/daemon.c index dad9f86b344e5..7411fabe75736 100644 --- a/daemon/daemon.c +++ b/daemon/daemon.c @@ -221,7 +221,9 @@ daemon_init(void) # ifdef HAVE_ERR_LOAD_CRYPTO_STRINGS ERR_load_crypto_strings(); # endif +#if OPENSSL_VERSION_NUMBER < 0x10100000 || !defined(HAVE_OPENSSL_INIT_SSL) ERR_load_SSL_strings(); +#endif # ifdef USE_GOST (void)sldns_key_EVP_load_gost_id(); # endif @@ -239,7 +241,7 @@ daemon_init(void) # if OPENSSL_VERSION_NUMBER < 0x10100000 || !defined(HAVE_OPENSSL_INIT_SSL) (void)SSL_library_init(); # else - (void)OPENSSL_init_ssl(0, NULL); + (void)OPENSSL_init_ssl(OPENSSL_INIT_LOAD_SSL_STRINGS, NULL); # endif # if defined(HAVE_SSL) && defined(OPENSSL_THREADS) && !defined(THREADS_DISABLED) if(!ub_openssl_lock_init()) @@ -421,8 +423,8 @@ daemon_create_workers(struct daemon* daemon) daemon->rand = ub_initstate(seed, NULL); if(!daemon->rand) fatal_exit("could not init random generator"); + hash_set_raninit((uint32_t)ub_random(daemon->rand)); } - hash_set_raninit((uint32_t)ub_random(daemon->rand)); shufport = (int*)calloc(65536, sizeof(int)); if(!shufport) fatal_exit("out of memory during daemon init"); @@ -691,6 +693,9 @@ daemon_cleanup(struct daemon* daemon) #ifdef USE_DNSTAP dt_delete(daemon->dtenv); #endif +#ifdef USE_DNSCRYPT + dnsc_delete(daemon->dnscenv); +#endif daemon->cfg = NULL; } diff --git a/daemon/remote.c b/daemon/remote.c index bb41cc5df2dbb..243d94c49aa16 100644 --- a/daemon/remote.c +++ b/daemon/remote.c @@ -229,42 +229,10 @@ daemon_remote_create(struct config_file* cfg) free(rc); return NULL; } - /* no SSLv2, SSLv3 because has defects */ - if((SSL_CTX_set_options(rc->ctx, SSL_OP_NO_SSLv2) & SSL_OP_NO_SSLv2) - != SSL_OP_NO_SSLv2){ - log_crypto_err("could not set SSL_OP_NO_SSLv2"); + if(!listen_sslctx_setup(rc->ctx)) { daemon_remote_delete(rc); return NULL; } - if((SSL_CTX_set_options(rc->ctx, SSL_OP_NO_SSLv3) & SSL_OP_NO_SSLv3) - != SSL_OP_NO_SSLv3){ - log_crypto_err("could not set SSL_OP_NO_SSLv3"); - daemon_remote_delete(rc); - return NULL; - } -#if defined(SSL_OP_NO_TLSv1) && defined(SSL_OP_NO_TLSv1_1) - /* if we have tls 1.1 disable 1.0 */ - if((SSL_CTX_set_options(rc->ctx, SSL_OP_NO_TLSv1) & SSL_OP_NO_TLSv1) - != SSL_OP_NO_TLSv1){ - log_crypto_err("could not set SSL_OP_NO_TLSv1"); - daemon_remote_delete(rc); - return NULL; - } -#endif -#if defined(SSL_OP_NO_TLSv1_1) && defined(SSL_OP_NO_TLSv1_2) - /* if we have tls 1.2 disable 1.1 */ - if((SSL_CTX_set_options(rc->ctx, SSL_OP_NO_TLSv1_1) & SSL_OP_NO_TLSv1_1) - != SSL_OP_NO_TLSv1_1){ - log_crypto_err("could not set SSL_OP_NO_TLSv1_1"); - daemon_remote_delete(rc); - return NULL; - } -#endif -#if defined(SHA256_DIGEST_LENGTH) && defined(USE_ECDSA) - /* if we have sha256, set the cipher list to have no known vulns */ - if(!SSL_CTX_set_cipher_list(rc->ctx, "ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256")) - log_crypto_err("could not set cipher list with SSL_CTX_set_cipher_list"); -#endif if (cfg->remote_control_use_cert == 0) { /* No certificates are requested */ @@ -314,23 +282,7 @@ daemon_remote_create(struct config_file* cfg) log_crypto_err("Error in SSL_CTX check_private_key"); goto setup_error; } -#if HAVE_DECL_SSL_CTX_SET_ECDH_AUTO - if(!SSL_CTX_set_ecdh_auto(rc->ctx,1)) { - log_crypto_err("Error in SSL_CTX_ecdh_auto, not enabling ECDHE"); - } -#elif defined(USE_ECDSA) - if(1) { - EC_KEY *ecdh = EC_KEY_new_by_curve_name (NID_X9_62_prime256v1); - if (!ecdh) { - log_crypto_err("could not find p256, not enabling ECDHE"); - } else { - if (1 != SSL_CTX_set_tmp_ecdh (rc->ctx, ecdh)) { - log_crypto_err("Error in SSL_CTX_set_tmp_ecdh, not enabling ECDHE"); - } - EC_KEY_free (ecdh); - } - } -#endif + listen_sslctx_setup_2(rc->ctx); if(!SSL_CTX_load_verify_locations(rc->ctx, s_cert, NULL)) { log_crypto_err("Error setting up SSL_CTX verify locations"); setup_error: @@ -415,7 +367,7 @@ add_open(const char* ip, int nr, struct listen_port** list, int noproto_is_err, if (cfg->username && cfg->username[0] && cfg_uid != (uid_t)-1) { if(chown(ip, cfg_uid, cfg_gid) == -1) - log_err("cannot chown %u.%u %s: %s", + verbose(VERB_QUERY, "cannot chown %u.%u %s: %s", (unsigned)cfg_uid, (unsigned)cfg_gid, ip, strerror(errno)); } @@ -841,7 +793,7 @@ print_stats(SSL* ssl, const char* nm, struct ub_stats_info* s) static int print_thread_stats(SSL* ssl, int i, struct ub_stats_info* s) { - char nm[16]; + char nm[32]; snprintf(nm, sizeof(nm), "thread%d", i); nm[sizeof(nm)-1]=0; return print_stats(ssl, nm, s); @@ -873,6 +825,9 @@ print_mem(SSL* ssl, struct worker* worker, struct daemon* daemon) #ifdef USE_IPSECMOD size_t ipsecmod = 0; #endif /* USE_IPSECMOD */ +#ifdef USE_DNSCRYPT + size_t dnscrypt_shared_secret = 0; +#endif /* USE_DNSCRYPT */ msg = slabhash_get_mem(daemon->env->msg_cache); rrset = slabhash_get_mem(&daemon->env->rrset_cache->table); val = mod_get_mem(&worker->env, "validator"); @@ -884,6 +839,12 @@ print_mem(SSL* ssl, struct worker* worker, struct daemon* daemon) #ifdef USE_IPSECMOD ipsecmod = mod_get_mem(&worker->env, "ipsecmod"); #endif /* USE_IPSECMOD */ +#ifdef USE_DNSCRYPT + if(daemon->dnscenv) { + dnscrypt_shared_secret = slabhash_get_mem( + daemon->dnscenv->shared_secrets_cache); + } +#endif /* USE_DNSCRYPT */ if(!print_longnum(ssl, "mem.cache.rrset"SQ, rrset)) return 0; @@ -903,6 +864,11 @@ print_mem(SSL* ssl, struct worker* worker, struct daemon* daemon) if(!print_longnum(ssl, "mem.mod.ipsecmod"SQ, ipsecmod)) return 0; #endif /* USE_IPSECMOD */ +#ifdef USE_DNSCRYPT + if(!print_longnum(ssl, "mem.cache.dnscrypt_shared_secret"SQ, + dnscrypt_shared_secret)) + return 0; +#endif /* USE_DNSCRYPT */ return 1; } @@ -1065,6 +1031,9 @@ print_ext(SSL* ssl, struct ub_stats_info* s) if(!ssl_printf(ssl, "num.answer.rcode.nodata"SQ"%lu\n", (unsigned long)s->svr.ans_rcode_nodata)) return 0; } + /* iteration */ + if(!ssl_printf(ssl, "num.query.ratelimited"SQ"%lu\n", + (unsigned long)s->svr.queries_ratelimited)) return 0; /* validation */ if(!ssl_printf(ssl, "num.answer.secure"SQ"%lu\n", (unsigned long)s->svr.ans_secure)) return 0; @@ -1086,6 +1055,12 @@ print_ext(SSL* ssl, struct ub_stats_info* s) (unsigned)s->svr.infra_cache_count)) return 0; if(!ssl_printf(ssl, "key.cache.count"SQ"%u\n", (unsigned)s->svr.key_cache_count)) return 0; +#ifdef USE_DNSCRYPT + if(!ssl_printf(ssl, "dnscrypt_shared_secret.cache.count"SQ"%u\n", + (unsigned)s->svr.shared_secret_cache_count)) return 0; + if(!ssl_printf(ssl, "num.query.dnscrypt.shared_secret.cachemiss"SQ"%lu\n", + (unsigned long)s->svr.num_query_dnscrypt_secret_missed_cache)) return 0; +#endif /* USE_DNSCRYPT */ return 1; } @@ -2389,10 +2364,16 @@ dump_infra_host(struct lruhash_entry* e, void* arg) struct infra_data* d = (struct infra_data*)e->data; char ip_str[1024]; char name[257]; + int port; if(a->ssl_failed) return; addr_to_str(&k->addr, k->addrlen, ip_str, sizeof(ip_str)); dname_str(k->zonename, name); + port = (int)ntohs(((struct sockaddr_in*)&k->addr)->sin_port); + if(port != UNBOUND_DNS_PORT) { + snprintf(ip_str+strlen(ip_str), sizeof(ip_str)-strlen(ip_str), + "@%d", port); + } /* skip expired stuff (only backed off) */ if(d->ttl < a->now) { if(d->rtt.rto >= USEFUL_SERVER_TOP_TIMEOUT) { diff --git a/daemon/stats.c b/daemon/stats.c index 599f39bcddda0..1058556be7c26 100644 --- a/daemon/stats.c +++ b/daemon/stats.c @@ -56,6 +56,7 @@ #include "util/timehist.h" #include "util/net_help.h" #include "validator/validator.h" +#include "iterator/iterator.h" #include "sldns/sbuffer.h" #include "services/cache/rrset.h" #include "services/cache/infra.h" @@ -123,7 +124,7 @@ void server_stats_log(struct ub_server_stats* stats, struct worker* worker, /** get rrsets bogus number from validator */ static size_t -get_rrset_bogus(struct worker* worker) +get_rrset_bogus(struct worker* worker, int reset) { int m = modstack_find(&worker->env.mesh->mods, "validator"); struct val_env* ve; @@ -133,12 +134,48 @@ get_rrset_bogus(struct worker* worker) ve = (struct val_env*)worker->env.modinfo[m]; lock_basic_lock(&ve->bogus_lock); r = ve->num_rrset_bogus; - if(!worker->env.cfg->stat_cumulative) + if(reset && !worker->env.cfg->stat_cumulative) ve->num_rrset_bogus = 0; lock_basic_unlock(&ve->bogus_lock); return r; } +/** get number of ratelimited queries from iterator */ +static size_t +get_queries_ratelimit(struct worker* worker, int reset) +{ + int m = modstack_find(&worker->env.mesh->mods, "iterator"); + struct iter_env* ie; + size_t r; + if(m == -1) + return 0; + ie = (struct iter_env*)worker->env.modinfo[m]; + lock_basic_lock(&ie->queries_ratelimit_lock); + r = ie->num_queries_ratelimited; + if(reset && !worker->env.cfg->stat_cumulative) + ie->num_queries_ratelimited = 0; + lock_basic_unlock(&ie->queries_ratelimit_lock); + return r; +} + +#ifdef USE_DNSCRYPT +/** get the number of shared secret cache miss */ +static size_t +get_dnscrypt_cache_miss(struct worker* worker, int reset) +{ + size_t r; + struct dnsc_env* de = worker->daemon->dnscenv; + if(!de) return 0; + + lock_basic_lock(&de->shared_secrets_cache_lock); + r = de->num_query_dnscrypt_secret_missed_cache; + if(reset && !worker->env.cfg->stat_cumulative) + de->num_query_dnscrypt_secret_missed_cache = 0; + lock_basic_unlock(&de->shared_secrets_cache_lock); + return r; +} +#endif /* USE_DNSCRYPT */ + void server_stats_compile(struct worker* worker, struct ub_stats_info* s, int reset) { @@ -169,7 +206,10 @@ server_stats_compile(struct worker* worker, struct ub_stats_info* s, int reset) s->svr.qtcp_outgoing = (long long)worker->back->num_tcp_outgoing; /* get and reset validator rrset bogus number */ - s->svr.rrset_bogus = (long long)get_rrset_bogus(worker); + s->svr.rrset_bogus = (long long)get_rrset_bogus(worker, reset); + + /* get and reset iterator query ratelimit number */ + s->svr.queries_ratelimited = (long long)get_queries_ratelimit(worker, reset); /* get cache sizes */ s->svr.msg_cache_count = (long long)count_slabhash_entries(worker->env.msg_cache); @@ -179,6 +219,21 @@ server_stats_compile(struct worker* worker, struct ub_stats_info* s, int reset) s->svr.key_cache_count = (long long)count_slabhash_entries(worker->env.key_cache->slab); else s->svr.key_cache_count = 0; +#ifdef USE_DNSCRYPT + if(worker->daemon->dnscenv) { + s->svr.num_query_dnscrypt_secret_missed_cache = + (long long)get_dnscrypt_cache_miss(worker, reset); + s->svr.shared_secret_cache_count = (long long)count_slabhash_entries( + worker->daemon->dnscenv->shared_secrets_cache); + } else { + s->svr.num_query_dnscrypt_secret_missed_cache = 0; + s->svr.shared_secret_cache_count = 0; + } +#else + s->svr.num_query_dnscrypt_secret_missed_cache = 0; + s->svr.shared_secret_cache_count = 0; +#endif /* USE_DNSCRYPT */ + /* get tcp accept usage */ s->svr.tcp_accept_usage = 0; for(lp = worker->front->cps; lp; lp = lp->next) { @@ -240,7 +295,7 @@ void server_stats_add(struct ub_stats_info* total, struct ub_stats_info* a) a->svr.num_query_dnscrypt_cleartext; total->svr.num_query_dnscrypt_crypted_malformed += \ a->svr.num_query_dnscrypt_crypted_malformed; -#endif +#endif /* USE_DNSCRYPT */ /* the max size reached is upped to higher of both */ if(a->svr.max_query_list_size > total->svr.max_query_list_size) total->svr.max_query_list_size = a->svr.max_query_list_size; @@ -266,7 +321,6 @@ void server_stats_add(struct ub_stats_info* total, struct ub_stats_info* a) total->svr.zero_ttl_responses += a->svr.zero_ttl_responses; total->svr.ans_secure += a->svr.ans_secure; total->svr.ans_bogus += a->svr.ans_bogus; - total->svr.rrset_bogus += a->svr.rrset_bogus; total->svr.unwanted_replies += a->svr.unwanted_replies; total->svr.unwanted_queries += a->svr.unwanted_queries; total->svr.tcp_accept_usage += a->svr.tcp_accept_usage; diff --git a/daemon/unbound.c b/daemon/unbound.c index ba7337d8907ad..070a824d67343 100644 --- a/daemon/unbound.c +++ b/daemon/unbound.c @@ -128,6 +128,9 @@ static void usage(void) for(m = module_list_avail(); *m; m++) printf(" %s", *m); printf("\n"); +#ifdef USE_DNSCRYPT + printf("DNSCrypt feature available\n"); +#endif printf("BSD licensed, see LICENSE in source package for details.\n"); printf("Report bugs to %s\n", PACKAGE_BUGREPORT); ub_event_base_free(base); @@ -400,7 +403,7 @@ detach(void) /** daemonize, drop user priviliges and chroot if needed */ static void perform_setup(struct daemon* daemon, struct config_file* cfg, int debug_mode, - const char** cfgfile) + const char** cfgfile, int need_pidfile) { #ifdef HAVE_KILL int pidinchroot; @@ -444,13 +447,13 @@ perform_setup(struct daemon* daemon, struct config_file* cfg, int debug_mode, #ifdef HAVE_KILL /* true if pidfile is inside chrootdir, or nochroot */ - pidinchroot = !(cfg->chrootdir && cfg->chrootdir[0]) || + pidinchroot = need_pidfile && (!(cfg->chrootdir && cfg->chrootdir[0]) || (cfg->chrootdir && cfg->chrootdir[0] && strncmp(cfg->pidfile, cfg->chrootdir, - strlen(cfg->chrootdir))==0); + strlen(cfg->chrootdir))==0)); /* check old pid file before forking */ - if(cfg->pidfile && cfg->pidfile[0]) { + if(cfg->pidfile && cfg->pidfile[0] && need_pidfile) { /* calculate position of pidfile */ if(cfg->pidfile[0] == '/') daemon->pidfile = strdup(cfg->pidfile); @@ -469,7 +472,7 @@ perform_setup(struct daemon* daemon, struct config_file* cfg, int debug_mode, /* write new pidfile (while still root, so can be outside chroot) */ #ifdef HAVE_KILL - if(cfg->pidfile && cfg->pidfile[0]) { + if(cfg->pidfile && cfg->pidfile[0] && need_pidfile) { writepid(daemon->pidfile, getpid()); if(cfg->username && cfg->username[0] && cfg_uid != (uid_t)-1 && pidinchroot) { @@ -484,6 +487,7 @@ perform_setup(struct daemon* daemon, struct config_file* cfg, int debug_mode, } #else (void)daemon; + (void)need_pidfile; #endif /* HAVE_KILL */ /* Set user context */ @@ -600,9 +604,10 @@ perform_setup(struct daemon* daemon, struct config_file* cfg, int debug_mode, * These increase verbosity as specified in the config file. * @param debug_mode: if set, do not daemonize. * @param log_default_identity: Default identity to report in logs + * @param need_pidfile: if false, no pidfile is checked or created. */ static void -run_daemon(const char* cfgfile, int cmdline_verbose, int debug_mode, const char* log_default_identity) +run_daemon(const char* cfgfile, int cmdline_verbose, int debug_mode, const char* log_default_identity, int need_pidfile) { struct config_file* cfg = NULL; struct daemon* daemon = NULL; @@ -632,7 +637,7 @@ run_daemon(const char* cfgfile, int cmdline_verbose, int debug_mode, const char* if(!daemon_open_shared_ports(daemon)) fatal_exit("could not open ports"); if(!done_setup) { - perform_setup(daemon, cfg, debug_mode, &cfgfile); + perform_setup(daemon, cfg, debug_mode, &cfgfile, need_pidfile); done_setup = 1; } else { /* reopen log after HUP to facilitate log rotation */ @@ -682,6 +687,8 @@ main(int argc, char* argv[]) const char* log_ident_default; int cmdline_verbose = 0; int debug_mode = 0; + int need_pidfile = 1; + #ifdef UB_ON_WINDOWS int cmdline_cfg = 0; #endif @@ -690,7 +697,7 @@ main(int argc, char* argv[]) log_ident_default = strrchr(argv[0],'/')?strrchr(argv[0],'/')+1:argv[0]; log_ident_set(log_ident_default); /* parse the options */ - while( (c=getopt(argc, argv, "c:dhvw:")) != -1) { + while( (c=getopt(argc, argv, "c:dhpvw:")) != -1) { switch(c) { case 'c': cfgfile = optarg; @@ -702,6 +709,9 @@ main(int argc, char* argv[]) cmdline_verbose++; verbosity++; break; + case 'p': + need_pidfile = 0; + break; case 'd': debug_mode++; break; @@ -732,7 +742,7 @@ main(int argc, char* argv[]) return 1; } - run_daemon(cfgfile, cmdline_verbose, debug_mode, log_ident_default); + run_daemon(cfgfile, cmdline_verbose, debug_mode, log_ident_default, need_pidfile); log_init(NULL, 0, NULL); /* close logfile */ return 0; } diff --git a/daemon/worker.c b/daemon/worker.c index 2c4cf5ba6c0a1..683f93169117d 100644 --- a/daemon/worker.c +++ b/daemon/worker.c @@ -1009,6 +1009,7 @@ worker_handle_request(struct comm_point* c, void* arg, int error, struct query_info* lookup_qinfo = &qinfo; struct query_info qinfo_tmp; /* placeholdoer for lookup_qinfo */ struct respip_client_info* cinfo = NULL, cinfo_tmp; + memset(&qinfo, 0, sizeof(qinfo)); if(error != NETEVENT_NOERROR) { /* some bad tcp query DNS formats give these error calls */ @@ -1111,6 +1112,7 @@ worker_handle_request(struct comm_point* c, void* arg, int error, if(!query_info_parse(&qinfo, c->buffer)) { verbose(VERB_ALGO, "worker parse request: formerror."); log_addr(VERB_CLIENT,"from",&repinfo->addr, repinfo->addrlen); + memset(&qinfo, 0, sizeof(qinfo)); /* zero qinfo.qname */ if(worker_err_ratelimit(worker, LDNS_RCODE_FORMERR) == -1) { comm_point_drop_reply(repinfo); return 0; @@ -1355,6 +1357,10 @@ lookup_cache: lock_rw_unlock(&e->lock); regional_free_all(worker->scratchpad); goto send_reply; + } else { + /* Note that we've already released the + * lock if we're here after prefetch. */ + lock_rw_unlock(&e->lock); } /* We've found a partial reply ending with an * alias. Replace the lookup qinfo for the @@ -1362,7 +1368,6 @@ lookup_cache: * (possibly) complete the reply. As we're * passing the "base" reply, there will be no * more alias chasing. */ - lock_rw_unlock(&e->lock); memset(&qinfo_tmp, 0, sizeof(qinfo_tmp)); get_cname_target(alias_rrset, &qinfo_tmp.qname, &qinfo_tmp.qname_len); @@ -1669,7 +1674,17 @@ worker_init(struct worker* worker, struct config_file *cfg, worker->env.send_query = &worker_send_query; worker->env.alloc = &worker->alloc; worker->env.rnd = worker->rndstate; - worker->env.scratch = worker->scratchpad; + /* If case prefetch is triggered, the corresponding mesh will clear + * the scratchpad for the module env in the middle of request handling. + * It would be prone to a use-after-free kind of bug, so we avoid + * sharing it with worker's own scratchpad at the cost of having + * one more pad per worker. */ + worker->env.scratch = regional_create_custom(cfg->msg_buffer_size); + if(!worker->env.scratch) { + log_err("malloc failure"); + worker_delete(worker); + return 0; + } worker->env.mesh = mesh_create(&worker->daemon->mods, &worker->env); worker->env.detach_subs = &mesh_detach_subs; worker->env.attach_sub = &mesh_attach_sub; @@ -1758,6 +1773,7 @@ worker_delete(struct worker* worker) comm_base_delete(worker->base); ub_randfree(worker->rndstate); alloc_clear(&worker->alloc); + regional_destroy(worker->env.scratch); regional_destroy(worker->scratchpad); free(worker); } |