diff options
| author | Dag-Erling Smørgrav <des@FreeBSD.org> | 2018-05-12 11:56:52 +0000 |
|---|---|---|
| committer | Dag-Erling Smørgrav <des@FreeBSD.org> | 2018-05-12 11:56:52 +0000 |
| commit | 4289761a7b61df4b64c11ada446a187df61e6a1e (patch) | |
| tree | ed7ceb7a1652fb9f865fafd21fbe18d1a3b5f79d /daemon | |
| parent | 197f1a0fe3e81cde0cd25a3a1f37ebedf9a99488 (diff) | |
Diffstat (limited to 'daemon')
| -rw-r--r-- | daemon/daemon.c | 2 | ||||
| -rw-r--r-- | daemon/remote.c | 56 | ||||
| -rw-r--r-- | daemon/stats.c | 45 | ||||
| -rw-r--r-- | daemon/worker.c | 84 |
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; |
