1238106Sdes/*
2238106Sdes * util/data/packed_rrset.c - data storage for a set of resource records.
3238106Sdes *
4238106Sdes * Copyright (c) 2007, NLnet Labs. All rights reserved.
5238106Sdes *
6238106Sdes * This software is open source.
7238106Sdes *
8238106Sdes * Redistribution and use in source and binary forms, with or without
9238106Sdes * modification, are permitted provided that the following conditions
10238106Sdes * are met:
11238106Sdes *
12238106Sdes * Redistributions of source code must retain the above copyright notice,
13238106Sdes * this list of conditions and the following disclaimer.
14238106Sdes *
15238106Sdes * Redistributions in binary form must reproduce the above copyright notice,
16238106Sdes * this list of conditions and the following disclaimer in the documentation
17238106Sdes * and/or other materials provided with the distribution.
18238106Sdes *
19238106Sdes * Neither the name of the NLNET LABS nor the names of its contributors may
20238106Sdes * be used to endorse or promote products derived from this software without
21238106Sdes * specific prior written permission.
22238106Sdes *
23238106Sdes * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24269257Sdes * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25269257Sdes * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
26269257Sdes * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
27269257Sdes * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
28269257Sdes * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
29269257Sdes * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
30269257Sdes * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
31269257Sdes * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
32269257Sdes * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
33269257Sdes * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34238106Sdes */
35238106Sdes
36238106Sdes/**
37238106Sdes * \file
38238106Sdes *
39238106Sdes * This file contains the data storage for RRsets.
40238106Sdes */
41238106Sdes
42238106Sdes#include "config.h"
43238106Sdes#include "util/data/packed_rrset.h"
44238106Sdes#include "util/data/dname.h"
45238106Sdes#include "util/storage/lookup3.h"
46238106Sdes#include "util/log.h"
47238106Sdes#include "util/alloc.h"
48238106Sdes#include "util/regional.h"
49238106Sdes#include "util/net_help.h"
50291767Sdes#include "sldns/rrdef.h"
51291767Sdes#include "sldns/sbuffer.h"
52291767Sdes#include "sldns/wire2str.h"
53238106Sdes
54238106Sdesvoid
55238106Sdesub_packed_rrset_parsedelete(struct ub_packed_rrset_key* pkey,
56238106Sdes        struct alloc_cache* alloc)
57238106Sdes{
58238106Sdes	if(!pkey)
59238106Sdes		return;
60238106Sdes	if(pkey->entry.data)
61238106Sdes		free(pkey->entry.data);
62238106Sdes	pkey->entry.data = NULL;
63238106Sdes	if(pkey->rk.dname)
64238106Sdes		free(pkey->rk.dname);
65238106Sdes	pkey->rk.dname = NULL;
66238106Sdes	pkey->id = 0;
67238106Sdes	alloc_special_release(alloc, pkey);
68238106Sdes}
69238106Sdes
70238106Sdessize_t
71238106Sdesub_rrset_sizefunc(void* key, void* data)
72238106Sdes{
73238106Sdes	struct ub_packed_rrset_key* k = (struct ub_packed_rrset_key*)key;
74238106Sdes	struct packed_rrset_data* d = (struct packed_rrset_data*)data;
75238106Sdes	size_t s = sizeof(struct ub_packed_rrset_key) + k->rk.dname_len;
76238106Sdes	s += packed_rrset_sizeof(d) + lock_get_mem(&k->entry.lock);
77238106Sdes	return s;
78238106Sdes}
79238106Sdes
80238106Sdessize_t
81238106Sdespacked_rrset_sizeof(struct packed_rrset_data* d)
82238106Sdes{
83238106Sdes	size_t s;
84238106Sdes	if(d->rrsig_count > 0) {
85238106Sdes		s = ((uint8_t*)d->rr_data[d->count+d->rrsig_count-1] -
86238106Sdes			(uint8_t*)d) + d->rr_len[d->count+d->rrsig_count-1];
87238106Sdes	} else {
88238106Sdes		log_assert(d->count > 0);
89238106Sdes		s = ((uint8_t*)d->rr_data[d->count-1] - (uint8_t*)d) +
90238106Sdes			d->rr_len[d->count-1];
91238106Sdes	}
92238106Sdes	return s;
93238106Sdes}
94238106Sdes
95238106Sdesint
96238106Sdesub_rrset_compare(void* k1, void* k2)
97238106Sdes{
98238106Sdes	struct ub_packed_rrset_key* key1 = (struct ub_packed_rrset_key*)k1;
99238106Sdes	struct ub_packed_rrset_key* key2 = (struct ub_packed_rrset_key*)k2;
100238106Sdes	int c;
101238106Sdes	if(key1 == key2)
102238106Sdes		return 0;
103238106Sdes	if(key1->rk.type != key2->rk.type) {
104238106Sdes		if(key1->rk.type < key2->rk.type)
105238106Sdes			return -1;
106238106Sdes		return 1;
107238106Sdes	}
108238106Sdes	if(key1->rk.dname_len != key2->rk.dname_len) {
109238106Sdes		if(key1->rk.dname_len < key2->rk.dname_len)
110238106Sdes			return -1;
111238106Sdes		return 1;
112238106Sdes	}
113238106Sdes	if((c=query_dname_compare(key1->rk.dname, key2->rk.dname)) != 0)
114238106Sdes		return c;
115238106Sdes	if(key1->rk.rrset_class != key2->rk.rrset_class) {
116238106Sdes		if(key1->rk.rrset_class < key2->rk.rrset_class)
117238106Sdes			return -1;
118238106Sdes		return 1;
119238106Sdes	}
120238106Sdes	if(key1->rk.flags != key2->rk.flags) {
121238106Sdes		if(key1->rk.flags < key2->rk.flags)
122238106Sdes			return -1;
123238106Sdes		return 1;
124238106Sdes	}
125238106Sdes	return 0;
126238106Sdes}
127238106Sdes
128238106Sdesvoid
129238106Sdesub_rrset_key_delete(void* key, void* userdata)
130238106Sdes{
131238106Sdes	struct ub_packed_rrset_key* k = (struct ub_packed_rrset_key*)key;
132238106Sdes	struct alloc_cache* a = (struct alloc_cache*)userdata;
133238106Sdes	k->id = 0;
134238106Sdes	free(k->rk.dname);
135238106Sdes	k->rk.dname = NULL;
136238106Sdes	alloc_special_release(a, k);
137238106Sdes}
138238106Sdes
139238106Sdesvoid
140238106Sdesrrset_data_delete(void* data, void* ATTR_UNUSED(userdata))
141238106Sdes{
142238106Sdes	struct packed_rrset_data* d = (struct packed_rrset_data*)data;
143238106Sdes	free(d);
144238106Sdes}
145238106Sdes
146238106Sdesint
147238106Sdesrrsetdata_equal(struct packed_rrset_data* d1, struct packed_rrset_data* d2)
148238106Sdes{
149238106Sdes	size_t i;
150238106Sdes	size_t total;
151238106Sdes	if(d1->count != d2->count || d1->rrsig_count != d2->rrsig_count)
152238106Sdes		return 0;
153238106Sdes	total = d1->count + d1->rrsig_count;
154238106Sdes	for(i=0; i<total; i++) {
155238106Sdes		if(d1->rr_len[i] != d2->rr_len[i])
156238106Sdes			return 0;
157238106Sdes		if(memcmp(d1->rr_data[i], d2->rr_data[i], d1->rr_len[i]) != 0)
158238106Sdes			return 0;
159238106Sdes	}
160238106Sdes	return 1;
161238106Sdes}
162238106Sdes
163238106Sdeshashvalue_t
164238106Sdesrrset_key_hash(struct packed_rrset_key* key)
165238106Sdes{
166238106Sdes	/* type is hashed in host order */
167238106Sdes	uint16_t t = ntohs(key->type);
168238106Sdes	/* Note this MUST be identical to pkt_hash_rrset in msgparse.c */
169238106Sdes	/* this routine does not have a compressed name */
170238106Sdes	hashvalue_t h = 0xab;
171238106Sdes	h = dname_query_hash(key->dname, h);
172238106Sdes	h = hashlittle(&t, sizeof(t), h);
173238106Sdes	h = hashlittle(&key->rrset_class, sizeof(uint16_t), h);
174238106Sdes	h = hashlittle(&key->flags, sizeof(uint32_t), h);
175238106Sdes	return h;
176238106Sdes}
177238106Sdes
178238106Sdesvoid
179238106Sdespacked_rrset_ptr_fixup(struct packed_rrset_data* data)
180238106Sdes{
181238106Sdes	size_t i;
182238106Sdes	size_t total = data->count + data->rrsig_count;
183238106Sdes	uint8_t* nextrdata;
184238106Sdes	/* fixup pointers in packed rrset data */
185238106Sdes	data->rr_len = (size_t*)((uint8_t*)data +
186238106Sdes		sizeof(struct packed_rrset_data));
187238106Sdes	data->rr_data = (uint8_t**)&(data->rr_len[total]);
188269257Sdes	data->rr_ttl = (time_t*)&(data->rr_data[total]);
189238106Sdes	nextrdata = (uint8_t*)&(data->rr_ttl[total]);
190238106Sdes	for(i=0; i<total; i++) {
191238106Sdes		data->rr_data[i] = nextrdata;
192238106Sdes		nextrdata += data->rr_len[i];
193238106Sdes	}
194238106Sdes}
195238106Sdes
196238106Sdesvoid
197238106Sdesget_cname_target(struct ub_packed_rrset_key* rrset, uint8_t** dname,
198238106Sdes	size_t* dname_len)
199238106Sdes{
200238106Sdes	struct packed_rrset_data* d;
201238106Sdes	size_t len;
202238106Sdes	if(ntohs(rrset->rk.type) != LDNS_RR_TYPE_CNAME &&
203238106Sdes		ntohs(rrset->rk.type) != LDNS_RR_TYPE_DNAME)
204238106Sdes		return;
205238106Sdes	d = (struct packed_rrset_data*)rrset->entry.data;
206238106Sdes	if(d->count < 1)
207238106Sdes		return;
208238106Sdes	if(d->rr_len[0] < 3) /* at least rdatalen + 0byte root label */
209238106Sdes		return;
210269257Sdes	len = sldns_read_uint16(d->rr_data[0]);
211238106Sdes	if(len != d->rr_len[0] - sizeof(uint16_t))
212238106Sdes		return;
213238106Sdes	if(dname_valid(d->rr_data[0]+sizeof(uint16_t), len) != len)
214238106Sdes		return;
215238106Sdes	*dname = d->rr_data[0]+sizeof(uint16_t);
216238106Sdes	*dname_len = len;
217238106Sdes}
218238106Sdes
219238106Sdesvoid
220269257Sdespacked_rrset_ttl_add(struct packed_rrset_data* data, time_t add)
221238106Sdes{
222238106Sdes	size_t i;
223238106Sdes	size_t total = data->count + data->rrsig_count;
224238106Sdes	data->ttl += add;
225238106Sdes	for(i=0; i<total; i++)
226238106Sdes		data->rr_ttl[i] += add;
227238106Sdes}
228238106Sdes
229238106Sdesconst char*
230238106Sdesrrset_trust_to_string(enum rrset_trust s)
231238106Sdes{
232238106Sdes	switch(s) {
233238106Sdes	case rrset_trust_none: 		return "rrset_trust_none";
234238106Sdes	case rrset_trust_add_noAA: 	return "rrset_trust_add_noAA";
235238106Sdes	case rrset_trust_auth_noAA: 	return "rrset_trust_auth_noAA";
236238106Sdes	case rrset_trust_add_AA: 	return "rrset_trust_add_AA";
237238106Sdes	case rrset_trust_nonauth_ans_AA:return "rrset_trust_nonauth_ans_AA";
238238106Sdes	case rrset_trust_ans_noAA: 	return "rrset_trust_ans_noAA";
239238106Sdes	case rrset_trust_glue: 		return "rrset_trust_glue";
240238106Sdes	case rrset_trust_auth_AA: 	return "rrset_trust_auth_AA";
241238106Sdes	case rrset_trust_ans_AA: 	return "rrset_trust_ans_AA";
242238106Sdes	case rrset_trust_sec_noglue: 	return "rrset_trust_sec_noglue";
243238106Sdes	case rrset_trust_prim_noglue: 	return "rrset_trust_prim_noglue";
244238106Sdes	case rrset_trust_validated: 	return "rrset_trust_validated";
245238106Sdes	case rrset_trust_ultimate: 	return "rrset_trust_ultimate";
246238106Sdes	}
247238106Sdes	return "unknown_rrset_trust_value";
248238106Sdes}
249238106Sdes
250238106Sdesconst char*
251238106Sdessec_status_to_string(enum sec_status s)
252238106Sdes{
253238106Sdes	switch(s) {
254238106Sdes	case sec_status_unchecked: 	return "sec_status_unchecked";
255238106Sdes	case sec_status_bogus: 		return "sec_status_bogus";
256238106Sdes	case sec_status_indeterminate: 	return "sec_status_indeterminate";
257238106Sdes	case sec_status_insecure: 	return "sec_status_insecure";
258238106Sdes	case sec_status_secure: 	return "sec_status_secure";
259238106Sdes	}
260238106Sdes	return "unknown_sec_status_value";
261238106Sdes}
262238106Sdes
263238106Sdesvoid log_rrset_key(enum verbosity_value v, const char* str,
264238106Sdes	struct ub_packed_rrset_key* rrset)
265238106Sdes{
266238106Sdes	if(verbosity >= v)
267238106Sdes		log_nametypeclass(v, str, rrset->rk.dname,
268238106Sdes			ntohs(rrset->rk.type), ntohs(rrset->rk.rrset_class));
269238106Sdes}
270238106Sdes
271269257Sdesint packed_rr_to_string(struct ub_packed_rrset_key* rrset, size_t i,
272269257Sdes	time_t now, char* dest, size_t dest_len)
273269257Sdes{
274269257Sdes	struct packed_rrset_data* d = (struct packed_rrset_data*)rrset->
275269257Sdes		entry.data;
276269257Sdes	uint8_t rr[65535];
277269257Sdes	size_t rlen = rrset->rk.dname_len + 2 + 2 + 4 + d->rr_len[i];
278269257Sdes	log_assert(dest_len > 0 && dest);
279269257Sdes	if(rlen > dest_len) {
280269257Sdes		dest[0] = 0;
281269257Sdes		return 0;
282269257Sdes	}
283269257Sdes	memmove(rr, rrset->rk.dname, rrset->rk.dname_len);
284269257Sdes	if(i < d->count)
285269257Sdes		memmove(rr+rrset->rk.dname_len, &rrset->rk.type, 2);
286269257Sdes	else	sldns_write_uint16(rr+rrset->rk.dname_len, LDNS_RR_TYPE_RRSIG);
287269257Sdes	memmove(rr+rrset->rk.dname_len+2, &rrset->rk.rrset_class, 2);
288269257Sdes	sldns_write_uint32(rr+rrset->rk.dname_len+4,
289269257Sdes		(uint32_t)(d->rr_ttl[i]-now));
290269257Sdes	memmove(rr+rrset->rk.dname_len+8, d->rr_data[i], d->rr_len[i]);
291269257Sdes	if(sldns_wire2str_rr_buf(rr, rlen, dest, dest_len) == -1) {
292269257Sdes		log_info("rrbuf failure %d %s", (int)d->rr_len[i], dest);
293269257Sdes		dest[0] = 0;
294269257Sdes		return 0;
295269257Sdes	}
296269257Sdes	return 1;
297269257Sdes}
298269257Sdes
299269257Sdesvoid log_packed_rrset(enum verbosity_value v, const char* str,
300269257Sdes	struct ub_packed_rrset_key* rrset)
301269257Sdes{
302269257Sdes	struct packed_rrset_data* d = (struct packed_rrset_data*)rrset->
303269257Sdes		entry.data;
304269257Sdes	char buf[65535];
305269257Sdes	size_t i;
306269257Sdes	if(verbosity < v)
307269257Sdes		return;
308269257Sdes	for(i=0; i<d->count+d->rrsig_count; i++) {
309269257Sdes		if(!packed_rr_to_string(rrset, i, 0, buf, sizeof(buf))) {
310269257Sdes			log_info("%s: rr %d wire2str-error", str, (int)i);
311269257Sdes		} else {
312269257Sdes			log_info("%s: %s", str, buf);
313269257Sdes		}
314269257Sdes	}
315269257Sdes}
316269257Sdes
317269257Sdestime_t
318238106Sdesub_packed_rrset_ttl(struct ub_packed_rrset_key* key)
319238106Sdes{
320238106Sdes	struct packed_rrset_data* d = (struct packed_rrset_data*)key->
321238106Sdes		entry.data;
322238106Sdes	return d->ttl;
323238106Sdes}
324238106Sdes
325238106Sdesstruct ub_packed_rrset_key*
326238106Sdespacked_rrset_copy_region(struct ub_packed_rrset_key* key,
327269257Sdes	struct regional* region, time_t now)
328238106Sdes{
329238106Sdes	struct ub_packed_rrset_key* ck = regional_alloc(region,
330238106Sdes		sizeof(struct ub_packed_rrset_key));
331238106Sdes	struct packed_rrset_data* d;
332238106Sdes	struct packed_rrset_data* data = (struct packed_rrset_data*)
333238106Sdes		key->entry.data;
334238106Sdes	size_t dsize, i;
335238106Sdes	if(!ck)
336238106Sdes		return NULL;
337238106Sdes	ck->id = key->id;
338238106Sdes	memset(&ck->entry, 0, sizeof(ck->entry));
339238106Sdes	ck->entry.hash = key->entry.hash;
340238106Sdes	ck->entry.key = ck;
341238106Sdes	ck->rk = key->rk;
342238106Sdes	ck->rk.dname = regional_alloc_init(region, key->rk.dname,
343238106Sdes		key->rk.dname_len);
344238106Sdes	if(!ck->rk.dname)
345238106Sdes		return NULL;
346238106Sdes	dsize = packed_rrset_sizeof(data);
347238106Sdes	d = (struct packed_rrset_data*)regional_alloc_init(region, data, dsize);
348238106Sdes	if(!d)
349238106Sdes		return NULL;
350238106Sdes	ck->entry.data = d;
351238106Sdes	packed_rrset_ptr_fixup(d);
352238106Sdes	/* make TTLs relative - once per rrset */
353238106Sdes	for(i=0; i<d->count + d->rrsig_count; i++) {
354238106Sdes		if(d->rr_ttl[i] < now)
355238106Sdes			d->rr_ttl[i] = 0;
356238106Sdes		else	d->rr_ttl[i] -= now;
357238106Sdes	}
358238106Sdes	if(d->ttl < now)
359238106Sdes		d->ttl = 0;
360238106Sdes	else	d->ttl -= now;
361238106Sdes	return ck;
362238106Sdes}
363238106Sdes
364238106Sdesstruct ub_packed_rrset_key*
365238106Sdespacked_rrset_copy_alloc(struct ub_packed_rrset_key* key,
366269257Sdes	struct alloc_cache* alloc, time_t now)
367238106Sdes{
368238106Sdes	struct packed_rrset_data* fd, *dd;
369238106Sdes	struct ub_packed_rrset_key* dk = alloc_special_obtain(alloc);
370238106Sdes	if(!dk) return NULL;
371238106Sdes	fd = (struct packed_rrset_data*)key->entry.data;
372238106Sdes	dk->entry.hash = key->entry.hash;
373238106Sdes	dk->rk = key->rk;
374238106Sdes	dk->rk.dname = (uint8_t*)memdup(key->rk.dname, key->rk.dname_len);
375238106Sdes	if(!dk->rk.dname) {
376238106Sdes		alloc_special_release(alloc, dk);
377238106Sdes		return NULL;
378238106Sdes	}
379238106Sdes	dd = (struct packed_rrset_data*)memdup(fd, packed_rrset_sizeof(fd));
380238106Sdes	if(!dd) {
381238106Sdes		free(dk->rk.dname);
382238106Sdes		alloc_special_release(alloc, dk);
383238106Sdes		return NULL;
384238106Sdes	}
385238106Sdes	packed_rrset_ptr_fixup(dd);
386238106Sdes	dk->entry.data = (void*)dd;
387238106Sdes	packed_rrset_ttl_add(dd, now);
388238106Sdes	return dk;
389238106Sdes}
390