1 /* 2 * validator/val_neg.h - validator aggressive negative caching functions. 3 * 4 * Copyright (c) 2008, NLnet Labs. All rights reserved. 5 * 6 * This software is open source. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 12 * Redistributions of source code must retain the above copyright notice, 13 * this list of conditions and the following disclaimer. 14 * 15 * Redistributions in binary form must reproduce the above copyright notice, 16 * this list of conditions and the following disclaimer in the documentation 17 * and/or other materials provided with the distribution. 18 * 19 * Neither the name of the NLNET LABS nor the names of its contributors may 20 * be used to endorse or promote products derived from this software without 21 * specific prior written permission. 22 * 23 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 24 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 25 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 26 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE 27 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 28 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 29 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 30 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 31 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 32 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 33 * POSSIBILITY OF SUCH DAMAGE. 34 */ 35 36 /** 37 * \file 38 * 39 * This file contains helper functions for the validator module. 40 * The functions help with aggressive negative caching. 41 * This creates new denials of existance, and proofs for absence of types 42 * from cached NSEC records. 43 */ 44 45 #ifndef VALIDATOR_VAL_NEG_H 46 #define VALIDATOR_VAL_NEG_H 47 #include "util/locks.h" 48 #include "util/rbtree.h" 49 struct val_neg_data; 50 struct config_file; 51 struct reply_info; 52 struct rrset_cache; 53 struct regional; 54 struct query_info; 55 struct dns_msg; 56 struct ub_packed_rrset_key; 57 58 /** 59 * The negative cache. It is shared between the threads, so locked. 60 * Kept as validator-environ-state. It refers back to the rrset cache for 61 * data elements. It can be out of date and contain conflicting data 62 * from zone content changes. 63 * It contains a tree of zones, every zone has a tree of data elements. 64 * The data elements are part of one big LRU list, with one memory counter. 65 */ 66 struct val_neg_cache { 67 /** the big lock on the negative cache. Because we use a rbtree 68 * for the data (quick lookup), we need a big lock */ 69 lock_basic_t lock; 70 /** The zone rbtree. contents sorted canonical, type val_neg_zone */ 71 rbtree_t tree; 72 /** the first in linked list of LRU of val_neg_data */ 73 struct val_neg_data* first; 74 /** last in lru (least recently used element) */ 75 struct val_neg_data* last; 76 /** current memory in use (bytes) */ 77 size_t use; 78 /** max memory to use (bytes) */ 79 size_t max; 80 /** max nsec3 iterations allowed */ 81 size_t nsec3_max_iter; 82 }; 83 84 /** 85 * Per Zone aggressive negative caching data. 86 */ 87 struct val_neg_zone { 88 /** rbtree node element, key is this struct: the name, class */ 89 rbnode_t node; 90 /** name; the key */ 91 uint8_t* name; 92 /** length of name */ 93 size_t len; 94 /** labels in name */ 95 int labs; 96 97 /** pointer to parent zone in the negative cache */ 98 struct val_neg_zone* parent; 99 100 /** the number of elements, including this one and the ones whose 101 * parents (-parents) include this one, that are in_use 102 * No elements have a count of zero, those are removed. */ 103 int count; 104 105 /** if 0: NSEC zone, else NSEC3 hash algorithm in use */ 106 int nsec3_hash; 107 /** nsec3 iteration count in use */ 108 size_t nsec3_iter; 109 /** nsec3 salt in use */ 110 uint8_t* nsec3_salt; 111 /** length of salt in bytes */ 112 size_t nsec3_saltlen; 113 114 /** tree of NSEC data for this zone, sorted canonical 115 * by NSEC owner name */ 116 rbtree_t tree; 117 118 /** class of node; host order */ 119 uint16_t dclass; 120 /** if this element is in use, boolean */ 121 uint8_t in_use; 122 }; 123 124 /** 125 * Data element for aggressive negative caching. 126 * The tree of these elements acts as an index onto the rrset cache. 127 * It shows the NSEC records that (may) exist and are (possibly) secure. 128 * The rbtree allows for logN search for a covering NSEC record. 129 * To make tree insertion and deletion logN too, all the parent (one label 130 * less than the name) data elements are also in the rbtree, with a usage 131 * count for every data element. 132 * There is no actual data stored in this data element, if it is in_use, 133 * then the data can (possibly) be found in the rrset cache. 134 */ 135 struct val_neg_data { 136 /** rbtree node element, key is this struct: the name */ 137 rbnode_t node; 138 /** name; the key */ 139 uint8_t* name; 140 /** length of name */ 141 size_t len; 142 /** labels in name */ 143 int labs; 144 145 /** pointer to parent node in the negative cache */ 146 struct val_neg_data* parent; 147 148 /** the number of elements, including this one and the ones whose 149 * parents (-parents) include this one, that are in use 150 * No elements have a count of zero, those are removed. */ 151 int count; 152 153 /** the zone that this denial is part of */ 154 struct val_neg_zone* zone; 155 156 /** previous in LRU */ 157 struct val_neg_data* prev; 158 /** next in LRU (next element was less recently used) */ 159 struct val_neg_data* next; 160 161 /** if this element is in use, boolean */ 162 uint8_t in_use; 163 }; 164 165 /** 166 * Create negative cache 167 * @param cfg: config options. 168 * @param maxiter: max nsec3 iterations allowed. 169 * @return neg cache, empty or NULL on failure. 170 */ 171 struct val_neg_cache* val_neg_create(struct config_file* cfg, size_t maxiter); 172 173 /** 174 * see how much memory is in use by the negative cache. 175 * @param neg: negative cache 176 * @return number of bytes in use. 177 */ 178 size_t val_neg_get_mem(struct val_neg_cache* neg); 179 180 /** 181 * Destroy negative cache. There must no longer be any other threads. 182 * @param neg: negative cache. 183 */ 184 void neg_cache_delete(struct val_neg_cache* neg); 185 186 /** 187 * Comparison function for rbtree val neg data elements 188 */ 189 int val_neg_data_compare(const void* a, const void* b); 190 191 /** 192 * Comparison function for rbtree val neg zone elements 193 */ 194 int val_neg_zone_compare(const void* a, const void* b); 195 196 /** 197 * Insert NSECs from this message into the negative cache for reference. 198 * @param neg: negative cache 199 * @param rep: reply with NSECs. 200 * Errors are ignored, means that storage is omitted. 201 */ 202 void val_neg_addreply(struct val_neg_cache* neg, struct reply_info* rep); 203 204 /** 205 * Insert NSECs from this referral into the negative cache for reference. 206 * @param neg: negative cache 207 * @param rep: referral reply with NS, NSECs. 208 * @param zone: bailiwick for the referral. 209 * Errors are ignored, means that storage is omitted. 210 */ 211 void val_neg_addreferral(struct val_neg_cache* neg, struct reply_info* rep, 212 uint8_t* zone); 213 214 /** 215 * Perform a DLV style lookup 216 * During the lookup, we could find out that data has expired. In that 217 * case the neg_cache entries are removed, and lookup fails. 218 * 219 * @param neg: negative cache. 220 * @param qname: name to look for 221 * @param len: length of qname. 222 * @param qclass: class to look in. 223 * @param rrset_cache: the rrset cache, for NSEC lookups. 224 * @param now: current time for ttl checks. 225 * @return 226 * 0 on error 227 * 0 if no proof of negative 228 * 1 if indeed negative was proven 229 * thus, qname DLV qclass does not exist. 230 */ 231 int val_neg_dlvlookup(struct val_neg_cache* neg, uint8_t* qname, size_t len, 232 uint16_t qclass, struct rrset_cache* rrset_cache, uint32_t now); 233 234 /** 235 * For the given query, try to get a reply out of the negative cache. 236 * The reply still needs to be validated. 237 * @param neg: negative cache. 238 * @param qinfo: query 239 * @param region: where to allocate reply. 240 * @param rrset_cache: rrset cache. 241 * @param buf: temporary buffer. 242 * @param now: to check TTLs against. 243 * @param addsoa: if true, produce result for external consumption. 244 * if false, do not add SOA - for unbound-internal consumption. 245 * @param topname: do not look higher than this name, 246 * so that the result cannot be taken from a zone above the current 247 * trust anchor. Which could happen with multiple islands of trust. 248 * if NULL, then no trust anchor is used, but also the algorithm becomes 249 * more conservative, especially for opt-out zones, since the receiver 250 * may have a trust-anchor below the optout and thus the optout cannot 251 * be used to create a proof from the negative cache. 252 * @return a reply message if something was found. 253 * This reply may still need validation. 254 * NULL if nothing found (or out of memory). 255 */ 256 struct dns_msg* val_neg_getmsg(struct val_neg_cache* neg, 257 struct query_info* qinfo, struct regional* region, 258 struct rrset_cache* rrset_cache, ldns_buffer* buf, uint32_t now, 259 int addsoa, uint8_t* topname); 260 261 262 /**** functions exposed for unit test ****/ 263 /** 264 * Insert data into the data tree of a zone 265 * Does not do locking. 266 * @param neg: negative cache 267 * @param zone: zone to insert into 268 * @param nsec: record to insert. 269 */ 270 void neg_insert_data(struct val_neg_cache* neg, 271 struct val_neg_zone* zone, struct ub_packed_rrset_key* nsec); 272 273 /** 274 * Delete a data element from the negative cache. 275 * May delete other data elements to keep tree coherent, or 276 * only mark the element as 'not in use'. 277 * Does not do locking. 278 * @param neg: negative cache. 279 * @param el: data element to delete. 280 */ 281 void neg_delete_data(struct val_neg_cache* neg, struct val_neg_data* el); 282 283 /** 284 * Find the given zone, from the SOA owner name and class 285 * Does not do locking. 286 * @param neg: negative cache 287 * @param nm: what to look for. 288 * @param len: length of nm 289 * @param dclass: class to look for. 290 * @return zone or NULL if not found. 291 */ 292 struct val_neg_zone* neg_find_zone(struct val_neg_cache* neg, 293 uint8_t* nm, size_t len, uint16_t dclass); 294 295 /** 296 * Create a new zone. 297 * Does not do locking. 298 * @param neg: negative cache 299 * @param nm: what to look for. 300 * @param nm_len: length of name. 301 * @param dclass: class of zone, host order. 302 * @return zone or NULL if out of memory. 303 */ 304 struct val_neg_zone* neg_create_zone(struct val_neg_cache* neg, 305 uint8_t* nm, size_t nm_len, uint16_t dclass); 306 307 /** 308 * take a zone into use. increases counts of parents. 309 * Does not do locking. 310 * @param zone: zone to take into use. 311 */ 312 void val_neg_zone_take_inuse(struct val_neg_zone* zone); 313 314 #endif /* VALIDATOR_VAL_NEG_H */ 315