Coverage Report

Created: 2025-07-18 07:01

/src/unbound/util/data/packed_rrset.c
Line
Count
Source (jump to first uncovered line)
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
0
{
59
0
  if(!pkey)
60
0
    return;
61
0
  free(pkey->entry.data);
62
0
  pkey->entry.data = NULL;
63
0
  free(pkey->rk.dname);
64
0
  pkey->rk.dname = NULL;
65
0
  pkey->id = 0;
66
0
  alloc_special_release(alloc, pkey);
67
0
}
68
69
size_t 
70
ub_rrset_sizefunc(void* key, void* data)
71
9.44k
{
72
9.44k
  struct ub_packed_rrset_key* k = (struct ub_packed_rrset_key*)key;
73
9.44k
  struct packed_rrset_data* d = (struct packed_rrset_data*)data;
74
9.44k
  size_t s = sizeof(struct ub_packed_rrset_key) + k->rk.dname_len;
75
9.44k
  s += packed_rrset_sizeof(d) + lock_get_mem(&k->entry.lock);
76
9.44k
  return s;
77
9.44k
}
78
79
size_t 
80
packed_rrset_sizeof(struct packed_rrset_data* d)
81
9.44k
{
82
9.44k
  size_t s;
83
9.44k
  if(d->rrsig_count > 0) {
84
154
    s = ((uint8_t*)d->rr_data[d->count+d->rrsig_count-1] - 
85
154
      (uint8_t*)d) + d->rr_len[d->count+d->rrsig_count-1];
86
9.29k
  } else {
87
9.29k
    log_assert(d->count > 0);
88
9.29k
    s = ((uint8_t*)d->rr_data[d->count-1] - (uint8_t*)d) + 
89
9.29k
      d->rr_len[d->count-1];
90
9.29k
  }
91
9.44k
  return s;
92
9.44k
}
93
94
int 
95
ub_rrset_compare(void* k1, void* k2)
96
120
{
97
120
  struct ub_packed_rrset_key* key1 = (struct ub_packed_rrset_key*)k1;
98
120
  struct ub_packed_rrset_key* key2 = (struct ub_packed_rrset_key*)k2;
99
120
  int c;
100
120
  if(key1 == key2)
101
0
    return 0;
102
120
  if(key1->rk.type != key2->rk.type) {
103
4
    if(key1->rk.type < key2->rk.type)
104
2
      return -1;
105
2
    return 1;
106
4
  }
107
116
  if(key1->rk.dname_len != key2->rk.dname_len) {
108
116
    if(key1->rk.dname_len < key2->rk.dname_len)
109
58
      return -1;
110
58
    return 1;
111
116
  }
112
0
  if((c=query_dname_compare(key1->rk.dname, key2->rk.dname)) != 0)
113
0
    return c;
114
0
  if(key1->rk.rrset_class != key2->rk.rrset_class) {
115
0
    if(key1->rk.rrset_class < key2->rk.rrset_class)
116
0
      return -1;
117
0
    return 1;
118
0
  }
119
0
  if(key1->rk.flags != key2->rk.flags) {
120
0
    if(key1->rk.flags < key2->rk.flags)
121
0
      return -1;
122
0
    return 1;
123
0
  }
124
0
  return 0;
125
0
}
126
127
void 
128
ub_rrset_key_delete(void* key, void* userdata)
129
9.44k
{
130
9.44k
  struct ub_packed_rrset_key* k = (struct ub_packed_rrset_key*)key;
131
9.44k
  struct alloc_cache* a = (struct alloc_cache*)userdata;
132
9.44k
  k->id = 0;
133
9.44k
  free(k->rk.dname);
134
9.44k
  k->rk.dname = NULL;
135
9.44k
  alloc_special_release(a, k);
136
9.44k
}
137
138
void 
139
rrset_data_delete(void* data, void* ATTR_UNUSED(userdata))
140
9.44k
{
141
9.44k
  struct packed_rrset_data* d = (struct packed_rrset_data*)data;
142
9.44k
  free(d);
143
9.44k
}
144
145
int 
146
rrsetdata_equal(struct packed_rrset_data* d1, struct packed_rrset_data* d2)
147
0
{
148
0
  size_t i;
149
0
  size_t total;
150
0
  if(d1->count != d2->count || d1->rrsig_count != d2->rrsig_count) 
151
0
    return 0;
152
0
  total = d1->count + d1->rrsig_count;
153
0
  for(i=0; i<total; i++) {
154
0
    if(d1->rr_len[i] != d2->rr_len[i])
155
0
      return 0;
156
0
    if(memcmp(d1->rr_data[i], d2->rr_data[i], d1->rr_len[i]) != 0)
157
0
      return 0;
158
0
  }
159
0
  return 1;
160
0
}
161
162
hashvalue_type
163
rrset_key_hash(struct packed_rrset_key* key)
164
0
{
165
  /* type is hashed in host order */
166
0
  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
0
  hashvalue_type h = 0xab;
170
0
  h = dname_query_hash(key->dname, h);
171
0
  h = hashlittle(&t, sizeof(t), h);
172
0
  h = hashlittle(&key->rrset_class, sizeof(uint16_t), h);
173
0
  h = hashlittle(&key->flags, sizeof(uint32_t), h);
174
0
  return h;
175
0
}
176
177
void 
178
packed_rrset_ptr_fixup(struct packed_rrset_data* data)
179
0
{
180
0
  size_t i;
181
0
  size_t total = data->count + data->rrsig_count;
182
0
  uint8_t* nextrdata;
183
  /* fixup pointers in packed rrset data */
184
0
  data->rr_len = (size_t*)((uint8_t*)data +
185
0
    sizeof(struct packed_rrset_data));
186
0
  data->rr_data = (uint8_t**)&(data->rr_len[total]);
187
0
  data->rr_ttl = (time_t*)&(data->rr_data[total]);
188
0
  nextrdata = (uint8_t*)&(data->rr_ttl[total]);
189
0
  for(i=0; i<total; i++) {
190
0
    data->rr_data[i] = nextrdata;
191
0
    nextrdata += data->rr_len[i];
192
0
  }
193
0
}
194
195
void 
196
get_cname_target(struct ub_packed_rrset_key* rrset, uint8_t** dname, 
197
  size_t* dname_len)
