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