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 "util/data/msgreply.h"
51 #include "util/regional.h"
52 #include "util/net_help.h"
53 #include "util/data/dname.h"
54 #include "iterator/iterator.h"
55 #include "iterator/iter_delegpt.h"
56 #include "iterator/iter_utils.h"
57 #include "iterator/iter_fwd.h"
58 #include "iterator/iter_hints.h"
59 #include "sldns/sbuffer.h"
60 #include "sldns/wire2str.h"
61 #include "sldns/str2wire.h"
62 
63 /** dump one rrset zonefile line */
64 static int
dump_rrset_line(RES * ssl,struct ub_packed_rrset_key * k,time_t now,size_t i)65 dump_rrset_line(RES* ssl, struct ub_packed_rrset_key* k, time_t now, size_t i)
66 {
67 	char s[65535];
68 	if(!packed_rr_to_string(k, i, now, s, sizeof(s))) {
69 		return ssl_printf(ssl, "BADRR\n");
70 	}
71 	return ssl_printf(ssl, "%s", s);
72 }
73 
74 /** dump rrset key and data info */
75 static int
dump_rrset(RES * ssl,struct ub_packed_rrset_key * k,struct packed_rrset_data * d,time_t now)76 dump_rrset(RES* ssl, struct ub_packed_rrset_key* k,
77 	struct packed_rrset_data* d, time_t now)
78 {
79 	size_t i;
80 	/* rd lock held by caller */
81 	if(!k || !d) return 1;
82 	if(k->id == 0) return 1; /* deleted */
83 	if(d->ttl < now) return 1; /* expired */
84 
85 	/* meta line */
86 	if(!ssl_printf(ssl, ";rrset%s " ARG_LL "d %u %u %d %d\n",
87 		(k->rk.flags & PACKED_RRSET_NSEC_AT_APEX)?" nsec_apex":"",
88 		(long long)(d->ttl - now),
89 		(unsigned)d->count, (unsigned)d->rrsig_count,
90 		(int)d->trust, (int)d->security
91 		))
92 		return 0;
93 	for(i=0; i<d->count + d->rrsig_count; i++) {
94 		if(!dump_rrset_line(ssl, k, now, i))
95 			return 0;
96 	}
97 	return 1;
98 }
99 
100 /** dump lruhash rrset cache */
101 static int
dump_rrset_lruhash(RES * ssl,struct lruhash * h,time_t now)102 dump_rrset_lruhash(RES* ssl, struct lruhash* h, time_t now)
103 {
104 	struct lruhash_entry* e;
105 	/* lruhash already locked by caller */
106 	/* walk in order of lru; best first */
107 	for(e=h->lru_start; e; e = e->lru_next) {
108 		lock_rw_rdlock(&e->lock);
109 		if(!dump_rrset(ssl, (struct ub_packed_rrset_key*)e->key,
110 			(struct packed_rrset_data*)e->data, now)) {
111 			lock_rw_unlock(&e->lock);
112 			return 0;
113 		}
114 		lock_rw_unlock(&e->lock);
115 	}
116 	return 1;
117 }
118 
119 /** dump rrset cache */
120 static int
dump_rrset_cache(RES * ssl,struct worker * worker)121 dump_rrset_cache(RES* ssl, struct worker* worker)
122 {
123 	struct rrset_cache* r = worker->env.rrset_cache;
124 	size_t slab;
125 	if(!ssl_printf(ssl, "START_RRSET_CACHE\n")) return 0;
126 	for(slab=0; slab<r->table.size; slab++) {
127 		lock_quick_lock(&r->table.array[slab]->lock);
128 		if(!dump_rrset_lruhash(ssl, r->table.array[slab],
129 			*worker->env.now)) {
130 			lock_quick_unlock(&r->table.array[slab]->lock);
131 			return 0;
132 		}
133 		lock_quick_unlock(&r->table.array[slab]->lock);
134 	}
135 	return ssl_printf(ssl, "END_RRSET_CACHE\n");
136 }
137 
138 /** dump message to rrset reference */
139 static int
dump_msg_ref(RES * ssl,struct ub_packed_rrset_key * k)140 dump_msg_ref(RES* ssl, struct ub_packed_rrset_key* k)
141 {
142 	char* nm, *tp, *cl;
143 	nm = sldns_wire2str_dname(k->rk.dname, k->rk.dname_len);
144 	tp = sldns_wire2str_type(ntohs(k->rk.type));
145 	cl = sldns_wire2str_class(ntohs(k->rk.rrset_class));
146 	if(!nm || !cl || !tp) {
147 		free(nm);
148 		free(tp);
149 		free(cl);
150 		return ssl_printf(ssl, "BADREF\n");
151 	}
152 	if(!ssl_printf(ssl, "%s %s %s %d\n", nm, cl, tp, (int)k->rk.flags)) {
153 		free(nm);
154 		free(tp);
155 		free(cl);
156 		return 0;
157 	}
158 	free(nm);
159 	free(tp);
160 	free(cl);
161 
162 	return 1;
163 }
164 
165 /** dump message entry */
166 static int
dump_msg(RES * ssl,struct query_info * k,struct reply_info * d,time_t now)167 dump_msg(RES* ssl, struct query_info* k, struct reply_info* d,
168 	time_t now)
169 {
170 	size_t i;
171 	char* nm, *tp, *cl;
172 	if(!k || !d) return 1;
173 	if(d->ttl < now) return 1; /* expired */
174 
175 	nm = sldns_wire2str_dname(k->qname, k->qname_len);
176 	tp = sldns_wire2str_type(k->qtype);
177 	cl = sldns_wire2str_class(k->qclass);
178 	if(!nm || !tp || !cl) {
179 		free(nm);
180 		free(tp);
181 		free(cl);
182 		return 1; /* skip this entry */
183 	}
184 	if(!rrset_array_lock(d->ref, d->rrset_count, now)) {
185 		/* rrsets have timed out or do not exist */
186 		free(nm);
187 		free(tp);
188 		free(cl);
189 		return 1; /* skip this entry */
190 	}
191 
192 	/* meta line */
193 	if(!ssl_printf(ssl, "msg %s %s %s %d %d " ARG_LL "d %d %u %u %u\n",
194 			nm, cl, tp,
195 			(int)d->flags, (int)d->qdcount,
196 			(long long)(d->ttl-now), (int)d->security,
197 			(unsigned)d->an_numrrsets,
198 			(unsigned)d->ns_numrrsets,
199 			(unsigned)d->ar_numrrsets)) {
200 		free(nm);
201 		free(tp);
202 		free(cl);
203 		rrset_array_unlock(d->ref, d->rrset_count);
204 		return 0;
205 	}
206 	free(nm);
207 	free(tp);
208 	free(cl);
209 
210 	for(i=0; i<d->rrset_count; i++) {
211 		if(!dump_msg_ref(ssl, d->rrsets[i])) {
212 			rrset_array_unlock(d->ref, d->rrset_count);
213 			return 0;
214 		}
215 	}
216 	rrset_array_unlock(d->ref, d->rrset_count);
217 
218 	return 1;
219 }
220 
221 /** copy msg to worker pad */
222 static int
copy_msg(struct regional * region,struct lruhash_entry * e,struct query_info ** k,struct reply_info ** d)223 copy_msg(struct regional* region, struct lruhash_entry* e,
224 	struct query_info** k, struct reply_info** d)
225 {
226 	struct reply_info* rep = (struct reply_info*)e->data;
227 	if(rep->rrset_count > RR_COUNT_MAX)
228 		return 0; /* to protect against integer overflow */
229 	*d = (struct reply_info*)regional_alloc_init(region, e->data,
230 		sizeof(struct reply_info) +
231 		sizeof(struct rrset_ref) * (rep->rrset_count-1) +
232 		sizeof(struct ub_packed_rrset_key*) * rep->rrset_count);
233 	if(!*d)
234 		return 0;
235 	(*d)->rrsets = (struct ub_packed_rrset_key**)(void *)(
236 		(uint8_t*)(&((*d)->ref[0])) +
237 		sizeof(struct rrset_ref) * rep->rrset_count);
238 	*k = (struct query_info*)regional_alloc_init(region,
239 		e->key, sizeof(struct query_info));
240 	if(!*k)
241 		return 0;
242 	(*k)->qname = regional_alloc_init(region,
243 		(*k)->qname, (*k)->qname_len);
244 	return (*k)->qname != NULL;
245 }
246 
247 /** dump lruhash msg cache */
248 static int
dump_msg_lruhash(RES * ssl,struct worker * worker,struct lruhash * h)249 dump_msg_lruhash(RES* ssl, struct worker* worker, struct lruhash* h)
250 {
251 	struct lruhash_entry* e;
252 	struct query_info* k;
253 	struct reply_info* d;
254 
255 	/* lruhash already locked by caller */
256 	/* walk in order of lru; best first */
257 	for(e=h->lru_start; e; e = e->lru_next) {
258 		regional_free_all(worker->scratchpad);
259 		lock_rw_rdlock(&e->lock);
260 		/* make copy of rrset in worker buffer */
261 		if(!copy_msg(worker->scratchpad, e, &k, &d)) {
262 			lock_rw_unlock(&e->lock);
263 			return 0;
264 		}
265 		lock_rw_unlock(&e->lock);
266 		/* release lock so we can lookup the rrset references
267 		 * in the rrset cache */
268 		if(!dump_msg(ssl, k, d, *worker->env.now)) {
269 			return 0;
270 		}
271 	}
272 	return 1;
273 }
274 
275 /** dump msg cache */
276 static int
dump_msg_cache(RES * ssl,struct worker * worker)277 dump_msg_cache(RES* ssl, struct worker* worker)
278 {
279 	struct slabhash* sh = worker->env.msg_cache;
280 	size_t slab;
281 	if(!ssl_printf(ssl, "START_MSG_CACHE\n")) return 0;
282 	for(slab=0; slab<sh->size; slab++) {
283 		lock_quick_lock(&sh->array[slab]->lock);
284 		if(!dump_msg_lruhash(ssl, worker, sh->array[slab])) {
285 			lock_quick_unlock(&sh->array[slab]->lock);
286 			return 0;
287 		}
288 		lock_quick_unlock(&sh->array[slab]->lock);
289 	}
290 	return ssl_printf(ssl, "END_MSG_CACHE\n");
291 }
292 
293 int
dump_cache(RES * ssl,struct worker * worker)294 dump_cache(RES* ssl, struct worker* worker)
295 {
296 	if(!dump_rrset_cache(ssl, worker))
297 		return 0;
298 	if(!dump_msg_cache(ssl, worker))
299 		return 0;
300 	return ssl_printf(ssl, "EOF\n");
301 }
302 
303 /** read a line from ssl into buffer */
304 static int
ssl_read_buf(RES * ssl,sldns_buffer * buf)305 ssl_read_buf(RES* ssl, sldns_buffer* buf)
306 {
307 	return ssl_read_line(ssl, (char*)sldns_buffer_begin(buf),
308 		sldns_buffer_capacity(buf));
309 }
310 
311 /** check fixed text on line */
312 static int
read_fixed(RES * ssl,sldns_buffer * buf,const char * str)313 read_fixed(RES* ssl, sldns_buffer* buf, const char* str)
314 {
315 	if(!ssl_read_buf(ssl, buf)) return 0;
316 	return (strcmp((char*)sldns_buffer_begin(buf), str) == 0);
317 }
318 
319 /** load an RR into rrset */
320 static int
load_rr(RES * ssl,sldns_buffer * buf,struct regional * region,struct ub_packed_rrset_key * rk,struct packed_rrset_data * d,unsigned int i,int is_rrsig,int * go_on,time_t now)321 load_rr(RES* ssl, sldns_buffer* buf, struct regional* region,
322 	struct ub_packed_rrset_key* rk, struct packed_rrset_data* d,
323 	unsigned int i, int is_rrsig, int* go_on, time_t now)
324 {
325 	uint8_t rr[LDNS_RR_BUF_SIZE];
326 	size_t rr_len = sizeof(rr), dname_len = 0;
327 	int status;
328 
329 	/* read the line */
330 	if(!ssl_read_buf(ssl, buf))
331 		return 0;
332 	if(strncmp((char*)sldns_buffer_begin(buf), "BADRR\n", 6) == 0) {
333 		*go_on = 0;
334 		return 1;
335 	}
336 	status = sldns_str2wire_rr_buf((char*)sldns_buffer_begin(buf), rr,
337 		&rr_len, &dname_len, 3600, NULL, 0, NULL, 0);
338 	if(status != 0) {
339 		log_warn("error cannot parse rr: %s: %s",
340 			sldns_get_errorstr_parse(status),
341 			(char*)sldns_buffer_begin(buf));
342 		return 0;
343 	}
344 	if(is_rrsig && sldns_wirerr_get_type(rr, rr_len, dname_len)
345 		!= LDNS_RR_TYPE_RRSIG) {
346 		log_warn("error expected rrsig but got %s",
347 			(char*)sldns_buffer_begin(buf));
348 		return 0;
349 	}
350 
351 	/* convert ldns rr into packed_rr */
352 	d->rr_ttl[i] = (time_t)sldns_wirerr_get_ttl(rr, rr_len, dname_len) + now;
353 	sldns_buffer_clear(buf);
354 	d->rr_len[i] = sldns_wirerr_get_rdatalen(rr, rr_len, dname_len)+2;
355 	d->rr_data[i] = (uint8_t*)regional_alloc_init(region,
356 		sldns_wirerr_get_rdatawl(rr, rr_len, dname_len), d->rr_len[i]);
357 	if(!d->rr_data[i]) {
358 		log_warn("error out of memory");
359 		return 0;
360 	}
361 
362 	/* if first entry, fill the key structure */
363 	if(i==0) {
364 		rk->rk.type = htons(sldns_wirerr_get_type(rr, rr_len, dname_len));
365 		rk->rk.rrset_class = htons(sldns_wirerr_get_class(rr, rr_len, dname_len));
366 		rk->rk.dname_len = dname_len;
367 		rk->rk.dname = regional_alloc_init(region, rr, dname_len);
368 		if(!rk->rk.dname) {
369 			log_warn("error out of memory");
370 			return 0;
371 		}
372 	}
373 
374 	return 1;
375 }
376 
377 /** move entry into cache */
378 static int
move_into_cache(struct ub_packed_rrset_key * k,struct packed_rrset_data * d,struct worker * worker)379 move_into_cache(struct ub_packed_rrset_key* k,
380 	struct packed_rrset_data* d, struct worker* worker)
381 {
382 	struct ub_packed_rrset_key* ak;
383 	struct packed_rrset_data* ad;
384 	size_t s, i, num = d->count + d->rrsig_count;
385 	struct rrset_ref ref;
386 	uint8_t* p;
387 
388 	ak = alloc_special_obtain(&worker->alloc);
389 	if(!ak) {
390 		log_warn("error out of memory");
391 		return 0;
392 	}
393 	ak->entry.data = NULL;
394 	ak->rk = k->rk;
395 	ak->entry.hash = rrset_key_hash(&k->rk);
396 	ak->rk.dname = (uint8_t*)memdup(k->rk.dname, k->rk.dname_len);
397 	if(!ak->rk.dname) {
398 		log_warn("error out of memory");
399 		ub_packed_rrset_parsedelete(ak, &worker->alloc);
400 		return 0;
401 	}
402 	s = sizeof(*ad) + (sizeof(size_t) + sizeof(uint8_t*) +
403 		sizeof(time_t))* num;
404 	for(i=0; i<num; i++)
405 		s += d->rr_len[i];
406 	ad = (struct packed_rrset_data*)malloc(s);
407 	if(!ad) {
408 		log_warn("error out of memory");
409 		ub_packed_rrset_parsedelete(ak, &worker->alloc);
410 		return 0;
411 	}
412 	p = (uint8_t*)ad;
413 	memmove(p, d, sizeof(*ad));
414 	p += sizeof(*ad);
415 	memmove(p, &d->rr_len[0], sizeof(size_t)*num);
416 	p += sizeof(size_t)*num;
417 	memmove(p, &d->rr_data[0], sizeof(uint8_t*)*num);
418 	p += sizeof(uint8_t*)*num;
419 	memmove(p, &d->rr_ttl[0], sizeof(time_t)*num);
420 	p += sizeof(time_t)*num;
421 	for(i=0; i<num; i++) {
422 		memmove(p, d->rr_data[i], d->rr_len[i]);
423 		p += d->rr_len[i];
424 	}
425 	packed_rrset_ptr_fixup(ad);
426 
427 	ak->entry.data = ad;
428 
429 	ref.key = ak;
430 	ref.id = ak->id;
431 	(void)rrset_cache_update(worker->env.rrset_cache, &ref,
432 		&worker->alloc, *worker->env.now);
433 	return 1;
434 }
435 
436 /** load an rrset entry */
437 static int
load_rrset(RES * ssl,sldns_buffer * buf,struct worker * worker)438 load_rrset(RES* ssl, sldns_buffer* buf, struct worker* worker)
439 {
440 	char* s = (char*)sldns_buffer_begin(buf);
441 	struct regional* region = worker->scratchpad;
442 	struct ub_packed_rrset_key* rk;
443 	struct packed_rrset_data* d;
444 	unsigned int rr_count, rrsig_count, trust, security;
445 	long long ttl;
446 	unsigned int i;
447 	int go_on = 1;
448 	regional_free_all(region);
449 
450 	rk = (struct ub_packed_rrset_key*)regional_alloc_zero(region,
451 		sizeof(*rk));
452 	d = (struct packed_rrset_data*)regional_alloc_zero(region, sizeof(*d));
453 	if(!rk || !d) {
454 		log_warn("error out of memory");
455 		return 0;
456 	}
457 
458 	if(strncmp(s, ";rrset", 6) != 0) {
459 		log_warn("error expected ';rrset' but got %s", s);
460 		return 0;
461 	}
462 	s += 6;
463 	if(strncmp(s, " nsec_apex", 10) == 0) {
464 		s += 10;
465 		rk->rk.flags |= PACKED_RRSET_NSEC_AT_APEX;
466 	}
467 	if(sscanf(s, " " ARG_LL "d %u %u %u %u", &ttl, &rr_count, &rrsig_count,
468 		&trust, &security) != 5) {
469 		log_warn("error bad rrset spec %s", s);
470 		return 0;
471 	}
472 	if(rr_count == 0 && rrsig_count == 0) {
473 		log_warn("bad rrset without contents");
474 		return 0;
475 	}
476 	if(rr_count > RR_COUNT_MAX || rrsig_count > RR_COUNT_MAX) {
477 		log_warn("bad rrset with too many rrs");
478 		return 0;
479 	}
480 	d->count = (size_t)rr_count;
481 	d->rrsig_count = (size_t)rrsig_count;
482 	d->security = (enum sec_status)security;
483 	d->trust = (enum rrset_trust)trust;
484 	d->ttl = (time_t)ttl + *worker->env.now;
485 
486 	d->rr_len = regional_alloc_zero(region,
487 		sizeof(size_t)*(d->count+d->rrsig_count));
488 	d->rr_ttl = regional_alloc_zero(region,
489 		sizeof(time_t)*(d->count+d->rrsig_count));
490 	d->rr_data = regional_alloc_zero(region,
491 		sizeof(uint8_t*)*(d->count+d->rrsig_count));
492 	if(!d->rr_len || !d->rr_ttl || !d->rr_data) {
493 		log_warn("error out of memory");
494 		return 0;
495 	}
496 
497 	/* read the rr's themselves */
498 	for(i=0; i<rr_count; i++) {
499 		if(!load_rr(ssl, buf, region, rk, d, i, 0,
500 			&go_on, *worker->env.now)) {
501 			log_warn("could not read rr %u", i);
502 			return 0;
503 		}
504 	}
505 	for(i=0; i<rrsig_count; i++) {
506 		if(!load_rr(ssl, buf, region, rk, d, i+rr_count, 1,
507 			&go_on, *worker->env.now)) {
508 			log_warn("could not read rrsig %u", i);
509 			return 0;
510 		}
511 	}
512 	if(!go_on) {
513 		/* skip this entry */
514 		return 1;
515 	}
516 
517 	return move_into_cache(rk, d, worker);
518 }
519 
520 /** load rrset cache */
521 static int
load_rrset_cache(RES * ssl,struct worker * worker)522 load_rrset_cache(RES* ssl, struct worker* worker)
523 {
524 	sldns_buffer* buf = worker->env.scratch_buffer;
525 	if(!read_fixed(ssl, buf, "START_RRSET_CACHE")) return 0;
526 	while(ssl_read_buf(ssl, buf) &&
527 		strcmp((char*)sldns_buffer_begin(buf), "END_RRSET_CACHE")!=0) {
528 		if(!load_rrset(ssl, buf, worker))
529 			return 0;
530 	}
531 	return 1;
532 }
533 
534 /** read qinfo from next three words */
535 static char*
load_qinfo(char * str,struct query_info * qinfo,struct regional * region)536 load_qinfo(char* str, struct query_info* qinfo, struct regional* region)
537 {
538 	/* s is part of the buf */
539 	char* s = str;
540 	uint8_t rr[LDNS_RR_BUF_SIZE];
541 	size_t rr_len = sizeof(rr), dname_len = 0;
542 	int status;
543 
544 	/* skip three words */
545 	s = strchr(str, ' ');
546 	if(s) s = strchr(s+1, ' ');
547 	if(s) s = strchr(s+1, ' ');
548 	if(!s) {
549 		log_warn("error line too short, %s", str);
550 		return NULL;
551 	}
552 	s[0] = 0;
553 	s++;
554 
555 	/* parse them */
556 	status = sldns_str2wire_rr_question_buf(str, rr, &rr_len, &dname_len,
557 		NULL, 0, NULL, 0);
558 	if(status != 0) {
559 		log_warn("error cannot parse: %s %s",
560 			sldns_get_errorstr_parse(status), str);
561 		return NULL;
562 	}
563 	qinfo->qtype = sldns_wirerr_get_type(rr, rr_len, dname_len);
564 	qinfo->qclass = sldns_wirerr_get_class(rr, rr_len, dname_len);
565 	qinfo->qname_len = dname_len;
566 	qinfo->qname = (uint8_t*)regional_alloc_init(region, rr, dname_len);
567 	qinfo->local_alias = NULL;
568 	if(!qinfo->qname) {
569 		log_warn("error out of memory");
570 		return NULL;
571 	}
572 
573 	return s;
574 }
575 
576 /** load a msg rrset reference */
577 static int
load_ref(RES * ssl,sldns_buffer * buf,struct worker * worker,struct regional * region,struct ub_packed_rrset_key ** rrset,int * go_on)578 load_ref(RES* ssl, sldns_buffer* buf, struct worker* worker,
579 	struct regional *region, struct ub_packed_rrset_key** rrset,
580 	int* go_on)
581 {
582 	char* s = (char*)sldns_buffer_begin(buf);
583 	struct query_info qinfo;
584 	unsigned int flags;
585 	struct ub_packed_rrset_key* k;
586 
587 	/* read line */
588 	if(!ssl_read_buf(ssl, buf))
589 		return 0;
590 	if(strncmp(s, "BADREF", 6) == 0) {
591 		*go_on = 0; /* its bad, skip it and skip message */
592 		return 1;
593 	}
594 
595 	s = load_qinfo(s, &qinfo, region);
596 	if(!s) {
597 		return 0;
598 	}
599 	if(sscanf(s, " %u", &flags) != 1) {
600 		log_warn("error cannot parse flags: %s", s);
601 		return 0;
602 	}
603 
604 	/* lookup in cache */
605 	k = rrset_cache_lookup(worker->env.rrset_cache, qinfo.qname,
606 		qinfo.qname_len, qinfo.qtype, qinfo.qclass,
607 		(uint32_t)flags, *worker->env.now, 0);
608 	if(!k) {
609 		/* not found or expired */
610 		*go_on = 0;
611 		return 1;
612 	}
613 
614 	/* store in result */
615 	*rrset = packed_rrset_copy_region(k, region, *worker->env.now);
616 	lock_rw_unlock(&k->entry.lock);
617 
618 	return (*rrset != NULL);
619 }
620 
621 /** load a msg entry */
622 static int
load_msg(RES * ssl,sldns_buffer * buf,struct worker * worker)623 load_msg(RES* ssl, sldns_buffer* buf, struct worker* worker)
624 {
625 	struct regional* region = worker->scratchpad;
626 	struct query_info qinf;
627 	struct reply_info rep;
628 	char* s = (char*)sldns_buffer_begin(buf);
629 	unsigned int flags, qdcount, security, an, ns, ar;
630 	long long ttl;
631 	size_t i;
632 	int go_on = 1;
633 
634 	regional_free_all(region);
635 
636 	if(strncmp(s, "msg ", 4) != 0) {
637 		log_warn("error expected msg but got %s", s);
638 		return 0;
639 	}
640 	s += 4;
641 	s = load_qinfo(s, &qinf, region);
642 	if(!s) {
643 		return 0;
644 	}
645 
646 	/* read remainder of line */
647 	if(sscanf(s, " %u %u " ARG_LL "d %u %u %u %u", &flags, &qdcount, &ttl,
648 		&security, &an, &ns, &ar) != 7) {
649 		log_warn("error cannot parse numbers: %s", s);
650 		return 0;
651 	}
652 	rep.flags = (uint16_t)flags;
653 	rep.qdcount = (uint16_t)qdcount;
654 	rep.ttl = (time_t)ttl;
655 	rep.prefetch_ttl = PREFETCH_TTL_CALC(rep.ttl);
656 	rep.serve_expired_ttl = rep.ttl + SERVE_EXPIRED_TTL;
657 	rep.security = (enum sec_status)security;
658 	if(an > RR_COUNT_MAX || ns > RR_COUNT_MAX || ar > RR_COUNT_MAX) {
659 		log_warn("error too many rrsets");
660 		return 0; /* protect against integer overflow in alloc */
661 	}
662 	rep.an_numrrsets = (size_t)an;
663 	rep.ns_numrrsets = (size_t)ns;
664 	rep.ar_numrrsets = (size_t)ar;
665 	rep.rrset_count = (size_t)an+(size_t)ns+(size_t)ar;
666 	rep.rrsets = (struct ub_packed_rrset_key**)regional_alloc_zero(
667 		region, sizeof(struct ub_packed_rrset_key*)*rep.rrset_count);
668 
669 	/* fill repinfo with references */
670 	for(i=0; i<rep.rrset_count; i++) {
671 		if(!load_ref(ssl, buf, worker, region, &rep.rrsets[i],
672 			&go_on)) {
673 			return 0;
674 		}
675 	}
676 
677 	if(!go_on)
678 		return 1; /* skip this one, not all references satisfied */
679 
680 	if(!dns_cache_store(&worker->env, &qinf, &rep, 0, 0, 0, NULL, flags)) {
681 		log_warn("error out of memory");
682 		return 0;
683 	}
684 	return 1;
685 }
686 
687 /** load msg cache */
688 static int
load_msg_cache(RES * ssl,struct worker * worker)689 load_msg_cache(RES* ssl, struct worker* worker)
690 {
691 	sldns_buffer* buf = worker->env.scratch_buffer;
692 	if(!read_fixed(ssl, buf, "START_MSG_CACHE")) return 0;
693 	while(ssl_read_buf(ssl, buf) &&
694 		strcmp((char*)sldns_buffer_begin(buf), "END_MSG_CACHE")!=0) {
695 		if(!load_msg(ssl, buf, worker))
696 			return 0;
697 	}
698 	return 1;
699 }
700 
701 int
load_cache(RES * ssl,struct worker * worker)702 load_cache(RES* ssl, struct worker* worker)
703 {
704 	if(!load_rrset_cache(ssl, worker))
705 		return 0;
706 	if(!load_msg_cache(ssl, worker))
707 		return 0;
708 	return read_fixed(ssl, worker->env.scratch_buffer, "EOF");
709 }
710 
711 /** print details on a delegation point */
712 static void
print_dp_details(RES * ssl,struct worker * worker,struct delegpt * dp)713 print_dp_details(RES* ssl, struct worker* worker, struct delegpt* dp)
714 {
715 	char buf[257];
716 	struct delegpt_addr* a;
717 	int lame, dlame, rlame, rto, edns_vs, to, delay,
718 		tA = 0, tAAAA = 0, tother = 0;
719 	long long entry_ttl;
720 	struct rtt_info ri;
721 	uint8_t edns_lame_known;
722 	for(a = dp->target_list; a; a = a->next_target) {
723 		addr_to_str(&a->addr, a->addrlen, buf, sizeof(buf));
724 		if(!ssl_printf(ssl, "%-16s\t", buf))
725 			return;
726 		if(a->bogus) {
727 			if(!ssl_printf(ssl, "Address is BOGUS. "))
728 				return;
729 		}
730 		/* lookup in infra cache */
731 		delay=0;
732 		entry_ttl = infra_get_host_rto(worker->env.infra_cache,
733 			&a->addr, a->addrlen, dp->name, dp->namelen,
734 			&ri, &delay, *worker->env.now, &tA, &tAAAA, &tother);
735 		if(entry_ttl == -2 && ri.rto >= USEFUL_SERVER_TOP_TIMEOUT) {
736 			if(!ssl_printf(ssl, "expired, rto %d msec, tA %d "
737 				"tAAAA %d tother %d.\n", ri.rto, tA, tAAAA,
738 				tother))
739 				return;
740 			continue;
741 		}
742 		if(entry_ttl == -1 || entry_ttl == -2) {
743 			if(!ssl_printf(ssl, "not in infra cache.\n"))
744 				return;
745 			continue; /* skip stuff not in infra cache */
746 		}
747 
748 		/* uses type_A because most often looked up, but other
749 		 * lameness won't be reported then */
750 		if(!infra_get_lame_rtt(worker->env.infra_cache,
751 			&a->addr, a->addrlen, dp->name, dp->namelen,
752 			LDNS_RR_TYPE_A, &lame, &dlame, &rlame, &rto,
753 			*worker->env.now)) {
754 			if(!ssl_printf(ssl, "not in infra cache.\n"))
755 				return;
756 			continue; /* skip stuff not in infra cache */
757 		}
758 		if(!ssl_printf(ssl, "%s%s%s%srto %d msec, ttl " ARG_LL "d, "
759 			"ping %d var %d rtt %d, tA %d, tAAAA %d, tother %d",
760 			lame?"LAME ":"", dlame?"NoDNSSEC ":"",
761 			a->lame?"AddrWasParentSide ":"",
762 			rlame?"NoAuthButRecursive ":"", rto, entry_ttl,
763 			ri.srtt, ri.rttvar, rtt_notimeout(&ri),
764 			tA, tAAAA, tother))
765 			return;
766 		if(delay)
767 			if(!ssl_printf(ssl, ", probedelay %d", delay))
768 				return;
769 		if(infra_host(worker->env.infra_cache, &a->addr, a->addrlen,
770 			dp->name, dp->namelen, *worker->env.now, &edns_vs,
771 			&edns_lame_known, &to)) {
772 			if(edns_vs == -1) {
773 				if(!ssl_printf(ssl, ", noEDNS%s.",
774 					edns_lame_known?" probed":" assumed"))
775 					return;
776 			} else {
777 				if(!ssl_printf(ssl, ", EDNS %d%s.", edns_vs,
778 					edns_lame_known?" probed":" assumed"))
779 					return;
780 			}
781 		}
782 		if(!ssl_printf(ssl, "\n"))
783 			return;
784 	}
785 }
786 
787 /** print main dp info */
788 static void
print_dp_main(RES * ssl,struct delegpt * dp,struct dns_msg * msg)789 print_dp_main(RES* ssl, struct delegpt* dp, struct dns_msg* msg)
790 {
791 	size_t i, n_ns, n_miss, n_addr, n_res, n_avail;
792 
793 	/* print the dp */
794 	if(msg)
795 	    for(i=0; i<msg->rep->rrset_count; i++) {
796 		struct ub_packed_rrset_key* k = msg->rep->rrsets[i];
797 		struct packed_rrset_data* d =
798 			(struct packed_rrset_data*)k->entry.data;
799 		if(d->security == sec_status_bogus) {
800 			if(!ssl_printf(ssl, "Address is BOGUS:\n"))
801 				return;
802 		}
803 		if(!dump_rrset(ssl, k, d, 0))
804 			return;
805 	    }
806 	delegpt_count_ns(dp, &n_ns, &n_miss);
807 	delegpt_count_addr(dp, &n_addr, &n_res, &n_avail);
808 	/* since dp has not been used by iterator, all are available*/
809 	if(!ssl_printf(ssl, "Delegation with %d names, of which %d "
810 		"can be examined to query further addresses.\n"
811 		"%sIt provides %d IP addresses.\n",
812 		(int)n_ns, (int)n_miss, (dp->bogus?"It is BOGUS. ":""),
813 		(int)n_addr))
814 		return;
815 }
816 
print_deleg_lookup(RES * ssl,struct worker * worker,uint8_t * nm,size_t nmlen,int ATTR_UNUSED (nmlabs))817 int print_deleg_lookup(RES* ssl, struct worker* worker, uint8_t* nm,
818 	size_t nmlen, int ATTR_UNUSED(nmlabs))
819 {
820 	/* deep links into the iterator module */
821 	struct delegpt* dp;
822 	struct dns_msg* msg;
823 	struct regional* region = worker->scratchpad;
824 	char b[260];
825 	struct query_info qinfo;
826 	struct iter_hints_stub* stub;
827 	regional_free_all(region);
828 	qinfo.qname = nm;
829 	qinfo.qname_len = nmlen;
830 	qinfo.qtype = LDNS_RR_TYPE_A;
831 	qinfo.qclass = LDNS_RR_CLASS_IN;
832 	qinfo.local_alias = NULL;
833 
834 	dname_str(nm, b);
835 	if(!ssl_printf(ssl, "The following name servers are used for lookup "
836 		"of %s\n", b))
837 		return 0;
838 
839 	dp = forwards_lookup(worker->env.fwds, nm, qinfo.qclass);
840 	if(dp) {
841 		if(!ssl_printf(ssl, "forwarding request:\n"))
842 			return 0;
843 		print_dp_main(ssl, dp, NULL);
844 		print_dp_details(ssl, worker, dp);
845 		return 1;
846 	}
847 
848 	while(1) {
849 		dp = dns_cache_find_delegation(&worker->env, nm, nmlen,
850 			qinfo.qtype, qinfo.qclass, region, &msg,
851 			*worker->env.now);
852 		if(!dp) {
853 			return ssl_printf(ssl, "no delegation from "
854 				"cache; goes to configured roots\n");
855 		}
856 		/* go up? */
857 		if(iter_dp_is_useless(&qinfo, BIT_RD, dp)) {
858 			print_dp_main(ssl, dp, msg);
859 			print_dp_details(ssl, worker, dp);
860 			if(!ssl_printf(ssl, "cache delegation was "
861 				"useless (no IP addresses)\n"))
862 				return 0;
863 			if(dname_is_root(nm)) {
864 				/* goes to root config */
865 				return ssl_printf(ssl, "no delegation from "
866 					"cache; goes to configured roots\n");
867 			} else {
868 				/* useless, goes up */
869 				nm = dp->name;
870 				nmlen = dp->namelen;
871 				dname_remove_label(&nm, &nmlen);
872 				dname_str(nm, b);
873 				if(!ssl_printf(ssl, "going up, lookup %s\n", b))
874 					return 0;
875 				continue;
876 			}
877 		}
878 		stub = hints_lookup_stub(worker->env.hints, nm, qinfo.qclass,
879 			dp);
880 		if(stub) {
881 			if(stub->noprime) {
882 				if(!ssl_printf(ssl, "The noprime stub servers "
883 					"are used:\n"))
884 					return 0;
885 			} else {
886 				if(!ssl_printf(ssl, "The stub is primed "
887 						"with servers:\n"))
888 					return 0;
889 			}
890 			print_dp_main(ssl, stub->dp, NULL);
891 			print_dp_details(ssl, worker, stub->dp);
892 		} else {
893 			print_dp_main(ssl, dp, msg);
894 			print_dp_details(ssl, worker, dp);
895 		}
896 		break;
897 	}
898 
899 	return 1;
900 }
901