1933707f3Ssthen /*
2933707f3Ssthen * daemon/cachedump.c - dump the cache to text format.
3933707f3Ssthen *
4933707f3Ssthen * Copyright (c) 2008, NLnet Labs. All rights reserved.
5933707f3Ssthen *
6933707f3Ssthen * This software is open source.
7933707f3Ssthen *
8933707f3Ssthen * Redistribution and use in source and binary forms, with or without
9933707f3Ssthen * modification, are permitted provided that the following conditions
10933707f3Ssthen * are met:
11933707f3Ssthen *
12933707f3Ssthen * Redistributions of source code must retain the above copyright notice,
13933707f3Ssthen * this list of conditions and the following disclaimer.
14933707f3Ssthen *
15933707f3Ssthen * Redistributions in binary form must reproduce the above copyright notice,
16933707f3Ssthen * this list of conditions and the following disclaimer in the documentation
17933707f3Ssthen * and/or other materials provided with the distribution.
18933707f3Ssthen *
19933707f3Ssthen * Neither the name of the NLNET LABS nor the names of its contributors may
20933707f3Ssthen * be used to endorse or promote products derived from this software without
21933707f3Ssthen * specific prior written permission.
22933707f3Ssthen *
23933707f3Ssthen * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
245d76a658Ssthen * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
255d76a658Ssthen * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
265d76a658Ssthen * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
275d76a658Ssthen * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
285d76a658Ssthen * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
295d76a658Ssthen * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
305d76a658Ssthen * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
315d76a658Ssthen * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
325d76a658Ssthen * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
335d76a658Ssthen * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34933707f3Ssthen */
35933707f3Ssthen
36933707f3Ssthen /**
37933707f3Ssthen * \file
38933707f3Ssthen *
39933707f3Ssthen * This file contains functions to read and write the cache(s)
40933707f3Ssthen * to text format.
41933707f3Ssthen */
42933707f3Ssthen #include "config.h"
435d76a658Ssthen #include <openssl/ssl.h>
44933707f3Ssthen #include "daemon/cachedump.h"
45933707f3Ssthen #include "daemon/remote.h"
46933707f3Ssthen #include "daemon/worker.h"
47933707f3Ssthen #include "services/cache/rrset.h"
48933707f3Ssthen #include "services/cache/dns.h"
49933707f3Ssthen #include "services/cache/infra.h"
500bdb4f62Ssthen #include "services/outside_network.h"
51933707f3Ssthen #include "util/data/msgreply.h"
52933707f3Ssthen #include "util/regional.h"
53933707f3Ssthen #include "util/net_help.h"
54933707f3Ssthen #include "util/data/dname.h"
550bdb4f62Ssthen #include "util/config_file.h"
56933707f3Ssthen #include "iterator/iterator.h"
57933707f3Ssthen #include "iterator/iter_delegpt.h"
58933707f3Ssthen #include "iterator/iter_utils.h"
59933707f3Ssthen #include "iterator/iter_fwd.h"
60933707f3Ssthen #include "iterator/iter_hints.h"
61a58bff56Ssthen #include "sldns/sbuffer.h"
62a58bff56Ssthen #include "sldns/wire2str.h"
63a58bff56Ssthen #include "sldns/str2wire.h"
64933707f3Ssthen
65933707f3Ssthen /** dump one rrset zonefile line */
66933707f3Ssthen static int
dump_rrset_line(RES * ssl,struct ub_packed_rrset_key * k,time_t now,size_t i)6720237c55Ssthen dump_rrset_line(RES* ssl, struct ub_packed_rrset_key* k, time_t now, size_t i)
68933707f3Ssthen {
695d76a658Ssthen char s[65535];
705d76a658Ssthen if(!packed_rr_to_string(k, i, now, s, sizeof(s))) {
71933707f3Ssthen return ssl_printf(ssl, "BADRR\n");
72933707f3Ssthen }
735d76a658Ssthen return ssl_printf(ssl, "%s", s);
74933707f3Ssthen }
75933707f3Ssthen
76933707f3Ssthen /** dump rrset key and data info */
77933707f3Ssthen static int
dump_rrset(RES * ssl,struct ub_packed_rrset_key * k,struct packed_rrset_data * d,time_t now)7820237c55Ssthen dump_rrset(RES* ssl, struct ub_packed_rrset_key* k,
79229e174cSsthen struct packed_rrset_data* d, time_t now)
80933707f3Ssthen {
81933707f3Ssthen size_t i;
82933707f3Ssthen /* rd lock held by caller */
83933707f3Ssthen if(!k || !d) return 1;
84938a3a5eSflorian if(k->id == 0) return 1; /* deleted */
85933707f3Ssthen if(d->ttl < now) return 1; /* expired */
86933707f3Ssthen
87933707f3Ssthen /* meta line */
885d76a658Ssthen if(!ssl_printf(ssl, ";rrset%s " ARG_LL "d %u %u %d %d\n",
89933707f3Ssthen (k->rk.flags & PACKED_RRSET_NSEC_AT_APEX)?" nsec_apex":"",
90229e174cSsthen (long long)(d->ttl - now),
91933707f3Ssthen (unsigned)d->count, (unsigned)d->rrsig_count,
92933707f3Ssthen (int)d->trust, (int)d->security
93933707f3Ssthen ))
94933707f3Ssthen return 0;
955d76a658Ssthen for(i=0; i<d->count + d->rrsig_count; i++) {
965d76a658Ssthen if(!dump_rrset_line(ssl, k, now, i))
97933707f3Ssthen return 0;
98933707f3Ssthen }
99933707f3Ssthen return 1;
100933707f3Ssthen }
101933707f3Ssthen
102933707f3Ssthen /** dump lruhash rrset cache */
103933707f3Ssthen static int
dump_rrset_lruhash(RES * ssl,struct lruhash * h,time_t now)10420237c55Ssthen dump_rrset_lruhash(RES* ssl, struct lruhash* h, time_t now)
105933707f3Ssthen {
106933707f3Ssthen struct lruhash_entry* e;
107933707f3Ssthen /* lruhash already locked by caller */
108933707f3Ssthen /* walk in order of lru; best first */
109933707f3Ssthen for(e=h->lru_start; e; e = e->lru_next) {
110933707f3Ssthen lock_rw_rdlock(&e->lock);
111933707f3Ssthen if(!dump_rrset(ssl, (struct ub_packed_rrset_key*)e->key,
112933707f3Ssthen (struct packed_rrset_data*)e->data, now)) {
113933707f3Ssthen lock_rw_unlock(&e->lock);
114933707f3Ssthen return 0;
115933707f3Ssthen }
116933707f3Ssthen lock_rw_unlock(&e->lock);
117933707f3Ssthen }
118933707f3Ssthen return 1;
119933707f3Ssthen }
120933707f3Ssthen
121933707f3Ssthen /** dump rrset cache */
122933707f3Ssthen static int
dump_rrset_cache(RES * ssl,struct worker * worker)12320237c55Ssthen dump_rrset_cache(RES* ssl, struct worker* worker)
124933707f3Ssthen {
125933707f3Ssthen struct rrset_cache* r = worker->env.rrset_cache;
126933707f3Ssthen size_t slab;
127933707f3Ssthen if(!ssl_printf(ssl, "START_RRSET_CACHE\n")) return 0;
128933707f3Ssthen for(slab=0; slab<r->table.size; slab++) {
129933707f3Ssthen lock_quick_lock(&r->table.array[slab]->lock);
130933707f3Ssthen if(!dump_rrset_lruhash(ssl, r->table.array[slab],
131933707f3Ssthen *worker->env.now)) {
132933707f3Ssthen lock_quick_unlock(&r->table.array[slab]->lock);
133933707f3Ssthen return 0;
134933707f3Ssthen }
135933707f3Ssthen lock_quick_unlock(&r->table.array[slab]->lock);
136933707f3Ssthen }
137933707f3Ssthen return ssl_printf(ssl, "END_RRSET_CACHE\n");
138933707f3Ssthen }
139933707f3Ssthen
140933707f3Ssthen /** dump message to rrset reference */
141933707f3Ssthen static int
dump_msg_ref(RES * ssl,struct ub_packed_rrset_key * k)14220237c55Ssthen dump_msg_ref(RES* ssl, struct ub_packed_rrset_key* k)
143933707f3Ssthen {
144933707f3Ssthen char* nm, *tp, *cl;
1455d76a658Ssthen nm = sldns_wire2str_dname(k->rk.dname, k->rk.dname_len);
1465d76a658Ssthen tp = sldns_wire2str_type(ntohs(k->rk.type));
1475d76a658Ssthen cl = sldns_wire2str_class(ntohs(k->rk.rrset_class));
148933707f3Ssthen if(!nm || !cl || !tp) {
149933707f3Ssthen free(nm);
150933707f3Ssthen free(tp);
151933707f3Ssthen free(cl);
152933707f3Ssthen return ssl_printf(ssl, "BADREF\n");
153933707f3Ssthen }
154933707f3Ssthen if(!ssl_printf(ssl, "%s %s %s %d\n", nm, cl, tp, (int)k->rk.flags)) {
155933707f3Ssthen free(nm);
156933707f3Ssthen free(tp);
157933707f3Ssthen free(cl);
158933707f3Ssthen return 0;
159933707f3Ssthen }
160933707f3Ssthen free(nm);
161933707f3Ssthen free(tp);
162933707f3Ssthen free(cl);
163933707f3Ssthen
164933707f3Ssthen return 1;
165933707f3Ssthen }
166933707f3Ssthen
167933707f3Ssthen /** dump message entry */
168933707f3Ssthen static int
dump_msg(RES * ssl,struct query_info * k,struct reply_info * d,time_t now)1698b7325afSsthen dump_msg(RES* ssl, struct query_info* k, struct reply_info* d, time_t now)
170933707f3Ssthen {
171933707f3Ssthen size_t i;
172933707f3Ssthen char* nm, *tp, *cl;
173933707f3Ssthen if(!k || !d) return 1;
174933707f3Ssthen if(d->ttl < now) return 1; /* expired */
175933707f3Ssthen
1765d76a658Ssthen nm = sldns_wire2str_dname(k->qname, k->qname_len);
1775d76a658Ssthen tp = sldns_wire2str_type(k->qtype);
1785d76a658Ssthen cl = sldns_wire2str_class(k->qclass);
179933707f3Ssthen if(!nm || !tp || !cl) {
180933707f3Ssthen free(nm);
181933707f3Ssthen free(tp);
182933707f3Ssthen free(cl);
183933707f3Ssthen return 1; /* skip this entry */
184933707f3Ssthen }
185933707f3Ssthen if(!rrset_array_lock(d->ref, d->rrset_count, now)) {
186933707f3Ssthen /* rrsets have timed out or do not exist */
187933707f3Ssthen free(nm);
188933707f3Ssthen free(tp);
189933707f3Ssthen free(cl);
190933707f3Ssthen return 1; /* skip this entry */
191933707f3Ssthen }
192933707f3Ssthen
193933707f3Ssthen /* meta line */
1948b7325afSsthen if(!ssl_printf(ssl, "msg %s %s %s %d %d " ARG_LL "d %d %u %u %u %d %s\n",
195933707f3Ssthen nm, cl, tp,
196933707f3Ssthen (int)d->flags, (int)d->qdcount,
197229e174cSsthen (long long)(d->ttl-now), (int)d->security,
198933707f3Ssthen (unsigned)d->an_numrrsets,
199933707f3Ssthen (unsigned)d->ns_numrrsets,
2008b7325afSsthen (unsigned)d->ar_numrrsets,
2018b7325afSsthen (int)d->reason_bogus,
2028b7325afSsthen d->reason_bogus_str?d->reason_bogus_str:"")) {
203933707f3Ssthen free(nm);
204933707f3Ssthen free(tp);
205933707f3Ssthen free(cl);
206933707f3Ssthen rrset_array_unlock(d->ref, d->rrset_count);
207933707f3Ssthen return 0;
208933707f3Ssthen }
209933707f3Ssthen free(nm);
210933707f3Ssthen free(tp);
211933707f3Ssthen free(cl);
212933707f3Ssthen
213933707f3Ssthen for(i=0; i<d->rrset_count; i++) {
214933707f3Ssthen if(!dump_msg_ref(ssl, d->rrsets[i])) {
215933707f3Ssthen rrset_array_unlock(d->ref, d->rrset_count);
216933707f3Ssthen return 0;
217933707f3Ssthen }
218933707f3Ssthen }
219933707f3Ssthen rrset_array_unlock(d->ref, d->rrset_count);
220933707f3Ssthen
221933707f3Ssthen return 1;
222933707f3Ssthen }
223933707f3Ssthen
224933707f3Ssthen /** copy msg to worker pad */
225933707f3Ssthen static int
copy_msg(struct regional * region,struct lruhash_entry * e,struct query_info ** k,struct reply_info ** d)226933707f3Ssthen copy_msg(struct regional* region, struct lruhash_entry* e,
227933707f3Ssthen struct query_info** k, struct reply_info** d)
228933707f3Ssthen {
229933707f3Ssthen struct reply_info* rep = (struct reply_info*)e->data;
230a58bff56Ssthen if(rep->rrset_count > RR_COUNT_MAX)
231a58bff56Ssthen return 0; /* to protect against integer overflow */
232933707f3Ssthen *d = (struct reply_info*)regional_alloc_init(region, e->data,
233933707f3Ssthen sizeof(struct reply_info) +
234933707f3Ssthen sizeof(struct rrset_ref) * (rep->rrset_count-1) +
235933707f3Ssthen sizeof(struct ub_packed_rrset_key*) * rep->rrset_count);
236933707f3Ssthen if(!*d)
237933707f3Ssthen return 0;
23898f3ca02Sbrad (*d)->rrsets = (struct ub_packed_rrset_key**)(void *)(
239933707f3Ssthen (uint8_t*)(&((*d)->ref[0])) +
240933707f3Ssthen sizeof(struct rrset_ref) * rep->rrset_count);
241933707f3Ssthen *k = (struct query_info*)regional_alloc_init(region,
242933707f3Ssthen e->key, sizeof(struct query_info));
243933707f3Ssthen if(!*k)
244933707f3Ssthen return 0;
245933707f3Ssthen (*k)->qname = regional_alloc_init(region,
246933707f3Ssthen (*k)->qname, (*k)->qname_len);
247933707f3Ssthen return (*k)->qname != NULL;
248933707f3Ssthen }
249933707f3Ssthen
250933707f3Ssthen /** dump lruhash msg cache */
251933707f3Ssthen static int
dump_msg_lruhash(RES * ssl,struct worker * worker,struct lruhash * h)25220237c55Ssthen dump_msg_lruhash(RES* ssl, struct worker* worker, struct lruhash* h)
253933707f3Ssthen {
254933707f3Ssthen struct lruhash_entry* e;
255933707f3Ssthen struct query_info* k;
256933707f3Ssthen struct reply_info* d;
257933707f3Ssthen
258933707f3Ssthen /* lruhash already locked by caller */
259933707f3Ssthen /* walk in order of lru; best first */
260933707f3Ssthen for(e=h->lru_start; e; e = e->lru_next) {
261933707f3Ssthen regional_free_all(worker->scratchpad);
262933707f3Ssthen lock_rw_rdlock(&e->lock);
263933707f3Ssthen /* make copy of rrset in worker buffer */
264933707f3Ssthen if(!copy_msg(worker->scratchpad, e, &k, &d)) {
265933707f3Ssthen lock_rw_unlock(&e->lock);
266933707f3Ssthen return 0;
267933707f3Ssthen }
268933707f3Ssthen lock_rw_unlock(&e->lock);
269933707f3Ssthen /* release lock so we can lookup the rrset references
270933707f3Ssthen * in the rrset cache */
271933707f3Ssthen if(!dump_msg(ssl, k, d, *worker->env.now)) {
272933707f3Ssthen return 0;
273933707f3Ssthen }
274933707f3Ssthen }
275933707f3Ssthen return 1;
276933707f3Ssthen }
277933707f3Ssthen
278933707f3Ssthen /** dump msg cache */
279933707f3Ssthen static int
dump_msg_cache(RES * ssl,struct worker * worker)28020237c55Ssthen dump_msg_cache(RES* ssl, struct worker* worker)
281933707f3Ssthen {
282933707f3Ssthen struct slabhash* sh = worker->env.msg_cache;
283933707f3Ssthen size_t slab;
284933707f3Ssthen if(!ssl_printf(ssl, "START_MSG_CACHE\n")) return 0;
285933707f3Ssthen for(slab=0; slab<sh->size; slab++) {
286933707f3Ssthen lock_quick_lock(&sh->array[slab]->lock);
287933707f3Ssthen if(!dump_msg_lruhash(ssl, worker, sh->array[slab])) {
288933707f3Ssthen lock_quick_unlock(&sh->array[slab]->lock);
289933707f3Ssthen return 0;
290933707f3Ssthen }
291933707f3Ssthen lock_quick_unlock(&sh->array[slab]->lock);
292933707f3Ssthen }
293933707f3Ssthen return ssl_printf(ssl, "END_MSG_CACHE\n");
294933707f3Ssthen }
295933707f3Ssthen
296933707f3Ssthen int
dump_cache(RES * ssl,struct worker * worker)29720237c55Ssthen dump_cache(RES* ssl, struct worker* worker)
298933707f3Ssthen {
299933707f3Ssthen if(!dump_rrset_cache(ssl, worker))
300933707f3Ssthen return 0;
301933707f3Ssthen if(!dump_msg_cache(ssl, worker))
302933707f3Ssthen return 0;
303933707f3Ssthen return ssl_printf(ssl, "EOF\n");
304933707f3Ssthen }
305933707f3Ssthen
306933707f3Ssthen /** read a line from ssl into buffer */
307933707f3Ssthen static int
ssl_read_buf(RES * ssl,sldns_buffer * buf)30820237c55Ssthen ssl_read_buf(RES* ssl, sldns_buffer* buf)
309933707f3Ssthen {
3105d76a658Ssthen return ssl_read_line(ssl, (char*)sldns_buffer_begin(buf),
3115d76a658Ssthen sldns_buffer_capacity(buf));
312933707f3Ssthen }
313933707f3Ssthen
314933707f3Ssthen /** check fixed text on line */
315933707f3Ssthen static int
read_fixed(RES * ssl,sldns_buffer * buf,const char * str)31620237c55Ssthen read_fixed(RES* ssl, sldns_buffer* buf, const char* str)
317933707f3Ssthen {
318933707f3Ssthen if(!ssl_read_buf(ssl, buf)) return 0;
3195d76a658Ssthen return (strcmp((char*)sldns_buffer_begin(buf), str) == 0);
320933707f3Ssthen }
321933707f3Ssthen
322933707f3Ssthen /** load an RR into rrset */
323933707f3Ssthen static int
load_rr(RES * ssl,sldns_buffer * buf,struct regional * region,struct ub_packed_rrset_key * rk,struct packed_rrset_data * d,unsigned int i,int is_rrsig,int * go_on,time_t now)32420237c55Ssthen load_rr(RES* ssl, sldns_buffer* buf, struct regional* region,
325933707f3Ssthen struct ub_packed_rrset_key* rk, struct packed_rrset_data* d,
326229e174cSsthen unsigned int i, int is_rrsig, int* go_on, time_t now)
327933707f3Ssthen {
3285d76a658Ssthen uint8_t rr[LDNS_RR_BUF_SIZE];
3295d76a658Ssthen size_t rr_len = sizeof(rr), dname_len = 0;
3305d76a658Ssthen int status;
331933707f3Ssthen
332933707f3Ssthen /* read the line */
333933707f3Ssthen if(!ssl_read_buf(ssl, buf))
334933707f3Ssthen return 0;
3355d76a658Ssthen if(strncmp((char*)sldns_buffer_begin(buf), "BADRR\n", 6) == 0) {
336933707f3Ssthen *go_on = 0;
337933707f3Ssthen return 1;
338933707f3Ssthen }
3395d76a658Ssthen status = sldns_str2wire_rr_buf((char*)sldns_buffer_begin(buf), rr,
3405d76a658Ssthen &rr_len, &dname_len, 3600, NULL, 0, NULL, 0);
3415d76a658Ssthen if(status != 0) {
342933707f3Ssthen log_warn("error cannot parse rr: %s: %s",
3435d76a658Ssthen sldns_get_errorstr_parse(status),
3445d76a658Ssthen (char*)sldns_buffer_begin(buf));
345933707f3Ssthen return 0;
346933707f3Ssthen }
3475d76a658Ssthen if(is_rrsig && sldns_wirerr_get_type(rr, rr_len, dname_len)
3485d76a658Ssthen != LDNS_RR_TYPE_RRSIG) {
349933707f3Ssthen log_warn("error expected rrsig but got %s",
3505d76a658Ssthen (char*)sldns_buffer_begin(buf));
351933707f3Ssthen return 0;
352933707f3Ssthen }
353933707f3Ssthen
354933707f3Ssthen /* convert ldns rr into packed_rr */
3555d76a658Ssthen d->rr_ttl[i] = (time_t)sldns_wirerr_get_ttl(rr, rr_len, dname_len) + now;
3565d76a658Ssthen sldns_buffer_clear(buf);
3575d76a658Ssthen d->rr_len[i] = sldns_wirerr_get_rdatalen(rr, rr_len, dname_len)+2;
358933707f3Ssthen d->rr_data[i] = (uint8_t*)regional_alloc_init(region,
3595d76a658Ssthen sldns_wirerr_get_rdatawl(rr, rr_len, dname_len), d->rr_len[i]);
360933707f3Ssthen if(!d->rr_data[i]) {
361933707f3Ssthen log_warn("error out of memory");
362933707f3Ssthen return 0;
363933707f3Ssthen }
364933707f3Ssthen
365933707f3Ssthen /* if first entry, fill the key structure */
366933707f3Ssthen if(i==0) {
3675d76a658Ssthen rk->rk.type = htons(sldns_wirerr_get_type(rr, rr_len, dname_len));
3685d76a658Ssthen rk->rk.rrset_class = htons(sldns_wirerr_get_class(rr, rr_len, dname_len));
3695d76a658Ssthen rk->rk.dname_len = dname_len;
3705d76a658Ssthen rk->rk.dname = regional_alloc_init(region, rr, dname_len);
371933707f3Ssthen if(!rk->rk.dname) {
372933707f3Ssthen log_warn("error out of memory");
373933707f3Ssthen return 0;
374933707f3Ssthen }
375933707f3Ssthen }
376933707f3Ssthen
377933707f3Ssthen return 1;
378933707f3Ssthen }
379933707f3Ssthen
380933707f3Ssthen /** move entry into cache */
381933707f3Ssthen static int
move_into_cache(struct ub_packed_rrset_key * k,struct packed_rrset_data * d,struct worker * worker)382933707f3Ssthen move_into_cache(struct ub_packed_rrset_key* k,
383933707f3Ssthen struct packed_rrset_data* d, struct worker* worker)
384933707f3Ssthen {
385933707f3Ssthen struct ub_packed_rrset_key* ak;
386933707f3Ssthen struct packed_rrset_data* ad;
387933707f3Ssthen size_t s, i, num = d->count + d->rrsig_count;
388933707f3Ssthen struct rrset_ref ref;
389933707f3Ssthen uint8_t* p;
390933707f3Ssthen
3918b7325afSsthen ak = alloc_special_obtain(worker->alloc);
392933707f3Ssthen if(!ak) {
393933707f3Ssthen log_warn("error out of memory");
394933707f3Ssthen return 0;
395933707f3Ssthen }
396933707f3Ssthen ak->entry.data = NULL;
397933707f3Ssthen ak->rk = k->rk;
398933707f3Ssthen ak->entry.hash = rrset_key_hash(&k->rk);
399933707f3Ssthen ak->rk.dname = (uint8_t*)memdup(k->rk.dname, k->rk.dname_len);
400933707f3Ssthen if(!ak->rk.dname) {
401933707f3Ssthen log_warn("error out of memory");
4028b7325afSsthen ub_packed_rrset_parsedelete(ak, worker->alloc);
403933707f3Ssthen return 0;
404933707f3Ssthen }
405933707f3Ssthen s = sizeof(*ad) + (sizeof(size_t) + sizeof(uint8_t*) +
406229e174cSsthen sizeof(time_t))* num;
407933707f3Ssthen for(i=0; i<num; i++)
408933707f3Ssthen s += d->rr_len[i];
409933707f3Ssthen ad = (struct packed_rrset_data*)malloc(s);
410933707f3Ssthen if(!ad) {
411933707f3Ssthen log_warn("error out of memory");
4128b7325afSsthen ub_packed_rrset_parsedelete(ak, worker->alloc);
413933707f3Ssthen return 0;
414933707f3Ssthen }
415933707f3Ssthen p = (uint8_t*)ad;
416933707f3Ssthen memmove(p, d, sizeof(*ad));
417933707f3Ssthen p += sizeof(*ad);
418933707f3Ssthen memmove(p, &d->rr_len[0], sizeof(size_t)*num);
419933707f3Ssthen p += sizeof(size_t)*num;
420933707f3Ssthen memmove(p, &d->rr_data[0], sizeof(uint8_t*)*num);
421933707f3Ssthen p += sizeof(uint8_t*)*num;
422229e174cSsthen memmove(p, &d->rr_ttl[0], sizeof(time_t)*num);
423229e174cSsthen p += sizeof(time_t)*num;
424933707f3Ssthen for(i=0; i<num; i++) {
425933707f3Ssthen memmove(p, d->rr_data[i], d->rr_len[i]);
426933707f3Ssthen p += d->rr_len[i];
427933707f3Ssthen }
428933707f3Ssthen packed_rrset_ptr_fixup(ad);
429933707f3Ssthen
430933707f3Ssthen ak->entry.data = ad;
431933707f3Ssthen
432933707f3Ssthen ref.key = ak;
433933707f3Ssthen ref.id = ak->id;
434933707f3Ssthen (void)rrset_cache_update(worker->env.rrset_cache, &ref,
4358b7325afSsthen worker->alloc, *worker->env.now);
4368b7325afSsthen
437933707f3Ssthen return 1;
438933707f3Ssthen }
439933707f3Ssthen
440933707f3Ssthen /** load an rrset entry */
441933707f3Ssthen static int
load_rrset(RES * ssl,sldns_buffer * buf,struct worker * worker)44220237c55Ssthen load_rrset(RES* ssl, sldns_buffer* buf, struct worker* worker)
443933707f3Ssthen {
4445d76a658Ssthen char* s = (char*)sldns_buffer_begin(buf);
445933707f3Ssthen struct regional* region = worker->scratchpad;
446933707f3Ssthen struct ub_packed_rrset_key* rk;
447933707f3Ssthen struct packed_rrset_data* d;
448229e174cSsthen unsigned int rr_count, rrsig_count, trust, security;
449229e174cSsthen long long ttl;
450933707f3Ssthen unsigned int i;
451933707f3Ssthen int go_on = 1;
452933707f3Ssthen regional_free_all(region);
453933707f3Ssthen
454933707f3Ssthen rk = (struct ub_packed_rrset_key*)regional_alloc_zero(region,
455933707f3Ssthen sizeof(*rk));
456933707f3Ssthen d = (struct packed_rrset_data*)regional_alloc_zero(region, sizeof(*d));
457933707f3Ssthen if(!rk || !d) {
458933707f3Ssthen log_warn("error out of memory");
459933707f3Ssthen return 0;
460933707f3Ssthen }
461933707f3Ssthen
462933707f3Ssthen if(strncmp(s, ";rrset", 6) != 0) {
463933707f3Ssthen log_warn("error expected ';rrset' but got %s", s);
464933707f3Ssthen return 0;
465933707f3Ssthen }
466933707f3Ssthen s += 6;
467933707f3Ssthen if(strncmp(s, " nsec_apex", 10) == 0) {
468933707f3Ssthen s += 10;
469933707f3Ssthen rk->rk.flags |= PACKED_RRSET_NSEC_AT_APEX;
470933707f3Ssthen }
4715d76a658Ssthen if(sscanf(s, " " ARG_LL "d %u %u %u %u", &ttl, &rr_count, &rrsig_count,
472933707f3Ssthen &trust, &security) != 5) {
473933707f3Ssthen log_warn("error bad rrset spec %s", s);
474933707f3Ssthen return 0;
475933707f3Ssthen }
476933707f3Ssthen if(rr_count == 0 && rrsig_count == 0) {
477933707f3Ssthen log_warn("bad rrset without contents");
478933707f3Ssthen return 0;
479933707f3Ssthen }
480a58bff56Ssthen if(rr_count > RR_COUNT_MAX || rrsig_count > RR_COUNT_MAX) {
481a58bff56Ssthen log_warn("bad rrset with too many rrs");
482a58bff56Ssthen return 0;
483a58bff56Ssthen }
484933707f3Ssthen d->count = (size_t)rr_count;
485933707f3Ssthen d->rrsig_count = (size_t)rrsig_count;
486933707f3Ssthen d->security = (enum sec_status)security;
487933707f3Ssthen d->trust = (enum rrset_trust)trust;
488229e174cSsthen d->ttl = (time_t)ttl + *worker->env.now;
489933707f3Ssthen
490933707f3Ssthen d->rr_len = regional_alloc_zero(region,
491933707f3Ssthen sizeof(size_t)*(d->count+d->rrsig_count));
492933707f3Ssthen d->rr_ttl = regional_alloc_zero(region,
493229e174cSsthen sizeof(time_t)*(d->count+d->rrsig_count));
494933707f3Ssthen d->rr_data = regional_alloc_zero(region,
495933707f3Ssthen sizeof(uint8_t*)*(d->count+d->rrsig_count));
496933707f3Ssthen if(!d->rr_len || !d->rr_ttl || !d->rr_data) {
497933707f3Ssthen log_warn("error out of memory");
498933707f3Ssthen return 0;
499933707f3Ssthen }
500933707f3Ssthen
501933707f3Ssthen /* read the rr's themselves */
502933707f3Ssthen for(i=0; i<rr_count; i++) {
503933707f3Ssthen if(!load_rr(ssl, buf, region, rk, d, i, 0,
504933707f3Ssthen &go_on, *worker->env.now)) {
505933707f3Ssthen log_warn("could not read rr %u", i);
506933707f3Ssthen return 0;
507933707f3Ssthen }
508933707f3Ssthen }
509933707f3Ssthen for(i=0; i<rrsig_count; i++) {
510933707f3Ssthen if(!load_rr(ssl, buf, region, rk, d, i+rr_count, 1,
511933707f3Ssthen &go_on, *worker->env.now)) {
512933707f3Ssthen log_warn("could not read rrsig %u", i);
513933707f3Ssthen return 0;
514933707f3Ssthen }
515933707f3Ssthen }
516933707f3Ssthen if(!go_on) {
517933707f3Ssthen /* skip this entry */
518933707f3Ssthen return 1;
519933707f3Ssthen }
520933707f3Ssthen
521933707f3Ssthen return move_into_cache(rk, d, worker);
522933707f3Ssthen }
523933707f3Ssthen
524933707f3Ssthen /** load rrset cache */
525933707f3Ssthen static int
load_rrset_cache(RES * ssl,struct worker * worker)52620237c55Ssthen load_rrset_cache(RES* ssl, struct worker* worker)
527933707f3Ssthen {
5285d76a658Ssthen sldns_buffer* buf = worker->env.scratch_buffer;
529933707f3Ssthen if(!read_fixed(ssl, buf, "START_RRSET_CACHE")) return 0;
530933707f3Ssthen while(ssl_read_buf(ssl, buf) &&
5315d76a658Ssthen strcmp((char*)sldns_buffer_begin(buf), "END_RRSET_CACHE")!=0) {
532933707f3Ssthen if(!load_rrset(ssl, buf, worker))
533933707f3Ssthen return 0;
534933707f3Ssthen }
535933707f3Ssthen return 1;
536933707f3Ssthen }
537933707f3Ssthen
538933707f3Ssthen /** read qinfo from next three words */
539933707f3Ssthen static char*
load_qinfo(char * str,struct query_info * qinfo,struct regional * region)5405d76a658Ssthen load_qinfo(char* str, struct query_info* qinfo, struct regional* region)
541933707f3Ssthen {
542933707f3Ssthen /* s is part of the buf */
543933707f3Ssthen char* s = str;
5445d76a658Ssthen uint8_t rr[LDNS_RR_BUF_SIZE];
5455d76a658Ssthen size_t rr_len = sizeof(rr), dname_len = 0;
5465d76a658Ssthen int status;
547933707f3Ssthen
548933707f3Ssthen /* skip three words */
549933707f3Ssthen s = strchr(str, ' ');
550933707f3Ssthen if(s) s = strchr(s+1, ' ');
551933707f3Ssthen if(s) s = strchr(s+1, ' ');
552933707f3Ssthen if(!s) {
553933707f3Ssthen log_warn("error line too short, %s", str);
554933707f3Ssthen return NULL;
555933707f3Ssthen }
556933707f3Ssthen s[0] = 0;
557933707f3Ssthen s++;
558933707f3Ssthen
559933707f3Ssthen /* parse them */
5605d76a658Ssthen status = sldns_str2wire_rr_question_buf(str, rr, &rr_len, &dname_len,
5615d76a658Ssthen NULL, 0, NULL, 0);
5625d76a658Ssthen if(status != 0) {
563933707f3Ssthen log_warn("error cannot parse: %s %s",
5645d76a658Ssthen sldns_get_errorstr_parse(status), str);
565933707f3Ssthen return NULL;
566933707f3Ssthen }
5675d76a658Ssthen qinfo->qtype = sldns_wirerr_get_type(rr, rr_len, dname_len);
5685d76a658Ssthen qinfo->qclass = sldns_wirerr_get_class(rr, rr_len, dname_len);
5695d76a658Ssthen qinfo->qname_len = dname_len;
5705d76a658Ssthen qinfo->qname = (uint8_t*)regional_alloc_init(region, rr, dname_len);
57177079be7Ssthen qinfo->local_alias = NULL;
572933707f3Ssthen if(!qinfo->qname) {
573933707f3Ssthen log_warn("error out of memory");
574933707f3Ssthen return NULL;
575933707f3Ssthen }
576933707f3Ssthen
577933707f3Ssthen return s;
578933707f3Ssthen }
579933707f3Ssthen
580933707f3Ssthen /** load a msg rrset reference */
581933707f3Ssthen static int
load_ref(RES * ssl,sldns_buffer * buf,struct worker * worker,struct regional * region,struct ub_packed_rrset_key ** rrset,int * go_on)58220237c55Ssthen load_ref(RES* ssl, sldns_buffer* buf, struct worker* worker,
583933707f3Ssthen struct regional *region, struct ub_packed_rrset_key** rrset,
584933707f3Ssthen int* go_on)
585933707f3Ssthen {
5865d76a658Ssthen char* s = (char*)sldns_buffer_begin(buf);
587933707f3Ssthen struct query_info qinfo;
588933707f3Ssthen unsigned int flags;
589933707f3Ssthen struct ub_packed_rrset_key* k;
590933707f3Ssthen
591933707f3Ssthen /* read line */
592933707f3Ssthen if(!ssl_read_buf(ssl, buf))
593933707f3Ssthen return 0;
594933707f3Ssthen if(strncmp(s, "BADREF", 6) == 0) {
595933707f3Ssthen *go_on = 0; /* its bad, skip it and skip message */
596933707f3Ssthen return 1;
597933707f3Ssthen }
598933707f3Ssthen
5995d76a658Ssthen s = load_qinfo(s, &qinfo, region);
600933707f3Ssthen if(!s) {
601933707f3Ssthen return 0;
602933707f3Ssthen }
603933707f3Ssthen if(sscanf(s, " %u", &flags) != 1) {
604933707f3Ssthen log_warn("error cannot parse flags: %s", s);
605933707f3Ssthen return 0;
606933707f3Ssthen }
607933707f3Ssthen
608933707f3Ssthen /* lookup in cache */
609933707f3Ssthen k = rrset_cache_lookup(worker->env.rrset_cache, qinfo.qname,
610933707f3Ssthen qinfo.qname_len, qinfo.qtype, qinfo.qclass,
611933707f3Ssthen (uint32_t)flags, *worker->env.now, 0);
612933707f3Ssthen if(!k) {
613933707f3Ssthen /* not found or expired */
614933707f3Ssthen *go_on = 0;
615933707f3Ssthen return 1;
616933707f3Ssthen }
617933707f3Ssthen
618933707f3Ssthen /* store in result */
619933707f3Ssthen *rrset = packed_rrset_copy_region(k, region, *worker->env.now);
620933707f3Ssthen lock_rw_unlock(&k->entry.lock);
621933707f3Ssthen
622933707f3Ssthen return (*rrset != NULL);
623933707f3Ssthen }
624933707f3Ssthen
625933707f3Ssthen /** load a msg entry */
626933707f3Ssthen static int
load_msg(RES * ssl,sldns_buffer * buf,struct worker * worker)62720237c55Ssthen load_msg(RES* ssl, sldns_buffer* buf, struct worker* worker)
628933707f3Ssthen {
629933707f3Ssthen struct regional* region = worker->scratchpad;
630933707f3Ssthen struct query_info qinf;
631933707f3Ssthen struct reply_info rep;
6325d76a658Ssthen char* s = (char*)sldns_buffer_begin(buf);
633229e174cSsthen unsigned int flags, qdcount, security, an, ns, ar;
634229e174cSsthen long long ttl;
635933707f3Ssthen size_t i;
636933707f3Ssthen int go_on = 1;
6378b7325afSsthen int ede;
6388b7325afSsthen int consumed = 0;
6398b7325afSsthen char* ede_str = NULL;
640933707f3Ssthen
641933707f3Ssthen regional_free_all(region);
642933707f3Ssthen
643933707f3Ssthen if(strncmp(s, "msg ", 4) != 0) {
644933707f3Ssthen log_warn("error expected msg but got %s", s);
645933707f3Ssthen return 0;
646933707f3Ssthen }
647933707f3Ssthen s += 4;
6485d76a658Ssthen s = load_qinfo(s, &qinf, region);
649933707f3Ssthen if(!s) {
650933707f3Ssthen return 0;
651933707f3Ssthen }
652933707f3Ssthen
653933707f3Ssthen /* read remainder of line */
6548b7325afSsthen /* note the last space before any possible EDE text */
6558b7325afSsthen if(sscanf(s, " %u %u " ARG_LL "d %u %u %u %u %d %n", &flags, &qdcount, &ttl,
6568b7325afSsthen &security, &an, &ns, &ar, &ede, &consumed) != 8) {
657933707f3Ssthen log_warn("error cannot parse numbers: %s", s);
658933707f3Ssthen return 0;
659933707f3Ssthen }
6608b7325afSsthen /* there may be EDE text after the numbers */
6618b7325afSsthen if(consumed > 0 && (size_t)consumed < strlen(s))
6628b7325afSsthen ede_str = s + consumed;
6638b7325afSsthen memset(&rep, 0, sizeof(rep));
664933707f3Ssthen rep.flags = (uint16_t)flags;
665933707f3Ssthen rep.qdcount = (uint16_t)qdcount;
666229e174cSsthen rep.ttl = (time_t)ttl;
667933707f3Ssthen rep.prefetch_ttl = PREFETCH_TTL_CALC(rep.ttl);
6682308e98cSsthen rep.serve_expired_ttl = rep.ttl + SERVE_EXPIRED_TTL;
669933707f3Ssthen rep.security = (enum sec_status)security;
670a58bff56Ssthen if(an > RR_COUNT_MAX || ns > RR_COUNT_MAX || ar > RR_COUNT_MAX) {
671a58bff56Ssthen log_warn("error too many rrsets");
672a58bff56Ssthen return 0; /* protect against integer overflow in alloc */
673a58bff56Ssthen }
674933707f3Ssthen rep.an_numrrsets = (size_t)an;
675933707f3Ssthen rep.ns_numrrsets = (size_t)ns;
676933707f3Ssthen rep.ar_numrrsets = (size_t)ar;
677933707f3Ssthen rep.rrset_count = (size_t)an+(size_t)ns+(size_t)ar;
6788b7325afSsthen rep.reason_bogus = (sldns_ede_code)ede;
6798b7325afSsthen rep.reason_bogus_str = ede_str?(char*)regional_strdup(region, ede_str):NULL;
680933707f3Ssthen rep.rrsets = (struct ub_packed_rrset_key**)regional_alloc_zero(
681933707f3Ssthen region, sizeof(struct ub_packed_rrset_key*)*rep.rrset_count);
682933707f3Ssthen
683933707f3Ssthen /* fill repinfo with references */
684933707f3Ssthen for(i=0; i<rep.rrset_count; i++) {
685933707f3Ssthen if(!load_ref(ssl, buf, worker, region, &rep.rrsets[i],
686933707f3Ssthen &go_on)) {
687933707f3Ssthen return 0;
688933707f3Ssthen }
689933707f3Ssthen }
690933707f3Ssthen
691933707f3Ssthen if(!go_on)
692933707f3Ssthen return 1; /* skip this one, not all references satisfied */
693933707f3Ssthen
694d1e2768aSsthen if(!dns_cache_store(&worker->env, &qinf, &rep, 0, 0, 0, NULL, flags,
695d1e2768aSsthen *worker->env.now)) {
696933707f3Ssthen log_warn("error out of memory");
697933707f3Ssthen return 0;
698933707f3Ssthen }
699933707f3Ssthen return 1;
700933707f3Ssthen }
701933707f3Ssthen
702933707f3Ssthen /** load msg cache */
703933707f3Ssthen static int
load_msg_cache(RES * ssl,struct worker * worker)70420237c55Ssthen load_msg_cache(RES* ssl, struct worker* worker)
705933707f3Ssthen {
7065d76a658Ssthen sldns_buffer* buf = worker->env.scratch_buffer;
707933707f3Ssthen if(!read_fixed(ssl, buf, "START_MSG_CACHE")) return 0;
708933707f3Ssthen while(ssl_read_buf(ssl, buf) &&
7095d76a658Ssthen strcmp((char*)sldns_buffer_begin(buf), "END_MSG_CACHE")!=0) {
710933707f3Ssthen if(!load_msg(ssl, buf, worker))
711933707f3Ssthen return 0;
712933707f3Ssthen }
713933707f3Ssthen return 1;
714933707f3Ssthen }
715933707f3Ssthen
716933707f3Ssthen int
load_cache(RES * ssl,struct worker * worker)71720237c55Ssthen load_cache(RES* ssl, struct worker* worker)
718933707f3Ssthen {
719933707f3Ssthen if(!load_rrset_cache(ssl, worker))
720933707f3Ssthen return 0;
721933707f3Ssthen if(!load_msg_cache(ssl, worker))
722933707f3Ssthen return 0;
723933707f3Ssthen return read_fixed(ssl, worker->env.scratch_buffer, "EOF");
724933707f3Ssthen }
725933707f3Ssthen
726933707f3Ssthen /** print details on a delegation point */
727933707f3Ssthen static void
print_dp_details(RES * ssl,struct worker * worker,struct delegpt * dp)72820237c55Ssthen print_dp_details(RES* ssl, struct worker* worker, struct delegpt* dp)
729933707f3Ssthen {
730933707f3Ssthen char buf[257];
731933707f3Ssthen struct delegpt_addr* a;
732229e174cSsthen int lame, dlame, rlame, rto, edns_vs, to, delay,
733d8d14d0cSsthen tA = 0, tAAAA = 0, tother = 0;
734229e174cSsthen long long entry_ttl;
735933707f3Ssthen struct rtt_info ri;
736933707f3Ssthen uint8_t edns_lame_known;
737933707f3Ssthen for(a = dp->target_list; a; a = a->next_target) {
738933707f3Ssthen addr_to_str(&a->addr, a->addrlen, buf, sizeof(buf));
739933707f3Ssthen if(!ssl_printf(ssl, "%-16s\t", buf))
740933707f3Ssthen return;
741933707f3Ssthen if(a->bogus) {
742933707f3Ssthen if(!ssl_printf(ssl, "Address is BOGUS. "))
743933707f3Ssthen return;
744933707f3Ssthen }
745933707f3Ssthen /* lookup in infra cache */
746933707f3Ssthen delay=0;
747933707f3Ssthen entry_ttl = infra_get_host_rto(worker->env.infra_cache,
748933707f3Ssthen &a->addr, a->addrlen, dp->name, dp->namelen,
749d8d14d0cSsthen &ri, &delay, *worker->env.now, &tA, &tAAAA, &tother);
750933707f3Ssthen if(entry_ttl == -2 && ri.rto >= USEFUL_SERVER_TOP_TIMEOUT) {
751d8d14d0cSsthen if(!ssl_printf(ssl, "expired, rto %d msec, tA %d "
752d8d14d0cSsthen "tAAAA %d tother %d.\n", ri.rto, tA, tAAAA,
753d8d14d0cSsthen tother))
754933707f3Ssthen return;
755933707f3Ssthen continue;
756933707f3Ssthen }
757933707f3Ssthen if(entry_ttl == -1 || entry_ttl == -2) {
758933707f3Ssthen if(!ssl_printf(ssl, "not in infra cache.\n"))
759933707f3Ssthen return;
760933707f3Ssthen continue; /* skip stuff not in infra cache */
761933707f3Ssthen }
762933707f3Ssthen
763933707f3Ssthen /* uses type_A because most often looked up, but other
764933707f3Ssthen * lameness won't be reported then */
765933707f3Ssthen if(!infra_get_lame_rtt(worker->env.infra_cache,
766933707f3Ssthen &a->addr, a->addrlen, dp->name, dp->namelen,
767933707f3Ssthen LDNS_RR_TYPE_A, &lame, &dlame, &rlame, &rto,
768933707f3Ssthen *worker->env.now)) {
769933707f3Ssthen if(!ssl_printf(ssl, "not in infra cache.\n"))
770933707f3Ssthen return;
771933707f3Ssthen continue; /* skip stuff not in infra cache */
772933707f3Ssthen }
7735d76a658Ssthen if(!ssl_printf(ssl, "%s%s%s%srto %d msec, ttl " ARG_LL "d, "
7745d76a658Ssthen "ping %d var %d rtt %d, tA %d, tAAAA %d, tother %d",
775933707f3Ssthen lame?"LAME ":"", dlame?"NoDNSSEC ":"",
776933707f3Ssthen a->lame?"AddrWasParentSide ":"",
777933707f3Ssthen rlame?"NoAuthButRecursive ":"", rto, entry_ttl,
778d8d14d0cSsthen ri.srtt, ri.rttvar, rtt_notimeout(&ri),
779d8d14d0cSsthen tA, tAAAA, tother))
780933707f3Ssthen return;
781933707f3Ssthen if(delay)
782933707f3Ssthen if(!ssl_printf(ssl, ", probedelay %d", delay))
783933707f3Ssthen return;
784933707f3Ssthen if(infra_host(worker->env.infra_cache, &a->addr, a->addrlen,
785933707f3Ssthen dp->name, dp->namelen, *worker->env.now, &edns_vs,
786933707f3Ssthen &edns_lame_known, &to)) {
787933707f3Ssthen if(edns_vs == -1) {
788933707f3Ssthen if(!ssl_printf(ssl, ", noEDNS%s.",
789933707f3Ssthen edns_lame_known?" probed":" assumed"))
790933707f3Ssthen return;
791933707f3Ssthen } else {
792933707f3Ssthen if(!ssl_printf(ssl, ", EDNS %d%s.", edns_vs,
793933707f3Ssthen edns_lame_known?" probed":" assumed"))
794933707f3Ssthen return;
795933707f3Ssthen }
796933707f3Ssthen }
797933707f3Ssthen if(!ssl_printf(ssl, "\n"))
798933707f3Ssthen return;
799933707f3Ssthen }
800933707f3Ssthen }
801933707f3Ssthen
802933707f3Ssthen /** print main dp info */
803933707f3Ssthen static void
print_dp_main(RES * ssl,struct delegpt * dp,struct dns_msg * msg)80420237c55Ssthen print_dp_main(RES* ssl, struct delegpt* dp, struct dns_msg* msg)
805933707f3Ssthen {
806933707f3Ssthen size_t i, n_ns, n_miss, n_addr, n_res, n_avail;
807933707f3Ssthen
808933707f3Ssthen /* print the dp */
809933707f3Ssthen if(msg)
810933707f3Ssthen for(i=0; i<msg->rep->rrset_count; i++) {
811933707f3Ssthen struct ub_packed_rrset_key* k = msg->rep->rrsets[i];
812933707f3Ssthen struct packed_rrset_data* d =
813933707f3Ssthen (struct packed_rrset_data*)k->entry.data;
814933707f3Ssthen if(d->security == sec_status_bogus) {
815933707f3Ssthen if(!ssl_printf(ssl, "Address is BOGUS:\n"))
816933707f3Ssthen return;
817933707f3Ssthen }
818933707f3Ssthen if(!dump_rrset(ssl, k, d, 0))
819933707f3Ssthen return;
820933707f3Ssthen }
821933707f3Ssthen delegpt_count_ns(dp, &n_ns, &n_miss);
822933707f3Ssthen delegpt_count_addr(dp, &n_addr, &n_res, &n_avail);
823933707f3Ssthen /* since dp has not been used by iterator, all are available*/
824933707f3Ssthen if(!ssl_printf(ssl, "Delegation with %d names, of which %d "
825933707f3Ssthen "can be examined to query further addresses.\n"
826933707f3Ssthen "%sIt provides %d IP addresses.\n",
827933707f3Ssthen (int)n_ns, (int)n_miss, (dp->bogus?"It is BOGUS. ":""),
828933707f3Ssthen (int)n_addr))
829933707f3Ssthen return;
830933707f3Ssthen }
831933707f3Ssthen
print_deleg_lookup(RES * ssl,struct worker * worker,uint8_t * nm,size_t nmlen,int ATTR_UNUSED (nmlabs))83220237c55Ssthen int print_deleg_lookup(RES* ssl, struct worker* worker, uint8_t* nm,
833933707f3Ssthen size_t nmlen, int ATTR_UNUSED(nmlabs))
834933707f3Ssthen {
835933707f3Ssthen /* deep links into the iterator module */
836933707f3Ssthen struct delegpt* dp;
837933707f3Ssthen struct dns_msg* msg;
838933707f3Ssthen struct regional* region = worker->scratchpad;
839933707f3Ssthen char b[260];
840933707f3Ssthen struct query_info qinfo;
841933707f3Ssthen struct iter_hints_stub* stub;
842*2bdc0ed1Ssthen int nolock = 0;
843933707f3Ssthen regional_free_all(region);
844933707f3Ssthen qinfo.qname = nm;
845933707f3Ssthen qinfo.qname_len = nmlen;
846933707f3Ssthen qinfo.qtype = LDNS_RR_TYPE_A;
847933707f3Ssthen qinfo.qclass = LDNS_RR_CLASS_IN;
84877079be7Ssthen qinfo.local_alias = NULL;
849933707f3Ssthen
850933707f3Ssthen dname_str(nm, b);
851933707f3Ssthen if(!ssl_printf(ssl, "The following name servers are used for lookup "
852933707f3Ssthen "of %s\n", b))
853933707f3Ssthen return 0;
854933707f3Ssthen
855*2bdc0ed1Ssthen dp = forwards_lookup(worker->env.fwds, nm, qinfo.qclass, nolock);
856933707f3Ssthen if(dp) {
857*2bdc0ed1Ssthen if(!ssl_printf(ssl, "forwarding request:\n")) {
858*2bdc0ed1Ssthen lock_rw_unlock(&worker->env.fwds->lock);
859933707f3Ssthen return 0;
860*2bdc0ed1Ssthen }
861933707f3Ssthen print_dp_main(ssl, dp, NULL);
862933707f3Ssthen print_dp_details(ssl, worker, dp);
863*2bdc0ed1Ssthen lock_rw_unlock(&worker->env.fwds->lock);
864933707f3Ssthen return 1;
865933707f3Ssthen }
866933707f3Ssthen
867933707f3Ssthen while(1) {
868933707f3Ssthen dp = dns_cache_find_delegation(&worker->env, nm, nmlen,
869933707f3Ssthen qinfo.qtype, qinfo.qclass, region, &msg,
870d1e2768aSsthen *worker->env.now, 0, NULL, 0);
871933707f3Ssthen if(!dp) {
872933707f3Ssthen return ssl_printf(ssl, "no delegation from "
873933707f3Ssthen "cache; goes to configured roots\n");
874933707f3Ssthen }
875933707f3Ssthen /* go up? */
8760bdb4f62Ssthen if(iter_dp_is_useless(&qinfo, BIT_RD, dp,
8770bdb4f62Ssthen (worker->env.cfg->do_ip4 && worker->back->num_ip4 != 0),
8788b7325afSsthen (worker->env.cfg->do_ip6 && worker->back->num_ip6 != 0),
8798b7325afSsthen worker->env.cfg->do_nat64)) {
880933707f3Ssthen print_dp_main(ssl, dp, msg);
881933707f3Ssthen print_dp_details(ssl, worker, dp);
882933707f3Ssthen if(!ssl_printf(ssl, "cache delegation was "
883933707f3Ssthen "useless (no IP addresses)\n"))
884933707f3Ssthen return 0;
885933707f3Ssthen if(dname_is_root(nm)) {
886933707f3Ssthen /* goes to root config */
887933707f3Ssthen return ssl_printf(ssl, "no delegation from "
888933707f3Ssthen "cache; goes to configured roots\n");
889933707f3Ssthen } else {
890933707f3Ssthen /* useless, goes up */
891933707f3Ssthen nm = dp->name;
892933707f3Ssthen nmlen = dp->namelen;
893933707f3Ssthen dname_remove_label(&nm, &nmlen);
894933707f3Ssthen dname_str(nm, b);
895933707f3Ssthen if(!ssl_printf(ssl, "going up, lookup %s\n", b))
896933707f3Ssthen return 0;
897933707f3Ssthen continue;
898933707f3Ssthen }
899933707f3Ssthen }
900d8d14d0cSsthen stub = hints_lookup_stub(worker->env.hints, nm, qinfo.qclass,
901*2bdc0ed1Ssthen dp, nolock);
902933707f3Ssthen if(stub) {
903933707f3Ssthen if(stub->noprime) {
904933707f3Ssthen if(!ssl_printf(ssl, "The noprime stub servers "
905*2bdc0ed1Ssthen "are used:\n")) {
906*2bdc0ed1Ssthen lock_rw_unlock(&worker->env.hints->lock);
907933707f3Ssthen return 0;
908*2bdc0ed1Ssthen }
909933707f3Ssthen } else {
910933707f3Ssthen if(!ssl_printf(ssl, "The stub is primed "
911*2bdc0ed1Ssthen "with servers:\n")) {
912*2bdc0ed1Ssthen lock_rw_unlock(&worker->env.hints->lock);
913933707f3Ssthen return 0;
914933707f3Ssthen }
915*2bdc0ed1Ssthen }
916933707f3Ssthen print_dp_main(ssl, stub->dp, NULL);
917933707f3Ssthen print_dp_details(ssl, worker, stub->dp);
918*2bdc0ed1Ssthen lock_rw_unlock(&worker->env.hints->lock);
919933707f3Ssthen } else {
920933707f3Ssthen print_dp_main(ssl, dp, msg);
921933707f3Ssthen print_dp_details(ssl, worker, dp);
922933707f3Ssthen }
923933707f3Ssthen break;
924933707f3Ssthen }
925933707f3Ssthen
926933707f3Ssthen return 1;
927933707f3Ssthen }
928