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