summaryrefslogtreecommitdiffstats
path: root/contrib/unbound/daemon
diff options
context:
space:
mode:
authordes <des@FreeBSD.org>2015-07-06 13:23:27 +0000
committerdes <des@FreeBSD.org>2015-07-06 13:23:27 +0000
commita060063a487e71aee85b154308b20e3c3d050c54 (patch)
tree78e508412e7aed4056295e6af1335856834fc7e3 /contrib/unbound/daemon
parentc49abb198d367256a94da48fed297b82b5a11ad9 (diff)
downloadFreeBSD-src-a060063a487e71aee85b154308b20e3c3d050c54.zip
FreeBSD-src-a060063a487e71aee85b154308b20e3c3d050c54.tar.gz
MFH (r276605, r282089): upgrade to latest Unbound
MFH (r276699, r276702, r277057): local control socket MFH (r276599, r276612, r282087, r282088): build fixes This brings in Unbound 1.5.3 from head. Local control sockets are now supported and will be used by default for new installations. Existing systems will continue to use TCP control sockets until the automated setup script is re-run ("service local_unbound setup") and the service restarted ("service local_unbound restart"). Approved by: re (kib) Relnotes: yes
Diffstat (limited to 'contrib/unbound/daemon')
-rw-r--r--contrib/unbound/daemon/cachedump.c2
-rw-r--r--contrib/unbound/daemon/daemon.c39
-rw-r--r--contrib/unbound/daemon/daemon.h11
-rw-r--r--contrib/unbound/daemon/remote.c464
-rw-r--r--contrib/unbound/daemon/remote.h2
-rw-r--r--contrib/unbound/daemon/stats.c13
-rw-r--r--contrib/unbound/daemon/stats.h11
-rw-r--r--contrib/unbound/daemon/unbound.c71
-rw-r--r--contrib/unbound/daemon/worker.c91
-rw-r--r--contrib/unbound/daemon/worker.h6
10 files changed, 517 insertions, 193 deletions
diff --git a/contrib/unbound/daemon/cachedump.c b/contrib/unbound/daemon/cachedump.c
index cf5b1a1..20a46ae 100644
--- a/contrib/unbound/daemon/cachedump.c
+++ b/contrib/unbound/daemon/cachedump.c
@@ -664,7 +664,7 @@ load_msg(SSL* ssl, sldns_buffer* buf, struct worker* worker)
if(!go_on)
return 1; /* skip this one, not all references satisfied */
- if(!dns_cache_store(&worker->env, &qinf, &rep, 0, 0, 0, NULL)) {
+ if(!dns_cache_store(&worker->env, &qinf, &rep, 0, 0, 0, NULL, flags)) {
log_warn("error out of memory");
return 0;
}
diff --git a/contrib/unbound/daemon/daemon.c b/contrib/unbound/daemon/daemon.c
index aed22c2..f693a02 100644
--- a/contrib/unbound/daemon/daemon.c
+++ b/contrib/unbound/daemon/daemon.c
@@ -109,8 +109,9 @@ int ub_c_lex_destroy(void);
static RETSIGTYPE record_sigh(int sig)
{
#ifdef LIBEVENT_SIGNAL_PROBLEM
- verbose(VERB_OPS, "quit on signal, no cleanup and statistics, "
- "because installed libevent version is not threadsafe");
+ /* 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)
@@ -135,7 +136,8 @@ static RETSIGTYPE record_sigh(int sig)
break;
#endif
default:
- log_err("ignoring signal %d", sig);
+ /* ignoring signal */
+ break;
}
}
@@ -256,8 +258,8 @@ daemon_open_shared_ports(struct daemon* daemon)
log_assert(daemon);
if(daemon->cfg->port != daemon->listening_port) {
size_t i;
- int reuseport = 0;
struct listen_port* p0;
+ daemon->reuseport = 0;
/* free and close old ports */
if(daemon->ports != NULL) {
for(i=0; i<daemon->num_ports; i++)
@@ -266,17 +268,17 @@ daemon_open_shared_ports(struct daemon* daemon)
daemon->ports = NULL;
}
/* see if we want to reuseport */
-#if defined(__linux__) && defined(SO_REUSEPORT)
+#ifdef SO_REUSEPORT
if(daemon->cfg->so_reuseport && daemon->cfg->num_threads > 0)
- reuseport = 1;
+ daemon->reuseport = 1;
#endif
/* try to use reuseport */
- p0 = listening_ports_open(daemon->cfg, &reuseport);
+ p0 = listening_ports_open(daemon->cfg, &daemon->reuseport);
if(!p0) {
listening_ports_free(p0);
return 0;
}
- if(reuseport) {
+ if(daemon->reuseport) {
/* reuseport was successful, allocate for it */
daemon->num_ports = (size_t)daemon->cfg->num_threads;
} else {
@@ -290,12 +292,13 @@ daemon_open_shared_ports(struct daemon* daemon)
return 0;
}
daemon->ports[0] = p0;
- if(reuseport) {
+ if(daemon->reuseport) {
/* continue to use reuseport */
for(i=1; i<daemon->num_ports; i++) {
if(!(daemon->ports[i]=
listening_ports_open(daemon->cfg,
- &reuseport)) || !reuseport ) {
+ &daemon->reuseport))
+ || !daemon->reuseport ) {
for(i=0; i<daemon->num_ports; i++)
listening_ports_free(daemon->ports[i]);
free(daemon->ports);
@@ -398,6 +401,17 @@ daemon_create_workers(struct daemon* daemon)
daemon->num = (daemon->cfg->num_threads?daemon->cfg->num_threads:1);
daemon->workers = (struct worker**)calloc((size_t)daemon->num,
sizeof(struct worker*));
+ 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,
@@ -448,7 +462,7 @@ thread_start(void* arg)
tube_close_write(worker->cmd);
close_other_pipes(worker->daemon, worker->thread_num);
#endif
-#if defined(__linux__) && defined(SO_REUSEPORT)
+#ifdef SO_REUSEPORT
if(worker->daemon->cfg->so_reuseport)
port_num = worker->thread_num;
else
@@ -582,6 +596,9 @@ daemon_cleanup(struct daemon* daemon)
free(daemon->workers);
daemon->workers = NULL;
daemon->num = 0;
+#ifdef USE_DNSTAP
+ dt_delete(daemon->dtenv);
+#endif
daemon->cfg = NULL;
}
diff --git a/contrib/unbound/daemon/daemon.h b/contrib/unbound/daemon/daemon.h
index 855b0d3..86ddab1 100644
--- a/contrib/unbound/daemon/daemon.h
+++ b/contrib/unbound/daemon/daemon.h
@@ -59,6 +59,11 @@ struct local_zones;
struct ub_randstate;
struct daemon_remote;
+#include "dnstap/dnstap_config.h"
+#ifdef USE_DNSTAP
+struct dt_env;
+#endif
+
/**
* Structure holding worker list.
* Holds globally visible information.
@@ -77,6 +82,8 @@ struct daemon {
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 */
@@ -107,6 +114,10 @@ struct daemon {
struct timeval time_last_stat;
/** time when daemon started */
struct timeval time_boot;
+#ifdef USE_DNSTAP
+ /** the dnstap environment master value, copied and changed by threads*/
+ struct dt_env* dtenv;
+#endif
};
/**
diff --git a/contrib/unbound/daemon/remote.c b/contrib/unbound/daemon/remote.c
index 6882e16..3ce55ee 100644
--- a/contrib/unbound/daemon/remote.c
+++ b/contrib/unbound/daemon/remote.c
@@ -38,14 +38,18 @@
*
* 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.
+ * 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
+#ifndef HEADER_DH_H
+#include <openssl/dh.h>
+#endif
+
#include <ctype.h>
#include "daemon/remote.h"
#include "daemon/worker.h"
@@ -82,6 +86,9 @@
#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
@@ -131,6 +138,41 @@ timeval_divide(struct timeval* avg, const struct timeval* sum, size_t d)
#endif
}
+/*
+ * The following function was generated using the openssl utility, using
+ * the command : "openssl dhparam -dsaparam -C 512"
+ */
+#ifndef S_SPLINT_S
+DH *get_dh512()
+{
+ static unsigned char dh512_p[]={
+ 0xC9,0xD7,0x05,0xDA,0x5F,0xAB,0x14,0xE8,0x11,0x56,0x77,0x85,
+ 0xB1,0x24,0x2C,0x95,0x60,0xEA,0xE2,0x10,0x6F,0x0F,0x84,0xEC,
+ 0xF4,0x45,0xE8,0x90,0x7A,0xA7,0x03,0xFF,0x5B,0x88,0x53,0xDE,
+ 0xC4,0xDE,0xBC,0x42,0x78,0x71,0x23,0x7E,0x24,0xA5,0x5E,0x4E,
+ 0xEF,0x6F,0xFF,0x5F,0xAF,0xBE,0x8A,0x77,0x62,0xB4,0x65,0x82,
+ 0x7E,0xC9,0xED,0x2F,
+ };
+ static unsigned char dh512_g[]={
+ 0x8D,0x3A,0x52,0xBC,0x8A,0x71,0x94,0x33,0x2F,0xE1,0xE8,0x4C,
+ 0x73,0x47,0x03,0x4E,0x7D,0x40,0xE5,0x84,0xA0,0xB5,0x6D,0x10,
+ 0x6F,0x90,0x43,0x05,0x1A,0xF9,0x0B,0x6A,0xD1,0x2A,0x9C,0x25,
+ 0x0A,0xB9,0xD1,0x14,0xDC,0x35,0x1C,0x48,0x7C,0xC6,0x0C,0x6D,
+ 0x32,0x1D,0xD3,0xC8,0x10,0xA8,0x82,0x14,0xA2,0x1C,0xF4,0x53,
+ 0x23,0x3B,0x1C,0xB9,
+ };
+ DH *dh;
+
+ if ((dh=DH_new()) == NULL) return(NULL);
+ dh->p=BN_bin2bn(dh512_p,sizeof(dh512_p),NULL);
+ dh->g=BN_bin2bn(dh512_g,sizeof(dh512_g),NULL);
+ if ((dh->p == NULL) || (dh->g == NULL))
+ { DH_free(dh); return(NULL); }
+ dh->length = 160;
+ return(dh);
+}
+#endif /* SPLINT */
+
struct daemon_remote*
daemon_remote_create(struct config_file* cfg)
{
@@ -154,12 +196,35 @@ daemon_remote_create(struct config_file* cfg)
free(rc);
return NULL;
}
- /* no SSLv2 because has defects */
+ /* no SSLv2, SSLv3 because has defects */
if(!(SSL_CTX_set_options(rc->ctx, 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)){
+ log_crypto_err("could not set SSL_OP_NO_SSLv3");
+ daemon_remote_delete(rc);
+ return NULL;
+ }
+
+ if (cfg->remote_control_use_cert == 0) {
+ /* No certificates are requested */
+ if(!SSL_CTX_set_cipher_list(rc->ctx, "aNULL")) {
+ log_crypto_err("Failed to set aNULL cipher list");
+ return NULL;
+ }
+
+ /* 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_dh512())) {
+ log_crypto_err("Wanted to set DH param, but failed");
+ return NULL;
+ }
+ 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) {
@@ -236,10 +301,12 @@ void daemon_remote_delete(struct daemon_remote* rc)
* @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)
+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;
@@ -250,29 +317,51 @@ add_open(const char* ip, int nr, struct listen_port** list, int noproto_is_err)
snprintf(port, sizeof(port), "%d", nr);
port[sizeof(port)-1]=0;
memset(&hints, 0, sizeof(hints));
- 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 */
+
+ if(ip[0] == '/') {
+ /* This looks like a local socket */
+ fd = create_local_accept_sock(ip, &noproto);
+ /*
+ * 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)
+ chown(ip, cfg_uid, cfg_gid);
+ 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),
+ 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):""
+ r==EAI_SYSTEM?(char*)strerror(errno):""
#else
- ""
+ ""
#endif
);
- return 0;
+ return 0;
+ }
+
+ /* open fd */
+ fd = create_tcp_accept_sock(res, 1, &noproto, 0);
+ freeaddrinfo(res);
}
- /* open fd */
- fd = create_tcp_accept_sock(res, 1, &noproto, 0);
- freeaddrinfo(res);
if(fd == -1 && noproto) {
if(!noproto_is_err)
return 1; /* return success, but do nothing */
@@ -309,7 +398,7 @@ struct listen_port* daemon_remote_open_ports(struct config_file* cfg)
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)) {
+ if(!add_open(p->str, cfg->control_port, &l, 1, cfg)) {
listening_ports_free(l);
return NULL;
}
@@ -317,12 +406,12 @@ struct listen_port* daemon_remote_open_ports(struct config_file* cfg)
} else {
/* defaults */
if(cfg->do_ip6 &&
- !add_open("::1", cfg->control_port, &l, 0)) {
+ !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)) {
+ !add_open("127.0.0.1", cfg->control_port, &l, 1, cfg)) {
listening_ports_free(l);
return NULL;
}
@@ -558,7 +647,7 @@ static char*
skipwhite(char* str)
{
/* EOS \0 is not a space */
- while( isspace(*str) )
+ while( isspace((unsigned char)*str) )
str++;
return str;
}
@@ -605,32 +694,32 @@ static int
print_stats(SSL* ssl, const char* nm, struct stats_info* s)
{
struct timeval avg;
- if(!ssl_printf(ssl, "%s.num.queries"SQ"%u\n", nm,
- (unsigned)s->svr.num_queries)) return 0;
- if(!ssl_printf(ssl, "%s.num.cachehits"SQ"%u\n", nm,
- (unsigned)(s->svr.num_queries
+ 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.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"%u\n", nm,
- (unsigned)s->svr.num_queries_missed_cache)) return 0;
- if(!ssl_printf(ssl, "%s.num.prefetch"SQ"%u\n", nm,
- (unsigned)s->svr.num_queries_prefetch)) return 0;
- if(!ssl_printf(ssl, "%s.num.recursivereplies"SQ"%u\n", nm,
- (unsigned)s->mesh_replies_sent)) 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.recursivereplies"SQ"%lu\n", nm,
+ (unsigned long)s->mesh_replies_sent)) return 0;
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"%u\n", nm,
- (unsigned)s->svr.max_query_list_size)) return 0;
- if(!ssl_printf(ssl, "%s.requestlist.overwritten"SQ"%u\n", nm,
- (unsigned)s->mesh_jostled)) return 0;
- if(!ssl_printf(ssl, "%s.requestlist.exceeded"SQ"%u\n", nm,
- (unsigned)s->mesh_dropped)) return 0;
- if(!ssl_printf(ssl, "%s.requestlist.current.all"SQ"%u\n", nm,
- (unsigned)s->mesh_num_states)) return 0;
- if(!ssl_printf(ssl, "%s.requestlist.current.user"SQ"%u\n", nm,
- (unsigned)s->mesh_num_reply_states)) 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;
@@ -660,7 +749,7 @@ print_longnum(SSL* ssl, const char* desc, size_t x)
return ssl_printf(ssl, "%s%u%6.6u\n", desc,
(unsigned)front, (unsigned)back);
} else {
- return ssl_printf(ssl, "%s%u\n", desc, (unsigned)x);
+ return ssl_printf(ssl, "%s%lu\n", desc, (unsigned long)x);
}
}
@@ -739,12 +828,12 @@ print_hist(SSL* ssl, struct stats_info* s)
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=%u\n",
+ "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)hist->buckets[i].count)) {
+ (unsigned long)hist->buckets[i].count)) {
timehist_delete(hist);
return 0;
}
@@ -781,12 +870,12 @@ print_ext(SSL* ssl, struct stats_info* s)
} else {
snprintf(nm, sizeof(nm), "TYPE%d", i);
}
- if(!ssl_printf(ssl, "num.query.type.%s"SQ"%u\n",
- nm, (unsigned)s->svr.qtype[i])) return 0;
+ 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"%u\n",
- (unsigned)s->svr.qtype_big)) return 0;
+ 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++) {
@@ -798,12 +887,12 @@ print_ext(SSL* ssl, struct stats_info* s)
} else {
snprintf(nm, sizeof(nm), "CLASS%d", i);
}
- if(!ssl_printf(ssl, "num.query.class.%s"SQ"%u\n",
- nm, (unsigned)s->svr.qclass[i])) return 0;
+ 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"%u\n",
- (unsigned)s->svr.qclass_big)) return 0;
+ 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++) {
@@ -815,39 +904,42 @@ print_ext(SSL* ssl, struct stats_info* s)
} else {
snprintf(nm, sizeof(nm), "OPCODE%d", i);
}
- if(!ssl_printf(ssl, "num.query.opcode.%s"SQ"%u\n",
- nm, (unsigned)s->svr.qopcode[i])) return 0;
+ 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"%u\n",
- (unsigned)s->svr.qtcp)) return 0;
- if(!ssl_printf(ssl, "num.query.ipv6"SQ"%u\n",
- (unsigned)s->svr.qipv6)) return 0;
+ 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"%u\n",
- (unsigned)s->svr.qbit_QR)) return 0;
- if(!ssl_printf(ssl, "num.query.flags.AA"SQ"%u\n",
- (unsigned)s->svr.qbit_AA)) return 0;
- if(!ssl_printf(ssl, "num.query.flags.TC"SQ"%u\n",
- (unsigned)s->svr.qbit_TC)) return 0;
- if(!ssl_printf(ssl, "num.query.flags.RD"SQ"%u\n",
- (unsigned)s->svr.qbit_RD)) return 0;
- if(!ssl_printf(ssl, "num.query.flags.RA"SQ"%u\n",
- (unsigned)s->svr.qbit_RA)) return 0;
- if(!ssl_printf(ssl, "num.query.flags.Z"SQ"%u\n",
- (unsigned)s->svr.qbit_Z)) return 0;
- if(!ssl_printf(ssl, "num.query.flags.AD"SQ"%u\n",
- (unsigned)s->svr.qbit_AD)) return 0;
- if(!ssl_printf(ssl, "num.query.flags.CD"SQ"%u\n",
- (unsigned)s->svr.qbit_CD)) return 0;
- if(!ssl_printf(ssl, "num.query.edns.present"SQ"%u\n",
- (unsigned)s->svr.qEDNS)) return 0;
- if(!ssl_printf(ssl, "num.query.edns.DO"SQ"%u\n",
- (unsigned)s->svr.qEDNS_DO)) return 0;
+ 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++) {
- if(inhibit_zero && s->svr.ans_rcode[i] == 0)
+ /* 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) {
@@ -855,25 +947,34 @@ print_ext(SSL* ssl, struct stats_info* s)
} else {
snprintf(nm, sizeof(nm), "RCODE%d", i);
}
- if(!ssl_printf(ssl, "num.answer.rcode.%s"SQ"%u\n",
- nm, (unsigned)s->svr.ans_rcode[i])) return 0;
+ 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"%u\n",
- (unsigned)s->svr.ans_rcode_nodata)) return 0;
+ 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"%u\n",
- (unsigned)s->svr.ans_secure)) return 0;
- if(!ssl_printf(ssl, "num.answer.bogus"SQ"%u\n",
- (unsigned)s->svr.ans_bogus)) return 0;
- if(!ssl_printf(ssl, "num.rrset.bogus"SQ"%u\n",
- (unsigned)s->svr.rrset_bogus)) return 0;
+ 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"%u\n",
- (unsigned)s->svr.unwanted_queries)) return 0;
- if(!ssl_printf(ssl, "unwanted.replies"SQ"%u\n",
- (unsigned)s->svr.unwanted_replies)) return 0;
+ 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;
}
@@ -1078,8 +1179,13 @@ do_cache_remove(struct worker* worker, uint8_t* nm, size_t nmlen,
k.qname_len = nmlen;
k.qtype = t;
k.qclass = c;
- h = query_info_hash(&k);
+ 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 */
@@ -1286,9 +1392,9 @@ do_flush_zone(SSL* ssl, struct worker* worker, char* arg)
free(nm);
- (void)ssl_printf(ssl, "ok removed %u rrsets, %u messages "
- "and %u key entries\n", (unsigned)inf.num_rrsets,
- (unsigned)inf.num_msgs, (unsigned)inf.num_keys);
+ (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 */
@@ -1330,7 +1436,7 @@ bogus_del_kcache(struct lruhash_entry* e, void* arg)
}
}
-/** remove all rrsets and keys from zone from cache */
+/** remove all bogus rrsets, msgs and keys from cache */
static void
do_flush_bogus(SSL* ssl, struct worker* worker)
{
@@ -1354,9 +1460,85 @@ do_flush_bogus(SSL* ssl, struct worker* worker)
&bogus_del_kcache, &inf);
}
- (void)ssl_printf(ssl, "ok removed %u rrsets, %u messages "
- "and %u key entries\n", (unsigned)inf.num_rrsets,
- (unsigned)inf.num_msgs, (unsigned)inf.num_keys);
+ (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.now = *worker->env.now;
+ 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 */
@@ -1395,7 +1577,7 @@ ssl_print_name_dp(SSL* ssl, const char* str, uint8_t* nm, uint16_t dclass,
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)) {
+ if(!ssl_printf(ssl, "%s %s %s ", buf, (c?c:"CLASS??"), str)) {
free(c);
return 0;
}
@@ -1730,6 +1912,10 @@ do_status(SSL* ssl, struct worker* worker)
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;
@@ -1852,6 +2038,9 @@ struct infra_arg {
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 */
@@ -1863,27 +2052,34 @@ dump_infra_host(struct lruhash_entry* e, void* arg)
struct infra_data* d = (struct infra_data*)e->data;
char ip_str[1024];
char name[257];
+ 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)) return;
+ name, d->rtt.rto)) {
+ a->ssl_failed = 1;
+ return;
+ }
}
return;
}
- if(!ssl_printf(a->ssl, "%s %s ttl %d ping %d var %d rtt %d rto %d "
+ 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, (int)(d->ttl - a->now),
+ "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))
+ (int)d->lame_other)) {
+ a->ssl_failed = 1;
return;
+ }
}
/** do the dump_infra command */
@@ -1894,6 +2090,7 @@ do_dump_infra(SSL* ssl, struct worker* worker)
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);
}
@@ -1946,10 +2143,23 @@ 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 */
- if(!ssl_print_name_dp(ssl, "forward", z->name, z->dclass,
- z->dp))
+
+ /* 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;
}
}
@@ -1959,9 +2169,24 @@ 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) {
- if(!ssl_print_name_dp(ssl,
- z->noprime?"stub noprime":"stub prime", z->node.name,
+
+ /* 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;
}
@@ -1978,8 +2203,13 @@ do_list_local_zones(SSL* ssl, struct worker* worker)
RBTREE_FOR(z, struct local_zone*, &zones->ztree) {
lock_rw_rdlock(&z->lock);
dname_str(z->name, buf);
- (void)ssl_printf(ssl, "%s %s\n", buf,
- local_zone_type2str(z->type));
+ 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);
@@ -2173,6 +2403,8 @@ execute_cmd(struct daemon_remote* rc, SSL* ssl, char* cmd,
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);
}
@@ -2286,7 +2518,9 @@ int remote_control_callback(struct comm_point* c, void* arg, int err,
s->shake_state = rc_none;
/* once handshake has completed, check authentication */
- if(SSL_get_verify_result(s->ssl) == X509_V_OK) {
+ 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 "
diff --git a/contrib/unbound/daemon/remote.h b/contrib/unbound/daemon/remote.h
index cc670b7..b25bfb1 100644
--- a/contrib/unbound/daemon/remote.h
+++ b/contrib/unbound/daemon/remote.h
@@ -89,6 +89,8 @@ struct daemon_remote {
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 */
diff --git a/contrib/unbound/daemon/stats.c b/contrib/unbound/daemon/stats.c
index 57ad1ef..d3f41de 100644
--- a/contrib/unbound/daemon/stats.c
+++ b/contrib/unbound/daemon/stats.c
@@ -56,6 +56,9 @@
#include "util/net_help.h"
#include "validator/validator.h"
#include "ldns/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
@@ -158,10 +161,19 @@ server_stats_compile(struct worker* worker, struct stats_info* s, int reset)
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;
+
if(reset && !worker->env.cfg->stat_cumulative) {
worker_stats_clear(worker);
}
@@ -217,6 +229,7 @@ void server_stats_add(struct stats_info* total, struct stats_info* a)
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;
diff --git a/contrib/unbound/daemon/stats.h b/contrib/unbound/daemon/stats.h
index 7c31551..5ea00a0 100644
--- a/contrib/unbound/daemon/stats.h
+++ b/contrib/unbound/daemon/stats.h
@@ -91,6 +91,8 @@ struct server_stats {
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 */
@@ -133,6 +135,15 @@ struct server_stats {
* 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;
};
/**
diff --git a/contrib/unbound/daemon/unbound.c b/contrib/unbound/daemon/unbound.c
index 716fbce..8e07c38 100644
--- a/contrib/unbound/daemon/unbound.c
+++ b/contrib/unbound/daemon/unbound.c
@@ -84,7 +84,13 @@
# include "util/mini_event.h"
# endif
#else
-# include <event.h>
+# ifdef HAVE_EVENT_H
+# include <event.h>
+# else
+# include "event2/event.h"
+# include "event2/event_struct.h"
+# include "event2/event_compat.h"
+# endif
#endif
#ifdef UB_ON_WINDOWS
@@ -263,8 +269,6 @@ checkrlimits(struct config_file* cfg)
#ifdef HAVE_SETRLIMIT
if(setrlimit(RLIMIT_NOFILE, &rlim) < 0) {
log_warn("setrlimit: %s", strerror(errno));
-#else
- if(1) {
#endif
log_warn("cannot increase max open fds from %u to %u",
(unsigned)avail, (unsigned)total+10);
@@ -280,8 +284,10 @@ checkrlimits(struct config_file* cfg)
log_warn("increase ulimit or decrease threads, "
"ports in config to remove this warning");
return;
+#ifdef HAVE_SETRLIMIT
}
- log_warn("increased limit(open files) from %u to %u",
+#endif
+ verbose(VERB_ALGO, "increased limit(open files) from %u to %u",
(unsigned)avail, (unsigned)total+10);
}
#else
@@ -293,10 +299,14 @@ checkrlimits(struct config_file* cfg)
/** set verbosity, check rlimits, cache settings */
static void
apply_settings(struct daemon* daemon, struct config_file* cfg,
- int cmdline_verbose)
+ int cmdline_verbose, int debug_mode)
{
/* apply if they have changed */
verbosity = cmdline_verbose + cfg->verbosity;
+ if (debug_mode > 1) {
+ cfg->use_syslog = 0;
+ cfg->logfile = NULL;
+ }
daemon_apply_cfg(daemon, cfg);
checkrlimits(cfg);
}
@@ -433,18 +443,10 @@ perform_setup(struct daemon* daemon, struct config_file* cfg, int debug_mode,
{
#ifdef HAVE_GETPWNAM
struct passwd *pwd = NULL;
- uid_t uid;
- gid_t gid;
- /* initialize, but not to 0 (root) */
- memset(&uid, 112, sizeof(uid));
- memset(&gid, 112, sizeof(gid));
- log_assert(cfg);
if(cfg->username && cfg->username[0]) {
if((pwd = getpwnam(cfg->username)) == NULL)
fatal_exit("user '%s' does not exist.", cfg->username);
- uid = pwd->pw_uid;
- gid = pwd->pw_gid;
/* endpwent below, in case we need pwd for setusercontext */
}
#endif
@@ -501,33 +503,28 @@ perform_setup(struct daemon* daemon, struct config_file* cfg, int debug_mode,
#ifdef HAVE_KILL
if(cfg->pidfile && cfg->pidfile[0]) {
writepid(daemon->pidfile, getpid());
- if(!(cfg->chrootdir && cfg->chrootdir[0]) ||
- (cfg->chrootdir && cfg->chrootdir[0] &&
- strncmp(daemon->pidfile, cfg->chrootdir,
- strlen(cfg->chrootdir))==0)) {
- /* delete of pidfile could potentially work,
- * chown to get permissions */
- if(cfg->username && cfg->username[0]) {
- if(chown(daemon->pidfile, uid, gid) == -1) {
+ if(cfg->username && cfg->username[0] && cfg_uid != (uid_t)-1) {
+# ifdef HAVE_CHOWN
+ if(chown(daemon->pidfile, cfg_uid, cfg_gid) == -1) {
log_err("cannot chown %u.%u %s: %s",
- (unsigned)uid, (unsigned)gid,
+ (unsigned)cfg_uid, (unsigned)cfg_gid,
daemon->pidfile, strerror(errno));
- }
}
+# endif /* HAVE_CHOWN */
}
}
#else
(void)daemon;
-#endif
+#endif /* HAVE_KILL */
/* Set user context */
#ifdef HAVE_GETPWNAM
- if(cfg->username && cfg->username[0]) {
+ 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, uid, (unsigned)
+ 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));
@@ -589,29 +586,29 @@ perform_setup(struct daemon* daemon, struct config_file* cfg, int debug_mode,
/* drop permissions after chroot, getpwnam, pidfile, syslog done*/
#ifdef HAVE_GETPWNAM
- if(cfg->username && cfg->username[0]) {
+ if(cfg->username && cfg->username[0] && cfg_uid != (uid_t)-1) {
# ifdef HAVE_INITGROUPS
- if(initgroups(cfg->username, gid) != 0)
+ if(initgroups(cfg->username, cfg_gid) != 0)
log_warn("unable to initgroups %s: %s",
cfg->username, strerror(errno));
# endif /* HAVE_INITGROUPS */
endpwent();
#ifdef HAVE_SETRESGID
- if(setresgid(gid,gid,gid) != 0)
+ if(setresgid(cfg_gid,cfg_gid,cfg_gid) != 0)
#elif defined(HAVE_SETREGID) && !defined(DARWIN_BROKEN_SETREUID)
- if(setregid(gid,gid) != 0)
+ if(setregid(cfg_gid,cfg_gid) != 0)
#else /* use setgid */
- if(setgid(gid) != 0)
+ 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(uid,uid,uid) != 0)
+ if(setresuid(cfg_uid,cfg_uid,cfg_uid) != 0)
#elif defined(HAVE_SETREUID) && !defined(DARWIN_BROKEN_SETREUID)
- if(setreuid(uid,uid) != 0)
+ if(setreuid(cfg_uid,cfg_uid) != 0)
#else /* use setuid */
- if(setuid(uid) != 0)
+ if(setuid(cfg_uid) != 0)
#endif /* HAVE_SETRESUID */
fatal_exit("unable to set user id of %s: %s",
cfg->username, strerror(errno));
@@ -655,7 +652,9 @@ run_daemon(const char* cfgfile, int cmdline_verbose, int debug_mode)
cfgfile);
log_warn("Continuing with default config settings");
}
- apply_settings(daemon, cfg, cmdline_verbose);
+ apply_settings(daemon, cfg, cmdline_verbose, debug_mode);
+ if(!done_setup)
+ config_lookup_uid(cfg);
/* prepare */
if(!daemon_open_shared_ports(daemon))
@@ -735,7 +734,7 @@ main(int argc, char* argv[])
verbosity++;
break;
case 'd':
- debug_mode = 1;
+ debug_mode++;
break;
case 'w':
winopt = optarg;
diff --git a/contrib/unbound/daemon/worker.c b/contrib/unbound/daemon/worker.c
index ccc45f6..5edc21d 100644
--- a/contrib/unbound/daemon/worker.c
+++ b/contrib/unbound/daemon/worker.c
@@ -777,16 +777,24 @@ worker_handle_request(struct comm_point* c, void* arg, int error,
struct query_info qinfo;
struct edns_data edns;
enum acl_access acl;
+ int rc = 0;
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_DNSTAP
+ if(worker->dtenv.log_client_query_messages)
+ dt_msg_send_client_query(&worker->dtenv, &repinfo->addr, c->type,
+ c->buffer);
+#endif
acl = acl_list_lookup(worker->daemon->acl, &repinfo->addr,
repinfo->addrlen);
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) {
@@ -810,7 +818,7 @@ worker_handle_request(struct comm_point* c, void* arg, int error,
LDNS_RCODE_SET(sldns_buffer_begin(c->buffer),
LDNS_RCODE_FORMERR);
server_stats_insrcode(&worker->stats, c->buffer);
- return 1;
+ goto send_reply;
}
if(worker->env.cfg->log_queries) {
char ip[128];
@@ -829,7 +837,7 @@ worker_handle_request(struct comm_point* c, void* arg, int error,
worker->stats.qtype[qinfo.qtype]++;
server_stats_insrcode(&worker->stats, c->buffer);
}
- return 1;
+ goto send_reply;
}
if((ret=parse_edns_from_pkt(c->buffer, &edns)) != 0) {
verbose(VERB_ALGO, "worker parse edns: formerror.");
@@ -838,7 +846,7 @@ worker_handle_request(struct comm_point* c, void* arg, int error,
LDNS_QR_SET(sldns_buffer_begin(c->buffer));
LDNS_RCODE_SET(sldns_buffer_begin(c->buffer), ret);
server_stats_insrcode(&worker->stats, c->buffer);
- return 1;
+ goto send_reply;
}
if(edns.edns_present && edns.edns_version != 0) {
edns.ext_rcode = (uint8_t)(EDNS_RCODE_BADVERS>>4);
@@ -848,10 +856,10 @@ worker_handle_request(struct comm_point* c, void* arg, int error,
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),
+ *(uint16_t*)(void *)sldns_buffer_begin(c->buffer),
sldns_buffer_read_u16_at(c->buffer, 2), NULL);
attach_edns_record(c->buffer, &edns);
- return 1;
+ goto send_reply;
}
if(edns.edns_present && edns.udp_size < NORMAL_UDP_SIZE &&
worker->daemon->cfg->harden_short_bufsize) {
@@ -879,7 +887,7 @@ worker_handle_request(struct comm_point* c, void* arg, int error,
sldns_buffer_write_at(c->buffer, 4,
(uint8_t*)"\0\0\0\0\0\0\0\0", 8);
sldns_buffer_flip(c->buffer);
- return 1;
+ goto send_reply;
}
if(worker->stats.extended)
server_stats_insquery(&worker->stats, c, qinfo.qtype,
@@ -889,23 +897,25 @@ worker_handle_request(struct comm_point* c, void* arg, int error,
if(qinfo.qclass == LDNS_RR_CLASS_CH && answer_chaos(worker, &qinfo,
&edns, c->buffer)) {
server_stats_insrcode(&worker->stats, c->buffer);
- return 1;
+ goto send_reply;
}
if(local_zones_answer(worker->daemon->local_zones, &qinfo, &edns,
- c->buffer, worker->scratchpad)) {
+ c->buffer, worker->scratchpad, repinfo)) {
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);
- return 1;
+ 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)
{
+ if(ret == 1)
+ goto send_reply;
return ret;
}
@@ -923,9 +933,9 @@ worker_handle_request(struct comm_point* c, void* arg, int error,
server_stats_insrcode(&worker->stats, c->buffer);
log_addr(VERB_ALGO, "refused nonrec (cache snoop) query from",
&repinfo->addr, repinfo->addrlen);
- return 1;
+ goto send_reply;
}
- h = query_info_hash(&qinfo);
+ h = query_info_hash(&qinfo, sldns_buffer_read_u16_at(c->buffer, 2));
if((e=slabhash_lookup(worker->env.msg_cache, h, &qinfo, 0))) {
/* answer from cache - we have acquired a readlock on it */
if(answer_from_cache(worker, &qinfo,
@@ -942,10 +952,11 @@ worker_handle_request(struct comm_point* c, void* arg, int error,
reply_and_prefetch(worker, &qinfo,
sldns_buffer_read_u16_at(c->buffer, 2),
repinfo, leeway);
- return 0;
+ rc = 0;
+ goto send_reply_rc;
}
lock_rw_unlock(&e->lock);
- return 1;
+ goto send_reply;
}
verbose(VERB_ALGO, "answer from the cache failed");
lock_rw_unlock(&e->lock);
@@ -955,7 +966,7 @@ worker_handle_request(struct comm_point* c, void* arg, int error,
*(uint16_t*)(void *)sldns_buffer_begin(c->buffer),
sldns_buffer_read_u16_at(c->buffer, 2), repinfo,
&edns)) {
- return 1;
+ goto send_reply;
}
verbose(VERB_ALGO, "answer norec from cache -- "
"need to validate or not primed");
@@ -974,45 +985,49 @@ worker_handle_request(struct comm_point* c, void* arg, int error,
/* grab a work request structure for this new request */
mesh_new_client(worker->env.mesh, &qinfo,
sldns_buffer_read_u16_at(c->buffer, 2),
- &edns, repinfo, *(uint16_t*)(void *)sldns_buffer_begin(c->buffer));
+ &edns, repinfo, *(uint16_t*)(void *)sldns_buffer_begin(c->buffer));
worker_mem_report(worker, NULL);
return 0;
+
+send_reply:
+ rc = 1;
+send_reply_rc:
+#ifdef USE_DNSTAP
+ if(worker->dtenv.log_client_response_messages)
+ dt_msg_send_client_response(&worker->dtenv, &repinfo->addr,
+ c->type, c->buffer);
+#endif
+ return rc;
}
void
worker_sighandler(int sig, void* arg)
{
- /* note that log, print, syscalls here give race conditions. */
- /* we still print DETAIL logs, because this is extensive per message
- * logging anyway, and the operator may then have an interest
- * in the cause for unbound to exit */
+ /* 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:
- verbose(VERB_QUERY, "caught signal SIGHUP");
comm_base_exit(worker->base);
break;
#endif
case SIGINT:
- verbose(VERB_QUERY, "caught signal SIGINT");
worker->need_to_exit = 1;
comm_base_exit(worker->base);
break;
#ifdef SIGQUIT
case SIGQUIT:
- verbose(VERB_QUERY, "caught signal SIGQUIT");
worker->need_to_exit = 1;
comm_base_exit(worker->base);
break;
#endif
case SIGTERM:
- verbose(VERB_QUERY, "caught signal SIGTERM");
worker->need_to_exit = 1;
comm_base_exit(worker->base);
break;
default:
- log_err("unknown signal: %d, ignored", sig);
+ /* unknown signal, ignored */
break;
}
}
@@ -1090,6 +1105,14 @@ worker_create(struct daemon* daemon, int id, int* ports, int n)
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;
}
@@ -1097,6 +1120,11 @@ 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) {
@@ -1145,7 +1173,8 @@ worker_init(struct worker* worker, struct config_file *cfg,
}
worker->front = listen_create(worker->base, ports,
cfg->msg_buffer_size, (int)cfg->incoming_num_tcp,
- worker->daemon->listen_sslctx, worker_handle_request, worker);
+ worker->daemon->listen_sslctx, dtenv, worker_handle_request,
+ worker);
if(!worker->front) {
log_err("could not create listening sockets");
worker_delete(worker);
@@ -1158,7 +1187,8 @@ worker_init(struct worker* worker, struct config_file *cfg,
worker->daemon->env->infra_cache, worker->rndstate,
cfg->use_caps_bits_for_id, worker->ports, worker->numports,
cfg->unwanted_threshold, &worker_alloc_cleanup, worker,
- cfg->do_udp, worker->daemon->connect_sslctx, cfg->delay_close);
+ cfg->do_udp, worker->daemon->connect_sslctx, cfg->delay_close,
+ dtenv);
if(!worker->back) {
log_err("could not create outgoing sockets");
worker_delete(worker);
@@ -1293,8 +1323,8 @@ worker_delete(struct worker* worker)
struct outbound_entry*
worker_send_query(uint8_t* qname, size_t qnamelen, uint16_t qtype,
uint16_t qclass, uint16_t flags, int dnssec, int want_dnssec,
- struct sockaddr_storage* addr, socklen_t addrlen, uint8_t* zone,
- size_t zonelen, struct module_qstate* q)
+ int nocaps, struct sockaddr_storage* addr, socklen_t addrlen,
+ uint8_t* zone, size_t zonelen, struct module_qstate* q)
{
struct worker* worker = q->env->worker;
struct outbound_entry* e = (struct outbound_entry*)regional_alloc(
@@ -1303,7 +1333,7 @@ worker_send_query(uint8_t* qname, size_t qnamelen, uint16_t qtype,
return NULL;
e->qstate = q;
e->qsent = outnet_serviced_query(worker->back, qname,
- qnamelen, qtype, qclass, flags, dnssec, want_dnssec,
+ qnamelen, qtype, qclass, flags, dnssec, want_dnssec, nocaps,
q->env->cfg->tcp_upstream, q->env->cfg->ssl_upstream, addr,
addrlen, zone, zonelen, worker_handle_service_reply, e,
worker->back->udp_buff);
@@ -1326,6 +1356,7 @@ 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)
@@ -1349,7 +1380,7 @@ struct outbound_entry* libworker_send_query(uint8_t* ATTR_UNUSED(qname),
size_t ATTR_UNUSED(qnamelen), uint16_t ATTR_UNUSED(qtype),
uint16_t ATTR_UNUSED(qclass), uint16_t ATTR_UNUSED(flags),
int ATTR_UNUSED(dnssec), int ATTR_UNUSED(want_dnssec),
- struct sockaddr_storage* ATTR_UNUSED(addr),
+ int ATTR_UNUSED(nocaps), struct sockaddr_storage* ATTR_UNUSED(addr),
socklen_t ATTR_UNUSED(addrlen), uint8_t* ATTR_UNUSED(zone),
size_t ATTR_UNUSED(zonelen), struct module_qstate* ATTR_UNUSED(q))
{
diff --git a/contrib/unbound/daemon/worker.h b/contrib/unbound/daemon/worker.h
index 83503ae..ff69bc1 100644
--- a/contrib/unbound/daemon/worker.h
+++ b/contrib/unbound/daemon/worker.h
@@ -51,6 +51,7 @@
#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;
@@ -116,6 +117,11 @@ struct worker {
/** 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
};
/**
OpenPOWER on IntegriCloud