1 /* $NetBSD: delv.c,v 1.4 2015/07/08 17:28:54 christos Exp $ */
4 * Copyright (C) 2014, 2015 Internet Systems Consortium, Inc. ("ISC")
6 * Permission to use, copy, modify, and/or distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
10 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
11 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
12 * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
13 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
14 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
15 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
16 * PERFORMANCE OF THIS SOFTWARE.
20 #include <bind.keys.h>
23 #include <sys/types.h>
24 #include <sys/socket.h>
27 #include <netinet/in.h>
29 #include <arpa/inet.h>
40 #include <isc/base64.h>
41 #include <isc/buffer.h>
46 #include <isc/ntpaths.h>
48 #include <isc/parseint.h>
49 #include <isc/print.h>
50 #include <isc/sockaddr.h>
51 #include <isc/socket.h>
52 #include <isc/string.h>
54 #include <isc/timer.h>
57 #include <irs/resconf.h>
58 #include <irs/netdb.h>
60 #include <isccfg/log.h>
61 #include <isccfg/namedconf.h>
63 #include <dns/byaddr.h>
64 #include <dns/client.h>
65 #include <dns/fixedname.h>
66 #include <dns/keytable.h>
67 #include <dns/keyvalues.h>
70 #include <dns/masterdump.h>
72 #include <dns/rdata.h>
73 #include <dns/rdataclass.h>
74 #include <dns/rdataset.h>
75 #include <dns/rdatastruct.h>
76 #include <dns/rdatatype.h>
77 #include <dns/result.h>
78 #include <dns/secalg.h>
82 #include <dst/result.h>
87 if (result != ISC_R_SUCCESS) \
89 } while (/*CONSTCOND*/0)
91 #define MAXNAME (DNS_NAME_MAXTEXT+1)
93 /* Variables used internally by delv. */
95 static isc_mem_t
*mctx
= NULL
;
96 static isc_log_t
*lctx
= NULL
;
99 static char *server
= NULL
;
100 static const char *port
= "53";
101 static isc_sockaddr_t
*srcaddr4
= NULL
, *srcaddr6
= NULL
;
102 static isc_sockaddr_t a4
, a6
;
103 static char *curqname
= NULL
, *qname
= NULL
;
104 static isc_boolean_t classset
= ISC_FALSE
;
105 static dns_rdatatype_t qtype
= dns_rdatatype_none
;
106 static isc_boolean_t typeset
= ISC_FALSE
;
108 static unsigned int styleflags
= 0;
109 static isc_uint32_t splitwidth
= 0xffffffff;
111 showcomments
= ISC_TRUE
,
112 showdnssec
= ISC_TRUE
,
113 showtrust
= ISC_TRUE
,
114 rrcomments
= ISC_TRUE
,
116 nocrypto
= ISC_FALSE
,
118 multiline
= ISC_FALSE
,
119 short_form
= ISC_FALSE
;
122 resolve_trace
= ISC_FALSE
,
123 validator_trace
= ISC_FALSE
,
124 message_trace
= ISC_FALSE
;
133 root_validation
= ISC_TRUE
,
134 dlv_validation
= ISC_TRUE
;
136 static char *anchorfile
= NULL
;
137 static char *trust_anchor
= NULL
;
138 static char *dlv_anchor
= NULL
;
139 static int trusted_keys
= 0;
141 static dns_fixedname_t afn
, dfn
;
142 static dns_name_t
*anchor_name
= NULL
, *dlv_name
= NULL
;
144 /* Default bind.keys contents */
145 static char anchortext
[] = MANAGED_KEYS
;
148 * Static function prototypes
151 get_reverse(char *reverse
, size_t len
, char *value
, isc_boolean_t strict
);
154 parse_uint(isc_uint32_t
*uip
, const char *value
, isc_uint32_t max
,
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 (specify query class)\n"
173 " -4 (use IPv4 query transport only)\n"
174 " -6 (use IPv6 query transport only)\n"
175 " -i (disable DNSSEC validation)\n"
176 " -m (enable memory usage debugging)\n"
177 " d-opt is of the form +keyword[=value], where keyword is:\n"
178 " +[no]all (Set or clear all display flags)\n"
179 " +[no]class (Control display of class)\n"
180 " +[no]crypto (Control display of cryptographic\n"
181 " fields in records)\n"
182 " +[no]multiline (Print records in an expanded format)\n"
183 " +[no]comments (Control display of comment lines)\n"
184 " +[no]rrcomments (Control display of per-record "
186 " +[no]short (Short form answer)\n"
187 " +[no]split=## (Split hex/base64 fields into chunks)\n"
188 " +[no]ttl (Control display of ttls in records)\n"
189 " +[no]trust (Control display of trust level)\n"
190 " +[no]rtrace (Trace resolver fetches)\n"
191 " +[no]mtrace (Trace messages received)\n"
192 " +[no]vtrace (Trace validation process)\n"
193 " +[no]dlv (DNSSEC lookaside validation anchor)\n"
194 " +[no]root (DNSSEC validation trust anchor)\n"
195 " +[no]dnssec (Display DNSSEC records)\n"
196 " -h (print help and exit)\n"
197 " -v (print version and exit)\n",
202 ISC_PLATFORM_NORETURN_PRE
static void
203 fatal(const char *format
, ...)
204 ISC_FORMAT_PRINTF(1, 2) ISC_PLATFORM_NORETURN_POST
;
207 fatal(const char *format
, ...) {
211 fprintf(stderr
, "%s: ", progname
);
212 va_start(args
, format
);
213 vfprintf(stderr
, format
, args
);
215 fprintf(stderr
, "\n");
220 warn(const char *format
, ...) ISC_FORMAT_PRINTF(1, 2);
223 warn(const char *format
, ...) {
227 fprintf(stderr
, "%s: warning: ", progname
);
228 va_start(args
, format
);
229 vfprintf(stderr
, format
, args
);
231 fprintf(stderr
, "\n");
234 static isc_logcategory_t categories
[] = {
238 #define LOGCATEGORY_DEFAULT (&categories[0])
239 #define LOGMODULE_DEFAULT (&modules[0])
241 static isc_logmodule_t modules
[] = {
247 delv_log(int level
, const char *fmt
, ...) ISC_FORMAT_PRINTF(2, 3);
250 delv_log(int level
, const char *fmt
, ...) {
254 if (! isc_log_wouldlog(lctx
, level
))
259 vsnprintf(msgbuf
, sizeof(msgbuf
), fmt
, ap
);
260 isc_log_write(lctx
, LOGCATEGORY_DEFAULT
, LOGMODULE_DEFAULT
,
261 level
, "%s", msgbuf
);
265 static int loglevel
= 0;
268 setup_logging(FILE *errout
) {
270 isc_logdestination_t destination
;
271 isc_logconfig_t
*logconfig
= NULL
;
273 result
= isc_log_create(mctx
, &lctx
, &logconfig
);
274 if (result
!= ISC_R_SUCCESS
)
275 fatal("Couldn't set up logging");
277 isc_log_registercategories(lctx
, categories
);
278 isc_log_registermodules(lctx
, modules
);
279 isc_log_setcontext(lctx
);
281 dns_log_setcontext(lctx
);
284 destination
.file
.stream
= errout
;
285 destination
.file
.name
= NULL
;
286 destination
.file
.versions
= ISC_LOG_ROLLNEVER
;
287 destination
.file
.maximum_size
= 0;
289 result
= isc_log_createchannel(logconfig
, "stderr",
290 ISC_LOG_TOFILEDESC
, ISC_LOG_DYNAMIC
,
291 &destination
, ISC_LOG_PRINTPREFIX
);
292 if (result
!= ISC_R_SUCCESS
)
293 fatal("Couldn't set up log channel 'stderr'");
295 isc_log_setdebuglevel(lctx
, loglevel
);
297 result
= isc_log_settag(logconfig
, ";; ");
298 if (result
!= ISC_R_SUCCESS
)
299 fatal("Couldn't set log tag");
301 result
= isc_log_usechannel(logconfig
, "stderr",
302 ISC_LOGCATEGORY_DEFAULT
, NULL
);
303 if (result
!= ISC_R_SUCCESS
)
304 fatal("Couldn't attach to log channel 'stderr'");
306 if (resolve_trace
&& loglevel
< 1) {
307 result
= isc_log_createchannel(logconfig
, "resolver",
311 ISC_LOG_PRINTPREFIX
);
312 if (result
!= ISC_R_SUCCESS
)
313 fatal("Couldn't set up log channel 'resolver'");
315 result
= isc_log_usechannel(logconfig
, "resolver",
316 DNS_LOGCATEGORY_RESOLVER
,
317 DNS_LOGMODULE_RESOLVER
);
318 if (result
!= ISC_R_SUCCESS
)
319 fatal("Couldn't attach to log channel 'resolver'");
322 if (validator_trace
&& loglevel
< 3) {
323 result
= isc_log_createchannel(logconfig
, "validator",
327 ISC_LOG_PRINTPREFIX
);
328 if (result
!= ISC_R_SUCCESS
)
329 fatal("Couldn't set up log channel 'validator'");
331 result
= isc_log_usechannel(logconfig
, "validator",
332 DNS_LOGCATEGORY_DNSSEC
,
333 DNS_LOGMODULE_VALIDATOR
);
334 if (result
!= ISC_R_SUCCESS
)
335 fatal("Couldn't attach to log channel 'validator'");
338 if (message_trace
&& loglevel
< 10) {
339 result
= isc_log_createchannel(logconfig
, "messages",
343 ISC_LOG_PRINTPREFIX
);
344 if (result
!= ISC_R_SUCCESS
)
345 fatal("Couldn't set up log channel 'messages'");
347 result
= isc_log_usechannel(logconfig
, "messages",
348 DNS_LOGCATEGORY_RESOLVER
,
349 DNS_LOGMODULE_PACKETS
);
350 if (result
!= ISC_R_SUCCESS
)
351 fatal("Couldn't attach to log channel 'messagse'");
356 print_status(dns_rdataset_t
*rdataset
) {
357 const char *astr
= "", *tstr
= "";
359 REQUIRE(rdataset
!= NULL
);
361 if (!showtrust
|| !dns_rdataset_isassociated(rdataset
))
364 if ((rdataset
->attributes
& DNS_RDATASETATTR_NEGATIVE
) != 0)
365 astr
= "negative response, ";
367 switch (rdataset
->trust
) {
371 case dns_trust_pending_additional
:
372 tstr
= "signed additional data, pending validation";
374 case dns_trust_pending_answer
:
375 tstr
= "signed answer, pending validation";
377 case dns_trust_additional
:
378 tstr
= "unsigned additional data";
383 case dns_trust_answer
:
384 if (root_validation
|| dlv_validation
)
385 tstr
= "unsigned answer";
387 tstr
= "answer not validated";
389 case dns_trust_authauthority
:
390 tstr
= "authority data";
392 case dns_trust_authanswer
:
393 tstr
= "authoritative";
395 case dns_trust_secure
:
396 tstr
= "fully validated";
398 case dns_trust_ultimate
:
399 tstr
= "ultimate trust";
403 printf("; %s%s\n", astr
, tstr
);
407 printdata(dns_rdataset_t
*rdataset
, dns_name_t
*owner
,
408 dns_master_style_t
*style
)
410 isc_result_t result
= ISC_R_SUCCESS
;
411 static dns_trust_t trust
;
412 static isc_boolean_t first
= ISC_TRUE
;
418 if (!dns_rdataset_isassociated(rdataset
)) {
419 char namebuf
[DNS_NAME_FORMATSIZE
];
420 dns_name_format(owner
, namebuf
, sizeof(namebuf
));
421 delv_log(ISC_LOG_DEBUG(4),
422 "WARN: empty rdataset %s", namebuf
);
423 return (ISC_R_SUCCESS
);
426 if (!showdnssec
&& rdataset
->type
== dns_rdatatype_rrsig
)
427 return (ISC_R_SUCCESS
);
429 if (first
|| rdataset
->trust
!= trust
) {
430 if (!first
&& showtrust
&& !short_form
)
432 print_status(rdataset
);
433 trust
= rdataset
->trust
;
438 t
= isc_mem_get(mctx
, len
);
440 return (ISC_R_NOMEMORY
);
442 isc_buffer_init(&target
, t
, len
);
444 dns_rdata_t rdata
= DNS_RDATA_INIT
;
445 for (result
= dns_rdataset_first(rdataset
);
446 result
== ISC_R_SUCCESS
;
447 result
= dns_rdataset_next(rdataset
))
449 if ((rdataset
->attributes
&
450 DNS_RDATASETATTR_NEGATIVE
) != 0)
453 dns_rdataset_current(rdataset
, &rdata
);
454 result
= dns_rdata_tofmttext(&rdata
,
459 if (result
!= ISC_R_SUCCESS
)
462 if (isc_buffer_availablelength(&target
) < 1) {
463 result
= ISC_R_NOSPACE
;
467 isc_buffer_putstr(&target
, "\n");
469 dns_rdata_reset(&rdata
);
472 if ((rdataset
->attributes
&
473 DNS_RDATASETATTR_NEGATIVE
) != 0)
474 isc_buffer_putstr(&target
, "; ");
476 result
= dns_master_rdatasettotext(owner
, rdataset
,
480 if (result
== ISC_R_NOSPACE
) {
481 isc_mem_put(mctx
, t
, len
);
483 } else if (result
== ISC_R_NOMORE
)
484 result
= ISC_R_SUCCESS
;
487 } while (result
== ISC_R_NOSPACE
);
489 isc_buffer_usedregion(&target
, &r
);
490 printf("%.*s", (int)r
.length
, (char *)r
.base
);
494 isc_mem_put(mctx
, t
, len
);
496 return (ISC_R_SUCCESS
);
500 setup_style(dns_master_style_t
**stylep
) {
502 dns_master_style_t
*style
= NULL
;
504 REQUIRE(stylep
!= NULL
|| *stylep
== NULL
);
506 styleflags
|= DNS_STYLEFLAG_REL_OWNER
;
508 styleflags
|= DNS_STYLEFLAG_COMMENT
;
510 styleflags
|= DNS_STYLEFLAG_RRCOMMENT
;
512 styleflags
|= DNS_STYLEFLAG_NO_TTL
;
514 styleflags
|= DNS_STYLEFLAG_NO_CLASS
;
516 styleflags
|= DNS_STYLEFLAG_NOCRYPTO
;
518 styleflags
|= DNS_STYLEFLAG_MULTILINE
;
519 styleflags
|= DNS_STYLEFLAG_COMMENT
;
522 if (multiline
|| (nottl
&& noclass
))
523 result
= dns_master_stylecreate2(&style
, styleflags
,
524 24, 24, 24, 32, 80, 8,
526 else if (nottl
|| noclass
)
527 result
= dns_master_stylecreate2(&style
, styleflags
,
528 24, 24, 32, 40, 80, 8,
531 result
= dns_master_stylecreate2(&style
, styleflags
,
532 24, 32, 40, 48, 80, 8,
535 if (result
== ISC_R_SUCCESS
)
541 convert_name(dns_fixedname_t
*fn
, dns_name_t
**name
, const char *text
) {
547 REQUIRE(fn
!= NULL
&& name
!= NULL
&& text
!= NULL
);
550 isc_buffer_constinit(&b
, text
, len
);
551 isc_buffer_add(&b
, len
);
552 dns_fixedname_init(fn
);
553 n
= dns_fixedname_name(fn
);
555 result
= dns_name_fromtext(n
, &b
, dns_rootname
, 0, NULL
);
556 if (result
!= ISC_R_SUCCESS
) {
557 delv_log(ISC_LOG_ERROR
, "failed to convert QNAME %s: %s",
558 text
, isc_result_totext(result
));
563 return (ISC_R_SUCCESS
);
567 key_fromconfig(const cfg_obj_t
*key
, dns_client_t
*client
) {
568 dns_rdata_dnskey_t keystruct
;
569 isc_uint32_t flags
, proto
, alg
;
570 const char *keystr
, *keynamestr
;
571 unsigned char keydata
[4096];
572 isc_buffer_t keydatabuf
;
573 unsigned char rrdata
[4096];
574 isc_buffer_t rrdatabuf
;
576 dns_fixedname_t fkeyname
;
579 isc_boolean_t match_root
, match_dlv
;
581 keynamestr
= cfg_obj_asstring(cfg_tuple_get(key
, "name"));
582 CHECK(convert_name(&fkeyname
, &keyname
, keynamestr
));
584 if (!root_validation
&& !dlv_validation
)
585 return (ISC_R_SUCCESS
);
587 match_root
= dns_name_equal(keyname
, anchor_name
);
588 match_dlv
= dns_name_equal(keyname
, dlv_name
);
590 if (!match_root
&& !match_dlv
)
591 return (ISC_R_SUCCESS
);
592 if ((!root_validation
&& match_root
) || (!dlv_validation
&& match_dlv
))
593 return (ISC_R_SUCCESS
);
596 delv_log(ISC_LOG_DEBUG(3), "adding trust anchor %s",
599 delv_log(ISC_LOG_DEBUG(3), "adding DLV trust anchor %s",
602 flags
= cfg_obj_asuint32(cfg_tuple_get(key
, "flags"));
603 proto
= cfg_obj_asuint32(cfg_tuple_get(key
, "protocol"));
604 alg
= cfg_obj_asuint32(cfg_tuple_get(key
, "algorithm"));
606 keystruct
.common
.rdclass
= dns_rdataclass_in
;
607 keystruct
.common
.rdtype
= dns_rdatatype_dnskey
;
609 * The key data in keystruct is not dynamically allocated.
611 keystruct
.mctx
= NULL
;
613 ISC_LINK_INIT(&keystruct
.common
, link
);
622 keystruct
.flags
= (isc_uint16_t
)flags
;
623 keystruct
.protocol
= (isc_uint8_t
)proto
;
624 keystruct
.algorithm
= (isc_uint8_t
)alg
;
626 isc_buffer_init(&keydatabuf
, keydata
, sizeof(keydata
));
627 isc_buffer_init(&rrdatabuf
, rrdata
, sizeof(rrdata
));
629 keystr
= cfg_obj_asstring(cfg_tuple_get(key
, "key"));
630 CHECK(isc_base64_decodestring(keystr
, &keydatabuf
));
631 isc_buffer_usedregion(&keydatabuf
, &r
);
632 keystruct
.datalen
= r
.length
;
633 keystruct
.data
= r
.base
;
635 CHECK(dns_rdata_fromstruct(NULL
,
636 keystruct
.common
.rdclass
,
637 keystruct
.common
.rdtype
,
638 &keystruct
, &rrdatabuf
));
640 CHECK(dns_client_addtrustedkey(client
, dns_rdataclass_in
,
641 keyname
, &rrdatabuf
));
645 if (result
== DST_R_NOCRYPTO
)
646 cfg_obj_log(key
, lctx
, ISC_LOG_ERROR
, "no crypto support");
647 else if (result
== DST_R_UNSUPPORTEDALG
) {
648 cfg_obj_log(key
, lctx
, ISC_LOG_WARNING
,
649 "skipping trusted key '%s': %s",
650 keynamestr
, isc_result_totext(result
));
651 result
= ISC_R_SUCCESS
;
652 } else if (result
!= ISC_R_SUCCESS
) {
653 cfg_obj_log(key
, lctx
, ISC_LOG_ERROR
,
654 "failed to add trusted key '%s': %s",
655 keynamestr
, isc_result_totext(result
));
656 result
= ISC_R_FAILURE
;
663 load_keys(const cfg_obj_t
*keys
, dns_client_t
*client
) {
664 const cfg_listelt_t
*elt
, *elt2
;
665 const cfg_obj_t
*key
, *keylist
;
666 isc_result_t result
= ISC_R_SUCCESS
;
668 for (elt
= cfg_list_first(keys
);
670 elt
= cfg_list_next(elt
))
672 keylist
= cfg_listelt_value(elt
);
674 for (elt2
= cfg_list_first(keylist
);
676 elt2
= cfg_list_next(elt2
))
678 key
= cfg_listelt_value(elt2
);
679 CHECK(key_fromconfig(key
, client
));
684 if (result
== DST_R_NOCRYPTO
)
685 result
= ISC_R_SUCCESS
;
690 setup_dnsseckeys(dns_client_t
*client
) {
692 cfg_parser_t
*parser
= NULL
;
693 const cfg_obj_t
*keys
= NULL
;
694 const cfg_obj_t
*managed_keys
= NULL
;
695 cfg_obj_t
*bindkeys
= NULL
;
696 const char *filename
= anchorfile
;
698 if (!root_validation
&& !dlv_validation
)
699 return (ISC_R_SUCCESS
);
701 if (filename
== NULL
) {
703 filename
= NS_SYSCONFDIR
"/bind.keys";
705 static char buf
[MAX_PATH
];
706 strlcpy(buf
, isc_ntpaths_get(SYS_CONF_DIR
), sizeof(buf
));
707 strlcat(buf
, "\\bind.keys", sizeof(buf
));
712 if (trust_anchor
== NULL
) {
713 trust_anchor
= isc_mem_strdup(mctx
, ".");
714 if (trust_anchor
== NULL
)
715 fatal("out of memory");
718 if (dlv_anchor
== NULL
) {
719 dlv_anchor
= isc_mem_strdup(mctx
, "dlv.isc.org");
720 if (dlv_anchor
== NULL
)
721 fatal("out of memory");
724 CHECK(convert_name(&afn
, &anchor_name
, trust_anchor
));
725 CHECK(convert_name(&dfn
, &dlv_name
, dlv_anchor
));
727 CHECK(cfg_parser_create(mctx
, dns_lctx
, &parser
));
729 if (access(filename
, R_OK
) != 0) {
730 if (anchorfile
!= NULL
)
731 fatal("Unable to read key file '%s'", anchorfile
);
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'",
741 if (bindkeys
== NULL
) {
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
,
748 if (result
!= ISC_R_SUCCESS
)
749 fatal("Unable to parse built-in keys");
752 INSIST(bindkeys
!= NULL
);
753 cfg_map_get(bindkeys
, "trusted-keys", &keys
);
754 cfg_map_get(bindkeys
, "managed-keys", &managed_keys
);
757 CHECK(load_keys(keys
, client
));
758 if (managed_keys
!= NULL
)
759 CHECK(load_keys(managed_keys
, client
));
760 result
= ISC_R_SUCCESS
;
762 if (trusted_keys
== 0)
763 fatal("No trusted keys were loaded");
766 dns_client_setdlv(client
, dns_rdataclass_in
, dlv_anchor
);
769 if (result
!= ISC_R_SUCCESS
)
770 delv_log(ISC_LOG_ERROR
, "setup_dnsseckeys: %s",
771 isc_result_totext(result
));
776 addserver(dns_client_t
*client
) {
777 struct addrinfo hints
, *res
, *cur
;
782 isc_sockaddrlist_t servers
;
783 isc_uint32_t destport
;
785 dns_name_t
*name
= NULL
;
787 result
= parse_uint(&destport
, port
, 0xffff, "port");
788 if (result
!= ISC_R_SUCCESS
)
789 fatal("Couldn't parse port number");
791 ISC_LIST_INIT(servers
);
793 if (use_ipv4
&& inet_pton(AF_INET
, server
, &in4
) == 1) {
794 sa
= isc_mem_get(mctx
, sizeof(*sa
));
796 return (ISC_R_NOMEMORY
);
797 ISC_LINK_INIT(sa
, link
);
798 isc_sockaddr_fromin(sa
, &in4
, destport
);
799 ISC_LIST_APPEND(servers
, sa
, link
);
800 } else if (use_ipv6
&& inet_pton(AF_INET6
, server
, &in6
) == 1) {
801 sa
= isc_mem_get(mctx
, sizeof(*sa
));
803 return (ISC_R_NOMEMORY
);
804 ISC_LINK_INIT(sa
, link
);
805 isc_sockaddr_fromin6(sa
, &in6
, destport
);
806 ISC_LIST_APPEND(servers
, sa
, link
);
808 memset(&hints
, 0, sizeof(hints
));
810 hints
.ai_family
= AF_INET
;
812 hints
.ai_family
= AF_INET6
;
814 hints
.ai_family
= AF_UNSPEC
;
815 hints
.ai_socktype
= SOCK_DGRAM
;
816 hints
.ai_protocol
= IPPROTO_UDP
;
817 gai_error
= getaddrinfo(server
, port
, &hints
, &res
);
818 if (gai_error
!= 0) {
819 delv_log(ISC_LOG_ERROR
,
820 "getaddrinfo failed: %s",
821 gai_strerror(gai_error
));
822 return (ISC_R_FAILURE
);
825 result
= ISC_R_SUCCESS
;
826 for (cur
= res
; cur
!= NULL
; cur
= cur
->ai_next
) {
827 if (cur
->ai_family
!= AF_INET
&&
828 cur
->ai_family
!= AF_INET6
)
830 sa
= isc_mem_get(mctx
, sizeof(*sa
));
832 result
= ISC_R_NOMEMORY
;
835 memset(sa
, 0, sizeof(*sa
));
836 ISC_LINK_INIT(sa
, link
);
837 memmove(&sa
->type
, cur
->ai_addr
, cur
->ai_addrlen
);
838 sa
->length
= (unsigned int)cur
->ai_addrlen
;
839 ISC_LIST_APPEND(servers
, sa
, link
);
846 CHECK(dns_client_setservers(client
, dns_rdataclass_in
, name
, &servers
));
849 while (!ISC_LIST_EMPTY(servers
)) {
850 sa
= ISC_LIST_HEAD(servers
);
851 ISC_LIST_UNLINK(servers
, sa
, link
);
852 isc_mem_put(mctx
, sa
, sizeof(*sa
));
855 if (result
!= ISC_R_SUCCESS
)
856 delv_log(ISC_LOG_ERROR
, "addserver: %s",
857 isc_result_totext(result
));
863 findserver(dns_client_t
*client
) {
865 irs_resconf_t
*resconf
= NULL
;
866 isc_sockaddrlist_t
*nameservers
;
867 isc_sockaddr_t
*sa
, *next
;
868 isc_uint32_t destport
;
870 result
= parse_uint(&destport
, port
, 0xffff, "port");
871 if (result
!= ISC_R_SUCCESS
)
872 fatal("Couldn't parse port number");
874 result
= irs_resconf_load(mctx
, "/etc/resolv.conf", &resconf
);
875 if (result
!= ISC_R_SUCCESS
&& result
!= ISC_R_FILENOTFOUND
) {
876 delv_log(ISC_LOG_ERROR
, "irs_resconf_load: %s",
877 isc_result_totext(result
));
881 /* Get nameservers from resolv.conf */
882 nameservers
= irs_resconf_getnameservers(resconf
);
883 for (sa
= ISC_LIST_HEAD(*nameservers
); sa
!= NULL
; sa
= next
) {
884 next
= ISC_LIST_NEXT(sa
, link
);
886 /* Set destination port */
887 if (sa
->type
.sa
.sa_family
== AF_INET
&& use_ipv4
) {
888 sa
->type
.sin
.sin_port
= htons(destport
);
891 if (sa
->type
.sa
.sa_family
== AF_INET6
&& use_ipv6
) {
892 sa
->type
.sin6
.sin6_port
= htons(destport
);
896 /* Incompatible protocol family */
897 ISC_LIST_UNLINK(*nameservers
, sa
, link
);
898 isc_mem_put(mctx
, sa
, sizeof(*sa
));
901 /* None found, use localhost */
902 if (ISC_LIST_EMPTY(*nameservers
)) {
904 struct in_addr localhost
;
905 localhost
.s_addr
= htonl(INADDR_LOOPBACK
);
906 sa
= isc_mem_get(mctx
, sizeof(*sa
));
908 result
= ISC_R_NOMEMORY
;
911 isc_sockaddr_fromin(sa
, &localhost
, destport
);
913 ISC_LINK_INIT(sa
, link
);
914 ISC_LIST_APPEND(*nameservers
, sa
, link
);
918 sa
= isc_mem_get(mctx
, sizeof(*sa
));
920 result
= ISC_R_NOMEMORY
;
923 isc_sockaddr_fromin6(sa
, &in6addr_loopback
, destport
);
925 ISC_LINK_INIT(sa
, link
);
926 ISC_LIST_APPEND(*nameservers
, sa
, link
);
930 result
= dns_client_setservers(client
, dns_rdataclass_in
, NULL
,
932 if (result
!= ISC_R_SUCCESS
)
933 delv_log(ISC_LOG_ERROR
, "dns_client_setservers: %s",
934 isc_result_totext(result
));
938 irs_resconf_destroy(&resconf
);
943 next_token(char **stringp
, const char *delim
) {
947 res
= strsep(stringp
, delim
);
950 } while (*res
== '\0');
955 parse_uint(isc_uint32_t
*uip
, const char *value
, isc_uint32_t max
,
958 isc_result_t result
= isc_parse_uint32(&n
, value
, 10);
959 if (result
== ISC_R_SUCCESS
&& n
> max
)
960 result
= ISC_R_RANGE
;
961 if (result
!= ISC_R_SUCCESS
) {
962 printf("invalid %s '%s': %s\n", desc
,
963 value
, isc_result_totext(result
));
967 return (ISC_R_SUCCESS
);
971 plus_option(char *option
) {
973 char option_store
[256];
974 char *cmd
, *value
, *ptr
;
975 isc_boolean_t state
= ISC_TRUE
;
977 strncpy(option_store
, option
, sizeof(option_store
));
978 option_store
[sizeof(option_store
)-1]=0;
980 cmd
= next_token(&ptr
,"=");
982 printf(";; Invalid option %s\n", option_store
);
986 if (strncasecmp(cmd
, "no", 2)==0) {
991 #define FULLCHECK(A) \
993 size_t _l = strlen(cmd); \
994 if (_l >= sizeof(A) || strncasecmp(cmd, A, _l) != 0) \
995 goto invalid_option; \
996 } while (/*CONSTCOND*/0)
1001 showcomments
= state
;
1007 case 'd': /* cdflag */
1008 FULLCHECK("cdflag");
1011 case 'l': /* class */
1013 noclass
= ISC_TF(!state
);
1015 case 'o': /* comments */
1016 FULLCHECK("comments");
1017 showcomments
= state
;
1019 case 'r': /* crypto */
1020 FULLCHECK("crypto");
1021 nocrypto
= ISC_TF(!state
);
1024 goto invalid_option
;
1031 if (state
&& no_sigs
)
1033 dlv_validation
= state
;
1034 if (value
!= NULL
) {
1035 dlv_anchor
= isc_mem_strdup(mctx
, value
);
1036 if (dlv_anchor
== NULL
)
1037 fatal("out of memory");
1040 case 'n': /* dnssec */
1041 FULLCHECK("dnssec");
1045 goto invalid_option
;
1050 case 't': /* mtrace */
1051 message_trace
= state
;
1053 resolve_trace
= state
;
1055 case 'u': /* multiline */
1056 FULLCHECK("multiline");
1060 goto invalid_option
;
1065 case 'o': /* root */
1067 if (state
&& no_sigs
)
1069 root_validation
= state
;
1070 if (value
!= NULL
) {
1071 trust_anchor
= isc_mem_strdup(mctx
, value
);
1072 if (trust_anchor
== NULL
)
1073 fatal("out of memory");
1076 case 'r': /* rrcomments */
1077 FULLCHECK("rrcomments");
1080 case 't': /* rtrace */
1081 FULLCHECK("rtrace");
1082 resolve_trace
= state
;
1085 goto invalid_option
;
1090 case 'h': /* short */
1094 multiline
= ISC_FALSE
;
1095 showcomments
= ISC_FALSE
;
1096 showtrust
= ISC_FALSE
;
1097 showdnssec
= ISC_FALSE
;
1100 case 'p': /* split */
1102 if (value
!= NULL
&& !state
)
1103 goto invalid_option
;
1107 } else if (value
== NULL
)
1110 result
= parse_uint(&splitwidth
, value
,
1112 if (splitwidth
% 4 != 0) {
1113 splitwidth
= ((splitwidth
+ 3) / 4) * 4;
1114 warn("split must be a multiple of 4; "
1115 "adjusting to %d", splitwidth
);
1118 * There is an adjustment done in the
1119 * totext_<rrtype>() functions which causes
1120 * splitwidth to shrink. This is okay when we're
1121 * using the default width but incorrect in this
1122 * case, so we correct for it
1126 if (result
!= ISC_R_SUCCESS
)
1127 fatal("Couldn't parse split");
1130 goto invalid_option
;
1135 case 'r': /* trust */
1141 nottl
= ISC_TF(!state
);
1144 goto invalid_option
;
1147 case 'v': /* vtrace */
1148 FULLCHECK("vtrace");
1149 validator_trace
= state
;
1151 resolve_trace
= state
;
1156 * We can also add a "need_value:" case here if we ever
1157 * add a plus-option that requires a specified value
1159 fprintf(stderr
, "Invalid option: +%s\n", option
);
1166 * options: "46a:b:c:d:himp:q:t:vx:";
1168 static const char *single_dash_opts
= "46himv";
1169 static isc_boolean_t
1170 dash_option(char *option
, char *next
, isc_boolean_t
*open_type_class
) {
1172 isc_result_t result
;
1173 isc_boolean_t value_from_next
;
1174 isc_textregion_t tr
;
1175 dns_rdatatype_t rdtype
;
1176 dns_rdataclass_t rdclass
;
1177 char textname
[MAXNAME
];
1179 struct in6_addr in6
;
1184 while (strpbrk(option
, single_dash_opts
) == &option
[0]) {
1186 * Since the -[46himv] options do not take an argument,
1187 * account for them (in any number and/or combination)
1188 * if they appear as the first character(s) of a q-opt.
1193 if (isc_net_probeipv4() != ISC_R_SUCCESS
)
1194 fatal("IPv4 networking not available");
1196 isc_net_disableipv6();
1197 use_ipv6
= ISC_FALSE
;
1201 if (isc_net_probeipv6() != ISC_R_SUCCESS
)
1202 fatal("IPv6 networking not available");
1204 isc_net_disableipv4();
1205 use_ipv4
= ISC_FALSE
;
1214 dlv_validation
= ISC_FALSE
;
1215 root_validation
= ISC_FALSE
;
1218 /* handled in preparse_args() */
1221 fputs("delv " VERSION
"\n", stderr
);
1227 if (strlen(option
) > 1U)
1228 option
= &option
[1];
1233 if (strlen(option
) > 1U) {
1234 value_from_next
= ISC_FALSE
;
1237 value_from_next
= ISC_TRUE
;
1241 goto invalid_option
;
1244 anchorfile
= isc_mem_strdup(mctx
, value
);
1245 if (anchorfile
== NULL
)
1246 fatal("out of memory");
1247 return (value_from_next
);
1249 hash
= strchr(value
, '#');
1251 result
= parse_uint(&num
, hash
+ 1, 0xffff, "port");
1252 if (result
!= ISC_R_SUCCESS
)
1253 fatal("Couldn't parse port number");
1259 if (inet_pton(AF_INET
, value
, &in4
) == 1) {
1260 if (srcaddr4
!= NULL
)
1261 fatal("Only one local address per family "
1262 "can be specified\n");
1263 isc_sockaddr_fromin(&a4
, &in4
, srcport
);
1265 } else if (inet_pton(AF_INET6
, value
, &in6
) == 1) {
1266 if (srcaddr6
!= NULL
)
1267 fatal("Only one local address per family "
1268 "can be specified\n");
1269 isc_sockaddr_fromin6(&a6
, &in6
, srcport
);
1274 fatal("Invalid address %s", value
);
1278 return (value_from_next
);
1281 warn("extra query class");
1283 *open_type_class
= ISC_FALSE
;
1285 tr
.length
= strlen(value
);
1286 result
= dns_rdataclass_fromtext(&rdclass
,
1287 (isc_textregion_t
*)&tr
);
1288 if (result
== ISC_R_SUCCESS
)
1289 classset
= ISC_TRUE
;
1290 else if (rdclass
!= dns_rdataclass_in
)
1291 warn("ignoring non-IN query class");
1293 warn("ignoring invalid class");
1294 return (value_from_next
);
1296 result
= parse_uint(&num
, value
, 99, "debug level");
1297 if (result
!= ISC_R_SUCCESS
)
1298 fatal("Couldn't parse debug level");
1300 return (value_from_next
);
1303 return (value_from_next
);
1305 if (curqname
!= NULL
) {
1306 warn("extra query name");
1307 isc_mem_free(mctx
, curqname
);
1309 curqname
= isc_mem_strdup(mctx
, value
);
1310 if (curqname
== NULL
)
1311 fatal("out of memory");
1312 return (value_from_next
);
1314 *open_type_class
= ISC_FALSE
;
1316 tr
.length
= strlen(value
);
1317 result
= dns_rdatatype_fromtext(&rdtype
,
1318 (isc_textregion_t
*)&tr
);
1319 if (result
== ISC_R_SUCCESS
) {
1321 warn("extra query type");
1322 if (rdtype
== dns_rdatatype_ixfr
||
1323 rdtype
== dns_rdatatype_axfr
)
1324 fatal("Transfer not supported");
1328 warn("ignoring invalid type");
1329 return (value_from_next
);
1331 result
= get_reverse(textname
, sizeof(textname
), value
,
1333 if (result
== ISC_R_SUCCESS
) {
1334 if (curqname
!= NULL
) {
1335 isc_mem_free(mctx
, curqname
);
1336 warn("extra query name");
1338 curqname
= isc_mem_strdup(mctx
, textname
);
1339 if (curqname
== NULL
)
1340 fatal("out of memory");
1342 warn("extra query type");
1343 qtype
= dns_rdatatype_ptr
;
1346 fprintf(stderr
, "Invalid IP address %s\n", value
);
1349 return (value_from_next
);
1352 fprintf(stderr
, "Invalid option: -%s\n", option
);
1360 * Check for -m first to determine whether to enable
1361 * memory debugging when setting up the memory context.
1364 preparse_args(int argc
, char **argv
) {
1367 for (argc
--, argv
++; argc
> 0; argc
--, argv
++) {
1368 if (argv
[0][0] != '-')
1370 option
= &argv
[0][1];
1371 while (strpbrk(option
, single_dash_opts
) == &option
[0]) {
1372 if (option
[0] == 'm') {
1373 isc_mem_debugging
= ISC_MEM_DEBUGTRACE
|
1374 ISC_MEM_DEBUGRECORD
;
1377 option
= &option
[1];
1383 * Argument parsing is based on dig, but simplified: only one
1384 * QNAME/QCLASS/QTYPE tuple can be specified, and options have
1385 * been removed that aren't applicable to delv. The interface
1386 * should be familiar to dig users, however.
1389 parse_args(int argc
, char **argv
) {
1390 isc_result_t result
;
1391 isc_textregion_t tr
;
1392 dns_rdatatype_t rdtype
;
1393 dns_rdataclass_t rdclass
;
1394 isc_boolean_t open_type_class
= ISC_TRUE
;
1396 for (; argc
> 0; argc
--, argv
++) {
1397 if (argv
[0][0] == '@') {
1398 server
= &argv
[0][1];
1399 } else if (argv
[0][0] == '+') {
1400 plus_option(&argv
[0][1]);
1401 } else if (argv
[0][0] == '-') {
1403 if (dash_option(&argv
[0][1], NULL
,
1410 if (dash_option(&argv
[0][1], argv
[1],
1419 * Anything which isn't an option
1421 if (open_type_class
) {
1423 tr
.length
= strlen(argv
[0]);
1424 result
= dns_rdatatype_fromtext(&rdtype
,
1425 (isc_textregion_t
*)&tr
);
1426 if (result
== ISC_R_SUCCESS
) {
1428 warn("extra query type");
1429 if (rdtype
== dns_rdatatype_ixfr
||
1430 rdtype
== dns_rdatatype_axfr
)
1431 fatal("Transfer not supported");
1436 result
= dns_rdataclass_fromtext(&rdclass
,
1437 (isc_textregion_t
*)&tr
);
1438 if (result
== ISC_R_SUCCESS
) {
1440 warn("extra query class");
1441 else if (rdclass
!= dns_rdataclass_in
)
1442 warn("ignoring non-IN "
1448 if (curqname
== NULL
) {
1449 curqname
= isc_mem_strdup(mctx
, argv
[0]);
1450 if (curqname
== NULL
)
1451 fatal("out of memory");
1457 * If no qname or qtype specified, search for root/NS
1458 * If no qtype specified, use A
1461 qtype
= dns_rdatatype_a
;
1463 if (curqname
== NULL
) {
1464 qname
= isc_mem_strdup(mctx
, ".");
1466 fatal("out of memory");
1469 qtype
= dns_rdatatype_ns
;
1475 append_str(const char *text
, int len
, char **p
, char *end
) {
1477 return (ISC_R_NOSPACE
);
1478 memmove(*p
, text
, len
);
1480 return (ISC_R_SUCCESS
);
1484 reverse_octets(const char *in
, char **p
, char *end
) {
1485 char *dot
= strchr(in
, '.');
1488 isc_result_t result
;
1489 result
= reverse_octets(dot
+ 1, p
, end
);
1490 if (result
!= ISC_R_SUCCESS
)
1492 result
= append_str(".", 1, p
, end
);
1493 if (result
!= ISC_R_SUCCESS
)
1495 len
= (int)(dot
- in
);
1498 return (append_str(in
, len
, p
, end
));
1502 get_reverse(char *reverse
, size_t len
, char *value
, isc_boolean_t strict
) {
1504 isc_result_t result
;
1507 addr
.family
= AF_INET6
;
1508 r
= inet_pton(AF_INET6
, value
, &addr
.type
.in6
);
1510 /* This is a valid IPv6 address. */
1511 dns_fixedname_t fname
;
1513 unsigned int options
= 0;
1515 dns_fixedname_init(&fname
);
1516 name
= dns_fixedname_name(&fname
);
1517 result
= dns_byaddr_createptrname2(&addr
, options
, name
);
1518 if (result
!= ISC_R_SUCCESS
)
1520 dns_name_format(name
, reverse
, (unsigned int)len
);
1521 return (ISC_R_SUCCESS
);
1524 * Not a valid IPv6 address. Assume IPv4.
1525 * If 'strict' is not set, construct the
1526 * in-addr.arpa name by blindly reversing
1527 * octets whether or not they look like integers,
1528 * so that this can be used for RFC2317 names
1532 char *end
= reverse
+ len
;
1533 if (strict
&& inet_pton(AF_INET
, value
, &addr
.type
.in
) != 1)
1534 return (DNS_R_BADDOTTEDQUAD
);
1535 result
= reverse_octets(value
, &p
, end
);
1536 if (result
!= ISC_R_SUCCESS
)
1538 result
= append_str(".in-addr.arpa.", 15, &p
, end
);
1539 if (result
!= ISC_R_SUCCESS
)
1541 return (ISC_R_SUCCESS
);
1546 main(int argc
, char *argv
[]) {
1547 dns_client_t
*client
= NULL
;
1548 isc_result_t result
;
1549 dns_fixedname_t qfn
;
1550 dns_name_t
*query_name
, *response_name
;
1551 dns_rdataset_t
*rdataset
;
1552 dns_namelist_t namelist
;
1553 unsigned int resopt
, clopt
;
1554 isc_appctx_t
*actx
= NULL
;
1555 isc_taskmgr_t
*taskmgr
= NULL
;
1556 isc_socketmgr_t
*socketmgr
= NULL
;
1557 isc_timermgr_t
*timermgr
= NULL
;
1558 dns_master_style_t
*style
= NULL
;
1560 struct sigaction sa
;
1563 preparse_args(argc
, argv
);
1570 result
= dns_lib_init();
1571 if (result
!= ISC_R_SUCCESS
)
1572 fatal("dns_lib_init failed: %d", result
);
1574 result
= isc_mem_create(0, 0, &mctx
);
1575 if (result
!= ISC_R_SUCCESS
)
1576 fatal("failed to create mctx");
1578 CHECK(isc_appctx_create(mctx
, &actx
));
1579 CHECK(isc_taskmgr_createinctx(mctx
, actx
, 1, 0, &taskmgr
));
1580 CHECK(isc_socketmgr_createinctx(mctx
, actx
, &socketmgr
));
1581 CHECK(isc_timermgr_createinctx(mctx
, actx
, &timermgr
));
1583 parse_args(argc
, argv
);
1585 CHECK(setup_style(&style
));
1587 setup_logging(stderr
);
1589 CHECK(isc_app_ctxstart(actx
));
1592 /* Unblock SIGINT if it's been blocked by isc_app_ctxstart() */
1593 memset(&sa
, 0, sizeof(sa
));
1594 sa
.sa_handler
= SIG_DFL
;
1595 if (sigfillset(&sa
.sa_mask
) != 0 || sigaction(SIGINT
, &sa
, NULL
) < 0)
1596 fatal("Couldn't set up signal handler");
1600 clopt
= DNS_CLIENTCREATEOPT_USECACHE
;
1601 result
= dns_client_createx2(mctx
, actx
, taskmgr
, socketmgr
, timermgr
,
1602 clopt
, &client
, srcaddr4
, srcaddr6
);
1603 if (result
!= ISC_R_SUCCESS
) {
1604 delv_log(ISC_LOG_ERROR
, "dns_client_create: %s",
1605 isc_result_totext(result
));
1609 /* Set the nameserver */
1615 CHECK(setup_dnsseckeys(client
));
1617 /* Construct QNAME */
1618 CHECK(convert_name(&qfn
, &query_name
, qname
));
1620 /* Set up resolution options */
1621 resopt
= DNS_CLIENTRESOPT_ALLOWRUN
| DNS_CLIENTRESOPT_NOCDFLAG
;
1623 resopt
|= DNS_CLIENTRESOPT_NODNSSEC
;
1624 if (!root_validation
&& !dlv_validation
)
1625 resopt
|= DNS_CLIENTRESOPT_NOVALIDATE
;
1627 resopt
&= ~DNS_CLIENTRESOPT_NOCDFLAG
;
1629 /* Perform resolution */
1630 ISC_LIST_INIT(namelist
);
1631 result
= dns_client_resolve(client
, query_name
, dns_rdataclass_in
,
1632 qtype
, resopt
, &namelist
);
1633 if (result
!= ISC_R_SUCCESS
)
1634 delv_log(ISC_LOG_ERROR
, "resolution failed: %s",
1635 isc_result_totext(result
));
1637 for (response_name
= ISC_LIST_HEAD(namelist
);
1638 response_name
!= NULL
;
1639 response_name
= ISC_LIST_NEXT(response_name
, link
)) {
1640 for (rdataset
= ISC_LIST_HEAD(response_name
->list
);
1642 rdataset
= ISC_LIST_NEXT(rdataset
, link
)) {
1643 result
= printdata(rdataset
, response_name
, style
);
1644 if (result
!= ISC_R_SUCCESS
)
1645 delv_log(ISC_LOG_ERROR
, "print data failed");
1649 dns_client_freeresanswer(client
, &namelist
);
1652 if (dlv_anchor
!= NULL
)
1653 isc_mem_free(mctx
, dlv_anchor
);
1654 if (trust_anchor
!= NULL
)
1655 isc_mem_free(mctx
, trust_anchor
);
1656 if (anchorfile
!= NULL
)
1657 isc_mem_free(mctx
, anchorfile
);
1659 isc_mem_free(mctx
, qname
);
1661 dns_master_styledestroy(&style
, mctx
);
1663 dns_client_destroy(&client
);
1664 if (taskmgr
!= NULL
)
1665 isc_taskmgr_destroy(&taskmgr
);
1666 if (timermgr
!= NULL
)
1667 isc_timermgr_destroy(&timermgr
);
1668 if (socketmgr
!= NULL
)
1669 isc_socketmgr_destroy(&socketmgr
);
1671 isc_appctx_destroy(&actx
);
1673 isc_log_destroy(&lctx
);
1674 isc_mem_detach(&mctx
);