Import bind 9.5.2 vendor sources.
[dragonfly.git] / contrib / bind-9.5.2 / 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.31.62.5 2009/01/27 21:17:39 jinmei 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 (illegal)",
227                                      ownerbuf, namebuf);
228                         /* XXX950 make fatal for 9.5.0 */
229                         /* answer = ISC_FALSE; */
230                         add(namebuf, ERR_IS_CNAME);
231                 }
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);
243                 }
244                 /* XXX950 make fatal for 9.5.0 */
245                 return (ISC_TRUE);
246
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);
253                 }
254                 return (ISC_TRUE);
255         }
256         if (a == NULL || aaaa == NULL)
257                 return (answer);
258         /*
259          * Check that all glue records really exist.
260          */
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;
274                         }
275                 }
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; */
285                 }
286                 dns_rdata_reset(&rdata);
287                 result = dns_rdataset_next(a);
288         }
289
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;
304                         }
305                 }
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; */
315                 }
316                 dns_rdata_reset(&rdata);
317                 result = dns_rdataset_next(aaaa);
318         }
319
320  checkmissing:
321         /*
322          * Check that all addresses appear in the glue.
323          */
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;
340                         }
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);
352                         }
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;
362                         }
363                 }
364                 if (missing_glue)
365                         add(namebuf, ERR_MISSING_GLUE);
366         }
367         freeaddrinfo(ai);
368         return (answer);
369 #else
370         return (ISC_TRUE);
371 #endif
372 }
373
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;
383
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;
389
390         dns_name_format(name, namebuf, sizeof(namebuf) - 1);
391         /*
392          * Turn off search.
393          */
394         if (dns_name_countlabels(name) > 1U)
395                 strcat(namebuf, ".");
396         dns_name_format(owner, ownerbuf, sizeof(ownerbuf));
397
398         result = getaddrinfo(namebuf, NULL, &hints, &ai);
399         dns_name_format(name, namebuf, sizeof(namebuf) - 1);
400         switch (result) {
401         case 0:
402                 /*
403                  * Work around broken getaddrinfo() implementations that
404                  * fail to set ai_canonname on first entry.
405                  */
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);
421                                 }
422                                 if (level == ISC_LOG_ERROR)
423                                         answer = ISC_FALSE;
424                         }
425                 }
426                 freeaddrinfo(ai);
427                 return (answer);
428
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);
439                 }
440                 /* XXX950 make fatal for 9.5.0. */
441                 return (ISC_TRUE);
442
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);
449                 }
450                 return (ISC_TRUE);
451         }
452 #else
453         return (ISC_TRUE);
454 #endif
455 }
456
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;
466
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;
472
473         dns_name_format(name, namebuf, sizeof(namebuf) - 1);
474         /*
475          * Turn off search.
476          */
477         if (dns_name_countlabels(name) > 1U)
478                 strcat(namebuf, ".");
479         dns_name_format(owner, ownerbuf, sizeof(ownerbuf));
480
481         result = getaddrinfo(namebuf, NULL, &hints, &ai);
482         dns_name_format(name, namebuf, sizeof(namebuf) - 1);
483         switch (result) {
484         case 0:
485                 /*
486                  * Work around broken getaddrinfo() implementations that
487                  * fail to set ai_canonname on first entry.
488                  */
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);
504                                 }
505                                 if (level == ISC_LOG_ERROR)
506                                         answer = ISC_FALSE;
507                         }
508                 }
509                 freeaddrinfo(ai);
510                 return (answer);
511
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);
522                 }
523                 /* XXX950 make fatal for 9.5.0. */
524                 return (ISC_TRUE);
525
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);
532                 }
533                 return (ISC_TRUE);
534         }
535 #else
536         return (ISC_TRUE);
537 #endif
538 }
539
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;
545
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);
552
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);
563
564         *logp = log;
565         return (ISC_R_SUCCESS);
566 }
567
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)
573 {
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;
581
582         REQUIRE(zonep == NULL || *zonep == NULL);
583
584         if (debug)
585                 fprintf(stderr, "loading \"%s\" from \"%s\" class \"%s\"\n",
586                         zonename, filename, classname);
587
588         CHECK(dns_zone_create(&zone, mctx));
589
590         dns_zone_settype(zone, dns_zone_master);
591
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));
601
602         DE_CONST(classname, region.base);
603         region.length = strlen(classname);
604         CHECK(dns_rdataclass_fromtext(&rdclass, &region));
605
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);
615
616         CHECK(dns_zone_load(zone));
617         if (zonep != NULL) {
618                 *zonep = zone;
619                 zone = NULL;
620         }
621
622  cleanup:
623         if (zone != NULL)
624                 dns_zone_detach(&zone);
625         return (result);
626 }
627
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)
632 {
633         isc_result_t result;
634         FILE *output = stdout;
635
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);
642         }
643
644         if (filename != NULL && strcmp(filename, "-") != 0) {
645                 result = isc_stdio_open(filename, "w+", &output);
646
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);
651                 }
652         }
653
654         result = dns_zone_dumptostream2(zone, output, fileformat, style);
655
656         if (output != stdout)
657                 (void)isc_stdio_close(output);
658
659         return (result);
660 }