Coverage Report

Created: 2026-01-24 06:24

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/bind9/lib/dns/forward.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 <isc/magic.h>
17
#include <isc/mem.h>
18
#include <isc/result.h>
19
#include <isc/util.h>
20
21
#include <dns/fixedname.h>
22
#include <dns/forward.h>
23
#include <dns/name.h>
24
#include <dns/qp.h>
25
#include <dns/types.h>
26
#include <dns/view.h>
27
28
struct dns_fwdtable {
29
  /* Unlocked. */
30
  unsigned int magic;
31
  isc_mem_t *mctx;
32
  dns_qpmulti_t *table;
33
};
34
35
2
#define FWDTABLEMAGIC    ISC_MAGIC('F', 'w', 'd', 'T')
36
#define VALID_FWDTABLE(ft) ISC_MAGIC_VALID(ft, FWDTABLEMAGIC)
37
38
static void
39
qp_attach(void *uctx, void *pval, uint32_t ival);
40
static void
41
qp_detach(void *uctx, void *pval, uint32_t ival);
42
static size_t
43
qp_makekey(dns_qpkey_t key, void *uctx, void *pval, uint32_t ival);
44
static void
45
qp_triename(void *uctx, char *buf, size_t size);
46
47
static dns_qpmethods_t qpmethods = {
48
  qp_attach,
49
  qp_detach,
50
  qp_makekey,
51
  qp_triename,
52
};
53
54
void
55
dns_fwdtable_create(isc_mem_t *mctx, dns_view_t *view,
56
2
        dns_fwdtable_t **fwdtablep) {
57
2
  dns_fwdtable_t *fwdtable = NULL;
58
59
2
  REQUIRE(fwdtablep != NULL && *fwdtablep == NULL);
60
61
2
  fwdtable = isc_mem_get(mctx, sizeof(*fwdtable));
62
2
  *fwdtable = (dns_fwdtable_t){ .magic = FWDTABLEMAGIC };
63
64
2
  dns_qpmulti_create(mctx, &qpmethods, view, &fwdtable->table);
65
66
2
  isc_mem_attach(mctx, &fwdtable->mctx);
67
2
  *fwdtablep = fwdtable;
68
2
}
69
70
static dns_forwarders_t *
71
new_forwarders(isc_mem_t *mctx, const dns_name_t *name,
72
0
         dns_fwdpolicy_t fwdpolicy) {
73
0
  dns_forwarders_t *forwarders = NULL;
74
75
0
  forwarders = isc_mem_get(mctx, sizeof(*forwarders));
76
0
  *forwarders = (dns_forwarders_t){
77
0
    .fwdpolicy = fwdpolicy,
78
0
    .name = DNS_NAME_INITEMPTY,
79
0
    .fwdrs = ISC_LIST_INITIALIZER,
80
0
  };
81
0
  isc_mem_attach(mctx, &forwarders->mctx);
82
0
  isc_refcount_init(&forwarders->references, 1);
83
84
0
  dns_name_dup(name, mctx, &forwarders->name);
85
86
0
  return forwarders;
87
0
}
88
89
isc_result_t
90
dns_fwdtable_addfwd(dns_fwdtable_t *fwdtable, const dns_name_t *name,
91
0
        dns_forwarderlist_t *fwdrs, dns_fwdpolicy_t fwdpolicy) {
92
0
  isc_result_t result;
93
0
  dns_forwarders_t *forwarders = NULL;
94
0
  dns_qp_t *qp = NULL;
95
96
0
  REQUIRE(VALID_FWDTABLE(fwdtable));
97
98
0
  forwarders = new_forwarders(fwdtable->mctx, name, fwdpolicy);
99
100
0
  ISC_LIST_FOREACH(*fwdrs, fwd, link) {
101
0
    dns_forwarder_t *nfwd = isc_mem_get(fwdtable->mctx,
102
0
                sizeof(*nfwd));
103
0
    *nfwd = *fwd;
104
105
0
    if (fwd->tlsname != NULL) {
106
0
      nfwd->tlsname = isc_mem_get(fwdtable->mctx,
107
0
                sizeof(*nfwd->tlsname));
108
0
      dns_name_init(nfwd->tlsname);
109
0
      dns_name_dup(fwd->tlsname, fwdtable->mctx,
110
0
             nfwd->tlsname);
111
0
    }
112
113
0
    ISC_LINK_INIT(nfwd, link);
114
0
    ISC_LIST_APPEND(forwarders->fwdrs, nfwd, link);
115
0
  }
116
117
0
  dns_qpmulti_write(fwdtable->table, &qp);
118
0
  result = dns_qp_insert(qp, forwarders, 0);
119
0
  dns_qp_compact(qp, DNS_QPGC_MAYBE);
120
0
  dns_qpmulti_commit(fwdtable->table, &qp);
121
122
0
  dns_forwarders_detach(&forwarders);
123
124
0
  return result;
125
0
}
126
127
isc_result_t
128
dns_fwdtable_add(dns_fwdtable_t *fwdtable, const dns_name_t *name,
129
0
     isc_sockaddrlist_t *addrs, dns_fwdpolicy_t fwdpolicy) {
130
0
  isc_result_t result;
131
0
  dns_forwarders_t *forwarders = NULL;
132
0
  dns_qp_t *qp = NULL;
133
134
0
  REQUIRE(VALID_FWDTABLE(fwdtable));
135
136
0
  forwarders = new_forwarders(fwdtable->mctx, name, fwdpolicy);
137
138
0
  ISC_LIST_FOREACH(*addrs, sa, link) {
139
0
    dns_forwarder_t *fwd = isc_mem_get(fwdtable->mctx,
140
0
               sizeof(*fwd));
141
0
    *fwd = (dns_forwarder_t){ .addr = *sa,
142
0
            .link = ISC_LINK_INITIALIZER };
143
0
    ISC_LIST_APPEND(forwarders->fwdrs, fwd, link);
144
0
  }
145
146
0
  dns_qpmulti_write(fwdtable->table, &qp);
147
0
  result = dns_qp_insert(qp, forwarders, 0);
148
0
  dns_qp_compact(qp, DNS_QPGC_MAYBE);
149
0
  dns_qpmulti_commit(fwdtable->table, &qp);
150
151
0
  dns_forwarders_detach(&forwarders);
152
153
0
  return result;
154
0
}
155
156
isc_result_t
157
dns_fwdtable_find(dns_fwdtable_t *fwdtable, const dns_name_t *name,
158
0
      dns_forwarders_t **forwardersp) {
159
0
  isc_result_t result;
160
0
  dns_qpread_t qpr;
161
0
  void *pval = NULL;
162
163
0
  REQUIRE(VALID_FWDTABLE(fwdtable));
164
165
0
  dns_qpmulti_query(fwdtable->table, &qpr);
166
0
  result = dns_qp_lookup(&qpr, name, DNS_DBNAMESPACE_NORMAL, NULL, NULL,
167
0
             &pval, NULL);
168
0
  if (result == ISC_R_SUCCESS || result == DNS_R_PARTIALMATCH) {
169
0
    dns_forwarders_t *fwdrs = pval;
170
0
    *forwardersp = fwdrs;
171
0
    dns_forwarders_ref(fwdrs);
172
0
  }
173
0
  dns_qpread_destroy(fwdtable->table, &qpr);
174
175
0
  return result;
176
0
}
177
178
void
179
0
dns_fwdtable_destroy(dns_fwdtable_t **fwdtablep) {
180
0
  dns_fwdtable_t *fwdtable = NULL;
181
182
0
  REQUIRE(fwdtablep != NULL && VALID_FWDTABLE(*fwdtablep));
183
184
0
  fwdtable = *fwdtablep;
185
0
  *fwdtablep = NULL;
186
187
0
  dns_qpmulti_destroy(&fwdtable->table);
188
0
  fwdtable->magic = 0;
189
190
0
  isc_mem_putanddetach(&fwdtable->mctx, fwdtable, sizeof(*fwdtable));
191
0
}
192
193
/***
194
 *** Private
195
 ***/
