1118611Snjl/*
2118611Snjl * util/data/packed_rrset.c - data storage for a set of resource records.
3118611Snjl *
4118611Snjl * Copyright (c) 2007, NLnet Labs. All rights reserved.
5118611Snjl *
6118611Snjl * This software is open source.
7118611Snjl *
8118611Snjl * Redistribution and use in source and binary forms, with or without
9118611Snjl * modification, are permitted provided that the following conditions
10118611Snjl * are met:
11118611Snjl *
12118611Snjl * Redistributions of source code must retain the above copyright notice,
13118611Snjl * this list of conditions and the following disclaimer.
14118611Snjl *
15118611Snjl * Redistributions in binary form must reproduce the above copyright notice,
16118611Snjl * this list of conditions and the following disclaimer in the documentation
17118611Snjl * and/or other materials provided with the distribution.
18118611Snjl *
19118611Snjl * Neither the name of the NLNET LABS nor the names of its contributors may
20118611Snjl * be used to endorse or promote products derived from this software without
21118611Snjl * specific prior written permission.
22118611Snjl *
23118611Snjl * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24118611Snjl * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25118611Snjl * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
26118611Snjl * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
27118611Snjl * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
28118611Snjl * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
29118611Snjl * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
30118611Snjl * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
31118611Snjl * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
32118611Snjl * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
33118611Snjl * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34118611Snjl */
35118611Snjl
36118611Snjl/**
37118611Snjl * \file
38118611Snjl *
39118611Snjl * This file contains the data storage for RRsets.
40118611Snjl */
41118611Snjl
42118611Snjl#include "config.h"
43118611Snjl#include "util/data/msgparse.h"
44118611Snjl#include "util/data/packed_rrset.h"
45118611Snjl#include "util/data/dname.h"
46118611Snjl#include "util/storage/lookup3.h"
47118611Snjl#include "util/log.h"
48118611Snjl#include "util/alloc.h"
49118611Snjl#include "util/regional.h"
50118611Snjl#include "util/net_help.h"
51118611Snjl#include "sldns/rrdef.h"
52118611Snjl#include "sldns/sbuffer.h"
53118611Snjl#include "sldns/wire2str.h"
54118611Snjl
55118611Snjlvoid
56118611Snjlub_packed_rrset_parsedelete(struct ub_packed_rrset_key* pkey,
57118611Snjl        struct alloc_cache* alloc)
58118611Snjl{
59118611Snjl	if(!pkey)
60118611Snjl		return;
61118611Snjl	free(pkey->entry.data);
62118611Snjl	pkey->entry.data = NULL;
63118611Snjl	free(pkey->rk.dname);
64118611Snjl	pkey->rk.dname = NULL;
65118611Snjl	pkey->id = 0;
66118611Snjl	alloc_special_release(alloc, pkey);
67118611Snjl}
68118611Snjl
69118611Snjlsize_t
70118611Snjlub_rrset_sizefunc(void* key, void* data)
71118611Snjl{
72118611Snjl	struct ub_packed_rrset_key* k = (struct ub_packed_rrset_key*)key;
73118611Snjl	struct packed_rrset_data* d = (struct packed_rrset_data*)data;
74118611Snjl	size_t s = sizeof(struct ub_packed_rrset_key) + k->rk.dname_len;
75118611Snjl	s += packed_rrset_sizeof(d) + lock_get_mem(&k->entry.lock);
76118611Snjl	return s;
77118611Snjl}
78118611Snjl
79118611Snjlsize_t
80118611Snjlpacked_rrset_sizeof(struct packed_rrset_data* d)
81118611Snjl{
82118611Snjl	size_t s;
83118611Snjl	if(d->rrsig_count > 0) {
84118611Snjl		s = ((uint8_t*)d->rr_data[d->count+d->rrsig_count-1] -
85118611Snjl			(uint8_t*)d) + d->rr_len[d->count+d->rrsig_count-1];
86118611Snjl	} else {
87118611Snjl		log_assert(d->count > 0);
88118611Snjl		s = ((uint8_t*)d->rr_data[d->count-1] - (uint8_t*)d) +
89118611Snjl			d->rr_len[d->count-1];
90118611Snjl	}
91118611Snjl	return s;
92118611Snjl}
93118611Snjl
94118611Snjlint
95118611Snjlub_rrset_compare(void* k1, void* k2)
96118611Snjl{
97118611Snjl	struct ub_packed_rrset_key* key1 = (struct ub_packed_rrset_key*)k1;
98118611Snjl	struct ub_packed_rrset_key* key2 = (struct ub_packed_rrset_key*)k2;
99118611Snjl	int c;
100118611Snjl	if(key1 == key2)
101118611Snjl		return 0;
102118611Snjl	if(key1->rk.type != key2->rk.type) {
103118611Snjl		if(key1->rk.type < key2->rk.type)
104118611Snjl			return -1;
105118611Snjl		return 1;
106118611Snjl	}
107118611Snjl	if(key1->rk.dname_len != key2->rk.dname_len) {
108118611Snjl		if(key1->rk.dname_len < key2->rk.dname_len)
109118611Snjl			return -1;
110118611Snjl		return 1;
111118611Snjl	}
112118611Snjl	if((c=query_dname_compare(key1->rk.dname, key2->rk.dname)) != 0)
113118611Snjl		return c;
114118611Snjl	if(key1->rk.rrset_class != key2->rk.rrset_class) {
115118611Snjl		if(key1->rk.rrset_class < key2->rk.rrset_class)
116118611Snjl			return -1;
117118611Snjl		return 1;
118118611Snjl	}
119118611Snjl	if(key1->rk.flags != key2->rk.flags) {
120118611Snjl		if(key1->rk.flags < key2->rk.flags)
121118611Snjl			return -1;
122118611Snjl		return 1;
123118611Snjl	}
124118611Snjl	return 0;
125118611Snjl}
126118611Snjl
127118611Snjlvoid
128118611Snjlub_rrset_key_delete(void* key, void* userdata)
129118611Snjl{
130118611Snjl	struct ub_packed_rrset_key* k = (struct ub_packed_rrset_key*)key;
131118611Snjl	struct alloc_cache* a = (struct alloc_cache*)userdata;
132118611Snjl	k->id = 0;
133118611Snjl	free(k->rk.dname);
134118611Snjl	k->rk.dname = NULL;
135118611Snjl	alloc_special_release(a, k);
136118611Snjl}
137118611Snjl
138118611Snjlvoid
139118611Snjlrrset_data_delete(void* data, void* ATTR_UNUSED(userdata))
140118611Snjl{
141118611Snjl	struct packed_rrset_data* d = (struct packed_rrset_data*)data;
142118611Snjl	free(d);
143118611Snjl}
144118611Snjl
145118611Snjlint
146118611Snjlrrsetdata_equal(struct packed_rrset_data* d1, struct packed_rrset_data* d2)
147118611Snjl{
148118611Snjl	size_t i;
149118611Snjl	size_t total;
150118611Snjl	if(d1->count != d2->count || d1->rrsig_count != d2->rrsig_count)
151118611Snjl		return 0;
152118611Snjl	total = d1->count + d1->rrsig_count;
153118611Snjl	for(i=0; i<total; i++) {
154118611Snjl		if(d1->rr_len[i] != d2->rr_len[i])
155118611Snjl			return 0;
156118611Snjl		if(memcmp(d1->rr_data[i], d2->rr_data[i], d1->rr_len[i]) != 0)
157118611Snjl			return 0;
158118611Snjl	}
159118611Snjl	return 1;
160118611Snjl}
161118611Snjl
162118611Snjlhashvalue_type
163118611Snjlrrset_key_hash(struct packed_rrset_key* key)
164118611Snjl{
165118611Snjl	/* type is hashed in host order */
166118611Snjl	uint16_t t = ntohs(key->type);
167118611Snjl	/* Note this MUST be identical to pkt_hash_rrset in msgparse.c */
168118611Snjl	/* this routine does not have a compressed name */
169118611Snjl	hashvalue_type h = 0xab;
170118611Snjl	h = dname_query_hash(key->dname, h);
171118611Snjl	h = hashlittle(&t, sizeof(t), h);
172118611Snjl	h = hashlittle(&key->rrset_class, sizeof(uint16_t), h);
173118611Snjl	h = hashlittle(&key->flags, sizeof(uint32_t), h);
174118611Snjl	return h;
175118611Snjl}
176118611Snjl
177118611Snjlvoid
178118611Snjlpacked_rrset_ptr_fixup(struct packed_rrset_data* data)
179118611Snjl{
180118611Snjl	size_t i;
181118611Snjl	size_t total = data->count + data->rrsig_count;
182118611Snjl	uint8_t* nextrdata;
183118611Snjl	/* fixup pointers in packed rrset data */
184118611Snjl	data->rr_len = (size_t*)((uint8_t*)data +
185118611Snjl		sizeof(struct packed_rrset_data));
186118611Snjl	data->rr_data = (uint8_t**)&(data->rr_len[total]);
187118611Snjl	data->rr_ttl = (time_t*)&(data->rr_data[total]);
188118611Snjl	nextrdata = (uint8_t*)&(data->rr_ttl[total]);
189118611Snjl	for(i=0; i<total; i++) {
190118611Snjl		data->rr_data[i] = nextrdata;
191118611Snjl		nextrdata += data->rr_len[i];
192118611Snjl	}
193118611Snjl}
194118611Snjl
195118611Snjlvoid
196118611Snjlget_cname_target(struct ub_packed_rrset_key* rrset, uint8_t** dname,
197118611Snjl	size_t* dname_len)
198118611Snjl{
199118611Snjl	struct packed_rrset_data* d;
200118611Snjl	size_t len;
201118611Snjl	if(ntohs(rrset->rk.type) != LDNS_RR_TYPE_CNAME &&
202118611Snjl		ntohs(rrset->rk.type) != LDNS_RR_TYPE_DNAME)
203118611Snjl		return;
204118611Snjl	d = (struct packed_rrset_data*)rrset->entry.data;
205118611Snjl	if(d->count < 1)
206118611Snjl		return;
207118611Snjl	if(d->rr_len[0] < 3) /* at least rdatalen + 0byte root label */
208118611Snjl		return;
209118611Snjl	len = sldns_read_uint16(d->rr_data[0]);
210118611Snjl	if(len != d->rr_len[0] - sizeof(uint16_t))
211118611Snjl		return;
212118611Snjl	if(dname_valid(d->rr_data[0]+sizeof(uint16_t), len) != len)
213118611Snjl		return;
214118611Snjl	*dname = d->rr_data[0]+sizeof(uint16_t);
215118611Snjl	*dname_len = len;
216118611Snjl}
217118611Snjl
218118611Snjlvoid
219118611Snjlpacked_rrset_ttl_add(struct packed_rrset_data* data, time_t add)
220118611Snjl{
221118611Snjl	size_t i;
222118611Snjl	size_t total = data->count + data->rrsig_count;
223118611Snjl	data->ttl_add = add;
224118611Snjl	data->ttl += add;
225118611Snjl	for(i=0; i<total; i++)
226118611Snjl		data->rr_ttl[i] += add;
227118611Snjl}
228118611Snjl
229118611Snjlconst char*
230118611Snjlrrset_trust_to_string(enum rrset_trust s)
231118611Snjl{
232118611Snjl	switch(s) {
233118611Snjl	case rrset_trust_none: 		return "rrset_trust_none";
234118611Snjl	case rrset_trust_add_noAA: 	return "rrset_trust_add_noAA";
235118611Snjl	case rrset_trust_auth_noAA: 	return "rrset_trust_auth_noAA";
236118611Snjl	case rrset_trust_add_AA: 	return "rrset_trust_add_AA";
237118611Snjl	case rrset_trust_nonauth_ans_AA:return "rrset_trust_nonauth_ans_AA";
238118611Snjl	case rrset_trust_ans_noAA: 	return "rrset_trust_ans_noAA";
239118611Snjl	case rrset_trust_glue: 		return "rrset_trust_glue";
240118611Snjl	case rrset_trust_auth_AA: 	return "rrset_trust_auth_AA";
241118611Snjl	case rrset_trust_ans_AA: 	return "rrset_trust_ans_AA";
242118611Snjl	case rrset_trust_sec_noglue: 	return "rrset_trust_sec_noglue";
243118611Snjl	case rrset_trust_prim_noglue: 	return "rrset_trust_prim_noglue";
244118611Snjl	case rrset_trust_validated: 	return "rrset_trust_validated";
245118611Snjl	case rrset_trust_ultimate: 	return "rrset_trust_ultimate";
246118611Snjl	}
247118611Snjl	return "unknown_rrset_trust_value";
248118611Snjl}
249118611Snjl
250118611Snjlconst char*
251118611Snjlsec_status_to_string(enum sec_status s)
252118611Snjl{
253118611Snjl	switch(s) {
254118611Snjl	case sec_status_unchecked: 	return "sec_status_unchecked";
255118611Snjl	case sec_status_bogus: 		return "sec_status_bogus";
256118611Snjl	case sec_status_indeterminate: 	return "sec_status_indeterminate";
257118611Snjl	case sec_status_insecure: 	return "sec_status_insecure";
258118611Snjl	case sec_status_secure_sentinel_fail: 	return "sec_status_secure_sentinel_fail";
259118611Snjl	case sec_status_secure: 	return "sec_status_secure";
260118611Snjl	}
261118611Snjl	return "unknown_sec_status_value";
262118611Snjl}
263118611Snjl
264118611Snjlvoid log_rrset_key(enum verbosity_value v, const char* str,
265118611Snjl	struct ub_packed_rrset_key* rrset)
266118611Snjl{
267118611Snjl	if(verbosity >= v)
268118611Snjl		log_nametypeclass(v, str, rrset->rk.dname,
269118611Snjl			ntohs(rrset->rk.type), ntohs(rrset->rk.rrset_class));
270118611Snjl}
271118611Snjl
272118611Snjlint packed_rr_to_string(struct ub_packed_rrset_key* rrset, size_t i,
273118611Snjl	time_t now, char* dest, size_t dest_len)
274118611Snjl{
275118611Snjl	struct packed_rrset_data* d = (struct packed_rrset_data*)rrset->
276118611Snjl		entry.data;
277118611Snjl	uint8_t rr[65535];
278118611Snjl	size_t rlen = rrset->rk.dname_len + 2 + 2 + 4 + d->rr_len[i];
279118611Snjl	time_t adjust = 0;
280118611Snjl	log_assert(dest_len > 0 && dest);
281118611Snjl	if(rlen > dest_len) {
282118611Snjl		dest[0] = 0;
283118611Snjl		return 0;
284118611Snjl	}
285118611Snjl	memmove(rr, rrset->rk.dname, rrset->rk.dname_len);
286118611Snjl	if(i < d->count)
287118611Snjl		memmove(rr+rrset->rk.dname_len, &rrset->rk.type, 2);
288118611Snjl	else	sldns_write_uint16(rr+rrset->rk.dname_len, LDNS_RR_TYPE_RRSIG);
289118611Snjl	memmove(rr+rrset->rk.dname_len+2, &rrset->rk.rrset_class, 2);
290118611Snjl	adjust = SERVE_ORIGINAL_TTL ? d->ttl_add : now;
291118611Snjl	if (d->rr_ttl[i] < adjust) adjust = d->rr_ttl[i]; /* Prevent negative TTL overflow */
292118611Snjl	sldns_write_uint32(rr+rrset->rk.dname_len+4,
293118611Snjl		(uint32_t)(d->rr_ttl[i]-adjust));
294118611Snjl	memmove(rr+rrset->rk.dname_len+8, d->rr_data[i], d->rr_len[i]);
295118611Snjl	if(sldns_wire2str_rr_buf(rr, rlen, dest, dest_len) == -1) {
296118611Snjl		log_info("rrbuf failure %d %s", (int)d->rr_len[i], dest);
297118611Snjl		dest[0] = 0;
298118611Snjl		return 0;
299118611Snjl	}
300118611Snjl	return 1;
301118611Snjl}
302118611Snjl
303118611Snjlvoid log_packed_rrset(enum verbosity_value v, const char* str,
304118611Snjl	struct ub_packed_rrset_key* rrset)
305118611Snjl{
306118611Snjl	struct packed_rrset_data* d = (struct packed_rrset_data*)rrset->
307118611Snjl		entry.data;
308118611Snjl	char buf[65535];
309118611Snjl	size_t i;
310118611Snjl	if(verbosity < v)
311118611Snjl		return;
312118611Snjl	for(i=0; i<d->count+d->rrsig_count; i++) {
313118611Snjl		if(!packed_rr_to_string(rrset, i, 0, buf, sizeof(buf))) {
314118611Snjl			log_info("%s: rr %d wire2str-error", str, (int)i);
315118611Snjl		} else {
316118611Snjl			log_info("%s: %s", str, buf);
317118611Snjl		}
318118611Snjl	}
319118611Snjl}
320118611Snjl
321118611Snjltime_t
322118611Snjlub_packed_rrset_ttl(struct ub_packed_rrset_key* key)
323118611Snjl{
324118611Snjl	struct packed_rrset_data* d = (struct packed_rrset_data*)key->
325118611Snjl		entry.data;
326118611Snjl	return d->ttl;
327118611Snjl}
328118611Snjl
329118611Snjlstruct ub_packed_rrset_key*
330118611Snjlpacked_rrset_copy_region(struct ub_packed_rrset_key* key,
331118611Snjl	struct regional* region, time_t now)
332118611Snjl{
333118611Snjl	struct ub_packed_rrset_key* ck = regional_alloc(region,
334118611Snjl		sizeof(struct ub_packed_rrset_key));
335118611Snjl	struct packed_rrset_data* d;
336118611Snjl	struct packed_rrset_data* data = (struct packed_rrset_data*)
337118611Snjl		key->entry.data;
338118611Snjl	size_t dsize, i;
339118611Snjl	time_t adjust = 0;
340118611Snjl	if(!ck)
341118611Snjl		return NULL;
342118611Snjl	ck->id = key->id;
343118611Snjl	memset(&ck->entry, 0, sizeof(ck->entry));
344118611Snjl	ck->entry.hash = key->entry.hash;
345118611Snjl	ck->entry.key = ck;
346118611Snjl	ck->rk = key->rk;
347118611Snjl	ck->rk.dname = regional_alloc_init(region, key->rk.dname,
348118611Snjl		key->rk.dname_len);
349118611Snjl	if(!ck->rk.dname)
350118611Snjl		return NULL;
351118611Snjl	dsize = packed_rrset_sizeof(data);
352118611Snjl	d = (struct packed_rrset_data*)regional_alloc_init(region, data, dsize);
353118611Snjl	if(!d)
354118611Snjl		return NULL;
355118611Snjl	ck->entry.data = d;
356118611Snjl	packed_rrset_ptr_fixup(d);
357118611Snjl	/* make TTLs relative - once per rrset */
358118611Snjl	adjust = SERVE_ORIGINAL_TTL ? data->ttl_add : now;
359118611Snjl	for(i=0; i<d->count + d->rrsig_count; i++) {
360118611Snjl		if(d->rr_ttl[i] < adjust)
361118611Snjl			d->rr_ttl[i] = SERVE_EXPIRED?SERVE_EXPIRED_REPLY_TTL:0;
362118611Snjl		else	d->rr_ttl[i] -= adjust;
363118611Snjl	}
364118611Snjl	if(d->ttl < adjust)
365118611Snjl		d->ttl = SERVE_EXPIRED?SERVE_EXPIRED_REPLY_TTL:0;
366118611Snjl	else	d->ttl -= adjust;
367118611Snjl	d->ttl_add = 0; /* TTLs have been made relative */
368118611Snjl	return ck;
369118611Snjl}
370118611Snjl
371118611Snjlstruct ub_packed_rrset_key*
372118611Snjlpacked_rrset_copy_alloc(struct ub_packed_rrset_key* key,
373118611Snjl	struct alloc_cache* alloc, time_t now)
374118611Snjl{
375118611Snjl	struct packed_rrset_data* fd, *dd;
376118611Snjl	struct ub_packed_rrset_key* dk = alloc_special_obtain(alloc);
377118611Snjl	if(!dk) return NULL;
378118611Snjl	fd = (struct packed_rrset_data*)key->entry.data;
379118611Snjl	dk->entry.hash = key->entry.hash;
380118611Snjl	dk->rk = key->rk;
381118611Snjl	dk->rk.dname = (uint8_t*)memdup(key->rk.dname, key->rk.dname_len);
382118611Snjl	if(!dk->rk.dname) {
383118611Snjl		alloc_special_release(alloc, dk);
384118611Snjl		return NULL;
385118611Snjl	}
386118611Snjl	dd = (struct packed_rrset_data*)memdup(fd, packed_rrset_sizeof(fd));
387118611Snjl	if(!dd) {
388118611Snjl		free(dk->rk.dname);
389118611Snjl		alloc_special_release(alloc, dk);
390118611Snjl		return NULL;
391118611Snjl	}
392118611Snjl	packed_rrset_ptr_fixup(dd);
393118611Snjl	dk->entry.data = (void*)dd;
394118611Snjl	packed_rrset_ttl_add(dd, now);
395118611Snjl	return dk;
396118611Snjl}
397118611Snjl
398118611Snjlint
399118611Snjlpacked_rrset_find_rr(struct packed_rrset_data* d, uint8_t* rdata, size_t len,
400118611Snjl	size_t* index)
401118611Snjl{
402118611Snjl	size_t i;
403118611Snjl	for(i=0; i<d->count; i++) {
404118611Snjl		if(d->rr_len[i] != len)
405118611Snjl			continue;
406118611Snjl		if(memcmp(d->rr_data[i], rdata, len) == 0) {
407118611Snjl			*index = i;
408118611Snjl			return 1;
409118611Snjl		}
410118611Snjl	}
411118611Snjl	return 0;
412118611Snjl}
413118611Snjl