Home | History | Annotate | Line # | Download | only in data
      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(ntohs(rrset->rk.type) != LDNS_RR_TYPE_CNAME &&
    202 		ntohs(rrset->rk.type) != LDNS_RR_TYPE_DNAME)
    203 		return;
    204 	d = (struct packed_rrset_data*)rrset->entry.data;
    205 	if(d->count < 1)
    206 		return;
    207 	if(d->rr_len[0] < 3) /* at least rdatalen + 0byte root label */
    208 		return;
    209 	len = sldns_read_uint16(d->rr_data[0]);
    210 	if(len != d->rr_len[0] - sizeof(uint16_t))
    211 		return;
    212 	if(dname_valid(d->rr_data[0]+sizeof(uint16_t), len) != len)
    213 		return;
    214 	*dname = d->rr_data[0]+sizeof(uint16_t);
    215 	*dname_len = len;
    216 }
    217 
    218 void
    219 packed_rrset_ttl_add(struct packed_rrset_data* data, time_t add)
    220 {
    221 	size_t i;
    222 	size_t total = data->count + data->rrsig_count;
    223 	data->ttl_add = add;
    224 	data->ttl += add;
    225 	for(i=0; i<total; i++)
    226 		data->rr_ttl[i] += add;
    227 }
    228 
    229 const char*
    230 rrset_trust_to_string(enum rrset_trust s)
    231 {
    232 	switch(s) {
    233 	case rrset_trust_none: 		return "rrset_trust_none";
    234 	case rrset_trust_add_noAA: 	return "rrset_trust_add_noAA";
    235 	case rrset_trust_auth_noAA: 	return "rrset_trust_auth_noAA";
    236 	case rrset_trust_add_AA: 	return "rrset_trust_add_AA";
    237 	case rrset_trust_nonauth_ans_AA:return "rrset_trust_nonauth_ans_AA";
    238 	case rrset_trust_ans_noAA: 	return "rrset_trust_ans_noAA";
    239 	case rrset_trust_glue: 		return "rrset_trust_glue";
    240 	case rrset_trust_auth_AA: 	return "rrset_trust_auth_AA";
    241 	case rrset_trust_ans_AA: 	return "rrset_trust_ans_AA";
    242 	case rrset_trust_sec_noglue: 	return "rrset_trust_sec_noglue";
    243 	case rrset_trust_prim_noglue: 	return "rrset_trust_prim_noglue";
    244 	case rrset_trust_validated: 	return "rrset_trust_validated";
    245 	case rrset_trust_ultimate: 	return "rrset_trust_ultimate";
    246 	}
    247 	return "unknown_rrset_trust_value";
    248 }
    249 
    250 const char*
    251 sec_status_to_string(enum sec_status s)
    252 {
    253 	switch(s) {
    254 	case sec_status_unchecked: 	return "sec_status_unchecked";
    255 	case sec_status_bogus: 		return "sec_status_bogus";
    256 	case sec_status_indeterminate: 	return "sec_status_indeterminate";
    257 	case sec_status_insecure: 	return "sec_status_insecure";
    258 	case sec_status_secure_sentinel_fail: 	return "sec_status_secure_sentinel_fail";
    259 	case sec_status_secure: 	return "sec_status_secure";
    260 	}
    261 	return "unknown_sec_status_value";
    262 }
    263 
    264 void log_rrset_key(enum verbosity_value v, const char* str,
    265 	struct ub_packed_rrset_key* rrset)
    266 {
    267 	if(verbosity >= v)
    268 		log_nametypeclass(v, str, rrset->rk.dname,
    269 			ntohs(rrset->rk.type), ntohs(rrset->rk.rrset_class));
    270 }
    271 
    272 int packed_rr_to_string(struct ub_packed_rrset_key* rrset, size_t i,
    273 	time_t now, char* dest, size_t dest_len)
    274 {
    275 	struct packed_rrset_data* d = (struct packed_rrset_data*)rrset->
    276 		entry.data;
    277 	uint8_t rr[65535];
    278 	size_t wlen;
    279 	size_t rlen = rrset->rk.dname_len + 2 + 2 + 4 + d->rr_len[i];
    280 	time_t adjust = 0;
    281 	log_assert(dest_len > 0 && dest);
    282 	if(rlen > dest_len) {
    283 		dest[0] = 0;
    284 		return 0;
    285 	}
    286 	memmove(rr, rrset->rk.dname, rrset->rk.dname_len);
    287 	if(i < d->count)
    288 		memmove(rr+rrset->rk.dname_len, &rrset->rk.type, 2);
    289 	else	sldns_write_uint16(rr+rrset->rk.dname_len, LDNS_RR_TYPE_RRSIG);
    290 	memmove(rr+rrset->rk.dname_len+2, &rrset->rk.rrset_class, 2);
    291 	adjust = SERVE_ORIGINAL_TTL ? d->ttl_add : now;
    292 	if (d->rr_ttl[i] < adjust) adjust = d->rr_ttl[i]; /* Prevent negative TTL overflow */
    293 	sldns_write_uint32(rr+rrset->rk.dname_len+4,
    294 		(uint32_t)(d->rr_ttl[i]-adjust));
    295 	memmove(rr+rrset->rk.dname_len+8, d->rr_data[i], d->rr_len[i]);
    296 	wlen = (size_t)sldns_wire2str_rr_buf(rr, rlen, dest, dest_len);
    297 	if(wlen >= dest_len) {
    298 		/* the output string was truncated */
    299 		log_info("rrbuf failure %d %s", (int)d->rr_len[i], dest);
    300 		dest[0] = 0;
    301 		return 0;
    302 	}
    303 	return 1;
    304 }
    305 
    306 void log_packed_rrset(enum verbosity_value v, const char* str,
    307 	struct ub_packed_rrset_key* rrset)
    308 {
    309 	struct packed_rrset_data* d = (struct packed_rrset_data*)rrset->
    310 		entry.data;
    311 	char buf[65535];
    312 	size_t i;
    313 	if(verbosity < v)
    314 		return;
    315 	for(i=0; i<d->count+d->rrsig_count; i++) {
    316 		if(!packed_rr_to_string(rrset, i, 0, buf, sizeof(buf))) {
    317 			log_info("%s: rr %d wire2str-error", str, (int)i);
    318 		} else {
    319 			log_info("%s: %s", str, buf);
    320 		}
    321 	}
    322 }
    323 
    324 time_t
    325 ub_packed_rrset_ttl(struct ub_packed_rrset_key* key)
    326 {
    327 	struct packed_rrset_data* d = (struct packed_rrset_data*)key->
    328 		entry.data;
    329 	return d->ttl;
    330 }
    331 
    332 struct ub_packed_rrset_key*
    333 packed_rrset_copy_region(struct ub_packed_rrset_key* key,
    334 	struct regional* region, time_t now)
    335 {
    336 	struct ub_packed_rrset_key* ck = regional_alloc(region,
    337 		sizeof(struct ub_packed_rrset_key));
    338 	struct packed_rrset_data* d;
    339 	struct packed_rrset_data* data = key->entry.data;
    340 	size_t dsize, i;
    341 	time_t now_control;
    342 	if(!ck)
    343 		return NULL;
    344 	ck->id = key->id;
    345 	memset(&ck->entry, 0, sizeof(ck->entry));
    346 	ck->entry.hash = key->entry.hash;
    347 	ck->entry.key = ck;
    348 	ck->rk = key->rk;
    349 	ck->rk.dname = regional_alloc_init(region, key->rk.dname,
    350 		key->rk.dname_len);
    351 	if(!ck->rk.dname)
    352 		return NULL;
    353 	dsize = packed_rrset_sizeof(data);
    354 	d = regional_alloc_init(region, data, dsize);
    355 	if(!d)
    356 		return NULL;
    357 	ck->entry.data = d;
    358 	packed_rrset_ptr_fixup(d);
    359 	/* make TTLs relative - once per rr */
    360 	if(now > 0) {
    361 		/* NS RRSets may be here with ttl_add higher than now because
    362 		 * of the novel ghost attack mitigation i.e., using the
    363 		 * qstarttime for NS RRSets. In that case make sure that the
    364 		 * returned TTL is not higher than the original one. */
    365 		log_assert(d->ttl_add <= now ||
    366 			(ntohs(key->rk.type) == LDNS_RR_TYPE_NS));
    367 		now_control = SERVE_ORIGINAL_TTL ? data->ttl_add
    368 			: (d->ttl_add > now ? d->ttl_add : now );
    369 		for(i=0; i<d->count + d->rrsig_count; i++) {
    370 			if(TTL_IS_EXPIRED(d->rr_ttl[i], now_control)) {
    371 				d->rr_ttl[i] = EXPIRED_REPLY_TTL_CALC(d->rr_ttl[i], data->ttl_add);
    372 			} else	d->rr_ttl[i] -= now_control;
    373 		}
    374 		if(TTL_IS_EXPIRED(d->ttl, now_control)) {
    375 			d->ttl = EXPIRED_REPLY_TTL_CALC(d->ttl, data->ttl_add);
    376 		} else	d->ttl -= now_control;
    377 		d->ttl_add = 0; /* TTLs have been made relative */
    378 	}
    379 	return ck;
    380 }
    381 
    382 struct ub_packed_rrset_key*
    383 packed_rrset_copy_alloc(struct ub_packed_rrset_key* key,
    384 	struct alloc_cache* alloc, time_t now)
    385 {
    386 	struct packed_rrset_data* fd, *dd;
    387 	struct ub_packed_rrset_key* dk = alloc_special_obtain(alloc);
    388 	if(!dk) return NULL;
    389 	fd = (struct packed_rrset_data*)key->entry.data;
    390 	dk->entry.hash = key->entry.hash;
    391 	dk->rk = key->rk;
    392 	dk->rk.dname = (uint8_t*)memdup(key->rk.dname, key->rk.dname_len);
    393 	if(!dk->rk.dname) {
    394 		alloc_special_release(alloc, dk);
    395 		return NULL;
    396 	}
    397 	dd = (struct packed_rrset_data*)memdup(fd, packed_rrset_sizeof(fd));
    398 	if(!dd) {
    399 		free(dk->rk.dname);
    400 		alloc_special_release(alloc, dk);
    401 		return NULL;
    402 	}
    403 	packed_rrset_ptr_fixup(dd);
    404 	dk->entry.data = (void*)dd;
    405 	packed_rrset_ttl_add(dd, now);
    406 	return dk;
    407 }
    408 
    409 int
    410 packed_rrset_find_rr(struct packed_rrset_data* d, uint8_t* rdata, size_t len,
    411 	size_t* index)
    412 {
    413 	size_t i;
    414 	for(i=0; i<d->count; i++) {
    415 		if(d->rr_len[i] != len)
    416 			continue;
    417 		if(memcmp(d->rr_data[i], rdata, len) == 0) {
    418 			*index = i;
    419 			return 1;
    420 		}
    421 	}
    422 	return 0;
    423 }
    424