check-tool.c revision 1.5
1/* $NetBSD: check-tool.c,v 1.5 2020/05/24 19:46:10 christos Exp $ */ 2 3/* 4 * Copyright (C) Internet Systems Consortium, Inc. ("ISC") 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 http://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 (/*CONSTCOND*/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 81static const char *dbtype[] = { "rbt" }; 82 83int debug = 0; 84const char *journal = NULL; 85bool nomerge = true; 86#if CHECK_LOCAL 87bool docheckmx = true; 88bool dochecksrv = true; 89bool docheckns = true; 90#else /* if CHECK_LOCAL */ 91bool docheckmx = false; 92bool dochecksrv = false; 93bool docheckns = false; 94#endif /* if CHECK_LOCAL */ 95dns_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 */ 107static isc_logcategory_t categories[] = { { "", 0 }, 108 { "unmatched", 0 }, 109 { NULL, 0 } }; 110 111static isc_symtab_t *symtab = NULL; 112static isc_mem_t *sym_mctx; 113 114static void 115freekey(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 121static void 122add(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 148static bool 149logged(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 163static bool 164checkns(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 287checkaaaa: 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 321checkmissing: 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 380static bool 381checkmx(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 466static bool 467checksrv(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 552isc_result_t 553setup_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 */ 581static isc_result_t 582check_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 650cleanup: 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 */ 671isc_result_t 672load_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_master); 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 741cleanup: 742 if (zone != NULL) { 743 dns_zone_detach(&zone); 744 } 745 return (result); 746} 747 748/*% dump the zone */ 749isc_result_t 750dump_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 790void 791InitSockets(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 805void 806DestroySockets(void) { 807 WSACleanup(); 808} 809#endif /* ifdef _WIN32 */ 810