diff options
Diffstat (limited to 'external/unbound/daemon')
-rw-r--r-- | external/unbound/daemon/acl_list.c | 325 | ||||
-rw-r--r-- | external/unbound/daemon/acl_list.h | 38 | ||||
-rw-r--r-- | external/unbound/daemon/cachedump.c | 2 | ||||
-rw-r--r-- | external/unbound/daemon/daemon.c | 114 | ||||
-rw-r--r-- | external/unbound/daemon/daemon.h | 19 | ||||
-rw-r--r-- | external/unbound/daemon/remote.c | 581 | ||||
-rw-r--r-- | external/unbound/daemon/remote.h | 4 | ||||
-rw-r--r-- | external/unbound/daemon/stats.c | 16 | ||||
-rw-r--r-- | external/unbound/daemon/stats.h | 16 | ||||
-rw-r--r-- | external/unbound/daemon/unbound.c | 150 | ||||
-rw-r--r-- | external/unbound/daemon/worker.c | 672 | ||||
-rw-r--r-- | external/unbound/daemon/worker.h | 3 |
12 files changed, 1591 insertions, 349 deletions
diff --git a/external/unbound/daemon/acl_list.c b/external/unbound/daemon/acl_list.c index 84d099ca5..f7d71b9fd 100644 --- a/external/unbound/daemon/acl_list.c +++ b/external/unbound/daemon/acl_list.c @@ -45,6 +45,8 @@ #include "util/log.h" #include "util/config_file.h" #include "util/net_help.h" +#include "services/localzone.h" +#include "sldns/str2wire.h" struct acl_list* acl_list_create(void) @@ -71,21 +73,21 @@ acl_list_delete(struct acl_list* acl) } /** insert new address into acl_list structure */ -static int +static struct acl_addr* acl_list_insert(struct acl_list* acl, struct sockaddr_storage* addr, socklen_t addrlen, int net, enum acl_access control, int complain_duplicates) { - struct acl_addr* node = regional_alloc(acl->region, + struct acl_addr* node = regional_alloc_zero(acl->region, sizeof(struct acl_addr)); if(!node) - return 0; + return NULL; node->control = control; if(!addr_tree_insert(&acl->tree, &node->node, addr, addrlen, net)) { if(complain_duplicates) verbose(VERB_QUERY, "duplicate acl address ignored."); } - return 1; + return node; } /** apply acl_list string */ @@ -125,6 +127,205 @@ acl_list_str_cfg(struct acl_list* acl, const char* str, const char* s2, return 1; } +/** find or create node (NULL on parse or error) */ +static struct acl_addr* +acl_find_or_create(struct acl_list* acl, const char* str) +{ + struct acl_addr* node; + struct sockaddr_storage addr; + int net; + socklen_t addrlen; + if(!netblockstrtoaddr(str, UNBOUND_DNS_PORT, &addr, &addrlen, &net)) { + log_err("cannot parse netblock: %s", str); + return NULL; + } + /* find or create node */ + if(!(node=(struct acl_addr*)addr_tree_find(&acl->tree, &addr, + addrlen, net))) { + /* create node, type 'allow' since otherwise tags are + * pointless, can override with specific access-control: cfg */ + if(!(node=(struct acl_addr*)acl_list_insert(acl, &addr, + addrlen, net, acl_allow, 1))) { + log_err("out of memory"); + return NULL; + } + } + return node; +} + +/** apply acl_tag string */ +static int +acl_list_tags_cfg(struct acl_list* acl, const char* str, uint8_t* bitmap, + size_t bitmaplen) +{ + struct acl_addr* node; + if(!(node=acl_find_or_create(acl, str))) + return 0; + node->taglen = bitmaplen; + node->taglist = regional_alloc_init(acl->region, bitmap, bitmaplen); + if(!node->taglist) { + log_err("out of memory"); + return 0; + } + return 1; +} + +/** apply acl_view string */ +static int +acl_list_view_cfg(struct acl_list* acl, const char* str, const char* str2, + struct views* vs) +{ + struct acl_addr* node; + if(!(node=acl_find_or_create(acl, str))) + return 0; + node->view = views_find_view(vs, str2, 0 /* get read lock*/); + if(!node->view) { + log_err("no view with name: %s", str2); + return 0; + } + lock_rw_unlock(&node->view->lock); + return 1; +} + +/** apply acl_tag_action string */ +static int +acl_list_tag_action_cfg(struct acl_list* acl, struct config_file* cfg, + const char* str, const char* tag, const char* action) +{ + struct acl_addr* node; + int tagid; + enum localzone_type t; + if(!(node=acl_find_or_create(acl, str))) + return 0; + /* allocate array if not yet */ + if(!node->tag_actions) { + node->tag_actions = (uint8_t*)regional_alloc_zero(acl->region, + sizeof(*node->tag_actions)*cfg->num_tags); + if(!node->tag_actions) { + log_err("out of memory"); + return 0; + } + node->tag_actions_size = (size_t)cfg->num_tags; + } + /* parse tag */ + if((tagid=find_tag_id(cfg, tag)) == -1) { + log_err("cannot parse tag (define-tag it): %s %s", str, tag); + return 0; + } + if((size_t)tagid >= node->tag_actions_size) { + log_err("tagid too large for array %s %s", str, tag); + return 0; + } + if(!local_zone_str2type(action, &t)) { + log_err("cannot parse access control action type: %s %s %s", + str, tag, action); + return 0; + } + node->tag_actions[tagid] = (uint8_t)t; + return 1; +} + +/** check wire data parse */ +static int +check_data(const char* data, const struct config_strlist* head) +{ + char buf[65536]; + uint8_t rr[LDNS_RR_BUF_SIZE]; + size_t len = sizeof(rr); + int res; + /* '.' is sufficient for validation, and it makes the call to + * sldns_wirerr_get_type() simpler below. */ + snprintf(buf, sizeof(buf), "%s %s", ".", data); + res = sldns_str2wire_rr_buf(buf, rr, &len, NULL, 3600, NULL, 0, + NULL, 0); + + /* Reject it if we would end up having CNAME and other data (including + * another CNAME) for the same tag. */ + if(res == 0 && head) { + const char* err_data = NULL; + + if(sldns_wirerr_get_type(rr, len, 1) == LDNS_RR_TYPE_CNAME) { + /* adding CNAME while other data already exists. */ + err_data = data; + } else { + snprintf(buf, sizeof(buf), "%s %s", ".", head->str); + len = sizeof(rr); + res = sldns_str2wire_rr_buf(buf, rr, &len, NULL, 3600, + NULL, 0, NULL, 0); + if(res != 0) { + /* This should be impossible here as head->str + * has been validated, but we check it just in + * case. */ + return 0; + } + if(sldns_wirerr_get_type(rr, len, 1) == + LDNS_RR_TYPE_CNAME) /* already have CNAME */ + err_data = head->str; + } + if(err_data) { + log_err("redirect tag data '%s' must not coexist with " + "other data.", err_data); + return 0; + } + } + if(res == 0) + return 1; + log_err("rr data [char %d] parse error %s", + (int)LDNS_WIREPARSE_OFFSET(res)-13, + sldns_get_errorstr_parse(res)); + return 0; +} + +/** apply acl_tag_data string */ +static int +acl_list_tag_data_cfg(struct acl_list* acl, struct config_file* cfg, + const char* str, const char* tag, const char* data) +{ + struct acl_addr* node; + int tagid; + char* dupdata; + if(!(node=acl_find_or_create(acl, str))) + return 0; + /* allocate array if not yet */ + if(!node->tag_datas) { + node->tag_datas = (struct config_strlist**)regional_alloc_zero( + acl->region, sizeof(*node->tag_datas)*cfg->num_tags); + if(!node->tag_datas) { + log_err("out of memory"); + return 0; + } + node->tag_datas_size = (size_t)cfg->num_tags; + } + /* parse tag */ + if((tagid=find_tag_id(cfg, tag)) == -1) { + log_err("cannot parse tag (define-tag it): %s %s", str, tag); + return 0; + } + if((size_t)tagid >= node->tag_datas_size) { + log_err("tagid too large for array %s %s", str, tag); + return 0; + } + + /* check data? */ + if(!check_data(data, node->tag_datas[tagid])) { + log_err("cannot parse access-control-tag data: %s %s '%s'", + str, tag, data); + return 0; + } + + dupdata = regional_strdup(acl->region, data); + if(!dupdata) { + log_err("out of memory"); + return 0; + } + if(!cfg_region_strlist_insert(acl->region, + &(node->tag_datas[tagid]), dupdata)) { + log_err("out of memory"); + return 0; + } + return 1; +} + /** read acl_list config */ static int read_acl_list(struct acl_list* acl, struct config_file* cfg) @@ -138,13 +339,114 @@ read_acl_list(struct acl_list* acl, struct config_file* cfg) return 1; } +/** read acl tags config */ +static int +read_acl_tags(struct acl_list* acl, struct config_file* cfg) +{ + struct config_strbytelist* np, *p = cfg->acl_tags; + cfg->acl_tags = NULL; + while(p) { + log_assert(p->str && p->str2); + if(!acl_list_tags_cfg(acl, p->str, p->str2, p->str2len)) { + config_del_strbytelist(p); + return 0; + } + /* free the items as we go to free up memory */ + np = p->next; + free(p->str); + free(p->str2); + free(p); + p = np; + } + return 1; +} + +/** read acl view config */ +static int +read_acl_view(struct acl_list* acl, struct config_file* cfg, struct views* v) +{ + struct config_str2list* np, *p = cfg->acl_view; + cfg->acl_view = NULL; + while(p) { + log_assert(p->str && p->str2); + if(!acl_list_view_cfg(acl, p->str, p->str2, v)) { + return 0; + } + /* free the items as we go to free up memory */ + np = p->next; + free(p->str); + free(p->str2); + free(p); + p = np; + } + return 1; +} + +/** read acl tag actions config */ +static int +read_acl_tag_actions(struct acl_list* acl, struct config_file* cfg) +{ + struct config_str3list* p, *np; + p = cfg->acl_tag_actions; + cfg->acl_tag_actions = NULL; + while(p) { + log_assert(p->str && p->str2 && p->str3); + if(!acl_list_tag_action_cfg(acl, cfg, p->str, p->str2, + p->str3)) { + config_deltrplstrlist(p); + return 0; + } + /* free the items as we go to free up memory */ + np = p->next; + free(p->str); + free(p->str2); + free(p->str3); + free(p); + p = np; + } + return 1; +} + +/** read acl tag datas config */ +static int +read_acl_tag_datas(struct acl_list* acl, struct config_file* cfg) +{ + struct config_str3list* p, *np; + p = cfg->acl_tag_datas; + cfg->acl_tag_datas = NULL; + while(p) { + log_assert(p->str && p->str2 && p->str3); + if(!acl_list_tag_data_cfg(acl, cfg, p->str, p->str2, p->str3)) { + config_deltrplstrlist(p); + return 0; + } + /* free the items as we go to free up memory */ + np = p->next; + free(p->str); + free(p->str2); + free(p->str3); + free(p); + p = np; + } + return 1; +} + int -acl_list_apply_cfg(struct acl_list* acl, struct config_file* cfg) +acl_list_apply_cfg(struct acl_list* acl, struct config_file* cfg, + struct views* v) { regional_free_all(acl->region); addr_tree_init(&acl->tree); if(!read_acl_list(acl, cfg)) return 0; + if(!read_acl_view(acl, cfg, v)) + return 0; + if(!read_acl_tags(acl, cfg)) + return 0; + if(!read_acl_tag_actions(acl, cfg)) + return 0; + if(!read_acl_tag_datas(acl, cfg)) + return 0; /* insert defaults, with '0' to ignore them if they are duplicates */ if(!acl_list_str_cfg(acl, "0.0.0.0/0", "refuse", 0)) return 0; @@ -163,13 +465,18 @@ acl_list_apply_cfg(struct acl_list* acl, struct config_file* cfg) } enum acl_access -acl_list_lookup(struct acl_list* acl, struct sockaddr_storage* addr, +acl_get_control(struct acl_addr* acl) +{ + if(acl) return acl->control; + return acl_deny; +} + +struct acl_addr* +acl_addr_lookup(struct acl_list* acl, struct sockaddr_storage* addr, socklen_t addrlen) { - struct acl_addr* r = (struct acl_addr*)addr_tree_lookup(&acl->tree, + return (struct acl_addr*)addr_tree_lookup(&acl->tree, addr, addrlen); - if(r) return r->control; - return acl_deny; } size_t diff --git a/external/unbound/daemon/acl_list.h b/external/unbound/daemon/acl_list.h index 2323697d5..d0d42bfae 100644 --- a/external/unbound/daemon/acl_list.h +++ b/external/unbound/daemon/acl_list.h @@ -43,6 +43,7 @@ #ifndef DAEMON_ACL_LIST_H #define DAEMON_ACL_LIST_H #include "util/storage/dnstree.h" +#include "services/view.h" struct config_file; struct regional; @@ -75,7 +76,7 @@ struct acl_list { * Tree of the addresses that are allowed/blocked. * contents of type acl_addr. */ - rbtree_t tree; + rbtree_type tree; }; /** @@ -87,6 +88,21 @@ struct acl_addr { struct addr_tree_node node; /** access control on this netblock */ enum acl_access control; + /** tag bitlist */ + uint8_t* taglist; + /** length of the taglist (in bytes) */ + size_t taglen; + /** array per tagnumber of localzonetype(in one byte). NULL if none. */ + uint8_t* tag_actions; + /** size of the tag_actions_array */ + size_t tag_actions_size; + /** array per tagnumber, with per tag a list of rdata strings. + * NULL if none. strings are like 'A 127.0.0.1' 'AAAA ::1' */ + struct config_strlist** tag_datas; + /** size of the tag_datas array */ + size_t tag_datas_size; + /* view element, NULL if none */ + struct view* view; }; /** @@ -105,19 +121,29 @@ void acl_list_delete(struct acl_list* acl); * Process access control config. * @param acl: where to store. * @param cfg: config options. + * @param v: views structure * @return 0 on error. */ -int acl_list_apply_cfg(struct acl_list* acl, struct config_file* cfg); +int acl_list_apply_cfg(struct acl_list* acl, struct config_file* cfg, + struct views* v); /** - * Lookup address to see its access control status. + * Lookup access control status for acl structure. + * @param acl: structure for acl storage. + * @return: what to do with message from this address. + */ +enum acl_access acl_get_control(struct acl_addr* acl); + +/** + * Lookup address to see its acl structure * @param acl: structure for address storage. * @param addr: address to check * @param addrlen: length of addr. - * @return: what to do with message from this address. + * @return: acl structure from this address. */ -enum acl_access acl_list_lookup(struct acl_list* acl, - struct sockaddr_storage* addr, socklen_t addrlen); +struct acl_addr* +acl_addr_lookup(struct acl_list* acl, struct sockaddr_storage* addr, + socklen_t addrlen); /** * Get memory used by acl structure. diff --git a/external/unbound/daemon/cachedump.c b/external/unbound/daemon/cachedump.c index 4b0a583a6..8992e6cb8 100644 --- a/external/unbound/daemon/cachedump.c +++ b/external/unbound/daemon/cachedump.c @@ -563,6 +563,7 @@ load_qinfo(char* str, struct query_info* qinfo, struct regional* region) qinfo->qclass = sldns_wirerr_get_class(rr, rr_len, dname_len); qinfo->qname_len = dname_len; qinfo->qname = (uint8_t*)regional_alloc_init(region, rr, dname_len); + qinfo->local_alias = NULL; if(!qinfo->qname) { log_warn("error out of memory"); return NULL; @@ -826,6 +827,7 @@ int print_deleg_lookup(SSL* ssl, struct worker* worker, uint8_t* nm, qinfo.qname_len = nmlen; qinfo.qtype = LDNS_RR_TYPE_A; qinfo.qclass = LDNS_RR_CLASS_IN; + qinfo.local_alias = NULL; dname_str(nm, b); if(!ssl_printf(ssl, "The following name servers are used for lookup " diff --git a/external/unbound/daemon/daemon.c b/external/unbound/daemon/daemon.c index e763f724e..dad9f86b3 100644 --- a/external/unbound/daemon/daemon.c +++ b/external/unbound/daemon/daemon.c @@ -73,20 +73,27 @@ #include "util/log.h" #include "util/config_file.h" #include "util/data/msgreply.h" +#include "util/shm_side/shm_main.h" #include "util/storage/lookup3.h" #include "util/storage/slabhash.h" #include "services/listen_dnsport.h" #include "services/cache/rrset.h" #include "services/cache/infra.h" #include "services/localzone.h" +#include "services/view.h" #include "services/modstack.h" #include "util/module.h" #include "util/random.h" #include "util/tube.h" #include "util/net_help.h" #include "sldns/keyraw.h" +#include "respip/respip.h" #include <signal.h> +#ifdef HAVE_SYSTEMD +#include <systemd/sd-daemon.h> +#endif + /** How many quit requests happened. */ static int sig_record_quit = 0; /** How many reload requests happened. */ @@ -174,8 +181,15 @@ static void signal_handling_playback(struct worker* wrk) { #ifdef SIGHUP - if(sig_record_reload) + if(sig_record_reload) { +# ifdef HAVE_SYSTEMD + sd_notify(0, "RELOADING=1"); +# endif worker_sighandler(SIGHUP, wrk); +# ifdef HAVE_SYSTEMD + sd_notify(0, "READY=1"); +# endif + } #endif if(sig_record_quit) worker_sighandler(SIGTERM, wrk); @@ -204,20 +218,29 @@ daemon_init(void) signal_handling_record(); checklock_start(); #ifdef HAVE_SSL +# ifdef HAVE_ERR_LOAD_CRYPTO_STRINGS ERR_load_crypto_strings(); - ERR_load_SSL_strings(); -# ifdef HAVE_OPENSSL_CONFIG - OPENSSL_config("unbound"); # endif + ERR_load_SSL_strings(); # ifdef USE_GOST (void)sldns_key_EVP_load_gost_id(); # endif +# if OPENSSL_VERSION_NUMBER < 0x10100000 || !defined(HAVE_OPENSSL_INIT_CRYPTO) OpenSSL_add_all_algorithms(); +# else + OPENSSL_init_crypto(OPENSSL_INIT_ADD_ALL_CIPHERS + | OPENSSL_INIT_ADD_ALL_DIGESTS + | OPENSSL_INIT_LOAD_CRYPTO_STRINGS, NULL); +# endif # if HAVE_DECL_SSL_COMP_GET_COMPRESSION_METHODS /* grab the COMP method ptr because openssl leaks it */ comp_meth = (void*)SSL_COMP_get_compression_methods(); # endif +# if OPENSSL_VERSION_NUMBER < 0x10100000 || !defined(HAVE_OPENSSL_INIT_SSL) (void)SSL_library_init(); +# else + (void)OPENSSL_init_ssl(0, NULL); +# endif # if defined(HAVE_SSL) && defined(OPENSSL_THREADS) && !defined(THREADS_DISABLED) if(!ub_openssl_lock_init()) fatal_exit("could not init openssl locks"); @@ -239,9 +262,16 @@ daemon_init(void) free(daemon); return NULL; } + /* init edns_known_options */ + if(!edns_known_options_init(daemon->env)) { + free(daemon->env); + free(daemon); + return NULL; + } alloc_init(&daemon->superalloc, NULL, 0); daemon->acl = acl_list_create(); if(!daemon->acl) { + edns_known_options_delete(daemon->env); free(daemon->env); free(daemon); return NULL; @@ -338,6 +368,7 @@ static void daemon_setup_modules(struct daemon* daemon) daemon->env)) { fatal_exit("failed to setup modules"); } + log_edns_known_options(VERB_ALGO, daemon->env); } /** @@ -407,6 +438,8 @@ daemon_create_workers(struct daemon* daemon) } daemon->workers = (struct worker**)calloc((size_t)daemon->num, sizeof(struct worker*)); + if(!daemon->workers) + fatal_exit("out of memory during daemon init"); if(daemon->cfg->dnstap) { #ifdef USE_DNSTAP daemon->dtenv = dt_create(daemon->cfg->dnstap_socket_path, @@ -530,17 +563,55 @@ daemon_stop_others(struct daemon* daemon) void daemon_fork(struct daemon* daemon) { + int have_view_respip_cfg = 0; + log_assert(daemon); - if(!acl_list_apply_cfg(daemon->acl, daemon->cfg)) + if(!(daemon->views = views_create())) + fatal_exit("Could not create views: out of memory"); + /* create individual views and their localzone/data trees */ + if(!views_apply_cfg(daemon->views, daemon->cfg)) + fatal_exit("Could not set up views"); + + if(!acl_list_apply_cfg(daemon->acl, daemon->cfg, daemon->views)) fatal_exit("Could not setup access control list"); + if(daemon->cfg->dnscrypt) { +#ifdef USE_DNSCRYPT + daemon->dnscenv = dnsc_create(); + if (!daemon->dnscenv) + fatal_exit("dnsc_create failed"); + dnsc_apply_cfg(daemon->dnscenv, daemon->cfg); +#else + fatal_exit("dnscrypt enabled in config but unbound was not built with " + "dnscrypt support"); +#endif + } + /* create global local_zones */ if(!(daemon->local_zones = local_zones_create())) fatal_exit("Could not create local zones: out of memory"); if(!local_zones_apply_cfg(daemon->local_zones, daemon->cfg)) fatal_exit("Could not set up local zones"); + /* process raw response-ip configuration data */ + if(!(daemon->respip_set = respip_set_create())) + fatal_exit("Could not create response IP set"); + if(!respip_global_apply_cfg(daemon->respip_set, daemon->cfg)) + fatal_exit("Could not set up response IP set"); + if(!respip_views_apply_cfg(daemon->views, daemon->cfg, + &have_view_respip_cfg)) + fatal_exit("Could not set up per-view response IP sets"); + daemon->use_response_ip = !respip_set_is_empty(daemon->respip_set) || + have_view_respip_cfg; + /* setup modules */ daemon_setup_modules(daemon); + /* response-ip-xxx options don't work as expected without the respip + * module. To avoid run-time operational surprise we reject such + * configuration. */ + if(daemon->use_response_ip && + modstack_find(&daemon->mods, "respip") < 0) + fatal_exit("response-ip options require respip module"); + /* first create all the worker structures, so we can pass * them to the newly created threads. */ @@ -567,14 +638,26 @@ daemon_fork(struct daemon* daemon) #endif signal_handling_playback(daemon->workers[0]); + if (!shm_main_init(daemon)) + log_warn("SHM has failed"); + /* Start resolver service on main thread. */ +#ifdef HAVE_SYSTEMD + sd_notify(0, "READY=1"); +#endif log_info("start of service (%s).", PACKAGE_STRING); worker_work(daemon->workers[0]); +#ifdef HAVE_SYSTEMD + sd_notify(0, "STOPPING=1"); +#endif log_info("service stopped (%s).", PACKAGE_STRING); /* we exited! a signal happened! Stop other threads */ daemon_stop_others(daemon); + /* Shutdown SHM */ + shm_main_shutdown(daemon); + daemon->need_to_exit = daemon->workers[0]->need_to_exit; } @@ -589,13 +672,16 @@ daemon_cleanup(struct daemon* daemon) log_thread_set(NULL); /* clean up caches because * a) RRset IDs will be recycled after a reload, causing collisions - * b) validation config can change, thus rrset, msg, keycache clear - * The infra cache is kept, the timing and edns info is still valid */ + * b) validation config can change, thus rrset, msg, keycache clear */ slabhash_clear(&daemon->env->rrset_cache->table); slabhash_clear(daemon->env->msg_cache); local_zones_delete(daemon->local_zones); daemon->local_zones = NULL; - /* key cache is cleared by module desetup during next daemon_init() */ + respip_set_delete(daemon->respip_set); + daemon->respip_set = NULL; + views_delete(daemon->views); + daemon->views = NULL; + /* key cache is cleared by module desetup during next daemon_fork() */ daemon_remote_clear(daemon->rc); for(i=0; i<daemon->num; i++) worker_delete(daemon->workers[i]); @@ -624,6 +710,7 @@ daemon_delete(struct daemon* daemon) slabhash_delete(daemon->env->msg_cache); rrset_cache_delete(daemon->env->rrset_cache); infra_delete(daemon->env->infra_cache); + edns_known_options_delete(daemon->env); } ub_randfree(daemon->rand); alloc_clear(&daemon->superalloc); @@ -647,18 +734,27 @@ daemon_delete(struct daemon* daemon) # endif # if HAVE_DECL_SSL_COMP_GET_COMPRESSION_METHODS && HAVE_DECL_SK_SSL_COMP_POP_FREE # ifndef S_SPLINT_S +# if OPENSSL_VERSION_NUMBER < 0x10100000 sk_SSL_COMP_pop_free(comp_meth, (void(*)())CRYPTO_free); +# endif # endif # endif # ifdef HAVE_OPENSSL_CONFIG EVP_cleanup(); +# if OPENSSL_VERSION_NUMBER < 0x10100000 ENGINE_cleanup(); +# endif CONF_modules_free(); # endif +# ifdef HAVE_CRYPTO_CLEANUP_ALL_EX_DATA CRYPTO_cleanup_all_ex_data(); /* safe, no more threads right now */ - ERR_remove_state(0); +# endif +# ifdef HAVE_ERR_FREE_STRINGS ERR_free_strings(); +# endif +# if OPENSSL_VERSION_NUMBER < 0x10100000 RAND_cleanup(); +# endif # if defined(HAVE_SSL) && defined(OPENSSL_THREADS) && !defined(THREADS_DISABLED) ub_openssl_lock_delete(); # endif diff --git a/external/unbound/daemon/daemon.h b/external/unbound/daemon/daemon.h index 86ddab1df..71e5bb96d 100644 --- a/external/unbound/daemon/daemon.h +++ b/external/unbound/daemon/daemon.h @@ -56,14 +56,22 @@ struct module_env; struct rrset_cache; struct acl_list; struct local_zones; +struct views; struct ub_randstate; struct daemon_remote; +struct respip_set; +struct shm_main_info; #include "dnstap/dnstap_config.h" #ifdef USE_DNSTAP struct dt_env; #endif +#include "dnscrypt/dnscrypt_config.h" +#ifdef USE_DNSCRYPT +struct dnsc_env; +#endif + /** * Structure holding worker list. * Holds globally visible information. @@ -114,10 +122,21 @@ struct daemon { struct timeval time_last_stat; /** time when daemon started */ struct timeval time_boot; + /** views structure containing view tree */ + struct views* views; #ifdef USE_DNSTAP /** the dnstap environment master value, copied and changed by threads*/ struct dt_env* dtenv; #endif + struct shm_main_info* shm_info; + /** response-ip set with associated actions and tags. */ + struct respip_set* respip_set; + /** some response-ip tags or actions are configured if true */ + int use_response_ip; +#ifdef USE_DNSCRYPT + /** the dnscrypt environment */ + struct dnsc_env* dnscenv; +#endif }; /** diff --git a/external/unbound/daemon/remote.c b/external/unbound/daemon/remote.c index d533e0867..c15967c20 100644 --- a/external/unbound/daemon/remote.c +++ b/external/unbound/daemon/remote.c @@ -46,9 +46,12 @@ #ifdef HAVE_OPENSSL_ERR_H #include <openssl/err.h> #endif -#ifndef HEADER_DH_H +#ifdef HAVE_OPENSSL_DH_H #include <openssl/dh.h> #endif +#ifdef HAVE_OPENSSL_BN_H +#include <openssl/bn.h> +#endif #include <ctype.h> #include "daemon/remote.h" @@ -140,49 +143,68 @@ timeval_divide(struct timeval* avg, const struct timeval* sum, size_t d) /* * The following function was generated using the openssl utility, using - * the command : "openssl dhparam -dsaparam -C 1024" + * the command : "openssl dhparam -C 2048" * (some openssl versions reject DH that is 'too small', eg. 512). */ +#if OPENSSL_VERSION_NUMBER < 0x10100000 || defined(HAVE_LIBRESSL) #ifndef S_SPLINT_S -DH *get_dh1024() -{ - static unsigned char dh1024_p[]={ - 0xB3,0x67,0x2E,0x3B,0x68,0xC5,0xDA,0x58,0x46,0xD6,0x2B,0xD3, - 0x41,0x78,0x97,0xE4,0xE1,0x61,0x71,0x68,0xE6,0x0F,0x1D,0x78, - 0x05,0xAA,0xF0,0xFF,0x30,0xDF,0xAC,0x49,0x7F,0xE0,0x90,0xFE, - 0xB9,0x56,0x4E,0x3F,0xE2,0x98,0x8A,0xED,0xF5,0x28,0x39,0xEF, - 0x2E,0xA6,0xB7,0x67,0xB2,0x43,0xE4,0x53,0xF8,0xEB,0x2C,0x1F, - 0x06,0x77,0x3A,0x6F,0x62,0x98,0xC1,0x3B,0xF7,0xBA,0x4D,0x93, - 0xF7,0xEB,0x5A,0xAD,0xC5,0x5F,0xF0,0xB7,0x24,0x35,0x81,0xF7, - 0x7F,0x1F,0x24,0xC0,0xDF,0xD3,0xD8,0x40,0x72,0x7E,0xF3,0x19, - 0x2B,0x26,0x27,0xF4,0xB6,0xB3,0xD4,0x7D,0x08,0x23,0xBE,0x68, - 0x2B,0xCA,0xB4,0x46,0xA8,0x9E,0xDD,0x6C,0x3D,0x75,0xA6,0x48, - 0xF7,0x44,0x43,0xBF,0x91,0xC2,0xB4,0x49, +static DH *get_dh2048(void) +{ + static unsigned char dh2048_p[]={ + 0xE7,0x36,0x28,0x3B,0xE4,0xC3,0x32,0x1C,0x01,0xC3,0x67,0xD6, + 0xF5,0xF3,0xDA,0xDC,0x71,0xC0,0x42,0x8B,0xE6,0xEB,0x8D,0x80, + 0x35,0x7F,0x09,0x45,0x30,0xE5,0xB2,0x92,0x81,0x3F,0x08,0xCD, + 0x36,0x5E,0x19,0x83,0x62,0xCC,0xAE,0x9B,0x81,0x66,0x24,0xEE, + 0x16,0x6F,0xA9,0x9E,0xF4,0x82,0x1B,0xDD,0x46,0xC7,0x33,0x5D, + 0xF4,0xCA,0xE6,0x8F,0xFC,0xD4,0xD8,0x58,0x94,0x24,0x5D,0xFF, + 0x0A,0xE8,0xEF,0x3D,0xCE,0xBB,0x50,0x94,0xE0,0x5F,0xE8,0x41, + 0xC3,0x35,0x30,0x37,0xD5,0xCB,0x8F,0x3D,0x95,0x15,0x1A,0x77, + 0x42,0xB2,0x06,0x86,0xF6,0x09,0x66,0x0E,0x9A,0x25,0x94,0x3E, + 0xD2,0x04,0x25,0x25,0x1D,0x23,0xEB,0xDC,0x4D,0x0C,0x83,0x28, + 0x2E,0x15,0x81,0x2D,0xC1,0xAF,0x8D,0x36,0x64,0xE3,0x9A,0x83, + 0x78,0xC2,0x8D,0xC0,0x9D,0xD9,0x3A,0x1C,0xC5,0x2B,0x50,0x68, + 0x07,0xA9,0x4B,0x8C,0x07,0x57,0xD6,0x15,0x03,0x4E,0x9E,0x01, + 0xF2,0x6F,0x35,0xAC,0x26,0x9C,0x92,0x68,0x61,0x13,0xFB,0x01, + 0xBA,0x22,0x36,0x01,0x55,0xB6,0x62,0xD9,0xB2,0x98,0xCE,0x5D, + 0x4B,0xA5,0x41,0xD6,0xE5,0x70,0x78,0x12,0x1F,0x64,0xB6,0x6F, + 0xB0,0x91,0x51,0x91,0x92,0xC0,0x94,0x3A,0xD1,0x28,0x4D,0x30, + 0x84,0x3E,0xE4,0xE4,0x7F,0x47,0x89,0xB1,0xB6,0x8C,0x8E,0x0E, + 0x26,0xDB,0xCD,0x17,0x07,0x2A,0x21,0x7A,0xCC,0x68,0xE8,0x57, + 0x94,0x9E,0x59,0x61,0xEC,0x20,0x34,0x26,0x0D,0x66,0x44,0xEB, + 0x6F,0x02,0x58,0xE2,0xED,0xF6,0xF3,0x1B,0xBF,0x9E,0x45,0x52, + 0x5A,0x49,0xA1,0x5B, }; - static unsigned char dh1024_g[]={ - 0x5F,0x37,0xB5,0x80,0x4D,0xB4,0xC4,0xB2,0x37,0x12,0xD5,0x2F, - 0x56,0x81,0xB0,0xDF,0x3D,0x27,0xA2,0x54,0xE7,0x14,0x65,0x2D, - 0x72,0xA8,0x97,0xE0,0xA9,0x4A,0x09,0x5E,0x89,0xBE,0x34,0x9A, - 0x90,0x98,0xC1,0xE8,0xBB,0x01,0x2B,0xC2,0x74,0x74,0x90,0x59, - 0x0B,0x72,0x62,0x5C,0xFD,0x49,0x63,0x4B,0x38,0x91,0xF1,0x7F, - 0x13,0x25,0xEB,0x52,0x50,0x47,0xA2,0x8C,0x32,0x28,0x42,0xAC, - 0xBD,0x7A,0xCC,0x58,0xBE,0x36,0xDA,0x6A,0x24,0x06,0xC7,0xF1, - 0xDA,0x8D,0x8A,0x3B,0x03,0xFA,0x6F,0x25,0xE5,0x20,0xA7,0xD6, - 0x6F,0x74,0x61,0x53,0x14,0x81,0x29,0x04,0xB5,0x61,0x12,0x53, - 0xA3,0xD6,0x09,0x98,0x0C,0x8F,0x1C,0xBB,0xD7,0x1C,0x2C,0xEE, - 0x56,0x4B,0x74,0x8F,0x4A,0xF8,0xA9,0xD5, + static unsigned char dh2048_g[]={ + 0x02, }; - DH *dh; - - if ((dh=DH_new()) == NULL) return(NULL); - dh->p=BN_bin2bn(dh1024_p,sizeof(dh1024_p),NULL); - dh->g=BN_bin2bn(dh1024_g,sizeof(dh1024_g),NULL); - if ((dh->p == NULL) || (dh->g == NULL)) - { DH_free(dh); return(NULL); } - dh->length = 160; - return(dh); + DH *dh = NULL; + BIGNUM *p = NULL, *g = NULL; + + dh = DH_new(); + p = BN_bin2bn(dh2048_p, sizeof(dh2048_p), NULL); + g = BN_bin2bn(dh2048_g, sizeof(dh2048_g), NULL); + if (!dh || !p || !g) + goto err; + +#if OPENSSL_VERSION_NUMBER < 0x10100000 || defined(HAVE_LIBRESSL) + dh->p = p; + dh->g = g; +#else + if (!DH_set0_pqg(dh, p, NULL, g)) + goto err; +#endif + return dh; +err: + if (p) + BN_free(p); + if (g) + BN_free(g); + if (dh) + DH_free(dh); + return NULL; } #endif /* SPLINT */ +#endif /* OPENSSL_VERSION_NUMBER < 0x10100000 */ struct daemon_remote* daemon_remote_create(struct config_file* cfg) @@ -220,21 +242,53 @@ daemon_remote_create(struct config_file* cfg) 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 +#ifdef SHA256_DIGEST_LENGTH + /* 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("coult not set cipher list with SSL_CTX_set_cipher_list"); +#endif if (cfg->remote_control_use_cert == 0) { /* No certificates are requested */ - if(!SSL_CTX_set_cipher_list(rc->ctx, "aNULL")) { +#ifdef HAVE_SSL_CTX_SET_SECURITY_LEVEL + SSL_CTX_set_security_level(rc->ctx, 0); +#endif + if(!SSL_CTX_set_cipher_list(rc->ctx, "aNULL, eNULL")) { log_crypto_err("Failed to set aNULL cipher list"); + daemon_remote_delete(rc); return NULL; } + /* in openssl 1.1, the securitylevel 0 allows eNULL, that + * does not need the DH */ +#if OPENSSL_VERSION_NUMBER < 0x10100000 || defined(HAVE_LIBRESSL) /* Since we have no certificates and hence no source of * DH params, let's generate and set them */ - if(!SSL_CTX_set_tmp_dh(rc->ctx,get_dh1024())) { + if(!SSL_CTX_set_tmp_dh(rc->ctx,get_dh2048())) { log_crypto_err("Wanted to set DH param, but failed"); + daemon_remote_delete(rc); return NULL; } +#endif return rc; } rc->use_cert = 1; @@ -350,7 +404,7 @@ add_open(const char* ip, int nr, struct listen_port** list, int noproto_is_err, if(ip[0] == '/') { /* This looks like a local socket */ - fd = create_local_accept_sock(ip, &noproto); + fd = create_local_accept_sock(ip, &noproto, cfg->use_systemd); /* * Change socket ownership and permissions so users other * than root can access it provided they are in the same @@ -359,8 +413,12 @@ add_open(const char* ip, int nr, struct listen_port** list, int noproto_is_err, if(fd != -1) { #ifdef HAVE_CHOWN if (cfg->username && cfg->username[0] && - cfg_uid != (uid_t)-1) - chown(ip, cfg_uid, cfg_gid); + cfg_uid != (uid_t)-1) { + if(chown(ip, cfg_uid, cfg_gid) == -1) + log_err("cannot chown %u.%u %s: %s", + (unsigned)cfg_uid, (unsigned)cfg_gid, + ip, strerror(errno)); + } chmod(ip, (mode_t)(S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP)); #else (void)cfg; @@ -389,7 +447,7 @@ add_open(const char* ip, int nr, struct listen_port** list, int noproto_is_err, /* open fd */ fd = create_tcp_accept_sock(res, 1, &noproto, 0, - cfg->ip_transparent); + cfg->ip_transparent, 0, cfg->ip_freebind, cfg->use_systemd); freeaddrinfo(res); } @@ -727,6 +785,8 @@ print_stats(SSL* ssl, const char* nm, struct stats_info* s) struct timeval avg; if(!ssl_printf(ssl, "%s.num.queries"SQ"%lu\n", nm, (unsigned long)s->svr.num_queries)) return 0; + if(!ssl_printf(ssl, "%s.num.queries_ip_ratelimited"SQ"%lu\n", nm, + (unsigned long)s->svr.num_queries_ip_ratelimited)) return 0; if(!ssl_printf(ssl, "%s.num.cachehits"SQ"%lu\n", nm, (unsigned long)(s->svr.num_queries - s->svr.num_queries_missed_cache))) return 0; @@ -734,8 +794,20 @@ print_stats(SSL* ssl, const char* nm, struct stats_info* s) (unsigned long)s->svr.num_queries_missed_cache)) return 0; if(!ssl_printf(ssl, "%s.num.prefetch"SQ"%lu\n", nm, (unsigned long)s->svr.num_queries_prefetch)) return 0; + if(!ssl_printf(ssl, "%s.num.zero_ttl"SQ"%lu\n", nm, + (unsigned long)s->svr.zero_ttl_responses)) return 0; if(!ssl_printf(ssl, "%s.num.recursivereplies"SQ"%lu\n", nm, (unsigned long)s->mesh_replies_sent)) return 0; +#ifdef USE_DNSCRYPT + if(!ssl_printf(ssl, "%s.num.dnscrypt.crypted"SQ"%lu\n", nm, + (unsigned long)s->svr.num_query_dnscrypt_crypted)) return 0; + if(!ssl_printf(ssl, "%s.num.dnscrypt.cert"SQ"%lu\n", nm, + (unsigned long)s->svr.num_query_dnscrypt_cert)) return 0; + if(!ssl_printf(ssl, "%s.num.dnscrypt.cleartext"SQ"%lu\n", nm, + (unsigned long)s->svr.num_query_dnscrypt_cleartext)) return 0; + if(!ssl_printf(ssl, "%s.num.dnscrypt.malformed"SQ"%lu\n", nm, + (unsigned long)s->svr.num_query_dnscrypt_crypted_malformed)) return 0; +#endif if(!ssl_printf(ssl, "%s.requestlist.avg"SQ"%g\n", nm, (s->svr.num_queries_missed_cache+s->svr.num_queries_prefetch)? (double)s->svr.sum_query_list_size/ @@ -791,17 +863,15 @@ static int print_mem(SSL* ssl, struct worker* worker, struct daemon* daemon) { int m; - size_t msg, rrset, val, iter; -#ifdef HAVE_SBRK - extern void* unbound_start_brk; - void* cur = sbrk(0); - if(!print_longnum(ssl, "mem.total.sbrk"SQ, - (size_t)((char*)cur - (char*)unbound_start_brk))) return 0; -#endif /* HAVE_SBRK */ + size_t msg, rrset, val, iter, respip; +#ifdef CLIENT_SUBNET + size_t subnet = 0; +#endif /* CLIENT_SUBNET */ msg = slabhash_get_mem(daemon->env->msg_cache); rrset = slabhash_get_mem(&daemon->env->rrset_cache->table); val=0; iter=0; + respip=0; m = modstack_find(&worker->env.mesh->mods, "validator"); if(m != -1) { fptr_ok(fptr_whitelist_mod_get_mem(worker->env.mesh-> @@ -816,6 +886,22 @@ print_mem(SSL* ssl, struct worker* worker, struct daemon* daemon) iter = (*worker->env.mesh->mods.mod[m]->get_mem) (&worker->env, m); } + m = modstack_find(&worker->env.mesh->mods, "respip"); + if(m != -1) { + fptr_ok(fptr_whitelist_mod_get_mem(worker->env.mesh-> + mods.mod[m]->get_mem)); + respip = (*worker->env.mesh->mods.mod[m]->get_mem) + (&worker->env, m); + } +#ifdef CLIENT_SUBNET + m = modstack_find(&worker->env.mesh->mods, "subnet"); + if(m != -1) { + fptr_ok(fptr_whitelist_mod_get_mem(worker->env.mesh-> + mods.mod[m]->get_mem)); + subnet = (*worker->env.mesh->mods.mod[m]->get_mem) + (&worker->env, m); + } +#endif /* CLIENT_SUBNET */ if(!print_longnum(ssl, "mem.cache.rrset"SQ, rrset)) return 0; @@ -825,6 +911,12 @@ print_mem(SSL* ssl, struct worker* worker, struct daemon* daemon) return 0; if(!print_longnum(ssl, "mem.mod.validator"SQ, val)) return 0; + if(!print_longnum(ssl, "mem.mod.respip"SQ, respip)) + return 0; +#ifdef CLIENT_SUBNET + if(!print_longnum(ssl, "mem.mod.subnet"SQ, subnet)) + return 0; +#endif /* CLIENT_SUBNET */ return 1; } @@ -1097,8 +1189,8 @@ find_arg2(SSL* ssl, char* arg, char** arg2) } /** Add a new zone */ -static void -do_zone_add(SSL* ssl, struct worker* worker, char* arg) +static int +perform_zone_add(SSL* ssl, struct local_zones* zones, char* arg) { uint8_t* nm; int nmlabs; @@ -1107,83 +1199,290 @@ do_zone_add(SSL* ssl, struct worker* worker, char* arg) enum localzone_type t; struct local_zone* z; if(!find_arg2(ssl, arg, &arg2)) - return; + return 0; if(!parse_arg_name(ssl, arg, &nm, &nmlen, &nmlabs)) - return; + return 0; if(!local_zone_str2type(arg2, &t)) { ssl_printf(ssl, "error not a zone type. %s\n", arg2); free(nm); - return; + return 0; } - lock_rw_wrlock(&worker->daemon->local_zones->lock); - if((z=local_zones_find(worker->daemon->local_zones, nm, nmlen, + lock_rw_wrlock(&zones->lock); + if((z=local_zones_find(zones, nm, nmlen, nmlabs, LDNS_RR_CLASS_IN))) { /* already present in tree */ lock_rw_wrlock(&z->lock); z->type = t; /* update type anyway */ lock_rw_unlock(&z->lock); free(nm); - lock_rw_unlock(&worker->daemon->local_zones->lock); - send_ok(ssl); - return; + lock_rw_unlock(&zones->lock); + return 1; } - if(!local_zones_add_zone(worker->daemon->local_zones, nm, nmlen, + if(!local_zones_add_zone(zones, nm, nmlen, nmlabs, LDNS_RR_CLASS_IN, t)) { - lock_rw_unlock(&worker->daemon->local_zones->lock); + lock_rw_unlock(&zones->lock); ssl_printf(ssl, "error out of memory\n"); - return; + return 0; } - lock_rw_unlock(&worker->daemon->local_zones->lock); + lock_rw_unlock(&zones->lock); + return 1; +} + +/** Do the local_zone command */ +static void +do_zone_add(SSL* ssl, struct local_zones* zones, char* arg) +{ + if(!perform_zone_add(ssl, zones, arg)) + return; send_ok(ssl); } -/** Remove a zone */ +/** Do the local_zones command */ static void -do_zone_remove(SSL* ssl, struct worker* worker, char* arg) +do_zones_add(SSL* ssl, struct local_zones* zones) +{ + char buf[2048]; + int num = 0; + while(ssl_read_line(ssl, buf, sizeof(buf))) { + if(buf[0] == 0x04 && buf[1] == 0) + break; /* end of transmission */ + if(!perform_zone_add(ssl, zones, buf)) { + if(!ssl_printf(ssl, "error for input line: %s\n", buf)) + return; + } + else + num++; + } + (void)ssl_printf(ssl, "added %d zones\n", num); +} + +/** Remove a zone */ +static int +perform_zone_remove(SSL* ssl, struct local_zones* zones, char* arg) { uint8_t* nm; int nmlabs; size_t nmlen; struct local_zone* z; if(!parse_arg_name(ssl, arg, &nm, &nmlen, &nmlabs)) - return; - lock_rw_wrlock(&worker->daemon->local_zones->lock); - if((z=local_zones_find(worker->daemon->local_zones, nm, nmlen, + return 0; + lock_rw_wrlock(&zones->lock); + if((z=local_zones_find(zones, nm, nmlen, nmlabs, LDNS_RR_CLASS_IN))) { /* present in tree */ - local_zones_del_zone(worker->daemon->local_zones, z); + local_zones_del_zone(zones, z); } - lock_rw_unlock(&worker->daemon->local_zones->lock); + lock_rw_unlock(&zones->lock); free(nm); + return 1; +} + +/** Do the local_zone_remove command */ +static void +do_zone_remove(SSL* ssl, struct local_zones* zones, char* arg) +{ + if(!perform_zone_remove(ssl, zones, arg)) + return; send_ok(ssl); } -/** Add new RR data */ +/** Do the local_zones_remove command */ static void -do_data_add(SSL* ssl, struct worker* worker, char* arg) +do_zones_remove(SSL* ssl, struct local_zones* zones) +{ + char buf[2048]; + int num = 0; + while(ssl_read_line(ssl, buf, sizeof(buf))) { + if(buf[0] == 0x04 && buf[1] == 0) + break; /* end of transmission */ + if(!perform_zone_remove(ssl, zones, buf)) { + if(!ssl_printf(ssl, "error for input line: %s\n", buf)) + return; + } + else + num++; + } + (void)ssl_printf(ssl, "removed %d zones\n", num); +} + +/** Add new RR data */ +static int +perform_data_add(SSL* ssl, struct local_zones* zones, char* arg) { - if(!local_zones_add_RR(worker->daemon->local_zones, arg)) { + if(!local_zones_add_RR(zones, arg)) { ssl_printf(ssl,"error in syntax or out of memory, %s\n", arg); - return; + return 0; } + return 1; +} + +/** Do the local_data command */ +static void +do_data_add(SSL* ssl, struct local_zones* zones, char* arg) +{ + if(!perform_data_add(ssl, zones, arg)) + return; send_ok(ssl); } -/** Remove RR data */ +/** Do the local_datas command */ static void -do_data_remove(SSL* ssl, struct worker* worker, char* arg) +do_datas_add(SSL* ssl, struct local_zones* zones) +{ + char buf[2048]; + int num = 0; + while(ssl_read_line(ssl, buf, sizeof(buf))) { + if(buf[0] == 0x04 && buf[1] == 0) + break; /* end of transmission */ + if(!perform_data_add(ssl, zones, buf)) { + if(!ssl_printf(ssl, "error for input line: %s\n", buf)) + return; + } + else + num++; + } + (void)ssl_printf(ssl, "added %d datas\n", num); +} + +/** Remove RR data */ +static int +perform_data_remove(SSL* ssl, struct local_zones* zones, char* arg) { uint8_t* nm; int nmlabs; size_t nmlen; if(!parse_arg_name(ssl, arg, &nm, &nmlen, &nmlabs)) - return; - local_zones_del_data(worker->daemon->local_zones, nm, + return 0; + local_zones_del_data(zones, nm, nmlen, nmlabs, LDNS_RR_CLASS_IN); free(nm); + return 1; +} + +/** Do the local_data_remove command */ +static void +do_data_remove(SSL* ssl, struct local_zones* zones, char* arg) +{ + if(!perform_data_remove(ssl, zones, arg)) + return; send_ok(ssl); } +/** Do the local_datas_remove command */ +static void +do_datas_remove(SSL* ssl, struct local_zones* zones) +{ + char buf[2048]; + int num = 0; + while(ssl_read_line(ssl, buf, sizeof(buf))) { + if(buf[0] == 0x04 && buf[1] == 0) + break; /* end of transmission */ + if(!perform_data_remove(ssl, zones, buf)) { + if(!ssl_printf(ssl, "error for input line: %s\n", buf)) + return; + } + else + num++; + } + (void)ssl_printf(ssl, "removed %d datas\n", num); +} + +/** Add a new zone to view */ +static void +do_view_zone_add(SSL* ssl, struct worker* worker, char* arg) +{ + char* arg2; + struct view* v; + if(!find_arg2(ssl, arg, &arg2)) + return; + v = views_find_view(worker->daemon->views, + arg, 1 /* get write lock*/); + if(!v) { + ssl_printf(ssl,"no view with name: %s\n", arg); + return; + } + if(!v->local_zones) { + if(!(v->local_zones = local_zones_create())){ + lock_rw_unlock(&v->lock); + ssl_printf(ssl,"error out of memory\n"); + return; + } + } + do_zone_add(ssl, v->local_zones, arg2); + lock_rw_unlock(&v->lock); +} + +/** Remove a zone from view */ +static void +do_view_zone_remove(SSL* ssl, struct worker* worker, char* arg) +{ + char* arg2; + struct view* v; + if(!find_arg2(ssl, arg, &arg2)) + return; + v = views_find_view(worker->daemon->views, + arg, 1 /* get write lock*/); + if(!v) { + ssl_printf(ssl,"no view with name: %s\n", arg); + return; + } + if(!v->local_zones) { + lock_rw_unlock(&v->lock); + send_ok(ssl); + return; + } + do_zone_remove(ssl, v->local_zones, arg2); + lock_rw_unlock(&v->lock); +} + +/** Add new RR data to view */ +static void +do_view_data_add(SSL* ssl, struct worker* worker, char* arg) +{ + char* arg2; + struct view* v; + if(!find_arg2(ssl, arg, &arg2)) + return; + v = views_find_view(worker->daemon->views, + arg, 1 /* get write lock*/); + if(!v) { + ssl_printf(ssl,"no view with name: %s\n", arg); + return; + } + if(!v->local_zones) { + if(!(v->local_zones = local_zones_create())){ + lock_rw_unlock(&v->lock); + ssl_printf(ssl,"error out of memory\n"); + return; + } + } + do_data_add(ssl, v->local_zones, arg2); + lock_rw_unlock(&v->lock); +} + +/** Remove RR data from view */ +static void +do_view_data_remove(SSL* ssl, struct worker* worker, char* arg) +{ + char* arg2; + struct view* v; + if(!find_arg2(ssl, arg, &arg2)) + return; + v = views_find_view(worker->daemon->views, + arg, 1 /* get write lock*/); + if(!v) { + ssl_printf(ssl,"no view with name: %s\n", arg); + return; + } + if(!v->local_zones) { + lock_rw_unlock(&v->lock); + send_ok(ssl); + return; + } + do_data_remove(ssl, v->local_zones, arg2); + lock_rw_unlock(&v->lock); +} + /** cache lookup of nameservers */ static void do_lookup(SSL* ssl, struct worker* worker, char* arg) @@ -1202,7 +1501,7 @@ static void do_cache_remove(struct worker* worker, uint8_t* nm, size_t nmlen, uint16_t t, uint16_t c) { - hashvalue_t h; + hashvalue_type h; struct query_info k; rrset_cache_remove(worker->env.rrset_cache, nm, nmlen, t, c, 0); if(t == LDNS_RR_TYPE_SOA) @@ -1212,6 +1511,7 @@ do_cache_remove(struct worker* worker, uint8_t* nm, size_t nmlen, k.qname_len = nmlen; k.qtype = t; k.qclass = c; + k.local_alias = NULL; h = query_info_hash(&k, 0); slabhash_remove(worker->env.msg_cache, h, &k); if(t == LDNS_RR_TYPE_AAAA) { @@ -2157,6 +2457,14 @@ do_set_option(SSL* ssl, struct worker* worker, char* arg) (void)ssl_printf(ssl, "error setting option\n"); return; } + /* effectuate some arguments */ + if(strcmp(arg, "val-override-date:") == 0) { + int m = modstack_find(&worker->env.mesh->mods, "validator"); + struct val_env* val_env = NULL; + if(m != -1) val_env = (struct val_env*)worker->env.modinfo[m]; + if(val_env) + val_env->date_override = worker->env.cfg->val_date_override; + } send_ok(ssl); } @@ -2237,9 +2545,8 @@ do_list_stubs(SSL* ssl, struct worker* worker) /** do the list_local_zones command */ static void -do_list_local_zones(SSL* ssl, struct worker* worker) +do_list_local_zones(SSL* ssl, struct local_zones* zones) { - struct local_zones* zones = worker->daemon->local_zones; struct local_zone* z; char buf[257]; lock_rw_rdlock(&zones->lock); @@ -2260,9 +2567,8 @@ do_list_local_zones(SSL* ssl, struct worker* worker) /** do the list_local_data command */ static void -do_list_local_data(SSL* ssl, struct worker* worker) +do_list_local_data(SSL* ssl, struct worker* worker, struct local_zones* zones) { - struct local_zones* zones = worker->daemon->local_zones; struct local_zone* z; struct local_data* d; struct local_rrset* p; @@ -2298,6 +2604,38 @@ do_list_local_data(SSL* ssl, struct worker* worker) lock_rw_unlock(&zones->lock); } +/** do the view_list_local_zones command */ +static void +do_view_list_local_zones(SSL* ssl, struct worker* worker, char* arg) +{ + struct view* v = views_find_view(worker->daemon->views, + arg, 0 /* get read lock*/); + if(!v) { + ssl_printf(ssl,"no view with name: %s\n", arg); + return; + } + if(v->local_zones) { + do_list_local_zones(ssl, v->local_zones); + } + lock_rw_unlock(&v->lock); +} + +/** do the view_list_local_data command */ +static void +do_view_list_local_data(SSL* ssl, struct worker* worker, char* arg) +{ + struct view* v = views_find_view(worker->daemon->views, + arg, 0 /* get read lock*/); + if(!v) { + ssl_printf(ssl,"no view with name: %s\n", arg); + return; + } + if(v->local_zones) { + do_list_local_data(ssl, worker, v->local_zones); + } + lock_rw_unlock(&v->lock); +} + /** struct for user arg ratelimit list */ struct ratelimit_list_arg { /** the infra cache */ @@ -2310,6 +2648,8 @@ struct ratelimit_list_arg { time_t now; }; +#define ip_ratelimit_list_arg ratelimit_list_arg + /** list items in the ratelimit table */ static void rate_list(struct lruhash_entry* e, void* arg) @@ -2328,6 +2668,24 @@ rate_list(struct lruhash_entry* e, void* arg) ssl_printf(a->ssl, "%s %d limit %d\n", buf, max, lim); } +/** list items in the ip_ratelimit table */ +static void +ip_rate_list(struct lruhash_entry* e, void* arg) +{ + char ip[128]; + struct ip_ratelimit_list_arg* a = (struct ip_ratelimit_list_arg*)arg; + struct ip_rate_key* k = (struct ip_rate_key*)e->key; + struct ip_rate_data* d = (struct ip_rate_data*)e->data; + int lim = infra_ip_ratelimit; + int max = infra_rate_max(d, a->now); + if(a->all == 0) { + if(max < lim) + return; + } + addr_to_str(&k->addr, k->addrlen, ip, sizeof(ip)); + ssl_printf(a->ssl, "%s %d limit %d\n", ip, max, lim); +} + /** do the ratelimit_list command */ static void do_ratelimit_list(SSL* ssl, struct worker* worker, char* arg) @@ -2346,6 +2704,24 @@ do_ratelimit_list(SSL* ssl, struct worker* worker, char* arg) slabhash_traverse(a.infra->domain_rates, 0, rate_list, &a); } +/** do the ip_ratelimit_list command */ +static void +do_ip_ratelimit_list(SSL* ssl, struct worker* worker, char* arg) +{ + struct ip_ratelimit_list_arg a; + a.all = 0; + a.infra = worker->env.infra_cache; + a.now = *worker->env.now; + a.ssl = ssl; + arg = skipwhite(arg); + if(strcmp(arg, "+a") == 0) + a.all = 1; + if(a.infra->client_ip_rates==NULL || + (a.all == 0 && infra_ip_ratelimit == 0)) + return; + slabhash_traverse(a.infra->client_ip_rates, 0, ip_rate_list, &a); +} + /** tell other processes to execute the command */ static void distribute_cmd(struct daemon_remote* rc, SSL* ssl, char* cmd) @@ -2410,14 +2786,23 @@ execute_cmd(struct daemon_remote* rc, SSL* ssl, char* cmd, do_insecure_list(ssl, worker); return; } else if(cmdcmp(p, "list_local_zones", 16)) { - do_list_local_zones(ssl, worker); + do_list_local_zones(ssl, worker->daemon->local_zones); return; } else if(cmdcmp(p, "list_local_data", 15)) { - do_list_local_data(ssl, worker); + do_list_local_data(ssl, worker, worker->daemon->local_zones); + return; + } else if(cmdcmp(p, "view_list_local_zones", 21)) { + do_view_list_local_zones(ssl, worker, skipwhite(p+21)); + return; + } else if(cmdcmp(p, "view_list_local_data", 20)) { + do_view_list_local_data(ssl, worker, skipwhite(p+20)); return; } else if(cmdcmp(p, "ratelimit_list", 14)) { do_ratelimit_list(ssl, worker, p+14); return; + } else if(cmdcmp(p, "ip_ratelimit_list", 17)) { + do_ip_ratelimit_list(ssl, worker, p+17); + return; } else if(cmdcmp(p, "stub_add", 8)) { /* must always distribute this cmd */ if(rc) distribute_cmd(rc, ssl, cmd); @@ -2479,13 +2864,29 @@ execute_cmd(struct daemon_remote* rc, SSL* ssl, char* cmd, if(cmdcmp(p, "verbosity", 9)) { do_verbosity(ssl, skipwhite(p+9)); } else if(cmdcmp(p, "local_zone_remove", 17)) { - do_zone_remove(ssl, worker, skipwhite(p+17)); + do_zone_remove(ssl, worker->daemon->local_zones, skipwhite(p+17)); + } else if(cmdcmp(p, "local_zones_remove", 18)) { + do_zones_remove(ssl, worker->daemon->local_zones); } else if(cmdcmp(p, "local_zone", 10)) { - do_zone_add(ssl, worker, skipwhite(p+10)); + do_zone_add(ssl, worker->daemon->local_zones, skipwhite(p+10)); + } else if(cmdcmp(p, "local_zones", 11)) { + do_zones_add(ssl, worker->daemon->local_zones); } else if(cmdcmp(p, "local_data_remove", 17)) { - do_data_remove(ssl, worker, skipwhite(p+17)); + do_data_remove(ssl, worker->daemon->local_zones, skipwhite(p+17)); + } else if(cmdcmp(p, "local_datas_remove", 18)) { + do_datas_remove(ssl, worker->daemon->local_zones); } else if(cmdcmp(p, "local_data", 10)) { - do_data_add(ssl, worker, skipwhite(p+10)); + do_data_add(ssl, worker->daemon->local_zones, skipwhite(p+10)); + } else if(cmdcmp(p, "local_datas", 11)) { + do_datas_add(ssl, worker->daemon->local_zones); + } else if(cmdcmp(p, "view_local_zone_remove", 22)) { + do_view_zone_remove(ssl, worker, skipwhite(p+22)); + } else if(cmdcmp(p, "view_local_zone", 15)) { + do_view_zone_add(ssl, worker, skipwhite(p+15)); + } else if(cmdcmp(p, "view_local_data_remove", 22)) { + do_view_data_remove(ssl, worker, skipwhite(p+22)); + } else if(cmdcmp(p, "view_local_data", 15)) { + do_view_data_add(ssl, worker, skipwhite(p+15)); } else if(cmdcmp(p, "flush_zone", 10)) { do_flush_zone(ssl, worker, skipwhite(p+10)); } else if(cmdcmp(p, "flush_type", 10)) { diff --git a/external/unbound/daemon/remote.h b/external/unbound/daemon/remote.h index b25bfb1af..190286d47 100644 --- a/external/unbound/daemon/remote.h +++ b/external/unbound/daemon/remote.h @@ -56,8 +56,8 @@ struct comm_reply; struct comm_point; struct daemon_remote; -/** number of seconds timeout on incoming remote control handshake */ -#define REMOTE_CONTROL_TCP_TIMEOUT 120 +/** number of milliseconds timeout on incoming remote control handshake */ +#define REMOTE_CONTROL_TCP_TIMEOUT 120000 /** * a busy control command connection, SSL state diff --git a/external/unbound/daemon/stats.c b/external/unbound/daemon/stats.c index 838cf05ae..3665616be 100644 --- a/external/unbound/daemon/stats.c +++ b/external/unbound/daemon/stats.c @@ -102,12 +102,14 @@ void server_stats_log(struct server_stats* stats, struct worker* worker, int threadnum) { log_info("server stats for thread %d: %u queries, " - "%u answers from cache, %u recursions, %u prefetch", + "%u answers from cache, %u recursions, %u prefetch, %u rejected by " + "ip ratelimiting", threadnum, (unsigned)stats->num_queries, (unsigned)(stats->num_queries - stats->num_queries_missed_cache), (unsigned)stats->num_queries_missed_cache, - (unsigned)stats->num_queries_prefetch); + (unsigned)stats->num_queries_prefetch, + (unsigned)stats->num_queries_ip_ratelimited); log_info("server stats for thread %d: requestlist max %u avg %g " "exceeded %u jostled %u", threadnum, (unsigned)stats->max_query_list_size, @@ -226,9 +228,18 @@ void server_stats_reply(struct worker* worker, int reset) void server_stats_add(struct stats_info* total, struct stats_info* a) { total->svr.num_queries += a->svr.num_queries; + total->svr.num_queries_ip_ratelimited += a->svr.num_queries_ip_ratelimited; total->svr.num_queries_missed_cache += a->svr.num_queries_missed_cache; total->svr.num_queries_prefetch += a->svr.num_queries_prefetch; total->svr.sum_query_list_size += a->svr.sum_query_list_size; +#ifdef USE_DNSCRYPT + total->svr.num_query_dnscrypt_crypted += a->svr.num_query_dnscrypt_crypted; + total->svr.num_query_dnscrypt_cert += a->svr.num_query_dnscrypt_cert; + total->svr.num_query_dnscrypt_cleartext += \ + a->svr.num_query_dnscrypt_cleartext; + total->svr.num_query_dnscrypt_crypted_malformed += \ + a->svr.num_query_dnscrypt_crypted_malformed; +#endif /* 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; @@ -251,6 +262,7 @@ void server_stats_add(struct stats_info* total, struct stats_info* a) total->svr.qEDNS += a->svr.qEDNS; total->svr.qEDNS_DO += a->svr.qEDNS_DO; total->svr.ans_rcode_nodata += a->svr.ans_rcode_nodata; + 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; diff --git a/external/unbound/daemon/stats.h b/external/unbound/daemon/stats.h index 6985446ce..39c4d21c5 100644 --- a/external/unbound/daemon/stats.h +++ b/external/unbound/daemon/stats.h @@ -43,6 +43,7 @@ #ifndef DAEMON_STATS_H #define DAEMON_STATS_H #include "util/timehist.h" +#include "dnscrypt/dnscrypt_config.h" struct worker; struct config_file; struct comm_point; @@ -63,6 +64,8 @@ struct sldns_buffer; struct server_stats { /** number of queries from clients received. */ size_t num_queries; + /** number of queries that have been dropped/ratelimited by ip. */ + size_t num_queries_ip_ratelimited; /** number of queries that had a cache-miss. */ size_t num_queries_missed_cache; /** number of prefetch queries - cachehits with prefetch */ @@ -131,7 +134,8 @@ struct server_stats { size_t unwanted_queries; /** usage of tcp accept list */ size_t tcp_accept_usage; - + /** answers served from expired cache */ + size_t zero_ttl_responses; /** histogram data exported to array * if the array is the same size, no data is lost, and * if all histograms are same size (is so by default) then @@ -146,6 +150,16 @@ struct server_stats { size_t infra_cache_count; /** number of key cache entries */ size_t key_cache_count; +#ifdef USE_DNSCRYPT + /** number of queries that used dnscrypt */ + size_t num_query_dnscrypt_crypted; + /** number of queries that queried dnscrypt certificates */ + size_t num_query_dnscrypt_cert; + /** number of queries in clear text and not asking for the certificates */ + size_t num_query_dnscrypt_cleartext; + /** number of malformed encrypted queries */ + size_t num_query_dnscrypt_crypted_malformed; +#endif }; /** diff --git a/external/unbound/daemon/unbound.c b/external/unbound/daemon/unbound.c index 0ceee538c..ba7337d89 100644 --- a/external/unbound/daemon/unbound.c +++ b/external/unbound/daemon/unbound.c @@ -57,6 +57,7 @@ #include "util/data/msgreply.h" #include "util/module.h" #include "util/net_help.h" +#include "util/ub_event.h" #include <signal.h> #include <fcntl.h> #include <openssl/crypto.h> @@ -77,22 +78,6 @@ #include <login_cap.h> #endif -#ifdef USE_MINI_EVENT -# ifdef USE_WINSOCK -# include "util/winsock_event.h" -# else -# include "util/mini_event.h" -# endif -#else -# ifdef HAVE_EVENT_H -# include <event.h> -# else -# include "event2/event.h" -# include "event2/event_struct.h" -# include "event2/event_compat.h" -# endif -#endif - #ifdef UB_ON_WINDOWS # include "winrc/win_svc.h" #endif @@ -102,64 +87,14 @@ # include "nss.h" #endif -#ifdef HAVE_SBRK -/** global debug value to keep track of heap memory allocation */ -void* unbound_start_brk = 0; -#endif - -#if !defined(HAVE_EVENT_BASE_GET_METHOD) && (defined(HAVE_EV_LOOP) || defined(HAVE_EV_DEFAULT_LOOP)) -static const char* ev_backend2str(int b) -{ - switch(b) { - case EVBACKEND_SELECT: return "select"; - case EVBACKEND_POLL: return "poll"; - case EVBACKEND_EPOLL: return "epoll"; - case EVBACKEND_KQUEUE: return "kqueue"; - case EVBACKEND_DEVPOLL: return "devpoll"; - case EVBACKEND_PORT: return "evport"; - } - return "unknown"; -} -#endif - -/** get the event system in use */ -static void get_event_sys(const char** n, const char** s, const char** m) -{ -#ifdef USE_WINSOCK - *n = "event"; - *s = "winsock"; - *m = "WSAWaitForMultipleEvents"; -#elif defined(USE_MINI_EVENT) - *n = "mini-event"; - *s = "internal"; - *m = "select"; -#else - struct event_base* b; - *s = event_get_version(); -# ifdef HAVE_EVENT_BASE_GET_METHOD - *n = "libevent"; - b = event_base_new(); - *m = event_base_get_method(b); -# elif defined(HAVE_EV_LOOP) || defined(HAVE_EV_DEFAULT_LOOP) - *n = "libev"; - b = (struct event_base*)ev_default_loop(EVFLAG_AUTO); - *m = ev_backend2str(ev_backend((struct ev_loop*)b)); -# else - *n = "unknown"; - *m = "not obtainable"; - b = NULL; -# endif -# ifdef HAVE_EVENT_BASE_FREE - event_base_free(b); -# endif -#endif -} - /** print usage. */ -static void usage() +static void usage(void) { const char** m; const char *evnm="event", *evsys="", *evmethod=""; + time_t t; + struct timeval now; + struct ub_event_base* base; printf("usage: unbound [options]\n"); printf(" start unbound daemon DNS resolver.\n"); printf("-h this help\n"); @@ -173,11 +108,16 @@ static void usage() printf(" service - used to start from services control panel\n"); #endif printf("Version %s\n", PACKAGE_VERSION); - get_event_sys(&evnm, &evsys, &evmethod); + base = ub_default_event_base(0,&t,&now); + ub_get_event_sys(base, &evnm, &evsys, &evmethod); printf("linked libs: %s %s (it uses %s), %s\n", evnm, evsys, evmethod, #ifdef HAVE_SSL +# ifdef SSLEAY_VERSION SSLeay_version(SSLEAY_VERSION) +# else + OpenSSL_version(OPENSSL_VERSION) +# endif #elif defined(HAVE_NSS) NSS_GetVersion() #elif defined(HAVE_NETTLE) @@ -190,6 +130,7 @@ static void usage() printf("\n"); printf("BSD licensed, see LICENSE in source package for details.\n"); printf("Report bugs to %s\n", PACKAGE_BUGREPORT); + ub_event_base_free(base); } #ifndef unbound_testbound @@ -230,7 +171,7 @@ checkrlimits(struct config_file* cfg) struct rlimit rlim; if(total > 1024 && - strncmp(event_get_version(), "mini-event", 10) == 0) { + strncmp(ub_event_get_version(), "mini-event", 10) == 0) { log_warn("too many file descriptors requested. The builtin" "mini-event cannot handle more than 1024. Config " "for less fds or compile with libevent"); @@ -244,7 +185,7 @@ checkrlimits(struct config_file* cfg) total = 1024; } if(perthread > 64 && - strncmp(event_get_version(), "winsock-event", 13) == 0) { + strncmp(ub_event_get_version(), "winsock-event", 13) == 0) { log_err("too many file descriptors requested. The winsock" " event handler cannot handle more than 64 per " " thread. Config for less fds"); @@ -298,19 +239,37 @@ checkrlimits(struct config_file* cfg) #endif /* S_SPLINT_S */ } +/** set default logfile identity based on value from argv[0] at startup **/ +static void +log_ident_set_fromdefault(struct config_file* cfg, + const char *log_default_identity) +{ + if(cfg->log_identity == NULL || cfg->log_identity[0] == 0) + log_ident_set(log_default_identity); + else + log_ident_set(cfg->log_identity); +} + /** set verbosity, check rlimits, cache settings */ static void apply_settings(struct daemon* daemon, struct config_file* cfg, - int cmdline_verbose, int debug_mode) + int cmdline_verbose, int debug_mode, const char* log_default_identity) { /* apply if they have changed */ verbosity = cmdline_verbose + cfg->verbosity; if (debug_mode > 1) { cfg->use_syslog = 0; + free(cfg->logfile); cfg->logfile = NULL; } daemon_apply_cfg(daemon, cfg); checkrlimits(cfg); + + if (cfg->use_systemd && cfg->do_daemonize) { + log_warn("use-systemd and do-daemonize should not be enabled at the same time"); + } + + log_ident_set_fromdefault(cfg, log_default_identity); } #ifdef HAVE_KILL @@ -443,6 +402,9 @@ static void perform_setup(struct daemon* daemon, struct config_file* cfg, int debug_mode, const char** cfgfile) { +#ifdef HAVE_KILL + int pidinchroot; +#endif #ifdef HAVE_GETPWNAM struct passwd *pwd = NULL; @@ -481,6 +443,12 @@ perform_setup(struct daemon* daemon, struct config_file* cfg, int debug_mode, #endif #ifdef HAVE_KILL + /* true if pidfile is inside chrootdir, or nochroot */ + pidinchroot = !(cfg->chrootdir && cfg->chrootdir[0]) || + (cfg->chrootdir && cfg->chrootdir[0] && + strncmp(cfg->pidfile, cfg->chrootdir, + strlen(cfg->chrootdir))==0); + /* check old pid file before forking */ if(cfg->pidfile && cfg->pidfile[0]) { /* calculate position of pidfile */ @@ -490,12 +458,7 @@ perform_setup(struct daemon* daemon, struct config_file* cfg, int debug_mode, cfg, 1); if(!daemon->pidfile) fatal_exit("pidfile alloc: out of memory"); - checkoldpid(daemon->pidfile, - /* true if pidfile is inside chrootdir, or nochroot */ - !(cfg->chrootdir && cfg->chrootdir[0]) || - (cfg->chrootdir && cfg->chrootdir[0] && - strncmp(daemon->pidfile, cfg->chrootdir, - strlen(cfg->chrootdir))==0)); + checkoldpid(daemon->pidfile, pidinchroot); } #endif @@ -508,10 +471,11 @@ perform_setup(struct daemon* daemon, struct config_file* cfg, int debug_mode, #ifdef HAVE_KILL if(cfg->pidfile && cfg->pidfile[0]) { writepid(daemon->pidfile, getpid()); - if(cfg->username && cfg->username[0] && cfg_uid != (uid_t)-1) { + if(cfg->username && cfg->username[0] && cfg_uid != (uid_t)-1 && + pidinchroot) { # ifdef HAVE_CHOWN if(chown(daemon->pidfile, 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, daemon->pidfile, strerror(errno)); } @@ -597,7 +561,9 @@ perform_setup(struct daemon* daemon, struct config_file* cfg, int debug_mode, log_warn("unable to initgroups %s: %s", cfg->username, strerror(errno)); # endif /* HAVE_INITGROUPS */ +# ifdef HAVE_ENDPWENT endpwent(); +# endif #ifdef HAVE_SETRESGID if(setresgid(cfg_gid,cfg_gid,cfg_gid) != 0) @@ -633,9 +599,10 @@ perform_setup(struct daemon* daemon, struct config_file* cfg, int debug_mode, * @param cmdline_verbose: verbosity resulting from commandline -v. * 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 */ static void -run_daemon(const char* cfgfile, int cmdline_verbose, int debug_mode) +run_daemon(const char* cfgfile, int cmdline_verbose, int debug_mode, const char* log_default_identity) { struct config_file* cfg = NULL; struct daemon* daemon = NULL; @@ -657,7 +624,7 @@ run_daemon(const char* cfgfile, int cmdline_verbose, int debug_mode) cfgfile); log_warn("Continuing with default config settings"); } - apply_settings(daemon, cfg, cmdline_verbose, debug_mode); + apply_settings(daemon, cfg, cmdline_verbose, debug_mode, log_default_identity); if(!done_setup) config_lookup_uid(cfg); @@ -665,7 +632,7 @@ run_daemon(const char* cfgfile, int cmdline_verbose, int debug_mode) 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); done_setup = 1; } else { /* reopen log after HUP to facilitate log rotation */ @@ -712,19 +679,16 @@ main(int argc, char* argv[]) int c; const char* cfgfile = CONFIGFILE; const char* winopt = NULL; + const char* log_ident_default; int cmdline_verbose = 0; int debug_mode = 0; #ifdef UB_ON_WINDOWS int cmdline_cfg = 0; #endif -#ifdef HAVE_SBRK - /* take debug snapshot of heap */ - unbound_start_brk = sbrk(0); -#endif - log_init(NULL, 0, NULL); - log_ident_set(strrchr(argv[0],'/')?strrchr(argv[0],'/')+1:argv[0]); + 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) { switch(c) { @@ -735,7 +699,7 @@ main(int argc, char* argv[]) #endif break; case 'v': - cmdline_verbose ++; + cmdline_verbose++; verbosity++; break; case 'd': @@ -768,7 +732,7 @@ main(int argc, char* argv[]) return 1; } - run_daemon(cfgfile, cmdline_verbose, debug_mode); + run_daemon(cfgfile, cmdline_verbose, debug_mode, log_ident_default); log_init(NULL, 0, NULL); /* close logfile */ return 0; } diff --git a/external/unbound/daemon/worker.c b/external/unbound/daemon/worker.c index c90a65998..b1cc974aa 100644 --- a/external/unbound/daemon/worker.c +++ b/external/unbound/daemon/worker.c @@ -69,9 +69,13 @@ #include "iterator/iter_hints.h" #include "validator/autotrust.h" #include "validator/val_anchor.h" +#include "respip/respip.h" #include "libunbound/context.h" #include "libunbound/libworker.h" #include "sldns/sbuffer.h" +#include "sldns/wire2str.h" +#include "util/shm_side/shm_main.h" +#include "dnscrypt/dnscrypt.h" #ifdef HAVE_SYS_TYPES_H # include <sys/types.h> @@ -101,61 +105,21 @@ */ #define PREFETCH_EXPIRY_ADD 60 -#ifdef UNBOUND_ALLOC_STATS -/** measure memory leakage */ -static void -debug_memleak(size_t accounted, size_t heap, - size_t total_alloc, size_t total_free) -{ - static int init = 0; - static size_t base_heap, base_accounted, base_alloc, base_free; - size_t base_af, cur_af, grow_af, grow_acc; - if(!init) { - init = 1; - base_heap = heap; - base_accounted = accounted; - base_alloc = total_alloc; - base_free = total_free; - } - base_af = base_alloc - base_free; - cur_af = total_alloc - total_free; - grow_af = cur_af - base_af; - grow_acc = accounted - base_accounted; - log_info("Leakage: %d leaked. growth: %u use, %u acc, %u heap", - (int)(grow_af - grow_acc), (unsigned)grow_af, - (unsigned)grow_acc, (unsigned)(heap - base_heap)); -} - -/** give debug heap size indication */ -static void -debug_total_mem(size_t calctotal) -{ -#ifdef HAVE_SBRK - extern void* unbound_start_brk; - extern size_t unbound_mem_alloc, unbound_mem_freed; - void* cur = sbrk(0); - int total = cur-unbound_start_brk; - log_info("Total heap memory estimate: %u total-alloc: %u " - "total-free: %u", (unsigned)total, - (unsigned)unbound_mem_alloc, (unsigned)unbound_mem_freed); - debug_memleak(calctotal, (size_t)total, - unbound_mem_alloc, unbound_mem_freed); -#else - (void)calctotal; -#endif /* HAVE_SBRK */ -} -#endif /* UNBOUND_ALLOC_STATS */ - /** Report on memory usage by this thread and global */ static void worker_mem_report(struct worker* ATTR_UNUSED(worker), struct serviced_query* ATTR_UNUSED(cur_serv)) { #ifdef UNBOUND_ALLOC_STATS + /* measure memory leakage */ + extern size_t unbound_mem_alloc, unbound_mem_freed; /* debug func in validator module */ size_t total, front, back, mesh, msg, rrset, infra, ac, superac; size_t me, iter, val, anch; int i; +#ifdef CLIENT_SUBNET + size_t subnet = 0; +#endif /* CLIENT_SUBNET */ if(verbosity < VERB_ALGO) return; front = listen_get_mem(worker->front); @@ -175,6 +139,12 @@ worker_mem_report(struct worker* ATTR_UNUSED(worker), if(strcmp(worker->env.mesh->mods.mod[i]->name, "validator")==0) val += (*worker->env.mesh->mods.mod[i]->get_mem) (&worker->env, i); +#ifdef CLIENT_SUBNET + else if(strcmp(worker->env.mesh->mods.mod[i]->name, + "subnet")==0) + subnet += (*worker->env.mesh->mods.mod[i]->get_mem) + (&worker->env, i); +#endif /* CLIENT_SUBNET */ else iter += (*worker->env.mesh->mods.mod[i]->get_mem) (&worker->env, i); } @@ -192,6 +162,17 @@ worker_mem_report(struct worker* ATTR_UNUSED(worker), me += serviced_get_mem(cur_serv); } total = front+back+mesh+msg+rrset+infra+iter+val+ac+superac+me; +#ifdef CLIENT_SUBNET + total += subnet; + log_info("Memory conditions: %u front=%u back=%u mesh=%u msg=%u " + "rrset=%u infra=%u iter=%u val=%u subnet=%u anchors=%u " + "alloccache=%u globalalloccache=%u me=%u", + (unsigned)total, (unsigned)front, (unsigned)back, + (unsigned)mesh, (unsigned)msg, (unsigned)rrset, (unsigned)infra, + (unsigned)iter, (unsigned)val, + (unsigned)subnet, (unsigned)anch, (unsigned)ac, + (unsigned)superac, (unsigned)me); +#else /* no CLIENT_SUBNET */ log_info("Memory conditions: %u front=%u back=%u mesh=%u msg=%u " "rrset=%u infra=%u iter=%u val=%u anchors=%u " "alloccache=%u globalalloccache=%u me=%u", @@ -199,9 +180,15 @@ worker_mem_report(struct worker* ATTR_UNUSED(worker), (unsigned)mesh, (unsigned)msg, (unsigned)rrset, (unsigned)infra, (unsigned)iter, (unsigned)val, (unsigned)anch, (unsigned)ac, (unsigned)superac, (unsigned)me); - debug_total_mem(total); +#endif /* CLIENT_SUBNET */ + log_info("Total heap memory estimate: %u total-alloc: %u " + "total-free: %u", (unsigned)total, + (unsigned)unbound_mem_alloc, (unsigned)unbound_mem_freed); #else /* no UNBOUND_ALLOC_STATS */ size_t val = 0; +#ifdef CLIENT_SUBNET + size_t subnet = 0; +#endif /* CLIENT_SUBNET */ int i; if(verbosity < VERB_QUERY) return; @@ -211,12 +198,27 @@ worker_mem_report(struct worker* ATTR_UNUSED(worker), if(strcmp(worker->env.mesh->mods.mod[i]->name, "validator")==0) val += (*worker->env.mesh->mods.mod[i]->get_mem) (&worker->env, i); +#ifdef CLIENT_SUBNET + else if(strcmp(worker->env.mesh->mods.mod[i]->name, + "subnet")==0) + subnet += (*worker->env.mesh->mods.mod[i]->get_mem) + (&worker->env, i); +#endif /* CLIENT_SUBNET */ } +#ifdef CLIENT_SUBNET + verbose(VERB_QUERY, "cache memory msg=%u rrset=%u infra=%u val=%u " + "subnet=%u", + (unsigned)slabhash_get_mem(worker->env.msg_cache), + (unsigned)slabhash_get_mem(&worker->env.rrset_cache->table), + (unsigned)infra_get_mem(worker->env.infra_cache), + (unsigned)val, (unsigned)subnet); +#else /* no CLIENT_SUBNET */ verbose(VERB_QUERY, "cache memory msg=%u rrset=%u infra=%u val=%u", (unsigned)slabhash_get_mem(worker->env.msg_cache), (unsigned)slabhash_get_mem(&worker->env.rrset_cache->table), (unsigned)infra_get_mem(worker->env.infra_cache), (unsigned)val); +#endif /* CLIENT_SUBNET */ #endif /* UNBOUND_ALLOC_STATS */ } @@ -483,15 +485,17 @@ answer_norec_from_cache(struct worker* worker, struct query_info* qinfo, qinfo->qname_len, qinfo->qtype, qinfo->qclass, worker->scratchpad, &msg, timenow); if(!dp) { /* no delegation, need to reprime */ - regional_free_all(worker->scratchpad); return 0; } + /* In case we have a local alias, copy it into the delegation message. + * Shallow copy should be fine, as we'll be done with msg in this + * function. */ + msg->qinfo.local_alias = qinfo->local_alias; if(must_validate) { switch(check_delegation_secure(msg->rep)) { case sec_status_unchecked: /* some rrsets have not been verified yet, go and * let validator do that */ - regional_free_all(worker->scratchpad); return 0; case sec_status_bogus: /* some rrsets are bogus, reply servfail */ @@ -499,9 +503,11 @@ answer_norec_from_cache(struct worker* worker, struct query_info* qinfo, edns->udp_size = EDNS_ADVERTISED_SIZE; edns->ext_rcode = 0; edns->bits &= EDNS_DO; + if(!inplace_cb_reply_servfail_call(&worker->env, qinfo, NULL, + msg->rep, LDNS_RCODE_SERVFAIL, edns, worker->scratchpad)) + return 0; error_encode(repinfo->c->buffer, LDNS_RCODE_SERVFAIL, &msg->qinfo, id, flags, edns); - regional_free_all(worker->scratchpad); if(worker->stats.extended) { worker->stats.ans_bogus++; worker->stats.ans_rcode[LDNS_RCODE_SERVFAIL]++; @@ -527,14 +533,19 @@ answer_norec_from_cache(struct worker* worker, struct query_info* qinfo, edns->udp_size = EDNS_ADVERTISED_SIZE; edns->ext_rcode = 0; edns->bits &= EDNS_DO; + if(!inplace_cb_reply_cache_call(&worker->env, qinfo, NULL, msg->rep, + (int)(flags&LDNS_RCODE_MASK), edns, worker->scratchpad)) + return 0; msg->rep->flags |= BIT_QR|BIT_RA; if(!reply_info_answer_encode(&msg->qinfo, msg->rep, id, flags, repinfo->c->buffer, 0, 1, worker->scratchpad, udpsize, edns, (int)(edns->bits & EDNS_DO), secure)) { + if(!inplace_cb_reply_servfail_call(&worker->env, qinfo, NULL, NULL, + LDNS_RCODE_SERVFAIL, edns, worker->scratchpad)) + edns->opt_list = NULL; error_encode(repinfo->c->buffer, LDNS_RCODE_SERVFAIL, &msg->qinfo, id, flags, edns); } - regional_free_all(worker->scratchpad); if(worker->stats.extended) { if(secure) worker->stats.ans_secure++; server_stats_insrcode(&worker->stats, repinfo->c->buffer); @@ -542,28 +553,93 @@ answer_norec_from_cache(struct worker* worker, struct query_info* qinfo, return 1; } -/** answer query from the cache */ +/** Apply, if applicable, a response IP action to a cached answer. + * If the answer is rewritten as a result of an action, '*encode_repp' will + * point to the reply info containing the modified answer. '*encode_repp' will + * be intact otherwise. + * It returns 1 on success, 0 otherwise. */ +static int +apply_respip_action(struct worker* worker, const struct query_info* qinfo, + struct respip_client_info* cinfo, struct reply_info* rep, + struct comm_reply* repinfo, struct ub_packed_rrset_key** alias_rrset, + struct reply_info** encode_repp) +{ + struct respip_action_info actinfo = {respip_none, NULL}; + + if(qinfo->qtype != LDNS_RR_TYPE_A && + qinfo->qtype != LDNS_RR_TYPE_AAAA && + qinfo->qtype != LDNS_RR_TYPE_ANY) + return 1; + + if(!respip_rewrite_reply(qinfo, cinfo, rep, encode_repp, &actinfo, + alias_rrset, 0, worker->scratchpad)) + return 0; + + /* xxx_deny actions mean dropping the reply, unless the original reply + * was redirected to response-ip data. */ + if((actinfo.action == respip_deny || + actinfo.action == respip_inform_deny) && + *encode_repp == rep) + *encode_repp = NULL; + + /* If address info is returned, it means the action should be an + * 'inform' variant and the information should be logged. */ + if(actinfo.addrinfo) { + respip_inform_print(actinfo.addrinfo, qinfo->qname, + qinfo->qtype, qinfo->qclass, qinfo->local_alias, + repinfo); + } + + return 1; +} + +/** answer query from the cache. + * Normally, the answer message will be built in repinfo->c->buffer; if the + * answer is supposed to be suppressed or the answer is supposed to be an + * incomplete CNAME chain, the buffer is explicitly cleared to signal the + * caller as such. In the latter case *partial_rep will point to the incomplete + * reply, and this function is (possibly) supposed to be called again with that + * *partial_rep value to complete the chain. In addition, if the query should + * be completely dropped, '*need_drop' will be set to 1. */ static int answer_from_cache(struct worker* worker, struct query_info* qinfo, + struct respip_client_info* cinfo, int* need_drop, + struct ub_packed_rrset_key** alias_rrset, + struct reply_info** partial_repp, struct reply_info* rep, uint16_t id, uint16_t flags, struct comm_reply* repinfo, struct edns_data* edns) { time_t timenow = *worker->env.now; uint16_t udpsize = edns->udp_size; + struct reply_info* encode_rep = rep; + struct reply_info* partial_rep = *partial_repp; int secure; int must_validate = (!(flags&BIT_CD) || worker->env.cfg->ignore_cd) && worker->env.need_to_validate; - /* see if it is possible */ - if(rep->ttl < timenow) { - /* the rrsets may have been updated in the meantime. - * we will refetch the message format from the - * authoritative server - */ - return 0; + *partial_repp = NULL; /* avoid accidental further pass */ + if(worker->env.cfg->serve_expired) { + /* always lock rrsets, rep->ttl is ignored */ + if(!rrset_array_lock(rep->ref, rep->rrset_count, 0)) + return 0; + /* below, rrsets with ttl before timenow become TTL 0 in + * the response */ + /* This response was served with zero TTL */ + if (timenow >= rep->ttl) { + worker->stats.zero_ttl_responses++; + } + } else { + /* see if it is possible */ + if(rep->ttl < timenow) { + /* the rrsets may have been updated in the meantime. + * we will refetch the message format from the + * authoritative server + */ + return 0; + } + if(!rrset_array_lock(rep->ref, rep->rrset_count, timenow)) + return 0; + /* locked and ids and ttls are OK. */ } - if(!rrset_array_lock(rep->ref, rep->rrset_count, timenow)) - return 0; - /* locked and ids and ttls are OK. */ /* check CNAME chain (if any) */ if(rep->an_numrrsets > 0 && (rep->rrsets[0]->rk.type == htons(LDNS_RR_TYPE_CNAME) || rep->rrsets[0]->rk.type == @@ -574,7 +650,6 @@ answer_from_cache(struct worker* worker, struct query_info* qinfo, bail_out: rrset_array_unlock_touch(worker->env.rrset_cache, worker->scratchpad, rep->ref, rep->rrset_count); - regional_free_all(worker->scratchpad); return 0; } } @@ -585,11 +660,13 @@ answer_from_cache(struct worker* worker, struct query_info* qinfo, edns->udp_size = EDNS_ADVERTISED_SIZE; edns->ext_rcode = 0; edns->bits &= EDNS_DO; + if(!inplace_cb_reply_servfail_call(&worker->env, qinfo, NULL, rep, + LDNS_RCODE_SERVFAIL, edns, worker->scratchpad)) + goto bail_out; error_encode(repinfo->c->buffer, LDNS_RCODE_SERVFAIL, qinfo, id, flags, edns); rrset_array_unlock_touch(worker->env.rrset_cache, worker->scratchpad, rep->ref, rep->rrset_count); - regional_free_all(worker->scratchpad); if(worker->stats.extended) { worker->stats.ans_bogus ++; worker->stats.ans_rcode[LDNS_RCODE_SERVFAIL] ++; @@ -616,9 +693,41 @@ answer_from_cache(struct worker* worker, struct query_info* qinfo, edns->udp_size = EDNS_ADVERTISED_SIZE; edns->ext_rcode = 0; edns->bits &= EDNS_DO; - if(!reply_info_answer_encode(qinfo, rep, id, flags, + if(!inplace_cb_reply_cache_call(&worker->env, qinfo, NULL, rep, + (int)(flags&LDNS_RCODE_MASK), edns, worker->scratchpad)) + goto bail_out; + *alias_rrset = NULL; /* avoid confusion if caller set it to non-NULL */ + if(worker->daemon->use_response_ip && !partial_rep && + !apply_respip_action(worker, qinfo, cinfo, rep, repinfo, alias_rrset, + &encode_rep)) { + goto bail_out; + } else if(partial_rep && + !respip_merge_cname(partial_rep, qinfo, rep, cinfo, + must_validate, &encode_rep, worker->scratchpad)) { + goto bail_out; + } + if(encode_rep != rep) + secure = 0; /* if rewritten, it can't be considered "secure" */ + if(!encode_rep || *alias_rrset) { + sldns_buffer_clear(repinfo->c->buffer); + sldns_buffer_flip(repinfo->c->buffer); + if(!encode_rep) + *need_drop = 1; + else { + /* If a partial CNAME chain is found, we first need to + * make a copy of the reply in the scratchpad so we + * can release the locks and lookup the cache again. */ + *partial_repp = reply_info_copy(encode_rep, NULL, + worker->scratchpad); + if(!*partial_repp) + goto bail_out; + } + } else if(!reply_info_answer_encode(qinfo, encode_rep, id, flags, repinfo->c->buffer, timenow, 1, worker->scratchpad, udpsize, edns, (int)(edns->bits & EDNS_DO), secure)) { + if(!inplace_cb_reply_servfail_call(&worker->env, qinfo, NULL, NULL, + LDNS_RCODE_SERVFAIL, edns, worker->scratchpad)) + edns->opt_list = NULL; error_encode(repinfo->c->buffer, LDNS_RCODE_SERVFAIL, qinfo, id, flags, edns); } @@ -626,7 +735,6 @@ answer_from_cache(struct worker* worker, struct query_info* qinfo, * is bad while holding locks. */ rrset_array_unlock_touch(worker->env.rrset_cache, worker->scratchpad, rep->ref, rep->rrset_count); - regional_free_all(worker->scratchpad); if(worker->stats.extended) { if(secure) worker->stats.ans_secure++; server_stats_insrcode(&worker->stats, repinfo->c->buffer); @@ -635,14 +743,18 @@ answer_from_cache(struct worker* worker, struct query_info* qinfo, return 1; } -/** Reply to client and perform prefetch to keep cache up to date */ +/** Reply to client and perform prefetch to keep cache up to date. + * If the buffer for the reply is empty, it indicates that only prefetch is + * necessary and the reply should be suppressed (because it's dropped or + * being deferred). */ static void reply_and_prefetch(struct worker* worker, struct query_info* qinfo, uint16_t flags, struct comm_reply* repinfo, time_t leeway) { /* first send answer to client to keep its latency * as small as a cachereply */ - comm_point_send_reply(repinfo); + if(sldns_buffer_limit(repinfo->c->buffer) != 0) + comm_point_send_reply(repinfo); server_stats_prefetch(&worker->stats, worker); /* create the prefetch in the mesh as a normal lookup without @@ -657,41 +769,115 @@ reply_and_prefetch(struct worker* worker, struct query_info* qinfo, * Fill CH class answer into buffer. Keeps query. * @param pkt: buffer * @param str: string to put into text record (<255). + * array of strings, every string becomes a text record. + * @param num: number of strings in array. * @param edns: edns reply information. + * @param worker: worker with scratch region. */ static void -chaos_replystr(sldns_buffer* pkt, const char* str, struct edns_data* edns) +chaos_replystr(sldns_buffer* pkt, char** str, int num, struct edns_data* edns, + struct worker* worker) { - size_t len = strlen(str); + int i; unsigned int rd = LDNS_RD_WIRE(sldns_buffer_begin(pkt)); unsigned int cd = LDNS_CD_WIRE(sldns_buffer_begin(pkt)); - if(len>255) len=255; /* cap size of TXT record */ sldns_buffer_clear(pkt); sldns_buffer_skip(pkt, (ssize_t)sizeof(uint16_t)); /* skip id */ sldns_buffer_write_u16(pkt, (uint16_t)(BIT_QR|BIT_RA)); if(rd) LDNS_RD_SET(sldns_buffer_begin(pkt)); if(cd) LDNS_CD_SET(sldns_buffer_begin(pkt)); sldns_buffer_write_u16(pkt, 1); /* qdcount */ - sldns_buffer_write_u16(pkt, 1); /* ancount */ + sldns_buffer_write_u16(pkt, (uint16_t)num); /* ancount */ sldns_buffer_write_u16(pkt, 0); /* nscount */ sldns_buffer_write_u16(pkt, 0); /* arcount */ (void)query_dname_len(pkt); /* skip qname */ sldns_buffer_skip(pkt, (ssize_t)sizeof(uint16_t)); /* skip qtype */ sldns_buffer_skip(pkt, (ssize_t)sizeof(uint16_t)); /* skip qclass */ - sldns_buffer_write_u16(pkt, 0xc00c); /* compr ptr to query */ - sldns_buffer_write_u16(pkt, LDNS_RR_TYPE_TXT); - sldns_buffer_write_u16(pkt, LDNS_RR_CLASS_CH); - sldns_buffer_write_u32(pkt, 0); /* TTL */ - sldns_buffer_write_u16(pkt, sizeof(uint8_t) + len); - sldns_buffer_write_u8(pkt, len); - sldns_buffer_write(pkt, str, len); + for(i=0; i<num; i++) { + size_t len = strlen(str[i]); + if(len>255) len=255; /* cap size of TXT record */ + sldns_buffer_write_u16(pkt, 0xc00c); /* compr ptr to query */ + sldns_buffer_write_u16(pkt, LDNS_RR_TYPE_TXT); + sldns_buffer_write_u16(pkt, LDNS_RR_CLASS_CH); + sldns_buffer_write_u32(pkt, 0); /* TTL */ + sldns_buffer_write_u16(pkt, sizeof(uint8_t) + len); + sldns_buffer_write_u8(pkt, len); + sldns_buffer_write(pkt, str[i], len); + } sldns_buffer_flip(pkt); edns->edns_version = EDNS_ADVERTISED_VERSION; edns->udp_size = EDNS_ADVERTISED_SIZE; edns->bits &= EDNS_DO; + if(!inplace_cb_reply_local_call(&worker->env, NULL, NULL, NULL, + LDNS_RCODE_NOERROR, edns, worker->scratchpad)) + edns->opt_list = NULL; attach_edns_record(pkt, edns); } +/** Reply with one string */ +static void +chaos_replyonestr(sldns_buffer* pkt, const char* str, struct edns_data* edns, + struct worker* worker) +{ + chaos_replystr(pkt, (char**)&str, 1, edns, worker); +} + +/** + * Create CH class trustanchor answer. + * @param pkt: buffer + * @param edns: edns reply information. + * @param w: worker with scratch region. + */ +static void +chaos_trustanchor(sldns_buffer* pkt, struct edns_data* edns, struct worker* w) +{ +#define TA_RESPONSE_MAX_TXT 16 /* max number of TXT records */ +#define TA_RESPONSE_MAX_TAGS 32 /* max number of tags printed per zone */ + char* str_array[TA_RESPONSE_MAX_TXT]; + uint16_t tags[TA_RESPONSE_MAX_TAGS]; + int num = 0; + struct trust_anchor* ta; + + if(!w->env.need_to_validate) { + /* no validator module, reply no trustanchors */ + chaos_replystr(pkt, NULL, 0, edns, w); + return; + } + + /* fill the string with contents */ + lock_basic_lock(&w->env.anchors->lock); + RBTREE_FOR(ta, struct trust_anchor*, w->env.anchors->tree) { + char* str; + size_t i, numtag, str_len = 255; + if(num == TA_RESPONSE_MAX_TXT) continue; + str = (char*)regional_alloc(w->scratchpad, str_len); + if(!str) continue; + lock_basic_lock(&ta->lock); + numtag = anchor_list_keytags(ta, tags, TA_RESPONSE_MAX_TAGS); + if(numtag == 0) { + /* empty, insecure point */ + lock_basic_unlock(&ta->lock); + continue; + } + str_array[num] = str; + num++; + + /* spool name of anchor */ + (void)sldns_wire2str_dname_buf(ta->name, ta->namelen, str, str_len); + str_len -= strlen(str); str += strlen(str); + /* spool tags */ + for(i=0; i<numtag; i++) { + snprintf(str, str_len, " %u", (unsigned)tags[i]); + str_len -= strlen(str); str += strlen(str); + } + lock_basic_unlock(&ta->lock); + } + lock_basic_unlock(&w->env.anchors->lock); + + chaos_replystr(pkt, str_array, num, edns, w); + regional_free_all(w->scratchpad); +} + /** * Answer CH class queries. * @param w: worker @@ -718,13 +904,13 @@ answer_chaos(struct worker* w, struct query_info* qinfo, char buf[MAXHOSTNAMELEN+1]; if (gethostname(buf, MAXHOSTNAMELEN) == 0) { buf[MAXHOSTNAMELEN] = 0; - chaos_replystr(pkt, buf, edns); + chaos_replyonestr(pkt, buf, edns, w); } else { log_err("gethostname: %s", strerror(errno)); - chaos_replystr(pkt, "no hostname", edns); + chaos_replyonestr(pkt, "no hostname", edns, w); } } - else chaos_replystr(pkt, cfg->identity, edns); + else chaos_replyonestr(pkt, cfg->identity, edns, w); return 1; } if(query_dname_compare(qinfo->qname, @@ -735,10 +921,19 @@ answer_chaos(struct worker* w, struct query_info* qinfo, if(cfg->hide_version) return 0; if(cfg->version==NULL || cfg->version[0]==0) - chaos_replystr(pkt, PACKAGE_STRING, edns); - else chaos_replystr(pkt, cfg->version, edns); + chaos_replyonestr(pkt, PACKAGE_STRING, edns, w); + else chaos_replyonestr(pkt, cfg->version, edns, w); return 1; } + if(query_dname_compare(qinfo->qname, + (uint8_t*)"\013trustanchor\007unbound") == 0) + { + if(cfg->hide_trustanchor) + return 0; + chaos_trustanchor(pkt, edns, w); + return 1; + } + return 0; } @@ -768,6 +963,8 @@ deny_refuse(struct comm_point* c, enum acl_access acl, LDNS_QR_SET(sldns_buffer_begin(c->buffer)); LDNS_RCODE_SET(sldns_buffer_begin(c->buffer), LDNS_RCODE_REFUSED); + sldns_buffer_set_position(c->buffer, LDNS_HEADER_SIZE); + sldns_buffer_flip(c->buffer); return 1; } @@ -794,25 +991,75 @@ worker_handle_request(struct comm_point* c, void* arg, int error, { struct worker* worker = (struct worker*)arg; int ret; - hashvalue_t h; + hashvalue_type h; struct lruhash_entry* e; struct query_info qinfo; struct edns_data edns; enum acl_access acl; + struct acl_addr* acladdr; int rc = 0; + int need_drop = 0; + /* We might have to chase a CNAME chain internally, in which case + * we'll have up to two replies and combine them to build a complete + * answer. These variables control this case. */ + struct ub_packed_rrset_key* alias_rrset = NULL; + struct reply_info* partial_rep = NULL; + struct query_info* lookup_qinfo = &qinfo; + struct query_info qinfo_tmp; /* placeholdoer for lookup_qinfo */ + struct respip_client_info* cinfo = NULL, cinfo_tmp; if(error != NETEVENT_NOERROR) { /* some bad tcp query DNS formats give these error calls */ verbose(VERB_ALGO, "handle request called with err=%d", error); return 0; } +#ifdef USE_DNSCRYPT + repinfo->max_udp_size = worker->daemon->cfg->max_udp_size; + if(!dnsc_handle_curved_request(worker->daemon->dnscenv, repinfo)) { + worker->stats.num_query_dnscrypt_crypted_malformed++; + return 0; + } + if(c->dnscrypt && !repinfo->is_dnscrypted) { + char buf[LDNS_MAX_DOMAINLEN+1]; + // Check if this is unencrypted and asking for certs + if(worker_check_request(c->buffer, worker) != 0) { + verbose(VERB_ALGO, "dnscrypt: worker check request: bad query."); + log_addr(VERB_CLIENT,"from",&repinfo->addr, repinfo->addrlen); + comm_point_drop_reply(repinfo); + return 0; + } + if(!query_info_parse(&qinfo, c->buffer)) { + verbose(VERB_ALGO, "dnscrypt: worker parse request: formerror."); + log_addr(VERB_CLIENT,"from",&repinfo->addr, repinfo->addrlen); + comm_point_drop_reply(repinfo); + return 0; + } + dname_str(qinfo.qname, buf); + if(!(qinfo.qtype == LDNS_RR_TYPE_TXT && + strcasecmp(buf, worker->daemon->dnscenv->provider_name) == 0)) { + verbose(VERB_ALGO, + "dnscrypt: not TXT %s. Receive: %s %s", + worker->daemon->dnscenv->provider_name, + sldns_rr_descript(qinfo.qtype)->_name, + buf); + comm_point_drop_reply(repinfo); + worker->stats.num_query_dnscrypt_cleartext++; + return 0; + } + worker->stats.num_query_dnscrypt_cert++; + sldns_buffer_rewind(c->buffer); + } else if(c->dnscrypt && repinfo->is_dnscrypted) { + worker->stats.num_query_dnscrypt_crypted++; + } +#endif #ifdef USE_DNSTAP if(worker->dtenv.log_client_query_messages) dt_msg_send_client_query(&worker->dtenv, &repinfo->addr, c->type, c->buffer); #endif - acl = acl_list_lookup(worker->daemon->acl, &repinfo->addr, + acladdr = acl_addr_lookup(worker->daemon->acl, &repinfo->addr, repinfo->addrlen); + acl = acl_get_control(acladdr); if((ret=deny_refuse_all(c, acl, worker, repinfo)) != -1) { if(ret == 1) @@ -830,7 +1077,29 @@ worker_handle_request(struct comm_point* c, void* arg, int error, comm_point_drop_reply(repinfo); return 0; } + worker->stats.num_queries++; + + /* check if this query should be dropped based on source ip rate limiting */ + if(!infra_ip_ratelimit_inc(worker->env.infra_cache, repinfo, + *worker->env.now)) { + /* See if we are passed through with slip factor */ + if(worker->env.cfg->ip_ratelimit_factor != 0 && + ub_random_max(worker->env.rnd, + worker->env.cfg->ip_ratelimit_factor) == 1) { + + char addrbuf[128]; + addr_to_str(&repinfo->addr, repinfo->addrlen, + addrbuf, sizeof(addrbuf)); + verbose(VERB_OPS, "ip_ratelimit allowed through for ip address %s ", + addrbuf); + } else { + worker->stats.num_queries_ip_ratelimited++; + comm_point_drop_reply(repinfo); + return 0; + } + } + /* see if query is in the cache */ if(!query_info_parse(&qinfo, c->buffer)) { verbose(VERB_ALGO, "worker parse request: formerror."); @@ -865,7 +1134,29 @@ worker_handle_request(struct comm_point* c, void* arg, int error, } goto send_reply; } - if((ret=parse_edns_from_pkt(c->buffer, &edns)) != 0) { + if(qinfo.qtype == LDNS_RR_TYPE_OPT || + qinfo.qtype == LDNS_RR_TYPE_TSIG || + qinfo.qtype == LDNS_RR_TYPE_TKEY || + qinfo.qtype == LDNS_RR_TYPE_MAILA || + qinfo.qtype == LDNS_RR_TYPE_MAILB || + (qinfo.qtype >= 128 && qinfo.qtype <= 248)) { + verbose(VERB_ALGO, "worker request: formerror for meta-type."); + log_addr(VERB_CLIENT,"from",&repinfo->addr, repinfo->addrlen); + if(worker_err_ratelimit(worker, LDNS_RCODE_FORMERR) == -1) { + comm_point_drop_reply(repinfo); + return 0; + } + sldns_buffer_rewind(c->buffer); + LDNS_QR_SET(sldns_buffer_begin(c->buffer)); + LDNS_RCODE_SET(sldns_buffer_begin(c->buffer), + LDNS_RCODE_FORMERR); + if(worker->stats.extended) { + worker->stats.qtype[qinfo.qtype]++; + server_stats_insrcode(&worker->stats, c->buffer); + } + goto send_reply; + } + if((ret=parse_edns_from_pkt(c->buffer, &edns, worker->scratchpad)) != 0) { struct edns_data reply_edns; verbose(VERB_ALGO, "worker parse edns: formerror."); log_addr(VERB_CLIENT,"from",&repinfo->addr, repinfo->addrlen); @@ -876,6 +1167,7 @@ worker_handle_request(struct comm_point* c, void* arg, int error, error_encode(c->buffer, ret, &qinfo, *(uint16_t*)(void *)sldns_buffer_begin(c->buffer), sldns_buffer_read_u16_at(c->buffer, 2), &reply_edns); + regional_free_all(worker->scratchpad); server_stats_insrcode(&worker->stats, c->buffer); goto send_reply; } @@ -884,12 +1176,14 @@ worker_handle_request(struct comm_point* c, void* arg, int error, edns.edns_version = EDNS_ADVERTISED_VERSION; edns.udp_size = EDNS_ADVERTISED_SIZE; edns.bits &= EDNS_DO; + edns.opt_list = NULL; verbose(VERB_ALGO, "query with bad edns version."); log_addr(VERB_CLIENT,"from",&repinfo->addr, repinfo->addrlen); error_encode(c->buffer, EDNS_RCODE_BADVERS&0xf, &qinfo, *(uint16_t*)(void *)sldns_buffer_begin(c->buffer), sldns_buffer_read_u16_at(c->buffer, 2), NULL); attach_edns_record(c->buffer, &edns); + regional_free_all(worker->scratchpad); goto send_reply; } if(edns.edns_present && edns.udp_size < NORMAL_UDP_SIZE && @@ -918,6 +1212,7 @@ worker_handle_request(struct comm_point* c, void* arg, int error, sldns_buffer_write_at(c->buffer, 4, (uint8_t*)"\0\0\0\0\0\0\0\0", 8); sldns_buffer_flip(c->buffer); + regional_free_all(worker->scratchpad); goto send_reply; } if(worker->stats.extended) @@ -928,10 +1223,15 @@ worker_handle_request(struct comm_point* c, void* arg, int error, if(qinfo.qclass == LDNS_RR_CLASS_CH && answer_chaos(worker, &qinfo, &edns, c->buffer)) { server_stats_insrcode(&worker->stats, c->buffer); + regional_free_all(worker->scratchpad); goto send_reply; } - if(local_zones_answer(worker->daemon->local_zones, &qinfo, &edns, - c->buffer, worker->scratchpad, repinfo)) { + if(local_zones_answer(worker->daemon->local_zones, &worker->env, &qinfo, + &edns, c->buffer, worker->scratchpad, repinfo, acladdr->taglist, + acladdr->taglen, acladdr->tag_actions, + acladdr->tag_actions_size, acladdr->tag_datas, + acladdr->tag_datas_size, worker->daemon->cfg->tagname, + worker->daemon->cfg->num_tags, acladdr->view)) { regional_free_all(worker->scratchpad); if(sldns_buffer_limit(c->buffer) == 0) { comm_point_drop_reply(repinfo); @@ -945,6 +1245,7 @@ worker_handle_request(struct comm_point* c, void* arg, int error, * might need to bail out based on ACLs now. */ if((ret=deny_refuse_non_local(c, acl, worker, repinfo)) != -1) { + regional_free_all(worker->scratchpad); if(ret == 1) goto send_reply; return ret; @@ -961,46 +1262,125 @@ worker_handle_request(struct comm_point* c, void* arg, int error, LDNS_RCODE_SET(sldns_buffer_begin(c->buffer), LDNS_RCODE_REFUSED); sldns_buffer_flip(c->buffer); + regional_free_all(worker->scratchpad); server_stats_insrcode(&worker->stats, c->buffer); log_addr(VERB_ALGO, "refused nonrec (cache snoop) query from", &repinfo->addr, repinfo->addrlen); goto send_reply; } - h = query_info_hash(&qinfo, sldns_buffer_read_u16_at(c->buffer, 2)); - if((e=slabhash_lookup(worker->env.msg_cache, h, &qinfo, 0))) { - /* answer from cache - we have acquired a readlock on it */ - if(answer_from_cache(worker, &qinfo, - (struct reply_info*)e->data, - *(uint16_t*)(void *)sldns_buffer_begin(c->buffer), - sldns_buffer_read_u16_at(c->buffer, 2), repinfo, - &edns)) { - /* prefetch it if the prefetch TTL expired */ - if(worker->env.cfg->prefetch && *worker->env.now >= - ((struct reply_info*)e->data)->prefetch_ttl) { - time_t leeway = ((struct reply_info*)e-> - data)->ttl - *worker->env.now; + + /* If we've found a local alias, replace the qname with the alias + * target before resolving it. */ + if(qinfo.local_alias) { + struct ub_packed_rrset_key* rrset = qinfo.local_alias->rrset; + struct packed_rrset_data* d = rrset->entry.data; + + /* Sanity check: our current implementation only supports + * a single CNAME RRset as a local alias. */ + if(qinfo.local_alias->next || + rrset->rk.type != htons(LDNS_RR_TYPE_CNAME) || + d->count != 1) { + log_err("assumption failure: unexpected local alias"); + regional_free_all(worker->scratchpad); + return 0; /* drop it */ + } + qinfo.qname = d->rr_data[0] + 2; + qinfo.qname_len = d->rr_len[0] - 2; + } + + /* If we may apply IP-based actions to the answer, build the client + * information. As this can be expensive, skip it if there is + * absolutely no possibility of it. */ + if(worker->daemon->use_response_ip && + (qinfo.qtype == LDNS_RR_TYPE_A || + qinfo.qtype == LDNS_RR_TYPE_AAAA || + qinfo.qtype == LDNS_RR_TYPE_ANY)) { + cinfo_tmp.taglist = acladdr->taglist; + cinfo_tmp.taglen = acladdr->taglen; + cinfo_tmp.tag_actions = acladdr->tag_actions; + cinfo_tmp.tag_actions_size = acladdr->tag_actions_size; + cinfo_tmp.tag_datas = acladdr->tag_datas; + cinfo_tmp.tag_datas_size = acladdr->tag_datas_size; + cinfo_tmp.view = acladdr->view; + cinfo_tmp.respip_set = worker->daemon->respip_set; + cinfo = &cinfo_tmp; + } + +lookup_cache: + /* Lookup the cache. In case we chase an intermediate CNAME chain + * this is a two-pass operation, and lookup_qinfo is different for + * each pass. We should still pass the original qinfo to + * answer_from_cache(), however, since it's used to build the reply. */ + if(!edns_bypass_cache_stage(edns.opt_list, &worker->env)) { + h = query_info_hash(lookup_qinfo, sldns_buffer_read_u16_at(c->buffer, 2)); + if((e=slabhash_lookup(worker->env.msg_cache, h, lookup_qinfo, 0))) { + /* answer from cache - we have acquired a readlock on it */ + if(answer_from_cache(worker, &qinfo, + cinfo, &need_drop, &alias_rrset, &partial_rep, + (struct reply_info*)e->data, + *(uint16_t*)(void *)sldns_buffer_begin(c->buffer), + sldns_buffer_read_u16_at(c->buffer, 2), repinfo, + &edns)) { + /* prefetch it if the prefetch TTL expired. + * Note that if there is more than one pass + * its qname must be that used for cache + * lookup. */ + if((worker->env.cfg->prefetch || worker->env.cfg->serve_expired) + && *worker->env.now >= + ((struct reply_info*)e->data)->prefetch_ttl) { + time_t leeway = ((struct reply_info*)e-> + data)->ttl - *worker->env.now; + if(((struct reply_info*)e->data)->ttl + < *worker->env.now) + leeway = 0; + lock_rw_unlock(&e->lock); + reply_and_prefetch(worker, lookup_qinfo, + sldns_buffer_read_u16_at(c->buffer, 2), + repinfo, leeway); + if(!partial_rep) { + rc = 0; + regional_free_all(worker->scratchpad); + goto send_reply_rc; + } + } else if(!partial_rep) { + lock_rw_unlock(&e->lock); + regional_free_all(worker->scratchpad); + goto send_reply; + } + /* We've found a partial reply ending with an + * alias. Replace the lookup qinfo for the + * alias target and lookup the cache again to + * (possibly) complete the reply. As we're + * passing the "base" reply, there will be no + * more alias chasing. */ lock_rw_unlock(&e->lock); - reply_and_prefetch(worker, &qinfo, - sldns_buffer_read_u16_at(c->buffer, 2), - repinfo, leeway); - rc = 0; - goto send_reply_rc; + memset(&qinfo_tmp, 0, sizeof(qinfo_tmp)); + get_cname_target(alias_rrset, &qinfo_tmp.qname, + &qinfo_tmp.qname_len); + if(!qinfo_tmp.qname) { + log_err("unexpected: invalid answer alias"); + regional_free_all(worker->scratchpad); + return 0; /* drop query */ + } + qinfo_tmp.qtype = qinfo.qtype; + qinfo_tmp.qclass = qinfo.qclass; + lookup_qinfo = &qinfo_tmp; + goto lookup_cache; } + verbose(VERB_ALGO, "answer from the cache failed"); lock_rw_unlock(&e->lock); - goto send_reply; } - verbose(VERB_ALGO, "answer from the cache failed"); - lock_rw_unlock(&e->lock); - } - if(!LDNS_RD_WIRE(sldns_buffer_begin(c->buffer))) { - if(answer_norec_from_cache(worker, &qinfo, - *(uint16_t*)(void *)sldns_buffer_begin(c->buffer), - sldns_buffer_read_u16_at(c->buffer, 2), repinfo, - &edns)) { - goto send_reply; + if(!LDNS_RD_WIRE(sldns_buffer_begin(c->buffer))) { + if(answer_norec_from_cache(worker, &qinfo, + *(uint16_t*)(void *)sldns_buffer_begin(c->buffer), + sldns_buffer_read_u16_at(c->buffer, 2), repinfo, + &edns)) { + regional_free_all(worker->scratchpad); + goto send_reply; + } + verbose(VERB_ALGO, "answer norec from cache -- " + "need to validate or not primed"); } - verbose(VERB_ALGO, "answer norec from cache -- " - "need to validate or not primed"); } sldns_buffer_rewind(c->buffer); server_stats_querymiss(&worker->stats, worker); @@ -1014,20 +1394,36 @@ worker_handle_request(struct comm_point* c, void* arg, int error, } /* grab a work request structure for this new request */ - mesh_new_client(worker->env.mesh, &qinfo, + mesh_new_client(worker->env.mesh, &qinfo, cinfo, sldns_buffer_read_u16_at(c->buffer, 2), &edns, repinfo, *(uint16_t*)(void *)sldns_buffer_begin(c->buffer)); + regional_free_all(worker->scratchpad); worker_mem_report(worker, NULL); return 0; send_reply: rc = 1; send_reply_rc: + if(need_drop) { + comm_point_drop_reply(repinfo); + return 0; + } #ifdef USE_DNSTAP if(worker->dtenv.log_client_response_messages) dt_msg_send_client_response(&worker->dtenv, &repinfo->addr, c->type, c->buffer); #endif + if(worker->env.cfg->log_replies) + { + struct timeval tv = {0, 0}; + log_reply_info(0, &qinfo, &repinfo->addr, repinfo->addrlen, + tv, 1, c->buffer); + } +#ifdef USE_DNSCRYPT + if(!dnsc_handle_uncurved_request(repinfo)) { + return 0; + } +#endif return rc; } @@ -1083,6 +1479,10 @@ void worker_stat_timer_cb(void* arg) server_stats_log(&worker->stats, worker, worker->thread_num); mesh_stats(worker->env.mesh, "mesh has"); worker_mem_report(worker, NULL); + /* SHM is enabled, process data to SHM */ + if (worker->daemon->cfg->shm_enable) { + shm_main_run(worker); + } if(!worker->daemon->cfg->stat_cumulative) { worker_stats_clear(worker); } @@ -1217,7 +1617,8 @@ worker_init(struct worker* worker, struct config_file *cfg, cfg->do_tcp?cfg->outgoing_num_tcp:0, worker->daemon->env->infra_cache, worker->rndstate, cfg->use_caps_bits_for_id, worker->ports, worker->numports, - cfg->unwanted_threshold, &worker_alloc_cleanup, worker, + cfg->unwanted_threshold, cfg->outgoing_tcp_mss, + &worker_alloc_cleanup, worker, cfg->do_udp, worker->daemon->connect_sslctx, cfg->delay_close, dtenv); if(!worker->back) { @@ -1352,10 +1753,10 @@ worker_delete(struct worker* worker) } struct outbound_entry* -worker_send_query(uint8_t* qname, size_t qnamelen, uint16_t qtype, - uint16_t qclass, uint16_t flags, int dnssec, int want_dnssec, - int nocaps, struct sockaddr_storage* addr, socklen_t addrlen, - uint8_t* zone, size_t zonelen, struct module_qstate* q) +worker_send_query(struct query_info* qinfo, uint16_t flags, int dnssec, + int want_dnssec, int nocaps, struct sockaddr_storage* addr, + socklen_t addrlen, uint8_t* zone, size_t zonelen, int ssl_upstream, + struct module_qstate* q) { struct worker* worker = q->env->worker; struct outbound_entry* e = (struct outbound_entry*)regional_alloc( @@ -1363,11 +1764,10 @@ worker_send_query(uint8_t* qname, size_t qnamelen, uint16_t qtype, if(!e) return NULL; e->qstate = q; - e->qsent = outnet_serviced_query(worker->back, qname, - qnamelen, qtype, qclass, flags, dnssec, want_dnssec, nocaps, - q->env->cfg->tcp_upstream, q->env->cfg->ssl_upstream, addr, - addrlen, zone, zonelen, worker_handle_service_reply, e, - worker->back->udp_buff); + e->qsent = outnet_serviced_query(worker->back, qinfo, flags, dnssec, + want_dnssec, nocaps, q->env->cfg->tcp_upstream, + ssl_upstream, addr, addrlen, zone, zonelen, q, + worker_handle_service_reply, e, worker->back->udp_buff, q->env); if(!e->qsent) { return NULL; } @@ -1407,13 +1807,13 @@ void worker_stop_accept(void* arg) } /* --- fake callbacks for fptr_wlist to work --- */ -struct outbound_entry* libworker_send_query(uint8_t* ATTR_UNUSED(qname), - size_t ATTR_UNUSED(qnamelen), uint16_t ATTR_UNUSED(qtype), - uint16_t ATTR_UNUSED(qclass), uint16_t ATTR_UNUSED(flags), - int ATTR_UNUSED(dnssec), int ATTR_UNUSED(want_dnssec), - int ATTR_UNUSED(nocaps), struct sockaddr_storage* ATTR_UNUSED(addr), - socklen_t ATTR_UNUSED(addrlen), uint8_t* ATTR_UNUSED(zone), - size_t ATTR_UNUSED(zonelen), struct module_qstate* ATTR_UNUSED(q)) +struct outbound_entry* libworker_send_query( + struct query_info* ATTR_UNUSED(qinfo), + uint16_t ATTR_UNUSED(flags), int ATTR_UNUSED(dnssec), + int ATTR_UNUSED(want_dnssec), int ATTR_UNUSED(nocaps), + struct sockaddr_storage* ATTR_UNUSED(addr), socklen_t ATTR_UNUSED(addrlen), + uint8_t* ATTR_UNUSED(zone), size_t ATTR_UNUSED(zonelen), + int ATTR_UNUSED(ssl_upstream), struct module_qstate* ATTR_UNUSED(q)) { log_assert(0); return 0; diff --git a/external/unbound/daemon/worker.h b/external/unbound/daemon/worker.h index 63613430b..0d7ce9521 100644 --- a/external/unbound/daemon/worker.h +++ b/external/unbound/daemon/worker.h @@ -61,6 +61,7 @@ struct ub_randstate; struct regional; struct tube; struct daemon_remote; +struct query_info; /** worker commands */ enum worker_commands { @@ -84,7 +85,7 @@ struct worker { /** global shared daemon structure */ struct daemon* daemon; /** thread id */ - ub_thread_t thr_id; + ub_thread_type thr_id; /** pipe, for commands for this worker */ struct tube* cmd; /** the event base this worker works with */ |