]> CyberLeo.Net >> Repos - FreeBSD/releng/8.1.git/blob - contrib/bind9/bin/check/check-tool.c
Copy stable/8 to releng/8.1 in preparation for 8.1-RC1.
[FreeBSD/releng/8.1.git] / contrib / bind9 / bin / check / check-tool.c
1 /*
2  * Copyright (C) 2004-2009  Internet Systems Consortium, Inc. ("ISC")
3  * Copyright (C) 2000-2002  Internet Software Consortium.
4  *
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.
8  *
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.
16  */
17
18 /* $Id: check-tool.c,v 1.35.36.3 2009/01/20 02:03:18 marka Exp $ */
19
20 /*! \file */
21
22 #include <config.h>
23
24 #include <stdio.h>
25
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>
38
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>
47
48 #include <isccfg/log.h>
49
50 #ifndef CHECK_SIBLING
51 #define CHECK_SIBLING 1
52 #endif
53
54 #ifndef CHECK_LOCAL
55 #define CHECK_LOCAL 1
56 #endif
57
58 #ifdef HAVE_ADDRINFO
59 #ifdef HAVE_GETADDRINFO
60 #ifdef HAVE_GAISTRERROR
61 #define USE_GETADDRINFO
62 #endif
63 #endif
64 #endif
65
66 #define CHECK(r) \
67         do { \
68                 result = (r); \
69                 if (result != ISC_R_SUCCESS) \
70                         goto cleanup; \
71         } while (0)
72
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
81
82 static const char *dbtype[] = { "rbt" };
83
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;
106
107 /*
108  * This needs to match the list in bin/named/log.c.
109  */
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 }
120 };
121
122 static isc_symtab_t *symtab = NULL;
123 static isc_mem_t *sym_mctx;
124
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);
130 }
131
132 static void
133 add(char *key, int value) {
134         isc_result_t result;
135         isc_symvalue_t symvalue;
136
137         if (sym_mctx == NULL) {
138                 result = isc_mem_create(0, 0, &sym_mctx);
139                 if (result != ISC_R_SUCCESS)
140                         return;
141         }
142
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;
148         }
149
150         key = isc_mem_strdup(sym_mctx, key);
151         if (key == NULL)
152                 return;
153
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);
159 }
160
161 static isc_boolean_t
162 logged(char *key, int value) {
163         isc_result_t result;
164
165         if (symtab == NULL)
166                 return (ISC_FALSE);
167
168         result = isc_symtab_lookup(symtab, key, value, NULL);
169         if (result == ISC_R_SUCCESS)
170                 return (ISC_TRUE);
171         return (ISC_FALSE);
172 }
173
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)
177 {
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;
190
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;
200
201         dns_name_format(name, namebuf, sizeof(namebuf) - 1);
202         /*
203          * Turn off search.
204          */
205         if (dns_name_countlabels(name) > 1U)
206                 strcat(namebuf, ".");
207         dns_name_format(owner, ownerbuf, sizeof(ownerbuf));
208
209         result = getaddrinfo(namebuf, NULL, &hints, &ai);
210         dns_name_format(name, namebuf, sizeof(namebuf) - 1);
211         switch (result) {
212         case 0:
213                 /*
214                  * Work around broken getaddrinfo() implementations that
215                  * fail to set ai_canonname on first entry.
216                  */
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 '%s' (illegal)",
227                                      ownerbuf, namebuf,
228                                      cur->ai_canonname);
229                         /* XXX950 make fatal for 9.5.0 */
230                         /* answer = ISC_FALSE; */
231                         add(namebuf, ERR_IS_CNAME);
232                 }
233                 break;
234         case EAI_NONAME:
235 #if defined(EAI_NODATA) && (EAI_NODATA != EAI_NONAME)
236         case EAI_NODATA:
237 #endif
238                 if (!logged(namebuf, ERR_NO_ADDRESSES)) {
239                         dns_zone_log(zone, ISC_LOG_ERROR,
240                                      "%s/NS '%s' (out of zone) "
241                                      "has no addresses records (A or AAAA)",
242                                      ownerbuf, namebuf);
243                         add(namebuf, ERR_NO_ADDRESSES);
244                 }
245                 /* XXX950 make fatal for 9.5.0 */
246                 return (ISC_TRUE);
247
248         default:
249                 if (!logged(namebuf, ERR_LOOKUP_FAILURE)) {
250                         dns_zone_log(zone, ISC_LOG_WARNING,
251                                      "getaddrinfo(%s) failed: %s",
252                                      namebuf, gai_strerror(result));
253                         add(namebuf, ERR_LOOKUP_FAILURE);
254                 }
255                 return (ISC_TRUE);
256         }
257         if (a == NULL || aaaa == NULL)
258                 return (answer);
259         /*
260          * Check that all glue records really exist.
261          */
262         if (!dns_rdataset_isassociated(a))
263                 goto checkaaaa;
264         result = dns_rdataset_first(a);
265         while (result == ISC_R_SUCCESS) {
266                 dns_rdataset_current(a, &rdata);
267                 match = ISC_FALSE;
268                 for (cur = ai; cur != NULL; cur = cur->ai_next) {
269                         if (cur->ai_family != AF_INET)
270                                 continue;
271                         ptr = &((struct sockaddr_in *)(cur->ai_addr))->sin_addr;
272                         if (memcmp(ptr, rdata.data, rdata.length) == 0) {
273                                 match = ISC_TRUE;
274                                 break;
275                         }
276                 }
277                 if (!match && !logged(namebuf, ERR_EXTRA_A)) {
278                         dns_zone_log(zone, ISC_LOG_ERROR, "%s/NS '%s' "
279                                      "extra GLUE A record (%s)",
280                                      ownerbuf, namebuf,
281                                      inet_ntop(AF_INET, rdata.data,
282                                                addrbuf, sizeof(addrbuf)));
283                         add(namebuf, ERR_EXTRA_A);
284                         /* XXX950 make fatal for 9.5.0 */
285                         /* answer = ISC_FALSE; */
286                 }
287                 dns_rdata_reset(&rdata);
288                 result = dns_rdataset_next(a);
289         }
290
291  checkaaaa:
292         if (!dns_rdataset_isassociated(aaaa))
293                 goto checkmissing;
294         result = dns_rdataset_first(aaaa);
295         while (result == ISC_R_SUCCESS) {
296                 dns_rdataset_current(aaaa, &rdata);
297                 match = ISC_FALSE;
298                 for (cur = ai; cur != NULL; cur = cur->ai_next) {
299                         if (cur->ai_family != AF_INET6)
300                                 continue;
301                         ptr = &((struct sockaddr_in6 *)(cur->ai_addr))->sin6_addr;
302                         if (memcmp(ptr, rdata.data, rdata.length) == 0) {
303                                 match = ISC_TRUE;
304                                 break;
305                         }
306                 }
307                 if (!match && !logged(namebuf, ERR_EXTRA_AAAA)) {
308                         dns_zone_log(zone, ISC_LOG_ERROR, "%s/NS '%s' "
309                                      "extra GLUE AAAA record (%s)",
310                                      ownerbuf, namebuf,
311                                      inet_ntop(AF_INET6, rdata.data,
312                                                addrbuf, sizeof(addrbuf)));
313                         add(namebuf, ERR_EXTRA_AAAA);
314                         /* XXX950 make fatal for 9.5.0. */
315                         /* answer = ISC_FALSE; */
316                 }
317                 dns_rdata_reset(&rdata);
318                 result = dns_rdataset_next(aaaa);
319         }
320
321  checkmissing:
322         /*
323          * Check that all addresses appear in the glue.
324          */
325         if (!logged(namebuf, ERR_MISSING_GLUE)) {
326                 isc_boolean_t missing_glue = ISC_FALSE;
327                 for (cur = ai; cur != NULL; cur = cur->ai_next) {
328                         switch (cur->ai_family) {
329                         case AF_INET:
330                                 rdataset = a;
331                                 ptr = &((struct sockaddr_in *)(cur->ai_addr))->sin_addr;
332                                 type = "A";
333                                 break;
334                         case AF_INET6:
335                                 rdataset = aaaa;
336                                 ptr = &((struct sockaddr_in6 *)(cur->ai_addr))->sin6_addr;
337                                 type = "AAAA";
338                                 break;
339                         default:
340                                  continue;
341                         }
342                         match = ISC_FALSE;
343                         if (dns_rdataset_isassociated(rdataset))
344                                 result = dns_rdataset_first(rdataset);
345                         else
346                                 result = ISC_R_FAILURE;
347                         while (result == ISC_R_SUCCESS && !match) {
348                                 dns_rdataset_current(rdataset, &rdata);
349                                 if (memcmp(ptr, rdata.data, rdata.length) == 0)
350                                         match = ISC_TRUE;
351                                 dns_rdata_reset(&rdata);
352                                 result = dns_rdataset_next(rdataset);
353                         }
354                         if (!match) {
355                                 dns_zone_log(zone, ISC_LOG_ERROR, "%s/NS '%s' "
356                                              "missing GLUE %s record (%s)",
357                                              ownerbuf, namebuf, type,
358                                              inet_ntop(cur->ai_family, ptr,
359                                                        addrbuf, sizeof(addrbuf)));
360                                 /* XXX950 make fatal for 9.5.0. */
361                                 /* answer = ISC_FALSE; */
362                                 missing_glue = ISC_TRUE;
363                         }
364                 }
365                 if (missing_glue)
366                         add(namebuf, ERR_MISSING_GLUE);
367         }
368         freeaddrinfo(ai);
369         return (answer);
370 #else
371         return (ISC_TRUE);
372 #endif
373 }
374
375 static isc_boolean_t
376 checkmx(dns_zone_t *zone, dns_name_t *name, dns_name_t *owner) {
377 #ifdef USE_GETADDRINFO
378         struct addrinfo hints, *ai, *cur;
379         char namebuf[DNS_NAME_FORMATSIZE + 1];
380         char ownerbuf[DNS_NAME_FORMATSIZE];
381         int result;
382         int level = ISC_LOG_ERROR;
383         isc_boolean_t answer = ISC_TRUE;
384
385         memset(&hints, 0, sizeof(hints));
386         hints.ai_flags = AI_CANONNAME;
387         hints.ai_family = PF_UNSPEC;
388         hints.ai_socktype = SOCK_STREAM;
389         hints.ai_protocol = IPPROTO_TCP;
390
391         dns_name_format(name, namebuf, sizeof(namebuf) - 1);
392         /*
393          * Turn off search.
394          */
395         if (dns_name_countlabels(name) > 1U)
396                 strcat(namebuf, ".");
397         dns_name_format(owner, ownerbuf, sizeof(ownerbuf));
398
399         result = getaddrinfo(namebuf, NULL, &hints, &ai);
400         dns_name_format(name, namebuf, sizeof(namebuf) - 1);
401         switch (result) {
402         case 0:
403                 /*
404                  * Work around broken getaddrinfo() implementations that
405                  * fail to set ai_canonname on first entry.
406                  */
407                 cur = ai;
408                 while (cur != NULL && cur->ai_canonname == NULL &&
409                        cur->ai_next != NULL)
410                         cur = cur->ai_next;
411                 if (cur != NULL && cur->ai_canonname != NULL &&
412                     strcasecmp(cur->ai_canonname, namebuf) != 0) {
413                         if ((zone_options & DNS_ZONEOPT_WARNMXCNAME) != 0)
414                                 level = ISC_LOG_WARNING;
415                         if ((zone_options & DNS_ZONEOPT_IGNOREMXCNAME) == 0) {
416                                 if (!logged(namebuf, ERR_IS_MXCNAME)) {
417                                         dns_zone_log(zone, level,
418                                                      "%s/MX '%s' (out of zone)"
419                                                      " is a CNAME '%s' "
420                                                      "(illegal)",
421                                                      ownerbuf, namebuf,
422                                                      cur->ai_canonname);
423                                         add(namebuf, ERR_IS_MXCNAME);
424                                 }
425                                 if (level == ISC_LOG_ERROR)
426                                         answer = ISC_FALSE;
427                         }
428                 }
429                 freeaddrinfo(ai);
430                 return (answer);
431
432         case EAI_NONAME:
433 #if defined(EAI_NODATA) && (EAI_NODATA != EAI_NONAME)
434         case EAI_NODATA:
435 #endif
436                 if (!logged(namebuf, ERR_NO_ADDRESSES)) {
437                         dns_zone_log(zone, ISC_LOG_ERROR,
438                                      "%s/MX '%s' (out of zone) "
439                                      "has no addresses records (A or AAAA)",
440                                      ownerbuf, namebuf);
441                         add(namebuf, ERR_NO_ADDRESSES);
442                 }
443                 /* XXX950 make fatal for 9.5.0. */
444                 return (ISC_TRUE);
445
446         default:
447                 if (!logged(namebuf, ERR_LOOKUP_FAILURE)) {
448                         dns_zone_log(zone, ISC_LOG_WARNING,
449                              "getaddrinfo(%s) failed: %s",
450                              namebuf, gai_strerror(result));
451                         add(namebuf, ERR_LOOKUP_FAILURE);
452                 }
453                 return (ISC_TRUE);
454         }
455 #else
456         return (ISC_TRUE);
457 #endif
458 }
459
460 static isc_boolean_t
461 checksrv(dns_zone_t *zone, dns_name_t *name, dns_name_t *owner) {
462 #ifdef USE_GETADDRINFO
463         struct addrinfo hints, *ai, *cur;
464         char namebuf[DNS_NAME_FORMATSIZE + 1];
465         char ownerbuf[DNS_NAME_FORMATSIZE];
466         int result;
467         int level = ISC_LOG_ERROR;
468         isc_boolean_t answer = ISC_TRUE;
469
470         memset(&hints, 0, sizeof(hints));
471         hints.ai_flags = AI_CANONNAME;
472         hints.ai_family = PF_UNSPEC;
473         hints.ai_socktype = SOCK_STREAM;
474         hints.ai_protocol = IPPROTO_TCP;
475
476         dns_name_format(name, namebuf, sizeof(namebuf) - 1);
477         /*
478          * Turn off search.
479          */
480         if (dns_name_countlabels(name) > 1U)
481                 strcat(namebuf, ".");
482         dns_name_format(owner, ownerbuf, sizeof(ownerbuf));
483
484         result = getaddrinfo(namebuf, NULL, &hints, &ai);
485         dns_name_format(name, namebuf, sizeof(namebuf) - 1);
486         switch (result) {
487         case 0:
488                 /*
489                  * Work around broken getaddrinfo() implementations that
490                  * fail to set ai_canonname on first entry.
491                  */
492                 cur = ai;
493                 while (cur != NULL && cur->ai_canonname == NULL &&
494                        cur->ai_next != NULL)
495                         cur = cur->ai_next;
496                 if (cur != NULL && cur->ai_canonname != NULL &&
497                     strcasecmp(cur->ai_canonname, namebuf) != 0) {
498                         if ((zone_options & DNS_ZONEOPT_WARNSRVCNAME) != 0)
499                                 level = ISC_LOG_WARNING;
500                         if ((zone_options & DNS_ZONEOPT_IGNORESRVCNAME) == 0) {
501                                 if (!logged(namebuf, ERR_IS_SRVCNAME)) {
502                                         dns_zone_log(zone, level, "%s/SRV '%s'"
503                                                      " (out of zone) is a "
504                                                      "CNAME '%s' (illegal)",
505                                                      ownerbuf, namebuf,
506                                                      cur->ai_canonname);
507                                         add(namebuf, ERR_IS_SRVCNAME);
508                                 }
509                                 if (level == ISC_LOG_ERROR)
510                                         answer = ISC_FALSE;
511                         }
512                 }
513                 freeaddrinfo(ai);
514                 return (answer);
515
516         case EAI_NONAME:
517 #if defined(EAI_NODATA) && (EAI_NODATA != EAI_NONAME)
518         case EAI_NODATA:
519 #endif
520                 if (!logged(namebuf, ERR_NO_ADDRESSES)) {
521                         dns_zone_log(zone, ISC_LOG_ERROR,
522                                      "%s/SRV '%s' (out of zone) "
523                                      "has no addresses records (A or AAAA)",
524                                      ownerbuf, namebuf);
525                         add(namebuf, ERR_NO_ADDRESSES);
526                 }
527                 /* XXX950 make fatal for 9.5.0. */
528                 return (ISC_TRUE);
529
530         default:
531                 if (!logged(namebuf, ERR_LOOKUP_FAILURE)) {
532                         dns_zone_log(zone, ISC_LOG_WARNING,
533                                      "getaddrinfo(%s) failed: %s",
534                                      namebuf, gai_strerror(result));
535                         add(namebuf, ERR_LOOKUP_FAILURE);
536                 }
537                 return (ISC_TRUE);
538         }
539 #else
540         return (ISC_TRUE);
541 #endif
542 }
543
544 isc_result_t
545 setup_logging(isc_mem_t *mctx, FILE *errout, isc_log_t **logp) {
546         isc_logdestination_t destination;
547         isc_logconfig_t *logconfig = NULL;
548         isc_log_t *log = NULL;
549
550         RUNTIME_CHECK(isc_log_create(mctx, &log, &logconfig) == ISC_R_SUCCESS);
551         isc_log_registercategories(log, categories);
552         isc_log_setcontext(log);
553         dns_log_init(log);
554         dns_log_setcontext(log);
555         cfg_log_init(log);
556
557         destination.file.stream = errout;
558         destination.file.name = NULL;
559         destination.file.versions = ISC_LOG_ROLLNEVER;
560         destination.file.maximum_size = 0;
561         RUNTIME_CHECK(isc_log_createchannel(logconfig, "stderr",
562                                        ISC_LOG_TOFILEDESC,
563                                        ISC_LOG_DYNAMIC,
564                                        &destination, 0) == ISC_R_SUCCESS);
565         RUNTIME_CHECK(isc_log_usechannel(logconfig, "stderr",
566                                          NULL, NULL) == ISC_R_SUCCESS);
567
568         *logp = log;
569         return (ISC_R_SUCCESS);
570 }
571
572 /*% load the zone */
573 isc_result_t
574 load_zone(isc_mem_t *mctx, const char *zonename, const char *filename,
575           dns_masterformat_t fileformat, const char *classname,
576           dns_zone_t **zonep)
577 {
578         isc_result_t result;
579         dns_rdataclass_t rdclass;
580         isc_textregion_t region;
581         isc_buffer_t buffer;
582         dns_fixedname_t fixorigin;
583         dns_name_t *origin;
584         dns_zone_t *zone = NULL;
585
586         REQUIRE(zonep == NULL || *zonep == NULL);
587
588         if (debug)
589                 fprintf(stderr, "loading \"%s\" from \"%s\" class \"%s\"\n",
590                         zonename, filename, classname);
591
592         CHECK(dns_zone_create(&zone, mctx));
593
594         dns_zone_settype(zone, dns_zone_master);
595
596         isc_buffer_init(&buffer, zonename, strlen(zonename));
597         isc_buffer_add(&buffer, strlen(zonename));
598         dns_fixedname_init(&fixorigin);
599         origin = dns_fixedname_name(&fixorigin);
600         CHECK(dns_name_fromtext(origin, &buffer, dns_rootname,
601                                 ISC_FALSE, NULL));
602         CHECK(dns_zone_setorigin(zone, origin));
603         CHECK(dns_zone_setdbtype(zone, 1, (const char * const *) dbtype));
604         CHECK(dns_zone_setfile2(zone, filename, fileformat));
605
606         DE_CONST(classname, region.base);
607         region.length = strlen(classname);
608         CHECK(dns_rdataclass_fromtext(&rdclass, &region));
609
610         dns_zone_setclass(zone, rdclass);
611         dns_zone_setoption(zone, zone_options, ISC_TRUE);
612         dns_zone_setoption(zone, DNS_ZONEOPT_NOMERGE, nomerge);
613         if (docheckmx)
614                 dns_zone_setcheckmx(zone, checkmx);
615         if (docheckns)
616                 dns_zone_setcheckns(zone, checkns);
617         if (dochecksrv)
618                 dns_zone_setchecksrv(zone, checksrv);
619
620         CHECK(dns_zone_load(zone));
621         if (zonep != NULL) {
622                 *zonep = zone;
623                 zone = NULL;
624         }
625
626  cleanup:
627         if (zone != NULL)
628                 dns_zone_detach(&zone);
629         return (result);
630 }
631
632 /*% dump the zone */
633 isc_result_t
634 dump_zone(const char *zonename, dns_zone_t *zone, const char *filename,
635           dns_masterformat_t fileformat, const dns_master_style_t *style)
636 {
637         isc_result_t result;
638         FILE *output = stdout;
639
640         if (debug) {
641                 if (filename != NULL && strcmp(filename, "-") != 0)
642                         fprintf(stderr, "dumping \"%s\" to \"%s\"\n",
643                                 zonename, filename);
644                 else
645                         fprintf(stderr, "dumping \"%s\"\n", zonename);
646         }
647
648         if (filename != NULL && strcmp(filename, "-") != 0) {
649                 result = isc_stdio_open(filename, "w+", &output);
650
651                 if (result != ISC_R_SUCCESS) {
652                         fprintf(stderr, "could not open output "
653                                 "file \"%s\" for writing\n", filename);
654                         return (ISC_R_FAILURE);
655                 }
656         }
657
658         result = dns_zone_dumptostream2(zone, output, fileformat, style);
659
660         if (output != stdout)
661                 (void)isc_stdio_close(output);
662
663         return (result);
664 }