1/* 2 * Copyright (C) 2004-2009, 2011-2014 Internet Systems Consortium, Inc. ("ISC") 3 * Copyright (C) 1999-2003 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$ */ 19 20/*! \file */ 21 22#include <config.h> 23 24#include <stdlib.h> 25 26#include <isc/event.h> 27#include <isc/file.h> 28#include <isc/magic.h> 29#include <isc/mem.h> 30#include <isc/print.h> 31#include <isc/stdio.h> 32#include <isc/string.h> 33#include <isc/task.h> 34#include <isc/time.h> 35#include <isc/util.h> 36 37#include <dns/db.h> 38#include <dns/dbiterator.h> 39#include <dns/events.h> 40#include <dns/fixedname.h> 41#include <dns/lib.h> 42#include <dns/log.h> 43#include <dns/master.h> 44#include <dns/masterdump.h> 45#include <dns/ncache.h> 46#include <dns/rdata.h> 47#include <dns/rdataclass.h> 48#include <dns/rdataset.h> 49#include <dns/rdatasetiter.h> 50#include <dns/rdatatype.h> 51#include <dns/result.h> 52#include <dns/time.h> 53#include <dns/ttl.h> 54 55#define DNS_DCTX_MAGIC ISC_MAGIC('D', 'c', 't', 'x') 56#define DNS_DCTX_VALID(d) ISC_MAGIC_VALID(d, DNS_DCTX_MAGIC) 57 58#define RETERR(x) do { \ 59 isc_result_t _r = (x); \ 60 if (_r != ISC_R_SUCCESS) \ 61 return (_r); \ 62 } while (0) 63 64#define CHECK(x) do { \ 65 if ((x) != ISC_R_SUCCESS) \ 66 goto cleanup; \ 67 } while (0) 68 69struct dns_master_style { 70 unsigned int flags; /* DNS_STYLEFLAG_* */ 71 unsigned int ttl_column; 72 unsigned int class_column; 73 unsigned int type_column; 74 unsigned int rdata_column; 75 unsigned int line_length; 76 unsigned int tab_width; 77 unsigned int split_width; 78}; 79 80/*% 81 * The maximum length of the newline+indentation that is output 82 * when inserting a line break in an RR. This effectively puts an 83 * upper limits on the value of "rdata_column", because if it is 84 * very large, the tabs and spaces needed to reach it will not fit. 85 */ 86#define DNS_TOTEXT_LINEBREAK_MAXLEN 100 87 88/*% 89 * Context structure for a masterfile dump in progress. 90 */ 91typedef struct dns_totext_ctx { 92 dns_master_style_t style; 93 isc_boolean_t class_printed; 94 char * linebreak; 95 char linebreak_buf[DNS_TOTEXT_LINEBREAK_MAXLEN]; 96 dns_name_t * origin; 97 dns_name_t * neworigin; 98 dns_fixedname_t origin_fixname; 99 isc_uint32_t current_ttl; 100 isc_boolean_t current_ttl_valid; 101} dns_totext_ctx_t; 102 103LIBDNS_EXTERNAL_DATA const dns_master_style_t 104dns_master_style_keyzone = { 105 DNS_STYLEFLAG_OMIT_OWNER | 106 DNS_STYLEFLAG_OMIT_CLASS | 107 DNS_STYLEFLAG_REL_OWNER | 108 DNS_STYLEFLAG_REL_DATA | 109 DNS_STYLEFLAG_OMIT_TTL | 110 DNS_STYLEFLAG_TTL | 111 DNS_STYLEFLAG_COMMENT | 112 DNS_STYLEFLAG_RRCOMMENT | 113 DNS_STYLEFLAG_MULTILINE | 114 DNS_STYLEFLAG_KEYDATA, 115 24, 24, 24, 32, 80, 8, UINT_MAX 116}; 117 118LIBDNS_EXTERNAL_DATA const dns_master_style_t 119dns_master_style_default = { 120 DNS_STYLEFLAG_OMIT_OWNER | 121 DNS_STYLEFLAG_OMIT_CLASS | 122 DNS_STYLEFLAG_REL_OWNER | 123 DNS_STYLEFLAG_REL_DATA | 124 DNS_STYLEFLAG_OMIT_TTL | 125 DNS_STYLEFLAG_TTL | 126 DNS_STYLEFLAG_COMMENT | 127 DNS_STYLEFLAG_RRCOMMENT | 128 DNS_STYLEFLAG_MULTILINE, 129 24, 24, 24, 32, 80, 8, UINT_MAX 130}; 131 132LIBDNS_EXTERNAL_DATA const dns_master_style_t 133dns_master_style_full = { 134 DNS_STYLEFLAG_COMMENT | 135 DNS_STYLEFLAG_RESIGN, 136 46, 46, 46, 64, 120, 8, UINT_MAX 137}; 138 139LIBDNS_EXTERNAL_DATA const dns_master_style_t 140dns_master_style_explicitttl = { 141 DNS_STYLEFLAG_OMIT_OWNER | 142 DNS_STYLEFLAG_OMIT_CLASS | 143 DNS_STYLEFLAG_REL_OWNER | 144 DNS_STYLEFLAG_REL_DATA | 145 DNS_STYLEFLAG_COMMENT | 146 DNS_STYLEFLAG_RRCOMMENT | 147 DNS_STYLEFLAG_MULTILINE, 148 24, 32, 32, 40, 80, 8, UINT_MAX 149}; 150 151LIBDNS_EXTERNAL_DATA const dns_master_style_t 152dns_master_style_cache = { 153 DNS_STYLEFLAG_OMIT_OWNER | 154 DNS_STYLEFLAG_OMIT_CLASS | 155 DNS_STYLEFLAG_MULTILINE | 156 DNS_STYLEFLAG_TRUST | 157 DNS_STYLEFLAG_NCACHE, 158 24, 32, 32, 40, 80, 8, UINT_MAX 159}; 160 161LIBDNS_EXTERNAL_DATA const dns_master_style_t 162dns_master_style_simple = { 163 0, 164 24, 32, 32, 40, 80, 8, UINT_MAX 165}; 166 167/*% 168 * A style suitable for dns_rdataset_totext(). 169 */ 170LIBDNS_EXTERNAL_DATA const dns_master_style_t 171dns_master_style_debug = { 172 DNS_STYLEFLAG_REL_OWNER, 173 24, 32, 40, 48, 80, 8, UINT_MAX 174}; 175 176 177#define N_SPACES 10 178static char spaces[N_SPACES+1] = " "; 179 180#define N_TABS 10 181static char tabs[N_TABS+1] = "\t\t\t\t\t\t\t\t\t\t"; 182 183#ifdef BIND9 184struct dns_dumpctx { 185 unsigned int magic; 186 isc_mem_t *mctx; 187 isc_mutex_t lock; 188 unsigned int references; 189 isc_boolean_t canceled; 190 isc_boolean_t first; 191 isc_boolean_t do_date; 192 isc_stdtime_t now; 193 FILE *f; 194 dns_db_t *db; 195 dns_dbversion_t *version; 196 dns_dbiterator_t *dbiter; 197 dns_totext_ctx_t tctx; 198 isc_task_t *task; 199 dns_dumpdonefunc_t done; 200 void *done_arg; 201 unsigned int nodes; 202 /* dns_master_dumpinc() */ 203 char *file; 204 char *tmpfile; 205 dns_masterformat_t format; 206 dns_masterrawheader_t header; 207 isc_result_t (*dumpsets)(isc_mem_t *mctx, dns_name_t *name, 208 dns_rdatasetiter_t *rdsiter, 209 dns_totext_ctx_t *ctx, 210 isc_buffer_t *buffer, FILE *f); 211}; 212#endif /* BIND9 */ 213 214#define NXDOMAIN(x) (((x)->attributes & DNS_RDATASETATTR_NXDOMAIN) != 0) 215 216/*% 217 * Output tabs and spaces to go from column '*current' to 218 * column 'to', and update '*current' to reflect the new 219 * current column. 220 */ 221static isc_result_t 222indent(unsigned int *current, unsigned int to, int tabwidth, 223 isc_buffer_t *target) 224{ 225 isc_region_t r; 226 unsigned char *p; 227 unsigned int from; 228 int ntabs, nspaces, t; 229 230 from = *current; 231 232 if (to < from + 1) 233 to = from + 1; 234 235 ntabs = to / tabwidth - from / tabwidth; 236 if (ntabs < 0) 237 ntabs = 0; 238 239 if (ntabs > 0) { 240 isc_buffer_availableregion(target, &r); 241 if (r.length < (unsigned) ntabs) 242 return (ISC_R_NOSPACE); 243 p = r.base; 244 245 t = ntabs; 246 while (t) { 247 int n = t; 248 if (n > N_TABS) 249 n = N_TABS; 250 memmove(p, tabs, n); 251 p += n; 252 t -= n; 253 } 254 isc_buffer_add(target, ntabs); 255 from = (to / tabwidth) * tabwidth; 256 } 257 258 nspaces = to - from; 259 INSIST(nspaces >= 0); 260 261 isc_buffer_availableregion(target, &r); 262 if (r.length < (unsigned) nspaces) 263 return (ISC_R_NOSPACE); 264 p = r.base; 265 266 t = nspaces; 267 while (t) { 268 int n = t; 269 if (n > N_SPACES) 270 n = N_SPACES; 271 memmove(p, spaces, n); 272 p += n; 273 t -= n; 274 } 275 isc_buffer_add(target, nspaces); 276 277 *current = to; 278 return (ISC_R_SUCCESS); 279} 280 281static isc_result_t 282totext_ctx_init(const dns_master_style_t *style, dns_totext_ctx_t *ctx) { 283 isc_result_t result; 284 285 REQUIRE(style->tab_width != 0); 286 287 ctx->style = *style; 288 ctx->class_printed = ISC_FALSE; 289 290 dns_fixedname_init(&ctx->origin_fixname); 291 292 /* 293 * Set up the line break string if needed. 294 */ 295 if ((ctx->style.flags & DNS_STYLEFLAG_MULTILINE) != 0) { 296 isc_buffer_t buf; 297 isc_region_t r; 298 unsigned int col = 0; 299 300 isc_buffer_init(&buf, ctx->linebreak_buf, 301 sizeof(ctx->linebreak_buf)); 302 303 isc_buffer_availableregion(&buf, &r); 304 if (r.length < 1) 305 return (DNS_R_TEXTTOOLONG); 306 r.base[0] = '\n'; 307 isc_buffer_add(&buf, 1); 308 309 result = indent(&col, ctx->style.rdata_column, 310 ctx->style.tab_width, &buf); 311 /* 312 * Do not return ISC_R_NOSPACE if the line break string 313 * buffer is too small, because that would just make 314 * dump_rdataset() retry indefinitely with ever 315 * bigger target buffers. That's a different buffer, 316 * so it won't help. Use DNS_R_TEXTTOOLONG as a substitute. 317 */ 318 if (result == ISC_R_NOSPACE) 319 return (DNS_R_TEXTTOOLONG); 320 if (result != ISC_R_SUCCESS) 321 return (result); 322 323 isc_buffer_availableregion(&buf, &r); 324 if (r.length < 1) 325 return (DNS_R_TEXTTOOLONG); 326 r.base[0] = '\0'; 327 isc_buffer_add(&buf, 1); 328 ctx->linebreak = ctx->linebreak_buf; 329 } else { 330 ctx->linebreak = NULL; 331 } 332 333 ctx->origin = NULL; 334 ctx->neworigin = NULL; 335 ctx->current_ttl = 0; 336 ctx->current_ttl_valid = ISC_FALSE; 337 338 return (ISC_R_SUCCESS); 339} 340 341#define INDENT_TO(col) \ 342 do { \ 343 if ((result = indent(&column, ctx->style.col, \ 344 ctx->style.tab_width, target)) \ 345 != ISC_R_SUCCESS) \ 346 return (result); \ 347 } while (0) 348 349 350static isc_result_t 351str_totext(const char *source, isc_buffer_t *target) { 352 unsigned int l; 353 isc_region_t region; 354 355 isc_buffer_availableregion(target, ®ion); 356 l = strlen(source); 357 358 if (l > region.length) 359 return (ISC_R_NOSPACE); 360 361 memmove(region.base, source, l); 362 isc_buffer_add(target, l); 363 return (ISC_R_SUCCESS); 364} 365 366static isc_result_t 367ncache_summary(dns_rdataset_t *rdataset, isc_boolean_t omit_final_dot, 368 isc_buffer_t *target) 369{ 370 isc_result_t result = ISC_R_SUCCESS; 371 dns_rdataset_t rds; 372 dns_name_t name; 373 374 dns_rdataset_init(&rds); 375 dns_name_init(&name, NULL); 376 377 do { 378 dns_ncache_current(rdataset, &name, &rds); 379 for (result = dns_rdataset_first(&rds); 380 result == ISC_R_SUCCESS; 381 result = dns_rdataset_next(&rds)) { 382 CHECK(str_totext("; ", target)); 383 CHECK(dns_name_totext(&name, omit_final_dot, target)); 384 CHECK(str_totext(" ", target)); 385 CHECK(dns_rdatatype_totext(rds.type, target)); 386 if (rds.type == dns_rdatatype_rrsig) { 387 CHECK(str_totext(" ", target)); 388 CHECK(dns_rdatatype_totext(rds.covers, target)); 389 CHECK(str_totext(" ...\n", target)); 390 } else { 391 dns_rdata_t rdata = DNS_RDATA_INIT; 392 dns_rdataset_current(&rds, &rdata); 393 CHECK(str_totext(" ", target)); 394 CHECK(dns_rdata_tofmttext(&rdata, dns_rootname, 395 0, 0, 0, " ", target)); 396 CHECK(str_totext("\n", target)); 397 } 398 } 399 dns_rdataset_disassociate(&rds); 400 result = dns_rdataset_next(rdataset); 401 } while (result == ISC_R_SUCCESS); 402 403 if (result == ISC_R_NOMORE) 404 result = ISC_R_SUCCESS; 405 cleanup: 406 if (dns_rdataset_isassociated(&rds)) 407 dns_rdataset_disassociate(&rds); 408 409 return (result); 410} 411 412/* 413 * Convert 'rdataset' to master file text format according to 'ctx', 414 * storing the result in 'target'. If 'owner_name' is NULL, it 415 * is omitted; otherwise 'owner_name' must be valid and have at least 416 * one label. 417 */ 418 419static isc_result_t 420rdataset_totext(dns_rdataset_t *rdataset, 421 dns_name_t *owner_name, 422 dns_totext_ctx_t *ctx, 423 isc_boolean_t omit_final_dot, 424 isc_buffer_t *target) 425{ 426 isc_result_t result; 427 unsigned int column; 428 isc_boolean_t first = ISC_TRUE; 429 isc_uint32_t current_ttl; 430 isc_boolean_t current_ttl_valid; 431 dns_rdatatype_t type; 432 unsigned int type_start; 433 434 REQUIRE(DNS_RDATASET_VALID(rdataset)); 435 436 rdataset->attributes |= DNS_RDATASETATTR_LOADORDER; 437 result = dns_rdataset_first(rdataset); 438 439 current_ttl = ctx->current_ttl; 440 current_ttl_valid = ctx->current_ttl_valid; 441 442 while (result == ISC_R_SUCCESS) { 443 column = 0; 444 445 /* 446 * Owner name. 447 */ 448 if (owner_name != NULL && 449 ! ((ctx->style.flags & DNS_STYLEFLAG_OMIT_OWNER) != 0 && 450 !first)) 451 { 452 unsigned int name_start = target->used; 453 RETERR(dns_name_totext(owner_name, 454 omit_final_dot, 455 target)); 456 column += target->used - name_start; 457 } 458 459 /* 460 * TTL. 461 */ 462 if ((ctx->style.flags & DNS_STYLEFLAG_NO_TTL) == 0 && 463 !((ctx->style.flags & DNS_STYLEFLAG_OMIT_TTL) != 0 && 464 current_ttl_valid && 465 rdataset->ttl == current_ttl)) 466 { 467 char ttlbuf[64]; 468 isc_region_t r; 469 unsigned int length; 470 471 INDENT_TO(ttl_column); 472 length = snprintf(ttlbuf, sizeof(ttlbuf), "%u", 473 rdataset->ttl); 474 INSIST(length <= sizeof(ttlbuf)); 475 isc_buffer_availableregion(target, &r); 476 if (r.length < length) 477 return (ISC_R_NOSPACE); 478 memmove(r.base, ttlbuf, length); 479 isc_buffer_add(target, length); 480 column += length; 481 482 /* 483 * If the $TTL directive is not in use, the TTL we 484 * just printed becomes the default for subsequent RRs. 485 */ 486 if ((ctx->style.flags & DNS_STYLEFLAG_TTL) == 0) { 487 current_ttl = rdataset->ttl; 488 current_ttl_valid = ISC_TRUE; 489 } 490 } 491 492 /* 493 * Class. 494 */ 495 if ((ctx->style.flags & DNS_STYLEFLAG_NO_CLASS) == 0 && 496 ((ctx->style.flags & DNS_STYLEFLAG_OMIT_CLASS) == 0 || 497 ctx->class_printed == ISC_FALSE)) 498 { 499 unsigned int class_start; 500 INDENT_TO(class_column); 501 class_start = target->used; 502 result = dns_rdataclass_totext(rdataset->rdclass, 503 target); 504 if (result != ISC_R_SUCCESS) 505 return (result); 506 column += (target->used - class_start); 507 } 508 509 /* 510 * Type. 511 */ 512 513 if ((rdataset->attributes & DNS_RDATASETATTR_NEGATIVE) != 0) { 514 type = rdataset->covers; 515 } else { 516 type = rdataset->type; 517 } 518 519 INDENT_TO(type_column); 520 type_start = target->used; 521 if ((rdataset->attributes & DNS_RDATASETATTR_NEGATIVE) != 0) 522 RETERR(str_totext("\\-", target)); 523 switch (type) { 524 case dns_rdatatype_keydata: 525#define KEYDATA "KEYDATA" 526 if ((ctx->style.flags & DNS_STYLEFLAG_KEYDATA) != 0) { 527 if (isc_buffer_availablelength(target) < 528 (sizeof(KEYDATA) - 1)) 529 return (ISC_R_NOSPACE); 530 isc_buffer_putstr(target, KEYDATA); 531 break; 532 } 533 /* FALLTHROUGH */ 534 default: 535 result = dns_rdatatype_totext(type, target); 536 if (result != ISC_R_SUCCESS) 537 return (result); 538 } 539 column += (target->used - type_start); 540 541 /* 542 * Rdata. 543 */ 544 INDENT_TO(rdata_column); 545 if ((rdataset->attributes & DNS_RDATASETATTR_NEGATIVE) != 0) { 546 if (NXDOMAIN(rdataset)) 547 RETERR(str_totext(";-$NXDOMAIN\n", target)); 548 else 549 RETERR(str_totext(";-$NXRRSET\n", target)); 550 /* 551 * Print a summary of the cached records which make 552 * up the negative response. 553 */ 554 RETERR(ncache_summary(rdataset, omit_final_dot, 555 target)); 556 break; 557 } else { 558 dns_rdata_t rdata = DNS_RDATA_INIT; 559 isc_region_t r; 560 561 dns_rdataset_current(rdataset, &rdata); 562 563 RETERR(dns_rdata_tofmttext(&rdata, 564 ctx->origin, 565 ctx->style.flags, 566 ctx->style.line_length - 567 ctx->style.rdata_column, 568 ctx->style.split_width, 569 ctx->linebreak, 570 target)); 571 572 isc_buffer_availableregion(target, &r); 573 if (r.length < 1) 574 return (ISC_R_NOSPACE); 575 r.base[0] = '\n'; 576 isc_buffer_add(target, 1); 577 } 578 579 first = ISC_FALSE; 580 result = dns_rdataset_next(rdataset); 581 } 582 583 if (result != ISC_R_NOMORE) 584 return (result); 585 586 /* 587 * Update the ctx state to reflect what we just printed. 588 * This is done last, only when we are sure we will return 589 * success, because this function may be called multiple 590 * times with increasing buffer sizes until it succeeds, 591 * and failed attempts must not update the state prematurely. 592 */ 593 ctx->class_printed = ISC_TRUE; 594 ctx->current_ttl= current_ttl; 595 ctx->current_ttl_valid = current_ttl_valid; 596 597 return (ISC_R_SUCCESS); 598} 599 600/* 601 * Print the name, type, and class of an empty rdataset, 602 * such as those used to represent the question section 603 * of a DNS message. 604 */ 605static isc_result_t 606question_totext(dns_rdataset_t *rdataset, 607 dns_name_t *owner_name, 608 dns_totext_ctx_t *ctx, 609 isc_boolean_t omit_final_dot, 610 isc_buffer_t *target) 611{ 612 unsigned int column; 613 isc_result_t result; 614 isc_region_t r; 615 616 REQUIRE(DNS_RDATASET_VALID(rdataset)); 617 result = dns_rdataset_first(rdataset); 618 REQUIRE(result == ISC_R_NOMORE); 619 620 column = 0; 621 622 /* Owner name */ 623 { 624 unsigned int name_start = target->used; 625 RETERR(dns_name_totext(owner_name, 626 omit_final_dot, 627 target)); 628 column += target->used - name_start; 629 } 630 631 /* Class */ 632 { 633 unsigned int class_start; 634 INDENT_TO(class_column); 635 class_start = target->used; 636 result = dns_rdataclass_totext(rdataset->rdclass, target); 637 if (result != ISC_R_SUCCESS) 638 return (result); 639 column += (target->used - class_start); 640 } 641 642 /* Type */ 643 { 644 unsigned int type_start; 645 INDENT_TO(type_column); 646 type_start = target->used; 647 result = dns_rdatatype_totext(rdataset->type, target); 648 if (result != ISC_R_SUCCESS) 649 return (result); 650 column += (target->used - type_start); 651 } 652 653 isc_buffer_availableregion(target, &r); 654 if (r.length < 1) 655 return (ISC_R_NOSPACE); 656 r.base[0] = '\n'; 657 isc_buffer_add(target, 1); 658 659 return (ISC_R_SUCCESS); 660} 661 662isc_result_t 663dns_rdataset_totext(dns_rdataset_t *rdataset, 664 dns_name_t *owner_name, 665 isc_boolean_t omit_final_dot, 666 isc_boolean_t question, 667 isc_buffer_t *target) 668{ 669 dns_totext_ctx_t ctx; 670 isc_result_t result; 671 result = totext_ctx_init(&dns_master_style_debug, &ctx); 672 if (result != ISC_R_SUCCESS) { 673 UNEXPECTED_ERROR(__FILE__, __LINE__, 674 "could not set master file style"); 675 return (ISC_R_UNEXPECTED); 676 } 677 678 /* 679 * The caller might want to give us an empty owner 680 * name (e.g. if they are outputting into a master 681 * file and this rdataset has the same name as the 682 * previous one.) 683 */ 684 if (dns_name_countlabels(owner_name) == 0) 685 owner_name = NULL; 686 687 if (question) 688 return (question_totext(rdataset, owner_name, &ctx, 689 omit_final_dot, target)); 690 else 691 return (rdataset_totext(rdataset, owner_name, &ctx, 692 omit_final_dot, target)); 693} 694 695isc_result_t 696dns_master_rdatasettotext(dns_name_t *owner_name, 697 dns_rdataset_t *rdataset, 698 const dns_master_style_t *style, 699 isc_buffer_t *target) 700{ 701 dns_totext_ctx_t ctx; 702 isc_result_t result; 703 result = totext_ctx_init(style, &ctx); 704 if (result != ISC_R_SUCCESS) { 705 UNEXPECTED_ERROR(__FILE__, __LINE__, 706 "could not set master file style"); 707 return (ISC_R_UNEXPECTED); 708 } 709 710 return (rdataset_totext(rdataset, owner_name, &ctx, 711 ISC_FALSE, target)); 712} 713 714isc_result_t 715dns_master_questiontotext(dns_name_t *owner_name, 716 dns_rdataset_t *rdataset, 717 const dns_master_style_t *style, 718 isc_buffer_t *target) 719{ 720 dns_totext_ctx_t ctx; 721 isc_result_t result; 722 result = totext_ctx_init(style, &ctx); 723 if (result != ISC_R_SUCCESS) { 724 UNEXPECTED_ERROR(__FILE__, __LINE__, 725 "could not set master file style"); 726 return (ISC_R_UNEXPECTED); 727 } 728 729 return (question_totext(rdataset, owner_name, &ctx, 730 ISC_FALSE, target)); 731} 732 733#ifdef BIND9 734/* 735 * Print an rdataset. 'buffer' is a scratch buffer, which must have been 736 * dynamically allocated by the caller. It must be large enough to 737 * hold the result from dns_ttl_totext(). If more than that is needed, 738 * the buffer will be grown automatically. 739 */ 740 741static isc_result_t 742dump_rdataset(isc_mem_t *mctx, dns_name_t *name, dns_rdataset_t *rdataset, 743 dns_totext_ctx_t *ctx, 744 isc_buffer_t *buffer, FILE *f) 745{ 746 isc_region_t r; 747 isc_result_t result; 748 749 REQUIRE(buffer->length > 0); 750 751 /* 752 * Output a $TTL directive if needed. 753 */ 754 755 if ((ctx->style.flags & DNS_STYLEFLAG_TTL) != 0) { 756 if (ctx->current_ttl_valid == ISC_FALSE || 757 ctx->current_ttl != rdataset->ttl) 758 { 759 if ((ctx->style.flags & DNS_STYLEFLAG_COMMENT) != 0) 760 { 761 isc_buffer_clear(buffer); 762 result = dns_ttl_totext(rdataset->ttl, 763 ISC_TRUE, buffer); 764 INSIST(result == ISC_R_SUCCESS); 765 isc_buffer_usedregion(buffer, &r); 766 fprintf(f, "$TTL %u\t; %.*s\n", rdataset->ttl, 767 (int) r.length, (char *) r.base); 768 } else { 769 fprintf(f, "$TTL %u\n", rdataset->ttl); 770 } 771 ctx->current_ttl = rdataset->ttl; 772 ctx->current_ttl_valid = ISC_TRUE; 773 } 774 } 775 776 isc_buffer_clear(buffer); 777 778 /* 779 * Generate the text representation of the rdataset into 780 * the buffer. If the buffer is too small, grow it. 781 */ 782 for (;;) { 783 int newlength; 784 void *newmem; 785 result = rdataset_totext(rdataset, name, ctx, 786 ISC_FALSE, buffer); 787 if (result != ISC_R_NOSPACE) 788 break; 789 790 newlength = buffer->length * 2; 791 newmem = isc_mem_get(mctx, newlength); 792 if (newmem == NULL) 793 return (ISC_R_NOMEMORY); 794 isc_mem_put(mctx, buffer->base, buffer->length); 795 isc_buffer_init(buffer, newmem, newlength); 796 } 797 if (result != ISC_R_SUCCESS) 798 return (result); 799 800 /* 801 * Write the buffer contents to the master file. 802 */ 803 isc_buffer_usedregion(buffer, &r); 804 result = isc_stdio_write(r.base, 1, (size_t)r.length, f, NULL); 805 806 if (result != ISC_R_SUCCESS) { 807 UNEXPECTED_ERROR(__FILE__, __LINE__, 808 "master file write failed: %s", 809 isc_result_totext(result)); 810 return (result); 811 } 812 813 return (ISC_R_SUCCESS); 814} 815 816/* 817 * Define the order in which rdatasets should be printed in zone 818 * files. We will print SOA and NS records before others, SIGs 819 * immediately following the things they sign, and order everything 820 * else by RR number. This is all just for aesthetics and 821 * compatibility with buggy software that expects the SOA to be first; 822 * the DNS specifications allow any order. 823 */ 824 825static int 826dump_order(const dns_rdataset_t *rds) { 827 int t; 828 int sig; 829 if (rds->type == dns_rdatatype_rrsig) { 830 t = rds->covers; 831 sig = 1; 832 } else { 833 t = rds->type; 834 sig = 0; 835 } 836 switch (t) { 837 case dns_rdatatype_soa: 838 t = 0; 839 break; 840 case dns_rdatatype_ns: 841 t = 1; 842 break; 843 default: 844 t += 2; 845 break; 846 } 847 return (t << 1) + sig; 848} 849 850static int 851dump_order_compare(const void *a, const void *b) { 852 return (dump_order(*((const dns_rdataset_t * const *) a)) - 853 dump_order(*((const dns_rdataset_t * const *) b))); 854} 855 856/* 857 * Dump all the rdatasets of a domain name to a master file. We make 858 * a "best effort" attempt to sort the RRsets in a nice order, but if 859 * there are more than MAXSORT RRsets, we punt and only sort them in 860 * groups of MAXSORT. This is not expected to ever happen in practice 861 * since much less than 64 RR types have been registered with the 862 * IANA, so far, and the output will be correct (though not 863 * aesthetically pleasing) even if it does happen. 864 */ 865 866#define MAXSORT 64 867 868static isc_result_t 869dump_rdatasets_text(isc_mem_t *mctx, dns_name_t *name, 870 dns_rdatasetiter_t *rdsiter, dns_totext_ctx_t *ctx, 871 isc_buffer_t *buffer, FILE *f) 872{ 873 isc_result_t itresult, dumpresult; 874 isc_region_t r; 875 dns_rdataset_t rdatasets[MAXSORT]; 876 dns_rdataset_t *sorted[MAXSORT]; 877 int i, n; 878 879 itresult = dns_rdatasetiter_first(rdsiter); 880 dumpresult = ISC_R_SUCCESS; 881 882 if (itresult == ISC_R_SUCCESS && ctx->neworigin != NULL) { 883 isc_buffer_clear(buffer); 884 itresult = dns_name_totext(ctx->neworigin, ISC_FALSE, buffer); 885 RUNTIME_CHECK(itresult == ISC_R_SUCCESS); 886 isc_buffer_usedregion(buffer, &r); 887 fprintf(f, "$ORIGIN %.*s\n", (int) r.length, (char *) r.base); 888 ctx->neworigin = NULL; 889 } 890 891 again: 892 for (i = 0; 893 itresult == ISC_R_SUCCESS && i < MAXSORT; 894 itresult = dns_rdatasetiter_next(rdsiter), i++) { 895 dns_rdataset_init(&rdatasets[i]); 896 dns_rdatasetiter_current(rdsiter, &rdatasets[i]); 897 sorted[i] = &rdatasets[i]; 898 } 899 n = i; 900 INSIST(n <= MAXSORT); 901 902 qsort(sorted, n, sizeof(sorted[0]), dump_order_compare); 903 904 for (i = 0; i < n; i++) { 905 dns_rdataset_t *rds = sorted[i]; 906 if (ctx->style.flags & DNS_STYLEFLAG_TRUST) 907 fprintf(f, "; %s\n", dns_trust_totext(rds->trust)); 908 if (((rds->attributes & DNS_RDATASETATTR_NEGATIVE) != 0) && 909 (ctx->style.flags & DNS_STYLEFLAG_NCACHE) == 0) { 910 /* Omit negative cache entries */ 911 } else { 912 isc_result_t result = 913 dump_rdataset(mctx, name, rds, ctx, 914 buffer, f); 915 if (result != ISC_R_SUCCESS) 916 dumpresult = result; 917 if ((ctx->style.flags & DNS_STYLEFLAG_OMIT_OWNER) != 0) 918 name = NULL; 919 } 920 if (ctx->style.flags & DNS_STYLEFLAG_RESIGN && 921 rds->attributes & DNS_RDATASETATTR_RESIGN) { 922 isc_buffer_t b; 923 char buf[sizeof("YYYYMMDDHHMMSS")]; 924 memset(buf, 0, sizeof(buf)); 925 isc_buffer_init(&b, buf, sizeof(buf) - 1); 926 dns_time64_totext((isc_uint64_t)rds->resign, &b); 927 fprintf(f, "; resign=%s\n", buf); 928 } 929 dns_rdataset_disassociate(rds); 930 } 931 932 if (dumpresult != ISC_R_SUCCESS) 933 return (dumpresult); 934 935 /* 936 * If we got more data than could be sorted at once, 937 * go handle the rest. 938 */ 939 if (itresult == ISC_R_SUCCESS) 940 goto again; 941 942 if (itresult == ISC_R_NOMORE) 943 itresult = ISC_R_SUCCESS; 944 945 return (itresult); 946} 947 948/* 949 * Dump given RRsets in the "raw" format. 950 */ 951static isc_result_t 952dump_rdataset_raw(isc_mem_t *mctx, dns_name_t *name, dns_rdataset_t *rdataset, 953 isc_buffer_t *buffer, FILE *f) 954{ 955 isc_result_t result; 956 isc_uint32_t totallen; 957 isc_uint16_t dlen; 958 isc_region_t r, r_hdr; 959 960 REQUIRE(buffer->length > 0); 961 REQUIRE(DNS_RDATASET_VALID(rdataset)); 962 963 rdataset->attributes |= DNS_RDATASETATTR_LOADORDER; 964 restart: 965 totallen = 0; 966 result = dns_rdataset_first(rdataset); 967 REQUIRE(result == ISC_R_SUCCESS); 968 969 isc_buffer_clear(buffer); 970 971 /* 972 * Common header and owner name (length followed by name) 973 * These fields should be in a moderate length, so we assume we 974 * can store all of them in the initial buffer. 975 */ 976 isc_buffer_availableregion(buffer, &r_hdr); 977 INSIST(r_hdr.length >= sizeof(dns_masterrawrdataset_t)); 978 isc_buffer_putuint32(buffer, totallen); /* XXX: leave space */ 979 isc_buffer_putuint16(buffer, rdataset->rdclass); /* 16-bit class */ 980 isc_buffer_putuint16(buffer, rdataset->type); /* 16-bit type */ 981 isc_buffer_putuint16(buffer, rdataset->covers); /* same as type */ 982 isc_buffer_putuint32(buffer, rdataset->ttl); /* 32-bit TTL */ 983 isc_buffer_putuint32(buffer, dns_rdataset_count(rdataset)); 984 totallen = isc_buffer_usedlength(buffer); 985 INSIST(totallen <= sizeof(dns_masterrawrdataset_t)); 986 987 dns_name_toregion(name, &r); 988 INSIST(isc_buffer_availablelength(buffer) >= 989 (sizeof(dlen) + r.length)); 990 dlen = (isc_uint16_t)r.length; 991 isc_buffer_putuint16(buffer, dlen); 992 isc_buffer_copyregion(buffer, &r); 993 totallen += sizeof(dlen) + r.length; 994 995 do { 996 dns_rdata_t rdata = DNS_RDATA_INIT; 997 isc_region_t r; 998 999 dns_rdataset_current(rdataset, &rdata); 1000 dns_rdata_toregion(&rdata, &r); 1001 INSIST(r.length <= 0xffffU); 1002 dlen = (isc_uint16_t)r.length; 1003 1004 /* 1005 * Copy the rdata into the buffer. If the buffer is too small, 1006 * grow it. This should be rare, so we'll simply restart the 1007 * entire procedure (or should we copy the old data and 1008 * continue?). 1009 */ 1010 if (isc_buffer_availablelength(buffer) < 1011 sizeof(dlen) + r.length) { 1012 int newlength; 1013 void *newmem; 1014 1015 newlength = buffer->length * 2; 1016 newmem = isc_mem_get(mctx, newlength); 1017 if (newmem == NULL) 1018 return (ISC_R_NOMEMORY); 1019 isc_mem_put(mctx, buffer->base, buffer->length); 1020 isc_buffer_init(buffer, newmem, newlength); 1021 goto restart; 1022 } 1023 isc_buffer_putuint16(buffer, dlen); 1024 isc_buffer_copyregion(buffer, &r); 1025 totallen += sizeof(dlen) + r.length; 1026 1027 result = dns_rdataset_next(rdataset); 1028 } while (result == ISC_R_SUCCESS); 1029 1030 if (result != ISC_R_NOMORE) 1031 return (result); 1032 1033 /* 1034 * Fill in the total length field. 1035 * XXX: this is a bit tricky. Since we have already "used" the space 1036 * for the total length in the buffer, we first remember the entire 1037 * buffer length in the region, "rewind", and then write the value. 1038 */ 1039 isc_buffer_usedregion(buffer, &r); 1040 isc_buffer_clear(buffer); 1041 isc_buffer_putuint32(buffer, totallen); 1042 INSIST(isc_buffer_usedlength(buffer) < totallen); 1043 1044 /* 1045 * Write the buffer contents to the raw master file. 1046 */ 1047 result = isc_stdio_write(r.base, 1, (size_t)r.length, f, NULL); 1048 1049 if (result != ISC_R_SUCCESS) { 1050 UNEXPECTED_ERROR(__FILE__, __LINE__, 1051 "raw master file write failed: %s", 1052 isc_result_totext(result)); 1053 return (result); 1054 } 1055 1056 return (result); 1057} 1058 1059static isc_result_t 1060dump_rdatasets_raw(isc_mem_t *mctx, dns_name_t *name, 1061 dns_rdatasetiter_t *rdsiter, dns_totext_ctx_t *ctx, 1062 isc_buffer_t *buffer, FILE *f) 1063{ 1064 isc_result_t result; 1065 dns_rdataset_t rdataset; 1066 1067 for (result = dns_rdatasetiter_first(rdsiter); 1068 result == ISC_R_SUCCESS; 1069 result = dns_rdatasetiter_next(rdsiter)) { 1070 1071 dns_rdataset_init(&rdataset); 1072 dns_rdatasetiter_current(rdsiter, &rdataset); 1073 1074 if (((rdataset.attributes & DNS_RDATASETATTR_NEGATIVE) != 0) && 1075 (ctx->style.flags & DNS_STYLEFLAG_NCACHE) == 0) { 1076 /* Omit negative cache entries */ 1077 } else { 1078 result = dump_rdataset_raw(mctx, name, &rdataset, 1079 buffer, f); 1080 } 1081 dns_rdataset_disassociate(&rdataset); 1082 if (result != ISC_R_SUCCESS) 1083 return (result); 1084 } 1085 1086 if (result == ISC_R_NOMORE) 1087 result = ISC_R_SUCCESS; 1088 1089 return (result); 1090} 1091 1092/* 1093 * Initial size of text conversion buffer. The buffer is used 1094 * for several purposes: converting origin names, rdatasets, 1095 * $DATE timestamps, and comment strings for $TTL directives. 1096 * 1097 * When converting rdatasets, it is dynamically resized, but 1098 * when converting origins, timestamps, etc it is not. Therefore, 1099 * the initial size must large enough to hold the longest possible 1100 * text representation of any domain name (for $ORIGIN). 1101 */ 1102static const int initial_buffer_length = 1200; 1103 1104static isc_result_t 1105dumptostreaminc(dns_dumpctx_t *dctx); 1106 1107static void 1108dumpctx_destroy(dns_dumpctx_t *dctx) { 1109 1110 dctx->magic = 0; 1111 DESTROYLOCK(&dctx->lock); 1112 dns_dbiterator_destroy(&dctx->dbiter); 1113 if (dctx->version != NULL) 1114 dns_db_closeversion(dctx->db, &dctx->version, ISC_FALSE); 1115 dns_db_detach(&dctx->db); 1116 if (dctx->task != NULL) 1117 isc_task_detach(&dctx->task); 1118 if (dctx->file != NULL) 1119 isc_mem_free(dctx->mctx, dctx->file); 1120 if (dctx->tmpfile != NULL) 1121 isc_mem_free(dctx->mctx, dctx->tmpfile); 1122 isc_mem_putanddetach(&dctx->mctx, dctx, sizeof(*dctx)); 1123} 1124 1125void 1126dns_dumpctx_attach(dns_dumpctx_t *source, dns_dumpctx_t **target) { 1127 1128 REQUIRE(DNS_DCTX_VALID(source)); 1129 REQUIRE(target != NULL && *target == NULL); 1130 1131 LOCK(&source->lock); 1132 INSIST(source->references > 0); 1133 source->references++; 1134 INSIST(source->references != 0); /* Overflow? */ 1135 UNLOCK(&source->lock); 1136 1137 *target = source; 1138} 1139 1140void 1141dns_dumpctx_detach(dns_dumpctx_t **dctxp) { 1142 dns_dumpctx_t *dctx; 1143 isc_boolean_t need_destroy = ISC_FALSE; 1144 1145 REQUIRE(dctxp != NULL); 1146 dctx = *dctxp; 1147 REQUIRE(DNS_DCTX_VALID(dctx)); 1148 1149 *dctxp = NULL; 1150 1151 LOCK(&dctx->lock); 1152 INSIST(dctx->references != 0); 1153 dctx->references--; 1154 if (dctx->references == 0) 1155 need_destroy = ISC_TRUE; 1156 UNLOCK(&dctx->lock); 1157 if (need_destroy) 1158 dumpctx_destroy(dctx); 1159} 1160 1161dns_dbversion_t * 1162dns_dumpctx_version(dns_dumpctx_t *dctx) { 1163 REQUIRE(DNS_DCTX_VALID(dctx)); 1164 return (dctx->version); 1165} 1166 1167dns_db_t * 1168dns_dumpctx_db(dns_dumpctx_t *dctx) { 1169 REQUIRE(DNS_DCTX_VALID(dctx)); 1170 return (dctx->db); 1171} 1172 1173void 1174dns_dumpctx_cancel(dns_dumpctx_t *dctx) { 1175 REQUIRE(DNS_DCTX_VALID(dctx)); 1176 1177 LOCK(&dctx->lock); 1178 dctx->canceled = ISC_TRUE; 1179 UNLOCK(&dctx->lock); 1180} 1181 1182static isc_result_t 1183flushandsync(FILE *f, isc_result_t result, const char *temp) { 1184 isc_boolean_t logit = ISC_TF(result == ISC_R_SUCCESS); 1185 1186 if (result == ISC_R_SUCCESS) 1187 result = isc_stdio_flush(f); 1188 if (result != ISC_R_SUCCESS && logit) { 1189 if (temp != NULL) 1190 isc_log_write(dns_lctx, ISC_LOGCATEGORY_GENERAL, 1191 DNS_LOGMODULE_MASTERDUMP, ISC_LOG_ERROR, 1192 "dumping to master file: %s: flush: %s", 1193 temp, isc_result_totext(result)); 1194 else 1195 isc_log_write(dns_lctx, ISC_LOGCATEGORY_GENERAL, 1196 DNS_LOGMODULE_MASTERDUMP, ISC_LOG_ERROR, 1197 "dumping to stream: flush: %s", 1198 isc_result_totext(result)); 1199 logit = ISC_FALSE; 1200 } 1201 1202 if (result == ISC_R_SUCCESS) 1203 result = isc_stdio_sync(f); 1204 if (result != ISC_R_SUCCESS && logit) { 1205 if (temp != NULL) 1206 isc_log_write(dns_lctx, ISC_LOGCATEGORY_GENERAL, 1207 DNS_LOGMODULE_MASTERDUMP, ISC_LOG_ERROR, 1208 "dumping to master file: %s: fsync: %s", 1209 temp, isc_result_totext(result)); 1210 else 1211 isc_log_write(dns_lctx, ISC_LOGCATEGORY_GENERAL, 1212 DNS_LOGMODULE_MASTERDUMP, ISC_LOG_ERROR, 1213 "dumping to stream: fsync: %s", 1214 isc_result_totext(result)); 1215 } 1216 return (result); 1217} 1218 1219static isc_result_t 1220closeandrename(FILE *f, isc_result_t result, const char *temp, const char *file) 1221{ 1222 isc_result_t tresult; 1223 isc_boolean_t logit = ISC_TF(result == ISC_R_SUCCESS); 1224 1225 result = flushandsync(f, result, temp); 1226 if (result != ISC_R_SUCCESS) 1227 logit = ISC_FALSE; 1228 1229 tresult = isc_stdio_close(f); 1230 if (result == ISC_R_SUCCESS) 1231 result = tresult; 1232 if (result != ISC_R_SUCCESS && logit) { 1233 isc_log_write(dns_lctx, ISC_LOGCATEGORY_GENERAL, 1234 DNS_LOGMODULE_MASTERDUMP, ISC_LOG_ERROR, 1235 "dumping master file: %s: fclose: %s", 1236 temp, isc_result_totext(result)); 1237 logit = ISC_FALSE; 1238 } 1239 if (result == ISC_R_SUCCESS) 1240 result = isc_file_rename(temp, file); 1241 else 1242 (void)isc_file_remove(temp); 1243 if (result != ISC_R_SUCCESS && logit) { 1244 isc_log_write(dns_lctx, ISC_LOGCATEGORY_GENERAL, 1245 DNS_LOGMODULE_MASTERDUMP, ISC_LOG_ERROR, 1246 "dumping master file: rename: %s: %s", 1247 file, isc_result_totext(result)); 1248 } 1249 return (result); 1250} 1251 1252static void 1253dump_quantum(isc_task_t *task, isc_event_t *event) { 1254 isc_result_t result; 1255 isc_result_t tresult; 1256 dns_dumpctx_t *dctx; 1257 1258 REQUIRE(event != NULL); 1259 dctx = event->ev_arg; 1260 REQUIRE(DNS_DCTX_VALID(dctx)); 1261 if (dctx->canceled) 1262 result = ISC_R_CANCELED; 1263 else 1264 result = dumptostreaminc(dctx); 1265 if (result == DNS_R_CONTINUE) { 1266 event->ev_arg = dctx; 1267 isc_task_send(task, &event); 1268 return; 1269 } 1270 1271 if (dctx->file != NULL) { 1272 tresult = closeandrename(dctx->f, result, 1273 dctx->tmpfile, dctx->file); 1274 if (tresult != ISC_R_SUCCESS && result == ISC_R_SUCCESS) 1275 result = tresult; 1276 } else 1277 result = flushandsync(dctx->f, result, NULL); 1278 (dctx->done)(dctx->done_arg, result); 1279 isc_event_free(&event); 1280 dns_dumpctx_detach(&dctx); 1281} 1282 1283static isc_result_t 1284task_send(dns_dumpctx_t *dctx) { 1285 isc_event_t *event; 1286 1287 event = isc_event_allocate(dctx->mctx, NULL, DNS_EVENT_DUMPQUANTUM, 1288 dump_quantum, dctx, sizeof(*event)); 1289 if (event == NULL) 1290 return (ISC_R_NOMEMORY); 1291 isc_task_send(dctx->task, &event); 1292 return (ISC_R_SUCCESS); 1293} 1294 1295static isc_result_t 1296dumpctx_create(isc_mem_t *mctx, dns_db_t *db, dns_dbversion_t *version, 1297 const dns_master_style_t *style, FILE *f, dns_dumpctx_t **dctxp, 1298 dns_masterformat_t format, dns_masterrawheader_t *header) 1299{ 1300 dns_dumpctx_t *dctx; 1301 isc_result_t result; 1302 unsigned int options; 1303 1304 dctx = isc_mem_get(mctx, sizeof(*dctx)); 1305 if (dctx == NULL) 1306 return (ISC_R_NOMEMORY); 1307 1308 dctx->mctx = NULL; 1309 dctx->f = f; 1310 dctx->dbiter = NULL; 1311 dctx->db = NULL; 1312 dctx->version = NULL; 1313 dctx->done = NULL; 1314 dctx->done_arg = NULL; 1315 dctx->task = NULL; 1316 dctx->nodes = 0; 1317 dctx->first = ISC_TRUE; 1318 dctx->canceled = ISC_FALSE; 1319 dctx->file = NULL; 1320 dctx->tmpfile = NULL; 1321 dctx->format = format; 1322 if (header == NULL) 1323 dns_master_initrawheader(&dctx->header); 1324 else 1325 dctx->header = *header; 1326 1327 switch (format) { 1328 case dns_masterformat_text: 1329 dctx->dumpsets = dump_rdatasets_text; 1330 break; 1331 case dns_masterformat_raw: 1332 dctx->dumpsets = dump_rdatasets_raw; 1333 break; 1334 default: 1335 INSIST(0); 1336 break; 1337 } 1338 1339 result = totext_ctx_init(style, &dctx->tctx); 1340 if (result != ISC_R_SUCCESS) { 1341 UNEXPECTED_ERROR(__FILE__, __LINE__, 1342 "could not set master file style"); 1343 goto cleanup; 1344 } 1345 1346 isc_stdtime_get(&dctx->now); 1347 dns_db_attach(db, &dctx->db); 1348 1349 dctx->do_date = dns_db_iscache(dctx->db); 1350 1351 if (dctx->format == dns_masterformat_text && 1352 (dctx->tctx.style.flags & DNS_STYLEFLAG_REL_OWNER) != 0) { 1353 options = DNS_DB_RELATIVENAMES; 1354 } else 1355 options = 0; 1356 result = dns_db_createiterator(dctx->db, options, &dctx->dbiter); 1357 if (result != ISC_R_SUCCESS) 1358 goto cleanup; 1359 1360 result = isc_mutex_init(&dctx->lock); 1361 if (result != ISC_R_SUCCESS) 1362 goto cleanup; 1363 if (version != NULL) 1364 dns_db_attachversion(dctx->db, version, &dctx->version); 1365 else if (!dns_db_iscache(db)) 1366 dns_db_currentversion(dctx->db, &dctx->version); 1367 isc_mem_attach(mctx, &dctx->mctx); 1368 dctx->references = 1; 1369 dctx->magic = DNS_DCTX_MAGIC; 1370 *dctxp = dctx; 1371 return (ISC_R_SUCCESS); 1372 1373 cleanup: 1374 if (dctx->dbiter != NULL) 1375 dns_dbiterator_destroy(&dctx->dbiter); 1376 if (dctx->db != NULL) 1377 dns_db_detach(&dctx->db); 1378 if (dctx != NULL) 1379 isc_mem_put(mctx, dctx, sizeof(*dctx)); 1380 return (result); 1381} 1382 1383static isc_result_t 1384dumptostreaminc(dns_dumpctx_t *dctx) { 1385 isc_result_t result; 1386 isc_buffer_t buffer; 1387 char *bufmem; 1388 isc_region_t r; 1389 dns_name_t *name; 1390 dns_fixedname_t fixname; 1391 unsigned int nodes; 1392 dns_masterrawheader_t rawheader; 1393 isc_uint32_t rawversion, now32; 1394 isc_time_t start; 1395 1396 bufmem = isc_mem_get(dctx->mctx, initial_buffer_length); 1397 if (bufmem == NULL) 1398 return (ISC_R_NOMEMORY); 1399 1400 isc_buffer_init(&buffer, bufmem, initial_buffer_length); 1401 1402 dns_fixedname_init(&fixname); 1403 name = dns_fixedname_name(&fixname); 1404 1405 if (dctx->first) { 1406 switch (dctx->format) { 1407 case dns_masterformat_text: 1408 /* 1409 * If the database has cache semantics, output an 1410 * RFC2540 $DATE directive so that the TTLs can be 1411 * adjusted when it is reloaded. For zones it is not 1412 * really needed, and it would make the file 1413 * incompatible with pre-RFC2540 software, so we omit 1414 * it in the zone case. 1415 */ 1416 if (dctx->do_date) { 1417 result = dns_time32_totext(dctx->now, &buffer); 1418 RUNTIME_CHECK(result == ISC_R_SUCCESS); 1419 isc_buffer_usedregion(&buffer, &r); 1420 fprintf(dctx->f, "$DATE %.*s\n", 1421 (int) r.length, (char *) r.base); 1422 } 1423 break; 1424 case dns_masterformat_raw: 1425 r.base = (unsigned char *)&rawheader; 1426 r.length = sizeof(rawheader); 1427 isc_buffer_region(&buffer, &r); 1428#if !defined(STDTIME_ON_32BITS) || (STDTIME_ON_32BITS + 0) != 1 1429 /* 1430 * We assume isc_stdtime_t is a 32-bit integer, 1431 * which should be the case on most cases. 1432 * If it turns out to be uncommon, we'll need 1433 * to bump the version number and revise the 1434 * header format. 1435 */ 1436 isc_log_write(dns_lctx, 1437 ISC_LOGCATEGORY_GENERAL, 1438 DNS_LOGMODULE_MASTERDUMP, 1439 ISC_LOG_INFO, 1440 "dumping master file in raw " 1441 "format: stdtime is not 32bits"); 1442 now32 = 0; 1443#else 1444 now32 = dctx->now; 1445#endif 1446 rawversion = 1; 1447 if ((dctx->header.flags & DNS_MASTERRAW_COMPAT) != 0) 1448 rawversion = 0; 1449 isc_buffer_putuint32(&buffer, dns_masterformat_raw); 1450 isc_buffer_putuint32(&buffer, rawversion); 1451 isc_buffer_putuint32(&buffer, now32); 1452 1453 if (rawversion == 1) { 1454 isc_buffer_putuint32(&buffer, 1455 dctx->header.flags); 1456 isc_buffer_putuint32(&buffer, 1457 dctx->header.sourceserial); 1458 isc_buffer_putuint32(&buffer, 1459 dctx->header.lastxfrin); 1460 } 1461 1462 INSIST(isc_buffer_usedlength(&buffer) <= 1463 sizeof(rawheader)); 1464 result = isc_stdio_write(buffer.base, 1, 1465 isc_buffer_usedlength(&buffer), 1466 dctx->f, NULL); 1467 if (result != ISC_R_SUCCESS) 1468 return (result); 1469 isc_buffer_clear(&buffer); 1470 break; 1471 default: 1472 INSIST(0); 1473 } 1474 1475 result = dns_dbiterator_first(dctx->dbiter); 1476 dctx->first = ISC_FALSE; 1477 } else 1478 result = ISC_R_SUCCESS; 1479 1480 nodes = dctx->nodes; 1481 isc_time_now(&start); 1482 while (result == ISC_R_SUCCESS && (dctx->nodes == 0 || nodes--)) { 1483 dns_rdatasetiter_t *rdsiter = NULL; 1484 dns_dbnode_t *node = NULL; 1485 1486 result = dns_dbiterator_current(dctx->dbiter, &node, name); 1487 if (result != ISC_R_SUCCESS && result != DNS_R_NEWORIGIN) 1488 break; 1489 if (result == DNS_R_NEWORIGIN) { 1490 dns_name_t *origin = 1491 dns_fixedname_name(&dctx->tctx.origin_fixname); 1492 result = dns_dbiterator_origin(dctx->dbiter, origin); 1493 RUNTIME_CHECK(result == ISC_R_SUCCESS); 1494 if ((dctx->tctx.style.flags & DNS_STYLEFLAG_REL_DATA) != 0) 1495 dctx->tctx.origin = origin; 1496 dctx->tctx.neworigin = origin; 1497 } 1498 result = dns_db_allrdatasets(dctx->db, node, dctx->version, 1499 dctx->now, &rdsiter); 1500 if (result != ISC_R_SUCCESS) { 1501 dns_db_detachnode(dctx->db, &node); 1502 goto fail; 1503 } 1504 result = (dctx->dumpsets)(dctx->mctx, name, rdsiter, 1505 &dctx->tctx, &buffer, dctx->f); 1506 dns_rdatasetiter_destroy(&rdsiter); 1507 if (result != ISC_R_SUCCESS) { 1508 dns_db_detachnode(dctx->db, &node); 1509 goto fail; 1510 } 1511 dns_db_detachnode(dctx->db, &node); 1512 result = dns_dbiterator_next(dctx->dbiter); 1513 } 1514 1515 /* 1516 * Work out how many nodes can be written in the time between 1517 * two requests to the nameserver. Smooth the resulting number and 1518 * use it as a estimate for the number of nodes to be written in the 1519 * next iteration. 1520 */ 1521 if (dctx->nodes != 0 && result == ISC_R_SUCCESS) { 1522 unsigned int pps = dns_pps; /* packets per second */ 1523 unsigned int interval; 1524 isc_uint64_t usecs; 1525 isc_time_t end; 1526 1527 isc_time_now(&end); 1528 if (pps < 100) 1529 pps = 100; 1530 interval = 1000000 / pps; /* interval in usecs */ 1531 if (interval == 0) 1532 interval = 1; 1533 usecs = isc_time_microdiff(&end, &start); 1534 if (usecs == 0) { 1535 dctx->nodes = dctx->nodes * 2; 1536 if (dctx->nodes > 1000) 1537 dctx->nodes = 1000; 1538 } else { 1539 nodes = dctx->nodes * interval; 1540 nodes /= (unsigned int)usecs; 1541 if (nodes == 0) 1542 nodes = 1; 1543 else if (nodes > 1000) 1544 nodes = 1000; 1545 1546 /* Smooth and assign. */ 1547 dctx->nodes = (nodes + dctx->nodes * 7) / 8; 1548 1549 isc_log_write(dns_lctx, ISC_LOGCATEGORY_GENERAL, 1550 DNS_LOGMODULE_MASTERDUMP, 1551 ISC_LOG_DEBUG(1), 1552 "dumptostreaminc(%p) new nodes -> %d\n", 1553 dctx, dctx->nodes); 1554 } 1555 result = DNS_R_CONTINUE; 1556 } else if (result == ISC_R_NOMORE) 1557 result = ISC_R_SUCCESS; 1558 fail: 1559 RUNTIME_CHECK(dns_dbiterator_pause(dctx->dbiter) == ISC_R_SUCCESS); 1560 isc_mem_put(dctx->mctx, buffer.base, buffer.length); 1561 return (result); 1562} 1563 1564isc_result_t 1565dns_master_dumptostreaminc(isc_mem_t *mctx, dns_db_t *db, 1566 dns_dbversion_t *version, 1567 const dns_master_style_t *style, 1568 FILE *f, isc_task_t *task, 1569 dns_dumpdonefunc_t done, void *done_arg, 1570 dns_dumpctx_t **dctxp) 1571{ 1572 dns_dumpctx_t *dctx = NULL; 1573 isc_result_t result; 1574 1575 REQUIRE(task != NULL); 1576 REQUIRE(f != NULL); 1577 REQUIRE(done != NULL); 1578 1579 result = dumpctx_create(mctx, db, version, style, f, &dctx, 1580 dns_masterformat_text, NULL); 1581 if (result != ISC_R_SUCCESS) 1582 return (result); 1583 isc_task_attach(task, &dctx->task); 1584 dctx->done = done; 1585 dctx->done_arg = done_arg; 1586 dctx->nodes = 100; 1587 1588 result = task_send(dctx); 1589 if (result == ISC_R_SUCCESS) { 1590 dns_dumpctx_attach(dctx, dctxp); 1591 return (DNS_R_CONTINUE); 1592 } 1593 1594 dns_dumpctx_detach(&dctx); 1595 return (result); 1596} 1597 1598/* 1599 * Dump an entire database into a master file. 1600 */ 1601isc_result_t 1602dns_master_dumptostream(isc_mem_t *mctx, dns_db_t *db, 1603 dns_dbversion_t *version, 1604 const dns_master_style_t *style, 1605 FILE *f) 1606{ 1607 return (dns_master_dumptostream3(mctx, db, version, style, 1608 dns_masterformat_text, NULL, f)); 1609} 1610 1611isc_result_t 1612dns_master_dumptostream2(isc_mem_t *mctx, dns_db_t *db, 1613 dns_dbversion_t *version, 1614 const dns_master_style_t *style, 1615 dns_masterformat_t format, FILE *f) 1616{ 1617 return (dns_master_dumptostream3(mctx, db, version, style, 1618 format, NULL, f)); 1619} 1620 1621isc_result_t 1622dns_master_dumptostream3(isc_mem_t *mctx, dns_db_t *db, 1623 dns_dbversion_t *version, 1624 const dns_master_style_t *style, 1625 dns_masterformat_t format, 1626 dns_masterrawheader_t *header, FILE *f) 1627{ 1628 dns_dumpctx_t *dctx = NULL; 1629 isc_result_t result; 1630 1631 result = dumpctx_create(mctx, db, version, style, f, &dctx, 1632 format, header); 1633 if (result != ISC_R_SUCCESS) 1634 return (result); 1635 1636 result = dumptostreaminc(dctx); 1637 INSIST(result != DNS_R_CONTINUE); 1638 dns_dumpctx_detach(&dctx); 1639 1640 result = flushandsync(f, result, NULL); 1641 return (result); 1642} 1643 1644static isc_result_t 1645opentmp(isc_mem_t *mctx, dns_masterformat_t format, const char *file, 1646 char **tempp, FILE **fp) { 1647 FILE *f = NULL; 1648 isc_result_t result; 1649 char *tempname = NULL; 1650 int tempnamelen; 1651 1652 tempnamelen = strlen(file) + 20; 1653 tempname = isc_mem_allocate(mctx, tempnamelen); 1654 if (tempname == NULL) 1655 return (ISC_R_NOMEMORY); 1656 1657 result = isc_file_mktemplate(file, tempname, tempnamelen); 1658 if (result != ISC_R_SUCCESS) 1659 goto cleanup; 1660 1661 if (format == dns_masterformat_text) 1662 result = isc_file_openunique(tempname, &f); 1663 else 1664 result = isc_file_bopenunique(tempname, &f); 1665 if (result != ISC_R_SUCCESS) { 1666 isc_log_write(dns_lctx, ISC_LOGCATEGORY_GENERAL, 1667 DNS_LOGMODULE_MASTERDUMP, ISC_LOG_ERROR, 1668 "dumping master file: %s: open: %s", 1669 tempname, isc_result_totext(result)); 1670 goto cleanup; 1671 } 1672 *tempp = tempname; 1673 *fp = f; 1674 return (ISC_R_SUCCESS); 1675 1676cleanup: 1677 isc_mem_free(mctx, tempname); 1678 return (result); 1679} 1680 1681isc_result_t 1682dns_master_dumpinc(isc_mem_t *mctx, dns_db_t *db, dns_dbversion_t *version, 1683 const dns_master_style_t *style, const char *filename, 1684 isc_task_t *task, dns_dumpdonefunc_t done, void *done_arg, 1685 dns_dumpctx_t **dctxp) 1686{ 1687 return (dns_master_dumpinc3(mctx, db, version, style, filename, task, 1688 done, done_arg, dctxp, 1689 dns_masterformat_text, NULL)); 1690} 1691 1692isc_result_t 1693dns_master_dumpinc2(isc_mem_t *mctx, dns_db_t *db, dns_dbversion_t *version, 1694 const dns_master_style_t *style, const char *filename, 1695 isc_task_t *task, dns_dumpdonefunc_t done, void *done_arg, 1696 dns_dumpctx_t **dctxp, dns_masterformat_t format) 1697{ 1698 return (dns_master_dumpinc3(mctx, db, version, style, filename, task, 1699 done, done_arg, dctxp, format, NULL)); 1700} 1701 1702isc_result_t 1703dns_master_dumpinc3(isc_mem_t *mctx, dns_db_t *db, dns_dbversion_t *version, 1704 const dns_master_style_t *style, const char *filename, 1705 isc_task_t *task, dns_dumpdonefunc_t done, void *done_arg, 1706 dns_dumpctx_t **dctxp, dns_masterformat_t format, 1707 dns_masterrawheader_t *header) 1708{ 1709 FILE *f = NULL; 1710 isc_result_t result; 1711 char *tempname = NULL; 1712 char *file = NULL; 1713 dns_dumpctx_t *dctx = NULL; 1714 1715 file = isc_mem_strdup(mctx, filename); 1716 if (file == NULL) 1717 return (ISC_R_NOMEMORY); 1718 1719 result = opentmp(mctx, format, filename, &tempname, &f); 1720 if (result != ISC_R_SUCCESS) 1721 goto cleanup; 1722 1723 result = dumpctx_create(mctx, db, version, style, f, &dctx, 1724 format, header); 1725 if (result != ISC_R_SUCCESS) { 1726 (void)isc_stdio_close(f); 1727 (void)isc_file_remove(tempname); 1728 goto cleanup; 1729 } 1730 1731 isc_task_attach(task, &dctx->task); 1732 dctx->done = done; 1733 dctx->done_arg = done_arg; 1734 dctx->nodes = 100; 1735 dctx->file = file; 1736 file = NULL; 1737 dctx->tmpfile = tempname; 1738 tempname = NULL; 1739 1740 result = task_send(dctx); 1741 if (result == ISC_R_SUCCESS) { 1742 dns_dumpctx_attach(dctx, dctxp); 1743 return (DNS_R_CONTINUE); 1744 } 1745 1746 cleanup: 1747 if (dctx != NULL) 1748 dns_dumpctx_detach(&dctx); 1749 if (file != NULL) 1750 isc_mem_free(mctx, file); 1751 if (tempname != NULL) 1752 isc_mem_free(mctx, tempname); 1753 return (result); 1754} 1755 1756isc_result_t 1757dns_master_dump(isc_mem_t *mctx, dns_db_t *db, dns_dbversion_t *version, 1758 const dns_master_style_t *style, const char *filename) 1759{ 1760 return (dns_master_dump3(mctx, db, version, style, filename, 1761 dns_masterformat_text, NULL)); 1762} 1763 1764isc_result_t 1765dns_master_dump2(isc_mem_t *mctx, dns_db_t *db, dns_dbversion_t *version, 1766 const dns_master_style_t *style, const char *filename, 1767 dns_masterformat_t format) 1768{ 1769 return (dns_master_dump3(mctx, db, version, style, filename, 1770 format, NULL)); 1771} 1772 1773isc_result_t 1774dns_master_dump3(isc_mem_t *mctx, dns_db_t *db, dns_dbversion_t *version, 1775 const dns_master_style_t *style, const char *filename, 1776 dns_masterformat_t format, dns_masterrawheader_t *header) 1777{ 1778 FILE *f = NULL; 1779 isc_result_t result; 1780 char *tempname; 1781 dns_dumpctx_t *dctx = NULL; 1782 1783 result = opentmp(mctx, format, filename, &tempname, &f); 1784 if (result != ISC_R_SUCCESS) 1785 return (result); 1786 1787 result = dumpctx_create(mctx, db, version, style, f, &dctx, 1788 format, header); 1789 if (result != ISC_R_SUCCESS) 1790 goto cleanup; 1791 1792 result = dumptostreaminc(dctx); 1793 INSIST(result != DNS_R_CONTINUE); 1794 dns_dumpctx_detach(&dctx); 1795 1796 result = closeandrename(f, result, tempname, filename); 1797 1798 cleanup: 1799 isc_mem_free(mctx, tempname); 1800 return (result); 1801} 1802 1803/* 1804 * Dump a database node into a master file. 1805 * XXX: this function assumes the text format. 1806 */ 1807isc_result_t 1808dns_master_dumpnodetostream(isc_mem_t *mctx, dns_db_t *db, 1809 dns_dbversion_t *version, 1810 dns_dbnode_t *node, dns_name_t *name, 1811 const dns_master_style_t *style, 1812 FILE *f) 1813{ 1814 isc_result_t result; 1815 isc_buffer_t buffer; 1816 char *bufmem; 1817 isc_stdtime_t now; 1818 dns_totext_ctx_t ctx; 1819 dns_rdatasetiter_t *rdsiter = NULL; 1820 1821 result = totext_ctx_init(style, &ctx); 1822 if (result != ISC_R_SUCCESS) { 1823 UNEXPECTED_ERROR(__FILE__, __LINE__, 1824 "could not set master file style"); 1825 return (ISC_R_UNEXPECTED); 1826 } 1827 1828 isc_stdtime_get(&now); 1829 1830 bufmem = isc_mem_get(mctx, initial_buffer_length); 1831 if (bufmem == NULL) 1832 return (ISC_R_NOMEMORY); 1833 1834 isc_buffer_init(&buffer, bufmem, initial_buffer_length); 1835 1836 result = dns_db_allrdatasets(db, node, version, now, &rdsiter); 1837 if (result != ISC_R_SUCCESS) 1838 goto failure; 1839 result = dump_rdatasets_text(mctx, name, rdsiter, &ctx, &buffer, f); 1840 if (result != ISC_R_SUCCESS) 1841 goto failure; 1842 dns_rdatasetiter_destroy(&rdsiter); 1843 1844 result = ISC_R_SUCCESS; 1845 1846 failure: 1847 isc_mem_put(mctx, buffer.base, buffer.length); 1848 return (result); 1849} 1850 1851isc_result_t 1852dns_master_dumpnode(isc_mem_t *mctx, dns_db_t *db, dns_dbversion_t *version, 1853 dns_dbnode_t *node, dns_name_t *name, 1854 const dns_master_style_t *style, const char *filename) 1855{ 1856 FILE *f = NULL; 1857 isc_result_t result; 1858 1859 result = isc_stdio_open(filename, "w", &f); 1860 if (result != ISC_R_SUCCESS) { 1861 isc_log_write(dns_lctx, ISC_LOGCATEGORY_GENERAL, 1862 DNS_LOGMODULE_MASTERDUMP, ISC_LOG_ERROR, 1863 "dumping node to file: %s: open: %s", filename, 1864 isc_result_totext(result)); 1865 return (ISC_R_UNEXPECTED); 1866 } 1867 1868 result = dns_master_dumpnodetostream(mctx, db, version, node, name, 1869 style, f); 1870 if (result != ISC_R_SUCCESS) { 1871 isc_log_write(dns_lctx, ISC_LOGCATEGORY_GENERAL, 1872 DNS_LOGMODULE_MASTERDUMP, ISC_LOG_ERROR, 1873 "dumping master file: %s: dump: %s", filename, 1874 isc_result_totext(result)); 1875 (void)isc_stdio_close(f); 1876 return (ISC_R_UNEXPECTED); 1877 } 1878 1879 result = isc_stdio_close(f); 1880 if (result != ISC_R_SUCCESS) { 1881 isc_log_write(dns_lctx, ISC_LOGCATEGORY_GENERAL, 1882 DNS_LOGMODULE_MASTERDUMP, ISC_LOG_ERROR, 1883 "dumping master file: %s: close: %s", filename, 1884 isc_result_totext(result)); 1885 return (ISC_R_UNEXPECTED); 1886 } 1887 1888 return (result); 1889} 1890#endif /* BIND9 */ 1891 1892isc_result_t 1893dns_master_stylecreate(dns_master_style_t **stylep, unsigned int flags, 1894 unsigned int ttl_column, unsigned int class_column, 1895 unsigned int type_column, unsigned int rdata_column, 1896 unsigned int line_length, unsigned int tab_width, 1897 isc_mem_t *mctx) 1898{ 1899 return (dns_master_stylecreate2(stylep, flags, ttl_column, 1900 class_column, type_column, 1901 rdata_column, line_length, 1902 tab_width, 0xffffffff, mctx)); 1903} 1904 1905isc_result_t 1906dns_master_stylecreate2(dns_master_style_t **stylep, unsigned int flags, 1907 unsigned int ttl_column, unsigned int class_column, 1908 unsigned int type_column, unsigned int rdata_column, 1909 unsigned int line_length, unsigned int tab_width, 1910 unsigned int split_width, isc_mem_t *mctx) 1911{ 1912 dns_master_style_t *style; 1913 1914 REQUIRE(stylep != NULL && *stylep == NULL); 1915 style = isc_mem_get(mctx, sizeof(*style)); 1916 if (style == NULL) 1917 return (ISC_R_NOMEMORY); 1918 1919 style->flags = flags; 1920 style->ttl_column = ttl_column; 1921 style->class_column = class_column; 1922 style->type_column = type_column; 1923 style->rdata_column = rdata_column; 1924 style->line_length = line_length; 1925 style->tab_width = tab_width; 1926 style->split_width = split_width; 1927 1928 *stylep = style; 1929 return (ISC_R_SUCCESS); 1930} 1931 1932void 1933dns_master_styledestroy(dns_master_style_t **stylep, isc_mem_t *mctx) { 1934 dns_master_style_t *style; 1935 1936 REQUIRE(stylep != NULL && *stylep != NULL); 1937 style = *stylep; 1938 *stylep = NULL; 1939 isc_mem_put(mctx, style, sizeof(*style)); 1940} 1941