Coverage Report

Created: 2025-11-09 06:44

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/bind9/lib/dns/zonefetch.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/async.h>
17
#include <isc/loop.h>
18
19
#include <dns/resolver.h>
20
#include <dns/view.h>
21
#include <dns/zone.h>
22
#include <dns/zonefetch.h>
23
24
#include "zone_p.h"
25
26
void
27
0
dns_zonefetch_run(void *arg) {
28
0
  dns_zonefetch_t *fetch = (dns_zonefetch_t *)arg;
29
0
  dns_zone_t *zone;
30
0
  dns_view_t *view;
31
0
  isc_loop_t *loop;
32
0
  isc_result_t result;
33
0
  dns_resolver_t *resolver = NULL;
34
35
0
  zone = fetch->zone;
36
0
  if (dns__zone_exiting(zone)) {
37
0
    result = ISC_R_SHUTTINGDOWN;
38
0
    goto cancel;
39
0
  }
40
0
  view = dns_zone_getview(zone);
41
0
  loop = dns_zone_getloop(zone);
42
43
0
  INSIST(view != NULL);
44
0
  INSIST(loop != NULL);
45
46
0
  fetch->fetchmethods.start_fetch(fetch);
47
48
0
  result = dns_view_getresolver(view, &resolver);
49
0
  if (result != ISC_R_SUCCESS) {
50
0
    goto cancel;
51
0
  }
52
53
0
  if (isc_log_wouldlog(ISC_LOG_DEBUG(3))) {
54
0
    char namebuf[DNS_NAME_FORMATSIZE];
55
0
    char typebuf[DNS_RDATATYPE_FORMATSIZE];
56
0
    dns_name_format(fetch->qname, namebuf, sizeof(namebuf));
57
0
    dns_rdatatype_format(fetch->qtype, typebuf, sizeof(typebuf));
58
0
    dns_zone_logc(zone, DNS_LOGCATEGORY_DNSSEC, ISC_LOG_DEBUG(3),
59
0
            "Do fetch for %s/%s request", namebuf, typebuf);
60
0
  }
61
62
  /*
63
   * Use of DNS_FETCHOPT_NOCACHED is essential here.  If it is not
64
   * set and the cache still holds a non-expired, validated version
65
   * of the RRset being queried for by the time the response is
66
   * received, the cached RRset will be passed to dns_zonefetch_done()
67
   * instead of the one received in the response as the latter will
68
   * have a lower trust level due to not being validated until
69
   * dns_zonefetch_done() is called.
70
   */
71
0
  INSIST((fetch->options & DNS_FETCHOPT_NOCACHED) != 0);
72
73
0
  result = dns_resolver_createfetch(
74
0
    resolver, fetch->qname, fetch->qtype, NULL, NULL, NULL, NULL, 0,
75
0
    fetch->options, 0, NULL, NULL, loop, dns_zonefetch_done, fetch,
76
0
    NULL, &fetch->rrset, &fetch->sigset, &fetch->fetch);
77
78
0
  dns_resolver_detach(&resolver);
79
80
0
cancel:
81
0
  if (result == ISC_R_SUCCESS) {
82
0
    return;
83
0
  } else if (result != ISC_R_SHUTTINGDOWN) {
84
0
    char namebuf[DNS_NAME_FORMATSIZE];
85
0
    char typebuf[DNS_RDATATYPE_FORMATSIZE];
86
0
    dns_name_format(fetch->qname, namebuf, sizeof(namebuf));
87
0
    dns_rdatatype_format(fetch->qtype, typebuf, sizeof(typebuf));
88
0
    dns_zone_log(zone, ISC_LOG_WARNING,
89
0
           "Failed fetch for %s/%s request", namebuf,
90
0
           typebuf);
91
0
  }
92
93
  /*
94
   * Fetch failed, cancel.
95
   */
96
0
  dns__zone_lock(zone);
97
98
0
  dns_name_t *zname = dns_fixedname_name(&fetch->name);
99
0
  isc_mem_t *mctx = dns_zone_getmctx(zone);
100
0
  bool free_needed;
101
102
0
  isc_refcount_decrement(dns__zone_irefs(zone));
103
0
  dns_name_free(zname, mctx);
104
105
0
  fetch->fetchmethods.cancel_fetch(fetch);
106
107
0
  isc_mem_putanddetach(&fetch->mctx, fetch, sizeof(*fetch));
108
0
  free_needed = dns__zone_free_check(zone);
109
110
0
  dns__zone_unlock(zone);
111
112
0
  if (free_needed) {
113
0
    dns__zone_free(zone);
114
0
  }
115
0
}
116
117
void
118
0
dns_zonefetch_done(void *arg) {
119
0
  dns_fetchresponse_t *resp = (dns_fetchresponse_t *)arg;
120
0
  isc_result_t result = ISC_R_NOMORE;
121
0
  isc_result_t eresult;
122
0
  dns_zonefetch_t *fetch = NULL;
123
0
  dns_zone_t *zone = NULL;
124
0
  dns_view_t *view = NULL;
125
0
  isc_mem_t *mctx = NULL;
126
0
  dns_name_t *zname = NULL;
127
0
  dns_rdataset_t *rrset = NULL;
128
0
  dns_rdataset_t *sigset = NULL;
129
130
0
  INSIST(resp != NULL);
131
132
0
  fetch = resp->arg;
133
134
0
  INSIST(fetch != NULL);
135
136
0
  mctx = fetch->mctx;
137
0
  zone = fetch->zone;
138
0
  zname = dns_fixedname_name(&fetch->name);
139
0
  rrset = &fetch->rrset;
140
0
  sigset = &fetch->sigset;
141
0
  view = dns_zone_getview(zone);
142
0
  eresult = resp->result;
143
144
  /* Free resources which are not of interest */
145
0
  if (resp->node != NULL) {
146
0
    dns_db_detachnode(&resp->node);
147
0
  }
148
0
  if (resp->db != NULL) {
149
0
    dns_db_detach(&resp->db);
150
0
  }
151
0
  dns_resolver_destroyfetch(&fetch->fetch);
152
153
0
  dns__zone_lock(zone);
154
0
  if (dns__zone_exiting(zone) || view == NULL) {
155
0
    goto cleanup;
156
0
  }
157
158
0
  result = fetch->fetchmethods.done_fetch(fetch, eresult);
159
160
0
cleanup:
161
0
  isc_refcount_decrement(dns__zone_irefs(zone));
162
163
0
  if (dns_rdataset_isassociated(rrset)) {
164
0
    dns_rdataset_disassociate(rrset);
165
0
  }
166
0
  if (dns_rdataset_isassociated(sigset)) {
167
0
    dns_rdataset_disassociate(sigset);
168
0
  }
169
170
0
  fetch->fetchmethods.cleanup_fetch(fetch);
171
172
0
  dns_resolver_freefresp(&resp);
173
174
0
  if (result == DNS_R_CONTINUE) {
175
0
    dns__zone_unlock(zone);
176
0
    fetch->fetchmethods.continue_fetch(fetch);
177
0
  } else {
178
0
    bool free_needed = false;
179
0
    dns_name_free(zname, mctx);
180
0
    isc_mem_putanddetach(&fetch->mctx, fetch,
181
0
             sizeof(dns_zonefetch_t));
182
0
    free_needed = dns__zone_free_check(zone);
183
184
0
    dns__zone_unlock(zone);
185
186
0
    if (free_needed) {
187
0
      dns__zone_free(zone);
188
0
    }
189
0
  }
190
0
}
191
192
static void
193
0
zonefetch_schedule(dns_zonefetch_t *fetch, dns_name_t *name) {
194
0
  dns_zone_t *zone = fetch->zone;
195
196
0
  isc_refcount_increment0(dns__zone_irefs(zone));
197
198
0
  if (name != NULL) {
199
0
    dns_name_t *fname = dns_fixedname_initname(&fetch->name);
200
0
    dns_name_dup(name, fetch->mctx, fname);
201
0
  }
202
203
0
  dns_rdataset_init(&fetch->rrset);
204
0
  dns_rdataset_init(&fetch->sigset);
205
206
0
  isc_async_run(dns_zone_getloop(zone), dns_zonefetch_run, fetch);
207
0
}
208
209
void
210
0
dns_zonefetch_schedule(dns_zonefetch_t *fetch, dns_name_t *name) {
211
0
  REQUIRE(fetch != NULL);
212
0
  REQUIRE(name != NULL);
213
214
0
  zonefetch_schedule(fetch, name);
215
0
}
216
217
void
218
0
dns_zonefetch_reschedule(dns_zonefetch_t *fetch) {
219
0
  REQUIRE(fetch != NULL);
220
221
0
  zonefetch_schedule(fetch, NULL);
222
0
}
223
224
isc_result_t
225
dns_zonefetch_verify(dns_zonefetch_t *fetch, isc_result_t eresult,
226
0
         dns_trust_t trust) {
227
0
  char namebuf[DNS_NAME_FORMATSIZE];
228
0
  char typebuf[DNS_RDATATYPE_FORMATSIZE];
229
0
  dns_rdataset_t *rrset = NULL;
230
0
  dns_rdataset_t *sigset = NULL;
231
232
0
  REQUIRE(fetch != NULL);
233
234
0
  rrset = &fetch->rrset;
235
0
  sigset = &fetch->sigset;
236
0
  dns_name_format(fetch->qname, namebuf, sizeof(namebuf));
237
0
  dns_rdatatype_format(fetch->qtype, typebuf, sizeof(typebuf));
238
239
0
  if (eresult != ISC_R_SUCCESS) {
240
0
    dns_zone_logc(fetch->zone, DNS_LOGCATEGORY_DNSSEC,
241
0
            ISC_LOG_WARNING, "Unable to fetch %s/%s: %s",
242
0
            namebuf, typebuf, isc_result_totext(eresult));
243
0
    return eresult;
244
0
  }
245
246
  /* No records found */
247
0
  if (!dns_rdataset_isassociated(rrset)) {
248
0
    dns_zone_logc(fetch->zone, DNS_LOGCATEGORY_DNSSEC,
249
0
            ISC_LOG_WARNING, "No %s records found for '%s'",
250
0
            typebuf, namebuf);
251
0
    return ISC_R_NOTFOUND;
252
0
  }
253
254
  /* No RRSIGs found */
255
0
  if (!dns_rdataset_isassociated(sigset)) {
256
0
    dns_zone_logc(fetch->zone, DNS_LOGCATEGORY_DNSSEC,
257
0
            ISC_LOG_WARNING, "No %s RRSIGs found for '%s'",
258
0
            typebuf, namebuf);
259
0
    return DNS_R_NOVALIDSIG;
260
0
  }
261
262
  /* Check trust level */
263
0
  if (rrset->trust < trust) {
264
0
    dns_zone_logc(fetch->zone, DNS_LOGCATEGORY_DNSSEC,
265
0
            ISC_LOG_WARNING,
266
0
            "Invalid %s RRset for '%s' trust level %u",
267
0
            typebuf, namebuf, rrset->trust);
268
0
    return DNS_R_NOVALIDSIG;
269
0
  }
270
271
0
  return ISC_R_SUCCESS;
272
0
}