Remove building with NOCRYPTO option
[minix.git] / external / bsd / bind / dist / lib / dns / master.c
blob6c8566275457407e2b5d99ede481d8dfc95ed042
1 /* $NetBSD: master.c,v 1.14 2015/07/08 17:28:58 christos Exp $ */
3 /*
4 * Copyright (C) 2004-2009, 2011-2015 Internet Systems Consortium, Inc. ("ISC")
5 * Copyright (C) 1999-2003 Internet Software Consortium.
7 * Permission to use, copy, modify, and/or distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice and this permission notice appear in all copies.
11 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
12 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
13 * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
14 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
15 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
16 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
17 * PERFORMANCE OF THIS SOFTWARE.
20 /* Id */
22 /*! \file */
24 #include <config.h>
26 #include <isc/event.h>
27 #include <isc/lex.h>
28 #include <isc/magic.h>
29 #include <isc/mem.h>
30 #include <isc/print.h>
31 #include <isc/serial.h>
32 #include <isc/stdio.h>
33 #include <isc/stdtime.h>
34 #include <isc/string.h>
35 #include <isc/task.h>
36 #include <isc/util.h>
38 #include <dns/callbacks.h>
39 #include <dns/events.h>
40 #include <dns/fixedname.h>
41 #include <dns/master.h>
42 #include <dns/name.h>
43 #include <dns/rdata.h>
44 #include <dns/rdataclass.h>
45 #include <dns/rdatalist.h>
46 #include <dns/rdataset.h>
47 #include <dns/rdatastruct.h>
48 #include <dns/rdatatype.h>
49 #include <dns/result.h>
50 #include <dns/soa.h>
51 #include <dns/time.h>
52 #include <dns/ttl.h>
54 /*!
55 * Grow the number of dns_rdatalist_t (#RDLSZ) and dns_rdata_t (#RDSZ) structures
56 * by these sizes when we need to.
59 /*% RDLSZ reflects the number of different types with the same name expected. */
60 #define RDLSZ 32
61 /*%
62 * RDSZ reflects the number of rdata expected at a give name that can fit into
63 * 64k.
65 #define RDSZ 512
67 #define NBUFS 4
68 #define MAXWIRESZ 255
70 /*%
71 * Target buffer size and minimum target size.
72 * MINTSIZ must be big enough to hold the largest rdata record.
73 * \brief
74 * TSIZ >= MINTSIZ
76 #define TSIZ (128*1024)
77 /*%
78 * max message size - header - root - type - class - ttl - rdlen
80 #define MINTSIZ DNS_RDATA_MAXLENGTH
81 /*%
82 * Size for tokens in the presentation format,
83 * The largest tokens are the base64 blocks in KEY and CERT records,
84 * Largest key allowed is about 1372 bytes but
85 * there is no fixed upper bound on CERT records.
86 * 2K is too small for some X.509s, 8K is overkill.
88 #define TOKENSIZ (8*1024)
90 /*%
91 * Buffers sizes for $GENERATE.
93 #define DNS_MASTER_LHS 2048
94 #define DNS_MASTER_RHS MINTSIZ
96 #define CHECKNAMESFAIL(x) (((x) & DNS_MASTER_CHECKNAMESFAIL) != 0)
98 typedef ISC_LIST(dns_rdatalist_t) rdatalist_head_t;
100 typedef struct dns_incctx dns_incctx_t;
103 * Master file load state.
106 struct dns_loadctx {
107 unsigned int magic;
108 isc_mem_t *mctx;
109 dns_masterformat_t format;
111 dns_rdatacallbacks_t *callbacks;
112 isc_task_t *task;
113 dns_loaddonefunc_t done;
114 void *done_arg;
116 /* Common methods */
117 isc_result_t (*openfile)(dns_loadctx_t *lctx,
118 const char *filename);
119 isc_result_t (*load)(dns_loadctx_t *lctx);
121 /* Members used by all formats */
122 isc_uint32_t maxttl;
124 /* Members specific to the text format: */
125 isc_lex_t *lex;
126 isc_boolean_t keep_lex;
127 unsigned int options;
128 isc_boolean_t ttl_known;
129 isc_boolean_t default_ttl_known;
130 isc_boolean_t warn_1035;
131 isc_boolean_t warn_tcr;
132 isc_boolean_t warn_sigexpired;
133 isc_boolean_t seen_include;
134 isc_uint32_t ttl;
135 isc_uint32_t default_ttl;
136 dns_rdataclass_t zclass;
137 dns_fixedname_t fixed_top;
138 dns_name_t *top; /*%< top of zone */
140 /* Members specific to the raw format: */
141 FILE *f;
142 isc_boolean_t first;
143 dns_masterrawheader_t header;
145 /* Which fixed buffers we are using? */
146 unsigned int loop_cnt; /*% records per quantum,
147 * 0 => all. */
148 isc_boolean_t canceled;
149 isc_mutex_t lock;
150 isc_result_t result;
151 /* locked by lock */
152 isc_uint32_t references;
153 dns_incctx_t *inc;
154 isc_uint32_t resign;
156 dns_masterincludecb_t include_cb;
157 void *include_arg;
160 struct dns_incctx {
161 dns_incctx_t *parent;
162 dns_name_t *origin;
163 dns_name_t *current;
164 dns_name_t *glue;
165 dns_fixedname_t fixed[NBUFS]; /* working buffers */
166 unsigned int in_use[NBUFS]; /* covert to bitmap? */
167 int glue_in_use;
168 int current_in_use;
169 int origin_in_use;
170 isc_boolean_t origin_changed;
171 isc_boolean_t drop;
172 unsigned int glue_line;
173 unsigned int current_line;
176 #define DNS_LCTX_MAGIC ISC_MAGIC('L','c','t','x')
177 #define DNS_LCTX_VALID(lctx) ISC_MAGIC_VALID(lctx, DNS_LCTX_MAGIC)
179 #define DNS_AS_STR(t) ((t).value.as_textregion.base)
181 static isc_result_t
182 openfile_text(dns_loadctx_t *lctx, const char *master_file);
184 static isc_result_t
185 load_text(dns_loadctx_t *lctx);
187 static isc_result_t
188 openfile_raw(dns_loadctx_t *lctx, const char *master_file);
190 static isc_result_t
191 load_raw(dns_loadctx_t *lctx);
193 static isc_result_t
194 openfile_map(dns_loadctx_t *lctx, const char *master_file);
196 static isc_result_t
197 load_map(dns_loadctx_t *lctx);
199 static isc_result_t
200 pushfile(const char *master_file, dns_name_t *origin, dns_loadctx_t *lctx);
202 static isc_result_t
203 commit(dns_rdatacallbacks_t *, dns_loadctx_t *, rdatalist_head_t *,
204 dns_name_t *, const char *, unsigned int);
206 static isc_boolean_t
207 is_glue(rdatalist_head_t *, dns_name_t *);
209 static dns_rdatalist_t *
210 grow_rdatalist(int, dns_rdatalist_t *, int, rdatalist_head_t *,
211 rdatalist_head_t *, isc_mem_t *mctx);
213 static dns_rdata_t *
214 grow_rdata(int, dns_rdata_t *, int, rdatalist_head_t *, rdatalist_head_t *,
215 isc_mem_t *);
217 static void
218 load_quantum(isc_task_t *task, isc_event_t *event);
220 static isc_result_t
221 task_send(dns_loadctx_t *lctx);
223 static void
224 loadctx_destroy(dns_loadctx_t *lctx);
226 #define GETTOKENERR(lexer, options, token, eol, err) \
227 do { \
228 result = gettoken(lexer, options, token, eol, callbacks); \
229 switch (result) { \
230 case ISC_R_SUCCESS: \
231 break; \
232 case ISC_R_UNEXPECTED: \
233 goto insist_and_cleanup; \
234 default: \
235 if (MANYERRS(lctx, result)) { \
236 SETRESULT(lctx, result); \
237 LOGIT(result); \
238 read_till_eol = ISC_TRUE; \
239 err \
240 goto next_line; \
241 } else \
242 goto log_and_cleanup; \
244 if ((token)->type == isc_tokentype_special) { \
245 result = DNS_R_SYNTAX; \
246 if (MANYERRS(lctx, result)) { \
247 SETRESULT(lctx, result); \
248 LOGIT(result); \
249 read_till_eol = ISC_TRUE; \
250 goto next_line; \
251 } else \
252 goto log_and_cleanup; \
254 } while (/*CONSTCOND*/0)
255 #define GETTOKEN(lexer, options, token, eol) \
256 GETTOKENERR(lexer, options, token, eol, {} )
258 #define COMMITALL \
259 do { \
260 result = commit(callbacks, lctx, &current_list, \
261 ictx->current, source, ictx->current_line); \
262 if (MANYERRS(lctx, result)) { \
263 SETRESULT(lctx, result); \
264 } else if (result != ISC_R_SUCCESS) \
265 goto insist_and_cleanup; \
266 result = commit(callbacks, lctx, &glue_list, \
267 ictx->glue, source, ictx->glue_line); \
268 if (MANYERRS(lctx, result)) { \
269 SETRESULT(lctx, result); \
270 } else if (result != ISC_R_SUCCESS) \
271 goto insist_and_cleanup; \
272 rdcount = 0; \
273 rdlcount = 0; \
274 isc_buffer_init(&target, target_mem, target_size); \
275 rdcount_save = rdcount; \
276 rdlcount_save = rdlcount; \
277 } while (/*CONSTCOND*/0)
279 #define WARNUNEXPECTEDEOF(lexer) \
280 do { \
281 if (isc_lex_isfile(lexer)) \
282 (*callbacks->warn)(callbacks, \
283 "%s: file does not end with newline", \
284 source); \
285 } while (/*CONSTCOND*/0)
287 #define EXPECTEOL \
288 do { \
289 GETTOKEN(lctx->lex, 0, &token, ISC_TRUE); \
290 if (token.type != isc_tokentype_eol) { \
291 isc_lex_ungettoken(lctx->lex, &token); \
292 result = DNS_R_EXTRATOKEN; \
293 if (MANYERRS(lctx, result)) { \
294 SETRESULT(lctx, result); \
295 LOGIT(result); \
296 read_till_eol = ISC_TRUE; \
297 } else if (result != ISC_R_SUCCESS) \
298 goto log_and_cleanup; \
300 } while (/*CONSTCOND*/0)
302 #define MANYERRS(lctx, result) \
303 ((result != ISC_R_SUCCESS) && \
304 (result != ISC_R_IOERROR) && \
305 ((lctx)->options & DNS_MASTER_MANYERRORS) != 0)
307 #define SETRESULT(lctx, r) \
308 do { \
309 if ((lctx)->result == ISC_R_SUCCESS) \
310 (lctx)->result = r; \
311 } while (/*CONSTCOND*/0)
313 #define LOGITFILE(result, filename) \
314 if (result == ISC_R_INVALIDFILE || result == ISC_R_FILENOTFOUND || \
315 result == ISC_R_IOERROR || result == ISC_R_TOOMANYOPENFILES || \
316 result == ISC_R_NOPERM) \
317 (*callbacks->error)(callbacks, "%s: %s:%lu: %s: %s", \
318 "dns_master_load", source, line, \
319 filename, dns_result_totext(result)); \
320 else LOGIT(result)
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", \
329 source, line, dns_result_totext(result))
332 static unsigned char in_addr_arpa_data[] = "\007IN-ADDR\004ARPA";
333 static unsigned char in_addr_arpa_offsets[] = { 0, 8, 13 };
334 static const dns_name_t in_addr_arpa =
336 DNS_NAME_MAGIC,
337 in_addr_arpa_data, 14, 3,
338 DNS_NAMEATTR_READONLY | DNS_NAMEATTR_ABSOLUTE,
339 in_addr_arpa_offsets, NULL,
340 {(void *)-1, (void *)-1},
341 {NULL, NULL}
344 static unsigned char ip6_int_data[] = "\003IP6\003INT";
345 static unsigned char ip6_int_offsets[] = { 0, 4, 8 };
346 static const dns_name_t ip6_int =
348 DNS_NAME_MAGIC,
349 ip6_int_data, 9, 3,
350 DNS_NAMEATTR_READONLY | DNS_NAMEATTR_ABSOLUTE,
351 ip6_int_offsets, NULL,
352 {(void *)-1, (void *)-1},
353 {NULL, NULL}
356 static unsigned char ip6_arpa_data[] = "\003IP6\004ARPA";
357 static unsigned char ip6_arpa_offsets[] = { 0, 4, 9 };
358 static const dns_name_t ip6_arpa =
360 DNS_NAME_MAGIC,
361 ip6_arpa_data, 10, 3,
362 DNS_NAMEATTR_READONLY | DNS_NAMEATTR_ABSOLUTE,
363 ip6_arpa_offsets, NULL,
364 {(void *)-1, (void *)-1},
365 {NULL, NULL}
369 static inline isc_result_t
370 gettoken(isc_lex_t *lex, unsigned int options, isc_token_t *token,
371 isc_boolean_t eol, dns_rdatacallbacks_t *callbacks)
373 isc_result_t result;
375 options |= ISC_LEXOPT_EOL | ISC_LEXOPT_EOF | ISC_LEXOPT_DNSMULTILINE |
376 ISC_LEXOPT_ESCAPE;
377 result = isc_lex_gettoken(lex, options, token);
378 if (result != ISC_R_SUCCESS) {
379 switch (result) {
380 case ISC_R_NOMEMORY:
381 return (ISC_R_NOMEMORY);
382 default:
383 (*callbacks->error)(callbacks,
384 "dns_master_load: %s:%lu:"
385 " isc_lex_gettoken() failed: %s",
386 isc_lex_getsourcename(lex),
387 isc_lex_getsourceline(lex),
388 isc_result_totext(result));
389 return (result);
391 /*NOTREACHED*/
393 if (eol != ISC_TRUE)
394 if (token->type == isc_tokentype_eol ||
395 token->type == isc_tokentype_eof) {
396 unsigned long int line;
397 const char *what;
398 const char *file;
399 file = isc_lex_getsourcename(lex);
400 line = isc_lex_getsourceline(lex);
401 if (token->type == isc_tokentype_eol) {
402 line--;
403 what = "line";
404 } else
405 what = "file";
406 (*callbacks->error)(callbacks,
407 "dns_master_load: %s:%lu: unexpected end of %s",
408 file, line, what);
409 return (ISC_R_UNEXPECTEDEND);
411 return (ISC_R_SUCCESS);
415 void
416 dns_loadctx_attach(dns_loadctx_t *source, dns_loadctx_t **target) {
418 REQUIRE(target != NULL && *target == NULL);
419 REQUIRE(DNS_LCTX_VALID(source));
421 LOCK(&source->lock);
422 INSIST(source->references > 0);
423 source->references++;
424 INSIST(source->references != 0); /* Overflow? */
425 UNLOCK(&source->lock);
427 *target = source;
430 void
431 dns_loadctx_detach(dns_loadctx_t **lctxp) {
432 dns_loadctx_t *lctx;
433 isc_boolean_t need_destroy = ISC_FALSE;
435 REQUIRE(lctxp != NULL);
436 lctx = *lctxp;
437 REQUIRE(DNS_LCTX_VALID(lctx));
439 LOCK(&lctx->lock);
440 INSIST(lctx->references > 0);
441 lctx->references--;
442 if (lctx->references == 0)
443 need_destroy = ISC_TRUE;
444 UNLOCK(&lctx->lock);
446 if (need_destroy)
447 loadctx_destroy(lctx);
448 *lctxp = NULL;
451 static void
452 incctx_destroy(isc_mem_t *mctx, dns_incctx_t *ictx) {
453 dns_incctx_t *parent;
455 again:
456 parent = ictx->parent;
457 ictx->parent = NULL;
459 isc_mem_put(mctx, ictx, sizeof(*ictx));
461 if (parent != NULL) {
462 ictx = parent;
463 goto again;
467 static void
468 loadctx_destroy(dns_loadctx_t *lctx) {
469 isc_mem_t *mctx;
470 isc_result_t result;
472 REQUIRE(DNS_LCTX_VALID(lctx));
474 lctx->magic = 0;
475 if (lctx->inc != NULL)
476 incctx_destroy(lctx->mctx, lctx->inc);
478 if (lctx->f != NULL) {
479 result = isc_stdio_close(lctx->f);
480 if (result != ISC_R_SUCCESS) {
481 UNEXPECTED_ERROR(__FILE__, __LINE__,
482 "isc_stdio_close() failed: %s",
483 isc_result_totext(result));
487 /* isc_lex_destroy() will close all open streams */
488 if (lctx->lex != NULL && !lctx->keep_lex)
489 isc_lex_destroy(&lctx->lex);
491 if (lctx->task != NULL)
492 isc_task_detach(&lctx->task);
493 DESTROYLOCK(&lctx->lock);
494 mctx = NULL;
495 isc_mem_attach(lctx->mctx, &mctx);
496 isc_mem_detach(&lctx->mctx);
497 isc_mem_put(mctx, lctx, sizeof(*lctx));
498 isc_mem_detach(&mctx);
501 static isc_result_t
502 incctx_create(isc_mem_t *mctx, dns_name_t *origin, dns_incctx_t **ictxp) {
503 dns_incctx_t *ictx;
504 isc_region_t r;
505 int i;
507 ictx = isc_mem_get(mctx, sizeof(*ictx));
508 if (ictx == NULL)
509 return (ISC_R_NOMEMORY);
511 for (i = 0; i < NBUFS; i++) {
512 dns_fixedname_init(&ictx->fixed[i]);
513 ictx->in_use[i] = ISC_FALSE;
516 ictx->origin_in_use = 0;
517 ictx->origin = dns_fixedname_name(&ictx->fixed[ictx->origin_in_use]);
518 ictx->in_use[ictx->origin_in_use] = ISC_TRUE;
519 dns_name_toregion(origin, &r);
520 dns_name_fromregion(ictx->origin, &r);
522 ictx->glue = NULL;
523 ictx->current = NULL;
524 ictx->glue_in_use = -1;
525 ictx->current_in_use = -1;
526 ictx->parent = NULL;
527 ictx->drop = ISC_FALSE;
528 ictx->glue_line = 0;
529 ictx->current_line = 0;
530 ictx->origin_changed = ISC_TRUE;
532 *ictxp = ictx;
533 return (ISC_R_SUCCESS);
536 static isc_result_t
537 loadctx_create(dns_masterformat_t format, isc_mem_t *mctx,
538 unsigned int options, isc_uint32_t resign, dns_name_t *top,
539 dns_rdataclass_t zclass, dns_name_t *origin,
540 dns_rdatacallbacks_t *callbacks, isc_task_t *task,
541 dns_loaddonefunc_t done, void *done_arg,
542 dns_masterincludecb_t include_cb, void *include_arg,
543 isc_lex_t *lex, dns_loadctx_t **lctxp)
545 dns_loadctx_t *lctx;
546 isc_result_t result;
547 isc_region_t r;
548 isc_lexspecials_t specials;
550 REQUIRE(lctxp != NULL && *lctxp == NULL);
551 REQUIRE(callbacks != NULL);
552 REQUIRE(callbacks->add != NULL);
553 REQUIRE(callbacks->error != NULL);
554 REQUIRE(callbacks->warn != NULL);
555 REQUIRE(mctx != NULL);
556 REQUIRE(dns_name_isabsolute(top));
557 REQUIRE(dns_name_isabsolute(origin));
558 REQUIRE((task == NULL && done == NULL) ||
559 (task != NULL && done != NULL));
561 lctx = isc_mem_get(mctx, sizeof(*lctx));
562 if (lctx == NULL)
563 return (ISC_R_NOMEMORY);
564 result = isc_mutex_init(&lctx->lock);
565 if (result != ISC_R_SUCCESS) {
566 isc_mem_put(mctx, lctx, sizeof(*lctx));
567 return (result);
570 lctx->inc = NULL;
571 result = incctx_create(mctx, origin, &lctx->inc);
572 if (result != ISC_R_SUCCESS)
573 goto cleanup_ctx;
575 lctx->maxttl = 0;
577 lctx->format = format;
578 switch (format) {
579 default:
580 INSIST(0);
581 case dns_masterformat_text:
582 lctx->openfile = openfile_text;
583 lctx->load = load_text;
584 break;
585 case dns_masterformat_raw:
586 lctx->openfile = openfile_raw;
587 lctx->load = load_raw;
588 break;
589 case dns_masterformat_map:
590 lctx->openfile = openfile_map;
591 lctx->load = load_map;
592 break;
595 if (lex != NULL) {
596 lctx->lex = lex;
597 lctx->keep_lex = ISC_TRUE;
598 } else {
599 lctx->lex = NULL;
600 result = isc_lex_create(mctx, TOKENSIZ, &lctx->lex);
601 if (result != ISC_R_SUCCESS)
602 goto cleanup_inc;
603 lctx->keep_lex = ISC_FALSE;
604 memset(specials, 0, sizeof(specials));
605 specials[0] = 1;
606 specials['('] = 1;
607 specials[')'] = 1;
608 specials['"'] = 1;
609 isc_lex_setspecials(lctx->lex, specials);
610 isc_lex_setcomments(lctx->lex, ISC_LEXCOMMENT_DNSMASTERFILE);
613 lctx->ttl_known = ISC_TF((options & DNS_MASTER_NOTTL) != 0);
614 lctx->ttl = 0;
615 lctx->default_ttl_known = lctx->ttl_known;
616 lctx->default_ttl = 0;
617 lctx->warn_1035 = ISC_TRUE; /* XXX Argument? */
618 lctx->warn_tcr = ISC_TRUE; /* XXX Argument? */
619 lctx->warn_sigexpired = ISC_TRUE; /* XXX Argument? */
620 lctx->options = options;
621 lctx->seen_include = ISC_FALSE;
622 lctx->zclass = zclass;
623 lctx->resign = resign;
624 lctx->result = ISC_R_SUCCESS;
625 lctx->include_cb = include_cb;
626 lctx->include_arg = include_arg;
628 dns_fixedname_init(&lctx->fixed_top);
629 lctx->top = dns_fixedname_name(&lctx->fixed_top);
630 dns_name_toregion(top, &r);
631 dns_name_fromregion(lctx->top, &r);
633 lctx->f = NULL;
634 lctx->first = ISC_TRUE;
635 dns_master_initrawheader(&lctx->header);
637 lctx->loop_cnt = (done != NULL) ? 100 : 0;
638 lctx->callbacks = callbacks;
639 lctx->task = NULL;
640 if (task != NULL)
641 isc_task_attach(task, &lctx->task);
642 lctx->done = done;
643 lctx->done_arg = done_arg;
644 lctx->canceled = ISC_FALSE;
645 lctx->mctx = NULL;
646 isc_mem_attach(mctx, &lctx->mctx);
647 lctx->references = 1; /* Implicit attach. */
648 lctx->magic = DNS_LCTX_MAGIC;
649 *lctxp = lctx;
650 return (ISC_R_SUCCESS);
652 cleanup_inc:
653 incctx_destroy(mctx, lctx->inc);
654 cleanup_ctx:
655 isc_mem_put(mctx, lctx, sizeof(*lctx));
656 return (result);
659 static const char *hex = "0123456789abcdef0123456789ABCDEF";
662 * Convert value into a nibble sequence from least significant to most
663 * significant nibble. Zero fill upper most significant nibbles if
664 * required to make the width.
666 * Returns the number of characters that should have been written without
667 * counting the terminating NUL.
669 static unsigned int
670 nibbles(char *numbuf, size_t length, unsigned int width, char mode, int value) {
671 unsigned int count = 0;
674 * This reserve space for the NUL string terminator.
676 if (length > 0U) {
677 *numbuf = '\0';
678 length--;
680 do {
681 char val = hex[(value & 0x0f) + ((mode == 'n') ? 0 : 16)];
682 value >>= 4;
683 if (length > 0U) {
684 *numbuf++ = val;
685 *numbuf = '\0';
686 length--;
688 if (width > 0)
689 width--;
690 count++;
692 * If width is non zero then we need to add a label seperator.
693 * If value is non zero then we need to add another label and
694 * that requires a label seperator.
696 if (width > 0 || value != 0) {
697 if (length > 0U) {
698 *numbuf++ = '.';
699 *numbuf = '\0';
700 length--;
702 if (width > 0)
703 width--;
704 count++;
706 } while (value != 0 || width > 0);
707 return (count);
710 static isc_result_t
711 genname(char *name, int it, char *buffer, size_t length) {
712 char fmt[sizeof("%04000000000d")];
713 char numbuf[128];
714 char *cp;
715 char mode[2];
716 int delta = 0;
717 isc_textregion_t r;
718 unsigned int n;
719 unsigned int width;
720 isc_boolean_t nibblemode;
722 r.base = buffer;
723 r.length = (unsigned int)length;
725 while (*name != '\0') {
726 if (*name == '$') {
727 name++;
728 if (*name == '$') {
729 if (r.length == 0)
730 return (ISC_R_NOSPACE);
731 r.base[0] = *name++;
732 isc_textregion_consume(&r, 1);
733 continue;
735 nibblemode = ISC_FALSE;
736 strcpy(fmt, "%d");
737 /* Get format specifier. */
738 if (*name == '{' ) {
739 n = sscanf(name, "{%d,%u,%1[doxXnN]}",
740 &delta, &width, mode);
741 switch (n) {
742 case 1:
743 break;
744 case 2:
745 n = snprintf(fmt, sizeof(fmt),
746 "%%0%ud", width);
747 break;
748 case 3:
749 if (mode[0] == 'n' || mode[0] == 'N')
750 nibblemode = ISC_TRUE;
751 n = snprintf(fmt, sizeof(fmt),
752 "%%0%u%c", width, mode[0]);
753 break;
754 default:
755 return (DNS_R_SYNTAX);
757 if (n >= sizeof(fmt))
758 return (ISC_R_NOSPACE);
759 /* Skip past closing brace. */
760 while (*name != '\0' && *name++ != '}')
761 continue;
763 if (nibblemode)
764 n = nibbles(numbuf, sizeof(numbuf), width,
765 mode[0], it + delta);
766 else
767 n = snprintf(numbuf, sizeof(numbuf), fmt,
768 it + delta);
769 if (n >= sizeof(numbuf))
770 return (ISC_R_NOSPACE);
771 cp = numbuf;
772 while (*cp != '\0') {
773 if (r.length == 0)
774 return (ISC_R_NOSPACE);
775 r.base[0] = *cp++;
776 isc_textregion_consume(&r, 1);
778 } else if (*name == '\\') {
779 if (r.length == 0)
780 return (ISC_R_NOSPACE);
781 r.base[0] = *name++;
782 isc_textregion_consume(&r, 1);
783 if (*name == '\0')
784 continue;
785 if (r.length == 0)
786 return (ISC_R_NOSPACE);
787 r.base[0] = *name++;
788 isc_textregion_consume(&r, 1);
789 } else {
790 if (r.length == 0)
791 return (ISC_R_NOSPACE);
792 r.base[0] = *name++;
793 isc_textregion_consume(&r, 1);
796 if (r.length == 0)
797 return (ISC_R_NOSPACE);
798 r.base[0] = '\0';
799 return (ISC_R_SUCCESS);
802 static isc_result_t
803 generate(dns_loadctx_t *lctx, char *range, char *lhs, char *gtype, char *rhs,
804 const char *source, unsigned int line)
806 char *target_mem = NULL;
807 char *lhsbuf = NULL;
808 char *rhsbuf = NULL;
809 dns_fixedname_t ownerfixed;
810 dns_name_t *owner;
811 dns_rdata_t rdata = DNS_RDATA_INIT;
812 dns_rdatacallbacks_t *callbacks;
813 dns_rdatalist_t rdatalist;
814 dns_rdatatype_t type;
815 rdatalist_head_t head;
816 int target_size = MINTSIZ; /* only one rdata at a time */
817 isc_buffer_t buffer;
818 isc_buffer_t target;
819 isc_result_t result;
820 isc_textregion_t r;
821 int i, n, start, stop, step = 0;
822 dns_incctx_t *ictx;
823 char dummy;
825 ictx = lctx->inc;
826 callbacks = lctx->callbacks;
827 dns_fixedname_init(&ownerfixed);
828 owner = dns_fixedname_name(&ownerfixed);
829 ISC_LIST_INIT(head);
831 target_mem = isc_mem_get(lctx->mctx, target_size);
832 rhsbuf = isc_mem_get(lctx->mctx, DNS_MASTER_RHS);
833 lhsbuf = isc_mem_get(lctx->mctx, DNS_MASTER_LHS);
834 if (target_mem == NULL || rhsbuf == NULL || lhsbuf == NULL) {
835 result = ISC_R_NOMEMORY;
836 goto error_cleanup;
838 isc_buffer_init(&target, target_mem, target_size);
840 n = sscanf(range, "%d-%d%[/]%d", &start, &stop, &dummy, &step);
841 if ((n != 2 && n != 4) || (start < 0) || (stop < 0) ||
842 (n == 4 && step < 1) || (stop < start))
844 (*callbacks->error)(callbacks,
845 "%s: %s:%lu: invalid range '%s'",
846 "$GENERATE", source, line, range);
847 result = DNS_R_SYNTAX;
848 goto insist_cleanup;
850 if (n == 2)
851 step = 1;
854 * Get type.
856 r.base = gtype;
857 r.length = strlen(gtype);
858 result = dns_rdatatype_fromtext(&type, &r);
859 if (result != ISC_R_SUCCESS) {
860 (*callbacks->error)(callbacks,
861 "%s: %s:%lu: unknown RR type '%s'",
862 "$GENERATE", source, line, gtype);
863 goto insist_cleanup;
866 ISC_LIST_INIT(rdatalist.rdata);
867 ISC_LINK_INIT(&rdatalist, link);
868 for (i = start; i <= stop; i += step) {
869 result = genname(lhs, i, lhsbuf, DNS_MASTER_LHS);
870 if (result != ISC_R_SUCCESS)
871 goto error_cleanup;
872 result = genname(rhs, i, rhsbuf, DNS_MASTER_RHS);
873 if (result != ISC_R_SUCCESS)
874 goto error_cleanup;
876 isc_buffer_init(&buffer, lhsbuf, strlen(lhsbuf));
877 isc_buffer_add(&buffer, strlen(lhsbuf));
878 isc_buffer_setactive(&buffer, strlen(lhsbuf));
879 result = dns_name_fromtext(owner, &buffer, ictx->origin,
880 0, NULL);
881 if (result != ISC_R_SUCCESS)
882 goto error_cleanup;
884 if ((lctx->options & DNS_MASTER_ZONE) != 0 &&
885 (lctx->options & DNS_MASTER_SLAVE) == 0 &&
886 (lctx->options & DNS_MASTER_KEY) == 0 &&
887 !dns_name_issubdomain(owner, lctx->top))
889 char namebuf[DNS_NAME_FORMATSIZE];
890 dns_name_format(owner, namebuf, sizeof(namebuf));
892 * Ignore out-of-zone data.
894 (*callbacks->warn)(callbacks,
895 "%s:%lu: "
896 "ignoring out-of-zone data (%s)",
897 source, line, namebuf);
898 continue;
901 isc_buffer_init(&buffer, rhsbuf, strlen(rhsbuf));
902 isc_buffer_add(&buffer, strlen(rhsbuf));
903 isc_buffer_setactive(&buffer, strlen(rhsbuf));
905 result = isc_lex_openbuffer(lctx->lex, &buffer);
906 if (result != ISC_R_SUCCESS)
907 goto error_cleanup;
909 isc_buffer_init(&target, target_mem, target_size);
910 result = dns_rdata_fromtext(&rdata, lctx->zclass, type,
911 lctx->lex, ictx->origin, 0,
912 lctx->mctx, &target, callbacks);
913 RUNTIME_CHECK(isc_lex_close(lctx->lex) == ISC_R_SUCCESS);
914 if (result != ISC_R_SUCCESS)
915 goto error_cleanup;
917 rdatalist.type = type;
918 rdatalist.covers = 0;
919 rdatalist.rdclass = lctx->zclass;
920 rdatalist.ttl = lctx->ttl;
921 ISC_LIST_PREPEND(head, &rdatalist, link);
922 ISC_LIST_APPEND(rdatalist.rdata, &rdata, link);
923 result = commit(callbacks, lctx, &head, owner, source, line);
924 ISC_LIST_UNLINK(rdatalist.rdata, &rdata, link);
925 if (result != ISC_R_SUCCESS)
926 goto error_cleanup;
927 dns_rdata_reset(&rdata);
929 result = ISC_R_SUCCESS;
930 goto cleanup;
932 error_cleanup:
933 if (result == ISC_R_NOMEMORY)
934 (*callbacks->error)(callbacks, "$GENERATE: %s",
935 dns_result_totext(result));
936 else
937 (*callbacks->error)(callbacks, "$GENERATE: %s:%lu: %s",
938 source, line, dns_result_totext(result));
940 insist_cleanup:
941 INSIST(result != ISC_R_SUCCESS);
943 cleanup:
944 if (target_mem != NULL)
945 isc_mem_put(lctx->mctx, target_mem, target_size);
946 if (lhsbuf != NULL)
947 isc_mem_put(lctx->mctx, lhsbuf, DNS_MASTER_LHS);
948 if (rhsbuf != NULL)
949 isc_mem_put(lctx->mctx, rhsbuf, DNS_MASTER_RHS);
950 return (result);
953 static void
954 limit_ttl(dns_rdatacallbacks_t *callbacks, const char *source,
955 unsigned int line, isc_uint32_t *ttlp)
957 if (*ttlp > 0x7fffffffUL) {
958 (callbacks->warn)(callbacks,
959 "%s: %s:%lu: "
960 "$TTL %lu > MAXTTL, "
961 "setting $TTL to 0",
962 "dns_master_load",
963 source, line,
964 *ttlp);
965 *ttlp = 0;
969 static isc_result_t
970 check_ns(dns_loadctx_t *lctx, isc_token_t *token, const char *source,
971 unsigned long line)
973 char *tmp = NULL;
974 isc_result_t result = ISC_R_SUCCESS;
975 void (*callback)(struct dns_rdatacallbacks *, const char *, ...);
977 if ((lctx->options & DNS_MASTER_FATALNS) != 0)
978 callback = lctx->callbacks->error;
979 else
980 callback = lctx->callbacks->warn;
982 if (token->type == isc_tokentype_string) {
983 struct in_addr addr;
984 struct in6_addr addr6;
986 tmp = isc_mem_strdup(lctx->mctx, DNS_AS_STR(*token));
987 if (tmp == NULL)
988 return (ISC_R_NOMEMORY);
990 * Catch both "1.2.3.4" and "1.2.3.4."
992 if (tmp[strlen(tmp) - 1] == '.')
993 tmp[strlen(tmp) - 1] = '\0';
994 if (inet_aton(tmp, &addr) == 1 ||
995 inet_pton(AF_INET6, tmp, &addr6) == 1)
996 result = DNS_R_NSISADDRESS;
998 if (result != ISC_R_SUCCESS)
999 (*callback)(lctx->callbacks, "%s:%lu: NS record '%s' "
1000 "appears to be an address",
1001 source, line, DNS_AS_STR(*token));
1002 if (tmp != NULL)
1003 isc_mem_free(lctx->mctx, tmp);
1004 return (result);
1007 static void
1008 check_wildcard(dns_incctx_t *ictx, const char *source, unsigned long line,
1009 dns_rdatacallbacks_t *callbacks)
1011 dns_name_t *name;
1013 name = (ictx->glue != NULL) ? ictx->glue : ictx->current;
1014 if (dns_name_internalwildcard(name)) {
1015 char namebuf[DNS_NAME_FORMATSIZE];
1017 dns_name_format(name, namebuf, sizeof(namebuf));
1018 (*callbacks->warn)(callbacks, "%s:%lu: warning: ownername "
1019 "'%s' contains an non-terminal wildcard",
1020 source, line, namebuf);
1024 static isc_result_t
1025 openfile_text(dns_loadctx_t *lctx, const char *master_file) {
1026 return (isc_lex_openfile(lctx->lex, master_file));
1029 static isc_result_t
1030 load_text(dns_loadctx_t *lctx) {
1031 dns_rdataclass_t rdclass;
1032 dns_rdatatype_t type, covers;
1033 isc_uint32_t ttl_offset = 0;
1034 dns_name_t *new_name;
1035 isc_boolean_t current_has_delegation = ISC_FALSE;
1036 isc_boolean_t done = ISC_FALSE;
1037 isc_boolean_t finish_origin = ISC_FALSE;
1038 isc_boolean_t finish_include = ISC_FALSE;
1039 isc_boolean_t read_till_eol = ISC_FALSE;
1040 isc_boolean_t initialws;
1041 char *include_file = NULL;
1042 isc_token_t token;
1043 isc_result_t result = ISC_R_UNEXPECTED;
1044 rdatalist_head_t glue_list;
1045 rdatalist_head_t current_list;
1046 dns_rdatalist_t *this;
1047 dns_rdatalist_t *rdatalist = NULL;
1048 dns_rdatalist_t *new_rdatalist;
1049 int rdlcount = 0;
1050 int rdlcount_save = 0;
1051 int rdatalist_size = 0;
1052 isc_buffer_t buffer;
1053 isc_buffer_t target;
1054 isc_buffer_t target_ft;
1055 isc_buffer_t target_save;
1056 dns_rdata_t *rdata = NULL;
1057 dns_rdata_t *new_rdata;
1058 int rdcount = 0;
1059 int rdcount_save = 0;
1060 int rdata_size = 0;
1061 unsigned char *target_mem = NULL;
1062 int target_size = TSIZ;
1063 int new_in_use;
1064 unsigned int loop_cnt = 0;
1065 isc_mem_t *mctx;
1066 dns_rdatacallbacks_t *callbacks;
1067 dns_incctx_t *ictx;
1068 char *range = NULL;
1069 char *lhs = NULL;
1070 char *gtype = NULL;
1071 char *rhs = NULL;
1072 const char *source = "";
1073 unsigned long line = 0;
1074 isc_boolean_t explicit_ttl;
1075 isc_stdtime_t now;
1076 char classname1[DNS_RDATACLASS_FORMATSIZE];
1077 char classname2[DNS_RDATACLASS_FORMATSIZE];
1078 unsigned int options = 0;
1080 REQUIRE(DNS_LCTX_VALID(lctx));
1081 callbacks = lctx->callbacks;
1082 mctx = lctx->mctx;
1083 ictx = lctx->inc;
1085 ISC_LIST_INIT(glue_list);
1086 ISC_LIST_INIT(current_list);
1088 isc_stdtime_get(&now);
1091 * Allocate target_size of buffer space. This is greater than twice
1092 * the maximum individual RR data size.
1094 target_mem = isc_mem_get(mctx, target_size);
1095 if (target_mem == NULL) {
1096 result = ISC_R_NOMEMORY;
1097 goto log_and_cleanup;
1099 isc_buffer_init(&target, target_mem, target_size);
1100 target_save = target;
1102 if ((lctx->options & DNS_MASTER_CHECKNAMES) != 0)
1103 options |= DNS_RDATA_CHECKNAMES;
1104 if ((lctx->options & DNS_MASTER_CHECKNAMESFAIL) != 0)
1105 options |= DNS_RDATA_CHECKNAMESFAIL;
1106 if ((lctx->options & DNS_MASTER_CHECKMX) != 0)
1107 options |= DNS_RDATA_CHECKMX;
1108 if ((lctx->options & DNS_MASTER_CHECKMXFAIL) != 0)
1109 options |= DNS_RDATA_CHECKMXFAIL;
1110 source = isc_lex_getsourcename(lctx->lex);
1111 do {
1112 initialws = ISC_FALSE;
1113 line = isc_lex_getsourceline(lctx->lex);
1114 GETTOKEN(lctx->lex, ISC_LEXOPT_INITIALWS | ISC_LEXOPT_QSTRING,
1115 &token, ISC_TRUE);
1116 line = isc_lex_getsourceline(lctx->lex);
1118 if (token.type == isc_tokentype_eof) {
1119 if (read_till_eol)
1120 WARNUNEXPECTEDEOF(lctx->lex);
1121 /* Pop the include stack? */
1122 if (ictx->parent != NULL) {
1123 COMMITALL;
1124 lctx->inc = ictx->parent;
1125 ictx->parent = NULL;
1126 incctx_destroy(lctx->mctx, ictx);
1127 RUNTIME_CHECK(isc_lex_close(lctx->lex) == ISC_R_SUCCESS);
1128 line = isc_lex_getsourceline(lctx->lex);
1129 source = isc_lex_getsourcename(lctx->lex);
1130 ictx = lctx->inc;
1131 continue;
1133 done = ISC_TRUE;
1134 continue;
1137 if (token.type == isc_tokentype_eol) {
1138 read_till_eol = ISC_FALSE;
1139 continue; /* blank line */
1142 if (read_till_eol)
1143 continue;
1145 if (token.type == isc_tokentype_initialws) {
1147 * Still working on the same name.
1149 initialws = ISC_TRUE;
1150 } else if (token.type == isc_tokentype_string ||
1151 token.type == isc_tokentype_qstring) {
1154 * "$" Support.
1156 * "$ORIGIN" and "$INCLUDE" can both take domain names.
1157 * The processing of "$ORIGIN" and "$INCLUDE" extends
1158 * across the normal domain name processing.
1161 if (strcasecmp(DNS_AS_STR(token), "$ORIGIN") == 0) {
1162 GETTOKEN(lctx->lex, 0, &token, ISC_FALSE);
1163 finish_origin = ISC_TRUE;
1164 } else if (strcasecmp(DNS_AS_STR(token),
1165 "$TTL") == 0) {
1166 GETTOKENERR(lctx->lex, 0, &token, ISC_FALSE,
1167 lctx->ttl = 0;
1168 lctx->default_ttl_known = ISC_TRUE;);
1169 result =
1170 dns_ttl_fromtext(&token.value.as_textregion,
1171 &lctx->ttl);
1172 if (MANYERRS(lctx, result)) {
1173 SETRESULT(lctx, result);
1174 lctx->ttl = 0;
1175 } else if (result != ISC_R_SUCCESS)
1176 goto insist_and_cleanup;
1177 limit_ttl(callbacks, source, line, &lctx->ttl);
1178 lctx->default_ttl = lctx->ttl;
1179 lctx->default_ttl_known = ISC_TRUE;
1180 EXPECTEOL;
1181 continue;
1182 } else if (strcasecmp(DNS_AS_STR(token),
1183 "$INCLUDE") == 0) {
1184 COMMITALL;
1185 if ((lctx->options & DNS_MASTER_NOINCLUDE)
1186 != 0)
1188 (callbacks->error)(callbacks,
1189 "%s: %s:%lu: $INCLUDE not allowed",
1190 "dns_master_load",
1191 source, line);
1192 result = DNS_R_REFUSED;
1193 goto insist_and_cleanup;
1195 if (ttl_offset != 0) {
1196 (callbacks->error)(callbacks,
1197 "%s: %s:%lu: $INCLUDE "
1198 "may not be used with $DATE",
1199 "dns_master_load",
1200 source, line);
1201 result = DNS_R_SYNTAX;
1202 goto insist_and_cleanup;
1204 GETTOKEN(lctx->lex, ISC_LEXOPT_QSTRING, &token,
1205 ISC_FALSE);
1206 if (include_file != NULL)
1207 isc_mem_free(mctx, include_file);
1208 include_file = isc_mem_strdup(mctx,
1209 DNS_AS_STR(token));
1210 if (include_file == NULL) {
1211 result = ISC_R_NOMEMORY;
1212 goto log_and_cleanup;
1214 GETTOKEN(lctx->lex, 0, &token, ISC_TRUE);
1216 if (token.type == isc_tokentype_eol ||
1217 token.type == isc_tokentype_eof) {
1218 if (token.type == isc_tokentype_eof)
1219 WARNUNEXPECTEDEOF(lctx->lex);
1221 * No origin field.
1223 result = pushfile(include_file,
1224 ictx->origin, lctx);
1225 if (MANYERRS(lctx, result)) {
1226 SETRESULT(lctx, result);
1227 LOGITFILE(result, include_file);
1228 continue;
1229 } else if (result != ISC_R_SUCCESS) {
1230 LOGITFILE(result, include_file);
1231 goto insist_and_cleanup;
1233 ictx = lctx->inc;
1234 source =
1235 isc_lex_getsourcename(lctx->lex);
1236 line = isc_lex_getsourceline(lctx->lex);
1237 POST(line);
1238 continue;
1241 * There is an origin field. Fall through
1242 * to domain name processing code and do
1243 * the actual inclusion later.
1245 finish_include = ISC_TRUE;
1246 } else if (strcasecmp(DNS_AS_STR(token),
1247 "$DATE") == 0) {
1248 isc_int64_t dump_time64;
1249 isc_stdtime_t dump_time, current_time;
1250 GETTOKEN(lctx->lex, 0, &token, ISC_FALSE);
1251 isc_stdtime_get(&current_time);
1252 result = dns_time64_fromtext(DNS_AS_STR(token),
1253 &dump_time64);
1254 if (MANYERRS(lctx, result)) {
1255 SETRESULT(lctx, result);
1256 LOGIT(result);
1257 dump_time64 = 0;
1258 } else if (result != ISC_R_SUCCESS)
1259 goto log_and_cleanup;
1260 dump_time = (isc_stdtime_t)dump_time64;
1261 if (dump_time != dump_time64) {
1262 UNEXPECTED_ERROR(__FILE__, __LINE__,
1263 "%s: %s:%lu: $DATE outside epoch",
1264 "dns_master_load", source, line);
1265 result = ISC_R_UNEXPECTED;
1266 goto insist_and_cleanup;
1268 if (dump_time > current_time) {
1269 UNEXPECTED_ERROR(__FILE__, __LINE__,
1270 "%s: %s:%lu: "
1271 "$DATE in future, using current date",
1272 "dns_master_load", source, line);
1273 dump_time = current_time;
1275 ttl_offset = current_time - dump_time;
1276 EXPECTEOL;
1277 continue;
1278 } else if (strcasecmp(DNS_AS_STR(token),
1279 "$GENERATE") == 0) {
1281 * Lazy cleanup.
1283 if (range != NULL)
1284 isc_mem_free(mctx, range);
1285 if (lhs != NULL)
1286 isc_mem_free(mctx, lhs);
1287 if (gtype != NULL)
1288 isc_mem_free(mctx, gtype);
1289 if (rhs != NULL)
1290 isc_mem_free(mctx, rhs);
1291 range = lhs = gtype = rhs = NULL;
1292 /* RANGE */
1293 GETTOKEN(lctx->lex, 0, &token, ISC_FALSE);
1294 range = isc_mem_strdup(mctx,
1295 DNS_AS_STR(token));
1296 if (range == NULL) {
1297 result = ISC_R_NOMEMORY;
1298 goto log_and_cleanup;
1300 /* LHS */
1301 GETTOKEN(lctx->lex, 0, &token, ISC_FALSE);
1302 lhs = isc_mem_strdup(mctx, DNS_AS_STR(token));
1303 if (lhs == NULL) {
1304 result = ISC_R_NOMEMORY;
1305 goto log_and_cleanup;
1307 rdclass = 0;
1308 explicit_ttl = ISC_FALSE;
1309 /* CLASS? */
1310 GETTOKEN(lctx->lex, 0, &token, ISC_FALSE);
1311 if (dns_rdataclass_fromtext(&rdclass,
1312 &token.value.as_textregion)
1313 == ISC_R_SUCCESS) {
1314 GETTOKEN(lctx->lex, 0, &token,
1315 ISC_FALSE);
1317 /* TTL? */
1318 if (dns_ttl_fromtext(&token.value.as_textregion,
1319 &lctx->ttl)
1320 == ISC_R_SUCCESS) {
1321 limit_ttl(callbacks, source, line,
1322 &lctx->ttl);
1323 lctx->ttl_known = ISC_TRUE;
1324 explicit_ttl = ISC_TRUE;
1325 GETTOKEN(lctx->lex, 0, &token,
1326 ISC_FALSE);
1328 /* CLASS? */
1329 if (rdclass == 0 &&
1330 dns_rdataclass_fromtext(&rdclass,
1331 &token.value.as_textregion)
1332 == ISC_R_SUCCESS)
1333 GETTOKEN(lctx->lex, 0, &token,
1334 ISC_FALSE);
1335 /* TYPE */
1336 gtype = isc_mem_strdup(mctx,
1337 DNS_AS_STR(token));
1338 if (gtype == NULL) {
1339 result = ISC_R_NOMEMORY;
1340 goto log_and_cleanup;
1342 /* RHS */
1343 GETTOKEN(lctx->lex, ISC_LEXOPT_QSTRING,
1344 &token, ISC_FALSE);
1345 rhs = isc_mem_strdup(mctx, DNS_AS_STR(token));
1346 if (rhs == NULL) {
1347 result = ISC_R_NOMEMORY;
1348 goto log_and_cleanup;
1350 if (!lctx->ttl_known &&
1351 !lctx->default_ttl_known) {
1352 (*callbacks->error)(callbacks,
1353 "%s: %s:%lu: no TTL specified",
1354 "dns_master_load", source, line);
1355 result = DNS_R_NOTTL;
1356 if (MANYERRS(lctx, result)) {
1357 SETRESULT(lctx, result);
1358 lctx->ttl = 0;
1359 } else if (result != ISC_R_SUCCESS)
1360 goto insist_and_cleanup;
1361 } else if (!explicit_ttl &&
1362 lctx->default_ttl_known) {
1363 lctx->ttl = lctx->default_ttl;
1366 * If the class specified does not match the
1367 * zone's class print out a error message and
1368 * exit.
1370 if (rdclass != 0 && rdclass != lctx->zclass) {
1371 goto bad_class;
1373 result = generate(lctx, range, lhs, gtype, rhs,
1374 source, line);
1375 if (MANYERRS(lctx, result)) {
1376 SETRESULT(lctx, result);
1377 } else if (result != ISC_R_SUCCESS)
1378 goto insist_and_cleanup;
1379 EXPECTEOL;
1380 continue;
1381 } else if (strncasecmp(DNS_AS_STR(token),
1382 "$", 1) == 0) {
1383 (callbacks->error)(callbacks,
1384 "%s: %s:%lu: "
1385 "unknown $ directive '%s'",
1386 "dns_master_load", source, line,
1387 DNS_AS_STR(token));
1388 result = DNS_R_SYNTAX;
1389 if (MANYERRS(lctx, result)) {
1390 SETRESULT(lctx, result);
1391 } else if (result != ISC_R_SUCCESS)
1392 goto insist_and_cleanup;
1396 * Normal processing resumes.
1398 * Find a free name buffer.
1400 for (new_in_use = 0; new_in_use < NBUFS; new_in_use++)
1401 if (!ictx->in_use[new_in_use])
1402 break;
1403 INSIST(new_in_use < NBUFS);
1404 dns_fixedname_init(&ictx->fixed[new_in_use]);
1405 new_name = dns_fixedname_name(&ictx->fixed[new_in_use]);
1406 isc_buffer_init(&buffer, token.value.as_region.base,
1407 token.value.as_region.length);
1408 isc_buffer_add(&buffer, token.value.as_region.length);
1409 isc_buffer_setactive(&buffer,
1410 token.value.as_region.length);
1411 result = dns_name_fromtext(new_name, &buffer,
1412 ictx->origin, 0, NULL);
1413 if (MANYERRS(lctx, result)) {
1414 SETRESULT(lctx, result);
1415 LOGIT(result);
1416 read_till_eol = ISC_TRUE;
1417 continue;
1418 } else if (result != ISC_R_SUCCESS)
1419 goto log_and_cleanup;
1422 * Finish $ORIGIN / $INCLUDE processing if required.
1424 if (finish_origin) {
1425 if (ictx->origin_in_use != -1)
1426 ictx->in_use[ictx->origin_in_use] =
1427 ISC_FALSE;
1428 ictx->origin_in_use = new_in_use;
1429 ictx->in_use[ictx->origin_in_use] = ISC_TRUE;
1430 ictx->origin = new_name;
1431 ictx->origin_changed = ISC_TRUE;
1432 finish_origin = ISC_FALSE;
1433 EXPECTEOL;
1434 continue;
1436 if (finish_include) {
1437 finish_include = ISC_FALSE;
1438 EXPECTEOL;
1439 result = pushfile(include_file, new_name, lctx);
1440 if (MANYERRS(lctx, result)) {
1441 SETRESULT(lctx, result);
1442 LOGITFILE(result, include_file);
1443 continue;
1444 } else if (result != ISC_R_SUCCESS) {
1445 LOGITFILE(result, include_file);
1446 goto insist_and_cleanup;
1448 ictx = lctx->inc;
1449 ictx->origin_changed = ISC_TRUE;
1450 source = isc_lex_getsourcename(lctx->lex);
1451 line = isc_lex_getsourceline(lctx->lex);
1452 POST(line);
1453 continue;
1457 * "$" Processing Finished
1461 * If we are processing glue and the new name does
1462 * not match the current glue name, commit the glue
1463 * and pop stacks leaving us in 'normal' processing
1464 * state. Linked lists are undone by commit().
1466 if (ictx->glue != NULL &&
1467 dns_name_compare(ictx->glue, new_name) != 0) {
1468 result = commit(callbacks, lctx, &glue_list,
1469 ictx->glue, source,
1470 ictx->glue_line);
1471 if (MANYERRS(lctx, result)) {
1472 SETRESULT(lctx, result);
1473 } else if (result != ISC_R_SUCCESS)
1474 goto insist_and_cleanup;
1475 if (ictx->glue_in_use != -1)
1476 ictx->in_use[ictx->glue_in_use] =
1477 ISC_FALSE;
1478 ictx->glue_in_use = -1;
1479 ictx->glue = NULL;
1480 rdcount = rdcount_save;
1481 rdlcount = rdlcount_save;
1482 target = target_save;
1486 * If we are in 'normal' processing state and the new
1487 * name does not match the current name, see if the
1488 * new name is for glue and treat it as such,
1489 * otherwise we have a new name so commit what we
1490 * have.
1492 if ((ictx->glue == NULL) && (ictx->current == NULL ||
1493 dns_name_compare(ictx->current, new_name) != 0)) {
1494 if (current_has_delegation &&
1495 is_glue(&current_list, new_name)) {
1496 rdcount_save = rdcount;
1497 rdlcount_save = rdlcount;
1498 target_save = target;
1499 ictx->glue = new_name;
1500 ictx->glue_in_use = new_in_use;
1501 ictx->in_use[ictx->glue_in_use] =
1502 ISC_TRUE;
1503 } else {
1504 result = commit(callbacks, lctx,
1505 &current_list,
1506 ictx->current,
1507 source,
1508 ictx->current_line);
1509 if (MANYERRS(lctx, result)) {
1510 SETRESULT(lctx, result);
1511 } else if (result != ISC_R_SUCCESS)
1512 goto insist_and_cleanup;
1513 rdcount = 0;
1514 rdlcount = 0;
1515 if (ictx->current_in_use != -1)
1516 ictx->in_use[ictx->current_in_use] =
1517 ISC_FALSE;
1518 ictx->current_in_use = new_in_use;
1519 ictx->in_use[ictx->current_in_use] =
1520 ISC_TRUE;
1521 ictx->current = new_name;
1522 current_has_delegation = ISC_FALSE;
1523 isc_buffer_init(&target, target_mem,
1524 target_size);
1527 * Check for internal wildcards.
1529 if ((lctx->options & DNS_MASTER_CHECKWILDCARD)
1530 != 0)
1531 check_wildcard(ictx, source, line,
1532 callbacks);
1535 if ((lctx->options & DNS_MASTER_ZONE) != 0 &&
1536 (lctx->options & DNS_MASTER_SLAVE) == 0 &&
1537 (lctx->options & DNS_MASTER_KEY) == 0 &&
1538 !dns_name_issubdomain(new_name, lctx->top))
1540 char namebuf[DNS_NAME_FORMATSIZE];
1541 dns_name_format(new_name, namebuf,
1542 sizeof(namebuf));
1544 * Ignore out-of-zone data.
1546 (*callbacks->warn)(callbacks,
1547 "%s:%lu: "
1548 "ignoring out-of-zone data (%s)",
1549 source, line, namebuf);
1550 ictx->drop = ISC_TRUE;
1551 } else
1552 ictx->drop = ISC_FALSE;
1553 } else {
1554 UNEXPECTED_ERROR(__FILE__, __LINE__,
1555 "%s:%lu: isc_lex_gettoken() returned "
1556 "unexpected token type (%d)",
1557 source, line, token.type);
1558 result = ISC_R_UNEXPECTED;
1559 if (MANYERRS(lctx, result)) {
1560 SETRESULT(lctx, result);
1561 LOGIT(result);
1562 continue;
1563 } else if (result != ISC_R_SUCCESS)
1564 goto insist_and_cleanup;
1568 * Find TTL, class and type. Both TTL and class are optional
1569 * and may occur in any order if they exist. TTL and class
1570 * come before type which must exist.
1572 * [<TTL>] [<class>] <type> <RDATA>
1573 * [<class>] [<TTL>] <type> <RDATA>
1576 type = 0;
1577 rdclass = 0;
1579 GETTOKEN(lctx->lex, 0, &token, initialws);
1581 if (initialws) {
1582 if (token.type == isc_tokentype_eol) {
1583 read_till_eol = ISC_FALSE;
1584 continue; /* blank line */
1587 if (token.type == isc_tokentype_eof) {
1588 WARNUNEXPECTEDEOF(lctx->lex);
1589 read_till_eol = ISC_FALSE;
1590 isc_lex_ungettoken(lctx->lex, &token);
1591 continue;
1594 if (ictx->current == NULL) {
1595 (*callbacks->error)(callbacks,
1596 "%s:%lu: no current owner name",
1597 source, line);
1598 result = DNS_R_NOOWNER;
1599 if (MANYERRS(lctx, result)) {
1600 SETRESULT(lctx, result);
1601 read_till_eol = ISC_TRUE;
1602 continue;
1603 } else if (result != ISC_R_SUCCESS)
1604 goto insist_and_cleanup;
1607 if (ictx->origin_changed) {
1608 char cbuf[DNS_NAME_FORMATSIZE];
1609 char obuf[DNS_NAME_FORMATSIZE];
1610 dns_name_format(ictx->current, cbuf,
1611 sizeof(cbuf));
1612 dns_name_format(ictx->origin, obuf,
1613 sizeof(obuf));
1614 (*callbacks->warn)(callbacks,
1615 "%s:%lu: record with inherited "
1616 "owner (%s) immediately after "
1617 "$ORIGIN (%s)", source, line,
1618 cbuf, obuf);
1622 ictx->origin_changed = ISC_FALSE;
1624 if (dns_rdataclass_fromtext(&rdclass,
1625 &token.value.as_textregion)
1626 == ISC_R_SUCCESS)
1627 GETTOKEN(lctx->lex, 0, &token, ISC_FALSE);
1629 explicit_ttl = ISC_FALSE;
1630 result = dns_ttl_fromtext(&token.value.as_textregion,
1631 &lctx->ttl);
1632 if (result == ISC_R_SUCCESS) {
1633 limit_ttl(callbacks, source, line, &lctx->ttl);
1634 explicit_ttl = ISC_TRUE;
1635 lctx->ttl_known = ISC_TRUE;
1636 GETTOKEN(lctx->lex, 0, &token, ISC_FALSE);
1639 if (token.type != isc_tokentype_string) {
1640 UNEXPECTED_ERROR(__FILE__, __LINE__,
1641 "isc_lex_gettoken() returned unexpected token type");
1642 result = ISC_R_UNEXPECTED;
1643 if (MANYERRS(lctx, result)) {
1644 SETRESULT(lctx, result);
1645 read_till_eol = ISC_TRUE;
1646 continue;
1647 } else if (result != ISC_R_SUCCESS)
1648 goto insist_and_cleanup;
1651 if (rdclass == 0 &&
1652 dns_rdataclass_fromtext(&rdclass,
1653 &token.value.as_textregion)
1654 == ISC_R_SUCCESS)
1655 GETTOKEN(lctx->lex, 0, &token, ISC_FALSE);
1657 if (token.type != isc_tokentype_string) {
1658 UNEXPECTED_ERROR(__FILE__, __LINE__,
1659 "isc_lex_gettoken() returned unexpected token type");
1660 result = ISC_R_UNEXPECTED;
1661 if (MANYERRS(lctx, result)) {
1662 SETRESULT(lctx, result);
1663 read_till_eol = ISC_TRUE;
1664 continue;
1665 } else if (result != ISC_R_SUCCESS)
1666 goto insist_and_cleanup;
1669 result = dns_rdatatype_fromtext(&type,
1670 &token.value.as_textregion);
1671 if (result != ISC_R_SUCCESS) {
1672 (*callbacks->warn)(callbacks,
1673 "%s:%lu: unknown RR type '%.*s'",
1674 source, line,
1675 token.value.as_textregion.length,
1676 token.value.as_textregion.base);
1677 if (MANYERRS(lctx, result)) {
1678 SETRESULT(lctx, result);
1679 read_till_eol = ISC_TRUE;
1680 continue;
1681 } else if (result != ISC_R_SUCCESS)
1682 goto insist_and_cleanup;
1686 * If the class specified does not match the zone's class
1687 * print out a error message and exit.
1689 if (rdclass != 0 && rdclass != lctx->zclass) {
1690 bad_class:
1692 dns_rdataclass_format(rdclass, classname1,
1693 sizeof(classname1));
1694 dns_rdataclass_format(lctx->zclass, classname2,
1695 sizeof(classname2));
1696 (*callbacks->error)(callbacks,
1697 "%s:%lu: class '%s' != "
1698 "zone class '%s'",
1699 source, line,
1700 classname1, classname2);
1701 result = DNS_R_BADCLASS;
1702 if (MANYERRS(lctx, result)) {
1703 SETRESULT(lctx, result);
1704 read_till_eol = ISC_TRUE;
1705 continue;
1706 } else if (result != ISC_R_SUCCESS)
1707 goto insist_and_cleanup;
1710 if (type == dns_rdatatype_ns && ictx->glue == NULL)
1711 current_has_delegation = ISC_TRUE;
1714 * RFC1123: MD and MF are not allowed to be loaded from
1715 * master files.
1717 if ((lctx->options & DNS_MASTER_ZONE) != 0 &&
1718 (lctx->options & DNS_MASTER_SLAVE) == 0 &&
1719 (type == dns_rdatatype_md || type == dns_rdatatype_mf)) {
1720 char typename[DNS_RDATATYPE_FORMATSIZE];
1722 result = DNS_R_OBSOLETE;
1724 dns_rdatatype_format(type, typename, sizeof(typename));
1725 (*callbacks->error)(callbacks,
1726 "%s:%lu: %s '%s': %s",
1727 source, line,
1728 "type", typename,
1729 dns_result_totext(result));
1730 if (MANYERRS(lctx, result)) {
1731 SETRESULT(lctx, result);
1732 } else
1733 goto insist_and_cleanup;
1737 * Find a rdata structure.
1739 if (rdcount == rdata_size) {
1740 new_rdata = grow_rdata(rdata_size + RDSZ, rdata,
1741 rdata_size, &current_list,
1742 &glue_list, mctx);
1743 if (new_rdata == NULL) {
1744 result = ISC_R_NOMEMORY;
1745 goto log_and_cleanup;
1747 rdata_size += RDSZ;
1748 rdata = new_rdata;
1752 * Peek at the NS record.
1754 if (type == dns_rdatatype_ns &&
1755 lctx->zclass == dns_rdataclass_in &&
1756 (lctx->options & DNS_MASTER_CHECKNS) != 0) {
1758 GETTOKEN(lctx->lex, 0, &token, ISC_FALSE);
1759 result = check_ns(lctx, &token, source, line);
1760 isc_lex_ungettoken(lctx->lex, &token);
1761 if ((lctx->options & DNS_MASTER_FATALNS) != 0) {
1762 if (MANYERRS(lctx, result)) {
1763 SETRESULT(lctx, result);
1764 } else if (result != ISC_R_SUCCESS)
1765 goto insist_and_cleanup;
1770 * Check owner name.
1772 options &= ~DNS_RDATA_CHECKREVERSE;
1773 if ((lctx->options & DNS_MASTER_CHECKNAMES) != 0) {
1774 isc_boolean_t ok;
1775 dns_name_t *name;
1777 name = (ictx->glue != NULL) ? ictx->glue :
1778 ictx->current;
1779 ok = dns_rdata_checkowner(name, lctx->zclass, type,
1780 ISC_TRUE);
1781 if (!ok) {
1782 char namebuf[DNS_NAME_FORMATSIZE];
1783 const char *desc;
1784 dns_name_format(name, namebuf, sizeof(namebuf));
1785 result = DNS_R_BADOWNERNAME;
1786 desc = dns_result_totext(result);
1787 if (CHECKNAMESFAIL(lctx->options) ||
1788 type == dns_rdatatype_nsec3) {
1789 (*callbacks->error)(callbacks,
1790 "%s:%lu: %s: %s",
1791 source, line,
1792 namebuf, desc);
1793 if (MANYERRS(lctx, result)) {
1794 SETRESULT(lctx, result);
1795 } else if (result != ISC_R_SUCCESS)
1796 goto cleanup;
1797 } else {
1798 (*callbacks->warn)(callbacks,
1799 "%s:%lu: %s: %s",
1800 source, line,
1801 namebuf, desc);
1804 if (type == dns_rdatatype_ptr &&
1805 (dns_name_issubdomain(name, &in_addr_arpa) ||
1806 dns_name_issubdomain(name, &ip6_arpa) ||
1807 dns_name_issubdomain(name, &ip6_int)))
1808 options |= DNS_RDATA_CHECKREVERSE;
1812 * Read rdata contents.
1814 dns_rdata_init(&rdata[rdcount]);
1815 target_ft = target;
1816 result = dns_rdata_fromtext(&rdata[rdcount], lctx->zclass,
1817 type, lctx->lex, ictx->origin,
1818 options, lctx->mctx, &target,
1819 callbacks);
1820 if (MANYERRS(lctx, result)) {
1821 SETRESULT(lctx, result);
1822 continue;
1823 } else if (result != ISC_R_SUCCESS)
1824 goto insist_and_cleanup;
1826 if (ictx->drop) {
1827 target = target_ft;
1828 continue;
1831 if (type == dns_rdatatype_soa &&
1832 (lctx->options & DNS_MASTER_ZONE) != 0 &&
1833 dns_name_compare(ictx->current, lctx->top) != 0) {
1834 char namebuf[DNS_NAME_FORMATSIZE];
1835 dns_name_format(ictx->current, namebuf,
1836 sizeof(namebuf));
1837 (*callbacks->error)(callbacks, "%s:%lu: SOA "
1838 "record not at top of zone (%s)",
1839 source, line, namebuf);
1840 result = DNS_R_NOTZONETOP;
1841 if (MANYERRS(lctx, result)) {
1842 SETRESULT(lctx, result);
1843 read_till_eol = ISC_TRUE;
1844 target = target_ft;
1845 continue;
1846 } else if (result != ISC_R_SUCCESS)
1847 goto insist_and_cleanup;
1851 if (type == dns_rdatatype_rrsig ||
1852 type == dns_rdatatype_sig)
1853 covers = dns_rdata_covers(&rdata[rdcount]);
1854 else
1855 covers = 0;
1857 if (!lctx->ttl_known && !lctx->default_ttl_known) {
1858 if (type == dns_rdatatype_soa) {
1859 (*callbacks->warn)(callbacks,
1860 "%s:%lu: no TTL specified; "
1861 "using SOA MINTTL instead",
1862 source, line);
1863 lctx->ttl = dns_soa_getminimum(&rdata[rdcount]);
1864 limit_ttl(callbacks, source, line, &lctx->ttl);
1865 lctx->default_ttl = lctx->ttl;
1866 lctx->default_ttl_known = ISC_TRUE;
1867 } else if ((lctx->options & DNS_MASTER_HINT) != 0) {
1869 * Zero TTL's are fine for hints.
1871 lctx->ttl = 0;
1872 lctx->default_ttl = lctx->ttl;
1873 lctx->default_ttl_known = ISC_TRUE;
1874 } else {
1875 (*callbacks->warn)(callbacks,
1876 "%s:%lu: no TTL specified; "
1877 "zone rejected",
1878 source, line);
1879 result = DNS_R_NOTTL;
1880 if (MANYERRS(lctx, result)) {
1881 SETRESULT(lctx, result);
1882 lctx->ttl = 0;
1883 } else {
1884 goto insist_and_cleanup;
1887 } else if (!explicit_ttl && lctx->default_ttl_known) {
1888 lctx->ttl = lctx->default_ttl;
1889 } else if (!explicit_ttl && lctx->warn_1035) {
1890 (*callbacks->warn)(callbacks,
1891 "%s:%lu: "
1892 "using RFC1035 TTL semantics",
1893 source, line);
1894 lctx->warn_1035 = ISC_FALSE;
1897 if (type == dns_rdatatype_rrsig && lctx->warn_sigexpired) {
1898 dns_rdata_rrsig_t sig;
1899 result = dns_rdata_tostruct(&rdata[rdcount], &sig,
1900 NULL);
1901 RUNTIME_CHECK(result == ISC_R_SUCCESS);
1902 if (isc_serial_lt(sig.timeexpire, now)) {
1903 (*callbacks->warn)(callbacks,
1904 "%s:%lu: "
1905 "signature has expired",
1906 source, line);
1907 lctx->warn_sigexpired = ISC_FALSE;
1911 if ((type == dns_rdatatype_sig || type == dns_rdatatype_nxt) &&
1912 lctx->warn_tcr && (lctx->options & DNS_MASTER_ZONE) != 0 &&
1913 (lctx->options & DNS_MASTER_SLAVE) == 0) {
1914 (*callbacks->warn)(callbacks, "%s:%lu: old style DNSSEC "
1915 " zone detected", source, line);
1916 lctx->warn_tcr = ISC_FALSE;
1919 if ((lctx->options & DNS_MASTER_AGETTL) != 0) {
1921 * Adjust the TTL for $DATE. If the RR has already
1922 * expired, ignore it.
1924 if (lctx->ttl < ttl_offset)
1925 continue;
1926 lctx->ttl -= ttl_offset;
1930 * Find type in rdatalist.
1931 * If it does not exist create new one and prepend to list
1932 * as this will minimise list traversal.
1934 if (ictx->glue != NULL)
1935 this = ISC_LIST_HEAD(glue_list);
1936 else
1937 this = ISC_LIST_HEAD(current_list);
1939 while (this != NULL) {
1940 if (this->type == type && this->covers == covers)
1941 break;
1942 this = ISC_LIST_NEXT(this, link);
1945 if (this == NULL) {
1946 if (rdlcount == rdatalist_size) {
1947 new_rdatalist =
1948 grow_rdatalist(rdatalist_size + RDLSZ,
1949 rdatalist,
1950 rdatalist_size,
1951 &current_list,
1952 &glue_list,
1953 mctx);
1954 if (new_rdatalist == NULL) {
1955 result = ISC_R_NOMEMORY;
1956 goto log_and_cleanup;
1958 rdatalist = new_rdatalist;
1959 rdatalist_size += RDLSZ;
1961 this = &rdatalist[rdlcount++];
1962 this->type = type;
1963 this->covers = covers;
1964 this->rdclass = lctx->zclass;
1965 this->ttl = lctx->ttl;
1966 ISC_LIST_INIT(this->rdata);
1967 if (ictx->glue != NULL)
1968 ISC_LIST_INITANDPREPEND(glue_list, this, link);
1969 else
1970 ISC_LIST_INITANDPREPEND(current_list, this,
1971 link);
1972 } else if (this->ttl != lctx->ttl) {
1973 (*callbacks->warn)(callbacks,
1974 "%s:%lu: "
1975 "TTL set to prior TTL (%lu)",
1976 source, line, this->ttl);
1977 lctx->ttl = this->ttl;
1980 if ((lctx->options & DNS_MASTER_CHECKTTL) != 0 &&
1981 lctx->ttl > lctx->maxttl)
1983 (callbacks->error)(callbacks,
1984 "dns_master_load: %s:%lu: "
1985 "TTL %d exceeds configured max-zone-ttl %d",
1986 source, line, lctx->ttl, lctx->maxttl);
1987 result = ISC_R_RANGE;
1988 goto log_and_cleanup;
1991 ISC_LIST_APPEND(this->rdata, &rdata[rdcount], link);
1992 if (ictx->glue != NULL)
1993 ictx->glue_line = line;
1994 else
1995 ictx->current_line = line;
1996 rdcount++;
1999 * We must have at least 64k as rdlen is 16 bits.
2000 * If we don't commit everything we have so far.
2002 if ((target.length - target.used) < MINTSIZ)
2003 COMMITALL;
2004 next_line:
2006 } while (!done && (lctx->loop_cnt == 0 || loop_cnt++ < lctx->loop_cnt));
2009 * Commit what has not yet been committed.
2011 result = commit(callbacks, lctx, &current_list, ictx->current,
2012 source, ictx->current_line);
2013 if (MANYERRS(lctx, result)) {
2014 SETRESULT(lctx, result);
2015 } else if (result != ISC_R_SUCCESS)
2016 goto insist_and_cleanup;
2017 result = commit(callbacks, lctx, &glue_list, ictx->glue,
2018 source, ictx->glue_line);
2019 if (MANYERRS(lctx, result)) {
2020 SETRESULT(lctx, result);
2021 } else if (result != ISC_R_SUCCESS)
2022 goto insist_and_cleanup;
2024 if (!done) {
2025 INSIST(lctx->done != NULL && lctx->task != NULL);
2026 result = DNS_R_CONTINUE;
2027 } else if (result == ISC_R_SUCCESS && lctx->result != ISC_R_SUCCESS) {
2028 result = lctx->result;
2029 } else if (result == ISC_R_SUCCESS && lctx->seen_include)
2030 result = DNS_R_SEENINCLUDE;
2031 goto cleanup;
2033 log_and_cleanup:
2034 LOGIT(result);
2036 insist_and_cleanup:
2037 INSIST(result != ISC_R_SUCCESS);
2039 cleanup:
2040 while ((this = ISC_LIST_HEAD(current_list)) != NULL)
2041 ISC_LIST_UNLINK(current_list, this, link);
2042 while ((this = ISC_LIST_HEAD(glue_list)) != NULL)
2043 ISC_LIST_UNLINK(glue_list, this, link);
2044 if (rdatalist != NULL)
2045 isc_mem_put(mctx, rdatalist,
2046 rdatalist_size * sizeof(*rdatalist));
2047 if (rdata != NULL)
2048 isc_mem_put(mctx, rdata, rdata_size * sizeof(*rdata));
2049 if (target_mem != NULL)
2050 isc_mem_put(mctx, target_mem, target_size);
2051 if (include_file != NULL)
2052 isc_mem_free(mctx, include_file);
2053 if (range != NULL)
2054 isc_mem_free(mctx, range);
2055 if (lhs != NULL)
2056 isc_mem_free(mctx, lhs);
2057 if (gtype != NULL)
2058 isc_mem_free(mctx, gtype);
2059 if (rhs != NULL)
2060 isc_mem_free(mctx, rhs);
2061 return (result);
2064 static isc_result_t
2065 pushfile(const char *master_file, dns_name_t *origin, dns_loadctx_t *lctx) {
2066 isc_result_t result;
2067 dns_incctx_t *ictx;
2068 dns_incctx_t *new = NULL;
2069 isc_region_t r;
2070 int new_in_use;
2072 REQUIRE(master_file != NULL);
2073 REQUIRE(DNS_LCTX_VALID(lctx));
2075 ictx = lctx->inc;
2076 lctx->seen_include = ISC_TRUE;
2078 result = incctx_create(lctx->mctx, origin, &new);
2079 if (result != ISC_R_SUCCESS)
2080 return (result);
2083 * Push origin_changed.
2085 new->origin_changed = ictx->origin_changed;
2087 /* Set current domain. */
2088 if (ictx->glue != NULL || ictx->current != NULL) {
2089 for (new_in_use = 0; new_in_use < NBUFS; new_in_use++)
2090 if (!new->in_use[new_in_use])
2091 break;
2092 INSIST(new_in_use < NBUFS);
2093 new->current_in_use = new_in_use;
2094 new->current =
2095 dns_fixedname_name(&new->fixed[new->current_in_use]);
2096 new->in_use[new->current_in_use] = ISC_TRUE;
2097 dns_name_toregion((ictx->glue != NULL) ?
2098 ictx->glue : ictx->current, &r);
2099 dns_name_fromregion(new->current, &r);
2100 new->drop = ictx->drop;
2103 result = (lctx->openfile)(lctx, master_file);
2104 if (result != ISC_R_SUCCESS)
2105 goto cleanup;
2106 new->parent = ictx;
2107 lctx->inc = new;
2109 if (lctx->include_cb != NULL)
2110 lctx->include_cb(master_file, lctx->include_arg);
2111 return (ISC_R_SUCCESS);
2113 cleanup:
2114 incctx_destroy(lctx->mctx, new);
2115 return (result);
2118 static inline isc_result_t
2119 read_and_check(isc_boolean_t do_read, isc_buffer_t *buffer,
2120 size_t len, FILE *f)
2122 isc_result_t result;
2124 if (do_read) {
2125 INSIST(isc_buffer_availablelength(buffer) >= len);
2126 result = isc_stdio_read(isc_buffer_used(buffer), 1, len,
2127 f, NULL);
2128 if (result != ISC_R_SUCCESS)
2129 return (result);
2130 isc_buffer_add(buffer, (unsigned int)len);
2131 } else if (isc_buffer_remaininglength(buffer) < len)
2132 return (ISC_R_RANGE);
2134 return (ISC_R_SUCCESS);
2137 static isc_result_t
2138 load_header(dns_loadctx_t *lctx) {
2139 isc_result_t result = ISC_R_SUCCESS;
2140 dns_masterrawheader_t header;
2141 dns_rdatacallbacks_t *callbacks;
2142 size_t commonlen = sizeof(header.format) + sizeof(header.version);
2143 size_t remainder;
2144 unsigned char data[sizeof(header)];
2145 isc_buffer_t target;
2147 REQUIRE(DNS_LCTX_VALID(lctx));
2149 if (lctx->format != dns_masterformat_raw &&
2150 lctx->format != dns_masterformat_map)
2151 return (ISC_R_NOTIMPLEMENTED);
2153 callbacks = lctx->callbacks;
2154 dns_master_initrawheader(&header);
2156 INSIST(commonlen <= sizeof(header));
2157 isc_buffer_init(&target, data, sizeof(data));
2159 result = isc_stdio_read(data, 1, commonlen, lctx->f, NULL);
2160 if (result != ISC_R_SUCCESS) {
2161 UNEXPECTED_ERROR(__FILE__, __LINE__,
2162 "isc_stdio_read failed: %s",
2163 isc_result_totext(result));
2164 return (result);
2167 isc_buffer_add(&target, (unsigned int)commonlen);
2168 header.format = isc_buffer_getuint32(&target);
2169 if (header.format != lctx->format) {
2170 (*callbacks->error)(callbacks, "dns_master_load: "
2171 "file format mismatch (not %s)",
2172 lctx->format == dns_masterformat_map
2173 ? "map"
2174 : "raw");
2175 return (ISC_R_NOTIMPLEMENTED);
2178 header.version = isc_buffer_getuint32(&target);
2180 switch (header.version) {
2181 case 0:
2182 remainder = sizeof(header.dumptime);
2183 break;
2184 case DNS_RAWFORMAT_VERSION:
2185 remainder = sizeof(header) - commonlen;
2186 break;
2187 default:
2188 (*callbacks->error)(callbacks,
2189 "dns_master_load: "
2190 "unsupported file format version");
2191 return (ISC_R_NOTIMPLEMENTED);
2194 result = isc_stdio_read(data + commonlen, 1, remainder, lctx->f, NULL);
2195 if (result != ISC_R_SUCCESS) {
2196 UNEXPECTED_ERROR(__FILE__, __LINE__,
2197 "isc_stdio_read failed: %s",
2198 isc_result_totext(result));
2199 return (result);
2202 isc_buffer_add(&target, (unsigned int)remainder);
2203 header.dumptime = isc_buffer_getuint32(&target);
2204 if (header.version == DNS_RAWFORMAT_VERSION) {
2205 header.flags = isc_buffer_getuint32(&target);
2206 header.sourceserial = isc_buffer_getuint32(&target);
2207 header.lastxfrin = isc_buffer_getuint32(&target);
2210 lctx->first = ISC_FALSE;
2211 lctx->header = header;
2213 return (ISC_R_SUCCESS);
2216 static isc_result_t
2217 openfile_map(dns_loadctx_t *lctx, const char *master_file) {
2218 isc_result_t result;
2220 result = isc_stdio_open(master_file, "rb", &lctx->f);
2221 if (result != ISC_R_SUCCESS && result != ISC_R_FILENOTFOUND) {
2222 UNEXPECTED_ERROR(__FILE__, __LINE__,
2223 "isc_stdio_open() failed: %s",
2224 isc_result_totext(result));
2227 return (result);
2231 * Load a map format file, using mmap() to access RBT trees directly
2233 static isc_result_t
2234 load_map(dns_loadctx_t *lctx) {
2235 isc_result_t result = ISC_R_SUCCESS;
2236 dns_rdatacallbacks_t *callbacks;
2238 REQUIRE(DNS_LCTX_VALID(lctx));
2240 callbacks = lctx->callbacks;
2242 if (lctx->first) {
2243 result = load_header(lctx);
2244 if (result != ISC_R_SUCCESS)
2245 return (result);
2247 result = (*callbacks->deserialize)
2248 (callbacks->deserialize_private,
2249 lctx->f, sizeof(dns_masterrawheader_t));
2252 return (result);
2255 static isc_result_t
2256 openfile_raw(dns_loadctx_t *lctx, const char *master_file) {
2257 isc_result_t result;
2259 result = isc_stdio_open(master_file, "rb", &lctx->f);
2260 if (result != ISC_R_SUCCESS && result != ISC_R_FILENOTFOUND) {
2261 UNEXPECTED_ERROR(__FILE__, __LINE__,
2262 "isc_stdio_open() failed: %s",
2263 isc_result_totext(result));
2266 return (result);
2269 static isc_result_t
2270 load_raw(dns_loadctx_t *lctx) {
2271 isc_result_t result = ISC_R_SUCCESS;
2272 isc_boolean_t done = ISC_FALSE;
2273 unsigned int loop_cnt = 0;
2274 dns_rdatacallbacks_t *callbacks;
2275 unsigned char namebuf[DNS_NAME_MAXWIRE];
2276 dns_fixedname_t fixed;
2277 dns_name_t *name;
2278 rdatalist_head_t head, dummy;
2279 dns_rdatalist_t rdatalist;
2280 isc_mem_t *mctx = lctx->mctx;
2281 dns_rdata_t *rdata = NULL;
2282 unsigned int rdata_size = 0;
2283 int target_size = TSIZ;
2284 isc_buffer_t target, buf;
2285 unsigned char *target_mem = NULL;
2286 dns_decompress_t dctx;
2288 REQUIRE(DNS_LCTX_VALID(lctx));
2289 callbacks = lctx->callbacks;
2290 dns_decompress_init(&dctx, -1, DNS_DECOMPRESS_NONE);
2292 if (lctx->first) {
2293 result = load_header(lctx);
2294 if (result != ISC_R_SUCCESS)
2295 return (result);
2298 ISC_LIST_INIT(head);
2299 ISC_LIST_INIT(dummy);
2300 dns_rdatalist_init(&rdatalist);
2303 * Allocate target_size of buffer space. This is greater than twice
2304 * the maximum individual RR data size.
2306 target_mem = isc_mem_get(mctx, target_size);
2307 if (target_mem == NULL) {
2308 result = ISC_R_NOMEMORY;
2309 goto cleanup;
2311 isc_buffer_init(&target, target_mem, target_size);
2313 dns_fixedname_init(&fixed);
2314 name = dns_fixedname_name(&fixed);
2317 * In the following loop, we regard any error fatal regardless of
2318 * whether "MANYERRORS" is set in the context option. This is because
2319 * normal errors should already have been checked at creation time.
2320 * Besides, it is very unlikely that we can recover from an error
2321 * in this format, and so trying to continue parsing erroneous data
2322 * does not really make sense.
2324 for (loop_cnt = 0;
2325 (lctx->loop_cnt == 0 || loop_cnt < lctx->loop_cnt);
2326 loop_cnt++) {
2327 unsigned int i, rdcount;
2328 isc_uint16_t namelen;
2329 isc_uint32_t totallen;
2330 size_t minlen, readlen;
2331 isc_boolean_t sequential_read = ISC_FALSE;
2333 /* Read the data length */
2334 isc_buffer_clear(&target);
2335 INSIST(isc_buffer_availablelength(&target) >=
2336 sizeof(totallen));
2337 result = isc_stdio_read(target.base, 1, sizeof(totallen),
2338 lctx->f, NULL);
2339 if (result == ISC_R_EOF) {
2340 result = ISC_R_SUCCESS;
2341 done = ISC_TRUE;
2342 break;
2344 if (result != ISC_R_SUCCESS)
2345 goto cleanup;
2346 isc_buffer_add(&target, sizeof(totallen));
2347 totallen = isc_buffer_getuint32(&target);
2349 * Validation: the input data must at least contain the common
2350 * header.
2352 minlen = sizeof(totallen) + sizeof(isc_uint16_t) +
2353 sizeof(isc_uint16_t) + sizeof(isc_uint16_t) +
2354 sizeof(isc_uint32_t) + sizeof(isc_uint32_t);
2355 if (totallen < minlen) {
2356 result = ISC_R_RANGE;
2357 goto cleanup;
2359 totallen -= sizeof(totallen);
2361 isc_buffer_clear(&target);
2362 if (totallen > isc_buffer_availablelength(&target)) {
2364 * The default buffer size should typically be large
2365 * enough to store the entire RRset. We could try to
2366 * allocate enough space if this is not the case, but
2367 * it might cause a hazardous result when "totallen"
2368 * is forged. Thus, we'd rather take an inefficient
2369 * but robust approach in this atypical case: read
2370 * data step by step, and commit partial data when
2371 * necessary. Note that the buffer must be large
2372 * enough to store the "header part", owner name, and
2373 * at least one rdata (however large it is).
2375 sequential_read = ISC_TRUE;
2376 readlen = minlen - sizeof(totallen);
2377 } else {
2379 * Typical case. We can read the whole RRset at once
2380 * with the default buffer.
2382 readlen = totallen;
2384 result = isc_stdio_read(target.base, 1, readlen,
2385 lctx->f, NULL);
2386 if (result != ISC_R_SUCCESS)
2387 goto cleanup;
2388 isc_buffer_add(&target, (unsigned int)readlen);
2390 /* Construct RRset headers */
2391 rdatalist.rdclass = isc_buffer_getuint16(&target);
2392 rdatalist.type = isc_buffer_getuint16(&target);
2393 rdatalist.covers = isc_buffer_getuint16(&target);
2394 rdatalist.ttl = isc_buffer_getuint32(&target);
2395 rdcount = isc_buffer_getuint32(&target);
2396 if (rdcount == 0 || rdcount > 0xffff) {
2397 result = ISC_R_RANGE;
2398 goto cleanup;
2400 INSIST(isc_buffer_consumedlength(&target) <= readlen);
2402 /* Owner name: length followed by name */
2403 result = read_and_check(sequential_read, &target,
2404 sizeof(namelen), lctx->f);
2405 if (result != ISC_R_SUCCESS)
2406 goto cleanup;
2407 namelen = isc_buffer_getuint16(&target);
2408 if (namelen > sizeof(namebuf)) {
2409 result = ISC_R_RANGE;
2410 goto cleanup;
2413 result = read_and_check(sequential_read, &target, namelen,
2414 lctx->f);
2415 if (result != ISC_R_SUCCESS)
2416 goto cleanup;
2418 isc_buffer_setactive(&target, (unsigned int)namelen);
2419 result = dns_name_fromwire(name, &target, &dctx, 0, NULL);
2420 if (result != ISC_R_SUCCESS)
2421 goto cleanup;
2423 if ((lctx->options & DNS_MASTER_CHECKTTL) != 0 &&
2424 rdatalist.ttl > lctx->maxttl)
2426 (callbacks->error)(callbacks,
2427 "dns_master_load: "
2428 "TTL %d exceeds configured "
2429 "max-zone-ttl %d",
2430 rdatalist.ttl, lctx->maxttl);
2431 result = ISC_R_RANGE;
2432 goto cleanup;
2435 /* Rdata contents. */
2436 if (rdcount > rdata_size) {
2437 dns_rdata_t *new_rdata = NULL;
2439 new_rdata = grow_rdata(rdcount + RDSZ, rdata,
2440 rdata_size, &head,
2441 &dummy, mctx);
2442 if (new_rdata == NULL) {
2443 result = ISC_R_NOMEMORY;
2444 goto cleanup;
2446 rdata_size = rdcount + RDSZ;
2447 rdata = new_rdata;
2450 continue_read:
2451 for (i = 0; i < rdcount; i++) {
2452 isc_uint16_t rdlen;
2454 dns_rdata_init(&rdata[i]);
2456 if (sequential_read &&
2457 isc_buffer_availablelength(&target) < MINTSIZ) {
2458 unsigned int j;
2460 INSIST(i > 0); /* detect an infinite loop */
2462 /* Partial Commit. */
2463 ISC_LIST_APPEND(head, &rdatalist, link);
2464 result = commit(callbacks, lctx, &head, name,
2465 NULL, 0);
2466 for (j = 0; j < i; j++) {
2467 ISC_LIST_UNLINK(rdatalist.rdata,
2468 &rdata[j], link);
2469 dns_rdata_reset(&rdata[j]);
2471 if (result != ISC_R_SUCCESS)
2472 goto cleanup;
2474 /* Rewind the buffer and continue */
2475 isc_buffer_clear(&target);
2477 rdcount -= i;
2479 goto continue_read;
2482 /* rdata length */
2483 result = read_and_check(sequential_read, &target,
2484 sizeof(rdlen), lctx->f);
2485 if (result != ISC_R_SUCCESS)
2486 goto cleanup;
2487 rdlen = isc_buffer_getuint16(&target);
2489 /* rdata */
2490 result = read_and_check(sequential_read, &target,
2491 rdlen, lctx->f);
2492 if (result != ISC_R_SUCCESS)
2493 goto cleanup;
2494 isc_buffer_setactive(&target, (unsigned int)rdlen);
2496 * It is safe to have the source active region and
2497 * the target available region be the same if
2498 * decompression is disabled (see dctx above) and we
2499 * are not downcasing names (options == 0).
2501 isc_buffer_init(&buf, isc_buffer_current(&target),
2502 (unsigned int)rdlen);
2503 result = dns_rdata_fromwire(&rdata[i],
2504 rdatalist.rdclass,
2505 rdatalist.type, &target,
2506 &dctx, 0, &buf);
2507 if (result != ISC_R_SUCCESS)
2508 goto cleanup;
2509 ISC_LIST_APPEND(rdatalist.rdata, &rdata[i], link);
2513 * Sanity check. Still having remaining space is not
2514 * necessarily critical, but it very likely indicates broken
2515 * or malformed data.
2517 if (isc_buffer_remaininglength(&target) != 0) {
2518 result = ISC_R_RANGE;
2519 goto cleanup;
2522 ISC_LIST_APPEND(head, &rdatalist, link);
2524 /* Commit this RRset. rdatalist will be unlinked. */
2525 result = commit(callbacks, lctx, &head, name, NULL, 0);
2527 for (i = 0; i < rdcount; i++) {
2528 ISC_LIST_UNLINK(rdatalist.rdata, &rdata[i], link);
2529 dns_rdata_reset(&rdata[i]);
2532 if (result != ISC_R_SUCCESS)
2533 goto cleanup;
2536 if (!done) {
2537 INSIST(lctx->done != NULL && lctx->task != NULL);
2538 result = DNS_R_CONTINUE;
2539 } else if (result == ISC_R_SUCCESS && lctx->result != ISC_R_SUCCESS)
2540 result = lctx->result;
2542 if (result == ISC_R_SUCCESS && callbacks->rawdata != NULL)
2543 (*callbacks->rawdata)(callbacks->zone, &lctx->header);
2545 cleanup:
2546 if (rdata != NULL)
2547 isc_mem_put(mctx, rdata, rdata_size * sizeof(*rdata));
2548 if (target_mem != NULL)
2549 isc_mem_put(mctx, target_mem, target_size);
2550 if (result != ISC_R_SUCCESS && result != DNS_R_CONTINUE) {
2551 (*callbacks->error)(callbacks, "dns_master_load: %s",
2552 dns_result_totext(result));
2555 return (result);
2558 isc_result_t
2559 dns_master_loadfile(const char *master_file, dns_name_t *top,
2560 dns_name_t *origin,
2561 dns_rdataclass_t zclass, unsigned int options,
2562 dns_rdatacallbacks_t *callbacks, isc_mem_t *mctx)
2564 return (dns_master_loadfile5(master_file, top, origin, zclass,
2565 options, 0, callbacks, NULL, NULL,
2566 mctx, dns_masterformat_text, 0));
2569 isc_result_t
2570 dns_master_loadfile2(const char *master_file, dns_name_t *top,
2571 dns_name_t *origin,
2572 dns_rdataclass_t zclass, unsigned int options,
2573 dns_rdatacallbacks_t *callbacks, isc_mem_t *mctx,
2574 dns_masterformat_t format)
2576 return (dns_master_loadfile5(master_file, top, origin, zclass,
2577 options, 0, callbacks, NULL, NULL,
2578 mctx, format, 0));
2581 isc_result_t
2582 dns_master_loadfile3(const char *master_file, dns_name_t *top,
2583 dns_name_t *origin, dns_rdataclass_t zclass,
2584 unsigned int options, isc_uint32_t resign,
2585 dns_rdatacallbacks_t *callbacks, isc_mem_t *mctx,
2586 dns_masterformat_t format)
2588 return (dns_master_loadfile5(master_file, top, origin, zclass,
2589 options, resign, callbacks, NULL, NULL,
2590 mctx, format, 0));
2593 isc_result_t
2594 dns_master_loadfile4(const char *master_file, dns_name_t *top,
2595 dns_name_t *origin, dns_rdataclass_t zclass,
2596 unsigned int options, isc_uint32_t resign,
2597 dns_rdatacallbacks_t *callbacks,
2598 dns_masterincludecb_t include_cb, void *include_arg,
2599 isc_mem_t *mctx, dns_masterformat_t format)
2601 return (dns_master_loadfile5(master_file, top, origin, zclass,
2602 options, resign, callbacks,
2603 include_cb, include_arg,
2604 mctx, format, 0));
2607 isc_result_t
2608 dns_master_loadfile5(const char *master_file, dns_name_t *top,
2609 dns_name_t *origin, dns_rdataclass_t zclass,
2610 unsigned int options, isc_uint32_t resign,
2611 dns_rdatacallbacks_t *callbacks,
2612 dns_masterincludecb_t include_cb, void *include_arg,
2613 isc_mem_t *mctx, dns_masterformat_t format,
2614 dns_ttl_t maxttl)
2616 dns_loadctx_t *lctx = NULL;
2617 isc_result_t result;
2619 result = loadctx_create(format, mctx, options, resign, top, zclass,
2620 origin, callbacks, NULL, NULL, NULL,
2621 include_cb, include_arg, NULL, &lctx);
2622 if (result != ISC_R_SUCCESS)
2623 return (result);
2625 lctx->maxttl = maxttl;
2627 result = (lctx->openfile)(lctx, master_file);
2628 if (result != ISC_R_SUCCESS)
2629 goto cleanup;
2631 result = (lctx->load)(lctx);
2632 INSIST(result != DNS_R_CONTINUE);
2634 cleanup:
2635 dns_loadctx_detach(&lctx);
2636 return (result);
2639 isc_result_t
2640 dns_master_loadfileinc(const char *master_file, dns_name_t *top,
2641 dns_name_t *origin, dns_rdataclass_t zclass,
2642 unsigned int options, dns_rdatacallbacks_t *callbacks,
2643 isc_task_t *task, dns_loaddonefunc_t done,
2644 void *done_arg, dns_loadctx_t **lctxp, isc_mem_t *mctx)
2646 return (dns_master_loadfileinc4(master_file, top, origin, zclass,
2647 options, 0, callbacks, task, done,
2648 done_arg, lctxp, NULL, NULL, mctx,
2649 dns_masterformat_text));
2652 isc_result_t
2653 dns_master_loadfileinc2(const char *master_file, dns_name_t *top,
2654 dns_name_t *origin, dns_rdataclass_t zclass,
2655 unsigned int options, dns_rdatacallbacks_t *callbacks,
2656 isc_task_t *task, dns_loaddonefunc_t done,
2657 void *done_arg, dns_loadctx_t **lctxp, isc_mem_t *mctx,
2658 dns_masterformat_t format)
2660 return (dns_master_loadfileinc4(master_file, top, origin, zclass,
2661 options, 0, callbacks, task, done,
2662 done_arg, lctxp, NULL, NULL, mctx,
2663 format));
2666 isc_result_t
2667 dns_master_loadfileinc3(const char *master_file, dns_name_t *top,
2668 dns_name_t *origin, dns_rdataclass_t zclass,
2669 unsigned int options, isc_uint32_t resign,
2670 dns_rdatacallbacks_t *callbacks, isc_task_t *task,
2671 dns_loaddonefunc_t done, void *done_arg,
2672 dns_loadctx_t **lctxp, isc_mem_t *mctx,
2673 dns_masterformat_t format)
2675 return (dns_master_loadfileinc4(master_file, top, origin, zclass,
2676 options, resign, callbacks, task,
2677 done, done_arg, lctxp, NULL, NULL,
2678 mctx, format));
2681 isc_result_t
2682 dns_master_loadfileinc4(const char *master_file, dns_name_t *top,
2683 dns_name_t *origin, dns_rdataclass_t zclass,
2684 unsigned int options, isc_uint32_t resign,
2685 dns_rdatacallbacks_t *callbacks,
2686 isc_task_t *task, dns_loaddonefunc_t done,
2687 void *done_arg, dns_loadctx_t **lctxp,
2688 dns_masterincludecb_t include_cb, void *include_arg,
2689 isc_mem_t *mctx, dns_masterformat_t format)
2691 options &= ~DNS_MASTER_CHECKTTL;
2692 return (dns_master_loadfileinc5(master_file, top, origin, zclass,
2693 options, resign, callbacks, task,
2694 done, done_arg, lctxp, include_cb,
2695 include_arg, mctx, format, 0));
2698 isc_result_t
2699 dns_master_loadfileinc5(const char *master_file, dns_name_t *top,
2700 dns_name_t *origin, dns_rdataclass_t zclass,
2701 unsigned int options, isc_uint32_t resign,
2702 dns_rdatacallbacks_t *callbacks,
2703 isc_task_t *task, dns_loaddonefunc_t done,
2704 void *done_arg, dns_loadctx_t **lctxp,
2705 dns_masterincludecb_t include_cb, void *include_arg,
2706 isc_mem_t *mctx, dns_masterformat_t format,
2707 isc_uint32_t maxttl)
2709 dns_loadctx_t *lctx = NULL;
2710 isc_result_t result;
2712 REQUIRE(task != NULL);
2713 REQUIRE(done != NULL);
2715 result = loadctx_create(format, mctx, options, resign, top, zclass,
2716 origin, callbacks, task, done, done_arg,
2717 include_cb, include_arg, NULL, &lctx);
2718 if (result != ISC_R_SUCCESS)
2719 return (result);
2721 lctx->maxttl = maxttl;
2723 result = (lctx->openfile)(lctx, master_file);
2724 if (result != ISC_R_SUCCESS)
2725 goto cleanup;
2727 result = task_send(lctx);
2728 if (result == ISC_R_SUCCESS) {
2729 dns_loadctx_attach(lctx, lctxp);
2730 return (DNS_R_CONTINUE);
2733 cleanup:
2734 dns_loadctx_detach(&lctx);
2735 return (result);
2738 isc_result_t
2739 dns_master_loadstream(FILE *stream, dns_name_t *top, dns_name_t *origin,
2740 dns_rdataclass_t zclass, unsigned int options,
2741 dns_rdatacallbacks_t *callbacks, isc_mem_t *mctx)
2743 isc_result_t result;
2744 dns_loadctx_t *lctx = NULL;
2746 REQUIRE(stream != NULL);
2748 result = loadctx_create(dns_masterformat_text, mctx, options, 0, top,
2749 zclass, origin, callbacks, NULL, NULL, NULL,
2750 NULL, NULL, NULL, &lctx);
2751 if (result != ISC_R_SUCCESS)
2752 goto cleanup;
2754 result = isc_lex_openstream(lctx->lex, stream);
2755 if (result != ISC_R_SUCCESS)
2756 goto cleanup;
2758 result = (lctx->load)(lctx);
2759 INSIST(result != DNS_R_CONTINUE);
2761 cleanup:
2762 if (lctx != NULL)
2763 dns_loadctx_detach(&lctx);
2764 return (result);
2767 isc_result_t
2768 dns_master_loadstreaminc(FILE *stream, dns_name_t *top, dns_name_t *origin,
2769 dns_rdataclass_t zclass, unsigned int options,
2770 dns_rdatacallbacks_t *callbacks, isc_task_t *task,
2771 dns_loaddonefunc_t done, void *done_arg,
2772 dns_loadctx_t **lctxp, isc_mem_t *mctx)
2774 isc_result_t result;
2775 dns_loadctx_t *lctx = NULL;
2777 REQUIRE(stream != NULL);
2778 REQUIRE(task != NULL);
2779 REQUIRE(done != NULL);
2781 result = loadctx_create(dns_masterformat_text, mctx, options, 0, top,
2782 zclass, origin, callbacks, task, done,
2783 done_arg, NULL, NULL, NULL, &lctx);
2784 if (result != ISC_R_SUCCESS)
2785 goto cleanup;
2787 result = isc_lex_openstream(lctx->lex, stream);
2788 if (result != ISC_R_SUCCESS)
2789 goto cleanup;
2791 result = task_send(lctx);
2792 if (result == ISC_R_SUCCESS) {
2793 dns_loadctx_attach(lctx, lctxp);
2794 return (DNS_R_CONTINUE);
2797 cleanup:
2798 if (lctx != NULL)
2799 dns_loadctx_detach(&lctx);
2800 return (result);
2803 isc_result_t
2804 dns_master_loadbuffer(isc_buffer_t *buffer, dns_name_t *top,
2805 dns_name_t *origin, dns_rdataclass_t zclass,
2806 unsigned int options,
2807 dns_rdatacallbacks_t *callbacks, isc_mem_t *mctx)
2809 isc_result_t result;
2810 dns_loadctx_t *lctx = NULL;
2812 REQUIRE(buffer != NULL);
2814 result = loadctx_create(dns_masterformat_text, mctx, options, 0, top,
2815 zclass, origin, callbacks, NULL, NULL, NULL,
2816 NULL, NULL, NULL, &lctx);
2817 if (result != ISC_R_SUCCESS)
2818 return (result);
2820 result = isc_lex_openbuffer(lctx->lex, buffer);
2821 if (result != ISC_R_SUCCESS)
2822 goto cleanup;
2824 result = (lctx->load)(lctx);
2825 INSIST(result != DNS_R_CONTINUE);
2827 cleanup:
2828 dns_loadctx_detach(&lctx);
2829 return (result);
2832 isc_result_t
2833 dns_master_loadbufferinc(isc_buffer_t *buffer, dns_name_t *top,
2834 dns_name_t *origin, dns_rdataclass_t zclass,
2835 unsigned int options,
2836 dns_rdatacallbacks_t *callbacks, isc_task_t *task,
2837 dns_loaddonefunc_t done, void *done_arg,
2838 dns_loadctx_t **lctxp, isc_mem_t *mctx)
2840 isc_result_t result;
2841 dns_loadctx_t *lctx = NULL;
2843 REQUIRE(buffer != NULL);
2844 REQUIRE(task != NULL);
2845 REQUIRE(done != NULL);
2847 result = loadctx_create(dns_masterformat_text, mctx, options, 0, top,
2848 zclass, origin, callbacks, task, done,
2849 done_arg, NULL, NULL, NULL, &lctx);
2850 if (result != ISC_R_SUCCESS)
2851 return (result);
2853 result = isc_lex_openbuffer(lctx->lex, buffer);
2854 if (result != ISC_R_SUCCESS)
2855 goto cleanup;
2857 result = task_send(lctx);
2858 if (result == ISC_R_SUCCESS) {
2859 dns_loadctx_attach(lctx, lctxp);
2860 return (DNS_R_CONTINUE);
2863 cleanup:
2864 dns_loadctx_detach(&lctx);
2865 return (result);
2868 isc_result_t
2869 dns_master_loadlexer(isc_lex_t *lex, dns_name_t *top,
2870 dns_name_t *origin, dns_rdataclass_t zclass,
2871 unsigned int options,
2872 dns_rdatacallbacks_t *callbacks, isc_mem_t *mctx)
2874 isc_result_t result;
2875 dns_loadctx_t *lctx = NULL;
2877 REQUIRE(lex != NULL);
2879 result = loadctx_create(dns_masterformat_text, mctx, options, 0, top,
2880 zclass, origin, callbacks, NULL, NULL, NULL,
2881 NULL, NULL, lex, &lctx);
2882 if (result != ISC_R_SUCCESS)
2883 return (result);
2885 result = (lctx->load)(lctx);
2886 INSIST(result != DNS_R_CONTINUE);
2888 dns_loadctx_detach(&lctx);
2889 return (result);
2892 isc_result_t
2893 dns_master_loadlexerinc(isc_lex_t *lex, dns_name_t *top,
2894 dns_name_t *origin, dns_rdataclass_t zclass,
2895 unsigned int options,
2896 dns_rdatacallbacks_t *callbacks, isc_task_t *task,
2897 dns_loaddonefunc_t done, void *done_arg,
2898 dns_loadctx_t **lctxp, isc_mem_t *mctx)
2900 isc_result_t result;
2901 dns_loadctx_t *lctx = NULL;
2903 REQUIRE(lex != NULL);
2904 REQUIRE(task != NULL);
2905 REQUIRE(done != NULL);
2907 result = loadctx_create(dns_masterformat_text, mctx, options, 0, top,
2908 zclass, origin, callbacks, task, done,
2909 done_arg, NULL, NULL, lex, &lctx);
2910 if (result != ISC_R_SUCCESS)
2911 return (result);
2913 result = task_send(lctx);
2914 if (result == ISC_R_SUCCESS) {
2915 dns_loadctx_attach(lctx, lctxp);
2916 return (DNS_R_CONTINUE);
2919 dns_loadctx_detach(&lctx);
2920 return (result);
2924 * Grow the slab of dns_rdatalist_t structures.
2925 * Re-link glue and current list.
2927 static dns_rdatalist_t *
2928 grow_rdatalist(int new_len, dns_rdatalist_t *old, int old_len,
2929 rdatalist_head_t *current, rdatalist_head_t *glue,
2930 isc_mem_t *mctx)
2932 dns_rdatalist_t *new;
2933 int rdlcount = 0;
2934 ISC_LIST(dns_rdatalist_t) save;
2935 dns_rdatalist_t *this;
2937 new = isc_mem_get(mctx, new_len * sizeof(*new));
2938 if (new == NULL)
2939 return (NULL);
2941 ISC_LIST_INIT(save);
2942 while ((this = ISC_LIST_HEAD(*current)) != NULL) {
2943 ISC_LIST_UNLINK(*current, this, link);
2944 ISC_LIST_APPEND(save, this, link);
2946 while ((this = ISC_LIST_HEAD(save)) != NULL) {
2947 ISC_LIST_UNLINK(save, this, link);
2948 INSIST(rdlcount < new_len);
2949 new[rdlcount] = *this;
2950 ISC_LIST_APPEND(*current, &new[rdlcount], link);
2951 rdlcount++;
2954 ISC_LIST_INIT(save);
2955 while ((this = ISC_LIST_HEAD(*glue)) != NULL) {
2956 ISC_LIST_UNLINK(*glue, this, link);
2957 ISC_LIST_APPEND(save, this, link);
2959 while ((this = ISC_LIST_HEAD(save)) != NULL) {
2960 ISC_LIST_UNLINK(save, this, link);
2961 INSIST(rdlcount < new_len);
2962 new[rdlcount] = *this;
2963 ISC_LIST_APPEND(*glue, &new[rdlcount], link);
2964 rdlcount++;
2967 INSIST(rdlcount == old_len);
2968 if (old != NULL)
2969 isc_mem_put(mctx, old, old_len * sizeof(*old));
2970 return (new);
2974 * Grow the slab of rdata structs.
2975 * Re-link the current and glue chains.
2977 static dns_rdata_t *
2978 grow_rdata(int new_len, dns_rdata_t *old, int old_len,
2979 rdatalist_head_t *current, rdatalist_head_t *glue,
2980 isc_mem_t *mctx)
2982 dns_rdata_t *new;
2983 int rdcount = 0;
2984 ISC_LIST(dns_rdata_t) save;
2985 dns_rdatalist_t *this;
2986 dns_rdata_t *rdata;
2988 new = isc_mem_get(mctx, new_len * sizeof(*new));
2989 if (new == NULL)
2990 return (NULL);
2991 memset(new, 0, new_len * sizeof(*new));
2994 * Copy current relinking.
2996 this = ISC_LIST_HEAD(*current);
2997 while (this != NULL) {
2998 ISC_LIST_INIT(save);
2999 while ((rdata = ISC_LIST_HEAD(this->rdata)) != NULL) {
3000 ISC_LIST_UNLINK(this->rdata, rdata, link);
3001 ISC_LIST_APPEND(save, rdata, link);
3003 while ((rdata = ISC_LIST_HEAD(save)) != NULL) {
3004 ISC_LIST_UNLINK(save, rdata, link);
3005 INSIST(rdcount < new_len);
3006 new[rdcount] = *rdata;
3007 ISC_LIST_APPEND(this->rdata, &new[rdcount], link);
3008 rdcount++;
3010 this = ISC_LIST_NEXT(this, link);
3014 * Copy glue relinking.
3016 this = ISC_LIST_HEAD(*glue);
3017 while (this != NULL) {
3018 ISC_LIST_INIT(save);
3019 while ((rdata = ISC_LIST_HEAD(this->rdata)) != NULL) {
3020 ISC_LIST_UNLINK(this->rdata, rdata, link);
3021 ISC_LIST_APPEND(save, rdata, link);
3023 while ((rdata = ISC_LIST_HEAD(save)) != NULL) {
3024 ISC_LIST_UNLINK(save, rdata, link);
3025 INSIST(rdcount < new_len);
3026 new[rdcount] = *rdata;
3027 ISC_LIST_APPEND(this->rdata, &new[rdcount], link);
3028 rdcount++;
3030 this = ISC_LIST_NEXT(this, link);
3032 INSIST(rdcount == old_len || rdcount == 0);
3033 if (old != NULL)
3034 isc_mem_put(mctx, old, old_len * sizeof(*old));
3035 return (new);
3038 static isc_uint32_t
3039 resign_fromlist(dns_rdatalist_t *this, isc_uint32_t resign) {
3040 dns_rdata_t *rdata;
3041 dns_rdata_rrsig_t sig;
3042 isc_uint32_t when;
3044 rdata = ISC_LIST_HEAD(this->rdata);
3045 INSIST(rdata != NULL);
3046 (void)dns_rdata_tostruct(rdata, &sig, NULL);
3047 when = sig.timeexpire - resign;
3049 rdata = ISC_LIST_NEXT(rdata, link);
3050 while (rdata != NULL) {
3051 (void)dns_rdata_tostruct(rdata, &sig, NULL);
3052 if (sig.timeexpire - resign < when)
3053 when = sig.timeexpire - resign;
3054 rdata = ISC_LIST_NEXT(rdata, link);
3056 return (when);
3060 * Convert each element from a rdatalist_t to rdataset then call commit.
3061 * Unlink each element as we go.
3064 static isc_result_t
3065 commit(dns_rdatacallbacks_t *callbacks, dns_loadctx_t *lctx,
3066 rdatalist_head_t *head, dns_name_t *owner,
3067 const char *source, unsigned int line)
3069 dns_rdatalist_t *this;
3070 dns_rdataset_t dataset;
3071 isc_result_t result;
3072 char namebuf[DNS_NAME_FORMATSIZE];
3073 void (*error)(struct dns_rdatacallbacks *, const char *, ...);
3075 this = ISC_LIST_HEAD(*head);
3076 error = callbacks->error;
3078 if (this == NULL)
3079 return (ISC_R_SUCCESS);
3080 do {
3081 dns_rdataset_init(&dataset);
3082 RUNTIME_CHECK(dns_rdatalist_tordataset(this, &dataset)
3083 == ISC_R_SUCCESS);
3084 dataset.trust = dns_trust_ultimate;
3086 * If this is a secure dynamic zone set the re-signing time.
3088 if (dataset.type == dns_rdatatype_rrsig &&
3089 (lctx->options & DNS_MASTER_RESIGN) != 0) {
3090 dataset.attributes |= DNS_RDATASETATTR_RESIGN;
3091 dataset.resign = resign_fromlist(this, lctx->resign);
3093 result = ((*callbacks->add)(callbacks->add_private, owner,
3094 &dataset));
3095 if (result == ISC_R_NOMEMORY) {
3096 (*error)(callbacks, "dns_master_load: %s",
3097 dns_result_totext(result));
3098 } else if (result != ISC_R_SUCCESS) {
3099 dns_name_format(owner, namebuf, sizeof(namebuf));
3100 if (source != NULL) {
3101 (*error)(callbacks, "%s: %s:%lu: %s: %s",
3102 "dns_master_load", source, line,
3103 namebuf, dns_result_totext(result));
3104 } else {
3105 (*error)(callbacks, "%s: %s: %s",
3106 "dns_master_load", namebuf,
3107 dns_result_totext(result));
3110 if (MANYERRS(lctx, result))
3111 SETRESULT(lctx, result);
3112 else if (result != ISC_R_SUCCESS)
3113 return (result);
3114 ISC_LIST_UNLINK(*head, this, link);
3115 this = ISC_LIST_HEAD(*head);
3116 } while (this != NULL);
3117 return (ISC_R_SUCCESS);
3121 * Returns ISC_TRUE if one of the NS rdata's contains 'owner'.
3124 static isc_boolean_t
3125 is_glue(rdatalist_head_t *head, dns_name_t *owner) {
3126 dns_rdatalist_t *this;
3127 dns_rdata_t *rdata;
3128 isc_region_t region;
3129 dns_name_t name;
3132 * Find NS rrset.
3134 this = ISC_LIST_HEAD(*head);
3135 while (this != NULL) {
3136 if (this->type == dns_rdatatype_ns)
3137 break;
3138 this = ISC_LIST_NEXT(this, link);
3140 if (this == NULL)
3141 return (ISC_FALSE);
3143 rdata = ISC_LIST_HEAD(this->rdata);
3144 while (rdata != NULL) {
3145 dns_name_init(&name, NULL);
3146 dns_rdata_toregion(rdata, &region);
3147 dns_name_fromregion(&name, &region);
3148 if (dns_name_compare(&name, owner) == 0)
3149 return (ISC_TRUE);
3150 rdata = ISC_LIST_NEXT(rdata, link);
3152 return (ISC_FALSE);
3155 static void
3156 load_quantum(isc_task_t *task, isc_event_t *event) {
3157 isc_result_t result;
3158 dns_loadctx_t *lctx;
3160 REQUIRE(event != NULL);
3161 lctx = event->ev_arg;
3162 REQUIRE(DNS_LCTX_VALID(lctx));
3164 if (lctx->canceled)
3165 result = ISC_R_CANCELED;
3166 else
3167 result = (lctx->load)(lctx);
3168 if (result == DNS_R_CONTINUE) {
3169 event->ev_arg = lctx;
3170 isc_task_send(task, &event);
3171 } else {
3172 (lctx->done)(lctx->done_arg, result);
3173 isc_event_free(&event);
3174 dns_loadctx_detach(&lctx);
3178 static isc_result_t
3179 task_send(dns_loadctx_t *lctx) {
3180 isc_event_t *event;
3182 event = isc_event_allocate(lctx->mctx, NULL,
3183 DNS_EVENT_MASTERQUANTUM,
3184 load_quantum, lctx, sizeof(*event));
3185 if (event == NULL)
3186 return (ISC_R_NOMEMORY);
3187 isc_task_send(lctx->task, &event);
3188 return (ISC_R_SUCCESS);
3191 void
3192 dns_loadctx_cancel(dns_loadctx_t *lctx) {
3193 REQUIRE(DNS_LCTX_VALID(lctx));
3195 LOCK(&lctx->lock);
3196 lctx->canceled = ISC_TRUE;
3197 UNLOCK(&lctx->lock);
3200 void
3201 dns_master_initrawheader(dns_masterrawheader_t *header) {
3202 memset(header, 0, sizeof(dns_masterrawheader_t));