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