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