1 /*------------------------------------------------------------------------------
2 *
3 * Copyright (c) 2011-2021, EURid vzw. All rights reserved.
4 * The YADIFA TM software product is provided under the BSD 3-clause license:
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 * * Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * * Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * * Neither the name of EURid nor the names of its contributors may be
16 * used to endorse or promote products derived from this software
17 * without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
23 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
30 *
31 *------------------------------------------------------------------------------
32 *
33 */
34
35 /** @defgroup dnsdbzone Zone related functions
36 * @ingroup dnsdb
37 * @brief Functions used to manipulate a zone
38 *
39 * Functions used to manipulate a zone
40 *
41 * @{
42 */
43
44 #include "dnsdb/dnsdb-config.h"
45 #include <dnscore/format.h>
46 #include <dnscore/logger.h>
47 #include <dnscore/dnsname.h>
48 #include <dnscore/bytearray_output_stream.h>
49 #include <dnsdb/rrsig.h>
50 #include <dnscore/rfc.h>
51 #include <dnsdb/nsec3.h>
52
53 #if ZDB_HAS_DNSSEC_SUPPORT
54 #include <dnscore/dnskey.h>
55 #endif
56
57 #include "dnsdb/zdb_zone.h"
58 #include "dnsdb/zdb_zone_label.h"
59 #include "dnsdb/zdb_rr_label.h"
60 #include "dnsdb/zdb_record.h"
61 #include "dnsdb/zdb_icmtl.h"
62 #include "dnsdb/zdb_sanitize.h"
63 #include "dnsdb/zdb_utils.h"
64 #include "dnsdb/zdb_zone_write.h"
65 #include "dnsdb/zdb_zone_label_iterator.h"
66 #include "dnsdb/zdb-zone-find.h"
67
68 #if ZDB_HAS_DNSSEC_SUPPORT
69 #include "dnsdb/dnssec-keystore.h"
70 #include "dnsdb/dnssec.h"
71 #endif
72
73 #if ZDB_HAS_NSEC3_SUPPORT
74 #include "dnsdb/nsec3.h"
75 #endif
76
77 #if ZDB_HAS_NSEC_SUPPORT
78 #include "dnsdb/nsec.h"
79 #endif
80
81 #include "dnsdb/zdb_zone_load.h"
82
83 extern logger_handle *g_database_logger;
84 #define MODULE_MSG_HANDLE g_database_logger
85
86 void
zdb_zone_load_parms_init(struct zdb_zone_load_parms * parms,zone_reader * zr,const u8 * expected_origin,u16 flags)87 zdb_zone_load_parms_init(struct zdb_zone_load_parms *parms, zone_reader *zr, const u8 *expected_origin, u16 flags)
88 {
89 ZEROMEMORY(parms, sizeof(struct zdb_zone_load_parms));
90 parms->zr = zr;
91 parms->expected_origin = expected_origin;
92 parms->dnskey_state = U32_SET_EMPTY;
93 parms->out_zone = NULL;
94 parms->flags = flags;
95 parms->state = 0;
96 }
97
98 zdb_zone *
zdb_zone_load_parms_zone_detach(struct zdb_zone_load_parms * parms)99 zdb_zone_load_parms_zone_detach(struct zdb_zone_load_parms *parms)
100 {
101 zdb_zone *zone;
102 zone = parms->out_zone;
103 parms->out_zone = NULL;
104 return zone;
105 }
106
107 zdb_zone *
zdb_zone_load_parms_zone_get(struct zdb_zone_load_parms * parms)108 zdb_zone_load_parms_zone_get(struct zdb_zone_load_parms *parms)
109 {
110 return parms->out_zone;
111 }
112
113 ya_result
zdb_zone_load_parms_result_code(struct zdb_zone_load_parms * parms)114 zdb_zone_load_parms_result_code(struct zdb_zone_load_parms *parms)
115 {
116 return parms->result_code;
117 }
118
119 static void
zdb_zone_load_parms_finalize_dnskey_state_cb(u32_node * node)120 zdb_zone_load_parms_finalize_dnskey_state_cb(u32_node *node)
121 {
122 struct zdb_zone_load_dnskey_state_for_key *state = (struct zdb_zone_load_dnskey_state_for_key*)node->value;
123 #if DEBUG
124 union zdb_zone_load_dnskey_id id;
125 id.id = node->key;
126 log_debug("destroying key state: tag=%i alg=%i sig: count=%i from=%T until=%T flags=%x", ntohs(id.fields.tag), id.fields.algorithm, state->rrsig_count, state->signed_from, state->signed_until, state->flags);
127 #endif
128 ZFREE_OBJECT(state);
129 }
130
131 void
zdb_zone_load_parms_finalize(struct zdb_zone_load_parms * parms)132 zdb_zone_load_parms_finalize(struct zdb_zone_load_parms *parms)
133 {
134 if((parms->state & ZDB_ZONE_LOAD_STATE_SANITIZE_FIELD_AVAIABLE) != 0)
135 {
136 zdb_sanitize_parms_finalize(&parms->sanitize_parms);
137 parms->state &= ~ZDB_ZONE_LOAD_STATE_SANITIZE_FIELD_AVAIABLE;
138 }
139
140 if(parms->dnskey_state != NULL)
141 {
142 // destroy the collection
143 u32_set_callback_and_destroy(&parms->dnskey_state, zdb_zone_load_parms_finalize_dnskey_state_cb);
144 }
145
146 if(parms->out_zone != NULL)
147 {
148 // releases the zone
149 zdb_zone_release(parms->out_zone);
150 parms->out_zone = NULL;
151 }
152 }
153
154 struct zdb_zone_load_dnskey_state_for_key*
zdb_zone_load_parms_dnskey_state(struct zdb_zone_load_parms * parms,union zdb_zone_load_dnskey_id id)155 zdb_zone_load_parms_dnskey_state(struct zdb_zone_load_parms *parms, union zdb_zone_load_dnskey_id id)
156 {
157 u32_node *node = u32_set_insert(&parms->dnskey_state, id.id);
158 struct zdb_zone_load_dnskey_state_for_key *state;
159
160 if(node->value == NULL)
161 {
162 // new instance
163 ZALLOC_OBJECT_OR_DIE(state, struct zdb_zone_load_dnskey_state_for_key, ZZLDSKEY_TAG);
164 state->signed_from = MAX_U32;
165 state->signed_until = 0;
166 state->rrsig_count = 0;
167 state->key_flags = 0;
168 state->flags = 0;
169 node->value = state;
170 }
171 else
172 {
173 state = (struct zdb_zone_load_dnskey_state_for_key*)node->value;
174 }
175
176 return state;
177 }
178
179 void
zdb_zone_load_parms_dnskey_add(struct zdb_zone_load_parms * parms,const u8 * dnskey_rdata,u16 dnskey_rdata_size)180 zdb_zone_load_parms_dnskey_add(struct zdb_zone_load_parms *parms, const u8 *dnskey_rdata, u16 dnskey_rdata_size)
181 {
182 if(dnskey_rdata_size < 4)
183 {
184 return;
185 }
186
187 u16 tag = dnskey_get_tag_from_rdata(dnskey_rdata, dnskey_rdata_size);
188 u8 alg = dnskey_get_algorithm_from_rdata(dnskey_rdata);
189
190 // insert node
191
192 union zdb_zone_load_dnskey_id id;
193 id.fields.tag = tag;
194 id.fields.algorithm = alg;
195 id.fields.must_be_zero = 0;
196
197 struct zdb_zone_load_dnskey_state_for_key *state = zdb_zone_load_parms_dnskey_state(parms, id);
198 state->flags |= ZDB_ZONE_LOAD_DNSKEY_STATE_FLAG_HAS_PUBKEY;
199 state->key_flags = dnskey_get_flags_from_rdata(dnskey_rdata);
200 }
201
202 u16
zdb_zone_load_parms_get_key_flags_from_rrsig_rdata(struct zdb_zone_load_parms * parms,const u8 * rrsig_rdata,u16 rrsig_rdata_size)203 zdb_zone_load_parms_get_key_flags_from_rrsig_rdata(struct zdb_zone_load_parms *parms, const u8 *rrsig_rdata, u16 rrsig_rdata_size)
204 {
205 u16 tag = rrsig_get_key_tag_from_rdata(rrsig_rdata, rrsig_rdata_size);
206 u8 alg = rrsig_get_algorithm_from_rdata(rrsig_rdata, rrsig_rdata_size);
207
208 union zdb_zone_load_dnskey_id id;
209 id.fields.tag = tag;
210 id.fields.algorithm = alg;
211 id.fields.must_be_zero = 0;
212
213 struct zdb_zone_load_dnskey_state_for_key *state = zdb_zone_load_parms_dnskey_state(parms, id);
214 return state->key_flags;
215 }
216
217 void
zdb_zone_load_parms_rrsig_add(struct zdb_zone_load_parms * parms,const u8 * rrsig_rdata,u16 rrsig_rdata_size)218 zdb_zone_load_parms_rrsig_add(struct zdb_zone_load_parms *parms, const u8 *rrsig_rdata, u16 rrsig_rdata_size)
219 {
220 if(rrsig_rdata_size < RRSIG_RDATA_HEADER_LEN)
221 {
222 return;
223 }
224
225 u16 tag = rrsig_get_key_tag_from_rdata(rrsig_rdata, rrsig_rdata_size);
226 u8 alg = rrsig_get_algorithm_from_rdata(rrsig_rdata, rrsig_rdata_size);
227
228 // insert node
229
230 union zdb_zone_load_dnskey_id id;
231 id.fields.tag = tag;
232 id.fields.algorithm = alg;
233 id.fields.must_be_zero = 0;
234
235 struct zdb_zone_load_dnskey_state_for_key *state = zdb_zone_load_parms_dnskey_state(parms, id);
236 state->flags |= ZDB_ZONE_LOAD_DNSKEY_STATE_FLAG_HAS_PUBKEY;
237
238 s64 valid_until = rrsig_get_valid_until_from_rdata(rrsig_rdata, rrsig_rdata_size);
239 s64 valid_from = rrsig_get_valid_from_from_rdata(rrsig_rdata, rrsig_rdata_size);
240
241 if(state->signed_until < valid_until)
242 {
243 state->signed_until = valid_until;
244 }
245
246 if(state->signed_from > valid_from)
247 {
248 state->signed_from = valid_from;
249 }
250
251 ++state->rrsig_count;
252 }
253
254 ya_result
zdb_zone_load_ex(struct zdb_zone_load_parms * parms)255 zdb_zone_load_ex(struct zdb_zone_load_parms *parms)
256 {
257 u64 wire_size = 0;
258 u8* rdata;
259 size_t rdata_len;
260 ya_result return_code;
261 resource_record entry;
262 s32 soa_min_ttl = 0;
263 u32 soa_serial = 0;
264 u32 earliest_signature_expiration = MAX_S32;
265 #if ZDB_HAS_DNSSEC_SUPPORT
266 #if ZDB_HAS_NSEC3_SUPPORT
267 u32 has_optout = 0;
268 u32 has_optin = 0;
269 #endif
270 bool nsec3_keys = FALSE;
271 bool nsec_keys = FALSE;
272 bool has_dnskey = FALSE;
273 #endif
274 bool has_nsec3 = FALSE;
275 bool has_nsec = FALSE;
276 bool has_rrsig = FALSE;
277 bool dynupdate_forbidden = FALSE;
278 //bool modified = FALSE;
279
280 #if ZDB_HAS_NSEC3_SUPPORT
281 nsec3_load_context nsec3_context;
282 #endif
283
284 char origin_ascii[MAX_DOMAIN_TEXT_LENGTH + 1];
285
286 if((parms->zr == NULL) || (parms->out_zone != NULL))
287 {
288 parms->result_code = INVALID_ARGUMENT_ERROR;
289 return INVALID_ARGUMENT_ERROR; // reader must be set, out_zone must be NULL
290 }
291
292 /* ------------------------------------------------------------ */
293
294 zone_reader *zr = parms->zr;
295 const u8 *expected_origin = parms->expected_origin;
296 const u16 flags = parms->flags;
297
298 resource_record_init(&entry);
299
300 if(FAIL(return_code = zone_reader_read_record(zr, &entry)))
301 {
302 resource_record_freecontent(&entry); /* destroys */
303
304 const char *message = zone_reader_get_last_error_message(zr);
305
306 if(expected_origin != NULL)
307 {
308 if(message == NULL)
309 {
310 log_err("zone load: %{dnsname}: reading zone: %r", expected_origin, return_code);
311 }
312 else
313 {
314 log_err("zone load: %{dnsname}: reading zone: %s: %r", expected_origin, message, return_code);
315 }
316 }
317 else
318 {
319 if(message == NULL)
320 {
321 log_err("zone load: reading zone: %r", return_code);
322 }
323 else
324 {
325 log_err("zone load: reading zone: %s: %r", message, return_code);
326 }
327 }
328
329 parms->result_code = return_code;
330
331 return return_code;
332 }
333
334 if(entry.type != TYPE_SOA)
335 {
336 /* bad */
337
338 resource_record_freecontent(&entry); /* destroys */
339
340 if(expected_origin != NULL)
341 {
342 log_err("zone load: %{dnsname}: first record expected to be an SOA, got %{dnstype} instead", expected_origin, &entry.type);
343 }
344 else
345 {
346 log_err("zone load: first record expected to be an SOA, got %{dnstype} instead", &entry.type);
347 }
348
349 parms->result_code = ZDB_READER_FIRST_RECORD_NOT_SOA;
350
351 return ZDB_READER_FIRST_RECORD_NOT_SOA;
352 }
353
354 if(expected_origin != NULL)
355 {
356 bool char_space_ok = TRUE;
357 bool matched_origin = TRUE;
358 if(!((char_space_ok = dnsname_locase_verify_charspace(entry.name)) && (matched_origin = dnsname_equals(entry.name, expected_origin))))
359 {
360 if(!char_space_ok)
361 {
362 log_err("zone load: %{dnsname}: invalid character space: %{dnsname}", expected_origin, entry.name);
363 }
364
365 if(!matched_origin)
366 {
367 log_err("zone load: %{dnsname}: found name outside of zone: %{dnsname}", expected_origin, entry.name);
368 }
369
370 resource_record_freecontent(&entry); /* destroys, actually no-operation in this version */
371
372 parms->result_code = ZDB_READER_WRONGNAMEFORZONE;
373
374 return ZDB_READER_WRONGNAMEFORZONE;
375 }
376
377 if(!matched_origin)
378 {
379 resource_record_freecontent(&entry); /* destroys */
380
381 log_err("zone load: %{dnsname}: zone file domain do not match the expected one (%{dnsname})", expected_origin, entry.name);
382
383 parms->result_code = ZDB_READER_ANOTHER_DOMAIN_WAS_EXPECTED;
384
385 return ZDB_READER_ANOTHER_DOMAIN_WAS_EXPECTED;
386 }
387 }
388 else
389 {
390 bool char_space_ok = dnsname_locase_verify_charspace(entry.name);
391
392 if(!char_space_ok)
393 {
394 log_err("zone load: invalid character space: %{dnsname}", entry.name);
395
396 resource_record_freecontent(&entry); /* destroys, actually no-operation in this version */
397
398 parms->result_code = ZDB_READER_WRONGNAMEFORZONE;
399
400 return ZDB_READER_WRONGNAMEFORZONE;
401 }
402 }
403
404 dnsname_vector name;
405 DEBUG_RESET_dnsname(name);
406 u16 zclass = entry.class;
407
408 dnsname_to_dnsname_vector(entry.name, &name);
409
410 rr_soa_get_minimumttl(zone_reader_rdata(entry), zone_reader_rdata_size(entry), &soa_min_ttl);
411 rr_soa_get_serial(zone_reader_rdata(entry), zone_reader_rdata_size(entry), &soa_serial);
412
413 dnsname_to_cstr(origin_ascii, entry.name);
414
415 dynupdate_forbidden = FALSE;
416
417 #if ZDB_HAS_DNSSEC_SUPPORT
418 has_dnskey = FALSE;
419 has_nsec3 = FALSE;
420 has_nsec = FALSE;
421 nsec3_keys = FALSE;
422 nsec_keys = FALSE;
423 #if ZDB_HAS_NSEC3_SUPPORT
424 has_optout = 0;
425 has_optin = 0;
426 #endif
427 #endif
428
429 zdb_zone* zone;
430
431 zone = zdb_zone_create(entry.name); // comes with an RC = 1, not locked
432
433 if(zone == NULL)
434 {
435 log_err("zone load: unable to load zone %{dnsname} %{dnsclass}", entry.name, &zclass);
436
437 parms->result_code = ZDB_ERROR_NOSUCHCLASS;
438
439 return ZDB_ERROR_NOSUCHCLASS;
440 }
441
442 zdb_zone_lock(zone, ZDB_ZONE_MUTEX_LOAD);
443
444 zone->min_ttl = soa_min_ttl;
445 zone->text_serial = soa_serial;
446 zone->axfr_serial = soa_serial - 1; /* ensure that the axfr on disk is not automatically taken in account later */
447
448 if((parms->flags & ZDB_ZONE_NO_MAINTENANCE) == 0)
449 {
450 switch(parms->flags & ZDB_ZONE_DNSSEC_MASK)
451 {
452 case ZDB_ZONE_NSEC:
453 zone_set_maintain_mode(zone, ZDB_ZONE_MAINTAIN_NSEC);
454 break;
455 case ZDB_ZONE_NSEC3:
456 zone_set_maintain_mode(zone, ZDB_ZONE_MAINTAIN_NSEC3);
457 break;
458 case ZDB_ZONE_NSEC3_OPTOUT:
459 zone_set_maintain_mode(zone, ZDB_ZONE_MAINTAIN_NSEC3_OPTOUT);
460 break;
461 }
462 }
463
464 dnsname_to_dnsname_vector(zone->origin, &name);
465 //dnsname_vector_copy(&name, &zone->origin_vector);
466
467 #if ZDB_HAS_NSEC3_SUPPORT
468 nsec3_load_init(&nsec3_context, zone);
469 nsec3_load_allowed_to_fix(&nsec3_context, (parms->flags & ZDB_ZONE_IS_SLAVE) == 0);
470 #endif
471
472 zdb_packed_ttlrdata* ttlrdata;
473
474 u32 loop_count;
475
476 for(loop_count = 1;; loop_count++)
477 {
478 /* Add the entry */
479
480 if(dnscore_shuttingdown())
481 {
482 return_code = STOPPED_BY_APPLICATION_SHUTDOWN;
483 break;
484 }
485
486 dnsname_vector entry_name;
487
488 DEBUG_RESET_dnsname(entry_name);
489 dnsname_to_dnsname_vector(entry.name, &entry_name);
490
491 s32 a_i, b_i;
492
493 if((a_i = name.size) > (b_i = entry_name.size))
494 {
495 // error
496
497 return_code = ZDB_READER_WRONGNAMEFORZONE;
498
499 log_err("zone load: domain name %{dnsnamevector} is too big", &entry_name);
500
501 break;
502 }
503
504 /* ZONE ENTRY CHECK */
505
506 while(a_i >= 0)
507 {
508 const u8* a = name.labels[a_i--];
509 const u8* b = entry_name.labels[b_i--];
510
511 if(!dnslabel_equals(a, b))
512 {
513 log_warn("zone load: bad domain name %{dnsnamevector} for zone %{dnsnamevector}", &entry_name, &name);
514
515 goto zdb_zone_load_loop;
516 }
517 }
518
519 if(FAIL(return_code))
520 {
521 break;
522 }
523
524 rdata_len = zone_reader_rdata_size(entry);
525 rdata = zone_reader_rdata(entry);
526
527 #if ZDB_HAS_NSEC3_SUPPORT
528
529 /*
530 * SPECIAL NSEC3 support !!!
531 *
532 * If the record is an RRSIG(NSEC3), an NSEC3, or an NSEC3PARAM then
533 * it cannot be handled the same way as the others.
534 *
535 */
536
537 if(entry.type == TYPE_NSEC3PARAM)
538 {
539 if(FAIL(return_code = nsec3_load_add_nsec3param(&nsec3_context, rdata, rdata_len)))
540 {
541 break;
542 }
543
544 ZDB_RECORD_ZALLOC(ttlrdata, /*entry.ttl*/0, rdata_len, rdata);
545 zdb_zone_record_add(zone, entry_name.labels, entry_name.size, entry.type, ttlrdata); // verified
546
547 // has_nsec3 ?
548 }
549 else if(entry.type == TYPE_NSEC3CHAINSTATE)
550 {
551 if(FAIL(nsec3_load_add_nsec3chainstate(&nsec3_context, rdata, rdata_len)))
552 {
553 break;
554 }
555 ZDB_RECORD_ZALLOC(ttlrdata, /*entry.ttl*/0, rdata_len, rdata);
556 zdb_zone_record_add(zone, entry_name.labels, entry_name.size, entry.type, ttlrdata); // verified
557 }
558 else if(entry.type == TYPE_NSEC3)
559 {
560 bool rdata_optout = NSEC3_RDATA_IS_OPTOUT(rdata);
561
562 if(rdata_optout)
563 {
564 has_optout++;
565 }
566 else
567 {
568 has_optin++;
569 }
570
571 if(FAIL(return_code = nsec3_load_add_nsec3(&nsec3_context, entry.name, entry.ttl, rdata, rdata_len)))
572 {
573 break;
574 }
575
576 has_nsec3 = TRUE;
577 }
578 else if(entry.type == TYPE_RRSIG && ((GET_U16_AT(*rdata)) == TYPE_NSEC3)) /** @note : NATIVETYPE */
579 {
580 if(FAIL(return_code = nsec3_load_add_rrsig(&nsec3_context, entry.name, /*entry.ttl*/soa_min_ttl, rdata, rdata_len)))
581 {
582 break;
583 }
584 }
585 else
586 {
587 #endif
588 /*
589 * This is the general case
590 * It happen with NSEC3 support if the type is neither NSEC3PARAM, NSEC3 nor RRSIG(NSEC3)
591 */
592 switch(entry.type)
593 {
594 case TYPE_DNSKEY:
595 {
596 #if ZDB_HAS_DNSSEC_SUPPORT
597 /*
598 * Check if we have access to the private part of the key
599 */
600
601 u16 tag = dnskey_get_tag_from_rdata(rdata, rdata_len);
602 u16 key_flags = GET_U16_AT(rdata[0]);
603 u8 algorithm = rdata[3];
604
605 switch(algorithm)
606 {
607 case DNSKEY_ALGORITHM_DSASHA1:
608 case DNSKEY_ALGORITHM_RSASHA1:
609 {
610 nsec_keys = TRUE;
611 break;
612 }
613 case DNSKEY_ALGORITHM_DSASHA1_NSEC3:
614 case DNSKEY_ALGORITHM_RSASHA1_NSEC3:
615 {
616 nsec3_keys = TRUE;
617 break;
618 }
619 case DNSKEY_ALGORITHM_RSASHA256_NSEC3:
620 case DNSKEY_ALGORITHM_RSASHA512_NSEC3:
621 case DNSKEY_ALGORITHM_ECDSAP256SHA256:
622 case DNSKEY_ALGORITHM_ECDSAP384SHA384:
623 case DNSKEY_ALGORITHM_ED25519:
624 case DNSKEY_ALGORITHM_ED448:
625 #ifdef DNSKEY_ALGORITHM_DUMMY
626 case DNSKEY_ALGORITHM_DUMMY:
627 #endif
628 {
629 nsec_keys = TRUE;
630 nsec3_keys = TRUE;
631 break;
632 }
633 default:
634 {
635 log_info("zone load: unknown key algorithm for K%{dnsname}+%03d+%05hd", zone->origin, algorithm, tag);
636 break;
637 }
638 }
639
640 dnssec_key *key = NULL;
641
642 if((flags & ZDB_ZONE_IS_SLAVE) == 0)
643 {
644 if(ISOK(return_code = dnssec_keystore_load_private_key_from_parameters(algorithm, tag, key_flags, zone->origin, &key))) // converted, key properly released
645 {
646 if(return_code > 0)
647 {
648 log_info("zone load: loaded private key K%{dnsname}+%03d+%05hd", zone->origin, algorithm, tag);
649 }
650
651 // we are only interested on its existence so it can be released now (the fact the pointer is not NULL is all that matters)
652 dnskey_state_enable(key, DNSKEY_KEY_IS_IN_ZONE);
653 dnskey_release(key);
654 has_dnskey = TRUE;
655 }
656 else
657 {
658 int log_level = zdb_zone_get_rrsig_push_allowed(zone)?MSG_INFO:MSG_WARNING;
659 log_to_level(log_level, "zone load: unable to load the private key K%{dnsname}+%03d+%05hd: %r", zone->origin, algorithm, tag, return_code);
660 }
661 }
662
663 if(key == NULL)
664 {
665 /*
666 * Either:
667 *
668 * _ The private key is not available (error)
669 * _ The private key should not be loaded (slave)
670 *
671 * Get the public key for signature verifications.
672 */
673
674 if(ISOK(return_code = dnssec_keystore_load_public_key_from_rdata(rdata, rdata_len, zone->origin, &key))) // converted
675 {
676 log_info("zone load: loaded public key K%{dnsname}+%03d+%05hd", zone->origin, algorithm, tag);
677 dnskey_state_enable(key, DNSKEY_KEY_IS_IN_ZONE);
678 dnskey_release(key);
679
680 has_dnskey = TRUE;
681 }
682 else
683 {
684 /* the key is wrong */
685 log_warn("zone load: unable to load public key K%{dnsname}+%03d+%05hd: %r", zone->origin, algorithm, tag, return_code);
686 }
687 }
688 #else
689 /* DNSKEY not supported */
690 #endif
691 ZDB_RECORD_ZALLOC(ttlrdata, entry.ttl, rdata_len, rdata);
692 zdb_zone_record_add(zone, entry_name.labels, entry_name.size, entry.type, ttlrdata); // class is implicit, verified
693 break;
694 }
695 #if ZDB_HAS_NSEC_SUPPORT
696 case TYPE_NSEC:
697 {
698 has_nsec = TRUE;
699 ZDB_RECORD_ZALLOC(ttlrdata, entry.ttl, rdata_len, rdata);
700 zdb_zone_record_add(zone, entry_name.labels, entry_name.size, entry.type, ttlrdata); /* class is implicit */
701 break;
702 }
703 #endif
704 case TYPE_RRSIG:
705 {
706 #if !ZDB_HAS_DNSSEC_SUPPORT
707 if(!has_rrsig)
708 {
709 log_warn("zone load: type %{dnstype} is not supported", &entry.type);
710 }
711 #else
712 has_rrsig = TRUE;
713 #endif
714 if((GET_U16_AT(*rdata)) == TYPE_NSEC3PARAM) // RRSIG covered type
715 {
716 entry.ttl = 0;
717 }
718
719 u32 rrsig_expiration = rrsig_get_valid_until_from_rdata(rdata, rdata_len);
720
721 if(rrsig_expiration < earliest_signature_expiration)
722 {
723 earliest_signature_expiration = rrsig_expiration;
724 }
725 }
726 FALLTHROUGH // fall through
727 default:
728 {
729 ZDB_RECORD_ZALLOC(ttlrdata, entry.ttl, rdata_len, rdata);
730 zdb_zone_record_add(zone, entry_name.labels, entry_name.size, entry.type, ttlrdata); // class is implicit, name parameters verified
731 break;
732 }
733 #if !ZDB_HAS_NSEC3_SUPPORT
734 case TYPE_NSEC3PARAM:
735 {
736 if(!has_nsec3param)
737 {
738 log_warn("zone load: type %{dnstype} is not supported", &entry.type);
739 }
740 has_nsec3param = TRUE;
741 break;
742 }
743 case TYPE_NSEC3:
744 {
745 if(!has_nsec3)
746 {
747 log_warn("zone load: type %{dnstype} is not supported", &entry.type);
748 }
749 has_nsec3 = TRUE;
750 break;
751 }
752 #endif
753 #if !ZDB_HAS_NSEC_SUPPORT
754 case TYPE_NSEC:
755 {
756 if(!has_nsec)
757 {
758 log_warn("zone load: type %{dnstype} is not supported", &entry.type);
759 }
760 has_nsec = TRUE;
761 break;
762 }
763 #endif
764 } // switch(entry.type)
765
766 #if ZDB_HAS_NSEC3_SUPPORT
767 } // else
768 #endif
769
770 zdb_zone_load_loop:
771
772 wire_size += resource_record_size(&entry);
773
774 resource_record_resetcontent(&entry); /* "next" */
775
776 /**
777 * Note : Return can be
778 *
779 * OK: got a record
780 * 1: end of zone file
781 * error code: failure
782 */
783
784 if(OK != (return_code = zone_reader_read_record(zr, &entry)))
785 {
786 if(FAIL(return_code))
787 {
788 if(return_code == /**/ ERROR)
789 {
790 return_code = UNEXPECTED_EOF;
791 }
792
793 const char *message = zone_reader_get_last_error_message(zr);
794
795 if(message == NULL)
796 {
797 log_err("zone load: reading record #%d of zone %{dnsname}: %r", loop_count, zone->origin, return_code);
798 }
799 else
800 {
801 log_err("zone load: reading record #%d of zone %{dnsname}: %s: %r", loop_count, zone->origin, message, return_code);
802 }
803 }
804 break;
805 }
806
807 if(!dnsname_locase_verify_charspace(entry.name))
808 {
809 log_warn("zone load: DNS character space error on '%{dnsname}'", entry.name);
810 }
811 }
812
813 resource_record_freecontent(&entry); /* destroys, not "next" */
814
815 if(ISOK(return_code))
816 {
817 zdb_sanitize_zone_rrset_flags(zone);
818 }
819
820 #if ZDB_HAS_DNSSEC_SUPPORT
821 #if ZDB_HAS_NSEC3_SUPPORT
822 if(has_nsec3 && (has_optout > 0))
823 {
824 zone->_flags |= ZDB_ZONE_HAS_OPTOUT_COVERAGE;
825 }
826 #endif
827
828 log_debug7("zone load: has_rrsig=%i has_dnskey=%i", has_rrsig, has_dnskey);
829 #endif
830
831 if(dynupdate_forbidden)
832 {
833 log_info("zone load: freezing zone %{dnsname}", zone->origin);
834 zdb_zone_set_frozen(zone);
835 }
836
837 #if ZDB_HAS_DNSSEC_SUPPORT
838
839 if(ISOK(return_code))
840 {
841 if(has_nsec && has_nsec3)
842 {
843 log_err("zone load: zone %{dnsname} has both NSEC and NSEC3 records!", zone->origin);
844
845 // return_code = ZDB_READER_MIXED_DNSSEC_VERSIONS;
846 has_nsec = FALSE;
847 }
848 if((flags & ZDB_ZONE_IS_SLAVE) == 0)
849 {
850 if(nsec_keys && nsec3_keys) // after algorithm 7, keys can be used both for NSEC and NSEC3
851 {
852 if(!(has_nsec3|has_nsec))
853 {
854 log_warn("zone load: zone %{dnsname} has DNSKEY but there is no NSEC nor NSEC3 coverage", zone->origin);
855 }
856 }
857 else if(nsec3_keys)
858 {
859 if(!has_nsec3)
860 {
861 log_warn("zone load: zone %{dnsname} has NSEC3 DNSKEY but there is no NSEC3 coverage", zone->origin);
862 }
863 }
864 else if(nsec_keys)
865 {
866 if(!has_nsec)
867 {
868 log_warn("zone load: zone %{dnsname} has NSEC DNSKEY but there is no NSEC coverage", zone->origin);
869 }
870 }
871 else
872 {
873 if(has_nsec3)
874 {
875 log_warn("zone load: zone %{dnsname} is NSEC3 but there are no NSEC3 keys available", zone->origin);
876 }
877
878 if(has_nsec)
879 {
880 log_warn("zone load: zone %{dnsname} is NSEC but there are no NSEC keys available", zone->origin);
881 }
882 }
883 }
884 }
885
886 if(ISOK(return_code))
887 {
888 if(!(has_nsec || has_nsec3))
889 {
890 switch(flags & ZDB_ZONE_DNSSEC_MASK)
891 {
892 case ZDB_ZONE_NSEC:
893 {
894 log_warn("zone load: zone is configured as NSEC but no NSEC records have been found");
895 if((flags & ZDB_ZONE_IS_SLAVE) == 0)
896 {
897 has_nsec = TRUE;
898 }
899 break;
900 }
901 case ZDB_ZONE_NSEC3:
902 case ZDB_ZONE_NSEC3_OPTOUT:
903 {
904 log_warn("zone load: zone is configured as NSEC3 but no NSEC3 records have been found");
905 if((flags & ZDB_ZONE_IS_SLAVE) == 0)
906 {
907 has_nsec3 = TRUE;
908 }
909 break;
910 }
911 default:
912 {
913 break;
914 }
915 }
916 }
917
918 if(has_nsec3)
919 {
920 if((parms->flags & ZDB_ZONE_NO_MAINTENANCE) == 0)
921 {
922 zone->_flags |= ZDB_ZONE_MAINTAIN_NSEC3;
923
924 if(has_optout > 0)
925 {
926 zone_set_maintain_mode(zone, ZDB_ZONE_MAINTAIN_NSEC3_OPTOUT);
927 }
928 else
929 {
930 zone_set_maintain_mode(zone, ZDB_ZONE_MAINTAIN_NSEC3);
931 }
932 }
933
934 zdb_rr_label_flag_or(zone->apex, ZDB_RR_LABEL_N3OCOVERED|ZDB_RR_LABEL_N3COVERED);
935
936 #if ZDB_HAS_NSEC3_SUPPORT
937 /**
938 * Check if there is both NSEC & NSEC3. Reject if yes.
939 * compile NSEC if any
940 * compile NSEC3 if any
941 *
942 * I'm only doing NSEC3 here.
943 */
944
945 if((flags & ZDB_ZONE_DNSSEC_MASK) == ZDB_ZONE_NSEC)
946 {
947 log_warn("zone load: zone %{dnsname} was set to NSEC but is NSEC3", zone->origin);
948 }
949
950 if(has_optin > 0)
951 {
952 if(has_optout > 0)
953 {
954 log_warn("zone load: zone %{dnsname} has got both OPT-OUT and OPT-IN records (%u and %u)", zone->origin, has_optout, has_optin);
955 nsec3_context.opt_out = TRUE;
956 }
957 else
958 {
959 nsec3_context.opt_out = FALSE;
960 }
961
962 if((flags & ZDB_ZONE_DNSSEC_MASK) == ZDB_ZONE_NSEC3_OPTOUT)
963 {
964 log_warn("zone load: zone %{dnsname} was set to OPT-OUT but appears to be OPT-IN", zone->origin);
965 }
966 }
967 else if(has_optout > 0)
968 {
969 /* has_optin is false and has_optout is true */
970
971 if((flags & ZDB_ZONE_DNSSEC_MASK) == ZDB_ZONE_NSEC3)
972 {
973 log_warn("zone load: zone %{dnsname} was set to OPT-IN but appears to be OPT-OUT (%u)", zone->origin, has_optout);
974 }
975
976 nsec3_context.opt_out = TRUE;
977 }
978 else /* use the configuration */
979 {
980 nsec3_context.opt_out = ((flags & ZDB_ZONE_DNSSEC_MASK) == ZDB_ZONE_NSEC3_OPTOUT)?TRUE:FALSE;
981 }
982
983 log_info("zone load: zone %{dnsname} is %s", zone->origin, (nsec3_context.opt_out)?"OPT-OUT":"OPT-IN");
984
985 /* If there is something in the NSEC3 context ... */
986
987 if(!nsec3_load_is_context_empty(&nsec3_context))
988 {
989 /* ... do it. */
990
991 log_debug("zone load: zone %{dnsname}: NSEC3 post-processing.", zone->origin);
992
993 return_code = nsec3_load_generate(&nsec3_context);
994
995 if(((flags & ZDB_ZONE_IS_SLAVE) != 0) && (nsec3_context.nsec3_rejected > 0))
996 {
997 return_code = DNSSEC_ERROR_NSEC3_INVALIDZONESTATE; // the zone is corrupted and as a slave nothing can be done about it.
998 }
999
1000 if(ISOK(return_code))
1001 {
1002 /*
1003 if(nsec3_context.opt_out)
1004 {
1005 zdb_rr_label_flag_or(zone->apex, ZDB_RR_LABEL_NSEC3 | ZDB_RR_LABEL_NSEC3_OPTOUT);
1006 }
1007 else
1008 {
1009 zdb_rr_label_flag_or(zone->apex, ZDB_RR_LABEL_NSEC3);
1010 }
1011 */
1012
1013 if(nsec3_context.fix_applied)
1014 {
1015 parms->state |= ZDB_ZONE_LOAD_STATE_SANITIZE_SUMMARY_NSEC3_CHAIN_FIXED;
1016 zdb_zone_set_status(zone, ZDB_ZONE_STATUS_MODIFIED);
1017 }
1018
1019
1020 #if HAS_RRSIG_MANAGEMENT_SUPPORT
1021 zdb_zone_set_maintained(zone, TRUE);
1022 #endif
1023
1024 log_debug("zone load: zone %{dnsname}: NSEC3 post-processing done", zone->origin);
1025 }
1026 else
1027 {
1028 log_err("zone load: zone %{dnsname}: error %r: NSEC3 post-processing failed", zone->origin, return_code);
1029 }
1030 }
1031 else
1032 {
1033 log_debug("zone load: zone %{dnsname}: NSEC3 context is empty", zone->origin);
1034 has_nsec3 = FALSE;
1035 }
1036
1037
1038
1039 #else // ZDB_HAS_NSEC3_SUPPORT is 0
1040 log_err("zone load: zone %{dnsname} has NSEC3* record(s) but the server has been compiled without NSEC support", zone->origin);
1041 #endif
1042 }
1043 else if(has_nsec)
1044 {
1045 zone->_flags |= ZDB_ZONE_MAINTAIN_NSEC;
1046
1047 if((flags & ZDB_ZONE_DNSSEC_MASK) >= ZDB_ZONE_NSEC3)
1048 {
1049 log_warn("zone load: zone %{dnsname} was set to NSEC3 but is NSEC", zone->origin);
1050 }
1051
1052 #if ZDB_HAS_NSEC_SUPPORT
1053 log_debug("zone load: zone %{dnsname}: NSEC post-processing.", zone->origin);
1054
1055 if(ISOK(return_code = nsec_update_zone(zone, (flags & ZDB_ZONE_IS_SLAVE) != 0)))
1056 {//DNSSEC_ERROR_NSEC_INVALIDZONESTATE
1057 zdb_rr_label_flag_or(zone->apex, ZDB_RR_LABEL_NSEC);
1058 zdb_rr_label_flag_and(zone->apex, ~(ZDB_RR_LABEL_NSEC3|ZDB_RR_LABEL_NSEC3_OPTOUT));
1059 #if HAS_RRSIG_MANAGEMENT_SUPPORT
1060 zdb_zone_set_maintained(zone, (flags & ZDB_ZONE_IS_SLAVE) == 0);
1061 #endif
1062 }
1063
1064 #else
1065 log_err("zone load: zone %{dnsname} has NSEC record(s) but the server has been compiled without NSEC support", zone->origin);
1066 #endif
1067 }
1068 }
1069 #endif
1070
1071 #if ZDB_HAS_NSEC3_SUPPORT
1072 nsec3_load_destroy(&nsec3_context);
1073 #endif
1074
1075 if(ISOK(return_code))
1076 {
1077 log_info("zone load: zone %{dnsname} has been loaded (%d record(s) parsed)", zone->origin, loop_count);
1078
1079 log_debug("zone load: zone %{dnsname} wire size: %i", zone->origin, wire_size);
1080 zone->wire_size = wire_size;
1081 zone->progressive_signature_update.earliest_signature_expiration = earliest_signature_expiration;
1082
1083 log_debug("zone load: zone %{dnsname} earliest signature expiration at %T in %d seconds", zone->origin, earliest_signature_expiration, (s32)(earliest_signature_expiration - time(NULL)));
1084
1085 parms->out_zone = zone;
1086
1087 #if defined(ZDB_ZONE_MOUNT_ON_LOAD)
1088 if((flags & ZDB_ZONE_MOUNT_ON_LOAD) != 0)
1089 {
1090 log_info("zone load: zone %{dnsname} has been mounted", zone->origin);
1091
1092 zdb_zone *old_zone = zdb_set_zone(db, zone);
1093 yassert(old_zone == NULL);
1094 (void)old_zone;
1095 }
1096 #endif
1097
1098 }
1099 else
1100 {
1101 log_err("zone load: zone %{dnsname}: error %r (%d record(s) parsed)", zone->origin, return_code, loop_count);
1102 }
1103
1104 if(ISOK(return_code) && ((flags & ZDB_ZONE_REPLAY_JOURNAL) != 0))
1105 {
1106 /*
1107 * The zone file has been read.
1108 * NSEC structures have been created
1109 *
1110 * At this point, the incremental journal should be replayed.
1111 *
1112 */
1113
1114 #if DEBUG
1115 log_debug("zone load: replaying changes from journal");
1116 #endif
1117 zdb_zone_unlock(zone, ZDB_ZONE_MUTEX_LOAD);
1118 return_code = zdb_icmtl_replay(zone);
1119 zdb_zone_lock(zone, ZDB_ZONE_MUTEX_LOAD);
1120
1121 if(ISOK(return_code))
1122 {
1123 if(return_code > 0)
1124 {
1125 log_info("zone load: replayed %d changes from journal", return_code);
1126 }
1127
1128 if(!has_nsec3)
1129 {
1130 if((has_nsec3 = zdb_rr_label_flag_isset(zone->apex, ZDB_RR_LABEL_NSEC3|ZDB_RR_LABEL_NSEC3_OPTOUT)))
1131 {
1132 zone->_flags |= ZDB_ZONE_MAINTAIN_NSEC3;
1133 if((zone->apex->nsec.nsec3 != NULL) && (has_optout = zone->apex->nsec.nsec3->_self != NULL))
1134 {
1135 has_optout = (zone->apex->nsec.nsec3->_self->flags != 0);
1136 }
1137 }
1138 }
1139
1140 if(has_nsec3 && (has_optout > 0))
1141 {
1142 zone->_flags |= ZDB_ZONE_HAS_OPTOUT_COVERAGE;
1143
1144 }
1145
1146 if(parms->state & ZDB_ZONE_LOAD_STATE_SANITIZE_SUMMARY_NSEC3_CHAIN_FIXED)
1147 {
1148 // the zone must look new to the slaves
1149 // increment serial
1150 // sign serial
1151 // delete journal before mount
1152
1153 zdb_packed_ttlrdata *soa_rr = zdb_record_find(&zone->apex->resource_record_set, TYPE_SOA);
1154 yassert(soa_rr != NULL);
1155 rr_soa_increase_serial(ZDB_PACKEDRECORD_PTR_RDATAPTR(soa_rr), ZDB_PACKEDRECORD_PTR_RDATASIZE(soa_rr), 1);
1156 rrsig_delete_covering(zone->apex, TYPE_SOA);
1157
1158 zdb_zone_set_status(zone, ZDB_ZONE_STATUS_MODIFIED);
1159 }
1160
1161 if((flags & ZDB_ZONE_IS_SLAVE) == 0)
1162 {
1163 //#if DEBUG
1164 log_info("zone load: post-replay sanity check for %{dnsname}", zone->origin);
1165 //#endif
1166 if(ISOK(return_code = zdb_sanitize_zone_ex(zone, parms)))
1167 {
1168 log_info("zone load: post-replay sanity check for %{dnsname} done", zone->origin);
1169 }
1170 else
1171 {
1172 log_err("zone load: impossible to sanitise %{dnsname}, dropping zone", zone->origin);
1173 }
1174
1175 log_debug("zone load: post-replay sanity check for %{dnsname} done", zone->origin);
1176 }
1177 else
1178 {
1179 log_debug("zone load: no post-replay sanity check for %{dnsname} slave", zone->origin);
1180 }
1181
1182 if(has_nsec3)
1183 {
1184 // the chain has just been created, but is probably missing internal links
1185 log_debug("journal: %{dnsname}: no journal, updating links", zone->origin);
1186
1187 nsec3_zone_update_chain0_links(zone);
1188 }
1189 }
1190 else if(return_code == ZDB_ERROR_ICMTL_NOTFOUND)
1191 {
1192 if((flags & ZDB_ZONE_IS_SLAVE) == 0)
1193 {
1194 log_debug("zone load: post-replay sanity check for %{dnsname}", zone->origin);
1195
1196 if(ISOK(return_code = zdb_sanitize_zone_ex(zone, parms)))
1197 {
1198 log_info("zone load: post-replay sanity check for %{dnsname} done", zone->origin);
1199
1200 if(has_nsec3)
1201 {
1202 // the chain has just been created, but is probably missing internal links
1203 log_debug("journal: %{dnsname}: no journal, updating links", zone->origin);
1204
1205 nsec3_zone_update_chain0_links(zone);
1206 }
1207 }
1208 else
1209 {
1210 log_err("zone load: impossible to sanitise %{dnsname}, dropping zone", zone->origin);
1211 }
1212 }
1213 else
1214 {
1215 log_debug("zone load: no post-replay sanity check for %{dnsname} slave", zone->origin);
1216 }
1217 }
1218 else
1219 {
1220 log_err("zone load: journal replay returned %r", return_code);
1221 }
1222
1223 /*
1224 * End of the incremental replay
1225 */
1226 }
1227
1228 if(zone != NULL)
1229 {
1230 zdb_zone_unlock(zone, ZDB_ZONE_MUTEX_LOAD);
1231
1232 if(FAIL(return_code))
1233 {
1234 zdb_zone_release(zone);
1235 parms->out_zone = NULL;
1236 }
1237 }
1238
1239 parms->result_code = return_code;
1240
1241 return return_code;
1242 }
1243
1244 /**
1245 * @brief Load a zone in the database.
1246 *
1247 * Load a zone in the database.
1248 *
1249 * @note It is not a good idea to scan the zone content in here. ie: getting the earliest signature expiration. (It's counter-productive and pointless)
1250 *
1251 * @param[in] db_UNUSED a pointer to the database, obsolete, can be set to NULL
1252 * @param[in] zr a pointer to an opened zone_reader
1253 * @param[in] zone_pointer_out a pointer to the pointer that will be set with the loaded zone
1254 * @param[in] expected_origin the expected origin for the loaded file, can be set to NULL
1255 * @param[in] flags various flags
1256 *
1257 * @return an error code.
1258 *
1259 */
1260
1261 ya_result
zdb_zone_load(zdb * db_UNUSED,zone_reader * zr,zdb_zone ** zone_pointer_out,const u8 * expected_origin,u16 flags)1262 zdb_zone_load(zdb *db_UNUSED, zone_reader *zr, zdb_zone **zone_pointer_out, const u8 *expected_origin, u16 flags)
1263 {
1264 (void)db_UNUSED;
1265 struct zdb_zone_load_parms parms;
1266 zdb_zone_load_parms_init(&parms, zr, expected_origin, flags);
1267 ya_result ret = zdb_zone_load_ex(&parms);
1268 if(ISOK(ret))
1269 {
1270 *zone_pointer_out = zdb_zone_load_parms_zone_detach(&parms);
1271 }
1272 else
1273 {
1274 *zone_pointer_out = NULL;
1275 }
1276 zdb_zone_load_parms_finalize(&parms);
1277 return ret;
1278 }
1279
1280 /**
1281 * @brief Load the zone SOA.
1282 *
1283 * Load the zone SOA record
1284 * This is meant mainly for the slave that could choose between, ie: zone file or axfr zone file
1285 * The SOA MUST BE the first record
1286 *
1287 * @param[in] db a pointer to the database
1288 * @param[in] zone_data a pointer to an opened zone_reader at its start
1289 * @param[out] zone_pointer_out will contains a pointer to the loaded zone if the call is successful
1290 *
1291 * @return an error code.
1292 *
1293 */
1294 ya_result
zdb_zone_get_soa(zone_reader * zone_data,u16 * rdata_size,u8 * rdata)1295 zdb_zone_get_soa(zone_reader *zone_data, u16 *rdata_size, u8 *rdata)
1296 {
1297 ya_result return_value;
1298 resource_record entry;
1299
1300 resource_record_init(&entry);
1301
1302 if(ISOK(return_value = zone_reader_read_record(zone_data, &entry)))
1303 {
1304 if(entry.type == TYPE_SOA)
1305 {
1306 s32 soa_rdata_len = zone_reader_rdata_size(entry);
1307 u8 *soa_rdata = zone_reader_rdata(entry);
1308
1309 if(soa_rdata_len < MAX_SOA_RDATA_LENGTH)
1310 {
1311 memcpy(rdata, soa_rdata, soa_rdata_len);
1312 *rdata_size = soa_rdata_len;
1313 }
1314 else
1315 {
1316 return_value = INVALID_RECORD; // too big
1317 }
1318 }
1319 else
1320 {
1321 return_value = INVALID_STATE_ERROR;
1322 }
1323 }
1324
1325 return return_value;
1326 }
1327
1328 /**
1329 @}
1330 */
1331