Coverage Report

Created: 2026-07-16 07:05

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/bind9/lib/isc/radix.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
#include <inttypes.h>
15
16
#include <isc/bit.h>
17
#include <isc/mem.h>
18
#include <isc/radix.h>
19
#include <isc/types.h>
20
#include <isc/util.h>
21
22
static int
23
0
comp_with_mask(void *addr, void *dest, unsigned int mask) {
24
  /* Mask length of zero matches everything */
25
0
  if (mask == 0) {
26
0
    return 1;
27
0
  }
28
29
0
  if (memcmp(addr, dest, mask / 8) == 0) {
30
0
    unsigned int n = mask / 8;
31
0
    unsigned int m = ((~0U) << (8 - (mask % 8)));
32
33
0
    if ((mask % 8) == 0 ||
34
0
        (((uint8_t *)addr)[n] & m) == (((uint8_t *)dest)[n] & m))
35
0
    {
36
0
      return 1;
37
0
    }
38
0
  }
39
0
  return 0;
40
0
}
41
42
static isc_radix_node_t *
43
0
radix_node_create(isc_mem_t *mctx, isc_prefix_t *prefix, uint8_t bit) {
44
0
  isc_radix_node_t *node = isc_mem_get(mctx, sizeof(*node));
45
0
  *node = (isc_radix_node_t){
46
0
    .bit = bit,
47
0
    .node_num = { -1, -1 },
48
0
  };
49
0
  if (prefix != NULL) {
50
0
    node->prefix = *prefix;
51
0
  }
52
0
  return node;
53
0
}
54
55
void
56
4
isc_radix_create(isc_mem_t *mctx, isc_radix_tree_t **target, uint8_t maxbits) {
57
4
  REQUIRE(target != NULL && *target == NULL);
58
4
  RUNTIME_CHECK(maxbits <= RADIX_MAXBITS);
59
60
4
  isc_radix_tree_t *radix = isc_mem_get(mctx, sizeof(isc_radix_tree_t));
61
4
  *radix = (isc_radix_tree_t){
62
4
    .maxbits = maxbits,
63
4
    .magic = RADIX_TREE_MAGIC,
64
4
  };
65
4
  isc_mem_attach(mctx, &radix->mctx);
66
4
  *target = radix;
67
4
}
68
69
/*
70
 * if func is supplied, it will be called as func(node->data)
71
 * before deleting the node
72
 */
