aboutsummaryrefslogtreecommitdiff
path: root/external/unbound/daemon
diff options
context:
space:
mode:
Diffstat (limited to 'external/unbound/daemon')
-rw-r--r--external/unbound/daemon/acl_list.c487
-rw-r--r--external/unbound/daemon/acl_list.h155
-rw-r--r--external/unbound/daemon/cachedump.c898
-rw-r--r--external/unbound/daemon/cachedump.h107
-rw-r--r--external/unbound/daemon/daemon.c795
-rw-r--r--external/unbound/daemon/daemon.h183
-rw-r--r--external/unbound/daemon/remote.c3050
-rw-r--r--external/unbound/daemon/remote.h191
-rw-r--r--external/unbound/daemon/stats.c343
-rw-r--r--external/unbound/daemon/stats.h262
-rw-r--r--external/unbound/daemon/unbound.c738
-rw-r--r--external/unbound/daemon/worker.c1883
-rw-r--r--external/unbound/daemon/worker.h178
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 */