xref: /freebsd/contrib/unbound/util/data/packed_rrset.c (revision 7a789145f88a6aceacc59029a0cafe7de7aeefea)
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
ub_packed_rrset_parsedelete(struct ub_packed_rrset_key * pkey,struct alloc_cache * alloc)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
ub_rrset_sizefunc(void * key,void * data)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
packed_rrset_sizeof(struct packed_rrset_data * d)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
ub_rrset_compare(void * k1,void * k2)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
ub_rrset_key_delete(void * key,void * userdata)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
rrset_data_delete(void * data,void * ATTR_UNUSED (userdata))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
rrsetdata_equal(struct packed_rrset_data * d1,struct packed_rrset_data * d2)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
rrset_key_hash(struct packed_rrset_key * key)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
packed_rrset_ptr_fixup(struct packed_rrset_data * data)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
get_cname_target(struct ub_packed_rrset_key * rrset,uint8_t ** dname,size_t * dname_len)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
packed_rrset_ttl_add(struct packed_rrset_data * data,time_t add)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*
rrset_trust_to_string(enum rrset_trust s)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*
sec_status_to_string(enum sec_status s)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 
log_rrset_key(enum verbosity_value v,const char * str,struct ub_packed_rrset_key * rrset)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 
packed_rr_to_string(struct ub_packed_rrset_key * rrset,size_t i,time_t now,char * dest,size_t dest_len)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 
log_packed_rrset(enum verbosity_value v,const char * str,struct ub_packed_rrset_key * rrset)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
ub_packed_rrset_ttl(struct ub_packed_rrset_key * key)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*
packed_rrset_copy_region(struct ub_packed_rrset_key * key,struct regional * region,time_t now)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*
packed_rrset_copy_alloc(struct ub_packed_rrset_key * key,struct alloc_cache * alloc,time_t now)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
packed_rrset_find_rr(struct packed_rrset_data * d,uint8_t * rdata,size_t len,size_t * index)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