xref: /minix/external/bsd/bind/dist/bin/delv/delv.c (revision 83ee113e)
1 /*	$NetBSD: delv.c,v 1.4 2015/07/08 17:28:54 christos Exp $	*/
2 
3 /*
4  * Copyright (C) 2014, 2015  Internet Systems Consortium, Inc. ("ISC")
5  *
6  * Permission to use, copy, modify, and/or distribute this software for any
7  * purpose with or without fee is hereby granted, provided that the above
8  * copyright notice and this permission notice appear in all copies.
9  *
10  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
11  * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
12  * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
13  * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
14  * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
15  * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
16  * PERFORMANCE OF THIS SOFTWARE.
17  */
18 
19 #include <config.h>
20 #include <bind.keys.h>
21 
22 #ifndef WIN32
23 #include <sys/types.h>
24 #include <sys/socket.h>
25 #include <signal.h>
26 
27 #include <netinet/in.h>
28 
29 #include <arpa/inet.h>
30 
31 #include <netdb.h>
32 #endif
33 
34 #include <stdio.h>
35 #include <stdlib.h>
36 #include <string.h>
37 #include <unistd.h>
38 
39 #include <isc/app.h>
40 #include <isc/base64.h>
41 #include <isc/buffer.h>
42 #include <isc/lib.h>
43 #include <isc/log.h>
44 #include <isc/mem.h>
45 #ifdef WIN32
46 #include <isc/ntpaths.h>
47 #endif
48 #include <isc/parseint.h>
49 #include <isc/print.h>
50 #include <isc/sockaddr.h>
51 #include <isc/socket.h>
52 #include <isc/string.h>
53 #include <isc/task.h>
54 #include <isc/timer.h>
55 #include <isc/util.h>
56 
57 #include <irs/resconf.h>
58 #include <irs/netdb.h>
59 
60 #include <isccfg/log.h>
61 #include <isccfg/namedconf.h>
62 
63 #include <dns/byaddr.h>
64 #include <dns/client.h>
65 #include <dns/fixedname.h>
66 #include <dns/keytable.h>
67 #include <dns/keyvalues.h>
68 #include <dns/lib.h>
69 #include <dns/log.h>
70 #include <dns/masterdump.h>
71 #include <dns/name.h>
72 #include <dns/rdata.h>
73 #include <dns/rdataclass.h>
74 #include <dns/rdataset.h>
75 #include <dns/rdatastruct.h>
76 #include <dns/rdatatype.h>
77 #include <dns/result.h>
78 #include <dns/secalg.h>
79 #include <dns/view.h>
80 
81 #include <dst/dst.h>
82 #include <dst/result.h>
83 
84 #define CHECK(r) \
85 	do { \
86 		result = (r); \
87 		if (result != ISC_R_SUCCESS) \
88 			goto cleanup; \
89 	} while (/*CONSTCOND*/0)
90 
91 #define MAXNAME (DNS_NAME_MAXTEXT+1)
92 
93 /* Variables used internally by delv. */
94 char *progname;
95 static isc_mem_t *mctx = NULL;
96 static isc_log_t *lctx = NULL;
97 
98 /* Configurables */
99 static char *server = NULL;
100 static const char *port = "53";
101 static isc_sockaddr_t *srcaddr4 = NULL, *srcaddr6 = NULL;
102 static isc_sockaddr_t a4, a6;
103 static char *curqname = NULL, *qname = NULL;
104 static isc_boolean_t classset = ISC_FALSE;
105 static dns_rdatatype_t qtype = dns_rdatatype_none;
106 static isc_boolean_t typeset = ISC_FALSE;
107 
108 static unsigned int styleflags = 0;
109 static isc_uint32_t splitwidth = 0xffffffff;
110 static isc_boolean_t
111 	showcomments = ISC_TRUE,
112 	showdnssec = ISC_TRUE,
113 	showtrust = ISC_TRUE,
114 	rrcomments = ISC_TRUE,
115 	noclass = ISC_FALSE,
116 	nocrypto = ISC_FALSE,
117 	nottl = ISC_FALSE,
118 	multiline = ISC_FALSE,
119 	short_form = ISC_FALSE;
120 
121 static isc_boolean_t
122 	resolve_trace = ISC_FALSE,
123 	validator_trace = ISC_FALSE,
124 	message_trace = ISC_FALSE;
125 
126 static isc_boolean_t
127 	use_ipv4 = ISC_TRUE,
128 	use_ipv6 = ISC_TRUE;
129 
130 static isc_boolean_t
131 	cdflag = ISC_FALSE,
132 	no_sigs = ISC_FALSE,
133 	root_validation = ISC_TRUE,
134 	dlv_validation = ISC_TRUE;
135 
136 static char *anchorfile = NULL;
137 static char *trust_anchor = NULL;
138 static char *dlv_anchor = NULL;
139 static int trusted_keys = 0;
140 
141 static dns_fixedname_t afn, dfn;
142 static dns_name_t *anchor_name = NULL, *dlv_name = NULL;
143 
144 /* Default bind.keys contents */
145 static char anchortext[] = MANAGED_KEYS;
146 
147 /*
148  * Static function prototypes
149  */
150 static isc_result_t
151 get_reverse(char *reverse, size_t len, char *value, isc_boolean_t strict);
152 
153 static isc_result_t
154 parse_uint(isc_uint32_t *uip, const char *value, isc_uint32_t max,
155 	   const char *desc);
156 
157 static void
158 usage(void) {
159 	fputs(
160 "Usage:  delv [@server] {q-opt} {d-opt} [domain] [q-type] [q-class]\n"
161 "Where:  domain	  is in the Domain Name System\n"
162 "        q-class  is one of (in,hs,ch,...) [default: in]\n"
163 "        q-type   is one of (a,any,mx,ns,soa,hinfo,axfr,txt,...) [default:a]\n"
164 "        q-opt    is one of:\n"
165 "                 -x dot-notation     (shortcut for reverse lookups)\n"
166 "                 -d level            (set debugging level)\n"
167 "                 -a anchor-file      (specify root and dlv trust anchors)\n"
168 "                 -b address[#port]   (bind to source address/port)\n"
169 "                 -p port             (specify port number)\n"
170 "                 -q name             (specify query name)\n"
171 "                 -t type             (specify query type)\n"
172 "                 -c class            (specify query class)\n"
173 "                 -4                  (use IPv4 query transport only)\n"
174 "                 -6                  (use IPv6 query transport only)\n"
175 "                 -i                  (disable DNSSEC validation)\n"
176 "                 -m                  (enable memory usage debugging)\n"
177 "        d-opt    is of the form +keyword[=value], where keyword is:\n"
178 "                 +[no]all            (Set or clear all display flags)\n"
179 "                 +[no]class          (Control display of class)\n"
180 "                 +[no]crypto         (Control display of cryptographic\n"
181 "                                      fields in records)\n"
182 "                 +[no]multiline      (Print records in an expanded format)\n"
183 "                 +[no]comments       (Control display of comment lines)\n"
184 "                 +[no]rrcomments     (Control display of per-record "
185 				       "comments)\n"
186 "                 +[no]short          (Short form answer)\n"
187 "                 +[no]split=##       (Split hex/base64 fields into chunks)\n"
188 "                 +[no]ttl            (Control display of ttls in records)\n"
189 "                 +[no]trust          (Control display of trust level)\n"
190 "                 +[no]rtrace         (Trace resolver fetches)\n"
191 "                 +[no]mtrace         (Trace messages received)\n"
192 "                 +[no]vtrace         (Trace validation process)\n"
193 "                 +[no]dlv            (DNSSEC lookaside validation anchor)\n"
194 "                 +[no]root           (DNSSEC validation trust anchor)\n"
195 "                 +[no]dnssec         (Display DNSSEC records)\n"
196 "        -h                           (print help and exit)\n"
197 "        -v                           (print version and exit)\n",
198 	stderr);
199 	exit(1);
200 }
201 
202 ISC_PLATFORM_NORETURN_PRE static void
203 fatal(const char *format, ...)
204 ISC_FORMAT_PRINTF(1, 2) ISC_PLATFORM_NORETURN_POST;
205 
206 static void
207 fatal(const char *format, ...) {
208 	va_list args;
209 
210 	fflush(stdout);
211 	fprintf(stderr, "%s: ", progname);
212 	va_start(args, format);
213 	vfprintf(stderr, format, args);
214 	va_end(args);
215 	fprintf(stderr, "\n");
216 	exit(1);
217 }
218 
219 static void
220 warn(const char *format, ...) ISC_FORMAT_PRINTF(1, 2);
221 
222 static void
223 warn(const char *format, ...) {
224 	va_list args;
225 
226 	fflush(stdout);
227 	fprintf(stderr, "%s: warning: ", progname);
228 	va_start(args, format);
229 	vfprintf(stderr, format, args);
230 	va_end(args);
231 	fprintf(stderr, "\n");
232 }
233 
234 static isc_logcategory_t categories[] = {
235 	{ "delv",	     0 },
236 	{ NULL,		     0 }
237 };
238 #define LOGCATEGORY_DEFAULT		(&categories[0])
239 #define LOGMODULE_DEFAULT		(&modules[0])
240 
241 static isc_logmodule_t modules[] = {
242 	{ "delv",	 		0 },
243 	{ NULL, 			0 }
244 };
245 
246 static void
247 delv_log(int level, const char *fmt, ...) ISC_FORMAT_PRINTF(2, 3);
248 
249 static void
250 delv_log(int level, const char *fmt, ...) {
251 	va_list ap;
252 	char msgbuf[2048];
253 
254 	if (! isc_log_wouldlog(lctx, level))
255 		return;
256 
257 	va_start(ap, fmt);
258 
259 	vsnprintf(msgbuf, sizeof(msgbuf), fmt, ap);
260 	isc_log_write(lctx, LOGCATEGORY_DEFAULT, LOGMODULE_DEFAULT,
261 		      level, "%s", msgbuf);
262 	va_end(ap);
263 }
264 
265 static int loglevel = 0;
266 
267 static void
268 setup_logging(FILE *errout) {
269 	isc_result_t result;
270 	isc_logdestination_t destination;
271 	isc_logconfig_t *logconfig = NULL;
272 
273 	result = isc_log_create(mctx, &lctx, &logconfig);
274 	if (result != ISC_R_SUCCESS)
275 		fatal("Couldn't set up logging");
276 
277 	isc_log_registercategories(lctx, categories);
278 	isc_log_registermodules(lctx, modules);
279 	isc_log_setcontext(lctx);
280 	dns_log_init(lctx);
281 	dns_log_setcontext(lctx);
282 	cfg_log_init(lctx);
283 
284 	destination.file.stream = errout;
285 	destination.file.name = NULL;
286 	destination.file.versions = ISC_LOG_ROLLNEVER;
287 	destination.file.maximum_size = 0;
288 
289 	result = isc_log_createchannel(logconfig, "stderr",
290 				       ISC_LOG_TOFILEDESC, ISC_LOG_DYNAMIC,
291 				       &destination, ISC_LOG_PRINTPREFIX);
292 	if (result != ISC_R_SUCCESS)
293 		fatal("Couldn't set up log channel 'stderr'");
294 
295 	isc_log_setdebuglevel(lctx, loglevel);
296 
297 	result = isc_log_settag(logconfig, ";; ");
298 	if (result != ISC_R_SUCCESS)
299 		fatal("Couldn't set log tag");
300 
301 	result = isc_log_usechannel(logconfig, "stderr",
302 				    ISC_LOGCATEGORY_DEFAULT, NULL);
303 	if (result != ISC_R_SUCCESS)
304 		fatal("Couldn't attach to log channel 'stderr'");
305 
306 	if (resolve_trace && loglevel < 1) {
307 		result = isc_log_createchannel(logconfig, "resolver",
308 					       ISC_LOG_TOFILEDESC,
309 					       ISC_LOG_DEBUG(1),
310 					       &destination,
311 					       ISC_LOG_PRINTPREFIX);
312 		if (result != ISC_R_SUCCESS)
313 			fatal("Couldn't set up log channel 'resolver'");
314 
315 		result = isc_log_usechannel(logconfig, "resolver",
316 					    DNS_LOGCATEGORY_RESOLVER,
317 					    DNS_LOGMODULE_RESOLVER);
318 		if (result != ISC_R_SUCCESS)
319 			fatal("Couldn't attach to log channel 'resolver'");
320 	}
321 
322 	if (validator_trace && loglevel < 3) {
323 		result = isc_log_createchannel(logconfig, "validator",
324 					       ISC_LOG_TOFILEDESC,
325 					       ISC_LOG_DEBUG(3),
326 					       &destination,
327 					       ISC_LOG_PRINTPREFIX);
328 		if (result != ISC_R_SUCCESS)
329 			fatal("Couldn't set up log channel 'validator'");
330 
331 		result = isc_log_usechannel(logconfig, "validator",
332 					    DNS_LOGCATEGORY_DNSSEC,
333 					    DNS_LOGMODULE_VALIDATOR);
334 		if (result != ISC_R_SUCCESS)
335 			fatal("Couldn't attach to log channel 'validator'");
336 	}
337 
338 	if (message_trace && loglevel < 10) {
339 		result = isc_log_createchannel(logconfig, "messages",
340 					       ISC_LOG_TOFILEDESC,
341 					       ISC_LOG_DEBUG(10),
342 					       &destination,
343 					       ISC_LOG_PRINTPREFIX);
344 		if (result != ISC_R_SUCCESS)
345 			fatal("Couldn't set up log channel 'messages'");
346 
347 		result = isc_log_usechannel(logconfig, "messages",
348 					    DNS_LOGCATEGORY_RESOLVER,
349 					    DNS_LOGMODULE_PACKETS);
350 		if (result != ISC_R_SUCCESS)
351 			fatal("Couldn't attach to log channel 'messagse'");
352 	}
353 }
354 
355 static void
356 print_status(dns_rdataset_t *rdataset) {
357 	const char *astr = "", *tstr = "";
358 
359 	REQUIRE(rdataset != NULL);
360 
361 	if (!showtrust || !dns_rdataset_isassociated(rdataset))
362 		return;
363 
364 	if ((rdataset->attributes & DNS_RDATASETATTR_NEGATIVE) != 0)
365 		astr = "negative response, ";
366 
367 	switch (rdataset->trust) {
368 	case dns_trust_none:
369 		tstr = "untrusted";
370 		break;
371 	case dns_trust_pending_additional:
372 		tstr = "signed additional data, pending validation";
373 		break;
374 	case dns_trust_pending_answer:
375 		tstr = "signed answer, pending validation";
376 		break;
377 	case dns_trust_additional:
378 		tstr = "unsigned additional data";
379 		break;
380 	case dns_trust_glue:
381 		tstr = "glue data";
382 		break;
383 	case dns_trust_answer:
384 		if (root_validation || dlv_validation)
385 			tstr = "unsigned answer";
386 		else
387 			tstr = "answer not validated";
388 		break;
389 	case dns_trust_authauthority:
390 		tstr = "authority data";
391 		break;
392 	case dns_trust_authanswer:
393 		tstr = "authoritative";
394 		break;
395 	case dns_trust_secure:
396 		tstr = "fully validated";
397 		break;
398 	case dns_trust_ultimate:
399 		tstr = "ultimate trust";
400 		break;
401 	}
402 
403 	printf("; %s%s\n", astr, tstr);
404 }
405 
406 static isc_result_t
407 printdata(dns_rdataset_t *rdataset, dns_name_t *owner,
408 	  dns_master_style_t *style)
409 {
410 	isc_result_t result = ISC_R_SUCCESS;
411 	static dns_trust_t trust;
412 	static isc_boolean_t first = ISC_TRUE;
413 	isc_buffer_t target;
414 	isc_region_t r;
415 	char *t = NULL;
416 	int len = 2048;
417 
418 	if (!dns_rdataset_isassociated(rdataset)) {
419 		char namebuf[DNS_NAME_FORMATSIZE];
420 		dns_name_format(owner, namebuf, sizeof(namebuf));
421 		delv_log(ISC_LOG_DEBUG(4),
422 			  "WARN: empty rdataset %s", namebuf);
423 		return (ISC_R_SUCCESS);
424 	}
425 
426 	if (!showdnssec && rdataset->type == dns_rdatatype_rrsig)
427 		return (ISC_R_SUCCESS);
428 
429 	if (first || rdataset->trust != trust) {
430 		if (!first && showtrust && !short_form)
431 			putchar('\n');
432 		print_status(rdataset);
433 		trust = rdataset->trust;
434 		first = ISC_FALSE;
435 	}
436 
437 	do {
438 		t = isc_mem_get(mctx, len);
439 		if (t == NULL)
440 			return (ISC_R_NOMEMORY);
441 
442 		isc_buffer_init(&target, t, len);
443 		if (short_form) {
444 			dns_rdata_t rdata = DNS_RDATA_INIT;
445 			for (result = dns_rdataset_first(rdataset);
446 			     result == ISC_R_SUCCESS;
447 			     result = dns_rdataset_next(rdataset))
448 			{
449 				if ((rdataset->attributes &
450 				     DNS_RDATASETATTR_NEGATIVE) != 0)
451 					continue;
452 
453 				dns_rdataset_current(rdataset, &rdata);
454 				result = dns_rdata_tofmttext(&rdata,
455 							     dns_rootname,
456 							     styleflags,
457 							     0, 60, " ",
458 							     &target);
459 				if (result != ISC_R_SUCCESS)
460 					break;
461 
462 				if (isc_buffer_availablelength(&target) < 1) {
463 					result = ISC_R_NOSPACE;
464 					break;
465 				}
466 
467 				isc_buffer_putstr(&target, "\n");
468 
469 				dns_rdata_reset(&rdata);
470 			}
471 		} else {
472 			if ((rdataset->attributes &
473 			     DNS_RDATASETATTR_NEGATIVE) != 0)
474 				isc_buffer_putstr(&target, "; ");
475 
476 			result = dns_master_rdatasettotext(owner, rdataset,
477 							   style, &target);
478 		}
479 
480 		if (result == ISC_R_NOSPACE) {
481 			isc_mem_put(mctx, t, len);
482 			len += 1024;
483 		} else if (result == ISC_R_NOMORE)
484 			result = ISC_R_SUCCESS;
485 		else
486 			CHECK(result);
487 	} while (result == ISC_R_NOSPACE);
488 
489 	isc_buffer_usedregion(&target, &r);
490 	printf("%.*s", (int)r.length, (char *)r.base);
491 
492  cleanup:
493 	if (t != NULL)
494 		isc_mem_put(mctx, t, len);
495 
496 	return (ISC_R_SUCCESS);
497 }
498 
499 static isc_result_t
500 setup_style(dns_master_style_t **stylep) {
501 	isc_result_t result;
502 	dns_master_style_t *style = NULL;
503 
504 	REQUIRE(stylep != NULL || *stylep == NULL);
505 
506 	styleflags |= DNS_STYLEFLAG_REL_OWNER;
507 	if (showcomments)
508 		styleflags |= DNS_STYLEFLAG_COMMENT;
509 	if (rrcomments)
510 		styleflags |= DNS_STYLEFLAG_RRCOMMENT;
511 	if (nottl)
512 		styleflags |= DNS_STYLEFLAG_NO_TTL;
513 	if (noclass)
514 		styleflags |= DNS_STYLEFLAG_NO_CLASS;
515 	if (nocrypto)
516 		styleflags |= DNS_STYLEFLAG_NOCRYPTO;
517 	if (multiline) {
518 		styleflags |= DNS_STYLEFLAG_MULTILINE;
519 		styleflags |= DNS_STYLEFLAG_COMMENT;
520 	}
521 
522 	if (multiline || (nottl && noclass))
523 		result = dns_master_stylecreate2(&style, styleflags,
524 						 24, 24, 24, 32, 80, 8,
525 						 splitwidth, mctx);
526 	else if (nottl || noclass)
527 		result = dns_master_stylecreate2(&style, styleflags,
528 						 24, 24, 32, 40, 80, 8,
529 						 splitwidth, mctx);
530 	else
531 		result = dns_master_stylecreate2(&style, styleflags,
532 						 24, 32, 40, 48, 80, 8,
533 						 splitwidth, mctx);
534 
535 	if (result == ISC_R_SUCCESS)
536 		*stylep = style;
537 	return (result);
538 }
539 
540 static isc_result_t
541 convert_name(dns_fixedname_t *fn, dns_name_t **name, const char *text) {
542 	isc_result_t result;
543 	isc_buffer_t b;
544 	dns_name_t *n;
545 	unsigned int len;
546 
547 	REQUIRE(fn != NULL && name != NULL && text != NULL);
548 	len = strlen(text);
549 
550 	isc_buffer_constinit(&b, text, len);
551 	isc_buffer_add(&b, len);
552 	dns_fixedname_init(fn);
553 	n = dns_fixedname_name(fn);
554 
555 	result = dns_name_fromtext(n, &b, dns_rootname, 0, NULL);
556 	if (result != ISC_R_SUCCESS) {
557 		delv_log(ISC_LOG_ERROR, "failed to convert QNAME %s: %s",
558 			  text, isc_result_totext(result));
559 		return (result);
560 	}
561 
562 	*name = n;
563 	return (ISC_R_SUCCESS);
564 }
565 
566 static isc_result_t
567 key_fromconfig(const cfg_obj_t *key, dns_client_t *client) {
568 	dns_rdata_dnskey_t keystruct;
569 	isc_uint32_t flags, proto, alg;
570 	const char *keystr, *keynamestr;
571 	unsigned char keydata[4096];
572 	isc_buffer_t keydatabuf;
573 	unsigned char rrdata[4096];
574 	isc_buffer_t rrdatabuf;
575 	isc_region_t r;
576 	dns_fixedname_t fkeyname;
577 	dns_name_t *keyname;
578 	isc_result_t result;
579 	isc_boolean_t match_root, match_dlv;
580 
581 	keynamestr = cfg_obj_asstring(cfg_tuple_get(key, "name"));
582 	CHECK(convert_name(&fkeyname, &keyname, keynamestr));
583 
584 	if (!root_validation && !dlv_validation)
585 		return (ISC_R_SUCCESS);
586 
587 	match_root = dns_name_equal(keyname, anchor_name);
588 	match_dlv = dns_name_equal(keyname, dlv_name);
589 
590 	if (!match_root && !match_dlv)
591 		return (ISC_R_SUCCESS);
592 	if ((!root_validation && match_root) || (!dlv_validation && match_dlv))
593 		return (ISC_R_SUCCESS);
594 
595 	if (match_root)
596 		delv_log(ISC_LOG_DEBUG(3), "adding trust anchor %s",
597 			  trust_anchor);
598 	if (match_dlv)
599 		delv_log(ISC_LOG_DEBUG(3), "adding DLV trust anchor %s",
600 			  dlv_anchor);
601 
602 	flags = cfg_obj_asuint32(cfg_tuple_get(key, "flags"));
603 	proto = cfg_obj_asuint32(cfg_tuple_get(key, "protocol"));
604 	alg = cfg_obj_asuint32(cfg_tuple_get(key, "algorithm"));
605 
606 	keystruct.common.rdclass = dns_rdataclass_in;
607 	keystruct.common.rdtype = dns_rdatatype_dnskey;
608 	/*
609 	 * The key data in keystruct is not dynamically allocated.
610 	 */
611 	keystruct.mctx = NULL;
612 
613 	ISC_LINK_INIT(&keystruct.common, link);
614 
615 	if (flags > 0xffff)
616 		CHECK(ISC_R_RANGE);
617 	if (proto > 0xff)
618 		CHECK(ISC_R_RANGE);
619 	if (alg > 0xff)
620 		CHECK(ISC_R_RANGE);
621 
622 	keystruct.flags = (isc_uint16_t)flags;
623 	keystruct.protocol = (isc_uint8_t)proto;
624 	keystruct.algorithm = (isc_uint8_t)alg;
625 
626 	isc_buffer_init(&keydatabuf, keydata, sizeof(keydata));
627 	isc_buffer_init(&rrdatabuf, rrdata, sizeof(rrdata));
628 
629 	keystr = cfg_obj_asstring(cfg_tuple_get(key, "key"));
630 	CHECK(isc_base64_decodestring(keystr, &keydatabuf));
631 	isc_buffer_usedregion(&keydatabuf, &r);
632 	keystruct.datalen = r.length;
633 	keystruct.data = r.base;
634 
635 	CHECK(dns_rdata_fromstruct(NULL,
636 				   keystruct.common.rdclass,
637 				   keystruct.common.rdtype,
638 				   &keystruct, &rrdatabuf));
639 
640 	CHECK(dns_client_addtrustedkey(client, dns_rdataclass_in,
641 				       keyname, &rrdatabuf));
642 	trusted_keys++;
643 
644  cleanup:
645 	if (result == DST_R_NOCRYPTO)
646 		cfg_obj_log(key, lctx, ISC_LOG_ERROR, "no crypto support");
647 	else if (result == DST_R_UNSUPPORTEDALG) {
648 		cfg_obj_log(key, lctx, ISC_LOG_WARNING,
649 			    "skipping trusted key '%s': %s",
650 			    keynamestr, isc_result_totext(result));
651 		result = ISC_R_SUCCESS;
652 	} else if (result != ISC_R_SUCCESS) {
653 		cfg_obj_log(key, lctx, ISC_LOG_ERROR,
654 			    "failed to add trusted key '%s': %s",
655 			    keynamestr, isc_result_totext(result));
656 		result = ISC_R_FAILURE;
657 	}
658 
659 	return (result);
660 }
661 
662 static isc_result_t
663 load_keys(const cfg_obj_t *keys, dns_client_t *client) {
664 	const cfg_listelt_t *elt, *elt2;
665 	const cfg_obj_t *key, *keylist;
666 	isc_result_t result = ISC_R_SUCCESS;
667 
668 	for (elt = cfg_list_first(keys);
669 	     elt != NULL;
670 	     elt = cfg_list_next(elt))
671 	{
672 		keylist = cfg_listelt_value(elt);
673 
674 		for (elt2 = cfg_list_first(keylist);
675 		     elt2 != NULL;
676 		     elt2 = cfg_list_next(elt2))
677 		{
678 			key = cfg_listelt_value(elt2);
679 			CHECK(key_fromconfig(key, client));
680 		}
681 	}
682 
683  cleanup:
684 	if (result == DST_R_NOCRYPTO)
685 		result = ISC_R_SUCCESS;
686 	return (result);
687 }
688 
689 static isc_result_t
690 setup_dnsseckeys(dns_client_t *client) {
691 	isc_result_t result;
692 	cfg_parser_t *parser = NULL;
693 	const cfg_obj_t *keys = NULL;
694 	const cfg_obj_t *managed_keys = NULL;
695 	cfg_obj_t *bindkeys = NULL;
696 	const char *filename = anchorfile;
697 
698 	if (!root_validation && !dlv_validation)
699 		return (ISC_R_SUCCESS);
700 
701 	if (filename == NULL) {
702 #ifndef WIN32
703 		filename = NS_SYSCONFDIR "/bind.keys";
704 #else
705 		static char buf[MAX_PATH];
706 		strlcpy(buf, isc_ntpaths_get(SYS_CONF_DIR), sizeof(buf));
707 		strlcat(buf, "\\bind.keys", sizeof(buf));
708 		filename = buf;
709 #endif
710 	}
711 
712 	if (trust_anchor == NULL) {
713 		trust_anchor = isc_mem_strdup(mctx, ".");
714 		if (trust_anchor == NULL)
715 			fatal("out of memory");
716 	}
717 
718 	if (dlv_anchor == NULL) {
719 		dlv_anchor = isc_mem_strdup(mctx, "dlv.isc.org");
720 		if (dlv_anchor == NULL)
721 			fatal("out of memory");
722 	}
723 
724 	CHECK(convert_name(&afn, &anchor_name, trust_anchor));
725 	CHECK(convert_name(&dfn, &dlv_name, dlv_anchor));
726 
727 	CHECK(cfg_parser_create(mctx, dns_lctx, &parser));
728 
729 	if (access(filename, R_OK) != 0) {
730 		if (anchorfile != NULL)
731 			fatal("Unable to read key file '%s'", anchorfile);
732 	} else {
733 		result = cfg_parse_file(parser, filename,
734 					&cfg_type_bindkeys, &bindkeys);
735 		if (result != ISC_R_SUCCESS)
736 			if (anchorfile != NULL)
737 				fatal("Unable to load keys from '%s'",
738 				      anchorfile);
739 	}
740 
741 	if (bindkeys == NULL) {
742 		isc_buffer_t b;
743 
744 		isc_buffer_init(&b, anchortext, sizeof(anchortext) - 1);
745 		isc_buffer_add(&b, sizeof(anchortext) - 1);
746 		result = cfg_parse_buffer(parser, &b, &cfg_type_bindkeys,
747 					  &bindkeys);
748 		if (result != ISC_R_SUCCESS)
749 			fatal("Unable to parse built-in keys");
750 	}
751 
752 	INSIST(bindkeys != NULL);
753 	cfg_map_get(bindkeys, "trusted-keys", &keys);
754 	cfg_map_get(bindkeys, "managed-keys", &managed_keys);
755 
756 	if (keys != NULL)
757 		CHECK(load_keys(keys, client));
758 	if (managed_keys != NULL)
759 		CHECK(load_keys(managed_keys, client));
760 	result = ISC_R_SUCCESS;
761 
762 	if (trusted_keys == 0)
763 		fatal("No trusted keys were loaded");
764 
765 	if (dlv_validation)
766 		dns_client_setdlv(client, dns_rdataclass_in, dlv_anchor);
767 
768  cleanup:
769 	if (result != ISC_R_SUCCESS)
770 		delv_log(ISC_LOG_ERROR, "setup_dnsseckeys: %s",
771 			  isc_result_totext(result));
772 	return (result);
773 }
774 
775 static isc_result_t
776 addserver(dns_client_t *client) {
777 	struct addrinfo hints, *res, *cur;
778 	int gai_error;
779 	struct in_addr in4;
780 	struct in6_addr in6;
781 	isc_sockaddr_t *sa;
782 	isc_sockaddrlist_t servers;
783 	isc_uint32_t destport;
784 	isc_result_t result;
785 	dns_name_t *name = NULL;
786 
787 	result = parse_uint(&destport, port, 0xffff, "port");
788 	if (result != ISC_R_SUCCESS)
789 		fatal("Couldn't parse port number");
790 
791 	ISC_LIST_INIT(servers);
792 
793 	if (use_ipv4 && inet_pton(AF_INET, server, &in4) == 1) {
794 		sa = isc_mem_get(mctx, sizeof(*sa));
795 		if (sa == NULL)
796 			return (ISC_R_NOMEMORY);
797 		ISC_LINK_INIT(sa, link);
798 		isc_sockaddr_fromin(sa, &in4, destport);
799 		ISC_LIST_APPEND(servers, sa, link);
800 	} else if (use_ipv6 && inet_pton(AF_INET6, server, &in6) == 1) {
801 		sa = isc_mem_get(mctx, sizeof(*sa));
802 		if (sa == NULL)
803 			return (ISC_R_NOMEMORY);
804 		ISC_LINK_INIT(sa, link);
805 		isc_sockaddr_fromin6(sa, &in6, destport);
806 		ISC_LIST_APPEND(servers, sa, link);
807 	} else {
808 		memset(&hints, 0, sizeof(hints));
809 		if (!use_ipv6)
810 			hints.ai_family = AF_INET;
811 		else if (!use_ipv4)
812 			hints.ai_family = AF_INET6;
813 		else
814 			hints.ai_family = AF_UNSPEC;
815 		hints.ai_socktype = SOCK_DGRAM;
816 		hints.ai_protocol = IPPROTO_UDP;
817 		gai_error = getaddrinfo(server, port, &hints, &res);
818 		if (gai_error != 0) {
819 			delv_log(ISC_LOG_ERROR,
820 				  "getaddrinfo failed: %s",
821 				  gai_strerror(gai_error));
822 			return (ISC_R_FAILURE);
823 		}
824 
825 		result = ISC_R_SUCCESS;
826 		for (cur = res; cur != NULL; cur = cur->ai_next) {
827 			if (cur->ai_family != AF_INET &&
828 			    cur->ai_family != AF_INET6)
829 				continue;
830 			sa = isc_mem_get(mctx, sizeof(*sa));
831 			if (sa == NULL) {
832 				result = ISC_R_NOMEMORY;
833 				break;
834 			}
835 			memset(sa, 0, sizeof(*sa));
836 			ISC_LINK_INIT(sa, link);
837 			memmove(&sa->type, cur->ai_addr, cur->ai_addrlen);
838 			sa->length = (unsigned int)cur->ai_addrlen;
839 			ISC_LIST_APPEND(servers, sa, link);
840 		}
841 		freeaddrinfo(res);
842 		CHECK(result);
843 	}
844 
845 
846 	CHECK(dns_client_setservers(client, dns_rdataclass_in, name, &servers));
847 
848  cleanup:
849 	while (!ISC_LIST_EMPTY(servers)) {
850 		sa = ISC_LIST_HEAD(servers);
851 		ISC_LIST_UNLINK(servers, sa, link);
852 		isc_mem_put(mctx, sa, sizeof(*sa));
853 	}
854 
855 	if (result != ISC_R_SUCCESS)
856 		delv_log(ISC_LOG_ERROR, "addserver: %s",
857 			  isc_result_totext(result));
858 
859 	return (result);
860 }
861 
862 static isc_result_t
863 findserver(dns_client_t *client) {
864 	isc_result_t result;
865 	irs_resconf_t *resconf = NULL;
866 	isc_sockaddrlist_t *nameservers;
867 	isc_sockaddr_t *sa, *next;
868 	isc_uint32_t destport;
869 
870 	result = parse_uint(&destport, port, 0xffff, "port");
871 	if (result != ISC_R_SUCCESS)
872 		fatal("Couldn't parse port number");
873 
874 	result = irs_resconf_load(mctx, "/etc/resolv.conf", &resconf);
875 	if (result != ISC_R_SUCCESS && result != ISC_R_FILENOTFOUND) {
876 		delv_log(ISC_LOG_ERROR, "irs_resconf_load: %s",
877 			  isc_result_totext(result));
878 		goto cleanup;
879 	}
880 
881 	/* Get nameservers from resolv.conf */
882 	nameservers = irs_resconf_getnameservers(resconf);
883 	for (sa = ISC_LIST_HEAD(*nameservers); sa != NULL; sa = next) {
884 		next = ISC_LIST_NEXT(sa, link);
885 
886 		/* Set destination port */
887 		if (sa->type.sa.sa_family == AF_INET && use_ipv4) {
888 			sa->type.sin.sin_port = htons(destport);
889 			continue;
890 		}
891 		if (sa->type.sa.sa_family == AF_INET6 && use_ipv6) {
892 			sa->type.sin6.sin6_port = htons(destport);
893 			continue;
894 		}
895 
896 		/* Incompatible protocol family */
897 		ISC_LIST_UNLINK(*nameservers, sa, link);
898 		isc_mem_put(mctx, sa, sizeof(*sa));
899 	}
900 
901 	/* None found, use localhost */
902 	if (ISC_LIST_EMPTY(*nameservers)) {
903 		if (use_ipv4) {
904 			struct in_addr localhost;
905 			localhost.s_addr = htonl(INADDR_LOOPBACK);
906 			sa = isc_mem_get(mctx, sizeof(*sa));
907 			if (sa == NULL) {
908 				result = ISC_R_NOMEMORY;
909 				goto cleanup;
910 			}
911 			isc_sockaddr_fromin(sa, &localhost, destport);
912 
913 			ISC_LINK_INIT(sa, link);
914 			ISC_LIST_APPEND(*nameservers, sa, link);
915 		}
916 
917 		if (use_ipv6) {
918 			sa = isc_mem_get(mctx, sizeof(*sa));
919 			if (sa == NULL) {
920 				result = ISC_R_NOMEMORY;
921 				goto cleanup;
922 			}
923 			isc_sockaddr_fromin6(sa, &in6addr_loopback, destport);
924 
925 			ISC_LINK_INIT(sa, link);
926 			ISC_LIST_APPEND(*nameservers, sa, link);
927 		}
928 	}
929 
930 	result = dns_client_setservers(client, dns_rdataclass_in, NULL,
931 				       nameservers);
932 	if (result != ISC_R_SUCCESS)
933 		delv_log(ISC_LOG_ERROR, "dns_client_setservers: %s",
934 			  isc_result_totext(result));
935 
936 cleanup:
937 	if (resconf != NULL)
938 		irs_resconf_destroy(&resconf);
939 	return (result);
940 }
941 
942 static char *
943 next_token(char **stringp, const char *delim) {
944 	char *res;
945 
946 	do {
947 		res = strsep(stringp, delim);
948 		if (res == NULL)
949 			break;
950 	} while (*res == '\0');
951 	return (res);
952 }
953 
954 static isc_result_t
955 parse_uint(isc_uint32_t *uip, const char *value, isc_uint32_t max,
956 	   const char *desc) {
957 	isc_uint32_t n;
958 	isc_result_t result = isc_parse_uint32(&n, value, 10);
959 	if (result == ISC_R_SUCCESS && n > max)
960 		result = ISC_R_RANGE;
961 	if (result != ISC_R_SUCCESS) {
962 		printf("invalid %s '%s': %s\n", desc,
963 		       value, isc_result_totext(result));
964 		return (result);
965 	}
966 	*uip = n;
967 	return (ISC_R_SUCCESS);
968 }
969 
970 static void
971 plus_option(char *option) {
972 	isc_result_t result;
973 	char option_store[256];
974 	char *cmd, *value, *ptr;
975 	isc_boolean_t state = ISC_TRUE;
976 
977 	strncpy(option_store, option, sizeof(option_store));
978 	option_store[sizeof(option_store)-1]=0;
979 	ptr = option_store;
980 	cmd = next_token(&ptr,"=");
981 	if (cmd == NULL) {
982 		printf(";; Invalid option %s\n", option_store);
983 		return;
984 	}
985 	value = ptr;
986 	if (strncasecmp(cmd, "no", 2)==0) {
987 		cmd += 2;
988 		state = ISC_FALSE;
989 	}
990 
991 #define FULLCHECK(A) \
992 	do { \
993 		size_t _l = strlen(cmd); \
994 		if (_l >= sizeof(A) || strncasecmp(cmd, A, _l) != 0) \
995 			goto invalid_option; \
996 	} while (/*CONSTCOND*/0)
997 
998 	switch (cmd[0]) {
999 	case 'a': /* all */
1000 		FULLCHECK("all");
1001 		showcomments = state;
1002 		rrcomments = state;
1003 		showtrust = state;
1004 		break;
1005 	case 'c':
1006 		switch (cmd[1]) {
1007 		case 'd': /* cdflag */
1008 			FULLCHECK("cdflag");
1009 			cdflag = state;
1010 			break;
1011 		case 'l': /* class */
1012 			FULLCHECK("class");
1013 			noclass = ISC_TF(!state);
1014 			break;
1015 		case 'o': /* comments */
1016 			FULLCHECK("comments");
1017 			showcomments = state;
1018 			break;
1019 		case 'r': /* crypto */
1020 			FULLCHECK("crypto");
1021 			nocrypto = ISC_TF(!state);
1022 			break;
1023 		default:
1024 			goto invalid_option;
1025 		}
1026 		break;
1027 	case 'd':
1028 		switch (cmd[1]) {
1029 		case 'l': /* dlv */
1030 			FULLCHECK("dlv");
1031 			if (state && no_sigs)
1032 				break;
1033 			dlv_validation = state;
1034 			if (value != NULL) {
1035 				dlv_anchor = isc_mem_strdup(mctx, value);
1036 				if (dlv_anchor == NULL)
1037 					fatal("out of memory");
1038 			}
1039 			break;
1040 		case 'n': /* dnssec */
1041 			FULLCHECK("dnssec");
1042 			showdnssec = state;
1043 			break;
1044 		default:
1045 			goto invalid_option;
1046 		}
1047 		break;
1048 	case 'm':
1049 		switch (cmd[1]) {
1050 		case 't': /* mtrace */
1051 			message_trace = state;
1052 			if (state)
1053 				resolve_trace = state;
1054 			break;
1055 		case 'u': /* multiline */
1056 			FULLCHECK("multiline");
1057 			multiline = state;
1058 			break;
1059 		default:
1060 			goto invalid_option;
1061 		}
1062 		break;
1063 	case 'r':
1064 		switch (cmd[1]) {
1065 		case 'o': /* root */
1066 			FULLCHECK("root");
1067 			if (state && no_sigs)
1068 				break;
1069 			root_validation = state;
1070 			if (value != NULL) {
1071 				trust_anchor = isc_mem_strdup(mctx, value);
1072 				if (trust_anchor == NULL)
1073 					fatal("out of memory");
1074 			}
1075 			break;
1076 		case 'r': /* rrcomments */
1077 			FULLCHECK("rrcomments");
1078 			rrcomments = state;
1079 			break;
1080 		case 't': /* rtrace */
1081 			FULLCHECK("rtrace");
1082 			resolve_trace = state;
1083 			break;
1084 		default:
1085 			goto invalid_option;
1086 		}
1087 		break;
1088 	case 's':
1089 		switch (cmd[1]) {
1090 		case 'h': /* short */
1091 			FULLCHECK("short");
1092 			short_form = state;
1093 			if (short_form) {
1094 				multiline = ISC_FALSE;
1095 				showcomments = ISC_FALSE;
1096 				showtrust = ISC_FALSE;
1097 				showdnssec = ISC_FALSE;
1098 			}
1099 			break;
1100 		case 'p': /* split */
1101 			FULLCHECK("split");
1102 			if (value != NULL && !state)
1103 				goto invalid_option;
1104 			if (!state) {
1105 				splitwidth = 0;
1106 				break;
1107 			} else if (value == NULL)
1108 				break;
1109 
1110 			result = parse_uint(&splitwidth, value,
1111 					    1023, "split");
1112 			if (splitwidth % 4 != 0) {
1113 				splitwidth = ((splitwidth + 3) / 4) * 4;
1114 				warn("split must be a multiple of 4; "
1115 				     "adjusting to %d", splitwidth);
1116 			}
1117 			/*
1118 			 * There is an adjustment done in the
1119 			 * totext_<rrtype>() functions which causes
1120 			 * splitwidth to shrink.  This is okay when we're
1121 			 * using the default width but incorrect in this
1122 			 * case, so we correct for it
1123 			 */
1124 			if (splitwidth)
1125 				splitwidth += 3;
1126 			if (result != ISC_R_SUCCESS)
1127 				fatal("Couldn't parse split");
1128 			break;
1129 		default:
1130 			goto invalid_option;
1131 		}
1132 		break;
1133 	case 't':
1134 		switch (cmd[1]) {
1135 		case 'r': /* trust */
1136 			FULLCHECK("trust");
1137 			showtrust = state;
1138 			break;
1139 		case 't': /* ttl */
1140 			FULLCHECK("ttl");
1141 			nottl = ISC_TF(!state);
1142 			break;
1143 		default:
1144 			goto invalid_option;
1145 		}
1146 		break;
1147 	case 'v': /* vtrace */
1148 		FULLCHECK("vtrace");
1149 		validator_trace = state;
1150 		if (state)
1151 			resolve_trace = state;
1152 		break;
1153 	default:
1154 	invalid_option:
1155 		/*
1156 		 * We can also add a "need_value:" case here if we ever
1157 		 * add a plus-option that requires a specified value
1158 		 */
1159 		fprintf(stderr, "Invalid option: +%s\n", option);
1160 		usage();
1161 	}
1162 	return;
1163 }
1164 
1165 /*
1166  * options: "46a:b:c:d:himp:q:t:vx:";
1167  */
1168 static const char *single_dash_opts = "46himv";
1169 static isc_boolean_t
1170 dash_option(char *option, char *next, isc_boolean_t *open_type_class) {
1171 	char opt, *value;
1172 	isc_result_t result;
1173 	isc_boolean_t value_from_next;
1174 	isc_textregion_t tr;
1175 	dns_rdatatype_t rdtype;
1176 	dns_rdataclass_t rdclass;
1177 	char textname[MAXNAME];
1178 	struct in_addr in4;
1179 	struct in6_addr in6;
1180 	in_port_t srcport;
1181 	isc_uint32_t num;
1182 	char *hash;
1183 
1184 	while (strpbrk(option, single_dash_opts) == &option[0]) {
1185 		/*
1186 		 * Since the -[46himv] options do not take an argument,
1187 		 * account for them (in any number and/or combination)
1188 		 * if they appear as the first character(s) of a q-opt.
1189 		 */
1190 		opt = option[0];
1191 		switch (opt) {
1192 		case '4':
1193 			if (isc_net_probeipv4() != ISC_R_SUCCESS)
1194 				fatal("IPv4 networking not available");
1195 			if (use_ipv6) {
1196 				isc_net_disableipv6();
1197 				use_ipv6 = ISC_FALSE;
1198 			}
1199 			break;
1200 		case '6':
1201 			if (isc_net_probeipv6() != ISC_R_SUCCESS)
1202 				fatal("IPv6 networking not available");
1203 			if (use_ipv4) {
1204 				isc_net_disableipv4();
1205 				use_ipv4 = ISC_FALSE;
1206 			}
1207 			break;
1208 		case 'h':
1209 			usage();
1210 			exit(0);
1211 			/* NOTREACHED */
1212 		case 'i':
1213 			no_sigs = ISC_TRUE;
1214 			dlv_validation = ISC_FALSE;
1215 			root_validation = ISC_FALSE;
1216 			break;
1217 		case 'm':
1218 			/* handled in preparse_args() */
1219 			break;
1220 		case 'v':
1221 			fputs("delv " VERSION "\n", stderr);
1222 			exit(0);
1223 			/* NOTREACHED */
1224 		default:
1225 			INSIST(0);
1226 		}
1227 		if (strlen(option) > 1U)
1228 			option = &option[1];
1229 		else
1230 			return (ISC_FALSE);
1231 	}
1232 	opt = option[0];
1233 	if (strlen(option) > 1U) {
1234 		value_from_next = ISC_FALSE;
1235 		value = &option[1];
1236 	} else {
1237 		value_from_next = ISC_TRUE;
1238 		value = next;
1239 	}
1240 	if (value == NULL)
1241 		goto invalid_option;
1242 	switch (opt) {
1243 	case 'a':
1244 		anchorfile = isc_mem_strdup(mctx, value);
1245 		if (anchorfile == NULL)
1246 			fatal("out of memory");
1247 		return (value_from_next);
1248 	case 'b':
1249 		hash = strchr(value, '#');
1250 		if (hash != NULL) {
1251 			result = parse_uint(&num, hash + 1, 0xffff, "port");
1252 			if (result != ISC_R_SUCCESS)
1253 				fatal("Couldn't parse port number");
1254 			srcport = num;
1255 			*hash = '\0';
1256 		} else
1257 			srcport = 0;
1258 
1259 		if (inet_pton(AF_INET, value, &in4) == 1) {
1260 			if (srcaddr4 != NULL)
1261 				fatal("Only one local address per family "
1262 				      "can be specified\n");
1263 			isc_sockaddr_fromin(&a4, &in4, srcport);
1264 			srcaddr4 = &a4;
1265 		} else if (inet_pton(AF_INET6, value, &in6) == 1) {
1266 			if (srcaddr6 != NULL)
1267 				fatal("Only one local address per family "
1268 				      "can be specified\n");
1269 			isc_sockaddr_fromin6(&a6, &in6, srcport);
1270 			srcaddr6 = &a6;
1271 		} else {
1272 			if (hash != NULL)
1273 				*hash = '#';
1274 			fatal("Invalid address %s", value);
1275 		}
1276 		if (hash != NULL)
1277 			*hash = '#';
1278 		return (value_from_next);
1279 	case 'c':
1280 		if (classset)
1281 			warn("extra query class");
1282 
1283 		*open_type_class = ISC_FALSE;
1284 		tr.base = value;
1285 		tr.length = strlen(value);
1286 		result = dns_rdataclass_fromtext(&rdclass,
1287 						 (isc_textregion_t *)&tr);
1288 		if (result == ISC_R_SUCCESS)
1289 			classset = ISC_TRUE;
1290 		else if (rdclass != dns_rdataclass_in)
1291 			warn("ignoring non-IN query class");
1292 		else
1293 			warn("ignoring invalid class");
1294 		return (value_from_next);
1295 	case 'd':
1296 		result = parse_uint(&num, value, 99, "debug level");
1297 		if (result != ISC_R_SUCCESS)
1298 			fatal("Couldn't parse debug level");
1299 		loglevel = num;
1300 		return (value_from_next);
1301 	case 'p':
1302 		port = value;
1303 		return (value_from_next);
1304 	case 'q':
1305 		if (curqname != NULL) {
1306 			warn("extra query name");
1307 			isc_mem_free(mctx, curqname);
1308 		}
1309 		curqname = isc_mem_strdup(mctx, value);
1310 		if (curqname == NULL)
1311 			fatal("out of memory");
1312 		return (value_from_next);
1313 	case 't':
1314 		*open_type_class = ISC_FALSE;
1315 		tr.base = value;
1316 		tr.length = strlen(value);
1317 		result = dns_rdatatype_fromtext(&rdtype,
1318 					(isc_textregion_t *)&tr);
1319 		if (result == ISC_R_SUCCESS) {
1320 			if (typeset)
1321 				warn("extra query type");
1322 			if (rdtype == dns_rdatatype_ixfr ||
1323 			    rdtype == dns_rdatatype_axfr)
1324 				fatal("Transfer not supported");
1325 			qtype = rdtype;
1326 			typeset = ISC_TRUE;
1327 		} else
1328 			warn("ignoring invalid type");
1329 		return (value_from_next);
1330 	case 'x':
1331 		result = get_reverse(textname, sizeof(textname), value,
1332 				     ISC_FALSE);
1333 		if (result == ISC_R_SUCCESS) {
1334 			if (curqname != NULL) {
1335 				isc_mem_free(mctx, curqname);
1336 				warn("extra query name");
1337 			}
1338 			curqname = isc_mem_strdup(mctx, textname);
1339 			if (curqname == NULL)
1340 				fatal("out of memory");
1341 			if (typeset)
1342 				warn("extra query type");
1343 			qtype = dns_rdatatype_ptr;
1344 			typeset = ISC_TRUE;
1345 		} else {
1346 			fprintf(stderr, "Invalid IP address %s\n", value);
1347 			exit(1);
1348 		}
1349 		return (value_from_next);
1350 	invalid_option:
1351 	default:
1352 		fprintf(stderr, "Invalid option: -%s\n", option);
1353 		usage();
1354 	}
1355 	/* NOTREACHED */
1356 	return (ISC_FALSE);
1357 }
1358 
1359 /*
1360  * Check for -m first to determine whether to enable
1361  * memory debugging when setting up the memory context.
1362  */
1363 static void
1364 preparse_args(int argc, char **argv) {
1365 	char *option;
1366 
1367 	for (argc--, argv++; argc > 0; argc--, argv++) {
1368 		if (argv[0][0] != '-')
1369 			continue;
1370 		option = &argv[0][1];
1371 		while (strpbrk(option, single_dash_opts) == &option[0]) {
1372 			if (option[0] == 'm') {
1373 				isc_mem_debugging = ISC_MEM_DEBUGTRACE |
1374 					ISC_MEM_DEBUGRECORD;
1375 				return;
1376 			}
1377 			option = &option[1];
1378 		}
1379 	}
1380 }
1381 
1382 /*
1383  * Argument parsing is based on dig, but simplified: only one
1384  * QNAME/QCLASS/QTYPE tuple can be specified, and options have
1385  * been removed that aren't applicable to delv. The interface
1386  * should be familiar to dig users, however.
1387  */
1388 static void
1389 parse_args(int argc, char **argv) {
1390 	isc_result_t result;
1391 	isc_textregion_t tr;
1392 	dns_rdatatype_t rdtype;
1393 	dns_rdataclass_t rdclass;
1394 	isc_boolean_t open_type_class = ISC_TRUE;
1395 
1396 	for (; argc > 0; argc--, argv++) {
1397 		if (argv[0][0] == '@') {
1398 			server = &argv[0][1];
1399 		} else if (argv[0][0] == '+') {
1400 			plus_option(&argv[0][1]);
1401 		} else if (argv[0][0] == '-') {
1402 			if (argc <= 1) {
1403 				if (dash_option(&argv[0][1], NULL,
1404 						&open_type_class))
1405 				{
1406 					argc--;
1407 					argv++;
1408 				}
1409 			} else {
1410 				if (dash_option(&argv[0][1], argv[1],
1411 						&open_type_class))
1412 				{
1413 					argc--;
1414 					argv++;
1415 				}
1416 			}
1417 		} else {
1418 			/*
1419 			 * Anything which isn't an option
1420 			 */
1421 			if (open_type_class) {
1422 				tr.base = argv[0];
1423 				tr.length = strlen(argv[0]);
1424 				result = dns_rdatatype_fromtext(&rdtype,
1425 					(isc_textregion_t *)&tr);
1426 				if (result == ISC_R_SUCCESS) {
1427 					if (typeset)
1428 						warn("extra query type");
1429 					if (rdtype == dns_rdatatype_ixfr ||
1430 					    rdtype == dns_rdatatype_axfr)
1431 						fatal("Transfer not supported");
1432 					qtype = rdtype;
1433 					typeset = ISC_TRUE;
1434 					continue;
1435 				}
1436 				result = dns_rdataclass_fromtext(&rdclass,
1437 						     (isc_textregion_t *)&tr);
1438 				if (result == ISC_R_SUCCESS) {
1439 					if (classset)
1440 						warn("extra query class");
1441 					else if (rdclass != dns_rdataclass_in)
1442 						warn("ignoring non-IN "
1443 						     "query class");
1444 					continue;
1445 				}
1446 			}
1447 
1448 			if (curqname == NULL) {
1449 				curqname = isc_mem_strdup(mctx, argv[0]);
1450 				if (curqname == NULL)
1451 					fatal("out of memory");
1452 			}
1453 		}
1454 	}
1455 
1456 	/*
1457 	 * If no qname or qtype specified, search for root/NS
1458 	 * If no qtype specified, use A
1459 	 */
1460 	if (!typeset)
1461 		qtype = dns_rdatatype_a;
1462 
1463 	if (curqname == NULL) {
1464 		qname = isc_mem_strdup(mctx, ".");
1465 		if (qname == NULL)
1466 			fatal("out of memory");
1467 
1468 		if (!typeset)
1469 			qtype = dns_rdatatype_ns;
1470 	} else
1471 		qname = curqname;
1472 }
1473 
1474 static isc_result_t
1475 append_str(const char *text, int len, char **p, char *end) {
1476 	if (len > end - *p)
1477 		return (ISC_R_NOSPACE);
1478 	memmove(*p, text, len);
1479 	*p += len;
1480 	return (ISC_R_SUCCESS);
1481 }
1482 
1483 static isc_result_t
1484 reverse_octets(const char *in, char **p, char *end) {
1485 	char *dot = strchr(in, '.');
1486 	int len;
1487 	if (dot != NULL) {
1488 		isc_result_t result;
1489 		result = reverse_octets(dot + 1, p, end);
1490 		if (result != ISC_R_SUCCESS)
1491 			return (result);
1492 		result = append_str(".", 1, p, end);
1493 		if (result != ISC_R_SUCCESS)
1494 			return (result);
1495 		len = (int)(dot - in);
1496 	} else
1497 		len = strlen(in);
1498 	return (append_str(in, len, p, end));
1499 }
1500 
1501 static isc_result_t
1502 get_reverse(char *reverse, size_t len, char *value, isc_boolean_t strict) {
1503 	int r;
1504 	isc_result_t result;
1505 	isc_netaddr_t addr;
1506 
1507 	addr.family = AF_INET6;
1508 	r = inet_pton(AF_INET6, value, &addr.type.in6);
1509 	if (r > 0) {
1510 		/* This is a valid IPv6 address. */
1511 		dns_fixedname_t fname;
1512 		dns_name_t *name;
1513 		unsigned int options = 0;
1514 
1515 		dns_fixedname_init(&fname);
1516 		name = dns_fixedname_name(&fname);
1517 		result = dns_byaddr_createptrname2(&addr, options, name);
1518 		if (result != ISC_R_SUCCESS)
1519 			return (result);
1520 		dns_name_format(name, reverse, (unsigned int)len);
1521 		return (ISC_R_SUCCESS);
1522 	} else {
1523 		/*
1524 		 * Not a valid IPv6 address.  Assume IPv4.
1525 		 * If 'strict' is not set, construct the
1526 		 * in-addr.arpa name by blindly reversing
1527 		 * octets whether or not they look like integers,
1528 		 * so that this can be used for RFC2317 names
1529 		 * and such.
1530 		 */
1531 		char *p = reverse;
1532 		char *end = reverse + len;
1533 		if (strict && inet_pton(AF_INET, value, &addr.type.in) != 1)
1534 			return (DNS_R_BADDOTTEDQUAD);
1535 		result = reverse_octets(value, &p, end);
1536 		if (result != ISC_R_SUCCESS)
1537 			return (result);
1538 		result = append_str(".in-addr.arpa.", 15, &p, end);
1539 		if (result != ISC_R_SUCCESS)
1540 			return (result);
1541 		return (ISC_R_SUCCESS);
1542 	}
1543 }
1544 
1545 int
1546 main(int argc, char *argv[]) {
1547 	dns_client_t *client = NULL;
1548 	isc_result_t result;
1549 	dns_fixedname_t qfn;
1550 	dns_name_t *query_name, *response_name;
1551 	dns_rdataset_t *rdataset;
1552 	dns_namelist_t namelist;
1553 	unsigned int resopt, clopt;
1554 	isc_appctx_t *actx = NULL;
1555 	isc_taskmgr_t *taskmgr = NULL;
1556 	isc_socketmgr_t *socketmgr = NULL;
1557 	isc_timermgr_t *timermgr = NULL;
1558 	dns_master_style_t *style = NULL;
1559 #ifndef WIN32
1560 	struct sigaction sa;
1561 #endif
1562 
1563 	preparse_args(argc, argv);
1564 	progname = argv[0];
1565 
1566 	argc--;
1567 	argv++;
1568 
1569 	isc_lib_register();
1570 	result = dns_lib_init();
1571 	if (result != ISC_R_SUCCESS)
1572 		fatal("dns_lib_init failed: %d", result);
1573 
1574 	result = isc_mem_create(0, 0, &mctx);
1575 	if (result != ISC_R_SUCCESS)
1576 		fatal("failed to create mctx");
1577 
1578 	CHECK(isc_appctx_create(mctx, &actx));
1579 	CHECK(isc_taskmgr_createinctx(mctx, actx, 1, 0, &taskmgr));
1580 	CHECK(isc_socketmgr_createinctx(mctx, actx, &socketmgr));
1581 	CHECK(isc_timermgr_createinctx(mctx, actx, &timermgr));
1582 
1583 	parse_args(argc, argv);
1584 
1585 	CHECK(setup_style(&style));
1586 
1587 	setup_logging(stderr);
1588 
1589 	CHECK(isc_app_ctxstart(actx));
1590 
1591 #ifndef WIN32
1592 	/* Unblock SIGINT if it's been blocked by isc_app_ctxstart() */
1593 	memset(&sa, 0, sizeof(sa));
1594 	sa.sa_handler = SIG_DFL;
1595 	if (sigfillset(&sa.sa_mask) != 0 || sigaction(SIGINT, &sa, NULL) < 0)
1596 		fatal("Couldn't set up signal handler");
1597 #endif
1598 
1599 	/* Create client */
1600 	clopt = DNS_CLIENTCREATEOPT_USECACHE;
1601 	result = dns_client_createx2(mctx, actx, taskmgr, socketmgr, timermgr,
1602 				     clopt, &client, srcaddr4, srcaddr6);
1603 	if (result != ISC_R_SUCCESS) {
1604 		delv_log(ISC_LOG_ERROR, "dns_client_create: %s",
1605 			  isc_result_totext(result));
1606 		goto cleanup;
1607 	}
1608 
1609 	/* Set the nameserver */
1610 	if (server != NULL)
1611 		addserver(client);
1612 	else
1613 		findserver(client);
1614 
1615 	CHECK(setup_dnsseckeys(client));
1616 
1617 	/* Construct QNAME */
1618 	CHECK(convert_name(&qfn, &query_name, qname));
1619 
1620 	/* Set up resolution options */
1621 	resopt = DNS_CLIENTRESOPT_ALLOWRUN | DNS_CLIENTRESOPT_NOCDFLAG;
1622 	if (no_sigs)
1623 		resopt |= DNS_CLIENTRESOPT_NODNSSEC;
1624 	if (!root_validation && !dlv_validation)
1625 		resopt |= DNS_CLIENTRESOPT_NOVALIDATE;
1626 	if (cdflag)
1627 		resopt &= ~DNS_CLIENTRESOPT_NOCDFLAG;
1628 
1629 	/* Perform resolution */
1630 	ISC_LIST_INIT(namelist);
1631 	result = dns_client_resolve(client, query_name, dns_rdataclass_in,
1632 				    qtype, resopt, &namelist);
1633 	if (result != ISC_R_SUCCESS)
1634 		delv_log(ISC_LOG_ERROR, "resolution failed: %s",
1635 			  isc_result_totext(result));
1636 
1637 	for (response_name = ISC_LIST_HEAD(namelist);
1638 	     response_name != NULL;
1639 	     response_name = ISC_LIST_NEXT(response_name, link)) {
1640 		for (rdataset = ISC_LIST_HEAD(response_name->list);
1641 		     rdataset != NULL;
1642 		     rdataset = ISC_LIST_NEXT(rdataset, link)) {
1643 			result = printdata(rdataset, response_name, style);
1644 			if (result != ISC_R_SUCCESS)
1645 				delv_log(ISC_LOG_ERROR, "print data failed");
1646 		}
1647 	}
1648 
1649 	dns_client_freeresanswer(client, &namelist);
1650 
1651 cleanup:
1652 	if (dlv_anchor != NULL)
1653 		isc_mem_free(mctx, dlv_anchor);
1654 	if (trust_anchor != NULL)
1655 		isc_mem_free(mctx, trust_anchor);
1656 	if (anchorfile != NULL)
1657 		isc_mem_free(mctx, anchorfile);
1658 	if (qname != NULL)
1659 		isc_mem_free(mctx, qname);
1660 	if (style != NULL)
1661 		dns_master_styledestroy(&style, mctx);
1662 	if (client != NULL)
1663 		dns_client_destroy(&client);
1664 	if (taskmgr != NULL)
1665 		isc_taskmgr_destroy(&taskmgr);
1666 	if (timermgr != NULL)
1667 		isc_timermgr_destroy(&timermgr);
1668 	if (socketmgr != NULL)
1669 		isc_socketmgr_destroy(&socketmgr);
1670 	if (actx != NULL)
1671 		isc_appctx_destroy(&actx);
1672 	if (lctx != NULL)
1673 		isc_log_destroy(&lctx);
1674 	isc_mem_detach(&mctx);
1675 
1676 	dns_lib_shutdown();
1677 
1678 	return (0);
1679 }
1680