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