73
74
static void
75
0
clear_radix(isc_radix_tree_t *radix) {
76
0
  REQUIRE(radix != NULL);
77
78
0
  isc_radix_node_t *stack[RADIX_MAXBITS + 1];
79
0
  isc_radix_node_t **sp = stack;
80
0
  isc_radix_node_t *cur = radix->head;
81
82
0
  while (cur != NULL) {
83
0
    isc_radix_node_t *l = cur->left;
84
0
    isc_radix_node_t *r = cur->right;
85
86
0
    isc_mem_put(radix->mctx, cur, sizeof(*cur));
87
0
    radix->num_active_node--;
88
89
0
    if (l != NULL) {
90
0
      if (r != NULL) {
91
0
        *sp++ = r;
92
0
      }
93
0
      cur = l;
94
0
    } else if (r != NULL) {
95
0
      cur = r;
96
0
    } else if (sp != stack) {
97
0
      cur = *(--sp);
98
0
    } else {
99
0
      cur = NULL;
100
0
    }
101
0
  }
102
103
0
  RUNTIME_CHECK(radix->num_active_node == 0);
104
0
}
105
106
void
107
0
isc_radix_destroy(isc_radix_tree_t *radix) {
108
0
  REQUIRE(radix != NULL);
109
0
  clear_radix(radix);
110
0
  isc_mem_putanddetach(&radix->mctx, radix, sizeof(*radix));
111
0
}
112
113
void
114
isc_radix_foreach(isc_radix_tree_t *radix, isc_radix_foreachfunc_t func,
115
0
      void *arg) {
116
0
  REQUIRE(radix != NULL);
117
0
  REQUIRE(func != NULL);
118
119
0
  isc_radix_node_t *stack[RADIX_MAXBITS + 1];
120
0
  isc_radix_node_t **sp = stack;
121
0
  isc_radix_node_t *cur = radix->head;
122
123
0
  while (cur != NULL) {
124
0
    if (cur->prefix.family != 0) {
125
0
      func(cur, arg);
126
0
    }
127
128
0
    if (cur->left != NULL) {
129
0
      if (cur->right != NULL) {
130
0
        *sp++ = cur->right;
131
0
      }
132
0
      cur = cur->left;
133
0
    } else if (cur->right != NULL) {
134
0
      cur = cur->right;
135
0
    } else if (sp != stack) {
136
0
      cur = *(--sp);
137
0
    } else {
138
0
      cur = NULL;
139
0
    }
140
0
  }
141
0
}
142
143
isc_result_t
144
isc_radix_search(isc_radix_tree_t *radix, isc_radix_node_t **target,
145
0
     isc_prefix_t *prefix) {
146
0
  isc_radix_node_t *stack[RADIX_MAXBITS + 1];
147
0
  int cnt = 0;
148
149
0
  REQUIRE(radix != NULL);
150
0
  REQUIRE(prefix != NULL);
151
0
  REQUIRE(target != NULL && *target == NULL);
152
0
  RUNTIME_CHECK(prefix->bitlen <= radix->maxbits);
153
154
0
  *target = NULL;
155
156
0
  if (radix->head == NULL) {
157
0
    return ISC_R_NOTFOUND;
158
0
  }
159
160
  /* Walk the tree collecting candidate nodes. */
161
0
  uint8_t *addr = isc_prefix_touint8(prefix);
162
0
  uint8_t bitlen = prefix->bitlen;
163
0
  isc_radix_node_t *node = radix->head;
164
165
0
  while (node != NULL && node->bit < bitlen) {
166
0
    if (node->prefix.family != 0) {
167
0
      stack[cnt++] = node;
168
0
    }
169
170
0
    if (isc_prefix_bit_isset(addr, node->bit)) {
171
0
      node = node->right;
172
0
    } else {
173
0
      node = node->left;
174
0
    }
175
0
  }
176
177
0
  if (node != NULL && node->prefix.family != 0) {
178
0
    stack[cnt++] = node;
179
0
  }
180
181
  /* Find the first-inserted matching node among the candidates. */
182
0
  int tfam = -1;
183
0
  while (cnt-- > 0) {
184
0
    node = stack[cnt];
185
186
0
    if (prefix->bitlen < node->bit) {
187
0
      continue;
188
0
    }
189
190
0
    if (comp_with_mask(isc_prefix_touint8(&node->prefix),
191
0
           isc_prefix_touint8(prefix),
192
0
           node->prefix.bitlen))
193
0
    {
194
0
      int fam = ISC_RADIX_FAMILY(prefix);
195
0
      if (node->node_num[fam] != -1 &&
196
0
          ((*target == NULL) ||
197
0
           (*target)->node_num[tfam] > node->node_num[fam]))
198
0
      {
199
0
        *target = node;
200
0
        tfam = fam;
201
0
      }
202
0
    }
203
0
  }
204
205
0
  if (*target == NULL) {
206
0
    return ISC_R_NOTFOUND;
207
0
  }
208
209
0
  return ISC_R_SUCCESS;
210
0
}
211
212
void
213
isc_radix_insert(isc_radix_tree_t *radix, isc_radix_node_t **target,
214
0
     isc_radix_node_t *source, isc_prefix_t *prefix) {
215
0
  isc_radix_node_t *node;
216
217
0
  REQUIRE(radix != NULL);
218
0
  REQUIRE(target != NULL && *target == NULL);
219
0
  REQUIRE(prefix != NULL ||
220
0
    (source != NULL && source->prefix.family != 0));
221
0
  RUNTIME_CHECK(prefix == NULL || prefix->bitlen <= radix->maxbits);
222
223
0
  if (prefix == NULL) {
224
0
    prefix = &source->prefix;
225
0
  }
226
227
0
  INSIST(prefix != NULL);
228
229
0
  uint8_t bitlen = prefix->bitlen;
230
231
0
  if (radix->head == NULL) {
232
0
    node = radix_node_create(radix->mctx, prefix, bitlen);
233
0
    if (source != NULL) {
234
      /*
235
       * If source is non-NULL, then we're merging in a
236
       * node from an existing radix tree.  To keep
237
       * the node_num values consistent, the calling
238
       * function will add the total number of nodes
239
       * added to num_added_node at the end of
240
       * the merge operation--we don't do it here.
241
       */
242
0
      for (size_t i = 0; i < RADIX_FAMILIES; i++) {
243
0
        if (source->node_num[i] != -1) {
244
0
          node->node_num[i] =
245
0
            radix->num_added_node +
246
0
            source->node_num[i];
247
0
        }
248
0
        node->match[i] = source->match[i];
249
0
      }
250
0
    } else {
251
0
      int next = ++radix->num_added_node;
252
0
      node->node_num[ISC_RADIX_FAMILY(prefix)] = next;
253
0
    }
254
0
    radix->head = node;
255
0
    radix->num_active_node++;
256
0
    *target = node;
257
0
    return;
258
0
  }
259
260
0
  uint8_t *addr = isc_prefix_touint8(prefix);
261
0
  node = radix->head;
262
263
0
  while (node->bit < bitlen || node->prefix.family == 0) {
264
0
    if (node->bit < radix->maxbits &&
265
0
        isc_prefix_bit_isset(addr, node->bit))
266
0
    {
267
0
      if (node->right == NULL) {
268
0
        break;
269
0
      }
270
0
      node = node->right;
271
0
    } else {
272
0
      if (node->left == NULL) {
273
0
        break;
274
0
      }
275
0
      node = node->left;
276
0
    }
277
278
0
    INSIST(node != NULL);
279
0
  }
280
281
0
  INSIST(node->prefix.family != 0);
282
283
  /* Find the first bit different. */
284
0
  uint8_t *test_addr = isc_prefix_touint8(&node->prefix);
285
0
  uint8_t check_bit = (node->bit < bitlen) ? node->bit : bitlen;
286
0
  uint8_t differ_bit = 0;
287
0
  for (size_t i = 0; i * 8 < check_bit; i++) {
288
0
    uint8_t r = addr[i] ^ test_addr[i];
289
0
    if (r == 0) {
290
0
      differ_bit = (i + 1) * 8;
291
0
      continue;
292
0
    }
293
0
    differ_bit = i * 8 + (stdc_leading_zeros((unsigned int)r) - 24);
294
0
    break;
295
0
  }
296
297
0
  if (differ_bit > check_bit) {
298
0
    differ_bit = check_bit;
299
0
  }
300
301
0
  isc_radix_node_t *parent = node->parent;
302
0
  while (parent != NULL && parent->bit >= differ_bit) {
303
0
    node = parent;
304
0
    parent = node->parent;
305
0
  }
306
307
0
  if (differ_bit == bitlen && node->bit == bitlen) {
308
0
    if (node->prefix.family != 0) {
309
      /* Set node_num only if it hasn't been set before */
310
0
      if (source != NULL) {
311
        /* Merging nodes */
312
0
        for (size_t i = 0; i < RADIX_FAMILIES; i++) {
313
0
          if (node->node_num[i] == -1 &&
314
0
              source->node_num[i] != -1)
315
0
          {
316
0
            node->node_num[i] =
317
0
              radix->num_added_node +
318
0
              source->node_num[i];
319
0
            node->match[i] =
320
0
              source->match[i];
321
0
          }
322
0
        }
323
0
      } else {
324
0
        int foff = ISC_RADIX_FAMILY(prefix);
325
0
        if (node->node_num[foff] == -1) {
326
0
          node->node_num[foff] =
327
0
            ++radix->num_added_node;
328
0
        }
329
0
      }
330
0
      *target = node;
331
0
      return;
332
0
    } else {
333
0
      node->prefix = *prefix;
334
0
    }
335
0
    INSIST(node->match[RADIX_V4] == RADIX_UNSET &&
336
0
           node->node_num[RADIX_V4] == -1 &&
337
0
           node->match[RADIX_V6] == RADIX_UNSET &&
338
0
           node->node_num[RADIX_V6] == -1);
339
0
    if (source != NULL) {
340
      /* Merging node */
341
0
      for (size_t i = 0; i < RADIX_FAMILIES; i++) {
342
0
        int cur = radix->num_added_node;
343
0
        if (source->node_num[i] != -1) {
344
0
          node->node_num[i] =
345
0
            source->node_num[i] + cur;
346
0
          node->match[i] = source->match[i];
347
0
        }
348
0
      }
349
0
    } else {
350
0
      int next = ++radix->num_added_node;
351
0
      node->node_num[ISC_RADIX_FAMILY(prefix)] = next;
352
0
    }
353
0
    *target = node;
354
0
    return;
355
0
  }
356
357
0
  isc_radix_node_t *new_node = radix_node_create(radix->mctx, prefix,
358
0
                   bitlen);
359
0
  isc_radix_node_t *glue = NULL;
360
0
  if (node->bit != differ_bit && bitlen != differ_bit) {
361
0
    glue = radix_node_create(radix->mctx, NULL, differ_bit);
362
0
  }
363
0
  radix->num_active_node++;
364
365
0
  if (source != NULL) {
366
    /* Merging node */
367
0
    for (size_t i = 0; i < RADIX_FAMILIES; i++) {
368
0
      int cur = radix->num_added_node;
369
0
      if (source->node_num[i] != -1) {
370
0
        new_node->node_num[i] = source->node_num[i] +
371
0
              cur;
372
0
        new_node->match[i] = source->match[i];
373
0
      }
374
0
    }
375
0
  } else {
376
0
    int next = ++radix->num_added_node;
377
0
    new_node->node_num[ISC_RADIX_FAMILY(prefix)] = next;
378
0
  }
379
380
0
  if (node->bit == differ_bit) {
381
0
    INSIST(glue == NULL);
382
0
    new_node->parent = node;
383
0
    if (node->bit < radix->maxbits &&
384
0
        isc_prefix_bit_isset(addr, node->bit))
385
0
    {
386
0
      INSIST(node->right == NULL);
387
0
      node->right = new_node;
388
0
    } else {
389
0
      INSIST(node->left == NULL);
390
0
      node->left = new_node;
391
0
    }
392
0
    *target = new_node;
393
0
    return;
394
0
  }
395
396
0
  if (bitlen == differ_bit) {
397
0
    INSIST(glue == NULL);
398
0
    if (bitlen < radix->maxbits &&
399
0
        isc_prefix_bit_isset(test_addr, bitlen))
400
0
    {
401
0
      new_node->right = node;
402
0
    } else {
403
0
      new_node->left = node;
404
0
    }
405
0
    new_node->parent = node->parent;
406
0
    if (node->parent == NULL) {
407
0
      INSIST(radix->head == node);
408
0
      radix->head = new_node;
409
0
    } else if (node->parent->right == node) {
410
0
      node->parent->right = new_node;
411
0
    } else {
412
0
      node->parent->left = new_node;
413
0
    }
414
0
    node->parent = new_node;
415
0
  } else {
416
0
    INSIST(glue != NULL);
417
0
    glue->parent = node->parent;
418
0
    radix->num_active_node++;
419
0
    if (differ_bit < radix->maxbits &&
420
0
        isc_prefix_bit_isset(addr, differ_bit))
421
0
    {
422
0
      glue->right = new_node;
423
0
      glue->left = node;
424
0
    } else {
425
0
      glue->right = node;
426
0
      glue->left = new_node;
427
0
    }
428
0
    new_node->parent = glue;
429
430
0
    if (node->parent == NULL) {
431
0
      INSIST(radix->head == node);
432
0
      radix->head = glue;
433
0
    } else if (node->parent->right == node) {
434
0
      node->parent->right = glue;
435
0
    } else {
436
0
      INSIST(node->parent->left == node);
437
0
      node->parent->left = glue;
438
0
    }
439
0
    node->parent = glue;
440
0
  }
441
442
0
  *target = new_node;
443
0
  return;
444
0
}
445
446
void
447
0
isc_radix_remove(isc_radix_tree_t *radix, isc_radix_node_t *node) {
448
0
  isc_radix_node_t *parent, *child;
449
450
0
  REQUIRE(radix != NULL);
451
0
  REQUIRE(node != NULL);
452
453
0
  if (node->right && node->left) {
454
    /*
455
     * This might be a placeholder node -- have to check and
456
     * make sure there is a prefix associated with it!
457
     */
458
0
    memset(&node->prefix, 0, sizeof(node->prefix));
459
0
    node->match[RADIX_V4] = RADIX_UNSET;
460
0
    node->match[RADIX_V6] = RADIX_UNSET;
461
0
    return;
462
0
  }
463
464
0
  if (node->right == NULL && node->left == NULL) {
465
0
    parent = node->parent;
466
467
0
    if (parent == NULL) {
468
0
      INSIST(radix->head == node);
469
0
      radix->head = NULL;
470
0
      isc_mem_put(radix->mctx, node, sizeof(*node));
471
0
      radix->num_active_node--;
472
0
      return;
473
0
    }
474
475
0
    if (parent->right == node) {
476
0
      parent->right = NULL;
477
0
      child = parent->left;
478
0
    } else {
479
0
      INSIST(parent->left == node);
480
0
      parent->left = NULL;
481
0
      child = parent->right;
482
0
    }
483
484
0
    isc_mem_put(radix->mctx, node, sizeof(*node));
485
0
    radix->num_active_node--;
486
487
0
    if (parent->prefix.family != 0) {
488
0
      return;
489
0
    }
490
491
    /* We need to remove parent too. */
492
0
    if (parent->parent == NULL) {
493
0
      INSIST(radix->head == parent);
494
0
      radix->head = child;
495
0
    } else if (parent->parent->right == parent) {
496
0
      parent->parent->right = child;
497
0
    } else {
498
0
      INSIST(parent->parent->left == parent);
499
0
      parent->parent->left = child;
500
0
    }
501
502
0
    child->parent = parent->parent;
503
0
    isc_mem_put(radix->mctx, parent, sizeof(*parent));
504
0
    radix->num_active_node--;
505
0
    return;
506
0
  }
507
508
0
  if (node->right) {
509
0
    child = node->right;
510
0
  } else {
511
0
    INSIST(node->left != NULL);
512
0
    child = node->left;
513
0
  }
514
515
0
  parent = node->parent;
516
0
  child->parent = parent;
517
518
0
  if (parent == NULL) {
519
0
    INSIST(radix->head == node);
520
0
    radix->head = child;
521
0
    isc_mem_put(radix->mctx, node, sizeof(*node));
522
0
    radix->num_active_node--;
523
0
    return;
524
0
  }
525
526
0
  if (parent->right == node) {
527
0
    parent->right = child;
528
0
  } else {
529
0
    INSIST(parent->left == node);
530
0
    parent->left = child;
531
0
  }
532
533
  isc_mem_put(radix->mctx, node, sizeof(*node));
534
0
  radix->num_active_node--;
535
0
}