Home | History | Annotate | Line # | Download | only in daemon
      1 /*
      2  * daemon/cachedump.c - dump the cache to text format.
      3  *
      4  * Copyright (c) 2008, NLnet Labs. All rights reserved.
      5  *
      6  * This software is open source.
      7  *
      8  * Redistribution and use in source and binary forms, with or without
      9  * modification, are permitted provided that the following conditions
     10  * are met:
     11  *
     12  * Redistributions of source code must retain the above copyright notice,
     13  * this list of conditions and the following disclaimer.
     14  *
     15  * Redistributions in binary form must reproduce the above copyright notice,
     16  * this list of conditions and the following disclaimer in the documentation
     17  * and/or other materials provided with the distribution.
     18  *
     19  * Neither the name of the NLNET LABS nor the names of its contributors may
     20  * be used to endorse or promote products derived from this software without
     21  * specific prior written permission.
     22  *
     23  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     24  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     25  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     26  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     27  * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     28  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
     29  * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
     30  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
     31  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
     32  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
     33  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     34  */
     35 
     36 /**
     37  * \file
     38  *
     39  * This file contains functions to read and write the cache(s)
     40  * to text format.
     41  */
     42 #include "config.h"
     43 #include <openssl/ssl.h>
     44 #include "daemon/cachedump.h"
     45 #include "daemon/remote.h"
     46 #include "daemon/worker.h"
     47 #include "services/cache/rrset.h"
     48 #include "services/cache/dns.h"
     49 #include "services/cache/infra.h"
     50 #include "services/outside_network.h"
     51 #include "util/data/msgreply.h"
     52 #include "util/regional.h"
     53 #include "util/net_help.h"
     54 #include "util/data/dname.h"
     55 #include "util/config_file.h"
     56 #include "iterator/iterator.h"
     57 #include "iterator/iter_delegpt.h"
     58 #include "iterator/iter_utils.h"
     59 #include "iterator/iter_fwd.h"
     60 #include "iterator/iter_hints.h"
     61 #include "sldns/sbuffer.h"
     62 #include "sldns/wire2str.h"
     63 #include "sldns/str2wire.h"
     64 
     65 static void spool_txt_printf(struct config_strlist_head* txt,
     66 	const char* format, ...) ATTR_FORMAT(printf, 2, 3);
     67 
     68 /** Append to strlist at end, and log error if out of memory. */
     69 static void
     70 spool_txt_string(struct config_strlist_head* txt, char* str)
     71 {
     72 	if(!cfg_strlist_append(txt, strdup(str))) {
     73 		log_err("out of memory in spool text");
     74 	}
     75 }
     76 
     77 /** Spool txt to spool list. */
     78 static void
     79 spool_txt_vmsg(struct config_strlist_head* txt, const char* format,
     80 	va_list args)
     81 {
     82 	char msg[65535];
     83 	vsnprintf(msg, sizeof(msg), format, args);
     84 	spool_txt_string(txt, msg);
     85 }
     86 
     87 /** Print item to spool list. On alloc failure the list is as before. */
     88 static void
     89 spool_txt_printf(struct config_strlist_head* txt, const char* format, ...)
     90 {
     91 	va_list args;
     92 	va_start(args, format);
     93 	spool_txt_vmsg(txt, format, args);
     94 	va_end(args);
     95 }
     96 
     97 /** dump one rrset zonefile line */
     98 static void
     99 dump_rrset_line(struct config_strlist_head* txt, struct ub_packed_rrset_key* k,
    100 	time_t now, size_t i)
    101 {
    102 	char s[65535*4+2048];
    103 	if(!packed_rr_to_string(k, i, now, s, sizeof(s))) {
    104 		spool_txt_string(txt, "BADRR\n");
    105 		return;
    106 	}
    107 	spool_txt_string(txt, s);
    108 }
    109 
    110 /** dump rrset key and data info */
    111 static void
    112 dump_rrset(struct config_strlist_head* txt, struct ub_packed_rrset_key* k,
    113 	struct packed_rrset_data* d, time_t now)
    114 {
    115 	size_t i;
    116 	/* rd lock held by caller */
    117 	if(!k || !d) return;
    118 	if(k->id == 0) return; /* deleted */
    119 	if(d->ttl < now) return; /* expired */
    120 
    121 	/* meta line */
    122 	spool_txt_printf(txt, ";rrset%s " ARG_LL "d %u %u %d %d\n",
    123 		(k->rk.flags & PACKED_RRSET_NSEC_AT_APEX)?" nsec_apex":"",
    124 		(long long)(d->ttl - now),
    125 		(unsigned)d->count, (unsigned)d->rrsig_count,
    126 		(int)d->trust, (int)d->security
    127 		);
    128 	for(i=0; i<d->count + d->rrsig_count; i++) {
    129 		dump_rrset_line(txt, k, now, i);
    130 	}
    131 }
    132 
    133 /** Spool strlist to the output. */
    134 static int
    135 spool_strlist(RES* ssl, struct config_strlist* list)
    136 {
    137 	struct config_strlist* s;
    138 	for(s=list; s; s=s->next) {
    139 		if(!ssl_printf(ssl, "%s", s->str))
    140 			return 0;
    141 	}
    142 	return 1;
    143 }
    144 
    145 /** dump lruhash cache and call callback for every item. */
    146 static int
    147 dump_lruhash(struct lruhash* table,
    148 	void (*func)(struct lruhash_entry*, struct config_strlist_head*, void*),
    149 	RES* ssl, void* arg)
    150 {
    151 	int just_started = 1;
    152 	int not_done = 1;
    153 	hashvalue_type hash;
    154 	size_t num = 0; /* number of entries processed. */
    155 	size_t max = 2; /* number of entries after which it unlocks. */
    156 	struct config_strlist_head txt; /* Text strings spooled. */
    157 	memset(&txt, 0, sizeof(txt));
    158 
    159 	while(not_done) {
    160 		size_t i; /* hash bin. */
    161 		/* Process a number of items. */
    162 		num = 0;
    163 		lock_quick_lock(&table->lock);
    164 		if(just_started) {
    165 			i = 0;
    166 		} else {
    167 			i = hash&table->size_mask;
    168 		}
    169 		while(num < max) {
    170 			/* Process bin. */
    171 			int found = 0;
    172 			size_t num_bin = 0;
    173 			struct lruhash_bin* bin = &table->array[i];
    174 			struct lruhash_entry* e;
    175 			lock_quick_lock(&bin->lock);
    176 			for(e = bin->overflow_list; e; e = e->overflow_next) {
    177 				/* Entry e is locked by the func. */
    178 				func(e, &txt, arg);
    179 				num_bin++;
    180 			}
    181 			lock_quick_unlock(&bin->lock);
    182 			/* This addition of bin number of entries may take
    183 			 * it over the max. */
    184 			num += num_bin;
    185 
    186 			/* Move to next bin. */
    187 			/* Find one with an entry, with a  hash value, so we
    188 			 * can continue from the hash value. The hash value
    189 			 * can be indexed also if the array changes size. */
    190 			i++;
    191 			while(i < table->size) {
    192 				bin = &table->array[i];
    193 				lock_quick_lock(&bin->lock);
    194 				if(bin->overflow_list) {
    195 					hash = bin->overflow_list->hash;
    196 					lock_quick_unlock(&bin->lock);
    197 					found = 1;
    198 					just_started = 0;
    199 					break;
    200 				}
    201 				lock_quick_unlock(&bin->lock);
    202 				i++;
    203 			}
    204 			if(!found) {
    205 				not_done = 0;
    206 				break;
    207 			}
    208 		}
    209 		lock_quick_unlock(&table->lock);
    210 		/* Print the spooled items, that are collected while the
    211 		 * locks are locked. The print happens while they are not
    212 		 * locked. */
    213 		if(txt.first) {
    214 			if(!spool_strlist(ssl, txt.first)) {
    215 				config_delstrlist(txt.first);
    216 				return 0;
    217 			}
    218 			config_delstrlist(txt.first);
    219 			memset(&txt, 0, sizeof(txt));
    220 		}
    221 	}
    222 	/* Print the final spooled items. */
    223 	if(txt.first) {
    224 		if(!spool_strlist(ssl, txt.first)) {
    225 			config_delstrlist(txt.first);
    226 			return 0;
    227 		}
    228 		config_delstrlist(txt.first);
    229 	}
    230 	return 1;
    231 }
    232 
    233 /** dump slabhash cache and call callback for every item. */
    234 static int
    235 dump_slabhash(struct slabhash* sh,
    236 	void (*func)(struct lruhash_entry*, struct config_strlist_head*, void*),
    237 	RES* ssl, void* arg)
    238 {
    239 	/* Process a number of items at a time, then unlock the cache,
    240 	 * so that ordinary processing can continue. Keep an iteration marker
    241 	 * to continue the loop. That means the cache can change, items
    242 	 * could be inserted and deleted. And, for example, the hash table
    243 	 * can grow. */
    244 	size_t slab;
    245 	for(slab=0; slab<sh->size; slab++) {
    246 		if(!dump_lruhash(sh->array[slab], func, ssl, arg))
    247 			return 0;
    248 	}
    249 	return 1;
    250 }
    251 
    252 /** Struct for dump information. */
    253 struct dump_info {
    254 	/** The worker. */
    255 	struct worker* worker;
    256 	/** The printout connection. */
    257 	RES* ssl;
    258 };
    259 
    260 /** Dump the rrset cache entry */
    261 static void
    262 dump_rrset_entry(struct lruhash_entry* e, struct config_strlist_head* txt,
    263 	void* arg)
    264 {
    265 	struct dump_info* dump_info = (struct dump_info*)arg;
    266 	lock_rw_rdlock(&e->lock);
    267 	dump_rrset(txt, (struct ub_packed_rrset_key*)e->key,
    268 		(struct packed_rrset_data*)e->data,
    269 		*dump_info->worker->env.now);
    270 	lock_rw_unlock(&e->lock);
    271 }
    272 
    273 /** dump rrset cache */
    274 static int
    275 dump_rrset_cache(RES* ssl, struct worker* worker)
    276 {
    277 	struct rrset_cache* r = worker->env.rrset_cache;
    278 	struct dump_info dump_info;
    279 	dump_info.worker = worker;
    280 	dump_info.ssl = ssl;
    281 	if(!ssl_printf(ssl, "START_RRSET_CACHE\n")) return 0;
    282 	if(!dump_slabhash(&r->table, &dump_rrset_entry, ssl, &dump_info))
    283 		return 0;
    284 	return ssl_printf(ssl, "END_RRSET_CACHE\n");
    285 }
    286 
    287 /** dump message to rrset reference */
    288 static void
    289 dump_msg_ref(struct config_strlist_head* txt, struct ub_packed_rrset_key* k)
    290 {
    291 	char* nm, *tp, *cl;
    292 	nm = sldns_wire2str_dname(k->rk.dname, k->rk.dname_len);
    293 	tp = sldns_wire2str_type(ntohs(k->rk.type));
    294 	cl = sldns_wire2str_class(ntohs(k->rk.rrset_class));
    295 	if(!nm || !cl || !tp) {
    296 		free(nm);
    297 		free(tp);
    298 		free(cl);
    299 		spool_txt_string(txt, "BADREF\n");
    300 		return;
    301 	}
    302 	spool_txt_printf(txt, "%s %s %s %d\n", nm, cl, tp, (int)k->rk.flags);
    303 	free(nm);
    304 	free(tp);
    305 	free(cl);
    306 }
    307 
    308 /** dump message entry */
    309 static void
    310 dump_msg(struct config_strlist_head* txt, struct query_info* k,
    311 	struct reply_info* d, time_t now)
    312 {
    313 	size_t i;
    314 	char* nm, *tp, *cl;
    315 	if(!k || !d) return;
    316 	if(d->ttl < now) return; /* expired */
    317 
    318 	nm = sldns_wire2str_dname(k->qname, k->qname_len);
    319 	tp = sldns_wire2str_type(k->qtype);
    320 	cl = sldns_wire2str_class(k->qclass);
    321 	if(!nm || !tp || !cl) {
    322 		free(nm);
    323 		free(tp);
    324 		free(cl);
    325 		return; /* skip this entry */
    326 	}
    327 	if(!rrset_array_lock(d->ref, d->rrset_count, now)) {
    328 		/* rrsets have timed out or do not exist */
    329 		free(nm);
    330 		free(tp);
    331 		free(cl);
    332 		return; /* skip this entry */
    333 	}
    334 
    335 	/* meta line */
    336 	spool_txt_printf(txt,
    337 		"msg %s %s %s %d %d " ARG_LL "d %d %u %u %u %d %s\n",
    338 		nm, cl, tp,
    339 		(int)d->flags, (int)d->qdcount,
    340 		(long long)(d->ttl-now), (int)d->security,
    341 		(unsigned)d->an_numrrsets,
    342 		(unsigned)d->ns_numrrsets,
    343 		(unsigned)d->ar_numrrsets,
    344 		(int)d->reason_bogus,
    345 		d->reason_bogus_str?d->reason_bogus_str:"");
    346 	free(nm);
    347 	free(tp);
    348 	free(cl);
    349 
    350 	for(i=0; i<d->rrset_count; i++) {
    351 		dump_msg_ref(txt, d->rrsets[i]);
    352 	}
    353 	rrset_array_unlock(d->ref, d->rrset_count);
    354 }
    355 
    356 /** copy msg to worker pad */
    357 static int
    358 copy_msg(struct regional* region, struct lruhash_entry* e,
    359 	struct query_info** k, struct reply_info** d)
    360 {
    361 	struct reply_info* rep = (struct reply_info*)e->data;
    362 	if(rep->rrset_count > RR_COUNT_MAX)
    363 		return 0; /* to protect against integer overflow */
    364 	*d = (struct reply_info*)regional_alloc_init(region, e->data,
    365 		sizeof(struct reply_info) +
    366 		sizeof(struct rrset_ref) * (rep->rrset_count-1) +
    367 		sizeof(struct ub_packed_rrset_key*) * rep->rrset_count);
    368 	if(!*d)
    369 		return 0;
    370 	(*d)->rrsets = (struct ub_packed_rrset_key**)(void *)(
    371 		(uint8_t*)(&((*d)->ref[0])) +
    372 		sizeof(struct rrset_ref) * rep->rrset_count);
    373 	*k = (struct query_info*)regional_alloc_init(region,
    374 		e->key, sizeof(struct query_info));
    375 	if(!*k)
    376 		return 0;
    377 	(*k)->qname = regional_alloc_init(region,
    378 		(*k)->qname, (*k)->qname_len);
    379 	return (*k)->qname != NULL;
    380 }
    381 
    382 /** Dump the msg entry. */
    383 static void
    384 dump_msg_entry(struct lruhash_entry* e, struct config_strlist_head* txt,
    385 	void* arg)
    386 {
    387 	struct dump_info* dump_info = (struct dump_info*)arg;
    388 	struct query_info* k;
    389 	struct reply_info* d;
    390 
    391 	regional_free_all(dump_info->worker->scratchpad);
    392 	/* Make copy of rrset in worker buffer. */
    393 	lock_rw_rdlock(&e->lock);
    394 	if(!copy_msg(dump_info->worker->scratchpad, e, &k, &d)) {
    395 		lock_rw_unlock(&e->lock);
    396 		log_err("out of memory in dump_msg_entry");
    397 		return;
    398 	}
    399 	lock_rw_unlock(&e->lock);
    400 	/* Release lock so we can lookup the rrset references
    401 	 * in the rrset cache. */
    402 	dump_msg(txt, k, d, *dump_info->worker->env.now);
    403 }
    404 
    405 /** dump msg cache */
    406 static int
    407 dump_msg_cache(RES* ssl, struct worker* worker)
    408 {
    409 	struct dump_info dump_info;
    410 	dump_info.worker = worker;
    411 	dump_info.ssl = ssl;
    412 	if(!ssl_printf(ssl, "START_MSG_CACHE\n")) return 0;
    413 	if(!dump_slabhash(worker->env.msg_cache, &dump_msg_entry, ssl,
    414 		&dump_info))
    415 		return 0;
    416 	return ssl_printf(ssl, "END_MSG_CACHE\n");
    417 }
    418 
    419 int
    420 dump_cache(RES* ssl, struct worker* worker)
    421 {
    422 	if(!dump_rrset_cache(ssl, worker))
    423 		return 0;
    424 	if(!dump_msg_cache(ssl, worker))
    425 		return 0;
    426 	return ssl_printf(ssl, "EOF\n");
    427 }
    428 
    429 /** read a line from ssl into buffer */
    430 static int
    431 ssl_read_buf(RES* ssl, sldns_buffer* buf)
    432 {
    433 	return ssl_read_line(ssl, (char*)sldns_buffer_begin(buf),
    434 		sldns_buffer_capacity(buf));
    435 }
    436 
    437 /** check fixed text on line */
    438 static int
    439 read_fixed(RES* ssl, sldns_buffer* buf, const char* str)
    440 {
    441 	if(!ssl_read_buf(ssl, buf)) return 0;
    442 	return (strcmp((char*)sldns_buffer_begin(buf), str) == 0);
    443 }
    444 
    445 /** load an RR into rrset */
    446 static int
    447 load_rr(RES* ssl, sldns_buffer* buf, struct regional* region,
    448 	struct ub_packed_rrset_key* rk, struct packed_rrset_data* d,
    449 	unsigned int i, int is_rrsig, int* go_on, time_t now)
    450 {
    451 	uint8_t rr[LDNS_RR_BUF_SIZE];
    452 	size_t rr_len = sizeof(rr), dname_len = 0;
    453 	int status;
    454 
    455 	/* read the line */
    456 	if(!ssl_read_buf(ssl, buf))
    457 		return 0;
    458 	if(strcmp((char*)sldns_buffer_begin(buf), "BADRR") == 0) {
    459 		*go_on = 0;
    460 		return 1;
    461 	}
    462 	status = sldns_str2wire_rr_buf((char*)sldns_buffer_begin(buf), rr,
    463 		&rr_len, &dname_len, 3600, NULL, 0, NULL, 0);
    464 	if(status != 0) {
    465 		log_warn("error cannot parse rr: %s: %s",
    466 			sldns_get_errorstr_parse(status),
    467 			(char*)sldns_buffer_begin(buf));
    468 		return 0;
    469 	}
    470 	if(is_rrsig && sldns_wirerr_get_type(rr, rr_len, dname_len)
    471 		!= LDNS_RR_TYPE_RRSIG) {
    472 		log_warn("error expected rrsig but got %s",
    473 			(char*)sldns_buffer_begin(buf));
    474 		return 0;
    475 	}
    476 
    477 	/* convert ldns rr into packed_rr */
    478 	d->rr_ttl[i] = (time_t)sldns_wirerr_get_ttl(rr, rr_len, dname_len) + now;
    479 	sldns_buffer_clear(buf);
    480 	d->rr_len[i] = sldns_wirerr_get_rdatalen(rr, rr_len, dname_len)+2;
    481 	d->rr_data[i] = (uint8_t*)regional_alloc_init(region,
    482 		sldns_wirerr_get_rdatawl(rr, rr_len, dname_len), d->rr_len[i]);
    483 	if(!d->rr_data[i]) {
    484 		log_warn("error out of memory");
    485 		return 0;
    486 	}
    487 
    488 	/* if first entry, fill the key structure */
    489 	if(i==0) {
    490 		rk->rk.type = htons(sldns_wirerr_get_type(rr, rr_len, dname_len));
    491 		rk->rk.rrset_class = htons(sldns_wirerr_get_class(rr, rr_len, dname_len));
    492 		rk->rk.dname_len = dname_len;
    493 		rk->rk.dname = regional_alloc_init(region, rr, dname_len);
    494 		if(!rk->rk.dname) {
    495 			log_warn("error out of memory");
    496 			return 0;
    497 		}
    498 	}
    499 
    500 	return 1;
    501 }
    502 
    503 /** move entry into cache */
    504 static int
    505 move_into_cache(struct ub_packed_rrset_key* k,
    506 	struct packed_rrset_data* d, struct worker* worker)
    507 {
    508 	struct ub_packed_rrset_key* ak;
    509 	struct packed_rrset_data* ad;
    510 	size_t s, i, num = d->count + d->rrsig_count;
    511 	struct rrset_ref ref;
    512 	uint8_t* p;
    513 
    514 	ak = alloc_special_obtain(worker->alloc);
    515 	if(!ak) {
    516 		log_warn("error out of memory");
    517 		return 0;
    518 	}
    519 	ak->entry.data = NULL;
    520 	ak->rk = k->rk;
    521 	ak->entry.hash = rrset_key_hash(&k->rk);
    522 	ak->rk.dname = (uint8_t*)memdup(k->rk.dname, k->rk.dname_len);
    523 	if(!ak->rk.dname) {
    524 		log_warn("error out of memory");
    525 		ub_packed_rrset_parsedelete(ak, worker->alloc);
    526 		return 0;
    527 	}
    528 	s = sizeof(*ad) + (sizeof(size_t) + sizeof(uint8_t*) +
    529 		sizeof(time_t))* num;
    530 	for(i=0; i<num; i++)
    531 		s += d->rr_len[i];
    532 	ad = (struct packed_rrset_data*)malloc(s);
    533 	if(!ad) {
    534 		log_warn("error out of memory");
    535 		ub_packed_rrset_parsedelete(ak, worker->alloc);
    536 		return 0;
    537 	}
    538 	p = (uint8_t*)ad;
    539 	memmove(p, d, sizeof(*ad));
    540 	p += sizeof(*ad);
    541 	memmove(p, &d->rr_len[0], sizeof(size_t)*num);
    542 	p += sizeof(size_t)*num;
    543 	memmove(p, &d->rr_data[0], sizeof(uint8_t*)*num);
    544 	p += sizeof(uint8_t*)*num;
    545 	memmove(p, &d->rr_ttl[0], sizeof(time_t)*num);
    546 	p += sizeof(time_t)*num;
    547 	for(i=0; i<num; i++) {
    548 		memmove(p, d->rr_data[i], d->rr_len[i]);
    549 		p += d->rr_len[i];
    550 	}
    551 	packed_rrset_ptr_fixup(ad);
    552 
    553 	ak->entry.data = ad;
    554 
    555 	ref.key = ak;
    556 	ref.id = ak->id;
    557 	(void)rrset_cache_update(worker->env.rrset_cache, &ref,
    558 		worker->alloc, *worker->env.now);
    559 
    560 	return 1;
    561 }
    562 
    563 /** load an rrset entry */
    564 static int
    565 load_rrset(RES* ssl, sldns_buffer* buf, struct worker* worker)
    566 {
    567 	char* s = (char*)sldns_buffer_begin(buf);
    568 	struct regional* region = worker->scratchpad;
    569 	struct ub_packed_rrset_key* rk;
    570 	struct packed_rrset_data* d;
    571 	unsigned int rr_count, rrsig_count, trust, security;
    572 	long long ttl;
    573 	unsigned int i;
    574 	int go_on = 1;
    575 	regional_free_all(region);
    576 
    577 	rk = (struct ub_packed_rrset_key*)regional_alloc_zero(region,
    578 		sizeof(*rk));
    579 	d = (struct packed_rrset_data*)regional_alloc_zero(region, sizeof(*d));
    580 	if(!rk || !d) {
    581 		log_warn("error out of memory");
    582 		return 0;
    583 	}
    584 
    585 	if(strncmp(s, ";rrset", 6) != 0) {
    586 		log_warn("error expected ';rrset' but got %s", s);
    587 		return 0;
    588 	}
    589 	s += 6;
    590 	if(strncmp(s, " nsec_apex", 10) == 0) {
    591 		s += 10;
    592 		rk->rk.flags |= PACKED_RRSET_NSEC_AT_APEX;
    593 	}
    594 	if(sscanf(s, " " ARG_LL "d %u %u %u %u", &ttl, &rr_count, &rrsig_count,
    595 		&trust, &security) != 5) {
    596 		log_warn("error bad rrset spec %s", s);
    597 		return 0;
    598 	}
    599 	if(rr_count == 0 && rrsig_count == 0) {
    600 		log_warn("bad rrset without contents");
    601 		return 0;
    602 	}
    603 	if(rr_count > RR_COUNT_MAX || rrsig_count > RR_COUNT_MAX) {
    604 		log_warn("bad rrset with too many rrs");
    605 		return 0;
    606 	}
    607 	d->count = (size_t)rr_count;
    608 	d->rrsig_count = (size_t)rrsig_count;
    609 	d->security = (enum sec_status)security;
    610 	d->trust = (enum rrset_trust)trust;
    611 	d->ttl = (time_t)ttl + *worker->env.now;
    612 
    613 	d->rr_len = regional_alloc_zero(region,
    614 		sizeof(size_t)*(d->count+d->rrsig_count));
    615 	d->rr_ttl = regional_alloc_zero(region,
    616 		sizeof(time_t)*(d->count+d->rrsig_count));
    617 	d->rr_data = regional_alloc_zero(region,
    618 		sizeof(uint8_t*)*(d->count+d->rrsig_count));
    619 	if(!d->rr_len || !d->rr_ttl || !d->rr_data) {
    620 		log_warn("error out of memory");
    621 		return 0;
    622 	}
    623 
    624 	/* read the rr's themselves */
    625 	for(i=0; i<rr_count; i++) {
    626 		if(!load_rr(ssl, buf, region, rk, d, i, 0,
    627 			&go_on, *worker->env.now)) {
    628 			log_warn("could not read rr %u", i);
    629 			return 0;
    630 		}
    631 	}
    632 	for(i=0; i<rrsig_count; i++) {
    633 		if(!load_rr(ssl, buf, region, rk, d, i+rr_count, 1,
    634 			&go_on, *worker->env.now)) {
    635 			log_warn("could not read rrsig %u", i);
    636 			return 0;
    637 		}
    638 	}
    639 	if(!go_on) {
    640 		/* skip this entry */
    641 		return 1;
    642 	}
    643 
    644 	return move_into_cache(rk, d, worker);
    645 }
    646 
    647 /** load rrset cache */
    648 static int
    649 load_rrset_cache(RES* ssl, struct worker* worker)
    650 {
    651 	sldns_buffer* buf = worker->env.scratch_buffer;
    652 	if(!read_fixed(ssl, buf, "START_RRSET_CACHE")) return 0;
    653 	while(ssl_read_buf(ssl, buf) &&
    654 		strcmp((char*)sldns_buffer_begin(buf), "END_RRSET_CACHE")!=0) {
    655 		if(!load_rrset(ssl, buf, worker))
    656 			return 0;
    657 	}
    658 	return 1;
    659 }
    660 
    661 /** read qinfo from next three words */
    662 static char*
    663 load_qinfo(char* str, struct query_info* qinfo, struct regional* region)
    664 {
    665 	/* s is part of the buf */
    666 	char* s = str;
    667 	uint8_t rr[LDNS_RR_BUF_SIZE];
    668 	size_t rr_len = sizeof(rr), dname_len = 0;
    669 	int status;
    670 
    671 	/* skip three words */
    672 	s = strchr(str, ' ');
    673 	if(s) s = strchr(s+1, ' ');
    674 	if(s) s = strchr(s+1, ' ');
    675 	if(!s) {
    676 		log_warn("error line too short, %s", str);
    677 		return NULL;
    678 	}
    679 	s[0] = 0;
    680 	s++;
    681 
    682 	/* parse them */
    683 	status = sldns_str2wire_rr_question_buf(str, rr, &rr_len, &dname_len,
    684 		NULL, 0, NULL, 0);
    685 	if(status != 0) {
    686 		log_warn("error cannot parse: %s %s",
    687 			sldns_get_errorstr_parse(status), str);
    688 		return NULL;
    689 	}
    690 	qinfo->qtype = sldns_wirerr_get_type(rr, rr_len, dname_len);
    691 	qinfo->qclass = sldns_wirerr_get_class(rr, rr_len, dname_len);
    692 	qinfo->qname_len = dname_len;
    693 	qinfo->qname = (uint8_t*)regional_alloc_init(region, rr, dname_len);
    694 	qinfo->local_alias = NULL;
    695 	if(!qinfo->qname) {
    696 		log_warn("error out of memory");
    697 		return NULL;
    698 	}
    699 
    700 	return s;
    701 }
    702 
    703 /** load a msg rrset reference */
    704 static int
    705 load_ref(RES* ssl, sldns_buffer* buf, struct worker* worker,
    706 	struct regional *region, struct ub_packed_rrset_key** rrset,
    707 	int* go_on)
    708 {
    709 	char* s = (char*)sldns_buffer_begin(buf);
    710 	struct query_info qinfo;
    711 	unsigned int flags;
    712 	struct ub_packed_rrset_key* k;
    713 
    714 	/* read line */
    715 	if(!ssl_read_buf(ssl, buf))
    716 		return 0;
    717 	if(strncmp(s, "BADREF", 6) == 0) {
    718 		*go_on = 0; /* its bad, skip it and skip message */
    719 		return 1;
    720 	}
    721 
    722 	s = load_qinfo(s, &qinfo, region);
    723 	if(!s) {
    724 		return 0;
    725 	}
    726 	if(sscanf(s, " %u", &flags) != 1) {
    727 		log_warn("error cannot parse flags: %s", s);
    728 		return 0;
    729 	}
    730 
    731 	/* lookup in cache */
    732 	k = rrset_cache_lookup(worker->env.rrset_cache, qinfo.qname,
    733 		qinfo.qname_len, qinfo.qtype, qinfo.qclass,
    734 		(uint32_t)flags, *worker->env.now, 0);
    735 	if(!k) {
    736 		/* not found or expired */
    737 		*go_on = 0;
    738 		return 1;
    739 	}
    740 
    741 	/* store in result */
    742 	*rrset = packed_rrset_copy_region(k, region, *worker->env.now);
    743 	lock_rw_unlock(&k->entry.lock);
    744 
    745 	return (*rrset != NULL);
    746 }
    747 
    748 /** load a msg entry */
    749 static int
    750 load_msg(RES* ssl, sldns_buffer* buf, struct worker* worker)
    751 {
    752 	struct regional* region = worker->scratchpad;
    753 	struct query_info qinf;
    754 	struct reply_info rep;
    755 	char* s = (char*)sldns_buffer_begin(buf);
    756 	unsigned int flags, qdcount, security, an, ns, ar;
    757 	long long ttl;
    758 	size_t i;
    759 	int go_on = 1;
    760 	int ede;
    761 	int consumed = 0;
    762 	char* ede_str = NULL;
    763 
    764 	regional_free_all(region);
    765 
    766 	if(strncmp(s, "msg ", 4) != 0) {
    767 		log_warn("error expected msg but got %s", s);
    768 		return 0;
    769 	}
    770 	s += 4;
    771 	s = load_qinfo(s, &qinf, region);
    772 	if(!s) {
    773 		return 0;
    774 	}
    775 
    776 	/* read remainder of line */
    777 	/* note the last space before any possible EDE text */
    778 	if(sscanf(s, " %u %u " ARG_LL "d %u %u %u %u %d %n", &flags, &qdcount, &ttl,
    779 		&security, &an, &ns, &ar, &ede, &consumed) != 8) {
    780 		log_warn("error cannot parse numbers: %s", s);
    781 		return 0;
    782 	}
    783 	/* there may be EDE text after the numbers */
    784 	if(consumed > 0 && (size_t)consumed < strlen(s))
    785 		ede_str = s + consumed;
    786 	memset(&rep, 0, sizeof(rep));
    787 	rep.flags = (uint16_t)flags;
    788 	rep.qdcount = (uint16_t)qdcount;
    789 	rep.ttl = (time_t)ttl;
    790 	rep.prefetch_ttl = PREFETCH_TTL_CALC(rep.ttl);
    791 	rep.serve_expired_ttl = rep.ttl + SERVE_EXPIRED_TTL;
    792 	rep.security = (enum sec_status)security;
    793 	if(an > RR_COUNT_MAX || ns > RR_COUNT_MAX || ar > RR_COUNT_MAX) {
    794 		log_warn("error too many rrsets");
    795 		return 0; /* protect against integer overflow in alloc */
    796 	}
    797 	rep.an_numrrsets = (size_t)an;
    798 	rep.ns_numrrsets = (size_t)ns;
    799 	rep.ar_numrrsets = (size_t)ar;
    800 	rep.rrset_count = (size_t)an+(size_t)ns+(size_t)ar;
    801 	rep.reason_bogus = (sldns_ede_code)ede;
    802 	rep.reason_bogus_str = ede_str?(char*)regional_strdup(region, ede_str):NULL;
    803 	rep.rrsets = (struct ub_packed_rrset_key**)regional_alloc_zero(
    804 		region, sizeof(struct ub_packed_rrset_key*)*rep.rrset_count);
    805 
    806 	/* fill repinfo with references */
    807 	for(i=0; i<rep.rrset_count; i++) {
    808 		if(!load_ref(ssl, buf, worker, region, &rep.rrsets[i],
    809 			&go_on)) {
    810 			return 0;
    811 		}
    812 	}
    813 
    814 	if(!go_on)
    815 		return 1; /* skip this one, not all references satisfied */
    816 
    817 	if(!dns_cache_store(&worker->env, &qinf, &rep, 0, 0, 0, NULL, flags,
    818 		*worker->env.now, 1)) {
    819 		log_warn("error out of memory");
    820 		return 0;
    821 	}
    822 	return 1;
    823 }
    824 
    825 /** load msg cache */
    826 static int
    827 load_msg_cache(RES* ssl, struct worker* worker)
    828 {
    829 	sldns_buffer* buf = worker->env.scratch_buffer;
    830 	if(!read_fixed(ssl, buf, "START_MSG_CACHE")) return 0;
    831 	while(ssl_read_buf(ssl, buf) &&
    832 		strcmp((char*)sldns_buffer_begin(buf), "END_MSG_CACHE")!=0) {
    833 		if(!load_msg(ssl, buf, worker))
    834 			return 0;
    835 	}
    836 	return 1;
    837 }
    838 
    839 int
    840 load_cache(RES* ssl, struct worker* worker)
    841 {
    842 	if(!load_rrset_cache(ssl, worker))
    843 		return 0;
    844 	if(!load_msg_cache(ssl, worker))
    845 		return 0;
    846 	return read_fixed(ssl, worker->env.scratch_buffer, "EOF");
    847 }
    848 
    849 /** print details on a delegation point */
    850 static void
    851 print_dp_details(RES* ssl, struct worker* worker, struct delegpt* dp)
    852 {
    853 	char buf[257];
    854 	struct delegpt_addr* a;
    855 	int lame, dlame, rlame, rto, edns_vs, to, delay,
    856 		tA = 0, tAAAA = 0, tother = 0;
    857 	long long entry_ttl;
    858 	struct rtt_info ri;
    859 	uint8_t edns_lame_known;
    860 	for(a = dp->target_list; a; a = a->next_target) {
    861 		addr_to_str(&a->addr, a->addrlen, buf, sizeof(buf));
    862 		if(!ssl_printf(ssl, "%-16s\t", buf))
    863 			return;
    864 		if(a->bogus) {
    865 			if(!ssl_printf(ssl, "Address is BOGUS. "))
    866 				return;
    867 		}
    868 		/* lookup in infra cache */
    869 		delay=0;
    870 		entry_ttl = infra_get_host_rto(worker->env.infra_cache,
    871 			&a->addr, a->addrlen, dp->name, dp->namelen,
    872 			&ri, &delay, *worker->env.now, &tA, &tAAAA, &tother);
    873 		if(entry_ttl == -2 && ri.rto >= USEFUL_SERVER_TOP_TIMEOUT) {
    874 			if(!ssl_printf(ssl, "expired, rto %d msec, tA %d "
    875 				"tAAAA %d tother %d.\n", ri.rto, tA, tAAAA,
    876 				tother))
    877 				return;
    878 			continue;
    879 		}
    880 		if(entry_ttl == -1 || entry_ttl == -2) {
    881 			if(!ssl_printf(ssl, "not in infra cache.\n"))
    882 				return;
    883 			continue; /* skip stuff not in infra cache */
    884 		}
    885 
    886 		/* uses type_A because most often looked up, but other
    887 		 * lameness won't be reported then */
    888 		if(!infra_get_lame_rtt(worker->env.infra_cache,
    889 			&a->addr, a->addrlen, dp->name, dp->namelen,
    890 			LDNS_RR_TYPE_A, &lame, &dlame, &rlame, &rto,
    891 			*worker->env.now)) {
    892 			if(!ssl_printf(ssl, "not in infra cache.\n"))
    893 				return;
    894 			continue; /* skip stuff not in infra cache */
    895 		}
    896 		if(!ssl_printf(ssl, "%s%s%s%srto %d msec, ttl " ARG_LL "d, "
    897 			"ping %d var %d rtt %d, tA %d, tAAAA %d, tother %d",
    898 			lame?"LAME ":"", dlame?"NoDNSSEC ":"",
    899 			a->lame?"AddrWasParentSide ":"",
    900 			rlame?"NoAuthButRecursive ":"", rto, entry_ttl,
    901 			ri.srtt, ri.rttvar, rtt_notimeout(&ri),
    902 			tA, tAAAA, tother))
    903 			return;
    904 		if(delay)
    905 			if(!ssl_printf(ssl, ", probedelay %d", delay))
    906 				return;
    907 		if(infra_host(worker->env.infra_cache, &a->addr, a->addrlen,
    908 			dp->name, dp->namelen, *worker->env.now, &edns_vs,
    909 			&edns_lame_known, &to)) {
    910 			if(edns_vs == -1) {
    911 				if(!ssl_printf(ssl, ", noEDNS%s.",
    912 					edns_lame_known?" probed":" assumed"))
    913 					return;
    914 			} else {
    915 				if(!ssl_printf(ssl, ", EDNS %d%s.", edns_vs,
    916 					edns_lame_known?" probed":" assumed"))
    917 					return;
    918 			}
    919 		}
    920 		if(!ssl_printf(ssl, "\n"))
    921 			return;
    922 	}
    923 }
    924 
    925 /** print main dp info */
    926 static void
    927 print_dp_main(RES* ssl, struct delegpt* dp, struct dns_msg* msg)
    928 {
    929 	size_t i, n_ns, n_miss, n_addr, n_res, n_avail;
    930 
    931 	/* print the dp */
    932 	if(msg)
    933 	    for(i=0; i<msg->rep->rrset_count; i++) {
    934 		struct ub_packed_rrset_key* k = msg->rep->rrsets[i];
    935 		struct packed_rrset_data* d =
    936 			(struct packed_rrset_data*)k->entry.data;
    937 		struct config_strlist_head txt;
    938 		memset(&txt, 0, sizeof(txt));
    939 		if(d->security == sec_status_bogus) {
    940 			if(!ssl_printf(ssl, "Address is BOGUS:\n"))
    941 				return;
    942 		}
    943 		dump_rrset(&txt, k, d, 0);
    944 		if(!spool_strlist(ssl, txt.first)) {
    945 			config_delstrlist(txt.first);
    946 			return;
    947 		}
    948 		config_delstrlist(txt.first);
    949 	    }
    950 	delegpt_count_ns(dp, &n_ns, &n_miss);
    951 	delegpt_count_addr(dp, &n_addr, &n_res, &n_avail);
    952 	/* since dp has not been used by iterator, all are available*/
    953 	if(!ssl_printf(ssl, "Delegation with %d names, of which %d "
    954 		"can be examined to query further addresses.\n"
    955 		"%sIt provides %d IP addresses.\n",
    956 		(int)n_ns, (int)n_miss, (dp->bogus?"It is BOGUS. ":""),
    957 		(int)n_addr))
    958 		return;
    959 }
    960 
    961 int print_deleg_lookup(RES* ssl, struct worker* worker, uint8_t* nm,
    962 	size_t nmlen, int ATTR_UNUSED(nmlabs))
    963 {
    964 	/* deep links into the iterator module */
    965 	struct delegpt* dp;
    966 	struct dns_msg* msg;
    967 	struct regional* region = worker->scratchpad;
    968 	char b[LDNS_MAX_DOMAINLEN];
    969 	struct query_info qinfo;
    970 	struct iter_hints_stub* stub;
    971 	int nolock = 0;
    972 	regional_free_all(region);
    973 	qinfo.qname = nm;
    974 	qinfo.qname_len = nmlen;
    975 	qinfo.qtype = LDNS_RR_TYPE_A;
    976 	qinfo.qclass = LDNS_RR_CLASS_IN;
    977 	qinfo.local_alias = NULL;
    978 
    979 	dname_str(nm, b);
    980 	if(!ssl_printf(ssl, "The following name servers are used for lookup "
    981 		"of %s\n", b))
    982 		return 0;
    983 
    984 	dp = forwards_lookup(worker->env.fwds, nm, qinfo.qclass, nolock);
    985 	if(dp) {
    986 		if(!ssl_printf(ssl, "forwarding request:\n")) {
    987 			lock_rw_unlock(&worker->env.fwds->lock);
    988 			return 0;
    989 		}
    990 		print_dp_main(ssl, dp, NULL);
    991 		print_dp_details(ssl, worker, dp);
    992 		lock_rw_unlock(&worker->env.fwds->lock);
    993 		return 1;
    994 	}
    995 
    996 	while(1) {
    997 		dp = dns_cache_find_delegation(&worker->env, nm, nmlen,
    998 			qinfo.qtype, qinfo.qclass, region, &msg,
    999 			*worker->env.now, 0, NULL, 0);
   1000 		if(!dp) {
   1001 			return ssl_printf(ssl, "no delegation from "
   1002 				"cache; goes to configured roots\n");
   1003 		}
   1004 		/* go up? */
   1005 		if(iter_dp_is_useless(&qinfo, BIT_RD, dp,
   1006 			(worker->env.cfg->do_ip4 && worker->back->num_ip4 != 0),
   1007 			(worker->env.cfg->do_ip6 && worker->back->num_ip6 != 0),
   1008 			worker->env.cfg->do_nat64)) {
   1009 			print_dp_main(ssl, dp, msg);
   1010 			print_dp_details(ssl, worker, dp);
   1011 			if(!ssl_printf(ssl, "cache delegation was "
   1012 				"useless (no IP addresses)\n"))
   1013 				return 0;
   1014 			if(dname_is_root(nm)) {
   1015 				/* goes to root config */
   1016 				return ssl_printf(ssl, "no delegation from "
   1017 					"cache; goes to configured roots\n");
   1018 			} else {
   1019 				/* useless, goes up */
   1020 				nm = dp->name;
   1021 				nmlen = dp->namelen;
   1022 				dname_remove_label(&nm, &nmlen);
   1023 				dname_str(nm, b);
   1024 				if(!ssl_printf(ssl, "going up, lookup %s\n", b))
   1025 					return 0;
   1026 				continue;
   1027 			}
   1028 		}
   1029 		stub = hints_lookup_stub(worker->env.hints, nm, qinfo.qclass,
   1030 			dp, nolock);
   1031 		if(stub) {
   1032 			if(stub->noprime) {
   1033 				if(!ssl_printf(ssl, "The noprime stub servers "
   1034 					"are used:\n")) {
   1035 					lock_rw_unlock(&worker->env.hints->lock);
   1036 					return 0;
   1037 				}
   1038 			} else {
   1039 				if(!ssl_printf(ssl, "The stub is primed "
   1040 						"with servers:\n")) {
   1041 					lock_rw_unlock(&worker->env.hints->lock);
   1042 					return 0;
   1043 				}
   1044 			}
   1045 			print_dp_main(ssl, stub->dp, NULL);
   1046 			print_dp_details(ssl, worker, stub->dp);
   1047 			lock_rw_unlock(&worker->env.hints->lock);
   1048 		} else {
   1049 			print_dp_main(ssl, dp, msg);
   1050 			print_dp_details(ssl, worker, dp);
   1051 		}
   1052 		break;
   1053 	}
   1054 
   1055 	return 1;
   1056 }
   1057