1238106Sdes/* 2238106Sdes * daemon/cachedump.c - dump the cache to text format. 3238106Sdes * 4238106Sdes * Copyright (c) 2008, NLnet Labs. All rights reserved. 5238106Sdes * 6238106Sdes * This software is open source. 7238106Sdes * 8238106Sdes * Redistribution and use in source and binary forms, with or without 9238106Sdes * modification, are permitted provided that the following conditions 10238106Sdes * are met: 11238106Sdes * 12238106Sdes * Redistributions of source code must retain the above copyright notice, 13238106Sdes * this list of conditions and the following disclaimer. 14238106Sdes * 15238106Sdes * Redistributions in binary form must reproduce the above copyright notice, 16238106Sdes * this list of conditions and the following disclaimer in the documentation 17238106Sdes * and/or other materials provided with the distribution. 18238106Sdes * 19238106Sdes * Neither the name of the NLNET LABS nor the names of its contributors may 20238106Sdes * be used to endorse or promote products derived from this software without 21238106Sdes * specific prior written permission. 22238106Sdes * 23238106Sdes * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 24269257Sdes * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 25269257Sdes * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 26269257Sdes * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 27269257Sdes * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 28269257Sdes * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 29269257Sdes * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 30269257Sdes * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 31269257Sdes * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 32269257Sdes * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 33269257Sdes * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 34238106Sdes */ 35238106Sdes 36238106Sdes/** 37238106Sdes * \file 38238106Sdes * 39238106Sdes * This file contains functions to read and write the cache(s) 40238106Sdes * to text format. 41238106Sdes */ 42238106Sdes#include "config.h" 43269257Sdes#include <openssl/ssl.h> 44238106Sdes#include "daemon/cachedump.h" 45238106Sdes#include "daemon/remote.h" 46238106Sdes#include "daemon/worker.h" 47238106Sdes#include "services/cache/rrset.h" 48238106Sdes#include "services/cache/dns.h" 49238106Sdes#include "services/cache/infra.h" 50238106Sdes#include "util/data/msgreply.h" 51238106Sdes#include "util/regional.h" 52238106Sdes#include "util/net_help.h" 53238106Sdes#include "util/data/dname.h" 54238106Sdes#include "iterator/iterator.h" 55238106Sdes#include "iterator/iter_delegpt.h" 56238106Sdes#include "iterator/iter_utils.h" 57238106Sdes#include "iterator/iter_fwd.h" 58238106Sdes#include "iterator/iter_hints.h" 59269257Sdes#include "ldns/sbuffer.h" 60269257Sdes#include "ldns/wire2str.h" 61269257Sdes#include "ldns/str2wire.h" 62238106Sdes 63238106Sdes/** dump one rrset zonefile line */ 64238106Sdesstatic int 65269257Sdesdump_rrset_line(SSL* ssl, struct ub_packed_rrset_key* k, time_t now, size_t i) 66238106Sdes{ 67269257Sdes char s[65535]; 68269257Sdes if(!packed_rr_to_string(k, i, now, s, sizeof(s))) { 69238106Sdes return ssl_printf(ssl, "BADRR\n"); 70238106Sdes } 71269257Sdes return ssl_printf(ssl, "%s", s); 72238106Sdes} 73238106Sdes 74238106Sdes/** dump rrset key and data info */ 75238106Sdesstatic int 76238106Sdesdump_rrset(SSL* ssl, struct ub_packed_rrset_key* k, 77269257Sdes struct packed_rrset_data* d, time_t now) 78238106Sdes{ 79238106Sdes size_t i; 80238106Sdes /* rd lock held by caller */ 81238106Sdes if(!k || !d) return 1; 82238106Sdes if(d->ttl < now) return 1; /* expired */ 83238106Sdes 84238106Sdes /* meta line */ 85269257Sdes if(!ssl_printf(ssl, ";rrset%s " ARG_LL "d %u %u %d %d\n", 86238106Sdes (k->rk.flags & PACKED_RRSET_NSEC_AT_APEX)?" nsec_apex":"", 87269257Sdes (long long)(d->ttl - now), 88238106Sdes (unsigned)d->count, (unsigned)d->rrsig_count, 89238106Sdes (int)d->trust, (int)d->security 90238106Sdes )) 91238106Sdes return 0; 92269257Sdes for(i=0; i<d->count + d->rrsig_count; i++) { 93269257Sdes if(!dump_rrset_line(ssl, k, now, i)) 94238106Sdes return 0; 95238106Sdes } 96238106Sdes return 1; 97238106Sdes} 98238106Sdes 99238106Sdes/** dump lruhash rrset cache */ 100238106Sdesstatic int 101269257Sdesdump_rrset_lruhash(SSL* ssl, struct lruhash* h, time_t now) 102238106Sdes{ 103238106Sdes struct lruhash_entry* e; 104238106Sdes /* lruhash already locked by caller */ 105238106Sdes /* walk in order of lru; best first */ 106238106Sdes for(e=h->lru_start; e; e = e->lru_next) { 107238106Sdes lock_rw_rdlock(&e->lock); 108238106Sdes if(!dump_rrset(ssl, (struct ub_packed_rrset_key*)e->key, 109238106Sdes (struct packed_rrset_data*)e->data, now)) { 110238106Sdes lock_rw_unlock(&e->lock); 111238106Sdes return 0; 112238106Sdes } 113238106Sdes lock_rw_unlock(&e->lock); 114238106Sdes } 115238106Sdes return 1; 116238106Sdes} 117238106Sdes 118238106Sdes/** dump rrset cache */ 119238106Sdesstatic int 120238106Sdesdump_rrset_cache(SSL* ssl, struct worker* worker) 121238106Sdes{ 122238106Sdes struct rrset_cache* r = worker->env.rrset_cache; 123238106Sdes size_t slab; 124238106Sdes if(!ssl_printf(ssl, "START_RRSET_CACHE\n")) return 0; 125238106Sdes for(slab=0; slab<r->table.size; slab++) { 126238106Sdes lock_quick_lock(&r->table.array[slab]->lock); 127238106Sdes if(!dump_rrset_lruhash(ssl, r->table.array[slab], 128238106Sdes *worker->env.now)) { 129238106Sdes lock_quick_unlock(&r->table.array[slab]->lock); 130238106Sdes return 0; 131238106Sdes } 132238106Sdes lock_quick_unlock(&r->table.array[slab]->lock); 133238106Sdes } 134238106Sdes return ssl_printf(ssl, "END_RRSET_CACHE\n"); 135238106Sdes} 136238106Sdes 137238106Sdes/** dump message to rrset reference */ 138238106Sdesstatic int 139238106Sdesdump_msg_ref(SSL* ssl, struct ub_packed_rrset_key* k) 140238106Sdes{ 141238106Sdes char* nm, *tp, *cl; 142269257Sdes nm = sldns_wire2str_dname(k->rk.dname, k->rk.dname_len); 143269257Sdes tp = sldns_wire2str_type(ntohs(k->rk.type)); 144269257Sdes cl = sldns_wire2str_class(ntohs(k->rk.rrset_class)); 145238106Sdes if(!nm || !cl || !tp) { 146238106Sdes free(nm); 147238106Sdes free(tp); 148238106Sdes free(cl); 149238106Sdes return ssl_printf(ssl, "BADREF\n"); 150238106Sdes } 151238106Sdes if(!ssl_printf(ssl, "%s %s %s %d\n", nm, cl, tp, (int)k->rk.flags)) { 152238106Sdes free(nm); 153238106Sdes free(tp); 154238106Sdes free(cl); 155238106Sdes return 0; 156238106Sdes } 157238106Sdes free(nm); 158238106Sdes free(tp); 159238106Sdes free(cl); 160238106Sdes 161238106Sdes return 1; 162238106Sdes} 163238106Sdes 164238106Sdes/** dump message entry */ 165238106Sdesstatic int 166238106Sdesdump_msg(SSL* ssl, struct query_info* k, struct reply_info* d, 167269257Sdes time_t now) 168238106Sdes{ 169238106Sdes size_t i; 170238106Sdes char* nm, *tp, *cl; 171238106Sdes if(!k || !d) return 1; 172238106Sdes if(d->ttl < now) return 1; /* expired */ 173238106Sdes 174269257Sdes nm = sldns_wire2str_dname(k->qname, k->qname_len); 175269257Sdes tp = sldns_wire2str_type(k->qtype); 176269257Sdes cl = sldns_wire2str_class(k->qclass); 177238106Sdes if(!nm || !tp || !cl) { 178238106Sdes free(nm); 179238106Sdes free(tp); 180238106Sdes free(cl); 181238106Sdes return 1; /* skip this entry */ 182238106Sdes } 183238106Sdes if(!rrset_array_lock(d->ref, d->rrset_count, now)) { 184238106Sdes /* rrsets have timed out or do not exist */ 185238106Sdes free(nm); 186238106Sdes free(tp); 187238106Sdes free(cl); 188238106Sdes return 1; /* skip this entry */ 189238106Sdes } 190238106Sdes 191238106Sdes /* meta line */ 192269257Sdes if(!ssl_printf(ssl, "msg %s %s %s %d %d " ARG_LL "d %d %u %u %u\n", 193238106Sdes nm, cl, tp, 194238106Sdes (int)d->flags, (int)d->qdcount, 195269257Sdes (long long)(d->ttl-now), (int)d->security, 196238106Sdes (unsigned)d->an_numrrsets, 197238106Sdes (unsigned)d->ns_numrrsets, 198238106Sdes (unsigned)d->ar_numrrsets)) { 199238106Sdes free(nm); 200238106Sdes free(tp); 201238106Sdes free(cl); 202238106Sdes rrset_array_unlock(d->ref, d->rrset_count); 203238106Sdes return 0; 204238106Sdes } 205238106Sdes free(nm); 206238106Sdes free(tp); 207238106Sdes free(cl); 208238106Sdes 209238106Sdes for(i=0; i<d->rrset_count; i++) { 210238106Sdes if(!dump_msg_ref(ssl, d->rrsets[i])) { 211238106Sdes rrset_array_unlock(d->ref, d->rrset_count); 212238106Sdes return 0; 213238106Sdes } 214238106Sdes } 215238106Sdes rrset_array_unlock(d->ref, d->rrset_count); 216238106Sdes 217238106Sdes return 1; 218238106Sdes} 219238106Sdes 220238106Sdes/** copy msg to worker pad */ 221238106Sdesstatic int 222238106Sdescopy_msg(struct regional* region, struct lruhash_entry* e, 223238106Sdes struct query_info** k, struct reply_info** d) 224238106Sdes{ 225238106Sdes struct reply_info* rep = (struct reply_info*)e->data; 226238106Sdes *d = (struct reply_info*)regional_alloc_init(region, e->data, 227238106Sdes sizeof(struct reply_info) + 228238106Sdes sizeof(struct rrset_ref) * (rep->rrset_count-1) + 229238106Sdes sizeof(struct ub_packed_rrset_key*) * rep->rrset_count); 230238106Sdes if(!*d) 231238106Sdes return 0; 232255579Sdes (*d)->rrsets = (struct ub_packed_rrset_key**)(void *)( 233238106Sdes (uint8_t*)(&((*d)->ref[0])) + 234238106Sdes sizeof(struct rrset_ref) * rep->rrset_count); 235238106Sdes *k = (struct query_info*)regional_alloc_init(region, 236238106Sdes e->key, sizeof(struct query_info)); 237238106Sdes if(!*k) 238238106Sdes return 0; 239238106Sdes (*k)->qname = regional_alloc_init(region, 240238106Sdes (*k)->qname, (*k)->qname_len); 241238106Sdes return (*k)->qname != NULL; 242238106Sdes} 243238106Sdes 244238106Sdes/** dump lruhash msg cache */ 245238106Sdesstatic int 246238106Sdesdump_msg_lruhash(SSL* ssl, struct worker* worker, struct lruhash* h) 247238106Sdes{ 248238106Sdes struct lruhash_entry* e; 249238106Sdes struct query_info* k; 250238106Sdes struct reply_info* d; 251238106Sdes 252238106Sdes /* lruhash already locked by caller */ 253238106Sdes /* walk in order of lru; best first */ 254238106Sdes for(e=h->lru_start; e; e = e->lru_next) { 255238106Sdes regional_free_all(worker->scratchpad); 256238106Sdes lock_rw_rdlock(&e->lock); 257238106Sdes /* make copy of rrset in worker buffer */ 258238106Sdes if(!copy_msg(worker->scratchpad, e, &k, &d)) { 259238106Sdes lock_rw_unlock(&e->lock); 260238106Sdes return 0; 261238106Sdes } 262238106Sdes lock_rw_unlock(&e->lock); 263238106Sdes /* release lock so we can lookup the rrset references 264238106Sdes * in the rrset cache */ 265238106Sdes if(!dump_msg(ssl, k, d, *worker->env.now)) { 266238106Sdes return 0; 267238106Sdes } 268238106Sdes } 269238106Sdes return 1; 270238106Sdes} 271238106Sdes 272238106Sdes/** dump msg cache */ 273238106Sdesstatic int 274238106Sdesdump_msg_cache(SSL* ssl, struct worker* worker) 275238106Sdes{ 276238106Sdes struct slabhash* sh = worker->env.msg_cache; 277238106Sdes size_t slab; 278238106Sdes if(!ssl_printf(ssl, "START_MSG_CACHE\n")) return 0; 279238106Sdes for(slab=0; slab<sh->size; slab++) { 280238106Sdes lock_quick_lock(&sh->array[slab]->lock); 281238106Sdes if(!dump_msg_lruhash(ssl, worker, sh->array[slab])) { 282238106Sdes lock_quick_unlock(&sh->array[slab]->lock); 283238106Sdes return 0; 284238106Sdes } 285238106Sdes lock_quick_unlock(&sh->array[slab]->lock); 286238106Sdes } 287238106Sdes return ssl_printf(ssl, "END_MSG_CACHE\n"); 288238106Sdes} 289238106Sdes 290238106Sdesint 291238106Sdesdump_cache(SSL* ssl, struct worker* worker) 292238106Sdes{ 293238106Sdes if(!dump_rrset_cache(ssl, worker)) 294238106Sdes return 0; 295238106Sdes if(!dump_msg_cache(ssl, worker)) 296238106Sdes return 0; 297238106Sdes return ssl_printf(ssl, "EOF\n"); 298238106Sdes} 299238106Sdes 300238106Sdes/** read a line from ssl into buffer */ 301238106Sdesstatic int 302269257Sdesssl_read_buf(SSL* ssl, sldns_buffer* buf) 303238106Sdes{ 304269257Sdes return ssl_read_line(ssl, (char*)sldns_buffer_begin(buf), 305269257Sdes sldns_buffer_capacity(buf)); 306238106Sdes} 307238106Sdes 308238106Sdes/** check fixed text on line */ 309238106Sdesstatic int 310269257Sdesread_fixed(SSL* ssl, sldns_buffer* buf, const char* str) 311238106Sdes{ 312238106Sdes if(!ssl_read_buf(ssl, buf)) return 0; 313269257Sdes return (strcmp((char*)sldns_buffer_begin(buf), str) == 0); 314238106Sdes} 315238106Sdes 316238106Sdes/** load an RR into rrset */ 317238106Sdesstatic int 318269257Sdesload_rr(SSL* ssl, sldns_buffer* buf, struct regional* region, 319238106Sdes struct ub_packed_rrset_key* rk, struct packed_rrset_data* d, 320269257Sdes unsigned int i, int is_rrsig, int* go_on, time_t now) 321238106Sdes{ 322269257Sdes uint8_t rr[LDNS_RR_BUF_SIZE]; 323269257Sdes size_t rr_len = sizeof(rr), dname_len = 0; 324269257Sdes int status; 325238106Sdes 326238106Sdes /* read the line */ 327238106Sdes if(!ssl_read_buf(ssl, buf)) 328238106Sdes return 0; 329269257Sdes if(strncmp((char*)sldns_buffer_begin(buf), "BADRR\n", 6) == 0) { 330238106Sdes *go_on = 0; 331238106Sdes return 1; 332238106Sdes } 333269257Sdes status = sldns_str2wire_rr_buf((char*)sldns_buffer_begin(buf), rr, 334269257Sdes &rr_len, &dname_len, 3600, NULL, 0, NULL, 0); 335269257Sdes if(status != 0) { 336238106Sdes log_warn("error cannot parse rr: %s: %s", 337269257Sdes sldns_get_errorstr_parse(status), 338269257Sdes (char*)sldns_buffer_begin(buf)); 339238106Sdes return 0; 340238106Sdes } 341269257Sdes if(is_rrsig && sldns_wirerr_get_type(rr, rr_len, dname_len) 342269257Sdes != LDNS_RR_TYPE_RRSIG) { 343238106Sdes log_warn("error expected rrsig but got %s", 344269257Sdes (char*)sldns_buffer_begin(buf)); 345238106Sdes return 0; 346238106Sdes } 347238106Sdes 348238106Sdes /* convert ldns rr into packed_rr */ 349269257Sdes d->rr_ttl[i] = (time_t)sldns_wirerr_get_ttl(rr, rr_len, dname_len) + now; 350269257Sdes sldns_buffer_clear(buf); 351269257Sdes d->rr_len[i] = sldns_wirerr_get_rdatalen(rr, rr_len, dname_len)+2; 352238106Sdes d->rr_data[i] = (uint8_t*)regional_alloc_init(region, 353269257Sdes sldns_wirerr_get_rdatawl(rr, rr_len, dname_len), d->rr_len[i]); 354238106Sdes if(!d->rr_data[i]) { 355238106Sdes log_warn("error out of memory"); 356238106Sdes return 0; 357238106Sdes } 358238106Sdes 359238106Sdes /* if first entry, fill the key structure */ 360238106Sdes if(i==0) { 361269257Sdes rk->rk.type = htons(sldns_wirerr_get_type(rr, rr_len, dname_len)); 362269257Sdes rk->rk.rrset_class = htons(sldns_wirerr_get_class(rr, rr_len, dname_len)); 363269257Sdes rk->rk.dname_len = dname_len; 364269257Sdes rk->rk.dname = regional_alloc_init(region, rr, dname_len); 365238106Sdes if(!rk->rk.dname) { 366238106Sdes log_warn("error out of memory"); 367238106Sdes return 0; 368238106Sdes } 369238106Sdes } 370238106Sdes 371238106Sdes return 1; 372238106Sdes} 373238106Sdes 374238106Sdes/** move entry into cache */ 375238106Sdesstatic int 376238106Sdesmove_into_cache(struct ub_packed_rrset_key* k, 377238106Sdes struct packed_rrset_data* d, struct worker* worker) 378238106Sdes{ 379238106Sdes struct ub_packed_rrset_key* ak; 380238106Sdes struct packed_rrset_data* ad; 381238106Sdes size_t s, i, num = d->count + d->rrsig_count; 382238106Sdes struct rrset_ref ref; 383238106Sdes uint8_t* p; 384238106Sdes 385238106Sdes ak = alloc_special_obtain(&worker->alloc); 386238106Sdes if(!ak) { 387238106Sdes log_warn("error out of memory"); 388238106Sdes return 0; 389238106Sdes } 390238106Sdes ak->entry.data = NULL; 391238106Sdes ak->rk = k->rk; 392238106Sdes ak->entry.hash = rrset_key_hash(&k->rk); 393238106Sdes ak->rk.dname = (uint8_t*)memdup(k->rk.dname, k->rk.dname_len); 394238106Sdes if(!ak->rk.dname) { 395238106Sdes log_warn("error out of memory"); 396238106Sdes ub_packed_rrset_parsedelete(ak, &worker->alloc); 397238106Sdes return 0; 398238106Sdes } 399238106Sdes s = sizeof(*ad) + (sizeof(size_t) + sizeof(uint8_t*) + 400269257Sdes sizeof(time_t))* num; 401238106Sdes for(i=0; i<num; i++) 402238106Sdes s += d->rr_len[i]; 403238106Sdes ad = (struct packed_rrset_data*)malloc(s); 404238106Sdes if(!ad) { 405238106Sdes log_warn("error out of memory"); 406238106Sdes ub_packed_rrset_parsedelete(ak, &worker->alloc); 407238106Sdes return 0; 408238106Sdes } 409238106Sdes p = (uint8_t*)ad; 410238106Sdes memmove(p, d, sizeof(*ad)); 411238106Sdes p += sizeof(*ad); 412238106Sdes memmove(p, &d->rr_len[0], sizeof(size_t)*num); 413238106Sdes p += sizeof(size_t)*num; 414238106Sdes memmove(p, &d->rr_data[0], sizeof(uint8_t*)*num); 415238106Sdes p += sizeof(uint8_t*)*num; 416269257Sdes memmove(p, &d->rr_ttl[0], sizeof(time_t)*num); 417269257Sdes p += sizeof(time_t)*num; 418238106Sdes for(i=0; i<num; i++) { 419238106Sdes memmove(p, d->rr_data[i], d->rr_len[i]); 420238106Sdes p += d->rr_len[i]; 421238106Sdes } 422238106Sdes packed_rrset_ptr_fixup(ad); 423238106Sdes 424238106Sdes ak->entry.data = ad; 425238106Sdes 426238106Sdes ref.key = ak; 427238106Sdes ref.id = ak->id; 428238106Sdes (void)rrset_cache_update(worker->env.rrset_cache, &ref, 429238106Sdes &worker->alloc, *worker->env.now); 430238106Sdes return 1; 431238106Sdes} 432238106Sdes 433238106Sdes/** load an rrset entry */ 434238106Sdesstatic int 435269257Sdesload_rrset(SSL* ssl, sldns_buffer* buf, struct worker* worker) 436238106Sdes{ 437269257Sdes char* s = (char*)sldns_buffer_begin(buf); 438238106Sdes struct regional* region = worker->scratchpad; 439238106Sdes struct ub_packed_rrset_key* rk; 440238106Sdes struct packed_rrset_data* d; 441269257Sdes unsigned int rr_count, rrsig_count, trust, security; 442269257Sdes long long ttl; 443238106Sdes unsigned int i; 444238106Sdes int go_on = 1; 445238106Sdes regional_free_all(region); 446238106Sdes 447238106Sdes rk = (struct ub_packed_rrset_key*)regional_alloc_zero(region, 448238106Sdes sizeof(*rk)); 449238106Sdes d = (struct packed_rrset_data*)regional_alloc_zero(region, sizeof(*d)); 450238106Sdes if(!rk || !d) { 451238106Sdes log_warn("error out of memory"); 452238106Sdes return 0; 453238106Sdes } 454238106Sdes 455238106Sdes if(strncmp(s, ";rrset", 6) != 0) { 456238106Sdes log_warn("error expected ';rrset' but got %s", s); 457238106Sdes return 0; 458238106Sdes } 459238106Sdes s += 6; 460238106Sdes if(strncmp(s, " nsec_apex", 10) == 0) { 461238106Sdes s += 10; 462238106Sdes rk->rk.flags |= PACKED_RRSET_NSEC_AT_APEX; 463238106Sdes } 464269257Sdes if(sscanf(s, " " ARG_LL "d %u %u %u %u", &ttl, &rr_count, &rrsig_count, 465238106Sdes &trust, &security) != 5) { 466238106Sdes log_warn("error bad rrset spec %s", s); 467238106Sdes return 0; 468238106Sdes } 469238106Sdes if(rr_count == 0 && rrsig_count == 0) { 470238106Sdes log_warn("bad rrset without contents"); 471238106Sdes return 0; 472238106Sdes } 473238106Sdes d->count = (size_t)rr_count; 474238106Sdes d->rrsig_count = (size_t)rrsig_count; 475238106Sdes d->security = (enum sec_status)security; 476238106Sdes d->trust = (enum rrset_trust)trust; 477269257Sdes d->ttl = (time_t)ttl + *worker->env.now; 478238106Sdes 479238106Sdes d->rr_len = regional_alloc_zero(region, 480238106Sdes sizeof(size_t)*(d->count+d->rrsig_count)); 481238106Sdes d->rr_ttl = regional_alloc_zero(region, 482269257Sdes sizeof(time_t)*(d->count+d->rrsig_count)); 483238106Sdes d->rr_data = regional_alloc_zero(region, 484238106Sdes sizeof(uint8_t*)*(d->count+d->rrsig_count)); 485238106Sdes if(!d->rr_len || !d->rr_ttl || !d->rr_data) { 486238106Sdes log_warn("error out of memory"); 487238106Sdes return 0; 488238106Sdes } 489238106Sdes 490238106Sdes /* read the rr's themselves */ 491238106Sdes for(i=0; i<rr_count; i++) { 492238106Sdes if(!load_rr(ssl, buf, region, rk, d, i, 0, 493238106Sdes &go_on, *worker->env.now)) { 494238106Sdes log_warn("could not read rr %u", i); 495238106Sdes return 0; 496238106Sdes } 497238106Sdes } 498238106Sdes for(i=0; i<rrsig_count; i++) { 499238106Sdes if(!load_rr(ssl, buf, region, rk, d, i+rr_count, 1, 500238106Sdes &go_on, *worker->env.now)) { 501238106Sdes log_warn("could not read rrsig %u", i); 502238106Sdes return 0; 503238106Sdes } 504238106Sdes } 505238106Sdes if(!go_on) { 506238106Sdes /* skip this entry */ 507238106Sdes return 1; 508238106Sdes } 509238106Sdes 510238106Sdes return move_into_cache(rk, d, worker); 511238106Sdes} 512238106Sdes 513238106Sdes/** load rrset cache */ 514238106Sdesstatic int 515238106Sdesload_rrset_cache(SSL* ssl, struct worker* worker) 516238106Sdes{ 517269257Sdes sldns_buffer* buf = worker->env.scratch_buffer; 518238106Sdes if(!read_fixed(ssl, buf, "START_RRSET_CACHE")) return 0; 519238106Sdes while(ssl_read_buf(ssl, buf) && 520269257Sdes strcmp((char*)sldns_buffer_begin(buf), "END_RRSET_CACHE")!=0) { 521238106Sdes if(!load_rrset(ssl, buf, worker)) 522238106Sdes return 0; 523238106Sdes } 524238106Sdes return 1; 525238106Sdes} 526238106Sdes 527238106Sdes/** read qinfo from next three words */ 528238106Sdesstatic char* 529269257Sdesload_qinfo(char* str, struct query_info* qinfo, struct regional* region) 530238106Sdes{ 531238106Sdes /* s is part of the buf */ 532238106Sdes char* s = str; 533269257Sdes uint8_t rr[LDNS_RR_BUF_SIZE]; 534269257Sdes size_t rr_len = sizeof(rr), dname_len = 0; 535269257Sdes int status; 536238106Sdes 537238106Sdes /* skip three words */ 538238106Sdes s = strchr(str, ' '); 539238106Sdes if(s) s = strchr(s+1, ' '); 540238106Sdes if(s) s = strchr(s+1, ' '); 541238106Sdes if(!s) { 542238106Sdes log_warn("error line too short, %s", str); 543238106Sdes return NULL; 544238106Sdes } 545238106Sdes s[0] = 0; 546238106Sdes s++; 547238106Sdes 548238106Sdes /* parse them */ 549269257Sdes status = sldns_str2wire_rr_question_buf(str, rr, &rr_len, &dname_len, 550269257Sdes NULL, 0, NULL, 0); 551269257Sdes if(status != 0) { 552238106Sdes log_warn("error cannot parse: %s %s", 553269257Sdes sldns_get_errorstr_parse(status), str); 554238106Sdes return NULL; 555238106Sdes } 556269257Sdes qinfo->qtype = sldns_wirerr_get_type(rr, rr_len, dname_len); 557269257Sdes qinfo->qclass = sldns_wirerr_get_class(rr, rr_len, dname_len); 558269257Sdes qinfo->qname_len = dname_len; 559269257Sdes qinfo->qname = (uint8_t*)regional_alloc_init(region, rr, dname_len); 560238106Sdes if(!qinfo->qname) { 561238106Sdes log_warn("error out of memory"); 562238106Sdes return NULL; 563238106Sdes } 564238106Sdes 565238106Sdes return s; 566238106Sdes} 567238106Sdes 568238106Sdes/** load a msg rrset reference */ 569238106Sdesstatic int 570269257Sdesload_ref(SSL* ssl, sldns_buffer* buf, struct worker* worker, 571238106Sdes struct regional *region, struct ub_packed_rrset_key** rrset, 572238106Sdes int* go_on) 573238106Sdes{ 574269257Sdes char* s = (char*)sldns_buffer_begin(buf); 575238106Sdes struct query_info qinfo; 576238106Sdes unsigned int flags; 577238106Sdes struct ub_packed_rrset_key* k; 578238106Sdes 579238106Sdes /* read line */ 580238106Sdes if(!ssl_read_buf(ssl, buf)) 581238106Sdes return 0; 582238106Sdes if(strncmp(s, "BADREF", 6) == 0) { 583238106Sdes *go_on = 0; /* its bad, skip it and skip message */ 584238106Sdes return 1; 585238106Sdes } 586238106Sdes 587269257Sdes s = load_qinfo(s, &qinfo, region); 588238106Sdes if(!s) { 589238106Sdes return 0; 590238106Sdes } 591238106Sdes if(sscanf(s, " %u", &flags) != 1) { 592238106Sdes log_warn("error cannot parse flags: %s", s); 593238106Sdes return 0; 594238106Sdes } 595238106Sdes 596238106Sdes /* lookup in cache */ 597238106Sdes k = rrset_cache_lookup(worker->env.rrset_cache, qinfo.qname, 598238106Sdes qinfo.qname_len, qinfo.qtype, qinfo.qclass, 599238106Sdes (uint32_t)flags, *worker->env.now, 0); 600238106Sdes if(!k) { 601238106Sdes /* not found or expired */ 602238106Sdes *go_on = 0; 603238106Sdes return 1; 604238106Sdes } 605238106Sdes 606238106Sdes /* store in result */ 607238106Sdes *rrset = packed_rrset_copy_region(k, region, *worker->env.now); 608238106Sdes lock_rw_unlock(&k->entry.lock); 609238106Sdes 610238106Sdes return (*rrset != NULL); 611238106Sdes} 612238106Sdes 613238106Sdes/** load a msg entry */ 614238106Sdesstatic int 615269257Sdesload_msg(SSL* ssl, sldns_buffer* buf, struct worker* worker) 616238106Sdes{ 617238106Sdes struct regional* region = worker->scratchpad; 618238106Sdes struct query_info qinf; 619238106Sdes struct reply_info rep; 620269257Sdes char* s = (char*)sldns_buffer_begin(buf); 621269257Sdes unsigned int flags, qdcount, security, an, ns, ar; 622269257Sdes long long ttl; 623238106Sdes size_t i; 624238106Sdes int go_on = 1; 625238106Sdes 626238106Sdes regional_free_all(region); 627238106Sdes 628238106Sdes if(strncmp(s, "msg ", 4) != 0) { 629238106Sdes log_warn("error expected msg but got %s", s); 630238106Sdes return 0; 631238106Sdes } 632238106Sdes s += 4; 633269257Sdes s = load_qinfo(s, &qinf, region); 634238106Sdes if(!s) { 635238106Sdes return 0; 636238106Sdes } 637238106Sdes 638238106Sdes /* read remainder of line */ 639269257Sdes if(sscanf(s, " %u %u " ARG_LL "d %u %u %u %u", &flags, &qdcount, &ttl, 640238106Sdes &security, &an, &ns, &ar) != 7) { 641238106Sdes log_warn("error cannot parse numbers: %s", s); 642238106Sdes return 0; 643238106Sdes } 644238106Sdes rep.flags = (uint16_t)flags; 645238106Sdes rep.qdcount = (uint16_t)qdcount; 646269257Sdes rep.ttl = (time_t)ttl; 647238106Sdes rep.prefetch_ttl = PREFETCH_TTL_CALC(rep.ttl); 648238106Sdes rep.security = (enum sec_status)security; 649238106Sdes rep.an_numrrsets = (size_t)an; 650238106Sdes rep.ns_numrrsets = (size_t)ns; 651238106Sdes rep.ar_numrrsets = (size_t)ar; 652238106Sdes rep.rrset_count = (size_t)an+(size_t)ns+(size_t)ar; 653238106Sdes rep.rrsets = (struct ub_packed_rrset_key**)regional_alloc_zero( 654238106Sdes region, sizeof(struct ub_packed_rrset_key*)*rep.rrset_count); 655238106Sdes 656238106Sdes /* fill repinfo with references */ 657238106Sdes for(i=0; i<rep.rrset_count; i++) { 658238106Sdes if(!load_ref(ssl, buf, worker, region, &rep.rrsets[i], 659238106Sdes &go_on)) { 660238106Sdes return 0; 661238106Sdes } 662238106Sdes } 663238106Sdes 664238106Sdes if(!go_on) 665238106Sdes return 1; /* skip this one, not all references satisfied */ 666238106Sdes 667238106Sdes if(!dns_cache_store(&worker->env, &qinf, &rep, 0, 0, 0, NULL)) { 668238106Sdes log_warn("error out of memory"); 669238106Sdes return 0; 670238106Sdes } 671238106Sdes return 1; 672238106Sdes} 673238106Sdes 674238106Sdes/** load msg cache */ 675238106Sdesstatic int 676238106Sdesload_msg_cache(SSL* ssl, struct worker* worker) 677238106Sdes{ 678269257Sdes sldns_buffer* buf = worker->env.scratch_buffer; 679238106Sdes if(!read_fixed(ssl, buf, "START_MSG_CACHE")) return 0; 680238106Sdes while(ssl_read_buf(ssl, buf) && 681269257Sdes strcmp((char*)sldns_buffer_begin(buf), "END_MSG_CACHE")!=0) { 682238106Sdes if(!load_msg(ssl, buf, worker)) 683238106Sdes return 0; 684238106Sdes } 685238106Sdes return 1; 686238106Sdes} 687238106Sdes 688238106Sdesint 689238106Sdesload_cache(SSL* ssl, struct worker* worker) 690238106Sdes{ 691238106Sdes if(!load_rrset_cache(ssl, worker)) 692238106Sdes return 0; 693238106Sdes if(!load_msg_cache(ssl, worker)) 694238106Sdes return 0; 695238106Sdes return read_fixed(ssl, worker->env.scratch_buffer, "EOF"); 696238106Sdes} 697238106Sdes 698238106Sdes/** print details on a delegation point */ 699238106Sdesstatic void 700238106Sdesprint_dp_details(SSL* ssl, struct worker* worker, struct delegpt* dp) 701238106Sdes{ 702238106Sdes char buf[257]; 703238106Sdes struct delegpt_addr* a; 704269257Sdes int lame, dlame, rlame, rto, edns_vs, to, delay, 705238106Sdes tA = 0, tAAAA = 0, tother = 0; 706269257Sdes long long entry_ttl; 707238106Sdes struct rtt_info ri; 708238106Sdes uint8_t edns_lame_known; 709238106Sdes for(a = dp->target_list; a; a = a->next_target) { 710238106Sdes addr_to_str(&a->addr, a->addrlen, buf, sizeof(buf)); 711238106Sdes if(!ssl_printf(ssl, "%-16s\t", buf)) 712238106Sdes return; 713238106Sdes if(a->bogus) { 714238106Sdes if(!ssl_printf(ssl, "Address is BOGUS. ")) 715238106Sdes return; 716238106Sdes } 717238106Sdes /* lookup in infra cache */ 718238106Sdes delay=0; 719238106Sdes entry_ttl = infra_get_host_rto(worker->env.infra_cache, 720238106Sdes &a->addr, a->addrlen, dp->name, dp->namelen, 721238106Sdes &ri, &delay, *worker->env.now, &tA, &tAAAA, &tother); 722238106Sdes if(entry_ttl == -2 && ri.rto >= USEFUL_SERVER_TOP_TIMEOUT) { 723238106Sdes if(!ssl_printf(ssl, "expired, rto %d msec, tA %d " 724238106Sdes "tAAAA %d tother %d.\n", ri.rto, tA, tAAAA, 725238106Sdes tother)) 726238106Sdes return; 727238106Sdes continue; 728238106Sdes } 729238106Sdes if(entry_ttl == -1 || entry_ttl == -2) { 730238106Sdes if(!ssl_printf(ssl, "not in infra cache.\n")) 731238106Sdes return; 732238106Sdes continue; /* skip stuff not in infra cache */ 733238106Sdes } 734238106Sdes 735238106Sdes /* uses type_A because most often looked up, but other 736238106Sdes * lameness won't be reported then */ 737238106Sdes if(!infra_get_lame_rtt(worker->env.infra_cache, 738238106Sdes &a->addr, a->addrlen, dp->name, dp->namelen, 739238106Sdes LDNS_RR_TYPE_A, &lame, &dlame, &rlame, &rto, 740238106Sdes *worker->env.now)) { 741238106Sdes if(!ssl_printf(ssl, "not in infra cache.\n")) 742238106Sdes return; 743238106Sdes continue; /* skip stuff not in infra cache */ 744238106Sdes } 745269257Sdes if(!ssl_printf(ssl, "%s%s%s%srto %d msec, ttl " ARG_LL "d, " 746269257Sdes "ping %d var %d rtt %d, tA %d, tAAAA %d, tother %d", 747238106Sdes lame?"LAME ":"", dlame?"NoDNSSEC ":"", 748238106Sdes a->lame?"AddrWasParentSide ":"", 749238106Sdes rlame?"NoAuthButRecursive ":"", rto, entry_ttl, 750238106Sdes ri.srtt, ri.rttvar, rtt_notimeout(&ri), 751238106Sdes tA, tAAAA, tother)) 752238106Sdes return; 753238106Sdes if(delay) 754238106Sdes if(!ssl_printf(ssl, ", probedelay %d", delay)) 755238106Sdes return; 756238106Sdes if(infra_host(worker->env.infra_cache, &a->addr, a->addrlen, 757238106Sdes dp->name, dp->namelen, *worker->env.now, &edns_vs, 758238106Sdes &edns_lame_known, &to)) { 759238106Sdes if(edns_vs == -1) { 760238106Sdes if(!ssl_printf(ssl, ", noEDNS%s.", 761238106Sdes edns_lame_known?" probed":" assumed")) 762238106Sdes return; 763238106Sdes } else { 764238106Sdes if(!ssl_printf(ssl, ", EDNS %d%s.", edns_vs, 765238106Sdes edns_lame_known?" probed":" assumed")) 766238106Sdes return; 767238106Sdes } 768238106Sdes } 769238106Sdes if(!ssl_printf(ssl, "\n")) 770238106Sdes return; 771238106Sdes } 772238106Sdes} 773238106Sdes 774238106Sdes/** print main dp info */ 775238106Sdesstatic void 776238106Sdesprint_dp_main(SSL* ssl, struct delegpt* dp, struct dns_msg* msg) 777238106Sdes{ 778238106Sdes size_t i, n_ns, n_miss, n_addr, n_res, n_avail; 779238106Sdes 780238106Sdes /* print the dp */ 781238106Sdes if(msg) 782238106Sdes for(i=0; i<msg->rep->rrset_count; i++) { 783238106Sdes struct ub_packed_rrset_key* k = msg->rep->rrsets[i]; 784238106Sdes struct packed_rrset_data* d = 785238106Sdes (struct packed_rrset_data*)k->entry.data; 786238106Sdes if(d->security == sec_status_bogus) { 787238106Sdes if(!ssl_printf(ssl, "Address is BOGUS:\n")) 788238106Sdes return; 789238106Sdes } 790238106Sdes if(!dump_rrset(ssl, k, d, 0)) 791238106Sdes return; 792238106Sdes } 793238106Sdes delegpt_count_ns(dp, &n_ns, &n_miss); 794238106Sdes delegpt_count_addr(dp, &n_addr, &n_res, &n_avail); 795238106Sdes /* since dp has not been used by iterator, all are available*/ 796238106Sdes if(!ssl_printf(ssl, "Delegation with %d names, of which %d " 797238106Sdes "can be examined to query further addresses.\n" 798238106Sdes "%sIt provides %d IP addresses.\n", 799238106Sdes (int)n_ns, (int)n_miss, (dp->bogus?"It is BOGUS. ":""), 800238106Sdes (int)n_addr)) 801238106Sdes return; 802238106Sdes} 803238106Sdes 804238106Sdesint print_deleg_lookup(SSL* ssl, struct worker* worker, uint8_t* nm, 805238106Sdes size_t nmlen, int ATTR_UNUSED(nmlabs)) 806238106Sdes{ 807238106Sdes /* deep links into the iterator module */ 808238106Sdes struct delegpt* dp; 809238106Sdes struct dns_msg* msg; 810238106Sdes struct regional* region = worker->scratchpad; 811238106Sdes char b[260]; 812238106Sdes struct query_info qinfo; 813238106Sdes struct iter_hints_stub* stub; 814238106Sdes regional_free_all(region); 815238106Sdes qinfo.qname = nm; 816238106Sdes qinfo.qname_len = nmlen; 817238106Sdes qinfo.qtype = LDNS_RR_TYPE_A; 818238106Sdes qinfo.qclass = LDNS_RR_CLASS_IN; 819238106Sdes 820238106Sdes dname_str(nm, b); 821238106Sdes if(!ssl_printf(ssl, "The following name servers are used for lookup " 822238106Sdes "of %s\n", b)) 823238106Sdes return 0; 824238106Sdes 825238106Sdes dp = forwards_lookup(worker->env.fwds, nm, qinfo.qclass); 826238106Sdes if(dp) { 827238106Sdes if(!ssl_printf(ssl, "forwarding request:\n")) 828238106Sdes return 0; 829238106Sdes print_dp_main(ssl, dp, NULL); 830238106Sdes print_dp_details(ssl, worker, dp); 831238106Sdes return 1; 832238106Sdes } 833238106Sdes 834238106Sdes while(1) { 835238106Sdes dp = dns_cache_find_delegation(&worker->env, nm, nmlen, 836238106Sdes qinfo.qtype, qinfo.qclass, region, &msg, 837238106Sdes *worker->env.now); 838238106Sdes if(!dp) { 839238106Sdes return ssl_printf(ssl, "no delegation from " 840238106Sdes "cache; goes to configured roots\n"); 841238106Sdes } 842238106Sdes /* go up? */ 843238106Sdes if(iter_dp_is_useless(&qinfo, BIT_RD, dp)) { 844238106Sdes print_dp_main(ssl, dp, msg); 845238106Sdes print_dp_details(ssl, worker, dp); 846238106Sdes if(!ssl_printf(ssl, "cache delegation was " 847238106Sdes "useless (no IP addresses)\n")) 848238106Sdes return 0; 849238106Sdes if(dname_is_root(nm)) { 850238106Sdes /* goes to root config */ 851238106Sdes return ssl_printf(ssl, "no delegation from " 852238106Sdes "cache; goes to configured roots\n"); 853238106Sdes } else { 854238106Sdes /* useless, goes up */ 855238106Sdes nm = dp->name; 856238106Sdes nmlen = dp->namelen; 857238106Sdes dname_remove_label(&nm, &nmlen); 858238106Sdes dname_str(nm, b); 859238106Sdes if(!ssl_printf(ssl, "going up, lookup %s\n", b)) 860238106Sdes return 0; 861238106Sdes continue; 862238106Sdes } 863238106Sdes } 864238106Sdes stub = hints_lookup_stub(worker->env.hints, nm, qinfo.qclass, 865238106Sdes dp); 866238106Sdes if(stub) { 867238106Sdes if(stub->noprime) { 868238106Sdes if(!ssl_printf(ssl, "The noprime stub servers " 869238106Sdes "are used:\n")) 870238106Sdes return 0; 871238106Sdes } else { 872238106Sdes if(!ssl_printf(ssl, "The stub is primed " 873238106Sdes "with servers:\n")) 874238106Sdes return 0; 875238106Sdes } 876238106Sdes print_dp_main(ssl, stub->dp, NULL); 877238106Sdes print_dp_details(ssl, worker, stub->dp); 878238106Sdes } else { 879238106Sdes print_dp_main(ssl, dp, msg); 880238106Sdes print_dp_details(ssl, worker, dp); 881238106Sdes } 882238106Sdes break; 883238106Sdes } 884238106Sdes 885238106Sdes return 1; 886238106Sdes} 887