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