Coverage Report

Created: 2026-10-28 06:55

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/bind9/lib/dns/iptable.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
#include <stdbool.h>
16
17
#include <isc/mem.h>
18
#include <isc/radix.h>
19
#include <isc/util.h>
20
21
#include <dns/acl.h>
22
23
/*
24
 * Create a new IP table and the underlying radix structure
25
 */
26
void
27
4
dns_iptable_create(isc_mem_t *mctx, dns_iptable_t **target) {
28
4
  dns_iptable_t *tab = isc_mem_get(mctx, sizeof(*tab));
29
4
  *tab = (dns_iptable_t){
30
4
    .references = ISC_REFCOUNT_INITIALIZER(1),
31
4
    .magic = DNS_IPTABLE_MAGIC,
32
4
  };
33
4
  isc_mem_attach(mctx, &tab->mctx);
34
35
4
  isc_radix_create(mctx, &tab->radix, RADIX_MAXBITS);
36
37
4
  *target = tab;
38
4
}
39
40
/*
41
 * Add an IP prefix to an existing IP table
42
 */
43
static void
44
iptable_addentry(dns_iptable_t *tab, isc_prefix_t *pfx,
45
0
     isc_radix_match_t match) {
46
0
  isc_radix_node_t *node = NULL;
47
48
0
  isc_radix_insert(tab->radix, &node, NULL, pfx);
49
50
  /* Preserve first-match semantics: don't overwrite existing data */
51
0
  int fam = ISC_RADIX_FAMILY(pfx);
52
0
  if (node->match[fam] == RADIX_UNSET) {
53
0
    node->match[fam] = match;
54
0
  }
55
0
}
56
57
void
58
dns_iptable_addprefix(dns_iptable_t *tab, const isc_netaddr_t *addr,
59
0
          uint16_t bitlen, isc_radix_match_t match) {
60
0
  INSIST(DNS_IPTABLE_VALID(tab));
61
0
  INSIST(tab->radix != NULL);
62
63
0
  if (addr == NULL) {
64
    /*
65
     * "any" or "none": insert both IPv4 and IPv6 wildcard
66
     * entries so they match all addresses.
67
     */
68
0
    isc_prefix_t pfx4 = { .family = AF_INET, .bitlen = 0 };
69
0
    isc_prefix_t pfx6 = { .family = AF_INET6, .bitlen = 0 };
70
71
0
    iptable_addentry(tab, &pfx4, match);
72
0
    iptable_addentry(tab, &pfx6, match);
73
0
    return;
74
0
  }
75
76
0
  isc_prefix_t pfx;
77
0
  isc_prefix_from_netaddr(&pfx, addr, bitlen);
78
0
  iptable_addentry(tab, &pfx, match);
79
0
}
80
81
typedef struct {
82
  dns_iptable_t *tab;
83
  bool negate;
84
  int32_t max_node;
85
} iptable_merge_ctx_t;
86
87
static void
88
0
iptable_merge_node(isc_radix_node_t *node, void *arg) {
89
0
  iptable_merge_ctx_t *ctx = arg;
90
0
  isc_radix_node_t *new_node = NULL;
91
92
0
  isc_radix_insert(ctx->tab->radix, &new_node, node, NULL);
93
94
  /*
95
   * If we're negating a nested ACL, then we should
96
   * reverse the sense of every node.  However, this
97
   * could lead to a negative node in a nested ACL
98
   * becoming a positive match in the parent, which
99
   * could be a security risk.  To prevent this, we
100
   * just leave the negative nodes negative.
101
   */
102
0
  for (size_t i = 0; i < RADIX_FAMILIES; i++) {
103
0
    if (ctx->negate && node->match[i] == RADIX_ALLOW) {
104
0
      new_node->match[i] = RADIX_DENY;
105
0
    }
106
0
    if (node->node_num[i] > ctx->max_node) {
107
0
      ctx->max_node = node->node_num[i];
108
0
    }
109
0
  }
110
0
}
111
112
/*
113
 * Merge one IP table into another one.
114
 */
115
void
116
0
dns_iptable_merge(dns_iptable_t *tab, dns_iptable_t *source, bool negate) {
117
0
  iptable_merge_ctx_t ctx = { .tab = tab, .negate = negate };
118
119
0
  isc_radix_foreach(source->radix, iptable_merge_node, &ctx);
120
121
0
  tab->radix->num_added_node += ctx.max_node;
122
0
}
123
124
static void
125
0
dns__iptable_destroy(dns_iptable_t *dtab) {
126
0
  REQUIRE(DNS_IPTABLE_VALID(dtab));
127
128
0
  dtab->magic = 0;
129
130
0
  if (dtab->radix != NULL) {
131
0
    isc_radix_destroy(dtab->radix);
132
0
    dtab->radix = NULL;
133
0
  }
134
135
0
  isc_mem_putanddetach(&dtab->mctx, dtab, sizeof(*dtab));
136
0
}
137
138
#if DNS_IPTABLE_TRACE
139
ISC_REFCOUNT_TRACE_IMPL(dns_iptable, dns__iptable_destroy);
140
#else
141
ISC_REFCOUNT_IMPL(dns_iptable, dns__iptable_destroy);
Unexecuted instantiation: dns_iptable_ref
Unexecuted instantiation: dns_iptable_unref
Unexecuted instantiation: dns_iptable_detach
142
#endif