1 /*
2  * ldns-keyfetcher retrieves the DNSKEYS for a certain domain
3  * It traces the authoritative nameservers down from the root
4  * And uses TCP, to minimize spoofing danger.
5  *
6  * (c) NLnet Labs, 2006 - 2008
7  * See the file LICENSE for the license
8  */
9 
10 #include "config.h"
11 #include <ldns/ldns.h>
12 #include <errno.h>
13 
14 int verbosity = 0;
15 /* 0=use both ip4 and ip6 (default). 1=ip4only. 2=ip6only. */
16 uint8_t address_family = 0;
17 bool store_in_file = false;
18 
19 static void
usage(FILE * fp,char * prog)20 usage(FILE *fp, char *prog) {
21 	fprintf(fp, "%s domain\n", prog);
22 	fprintf(fp, "  retrieve the dnskeys for a domain\n");
23 	fprintf(fp, "Options:\n");
24 	fprintf(fp, "-4\t\tUse IPv4 only\n");
25 	fprintf(fp, "-6\t\tUse IPv6 only\n");
26 	fprintf(fp, "-h\t\tShow this help\n");
27 	fprintf(fp, "-i\t\tInsecurer mode; don't do checks, just query for the keys\n");
28 	fprintf(fp, "-r <file>\tUse file to read root hints from\n");
29 	fprintf(fp, "-s\t\tDon't print the keys but store them in files\n\t\tcalled K<file>.+<alg>.+<keytag>.key\n");
30 	fprintf(fp, "-v <int>\tVerbosity level (0-5, not verbose-very verbose)\n");
31 }
32 
33 static ldns_rr_list *
retrieve_dnskeys(ldns_resolver * local_res,ldns_rdf * name,ldns_rr_type t,ldns_rr_class c,ldns_rr_list * dns_root)34 retrieve_dnskeys(ldns_resolver *local_res, ldns_rdf *name, ldns_rr_type t,
35 		ldns_rr_class c, ldns_rr_list *dns_root)
36 {
37 	ldns_resolver *res;
38 	ldns_pkt *p;
39 	ldns_rr_list *new_nss_a;
40 	ldns_rr_list *new_nss_aaaa;
41 	ldns_rr_list *new_nss;
42 	ldns_rr_list *ns_addr;
43 	ldns_rr_list *ns_addr2;
44 	uint16_t loop_count;
45 	ldns_rdf *pop;
46 	ldns_status status;
47 	size_t i;
48 
49 	size_t nss_i;
50 	ldns_rr_list *answer_list = NULL;
51 	ldns_rr_list *authority_list = NULL;
52 
53 	size_t last_nameserver_count;
54 	ldns_rdf **last_nameservers;
55 
56 	loop_count = 0;
57 	new_nss_a = NULL;
58 	new_nss_aaaa = NULL;
59 	new_nss = NULL;
60 	ns_addr = NULL;
61 	ns_addr2 = NULL;
62 	p = ldns_pkt_new();
63 	res = ldns_resolver_new();
64 
65 	if (!p || !res) {
66                 fprintf(stderr, "Memory allocation failed");
67                 return NULL;
68         }
69 
70 	if (verbosity >= 2) {
71 		printf("Finding dnskey data for zone: ");
72 		ldns_rdf_print(stdout, name);
73 		printf("\n\n");
74 	}
75 
76 	/* transfer some properties of local_res to res,
77 	 * because they were given on the command line */
78 	ldns_resolver_set_ip6(res,
79 			ldns_resolver_ip6(local_res));
80 	ldns_resolver_set_port(res,
81 			ldns_resolver_port(local_res));
82 	ldns_resolver_set_debug(res,
83 			ldns_resolver_debug(local_res));
84 	ldns_resolver_set_dnssec(res,
85 			ldns_resolver_dnssec(local_res));
86 	ldns_resolver_set_fail(res,
87 			ldns_resolver_fail(local_res));
88 	ldns_resolver_set_usevc(res,
89 			ldns_resolver_usevc(local_res));
90 	ldns_resolver_set_random(res,
91 			ldns_resolver_random(local_res));
92 	ldns_resolver_set_recursive(res, false);
93 
94 	/* setup the root nameserver in the new resolver */
95 	status = ldns_resolver_push_nameserver_rr_list(res, dns_root);
96 	if (status != LDNS_STATUS_OK) {
97 		fprintf(stderr, "Error setting root nameservers in resolver: %s\n", ldns_get_errorstr_by_id(status));
98 		return NULL;
99 	}
100 
101 	ldns_pkt_free(p);
102 	status = ldns_resolver_send(&p, res, name, t, c, 0);
103 	if (status != LDNS_STATUS_OK) {
104 		fprintf(stderr, "Error querying root servers: %s\n", ldns_get_errorstr_by_id(status));
105 		return NULL;
106 	}
107 
108 	if (ldns_pkt_get_rcode(p) != LDNS_RCODE_NOERROR) {
109 		printf("Error in packet:\n");
110 		ldns_pkt_print(stdout, p);
111 		return NULL;
112 	}
113 
114 	if (verbosity >= 4) {
115 		ldns_pkt_print(stdout, p);
116 		printf("\n\n");
117 	}
118 
119 	/* from now on, use TCP */
120 	ldns_resolver_set_usevc(res, true);
121 
122 	while(status == LDNS_STATUS_OK &&
123 	      ldns_pkt_reply_type(p) == LDNS_PACKET_REFERRAL) {
124 
125 		if (verbosity >= 3) {
126 			printf("This is a delegation!\n\n");
127 		}
128 		if (address_family == 0 || address_family == 1) {
129 			new_nss_a = ldns_pkt_rr_list_by_type(p,
130 					LDNS_RR_TYPE_A, LDNS_SECTION_ADDITIONAL);
131 		} else {
132 			new_nss_a = ldns_rr_list_new();
133 		}
134 		if (address_family == 0 || address_family == 2) {
135 			new_nss_aaaa = ldns_pkt_rr_list_by_type(p,
136 					LDNS_RR_TYPE_AAAA, LDNS_SECTION_ADDITIONAL);
137 		} else {
138 			new_nss_aaaa = ldns_rr_list_new();
139 		}
140 		new_nss = ldns_pkt_rr_list_by_type(p,
141 				LDNS_RR_TYPE_NS, LDNS_SECTION_AUTHORITY);
142 
143 		/* remove the old nameserver from the resolver */
144 		while((pop = ldns_resolver_pop_nameserver(res))) { ldns_rdf_deep_free(pop); }
145 
146 		/* also check for new_nss emptiness */
147 
148 		if (!new_nss_aaaa && !new_nss_a) {
149 			/*
150 			 * no nameserver found!!!
151 			 * try to resolve the names we do got
152 			 */
153 			if (verbosity >= 3) {
154 				printf("Did not get address record for nameserver, doing separate query.\n");
155 			}
156 			ns_addr = ldns_rr_list_new();
157 			for(i = 0; (size_t) i < ldns_rr_list_rr_count(new_nss); i++) {
158 				/* get the name of the nameserver */
159 				pop = ldns_rr_rdf(ldns_rr_list_rr(new_nss, i), 0);
160 				if (!pop) {
161 					break;
162 				}
163 
164 				/* retrieve it's addresses */
165 				ns_addr2 = ldns_get_rr_list_addr_by_name(local_res, pop, c, 0);
166 				if (!ldns_rr_list_cat(ns_addr, ns_addr2)) {
167 					fprintf(stderr, "Internal error adding nameserver address.\n");
168 					exit(EXIT_FAILURE);
169 				}
170 				ldns_rr_list_free(ns_addr2);
171 			}
172 
173 			if (ns_addr) {
174 				if (ldns_resolver_push_nameserver_rr_list(res, ns_addr) !=
175 						LDNS_STATUS_OK) {
176 					fprintf(stderr, "Error adding new nameservers");
177 					ldns_pkt_free(p);
178 					return NULL;
179 				}
180 				ldns_rr_list_deep_free(ns_addr);
181 			} else {
182 				ldns_rr_list_print(stdout, ns_addr);
183 				fprintf(stderr, "Could not find the nameserver ip addr; abort");
184 				ldns_pkt_free(p);
185 				return NULL;
186 			}
187 		}
188 
189 		/* normally, the first working ns is used, but we need all now, so do it one by one
190 		 * if the answer is null, take it from the next resolver
191 		 * if the answer is not, compare it to that of the next resolver
192 		 * error if different, continue if the same
193 		 * if answer list null and no resolvers left die.
194 		 */
195 
196 		ldns_rr_list_deep_free(answer_list);
197 		ldns_rr_list_deep_free(authority_list);
198 		answer_list = NULL;
199 		authority_list = NULL;
200 		for (nss_i = 0; nss_i < ldns_rr_list_rr_count(new_nss_aaaa); nss_i++) {
201 			while((pop = ldns_resolver_pop_nameserver(res))) { ldns_rdf_deep_free(pop); }
202 
203 			status = ldns_resolver_push_nameserver(res, ldns_rr_rdf(ldns_rr_list_rr(new_nss_aaaa, nss_i), 0));
204 			if (status != LDNS_STATUS_OK) {
205 				fprintf(stderr, "Error adding nameserver to resolver: %s\n", ldns_get_errorstr_by_id(status));
206 			}
207 
208 			if (verbosity >= 1) {
209 				fprintf(stdout, "Querying nameserver: ");
210 				ldns_rdf_print(stdout, ldns_rr_owner(ldns_rr_list_rr(new_nss_aaaa, nss_i)));
211 				fprintf(stdout, " (");
212 				ldns_rdf_print(stdout, ldns_rr_rdf(ldns_rr_list_rr(new_nss_aaaa, nss_i), 0));
213 				fprintf(stdout, ")\n");
214 			}
215 			status = ldns_resolver_push_nameserver(res, ldns_rr_rdf(ldns_rr_list_rr(new_nss_aaaa, nss_i), 0));
216 			if (status != LDNS_STATUS_OK) {
217 				fprintf(stderr, "Error adding nameserver to resolver: %s\n", ldns_get_errorstr_by_id(status));
218 			}
219 
220 			ldns_pkt_free(p);
221 			status = ldns_resolver_send(&p, res, name, t, c, 0);
222 			if (status == LDNS_STATUS_OK && p) {
223 				if (ldns_pkt_get_rcode(p) != LDNS_RCODE_NOERROR) {
224 					printf("Error in packet:\n");
225 					ldns_pkt_print(stdout, p);
226 					return NULL;
227 				}
228 
229 				if (verbosity >= 4) {
230 					ldns_pkt_print(stdout, p);
231 					printf("\n\n");
232 				}
233 
234 				if (answer_list) {
235 					if (verbosity >= 2) {
236 						printf("Comparing answer list of answer to previous\n\n");
237 					}
238 					ldns_rr_list_sort(ldns_pkt_answer(p));
239 					ldns_rr_list_sort(answer_list);
240 					if (ldns_rr_list_compare(answer_list, ldns_pkt_answer(p)) != 0) {
241 						fprintf(stderr, "ERROR: different answer answer from nameserver\n");
242 						fprintf(stderr, "\nI had (from previous servers):\n");
243 						ldns_rr_list_print(stderr, answer_list);
244 						fprintf(stderr, "\nI received (from nameserver at ");
245 						ldns_rdf_print(stderr, ldns_resolver_nameservers(res)[0]);
246 						fprintf(stderr, "):\n");
247 						ldns_rr_list_print(stderr, ldns_pkt_answer(p));
248 						exit(EXIT_FAILURE);
249 					}
250 				} else {
251 					answer_list = ldns_rr_list_clone(ldns_pkt_answer(p));
252 					ldns_rr_list_sort(answer_list);
253 					if (verbosity >= 2) {
254 						printf("First answer list for this set, nothing to compare with\n\n");
255 					}
256 				}
257 				if (authority_list) {
258 					if (verbosity >= 2) {
259 						printf("Comparing authority list of answer to previous\n\n");
260 					}
261 					ldns_rr_list_sort(ldns_pkt_authority(p));
262 					ldns_rr_list_sort(authority_list);
263 					if (ldns_rr_list_compare(authority_list, ldns_pkt_authority(p)) != 0) {
264 						fprintf(stderr, "ERROR: different authority answer from nameserver\n");
265 						fprintf(stderr, "\nI had (from previous servers):\n");
266 						ldns_rr_list_print(stderr, authority_list);
267 						fprintf(stderr, "\nI received (from nameserver at ");
268 						ldns_rdf_print(stderr, ldns_resolver_nameservers(res)[0]);
269 						fprintf(stderr, "):\n");
270 						ldns_rr_list_print(stderr, ldns_pkt_authority(p));
271 						exit(EXIT_FAILURE);
272 					}
273 				} else {
274 					authority_list = ldns_rr_list_clone(ldns_pkt_authority(p));
275 					ldns_rr_list_sort(authority_list);
276 					if (verbosity >= 2) {
277 						printf("First authority list for this set, nothing to compare with\n\n");
278 					}
279 					if (verbosity >= 3) {
280 						printf("NS RRset:\n");
281 						ldns_rr_list_print(stdout, authority_list);
282 						printf("\n");
283 					}
284 				}
285 			}
286 		}
287 
288 		ldns_rr_list_deep_free(answer_list);
289 		ldns_rr_list_deep_free(authority_list);
290 		answer_list = NULL;
291 		authority_list = NULL;
292 		for (nss_i = 0; nss_i < ldns_rr_list_rr_count(new_nss_a); nss_i++) {
293 
294 			while((pop = ldns_resolver_pop_nameserver(res))) {ldns_rdf_deep_free(pop); }
295 
296 			if (verbosity >= 1) {
297 				fprintf(stdout, "Querying nameserver: ");
298 				ldns_rdf_print(stdout, ldns_rr_owner(ldns_rr_list_rr(new_nss_a, nss_i)));
299 				fprintf(stdout, " (");
300 				ldns_rdf_print(stdout, ldns_rr_rdf(ldns_rr_list_rr(new_nss_a, nss_i), 0));
301 				fprintf(stdout, ")\n");
302 			}
303 			status = ldns_resolver_push_nameserver(res, ldns_rr_rdf(ldns_rr_list_rr(new_nss_a, nss_i), 0));
304 			if (status != LDNS_STATUS_OK) {
305 				fprintf(stderr, "Error adding nameserver to resolver: %s\n", ldns_get_errorstr_by_id(status));
306 			}
307 
308 			ldns_pkt_free(p);
309 			status = ldns_resolver_send(&p, res, name, t, c, 0);
310 
311 			if (status == LDNS_STATUS_OK) {
312 				if (ldns_pkt_get_rcode(p) != LDNS_RCODE_NOERROR) {
313 					printf("Error in packet:\n");
314 					ldns_pkt_print(stdout, p);
315 					return NULL;
316 				}
317 
318 				if (verbosity >= 4) {
319 					ldns_pkt_print(stdout, p);
320 					printf("\n\n");
321 				}
322 
323 				if (answer_list) {
324 					if (verbosity >= 2) {
325 						printf("Comparing answer list of answer to previous\n\n");
326 					}
327 					ldns_rr_list_sort(ldns_pkt_answer(p));
328 					ldns_rr_list_sort(answer_list);
329 					if (ldns_rr_list_compare(answer_list, ldns_pkt_answer(p)) != 0) {
330 						fprintf(stderr, "ERROR: different answer answer from nameserver\n");
331 						fprintf(stderr, "\nI had (from previous servers):\n");
332 						ldns_rr_list_print(stderr, answer_list);
333 						fprintf(stderr, "\nI received (from nameserver at ");
334 						ldns_rdf_print(stderr, ldns_resolver_nameservers(res)[0]);
335 						fprintf(stderr, "):\n");
336 						ldns_rr_list_print(stderr, ldns_pkt_answer(p));
337 						exit(EXIT_FAILURE);
338 					}
339 				} else {
340 					if (verbosity >= 2) {
341 						printf("First answer list for this set, nothing to compare with\n\n");
342 					}
343 					answer_list = ldns_rr_list_clone(ldns_pkt_answer(p));
344 					ldns_rr_list_sort(answer_list);
345 				}
346 				if (authority_list) {
347 					if (verbosity >= 2) {
348 						printf("Comparing authority list of answer to previous\n\n");
349 					}
350 					ldns_rr_list_sort(ldns_pkt_authority(p));
351 					ldns_rr_list_sort(authority_list);
352 					if (ldns_rr_list_compare(authority_list, ldns_pkt_authority(p)) != 0) {
353 						fprintf(stderr, "ERROR: different authority answer from nameserver\n");
354 						fprintf(stderr, "\nI had (from previous servers):\n");
355 						ldns_rr_list_print(stderr, authority_list);
356 						fprintf(stderr, "\nI received (from nameserver at ");
357 						ldns_rdf_print(stderr, ldns_resolver_nameservers(res)[0]);
358 						fprintf(stderr, "):\n");
359 						ldns_rr_list_print(stderr, ldns_pkt_authority(p));
360 						exit(EXIT_FAILURE);
361 					}
362 				} else {
363 					if (verbosity >= 2) {
364 						printf("First authority list for this set, nothing to compare with\n\n");
365 					}
366 					authority_list = ldns_rr_list_clone(ldns_pkt_authority(p));
367 					ldns_rr_list_sort(authority_list);
368 					if (verbosity >= 3) {
369 						printf("NS RRset:\n");
370 						ldns_rr_list_print(stdout, authority_list);
371 						printf("\n");
372 					}
373 				}
374 			}
375 		}
376 		ldns_rr_list_deep_free(authority_list);
377 		authority_list = NULL;
378 
379 		if (loop_count++ > 20) {
380 			/* unlikely that we are doing something useful */
381 			fprintf(stderr, "Looks like we are looping");
382 			ldns_pkt_free(p);
383 			return NULL;
384 		}
385 
386 		ldns_pkt_free(p);
387 
388 		if (verbosity >= 3) {
389 			fprintf(stdout, "This level ok. Continuing to next.\n\n");
390 		}
391 
392 		status = ldns_resolver_send(&p, res, name, t, c, 0);
393 
394 		if (status != LDNS_STATUS_OK) {
395 			fprintf(stderr, "Error querying root servers: %s\n", ldns_get_errorstr_by_id(status));
396 			return NULL;
397 		}
398 
399 		if (ldns_pkt_get_rcode(p) != LDNS_RCODE_NOERROR) {
400 			printf("Error in packet:\n");
401 			ldns_pkt_print(stdout, p);
402 			return NULL;
403 		}
404 
405 		if (verbosity >= 4) {
406 			ldns_pkt_print(stdout, p);
407 			printf("\n\n");
408 		}
409 
410 
411 		ldns_rr_list_deep_free(new_nss_aaaa);
412 		ldns_rr_list_deep_free(new_nss_a);
413 		ldns_rr_list_deep_free(new_nss);
414 		new_nss_aaaa = NULL;
415 		new_nss_a = NULL;
416 		ns_addr = NULL;
417 	}
418 
419 	ldns_rr_list_deep_free(answer_list);
420 	answer_list = NULL;
421 	/* clone the nameserver list, we are going to handle them one by one */
422 	last_nameserver_count = 0;
423 	last_nameservers = LDNS_XMALLOC(ldns_rdf *, ldns_resolver_nameserver_count(res));
424 
425 	pop = NULL;
426 	while((pop = ldns_resolver_pop_nameserver(res))) {
427 		last_nameservers[last_nameserver_count] = pop;
428 		last_nameserver_count++;
429 	}
430 
431 	for (nss_i = 0; nss_i < last_nameserver_count; nss_i++) {
432 		/* remove previous nameserver */
433 		while((pop = ldns_resolver_pop_nameserver(res))) { ldns_rdf_deep_free(pop); }
434 
435 		if (verbosity >= 1) {
436 			printf("Querying nameserver: ");
437 			ldns_rdf_print(stdout, last_nameservers[nss_i]);
438 			printf("\n");
439 		}
440 		status = ldns_resolver_push_nameserver(res, last_nameservers[nss_i]);
441 		if (status != LDNS_STATUS_OK) {
442 			fprintf(stderr, "Error adding nameserver to resolver: %s\n", ldns_get_errorstr_by_id(status));
443 		}
444 
445 		ldns_pkt_free(p);
446 		status = ldns_resolver_send(&p, res, name, t, c, 0);
447 
448 		if (!p) {
449 			fprintf(stderr, "no packet received\n");
450 			LDNS_FREE(last_nameservers);
451 			return NULL;
452 		}
453 
454 		if (status == LDNS_STATUS_RES_NO_NS) {
455 			fprintf(stderr, "Error: nameserver at ");
456 			ldns_rdf_print(stderr, last_nameservers[nss_i]);
457 			fprintf(stderr, " not responding. Unable to check RRset here, aborting.\n");
458 			LDNS_FREE(last_nameservers);
459 			return NULL;
460 		}
461 
462 		if (ldns_pkt_get_rcode(p) != LDNS_RCODE_NOERROR) {
463 			printf("Error in packet:\n");
464 			ldns_pkt_print(stdout, p);
465 			LDNS_FREE(last_nameservers);
466 			return NULL;
467 		}
468 
469 		if (answer_list) {
470 			if (verbosity >= 2) {
471 				printf("1Comparing answer rr list of answer to previous\n");
472 			}
473 			ldns_rr_list_sort(ldns_pkt_answer(p));
474 			ldns_rr_list_sort(answer_list);
475 			if (ldns_rr_list_compare(answer_list, ldns_pkt_answer(p)) != 0) {
476 				printf("ERROR: different answer section in response from nameserver\n");
477 				fprintf(stderr, "\nI had:\n");
478 				ldns_rr_list_print(stderr, answer_list);
479 				fprintf(stderr, "\nI received (from nameserver at ");
480 				ldns_rdf_print(stderr, ldns_resolver_nameservers(res)[0]);
481 				fprintf(stderr, "):\n");
482 				ldns_rr_list_print(stderr, ldns_pkt_answer(p));
483 				exit(EXIT_FAILURE);
484 			}
485 		} else {
486 			if (verbosity >= 2) {
487 				printf("First answer rr list for this set, nothing to compare with\n");
488 			}
489 			answer_list = ldns_rr_list_clone(ldns_pkt_answer(p));
490 			if (verbosity >= 3) {
491 				printf("DNSKEY RRset:\n");
492 				ldns_rr_list_print(stdout, answer_list);
493 			}
494 		}
495 
496 	}
497 
498 	for (nss_i = 0; nss_i < last_nameserver_count; nss_i++) {
499 		ldns_rdf_deep_free(last_nameservers[nss_i]);
500 	}
501 	LDNS_FREE(last_nameservers);
502 	ldns_resolver_deep_free(res);
503 	ldns_pkt_free(p);
504 	return answer_list;
505 }
506 
507 
508 /*
509  * The file with the given path should contain a list of NS RRs
510  * for the root zone and A records for those NS RRs.
511  * Read them, check them, and append the a records to the rr list given.
512  */
513 static ldns_rr_list *
read_root_hints(const char * filename)514 read_root_hints(const char *filename)
515 {
516 	FILE *fp = NULL;
517 	int line_nr = 0;
518 	ldns_zone *z;
519 	ldns_status status;
520 	ldns_rr_list *addresses = NULL;
521 	ldns_rr *rr;
522 	size_t i;
523 
524 	fp = fopen(filename, "r");
525 	if (!fp) {
526 		fprintf(stderr, "Unable to open %s for reading: %s\n", filename, strerror(errno));
527 		return NULL;
528 	}
529 
530 	status = ldns_zone_new_frm_fp_l(&z, fp, NULL, 0, 0, &line_nr);
531 	fclose(fp);
532 	if (status != LDNS_STATUS_OK) {
533 		fprintf(stderr, "Error reading root hints file: %s\n", ldns_get_errorstr_by_id(status));
534 		return NULL;
535 	} else {
536 		addresses = ldns_rr_list_new();
537 		for (i = 0; i < ldns_rr_list_rr_count(ldns_zone_rrs(z)); i++) {
538 			rr = ldns_rr_list_rr(ldns_zone_rrs(z), i);
539 			if ((address_family == 0 || address_family == 1) &&
540 			    ldns_rr_get_type(rr) == LDNS_RR_TYPE_A ) {
541 				ldns_rr_list_push_rr(addresses, ldns_rr_clone(rr));
542 			}
543 			if ((address_family == 0 || address_family == 2) &&
544 			    ldns_rr_get_type(rr) == LDNS_RR_TYPE_AAAA) {
545 				ldns_rr_list_push_rr(addresses, ldns_rr_clone(rr));
546 			}
547 		}
548 		ldns_zone_deep_free(z);
549 		return addresses;
550 	}
551 }
552 
553 
554 int
main(int argc,char * argv[])555 main(int argc, char *argv[])
556 {
557 	ldns_resolver *res;
558 	ldns_rdf *ns;
559 	ldns_rdf *domain;
560 	ldns_rr_list *l = NULL;
561 
562 	ldns_rr_list *dns_root = NULL;
563 	const char *root_file = "/etc/named.root";
564 
565 	ldns_status status;
566 
567 	int i;
568 
569 	char *domain_str;
570 	char *outputfile_str;
571 	ldns_buffer *outputfile_buffer;
572 	FILE *outputfile;
573 	ldns_rr *k;
574 
575 	bool insecure = false;
576 	ldns_pkt *pkt;
577 
578 	domain = NULL;
579 	res = NULL;
580 
581 	if (argc < 2) {
582 		usage(stdout, argv[0]);
583 		exit(EXIT_FAILURE);
584 	} else {
585 		for (i = 1; i < argc; i++) {
586 			if (strncmp("-4", argv[i], 3) == 0) {
587 				if (address_family != 0) {
588 					fprintf(stderr, "Options -4 and -6 cannot be specified at the same time\n");
589 					exit(EXIT_FAILURE);
590 				}
591 				address_family = 1;
592 			} else if (strncmp("-6", argv[i], 3) == 0) {
593 				if (address_family != 0) {
594 					fprintf(stderr, "Options -4 and -6 cannot be specified at the same time\n");
595 					exit(EXIT_FAILURE);
596 				}
597 				address_family = 2;
598 			} else if (strncmp("-h", argv[i], 3) == 0) {
599 				usage(stdout, argv[0]);
600 				exit(EXIT_SUCCESS);
601 			} else if (strncmp("-i", argv[i], 2) == 0) {
602 				insecure = true;
603 			} else if (strncmp("-r", argv[i], 2) == 0) {
604 				if (strlen(argv[i]) > 2) {
605 					root_file = argv[i]+2;
606 				} else if (i+1 >= argc) {
607 					usage(stdout, argv[0]);
608 					exit(EXIT_FAILURE);
609 				} else {
610 					root_file = argv[i+1];
611 					i++;
612 				}
613 			} else if (strncmp("-s", argv[i], 3) == 0) {
614 				store_in_file = true;
615 			} else if (strncmp("-v", argv[i], 2) == 0) {
616 				if (strlen(argv[i]) > 2) {
617 					verbosity = atoi(argv[i]+2);
618 				} else if (i+1 > argc) {
619 					usage(stdout, argv[0]);
620 					exit(EXIT_FAILURE);
621 				} else {
622 					verbosity = atoi(argv[i+1]);
623 					i++;
624 				}
625 			} else {
626 				/* create a rdf from the command line arg */
627 				if (domain) {
628 					fprintf(stdout, "You can only specify one domain at a time\n");
629 					exit(EXIT_FAILURE);
630 				}
631 
632 				domain = ldns_dname_new_frm_str(argv[i]);
633 			}
634 
635 		}
636 		if (!domain) {
637 			usage(stdout, argv[0]);
638 			exit(EXIT_FAILURE);
639 		}
640 	}
641 
642 	dns_root = read_root_hints(root_file);
643 	if (!dns_root) {
644 		fprintf(stderr, "cannot read the root hints file\n");
645 		exit(EXIT_FAILURE);
646 	}
647 
648 	/* create a new resolver from /etc/resolv.conf */
649 	status = ldns_resolver_new_frm_file(&res, NULL);
650 
651 	if (status != LDNS_STATUS_OK) {
652 		fprintf(stderr, "Warning: Unable to create stub resolver from /etc/resolv.conf:\n");
653 		fprintf(stderr, "%s\n", ldns_get_errorstr_by_id(status));
654 		fprintf(stderr, "defaulting to nameserver at 127.0.0.1 for separate nameserver name lookups\n");
655 		do {
656 			res = ldns_resolver_new();
657 			if (res) {
658 				ns = ldns_rdf_new_frm_str(LDNS_RDF_TYPE_A,
659 						"127.0.0.1");
660 				if (ns) {
661 					status = ldns_resolver_push_nameserver(
662 							res, ns);
663 					if (status == LDNS_STATUS_OK) {
664 						break;
665 					}
666 					ldns_rdf_deep_free(ns);
667 				}
668 				ldns_resolver_free(res);
669 			}
670 			fprintf(stderr, "Unable to create stub resolver: %s\n",
671 					ldns_get_errorstr_by_id(status));
672 			exit(EXIT_FAILURE);
673 
674 		} while (false);
675 		ldns_rdf_deep_free(ns);
676 	}
677 
678 	ldns_resolver_set_ip6(res, address_family);
679 
680 	if (insecure) {
681 		pkt = ldns_resolver_query(res, domain, LDNS_RR_TYPE_DNSKEY, LDNS_RR_CLASS_IN, LDNS_RD);
682 		if (pkt) {
683 		l = ldns_pkt_rr_list_by_type(pkt, LDNS_RR_TYPE_DNSKEY, LDNS_SECTION_ANY_NOQUESTION);
684 		}
685 	} else {
686 		l = retrieve_dnskeys(res, domain, LDNS_RR_TYPE_DNSKEY, LDNS_RR_CLASS_IN, dns_root);
687 	}
688 
689 	/* separator for result data and verbosity data */
690 	if (verbosity > 0) {
691 		fprintf(stdout, "; ---------------------------\n");
692 		fprintf(stdout, "; Got the following keys:\n");
693 	}
694 	if (l) {
695 		if (store_in_file) {
696 			/* create filename:
697 			 * K<domain>.+<alg>.+<id>.key
698 			 */
699 			for (i = 0; (size_t) i < ldns_rr_list_rr_count(l); i++) {
700 				k = ldns_rr_list_rr(l, (size_t) i);
701 
702 				outputfile_buffer = ldns_buffer_new(300);
703 				domain_str = ldns_rdf2str(ldns_rr_owner(k));
704 				ldns_buffer_printf(outputfile_buffer, "K%s+%03u+%05u.key", domain_str, ldns_rdf2native_int8(ldns_rr_rdf(k, 2)),
705 					(unsigned int) ldns_calc_keytag(k));
706 				outputfile_str = ldns_buffer_export(outputfile_buffer);
707 
708 				if (verbosity >= 1) {
709 					fprintf(stdout, "Writing key to file %s\n", outputfile_str);
710 				}
711 
712 				outputfile = fopen(outputfile_str, "w");
713 				if (!outputfile) {
714 					fprintf(stderr, "Error writing key to file %s: %s\n", outputfile_str, strerror(errno));
715 				} else {
716 					ldns_rr_print(outputfile, k);
717 					fclose(outputfile);
718 				}
719 
720 				LDNS_FREE(domain_str);
721 				LDNS_FREE(outputfile_str);
722 				LDNS_FREE(outputfile_buffer);
723 			}
724 		} else {
725 			ldns_rr_list_print(stdout, l);
726 		}
727 	} else {
728 		fprintf(stderr, "no answer packet received, stub resolver config:\n");
729 		ldns_resolver_print(stderr, res);
730 	}
731 
732 	ldns_rdf_deep_free(domain);
733 	ldns_resolver_deep_free(res);
734 	ldns_rr_list_deep_free(l);
735 	ldns_rr_list_deep_free(dns_root);
736 	return EXIT_SUCCESS;
737 }
738