a85b5759f3
These files were pulled from the 1.6.3 release tarball. This new version builds against OpenSSL version 1.1 which will be the default in the new Debian Stable which is due to be released RealSoonNow (tm).
387 lines
11 KiB
C
387 lines
11 KiB
C
/*
|
|
* util/data/packed_rrset.c - data storage for a set of resource records.
|
|
*
|
|
* Copyright (c) 2007, NLnet Labs. All rights reserved.
|
|
*
|
|
* This software is open source.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions
|
|
* are met:
|
|
*
|
|
* Redistributions of source code must retain the above copyright notice,
|
|
* this list of conditions and the following disclaimer.
|
|
*
|
|
* Redistributions in binary form must reproduce the above copyright notice,
|
|
* this list of conditions and the following disclaimer in the documentation
|
|
* and/or other materials provided with the distribution.
|
|
*
|
|
* Neither the name of the NLNET LABS nor the names of its contributors may
|
|
* be used to endorse or promote products derived from this software without
|
|
* specific prior written permission.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
|
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
|
* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
|
|
* TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
|
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
|
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
|
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
*/
|
|
|
|
/**
|
|
* \file
|
|
*
|
|
* This file contains the data storage for RRsets.
|
|
*/
|
|
|
|
#include "config.h"
|
|
#include "util/data/packed_rrset.h"
|
|
#include "util/data/dname.h"
|
|
#include "util/storage/lookup3.h"
|
|
#include "util/log.h"
|
|
#include "util/alloc.h"
|
|
#include "util/regional.h"
|
|
#include "util/net_help.h"
|
|
#include "sldns/rrdef.h"
|
|
#include "sldns/sbuffer.h"
|
|
#include "sldns/wire2str.h"
|
|
|
|
void
|
|
ub_packed_rrset_parsedelete(struct ub_packed_rrset_key* pkey,
|
|
struct alloc_cache* alloc)
|
|
{
|
|
if(!pkey)
|
|
return;
|
|
free(pkey->entry.data);
|
|
pkey->entry.data = NULL;
|
|
free(pkey->rk.dname);
|
|
pkey->rk.dname = NULL;
|
|
pkey->id = 0;
|
|
alloc_special_release(alloc, pkey);
|
|
}
|
|
|
|
size_t
|
|
ub_rrset_sizefunc(void* key, void* data)
|
|
{
|
|
struct ub_packed_rrset_key* k = (struct ub_packed_rrset_key*)key;
|
|
struct packed_rrset_data* d = (struct packed_rrset_data*)data;
|
|
size_t s = sizeof(struct ub_packed_rrset_key) + k->rk.dname_len;
|
|
s += packed_rrset_sizeof(d) + lock_get_mem(&k->entry.lock);
|
|
return s;
|
|
}
|
|
|
|
size_t
|
|
packed_rrset_sizeof(struct packed_rrset_data* d)
|
|
{
|
|
size_t s;
|
|
if(d->rrsig_count > 0) {
|
|
s = ((uint8_t*)d->rr_data[d->count+d->rrsig_count-1] -
|
|
(uint8_t*)d) + d->rr_len[d->count+d->rrsig_count-1];
|
|
} else {
|
|
log_assert(d->count > 0);
|
|
s = ((uint8_t*)d->rr_data[d->count-1] - (uint8_t*)d) +
|
|
d->rr_len[d->count-1];
|
|
}
|
|
return s;
|
|
}
|
|
|
|
int
|
|
ub_rrset_compare(void* k1, void* k2)
|
|
{
|
|
struct ub_packed_rrset_key* key1 = (struct ub_packed_rrset_key*)k1;
|
|
struct ub_packed_rrset_key* key2 = (struct ub_packed_rrset_key*)k2;
|
|
int c;
|
|
if(key1 == key2)
|
|
return 0;
|
|
if(key1->rk.type != key2->rk.type) {
|
|
if(key1->rk.type < key2->rk.type)
|
|
return -1;
|
|
return 1;
|
|
}
|
|
if(key1->rk.dname_len != key2->rk.dname_len) {
|
|
if(key1->rk.dname_len < key2->rk.dname_len)
|
|
return -1;
|
|
return 1;
|
|
}
|
|
if((c=query_dname_compare(key1->rk.dname, key2->rk.dname)) != 0)
|
|
return c;
|
|
if(key1->rk.rrset_class != key2->rk.rrset_class) {
|
|
if(key1->rk.rrset_class < key2->rk.rrset_class)
|
|
return -1;
|
|
return 1;
|
|
}
|
|
if(key1->rk.flags != key2->rk.flags) {
|
|
if(key1->rk.flags < key2->rk.flags)
|
|
return -1;
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
void
|
|
ub_rrset_key_delete(void* key, void* userdata)
|
|
{
|
|
struct ub_packed_rrset_key* k = (struct ub_packed_rrset_key*)key;
|
|
struct alloc_cache* a = (struct alloc_cache*)userdata;
|
|
k->id = 0;
|
|
free(k->rk.dname);
|
|
k->rk.dname = NULL;
|
|
alloc_special_release(a, k);
|
|
}
|
|
|
|
void
|
|
rrset_data_delete(void* data, void* ATTR_UNUSED(userdata))
|
|
{
|
|
struct packed_rrset_data* d = (struct packed_rrset_data*)data;
|
|
free(d);
|
|
}
|
|
|
|
int
|
|
rrsetdata_equal(struct packed_rrset_data* d1, struct packed_rrset_data* d2)
|
|
{
|
|
size_t i;
|
|
size_t total;
|
|
if(d1->count != d2->count || d1->rrsig_count != d2->rrsig_count)
|
|
return 0;
|
|
total = d1->count + d1->rrsig_count;
|
|
for(i=0; i<total; i++) {
|
|
if(d1->rr_len[i] != d2->rr_len[i])
|
|
return 0;
|
|
if(memcmp(d1->rr_data[i], d2->rr_data[i], d1->rr_len[i]) != 0)
|
|
return 0;
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
hashvalue_type
|
|
rrset_key_hash(struct packed_rrset_key* key)
|
|
{
|
|
/* type is hashed in host order */
|
|
uint16_t t = ntohs(key->type);
|
|
/* Note this MUST be identical to pkt_hash_rrset in msgparse.c */
|
|
/* this routine does not have a compressed name */
|
|
hashvalue_type h = 0xab;
|
|
h = dname_query_hash(key->dname, h);
|
|
h = hashlittle(&t, sizeof(t), h);
|
|
h = hashlittle(&key->rrset_class, sizeof(uint16_t), h);
|
|
h = hashlittle(&key->flags, sizeof(uint32_t), h);
|
|
return h;
|
|
}
|
|
|
|
void
|
|
packed_rrset_ptr_fixup(struct packed_rrset_data* data)
|
|
{
|
|
size_t i;
|
|
size_t total = data->count + data->rrsig_count;
|
|
uint8_t* nextrdata;
|
|
/* fixup pointers in packed rrset data */
|
|
data->rr_len = (size_t*)((uint8_t*)data +
|
|
sizeof(struct packed_rrset_data));
|
|
data->rr_data = (uint8_t**)&(data->rr_len[total]);
|
|
data->rr_ttl = (time_t*)&(data->rr_data[total]);
|
|
nextrdata = (uint8_t*)&(data->rr_ttl[total]);
|
|
for(i=0; i<total; i++) {
|
|
data->rr_data[i] = nextrdata;
|
|
nextrdata += data->rr_len[i];
|
|
}
|
|
}
|
|
|
|
void
|
|
get_cname_target(struct ub_packed_rrset_key* rrset, uint8_t** dname,
|
|
size_t* dname_len)
|
|
{
|
|
struct packed_rrset_data* d;
|
|
size_t len;
|
|
if(ntohs(rrset->rk.type) != LDNS_RR_TYPE_CNAME &&
|
|
ntohs(rrset->rk.type) != LDNS_RR_TYPE_DNAME)
|
|
return;
|
|
d = (struct packed_rrset_data*)rrset->entry.data;
|
|
if(d->count < 1)
|
|
return;
|
|
if(d->rr_len[0] < 3) /* at least rdatalen + 0byte root label */
|
|
return;
|
|
len = sldns_read_uint16(d->rr_data[0]);
|
|
if(len != d->rr_len[0] - sizeof(uint16_t))
|
|
return;
|
|
if(dname_valid(d->rr_data[0]+sizeof(uint16_t), len) != len)
|
|
return;
|
|
*dname = d->rr_data[0]+sizeof(uint16_t);
|
|
*dname_len = len;
|
|
}
|
|
|
|
void
|
|
packed_rrset_ttl_add(struct packed_rrset_data* data, time_t add)
|
|
{
|
|
size_t i;
|
|
size_t total = data->count + data->rrsig_count;
|
|
data->ttl += add;
|
|
for(i=0; i<total; i++)
|
|
data->rr_ttl[i] += add;
|
|
}
|
|
|
|
const char*
|
|
rrset_trust_to_string(enum rrset_trust s)
|
|
{
|
|
switch(s) {
|
|
case rrset_trust_none: return "rrset_trust_none";
|
|
case rrset_trust_add_noAA: return "rrset_trust_add_noAA";
|
|
case rrset_trust_auth_noAA: return "rrset_trust_auth_noAA";
|
|
case rrset_trust_add_AA: return "rrset_trust_add_AA";
|
|
case rrset_trust_nonauth_ans_AA:return "rrset_trust_nonauth_ans_AA";
|
|
case rrset_trust_ans_noAA: return "rrset_trust_ans_noAA";
|
|
case rrset_trust_glue: return "rrset_trust_glue";
|
|
case rrset_trust_auth_AA: return "rrset_trust_auth_AA";
|
|
case rrset_trust_ans_AA: return "rrset_trust_ans_AA";
|
|
case rrset_trust_sec_noglue: return "rrset_trust_sec_noglue";
|
|
case rrset_trust_prim_noglue: return "rrset_trust_prim_noglue";
|
|
case rrset_trust_validated: return "rrset_trust_validated";
|
|
case rrset_trust_ultimate: return "rrset_trust_ultimate";
|
|
}
|
|
return "unknown_rrset_trust_value";
|
|
}
|
|
|
|
const char*
|
|
sec_status_to_string(enum sec_status s)
|
|
{
|
|
switch(s) {
|
|
case sec_status_unchecked: return "sec_status_unchecked";
|
|
case sec_status_bogus: return "sec_status_bogus";
|
|
case sec_status_indeterminate: return "sec_status_indeterminate";
|
|
case sec_status_insecure: return "sec_status_insecure";
|
|
case sec_status_secure: return "sec_status_secure";
|
|
}
|
|
return "unknown_sec_status_value";
|
|
}
|
|
|
|
void log_rrset_key(enum verbosity_value v, const char* str,
|
|
struct ub_packed_rrset_key* rrset)
|
|
{
|
|
if(verbosity >= v)
|
|
log_nametypeclass(v, str, rrset->rk.dname,
|
|
ntohs(rrset->rk.type), ntohs(rrset->rk.rrset_class));
|
|
}
|
|
|
|
int packed_rr_to_string(struct ub_packed_rrset_key* rrset, size_t i,
|
|
time_t now, char* dest, size_t dest_len)
|
|
{
|
|
struct packed_rrset_data* d = (struct packed_rrset_data*)rrset->
|
|
entry.data;
|
|
uint8_t rr[65535];
|
|
size_t rlen = rrset->rk.dname_len + 2 + 2 + 4 + d->rr_len[i];
|
|
log_assert(dest_len > 0 && dest);
|
|
if(rlen > dest_len) {
|
|
dest[0] = 0;
|
|
return 0;
|
|
}
|
|
memmove(rr, rrset->rk.dname, rrset->rk.dname_len);
|
|
if(i < d->count)
|
|
memmove(rr+rrset->rk.dname_len, &rrset->rk.type, 2);
|
|
else sldns_write_uint16(rr+rrset->rk.dname_len, LDNS_RR_TYPE_RRSIG);
|
|
memmove(rr+rrset->rk.dname_len+2, &rrset->rk.rrset_class, 2);
|
|
sldns_write_uint32(rr+rrset->rk.dname_len+4,
|
|
(uint32_t)(d->rr_ttl[i]-now));
|
|
memmove(rr+rrset->rk.dname_len+8, d->rr_data[i], d->rr_len[i]);
|
|
if(sldns_wire2str_rr_buf(rr, rlen, dest, dest_len) == -1) {
|
|
log_info("rrbuf failure %d %s", (int)d->rr_len[i], dest);
|
|
dest[0] = 0;
|
|
return 0;
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
void log_packed_rrset(enum verbosity_value v, const char* str,
|
|
struct ub_packed_rrset_key* rrset)
|
|
{
|
|
struct packed_rrset_data* d = (struct packed_rrset_data*)rrset->
|
|
entry.data;
|
|
char buf[65535];
|
|
size_t i;
|
|
if(verbosity < v)
|
|
return;
|
|
for(i=0; i<d->count+d->rrsig_count; i++) {
|
|
if(!packed_rr_to_string(rrset, i, 0, buf, sizeof(buf))) {
|
|
log_info("%s: rr %d wire2str-error", str, (int)i);
|
|
} else {
|
|
log_info("%s: %s", str, buf);
|
|
}
|
|
}
|
|
}
|
|
|
|
time_t
|
|
ub_packed_rrset_ttl(struct ub_packed_rrset_key* key)
|
|
{
|
|
struct packed_rrset_data* d = (struct packed_rrset_data*)key->
|
|
entry.data;
|
|
return d->ttl;
|
|
}
|
|
|
|
struct ub_packed_rrset_key*
|
|
packed_rrset_copy_region(struct ub_packed_rrset_key* key,
|
|
struct regional* region, time_t now)
|
|
{
|
|
struct ub_packed_rrset_key* ck = regional_alloc(region,
|
|
sizeof(struct ub_packed_rrset_key));
|
|
struct packed_rrset_data* d;
|
|
struct packed_rrset_data* data = (struct packed_rrset_data*)
|
|
key->entry.data;
|
|
size_t dsize, i;
|
|
if(!ck)
|
|
return NULL;
|
|
ck->id = key->id;
|
|
memset(&ck->entry, 0, sizeof(ck->entry));
|
|
ck->entry.hash = key->entry.hash;
|
|
ck->entry.key = ck;
|
|
ck->rk = key->rk;
|
|
ck->rk.dname = regional_alloc_init(region, key->rk.dname,
|
|
key->rk.dname_len);
|
|
if(!ck->rk.dname)
|
|
return NULL;
|
|
dsize = packed_rrset_sizeof(data);
|
|
d = (struct packed_rrset_data*)regional_alloc_init(region, data, dsize);
|
|
if(!d)
|
|
return NULL;
|
|
ck->entry.data = d;
|
|
packed_rrset_ptr_fixup(d);
|
|
/* make TTLs relative - once per rrset */
|
|
for(i=0; i<d->count + d->rrsig_count; i++) {
|
|
if(d->rr_ttl[i] < now)
|
|
d->rr_ttl[i] = 0;
|
|
else d->rr_ttl[i] -= now;
|
|
}
|
|
if(d->ttl < now)
|
|
d->ttl = 0;
|
|
else d->ttl -= now;
|
|
return ck;
|
|
}
|
|
|
|
struct ub_packed_rrset_key*
|
|
packed_rrset_copy_alloc(struct ub_packed_rrset_key* key,
|
|
struct alloc_cache* alloc, time_t now)
|
|
{
|
|
struct packed_rrset_data* fd, *dd;
|
|
struct ub_packed_rrset_key* dk = alloc_special_obtain(alloc);
|
|
if(!dk) return NULL;
|
|
fd = (struct packed_rrset_data*)key->entry.data;
|
|
dk->entry.hash = key->entry.hash;
|
|
dk->rk = key->rk;
|
|
dk->rk.dname = (uint8_t*)memdup(key->rk.dname, key->rk.dname_len);
|
|
if(!dk->rk.dname) {
|
|
alloc_special_release(alloc, dk);
|
|
return NULL;
|
|
}
|
|
dd = (struct packed_rrset_data*)memdup(fd, packed_rrset_sizeof(fd));
|
|
if(!dd) {
|
|
free(dk->rk.dname);
|
|
alloc_special_release(alloc, dk);
|
|
return NULL;
|
|
}
|
|
packed_rrset_ptr_fixup(dd);
|
|
dk->entry.data = (void*)dd;
|
|
packed_rrset_ttl_add(dd, now);
|
|
return dk;
|
|
}
|