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
36  *  @ingroup dnsdb
37  *  @brief
38  *
39  *
40  *
41  * @{
42  */
43 /*------------------------------------------------------------------------------
44  *
45  * USE INCLUDES */
46 #include "dnsdb/dnsdb-config.h"
47 #include <dnscore/u32_set.h>
48 #include <dnscore/logger.h>
49 #include "dnsdb/zdb-zone-maintenance.h"
50 #include "dnsdb/rrsig.h"
51 
52 extern logger_handle* g_database_logger;
53 #define MODULE_MSG_HANDLE g_database_logger
54 
55 /**
56  * Updates the signatures of a zone incrementally.
57  * Each call goes a bit further.
58  *
59  * @param zone
60  * @param signature_count_loose_limit
61  * @param present_signatures_are_verified
62  * @return the number of actions counted
63  */
64 
65 int
zdb_zone_maintenance_nsec(zdb_zone_maintenance_ctx * mctx,const zone_diff_fqdn * diff_fqdn,ptr_vector * rrset_to_sign)66 zdb_zone_maintenance_nsec(zdb_zone_maintenance_ctx* mctx, const zone_diff_fqdn *diff_fqdn, ptr_vector *rrset_to_sign)
67 {
68     //   if NSEC created :
69     //   _ add the NSEC record & signature if missing
70     //   _ update the NSEC RRSIG
71     //   _ add the NSEC node to the collection
72 
73     //   if NSEC removal :
74     //   _ remove the NSEC record & signature
75     //   _ remove the NSEC node from the collection
76 
77     // NSEC signatures should be handled with the general signatures
78 
79     int ret = 0;
80 
81     if((mctx->nsec_chain_status & (NSEC_ZONE_GENERATING|NSEC_ZONE_REMOVING)) == NSEC_ZONE_GENERATING)
82     {
83         // add
84         zdb_packed_ttlrdata *nsec_rrset = zdb_record_find(&mctx->label->resource_record_set, TYPE_NSEC);
85         if(nsec_rrset == NULL)
86         {
87             // need to add the NSEC record and its signature
88             // difficult as the next record has to be known
89 
90             ret = dnssec_chain_add_from_diff_fqdn(&mctx->nsec_chain_updater, diff_fqdn, 0);
91         }
92     }
93     else if((mctx->nsec_chain_status & (NSEC_ZONE_GENERATING|NSEC_ZONE_REMOVING)) == NSEC_ZONE_REMOVING)
94     {
95         // del
96         zdb_packed_ttlrdata *nsec_rrset = zdb_record_find(&mctx->label->resource_record_set, TYPE_NSEC);
97         if(nsec_rrset != NULL)
98         {
99             // need to remove the NSEC record(s) and its signature(s)
100             // simple to do
101             ret = dnssec_chain_del_from_diff_fqdn(&mctx->nsec_chain_updater, diff_fqdn, 0);
102         }
103     }
104     else
105     {
106         if(rrset_to_sign != NULL)
107         {
108 #if DEBUG
109             log_debug1("maintenance: %{dnsname}: looking at NSEC RRSIG coverage", mctx->zone->origin);
110 #endif
111             if(zone_diff_will_have_rrset_type(diff_fqdn, TYPE_NSEC))
112             {
113                 zone_diff_fqdn_rr_set *nsec_rrset = zone_diff_fqdn_rr_set_get((zone_diff_fqdn *) diff_fqdn, TYPE_NSEC);
114 
115                 if(nsec_rrset != NULL)
116                 {
117 #if DEBUG
118                     log_debug1("maintenance: %{dnsname}: NSEC RRSET exists", mctx->zone->origin);
119 #endif
120 #if 0
121                     zone_diff_fqdn_rr_set *rrsig_rrset = zone_diff_fqdn_rr_set_get((zone_diff_fqdn *) diff_fqdn, TYPE_RRSIG);
122 #endif
123                     bool sign_nsec_rrset = TRUE;
124 #if 0
125                     if(rrsig_rrset != NULL)
126                     {
127                         bool has_one_valid_signature = FALSE;
128                         sign_nsec_rrset = FALSE;
129 
130                         ptr_set_iterator rr_iter;
131                         ptr_set_iterator_init(&rrsig_rrset->rr, &rr_iter);
132                         while(ptr_set_iterator_hasnext(&rr_iter))
133                         {
134                             ptr_node *node = ptr_set_iterator_next_node(&rr_iter);
135                             zone_diff_label_rr *rr = (zone_diff_label_rr *)node->key;
136 
137                             if((rr->state & ZONE_DIFF_RR_REMOVE) != 0)
138                             {
139                                 continue; // signature is being removed already: ignore
140                             }
141 
142                             u16 covered_type = rrsig_get_type_covered_from_rdata(rr->rdata, rr->rdata_size);
143 
144                             if(covered_type == TYPE_NSEC)
145                             {
146                                 s32 key_index = -2;
147                                 if(rrsig_should_remove_signature_from_rdata(
148                                     rr->rdata, rr->rdata_size,
149                                     &mctx->zsks, mctx->now, mctx->zone->sig_validity_regeneration_seconds, &key_index) && (key_index != -1))
150                                 {
151 #if DEBUG
152                                     log_debug1("maintenance: %{dnsname}: NSEC RRSET signature should be removed", mctx->zone->origin);
153 #endif
154                                     sign_nsec_rrset = TRUE;
155                                     break;
156                                 }
157                                 else
158                                 {
159 #if DEBUG
160                                     log_debug1("maintenance: %{dnsname}: NSEC RRSET is covered by at least one signature", mctx->zone->origin);
161 #endif
162                                     has_one_valid_signature = TRUE;
163                                 }
164                             }
165                         }
166 
167                         sign_nsec_rrset |= has_one_valid_signature;
168                     }
169                     else
170                     {
171 #if DEBUG
172                         log_debug1("maintenance: %{dnsname}: NSEC RRSET and there are no signatures at all on the label", mctx->zone->origin);
173 #endif
174                         sign_nsec_rrset = TRUE;
175                     }
176 #endif
177                     if(sign_nsec_rrset) // always true ...
178                     {
179                         for(int i = 0; i <= ptr_vector_last_index(rrset_to_sign); ++i)
180                         {
181                             if(ptr_vector_get(rrset_to_sign, i) == nsec_rrset)
182                             {
183                                 sign_nsec_rrset = FALSE;
184                                 break;
185                             }
186                         }
187 
188                         if(sign_nsec_rrset)
189                         {
190 #if DEBUG
191                             u16 rtype = TYPE_NSEC;
192                             log_debug1("maintenance: %{dnsname}: %{dnsname} %{dnstype} will have its RRSIGs updated",
193                                     mctx->zone->origin,
194                                     diff_fqdn->fqdn,
195                                     &rtype);
196 #endif
197                             ptr_vector_append(rrset_to_sign, nsec_rrset);
198                             ++ret;
199                         }
200                         else
201                         {
202                             log_debug1("maintenance: %{dnsname}: NSEC RRSET is already marked for signature", mctx->zone->origin);
203                         }
204                     }
205                     else
206                     {
207 #if DEBUG
208                         log_debug1("maintenance: %{dnsname}: NSEC RRSET does not need to be signed again", mctx->zone->origin);
209 #endif
210                     }
211                 }
212             }
213         }
214     }
215     return ret;
216 }
217 
218 /** @} */
219