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