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