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