198
0
{
199
0
  struct packed_rrset_data* d;
200
0
  size_t len;
201
0
  if(ntohs(rrset->rk.type) != LDNS_RR_TYPE_CNAME && 
202
0
    ntohs(rrset->rk.type) != LDNS_RR_TYPE_DNAME)
203
0
    return;
204
0
  d = (struct packed_rrset_data*)rrset->entry.data;
205
0
  if(d->count < 1)
206
0
    return;
207
0
  if(d->rr_len[0] < 3) /* at least rdatalen + 0byte root label */
208
0
    return;
209
0
  len = sldns_read_uint16(d->rr_data[0]);
210
0
  if(len != d->rr_len[0] - sizeof(uint16_t))
211
0
    return;
212
0
  if(dname_valid(d->rr_data[0]+sizeof(uint16_t), len) != len)
213
0
    return;
214
0
  *dname = d->rr_data[0]+sizeof(uint16_t);
215
0
  *dname_len = len;
216
0
}
217
218
void 
219
packed_rrset_ttl_add(struct packed_rrset_data* data, time_t add)
220
9.44k
{
221
9.44k
  size_t i;
222
9.44k
  size_t total = data->count + data->rrsig_count;
223
9.44k
  data->ttl_add = add;
224
9.44k
  data->ttl += add;
225
125k
  for(i=0; i<total; i++)
226
115k
    data->rr_ttl[i] += add;
227
9.44k
}
228
229
const char* 
230
rrset_trust_to_string(enum rrset_trust s)
231
0
{
232
0
  switch(s) {
233
0
  case rrset_trust_none:    return "rrset_trust_none";
234
0
  case rrset_trust_add_noAA:  return "rrset_trust_add_noAA";
235
0
  case rrset_trust_auth_noAA:   return "rrset_trust_auth_noAA";
236
0
  case rrset_trust_add_AA:  return "rrset_trust_add_AA";
237
0
  case rrset_trust_nonauth_ans_AA:return "rrset_trust_nonauth_ans_AA";
238
0
  case rrset_trust_ans_noAA:  return "rrset_trust_ans_noAA";
239
0
  case rrset_trust_glue:    return "rrset_trust_glue";
240
0
  case rrset_trust_auth_AA:   return "rrset_trust_auth_AA";
241
0
  case rrset_trust_ans_AA:  return "rrset_trust_ans_AA";
242
0
  case rrset_trust_sec_noglue:  return "rrset_trust_sec_noglue";
243
0
  case rrset_trust_prim_noglue:   return "rrset_trust_prim_noglue";
244
0
  case rrset_trust_validated:   return "rrset_trust_validated";
245
0
  case rrset_trust_ultimate:  return "rrset_trust_ultimate";
246
0
  }
247
0
  return "unknown_rrset_trust_value";
248
0
}
249
250
const char* 
251
sec_status_to_string(enum sec_status s)
252
0
{
253
0
  switch(s) {
254
0
  case sec_status_unchecked:  return "sec_status_unchecked";
255
0
  case sec_status_bogus:    return "sec_status_bogus";
256
0
  case sec_status_indeterminate:  return "sec_status_indeterminate";
257
0
  case sec_status_insecure:   return "sec_status_insecure";
258
0
  case sec_status_secure_sentinel_fail:   return "sec_status_secure_sentinel_fail";
259
0
  case sec_status_secure:   return "sec_status_secure";
260
0
  }
261
0
  return "unknown_sec_status_value";
262
0
}
263
264
void log_rrset_key(enum verbosity_value v, const char* str, 
265
  struct ub_packed_rrset_key* rrset)
