summaryrefslogtreecommitdiff
path: root/daemon
diff options
context:
space:
mode:
authorDag-Erling Smørgrav <des@FreeBSD.org>2018-05-12 11:56:52 +0000
committerDag-Erling Smørgrav <des@FreeBSD.org>2018-05-12 11:56:52 +0000
commit4289761a7b61df4b64c11ada446a187df61e6a1e (patch)
treeed7ceb7a1652fb9f865fafd21fbe18d1a3b5f79d /daemon
parent197f1a0fe3e81cde0cd25a3a1f37ebedf9a99488 (diff)
Diffstat (limited to 'daemon')
-rw-r--r--daemon/daemon.c2
-rw-r--r--daemon/remote.c56
-rw-r--r--daemon/stats.c45
-rw-r--r--daemon/worker.c84
4 files changed, 178 insertions, 9 deletions
diff --git a/daemon/daemon.c b/daemon/daemon.c
index f68bd981b01b..85ae1e0a15ac 100644
--- a/daemon/daemon.c
+++ b/daemon/daemon.c
@@ -706,9 +706,11 @@ daemon_cleanup(struct daemon* daemon)
daemon->num = 0;
#ifdef USE_DNSTAP
dt_delete(daemon->dtenv);
+ daemon->dtenv = NULL;
#endif
#ifdef USE_DNSCRYPT
dnsc_delete(daemon->dnscenv);
+ daemon->dnscenv = NULL;
#endif
daemon->cfg = NULL;
}
diff --git a/daemon/remote.c b/daemon/remote.c
index 3477340ff578..cfc91eb98b3a 100644
--- a/daemon/remote.c
+++ b/daemon/remote.c
@@ -68,6 +68,7 @@
#include "services/cache/infra.h"
#include "services/mesh.h"
#include "services/localzone.h"
+#include "services/authzone.h"
#include "util/storage/slabhash.h"
#include "util/fptr_wlist.h"
#include "util/data/dname.h"
@@ -236,10 +237,15 @@ daemon_remote_create(struct config_file* cfg)
if (cfg->remote_control_use_cert == 0) {
/* No certificates are requested */
+#if defined(SSL_OP_NO_TLSv1_3)
+ /* in openssl 1.1.1, negotiation code for tls 1.3 does
+ * not allow the unauthenticated aNULL and eNULL ciphers */
+ SSL_CTX_set_options(rc->ctx, SSL_OP_NO_TLSv1_3);
+#endif
#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")) {
+ 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;
@@ -1046,6 +1052,10 @@ print_ext(SSL* ssl, struct ub_stats_info* s)
(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;
+ if(!ssl_printf(ssl, "num.query.aggressive.NOERROR"SQ"%lu\n",
+ (unsigned long)s->svr.num_neg_cache_noerror)) return 0;
+ if(!ssl_printf(ssl, "num.query.aggressive.NXDOMAIN"SQ"%lu\n",
+ (unsigned long)s->svr.num_neg_cache_nxdomain)) return 0;
/* threat detection */
if(!ssl_printf(ssl, "unwanted.queries"SQ"%lu\n",
(unsigned long)s->svr.unwanted_queries)) return 0;
@@ -1070,6 +1080,10 @@ print_ext(SSL* ssl, struct ub_stats_info* s)
if(!ssl_printf(ssl, "num.query.dnscrypt.replay"SQ"%lu\n",
(unsigned long)s->svr.num_query_dnscrypt_replay)) return 0;
#endif /* USE_DNSCRYPT */
+ if(!ssl_printf(ssl, "num.query.authzone.up"SQ"%lu\n",
+ (unsigned long)s->svr.num_query_authzone_up)) return 0;
+ if(!ssl_printf(ssl, "num.query.authzone.down"SQ"%lu\n",
+ (unsigned long)s->svr.num_query_authzone_down)) return 0;
return 1;
}
@@ -1644,6 +1658,7 @@ zone_del_msg(struct lruhash_entry* e, void* arg)
struct reply_info* d = (struct reply_info*)e->data;
if(d->ttl > inf->expired) {
d->ttl = inf->expired;
+ d->prefetch_ttl = inf->expired;
inf->num_msgs++;
}
}
@@ -1927,6 +1942,7 @@ parse_delegpt(SSL* ssl, char* args, uint8_t* nm, int allow_names)
struct delegpt* dp = delegpt_create_mlc(nm);
struct sockaddr_storage addr;
socklen_t addrlen;
+ char* auth_name;
if(!dp) {
(void)ssl_printf(ssl, "error out of memory\n");
return NULL;
@@ -1939,7 +1955,7 @@ parse_delegpt(SSL* ssl, char* args, uint8_t* nm, int allow_names)
p = skipwhite(p); /* position at next spot */
}
/* parse address */
- if(!extstrtoaddr(todo, &addr, &addrlen)) {
+ if(!authextstrtoaddr(todo, &addr, &addrlen, &auth_name)) {
if(allow_names) {
uint8_t* n = NULL;
size_t ln;
@@ -1967,7 +1983,8 @@ parse_delegpt(SSL* ssl, char* args, uint8_t* nm, int allow_names)
}
} else {
/* add address */
- if(!delegpt_add_addr_mlc(dp, &addr, addrlen, 0, 0)) {
+ if(!delegpt_add_addr_mlc(dp, &addr, addrlen, 0, 0,
+ auth_name)) {
(void)ssl_printf(ssl, "error out of memory\n");
delegpt_free_mlc(dp);
return NULL;
@@ -2527,6 +2544,36 @@ do_list_stubs(SSL* ssl, struct worker* worker)
}
}
+/** do the list_auth_zones command */
+static void
+do_list_auth_zones(SSL* ssl, struct auth_zones* az)
+{
+ struct auth_zone* z;
+ char buf[257], buf2[256];
+ lock_rw_rdlock(&az->lock);
+ RBTREE_FOR(z, struct auth_zone*, &az->ztree) {
+ lock_rw_rdlock(&z->lock);
+ dname_str(z->name, buf);
+ if(z->zone_expired)
+ snprintf(buf2, sizeof(buf2), "expired");
+ else {
+ uint32_t serial = 0;
+ if(auth_zone_get_serial(z, &serial))
+ snprintf(buf2, sizeof(buf2), "serial %u",
+ (unsigned)serial);
+ else snprintf(buf2, sizeof(buf2), "no serial");
+ }
+ if(!ssl_printf(ssl, "%s\t%s\n", buf, buf2)) {
+ /* failure to print */
+ lock_rw_unlock(&z->lock);
+ lock_rw_unlock(&az->lock);
+ return;
+ }
+ lock_rw_unlock(&z->lock);
+ }
+ lock_rw_unlock(&az->lock);
+}
+
/** do the list_local_zones command */
static void
do_list_local_zones(SSL* ssl, struct local_zones* zones)
@@ -2787,6 +2834,9 @@ execute_cmd(struct daemon_remote* rc, SSL* ssl, char* cmd,
} else if(cmdcmp(p, "ip_ratelimit_list", 17)) {
do_ip_ratelimit_list(ssl, worker, p+17);
return;
+ } else if(cmdcmp(p, "list_auth_zones", 15)) {
+ do_list_auth_zones(ssl, worker->env.auth_zones);
+ return;
} else if(cmdcmp(p, "stub_add", 8)) {
/* must always distribute this cmd */
if(rc) distribute_cmd(rc, ssl, cmd);
diff --git a/daemon/stats.c b/daemon/stats.c
index ed788720846a..6f4feaaad9d0 100644
--- a/daemon/stats.c
+++ b/daemon/stats.c
@@ -60,7 +60,9 @@
#include "sldns/sbuffer.h"
#include "services/cache/rrset.h"
#include "services/cache/infra.h"
+#include "services/authzone.h"
#include "validator/val_kcache.h"
+#include "validator/val_neg.h"
/** add timers and the values do not overflow or become negative */
static void
@@ -122,6 +124,30 @@ void server_stats_log(struct ub_server_stats* stats, struct worker* worker,
(unsigned)worker->env.mesh->stats_jostled);
}
+/** Set the neg cache stats. */
+static void
+set_neg_cache_stats(struct worker* worker, struct ub_server_stats* svr,
+ int reset)
+{
+ int m = modstack_find(&worker->env.mesh->mods, "validator");
+ struct val_env* ve;
+ struct val_neg_cache* neg;
+ if(m == -1)
+ return;
+ ve = (struct val_env*)worker->env.modinfo[m];
+ if(!ve->neg_cache)
+ return;
+ neg = ve->neg_cache;
+ lock_basic_lock(&neg->lock);
+ svr->num_neg_cache_noerror = (long long)neg->num_neg_cache_noerror;
+ svr->num_neg_cache_nxdomain = (long long)neg->num_neg_cache_nxdomain;
+ if(reset && !worker->env.cfg->stat_cumulative) {
+ neg->num_neg_cache_noerror = 0;
+ neg->num_neg_cache_nxdomain = 0;
+ }
+ lock_basic_unlock(&neg->lock);
+}
+
/** get rrsets bogus number from validator */
static size_t
get_rrset_bogus(struct worker* worker, int reset)
@@ -256,6 +282,25 @@ server_stats_compile(struct worker* worker, struct ub_stats_info* s, int reset)
s->svr.nonce_cache_count = 0;
s->svr.num_query_dnscrypt_replay = 0;
#endif /* USE_DNSCRYPT */
+ if(worker->env.auth_zones) {
+ if(reset && !worker->env.cfg->stat_cumulative) {
+ lock_rw_wrlock(&worker->env.auth_zones->lock);
+ } else {
+ lock_rw_rdlock(&worker->env.auth_zones->lock);
+ }
+ s->svr.num_query_authzone_up = (long long)worker->env.
+ auth_zones->num_query_up;
+ s->svr.num_query_authzone_down = (long long)worker->env.
+ auth_zones->num_query_down;
+ if(reset && !worker->env.cfg->stat_cumulative) {
+ worker->env.auth_zones->num_query_up = 0;
+ worker->env.auth_zones->num_query_down = 0;
+ }
+ lock_rw_unlock(&worker->env.auth_zones->lock);
+ }
+
+ /* Set neg cache usage numbers */
+ set_neg_cache_stats(worker, &s->svr, reset);
/* get tcp accept usage */
s->svr.tcp_accept_usage = 0;
diff --git a/daemon/worker.c b/daemon/worker.c
index 389a1de530ec..6121c7dbe363 100644
--- a/daemon/worker.c
+++ b/daemon/worker.c
@@ -342,7 +342,8 @@ worker_check_request(sldns_buffer* pkt, struct worker* worker)
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) {
+ if(LDNS_OPCODE_WIRE(sldns_buffer_begin(pkt)) != LDNS_PACKET_QUERY &&
+ LDNS_OPCODE_WIRE(sldns_buffer_begin(pkt)) != LDNS_PACKET_NOTIFY) {
verbose(VERB_QUERY, "request unknown opcode %d",
LDNS_OPCODE_WIRE(sldns_buffer_begin(pkt)));
return worker_err_ratelimit(worker, LDNS_RCODE_NOTIMPL);
@@ -352,7 +353,9 @@ worker_check_request(sldns_buffer* pkt, struct worker* worker)
LDNS_QDCOUNT(sldns_buffer_begin(pkt)));
return worker_err_ratelimit(worker, LDNS_RCODE_FORMERR);
}
- if(LDNS_ANCOUNT(sldns_buffer_begin(pkt)) != 0) {
+ if(LDNS_ANCOUNT(sldns_buffer_begin(pkt)) != 0 &&
+ (LDNS_ANCOUNT(sldns_buffer_begin(pkt)) != 1 ||
+ LDNS_OPCODE_WIRE(sldns_buffer_begin(pkt)) != LDNS_PACKET_NOTIFY)) {
verbose(VERB_QUERY, "request wrong nr an=%d",
LDNS_ANCOUNT(sldns_buffer_begin(pkt)));
return worker_err_ratelimit(worker, LDNS_RCODE_FORMERR);
@@ -499,6 +502,7 @@ answer_norec_from_cache(struct worker* worker, struct query_info* qinfo,
* let validator do that */
return 0;
case sec_status_bogus:
+ case sec_status_secure_sentinel_fail:
/* some rrsets are bogus, reply servfail */
edns->edns_version = EDNS_ADVERTISED_VERSION;
edns->udp_size = EDNS_ADVERTISED_SIZE;
@@ -655,7 +659,8 @@ answer_from_cache(struct worker* worker, struct query_info* qinfo,
}
}
/* check security status of the cached answer */
- if( rep->security == sec_status_bogus && must_validate) {
+ if(must_validate && (rep->security == sec_status_bogus ||
+ rep->security == sec_status_secure_sentinel_fail)) {
/* BAD cached */
edns->edns_version = EDNS_ADVERTISED_VERSION;
edns->udp_size = EDNS_ADVERTISED_SIZE;
@@ -940,6 +945,66 @@ answer_chaos(struct worker* w, struct query_info* qinfo,
return 0;
}
+/**
+ * Answer notify queries. These are notifies for authoritative zones,
+ * the reply is an ack that the notify has been received. We need to check
+ * access permission here.
+ * @param w: worker
+ * @param qinfo: query info. Pointer into packet buffer.
+ * @param edns: edns info from query.
+ * @param repinfo: reply info with source address.
+ * @param pkt: packet buffer.
+ */
+static void
+answer_notify(struct worker* w, struct query_info* qinfo,
+ struct edns_data* edns, sldns_buffer* pkt, struct comm_reply* repinfo)
+{
+ int refused = 0;
+ int rcode = LDNS_RCODE_NOERROR;
+ uint32_t serial = 0;
+ int has_serial;
+ if(!w->env.auth_zones) return;
+ has_serial = auth_zone_parse_notify_serial(pkt, &serial);
+ if(auth_zones_notify(w->env.auth_zones, &w->env, qinfo->qname,
+ qinfo->qname_len, qinfo->qclass, &repinfo->addr,
+ repinfo->addrlen, has_serial, serial, &refused)) {
+ rcode = LDNS_RCODE_NOERROR;
+ } else {
+ if(refused)
+ rcode = LDNS_RCODE_REFUSED;
+ else rcode = LDNS_RCODE_SERVFAIL;
+ }
+
+ if(verbosity >= VERB_DETAIL) {
+ char buf[380];
+ char zname[255+1];
+ char sr[25];
+ dname_str(qinfo->qname, zname);
+ sr[0]=0;
+ if(has_serial)
+ snprintf(sr, sizeof(sr), "serial %u ",
+ (unsigned)serial);
+ if(rcode == LDNS_RCODE_REFUSED)
+ snprintf(buf, sizeof(buf),
+ "refused NOTIFY %sfor %s from", sr, zname);
+ else if(rcode == LDNS_RCODE_SERVFAIL)
+ snprintf(buf, sizeof(buf),
+ "servfail for NOTIFY %sfor %s from", sr, zname);
+ else snprintf(buf, sizeof(buf),
+ "received NOTIFY %sfor %s from", sr, zname);
+ log_addr(VERB_DETAIL, buf, &repinfo->addr, repinfo->addrlen);
+ }
+ edns->edns_version = EDNS_ADVERTISED_VERSION;
+ edns->udp_size = EDNS_ADVERTISED_SIZE;
+ edns->ext_rcode = 0;
+ edns->bits &= EDNS_DO;
+ edns->opt_list = NULL;
+ error_encode(pkt, rcode, qinfo,
+ *(uint16_t*)(void *)sldns_buffer_begin(pkt),
+ sldns_buffer_read_u16_at(pkt, 2), edns);
+ LDNS_OPCODE_SET(sldns_buffer_begin(pkt), LDNS_PACKET_NOTIFY);
+}
+
static int
deny_refuse(struct comm_point* c, enum acl_access acl,
enum acl_access deny, enum acl_access refuse,
@@ -1238,6 +1303,12 @@ worker_handle_request(struct comm_point* c, void* arg, int error,
regional_free_all(worker->scratchpad);
goto send_reply;
}
+ if(LDNS_OPCODE_WIRE(sldns_buffer_begin(c->buffer)) ==
+ LDNS_PACKET_NOTIFY) {
+ answer_notify(worker, &qinfo, &edns, c->buffer, repinfo);
+ 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,
@@ -1806,7 +1877,7 @@ 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)
+ char* tls_auth_name, struct module_qstate* q)
{
struct worker* worker = q->env->worker;
struct outbound_entry* e = (struct outbound_entry*)regional_alloc(
@@ -1816,7 +1887,7 @@ worker_send_query(struct query_info* qinfo, uint16_t flags, int dnssec,
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,
+ ssl_upstream, tls_auth_name, addr, addrlen, zone, zonelen, q,
worker_handle_service_reply, e, worker->back->udp_buff, q->env);
if(!e->qsent) {
return NULL;
@@ -1863,7 +1934,8 @@ struct outbound_entry* libworker_send_query(
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))
+ int ATTR_UNUSED(ssl_upstream), char* ATTR_UNUSED(tls_auth_name),
+ struct module_qstate* ATTR_UNUSED(q))
{
log_assert(0);
return 0;