/contrib/bind9/lib/dns/master.c
C | 2941 lines | 2804 code | 79 blank | 58 comment | 107 complexity | 27f06f2d7c402d2e65f77ae8419f13c0 MD5 | raw file
Large files files are truncated, but you can click here to view the full file
1/* 2 * Copyright (C) 2004-2009, 2011, 2012 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 <isc/event.h> 25#include <isc/lex.h> 26#include <isc/magic.h> 27#include <isc/mem.h> 28#include <isc/print.h> 29#include <isc/serial.h> 30#include <isc/stdio.h> 31#include <isc/stdtime.h> 32#include <isc/string.h> 33#include <isc/task.h> 34#include <isc/util.h> 35 36#include <dns/callbacks.h> 37#include <dns/events.h> 38#include <dns/fixedname.h> 39#include <dns/master.h> 40#include <dns/name.h> 41#include <dns/rdata.h> 42#include <dns/rdataclass.h> 43#include <dns/rdatalist.h> 44#include <dns/rdataset.h> 45#include <dns/rdatastruct.h> 46#include <dns/rdatatype.h> 47#include <dns/result.h> 48#include <dns/soa.h> 49#include <dns/time.h> 50#include <dns/ttl.h> 51 52/*! 53 * Grow the number of dns_rdatalist_t (#RDLSZ) and dns_rdata_t (#RDSZ) structures 54 * by these sizes when we need to. 55 * 56 */ 57/*% RDLSZ reflects the number of different types with the same name expected. */ 58#define RDLSZ 32 59/*% 60 * RDSZ reflects the number of rdata expected at a give name that can fit into 61 * 64k. 62 */ 63#define RDSZ 512 64 65#define NBUFS 4 66#define MAXWIRESZ 255 67 68/*% 69 * Target buffer size and minimum target size. 70 * MINTSIZ must be big enough to hold the largest rdata record. 71 * \brief 72 * TSIZ >= MINTSIZ 73 */ 74#define TSIZ (128*1024) 75/*% 76 * max message size - header - root - type - class - ttl - rdlen 77 */ 78#define MINTSIZ DNS_RDATA_MAXLENGTH 79/*% 80 * Size for tokens in the presentation format, 81 * The largest tokens are the base64 blocks in KEY and CERT records, 82 * Largest key allowed is about 1372 bytes but 83 * there is no fixed upper bound on CERT records. 84 * 2K is too small for some X.509s, 8K is overkill. 85 */ 86#define TOKENSIZ (8*1024) 87 88/*% 89 * Buffers sizes for $GENERATE. 90 */ 91#define DNS_MASTER_LHS 2048 92#define DNS_MASTER_RHS MINTSIZ 93 94typedef ISC_LIST(dns_rdatalist_t) rdatalist_head_t; 95 96typedef struct dns_incctx dns_incctx_t; 97 98/*% 99 * Master file load state. 100 */ 101 102struct dns_loadctx { 103 unsigned int magic; 104 isc_mem_t *mctx; 105 dns_masterformat_t format; 106 107 dns_rdatacallbacks_t *callbacks; 108 isc_task_t *task; 109 dns_loaddonefunc_t done; 110 void *done_arg; 111 112 /* Common methods */ 113 isc_result_t (*openfile)(dns_loadctx_t *lctx, 114 const char *filename); 115 isc_result_t (*load)(dns_loadctx_t *lctx); 116 117 /* Members specific to the text format: */ 118 isc_lex_t *lex; 119 isc_boolean_t keep_lex; 120 unsigned int options; 121 isc_boolean_t ttl_known; 122 isc_boolean_t default_ttl_known; 123 isc_boolean_t warn_1035; 124 isc_boolean_t warn_tcr; 125 isc_boolean_t warn_sigexpired; 126 isc_boolean_t seen_include; 127 isc_uint32_t ttl; 128 isc_uint32_t default_ttl; 129 dns_rdataclass_t zclass; 130 dns_fixedname_t fixed_top; 131 dns_name_t *top; /*%< top of zone */ 132 133 /* Members specific to the raw format: */ 134 FILE *f; 135 isc_boolean_t first; 136 137 /* Which fixed buffers we are using? */ 138 unsigned int loop_cnt; /*% records per quantum, 139 * 0 => all. */ 140 isc_boolean_t canceled; 141 isc_mutex_t lock; 142 isc_result_t result; 143 /* locked by lock */ 144 isc_uint32_t references; 145 dns_incctx_t *inc; 146 isc_uint32_t resign; 147}; 148 149struct dns_incctx { 150 dns_incctx_t *parent; 151 dns_name_t *origin; 152 dns_name_t *current; 153 dns_name_t *glue; 154 dns_fixedname_t fixed[NBUFS]; /* working buffers */ 155 unsigned int in_use[NBUFS]; /* covert to bitmap? */ 156 int glue_in_use; 157 int current_in_use; 158 int origin_in_use; 159 isc_boolean_t drop; 160 unsigned int glue_line; 161 unsigned int current_line; 162}; 163 164#define DNS_LCTX_MAGIC ISC_MAGIC('L','c','t','x') 165#define DNS_LCTX_VALID(lctx) ISC_MAGIC_VALID(lctx, DNS_LCTX_MAGIC) 166 167#define DNS_AS_STR(t) ((t).value.as_textregion.base) 168 169static isc_result_t 170openfile_text(dns_loadctx_t *lctx, const char *master_file); 171 172static isc_result_t 173openfile_raw(dns_loadctx_t *lctx, const char *master_file); 174 175static isc_result_t 176load_text(dns_loadctx_t *lctx); 177 178static isc_result_t 179load_raw(dns_loadctx_t *lctx); 180 181static isc_result_t 182pushfile(const char *master_file, dns_name_t *origin, dns_loadctx_t *lctx); 183 184static isc_result_t 185commit(dns_rdatacallbacks_t *, dns_loadctx_t *, rdatalist_head_t *, 186 dns_name_t *, const char *, unsigned int); 187 188static isc_boolean_t 189is_glue(rdatalist_head_t *, dns_name_t *); 190 191static dns_rdatalist_t * 192grow_rdatalist(int, dns_rdatalist_t *, int, rdatalist_head_t *, 193 rdatalist_head_t *, isc_mem_t *mctx); 194 195static dns_rdata_t * 196grow_rdata(int, dns_rdata_t *, int, rdatalist_head_t *, rdatalist_head_t *, 197 isc_mem_t *); 198 199static void 200load_quantum(isc_task_t *task, isc_event_t *event); 201 202static isc_result_t 203task_send(dns_loadctx_t *lctx); 204 205static void 206loadctx_destroy(dns_loadctx_t *lctx); 207 208#define GETTOKEN(lexer, options, token, eol) \ 209 do { \ 210 result = gettoken(lexer, options, token, eol, callbacks); \ 211 switch (result) { \ 212 case ISC_R_SUCCESS: \ 213 break; \ 214 case ISC_R_UNEXPECTED: \ 215 goto insist_and_cleanup; \ 216 default: \ 217 if (MANYERRS(lctx, result)) { \ 218 SETRESULT(lctx, result); \ 219 LOGIT(result); \ 220 read_till_eol = ISC_TRUE; \ 221 goto next_line; \ 222 } else \ 223 goto log_and_cleanup; \ 224 } \ 225 if ((token)->type == isc_tokentype_special) { \ 226 result = DNS_R_SYNTAX; \ 227 if (MANYERRS(lctx, result)) { \ 228 SETRESULT(lctx, result); \ 229 LOGIT(result); \ 230 read_till_eol = ISC_TRUE; \ 231 goto next_line; \ 232 } else \ 233 goto log_and_cleanup; \ 234 } \ 235 } while (0) 236 237#define COMMITALL \ 238 do { \ 239 result = commit(callbacks, lctx, ¤t_list, \ 240 ictx->current, source, ictx->current_line); \ 241 if (MANYERRS(lctx, result)) { \ 242 SETRESULT(lctx, result); \ 243 } else if (result != ISC_R_SUCCESS) \ 244 goto insist_and_cleanup; \ 245 result = commit(callbacks, lctx, &glue_list, \ 246 ictx->glue, source, ictx->glue_line); \ 247 if (MANYERRS(lctx, result)) { \ 248 SETRESULT(lctx, result); \ 249 } else if (result != ISC_R_SUCCESS) \ 250 goto insist_and_cleanup; \ 251 rdcount = 0; \ 252 rdlcount = 0; \ 253 isc_buffer_init(&target, target_mem, target_size); \ 254 rdcount_save = rdcount; \ 255 rdlcount_save = rdlcount; \ 256 } while (0) 257 258#define WARNUNEXPECTEDEOF(lexer) \ 259 do { \ 260 if (isc_lex_isfile(lexer)) \ 261 (*callbacks->warn)(callbacks, \ 262 "%s: file does not end with newline", \ 263 source); \ 264 } while (0) 265 266#define EXPECTEOL \ 267 do { \ 268 GETTOKEN(lctx->lex, 0, &token, ISC_TRUE); \ 269 if (token.type != isc_tokentype_eol) { \ 270 isc_lex_ungettoken(lctx->lex, &token); \ 271 result = DNS_R_EXTRATOKEN; \ 272 if (MANYERRS(lctx, result)) { \ 273 SETRESULT(lctx, result); \ 274 LOGIT(result); \ 275 read_till_eol = ISC_TRUE; \ 276 continue; \ 277 } else if (result != ISC_R_SUCCESS) \ 278 goto log_and_cleanup; \ 279 } \ 280 } while (0) 281 282#define MANYERRS(lctx, result) \ 283 ((result != ISC_R_SUCCESS) && \ 284 (result != ISC_R_IOERROR) && \ 285 ((lctx)->options & DNS_MASTER_MANYERRORS) != 0) 286 287#define SETRESULT(lctx, r) \ 288 do { \ 289 if ((lctx)->result == ISC_R_SUCCESS) \ 290 (lctx)->result = r; \ 291 } while (0) 292 293#define LOGITFILE(result, filename) \ 294 if (result == ISC_R_INVALIDFILE || result == ISC_R_FILENOTFOUND || \ 295 result == ISC_R_IOERROR || result == ISC_R_TOOMANYOPENFILES || \ 296 result == ISC_R_NOPERM) \ 297 (*callbacks->error)(callbacks, "%s: %s:%lu: %s: %s", \ 298 "dns_master_load", source, line, \ 299 filename, dns_result_totext(result)); \ 300 else LOGIT(result) 301 302#define LOGIT(result) \ 303 if (result == ISC_R_NOMEMORY) \ 304 (*callbacks->error)(callbacks, "dns_master_load: %s", \ 305 dns_result_totext(result)); \ 306 else \ 307 (*callbacks->error)(callbacks, "%s: %s:%lu: %s", \ 308 "dns_master_load", \ 309 source, line, dns_result_totext(result)) 310 311 312static unsigned char in_addr_arpa_data[] = "\007IN-ADDR\004ARPA"; 313static unsigned char in_addr_arpa_offsets[] = { 0, 8, 13 }; 314static const dns_name_t in_addr_arpa = 315{ 316 DNS_NAME_MAGIC, 317 in_addr_arpa_data, 14, 3, 318 DNS_NAMEATTR_READONLY | DNS_NAMEATTR_ABSOLUTE, 319 in_addr_arpa_offsets, NULL, 320 {(void *)-1, (void *)-1}, 321 {NULL, NULL} 322}; 323 324static unsigned char ip6_int_data[] = "\003IP6\003INT"; 325static unsigned char ip6_int_offsets[] = { 0, 4, 8 }; 326static const dns_name_t ip6_int = 327{ 328 DNS_NAME_MAGIC, 329 ip6_int_data, 9, 3, 330 DNS_NAMEATTR_READONLY | DNS_NAMEATTR_ABSOLUTE, 331 ip6_int_offsets, NULL, 332 {(void *)-1, (void *)-1}, 333 {NULL, NULL} 334}; 335 336static unsigned char ip6_arpa_data[] = "\003IP6\004ARPA"; 337static unsigned char ip6_arpa_offsets[] = { 0, 4, 9 }; 338static const dns_name_t ip6_arpa = 339{ 340 DNS_NAME_MAGIC, 341 ip6_arpa_data, 10, 3, 342 DNS_NAMEATTR_READONLY | DNS_NAMEATTR_ABSOLUTE, 343 ip6_arpa_offsets, NULL, 344 {(void *)-1, (void *)-1}, 345 {NULL, NULL} 346}; 347 348 349static inline isc_result_t 350gettoken(isc_lex_t *lex, unsigned int options, isc_token_t *token, 351 isc_boolean_t eol, dns_rdatacallbacks_t *callbacks) 352{ 353 isc_result_t result; 354 355 options |= ISC_LEXOPT_EOL | ISC_LEXOPT_EOF | ISC_LEXOPT_DNSMULTILINE | 356 ISC_LEXOPT_ESCAPE; 357 result = isc_lex_gettoken(lex, options, token); 358 if (result != ISC_R_SUCCESS) { 359 switch (result) { 360 case ISC_R_NOMEMORY: 361 return (ISC_R_NOMEMORY); 362 default: 363 (*callbacks->error)(callbacks, 364 "dns_master_load: %s:%lu:" 365 " isc_lex_gettoken() failed: %s", 366 isc_lex_getsourcename(lex), 367 isc_lex_getsourceline(lex), 368 isc_result_totext(result)); 369 return (result); 370 } 371 /*NOTREACHED*/ 372 } 373 if (eol != ISC_TRUE) 374 if (token->type == isc_tokentype_eol || 375 token->type == isc_tokentype_eof) { 376 (*callbacks->error)(callbacks, 377 "dns_master_load: %s:%lu: unexpected end of %s", 378 isc_lex_getsourcename(lex), 379 isc_lex_getsourceline(lex), 380 (token->type == 381 isc_tokentype_eol) ? 382 "line" : "file"); 383 return (ISC_R_UNEXPECTEDEND); 384 } 385 return (ISC_R_SUCCESS); 386} 387 388 389void 390dns_loadctx_attach(dns_loadctx_t *source, dns_loadctx_t **target) { 391 392 REQUIRE(target != NULL && *target == NULL); 393 REQUIRE(DNS_LCTX_VALID(source)); 394 395 LOCK(&source->lock); 396 INSIST(source->references > 0); 397 source->references++; 398 INSIST(source->references != 0); /* Overflow? */ 399 UNLOCK(&source->lock); 400 401 *target = source; 402} 403 404void 405dns_loadctx_detach(dns_loadctx_t **lctxp) { 406 dns_loadctx_t *lctx; 407 isc_boolean_t need_destroy = ISC_FALSE; 408 409 REQUIRE(lctxp != NULL); 410 lctx = *lctxp; 411 REQUIRE(DNS_LCTX_VALID(lctx)); 412 413 LOCK(&lctx->lock); 414 INSIST(lctx->references > 0); 415 lctx->references--; 416 if (lctx->references == 0) 417 need_destroy = ISC_TRUE; 418 UNLOCK(&lctx->lock); 419 420 if (need_destroy) 421 loadctx_destroy(lctx); 422 *lctxp = NULL; 423} 424 425static void 426incctx_destroy(isc_mem_t *mctx, dns_incctx_t *ictx) { 427 dns_incctx_t *parent; 428 429 again: 430 parent = ictx->parent; 431 ictx->parent = NULL; 432 433 isc_mem_put(mctx, ictx, sizeof(*ictx)); 434 435 if (parent != NULL) { 436 ictx = parent; 437 goto again; 438 } 439} 440 441static void 442loadctx_destroy(dns_loadctx_t *lctx) { 443 isc_mem_t *mctx; 444 isc_result_t result; 445 446 REQUIRE(DNS_LCTX_VALID(lctx)); 447 448 lctx->magic = 0; 449 if (lctx->inc != NULL) 450 incctx_destroy(lctx->mctx, lctx->inc); 451 452 if (lctx->f != NULL) { 453 result = isc_stdio_close(lctx->f); 454 if (result != ISC_R_SUCCESS) { 455 UNEXPECTED_ERROR(__FILE__, __LINE__, 456 "isc_stdio_close() failed: %s", 457 isc_result_totext(result)); 458 } 459 } 460 461 /* isc_lex_destroy() will close all open streams */ 462 if (lctx->lex != NULL && !lctx->keep_lex) 463 isc_lex_destroy(&lctx->lex); 464 465 if (lctx->task != NULL) 466 isc_task_detach(&lctx->task); 467 DESTROYLOCK(&lctx->lock); 468 mctx = NULL; 469 isc_mem_attach(lctx->mctx, &mctx); 470 isc_mem_detach(&lctx->mctx); 471 isc_mem_put(mctx, lctx, sizeof(*lctx)); 472 isc_mem_detach(&mctx); 473} 474 475static isc_result_t 476incctx_create(isc_mem_t *mctx, dns_name_t *origin, dns_incctx_t **ictxp) { 477 dns_incctx_t *ictx; 478 isc_region_t r; 479 int i; 480 481 ictx = isc_mem_get(mctx, sizeof(*ictx)); 482 if (ictx == NULL) 483 return (ISC_R_NOMEMORY); 484 485 for (i = 0; i < NBUFS; i++) { 486 dns_fixedname_init(&ictx->fixed[i]); 487 ictx->in_use[i] = ISC_FALSE; 488 } 489 490 ictx->origin_in_use = 0; 491 ictx->origin = dns_fixedname_name(&ictx->fixed[ictx->origin_in_use]); 492 ictx->in_use[ictx->origin_in_use] = ISC_TRUE; 493 dns_name_toregion(origin, &r); 494 dns_name_fromregion(ictx->origin, &r); 495 496 ictx->glue = NULL; 497 ictx->current = NULL; 498 ictx->glue_in_use = -1; 499 ictx->current_in_use = -1; 500 ictx->parent = NULL; 501 ictx->drop = ISC_FALSE; 502 ictx->glue_line = 0; 503 ictx->current_line = 0; 504 505 *ictxp = ictx; 506 return (ISC_R_SUCCESS); 507} 508 509static isc_result_t 510loadctx_create(dns_masterformat_t format, isc_mem_t *mctx, 511 unsigned int options, isc_uint32_t resign, dns_name_t *top, 512 dns_rdataclass_t zclass, dns_name_t *origin, 513 dns_rdatacallbacks_t *callbacks, isc_task_t *task, 514 dns_loaddonefunc_t done, void *done_arg, isc_lex_t *lex, 515 dns_loadctx_t **lctxp) 516{ 517 dns_loadctx_t *lctx; 518 isc_result_t result; 519 isc_region_t r; 520 isc_lexspecials_t specials; 521 522 REQUIRE(lctxp != NULL && *lctxp == NULL); 523 REQUIRE(callbacks != NULL); 524 REQUIRE(callbacks->add != NULL); 525 REQUIRE(callbacks->error != NULL); 526 REQUIRE(callbacks->warn != NULL); 527 REQUIRE(mctx != NULL); 528 REQUIRE(dns_name_isabsolute(top)); 529 REQUIRE(dns_name_isabsolute(origin)); 530 REQUIRE((task == NULL && done == NULL) || 531 (task != NULL && done != NULL)); 532 533 lctx = isc_mem_get(mctx, sizeof(*lctx)); 534 if (lctx == NULL) 535 return (ISC_R_NOMEMORY); 536 result = isc_mutex_init(&lctx->lock); 537 if (result != ISC_R_SUCCESS) { 538 isc_mem_put(mctx, lctx, sizeof(*lctx)); 539 return (result); 540 } 541 542 lctx->inc = NULL; 543 result = incctx_create(mctx, origin, &lctx->inc); 544 if (result != ISC_R_SUCCESS) 545 goto cleanup_ctx; 546 547 lctx->format = format; 548 switch (format) { 549 default: 550 INSIST(0); 551 case dns_masterformat_text: 552 lctx->openfile = openfile_text; 553 lctx->load = load_text; 554 break; 555 case dns_masterformat_raw: 556 lctx->openfile = openfile_raw; 557 lctx->load = load_raw; 558 break; 559 } 560 561 if (lex != NULL) { 562 lctx->lex = lex; 563 lctx->keep_lex = ISC_TRUE; 564 } else { 565 lctx->lex = NULL; 566 result = isc_lex_create(mctx, TOKENSIZ, &lctx->lex); 567 if (result != ISC_R_SUCCESS) 568 goto cleanup_inc; 569 lctx->keep_lex = ISC_FALSE; 570 memset(specials, 0, sizeof(specials)); 571 specials['('] = 1; 572 specials[')'] = 1; 573 specials['"'] = 1; 574 isc_lex_setspecials(lctx->lex, specials); 575 isc_lex_setcomments(lctx->lex, ISC_LEXCOMMENT_DNSMASTERFILE); 576 } 577 578 lctx->ttl_known = ISC_FALSE; 579 lctx->ttl = 0; 580 lctx->default_ttl_known = ISC_FALSE; 581 lctx->default_ttl = 0; 582 lctx->warn_1035 = ISC_TRUE; /* XXX Argument? */ 583 lctx->warn_tcr = ISC_TRUE; /* XXX Argument? */ 584 lctx->warn_sigexpired = ISC_TRUE; /* XXX Argument? */ 585 lctx->options = options; 586 lctx->seen_include = ISC_FALSE; 587 lctx->zclass = zclass; 588 lctx->resign = resign; 589 lctx->result = ISC_R_SUCCESS; 590 591 dns_fixedname_init(&lctx->fixed_top); 592 lctx->top = dns_fixedname_name(&lctx->fixed_top); 593 dns_name_toregion(top, &r); 594 dns_name_fromregion(lctx->top, &r); 595 596 lctx->f = NULL; 597 lctx->first = ISC_TRUE; 598 599 lctx->loop_cnt = (done != NULL) ? 100 : 0; 600 lctx->callbacks = callbacks; 601 lctx->task = NULL; 602 if (task != NULL) 603 isc_task_attach(task, &lctx->task); 604 lctx->done = done; 605 lctx->done_arg = done_arg; 606 lctx->canceled = ISC_FALSE; 607 lctx->mctx = NULL; 608 isc_mem_attach(mctx, &lctx->mctx); 609 lctx->references = 1; /* Implicit attach. */ 610 lctx->magic = DNS_LCTX_MAGIC; 611 *lctxp = lctx; 612 return (ISC_R_SUCCESS); 613 614 cleanup_inc: 615 incctx_destroy(mctx, lctx->inc); 616 cleanup_ctx: 617 isc_mem_put(mctx, lctx, sizeof(*lctx)); 618 return (result); 619} 620 621static const char *hex = "0123456789abcdef0123456789ABCDEF"; 622 623/*% 624 * Convert value into a nibble sequence from least significant to most 625 * significant nibble. Zero fill upper most significant nibbles if 626 * required to make the width. 627 * 628 * Returns the number of characters that should have been written without 629 * counting the terminating NUL. 630 */ 631static unsigned int 632nibbles(char *numbuf, size_t length, unsigned int width, char mode, int value) { 633 unsigned int count = 0; 634 635 /* 636 * This reserve space for the NUL string terminator. 637 */ 638 if (length > 0U) { 639 *numbuf = '\0'; 640 length--; 641 } 642 do { 643 char val = hex[(value & 0x0f) + ((mode == 'n') ? 0 : 16)]; 644 value >>= 4; 645 if (length > 0U) { 646 *numbuf++ = val; 647 *numbuf = '\0'; 648 length--; 649 } 650 if (width > 0) 651 width--; 652 count++; 653 /* 654 * If width is non zero then we need to add a label seperator. 655 * If value is non zero then we need to add another label and 656 * that requires a label seperator. 657 */ 658 if (width > 0 || value != 0) { 659 if (length > 0U) { 660 *numbuf++ = '.'; 661 *numbuf = '\0'; 662 length--; 663 } 664 if (width > 0) 665 width--; 666 count++; 667 } 668 } while (value != 0 || width > 0); 669 return (count); 670} 671 672static isc_result_t 673genname(char *name, int it, char *buffer, size_t length) { 674 char fmt[sizeof("%04000000000d")]; 675 char numbuf[128]; 676 char *cp; 677 char mode[2]; 678 int delta = 0; 679 isc_textregion_t r; 680 unsigned int n; 681 unsigned int width; 682 isc_boolean_t nibblemode; 683 684 r.base = buffer; 685 r.length = length; 686 687 while (*name != '\0') { 688 if (*name == '$') { 689 name++; 690 if (*name == '$') { 691 if (r.length == 0) 692 return (ISC_R_NOSPACE); 693 r.base[0] = *name++; 694 isc_textregion_consume(&r, 1); 695 continue; 696 } 697 nibblemode = ISC_FALSE; 698 strcpy(fmt, "%d"); 699 /* Get format specifier. */ 700 if (*name == '{' ) { 701 n = sscanf(name, "{%d,%u,%1[doxXnN]}", 702 &delta, &width, mode); 703 switch (n) { 704 case 1: 705 break; 706 case 2: 707 n = snprintf(fmt, sizeof(fmt), 708 "%%0%ud", width); 709 break; 710 case 3: 711 if (mode[0] == 'n' || mode[0] == 'N') 712 nibblemode = ISC_TRUE; 713 n = snprintf(fmt, sizeof(fmt), 714 "%%0%u%c", width, mode[0]); 715 break; 716 default: 717 return (DNS_R_SYNTAX); 718 } 719 if (n >= sizeof(fmt)) 720 return (ISC_R_NOSPACE); 721 /* Skip past closing brace. */ 722 while (*name != '\0' && *name++ != '}') 723 continue; 724 } 725 if (nibblemode) 726 n = nibbles(numbuf, sizeof(numbuf), width, 727 mode[0], it + delta); 728 else 729 n = snprintf(numbuf, sizeof(numbuf), fmt, 730 it + delta); 731 if (n >= sizeof(numbuf)) 732 return (ISC_R_NOSPACE); 733 cp = numbuf; 734 while (*cp != '\0') { 735 if (r.length == 0) 736 return (ISC_R_NOSPACE); 737 r.base[0] = *cp++; 738 isc_textregion_consume(&r, 1); 739 } 740 } else if (*name == '\\') { 741 if (r.length == 0) 742 return (ISC_R_NOSPACE); 743 r.base[0] = *name++; 744 isc_textregion_consume(&r, 1); 745 if (*name == '\0') 746 continue; 747 if (r.length == 0) 748 return (ISC_R_NOSPACE); 749 r.base[0] = *name++; 750 isc_textregion_consume(&r, 1); 751 } else { 752 if (r.length == 0) 753 return (ISC_R_NOSPACE); 754 r.base[0] = *name++; 755 isc_textregion_consume(&r, 1); 756 } 757 } 758 if (r.length == 0) 759 return (ISC_R_NOSPACE); 760 r.base[0] = '\0'; 761 return (ISC_R_SUCCESS); 762} 763 764static isc_result_t 765openfile_text(dns_loadctx_t *lctx, const char *master_file) { 766 return (isc_lex_openfile(lctx->lex, master_file)); 767} 768 769static isc_result_t 770openfile_raw(dns_loadctx_t *lctx, const char *master_file) { 771 isc_result_t result; 772 773 result = isc_stdio_open(master_file, "r", &lctx->f); 774 if (result != ISC_R_SUCCESS && result != ISC_R_FILENOTFOUND) { 775 UNEXPECTED_ERROR(__FILE__, __LINE__, 776 "isc_stdio_open() failed: %s", 777 isc_result_totext(result)); 778 } 779 780 return (result); 781} 782 783static isc_result_t 784generate(dns_loadctx_t *lctx, char *range, char *lhs, char *gtype, char *rhs, 785 const char *source, unsigned int line) 786{ 787 char *target_mem = NULL; 788 char *lhsbuf = NULL; 789 char *rhsbuf = NULL; 790 dns_fixedname_t ownerfixed; 791 dns_name_t *owner; 792 dns_rdata_t rdata = DNS_RDATA_INIT; 793 dns_rdatacallbacks_t *callbacks; 794 dns_rdatalist_t rdatalist; 795 dns_rdatatype_t type; 796 rdatalist_head_t head; 797 int n; 798 int target_size = MINTSIZ; /* only one rdata at a time */ 799 isc_buffer_t buffer; 800 isc_buffer_t target; 801 isc_result_t result; 802 isc_textregion_t r; 803 unsigned int start, stop, step, i; 804 dns_incctx_t *ictx; 805 806 ictx = lctx->inc; 807 callbacks = lctx->callbacks; 808 dns_fixedname_init(&ownerfixed); 809 owner = dns_fixedname_name(&ownerfixed); 810 ISC_LIST_INIT(head); 811 812 target_mem = isc_mem_get(lctx->mctx, target_size); 813 rhsbuf = isc_mem_get(lctx->mctx, DNS_MASTER_RHS); 814 lhsbuf = isc_mem_get(lctx->mctx, DNS_MASTER_LHS); 815 if (target_mem == NULL || rhsbuf == NULL || lhsbuf == NULL) { 816 result = ISC_R_NOMEMORY; 817 goto error_cleanup; 818 } 819 isc_buffer_init(&target, target_mem, target_size); 820 821 n = sscanf(range, "%u-%u/%u", &start, &stop, &step); 822 if (n < 2 || stop < start) { 823 (*callbacks->error)(callbacks, 824 "%s: %s:%lu: invalid range '%s'", 825 "$GENERATE", source, line, range); 826 result = DNS_R_SYNTAX; 827 goto insist_cleanup; 828 } 829 if (n == 2) 830 step = 1; 831 832 /* 833 * Get type. 834 */ 835 r.base = gtype; 836 r.length = strlen(gtype); 837 result = dns_rdatatype_fromtext(&type, &r); 838 if (result != ISC_R_SUCCESS) { 839 (*callbacks->error)(callbacks, 840 "%s: %s:%lu: unknown RR type '%s'", 841 "$GENERATE", source, line, gtype); 842 goto insist_cleanup; 843 } 844 845 ISC_LIST_INIT(rdatalist.rdata); 846 ISC_LINK_INIT(&rdatalist, link); 847 for (i = start; i <= stop; i += step) { 848 result = genname(lhs, i, lhsbuf, DNS_MASTER_LHS); 849 if (result != ISC_R_SUCCESS) 850 goto error_cleanup; 851 result = genname(rhs, i, rhsbuf, DNS_MASTER_RHS); 852 if (result != ISC_R_SUCCESS) 853 goto error_cleanup; 854 855 isc_buffer_init(&buffer, lhsbuf, strlen(lhsbuf)); 856 isc_buffer_add(&buffer, strlen(lhsbuf)); 857 isc_buffer_setactive(&buffer, strlen(lhsbuf)); 858 result = dns_name_fromtext(owner, &buffer, ictx->origin, 859 0, NULL); 860 if (result != ISC_R_SUCCESS) 861 goto error_cleanup; 862 863 if ((lctx->options & DNS_MASTER_ZONE) != 0 && 864 (lctx->options & DNS_MASTER_SLAVE) == 0 && 865 (lctx->options & DNS_MASTER_KEY) == 0 && 866 !dns_name_issubdomain(owner, lctx->top)) 867 { 868 char namebuf[DNS_NAME_FORMATSIZE]; 869 dns_name_format(owner, namebuf, sizeof(namebuf)); 870 /* 871 * Ignore out-of-zone data. 872 */ 873 (*callbacks->warn)(callbacks, 874 "%s:%lu: " 875 "ignoring out-of-zone data (%s)", 876 source, line, namebuf); 877 continue; 878 } 879 880 isc_buffer_init(&buffer, rhsbuf, strlen(rhsbuf)); 881 isc_buffer_add(&buffer, strlen(rhsbuf)); 882 isc_buffer_setactive(&buffer, strlen(rhsbuf)); 883 884 result = isc_lex_openbuffer(lctx->lex, &buffer); 885 if (result != ISC_R_SUCCESS) 886 goto error_cleanup; 887 888 isc_buffer_init(&target, target_mem, target_size); 889 result = dns_rdata_fromtext(&rdata, lctx->zclass, type, 890 lctx->lex, ictx->origin, 0, 891 lctx->mctx, &target, callbacks); 892 RUNTIME_CHECK(isc_lex_close(lctx->lex) == ISC_R_SUCCESS); 893 if (result != ISC_R_SUCCESS) 894 goto error_cleanup; 895 896 rdatalist.type = type; 897 rdatalist.covers = 0; 898 rdatalist.rdclass = lctx->zclass; 899 rdatalist.ttl = lctx->ttl; 900 ISC_LIST_PREPEND(head, &rdatalist, link); 901 ISC_LIST_APPEND(rdatalist.rdata, &rdata, link); 902 result = commit(callbacks, lctx, &head, owner, source, line); 903 ISC_LIST_UNLINK(rdatalist.rdata, &rdata, link); 904 if (result != ISC_R_SUCCESS) 905 goto error_cleanup; 906 dns_rdata_reset(&rdata); 907 } 908 result = ISC_R_SUCCESS; 909 goto cleanup; 910 911 error_cleanup: 912 if (result == ISC_R_NOMEMORY) 913 (*callbacks->error)(callbacks, "$GENERATE: %s", 914 dns_result_totext(result)); 915 else 916 (*callbacks->error)(callbacks, "$GENERATE: %s:%lu: %s", 917 source, line, dns_result_totext(result)); 918 919 insist_cleanup: 920 INSIST(result != ISC_R_SUCCESS); 921 922 cleanup: 923 if (target_mem != NULL) 924 isc_mem_put(lctx->mctx, target_mem, target_size); 925 if (lhsbuf != NULL) 926 isc_mem_put(lctx->mctx, lhsbuf, DNS_MASTER_LHS); 927 if (rhsbuf != NULL) 928 isc_mem_put(lctx->mctx, rhsbuf, DNS_MASTER_RHS); 929 return (result); 930} 931 932static void 933limit_ttl(dns_rdatacallbacks_t *callbacks, const char *source, unsigned int line, 934 isc_uint32_t *ttlp) 935{ 936 if (*ttlp > 0x7fffffffUL) { 937 (callbacks->warn)(callbacks, 938 "%s: %s:%lu: " 939 "$TTL %lu > MAXTTL, " 940 "setting $TTL to 0", 941 "dns_master_load", 942 source, line, 943 *ttlp); 944 *ttlp = 0; 945 } 946} 947 948static isc_result_t 949check_ns(dns_loadctx_t *lctx, isc_token_t *token, const char *source, 950 unsigned long line) 951{ 952 char *tmp = NULL; 953 isc_result_t result = ISC_R_SUCCESS; 954 void (*callback)(struct dns_rdatacallbacks *, const char *, ...); 955 956 if ((lctx->options & DNS_MASTER_FATALNS) != 0) 957 callback = lctx->callbacks->error; 958 else 959 callback = lctx->callbacks->warn; 960 961 if (token->type == isc_tokentype_string) { 962 struct in_addr addr; 963 struct in6_addr addr6; 964 965 tmp = isc_mem_strdup(lctx->mctx, DNS_AS_STR(*token)); 966 if (tmp == NULL) 967 return (ISC_R_NOMEMORY); 968 /* 969 * Catch both "1.2.3.4" and "1.2.3.4." 970 */ 971 if (tmp[strlen(tmp) - 1] == '.') 972 tmp[strlen(tmp) - 1] = '\0'; 973 if (inet_aton(tmp, &addr) == 1 || 974 inet_pton(AF_INET6, tmp, &addr6) == 1) 975 result = DNS_R_NSISADDRESS; 976 } 977 if (result != ISC_R_SUCCESS) 978 (*callback)(lctx->callbacks, "%s:%lu: NS record '%s' " 979 "appears to be an address", 980 source, line, DNS_AS_STR(*token)); 981 if (tmp != NULL) 982 isc_mem_free(lctx->mctx, tmp); 983 return (result); 984} 985 986static void 987check_wildcard(dns_incctx_t *ictx, const char *source, unsigned long line, 988 dns_rdatacallbacks_t *callbacks) 989{ 990 dns_name_t *name; 991 992 name = (ictx->glue != NULL) ? ictx->glue : ictx->current; 993 if (dns_name_internalwildcard(name)) { 994 char namebuf[DNS_NAME_FORMATSIZE]; 995 996 dns_name_format(name, namebuf, sizeof(namebuf)); 997 (*callbacks->warn)(callbacks, "%s:%lu: warning: ownername " 998 "'%s' contains an non-terminal wildcard", 999 source, line, namebuf); 1000 } 1001} 1002 1003static isc_result_t 1004load_text(dns_loadctx_t *lctx) { 1005 dns_rdataclass_t rdclass; 1006 dns_rdatatype_t type, covers; 1007 isc_uint32_t ttl_offset = 0; 1008 dns_name_t *new_name; 1009 isc_boolean_t current_has_delegation = ISC_FALSE; 1010 isc_boolean_t done = ISC_FALSE; 1011 isc_boolean_t finish_origin = ISC_FALSE; 1012 isc_boolean_t finish_include = ISC_FALSE; 1013 isc_boolean_t read_till_eol = ISC_FALSE; 1014 isc_boolean_t initialws; 1015 char *include_file = NULL; 1016 isc_token_t token; 1017 isc_result_t result = ISC_R_UNEXPECTED; 1018 rdatalist_head_t glue_list; 1019 rdatalist_head_t current_list; 1020 dns_rdatalist_t *this; 1021 dns_rdatalist_t *rdatalist = NULL; 1022 dns_rdatalist_t *new_rdatalist; 1023 int rdlcount = 0; 1024 int rdlcount_save = 0; 1025 int rdatalist_size = 0; 1026 isc_buffer_t buffer; 1027 isc_buffer_t target; 1028 isc_buffer_t target_ft; 1029 isc_buffer_t target_save; 1030 dns_rdata_t *rdata = NULL; 1031 dns_rdata_t *new_rdata; 1032 int rdcount = 0; 1033 int rdcount_save = 0; 1034 int rdata_size = 0; 1035 unsigned char *target_mem = NULL; 1036 int target_size = TSIZ; 1037 int new_in_use; 1038 unsigned int loop_cnt = 0; 1039 isc_mem_t *mctx; 1040 dns_rdatacallbacks_t *callbacks; 1041 dns_incctx_t *ictx; 1042 char *range = NULL; 1043 char *lhs = NULL; 1044 char *gtype = NULL; 1045 char *rhs = NULL; 1046 const char *source = ""; 1047 unsigned long line = 0; 1048 isc_boolean_t explicit_ttl; 1049 isc_stdtime_t now; 1050 char classname1[DNS_RDATACLASS_FORMATSIZE]; 1051 char classname2[DNS_RDATACLASS_FORMATSIZE]; 1052 unsigned int options = 0; 1053 1054 REQUIRE(DNS_LCTX_VALID(lctx)); 1055 callbacks = lctx->callbacks; 1056 mctx = lctx->mctx; 1057 ictx = lctx->inc; 1058 1059 ISC_LIST_INIT(glue_list); 1060 ISC_LIST_INIT(current_list); 1061 1062 isc_stdtime_get(&now); 1063 1064 /* 1065 * Allocate target_size of buffer space. This is greater than twice 1066 * the maximum individual RR data size. 1067 */ 1068 target_mem = isc_mem_get(mctx, target_size); 1069 if (target_mem == NULL) { 1070 result = ISC_R_NOMEMORY; 1071 goto log_and_cleanup; 1072 } 1073 isc_buffer_init(&target, target_mem, target_size); 1074 target_save = target; 1075 1076 if ((lctx->options & DNS_MASTER_CHECKNAMES) != 0) 1077 options |= DNS_RDATA_CHECKNAMES; 1078 if ((lctx->options & DNS_MASTER_CHECKNAMESFAIL) != 0) 1079 options |= DNS_RDATA_CHECKNAMESFAIL; 1080 if ((lctx->options & DNS_MASTER_CHECKMX) != 0) 1081 options |= DNS_RDATA_CHECKMX; 1082 if ((lctx->options & DNS_MASTER_CHECKMXFAIL) != 0) 1083 options |= DNS_RDATA_CHECKMXFAIL; 1084 source = isc_lex_getsourcename(lctx->lex); 1085 do { 1086 initialws = ISC_FALSE; 1087 line = isc_lex_getsourceline(lctx->lex); 1088 GETTOKEN(lctx->lex, ISC_LEXOPT_INITIALWS | ISC_LEXOPT_QSTRING, 1089 &token, ISC_TRUE); 1090 line = isc_lex_getsourceline(lctx->lex); 1091 1092 if (token.type == isc_tokentype_eof) { 1093 if (read_till_eol) 1094 WARNUNEXPECTEDEOF(lctx->lex); 1095 /* Pop the include stack? */ 1096 if (ictx->parent != NULL) { 1097 COMMITALL; 1098 lctx->inc = ictx->parent; 1099 ictx->parent = NULL; 1100 incctx_destroy(lctx->mctx, ictx); 1101 RUNTIME_CHECK(isc_lex_close(lctx->lex) == ISC_R_SUCCESS); 1102 line = isc_lex_getsourceline(lctx->lex); 1103 source = isc_lex_getsourcename(lctx->lex); 1104 ictx = lctx->inc; 1105 EXPECTEOL; 1106 continue; 1107 } 1108 done = ISC_TRUE; 1109 continue; 1110 } 1111 1112 if (token.type == isc_tokentype_eol) { 1113 read_till_eol = ISC_FALSE; 1114 continue; /* blank line */ 1115 } 1116 1117 if (read_till_eol) 1118 continue; 1119 1120 if (token.type == isc_tokentype_initialws) { 1121 /* 1122 * Still working on the same name. 1123 */ 1124 initialws = ISC_TRUE; 1125 } else if (token.type == isc_tokentype_string || 1126 token.type == isc_tokentype_qstring) { 1127 1128 /* 1129 * "$" Support. 1130 * 1131 * "$ORIGIN" and "$INCLUDE" can both take domain names. 1132 * The processing of "$ORIGIN" and "$INCLUDE" extends 1133 * across the normal domain name processing. 1134 */ 1135 1136 if (strcasecmp(DNS_AS_STR(token), "$ORIGIN") == 0) { 1137 GETTOKEN(lctx->lex, 0, &token, ISC_FALSE); 1138 finish_origin = ISC_TRUE; 1139 } else if (strcasecmp(DNS_AS_STR(token), 1140 "$TTL") == 0) { 1141 GETTOKEN(lctx->lex, 0, &token, ISC_FALSE); 1142 result = 1143 dns_ttl_fromtext(&token.value.as_textregion, 1144 &lctx->ttl); 1145 if (MANYERRS(lctx, result)) { 1146 SETRESULT(lctx, result); 1147 lctx->ttl = 0; 1148 } else if (result != ISC_R_SUCCESS) 1149 goto insist_and_cleanup; 1150 limit_ttl(callbacks, source, line, &lctx->ttl); 1151 lctx->default_ttl = lctx->ttl; 1152 lctx->default_ttl_known = ISC_TRUE; 1153 EXPECTEOL; 1154 continue; 1155 } else if (strcasecmp(DNS_AS_STR(token), 1156 "$INCLUDE") == 0) { 1157 COMMITALL; 1158 if ((lctx->options & DNS_MASTER_NOINCLUDE) 1159 != 0) 1160 { 1161 (callbacks->error)(callbacks, 1162 "%s: %s:%lu: $INCLUDE not allowed", 1163 "dns_master_load", 1164 source, line); 1165 result = DNS_R_REFUSED; 1166 goto insist_and_cleanup; 1167 } 1168 if (ttl_offset != 0) { 1169 (callbacks->error)(callbacks, 1170 "%s: %s:%lu: $INCLUDE " 1171 "may not be used with $DATE", 1172 "dns_master_load", 1173 source, line); 1174 result = DNS_R_SYNTAX; 1175 goto insist_and_cleanup; 1176 } 1177 GETTOKEN(lctx->lex, ISC_LEXOPT_QSTRING, &token, 1178 ISC_FALSE); 1179 if (include_file != NULL) 1180 isc_mem_free(mctx, include_file); 1181 include_file = isc_mem_strdup(mctx, 1182 DNS_AS_STR(token)); 1183 if (include_file == NULL) { 1184 result = ISC_R_NOMEMORY; 1185 goto log_and_cleanup; 1186 } 1187 GETTOKEN(lctx->lex, 0, &token, ISC_TRUE); 1188 1189 if (token.type == isc_tokentype_eol || 1190 token.type == isc_tokentype_eof) { 1191 if (token.type == isc_tokentype_eof) 1192 WARNUNEXPECTEDEOF(lctx->lex); 1193 isc_lex_ungettoken(lctx->lex, &token); 1194 /* 1195 * No origin field. 1196 */ 1197 result = pushfile(include_file, 1198 ictx->origin, lctx); 1199 if (MANYERRS(lctx, result)) { 1200 SETRESULT(lctx, result); 1201 LOGITFILE(result, include_file); 1202 continue; 1203 } else if (result != ISC_R_SUCCESS) { 1204 LOGITFILE(result, include_file); 1205 goto insist_and_cleanup; 1206 } 1207 ictx = lctx->inc; 1208 source = 1209 isc_lex_getsourcename(lctx->lex); 1210 line = isc_lex_getsourceline(lctx->lex); 1211 POST(line); 1212 continue; 1213 } 1214 /* 1215 * There is an origin field. Fall through 1216 * to domain name processing code and do 1217 * the actual inclusion later. 1218 */ 1219 finish_include = ISC_TRUE; 1220 } else if (strcasecmp(DNS_AS_STR(token), 1221 "$DATE") == 0) { 1222 isc_int64_t dump_time64; 1223 isc_stdtime_t dump_time, current_time; 1224 GETTOKEN(lctx->lex, 0, &token, ISC_FALSE); 1225 isc_stdtime_get(¤t_time); 1226 result = dns_time64_fromtext(DNS_AS_STR(token), 1227 &dump_time64); 1228 if (MANYERRS(lctx, result)) { 1229 SETRESULT(lctx, result); 1230 LOGIT(result); 1231 dump_time64 = 0; 1232 } else if (result != ISC_R_SUCCESS) 1233 goto log_and_cleanup; 1234 dump_time = (isc_stdtime_t)dump_time64; 1235 if (dump_time != dump_time64) { 1236 UNEXPECTED_ERROR(__FILE__, __LINE__, 1237 "%s: %s:%lu: $DATE outside epoch", 1238 "dns_master_load", source, line); 1239 result = ISC_R_UNEXPECTED; 1240 goto insist_and_cleanup; 1241 } 1242 if (dump_time > current_time) { 1243 UNEXPECTED_ERROR(__FILE__, __LINE__, 1244 "%s: %s:%lu: " 1245 "$DATE in future, using current date", 1246 "dns_master_load", source, line); 1247 dump_time = current_time; 1248 } 1249 ttl_offset = current_time - dump_time; 1250 EXPECTEOL; 1251 continue; 1252 } else if (strcasecmp(DNS_AS_STR(token), 1253 "$GENERATE") == 0) { 1254 /* 1255 * Lazy cleanup. 1256 */ 1257 if (range != NULL) 1258 isc_mem_free(mctx, range); 1259 if (lhs != NULL) 1260 isc_mem_free(mctx, lhs); 1261 if (gtype != NULL) 1262 isc_mem_free(mctx, gtype); 1263 if (rhs != NULL) 1264 isc_mem_free(mctx, rhs); 1265 range = lhs = gtype = rhs = NULL; 1266 /* RANGE */ 1267 GETTOKEN(lctx->lex, 0, &token, ISC_FALSE); 1268 range = isc_mem_strdup(mctx, 1269 DNS_AS_STR(token)); 1270 if (range == NULL) { 1271 result = ISC_R_NOMEMORY; 1272 goto log_and_cleanup; 1273 } 1274 /* LHS */ 1275 GETTOKEN(lctx->lex, 0, &token, ISC_FALSE); 1276 lhs = isc_mem_strdup(mctx, DNS_AS_STR(token)); 1277 if (lhs == NULL) { 1278 result = ISC_R_NOMEMORY; 1279 goto log_and_cleanup; 1280 } 1281 rdclass = 0; 1282 explicit_ttl = ISC_FALSE; 1283 /* CLASS? */ 1284 GETTOKEN(lctx->lex, 0, &token, ISC_FALSE); 1285 if (dns_rdataclass_fromtext(&rdclass, 1286 &token.value.as_textregion) 1287 == ISC_R_SUCCESS) { 1288 GETTOKEN(lctx->lex, 0, &token, 1289 ISC_FALSE); 1290 } 1291 /* TTL? */ 1292 if (dns_ttl_fromtext(&token.value.as_textregion, 1293 &lctx->ttl) 1294 == ISC_R_SUCCESS) { 1295 limit_ttl(callbacks, source, line, 1296 &lctx->ttl); 1297 lctx->ttl_known = ISC_TRUE; 1298 explicit_ttl = ISC_TRUE; 1299 GETTOKEN(lctx->lex, 0, &token, 1300 ISC_FALSE); 1301 } 1302 /* CLASS? */ 1303 if (rdclass == 0 && 1304 dns_rdataclass_fromtext(&rdclass, 1305 &token.value.as_textregion) 1306 == ISC_R_SUCCESS) 1307 GETTOKEN(lctx->lex, 0, &token, 1308 ISC_FALSE); 1309 /* TYPE */ 1310 gtype = isc_mem_strdup(mctx, 1311 DNS_AS_STR(token)); 1312 if (gtype == NULL) { 1313 result = ISC_R_NOMEMORY; 1314 goto log_and_cleanup; 1315 } 1316 /* RHS */ 1317 GETTOKEN(lctx->lex, ISC_LEXOPT_QSTRING, 1318 &token, ISC_FALSE); 1319 rhs = isc_mem_strdup(mctx, DNS_AS_STR(token)); 1320 if (rhs == NULL) { 1321 result = ISC_R_NOMEMORY; 1322 goto log_and_cleanup; 1323 } 1324 if (!lctx->ttl_known && 1325 !lctx->default_ttl_known) { 1326 (*callbacks->error)(callbacks, 1327 "%s: %s:%lu: no TTL specified", 1328 "dns_master_load", source, line); 1329 result = DNS_R_NOTTL; 1330 if (MANYERRS(lctx, result)) { 1331 SETRESULT(lctx, result); 1332 lctx->ttl = 0; 1333 } else if (result != ISC_R_SUCCESS) 1334 goto insist_and_cleanup; 1335 } else if (!explicit_ttl && 1336 lctx->default_ttl_known) { 1337 lctx->ttl = lctx->default_ttl; 1338 } 1339 /* 1340 * If the class specified does not match the 1341 * zone's class print out a error message and 1342 * exit. 1343 */ 1344 if (rdclass != 0 && rdclass != lctx->zclass) { 1345 goto bad_class; 1346 } 1347 result = generate(lctx, range, lhs, gtype, rhs, 1348 source, line); 1349 if (MANYERRS(lctx, result)) { 1350 SETRESULT(lctx, result); 1351 } else if (result != ISC_R_SUCCESS) 1352 goto insist_and_cleanup; 1353 EXPECTEOL; 1354 continue; 1355 } else if (strncasecmp(DNS_AS_STR(token), 1356 "$", 1) == 0) { 1357 (callbacks->error)(callbacks, 1358 "%s: %s:%lu: " 1359 "unknown $ directive '%s'", 1360 "dns_master_load", source, line, 1361 DNS_AS_STR(token)); 1362 result = DNS_R_SYNTAX; 1363 if (MANYERRS(lctx, result)) { 1364 SETRESULT(lctx, result); 1365 } else if (result != ISC_R_SUCCESS) 1366 goto insist_and_cleanup; 1367 } 1368 1369 /* 1370 * Normal processing resumes. 1371 * 1372 * Find a free name buffer. 1373 */ 1374 for (new_in_use = 0; new_in_use < NBUFS; new_in_use++) 1375 if (!ictx->in_use[new_in_use]) 1376 break; 1377 INSIST(new_in_use < NBUFS); 1378 dns_fixedname_init(&ictx->fixed[new_in_use]); 1379 new_name = dns_fixedname_name(&ictx->fixed[new_in_use]); 1380 isc_buffer_init(&buffer, token.value.as_region.base, 1381 token.value.as_region.length); 1382 isc_buffer_add(&buffer, token.value.as_region.length); 1383 isc_buffer_setactive(&buffer, 1384 token.value.as_region.length); 1385 result = dns_name_fromtext(new_name, &buffer, 1386 ictx->origin, 0, NULL); 1387 if (MANYERRS(lctx, result)) { 1388 SETRESULT(lctx, result); 1389 LOGIT(result); 1390 read_till_eol = ISC_TRUE; 1391 continue; 1392 } else if (result != ISC_R_SUCCESS) 1393 goto log_and_cleanup; 1394 1395 /* 1396 * Finish $ORIGIN / $INCLUDE processing if required. 1397 */ 1398 if (finish_origin) { 1399 if (ictx->origin_in_use != -1) 1400 ictx->in_use[ictx->origin_in_use] = 1401 ISC_FALSE; 1402 ictx->origin_in_use = new_in_use; 1403 ictx->in_use[ictx->origin_in_use] = ISC_TRUE; 1404 ictx->origin = new_name; 1405 finish_origin = ISC_FALSE; 1406 EXPECTEOL; 1407 continue; 1408 } 1409 if (finish_include) { 1410 finish_include = ISC_FALSE; 1411 result = pushfile(include_file, new_name, lctx); 1412 if (MANYERRS(lctx, result)) { 1413 SETRESULT(lctx, result); 1414 LOGITFILE(result, include_file); 1415 continue; 1416 } else if (result != ISC_R_SUCCESS) { 1417 LOGITFILE(result, include_file); 1418 goto insist_and_cleanup; 1419 } 1420 ictx = lctx->inc; 1421 source = isc_lex_getsourcename(lctx->lex); 1422 line = isc_lex_getsourceline(lctx->lex); 1423 POST(line); 1424 continue; 1425 } 1426 1427 /* 1428 * "$" Processing Finished 1429 */ 1430 1431 /* 1432 * If we are processing glue and the new name does 1433 * not match the current glue name, commit the glue 1434 * and pop stacks leaving us in 'normal' processing 1435 * state. Linked lists are undone by commit(). 1436 */ 1437 if (ictx->glue != NULL && 1438 dns_name_compare(ictx->glue, new_name) != 0) { 1439 result = commit(callbacks, lctx, &glue_list, 1440 ictx->glue, source, 1441 ictx->glue_line); 1442 if (MANYERRS(lctx, result)) { 1443 SETRESULT(lctx, result); 1444 } else if (result != ISC_R_SUCCESS) 1445 goto insist_and_cleanup; 1446 if (ictx->glue_in_use != -1) 1447 ictx->in_use[ictx->glue_in_use] = 1448 ISC_FALSE; 1449 ictx->glue_in_use = -1; 1450 ictx->glue = NULL; 1451 rdcount = rdcount_save; 1452 rdlcount = rdlcount_save; 1453 target = target_save; 1454 } 1455 1456 /* 1457 * If we are in 'normal' processing state and the new 1458 * name does not match the current name, see if the 1459 * new name is for glue and treat it as such, 1460 * otherwise we have a new name so commit what we 1461 * have. 1462 */ 1463 if ((ictx->glue == NULL) && (ictx->current == NULL || 1464 dns_name_compare(ictx->current, new_name) != 0)) { 1465 if (current_has_delegation && 1466 is_glue(¤t_list, new_name)) { 1467 rdcount_save = rdcount; 1468 rdlcount_save = rdlcount; 1469 target_save = target; 1470 ictx->glue = new_name; 1471 ictx->glue_in_use = new_in_use; 1472 ictx->in_use[ictx->glue_in_use] = 1473 ISC_TRUE; 1474 } else { 1475 result = commit(callbacks, lctx, 1476 ¤t_list, 1477 ictx->current, 1478 source, 1479 ictx->current_line); 1480 if (MANYERRS(lctx, result)) { 1481 SETRESULT(lctx, result); 1482 } else if (result != ISC_R_SUCCESS) 1483 goto insist_and_cleanup; 1484 rdcount = 0; 1485 rdlcount = 0; 1486 if (ictx->current_in_use != -1) 1487 ictx->in_use[ictx->current_in_use] = 1488 ISC_FALSE; 1489 ictx->current_in_use = new_in_use; 1490 ictx->in_use[ictx->current_in_use] = 1491 ISC_TRUE; 1492 ictx->current = new_name; 1493 current_has_delegation = ISC_FALSE; 1494 isc_buffer_init(&target, target_mem, 1495 target_size); 1496 } 1497 /* 1498 * Check for internal wildcards. 1499 */ 1500 if ((lctx->options & DNS_MASTER_CHECKWILDCARD) 1501 != 0) 1502 check_wildcard(ictx, source, line, 1503 callbacks); 1504 1505 } 1506 if ((lctx->options & DNS_MASTER_ZONE) != 0 && 1507 (lctx->options & DNS_MASTER_SLAVE) == 0 && 1508 (lctx->options & DNS_MASTER_KEY) == 0 && 1509 !dns_name_issubdomain(new_name, lctx->top)) 1510 { 1511 char namebuf[DNS_NAME_FORMATSIZE]; 1512 dns_name_format(new_name, namebuf, 1513 sizeof(namebuf)); 1514 /* 1515 * Ignore out-of-zone data. 1516 */ 1517 (*callbacks->warn)(callbacks, 1518 "%s:%lu: " 1519 "ignoring out-of-zone data (%s)", 1520 source, line, namebuf); 1521 ictx->drop = ISC_TRUE; 1522 } else 1523 ictx->drop = ISC_FALSE; 1524 } else { 1525 UNEXPECTED_ERROR(__FILE__, __LINE__, 1526 "%s:%lu: isc_lex_gettoken() returned " 1527 "unexpected token type (%d)", 1528 source, line, token.type); 1529 result = ISC_R_UNEXPECTED; 1530 if (MANYERRS(lctx, result)) { 1531 SETRESULT(lctx, result); 1532 LOGIT(result); 1533 continue; 1534 } else if (result != ISC_R_SUCCESS) 1535 goto insist_and_cleanup; 1536 } 1537 1538 /* 1539 * Find TTL, class and type. Both TTL and class are optional 1540 * and may occur in any order if they exist. TTL and class 1541 * come before type which must exist. 1542 * 1543 * [<TTL>] [<class>] <type> <RDATA> 1544 * [<class>] [<TTL>] <type> <RDATA> 1545 */ 1546 1547 type = 0; 1548 rdclass = 0; 1549 1550 GETTOKEN(lctx->lex, 0, &token, initialws); 1551 1552 if (initialws) { 1553 if (token.type == isc_tokentype_eol) { 1554 read_till_eol = ISC_FALSE; 1555 continue; /* blank line */ 1556 } 1557 1558 if (token.type == isc_tokentype_eof) { 1559 WARNUNEXPECTEDEOF(lctx->lex); 1560 read_till_eol = ISC_FALSE; 1561 isc_lex_ungettoken(lctx->lex, &token); 1562 continue; 1563 } 1564 1565 if (ictx->current == NULL) { 1566 (*callbacks->error)(callbacks, 1567 "%s:%lu: no current owner name", 1568 source, line); 1569 result = DNS_R_NOOWNER; 1570 if (MANYERRS(lctx, result)) { 1571 SETRESULT(lctx, result); 1572 read_till_eol = ISC_TRUE; 1573 continue; 1574 } else if (result != ISC_R_SUCCESS) 1575 goto insist_and_cleanup; 1576 } 1577 } 1578 1579 if (dns_rdataclass_fromtext(&rdclass, 1580 &token.value.as_textregion) 1581 == ISC_R_SUCCESS) 1582 GETTOKEN(lctx->lex, 0, &token, ISC_FALSE); 1583 1584 explicit_ttl = ISC_FALSE; 1585 if (dns_ttl_fromtext(&token.value.as_textregion, &lctx->ttl) 1586 == ISC_R_SUCCESS) { 1587 limit_ttl(callbacks, source, line, &lctx->ttl); 1588 explicit_ttl = ISC_TRUE; 1589 lctx->ttl_known = ISC_TRUE; 1590 GETTOKEN(lctx->lex, 0, &token, ISC_FALSE); 1591 } 1592 1593 if (token.type != isc_tokentype_string) { 1594 UNEXPECTED_ERROR(__FILE__, __LINE__, 1595 "isc_lex_gettoken() returned unexpected token type"); 1596 result = ISC_R_UNEXPECTED; 1597 if (MANYERRS(lctx, result)) { 1598 SETRESULT(lctx, result); 1599 read_till_eol = ISC_TRUE; 1600 continue; 1601 } else if (result != ISC_R_SUCCESS) 1602 goto insist_and_cleanup; 1603 } 1604 1605 if (rdclass == 0 && 1606 dns_rdataclass_fromtext(&rdclass, 1607 &token.value.as_textregion) 1608 == ISC_R_SUCCESS) 1609 GETTOKEN(lctx->lex, 0, &token, ISC_FALSE); 1610 1611 if (token.type != isc_tokentype_string) { 1612 UNEXPECTED_ERROR(__FILE__, __LINE__, 1613 "isc_lex_gettoken() returned unexpected token type"); 1614 result = ISC_R_UNEXPECTED; 1615 if (MANYERRS(lctx, result)) { 1616 SETRESULT(lctx, result); 1617 read_till_eol = ISC_TRUE; 1618 continue; 1619 } else if (result != ISC_R_SUCCESS) 1620 goto insist_and_cleanup; 1621 } 1622 1623 result = dns_rdatatype_fromtext(&type, 1624 &token.value.as_textregion); 1625 if (result != ISC_R_SUCCESS) { 1626 (*callbacks->warn)(callbacks, 1627 "%s:%lu: unknown RR type '%.*s'", 1628 source, line, 1629 token.value.as_textregion.length, 1630 token.value.as_textregion.base); 1631 if (MANYERRS(lctx, result)) { 1632 SETRESULT(lctx, result); 1633 read_till_eol = ISC_TRUE; 1634 continue; 1635 } else if (result != ISC_R_SUCCESS) 1636 goto insist_and_cleanup; 1637 } 1638 1639 /* 1640 * If the class specified does not match the zone's class 1641 * print out a error message and exit. 1642 */ 1643 if (rdclass != 0 && rdclass != lctx->zclass) { 1644 bad_class: 1645 1646 dns_rdataclass_format(rdclass, classname1, 1647 sizeof(classname1)); 1648 dns_rdataclass_format(lctx->zclass, classname2, 1649 sizeof(classname2)); 1650 (*callbacks->error)(callbacks, 1651 "%s:%lu: class '%s' != " 1652 "zone class '%s'", 1653 source, line, 1654 classname1, classname2); 1655 result = DNS_R_BADCLASS; 1656 if (MANYERRS(lctx, result)) { 1657 SETRESULT(lctx, result); 1658 read_till_eol = ISC_TRUE; 1659 continue; 1660 } else if (result != ISC_R_SUCCESS) 1661 goto insist_and_cleanup; 1662 } 1663 1664 if (type == dns_rdatatype_ns && ictx->glue == NULL) 1665 current_has_delegation = ISC_TRUE; 1666 1667 /* 1668 * RFC1123: MD and MF are not allowed to be loaded from 1669 * master files. 1670 */ 1671 if ((lctx->options & DNS_MASTER_ZONE) != 0 && 1672 (lctx->options & DNS_MASTER_SLAVE) == 0 && 1673 (type == dns_rdatatype_md || type == dns_rdatatype_mf)) { 1674 char typename[DNS_RDATATYPE_FORMATSIZE]; 1675 1676 result = DNS_R_OBSOLETE; 1677 1678 dns_rdatatype_format(type, typename, sizeof(typename)); 1679 (*callbacks->error)(callbacks, 1680 "%s:%lu: %s '%s': %s", 1681 source, line, 1682 "type", typename, 1683 dns_result_totext(result)); 1684 if (MANYERRS(lctx, result)) { 1685 SETRESULT(lctx, result); 1686 } else 1687 goto insist_and_cleanup; 1688 } 1689 1690 /* 1691 * Find a rdata structure. 1692 */ 1693 if (rdcount == rdata_size) { 1694 new_rdata = grow_rdata(rdata_size + RDSZ, rdata, 1695 rdata_size, ¤t_list, 1696 &glue_list, mctx); 1697 if (new_rdata == NULL) { 1698 result = ISC_R_NOMEMORY; 1699 goto log_and_cleanup; 1700 } 1701 rdata_size += RDSZ; 1702 rdata = new_rdata; 1703 } 1704 1705 /* 1706 * Peek at the NS record. 1707 */ 1708 if (type == dns_rdatatype_ns && 1709 lctx->zclass == dns_rdataclass_in && 1710 (lctx->options & DNS_MASTER_CHECKNS) != 0) { 1711 1712 GETTOKEN(lctx->lex, 0, &token, ISC_FALSE); 1713 result = check_ns(lctx, &token, source, line); 1714 isc_lex_ungettoken(lctx->lex, &token); 1715 if ((lctx->options & DNS_MASTER_FATALNS) != 0) { 1716 if (MANYERRS(lctx, result)) { 1717 SETRESULT(lctx, result); 1718 } else if (result != ISC_R_SUCCESS) 1719 goto insist_and_cleanup; 1720 } 1721 } 1722 1723 /* 1724 * Check owner name. 1725 */ 1726 options &= ~DNS_RDATA_CHECKREVERSE; 1727 if ((lctx->options & DNS_MASTER_CHECKNAMES) != 0) { 1728 isc_boolean_t ok; 1729 dns_name_t *name; 1730 1731 name = (ictx->glue != NULL) ? ictx->glue : 1732 ictx->current; 1733 ok = dns_rdata_checkowner(name, lctx->zclass, type, 1734 ISC_TRUE); 1735 if (!ok) { 1736 char namebuf[DNS_NAME_FORMATSIZE]; 1737 const char *desc; 1738 dns_name_format(name, namebuf, sizeof(namebuf)); 1739 result = DNS_R_BADOWNERNAME; 1740 desc = dns_result_totext(result); 1741 if ((lctx->options & DNS_MASTER_CHECKNAMESFAIL) != 0) { 1742 (*callbacks->error)(callbacks, 1743 "%s:%lu: %s: %s", 1744 source, line, 1745 namebuf, desc); 1746 if (MANYERRS(lctx, result)) { 1747 SETRESULT(lctx, result); 1748 } else if (result != ISC_R_SUCCESS) 1749 goto cleanup; 1750 } else { 1751 (*callbacks->warn)(callbacks, 1752 "%s:%lu: %s: %s", 1753 source, line, 1754 namebuf, desc); 1755 } 1756 } 1757 if (type == dns_rdatatype_ptr && 1758 (dns_name_issubdomain(name, &in_addr_arpa) || 1759 dns_name_issubdomain(name, &ip6_arpa) || 1760 dns_name_issubdomain(name, &ip6_int))) 1761 options |= DNS_RDATA_CHECKREVERSE; 1762 } 1763 1764 /* 1765 * Read rdata contents. 1766 */ 1767 dns_rdata_init(&rdata[rdcount]); 1768 target_ft = target; 1769 result = dns_rdata_fromtext(&rdata[rdcount], lctx->zclass, 1770 type, lctx->lex, ictx->origin, 1771 options, lctx->mctx, &target, 1772 callbacks); 1773 if (MANYERRS(lctx, result)) { 1774 SETRESULT(lctx, result); 1775 continue; 1776 } else if (result != ISC_R_SUCCESS) 1777 goto insist_and_cleanup; 1778 1779 if (ictx->drop) { 1780 target = target_ft; 1781 continue; 1782 } 1783 1784 if (type == dns_rdatatype_soa && 1785 (lctx->options & DNS_MASTER_ZONE) != 0 && 1786 dns_name_compare(ictx->current, lctx->top) != 0) { 1787 char namebuf[DNS_NAME_FORMATSIZE]; 1788 dns_name_format(ictx->current, namebuf, 1789 sizeof(namebuf)); 1790 (*callbacks->error)(callbacks, "%s:%lu: SOA " 1791 "record not at top of zone (%s)", 1792 source, line, namebuf); 1793 result = DNS_R_NOTZONETOP; 1794 if (MANYERRS(lctx, result)) { 1795 SETRESULT(lctx, result); 1796 read_till_eol = ISC_TRUE; 1797 target = target_ft; 1798 continue; 1799 } else if (result != ISC_R_SUCCESS) 1800 goto insist_and_cleanup; 1801 } 1802 1803 1804 if (type == dns_rdatatype_rrsig || 1805 type == dns_rdatatype_sig) 1806 covers = dns_rdata_covers(&rdata[rdcount]); 1807 else 1808 covers = 0; 1809 1810 if (!lctx->ttl_known && !lctx->default_ttl_known) { 1811 if (type == dns_rdatatype_soa) { 1812 (*callbacks->warn)(callbacks, 1813 "%s:%lu: no TTL specified; " 1814 "using SOA MINTTL instead", 1815 source, line); 1816 lctx->ttl = dns_soa_getminimum(&rdata[rdcount]); 1817 limit_ttl(callbacks, source, line, &lctx->ttl); 1818 lctx->default_ttl = lctx->ttl; 1819 lctx->default_ttl_known = ISC_TRUE; 1820 } else if ((lctx->options & DNS_MASTER_HINT) != 0) { 1821 /* 1822 * Zero TTL's are fine for hints. 1823 */ 1824 lctx->ttl = 0; 1825 lctx->default_ttl = lctx->ttl; 1826 lctx->default_ttl_known = ISC_TRUE; 1827 } else { 1828 (*callbacks->warn)(callbacks, 1829 "%s:%lu: no TTL specified; " 1830 "zone rejected", 1831 source, line); 1832 result = DNS_R_NOTTL; 1833 if (MANYERRS(lctx, result)) { 1834 SETRESULT(lctx, result); 1835 lctx->ttl = 0; 1836 } else { 1837 goto insist_and_cleanup; 1838 } 1839 } 1840 } else if (!explicit_ttl && lctx->default_ttl_known) { 1841 lctx->ttl = lctx->default_ttl; 1842 } else if (!explicit_ttl && lctx->warn_1035) { 1843 (*callbacks->warn)(callbacks, 1844 "%s:%lu: " 1845 "using RFC1035 TTL semantics", 1846 source, line); 1847 lctx->warn_1035 = ISC_FALSE; 1848 } 1849 1850 if (type == dns_rdatatype_rrsig && lctx->warn_sigexpired) { 1851 dns_rdata_rrsig_t sig; 1852 result = dns_rdata_tostruct(&rdata[rdcount], &sig, 1853 NULL); 1854 RUNTIME_CHECK(result == ISC_R_SUCCESS); 1855 if (isc_serial_lt(sig.timeexpire, now)) { 1856 (*callbacks->warn)(callbacks, 1857 "%s:%lu: " 1858 "signature has expired", 1859 source, line); 1860…
Large files files are truncated, but you can click here to view the full file