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 24266114Sdes * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 25266114Sdes * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 26266114Sdes * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 27266114Sdes * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 28266114Sdes * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 29266114Sdes * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 30266114Sdes * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 31266114Sdes * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 32266114Sdes * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 33266114Sdes * 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" 43266114Sdes#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" 59287917Sdes#include "sldns/sbuffer.h" 60287917Sdes#include "sldns/wire2str.h" 61287917Sdes#include "sldns/str2wire.h" 62238106Sdes 63238106Sdes/** dump one rrset zonefile line */ 64238106Sdesstatic int 65356345Scydump_rrset_line(RES* ssl, struct ub_packed_rrset_key* k, time_t now, size_t i) 66238106Sdes{ 67266114Sdes char s[65535]; 68266114Sdes if(!packed_rr_to_string(k, i, now, s, sizeof(s))) { 69238106Sdes return ssl_printf(ssl, "BADRR\n"); 70238106Sdes } 71266114Sdes return ssl_printf(ssl, "%s", s); 72238106Sdes} 73238106Sdes 74238106Sdes/** dump rrset key and data info */ 75238106Sdesstatic int 76356345Scydump_rrset(RES* ssl, struct ub_packed_rrset_key* k, 77266114Sdes 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; 82356345Scy if(k->id == 0) return 1; /* deleted */ 83238106Sdes if(d->ttl < now) return 1; /* expired */ 84238106Sdes 85238106Sdes /* meta line */ 86266114Sdes if(!ssl_printf(ssl, ";rrset%s " ARG_LL "d %u %u %d %d\n", 87238106Sdes (k->rk.flags & PACKED_RRSET_NSEC_AT_APEX)?" nsec_apex":"", 88266114Sdes (long long)(d->ttl - now), 89238106Sdes (unsigned)d->count, (unsigned)d->rrsig_count, 90238106Sdes (int)d->trust, (int)d->security 91238106Sdes )) 92238106Sdes return 0; 93266114Sdes for(i=0; i<d->count + d->rrsig_count; i++) { 94266114Sdes if(!dump_rrset_line(ssl, k, now, i)) 95238106Sdes return 0; 96238106Sdes } 97238106Sdes return 1; 98238106Sdes} 99238106Sdes 100238106Sdes/** dump lruhash rrset cache */ 101238106Sdesstatic int 102356345Scydump_rrset_lruhash(RES* ssl, struct lruhash* h, time_t now) 103238106Sdes{ 104238106Sdes struct lruhash_entry* e; 105238106Sdes /* lruhash already locked by caller */ 106238106Sdes /* walk in order of lru; best first */ 107238106Sdes for(e=h->lru_start; e; e = e->lru_next) { 108238106Sdes lock_rw_rdlock(&e->lock); 109238106Sdes if(!dump_rrset(ssl, (struct ub_packed_rrset_key*)e->key, 110238106Sdes (struct packed_rrset_data*)e->data, now)) { 111238106Sdes lock_rw_unlock(&e->lock); 112238106Sdes return 0; 113238106Sdes } 114238106Sdes lock_rw_unlock(&e->lock); 115238106Sdes } 116238106Sdes return 1; 117238106Sdes} 118238106Sdes 119238106Sdes/** dump rrset cache */ 120238106Sdesstatic int 121356345Scydump_rrset_cache(RES* ssl, struct worker* worker) 122238106Sdes{ 123238106Sdes struct rrset_cache* r = worker->env.rrset_cache; 124238106Sdes size_t slab; 125238106Sdes if(!ssl_printf(ssl, "START_RRSET_CACHE\n")) return 0; 126238106Sdes for(slab=0; slab<r->table.size; slab++) { 127238106Sdes lock_quick_lock(&r->table.array[slab]->lock); 128238106Sdes if(!dump_rrset_lruhash(ssl, r->table.array[slab], 129238106Sdes *worker->env.now)) { 130238106Sdes lock_quick_unlock(&r->table.array[slab]->lock); 131238106Sdes return 0; 132238106Sdes } 133238106Sdes lock_quick_unlock(&r->table.array[slab]->lock); 134238106Sdes } 135238106Sdes return ssl_printf(ssl, "END_RRSET_CACHE\n"); 136238106Sdes} 137238106Sdes 138238106Sdes/** dump message to rrset reference */ 139238106Sdesstatic int 140356345Scydump_msg_ref(RES* ssl, struct ub_packed_rrset_key* k) 141238106Sdes{ 142238106Sdes char* nm, *tp, *cl; 143266114Sdes nm = sldns_wire2str_dname(k->rk.dname, k->rk.dname_len); 144266114Sdes tp = sldns_wire2str_type(ntohs(k->rk.type)); 145266114Sdes cl = sldns_wire2str_class(ntohs(k->rk.rrset_class)); 146238106Sdes if(!nm || !cl || !tp) { 147238106Sdes free(nm); 148238106Sdes free(tp); 149238106Sdes free(cl); 150238106Sdes return ssl_printf(ssl, "BADREF\n"); 151238106Sdes } 152238106Sdes if(!ssl_printf(ssl, "%s %s %s %d\n", nm, cl, tp, (int)k->rk.flags)) { 153238106Sdes free(nm); 154238106Sdes free(tp); 155238106Sdes free(cl); 156238106Sdes return 0; 157238106Sdes } 158238106Sdes free(nm); 159238106Sdes free(tp); 160238106Sdes free(cl); 161238106Sdes 162238106Sdes return 1; 163238106Sdes} 164238106Sdes 165238106Sdes/** dump message entry */ 166238106Sdesstatic int 167356345Scydump_msg(RES* ssl, struct query_info* k, struct reply_info* d, 168266114Sdes time_t now) 169238106Sdes{ 170238106Sdes size_t i; 171238106Sdes char* nm, *tp, *cl; 172238106Sdes if(!k || !d) return 1; 173238106Sdes if(d->ttl < now) return 1; /* expired */ 174238106Sdes 175266114Sdes nm = sldns_wire2str_dname(k->qname, k->qname_len); 176266114Sdes tp = sldns_wire2str_type(k->qtype); 177266114Sdes cl = sldns_wire2str_class(k->qclass); 178238106Sdes if(!nm || !tp || !cl) { 179238106Sdes free(nm); 180238106Sdes free(tp); 181238106Sdes free(cl); 182238106Sdes return 1; /* skip this entry */ 183238106Sdes } 184238106Sdes if(!rrset_array_lock(d->ref, d->rrset_count, now)) { 185238106Sdes /* rrsets have timed out or do not exist */ 186238106Sdes free(nm); 187238106Sdes free(tp); 188238106Sdes free(cl); 189238106Sdes return 1; /* skip this entry */ 190238106Sdes } 191238106Sdes 192238106Sdes /* meta line */ 193266114Sdes if(!ssl_printf(ssl, "msg %s %s %s %d %d " ARG_LL "d %d %u %u %u\n", 194238106Sdes nm, cl, tp, 195238106Sdes (int)d->flags, (int)d->qdcount, 196266114Sdes (long long)(d->ttl-now), (int)d->security, 197238106Sdes (unsigned)d->an_numrrsets, 198238106Sdes (unsigned)d->ns_numrrsets, 199238106Sdes (unsigned)d->ar_numrrsets)) { 200238106Sdes free(nm); 201238106Sdes free(tp); 202238106Sdes free(cl); 203238106Sdes rrset_array_unlock(d->ref, d->rrset_count); 204238106Sdes return 0; 205238106Sdes } 206238106Sdes free(nm); 207238106Sdes free(tp); 208238106Sdes free(cl); 209238106Sdes 210238106Sdes for(i=0; i<d->rrset_count; i++) { 211238106Sdes if(!dump_msg_ref(ssl, d->rrsets[i])) { 212238106Sdes rrset_array_unlock(d->ref, d->rrset_count); 213238106Sdes return 0; 214238106Sdes } 215238106Sdes } 216238106Sdes rrset_array_unlock(d->ref, d->rrset_count); 217238106Sdes 218238106Sdes return 1; 219238106Sdes} 220238106Sdes 221238106Sdes/** copy msg to worker pad */ 222238106Sdesstatic int 223238106Sdescopy_msg(struct regional* region, struct lruhash_entry* e, 224238106Sdes struct query_info** k, struct reply_info** d) 225238106Sdes{ 226238106Sdes struct reply_info* rep = (struct reply_info*)e->data; 227287917Sdes if(rep->rrset_count > RR_COUNT_MAX) 228287917Sdes return 0; /* to protect against integer overflow */ 229238106Sdes *d = (struct reply_info*)regional_alloc_init(region, e->data, 230238106Sdes sizeof(struct reply_info) + 231238106Sdes sizeof(struct rrset_ref) * (rep->rrset_count-1) + 232238106Sdes sizeof(struct ub_packed_rrset_key*) * rep->rrset_count); 233238106Sdes if(!*d) 234238106Sdes return 0; 235255579Sdes (*d)->rrsets = (struct ub_packed_rrset_key**)(void *)( 236238106Sdes (uint8_t*)(&((*d)->ref[0])) + 237238106Sdes sizeof(struct rrset_ref) * rep->rrset_count); 238238106Sdes *k = (struct query_info*)regional_alloc_init(region, 239238106Sdes e->key, sizeof(struct query_info)); 240238106Sdes if(!*k) 241238106Sdes return 0; 242238106Sdes (*k)->qname = regional_alloc_init(region, 243238106Sdes (*k)->qname, (*k)->qname_len); 244238106Sdes return (*k)->qname != NULL; 245238106Sdes} 246238106Sdes 247238106Sdes/** dump lruhash msg cache */ 248238106Sdesstatic int 249356345Scydump_msg_lruhash(RES* ssl, struct worker* worker, struct lruhash* h) 250238106Sdes{ 251238106Sdes struct lruhash_entry* e; 252238106Sdes struct query_info* k; 253238106Sdes struct reply_info* d; 254238106Sdes 255238106Sdes /* lruhash already locked by caller */ 256238106Sdes /* walk in order of lru; best first */ 257238106Sdes for(e=h->lru_start; e; e = e->lru_next) { 258238106Sdes regional_free_all(worker->scratchpad); 259238106Sdes lock_rw_rdlock(&e->lock); 260238106Sdes /* make copy of rrset in worker buffer */ 261238106Sdes if(!copy_msg(worker->scratchpad, e, &k, &d)) { 262238106Sdes lock_rw_unlock(&e->lock); 263238106Sdes return 0; 264238106Sdes } 265238106Sdes lock_rw_unlock(&e->lock); 266238106Sdes /* release lock so we can lookup the rrset references 267238106Sdes * in the rrset cache */ 268238106Sdes if(!dump_msg(ssl, k, d, *worker->env.now)) { 269238106Sdes return 0; 270238106Sdes } 271238106Sdes } 272238106Sdes return 1; 273238106Sdes} 274238106Sdes 275238106Sdes/** dump msg cache */ 276238106Sdesstatic int 277356345Scydump_msg_cache(RES* ssl, struct worker* worker) 278238106Sdes{ 279238106Sdes struct slabhash* sh = worker->env.msg_cache; 280238106Sdes size_t slab; 281238106Sdes if(!ssl_printf(ssl, "START_MSG_CACHE\n")) return 0; 282238106Sdes for(slab=0; slab<sh->size; slab++) { 283238106Sdes lock_quick_lock(&sh->array[slab]->lock); 284238106Sdes if(!dump_msg_lruhash(ssl, worker, sh->array[slab])) { 285238106Sdes lock_quick_unlock(&sh->array[slab]->lock); 286238106Sdes return 0; 287238106Sdes } 288238106Sdes lock_quick_unlock(&sh->array[slab]->lock); 289238106Sdes } 290238106Sdes return ssl_printf(ssl, "END_MSG_CACHE\n"); 291238106Sdes} 292238106Sdes 293238106Sdesint 294356345Scydump_cache(RES* ssl, struct worker* worker) 295238106Sdes{ 296238106Sdes if(!dump_rrset_cache(ssl, worker)) 297238106Sdes return 0; 298238106Sdes if(!dump_msg_cache(ssl, worker)) 299238106Sdes return 0; 300238106Sdes return ssl_printf(ssl, "EOF\n"); 301238106Sdes} 302238106Sdes 303238106Sdes/** read a line from ssl into buffer */ 304238106Sdesstatic int 305356345Scyssl_read_buf(RES* ssl, sldns_buffer* buf) 306238106Sdes{ 307266114Sdes return ssl_read_line(ssl, (char*)sldns_buffer_begin(buf), 308266114Sdes sldns_buffer_capacity(buf)); 309238106Sdes} 310238106Sdes 311238106Sdes/** check fixed text on line */ 312238106Sdesstatic int 313356345Scyread_fixed(RES* ssl, sldns_buffer* buf, const char* str) 314238106Sdes{ 315238106Sdes if(!ssl_read_buf(ssl, buf)) return 0; 316266114Sdes return (strcmp((char*)sldns_buffer_begin(buf), str) == 0); 317238106Sdes} 318238106Sdes 319238106Sdes/** load an RR into rrset */ 320238106Sdesstatic int 321356345Scyload_rr(RES* ssl, sldns_buffer* buf, struct regional* region, 322238106Sdes struct ub_packed_rrset_key* rk, struct packed_rrset_data* d, 323266114Sdes unsigned int i, int is_rrsig, int* go_on, time_t now) 324238106Sdes{ 325266114Sdes uint8_t rr[LDNS_RR_BUF_SIZE]; 326266114Sdes size_t rr_len = sizeof(rr), dname_len = 0; 327266114Sdes int status; 328238106Sdes 329238106Sdes /* read the line */ 330238106Sdes if(!ssl_read_buf(ssl, buf)) 331238106Sdes return 0; 332266114Sdes if(strncmp((char*)sldns_buffer_begin(buf), "BADRR\n", 6) == 0) { 333238106Sdes *go_on = 0; 334238106Sdes return 1; 335238106Sdes } 336266114Sdes status = sldns_str2wire_rr_buf((char*)sldns_buffer_begin(buf), rr, 337266114Sdes &rr_len, &dname_len, 3600, NULL, 0, NULL, 0); 338266114Sdes if(status != 0) { 339238106Sdes log_warn("error cannot parse rr: %s: %s", 340266114Sdes sldns_get_errorstr_parse(status), 341266114Sdes (char*)sldns_buffer_begin(buf)); 342238106Sdes return 0; 343238106Sdes } 344266114Sdes if(is_rrsig && sldns_wirerr_get_type(rr, rr_len, dname_len) 345266114Sdes != LDNS_RR_TYPE_RRSIG) { 346238106Sdes log_warn("error expected rrsig but got %s", 347266114Sdes (char*)sldns_buffer_begin(buf)); 348238106Sdes return 0; 349238106Sdes } 350238106Sdes 351238106Sdes /* convert ldns rr into packed_rr */ 352266114Sdes d->rr_ttl[i] = (time_t)sldns_wirerr_get_ttl(rr, rr_len, dname_len) + now; 353266114Sdes sldns_buffer_clear(buf); 354266114Sdes d->rr_len[i] = sldns_wirerr_get_rdatalen(rr, rr_len, dname_len)+2; 355238106Sdes d->rr_data[i] = (uint8_t*)regional_alloc_init(region, 356266114Sdes sldns_wirerr_get_rdatawl(rr, rr_len, dname_len), d->rr_len[i]); 357238106Sdes if(!d->rr_data[i]) { 358238106Sdes log_warn("error out of memory"); 359238106Sdes return 0; 360238106Sdes } 361238106Sdes 362238106Sdes /* if first entry, fill the key structure */ 363238106Sdes if(i==0) { 364266114Sdes rk->rk.type = htons(sldns_wirerr_get_type(rr, rr_len, dname_len)); 365266114Sdes rk->rk.rrset_class = htons(sldns_wirerr_get_class(rr, rr_len, dname_len)); 366266114Sdes rk->rk.dname_len = dname_len; 367266114Sdes rk->rk.dname = regional_alloc_init(region, rr, dname_len); 368238106Sdes if(!rk->rk.dname) { 369238106Sdes log_warn("error out of memory"); 370238106Sdes return 0; 371238106Sdes } 372238106Sdes } 373238106Sdes 374238106Sdes return 1; 375238106Sdes} 376238106Sdes 377238106Sdes/** move entry into cache */ 378238106Sdesstatic int 379238106Sdesmove_into_cache(struct ub_packed_rrset_key* k, 380238106Sdes struct packed_rrset_data* d, struct worker* worker) 381238106Sdes{ 382238106Sdes struct ub_packed_rrset_key* ak; 383238106Sdes struct packed_rrset_data* ad; 384238106Sdes size_t s, i, num = d->count + d->rrsig_count; 385238106Sdes struct rrset_ref ref; 386238106Sdes uint8_t* p; 387238106Sdes 388238106Sdes ak = alloc_special_obtain(&worker->alloc); 389238106Sdes if(!ak) { 390238106Sdes log_warn("error out of memory"); 391238106Sdes return 0; 392238106Sdes } 393238106Sdes ak->entry.data = NULL; 394238106Sdes ak->rk = k->rk; 395238106Sdes ak->entry.hash = rrset_key_hash(&k->rk); 396238106Sdes ak->rk.dname = (uint8_t*)memdup(k->rk.dname, k->rk.dname_len); 397238106Sdes if(!ak->rk.dname) { 398238106Sdes log_warn("error out of memory"); 399238106Sdes ub_packed_rrset_parsedelete(ak, &worker->alloc); 400238106Sdes return 0; 401238106Sdes } 402238106Sdes s = sizeof(*ad) + (sizeof(size_t) + sizeof(uint8_t*) + 403266114Sdes sizeof(time_t))* num; 404238106Sdes for(i=0; i<num; i++) 405238106Sdes s += d->rr_len[i]; 406238106Sdes ad = (struct packed_rrset_data*)malloc(s); 407238106Sdes if(!ad) { 408238106Sdes log_warn("error out of memory"); 409238106Sdes ub_packed_rrset_parsedelete(ak, &worker->alloc); 410238106Sdes return 0; 411238106Sdes } 412238106Sdes p = (uint8_t*)ad; 413238106Sdes memmove(p, d, sizeof(*ad)); 414238106Sdes p += sizeof(*ad); 415238106Sdes memmove(p, &d->rr_len[0], sizeof(size_t)*num); 416238106Sdes p += sizeof(size_t)*num; 417238106Sdes memmove(p, &d->rr_data[0], sizeof(uint8_t*)*num); 418238106Sdes p += sizeof(uint8_t*)*num; 419266114Sdes memmove(p, &d->rr_ttl[0], sizeof(time_t)*num); 420266114Sdes p += sizeof(time_t)*num; 421238106Sdes for(i=0; i<num; i++) { 422238106Sdes memmove(p, d->rr_data[i], d->rr_len[i]); 423238106Sdes p += d->rr_len[i]; 424238106Sdes } 425238106Sdes packed_rrset_ptr_fixup(ad); 426238106Sdes 427238106Sdes ak->entry.data = ad; 428238106Sdes 429238106Sdes ref.key = ak; 430238106Sdes ref.id = ak->id; 431238106Sdes (void)rrset_cache_update(worker->env.rrset_cache, &ref, 432238106Sdes &worker->alloc, *worker->env.now); 433238106Sdes return 1; 434238106Sdes} 435238106Sdes 436238106Sdes/** load an rrset entry */ 437238106Sdesstatic int 438356345Scyload_rrset(RES* ssl, sldns_buffer* buf, struct worker* worker) 439238106Sdes{ 440266114Sdes char* s = (char*)sldns_buffer_begin(buf); 441238106Sdes struct regional* region = worker->scratchpad; 442238106Sdes struct ub_packed_rrset_key* rk; 443238106Sdes struct packed_rrset_data* d; 444266114Sdes unsigned int rr_count, rrsig_count, trust, security; 445266114Sdes long long ttl; 446238106Sdes unsigned int i; 447238106Sdes int go_on = 1; 448238106Sdes regional_free_all(region); 449238106Sdes 450238106Sdes rk = (struct ub_packed_rrset_key*)regional_alloc_zero(region, 451238106Sdes sizeof(*rk)); 452238106Sdes d = (struct packed_rrset_data*)regional_alloc_zero(region, sizeof(*d)); 453238106Sdes if(!rk || !d) { 454238106Sdes log_warn("error out of memory"); 455238106Sdes return 0; 456238106Sdes } 457238106Sdes 458238106Sdes if(strncmp(s, ";rrset", 6) != 0) { 459238106Sdes log_warn("error expected ';rrset' but got %s", s); 460238106Sdes return 0; 461238106Sdes } 462238106Sdes s += 6; 463238106Sdes if(strncmp(s, " nsec_apex", 10) == 0) { 464238106Sdes s += 10; 465238106Sdes rk->rk.flags |= PACKED_RRSET_NSEC_AT_APEX; 466238106Sdes } 467266114Sdes if(sscanf(s, " " ARG_LL "d %u %u %u %u", &ttl, &rr_count, &rrsig_count, 468238106Sdes &trust, &security) != 5) { 469238106Sdes log_warn("error bad rrset spec %s", s); 470238106Sdes return 0; 471238106Sdes } 472238106Sdes if(rr_count == 0 && rrsig_count == 0) { 473238106Sdes log_warn("bad rrset without contents"); 474238106Sdes return 0; 475238106Sdes } 476287917Sdes if(rr_count > RR_COUNT_MAX || rrsig_count > RR_COUNT_MAX) { 477287917Sdes log_warn("bad rrset with too many rrs"); 478287917Sdes return 0; 479287917Sdes } 480238106Sdes d->count = (size_t)rr_count; 481238106Sdes d->rrsig_count = (size_t)rrsig_count; 482238106Sdes d->security = (enum sec_status)security; 483238106Sdes d->trust = (enum rrset_trust)trust; 484266114Sdes d->ttl = (time_t)ttl + *worker->env.now; 485238106Sdes 486238106Sdes d->rr_len = regional_alloc_zero(region, 487238106Sdes sizeof(size_t)*(d->count+d->rrsig_count)); 488238106Sdes d->rr_ttl = regional_alloc_zero(region, 489266114Sdes sizeof(time_t)*(d->count+d->rrsig_count)); 490238106Sdes d->rr_data = regional_alloc_zero(region, 491238106Sdes sizeof(uint8_t*)*(d->count+d->rrsig_count)); 492238106Sdes if(!d->rr_len || !d->rr_ttl || !d->rr_data) { 493238106Sdes log_warn("error out of memory"); 494238106Sdes return 0; 495238106Sdes } 496238106Sdes 497238106Sdes /* read the rr's themselves */ 498238106Sdes for(i=0; i<rr_count; i++) { 499238106Sdes if(!load_rr(ssl, buf, region, rk, d, i, 0, 500238106Sdes &go_on, *worker->env.now)) { 501238106Sdes log_warn("could not read rr %u", i); 502238106Sdes return 0; 503238106Sdes } 504238106Sdes } 505238106Sdes for(i=0; i<rrsig_count; i++) { 506238106Sdes if(!load_rr(ssl, buf, region, rk, d, i+rr_count, 1, 507238106Sdes &go_on, *worker->env.now)) { 508238106Sdes log_warn("could not read rrsig %u", i); 509238106Sdes return 0; 510238106Sdes } 511238106Sdes } 512238106Sdes if(!go_on) { 513238106Sdes /* skip this entry */ 514238106Sdes return 1; 515238106Sdes } 516238106Sdes 517238106Sdes return move_into_cache(rk, d, worker); 518238106Sdes} 519238106Sdes 520238106Sdes/** load rrset cache */ 521238106Sdesstatic int 522356345Scyload_rrset_cache(RES* ssl, struct worker* worker) 523238106Sdes{ 524266114Sdes sldns_buffer* buf = worker->env.scratch_buffer; 525238106Sdes if(!read_fixed(ssl, buf, "START_RRSET_CACHE")) return 0; 526238106Sdes while(ssl_read_buf(ssl, buf) && 527266114Sdes strcmp((char*)sldns_buffer_begin(buf), "END_RRSET_CACHE")!=0) { 528238106Sdes if(!load_rrset(ssl, buf, worker)) 529238106Sdes return 0; 530238106Sdes } 531238106Sdes return 1; 532238106Sdes} 533238106Sdes 534238106Sdes/** read qinfo from next three words */ 535238106Sdesstatic char* 536266114Sdesload_qinfo(char* str, struct query_info* qinfo, struct regional* region) 537238106Sdes{ 538238106Sdes /* s is part of the buf */ 539238106Sdes char* s = str; 540266114Sdes uint8_t rr[LDNS_RR_BUF_SIZE]; 541266114Sdes size_t rr_len = sizeof(rr), dname_len = 0; 542266114Sdes int status; 543238106Sdes 544238106Sdes /* skip three words */ 545238106Sdes s = strchr(str, ' '); 546238106Sdes if(s) s = strchr(s+1, ' '); 547238106Sdes if(s) s = strchr(s+1, ' '); 548238106Sdes if(!s) { 549238106Sdes log_warn("error line too short, %s", str); 550238106Sdes return NULL; 551238106Sdes } 552238106Sdes s[0] = 0; 553238106Sdes s++; 554238106Sdes 555238106Sdes /* parse them */ 556266114Sdes status = sldns_str2wire_rr_question_buf(str, rr, &rr_len, &dname_len, 557266114Sdes NULL, 0, NULL, 0); 558266114Sdes if(status != 0) { 559238106Sdes log_warn("error cannot parse: %s %s", 560266114Sdes sldns_get_errorstr_parse(status), str); 561238106Sdes return NULL; 562238106Sdes } 563266114Sdes qinfo->qtype = sldns_wirerr_get_type(rr, rr_len, dname_len); 564266114Sdes qinfo->qclass = sldns_wirerr_get_class(rr, rr_len, dname_len); 565266114Sdes qinfo->qname_len = dname_len; 566266114Sdes qinfo->qname = (uint8_t*)regional_alloc_init(region, rr, dname_len); 567356345Scy qinfo->local_alias = NULL; 568238106Sdes if(!qinfo->qname) { 569238106Sdes log_warn("error out of memory"); 570238106Sdes return NULL; 571238106Sdes } 572238106Sdes 573238106Sdes return s; 574238106Sdes} 575238106Sdes 576238106Sdes/** load a msg rrset reference */ 577238106Sdesstatic int 578356345Scyload_ref(RES* ssl, sldns_buffer* buf, struct worker* worker, 579238106Sdes struct regional *region, struct ub_packed_rrset_key** rrset, 580238106Sdes int* go_on) 581238106Sdes{ 582266114Sdes char* s = (char*)sldns_buffer_begin(buf); 583238106Sdes struct query_info qinfo; 584238106Sdes unsigned int flags; 585238106Sdes struct ub_packed_rrset_key* k; 586238106Sdes 587238106Sdes /* read line */ 588238106Sdes if(!ssl_read_buf(ssl, buf)) 589238106Sdes return 0; 590238106Sdes if(strncmp(s, "BADREF", 6) == 0) { 591238106Sdes *go_on = 0; /* its bad, skip it and skip message */ 592238106Sdes return 1; 593238106Sdes } 594238106Sdes 595266114Sdes s = load_qinfo(s, &qinfo, region); 596238106Sdes if(!s) { 597238106Sdes return 0; 598238106Sdes } 599238106Sdes if(sscanf(s, " %u", &flags) != 1) { 600238106Sdes log_warn("error cannot parse flags: %s", s); 601238106Sdes return 0; 602238106Sdes } 603238106Sdes 604238106Sdes /* lookup in cache */ 605238106Sdes k = rrset_cache_lookup(worker->env.rrset_cache, qinfo.qname, 606238106Sdes qinfo.qname_len, qinfo.qtype, qinfo.qclass, 607238106Sdes (uint32_t)flags, *worker->env.now, 0); 608238106Sdes if(!k) { 609238106Sdes /* not found or expired */ 610238106Sdes *go_on = 0; 611238106Sdes return 1; 612238106Sdes } 613238106Sdes 614238106Sdes /* store in result */ 615238106Sdes *rrset = packed_rrset_copy_region(k, region, *worker->env.now); 616238106Sdes lock_rw_unlock(&k->entry.lock); 617238106Sdes 618238106Sdes return (*rrset != NULL); 619238106Sdes} 620238106Sdes 621238106Sdes/** load a msg entry */ 622238106Sdesstatic int 623356345Scyload_msg(RES* ssl, sldns_buffer* buf, struct worker* worker) 624238106Sdes{ 625238106Sdes struct regional* region = worker->scratchpad; 626238106Sdes struct query_info qinf; 627238106Sdes struct reply_info rep; 628266114Sdes char* s = (char*)sldns_buffer_begin(buf); 629266114Sdes unsigned int flags, qdcount, security, an, ns, ar; 630266114Sdes long long ttl; 631238106Sdes size_t i; 632238106Sdes int go_on = 1; 633238106Sdes 634238106Sdes regional_free_all(region); 635238106Sdes 636238106Sdes if(strncmp(s, "msg ", 4) != 0) { 637238106Sdes log_warn("error expected msg but got %s", s); 638238106Sdes return 0; 639238106Sdes } 640238106Sdes s += 4; 641266114Sdes s = load_qinfo(s, &qinf, region); 642238106Sdes if(!s) { 643238106Sdes return 0; 644238106Sdes } 645238106Sdes 646238106Sdes /* read remainder of line */ 647266114Sdes if(sscanf(s, " %u %u " ARG_LL "d %u %u %u %u", &flags, &qdcount, &ttl, 648238106Sdes &security, &an, &ns, &ar) != 7) { 649238106Sdes log_warn("error cannot parse numbers: %s", s); 650238106Sdes return 0; 651238106Sdes } 652238106Sdes rep.flags = (uint16_t)flags; 653238106Sdes rep.qdcount = (uint16_t)qdcount; 654266114Sdes rep.ttl = (time_t)ttl; 655238106Sdes rep.prefetch_ttl = PREFETCH_TTL_CALC(rep.ttl); 656356345Scy rep.serve_expired_ttl = rep.ttl + SERVE_EXPIRED_TTL; 657238106Sdes rep.security = (enum sec_status)security; 658287917Sdes if(an > RR_COUNT_MAX || ns > RR_COUNT_MAX || ar > RR_COUNT_MAX) { 659287917Sdes log_warn("error too many rrsets"); 660287917Sdes return 0; /* protect against integer overflow in alloc */ 661287917Sdes } 662238106Sdes rep.an_numrrsets = (size_t)an; 663238106Sdes rep.ns_numrrsets = (size_t)ns; 664238106Sdes rep.ar_numrrsets = (size_t)ar; 665238106Sdes rep.rrset_count = (size_t)an+(size_t)ns+(size_t)ar; 666238106Sdes rep.rrsets = (struct ub_packed_rrset_key**)regional_alloc_zero( 667238106Sdes region, sizeof(struct ub_packed_rrset_key*)*rep.rrset_count); 668238106Sdes 669238106Sdes /* fill repinfo with references */ 670238106Sdes for(i=0; i<rep.rrset_count; i++) { 671238106Sdes if(!load_ref(ssl, buf, worker, region, &rep.rrsets[i], 672238106Sdes &go_on)) { 673238106Sdes return 0; 674238106Sdes } 675238106Sdes } 676238106Sdes 677238106Sdes if(!go_on) 678238106Sdes return 1; /* skip this one, not all references satisfied */ 679238106Sdes 680276605Sdes if(!dns_cache_store(&worker->env, &qinf, &rep, 0, 0, 0, NULL, flags)) { 681238106Sdes log_warn("error out of memory"); 682238106Sdes return 0; 683238106Sdes } 684238106Sdes return 1; 685238106Sdes} 686238106Sdes 687238106Sdes/** load msg cache */ 688238106Sdesstatic int 689356345Scyload_msg_cache(RES* ssl, struct worker* worker) 690238106Sdes{ 691266114Sdes sldns_buffer* buf = worker->env.scratch_buffer; 692238106Sdes if(!read_fixed(ssl, buf, "START_MSG_CACHE")) return 0; 693238106Sdes while(ssl_read_buf(ssl, buf) && 694266114Sdes strcmp((char*)sldns_buffer_begin(buf), "END_MSG_CACHE")!=0) { 695238106Sdes if(!load_msg(ssl, buf, worker)) 696238106Sdes return 0; 697238106Sdes } 698238106Sdes return 1; 699238106Sdes} 700238106Sdes 701238106Sdesint 702356345Scyload_cache(RES* ssl, struct worker* worker) 703238106Sdes{ 704238106Sdes if(!load_rrset_cache(ssl, worker)) 705238106Sdes return 0; 706238106Sdes if(!load_msg_cache(ssl, worker)) 707238106Sdes return 0; 708238106Sdes return read_fixed(ssl, worker->env.scratch_buffer, "EOF"); 709238106Sdes} 710238106Sdes 711238106Sdes/** print details on a delegation point */ 712238106Sdesstatic void 713356345Scyprint_dp_details(RES* ssl, struct worker* worker, struct delegpt* dp) 714238106Sdes{ 715238106Sdes char buf[257]; 716238106Sdes struct delegpt_addr* a; 717266114Sdes int lame, dlame, rlame, rto, edns_vs, to, delay, 718238106Sdes tA = 0, tAAAA = 0, tother = 0; 719266114Sdes long long entry_ttl; 720238106Sdes struct rtt_info ri; 721238106Sdes uint8_t edns_lame_known; 722238106Sdes for(a = dp->target_list; a; a = a->next_target) { 723238106Sdes addr_to_str(&a->addr, a->addrlen, buf, sizeof(buf)); 724238106Sdes if(!ssl_printf(ssl, "%-16s\t", buf)) 725238106Sdes return; 726238106Sdes if(a->bogus) { 727238106Sdes if(!ssl_printf(ssl, "Address is BOGUS. ")) 728238106Sdes return; 729238106Sdes } 730238106Sdes /* lookup in infra cache */ 731238106Sdes delay=0; 732238106Sdes entry_ttl = infra_get_host_rto(worker->env.infra_cache, 733238106Sdes &a->addr, a->addrlen, dp->name, dp->namelen, 734238106Sdes &ri, &delay, *worker->env.now, &tA, &tAAAA, &tother); 735238106Sdes if(entry_ttl == -2 && ri.rto >= USEFUL_SERVER_TOP_TIMEOUT) { 736238106Sdes if(!ssl_printf(ssl, "expired, rto %d msec, tA %d " 737238106Sdes "tAAAA %d tother %d.\n", ri.rto, tA, tAAAA, 738238106Sdes tother)) 739238106Sdes return; 740238106Sdes continue; 741238106Sdes } 742238106Sdes if(entry_ttl == -1 || entry_ttl == -2) { 743238106Sdes if(!ssl_printf(ssl, "not in infra cache.\n")) 744238106Sdes return; 745238106Sdes continue; /* skip stuff not in infra cache */ 746238106Sdes } 747238106Sdes 748238106Sdes /* uses type_A because most often looked up, but other 749238106Sdes * lameness won't be reported then */ 750238106Sdes if(!infra_get_lame_rtt(worker->env.infra_cache, 751238106Sdes &a->addr, a->addrlen, dp->name, dp->namelen, 752238106Sdes LDNS_RR_TYPE_A, &lame, &dlame, &rlame, &rto, 753238106Sdes *worker->env.now)) { 754238106Sdes if(!ssl_printf(ssl, "not in infra cache.\n")) 755238106Sdes return; 756238106Sdes continue; /* skip stuff not in infra cache */ 757238106Sdes } 758266114Sdes if(!ssl_printf(ssl, "%s%s%s%srto %d msec, ttl " ARG_LL "d, " 759266114Sdes "ping %d var %d rtt %d, tA %d, tAAAA %d, tother %d", 760238106Sdes lame?"LAME ":"", dlame?"NoDNSSEC ":"", 761238106Sdes a->lame?"AddrWasParentSide ":"", 762238106Sdes rlame?"NoAuthButRecursive ":"", rto, entry_ttl, 763238106Sdes ri.srtt, ri.rttvar, rtt_notimeout(&ri), 764238106Sdes tA, tAAAA, tother)) 765238106Sdes return; 766238106Sdes if(delay) 767238106Sdes if(!ssl_printf(ssl, ", probedelay %d", delay)) 768238106Sdes return; 769238106Sdes if(infra_host(worker->env.infra_cache, &a->addr, a->addrlen, 770238106Sdes dp->name, dp->namelen, *worker->env.now, &edns_vs, 771238106Sdes &edns_lame_known, &to)) { 772238106Sdes if(edns_vs == -1) { 773238106Sdes if(!ssl_printf(ssl, ", noEDNS%s.", 774238106Sdes edns_lame_known?" probed":" assumed")) 775238106Sdes return; 776238106Sdes } else { 777238106Sdes if(!ssl_printf(ssl, ", EDNS %d%s.", edns_vs, 778238106Sdes edns_lame_known?" probed":" assumed")) 779238106Sdes return; 780238106Sdes } 781238106Sdes } 782238106Sdes if(!ssl_printf(ssl, "\n")) 783238106Sdes return; 784238106Sdes } 785238106Sdes} 786238106Sdes 787238106Sdes/** print main dp info */ 788238106Sdesstatic void 789356345Scyprint_dp_main(RES* ssl, struct delegpt* dp, struct dns_msg* msg) 790238106Sdes{ 791238106Sdes size_t i, n_ns, n_miss, n_addr, n_res, n_avail; 792238106Sdes 793238106Sdes /* print the dp */ 794238106Sdes if(msg) 795238106Sdes for(i=0; i<msg->rep->rrset_count; i++) { 796238106Sdes struct ub_packed_rrset_key* k = msg->rep->rrsets[i]; 797238106Sdes struct packed_rrset_data* d = 798238106Sdes (struct packed_rrset_data*)k->entry.data; 799238106Sdes if(d->security == sec_status_bogus) { 800238106Sdes if(!ssl_printf(ssl, "Address is BOGUS:\n")) 801238106Sdes return; 802238106Sdes } 803238106Sdes if(!dump_rrset(ssl, k, d, 0)) 804238106Sdes return; 805238106Sdes } 806238106Sdes delegpt_count_ns(dp, &n_ns, &n_miss); 807238106Sdes delegpt_count_addr(dp, &n_addr, &n_res, &n_avail); 808238106Sdes /* since dp has not been used by iterator, all are available*/ 809238106Sdes if(!ssl_printf(ssl, "Delegation with %d names, of which %d " 810238106Sdes "can be examined to query further addresses.\n" 811238106Sdes "%sIt provides %d IP addresses.\n", 812238106Sdes (int)n_ns, (int)n_miss, (dp->bogus?"It is BOGUS. ":""), 813238106Sdes (int)n_addr)) 814238106Sdes return; 815238106Sdes} 816238106Sdes 817356345Scyint print_deleg_lookup(RES* ssl, struct worker* worker, uint8_t* nm, 818238106Sdes size_t nmlen, int ATTR_UNUSED(nmlabs)) 819238106Sdes{ 820238106Sdes /* deep links into the iterator module */ 821238106Sdes struct delegpt* dp; 822238106Sdes struct dns_msg* msg; 823238106Sdes struct regional* region = worker->scratchpad; 824238106Sdes char b[260]; 825238106Sdes struct query_info qinfo; 826238106Sdes struct iter_hints_stub* stub; 827238106Sdes regional_free_all(region); 828238106Sdes qinfo.qname = nm; 829238106Sdes qinfo.qname_len = nmlen; 830238106Sdes qinfo.qtype = LDNS_RR_TYPE_A; 831238106Sdes qinfo.qclass = LDNS_RR_CLASS_IN; 832356345Scy qinfo.local_alias = NULL; 833238106Sdes 834238106Sdes dname_str(nm, b); 835238106Sdes if(!ssl_printf(ssl, "The following name servers are used for lookup " 836238106Sdes "of %s\n", b)) 837238106Sdes return 0; 838238106Sdes 839238106Sdes dp = forwards_lookup(worker->env.fwds, nm, qinfo.qclass); 840238106Sdes if(dp) { 841238106Sdes if(!ssl_printf(ssl, "forwarding request:\n")) 842238106Sdes return 0; 843238106Sdes print_dp_main(ssl, dp, NULL); 844238106Sdes print_dp_details(ssl, worker, dp); 845238106Sdes return 1; 846238106Sdes } 847238106Sdes 848238106Sdes while(1) { 849238106Sdes dp = dns_cache_find_delegation(&worker->env, nm, nmlen, 850238106Sdes qinfo.qtype, qinfo.qclass, region, &msg, 851238106Sdes *worker->env.now); 852238106Sdes if(!dp) { 853238106Sdes return ssl_printf(ssl, "no delegation from " 854238106Sdes "cache; goes to configured roots\n"); 855238106Sdes } 856238106Sdes /* go up? */ 857238106Sdes if(iter_dp_is_useless(&qinfo, BIT_RD, dp)) { 858238106Sdes print_dp_main(ssl, dp, msg); 859238106Sdes print_dp_details(ssl, worker, dp); 860238106Sdes if(!ssl_printf(ssl, "cache delegation was " 861238106Sdes "useless (no IP addresses)\n")) 862238106Sdes return 0; 863238106Sdes if(dname_is_root(nm)) { 864238106Sdes /* goes to root config */ 865238106Sdes return ssl_printf(ssl, "no delegation from " 866238106Sdes "cache; goes to configured roots\n"); 867238106Sdes } else { 868238106Sdes /* useless, goes up */ 869238106Sdes nm = dp->name; 870238106Sdes nmlen = dp->namelen; 871238106Sdes dname_remove_label(&nm, &nmlen); 872238106Sdes dname_str(nm, b); 873238106Sdes if(!ssl_printf(ssl, "going up, lookup %s\n", b)) 874238106Sdes return 0; 875238106Sdes continue; 876238106Sdes } 877238106Sdes } 878238106Sdes stub = hints_lookup_stub(worker->env.hints, nm, qinfo.qclass, 879238106Sdes dp); 880238106Sdes if(stub) { 881238106Sdes if(stub->noprime) { 882238106Sdes if(!ssl_printf(ssl, "The noprime stub servers " 883238106Sdes "are used:\n")) 884238106Sdes return 0; 885238106Sdes } else { 886238106Sdes if(!ssl_printf(ssl, "The stub is primed " 887238106Sdes "with servers:\n")) 888238106Sdes return 0; 889238106Sdes } 890238106Sdes print_dp_main(ssl, stub->dp, NULL); 891238106Sdes print_dp_details(ssl, worker, stub->dp); 892238106Sdes } else { 893238106Sdes print_dp_main(ssl, dp, msg); 894238106Sdes print_dp_details(ssl, worker, dp); 895238106Sdes } 896238106Sdes break; 897238106Sdes } 898238106Sdes 899238106Sdes return 1; 900238106Sdes} 901