diff options
Diffstat (limited to 'contrib/unbound/daemon')
-rw-r--r-- | contrib/unbound/daemon/cachedump.c | 339 | ||||
-rw-r--r-- | contrib/unbound/daemon/remote.c | 769 | ||||
-rw-r--r-- | contrib/unbound/daemon/stats.c | 2 | ||||
-rw-r--r-- | contrib/unbound/daemon/unbound.c | 9 | ||||
-rw-r--r-- | contrib/unbound/daemon/worker.c | 19 |
5 files changed, 809 insertions, 329 deletions
diff --git a/contrib/unbound/daemon/cachedump.c b/contrib/unbound/daemon/cachedump.c index ba986c763edc..f0a693bf6f8e 100644 --- a/contrib/unbound/daemon/cachedump.c +++ b/contrib/unbound/daemon/cachedump.c @@ -62,84 +62,231 @@ #include "sldns/wire2str.h" #include "sldns/str2wire.h" +static void spool_txt_printf(struct config_strlist_head* txt, + const char* format, ...) ATTR_FORMAT(printf, 2, 3); + +/** Append to strlist at end, and log error if out of memory. */ +static void +spool_txt_string(struct config_strlist_head* txt, char* str) +{ + if(!cfg_strlist_append(txt, strdup(str))) { + log_err("out of memory in spool text"); + } +} + +/** Spool txt to spool list. */ +static void +spool_txt_vmsg(struct config_strlist_head* txt, const char* format, + va_list args) +{ + char msg[65535]; + vsnprintf(msg, sizeof(msg), format, args); + spool_txt_string(txt, msg); +} + +/** Print item to spool list. On alloc failure the list is as before. */ +static void +spool_txt_printf(struct config_strlist_head* txt, const char* format, ...) +{ + va_list args; + va_start(args, format); + spool_txt_vmsg(txt, format, args); + va_end(args); +} + /** dump one rrset zonefile line */ -static int -dump_rrset_line(RES* ssl, struct ub_packed_rrset_key* k, time_t now, size_t i) +static void +dump_rrset_line(struct config_strlist_head* txt, 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"); + spool_txt_string(txt, "BADRR\n"); + return; } - return ssl_printf(ssl, "%s", s); + spool_txt_string(txt, s); } /** dump rrset key and data info */ -static int -dump_rrset(RES* ssl, struct ub_packed_rrset_key* k, +static void +dump_rrset(struct config_strlist_head* txt, 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(k->id == 0) return 1; /* deleted */ - if(d->ttl < now) return 1; /* expired */ + if(!k || !d) return; + if(k->id == 0) return; /* deleted */ + if(d->ttl < now) return; /* expired */ /* meta line */ - if(!ssl_printf(ssl, ";rrset%s " ARG_LL "d %u %u %d %d\n", + spool_txt_printf(txt, ";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)) + dump_rrset_line(txt, k, now, i); + } +} + +/** Spool strlist to the output. */ +static int +spool_strlist(RES* ssl, struct config_strlist* list) +{ + struct config_strlist* s; + for(s=list; s; s=s->next) { + if(!ssl_printf(ssl, "%s", s->str)) return 0; } return 1; } -/** dump lruhash rrset cache */ +/** dump lruhash cache and call callback for every item. */ static int -dump_rrset_lruhash(RES* ssl, struct lruhash* h, time_t now) +dump_lruhash(struct lruhash* table, + void (*func)(struct lruhash_entry*, struct config_strlist_head*, void*), + RES* ssl, void* arg) { - 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); + int just_started = 1; + int not_done = 1; + hashvalue_type hash; + size_t num = 0; /* number of entries processed. */ + size_t max = 2; /* number of entries after which it unlocks. */ + struct config_strlist_head txt; /* Text strings spooled. */ + memset(&txt, 0, sizeof(txt)); + + while(not_done) { + size_t i; /* hash bin. */ + /* Process a number of items. */ + num = 0; + lock_quick_lock(&table->lock); + if(just_started) { + i = 0; + } else { + i = hash&table->size_mask; + } + while(num < max) { + /* Process bin. */ + int found = 0; + size_t num_bin = 0; + struct lruhash_bin* bin = &table->array[i]; + struct lruhash_entry* e; + lock_quick_lock(&bin->lock); + for(e = bin->overflow_list; e; e = e->overflow_next) { + /* Entry e is locked by the func. */ + func(e, &txt, arg); + num_bin++; + } + lock_quick_unlock(&bin->lock); + /* This addition of bin number of entries may take + * it over the max. */ + num += num_bin; + + /* Move to next bin. */ + /* Find one with an entry, with a hash value, so we + * can continue from the hash value. The hash value + * can be indexed also if the array changes size. */ + i++; + while(i < table->size) { + bin = &table->array[i]; + lock_quick_lock(&bin->lock); + if(bin->overflow_list) { + hash = bin->overflow_list->hash; + lock_quick_unlock(&bin->lock); + found = 1; + just_started = 0; + break; + } + lock_quick_unlock(&bin->lock); + i++; + } + if(!found) { + not_done = 0; + break; + } + } + lock_quick_unlock(&table->lock); + /* Print the spooled items, that are collected while the + * locks are locked. The print happens while they are not + * locked. */ + if(txt.first) { + if(!spool_strlist(ssl, txt.first)) { + config_delstrlist(txt.first); + return 0; + } + config_delstrlist(txt.first); + memset(&txt, 0, sizeof(txt)); + } + } + /* Print the final spooled items. */ + if(txt.first) { + if(!spool_strlist(ssl, txt.first)) { + config_delstrlist(txt.first); return 0; } - lock_rw_unlock(&e->lock); + config_delstrlist(txt.first); + } + return 1; +} + +/** dump slabhash cache and call callback for every item. */ +static int +dump_slabhash(struct slabhash* sh, + void (*func)(struct lruhash_entry*, struct config_strlist_head*, void*), + RES* ssl, void* arg) +{ + /* Process a number of items at a time, then unlock the cache, + * so that ordinary processing can continue. Keep an iteration marker + * to continue the loop. That means the cache can change, items + * could be inserted and deleted. And, for example, the hash table + * can grow. */ + size_t slab; + for(slab=0; slab<sh->size; slab++) { + if(!dump_lruhash(sh->array[slab], func, ssl, arg)) + return 0; } return 1; } +/** Struct for dump information. */ +struct dump_info { + /** The worker. */ + struct worker* worker; + /** The printout connection. */ + RES* ssl; +}; + +/** Dump the rrset cache entry */ +static void +dump_rrset_entry(struct lruhash_entry* e, struct config_strlist_head* txt, + void* arg) +{ + struct dump_info* dump_info = (struct dump_info*)arg; + lock_rw_rdlock(&e->lock); + dump_rrset(txt, (struct ub_packed_rrset_key*)e->key, + (struct packed_rrset_data*)e->data, + *dump_info->worker->env.now); + lock_rw_unlock(&e->lock); +} + /** dump rrset cache */ static int dump_rrset_cache(RES* ssl, struct worker* worker) { struct rrset_cache* r = worker->env.rrset_cache; - size_t slab; + struct dump_info dump_info; + dump_info.worker = worker; + dump_info.ssl = ssl; 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); - } + if(!dump_slabhash(&r->table, &dump_rrset_entry, ssl, &dump_info)) + return 0; return ssl_printf(ssl, "END_RRSET_CACHE\n"); } /** dump message to rrset reference */ -static int -dump_msg_ref(RES* ssl, struct ub_packed_rrset_key* k) +static void +dump_msg_ref(struct config_strlist_head* txt, struct ub_packed_rrset_key* k) { char* nm, *tp, *cl; nm = sldns_wire2str_dname(k->rk.dname, k->rk.dname_len); @@ -149,30 +296,25 @@ dump_msg_ref(RES* ssl, struct ub_packed_rrset_key* k) 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; + spool_txt_string(txt, "BADREF\n"); + return; } + spool_txt_printf(txt, "%s %s %s %d\n", nm, cl, tp, (int)k->rk.flags); free(nm); free(tp); free(cl); - - return 1; } /** dump message entry */ -static int -dump_msg(RES* ssl, struct query_info* k, struct reply_info* d, time_t now) +static void +dump_msg(struct config_strlist_head* txt, 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 */ - + if(!k || !d) return; + if(d->ttl < now) return; /* expired */ + nm = sldns_wire2str_dname(k->qname, k->qname_len); tp = sldns_wire2str_type(k->qtype); cl = sldns_wire2str_class(k->qclass); @@ -180,45 +322,35 @@ dump_msg(RES* ssl, struct query_info* k, struct reply_info* d, time_t now) free(nm); free(tp); free(cl); - return 1; /* skip this entry */ + return; /* 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 */ + return; /* skip this entry */ } - + /* meta line */ - if(!ssl_printf(ssl, "msg %s %s %s %d %d " ARG_LL "d %d %u %u %u %d %s\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, - (int)d->reason_bogus, - d->reason_bogus_str?d->reason_bogus_str:"")) { - free(nm); - free(tp); - free(cl); - rrset_array_unlock(d->ref, d->rrset_count); - return 0; - } + spool_txt_printf(txt, + "msg %s %s %s %d %d " ARG_LL "d %d %u %u %u %d %s\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, + (int)d->reason_bogus, + d->reason_bogus_str?d->reason_bogus_str:""); 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; - } + dump_msg_ref(txt, d->rrsets[i]); } rrset_array_unlock(d->ref, d->rrset_count); - - return 1; } /** copy msg to worker pad */ @@ -247,49 +379,40 @@ copy_msg(struct regional* region, struct lruhash_entry* e, return (*k)->qname != NULL; } -/** dump lruhash msg cache */ -static int -dump_msg_lruhash(RES* ssl, struct worker* worker, struct lruhash* h) +/** Dump the msg entry. */ +static void +dump_msg_entry(struct lruhash_entry* e, struct config_strlist_head* txt, + void* arg) { - struct lruhash_entry* e; + struct dump_info* dump_info = (struct dump_info*)arg; 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; - } + regional_free_all(dump_info->worker->scratchpad); + /* Make copy of rrset in worker buffer. */ + lock_rw_rdlock(&e->lock); + if(!copy_msg(dump_info->worker->scratchpad, e, &k, &d)) { 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; - } + log_err("out of memory in dump_msg_entry"); + return; } - return 1; + lock_rw_unlock(&e->lock); + /* Release lock so we can lookup the rrset references + * in the rrset cache. */ + dump_msg(txt, k, d, *dump_info->worker->env.now); } /** dump msg cache */ static int dump_msg_cache(RES* ssl, struct worker* worker) { - struct slabhash* sh = worker->env.msg_cache; - size_t slab; + struct dump_info dump_info; + dump_info.worker = worker; + dump_info.ssl = ssl; 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); - } + if(!dump_slabhash(worker->env.msg_cache, &dump_msg_entry, ssl, + &dump_info)) + return 0; return ssl_printf(ssl, "END_MSG_CACHE\n"); } @@ -811,12 +934,18 @@ print_dp_main(RES* ssl, struct delegpt* dp, struct dns_msg* msg) struct ub_packed_rrset_key* k = msg->rep->rrsets[i]; struct packed_rrset_data* d = (struct packed_rrset_data*)k->entry.data; + struct config_strlist_head txt; + memset(&txt, 0, sizeof(txt)); if(d->security == sec_status_bogus) { if(!ssl_printf(ssl, "Address is BOGUS:\n")) return; } - if(!dump_rrset(ssl, k, d, 0)) + dump_rrset(&txt, k, d, 0); + if(!spool_strlist(ssl, txt.first)) { + config_delstrlist(txt.first); return; + } + config_delstrlist(txt.first); } delegpt_count_ns(dp, &n_ns, &n_miss); delegpt_count_addr(dp, &n_addr, &n_res, &n_avail); diff --git a/contrib/unbound/daemon/remote.c b/contrib/unbound/daemon/remote.c index 89134efc92a8..e10dadde7862 100644 --- a/contrib/unbound/daemon/remote.c +++ b/contrib/unbound/daemon/remote.c @@ -101,6 +101,10 @@ #ifdef USE_CACHEDB #include "cachedb/cachedb.h" #endif +#ifdef CLIENT_SUBNET +#include "edns-subnet/subnetmod.h" +#include "edns-subnet/addrtree.h" +#endif #ifdef HAVE_SYS_TYPES_H # include <sys/types.h> @@ -1148,6 +1152,8 @@ print_ext(RES* ssl, struct ub_stats_info* s, int inhibit_zero) (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.valops"SQ"%lu\n", + (unsigned long)s->svr.val_ops)) 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", @@ -1576,7 +1582,7 @@ do_view_zone_add(RES* ssl, struct worker* worker, char* arg) } if(!v->isfirst) { /* Global local-zone is not used for this view, - * therefore add defaults to this view-specic + * therefore add defaults to this view-specific * local-zone. */ struct config_file lz_cfg; memset(&lz_cfg, 0, sizeof(lz_cfg)); @@ -1740,6 +1746,334 @@ do_view_datas_remove(struct daemon_remote* rc, RES* ssl, struct worker* worker, (void)ssl_printf(ssl, "removed %d datas\n", num); } +/** information for the domain search */ +struct cache_lookup_info { + /** The connection to print on. */ + RES* ssl; + /** The worker. */ + struct worker* worker; + /** The domain, in wireformat. */ + uint8_t* nm; + /** The length of nm. */ + size_t nmlen; +}; + +#ifdef CLIENT_SUBNET +static void addrtree_traverse_visit_node(struct addrnode* n, addrkey_t* addr, + size_t addr_size, int is_ipv6, time_t now, struct query_info* q, + void (*func)(struct query_info*, struct reply_info*, addrkey_t*, + size_t, int, addrlen_t, int, time_t, void*), void* arg); + +/** Lookup in subnet addrtree */ +static void +cache_lookup_subnet_addrnode(struct query_info* q, struct reply_info* d, + addrkey_t* addr, size_t addr_size, int is_ipv6, addrlen_t scope, + int only_match_scope_zero, time_t ttl, void* arg) +{ + size_t i; + char s[65535], tp[32], cl[32], rc[32], fg[32], astr[64]; + struct cache_lookup_info* inf = (struct cache_lookup_info*)arg; + if(is_ipv6) { + if(addr_size < 16 || inet_ntop(AF_INET6, addr, astr, + sizeof(astr)) == NULL) + snprintf(astr, sizeof(astr), "(inet6ntoperror)"); + } else { + if(addr_size < 4 || inet_ntop(AF_INET, addr, astr, + sizeof(astr)) == NULL) + snprintf(astr, sizeof(astr), "(inetntoperror)"); + } + sldns_wire2str_dname_buf(q->qname, q->qname_len, s, sizeof(s)); + sldns_wire2str_type_buf(q->qtype, tp, sizeof(tp)); + sldns_wire2str_class_buf(q->qclass, cl, sizeof(cl)); + sldns_wire2str_rcode_buf(FLAGS_GET_RCODE(d->flags), + rc, sizeof(rc)); + snprintf(fg, sizeof(fg), "%s%s%s%s%s%s%s%s", + ((d->flags&BIT_QR)?" QR":""), + ((d->flags&BIT_AA)?" AA":""), + ((d->flags&BIT_TC)?" TC":""), + ((d->flags&BIT_RD)?" RD":""), + ((d->flags&BIT_RA)?" RA":""), + ((d->flags&BIT_Z)?" Z":""), + ((d->flags&BIT_AD)?" AD":""), + ((d->flags&BIT_CD)?" CD":"")); + if(!rrset_array_lock(d->ref, d->rrset_count, + *inf->worker->env.now)) { + /* rrsets have timed out or do not exist */ + return; + } + if(!ssl_printf(inf->ssl, "subnet %s/%d%s %s %s %s " ARG_LL "d\n", astr, + (int)scope, (only_match_scope_zero?" scope_zero":""), + s, cl, tp, (long long)(ttl-*inf->worker->env.now))) { + rrset_array_unlock(d->ref, d->rrset_count); + return; + } + ssl_printf(inf->ssl, + "subnet msg %s %s %s%s %s %d %d " ARG_LL "d %d %u %u %u %d %s\n", + s, cl, tp, fg, rc, + (int)d->flags, (int)d->qdcount, + (long long)(d->ttl-*inf->worker->env.now), + (int)d->security, + (unsigned)d->an_numrrsets, + (unsigned)d->ns_numrrsets, + (unsigned)d->ar_numrrsets, + (int)d->reason_bogus, + d->reason_bogus_str?d->reason_bogus_str:""); + for(i=0; i<d->rrset_count; i++) { + struct ub_packed_rrset_key* rk = d->rrsets[i]; + struct packed_rrset_data* rd = (struct packed_rrset_data*)rk->entry.data; + size_t j; + for(j=0; j<rd->count + rd->rrsig_count; j++) { + if(!packed_rr_to_string(rk, j, + *inf->worker->env.now, s, sizeof(s))) { + ssl_printf(inf->ssl, "BADRR\n"); + } else { + ssl_printf(inf->ssl, "%s", s); + } + } + } + rrset_array_unlock(d->ref, d->rrset_count); + ssl_printf(inf->ssl, "\n"); +} + +/** Visit an edge in subnet addrtree traverse */ +static void +addrtree_traverse_visit_edge(struct addredge* edge, addrkey_t* addr, + size_t addr_size, int is_ipv6, time_t now, struct query_info* q, + void (*func)(struct query_info*, struct reply_info*, addrkey_t*, + size_t, int, addrlen_t, int, time_t, void*), void* arg) +{ + size_t n; + addrlen_t addrlen; + if(!edge || !edge->node) + return; + addrlen = edge->len; + /* ceil() */ + n = (size_t)((addrlen / KEYWIDTH) + ((addrlen % KEYWIDTH != 0)?1:0)); + if(n > addr_size) + n = addr_size; + memset(addr, 0, addr_size); + memcpy(addr, edge->str, n); + addrtree_traverse_visit_node(edge->node, addr, addr_size, is_ipv6, + now, q, func, arg); +} + +/** Visit a node in subnet addrtree traverse */ +static void +addrtree_traverse_visit_node(struct addrnode* n, addrkey_t* addr, + size_t addr_size, int is_ipv6, time_t now, struct query_info* q, + void (*func)(struct query_info*, struct reply_info*, addrkey_t*, + size_t, int, addrlen_t, int, time_t, void*), void* arg) +{ + /* If this node has data, and not expired. */ + if(n->elem && n->ttl >= now) { + func(q, (struct reply_info*)n->elem, addr, addr_size, is_ipv6, + n->scope, n->only_match_scope_zero, n->ttl, arg); + } + /* Traverse edges. */ + addrtree_traverse_visit_edge(n->edge[0], addr, addr_size, is_ipv6, + now, q, func, arg); + addrtree_traverse_visit_edge(n->edge[1], addr, addr_size, is_ipv6, + now, q, func, arg); +} + +/** Traverse subnet addrtree */ +static void +addrtree_traverse(struct addrtree* tree, int is_ipv6, time_t now, + struct query_info* q, + void (*func)(struct query_info*, struct reply_info*, addrkey_t*, + size_t, int, addrlen_t, int, time_t, void*), void* arg) +{ + uint8_t addr[16]; /* Large enough for IPv4 and IPv6. */ + memset(addr, 0, sizeof(addr)); + addrtree_traverse_visit_node(tree->root, (addrkey_t*)addr, + sizeof(addr), is_ipv6, now, q, func, arg); +} + +/** Lookup cache_lookup for subnet content. */ +static void +cache_lookup_subnet_msg(struct lruhash_entry* e, void* arg) +{ + struct cache_lookup_info* inf = (struct cache_lookup_info*)arg; + struct msgreply_entry *k = (struct msgreply_entry*)e->key; + struct subnet_msg_cache_data* d = + (struct subnet_msg_cache_data*)e->data; + if(!dname_subdomain_c(k->key.qname, inf->nm)) + return; + + if(d->tree4) { + addrtree_traverse(d->tree4, 0, *inf->worker->env.now, &k->key, + &cache_lookup_subnet_addrnode, inf); + } + if(d->tree6) { + addrtree_traverse(d->tree6, 1, *inf->worker->env.now, &k->key, + &cache_lookup_subnet_addrnode, inf); + } +} +#endif /* CLIENT_SUBNET */ + +static void +cache_lookup_rrset(struct lruhash_entry* e, void* arg) +{ + struct cache_lookup_info* inf = (struct cache_lookup_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; + if(*inf->worker->env.now < d->ttl && + k->id != 0 && /* not deleted */ + dname_subdomain_c(k->rk.dname, inf->nm)) { + size_t i; + for(i=0; i<d->count + d->rrsig_count; i++) { + char s[65535]; + if(!packed_rr_to_string(k, i, *inf->worker->env.now, + s, sizeof(s))) { + ssl_printf(inf->ssl, "BADRR\n"); + return; + } + ssl_printf(inf->ssl, "%s", s); + } + ssl_printf(inf->ssl, "\n"); + } +} + +static void +cache_lookup_msg(struct lruhash_entry* e, void* arg) +{ + struct cache_lookup_info* inf = (struct cache_lookup_info*)arg; + struct msgreply_entry* k = (struct msgreply_entry*)e->key; + struct reply_info* d = (struct reply_info*)e->data; + if(*inf->worker->env.now < d->ttl && + dname_subdomain_c(k->key.qname, inf->nm)) { + size_t i; + char s[65535], tp[32], cl[32], rc[32], fg[32]; + sldns_wire2str_dname_buf(k->key.qname, k->key.qname_len, + s, sizeof(s)); + sldns_wire2str_type_buf(k->key.qtype, tp, sizeof(tp)); + sldns_wire2str_class_buf(k->key.qclass, cl, sizeof(cl)); + sldns_wire2str_rcode_buf(FLAGS_GET_RCODE(d->flags), + rc, sizeof(rc)); + snprintf(fg, sizeof(fg), "%s%s%s%s%s%s%s%s", + ((d->flags&BIT_QR)?" QR":""), + ((d->flags&BIT_AA)?" AA":""), + ((d->flags&BIT_TC)?" TC":""), + ((d->flags&BIT_RD)?" RD":""), + ((d->flags&BIT_RA)?" RA":""), + ((d->flags&BIT_Z)?" Z":""), + ((d->flags&BIT_AD)?" AD":""), + ((d->flags&BIT_CD)?" CD":"")); + if(!rrset_array_lock(d->ref, d->rrset_count, + *inf->worker->env.now)) { + /* rrsets have timed out or do not exist */ + return; + } + ssl_printf(inf->ssl, + "msg %s %s %s%s %s %d %d " ARG_LL "d %d %u %u %u %d %s\n", + s, cl, tp, fg, rc, + (int)d->flags, (int)d->qdcount, + (long long)(d->ttl-*inf->worker->env.now), + (int)d->security, + (unsigned)d->an_numrrsets, + (unsigned)d->ns_numrrsets, + (unsigned)d->ar_numrrsets, + (int)d->reason_bogus, + d->reason_bogus_str?d->reason_bogus_str:""); + for(i=0; i<d->rrset_count; i++) { + struct ub_packed_rrset_key* rk = d->rrsets[i]; + struct packed_rrset_data* rd = (struct packed_rrset_data*)rk->entry.data; + size_t j; + for(j=0; j<rd->count + rd->rrsig_count; j++) { + if(!packed_rr_to_string(rk, j, + *inf->worker->env.now, s, sizeof(s))) { + rrset_array_unlock(d->ref, d->rrset_count); + ssl_printf(inf->ssl, "BADRR\n"); + return; + } + ssl_printf(inf->ssl, "%s", s); + } + } + rrset_array_unlock(d->ref, d->rrset_count); + ssl_printf(inf->ssl, "\n"); + } +} + +/** perform cache search for domain */ +static void +do_cache_lookup_domain(RES* ssl, struct worker* worker, uint8_t* nm, + size_t nmlen) +{ +#ifdef CLIENT_SUBNET + int m; + struct subnet_env* sn_env = NULL; +#endif /* CLIENT_SUBNET */ + struct cache_lookup_info inf; + inf.ssl = ssl; + inf.worker = worker; + inf.nm = nm; + inf.nmlen = nmlen; + +#ifdef CLIENT_SUBNET + m = modstack_find(worker->env.modstack, "subnetcache"); + if(m != -1) sn_env = (struct subnet_env*)worker->env.modinfo[m]; + if(sn_env) { + lock_rw_rdlock(&sn_env->biglock); + slabhash_traverse(sn_env->subnet_msg_cache, 0, + &cache_lookup_subnet_msg, &inf); + lock_rw_unlock(&sn_env->biglock); + } +#endif /* CLIENT_SUBNET */ + + slabhash_traverse(&worker->env.rrset_cache->table, 0, + &cache_lookup_rrset, &inf); + slabhash_traverse(worker->env.msg_cache, 0, &cache_lookup_msg, &inf); +} + +/** cache lookup of domain */ +static void +do_cache_lookup(RES* ssl, struct worker* worker, char* arg) +{ + uint8_t nm[LDNS_MAX_DOMAINLEN+1]; + size_t nmlen; + int status; + char* s = arg, *next = NULL; + int allow_long = 0; + + if(arg[0] == '+' && arg[1] == 't' && (arg[2]==' ' || arg[2]=='\t')) { + allow_long = 1; + s = arg+2; + } + + /* Find the commandline arguments of domains. */ + while(s && *s != 0) { + s = skipwhite(s); + if(*s == 0) + break; + if(strchr(s, ' ') || strchr(s, '\t')) { + char* sp = strchr(s, ' '); + if(strchr(s, '\t') != 0 && strchr(s, '\t') < sp) + sp = strchr(s, '\t'); + *sp = 0; + next = sp+1; + } else { + next = NULL; + } + + nmlen = sizeof(nm); + status = sldns_str2wire_dname_buf(s, nm, &nmlen); + if(status != 0) { + ssl_printf(ssl, "error cannot parse name %s at %d: %s\n", s, + LDNS_WIREPARSE_OFFSET(status), + sldns_get_errorstr_parse(status)); + return; + } + if(!allow_long && dname_count_labels(nm) < 3) { + ssl_printf(ssl, "error name too short: '%s'. Need example.com. or longer, short names take very long, use +t to allow them.\n", s); + return; + } + + do_cache_lookup_domain(ssl, worker, nm, nmlen); + + s = next; + } +} + /** cache lookup of nameservers */ static void do_lookup(RES* ssl, struct worker* worker, char* arg) @@ -2887,10 +3221,13 @@ do_auth_zone_reload(RES* ssl, struct worker* worker, char* arg) (void)ssl_printf(ssl, "error: no SOA in zone after read %s\n", arg); return; } - if(xfr->have_zone) + if(xfr->have_zone) { xfr->lease_time = *worker->env.now; + xfr->soa_zone_acquired = *worker->env.now; + } lock_basic_unlock(&xfr->lock); } + z->soa_zone_acquired = *worker->env.now; auth_zone_verify_zonemd(z, &worker->env, &worker->env.mesh->mods, &reason, 0, 0); @@ -3039,7 +3376,7 @@ static void do_list_auth_zones(RES* ssl, struct auth_zones* az) { struct auth_zone* z; - char buf[LDNS_MAX_DOMAINLEN], buf2[256]; + char buf[LDNS_MAX_DOMAINLEN], buf2[256], buf3[256]; lock_rw_rdlock(&az->lock); RBTREE_FOR(z, struct auth_zone*, &az->ztree) { lock_rw_rdlock(&z->lock); @@ -3048,18 +3385,41 @@ do_list_auth_zones(RES* ssl, struct auth_zones* az) snprintf(buf2, sizeof(buf2), "expired"); else { uint32_t serial = 0; - if(auth_zone_get_serial(z, &serial)) + if(auth_zone_get_serial(z, &serial)) { snprintf(buf2, sizeof(buf2), "serial %u", (unsigned)serial); - else snprintf(buf2, sizeof(buf2), "no serial"); + if(z->soa_zone_acquired != 0) { +#if defined(HAVE_STRFTIME) && defined(HAVE_LOCALTIME_R) + char tmbuf[32]; + struct tm tm; + struct tm *tm_p; + tm_p = localtime_r( + &z->soa_zone_acquired, &tm); + if(!strftime(tmbuf, sizeof(tmbuf), "%Y-%m-%dT%H:%M:%S", tm_p)) + snprintf(tmbuf, sizeof(tmbuf), "strftime-err-%u", (unsigned)z->soa_zone_acquired); + snprintf(buf3, sizeof(buf3), + "\t since %u %s", + (unsigned)z->soa_zone_acquired, + tmbuf); +#else + snprintf(buf3, sizeof(buf3), + "\t since %u", + (unsigned)z->soa_zone_acquired); +#endif + } else { + buf3[0]=0; + } + } else { + snprintf(buf2, sizeof(buf2), "no serial"); + buf3[0]=0; + } } - if(!ssl_printf(ssl, "%s\t%s\n", buf, buf2)) { + lock_rw_unlock(&z->lock); + if(!ssl_printf(ssl, "%s\t%s%s\n", buf, buf2, buf3)) { /* failure to print */ - lock_rw_unlock(&z->lock); lock_rw_unlock(&az->lock); return; } - lock_rw_unlock(&z->lock); } lock_rw_unlock(&az->lock); } @@ -3502,6 +3862,30 @@ do_print_cookie_secrets(RES* ssl, struct worker* worker) { explicit_bzero(secret_hex, sizeof(secret_hex)); } +/** check that there is no argument after a command that takes no arguments. */ +static int +cmd_no_args(RES* ssl, char* cmd, char* p) +{ + if(p && *p != 0) { + /* cmd contains the command that is called at the start, + * with space or tab after it. */ + char* c = cmd; + if(strchr(c, ' ') && strchr(c, '\t')) { + if(strchr(c, ' ') < strchr(c, '\t')) + *strchr(c, ' ')=0; + else *strchr(c, '\t')=0; + } else if(strchr(c, ' ')) { + *strchr(c, ' ')=0; + } else if(strchr(c, '\t')) { + *strchr(c, '\t')=0; + } + (void)ssl_printf(ssl, "error command %s takes no arguments," + " have '%s'\n", c, p); + return 1; + } + return 0; +} + /** check for name with end-of-string, space or tab after it */ static int cmdcmp(char* p, const char* cmd, size_t len) @@ -3517,27 +3901,41 @@ execute_cmd(struct daemon_remote* rc, struct rc_state* s, RES* ssl, char* cmd, char* p = skipwhite(cmd); /* compare command */ if(cmdcmp(p, "stop", 4)) { + if(cmd_no_args(ssl, p, skipwhite(p+4))) + return; do_stop(ssl, worker); return; } else if(cmdcmp(p, "reload_keep_cache", 17)) { + if(cmd_no_args(ssl, p, skipwhite(p+17))) + return; do_reload(ssl, worker, 1); return; } else if(cmdcmp(p, "reload", 6)) { + if(cmd_no_args(ssl, p, skipwhite(p+6))) + return; do_reload(ssl, worker, 0); return; } else if(cmdcmp(p, "fast_reload", 11)) { do_fast_reload(ssl, worker, s, skipwhite(p+11)); return; } else if(cmdcmp(p, "stats_noreset", 13)) { + if(cmd_no_args(ssl, p, skipwhite(p+13))) + return; do_stats(ssl, worker, 0); return; } else if(cmdcmp(p, "stats", 5)) { + if(cmd_no_args(ssl, p, skipwhite(p+5))) + return; do_stats(ssl, worker, 1); return; } else if(cmdcmp(p, "status", 6)) { + if(cmd_no_args(ssl, p, skipwhite(p+6))) + return; do_status(ssl, worker); return; } else if(cmdcmp(p, "dump_cache", 10)) { + if(cmd_no_args(ssl, p, skipwhite(p+10))) + return; #ifdef THREADS_DISABLED if(worker->daemon->num > 1) { (void)ssl_printf(ssl, "dump_cache/load_cache is not " @@ -3548,6 +3946,8 @@ execute_cmd(struct daemon_remote* rc, struct rc_state* s, RES* ssl, char* cmd, (void)dump_cache(ssl, worker); return; } else if(cmdcmp(p, "load_cache", 10)) { + if(cmd_no_args(ssl, p, skipwhite(p+10))) + return; #ifdef THREADS_DISABLED if(worker->daemon->num > 1) { /* The warning can't be printed when stdin is sending @@ -3558,18 +3958,28 @@ execute_cmd(struct daemon_remote* rc, struct rc_state* s, RES* ssl, char* cmd, if(load_cache(ssl, worker)) send_ok(ssl); return; } else if(cmdcmp(p, "list_forwards", 13)) { + if(cmd_no_args(ssl, p, skipwhite(p+13))) + return; do_list_forwards(ssl, worker); return; } else if(cmdcmp(p, "list_stubs", 10)) { + if(cmd_no_args(ssl, p, skipwhite(p+10))) + return; do_list_stubs(ssl, worker); return; } else if(cmdcmp(p, "list_insecure", 13)) { + if(cmd_no_args(ssl, p, skipwhite(p+13))) + return; do_insecure_list(ssl, worker); return; } else if(cmdcmp(p, "list_local_zones", 16)) { + if(cmd_no_args(ssl, p, skipwhite(p+16))) + return; do_list_local_zones(ssl, worker->daemon->local_zones); return; } else if(cmdcmp(p, "list_local_data", 15)) { + if(cmd_no_args(ssl, p, skipwhite(p+15))) + return; do_list_local_data(ssl, worker, worker->daemon->local_zones); return; } else if(cmdcmp(p, "view_list_local_zones", 21)) { @@ -3585,6 +3995,8 @@ execute_cmd(struct daemon_remote* rc, struct rc_state* s, RES* ssl, char* cmd, do_ip_ratelimit_list(ssl, worker, p+17); return; } else if(cmdcmp(p, "list_auth_zones", 15)) { + if(cmd_no_args(ssl, p, skipwhite(p+15))) + return; do_list_auth_zones(ssl, worker->env.auth_zones); return; } else if(cmdcmp(p, "auth_zone_reload", 16)) { @@ -3605,14 +4017,21 @@ execute_cmd(struct daemon_remote* rc, struct rc_state* s, RES* ssl, char* cmd, return; } else if(cmdcmp(p, "flush_stats", 11)) { /* must always distribute this cmd */ + if(cmd_no_args(ssl, p, skipwhite(p+11))) + return; 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(cmd_no_args(ssl, p, skipwhite(p+17))) + return; if(rc) distribute_cmd(rc, ssl, cmd); do_flush_requestlist(ssl, worker); return; + } else if(cmdcmp(p, "cache_lookup", 12)) { + do_cache_lookup(ssl, worker, skipwhite(p+12)); + return; } else if(cmdcmp(p, "lookup", 6)) { do_lookup(ssl, worker, skipwhite(p+6)); return; @@ -3620,15 +4039,23 @@ execute_cmd(struct daemon_remote* rc, struct rc_state* s, RES* ssl, char* cmd, * Each line needs to be distributed if THREADS_DISABLED. */ } else if(cmdcmp(p, "local_zones_remove", 18)) { + if(cmd_no_args(ssl, p, skipwhite(p+18))) + return; do_zones_remove(rc, ssl, worker); return; } else if(cmdcmp(p, "local_zones", 11)) { + if(cmd_no_args(ssl, p, skipwhite(p+11))) + return; do_zones_add(rc, ssl, worker); return; } else if(cmdcmp(p, "local_datas_remove", 18)) { + if(cmd_no_args(ssl, p, skipwhite(p+18))) + return; do_datas_remove(rc, ssl, worker); return; } else if(cmdcmp(p, "local_datas", 11)) { + if(cmd_no_args(ssl, p, skipwhite(p+11))) + return; do_datas_add(rc, ssl, worker); return; } else if(cmdcmp(p, "view_local_datas_remove", 23)){ @@ -3638,6 +4065,8 @@ execute_cmd(struct daemon_remote* rc, struct rc_state* s, RES* ssl, char* cmd, do_view_datas_add(rc, ssl, worker, skipwhite(p+16)); return; } else if(cmdcmp(p, "print_cookie_secrets", 20)) { + if(cmd_no_args(ssl, p, skipwhite(p+20))) + return; do_print_cookie_secrets(ssl, worker); return; } @@ -3687,10 +4116,16 @@ execute_cmd(struct daemon_remote* rc, struct rc_state* s, RES* ssl, char* cmd, } else if(cmdcmp(p, "flush", 5)) { do_flush_name(ssl, worker, skipwhite(p+5)); } else if(cmdcmp(p, "dump_requestlist", 16)) { + if(cmd_no_args(ssl, p, skipwhite(p+16))) + return; do_dump_requestlist(ssl, worker); } else if(cmdcmp(p, "dump_infra", 10)) { + if(cmd_no_args(ssl, p, skipwhite(p+10))) + return; do_dump_infra(ssl, worker); } else if(cmdcmp(p, "log_reopen", 10)) { + if(cmd_no_args(ssl, p, skipwhite(p+10))) + return; do_log_reopen(ssl, worker); } else if(cmdcmp(p, "set_option", 10)) { do_set_option(ssl, worker, skipwhite(p+10)); @@ -3707,8 +4142,12 @@ execute_cmd(struct daemon_remote* rc, struct rc_state* s, RES* ssl, char* cmd, } else if(cmdcmp(p, "add_cookie_secret", 17)) { do_add_cookie_secret(ssl, worker, skipwhite(p+17)); } else if(cmdcmp(p, "drop_cookie_secret", 18)) { + if(cmd_no_args(ssl, p, skipwhite(p+18))) + return; do_drop_cookie_secret(ssl, worker); } else if(cmdcmp(p, "activate_cookie_secret", 22)) { + if(cmd_no_args(ssl, p, skipwhite(p+22))) + return; do_activate_cookie_secret(ssl, worker); } else { (void)ssl_printf(ssl, "error unknown command '%s'\n", p); @@ -4348,37 +4787,45 @@ fr_check_tag_defines(struct fast_reload_thread* fr, struct config_file* newcfg) return 1; } -/** fast reload thread, check if config item has changed, if not add to - * the explanatory string. */ +/** fast reload thread, add incompatible option to the explanatory string */ static void -fr_check_changed_cfg(int cmp, const char* desc, char* str, size_t len) +fr_add_incompatible_option(const char* desc, char* str, size_t len) { - if(cmp) { - size_t slen = strlen(str); - size_t desclen = strlen(desc); - if(slen == 0) { - snprintf(str, len, "%s", desc); - return; - } - if(len - slen < desclen+2) - return; /* It does not fit */ - snprintf(str+slen, len-slen, " %s", desc); + size_t slen = strlen(str); + size_t desclen = strlen(desc); + if(slen == 0) { + snprintf(str, len, "%s", desc); + return; } + if(len - slen < desclen+2) + return; /* It does not fit */ + snprintf(str+slen, len-slen, " %s", desc); } +/** fast reload thread, check if config item has changed; thus incompatible */ +#define FR_CHECK_CHANGED_CFG(desc, var, str) \ +do { \ + if(cfg->var != newcfg->var) { \ + fr_add_incompatible_option(desc, str, sizeof(str)); \ + } \ +} while(0); + /** fast reload thread, check if config string has changed, checks NULLs. */ -static void -fr_check_changed_cfg_str(char* cmp1, char* cmp2, const char* desc, char* str, - size_t len) -{ - if((!cmp1 && cmp2) || - (cmp1 && !cmp2) || - (cmp1 && cmp2 && strcmp(cmp1, cmp2) != 0)) { - fr_check_changed_cfg(1, desc, str, len); - } -} +#define FR_CHECK_CHANGED_CFG_STR(desc, var, str) \ +do { \ + if((!cfg->var && newcfg->var) || \ + (cfg->var && !newcfg->var) || \ + (cfg->var && newcfg->var \ + && strcmp(cfg->var, newcfg->var) != 0)) { \ + fr_add_incompatible_option(desc, str, sizeof(str)); \ + } \ +} while(0); /** fast reload thread, check if config strlist has changed. */ +#define FR_CHECK_CHANGED_CFG_STRLIST(desc, var, str) do { \ + fr_check_changed_cfg_strlist(cfg->var, newcfg->var, desc, str, \ + sizeof(str)); \ + } while(0); static void fr_check_changed_cfg_strlist(struct config_strlist* cmp1, struct config_strlist* cmp2, const char* desc, char* str, size_t len) @@ -4389,18 +4836,22 @@ fr_check_changed_cfg_strlist(struct config_strlist* cmp1, (p1->str && !p2->str) || (p1->str && p2->str && strcmp(p1->str, p2->str) != 0)) { /* The strlist is different. */ - fr_check_changed_cfg(1, desc, str, len); + fr_add_incompatible_option(desc, str, len); return; } p1 = p1->next; p2 = p2->next; } if((!p1 && p2) || (p1 && !p2)) { - fr_check_changed_cfg(1, desc, str, len); + fr_add_incompatible_option(desc, str, len); } } /** fast reload thread, check if config str2list has changed. */ +#define FR_CHECK_CHANGED_CFG_STR2LIST(desc, var, buff) do { \ + fr_check_changed_cfg_str2list(cfg->var, newcfg->var, desc, buff,\ + sizeof(buff)); \ + } while(0); static void fr_check_changed_cfg_str2list(struct config_str2list* cmp1, struct config_str2list* cmp2, const char* desc, char* str, size_t len) @@ -4411,7 +4862,7 @@ fr_check_changed_cfg_str2list(struct config_str2list* cmp1, (p1->str && !p2->str) || (p1->str && p2->str && strcmp(p1->str, p2->str) != 0)) { /* The str2list is different. */ - fr_check_changed_cfg(1, desc, str, len); + fr_add_incompatible_option(desc, str, len); return; } if((!p1->str2 && p2->str2) || @@ -4419,14 +4870,14 @@ fr_check_changed_cfg_str2list(struct config_str2list* cmp1, (p1->str2 && p2->str2 && strcmp(p1->str2, p2->str2) != 0)) { /* The str2list is different. */ - fr_check_changed_cfg(1, desc, str, len); + fr_add_incompatible_option(desc, str, len); return; } p1 = p1->next; p2 = p2->next; } if((!p1 && p2) || (p1 && !p2)) { - fr_check_changed_cfg(1, desc, str, len); + fr_add_incompatible_option(desc, str, len); } } @@ -4440,98 +4891,54 @@ fr_check_compat_cfg(struct fast_reload_thread* fr, struct config_file* newcfg) changed_str[0]=0; /* Find incompatible options, and if so, print an error. */ - fr_check_changed_cfg(cfg->num_threads != newcfg->num_threads, - "num-threads", changed_str, sizeof(changed_str)); - fr_check_changed_cfg(cfg->do_ip4 != newcfg->do_ip4, - "do-ip4", changed_str, sizeof(changed_str)); - fr_check_changed_cfg(cfg->do_ip6 != newcfg->do_ip6, - "do-ip6", changed_str, sizeof(changed_str)); - fr_check_changed_cfg(cfg->do_udp != newcfg->do_udp, - "do-udp", changed_str, sizeof(changed_str)); - fr_check_changed_cfg(cfg->do_tcp != newcfg->do_tcp, - "do-tcp", changed_str, sizeof(changed_str)); - fr_check_changed_cfg(cfg->port != newcfg->port, - "port", changed_str, sizeof(changed_str)); + FR_CHECK_CHANGED_CFG("num-threads", num_threads, changed_str); + FR_CHECK_CHANGED_CFG("do-ip4", do_ip4, changed_str); + FR_CHECK_CHANGED_CFG("do-ip6", do_ip6, changed_str); + FR_CHECK_CHANGED_CFG("do-udp", do_udp, changed_str); + FR_CHECK_CHANGED_CFG("do-tcp", do_tcp, changed_str); + FR_CHECK_CHANGED_CFG("port", port, changed_str); /* But cfg->outgoing_num_ports has been changed at startup, * possibly to reduce it, so do not check it here. */ - fr_check_changed_cfg(cfg->outgoing_num_tcp != newcfg->outgoing_num_tcp, - "outgoing-num-tcp", changed_str, sizeof(changed_str)); - fr_check_changed_cfg(cfg->incoming_num_tcp != newcfg->incoming_num_tcp, - "incoming-num-tcp", changed_str, sizeof(changed_str)); - fr_check_changed_cfg(cfg->num_out_ifs != newcfg->num_out_ifs, - "outgoing-interface", changed_str, sizeof(changed_str)); + FR_CHECK_CHANGED_CFG("outgoing-num-tcp", outgoing_num_tcp, changed_str); + FR_CHECK_CHANGED_CFG("incoming-num-tcp", incoming_num_tcp, changed_str); + FR_CHECK_CHANGED_CFG("outgoing-interface", num_out_ifs, changed_str); if(cfg->num_out_ifs == newcfg->num_out_ifs) { for(i=0; i<cfg->num_out_ifs; i++) - fr_check_changed_cfg(strcmp(cfg->out_ifs[i], - newcfg->out_ifs[i]) != 0, "outgoing-interface", - changed_str, sizeof(changed_str)); + FR_CHECK_CHANGED_CFG_STR("outgoing-interface", + out_ifs[i], changed_str); } - fr_check_changed_cfg(cfg->num_ifs != newcfg->num_ifs, - "interface", changed_str, sizeof(changed_str)); + FR_CHECK_CHANGED_CFG("interface", num_ifs, changed_str); if(cfg->num_ifs == newcfg->num_ifs) { for(i=0; i<cfg->num_ifs; i++) - fr_check_changed_cfg(strcmp(cfg->ifs[i], - newcfg->ifs[i]) != 0, "interface", - changed_str, sizeof(changed_str)); - } - fr_check_changed_cfg(cfg->if_automatic != newcfg->if_automatic, - "interface-automatic", changed_str, sizeof(changed_str)); - fr_check_changed_cfg(cfg->so_rcvbuf != newcfg->so_rcvbuf, - "so-rcvbuf", changed_str, sizeof(changed_str)); - fr_check_changed_cfg(cfg->so_sndbuf != newcfg->so_sndbuf, - "so-sndbuf", changed_str, sizeof(changed_str)); - fr_check_changed_cfg(cfg->so_reuseport != newcfg->so_reuseport, - "so-reuseport", changed_str, sizeof(changed_str)); - fr_check_changed_cfg(cfg->ip_transparent != newcfg->ip_transparent, - "ip-transparent", changed_str, sizeof(changed_str)); - fr_check_changed_cfg(cfg->ip_freebind != newcfg->ip_freebind, - "ip-freebind", changed_str, sizeof(changed_str)); - fr_check_changed_cfg(cfg->udp_connect != newcfg->udp_connect, - "udp-connect", changed_str, sizeof(changed_str)); - fr_check_changed_cfg(cfg->msg_buffer_size != newcfg->msg_buffer_size, - "msg-buffer-size", changed_str, sizeof(changed_str)); - fr_check_changed_cfg(cfg->do_tcp_keepalive != newcfg->do_tcp_keepalive, - "edns-tcp-keepalive", changed_str, sizeof(changed_str)); - fr_check_changed_cfg( - cfg->tcp_keepalive_timeout != newcfg->tcp_keepalive_timeout, - "edns-tcp-keepalive-timeout", changed_str, sizeof(changed_str)); - fr_check_changed_cfg(cfg->tcp_idle_timeout != newcfg->tcp_idle_timeout, - "tcp-idle-timeout", changed_str, sizeof(changed_str)); + FR_CHECK_CHANGED_CFG_STR("interface", + ifs[i], changed_str); + } + FR_CHECK_CHANGED_CFG("interface-automatic", if_automatic, changed_str); + FR_CHECK_CHANGED_CFG("so-rcvbuf", so_rcvbuf, changed_str); + FR_CHECK_CHANGED_CFG("so-sndbuf", so_sndbuf, changed_str); + FR_CHECK_CHANGED_CFG("so-reuseport", so_reuseport, changed_str); + FR_CHECK_CHANGED_CFG("ip-transparent", ip_transparent, changed_str); + FR_CHECK_CHANGED_CFG("ip-freebind", ip_freebind, changed_str); + FR_CHECK_CHANGED_CFG("udp-connect", udp_connect, changed_str); + FR_CHECK_CHANGED_CFG("msg-buffer-size", msg_buffer_size, changed_str); + FR_CHECK_CHANGED_CFG("edns-tcp-keepalive", do_tcp_keepalive, changed_str); + FR_CHECK_CHANGED_CFG("edns-tcp-keepalive-timeout", tcp_keepalive_timeout, changed_str); + FR_CHECK_CHANGED_CFG("tcp-idle-timeout", tcp_idle_timeout, changed_str); /* Not changed, only if DoH is used, it is then stored in commpoints, * as well as used from cfg. */ - fr_check_changed_cfg( - cfg->harden_large_queries != newcfg->harden_large_queries, - "harden-large-queries", changed_str, sizeof(changed_str)); - fr_check_changed_cfg(cfg->http_max_streams != newcfg->http_max_streams, - "http-max-streams", changed_str, sizeof(changed_str)); - fr_check_changed_cfg_str(cfg->http_endpoint, newcfg->http_endpoint, - "http-endpoint", changed_str, sizeof(changed_str)); - fr_check_changed_cfg( - cfg->http_notls_downstream != newcfg->http_notls_downstream, - "http_notls_downstream", changed_str, sizeof(changed_str)); - fr_check_changed_cfg(cfg->https_port != newcfg->https_port, - "https-port", changed_str, sizeof(changed_str)); - fr_check_changed_cfg(cfg->ssl_port != newcfg->ssl_port, - "tls-port", changed_str, sizeof(changed_str)); - fr_check_changed_cfg_str(cfg->ssl_service_key, newcfg->ssl_service_key, - "tls-service-key", changed_str, sizeof(changed_str)); - fr_check_changed_cfg_str(cfg->ssl_service_pem, newcfg->ssl_service_pem, - "tls-service-pem", changed_str, sizeof(changed_str)); - fr_check_changed_cfg_str(cfg->tls_cert_bundle, newcfg->tls_cert_bundle, - "tls-cert-bundle", changed_str, sizeof(changed_str)); - fr_check_changed_cfg_strlist(cfg->proxy_protocol_port, - newcfg->proxy_protocol_port, "proxy-protocol-port", - changed_str, sizeof(changed_str)); - fr_check_changed_cfg_strlist(cfg->tls_additional_port, - newcfg->tls_additional_port, "tls-additional-port", - changed_str, sizeof(changed_str)); - fr_check_changed_cfg_str(cfg->if_automatic_ports, - newcfg->if_automatic_ports, "interface-automatic-ports", - changed_str, sizeof(changed_str)); - fr_check_changed_cfg(cfg->udp_upstream_without_downstream != - newcfg->udp_upstream_without_downstream, - "udp-upstream-without-downstream", changed_str, - sizeof(changed_str)); + FR_CHECK_CHANGED_CFG("harden-large-queries", harden_large_queries, changed_str); + FR_CHECK_CHANGED_CFG("http-max-streams", http_max_streams, changed_str); + FR_CHECK_CHANGED_CFG_STR("http-endpoint", http_endpoint, changed_str); + FR_CHECK_CHANGED_CFG("http_notls_downstream", http_notls_downstream, changed_str); + FR_CHECK_CHANGED_CFG("https-port", https_port, changed_str); + FR_CHECK_CHANGED_CFG("tls-port", ssl_port, changed_str); + FR_CHECK_CHANGED_CFG_STR("tls-service-key", ssl_service_key, changed_str); + FR_CHECK_CHANGED_CFG_STR("tls-service-pem", ssl_service_pem, changed_str); + FR_CHECK_CHANGED_CFG_STR("tls-cert-bundle", tls_cert_bundle, changed_str); + FR_CHECK_CHANGED_CFG_STRLIST("proxy-protocol-port", proxy_protocol_port, changed_str); + FR_CHECK_CHANGED_CFG_STRLIST("tls-additional-port", tls_additional_port, changed_str); + FR_CHECK_CHANGED_CFG_STR("interface-automatic-ports", if_automatic_ports, changed_str); + FR_CHECK_CHANGED_CFG("udp-upstream-without-downstream", udp_upstream_without_downstream, changed_str); if(changed_str[0] != 0) { /* The new config changes some items that do not work with @@ -4549,7 +4956,7 @@ fr_check_compat_cfg(struct fast_reload_thread* fr, struct config_file* newcfg) /** fast reload thread, check nopause config items */ static int -fr_check_nopause_cfg(struct fast_reload_thread* fr, struct config_file* newcfg) +fr_check_nopause_compat_cfg(struct fast_reload_thread* fr, struct config_file* newcfg) { char changed_str[1024]; struct config_file* cfg = fr->worker->env.cfg; @@ -4558,94 +4965,43 @@ fr_check_nopause_cfg(struct fast_reload_thread* fr, struct config_file* newcfg) changed_str[0]=0; /* Check for iter_env. */ - fr_check_changed_cfg( - cfg->outbound_msg_retry != newcfg->outbound_msg_retry, - "outbound-msg-retry", changed_str, sizeof(changed_str)); - fr_check_changed_cfg(cfg->max_sent_count != newcfg->max_sent_count, - "max-sent-count", changed_str, sizeof(changed_str)); - fr_check_changed_cfg( - cfg->max_query_restarts != newcfg->max_query_restarts, - "max-query-restarts", changed_str, sizeof(changed_str)); - fr_check_changed_cfg(strcmp(cfg->target_fetch_policy, - newcfg->target_fetch_policy) != 0, - "target-fetch-policy", changed_str, sizeof(changed_str)); - fr_check_changed_cfg( - cfg->donotquery_localhost != newcfg->donotquery_localhost, - "do-not-query-localhost", changed_str, sizeof(changed_str)); - fr_check_changed_cfg_strlist(cfg->donotqueryaddrs, - newcfg->donotqueryaddrs, "do-not-query-localhost", - changed_str, sizeof(changed_str)); - fr_check_changed_cfg_strlist(cfg->private_address, - newcfg->private_address, "private-address", - changed_str, sizeof(changed_str)); - fr_check_changed_cfg_strlist(cfg->private_domain, - newcfg->private_domain, "private-domain", - changed_str, sizeof(changed_str)); - fr_check_changed_cfg_strlist(cfg->caps_whitelist, - newcfg->caps_whitelist, "caps-exempt", - changed_str, sizeof(changed_str)); - fr_check_changed_cfg(cfg->do_nat64 != newcfg->do_nat64, - "do-nat64", changed_str, sizeof(changed_str)); - fr_check_changed_cfg_str(cfg->nat64_prefix, newcfg->nat64_prefix, - "nat64-prefix", changed_str, sizeof(changed_str)); + FR_CHECK_CHANGED_CFG("outbound-msg-retry", outbound_msg_retry, changed_str); + FR_CHECK_CHANGED_CFG("max-sent-count", max_sent_count, changed_str); + FR_CHECK_CHANGED_CFG("max-query-restarts", max_query_restarts, changed_str); + FR_CHECK_CHANGED_CFG_STR("target-fetch-policy", target_fetch_policy, changed_str); + FR_CHECK_CHANGED_CFG("do-not-query-localhost", donotquery_localhost, changed_str); + FR_CHECK_CHANGED_CFG_STRLIST("do-not-query-address", donotqueryaddrs, changed_str); + FR_CHECK_CHANGED_CFG_STRLIST("private-address", private_address, changed_str); + FR_CHECK_CHANGED_CFG_STRLIST("private-domain", private_domain, changed_str); + FR_CHECK_CHANGED_CFG_STRLIST("caps-exempt", caps_whitelist, changed_str); + FR_CHECK_CHANGED_CFG("do-nat64", do_nat64, changed_str); + FR_CHECK_CHANGED_CFG_STR("nat64-prefix", nat64_prefix, changed_str); /* Check for val_env. */ - fr_check_changed_cfg(cfg->bogus_ttl != newcfg->bogus_ttl, - "val-bogus-ttl", changed_str, sizeof(changed_str)); - fr_check_changed_cfg( - cfg->val_date_override != newcfg->val_date_override, - "val-date-override", changed_str, sizeof(changed_str)); - fr_check_changed_cfg(cfg->val_sig_skew_min != newcfg->val_sig_skew_min, - "val-sig-skew-min", changed_str, sizeof(changed_str)); - fr_check_changed_cfg(cfg->val_sig_skew_max != newcfg->val_sig_skew_max, - "val-sig-skew-max", changed_str, sizeof(changed_str)); - fr_check_changed_cfg(cfg->val_max_restart != newcfg->val_max_restart, - "val-max-restart", changed_str, sizeof(changed_str)); - fr_check_changed_cfg(strcmp(cfg->val_nsec3_key_iterations, - newcfg->val_nsec3_key_iterations) != 0, - "val-nsec3-keysize-iterations", changed_str, - sizeof(changed_str)); + FR_CHECK_CHANGED_CFG("val-bogus-ttl", bogus_ttl, changed_str); + FR_CHECK_CHANGED_CFG("val-date-override", val_date_override, changed_str); + FR_CHECK_CHANGED_CFG("val-sig-skew-min", val_sig_skew_min, changed_str); + FR_CHECK_CHANGED_CFG("val-sig-skew-max", val_sig_skew_max, changed_str); + FR_CHECK_CHANGED_CFG("val-max-restart", val_max_restart, changed_str); + FR_CHECK_CHANGED_CFG_STR("val-nsec3-keysize-iterations", + val_nsec3_key_iterations, changed_str); /* Check for infra. */ - fr_check_changed_cfg(cfg->host_ttl != newcfg->host_ttl, - "infra-host-ttl", changed_str, sizeof(changed_str)); - fr_check_changed_cfg( - cfg->infra_keep_probing != newcfg->infra_keep_probing, - "infra-keep-probing", changed_str, sizeof(changed_str)); - fr_check_changed_cfg( - cfg->ratelimit != newcfg->ratelimit, - "ratelimit", changed_str, sizeof(changed_str)); - fr_check_changed_cfg( - cfg->ip_ratelimit != newcfg->ip_ratelimit, - "ip-ratelimit", changed_str, sizeof(changed_str)); - fr_check_changed_cfg( - cfg->ip_ratelimit_cookie != newcfg->ip_ratelimit_cookie, - "ip-ratelimit-cookie", changed_str, sizeof(changed_str)); - fr_check_changed_cfg_str2list(cfg->wait_limit_netblock, - newcfg->wait_limit_netblock, "wait-limit-netblock", - changed_str, sizeof(changed_str)); - fr_check_changed_cfg_str2list(cfg->wait_limit_cookie_netblock, - newcfg->wait_limit_cookie_netblock, - "wait-limit-cookie-netblock", changed_str, - sizeof(changed_str)); - fr_check_changed_cfg_str2list(cfg->ratelimit_below_domain, - newcfg->ratelimit_below_domain, "ratelimit-below-domain", - changed_str, sizeof(changed_str)); - fr_check_changed_cfg_str2list(cfg->ratelimit_for_domain, - newcfg->ratelimit_for_domain, "ratelimit-for-domain", - changed_str, sizeof(changed_str)); + FR_CHECK_CHANGED_CFG("infra-host-ttl", host_ttl, changed_str); + FR_CHECK_CHANGED_CFG("infra-keep-probing", infra_keep_probing, changed_str); + FR_CHECK_CHANGED_CFG("ratelimit", ratelimit, changed_str); + FR_CHECK_CHANGED_CFG("ip-ratelimit", ip_ratelimit, changed_str); + FR_CHECK_CHANGED_CFG("ip-ratelimit-cookie", ip_ratelimit_cookie, changed_str); + FR_CHECK_CHANGED_CFG_STR2LIST("wait-limit-netblock", wait_limit_netblock, changed_str); + FR_CHECK_CHANGED_CFG_STR2LIST("wait-limit-cookie-netblock", wait_limit_cookie_netblock, changed_str); + FR_CHECK_CHANGED_CFG_STR2LIST("ratelimit-below-domain", ratelimit_below_domain, changed_str); + FR_CHECK_CHANGED_CFG_STR2LIST("ratelimit-for-domain", ratelimit_for_domain, changed_str); /* Check for dnstap. */ - fr_check_changed_cfg( - cfg->dnstap_send_identity != newcfg->dnstap_send_identity, - "dnstap-send-identity", changed_str, sizeof(changed_str)); - fr_check_changed_cfg( - cfg->dnstap_send_version != newcfg->dnstap_send_version, - "dnstap-send-version", changed_str, sizeof(changed_str)); - fr_check_changed_cfg_str(cfg->dnstap_identity, newcfg->dnstap_identity, - "dnstap-identity", changed_str, sizeof(changed_str)); - fr_check_changed_cfg_str(cfg->dnstap_version, newcfg->dnstap_version, - "dnstap-version", changed_str, sizeof(changed_str)); + FR_CHECK_CHANGED_CFG("dnstap-send-identity", dnstap_send_identity, changed_str); + FR_CHECK_CHANGED_CFG("dnstap-send-version", dnstap_send_version, changed_str); + FR_CHECK_CHANGED_CFG_STR("dnstap-identity", dnstap_identity, changed_str); + FR_CHECK_CHANGED_CFG_STR("dnstap-version", dnstap_version, changed_str); if(changed_str[0] != 0) { /* The new config changes some items that need a pause, @@ -5507,7 +5863,7 @@ fr_atomic_copy_cfg(struct config_file* oldcfg, struct config_file* cfg, COPY_VAR_ptr(tls_cert_bundle); COPY_VAR_int(tls_win_cert); COPY_VAR_ptr(tls_additional_port); - /* The first is used to walk throught the list but last is + /* The first is used to walk through the list but last is * only used during config read. */ COPY_VAR_ptr(tls_session_ticket_keys.first); COPY_VAR_ptr(tls_session_ticket_keys.last); @@ -5694,7 +6050,7 @@ fr_atomic_copy_cfg(struct config_file* oldcfg, struct config_file* cfg, tagname, num_tags */ COPY_VAR_int(remote_control_enable); - /* The first is used to walk throught the list but last is + /* The first is used to walk through the list but last is * only used during config read. */ COPY_VAR_ptr(control_ifs.first); COPY_VAR_ptr(control_ifs.last); @@ -6193,7 +6549,7 @@ fr_load_config(struct fast_reload_thread* fr, struct timeval* time_read, config_delete(newcfg); return 0; } - if(!fr_check_nopause_cfg(fr, newcfg)) { + if(!fr_check_nopause_compat_cfg(fr, newcfg)) { config_delete(newcfg); return 0; } @@ -7131,6 +7487,7 @@ fr_worker_auth_add(struct worker* worker, struct fast_reload_auth_change* item, xfr->serial = 0; } } + auth_zone_pickup_initial_zone(item->new_z, &worker->env); lock_rw_unlock(&item->new_z->lock); lock_rw_unlock(&worker->env.auth_zones->lock); lock_rw_unlock(&worker->daemon->fast_reload_thread->old_auth_zones->lock); @@ -7257,7 +7614,7 @@ void fast_reload_worker_pickup_changes(struct worker* worker) { /* The pickup of changes is called when the fast reload has - * a syncronized moment, and all the threads are paused and the + * a synchronized moment, and all the threads are paused and the * reload has been applied. Then the worker can pick up the new * changes and store them in worker-specific structs. * The pickup is also called when there is no pause, and then diff --git a/contrib/unbound/daemon/stats.c b/contrib/unbound/daemon/stats.c index 7efb83a0bc3f..41c4656aaec5 100644 --- a/contrib/unbound/daemon/stats.c +++ b/contrib/unbound/daemon/stats.c @@ -273,6 +273,7 @@ server_stats_compile(struct worker* worker, struct ub_stats_info* s, int reset) /* add in the values from the mesh */ s->svr.ans_secure += (long long)worker->env.mesh->ans_secure; s->svr.ans_bogus += (long long)worker->env.mesh->ans_bogus; + s->svr.val_ops += (long long)worker->env.mesh->val_ops; s->svr.ans_rcode_nodata += (long long)worker->env.mesh->ans_nodata; s->svr.ans_expired += (long long)worker->env.mesh->ans_expired; for(i=0; i<UB_STATS_RCODE_NUM; i++) @@ -495,6 +496,7 @@ void server_stats_add(struct ub_stats_info* total, struct ub_stats_info* a) total->svr.ans_rcode_nodata += a->svr.ans_rcode_nodata; total->svr.ans_secure += a->svr.ans_secure; total->svr.ans_bogus += a->svr.ans_bogus; + total->svr.val_ops += a->svr.val_ops; 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; diff --git a/contrib/unbound/daemon/unbound.c b/contrib/unbound/daemon/unbound.c index 8e59bb25a725..164d0fb89509 100644 --- a/contrib/unbound/daemon/unbound.c +++ b/contrib/unbound/daemon/unbound.c @@ -174,7 +174,7 @@ static void checkrlimits(struct config_file* cfg) { #ifndef S_SPLINT_S -#ifdef HAVE_GETRLIMIT +#if defined(HAVE_GETRLIMIT) && !defined(unbound_testbound) /* 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)); @@ -463,11 +463,11 @@ detach(void) #endif /* HAVE_DAEMON */ } +#ifdef HAVE_SSL /* setup a listening ssl context, fatal_exit() on any failure */ static void setup_listen_sslctx(void** ctx, int is_dot, int is_doh, struct config_file* cfg) { -#ifdef HAVE_SSL if(!(*ctx = listen_sslctx_create( cfg->ssl_service_key, cfg->ssl_service_pem, NULL, cfg->tls_ciphers, cfg->tls_ciphersuites, @@ -476,10 +476,8 @@ setup_listen_sslctx(void** ctx, int is_dot, int is_doh, struct config_file* cfg) is_dot, is_doh))) { fatal_exit("could not set up listen SSL_CTX"); } -#else /* HAVE_SSL */ - (void)ctx;(void)is_dot;(void)is_doh;(void)cfg; -#endif /* HAVE_SSL */ } +#endif /* HAVE_SSL */ /* setups the needed ssl contexts, fatal_exit() on any failure */ static void @@ -747,6 +745,7 @@ run_daemon(const char* cfgfile, int cmdline_verbose, int debug_mode, int need_pi "the commandline to see more errors, " "or unbound-checkconf", cfgfile); log_warn("Continuing with default config settings"); + config_auto_slab_values(cfg); } apply_settings(daemon, cfg, cmdline_verbose, debug_mode); if(!done_setup) diff --git a/contrib/unbound/daemon/worker.c b/contrib/unbound/daemon/worker.c index ead20938e172..8e4a9b3d650a 100644 --- a/contrib/unbound/daemon/worker.c +++ b/contrib/unbound/daemon/worker.c @@ -1707,6 +1707,7 @@ worker_handle_request(struct comm_point* c, void* arg, int error, repinfo->client_addrlen, edns.cookie_valid, c->buffer)) { worker->stats.num_queries_ip_ratelimited++; + regional_free_all(worker->scratchpad); comm_point_drop_reply(repinfo); return 0; } @@ -1818,8 +1819,9 @@ worker_handle_request(struct comm_point* c, void* arg, int error, goto send_reply; } if(worker->env.auth_zones && - auth_zones_answer(worker->env.auth_zones, &worker->env, - &qinfo, &edns, repinfo, c->buffer, worker->scratchpad)) { + auth_zones_downstream_answer(worker->env.auth_zones, + &worker->env, &qinfo, &edns, repinfo, c->buffer, + worker->scratchpad)) { regional_free_all(worker->scratchpad); if(sldns_buffer_limit(c->buffer) == 0) { comm_point_drop_reply(repinfo); @@ -1872,20 +1874,11 @@ worker_handle_request(struct comm_point* c, void* arg, int error, /* 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"); + if(!local_alias_shallow_copy_qname(qinfo.local_alias, &qinfo.qname, + &qinfo.qname_len)) { 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 |