Coverage Report

Created: 2026-07-16 07:05

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/bind9/lib/dns/rdatalist.c
Line
Count
Source
1
/*
2
 * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
3
 *
4
 * SPDX-License-Identifier: MPL-2.0
5
 *
6
 * This Source Code Form is subject to the terms of the Mozilla Public
7
 * License, v. 2.0. If a copy of the MPL was not distributed with this
8
 * file, you can obtain one at https://mozilla.org/MPL/2.0/.
9
 *
10
 * See the COPYRIGHT file distributed with this work for additional
11
 * information regarding copyright ownership.
12
 */
13
14
/*! \file */
15
16
#include <stddef.h>
17
#include <string.h>
18
19
#include <isc/util.h>
20
21
#include <dns/name.h>
22
#include <dns/nsec3.h>
23
#include <dns/rdata.h>
24
#include <dns/rdatalist.h>
25
#include <dns/rdataset.h>
26
27
static dns_rdatasetmethods_t methods = {
28
  .disassociate = dns_rdatalist_disassociate,
29
  .first = dns__rdatalist_first,
30
  .next = dns__rdatalist_next,
31
  .current = dns__rdatalist_current,
32
  .clone = dns__rdatalist_clone,
33
  .count = dns__rdatalist_count,
34
  .addnoqname = dns__rdatalist_addnoqname,
35
  .getnoqname = dns__rdatalist_getnoqname,
36
  .addclosest = dns__rdatalist_addclosest,
37
  .getclosest = dns__rdatalist_getclosest,
38
  .setownercase = dns__rdatalist_setownercase,
39
  .getownercase = dns__rdatalist_getownercase,
40
};
41
42
void
43
12.0M
dns_rdatalist_init(dns_rdatalist_t *rdatalist) {
44
12.0M
  REQUIRE(rdatalist != NULL);
45
46
  /*
47
   * Initialize rdatalist.
48
   */
49
12.0M
  *rdatalist = (dns_rdatalist_t){
50
12.0M
    .rdata = ISC_LIST_INITIALIZER,
51
12.0M
    .link = ISC_LINK_INITIALIZER,
52
12.0M
  };
53
12.0M
  memset(rdatalist->upper, 0xeb, sizeof(rdatalist->upper));
54
55
  /*
56
   * Clear upper set bit.
57
   */
58
12.0M
  rdatalist->upper[0] &= ~0x01;
59
12.0M
}
60
61
void
62
12.0M
dns_rdatalist_tordataset(dns_rdatalist_t *rdatalist, dns_rdataset_t *rdataset) {
63
  /*
64
   * Make 'rdataset' refer to the rdata in 'rdatalist'.
65
   */
66
67
12.0M
  REQUIRE(rdatalist != NULL);
68
12.0M
  REQUIRE(DNS_RDATASET_VALID(rdataset));
69
12.0M
  REQUIRE(!dns_rdataset_isassociated(rdataset));
70
71
  /* Check if dns_rdatalist_init has was called. */
72
12.0M
  REQUIRE(rdatalist->upper[0] == 0xea);
73
74
12.0M
  *rdataset = (dns_rdataset_t){
75
12.0M
    .methods = &methods,
76
12.0M
    .rdclass = rdatalist->rdclass,
77
12.0M
    .type = rdatalist->type,
78
12.0M
    .covers = rdatalist->covers,
79
12.0M
    .ttl = rdatalist->ttl,
80
12.0M
    .rdlist.list = rdatalist,
81
82
12.0M
    .link = rdataset->link,
83
12.0M
    .attributes = rdataset->attributes,
84
12.0M
    .magic = rdataset->magic,
85
12.0M
  };
86
12.0M
}
87
88
void
89
dns_rdatalist_fromrdataset(dns_rdataset_t *rdataset,
90
315k
         dns_rdatalist_t **rdatalist) {
91
315k
  REQUIRE(rdatalist != NULL && rdataset != NULL);
92
315k
  REQUIRE(rdataset->methods == &methods);
93
94
315k
  *rdatalist = rdataset->rdlist.list;
95
315k
}
96
97
void
98
425k
dns_rdatalist_disassociate(dns_rdataset_t *rdataset DNS__DB_FLARG) {
99
425k
  UNUSED(rdataset);
100
425k
}
101
102
isc_result_t
103
12.0M
dns__rdatalist_first(dns_rdataset_t *rdataset) {
104
12.0M
  dns_rdatalist_t *rdatalist = NULL;
105
106
12.0M
  rdatalist = rdataset->rdlist.list;
107
12.0M
  rdataset->rdlist.iter = ISC_LIST_HEAD(rdatalist->rdata);
108
109
12.0M
  if (rdataset->rdlist.iter == NULL) {
110
213k
    return ISC_R_NOMORE;
111
213k
  }
112
113
11.8M
  return ISC_R_SUCCESS;
114
12.0M
}
115
116
isc_result_t
117
12.1M
dns__rdatalist_next(dns_rdataset_t *rdataset) {
118
12.1M
  dns_rdata_t *rdata;
119
120
12.1M
  rdata = rdataset->rdlist.iter;
121
12.1M
  if (rdata == NULL) {
122
0
    return ISC_R_NOMORE;
123
0
  }
124
125
12.1M
  rdataset->rdlist.iter = ISC_LIST_NEXT(rdata, link);
126
127
12.1M
  if (rdataset->rdlist.iter == NULL) {
128
11.8M
    return ISC_R_NOMORE;
129
11.8M
  }
130
131
360k
  return ISC_R_SUCCESS;
132
12.1M
}
133
134
void
135
12.1M
dns__rdatalist_current(dns_rdataset_t *rdataset, dns_rdata_t *rdata) {
136
12.1M
  dns_rdata_t *list_rdata;
137
138
12.1M
  list_rdata = rdataset->rdlist.iter;
139
12.1M
  INSIST(list_rdata != NULL);
140
141
12.1M
  dns_rdata_clone(list_rdata, rdata);
142
12.1M
}
143
144
void
145
dns__rdatalist_clone(const dns_rdataset_t *source,
146
0
         dns_rdataset_t *target DNS__DB_FLARG) {
147
0
  REQUIRE(source != NULL);
148
0
  REQUIRE(target != NULL);
149
150
0
  *target = *source;
151
152
0
  target->rdlist.iter = NULL;
153
0
}
154
155
unsigned int
156
11.6M
dns__rdatalist_count(dns_rdataset_t *rdataset) {
157
11.6M
  dns_rdatalist_t *rdatalist = NULL;
158
11.6M
  unsigned int count;
159
160
11.6M
  REQUIRE(rdataset != NULL);
161
162
11.6M
  rdatalist = rdataset->rdlist.list;
163
164
11.6M
  count = 0;
165
11.9M
  ISC_LIST_FOREACH(rdatalist->rdata, rdata, link) {
166
11.9M
    count++;
167
11.9M
  }
168
169
11.6M
  return count;
170
11.6M
}
171
172
isc_result_t
173
0
dns__rdatalist_addnoqname(dns_rdataset_t *rdataset, dns_name_t *name) {
174
0
  dns_rdataset_t *neg = NULL;
175
0
  dns_rdataset_t *negsig = NULL;
176
0
  dns_ttl_t ttl;
177
178
0
  REQUIRE(rdataset != NULL);
179
180
0
  ISC_LIST_FOREACH(name->list, rdset, link) {
181
0
    if (rdset->rdclass != rdataset->rdclass) {
182
0
      continue;
183
0
    }
184
0
    if (dns_rdatatype_isnsec(rdset->type)) {
185
0
      neg = rdset;
186
0
    }
187
0
  }
188
0
  if (neg == NULL) {
189
0
    return ISC_R_NOTFOUND;
190
0
  }
191
192
0
  ISC_LIST_FOREACH(name->list, rdset, link) {
193
0
    if (rdset->type == dns_rdatatype_rrsig &&
194
0
        rdset->covers == neg->type)
195
0
    {
196
0
      negsig = rdset;
197
0
    }
198
0
  }
199
200
0
  if (negsig == NULL) {
201
0
    return ISC_R_NOTFOUND;
202
0
  }
203
204
  /*
205
   * Minimise ttl.
206
   */
207
0
  ttl = rdataset->ttl;
208
0
  if (neg->ttl < ttl) {
209
0
    ttl = neg->ttl;
210
0
  }
211
0
  if (negsig->ttl < ttl) {
212
0
    ttl = negsig->ttl;
213
0
  }
214
0
  rdataset->ttl = neg->ttl = negsig->ttl = ttl;
215
0
  rdataset->attributes.noqname = true;
216
0
  rdataset->rdlist.noqname = name;
217
0
  return ISC_R_SUCCESS;
218
0
}
219
220
isc_result_t
221
dns__rdatalist_getnoqname(dns_rdataset_t *rdataset, dns_name_t *name,
222
        dns_rdataset_t *neg,
223
0
        dns_rdataset_t *negsig DNS__DB_FLARG) {
224
0
  dns_rdataclass_t rdclass;
225
0
  dns_rdataset_t *tneg = NULL;
226
0
  dns_rdataset_t *tnegsig = NULL;
227
0
  dns_name_t *noqname = NULL;
228
229
0
  REQUIRE(rdataset != NULL);
230
0
  REQUIRE(rdataset->attributes.noqname);
231
232
0
  rdclass = rdataset->rdclass;
233
0
  noqname = rdataset->rdlist.noqname;
234
235
0
  (void)dns_name_dynamic(noqname); /* Sanity Check. */
236
237
0
  ISC_LIST_FOREACH(noqname->list, rdset, link) {
238
0
    if (rdset->rdclass != rdclass) {
239
0
      continue;
240
0
    }
241
0
    if (dns_rdatatype_isnsec(rdset->type)) {
242
0
      tneg = rdset;
243
0
    }
244
0
  }
245
0
  if (tneg == NULL) {
246
0
    return ISC_R_NOTFOUND;
247
0
  }
248
249
0
  ISC_LIST_FOREACH(noqname->list, rdset, link) {
250
0
    if (rdset->type == dns_rdatatype_rrsig &&
251
0
        rdset->covers == tneg->type)
252
0
    {
253
0
      tnegsig = rdset;
254
0
    }
255
0
  }
256
0
  if (tnegsig == NULL) {
257
0
    return ISC_R_NOTFOUND;
258
0
  }
259
260
0
  dns_name_clone(noqname, name);
261
0
  dns_rdataset_clone(tneg, neg);
262
0
  dns_rdataset_clone(tnegsig, negsig);
263
0
  return ISC_R_SUCCESS;
264
0
}
265
266
isc_result_t
267
0
dns__rdatalist_addclosest(dns_rdataset_t *rdataset, dns_name_t *name) {
268
0
  dns_rdataset_t *neg = NULL;
269
0
  dns_rdataset_t *negsig = NULL;
270
0
  dns_ttl_t ttl;
271
272
0
  REQUIRE(rdataset != NULL);
273
274
0
  ISC_LIST_FOREACH(name->list, rdset, link) {
275
0
    if (rdset->rdclass != rdataset->rdclass) {
276
0
      continue;
277
0
    }
278
0
    if (dns_rdatatype_isnsec(rdset->type)) {
279
0
      neg = rdset;
280
0
    }
281
0
  }
282
0
  if (neg == NULL) {
283
0
    return ISC_R_NOTFOUND;
284
0
  }
285
286
0
  ISC_LIST_FOREACH(name->list, rdset, link) {
287
0
    if (rdset->type == dns_rdatatype_rrsig &&
288
0
        rdset->covers == neg->type)
289
0
    {
290
0
      negsig = rdset;
291
0
    }
292
0
  }
293
294
0
  if (negsig == NULL) {
295
0
    return ISC_R_NOTFOUND;
296
0
  }
297
  /*
298
   * Minimise ttl.
299
   */
300
0
  ttl = rdataset->ttl;
301
0
  if (neg->ttl < ttl) {
302
0
    ttl = neg->ttl;
303
0
  }
304
0
  if (negsig->ttl < ttl) {
305
0
    ttl = negsig->ttl;
306
0
  }
307
0
  rdataset->ttl = neg->ttl = negsig->ttl = ttl;
308
0
  rdataset->attributes.closest = true;
309
0
  rdataset->rdlist.closest = name;
310
0
  return ISC_R_SUCCESS;
311
0
}
312
313
isc_result_t
314
dns__rdatalist_getclosest(dns_rdataset_t *rdataset, dns_name_t *name,
315
        dns_rdataset_t *neg,
316
0
        dns_rdataset_t *negsig DNS__DB_FLARG) {
317
0
  dns_rdataclass_t rdclass;
318
0
  dns_rdataset_t *tneg = NULL;
319
0
  dns_rdataset_t *tnegsig = NULL;
320
0
  dns_name_t *closest = NULL;
321
322
0
  REQUIRE(rdataset != NULL);
323
0
  REQUIRE(rdataset->attributes.closest);
324
325
0
  rdclass = rdataset->rdclass;
326
0
  closest = rdataset->rdlist.closest;
327
328
0
  (void)dns_name_dynamic(closest); /* Sanity Check. */
329
330
0
  ISC_LIST_FOREACH(closest->list, rdset, link) {
331
0
    if (rdset->rdclass != rdclass) {
332
0
      continue;
333
0
    }
334
0
    if (dns_rdatatype_isnsec(rdset->type)) {
335
0
      tneg = rdset;
336
0
    }
337
0
  }
338
0
  if (tneg == NULL) {
339
0
    return ISC_R_NOTFOUND;
340
0
  }
341
342
0
  ISC_LIST_FOREACH(closest->list, rdset, link) {
343
0
    if (rdset->type == dns_rdatatype_rrsig &&
344
0
        rdset->covers == tneg->type)
345
0
    {
346
0
      tnegsig = rdset;
347
0
    }
348
0
  }
349
0
  if (tnegsig == NULL) {
350
0
    return ISC_R_NOTFOUND;
351
0
  }
352
353
0
  dns_name_clone(closest, name);
354
0
  dns_rdataset_clone(tneg, neg);
355
0
  dns_rdataset_clone(tnegsig, negsig);
356
0
  return ISC_R_SUCCESS;
357
0
}
358
359
void
360
303k
dns__rdatalist_setownercase(dns_rdataset_t *rdataset, const dns_name_t *name) {
361
303k
  dns_rdatalist_t *rdatalist;
362
303k
  unsigned int i;
363
364
  /*
365
   * We do not need to worry about label lengths as they are all
366
   * less than or equal to 63.
367
   */
368
303k
  rdatalist = rdataset->rdlist.list;
369
303k
  memset(rdatalist->upper, 0, sizeof(rdatalist->upper));
370
3.33M
  for (i = 1; i < name->length; i++) {
371
3.02M
    if (name->ndata[i] >= 0x41 && name->ndata[i] <= 0x5a) {
372
62.7k
      rdatalist->upper[i / 8] |= 1 << (i % 8);
373
62.7k
    }
374
3.02M
  }
375
  /*
376
   * Record that upper has been set.
377
   */
378
303k
  rdatalist->upper[0] |= 0x01;
379
303k
}
380
381
void
382
277k
dns__rdatalist_getownercase(const dns_rdataset_t *rdataset, dns_name_t *name) {
383
277k
  dns_rdatalist_t *rdatalist;
384
277k
  unsigned int i;
385
386
277k
  rdatalist = rdataset->rdlist.list;
387
277k
  if ((rdatalist->upper[0] & 0x01) == 0) {
388
94.1k
    return;
389
94.1k
  }
390
2.55M
  for (i = 0; i < name->length; i++) {
391
    /*
392
     * Set the case bit if it does not match the recorded bit.
393
     */
394
2.37M
    if (name->ndata[i] >= 0x61 && name->ndata[i] <= 0x7a &&
395
73.9k
        (rdatalist->upper[i / 8] & (1 << (i % 8))) != 0)
396
0
    {
397
0
      name->ndata[i] &= ~0x20; /* clear the lower case bit */
398
2.37M
    } else if (name->ndata[i] >= 0x41 && name->ndata[i] <= 0x5a &&
399
58.3k
         (rdatalist->upper[i / 8] & (1 << (i % 8))) == 0)
400
0
    {
401
0
      name->ndata[i] |= 0x20; /* set the lower case bit */
402
0
    }
403
2.37M
  }
404
183k
}