1238104Sdes/*
2238104Sdes * dnssec.c
3238104Sdes * Some DNSSEC helper function are defined here
4238104Sdes * and tracing is done
5238104Sdes * (c) 2005 NLnet Labs
6238104Sdes *
7238104Sdes * See the file LICENSE for the license
8238104Sdes *
9238104Sdes */
10238104Sdes
11238104Sdes#include "drill.h"
12238104Sdes#include <ldns/ldns.h>
13238104Sdes
14238104Sdes/* get rr_type from a server from a server */
15238104Sdesldns_rr_list *
16238104Sdesget_rr(ldns_resolver *res, ldns_rdf *zname, ldns_rr_type t, ldns_rr_class c)
17238104Sdes{
18238104Sdes	/* query, retrieve, extract and return */
19238104Sdes	ldns_pkt *p;
20238104Sdes	ldns_rr_list *found;
21238104Sdes
22238104Sdes	p = ldns_pkt_new();
23238104Sdes	found = NULL;
24238104Sdes
25246854Sdes	if (ldns_resolver_send(&p, res, zname, t, c, 0) == LDNS_STATUS_OK) {
26238104Sdes		found = ldns_pkt_rr_list_by_type(p, t, LDNS_SECTION_ANY_NOQUESTION);
27238104Sdes	}
28246854Sdes	ldns_pkt_free(p);
29238104Sdes	return found;
30238104Sdes}
31238104Sdes
32238104Sdesvoid
33238104Sdesdrill_pkt_print(FILE *fd, ldns_resolver *r, ldns_pkt *p)
34238104Sdes{
35238104Sdes	ldns_rr_list *new_nss;
36238104Sdes	ldns_rr_list *hostnames;
37246854Sdes	char *answerfrom_str;
38238104Sdes
39238104Sdes	if (verbosity < 5) {
40238104Sdes		return;
41238104Sdes	}
42238104Sdes
43238104Sdes	hostnames = ldns_get_rr_list_name_by_addr(r, ldns_pkt_answerfrom(p), 0, 0);
44238104Sdes
45238104Sdes	new_nss = ldns_pkt_rr_list_by_type(p,
46238104Sdes			LDNS_RR_TYPE_NS, LDNS_SECTION_ANSWER);
47238104Sdes	ldns_rr_list_print(fd, new_nss);
48246854Sdes	ldns_rr_list_deep_free(new_nss);
49238104Sdes
50238104Sdes	fprintf(fd, ";; Received %d bytes from %s#%d(",
51238104Sdes			(int) ldns_pkt_size(p),
52238104Sdes			ldns_rdf2str(ldns_pkt_answerfrom(p)),
53238104Sdes			(int) ldns_resolver_port(r));
54238104Sdes	/* if we can resolve this print it, other print the ip again */
55238104Sdes	if (hostnames) {
56238104Sdes		ldns_rdf_print(fd,
57238104Sdes				ldns_rr_rdf(ldns_rr_list_rr(hostnames, 0), 0));
58238104Sdes		ldns_rr_list_deep_free(hostnames);
59238104Sdes	} else {
60246854Sdes		answerfrom_str = ldns_rdf2str(ldns_pkt_answerfrom(p));
61246854Sdes		if (answerfrom_str) {
62246854Sdes			fprintf(fd, "%s", answerfrom_str);
63246854Sdes			LDNS_FREE(answerfrom_str);
64246854Sdes		}
65238104Sdes	}
66238104Sdes	fprintf(fd, ") in %u ms\n\n", (unsigned int)ldns_pkt_querytime(p));
67238104Sdes}
68238104Sdes
69238104Sdesvoid
70238104Sdesdrill_pkt_print_footer(FILE *fd, ldns_resolver *r, ldns_pkt *p)
71238104Sdes{
72238104Sdes	ldns_rr_list *hostnames;
73246854Sdes	char *answerfrom_str;
74238104Sdes
75238104Sdes	if (verbosity < 5) {
76238104Sdes		return;
77238104Sdes	}
78238104Sdes
79238104Sdes	hostnames = ldns_get_rr_list_name_by_addr(r, ldns_pkt_answerfrom(p), 0, 0);
80238104Sdes
81238104Sdes	fprintf(fd, ";; Received %d bytes from %s#%d(",
82238104Sdes			(int) ldns_pkt_size(p),
83238104Sdes			ldns_rdf2str(ldns_pkt_answerfrom(p)),
84238104Sdes			(int) ldns_resolver_port(r));
85238104Sdes	/* if we can resolve this print it, other print the ip again */
86238104Sdes	if (hostnames) {
87238104Sdes		ldns_rdf_print(fd,
88238104Sdes				ldns_rr_rdf(ldns_rr_list_rr(hostnames, 0), 0));
89238104Sdes		ldns_rr_list_deep_free(hostnames);
90238104Sdes	} else {
91246854Sdes		answerfrom_str = ldns_rdf2str(ldns_pkt_answerfrom(p));
92246854Sdes		if (answerfrom_str) {
93246854Sdes			fprintf(fd, "%s", answerfrom_str);
94246854Sdes			LDNS_FREE(answerfrom_str);
95246854Sdes		}
96238104Sdes	}
97238104Sdes	fprintf(fd, ") in %u ms\n\n", (unsigned int)ldns_pkt_querytime(p));
98238104Sdes}
99238104Sdes/*
100238104Sdes * generic function to get some RRset from a nameserver
101238104Sdes * and possible some signatures too (that would be the day...)
102238104Sdes */
103238104Sdesldns_pkt_type
104238104Sdesget_dnssec_rr(ldns_pkt *p, ldns_rdf *name, ldns_rr_type t,
105238104Sdes	ldns_rr_list **rrlist, ldns_rr_list **sig)
106238104Sdes{
107238104Sdes	ldns_pkt_type pt = LDNS_PACKET_UNKNOWN;
108238104Sdes	ldns_rr_list *sigs = NULL;
109238104Sdes	size_t i;
110238104Sdes
111238104Sdes	if (!p) {
112238104Sdes		if (rrlist) {
113238104Sdes			*rrlist = NULL;
114238104Sdes		}
115238104Sdes		return LDNS_PACKET_UNKNOWN;
116238104Sdes	}
117238104Sdes
118238104Sdes	pt = ldns_pkt_reply_type(p);
119238104Sdes	if (name) {
120246854Sdes		if (rrlist) {
121246854Sdes			*rrlist = ldns_pkt_rr_list_by_name_and_type(p, name, t,
122246854Sdes					LDNS_SECTION_ANSWER);
123246854Sdes			if (!*rrlist) {
124246854Sdes				*rrlist = ldns_pkt_rr_list_by_name_and_type(
125246854Sdes						p, name, t,
126246854Sdes						LDNS_SECTION_AUTHORITY);
127246854Sdes			}
128238104Sdes		}
129246854Sdes		if (sig) {
130246854Sdes			sigs = ldns_pkt_rr_list_by_name_and_type(p, name,
131246854Sdes					LDNS_RR_TYPE_RRSIG,
132246854Sdes					LDNS_SECTION_ANSWER);
133246854Sdes			if (!sigs) {
134246854Sdes				sigs = ldns_pkt_rr_list_by_name_and_type(
135246854Sdes						p, name, LDNS_RR_TYPE_RRSIG,
136246854Sdes						LDNS_SECTION_AUTHORITY);
137246854Sdes			}
138238104Sdes		}
139238104Sdes	} else {
140246854Sdes		/* A DS-referral - get the DS records if they are there */
141246854Sdes		if (rrlist) {
142246854Sdes			*rrlist = ldns_pkt_rr_list_by_type(
143246854Sdes					p, t, LDNS_SECTION_AUTHORITY);
144246854Sdes		}
145246854Sdes		if (sig) {
146246854Sdes			sigs = ldns_pkt_rr_list_by_type(p,
147246854Sdes					LDNS_RR_TYPE_RRSIG,
148246854Sdes					LDNS_SECTION_AUTHORITY);
149246854Sdes		}
150238104Sdes	}
151238104Sdes	if (sig) {
152238104Sdes		*sig = ldns_rr_list_new();
153238104Sdes		for (i = 0; i < ldns_rr_list_rr_count(sigs); i++) {
154238104Sdes			/* only add the sigs that cover this type */
155246854Sdes			if (t == ldns_rdf2rr_type(ldns_rr_rrsig_typecovered(
156246854Sdes						ldns_rr_list_rr(sigs, i)))) {
157246854Sdes
158246854Sdes				ldns_rr_list_push_rr(*sig,
159246854Sdes						ldns_rr_clone(
160246854Sdes							ldns_rr_list_rr(
161246854Sdes								sigs, i)));
162238104Sdes			}
163238104Sdes		}
164238104Sdes	}
165238104Sdes	ldns_rr_list_deep_free(sigs);
166238104Sdes
167238104Sdes	if (pt == LDNS_PACKET_NXDOMAIN || pt == LDNS_PACKET_NODATA) {
168238104Sdes		return pt;
169238104Sdes	} else {
170238104Sdes		return LDNS_PACKET_ANSWER;
171238104Sdes	}
172238104Sdes}
173238104Sdes
174238104Sdes
175238104Sdesldns_status
176238104Sdesldns_verify_denial(ldns_pkt *pkt, ldns_rdf *name, ldns_rr_type type, ldns_rr_list **nsec_rrs, ldns_rr_list **nsec_rr_sigs)
177238104Sdes{
178246854Sdes#ifdef HAVE_SSL
179238104Sdes	uint16_t nsec_i;
180238104Sdes
181238104Sdes	ldns_rr_list *nsecs;
182238104Sdes	ldns_status result;
183238104Sdes
184238104Sdes	if (verbosity >= 5) {
185238104Sdes		printf("VERIFY DENIAL FROM:\n");
186238104Sdes		ldns_pkt_print(stdout, pkt);
187238104Sdes	}
188238104Sdes
189238104Sdes	result = LDNS_STATUS_CRYPTO_NO_RRSIG;
190238104Sdes	/* Try to see if there are NSECS in the packet */
191238104Sdes	nsecs = ldns_pkt_rr_list_by_type(pkt, LDNS_RR_TYPE_NSEC, LDNS_SECTION_ANY_NOQUESTION);
192238104Sdes	if (nsecs) {
193238104Sdes		for (nsec_i = 0; nsec_i < ldns_rr_list_rr_count(nsecs); nsec_i++) {
194238104Sdes			/* there are four options:
195238104Sdes			 * - name equals ownername and is covered by the type bitmap
196238104Sdes			 * - name equals ownername but is not covered by the type bitmap
197238104Sdes			 * - name falls within nsec coverage but is not equal to the owner name
198238104Sdes			 * - name falls outside of nsec coverage
199238104Sdes			 */
200238104Sdes			if (ldns_dname_compare(ldns_rr_owner(ldns_rr_list_rr(nsecs, nsec_i)), name) == 0) {
201238104Sdes				/*
202238104Sdes				printf("CHECKING NSEC:\n");
203238104Sdes				ldns_rr_print(stdout, ldns_rr_list_rr(nsecs, nsec_i));
204238104Sdes				printf("DAWASEM\n");
205238104Sdes				*/
206238104Sdes				if (ldns_nsec_bitmap_covers_type(
207238104Sdes					   ldns_nsec_get_bitmap(ldns_rr_list_rr(nsecs,
208238104Sdes													nsec_i)),
209238104Sdes					   type)) {
210238104Sdes					/* Error, according to the nsec this rrset is signed */
211238104Sdes					result = LDNS_STATUS_CRYPTO_NO_RRSIG;
212238104Sdes				} else {
213238104Sdes					/* ok nsec denies existence */
214238104Sdes					if (verbosity >= 3) {
215238104Sdes						printf(";; Existence of data set with this type denied by NSEC\n");
216238104Sdes					}
217238104Sdes						/*printf(";; Verifiably insecure.\n");*/
218238104Sdes						if (nsec_rrs && nsec_rr_sigs) {
219238104Sdes							(void) get_dnssec_rr(pkt, ldns_rr_owner(ldns_rr_list_rr(nsecs, nsec_i)), LDNS_RR_TYPE_NSEC, nsec_rrs, nsec_rr_sigs);
220238104Sdes						}
221238104Sdes						ldns_rr_list_deep_free(nsecs);
222238104Sdes						return LDNS_STATUS_OK;
223238104Sdes				}
224238104Sdes			} else if (ldns_nsec_covers_name(ldns_rr_list_rr(nsecs, nsec_i), name)) {
225238104Sdes				if (verbosity >= 3) {
226238104Sdes					printf(";; Existence of data set with this name denied by NSEC\n");
227238104Sdes				}
228238104Sdes				if (nsec_rrs && nsec_rr_sigs) {
229238104Sdes					(void) get_dnssec_rr(pkt, ldns_rr_owner(ldns_rr_list_rr(nsecs, nsec_i)), LDNS_RR_TYPE_NSEC, nsec_rrs, nsec_rr_sigs);
230238104Sdes				}
231238104Sdes				ldns_rr_list_deep_free(nsecs);
232238104Sdes				return LDNS_STATUS_OK;
233238104Sdes			} else {
234238104Sdes				/* nsec has nothing to do with this data */
235238104Sdes			}
236238104Sdes		}
237238104Sdes		ldns_rr_list_deep_free(nsecs);
238238104Sdes	} else if( (nsecs = ldns_pkt_rr_list_by_type(pkt, LDNS_RR_TYPE_NSEC3, LDNS_SECTION_ANY_NOQUESTION)) ) {
239238104Sdes                ldns_rr_list* sigs = ldns_pkt_rr_list_by_type(pkt, LDNS_RR_TYPE_RRSIG, LDNS_SECTION_ANY_NOQUESTION);
240238104Sdes                ldns_rr* q = ldns_rr_new();
241238104Sdes		ldns_rr* match = NULL;
242246854Sdes
243246854Sdes                if(!sigs) {
244246854Sdes			if (q) {
245246854Sdes                		ldns_rr_free(q);
246246854Sdes			}
247246854Sdes			ldns_rr_list_deep_free(nsecs);
248246854Sdes			return LDNS_STATUS_MEM_ERR;
249246854Sdes		}
250246854Sdes                if(!q) {
251246854Sdes			ldns_rr_list_deep_free(nsecs);
252246854Sdes			ldns_rr_list_deep_free(sigs);
253246854Sdes			return LDNS_STATUS_MEM_ERR;
254246854Sdes		}
255238104Sdes                ldns_rr_set_question(q, 1);
256238104Sdes                ldns_rr_set_ttl(q, 0);
257238104Sdes                ldns_rr_set_owner(q, ldns_rdf_clone(name));
258246854Sdes                if(!ldns_rr_owner(q)) {
259246854Sdes                	ldns_rr_free(q);
260246854Sdes			ldns_rr_list_deep_free(sigs);
261246854Sdes			ldns_rr_list_deep_free(nsecs);
262246854Sdes			return LDNS_STATUS_MEM_ERR;
263246854Sdes		}
264238104Sdes                ldns_rr_set_type(q, type);
265238104Sdes
266238104Sdes                /* result = ldns_dnssec_verify_denial_nsec3(q, nsecs, sigs, ldns_pkt_get_rcode(pkt), type, ldns_pkt_ancount(pkt) == 0); */
267238104Sdes                result = ldns_dnssec_verify_denial_nsec3_match(q, nsecs, sigs, ldns_pkt_get_rcode(pkt), type, ldns_pkt_ancount(pkt) == 0, &match);
268238104Sdes		if (result == LDNS_STATUS_OK && match && nsec_rrs && nsec_rr_sigs) {
269238104Sdes			(void) get_dnssec_rr(pkt, ldns_rr_owner(match), LDNS_RR_TYPE_NSEC3, nsec_rrs, nsec_rr_sigs);
270238104Sdes		}
271238104Sdes                ldns_rr_free(q);
272238104Sdes		ldns_rr_list_deep_free(nsecs);
273238104Sdes		ldns_rr_list_deep_free(sigs);
274238104Sdes        }
275238104Sdes	return result;
276246854Sdes#else
277246854Sdes	(void)pkt;
278246854Sdes	(void)name;
279246854Sdes	(void)type;
280246854Sdes	(void)nsec_rrs;
281246854Sdes	(void)nsec_rr_sigs;
282246854Sdes	return LDNS_STATUS_ERR;
283246854Sdes#endif /* HAVE_SSL */
284238104Sdes}
285238104Sdes
286238104Sdes/* NSEC3 draft -07 */
287238104Sdes/*return hash name match*/
288238104Sdesldns_rr *
289238104Sdesldns_nsec3_exact_match(ldns_rdf *qname, ldns_rr_type qtype, ldns_rr_list *nsec3s) {
290238104Sdes	uint8_t algorithm;
291238104Sdes	uint32_t iterations;
292238104Sdes	uint8_t salt_length;
293238104Sdes	uint8_t *salt;
294238104Sdes
295238104Sdes	ldns_rdf *sname = NULL, *hashed_sname = NULL;
296238104Sdes
297238104Sdes	size_t nsec_i;
298238104Sdes	ldns_rr *nsec;
299238104Sdes	ldns_rr *result = NULL;
300238104Sdes
301238104Sdes	const ldns_rr_descriptor *descriptor;
302238104Sdes
303238104Sdes	ldns_rdf *zone_name = NULL;
304238104Sdes
305238104Sdes	if (verbosity >= 4) {
306238104Sdes		printf(";; finding exact match for ");
307238104Sdes		descriptor = ldns_rr_descript(qtype);
308238104Sdes		if (descriptor && descriptor->_name) {
309238104Sdes			printf("%s ", descriptor->_name);
310238104Sdes		} else {
311238104Sdes			printf("TYPE%d ", qtype);
312238104Sdes		}
313238104Sdes		ldns_rdf_print(stdout, qname);
314238104Sdes		printf("\n");
315238104Sdes	}
316238104Sdes
317238104Sdes	if (!qname || !nsec3s || ldns_rr_list_rr_count(nsec3s) < 1) {
318238104Sdes		if (verbosity >= 4) {
319238104Sdes			printf("no qname, nsec3s or list empty\n");
320238104Sdes		}
321238104Sdes		return NULL;
322238104Sdes	}
323238104Sdes
324238104Sdes	nsec = ldns_rr_list_rr(nsec3s, 0);
325238104Sdes	algorithm = ldns_nsec3_algorithm(nsec);
326238104Sdes	salt_length = ldns_nsec3_salt_length(nsec);
327238104Sdes	salt = ldns_nsec3_salt_data(nsec);
328238104Sdes	iterations = ldns_nsec3_iterations(nsec);
329238104Sdes	if (salt == NULL) {
330238104Sdes		goto done;
331238104Sdes	}
332238104Sdes
333238104Sdes	sname = ldns_rdf_clone(qname);
334238104Sdes	if (sname == NULL) {
335238104Sdes		goto done;
336238104Sdes	}
337238104Sdes	if (verbosity >= 4) {
338238104Sdes		printf(";; owner name hashes to: ");
339238104Sdes	}
340238104Sdes	hashed_sname = ldns_nsec3_hash_name(sname, algorithm, iterations, salt_length, salt);
341238104Sdes	if (hashed_sname == NULL) {
342238104Sdes		goto done;
343238104Sdes	}
344238104Sdes	zone_name = ldns_dname_left_chop(ldns_rr_owner(nsec));
345238104Sdes	if (zone_name == NULL) {
346238104Sdes		goto done;
347238104Sdes	}
348238104Sdes	if (ldns_dname_cat(hashed_sname, zone_name) != LDNS_STATUS_OK) {
349238104Sdes		goto done;
350238104Sdes	};
351238104Sdes
352238104Sdes	if (verbosity >= 4) {
353238104Sdes		ldns_rdf_print(stdout, hashed_sname);
354238104Sdes		printf("\n");
355238104Sdes	}
356238104Sdes
357238104Sdes	for (nsec_i = 0; nsec_i < ldns_rr_list_rr_count(nsec3s); nsec_i++) {
358238104Sdes		nsec = ldns_rr_list_rr(nsec3s, nsec_i);
359238104Sdes
360238104Sdes		/* check values of iterations etc! */
361238104Sdes
362238104Sdes		/* exact match? */
363238104Sdes		if (ldns_dname_compare(ldns_rr_owner(nsec), hashed_sname) == 0) {
364238104Sdes			result = nsec;
365238104Sdes			goto done;
366238104Sdes		}
367238104Sdes
368238104Sdes	}
369238104Sdes
370238104Sdesdone:
371238104Sdes	ldns_rdf_deep_free(zone_name);
372238104Sdes	ldns_rdf_deep_free(sname);
373238104Sdes	ldns_rdf_deep_free(hashed_sname);
374238104Sdes	LDNS_FREE(salt);
375238104Sdes
376238104Sdes	if (verbosity >= 4) {
377238104Sdes		if (result) {
378238104Sdes			printf(";; Found.\n");
379238104Sdes		} else {
380238104Sdes			printf(";; Not foud.\n");
381238104Sdes		}
382238104Sdes	}
383238104Sdes	return result;
384238104Sdes}
385238104Sdes
386238104Sdes/*return the owner name of the closest encloser for name from the list of rrs */
387238104Sdes/* this is NOT the hash, but the original name! */
388238104Sdesldns_rdf *
389238104Sdesldns_nsec3_closest_encloser(ldns_rdf *qname, ldns_rr_type qtype, ldns_rr_list *nsec3s)
390238104Sdes{
391238104Sdes	/* remember parameters, they must match */
392238104Sdes	uint8_t algorithm;
393238104Sdes	uint32_t iterations;
394238104Sdes	uint8_t salt_length;
395238104Sdes	uint8_t *salt;
396238104Sdes
397238104Sdes	ldns_rdf *sname = NULL, *hashed_sname = NULL, *tmp;
398238104Sdes	bool flag;
399238104Sdes
400238104Sdes	bool exact_match_found;
401238104Sdes	bool in_range_found;
402238104Sdes
403238104Sdes	ldns_rdf *zone_name = NULL;
404238104Sdes
405238104Sdes	size_t nsec_i;
406238104Sdes	ldns_rr *nsec;
407238104Sdes	ldns_rdf *result = NULL;
408238104Sdes
409238104Sdes	if (!qname || !nsec3s || ldns_rr_list_rr_count(nsec3s) < 1) {
410238104Sdes		return NULL;
411238104Sdes	}
412238104Sdes
413238104Sdes	if (verbosity >= 4) {
414238104Sdes		printf(";; finding closest encloser for type %d ", qtype);
415238104Sdes		ldns_rdf_print(stdout, qname);
416238104Sdes		printf("\n");
417238104Sdes	}
418238104Sdes
419238104Sdes	nsec = ldns_rr_list_rr(nsec3s, 0);
420238104Sdes	algorithm = ldns_nsec3_algorithm(nsec);
421238104Sdes	salt_length = ldns_nsec3_salt_length(nsec);
422238104Sdes	salt = ldns_nsec3_salt_data(nsec);
423238104Sdes	iterations = ldns_nsec3_iterations(nsec);
424238104Sdes	if (salt == NULL) {
425238104Sdes		goto done;
426238104Sdes	}
427238104Sdes
428238104Sdes	sname = ldns_rdf_clone(qname);
429238104Sdes	if (sname == NULL) {
430238104Sdes		goto done;
431238104Sdes	}
432238104Sdes
433238104Sdes	flag = false;
434238104Sdes
435238104Sdes	zone_name = ldns_dname_left_chop(ldns_rr_owner(nsec));
436238104Sdes	if (zone_name == NULL) {
437238104Sdes		goto done;
438238104Sdes	}
439238104Sdes
440238104Sdes	/* algorithm from nsec3-07 8.3 */
441238104Sdes	while (ldns_dname_label_count(sname) > 0) {
442238104Sdes		exact_match_found = false;
443238104Sdes		in_range_found = false;
444238104Sdes
445238104Sdes		if (verbosity >= 3) {
446238104Sdes			printf(";; ");
447238104Sdes			ldns_rdf_print(stdout, sname);
448238104Sdes			printf(" hashes to: ");
449238104Sdes		}
450238104Sdes		hashed_sname = ldns_nsec3_hash_name(sname, algorithm, iterations, salt_length, salt);
451238104Sdes		if (hashed_sname == NULL) {
452238104Sdes			goto done;
453238104Sdes		}
454238104Sdes
455238104Sdes		if (ldns_dname_cat(hashed_sname, zone_name) != LDNS_STATUS_OK){
456238104Sdes			goto done;
457238104Sdes		}
458238104Sdes
459238104Sdes		if (verbosity >= 3) {
460238104Sdes			ldns_rdf_print(stdout, hashed_sname);
461238104Sdes			printf("\n");
462238104Sdes		}
463238104Sdes
464238104Sdes		for (nsec_i = 0; nsec_i < ldns_rr_list_rr_count(nsec3s); nsec_i++) {
465238104Sdes			nsec = ldns_rr_list_rr(nsec3s, nsec_i);
466238104Sdes
467238104Sdes			/* check values of iterations etc! */
468238104Sdes
469238104Sdes			/* exact match? */
470238104Sdes			if (ldns_dname_compare(ldns_rr_owner(nsec), hashed_sname) == 0) {
471238104Sdes				if (verbosity >= 4) {
472238104Sdes					printf(";; exact match found\n");
473238104Sdes				}
474238104Sdes			 	exact_match_found = true;
475238104Sdes			} else if (ldns_nsec_covers_name(nsec, hashed_sname)) {
476238104Sdes				if (verbosity >= 4) {
477238104Sdes					printf(";; in range of an nsec\n");
478238104Sdes				}
479238104Sdes				in_range_found = true;
480238104Sdes			}
481238104Sdes
482238104Sdes		}
483238104Sdes		if (!exact_match_found && in_range_found) {
484238104Sdes			flag = true;
485238104Sdes		} else if (exact_match_found && flag) {
486238104Sdes			result = ldns_rdf_clone(sname);
487238104Sdes		} else if (exact_match_found && !flag) {
488238104Sdes			// error!
489238104Sdes			if (verbosity >= 4) {
490238104Sdes				printf(";; the closest encloser is the same name (ie. this is an exact match, ie there is no closest encloser)\n");
491238104Sdes			}
492238104Sdes			ldns_rdf_deep_free(hashed_sname);
493238104Sdes			goto done;
494238104Sdes		} else {
495238104Sdes			flag = false;
496238104Sdes		}
497238104Sdes
498238104Sdes		ldns_rdf_deep_free(hashed_sname);
499238104Sdes		tmp = sname;
500238104Sdes		sname = ldns_dname_left_chop(sname);
501238104Sdes		ldns_rdf_deep_free(tmp);
502238104Sdes		if (sname == NULL) {
503238104Sdes			goto done;
504238104Sdes		}
505238104Sdes	}
506238104Sdes
507238104Sdesdone:
508238104Sdes	LDNS_FREE(salt);
509238104Sdes	ldns_rdf_deep_free(zone_name);
510238104Sdes	ldns_rdf_deep_free(sname);
511238104Sdes
512238104Sdes	if (!result) {
513238104Sdes		if (verbosity >= 4) {
514238104Sdes			printf(";; no closest encloser found\n");
515238104Sdes		}
516238104Sdes	}
517238104Sdes
518238104Sdes	/* todo checks from end of 6.2. here or in caller? */
519238104Sdes	return result;
520238104Sdes}
521