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