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