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 24238106Sdes * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 25238106Sdes * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 26238106Sdes * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE 27238106Sdes * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 28238106Sdes * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 29238106Sdes * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 30238106Sdes * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 31238106Sdes * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 32238106Sdes * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 33238106Sdes * 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" 43238106Sdes#include <ldns/ldns.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" 59238106Sdes 60238106Sdes/** convert to ldns rr */ 61238106Sdesstatic ldns_rr* 62238106Sdesto_rr(struct ub_packed_rrset_key* k, struct packed_rrset_data* d, 63238106Sdes uint32_t now, size_t i, uint16_t type) 64238106Sdes{ 65238106Sdes ldns_rr* rr = ldns_rr_new(); 66238106Sdes ldns_rdf* rdf; 67238106Sdes ldns_status status; 68238106Sdes size_t pos; 69238106Sdes log_assert(i < d->count + d->rrsig_count); 70238106Sdes if(!rr) { 71238106Sdes return NULL; 72238106Sdes } 73238106Sdes ldns_rr_set_type(rr, type); 74238106Sdes ldns_rr_set_class(rr, ntohs(k->rk.rrset_class)); 75238106Sdes if(d->rr_ttl[i] < now) 76238106Sdes ldns_rr_set_ttl(rr, 0); 77238106Sdes else ldns_rr_set_ttl(rr, d->rr_ttl[i] - now); 78238106Sdes pos = 0; 79238106Sdes status = ldns_wire2dname(&rdf, k->rk.dname, k->rk.dname_len, &pos); 80238106Sdes if(status != LDNS_STATUS_OK) { 81238106Sdes /* we drop detailed error in status */ 82238106Sdes ldns_rr_free(rr); 83238106Sdes return NULL; 84238106Sdes } 85238106Sdes ldns_rr_set_owner(rr, rdf); 86238106Sdes pos = 0; 87238106Sdes status = ldns_wire2rdf(rr, d->rr_data[i], d->rr_len[i], &pos); 88238106Sdes if(status != LDNS_STATUS_OK) { 89238106Sdes /* we drop detailed error in status */ 90238106Sdes ldns_rr_free(rr); 91238106Sdes return NULL; 92238106Sdes } 93238106Sdes return rr; 94238106Sdes} 95238106Sdes 96238106Sdes/** dump one rrset zonefile line */ 97238106Sdesstatic int 98238106Sdesdump_rrset_line(SSL* ssl, struct ub_packed_rrset_key* k, 99238106Sdes struct packed_rrset_data* d, uint32_t now, size_t i, uint16_t type) 100238106Sdes{ 101238106Sdes char* s; 102238106Sdes ldns_rr* rr = to_rr(k, d, now, i, type); 103238106Sdes if(!rr) { 104238106Sdes return ssl_printf(ssl, "BADRR\n"); 105238106Sdes } 106238106Sdes s = ldns_rr2str(rr); 107238106Sdes ldns_rr_free(rr); 108238106Sdes if(!s) { 109238106Sdes return ssl_printf(ssl, "BADRR\n"); 110238106Sdes } 111238106Sdes if(!ssl_printf(ssl, "%s", s)) { 112238106Sdes free(s); 113238106Sdes return 0; 114238106Sdes } 115238106Sdes free(s); 116238106Sdes return 1; 117238106Sdes} 118238106Sdes 119238106Sdes/** dump rrset key and data info */ 120238106Sdesstatic int 121238106Sdesdump_rrset(SSL* ssl, struct ub_packed_rrset_key* k, 122238106Sdes struct packed_rrset_data* d, uint32_t now) 123238106Sdes{ 124238106Sdes size_t i; 125238106Sdes /* rd lock held by caller */ 126238106Sdes if(!k || !d) return 1; 127238106Sdes if(d->ttl < now) return 1; /* expired */ 128238106Sdes 129238106Sdes /* meta line */ 130238106Sdes if(!ssl_printf(ssl, ";rrset%s %u %u %u %d %d\n", 131238106Sdes (k->rk.flags & PACKED_RRSET_NSEC_AT_APEX)?" nsec_apex":"", 132238106Sdes (unsigned)(d->ttl - now), 133238106Sdes (unsigned)d->count, (unsigned)d->rrsig_count, 134238106Sdes (int)d->trust, (int)d->security 135238106Sdes )) 136238106Sdes return 0; 137238106Sdes for(i=0; i<d->count; i++) { 138238106Sdes if(!dump_rrset_line(ssl, k, d, now, i, ntohs(k->rk.type))) 139238106Sdes return 0; 140238106Sdes } 141238106Sdes for(i=0; i<d->rrsig_count; i++) { 142238106Sdes if(!dump_rrset_line(ssl, k, d, now, i+d->count, 143238106Sdes LDNS_RR_TYPE_RRSIG)) 144238106Sdes return 0; 145238106Sdes } 146238106Sdes 147238106Sdes return 1; 148238106Sdes} 149238106Sdes 150238106Sdes/** dump lruhash rrset cache */ 151238106Sdesstatic int 152238106Sdesdump_rrset_lruhash(SSL* ssl, struct lruhash* h, uint32_t now) 153238106Sdes{ 154238106Sdes struct lruhash_entry* e; 155238106Sdes /* lruhash already locked by caller */ 156238106Sdes /* walk in order of lru; best first */ 157238106Sdes for(e=h->lru_start; e; e = e->lru_next) { 158238106Sdes lock_rw_rdlock(&e->lock); 159238106Sdes if(!dump_rrset(ssl, (struct ub_packed_rrset_key*)e->key, 160238106Sdes (struct packed_rrset_data*)e->data, now)) { 161238106Sdes lock_rw_unlock(&e->lock); 162238106Sdes return 0; 163238106Sdes } 164238106Sdes lock_rw_unlock(&e->lock); 165238106Sdes } 166238106Sdes return 1; 167238106Sdes} 168238106Sdes 169238106Sdes/** dump rrset cache */ 170238106Sdesstatic int 171238106Sdesdump_rrset_cache(SSL* ssl, struct worker* worker) 172238106Sdes{ 173238106Sdes struct rrset_cache* r = worker->env.rrset_cache; 174238106Sdes size_t slab; 175238106Sdes if(!ssl_printf(ssl, "START_RRSET_CACHE\n")) return 0; 176238106Sdes for(slab=0; slab<r->table.size; slab++) { 177238106Sdes lock_quick_lock(&r->table.array[slab]->lock); 178238106Sdes if(!dump_rrset_lruhash(ssl, r->table.array[slab], 179238106Sdes *worker->env.now)) { 180238106Sdes lock_quick_unlock(&r->table.array[slab]->lock); 181238106Sdes return 0; 182238106Sdes } 183238106Sdes lock_quick_unlock(&r->table.array[slab]->lock); 184238106Sdes } 185238106Sdes return ssl_printf(ssl, "END_RRSET_CACHE\n"); 186238106Sdes} 187238106Sdes 188238106Sdes/** dump message to rrset reference */ 189238106Sdesstatic int 190238106Sdesdump_msg_ref(SSL* ssl, struct ub_packed_rrset_key* k) 191238106Sdes{ 192238106Sdes ldns_rdf* rdf; 193238106Sdes ldns_status status; 194238106Sdes size_t pos; 195238106Sdes char* nm, *tp, *cl; 196238106Sdes 197238106Sdes pos = 0; 198238106Sdes status = ldns_wire2dname(&rdf, k->rk.dname, k->rk.dname_len, &pos); 199238106Sdes if(status != LDNS_STATUS_OK) { 200238106Sdes return ssl_printf(ssl, "BADREF\n"); 201238106Sdes } 202238106Sdes nm = ldns_rdf2str(rdf); 203238106Sdes ldns_rdf_deep_free(rdf); 204238106Sdes tp = ldns_rr_type2str(ntohs(k->rk.type)); 205238106Sdes cl = ldns_rr_class2str(ntohs(k->rk.rrset_class)); 206238106Sdes if(!nm || !cl || !tp) { 207238106Sdes free(nm); 208238106Sdes free(tp); 209238106Sdes free(cl); 210238106Sdes return ssl_printf(ssl, "BADREF\n"); 211238106Sdes } 212238106Sdes if(!ssl_printf(ssl, "%s %s %s %d\n", nm, cl, tp, (int)k->rk.flags)) { 213238106Sdes free(nm); 214238106Sdes free(tp); 215238106Sdes free(cl); 216238106Sdes return 0; 217238106Sdes } 218238106Sdes free(nm); 219238106Sdes free(tp); 220238106Sdes free(cl); 221238106Sdes 222238106Sdes return 1; 223238106Sdes} 224238106Sdes 225238106Sdes/** dump message entry */ 226238106Sdesstatic int 227238106Sdesdump_msg(SSL* ssl, struct query_info* k, struct reply_info* d, 228238106Sdes uint32_t now) 229238106Sdes{ 230238106Sdes size_t i; 231238106Sdes char* nm, *tp, *cl; 232238106Sdes ldns_rdf* rdf; 233238106Sdes ldns_status status; 234238106Sdes size_t pos; 235238106Sdes if(!k || !d) return 1; 236238106Sdes if(d->ttl < now) return 1; /* expired */ 237238106Sdes 238238106Sdes pos = 0; 239238106Sdes status = ldns_wire2dname(&rdf, k->qname, k->qname_len, &pos); 240238106Sdes if(status != LDNS_STATUS_OK) { 241238106Sdes return 1; /* skip this entry */ 242238106Sdes } 243238106Sdes nm = ldns_rdf2str(rdf); 244238106Sdes ldns_rdf_deep_free(rdf); 245238106Sdes tp = ldns_rr_type2str(k->qtype); 246238106Sdes cl = ldns_rr_class2str(k->qclass); 247238106Sdes if(!nm || !tp || !cl) { 248238106Sdes free(nm); 249238106Sdes free(tp); 250238106Sdes free(cl); 251238106Sdes return 1; /* skip this entry */ 252238106Sdes } 253238106Sdes if(!rrset_array_lock(d->ref, d->rrset_count, now)) { 254238106Sdes /* rrsets have timed out or do not exist */ 255238106Sdes free(nm); 256238106Sdes free(tp); 257238106Sdes free(cl); 258238106Sdes return 1; /* skip this entry */ 259238106Sdes } 260238106Sdes 261238106Sdes /* meta line */ 262238106Sdes if(!ssl_printf(ssl, "msg %s %s %s %d %d %u %d %u %u %u\n", 263238106Sdes nm, cl, tp, 264238106Sdes (int)d->flags, (int)d->qdcount, 265238106Sdes (unsigned)(d->ttl-now), (int)d->security, 266238106Sdes (unsigned)d->an_numrrsets, 267238106Sdes (unsigned)d->ns_numrrsets, 268238106Sdes (unsigned)d->ar_numrrsets)) { 269238106Sdes free(nm); 270238106Sdes free(tp); 271238106Sdes free(cl); 272238106Sdes rrset_array_unlock(d->ref, d->rrset_count); 273238106Sdes return 0; 274238106Sdes } 275238106Sdes free(nm); 276238106Sdes free(tp); 277238106Sdes free(cl); 278238106Sdes 279238106Sdes for(i=0; i<d->rrset_count; i++) { 280238106Sdes if(!dump_msg_ref(ssl, d->rrsets[i])) { 281238106Sdes rrset_array_unlock(d->ref, d->rrset_count); 282238106Sdes return 0; 283238106Sdes } 284238106Sdes } 285238106Sdes rrset_array_unlock(d->ref, d->rrset_count); 286238106Sdes 287238106Sdes return 1; 288238106Sdes} 289238106Sdes 290238106Sdes/** copy msg to worker pad */ 291238106Sdesstatic int 292238106Sdescopy_msg(struct regional* region, struct lruhash_entry* e, 293238106Sdes struct query_info** k, struct reply_info** d) 294238106Sdes{ 295238106Sdes struct reply_info* rep = (struct reply_info*)e->data; 296238106Sdes *d = (struct reply_info*)regional_alloc_init(region, e->data, 297238106Sdes sizeof(struct reply_info) + 298238106Sdes sizeof(struct rrset_ref) * (rep->rrset_count-1) + 299238106Sdes sizeof(struct ub_packed_rrset_key*) * rep->rrset_count); 300238106Sdes if(!*d) 301238106Sdes return 0; 302255579Sdes (*d)->rrsets = (struct ub_packed_rrset_key**)(void *)( 303238106Sdes (uint8_t*)(&((*d)->ref[0])) + 304238106Sdes sizeof(struct rrset_ref) * rep->rrset_count); 305238106Sdes *k = (struct query_info*)regional_alloc_init(region, 306238106Sdes e->key, sizeof(struct query_info)); 307238106Sdes if(!*k) 308238106Sdes return 0; 309238106Sdes (*k)->qname = regional_alloc_init(region, 310238106Sdes (*k)->qname, (*k)->qname_len); 311238106Sdes return (*k)->qname != NULL; 312238106Sdes} 313238106Sdes 314238106Sdes/** dump lruhash msg cache */ 315238106Sdesstatic int 316238106Sdesdump_msg_lruhash(SSL* ssl, struct worker* worker, struct lruhash* h) 317238106Sdes{ 318238106Sdes struct lruhash_entry* e; 319238106Sdes struct query_info* k; 320238106Sdes struct reply_info* d; 321238106Sdes 322238106Sdes /* lruhash already locked by caller */ 323238106Sdes /* walk in order of lru; best first */ 324238106Sdes for(e=h->lru_start; e; e = e->lru_next) { 325238106Sdes regional_free_all(worker->scratchpad); 326238106Sdes lock_rw_rdlock(&e->lock); 327238106Sdes /* make copy of rrset in worker buffer */ 328238106Sdes if(!copy_msg(worker->scratchpad, e, &k, &d)) { 329238106Sdes lock_rw_unlock(&e->lock); 330238106Sdes return 0; 331238106Sdes } 332238106Sdes lock_rw_unlock(&e->lock); 333238106Sdes /* release lock so we can lookup the rrset references 334238106Sdes * in the rrset cache */ 335238106Sdes if(!dump_msg(ssl, k, d, *worker->env.now)) { 336238106Sdes return 0; 337238106Sdes } 338238106Sdes } 339238106Sdes return 1; 340238106Sdes} 341238106Sdes 342238106Sdes/** dump msg cache */ 343238106Sdesstatic int 344238106Sdesdump_msg_cache(SSL* ssl, struct worker* worker) 345238106Sdes{ 346238106Sdes struct slabhash* sh = worker->env.msg_cache; 347238106Sdes size_t slab; 348238106Sdes if(!ssl_printf(ssl, "START_MSG_CACHE\n")) return 0; 349238106Sdes for(slab=0; slab<sh->size; slab++) { 350238106Sdes lock_quick_lock(&sh->array[slab]->lock); 351238106Sdes if(!dump_msg_lruhash(ssl, worker, sh->array[slab])) { 352238106Sdes lock_quick_unlock(&sh->array[slab]->lock); 353238106Sdes return 0; 354238106Sdes } 355238106Sdes lock_quick_unlock(&sh->array[slab]->lock); 356238106Sdes } 357238106Sdes return ssl_printf(ssl, "END_MSG_CACHE\n"); 358238106Sdes} 359238106Sdes 360238106Sdesint 361238106Sdesdump_cache(SSL* ssl, struct worker* worker) 362238106Sdes{ 363238106Sdes if(!dump_rrset_cache(ssl, worker)) 364238106Sdes return 0; 365238106Sdes if(!dump_msg_cache(ssl, worker)) 366238106Sdes return 0; 367238106Sdes return ssl_printf(ssl, "EOF\n"); 368238106Sdes} 369238106Sdes 370238106Sdes/** read a line from ssl into buffer */ 371238106Sdesstatic int 372238106Sdesssl_read_buf(SSL* ssl, ldns_buffer* buf) 373238106Sdes{ 374238106Sdes return ssl_read_line(ssl, (char*)ldns_buffer_begin(buf), 375238106Sdes ldns_buffer_capacity(buf)); 376238106Sdes} 377238106Sdes 378238106Sdes/** check fixed text on line */ 379238106Sdesstatic int 380238106Sdesread_fixed(SSL* ssl, ldns_buffer* buf, const char* str) 381238106Sdes{ 382238106Sdes if(!ssl_read_buf(ssl, buf)) return 0; 383238106Sdes return (strcmp((char*)ldns_buffer_begin(buf), str) == 0); 384238106Sdes} 385238106Sdes 386238106Sdes/** load an RR into rrset */ 387238106Sdesstatic int 388238106Sdesload_rr(SSL* ssl, ldns_buffer* buf, struct regional* region, 389238106Sdes struct ub_packed_rrset_key* rk, struct packed_rrset_data* d, 390238106Sdes unsigned int i, int is_rrsig, int* go_on, uint32_t now) 391238106Sdes{ 392238106Sdes ldns_rr* rr; 393238106Sdes ldns_status status; 394238106Sdes 395238106Sdes /* read the line */ 396238106Sdes if(!ssl_read_buf(ssl, buf)) 397238106Sdes return 0; 398238106Sdes if(strncmp((char*)ldns_buffer_begin(buf), "BADRR\n", 6) == 0) { 399238106Sdes *go_on = 0; 400238106Sdes return 1; 401238106Sdes } 402238106Sdes status = ldns_rr_new_frm_str(&rr, (char*)ldns_buffer_begin(buf), 403238106Sdes LDNS_DEFAULT_TTL, NULL, NULL); 404238106Sdes if(status != LDNS_STATUS_OK) { 405238106Sdes log_warn("error cannot parse rr: %s: %s", 406238106Sdes ldns_get_errorstr_by_id(status), 407238106Sdes (char*)ldns_buffer_begin(buf)); 408238106Sdes return 0; 409238106Sdes } 410238106Sdes if(is_rrsig && ldns_rr_get_type(rr) != LDNS_RR_TYPE_RRSIG) { 411238106Sdes log_warn("error expected rrsig but got %s", 412238106Sdes (char*)ldns_buffer_begin(buf)); 413238106Sdes return 0; 414238106Sdes } 415238106Sdes 416238106Sdes /* convert ldns rr into packed_rr */ 417238106Sdes d->rr_ttl[i] = ldns_rr_ttl(rr) + now; 418238106Sdes ldns_buffer_clear(buf); 419238106Sdes ldns_buffer_skip(buf, 2); 420238106Sdes status = ldns_rr_rdata2buffer_wire(buf, rr); 421238106Sdes if(status != LDNS_STATUS_OK) { 422238106Sdes log_warn("error cannot rr2wire: %s", 423238106Sdes ldns_get_errorstr_by_id(status)); 424238106Sdes ldns_rr_free(rr); 425238106Sdes return 0; 426238106Sdes } 427238106Sdes ldns_buffer_flip(buf); 428238106Sdes ldns_buffer_write_u16_at(buf, 0, ldns_buffer_limit(buf) - 2); 429238106Sdes 430238106Sdes d->rr_len[i] = ldns_buffer_limit(buf); 431238106Sdes d->rr_data[i] = (uint8_t*)regional_alloc_init(region, 432238106Sdes ldns_buffer_begin(buf), ldns_buffer_limit(buf)); 433238106Sdes if(!d->rr_data[i]) { 434238106Sdes ldns_rr_free(rr); 435238106Sdes log_warn("error out of memory"); 436238106Sdes return 0; 437238106Sdes } 438238106Sdes 439238106Sdes /* if first entry, fill the key structure */ 440238106Sdes if(i==0) { 441238106Sdes rk->rk.type = htons(ldns_rr_get_type(rr)); 442238106Sdes rk->rk.rrset_class = htons(ldns_rr_get_class(rr)); 443238106Sdes ldns_buffer_clear(buf); 444238106Sdes status = ldns_dname2buffer_wire(buf, ldns_rr_owner(rr)); 445238106Sdes if(status != LDNS_STATUS_OK) { 446238106Sdes log_warn("error cannot dname2buffer: %s", 447238106Sdes ldns_get_errorstr_by_id(status)); 448238106Sdes ldns_rr_free(rr); 449238106Sdes return 0; 450238106Sdes } 451238106Sdes ldns_buffer_flip(buf); 452238106Sdes rk->rk.dname_len = ldns_buffer_limit(buf); 453238106Sdes rk->rk.dname = regional_alloc_init(region, 454238106Sdes ldns_buffer_begin(buf), ldns_buffer_limit(buf)); 455238106Sdes if(!rk->rk.dname) { 456238106Sdes log_warn("error out of memory"); 457238106Sdes ldns_rr_free(rr); 458238106Sdes return 0; 459238106Sdes } 460238106Sdes } 461238106Sdes ldns_rr_free(rr); 462238106Sdes 463238106Sdes return 1; 464238106Sdes} 465238106Sdes 466238106Sdes/** move entry into cache */ 467238106Sdesstatic int 468238106Sdesmove_into_cache(struct ub_packed_rrset_key* k, 469238106Sdes struct packed_rrset_data* d, struct worker* worker) 470238106Sdes{ 471238106Sdes struct ub_packed_rrset_key* ak; 472238106Sdes struct packed_rrset_data* ad; 473238106Sdes size_t s, i, num = d->count + d->rrsig_count; 474238106Sdes struct rrset_ref ref; 475238106Sdes uint8_t* p; 476238106Sdes 477238106Sdes ak = alloc_special_obtain(&worker->alloc); 478238106Sdes if(!ak) { 479238106Sdes log_warn("error out of memory"); 480238106Sdes return 0; 481238106Sdes } 482238106Sdes ak->entry.data = NULL; 483238106Sdes ak->rk = k->rk; 484238106Sdes ak->entry.hash = rrset_key_hash(&k->rk); 485238106Sdes ak->rk.dname = (uint8_t*)memdup(k->rk.dname, k->rk.dname_len); 486238106Sdes if(!ak->rk.dname) { 487238106Sdes log_warn("error out of memory"); 488238106Sdes ub_packed_rrset_parsedelete(ak, &worker->alloc); 489238106Sdes return 0; 490238106Sdes } 491238106Sdes s = sizeof(*ad) + (sizeof(size_t) + sizeof(uint8_t*) + 492238106Sdes sizeof(uint32_t))* num; 493238106Sdes for(i=0; i<num; i++) 494238106Sdes s += d->rr_len[i]; 495238106Sdes ad = (struct packed_rrset_data*)malloc(s); 496238106Sdes if(!ad) { 497238106Sdes log_warn("error out of memory"); 498238106Sdes ub_packed_rrset_parsedelete(ak, &worker->alloc); 499238106Sdes return 0; 500238106Sdes } 501238106Sdes p = (uint8_t*)ad; 502238106Sdes memmove(p, d, sizeof(*ad)); 503238106Sdes p += sizeof(*ad); 504238106Sdes memmove(p, &d->rr_len[0], sizeof(size_t)*num); 505238106Sdes p += sizeof(size_t)*num; 506238106Sdes memmove(p, &d->rr_data[0], sizeof(uint8_t*)*num); 507238106Sdes p += sizeof(uint8_t*)*num; 508238106Sdes memmove(p, &d->rr_ttl[0], sizeof(uint32_t)*num); 509238106Sdes p += sizeof(uint32_t)*num; 510238106Sdes for(i=0; i<num; i++) { 511238106Sdes memmove(p, d->rr_data[i], d->rr_len[i]); 512238106Sdes p += d->rr_len[i]; 513238106Sdes } 514238106Sdes packed_rrset_ptr_fixup(ad); 515238106Sdes 516238106Sdes ak->entry.data = ad; 517238106Sdes 518238106Sdes ref.key = ak; 519238106Sdes ref.id = ak->id; 520238106Sdes (void)rrset_cache_update(worker->env.rrset_cache, &ref, 521238106Sdes &worker->alloc, *worker->env.now); 522238106Sdes return 1; 523238106Sdes} 524238106Sdes 525238106Sdes/** load an rrset entry */ 526238106Sdesstatic int 527238106Sdesload_rrset(SSL* ssl, ldns_buffer* buf, struct worker* worker) 528238106Sdes{ 529238106Sdes char* s = (char*)ldns_buffer_begin(buf); 530238106Sdes struct regional* region = worker->scratchpad; 531238106Sdes struct ub_packed_rrset_key* rk; 532238106Sdes struct packed_rrset_data* d; 533238106Sdes unsigned int ttl, rr_count, rrsig_count, trust, security; 534238106Sdes unsigned int i; 535238106Sdes int go_on = 1; 536238106Sdes regional_free_all(region); 537238106Sdes 538238106Sdes rk = (struct ub_packed_rrset_key*)regional_alloc_zero(region, 539238106Sdes sizeof(*rk)); 540238106Sdes d = (struct packed_rrset_data*)regional_alloc_zero(region, sizeof(*d)); 541238106Sdes if(!rk || !d) { 542238106Sdes log_warn("error out of memory"); 543238106Sdes return 0; 544238106Sdes } 545238106Sdes 546238106Sdes if(strncmp(s, ";rrset", 6) != 0) { 547238106Sdes log_warn("error expected ';rrset' but got %s", s); 548238106Sdes return 0; 549238106Sdes } 550238106Sdes s += 6; 551238106Sdes if(strncmp(s, " nsec_apex", 10) == 0) { 552238106Sdes s += 10; 553238106Sdes rk->rk.flags |= PACKED_RRSET_NSEC_AT_APEX; 554238106Sdes } 555238106Sdes if(sscanf(s, " %u %u %u %u %u", &ttl, &rr_count, &rrsig_count, 556238106Sdes &trust, &security) != 5) { 557238106Sdes log_warn("error bad rrset spec %s", s); 558238106Sdes return 0; 559238106Sdes } 560238106Sdes if(rr_count == 0 && rrsig_count == 0) { 561238106Sdes log_warn("bad rrset without contents"); 562238106Sdes return 0; 563238106Sdes } 564238106Sdes d->count = (size_t)rr_count; 565238106Sdes d->rrsig_count = (size_t)rrsig_count; 566238106Sdes d->security = (enum sec_status)security; 567238106Sdes d->trust = (enum rrset_trust)trust; 568238106Sdes d->ttl = (uint32_t)ttl + *worker->env.now; 569238106Sdes 570238106Sdes d->rr_len = regional_alloc_zero(region, 571238106Sdes sizeof(size_t)*(d->count+d->rrsig_count)); 572238106Sdes d->rr_ttl = regional_alloc_zero(region, 573238106Sdes sizeof(uint32_t)*(d->count+d->rrsig_count)); 574238106Sdes d->rr_data = regional_alloc_zero(region, 575238106Sdes sizeof(uint8_t*)*(d->count+d->rrsig_count)); 576238106Sdes if(!d->rr_len || !d->rr_ttl || !d->rr_data) { 577238106Sdes log_warn("error out of memory"); 578238106Sdes return 0; 579238106Sdes } 580238106Sdes 581238106Sdes /* read the rr's themselves */ 582238106Sdes for(i=0; i<rr_count; i++) { 583238106Sdes if(!load_rr(ssl, buf, region, rk, d, i, 0, 584238106Sdes &go_on, *worker->env.now)) { 585238106Sdes log_warn("could not read rr %u", i); 586238106Sdes return 0; 587238106Sdes } 588238106Sdes } 589238106Sdes for(i=0; i<rrsig_count; i++) { 590238106Sdes if(!load_rr(ssl, buf, region, rk, d, i+rr_count, 1, 591238106Sdes &go_on, *worker->env.now)) { 592238106Sdes log_warn("could not read rrsig %u", i); 593238106Sdes return 0; 594238106Sdes } 595238106Sdes } 596238106Sdes if(!go_on) { 597238106Sdes /* skip this entry */ 598238106Sdes return 1; 599238106Sdes } 600238106Sdes 601238106Sdes return move_into_cache(rk, d, worker); 602238106Sdes} 603238106Sdes 604238106Sdes/** load rrset cache */ 605238106Sdesstatic int 606238106Sdesload_rrset_cache(SSL* ssl, struct worker* worker) 607238106Sdes{ 608238106Sdes ldns_buffer* buf = worker->env.scratch_buffer; 609238106Sdes if(!read_fixed(ssl, buf, "START_RRSET_CACHE")) return 0; 610238106Sdes while(ssl_read_buf(ssl, buf) && 611238106Sdes strcmp((char*)ldns_buffer_begin(buf), "END_RRSET_CACHE")!=0) { 612238106Sdes if(!load_rrset(ssl, buf, worker)) 613238106Sdes return 0; 614238106Sdes } 615238106Sdes return 1; 616238106Sdes} 617238106Sdes 618238106Sdes/** read qinfo from next three words */ 619238106Sdesstatic char* 620238106Sdesload_qinfo(char* str, struct query_info* qinfo, ldns_buffer* buf, 621238106Sdes struct regional* region) 622238106Sdes{ 623238106Sdes /* s is part of the buf */ 624238106Sdes char* s = str; 625238106Sdes ldns_rr* rr; 626238106Sdes ldns_status status; 627238106Sdes 628238106Sdes /* skip three words */ 629238106Sdes s = strchr(str, ' '); 630238106Sdes if(s) s = strchr(s+1, ' '); 631238106Sdes if(s) s = strchr(s+1, ' '); 632238106Sdes if(!s) { 633238106Sdes log_warn("error line too short, %s", str); 634238106Sdes return NULL; 635238106Sdes } 636238106Sdes s[0] = 0; 637238106Sdes s++; 638238106Sdes 639238106Sdes /* parse them */ 640238106Sdes status = ldns_rr_new_question_frm_str(&rr, str, NULL, NULL); 641238106Sdes if(status != LDNS_STATUS_OK) { 642238106Sdes log_warn("error cannot parse: %s %s", 643238106Sdes ldns_get_errorstr_by_id(status), str); 644238106Sdes return NULL; 645238106Sdes } 646238106Sdes qinfo->qtype = ldns_rr_get_type(rr); 647238106Sdes qinfo->qclass = ldns_rr_get_class(rr); 648238106Sdes ldns_buffer_clear(buf); 649238106Sdes status = ldns_dname2buffer_wire(buf, ldns_rr_owner(rr)); 650238106Sdes ldns_rr_free(rr); 651238106Sdes if(status != LDNS_STATUS_OK) { 652238106Sdes log_warn("error cannot dname2wire: %s", 653238106Sdes ldns_get_errorstr_by_id(status)); 654238106Sdes return NULL; 655238106Sdes } 656238106Sdes ldns_buffer_flip(buf); 657238106Sdes qinfo->qname_len = ldns_buffer_limit(buf); 658238106Sdes qinfo->qname = (uint8_t*)regional_alloc_init(region, 659238106Sdes ldns_buffer_begin(buf), ldns_buffer_limit(buf)); 660238106Sdes if(!qinfo->qname) { 661238106Sdes log_warn("error out of memory"); 662238106Sdes return NULL; 663238106Sdes } 664238106Sdes 665238106Sdes return s; 666238106Sdes} 667238106Sdes 668238106Sdes/** load a msg rrset reference */ 669238106Sdesstatic int 670238106Sdesload_ref(SSL* ssl, ldns_buffer* buf, struct worker* worker, 671238106Sdes struct regional *region, struct ub_packed_rrset_key** rrset, 672238106Sdes int* go_on) 673238106Sdes{ 674238106Sdes char* s = (char*)ldns_buffer_begin(buf); 675238106Sdes struct query_info qinfo; 676238106Sdes unsigned int flags; 677238106Sdes struct ub_packed_rrset_key* k; 678238106Sdes 679238106Sdes /* read line */ 680238106Sdes if(!ssl_read_buf(ssl, buf)) 681238106Sdes return 0; 682238106Sdes if(strncmp(s, "BADREF", 6) == 0) { 683238106Sdes *go_on = 0; /* its bad, skip it and skip message */ 684238106Sdes return 1; 685238106Sdes } 686238106Sdes 687238106Sdes s = load_qinfo(s, &qinfo, buf, region); 688238106Sdes if(!s) { 689238106Sdes return 0; 690238106Sdes } 691238106Sdes if(sscanf(s, " %u", &flags) != 1) { 692238106Sdes log_warn("error cannot parse flags: %s", s); 693238106Sdes return 0; 694238106Sdes } 695238106Sdes 696238106Sdes /* lookup in cache */ 697238106Sdes k = rrset_cache_lookup(worker->env.rrset_cache, qinfo.qname, 698238106Sdes qinfo.qname_len, qinfo.qtype, qinfo.qclass, 699238106Sdes (uint32_t)flags, *worker->env.now, 0); 700238106Sdes if(!k) { 701238106Sdes /* not found or expired */ 702238106Sdes *go_on = 0; 703238106Sdes return 1; 704238106Sdes } 705238106Sdes 706238106Sdes /* store in result */ 707238106Sdes *rrset = packed_rrset_copy_region(k, region, *worker->env.now); 708238106Sdes lock_rw_unlock(&k->entry.lock); 709238106Sdes 710238106Sdes return (*rrset != NULL); 711238106Sdes} 712238106Sdes 713238106Sdes/** load a msg entry */ 714238106Sdesstatic int 715238106Sdesload_msg(SSL* ssl, ldns_buffer* buf, struct worker* worker) 716238106Sdes{ 717238106Sdes struct regional* region = worker->scratchpad; 718238106Sdes struct query_info qinf; 719238106Sdes struct reply_info rep; 720238106Sdes char* s = (char*)ldns_buffer_begin(buf); 721238106Sdes unsigned int flags, qdcount, ttl, security, an, ns, ar; 722238106Sdes size_t i; 723238106Sdes int go_on = 1; 724238106Sdes 725238106Sdes regional_free_all(region); 726238106Sdes 727238106Sdes if(strncmp(s, "msg ", 4) != 0) { 728238106Sdes log_warn("error expected msg but got %s", s); 729238106Sdes return 0; 730238106Sdes } 731238106Sdes s += 4; 732238106Sdes s = load_qinfo(s, &qinf, buf, region); 733238106Sdes if(!s) { 734238106Sdes return 0; 735238106Sdes } 736238106Sdes 737238106Sdes /* read remainder of line */ 738238106Sdes if(sscanf(s, " %u %u %u %u %u %u %u", &flags, &qdcount, &ttl, 739238106Sdes &security, &an, &ns, &ar) != 7) { 740238106Sdes log_warn("error cannot parse numbers: %s", s); 741238106Sdes return 0; 742238106Sdes } 743238106Sdes rep.flags = (uint16_t)flags; 744238106Sdes rep.qdcount = (uint16_t)qdcount; 745238106Sdes rep.ttl = (uint32_t)ttl; 746238106Sdes rep.prefetch_ttl = PREFETCH_TTL_CALC(rep.ttl); 747238106Sdes rep.security = (enum sec_status)security; 748238106Sdes rep.an_numrrsets = (size_t)an; 749238106Sdes rep.ns_numrrsets = (size_t)ns; 750238106Sdes rep.ar_numrrsets = (size_t)ar; 751238106Sdes rep.rrset_count = (size_t)an+(size_t)ns+(size_t)ar; 752238106Sdes rep.rrsets = (struct ub_packed_rrset_key**)regional_alloc_zero( 753238106Sdes region, sizeof(struct ub_packed_rrset_key*)*rep.rrset_count); 754238106Sdes 755238106Sdes /* fill repinfo with references */ 756238106Sdes for(i=0; i<rep.rrset_count; i++) { 757238106Sdes if(!load_ref(ssl, buf, worker, region, &rep.rrsets[i], 758238106Sdes &go_on)) { 759238106Sdes return 0; 760238106Sdes } 761238106Sdes } 762238106Sdes 763238106Sdes if(!go_on) 764238106Sdes return 1; /* skip this one, not all references satisfied */ 765238106Sdes 766238106Sdes if(!dns_cache_store(&worker->env, &qinf, &rep, 0, 0, 0, NULL)) { 767238106Sdes log_warn("error out of memory"); 768238106Sdes return 0; 769238106Sdes } 770238106Sdes return 1; 771238106Sdes} 772238106Sdes 773238106Sdes/** load msg cache */ 774238106Sdesstatic int 775238106Sdesload_msg_cache(SSL* ssl, struct worker* worker) 776238106Sdes{ 777238106Sdes ldns_buffer* buf = worker->env.scratch_buffer; 778238106Sdes if(!read_fixed(ssl, buf, "START_MSG_CACHE")) return 0; 779238106Sdes while(ssl_read_buf(ssl, buf) && 780238106Sdes strcmp((char*)ldns_buffer_begin(buf), "END_MSG_CACHE")!=0) { 781238106Sdes if(!load_msg(ssl, buf, worker)) 782238106Sdes return 0; 783238106Sdes } 784238106Sdes return 1; 785238106Sdes} 786238106Sdes 787238106Sdesint 788238106Sdesload_cache(SSL* ssl, struct worker* worker) 789238106Sdes{ 790238106Sdes if(!load_rrset_cache(ssl, worker)) 791238106Sdes return 0; 792238106Sdes if(!load_msg_cache(ssl, worker)) 793238106Sdes return 0; 794238106Sdes return read_fixed(ssl, worker->env.scratch_buffer, "EOF"); 795238106Sdes} 796238106Sdes 797238106Sdes/** print details on a delegation point */ 798238106Sdesstatic void 799238106Sdesprint_dp_details(SSL* ssl, struct worker* worker, struct delegpt* dp) 800238106Sdes{ 801238106Sdes char buf[257]; 802238106Sdes struct delegpt_addr* a; 803238106Sdes int lame, dlame, rlame, rto, edns_vs, to, delay, entry_ttl, 804238106Sdes tA = 0, tAAAA = 0, tother = 0; 805238106Sdes struct rtt_info ri; 806238106Sdes uint8_t edns_lame_known; 807238106Sdes for(a = dp->target_list; a; a = a->next_target) { 808238106Sdes addr_to_str(&a->addr, a->addrlen, buf, sizeof(buf)); 809238106Sdes if(!ssl_printf(ssl, "%-16s\t", buf)) 810238106Sdes return; 811238106Sdes if(a->bogus) { 812238106Sdes if(!ssl_printf(ssl, "Address is BOGUS. ")) 813238106Sdes return; 814238106Sdes } 815238106Sdes /* lookup in infra cache */ 816238106Sdes delay=0; 817238106Sdes entry_ttl = infra_get_host_rto(worker->env.infra_cache, 818238106Sdes &a->addr, a->addrlen, dp->name, dp->namelen, 819238106Sdes &ri, &delay, *worker->env.now, &tA, &tAAAA, &tother); 820238106Sdes if(entry_ttl == -2 && ri.rto >= USEFUL_SERVER_TOP_TIMEOUT) { 821238106Sdes if(!ssl_printf(ssl, "expired, rto %d msec, tA %d " 822238106Sdes "tAAAA %d tother %d.\n", ri.rto, tA, tAAAA, 823238106Sdes tother)) 824238106Sdes return; 825238106Sdes continue; 826238106Sdes } 827238106Sdes if(entry_ttl == -1 || entry_ttl == -2) { 828238106Sdes if(!ssl_printf(ssl, "not in infra cache.\n")) 829238106Sdes return; 830238106Sdes continue; /* skip stuff not in infra cache */ 831238106Sdes } 832238106Sdes 833238106Sdes /* uses type_A because most often looked up, but other 834238106Sdes * lameness won't be reported then */ 835238106Sdes if(!infra_get_lame_rtt(worker->env.infra_cache, 836238106Sdes &a->addr, a->addrlen, dp->name, dp->namelen, 837238106Sdes LDNS_RR_TYPE_A, &lame, &dlame, &rlame, &rto, 838238106Sdes *worker->env.now)) { 839238106Sdes if(!ssl_printf(ssl, "not in infra cache.\n")) 840238106Sdes return; 841238106Sdes continue; /* skip stuff not in infra cache */ 842238106Sdes } 843238106Sdes if(!ssl_printf(ssl, "%s%s%s%srto %d msec, ttl %d, ping %d " 844238106Sdes "var %d rtt %d, tA %d, tAAAA %d, tother %d", 845238106Sdes lame?"LAME ":"", dlame?"NoDNSSEC ":"", 846238106Sdes a->lame?"AddrWasParentSide ":"", 847238106Sdes rlame?"NoAuthButRecursive ":"", rto, entry_ttl, 848238106Sdes ri.srtt, ri.rttvar, rtt_notimeout(&ri), 849238106Sdes tA, tAAAA, tother)) 850238106Sdes return; 851238106Sdes if(delay) 852238106Sdes if(!ssl_printf(ssl, ", probedelay %d", delay)) 853238106Sdes return; 854238106Sdes if(infra_host(worker->env.infra_cache, &a->addr, a->addrlen, 855238106Sdes dp->name, dp->namelen, *worker->env.now, &edns_vs, 856238106Sdes &edns_lame_known, &to)) { 857238106Sdes if(edns_vs == -1) { 858238106Sdes if(!ssl_printf(ssl, ", noEDNS%s.", 859238106Sdes edns_lame_known?" probed":" assumed")) 860238106Sdes return; 861238106Sdes } else { 862238106Sdes if(!ssl_printf(ssl, ", EDNS %d%s.", edns_vs, 863238106Sdes edns_lame_known?" probed":" assumed")) 864238106Sdes return; 865238106Sdes } 866238106Sdes } 867238106Sdes if(!ssl_printf(ssl, "\n")) 868238106Sdes return; 869238106Sdes } 870238106Sdes} 871238106Sdes 872238106Sdes/** print main dp info */ 873238106Sdesstatic void 874238106Sdesprint_dp_main(SSL* ssl, struct delegpt* dp, struct dns_msg* msg) 875238106Sdes{ 876238106Sdes size_t i, n_ns, n_miss, n_addr, n_res, n_avail; 877238106Sdes 878238106Sdes /* print the dp */ 879238106Sdes if(msg) 880238106Sdes for(i=0; i<msg->rep->rrset_count; i++) { 881238106Sdes struct ub_packed_rrset_key* k = msg->rep->rrsets[i]; 882238106Sdes struct packed_rrset_data* d = 883238106Sdes (struct packed_rrset_data*)k->entry.data; 884238106Sdes if(d->security == sec_status_bogus) { 885238106Sdes if(!ssl_printf(ssl, "Address is BOGUS:\n")) 886238106Sdes return; 887238106Sdes } 888238106Sdes if(!dump_rrset(ssl, k, d, 0)) 889238106Sdes return; 890238106Sdes } 891238106Sdes delegpt_count_ns(dp, &n_ns, &n_miss); 892238106Sdes delegpt_count_addr(dp, &n_addr, &n_res, &n_avail); 893238106Sdes /* since dp has not been used by iterator, all are available*/ 894238106Sdes if(!ssl_printf(ssl, "Delegation with %d names, of which %d " 895238106Sdes "can be examined to query further addresses.\n" 896238106Sdes "%sIt provides %d IP addresses.\n", 897238106Sdes (int)n_ns, (int)n_miss, (dp->bogus?"It is BOGUS. ":""), 898238106Sdes (int)n_addr)) 899238106Sdes return; 900238106Sdes} 901238106Sdes 902238106Sdesint print_deleg_lookup(SSL* ssl, struct worker* worker, uint8_t* nm, 903238106Sdes size_t nmlen, int ATTR_UNUSED(nmlabs)) 904238106Sdes{ 905238106Sdes /* deep links into the iterator module */ 906238106Sdes struct delegpt* dp; 907238106Sdes struct dns_msg* msg; 908238106Sdes struct regional* region = worker->scratchpad; 909238106Sdes char b[260]; 910238106Sdes struct query_info qinfo; 911238106Sdes struct iter_hints_stub* stub; 912238106Sdes regional_free_all(region); 913238106Sdes qinfo.qname = nm; 914238106Sdes qinfo.qname_len = nmlen; 915238106Sdes qinfo.qtype = LDNS_RR_TYPE_A; 916238106Sdes qinfo.qclass = LDNS_RR_CLASS_IN; 917238106Sdes 918238106Sdes dname_str(nm, b); 919238106Sdes if(!ssl_printf(ssl, "The following name servers are used for lookup " 920238106Sdes "of %s\n", b)) 921238106Sdes return 0; 922238106Sdes 923238106Sdes dp = forwards_lookup(worker->env.fwds, nm, qinfo.qclass); 924238106Sdes if(dp) { 925238106Sdes if(!ssl_printf(ssl, "forwarding request:\n")) 926238106Sdes return 0; 927238106Sdes print_dp_main(ssl, dp, NULL); 928238106Sdes print_dp_details(ssl, worker, dp); 929238106Sdes return 1; 930238106Sdes } 931238106Sdes 932238106Sdes while(1) { 933238106Sdes dp = dns_cache_find_delegation(&worker->env, nm, nmlen, 934238106Sdes qinfo.qtype, qinfo.qclass, region, &msg, 935238106Sdes *worker->env.now); 936238106Sdes if(!dp) { 937238106Sdes return ssl_printf(ssl, "no delegation from " 938238106Sdes "cache; goes to configured roots\n"); 939238106Sdes } 940238106Sdes /* go up? */ 941238106Sdes if(iter_dp_is_useless(&qinfo, BIT_RD, dp)) { 942238106Sdes print_dp_main(ssl, dp, msg); 943238106Sdes print_dp_details(ssl, worker, dp); 944238106Sdes if(!ssl_printf(ssl, "cache delegation was " 945238106Sdes "useless (no IP addresses)\n")) 946238106Sdes return 0; 947238106Sdes if(dname_is_root(nm)) { 948238106Sdes /* goes to root config */ 949238106Sdes return ssl_printf(ssl, "no delegation from " 950238106Sdes "cache; goes to configured roots\n"); 951238106Sdes } else { 952238106Sdes /* useless, goes up */ 953238106Sdes nm = dp->name; 954238106Sdes nmlen = dp->namelen; 955238106Sdes dname_remove_label(&nm, &nmlen); 956238106Sdes dname_str(nm, b); 957238106Sdes if(!ssl_printf(ssl, "going up, lookup %s\n", b)) 958238106Sdes return 0; 959238106Sdes continue; 960238106Sdes } 961238106Sdes } 962238106Sdes stub = hints_lookup_stub(worker->env.hints, nm, qinfo.qclass, 963238106Sdes dp); 964238106Sdes if(stub) { 965238106Sdes if(stub->noprime) { 966238106Sdes if(!ssl_printf(ssl, "The noprime stub servers " 967238106Sdes "are used:\n")) 968238106Sdes return 0; 969238106Sdes } else { 970238106Sdes if(!ssl_printf(ssl, "The stub is primed " 971238106Sdes "with servers:\n")) 972238106Sdes return 0; 973238106Sdes } 974238106Sdes print_dp_main(ssl, stub->dp, NULL); 975238106Sdes print_dp_details(ssl, worker, stub->dp); 976238106Sdes } else { 977238106Sdes print_dp_main(ssl, dp, msg); 978238106Sdes print_dp_details(ssl, worker, dp); 979238106Sdes } 980238106Sdes break; 981238106Sdes } 982238106Sdes 983238106Sdes return 1; 984238106Sdes} 985