/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 |