1 /* 2 * util/data/packed_rrset.c - data storage for a set of resource records. 3 * 4 * Copyright (c) 2007, 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 25 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 26 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 27 * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 28 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 29 * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 30 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 31 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 32 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 33 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 34 */ 35 36 /** 37 * \file 38 * 39 * This file contains the data storage for RRsets. 40 */ 41 42 #include "config.h" 43 #include "util/data/msgparse.h" 44 #include "util/data/packed_rrset.h" 45 #include "util/data/dname.h" 46 #include "util/storage/lookup3.h" 47 #include "util/log.h" 48 #include "util/alloc.h" 49 #include "util/regional.h" 50 #include "util/net_help.h" 51 #include "sldns/rrdef.h" 52 #include "sldns/sbuffer.h" 53 #include "sldns/wire2str.h" 54 55 void 56 ub_packed_rrset_parsedelete(struct ub_packed_rrset_key* pkey, 57 struct alloc_cache* alloc) 58 { 59 if(!pkey) 60 return; 61 free(pkey->entry.data); 62 pkey->entry.data = NULL; 63 free(pkey->rk.dname); 64 pkey->rk.dname = NULL; 65 pkey->id = 0; 66 alloc_special_release(alloc, pkey); 67 } 68 69 size_t 70 ub_rrset_sizefunc(void* key, void* data) 71 { 72 struct ub_packed_rrset_key* k = (struct ub_packed_rrset_key*)key; 73 struct packed_rrset_data* d = (struct packed_rrset_data*)data; 74 size_t s = sizeof(struct ub_packed_rrset_key) + k->rk.dname_len; 75 s += packed_rrset_sizeof(d) + lock_get_mem(&k->entry.lock); 76 return s; 77 } 78 79 size_t 80 packed_rrset_sizeof(struct packed_rrset_data* d) 81 { 82 size_t s; 83 if(d->rrsig_count > 0) { 84 s = ((uint8_t*)d->rr_data[d->count+d->rrsig_count-1] - 85 (uint8_t*)d) + d->rr_len[d->count+d->rrsig_count-1]; 86 } else { 87 log_assert(d->count > 0); 88 s = ((uint8_t*)d->rr_data[d->count-1] - (uint8_t*)d) + 89 d->rr_len[d->count-1]; 90 } 91 return s; 92 } 93 94 int 95 ub_rrset_compare(void* k1, void* k2) 96 { 97 struct ub_packed_rrset_key* key1 = (struct ub_packed_rrset_key*)k1; 98 struct ub_packed_rrset_key* key2 = (struct ub_packed_rrset_key*)k2; 99 int c; 100 if(key1 == key2) 101 return 0; 102 if(key1->rk.type != key2->rk.type) { 103 if(key1->rk.type < key2->rk.type) 104 return -1; 105 return 1; 106 } 107 if(key1->rk.dname_len != key2->rk.dname_len) { 108 if(key1->rk.dname_len < key2->rk.dname_len) 109 return -1; 110 return 1; 111 } 112 if((c=query_dname_compare(key1->rk.dname, key2->rk.dname)) != 0) 113 return c; 114 if(key1->rk.rrset_class != key2->rk.rrset_class) { 115 if(key1->rk.rrset_class < key2->rk.rrset_class) 116 return -1; 117 return 1; 118 } 119 if(key1->rk.flags != key2->rk.flags) { 120 if(key1->rk.flags < key2->rk.flags) 121 return -1; 122 return 1; 123 } 124 return 0; 125 } 126 127 void 128 ub_rrset_key_delete(void* key, void* userdata) 129 { 130 struct ub_packed_rrset_key* k = (struct ub_packed_rrset_key*)key; 131 struct alloc_cache* a = (struct alloc_cache*)userdata; 132 k->id = 0; 133 free(k->rk.dname); 134 k->rk.dname = NULL; 135 alloc_special_release(a, k); 136 } 137 138 void 139 rrset_data_delete(void* data, void* ATTR_UNUSED(userdata)) 140 { 141 struct packed_rrset_data* d = (struct packed_rrset_data*)data; 142 free(d); 143 } 144 145 int 146 rrsetdata_equal(struct packed_rrset_data* d1, struct packed_rrset_data* d2) 147 { 148 size_t i; 149 size_t total; 150 if(d1->count != d2->count || d1->rrsig_count != d2->rrsig_count) 151 return 0; 152 total = d1->count + d1->rrsig_count; 153 for(i=0; i<total; i++) { 154 if(d1->rr_len[i] != d2->rr_len[i]) 155 return 0; 156 if(memcmp(d1->rr_data[i], d2->rr_data[i], d1->rr_len[i]) != 0) 157 return 0; 158 } 159 return 1; 160 } 161 162 hashvalue_type 163 rrset_key_hash(struct packed_rrset_key* key) 164 { 165 /* type is hashed in host order */ 166 uint16_t t = ntohs(key->type); 167 /* Note this MUST be identical to pkt_hash_rrset in msgparse.c */ 168 /* this routine does not have a compressed name */ 169 hashvalue_type h = 0xab; 170 h = dname_query_hash(key->dname, h); 171 h = hashlittle(&t, sizeof(t), h); 172 h = hashlittle(&key->rrset_class, sizeof(uint16_t), h); 173 h = hashlittle(&key->flags, sizeof(uint32_t), h); 174 return h; 175 } 176 177 void 178 packed_rrset_ptr_fixup(struct packed_rrset_data* data) 179 { 180 size_t i; 181 size_t total = data->count + data->rrsig_count; 182 uint8_t* nextrdata; 183 /* fixup pointers in packed rrset data */ 184 data->rr_len = (size_t*)((uint8_t*)data + 185 sizeof(struct packed_rrset_data)); 186 data->rr_data = (uint8_t**)&(data->rr_len[total]); 187 data->rr_ttl = (time_t*)&(data->rr_data[total]); 188 nextrdata = (uint8_t*)&(data->rr_ttl[total]); 189 for(i=0; i<total; i++) { 190 data->rr_data[i] = nextrdata; 191 nextrdata += data->rr_len[i]; 192 } 193 } 194 195 void 196 get_cname_target(struct ub_packed_rrset_key* rrset, uint8_t** dname, 197 size_t* dname_len) 198 { 199 struct packed_rrset_data* d; 200 size_t len; 201 if(!rrset) return; 202 if(ntohs(rrset->rk.type) != LDNS_RR_TYPE_CNAME && 203 ntohs(rrset->rk.type) != LDNS_RR_TYPE_DNAME) 204 return; 205 d = (struct packed_rrset_data*)rrset->entry.data; 206 if(d->count < 1) 207 return; 208 if(d->rr_len[0] < 3) /* at least rdatalen + 0byte root label */ 209 return; 210 len = sldns_read_uint16(d->rr_data[0]); 211 if(len != d->rr_len[0] - sizeof(uint16_t)) 212 return; 213 if(dname_valid(d->rr_data[0]+sizeof(uint16_t), len) != len) 214 return; 215 *dname = d->rr_data[0]+sizeof(uint16_t); 216 *dname_len = len; 217 } 218 219 void 220 packed_rrset_ttl_add(struct packed_rrset_data* data, time_t add) 221 { 222 size_t i; 223 size_t total = data->count + data->rrsig_count; 224 data->ttl_add = add; 225 data->ttl += add; 226 for(i=0; i<total; i++) 227 data->rr_ttl[i] += add; 228 } 229 230 const char* 231 rrset_trust_to_string(enum rrset_trust s) 232 { 233 switch(s) { 234 case rrset_trust_none: return "rrset_trust_none"; 235 case rrset_trust_add_noAA: return "rrset_trust_add_noAA"; 236 case rrset_trust_auth_noAA: return "rrset_trust_auth_noAA"; 237 case rrset_trust_add_AA: return "rrset_trust_add_AA"; 238 case rrset_trust_nonauth_ans_AA:return "rrset_trust_nonauth_ans_AA"; 239 case rrset_trust_ans_noAA: return "rrset_trust_ans_noAA"; 240 case rrset_trust_glue: return "rrset_trust_glue"; 241 case rrset_trust_auth_AA: return "rrset_trust_auth_AA"; 242 case rrset_trust_ans_AA: return "rrset_trust_ans_AA"; 243 case rrset_trust_sec_noglue: return "rrset_trust_sec_noglue"; 244 case rrset_trust_prim_noglue: return "rrset_trust_prim_noglue"; 245 case rrset_trust_validated: return "rrset_trust_validated"; 246 case rrset_trust_ultimate: return "rrset_trust_ultimate"; 247 } 248 return "unknown_rrset_trust_value"; 249 } 250 251 const char* 252 sec_status_to_string(enum sec_status s) 253 { 254 switch(s) { 255 case sec_status_unchecked: return "sec_status_unchecked"; 256 case sec_status_bogus: return "sec_status_bogus"; 257 case sec_status_indeterminate: return "sec_status_indeterminate"; 258 case sec_status_insecure: return "sec_status_insecure"; 259 case sec_status_secure_sentinel_fail: return "sec_status_secure_sentinel_fail"; 260 case sec_status_secure: return "sec_status_secure"; 261 } 262 return "unknown_sec_status_value"; 263 } 264 265 void log_rrset_key(enum verbosity_value v, const char* str, 266 struct ub_packed_rrset_key* rrset) 267 { 268 if(verbosity >= v) 269 log_nametypeclass(v, str, rrset->rk.dname, 270 ntohs(rrset->rk.type), ntohs(rrset->rk.rrset_class)); 271 } 272 273 int packed_rr_to_string(struct ub_packed_rrset_key* rrset, size_t i, 274 time_t now, char* dest, size_t dest_len) 275 { 276 struct packed_rrset_data* d = (struct packed_rrset_data*)rrset-> 277 entry.data; 278 uint8_t rr[65535]; 279 size_t wlen; 280 size_t rlen = rrset->rk.dname_len + 2 + 2 + 4 + d->rr_len[i]; 281 time_t adjust = 0; 282 log_assert(dest_len > 0 && dest); 283 if(rlen > dest_len) { 284 dest[0] = 0; 285 return 0; 286 } 287 memmove(rr, rrset->rk.dname, rrset->rk.dname_len); 288 if(i < d->count) 289 memmove(rr+rrset->rk.dname_len, &rrset->rk.type, 2); 290 else sldns_write_uint16(rr+rrset->rk.dname_len, LDNS_RR_TYPE_RRSIG); 291 memmove(rr+rrset->rk.dname_len+2, &rrset->rk.rrset_class, 2); 292 adjust = SERVE_ORIGINAL_TTL ? d->ttl_add : now; 293 if (d->rr_ttl[i] < adjust) adjust = d->rr_ttl[i]; /* Prevent negative TTL overflow */ 294 sldns_write_uint32(rr+rrset->rk.dname_len+4, 295 (uint32_t)(d->rr_ttl[i]-adjust)); 296 memmove(rr+rrset->rk.dname_len+8, d->rr_data[i], d->rr_len[i]); 297 wlen = (size_t)sldns_wire2str_rr_buf(rr, rlen, dest, dest_len); 298 if(wlen >= dest_len) { 299 /* the output string was truncated */ 300 verbose(VERB_ALGO, "rrbuf failure %d %s", (int)d->rr_len[i], dest); 301 dest[0] = 0; 302 return 0; 303 } 304 return 1; 305 } 306 307 void log_packed_rrset(enum verbosity_value v, const char* str, 308 struct ub_packed_rrset_key* rrset) 309 { 310 struct packed_rrset_data* d = (struct packed_rrset_data*)rrset-> 311 entry.data; 312 char buf[65535]; 313 size_t i; 314 if(verbosity < v) 315 return; 316 for(i=0; i<d->count+d->rrsig_count; i++) { 317 if(!packed_rr_to_string(rrset, i, 0, buf, sizeof(buf))) { 318 log_info("%s: rr %d wire2str-error", str, (int)i); 319 } else { 320 log_info("%s: %s", str, buf); 321 } 322 } 323 } 324 325 time_t 326 ub_packed_rrset_ttl(struct ub_packed_rrset_key* key) 327 { 328 struct packed_rrset_data* d = (struct packed_rrset_data*)key-> 329 entry.data; 330 return d->ttl; 331 } 332 333 struct ub_packed_rrset_key* 334 packed_rrset_copy_region(struct ub_packed_rrset_key* key, 335 struct regional* region, time_t now) 336 { 337 struct ub_packed_rrset_key* ck = regional_alloc(region, 338 sizeof(struct ub_packed_rrset_key)); 339 struct packed_rrset_data* d; 340 struct packed_rrset_data* data = key->entry.data; 341 size_t dsize, i; 342 time_t now_control; 343 if(!ck) 344 return NULL; 345 ck->id = key->id; 346 memset(&ck->entry, 0, sizeof(ck->entry)); 347 ck->entry.hash = key->entry.hash; 348 ck->entry.key = ck; 349 ck->rk = key->rk; 350 ck->rk.dname = regional_alloc_init(region, key->rk.dname, 351 key->rk.dname_len); 352 if(!ck->rk.dname) 353 return NULL; 354 dsize = packed_rrset_sizeof(data); 355 d = regional_alloc_init(region, data, dsize); 356 if(!d) 357 return NULL; 358 ck->entry.data = d; 359 packed_rrset_ptr_fixup(d); 360 /* make TTLs relative - once per rr */ 361 if(now > 0) { 362 /* NS RRSets may be here with ttl_add higher than now because 363 * of the novel ghost attack mitigation i.e., using the 364 * qstarttime for NS RRSets. In that case make sure that the 365 * returned TTL is not higher than the original one. */ 366 /* For types other than type NS, auth zone and rpz code 367 * can have ttl_add values. Also time could conceivably move 368 * in reverse, due to operator action, and it is prudent 369 * to not assert on that here. 370 * So there is no assertion d->ttl_add <= now || type==NS */ 371 now_control = SERVE_ORIGINAL_TTL ? data->ttl_add 372 : (d->ttl_add > now ? d->ttl_add : now ); 373 for(i=0; i<d->count + d->rrsig_count; i++) { 374 if(TTL_IS_EXPIRED(d->rr_ttl[i], now_control)) { 375 d->rr_ttl[i] = EXPIRED_REPLY_TTL_CALC(d->rr_ttl[i], data->ttl_add); 376 } else d->rr_ttl[i] -= now_control; 377 } 378 if(TTL_IS_EXPIRED(d->ttl, now_control)) { 379 d->ttl = EXPIRED_REPLY_TTL_CALC(d->ttl, data->ttl_add); 380 } else d->ttl -= now_control; 381 d->ttl_add = 0; /* TTLs have been made relative */ 382 } 383 return ck; 384 } 385 386 struct ub_packed_rrset_key* 387 packed_rrset_copy_alloc(struct ub_packed_rrset_key* key, 388 struct alloc_cache* alloc, time_t now) 389 { 390 struct packed_rrset_data* fd, *dd; 391 struct ub_packed_rrset_key* dk = alloc_special_obtain(alloc); 392 if(!dk) return NULL; 393 fd = (struct packed_rrset_data*)key->entry.data; 394 dk->entry.hash = key->entry.hash; 395 dk->rk = key->rk; 396 dk->rk.dname = (uint8_t*)memdup(key->rk.dname, key->rk.dname_len); 397 if(!dk->rk.dname) { 398 alloc_special_release(alloc, dk); 399 return NULL; 400 } 401 dd = (struct packed_rrset_data*)memdup(fd, packed_rrset_sizeof(fd)); 402 if(!dd) { 403 free(dk->rk.dname); 404 alloc_special_release(alloc, dk); 405 return NULL; 406 } 407 packed_rrset_ptr_fixup(dd); 408 dk->entry.data = (void*)dd; 409 packed_rrset_ttl_add(dd, now); 410 return dk; 411 } 412 413 int 414 packed_rrset_find_rr(struct packed_rrset_data* d, uint8_t* rdata, size_t len, 415 size_t* index) 416 { 417 size_t i; 418 for(i=0; i<d->count; i++) { 419 if(d->rr_len[i] != len) 420 continue; 421 if(memcmp(d->rr_data[i], rdata, len) == 0) { 422 *index = i; 423 return 1; 424 } 425 } 426 return 0; 427 } 428