Patrick Welche <prlw1@cam.ac.uk>
[netbsd-mini2440.git] / external / bsd / bind / dist / lib / dns / master.c
blobe530d8aff23c25aae56c2b35f83abbccd7a06c11
1 /* $NetBSD: master.c,v 1.1.1.2 2009/10/25 00:02:30 christos Exp $ */
3 /*
4 * Copyright (C) 2004-2009 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: master.c,v 1.178 2009/09/01 00:22:26 jinmei Exp */
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 (65535 - 12 - 1 - 2 - 2 - 4 - 2)
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 typedef ISC_LIST(dns_rdatalist_t) rdatalist_head_t;
98 typedef struct dns_incctx dns_incctx_t;
101 * Master file load state.
104 struct dns_loadctx {
105 unsigned int magic;
106 isc_mem_t *mctx;
107 dns_masterformat_t format;
109 dns_rdatacallbacks_t *callbacks;
110 isc_task_t *task;
111 dns_loaddonefunc_t done;
112 void *done_arg;
114 /* Common methods */
115 isc_result_t (*openfile)(dns_loadctx_t *lctx,
116 const char *filename);
117 isc_result_t (*load)(dns_loadctx_t *lctx);
119 /* Members specific to the text format: */
120 isc_lex_t *lex;
121 isc_boolean_t keep_lex;
122 unsigned int options;
123 isc_boolean_t ttl_known;
124 isc_boolean_t default_ttl_known;
125 isc_boolean_t warn_1035;
126 isc_boolean_t warn_tcr;
127 isc_boolean_t warn_sigexpired;
128 isc_boolean_t seen_include;
129 isc_uint32_t ttl;
130 isc_uint32_t default_ttl;
131 dns_rdataclass_t zclass;
132 dns_fixedname_t fixed_top;
133 dns_name_t *top; /*%< top of zone */
135 /* Members specific to the raw format: */
136 FILE *f;
137 isc_boolean_t first;
139 /* Which fixed buffers we are using? */
140 unsigned int loop_cnt; /*% records per quantum,
141 * 0 => all. */
142 isc_boolean_t canceled;
143 isc_mutex_t lock;
144 isc_result_t result;
145 /* locked by lock */
146 isc_uint32_t references;
147 dns_incctx_t *inc;
148 isc_uint32_t resign;
151 struct dns_incctx {
152 dns_incctx_t *parent;
153 dns_name_t *origin;
154 dns_name_t *current;
155 dns_name_t *glue;
156 dns_fixedname_t fixed[NBUFS]; /* working buffers */
157 unsigned int in_use[NBUFS]; /* covert to bitmap? */
158 int glue_in_use;
159 int current_in_use;
160 int origin_in_use;
161 isc_boolean_t drop;
162 unsigned int glue_line;
163 unsigned int current_line;
166 #define DNS_LCTX_MAGIC ISC_MAGIC('L','c','t','x')
167 #define DNS_LCTX_VALID(lctx) ISC_MAGIC_VALID(lctx, DNS_LCTX_MAGIC)
169 #define DNS_AS_STR(t) ((t).value.as_textregion.base)
171 static isc_result_t
172 openfile_text(dns_loadctx_t *lctx, const char *master_file);
174 static isc_result_t
175 openfile_raw(dns_loadctx_t *lctx, const char *master_file);
177 static isc_result_t
178 load_text(dns_loadctx_t *lctx);
180 static isc_result_t
181 load_raw(dns_loadctx_t *lctx);
183 static isc_result_t
184 pushfile(const char *master_file, dns_name_t *origin, dns_loadctx_t *lctx);
186 static isc_result_t
187 commit(dns_rdatacallbacks_t *, dns_loadctx_t *, rdatalist_head_t *,
188 dns_name_t *, const char *, unsigned int);
190 static isc_boolean_t
191 is_glue(rdatalist_head_t *, dns_name_t *);
193 static dns_rdatalist_t *
194 grow_rdatalist(int, dns_rdatalist_t *, int, rdatalist_head_t *,
195 rdatalist_head_t *, isc_mem_t *mctx);
197 static dns_rdata_t *
198 grow_rdata(int, dns_rdata_t *, int, rdatalist_head_t *, rdatalist_head_t *,
199 isc_mem_t *);
201 static void
202 load_quantum(isc_task_t *task, isc_event_t *event);
204 static isc_result_t
205 task_send(dns_loadctx_t *lctx);
207 static void
208 loadctx_destroy(dns_loadctx_t *lctx);
210 #define GETTOKEN(lexer, options, token, eol) \
211 do { \
212 result = gettoken(lexer, options, token, eol, callbacks); \
213 switch (result) { \
214 case ISC_R_SUCCESS: \
215 break; \
216 case ISC_R_UNEXPECTED: \
217 goto insist_and_cleanup; \
218 default: \
219 if (MANYERRS(lctx, result)) { \
220 SETRESULT(lctx, result); \
221 LOGIT(result); \
222 read_till_eol = ISC_TRUE; \
223 goto next_line; \
224 } else \
225 goto log_and_cleanup; \
227 if ((token)->type == isc_tokentype_special) { \
228 result = DNS_R_SYNTAX; \
229 if (MANYERRS(lctx, result)) { \
230 SETRESULT(lctx, result); \
231 LOGIT(result); \
232 read_till_eol = ISC_TRUE; \
233 goto next_line; \
234 } else \
235 goto log_and_cleanup; \
237 } while (0)
239 #define COMMITALL \
240 do { \
241 result = commit(callbacks, lctx, &current_list, \
242 ictx->current, source, ictx->current_line); \
243 if (MANYERRS(lctx, result)) { \
244 SETRESULT(lctx, result); \
245 } else if (result != ISC_R_SUCCESS) \
246 goto insist_and_cleanup; \
247 result = commit(callbacks, lctx, &glue_list, \
248 ictx->glue, source, ictx->glue_line); \
249 if (MANYERRS(lctx, result)) { \
250 SETRESULT(lctx, result); \
251 } else if (result != ISC_R_SUCCESS) \
252 goto insist_and_cleanup; \
253 rdcount = 0; \
254 rdlcount = 0; \
255 isc_buffer_init(&target, target_mem, target_size); \
256 rdcount_save = rdcount; \
257 rdlcount_save = rdlcount; \
258 } while (0)
260 #define WARNUNEXPECTEDEOF(lexer) \
261 do { \
262 if (isc_lex_isfile(lexer)) \
263 (*callbacks->warn)(callbacks, \
264 "%s: file does not end with newline", \
265 source); \
266 } while (0)
268 #define EXPECTEOL \
269 do { \
270 GETTOKEN(lctx->lex, 0, &token, ISC_TRUE); \
271 if (token.type != isc_tokentype_eol) { \
272 isc_lex_ungettoken(lctx->lex, &token); \
273 result = DNS_R_EXTRATOKEN; \
274 if (MANYERRS(lctx, result)) { \
275 SETRESULT(lctx, result); \
276 LOGIT(result); \
277 read_till_eol = ISC_TRUE; \
278 /* continue; */ \
279 } else if (result != ISC_R_SUCCESS) \
280 goto log_and_cleanup; \
282 } while (0)
284 #define MANYERRS(lctx, result) \
285 ((result != ISC_R_SUCCESS) && \
286 (result != ISC_R_IOERROR) && \
287 ((lctx)->options & DNS_MASTER_MANYERRORS) != 0)
289 #define SETRESULT(lctx, r) \
290 do { \
291 if ((lctx)->result == ISC_R_SUCCESS) \
292 (lctx)->result = r; \
293 } while (0)
295 #define LOGITFILE(result, filename) \
296 if (result == ISC_R_INVALIDFILE || result == ISC_R_FILENOTFOUND || \
297 result == ISC_R_IOERROR || result == ISC_R_TOOMANYOPENFILES || \
298 result == ISC_R_NOPERM) \
299 (*callbacks->error)(callbacks, "%s: %s:%lu: %s: %s", \
300 "dns_master_load", source, line, \
301 filename, dns_result_totext(result)); \
302 else LOGIT(result)
304 #define LOGIT(result) \
305 if (result == ISC_R_NOMEMORY) \
306 (*callbacks->error)(callbacks, "dns_master_load: %s", \
307 dns_result_totext(result)); \
308 else \
309 (*callbacks->error)(callbacks, "%s: %s:%lu: %s", \
310 "dns_master_load", \
311 source, line, dns_result_totext(result))
314 static unsigned char in_addr_arpa_data[] = "\007IN-ADDR\004ARPA";
315 static unsigned char in_addr_arpa_offsets[] = { 0, 8, 13 };
316 static const dns_name_t in_addr_arpa =
318 DNS_NAME_MAGIC,
319 in_addr_arpa_data, 14, 3,
320 DNS_NAMEATTR_READONLY | DNS_NAMEATTR_ABSOLUTE,
321 in_addr_arpa_offsets, NULL,
322 {(void *)-1, (void *)-1},
323 {NULL, NULL}
326 static unsigned char ip6_int_data[] = "\003IP6\003INT";
327 static unsigned char ip6_int_offsets[] = { 0, 4, 8 };
328 static const dns_name_t ip6_int =
330 DNS_NAME_MAGIC,
331 ip6_int_data, 9, 3,
332 DNS_NAMEATTR_READONLY | DNS_NAMEATTR_ABSOLUTE,
333 ip6_int_offsets, NULL,
334 {(void *)-1, (void *)-1},
335 {NULL, NULL}
338 static unsigned char ip6_arpa_data[] = "\003IP6\004ARPA";
339 static unsigned char ip6_arpa_offsets[] = { 0, 4, 9 };
340 static const dns_name_t ip6_arpa =
342 DNS_NAME_MAGIC,
343 ip6_arpa_data, 10, 3,
344 DNS_NAMEATTR_READONLY | DNS_NAMEATTR_ABSOLUTE,
345 ip6_arpa_offsets, NULL,
346 {(void *)-1, (void *)-1},
347 {NULL, NULL}
351 static inline isc_result_t
352 gettoken(isc_lex_t *lex, unsigned int options, isc_token_t *token,
353 isc_boolean_t eol, dns_rdatacallbacks_t *callbacks)
355 isc_result_t result;
357 options |= ISC_LEXOPT_EOL | ISC_LEXOPT_EOF | ISC_LEXOPT_DNSMULTILINE |
358 ISC_LEXOPT_ESCAPE;
359 result = isc_lex_gettoken(lex, options, token);
360 if (result != ISC_R_SUCCESS) {
361 switch (result) {
362 case ISC_R_NOMEMORY:
363 return (ISC_R_NOMEMORY);
364 default:
365 (*callbacks->error)(callbacks,
366 "dns_master_load: %s:%lu:"
367 " isc_lex_gettoken() failed: %s",
368 isc_lex_getsourcename(lex),
369 isc_lex_getsourceline(lex),
370 isc_result_totext(result));
371 return (result);
373 /*NOTREACHED*/
375 if (eol != ISC_TRUE)
376 if (token->type == isc_tokentype_eol ||
377 token->type == isc_tokentype_eof) {
378 (*callbacks->error)(callbacks,
379 "dns_master_load: %s:%lu: unexpected end of %s",
380 isc_lex_getsourcename(lex),
381 isc_lex_getsourceline(lex),
382 (token->type ==
383 isc_tokentype_eol) ?
384 "line" : "file");
385 return (ISC_R_UNEXPECTEDEND);
387 return (ISC_R_SUCCESS);
391 void
392 dns_loadctx_attach(dns_loadctx_t *source, dns_loadctx_t **target) {
394 REQUIRE(target != NULL && *target == NULL);
395 REQUIRE(DNS_LCTX_VALID(source));
397 LOCK(&source->lock);
398 INSIST(source->references > 0);
399 source->references++;
400 INSIST(source->references != 0); /* Overflow? */
401 UNLOCK(&source->lock);
403 *target = source;
406 void
407 dns_loadctx_detach(dns_loadctx_t **lctxp) {
408 dns_loadctx_t *lctx;
409 isc_boolean_t need_destroy = ISC_FALSE;
411 REQUIRE(lctxp != NULL);
412 lctx = *lctxp;
413 REQUIRE(DNS_LCTX_VALID(lctx));
415 LOCK(&lctx->lock);
416 INSIST(lctx->references > 0);
417 lctx->references--;
418 if (lctx->references == 0)
419 need_destroy = ISC_TRUE;
420 UNLOCK(&lctx->lock);
422 if (need_destroy)
423 loadctx_destroy(lctx);
424 *lctxp = NULL;
427 static void
428 incctx_destroy(isc_mem_t *mctx, dns_incctx_t *ictx) {
429 dns_incctx_t *parent;
431 again:
432 parent = ictx->parent;
433 ictx->parent = NULL;
435 isc_mem_put(mctx, ictx, sizeof(*ictx));
437 if (parent != NULL) {
438 ictx = parent;
439 goto again;
443 static void
444 loadctx_destroy(dns_loadctx_t *lctx) {
445 isc_mem_t *mctx;
446 isc_result_t result;
448 REQUIRE(DNS_LCTX_VALID(lctx));
450 lctx->magic = 0;
451 if (lctx->inc != NULL)
452 incctx_destroy(lctx->mctx, lctx->inc);
454 if (lctx->f != NULL) {
455 result = isc_stdio_close(lctx->f);
456 if (result != ISC_R_SUCCESS) {
457 UNEXPECTED_ERROR(__FILE__, __LINE__,
458 "isc_stdio_close() failed: %s",
459 isc_result_totext(result));
463 /* isc_lex_destroy() will close all open streams */
464 if (lctx->lex != NULL && !lctx->keep_lex)
465 isc_lex_destroy(&lctx->lex);
467 if (lctx->task != NULL)
468 isc_task_detach(&lctx->task);
469 DESTROYLOCK(&lctx->lock);
470 mctx = NULL;
471 isc_mem_attach(lctx->mctx, &mctx);
472 isc_mem_detach(&lctx->mctx);
473 isc_mem_put(mctx, lctx, sizeof(*lctx));
474 isc_mem_detach(&mctx);
477 static isc_result_t
478 incctx_create(isc_mem_t *mctx, dns_name_t *origin, dns_incctx_t **ictxp) {
479 dns_incctx_t *ictx;
480 isc_region_t r;
481 int i;
483 ictx = isc_mem_get(mctx, sizeof(*ictx));
484 if (ictx == NULL)
485 return (ISC_R_NOMEMORY);
487 for (i = 0; i < NBUFS; i++) {
488 dns_fixedname_init(&ictx->fixed[i]);
489 ictx->in_use[i] = ISC_FALSE;
492 ictx->origin_in_use = 0;
493 ictx->origin = dns_fixedname_name(&ictx->fixed[ictx->origin_in_use]);
494 ictx->in_use[ictx->origin_in_use] = ISC_TRUE;
495 dns_name_toregion(origin, &r);
496 dns_name_fromregion(ictx->origin, &r);
498 ictx->glue = NULL;
499 ictx->current = NULL;
500 ictx->glue_in_use = -1;
501 ictx->current_in_use = -1;
502 ictx->parent = NULL;
503 ictx->drop = ISC_FALSE;
504 ictx->glue_line = 0;
505 ictx->current_line = 0;
507 *ictxp = ictx;
508 return (ISC_R_SUCCESS);
511 static isc_result_t
512 loadctx_create(dns_masterformat_t format, isc_mem_t *mctx,
513 unsigned int options, isc_uint32_t resign, dns_name_t *top,
514 dns_rdataclass_t zclass, dns_name_t *origin,
515 dns_rdatacallbacks_t *callbacks, isc_task_t *task,
516 dns_loaddonefunc_t done, void *done_arg, isc_lex_t *lex,
517 dns_loadctx_t **lctxp)
519 dns_loadctx_t *lctx;
520 isc_result_t result;
521 isc_region_t r;
522 isc_lexspecials_t specials;
524 REQUIRE(lctxp != NULL && *lctxp == NULL);
525 REQUIRE(callbacks != NULL);
526 REQUIRE(callbacks->add != NULL);
527 REQUIRE(callbacks->error != NULL);
528 REQUIRE(callbacks->warn != NULL);
529 REQUIRE(mctx != NULL);
530 REQUIRE(dns_name_isabsolute(top));
531 REQUIRE(dns_name_isabsolute(origin));
532 REQUIRE((task == NULL && done == NULL) ||
533 (task != NULL && done != NULL));
535 lctx = isc_mem_get(mctx, sizeof(*lctx));
536 if (lctx == NULL)
537 return (ISC_R_NOMEMORY);
538 result = isc_mutex_init(&lctx->lock);
539 if (result != ISC_R_SUCCESS) {
540 isc_mem_put(mctx, lctx, sizeof(*lctx));
541 return (result);
544 lctx->inc = NULL;
545 result = incctx_create(mctx, origin, &lctx->inc);
546 if (result != ISC_R_SUCCESS)
547 goto cleanup_ctx;
549 lctx->format = format;
550 switch (format) {
551 default:
552 INSIST(0);
553 case dns_masterformat_text:
554 lctx->openfile = openfile_text;
555 lctx->load = load_text;
556 break;
557 case dns_masterformat_raw:
558 lctx->openfile = openfile_raw;
559 lctx->load = load_raw;
560 break;
563 if (lex != NULL) {
564 lctx->lex = lex;
565 lctx->keep_lex = ISC_TRUE;
566 } else {
567 lctx->lex = NULL;
568 result = isc_lex_create(mctx, TOKENSIZ, &lctx->lex);
569 if (result != ISC_R_SUCCESS)
570 goto cleanup_inc;
571 lctx->keep_lex = ISC_FALSE;
572 memset(specials, 0, sizeof(specials));
573 specials['('] = 1;
574 specials[')'] = 1;
575 specials['"'] = 1;
576 isc_lex_setspecials(lctx->lex, specials);
577 isc_lex_setcomments(lctx->lex, ISC_LEXCOMMENT_DNSMASTERFILE);
580 lctx->ttl_known = ISC_FALSE;
581 lctx->ttl = 0;
582 lctx->default_ttl_known = ISC_FALSE;
583 lctx->default_ttl = 0;
584 lctx->warn_1035 = ISC_TRUE; /* XXX Argument? */
585 lctx->warn_tcr = ISC_TRUE; /* XXX Argument? */
586 lctx->warn_sigexpired = ISC_TRUE; /* XXX Argument? */
587 lctx->options = options;
588 lctx->seen_include = ISC_FALSE;
589 lctx->zclass = zclass;
590 lctx->resign = resign;
591 lctx->result = ISC_R_SUCCESS;
593 dns_fixedname_init(&lctx->fixed_top);
594 lctx->top = dns_fixedname_name(&lctx->fixed_top);
595 dns_name_toregion(top, &r);
596 dns_name_fromregion(lctx->top, &r);
598 lctx->f = NULL;
599 lctx->first = ISC_TRUE;
601 lctx->loop_cnt = (done != NULL) ? 100 : 0;
602 lctx->callbacks = callbacks;
603 lctx->task = NULL;
604 if (task != NULL)
605 isc_task_attach(task, &lctx->task);
606 lctx->done = done;
607 lctx->done_arg = done_arg;
608 lctx->canceled = ISC_FALSE;
609 lctx->mctx = NULL;
610 isc_mem_attach(mctx, &lctx->mctx);
611 lctx->references = 1; /* Implicit attach. */
612 lctx->magic = DNS_LCTX_MAGIC;
613 *lctxp = lctx;
614 return (ISC_R_SUCCESS);
616 cleanup_inc:
617 incctx_destroy(mctx, lctx->inc);
618 cleanup_ctx:
619 isc_mem_put(mctx, lctx, sizeof(*lctx));
620 return (result);
623 static const char *hex = "0123456789abcdef0123456789ABCDEF";
626 * Convert value into a nibble sequence from least significant to most
627 * significant nibble. Zero fill upper most significant nibbles if
628 * required to make the width.
630 * Returns the number of characters that should have been written without
631 * counting the terminating NUL.
633 static unsigned int
634 nibbles(char *numbuf, size_t length, unsigned int width, char mode, int value) {
635 unsigned int count = 0;
638 * This reserve space for the NUL string terminator.
640 if (length > 0U) {
641 *numbuf = '\0';
642 length--;
644 do {
645 char val = hex[(value & 0x0f) + ((mode == 'n') ? 0 : 16)];
646 value >>= 4;
647 if (length > 0U) {
648 *numbuf++ = val;
649 *numbuf = '\0';
650 length--;
652 if (width > 0)
653 width--;
654 count++;
656 * If width is non zero then we need to add a label seperator.
657 * If value is non zero then we need to add another label and
658 * that requires a label seperator.
660 if (width > 0 || value != 0) {
661 if (length > 0U) {
662 *numbuf++ = '.';
663 *numbuf = '\0';
664 length--;
666 if (width > 0)
667 width--;
668 count++;
670 } while (value != 0 || width > 0);
671 return (count);
674 static isc_result_t
675 genname(char *name, int it, char *buffer, size_t length) {
676 char fmt[sizeof("%04000000000d")];
677 char numbuf[128];
678 char *cp;
679 char mode[2];
680 int delta = 0;
681 isc_textregion_t r;
682 unsigned int n;
683 unsigned int width;
684 isc_boolean_t nibblemode;
686 r.base = buffer;
687 r.length = length;
689 while (*name != '\0') {
690 if (*name == '$') {
691 name++;
692 if (*name == '$') {
693 if (r.length == 0)
694 return (ISC_R_NOSPACE);
695 r.base[0] = *name++;
696 isc_textregion_consume(&r, 1);
697 continue;
699 nibblemode = ISC_FALSE;
700 strcpy(fmt, "%d");
701 /* Get format specifier. */
702 if (*name == '{' ) {
703 n = sscanf(name, "{%d,%u,%1[doxXnN]}",
704 &delta, &width, mode);
705 switch (n) {
706 case 1:
707 break;
708 case 2:
709 n = snprintf(fmt, sizeof(fmt),
710 "%%0%ud", width);
711 break;
712 case 3:
713 if (mode[0] == 'n' || mode[0] == 'N')
714 nibblemode = ISC_TRUE;
715 n = snprintf(fmt, sizeof(fmt),
716 "%%0%u%c", width, mode[0]);
717 break;
718 default:
719 return (DNS_R_SYNTAX);
721 if (n >= sizeof(fmt))
722 return (ISC_R_NOSPACE);
723 /* Skip past closing brace. */
724 while (*name != '\0' && *name++ != '}')
725 continue;
727 if (nibblemode)
728 n = nibbles(numbuf, sizeof(numbuf), width,
729 mode[0], it + delta);
730 else
731 n = snprintf(numbuf, sizeof(numbuf), fmt,
732 it + delta);
733 if (n >= sizeof(numbuf))
734 return (ISC_R_NOSPACE);
735 cp = numbuf;
736 while (*cp != '\0') {
737 if (r.length == 0)
738 return (ISC_R_NOSPACE);
739 r.base[0] = *cp++;
740 isc_textregion_consume(&r, 1);
742 } else if (*name == '\\') {
743 if (r.length == 0)
744 return (ISC_R_NOSPACE);
745 r.base[0] = *name++;
746 isc_textregion_consume(&r, 1);
747 if (*name == '\0')
748 continue;
749 if (r.length == 0)
750 return (ISC_R_NOSPACE);
751 r.base[0] = *name++;
752 isc_textregion_consume(&r, 1);
753 } else {
754 if (r.length == 0)
755 return (ISC_R_NOSPACE);
756 r.base[0] = *name++;
757 isc_textregion_consume(&r, 1);
760 if (r.length == 0)
761 return (ISC_R_NOSPACE);
762 r.base[0] = '\0';
763 return (ISC_R_SUCCESS);
766 static isc_result_t
767 openfile_text(dns_loadctx_t *lctx, const char *master_file) {
768 return (isc_lex_openfile(lctx->lex, master_file));
771 static isc_result_t
772 openfile_raw(dns_loadctx_t *lctx, const char *master_file) {
773 isc_result_t result;
775 result = isc_stdio_open(master_file, "r", &lctx->f);
776 if (result != ISC_R_SUCCESS && result != ISC_R_FILENOTFOUND) {
777 UNEXPECTED_ERROR(__FILE__, __LINE__,
778 "isc_stdio_open() failed: %s",
779 isc_result_totext(result));
782 return (result);
785 static isc_result_t
786 generate(dns_loadctx_t *lctx, char *range, char *lhs, char *gtype, char *rhs,
787 const char *source, unsigned int line)
789 char *target_mem = NULL;
790 char *lhsbuf = NULL;
791 char *rhsbuf = NULL;
792 dns_fixedname_t ownerfixed;
793 dns_name_t *owner;
794 dns_rdata_t rdata = DNS_RDATA_INIT;
795 dns_rdatacallbacks_t *callbacks;
796 dns_rdatalist_t rdatalist;
797 dns_rdatatype_t type;
798 rdatalist_head_t head;
799 int n;
800 int target_size = MINTSIZ; /* only one rdata at a time */
801 isc_buffer_t buffer;
802 isc_buffer_t target;
803 isc_result_t result;
804 isc_textregion_t r;
805 unsigned int start, stop, step, i;
806 dns_incctx_t *ictx;
808 ictx = lctx->inc;
809 callbacks = lctx->callbacks;
810 dns_fixedname_init(&ownerfixed);
811 owner = dns_fixedname_name(&ownerfixed);
812 ISC_LIST_INIT(head);
814 target_mem = isc_mem_get(lctx->mctx, target_size);
815 rhsbuf = isc_mem_get(lctx->mctx, DNS_MASTER_RHS);
816 lhsbuf = isc_mem_get(lctx->mctx, DNS_MASTER_LHS);
817 if (target_mem == NULL || rhsbuf == NULL || lhsbuf == NULL) {
818 result = ISC_R_NOMEMORY;
819 goto error_cleanup;
821 isc_buffer_init(&target, target_mem, target_size);
823 n = sscanf(range, "%u-%u/%u", &start, &stop, &step);
824 if (n < 2 || stop < start) {
825 (*callbacks->error)(callbacks,
826 "%s: %s:%lu: invalid range '%s'",
827 "$GENERATE", source, line, range);
828 result = DNS_R_SYNTAX;
829 goto insist_cleanup;
831 if (n == 2)
832 step = 1;
835 * Get type.
837 r.base = gtype;
838 r.length = strlen(gtype);
839 result = dns_rdatatype_fromtext(&type, &r);
840 if (result != ISC_R_SUCCESS) {
841 (*callbacks->error)(callbacks,
842 "%s: %s:%lu: unknown RR type '%s'",
843 "$GENERATE", source, line, gtype);
844 goto insist_cleanup;
847 ISC_LIST_INIT(rdatalist.rdata);
848 ISC_LINK_INIT(&rdatalist, link);
849 for (i = start; i <= stop; i += step) {
850 result = genname(lhs, i, lhsbuf, DNS_MASTER_LHS);
851 if (result != ISC_R_SUCCESS)
852 goto error_cleanup;
853 result = genname(rhs, i, rhsbuf, DNS_MASTER_RHS);
854 if (result != ISC_R_SUCCESS)
855 goto error_cleanup;
857 isc_buffer_init(&buffer, lhsbuf, strlen(lhsbuf));
858 isc_buffer_add(&buffer, strlen(lhsbuf));
859 isc_buffer_setactive(&buffer, strlen(lhsbuf));
860 result = dns_name_fromtext(owner, &buffer, ictx->origin,
861 0, NULL);
862 if (result != ISC_R_SUCCESS)
863 goto error_cleanup;
865 if ((lctx->options & DNS_MASTER_ZONE) != 0 &&
866 (lctx->options & DNS_MASTER_SLAVE) == 0 &&
867 (lctx->options & DNS_MASTER_KEY) == 0 &&
868 !dns_name_issubdomain(owner, lctx->top))
870 char namebuf[DNS_NAME_FORMATSIZE];
871 dns_name_format(owner, namebuf, sizeof(namebuf));
873 * Ignore out-of-zone data.
875 (*callbacks->warn)(callbacks,
876 "%s:%lu: "
877 "ignoring out-of-zone data (%s)",
878 source, line, namebuf);
879 continue;
882 isc_buffer_init(&buffer, rhsbuf, strlen(rhsbuf));
883 isc_buffer_add(&buffer, strlen(rhsbuf));
884 isc_buffer_setactive(&buffer, strlen(rhsbuf));
886 result = isc_lex_openbuffer(lctx->lex, &buffer);
887 if (result != ISC_R_SUCCESS)
888 goto error_cleanup;
890 isc_buffer_init(&target, target_mem, target_size);
891 result = dns_rdata_fromtext(&rdata, lctx->zclass, type,
892 lctx->lex, ictx->origin, 0,
893 lctx->mctx, &target, callbacks);
894 RUNTIME_CHECK(isc_lex_close(lctx->lex) == ISC_R_SUCCESS);
895 if (result != ISC_R_SUCCESS)
896 goto error_cleanup;
898 rdatalist.type = type;
899 rdatalist.covers = 0;
900 rdatalist.rdclass = lctx->zclass;
901 rdatalist.ttl = lctx->ttl;
902 ISC_LIST_PREPEND(head, &rdatalist, link);
903 ISC_LIST_APPEND(rdatalist.rdata, &rdata, link);
904 result = commit(callbacks, lctx, &head, owner, source, line);
905 ISC_LIST_UNLINK(rdatalist.rdata, &rdata, link);
906 if (result != ISC_R_SUCCESS)
907 goto error_cleanup;
908 dns_rdata_reset(&rdata);
910 result = ISC_R_SUCCESS;
911 goto cleanup;
913 error_cleanup:
914 if (result == ISC_R_NOMEMORY)
915 (*callbacks->error)(callbacks, "$GENERATE: %s",
916 dns_result_totext(result));
917 else
918 (*callbacks->error)(callbacks, "$GENERATE: %s:%lu: %s",
919 source, line, dns_result_totext(result));
921 insist_cleanup:
922 INSIST(result != ISC_R_SUCCESS);
924 cleanup:
925 if (target_mem != NULL)
926 isc_mem_put(lctx->mctx, target_mem, target_size);
927 if (lhsbuf != NULL)
928 isc_mem_put(lctx->mctx, lhsbuf, DNS_MASTER_LHS);
929 if (rhsbuf != NULL)
930 isc_mem_put(lctx->mctx, rhsbuf, DNS_MASTER_RHS);
931 return (result);
934 static void
935 limit_ttl(dns_rdatacallbacks_t *callbacks, const char *source, unsigned int line,
936 isc_uint32_t *ttlp)
938 if (*ttlp > 0x7fffffffUL) {
939 (callbacks->warn)(callbacks,
940 "%s: %s:%lu: "
941 "$TTL %lu > MAXTTL, "
942 "setting $TTL to 0",
943 "dns_master_load",
944 source, line,
945 *ttlp);
946 *ttlp = 0;
950 static isc_result_t
951 check_ns(dns_loadctx_t *lctx, isc_token_t *token, const char *source,
952 unsigned long line)
954 char *tmp = NULL;
955 isc_result_t result = ISC_R_SUCCESS;
956 void (*callback)(struct dns_rdatacallbacks *, const char *, ...);
958 if ((lctx->options & DNS_MASTER_FATALNS) != 0)
959 callback = lctx->callbacks->error;
960 else
961 callback = lctx->callbacks->warn;
963 if (token->type == isc_tokentype_string) {
964 struct in_addr addr;
965 struct in6_addr addr6;
967 tmp = isc_mem_strdup(lctx->mctx, DNS_AS_STR(*token));
968 if (tmp == NULL)
969 return (ISC_R_NOMEMORY);
971 * Catch both "1.2.3.4" and "1.2.3.4."
973 if (tmp[strlen(tmp) - 1] == '.')
974 tmp[strlen(tmp) - 1] = '\0';
975 if (inet_aton(tmp, &addr) == 1 ||
976 inet_pton(AF_INET6, tmp, &addr6) == 1)
977 result = DNS_R_NSISADDRESS;
979 if (result != ISC_R_SUCCESS)
980 (*callback)(lctx->callbacks, "%s:%lu: NS record '%s' "
981 "appears to be an address",
982 source, line, DNS_AS_STR(*token));
983 if (tmp != NULL)
984 isc_mem_free(lctx->mctx, tmp);
985 return (result);
988 static void
989 check_wildcard(dns_incctx_t *ictx, const char *source, unsigned long line,
990 dns_rdatacallbacks_t *callbacks)
992 dns_name_t *name;
994 name = (ictx->glue != NULL) ? ictx->glue : ictx->current;
995 if (dns_name_internalwildcard(name)) {
996 char namebuf[DNS_NAME_FORMATSIZE];
998 dns_name_format(name, namebuf, sizeof(namebuf));
999 (*callbacks->warn)(callbacks, "%s:%lu: warning: ownername "
1000 "'%s' contains an non-terminal wildcard",
1001 source, line, namebuf);
1005 static isc_result_t
1006 load_text(dns_loadctx_t *lctx) {
1007 dns_rdataclass_t rdclass;
1008 dns_rdatatype_t type, covers;
1009 isc_uint32_t ttl_offset = 0;
1010 dns_name_t *new_name;
1011 isc_boolean_t current_has_delegation = ISC_FALSE;
1012 isc_boolean_t done = ISC_FALSE;
1013 isc_boolean_t finish_origin = ISC_FALSE;
1014 isc_boolean_t finish_include = ISC_FALSE;
1015 isc_boolean_t read_till_eol = ISC_FALSE;
1016 isc_boolean_t initialws;
1017 char *include_file = NULL;
1018 isc_token_t token;
1019 isc_result_t result = ISC_R_UNEXPECTED;
1020 rdatalist_head_t glue_list;
1021 rdatalist_head_t current_list;
1022 dns_rdatalist_t *this;
1023 dns_rdatalist_t *rdatalist = NULL;
1024 dns_rdatalist_t *new_rdatalist;
1025 int rdlcount = 0;
1026 int rdlcount_save = 0;
1027 int rdatalist_size = 0;
1028 isc_buffer_t buffer;
1029 isc_buffer_t target;
1030 isc_buffer_t target_ft;
1031 isc_buffer_t target_save;
1032 dns_rdata_t *rdata = NULL;
1033 dns_rdata_t *new_rdata;
1034 int rdcount = 0;
1035 int rdcount_save = 0;
1036 int rdata_size = 0;
1037 unsigned char *target_mem = NULL;
1038 int target_size = TSIZ;
1039 int new_in_use;
1040 unsigned int loop_cnt = 0;
1041 isc_mem_t *mctx;
1042 dns_rdatacallbacks_t *callbacks;
1043 dns_incctx_t *ictx;
1044 char *range = NULL;
1045 char *lhs = NULL;
1046 char *gtype = NULL;
1047 char *rhs = NULL;
1048 const char *source = "";
1049 unsigned long line = 0;
1050 isc_boolean_t explicit_ttl;
1051 isc_stdtime_t now;
1052 char classname1[DNS_RDATACLASS_FORMATSIZE];
1053 char classname2[DNS_RDATACLASS_FORMATSIZE];
1054 unsigned int options = 0;
1056 REQUIRE(DNS_LCTX_VALID(lctx));
1057 callbacks = lctx->callbacks;
1058 mctx = lctx->mctx;
1059 ictx = lctx->inc;
1061 ISC_LIST_INIT(glue_list);
1062 ISC_LIST_INIT(current_list);
1064 isc_stdtime_get(&now);
1067 * Allocate target_size of buffer space. This is greater than twice
1068 * the maximum individual RR data size.
1070 target_mem = isc_mem_get(mctx, target_size);
1071 if (target_mem == NULL) {
1072 result = ISC_R_NOMEMORY;
1073 goto log_and_cleanup;
1075 isc_buffer_init(&target, target_mem, target_size);
1076 target_save = target;
1078 if ((lctx->options & DNS_MASTER_CHECKNAMES) != 0)
1079 options |= DNS_RDATA_CHECKNAMES;
1080 if ((lctx->options & DNS_MASTER_CHECKNAMESFAIL) != 0)
1081 options |= DNS_RDATA_CHECKNAMESFAIL;
1082 if ((lctx->options & DNS_MASTER_CHECKMX) != 0)
1083 options |= DNS_RDATA_CHECKMX;
1084 if ((lctx->options & DNS_MASTER_CHECKMXFAIL) != 0)
1085 options |= DNS_RDATA_CHECKMXFAIL;
1086 source = isc_lex_getsourcename(lctx->lex);
1087 do {
1088 initialws = ISC_FALSE;
1089 line = isc_lex_getsourceline(lctx->lex);
1090 GETTOKEN(lctx->lex, ISC_LEXOPT_INITIALWS | ISC_LEXOPT_QSTRING,
1091 &token, ISC_TRUE);
1092 line = isc_lex_getsourceline(lctx->lex);
1094 if (token.type == isc_tokentype_eof) {
1095 if (read_till_eol)
1096 WARNUNEXPECTEDEOF(lctx->lex);
1097 /* Pop the include stack? */
1098 if (ictx->parent != NULL) {
1099 COMMITALL;
1100 lctx->inc = ictx->parent;
1101 ictx->parent = NULL;
1102 incctx_destroy(lctx->mctx, ictx);
1103 RUNTIME_CHECK(isc_lex_close(lctx->lex) == ISC_R_SUCCESS);
1104 line = isc_lex_getsourceline(lctx->lex);
1105 source = isc_lex_getsourcename(lctx->lex);
1106 ictx = lctx->inc;
1107 EXPECTEOL;
1108 continue;
1110 done = ISC_TRUE;
1111 continue;
1114 if (token.type == isc_tokentype_eol) {
1115 read_till_eol = ISC_FALSE;
1116 continue; /* blank line */
1119 if (read_till_eol)
1120 continue;
1122 if (token.type == isc_tokentype_initialws) {
1124 * Still working on the same name.
1126 initialws = ISC_TRUE;
1127 } else if (token.type == isc_tokentype_string ||
1128 token.type == isc_tokentype_qstring) {
1131 * "$" Support.
1133 * "$ORIGIN" and "$INCLUDE" can both take domain names.
1134 * The processing of "$ORIGIN" and "$INCLUDE" extends
1135 * across the normal domain name processing.
1138 if (strcasecmp(DNS_AS_STR(token), "$ORIGIN") == 0) {
1139 GETTOKEN(lctx->lex, 0, &token, ISC_FALSE);
1140 finish_origin = ISC_TRUE;
1141 } else if (strcasecmp(DNS_AS_STR(token),
1142 "$TTL") == 0) {
1143 GETTOKEN(lctx->lex, 0, &token, ISC_FALSE);
1144 result =
1145 dns_ttl_fromtext(&token.value.as_textregion,
1146 &lctx->ttl);
1147 if (MANYERRS(lctx, result)) {
1148 SETRESULT(lctx, result);
1149 lctx->ttl = 0;
1150 } else if (result != ISC_R_SUCCESS)
1151 goto insist_and_cleanup;
1152 limit_ttl(callbacks, source, line, &lctx->ttl);
1153 lctx->default_ttl = lctx->ttl;
1154 lctx->default_ttl_known = ISC_TRUE;
1155 EXPECTEOL;
1156 continue;
1157 } else if (strcasecmp(DNS_AS_STR(token),
1158 "$INCLUDE") == 0) {
1159 COMMITALL;
1160 if ((lctx->options & DNS_MASTER_NOINCLUDE)
1161 != 0)
1163 (callbacks->error)(callbacks,
1164 "%s: %s:%lu: $INCLUDE not allowed",
1165 "dns_master_load",
1166 source, line);
1167 result = DNS_R_REFUSED;
1168 goto insist_and_cleanup;
1170 if (ttl_offset != 0) {
1171 (callbacks->error)(callbacks,
1172 "%s: %s:%lu: $INCLUDE "
1173 "may not be used with $DATE",
1174 "dns_master_load",
1175 source, line);
1176 result = DNS_R_SYNTAX;
1177 goto insist_and_cleanup;
1179 GETTOKEN(lctx->lex, ISC_LEXOPT_QSTRING, &token,
1180 ISC_FALSE);
1181 if (include_file != NULL)
1182 isc_mem_free(mctx, include_file);
1183 include_file = isc_mem_strdup(mctx,
1184 DNS_AS_STR(token));
1185 if (include_file == NULL) {
1186 result = ISC_R_NOMEMORY;
1187 goto log_and_cleanup;
1189 GETTOKEN(lctx->lex, 0, &token, ISC_TRUE);
1191 if (token.type == isc_tokentype_eol ||
1192 token.type == isc_tokentype_eof) {
1193 if (token.type == isc_tokentype_eof)
1194 WARNUNEXPECTEDEOF(lctx->lex);
1195 isc_lex_ungettoken(lctx->lex, &token);
1197 * No origin field.
1199 result = pushfile(include_file,
1200 ictx->origin, lctx);
1201 if (MANYERRS(lctx, result)) {
1202 SETRESULT(lctx, result);
1203 LOGITFILE(result, include_file);
1204 continue;
1205 } else if (result != ISC_R_SUCCESS) {
1206 LOGITFILE(result, include_file);
1207 goto insist_and_cleanup;
1209 ictx = lctx->inc;
1210 line = isc_lex_getsourceline(lctx->lex);
1211 source =
1212 isc_lex_getsourcename(lctx->lex);
1213 continue;
1216 * There is an origin field. Fall through
1217 * to domain name processing code and do
1218 * the actual inclusion later.
1220 finish_include = ISC_TRUE;
1221 } else if (strcasecmp(DNS_AS_STR(token),
1222 "$DATE") == 0) {
1223 isc_int64_t dump_time64;
1224 isc_stdtime_t dump_time, current_time;
1225 GETTOKEN(lctx->lex, 0, &token, ISC_FALSE);
1226 isc_stdtime_get(&current_time);
1227 result = dns_time64_fromtext(DNS_AS_STR(token),
1228 &dump_time64);
1229 if (MANYERRS(lctx, result)) {
1230 SETRESULT(lctx, result);
1231 LOGIT(result);
1232 dump_time64 = 0;
1233 } else if (result != ISC_R_SUCCESS)
1234 goto log_and_cleanup;
1235 dump_time = (isc_stdtime_t)dump_time64;
1236 if (dump_time != dump_time64) {
1237 UNEXPECTED_ERROR(__FILE__, __LINE__,
1238 "%s: %s:%lu: $DATE outside epoch",
1239 "dns_master_load", source, line);
1240 result = ISC_R_UNEXPECTED;
1241 goto insist_and_cleanup;
1243 if (dump_time > current_time) {
1244 UNEXPECTED_ERROR(__FILE__, __LINE__,
1245 "%s: %s:%lu: "
1246 "$DATE in future, using current date",
1247 "dns_master_load", source, line);
1248 dump_time = current_time;
1250 ttl_offset = current_time - dump_time;
1251 EXPECTEOL;
1252 continue;
1253 } else if (strcasecmp(DNS_AS_STR(token),
1254 "$GENERATE") == 0) {
1256 * Lazy cleanup.
1258 if (range != NULL)
1259 isc_mem_free(mctx, range);
1260 if (lhs != NULL)
1261 isc_mem_free(mctx, lhs);
1262 if (gtype != NULL)
1263 isc_mem_free(mctx, gtype);
1264 if (rhs != NULL)
1265 isc_mem_free(mctx, rhs);
1266 range = lhs = gtype = rhs = NULL;
1267 /* RANGE */
1268 GETTOKEN(lctx->lex, 0, &token, ISC_FALSE);
1269 range = isc_mem_strdup(mctx,
1270 DNS_AS_STR(token));
1271 if (range == NULL) {
1272 result = ISC_R_NOMEMORY;
1273 goto log_and_cleanup;
1275 /* LHS */
1276 GETTOKEN(lctx->lex, 0, &token, ISC_FALSE);
1277 lhs = isc_mem_strdup(mctx, DNS_AS_STR(token));
1278 if (lhs == NULL) {
1279 result = ISC_R_NOMEMORY;
1280 goto log_and_cleanup;
1282 rdclass = 0;
1283 explicit_ttl = ISC_FALSE;
1284 /* CLASS? */
1285 GETTOKEN(lctx->lex, 0, &token, ISC_FALSE);
1286 if (dns_rdataclass_fromtext(&rdclass,
1287 &token.value.as_textregion)
1288 == ISC_R_SUCCESS) {
1289 GETTOKEN(lctx->lex, 0, &token,
1290 ISC_FALSE);
1292 /* TTL? */
1293 if (dns_ttl_fromtext(&token.value.as_textregion,
1294 &lctx->ttl)
1295 == ISC_R_SUCCESS) {
1296 limit_ttl(callbacks, source, line,
1297 &lctx->ttl);
1298 lctx->ttl_known = ISC_TRUE;
1299 explicit_ttl = ISC_TRUE;
1300 GETTOKEN(lctx->lex, 0, &token,
1301 ISC_FALSE);
1303 /* CLASS? */
1304 if (rdclass == 0 &&
1305 dns_rdataclass_fromtext(&rdclass,
1306 &token.value.as_textregion)
1307 == ISC_R_SUCCESS)
1308 GETTOKEN(lctx->lex, 0, &token,
1309 ISC_FALSE);
1310 /* TYPE */
1311 gtype = isc_mem_strdup(mctx,
1312 DNS_AS_STR(token));
1313 if (gtype == NULL) {
1314 result = ISC_R_NOMEMORY;
1315 goto log_and_cleanup;
1317 /* RHS */
1318 GETTOKEN(lctx->lex, ISC_LEXOPT_QSTRING,
1319 &token, ISC_FALSE);
1320 rhs = isc_mem_strdup(mctx, DNS_AS_STR(token));
1321 if (rhs == NULL) {
1322 result = ISC_R_NOMEMORY;
1323 goto log_and_cleanup;
1325 if (!lctx->ttl_known &&
1326 !lctx->default_ttl_known) {
1327 (*callbacks->error)(callbacks,
1328 "%s: %s:%lu: no TTL specified",
1329 "dns_master_load", source, line);
1330 result = DNS_R_NOTTL;
1331 if (MANYERRS(lctx, result)) {
1332 SETRESULT(lctx, result);
1333 lctx->ttl = 0;
1334 } else if (result != ISC_R_SUCCESS)
1335 goto insist_and_cleanup;
1336 } else if (!explicit_ttl &&
1337 lctx->default_ttl_known) {
1338 lctx->ttl = lctx->default_ttl;
1341 * If the class specified does not match the
1342 * zone's class print out a error message and
1343 * exit.
1345 if (rdclass != 0 && rdclass != lctx->zclass) {
1346 goto bad_class;
1348 result = generate(lctx, range, lhs, gtype, rhs,
1349 source, line);
1350 if (MANYERRS(lctx, result)) {
1351 SETRESULT(lctx, result);
1352 } else if (result != ISC_R_SUCCESS)
1353 goto insist_and_cleanup;
1354 EXPECTEOL;
1355 continue;
1356 } else if (strncasecmp(DNS_AS_STR(token),
1357 "$", 1) == 0) {
1358 (callbacks->error)(callbacks,
1359 "%s: %s:%lu: "
1360 "unknown $ directive '%s'",
1361 "dns_master_load", source, line,
1362 DNS_AS_STR(token));
1363 result = DNS_R_SYNTAX;
1364 if (MANYERRS(lctx, result)) {
1365 SETRESULT(lctx, result);
1366 } else if (result != ISC_R_SUCCESS)
1367 goto insist_and_cleanup;
1371 * Normal processing resumes.
1373 * Find a free name buffer.
1375 for (new_in_use = 0; new_in_use < NBUFS; new_in_use++)
1376 if (!ictx->in_use[new_in_use])
1377 break;
1378 INSIST(new_in_use < NBUFS);
1379 dns_fixedname_init(&ictx->fixed[new_in_use]);
1380 new_name = dns_fixedname_name(&ictx->fixed[new_in_use]);
1381 isc_buffer_init(&buffer, token.value.as_region.base,
1382 token.value.as_region.length);
1383 isc_buffer_add(&buffer, token.value.as_region.length);
1384 isc_buffer_setactive(&buffer,
1385 token.value.as_region.length);
1386 result = dns_name_fromtext(new_name, &buffer,
1387 ictx->origin, 0, NULL);
1388 if (MANYERRS(lctx, result)) {
1389 SETRESULT(lctx, result);
1390 LOGIT(result);
1391 read_till_eol = ISC_TRUE;
1392 continue;
1393 } else if (result != ISC_R_SUCCESS)
1394 goto log_and_cleanup;
1397 * Finish $ORIGIN / $INCLUDE processing if required.
1399 if (finish_origin) {
1400 if (ictx->origin_in_use != -1)
1401 ictx->in_use[ictx->origin_in_use] =
1402 ISC_FALSE;
1403 ictx->origin_in_use = new_in_use;
1404 ictx->in_use[ictx->origin_in_use] = ISC_TRUE;
1405 ictx->origin = new_name;
1406 finish_origin = ISC_FALSE;
1407 EXPECTEOL;
1408 continue;
1410 if (finish_include) {
1411 finish_include = ISC_FALSE;
1412 result = pushfile(include_file, new_name, lctx);
1413 if (MANYERRS(lctx, result)) {
1414 SETRESULT(lctx, result);
1415 LOGITFILE(result, include_file);
1416 continue;
1417 } else if (result != ISC_R_SUCCESS) {
1418 LOGITFILE(result, include_file);
1419 goto insist_and_cleanup;
1421 ictx = lctx->inc;
1422 line = isc_lex_getsourceline(lctx->lex);
1423 source = isc_lex_getsourcename(lctx->lex);
1424 continue;
1428 * "$" Processing Finished
1432 * If we are processing glue and the new name does
1433 * not match the current glue name, commit the glue
1434 * and pop stacks leaving us in 'normal' processing
1435 * state. Linked lists are undone by commit().
1437 if (ictx->glue != NULL &&
1438 dns_name_compare(ictx->glue, new_name) != 0) {
1439 result = commit(callbacks, lctx, &glue_list,
1440 ictx->glue, source,
1441 ictx->glue_line);
1442 if (MANYERRS(lctx, result)) {
1443 SETRESULT(lctx, result);
1444 } else if (result != ISC_R_SUCCESS)
1445 goto insist_and_cleanup;
1446 if (ictx->glue_in_use != -1)
1447 ictx->in_use[ictx->glue_in_use] =
1448 ISC_FALSE;
1449 ictx->glue_in_use = -1;
1450 ictx->glue = NULL;
1451 rdcount = rdcount_save;
1452 rdlcount = rdlcount_save;
1453 target = target_save;
1457 * If we are in 'normal' processing state and the new
1458 * name does not match the current name, see if the
1459 * new name is for glue and treat it as such,
1460 * otherwise we have a new name so commit what we
1461 * have.
1463 if ((ictx->glue == NULL) && (ictx->current == NULL ||
1464 dns_name_compare(ictx->current, new_name) != 0)) {
1465 if (current_has_delegation &&
1466 is_glue(&current_list, new_name)) {
1467 rdcount_save = rdcount;
1468 rdlcount_save = rdlcount;
1469 target_save = target;
1470 ictx->glue = new_name;
1471 ictx->glue_in_use = new_in_use;
1472 ictx->in_use[ictx->glue_in_use] =
1473 ISC_TRUE;
1474 } else {
1475 result = commit(callbacks, lctx,
1476 &current_list,
1477 ictx->current,
1478 source,
1479 ictx->current_line);
1480 if (MANYERRS(lctx, result)) {
1481 SETRESULT(lctx, result);
1482 } else if (result != ISC_R_SUCCESS)
1483 goto insist_and_cleanup;
1484 rdcount = 0;
1485 rdlcount = 0;
1486 if (ictx->current_in_use != -1)
1487 ictx->in_use[ictx->current_in_use] =
1488 ISC_FALSE;
1489 ictx->current_in_use = new_in_use;
1490 ictx->in_use[ictx->current_in_use] =
1491 ISC_TRUE;
1492 ictx->current = new_name;
1493 current_has_delegation = ISC_FALSE;
1494 isc_buffer_init(&target, target_mem,
1495 target_size);
1498 * Check for internal wildcards.
1500 if ((lctx->options & DNS_MASTER_CHECKWILDCARD)
1501 != 0)
1502 check_wildcard(ictx, source, line,
1503 callbacks);
1506 if ((lctx->options & DNS_MASTER_ZONE) != 0 &&
1507 (lctx->options & DNS_MASTER_SLAVE) == 0 &&
1508 (lctx->options & DNS_MASTER_KEY) == 0 &&
1509 !dns_name_issubdomain(new_name, lctx->top))
1511 char namebuf[DNS_NAME_FORMATSIZE];
1512 dns_name_format(new_name, namebuf,
1513 sizeof(namebuf));
1515 * Ignore out-of-zone data.
1517 (*callbacks->warn)(callbacks,
1518 "%s:%lu: "
1519 "ignoring out-of-zone data (%s)",
1520 source, line, namebuf);
1521 ictx->drop = ISC_TRUE;
1522 } else
1523 ictx->drop = ISC_FALSE;
1524 } else {
1525 UNEXPECTED_ERROR(__FILE__, __LINE__,
1526 "%s:%lu: isc_lex_gettoken() returned "
1527 "unexpected token type (%d)",
1528 source, line, token.type);
1529 result = ISC_R_UNEXPECTED;
1530 if (MANYERRS(lctx, result)) {
1531 SETRESULT(lctx, result);
1532 LOGIT(result);
1533 continue;
1534 } else if (result != ISC_R_SUCCESS)
1535 goto insist_and_cleanup;
1539 * Find TTL, class and type. Both TTL and class are optional
1540 * and may occur in any order if they exist. TTL and class
1541 * come before type which must exist.
1543 * [<TTL>] [<class>] <type> <RDATA>
1544 * [<class>] [<TTL>] <type> <RDATA>
1547 type = 0;
1548 rdclass = 0;
1550 GETTOKEN(lctx->lex, 0, &token, initialws);
1552 if (initialws) {
1553 if (token.type == isc_tokentype_eol) {
1554 read_till_eol = ISC_FALSE;
1555 continue; /* blank line */
1558 if (token.type == isc_tokentype_eof) {
1559 WARNUNEXPECTEDEOF(lctx->lex);
1560 read_till_eol = ISC_FALSE;
1561 isc_lex_ungettoken(lctx->lex, &token);
1562 continue;
1565 if (ictx->current == NULL) {
1566 (*callbacks->error)(callbacks,
1567 "%s:%lu: no current owner name",
1568 source, line);
1569 result = DNS_R_NOOWNER;
1570 if (MANYERRS(lctx, result)) {
1571 SETRESULT(lctx, result);
1572 read_till_eol = ISC_TRUE;
1573 continue;
1574 } else if (result != ISC_R_SUCCESS)
1575 goto insist_and_cleanup;
1579 if (dns_rdataclass_fromtext(&rdclass,
1580 &token.value.as_textregion)
1581 == ISC_R_SUCCESS)
1582 GETTOKEN(lctx->lex, 0, &token, ISC_FALSE);
1584 explicit_ttl = ISC_FALSE;
1585 if (dns_ttl_fromtext(&token.value.as_textregion, &lctx->ttl)
1586 == ISC_R_SUCCESS) {
1587 limit_ttl(callbacks, source, line, &lctx->ttl);
1588 explicit_ttl = ISC_TRUE;
1589 lctx->ttl_known = ISC_TRUE;
1590 GETTOKEN(lctx->lex, 0, &token, ISC_FALSE);
1593 if (token.type != isc_tokentype_string) {
1594 UNEXPECTED_ERROR(__FILE__, __LINE__,
1595 "isc_lex_gettoken() returned unexpected token type");
1596 result = ISC_R_UNEXPECTED;
1597 if (MANYERRS(lctx, result)) {
1598 SETRESULT(lctx, result);
1599 read_till_eol = ISC_TRUE;
1600 continue;
1601 } else if (result != ISC_R_SUCCESS)
1602 goto insist_and_cleanup;
1605 if (rdclass == 0 &&
1606 dns_rdataclass_fromtext(&rdclass,
1607 &token.value.as_textregion)
1608 == ISC_R_SUCCESS)
1609 GETTOKEN(lctx->lex, 0, &token, ISC_FALSE);
1611 if (token.type != isc_tokentype_string) {
1612 UNEXPECTED_ERROR(__FILE__, __LINE__,
1613 "isc_lex_gettoken() returned unexpected token type");
1614 result = ISC_R_UNEXPECTED;
1615 if (MANYERRS(lctx, result)) {
1616 SETRESULT(lctx, result);
1617 read_till_eol = ISC_TRUE;
1618 continue;
1619 } else if (result != ISC_R_SUCCESS)
1620 goto insist_and_cleanup;
1623 result = dns_rdatatype_fromtext(&type,
1624 &token.value.as_textregion);
1625 if (result != ISC_R_SUCCESS) {
1626 (*callbacks->warn)(callbacks,
1627 "%s:%lu: unknown RR type '%.*s'",
1628 source, line,
1629 token.value.as_textregion.length,
1630 token.value.as_textregion.base);
1631 if (MANYERRS(lctx, result)) {
1632 SETRESULT(lctx, result);
1633 read_till_eol = ISC_TRUE;
1634 continue;
1635 } else if (result != ISC_R_SUCCESS)
1636 goto insist_and_cleanup;
1640 * If the class specified does not match the zone's class
1641 * print out a error message and exit.
1643 if (rdclass != 0 && rdclass != lctx->zclass) {
1644 bad_class:
1646 dns_rdataclass_format(rdclass, classname1,
1647 sizeof(classname1));
1648 dns_rdataclass_format(lctx->zclass, classname2,
1649 sizeof(classname2));
1650 (*callbacks->error)(callbacks,
1651 "%s:%lu: class '%s' != "
1652 "zone class '%s'",
1653 source, line,
1654 classname1, classname2);
1655 result = DNS_R_BADCLASS;
1656 if (MANYERRS(lctx, result)) {
1657 SETRESULT(lctx, result);
1658 read_till_eol = ISC_TRUE;
1659 continue;
1660 } else if (result != ISC_R_SUCCESS)
1661 goto insist_and_cleanup;
1664 if (type == dns_rdatatype_ns && ictx->glue == NULL)
1665 current_has_delegation = ISC_TRUE;
1668 * RFC1123: MD and MF are not allowed to be loaded from
1669 * master files.
1671 if ((lctx->options & DNS_MASTER_ZONE) != 0 &&
1672 (lctx->options & DNS_MASTER_SLAVE) == 0 &&
1673 (type == dns_rdatatype_md || type == dns_rdatatype_mf)) {
1674 char typename[DNS_RDATATYPE_FORMATSIZE];
1676 result = DNS_R_OBSOLETE;
1678 dns_rdatatype_format(type, typename, sizeof(typename));
1679 (*callbacks->error)(callbacks,
1680 "%s:%lu: %s '%s': %s",
1681 source, line,
1682 "type", typename,
1683 dns_result_totext(result));
1684 if (MANYERRS(lctx, result)) {
1685 SETRESULT(lctx, result);
1686 } else
1687 goto insist_and_cleanup;
1691 * Find a rdata structure.
1693 if (rdcount == rdata_size) {
1694 new_rdata = grow_rdata(rdata_size + RDSZ, rdata,
1695 rdata_size, &current_list,
1696 &glue_list, mctx);
1697 if (new_rdata == NULL) {
1698 result = ISC_R_NOMEMORY;
1699 goto log_and_cleanup;
1701 rdata_size += RDSZ;
1702 rdata = new_rdata;
1706 * Peek at the NS record.
1708 if (type == dns_rdatatype_ns &&
1709 lctx->zclass == dns_rdataclass_in &&
1710 (lctx->options & DNS_MASTER_CHECKNS) != 0) {
1712 GETTOKEN(lctx->lex, 0, &token, ISC_FALSE);
1713 result = check_ns(lctx, &token, source, line);
1714 isc_lex_ungettoken(lctx->lex, &token);
1715 if ((lctx->options & DNS_MASTER_FATALNS) != 0) {
1716 if (MANYERRS(lctx, result)) {
1717 SETRESULT(lctx, result);
1718 } else if (result != ISC_R_SUCCESS)
1719 goto insist_and_cleanup;
1724 * Check owner name.
1726 options &= ~DNS_RDATA_CHECKREVERSE;
1727 if ((lctx->options & DNS_MASTER_CHECKNAMES) != 0) {
1728 isc_boolean_t ok;
1729 dns_name_t *name;
1731 name = (ictx->glue != NULL) ? ictx->glue :
1732 ictx->current;
1733 ok = dns_rdata_checkowner(name, lctx->zclass, type,
1734 ISC_TRUE);
1735 if (!ok) {
1736 char namebuf[DNS_NAME_FORMATSIZE];
1737 const char *desc;
1738 dns_name_format(name, namebuf, sizeof(namebuf));
1739 result = DNS_R_BADOWNERNAME;
1740 desc = dns_result_totext(result);
1741 if ((lctx->options & DNS_MASTER_CHECKNAMESFAIL) != 0) {
1742 (*callbacks->error)(callbacks,
1743 "%s:%lu: %s: %s",
1744 source, line,
1745 namebuf, desc);
1746 if (MANYERRS(lctx, result)) {
1747 SETRESULT(lctx, result);
1748 } else if (result != ISC_R_SUCCESS)
1749 goto cleanup;
1750 } else {
1751 (*callbacks->warn)(callbacks,
1752 "%s:%lu: %s: %s",
1753 source, line,
1754 namebuf, desc);
1757 if (type == dns_rdatatype_ptr &&
1758 (dns_name_issubdomain(name, &in_addr_arpa) ||
1759 dns_name_issubdomain(name, &ip6_arpa) ||
1760 dns_name_issubdomain(name, &ip6_int)))
1761 options |= DNS_RDATA_CHECKREVERSE;
1765 * Read rdata contents.
1767 dns_rdata_init(&rdata[rdcount]);
1768 target_ft = target;
1769 result = dns_rdata_fromtext(&rdata[rdcount], lctx->zclass,
1770 type, lctx->lex, ictx->origin,
1771 options, lctx->mctx, &target,
1772 callbacks);
1773 if (MANYERRS(lctx, result)) {
1774 SETRESULT(lctx, result);
1775 continue;
1776 } else if (result != ISC_R_SUCCESS)
1777 goto insist_and_cleanup;
1779 if (ictx->drop) {
1780 target = target_ft;
1781 continue;
1784 if (type == dns_rdatatype_soa &&
1785 (lctx->options & DNS_MASTER_ZONE) != 0 &&
1786 dns_name_compare(ictx->current, lctx->top) != 0) {
1787 char namebuf[DNS_NAME_FORMATSIZE];
1788 dns_name_format(ictx->current, namebuf,
1789 sizeof(namebuf));
1790 (*callbacks->error)(callbacks, "%s:%lu: SOA "
1791 "record not at top of zone (%s)",
1792 source, line, namebuf);
1793 result = DNS_R_NOTZONETOP;
1794 if (MANYERRS(lctx, result)) {
1795 SETRESULT(lctx, result);
1796 read_till_eol = ISC_TRUE;
1797 target = target_ft;
1798 continue;
1799 } else if (result != ISC_R_SUCCESS)
1800 goto insist_and_cleanup;
1804 if (type == dns_rdatatype_rrsig ||
1805 type == dns_rdatatype_sig)
1806 covers = dns_rdata_covers(&rdata[rdcount]);
1807 else
1808 covers = 0;
1810 if (!lctx->ttl_known && !lctx->default_ttl_known) {
1811 if (type == dns_rdatatype_soa) {
1812 (*callbacks->warn)(callbacks,
1813 "%s:%lu: no TTL specified; "
1814 "using SOA MINTTL instead",
1815 source, line);
1816 lctx->ttl = dns_soa_getminimum(&rdata[rdcount]);
1817 limit_ttl(callbacks, source, line, &lctx->ttl);
1818 lctx->default_ttl = lctx->ttl;
1819 lctx->default_ttl_known = ISC_TRUE;
1820 } else if ((lctx->options & DNS_MASTER_HINT) != 0) {
1822 * Zero TTL's are fine for hints.
1824 lctx->ttl = 0;
1825 lctx->default_ttl = lctx->ttl;
1826 lctx->default_ttl_known = ISC_TRUE;
1827 } else {
1828 (*callbacks->warn)(callbacks,
1829 "%s:%lu: no TTL specified; "
1830 "zone rejected",
1831 source, line);
1832 result = DNS_R_NOTTL;
1833 if (MANYERRS(lctx, result)) {
1834 SETRESULT(lctx, result);
1835 lctx->ttl = 0;
1836 } else {
1837 goto insist_and_cleanup;
1840 } else if (!explicit_ttl && lctx->default_ttl_known) {
1841 lctx->ttl = lctx->default_ttl;
1842 } else if (!explicit_ttl && lctx->warn_1035) {
1843 (*callbacks->warn)(callbacks,
1844 "%s:%lu: "
1845 "using RFC1035 TTL semantics",
1846 source, line);
1847 lctx->warn_1035 = ISC_FALSE;
1850 if (type == dns_rdatatype_rrsig && lctx->warn_sigexpired) {
1851 dns_rdata_rrsig_t sig;
1852 result = dns_rdata_tostruct(&rdata[rdcount], &sig,
1853 NULL);
1854 RUNTIME_CHECK(result == ISC_R_SUCCESS);
1855 if (isc_serial_lt(sig.timeexpire, now)) {
1856 (*callbacks->warn)(callbacks,
1857 "%s:%lu: "
1858 "signature has expired",
1859 source, line);
1860 lctx->warn_sigexpired = ISC_FALSE;
1864 if ((type == dns_rdatatype_sig || type == dns_rdatatype_nxt) &&
1865 lctx->warn_tcr && (lctx->options & DNS_MASTER_ZONE) != 0 &&
1866 (lctx->options & DNS_MASTER_SLAVE) == 0) {
1867 (*callbacks->warn)(callbacks, "%s:%lu: old style DNSSEC "
1868 " zone detected", source, line);
1869 lctx->warn_tcr = ISC_FALSE;
1872 if ((lctx->options & DNS_MASTER_AGETTL) != 0) {
1874 * Adjust the TTL for $DATE. If the RR has already
1875 * expired, ignore it.
1877 if (lctx->ttl < ttl_offset)
1878 continue;
1879 lctx->ttl -= ttl_offset;
1883 * Find type in rdatalist.
1884 * If it does not exist create new one and prepend to list
1885 * as this will minimise list traversal.
1887 if (ictx->glue != NULL)
1888 this = ISC_LIST_HEAD(glue_list);
1889 else
1890 this = ISC_LIST_HEAD(current_list);
1892 while (this != NULL) {
1893 if (this->type == type && this->covers == covers)
1894 break;
1895 this = ISC_LIST_NEXT(this, link);
1898 if (this == NULL) {
1899 if (rdlcount == rdatalist_size) {
1900 new_rdatalist =
1901 grow_rdatalist(rdatalist_size + RDLSZ,
1902 rdatalist,
1903 rdatalist_size,
1904 &current_list,
1905 &glue_list,
1906 mctx);
1907 if (new_rdatalist == NULL) {
1908 result = ISC_R_NOMEMORY;
1909 goto log_and_cleanup;
1911 rdatalist = new_rdatalist;
1912 rdatalist_size += RDLSZ;
1914 this = &rdatalist[rdlcount++];
1915 this->type = type;
1916 this->covers = covers;
1917 this->rdclass = lctx->zclass;
1918 this->ttl = lctx->ttl;
1919 ISC_LIST_INIT(this->rdata);
1920 if (ictx->glue != NULL)
1921 ISC_LIST_INITANDPREPEND(glue_list, this, link);
1922 else
1923 ISC_LIST_INITANDPREPEND(current_list, this,
1924 link);
1925 } else if (this->ttl != lctx->ttl) {
1926 (*callbacks->warn)(callbacks,
1927 "%s:%lu: "
1928 "TTL set to prior TTL (%lu)",
1929 source, line, this->ttl);
1930 lctx->ttl = this->ttl;
1933 ISC_LIST_APPEND(this->rdata, &rdata[rdcount], link);
1934 if (ictx->glue != NULL)
1935 ictx->glue_line = line;
1936 else
1937 ictx->current_line = line;
1938 rdcount++;
1941 * We must have at least 64k as rdlen is 16 bits.
1942 * If we don't commit everything we have so far.
1944 if ((target.length - target.used) < MINTSIZ)
1945 COMMITALL;
1946 next_line:
1948 } while (!done && (lctx->loop_cnt == 0 || loop_cnt++ < lctx->loop_cnt));
1951 * Commit what has not yet been committed.
1953 result = commit(callbacks, lctx, &current_list, ictx->current,
1954 source, ictx->current_line);
1955 if (MANYERRS(lctx, result)) {
1956 SETRESULT(lctx, result);
1957 } else if (result != ISC_R_SUCCESS)
1958 goto insist_and_cleanup;
1959 result = commit(callbacks, lctx, &glue_list, ictx->glue,
1960 source, ictx->glue_line);
1961 if (MANYERRS(lctx, result)) {
1962 SETRESULT(lctx, result);
1963 } else if (result != ISC_R_SUCCESS)
1964 goto insist_and_cleanup;
1966 if (!done) {
1967 INSIST(lctx->done != NULL && lctx->task != NULL);
1968 result = DNS_R_CONTINUE;
1969 } else if (result == ISC_R_SUCCESS && lctx->result != ISC_R_SUCCESS) {
1970 result = lctx->result;
1971 } else if (result == ISC_R_SUCCESS && lctx->seen_include)
1972 result = DNS_R_SEENINCLUDE;
1973 goto cleanup;
1975 log_and_cleanup:
1976 LOGIT(result);
1978 insist_and_cleanup:
1979 INSIST(result != ISC_R_SUCCESS);
1981 cleanup:
1982 while ((this = ISC_LIST_HEAD(current_list)) != NULL)
1983 ISC_LIST_UNLINK(current_list, this, link);
1984 while ((this = ISC_LIST_HEAD(glue_list)) != NULL)
1985 ISC_LIST_UNLINK(glue_list, this, link);
1986 if (rdatalist != NULL)
1987 isc_mem_put(mctx, rdatalist,
1988 rdatalist_size * sizeof(*rdatalist));
1989 if (rdata != NULL)
1990 isc_mem_put(mctx, rdata, rdata_size * sizeof(*rdata));
1991 if (target_mem != NULL)
1992 isc_mem_put(mctx, target_mem, target_size);
1993 if (include_file != NULL)
1994 isc_mem_free(mctx, include_file);
1995 if (range != NULL)
1996 isc_mem_free(mctx, range);
1997 if (lhs != NULL)
1998 isc_mem_free(mctx, lhs);
1999 if (gtype != NULL)
2000 isc_mem_free(mctx, gtype);
2001 if (rhs != NULL)
2002 isc_mem_free(mctx, rhs);
2003 return (result);
2006 static isc_result_t
2007 pushfile(const char *master_file, dns_name_t *origin, dns_loadctx_t *lctx) {
2008 isc_result_t result;
2009 dns_incctx_t *ictx;
2010 dns_incctx_t *new = NULL;
2011 isc_region_t r;
2012 int new_in_use;
2014 REQUIRE(master_file != NULL);
2015 REQUIRE(DNS_LCTX_VALID(lctx));
2017 ictx = lctx->inc;
2018 lctx->seen_include = ISC_TRUE;
2020 result = incctx_create(lctx->mctx, origin, &new);
2021 if (result != ISC_R_SUCCESS)
2022 return (result);
2024 /* Set current domain. */
2025 if (ictx->glue != NULL || ictx->current != NULL) {
2026 for (new_in_use = 0; new_in_use < NBUFS; new_in_use++)
2027 if (!new->in_use[new_in_use])
2028 break;
2029 INSIST(new_in_use < NBUFS);
2030 new->current_in_use = new_in_use;
2031 new->current =
2032 dns_fixedname_name(&new->fixed[new->current_in_use]);
2033 new->in_use[new->current_in_use] = ISC_TRUE;
2034 dns_name_toregion((ictx->glue != NULL) ?
2035 ictx->glue : ictx->current, &r);
2036 dns_name_fromregion(new->current, &r);
2037 new->drop = ictx->drop;
2040 result = (lctx->openfile)(lctx, master_file);
2041 if (result != ISC_R_SUCCESS)
2042 goto cleanup;
2043 new->parent = ictx;
2044 lctx->inc = new;
2045 return (ISC_R_SUCCESS);
2047 cleanup:
2048 if (new != NULL)
2049 incctx_destroy(lctx->mctx, new);
2050 return (result);
2053 static inline isc_result_t
2054 read_and_check(isc_boolean_t do_read, isc_buffer_t *buffer,
2055 size_t len, FILE *f)
2057 isc_result_t result;
2059 if (do_read) {
2060 INSIST(isc_buffer_availablelength(buffer) >= len);
2061 result = isc_stdio_read(isc_buffer_used(buffer), 1, len,
2062 f, NULL);
2063 if (result != ISC_R_SUCCESS)
2064 return (result);
2065 isc_buffer_add(buffer, len);
2066 } else if (isc_buffer_remaininglength(buffer) < len)
2067 return (ISC_R_RANGE);
2069 return (ISC_R_SUCCESS);
2072 static isc_result_t
2073 load_raw(dns_loadctx_t *lctx) {
2074 isc_result_t result = ISC_R_SUCCESS;
2075 isc_boolean_t done = ISC_FALSE;
2076 unsigned int loop_cnt = 0;
2077 dns_rdatacallbacks_t *callbacks;
2078 unsigned char namebuf[DNS_NAME_MAXWIRE];
2079 isc_region_t r;
2080 dns_name_t name;
2081 rdatalist_head_t head, dummy;
2082 dns_rdatalist_t rdatalist;
2083 isc_mem_t *mctx = lctx->mctx;
2084 dns_rdata_t *rdata = NULL;
2085 unsigned int rdata_size = 0;
2086 int target_size = TSIZ;
2087 isc_buffer_t target;
2088 unsigned char *target_mem = NULL;
2090 REQUIRE(DNS_LCTX_VALID(lctx));
2091 callbacks = lctx->callbacks;
2093 if (lctx->first) {
2094 dns_masterrawheader_t header;
2095 isc_uint32_t format, version, dumptime;
2096 size_t hdrlen = sizeof(format) + sizeof(version) +
2097 sizeof(dumptime);
2099 INSIST(hdrlen <= sizeof(header));
2100 isc_buffer_init(&target, &header, sizeof(header));
2102 result = isc_stdio_read(&header, 1, hdrlen, lctx->f, NULL);
2103 if (result != ISC_R_SUCCESS) {
2104 UNEXPECTED_ERROR(__FILE__, __LINE__,
2105 "isc_stdio_read failed: %s",
2106 isc_result_totext(result));
2107 return (result);
2109 isc_buffer_add(&target, hdrlen);
2110 format = isc_buffer_getuint32(&target);
2111 if (format != dns_masterformat_raw) {
2112 (*callbacks->error)(callbacks,
2113 "dns_master_load: "
2114 "file format mismatch");
2115 return (ISC_R_NOTIMPLEMENTED);
2118 version = isc_buffer_getuint32(&target);
2119 if (version > DNS_RAWFORMAT_VERSION) {
2120 (*callbacks->error)(callbacks,
2121 "dns_master_load: "
2122 "unsupported file format version");
2123 return (ISC_R_NOTIMPLEMENTED);
2126 /* Empty read: currently, we do not use dumptime */
2127 dumptime = isc_buffer_getuint32(&target);
2129 lctx->first = ISC_FALSE;
2132 ISC_LIST_INIT(head);
2133 ISC_LIST_INIT(dummy);
2134 dns_rdatalist_init(&rdatalist);
2137 * Allocate target_size of buffer space. This is greater than twice
2138 * the maximum individual RR data size.
2140 target_mem = isc_mem_get(mctx, target_size);
2141 if (target_mem == NULL) {
2142 result = ISC_R_NOMEMORY;
2143 goto cleanup;
2145 isc_buffer_init(&target, target_mem, target_size);
2148 * In the following loop, we regard any error fatal regardless of
2149 * whether "MANYERRORS" is set in the context option. This is because
2150 * normal errors should already have been checked at creation time.
2151 * Besides, it is very unlikely that we can recover from an error
2152 * in this format, and so trying to continue parsing erroneous data
2153 * does not really make sense.
2155 for (loop_cnt = 0;
2156 (lctx->loop_cnt == 0 || loop_cnt < lctx->loop_cnt);
2157 loop_cnt++) {
2158 unsigned int i, rdcount, consumed_name;
2159 isc_uint16_t namelen;
2160 isc_uint32_t totallen;
2161 size_t minlen, readlen;
2162 isc_boolean_t sequential_read = ISC_FALSE;
2164 /* Read the data length */
2165 isc_buffer_clear(&target);
2166 INSIST(isc_buffer_availablelength(&target) >=
2167 sizeof(totallen));
2168 result = isc_stdio_read(target.base, 1, sizeof(totallen),
2169 lctx->f, NULL);
2170 if (result == ISC_R_EOF) {
2171 result = ISC_R_SUCCESS;
2172 done = ISC_TRUE;
2173 break;
2175 if (result != ISC_R_SUCCESS)
2176 goto cleanup;
2177 isc_buffer_add(&target, sizeof(totallen));
2178 totallen = isc_buffer_getuint32(&target);
2180 * Validation: the input data must at least contain the common
2181 * header.
2183 minlen = sizeof(totallen) + sizeof(isc_uint16_t) +
2184 sizeof(isc_uint16_t) + sizeof(isc_uint16_t) +
2185 sizeof(isc_uint32_t) + sizeof(isc_uint32_t);
2186 if (totallen < minlen) {
2187 result = ISC_R_RANGE;
2188 goto cleanup;
2190 totallen -= sizeof(totallen);
2192 isc_buffer_clear(&target);
2193 if (totallen > isc_buffer_availablelength(&target)) {
2195 * The default buffer size should typically be large
2196 * enough to store the entire RRset. We could try to
2197 * allocate enough space if this is not the case, but
2198 * it might cause a hazardous result when "totallen"
2199 * is forged. Thus, we'd rather take an inefficient
2200 * but robust approach in this atypical case: read
2201 * data step by step, and commit partial data when
2202 * necessary. Note that the buffer must be large
2203 * enough to store the "header part", owner name, and
2204 * at least one rdata (however large it is).
2206 sequential_read = ISC_TRUE;
2207 readlen = minlen - sizeof(totallen);
2208 } else {
2210 * Typical case. We can read the whole RRset at once
2211 * with the default buffer.
2213 readlen = totallen;
2215 result = isc_stdio_read(target.base, 1, readlen,
2216 lctx->f, NULL);
2217 if (result != ISC_R_SUCCESS)
2218 goto cleanup;
2219 isc_buffer_add(&target, readlen);
2221 /* Construct RRset headers */
2222 rdatalist.rdclass = isc_buffer_getuint16(&target);
2223 rdatalist.type = isc_buffer_getuint16(&target);
2224 rdatalist.covers = isc_buffer_getuint16(&target);
2225 rdatalist.ttl = isc_buffer_getuint32(&target);
2226 rdcount = isc_buffer_getuint32(&target);
2227 if (rdcount == 0) {
2228 result = ISC_R_RANGE;
2229 goto cleanup;
2231 INSIST(isc_buffer_consumedlength(&target) <= readlen);
2233 /* Owner name: length followed by name */
2234 result = read_and_check(sequential_read, &target,
2235 sizeof(namelen), lctx->f);
2236 if (result != ISC_R_SUCCESS)
2237 goto cleanup;
2238 namelen = isc_buffer_getuint16(&target);
2239 if (namelen > sizeof(namebuf)) {
2240 result = ISC_R_RANGE;
2241 goto cleanup;
2244 result = read_and_check(sequential_read, &target, namelen,
2245 lctx->f);
2246 if (result != ISC_R_SUCCESS)
2247 goto cleanup;
2248 isc_buffer_setactive(&target, (unsigned int)namelen);
2249 isc_buffer_activeregion(&target, &r);
2250 dns_name_init(&name, NULL);
2251 dns_name_fromregion(&name, &r);
2252 isc_buffer_forward(&target, (unsigned int)namelen);
2253 consumed_name = isc_buffer_consumedlength(&target);
2255 /* Rdata contents. */
2256 if (rdcount > rdata_size) {
2257 dns_rdata_t *new_rdata = NULL;
2259 new_rdata = grow_rdata(rdata_size + RDSZ, rdata,
2260 rdata_size, &head,
2261 &dummy, mctx);
2262 if (new_rdata == NULL) {
2263 result = ISC_R_NOMEMORY;
2264 goto cleanup;
2266 rdata_size += RDSZ;
2267 rdata = new_rdata;
2270 continue_read:
2271 for (i = 0; i < rdcount; i++) {
2272 isc_uint16_t rdlen;
2274 dns_rdata_init(&rdata[i]);
2276 if (sequential_read &&
2277 isc_buffer_availablelength(&target) < MINTSIZ) {
2278 unsigned int j;
2280 INSIST(i > 0); /* detect an infinite loop */
2282 /* Partial Commit. */
2283 ISC_LIST_APPEND(head, &rdatalist, link);
2284 result = commit(callbacks, lctx, &head, &name,
2285 NULL, 0);
2286 for (j = 0; j < i; j++) {
2287 ISC_LIST_UNLINK(rdatalist.rdata,
2288 &rdata[j], link);
2289 dns_rdata_reset(&rdata[j]);
2291 if (result != ISC_R_SUCCESS)
2292 goto cleanup;
2294 /* Rewind the buffer and continue */
2295 isc_buffer_clear(&target);
2296 isc_buffer_add(&target, consumed_name);
2297 isc_buffer_forward(&target, consumed_name);
2299 rdcount -= i;
2300 i = 0;
2302 goto continue_read;
2305 /* rdata length */
2306 result = read_and_check(sequential_read, &target,
2307 sizeof(rdlen), lctx->f);
2308 if (result != ISC_R_SUCCESS)
2309 goto cleanup;
2310 rdlen = isc_buffer_getuint16(&target);
2312 /* rdata */
2313 result = read_and_check(sequential_read, &target,
2314 rdlen, lctx->f);
2315 if (result != ISC_R_SUCCESS)
2316 goto cleanup;
2317 isc_buffer_setactive(&target, (unsigned int)rdlen);
2318 isc_buffer_activeregion(&target, &r);
2319 isc_buffer_forward(&target, (unsigned int)rdlen);
2320 dns_rdata_fromregion(&rdata[i], rdatalist.rdclass,
2321 rdatalist.type, &r);
2323 ISC_LIST_APPEND(rdatalist.rdata, &rdata[i], link);
2327 * Sanity check. Still having remaining space is not
2328 * necessarily critical, but it very likely indicates broken
2329 * or malformed data.
2331 if (isc_buffer_remaininglength(&target) != 0) {
2332 result = ISC_R_RANGE;
2333 goto cleanup;
2336 ISC_LIST_APPEND(head, &rdatalist, link);
2338 /* Commit this RRset. rdatalist will be unlinked. */
2339 result = commit(callbacks, lctx, &head, &name, NULL, 0);
2341 for (i = 0; i < rdcount; i++) {
2342 ISC_LIST_UNLINK(rdatalist.rdata, &rdata[i], link);
2343 dns_rdata_reset(&rdata[i]);
2346 if (result != ISC_R_SUCCESS)
2347 goto cleanup;
2350 if (!done) {
2351 INSIST(lctx->done != NULL && lctx->task != NULL);
2352 result = DNS_R_CONTINUE;
2353 } else if (result == ISC_R_SUCCESS && lctx->result != ISC_R_SUCCESS)
2354 result = lctx->result;
2356 cleanup:
2357 if (rdata != NULL)
2358 isc_mem_put(mctx, rdata, rdata_size * sizeof(*rdata));
2359 if (target_mem != NULL)
2360 isc_mem_put(mctx, target_mem, target_size);
2361 if (result != ISC_R_SUCCESS && result != DNS_R_CONTINUE) {
2362 (*callbacks->error)(callbacks, "dns_master_load: %s",
2363 dns_result_totext(result));
2366 return (result);
2369 isc_result_t
2370 dns_master_loadfile(const char *master_file, dns_name_t *top,
2371 dns_name_t *origin,
2372 dns_rdataclass_t zclass, unsigned int options,
2373 dns_rdatacallbacks_t *callbacks, isc_mem_t *mctx)
2375 return (dns_master_loadfile3(master_file, top, origin, zclass, options,
2376 0, callbacks, mctx, dns_masterformat_text));
2379 isc_result_t
2380 dns_master_loadfile2(const char *master_file, dns_name_t *top,
2381 dns_name_t *origin,
2382 dns_rdataclass_t zclass, unsigned int options,
2383 dns_rdatacallbacks_t *callbacks, isc_mem_t *mctx,
2384 dns_masterformat_t format)
2386 return (dns_master_loadfile3(master_file, top, origin, zclass, options,
2387 0, callbacks, mctx, format));
2390 isc_result_t
2391 dns_master_loadfile3(const char *master_file, dns_name_t *top,
2392 dns_name_t *origin, dns_rdataclass_t zclass,
2393 unsigned int options, isc_uint32_t resign,
2394 dns_rdatacallbacks_t *callbacks, isc_mem_t *mctx,
2395 dns_masterformat_t format)
2397 dns_loadctx_t *lctx = NULL;
2398 isc_result_t result;
2400 result = loadctx_create(format, mctx, options, resign, top, zclass,
2401 origin, callbacks, NULL, NULL, NULL, NULL,
2402 &lctx);
2403 if (result != ISC_R_SUCCESS)
2404 return (result);
2406 result = (lctx->openfile)(lctx, master_file);
2407 if (result != ISC_R_SUCCESS)
2408 goto cleanup;
2410 result = (lctx->load)(lctx);
2411 INSIST(result != DNS_R_CONTINUE);
2413 cleanup:
2414 dns_loadctx_detach(&lctx);
2415 return (result);
2418 isc_result_t
2419 dns_master_loadfileinc(const char *master_file, dns_name_t *top,
2420 dns_name_t *origin, dns_rdataclass_t zclass,
2421 unsigned int options, dns_rdatacallbacks_t *callbacks,
2422 isc_task_t *task, dns_loaddonefunc_t done,
2423 void *done_arg, dns_loadctx_t **lctxp, isc_mem_t *mctx)
2425 return (dns_master_loadfileinc3(master_file, top, origin, zclass,
2426 options, 0, callbacks, task, done,
2427 done_arg, lctxp, mctx,
2428 dns_masterformat_text));
2431 isc_result_t
2432 dns_master_loadfileinc2(const char *master_file, dns_name_t *top,
2433 dns_name_t *origin, dns_rdataclass_t zclass,
2434 unsigned int options, dns_rdatacallbacks_t *callbacks,
2435 isc_task_t *task, dns_loaddonefunc_t done,
2436 void *done_arg, dns_loadctx_t **lctxp, isc_mem_t *mctx,
2437 dns_masterformat_t format)
2439 return (dns_master_loadfileinc3(master_file, top, origin, zclass,
2440 options, 0, callbacks, task, done,
2441 done_arg, lctxp, mctx, format));
2444 isc_result_t
2445 dns_master_loadfileinc3(const char *master_file, dns_name_t *top,
2446 dns_name_t *origin, dns_rdataclass_t zclass,
2447 unsigned int options, isc_uint32_t resign,
2448 dns_rdatacallbacks_t *callbacks, isc_task_t *task,
2449 dns_loaddonefunc_t done, void *done_arg,
2450 dns_loadctx_t **lctxp, isc_mem_t *mctx,
2451 dns_masterformat_t format)
2453 dns_loadctx_t *lctx = NULL;
2454 isc_result_t result;
2456 REQUIRE(task != NULL);
2457 REQUIRE(done != NULL);
2459 result = loadctx_create(format, mctx, options, resign, top, zclass,
2460 origin, callbacks, task, done, done_arg, NULL,
2461 &lctx);
2462 if (result != ISC_R_SUCCESS)
2463 return (result);
2465 result = (lctx->openfile)(lctx, master_file);
2466 if (result != ISC_R_SUCCESS)
2467 goto cleanup;
2469 result = task_send(lctx);
2470 if (result == ISC_R_SUCCESS) {
2471 dns_loadctx_attach(lctx, lctxp);
2472 return (DNS_R_CONTINUE);
2475 cleanup:
2476 dns_loadctx_detach(&lctx);
2477 return (result);
2480 isc_result_t
2481 dns_master_loadstream(FILE *stream, dns_name_t *top, dns_name_t *origin,
2482 dns_rdataclass_t zclass, unsigned int options,
2483 dns_rdatacallbacks_t *callbacks, isc_mem_t *mctx)
2485 isc_result_t result;
2486 dns_loadctx_t *lctx = NULL;
2488 REQUIRE(stream != NULL);
2490 result = loadctx_create(dns_masterformat_text, mctx, options, 0, top,
2491 zclass, origin, callbacks, NULL, NULL, NULL,
2492 NULL, &lctx);
2493 if (result != ISC_R_SUCCESS)
2494 goto cleanup;
2496 result = isc_lex_openstream(lctx->lex, stream);
2497 if (result != ISC_R_SUCCESS)
2498 goto cleanup;
2500 result = (lctx->load)(lctx);
2501 INSIST(result != DNS_R_CONTINUE);
2503 cleanup:
2504 if (lctx != NULL)
2505 dns_loadctx_detach(&lctx);
2506 return (result);
2509 isc_result_t
2510 dns_master_loadstreaminc(FILE *stream, dns_name_t *top, dns_name_t *origin,
2511 dns_rdataclass_t zclass, unsigned int options,
2512 dns_rdatacallbacks_t *callbacks, isc_task_t *task,
2513 dns_loaddonefunc_t done, void *done_arg,
2514 dns_loadctx_t **lctxp, isc_mem_t *mctx)
2516 isc_result_t result;
2517 dns_loadctx_t *lctx = NULL;
2519 REQUIRE(stream != NULL);
2520 REQUIRE(task != NULL);
2521 REQUIRE(done != NULL);
2523 result = loadctx_create(dns_masterformat_text, mctx, options, 0, top,
2524 zclass, origin, callbacks, task, done,
2525 done_arg, NULL, &lctx);
2526 if (result != ISC_R_SUCCESS)
2527 goto cleanup;
2529 result = isc_lex_openstream(lctx->lex, stream);
2530 if (result != ISC_R_SUCCESS)
2531 goto cleanup;
2533 result = task_send(lctx);
2534 if (result == ISC_R_SUCCESS) {
2535 dns_loadctx_attach(lctx, lctxp);
2536 return (DNS_R_CONTINUE);
2539 cleanup:
2540 if (lctx != NULL)
2541 dns_loadctx_detach(&lctx);
2542 return (result);
2545 isc_result_t
2546 dns_master_loadbuffer(isc_buffer_t *buffer, dns_name_t *top,
2547 dns_name_t *origin, dns_rdataclass_t zclass,
2548 unsigned int options,
2549 dns_rdatacallbacks_t *callbacks, isc_mem_t *mctx)
2551 isc_result_t result;
2552 dns_loadctx_t *lctx = NULL;
2554 REQUIRE(buffer != NULL);
2556 result = loadctx_create(dns_masterformat_text, mctx, options, 0, top,
2557 zclass, origin, callbacks, NULL, NULL, NULL,
2558 NULL, &lctx);
2559 if (result != ISC_R_SUCCESS)
2560 return (result);
2562 result = isc_lex_openbuffer(lctx->lex, buffer);
2563 if (result != ISC_R_SUCCESS)
2564 goto cleanup;
2566 result = (lctx->load)(lctx);
2567 INSIST(result != DNS_R_CONTINUE);
2569 cleanup:
2570 dns_loadctx_detach(&lctx);
2571 return (result);
2574 isc_result_t
2575 dns_master_loadbufferinc(isc_buffer_t *buffer, dns_name_t *top,
2576 dns_name_t *origin, dns_rdataclass_t zclass,
2577 unsigned int options,
2578 dns_rdatacallbacks_t *callbacks, isc_task_t *task,
2579 dns_loaddonefunc_t done, void *done_arg,
2580 dns_loadctx_t **lctxp, isc_mem_t *mctx)
2582 isc_result_t result;
2583 dns_loadctx_t *lctx = NULL;
2585 REQUIRE(buffer != NULL);
2586 REQUIRE(task != NULL);
2587 REQUIRE(done != NULL);
2589 result = loadctx_create(dns_masterformat_text, mctx, options, 0, top,
2590 zclass, origin, callbacks, task, done,
2591 done_arg, NULL, &lctx);
2592 if (result != ISC_R_SUCCESS)
2593 return (result);
2595 result = isc_lex_openbuffer(lctx->lex, buffer);
2596 if (result != ISC_R_SUCCESS)
2597 goto cleanup;
2599 result = task_send(lctx);
2600 if (result == ISC_R_SUCCESS) {
2601 dns_loadctx_attach(lctx, lctxp);
2602 return (DNS_R_CONTINUE);
2605 cleanup:
2606 dns_loadctx_detach(&lctx);
2607 return (result);
2610 isc_result_t
2611 dns_master_loadlexer(isc_lex_t *lex, dns_name_t *top,
2612 dns_name_t *origin, dns_rdataclass_t zclass,
2613 unsigned int options,
2614 dns_rdatacallbacks_t *callbacks, isc_mem_t *mctx)
2616 isc_result_t result;
2617 dns_loadctx_t *lctx = NULL;
2619 REQUIRE(lex != NULL);
2621 result = loadctx_create(dns_masterformat_text, mctx, options, 0, top,
2622 zclass, origin, callbacks, NULL, NULL, NULL,
2623 lex, &lctx);
2624 if (result != ISC_R_SUCCESS)
2625 return (result);
2627 result = (lctx->load)(lctx);
2628 INSIST(result != DNS_R_CONTINUE);
2630 dns_loadctx_detach(&lctx);
2631 return (result);
2634 isc_result_t
2635 dns_master_loadlexerinc(isc_lex_t *lex, dns_name_t *top,
2636 dns_name_t *origin, dns_rdataclass_t zclass,
2637 unsigned int options,
2638 dns_rdatacallbacks_t *callbacks, isc_task_t *task,
2639 dns_loaddonefunc_t done, void *done_arg,
2640 dns_loadctx_t **lctxp, isc_mem_t *mctx)
2642 isc_result_t result;
2643 dns_loadctx_t *lctx = NULL;
2645 REQUIRE(lex != NULL);
2646 REQUIRE(task != NULL);
2647 REQUIRE(done != NULL);
2649 result = loadctx_create(dns_masterformat_text, mctx, options, 0, top,
2650 zclass, origin, callbacks, task, done,
2651 done_arg, lex, &lctx);
2652 if (result != ISC_R_SUCCESS)
2653 return (result);
2655 result = task_send(lctx);
2656 if (result == ISC_R_SUCCESS) {
2657 dns_loadctx_attach(lctx, lctxp);
2658 return (DNS_R_CONTINUE);
2661 dns_loadctx_detach(&lctx);
2662 return (result);
2666 * Grow the slab of dns_rdatalist_t structures.
2667 * Re-link glue and current list.
2669 static dns_rdatalist_t *
2670 grow_rdatalist(int new_len, dns_rdatalist_t *old, int old_len,
2671 rdatalist_head_t *current, rdatalist_head_t *glue,
2672 isc_mem_t *mctx)
2674 dns_rdatalist_t *new;
2675 int rdlcount = 0;
2676 ISC_LIST(dns_rdatalist_t) save;
2677 dns_rdatalist_t *this;
2679 new = isc_mem_get(mctx, new_len * sizeof(*new));
2680 if (new == NULL)
2681 return (NULL);
2683 ISC_LIST_INIT(save);
2684 this = ISC_LIST_HEAD(*current);
2685 while ((this = ISC_LIST_HEAD(*current)) != NULL) {
2686 ISC_LIST_UNLINK(*current, this, link);
2687 ISC_LIST_APPEND(save, this, link);
2689 while ((this = ISC_LIST_HEAD(save)) != NULL) {
2690 ISC_LIST_UNLINK(save, this, link);
2691 new[rdlcount] = *this;
2692 ISC_LIST_APPEND(*current, &new[rdlcount], link);
2693 rdlcount++;
2696 ISC_LIST_INIT(save);
2697 this = ISC_LIST_HEAD(*glue);
2698 while ((this = ISC_LIST_HEAD(*glue)) != NULL) {
2699 ISC_LIST_UNLINK(*glue, this, link);
2700 ISC_LIST_APPEND(save, this, link);
2702 while ((this = ISC_LIST_HEAD(save)) != NULL) {
2703 ISC_LIST_UNLINK(save, this, link);
2704 new[rdlcount] = *this;
2705 ISC_LIST_APPEND(*glue, &new[rdlcount], link);
2706 rdlcount++;
2709 INSIST(rdlcount == old_len);
2710 if (old != NULL)
2711 isc_mem_put(mctx, old, old_len * sizeof(*old));
2712 return (new);
2716 * Grow the slab of rdata structs.
2717 * Re-link the current and glue chains.
2719 static dns_rdata_t *
2720 grow_rdata(int new_len, dns_rdata_t *old, int old_len,
2721 rdatalist_head_t *current, rdatalist_head_t *glue,
2722 isc_mem_t *mctx)
2724 dns_rdata_t *new;
2725 int rdcount = 0;
2726 ISC_LIST(dns_rdata_t) save;
2727 dns_rdatalist_t *this;
2728 dns_rdata_t *rdata;
2730 new = isc_mem_get(mctx, new_len * sizeof(*new));
2731 if (new == NULL)
2732 return (NULL);
2733 memset(new, 0, new_len * sizeof(*new));
2736 * Copy current relinking.
2738 this = ISC_LIST_HEAD(*current);
2739 while (this != NULL) {
2740 ISC_LIST_INIT(save);
2741 while ((rdata = ISC_LIST_HEAD(this->rdata)) != NULL) {
2742 ISC_LIST_UNLINK(this->rdata, rdata, link);
2743 ISC_LIST_APPEND(save, rdata, link);
2745 while ((rdata = ISC_LIST_HEAD(save)) != NULL) {
2746 ISC_LIST_UNLINK(save, rdata, link);
2747 new[rdcount] = *rdata;
2748 ISC_LIST_APPEND(this->rdata, &new[rdcount], link);
2749 rdcount++;
2751 this = ISC_LIST_NEXT(this, link);
2755 * Copy glue relinking.
2757 this = ISC_LIST_HEAD(*glue);
2758 while (this != NULL) {
2759 ISC_LIST_INIT(save);
2760 while ((rdata = ISC_LIST_HEAD(this->rdata)) != NULL) {
2761 ISC_LIST_UNLINK(this->rdata, rdata, link);
2762 ISC_LIST_APPEND(save, rdata, link);
2764 while ((rdata = ISC_LIST_HEAD(save)) != NULL) {
2765 ISC_LIST_UNLINK(save, rdata, link);
2766 new[rdcount] = *rdata;
2767 ISC_LIST_APPEND(this->rdata, &new[rdcount], link);
2768 rdcount++;
2770 this = ISC_LIST_NEXT(this, link);
2772 INSIST(rdcount == old_len);
2773 if (old != NULL)
2774 isc_mem_put(mctx, old, old_len * sizeof(*old));
2775 return (new);
2778 static isc_uint32_t
2779 resign_fromlist(dns_rdatalist_t *this, isc_uint32_t resign) {
2780 dns_rdata_t *rdata;
2781 dns_rdata_rrsig_t sig;
2782 isc_uint32_t when;
2784 rdata = ISC_LIST_HEAD(this->rdata);
2785 INSIST(rdata != NULL);
2786 (void)dns_rdata_tostruct(rdata, &sig, NULL);
2787 when = sig.timeexpire - resign;
2789 rdata = ISC_LIST_NEXT(rdata, link);
2790 while (rdata != NULL) {
2791 (void)dns_rdata_tostruct(rdata, &sig, NULL);
2792 if (sig.timeexpire - resign < when)
2793 when = sig.timeexpire - resign;
2794 rdata = ISC_LIST_NEXT(rdata, link);
2796 return (when);
2800 * Convert each element from a rdatalist_t to rdataset then call commit.
2801 * Unlink each element as we go.
2804 static isc_result_t
2805 commit(dns_rdatacallbacks_t *callbacks, dns_loadctx_t *lctx,
2806 rdatalist_head_t *head, dns_name_t *owner,
2807 const char *source, unsigned int line)
2809 dns_rdatalist_t *this;
2810 dns_rdataset_t dataset;
2811 isc_result_t result;
2812 char namebuf[DNS_NAME_FORMATSIZE];
2813 void (*error)(struct dns_rdatacallbacks *, const char *, ...);
2815 this = ISC_LIST_HEAD(*head);
2816 error = callbacks->error;
2818 if (this == NULL)
2819 return (ISC_R_SUCCESS);
2820 do {
2821 dns_rdataset_init(&dataset);
2822 RUNTIME_CHECK(dns_rdatalist_tordataset(this, &dataset)
2823 == ISC_R_SUCCESS);
2824 dataset.trust = dns_trust_ultimate;
2826 * If this is a secure dynamic zone set the re-signing time.
2828 if (dataset.type == dns_rdatatype_rrsig &&
2829 (lctx->options & DNS_MASTER_RESIGN) != 0) {
2830 dataset.attributes |= DNS_RDATASETATTR_RESIGN;
2831 dns_name_format(owner, namebuf, sizeof(namebuf));
2832 dataset.resign = resign_fromlist(this, lctx->resign);
2834 result = ((*callbacks->add)(callbacks->add_private, owner,
2835 &dataset));
2836 if (result == ISC_R_NOMEMORY) {
2837 (*error)(callbacks, "dns_master_load: %s",
2838 dns_result_totext(result));
2839 } else if (result != ISC_R_SUCCESS) {
2840 dns_name_format(owner, namebuf, sizeof(namebuf));
2841 if (source != NULL) {
2842 (*error)(callbacks, "%s: %s:%lu: %s: %s",
2843 "dns_master_load", source, line,
2844 namebuf, dns_result_totext(result));
2845 } else {
2846 (*error)(callbacks, "%s: %s: %s",
2847 "dns_master_load", namebuf,
2848 dns_result_totext(result));
2851 if (MANYERRS(lctx, result))
2852 SETRESULT(lctx, result);
2853 else if (result != ISC_R_SUCCESS)
2854 return (result);
2855 ISC_LIST_UNLINK(*head, this, link);
2856 this = ISC_LIST_HEAD(*head);
2857 } while (this != NULL);
2858 return (ISC_R_SUCCESS);
2862 * Returns ISC_TRUE if one of the NS rdata's contains 'owner'.
2865 static isc_boolean_t
2866 is_glue(rdatalist_head_t *head, dns_name_t *owner) {
2867 dns_rdatalist_t *this;
2868 dns_rdata_t *rdata;
2869 isc_region_t region;
2870 dns_name_t name;
2873 * Find NS rrset.
2875 this = ISC_LIST_HEAD(*head);
2876 while (this != NULL) {
2877 if (this->type == dns_rdatatype_ns)
2878 break;
2879 this = ISC_LIST_NEXT(this, link);
2881 if (this == NULL)
2882 return (ISC_FALSE);
2884 rdata = ISC_LIST_HEAD(this->rdata);
2885 while (rdata != NULL) {
2886 dns_name_init(&name, NULL);
2887 dns_rdata_toregion(rdata, &region);
2888 dns_name_fromregion(&name, &region);
2889 if (dns_name_compare(&name, owner) == 0)
2890 return (ISC_TRUE);
2891 rdata = ISC_LIST_NEXT(rdata, link);
2893 return (ISC_FALSE);
2896 static void
2897 load_quantum(isc_task_t *task, isc_event_t *event) {
2898 isc_result_t result;
2899 dns_loadctx_t *lctx;
2901 REQUIRE(event != NULL);
2902 lctx = event->ev_arg;
2903 REQUIRE(DNS_LCTX_VALID(lctx));
2905 if (lctx->canceled)
2906 result = ISC_R_CANCELED;
2907 else
2908 result = (lctx->load)(lctx);
2909 if (result == DNS_R_CONTINUE) {
2910 event->ev_arg = lctx;
2911 isc_task_send(task, &event);
2912 } else {
2913 (lctx->done)(lctx->done_arg, result);
2914 isc_event_free(&event);
2915 dns_loadctx_detach(&lctx);
2919 static isc_result_t
2920 task_send(dns_loadctx_t *lctx) {
2921 isc_event_t *event;
2923 event = isc_event_allocate(lctx->mctx, NULL,
2924 DNS_EVENT_MASTERQUANTUM,
2925 load_quantum, lctx, sizeof(*event));
2926 if (event == NULL)
2927 return (ISC_R_NOMEMORY);
2928 isc_task_send(lctx->task, &event);
2929 return (ISC_R_SUCCESS);
2932 void
2933 dns_loadctx_cancel(dns_loadctx_t *lctx) {
2934 REQUIRE(DNS_LCTX_VALID(lctx));
2936 LOCK(&lctx->lock);
2937 lctx->canceled = ISC_TRUE;
2938 UNLOCK(&lctx->lock);