266
0
{
267
0
  if(verbosity >= v)
268
0
    log_nametypeclass(v, str, rrset->rk.dname,
269
0
      ntohs(rrset->rk.type), ntohs(rrset->rk.rrset_class));
270
0
}
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
0
{
275
0
  struct packed_rrset_data* d = (struct packed_rrset_data*)rrset->
276
0
    entry.data;
277
0
  uint8_t rr[65535];
278
0
  size_t wlen;
279
0
  size_t rlen = rrset->rk.dname_len + 2 + 2 + 4 + d->rr_len[i];
280
0
  time_t adjust = 0;
281
0
  log_assert(dest_len > 0 && dest);
282
0
  if(rlen > dest_len) {
283
0
    dest[0] = 0;
284
0
    return 0;
285
0
  }
286
0
  memmove(rr, rrset->rk.dname, rrset->rk.dname_len);
287
0
  if(i < d->count)
288
0
    memmove(rr+rrset->rk.dname_len, &rrset->rk.type, 2);
289
0
  else  sldns_write_uint16(rr+rrset->rk.dname_len, LDNS_RR_TYPE_RRSIG);
290
0
  memmove(rr+rrset->rk.dname_len+2, &rrset->rk.rrset_class, 2);
291
0
  adjust = SERVE_ORIGINAL_TTL ? d->ttl_add : now;
292
0
  if (d->rr_ttl[i] < adjust) adjust = d->rr_ttl[i]; /* Prevent negative TTL overflow */
293
0
  sldns_write_uint32(rr+rrset->rk.dname_len+4,
294
0
    (uint32_t)(d->rr_ttl[i]-adjust));
295
0
  memmove(rr+rrset->rk.dname_len+8, d->rr_data[i], d->rr_len[i]);
296
0
  wlen = (size_t)sldns_wire2str_rr_buf(rr, rlen, dest, dest_len);
297
0
  if(wlen >= dest_len) {
298
    /* the output string was truncated */
299
0
    log_info("rrbuf failure %d %s", (int)d->rr_len[i], dest);
300
0
    dest[0] = 0;
301
0
    return 0;
302
0
  } 
303
0
  return 1;
304
0
}
305
306
void log_packed_rrset(enum verbosity_value v, const char* str,
307
  struct ub_packed_rrset_key* rrset)
