diff options
Diffstat (limited to 'external/unbound/daemon')
-rw-r--r-- | external/unbound/daemon/acl_list.c | 487 | ||||
-rw-r--r-- | external/unbound/daemon/acl_list.h | 155 | ||||
-rw-r--r-- | external/unbound/daemon/cachedump.c | 898 | ||||
-rw-r--r-- | external/unbound/daemon/cachedump.h | 107 | ||||
-rw-r--r-- | external/unbound/daemon/daemon.c | 795 | ||||
-rw-r--r-- | external/unbound/daemon/daemon.h | 183 | ||||
-rw-r--r-- | external/unbound/daemon/remote.c | 3050 | ||||
-rw-r--r-- | external/unbound/daemon/remote.h | 191 | ||||
-rw-r--r-- | external/unbound/daemon/stats.c | 343 | ||||
-rw-r--r-- | external/unbound/daemon/stats.h | 262 | ||||
-rw-r--r-- | external/unbound/daemon/unbound.c | 738 | ||||
-rw-r--r-- | external/unbound/daemon/worker.c | 1883 | ||||
-rw-r--r-- | external/unbound/daemon/worker.h | 178 |
13 files changed, 0 insertions, 9270 deletions
diff --git a/external/unbound/daemon/acl_list.c b/external/unbound/daemon/acl_list.c deleted file mode 100644 index f7d71b9fd..000000000 --- a/external/unbound/daemon/acl_list.c +++ /dev/null @@ -1,487 +0,0 @@ -/* - * daemon/acl_list.h - client access control storage for the server. - * - * Copyright (c) 2007, NLnet Labs. All rights reserved. - * - * This software is open source. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * Neither the name of the NLNET LABS nor the names of its contributors may - * be used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED - * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/** - * \file - * - * This file helps the server keep out queries from outside sources, that - * should not be answered. - */ -#include "config.h" -#include "daemon/acl_list.h" -#include "util/regional.h" -#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) -{ - struct acl_list* acl = (struct acl_list*)calloc(1, - sizeof(struct acl_list)); - if(!acl) - return NULL; - acl->region = regional_create(); - if(!acl->region) { - acl_list_delete(acl); - return NULL; - } - return acl; -} - -void -acl_list_delete(struct acl_list* acl) -{ - if(!acl) - return; - regional_destroy(acl->region); - free(acl); -} - -/** insert new address into acl_list structure */ -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_zero(acl->region, - sizeof(struct acl_addr)); - if(!node) - 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 node; -} - -/** apply acl_list string */ -static int -acl_list_str_cfg(struct acl_list* acl, const char* str, const char* s2, - int complain_duplicates) -{ - struct sockaddr_storage addr; - int net; - socklen_t addrlen; - enum acl_access control; - if(strcmp(s2, "allow") == 0) - control = acl_allow; - else if(strcmp(s2, "deny") == 0) - control = acl_deny; - else if(strcmp(s2, "refuse") == 0) - control = acl_refuse; - else if(strcmp(s2, "deny_non_local") == 0) - control = acl_deny_non_local; - else if(strcmp(s2, "refuse_non_local") == 0) - control = acl_refuse_non_local; - else if(strcmp(s2, "allow_snoop") == 0) - control = acl_allow_snoop; - else { - log_err("access control type %s unknown", str); - return 0; - } - if(!netblockstrtoaddr(str, UNBOUND_DNS_PORT, &addr, &addrlen, &net)) { - log_err("cannot parse access control: %s %s", str, s2); - return 0; - } - if(!acl_list_insert(acl, &addr, addrlen, net, control, - complain_duplicates)) { - log_err("out of memory"); - return 0; - } - 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) -{ - struct config_str2list* p; - for(p = cfg->acls; p; p = p->next) { - log_assert(p->str && p->str2); - if(!acl_list_str_cfg(acl, p->str, p->str2, 1)) - return 0; - } - 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, - 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; - if(!acl_list_str_cfg(acl, "127.0.0.0/8", "allow", 0)) - return 0; - if(cfg->do_ip6) { - if(!acl_list_str_cfg(acl, "::0/0", "refuse", 0)) - return 0; - if(!acl_list_str_cfg(acl, "::1", "allow", 0)) - return 0; - if(!acl_list_str_cfg(acl, "::ffff:127.0.0.1", "allow", 0)) - return 0; - } - addr_tree_init_parents(&acl->tree); - return 1; -} - -enum acl_access -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) -{ - return (struct acl_addr*)addr_tree_lookup(&acl->tree, - addr, addrlen); -} - -size_t -acl_list_get_mem(struct acl_list* acl) -{ - if(!acl) return 0; - return sizeof(*acl) + regional_get_mem(acl->region); -} diff --git a/external/unbound/daemon/acl_list.h b/external/unbound/daemon/acl_list.h deleted file mode 100644 index d0d42bfae..000000000 --- a/external/unbound/daemon/acl_list.h +++ /dev/null @@ -1,155 +0,0 @@ -/* - * daemon/acl_list.h - client access control storage for the server. - * - * Copyright (c) 2007, NLnet Labs. All rights reserved. - * - * This software is open source. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * Neither the name of the NLNET LABS nor the names of its contributors may - * be used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED - * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/** - * \file - * - * This file keeps track of the list of clients that are allowed to - * access the server. - */ - -#ifndef DAEMON_ACL_LIST_H -#define DAEMON_ACL_LIST_H -#include "util/storage/dnstree.h" -#include "services/view.h" -struct config_file; -struct regional; - -/** - * Enumeration of access control options for an address range. - * Allow or deny access. - */ -enum acl_access { - /** disallow any access whatsoever, drop it */ - acl_deny = 0, - /** disallow access, send a polite 'REFUSED' reply */ - acl_refuse, - /** disallow any access to zones that aren't local, drop it */ - acl_deny_non_local, - /** disallow access to zones that aren't local, 'REFUSED' reply */ - acl_refuse_non_local, - /** allow full access for recursion (+RD) queries */ - acl_allow, - /** allow full access for all queries, recursion and cache snooping */ - acl_allow_snoop -}; - -/** - * Access control storage structure - */ -struct acl_list { - /** regional for allocation */ - struct regional* region; - /** - * Tree of the addresses that are allowed/blocked. - * contents of type acl_addr. - */ - rbtree_type tree; -}; - -/** - * - * An address span with access control information - */ -struct acl_addr { - /** node in address tree */ - 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; -}; - -/** - * Create acl structure - * @return new structure or NULL on error. - */ -struct acl_list* acl_list_create(void); - -/** - * Delete acl structure. - * @param acl: to delete. - */ -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, - struct views* v); - -/** - * 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: acl structure from this address. - */ -struct acl_addr* -acl_addr_lookup(struct acl_list* acl, struct sockaddr_storage* addr, - socklen_t addrlen); - -/** - * Get memory used by acl structure. - * @param acl: structure for address storage. - * @return bytes in use. - */ -size_t acl_list_get_mem(struct acl_list* acl); - -#endif /* DAEMON_ACL_LIST_H */ diff --git a/external/unbound/daemon/cachedump.c b/external/unbound/daemon/cachedump.c deleted file mode 100644 index 8992e6cb8..000000000 --- a/external/unbound/daemon/cachedump.c +++ /dev/null @@ -1,898 +0,0 @@ -/* - * daemon/cachedump.c - dump the cache to text format. - * - * Copyright (c) 2008, NLnet Labs. All rights reserved. - * - * This software is open source. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * Neither the name of the NLNET LABS nor the names of its contributors may - * be used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED - * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/** - * \file - * - * This file contains functions to read and write the cache(s) - * to text format. - */ -#include "config.h" -#include <openssl/ssl.h> -#include "daemon/cachedump.h" -#include "daemon/remote.h" -#include "daemon/worker.h" -#include "services/cache/rrset.h" -#include "services/cache/dns.h" -#include "services/cache/infra.h" -#include "util/data/msgreply.h" -#include "util/regional.h" -#include "util/net_help.h" -#include "util/data/dname.h" -#include "iterator/iterator.h" -#include "iterator/iter_delegpt.h" -#include "iterator/iter_utils.h" -#include "iterator/iter_fwd.h" -#include "iterator/iter_hints.h" -#include "sldns/sbuffer.h" -#include "sldns/wire2str.h" -#include "sldns/str2wire.h" - -/** dump one rrset zonefile line */ -static int -dump_rrset_line(SSL* ssl, struct ub_packed_rrset_key* k, time_t now, size_t i) -{ - char s[65535]; - if(!packed_rr_to_string(k, i, now, s, sizeof(s))) { - return ssl_printf(ssl, "BADRR\n"); - } - return ssl_printf(ssl, "%s", s); -} - -/** dump rrset key and data info */ -static int -dump_rrset(SSL* ssl, struct ub_packed_rrset_key* k, - struct packed_rrset_data* d, time_t now) -{ - size_t i; - /* rd lock held by caller */ - if(!k || !d) return 1; - if(d->ttl < now) return 1; /* expired */ - - /* meta line */ - if(!ssl_printf(ssl, ";rrset%s " ARG_LL "d %u %u %d %d\n", - (k->rk.flags & PACKED_RRSET_NSEC_AT_APEX)?" nsec_apex":"", - (long long)(d->ttl - now), - (unsigned)d->count, (unsigned)d->rrsig_count, - (int)d->trust, (int)d->security - )) - return 0; - for(i=0; i<d->count + d->rrsig_count; i++) { - if(!dump_rrset_line(ssl, k, now, i)) - return 0; - } - return 1; -} - -/** dump lruhash rrset cache */ -static int -dump_rrset_lruhash(SSL* ssl, struct lruhash* h, time_t now) -{ - struct lruhash_entry* e; - /* lruhash already locked by caller */ - /* walk in order of lru; best first */ - for(e=h->lru_start; e; e = e->lru_next) { - lock_rw_rdlock(&e->lock); - if(!dump_rrset(ssl, (struct ub_packed_rrset_key*)e->key, - (struct packed_rrset_data*)e->data, now)) { - lock_rw_unlock(&e->lock); - return 0; - } - lock_rw_unlock(&e->lock); - } - return 1; -} - -/** dump rrset cache */ -static int -dump_rrset_cache(SSL* ssl, struct worker* worker) -{ - struct rrset_cache* r = worker->env.rrset_cache; - size_t slab; - if(!ssl_printf(ssl, "START_RRSET_CACHE\n")) return 0; - for(slab=0; slab<r->table.size; slab++) { - lock_quick_lock(&r->table.array[slab]->lock); - if(!dump_rrset_lruhash(ssl, r->table.array[slab], - *worker->env.now)) { - lock_quick_unlock(&r->table.array[slab]->lock); - return 0; - } - lock_quick_unlock(&r->table.array[slab]->lock); - } - return ssl_printf(ssl, "END_RRSET_CACHE\n"); -} - -/** dump message to rrset reference */ -static int -dump_msg_ref(SSL* ssl, struct ub_packed_rrset_key* k) -{ - char* nm, *tp, *cl; - nm = sldns_wire2str_dname(k->rk.dname, k->rk.dname_len); - tp = sldns_wire2str_type(ntohs(k->rk.type)); - cl = sldns_wire2str_class(ntohs(k->rk.rrset_class)); - if(!nm || !cl || !tp) { - free(nm); - free(tp); - free(cl); - return ssl_printf(ssl, "BADREF\n"); - } - if(!ssl_printf(ssl, "%s %s %s %d\n", nm, cl, tp, (int)k->rk.flags)) { - free(nm); - free(tp); - free(cl); - return 0; - } - free(nm); - free(tp); - free(cl); - - return 1; -} - -/** dump message entry */ -static int -dump_msg(SSL* ssl, struct query_info* k, struct reply_info* d, - time_t now) -{ - size_t i; - char* nm, *tp, *cl; - if(!k || !d) return 1; - if(d->ttl < now) return 1; /* expired */ - - nm = sldns_wire2str_dname(k->qname, k->qname_len); - tp = sldns_wire2str_type(k->qtype); - cl = sldns_wire2str_class(k->qclass); - if(!nm || !tp || !cl) { - free(nm); - free(tp); - free(cl); - return 1; /* skip this entry */ - } - if(!rrset_array_lock(d->ref, d->rrset_count, now)) { - /* rrsets have timed out or do not exist */ - free(nm); - free(tp); - free(cl); - return 1; /* skip this entry */ - } - - /* meta line */ - if(!ssl_printf(ssl, "msg %s %s %s %d %d " ARG_LL "d %d %u %u %u\n", - nm, cl, tp, - (int)d->flags, (int)d->qdcount, - (long long)(d->ttl-now), (int)d->security, - (unsigned)d->an_numrrsets, - (unsigned)d->ns_numrrsets, - (unsigned)d->ar_numrrsets)) { - free(nm); - free(tp); - free(cl); - rrset_array_unlock(d->ref, d->rrset_count); - return 0; - } - free(nm); - free(tp); - free(cl); - - for(i=0; i<d->rrset_count; i++) { - if(!dump_msg_ref(ssl, d->rrsets[i])) { - rrset_array_unlock(d->ref, d->rrset_count); - return 0; - } - } - rrset_array_unlock(d->ref, d->rrset_count); - - return 1; -} - -/** copy msg to worker pad */ -static int -copy_msg(struct regional* region, struct lruhash_entry* e, - struct query_info** k, struct reply_info** d) -{ - struct reply_info* rep = (struct reply_info*)e->data; - if(rep->rrset_count > RR_COUNT_MAX) - return 0; /* to protect against integer overflow */ - *d = (struct reply_info*)regional_alloc_init(region, e->data, - sizeof(struct reply_info) + - sizeof(struct rrset_ref) * (rep->rrset_count-1) + - sizeof(struct ub_packed_rrset_key*) * rep->rrset_count); - if(!*d) - return 0; - (*d)->rrsets = (struct ub_packed_rrset_key**)(void *)( - (uint8_t*)(&((*d)->ref[0])) + - sizeof(struct rrset_ref) * rep->rrset_count); - *k = (struct query_info*)regional_alloc_init(region, - e->key, sizeof(struct query_info)); - if(!*k) - return 0; - (*k)->qname = regional_alloc_init(region, - (*k)->qname, (*k)->qname_len); - return (*k)->qname != NULL; -} - -/** dump lruhash msg cache */ -static int -dump_msg_lruhash(SSL* ssl, struct worker* worker, struct lruhash* h) -{ - struct lruhash_entry* e; - struct query_info* k; - struct reply_info* d; - - /* lruhash already locked by caller */ - /* walk in order of lru; best first */ - for(e=h->lru_start; e; e = e->lru_next) { - regional_free_all(worker->scratchpad); - lock_rw_rdlock(&e->lock); - /* make copy of rrset in worker buffer */ - if(!copy_msg(worker->scratchpad, e, &k, &d)) { - lock_rw_unlock(&e->lock); - return 0; - } - lock_rw_unlock(&e->lock); - /* release lock so we can lookup the rrset references - * in the rrset cache */ - if(!dump_msg(ssl, k, d, *worker->env.now)) { - return 0; - } - } - return 1; -} - -/** dump msg cache */ -static int -dump_msg_cache(SSL* ssl, struct worker* worker) -{ - struct slabhash* sh = worker->env.msg_cache; - size_t slab; - if(!ssl_printf(ssl, "START_MSG_CACHE\n")) return 0; - for(slab=0; slab<sh->size; slab++) { - lock_quick_lock(&sh->array[slab]->lock); - if(!dump_msg_lruhash(ssl, worker, sh->array[slab])) { - lock_quick_unlock(&sh->array[slab]->lock); - return 0; - } - lock_quick_unlock(&sh->array[slab]->lock); - } - return ssl_printf(ssl, "END_MSG_CACHE\n"); -} - -int -dump_cache(SSL* ssl, struct worker* worker) -{ - if(!dump_rrset_cache(ssl, worker)) - return 0; - if(!dump_msg_cache(ssl, worker)) - return 0; - return ssl_printf(ssl, "EOF\n"); -} - -/** read a line from ssl into buffer */ -static int -ssl_read_buf(SSL* ssl, sldns_buffer* buf) -{ - return ssl_read_line(ssl, (char*)sldns_buffer_begin(buf), - sldns_buffer_capacity(buf)); -} - -/** check fixed text on line */ -static int -read_fixed(SSL* ssl, sldns_buffer* buf, const char* str) -{ - if(!ssl_read_buf(ssl, buf)) return 0; - return (strcmp((char*)sldns_buffer_begin(buf), str) == 0); -} - -/** load an RR into rrset */ -static int -load_rr(SSL* ssl, sldns_buffer* buf, struct regional* region, - struct ub_packed_rrset_key* rk, struct packed_rrset_data* d, - unsigned int i, int is_rrsig, int* go_on, time_t now) -{ - uint8_t rr[LDNS_RR_BUF_SIZE]; - size_t rr_len = sizeof(rr), dname_len = 0; - int status; - - /* read the line */ - if(!ssl_read_buf(ssl, buf)) - return 0; - if(strncmp((char*)sldns_buffer_begin(buf), "BADRR\n", 6) == 0) { - *go_on = 0; - return 1; - } - status = sldns_str2wire_rr_buf((char*)sldns_buffer_begin(buf), rr, - &rr_len, &dname_len, 3600, NULL, 0, NULL, 0); - if(status != 0) { - log_warn("error cannot parse rr: %s: %s", - sldns_get_errorstr_parse(status), - (char*)sldns_buffer_begin(buf)); - return 0; - } - if(is_rrsig && sldns_wirerr_get_type(rr, rr_len, dname_len) - != LDNS_RR_TYPE_RRSIG) { - log_warn("error expected rrsig but got %s", - (char*)sldns_buffer_begin(buf)); - return 0; - } - - /* convert ldns rr into packed_rr */ - d->rr_ttl[i] = (time_t)sldns_wirerr_get_ttl(rr, rr_len, dname_len) + now; - sldns_buffer_clear(buf); - d->rr_len[i] = sldns_wirerr_get_rdatalen(rr, rr_len, dname_len)+2; - d->rr_data[i] = (uint8_t*)regional_alloc_init(region, - sldns_wirerr_get_rdatawl(rr, rr_len, dname_len), d->rr_len[i]); - if(!d->rr_data[i]) { - log_warn("error out of memory"); - return 0; - } - - /* if first entry, fill the key structure */ - if(i==0) { - rk->rk.type = htons(sldns_wirerr_get_type(rr, rr_len, dname_len)); - rk->rk.rrset_class = htons(sldns_wirerr_get_class(rr, rr_len, dname_len)); - rk->rk.dname_len = dname_len; - rk->rk.dname = regional_alloc_init(region, rr, dname_len); - if(!rk->rk.dname) { - log_warn("error out of memory"); - return 0; - } - } - - return 1; -} - -/** move entry into cache */ -static int -move_into_cache(struct ub_packed_rrset_key* k, - struct packed_rrset_data* d, struct worker* worker) -{ - struct ub_packed_rrset_key* ak; - struct packed_rrset_data* ad; - size_t s, i, num = d->count + d->rrsig_count; - struct rrset_ref ref; - uint8_t* p; - - ak = alloc_special_obtain(&worker->alloc); - if(!ak) { - log_warn("error out of memory"); - return 0; - } - ak->entry.data = NULL; - ak->rk = k->rk; - ak->entry.hash = rrset_key_hash(&k->rk); - ak->rk.dname = (uint8_t*)memdup(k->rk.dname, k->rk.dname_len); - if(!ak->rk.dname) { - log_warn("error out of memory"); - ub_packed_rrset_parsedelete(ak, &worker->alloc); - return 0; - } - s = sizeof(*ad) + (sizeof(size_t) + sizeof(uint8_t*) + - sizeof(time_t))* num; - for(i=0; i<num; i++) - s += d->rr_len[i]; - ad = (struct packed_rrset_data*)malloc(s); - if(!ad) { - log_warn("error out of memory"); - ub_packed_rrset_parsedelete(ak, &worker->alloc); - return 0; - } - p = (uint8_t*)ad; - memmove(p, d, sizeof(*ad)); - p += sizeof(*ad); - memmove(p, &d->rr_len[0], sizeof(size_t)*num); - p += sizeof(size_t)*num; - memmove(p, &d->rr_data[0], sizeof(uint8_t*)*num); - p += sizeof(uint8_t*)*num; - memmove(p, &d->rr_ttl[0], sizeof(time_t)*num); - p += sizeof(time_t)*num; - for(i=0; i<num; i++) { - memmove(p, d->rr_data[i], d->rr_len[i]); - p += d->rr_len[i]; - } - packed_rrset_ptr_fixup(ad); - - ak->entry.data = ad; - - ref.key = ak; - ref.id = ak->id; - (void)rrset_cache_update(worker->env.rrset_cache, &ref, - &worker->alloc, *worker->env.now); - return 1; -} - -/** load an rrset entry */ -static int -load_rrset(SSL* ssl, sldns_buffer* buf, struct worker* worker) -{ - char* s = (char*)sldns_buffer_begin(buf); - struct regional* region = worker->scratchpad; - struct ub_packed_rrset_key* rk; - struct packed_rrset_data* d; - unsigned int rr_count, rrsig_count, trust, security; - long long ttl; - unsigned int i; - int go_on = 1; - regional_free_all(region); - - rk = (struct ub_packed_rrset_key*)regional_alloc_zero(region, - sizeof(*rk)); - d = (struct packed_rrset_data*)regional_alloc_zero(region, sizeof(*d)); - if(!rk || !d) { - log_warn("error out of memory"); - return 0; - } - - if(strncmp(s, ";rrset", 6) != 0) { - log_warn("error expected ';rrset' but got %s", s); - return 0; - } - s += 6; - if(strncmp(s, " nsec_apex", 10) == 0) { - s += 10; - rk->rk.flags |= PACKED_RRSET_NSEC_AT_APEX; - } - if(sscanf(s, " " ARG_LL "d %u %u %u %u", &ttl, &rr_count, &rrsig_count, - &trust, &security) != 5) { - log_warn("error bad rrset spec %s", s); - return 0; - } - if(rr_count == 0 && rrsig_count == 0) { - log_warn("bad rrset without contents"); - return 0; - } - if(rr_count > RR_COUNT_MAX || rrsig_count > RR_COUNT_MAX) { - log_warn("bad rrset with too many rrs"); - return 0; - } - d->count = (size_t)rr_count; - d->rrsig_count = (size_t)rrsig_count; - d->security = (enum sec_status)security; - d->trust = (enum rrset_trust)trust; - d->ttl = (time_t)ttl + *worker->env.now; - - d->rr_len = regional_alloc_zero(region, - sizeof(size_t)*(d->count+d->rrsig_count)); - d->rr_ttl = regional_alloc_zero(region, - sizeof(time_t)*(d->count+d->rrsig_count)); - d->rr_data = regional_alloc_zero(region, - sizeof(uint8_t*)*(d->count+d->rrsig_count)); - if(!d->rr_len || !d->rr_ttl || !d->rr_data) { - log_warn("error out of memory"); - return 0; - } - - /* read the rr's themselves */ - for(i=0; i<rr_count; i++) { - if(!load_rr(ssl, buf, region, rk, d, i, 0, - &go_on, *worker->env.now)) { - log_warn("could not read rr %u", i); - return 0; - } - } - for(i=0; i<rrsig_count; i++) { - if(!load_rr(ssl, buf, region, rk, d, i+rr_count, 1, - &go_on, *worker->env.now)) { - log_warn("could not read rrsig %u", i); - return 0; - } - } - if(!go_on) { - /* skip this entry */ - return 1; - } - - return move_into_cache(rk, d, worker); -} - -/** load rrset cache */ -static int -load_rrset_cache(SSL* ssl, struct worker* worker) -{ - sldns_buffer* buf = worker->env.scratch_buffer; - if(!read_fixed(ssl, buf, "START_RRSET_CACHE")) return 0; - while(ssl_read_buf(ssl, buf) && - strcmp((char*)sldns_buffer_begin(buf), "END_RRSET_CACHE")!=0) { - if(!load_rrset(ssl, buf, worker)) - return 0; - } - return 1; -} - -/** read qinfo from next three words */ -static char* -load_qinfo(char* str, struct query_info* qinfo, struct regional* region) -{ - /* s is part of the buf */ - char* s = str; - uint8_t rr[LDNS_RR_BUF_SIZE]; - size_t rr_len = sizeof(rr), dname_len = 0; - int status; - - /* skip three words */ - s = strchr(str, ' '); - if(s) s = strchr(s+1, ' '); - if(s) s = strchr(s+1, ' '); - if(!s) { - log_warn("error line too short, %s", str); - return NULL; - } - s[0] = 0; - s++; - - /* parse them */ - status = sldns_str2wire_rr_question_buf(str, rr, &rr_len, &dname_len, - NULL, 0, NULL, 0); - if(status != 0) { - log_warn("error cannot parse: %s %s", - sldns_get_errorstr_parse(status), str); - return NULL; - } - qinfo->qtype = sldns_wirerr_get_type(rr, rr_len, dname_len); - 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; - } - - return s; -} - -/** load a msg rrset reference */ -static int -load_ref(SSL* ssl, sldns_buffer* buf, struct worker* worker, - struct regional *region, struct ub_packed_rrset_key** rrset, - int* go_on) -{ - char* s = (char*)sldns_buffer_begin(buf); - struct query_info qinfo; - unsigned int flags; - struct ub_packed_rrset_key* k; - - /* read line */ - if(!ssl_read_buf(ssl, buf)) - return 0; - if(strncmp(s, "BADREF", 6) == 0) { - *go_on = 0; /* its bad, skip it and skip message */ - return 1; - } - - s = load_qinfo(s, &qinfo, region); - if(!s) { - return 0; - } - if(sscanf(s, " %u", &flags) != 1) { - log_warn("error cannot parse flags: %s", s); - return 0; - } - - /* lookup in cache */ - k = rrset_cache_lookup(worker->env.rrset_cache, qinfo.qname, - qinfo.qname_len, qinfo.qtype, qinfo.qclass, - (uint32_t)flags, *worker->env.now, 0); - if(!k) { - /* not found or expired */ - *go_on = 0; - return 1; - } - - /* store in result */ - *rrset = packed_rrset_copy_region(k, region, *worker->env.now); - lock_rw_unlock(&k->entry.lock); - - return (*rrset != NULL); -} - -/** load a msg entry */ -static int -load_msg(SSL* ssl, sldns_buffer* buf, struct worker* worker) -{ - struct regional* region = worker->scratchpad; - struct query_info qinf; - struct reply_info rep; - char* s = (char*)sldns_buffer_begin(buf); - unsigned int flags, qdcount, security, an, ns, ar; - long long ttl; - size_t i; - int go_on = 1; - - regional_free_all(region); - - if(strncmp(s, "msg ", 4) != 0) { - log_warn("error expected msg but got %s", s); - return 0; - } - s += 4; - s = load_qinfo(s, &qinf, region); - if(!s) { - return 0; - } - - /* read remainder of line */ - if(sscanf(s, " %u %u " ARG_LL "d %u %u %u %u", &flags, &qdcount, &ttl, - &security, &an, &ns, &ar) != 7) { - log_warn("error cannot parse numbers: %s", s); - return 0; - } - rep.flags = (uint16_t)flags; - rep.qdcount = (uint16_t)qdcount; - rep.ttl = (time_t)ttl; - rep.prefetch_ttl = PREFETCH_TTL_CALC(rep.ttl); - rep.security = (enum sec_status)security; - if(an > RR_COUNT_MAX || ns > RR_COUNT_MAX || ar > RR_COUNT_MAX) { - log_warn("error too many rrsets"); - return 0; /* protect against integer overflow in alloc */ - } - rep.an_numrrsets = (size_t)an; - rep.ns_numrrsets = (size_t)ns; - rep.ar_numrrsets = (size_t)ar; - rep.rrset_count = (size_t)an+(size_t)ns+(size_t)ar; - rep.rrsets = (struct ub_packed_rrset_key**)regional_alloc_zero( - region, sizeof(struct ub_packed_rrset_key*)*rep.rrset_count); - - /* fill repinfo with references */ - for(i=0; i<rep.rrset_count; i++) { - if(!load_ref(ssl, buf, worker, region, &rep.rrsets[i], - &go_on)) { - return 0; - } - } - - if(!go_on) - return 1; /* skip this one, not all references satisfied */ - - if(!dns_cache_store(&worker->env, &qinf, &rep, 0, 0, 0, NULL, flags)) { - log_warn("error out of memory"); - return 0; - } - return 1; -} - -/** load msg cache */ -static int -load_msg_cache(SSL* ssl, struct worker* worker) -{ - sldns_buffer* buf = worker->env.scratch_buffer; - if(!read_fixed(ssl, buf, "START_MSG_CACHE")) return 0; - while(ssl_read_buf(ssl, buf) && - strcmp((char*)sldns_buffer_begin(buf), "END_MSG_CACHE")!=0) { - if(!load_msg(ssl, buf, worker)) - return 0; - } - return 1; -} - -int -load_cache(SSL* ssl, struct worker* worker) -{ - if(!load_rrset_cache(ssl, worker)) - return 0; - if(!load_msg_cache(ssl, worker)) - return 0; - return read_fixed(ssl, worker->env.scratch_buffer, "EOF"); -} - -/** print details on a delegation point */ -static void -print_dp_details(SSL* ssl, struct worker* worker, struct delegpt* dp) -{ - char buf[257]; - struct delegpt_addr* a; - int lame, dlame, rlame, rto, edns_vs, to, delay, - tA = 0, tAAAA = 0, tother = 0; - long long entry_ttl; - struct rtt_info ri; - uint8_t edns_lame_known; - for(a = dp->target_list; a; a = a->next_target) { - addr_to_str(&a->addr, a->addrlen, buf, sizeof(buf)); - if(!ssl_printf(ssl, "%-16s\t", buf)) - return; - if(a->bogus) { - if(!ssl_printf(ssl, "Address is BOGUS. ")) - return; - } - /* lookup in infra cache */ - delay=0; - entry_ttl = infra_get_host_rto(worker->env.infra_cache, - &a->addr, a->addrlen, dp->name, dp->namelen, - &ri, &delay, *worker->env.now, &tA, &tAAAA, &tother); - if(entry_ttl == -2 && ri.rto >= USEFUL_SERVER_TOP_TIMEOUT) { - if(!ssl_printf(ssl, "expired, rto %d msec, tA %d " - "tAAAA %d tother %d.\n", ri.rto, tA, tAAAA, - tother)) - return; - continue; - } - if(entry_ttl == -1 || entry_ttl == -2) { - if(!ssl_printf(ssl, "not in infra cache.\n")) - return; - continue; /* skip stuff not in infra cache */ - } - - /* uses type_A because most often looked up, but other - * lameness won't be reported then */ - if(!infra_get_lame_rtt(worker->env.infra_cache, - &a->addr, a->addrlen, dp->name, dp->namelen, - LDNS_RR_TYPE_A, &lame, &dlame, &rlame, &rto, - *worker->env.now)) { - if(!ssl_printf(ssl, "not in infra cache.\n")) - return; - continue; /* skip stuff not in infra cache */ - } - if(!ssl_printf(ssl, "%s%s%s%srto %d msec, ttl " ARG_LL "d, " - "ping %d var %d rtt %d, tA %d, tAAAA %d, tother %d", - lame?"LAME ":"", dlame?"NoDNSSEC ":"", - a->lame?"AddrWasParentSide ":"", - rlame?"NoAuthButRecursive ":"", rto, entry_ttl, - ri.srtt, ri.rttvar, rtt_notimeout(&ri), - tA, tAAAA, tother)) - return; - if(delay) - if(!ssl_printf(ssl, ", probedelay %d", delay)) - return; - if(infra_host(worker->env.infra_cache, &a->addr, a->addrlen, - dp->name, dp->namelen, *worker->env.now, &edns_vs, - &edns_lame_known, &to)) { - if(edns_vs == -1) { - if(!ssl_printf(ssl, ", noEDNS%s.", - edns_lame_known?" probed":" assumed")) - return; - } else { - if(!ssl_printf(ssl, ", EDNS %d%s.", edns_vs, - edns_lame_known?" probed":" assumed")) - return; - } - } - if(!ssl_printf(ssl, "\n")) - return; - } -} - -/** print main dp info */ -static void -print_dp_main(SSL* ssl, struct delegpt* dp, struct dns_msg* msg) -{ - size_t i, n_ns, n_miss, n_addr, n_res, n_avail; - - /* print the dp */ - if(msg) - for(i=0; i<msg->rep->rrset_count; i++) { - struct ub_packed_rrset_key* k = msg->rep->rrsets[i]; - struct packed_rrset_data* d = - (struct packed_rrset_data*)k->entry.data; - if(d->security == sec_status_bogus) { - if(!ssl_printf(ssl, "Address is BOGUS:\n")) - return; - } - if(!dump_rrset(ssl, k, d, 0)) - return; - } - delegpt_count_ns(dp, &n_ns, &n_miss); - delegpt_count_addr(dp, &n_addr, &n_res, &n_avail); - /* since dp has not been used by iterator, all are available*/ - if(!ssl_printf(ssl, "Delegation with %d names, of which %d " - "can be examined to query further addresses.\n" - "%sIt provides %d IP addresses.\n", - (int)n_ns, (int)n_miss, (dp->bogus?"It is BOGUS. ":""), - (int)n_addr)) - return; -} - -int print_deleg_lookup(SSL* ssl, struct worker* worker, uint8_t* nm, - size_t nmlen, int ATTR_UNUSED(nmlabs)) -{ - /* deep links into the iterator module */ - struct delegpt* dp; - struct dns_msg* msg; - struct regional* region = worker->scratchpad; - char b[260]; - struct query_info qinfo; - struct iter_hints_stub* stub; - regional_free_all(region); - qinfo.qname = 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 " - "of %s\n", b)) - return 0; - - dp = forwards_lookup(worker->env.fwds, nm, qinfo.qclass); - if(dp) { - if(!ssl_printf(ssl, "forwarding request:\n")) - return 0; - print_dp_main(ssl, dp, NULL); - print_dp_details(ssl, worker, dp); - return 1; - } - - while(1) { - dp = dns_cache_find_delegation(&worker->env, nm, nmlen, - qinfo.qtype, qinfo.qclass, region, &msg, - *worker->env.now); - if(!dp) { - return ssl_printf(ssl, "no delegation from " - "cache; goes to configured roots\n"); - } - /* go up? */ - if(iter_dp_is_useless(&qinfo, BIT_RD, dp)) { - print_dp_main(ssl, dp, msg); - print_dp_details(ssl, worker, dp); - if(!ssl_printf(ssl, "cache delegation was " - "useless (no IP addresses)\n")) - return 0; - if(dname_is_root(nm)) { - /* goes to root config */ - return ssl_printf(ssl, "no delegation from " - "cache; goes to configured roots\n"); - } else { - /* useless, goes up */ - nm = dp->name; - nmlen = dp->namelen; - dname_remove_label(&nm, &nmlen); - dname_str(nm, b); - if(!ssl_printf(ssl, "going up, lookup %s\n", b)) - return 0; - continue; - } - } - stub = hints_lookup_stub(worker->env.hints, nm, qinfo.qclass, - dp); - if(stub) { - if(stub->noprime) { - if(!ssl_printf(ssl, "The noprime stub servers " - "are used:\n")) - return 0; - } else { - if(!ssl_printf(ssl, "The stub is primed " - "with servers:\n")) - return 0; - } - print_dp_main(ssl, stub->dp, NULL); - print_dp_details(ssl, worker, stub->dp); - } else { - print_dp_main(ssl, dp, msg); - print_dp_details(ssl, worker, dp); - } - break; - } - - return 1; -} diff --git a/external/unbound/daemon/cachedump.h b/external/unbound/daemon/cachedump.h deleted file mode 100644 index 0f2feabcb..000000000 --- a/external/unbound/daemon/cachedump.h +++ /dev/null @@ -1,107 +0,0 @@ -/* - * daemon/cachedump.h - dump the cache to text format. - * - * Copyright (c) 2008, NLnet Labs. All rights reserved. - * - * This software is open source. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * Neither the name of the NLNET LABS nor the names of its contributors may - * be used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED - * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/** - * \file - * - * This file contains functions to read and write the cache(s) - * to text format. - * - * The format of the file is as follows: - * [RRset cache] - * [Message cache] - * EOF -- fixed string "EOF" before end of the file. - * - * The RRset cache is: - * START_RRSET_CACHE - * [rrset]* - * END_RRSET_CACHE - * - * rrset is: - * ;rrset [nsec_apex] TTL rr_count rrsig_count trust security - * resource records, one per line, in zonefile format - * rrsig records, one per line, in zonefile format - * If the text conversion fails, BADRR is printed on the line. - * - * The Message cache is: - * START_MSG_CACHE - * [msg]* - * END_MSG_CACHE - * - * msg is: - * msg name class type flags qdcount ttl security an ns ar - * list of rrset references, one per line. If conversion fails, BADREF - * reference is: - * name class type flags - * - * Expired cache entries are not printed. - */ - -#ifndef DAEMON_DUMPCACHE_H -#define DAEMON_DUMPCACHE_H -struct worker; - -/** - * Dump cache(s) to text - * @param ssl: to print to - * @param worker: worker that is available (buffers, etc) and has - * ptrs to the caches. - * @return false on ssl print error. - */ -int dump_cache(SSL* ssl, struct worker* worker); - -/** - * Load cache(s) from text - * @param ssl: to read from - * @param worker: worker that is available (buffers, etc) and has - * ptrs to the caches. - * @return false on ssl error. - */ -int load_cache(SSL* ssl, struct worker* worker); - -/** - * Print the delegation used to lookup for this name. - * @param ssl: to read from - * @param worker: worker that is available (buffers, etc) and has - * ptrs to the caches. - * @param nm: name to lookup - * @param nmlen: length of name. - * @param nmlabs: labels in name. - * @return false on ssl error. - */ -int print_deleg_lookup(SSL* ssl, struct worker* worker, uint8_t* nm, - size_t nmlen, int nmlabs); - -#endif /* DAEMON_DUMPCACHE_H */ diff --git a/external/unbound/daemon/daemon.c b/external/unbound/daemon/daemon.c deleted file mode 100644 index dad9f86b3..000000000 --- a/external/unbound/daemon/daemon.c +++ /dev/null @@ -1,795 +0,0 @@ -/* - * daemon/daemon.c - collection of workers that handles requests. - * - * Copyright (c) 2007, NLnet Labs. All rights reserved. - * - * This software is open source. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * Neither the name of the NLNET LABS nor the names of its contributors may - * be used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED - * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/** - * \file - * - * The daemon consists of global settings and a number of workers. - */ - -#include "config.h" -#ifdef HAVE_OPENSSL_ERR_H -#include <openssl/err.h> -#endif - -#ifdef HAVE_OPENSSL_RAND_H -#include <openssl/rand.h> -#endif - -#ifdef HAVE_OPENSSL_CONF_H -#include <openssl/conf.h> -#endif - -#ifdef HAVE_OPENSSL_ENGINE_H -#include <openssl/engine.h> -#endif - -#ifdef HAVE_TIME_H -#include <time.h> -#endif -#include <sys/time.h> - -#ifdef HAVE_NSS -/* nss3 */ -#include "nss.h" -#endif - -#include "daemon/daemon.h" -#include "daemon/worker.h" -#include "daemon/remote.h" -#include "daemon/acl_list.h" -#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. */ -static int sig_record_reload = 0; - -#if HAVE_DECL_SSL_COMP_GET_COMPRESSION_METHODS -/** cleaner ssl memory freeup */ -static void* comp_meth = NULL; -#endif -#ifdef LEX_HAS_YYLEX_DESTROY -/** remove buffers for parsing and init */ -int ub_c_lex_destroy(void); -#endif - -/** used when no other sighandling happens, so we don't die - * when multiple signals in quick succession are sent to us. - * @param sig: signal number. - * @return signal handler return type (void or int). - */ -static RETSIGTYPE record_sigh(int sig) -{ -#ifdef LIBEVENT_SIGNAL_PROBLEM - /* cannot log, verbose here because locks may be held */ - /* quit on signal, no cleanup and statistics, - because installed libevent version is not threadsafe */ - exit(0); -#endif - switch(sig) - { - case SIGTERM: -#ifdef SIGQUIT - case SIGQUIT: -#endif -#ifdef SIGBREAK - case SIGBREAK: -#endif - case SIGINT: - sig_record_quit++; - break; -#ifdef SIGHUP - case SIGHUP: - sig_record_reload++; - break; -#endif -#ifdef SIGPIPE - case SIGPIPE: - break; -#endif - default: - /* ignoring signal */ - break; - } -} - -/** - * Signal handling during the time when netevent is disabled. - * Stores signals to replay later. - */ -static void -signal_handling_record(void) -{ - if( signal(SIGTERM, record_sigh) == SIG_ERR || -#ifdef SIGQUIT - signal(SIGQUIT, record_sigh) == SIG_ERR || -#endif -#ifdef SIGBREAK - signal(SIGBREAK, record_sigh) == SIG_ERR || -#endif -#ifdef SIGHUP - signal(SIGHUP, record_sigh) == SIG_ERR || -#endif -#ifdef SIGPIPE - signal(SIGPIPE, SIG_IGN) == SIG_ERR || -#endif - signal(SIGINT, record_sigh) == SIG_ERR - ) - log_err("install sighandler: %s", strerror(errno)); -} - -/** - * Replay old signals. - * @param wrk: worker that handles signals. - */ -static void -signal_handling_playback(struct worker* wrk) -{ -#ifdef SIGHUP - 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); - sig_record_quit = 0; - sig_record_reload = 0; -} - -struct daemon* -daemon_init(void) -{ - struct daemon* daemon = (struct daemon*)calloc(1, - sizeof(struct daemon)); -#ifdef USE_WINSOCK - int r; - WSADATA wsa_data; -#endif - if(!daemon) - return NULL; -#ifdef USE_WINSOCK - r = WSAStartup(MAKEWORD(2,2), &wsa_data); - if(r != 0) { - fatal_exit("could not init winsock. WSAStartup: %s", - wsa_strerror(r)); - } -#endif /* USE_WINSOCK */ - signal_handling_record(); - checklock_start(); -#ifdef HAVE_SSL -# ifdef HAVE_ERR_LOAD_CRYPTO_STRINGS - ERR_load_crypto_strings(); -# 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"); -# endif -#elif defined(HAVE_NSS) - if(NSS_NoDB_Init(NULL) != SECSuccess) - fatal_exit("could not init NSS"); -#endif /* HAVE_SSL or HAVE_NSS */ -#ifdef HAVE_TZSET - /* init timezone info while we are not chrooted yet */ - tzset(); -#endif - /* open /dev/random if needed */ - ub_systemseed((unsigned)time(NULL)^(unsigned)getpid()^0xe67); - daemon->need_to_exit = 0; - modstack_init(&daemon->mods); - if(!(daemon->env = (struct module_env*)calloc(1, - sizeof(*daemon->env)))) { - 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; - } - if(gettimeofday(&daemon->time_boot, NULL) < 0) - log_err("gettimeofday: %s", strerror(errno)); - daemon->time_last_stat = daemon->time_boot; - return daemon; -} - -int -daemon_open_shared_ports(struct daemon* daemon) -{ - log_assert(daemon); - if(daemon->cfg->port != daemon->listening_port) { - size_t i; - struct listen_port* p0; - daemon->reuseport = 0; - /* free and close old ports */ - if(daemon->ports != NULL) { - for(i=0; i<daemon->num_ports; i++) - listening_ports_free(daemon->ports[i]); - free(daemon->ports); - daemon->ports = NULL; - } - /* see if we want to reuseport */ -#ifdef SO_REUSEPORT - if(daemon->cfg->so_reuseport && daemon->cfg->num_threads > 0) - daemon->reuseport = 1; -#endif - /* try to use reuseport */ - p0 = listening_ports_open(daemon->cfg, &daemon->reuseport); - if(!p0) { - listening_ports_free(p0); - return 0; - } - if(daemon->reuseport) { - /* reuseport was successful, allocate for it */ - daemon->num_ports = (size_t)daemon->cfg->num_threads; - } else { - /* do the normal, singleportslist thing, - * reuseport not enabled or did not work */ - daemon->num_ports = 1; - } - if(!(daemon->ports = (struct listen_port**)calloc( - daemon->num_ports, sizeof(*daemon->ports)))) { - listening_ports_free(p0); - return 0; - } - daemon->ports[0] = p0; - if(daemon->reuseport) { - /* continue to use reuseport */ - for(i=1; i<daemon->num_ports; i++) { - if(!(daemon->ports[i]= - listening_ports_open(daemon->cfg, - &daemon->reuseport)) - || !daemon->reuseport ) { - for(i=0; i<daemon->num_ports; i++) - listening_ports_free(daemon->ports[i]); - free(daemon->ports); - daemon->ports = NULL; - return 0; - } - } - } - daemon->listening_port = daemon->cfg->port; - } - if(!daemon->cfg->remote_control_enable && daemon->rc_port) { - listening_ports_free(daemon->rc_ports); - daemon->rc_ports = NULL; - daemon->rc_port = 0; - } - if(daemon->cfg->remote_control_enable && - daemon->cfg->control_port != daemon->rc_port) { - listening_ports_free(daemon->rc_ports); - if(!(daemon->rc_ports=daemon_remote_open_ports(daemon->cfg))) - return 0; - daemon->rc_port = daemon->cfg->control_port; - } - return 1; -} - -/** - * Setup modules. setup module stack. - * @param daemon: the daemon - */ -static void daemon_setup_modules(struct daemon* daemon) -{ - daemon->env->cfg = daemon->cfg; - daemon->env->alloc = &daemon->superalloc; - daemon->env->worker = NULL; - daemon->env->need_to_validate = 0; /* set by module init below */ - if(!modstack_setup(&daemon->mods, daemon->cfg->module_conf, - daemon->env)) { - fatal_exit("failed to setup modules"); - } - log_edns_known_options(VERB_ALGO, daemon->env); -} - -/** - * Obtain allowed port numbers, concatenate the list, and shuffle them - * (ready to be handed out to threads). - * @param daemon: the daemon. Uses rand and cfg. - * @param shufport: the portlist output. - * @return number of ports available. - */ -static int daemon_get_shufport(struct daemon* daemon, int* shufport) -{ - int i, n, k, temp; - int avail = 0; - for(i=0; i<65536; i++) { - if(daemon->cfg->outgoing_avail_ports[i]) { - shufport[avail++] = daemon->cfg-> - outgoing_avail_ports[i]; - } - } - if(avail == 0) - fatal_exit("no ports are permitted for UDP, add " - "with outgoing-port-permit"); - /* Knuth shuffle */ - n = avail; - while(--n > 0) { - k = ub_random_max(daemon->rand, n+1); /* 0<= k<= n */ - temp = shufport[k]; - shufport[k] = shufport[n]; - shufport[n] = temp; - } - return avail; -} - -/** - * Allocate empty worker structures. With backptr and thread-number, - * from 0..numthread initialised. Used as user arguments to new threads. - * Creates the daemon random generator if it does not exist yet. - * The random generator stays existing between reloads with a unique state. - * @param daemon: the daemon with (new) config settings. - */ -static void -daemon_create_workers(struct daemon* daemon) -{ - int i, numport; - int* shufport; - log_assert(daemon && daemon->cfg); - if(!daemon->rand) { - unsigned int seed = (unsigned int)time(NULL) ^ - (unsigned int)getpid() ^ 0x438; - daemon->rand = ub_initstate(seed, NULL); - if(!daemon->rand) - fatal_exit("could not init random generator"); - } - hash_set_raninit((uint32_t)ub_random(daemon->rand)); - shufport = (int*)calloc(65536, sizeof(int)); - if(!shufport) - fatal_exit("out of memory during daemon init"); - numport = daemon_get_shufport(daemon, shufport); - verbose(VERB_ALGO, "total of %d outgoing ports available", numport); - - daemon->num = (daemon->cfg->num_threads?daemon->cfg->num_threads:1); - if(daemon->reuseport && (int)daemon->num < (int)daemon->num_ports) { - log_warn("cannot reduce num-threads to %d because so-reuseport " - "so continuing with %d threads.", (int)daemon->num, - (int)daemon->num_ports); - daemon->num = (int)daemon->num_ports; - } - 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, - (unsigned int)daemon->num); - if (!daemon->dtenv) - fatal_exit("dt_create failed"); - dt_apply_cfg(daemon->dtenv, daemon->cfg); -#else - fatal_exit("dnstap enabled in config but not built with dnstap support"); -#endif - } - for(i=0; i<daemon->num; i++) { - if(!(daemon->workers[i] = worker_create(daemon, i, - shufport+numport*i/daemon->num, - numport*(i+1)/daemon->num - numport*i/daemon->num))) - /* the above is not ports/numthr, due to rounding */ - fatal_exit("could not create worker"); - } - free(shufport); -} - -#ifdef THREADS_DISABLED -/** - * Close all pipes except for the numbered thread. - * @param daemon: daemon to close pipes in. - * @param thr: thread number 0..num-1 of thread to skip. - */ -static void close_other_pipes(struct daemon* daemon, int thr) -{ - int i; - for(i=0; i<daemon->num; i++) - if(i!=thr) { - if(i==0) { - /* only close read part, need to write stats */ - tube_close_read(daemon->workers[i]->cmd); - } else { - /* complete close channel to others */ - tube_delete(daemon->workers[i]->cmd); - daemon->workers[i]->cmd = NULL; - } - } -} -#endif /* THREADS_DISABLED */ - -/** - * Function to start one thread. - * @param arg: user argument. - * @return: void* user return value could be used for thread_join results. - */ -static void* -thread_start(void* arg) -{ - struct worker* worker = (struct worker*)arg; - int port_num = 0; - log_thread_set(&worker->thread_num); - ub_thread_blocksigs(); -#ifdef THREADS_DISABLED - /* close pipe ends used by main */ - tube_close_write(worker->cmd); - close_other_pipes(worker->daemon, worker->thread_num); -#endif -#ifdef SO_REUSEPORT - if(worker->daemon->cfg->so_reuseport) - port_num = worker->thread_num % worker->daemon->num_ports; - else - port_num = 0; -#endif - if(!worker_init(worker, worker->daemon->cfg, - worker->daemon->ports[port_num], 0)) - fatal_exit("Could not initialize thread"); - - worker_work(worker); - return NULL; -} - -/** - * Fork and init the other threads. Main thread returns for special handling. - * @param daemon: the daemon with other threads to fork. - */ -static void -daemon_start_others(struct daemon* daemon) -{ - int i; - log_assert(daemon); - verbose(VERB_ALGO, "start threads"); - /* skip i=0, is this thread */ - for(i=1; i<daemon->num; i++) { - ub_thread_create(&daemon->workers[i]->thr_id, - thread_start, daemon->workers[i]); -#ifdef THREADS_DISABLED - /* close pipe end of child */ - tube_close_read(daemon->workers[i]->cmd); -#endif /* no threads */ - } -} - -/** - * Stop the other threads. - * @param daemon: the daemon with other threads. - */ -static void -daemon_stop_others(struct daemon* daemon) -{ - int i; - log_assert(daemon); - verbose(VERB_ALGO, "stop threads"); - /* skip i=0, is this thread */ - /* use i=0 buffer for sending cmds; because we are #0 */ - for(i=1; i<daemon->num; i++) { - worker_send_cmd(daemon->workers[i], worker_cmd_quit); - } - /* wait for them to quit */ - for(i=1; i<daemon->num; i++) { - /* join it to make sure its dead */ - verbose(VERB_ALGO, "join %d", i); - ub_thread_join(daemon->workers[i]->thr_id); - verbose(VERB_ALGO, "join success %d", i); - } -} - -void -daemon_fork(struct daemon* daemon) -{ - int have_view_respip_cfg = 0; - - log_assert(daemon); - 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. - */ - daemon_create_workers(daemon); - -#if defined(HAVE_EV_LOOP) || defined(HAVE_EV_DEFAULT_LOOP) - /* in libev the first inited base gets signals */ - if(!worker_init(daemon->workers[0], daemon->cfg, daemon->ports[0], 1)) - fatal_exit("Could not initialize main thread"); -#endif - - /* Now create the threads and init the workers. - * By the way, this is thread #0 (the main thread). - */ - daemon_start_others(daemon); - - /* Special handling for the main thread. This is the thread - * that handles signals and remote control. - */ -#if !(defined(HAVE_EV_LOOP) || defined(HAVE_EV_DEFAULT_LOOP)) - /* libevent has the last inited base get signals (or any base) */ - if(!worker_init(daemon->workers[0], daemon->cfg, daemon->ports[0], 1)) - fatal_exit("Could not initialize main thread"); -#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; -} - -void -daemon_cleanup(struct daemon* daemon) -{ - int i; - log_assert(daemon); - /* before stopping main worker, handle signals ourselves, so we - don't die on multiple reload signals for example. */ - signal_handling_record(); - 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 */ - slabhash_clear(&daemon->env->rrset_cache->table); - slabhash_clear(daemon->env->msg_cache); - local_zones_delete(daemon->local_zones); - daemon->local_zones = NULL; - 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]); - free(daemon->workers); - daemon->workers = NULL; - daemon->num = 0; -#ifdef USE_DNSTAP - dt_delete(daemon->dtenv); -#endif - daemon->cfg = NULL; -} - -void -daemon_delete(struct daemon* daemon) -{ - size_t i; - if(!daemon) - return; - modstack_desetup(&daemon->mods, daemon->env); - daemon_remote_delete(daemon->rc); - for(i = 0; i < daemon->num_ports; i++) - listening_ports_free(daemon->ports[i]); - free(daemon->ports); - listening_ports_free(daemon->rc_ports); - if(daemon->env) { - 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); - acl_list_delete(daemon->acl); - free(daemon->chroot); - free(daemon->pidfile); - free(daemon->env); -#ifdef HAVE_SSL - SSL_CTX_free((SSL_CTX*)daemon->listen_sslctx); - SSL_CTX_free((SSL_CTX*)daemon->connect_sslctx); -#endif - free(daemon); -#ifdef LEX_HAS_YYLEX_DESTROY - /* lex cleanup */ - ub_c_lex_destroy(); -#endif - /* libcrypto cleanup */ -#ifdef HAVE_SSL -# if defined(USE_GOST) && defined(HAVE_LDNS_KEY_EVP_UNLOAD_GOST) - sldns_key_EVP_unload_gost(); -# 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 */ -# 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 -#elif defined(HAVE_NSS) - NSS_Shutdown(); -#endif /* HAVE_SSL or HAVE_NSS */ - checklock_stop(); -#ifdef USE_WINSOCK - if(WSACleanup() != 0) { - log_err("Could not WSACleanup: %s", - wsa_strerror(WSAGetLastError())); - } -#endif -} - -void daemon_apply_cfg(struct daemon* daemon, struct config_file* cfg) -{ - daemon->cfg = cfg; - config_apply(cfg); - if(!daemon->env->msg_cache || - cfg->msg_cache_size != slabhash_get_size(daemon->env->msg_cache) || - cfg->msg_cache_slabs != daemon->env->msg_cache->size) { - slabhash_delete(daemon->env->msg_cache); - daemon->env->msg_cache = slabhash_create(cfg->msg_cache_slabs, - HASH_DEFAULT_STARTARRAY, cfg->msg_cache_size, - msgreply_sizefunc, query_info_compare, - query_entry_delete, reply_info_delete, NULL); - if(!daemon->env->msg_cache) { - fatal_exit("malloc failure updating config settings"); - } - } - if((daemon->env->rrset_cache = rrset_cache_adjust( - daemon->env->rrset_cache, cfg, &daemon->superalloc)) == 0) - fatal_exit("malloc failure updating config settings"); - if((daemon->env->infra_cache = infra_adjust(daemon->env->infra_cache, - cfg))==0) - fatal_exit("malloc failure updating config settings"); -} diff --git a/external/unbound/daemon/daemon.h b/external/unbound/daemon/daemon.h deleted file mode 100644 index 71e5bb96d..000000000 --- a/external/unbound/daemon/daemon.h +++ /dev/null @@ -1,183 +0,0 @@ -/* - * daemon/daemon.h - collection of workers that handles requests. - * - * Copyright (c) 2007, NLnet Labs. All rights reserved. - * - * This software is open source. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * Neither the name of the NLNET LABS nor the names of its contributors may - * be used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED - * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/** - * \file - * - * The daemon consists of global settings and a number of workers. - */ - -#ifndef DAEMON_H -#define DAEMON_H - -#include "util/locks.h" -#include "util/alloc.h" -#include "services/modstack.h" -#ifdef UB_ON_WINDOWS -# include "util/winsock_event.h" -#endif -struct config_file; -struct worker; -struct listen_port; -struct slabhash; -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. - */ -struct daemon { - /** The config settings */ - struct config_file* cfg; - /** the chroot dir in use, NULL if none */ - char* chroot; - /** pidfile that is used */ - char* pidfile; - /** port number that has ports opened. */ - int listening_port; - /** array of listening ports, opened. Listening ports per worker, - * or just one element[0] shared by the worker threads. */ - struct listen_port** ports; - /** size of ports array */ - size_t num_ports; - /** reuseport is enabled if true */ - int reuseport; - /** port number for remote that has ports opened. */ - int rc_port; - /** listening ports for remote control */ - struct listen_port* rc_ports; - /** remote control connections management (for first worker) */ - struct daemon_remote* rc; - /** ssl context for listening to dnstcp over ssl, and connecting ssl */ - void* listen_sslctx, *connect_sslctx; - /** num threads allocated */ - int num; - /** the worker entries */ - struct worker** workers; - /** do we need to exit unbound (or is it only a reload?) */ - int need_to_exit; - /** master random table ; used for port div between threads on reload*/ - struct ub_randstate* rand; - /** master allocation cache */ - struct alloc_cache superalloc; - /** the module environment master value, copied and changed by threads*/ - struct module_env* env; - /** stack of module callbacks */ - struct module_stack mods; - /** access control, which client IPs are allowed to connect */ - struct acl_list* acl; - /** local authority zones */ - struct local_zones* local_zones; - /** last time of statistics printout */ - 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 -}; - -/** - * Initialize daemon structure. - * @return: The daemon structure, or NULL on error. - */ -struct daemon* daemon_init(void); - -/** - * Open shared listening ports (if needed). - * The cfg member pointer must have been set for the daemon. - * @param daemon: the daemon. - * @return: false on error. - */ -int daemon_open_shared_ports(struct daemon* daemon); - -/** - * Fork workers and start service. - * When the routine exits, it is no longer forked. - * @param daemon: the daemon. - */ -void daemon_fork(struct daemon* daemon); - -/** - * Close off the worker thread information. - * Bring the daemon back into state ready for daemon_fork again. - * @param daemon: the daemon. - */ -void daemon_cleanup(struct daemon* daemon); - -/** - * Delete workers, close listening ports. - * @param daemon: the daemon. - */ -void daemon_delete(struct daemon* daemon); - -/** - * Apply config settings. - * @param daemon: the daemon. - * @param cfg: new config settings. - */ -void daemon_apply_cfg(struct daemon* daemon, struct config_file* cfg); - -#endif /* DAEMON_H */ diff --git a/external/unbound/daemon/remote.c b/external/unbound/daemon/remote.c deleted file mode 100644 index c15967c20..000000000 --- a/external/unbound/daemon/remote.c +++ /dev/null @@ -1,3050 +0,0 @@ -/* - * daemon/remote.c - remote control for the unbound daemon. - * - * Copyright (c) 2008, NLnet Labs. All rights reserved. - * - * This software is open source. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * Neither the name of the NLNET LABS nor the names of its contributors may - * be used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED - * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/** - * \file - * - * This file contains the remote control functionality for the daemon. - * The remote control can be performed using either the commandline - * unbound-control tool, or a TLS capable web browser. - * The channel is secured using TLSv1, and certificates. - * Both the server and the client(control tool) have their own keys. - */ -#include "config.h" -#ifdef HAVE_OPENSSL_ERR_H -#include <openssl/err.h> -#endif -#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" -#include "daemon/worker.h" -#include "daemon/daemon.h" -#include "daemon/stats.h" -#include "daemon/cachedump.h" -#include "util/log.h" -#include "util/config_file.h" -#include "util/net_help.h" -#include "util/module.h" -#include "services/listen_dnsport.h" -#include "services/cache/rrset.h" -#include "services/cache/infra.h" -#include "services/mesh.h" -#include "services/localzone.h" -#include "util/storage/slabhash.h" -#include "util/fptr_wlist.h" -#include "util/data/dname.h" -#include "validator/validator.h" -#include "validator/val_kcache.h" -#include "validator/val_kentry.h" -#include "validator/val_anchor.h" -#include "iterator/iterator.h" -#include "iterator/iter_fwd.h" -#include "iterator/iter_hints.h" -#include "iterator/iter_delegpt.h" -#include "services/outbound_list.h" -#include "services/outside_network.h" -#include "sldns/str2wire.h" -#include "sldns/parseutil.h" -#include "sldns/wire2str.h" -#include "sldns/sbuffer.h" - -#ifdef HAVE_SYS_TYPES_H -# include <sys/types.h> -#endif -#ifdef HAVE_SYS_STAT_H -#include <sys/stat.h> -#endif -#ifdef HAVE_NETDB_H -#include <netdb.h> -#endif - -/* just for portability */ -#ifdef SQ -#undef SQ -#endif - -/** what to put on statistics lines between var and value, ": " or "=" */ -#define SQ "=" -/** if true, inhibits a lot of =0 lines from the stats output */ -static const int inhibit_zero = 1; - -/** subtract timers and the values do not overflow or become negative */ -static void -timeval_subtract(struct timeval* d, const struct timeval* end, - const struct timeval* start) -{ -#ifndef S_SPLINT_S - time_t end_usec = end->tv_usec; - d->tv_sec = end->tv_sec - start->tv_sec; - if(end_usec < start->tv_usec) { - end_usec += 1000000; - d->tv_sec--; - } - d->tv_usec = end_usec - start->tv_usec; -#endif -} - -/** divide sum of timers to get average */ -static void -timeval_divide(struct timeval* avg, const struct timeval* sum, size_t d) -{ -#ifndef S_SPLINT_S - size_t leftover; - if(d == 0) { - avg->tv_sec = 0; - avg->tv_usec = 0; - return; - } - avg->tv_sec = sum->tv_sec / d; - avg->tv_usec = sum->tv_usec / d; - /* handle fraction from seconds divide */ - leftover = sum->tv_sec - avg->tv_sec*d; - avg->tv_usec += (leftover*1000000)/d; -#endif -} - -/* - * The following function was generated using the openssl utility, using - * 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 -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 dh2048_g[]={ - 0x02, - }; - 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) -{ - char* s_cert; - char* s_key; - struct daemon_remote* rc = (struct daemon_remote*)calloc(1, - sizeof(*rc)); - if(!rc) { - log_err("out of memory in daemon_remote_create"); - return NULL; - } - rc->max_active = 10; - - if(!cfg->remote_control_enable) { - rc->ctx = NULL; - return rc; - } - rc->ctx = SSL_CTX_new(SSLv23_server_method()); - if(!rc->ctx) { - log_crypto_err("could not SSL_CTX_new"); - free(rc); - return NULL; - } - /* no SSLv2, SSLv3 because has defects */ - if((SSL_CTX_set_options(rc->ctx, SSL_OP_NO_SSLv2) & SSL_OP_NO_SSLv2) - != SSL_OP_NO_SSLv2){ - log_crypto_err("could not set SSL_OP_NO_SSLv2"); - daemon_remote_delete(rc); - return NULL; - } - if((SSL_CTX_set_options(rc->ctx, SSL_OP_NO_SSLv3) & SSL_OP_NO_SSLv3) - != SSL_OP_NO_SSLv3){ - log_crypto_err("could not set SSL_OP_NO_SSLv3"); - daemon_remote_delete(rc); - return NULL; - } -#if defined(SSL_OP_NO_TLSv1) && defined(SSL_OP_NO_TLSv1_1) - /* if we have tls 1.1 disable 1.0 */ - if((SSL_CTX_set_options(rc->ctx, SSL_OP_NO_TLSv1) & SSL_OP_NO_TLSv1) - != SSL_OP_NO_TLSv1){ - log_crypto_err("could not set SSL_OP_NO_TLSv1"); - daemon_remote_delete(rc); - return NULL; - } -#endif -#if defined(SSL_OP_NO_TLSv1_1) && defined(SSL_OP_NO_TLSv1_2) - /* if we have tls 1.2 disable 1.1 */ - if((SSL_CTX_set_options(rc->ctx, SSL_OP_NO_TLSv1_1) & SSL_OP_NO_TLSv1_1) - != SSL_OP_NO_TLSv1_1){ - log_crypto_err("could not set SSL_OP_NO_TLSv1_1"); - daemon_remote_delete(rc); - return NULL; - } -#endif -#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 */ -#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_dh2048())) { - log_crypto_err("Wanted to set DH param, but failed"); - daemon_remote_delete(rc); - return NULL; - } -#endif - return rc; - } - rc->use_cert = 1; - s_cert = fname_after_chroot(cfg->server_cert_file, cfg, 1); - s_key = fname_after_chroot(cfg->server_key_file, cfg, 1); - if(!s_cert || !s_key) { - log_err("out of memory in remote control fname"); - goto setup_error; - } - verbose(VERB_ALGO, "setup SSL certificates"); - if (!SSL_CTX_use_certificate_chain_file(rc->ctx,s_cert)) { - log_err("Error for server-cert-file: %s", s_cert); - log_crypto_err("Error in SSL_CTX use_certificate_chain_file"); - goto setup_error; - } - if(!SSL_CTX_use_PrivateKey_file(rc->ctx,s_key,SSL_FILETYPE_PEM)) { - log_err("Error for server-key-file: %s", s_key); - log_crypto_err("Error in SSL_CTX use_PrivateKey_file"); - goto setup_error; - } - if(!SSL_CTX_check_private_key(rc->ctx)) { - log_err("Error for server-key-file: %s", s_key); - log_crypto_err("Error in SSL_CTX check_private_key"); - goto setup_error; - } -#if HAVE_DECL_SSL_CTX_SET_ECDH_AUTO - if(!SSL_CTX_set_ecdh_auto(rc->ctx,1)) { - log_crypto_err("Error in SSL_CTX_ecdh_auto, not enabling ECDHE"); - } -#elif defined(USE_ECDSA) - if(1) { - EC_KEY *ecdh = EC_KEY_new_by_curve_name (NID_X9_62_prime256v1); - if (!ecdh) { - log_crypto_err("could not find p256, not enabling ECDHE"); - } else { - if (1 != SSL_CTX_set_tmp_ecdh (rc->ctx, ecdh)) { - log_crypto_err("Error in SSL_CTX_set_tmp_ecdh, not enabling ECDHE"); - } - EC_KEY_free (ecdh); - } - } -#endif - if(!SSL_CTX_load_verify_locations(rc->ctx, s_cert, NULL)) { - log_crypto_err("Error setting up SSL_CTX verify locations"); - setup_error: - free(s_cert); - free(s_key); - daemon_remote_delete(rc); - return NULL; - } - SSL_CTX_set_client_CA_list(rc->ctx, SSL_load_client_CA_file(s_cert)); - SSL_CTX_set_verify(rc->ctx, SSL_VERIFY_PEER, NULL); - free(s_cert); - free(s_key); - - return rc; -} - -void daemon_remote_clear(struct daemon_remote* rc) -{ - struct rc_state* p, *np; - if(!rc) return; - /* but do not close the ports */ - listen_list_delete(rc->accept_list); - rc->accept_list = NULL; - /* do close these sockets */ - p = rc->busy_list; - while(p) { - np = p->next; - if(p->ssl) - SSL_free(p->ssl); - comm_point_delete(p->c); - free(p); - p = np; - } - rc->busy_list = NULL; - rc->active = 0; - rc->worker = NULL; -} - -void daemon_remote_delete(struct daemon_remote* rc) -{ - if(!rc) return; - daemon_remote_clear(rc); - if(rc->ctx) { - SSL_CTX_free(rc->ctx); - } - free(rc); -} - -/** - * Add and open a new control port - * @param ip: ip str - * @param nr: port nr - * @param list: list head - * @param noproto_is_err: if lack of protocol support is an error. - * @param cfg: config with username for chown of unix-sockets. - * @return false on failure. - */ -static int -add_open(const char* ip, int nr, struct listen_port** list, int noproto_is_err, - struct config_file* cfg) -{ - struct addrinfo hints; - struct addrinfo* res; - struct listen_port* n; - int noproto; - int fd, r; - char port[15]; - snprintf(port, sizeof(port), "%d", nr); - port[sizeof(port)-1]=0; - memset(&hints, 0, sizeof(hints)); - - if(ip[0] == '/') { - /* This looks like a local socket */ - 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 - * group as the user we run as. - */ - if(fd != -1) { -#ifdef HAVE_CHOWN - if (cfg->username && cfg->username[0] && - cfg_uid != (uid_t)-1) { - if(chown(ip, cfg_uid, cfg_gid) == -1) - log_err("cannot chown %u.%u %s: %s", - (unsigned)cfg_uid, (unsigned)cfg_gid, - ip, strerror(errno)); - } - chmod(ip, (mode_t)(S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP)); -#else - (void)cfg; -#endif - } - } else { - hints.ai_socktype = SOCK_STREAM; - hints.ai_flags = AI_PASSIVE | AI_NUMERICHOST; - if((r = getaddrinfo(ip, port, &hints, &res)) != 0 || !res) { -#ifdef USE_WINSOCK - if(!noproto_is_err && r == EAI_NONAME) { - /* tried to lookup the address as name */ - return 1; /* return success, but do nothing */ - } -#endif /* USE_WINSOCK */ - log_err("control interface %s:%s getaddrinfo: %s %s", - ip?ip:"default", port, gai_strerror(r), -#ifdef EAI_SYSTEM - r==EAI_SYSTEM?(char*)strerror(errno):"" -#else - "" -#endif - ); - return 0; - } - - /* open fd */ - fd = create_tcp_accept_sock(res, 1, &noproto, 0, - cfg->ip_transparent, 0, cfg->ip_freebind, cfg->use_systemd); - freeaddrinfo(res); - } - - if(fd == -1 && noproto) { - if(!noproto_is_err) - return 1; /* return success, but do nothing */ - log_err("cannot open control interface %s %d : " - "protocol not supported", ip, nr); - return 0; - } - if(fd == -1) { - log_err("cannot open control interface %s %d", ip, nr); - return 0; - } - - /* alloc */ - n = (struct listen_port*)calloc(1, sizeof(*n)); - if(!n) { -#ifndef USE_WINSOCK - close(fd); -#else - closesocket(fd); -#endif - log_err("out of memory"); - return 0; - } - n->next = *list; - *list = n; - n->fd = fd; - return 1; -} - -struct listen_port* daemon_remote_open_ports(struct config_file* cfg) -{ - struct listen_port* l = NULL; - log_assert(cfg->remote_control_enable && cfg->control_port); - if(cfg->control_ifs) { - struct config_strlist* p; - for(p = cfg->control_ifs; p; p = p->next) { - if(!add_open(p->str, cfg->control_port, &l, 1, cfg)) { - listening_ports_free(l); - return NULL; - } - } - } else { - /* defaults */ - if(cfg->do_ip6 && - !add_open("::1", cfg->control_port, &l, 0, cfg)) { - listening_ports_free(l); - return NULL; - } - if(cfg->do_ip4 && - !add_open("127.0.0.1", cfg->control_port, &l, 1, cfg)) { - listening_ports_free(l); - return NULL; - } - } - return l; -} - -/** open accept commpoint */ -static int -accept_open(struct daemon_remote* rc, int fd) -{ - struct listen_list* n = (struct listen_list*)malloc(sizeof(*n)); - if(!n) { - log_err("out of memory"); - return 0; - } - n->next = rc->accept_list; - rc->accept_list = n; - /* open commpt */ - n->com = comm_point_create_raw(rc->worker->base, fd, 0, - &remote_accept_callback, rc); - if(!n->com) - return 0; - /* keep this port open, its fd is kept in the rc portlist */ - n->com->do_not_close = 1; - return 1; -} - -int daemon_remote_open_accept(struct daemon_remote* rc, - struct listen_port* ports, struct worker* worker) -{ - struct listen_port* p; - rc->worker = worker; - for(p = ports; p; p = p->next) { - if(!accept_open(rc, p->fd)) { - log_err("could not create accept comm point"); - return 0; - } - } - return 1; -} - -void daemon_remote_stop_accept(struct daemon_remote* rc) -{ - struct listen_list* p; - for(p=rc->accept_list; p; p=p->next) { - comm_point_stop_listening(p->com); - } -} - -void daemon_remote_start_accept(struct daemon_remote* rc) -{ - struct listen_list* p; - for(p=rc->accept_list; p; p=p->next) { - comm_point_start_listening(p->com, -1, -1); - } -} - -int remote_accept_callback(struct comm_point* c, void* arg, int err, - struct comm_reply* ATTR_UNUSED(rep)) -{ - struct daemon_remote* rc = (struct daemon_remote*)arg; - struct sockaddr_storage addr; - socklen_t addrlen; - int newfd; - struct rc_state* n; - if(err != NETEVENT_NOERROR) { - log_err("error %d on remote_accept_callback", err); - return 0; - } - /* perform the accept */ - newfd = comm_point_perform_accept(c, &addr, &addrlen); - if(newfd == -1) - return 0; - /* create new commpoint unless we are servicing already */ - if(rc->active >= rc->max_active) { - log_warn("drop incoming remote control: too many connections"); - close_exit: -#ifndef USE_WINSOCK - close(newfd); -#else - closesocket(newfd); -#endif - return 0; - } - - /* setup commpoint to service the remote control command */ - n = (struct rc_state*)calloc(1, sizeof(*n)); - if(!n) { - log_err("out of memory"); - goto close_exit; - } - /* start in reading state */ - n->c = comm_point_create_raw(rc->worker->base, newfd, 0, - &remote_control_callback, n); - if(!n->c) { - log_err("out of memory"); - free(n); - goto close_exit; - } - log_addr(VERB_QUERY, "new control connection from", &addr, addrlen); - n->c->do_not_close = 0; - comm_point_stop_listening(n->c); - comm_point_start_listening(n->c, -1, REMOTE_CONTROL_TCP_TIMEOUT); - memcpy(&n->c->repinfo.addr, &addr, addrlen); - n->c->repinfo.addrlen = addrlen; - n->shake_state = rc_hs_read; - n->ssl = SSL_new(rc->ctx); - if(!n->ssl) { - log_crypto_err("could not SSL_new"); - comm_point_delete(n->c); - free(n); - goto close_exit; - } - SSL_set_accept_state(n->ssl); - (void)SSL_set_mode(n->ssl, SSL_MODE_AUTO_RETRY); - if(!SSL_set_fd(n->ssl, newfd)) { - log_crypto_err("could not SSL_set_fd"); - SSL_free(n->ssl); - comm_point_delete(n->c); - free(n); - goto close_exit; - } - - n->rc = rc; - n->next = rc->busy_list; - rc->busy_list = n; - rc->active ++; - - /* perform the first nonblocking read already, for windows, - * so it can return wouldblock. could be faster too. */ - (void)remote_control_callback(n->c, n, NETEVENT_NOERROR, NULL); - return 0; -} - -/** delete from list */ -static void -state_list_remove_elem(struct rc_state** list, struct comm_point* c) -{ - while(*list) { - if( (*list)->c == c) { - *list = (*list)->next; - return; - } - list = &(*list)->next; - } -} - -/** decrease active count and remove commpoint from busy list */ -static void -clean_point(struct daemon_remote* rc, struct rc_state* s) -{ - state_list_remove_elem(&rc->busy_list, s->c); - rc->active --; - if(s->ssl) { - SSL_shutdown(s->ssl); - SSL_free(s->ssl); - } - comm_point_delete(s->c); - free(s); -} - -int -ssl_print_text(SSL* ssl, const char* text) -{ - int r; - if(!ssl) - return 0; - ERR_clear_error(); - if((r=SSL_write(ssl, text, (int)strlen(text))) <= 0) { - if(SSL_get_error(ssl, r) == SSL_ERROR_ZERO_RETURN) { - verbose(VERB_QUERY, "warning, in SSL_write, peer " - "closed connection"); - return 0; - } - log_crypto_err("could not SSL_write"); - return 0; - } - return 1; -} - -/** print text over the ssl connection */ -static int -ssl_print_vmsg(SSL* ssl, const char* format, va_list args) -{ - char msg[1024]; - vsnprintf(msg, sizeof(msg), format, args); - return ssl_print_text(ssl, msg); -} - -/** printf style printing to the ssl connection */ -int ssl_printf(SSL* ssl, const char* format, ...) -{ - va_list args; - int ret; - va_start(args, format); - ret = ssl_print_vmsg(ssl, format, args); - va_end(args); - return ret; -} - -int -ssl_read_line(SSL* ssl, char* buf, size_t max) -{ - int r; - size_t len = 0; - if(!ssl) - return 0; - while(len < max) { - ERR_clear_error(); - if((r=SSL_read(ssl, buf+len, 1)) <= 0) { - if(SSL_get_error(ssl, r) == SSL_ERROR_ZERO_RETURN) { - buf[len] = 0; - return 1; - } - log_crypto_err("could not SSL_read"); - return 0; - } - if(buf[len] == '\n') { - /* return string without \n */ - buf[len] = 0; - return 1; - } - len++; - } - buf[max-1] = 0; - log_err("control line too long (%d): %s", (int)max, buf); - return 0; -} - -/** skip whitespace, return new pointer into string */ -static char* -skipwhite(char* str) -{ - /* EOS \0 is not a space */ - while( isspace((unsigned char)*str) ) - str++; - return str; -} - -/** send the OK to the control client */ -static void send_ok(SSL* ssl) -{ - (void)ssl_printf(ssl, "ok\n"); -} - -/** do the stop command */ -static void -do_stop(SSL* ssl, struct daemon_remote* rc) -{ - rc->worker->need_to_exit = 1; - comm_base_exit(rc->worker->base); - send_ok(ssl); -} - -/** do the reload command */ -static void -do_reload(SSL* ssl, struct daemon_remote* rc) -{ - rc->worker->need_to_exit = 0; - comm_base_exit(rc->worker->base); - send_ok(ssl); -} - -/** do the verbosity command */ -static void -do_verbosity(SSL* ssl, char* str) -{ - int val = atoi(str); - if(val == 0 && strcmp(str, "0") != 0) { - ssl_printf(ssl, "error in verbosity number syntax: %s\n", str); - return; - } - verbosity = val; - send_ok(ssl); -} - -/** print stats from statinfo */ -static int -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; - if(!ssl_printf(ssl, "%s.num.cachemiss"SQ"%lu\n", nm, - (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/ - (s->svr.num_queries_missed_cache+ - s->svr.num_queries_prefetch) : 0.0)) return 0; - if(!ssl_printf(ssl, "%s.requestlist.max"SQ"%lu\n", nm, - (unsigned long)s->svr.max_query_list_size)) return 0; - if(!ssl_printf(ssl, "%s.requestlist.overwritten"SQ"%lu\n", nm, - (unsigned long)s->mesh_jostled)) return 0; - if(!ssl_printf(ssl, "%s.requestlist.exceeded"SQ"%lu\n", nm, - (unsigned long)s->mesh_dropped)) return 0; - if(!ssl_printf(ssl, "%s.requestlist.current.all"SQ"%lu\n", nm, - (unsigned long)s->mesh_num_states)) return 0; - if(!ssl_printf(ssl, "%s.requestlist.current.user"SQ"%lu\n", nm, - (unsigned long)s->mesh_num_reply_states)) return 0; - timeval_divide(&avg, &s->mesh_replies_sum_wait, s->mesh_replies_sent); - if(!ssl_printf(ssl, "%s.recursion.time.avg"SQ ARG_LL "d.%6.6d\n", nm, - (long long)avg.tv_sec, (int)avg.tv_usec)) return 0; - if(!ssl_printf(ssl, "%s.recursion.time.median"SQ"%g\n", nm, - s->mesh_time_median)) return 0; - if(!ssl_printf(ssl, "%s.tcpusage"SQ"%lu\n", nm, - (unsigned long)s->svr.tcp_accept_usage)) return 0; - return 1; -} - -/** print stats for one thread */ -static int -print_thread_stats(SSL* ssl, int i, struct stats_info* s) -{ - char nm[16]; - snprintf(nm, sizeof(nm), "thread%d", i); - nm[sizeof(nm)-1]=0; - return print_stats(ssl, nm, s); -} - -/** print long number */ -static int -print_longnum(SSL* ssl, const char* desc, size_t x) -{ - if(x > 1024*1024*1024) { - /* more than a Gb */ - size_t front = x / (size_t)1000000; - size_t back = x % (size_t)1000000; - return ssl_printf(ssl, "%s%u%6.6u\n", desc, - (unsigned)front, (unsigned)back); - } else { - return ssl_printf(ssl, "%s%lu\n", desc, (unsigned long)x); - } -} - -/** print mem stats */ -static int -print_mem(SSL* ssl, struct worker* worker, struct daemon* daemon) -{ - int m; - 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-> - mods.mod[m]->get_mem)); - val = (*worker->env.mesh->mods.mod[m]->get_mem) - (&worker->env, m); - } - m = modstack_find(&worker->env.mesh->mods, "iterator"); - if(m != -1) { - fptr_ok(fptr_whitelist_mod_get_mem(worker->env.mesh-> - mods.mod[m]->get_mem)); - 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; - if(!print_longnum(ssl, "mem.cache.message"SQ, msg)) - return 0; - if(!print_longnum(ssl, "mem.mod.iterator"SQ, iter)) - 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; -} - -/** print uptime stats */ -static int -print_uptime(SSL* ssl, struct worker* worker, int reset) -{ - struct timeval now = *worker->env.now_tv; - struct timeval up, dt; - timeval_subtract(&up, &now, &worker->daemon->time_boot); - timeval_subtract(&dt, &now, &worker->daemon->time_last_stat); - if(reset) - worker->daemon->time_last_stat = now; - if(!ssl_printf(ssl, "time.now"SQ ARG_LL "d.%6.6d\n", - (long long)now.tv_sec, (unsigned)now.tv_usec)) return 0; - if(!ssl_printf(ssl, "time.up"SQ ARG_LL "d.%6.6d\n", - (long long)up.tv_sec, (unsigned)up.tv_usec)) return 0; - if(!ssl_printf(ssl, "time.elapsed"SQ ARG_LL "d.%6.6d\n", - (long long)dt.tv_sec, (unsigned)dt.tv_usec)) return 0; - return 1; -} - -/** print extended histogram */ -static int -print_hist(SSL* ssl, struct stats_info* s) -{ - struct timehist* hist; - size_t i; - hist = timehist_setup(); - if(!hist) { - log_err("out of memory"); - return 0; - } - timehist_import(hist, s->svr.hist, NUM_BUCKETS_HIST); - for(i=0; i<hist->num; i++) { - if(!ssl_printf(ssl, - "histogram.%6.6d.%6.6d.to.%6.6d.%6.6d=%lu\n", - (int)hist->buckets[i].lower.tv_sec, - (int)hist->buckets[i].lower.tv_usec, - (int)hist->buckets[i].upper.tv_sec, - (int)hist->buckets[i].upper.tv_usec, - (unsigned long)hist->buckets[i].count)) { - timehist_delete(hist); - return 0; - } - } - timehist_delete(hist); - return 1; -} - -/** print extended stats */ -static int -print_ext(SSL* ssl, struct stats_info* s) -{ - int i; - char nm[16]; - const sldns_rr_descriptor* desc; - const sldns_lookup_table* lt; - /* TYPE */ - for(i=0; i<STATS_QTYPE_NUM; i++) { - if(inhibit_zero && s->svr.qtype[i] == 0) - continue; - desc = sldns_rr_descript((uint16_t)i); - if(desc && desc->_name) { - snprintf(nm, sizeof(nm), "%s", desc->_name); - } else if (i == LDNS_RR_TYPE_IXFR) { - snprintf(nm, sizeof(nm), "IXFR"); - } else if (i == LDNS_RR_TYPE_AXFR) { - snprintf(nm, sizeof(nm), "AXFR"); - } else if (i == LDNS_RR_TYPE_MAILA) { - snprintf(nm, sizeof(nm), "MAILA"); - } else if (i == LDNS_RR_TYPE_MAILB) { - snprintf(nm, sizeof(nm), "MAILB"); - } else if (i == LDNS_RR_TYPE_ANY) { - snprintf(nm, sizeof(nm), "ANY"); - } else { - snprintf(nm, sizeof(nm), "TYPE%d", i); - } - if(!ssl_printf(ssl, "num.query.type.%s"SQ"%lu\n", - nm, (unsigned long)s->svr.qtype[i])) return 0; - } - if(!inhibit_zero || s->svr.qtype_big) { - if(!ssl_printf(ssl, "num.query.type.other"SQ"%lu\n", - (unsigned long)s->svr.qtype_big)) return 0; - } - /* CLASS */ - for(i=0; i<STATS_QCLASS_NUM; i++) { - if(inhibit_zero && s->svr.qclass[i] == 0) - continue; - lt = sldns_lookup_by_id(sldns_rr_classes, i); - if(lt && lt->name) { - snprintf(nm, sizeof(nm), "%s", lt->name); - } else { - snprintf(nm, sizeof(nm), "CLASS%d", i); - } - if(!ssl_printf(ssl, "num.query.class.%s"SQ"%lu\n", - nm, (unsigned long)s->svr.qclass[i])) return 0; - } - if(!inhibit_zero || s->svr.qclass_big) { - if(!ssl_printf(ssl, "num.query.class.other"SQ"%lu\n", - (unsigned long)s->svr.qclass_big)) return 0; - } - /* OPCODE */ - for(i=0; i<STATS_OPCODE_NUM; i++) { - if(inhibit_zero && s->svr.qopcode[i] == 0) - continue; - lt = sldns_lookup_by_id(sldns_opcodes, i); - if(lt && lt->name) { - snprintf(nm, sizeof(nm), "%s", lt->name); - } else { - snprintf(nm, sizeof(nm), "OPCODE%d", i); - } - if(!ssl_printf(ssl, "num.query.opcode.%s"SQ"%lu\n", - nm, (unsigned long)s->svr.qopcode[i])) return 0; - } - /* transport */ - if(!ssl_printf(ssl, "num.query.tcp"SQ"%lu\n", - (unsigned long)s->svr.qtcp)) return 0; - if(!ssl_printf(ssl, "num.query.tcpout"SQ"%lu\n", - (unsigned long)s->svr.qtcp_outgoing)) return 0; - if(!ssl_printf(ssl, "num.query.ipv6"SQ"%lu\n", - (unsigned long)s->svr.qipv6)) return 0; - /* flags */ - if(!ssl_printf(ssl, "num.query.flags.QR"SQ"%lu\n", - (unsigned long)s->svr.qbit_QR)) return 0; - if(!ssl_printf(ssl, "num.query.flags.AA"SQ"%lu\n", - (unsigned long)s->svr.qbit_AA)) return 0; - if(!ssl_printf(ssl, "num.query.flags.TC"SQ"%lu\n", - (unsigned long)s->svr.qbit_TC)) return 0; - if(!ssl_printf(ssl, "num.query.flags.RD"SQ"%lu\n", - (unsigned long)s->svr.qbit_RD)) return 0; - if(!ssl_printf(ssl, "num.query.flags.RA"SQ"%lu\n", - (unsigned long)s->svr.qbit_RA)) return 0; - if(!ssl_printf(ssl, "num.query.flags.Z"SQ"%lu\n", - (unsigned long)s->svr.qbit_Z)) return 0; - if(!ssl_printf(ssl, "num.query.flags.AD"SQ"%lu\n", - (unsigned long)s->svr.qbit_AD)) return 0; - if(!ssl_printf(ssl, "num.query.flags.CD"SQ"%lu\n", - (unsigned long)s->svr.qbit_CD)) return 0; - if(!ssl_printf(ssl, "num.query.edns.present"SQ"%lu\n", - (unsigned long)s->svr.qEDNS)) return 0; - if(!ssl_printf(ssl, "num.query.edns.DO"SQ"%lu\n", - (unsigned long)s->svr.qEDNS_DO)) return 0; - - /* RCODE */ - for(i=0; i<STATS_RCODE_NUM; i++) { - /* Always include RCODEs 0-5 */ - if(inhibit_zero && i > LDNS_RCODE_REFUSED && s->svr.ans_rcode[i] == 0) - continue; - lt = sldns_lookup_by_id(sldns_rcodes, i); - if(lt && lt->name) { - snprintf(nm, sizeof(nm), "%s", lt->name); - } else { - snprintf(nm, sizeof(nm), "RCODE%d", i); - } - if(!ssl_printf(ssl, "num.answer.rcode.%s"SQ"%lu\n", - nm, (unsigned long)s->svr.ans_rcode[i])) return 0; - } - if(!inhibit_zero || s->svr.ans_rcode_nodata) { - if(!ssl_printf(ssl, "num.answer.rcode.nodata"SQ"%lu\n", - (unsigned long)s->svr.ans_rcode_nodata)) return 0; - } - /* validation */ - if(!ssl_printf(ssl, "num.answer.secure"SQ"%lu\n", - (unsigned long)s->svr.ans_secure)) return 0; - if(!ssl_printf(ssl, "num.answer.bogus"SQ"%lu\n", - (unsigned long)s->svr.ans_bogus)) return 0; - if(!ssl_printf(ssl, "num.rrset.bogus"SQ"%lu\n", - (unsigned long)s->svr.rrset_bogus)) return 0; - /* threat detection */ - if(!ssl_printf(ssl, "unwanted.queries"SQ"%lu\n", - (unsigned long)s->svr.unwanted_queries)) return 0; - if(!ssl_printf(ssl, "unwanted.replies"SQ"%lu\n", - (unsigned long)s->svr.unwanted_replies)) return 0; - /* cache counts */ - if(!ssl_printf(ssl, "msg.cache.count"SQ"%u\n", - (unsigned)s->svr.msg_cache_count)) return 0; - if(!ssl_printf(ssl, "rrset.cache.count"SQ"%u\n", - (unsigned)s->svr.rrset_cache_count)) return 0; - if(!ssl_printf(ssl, "infra.cache.count"SQ"%u\n", - (unsigned)s->svr.infra_cache_count)) return 0; - if(!ssl_printf(ssl, "key.cache.count"SQ"%u\n", - (unsigned)s->svr.key_cache_count)) return 0; - return 1; -} - -/** do the stats command */ -static void -do_stats(SSL* ssl, struct daemon_remote* rc, int reset) -{ - struct daemon* daemon = rc->worker->daemon; - struct stats_info total; - struct stats_info s; - int i; - log_assert(daemon->num > 0); - /* gather all thread statistics in one place */ - for(i=0; i<daemon->num; i++) { - server_stats_obtain(rc->worker, daemon->workers[i], &s, reset); - if(!print_thread_stats(ssl, i, &s)) - return; - if(i == 0) - total = s; - else server_stats_add(&total, &s); - } - /* print the thread statistics */ - total.mesh_time_median /= (double)daemon->num; - if(!print_stats(ssl, "total", &total)) - return; - if(!print_uptime(ssl, rc->worker, reset)) - return; - if(daemon->cfg->stat_extended) { - if(!print_mem(ssl, rc->worker, daemon)) - return; - if(!print_hist(ssl, &total)) - return; - if(!print_ext(ssl, &total)) - return; - } -} - -/** parse commandline argument domain name */ -static int -parse_arg_name(SSL* ssl, char* str, uint8_t** res, size_t* len, int* labs) -{ - uint8_t nm[LDNS_MAX_DOMAINLEN+1]; - size_t nmlen = sizeof(nm); - int status; - *res = NULL; - *len = 0; - *labs = 0; - status = sldns_str2wire_dname_buf(str, nm, &nmlen); - if(status != 0) { - ssl_printf(ssl, "error cannot parse name %s at %d: %s\n", str, - LDNS_WIREPARSE_OFFSET(status), - sldns_get_errorstr_parse(status)); - return 0; - } - *res = memdup(nm, nmlen); - if(!*res) { - ssl_printf(ssl, "error out of memory\n"); - return 0; - } - *labs = dname_count_size_labels(*res, len); - return 1; -} - -/** find second argument, modifies string */ -static int -find_arg2(SSL* ssl, char* arg, char** arg2) -{ - char* as = strchr(arg, ' '); - char* at = strchr(arg, '\t'); - if(as && at) { - if(at < as) - as = at; - as[0]=0; - *arg2 = skipwhite(as+1); - } else if(as) { - as[0]=0; - *arg2 = skipwhite(as+1); - } else if(at) { - at[0]=0; - *arg2 = skipwhite(at+1); - } else { - ssl_printf(ssl, "error could not find next argument " - "after %s\n", arg); - return 0; - } - return 1; -} - -/** Add a new zone */ -static int -perform_zone_add(SSL* ssl, struct local_zones* zones, char* arg) -{ - uint8_t* nm; - int nmlabs; - size_t nmlen; - char* arg2; - enum localzone_type t; - struct local_zone* z; - if(!find_arg2(ssl, arg, &arg2)) - return 0; - if(!parse_arg_name(ssl, arg, &nm, &nmlen, &nmlabs)) - return 0; - if(!local_zone_str2type(arg2, &t)) { - ssl_printf(ssl, "error not a zone type. %s\n", arg2); - free(nm); - return 0; - } - 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(&zones->lock); - return 1; - } - if(!local_zones_add_zone(zones, nm, nmlen, - nmlabs, LDNS_RR_CLASS_IN, t)) { - lock_rw_unlock(&zones->lock); - ssl_printf(ssl, "error out of memory\n"); - return 0; - } - 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); -} - -/** Do the local_zones command */ -static void -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 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(zones, z); - } - 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); -} - -/** Do the local_zones_remove command */ -static void -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(zones, arg)) { - ssl_printf(ssl,"error in syntax or out of memory, %s\n", arg); - 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); -} - -/** Do the local_datas command */ -static void -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 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) -{ - uint8_t* nm; - int nmlabs; - size_t nmlen; - if(!parse_arg_name(ssl, arg, &nm, &nmlen, &nmlabs)) - return; - (void)print_deleg_lookup(ssl, worker, nm, nmlen, nmlabs); - free(nm); -} - -/** flush something from rrset and msg caches */ -static void -do_cache_remove(struct worker* worker, uint8_t* nm, size_t nmlen, - uint16_t t, uint16_t c) -{ - 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) - rrset_cache_remove(worker->env.rrset_cache, nm, nmlen, t, c, - PACKED_RRSET_SOA_NEG); - k.qname = nm; - 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) { - /* for AAAA also flush dns64 bit_cd packet */ - h = query_info_hash(&k, BIT_CD); - slabhash_remove(worker->env.msg_cache, h, &k); - } -} - -/** flush a type */ -static void -do_flush_type(SSL* ssl, struct worker* worker, char* arg) -{ - uint8_t* nm; - int nmlabs; - size_t nmlen; - char* arg2; - uint16_t t; - if(!find_arg2(ssl, arg, &arg2)) - return; - if(!parse_arg_name(ssl, arg, &nm, &nmlen, &nmlabs)) - return; - t = sldns_get_rr_type_by_name(arg2); - do_cache_remove(worker, nm, nmlen, t, LDNS_RR_CLASS_IN); - - free(nm); - send_ok(ssl); -} - -/** flush statistics */ -static void -do_flush_stats(SSL* ssl, struct worker* worker) -{ - worker_stats_clear(worker); - send_ok(ssl); -} - -/** - * Local info for deletion functions - */ -struct del_info { - /** worker */ - struct worker* worker; - /** name to delete */ - uint8_t* name; - /** length */ - size_t len; - /** labels */ - int labs; - /** time to invalidate to */ - time_t expired; - /** number of rrsets removed */ - size_t num_rrsets; - /** number of msgs removed */ - size_t num_msgs; - /** number of key entries removed */ - size_t num_keys; - /** length of addr */ - socklen_t addrlen; - /** socket address for host deletion */ - struct sockaddr_storage addr; -}; - -/** callback to delete hosts in infra cache */ -static void -infra_del_host(struct lruhash_entry* e, void* arg) -{ - /* entry is locked */ - struct del_info* inf = (struct del_info*)arg; - struct infra_key* k = (struct infra_key*)e->key; - if(sockaddr_cmp(&inf->addr, inf->addrlen, &k->addr, k->addrlen) == 0) { - struct infra_data* d = (struct infra_data*)e->data; - d->probedelay = 0; - d->timeout_A = 0; - d->timeout_AAAA = 0; - d->timeout_other = 0; - rtt_init(&d->rtt); - if(d->ttl > inf->expired) { - d->ttl = inf->expired; - inf->num_keys++; - } - } -} - -/** flush infra cache */ -static void -do_flush_infra(SSL* ssl, struct worker* worker, char* arg) -{ - struct sockaddr_storage addr; - socklen_t len; - struct del_info inf; - if(strcmp(arg, "all") == 0) { - slabhash_clear(worker->env.infra_cache->hosts); - send_ok(ssl); - return; - } - if(!ipstrtoaddr(arg, UNBOUND_DNS_PORT, &addr, &len)) { - (void)ssl_printf(ssl, "error parsing ip addr: '%s'\n", arg); - return; - } - /* delete all entries from cache */ - /* what we do is to set them all expired */ - inf.worker = worker; - inf.name = 0; - inf.len = 0; - inf.labs = 0; - inf.expired = *worker->env.now; - inf.expired -= 3; /* handle 3 seconds skew between threads */ - inf.num_rrsets = 0; - inf.num_msgs = 0; - inf.num_keys = 0; - inf.addrlen = len; - memmove(&inf.addr, &addr, len); - slabhash_traverse(worker->env.infra_cache->hosts, 1, &infra_del_host, - &inf); - send_ok(ssl); -} - -/** flush requestlist */ -static void -do_flush_requestlist(SSL* ssl, struct worker* worker) -{ - mesh_delete_all(worker->env.mesh); - send_ok(ssl); -} - -/** callback to delete rrsets in a zone */ -static void -zone_del_rrset(struct lruhash_entry* e, void* arg) -{ - /* entry is locked */ - struct del_info* inf = (struct del_info*)arg; - struct ub_packed_rrset_key* k = (struct ub_packed_rrset_key*)e->key; - if(dname_subdomain_c(k->rk.dname, inf->name)) { - struct packed_rrset_data* d = - (struct packed_rrset_data*)e->data; - if(d->ttl > inf->expired) { - d->ttl = inf->expired; - inf->num_rrsets++; - } - } -} - -/** callback to delete messages in a zone */ -static void -zone_del_msg(struct lruhash_entry* e, void* arg) -{ - /* entry is locked */ - struct del_info* inf = (struct del_info*)arg; - struct msgreply_entry* k = (struct msgreply_entry*)e->key; - if(dname_subdomain_c(k->key.qname, inf->name)) { - struct reply_info* d = (struct reply_info*)e->data; - if(d->ttl > inf->expired) { - d->ttl = inf->expired; - inf->num_msgs++; - } - } -} - -/** callback to delete keys in zone */ -static void -zone_del_kcache(struct lruhash_entry* e, void* arg) -{ - /* entry is locked */ - struct del_info* inf = (struct del_info*)arg; - struct key_entry_key* k = (struct key_entry_key*)e->key; - if(dname_subdomain_c(k->name, inf->name)) { - struct key_entry_data* d = (struct key_entry_data*)e->data; - if(d->ttl > inf->expired) { - d->ttl = inf->expired; - inf->num_keys++; - } - } -} - -/** remove all rrsets and keys from zone from cache */ -static void -do_flush_zone(SSL* ssl, struct worker* worker, char* arg) -{ - uint8_t* nm; - int nmlabs; - size_t nmlen; - struct del_info inf; - if(!parse_arg_name(ssl, arg, &nm, &nmlen, &nmlabs)) - return; - /* delete all RRs and key entries from zone */ - /* what we do is to set them all expired */ - inf.worker = worker; - inf.name = nm; - inf.len = nmlen; - inf.labs = nmlabs; - inf.expired = *worker->env.now; - inf.expired -= 3; /* handle 3 seconds skew between threads */ - inf.num_rrsets = 0; - inf.num_msgs = 0; - inf.num_keys = 0; - slabhash_traverse(&worker->env.rrset_cache->table, 1, - &zone_del_rrset, &inf); - - slabhash_traverse(worker->env.msg_cache, 1, &zone_del_msg, &inf); - - /* and validator cache */ - if(worker->env.key_cache) { - slabhash_traverse(worker->env.key_cache->slab, 1, - &zone_del_kcache, &inf); - } - - free(nm); - - (void)ssl_printf(ssl, "ok removed %lu rrsets, %lu messages " - "and %lu key entries\n", (unsigned long)inf.num_rrsets, - (unsigned long)inf.num_msgs, (unsigned long)inf.num_keys); -} - -/** callback to delete bogus rrsets */ -static void -bogus_del_rrset(struct lruhash_entry* e, void* arg) -{ - /* entry is locked */ - struct del_info* inf = (struct del_info*)arg; - struct packed_rrset_data* d = (struct packed_rrset_data*)e->data; - if(d->security == sec_status_bogus) { - d->ttl = inf->expired; - inf->num_rrsets++; - } -} - -/** callback to delete bogus messages */ -static void -bogus_del_msg(struct lruhash_entry* e, void* arg) -{ - /* entry is locked */ - struct del_info* inf = (struct del_info*)arg; - struct reply_info* d = (struct reply_info*)e->data; - if(d->security == sec_status_bogus) { - d->ttl = inf->expired; - inf->num_msgs++; - } -} - -/** callback to delete bogus keys */ -static void -bogus_del_kcache(struct lruhash_entry* e, void* arg) -{ - /* entry is locked */ - struct del_info* inf = (struct del_info*)arg; - struct key_entry_data* d = (struct key_entry_data*)e->data; - if(d->isbad) { - d->ttl = inf->expired; - inf->num_keys++; - } -} - -/** remove all bogus rrsets, msgs and keys from cache */ -static void -do_flush_bogus(SSL* ssl, struct worker* worker) -{ - struct del_info inf; - /* what we do is to set them all expired */ - inf.worker = worker; - inf.expired = *worker->env.now; - inf.expired -= 3; /* handle 3 seconds skew between threads */ - inf.num_rrsets = 0; - inf.num_msgs = 0; - inf.num_keys = 0; - slabhash_traverse(&worker->env.rrset_cache->table, 1, - &bogus_del_rrset, &inf); - - slabhash_traverse(worker->env.msg_cache, 1, &bogus_del_msg, &inf); - - /* and validator cache */ - if(worker->env.key_cache) { - slabhash_traverse(worker->env.key_cache->slab, 1, - &bogus_del_kcache, &inf); - } - - (void)ssl_printf(ssl, "ok removed %lu rrsets, %lu messages " - "and %lu key entries\n", (unsigned long)inf.num_rrsets, - (unsigned long)inf.num_msgs, (unsigned long)inf.num_keys); -} - -/** callback to delete negative and servfail rrsets */ -static void -negative_del_rrset(struct lruhash_entry* e, void* arg) -{ - /* entry is locked */ - struct del_info* inf = (struct del_info*)arg; - struct ub_packed_rrset_key* k = (struct ub_packed_rrset_key*)e->key; - struct packed_rrset_data* d = (struct packed_rrset_data*)e->data; - /* delete the parentside negative cache rrsets, - * these are namerserver rrsets that failed lookup, rdata empty */ - if((k->rk.flags & PACKED_RRSET_PARENT_SIDE) && d->count == 1 && - d->rrsig_count == 0 && d->rr_len[0] == 0) { - d->ttl = inf->expired; - inf->num_rrsets++; - } -} - -/** callback to delete negative and servfail messages */ -static void -negative_del_msg(struct lruhash_entry* e, void* arg) -{ - /* entry is locked */ - struct del_info* inf = (struct del_info*)arg; - struct reply_info* d = (struct reply_info*)e->data; - /* rcode not NOERROR: NXDOMAIN, SERVFAIL, ..: an nxdomain or error - * or NOERROR rcode with ANCOUNT==0: a NODATA answer */ - if(FLAGS_GET_RCODE(d->flags) != 0 || d->an_numrrsets == 0) { - d->ttl = inf->expired; - inf->num_msgs++; - } -} - -/** callback to delete negative key entries */ -static void -negative_del_kcache(struct lruhash_entry* e, void* arg) -{ - /* entry is locked */ - struct del_info* inf = (struct del_info*)arg; - struct key_entry_data* d = (struct key_entry_data*)e->data; - /* could be bad because of lookup failure on the DS, DNSKEY, which - * was nxdomain or servfail, and thus a result of negative lookups */ - if(d->isbad) { - d->ttl = inf->expired; - inf->num_keys++; - } -} - -/** remove all negative(NODATA,NXDOMAIN), and servfail messages from cache */ -static void -do_flush_negative(SSL* ssl, struct worker* worker) -{ - struct del_info inf; - /* what we do is to set them all expired */ - inf.worker = worker; - inf.expired = *worker->env.now; - inf.expired -= 3; /* handle 3 seconds skew between threads */ - inf.num_rrsets = 0; - inf.num_msgs = 0; - inf.num_keys = 0; - slabhash_traverse(&worker->env.rrset_cache->table, 1, - &negative_del_rrset, &inf); - - slabhash_traverse(worker->env.msg_cache, 1, &negative_del_msg, &inf); - - /* and validator cache */ - if(worker->env.key_cache) { - slabhash_traverse(worker->env.key_cache->slab, 1, - &negative_del_kcache, &inf); - } - - (void)ssl_printf(ssl, "ok removed %lu rrsets, %lu messages " - "and %lu key entries\n", (unsigned long)inf.num_rrsets, - (unsigned long)inf.num_msgs, (unsigned long)inf.num_keys); -} - -/** remove name rrset from cache */ -static void -do_flush_name(SSL* ssl, struct worker* w, char* arg) -{ - uint8_t* nm; - int nmlabs; - size_t nmlen; - if(!parse_arg_name(ssl, arg, &nm, &nmlen, &nmlabs)) - return; - do_cache_remove(w, nm, nmlen, LDNS_RR_TYPE_A, LDNS_RR_CLASS_IN); - do_cache_remove(w, nm, nmlen, LDNS_RR_TYPE_AAAA, LDNS_RR_CLASS_IN); - do_cache_remove(w, nm, nmlen, LDNS_RR_TYPE_NS, LDNS_RR_CLASS_IN); - do_cache_remove(w, nm, nmlen, LDNS_RR_TYPE_SOA, LDNS_RR_CLASS_IN); - do_cache_remove(w, nm, nmlen, LDNS_RR_TYPE_CNAME, LDNS_RR_CLASS_IN); - do_cache_remove(w, nm, nmlen, LDNS_RR_TYPE_DNAME, LDNS_RR_CLASS_IN); - do_cache_remove(w, nm, nmlen, LDNS_RR_TYPE_MX, LDNS_RR_CLASS_IN); - do_cache_remove(w, nm, nmlen, LDNS_RR_TYPE_PTR, LDNS_RR_CLASS_IN); - do_cache_remove(w, nm, nmlen, LDNS_RR_TYPE_SRV, LDNS_RR_CLASS_IN); - do_cache_remove(w, nm, nmlen, LDNS_RR_TYPE_NAPTR, LDNS_RR_CLASS_IN); - - free(nm); - send_ok(ssl); -} - -/** printout a delegation point info */ -static int -ssl_print_name_dp(SSL* ssl, const char* str, uint8_t* nm, uint16_t dclass, - struct delegpt* dp) -{ - char buf[257]; - struct delegpt_ns* ns; - struct delegpt_addr* a; - int f = 0; - if(str) { /* print header for forward, stub */ - char* c = sldns_wire2str_class(dclass); - dname_str(nm, buf); - if(!ssl_printf(ssl, "%s %s %s ", buf, (c?c:"CLASS??"), str)) { - free(c); - return 0; - } - free(c); - } - for(ns = dp->nslist; ns; ns = ns->next) { - dname_str(ns->name, buf); - if(!ssl_printf(ssl, "%s%s", (f?" ":""), buf)) - return 0; - f = 1; - } - for(a = dp->target_list; a; a = a->next_target) { - addr_to_str(&a->addr, a->addrlen, buf, sizeof(buf)); - if(!ssl_printf(ssl, "%s%s", (f?" ":""), buf)) - return 0; - f = 1; - } - return ssl_printf(ssl, "\n"); -} - - -/** print root forwards */ -static int -print_root_fwds(SSL* ssl, struct iter_forwards* fwds, uint8_t* root) -{ - struct delegpt* dp; - dp = forwards_lookup(fwds, root, LDNS_RR_CLASS_IN); - if(!dp) - return ssl_printf(ssl, "off (using root hints)\n"); - /* if dp is returned it must be the root */ - log_assert(query_dname_compare(dp->name, root)==0); - return ssl_print_name_dp(ssl, NULL, root, LDNS_RR_CLASS_IN, dp); -} - -/** parse args into delegpt */ -static struct delegpt* -parse_delegpt(SSL* ssl, char* args, uint8_t* nm, int allow_names) -{ - /* parse args and add in */ - char* p = args; - char* todo; - struct delegpt* dp = delegpt_create_mlc(nm); - struct sockaddr_storage addr; - socklen_t addrlen; - if(!dp) { - (void)ssl_printf(ssl, "error out of memory\n"); - return NULL; - } - while(p) { - todo = p; - p = strchr(p, ' '); /* find next spot, if any */ - if(p) { - *p++ = 0; /* end this spot */ - p = skipwhite(p); /* position at next spot */ - } - /* parse address */ - if(!extstrtoaddr(todo, &addr, &addrlen)) { - if(allow_names) { - uint8_t* n = NULL; - size_t ln; - int lb; - if(!parse_arg_name(ssl, todo, &n, &ln, &lb)) { - (void)ssl_printf(ssl, "error cannot " - "parse IP address or name " - "'%s'\n", todo); - delegpt_free_mlc(dp); - return NULL; - } - if(!delegpt_add_ns_mlc(dp, n, 0)) { - (void)ssl_printf(ssl, "error out of memory\n"); - free(n); - delegpt_free_mlc(dp); - return NULL; - } - free(n); - - } else { - (void)ssl_printf(ssl, "error cannot parse" - " IP address '%s'\n", todo); - delegpt_free_mlc(dp); - return NULL; - } - } else { - /* add address */ - if(!delegpt_add_addr_mlc(dp, &addr, addrlen, 0, 0)) { - (void)ssl_printf(ssl, "error out of memory\n"); - delegpt_free_mlc(dp); - return NULL; - } - } - } - dp->has_parent_side_NS = 1; - return dp; -} - -/** do the status command */ -static void -do_forward(SSL* ssl, struct worker* worker, char* args) -{ - struct iter_forwards* fwd = worker->env.fwds; - uint8_t* root = (uint8_t*)"\000"; - if(!fwd) { - (void)ssl_printf(ssl, "error: structure not allocated\n"); - return; - } - if(args == NULL || args[0] == 0) { - (void)print_root_fwds(ssl, fwd, root); - return; - } - /* set root forwards for this thread. since we are in remote control - * the actual mesh is not running, so we can freely edit it. */ - /* delete all the existing queries first */ - mesh_delete_all(worker->env.mesh); - if(strcmp(args, "off") == 0) { - forwards_delete_zone(fwd, LDNS_RR_CLASS_IN, root); - } else { - struct delegpt* dp; - if(!(dp = parse_delegpt(ssl, args, root, 0))) - return; - if(!forwards_add_zone(fwd, LDNS_RR_CLASS_IN, dp)) { - (void)ssl_printf(ssl, "error out of memory\n"); - return; - } - } - send_ok(ssl); -} - -static int -parse_fs_args(SSL* ssl, char* args, uint8_t** nm, struct delegpt** dp, - int* insecure, int* prime) -{ - char* zonename; - char* rest; - size_t nmlen; - int nmlabs; - /* parse all -x args */ - while(args[0] == '+') { - if(!find_arg2(ssl, args, &rest)) - return 0; - while(*(++args) != 0) { - if(*args == 'i' && insecure) - *insecure = 1; - else if(*args == 'p' && prime) - *prime = 1; - else { - (void)ssl_printf(ssl, "error: unknown option %s\n", args); - return 0; - } - } - args = rest; - } - /* parse name */ - if(dp) { - if(!find_arg2(ssl, args, &rest)) - return 0; - zonename = args; - args = rest; - } else zonename = args; - if(!parse_arg_name(ssl, zonename, nm, &nmlen, &nmlabs)) - return 0; - - /* parse dp */ - if(dp) { - if(!(*dp = parse_delegpt(ssl, args, *nm, 1))) { - free(*nm); - return 0; - } - } - return 1; -} - -/** do the forward_add command */ -static void -do_forward_add(SSL* ssl, struct worker* worker, char* args) -{ - struct iter_forwards* fwd = worker->env.fwds; - int insecure = 0; - uint8_t* nm = NULL; - struct delegpt* dp = NULL; - if(!parse_fs_args(ssl, args, &nm, &dp, &insecure, NULL)) - return; - if(insecure && worker->env.anchors) { - if(!anchors_add_insecure(worker->env.anchors, LDNS_RR_CLASS_IN, - nm)) { - (void)ssl_printf(ssl, "error out of memory\n"); - delegpt_free_mlc(dp); - free(nm); - return; - } - } - if(!forwards_add_zone(fwd, LDNS_RR_CLASS_IN, dp)) { - (void)ssl_printf(ssl, "error out of memory\n"); - free(nm); - return; - } - free(nm); - send_ok(ssl); -} - -/** do the forward_remove command */ -static void -do_forward_remove(SSL* ssl, struct worker* worker, char* args) -{ - struct iter_forwards* fwd = worker->env.fwds; - int insecure = 0; - uint8_t* nm = NULL; - if(!parse_fs_args(ssl, args, &nm, NULL, &insecure, NULL)) - return; - if(insecure && worker->env.anchors) - anchors_delete_insecure(worker->env.anchors, LDNS_RR_CLASS_IN, - nm); - forwards_delete_zone(fwd, LDNS_RR_CLASS_IN, nm); - free(nm); - send_ok(ssl); -} - -/** do the stub_add command */ -static void -do_stub_add(SSL* ssl, struct worker* worker, char* args) -{ - struct iter_forwards* fwd = worker->env.fwds; - int insecure = 0, prime = 0; - uint8_t* nm = NULL; - struct delegpt* dp = NULL; - if(!parse_fs_args(ssl, args, &nm, &dp, &insecure, &prime)) - return; - if(insecure && worker->env.anchors) { - if(!anchors_add_insecure(worker->env.anchors, LDNS_RR_CLASS_IN, - nm)) { - (void)ssl_printf(ssl, "error out of memory\n"); - delegpt_free_mlc(dp); - free(nm); - return; - } - } - if(!forwards_add_stub_hole(fwd, LDNS_RR_CLASS_IN, nm)) { - if(insecure && worker->env.anchors) - anchors_delete_insecure(worker->env.anchors, - LDNS_RR_CLASS_IN, nm); - (void)ssl_printf(ssl, "error out of memory\n"); - delegpt_free_mlc(dp); - free(nm); - return; - } - if(!hints_add_stub(worker->env.hints, LDNS_RR_CLASS_IN, dp, !prime)) { - (void)ssl_printf(ssl, "error out of memory\n"); - forwards_delete_stub_hole(fwd, LDNS_RR_CLASS_IN, nm); - if(insecure && worker->env.anchors) - anchors_delete_insecure(worker->env.anchors, - LDNS_RR_CLASS_IN, nm); - free(nm); - return; - } - free(nm); - send_ok(ssl); -} - -/** do the stub_remove command */ -static void -do_stub_remove(SSL* ssl, struct worker* worker, char* args) -{ - struct iter_forwards* fwd = worker->env.fwds; - int insecure = 0; - uint8_t* nm = NULL; - if(!parse_fs_args(ssl, args, &nm, NULL, &insecure, NULL)) - return; - if(insecure && worker->env.anchors) - anchors_delete_insecure(worker->env.anchors, LDNS_RR_CLASS_IN, - nm); - forwards_delete_stub_hole(fwd, LDNS_RR_CLASS_IN, nm); - hints_delete_stub(worker->env.hints, LDNS_RR_CLASS_IN, nm); - free(nm); - send_ok(ssl); -} - -/** do the insecure_add command */ -static void -do_insecure_add(SSL* ssl, struct worker* worker, char* arg) -{ - size_t nmlen; - int nmlabs; - uint8_t* nm = NULL; - if(!parse_arg_name(ssl, arg, &nm, &nmlen, &nmlabs)) - return; - if(worker->env.anchors) { - if(!anchors_add_insecure(worker->env.anchors, - LDNS_RR_CLASS_IN, nm)) { - (void)ssl_printf(ssl, "error out of memory\n"); - free(nm); - return; - } - } - free(nm); - send_ok(ssl); -} - -/** do the insecure_remove command */ -static void -do_insecure_remove(SSL* ssl, struct worker* worker, char* arg) -{ - size_t nmlen; - int nmlabs; - uint8_t* nm = NULL; - if(!parse_arg_name(ssl, arg, &nm, &nmlen, &nmlabs)) - return; - if(worker->env.anchors) - anchors_delete_insecure(worker->env.anchors, - LDNS_RR_CLASS_IN, nm); - free(nm); - send_ok(ssl); -} - -static void -do_insecure_list(SSL* ssl, struct worker* worker) -{ - char buf[257]; - struct trust_anchor* a; - if(worker->env.anchors) { - RBTREE_FOR(a, struct trust_anchor*, worker->env.anchors->tree) { - if(a->numDS == 0 && a->numDNSKEY == 0) { - dname_str(a->name, buf); - ssl_printf(ssl, "%s\n", buf); - } - } - } -} - -/** do the status command */ -static void -do_status(SSL* ssl, struct worker* worker) -{ - int i; - time_t uptime; - if(!ssl_printf(ssl, "version: %s\n", PACKAGE_VERSION)) - return; - if(!ssl_printf(ssl, "verbosity: %d\n", verbosity)) - return; - if(!ssl_printf(ssl, "threads: %d\n", worker->daemon->num)) - return; - if(!ssl_printf(ssl, "modules: %d [", worker->daemon->mods.num)) - return; - for(i=0; i<worker->daemon->mods.num; i++) { - if(!ssl_printf(ssl, " %s", worker->daemon->mods.mod[i]->name)) - return; - } - if(!ssl_printf(ssl, " ]\n")) - return; - uptime = (time_t)time(NULL) - (time_t)worker->daemon->time_boot.tv_sec; - if(!ssl_printf(ssl, "uptime: " ARG_LL "d seconds\n", (long long)uptime)) - return; - if(!ssl_printf(ssl, "options:%s%s\n" , - (worker->daemon->reuseport?" reuseport":""), - (worker->daemon->rc->accept_list?" control(ssl)":""))) - return; - if(!ssl_printf(ssl, "unbound (pid %d) is running...\n", - (int)getpid())) - return; -} - -/** get age for the mesh state */ -static void -get_mesh_age(struct mesh_state* m, char* buf, size_t len, - struct module_env* env) -{ - if(m->reply_list) { - struct timeval d; - struct mesh_reply* r = m->reply_list; - /* last reply is the oldest */ - while(r && r->next) - r = r->next; - timeval_subtract(&d, env->now_tv, &r->start_time); - snprintf(buf, len, ARG_LL "d.%6.6d", - (long long)d.tv_sec, (int)d.tv_usec); - } else { - snprintf(buf, len, "-"); - } -} - -/** get status of a mesh state */ -static void -get_mesh_status(struct mesh_area* mesh, struct mesh_state* m, - char* buf, size_t len) -{ - enum module_ext_state s = m->s.ext_state[m->s.curmod]; - const char *modname = mesh->mods.mod[m->s.curmod]->name; - size_t l; - if(strcmp(modname, "iterator") == 0 && s == module_wait_reply && - m->s.minfo[m->s.curmod]) { - /* break into iterator to find out who its waiting for */ - struct iter_qstate* qstate = (struct iter_qstate*) - m->s.minfo[m->s.curmod]; - struct outbound_list* ol = &qstate->outlist; - struct outbound_entry* e; - snprintf(buf, len, "%s wait for", modname); - l = strlen(buf); - buf += l; len -= l; - if(ol->first == NULL) - snprintf(buf, len, " (empty_list)"); - for(e = ol->first; e; e = e->next) { - snprintf(buf, len, " "); - l = strlen(buf); - buf += l; len -= l; - addr_to_str(&e->qsent->addr, e->qsent->addrlen, - buf, len); - l = strlen(buf); - buf += l; len -= l; - } - } else if(s == module_wait_subquery) { - /* look in subs from mesh state to see what */ - char nm[257]; - struct mesh_state_ref* sub; - snprintf(buf, len, "%s wants", modname); - l = strlen(buf); - buf += l; len -= l; - if(m->sub_set.count == 0) - snprintf(buf, len, " (empty_list)"); - RBTREE_FOR(sub, struct mesh_state_ref*, &m->sub_set) { - char* t = sldns_wire2str_type(sub->s->s.qinfo.qtype); - char* c = sldns_wire2str_class(sub->s->s.qinfo.qclass); - dname_str(sub->s->s.qinfo.qname, nm); - snprintf(buf, len, " %s %s %s", (t?t:"TYPE??"), - (c?c:"CLASS??"), nm); - l = strlen(buf); - buf += l; len -= l; - free(t); - free(c); - } - } else { - snprintf(buf, len, "%s is %s", modname, strextstate(s)); - } -} - -/** do the dump_requestlist command */ -static void -do_dump_requestlist(SSL* ssl, struct worker* worker) -{ - struct mesh_area* mesh; - struct mesh_state* m; - int num = 0; - char buf[257]; - char timebuf[32]; - char statbuf[10240]; - if(!ssl_printf(ssl, "thread #%d\n", worker->thread_num)) - return; - if(!ssl_printf(ssl, "# type cl name seconds module status\n")) - return; - /* show worker mesh contents */ - mesh = worker->env.mesh; - if(!mesh) return; - RBTREE_FOR(m, struct mesh_state*, &mesh->all) { - char* t = sldns_wire2str_type(m->s.qinfo.qtype); - char* c = sldns_wire2str_class(m->s.qinfo.qclass); - dname_str(m->s.qinfo.qname, buf); - get_mesh_age(m, timebuf, sizeof(timebuf), &worker->env); - get_mesh_status(mesh, m, statbuf, sizeof(statbuf)); - if(!ssl_printf(ssl, "%3d %4s %2s %s %s %s\n", - num, (t?t:"TYPE??"), (c?c:"CLASS??"), buf, timebuf, - statbuf)) { - free(t); - free(c); - return; - } - num++; - free(t); - free(c); - } -} - -/** structure for argument data for dump infra host */ -struct infra_arg { - /** the infra cache */ - struct infra_cache* infra; - /** the SSL connection */ - SSL* ssl; - /** the time now */ - time_t now; - /** ssl failure? stop writing and skip the rest. If the tcp - * connection is broken, and writes fail, we then stop writing. */ - int ssl_failed; -}; - -/** callback for every host element in the infra cache */ -static void -dump_infra_host(struct lruhash_entry* e, void* arg) -{ - struct infra_arg* a = (struct infra_arg*)arg; - struct infra_key* k = (struct infra_key*)e->key; - struct infra_data* d = (struct infra_data*)e->data; - char ip_str[1024]; - char name[257]; - if(a->ssl_failed) - return; - addr_to_str(&k->addr, k->addrlen, ip_str, sizeof(ip_str)); - dname_str(k->zonename, name); - /* skip expired stuff (only backed off) */ - if(d->ttl < a->now) { - if(d->rtt.rto >= USEFUL_SERVER_TOP_TIMEOUT) { - if(!ssl_printf(a->ssl, "%s %s expired rto %d\n", ip_str, - name, d->rtt.rto)) { - a->ssl_failed = 1; - return; - } - } - return; - } - if(!ssl_printf(a->ssl, "%s %s ttl %lu ping %d var %d rtt %d rto %d " - "tA %d tAAAA %d tother %d " - "ednsknown %d edns %d delay %d lame dnssec %d rec %d A %d " - "other %d\n", ip_str, name, (unsigned long)(d->ttl - a->now), - d->rtt.srtt, d->rtt.rttvar, rtt_notimeout(&d->rtt), d->rtt.rto, - d->timeout_A, d->timeout_AAAA, d->timeout_other, - (int)d->edns_lame_known, (int)d->edns_version, - (int)(a->now<d->probedelay?(d->probedelay - a->now):0), - (int)d->isdnsseclame, (int)d->rec_lame, (int)d->lame_type_A, - (int)d->lame_other)) { - a->ssl_failed = 1; - return; - } -} - -/** do the dump_infra command */ -static void -do_dump_infra(SSL* ssl, struct worker* worker) -{ - struct infra_arg arg; - arg.infra = worker->env.infra_cache; - arg.ssl = ssl; - arg.now = *worker->env.now; - arg.ssl_failed = 0; - slabhash_traverse(arg.infra->hosts, 0, &dump_infra_host, (void*)&arg); -} - -/** do the log_reopen command */ -static void -do_log_reopen(SSL* ssl, struct worker* worker) -{ - struct config_file* cfg = worker->env.cfg; - send_ok(ssl); - log_init(cfg->logfile, cfg->use_syslog, cfg->chrootdir); -} - -/** do the set_option command */ -static void -do_set_option(SSL* ssl, struct worker* worker, char* arg) -{ - char* arg2; - if(!find_arg2(ssl, arg, &arg2)) - return; - if(!config_set_option(worker->env.cfg, arg, arg2)) { - (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); -} - -/* routine to printout option values over SSL */ -void remote_get_opt_ssl(char* line, void* arg) -{ - SSL* ssl = (SSL*)arg; - (void)ssl_printf(ssl, "%s\n", line); -} - -/** do the get_option command */ -static void -do_get_option(SSL* ssl, struct worker* worker, char* arg) -{ - int r; - r = config_get_option(worker->env.cfg, arg, remote_get_opt_ssl, ssl); - if(!r) { - (void)ssl_printf(ssl, "error unknown option\n"); - return; - } -} - -/** do the list_forwards command */ -static void -do_list_forwards(SSL* ssl, struct worker* worker) -{ - /* since its a per-worker structure no locks needed */ - struct iter_forwards* fwds = worker->env.fwds; - struct iter_forward_zone* z; - struct trust_anchor* a; - int insecure; - RBTREE_FOR(z, struct iter_forward_zone*, fwds->tree) { - if(!z->dp) continue; /* skip empty marker for stub */ - - /* see if it is insecure */ - insecure = 0; - if(worker->env.anchors && - (a=anchor_find(worker->env.anchors, z->name, - z->namelabs, z->namelen, z->dclass))) { - if(!a->keylist && !a->numDS && !a->numDNSKEY) - insecure = 1; - lock_basic_unlock(&a->lock); - } - - if(!ssl_print_name_dp(ssl, (insecure?"forward +i":"forward"), - z->name, z->dclass, z->dp)) - return; - } -} - -/** do the list_stubs command */ -static void -do_list_stubs(SSL* ssl, struct worker* worker) -{ - struct iter_hints_stub* z; - struct trust_anchor* a; - int insecure; - char str[32]; - RBTREE_FOR(z, struct iter_hints_stub*, &worker->env.hints->tree) { - - /* see if it is insecure */ - insecure = 0; - if(worker->env.anchors && - (a=anchor_find(worker->env.anchors, z->node.name, - z->node.labs, z->node.len, z->node.dclass))) { - if(!a->keylist && !a->numDS && !a->numDNSKEY) - insecure = 1; - lock_basic_unlock(&a->lock); - } - - snprintf(str, sizeof(str), "stub %sprime%s", - (z->noprime?"no":""), (insecure?" +i":"")); - if(!ssl_print_name_dp(ssl, str, z->node.name, - z->node.dclass, z->dp)) - return; - } -} - -/** do the list_local_zones command */ -static void -do_list_local_zones(SSL* ssl, struct local_zones* zones) -{ - struct local_zone* z; - char buf[257]; - lock_rw_rdlock(&zones->lock); - RBTREE_FOR(z, struct local_zone*, &zones->ztree) { - lock_rw_rdlock(&z->lock); - dname_str(z->name, buf); - if(!ssl_printf(ssl, "%s %s\n", buf, - local_zone_type2str(z->type))) { - /* failure to print */ - lock_rw_unlock(&z->lock); - lock_rw_unlock(&zones->lock); - return; - } - lock_rw_unlock(&z->lock); - } - lock_rw_unlock(&zones->lock); -} - -/** do the list_local_data command */ -static void -do_list_local_data(SSL* ssl, struct worker* worker, struct local_zones* zones) -{ - struct local_zone* z; - struct local_data* d; - struct local_rrset* p; - char* s = (char*)sldns_buffer_begin(worker->env.scratch_buffer); - size_t slen = sldns_buffer_capacity(worker->env.scratch_buffer); - lock_rw_rdlock(&zones->lock); - RBTREE_FOR(z, struct local_zone*, &zones->ztree) { - lock_rw_rdlock(&z->lock); - RBTREE_FOR(d, struct local_data*, &z->data) { - for(p = d->rrsets; p; p = p->next) { - struct packed_rrset_data* d = - (struct packed_rrset_data*)p->rrset->entry.data; - size_t i; - for(i=0; i<d->count + d->rrsig_count; i++) { - if(!packed_rr_to_string(p->rrset, i, - 0, s, slen)) { - if(!ssl_printf(ssl, "BADRR\n")) { - lock_rw_unlock(&z->lock); - lock_rw_unlock(&zones->lock); - return; - } - } - if(!ssl_printf(ssl, "%s\n", s)) { - lock_rw_unlock(&z->lock); - lock_rw_unlock(&zones->lock); - return; - } - } - } - } - lock_rw_unlock(&z->lock); - } - 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 */ - struct infra_cache* infra; - /** the SSL to print to */ - SSL* ssl; - /** all or only ratelimited */ - int all; - /** current time */ - 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) -{ - struct ratelimit_list_arg* a = (struct ratelimit_list_arg*)arg; - struct rate_key* k = (struct rate_key*)e->key; - struct rate_data* d = (struct rate_data*)e->data; - char buf[257]; - int lim = infra_find_ratelimit(a->infra, k->name, k->namelen); - int max = infra_rate_max(d, a->now); - if(a->all == 0) { - if(max < lim) - return; - } - dname_str(k->name, buf); - 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) -{ - struct 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->domain_rates==NULL || - (a.all == 0 && infra_dp_ratelimit == 0)) - return; - 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) -{ - int i; - if(!cmd || !ssl) - return; - /* skip i=0 which is me */ - for(i=1; i<rc->worker->daemon->num; i++) { - worker_send_cmd(rc->worker->daemon->workers[i], - worker_cmd_remote); - if(!tube_write_msg(rc->worker->daemon->workers[i]->cmd, - (uint8_t*)cmd, strlen(cmd)+1, 0)) { - ssl_printf(ssl, "error could not distribute cmd\n"); - return; - } - } -} - -/** check for name with end-of-string, space or tab after it */ -static int -cmdcmp(char* p, const char* cmd, size_t len) -{ - return strncmp(p,cmd,len)==0 && (p[len]==0||p[len]==' '||p[len]=='\t'); -} - -/** execute a remote control command */ -static void -execute_cmd(struct daemon_remote* rc, SSL* ssl, char* cmd, - struct worker* worker) -{ - char* p = skipwhite(cmd); - /* compare command */ - if(cmdcmp(p, "stop", 4)) { - do_stop(ssl, rc); - return; - } else if(cmdcmp(p, "reload", 6)) { - do_reload(ssl, rc); - return; - } else if(cmdcmp(p, "stats_noreset", 13)) { - do_stats(ssl, rc, 0); - return; - } else if(cmdcmp(p, "stats", 5)) { - do_stats(ssl, rc, 1); - return; - } else if(cmdcmp(p, "status", 6)) { - do_status(ssl, worker); - return; - } else if(cmdcmp(p, "dump_cache", 10)) { - (void)dump_cache(ssl, worker); - return; - } else if(cmdcmp(p, "load_cache", 10)) { - if(load_cache(ssl, worker)) send_ok(ssl); - return; - } else if(cmdcmp(p, "list_forwards", 13)) { - do_list_forwards(ssl, worker); - return; - } else if(cmdcmp(p, "list_stubs", 10)) { - do_list_stubs(ssl, worker); - return; - } else if(cmdcmp(p, "list_insecure", 13)) { - do_insecure_list(ssl, worker); - return; - } else if(cmdcmp(p, "list_local_zones", 16)) { - do_list_local_zones(ssl, worker->daemon->local_zones); - return; - } else if(cmdcmp(p, "list_local_data", 15)) { - 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); - do_stub_add(ssl, worker, skipwhite(p+8)); - return; - } else if(cmdcmp(p, "stub_remove", 11)) { - /* must always distribute this cmd */ - if(rc) distribute_cmd(rc, ssl, cmd); - do_stub_remove(ssl, worker, skipwhite(p+11)); - return; - } else if(cmdcmp(p, "forward_add", 11)) { - /* must always distribute this cmd */ - if(rc) distribute_cmd(rc, ssl, cmd); - do_forward_add(ssl, worker, skipwhite(p+11)); - return; - } else if(cmdcmp(p, "forward_remove", 14)) { - /* must always distribute this cmd */ - if(rc) distribute_cmd(rc, ssl, cmd); - do_forward_remove(ssl, worker, skipwhite(p+14)); - return; - } else if(cmdcmp(p, "insecure_add", 12)) { - /* must always distribute this cmd */ - if(rc) distribute_cmd(rc, ssl, cmd); - do_insecure_add(ssl, worker, skipwhite(p+12)); - return; - } else if(cmdcmp(p, "insecure_remove", 15)) { - /* must always distribute this cmd */ - if(rc) distribute_cmd(rc, ssl, cmd); - do_insecure_remove(ssl, worker, skipwhite(p+15)); - return; - } else if(cmdcmp(p, "forward", 7)) { - /* must always distribute this cmd */ - if(rc) distribute_cmd(rc, ssl, cmd); - do_forward(ssl, worker, skipwhite(p+7)); - return; - } else if(cmdcmp(p, "flush_stats", 11)) { - /* must always distribute this cmd */ - if(rc) distribute_cmd(rc, ssl, cmd); - do_flush_stats(ssl, worker); - return; - } else if(cmdcmp(p, "flush_requestlist", 17)) { - /* must always distribute this cmd */ - if(rc) distribute_cmd(rc, ssl, cmd); - do_flush_requestlist(ssl, worker); - return; - } else if(cmdcmp(p, "lookup", 6)) { - do_lookup(ssl, worker, skipwhite(p+6)); - return; - } - -#ifdef THREADS_DISABLED - /* other processes must execute the command as well */ - /* commands that should not be distributed, returned above. */ - if(rc) { /* only if this thread is the master (rc) thread */ - /* done before the code below, which may split the string */ - distribute_cmd(rc, ssl, cmd); - } -#endif - if(cmdcmp(p, "verbosity", 9)) { - do_verbosity(ssl, skipwhite(p+9)); - } else if(cmdcmp(p, "local_zone_remove", 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->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->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->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)) { - do_flush_type(ssl, worker, skipwhite(p+10)); - } else if(cmdcmp(p, "flush_infra", 11)) { - do_flush_infra(ssl, worker, skipwhite(p+11)); - } else if(cmdcmp(p, "flush", 5)) { - do_flush_name(ssl, worker, skipwhite(p+5)); - } else if(cmdcmp(p, "dump_requestlist", 16)) { - do_dump_requestlist(ssl, worker); - } else if(cmdcmp(p, "dump_infra", 10)) { - do_dump_infra(ssl, worker); - } else if(cmdcmp(p, "log_reopen", 10)) { - do_log_reopen(ssl, worker); - } else if(cmdcmp(p, "set_option", 10)) { - do_set_option(ssl, worker, skipwhite(p+10)); - } else if(cmdcmp(p, "get_option", 10)) { - do_get_option(ssl, worker, skipwhite(p+10)); - } else if(cmdcmp(p, "flush_bogus", 11)) { - do_flush_bogus(ssl, worker); - } else if(cmdcmp(p, "flush_negative", 14)) { - do_flush_negative(ssl, worker); - } else { - (void)ssl_printf(ssl, "error unknown command '%s'\n", p); - } -} - -void -daemon_remote_exec(struct worker* worker) -{ - /* read the cmd string */ - uint8_t* msg = NULL; - uint32_t len = 0; - if(!tube_read_msg(worker->cmd, &msg, &len, 0)) { - log_err("daemon_remote_exec: tube_read_msg failed"); - return; - } - verbose(VERB_ALGO, "remote exec distributed: %s", (char*)msg); - execute_cmd(NULL, NULL, (char*)msg, worker); - free(msg); -} - -/** handle remote control request */ -static void -handle_req(struct daemon_remote* rc, struct rc_state* s, SSL* ssl) -{ - int r; - char pre[10]; - char magic[7]; - char buf[1024]; -#ifdef USE_WINSOCK - /* makes it possible to set the socket blocking again. */ - /* basically removes it from winsock_event ... */ - WSAEventSelect(s->c->fd, NULL, 0); -#endif - fd_set_block(s->c->fd); - - /* try to read magic UBCT[version]_space_ string */ - ERR_clear_error(); - if((r=SSL_read(ssl, magic, (int)sizeof(magic)-1)) <= 0) { - if(SSL_get_error(ssl, r) == SSL_ERROR_ZERO_RETURN) - return; - log_crypto_err("could not SSL_read"); - return; - } - magic[6] = 0; - if( r != 6 || strncmp(magic, "UBCT", 4) != 0) { - verbose(VERB_QUERY, "control connection has bad magic string"); - /* probably wrong tool connected, ignore it completely */ - return; - } - - /* read the command line */ - if(!ssl_read_line(ssl, buf, sizeof(buf))) { - return; - } - snprintf(pre, sizeof(pre), "UBCT%d ", UNBOUND_CONTROL_VERSION); - if(strcmp(magic, pre) != 0) { - verbose(VERB_QUERY, "control connection had bad " - "version %s, cmd: %s", magic, buf); - ssl_printf(ssl, "error version mismatch\n"); - return; - } - verbose(VERB_DETAIL, "control cmd: %s", buf); - - /* figure out what to do */ - execute_cmd(rc, ssl, buf, rc->worker); -} - -int remote_control_callback(struct comm_point* c, void* arg, int err, - struct comm_reply* ATTR_UNUSED(rep)) -{ - struct rc_state* s = (struct rc_state*)arg; - struct daemon_remote* rc = s->rc; - int r; - if(err != NETEVENT_NOERROR) { - if(err==NETEVENT_TIMEOUT) - log_err("remote control timed out"); - clean_point(rc, s); - return 0; - } - /* (continue to) setup the SSL connection */ - ERR_clear_error(); - r = SSL_do_handshake(s->ssl); - if(r != 1) { - int r2 = SSL_get_error(s->ssl, r); - if(r2 == SSL_ERROR_WANT_READ) { - if(s->shake_state == rc_hs_read) { - /* try again later */ - return 0; - } - s->shake_state = rc_hs_read; - comm_point_listen_for_rw(c, 1, 0); - return 0; - } else if(r2 == SSL_ERROR_WANT_WRITE) { - if(s->shake_state == rc_hs_write) { - /* try again later */ - return 0; - } - s->shake_state = rc_hs_write; - comm_point_listen_for_rw(c, 0, 1); - return 0; - } else { - if(r == 0) - log_err("remote control connection closed prematurely"); - log_addr(1, "failed connection from", - &s->c->repinfo.addr, s->c->repinfo.addrlen); - log_crypto_err("remote control failed ssl"); - clean_point(rc, s); - return 0; - } - } - s->shake_state = rc_none; - - /* once handshake has completed, check authentication */ - if (!rc->use_cert) { - verbose(VERB_ALGO, "unauthenticated remote control connection"); - } else if(SSL_get_verify_result(s->ssl) == X509_V_OK) { - X509* x = SSL_get_peer_certificate(s->ssl); - if(!x) { - verbose(VERB_DETAIL, "remote control connection " - "provided no client certificate"); - clean_point(rc, s); - return 0; - } - verbose(VERB_ALGO, "remote control connection authenticated"); - X509_free(x); - } else { - verbose(VERB_DETAIL, "remote control connection failed to " - "authenticate with client certificate"); - clean_point(rc, s); - return 0; - } - - /* if OK start to actually handle the request */ - handle_req(rc, s, s->ssl); - - verbose(VERB_ALGO, "remote control operation completed"); - clean_point(rc, s); - return 0; -} diff --git a/external/unbound/daemon/remote.h b/external/unbound/daemon/remote.h deleted file mode 100644 index 190286d47..000000000 --- a/external/unbound/daemon/remote.h +++ /dev/null @@ -1,191 +0,0 @@ -/* - * daemon/remote.h - remote control for the unbound daemon. - * - * Copyright (c) 2008, NLnet Labs. All rights reserved. - * - * This software is open source. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * Neither the name of the NLNET LABS nor the names of its contributors may - * be used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED - * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/** - * \file - * - * This file contains the remote control functionality for the daemon. - * The remote control can be performed using either the commandline - * unbound-control tool, or a SSLv3/TLS capable web browser. - * The channel is secured using SSLv3 or TLSv1, and certificates. - * Both the server and the client(control tool) have their own keys. - */ - -#ifndef DAEMON_REMOTE_H -#define DAEMON_REMOTE_H -#ifdef HAVE_OPENSSL_SSL_H -#include "openssl/ssl.h" -#endif -struct config_file; -struct listen_list; -struct listen_port; -struct worker; -struct comm_reply; -struct comm_point; -struct daemon_remote; - -/** number of milliseconds timeout on incoming remote control handshake */ -#define REMOTE_CONTROL_TCP_TIMEOUT 120000 - -/** - * a busy control command connection, SSL state - */ -struct rc_state { - /** the next item in list */ - struct rc_state* next; - /** the commpoint */ - struct comm_point* c; - /** in the handshake part */ - enum { rc_none, rc_hs_read, rc_hs_write } shake_state; -#ifdef HAVE_SSL - /** the ssl state */ - SSL* ssl; -#endif - /** the rc this is part of */ - struct daemon_remote* rc; -}; - -/** - * The remote control tool state. - * The state is only created for the first thread, other threads - * are called from this thread. Only the first threads listens to - * the control port. The other threads do not, but are called on the - * command channel(pipe) from the first thread. - */ -struct daemon_remote { - /** the worker for this remote control */ - struct worker* worker; - /** commpoints for accepting remote control connections */ - struct listen_list* accept_list; - /* if certificates are used */ - int use_cert; - /** number of active commpoints that are handling remote control */ - int active; - /** max active commpoints */ - int max_active; - /** current commpoints busy; should be a short list, malloced */ - struct rc_state* busy_list; -#ifdef HAVE_SSL - /** the SSL context for creating new SSL streams */ - SSL_CTX* ctx; -#endif -}; - -/** - * Create new remote control state for the daemon. - * @param cfg: config file with key file settings. - * @return new state, or NULL on failure. - */ -struct daemon_remote* daemon_remote_create(struct config_file* cfg); - -/** - * remote control state to delete. - * @param rc: state to delete. - */ -void daemon_remote_delete(struct daemon_remote* rc); - -/** - * remote control state to clear up. Busy and accept points are closed. - * Does not delete the rc itself, or the ssl context (with its keys). - * @param rc: state to clear. - */ -void daemon_remote_clear(struct daemon_remote* rc); - -/** - * Open and create listening ports for remote control. - * @param cfg: config options. - * @return list of ports or NULL on failure. - * can be freed with listening_ports_free(). - */ -struct listen_port* daemon_remote_open_ports(struct config_file* cfg); - -/** - * Setup comm points for accepting remote control connections. - * @param rc: state - * @param ports: already opened ports. - * @param worker: worker with communication base. and links to command channels. - * @return false on error. - */ -int daemon_remote_open_accept(struct daemon_remote* rc, - struct listen_port* ports, struct worker* worker); - -/** - * Stop accept handlers for TCP (until enabled again) - * @param rc: state - */ -void daemon_remote_stop_accept(struct daemon_remote* rc); - -/** - * Stop accept handlers for TCP (until enabled again) - * @param rc: state - */ -void daemon_remote_start_accept(struct daemon_remote* rc); - -/** - * Handle nonthreaded remote cmd execution. - * @param worker: this worker (the remote worker). - */ -void daemon_remote_exec(struct worker* worker); - -#ifdef HAVE_SSL -/** - * Print fixed line of text over ssl connection in blocking mode - * @param ssl: print to - * @param text: the text. - * @return false on connection failure. - */ -int ssl_print_text(SSL* ssl, const char* text); - -/** - * printf style printing to the ssl connection - * @param ssl: the SSL connection to print to. Blocking. - * @param format: printf style format string. - * @return success or false on a network failure. - */ -int ssl_printf(SSL* ssl, const char* format, ...) - ATTR_FORMAT(printf, 2, 3); - -/** - * Read until \n is encountered - * If SSL signals EOF, the string up to then is returned (without \n). - * @param ssl: the SSL connection to read from. blocking. - * @param buf: buffer to read to. - * @param max: size of buffer. - * @return false on connection failure. - */ -int ssl_read_line(SSL* ssl, char* buf, size_t max); -#endif /* HAVE_SSL */ - -#endif /* DAEMON_REMOTE_H */ diff --git a/external/unbound/daemon/stats.c b/external/unbound/daemon/stats.c deleted file mode 100644 index 3665616be..000000000 --- a/external/unbound/daemon/stats.c +++ /dev/null @@ -1,343 +0,0 @@ -/* - * daemon/stats.c - collect runtime performance indicators. - * - * Copyright (c) 2007, NLnet Labs. All rights reserved. - * - * This software is open source. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * Neither the name of the NLNET LABS nor the names of its contributors may - * be used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED - * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/** - * \file - * - * This file describes the data structure used to collect runtime performance - * numbers. These 'statistics' may be of interest to the operator. - */ -#include "config.h" -#ifdef HAVE_TIME_H -#include <time.h> -#endif -#include <sys/time.h> -#include <sys/types.h> -#include "daemon/stats.h" -#include "daemon/worker.h" -#include "daemon/daemon.h" -#include "services/mesh.h" -#include "services/outside_network.h" -#include "services/listen_dnsport.h" -#include "util/config_file.h" -#include "util/tube.h" -#include "util/timehist.h" -#include "util/net_help.h" -#include "validator/validator.h" -#include "sldns/sbuffer.h" -#include "services/cache/rrset.h" -#include "services/cache/infra.h" -#include "validator/val_kcache.h" - -/** add timers and the values do not overflow or become negative */ -static void -timeval_add(struct timeval* d, const struct timeval* add) -{ -#ifndef S_SPLINT_S - d->tv_sec += add->tv_sec; - d->tv_usec += add->tv_usec; - if(d->tv_usec > 1000000) { - d->tv_usec -= 1000000; - d->tv_sec++; - } -#endif -} - -void server_stats_init(struct server_stats* stats, struct config_file* cfg) -{ - memset(stats, 0, sizeof(*stats)); - stats->extended = cfg->stat_extended; -} - -void server_stats_querymiss(struct server_stats* stats, struct worker* worker) -{ - stats->num_queries_missed_cache++; - stats->sum_query_list_size += worker->env.mesh->all.count; - if(worker->env.mesh->all.count > stats->max_query_list_size) - stats->max_query_list_size = worker->env.mesh->all.count; -} - -void server_stats_prefetch(struct server_stats* stats, struct worker* worker) -{ - stats->num_queries_prefetch++; - /* changes the query list size so account that, like a querymiss */ - stats->sum_query_list_size += worker->env.mesh->all.count; - if(worker->env.mesh->all.count > stats->max_query_list_size) - stats->max_query_list_size = worker->env.mesh->all.count; -} - -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 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_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, - (stats->num_queries_missed_cache+stats->num_queries_prefetch)? - (double)stats->sum_query_list_size/ - (stats->num_queries_missed_cache+ - stats->num_queries_prefetch) : 0.0, - (unsigned)worker->env.mesh->stats_dropped, - (unsigned)worker->env.mesh->stats_jostled); -} - -/** get rrsets bogus number from validator */ -static size_t -get_rrset_bogus(struct worker* worker) -{ - int m = modstack_find(&worker->env.mesh->mods, "validator"); - struct val_env* ve; - size_t r; - if(m == -1) - return 0; - ve = (struct val_env*)worker->env.modinfo[m]; - lock_basic_lock(&ve->bogus_lock); - r = ve->num_rrset_bogus; - if(!worker->env.cfg->stat_cumulative) - ve->num_rrset_bogus = 0; - lock_basic_unlock(&ve->bogus_lock); - return r; -} - -void -server_stats_compile(struct worker* worker, struct stats_info* s, int reset) -{ - int i; - struct listen_list* lp; - - s->svr = worker->stats; - s->mesh_num_states = worker->env.mesh->all.count; - s->mesh_num_reply_states = worker->env.mesh->num_reply_states; - s->mesh_jostled = worker->env.mesh->stats_jostled; - s->mesh_dropped = worker->env.mesh->stats_dropped; - s->mesh_replies_sent = worker->env.mesh->replies_sent; - s->mesh_replies_sum_wait = worker->env.mesh->replies_sum_wait; - s->mesh_time_median = timehist_quartile(worker->env.mesh->histogram, - 0.50); - - /* add in the values from the mesh */ - s->svr.ans_secure += worker->env.mesh->ans_secure; - s->svr.ans_bogus += worker->env.mesh->ans_bogus; - s->svr.ans_rcode_nodata += worker->env.mesh->ans_nodata; - for(i=0; i<16; i++) - s->svr.ans_rcode[i] += worker->env.mesh->ans_rcode[i]; - timehist_export(worker->env.mesh->histogram, s->svr.hist, - NUM_BUCKETS_HIST); - /* values from outside network */ - s->svr.unwanted_replies = worker->back->unwanted_replies; - s->svr.qtcp_outgoing = worker->back->num_tcp_outgoing; - - /* get and reset validator rrset bogus number */ - s->svr.rrset_bogus = get_rrset_bogus(worker); - - /* get cache sizes */ - s->svr.msg_cache_count = count_slabhash_entries(worker->env.msg_cache); - s->svr.rrset_cache_count = count_slabhash_entries(&worker->env.rrset_cache->table); - s->svr.infra_cache_count = count_slabhash_entries(worker->env.infra_cache->hosts); - if(worker->env.key_cache) - s->svr.key_cache_count = count_slabhash_entries(worker->env.key_cache->slab); - else s->svr.key_cache_count = 0; - - /* get tcp accept usage */ - s->svr.tcp_accept_usage = 0; - for(lp = worker->front->cps; lp; lp = lp->next) { - if(lp->com->type == comm_tcp_accept) - s->svr.tcp_accept_usage += lp->com->cur_tcp_count; - } - - if(reset && !worker->env.cfg->stat_cumulative) { - worker_stats_clear(worker); - } -} - -void server_stats_obtain(struct worker* worker, struct worker* who, - struct stats_info* s, int reset) -{ - uint8_t *reply = NULL; - uint32_t len = 0; - if(worker == who) { - /* just fill it in */ - server_stats_compile(worker, s, reset); - return; - } - /* communicate over tube */ - verbose(VERB_ALGO, "write stats cmd"); - if(reset) - worker_send_cmd(who, worker_cmd_stats); - else worker_send_cmd(who, worker_cmd_stats_noreset); - verbose(VERB_ALGO, "wait for stats reply"); - if(!tube_read_msg(worker->cmd, &reply, &len, 0)) - fatal_exit("failed to read stats over cmd channel"); - if(len != (uint32_t)sizeof(*s)) - fatal_exit("stats on cmd channel wrong length %d %d", - (int)len, (int)sizeof(*s)); - memcpy(s, reply, (size_t)len); - free(reply); -} - -void server_stats_reply(struct worker* worker, int reset) -{ - struct stats_info s; - server_stats_compile(worker, &s, reset); - verbose(VERB_ALGO, "write stats replymsg"); - if(!tube_write_msg(worker->daemon->workers[0]->cmd, - (uint8_t*)&s, sizeof(s), 0)) - fatal_exit("could not write stat values over cmd channel"); -} - -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; - - if(a->svr.extended) { - int i; - total->svr.qtype_big += a->svr.qtype_big; - total->svr.qclass_big += a->svr.qclass_big; - total->svr.qtcp += a->svr.qtcp; - total->svr.qtcp_outgoing += a->svr.qtcp_outgoing; - total->svr.qipv6 += a->svr.qipv6; - total->svr.qbit_QR += a->svr.qbit_QR; - total->svr.qbit_AA += a->svr.qbit_AA; - total->svr.qbit_TC += a->svr.qbit_TC; - total->svr.qbit_RD += a->svr.qbit_RD; - total->svr.qbit_RA += a->svr.qbit_RA; - total->svr.qbit_Z += a->svr.qbit_Z; - total->svr.qbit_AD += a->svr.qbit_AD; - total->svr.qbit_CD += a->svr.qbit_CD; - 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; - total->svr.unwanted_replies += a->svr.unwanted_replies; - total->svr.unwanted_queries += a->svr.unwanted_queries; - total->svr.tcp_accept_usage += a->svr.tcp_accept_usage; - for(i=0; i<STATS_QTYPE_NUM; i++) - total->svr.qtype[i] += a->svr.qtype[i]; - for(i=0; i<STATS_QCLASS_NUM; i++) - total->svr.qclass[i] += a->svr.qclass[i]; - for(i=0; i<STATS_OPCODE_NUM; i++) - total->svr.qopcode[i] += a->svr.qopcode[i]; - for(i=0; i<STATS_RCODE_NUM; i++) - total->svr.ans_rcode[i] += a->svr.ans_rcode[i]; - for(i=0; i<NUM_BUCKETS_HIST; i++) - total->svr.hist[i] += a->svr.hist[i]; - } - - total->mesh_num_states += a->mesh_num_states; - total->mesh_num_reply_states += a->mesh_num_reply_states; - total->mesh_jostled += a->mesh_jostled; - total->mesh_dropped += a->mesh_dropped; - total->mesh_replies_sent += a->mesh_replies_sent; - timeval_add(&total->mesh_replies_sum_wait, &a->mesh_replies_sum_wait); - /* the medians are averaged together, this is not as accurate as - * taking the median over all of the data, but is good and fast - * added up here, division later*/ - total->mesh_time_median += a->mesh_time_median; -} - -void server_stats_insquery(struct server_stats* stats, struct comm_point* c, - uint16_t qtype, uint16_t qclass, struct edns_data* edns, - struct comm_reply* repinfo) -{ - uint16_t flags = sldns_buffer_read_u16_at(c->buffer, 2); - if(qtype < STATS_QTYPE_NUM) - stats->qtype[qtype]++; - else stats->qtype_big++; - if(qclass < STATS_QCLASS_NUM) - stats->qclass[qclass]++; - else stats->qclass_big++; - stats->qopcode[ LDNS_OPCODE_WIRE(sldns_buffer_begin(c->buffer)) ]++; - if(c->type != comm_udp) - stats->qtcp++; - if(repinfo && addr_is_ip6(&repinfo->addr, repinfo->addrlen)) - stats->qipv6++; - if( (flags&BIT_QR) ) - stats->qbit_QR++; - if( (flags&BIT_AA) ) - stats->qbit_AA++; - if( (flags&BIT_TC) ) - stats->qbit_TC++; - if( (flags&BIT_RD) ) - stats->qbit_RD++; - if( (flags&BIT_RA) ) - stats->qbit_RA++; - if( (flags&BIT_Z) ) - stats->qbit_Z++; - if( (flags&BIT_AD) ) - stats->qbit_AD++; - if( (flags&BIT_CD) ) - stats->qbit_CD++; - if(edns->edns_present) { - stats->qEDNS++; - if( (edns->bits & EDNS_DO) ) - stats->qEDNS_DO++; - } -} - -void server_stats_insrcode(struct server_stats* stats, sldns_buffer* buf) -{ - if(stats->extended && sldns_buffer_limit(buf) != 0) { - int r = (int)LDNS_RCODE_WIRE( sldns_buffer_begin(buf) ); - stats->ans_rcode[r] ++; - if(r == 0 && LDNS_ANCOUNT( sldns_buffer_begin(buf) ) == 0) - stats->ans_rcode_nodata ++; - } -} diff --git a/external/unbound/daemon/stats.h b/external/unbound/daemon/stats.h deleted file mode 100644 index 39c4d21c5..000000000 --- a/external/unbound/daemon/stats.h +++ /dev/null @@ -1,262 +0,0 @@ -/* - * daemon/stats.h - collect runtime performance indicators. - * - * Copyright (c) 2007, NLnet Labs. All rights reserved. - * - * This software is open source. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * Neither the name of the NLNET LABS nor the names of its contributors may - * be used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED - * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/** - * \file - * - * This file describes the data structure used to collect runtime performance - * numbers. These 'statistics' may be of interest to the operator. - */ - -#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; -struct comm_reply; -struct edns_data; -struct sldns_buffer; - -/** number of qtype that is stored for in array */ -#define STATS_QTYPE_NUM 256 -/** number of qclass that is stored for in array */ -#define STATS_QCLASS_NUM 256 -/** number of rcodes in stats */ -#define STATS_RCODE_NUM 16 -/** number of opcodes in stats */ -#define STATS_OPCODE_NUM 16 - -/** per worker statistics */ -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 */ - size_t num_queries_prefetch; - - /** - * Sum of the querylistsize of the worker for - * every query that missed cache. To calculate average. - */ - size_t sum_query_list_size; - /** max value of query list size reached. */ - size_t max_query_list_size; - - /** Extended stats below (bool) */ - int extended; - - /** qtype stats */ - size_t qtype[STATS_QTYPE_NUM]; - /** bigger qtype values not in array */ - size_t qtype_big; - /** qclass stats */ - size_t qclass[STATS_QCLASS_NUM]; - /** bigger qclass values not in array */ - size_t qclass_big; - /** query opcodes */ - size_t qopcode[STATS_OPCODE_NUM]; - /** number of queries over TCP */ - size_t qtcp; - /** number of outgoing queries over TCP */ - size_t qtcp_outgoing; - /** number of queries over IPv6 */ - size_t qipv6; - /** number of queries with QR bit */ - size_t qbit_QR; - /** number of queries with AA bit */ - size_t qbit_AA; - /** number of queries with TC bit */ - size_t qbit_TC; - /** number of queries with RD bit */ - size_t qbit_RD; - /** number of queries with RA bit */ - size_t qbit_RA; - /** number of queries with Z bit */ - size_t qbit_Z; - /** number of queries with AD bit */ - size_t qbit_AD; - /** number of queries with CD bit */ - size_t qbit_CD; - /** number of queries with EDNS OPT record */ - size_t qEDNS; - /** number of queries with EDNS with DO flag */ - size_t qEDNS_DO; - /** answer rcodes */ - size_t ans_rcode[STATS_RCODE_NUM]; - /** answers with pseudo rcode 'nodata' */ - size_t ans_rcode_nodata; - /** answers that were secure (AD) */ - size_t ans_secure; - /** answers that were bogus (withheld as SERVFAIL) */ - size_t ans_bogus; - /** rrsets marked bogus by validator */ - size_t rrset_bogus; - /** unwanted traffic received on server-facing ports */ - size_t unwanted_replies; - /** unwanted traffic received on client-facing ports */ - 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 - * adding up works well. */ - size_t hist[NUM_BUCKETS_HIST]; - - /** number of message cache entries */ - size_t msg_cache_count; - /** number of rrset cache entries */ - size_t rrset_cache_count; - /** number of infra cache entries */ - 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 -}; - -/** - * Statistics to send over the control pipe when asked - * This struct is made to be memcpied, sent in binary. - */ -struct stats_info { - /** the thread stats */ - struct server_stats svr; - - /** mesh stats: current number of states */ - size_t mesh_num_states; - /** mesh stats: current number of reply (user) states */ - size_t mesh_num_reply_states; - /** mesh stats: number of reply states overwritten with a new one */ - size_t mesh_jostled; - /** mesh stats: number of incoming queries dropped */ - size_t mesh_dropped; - /** mesh stats: replies sent */ - size_t mesh_replies_sent; - /** mesh stats: sum of waiting times for the replies */ - struct timeval mesh_replies_sum_wait; - /** mesh stats: median of waiting times for replies (in sec) */ - double mesh_time_median; -}; - -/** - * Initialize server stats to 0. - * @param stats: what to init (this is alloced by the caller). - * @param cfg: with extended statistics option. - */ -void server_stats_init(struct server_stats* stats, struct config_file* cfg); - -/** add query if it missed the cache */ -void server_stats_querymiss(struct server_stats* stats, struct worker* worker); - -/** add query if was cached and also resulted in a prefetch */ -void server_stats_prefetch(struct server_stats* stats, struct worker* worker); - -/** display the stats to the log */ -void server_stats_log(struct server_stats* stats, struct worker* worker, - int threadnum); - -/** - * Obtain the stats info for a given thread. Uses pipe to communicate. - * @param worker: the worker that is executing (the first worker). - * @param who: on who to get the statistics info. - * @param s: the stats block to fill in. - * @param reset: if stats can be reset. - */ -void server_stats_obtain(struct worker* worker, struct worker* who, - struct stats_info* s, int reset); - -/** - * Compile stats into structure for this thread worker. - * Also clears the statistics counters (if that is set by config file). - * @param worker: the worker to compile stats for, also the executing worker. - * @param s: stats block. - * @param reset: if true, depending on config stats are reset. - * if false, statistics are not reset. - */ -void server_stats_compile(struct worker* worker, struct stats_info* s, - int reset); - -/** - * Send stats over comm tube in reply to query cmd - * @param worker: this worker. - * @param reset: if true, depending on config stats are reset. - * if false, statistics are not reset. - */ -void server_stats_reply(struct worker* worker, int reset); - -/** - * Addup stat blocks. - * @param total: sum of the two entries. - * @param a: to add to it. - */ -void server_stats_add(struct stats_info* total, struct stats_info* a); - -/** - * Add stats for this query - * @param stats: the stats - * @param c: commpoint with type and buffer. - * @param qtype: query type - * @param qclass: query class - * @param edns: edns record - * @param repinfo: reply info with remote address - */ -void server_stats_insquery(struct server_stats* stats, struct comm_point* c, - uint16_t qtype, uint16_t qclass, struct edns_data* edns, - struct comm_reply* repinfo); - -/** - * Add rcode for this query. - * @param stats: the stats - * @param buf: buffer with rcode. If buffer is length0: not counted. - */ -void server_stats_insrcode(struct server_stats* stats, struct sldns_buffer* buf); - -#endif /* DAEMON_STATS_H */ diff --git a/external/unbound/daemon/unbound.c b/external/unbound/daemon/unbound.c deleted file mode 100644 index ba7337d89..000000000 --- a/external/unbound/daemon/unbound.c +++ /dev/null @@ -1,738 +0,0 @@ -/* - * daemon/unbound.c - main program for unbound DNS resolver daemon. - * - * Copyright (c) 2007, NLnet Labs. All rights reserved. - * - * This software is open source. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * Neither the name of the NLNET LABS nor the names of its contributors may - * be used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED - * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - */ - -/** - * \file - * - * Main program to start the DNS resolver daemon. - */ - -#include "config.h" -#ifdef HAVE_GETOPT_H -#include <getopt.h> -#endif -#include <sys/time.h> -#include "util/log.h" -#include "daemon/daemon.h" -#include "daemon/remote.h" -#include "util/config_file.h" -#include "util/storage/slabhash.h" -#include "services/listen_dnsport.h" -#include "services/cache/rrset.h" -#include "services/cache/infra.h" -#include "util/fptr_wlist.h" -#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> -#ifdef HAVE_PWD_H -#include <pwd.h> -#endif -#ifdef HAVE_GRP_H -#include <grp.h> -#endif - -#ifndef S_SPLINT_S -/* splint chokes on this system header file */ -#ifdef HAVE_SYS_RESOURCE_H -#include <sys/resource.h> -#endif -#endif /* S_SPLINT_S */ -#ifdef HAVE_LOGIN_CAP_H -#include <login_cap.h> -#endif - -#ifdef UB_ON_WINDOWS -# include "winrc/win_svc.h" -#endif - -#ifdef HAVE_NSS -/* nss3 */ -# include "nss.h" -#endif - -/** print 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"); - printf("-c file config file to read instead of %s\n", CONFIGFILE); - printf(" file format is described in unbound.conf(5).\n"); - printf("-d do not fork into the background.\n"); - printf("-v verbose (more times to increase verbosity)\n"); -#ifdef UB_ON_WINDOWS - printf("-w opt windows option: \n"); - printf(" install, remove - manage the services entry\n"); - printf(" service - used to start from services control panel\n"); -#endif - printf("Version %s\n", PACKAGE_VERSION); - 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) - "nettle" -#endif - ); - printf("linked modules:"); - for(m = module_list_avail(); *m; m++) - printf(" %s", *m); - 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 -int replay_var_compare(const void* ATTR_UNUSED(a), const void* ATTR_UNUSED(b)) -{ - log_assert(0); - return 0; -} -#endif - -/** check file descriptor count */ -static void -checkrlimits(struct config_file* cfg) -{ -#ifndef S_SPLINT_S -#ifdef HAVE_GETRLIMIT - /* list has number of ports to listen to, ifs number addresses */ - int list = ((cfg->do_udp?1:0) + (cfg->do_tcp?1 + - (int)cfg->incoming_num_tcp:0)); - size_t listen_ifs = (size_t)(cfg->num_ifs==0? - ((cfg->do_ip4 && !cfg->if_automatic?1:0) + - (cfg->do_ip6?1:0)):cfg->num_ifs); - size_t listen_num = list*listen_ifs; - size_t outudpnum = (size_t)cfg->outgoing_num_ports; - size_t outtcpnum = cfg->outgoing_num_tcp; - size_t misc = 4; /* logfile, pidfile, stdout... */ - size_t perthread_noudp = listen_num + outtcpnum + - 2/*cmdpipe*/ + 2/*libevent*/ + misc; - size_t perthread = perthread_noudp + outudpnum; - -#if !defined(HAVE_PTHREAD) && !defined(HAVE_SOLARIS_THREADS) - int numthread = 1; /* it forks */ -#else - int numthread = (cfg->num_threads?cfg->num_threads:1); -#endif - size_t total = numthread * perthread + misc; - size_t avail; - struct rlimit rlim; - - if(total > 1024 && - 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"); - if(numthread*perthread_noudp+15 > 1024) - fatal_exit("too much tcp. not enough fds."); - cfg->outgoing_num_ports = (int)((1024 - - numthread*perthread_noudp - - 10 /* safety margin */) /numthread); - log_warn("continuing with less udp ports: %u", - cfg->outgoing_num_ports); - total = 1024; - } - if(perthread > 64 && - 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"); - if(perthread_noudp+2 > 64) - fatal_exit("too much tcp. not enough fds."); - cfg->outgoing_num_ports = (int)((64 - - perthread_noudp - - 2/* safety margin */)); - log_warn("continuing with less udp ports: %u", - cfg->outgoing_num_ports); - total = numthread*(perthread_noudp+ - (size_t)cfg->outgoing_num_ports)+misc; - } - if(getrlimit(RLIMIT_NOFILE, &rlim) < 0) { - log_warn("getrlimit: %s", strerror(errno)); - return; - } - if(rlim.rlim_cur == (rlim_t)RLIM_INFINITY) - return; - if((size_t)rlim.rlim_cur < total) { - avail = (size_t)rlim.rlim_cur; - rlim.rlim_cur = (rlim_t)(total + 10); - rlim.rlim_max = (rlim_t)(total + 10); -#ifdef HAVE_SETRLIMIT - if(setrlimit(RLIMIT_NOFILE, &rlim) < 0) { - log_warn("setrlimit: %s", strerror(errno)); -#endif - log_warn("cannot increase max open fds from %u to %u", - (unsigned)avail, (unsigned)total+10); - /* check that calculation below does not underflow, - * with 15 as margin */ - if(numthread*perthread_noudp+15 > avail) - fatal_exit("too much tcp. not enough fds."); - cfg->outgoing_num_ports = (int)((avail - - numthread*perthread_noudp - - 10 /* safety margin */) /numthread); - log_warn("continuing with less udp ports: %u", - cfg->outgoing_num_ports); - log_warn("increase ulimit or decrease threads, " - "ports in config to remove this warning"); - return; -#ifdef HAVE_SETRLIMIT - } -#endif - verbose(VERB_ALGO, "increased limit(open files) from %u to %u", - (unsigned)avail, (unsigned)total+10); - } -#else - (void)cfg; -#endif /* HAVE_GETRLIMIT */ -#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, 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 -/** Read existing pid from pidfile. - * @param file: file name of pid file. - * @return: the pid from the file or -1 if none. - */ -static pid_t -readpid (const char* file) -{ - int fd; - pid_t pid; - char pidbuf[32]; - char* t; - ssize_t l; - - if ((fd = open(file, O_RDONLY)) == -1) { - if(errno != ENOENT) - log_err("Could not read pidfile %s: %s", - file, strerror(errno)); - return -1; - } - - if (((l = read(fd, pidbuf, sizeof(pidbuf)))) == -1) { - if(errno != ENOENT) - log_err("Could not read pidfile %s: %s", - file, strerror(errno)); - close(fd); - return -1; - } - - close(fd); - - /* Empty pidfile means no pidfile... */ - if (l == 0) { - return -1; - } - - pidbuf[sizeof(pidbuf)-1] = 0; - pid = (pid_t)strtol(pidbuf, &t, 10); - - if (*t && *t != '\n') { - return -1; - } - return pid; -} - -/** write pid to file. - * @param pidfile: file name of pid file. - * @param pid: pid to write to file. - */ -static void -writepid (const char* pidfile, pid_t pid) -{ - FILE* f; - - if ((f = fopen(pidfile, "w")) == NULL ) { - log_err("cannot open pidfile %s: %s", - pidfile, strerror(errno)); - return; - } - if(fprintf(f, "%lu\n", (unsigned long)pid) < 0) { - log_err("cannot write to pidfile %s: %s", - pidfile, strerror(errno)); - } - fclose(f); -} - -/** - * check old pid file. - * @param pidfile: the file name of the pid file. - * @param inchroot: if pidfile is inchroot and we can thus expect to - * be able to delete it. - */ -static void -checkoldpid(char* pidfile, int inchroot) -{ - pid_t old; - if((old = readpid(pidfile)) != -1) { - /* see if it is still alive */ - if(kill(old, 0) == 0 || errno == EPERM) - log_warn("unbound is already running as pid %u.", - (unsigned)old); - else if(inchroot) - log_warn("did not exit gracefully last time (%u)", - (unsigned)old); - } -} -#endif /* HAVE_KILL */ - -/** detach from command line */ -static void -detach(void) -{ -#if defined(HAVE_DAEMON) && !defined(DEPRECATED_DAEMON) - /* use POSIX daemon(3) function */ - if(daemon(1, 0) != 0) - fatal_exit("daemon failed: %s", strerror(errno)); -#else /* no HAVE_DAEMON */ -#ifdef HAVE_FORK - int fd; - /* Take off... */ - switch (fork()) { - case 0: - break; - case -1: - fatal_exit("fork failed: %s", strerror(errno)); - default: - /* exit interactive session */ - exit(0); - } - /* detach */ -#ifdef HAVE_SETSID - if(setsid() == -1) - fatal_exit("setsid() failed: %s", strerror(errno)); -#endif - if ((fd = open("/dev/null", O_RDWR, 0)) != -1) { - (void)dup2(fd, STDIN_FILENO); - (void)dup2(fd, STDOUT_FILENO); - (void)dup2(fd, STDERR_FILENO); - if (fd > 2) - (void)close(fd); - } -#endif /* HAVE_FORK */ -#endif /* HAVE_DAEMON */ -} - -/** daemonize, drop user priviliges and chroot if needed */ -static void -perform_setup(struct daemon* daemon, struct config_file* cfg, int debug_mode, - const char** cfgfile) -{ -#ifdef HAVE_KILL - int pidinchroot; -#endif -#ifdef HAVE_GETPWNAM - struct passwd *pwd = NULL; - - if(cfg->username && cfg->username[0]) { - if((pwd = getpwnam(cfg->username)) == NULL) - fatal_exit("user '%s' does not exist.", cfg->username); - /* endpwent below, in case we need pwd for setusercontext */ - } -#endif -#ifdef UB_ON_WINDOWS - w_config_adjust_directory(cfg); -#endif - - /* init syslog (as root) if needed, before daemonize, otherwise - * a fork error could not be printed since daemonize closed stderr.*/ - if(cfg->use_syslog) { - log_init(cfg->logfile, cfg->use_syslog, cfg->chrootdir); - } - /* if using a logfile, we cannot open it because the logfile would - * be created with the wrong permissions, we cannot chown it because - * we cannot chown system logfiles, so we do not open at all. - * So, using a logfile, the user does not see errors unless -d is - * given to unbound on the commandline. */ - - /* read ssl keys while superuser and outside chroot */ -#ifdef HAVE_SSL - if(!(daemon->rc = daemon_remote_create(cfg))) - fatal_exit("could not set up remote-control"); - if(cfg->ssl_service_key && cfg->ssl_service_key[0]) { - if(!(daemon->listen_sslctx = listen_sslctx_create( - cfg->ssl_service_key, cfg->ssl_service_pem, NULL))) - fatal_exit("could not set up listen SSL_CTX"); - } - if(!(daemon->connect_sslctx = connect_sslctx_create(NULL, NULL, NULL))) - fatal_exit("could not set up connect SSL_CTX"); -#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 */ - if(cfg->pidfile[0] == '/') - daemon->pidfile = strdup(cfg->pidfile); - else daemon->pidfile = fname_after_chroot(cfg->pidfile, - cfg, 1); - if(!daemon->pidfile) - fatal_exit("pidfile alloc: out of memory"); - checkoldpid(daemon->pidfile, pidinchroot); - } -#endif - - /* daemonize because pid is needed by the writepid func */ - if(!debug_mode && cfg->do_daemonize) { - detach(); - } - - /* write new pidfile (while still root, so can be outside chroot) */ -#ifdef HAVE_KILL - if(cfg->pidfile && cfg->pidfile[0]) { - writepid(daemon->pidfile, getpid()); - if(cfg->username && cfg->username[0] && cfg_uid != (uid_t)-1 && - pidinchroot) { -# ifdef HAVE_CHOWN - if(chown(daemon->pidfile, cfg_uid, cfg_gid) == -1) { - verbose(VERB_QUERY, "cannot chown %u.%u %s: %s", - (unsigned)cfg_uid, (unsigned)cfg_gid, - daemon->pidfile, strerror(errno)); - } -# endif /* HAVE_CHOWN */ - } - } -#else - (void)daemon; -#endif /* HAVE_KILL */ - - /* Set user context */ -#ifdef HAVE_GETPWNAM - if(cfg->username && cfg->username[0] && cfg_uid != (uid_t)-1) { -#ifdef HAVE_SETUSERCONTEXT - /* setusercontext does initgroups, setuid, setgid, and - * also resource limits from login config, but we - * still call setresuid, setresgid to be sure to set all uid*/ - if(setusercontext(NULL, pwd, cfg_uid, (unsigned) - LOGIN_SETALL & ~LOGIN_SETUSER & ~LOGIN_SETGROUP) != 0) - log_warn("unable to setusercontext %s: %s", - cfg->username, strerror(errno)); -#endif /* HAVE_SETUSERCONTEXT */ - } -#endif /* HAVE_GETPWNAM */ - - /* box into the chroot */ -#ifdef HAVE_CHROOT - if(cfg->chrootdir && cfg->chrootdir[0]) { - if(chdir(cfg->chrootdir)) { - fatal_exit("unable to chdir to chroot %s: %s", - cfg->chrootdir, strerror(errno)); - } - verbose(VERB_QUERY, "chdir to %s", cfg->chrootdir); - if(chroot(cfg->chrootdir)) - fatal_exit("unable to chroot to %s: %s", - cfg->chrootdir, strerror(errno)); - if(chdir("/")) - fatal_exit("unable to chdir to / in chroot %s: %s", - cfg->chrootdir, strerror(errno)); - verbose(VERB_QUERY, "chroot to %s", cfg->chrootdir); - if(strncmp(*cfgfile, cfg->chrootdir, - strlen(cfg->chrootdir)) == 0) - (*cfgfile) += strlen(cfg->chrootdir); - - /* adjust stored pidfile for chroot */ - if(daemon->pidfile && daemon->pidfile[0] && - strncmp(daemon->pidfile, cfg->chrootdir, - strlen(cfg->chrootdir))==0) { - char* old = daemon->pidfile; - daemon->pidfile = strdup(old+strlen(cfg->chrootdir)); - free(old); - if(!daemon->pidfile) - log_err("out of memory in pidfile adjust"); - } - daemon->chroot = strdup(cfg->chrootdir); - if(!daemon->chroot) - log_err("out of memory in daemon chroot dir storage"); - } -#else - (void)cfgfile; -#endif - /* change to working directory inside chroot */ - if(cfg->directory && cfg->directory[0]) { - char* dir = cfg->directory; - if(cfg->chrootdir && cfg->chrootdir[0] && - strncmp(dir, cfg->chrootdir, - strlen(cfg->chrootdir)) == 0) - dir += strlen(cfg->chrootdir); - if(dir[0]) { - if(chdir(dir)) { - fatal_exit("Could not chdir to %s: %s", - dir, strerror(errno)); - } - verbose(VERB_QUERY, "chdir to %s", dir); - } - } - - /* drop permissions after chroot, getpwnam, pidfile, syslog done*/ -#ifdef HAVE_GETPWNAM - if(cfg->username && cfg->username[0] && cfg_uid != (uid_t)-1) { -# ifdef HAVE_INITGROUPS - if(initgroups(cfg->username, cfg_gid) != 0) - 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) -#elif defined(HAVE_SETREGID) && !defined(DARWIN_BROKEN_SETREUID) - if(setregid(cfg_gid,cfg_gid) != 0) -#else /* use setgid */ - if(setgid(cfg_gid) != 0) -#endif /* HAVE_SETRESGID */ - fatal_exit("unable to set group id of %s: %s", - cfg->username, strerror(errno)); -#ifdef HAVE_SETRESUID - if(setresuid(cfg_uid,cfg_uid,cfg_uid) != 0) -#elif defined(HAVE_SETREUID) && !defined(DARWIN_BROKEN_SETREUID) - if(setreuid(cfg_uid,cfg_uid) != 0) -#else /* use setuid */ - if(setuid(cfg_uid) != 0) -#endif /* HAVE_SETRESUID */ - fatal_exit("unable to set user id of %s: %s", - cfg->username, strerror(errno)); - verbose(VERB_QUERY, "drop user privileges, run as %s", - cfg->username); - } -#endif /* HAVE_GETPWNAM */ - /* file logging inited after chroot,chdir,setuid is done so that - * it would succeed on SIGHUP as well */ - if(!cfg->use_syslog) - log_init(cfg->logfile, cfg->use_syslog, cfg->chrootdir); -} - -/** - * Run the daemon. - * @param cfgfile: the config file name. - * @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, const char* log_default_identity) -{ - struct config_file* cfg = NULL; - struct daemon* daemon = NULL; - int done_setup = 0; - - if(!(daemon = daemon_init())) - fatal_exit("alloc failure"); - while(!daemon->need_to_exit) { - if(done_setup) - verbose(VERB_OPS, "Restart of %s.", PACKAGE_STRING); - else verbose(VERB_OPS, "Start of %s.", PACKAGE_STRING); - - /* config stuff */ - if(!(cfg = config_create())) - fatal_exit("Could not alloc config defaults"); - if(!config_read(cfg, cfgfile, daemon->chroot)) { - if(errno != ENOENT) - fatal_exit("Could not read config file: %s", - cfgfile); - log_warn("Continuing with default config settings"); - } - apply_settings(daemon, cfg, cmdline_verbose, debug_mode, log_default_identity); - if(!done_setup) - config_lookup_uid(cfg); - - /* prepare */ - if(!daemon_open_shared_ports(daemon)) - fatal_exit("could not open ports"); - if(!done_setup) { - perform_setup(daemon, cfg, debug_mode, &cfgfile); - done_setup = 1; - } else { - /* reopen log after HUP to facilitate log rotation */ - if(!cfg->use_syslog) - log_init(cfg->logfile, 0, cfg->chrootdir); - } - /* work */ - daemon_fork(daemon); - - /* clean up for restart */ - verbose(VERB_ALGO, "cleanup."); - daemon_cleanup(daemon); - config_delete(cfg); - } - verbose(VERB_ALGO, "Exit cleanup."); - /* this unlink may not work if the pidfile is located outside - * of the chroot/workdir or we no longer have permissions */ - if(daemon->pidfile) { - int fd; - /* truncate pidfile */ - fd = open(daemon->pidfile, O_WRONLY | O_TRUNC, 0644); - if(fd != -1) - close(fd); - /* delete pidfile */ - unlink(daemon->pidfile); - } - daemon_delete(daemon); -} - -/** getopt global, in case header files fail to declare it. */ -extern int optind; -/** getopt global, in case header files fail to declare it. */ -extern char* optarg; - -/** - * main program. Set options given commandline arguments. - * @param argc: number of commandline arguments. - * @param argv: array of commandline arguments. - * @return: exit status of the program. - */ -int -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 - - log_init(NULL, 0, NULL); - 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) { - case 'c': - cfgfile = optarg; -#ifdef UB_ON_WINDOWS - cmdline_cfg = 1; -#endif - break; - case 'v': - cmdline_verbose++; - verbosity++; - break; - case 'd': - debug_mode++; - break; - case 'w': - winopt = optarg; - break; - case '?': - case 'h': - default: - usage(); - return 1; - } - } - argc -= optind; - argv += optind; - - if(winopt) { -#ifdef UB_ON_WINDOWS - wsvc_command_option(winopt, cfgfile, cmdline_verbose, - cmdline_cfg); -#else - fatal_exit("option not supported"); -#endif - } - - if(argc != 0) { - usage(); - return 1; - } - - 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 deleted file mode 100644 index b1cc974aa..000000000 --- a/external/unbound/daemon/worker.c +++ /dev/null @@ -1,1883 +0,0 @@ -/* - * daemon/worker.c - worker that handles a pending list of requests. - * - * Copyright (c) 2007, NLnet Labs. All rights reserved. - * - * This software is open source. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * Neither the name of the NLNET LABS nor the names of its contributors may - * be used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED - * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/** - * \file - * - * This file implements the worker that handles callbacks on events, for - * pending requests. - */ -#include "config.h" -#include "util/log.h" -#include "util/net_help.h" -#include "util/random.h" -#include "daemon/worker.h" -#include "daemon/daemon.h" -#include "daemon/remote.h" -#include "daemon/acl_list.h" -#include "util/netevent.h" -#include "util/config_file.h" -#include "util/module.h" -#include "util/regional.h" -#include "util/storage/slabhash.h" -#include "services/listen_dnsport.h" -#include "services/outside_network.h" -#include "services/outbound_list.h" -#include "services/cache/rrset.h" -#include "services/cache/infra.h" -#include "services/cache/dns.h" -#include "services/mesh.h" -#include "services/localzone.h" -#include "util/data/msgparse.h" -#include "util/data/msgencode.h" -#include "util/data/dname.h" -#include "util/fptr_wlist.h" -#include "util/tube.h" -#include "iterator/iter_fwd.h" -#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> -#endif -#ifdef HAVE_NETDB_H -#include <netdb.h> -#endif -#include <signal.h> -#ifdef UB_ON_WINDOWS -#include "winrc/win_svc.h" -#endif - -/** Size of an UDP datagram */ -#define NORMAL_UDP_SIZE 512 /* bytes */ -/** ratelimit for error responses */ -#define ERROR_RATELIMIT 100 /* qps */ - -/** - * seconds to add to prefetch leeway. This is a TTL that expires old rrsets - * earlier than they should in order to put the new update into the cache. - * This additional value is to make sure that if not all TTLs are equal in - * the message to be updated(and replaced), that rrsets with up to this much - * extra TTL are also replaced. This means that the resulting new message - * will have (most likely) this TTL at least, avoiding very small 'split - * second' TTLs due to operators choosing relative primes for TTLs (or so). - * Also has to be at least one to break ties (and overwrite cached entry). - */ -#define PREFETCH_EXPIRY_ADD 60 - -/** 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); - back = outnet_get_mem(worker->back); - msg = slabhash_get_mem(worker->env.msg_cache); - rrset = slabhash_get_mem(&worker->env.rrset_cache->table); - infra = infra_get_mem(worker->env.infra_cache); - mesh = mesh_get_mem(worker->env.mesh); - ac = alloc_get_mem(&worker->alloc); - superac = alloc_get_mem(&worker->daemon->superalloc); - anch = anchors_get_mem(worker->env.anchors); - iter = 0; - val = 0; - for(i=0; i<worker->env.mesh->mods.num; i++) { - fptr_ok(fptr_whitelist_mod_get_mem(worker->env.mesh-> - mods.mod[i]->get_mem)); - 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); - } - me = sizeof(*worker) + sizeof(*worker->base) + sizeof(*worker->comsig) - + comm_point_get_mem(worker->cmd_com) - + sizeof(worker->rndstate) - + regional_get_mem(worker->scratchpad) - + sizeof(*worker->env.scratch_buffer) - + sldns_buffer_capacity(worker->env.scratch_buffer) - + forwards_get_mem(worker->env.fwds) - + hints_get_mem(worker->env.hints); - if(worker->thread_num == 0) - me += acl_list_get_mem(worker->daemon->acl); - if(cur_serv) { - 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", - (unsigned)total, (unsigned)front, (unsigned)back, - (unsigned)mesh, (unsigned)msg, (unsigned)rrset, - (unsigned)infra, (unsigned)iter, (unsigned)val, (unsigned)anch, - (unsigned)ac, (unsigned)superac, (unsigned)me); -#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; - for(i=0; i<worker->env.mesh->mods.num; i++) { - fptr_ok(fptr_whitelist_mod_get_mem(worker->env.mesh-> - mods.mod[i]->get_mem)); - 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 */ -} - -void -worker_send_cmd(struct worker* worker, enum worker_commands cmd) -{ - uint32_t c = (uint32_t)htonl(cmd); - if(!tube_write_msg(worker->cmd, (uint8_t*)&c, sizeof(c), 0)) { - log_err("worker send cmd %d failed", (int)cmd); - } -} - -int -worker_handle_reply(struct comm_point* c, void* arg, int error, - struct comm_reply* reply_info) -{ - struct module_qstate* q = (struct module_qstate*)arg; - struct worker* worker = q->env->worker; - struct outbound_entry e; - e.qstate = q; - e.qsent = NULL; - - if(error != 0) { - mesh_report_reply(worker->env.mesh, &e, reply_info, error); - worker_mem_report(worker, NULL); - return 0; - } - /* sanity check. */ - if(!LDNS_QR_WIRE(sldns_buffer_begin(c->buffer)) - || LDNS_OPCODE_WIRE(sldns_buffer_begin(c->buffer)) != - LDNS_PACKET_QUERY - || LDNS_QDCOUNT(sldns_buffer_begin(c->buffer)) > 1) { - /* error becomes timeout for the module as if this reply - * never arrived. */ - mesh_report_reply(worker->env.mesh, &e, reply_info, - NETEVENT_TIMEOUT); - worker_mem_report(worker, NULL); - return 0; - } - mesh_report_reply(worker->env.mesh, &e, reply_info, NETEVENT_NOERROR); - worker_mem_report(worker, NULL); - return 0; -} - -int -worker_handle_service_reply(struct comm_point* c, void* arg, int error, - struct comm_reply* reply_info) -{ - struct outbound_entry* e = (struct outbound_entry*)arg; - struct worker* worker = e->qstate->env->worker; - struct serviced_query *sq = e->qsent; - - verbose(VERB_ALGO, "worker svcd callback for qstate %p", e->qstate); - if(error != 0) { - mesh_report_reply(worker->env.mesh, e, reply_info, error); - worker_mem_report(worker, sq); - return 0; - } - /* sanity check. */ - if(!LDNS_QR_WIRE(sldns_buffer_begin(c->buffer)) - || LDNS_OPCODE_WIRE(sldns_buffer_begin(c->buffer)) != - LDNS_PACKET_QUERY - || LDNS_QDCOUNT(sldns_buffer_begin(c->buffer)) > 1) { - /* error becomes timeout for the module as if this reply - * never arrived. */ - verbose(VERB_ALGO, "worker: bad reply handled as timeout"); - mesh_report_reply(worker->env.mesh, e, reply_info, - NETEVENT_TIMEOUT); - worker_mem_report(worker, sq); - return 0; - } - mesh_report_reply(worker->env.mesh, e, reply_info, NETEVENT_NOERROR); - worker_mem_report(worker, sq); - return 0; -} - -/** ratelimit error replies - * @param worker: the worker struct with ratelimit counter - * @param err: error code that would be wanted. - * @return value of err if okay, or -1 if it should be discarded instead. - */ -static int -worker_err_ratelimit(struct worker* worker, int err) -{ - if(worker->err_limit_time == *worker->env.now) { - /* see if limit is exceeded for this second */ - if(worker->err_limit_count++ > ERROR_RATELIMIT) - return -1; - } else { - /* new second, new limits */ - worker->err_limit_time = *worker->env.now; - worker->err_limit_count = 1; - } - return err; -} - -/** check request sanity. - * @param pkt: the wire packet to examine for sanity. - * @param worker: parameters for checking. - * @return error code, 0 OK, or -1 discard. -*/ -static int -worker_check_request(sldns_buffer* pkt, struct worker* worker) -{ - if(sldns_buffer_limit(pkt) < LDNS_HEADER_SIZE) { - verbose(VERB_QUERY, "request too short, discarded"); - return -1; - } - if(sldns_buffer_limit(pkt) > NORMAL_UDP_SIZE && - worker->daemon->cfg->harden_large_queries) { - verbose(VERB_QUERY, "request too large, discarded"); - return -1; - } - if(LDNS_QR_WIRE(sldns_buffer_begin(pkt))) { - verbose(VERB_QUERY, "request has QR bit on, discarded"); - return -1; - } - if(LDNS_TC_WIRE(sldns_buffer_begin(pkt))) { - LDNS_TC_CLR(sldns_buffer_begin(pkt)); - verbose(VERB_QUERY, "request bad, has TC bit on"); - return worker_err_ratelimit(worker, LDNS_RCODE_FORMERR); - } - if(LDNS_OPCODE_WIRE(sldns_buffer_begin(pkt)) != LDNS_PACKET_QUERY) { - verbose(VERB_QUERY, "request unknown opcode %d", - LDNS_OPCODE_WIRE(sldns_buffer_begin(pkt))); - return worker_err_ratelimit(worker, LDNS_RCODE_NOTIMPL); - } - if(LDNS_QDCOUNT(sldns_buffer_begin(pkt)) != 1) { - verbose(VERB_QUERY, "request wrong nr qd=%d", - LDNS_QDCOUNT(sldns_buffer_begin(pkt))); - return worker_err_ratelimit(worker, LDNS_RCODE_FORMERR); - } - if(LDNS_ANCOUNT(sldns_buffer_begin(pkt)) != 0) { - verbose(VERB_QUERY, "request wrong nr an=%d", - LDNS_ANCOUNT(sldns_buffer_begin(pkt))); - return worker_err_ratelimit(worker, LDNS_RCODE_FORMERR); - } - if(LDNS_NSCOUNT(sldns_buffer_begin(pkt)) != 0) { - verbose(VERB_QUERY, "request wrong nr ns=%d", - LDNS_NSCOUNT(sldns_buffer_begin(pkt))); - return worker_err_ratelimit(worker, LDNS_RCODE_FORMERR); - } - if(LDNS_ARCOUNT(sldns_buffer_begin(pkt)) > 1) { - verbose(VERB_QUERY, "request wrong nr ar=%d", - LDNS_ARCOUNT(sldns_buffer_begin(pkt))); - return worker_err_ratelimit(worker, LDNS_RCODE_FORMERR); - } - return 0; -} - -void -worker_handle_control_cmd(struct tube* ATTR_UNUSED(tube), uint8_t* msg, - size_t len, int error, void* arg) -{ - struct worker* worker = (struct worker*)arg; - enum worker_commands cmd; - if(error != NETEVENT_NOERROR) { - free(msg); - if(error == NETEVENT_CLOSED) - comm_base_exit(worker->base); - else log_info("control event: %d", error); - return; - } - if(len != sizeof(uint32_t)) { - fatal_exit("bad control msg length %d", (int)len); - } - cmd = sldns_read_uint32(msg); - free(msg); - switch(cmd) { - case worker_cmd_quit: - verbose(VERB_ALGO, "got control cmd quit"); - comm_base_exit(worker->base); - break; - case worker_cmd_stats: - verbose(VERB_ALGO, "got control cmd stats"); - server_stats_reply(worker, 1); - break; - case worker_cmd_stats_noreset: - verbose(VERB_ALGO, "got control cmd stats_noreset"); - server_stats_reply(worker, 0); - break; - case worker_cmd_remote: - verbose(VERB_ALGO, "got control cmd remote"); - daemon_remote_exec(worker); - break; - default: - log_err("bad command %d", (int)cmd); - break; - } -} - -/** check if a delegation is secure */ -static enum sec_status -check_delegation_secure(struct reply_info *rep) -{ - /* return smallest security status */ - size_t i; - enum sec_status sec = sec_status_secure; - enum sec_status s; - size_t num = rep->an_numrrsets + rep->ns_numrrsets; - /* check if answer and authority are OK */ - for(i=0; i<num; i++) { - s = ((struct packed_rrset_data*)rep->rrsets[i]->entry.data) - ->security; - if(s < sec) - sec = s; - } - /* in additional, only unchecked triggers revalidation */ - for(i=num; i<rep->rrset_count; i++) { - s = ((struct packed_rrset_data*)rep->rrsets[i]->entry.data) - ->security; - if(s == sec_status_unchecked) - return s; - } - return sec; -} - -/** remove nonsecure from a delegation referral additional section */ -static void -deleg_remove_nonsecure_additional(struct reply_info* rep) -{ - /* we can simply edit it, since we are working in the scratch region */ - size_t i; - enum sec_status s; - - for(i = rep->an_numrrsets+rep->ns_numrrsets; i<rep->rrset_count; i++) { - s = ((struct packed_rrset_data*)rep->rrsets[i]->entry.data) - ->security; - if(s != sec_status_secure) { - memmove(rep->rrsets+i, rep->rrsets+i+1, - sizeof(struct ub_packed_rrset_key*)* - (rep->rrset_count - i - 1)); - rep->ar_numrrsets--; - rep->rrset_count--; - i--; - } - } -} - -/** answer nonrecursive query from the cache */ -static int -answer_norec_from_cache(struct worker* worker, struct query_info* qinfo, - uint16_t id, uint16_t flags, struct comm_reply* repinfo, - struct edns_data* edns) -{ - /* for a nonrecursive query return either: - * o an error (servfail; we try to avoid this) - * o a delegation (closest we have; this routine tries that) - * o the answer (checked by answer_from_cache) - * - * So, grab a delegation from the rrset cache. - * Then check if it needs validation, if so, this routine fails, - * so that iterator can prime and validator can verify rrsets. - */ - uint16_t udpsize = edns->udp_size; - int secure = 0; - time_t timenow = *worker->env.now; - int must_validate = (!(flags&BIT_CD) || worker->env.cfg->ignore_cd) - && worker->env.need_to_validate; - struct dns_msg *msg = NULL; - struct delegpt *dp; - - dp = dns_cache_find_delegation(&worker->env, qinfo->qname, - qinfo->qname_len, qinfo->qtype, qinfo->qclass, - worker->scratchpad, &msg, timenow); - if(!dp) { /* no delegation, need to reprime */ - 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 */ - return 0; - case sec_status_bogus: - /* some rrsets are bogus, reply servfail */ - edns->edns_version = EDNS_ADVERTISED_VERSION; - 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); - if(worker->stats.extended) { - worker->stats.ans_bogus++; - worker->stats.ans_rcode[LDNS_RCODE_SERVFAIL]++; - } - return 1; - case sec_status_secure: - /* all rrsets are secure */ - /* remove non-secure rrsets from the add. section*/ - if(worker->env.cfg->val_clean_additional) - deleg_remove_nonsecure_additional(msg->rep); - secure = 1; - break; - case sec_status_indeterminate: - case sec_status_insecure: - default: - /* not secure */ - secure = 0; - break; - } - } - /* return this delegation from the cache */ - edns->edns_version = EDNS_ADVERTISED_VERSION; - 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); - } - if(worker->stats.extended) { - if(secure) worker->stats.ans_secure++; - server_stats_insrcode(&worker->stats, repinfo->c->buffer); - } - return 1; -} - -/** 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; - *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. */ - } - /* 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 == - htons(LDNS_RR_TYPE_DNAME))) { - if(!reply_check_cname_chain(qinfo, rep)) { - /* cname chain invalid, redo iterator steps */ - verbose(VERB_ALGO, "Cache reply: cname chain broken"); - bail_out: - rrset_array_unlock_touch(worker->env.rrset_cache, - worker->scratchpad, rep->ref, rep->rrset_count); - return 0; - } - } - /* check security status of the cached answer */ - if( rep->security == sec_status_bogus && must_validate) { - /* BAD cached */ - edns->edns_version = EDNS_ADVERTISED_VERSION; - 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); - if(worker->stats.extended) { - worker->stats.ans_bogus ++; - worker->stats.ans_rcode[LDNS_RCODE_SERVFAIL] ++; - } - return 1; - } else if( rep->security == sec_status_unchecked && must_validate) { - verbose(VERB_ALGO, "Cache reply: unchecked entry needs " - "validation"); - goto bail_out; /* need to validate cache entry first */ - } else if(rep->security == sec_status_secure) { - if(reply_all_rrsets_secure(rep)) - secure = 1; - else { - if(must_validate) { - verbose(VERB_ALGO, "Cache reply: secure entry" - " changed status"); - goto bail_out; /* rrset changed, re-verify */ - } - secure = 0; - } - } else secure = 0; - - edns->edns_version = EDNS_ADVERTISED_VERSION; - edns->udp_size = EDNS_ADVERTISED_SIZE; - edns->ext_rcode = 0; - edns->bits &= EDNS_DO; - 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); - } - /* cannot send the reply right now, because blocking network syscall - * is bad while holding locks. */ - rrset_array_unlock_touch(worker->env.rrset_cache, worker->scratchpad, - rep->ref, rep->rrset_count); - if(worker->stats.extended) { - if(secure) worker->stats.ans_secure++; - server_stats_insrcode(&worker->stats, repinfo->c->buffer); - } - /* go and return this buffer to the client */ - return 1; -} - -/** 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 */ - 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 - * client addrs waiting, which has the cache blacklisted (to bypass - * the cache and go to the network for the data). */ - /* this (potentially) runs the mesh for the new query */ - mesh_new_prefetch(worker->env.mesh, qinfo, flags, leeway + - PREFETCH_EXPIRY_ADD); -} - -/** - * 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, char** str, int num, struct edns_data* edns, - struct worker* worker) -{ - int i; - unsigned int rd = LDNS_RD_WIRE(sldns_buffer_begin(pkt)); - unsigned int cd = LDNS_CD_WIRE(sldns_buffer_begin(pkt)); - 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, (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 */ - 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 - * @param qinfo: query info. Pointer into packet buffer. - * @param edns: edns info from query. - * @param pkt: packet buffer. - * @return: true if a reply is to be sent. - */ -static int -answer_chaos(struct worker* w, struct query_info* qinfo, - struct edns_data* edns, sldns_buffer* pkt) -{ - struct config_file* cfg = w->env.cfg; - if(qinfo->qtype != LDNS_RR_TYPE_ANY && qinfo->qtype != LDNS_RR_TYPE_TXT) - return 0; - if(query_dname_compare(qinfo->qname, - (uint8_t*)"\002id\006server") == 0 || - query_dname_compare(qinfo->qname, - (uint8_t*)"\010hostname\004bind") == 0) - { - if(cfg->hide_identity) - return 0; - if(cfg->identity==NULL || cfg->identity[0]==0) { - char buf[MAXHOSTNAMELEN+1]; - if (gethostname(buf, MAXHOSTNAMELEN) == 0) { - buf[MAXHOSTNAMELEN] = 0; - chaos_replyonestr(pkt, buf, edns, w); - } else { - log_err("gethostname: %s", strerror(errno)); - chaos_replyonestr(pkt, "no hostname", edns, w); - } - } - else chaos_replyonestr(pkt, cfg->identity, edns, w); - return 1; - } - if(query_dname_compare(qinfo->qname, - (uint8_t*)"\007version\006server") == 0 || - query_dname_compare(qinfo->qname, - (uint8_t*)"\007version\004bind") == 0) - { - if(cfg->hide_version) - return 0; - if(cfg->version==NULL || cfg->version[0]==0) - 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; -} - -static int -deny_refuse(struct comm_point* c, enum acl_access acl, - enum acl_access deny, enum acl_access refuse, - struct worker* worker, struct comm_reply* repinfo) -{ - if(acl == deny) { - comm_point_drop_reply(repinfo); - if(worker->stats.extended) - worker->stats.unwanted_queries++; - return 0; - } else if(acl == refuse) { - log_addr(VERB_ALGO, "refused query from", - &repinfo->addr, repinfo->addrlen); - log_buf(VERB_ALGO, "refuse", c->buffer); - if(worker->stats.extended) - worker->stats.unwanted_queries++; - if(worker_check_request(c->buffer, worker) == -1) { - comm_point_drop_reply(repinfo); - return 0; /* discard this */ - } - sldns_buffer_set_limit(c->buffer, LDNS_HEADER_SIZE); - sldns_buffer_write_at(c->buffer, 4, - (uint8_t*)"\0\0\0\0\0\0\0\0", 8); - 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; - } - - return -1; -} - -static int -deny_refuse_all(struct comm_point* c, enum acl_access acl, - struct worker* worker, struct comm_reply* repinfo) -{ - return deny_refuse(c, acl, acl_deny, acl_refuse, worker, repinfo); -} - -static int -deny_refuse_non_local(struct comm_point* c, enum acl_access acl, - struct worker* worker, struct comm_reply* repinfo) -{ - return deny_refuse(c, acl, acl_deny_non_local, acl_refuse_non_local, worker, repinfo); -} - -int -worker_handle_request(struct comm_point* c, void* arg, int error, - struct comm_reply* repinfo) -{ - struct worker* worker = (struct worker*)arg; - int ret; - 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 - 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) - goto send_reply; - return ret; - } - if((ret=worker_check_request(c->buffer, worker)) != 0) { - verbose(VERB_ALGO, "worker check request: bad query."); - log_addr(VERB_CLIENT,"from",&repinfo->addr, repinfo->addrlen); - if(ret != -1) { - LDNS_QR_SET(sldns_buffer_begin(c->buffer)); - LDNS_RCODE_SET(sldns_buffer_begin(c->buffer), ret); - return 1; - } - 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."); - 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); - server_stats_insrcode(&worker->stats, c->buffer); - goto send_reply; - } - if(worker->env.cfg->log_queries) { - char ip[128]; - addr_to_str(&repinfo->addr, repinfo->addrlen, ip, sizeof(ip)); - log_nametypeclass(0, ip, qinfo.qname, qinfo.qtype, qinfo.qclass); - } - if(qinfo.qtype == LDNS_RR_TYPE_AXFR || - qinfo.qtype == LDNS_RR_TYPE_IXFR) { - verbose(VERB_ALGO, "worker request: refused zone transfer."); - log_addr(VERB_CLIENT,"from",&repinfo->addr, repinfo->addrlen); - sldns_buffer_rewind(c->buffer); - LDNS_QR_SET(sldns_buffer_begin(c->buffer)); - LDNS_RCODE_SET(sldns_buffer_begin(c->buffer), - LDNS_RCODE_REFUSED); - if(worker->stats.extended) { - worker->stats.qtype[qinfo.qtype]++; - server_stats_insrcode(&worker->stats, c->buffer); - } - goto send_reply; - } - 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); - memset(&reply_edns, 0, sizeof(reply_edns)); - reply_edns.edns_present = 1; - reply_edns.udp_size = EDNS_ADVERTISED_SIZE; - LDNS_RCODE_SET(sldns_buffer_begin(c->buffer), ret); - 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; - } - if(edns.edns_present && edns.edns_version != 0) { - edns.ext_rcode = (uint8_t)(EDNS_RCODE_BADVERS>>4); - 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 && - worker->daemon->cfg->harden_short_bufsize) { - verbose(VERB_QUERY, "worker request: EDNS bufsize %d ignored", - (int)edns.udp_size); - log_addr(VERB_CLIENT,"from",&repinfo->addr, repinfo->addrlen); - edns.udp_size = NORMAL_UDP_SIZE; - } - if(edns.udp_size > worker->daemon->cfg->max_udp_size && - c->type == comm_udp) { - verbose(VERB_QUERY, - "worker request: max UDP reply size modified" - " (%d to max-udp-size)", (int)edns.udp_size); - log_addr(VERB_CLIENT,"from",&repinfo->addr, repinfo->addrlen); - edns.udp_size = worker->daemon->cfg->max_udp_size; - } - if(edns.udp_size < LDNS_HEADER_SIZE) { - verbose(VERB_ALGO, "worker request: edns is too small."); - log_addr(VERB_CLIENT, "from", &repinfo->addr, repinfo->addrlen); - LDNS_QR_SET(sldns_buffer_begin(c->buffer)); - LDNS_TC_SET(sldns_buffer_begin(c->buffer)); - LDNS_RCODE_SET(sldns_buffer_begin(c->buffer), - LDNS_RCODE_SERVFAIL); - sldns_buffer_set_position(c->buffer, LDNS_HEADER_SIZE); - 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) - server_stats_insquery(&worker->stats, c, qinfo.qtype, - qinfo.qclass, &edns, repinfo); - if(c->type != comm_udp) - edns.udp_size = 65535; /* max size for TCP replies */ - 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, &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); - return 0; - } - server_stats_insrcode(&worker->stats, c->buffer); - goto send_reply; - } - - /* We've looked in our local zones. If the answer isn't there, we - * 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; - } - - /* If this request does not have the recursion bit set, verify - * ACLs allow the snooping. */ - if(!(LDNS_RD_WIRE(sldns_buffer_begin(c->buffer))) && - acl != acl_allow_snoop ) { - sldns_buffer_set_limit(c->buffer, LDNS_HEADER_SIZE); - sldns_buffer_write_at(c->buffer, 4, - (uint8_t*)"\0\0\0\0\0\0\0\0", 8); - LDNS_QR_SET(sldns_buffer_begin(c->buffer)); - 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; - } - - /* 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); - 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); - } - 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"); - } - } - sldns_buffer_rewind(c->buffer); - server_stats_querymiss(&worker->stats, worker); - - if(verbosity >= VERB_CLIENT) { - if(c->type == comm_udp) - log_addr(VERB_CLIENT, "udp request from", - &repinfo->addr, repinfo->addrlen); - else log_addr(VERB_CLIENT, "tcp request from", - &repinfo->addr, repinfo->addrlen); - } - - /* grab a work request structure for this new request */ - 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; -} - -void -worker_sighandler(int sig, void* arg) -{ - /* note that log, print, syscalls here give race conditions. - * And cause hangups if the log-lock is held by the application. */ - struct worker* worker = (struct worker*)arg; - switch(sig) { -#ifdef SIGHUP - case SIGHUP: - comm_base_exit(worker->base); - break; -#endif - case SIGINT: - worker->need_to_exit = 1; - comm_base_exit(worker->base); - break; -#ifdef SIGQUIT - case SIGQUIT: - worker->need_to_exit = 1; - comm_base_exit(worker->base); - break; -#endif - case SIGTERM: - worker->need_to_exit = 1; - comm_base_exit(worker->base); - break; - default: - /* unknown signal, ignored */ - break; - } -} - -/** restart statistics timer for worker, if enabled */ -static void -worker_restart_timer(struct worker* worker) -{ - if(worker->env.cfg->stat_interval > 0) { - struct timeval tv; -#ifndef S_SPLINT_S - tv.tv_sec = worker->env.cfg->stat_interval; - tv.tv_usec = 0; -#endif - comm_timer_set(worker->stat_timer, &tv); - } -} - -void worker_stat_timer_cb(void* arg) -{ - struct worker* worker = (struct worker*)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); - } - /* start next timer */ - worker_restart_timer(worker); -} - -void worker_probe_timer_cb(void* arg) -{ - struct worker* worker = (struct worker*)arg; - struct timeval tv; -#ifndef S_SPLINT_S - tv.tv_sec = (time_t)autr_probe_timer(&worker->env); - tv.tv_usec = 0; -#endif - if(tv.tv_sec != 0) - comm_timer_set(worker->env.probe_timer, &tv); -} - -struct worker* -worker_create(struct daemon* daemon, int id, int* ports, int n) -{ - unsigned int seed; - struct worker* worker = (struct worker*)calloc(1, - sizeof(struct worker)); - if(!worker) - return NULL; - worker->numports = n; - worker->ports = (int*)memdup(ports, sizeof(int)*n); - if(!worker->ports) { - free(worker); - return NULL; - } - worker->daemon = daemon; - worker->thread_num = id; - if(!(worker->cmd = tube_create())) { - free(worker->ports); - free(worker); - return NULL; - } - /* create random state here to avoid locking trouble in RAND_bytes */ - seed = (unsigned int)time(NULL) ^ (unsigned int)getpid() ^ - (((unsigned int)worker->thread_num)<<17); - /* shift thread_num so it does not match out pid bits */ - if(!(worker->rndstate = ub_initstate(seed, daemon->rand))) { - seed = 0; - log_err("could not init random numbers."); - tube_delete(worker->cmd); - free(worker->ports); - free(worker); - return NULL; - } - seed = 0; -#ifdef USE_DNSTAP - if(daemon->cfg->dnstap) { - log_assert(daemon->dtenv != NULL); - memcpy(&worker->dtenv, daemon->dtenv, sizeof(struct dt_env)); - if(!dt_init(&worker->dtenv)) - fatal_exit("dt_init failed"); - } -#endif - return worker; -} - -int -worker_init(struct worker* worker, struct config_file *cfg, - struct listen_port* ports, int do_sigs) -{ -#ifdef USE_DNSTAP - struct dt_env* dtenv = &worker->dtenv; -#else - void* dtenv = NULL; -#endif - worker->need_to_exit = 0; - worker->base = comm_base_create(do_sigs); - if(!worker->base) { - log_err("could not create event handling base"); - worker_delete(worker); - return 0; - } - comm_base_set_slow_accept_handlers(worker->base, &worker_stop_accept, - &worker_start_accept, worker); - if(do_sigs) { -#ifdef SIGHUP - ub_thread_sig_unblock(SIGHUP); -#endif - ub_thread_sig_unblock(SIGINT); -#ifdef SIGQUIT - ub_thread_sig_unblock(SIGQUIT); -#endif - ub_thread_sig_unblock(SIGTERM); -#ifndef LIBEVENT_SIGNAL_PROBLEM - worker->comsig = comm_signal_create(worker->base, - worker_sighandler, worker); - if(!worker->comsig -#ifdef SIGHUP - || !comm_signal_bind(worker->comsig, SIGHUP) -#endif -#ifdef SIGQUIT - || !comm_signal_bind(worker->comsig, SIGQUIT) -#endif - || !comm_signal_bind(worker->comsig, SIGTERM) - || !comm_signal_bind(worker->comsig, SIGINT)) { - log_err("could not create signal handlers"); - worker_delete(worker); - return 0; - } -#endif /* LIBEVENT_SIGNAL_PROBLEM */ - if(!daemon_remote_open_accept(worker->daemon->rc, - worker->daemon->rc_ports, worker)) { - worker_delete(worker); - return 0; - } -#ifdef UB_ON_WINDOWS - wsvc_setup_worker(worker); -#endif /* UB_ON_WINDOWS */ - } else { /* !do_sigs */ - worker->comsig = NULL; - } - worker->front = listen_create(worker->base, ports, - cfg->msg_buffer_size, (int)cfg->incoming_num_tcp, - worker->daemon->listen_sslctx, dtenv, worker_handle_request, - worker); - if(!worker->front) { - log_err("could not create listening sockets"); - worker_delete(worker); - return 0; - } - worker->back = outside_network_create(worker->base, - cfg->msg_buffer_size, (size_t)cfg->outgoing_num_ports, - cfg->out_ifs, cfg->num_out_ifs, cfg->do_ip4, cfg->do_ip6, - 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, cfg->outgoing_tcp_mss, - &worker_alloc_cleanup, worker, - cfg->do_udp, worker->daemon->connect_sslctx, cfg->delay_close, - dtenv); - if(!worker->back) { - log_err("could not create outgoing sockets"); - worker_delete(worker); - return 0; - } - /* start listening to commands */ - if(!tube_setup_bg_listen(worker->cmd, worker->base, - &worker_handle_control_cmd, worker)) { - log_err("could not create control compt."); - worker_delete(worker); - return 0; - } - worker->stat_timer = comm_timer_create(worker->base, - worker_stat_timer_cb, worker); - if(!worker->stat_timer) { - log_err("could not create statistics timer"); - } - - /* we use the msg_buffer_size as a good estimate for what the - * user wants for memory usage sizes */ - worker->scratchpad = regional_create_custom(cfg->msg_buffer_size); - if(!worker->scratchpad) { - log_err("malloc failure"); - worker_delete(worker); - return 0; - } - - server_stats_init(&worker->stats, cfg); - alloc_init(&worker->alloc, &worker->daemon->superalloc, - worker->thread_num); - alloc_set_id_cleanup(&worker->alloc, &worker_alloc_cleanup, worker); - worker->env = *worker->daemon->env; - comm_base_timept(worker->base, &worker->env.now, &worker->env.now_tv); - if(worker->thread_num == 0) - log_set_time(worker->env.now); - worker->env.worker = worker; - worker->env.send_query = &worker_send_query; - worker->env.alloc = &worker->alloc; - worker->env.rnd = worker->rndstate; - worker->env.scratch = worker->scratchpad; - worker->env.mesh = mesh_create(&worker->daemon->mods, &worker->env); - worker->env.detach_subs = &mesh_detach_subs; - worker->env.attach_sub = &mesh_attach_sub; - worker->env.kill_sub = &mesh_state_delete; - worker->env.detect_cycle = &mesh_detect_cycle; - worker->env.scratch_buffer = sldns_buffer_new(cfg->msg_buffer_size); - if(!(worker->env.fwds = forwards_create()) || - !forwards_apply_cfg(worker->env.fwds, cfg)) { - log_err("Could not set forward zones"); - worker_delete(worker); - return 0; - } - if(!(worker->env.hints = hints_create()) || - !hints_apply_cfg(worker->env.hints, cfg)) { - log_err("Could not set root or stub hints"); - worker_delete(worker); - return 0; - } - /* one probe timer per process -- if we have 5011 anchors */ - if(autr_get_num_anchors(worker->env.anchors) > 0 -#ifndef THREADS_DISABLED - && worker->thread_num == 0 -#endif - ) { - struct timeval tv; - tv.tv_sec = 0; - tv.tv_usec = 0; - worker->env.probe_timer = comm_timer_create(worker->base, - worker_probe_timer_cb, worker); - if(!worker->env.probe_timer) { - log_err("could not create 5011-probe timer"); - } else { - /* let timer fire, then it can reset itself */ - comm_timer_set(worker->env.probe_timer, &tv); - } - } - if(!worker->env.mesh || !worker->env.scratch_buffer) { - worker_delete(worker); - return 0; - } - worker_mem_report(worker, NULL); - /* if statistics enabled start timer */ - if(worker->env.cfg->stat_interval > 0) { - verbose(VERB_ALGO, "set statistics interval %d secs", - worker->env.cfg->stat_interval); - worker_restart_timer(worker); - } - return 1; -} - -void -worker_work(struct worker* worker) -{ - comm_base_dispatch(worker->base); -} - -void -worker_delete(struct worker* worker) -{ - if(!worker) - return; - if(worker->env.mesh && verbosity >= VERB_OPS) { - server_stats_log(&worker->stats, worker, worker->thread_num); - mesh_stats(worker->env.mesh, "mesh has"); - worker_mem_report(worker, NULL); - } - outside_network_quit_prepare(worker->back); - mesh_delete(worker->env.mesh); - sldns_buffer_free(worker->env.scratch_buffer); - forwards_delete(worker->env.fwds); - hints_delete(worker->env.hints); - listen_delete(worker->front); - outside_network_delete(worker->back); - comm_signal_delete(worker->comsig); - tube_delete(worker->cmd); - comm_timer_delete(worker->stat_timer); - comm_timer_delete(worker->env.probe_timer); - free(worker->ports); - if(worker->thread_num == 0) { - log_set_time(NULL); -#ifdef UB_ON_WINDOWS - wsvc_desetup_worker(worker); -#endif /* UB_ON_WINDOWS */ - } - comm_base_delete(worker->base); - ub_randfree(worker->rndstate); - alloc_clear(&worker->alloc); - regional_destroy(worker->scratchpad); - free(worker); -} - -struct outbound_entry* -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( - q->region, sizeof(*e)); - if(!e) - return NULL; - e->qstate = q; - 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; - } - return e; -} - -void -worker_alloc_cleanup(void* arg) -{ - struct worker* worker = (struct worker*)arg; - slabhash_clear(&worker->env.rrset_cache->table); - slabhash_clear(worker->env.msg_cache); -} - -void worker_stats_clear(struct worker* worker) -{ - server_stats_init(&worker->stats, worker->env.cfg); - mesh_stats_clear(worker->env.mesh); - worker->back->unwanted_replies = 0; - worker->back->num_tcp_outgoing = 0; -} - -void worker_start_accept(void* arg) -{ - struct worker* worker = (struct worker*)arg; - listen_start_accept(worker->front); - if(worker->thread_num == 0) - daemon_remote_start_accept(worker->daemon->rc); -} - -void worker_stop_accept(void* arg) -{ - struct worker* worker = (struct worker*)arg; - listen_stop_accept(worker->front); - if(worker->thread_num == 0) - daemon_remote_stop_accept(worker->daemon->rc); -} - -/* --- fake callbacks for fptr_wlist to work --- */ -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; -} - -int libworker_handle_reply(struct comm_point* ATTR_UNUSED(c), - void* ATTR_UNUSED(arg), int ATTR_UNUSED(error), - struct comm_reply* ATTR_UNUSED(reply_info)) -{ - log_assert(0); - return 0; -} - -int libworker_handle_service_reply(struct comm_point* ATTR_UNUSED(c), - void* ATTR_UNUSED(arg), int ATTR_UNUSED(error), - struct comm_reply* ATTR_UNUSED(reply_info)) -{ - log_assert(0); - return 0; -} - -void libworker_handle_control_cmd(struct tube* ATTR_UNUSED(tube), - uint8_t* ATTR_UNUSED(buffer), size_t ATTR_UNUSED(len), - int ATTR_UNUSED(error), void* ATTR_UNUSED(arg)) -{ - log_assert(0); -} - -void libworker_fg_done_cb(void* ATTR_UNUSED(arg), int ATTR_UNUSED(rcode), - sldns_buffer* ATTR_UNUSED(buf), enum sec_status ATTR_UNUSED(s), - char* ATTR_UNUSED(why_bogus)) -{ - log_assert(0); -} - -void libworker_bg_done_cb(void* ATTR_UNUSED(arg), int ATTR_UNUSED(rcode), - sldns_buffer* ATTR_UNUSED(buf), enum sec_status ATTR_UNUSED(s), - char* ATTR_UNUSED(why_bogus)) -{ - log_assert(0); -} - -void libworker_event_done_cb(void* ATTR_UNUSED(arg), int ATTR_UNUSED(rcode), - sldns_buffer* ATTR_UNUSED(buf), enum sec_status ATTR_UNUSED(s), - char* ATTR_UNUSED(why_bogus)) -{ - log_assert(0); -} - -int context_query_cmp(const void* ATTR_UNUSED(a), const void* ATTR_UNUSED(b)) -{ - log_assert(0); - return 0; -} - -int order_lock_cmp(const void* ATTR_UNUSED(e1), const void* ATTR_UNUSED(e2)) -{ - log_assert(0); - return 0; -} - -int codeline_cmp(const void* ATTR_UNUSED(a), const void* ATTR_UNUSED(b)) -{ - log_assert(0); - return 0; -} - diff --git a/external/unbound/daemon/worker.h b/external/unbound/daemon/worker.h deleted file mode 100644 index 0d7ce9521..000000000 --- a/external/unbound/daemon/worker.h +++ /dev/null @@ -1,178 +0,0 @@ -/* - * daemon/worker.h - worker that handles a pending list of requests. - * - * Copyright (c) 2007, NLnet Labs. All rights reserved. - * - * This software is open source. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * Neither the name of the NLNET LABS nor the names of its contributors may - * be used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED - * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/** - * \file - * - * This file describes the worker structure that holds a list of - * pending requests and handles them. - */ - -#ifndef DAEMON_WORKER_H -#define DAEMON_WORKER_H - -#include "libunbound/worker.h" -#include "util/netevent.h" -#include "util/locks.h" -#include "util/alloc.h" -#include "util/data/msgreply.h" -#include "util/data/msgparse.h" -#include "daemon/stats.h" -#include "util/module.h" -#include "dnstap/dnstap.h" -struct listen_dnsport; -struct outside_network; -struct config_file; -struct daemon; -struct listen_port; -struct ub_randstate; -struct regional; -struct tube; -struct daemon_remote; -struct query_info; - -/** worker commands */ -enum worker_commands { - /** make the worker quit */ - worker_cmd_quit, - /** obtain statistics */ - worker_cmd_stats, - /** obtain statistics without statsclear */ - worker_cmd_stats_noreset, - /** execute remote control command */ - worker_cmd_remote -}; - -/** - * Structure holding working information for unbound. - * Holds globally visible information. - */ -struct worker { - /** the thread number (in daemon array). First in struct for debug. */ - int thread_num; - /** global shared daemon structure */ - struct daemon* daemon; - /** thread id */ - ub_thread_type thr_id; - /** pipe, for commands for this worker */ - struct tube* cmd; - /** the event base this worker works with */ - struct comm_base* base; - /** the frontside listening interface where request events come in */ - struct listen_dnsport* front; - /** the backside outside network interface to the auth servers */ - struct outside_network* back; - /** ports to be used by this worker. */ - int* ports; - /** number of ports for this worker */ - int numports; - /** the signal handler */ - struct comm_signal* comsig; - /** commpoint to listen to commands. */ - struct comm_point* cmd_com; - /** timer for statistics */ - struct comm_timer* stat_timer; - /** ratelimit for errors, time value */ - time_t err_limit_time; - /** ratelimit for errors, packet count */ - unsigned int err_limit_count; - - /** random() table for this worker. */ - struct ub_randstate* rndstate; - /** do we need to restart or quit (on signal) */ - int need_to_exit; - /** allocation cache for this thread */ - struct alloc_cache alloc; - /** per thread statistics */ - struct server_stats stats; - /** thread scratch regional */ - struct regional* scratchpad; - - /** module environment passed to modules, changed for this thread */ - struct module_env env; - -#ifdef USE_DNSTAP - /** dnstap environment, changed for this thread */ - struct dt_env dtenv; -#endif -}; - -/** - * Create the worker structure. Bare bones version, zeroed struct, - * with backpointers only. Use worker_init on it later. - * @param daemon: the daemon that this worker thread is part of. - * @param id: the thread number from 0.. numthreads-1. - * @param ports: the ports it is allowed to use, array. - * @param n: the number of ports. - * @return: the new worker or NULL on alloc failure. - */ -struct worker* worker_create(struct daemon* daemon, int id, int* ports, int n); - -/** - * Initialize worker. - * Allocates event base, listens to ports - * @param worker: worker to initialize, created with worker_create. - * @param cfg: configuration settings. - * @param ports: list of shared query ports. - * @param do_sigs: if true, worker installs signal handlers. - * @return: false on error. - */ -int worker_init(struct worker* worker, struct config_file *cfg, - struct listen_port* ports, int do_sigs); - -/** - * Make worker work. - */ -void worker_work(struct worker* worker); - -/** - * Delete worker. - */ -void worker_delete(struct worker* worker); - -/** - * Send a command to a worker. Uses blocking writes. - * @param worker: worker to send command to. - * @param cmd: command to send. - */ -void worker_send_cmd(struct worker* worker, enum worker_commands cmd); - -/** - * Init worker stats - includes server_stats_init, outside network and mesh. - * @param worker: the worker to init - */ -void worker_stats_clear(struct worker* worker); - -#endif /* DAEMON_WORKER_H */ |