Import bind 9.5.2 vendor sources.
[dragonfly.git] / contrib / bind-9.5.2 / bin / check / check-tool.c
blobc50eee328b3eead42be354c90646aaf90926e952
1 /*
2 * Copyright (C) 2004-2009 Internet Systems Consortium, Inc. ("ISC")
3 * Copyright (C) 2000-2002 Internet Software Consortium.
5 * Permission to use, copy, modify, and/or distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
9 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
10 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
11 * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
12 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
13 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
14 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
15 * PERFORMANCE OF THIS SOFTWARE.
18 /* $Id: check-tool.c,v 1.31.62.5 2009/01/27 21:17:39 jinmei Exp $ */
20 /*! \file */
22 #include <config.h>
24 #include <stdio.h>
26 #include "check-tool.h"
27 #include <isc/buffer.h>
28 #include <isc/log.h>
29 #include <isc/mem.h>
30 #include <isc/netdb.h>
31 #include <isc/net.h>
32 #include <isc/region.h>
33 #include <isc/stdio.h>
34 #include <isc/string.h>
35 #include <isc/symtab.h>
36 #include <isc/types.h>
37 #include <isc/util.h>
39 #include <dns/fixedname.h>
40 #include <dns/log.h>
41 #include <dns/name.h>
42 #include <dns/rdata.h>
43 #include <dns/rdataclass.h>
44 #include <dns/rdataset.h>
45 #include <dns/types.h>
46 #include <dns/zone.h>
48 #include <isccfg/log.h>
50 #ifndef CHECK_SIBLING
51 #define CHECK_SIBLING 1
52 #endif
54 #ifndef CHECK_LOCAL
55 #define CHECK_LOCAL 1
56 #endif
58 #ifdef HAVE_ADDRINFO
59 #ifdef HAVE_GETADDRINFO
60 #ifdef HAVE_GAISTRERROR
61 #define USE_GETADDRINFO
62 #endif
63 #endif
64 #endif
66 #define CHECK(r) \
67 do { \
68 result = (r); \
69 if (result != ISC_R_SUCCESS) \
70 goto cleanup; \
71 } while (0)
73 #define ERR_IS_CNAME 1
74 #define ERR_NO_ADDRESSES 2
75 #define ERR_LOOKUP_FAILURE 3
76 #define ERR_EXTRA_A 4
77 #define ERR_EXTRA_AAAA 5
78 #define ERR_MISSING_GLUE 5
79 #define ERR_IS_MXCNAME 6
80 #define ERR_IS_SRVCNAME 7
82 static const char *dbtype[] = { "rbt" };
84 int debug = 0;
85 isc_boolean_t nomerge = ISC_TRUE;
86 #if CHECK_LOCAL
87 isc_boolean_t docheckmx = ISC_TRUE;
88 isc_boolean_t dochecksrv = ISC_TRUE;
89 isc_boolean_t docheckns = ISC_TRUE;
90 #else
91 isc_boolean_t docheckmx = ISC_FALSE;
92 isc_boolean_t dochecksrv = ISC_FALSE;
93 isc_boolean_t docheckns = ISC_FALSE;
94 #endif
95 unsigned int zone_options = DNS_ZONEOPT_CHECKNS |
96 DNS_ZONEOPT_CHECKMX |
97 DNS_ZONEOPT_MANYERRORS |
98 DNS_ZONEOPT_CHECKNAMES |
99 DNS_ZONEOPT_CHECKINTEGRITY |
100 #if CHECK_SIBLING
101 DNS_ZONEOPT_CHECKSIBLING |
102 #endif
103 DNS_ZONEOPT_CHECKWILDCARD |
104 DNS_ZONEOPT_WARNMXCNAME |
105 DNS_ZONEOPT_WARNSRVCNAME;
108 * This needs to match the list in bin/named/log.c.
110 static isc_logcategory_t categories[] = {
111 { "", 0 },
112 { "client", 0 },
113 { "network", 0 },
114 { "update", 0 },
115 { "queries", 0 },
116 { "unmatched", 0 },
117 { "update-security", 0 },
118 { "query-errors", 0 },
119 { NULL, 0 }
122 static isc_symtab_t *symtab = NULL;
123 static isc_mem_t *sym_mctx;
125 static void
126 freekey(char *key, unsigned int type, isc_symvalue_t value, void *userarg) {
127 UNUSED(type);
128 UNUSED(value);
129 isc_mem_free(userarg, key);
132 static void
133 add(char *key, int value) {
134 isc_result_t result;
135 isc_symvalue_t symvalue;
137 if (sym_mctx == NULL) {
138 result = isc_mem_create(0, 0, &sym_mctx);
139 if (result != ISC_R_SUCCESS)
140 return;
143 if (symtab == NULL) {
144 result = isc_symtab_create(sym_mctx, 100, freekey, sym_mctx,
145 ISC_FALSE, &symtab);
146 if (result != ISC_R_SUCCESS)
147 return;
150 key = isc_mem_strdup(sym_mctx, key);
151 if (key == NULL)
152 return;
154 symvalue.as_pointer = NULL;
155 result = isc_symtab_define(symtab, key, value, symvalue,
156 isc_symexists_reject);
157 if (result != ISC_R_SUCCESS)
158 isc_mem_free(sym_mctx, key);
161 static isc_boolean_t
162 logged(char *key, int value) {
163 isc_result_t result;
165 if (symtab == NULL)
166 return (ISC_FALSE);
168 result = isc_symtab_lookup(symtab, key, value, NULL);
169 if (result == ISC_R_SUCCESS)
170 return (ISC_TRUE);
171 return (ISC_FALSE);
174 static isc_boolean_t
175 checkns(dns_zone_t *zone, dns_name_t *name, dns_name_t *owner,
176 dns_rdataset_t *a, dns_rdataset_t *aaaa)
178 #ifdef USE_GETADDRINFO
179 dns_rdataset_t *rdataset;
180 dns_rdata_t rdata = DNS_RDATA_INIT;
181 struct addrinfo hints, *ai, *cur;
182 char namebuf[DNS_NAME_FORMATSIZE + 1];
183 char ownerbuf[DNS_NAME_FORMATSIZE];
184 char addrbuf[sizeof("xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:123.123.123.123")];
185 isc_boolean_t answer = ISC_TRUE;
186 isc_boolean_t match;
187 const char *type;
188 void *ptr = NULL;
189 int result;
191 REQUIRE(a == NULL || !dns_rdataset_isassociated(a) ||
192 a->type == dns_rdatatype_a);
193 REQUIRE(aaaa == NULL || !dns_rdataset_isassociated(aaaa) ||
194 aaaa->type == dns_rdatatype_aaaa);
195 memset(&hints, 0, sizeof(hints));
196 hints.ai_flags = AI_CANONNAME;
197 hints.ai_family = PF_UNSPEC;
198 hints.ai_socktype = SOCK_STREAM;
199 hints.ai_protocol = IPPROTO_TCP;
201 dns_name_format(name, namebuf, sizeof(namebuf) - 1);
203 * Turn off search.
205 if (dns_name_countlabels(name) > 1U)
206 strcat(namebuf, ".");
207 dns_name_format(owner, ownerbuf, sizeof(ownerbuf));
209 result = getaddrinfo(namebuf, NULL, &hints, &ai);
210 dns_name_format(name, namebuf, sizeof(namebuf) - 1);
211 switch (result) {
212 case 0:
214 * Work around broken getaddrinfo() implementations that
215 * fail to set ai_canonname on first entry.
217 cur = ai;
218 while (cur != NULL && cur->ai_canonname == NULL &&
219 cur->ai_next != NULL)
220 cur = cur->ai_next;
221 if (cur != NULL && cur->ai_canonname != NULL &&
222 strcasecmp(cur->ai_canonname, namebuf) != 0 &&
223 !logged(namebuf, ERR_IS_CNAME)) {
224 dns_zone_log(zone, ISC_LOG_ERROR,
225 "%s/NS '%s' (out of zone) "
226 "is a CNAME (illegal)",
227 ownerbuf, namebuf);
228 /* XXX950 make fatal for 9.5.0 */
229 /* answer = ISC_FALSE; */
230 add(namebuf, ERR_IS_CNAME);
232 break;
233 case EAI_NONAME:
234 #if defined(EAI_NODATA) && (EAI_NODATA != EAI_NONAME)
235 case EAI_NODATA:
236 #endif
237 if (!logged(namebuf, ERR_NO_ADDRESSES)) {
238 dns_zone_log(zone, ISC_LOG_ERROR,
239 "%s/NS '%s' (out of zone) "
240 "has no addresses records (A or AAAA)",
241 ownerbuf, namebuf);
242 add(namebuf, ERR_NO_ADDRESSES);
244 /* XXX950 make fatal for 9.5.0 */
245 return (ISC_TRUE);
247 default:
248 if (!logged(namebuf, ERR_LOOKUP_FAILURE)) {
249 dns_zone_log(zone, ISC_LOG_WARNING,
250 "getaddrinfo(%s) failed: %s",
251 namebuf, gai_strerror(result));
252 add(namebuf, ERR_LOOKUP_FAILURE);
254 return (ISC_TRUE);
256 if (a == NULL || aaaa == NULL)
257 return (answer);
259 * Check that all glue records really exist.
261 if (!dns_rdataset_isassociated(a))
262 goto checkaaaa;
263 result = dns_rdataset_first(a);
264 while (result == ISC_R_SUCCESS) {
265 dns_rdataset_current(a, &rdata);
266 match = ISC_FALSE;
267 for (cur = ai; cur != NULL; cur = cur->ai_next) {
268 if (cur->ai_family != AF_INET)
269 continue;
270 ptr = &((struct sockaddr_in *)(cur->ai_addr))->sin_addr;
271 if (memcmp(ptr, rdata.data, rdata.length) == 0) {
272 match = ISC_TRUE;
273 break;
276 if (!match && !logged(namebuf, ERR_EXTRA_A)) {
277 dns_zone_log(zone, ISC_LOG_ERROR, "%s/NS '%s' "
278 "extra GLUE A record (%s)",
279 ownerbuf, namebuf,
280 inet_ntop(AF_INET, rdata.data,
281 addrbuf, sizeof(addrbuf)));
282 add(namebuf, ERR_EXTRA_A);
283 /* XXX950 make fatal for 9.5.0 */
284 /* answer = ISC_FALSE; */
286 dns_rdata_reset(&rdata);
287 result = dns_rdataset_next(a);
290 checkaaaa:
291 if (!dns_rdataset_isassociated(aaaa))
292 goto checkmissing;
293 result = dns_rdataset_first(aaaa);
294 while (result == ISC_R_SUCCESS) {
295 dns_rdataset_current(aaaa, &rdata);
296 match = ISC_FALSE;
297 for (cur = ai; cur != NULL; cur = cur->ai_next) {
298 if (cur->ai_family != AF_INET6)
299 continue;
300 ptr = &((struct sockaddr_in6 *)(cur->ai_addr))->sin6_addr;
301 if (memcmp(ptr, rdata.data, rdata.length) == 0) {
302 match = ISC_TRUE;
303 break;
306 if (!match && !logged(namebuf, ERR_EXTRA_AAAA)) {
307 dns_zone_log(zone, ISC_LOG_ERROR, "%s/NS '%s' "
308 "extra GLUE AAAA record (%s)",
309 ownerbuf, namebuf,
310 inet_ntop(AF_INET6, rdata.data,
311 addrbuf, sizeof(addrbuf)));
312 add(namebuf, ERR_EXTRA_AAAA);
313 /* XXX950 make fatal for 9.5.0. */
314 /* answer = ISC_FALSE; */
316 dns_rdata_reset(&rdata);
317 result = dns_rdataset_next(aaaa);
320 checkmissing:
322 * Check that all addresses appear in the glue.
324 if (!logged(namebuf, ERR_MISSING_GLUE)) {
325 isc_boolean_t missing_glue = ISC_FALSE;
326 for (cur = ai; cur != NULL; cur = cur->ai_next) {
327 switch (cur->ai_family) {
328 case AF_INET:
329 rdataset = a;
330 ptr = &((struct sockaddr_in *)(cur->ai_addr))->sin_addr;
331 type = "A";
332 break;
333 case AF_INET6:
334 rdataset = aaaa;
335 ptr = &((struct sockaddr_in6 *)(cur->ai_addr))->sin6_addr;
336 type = "AAAA";
337 break;
338 default:
339 continue;
341 match = ISC_FALSE;
342 if (dns_rdataset_isassociated(rdataset))
343 result = dns_rdataset_first(rdataset);
344 else
345 result = ISC_R_FAILURE;
346 while (result == ISC_R_SUCCESS && !match) {
347 dns_rdataset_current(rdataset, &rdata);
348 if (memcmp(ptr, rdata.data, rdata.length) == 0)
349 match = ISC_TRUE;
350 dns_rdata_reset(&rdata);
351 result = dns_rdataset_next(rdataset);
353 if (!match) {
354 dns_zone_log(zone, ISC_LOG_ERROR, "%s/NS '%s' "
355 "missing GLUE %s record (%s)",
356 ownerbuf, namebuf, type,
357 inet_ntop(cur->ai_family, ptr,
358 addrbuf, sizeof(addrbuf)));
359 /* XXX950 make fatal for 9.5.0. */
360 /* answer = ISC_FALSE; */
361 missing_glue = ISC_TRUE;
364 if (missing_glue)
365 add(namebuf, ERR_MISSING_GLUE);
367 freeaddrinfo(ai);
368 return (answer);
369 #else
370 return (ISC_TRUE);
371 #endif
374 static isc_boolean_t
375 checkmx(dns_zone_t *zone, dns_name_t *name, dns_name_t *owner) {
376 #ifdef USE_GETADDRINFO
377 struct addrinfo hints, *ai, *cur;
378 char namebuf[DNS_NAME_FORMATSIZE + 1];
379 char ownerbuf[DNS_NAME_FORMATSIZE];
380 int result;
381 int level = ISC_LOG_ERROR;
382 isc_boolean_t answer = ISC_TRUE;
384 memset(&hints, 0, sizeof(hints));
385 hints.ai_flags = AI_CANONNAME;
386 hints.ai_family = PF_UNSPEC;
387 hints.ai_socktype = SOCK_STREAM;
388 hints.ai_protocol = IPPROTO_TCP;
390 dns_name_format(name, namebuf, sizeof(namebuf) - 1);
392 * Turn off search.
394 if (dns_name_countlabels(name) > 1U)
395 strcat(namebuf, ".");
396 dns_name_format(owner, ownerbuf, sizeof(ownerbuf));
398 result = getaddrinfo(namebuf, NULL, &hints, &ai);
399 dns_name_format(name, namebuf, sizeof(namebuf) - 1);
400 switch (result) {
401 case 0:
403 * Work around broken getaddrinfo() implementations that
404 * fail to set ai_canonname on first entry.
406 cur = ai;
407 while (cur != NULL && cur->ai_canonname == NULL &&
408 cur->ai_next != NULL)
409 cur = cur->ai_next;
410 if (cur != NULL && cur->ai_canonname != NULL &&
411 strcasecmp(cur->ai_canonname, namebuf) != 0) {
412 if ((zone_options & DNS_ZONEOPT_WARNMXCNAME) != 0)
413 level = ISC_LOG_WARNING;
414 if ((zone_options & DNS_ZONEOPT_IGNOREMXCNAME) == 0) {
415 if (!logged(namebuf, ERR_IS_MXCNAME)) {
416 dns_zone_log(zone, level,
417 "%s/MX '%s' (out of zone)"
418 " is a CNAME (illegal)",
419 ownerbuf, namebuf);
420 add(namebuf, ERR_IS_MXCNAME);
422 if (level == ISC_LOG_ERROR)
423 answer = ISC_FALSE;
426 freeaddrinfo(ai);
427 return (answer);
429 case EAI_NONAME:
430 #if defined(EAI_NODATA) && (EAI_NODATA != EAI_NONAME)
431 case EAI_NODATA:
432 #endif
433 if (!logged(namebuf, ERR_NO_ADDRESSES)) {
434 dns_zone_log(zone, ISC_LOG_ERROR,
435 "%s/MX '%s' (out of zone) "
436 "has no addresses records (A or AAAA)",
437 ownerbuf, namebuf);
438 add(namebuf, ERR_NO_ADDRESSES);
440 /* XXX950 make fatal for 9.5.0. */
441 return (ISC_TRUE);
443 default:
444 if (!logged(namebuf, ERR_LOOKUP_FAILURE)) {
445 dns_zone_log(zone, ISC_LOG_WARNING,
446 "getaddrinfo(%s) failed: %s",
447 namebuf, gai_strerror(result));
448 add(namebuf, ERR_LOOKUP_FAILURE);
450 return (ISC_TRUE);
452 #else
453 return (ISC_TRUE);
454 #endif
457 static isc_boolean_t
458 checksrv(dns_zone_t *zone, dns_name_t *name, dns_name_t *owner) {
459 #ifdef USE_GETADDRINFO
460 struct addrinfo hints, *ai, *cur;
461 char namebuf[DNS_NAME_FORMATSIZE + 1];
462 char ownerbuf[DNS_NAME_FORMATSIZE];
463 int result;
464 int level = ISC_LOG_ERROR;
465 isc_boolean_t answer = ISC_TRUE;
467 memset(&hints, 0, sizeof(hints));
468 hints.ai_flags = AI_CANONNAME;
469 hints.ai_family = PF_UNSPEC;
470 hints.ai_socktype = SOCK_STREAM;
471 hints.ai_protocol = IPPROTO_TCP;
473 dns_name_format(name, namebuf, sizeof(namebuf) - 1);
475 * Turn off search.
477 if (dns_name_countlabels(name) > 1U)
478 strcat(namebuf, ".");
479 dns_name_format(owner, ownerbuf, sizeof(ownerbuf));
481 result = getaddrinfo(namebuf, NULL, &hints, &ai);
482 dns_name_format(name, namebuf, sizeof(namebuf) - 1);
483 switch (result) {
484 case 0:
486 * Work around broken getaddrinfo() implementations that
487 * fail to set ai_canonname on first entry.
489 cur = ai;
490 while (cur != NULL && cur->ai_canonname == NULL &&
491 cur->ai_next != NULL)
492 cur = cur->ai_next;
493 if (cur != NULL && cur->ai_canonname != NULL &&
494 strcasecmp(cur->ai_canonname, namebuf) != 0) {
495 if ((zone_options & DNS_ZONEOPT_WARNSRVCNAME) != 0)
496 level = ISC_LOG_WARNING;
497 if ((zone_options & DNS_ZONEOPT_IGNORESRVCNAME) == 0) {
498 if (!logged(namebuf, ERR_IS_SRVCNAME)) {
499 dns_zone_log(zone, level, "%s/SRV '%s'"
500 " (out of zone) is a "
501 "CNAME (illegal)",
502 ownerbuf, namebuf);
503 add(namebuf, ERR_IS_SRVCNAME);
505 if (level == ISC_LOG_ERROR)
506 answer = ISC_FALSE;
509 freeaddrinfo(ai);
510 return (answer);
512 case EAI_NONAME:
513 #if defined(EAI_NODATA) && (EAI_NODATA != EAI_NONAME)
514 case EAI_NODATA:
515 #endif
516 if (!logged(namebuf, ERR_NO_ADDRESSES)) {
517 dns_zone_log(zone, ISC_LOG_ERROR,
518 "%s/SRV '%s' (out of zone) "
519 "has no addresses records (A or AAAA)",
520 ownerbuf, namebuf);
521 add(namebuf, ERR_NO_ADDRESSES);
523 /* XXX950 make fatal for 9.5.0. */
524 return (ISC_TRUE);
526 default:
527 if (!logged(namebuf, ERR_LOOKUP_FAILURE)) {
528 dns_zone_log(zone, ISC_LOG_WARNING,
529 "getaddrinfo(%s) failed: %s",
530 namebuf, gai_strerror(result));
531 add(namebuf, ERR_LOOKUP_FAILURE);
533 return (ISC_TRUE);
535 #else
536 return (ISC_TRUE);
537 #endif
540 isc_result_t
541 setup_logging(isc_mem_t *mctx, FILE *errout, isc_log_t **logp) {
542 isc_logdestination_t destination;
543 isc_logconfig_t *logconfig = NULL;
544 isc_log_t *log = NULL;
546 RUNTIME_CHECK(isc_log_create(mctx, &log, &logconfig) == ISC_R_SUCCESS);
547 isc_log_registercategories(log, categories);
548 isc_log_setcontext(log);
549 dns_log_init(log);
550 dns_log_setcontext(log);
551 cfg_log_init(log);
553 destination.file.stream = errout;
554 destination.file.name = NULL;
555 destination.file.versions = ISC_LOG_ROLLNEVER;
556 destination.file.maximum_size = 0;
557 RUNTIME_CHECK(isc_log_createchannel(logconfig, "stderr",
558 ISC_LOG_TOFILEDESC,
559 ISC_LOG_DYNAMIC,
560 &destination, 0) == ISC_R_SUCCESS);
561 RUNTIME_CHECK(isc_log_usechannel(logconfig, "stderr",
562 NULL, NULL) == ISC_R_SUCCESS);
564 *logp = log;
565 return (ISC_R_SUCCESS);
568 /*% load the zone */
569 isc_result_t
570 load_zone(isc_mem_t *mctx, const char *zonename, const char *filename,
571 dns_masterformat_t fileformat, const char *classname,
572 dns_zone_t **zonep)
574 isc_result_t result;
575 dns_rdataclass_t rdclass;
576 isc_textregion_t region;
577 isc_buffer_t buffer;
578 dns_fixedname_t fixorigin;
579 dns_name_t *origin;
580 dns_zone_t *zone = NULL;
582 REQUIRE(zonep == NULL || *zonep == NULL);
584 if (debug)
585 fprintf(stderr, "loading \"%s\" from \"%s\" class \"%s\"\n",
586 zonename, filename, classname);
588 CHECK(dns_zone_create(&zone, mctx));
590 dns_zone_settype(zone, dns_zone_master);
592 isc_buffer_init(&buffer, zonename, strlen(zonename));
593 isc_buffer_add(&buffer, strlen(zonename));
594 dns_fixedname_init(&fixorigin);
595 origin = dns_fixedname_name(&fixorigin);
596 CHECK(dns_name_fromtext(origin, &buffer, dns_rootname,
597 ISC_FALSE, NULL));
598 CHECK(dns_zone_setorigin(zone, origin));
599 CHECK(dns_zone_setdbtype(zone, 1, (const char * const *) dbtype));
600 CHECK(dns_zone_setfile2(zone, filename, fileformat));
602 DE_CONST(classname, region.base);
603 region.length = strlen(classname);
604 CHECK(dns_rdataclass_fromtext(&rdclass, &region));
606 dns_zone_setclass(zone, rdclass);
607 dns_zone_setoption(zone, zone_options, ISC_TRUE);
608 dns_zone_setoption(zone, DNS_ZONEOPT_NOMERGE, nomerge);
609 if (docheckmx)
610 dns_zone_setcheckmx(zone, checkmx);
611 if (docheckns)
612 dns_zone_setcheckns(zone, checkns);
613 if (dochecksrv)
614 dns_zone_setchecksrv(zone, checksrv);
616 CHECK(dns_zone_load(zone));
617 if (zonep != NULL) {
618 *zonep = zone;
619 zone = NULL;
622 cleanup:
623 if (zone != NULL)
624 dns_zone_detach(&zone);
625 return (result);
628 /*% dump the zone */
629 isc_result_t
630 dump_zone(const char *zonename, dns_zone_t *zone, const char *filename,
631 dns_masterformat_t fileformat, const dns_master_style_t *style)
633 isc_result_t result;
634 FILE *output = stdout;
636 if (debug) {
637 if (filename != NULL && strcmp(filename, "-") != 0)
638 fprintf(stderr, "dumping \"%s\" to \"%s\"\n",
639 zonename, filename);
640 else
641 fprintf(stderr, "dumping \"%s\"\n", zonename);
644 if (filename != NULL && strcmp(filename, "-") != 0) {
645 result = isc_stdio_open(filename, "w+", &output);
647 if (result != ISC_R_SUCCESS) {
648 fprintf(stderr, "could not open output "
649 "file \"%s\" for writing\n", filename);
650 return (ISC_R_FAILURE);
654 result = dns_zone_dumptostream2(zone, output, fileformat, style);
656 if (output != stdout)
657 (void)isc_stdio_close(output);
659 return (result);