308
0
{
309
0
  struct packed_rrset_data* d = (struct packed_rrset_data*)rrset->
310
0
    entry.data;
311
0
  char buf[65535];
312
0
  size_t i;
313
0
  if(verbosity < v)
314
0
    return;
315
0
  for(i=0; i<d->count+d->rrsig_count; i++) {
316
0
    if(!packed_rr_to_string(rrset, i, 0, buf, sizeof(buf))) {
317
0
      log_info("%s: rr %d wire2str-error", str, (int)i);
318
0
    } else {
319
0
      log_info("%s: %s", str, buf);
320
0
    }
321
0
  }
322
0
}
323
324
time_t 
325
ub_packed_rrset_ttl(struct ub_packed_rrset_key* key)
326
0
{
327
0
  struct packed_rrset_data* d = (struct packed_rrset_data*)key->
328
0
    entry.data;
329
0
  return d->ttl;
330
0
}
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
0
{
336
0
  struct ub_packed_rrset_key* ck = regional_alloc(region, 
337
0
    sizeof(struct ub_packed_rrset_key));
338
0
  struct packed_rrset_data* d;
339
0
  struct packed_rrset_data* data = (struct packed_rrset_data*)
340
0
    key->entry.data;
341
0
  size_t dsize, i;
342
0
  time_t adjust = 0;
343
0
  if(!ck)
344
0
    return NULL;
345
0
  ck->id = key->id;
346
0
  memset(&ck->entry, 0, sizeof(ck->entry));
347
0
  ck->entry.hash = key->entry.hash;
348
0
  ck->entry.key = ck;
349
0
  ck->rk = key->rk;
350
0
  ck->rk.dname = regional_alloc_init(region, key->rk.dname, 
351
0
    key->rk.dname_len);
352
0
  if(!ck->rk.dname)
353
0
    return NULL;
354
0
  dsize = packed_rrset_sizeof(data);
355
0
  d = (struct packed_rrset_data*)regional_alloc_init(region, data, dsize);
356
0
  if(!d)
357
0
    return NULL;
358
0
  ck->entry.data = d;
359
0
  packed_rrset_ptr_fixup(d);
360
  /* make TTLs relative - once per rrset */
361
0
  adjust = SERVE_ORIGINAL_TTL ? data->ttl_add : now;
362
0
  for(i=0; i<d->count + d->rrsig_count; i++) {
363
0
    if(d->rr_ttl[i] < adjust)
364
0
      d->rr_ttl[i] = SERVE_EXPIRED?SERVE_EXPIRED_REPLY_TTL:0;
365
0
    else  d->rr_ttl[i] -= adjust;
366
0
  }
367
0
  if(d->ttl < adjust)
368
0
    d->ttl = SERVE_EXPIRED?SERVE_EXPIRED_REPLY_TTL:0;
369
0
  else  d->ttl -= adjust;
370
0
  d->ttl_add = 0; /* TTLs have been made relative */
371
0
  return ck;
372
0
}
373
374
struct ub_packed_rrset_key* 
375
packed_rrset_copy_alloc(struct ub_packed_rrset_key* key, 
376
  struct alloc_cache* alloc, time_t now)
377
0
{
378
0
  struct packed_rrset_data* fd, *dd;
379
0
  struct ub_packed_rrset_key* dk = alloc_special_obtain(alloc);
380
0
  if(!dk) return NULL;
381
0
  fd = (struct packed_rrset_data*)key->entry.data;
382
0
  dk->entry.hash = key->entry.hash;
383
0
  dk->rk = key->rk;
384
0
  dk->rk.dname = (uint8_t*)memdup(key->rk.dname, key->rk.dname_len);
385
0
  if(!dk->rk.dname) {
386
0
    alloc_special_release(alloc, dk);
387
0
    return NULL;
388
0
  }
389
0
  dd = (struct packed_rrset_data*)memdup(fd, packed_rrset_sizeof(fd));
390
0
  if(!dd) {
391
0
    free(dk->rk.dname);
392
0
    alloc_special_release(alloc, dk);
393
0
    return NULL;
394
0
  }
395
0
  packed_rrset_ptr_fixup(dd);
396
0
  dk->entry.data = (void*)dd;
397
0
  packed_rrset_ttl_add(dd, now);
398
0
  return dk;
399
0
}
400
401
int
402
packed_rrset_find_rr(struct packed_rrset_data* d, uint8_t* rdata, size_t len,
403
  size_t* index)
404
0
{
405
0
  size_t i;
406
0
  for(i=0; i<d->count; i++) {
407
0
    if(d->rr_len[i] != len)
408
0
      continue;
409
0
    if(memcmp(d->rr_data[i], rdata, len) == 0) {
410
0
      *index = i;
411
0
      return 1;
412
0
    }
413
0
  }
414
0
  return 0;
415
0
}