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