xref: /freebsd/contrib/unbound/validator/val_nsec.c (revision b7579f77d18196a58ff700756c84dc9a302a7f67)
1*b7579f77SDag-Erling Smørgrav /*
2*b7579f77SDag-Erling Smørgrav  * validator/val_nsec.c - validator NSEC denial of existance functions.
3*b7579f77SDag-Erling Smørgrav  *
4*b7579f77SDag-Erling Smørgrav  * Copyright (c) 2007, NLnet Labs. All rights reserved.
5*b7579f77SDag-Erling Smørgrav  *
6*b7579f77SDag-Erling Smørgrav  * This software is open source.
7*b7579f77SDag-Erling Smørgrav  *
8*b7579f77SDag-Erling Smørgrav  * Redistribution and use in source and binary forms, with or without
9*b7579f77SDag-Erling Smørgrav  * modification, are permitted provided that the following conditions
10*b7579f77SDag-Erling Smørgrav  * are met:
11*b7579f77SDag-Erling Smørgrav  *
12*b7579f77SDag-Erling Smørgrav  * Redistributions of source code must retain the above copyright notice,
13*b7579f77SDag-Erling Smørgrav  * this list of conditions and the following disclaimer.
14*b7579f77SDag-Erling Smørgrav  *
15*b7579f77SDag-Erling Smørgrav  * Redistributions in binary form must reproduce the above copyright notice,
16*b7579f77SDag-Erling Smørgrav  * this list of conditions and the following disclaimer in the documentation
17*b7579f77SDag-Erling Smørgrav  * and/or other materials provided with the distribution.
18*b7579f77SDag-Erling Smørgrav  *
19*b7579f77SDag-Erling Smørgrav  * Neither the name of the NLNET LABS nor the names of its contributors may
20*b7579f77SDag-Erling Smørgrav  * be used to endorse or promote products derived from this software without
21*b7579f77SDag-Erling Smørgrav  * specific prior written permission.
22*b7579f77SDag-Erling Smørgrav  *
23*b7579f77SDag-Erling Smørgrav  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24*b7579f77SDag-Erling Smørgrav  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
25*b7579f77SDag-Erling Smørgrav  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
26*b7579f77SDag-Erling Smørgrav  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE
27*b7579f77SDag-Erling Smørgrav  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
28*b7579f77SDag-Erling Smørgrav  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
29*b7579f77SDag-Erling Smørgrav  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
30*b7579f77SDag-Erling Smørgrav  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
31*b7579f77SDag-Erling Smørgrav  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
32*b7579f77SDag-Erling Smørgrav  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
33*b7579f77SDag-Erling Smørgrav  * POSSIBILITY OF SUCH DAMAGE.
34*b7579f77SDag-Erling Smørgrav  */
35*b7579f77SDag-Erling Smørgrav 
36*b7579f77SDag-Erling Smørgrav /**
37*b7579f77SDag-Erling Smørgrav  * \file
38*b7579f77SDag-Erling Smørgrav  *
39*b7579f77SDag-Erling Smørgrav  * This file contains helper functions for the validator module.
40*b7579f77SDag-Erling Smørgrav  * The functions help with NSEC checking, the different NSEC proofs
41*b7579f77SDag-Erling Smørgrav  * for denial of existance, and proofs for presence of types.
42*b7579f77SDag-Erling Smørgrav  */
43*b7579f77SDag-Erling Smørgrav #include "config.h"
44*b7579f77SDag-Erling Smørgrav #include <ldns/packet.h>
45*b7579f77SDag-Erling Smørgrav #include "validator/val_nsec.h"
46*b7579f77SDag-Erling Smørgrav #include "validator/val_utils.h"
47*b7579f77SDag-Erling Smørgrav #include "util/data/msgreply.h"
48*b7579f77SDag-Erling Smørgrav #include "util/data/dname.h"
49*b7579f77SDag-Erling Smørgrav #include "util/net_help.h"
50*b7579f77SDag-Erling Smørgrav #include "util/module.h"
51*b7579f77SDag-Erling Smørgrav #include "services/cache/rrset.h"
52*b7579f77SDag-Erling Smørgrav 
53*b7579f77SDag-Erling Smørgrav /** get ttl of rrset */
54*b7579f77SDag-Erling Smørgrav static uint32_t
55*b7579f77SDag-Erling Smørgrav rrset_get_ttl(struct ub_packed_rrset_key* k)
56*b7579f77SDag-Erling Smørgrav {
57*b7579f77SDag-Erling Smørgrav 	struct packed_rrset_data* d = (struct packed_rrset_data*)k->entry.data;
58*b7579f77SDag-Erling Smørgrav 	return d->ttl;
59*b7579f77SDag-Erling Smørgrav }
60*b7579f77SDag-Erling Smørgrav 
61*b7579f77SDag-Erling Smørgrav int
62*b7579f77SDag-Erling Smørgrav nsecbitmap_has_type_rdata(uint8_t* bitmap, size_t len, uint16_t type)
63*b7579f77SDag-Erling Smørgrav {
64*b7579f77SDag-Erling Smørgrav 	/* Check type present in NSEC typemap with bitmap arg */
65*b7579f77SDag-Erling Smørgrav 	/* bitmasks for determining type-lowerbits presence */
66*b7579f77SDag-Erling Smørgrav 	uint8_t masks[8] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01};
67*b7579f77SDag-Erling Smørgrav 	uint8_t type_window = type>>8;
68*b7579f77SDag-Erling Smørgrav 	uint8_t type_low = type&0xff;
69*b7579f77SDag-Erling Smørgrav 	uint8_t win, winlen;
70*b7579f77SDag-Erling Smørgrav 	/* read each of the type bitmap windows and see if the searched
71*b7579f77SDag-Erling Smørgrav 	 * type is amongst it */
72*b7579f77SDag-Erling Smørgrav 	while(len > 0) {
73*b7579f77SDag-Erling Smørgrav 		if(len < 3) /* bad window, at least window# winlen bitmap */
74*b7579f77SDag-Erling Smørgrav 			return 0;
75*b7579f77SDag-Erling Smørgrav 		win = *bitmap++;
76*b7579f77SDag-Erling Smørgrav 		winlen = *bitmap++;
77*b7579f77SDag-Erling Smørgrav 		len -= 2;
78*b7579f77SDag-Erling Smørgrav 		if(len < winlen || winlen < 1 || winlen > 32)
79*b7579f77SDag-Erling Smørgrav 			return 0;	/* bad window length */
80*b7579f77SDag-Erling Smørgrav 		if(win == type_window) {
81*b7579f77SDag-Erling Smørgrav 			/* search window bitmap for the correct byte */
82*b7579f77SDag-Erling Smørgrav 			/* mybyte is 0 if we need the first byte */
83*b7579f77SDag-Erling Smørgrav 			size_t mybyte = type_low>>3;
84*b7579f77SDag-Erling Smørgrav 			if(winlen <= mybyte)
85*b7579f77SDag-Erling Smørgrav 				return 0; /* window too short */
86*b7579f77SDag-Erling Smørgrav 			return (int)(bitmap[mybyte] & masks[type_low&0x7]);
87*b7579f77SDag-Erling Smørgrav 		} else {
88*b7579f77SDag-Erling Smørgrav 			/* not the window we are looking for */
89*b7579f77SDag-Erling Smørgrav 			bitmap += winlen;
90*b7579f77SDag-Erling Smørgrav 			len -= winlen;
91*b7579f77SDag-Erling Smørgrav 		}
92*b7579f77SDag-Erling Smørgrav 	}
93*b7579f77SDag-Erling Smørgrav 	/* end of bitmap reached, no type found */
94*b7579f77SDag-Erling Smørgrav 	return 0;
95*b7579f77SDag-Erling Smørgrav }
96*b7579f77SDag-Erling Smørgrav 
97*b7579f77SDag-Erling Smørgrav int
98*b7579f77SDag-Erling Smørgrav nsec_has_type(struct ub_packed_rrset_key* nsec, uint16_t type)
99*b7579f77SDag-Erling Smørgrav {
100*b7579f77SDag-Erling Smørgrav 	struct packed_rrset_data* d = (struct packed_rrset_data*)nsec->
101*b7579f77SDag-Erling Smørgrav 		entry.data;
102*b7579f77SDag-Erling Smørgrav 	size_t len;
103*b7579f77SDag-Erling Smørgrav 	if(!d || d->count == 0 || d->rr_len[0] < 2+1)
104*b7579f77SDag-Erling Smørgrav 		return 0;
105*b7579f77SDag-Erling Smørgrav 	len = dname_valid(d->rr_data[0]+2, d->rr_len[0]-2);
106*b7579f77SDag-Erling Smørgrav 	if(!len)
107*b7579f77SDag-Erling Smørgrav 		return 0;
108*b7579f77SDag-Erling Smørgrav 	return nsecbitmap_has_type_rdata(d->rr_data[0]+2+len,
109*b7579f77SDag-Erling Smørgrav 		d->rr_len[0]-2-len, type);
110*b7579f77SDag-Erling Smørgrav }
111*b7579f77SDag-Erling Smørgrav 
112*b7579f77SDag-Erling Smørgrav /**
113*b7579f77SDag-Erling Smørgrav  * Get next owner name from nsec record
114*b7579f77SDag-Erling Smørgrav  * @param nsec: the nsec RRset.
115*b7579f77SDag-Erling Smørgrav  *	If there are multiple RRs, then this will only return one of them.
116*b7579f77SDag-Erling Smørgrav  * @param nm: the next name is returned.
117*b7579f77SDag-Erling Smørgrav  * @param ln: length of nm is returned.
118*b7579f77SDag-Erling Smørgrav  * @return false on a bad NSEC RR (too short, malformed dname).
119*b7579f77SDag-Erling Smørgrav  */
120*b7579f77SDag-Erling Smørgrav static int
121*b7579f77SDag-Erling Smørgrav nsec_get_next(struct ub_packed_rrset_key* nsec, uint8_t** nm, size_t* ln)
122*b7579f77SDag-Erling Smørgrav {
123*b7579f77SDag-Erling Smørgrav 	struct packed_rrset_data* d = (struct packed_rrset_data*)nsec->
124*b7579f77SDag-Erling Smørgrav 		entry.data;
125*b7579f77SDag-Erling Smørgrav 	if(!d || d->count == 0 || d->rr_len[0] < 2+1) {
126*b7579f77SDag-Erling Smørgrav 		*nm = 0;
127*b7579f77SDag-Erling Smørgrav 		*ln = 0;
128*b7579f77SDag-Erling Smørgrav 		return 0;
129*b7579f77SDag-Erling Smørgrav 	}
130*b7579f77SDag-Erling Smørgrav 	*nm = d->rr_data[0]+2;
131*b7579f77SDag-Erling Smørgrav 	*ln = dname_valid(*nm, d->rr_len[0]-2);
132*b7579f77SDag-Erling Smørgrav 	if(!*ln) {
133*b7579f77SDag-Erling Smørgrav 		*nm = 0;
134*b7579f77SDag-Erling Smørgrav 		*ln = 0;
135*b7579f77SDag-Erling Smørgrav 		return 0;
136*b7579f77SDag-Erling Smørgrav 	}
137*b7579f77SDag-Erling Smørgrav 	return 1;
138*b7579f77SDag-Erling Smørgrav }
139*b7579f77SDag-Erling Smørgrav 
140*b7579f77SDag-Erling Smørgrav /**
141*b7579f77SDag-Erling Smørgrav  * For an NSEC that matches the DS queried for, check absence of DS type.
142*b7579f77SDag-Erling Smørgrav  *
143*b7579f77SDag-Erling Smørgrav  * @param nsec: NSEC for proof, must be trusted.
144*b7579f77SDag-Erling Smørgrav  * @param qinfo: what is queried for.
145*b7579f77SDag-Erling Smørgrav  * @return if secure the nsec proves that no DS is present, or
146*b7579f77SDag-Erling Smørgrav  *	insecure if it proves it is not a delegation point.
147*b7579f77SDag-Erling Smørgrav  *	or bogus if something was wrong.
148*b7579f77SDag-Erling Smørgrav  */
149*b7579f77SDag-Erling Smørgrav static enum sec_status
150*b7579f77SDag-Erling Smørgrav val_nsec_proves_no_ds(struct ub_packed_rrset_key* nsec,
151*b7579f77SDag-Erling Smørgrav 	struct query_info* qinfo)
152*b7579f77SDag-Erling Smørgrav {
153*b7579f77SDag-Erling Smørgrav 	log_assert(qinfo->qtype == LDNS_RR_TYPE_DS);
154*b7579f77SDag-Erling Smørgrav 	log_assert(ntohs(nsec->rk.type) == LDNS_RR_TYPE_NSEC);
155*b7579f77SDag-Erling Smørgrav 
156*b7579f77SDag-Erling Smørgrav 	if(nsec_has_type(nsec, LDNS_RR_TYPE_SOA) && qinfo->qname_len != 1) {
157*b7579f77SDag-Erling Smørgrav 		/* SOA present means that this is the NSEC from the child,
158*b7579f77SDag-Erling Smørgrav 		 * not the parent (so it is the wrong one). */
159*b7579f77SDag-Erling Smørgrav 		return sec_status_bogus;
160*b7579f77SDag-Erling Smørgrav 	}
161*b7579f77SDag-Erling Smørgrav 	if(nsec_has_type(nsec, LDNS_RR_TYPE_DS)) {
162*b7579f77SDag-Erling Smørgrav 		/* DS present means that there should have been a positive
163*b7579f77SDag-Erling Smørgrav 		 * response to the DS query, so there is something wrong. */
164*b7579f77SDag-Erling Smørgrav 		return sec_status_bogus;
165*b7579f77SDag-Erling Smørgrav 	}
166*b7579f77SDag-Erling Smørgrav 
167*b7579f77SDag-Erling Smørgrav 	if(!nsec_has_type(nsec, LDNS_RR_TYPE_NS)) {
168*b7579f77SDag-Erling Smørgrav 		/* If there is no NS at this point at all, then this
169*b7579f77SDag-Erling Smørgrav 		 * doesn't prove anything one way or the other. */
170*b7579f77SDag-Erling Smørgrav 		return sec_status_insecure;
171*b7579f77SDag-Erling Smørgrav 	}
172*b7579f77SDag-Erling Smørgrav 	/* Otherwise, this proves no DS. */
173*b7579f77SDag-Erling Smørgrav 	return sec_status_secure;
174*b7579f77SDag-Erling Smørgrav }
175*b7579f77SDag-Erling Smørgrav 
176*b7579f77SDag-Erling Smørgrav /** check security status from cache or verify rrset, returns true if secure */
177*b7579f77SDag-Erling Smørgrav static int
178*b7579f77SDag-Erling Smørgrav nsec_verify_rrset(struct module_env* env, struct val_env* ve,
179*b7579f77SDag-Erling Smørgrav 	struct ub_packed_rrset_key* nsec, struct key_entry_key* kkey,
180*b7579f77SDag-Erling Smørgrav 	char** reason)
181*b7579f77SDag-Erling Smørgrav {
182*b7579f77SDag-Erling Smørgrav 	struct packed_rrset_data* d = (struct packed_rrset_data*)
183*b7579f77SDag-Erling Smørgrav 		nsec->entry.data;
184*b7579f77SDag-Erling Smørgrav 	if(d->security == sec_status_secure)
185*b7579f77SDag-Erling Smørgrav 		return 1;
186*b7579f77SDag-Erling Smørgrav 	rrset_check_sec_status(env->rrset_cache, nsec, *env->now);
187*b7579f77SDag-Erling Smørgrav 	if(d->security == sec_status_secure)
188*b7579f77SDag-Erling Smørgrav 		return 1;
189*b7579f77SDag-Erling Smørgrav 	d->security = val_verify_rrset_entry(env, ve, nsec, kkey, reason);
190*b7579f77SDag-Erling Smørgrav 	if(d->security == sec_status_secure) {
191*b7579f77SDag-Erling Smørgrav 		rrset_update_sec_status(env->rrset_cache, nsec, *env->now);
192*b7579f77SDag-Erling Smørgrav 		return 1;
193*b7579f77SDag-Erling Smørgrav 	}
194*b7579f77SDag-Erling Smørgrav 	return 0;
195*b7579f77SDag-Erling Smørgrav }
196*b7579f77SDag-Erling Smørgrav 
197*b7579f77SDag-Erling Smørgrav enum sec_status
198*b7579f77SDag-Erling Smørgrav val_nsec_prove_nodata_dsreply(struct module_env* env, struct val_env* ve,
199*b7579f77SDag-Erling Smørgrav 	struct query_info* qinfo, struct reply_info* rep,
200*b7579f77SDag-Erling Smørgrav 	struct key_entry_key* kkey, uint32_t* proof_ttl, char** reason)
201*b7579f77SDag-Erling Smørgrav {
202*b7579f77SDag-Erling Smørgrav 	struct ub_packed_rrset_key* nsec = reply_find_rrset_section_ns(
203*b7579f77SDag-Erling Smørgrav 		rep, qinfo->qname, qinfo->qname_len, LDNS_RR_TYPE_NSEC,
204*b7579f77SDag-Erling Smørgrav 		qinfo->qclass);
205*b7579f77SDag-Erling Smørgrav 	enum sec_status sec;
206*b7579f77SDag-Erling Smørgrav 	size_t i;
207*b7579f77SDag-Erling Smørgrav 	uint8_t* wc = NULL, *ce = NULL;
208*b7579f77SDag-Erling Smørgrav 	int valid_nsec = 0;
209*b7579f77SDag-Erling Smørgrav 	struct ub_packed_rrset_key* wc_nsec = NULL;
210*b7579f77SDag-Erling Smørgrav 
211*b7579f77SDag-Erling Smørgrav 	/* If we have a NSEC at the same name, it must prove one
212*b7579f77SDag-Erling Smørgrav 	 * of two things
213*b7579f77SDag-Erling Smørgrav 	 * --
214*b7579f77SDag-Erling Smørgrav 	 * 1) this is a delegation point and there is no DS
215*b7579f77SDag-Erling Smørgrav 	 * 2) this is not a delegation point */
216*b7579f77SDag-Erling Smørgrav 	if(nsec) {
217*b7579f77SDag-Erling Smørgrav 		if(!nsec_verify_rrset(env, ve, nsec, kkey, reason)) {
218*b7579f77SDag-Erling Smørgrav 			verbose(VERB_ALGO, "NSEC RRset for the "
219*b7579f77SDag-Erling Smørgrav 				"referral did not verify.");
220*b7579f77SDag-Erling Smørgrav 			return sec_status_bogus;
221*b7579f77SDag-Erling Smørgrav 		}
222*b7579f77SDag-Erling Smørgrav 		sec = val_nsec_proves_no_ds(nsec, qinfo);
223*b7579f77SDag-Erling Smørgrav 		if(sec == sec_status_bogus) {
224*b7579f77SDag-Erling Smørgrav 			/* something was wrong. */
225*b7579f77SDag-Erling Smørgrav 			*reason = "NSEC does not prove absence of DS";
226*b7579f77SDag-Erling Smørgrav 			return sec;
227*b7579f77SDag-Erling Smørgrav 		} else if(sec == sec_status_insecure) {
228*b7579f77SDag-Erling Smørgrav 			/* this wasn't a delegation point. */
229*b7579f77SDag-Erling Smørgrav 			return sec;
230*b7579f77SDag-Erling Smørgrav 		} else if(sec == sec_status_secure) {
231*b7579f77SDag-Erling Smørgrav 			/* this proved no DS. */
232*b7579f77SDag-Erling Smørgrav 			*proof_ttl = ub_packed_rrset_ttl(nsec);
233*b7579f77SDag-Erling Smørgrav 			return sec;
234*b7579f77SDag-Erling Smørgrav 		}
235*b7579f77SDag-Erling Smørgrav 		/* if unchecked, fall through to next proof */
236*b7579f77SDag-Erling Smørgrav 	}
237*b7579f77SDag-Erling Smørgrav 
238*b7579f77SDag-Erling Smørgrav 	/* Otherwise, there is no NSEC at qname. This could be an ENT.
239*b7579f77SDag-Erling Smørgrav 	 * (ENT=empty non terminal). If not, this is broken. */
240*b7579f77SDag-Erling Smørgrav 
241*b7579f77SDag-Erling Smørgrav 	/* verify NSEC rrsets in auth section */
242*b7579f77SDag-Erling Smørgrav 	for(i=rep->an_numrrsets; i < rep->an_numrrsets+rep->ns_numrrsets;
243*b7579f77SDag-Erling Smørgrav 		i++) {
244*b7579f77SDag-Erling Smørgrav 		if(rep->rrsets[i]->rk.type != htons(LDNS_RR_TYPE_NSEC))
245*b7579f77SDag-Erling Smørgrav 			continue;
246*b7579f77SDag-Erling Smørgrav 		if(!nsec_verify_rrset(env, ve, rep->rrsets[i], kkey, reason)) {
247*b7579f77SDag-Erling Smørgrav 			verbose(VERB_ALGO, "NSEC for empty non-terminal "
248*b7579f77SDag-Erling Smørgrav 				"did not verify.");
249*b7579f77SDag-Erling Smørgrav 			return sec_status_bogus;
250*b7579f77SDag-Erling Smørgrav 		}
251*b7579f77SDag-Erling Smørgrav 		if(nsec_proves_nodata(rep->rrsets[i], qinfo, &wc)) {
252*b7579f77SDag-Erling Smørgrav 			verbose(VERB_ALGO, "NSEC for empty non-terminal "
253*b7579f77SDag-Erling Smørgrav 				"proved no DS.");
254*b7579f77SDag-Erling Smørgrav 			*proof_ttl = rrset_get_ttl(rep->rrsets[i]);
255*b7579f77SDag-Erling Smørgrav 			if(wc && dname_is_wild(rep->rrsets[i]->rk.dname))
256*b7579f77SDag-Erling Smørgrav 				wc_nsec = rep->rrsets[i];
257*b7579f77SDag-Erling Smørgrav 			valid_nsec = 1;
258*b7579f77SDag-Erling Smørgrav 		}
259*b7579f77SDag-Erling Smørgrav 		if(val_nsec_proves_name_error(rep->rrsets[i], qinfo->qname)) {
260*b7579f77SDag-Erling Smørgrav 			ce = nsec_closest_encloser(qinfo->qname,
261*b7579f77SDag-Erling Smørgrav 				rep->rrsets[i]);
262*b7579f77SDag-Erling Smørgrav 		}
263*b7579f77SDag-Erling Smørgrav 	}
264*b7579f77SDag-Erling Smørgrav 	if(wc && !ce)
265*b7579f77SDag-Erling Smørgrav 		valid_nsec = 0;
266*b7579f77SDag-Erling Smørgrav 	else if(wc && ce) {
267*b7579f77SDag-Erling Smørgrav 		/* ce and wc must match */
268*b7579f77SDag-Erling Smørgrav 		if(query_dname_compare(wc, ce) != 0)
269*b7579f77SDag-Erling Smørgrav 			valid_nsec = 0;
270*b7579f77SDag-Erling Smørgrav 		else if(!wc_nsec)
271*b7579f77SDag-Erling Smørgrav 			valid_nsec = 0;
272*b7579f77SDag-Erling Smørgrav 	}
273*b7579f77SDag-Erling Smørgrav 	if(valid_nsec) {
274*b7579f77SDag-Erling Smørgrav 		if(wc) {
275*b7579f77SDag-Erling Smørgrav 			/* check if this is a delegation */
276*b7579f77SDag-Erling Smørgrav 			*reason = "NSEC for wildcard does not prove absence of DS";
277*b7579f77SDag-Erling Smørgrav 			return val_nsec_proves_no_ds(wc_nsec, qinfo);
278*b7579f77SDag-Erling Smørgrav 		}
279*b7579f77SDag-Erling Smørgrav 		/* valid nsec proves empty nonterminal */
280*b7579f77SDag-Erling Smørgrav 		return sec_status_insecure;
281*b7579f77SDag-Erling Smørgrav 	}
282*b7579f77SDag-Erling Smørgrav 
283*b7579f77SDag-Erling Smørgrav 	/* NSEC proof did not conlusively point to DS or no DS */
284*b7579f77SDag-Erling Smørgrav 	return sec_status_unchecked;
285*b7579f77SDag-Erling Smørgrav }
286*b7579f77SDag-Erling Smørgrav 
287*b7579f77SDag-Erling Smørgrav int nsec_proves_nodata(struct ub_packed_rrset_key* nsec,
288*b7579f77SDag-Erling Smørgrav 	struct query_info* qinfo, uint8_t** wc)
289*b7579f77SDag-Erling Smørgrav {
290*b7579f77SDag-Erling Smørgrav 	log_assert(wc);
291*b7579f77SDag-Erling Smørgrav 	if(query_dname_compare(nsec->rk.dname, qinfo->qname) != 0) {
292*b7579f77SDag-Erling Smørgrav 		uint8_t* nm;
293*b7579f77SDag-Erling Smørgrav 		size_t ln;
294*b7579f77SDag-Erling Smørgrav 
295*b7579f77SDag-Erling Smørgrav 		/* empty-non-terminal checking.
296*b7579f77SDag-Erling Smørgrav 		 * Done before wildcard, because this is an exact match,
297*b7579f77SDag-Erling Smørgrav 		 * and would prevent a wildcard from matching. */
298*b7579f77SDag-Erling Smørgrav 
299*b7579f77SDag-Erling Smørgrav 		/* If the nsec is proving that qname is an ENT, the nsec owner
300*b7579f77SDag-Erling Smørgrav 		 * will be less than qname, and the next name will be a child
301*b7579f77SDag-Erling Smørgrav 		 * domain of the qname. */
302*b7579f77SDag-Erling Smørgrav 		if(!nsec_get_next(nsec, &nm, &ln))
303*b7579f77SDag-Erling Smørgrav 			return 0; /* bad nsec */
304*b7579f77SDag-Erling Smørgrav 		if(dname_strict_subdomain_c(nm, qinfo->qname) &&
305*b7579f77SDag-Erling Smørgrav 			dname_canonical_compare(nsec->rk.dname,
306*b7579f77SDag-Erling Smørgrav 				qinfo->qname) < 0) {
307*b7579f77SDag-Erling Smørgrav 			return 1; /* proves ENT */
308*b7579f77SDag-Erling Smørgrav 		}
309*b7579f77SDag-Erling Smørgrav 
310*b7579f77SDag-Erling Smørgrav 		/* wildcard checking. */
311*b7579f77SDag-Erling Smørgrav 
312*b7579f77SDag-Erling Smørgrav 		/* If this is a wildcard NSEC, make sure that a) it was
313*b7579f77SDag-Erling Smørgrav 		 * possible to have generated qname from the wildcard and
314*b7579f77SDag-Erling Smørgrav 		 * b) the type map does not contain qtype. Note that this
315*b7579f77SDag-Erling Smørgrav 		 * does NOT prove that this wildcard was the applicable
316*b7579f77SDag-Erling Smørgrav 		 * wildcard. */
317*b7579f77SDag-Erling Smørgrav 		if(dname_is_wild(nsec->rk.dname)) {
318*b7579f77SDag-Erling Smørgrav 			/* the purported closest encloser. */
319*b7579f77SDag-Erling Smørgrav 			uint8_t* ce = nsec->rk.dname;
320*b7579f77SDag-Erling Smørgrav 			size_t ce_len = nsec->rk.dname_len;
321*b7579f77SDag-Erling Smørgrav 			dname_remove_label(&ce, &ce_len);
322*b7579f77SDag-Erling Smørgrav 
323*b7579f77SDag-Erling Smørgrav 			/* The qname must be a strict subdomain of the
324*b7579f77SDag-Erling Smørgrav 			 * closest encloser, for the wildcard to apply
325*b7579f77SDag-Erling Smørgrav 			 */
326*b7579f77SDag-Erling Smørgrav 			if(dname_strict_subdomain_c(qinfo->qname, ce)) {
327*b7579f77SDag-Erling Smørgrav 				/* here we have a matching NSEC for the qname,
328*b7579f77SDag-Erling Smørgrav 				 * perform matching NSEC checks */
329*b7579f77SDag-Erling Smørgrav 				if(nsec_has_type(nsec, LDNS_RR_TYPE_CNAME)) {
330*b7579f77SDag-Erling Smørgrav 				   /* should have gotten the wildcard CNAME */
331*b7579f77SDag-Erling Smørgrav 					return 0;
332*b7579f77SDag-Erling Smørgrav 				}
333*b7579f77SDag-Erling Smørgrav 				if(nsec_has_type(nsec, LDNS_RR_TYPE_NS) &&
334*b7579f77SDag-Erling Smørgrav 				   !nsec_has_type(nsec, LDNS_RR_TYPE_SOA)) {
335*b7579f77SDag-Erling Smørgrav 				   /* wrong parentside (wildcard) NSEC used */
336*b7579f77SDag-Erling Smørgrav 					return 0;
337*b7579f77SDag-Erling Smørgrav 				}
338*b7579f77SDag-Erling Smørgrav 				if(nsec_has_type(nsec, qinfo->qtype)) {
339*b7579f77SDag-Erling Smørgrav 					return 0;
340*b7579f77SDag-Erling Smørgrav 				}
341*b7579f77SDag-Erling Smørgrav 				*wc = ce;
342*b7579f77SDag-Erling Smørgrav 				return 1;
343*b7579f77SDag-Erling Smørgrav 			}
344*b7579f77SDag-Erling Smørgrav 		}
345*b7579f77SDag-Erling Smørgrav 
346*b7579f77SDag-Erling Smørgrav 		/* Otherwise, this NSEC does not prove ENT and is not a
347*b7579f77SDag-Erling Smørgrav 		 * wildcard, so it does not prove NODATA. */
348*b7579f77SDag-Erling Smørgrav 		return 0;
349*b7579f77SDag-Erling Smørgrav 	}
350*b7579f77SDag-Erling Smørgrav 
351*b7579f77SDag-Erling Smørgrav 	/* If the qtype exists, then we should have gotten it. */
352*b7579f77SDag-Erling Smørgrav 	if(nsec_has_type(nsec, qinfo->qtype)) {
353*b7579f77SDag-Erling Smørgrav 		return 0;
354*b7579f77SDag-Erling Smørgrav 	}
355*b7579f77SDag-Erling Smørgrav 
356*b7579f77SDag-Erling Smørgrav 	/* if the name is a CNAME node, then we should have gotten the CNAME*/
357*b7579f77SDag-Erling Smørgrav 	if(nsec_has_type(nsec, LDNS_RR_TYPE_CNAME)) {
358*b7579f77SDag-Erling Smørgrav 		return 0;
359*b7579f77SDag-Erling Smørgrav 	}
360*b7579f77SDag-Erling Smørgrav 
361*b7579f77SDag-Erling Smørgrav 	/* If an NS set exists at this name, and NOT a SOA (so this is a
362*b7579f77SDag-Erling Smørgrav 	 * zone cut, not a zone apex), then we should have gotten a
363*b7579f77SDag-Erling Smørgrav 	 * referral (or we just got the wrong NSEC).
364*b7579f77SDag-Erling Smørgrav 	 * The reverse of this check is used when qtype is DS, since that
365*b7579f77SDag-Erling Smørgrav 	 * must use the NSEC from above the zone cut. */
366*b7579f77SDag-Erling Smørgrav 	if(qinfo->qtype != LDNS_RR_TYPE_DS &&
367*b7579f77SDag-Erling Smørgrav 		nsec_has_type(nsec, LDNS_RR_TYPE_NS) &&
368*b7579f77SDag-Erling Smørgrav 		!nsec_has_type(nsec, LDNS_RR_TYPE_SOA)) {
369*b7579f77SDag-Erling Smørgrav 		return 0;
370*b7579f77SDag-Erling Smørgrav 	} else if(qinfo->qtype == LDNS_RR_TYPE_DS &&
371*b7579f77SDag-Erling Smørgrav 		nsec_has_type(nsec, LDNS_RR_TYPE_SOA) &&
372*b7579f77SDag-Erling Smørgrav 		!dname_is_root(qinfo->qname)) {
373*b7579f77SDag-Erling Smørgrav 		return 0;
374*b7579f77SDag-Erling Smørgrav 	}
375*b7579f77SDag-Erling Smørgrav 
376*b7579f77SDag-Erling Smørgrav 	return 1;
377*b7579f77SDag-Erling Smørgrav }
378*b7579f77SDag-Erling Smørgrav 
379*b7579f77SDag-Erling Smørgrav int
380*b7579f77SDag-Erling Smørgrav val_nsec_proves_name_error(struct ub_packed_rrset_key* nsec, uint8_t* qname)
381*b7579f77SDag-Erling Smørgrav {
382*b7579f77SDag-Erling Smørgrav 	uint8_t* owner = nsec->rk.dname;
383*b7579f77SDag-Erling Smørgrav 	uint8_t* next;
384*b7579f77SDag-Erling Smørgrav 	size_t nlen;
385*b7579f77SDag-Erling Smørgrav 	if(!nsec_get_next(nsec, &next, &nlen))
386*b7579f77SDag-Erling Smørgrav 		return 0;
387*b7579f77SDag-Erling Smørgrav 
388*b7579f77SDag-Erling Smørgrav 	/* If NSEC owner == qname, then this NSEC proves that qname exists. */
389*b7579f77SDag-Erling Smørgrav 	if(query_dname_compare(qname, owner) == 0) {
390*b7579f77SDag-Erling Smørgrav 		return 0;
391*b7579f77SDag-Erling Smørgrav 	}
392*b7579f77SDag-Erling Smørgrav 
393*b7579f77SDag-Erling Smørgrav 	/* If NSEC is a parent of qname, we need to check the type map
394*b7579f77SDag-Erling Smørgrav 	 * If the parent name has a DNAME or is a delegation point, then
395*b7579f77SDag-Erling Smørgrav 	 * this NSEC is being misused. */
396*b7579f77SDag-Erling Smørgrav 	if(dname_subdomain_c(qname, owner) &&
397*b7579f77SDag-Erling Smørgrav 		(nsec_has_type(nsec, LDNS_RR_TYPE_DNAME) ||
398*b7579f77SDag-Erling Smørgrav 		(nsec_has_type(nsec, LDNS_RR_TYPE_NS)
399*b7579f77SDag-Erling Smørgrav 			&& !nsec_has_type(nsec, LDNS_RR_TYPE_SOA))
400*b7579f77SDag-Erling Smørgrav 		)) {
401*b7579f77SDag-Erling Smørgrav 		return 0;
402*b7579f77SDag-Erling Smørgrav 	}
403*b7579f77SDag-Erling Smørgrav 
404*b7579f77SDag-Erling Smørgrav 	if(query_dname_compare(owner, next) == 0) {
405*b7579f77SDag-Erling Smørgrav 		/* this nsec is the only nsec */
406*b7579f77SDag-Erling Smørgrav 		/* zone.name NSEC zone.name, disproves everything else */
407*b7579f77SDag-Erling Smørgrav 		/* but only for subdomains of that zone */
408*b7579f77SDag-Erling Smørgrav 		if(dname_strict_subdomain_c(qname, next))
409*b7579f77SDag-Erling Smørgrav 			return 1;
410*b7579f77SDag-Erling Smørgrav 	}
411*b7579f77SDag-Erling Smørgrav 	else if(dname_canonical_compare(owner, next) > 0) {
412*b7579f77SDag-Erling Smørgrav 		/* this is the last nsec, ....(bigger) NSEC zonename(smaller) */
413*b7579f77SDag-Erling Smørgrav 		/* the names after the last (owner) name do not exist
414*b7579f77SDag-Erling Smørgrav 		 * there are no names before the zone name in the zone
415*b7579f77SDag-Erling Smørgrav 		 * but the qname must be a subdomain of the zone name(next). */
416*b7579f77SDag-Erling Smørgrav 		if(dname_canonical_compare(owner, qname) < 0 &&
417*b7579f77SDag-Erling Smørgrav 			dname_strict_subdomain_c(qname, next))
418*b7579f77SDag-Erling Smørgrav 			return 1;
419*b7579f77SDag-Erling Smørgrav 	} else {
420*b7579f77SDag-Erling Smørgrav 		/* regular NSEC, (smaller) NSEC (larger) */
421*b7579f77SDag-Erling Smørgrav 		if(dname_canonical_compare(owner, qname) < 0 &&
422*b7579f77SDag-Erling Smørgrav 		   dname_canonical_compare(qname, next) < 0) {
423*b7579f77SDag-Erling Smørgrav 			return 1;
424*b7579f77SDag-Erling Smørgrav 		}
425*b7579f77SDag-Erling Smørgrav 	}
426*b7579f77SDag-Erling Smørgrav 	return 0;
427*b7579f77SDag-Erling Smørgrav }
428*b7579f77SDag-Erling Smørgrav 
429*b7579f77SDag-Erling Smørgrav int val_nsec_proves_insecuredelegation(struct ub_packed_rrset_key* nsec,
430*b7579f77SDag-Erling Smørgrav 	struct query_info* qinfo)
431*b7579f77SDag-Erling Smørgrav {
432*b7579f77SDag-Erling Smørgrav 	if(nsec_has_type(nsec, LDNS_RR_TYPE_NS) &&
433*b7579f77SDag-Erling Smørgrav 		!nsec_has_type(nsec, LDNS_RR_TYPE_DS) &&
434*b7579f77SDag-Erling Smørgrav 		!nsec_has_type(nsec, LDNS_RR_TYPE_SOA)) {
435*b7579f77SDag-Erling Smørgrav 		/* see if nsec signals an insecure delegation */
436*b7579f77SDag-Erling Smørgrav 		if(qinfo->qtype == LDNS_RR_TYPE_DS) {
437*b7579f77SDag-Erling Smørgrav 			/* if type is DS and qname is equal to nsec, then it
438*b7579f77SDag-Erling Smørgrav 			 * is an exact match nsec, result not insecure */
439*b7579f77SDag-Erling Smørgrav 			if(dname_strict_subdomain_c(qinfo->qname,
440*b7579f77SDag-Erling Smørgrav 				nsec->rk.dname))
441*b7579f77SDag-Erling Smørgrav 				return 1;
442*b7579f77SDag-Erling Smørgrav 		} else {
443*b7579f77SDag-Erling Smørgrav 			if(dname_subdomain_c(qinfo->qname, nsec->rk.dname))
444*b7579f77SDag-Erling Smørgrav 				return 1;
445*b7579f77SDag-Erling Smørgrav 		}
446*b7579f77SDag-Erling Smørgrav 	}
447*b7579f77SDag-Erling Smørgrav 	return 0;
448*b7579f77SDag-Erling Smørgrav }
449*b7579f77SDag-Erling Smørgrav 
450*b7579f77SDag-Erling Smørgrav uint8_t*
451*b7579f77SDag-Erling Smørgrav nsec_closest_encloser(uint8_t* qname, struct ub_packed_rrset_key* nsec)
452*b7579f77SDag-Erling Smørgrav {
453*b7579f77SDag-Erling Smørgrav 	uint8_t* next;
454*b7579f77SDag-Erling Smørgrav 	size_t nlen;
455*b7579f77SDag-Erling Smørgrav 	uint8_t* common1, *common2;
456*b7579f77SDag-Erling Smørgrav 	if(!nsec_get_next(nsec, &next, &nlen))
457*b7579f77SDag-Erling Smørgrav 		return NULL;
458*b7579f77SDag-Erling Smørgrav 	/* longest common with owner or next name */
459*b7579f77SDag-Erling Smørgrav 	common1 = dname_get_shared_topdomain(nsec->rk.dname, qname);
460*b7579f77SDag-Erling Smørgrav 	common2 = dname_get_shared_topdomain(next, qname);
461*b7579f77SDag-Erling Smørgrav 	if(dname_count_labels(common1) > dname_count_labels(common2))
462*b7579f77SDag-Erling Smørgrav 		return common1;
463*b7579f77SDag-Erling Smørgrav 	return common2;
464*b7579f77SDag-Erling Smørgrav }
465*b7579f77SDag-Erling Smørgrav 
466*b7579f77SDag-Erling Smørgrav int val_nsec_proves_positive_wildcard(struct ub_packed_rrset_key* nsec,
467*b7579f77SDag-Erling Smørgrav 	struct query_info* qinf, uint8_t* wc)
468*b7579f77SDag-Erling Smørgrav {
469*b7579f77SDag-Erling Smørgrav 	uint8_t* ce;
470*b7579f77SDag-Erling Smørgrav 	/*  1) prove that qname doesn't exist and
471*b7579f77SDag-Erling Smørgrav 	 *  2) that the correct wildcard was used
472*b7579f77SDag-Erling Smørgrav 	 *  nsec has been verified already. */
473*b7579f77SDag-Erling Smørgrav 	if(!val_nsec_proves_name_error(nsec, qinf->qname))
474*b7579f77SDag-Erling Smørgrav 		return 0;
475*b7579f77SDag-Erling Smørgrav 	/* check wildcard name */
476*b7579f77SDag-Erling Smørgrav 	ce = nsec_closest_encloser(qinf->qname, nsec);
477*b7579f77SDag-Erling Smørgrav 	if(!ce)
478*b7579f77SDag-Erling Smørgrav 		return 0;
479*b7579f77SDag-Erling Smørgrav 	if(query_dname_compare(wc, ce) != 0) {
480*b7579f77SDag-Erling Smørgrav 		return 0;
481*b7579f77SDag-Erling Smørgrav 	}
482*b7579f77SDag-Erling Smørgrav 	return 1;
483*b7579f77SDag-Erling Smørgrav }
484*b7579f77SDag-Erling Smørgrav 
485*b7579f77SDag-Erling Smørgrav int
486*b7579f77SDag-Erling Smørgrav val_nsec_proves_no_wc(struct ub_packed_rrset_key* nsec, uint8_t* qname,
487*b7579f77SDag-Erling Smørgrav 	size_t qnamelen)
488*b7579f77SDag-Erling Smørgrav {
489*b7579f77SDag-Erling Smørgrav 	/* Determine if a NSEC record proves the non-existence of a
490*b7579f77SDag-Erling Smørgrav 	 * wildcard that could have produced qname. */
491*b7579f77SDag-Erling Smørgrav 	int labs;
492*b7579f77SDag-Erling Smørgrav 	int i;
493*b7579f77SDag-Erling Smørgrav 	uint8_t* ce = nsec_closest_encloser(qname, nsec);
494*b7579f77SDag-Erling Smørgrav 	uint8_t* strip;
495*b7579f77SDag-Erling Smørgrav 	size_t striplen;
496*b7579f77SDag-Erling Smørgrav 	uint8_t buf[LDNS_MAX_DOMAINLEN+3];
497*b7579f77SDag-Erling Smørgrav 	if(!ce)
498*b7579f77SDag-Erling Smørgrav 		return 0;
499*b7579f77SDag-Erling Smørgrav 	/* we can subtract the closest encloser count - since that is the
500*b7579f77SDag-Erling Smørgrav 	 * largest shared topdomain with owner and next NSEC name,
501*b7579f77SDag-Erling Smørgrav 	 * because the NSEC is no proof for names shorter than the owner
502*b7579f77SDag-Erling Smørgrav 	 * and next names. */
503*b7579f77SDag-Erling Smørgrav 	labs = dname_count_labels(qname) - dname_count_labels(ce);
504*b7579f77SDag-Erling Smørgrav 
505*b7579f77SDag-Erling Smørgrav 	for(i=labs; i>0; i--) {
506*b7579f77SDag-Erling Smørgrav 		/* i is number of labels to strip off qname, prepend * wild */
507*b7579f77SDag-Erling Smørgrav 		strip = qname;
508*b7579f77SDag-Erling Smørgrav 		striplen = qnamelen;
509*b7579f77SDag-Erling Smørgrav 		dname_remove_labels(&strip, &striplen, i);
510*b7579f77SDag-Erling Smørgrav 		if(striplen > LDNS_MAX_DOMAINLEN-2)
511*b7579f77SDag-Erling Smørgrav 			continue; /* too long to prepend wildcard */
512*b7579f77SDag-Erling Smørgrav 		buf[0] = 1;
513*b7579f77SDag-Erling Smørgrav 		buf[1] = (uint8_t)'*';
514*b7579f77SDag-Erling Smørgrav 		memmove(buf+2, strip, striplen);
515*b7579f77SDag-Erling Smørgrav 		if(val_nsec_proves_name_error(nsec, buf)) {
516*b7579f77SDag-Erling Smørgrav 			return 1;
517*b7579f77SDag-Erling Smørgrav 		}
518*b7579f77SDag-Erling Smørgrav 	}
519*b7579f77SDag-Erling Smørgrav 	return 0;
520*b7579f77SDag-Erling Smørgrav }
521*b7579f77SDag-Erling Smørgrav 
522*b7579f77SDag-Erling Smørgrav /**
523*b7579f77SDag-Erling Smørgrav  * Find shared topdomain that exists
524*b7579f77SDag-Erling Smørgrav  */
525*b7579f77SDag-Erling Smørgrav static void
526*b7579f77SDag-Erling Smørgrav dlv_topdomain(struct ub_packed_rrset_key* nsec, uint8_t* qname,
527*b7579f77SDag-Erling Smørgrav 	uint8_t** nm, size_t* nm_len)
528*b7579f77SDag-Erling Smørgrav {
529*b7579f77SDag-Erling Smørgrav 	/* make sure reply is part of nm */
530*b7579f77SDag-Erling Smørgrav 	/* take shared topdomain with left of NSEC. */
531*b7579f77SDag-Erling Smørgrav 
532*b7579f77SDag-Erling Smørgrav 	/* because, if empty nonterminal, then right is subdomain of qname.
533*b7579f77SDag-Erling Smørgrav 	 * and any shared topdomain would be empty nonterminals.
534*b7579f77SDag-Erling Smørgrav 	 *
535*b7579f77SDag-Erling Smørgrav 	 * If nxdomain, then the right is bigger, and could have an
536*b7579f77SDag-Erling Smørgrav 	 * interesting shared topdomain, but if it does have one, it is
537*b7579f77SDag-Erling Smørgrav 	 * an empty nonterminal. An empty nonterminal shared with the left
538*b7579f77SDag-Erling Smørgrav 	 * one. */
539*b7579f77SDag-Erling Smørgrav 	int n;
540*b7579f77SDag-Erling Smørgrav 	uint8_t* common = dname_get_shared_topdomain(qname, nsec->rk.dname);
541*b7579f77SDag-Erling Smørgrav 	n = dname_count_labels(*nm) - dname_count_labels(common);
542*b7579f77SDag-Erling Smørgrav 	dname_remove_labels(nm, nm_len, n);
543*b7579f77SDag-Erling Smørgrav }
544*b7579f77SDag-Erling Smørgrav 
545*b7579f77SDag-Erling Smørgrav int val_nsec_check_dlv(struct query_info* qinfo,
546*b7579f77SDag-Erling Smørgrav         struct reply_info* rep, uint8_t** nm, size_t* nm_len)
547*b7579f77SDag-Erling Smørgrav {
548*b7579f77SDag-Erling Smørgrav 	uint8_t* next;
549*b7579f77SDag-Erling Smørgrav 	size_t i, nlen;
550*b7579f77SDag-Erling Smørgrav 	int c;
551*b7579f77SDag-Erling Smørgrav 	/* we should now have a NOERROR/NODATA or NXDOMAIN message */
552*b7579f77SDag-Erling Smørgrav 	if(rep->an_numrrsets != 0) {
553*b7579f77SDag-Erling Smørgrav 		return 0;
554*b7579f77SDag-Erling Smørgrav 	}
555*b7579f77SDag-Erling Smørgrav 	/* is this NOERROR ? */
556*b7579f77SDag-Erling Smørgrav 	if(FLAGS_GET_RCODE(rep->flags) == LDNS_RCODE_NOERROR) {
557*b7579f77SDag-Erling Smørgrav 		/* it can be a plain NSEC match - go up one more level. */
558*b7579f77SDag-Erling Smørgrav 		/* or its an empty nonterminal - go up to nonempty level */
559*b7579f77SDag-Erling Smørgrav 		for(i=0; i<rep->ns_numrrsets; i++) {
560*b7579f77SDag-Erling Smørgrav 			if(htons(rep->rrsets[i]->rk.type)!=LDNS_RR_TYPE_NSEC ||
561*b7579f77SDag-Erling Smørgrav 				!nsec_get_next(rep->rrsets[i], &next, &nlen))
562*b7579f77SDag-Erling Smørgrav 				continue;
563*b7579f77SDag-Erling Smørgrav 			c = dname_canonical_compare(
564*b7579f77SDag-Erling Smørgrav 				rep->rrsets[i]->rk.dname, qinfo->qname);
565*b7579f77SDag-Erling Smørgrav 			if(c == 0) {
566*b7579f77SDag-Erling Smørgrav 				/* plain match */
567*b7579f77SDag-Erling Smørgrav 				if(nsec_has_type(rep->rrsets[i],
568*b7579f77SDag-Erling Smørgrav 					LDNS_RR_TYPE_DLV))
569*b7579f77SDag-Erling Smørgrav 					return 0;
570*b7579f77SDag-Erling Smørgrav 				dname_remove_label(nm, nm_len);
571*b7579f77SDag-Erling Smørgrav 				return 1;
572*b7579f77SDag-Erling Smørgrav 			} else if(c < 0 &&
573*b7579f77SDag-Erling Smørgrav 				dname_strict_subdomain_c(next, qinfo->qname)) {
574*b7579f77SDag-Erling Smørgrav 				/* ENT */
575*b7579f77SDag-Erling Smørgrav 				dlv_topdomain(rep->rrsets[i], qinfo->qname,
576*b7579f77SDag-Erling Smørgrav 					nm, nm_len);
577*b7579f77SDag-Erling Smørgrav 				return 1;
578*b7579f77SDag-Erling Smørgrav 			}
579*b7579f77SDag-Erling Smørgrav 		}
580*b7579f77SDag-Erling Smørgrav 		return 0;
581*b7579f77SDag-Erling Smørgrav 	}
582*b7579f77SDag-Erling Smørgrav 
583*b7579f77SDag-Erling Smørgrav 	/* is this NXDOMAIN ? */
584*b7579f77SDag-Erling Smørgrav 	if(FLAGS_GET_RCODE(rep->flags) == LDNS_RCODE_NXDOMAIN) {
585*b7579f77SDag-Erling Smørgrav 		/* find the qname denial NSEC record. It can tell us
586*b7579f77SDag-Erling Smørgrav 		 * a closest encloser name; or that we not need bother */
587*b7579f77SDag-Erling Smørgrav 		for(i=0; i<rep->ns_numrrsets; i++) {
588*b7579f77SDag-Erling Smørgrav 			if(htons(rep->rrsets[i]->rk.type) != LDNS_RR_TYPE_NSEC)
589*b7579f77SDag-Erling Smørgrav 				continue;
590*b7579f77SDag-Erling Smørgrav 			if(val_nsec_proves_name_error(rep->rrsets[i],
591*b7579f77SDag-Erling Smørgrav 				qinfo->qname)) {
592*b7579f77SDag-Erling Smørgrav 				log_nametypeclass(VERB_ALGO, "topdomain on",
593*b7579f77SDag-Erling Smørgrav 					rep->rrsets[i]->rk.dname,
594*b7579f77SDag-Erling Smørgrav 					ntohs(rep->rrsets[i]->rk.type), 0);
595*b7579f77SDag-Erling Smørgrav 				dlv_topdomain(rep->rrsets[i], qinfo->qname,
596*b7579f77SDag-Erling Smørgrav 					nm, nm_len);
597*b7579f77SDag-Erling Smørgrav 				return 1;
598*b7579f77SDag-Erling Smørgrav 			}
599*b7579f77SDag-Erling Smørgrav 		}
600*b7579f77SDag-Erling Smørgrav 		return 0;
601*b7579f77SDag-Erling Smørgrav 	}
602*b7579f77SDag-Erling Smørgrav 	return 0;
603*b7579f77SDag-Erling Smørgrav }
604