1 /* $NetBSD: check-tool.c,v 1.9 2023/01/25 21:43:22 christos Exp $ */
2
3 /*
4 * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
5 *
6 * SPDX-License-Identifier: MPL-2.0
7 *
8 * This Source Code Form is subject to the terms of the Mozilla Public
9 * License, v. 2.0. If a copy of the MPL was not distributed with this
10 * file, you can obtain one at https://mozilla.org/MPL/2.0/.
11 *
12 * See the COPYRIGHT file distributed with this work for additional
13 * information regarding copyright ownership.
14 */
15
16 /*! \file */
17
18 #include <inttypes.h>
19 #include <stdbool.h>
20 #include <stdio.h>
21
22 #ifdef _WIN32
23 #include <Winsock2.h>
24 #endif /* ifdef _WIN32 */
25
26 #include <isc/buffer.h>
27 #include <isc/log.h>
28 #include <isc/mem.h>
29 #include <isc/net.h>
30 #include <isc/netdb.h>
31 #include <isc/print.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/db.h>
40 #include <dns/dbiterator.h>
41 #include <dns/fixedname.h>
42 #include <dns/log.h>
43 #include <dns/name.h>
44 #include <dns/rdata.h>
45 #include <dns/rdataclass.h>
46 #include <dns/rdataset.h>
47 #include <dns/rdatasetiter.h>
48 #include <dns/rdatatype.h>
49 #include <dns/result.h>
50 #include <dns/types.h>
51 #include <dns/zone.h>
52
53 #include <isccfg/log.h>
54
55 #include <ns/log.h>
56
57 #include "check-tool.h"
58
59 #ifndef CHECK_SIBLING
60 #define CHECK_SIBLING 1
61 #endif /* ifndef CHECK_SIBLING */
62
63 #ifndef CHECK_LOCAL
64 #define CHECK_LOCAL 1
65 #endif /* ifndef CHECK_LOCAL */
66
67 #define CHECK(r) \
68 do { \
69 result = (r); \
70 if (result != ISC_R_SUCCESS) \
71 goto cleanup; \
72 } while (0)
73
74 #define ERR_IS_CNAME 1
75 #define ERR_NO_ADDRESSES 2
76 #define ERR_LOOKUP_FAILURE 3
77 #define ERR_EXTRA_A 4
78 #define ERR_EXTRA_AAAA 5
79 #define ERR_MISSING_GLUE 5
80 #define ERR_IS_MXCNAME 6
81 #define ERR_IS_SRVCNAME 7
82
83 static const char *dbtype[] = { "rbt" };
84
85 int debug = 0;
86 const char *journal = NULL;
87 bool nomerge = true;
88 #if CHECK_LOCAL
89 bool docheckmx = true;
90 bool dochecksrv = true;
91 bool docheckns = true;
92 #else /* if CHECK_LOCAL */
93 bool docheckmx = false;
94 bool dochecksrv = false;
95 bool docheckns = false;
96 #endif /* if CHECK_LOCAL */
97 dns_zoneopt_t zone_options = DNS_ZONEOPT_CHECKNS | DNS_ZONEOPT_CHECKMX |
98 DNS_ZONEOPT_MANYERRORS | DNS_ZONEOPT_CHECKNAMES |
99 DNS_ZONEOPT_CHECKINTEGRITY |
100 #if CHECK_SIBLING
101 DNS_ZONEOPT_CHECKSIBLING |
102 #endif /* if CHECK_SIBLING */
103 DNS_ZONEOPT_CHECKWILDCARD |
104 DNS_ZONEOPT_WARNMXCNAME | DNS_ZONEOPT_WARNSRVCNAME;
105
106 /*
107 * This needs to match the list in bin/named/log.c.
108 */
109 static isc_logcategory_t categories[] = { { "", 0 },
110 { "unmatched", 0 },
111 { NULL, 0 } };
112
113 static isc_symtab_t *symtab = NULL;
114 static isc_mem_t *sym_mctx;
115
116 static void
freekey(char * key,unsigned int type,isc_symvalue_t value,void * userarg)117 freekey(char *key, unsigned int type, isc_symvalue_t value, void *userarg) {
118 UNUSED(type);
119 UNUSED(value);
120 isc_mem_free(userarg, key);
121 }
122
123 static void
add(char * key,int value)124 add(char *key, int value) {
125 isc_result_t result;
126 isc_symvalue_t symvalue;
127
128 if (sym_mctx == NULL) {
129 isc_mem_create(&sym_mctx);
130 }
131
132 if (symtab == NULL) {
133 result = isc_symtab_create(sym_mctx, 100, freekey, sym_mctx,
134 false, &symtab);
135 if (result != ISC_R_SUCCESS) {
136 return;
137 }
138 }
139
140 key = isc_mem_strdup(sym_mctx, key);
141
142 symvalue.as_pointer = NULL;
143 result = isc_symtab_define(symtab, key, value, symvalue,
144 isc_symexists_reject);
145 if (result != ISC_R_SUCCESS) {
146 isc_mem_free(sym_mctx, key);
147 }
148 }
149
150 static bool
logged(char * key,int value)151 logged(char *key, int value) {
152 isc_result_t result;
153
154 if (symtab == NULL) {
155 return (false);
156 }
157
158 result = isc_symtab_lookup(symtab, key, value, NULL);
159 if (result == ISC_R_SUCCESS) {
160 return (true);
161 }
162 return (false);
163 }
164
165 static bool
checkns(dns_zone_t * zone,const dns_name_t * name,const dns_name_t * owner,dns_rdataset_t * a,dns_rdataset_t * aaaa)166 checkns(dns_zone_t *zone, const dns_name_t *name, const dns_name_t *owner,
167 dns_rdataset_t *a, dns_rdataset_t *aaaa) {
168 dns_rdataset_t *rdataset;
169 dns_rdata_t rdata = DNS_RDATA_INIT;
170 struct addrinfo hints, *ai, *cur;
171 char namebuf[DNS_NAME_FORMATSIZE + 1];
172 char ownerbuf[DNS_NAME_FORMATSIZE];
173 char addrbuf[sizeof("xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:123.123.123.123")];
174 bool answer = true;
175 bool match;
176 const char *type;
177 void *ptr = NULL;
178 int result;
179
180 REQUIRE(a == NULL || !dns_rdataset_isassociated(a) ||
181 a->type == dns_rdatatype_a);
182 REQUIRE(aaaa == NULL || !dns_rdataset_isassociated(aaaa) ||
183 aaaa->type == dns_rdatatype_aaaa);
184
185 if (a == NULL || aaaa == NULL) {
186 return (answer);
187 }
188
189 memset(&hints, 0, sizeof(hints));
190 hints.ai_flags = AI_CANONNAME;
191 hints.ai_family = PF_UNSPEC;
192 hints.ai_socktype = SOCK_STREAM;
193 hints.ai_protocol = IPPROTO_TCP;
194
195 dns_name_format(name, namebuf, sizeof(namebuf) - 1);
196 /*
197 * Turn off search.
198 */
199 if (dns_name_countlabels(name) > 1U) {
200 strlcat(namebuf, ".", sizeof(namebuf));
201 }
202 dns_name_format(owner, ownerbuf, sizeof(ownerbuf));
203
204 result = getaddrinfo(namebuf, NULL, &hints, &ai);
205 dns_name_format(name, namebuf, sizeof(namebuf) - 1);
206 switch (result) {
207 case 0:
208 /*
209 * Work around broken getaddrinfo() implementations that
210 * fail to set ai_canonname on first entry.
211 */
212 cur = ai;
213 while (cur != NULL && cur->ai_canonname == NULL &&
214 cur->ai_next != NULL)
215 {
216 cur = cur->ai_next;
217 }
218 if (cur != NULL && cur->ai_canonname != NULL &&
219 strcasecmp(cur->ai_canonname, namebuf) != 0 &&
220 !logged(namebuf, ERR_IS_CNAME))
221 {
222 dns_zone_log(zone, ISC_LOG_ERROR,
223 "%s/NS '%s' (out of zone) "
224 "is a CNAME '%s' (illegal)",
225 ownerbuf, namebuf, cur->ai_canonname);
226 /* XXX950 make fatal for 9.5.0 */
227 /* answer = false; */
228 add(namebuf, ERR_IS_CNAME);
229 }
230 break;
231 case EAI_NONAME:
232 #if defined(EAI_NODATA) && (EAI_NODATA != EAI_NONAME)
233 case EAI_NODATA:
234 #endif /* if defined(EAI_NODATA) && (EAI_NODATA != EAI_NONAME) */
235 if (!logged(namebuf, ERR_NO_ADDRESSES)) {
236 dns_zone_log(zone, ISC_LOG_ERROR,
237 "%s/NS '%s' (out of zone) "
238 "has no addresses records (A or AAAA)",
239 ownerbuf, namebuf);
240 add(namebuf, ERR_NO_ADDRESSES);
241 }
242 /* XXX950 make fatal for 9.5.0 */
243 return (true);
244
245 default:
246 if (!logged(namebuf, ERR_LOOKUP_FAILURE)) {
247 dns_zone_log(zone, ISC_LOG_WARNING,
248 "getaddrinfo(%s) failed: %s", namebuf,
249 gai_strerror(result));
250 add(namebuf, ERR_LOOKUP_FAILURE);
251 }
252 return (true);
253 }
254
255 /*
256 * Check that all glue records really exist.
257 */
258 if (!dns_rdataset_isassociated(a)) {
259 goto checkaaaa;
260 }
261 result = dns_rdataset_first(a);
262 while (result == ISC_R_SUCCESS) {
263 dns_rdataset_current(a, &rdata);
264 match = false;
265 for (cur = ai; cur != NULL; cur = cur->ai_next) {
266 if (cur->ai_family != AF_INET) {
267 continue;
268 }
269 ptr = &((struct sockaddr_in *)(cur->ai_addr))->sin_addr;
270 if (memcmp(ptr, rdata.data, rdata.length) == 0) {
271 match = true;
272 break;
273 }
274 }
275 if (!match && !logged(namebuf, ERR_EXTRA_A)) {
276 dns_zone_log(zone, ISC_LOG_ERROR,
277 "%s/NS '%s' "
278 "extra GLUE A record (%s)",
279 ownerbuf, namebuf,
280 inet_ntop(AF_INET, rdata.data, addrbuf,
281 sizeof(addrbuf)));
282 add(namebuf, ERR_EXTRA_A);
283 /* XXX950 make fatal for 9.5.0 */
284 /* answer = 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 }
294 result = dns_rdataset_first(aaaa);
295 while (result == ISC_R_SUCCESS) {
296 dns_rdataset_current(aaaa, &rdata);
297 match = false;
298 for (cur = ai; cur != NULL; cur = cur->ai_next) {
299 if (cur->ai_family != AF_INET6) {
300 continue;
301 }
302 ptr = &((struct sockaddr_in6 *)(cur->ai_addr))
303 ->sin6_addr;
304 if (memcmp(ptr, rdata.data, rdata.length) == 0) {
305 match = true;
306 break;
307 }
308 }
309 if (!match && !logged(namebuf, ERR_EXTRA_AAAA)) {
310 dns_zone_log(zone, ISC_LOG_ERROR,
311 "%s/NS '%s' "
312 "extra GLUE AAAA record (%s)",
313 ownerbuf, namebuf,
314 inet_ntop(AF_INET6, rdata.data, addrbuf,
315 sizeof(addrbuf)));
316 add(namebuf, ERR_EXTRA_AAAA);
317 /* XXX950 make fatal for 9.5.0. */
318 /* answer = false; */
319 }
320 dns_rdata_reset(&rdata);
321 result = dns_rdataset_next(aaaa);
322 }
323
324 checkmissing:
325 /*
326 * Check that all addresses appear in the glue.
327 */
328 if (!logged(namebuf, ERR_MISSING_GLUE)) {
329 bool missing_glue = false;
330 for (cur = ai; cur != NULL; cur = cur->ai_next) {
331 switch (cur->ai_family) {
332 case AF_INET:
333 rdataset = a;
334 ptr = &((struct sockaddr_in *)(cur->ai_addr))
335 ->sin_addr;
336 type = "A";
337 break;
338 case AF_INET6:
339 rdataset = aaaa;
340 ptr = &((struct sockaddr_in6 *)(cur->ai_addr))
341 ->sin6_addr;
342 type = "AAAA";
343 break;
344 default:
345 continue;
346 }
347 match = false;
348 if (dns_rdataset_isassociated(rdataset)) {
349 result = dns_rdataset_first(rdataset);
350 } else {
351 result = ISC_R_FAILURE;
352 }
353 while (result == ISC_R_SUCCESS && !match) {
354 dns_rdataset_current(rdataset, &rdata);
355 if (memcmp(ptr, rdata.data, rdata.length) == 0)
356 {
357 match = true;
358 }
359 dns_rdata_reset(&rdata);
360 result = dns_rdataset_next(rdataset);
361 }
362 if (!match) {
363 dns_zone_log(zone, ISC_LOG_ERROR,
364 "%s/NS '%s' "
365 "missing GLUE %s record (%s)",
366 ownerbuf, namebuf, type,
367 inet_ntop(cur->ai_family, ptr,
368 addrbuf,
369 sizeof(addrbuf)));
370 /* XXX950 make fatal for 9.5.0. */
371 /* answer = false; */
372 missing_glue = true;
373 }
374 }
375 if (missing_glue) {
376 add(namebuf, ERR_MISSING_GLUE);
377 }
378 }
379 freeaddrinfo(ai);
380 return (answer);
381 }
382
383 static bool
checkmx(dns_zone_t * zone,const dns_name_t * name,const dns_name_t * owner)384 checkmx(dns_zone_t *zone, const dns_name_t *name, const dns_name_t *owner) {
385 struct addrinfo hints, *ai, *cur;
386 char namebuf[DNS_NAME_FORMATSIZE + 1];
387 char ownerbuf[DNS_NAME_FORMATSIZE];
388 int result;
389 int level = ISC_LOG_ERROR;
390 bool answer = true;
391
392 memset(&hints, 0, sizeof(hints));
393 hints.ai_flags = AI_CANONNAME;
394 hints.ai_family = PF_UNSPEC;
395 hints.ai_socktype = SOCK_STREAM;
396 hints.ai_protocol = IPPROTO_TCP;
397
398 dns_name_format(name, namebuf, sizeof(namebuf) - 1);
399 /*
400 * Turn off search.
401 */
402 if (dns_name_countlabels(name) > 1U) {
403 strlcat(namebuf, ".", sizeof(namebuf));
404 }
405 dns_name_format(owner, ownerbuf, sizeof(ownerbuf));
406
407 result = getaddrinfo(namebuf, NULL, &hints, &ai);
408 dns_name_format(name, namebuf, sizeof(namebuf) - 1);
409 switch (result) {
410 case 0:
411 /*
412 * Work around broken getaddrinfo() implementations that
413 * fail to set ai_canonname on first entry.
414 */
415 cur = ai;
416 while (cur != NULL && cur->ai_canonname == NULL &&
417 cur->ai_next != NULL)
418 {
419 cur = cur->ai_next;
420 }
421 if (cur != NULL && cur->ai_canonname != NULL &&
422 strcasecmp(cur->ai_canonname, namebuf) != 0)
423 {
424 if ((zone_options & DNS_ZONEOPT_WARNMXCNAME) != 0) {
425 level = ISC_LOG_WARNING;
426 }
427 if ((zone_options & DNS_ZONEOPT_IGNOREMXCNAME) == 0) {
428 if (!logged(namebuf, ERR_IS_MXCNAME)) {
429 dns_zone_log(zone, level,
430 "%s/MX '%s' (out of zone)"
431 " is a CNAME '%s' "
432 "(illegal)",
433 ownerbuf, namebuf,
434 cur->ai_canonname);
435 add(namebuf, ERR_IS_MXCNAME);
436 }
437 if (level == ISC_LOG_ERROR) {
438 answer = false;
439 }
440 }
441 }
442 freeaddrinfo(ai);
443 return (answer);
444
445 case EAI_NONAME:
446 #if defined(EAI_NODATA) && (EAI_NODATA != EAI_NONAME)
447 case EAI_NODATA:
448 #endif /* if defined(EAI_NODATA) && (EAI_NODATA != EAI_NONAME) */
449 if (!logged(namebuf, ERR_NO_ADDRESSES)) {
450 dns_zone_log(zone, ISC_LOG_ERROR,
451 "%s/MX '%s' (out of zone) "
452 "has no addresses records (A or AAAA)",
453 ownerbuf, namebuf);
454 add(namebuf, ERR_NO_ADDRESSES);
455 }
456 /* XXX950 make fatal for 9.5.0. */
457 return (true);
458
459 default:
460 if (!logged(namebuf, ERR_LOOKUP_FAILURE)) {
461 dns_zone_log(zone, ISC_LOG_WARNING,
462 "getaddrinfo(%s) failed: %s", namebuf,
463 gai_strerror(result));
464 add(namebuf, ERR_LOOKUP_FAILURE);
465 }
466 return (true);
467 }
468 }
469
470 static bool
checksrv(dns_zone_t * zone,const dns_name_t * name,const dns_name_t * owner)471 checksrv(dns_zone_t *zone, const dns_name_t *name, const dns_name_t *owner) {
472 struct addrinfo hints, *ai, *cur;
473 char namebuf[DNS_NAME_FORMATSIZE + 1];
474 char ownerbuf[DNS_NAME_FORMATSIZE];
475 int result;
476 int level = ISC_LOG_ERROR;
477 bool answer = true;
478
479 memset(&hints, 0, sizeof(hints));
480 hints.ai_flags = AI_CANONNAME;
481 hints.ai_family = PF_UNSPEC;
482 hints.ai_socktype = SOCK_STREAM;
483 hints.ai_protocol = IPPROTO_TCP;
484
485 dns_name_format(name, namebuf, sizeof(namebuf) - 1);
486 /*
487 * Turn off search.
488 */
489 if (dns_name_countlabels(name) > 1U) {
490 strlcat(namebuf, ".", sizeof(namebuf));
491 }
492 dns_name_format(owner, ownerbuf, sizeof(ownerbuf));
493
494 result = getaddrinfo(namebuf, NULL, &hints, &ai);
495 dns_name_format(name, namebuf, sizeof(namebuf) - 1);
496 switch (result) {
497 case 0:
498 /*
499 * Work around broken getaddrinfo() implementations that
500 * fail to set ai_canonname on first entry.
501 */
502 cur = ai;
503 while (cur != NULL && cur->ai_canonname == NULL &&
504 cur->ai_next != NULL)
505 {
506 cur = cur->ai_next;
507 }
508 if (cur != NULL && cur->ai_canonname != NULL &&
509 strcasecmp(cur->ai_canonname, namebuf) != 0)
510 {
511 if ((zone_options & DNS_ZONEOPT_WARNSRVCNAME) != 0) {
512 level = ISC_LOG_WARNING;
513 }
514 if ((zone_options & DNS_ZONEOPT_IGNORESRVCNAME) == 0) {
515 if (!logged(namebuf, ERR_IS_SRVCNAME)) {
516 dns_zone_log(zone, level,
517 "%s/SRV '%s'"
518 " (out of zone) is a "
519 "CNAME '%s' (illegal)",
520 ownerbuf, namebuf,
521 cur->ai_canonname);
522 add(namebuf, ERR_IS_SRVCNAME);
523 }
524 if (level == ISC_LOG_ERROR) {
525 answer = false;
526 }
527 }
528 }
529 freeaddrinfo(ai);
530 return (answer);
531
532 case EAI_NONAME:
533 #if defined(EAI_NODATA) && (EAI_NODATA != EAI_NONAME)
534 case EAI_NODATA:
535 #endif /* if defined(EAI_NODATA) && (EAI_NODATA != EAI_NONAME) */
536 if (!logged(namebuf, ERR_NO_ADDRESSES)) {
537 dns_zone_log(zone, ISC_LOG_ERROR,
538 "%s/SRV '%s' (out of zone) "
539 "has no addresses records (A or AAAA)",
540 ownerbuf, namebuf);
541 add(namebuf, ERR_NO_ADDRESSES);
542 }
543 /* XXX950 make fatal for 9.5.0. */
544 return (true);
545
546 default:
547 if (!logged(namebuf, ERR_LOOKUP_FAILURE)) {
548 dns_zone_log(zone, ISC_LOG_WARNING,
549 "getaddrinfo(%s) failed: %s", namebuf,
550 gai_strerror(result));
551 add(namebuf, ERR_LOOKUP_FAILURE);
552 }
553 return (true);
554 }
555 }
556
557 isc_result_t
setup_logging(isc_mem_t * mctx,FILE * errout,isc_log_t ** logp)558 setup_logging(isc_mem_t *mctx, FILE *errout, isc_log_t **logp) {
559 isc_logdestination_t destination;
560 isc_logconfig_t *logconfig = NULL;
561 isc_log_t *log = NULL;
562
563 isc_log_create(mctx, &log, &logconfig);
564 isc_log_registercategories(log, categories);
565 isc_log_setcontext(log);
566 dns_log_init(log);
567 dns_log_setcontext(log);
568 cfg_log_init(log);
569 ns_log_init(log);
570
571 destination.file.stream = errout;
572 destination.file.name = NULL;
573 destination.file.versions = ISC_LOG_ROLLNEVER;
574 destination.file.maximum_size = 0;
575 isc_log_createchannel(logconfig, "stderr", ISC_LOG_TOFILEDESC,
576 ISC_LOG_DYNAMIC, &destination, 0);
577
578 RUNTIME_CHECK(isc_log_usechannel(logconfig, "stderr", NULL, NULL) ==
579 ISC_R_SUCCESS);
580
581 *logp = log;
582 return (ISC_R_SUCCESS);
583 }
584
585 /*% scan the zone for oversize TTLs */
586 static isc_result_t
check_ttls(dns_zone_t * zone,dns_ttl_t maxttl)587 check_ttls(dns_zone_t *zone, dns_ttl_t maxttl) {
588 isc_result_t result;
589 dns_db_t *db = NULL;
590 dns_dbversion_t *version = NULL;
591 dns_dbnode_t *node = NULL;
592 dns_dbiterator_t *dbiter = NULL;
593 dns_rdatasetiter_t *rdsiter = NULL;
594 dns_rdataset_t rdataset;
595 dns_fixedname_t fname;
596 dns_name_t *name;
597 name = dns_fixedname_initname(&fname);
598 dns_rdataset_init(&rdataset);
599
600 CHECK(dns_zone_getdb(zone, &db));
601 INSIST(db != NULL);
602
603 CHECK(dns_db_newversion(db, &version));
604 CHECK(dns_db_createiterator(db, 0, &dbiter));
605
606 for (result = dns_dbiterator_first(dbiter); result == ISC_R_SUCCESS;
607 result = dns_dbiterator_next(dbiter))
608 {
609 result = dns_dbiterator_current(dbiter, &node, name);
610 if (result == DNS_R_NEWORIGIN) {
611 result = ISC_R_SUCCESS;
612 }
613 CHECK(result);
614
615 CHECK(dns_db_allrdatasets(db, node, version, 0, 0, &rdsiter));
616 for (result = dns_rdatasetiter_first(rdsiter);
617 result == ISC_R_SUCCESS;
618 result = dns_rdatasetiter_next(rdsiter))
619 {
620 dns_rdatasetiter_current(rdsiter, &rdataset);
621 if (rdataset.ttl > maxttl) {
622 char nbuf[DNS_NAME_FORMATSIZE];
623 char tbuf[255];
624 isc_buffer_t b;
625 isc_region_t r;
626
627 dns_name_format(name, nbuf, sizeof(nbuf));
628 isc_buffer_init(&b, tbuf, sizeof(tbuf) - 1);
629 CHECK(dns_rdatatype_totext(rdataset.type, &b));
630 isc_buffer_usedregion(&b, &r);
631 r.base[r.length] = 0;
632
633 dns_zone_log(zone, ISC_LOG_ERROR,
634 "%s/%s TTL %d exceeds "
635 "maximum TTL %d",
636 nbuf, tbuf, rdataset.ttl, maxttl);
637 dns_rdataset_disassociate(&rdataset);
638 CHECK(ISC_R_RANGE);
639 }
640 dns_rdataset_disassociate(&rdataset);
641 }
642 if (result == ISC_R_NOMORE) {
643 result = ISC_R_SUCCESS;
644 }
645 CHECK(result);
646
647 dns_rdatasetiter_destroy(&rdsiter);
648 dns_db_detachnode(db, &node);
649 }
650
651 if (result == ISC_R_NOMORE) {
652 result = ISC_R_SUCCESS;
653 }
654
655 cleanup:
656 if (node != NULL) {
657 dns_db_detachnode(db, &node);
658 }
659 if (rdsiter != NULL) {
660 dns_rdatasetiter_destroy(&rdsiter);
661 }
662 if (dbiter != NULL) {
663 dns_dbiterator_destroy(&dbiter);
664 }
665 if (version != NULL) {
666 dns_db_closeversion(db, &version, false);
667 }
668 if (db != NULL) {
669 dns_db_detach(&db);
670 }
671
672 return (result);
673 }
674
675 /*% load the zone */
676 isc_result_t
load_zone(isc_mem_t * mctx,const char * zonename,const char * filename,dns_masterformat_t fileformat,const char * classname,dns_ttl_t maxttl,dns_zone_t ** zonep)677 load_zone(isc_mem_t *mctx, const char *zonename, const char *filename,
678 dns_masterformat_t fileformat, const char *classname,
679 dns_ttl_t maxttl, dns_zone_t **zonep) {
680 isc_result_t result;
681 dns_rdataclass_t rdclass;
682 isc_textregion_t region;
683 isc_buffer_t buffer;
684 dns_fixedname_t fixorigin;
685 dns_name_t *origin;
686 dns_zone_t *zone = NULL;
687
688 REQUIRE(zonep == NULL || *zonep == NULL);
689
690 if (debug) {
691 fprintf(stderr, "loading \"%s\" from \"%s\" class \"%s\"\n",
692 zonename, filename, classname);
693 }
694
695 CHECK(dns_zone_create(&zone, mctx));
696
697 dns_zone_settype(zone, dns_zone_primary);
698
699 isc_buffer_constinit(&buffer, zonename, strlen(zonename));
700 isc_buffer_add(&buffer, strlen(zonename));
701 origin = dns_fixedname_initname(&fixorigin);
702 CHECK(dns_name_fromtext(origin, &buffer, dns_rootname, 0, NULL));
703 CHECK(dns_zone_setorigin(zone, origin));
704 dns_zone_setdbtype(zone, 1, (const char *const *)dbtype);
705 CHECK(dns_zone_setfile(zone, filename, fileformat,
706 &dns_master_style_default));
707 if (journal != NULL) {
708 CHECK(dns_zone_setjournal(zone, journal));
709 }
710
711 DE_CONST(classname, region.base);
712 region.length = strlen(classname);
713 CHECK(dns_rdataclass_fromtext(&rdclass, ®ion));
714
715 dns_zone_setclass(zone, rdclass);
716 dns_zone_setoption(zone, zone_options, true);
717 dns_zone_setoption(zone, DNS_ZONEOPT_NOMERGE, nomerge);
718
719 dns_zone_setmaxttl(zone, maxttl);
720
721 if (docheckmx) {
722 dns_zone_setcheckmx(zone, checkmx);
723 }
724 if (docheckns) {
725 dns_zone_setcheckns(zone, checkns);
726 }
727 if (dochecksrv) {
728 dns_zone_setchecksrv(zone, checksrv);
729 }
730
731 CHECK(dns_zone_load(zone, false));
732
733 /*
734 * When loading map files we can't catch oversize TTLs during
735 * load, so we check for them here.
736 */
737 if (fileformat == dns_masterformat_map && maxttl != 0) {
738 CHECK(check_ttls(zone, maxttl));
739 }
740
741 if (zonep != NULL) {
742 *zonep = zone;
743 zone = NULL;
744 }
745
746 cleanup:
747 if (zone != NULL) {
748 dns_zone_detach(&zone);
749 }
750 return (result);
751 }
752
753 /*% dump the zone */
754 isc_result_t
dump_zone(const char * zonename,dns_zone_t * zone,const char * filename,dns_masterformat_t fileformat,const dns_master_style_t * style,const uint32_t rawversion)755 dump_zone(const char *zonename, dns_zone_t *zone, const char *filename,
756 dns_masterformat_t fileformat, const dns_master_style_t *style,
757 const uint32_t rawversion) {
758 isc_result_t result;
759 FILE *output = stdout;
760 const char *flags;
761
762 flags = (fileformat == dns_masterformat_text) ? "w" : "wb";
763
764 if (debug) {
765 if (filename != NULL && strcmp(filename, "-") != 0) {
766 fprintf(stderr, "dumping \"%s\" to \"%s\"\n", zonename,
767 filename);
768 } else {
769 fprintf(stderr, "dumping \"%s\"\n", zonename);
770 }
771 }
772
773 if (filename != NULL && strcmp(filename, "-") != 0) {
774 result = isc_stdio_open(filename, flags, &output);
775
776 if (result != ISC_R_SUCCESS) {
777 fprintf(stderr,
778 "could not open output "
779 "file \"%s\" for writing\n",
780 filename);
781 return (ISC_R_FAILURE);
782 }
783 }
784
785 result = dns_zone_dumptostream(zone, output, fileformat, style,
786 rawversion);
787 if (output != stdout) {
788 (void)isc_stdio_close(output);
789 }
790
791 return (result);
792 }
793
794 #ifdef _WIN32
795 void
InitSockets(void)796 InitSockets(void) {
797 WORD wVersionRequested;
798 WSADATA wsaData;
799 int err;
800
801 wVersionRequested = MAKEWORD(2, 0);
802
803 err = WSAStartup(wVersionRequested, &wsaData);
804 if (err != 0) {
805 fprintf(stderr, "WSAStartup() failed: %d\n", err);
806 exit(1);
807 }
808 }
809
810 void
DestroySockets(void)811 DestroySockets(void) {
812 WSACleanup();
813 }
814 #endif /* ifdef _WIN32 */
815