check-tool.c revision 1.9
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 83static const char *dbtype[] = { "rbt" }; 84 85int debug = 0; 86const char *journal = NULL; 87bool nomerge = true; 88#if CHECK_LOCAL 89bool docheckmx = true; 90bool dochecksrv = true; 91bool docheckns = true; 92#else /* if CHECK_LOCAL */ 93bool docheckmx = false; 94bool dochecksrv = false; 95bool docheckns = false; 96#endif /* if CHECK_LOCAL */ 97dns_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 */ 109static isc_logcategory_t categories[] = { { "", 0 }, 110 { "unmatched", 0 }, 111 { NULL, 0 } }; 112 113static isc_symtab_t *symtab = NULL; 114static isc_mem_t *sym_mctx; 115 116static void 117freekey(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 123static void 124add(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 150static bool 151logged(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 165static bool 166checkns(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 290checkaaaa: 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 324checkmissing: 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 383static bool 384checkmx(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 470static bool 471checksrv(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 557isc_result_t 558setup_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 */ 586static isc_result_t 587check_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 655cleanup: 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 */ 676isc_result_t 677load_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 746cleanup: 747 if (zone != NULL) { 748 dns_zone_detach(&zone); 749 } 750 return (result); 751} 752 753/*% dump the zone */ 754isc_result_t 755dump_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 795void 796InitSockets(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 810void 811DestroySockets(void) { 812 WSACleanup(); 813} 814#endif /* ifdef _WIN32 */ 815