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	const ldns_rr_descriptor *descriptor;
184
185	if (!pkt) {
186		descriptor = ldns_rr_descript(type);
187
188		printf("NETWORk ERROR! Cannot verify denial for: ");
189		ldns_rdf_print(stdout, name);
190		printf(" type ");
191		if (descriptor && descriptor->_name)
192			printf("%s", descriptor->_name);
193		else
194			printf("TYPE%u", type);
195		return LDNS_STATUS_CRYPTO_NO_RRSIG;
196	}
197	if (verbosity >= 5) {
198		printf("VERIFY DENIAL FROM:\n");
199		ldns_pkt_print(stdout, pkt);
200	}
201
202	result = LDNS_STATUS_CRYPTO_NO_RRSIG;
203	/* Try to see if there are NSECS in the packet */
204	nsecs = ldns_pkt_rr_list_by_type(pkt, LDNS_RR_TYPE_NSEC, LDNS_SECTION_ANY_NOQUESTION);
205	if (nsecs) {
206		for (nsec_i = 0; nsec_i < ldns_rr_list_rr_count(nsecs); nsec_i++) {
207			/* there are four options:
208			 * - name equals ownername and is covered by the type bitmap
209			 * - name equals ownername but is not covered by the type bitmap
210			 * - name falls within nsec coverage but is not equal to the owner name
211			 * - name falls outside of nsec coverage
212			 */
213			if (ldns_dname_compare(ldns_rr_owner(ldns_rr_list_rr(nsecs, nsec_i)), name) == 0) {
214				/*
215				printf("CHECKING NSEC:\n");
216				ldns_rr_print(stdout, ldns_rr_list_rr(nsecs, nsec_i));
217				printf("DAWASEM\n");
218				*/
219				if (ldns_nsec_bitmap_covers_type(
220					   ldns_nsec_get_bitmap(ldns_rr_list_rr(nsecs,
221													nsec_i)),
222					   type)) {
223					/* Error, according to the nsec this rrset is signed */
224					result = LDNS_STATUS_CRYPTO_NO_RRSIG;
225				} else {
226					/* ok nsec denies existence */
227					if (verbosity >= 3) {
228						printf(";; Existence of data set with this type denied by NSEC\n");
229					}
230						/*printf(";; Verifiably insecure.\n");*/
231						if (nsec_rrs && nsec_rr_sigs) {
232							(void) get_dnssec_rr(pkt, ldns_rr_owner(ldns_rr_list_rr(nsecs, nsec_i)), LDNS_RR_TYPE_NSEC, nsec_rrs, nsec_rr_sigs);
233						}
234						ldns_rr_list_deep_free(nsecs);
235						return LDNS_STATUS_OK;
236				}
237			} else if (ldns_nsec_covers_name(ldns_rr_list_rr(nsecs, nsec_i), name)) {
238				if (verbosity >= 3) {
239					printf(";; Existence of data set with this name denied by NSEC\n");
240				}
241				if (nsec_rrs && nsec_rr_sigs) {
242					(void) get_dnssec_rr(pkt, ldns_rr_owner(ldns_rr_list_rr(nsecs, nsec_i)), LDNS_RR_TYPE_NSEC, nsec_rrs, nsec_rr_sigs);
243				}
244				ldns_rr_list_deep_free(nsecs);
245				return LDNS_STATUS_OK;
246			} else {
247				/* nsec has nothing to do with this data */
248			}
249		}
250		ldns_rr_list_deep_free(nsecs);
251	} else if( (nsecs = ldns_pkt_rr_list_by_type(pkt, LDNS_RR_TYPE_NSEC3, LDNS_SECTION_ANY_NOQUESTION)) ) {
252                ldns_rr_list* sigs = ldns_pkt_rr_list_by_type(pkt, LDNS_RR_TYPE_RRSIG, LDNS_SECTION_ANY_NOQUESTION);
253                ldns_rr* q = ldns_rr_new();
254		ldns_rr* match = NULL;
255
256                if(!sigs) {
257			if (q) {
258                		ldns_rr_free(q);
259			}
260			ldns_rr_list_deep_free(nsecs);
261			return LDNS_STATUS_MEM_ERR;
262		}
263                if(!q) {
264			ldns_rr_list_deep_free(nsecs);
265			ldns_rr_list_deep_free(sigs);
266			return LDNS_STATUS_MEM_ERR;
267		}
268                ldns_rr_set_question(q, 1);
269                ldns_rr_set_ttl(q, 0);
270                ldns_rr_set_owner(q, ldns_rdf_clone(name));
271                if(!ldns_rr_owner(q)) {
272                	ldns_rr_free(q);
273			ldns_rr_list_deep_free(sigs);
274			ldns_rr_list_deep_free(nsecs);
275			return LDNS_STATUS_MEM_ERR;
276		}
277                ldns_rr_set_type(q, type);
278
279                /* result = ldns_dnssec_verify_denial_nsec3(q, nsecs, sigs, ldns_pkt_get_rcode(pkt), type, ldns_pkt_ancount(pkt) == 0); */
280                result = ldns_dnssec_verify_denial_nsec3_match(q, nsecs, sigs, ldns_pkt_get_rcode(pkt), type, ldns_pkt_ancount(pkt) == 0, &match);
281		if (result == LDNS_STATUS_OK && match && nsec_rrs && nsec_rr_sigs) {
282			(void) get_dnssec_rr(pkt, ldns_rr_owner(match), LDNS_RR_TYPE_NSEC3, nsec_rrs, nsec_rr_sigs);
283		}
284                ldns_rr_free(q);
285		ldns_rr_list_deep_free(nsecs);
286		ldns_rr_list_deep_free(sigs);
287        }
288	return result;
289#else
290	(void)pkt;
291	(void)name;
292	(void)type;
293	(void)nsec_rrs;
294	(void)nsec_rr_sigs;
295	return LDNS_STATUS_ERR;
296#endif /* HAVE_SSL */
297}
298
299/* NSEC3 draft -07 */
300/*return hash name match*/
301ldns_rr *
302ldns_nsec3_exact_match(ldns_rdf *qname, ldns_rr_type qtype, ldns_rr_list *nsec3s) {
303	uint8_t algorithm;
304	uint32_t iterations;
305	uint8_t salt_length;
306	uint8_t *salt;
307
308	ldns_rdf *sname = NULL, *hashed_sname = NULL;
309
310	size_t nsec_i;
311	ldns_rr *nsec;
312	ldns_rr *result = NULL;
313
314	const ldns_rr_descriptor *descriptor;
315
316	ldns_rdf *zone_name = NULL;
317
318	if (verbosity >= 4) {
319		printf(";; finding exact match for ");
320		descriptor = ldns_rr_descript(qtype);
321		if (descriptor && descriptor->_name) {
322			printf("%s ", descriptor->_name);
323		} else {
324			printf("TYPE%d ", qtype);
325		}
326		ldns_rdf_print(stdout, qname);
327		printf("\n");
328	}
329
330	if (!qname || !nsec3s || ldns_rr_list_rr_count(nsec3s) < 1) {
331		if (verbosity >= 4) {
332			printf("no qname, nsec3s or list empty\n");
333		}
334		return NULL;
335	}
336
337	nsec = ldns_rr_list_rr(nsec3s, 0);
338	algorithm = ldns_nsec3_algorithm(nsec);
339	salt_length = ldns_nsec3_salt_length(nsec);
340	salt = ldns_nsec3_salt_data(nsec);
341	iterations = ldns_nsec3_iterations(nsec);
342	if (salt == NULL) {
343		goto done;
344	}
345
346	sname = ldns_rdf_clone(qname);
347	if (sname == NULL) {
348		goto done;
349	}
350	if (verbosity >= 4) {
351		printf(";; owner name hashes to: ");
352	}
353	hashed_sname = ldns_nsec3_hash_name(sname, algorithm, iterations, salt_length, salt);
354	if (hashed_sname == NULL) {
355		goto done;
356	}
357	zone_name = ldns_dname_left_chop(ldns_rr_owner(nsec));
358	if (zone_name == NULL) {
359		goto done;
360	}
361	if (ldns_dname_cat(hashed_sname, zone_name) != LDNS_STATUS_OK) {
362		goto done;
363	};
364
365	if (verbosity >= 4) {
366		ldns_rdf_print(stdout, hashed_sname);
367		printf("\n");
368	}
369
370	for (nsec_i = 0; nsec_i < ldns_rr_list_rr_count(nsec3s); nsec_i++) {
371		nsec = ldns_rr_list_rr(nsec3s, nsec_i);
372
373		/* check values of iterations etc! */
374
375		/* exact match? */
376		if (ldns_dname_compare(ldns_rr_owner(nsec), hashed_sname) == 0) {
377			result = nsec;
378			goto done;
379		}
380
381	}
382
383done:
384	ldns_rdf_deep_free(zone_name);
385	ldns_rdf_deep_free(sname);
386	ldns_rdf_deep_free(hashed_sname);
387	LDNS_FREE(salt);
388
389	if (verbosity >= 4) {
390		if (result) {
391			printf(";; Found.\n");
392		} else {
393			printf(";; Not foud.\n");
394		}
395	}
396	return result;
397}
398
399/*return the owner name of the closest encloser for name from the list of rrs */
400/* this is NOT the hash, but the original name! */
401ldns_rdf *
402ldns_nsec3_closest_encloser(ldns_rdf *qname, ldns_rr_type qtype, ldns_rr_list *nsec3s)
403{
404	/* remember parameters, they must match */
405	uint8_t algorithm;
406	uint32_t iterations;
407	uint8_t salt_length;
408	uint8_t *salt;
409
410	ldns_rdf *sname = NULL, *hashed_sname = NULL, *tmp;
411	bool flag;
412
413	bool exact_match_found;
414	bool in_range_found;
415
416	ldns_rdf *zone_name = NULL;
417
418	size_t nsec_i;
419	ldns_rr *nsec;
420	ldns_rdf *result = NULL;
421
422	if (!qname || !nsec3s || ldns_rr_list_rr_count(nsec3s) < 1) {
423		return NULL;
424	}
425
426	if (verbosity >= 4) {
427		printf(";; finding closest encloser for type %d ", qtype);
428		ldns_rdf_print(stdout, qname);
429		printf("\n");
430	}
431
432	nsec = ldns_rr_list_rr(nsec3s, 0);
433	algorithm = ldns_nsec3_algorithm(nsec);
434	salt_length = ldns_nsec3_salt_length(nsec);
435	salt = ldns_nsec3_salt_data(nsec);
436	iterations = ldns_nsec3_iterations(nsec);
437	if (salt == NULL) {
438		goto done;
439	}
440
441	sname = ldns_rdf_clone(qname);
442	if (sname == NULL) {
443		goto done;
444	}
445
446	flag = false;
447
448	zone_name = ldns_dname_left_chop(ldns_rr_owner(nsec));
449	if (zone_name == NULL) {
450		goto done;
451	}
452
453	/* algorithm from nsec3-07 8.3 */
454	while (ldns_dname_label_count(sname) > 0) {
455		exact_match_found = false;
456		in_range_found = false;
457
458		if (verbosity >= 3) {
459			printf(";; ");
460			ldns_rdf_print(stdout, sname);
461			printf(" hashes to: ");
462		}
463		hashed_sname = ldns_nsec3_hash_name(sname, algorithm, iterations, salt_length, salt);
464		if (hashed_sname == NULL) {
465			goto done;
466		}
467
468		if (ldns_dname_cat(hashed_sname, zone_name) != LDNS_STATUS_OK){
469			ldns_rdf_deep_free(hashed_sname);
470			goto done;
471		}
472
473		if (verbosity >= 3) {
474			ldns_rdf_print(stdout, hashed_sname);
475			printf("\n");
476		}
477
478		for (nsec_i = 0; nsec_i < ldns_rr_list_rr_count(nsec3s); nsec_i++) {
479			nsec = ldns_rr_list_rr(nsec3s, nsec_i);
480
481			/* check values of iterations etc! */
482
483			/* exact match? */
484			if (ldns_dname_compare(ldns_rr_owner(nsec), hashed_sname) == 0) {
485				if (verbosity >= 4) {
486					printf(";; exact match found\n");
487				}
488			 	exact_match_found = true;
489			} else if (ldns_nsec_covers_name(nsec, hashed_sname)) {
490				if (verbosity >= 4) {
491					printf(";; in range of an nsec\n");
492				}
493				in_range_found = true;
494			}
495
496		}
497		if (!exact_match_found && in_range_found) {
498			flag = true;
499		} else if (exact_match_found && flag) {
500			result = ldns_rdf_clone(sname);
501		} else if (exact_match_found && !flag) {
502			// error!
503			if (verbosity >= 4) {
504				printf(";; the closest encloser is the same name (ie. this is an exact match, ie there is no closest encloser)\n");
505			}
506			ldns_rdf_deep_free(hashed_sname);
507			goto done;
508		} else {
509			flag = false;
510		}
511
512		ldns_rdf_deep_free(hashed_sname);
513		tmp = sname;
514		sname = ldns_dname_left_chop(sname);
515		ldns_rdf_deep_free(tmp);
516		if (sname == NULL) {
517			goto done;
518		}
519	}
520
521done:
522	LDNS_FREE(salt);
523	ldns_rdf_deep_free(zone_name);
524	ldns_rdf_deep_free(sname);
525
526	if (!result) {
527		if (verbosity >= 4) {
528			printf(";; no closest encloser found\n");
529		}
530	}
531
532	/* todo checks from end of 6.2. here or in caller? */
533	return result;
534}
535