196
197
static void
198
0
destroy_forwarders(dns_forwarders_t *forwarders) {
199
0
  ISC_LIST_FOREACH(forwarders->fwdrs, fwd, link) {
200
0
    ISC_LIST_UNLINK(forwarders->fwdrs, fwd, link);
201
0
    if (fwd->tlsname != NULL) {
202
0
      dns_name_free(fwd->tlsname, forwarders->mctx);
203
0
      isc_mem_put(forwarders->mctx, fwd->tlsname,
204
0
            sizeof(*fwd->tlsname));
205
0
    }
206
0
    isc_mem_put(forwarders->mctx, fwd, sizeof(*fwd));
207
0
  }
208
0
  dns_name_free(&forwarders->name, forwarders->mctx);
209
0
  isc_mem_putanddetach(&forwarders->mctx, forwarders,
210
0
           sizeof(*forwarders));
211
0
}
212
213
#if DNS_FORWARD_TRACE
214
ISC_REFCOUNT_TRACE_IMPL(dns_forwarders, destroy_forwarders);
215
#else
216
0
ISC_REFCOUNT_IMPL(dns_forwarders, destroy_forwarders);
Unexecuted instantiation: dns_forwarders_ref
Unexecuted instantiation: dns_forwarders_unref
Unexecuted instantiation: dns_forwarders_detach
217
0
#endif
218
0
219
0
static void
220
0
qp_attach(void *uctx ISC_ATTR_UNUSED, void *pval,
221
0
    uint32_t ival ISC_ATTR_UNUSED) {
222
0
  dns_forwarders_t *forwarders = pval;
223
0
  dns_forwarders_ref(forwarders);
224
0
}
225
226
static void
227
qp_detach(void *uctx ISC_ATTR_UNUSED, void *pval,
228
0
    uint32_t ival ISC_ATTR_UNUSED) {
229
0
  dns_forwarders_t *forwarders = pval;
230
0
  dns_forwarders_detach(&forwarders);
231
0
}
232
233
static size_t
234
qp_makekey(dns_qpkey_t key, void *uctx ISC_ATTR_UNUSED, void *pval,
235
0
     uint32_t ival ISC_ATTR_UNUSED) {
236
0
  dns_forwarders_t *fwd = pval;
237
0
  return dns_qpkey_fromname(key, &fwd->name, DNS_DBNAMESPACE_NORMAL);
238
0
}
239
240
static void
241
0
qp_triename(void *uctx, char *buf, size_t size) {
242
0
  dns_view_t *view = uctx;
243
0
  snprintf(buf, size, "view %s forwarder table", view->name);
244
0
}