1/*
2 * dnssec.c
3 * Some DNSSEC helper function are defined here
4 * and tracing is done
5 * (c) 2005 NLnet Labs
6 *
7 * See the file LICENSE for the license
8 *
9 */
10
11#include "drill.h"
12#include <ldns/ldns.h>
13
14/* get rr_type from a server from a server */
15ldns_rr_list *
16get_rr(ldns_resolver *res, ldns_rdf *zname, ldns_rr_type t, ldns_rr_class c)
17{
18	/* query, retrieve, extract and return */
19	ldns_pkt *p;
20	ldns_rr_list *found;
21
22	p = ldns_pkt_new();
23	found = NULL;
24
25	if (ldns_resolver_send(&p, res, zname, t, c, 0) == LDNS_STATUS_OK) {
26		found = ldns_pkt_rr_list_by_type(p, t, LDNS_SECTION_ANY_NOQUESTION);
27	}
28	ldns_pkt_free(p);
29	return found;
30}
31
32void
33drill_pkt_print(FILE *fd, ldns_resolver *r, ldns_pkt *p)
34{
35	ldns_rr_list *new_nss;
36	ldns_rr_list *hostnames;
37	char *answerfrom_str;
38
39	if (verbosity < 5) {
40		return;
41	}
42
43	hostnames = ldns_get_rr_list_name_by_addr(r, ldns_pkt_answerfrom(p), 0, 0);
44
45	new_nss = ldns_pkt_rr_list_by_type(p,
46			LDNS_RR_TYPE_NS, LDNS_SECTION_ANSWER);
47	ldns_rr_list_print(fd, new_nss);
48	ldns_rr_list_deep_free(new_nss);
49
50	fprintf(fd, ";; Received %d bytes from %s#%d(",
51			(int) ldns_pkt_size(p),
52			ldns_rdf2str(ldns_pkt_answerfrom(p)),
53			(int) ldns_resolver_port(r));
54	/* if we can resolve this print it, other print the ip again */
55	if (hostnames) {
56		ldns_rdf_print(fd,
57				ldns_rr_rdf(ldns_rr_list_rr(hostnames, 0), 0));
58		ldns_rr_list_deep_free(hostnames);
59	} else {
60		answerfrom_str = ldns_rdf2str(ldns_pkt_answerfrom(p));
61		if (answerfrom_str) {
62			fprintf(fd, "%s", answerfrom_str);
63			LDNS_FREE(answerfrom_str);
64		}
65	}
66	fprintf(fd, ") in %u ms\n\n", (unsigned int)ldns_pkt_querytime(p));
67}
68
69void
70drill_pkt_print_footer(FILE *fd, ldns_resolver *r, ldns_pkt *p)
71{
72	ldns_rr_list *hostnames;
73	char *answerfrom_str;
74
75	if (verbosity < 5) {
76		return;
77	}
78
79	hostnames = ldns_get_rr_list_name_by_addr(r, ldns_pkt_answerfrom(p), 0, 0);
80
81	fprintf(fd, ";; Received %d bytes from %s#%d(",
82			(int) ldns_pkt_size(p),
83			ldns_rdf2str(ldns_pkt_answerfrom(p)),
84			(int) ldns_resolver_port(r));
85	/* if we can resolve this print it, other print the ip again */
86	if (hostnames) {
87		ldns_rdf_print(fd,
88				ldns_rr_rdf(ldns_rr_list_rr(hostnames, 0), 0));
89		ldns_rr_list_deep_free(hostnames);
90	} else {
91		answerfrom_str = ldns_rdf2str(ldns_pkt_answerfrom(p));
92		if (answerfrom_str) {
93			fprintf(fd, "%s", answerfrom_str);
94			LDNS_FREE(answerfrom_str);
95		}
96	}
97	fprintf(fd, ") in %u ms\n\n", (unsigned int)ldns_pkt_querytime(p));
98}
99/*
100 * generic function to get some RRset from a nameserver
101 * and possible some signatures too (that would be the day...)
102 */
103ldns_pkt_type
104get_dnssec_rr(ldns_pkt *p, ldns_rdf *name, ldns_rr_type t,
105	ldns_rr_list **rrlist, ldns_rr_list **sig)
106{
107	ldns_pkt_type pt = LDNS_PACKET_UNKNOWN;
108	ldns_rr_list *sigs = NULL;
109	size_t i;
110
111	if (!p) {
112		if (rrlist) {
113			*rrlist = NULL;
114		}
115		return LDNS_PACKET_UNKNOWN;
116	}
117
118	pt = ldns_pkt_reply_type(p);
119	if (name) {
120		if (rrlist) {
121			*rrlist = ldns_pkt_rr_list_by_name_and_type(p, name, t,
122					LDNS_SECTION_ANSWER);
123			if (!*rrlist) {
124				*rrlist = ldns_pkt_rr_list_by_name_and_type(
125						p, name, t,
126						LDNS_SECTION_AUTHORITY);
127			}
128		}
129		if (sig) {
130			sigs = ldns_pkt_rr_list_by_name_and_type(p, name,
131					LDNS_RR_TYPE_RRSIG,
132					LDNS_SECTION_ANSWER);
133			if (!sigs) {
134				sigs = ldns_pkt_rr_list_by_name_and_type(
135						p, name, LDNS_RR_TYPE_RRSIG,
136						LDNS_SECTION_AUTHORITY);
137			}
138		}
139	} else {
140		/* A DS-referral - get the DS records if they are there */
141		if (rrlist) {
142			*rrlist = ldns_pkt_rr_list_by_type(
143					p, t, LDNS_SECTION_AUTHORITY);
144		}
145		if (sig) {
146			sigs = ldns_pkt_rr_list_by_type(p,
147					LDNS_RR_TYPE_RRSIG,
148					LDNS_SECTION_AUTHORITY);
149		}
150	}
151	if (sig) {
152		*sig = ldns_rr_list_new();
153		for (i = 0; i < ldns_rr_list_rr_count(sigs); i++) {
154			/* only add the sigs that cover this type */
155			if (t == ldns_rdf2rr_type(ldns_rr_rrsig_typecovered(
156						ldns_rr_list_rr(sigs, i)))) {
157
158				ldns_rr_list_push_rr(*sig,
159						ldns_rr_clone(
160							ldns_rr_list_rr(
161								sigs, i)));
162			}
163		}
164	}
165	ldns_rr_list_deep_free(sigs);
166
167	if (pt == LDNS_PACKET_NXDOMAIN || pt == LDNS_PACKET_NODATA) {
168		return pt;
169	} else {
170		return LDNS_PACKET_ANSWER;
171	}
172}
173
174
175ldns_status
176ldns_verify_denial(ldns_pkt *pkt, ldns_rdf *name, ldns_rr_type type, ldns_rr_list **nsec_rrs, ldns_rr_list **nsec_rr_sigs)
177{
178#ifdef HAVE_SSL
179	uint16_t nsec_i;
180
181	ldns_rr_list *nsecs;
182	ldns_status result;
183
184	if (verbosity >= 5) {
185		printf("VERIFY DENIAL FROM:\n");
186		ldns_pkt_print(stdout, pkt);
187	}
188
189	result = LDNS_STATUS_CRYPTO_NO_RRSIG;
190	/* Try to see if there are NSECS in the packet */
191	nsecs = ldns_pkt_rr_list_by_type(pkt, LDNS_RR_TYPE_NSEC, LDNS_SECTION_ANY_NOQUESTION);
192	if (nsecs) {
193		for (nsec_i = 0; nsec_i < ldns_rr_list_rr_count(nsecs); nsec_i++) {
194			/* there are four options:
195			 * - name equals ownername and is covered by the type bitmap
196			 * - name equals ownername but is not covered by the type bitmap
197			 * - name falls within nsec coverage but is not equal to the owner name
198			 * - name falls outside of nsec coverage
199			 */
200			if (ldns_dname_compare(ldns_rr_owner(ldns_rr_list_rr(nsecs, nsec_i)), name) == 0) {
201				/*
202				printf("CHECKING NSEC:\n");
203				ldns_rr_print(stdout, ldns_rr_list_rr(nsecs, nsec_i));
204				printf("DAWASEM\n");
205				*/
206				if (ldns_nsec_bitmap_covers_type(
207					   ldns_nsec_get_bitmap(ldns_rr_list_rr(nsecs,
208													nsec_i)),
209					   type)) {
210					/* Error, according to the nsec this rrset is signed */
211					result = LDNS_STATUS_CRYPTO_NO_RRSIG;
212				} else {
213					/* ok nsec denies existence */
214					if (verbosity >= 3) {
215						printf(";; Existence of data set with this type denied by NSEC\n");
216					}
217						/*printf(";; Verifiably insecure.\n");*/
218						if (nsec_rrs && nsec_rr_sigs) {
219							(void) get_dnssec_rr(pkt, ldns_rr_owner(ldns_rr_list_rr(nsecs, nsec_i)), LDNS_RR_TYPE_NSEC, nsec_rrs, nsec_rr_sigs);
220						}
221						ldns_rr_list_deep_free(nsecs);
222						return LDNS_STATUS_OK;
223				}
224			} else if (ldns_nsec_covers_name(ldns_rr_list_rr(nsecs, nsec_i), name)) {
225				if (verbosity >= 3) {
226					printf(";; Existence of data set with this name denied by NSEC\n");
227				}
228				if (nsec_rrs && nsec_rr_sigs) {
229					(void) get_dnssec_rr(pkt, ldns_rr_owner(ldns_rr_list_rr(nsecs, nsec_i)), LDNS_RR_TYPE_NSEC, nsec_rrs, nsec_rr_sigs);
230				}
231				ldns_rr_list_deep_free(nsecs);
232				return LDNS_STATUS_OK;
233			} else {
234				/* nsec has nothing to do with this data */
235			}
236		}
237		ldns_rr_list_deep_free(nsecs);
238	} else if( (nsecs = ldns_pkt_rr_list_by_type(pkt, LDNS_RR_TYPE_NSEC3, LDNS_SECTION_ANY_NOQUESTION)) ) {
239                ldns_rr_list* sigs = ldns_pkt_rr_list_by_type(pkt, LDNS_RR_TYPE_RRSIG, LDNS_SECTION_ANY_NOQUESTION);
240                ldns_rr* q = ldns_rr_new();
241		ldns_rr* match = NULL;
242
243                if(!sigs) {
244			if (q) {
245                		ldns_rr_free(q);
246			}
247			ldns_rr_list_deep_free(nsecs);
248			return LDNS_STATUS_MEM_ERR;
249		}
250                if(!q) {
251			ldns_rr_list_deep_free(nsecs);
252			ldns_rr_list_deep_free(sigs);
253			return LDNS_STATUS_MEM_ERR;
254		}
255                ldns_rr_set_question(q, 1);
256                ldns_rr_set_ttl(q, 0);
257                ldns_rr_set_owner(q, ldns_rdf_clone(name));
258                if(!ldns_rr_owner(q)) {
259                	ldns_rr_free(q);
260			ldns_rr_list_deep_free(sigs);
261			ldns_rr_list_deep_free(nsecs);
262			return LDNS_STATUS_MEM_ERR;
263		}
264                ldns_rr_set_type(q, type);
265
266                /* result = ldns_dnssec_verify_denial_nsec3(q, nsecs, sigs, ldns_pkt_get_rcode(pkt), type, ldns_pkt_ancount(pkt) == 0); */
267                result = ldns_dnssec_verify_denial_nsec3_match(q, nsecs, sigs, ldns_pkt_get_rcode(pkt), type, ldns_pkt_ancount(pkt) == 0, &match);
268		if (result == LDNS_STATUS_OK && match && nsec_rrs && nsec_rr_sigs) {
269			(void) get_dnssec_rr(pkt, ldns_rr_owner(match), LDNS_RR_TYPE_NSEC3, nsec_rrs, nsec_rr_sigs);
270		}
271                ldns_rr_free(q);
272		ldns_rr_list_deep_free(nsecs);
273		ldns_rr_list_deep_free(sigs);
274        }
275	return result;
276#else
277	(void)pkt;
278	(void)name;
279	(void)type;
280	(void)nsec_rrs;
281	(void)nsec_rr_sigs;
282	return LDNS_STATUS_ERR;
283#endif /* HAVE_SSL */
284}
285
286/* NSEC3 draft -07 */
287/*return hash name match*/
288ldns_rr *
289ldns_nsec3_exact_match(ldns_rdf *qname, ldns_rr_type qtype, ldns_rr_list *nsec3s) {
290	uint8_t algorithm;
291	uint32_t iterations;
292	uint8_t salt_length;
293	uint8_t *salt;
294
295	ldns_rdf *sname = NULL, *hashed_sname = NULL;
296
297	size_t nsec_i;
298	ldns_rr *nsec;
299	ldns_rr *result = NULL;
300
301	const ldns_rr_descriptor *descriptor;
302
303	ldns_rdf *zone_name = NULL;
304
305	if (verbosity >= 4) {
306		printf(";; finding exact match for ");
307		descriptor = ldns_rr_descript(qtype);
308		if (descriptor && descriptor->_name) {
309			printf("%s ", descriptor->_name);
310		} else {
311			printf("TYPE%d ", qtype);
312		}
313		ldns_rdf_print(stdout, qname);
314		printf("\n");
315	}
316
317	if (!qname || !nsec3s || ldns_rr_list_rr_count(nsec3s) < 1) {
318		if (verbosity >= 4) {
319			printf("no qname, nsec3s or list empty\n");
320		}
321		return NULL;
322	}
323
324	nsec = ldns_rr_list_rr(nsec3s, 0);
325	algorithm = ldns_nsec3_algorithm(nsec);
326	salt_length = ldns_nsec3_salt_length(nsec);
327	salt = ldns_nsec3_salt_data(nsec);
328	iterations = ldns_nsec3_iterations(nsec);
329	if (salt == NULL) {
330		goto done;
331	}
332
333	sname = ldns_rdf_clone(qname);
334	if (sname == NULL) {
335		goto done;
336	}
337	if (verbosity >= 4) {
338		printf(";; owner name hashes to: ");
339	}
340	hashed_sname = ldns_nsec3_hash_name(sname, algorithm, iterations, salt_length, salt);
341	if (hashed_sname == NULL) {
342		goto done;
343	}
344	zone_name = ldns_dname_left_chop(ldns_rr_owner(nsec));
345	if (zone_name == NULL) {
346		goto done;
347	}
348	if (ldns_dname_cat(hashed_sname, zone_name) != LDNS_STATUS_OK) {
349		goto done;
350	};
351
352	if (verbosity >= 4) {
353		ldns_rdf_print(stdout, hashed_sname);
354		printf("\n");
355	}
356
357	for (nsec_i = 0; nsec_i < ldns_rr_list_rr_count(nsec3s); nsec_i++) {
358		nsec = ldns_rr_list_rr(nsec3s, nsec_i);
359
360		/* check values of iterations etc! */
361
362		/* exact match? */
363		if (ldns_dname_compare(ldns_rr_owner(nsec), hashed_sname) == 0) {
364			result = nsec;
365			goto done;
366		}
367
368	}
369
370done:
371	ldns_rdf_deep_free(zone_name);
372	ldns_rdf_deep_free(sname);
373	ldns_rdf_deep_free(hashed_sname);
374	LDNS_FREE(salt);
375
376	if (verbosity >= 4) {
377		if (result) {
378			printf(";; Found.\n");
379		} else {
380			printf(";; Not foud.\n");
381		}
382	}
383	return result;
384}
385
386/*return the owner name of the closest encloser for name from the list of rrs */
387/* this is NOT the hash, but the original name! */
388ldns_rdf *
389ldns_nsec3_closest_encloser(ldns_rdf *qname, ldns_rr_type qtype, ldns_rr_list *nsec3s)
390{
391	/* remember parameters, they must match */
392	uint8_t algorithm;
393	uint32_t iterations;
394	uint8_t salt_length;
395	uint8_t *salt;
396
397	ldns_rdf *sname = NULL, *hashed_sname = NULL, *tmp;
398	bool flag;
399
400	bool exact_match_found;
401	bool in_range_found;
402
403	ldns_rdf *zone_name = NULL;
404
405	size_t nsec_i;
406	ldns_rr *nsec;
407	ldns_rdf *result = NULL;
408
409	if (!qname || !nsec3s || ldns_rr_list_rr_count(nsec3s) < 1) {
410		return NULL;
411	}
412
413	if (verbosity >= 4) {
414		printf(";; finding closest encloser for type %d ", qtype);
415		ldns_rdf_print(stdout, qname);
416		printf("\n");
417	}
418
419	nsec = ldns_rr_list_rr(nsec3s, 0);
420	algorithm = ldns_nsec3_algorithm(nsec);
421	salt_length = ldns_nsec3_salt_length(nsec);
422	salt = ldns_nsec3_salt_data(nsec);
423	iterations = ldns_nsec3_iterations(nsec);
424	if (salt == NULL) {
425		goto done;
426	}
427
428	sname = ldns_rdf_clone(qname);
429	if (sname == NULL) {
430		goto done;
431	}
432
433	flag = false;
434
435	zone_name = ldns_dname_left_chop(ldns_rr_owner(nsec));
436	if (zone_name == NULL) {
437		goto done;
438	}
439
440	/* algorithm from nsec3-07 8.3 */
441	while (ldns_dname_label_count(sname) > 0) {
442		exact_match_found = false;
443		in_range_found = false;
444
445		if (verbosity >= 3) {
446			printf(";; ");
447			ldns_rdf_print(stdout, sname);
448			printf(" hashes to: ");
449		}
450		hashed_sname = ldns_nsec3_hash_name(sname, algorithm, iterations, salt_length, salt);
451		if (hashed_sname == NULL) {
452			goto done;
453		}
454
455		if (ldns_dname_cat(hashed_sname, zone_name) != LDNS_STATUS_OK){
456			goto done;
457		}
458
459		if (verbosity >= 3) {
460			ldns_rdf_print(stdout, hashed_sname);
461			printf("\n");
462		}
463
464		for (nsec_i = 0; nsec_i < ldns_rr_list_rr_count(nsec3s); nsec_i++) {
465			nsec = ldns_rr_list_rr(nsec3s, nsec_i);
466
467			/* check values of iterations etc! */
468
469			/* exact match? */
470			if (ldns_dname_compare(ldns_rr_owner(nsec), hashed_sname) == 0) {
471				if (verbosity >= 4) {
472					printf(";; exact match found\n");
473				}
474			 	exact_match_found = true;
475			} else if (ldns_nsec_covers_name(nsec, hashed_sname)) {
476				if (verbosity >= 4) {
477					printf(";; in range of an nsec\n");
478				}
479				in_range_found = true;
480			}
481
482		}
483		if (!exact_match_found && in_range_found) {
484			flag = true;
485		} else if (exact_match_found && flag) {
486			result = ldns_rdf_clone(sname);
487		} else if (exact_match_found && !flag) {
488			// error!
489			if (verbosity >= 4) {
490				printf(";; the closest encloser is the same name (ie. this is an exact match, ie there is no closest encloser)\n");
491			}
492			ldns_rdf_deep_free(hashed_sname);
493			goto done;
494		} else {
495			flag = false;
496		}
497
498		ldns_rdf_deep_free(hashed_sname);
499		tmp = sname;
500		sname = ldns_dname_left_chop(sname);
501		ldns_rdf_deep_free(tmp);
502		if (sname == NULL) {
503			goto done;
504		}
505	}
506
507done:
508	LDNS_FREE(salt);
509	ldns_rdf_deep_free(zone_name);
510	ldns_rdf_deep_free(sname);
511
512	if (!result) {
513		if (verbosity >= 4) {
514			printf(";; no closest encloser found\n");
515		}
516	}
517
518	/* todo checks from end of 6.2. here or in caller? */
519	return result;
520}
521