master.c revision 1.14 1 /* $NetBSD: master.c,v 1.14 2025/01/26 16:25:23 christos Exp $ */
2
3 /*
4 * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
5 *
6 * SPDX-License-Identifier: MPL-2.0
7 *
8 * This Source Code Form is subject to the terms of the Mozilla Public
9 * License, v. 2.0. If a copy of the MPL was not distributed with this
10 * file, you can obtain one at https://mozilla.org/MPL/2.0/.
11 *
12 * See the COPYRIGHT file distributed with this work for additional
13 * information regarding copyright ownership.
14 */
15
16 /*! \file */
17
18 #include <inttypes.h>
19 #include <stdbool.h>
20
21 #include <isc/async.h>
22 #include <isc/atomic.h>
23 #include <isc/lex.h>
24 #include <isc/loop.h>
25 #include <isc/magic.h>
26 #include <isc/mem.h>
27 #include <isc/refcount.h>
28 #include <isc/result.h>
29 #include <isc/serial.h>
30 #include <isc/stdio.h>
31 #include <isc/stdtime.h>
32 #include <isc/string.h>
33 #include <isc/util.h>
34 #include <isc/work.h>
35
36 #include <dns/callbacks.h>
37 #include <dns/fixedname.h>
38 #include <dns/master.h>
39 #include <dns/name.h>
40 #include <dns/rdata.h>
41 #include <dns/rdataclass.h>
42 #include <dns/rdatalist.h>
43 #include <dns/rdataset.h>
44 #include <dns/rdatastruct.h>
45 #include <dns/rdatatype.h>
46 #include <dns/soa.h>
47 #include <dns/time.h>
48 #include <dns/ttl.h>
49
50 /*!
51 * Grow the number of dns_rdatalist_t (#RDLSZ) and dns_rdata_t (#RDSZ)
52 * structures by these sizes when we need to.
53 *
54 */
55 /*% RDLSZ reflects the number of different types with the same name expected. */
56 #define RDLSZ 32
57 /*%
58 * RDSZ reflects the number of rdata expected at a give name that can fit into
59 * 64k.
60 */
61 #define RDSZ 512
62
63 #define NBUFS 4
64 #define MAXWIRESZ 255
65
66 /*%
67 * Target buffer size and minimum target size.
68 * MINTSIZ must be big enough to hold the largest rdata record.
69 * \brief
70 * TSIZ >= MINTSIZ
71 */
72 #define TSIZ (128 * 1024)
73 /*%
74 * max message size - header - root - type - class - ttl - rdlen
75 */
76 #define MINTSIZ DNS_RDATA_MAXLENGTH
77 /*%
78 * Size for tokens in the presentation format,
79 * The largest tokens are the base64 blocks in KEY and CERT records,
80 * Largest key allowed is about 1372 bytes but
81 * there is no fixed upper bound on CERT records.
82 * 2K is too small for some X.509s, 8K is overkill.
83 */
84 #define TOKENSIZ (8 * 1024)
85
86 /*%
87 * Buffers sizes for $GENERATE.
88 */
89 #define DNS_MASTER_LHS 2048
90 #define DNS_MASTER_RHS MINTSIZ
91
92 #define CHECKNAMESFAIL(x) (((x) & DNS_MASTER_CHECKNAMESFAIL) != 0)
93
94 typedef ISC_LIST(dns_rdatalist_t) rdatalist_head_t;
95
96 typedef struct dns_incctx dns_incctx_t;
97
98 /*%
99 * Master file load state.
100 */
101
102 struct dns_loadctx {
103 unsigned int magic;
104 isc_mem_t *mctx;
105 dns_masterformat_t format;
106
107 dns_rdatacallbacks_t *callbacks;
108 dns_loaddonefunc_t done;
109 void *done_arg;
110
111 /* Common methods */
112 isc_result_t (*openfile)(dns_loadctx_t *lctx, const char *filename);
113 isc_result_t (*load)(dns_loadctx_t *lctx);
114
115 /* Members used by all formats */
116 uint32_t maxttl;
117
118 /* Members specific to the text format: */
119 isc_lex_t *lex;
120 bool keep_lex;
121 unsigned int options;
122 bool ttl_known;
123 bool default_ttl_known;
124 bool warn_1035;
125 bool warn_tcr;
126 bool warn_sigexpired;
127 bool seen_include;
128 uint32_t ttl;
129 uint32_t default_ttl;
130 dns_rdataclass_t zclass;
131 dns_fixedname_t fixed_top;
132 dns_name_t *top; /*%< top of zone */
133
134 /* Members specific to the raw format: */
135 FILE *f;
136 bool first;
137 dns_masterrawheader_t header;
138
139 /* Which fixed buffers we are using? */
140 isc_result_t result;
141
142 /* Atomic */
143 isc_refcount_t references;
144 atomic_bool canceled;
145
146 /* locked by lock */
147 dns_incctx_t *inc;
148 uint32_t resign;
149 isc_stdtime_t now;
150
151 dns_masterincludecb_t include_cb;
152 void *include_arg;
153 };
154
155 struct dns_incctx {
156 dns_incctx_t *parent;
157 dns_name_t *origin;
158 dns_name_t *current;
159 dns_name_t *glue;
160 dns_fixedname_t fixed[NBUFS]; /* working buffers */
161 unsigned int in_use[NBUFS]; /* covert to bitmap? */
162 int glue_in_use;
163 int current_in_use;
164 int origin_in_use;
165 bool origin_changed;
166 bool drop;
167 unsigned int glue_line;
168 unsigned int current_line;
169 };
170
171 #define DNS_LCTX_MAGIC ISC_MAGIC('L', 'c', 't', 'x')
172 #define DNS_LCTX_VALID(lctx) ISC_MAGIC_VALID(lctx, DNS_LCTX_MAGIC)
173
174 #define DNS_AS_STR(t) ((t).value.as_textregion.base)
175
176 static isc_result_t
177 openfile_text(dns_loadctx_t *lctx, const char *master_file);
178
179 static isc_result_t
180 load_text(dns_loadctx_t *lctx);
181
182 static isc_result_t
183 openfile_raw(dns_loadctx_t *lctx, const char *master_file);
184
185 static isc_result_t
186 load_raw(dns_loadctx_t *lctx);
187
188 static isc_result_t
189 pushfile(const char *master_file, dns_name_t *origin, dns_loadctx_t *lctx);
190
191 static isc_result_t
192 commit(dns_rdatacallbacks_t *, dns_loadctx_t *, rdatalist_head_t *,
193 dns_name_t *, const char *, unsigned int);
194
195 static bool
196 is_glue(rdatalist_head_t *, dns_name_t *);
197
198 static dns_rdatalist_t *
199 grow_rdatalist(int, dns_rdatalist_t *, int, rdatalist_head_t *,
200 rdatalist_head_t *, isc_mem_t *mctx);
201
202 static dns_rdata_t *
203 grow_rdata(int, dns_rdata_t *, int, rdatalist_head_t *, rdatalist_head_t *,
204 isc_mem_t *);
205
206 static void
207 loadctx_destroy(dns_loadctx_t *lctx);
208
209 #define LCTX_MANYERRORS(lctx) (((lctx)->options & DNS_MASTER_MANYERRORS) != 0)
210
211 #define GETTOKENERR(lexer, options, token, eol, err) \
212 do { \
213 result = gettoken(lexer, options, token, eol, callbacks); \
214 switch (result) { \
215 case ISC_R_SUCCESS: \
216 break; \
217 case ISC_R_NOTFILE: \
218 /* Treat "bad" $INCLUDE as eof. */ \
219 if (ictx->parent != NULL && LCTX_MANYERRORS(lctx)) { \
220 SETRESULT(lctx, result); \
221 COMMITALL; \
222 lctx->inc = ictx->parent; \
223 ictx->parent = NULL; \
224 incctx_destroy(lctx->mctx, ictx); \
225 RUNTIME_CHECK(isc_lex_close(lctx->lex) == \
226 ISC_R_SUCCESS); \
227 line = isc_lex_getsourceline(lctx->lex); \
228 POST(line); \
229 source = isc_lex_getsourcename(lctx->lex); \
230 ictx = lctx->inc; \
231 continue; \
232 } \
233 goto insist_and_cleanup; \
234 case ISC_R_UNEXPECTED: \
235 goto insist_and_cleanup; \
236 default: \
237 if (MANYERRS(lctx, result)) { \
238 SETRESULT(lctx, result); \
239 LOGIT(result); \
240 read_till_eol = true; \
241 err goto next_line; \
242 } else \
243 goto log_and_cleanup; \
244 } \
245 if ((token)->type == isc_tokentype_special) { \
246 result = DNS_R_SYNTAX; \
247 if (MANYERRS(lctx, result)) { \
248 SETRESULT(lctx, result); \
249 LOGIT(result); \
250 read_till_eol = true; \
251 goto next_line; \
252 } else \
253 goto log_and_cleanup; \
254 } \
255 } while (0)
256 #define GETTOKEN(lexer, options, token, eol) \
257 GETTOKENERR(lexer, options, token, eol, {})
258
259 #define COMMITALL \
260 do { \
261 result = commit(callbacks, lctx, ¤t_list, ictx->current, \
262 source, ictx->current_line); \
263 if (MANYERRS(lctx, result)) { \
264 SETRESULT(lctx, result); \
265 } else if (result != ISC_R_SUCCESS) \
266 goto insist_and_cleanup; \
267 result = commit(callbacks, lctx, &glue_list, ictx->glue, \
268 source, ictx->glue_line); \
269 if (MANYERRS(lctx, result)) { \
270 SETRESULT(lctx, result); \
271 } else if (result != ISC_R_SUCCESS) \
272 goto insist_and_cleanup; \
273 rdcount = 0; \
274 rdlcount = 0; \
275 isc_buffer_init(&target, target_mem, target_size); \
276 rdcount_save = rdcount; \
277 rdlcount_save = rdlcount; \
278 } while (0)
279
280 #define WARNUNEXPECTEDEOF(lexer) \
281 do { \
282 if (isc_lex_isfile(lexer)) \
283 (*callbacks->warn)(callbacks, \
284 "%s: file does not end with " \
285 "newline", \
286 source); \
287 } while (0)
288
289 #define EXPECTEOL \
290 do { \
291 GETTOKEN(lctx->lex, 0, &token, true); \
292 if (token.type != isc_tokentype_eol) { \
293 isc_lex_ungettoken(lctx->lex, &token); \
294 result = DNS_R_EXTRATOKEN; \
295 if (MANYERRS(lctx, result)) { \
296 SETRESULT(lctx, result); \
297 LOGIT(result); \
298 read_till_eol = true; \
299 break; \
300 } else if (result != ISC_R_SUCCESS) \
301 goto log_and_cleanup; \
302 } \
303 } while (0)
304
305 #define MANYERRS(lctx, result) \
306 ((result != ISC_R_SUCCESS) && (result != ISC_R_IOERROR) && \
307 LCTX_MANYERRORS(lctx))
308
309 #define SETRESULT(lctx, r) \
310 if ((lctx)->result == ISC_R_SUCCESS) { \
311 (lctx)->result = r; \
312 }
313
314 #define LOGITFILE(result, filename) \
315 if (result == ISC_R_INVALIDFILE || result == ISC_R_FILENOTFOUND || \
316 result == ISC_R_IOERROR || result == ISC_R_TOOMANYOPENFILES || \
317 result == ISC_R_NOPERM) \
318 (*callbacks->error)(callbacks, "%s: %s:%lu: %s: %s", \
319 "dns_master_load", source, line, filename, \
320 isc_result_totext(result)); \
321 else \
322 LOGIT(result)
323
324 #define LOGIT(result) \
325 if (result == ISC_R_NOMEMORY) \
326 (*callbacks->error)(callbacks, "dns_master_load: %s", \
327 isc_result_totext(result)); \
328 else \
329 (*callbacks->error)(callbacks, "%s: %s:%lu: %s", \
330 "dns_master_load", source, line, \
331 isc_result_totext(result))
332
333 static unsigned char in_addr_arpa_data[] = "\007IN-ADDR\004ARPA";
334 static unsigned char in_addr_arpa_offsets[] = { 0, 8, 13 };
335 static dns_name_t const in_addr_arpa =
336 DNS_NAME_INITABSOLUTE(in_addr_arpa_data, in_addr_arpa_offsets);
337
338 static unsigned char ip6_int_data[] = "\003IP6\003INT";
339 static unsigned char ip6_int_offsets[] = { 0, 4, 8 };
340 static dns_name_t const ip6_int = DNS_NAME_INITABSOLUTE(ip6_int_data,
341 ip6_int_offsets);
342
343 static unsigned char ip6_arpa_data[] = "\003IP6\004ARPA";
344 static unsigned char ip6_arpa_offsets[] = { 0, 4, 9 };
345 static dns_name_t const ip6_arpa = DNS_NAME_INITABSOLUTE(ip6_arpa_data,
346 ip6_arpa_offsets);
347
348 static bool
349 dns_master_isprimary(dns_loadctx_t *lctx) {
350 return (lctx->options & DNS_MASTER_ZONE) != 0 &&
351 (lctx->options & DNS_MASTER_SECONDARY) == 0 &&
352 (lctx->options & DNS_MASTER_KEY) == 0;
353 }
354
355 static isc_result_t
356 gettoken(isc_lex_t *lex, unsigned int options, isc_token_t *token, bool eol,
357 dns_rdatacallbacks_t *callbacks) {
358 isc_result_t result;
359
360 options |= ISC_LEXOPT_EOL | ISC_LEXOPT_EOF | ISC_LEXOPT_DNSMULTILINE |
361 ISC_LEXOPT_ESCAPE;
362 result = isc_lex_gettoken(lex, options, token);
363 if (result != ISC_R_SUCCESS) {
364 switch (result) {
365 case ISC_R_NOMEMORY:
366 return ISC_R_NOMEMORY;
367 default:
368 (*callbacks->error)(callbacks,
369 "dns_master_load: %s:%lu:"
370 " isc_lex_gettoken() failed: %s",
371 isc_lex_getsourcename(lex),
372 isc_lex_getsourceline(lex),
373 isc_result_totext(result));
374 return result;
375 }
376 /*NOTREACHED*/
377 }
378 if (eol != true) {
379 if (token->type == isc_tokentype_eol ||
380 token->type == isc_tokentype_eof)
381 {
382 {
383 unsigned long int line;
384 const char *what;
385 const char *file;
386 file = isc_lex_getsourcename(lex);
387 line = isc_lex_getsourceline(lex);
388 if (token->type == isc_tokentype_eol) {
389 line--;
390 what = "line";
391 } else {
392 what = "file";
393 }
394 (*callbacks->error)(callbacks,
395 "dns_master_load: %s:%lu: "
396 "unexpected end of %s",
397 file, line, what);
398 return ISC_R_UNEXPECTEDEND;
399 }
400 }
401 }
402 return ISC_R_SUCCESS;
403 }
404
405 void
406 dns_loadctx_attach(dns_loadctx_t *source, dns_loadctx_t **target) {
407 REQUIRE(target != NULL && *target == NULL);
408 REQUIRE(DNS_LCTX_VALID(source));
409
410 isc_refcount_increment(&source->references);
411
412 *target = source;
413 }
414
415 void
416 dns_loadctx_detach(dns_loadctx_t **lctxp) {
417 dns_loadctx_t *lctx;
418
419 REQUIRE(lctxp != NULL);
420 lctx = *lctxp;
421 *lctxp = NULL;
422 REQUIRE(DNS_LCTX_VALID(lctx));
423
424 if (isc_refcount_decrement(&lctx->references) == 1) {
425 loadctx_destroy(lctx);
426 }
427 }
428
429 static void
430 incctx_destroy(isc_mem_t *mctx, dns_incctx_t *ictx) {
431 dns_incctx_t *parent;
432
433 again:
434 parent = ictx->parent;
435 ictx->parent = NULL;
436
437 isc_mem_put(mctx, ictx, sizeof(*ictx));
438
439 if (parent != NULL) {
440 ictx = parent;
441 goto again;
442 }
443 }
444
445 static void
446 loadctx_destroy(dns_loadctx_t *lctx) {
447 REQUIRE(DNS_LCTX_VALID(lctx));
448
449 isc_refcount_destroy(&lctx->references);
450
451 lctx->magic = 0;
452 if (lctx->inc != NULL) {
453 incctx_destroy(lctx->mctx, lctx->inc);
454 }
455
456 if (lctx->f != NULL) {
457 isc_result_t result = isc_stdio_close(lctx->f);
458 if (result != ISC_R_SUCCESS) {
459 UNEXPECTED_ERROR("isc_stdio_close() failed: %s",
460 isc_result_totext(result));
461 }
462 }
463
464 /* isc_lex_destroy() will close all open streams */
465 if (lctx->lex != NULL && !lctx->keep_lex) {
466 isc_lex_destroy(&lctx->lex);
467 }
468
469 isc_mem_putanddetach(&lctx->mctx, lctx, sizeof(*lctx));
470 }
471
472 static void
473 incctx_create(isc_mem_t *mctx, dns_name_t *origin, dns_incctx_t **ictxp) {
474 dns_incctx_t *ictx;
475 isc_region_t r;
476 int i;
477
478 ictx = isc_mem_get(mctx, sizeof(*ictx));
479
480 for (i = 0; i < NBUFS; i++) {
481 dns_fixedname_init(&ictx->fixed[i]);
482 ictx->in_use[i] = false;
483 }
484
485 ictx->origin_in_use = 0;
486 ictx->origin = dns_fixedname_name(&ictx->fixed[ictx->origin_in_use]);
487 ictx->in_use[ictx->origin_in_use] = true;
488 dns_name_toregion(origin, &r);
489 dns_name_fromregion(ictx->origin, &r);
490
491 ictx->glue = NULL;
492 ictx->current = NULL;
493 ictx->glue_in_use = -1;
494 ictx->current_in_use = -1;
495 ictx->parent = NULL;
496 ictx->drop = false;
497 ictx->glue_line = 0;
498 ictx->current_line = 0;
499 ictx->origin_changed = true;
500
501 *ictxp = ictx;
502 }
503
504 static void
505 loadctx_create(dns_masterformat_t format, isc_mem_t *mctx, unsigned int options,
506 uint32_t resign, dns_name_t *top, dns_rdataclass_t zclass,
507 dns_name_t *origin, dns_rdatacallbacks_t *callbacks,
508 dns_loaddonefunc_t done, void *done_arg,
509 dns_masterincludecb_t include_cb, void *include_arg,
510 isc_lex_t *lex, dns_loadctx_t **lctxp) {
511 dns_loadctx_t *lctx = NULL;
512 isc_region_t r;
513
514 REQUIRE(lctxp != NULL && *lctxp == NULL);
515 REQUIRE(callbacks != NULL);
516 REQUIRE(callbacks->add != NULL);
517 REQUIRE(callbacks->error != NULL);
518 REQUIRE(callbacks->warn != NULL);
519 REQUIRE(mctx != NULL);
520 REQUIRE(dns_name_isabsolute(top));
521 REQUIRE(dns_name_isabsolute(origin));
522
523 lctx = isc_mem_get(mctx, sizeof(*lctx));
524 *lctx = (dns_loadctx_t){
525 .format = format,
526 .ttl_known = ((options & DNS_MASTER_NOTTL) != 0),
527 .default_ttl_known = ((options & DNS_MASTER_NOTTL) != 0),
528 .warn_1035 = true,
529 .warn_tcr = true,
530 .warn_sigexpired = true,
531 .options = options,
532 .zclass = zclass,
533 .resign = resign,
534 .include_cb = include_cb,
535 .include_arg = include_arg,
536 .first = true,
537 .done = done,
538 .callbacks = callbacks,
539 .done_arg = done_arg,
540 };
541
542 incctx_create(mctx, origin, &lctx->inc);
543
544 switch (format) {
545 case dns_masterformat_text:
546 lctx->openfile = openfile_text;
547 lctx->load = load_text;
548 break;
549 case dns_masterformat_raw:
550 lctx->openfile = openfile_raw;
551 lctx->load = load_raw;
552 break;
553 default:
554 UNREACHABLE();
555 }
556
557 if (lex != NULL) {
558 lctx->lex = lex;
559 lctx->keep_lex = true;
560 } else {
561 isc_lexspecials_t specials;
562 lctx->lex = NULL;
563 isc_lex_create(mctx, TOKENSIZ, &lctx->lex);
564 lctx->keep_lex = false;
565 /*
566 * If specials change update dns_test_rdatafromstring()
567 * in lib/dns/tests/dnstest.c.
568 */
569 memset(specials, 0, sizeof(specials));
570 specials[0] = 1;
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->now = isc_stdtime_now();
579
580 lctx->top = dns_fixedname_initname(&lctx->fixed_top);
581 dns_name_toregion(top, &r);
582 dns_name_fromregion(lctx->top, &r);
583
584 dns_master_initrawheader(&lctx->header);
585
586 isc_refcount_init(&lctx->references, 1); /* Implicit attach. */
587 isc_mem_attach(mctx, &lctx->mctx);
588
589 lctx->magic = DNS_LCTX_MAGIC;
590 *lctxp = lctx;
591 return;
592 }
593
594 static const char *hex = "0123456789abcdef0123456789ABCDEF";
595
596 /*%
597 * Convert value into a nibble sequence from least significant to most
598 * significant nibble. Zero fill upper most significant nibbles if
599 * required to make the width.
600 *
601 * Returns the number of characters that should have been written without
602 * counting the terminating NUL.
603 */
604 static unsigned int
605 nibbles(char *numbuf, size_t length, unsigned int width, char mode,
606 unsigned int value) {
607 unsigned int count = 0;
608
609 /*
610 * This reserve space for the NUL string terminator.
611 */
612 if (length > 0U) {
613 *numbuf = '\0';
614 length--;
615 }
616 do {
617 char val = hex[(value & 0x0f) + ((mode == 'n') ? 0 : 16)];
618 value >>= 4;
619 if (length > 0U) {
620 *numbuf++ = val;
621 *numbuf = '\0';
622 length--;
623 }
624 if (width > 0) {
625 width--;
626 }
627 count++;
628 /*
629 * If width is non zero then we need to add a label separator.
630 * If value is non zero then we need to add another label and
631 * that requires a label separator.
632 */
633 if (width > 0 || value != 0) {
634 if (length > 0U) {
635 *numbuf++ = '.';
636 *numbuf = '\0';
637 length--;
638 }
639 if (width > 0) {
640 width--;
641 }
642 count++;
643 }
644 } while (value != 0 || width > 0);
645 return count;
646 }
647
648 static isc_result_t
649 genname(char *name, int it, char *buffer, size_t length) {
650 char fmt[sizeof("%04000000000d")];
651 char numbuf[128];
652 char *cp;
653 char mode[2] = { 0 };
654 char brace[2] = { 0 };
655 char comma1[2] = { 0 };
656 char comma2[2] = { 0 };
657 int delta = 0;
658 isc_textregion_t r;
659 unsigned int n;
660 unsigned int width;
661 bool nibblemode;
662
663 r.base = buffer;
664 r.length = (unsigned int)length;
665
666 while (*name != '\0') {
667 if (*name == '$') {
668 name++;
669 if (*name == '$') {
670 if (r.length == 0) {
671 return ISC_R_NOSPACE;
672 }
673 r.base[0] = *name++;
674 isc_textregion_consume(&r, 1);
675 continue;
676 }
677 nibblemode = false;
678 strlcpy(fmt, "%d", sizeof(fmt));
679 /* Get format specifier. */
680 if (*name == '{') {
681 n = sscanf(name,
682 "{%d%1[,}]%u%1[,}]%1[doxXnN]%1[}]",
683 &delta, comma1, &width, comma2, mode,
684 brace);
685 if (n < 2 || n > 6) {
686 return DNS_R_SYNTAX;
687 }
688 if (comma1[0] == '}') {
689 /* %{delta} */
690 } else if (comma1[0] == ',' && comma2[0] == '}')
691 {
692 /* %{delta,width} */
693 n = snprintf(fmt, sizeof(fmt), "%%0%ud",
694 width);
695 } else if (comma1[0] == ',' &&
696 comma2[0] == ',' && mode[0] != 0 &&
697 brace[0] == '}')
698 {
699 /* %{delta,width,format} */
700 if (mode[0] == 'n' || mode[0] == 'N') {
701 nibblemode = true;
702 }
703 n = snprintf(fmt, sizeof(fmt),
704 "%%0%u%c", width, mode[0]);
705 } else {
706 return DNS_R_SYNTAX;
707 }
708 if (n >= sizeof(fmt)) {
709 return ISC_R_NOSPACE;
710 }
711 /* Skip past closing brace. */
712 while (*name != '\0' && *name++ != '}') {
713 continue;
714 }
715 }
716 /*
717 * 'it' is >= 0 so we don't need to check for
718 * underflow.
719 */
720 if (it > 0 && delta > INT_MAX - it) {
721 return ISC_R_RANGE;
722 }
723 if (nibblemode) {
724 n = nibbles(numbuf, sizeof(numbuf), width,
725 mode[0], it + delta);
726 } else {
727 n = snprintf(numbuf, sizeof(numbuf), fmt,
728 it + delta);
729 }
730 if (n >= sizeof(numbuf)) {
731 return ISC_R_NOSPACE;
732 }
733 cp = numbuf;
734 while (*cp != '\0') {
735 if (r.length == 0) {
736 return ISC_R_NOSPACE;
737 }
738 r.base[0] = *cp++;
739 isc_textregion_consume(&r, 1);
740 }
741 } else if (*name == '\\') {
742 if (r.length == 0) {
743 return ISC_R_NOSPACE;
744 }
745 r.base[0] = *name++;
746 isc_textregion_consume(&r, 1);
747 if (*name == '\0') {
748 continue;
749 }
750 if (r.length == 0) {
751 return ISC_R_NOSPACE;
752 }
753 r.base[0] = *name++;
754 isc_textregion_consume(&r, 1);
755 } else {
756 if (r.length == 0) {
757 return ISC_R_NOSPACE;
758 }
759 r.base[0] = *name++;
760 isc_textregion_consume(&r, 1);
761 }
762 }
763 if (r.length == 0) {
764 return ISC_R_NOSPACE;
765 }
766 r.base[0] = '\0';
767 return ISC_R_SUCCESS;
768 }
769
770 static isc_result_t
771 generate(dns_loadctx_t *lctx, char *range, char *lhs, char *gtype, char *rhs,
772 const char *source, unsigned int line) {
773 char *target_mem = NULL;
774 char *lhsbuf = NULL;
775 char *rhsbuf = NULL;
776 dns_fixedname_t ownerfixed;
777 dns_name_t *owner;
778 dns_rdata_t rdata = DNS_RDATA_INIT;
779 dns_rdatacallbacks_t *callbacks;
780 dns_rdatalist_t rdatalist;
781 dns_rdatatype_t type;
782 rdatalist_head_t head;
783 int target_size = MINTSIZ; /* only one rdata at a time */
784 isc_buffer_t buffer;
785 isc_buffer_t target;
786 isc_result_t result;
787 isc_textregion_t r;
788 int n, start, stop, step = 0;
789 unsigned int i;
790 dns_incctx_t *ictx;
791 char dummy[2];
792
793 ictx = lctx->inc;
794 callbacks = lctx->callbacks;
795 owner = dns_fixedname_initname(&ownerfixed);
796 ISC_LIST_INIT(head);
797
798 target_mem = isc_mem_get(lctx->mctx, target_size);
799 rhsbuf = isc_mem_get(lctx->mctx, DNS_MASTER_RHS);
800 lhsbuf = isc_mem_get(lctx->mctx, DNS_MASTER_LHS);
801 if (target_mem == NULL || rhsbuf == NULL || lhsbuf == NULL) {
802 result = ISC_R_NOMEMORY;
803 goto error_cleanup;
804 }
805 isc_buffer_init(&target, target_mem, target_size);
806
807 n = sscanf(range, "%d-%d%1[/]%d", &start, &stop, dummy, &step);
808 if ((n != 2 && n != 4) || (start < 0) || (stop < 0) ||
809 (n == 4 && step < 1) || (stop < start))
810 {
811 (*callbacks->error)(callbacks, "%s: %s:%lu: invalid range '%s'",
812 "$GENERATE", source, line, range);
813 result = DNS_R_SYNTAX;
814 goto insist_cleanup;
815 }
816 if (n == 2) {
817 step = 1;
818 }
819
820 /*
821 * Get type.
822 */
823 r.base = gtype;
824 r.length = strlen(gtype);
825 result = dns_rdatatype_fromtext(&type, &r);
826 if (result != ISC_R_SUCCESS) {
827 (*callbacks->error)(callbacks,
828 "%s: %s:%lu: unknown RR type '%s'",
829 "$GENERATE", source, line, gtype);
830 goto insist_cleanup;
831 }
832
833 /*
834 * RFC2930: TKEY and TSIG are not allowed to be loaded
835 * from master files.
836 */
837 if (dns_master_isprimary(lctx) && dns_rdatatype_ismeta(type)) {
838 (*callbacks->error)(callbacks, "%s: %s:%lu: meta RR type '%s'",
839 "$GENERATE", source, line, gtype);
840 result = DNS_R_METATYPE;
841 goto insist_cleanup;
842 }
843
844 for (i = start; i <= (unsigned int)stop; i += step) {
845 result = genname(lhs, i, lhsbuf, DNS_MASTER_LHS);
846 if (result != ISC_R_SUCCESS) {
847 goto error_cleanup;
848 }
849 result = genname(rhs, i, rhsbuf, DNS_MASTER_RHS);
850 if (result != ISC_R_SUCCESS) {
851 goto error_cleanup;
852 }
853
854 isc_buffer_init(&buffer, lhsbuf, strlen(lhsbuf));
855 isc_buffer_add(&buffer, strlen(lhsbuf));
856 isc_buffer_setactive(&buffer, strlen(lhsbuf));
857 result = dns_name_fromtext(owner, &buffer, ictx->origin, 0,
858 NULL);
859 if (result != ISC_R_SUCCESS) {
860 goto error_cleanup;
861 }
862
863 if (dns_master_isprimary(lctx) &&
864 !dns_name_issubdomain(owner, lctx->top))
865 {
866 char namebuf[DNS_NAME_FORMATSIZE];
867 dns_name_format(owner, namebuf, sizeof(namebuf));
868 /*
869 * Ignore out-of-zone data.
870 */
871 (*callbacks->warn)(callbacks,
872 "%s:%lu: "
873 "ignoring out-of-zone data (%s)",
874 source, line, namebuf);
875 continue;
876 }
877
878 isc_buffer_init(&buffer, rhsbuf, strlen(rhsbuf));
879 isc_buffer_add(&buffer, strlen(rhsbuf));
880 isc_buffer_setactive(&buffer, strlen(rhsbuf));
881
882 result = isc_lex_openbuffer(lctx->lex, &buffer);
883 if (result != ISC_R_SUCCESS) {
884 goto error_cleanup;
885 }
886
887 isc_buffer_init(&target, target_mem, target_size);
888 result = dns_rdata_fromtext(&rdata, lctx->zclass, type,
889 lctx->lex, ictx->origin, 0,
890 lctx->mctx, &target, callbacks);
891 RUNTIME_CHECK(isc_lex_close(lctx->lex) == ISC_R_SUCCESS);
892 if (result != ISC_R_SUCCESS) {
893 goto error_cleanup;
894 }
895
896 dns_rdatalist_init(&rdatalist);
897 rdatalist.type = type;
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 }
907 dns_rdata_reset(&rdata);
908 }
909 result = ISC_R_SUCCESS;
910 goto cleanup;
911
912 error_cleanup:
913 if (result == ISC_R_NOMEMORY) {
914 (*callbacks->error)(callbacks, "$GENERATE: %s",
915 isc_result_totext(result));
916 } else {
917 (*callbacks->error)(callbacks, "$GENERATE: %s:%lu: %s", source,
918 line, isc_result_totext(result));
919 }
920
921 insist_cleanup:
922 INSIST(result != ISC_R_SUCCESS);
923
924 cleanup:
925 if (target_mem != NULL) {
926 isc_mem_put(lctx->mctx, target_mem, target_size);
927 }
928 if (lhsbuf != NULL) {
929 isc_mem_put(lctx->mctx, lhsbuf, DNS_MASTER_LHS);
930 }
931 if (rhsbuf != NULL) {
932 isc_mem_put(lctx->mctx, rhsbuf, DNS_MASTER_RHS);
933 }
934 return result;
935 }
936
937 static void
938 limit_ttl(dns_rdatacallbacks_t *callbacks, const char *source,
939 unsigned int line, uint32_t *ttlp) {
940 if (*ttlp > 0x7fffffffUL) {
941 (callbacks->warn)(callbacks,
942 "%s: %s:%lu: "
943 "$TTL %lu > MAXTTL, "
944 "setting $TTL to 0",
945 "dns_master_load", source, line, *ttlp);
946 *ttlp = 0;
947 }
948 }
949
950 static isc_result_t
951 check_ns(dns_loadctx_t *lctx, isc_token_t *token, const char *source,
952 unsigned long line) {
953 char *tmp = NULL;
954 isc_result_t result = ISC_R_SUCCESS;
955 void (*callback)(struct dns_rdatacallbacks *, const char *, ...);
956
957 if ((lctx->options & DNS_MASTER_FATALNS) != 0) {
958 callback = lctx->callbacks->error;
959 } else {
960 callback = lctx->callbacks->warn;
961 }
962
963 if (token->type == isc_tokentype_string) {
964 struct in_addr addr;
965 struct in6_addr addr6;
966
967 tmp = isc_mem_strdup(lctx->mctx, DNS_AS_STR(*token));
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 }
974 if (inet_pton(AF_INET, tmp, &addr) == 1 ||
975 inet_pton(AF_INET6, tmp, &addr6) == 1)
976 {
977 result = DNS_R_NSISADDRESS;
978 }
979 }
980 if (result != ISC_R_SUCCESS) {
981 (*callback)(lctx->callbacks,
982 "%s:%lu: NS record '%s' "
983 "appears to be an address",
984 source, line, DNS_AS_STR(*token));
985 }
986 if (tmp != NULL) {
987 isc_mem_free(lctx->mctx, tmp);
988 }
989 return result;
990 }
991
992 static void
993 check_wildcard(dns_incctx_t *ictx, const char *source, unsigned long line,
994 dns_rdatacallbacks_t *callbacks) {
995 dns_name_t *name;
996
997 name = (ictx->glue != NULL) ? ictx->glue : ictx->current;
998 if (dns_name_internalwildcard(name)) {
999 char namebuf[DNS_NAME_FORMATSIZE];
1000
1001 dns_name_format(name, namebuf, sizeof(namebuf));
1002 (*callbacks->warn)(callbacks,
1003 "%s:%lu: warning: ownername "
1004 "'%s' contains an non-terminal wildcard",
1005 source, line, namebuf);
1006 }
1007 }
1008
1009 static isc_result_t
1010 openfile_text(dns_loadctx_t *lctx, const char *master_file) {
1011 return isc_lex_openfile(lctx->lex, master_file);
1012 }
1013
1014 static int
1015 find_free_name(dns_incctx_t *incctx) {
1016 int i;
1017
1018 for (i = 0; i < (NBUFS - 1); i++) {
1019 if (!incctx->in_use[i]) {
1020 break;
1021 }
1022 }
1023 INSIST(!incctx->in_use[i]);
1024 return i;
1025 }
1026
1027 static isc_result_t
1028 load_text(dns_loadctx_t *lctx) {
1029 dns_rdataclass_t rdclass;
1030 dns_rdatatype_t type, covers;
1031 uint32_t ttl_offset = 0;
1032 dns_name_t *new_name = NULL;
1033 bool current_has_delegation = false;
1034 bool finish_origin = false;
1035 bool finish_include = false;
1036 bool read_till_eol = false;
1037 bool initialws;
1038 char *include_file = NULL;
1039 isc_token_t token;
1040 isc_result_t result = ISC_R_UNEXPECTED;
1041 rdatalist_head_t glue_list;
1042 rdatalist_head_t current_list;
1043 dns_rdatalist_t *this = NULL;
1044 dns_rdatalist_t *rdatalist = NULL;
1045 dns_rdatalist_t *new_rdatalist = NULL;
1046 int rdlcount = 0;
1047 int rdlcount_save = 0;
1048 int rdatalist_size = 0;
1049 isc_buffer_t buffer;
1050 isc_buffer_t target;
1051 isc_buffer_t target_ft;
1052 isc_buffer_t target_save;
1053 dns_rdata_t *rdata = NULL;
1054 dns_rdata_t *new_rdata = NULL;
1055 int rdcount = 0;
1056 int rdcount_save = 0;
1057 int rdata_size = 0;
1058 unsigned char *target_mem = NULL;
1059 int target_size = TSIZ;
1060 int new_in_use;
1061 isc_mem_t *mctx = NULL;
1062 dns_rdatacallbacks_t *callbacks = NULL;
1063 dns_incctx_t *ictx = NULL;
1064 char *range = NULL;
1065 char *lhs = NULL;
1066 char *gtype = NULL;
1067 char *rhs = NULL;
1068 const char *source = NULL;
1069 unsigned long line = 0;
1070 bool explicit_ttl;
1071 char classname1[DNS_RDATACLASS_FORMATSIZE];
1072 char classname2[DNS_RDATACLASS_FORMATSIZE];
1073 unsigned int options = 0;
1074
1075 REQUIRE(DNS_LCTX_VALID(lctx));
1076 callbacks = lctx->callbacks;
1077 mctx = lctx->mctx;
1078 ictx = lctx->inc;
1079
1080 ISC_LIST_INIT(glue_list);
1081 ISC_LIST_INIT(current_list);
1082
1083 /*
1084 * Allocate target_size of buffer space. This is greater than twice
1085 * the maximum individual RR data size.
1086 */
1087 target_mem = isc_mem_get(mctx, target_size);
1088 isc_buffer_init(&target, target_mem, target_size);
1089 target_save = target;
1090
1091 /* open a database transaction */
1092 if (callbacks->setup != NULL) {
1093 callbacks->setup(callbacks->add_private);
1094 }
1095
1096 if ((lctx->options & DNS_MASTER_CHECKNAMES) != 0) {
1097 options |= DNS_RDATA_CHECKNAMES;
1098 }
1099 if ((lctx->options & DNS_MASTER_CHECKNAMESFAIL) != 0) {
1100 options |= DNS_RDATA_CHECKNAMESFAIL;
1101 }
1102 if ((lctx->options & DNS_MASTER_CHECKMX) != 0) {
1103 options |= DNS_RDATA_CHECKMX;
1104 }
1105 if ((lctx->options & DNS_MASTER_CHECKMXFAIL) != 0) {
1106 options |= DNS_RDATA_CHECKMXFAIL;
1107 }
1108 source = isc_lex_getsourcename(lctx->lex);
1109 while (true) {
1110 if (atomic_load_acquire(&lctx->canceled)) {
1111 result = ISC_R_CANCELED;
1112 goto log_and_cleanup;
1113 }
1114
1115 initialws = false;
1116 line = isc_lex_getsourceline(lctx->lex);
1117 GETTOKEN(lctx->lex, ISC_LEXOPT_INITIALWS | ISC_LEXOPT_QSTRING,
1118 &token, true);
1119 line = isc_lex_getsourceline(lctx->lex);
1120
1121 if (token.type == isc_tokentype_eof) {
1122 if (read_till_eol) {
1123 WARNUNEXPECTEDEOF(lctx->lex);
1124 }
1125 /* Pop the include stack? */
1126 if (ictx->parent != NULL) {
1127 COMMITALL;
1128 lctx->inc = ictx->parent;
1129 ictx->parent = NULL;
1130 incctx_destroy(lctx->mctx, ictx);
1131 RUNTIME_CHECK(isc_lex_close(lctx->lex) ==
1132 ISC_R_SUCCESS);
1133 line = isc_lex_getsourceline(lctx->lex);
1134 POST(line);
1135 source = isc_lex_getsourcename(lctx->lex);
1136 ictx = lctx->inc;
1137 continue;
1138 }
1139 break;
1140 }
1141
1142 if (token.type == isc_tokentype_eol) {
1143 read_till_eol = false;
1144 continue; /* blank line */
1145 }
1146
1147 if (read_till_eol) {
1148 continue;
1149 }
1150
1151 if (token.type == isc_tokentype_initialws) {
1152 /*
1153 * Still working on the same name.
1154 */
1155 initialws = true;
1156 } else if (token.type == isc_tokentype_string ||
1157 token.type == isc_tokentype_qstring)
1158 {
1159 /*
1160 * "$" Support.
1161 *
1162 * "$ORIGIN" and "$INCLUDE" can both take domain names.
1163 * The processing of "$ORIGIN" and "$INCLUDE" extends
1164 * across the normal domain name processing.
1165 */
1166
1167 if (strcasecmp(DNS_AS_STR(token), "$ORIGIN") == 0) {
1168 GETTOKEN(lctx->lex, 0, &token, false);
1169 finish_origin = true;
1170 } else if (strcasecmp(DNS_AS_STR(token), "$TTL") == 0) {
1171 GETTOKENERR(lctx->lex, 0, &token, false,
1172 lctx->ttl = 0;
1173 lctx->default_ttl_known = true;);
1174 result = dns_ttl_fromtext(
1175 &token.value.as_textregion, &lctx->ttl);
1176 if (MANYERRS(lctx, result)) {
1177 SETRESULT(lctx, result);
1178 lctx->ttl = 0;
1179 } else if (result != ISC_R_SUCCESS) {
1180 goto insist_and_cleanup;
1181 }
1182 limit_ttl(callbacks, source, line, &lctx->ttl);
1183 lctx->default_ttl = lctx->ttl;
1184 lctx->default_ttl_known = true;
1185 EXPECTEOL;
1186 continue;
1187 } else if (strcasecmp(DNS_AS_STR(token), "$INCLUDE") ==
1188 0)
1189 {
1190 COMMITALL;
1191 if ((lctx->options & DNS_MASTER_NOINCLUDE) != 0)
1192 {
1193 (callbacks->error)(callbacks,
1194 "%s: %s:%lu: "
1195 "$INCLUDE not "
1196 "allowed",
1197 "dns_master_load",
1198 source, line);
1199 result = DNS_R_REFUSED;
1200 goto insist_and_cleanup;
1201 }
1202 if (ttl_offset != 0) {
1203 (callbacks->error)(callbacks,
1204 "%s: %s:%lu: "
1205 "$INCLUDE "
1206 "may not be used "
1207 "with $DATE",
1208 "dns_master_load",
1209 source, line);
1210 result = DNS_R_SYNTAX;
1211 goto insist_and_cleanup;
1212 }
1213 GETTOKEN(lctx->lex, ISC_LEXOPT_QSTRING, &token,
1214 false);
1215 if (include_file != NULL) {
1216 isc_mem_free(mctx, include_file);
1217 }
1218 include_file =
1219 isc_mem_strdup(mctx, DNS_AS_STR(token));
1220 GETTOKEN(lctx->lex, 0, &token, true);
1221
1222 if (token.type == isc_tokentype_eol ||
1223 token.type == isc_tokentype_eof)
1224 {
1225 if (token.type == isc_tokentype_eof) {
1226 WARNUNEXPECTEDEOF(lctx->lex);
1227 }
1228 /*
1229 * No origin field.
1230 */
1231 result = pushfile(include_file,
1232 ictx->origin, lctx);
1233 if (MANYERRS(lctx, result)) {
1234 SETRESULT(lctx, result);
1235 LOGITFILE(result, include_file);
1236 continue;
1237 } else if (result != ISC_R_SUCCESS) {
1238 LOGITFILE(result, include_file);
1239 goto insist_and_cleanup;
1240 }
1241 ictx = lctx->inc;
1242 source = isc_lex_getsourcename(
1243 lctx->lex);
1244 line = isc_lex_getsourceline(lctx->lex);
1245 POST(line);
1246 continue;
1247 }
1248 /*
1249 * There is an origin field. Fall through
1250 * to domain name processing code and do
1251 * the actual inclusion later.
1252 */
1253 finish_include = true;
1254 } else if (strcasecmp(DNS_AS_STR(token), "$DATE") == 0)
1255 {
1256 int64_t dump_time64;
1257 isc_stdtime_t dump_time;
1258 isc_stdtime_t current_time = isc_stdtime_now();
1259 GETTOKEN(lctx->lex, 0, &token, false);
1260 result = dns_time64_fromtext(DNS_AS_STR(token),
1261 &dump_time64);
1262 if (MANYERRS(lctx, result)) {
1263 SETRESULT(lctx, result);
1264 LOGIT(result);
1265 dump_time64 = 0;
1266 } else if (result != ISC_R_SUCCESS) {
1267 goto log_and_cleanup;
1268 }
1269 dump_time = (isc_stdtime_t)dump_time64;
1270 if (dump_time != dump_time64) {
1271 UNEXPECTED_ERROR("%s: %s:%lu: $DATE "
1272 "outside epoch",
1273 "dns_master_load",
1274 source, line);
1275 result = ISC_R_UNEXPECTED;
1276 goto insist_and_cleanup;
1277 }
1278 if (dump_time > current_time) {
1279 UNEXPECTED_ERROR("%s: %s:%lu: "
1280 "$DATE in future, "
1281 "using current date",
1282 "dns_master_load",
1283 source, line);
1284 dump_time = current_time;
1285 }
1286 ttl_offset = current_time - dump_time;
1287 EXPECTEOL;
1288 continue;
1289 } else if (strcasecmp(DNS_AS_STR(token), "$GENERATE") ==
1290 0)
1291 {
1292 /*
1293 * Lazy cleanup.
1294 */
1295 if (range != NULL) {
1296 isc_mem_free(mctx, range);
1297 }
1298 if (lhs != NULL) {
1299 isc_mem_free(mctx, lhs);
1300 }
1301 if (gtype != NULL) {
1302 isc_mem_free(mctx, gtype);
1303 }
1304 if (rhs != NULL) {
1305 isc_mem_free(mctx, rhs);
1306 }
1307 range = lhs = gtype = rhs = NULL;
1308 /* RANGE */
1309 GETTOKEN(lctx->lex, 0, &token, false);
1310 range = isc_mem_strdup(mctx, DNS_AS_STR(token));
1311 /* LHS */
1312 GETTOKEN(lctx->lex, 0, &token, false);
1313 lhs = isc_mem_strdup(mctx, DNS_AS_STR(token));
1314 rdclass = 0;
1315 explicit_ttl = false;
1316 /* CLASS? */
1317 GETTOKEN(lctx->lex, 0, &token, false);
1318 if (dns_rdataclass_fromtext(
1319 &rdclass,
1320 &token.value.as_textregion) ==
1321 ISC_R_SUCCESS)
1322 {
1323 GETTOKEN(lctx->lex, 0, &token, false);
1324 }
1325 /* TTL? */
1326 if (dns_ttl_fromtext(&token.value.as_textregion,
1327 &lctx->ttl) ==
1328 ISC_R_SUCCESS)
1329 {
1330 limit_ttl(callbacks, source, line,
1331 &lctx->ttl);
1332 lctx->ttl_known = true;
1333 explicit_ttl = true;
1334 GETTOKEN(lctx->lex, 0, &token, false);
1335 }
1336 /* CLASS? */
1337 if (rdclass == 0 &&
1338 dns_rdataclass_fromtext(
1339 &rdclass,
1340 &token.value.as_textregion) ==
1341 ISC_R_SUCCESS)
1342 {
1343 GETTOKEN(lctx->lex, 0, &token, false);
1344 }
1345 /* TYPE */
1346 gtype = isc_mem_strdup(mctx, DNS_AS_STR(token));
1347 /* RHS */
1348 GETTOKEN(lctx->lex, ISC_LEXOPT_QSTRING, &token,
1349 false);
1350 rhs = isc_mem_strdup(mctx, DNS_AS_STR(token));
1351 if (!lctx->ttl_known &&
1352 !lctx->default_ttl_known)
1353 {
1354 (*callbacks->error)(callbacks,
1355 "%s: %s:%lu: no "
1356 "TTL specified",
1357 "dns_master_load",
1358 source, line);
1359 result = DNS_R_NOTTL;
1360 if (MANYERRS(lctx, result)) {
1361 SETRESULT(lctx, result);
1362 lctx->ttl = 0;
1363 } else {
1364 goto insist_and_cleanup;
1365 }
1366 } else if (!explicit_ttl &&
1367 lctx->default_ttl_known)
1368 {
1369 lctx->ttl = lctx->default_ttl;
1370 }
1371 /*
1372 * If the class specified does not match the
1373 * zone's class print out a error message and
1374 * exit.
1375 */
1376 if (rdclass != 0 && rdclass != lctx->zclass) {
1377 goto bad_class;
1378 }
1379 result = generate(lctx, range, lhs, gtype, rhs,
1380 source, line);
1381 if (MANYERRS(lctx, result)) {
1382 SETRESULT(lctx, result);
1383 } else if (result != ISC_R_SUCCESS) {
1384 goto insist_and_cleanup;
1385 }
1386 EXPECTEOL;
1387 continue;
1388 } else if (strncasecmp(DNS_AS_STR(token), "$", 1) == 0)
1389 {
1390 (callbacks->error)(callbacks,
1391 "%s: %s:%lu: "
1392 "unknown $ directive '%s'",
1393 "dns_master_load", source,
1394 line, DNS_AS_STR(token));
1395 result = DNS_R_SYNTAX;
1396 if (MANYERRS(lctx, result)) {
1397 SETRESULT(lctx, result);
1398 } else {
1399 goto insist_and_cleanup;
1400 }
1401 }
1402
1403 /*
1404 * Normal processing resumes.
1405 */
1406 new_in_use = find_free_name(ictx);
1407 new_name = dns_fixedname_initname(
1408 &ictx->fixed[new_in_use]);
1409 isc_buffer_init(&buffer, token.value.as_region.base,
1410 token.value.as_region.length);
1411 isc_buffer_add(&buffer, token.value.as_region.length);
1412 isc_buffer_setactive(&buffer,
1413 token.value.as_region.length);
1414 result = dns_name_fromtext(new_name, &buffer,
1415 ictx->origin, 0, NULL);
1416 if (MANYERRS(lctx, result)) {
1417 SETRESULT(lctx, result);
1418 LOGIT(result);
1419 read_till_eol = true;
1420 continue;
1421 } else if (result != ISC_R_SUCCESS) {
1422 goto log_and_cleanup;
1423 }
1424
1425 /*
1426 * Finish $ORIGIN / $INCLUDE processing if required.
1427 */
1428 if (finish_origin) {
1429 if (ictx->origin_in_use != -1) {
1430 ictx->in_use[ictx->origin_in_use] =
1431 false;
1432 }
1433 ictx->origin_in_use = new_in_use;
1434 ictx->in_use[ictx->origin_in_use] = true;
1435 ictx->origin = new_name;
1436 ictx->origin_changed = true;
1437 finish_origin = false;
1438 EXPECTEOL;
1439 continue;
1440 }
1441 if (finish_include) {
1442 finish_include = false;
1443 EXPECTEOL;
1444 result = pushfile(include_file, new_name, lctx);
1445 if (MANYERRS(lctx, result)) {
1446 SETRESULT(lctx, result);
1447 LOGITFILE(result, include_file);
1448 continue;
1449 } else if (result != ISC_R_SUCCESS) {
1450 LOGITFILE(result, include_file);
1451 goto insist_and_cleanup;
1452 }
1453 ictx = lctx->inc;
1454 ictx->origin_changed = true;
1455 source = isc_lex_getsourcename(lctx->lex);
1456 line = isc_lex_getsourceline(lctx->lex);
1457 POST(line);
1458 continue;
1459 }
1460
1461 /*
1462 * "$" Processing Finished
1463 */
1464
1465 /*
1466 * If we are processing glue and the new name does
1467 * not match the current glue name, commit the glue
1468 * and pop stacks leaving us in 'normal' processing
1469 * state. Linked lists are undone by commit().
1470 */
1471 if (ictx->glue != NULL &&
1472 !dns_name_caseequal(ictx->glue, new_name))
1473 {
1474 result = commit(callbacks, lctx, &glue_list,
1475 ictx->glue, source,
1476 ictx->glue_line);
1477 if (MANYERRS(lctx, result)) {
1478 SETRESULT(lctx, result);
1479 } else if (result != ISC_R_SUCCESS) {
1480 goto insist_and_cleanup;
1481 }
1482 if (ictx->glue_in_use != -1) {
1483 ictx->in_use[ictx->glue_in_use] = false;
1484 }
1485 ictx->glue_in_use = -1;
1486 ictx->glue = NULL;
1487 rdcount = rdcount_save;
1488 rdlcount = rdlcount_save;
1489 target = target_save;
1490 }
1491
1492 /*
1493 * If we are in 'normal' processing state and the new
1494 * name does not match the current name, see if the
1495 * new name is for glue and treat it as such,
1496 * otherwise we have a new name so commit what we
1497 * have.
1498 */
1499 if ((ictx->glue == NULL) &&
1500 (ictx->current == NULL ||
1501 !dns_name_caseequal(ictx->current, new_name)))
1502 {
1503 if (current_has_delegation &&
1504 is_glue(¤t_list, new_name))
1505 {
1506 rdcount_save = rdcount;
1507 rdlcount_save = rdlcount;
1508 target_save = target;
1509 ictx->glue = new_name;
1510 ictx->glue_in_use = new_in_use;
1511 ictx->in_use[ictx->glue_in_use] = true;
1512 } else {
1513 result = commit(callbacks, lctx,
1514 ¤t_list,
1515 ictx->current, source,
1516 ictx->current_line);
1517 if (MANYERRS(lctx, result)) {
1518 SETRESULT(lctx, result);
1519 } else if (result != ISC_R_SUCCESS) {
1520 goto insist_and_cleanup;
1521 }
1522 rdcount = 0;
1523 rdlcount = 0;
1524 if (ictx->current_in_use != -1) {
1525 ictx->in_use
1526 [ictx->current_in_use] =
1527 false;
1528 }
1529 ictx->current_in_use = new_in_use;
1530 ictx->in_use[ictx->current_in_use] =
1531 true;
1532 ictx->current = new_name;
1533 current_has_delegation = false;
1534 isc_buffer_init(&target, target_mem,
1535 target_size);
1536 }
1537 /*
1538 * Check for internal wildcards.
1539 */
1540 if ((lctx->options &
1541 DNS_MASTER_CHECKWILDCARD) != 0)
1542 {
1543 check_wildcard(ictx, source, line,
1544 callbacks);
1545 }
1546 }
1547 if (dns_master_isprimary(lctx) &&
1548 !dns_name_issubdomain(new_name, lctx->top))
1549 {
1550 char namebuf[DNS_NAME_FORMATSIZE];
1551 dns_name_format(new_name, namebuf,
1552 sizeof(namebuf));
1553 /*
1554 * Ignore out-of-zone data.
1555 */
1556 (*callbacks->warn)(callbacks,
1557 "%s:%lu: "
1558 "ignoring out-of-zone data "
1559 "(%s)",
1560 source, line, namebuf);
1561 ictx->drop = true;
1562 } else {
1563 ictx->drop = false;
1564 }
1565 } else {
1566 UNEXPECTED_ERROR("%s:%lu: isc_lex_gettoken() returned "
1567 "unexpected token type (%d)",
1568 source, line, token.type);
1569 result = ISC_R_UNEXPECTED;
1570 if (MANYERRS(lctx, result)) {
1571 SETRESULT(lctx, result);
1572 LOGIT(result);
1573 continue;
1574 } else {
1575 goto insist_and_cleanup;
1576 }
1577 }
1578
1579 /*
1580 * Find TTL, class and type. Both TTL and class are optional
1581 * and may occur in any order if they exist. TTL and class
1582 * come before type which must exist.
1583 *
1584 * [<TTL>] [<class>] <type> <RDATA>
1585 * [<class>] [<TTL>] <type> <RDATA>
1586 */
1587
1588 type = 0;
1589 rdclass = 0;
1590
1591 GETTOKEN(lctx->lex, 0, &token, initialws);
1592
1593 if (initialws) {
1594 if (token.type == isc_tokentype_eol) {
1595 read_till_eol = false;
1596 continue; /* blank line */
1597 }
1598
1599 if (token.type == isc_tokentype_eof) {
1600 WARNUNEXPECTEDEOF(lctx->lex);
1601 read_till_eol = false;
1602 isc_lex_ungettoken(lctx->lex, &token);
1603 continue;
1604 }
1605
1606 if (ictx->current == NULL) {
1607 (*callbacks->error)(callbacks,
1608 "%s:%lu: no current owner "
1609 "name",
1610 source, line);
1611 result = DNS_R_NOOWNER;
1612 if (MANYERRS(lctx, result)) {
1613 SETRESULT(lctx, result);
1614 read_till_eol = true;
1615 continue;
1616 } else {
1617 goto insist_and_cleanup;
1618 }
1619 }
1620
1621 if (ictx->origin_changed) {
1622 char cbuf[DNS_NAME_FORMATSIZE];
1623 char obuf[DNS_NAME_FORMATSIZE];
1624 dns_name_format(ictx->current, cbuf,
1625 sizeof(cbuf));
1626 dns_name_format(ictx->origin, obuf,
1627 sizeof(obuf));
1628 (*callbacks->warn)(callbacks,
1629 "%s:%lu: record with "
1630 "inherited "
1631 "owner (%s) immediately "
1632 "after "
1633 "$ORIGIN (%s)",
1634 source, line, cbuf, obuf);
1635 }
1636 }
1637
1638 ictx->origin_changed = false;
1639
1640 if (dns_rdataclass_fromtext(&rdclass,
1641 &token.value.as_textregion) ==
1642 ISC_R_SUCCESS)
1643 {
1644 GETTOKEN(lctx->lex, 0, &token, false);
1645 }
1646
1647 explicit_ttl = false;
1648 result = dns_ttl_fromtext(&token.value.as_textregion,
1649 &lctx->ttl);
1650 if (result == ISC_R_SUCCESS) {
1651 limit_ttl(callbacks, source, line, &lctx->ttl);
1652 explicit_ttl = true;
1653 lctx->ttl_known = true;
1654 GETTOKEN(lctx->lex, 0, &token, false);
1655 }
1656
1657 if (token.type != isc_tokentype_string) {
1658 UNEXPECTED_ERROR("isc_lex_gettoken() returned "
1659 "unexpected token type");
1660 result = ISC_R_UNEXPECTED;
1661 if (MANYERRS(lctx, result)) {
1662 SETRESULT(lctx, result);
1663 read_till_eol = true;
1664 continue;
1665 } else {
1666 goto insist_and_cleanup;
1667 }
1668 }
1669
1670 if (rdclass == 0 &&
1671 dns_rdataclass_fromtext(&rdclass,
1672 &token.value.as_textregion) ==
1673 ISC_R_SUCCESS)
1674 {
1675 GETTOKEN(lctx->lex, 0, &token, false);
1676 }
1677
1678 if (token.type != isc_tokentype_string) {
1679 UNEXPECTED_ERROR("isc_lex_gettoken() returned "
1680 "unexpected token type");
1681 result = ISC_R_UNEXPECTED;
1682 if (MANYERRS(lctx, result)) {
1683 SETRESULT(lctx, result);
1684 read_till_eol = true;
1685 continue;
1686 } else {
1687 goto insist_and_cleanup;
1688 }
1689 }
1690
1691 result = dns_rdatatype_fromtext(&type,
1692 &token.value.as_textregion);
1693 if (result != ISC_R_SUCCESS) {
1694 (*callbacks->warn)(
1695 callbacks, "%s:%lu: unknown RR type '%.*s'",
1696 source, line, token.value.as_textregion.length,
1697 token.value.as_textregion.base);
1698 if (MANYERRS(lctx, result)) {
1699 SETRESULT(lctx, result);
1700 read_till_eol = true;
1701 continue;
1702 } else {
1703 goto insist_and_cleanup;
1704 }
1705 }
1706
1707 /*
1708 * If the class specified does not match the zone's class
1709 * print out a error message and exit.
1710 */
1711 if (rdclass != 0 && rdclass != lctx->zclass) {
1712 bad_class:
1713
1714 dns_rdataclass_format(rdclass, classname1,
1715 sizeof(classname1));
1716 dns_rdataclass_format(lctx->zclass, classname2,
1717 sizeof(classname2));
1718 (*callbacks->error)(callbacks,
1719 "%s:%lu: class '%s' != "
1720 "zone class '%s'",
1721 source, line, classname1,
1722 classname2);
1723 result = DNS_R_BADCLASS;
1724 if (MANYERRS(lctx, result)) {
1725 SETRESULT(lctx, result);
1726 read_till_eol = true;
1727 continue;
1728 } else {
1729 goto insist_and_cleanup;
1730 }
1731 }
1732
1733 if (type == dns_rdatatype_ns && ictx->glue == NULL) {
1734 current_has_delegation = true;
1735 }
1736
1737 /*
1738 * RFC1123: MD and MF are not allowed to be loaded from
1739 * master files.
1740 */
1741 if (dns_master_isprimary(lctx) &&
1742 (type == dns_rdatatype_md || type == dns_rdatatype_mf))
1743 {
1744 char typebuf[DNS_RDATATYPE_FORMATSIZE];
1745
1746 result = DNS_R_OBSOLETE;
1747
1748 dns_rdatatype_format(type, typebuf, sizeof(typebuf));
1749 (*callbacks->error)(callbacks, "%s:%lu: %s '%s': %s",
1750 source, line, "type", typebuf,
1751 isc_result_totext(result));
1752 if (MANYERRS(lctx, result)) {
1753 SETRESULT(lctx, result);
1754 } else {
1755 goto insist_and_cleanup;
1756 }
1757 }
1758
1759 /*
1760 * RFC2930: TKEY and TSIG are not allowed to be loaded
1761 * from master files.
1762 */
1763 if (dns_master_isprimary(lctx) && dns_rdatatype_ismeta(type)) {
1764 char typebuf[DNS_RDATATYPE_FORMATSIZE];
1765
1766 result = DNS_R_METATYPE;
1767
1768 dns_rdatatype_format(type, typebuf, sizeof(typebuf));
1769 (*callbacks->error)(callbacks, "%s:%lu: %s '%s': %s",
1770 source, line, "type", typebuf,
1771 isc_result_totext(result));
1772 if (MANYERRS(lctx, result)) {
1773 SETRESULT(lctx, result);
1774 } else {
1775 goto insist_and_cleanup;
1776 }
1777 }
1778
1779 /*
1780 * Find a rdata structure.
1781 */
1782 if (rdcount == rdata_size) {
1783 new_rdata = grow_rdata(rdata_size + RDSZ, rdata,
1784 rdata_size, ¤t_list,
1785 &glue_list, mctx);
1786 if (new_rdata == NULL) {
1787 result = ISC_R_NOMEMORY;
1788 goto log_and_cleanup;
1789 }
1790 rdata_size += RDSZ;
1791 rdata = new_rdata;
1792 }
1793
1794 /*
1795 * Peek at the NS record.
1796 */
1797 if (type == dns_rdatatype_ns &&
1798 lctx->zclass == dns_rdataclass_in &&
1799 (lctx->options & DNS_MASTER_CHECKNS) != 0)
1800 {
1801 GETTOKEN(lctx->lex, 0, &token, false);
1802 result = check_ns(lctx, &token, source, line);
1803 isc_lex_ungettoken(lctx->lex, &token);
1804 if ((lctx->options & DNS_MASTER_FATALNS) != 0) {
1805 if (MANYERRS(lctx, result)) {
1806 SETRESULT(lctx, result);
1807 } else if (result != ISC_R_SUCCESS) {
1808 goto insist_and_cleanup;
1809 }
1810 }
1811 }
1812
1813 /*
1814 * Check owner name.
1815 */
1816 options &= ~DNS_RDATA_CHECKREVERSE;
1817 if ((lctx->options & DNS_MASTER_CHECKNAMES) != 0) {
1818 bool ok;
1819 dns_name_t *name;
1820
1821 name = (ictx->glue != NULL) ? ictx->glue
1822 : ictx->current;
1823 ok = dns_rdata_checkowner(name, lctx->zclass, type,
1824 true);
1825 if (!ok) {
1826 char namebuf[DNS_NAME_FORMATSIZE];
1827 const char *desc;
1828 dns_name_format(name, namebuf, sizeof(namebuf));
1829 result = DNS_R_BADOWNERNAME;
1830 desc = isc_result_totext(result);
1831 if (CHECKNAMESFAIL(lctx->options) ||
1832 type == dns_rdatatype_nsec3)
1833 {
1834 (*callbacks->error)(
1835 callbacks, "%s:%lu: %s: %s",
1836 source, line, namebuf, desc);
1837 if (MANYERRS(lctx, result)) {
1838 SETRESULT(lctx, result);
1839 } else {
1840 goto cleanup;
1841 }
1842 } else {
1843 (*callbacks->warn)(
1844 callbacks, "%s:%lu: %s: %s",
1845 source, line, namebuf, desc);
1846 }
1847 }
1848 if (type == dns_rdatatype_ptr &&
1849 !dns_name_isdnssd(name) &&
1850 (dns_name_issubdomain(name, &in_addr_arpa) ||
1851 dns_name_issubdomain(name, &ip6_arpa) ||
1852 dns_name_issubdomain(name, &ip6_int)))
1853 {
1854 options |= DNS_RDATA_CHECKREVERSE;
1855 }
1856 }
1857
1858 /*
1859 * Read rdata contents.
1860 */
1861 dns_rdata_init(&rdata[rdcount]);
1862 target_ft = target;
1863 result = dns_rdata_fromtext(&rdata[rdcount], lctx->zclass, type,
1864 lctx->lex, ictx->origin, options,
1865 lctx->mctx, &target, callbacks);
1866 if (MANYERRS(lctx, result)) {
1867 SETRESULT(lctx, result);
1868 continue;
1869 } else if (result != ISC_R_SUCCESS) {
1870 goto insist_and_cleanup;
1871 }
1872
1873 if (ictx->drop) {
1874 target = target_ft;
1875 continue;
1876 }
1877
1878 if (type == dns_rdatatype_soa &&
1879 (lctx->options & DNS_MASTER_ZONE) != 0 &&
1880 !dns_name_equal(ictx->current, lctx->top))
1881 {
1882 char namebuf[DNS_NAME_FORMATSIZE];
1883 dns_name_format(ictx->current, namebuf,
1884 sizeof(namebuf));
1885 (*callbacks->error)(callbacks,
1886 "%s:%lu: SOA "
1887 "record not at top of zone (%s)",
1888 source, line, namebuf);
1889 result = DNS_R_NOTZONETOP;
1890 if (MANYERRS(lctx, result)) {
1891 SETRESULT(lctx, result);
1892 read_till_eol = true;
1893 target = target_ft;
1894 continue;
1895 } else {
1896 goto insist_and_cleanup;
1897 }
1898 }
1899
1900 if (type == dns_rdatatype_svcb &&
1901 (lctx->options & DNS_MASTER_ZONE) != 0 &&
1902 (lctx->options & DNS_MASTER_CHECKSVCB) != 0)
1903 {
1904 result = dns_rdata_checksvcb(ictx->current,
1905 &rdata[rdcount]);
1906 if (result != ISC_R_SUCCESS) {
1907 (*callbacks->error)(callbacks,
1908 "%s:%lu: SVCB "
1909 "record not valid: %s",
1910 source, line,
1911 isc_result_totext(result));
1912 if (MANYERRS(lctx, result)) {
1913 SETRESULT(lctx, result);
1914 target = target_ft;
1915 continue;
1916 } else if (result != ISC_R_SUCCESS) {
1917 goto insist_and_cleanup;
1918 }
1919 }
1920 }
1921
1922 if (dns_rdatatype_atparent(type) &&
1923 dns_master_isprimary(lctx) &&
1924 dns_name_equal(ictx->current, lctx->top))
1925 {
1926 char namebuf[DNS_NAME_FORMATSIZE];
1927 char typebuf[DNS_RDATATYPE_FORMATSIZE];
1928
1929 dns_name_format(ictx->current, namebuf,
1930 sizeof(namebuf));
1931 dns_rdatatype_format(type, typebuf, sizeof(typebuf));
1932 (*callbacks->error)(
1933 callbacks,
1934 "%s:%lu: %s record at top of zone (%s)", source,
1935 line, typebuf, namebuf);
1936 result = DNS_R_ATZONETOP;
1937 if (MANYERRS(lctx, result)) {
1938 SETRESULT(lctx, result);
1939 target = target_ft;
1940 continue;
1941 } else {
1942 goto insist_and_cleanup;
1943 }
1944 }
1945
1946 if (type == dns_rdatatype_rrsig || type == dns_rdatatype_sig) {
1947 covers = dns_rdata_covers(&rdata[rdcount]);
1948 } else {
1949 covers = 0;
1950 }
1951
1952 if (!lctx->ttl_known && !lctx->default_ttl_known) {
1953 if (type == dns_rdatatype_soa) {
1954 (*callbacks->warn)(callbacks,
1955 "%s:%lu: no TTL specified; "
1956 "using SOA MINTTL instead",
1957 source, line);
1958 lctx->ttl = dns_soa_getminimum(&rdata[rdcount]);
1959 limit_ttl(callbacks, source, line, &lctx->ttl);
1960 lctx->default_ttl = lctx->ttl;
1961 lctx->default_ttl_known = true;
1962 } else if ((lctx->options & DNS_MASTER_HINT) != 0) {
1963 /*
1964 * Zero TTL's are fine for hints.
1965 */
1966 lctx->ttl = 0;
1967 lctx->default_ttl = lctx->ttl;
1968 lctx->default_ttl_known = true;
1969 } else {
1970 (*callbacks->warn)(callbacks,
1971 "%s:%lu: no TTL specified; "
1972 "zone rejected",
1973 source, line);
1974 result = DNS_R_NOTTL;
1975 if (MANYERRS(lctx, result)) {
1976 SETRESULT(lctx, result);
1977 lctx->ttl = 0;
1978 } else {
1979 goto insist_and_cleanup;
1980 }
1981 }
1982 } else if (!explicit_ttl && lctx->default_ttl_known) {
1983 lctx->ttl = lctx->default_ttl;
1984 } else if (!explicit_ttl && lctx->warn_1035) {
1985 (*callbacks->warn)(callbacks,
1986 "%s:%lu: "
1987 "using RFC1035 TTL semantics",
1988 source, line);
1989 lctx->warn_1035 = false;
1990 }
1991
1992 if (type == dns_rdatatype_rrsig && lctx->warn_sigexpired) {
1993 dns_rdata_rrsig_t sig;
1994 result = dns_rdata_tostruct(&rdata[rdcount], &sig,
1995 NULL);
1996 RUNTIME_CHECK(result == ISC_R_SUCCESS);
1997 if (isc_serial_lt(sig.timeexpire, lctx->now)) {
1998 (*callbacks->warn)(callbacks,
1999 "%s:%lu: "
2000 "signature has expired",
2001 source, line);
2002 lctx->warn_sigexpired = false;
2003 }
2004 }
2005
2006 if ((type == dns_rdatatype_sig || type == dns_rdatatype_nxt) &&
2007 lctx->warn_tcr && dns_master_isprimary(lctx))
2008 {
2009 (*callbacks->warn)(callbacks,
2010 "%s:%lu: old style DNSSEC "
2011 " zone detected",
2012 source, line);
2013 lctx->warn_tcr = false;
2014 }
2015
2016 if ((lctx->options & DNS_MASTER_AGETTL) != 0) {
2017 /*
2018 * Adjust the TTL for $DATE. If the RR has
2019 * already expired, set its TTL to 0. This
2020 * should be okay even if the TTL stretching
2021 * feature is not in effect, because it will
2022 * just be quickly expired by the cache, and the
2023 * way this was written before the patch it
2024 * could potentially add 0 TTLs anyway.
2025 */
2026 if (lctx->ttl < ttl_offset) {
2027 lctx->ttl = 0;
2028 } else {
2029 lctx->ttl -= ttl_offset;
2030 }
2031 }
2032
2033 /*
2034 * Find type in rdatalist.
2035 * If it does not exist create new one and prepend to list
2036 * as this will minimise list traversal.
2037 */
2038 if (ictx->glue != NULL) {
2039 this = ISC_LIST_HEAD(glue_list);
2040 } else {
2041 this = ISC_LIST_HEAD(current_list);
2042 }
2043
2044 while (this != NULL) {
2045 if (this->type == type && this->covers == covers) {
2046 break;
2047 }
2048 this = ISC_LIST_NEXT(this, link);
2049 }
2050
2051 if (this == NULL) {
2052 if (rdlcount == rdatalist_size) {
2053 new_rdatalist = grow_rdatalist(
2054 rdatalist_size + RDLSZ, rdatalist,
2055 rdatalist_size, ¤t_list,
2056 &glue_list, mctx);
2057 if (new_rdatalist == NULL) {
2058 result = ISC_R_NOMEMORY;
2059 goto log_and_cleanup;
2060 }
2061 rdatalist = new_rdatalist;
2062 rdatalist_size += RDLSZ;
2063 }
2064 this = &rdatalist[rdlcount++];
2065 dns_rdatalist_init(this);
2066 this->type = type;
2067 this->covers = covers;
2068 this->rdclass = lctx->zclass;
2069 this->ttl = lctx->ttl;
2070 if (ictx->glue != NULL) {
2071 ISC_LIST_INITANDPREPEND(glue_list, this, link);
2072 } else {
2073 ISC_LIST_INITANDPREPEND(current_list, this,
2074 link);
2075 }
2076 } else if (this->ttl != lctx->ttl) {
2077 (*callbacks->warn)(callbacks,
2078 "%s:%lu: "
2079 "TTL set to prior TTL (%lu)",
2080 source, line, this->ttl);
2081 lctx->ttl = this->ttl;
2082 }
2083
2084 if ((lctx->options & DNS_MASTER_CHECKTTL) != 0 &&
2085 lctx->ttl > lctx->maxttl)
2086 {
2087 (callbacks->error)(callbacks,
2088 "dns_master_load: %s:%lu: "
2089 "TTL %d exceeds configured "
2090 "max-zone-ttl %d",
2091 source, line, lctx->ttl,
2092 lctx->maxttl);
2093 result = ISC_R_RANGE;
2094 goto log_and_cleanup;
2095 }
2096
2097 ISC_LIST_APPEND(this->rdata, &rdata[rdcount], link);
2098 if (ictx->glue != NULL) {
2099 ictx->glue_line = line;
2100 } else {
2101 ictx->current_line = line;
2102 }
2103 rdcount++;
2104
2105 /*
2106 * We must have at least 64k as rdlen is 16 bits.
2107 * If we don't commit everything we have so far.
2108 */
2109 if ((target.length - target.used) < MINTSIZ) {
2110 COMMITALL;
2111 }
2112 next_line:;
2113 }
2114
2115 /*
2116 * Commit what has not yet been committed.
2117 */
2118 result = commit(callbacks, lctx, ¤t_list, ictx->current, source,
2119 ictx->current_line);
2120 if (MANYERRS(lctx, result)) {
2121 SETRESULT(lctx, result);
2122 } else if (result != ISC_R_SUCCESS) {
2123 goto insist_and_cleanup;
2124 }
2125 result = commit(callbacks, lctx, &glue_list, ictx->glue, source,
2126 ictx->glue_line);
2127 if (MANYERRS(lctx, result)) {
2128 SETRESULT(lctx, result);
2129 } else if (result != ISC_R_SUCCESS) {
2130 goto insist_and_cleanup;
2131 } else if (lctx->result != ISC_R_SUCCESS) {
2132 result = lctx->result;
2133 } else if (lctx->seen_include) {
2134 result = DNS_R_SEENINCLUDE;
2135 }
2136
2137 goto cleanup;
2138
2139 log_and_cleanup:
2140 LOGIT(result);
2141
2142 insist_and_cleanup:
2143 INSIST(result != ISC_R_SUCCESS);
2144
2145 cleanup:
2146 /* commit the database transaction */
2147 if (callbacks->commit != NULL) {
2148 callbacks->commit(callbacks->add_private);
2149 }
2150
2151 while ((this = ISC_LIST_HEAD(current_list)) != NULL) {
2152 ISC_LIST_UNLINK(current_list, this, link);
2153 }
2154 while ((this = ISC_LIST_HEAD(glue_list)) != NULL) {
2155 ISC_LIST_UNLINK(glue_list, this, link);
2156 }
2157 if (rdatalist != NULL) {
2158 isc_mem_cput(mctx, rdatalist, rdatalist_size,
2159 sizeof(*rdatalist));
2160 }
2161 if (rdata != NULL) {
2162 isc_mem_cput(mctx, rdata, rdata_size, sizeof(*rdata));
2163 }
2164 if (target_mem != NULL) {
2165 isc_mem_put(mctx, target_mem, target_size);
2166 }
2167 if (include_file != NULL) {
2168 isc_mem_free(mctx, include_file);
2169 }
2170 if (range != NULL) {
2171 isc_mem_free(mctx, range);
2172 }
2173 if (lhs != NULL) {
2174 isc_mem_free(mctx, lhs);
2175 }
2176 if (gtype != NULL) {
2177 isc_mem_free(mctx, gtype);
2178 }
2179 if (rhs != NULL) {
2180 isc_mem_free(mctx, rhs);
2181 }
2182
2183 return result;
2184 }
2185
2186 static isc_result_t
2187 pushfile(const char *master_file, dns_name_t *origin, dns_loadctx_t *lctx) {
2188 isc_result_t result;
2189 dns_incctx_t *ictx;
2190 dns_incctx_t *newctx = NULL;
2191 isc_region_t r;
2192
2193 REQUIRE(master_file != NULL);
2194 REQUIRE(DNS_LCTX_VALID(lctx));
2195
2196 ictx = lctx->inc;
2197 lctx->seen_include = true;
2198
2199 incctx_create(lctx->mctx, origin, &newctx);
2200
2201 /*
2202 * Push origin_changed.
2203 */
2204 newctx->origin_changed = ictx->origin_changed;
2205
2206 /* Set current domain. */
2207 if (ictx->glue != NULL || ictx->current != NULL) {
2208 newctx->current_in_use = find_free_name(newctx);
2209 newctx->current = dns_fixedname_name(
2210 &newctx->fixed[newctx->current_in_use]);
2211 newctx->in_use[newctx->current_in_use] = true;
2212 dns_name_toregion(
2213 (ictx->glue != NULL) ? ictx->glue : ictx->current, &r);
2214 dns_name_fromregion(newctx->current, &r);
2215 newctx->drop = ictx->drop;
2216 }
2217
2218 result = (lctx->openfile)(lctx, master_file);
2219 if (result != ISC_R_SUCCESS) {
2220 goto cleanup;
2221 }
2222 newctx->parent = ictx;
2223 lctx->inc = newctx;
2224
2225 if (lctx->include_cb != NULL) {
2226 lctx->include_cb(master_file, lctx->include_arg);
2227 }
2228 return ISC_R_SUCCESS;
2229
2230 cleanup:
2231 incctx_destroy(lctx->mctx, newctx);
2232 return result;
2233 }
2234
2235 /*
2236 * Fill/check exists buffer with 'len' bytes. Track remaining bytes to be
2237 * read when incrementally filling the buffer.
2238 */
2239 static isc_result_t
2240 read_and_check(bool do_read, isc_buffer_t *buffer, size_t len, FILE *f,
2241 uint32_t *totallen) {
2242 isc_result_t result;
2243
2244 REQUIRE(totallen != NULL);
2245
2246 if (do_read) {
2247 INSIST(isc_buffer_availablelength(buffer) >= len);
2248 result = isc_stdio_read(isc_buffer_used(buffer), 1, len, f,
2249 NULL);
2250 if (result != ISC_R_SUCCESS) {
2251 return result;
2252 }
2253 isc_buffer_add(buffer, (unsigned int)len);
2254 if (*totallen < len) {
2255 return ISC_R_RANGE;
2256 }
2257 *totallen -= (uint32_t)len;
2258 } else if (isc_buffer_remaininglength(buffer) < len) {
2259 return ISC_R_RANGE;
2260 }
2261
2262 return ISC_R_SUCCESS;
2263 }
2264
2265 static isc_result_t
2266 load_header(dns_loadctx_t *lctx) {
2267 isc_result_t result = ISC_R_SUCCESS;
2268 dns_masterrawheader_t header;
2269 dns_rdatacallbacks_t *callbacks;
2270 size_t commonlen = sizeof(header.format) + sizeof(header.version);
2271 size_t remainder;
2272 unsigned char data[sizeof(header)];
2273 isc_buffer_t target;
2274
2275 REQUIRE(DNS_LCTX_VALID(lctx));
2276
2277 if (lctx->format != dns_masterformat_raw) {
2278 return ISC_R_NOTIMPLEMENTED;
2279 }
2280
2281 callbacks = lctx->callbacks;
2282 dns_master_initrawheader(&header);
2283
2284 INSIST(commonlen <= sizeof(header));
2285 isc_buffer_init(&target, data, sizeof(data));
2286
2287 result = isc_stdio_read(data, 1, commonlen, lctx->f, NULL);
2288 if (result != ISC_R_SUCCESS) {
2289 UNEXPECTED_ERROR("isc_stdio_read failed: %s",
2290 isc_result_totext(result));
2291 return result;
2292 }
2293
2294 isc_buffer_add(&target, (unsigned int)commonlen);
2295 header.format = isc_buffer_getuint32(&target);
2296 if (header.format != lctx->format) {
2297 (*callbacks->error)(callbacks,
2298 "dns_master_load: "
2299 "file format mismatch (not raw)");
2300 return ISC_R_NOTIMPLEMENTED;
2301 }
2302
2303 header.version = isc_buffer_getuint32(&target);
2304
2305 switch (header.version) {
2306 case 0:
2307 remainder = sizeof(header.dumptime);
2308 break;
2309 case DNS_RAWFORMAT_VERSION:
2310 remainder = sizeof(header) - commonlen;
2311 break;
2312 default:
2313 (*callbacks->error)(callbacks, "dns_master_load: "
2314 "unsupported file format "
2315 "version");
2316 return ISC_R_NOTIMPLEMENTED;
2317 }
2318
2319 result = isc_stdio_read(data + commonlen, 1, remainder, lctx->f, NULL);
2320 if (result != ISC_R_SUCCESS) {
2321 UNEXPECTED_ERROR("isc_stdio_read failed: %s",
2322 isc_result_totext(result));
2323 return result;
2324 }
2325
2326 isc_buffer_add(&target, (unsigned int)remainder);
2327 header.dumptime = isc_buffer_getuint32(&target);
2328 if (header.version == DNS_RAWFORMAT_VERSION) {
2329 header.flags = isc_buffer_getuint32(&target);
2330 header.sourceserial = isc_buffer_getuint32(&target);
2331 header.lastxfrin = isc_buffer_getuint32(&target);
2332 }
2333
2334 lctx->first = false;
2335 lctx->header = header;
2336
2337 return ISC_R_SUCCESS;
2338 }
2339
2340 static isc_result_t
2341 openfile_raw(dns_loadctx_t *lctx, const char *master_file) {
2342 isc_result_t result;
2343
2344 result = isc_stdio_open(master_file, "rb", &lctx->f);
2345 if (result != ISC_R_SUCCESS && result != ISC_R_FILENOTFOUND) {
2346 UNEXPECTED_ERROR("isc_stdio_open() failed: %s",
2347 isc_result_totext(result));
2348 }
2349
2350 return result;
2351 }
2352
2353 static isc_result_t
2354 load_raw(dns_loadctx_t *lctx) {
2355 isc_result_t result = ISC_R_SUCCESS;
2356 dns_rdatacallbacks_t *callbacks;
2357 unsigned char namebuf[DNS_NAME_MAXWIRE];
2358 dns_fixedname_t fixed;
2359 dns_name_t *name;
2360 rdatalist_head_t head, dummy;
2361 dns_rdatalist_t rdatalist;
2362 isc_mem_t *mctx = lctx->mctx;
2363 dns_rdata_t *rdata = NULL;
2364 unsigned int rdata_size = 0;
2365 int target_size = TSIZ;
2366 isc_buffer_t target, buf;
2367 unsigned char *target_mem = NULL;
2368 dns_decompress_t dctx;
2369
2370 callbacks = lctx->callbacks;
2371 dctx = DNS_DECOMPRESS_NEVER;
2372
2373 if (lctx->first) {
2374 result = load_header(lctx);
2375 if (result != ISC_R_SUCCESS) {
2376 return result;
2377 }
2378 }
2379
2380 ISC_LIST_INIT(head);
2381 ISC_LIST_INIT(dummy);
2382
2383 /*
2384 * Allocate target_size of buffer space. This is greater than twice
2385 * the maximum individual RR data size.
2386 */
2387 target_mem = isc_mem_get(mctx, target_size);
2388 isc_buffer_init(&target, target_mem, target_size);
2389
2390 name = dns_fixedname_initname(&fixed);
2391
2392 /* open a database transaction */
2393 if (callbacks->setup != NULL) {
2394 callbacks->setup(callbacks->add_private);
2395 }
2396
2397 /*
2398 * In the following loop, we regard any error fatal regardless of
2399 * whether "MANYERRORS" is set in the context option. This is because
2400 * normal errors should already have been checked at creation time.
2401 * Besides, it is very unlikely that we can recover from an error
2402 * in this format, and so trying to continue parsing erroneous data
2403 * does not really make sense.
2404 */
2405 while (true) {
2406 unsigned int i, rdcount;
2407 uint16_t namelen;
2408 uint32_t totallen;
2409 size_t minlen, readlen;
2410 bool sequential_read = false;
2411
2412 /* Read the data length */
2413 isc_buffer_clear(&target);
2414 INSIST(isc_buffer_availablelength(&target) >= sizeof(totallen));
2415 result = isc_stdio_read(target.base, 1, sizeof(totallen),
2416 lctx->f, NULL);
2417 if (result == ISC_R_EOF) {
2418 result = ISC_R_SUCCESS;
2419 break;
2420 }
2421 if (result != ISC_R_SUCCESS) {
2422 goto cleanup;
2423 }
2424 isc_buffer_add(&target, sizeof(totallen));
2425 totallen = isc_buffer_getuint32(&target);
2426
2427 /*
2428 * Validation: the input data must at least contain the common
2429 * header.
2430 */
2431 minlen = sizeof(totallen) + sizeof(uint16_t) +
2432 sizeof(uint16_t) + sizeof(uint16_t) +
2433 sizeof(uint32_t) + sizeof(uint32_t);
2434 if (totallen < minlen) {
2435 result = ISC_R_RANGE;
2436 goto cleanup;
2437 }
2438 totallen -= sizeof(totallen);
2439
2440 isc_buffer_clear(&target);
2441 if (totallen > isc_buffer_availablelength(&target)) {
2442 /*
2443 * The default buffer size should typically be large
2444 * enough to store the entire RRset. We could try to
2445 * allocate enough space if this is not the case, but
2446 * it might cause a hazardous result when "totallen"
2447 * is forged. Thus, we'd rather take an inefficient
2448 * but robust approach in this atypical case: read
2449 * data step by step, and commit partial data when
2450 * necessary. Note that the buffer must be large
2451 * enough to store the "header part", owner name, and
2452 * at least one rdata (however large it is).
2453 */
2454 sequential_read = true;
2455 readlen = minlen - sizeof(totallen);
2456 } else {
2457 /*
2458 * Typical case. We can read the whole RRset at once
2459 * with the default buffer.
2460 */
2461 readlen = totallen;
2462 }
2463 result = isc_stdio_read(target.base, 1, readlen, lctx->f, NULL);
2464 if (result != ISC_R_SUCCESS) {
2465 goto cleanup;
2466 }
2467 isc_buffer_add(&target, (unsigned int)readlen);
2468 totallen -= (uint32_t)readlen;
2469
2470 /* Construct RRset headers */
2471 dns_rdatalist_init(&rdatalist);
2472 rdatalist.rdclass = isc_buffer_getuint16(&target);
2473 if (lctx->zclass != rdatalist.rdclass) {
2474 result = DNS_R_BADCLASS;
2475 goto cleanup;
2476 }
2477 rdatalist.type = isc_buffer_getuint16(&target);
2478 rdatalist.covers = isc_buffer_getuint16(&target);
2479 rdatalist.ttl = isc_buffer_getuint32(&target);
2480 rdcount = isc_buffer_getuint32(&target);
2481 if (rdcount == 0 || rdcount > 0xffff) {
2482 result = ISC_R_RANGE;
2483 goto cleanup;
2484 }
2485 INSIST(isc_buffer_consumedlength(&target) <= readlen);
2486
2487 /* Owner name: length followed by name */
2488 result = read_and_check(sequential_read, &target,
2489 sizeof(namelen), lctx->f, &totallen);
2490 if (result != ISC_R_SUCCESS) {
2491 goto cleanup;
2492 }
2493 namelen = isc_buffer_getuint16(&target);
2494 if (namelen > sizeof(namebuf)) {
2495 result = ISC_R_RANGE;
2496 goto cleanup;
2497 }
2498
2499 result = read_and_check(sequential_read, &target, namelen,
2500 lctx->f, &totallen);
2501 if (result != ISC_R_SUCCESS) {
2502 goto cleanup;
2503 }
2504
2505 isc_buffer_setactive(&target, (unsigned int)namelen);
2506 result = dns_name_fromwire(name, &target, dctx, NULL);
2507 if (result != ISC_R_SUCCESS) {
2508 goto cleanup;
2509 }
2510
2511 if ((lctx->options & DNS_MASTER_CHECKTTL) != 0 &&
2512 rdatalist.ttl > lctx->maxttl)
2513 {
2514 (callbacks->error)(callbacks,
2515 "dns_master_load: "
2516 "TTL %d exceeds configured "
2517 "max-zone-ttl %d",
2518 rdatalist.ttl, lctx->maxttl);
2519 result = ISC_R_RANGE;
2520 goto cleanup;
2521 }
2522
2523 /* Rdata contents. */
2524 if (rdcount > rdata_size) {
2525 dns_rdata_t *new_rdata = NULL;
2526
2527 new_rdata = grow_rdata(rdcount + RDSZ, rdata,
2528 rdata_size, &head, &dummy, mctx);
2529 if (new_rdata == NULL) {
2530 result = ISC_R_NOMEMORY;
2531 goto cleanup;
2532 }
2533 rdata_size = rdcount + RDSZ;
2534 rdata = new_rdata;
2535 }
2536
2537 continue_read:
2538 for (i = 0; i < rdcount; i++) {
2539 uint16_t rdlen;
2540
2541 dns_rdata_init(&rdata[i]);
2542
2543 if (sequential_read &&
2544 isc_buffer_availablelength(&target) < MINTSIZ)
2545 {
2546 unsigned int j;
2547
2548 INSIST(i > 0); /* detect an infinite loop */
2549
2550 /* Partial Commit. */
2551 ISC_LIST_APPEND(head, &rdatalist, link);
2552 result = commit(callbacks, lctx, &head, name,
2553 NULL, 0);
2554 for (j = 0; j < i; j++) {
2555 ISC_LIST_UNLINK(rdatalist.rdata,
2556 &rdata[j], link);
2557 dns_rdata_reset(&rdata[j]);
2558 }
2559 if (result != ISC_R_SUCCESS) {
2560 goto cleanup;
2561 }
2562
2563 /* Rewind the buffer and continue */
2564 isc_buffer_clear(&target);
2565
2566 rdcount -= i;
2567
2568 goto continue_read;
2569 }
2570
2571 /* rdata length */
2572 result = read_and_check(sequential_read, &target,
2573 sizeof(rdlen), lctx->f,
2574 &totallen);
2575 if (result != ISC_R_SUCCESS) {
2576 goto cleanup;
2577 }
2578 rdlen = isc_buffer_getuint16(&target);
2579
2580 /* rdata */
2581 result = read_and_check(sequential_read, &target, rdlen,
2582 lctx->f, &totallen);
2583 if (result != ISC_R_SUCCESS) {
2584 goto cleanup;
2585 }
2586 isc_buffer_setactive(&target, (unsigned int)rdlen);
2587 /*
2588 * It is safe to have the source active region and
2589 * the target available region be the same if
2590 * decompression is disabled (see dctx above) and we
2591 * are not downcasing names (options == 0).
2592 */
2593 isc_buffer_init(&buf, isc_buffer_current(&target),
2594 (unsigned int)rdlen);
2595 result = dns_rdata_fromwire(
2596 &rdata[i], rdatalist.rdclass, rdatalist.type,
2597 &target, dctx, &buf);
2598 if (result != ISC_R_SUCCESS) {
2599 goto cleanup;
2600 }
2601 ISC_LIST_APPEND(rdatalist.rdata, &rdata[i], link);
2602 }
2603
2604 /*
2605 * Sanity check. Still having remaining space is not
2606 * necessarily critical, but it very likely indicates broken
2607 * or malformed data.
2608 */
2609 if (isc_buffer_remaininglength(&target) != 0 || totallen != 0) {
2610 result = ISC_R_RANGE;
2611 goto cleanup;
2612 }
2613
2614 ISC_LIST_APPEND(head, &rdatalist, link);
2615
2616 /* Commit this RRset. rdatalist will be unlinked. */
2617 result = commit(callbacks, lctx, &head, name, NULL, 0);
2618
2619 for (i = 0; i < rdcount; i++) {
2620 ISC_LIST_UNLINK(rdatalist.rdata, &rdata[i], link);
2621 dns_rdata_reset(&rdata[i]);
2622 }
2623
2624 if (result != ISC_R_SUCCESS) {
2625 goto cleanup;
2626 }
2627 }
2628
2629 if (result == ISC_R_SUCCESS && lctx->result != ISC_R_SUCCESS) {
2630 result = lctx->result;
2631 }
2632
2633 if (result == ISC_R_SUCCESS && callbacks->rawdata != NULL) {
2634 (*callbacks->rawdata)(callbacks->zone, &lctx->header);
2635 }
2636
2637 cleanup:
2638 /* commit the database transaction */
2639 if (callbacks->commit != NULL) {
2640 callbacks->commit(callbacks->add_private);
2641 }
2642
2643 if (rdata != NULL) {
2644 isc_mem_cput(mctx, rdata, rdata_size, sizeof(*rdata));
2645 }
2646 if (target_mem != NULL) {
2647 isc_mem_put(mctx, target_mem, target_size);
2648 }
2649 if (result != ISC_R_SUCCESS) {
2650 (*callbacks->error)(callbacks, "dns_master_load: %s",
2651 isc_result_totext(result));
2652 }
2653
2654 return result;
2655 }
2656
2657 isc_result_t
2658 dns_master_loadfile(const char *master_file, dns_name_t *top,
2659 dns_name_t *origin, dns_rdataclass_t zclass,
2660 unsigned int options, uint32_t resign,
2661 dns_rdatacallbacks_t *callbacks,
2662 dns_masterincludecb_t include_cb, void *include_arg,
2663 isc_mem_t *mctx, dns_masterformat_t format,
2664 dns_ttl_t maxttl) {
2665 dns_loadctx_t *lctx = NULL;
2666 isc_result_t result;
2667
2668 loadctx_create(format, mctx, options, resign, top, zclass, origin,
2669 callbacks, NULL, NULL, include_cb, include_arg, NULL,
2670 &lctx);
2671
2672 lctx->maxttl = maxttl;
2673
2674 result = (lctx->openfile)(lctx, master_file);
2675 if (result != ISC_R_SUCCESS) {
2676 goto cleanup;
2677 }
2678
2679 result = (lctx->load)(lctx);
2680 INSIST(result != DNS_R_CONTINUE);
2681
2682 cleanup:
2683 dns_loadctx_detach(&lctx);
2684 return result;
2685 }
2686
2687 static void
2688 load(void *arg) {
2689 dns_loadctx_t *lctx = arg;
2690 lctx->result = (lctx->load)(lctx);
2691 }
2692
2693 static void
2694 load_done(void *arg) {
2695 dns_loadctx_t *lctx = arg;
2696
2697 (lctx->done)(lctx->done_arg, lctx->result);
2698 dns_loadctx_detach(&lctx);
2699 }
2700
2701 isc_result_t
2702 dns_master_loadfileasync(const char *master_file, dns_name_t *top,
2703 dns_name_t *origin, dns_rdataclass_t zclass,
2704 unsigned int options, uint32_t resign,
2705 dns_rdatacallbacks_t *callbacks, isc_loop_t *loop,
2706 dns_loaddonefunc_t done, void *done_arg,
2707 dns_loadctx_t **lctxp,
2708 dns_masterincludecb_t include_cb, void *include_arg,
2709 isc_mem_t *mctx, dns_masterformat_t format,
2710 uint32_t maxttl) {
2711 dns_loadctx_t *lctx = NULL;
2712 isc_result_t result;
2713
2714 REQUIRE(loop != NULL);
2715 REQUIRE(done != NULL);
2716
2717 loadctx_create(format, mctx, options, resign, top, zclass, origin,
2718 callbacks, done, done_arg, include_cb, include_arg, NULL,
2719 &lctx);
2720
2721 lctx->maxttl = maxttl;
2722
2723 result = (lctx->openfile)(lctx, master_file);
2724 if (result != ISC_R_SUCCESS) {
2725 dns_loadctx_detach(&lctx);
2726 return result;
2727 }
2728
2729 dns_loadctx_attach(lctx, lctxp);
2730 isc_work_enqueue(loop, load, load_done, lctx);
2731
2732 return ISC_R_SUCCESS;
2733 }
2734
2735 isc_result_t
2736 dns_master_loadstream(FILE *stream, dns_name_t *top, dns_name_t *origin,
2737 dns_rdataclass_t zclass, unsigned int options,
2738 dns_rdatacallbacks_t *callbacks, isc_mem_t *mctx) {
2739 isc_result_t result;
2740 dns_loadctx_t *lctx = NULL;
2741
2742 REQUIRE(stream != NULL);
2743
2744 loadctx_create(dns_masterformat_text, mctx, options, 0, top, zclass,
2745 origin, callbacks, NULL, NULL, NULL, NULL, NULL, &lctx);
2746
2747 result = isc_lex_openstream(lctx->lex, stream);
2748 if (result != ISC_R_SUCCESS) {
2749 goto cleanup;
2750 }
2751
2752 result = (lctx->load)(lctx);
2753 INSIST(result != DNS_R_CONTINUE);
2754
2755 cleanup:
2756 dns_loadctx_detach(&lctx);
2757 return result;
2758 }
2759
2760 isc_result_t
2761 dns_master_loadbuffer(isc_buffer_t *buffer, dns_name_t *top, dns_name_t *origin,
2762 dns_rdataclass_t zclass, unsigned int options,
2763 dns_rdatacallbacks_t *callbacks, isc_mem_t *mctx) {
2764 isc_result_t result;
2765 dns_loadctx_t *lctx = NULL;
2766
2767 REQUIRE(buffer != NULL);
2768
2769 loadctx_create(dns_masterformat_text, mctx, options, 0, top, zclass,
2770 origin, callbacks, NULL, NULL, NULL, NULL, NULL, &lctx);
2771
2772 result = isc_lex_openbuffer(lctx->lex, buffer);
2773 if (result != ISC_R_SUCCESS) {
2774 goto cleanup;
2775 }
2776
2777 result = (lctx->load)(lctx);
2778 INSIST(result != DNS_R_CONTINUE);
2779
2780 cleanup:
2781 dns_loadctx_detach(&lctx);
2782 return result;
2783 }
2784
2785 /*
2786 * Grow the slab of dns_rdatalist_t structures.
2787 * Re-link glue and current list.
2788 */
2789 static dns_rdatalist_t *
2790 grow_rdatalist(int new_len, dns_rdatalist_t *oldlist, int old_len,
2791 rdatalist_head_t *current, rdatalist_head_t *glue,
2792 isc_mem_t *mctx) {
2793 dns_rdatalist_t *newlist;
2794 int rdlcount = 0;
2795 ISC_LIST(dns_rdatalist_t) save;
2796 dns_rdatalist_t *this;
2797
2798 newlist = isc_mem_cget(mctx, new_len, sizeof(newlist[0]));
2799
2800 ISC_LIST_INIT(save);
2801 while ((this = ISC_LIST_HEAD(*current)) != NULL) {
2802 ISC_LIST_UNLINK(*current, this, link);
2803 ISC_LIST_APPEND(save, this, link);
2804 }
2805 while ((this = ISC_LIST_HEAD(save)) != NULL) {
2806 ISC_LIST_UNLINK(save, this, link);
2807 INSIST(rdlcount < new_len);
2808 newlist[rdlcount] = *this;
2809 ISC_LIST_APPEND(*current, &newlist[rdlcount], link);
2810 rdlcount++;
2811 }
2812
2813 ISC_LIST_INIT(save);
2814 while ((this = ISC_LIST_HEAD(*glue)) != NULL) {
2815 ISC_LIST_UNLINK(*glue, this, link);
2816 ISC_LIST_APPEND(save, this, link);
2817 }
2818 while ((this = ISC_LIST_HEAD(save)) != NULL) {
2819 ISC_LIST_UNLINK(save, this, link);
2820 INSIST(rdlcount < new_len);
2821 newlist[rdlcount] = *this;
2822 ISC_LIST_APPEND(*glue, &newlist[rdlcount], link);
2823 rdlcount++;
2824 }
2825
2826 INSIST(rdlcount == old_len);
2827 if (oldlist != NULL) {
2828 isc_mem_cput(mctx, oldlist, old_len, sizeof(*oldlist));
2829 }
2830 return newlist;
2831 }
2832
2833 /*
2834 * Grow the slab of rdata structs.
2835 * Re-link the current and glue chains.
2836 */
2837 static dns_rdata_t *
2838 grow_rdata(int new_len, dns_rdata_t *oldlist, int old_len,
2839 rdatalist_head_t *current, rdatalist_head_t *glue, isc_mem_t *mctx) {
2840 dns_rdata_t *newlist;
2841 int rdcount = 0;
2842 ISC_LIST(dns_rdata_t) save;
2843 dns_rdatalist_t *this;
2844 dns_rdata_t *rdata;
2845
2846 newlist = isc_mem_cget(mctx, new_len, sizeof(*newlist));
2847
2848 /*
2849 * Copy current relinking.
2850 */
2851 this = ISC_LIST_HEAD(*current);
2852 while (this != NULL) {
2853 ISC_LIST_INIT(save);
2854 while ((rdata = ISC_LIST_HEAD(this->rdata)) != NULL) {
2855 ISC_LIST_UNLINK(this->rdata, rdata, link);
2856 ISC_LIST_APPEND(save, rdata, link);
2857 }
2858 while ((rdata = ISC_LIST_HEAD(save)) != NULL) {
2859 ISC_LIST_UNLINK(save, rdata, link);
2860 INSIST(rdcount < new_len);
2861 newlist[rdcount] = *rdata;
2862 ISC_LIST_APPEND(this->rdata, &newlist[rdcount], link);
2863 rdcount++;
2864 }
2865 this = ISC_LIST_NEXT(this, link);
2866 }
2867
2868 /*
2869 * Copy glue relinking.
2870 */
2871 this = ISC_LIST_HEAD(*glue);
2872 while (this != NULL) {
2873 ISC_LIST_INIT(save);
2874 while ((rdata = ISC_LIST_HEAD(this->rdata)) != NULL) {
2875 ISC_LIST_UNLINK(this->rdata, rdata, link);
2876 ISC_LIST_APPEND(save, rdata, link);
2877 }
2878 while ((rdata = ISC_LIST_HEAD(save)) != NULL) {
2879 ISC_LIST_UNLINK(save, rdata, link);
2880 INSIST(rdcount < new_len);
2881 newlist[rdcount] = *rdata;
2882 ISC_LIST_APPEND(this->rdata, &newlist[rdcount], link);
2883 rdcount++;
2884 }
2885 this = ISC_LIST_NEXT(this, link);
2886 }
2887 INSIST(rdcount == old_len || rdcount == 0);
2888 if (oldlist != NULL) {
2889 isc_mem_cput(mctx, oldlist, old_len, sizeof(*oldlist));
2890 }
2891 return newlist;
2892 }
2893
2894 static uint32_t
2895 resign_fromlist(dns_rdatalist_t *this, dns_loadctx_t *lctx) {
2896 dns_rdata_t *rdata;
2897 dns_rdata_rrsig_t sig;
2898 uint32_t when;
2899
2900 rdata = ISC_LIST_HEAD(this->rdata);
2901 INSIST(rdata != NULL);
2902 (void)dns_rdata_tostruct(rdata, &sig, NULL);
2903 if (isc_serial_gt(sig.timesigned, lctx->now)) {
2904 when = lctx->now;
2905 } else {
2906 when = sig.timeexpire - lctx->resign;
2907 }
2908
2909 rdata = ISC_LIST_NEXT(rdata, link);
2910 while (rdata != NULL) {
2911 (void)dns_rdata_tostruct(rdata, &sig, NULL);
2912 if (isc_serial_gt(sig.timesigned, lctx->now)) {
2913 when = lctx->now;
2914 } else if (sig.timeexpire - lctx->resign < when) {
2915 when = sig.timeexpire - lctx->resign;
2916 }
2917 rdata = ISC_LIST_NEXT(rdata, link);
2918 }
2919 return when;
2920 }
2921
2922 /*
2923 * Convert each element from a rdatalist_t to rdataset then call commit.
2924 * Unlink each element as we go.
2925 */
2926
2927 static isc_result_t
2928 commit(dns_rdatacallbacks_t *callbacks, dns_loadctx_t *lctx,
2929 rdatalist_head_t *head, dns_name_t *owner, const char *source,
2930 unsigned int line) {
2931 dns_rdatalist_t *this;
2932 dns_rdataset_t dataset;
2933 isc_result_t result = ISC_R_SUCCESS;
2934 char namebuf[DNS_NAME_FORMATSIZE];
2935 void (*error)(struct dns_rdatacallbacks *, const char *, ...);
2936
2937 this = ISC_LIST_HEAD(*head);
2938 error = callbacks->error;
2939
2940 while (this != NULL) {
2941 dns_rdataset_init(&dataset);
2942 dns_rdatalist_tordataset(this, &dataset);
2943 dataset.trust = dns_trust_ultimate;
2944 /*
2945 * If this is a secure dynamic zone set the re-signing time.
2946 */
2947 if (dataset.type == dns_rdatatype_rrsig &&
2948 (lctx->options & DNS_MASTER_RESIGN) != 0)
2949 {
2950 dataset.attributes |= DNS_RDATASETATTR_RESIGN;
2951 dataset.resign = resign_fromlist(this, lctx);
2952 }
2953 result = callbacks->add(callbacks->add_private, owner,
2954 &dataset DNS__DB_FILELINE);
2955 if (result == ISC_R_NOMEMORY) {
2956 (*error)(callbacks, "dns_master_load: %s",
2957 isc_result_totext(result));
2958 } else if (result != ISC_R_SUCCESS) {
2959 dns_name_format(owner, namebuf, sizeof(namebuf));
2960 if (source != NULL) {
2961 (*error)(callbacks, "%s: %s:%lu: %s: %s",
2962 "dns_master_load", source, line,
2963 namebuf, isc_result_totext(result));
2964 } else {
2965 (*error)(callbacks, "%s: %s: %s",
2966 "dns_master_load", namebuf,
2967 isc_result_totext(result));
2968 }
2969 }
2970 if (MANYERRS(lctx, result)) {
2971 SETRESULT(lctx, result);
2972 } else if (result != ISC_R_SUCCESS) {
2973 break;
2974 }
2975 ISC_LIST_UNLINK(*head, this, link);
2976 this = ISC_LIST_HEAD(*head);
2977 }
2978
2979 return result;
2980 }
2981
2982 /*
2983 * Returns true if one of the NS rdata's contains 'owner'.
2984 */
2985
2986 static bool
2987 is_glue(rdatalist_head_t *head, dns_name_t *owner) {
2988 dns_rdatalist_t *this;
2989 dns_rdata_t *rdata;
2990 isc_region_t region;
2991 dns_name_t name;
2992
2993 /*
2994 * Find NS rrset.
2995 */
2996 this = ISC_LIST_HEAD(*head);
2997 while (this != NULL) {
2998 if (this->type == dns_rdatatype_ns) {
2999 break;
3000 }
3001 this = ISC_LIST_NEXT(this, link);
3002 }
3003 if (this == NULL) {
3004 return false;
3005 }
3006
3007 rdata = ISC_LIST_HEAD(this->rdata);
3008 while (rdata != NULL) {
3009 dns_name_init(&name, NULL);
3010 dns_rdata_toregion(rdata, ®ion);
3011 dns_name_fromregion(&name, ®ion);
3012 if (dns_name_equal(&name, owner)) {
3013 return true;
3014 }
3015 rdata = ISC_LIST_NEXT(rdata, link);
3016 }
3017 return false;
3018 }
3019
3020 void
3021 dns_loadctx_cancel(dns_loadctx_t *lctx) {
3022 REQUIRE(DNS_LCTX_VALID(lctx));
3023
3024 atomic_store_release(&lctx->canceled, true);
3025 }
3026
3027 void
3028 dns_master_initrawheader(dns_masterrawheader_t *header) {
3029 memset(header, 0, sizeof(dns_masterrawheader_t));
3030 }
3031