query.c revision 1.25 1 1.25 christos /* $NetBSD: query.c,v 1.25 2025/07/17 19:01:47 christos Exp $ */
2 1.1 christos
3 1.1 christos /*
4 1.1 christos * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
5 1.1 christos *
6 1.15 christos * SPDX-License-Identifier: MPL-2.0
7 1.15 christos *
8 1.1 christos * This Source Code Form is subject to the terms of the Mozilla Public
9 1.1 christos * License, v. 2.0. If a copy of the MPL was not distributed with this
10 1.11 christos * file, you can obtain one at https://mozilla.org/MPL/2.0/.
11 1.1 christos *
12 1.1 christos * See the COPYRIGHT file distributed with this work for additional
13 1.1 christos * information regarding copyright ownership.
14 1.1 christos */
15 1.1 christos
16 1.1 christos /*! \file */
17 1.1 christos
18 1.14 christos #include <ctype.h>
19 1.3 christos #include <inttypes.h>
20 1.3 christos #include <stdbool.h>
21 1.23 christos #include <stdint.h>
22 1.1 christos #include <string.h>
23 1.1 christos
24 1.23 christos #include <isc/async.h>
25 1.24 christos #include <isc/counter.h>
26 1.1 christos #include <isc/hex.h>
27 1.1 christos #include <isc/mem.h>
28 1.9 christos #include <isc/once.h>
29 1.1 christos #include <isc/random.h>
30 1.20 christos #include <isc/result.h>
31 1.1 christos #include <isc/rwlock.h>
32 1.1 christos #include <isc/serial.h>
33 1.1 christos #include <isc/stats.h>
34 1.1 christos #include <isc/string.h>
35 1.1 christos #include <isc/thread.h>
36 1.1 christos #include <isc/util.h>
37 1.1 christos
38 1.1 christos #include <dns/adb.h>
39 1.1 christos #include <dns/badcache.h>
40 1.1 christos #include <dns/byaddr.h>
41 1.1 christos #include <dns/cache.h>
42 1.1 christos #include <dns/db.h>
43 1.1 christos #include <dns/dlz.h>
44 1.1 christos #include <dns/dns64.h>
45 1.1 christos #include <dns/dnsrps.h>
46 1.1 christos #include <dns/dnssec.h>
47 1.24 christos #include <dns/ede.h>
48 1.1 christos #include <dns/keytable.h>
49 1.1 christos #include <dns/message.h>
50 1.1 christos #include <dns/ncache.h>
51 1.1 christos #include <dns/nsec.h>
52 1.1 christos #include <dns/nsec3.h>
53 1.1 christos #include <dns/order.h>
54 1.20 christos #include <dns/rbt.h>
55 1.23 christos #include <dns/rcode.h>
56 1.1 christos #include <dns/rdata.h>
57 1.1 christos #include <dns/rdataclass.h>
58 1.1 christos #include <dns/rdatalist.h>
59 1.1 christos #include <dns/rdataset.h>
60 1.1 christos #include <dns/rdatasetiter.h>
61 1.1 christos #include <dns/rdatastruct.h>
62 1.1 christos #include <dns/rdatatype.h>
63 1.1 christos #include <dns/resolver.h>
64 1.1 christos #include <dns/result.h>
65 1.1 christos #include <dns/stats.h>
66 1.1 christos #include <dns/tkey.h>
67 1.1 christos #include <dns/types.h>
68 1.1 christos #include <dns/view.h>
69 1.1 christos #include <dns/zone.h>
70 1.1 christos #include <dns/zt.h>
71 1.1 christos
72 1.1 christos #include <ns/client.h>
73 1.9 christos #include <ns/hooks.h>
74 1.1 christos #include <ns/interfacemgr.h>
75 1.1 christos #include <ns/log.h>
76 1.1 christos #include <ns/server.h>
77 1.1 christos #include <ns/sortlist.h>
78 1.1 christos #include <ns/stats.h>
79 1.1 christos #include <ns/xfrout.h>
80 1.1 christos
81 1.23 christos #include "probes.h"
82 1.7 christos
83 1.1 christos #if 0
84 1.1 christos /*
85 1.1 christos * It has been recommended that DNS64 be changed to return excluded
86 1.1 christos * AAAA addresses if DNS64 synthesis does not occur. This minimises
87 1.1 christos * the impact on the lookup results. While most DNS AAAA lookups are
88 1.1 christos * done to send IP packets to a host, not all of them are and filtering
89 1.1 christos * excluded addresses has a negative impact on those uses.
90 1.1 christos */
91 1.1 christos #define dns64_bis_return_excluded_addresses 1
92 1.9 christos #endif /* if 0 */
93 1.1 christos
94 1.11 christos #define QUERY_ERROR(qctx, r) \
95 1.11 christos do { \
96 1.11 christos (qctx)->result = r; \
97 1.11 christos (qctx)->want_restart = false; \
98 1.11 christos (qctx)->line = __LINE__; \
99 1.12 rillig } while (0)
100 1.1 christos
101 1.1 christos /*% Partial answer? */
102 1.9 christos #define PARTIALANSWER(c) \
103 1.9 christos (((c)->query.attributes & NS_QUERYATTR_PARTIALANSWER) != 0)
104 1.1 christos /*% Use Cache? */
105 1.9 christos #define USECACHE(c) (((c)->query.attributes & NS_QUERYATTR_CACHEOK) != 0)
106 1.1 christos /*% Recursion OK? */
107 1.9 christos #define RECURSIONOK(c) (((c)->query.attributes & NS_QUERYATTR_RECURSIONOK) != 0)
108 1.1 christos /*% Recursing? */
109 1.9 christos #define RECURSING(c) (((c)->query.attributes & NS_QUERYATTR_RECURSING) != 0)
110 1.1 christos /*% Want Recursion? */
111 1.9 christos #define WANTRECURSION(c) \
112 1.9 christos (((c)->query.attributes & NS_QUERYATTR_WANTRECURSION) != 0)
113 1.1 christos /*% Is TCP? */
114 1.9 christos #define TCP(c) (((c)->attributes & NS_CLIENTATTR_TCP) != 0)
115 1.1 christos
116 1.1 christos /*% Want DNSSEC? */
117 1.9 christos #define WANTDNSSEC(c) (((c)->attributes & NS_CLIENTATTR_WANTDNSSEC) != 0)
118 1.1 christos /*% Want WANTAD? */
119 1.9 christos #define WANTAD(c) (((c)->attributes & NS_CLIENTATTR_WANTAD) != 0)
120 1.23 christos /*% Client presented a bad COOKIE. */
121 1.23 christos #define BADCOOKIE(c) (((c)->attributes & NS_CLIENTATTR_BADCOOKIE) != 0)
122 1.1 christos /*% Client presented a valid COOKIE. */
123 1.9 christos #define HAVECOOKIE(c) (((c)->attributes & NS_CLIENTATTR_HAVECOOKIE) != 0)
124 1.1 christos /*% Client presented a COOKIE. */
125 1.9 christos #define WANTCOOKIE(c) (((c)->attributes & NS_CLIENTATTR_WANTCOOKIE) != 0)
126 1.1 christos /*% Client presented a CLIENT-SUBNET option. */
127 1.9 christos #define HAVEECS(c) (((c)->attributes & NS_CLIENTATTR_HAVEECS) != 0)
128 1.1 christos /*% No authority? */
129 1.9 christos #define NOAUTHORITY(c) (((c)->query.attributes & NS_QUERYATTR_NOAUTHORITY) != 0)
130 1.1 christos /*% No additional? */
131 1.9 christos #define NOADDITIONAL(c) \
132 1.9 christos (((c)->query.attributes & NS_QUERYATTR_NOADDITIONAL) != 0)
133 1.1 christos /*% Secure? */
134 1.9 christos #define SECURE(c) (((c)->query.attributes & NS_QUERYATTR_SECURE) != 0)
135 1.1 christos /*% DNS64 A lookup? */
136 1.9 christos #define DNS64(c) (((c)->query.attributes & NS_QUERYATTR_DNS64) != 0)
137 1.1 christos
138 1.9 christos #define DNS64EXCLUDE(c) \
139 1.9 christos (((c)->query.attributes & NS_QUERYATTR_DNS64EXCLUDE) != 0)
140 1.1 christos
141 1.9 christos #define REDIRECT(c) (((c)->query.attributes & NS_QUERYATTR_REDIRECT) != 0)
142 1.1 christos
143 1.14 christos /*% Was the client already sent a response? */
144 1.11 christos #define QUERY_ANSWERED(q) (((q)->attributes & NS_QUERYATTR_ANSWERED) != 0)
145 1.11 christos
146 1.13 christos /*% Does the query allow stale data in the response? */
147 1.13 christos #define QUERY_STALEOK(q) (((q)->attributes & NS_QUERYATTR_STALEOK) != 0)
148 1.13 christos
149 1.13 christos /*% Does the query wants to check for stale RRset due to a timeout? */
150 1.13 christos #define QUERY_STALETIMEOUT(q) (((q)->dboptions & DNS_DBFIND_STALETIMEOUT) != 0)
151 1.11 christos
152 1.1 christos /*% Does the rdataset 'r' have an attached 'No QNAME Proof'? */
153 1.9 christos #define NOQNAME(r) (((r)->attributes & DNS_RDATASETATTR_NOQNAME) != 0)
154 1.1 christos
155 1.4 christos /*% Does the rdataset 'r' contain a stale answer? */
156 1.9 christos #define STALE(r) (((r)->attributes & DNS_RDATASETATTR_STALE) != 0)
157 1.1 christos
158 1.11 christos /*% Does the rdataset 'r' is stale and within stale-refresh-time? */
159 1.11 christos #define STALE_WINDOW(r) (((r)->attributes & DNS_RDATASETATTR_STALE_WINDOW) != 0)
160 1.11 christos
161 1.1 christos #ifdef WANT_QUERYTRACE
162 1.15 christos static void
163 1.1 christos client_trace(ns_client_t *client, int level, const char *message) {
164 1.1 christos if (client != NULL && client->query.qname != NULL) {
165 1.1 christos if (isc_log_wouldlog(ns_lctx, level)) {
166 1.1 christos char qbuf[DNS_NAME_FORMATSIZE];
167 1.1 christos char tbuf[DNS_RDATATYPE_FORMATSIZE];
168 1.9 christos dns_name_format(client->query.qname, qbuf,
169 1.9 christos sizeof(qbuf));
170 1.9 christos dns_rdatatype_format(client->query.qtype, tbuf,
171 1.9 christos sizeof(tbuf));
172 1.9 christos isc_log_write(ns_lctx, NS_LOGCATEGORY_CLIENT,
173 1.1 christos NS_LOGMODULE_QUERY, level,
174 1.13 christos "query client=%p thread=0x%" PRIxPTR
175 1.1 christos "(%s/%s): %s",
176 1.13 christos client, isc_thread_self(), qbuf, tbuf,
177 1.13 christos message);
178 1.1 christos }
179 1.9 christos } else {
180 1.9 christos isc_log_write(ns_lctx, NS_LOGCATEGORY_CLIENT,
181 1.1 christos NS_LOGMODULE_QUERY, level,
182 1.13 christos "query client=%p thread=0x%" PRIxPTR
183 1.1 christos "(<unknown-query>): %s",
184 1.13 christos client, isc_thread_self(), message);
185 1.1 christos }
186 1.1 christos }
187 1.9 christos #define CTRACE(l, m) client_trace(client, l, m)
188 1.9 christos #define CCTRACE(l, m) client_trace(qctx->client, l, m)
189 1.9 christos #else /* ifdef WANT_QUERYTRACE */
190 1.9 christos #define CTRACE(l, m) ((void)m)
191 1.9 christos #define CCTRACE(l, m) ((void)m)
192 1.1 christos #endif /* WANT_QUERYTRACE */
193 1.1 christos
194 1.20 christos #define PENDINGOK(x) (((x) & DNS_DBFIND_PENDINGOK) != 0)
195 1.1 christos
196 1.1 christos #define SFCACHE_CDFLAG 0x1
197 1.1 christos
198 1.1 christos /*
199 1.20 christos * SAVE and RESTORE have the same semantics as:
200 1.1 christos *
201 1.20 christos * foo_attach(b, &a);
202 1.20 christos * foo_detach(&b);
203 1.1 christos *
204 1.1 christos * without the locking and magic testing.
205 1.1 christos *
206 1.20 christos * We use the names SAVE and RESTORE to show the operation being performed,
207 1.20 christos * even though the two macros are identical.
208 1.1 christos */
209 1.9 christos #define SAVE(a, b) \
210 1.9 christos do { \
211 1.9 christos INSIST(a == NULL); \
212 1.9 christos a = b; \
213 1.9 christos b = NULL; \
214 1.12 rillig } while (0)
215 1.1 christos #define RESTORE(a, b) SAVE(a, b)
216 1.1 christos
217 1.3 christos static bool
218 1.1 christos validate(ns_client_t *client, dns_db_t *db, dns_name_t *name,
219 1.1 christos dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset);
220 1.1 christos
221 1.1 christos static void
222 1.1 christos query_findclosestnsec3(dns_name_t *qname, dns_db_t *db,
223 1.1 christos dns_dbversion_t *version, ns_client_t *client,
224 1.1 christos dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset,
225 1.9 christos dns_name_t *fname, bool exact, dns_name_t *found);
226 1.1 christos
227 1.15 christos static void
228 1.1 christos log_queryerror(ns_client_t *client, isc_result_t result, int line, int level);
229 1.1 christos
230 1.1 christos static void
231 1.1 christos rpz_st_clear(ns_client_t *client);
232 1.1 christos
233 1.3 christos static bool
234 1.1 christos rpz_ck_dnssec(ns_client_t *client, isc_result_t qresult,
235 1.1 christos dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset);
236 1.1 christos
237 1.1 christos static void
238 1.1 christos log_noexistnodata(void *val, int level, const char *fmt, ...)
239 1.1 christos ISC_FORMAT_PRINTF(3, 4);
240 1.1 christos
241 1.20 christos static isc_result_t
242 1.20 christos query_addanswer(query_ctx_t *qctx);
243 1.20 christos
244 1.20 christos static isc_result_t
245 1.20 christos query_prepare_delegation_response(query_ctx_t *qctx);
246 1.20 christos
247 1.23 christos static isc_result_t
248 1.23 christos acquire_recursionquota(ns_client_t *client);
249 1.23 christos
250 1.23 christos static void
251 1.23 christos release_recursionquota(ns_client_t *client);
252 1.23 christos
253 1.3 christos /*
254 1.3 christos * Return the hooktable in use with 'qctx', or if there isn't one
255 1.3 christos * set, return the default hooktable.
256 1.3 christos */
257 1.15 christos static ns_hooktable_t *
258 1.3 christos get_hooktab(query_ctx_t *qctx) {
259 1.9 christos if (qctx == NULL || qctx->view == NULL || qctx->view->hooktable == NULL)
260 1.3 christos {
261 1.23 christos return ns__hook_table;
262 1.3 christos }
263 1.1 christos
264 1.23 christos return qctx->view->hooktable;
265 1.3 christos }
266 1.1 christos
267 1.3 christos /*
268 1.3 christos * Call the specified hook function in every configured module that implements
269 1.3 christos * that function. If any hook function returns NS_HOOK_RETURN, we
270 1.3 christos * set 'result' and terminate processing by jumping to the 'cleanup' tag.
271 1.3 christos *
272 1.3 christos * (Note that a hook function may set the 'result' to ISC_R_SUCCESS but
273 1.3 christos * still terminate processing within the calling function. That's why this
274 1.15 christos * is a macro instead of a static function; it needs to be able to use
275 1.3 christos * 'goto cleanup' regardless of the return value.)
276 1.3 christos */
277 1.9 christos #define CALL_HOOK(_id, _qctx) \
278 1.9 christos do { \
279 1.20 christos isc_result_t _res = result; \
280 1.9 christos ns_hooktable_t *_tab = get_hooktab(_qctx); \
281 1.9 christos ns_hook_t *_hook; \
282 1.9 christos _hook = ISC_LIST_HEAD((*_tab)[_id]); \
283 1.9 christos while (_hook != NULL) { \
284 1.9 christos ns_hook_action_t _func = _hook->action; \
285 1.9 christos void *_data = _hook->action_data; \
286 1.9 christos INSIST(_func != NULL); \
287 1.9 christos switch (_func(_qctx, _data, &_res)) { \
288 1.9 christos case NS_HOOK_CONTINUE: \
289 1.9 christos _hook = ISC_LIST_NEXT(_hook, link); \
290 1.9 christos break; \
291 1.9 christos case NS_HOOK_RETURN: \
292 1.9 christos result = _res; \
293 1.9 christos goto cleanup; \
294 1.9 christos default: \
295 1.15 christos UNREACHABLE(); \
296 1.9 christos } \
297 1.9 christos } \
298 1.3 christos } while (false)
299 1.1 christos
300 1.3 christos /*
301 1.3 christos * Call the specified hook function in every configured module that
302 1.3 christos * implements that function. All modules are called; hook function return
303 1.3 christos * codes are ignored. This is intended for use with initialization and
304 1.3 christos * destruction calls which *must* run in every configured module.
305 1.3 christos *
306 1.15 christos * (This could be implemented as a static void function, but is left as a
307 1.3 christos * macro for symmetry with CALL_HOOK above.)
308 1.3 christos */
309 1.9 christos #define CALL_HOOK_NORETURN(_id, _qctx) \
310 1.9 christos do { \
311 1.9 christos isc_result_t _res; \
312 1.9 christos ns_hooktable_t *_tab = get_hooktab(_qctx); \
313 1.9 christos ns_hook_t *_hook; \
314 1.9 christos _hook = ISC_LIST_HEAD((*_tab)[_id]); \
315 1.9 christos while (_hook != NULL) { \
316 1.9 christos ns_hook_action_t _func = _hook->action; \
317 1.9 christos void *_data = _hook->action_data; \
318 1.9 christos INSIST(_func != NULL); \
319 1.9 christos _func(_qctx, _data, &_res); \
320 1.9 christos _hook = ISC_LIST_NEXT(_hook, link); \
321 1.9 christos } \
322 1.3 christos } while (false)
323 1.1 christos
324 1.1 christos /*
325 1.1 christos * The functions defined below implement the query logic that previously lived
326 1.1 christos * in the single very complex function query_find(). The query_ctx_t structure
327 1.1 christos * defined in <ns/query.h> maintains state from function to function. The call
328 1.1 christos * flow for the general query processing algorithm is described below:
329 1.1 christos *
330 1.1 christos * 1. Set up query context and other resources for a client
331 1.1 christos * query (query_setup())
332 1.1 christos *
333 1.1 christos * 2. Start the search (ns__query_start())
334 1.1 christos *
335 1.1 christos * 3. Identify authoritative data sources which may have an answer;
336 1.1 christos * search them (query_lookup()). If an answer is found, go to 7.
337 1.1 christos *
338 1.1 christos * 4. If recursion or cache access are allowed, search the cache
339 1.1 christos * (query_lookup() again, using the cache database) to find a better
340 1.1 christos * answer. If an answer is found, go to 7.
341 1.1 christos *
342 1.3 christos * 5. If recursion is allowed, begin recursion (ns_query_recurse()).
343 1.1 christos * Go to 15 to clean up this phase of the query. When recursion
344 1.1 christos * is complete, processing will resume at 6.
345 1.1 christos *
346 1.1 christos * 6. Resume from recursion; set up query context for resumed processing.
347 1.1 christos *
348 1.1 christos * 7. Determine what sort of answer we've found (query_gotanswer())
349 1.1 christos * and call other functions accordingly:
350 1.1 christos * - not found (auth or cache), go to 8
351 1.1 christos * - delegation, go to 9
352 1.1 christos * - no such domain (auth), go to 10
353 1.1 christos * - empty answer (auth), go to 11
354 1.1 christos * - negative response (cache), go to 12
355 1.1 christos * - answer found, go to 13
356 1.1 christos *
357 1.1 christos * 8. The answer was not found in the database (query_notfound().
358 1.1 christos * Set up a referral and go to 9.
359 1.1 christos *
360 1.3 christos * 9. Handle a delegation response (query_delegation()). If we need
361 1.3 christos * to and are allowed to recurse (query_delegation_recurse()), go to 5,
362 1.3 christos * otherwise go to 15 to clean up and return the delegation to the client.
363 1.1 christos *
364 1.1 christos * 10. No such domain (query_nxdomain()). Attempt redirection; if
365 1.1 christos * unsuccessful, add authority section records (query_addsoa(),
366 1.1 christos * query_addauth()), then go to 15 to return NXDOMAIN to client.
367 1.1 christos *
368 1.1 christos * 11. Empty answer (query_nodata()). Add authority section records
369 1.1 christos * (query_addsoa(), query_addauth()) and signatures if authoritative
370 1.1 christos * (query_sign_nodata()) then go to 15 and return
371 1.1 christos * NOERROR/ANCOUNT=0 to client.
372 1.1 christos *
373 1.1 christos * 12. No such domain or empty answer returned from cache (query_ncache()).
374 1.1 christos * Set response code appropriately, go to 11.
375 1.1 christos *
376 1.1 christos * 13. Prepare a response (query_prepresponse()) and then fill it
377 1.1 christos * appropriately (query_respond(), or for type ANY,
378 1.1 christos * query_respond_any()).
379 1.1 christos *
380 1.1 christos * 14. If a restart is needed due to CNAME/DNAME chaining, go to 2.
381 1.1 christos *
382 1.1 christos * 15. Clean up resources. If recursing, stop and wait for the event
383 1.1 christos * handler to be called back (step 6). If an answer is ready,
384 1.1 christos * return it to the client.
385 1.1 christos *
386 1.1 christos * (XXX: This description omits several special cases including
387 1.3 christos * DNS64, RPZ, RRL, and the SERVFAIL cache. It also doesn't discuss
388 1.3 christos * plugins.)
389 1.1 christos */
390 1.1 christos
391 1.1 christos static void
392 1.1 christos query_trace(query_ctx_t *qctx);
393 1.1 christos
394 1.1 christos static void
395 1.23 christos qctx_init(ns_client_t *client, dns_fetchresponse_t **respp,
396 1.23 christos dns_rdatatype_t qtype, query_ctx_t *qctx);
397 1.1 christos
398 1.1 christos static isc_result_t
399 1.23 christos qctx_prepare_buffers(query_ctx_t *qctx, isc_buffer_t *buffer);
400 1.23 christos
401 1.23 christos static void
402 1.23 christos qctx_freedata(query_ctx_t *qctx);
403 1.23 christos
404 1.23 christos static void
405 1.23 christos qctx_destroy(query_ctx_t *qctx);
406 1.23 christos
407 1.23 christos static void
408 1.1 christos query_setup(ns_client_t *client, dns_rdatatype_t qtype);
409 1.1 christos
410 1.1 christos static isc_result_t
411 1.1 christos query_lookup(query_ctx_t *qctx);
412 1.1 christos
413 1.1 christos static void
414 1.23 christos fetch_callback(void *arg);
415 1.1 christos
416 1.1 christos static void
417 1.1 christos recparam_update(ns_query_recparam_t *param, dns_rdatatype_t qtype,
418 1.1 christos const dns_name_t *qname, const dns_name_t *qdomain);
419 1.1 christos
420 1.1 christos static isc_result_t
421 1.1 christos query_resume(query_ctx_t *qctx);
422 1.1 christos
423 1.1 christos static isc_result_t
424 1.1 christos query_checkrrl(query_ctx_t *qctx, isc_result_t result);
425 1.1 christos
426 1.1 christos static isc_result_t
427 1.1 christos query_checkrpz(query_ctx_t *qctx, isc_result_t result);
428 1.1 christos
429 1.1 christos static isc_result_t
430 1.1 christos query_rpzcname(query_ctx_t *qctx, dns_name_t *cname);
431 1.1 christos
432 1.1 christos static isc_result_t
433 1.1 christos query_gotanswer(query_ctx_t *qctx, isc_result_t result);
434 1.1 christos
435 1.1 christos static void
436 1.1 christos query_addnoqnameproof(query_ctx_t *qctx);
437 1.1 christos
438 1.1 christos static isc_result_t
439 1.1 christos query_respond_any(query_ctx_t *qctx);
440 1.1 christos
441 1.1 christos static isc_result_t
442 1.1 christos query_respond(query_ctx_t *qctx);
443 1.1 christos
444 1.1 christos static isc_result_t
445 1.1 christos query_dns64(query_ctx_t *qctx);
446 1.1 christos
447 1.1 christos static void
448 1.1 christos query_filter64(query_ctx_t *qctx);
449 1.1 christos
450 1.1 christos static isc_result_t
451 1.1 christos query_notfound(query_ctx_t *qctx);
452 1.1 christos
453 1.1 christos static isc_result_t
454 1.1 christos query_zone_delegation(query_ctx_t *qctx);
455 1.1 christos
456 1.1 christos static isc_result_t
457 1.1 christos query_delegation(query_ctx_t *qctx);
458 1.1 christos
459 1.3 christos static isc_result_t
460 1.3 christos query_delegation_recurse(query_ctx_t *qctx);
461 1.3 christos
462 1.1 christos static void
463 1.1 christos query_addds(query_ctx_t *qctx);
464 1.1 christos
465 1.1 christos static isc_result_t
466 1.1 christos query_nodata(query_ctx_t *qctx, isc_result_t result);
467 1.1 christos
468 1.1 christos static isc_result_t
469 1.1 christos query_sign_nodata(query_ctx_t *qctx);
470 1.1 christos
471 1.1 christos static void
472 1.1 christos query_addnxrrsetnsec(query_ctx_t *qctx);
473 1.1 christos
474 1.1 christos static isc_result_t
475 1.18 christos query_nxdomain(query_ctx_t *qctx, isc_result_t result);
476 1.1 christos
477 1.1 christos static isc_result_t
478 1.18 christos query_redirect(query_ctx_t *qctx, isc_result_t result);
479 1.1 christos
480 1.1 christos static isc_result_t
481 1.1 christos query_ncache(query_ctx_t *qctx, isc_result_t result);
482 1.1 christos
483 1.1 christos static isc_result_t
484 1.1 christos query_coveringnsec(query_ctx_t *qctx);
485 1.1 christos
486 1.1 christos static isc_result_t
487 1.3 christos query_zerottl_refetch(query_ctx_t *qctx);
488 1.3 christos
489 1.3 christos static isc_result_t
490 1.1 christos query_cname(query_ctx_t *qctx);
491 1.1 christos
492 1.1 christos static isc_result_t
493 1.1 christos query_dname(query_ctx_t *qctx);
494 1.1 christos
495 1.23 christos static void
496 1.1 christos query_addcname(query_ctx_t *qctx, dns_trust_t trust, dns_ttl_t ttl);
497 1.1 christos
498 1.1 christos static isc_result_t
499 1.1 christos query_prepresponse(query_ctx_t *qctx);
500 1.1 christos
501 1.1 christos static isc_result_t
502 1.1 christos query_addsoa(query_ctx_t *qctx, unsigned int override_ttl,
503 1.1 christos dns_section_t section);
504 1.1 christos
505 1.1 christos static isc_result_t
506 1.1 christos query_addns(query_ctx_t *qctx);
507 1.1 christos
508 1.1 christos static void
509 1.1 christos query_addbestns(query_ctx_t *qctx);
510 1.1 christos
511 1.1 christos static void
512 1.3 christos query_addwildcardproof(query_ctx_t *qctx, bool ispositive, bool nodata);
513 1.1 christos
514 1.1 christos static void
515 1.1 christos query_addauth(query_ctx_t *qctx);
516 1.1 christos
517 1.13 christos static void
518 1.13 christos query_clear_stale(ns_client_t *client);
519 1.13 christos
520 1.3 christos /*
521 1.1 christos * Increment query statistics counters.
522 1.1 christos */
523 1.15 christos static void
524 1.1 christos inc_stats(ns_client_t *client, isc_statscounter_t counter) {
525 1.1 christos dns_zone_t *zone = client->query.authzone;
526 1.1 christos dns_rdatatype_t qtype;
527 1.1 christos dns_rdataset_t *rdataset;
528 1.1 christos isc_stats_t *zonestats;
529 1.1 christos dns_stats_t *querystats = NULL;
530 1.1 christos
531 1.23 christos ns_stats_increment(client->manager->sctx->nsstats, counter);
532 1.1 christos
533 1.9 christos if (zone == NULL) {
534 1.1 christos return;
535 1.9 christos }
536 1.1 christos
537 1.1 christos /* Do regular response type stats */
538 1.1 christos zonestats = dns_zone_getrequeststats(zone);
539 1.1 christos
540 1.9 christos if (zonestats != NULL) {
541 1.1 christos isc_stats_increment(zonestats, counter);
542 1.9 christos }
543 1.1 christos
544 1.1 christos /* Do query type statistics
545 1.1 christos *
546 1.1 christos * We only increment per-type if we're using the authoritative
547 1.1 christos * answer counter, preventing double-counting.
548 1.1 christos */
549 1.1 christos if (counter == ns_statscounter_authans) {
550 1.1 christos querystats = dns_zone_getrcvquerystats(zone);
551 1.1 christos if (querystats != NULL) {
552 1.1 christos rdataset = ISC_LIST_HEAD(client->query.qname->list);
553 1.1 christos if (rdataset != NULL) {
554 1.1 christos qtype = rdataset->type;
555 1.1 christos dns_rdatatypestats_increment(querystats, qtype);
556 1.1 christos }
557 1.1 christos }
558 1.1 christos }
559 1.1 christos }
560 1.1 christos
561 1.23 christos #define NS_CLIENT_FLAGS_FORMATSIZE sizeof("+E(255)STDCV")
562 1.23 christos
563 1.23 christos static inline void
564 1.23 christos ns_client_log_flags(ns_client_t *client, unsigned int flags,
565 1.23 christos unsigned int extflags, char *buf, size_t len) {
566 1.23 christos isc_buffer_t b;
567 1.23 christos
568 1.23 christos isc_buffer_init(&b, buf, len);
569 1.23 christos isc_buffer_putuint8(&b, WANTRECURSION(client) ? '+' : '-');
570 1.23 christos if (client->ednsversion >= 0) {
571 1.23 christos char ednsbuf[sizeof("E(255)")] = { 0 };
572 1.23 christos
573 1.23 christos snprintf(ednsbuf, sizeof(ednsbuf), "E(%hhu)",
574 1.23 christos (unsigned char)client->ednsversion);
575 1.23 christos isc_buffer_putstr(&b, ednsbuf);
576 1.23 christos }
577 1.23 christos if (client->signer != NULL) {
578 1.23 christos isc_buffer_putuint8(&b, 'S');
579 1.23 christos }
580 1.23 christos if (TCP(client)) {
581 1.23 christos isc_buffer_putuint8(&b, 'T');
582 1.23 christos }
583 1.23 christos if ((extflags & DNS_MESSAGEEXTFLAG_DO) != 0) {
584 1.23 christos isc_buffer_putuint8(&b, 'D');
585 1.23 christos }
586 1.23 christos if ((flags & DNS_MESSAGEFLAG_CD) != 0) {
587 1.23 christos isc_buffer_putuint8(&b, 'C');
588 1.23 christos }
589 1.23 christos if (HAVECOOKIE(client)) {
590 1.23 christos isc_buffer_putuint8(&b, 'V');
591 1.23 christos } else if (WANTCOOKIE(client)) {
592 1.23 christos isc_buffer_putuint8(&b, 'K');
593 1.23 christos }
594 1.23 christos isc_buffer_putuint8(&b, 0);
595 1.23 christos }
596 1.23 christos
597 1.23 christos #define NS_CLIENT_ECS_FORMATSIZE (DNS_ECS_FORMATSIZE + sizeof(" [ECS ]") - 1)
598 1.23 christos
599 1.23 christos static inline void
600 1.23 christos ns_client_log_ecs(ns_client_t *client, char *ecsbuf, size_t len) {
601 1.23 christos strlcpy(ecsbuf, " [ECS ", len);
602 1.23 christos dns_ecs_format(&client->ecs, ecsbuf + 6, len - 6);
603 1.23 christos strlcat(ecsbuf, "]", len);
604 1.23 christos }
605 1.23 christos
606 1.23 christos static inline void
607 1.23 christos log_response(ns_client_t *client, dns_rcode_t rcode) {
608 1.23 christos char namebuf[DNS_NAME_FORMATSIZE];
609 1.23 christos char typebuf[DNS_RDATATYPE_FORMATSIZE];
610 1.23 christos char classbuf[DNS_RDATACLASS_FORMATSIZE];
611 1.23 christos char rcodebuf[20];
612 1.23 christos char onbuf[ISC_NETADDR_FORMATSIZE];
613 1.23 christos char ecsbuf[NS_CLIENT_ECS_FORMATSIZE] = { 0 };
614 1.23 christos char flagsbuf[NS_CLIENT_FLAGS_FORMATSIZE] = { 0 };
615 1.23 christos isc_buffer_t b;
616 1.23 christos int level = ISC_LOG_INFO;
617 1.23 christos
618 1.23 christos if (!isc_log_wouldlog(ns_lctx, level)) {
619 1.23 christos return;
620 1.23 christos }
621 1.23 christos
622 1.23 christos dns_name_format(client->query.origqname, namebuf, sizeof(namebuf));
623 1.23 christos dns_rdataclass_format(client->message->rdclass, classbuf,
624 1.23 christos sizeof(classbuf));
625 1.23 christos dns_rdatatype_format(client->query.qtype, typebuf, sizeof(typebuf));
626 1.23 christos isc_buffer_init(&b, rcodebuf, sizeof(rcodebuf));
627 1.23 christos dns_rcode_totext(rcode, &b);
628 1.23 christos isc_buffer_putuint8(&b, 0);
629 1.23 christos isc_netaddr_format(&client->destaddr, onbuf, sizeof(onbuf));
630 1.23 christos
631 1.23 christos if (HAVEECS(client)) {
632 1.23 christos ns_client_log_ecs(client, ecsbuf, sizeof(ecsbuf));
633 1.23 christos }
634 1.23 christos
635 1.23 christos ns_client_log_flags(client, client->message->flags, client->extflags,
636 1.23 christos flagsbuf, sizeof(flagsbuf));
637 1.23 christos ns_client_log(client, NS_LOGCATEGORY_RESPONSES, NS_LOGMODULE_QUERY,
638 1.23 christos level, "response: %s %s %s %s %u %u %u %s (%s)%s",
639 1.23 christos namebuf, classbuf, typebuf, rcodebuf,
640 1.23 christos client->message->counts[DNS_SECTION_ANSWER],
641 1.23 christos client->message->counts[DNS_SECTION_AUTHORITY],
642 1.23 christos client->message->counts[DNS_SECTION_ADDITIONAL], flagsbuf,
643 1.23 christos onbuf, ecsbuf);
644 1.23 christos }
645 1.23 christos
646 1.1 christos static void
647 1.1 christos query_send(ns_client_t *client) {
648 1.1 christos isc_statscounter_t counter;
649 1.1 christos
650 1.9 christos if ((client->message->flags & DNS_MESSAGEFLAG_AA) == 0) {
651 1.1 christos inc_stats(client, ns_statscounter_nonauthans);
652 1.9 christos } else {
653 1.1 christos inc_stats(client, ns_statscounter_authans);
654 1.9 christos }
655 1.1 christos
656 1.1 christos if (client->message->rcode == dns_rcode_noerror) {
657 1.1 christos dns_section_t answer = DNS_SECTION_ANSWER;
658 1.1 christos if (ISC_LIST_EMPTY(client->message->sections[answer])) {
659 1.9 christos if (client->query.isreferral) {
660 1.1 christos counter = ns_statscounter_referral;
661 1.9 christos } else {
662 1.1 christos counter = ns_statscounter_nxrrset;
663 1.9 christos }
664 1.9 christos } else {
665 1.1 christos counter = ns_statscounter_success;
666 1.9 christos }
667 1.9 christos } else if (client->message->rcode == dns_rcode_nxdomain) {
668 1.1 christos counter = ns_statscounter_nxdomain;
669 1.9 christos } else if (client->message->rcode == dns_rcode_badcookie) {
670 1.1 christos counter = ns_statscounter_badcookie;
671 1.9 christos } else { /* We end up here in case of YXDOMAIN, and maybe others */
672 1.1 christos counter = ns_statscounter_failure;
673 1.9 christos }
674 1.1 christos
675 1.1 christos inc_stats(client, counter);
676 1.1 christos ns_client_send(client);
677 1.11 christos
678 1.23 christos if ((client->manager->sctx->options & NS_SERVER_LOGRESPONSES) != 0) {
679 1.23 christos log_response(client, client->message->rcode);
680 1.11 christos }
681 1.23 christos
682 1.23 christos isc_nmhandle_detach(&client->reqhandle);
683 1.1 christos }
684 1.1 christos
685 1.1 christos static void
686 1.1 christos query_error(ns_client_t *client, isc_result_t result, int line) {
687 1.1 christos int loglevel = ISC_LOG_DEBUG(3);
688 1.23 christos dns_rcode_t rcode;
689 1.1 christos
690 1.23 christos rcode = dns_result_torcode(result);
691 1.23 christos switch (rcode) {
692 1.3 christos case dns_rcode_servfail:
693 1.1 christos loglevel = ISC_LOG_DEBUG(1);
694 1.1 christos inc_stats(client, ns_statscounter_servfail);
695 1.1 christos break;
696 1.3 christos case dns_rcode_formerr:
697 1.1 christos inc_stats(client, ns_statscounter_formerr);
698 1.1 christos break;
699 1.1 christos default:
700 1.1 christos inc_stats(client, ns_statscounter_failure);
701 1.1 christos break;
702 1.1 christos }
703 1.1 christos
704 1.23 christos if ((client->manager->sctx->options & NS_SERVER_LOGQUERIES) != 0) {
705 1.1 christos loglevel = ISC_LOG_INFO;
706 1.9 christos }
707 1.1 christos
708 1.1 christos log_queryerror(client, result, line, loglevel);
709 1.1 christos
710 1.1 christos ns_client_error(client, result);
711 1.11 christos
712 1.23 christos if (client->query.origqname != NULL &&
713 1.23 christos (client->manager->sctx->options & NS_SERVER_LOGRESPONSES) != 0)
714 1.23 christos {
715 1.23 christos log_response(client, rcode);
716 1.11 christos }
717 1.23 christos
718 1.23 christos isc_nmhandle_detach(&client->reqhandle);
719 1.1 christos }
720 1.1 christos
721 1.1 christos static void
722 1.1 christos query_next(ns_client_t *client, isc_result_t result) {
723 1.9 christos if (result == DNS_R_DUPLICATE) {
724 1.1 christos inc_stats(client, ns_statscounter_duplicate);
725 1.9 christos } else if (result == DNS_R_DROP) {
726 1.1 christos inc_stats(client, ns_statscounter_dropped);
727 1.9 christos } else {
728 1.1 christos inc_stats(client, ns_statscounter_failure);
729 1.9 christos }
730 1.9 christos ns_client_drop(client, result);
731 1.23 christos isc_nmhandle_detach(&client->reqhandle);
732 1.1 christos }
733 1.1 christos
734 1.15 christos static void
735 1.3 christos query_freefreeversions(ns_client_t *client, bool everything) {
736 1.1 christos ns_dbversion_t *dbversion, *dbversion_next;
737 1.1 christos unsigned int i;
738 1.1 christos
739 1.1 christos for (dbversion = ISC_LIST_HEAD(client->query.freeversions), i = 0;
740 1.9 christos dbversion != NULL; dbversion = dbversion_next, i++)
741 1.1 christos {
742 1.1 christos dbversion_next = ISC_LIST_NEXT(dbversion, link);
743 1.1 christos /*
744 1.1 christos * If we're not freeing everything, we keep the first three
745 1.1 christos * dbversions structures around.
746 1.1 christos */
747 1.1 christos if (i > 3 || everything) {
748 1.1 christos ISC_LIST_UNLINK(client->query.freeversions, dbversion,
749 1.1 christos link);
750 1.23 christos isc_mem_put(client->manager->mctx, dbversion,
751 1.1 christos sizeof(*dbversion));
752 1.1 christos }
753 1.1 christos }
754 1.1 christos }
755 1.1 christos
756 1.1 christos void
757 1.1 christos ns_query_cancel(ns_client_t *client) {
758 1.1 christos REQUIRE(NS_CLIENT_VALID(client));
759 1.1 christos
760 1.1 christos LOCK(&client->query.fetchlock);
761 1.23 christos for (int i = 0; i < RECTYPE_COUNT; i++) {
762 1.23 christos dns_fetch_t **fetchp = &client->query.recursions[i].fetch;
763 1.23 christos if (*fetchp != NULL) {
764 1.23 christos dns_resolver_cancelfetch(*fetchp);
765 1.23 christos *fetchp = NULL;
766 1.23 christos }
767 1.1 christos }
768 1.20 christos if (client->query.hookactx != NULL) {
769 1.20 christos client->query.hookactx->cancel(client->query.hookactx);
770 1.20 christos client->query.hookactx = NULL;
771 1.20 christos }
772 1.1 christos UNLOCK(&client->query.fetchlock);
773 1.1 christos }
774 1.1 christos
775 1.15 christos static void
776 1.3 christos query_reset(ns_client_t *client, bool everything) {
777 1.1 christos isc_buffer_t *dbuf, *dbuf_next;
778 1.1 christos ns_dbversion_t *dbversion, *dbversion_next;
779 1.1 christos
780 1.1 christos CTRACE(ISC_LOG_DEBUG(3), "query_reset");
781 1.1 christos
782 1.1 christos /*%
783 1.1 christos * Reset the query state of a client to its default state.
784 1.1 christos */
785 1.1 christos
786 1.1 christos /*
787 1.1 christos * Cancel the fetch if it's running.
788 1.1 christos */
789 1.1 christos ns_query_cancel(client);
790 1.1 christos
791 1.1 christos /*
792 1.1 christos * Cleanup any active versions.
793 1.1 christos */
794 1.1 christos for (dbversion = ISC_LIST_HEAD(client->query.activeversions);
795 1.9 christos dbversion != NULL; dbversion = dbversion_next)
796 1.9 christos {
797 1.1 christos dbversion_next = ISC_LIST_NEXT(dbversion, link);
798 1.9 christos dns_db_closeversion(dbversion->db, &dbversion->version, false);
799 1.1 christos dns_db_detach(&dbversion->db);
800 1.9 christos ISC_LIST_INITANDAPPEND(client->query.freeversions, dbversion,
801 1.9 christos link);
802 1.1 christos }
803 1.1 christos ISC_LIST_INIT(client->query.activeversions);
804 1.1 christos
805 1.9 christos if (client->query.authdb != NULL) {
806 1.1 christos dns_db_detach(&client->query.authdb);
807 1.9 christos }
808 1.9 christos if (client->query.authzone != NULL) {
809 1.1 christos dns_zone_detach(&client->query.authzone);
810 1.9 christos }
811 1.1 christos
812 1.9 christos if (client->query.dns64_aaaa != NULL) {
813 1.3 christos ns_client_putrdataset(client, &client->query.dns64_aaaa);
814 1.9 christos }
815 1.9 christos if (client->query.dns64_sigaaaa != NULL) {
816 1.3 christos ns_client_putrdataset(client, &client->query.dns64_sigaaaa);
817 1.9 christos }
818 1.1 christos if (client->query.dns64_aaaaok != NULL) {
819 1.23 christos isc_mem_cput(client->manager->mctx, client->query.dns64_aaaaok,
820 1.23 christos client->query.dns64_aaaaoklen, sizeof(bool));
821 1.9 christos client->query.dns64_aaaaok = NULL;
822 1.9 christos client->query.dns64_aaaaoklen = 0;
823 1.1 christos }
824 1.1 christos
825 1.3 christos ns_client_putrdataset(client, &client->query.redirect.rdataset);
826 1.3 christos ns_client_putrdataset(client, &client->query.redirect.sigrdataset);
827 1.1 christos if (client->query.redirect.db != NULL) {
828 1.9 christos if (client->query.redirect.node != NULL) {
829 1.1 christos dns_db_detachnode(client->query.redirect.db,
830 1.1 christos &client->query.redirect.node);
831 1.9 christos }
832 1.1 christos dns_db_detach(&client->query.redirect.db);
833 1.1 christos }
834 1.9 christos if (client->query.redirect.zone != NULL) {
835 1.1 christos dns_zone_detach(&client->query.redirect.zone);
836 1.9 christos }
837 1.1 christos
838 1.1 christos query_freefreeversions(client, everything);
839 1.1 christos
840 1.9 christos for (dbuf = ISC_LIST_HEAD(client->query.namebufs); dbuf != NULL;
841 1.9 christos dbuf = dbuf_next)
842 1.9 christos {
843 1.1 christos dbuf_next = ISC_LIST_NEXT(dbuf, link);
844 1.1 christos if (dbuf_next != NULL || everything) {
845 1.1 christos ISC_LIST_UNLINK(client->query.namebufs, dbuf, link);
846 1.1 christos isc_buffer_free(&dbuf);
847 1.1 christos }
848 1.1 christos }
849 1.1 christos
850 1.1 christos if (client->query.restarts > 0) {
851 1.1 christos /*
852 1.1 christos * client->query.qname was dynamically allocated.
853 1.1 christos */
854 1.9 christos dns_message_puttempname(client->message, &client->query.qname);
855 1.1 christos }
856 1.1 christos client->query.qname = NULL;
857 1.1 christos client->query.attributes = (NS_QUERYATTR_RECURSIONOK |
858 1.9 christos NS_QUERYATTR_CACHEOK | NS_QUERYATTR_SECURE);
859 1.1 christos client->query.restarts = 0;
860 1.3 christos client->query.timerset = false;
861 1.1 christos if (client->query.rpz_st != NULL) {
862 1.1 christos rpz_st_clear(client);
863 1.1 christos if (everything) {
864 1.1 christos INSIST(client->query.rpz_st->rpsdb == NULL);
865 1.23 christos isc_mem_put(client->manager->mctx, client->query.rpz_st,
866 1.1 christos sizeof(*client->query.rpz_st));
867 1.1 christos client->query.rpz_st = NULL;
868 1.1 christos }
869 1.1 christos }
870 1.24 christos if (client->query.qc != NULL) {
871 1.24 christos isc_counter_detach(&client->query.qc);
872 1.24 christos }
873 1.1 christos client->query.origqname = NULL;
874 1.1 christos client->query.dboptions = 0;
875 1.1 christos client->query.fetchoptions = 0;
876 1.1 christos client->query.gluedb = NULL;
877 1.3 christos client->query.authdbset = false;
878 1.3 christos client->query.isreferral = false;
879 1.1 christos client->query.dns64_options = 0;
880 1.3 christos client->query.dns64_ttl = UINT32_MAX;
881 1.3 christos recparam_update(&client->query.recparam, 0, NULL, NULL);
882 1.1 christos client->query.root_key_sentinel_keyid = 0;
883 1.3 christos client->query.root_key_sentinel_is_ta = false;
884 1.3 christos client->query.root_key_sentinel_not_ta = false;
885 1.1 christos }
886 1.1 christos
887 1.1 christos static void
888 1.9 christos query_cleanup(ns_client_t *client) {
889 1.3 christos query_reset(client, false);
890 1.1 christos }
891 1.1 christos
892 1.1 christos void
893 1.1 christos ns_query_free(ns_client_t *client) {
894 1.1 christos REQUIRE(NS_CLIENT_VALID(client));
895 1.1 christos
896 1.3 christos query_reset(client, true);
897 1.1 christos }
898 1.1 christos
899 1.23 christos void
900 1.1 christos ns_query_init(ns_client_t *client) {
901 1.23 christos REQUIRE(NS_CLIENT_VALID(client));
902 1.1 christos
903 1.23 christos client->query = (ns_query_t){ 0 };
904 1.1 christos
905 1.1 christos ISC_LIST_INIT(client->query.namebufs);
906 1.1 christos ISC_LIST_INIT(client->query.activeversions);
907 1.1 christos ISC_LIST_INIT(client->query.freeversions);
908 1.24 christos
909 1.1 christos /*
910 1.1 christos * This mutex is destroyed when the client is destroyed in
911 1.1 christos * exit_check().
912 1.1 christos */
913 1.3 christos isc_mutex_init(&client->query.fetchlock);
914 1.1 christos client->query.redirect.fname =
915 1.1 christos dns_fixedname_initname(&client->query.redirect.fixed);
916 1.3 christos query_reset(client, false);
917 1.14 christos ns_client_newdbversion(client, 3);
918 1.14 christos ns_client_newnamebuf(client);
919 1.1 christos }
920 1.1 christos
921 1.3 christos /*%
922 1.3 christos * Check if 'client' is allowed to query the cache of its associated view.
923 1.23 christos * Unless 'options' has the 'nolog' flag set, log the result of cache ACL
924 1.3 christos * evaluation using the appropriate level, along with 'name' and 'qtype'.
925 1.3 christos *
926 1.3 christos * The cache ACL is only evaluated once for each client and then the result is
927 1.3 christos * cached: if NS_QUERYATTR_CACHEACLOKVALID is set in client->query.attributes,
928 1.3 christos * cache ACL evaluation has already been performed. The evaluation result is
929 1.3 christos * also stored in client->query.attributes: if NS_QUERYATTR_CACHEACLOK is set,
930 1.3 christos * the client is allowed cache access.
931 1.3 christos *
932 1.3 christos * Returns:
933 1.3 christos *
934 1.3 christos *\li #ISC_R_SUCCESS 'client' is allowed to access cache
935 1.3 christos *\li #DNS_R_REFUSED 'client' is not allowed to access cache
936 1.3 christos */
937 1.3 christos static isc_result_t
938 1.3 christos query_checkcacheaccess(ns_client_t *client, const dns_name_t *name,
939 1.23 christos dns_rdatatype_t qtype, dns_getdb_options_t options) {
940 1.3 christos isc_result_t result;
941 1.3 christos
942 1.3 christos if ((client->query.attributes & NS_QUERYATTR_CACHEACLOKVALID) == 0) {
943 1.20 christos enum refusal_reasons {
944 1.20 christos ALLOW_QUERY_CACHE,
945 1.20 christos ALLOW_QUERY_CACHE_ON
946 1.20 christos };
947 1.20 christos static const char *acl_desc[] = {
948 1.20 christos "allow-query-cache did not match",
949 1.20 christos "allow-query-cache-on did not match",
950 1.20 christos };
951 1.20 christos
952 1.3 christos /*
953 1.3 christos * The view's cache ACLs have not yet been evaluated.
954 1.3 christos * Do it now. Both allow-query-cache and
955 1.20 christos * allow-query-cache-on must be satisfied.
956 1.3 christos */
957 1.3 christos char msg[NS_CLIENT_ACLMSGSIZE("query (cache)")];
958 1.1 christos
959 1.20 christos enum refusal_reasons refusal_reason = ALLOW_QUERY_CACHE;
960 1.3 christos result = ns_client_checkaclsilent(client, NULL,
961 1.9 christos client->view->cacheacl, true);
962 1.3 christos if (result == ISC_R_SUCCESS) {
963 1.20 christos refusal_reason = ALLOW_QUERY_CACHE_ON;
964 1.9 christos result = ns_client_checkaclsilent(
965 1.9 christos client, &client->destaddr,
966 1.9 christos client->view->cacheonacl, true);
967 1.9 christos }
968 1.3 christos if (result == ISC_R_SUCCESS) {
969 1.3 christos /*
970 1.3 christos * We were allowed by the "allow-query-cache" ACL.
971 1.3 christos */
972 1.3 christos client->query.attributes |= NS_QUERYATTR_CACHEACLOK;
973 1.23 christos if (!options.nolog &&
974 1.23 christos isc_log_wouldlog(ns_lctx, ISC_LOG_DEBUG(3)))
975 1.3 christos {
976 1.3 christos ns_client_aclmsg("query (cache)", name, qtype,
977 1.3 christos client->view->rdclass, msg,
978 1.3 christos sizeof(msg));
979 1.3 christos ns_client_log(client, DNS_LOGCATEGORY_SECURITY,
980 1.3 christos NS_LOGMODULE_QUERY,
981 1.3 christos ISC_LOG_DEBUG(3), "%s approved",
982 1.3 christos msg);
983 1.3 christos }
984 1.20 christos } else {
985 1.3 christos /*
986 1.3 christos * We were denied by the "allow-query-cache" ACL.
987 1.3 christos * There is no need to clear NS_QUERYATTR_CACHEACLOK
988 1.3 christos * since it is cleared by query_reset(), before query
989 1.3 christos * processing starts.
990 1.3 christos */
991 1.24 christos dns_ede_add(&client->edectx, DNS_EDE_PROHIBITED, NULL);
992 1.20 christos
993 1.23 christos if (!options.nolog) {
994 1.20 christos ns_client_aclmsg("query (cache)", name, qtype,
995 1.20 christos client->view->rdclass, msg,
996 1.20 christos sizeof(msg));
997 1.20 christos ns_client_log(client, DNS_LOGCATEGORY_SECURITY,
998 1.20 christos NS_LOGMODULE_QUERY, ISC_LOG_INFO,
999 1.20 christos "%s denied (%s)", msg,
1000 1.20 christos acl_desc[refusal_reason]);
1001 1.20 christos }
1002 1.3 christos }
1003 1.1 christos
1004 1.1 christos /*
1005 1.3 christos * Evaluation has been finished; make sure we will just consult
1006 1.3 christos * NS_QUERYATTR_CACHEACLOK for this client from now on.
1007 1.1 christos */
1008 1.3 christos client->query.attributes |= NS_QUERYATTR_CACHEACLOKVALID;
1009 1.1 christos }
1010 1.1 christos
1011 1.23 christos return (client->query.attributes & NS_QUERYATTR_CACHEACLOK) != 0
1012 1.23 christos ? ISC_R_SUCCESS
1013 1.23 christos : DNS_R_REFUSED;
1014 1.1 christos }
1015 1.1 christos
1016 1.15 christos static isc_result_t
1017 1.1 christos query_validatezonedb(ns_client_t *client, const dns_name_t *name,
1018 1.23 christos dns_rdatatype_t qtype, dns_getdb_options_t options,
1019 1.1 christos dns_zone_t *zone, dns_db_t *db,
1020 1.9 christos dns_dbversion_t **versionp) {
1021 1.1 christos isc_result_t result;
1022 1.1 christos dns_acl_t *queryacl, *queryonacl;
1023 1.1 christos ns_dbversion_t *dbversion;
1024 1.1 christos
1025 1.1 christos REQUIRE(zone != NULL);
1026 1.1 christos REQUIRE(db != NULL);
1027 1.1 christos
1028 1.1 christos /*
1029 1.3 christos * Mirror zone data is treated as cache data.
1030 1.3 christos */
1031 1.3 christos if (dns_zone_gettype(zone) == dns_zone_mirror) {
1032 1.23 christos return query_checkcacheaccess(client, name, qtype, options);
1033 1.3 christos }
1034 1.3 christos
1035 1.3 christos /*
1036 1.1 christos * This limits our searching to the zone where the first name
1037 1.1 christos * (the query target) was looked for. This prevents following
1038 1.1 christos * CNAMES or DNAMES into other zones and prevents returning
1039 1.1 christos * additional data from other zones. This does not apply if we're
1040 1.1 christos * answering a query where recursion is requested and allowed.
1041 1.1 christos */
1042 1.1 christos if (client->query.rpz_st == NULL &&
1043 1.1 christos !(WANTRECURSION(client) && RECURSIONOK(client)) &&
1044 1.1 christos client->query.authdbset && db != client->query.authdb)
1045 1.1 christos {
1046 1.23 christos return DNS_R_REFUSED;
1047 1.1 christos }
1048 1.1 christos
1049 1.1 christos /*
1050 1.1 christos * Non recursive query to a static-stub zone is prohibited; its
1051 1.1 christos * zone content is not public data, but a part of local configuration
1052 1.1 christos * and should not be disclosed.
1053 1.1 christos */
1054 1.1 christos if (dns_zone_gettype(zone) == dns_zone_staticstub &&
1055 1.16 christos !RECURSIONOK(client))
1056 1.16 christos {
1057 1.23 christos return DNS_R_REFUSED;
1058 1.1 christos }
1059 1.1 christos
1060 1.1 christos /*
1061 1.1 christos * If the zone has an ACL, we'll check it, otherwise
1062 1.1 christos * we use the view's "allow-query" ACL. Each ACL is only checked
1063 1.1 christos * once per query.
1064 1.1 christos *
1065 1.1 christos * Also, get the database version to use.
1066 1.1 christos */
1067 1.1 christos
1068 1.1 christos /*
1069 1.1 christos * Get the current version of this database.
1070 1.1 christos */
1071 1.3 christos dbversion = ns_client_findversion(client, db);
1072 1.1 christos if (dbversion == NULL) {
1073 1.1 christos CTRACE(ISC_LOG_ERROR, "unable to get db version");
1074 1.23 christos return DNS_R_SERVFAIL;
1075 1.1 christos }
1076 1.1 christos
1077 1.23 christos if (options.ignoreacl) {
1078 1.1 christos goto approved;
1079 1.9 christos }
1080 1.1 christos if (dbversion->acl_checked) {
1081 1.9 christos if (!dbversion->queryok) {
1082 1.23 christos return DNS_R_REFUSED;
1083 1.9 christos }
1084 1.1 christos goto approved;
1085 1.1 christos }
1086 1.1 christos
1087 1.1 christos queryacl = dns_zone_getqueryacl(zone);
1088 1.1 christos if (queryacl == NULL) {
1089 1.1 christos queryacl = client->view->queryacl;
1090 1.9 christos if ((client->query.attributes & NS_QUERYATTR_QUERYOKVALID) != 0)
1091 1.9 christos {
1092 1.1 christos /*
1093 1.1 christos * We've evaluated the view's queryacl already. If
1094 1.1 christos * NS_QUERYATTR_QUERYOK is set, then the client is
1095 1.1 christos * allowed to make queries, otherwise the query should
1096 1.1 christos * be refused.
1097 1.1 christos */
1098 1.3 christos dbversion->acl_checked = true;
1099 1.9 christos if ((client->query.attributes & NS_QUERYATTR_QUERYOK) ==
1100 1.16 christos 0)
1101 1.16 christos {
1102 1.3 christos dbversion->queryok = false;
1103 1.23 christos return DNS_R_REFUSED;
1104 1.1 christos }
1105 1.3 christos dbversion->queryok = true;
1106 1.1 christos goto approved;
1107 1.1 christos }
1108 1.1 christos }
1109 1.1 christos
1110 1.3 christos result = ns_client_checkaclsilent(client, NULL, queryacl, true);
1111 1.23 christos if (!options.nolog) {
1112 1.1 christos char msg[NS_CLIENT_ACLMSGSIZE("query")];
1113 1.1 christos if (result == ISC_R_SUCCESS) {
1114 1.1 christos if (isc_log_wouldlog(ns_lctx, ISC_LOG_DEBUG(3))) {
1115 1.1 christos ns_client_aclmsg("query", name, qtype,
1116 1.9 christos client->view->rdclass, msg,
1117 1.9 christos sizeof(msg));
1118 1.9 christos ns_client_log(client, DNS_LOGCATEGORY_SECURITY,
1119 1.1 christos NS_LOGMODULE_QUERY,
1120 1.9 christos ISC_LOG_DEBUG(3), "%s approved",
1121 1.9 christos msg);
1122 1.1 christos }
1123 1.1 christos } else {
1124 1.1 christos ns_client_aclmsg("query", name, qtype,
1125 1.9 christos client->view->rdclass, msg,
1126 1.9 christos sizeof(msg));
1127 1.1 christos ns_client_log(client, DNS_LOGCATEGORY_SECURITY,
1128 1.1 christos NS_LOGMODULE_QUERY, ISC_LOG_INFO,
1129 1.1 christos "%s denied", msg);
1130 1.24 christos dns_ede_add(&client->edectx, DNS_EDE_PROHIBITED, NULL);
1131 1.1 christos }
1132 1.1 christos }
1133 1.1 christos
1134 1.1 christos if (queryacl == client->view->queryacl) {
1135 1.1 christos if (result == ISC_R_SUCCESS) {
1136 1.1 christos /*
1137 1.1 christos * We were allowed by the default
1138 1.1 christos * "allow-query" ACL. Remember this so we
1139 1.1 christos * don't have to check again.
1140 1.1 christos */
1141 1.1 christos client->query.attributes |= NS_QUERYATTR_QUERYOK;
1142 1.1 christos }
1143 1.1 christos /*
1144 1.1 christos * We've now evaluated the view's query ACL, and
1145 1.1 christos * the NS_QUERYATTR_QUERYOK attribute is now valid.
1146 1.1 christos */
1147 1.1 christos client->query.attributes |= NS_QUERYATTR_QUERYOKVALID;
1148 1.1 christos }
1149 1.1 christos
1150 1.1 christos /* If and only if we've gotten this far, check allow-query-on too */
1151 1.1 christos if (result == ISC_R_SUCCESS) {
1152 1.1 christos queryonacl = dns_zone_getqueryonacl(zone);
1153 1.9 christos if (queryonacl == NULL) {
1154 1.1 christos queryonacl = client->view->queryonacl;
1155 1.9 christos }
1156 1.1 christos
1157 1.1 christos result = ns_client_checkaclsilent(client, &client->destaddr,
1158 1.3 christos queryonacl, true);
1159 1.20 christos if (result != ISC_R_SUCCESS) {
1160 1.24 christos dns_ede_add(&client->edectx, DNS_EDE_PROHIBITED, NULL);
1161 1.20 christos }
1162 1.23 christos if (!options.nolog && result != ISC_R_SUCCESS) {
1163 1.1 christos ns_client_log(client, DNS_LOGCATEGORY_SECURITY,
1164 1.1 christos NS_LOGMODULE_QUERY, ISC_LOG_INFO,
1165 1.1 christos "query-on denied");
1166 1.9 christos }
1167 1.1 christos }
1168 1.1 christos
1169 1.3 christos dbversion->acl_checked = true;
1170 1.1 christos if (result != ISC_R_SUCCESS) {
1171 1.3 christos dbversion->queryok = false;
1172 1.23 christos return DNS_R_REFUSED;
1173 1.1 christos }
1174 1.3 christos dbversion->queryok = true;
1175 1.1 christos
1176 1.9 christos approved:
1177 1.1 christos /* Transfer ownership, if necessary. */
1178 1.23 christos SET_IF_NOT_NULL(versionp, dbversion->version);
1179 1.23 christos return ISC_R_SUCCESS;
1180 1.1 christos }
1181 1.1 christos
1182 1.15 christos static isc_result_t
1183 1.1 christos query_getzonedb(ns_client_t *client, const dns_name_t *name,
1184 1.23 christos dns_rdatatype_t qtype, dns_getdb_options_t options,
1185 1.23 christos dns_zone_t **zonep, dns_db_t **dbp,
1186 1.23 christos dns_dbversion_t **versionp) {
1187 1.1 christos isc_result_t result;
1188 1.1 christos unsigned int ztoptions;
1189 1.1 christos dns_zone_t *zone = NULL;
1190 1.1 christos dns_db_t *db = NULL;
1191 1.3 christos bool partial = false;
1192 1.1 christos
1193 1.1 christos REQUIRE(zonep != NULL && *zonep == NULL);
1194 1.1 christos REQUIRE(dbp != NULL && *dbp == NULL);
1195 1.1 christos
1196 1.1 christos /*%
1197 1.1 christos * Find a zone database to answer the query.
1198 1.1 christos */
1199 1.3 christos ztoptions = DNS_ZTFIND_MIRROR;
1200 1.23 christos if (options.noexact) {
1201 1.3 christos ztoptions |= DNS_ZTFIND_NOEXACT;
1202 1.3 christos }
1203 1.1 christos
1204 1.23 christos result = dns_view_findzone(client->view, name, ztoptions, &zone);
1205 1.1 christos
1206 1.9 christos if (result == DNS_R_PARTIALMATCH) {
1207 1.3 christos partial = true;
1208 1.9 christos }
1209 1.9 christos if (result == ISC_R_SUCCESS || result == DNS_R_PARTIALMATCH) {
1210 1.1 christos result = dns_zone_getdb(zone, &db);
1211 1.9 christos }
1212 1.1 christos
1213 1.9 christos if (result != ISC_R_SUCCESS) {
1214 1.1 christos goto fail;
1215 1.9 christos }
1216 1.1 christos
1217 1.1 christos result = query_validatezonedb(client, name, qtype, options, zone, db,
1218 1.1 christos versionp);
1219 1.1 christos
1220 1.9 christos if (result != ISC_R_SUCCESS) {
1221 1.1 christos goto fail;
1222 1.9 christos }
1223 1.1 christos
1224 1.1 christos /* Transfer ownership. */
1225 1.1 christos *zonep = zone;
1226 1.1 christos *dbp = db;
1227 1.1 christos
1228 1.23 christos if (partial && options.partial) {
1229 1.23 christos return DNS_R_PARTIALMATCH;
1230 1.9 christos }
1231 1.23 christos return ISC_R_SUCCESS;
1232 1.1 christos
1233 1.9 christos fail:
1234 1.9 christos if (zone != NULL) {
1235 1.1 christos dns_zone_detach(&zone);
1236 1.9 christos }
1237 1.9 christos if (db != NULL) {
1238 1.1 christos dns_db_detach(&db);
1239 1.9 christos }
1240 1.1 christos
1241 1.23 christos return result;
1242 1.1 christos }
1243 1.1 christos
1244 1.1 christos static void
1245 1.9 christos rpz_log_rewrite(ns_client_t *client, bool disabled, dns_rpz_policy_t policy,
1246 1.9 christos dns_rpz_type_t type, dns_zone_t *p_zone, dns_name_t *p_name,
1247 1.9 christos dns_name_t *cname, dns_rpz_num_t rpz_num) {
1248 1.3 christos char cname_buf[DNS_NAME_FORMATSIZE] = { 0 };
1249 1.3 christos char p_name_buf[DNS_NAME_FORMATSIZE];
1250 1.1 christos char qname_buf[DNS_NAME_FORMATSIZE];
1251 1.3 christos char classbuf[DNS_RDATACLASS_FORMATSIZE];
1252 1.3 christos char typebuf[DNS_RDATATYPE_FORMATSIZE];
1253 1.1 christos const char *s1 = cname_buf, *s2 = cname_buf;
1254 1.3 christos dns_rdataset_t *rdataset;
1255 1.1 christos dns_rpz_st_t *st;
1256 1.3 christos isc_stats_t *zonestats;
1257 1.1 christos
1258 1.1 christos /*
1259 1.1 christos * Count enabled rewrites in the global counter.
1260 1.1 christos * Count both enabled and disabled rewrites for each zone.
1261 1.1 christos */
1262 1.1 christos if (!disabled && policy != DNS_RPZ_POLICY_PASSTHRU) {
1263 1.23 christos ns_stats_increment(client->manager->sctx->nsstats,
1264 1.1 christos ns_statscounter_rpz_rewrites);
1265 1.1 christos }
1266 1.1 christos if (p_zone != NULL) {
1267 1.1 christos zonestats = dns_zone_getrequeststats(p_zone);
1268 1.9 christos if (zonestats != NULL) {
1269 1.1 christos isc_stats_increment(zonestats,
1270 1.1 christos ns_statscounter_rpz_rewrites);
1271 1.9 christos }
1272 1.1 christos }
1273 1.1 christos
1274 1.9 christos if (!isc_log_wouldlog(ns_lctx, DNS_RPZ_INFO_LEVEL)) {
1275 1.1 christos return;
1276 1.9 christos }
1277 1.1 christos
1278 1.1 christos st = client->query.rpz_st;
1279 1.9 christos if ((st->popt.no_log & DNS_RPZ_ZBIT(rpz_num)) != 0) {
1280 1.1 christos return;
1281 1.9 christos }
1282 1.1 christos
1283 1.1 christos dns_name_format(client->query.qname, qname_buf, sizeof(qname_buf));
1284 1.1 christos dns_name_format(p_name, p_name_buf, sizeof(p_name_buf));
1285 1.1 christos if (cname != NULL) {
1286 1.1 christos s1 = " (CNAME to: ";
1287 1.1 christos dns_name_format(cname, cname_buf, sizeof(cname_buf));
1288 1.1 christos s2 = ")";
1289 1.1 christos }
1290 1.1 christos
1291 1.3 christos /*
1292 1.3 christos * Log Qclass and Qtype in addition to existing
1293 1.3 christos * fields.
1294 1.3 christos */
1295 1.3 christos rdataset = ISC_LIST_HEAD(client->query.origqname->list);
1296 1.3 christos INSIST(rdataset != NULL);
1297 1.3 christos dns_rdataclass_format(rdataset->rdclass, classbuf, sizeof(classbuf));
1298 1.3 christos dns_rdatatype_format(rdataset->type, typebuf, sizeof(typebuf));
1299 1.3 christos
1300 1.20 christos /* It's possible to have a separate log channel for rpz passthru. */
1301 1.20 christos isc_logcategory_t *log_cat = (policy == DNS_RPZ_POLICY_PASSTHRU)
1302 1.20 christos ? DNS_LOGCATEGORY_RPZ_PASSTHRU
1303 1.20 christos : DNS_LOGCATEGORY_RPZ;
1304 1.20 christos
1305 1.20 christos ns_client_log(client, log_cat, NS_LOGMODULE_QUERY, DNS_RPZ_INFO_LEVEL,
1306 1.3 christos "%srpz %s %s rewrite %s/%s/%s via %s%s%s%s",
1307 1.9 christos disabled ? "disabled " : "", dns_rpz_type2str(type),
1308 1.9 christos dns_rpz_policy2str(policy), qname_buf, typebuf, classbuf,
1309 1.3 christos p_name_buf, s1, cname_buf, s2);
1310 1.1 christos }
1311 1.1 christos
1312 1.1 christos static void
1313 1.1 christos rpz_log_fail_helper(ns_client_t *client, int level, dns_name_t *p_name,
1314 1.1 christos dns_rpz_type_t rpz_type1, dns_rpz_type_t rpz_type2,
1315 1.9 christos const char *str, isc_result_t result) {
1316 1.1 christos char qnamebuf[DNS_NAME_FORMATSIZE];
1317 1.1 christos char p_namebuf[DNS_NAME_FORMATSIZE];
1318 1.1 christos const char *failed, *via, *slash, *str_blank;
1319 1.1 christos const char *rpztypestr1;
1320 1.1 christos const char *rpztypestr2;
1321 1.1 christos
1322 1.9 christos if (!isc_log_wouldlog(ns_lctx, level)) {
1323 1.1 christos return;
1324 1.9 christos }
1325 1.1 christos
1326 1.1 christos /*
1327 1.1 christos * bin/tests/system/rpz/tests.sh looks for "rpz.*failed" for problems.
1328 1.1 christos */
1329 1.9 christos if (level <= DNS_RPZ_DEBUG_LEVEL1) {
1330 1.3 christos failed = " failed: ";
1331 1.9 christos } else {
1332 1.1 christos failed = ": ";
1333 1.9 christos }
1334 1.1 christos
1335 1.1 christos rpztypestr1 = dns_rpz_type2str(rpz_type1);
1336 1.1 christos if (rpz_type2 != DNS_RPZ_TYPE_BAD) {
1337 1.1 christos slash = "/";
1338 1.1 christos rpztypestr2 = dns_rpz_type2str(rpz_type2);
1339 1.1 christos } else {
1340 1.1 christos slash = "";
1341 1.1 christos rpztypestr2 = "";
1342 1.1 christos }
1343 1.1 christos
1344 1.1 christos str_blank = (*str != ' ' && *str != '\0') ? " " : "";
1345 1.1 christos
1346 1.1 christos dns_name_format(client->query.qname, qnamebuf, sizeof(qnamebuf));
1347 1.1 christos
1348 1.1 christos if (p_name != NULL) {
1349 1.1 christos via = " via ";
1350 1.1 christos dns_name_format(p_name, p_namebuf, sizeof(p_namebuf));
1351 1.1 christos } else {
1352 1.1 christos via = "";
1353 1.1 christos p_namebuf[0] = '\0';
1354 1.1 christos }
1355 1.1 christos
1356 1.9 christos ns_client_log(client, NS_LOGCATEGORY_QUERY_ERRORS, NS_LOGMODULE_QUERY,
1357 1.9 christos level, "rpz %s%s%s rewrite %s%s%s%s%s%s%s", rpztypestr1,
1358 1.9 christos slash, rpztypestr2, qnamebuf, via, p_namebuf, str_blank,
1359 1.1 christos str, failed, isc_result_totext(result));
1360 1.1 christos }
1361 1.1 christos
1362 1.1 christos static void
1363 1.1 christos rpz_log_fail(ns_client_t *client, int level, dns_name_t *p_name,
1364 1.9 christos dns_rpz_type_t rpz_type, const char *str, isc_result_t result) {
1365 1.9 christos rpz_log_fail_helper(client, level, p_name, rpz_type, DNS_RPZ_TYPE_BAD,
1366 1.9 christos str, result);
1367 1.1 christos }
1368 1.1 christos
1369 1.1 christos /*
1370 1.1 christos * Get a policy rewrite zone database.
1371 1.1 christos */
1372 1.1 christos static isc_result_t
1373 1.1 christos rpz_getdb(ns_client_t *client, dns_name_t *p_name, dns_rpz_type_t rpz_type,
1374 1.9 christos dns_zone_t **zonep, dns_db_t **dbp, dns_dbversion_t **versionp) {
1375 1.1 christos char qnamebuf[DNS_NAME_FORMATSIZE];
1376 1.1 christos char p_namebuf[DNS_NAME_FORMATSIZE];
1377 1.1 christos dns_dbversion_t *rpz_version = NULL;
1378 1.1 christos isc_result_t result;
1379 1.1 christos
1380 1.1 christos CTRACE(ISC_LOG_DEBUG(3), "rpz_getdb");
1381 1.1 christos
1382 1.23 christos dns_getdb_options_t options = { .ignoreacl = true };
1383 1.23 christos result = query_getzonedb(client, p_name, dns_rdatatype_any, options,
1384 1.23 christos zonep, dbp, &rpz_version);
1385 1.1 christos if (result == ISC_R_SUCCESS) {
1386 1.1 christos dns_rpz_st_t *st = client->query.rpz_st;
1387 1.1 christos
1388 1.1 christos /*
1389 1.1 christos * It isn't meaningful to log this message when
1390 1.1 christos * logging is disabled for some policy zones.
1391 1.1 christos */
1392 1.1 christos if (st->popt.no_log == 0 &&
1393 1.16 christos isc_log_wouldlog(ns_lctx, DNS_RPZ_DEBUG_LEVEL2))
1394 1.16 christos {
1395 1.1 christos dns_name_format(client->query.qname, qnamebuf,
1396 1.1 christos sizeof(qnamebuf));
1397 1.1 christos dns_name_format(p_name, p_namebuf, sizeof(p_namebuf));
1398 1.1 christos ns_client_log(client, DNS_LOGCATEGORY_RPZ,
1399 1.1 christos NS_LOGMODULE_QUERY, DNS_RPZ_DEBUG_LEVEL2,
1400 1.1 christos "try rpz %s rewrite %s via %s",
1401 1.9 christos dns_rpz_type2str(rpz_type), qnamebuf,
1402 1.9 christos p_namebuf);
1403 1.1 christos }
1404 1.1 christos *versionp = rpz_version;
1405 1.23 christos return ISC_R_SUCCESS;
1406 1.1 christos }
1407 1.1 christos rpz_log_fail(client, DNS_RPZ_ERROR_LEVEL, p_name, rpz_type,
1408 1.3 christos "query_getzonedb()", result);
1409 1.23 christos return result;
1410 1.1 christos }
1411 1.1 christos
1412 1.3 christos /*%
1413 1.3 christos * Find a cache database to answer the query. This may fail with DNS_R_REFUSED
1414 1.3 christos * if the client is not allowed to use the cache.
1415 1.3 christos */
1416 1.15 christos static isc_result_t
1417 1.1 christos query_getcachedb(ns_client_t *client, const dns_name_t *name,
1418 1.23 christos dns_rdatatype_t qtype, dns_db_t **dbp,
1419 1.23 christos dns_getdb_options_t options) {
1420 1.1 christos isc_result_t result;
1421 1.1 christos dns_db_t *db = NULL;
1422 1.1 christos
1423 1.1 christos REQUIRE(dbp != NULL && *dbp == NULL);
1424 1.1 christos
1425 1.3 christos if (!USECACHE(client)) {
1426 1.23 christos return DNS_R_REFUSED;
1427 1.1 christos }
1428 1.1 christos
1429 1.3 christos dns_db_attach(client->view->cachedb, &db);
1430 1.1 christos
1431 1.3 christos result = query_checkcacheaccess(client, name, qtype, options);
1432 1.3 christos if (result != ISC_R_SUCCESS) {
1433 1.3 christos dns_db_detach(&db);
1434 1.1 christos }
1435 1.1 christos
1436 1.3 christos /*
1437 1.3 christos * If query_checkcacheaccess() succeeded, transfer ownership of 'db'.
1438 1.3 christos * Otherwise, 'db' will be NULL due to the dns_db_detach() call above.
1439 1.3 christos */
1440 1.1 christos *dbp = db;
1441 1.1 christos
1442 1.23 christos return result;
1443 1.3 christos }
1444 1.1 christos
1445 1.15 christos static isc_result_t
1446 1.3 christos query_getdb(ns_client_t *client, dns_name_t *name, dns_rdatatype_t qtype,
1447 1.23 christos dns_getdb_options_t options, dns_zone_t **zonep, dns_db_t **dbp,
1448 1.9 christos dns_dbversion_t **versionp, bool *is_zonep) {
1449 1.1 christos isc_result_t result;
1450 1.1 christos isc_result_t tresult;
1451 1.1 christos unsigned int namelabels;
1452 1.1 christos unsigned int zonelabels;
1453 1.1 christos dns_zone_t *zone = NULL;
1454 1.1 christos
1455 1.1 christos REQUIRE(zonep != NULL && *zonep == NULL);
1456 1.1 christos
1457 1.1 christos /* Calculate how many labels are in name. */
1458 1.1 christos namelabels = dns_name_countlabels(name);
1459 1.1 christos zonelabels = 0;
1460 1.1 christos
1461 1.1 christos /* Try to find name in bind's standard database. */
1462 1.9 christos result = query_getzonedb(client, name, qtype, options, &zone, dbp,
1463 1.9 christos versionp);
1464 1.1 christos
1465 1.1 christos /* See how many labels are in the zone's name. */
1466 1.5 christos if (result == ISC_R_SUCCESS && zone != NULL) {
1467 1.1 christos zonelabels = dns_name_countlabels(dns_zone_getorigin(zone));
1468 1.5 christos }
1469 1.1 christos
1470 1.1 christos /*
1471 1.1 christos * If # zone labels < # name labels, try to find an even better match
1472 1.1 christos * Only try if DLZ drivers are loaded for this view
1473 1.1 christos */
1474 1.20 christos if (zonelabels < namelabels &&
1475 1.20 christos !ISC_LIST_EMPTY(client->view->dlz_searched))
1476 1.1 christos {
1477 1.1 christos dns_clientinfomethods_t cm;
1478 1.1 christos dns_clientinfo_t ci;
1479 1.1 christos dns_db_t *tdbp;
1480 1.1 christos
1481 1.1 christos dns_clientinfomethods_init(&cm, ns_client_sourceip);
1482 1.20 christos dns_clientinfo_init(&ci, client, NULL);
1483 1.20 christos dns_clientinfo_setecs(&ci, &client->ecs);
1484 1.1 christos
1485 1.1 christos tdbp = NULL;
1486 1.9 christos tresult = dns_view_searchdlz(client->view, name, zonelabels,
1487 1.9 christos &cm, &ci, &tdbp);
1488 1.9 christos /* If we successful, we found a better match. */
1489 1.1 christos if (tresult == ISC_R_SUCCESS) {
1490 1.1 christos ns_dbversion_t *dbversion;
1491 1.1 christos
1492 1.1 christos /*
1493 1.1 christos * If the previous search returned a zone, detach it.
1494 1.1 christos */
1495 1.9 christos if (zone != NULL) {
1496 1.1 christos dns_zone_detach(&zone);
1497 1.9 christos }
1498 1.1 christos
1499 1.1 christos /*
1500 1.1 christos * If the previous search returned a database,
1501 1.1 christos * detach it.
1502 1.1 christos */
1503 1.9 christos if (*dbp != NULL) {
1504 1.1 christos dns_db_detach(dbp);
1505 1.9 christos }
1506 1.1 christos
1507 1.1 christos /*
1508 1.1 christos * If the previous search returned a version, clear it.
1509 1.1 christos */
1510 1.1 christos *versionp = NULL;
1511 1.1 christos
1512 1.3 christos dbversion = ns_client_findversion(client, tdbp);
1513 1.1 christos if (dbversion == NULL) {
1514 1.1 christos tresult = ISC_R_NOMEMORY;
1515 1.1 christos } else {
1516 1.1 christos /*
1517 1.1 christos * Be sure to return our database.
1518 1.1 christos */
1519 1.1 christos *dbp = tdbp;
1520 1.1 christos *versionp = dbversion->version;
1521 1.1 christos }
1522 1.1 christos
1523 1.1 christos /*
1524 1.1 christos * We return a null zone, No stats for DLZ zones.
1525 1.1 christos */
1526 1.1 christos zone = NULL;
1527 1.1 christos result = tresult;
1528 1.1 christos }
1529 1.1 christos }
1530 1.1 christos
1531 1.1 christos /* If successful, Transfer ownership of zone. */
1532 1.1 christos if (result == ISC_R_SUCCESS) {
1533 1.1 christos *zonep = zone;
1534 1.1 christos /*
1535 1.1 christos * If neither attempt above succeeded, return the cache instead
1536 1.1 christos */
1537 1.3 christos *is_zonep = true;
1538 1.5 christos } else {
1539 1.5 christos if (result == ISC_R_NOTFOUND) {
1540 1.5 christos result = query_getcachedb(client, name, qtype, dbp,
1541 1.5 christos options);
1542 1.5 christos }
1543 1.3 christos *is_zonep = false;
1544 1.1 christos }
1545 1.23 christos return result;
1546 1.1 christos }
1547 1.1 christos
1548 1.15 christos static bool
1549 1.9 christos query_isduplicate(ns_client_t *client, dns_name_t *name, dns_rdatatype_t type,
1550 1.9 christos dns_name_t **mnamep) {
1551 1.1 christos dns_section_t section;
1552 1.1 christos dns_name_t *mname = NULL;
1553 1.1 christos isc_result_t result;
1554 1.1 christos
1555 1.1 christos CTRACE(ISC_LOG_DEBUG(3), "query_isduplicate");
1556 1.1 christos
1557 1.9 christos for (section = DNS_SECTION_ANSWER; section <= DNS_SECTION_ADDITIONAL;
1558 1.16 christos section++)
1559 1.16 christos {
1560 1.9 christos result = dns_message_findname(client->message, section, name,
1561 1.9 christos type, 0, &mname, NULL);
1562 1.1 christos if (result == ISC_R_SUCCESS) {
1563 1.1 christos /*
1564 1.1 christos * We've already got this RRset in the response.
1565 1.1 christos */
1566 1.9 christos CTRACE(ISC_LOG_DEBUG(3), "query_isduplicate: true: "
1567 1.9 christos "done");
1568 1.23 christos return true;
1569 1.1 christos } else if (result == DNS_R_NXRRSET) {
1570 1.1 christos /*
1571 1.1 christos * The name exists, but the rdataset does not.
1572 1.1 christos */
1573 1.9 christos if (section == DNS_SECTION_ADDITIONAL) {
1574 1.1 christos break;
1575 1.9 christos }
1576 1.9 christos } else {
1577 1.1 christos RUNTIME_CHECK(result == DNS_R_NXDOMAIN);
1578 1.9 christos }
1579 1.1 christos mname = NULL;
1580 1.1 christos }
1581 1.1 christos
1582 1.23 christos SET_IF_NOT_NULL(mnamep, mname);
1583 1.1 christos
1584 1.1 christos CTRACE(ISC_LOG_DEBUG(3), "query_isduplicate: false: done");
1585 1.23 christos return false;
1586 1.1 christos }
1587 1.1 christos
1588 1.6 christos /*
1589 1.6 christos * Look up data for given 'name' and 'type' in given 'version' of 'db' for
1590 1.6 christos * 'client'. Called from query_additionalauth().
1591 1.6 christos *
1592 1.6 christos * If the lookup is successful:
1593 1.6 christos *
1594 1.6 christos * - store the node containing the result at 'nodep',
1595 1.6 christos *
1596 1.6 christos * - store the owner name of the returned node in 'fname',
1597 1.6 christos *
1598 1.6 christos * - if 'type' is not ANY, dns_db_findext() will put the exact rdataset being
1599 1.6 christos * looked for in 'rdataset' and its signatures (if any) in 'sigrdataset',
1600 1.6 christos *
1601 1.6 christos * - if 'type' is ANY, dns_db_findext() will leave 'rdataset' and
1602 1.6 christos * 'sigrdataset' disassociated and the returned node will be iterated in
1603 1.6 christos * query_additional_cb().
1604 1.6 christos *
1605 1.6 christos * If the lookup is not successful:
1606 1.6 christos *
1607 1.6 christos * - 'nodep' will not be written to,
1608 1.6 christos * - 'fname' may still be modified as it is passed to dns_db_findext(),
1609 1.6 christos * - 'rdataset' and 'sigrdataset' will remain disassociated.
1610 1.6 christos */
1611 1.6 christos static isc_result_t
1612 1.6 christos query_additionalauthfind(dns_db_t *db, dns_dbversion_t *version,
1613 1.6 christos const dns_name_t *name, dns_rdatatype_t type,
1614 1.6 christos ns_client_t *client, dns_dbnode_t **nodep,
1615 1.6 christos dns_name_t *fname, dns_rdataset_t *rdataset,
1616 1.9 christos dns_rdataset_t *sigrdataset) {
1617 1.6 christos dns_clientinfomethods_t cm;
1618 1.6 christos dns_dbnode_t *node = NULL;
1619 1.6 christos dns_clientinfo_t ci;
1620 1.6 christos isc_result_t result;
1621 1.6 christos
1622 1.6 christos dns_clientinfomethods_init(&cm, ns_client_sourceip);
1623 1.20 christos dns_clientinfo_init(&ci, client, NULL);
1624 1.6 christos
1625 1.6 christos /*
1626 1.6 christos * Since we are looking for authoritative data, we do not set
1627 1.6 christos * the GLUEOK flag. Glue will be looked for later, but not
1628 1.6 christos * necessarily in the same database.
1629 1.6 christos */
1630 1.6 christos result = dns_db_findext(db, name, version, type,
1631 1.6 christos client->query.dboptions, client->now, &node,
1632 1.6 christos fname, &cm, &ci, rdataset, sigrdataset);
1633 1.6 christos if (result != ISC_R_SUCCESS) {
1634 1.6 christos if (dns_rdataset_isassociated(rdataset)) {
1635 1.6 christos dns_rdataset_disassociate(rdataset);
1636 1.6 christos }
1637 1.6 christos
1638 1.6 christos if (sigrdataset != NULL &&
1639 1.16 christos dns_rdataset_isassociated(sigrdataset))
1640 1.16 christos {
1641 1.6 christos dns_rdataset_disassociate(sigrdataset);
1642 1.6 christos }
1643 1.6 christos
1644 1.6 christos if (node != NULL) {
1645 1.6 christos dns_db_detachnode(db, &node);
1646 1.6 christos }
1647 1.6 christos
1648 1.23 christos return result;
1649 1.6 christos }
1650 1.6 christos
1651 1.6 christos /*
1652 1.6 christos * Do not return signatures if the zone is not fully signed.
1653 1.6 christos */
1654 1.6 christos if (sigrdataset != NULL && !dns_db_issecure(db) &&
1655 1.6 christos dns_rdataset_isassociated(sigrdataset))
1656 1.6 christos {
1657 1.6 christos dns_rdataset_disassociate(sigrdataset);
1658 1.6 christos }
1659 1.6 christos
1660 1.6 christos *nodep = node;
1661 1.6 christos
1662 1.23 christos return ISC_R_SUCCESS;
1663 1.6 christos }
1664 1.6 christos
1665 1.6 christos /*
1666 1.6 christos * For query context 'qctx', try finding authoritative additional data for
1667 1.6 christos * given 'name' and 'type'. Called from query_additional_cb().
1668 1.6 christos *
1669 1.6 christos * If successful:
1670 1.6 christos *
1671 1.6 christos * - store pointers to the database and node which contain the result in
1672 1.6 christos * 'dbp' and 'nodep', respectively,
1673 1.6 christos *
1674 1.6 christos * - store the owner name of the returned node in 'fname',
1675 1.6 christos *
1676 1.6 christos * - potentially bind 'rdataset' and 'sigrdataset', as explained in the
1677 1.6 christos * comment for query_additionalauthfind().
1678 1.6 christos *
1679 1.6 christos * If unsuccessful:
1680 1.6 christos *
1681 1.6 christos * - 'dbp' and 'nodep' will not be written to,
1682 1.6 christos * - 'fname' may still be modified as it is passed to dns_db_findext(),
1683 1.6 christos * - 'rdataset' and 'sigrdataset' will remain disassociated.
1684 1.6 christos */
1685 1.6 christos static isc_result_t
1686 1.6 christos query_additionalauth(query_ctx_t *qctx, const dns_name_t *name,
1687 1.9 christos dns_rdatatype_t type, dns_db_t **dbp, dns_dbnode_t **nodep,
1688 1.9 christos dns_name_t *fname, dns_rdataset_t *rdataset,
1689 1.9 christos dns_rdataset_t *sigrdataset) {
1690 1.6 christos ns_client_t *client = qctx->client;
1691 1.6 christos ns_dbversion_t *dbversion = NULL;
1692 1.6 christos dns_dbversion_t *version = NULL;
1693 1.6 christos dns_dbnode_t *node = NULL;
1694 1.6 christos dns_zone_t *zone = NULL;
1695 1.6 christos dns_db_t *db = NULL;
1696 1.6 christos isc_result_t result;
1697 1.6 christos
1698 1.6 christos /*
1699 1.6 christos * First, look within the same zone database for authoritative
1700 1.6 christos * additional data.
1701 1.6 christos */
1702 1.6 christos if (!client->query.authdbset || client->query.authdb == NULL) {
1703 1.23 christos return ISC_R_NOTFOUND;
1704 1.6 christos }
1705 1.6 christos
1706 1.6 christos dbversion = ns_client_findversion(client, client->query.authdb);
1707 1.6 christos if (dbversion == NULL) {
1708 1.23 christos return ISC_R_NOTFOUND;
1709 1.6 christos }
1710 1.6 christos
1711 1.6 christos dns_db_attach(client->query.authdb, &db);
1712 1.6 christos version = dbversion->version;
1713 1.6 christos
1714 1.6 christos CTRACE(ISC_LOG_DEBUG(3), "query_additionalauth: same zone");
1715 1.6 christos
1716 1.6 christos result = query_additionalauthfind(db, version, name, type, client,
1717 1.6 christos &node, fname, rdataset, sigrdataset);
1718 1.6 christos if (result != ISC_R_SUCCESS &&
1719 1.6 christos qctx->view->minimalresponses == dns_minimal_no &&
1720 1.6 christos RECURSIONOK(client))
1721 1.6 christos {
1722 1.6 christos /*
1723 1.6 christos * If we aren't doing response minimization and recursion is
1724 1.6 christos * allowed, we can try and see if any other zone matches.
1725 1.6 christos */
1726 1.6 christos version = NULL;
1727 1.6 christos dns_db_detach(&db);
1728 1.23 christos dns_getdb_options_t options = { .nolog = true };
1729 1.23 christos result = query_getzonedb(client, name, type, options, &zone,
1730 1.23 christos &db, &version);
1731 1.6 christos if (result != ISC_R_SUCCESS) {
1732 1.23 christos return result;
1733 1.6 christos }
1734 1.6 christos dns_zone_detach(&zone);
1735 1.6 christos
1736 1.6 christos CTRACE(ISC_LOG_DEBUG(3), "query_additionalauth: other zone");
1737 1.6 christos
1738 1.6 christos result = query_additionalauthfind(db, version, name, type,
1739 1.6 christos client, &node, fname,
1740 1.6 christos rdataset, sigrdataset);
1741 1.6 christos }
1742 1.6 christos
1743 1.6 christos if (result != ISC_R_SUCCESS) {
1744 1.6 christos dns_db_detach(&db);
1745 1.6 christos } else {
1746 1.6 christos *nodep = node;
1747 1.6 christos node = NULL;
1748 1.6 christos
1749 1.6 christos *dbp = db;
1750 1.6 christos db = NULL;
1751 1.6 christos }
1752 1.6 christos
1753 1.23 christos return result;
1754 1.6 christos }
1755 1.6 christos
1756 1.1 christos static isc_result_t
1757 1.20 christos query_additional_cb(void *arg, const dns_name_t *name, dns_rdatatype_t qtype,
1758 1.23 christos dns_rdataset_t *found DNS__DB_FLARG) {
1759 1.3 christos query_ctx_t *qctx = arg;
1760 1.3 christos ns_client_t *client = qctx->client;
1761 1.3 christos isc_result_t result, eresult = ISC_R_SUCCESS;
1762 1.3 christos dns_dbnode_t *node = NULL;
1763 1.3 christos dns_db_t *db = NULL;
1764 1.3 christos dns_name_t *fname = NULL, *mname = NULL;
1765 1.3 christos dns_rdataset_t *rdataset = NULL, *sigrdataset = NULL;
1766 1.3 christos dns_rdataset_t *trdataset = NULL;
1767 1.3 christos isc_buffer_t *dbuf = NULL;
1768 1.1 christos isc_buffer_t b;
1769 1.3 christos ns_dbversion_t *dbversion = NULL;
1770 1.3 christos dns_dbversion_t *version = NULL;
1771 1.3 christos bool added_something = false, need_addname = false;
1772 1.1 christos dns_rdatatype_t type;
1773 1.1 christos dns_clientinfomethods_t cm;
1774 1.1 christos dns_clientinfo_t ci;
1775 1.3 christos dns_rdatasetadditional_t additionaltype =
1776 1.3 christos dns_rdatasetadditional_fromauth;
1777 1.1 christos
1778 1.1 christos REQUIRE(NS_CLIENT_VALID(client));
1779 1.1 christos REQUIRE(qtype != dns_rdatatype_any);
1780 1.1 christos
1781 1.3 christos if (!WANTDNSSEC(client) && dns_rdatatype_isdnssec(qtype)) {
1782 1.23 christos return ISC_R_SUCCESS;
1783 1.3 christos }
1784 1.1 christos
1785 1.3 christos CTRACE(ISC_LOG_DEBUG(3), "query_additional_cb");
1786 1.1 christos
1787 1.1 christos dns_clientinfomethods_init(&cm, ns_client_sourceip);
1788 1.20 christos dns_clientinfo_init(&ci, client, NULL);
1789 1.1 christos
1790 1.1 christos /*
1791 1.1 christos * We treat type A additional section processing as if it
1792 1.1 christos * were "any address type" additional section processing.
1793 1.1 christos * To avoid multiple lookups, we do an 'any' database
1794 1.1 christos * lookup and iterate over the node.
1795 1.1 christos */
1796 1.3 christos if (qtype == dns_rdatatype_a) {
1797 1.1 christos type = dns_rdatatype_any;
1798 1.3 christos } else {
1799 1.1 christos type = qtype;
1800 1.3 christos }
1801 1.1 christos
1802 1.1 christos /*
1803 1.1 christos * Get some resources.
1804 1.1 christos */
1805 1.3 christos dbuf = ns_client_getnamebuf(client);
1806 1.3 christos fname = ns_client_newname(client, dbuf, &b);
1807 1.3 christos rdataset = ns_client_newrdataset(client);
1808 1.1 christos if (WANTDNSSEC(client)) {
1809 1.3 christos sigrdataset = ns_client_newrdataset(client);
1810 1.1 christos }
1811 1.1 christos
1812 1.1 christos /*
1813 1.1 christos * If we want only minimal responses and are here, then it must
1814 1.1 christos * be for glue.
1815 1.1 christos */
1816 1.11 christos if (qctx->view->minimalresponses == dns_minimal_yes &&
1817 1.11 christos client->query.qtype != dns_rdatatype_ns)
1818 1.11 christos {
1819 1.1 christos goto try_glue;
1820 1.3 christos }
1821 1.1 christos
1822 1.1 christos /*
1823 1.6 christos * First, look for authoritative additional data.
1824 1.1 christos */
1825 1.6 christos result = query_additionalauth(qctx, name, type, &db, &node, fname,
1826 1.6 christos rdataset, sigrdataset);
1827 1.1 christos if (result == ISC_R_SUCCESS) {
1828 1.1 christos goto found;
1829 1.1 christos }
1830 1.1 christos
1831 1.1 christos /*
1832 1.1 christos * No authoritative data was found. The cache is our next best bet.
1833 1.1 christos */
1834 1.3 christos if (!qctx->view->recursion) {
1835 1.1 christos goto try_glue;
1836 1.3 christos }
1837 1.1 christos
1838 1.1 christos additionaltype = dns_rdatasetadditional_fromcache;
1839 1.23 christos dns_getdb_options_t options = { .nolog = true };
1840 1.23 christos result = query_getcachedb(client, name, qtype, &db, options);
1841 1.1 christos if (result != ISC_R_SUCCESS) {
1842 1.1 christos /*
1843 1.1 christos * Most likely the client isn't allowed to query the cache.
1844 1.1 christos */
1845 1.1 christos goto try_glue;
1846 1.1 christos }
1847 1.1 christos /*
1848 1.1 christos * Attempt to validate glue.
1849 1.1 christos */
1850 1.1 christos if (sigrdataset == NULL) {
1851 1.3 christos sigrdataset = ns_client_newrdataset(client);
1852 1.1 christos }
1853 1.1 christos
1854 1.1 christos version = NULL;
1855 1.1 christos result = dns_db_findext(db, name, version, type,
1856 1.9 christos client->query.dboptions | DNS_DBFIND_GLUEOK |
1857 1.9 christos DNS_DBFIND_ADDITIONALOK,
1858 1.9 christos client->now, &node, fname, &cm, &ci, rdataset,
1859 1.9 christos sigrdataset);
1860 1.1 christos
1861 1.3 christos dns_cache_updatestats(qctx->view->cache, result);
1862 1.3 christos if (!WANTDNSSEC(client)) {
1863 1.3 christos ns_client_putrdataset(client, &sigrdataset);
1864 1.3 christos }
1865 1.9 christos if (result == ISC_R_SUCCESS) {
1866 1.1 christos goto found;
1867 1.9 christos }
1868 1.1 christos
1869 1.3 christos if (dns_rdataset_isassociated(rdataset)) {
1870 1.1 christos dns_rdataset_disassociate(rdataset);
1871 1.3 christos }
1872 1.3 christos if (sigrdataset != NULL && dns_rdataset_isassociated(sigrdataset)) {
1873 1.1 christos dns_rdataset_disassociate(sigrdataset);
1874 1.3 christos }
1875 1.3 christos if (node != NULL) {
1876 1.1 christos dns_db_detachnode(db, &node);
1877 1.3 christos }
1878 1.1 christos dns_db_detach(&db);
1879 1.1 christos
1880 1.9 christos try_glue:
1881 1.1 christos /*
1882 1.1 christos * No cached data was found. Glue is our last chance.
1883 1.1 christos * RFC1035 sayeth:
1884 1.1 christos *
1885 1.1 christos * NS records cause both the usual additional section
1886 1.1 christos * processing to locate a type A record, and, when used
1887 1.1 christos * in a referral, a special search of the zone in which
1888 1.1 christos * they reside for glue information.
1889 1.1 christos *
1890 1.1 christos * This is the "special search". Note that we must search
1891 1.1 christos * the zone where the NS record resides, not the zone it
1892 1.1 christos * points to, and that we only do the search in the delegation
1893 1.1 christos * case (identified by client->query.gluedb being set).
1894 1.1 christos */
1895 1.1 christos
1896 1.3 christos if (client->query.gluedb == NULL) {
1897 1.1 christos goto cleanup;
1898 1.3 christos }
1899 1.1 christos
1900 1.1 christos /*
1901 1.1 christos * Don't poison caches using the bailiwick protection model.
1902 1.1 christos */
1903 1.3 christos if (!dns_name_issubdomain(name, dns_db_origin(client->query.gluedb))) {
1904 1.1 christos goto cleanup;
1905 1.3 christos }
1906 1.1 christos
1907 1.3 christos dbversion = ns_client_findversion(client, client->query.gluedb);
1908 1.3 christos if (dbversion == NULL) {
1909 1.1 christos goto cleanup;
1910 1.3 christos }
1911 1.1 christos
1912 1.1 christos dns_db_attach(client->query.gluedb, &db);
1913 1.1 christos version = dbversion->version;
1914 1.1 christos additionaltype = dns_rdatasetadditional_fromglue;
1915 1.1 christos result = dns_db_findext(db, name, version, type,
1916 1.1 christos client->query.dboptions | DNS_DBFIND_GLUEOK,
1917 1.9 christos client->now, &node, fname, &cm, &ci, rdataset,
1918 1.9 christos sigrdataset);
1919 1.9 christos if (result != ISC_R_SUCCESS && result != DNS_R_ZONECUT &&
1920 1.16 christos result != DNS_R_GLUE)
1921 1.16 christos {
1922 1.1 christos goto cleanup;
1923 1.3 christos }
1924 1.1 christos
1925 1.9 christos found:
1926 1.1 christos /*
1927 1.1 christos * We have found a potential additional data rdataset, or
1928 1.1 christos * at least a node to iterate over.
1929 1.1 christos */
1930 1.3 christos ns_client_keepname(client, fname, dbuf);
1931 1.1 christos
1932 1.1 christos /*
1933 1.20 christos * Does the caller want the found rdataset?
1934 1.20 christos */
1935 1.20 christos if (found != NULL && dns_rdataset_isassociated(rdataset)) {
1936 1.20 christos dns_rdataset_clone(rdataset, found);
1937 1.20 christos }
1938 1.20 christos
1939 1.20 christos /*
1940 1.1 christos * If we have an rdataset, add it to the additional data
1941 1.1 christos * section.
1942 1.1 christos */
1943 1.1 christos mname = NULL;
1944 1.1 christos if (dns_rdataset_isassociated(rdataset) &&
1945 1.3 christos !query_isduplicate(client, fname, type, &mname))
1946 1.3 christos {
1947 1.1 christos if (mname != NULL) {
1948 1.1 christos INSIST(mname != fname);
1949 1.3 christos ns_client_releasename(client, &fname);
1950 1.1 christos fname = mname;
1951 1.3 christos } else {
1952 1.3 christos need_addname = true;
1953 1.3 christos }
1954 1.1 christos ISC_LIST_APPEND(fname->list, rdataset, link);
1955 1.1 christos trdataset = rdataset;
1956 1.1 christos rdataset = NULL;
1957 1.3 christos added_something = true;
1958 1.1 christos /*
1959 1.1 christos * Note: we only add SIGs if we've added the type they cover,
1960 1.1 christos * so we do not need to check if the SIG rdataset is already
1961 1.1 christos * in the response.
1962 1.1 christos */
1963 1.1 christos if (sigrdataset != NULL &&
1964 1.16 christos dns_rdataset_isassociated(sigrdataset))
1965 1.16 christos {
1966 1.1 christos ISC_LIST_APPEND(fname->list, sigrdataset, link);
1967 1.1 christos sigrdataset = NULL;
1968 1.1 christos }
1969 1.1 christos }
1970 1.1 christos
1971 1.1 christos if (qtype == dns_rdatatype_a) {
1972 1.1 christos /*
1973 1.1 christos * We now go looking for A and AAAA records, along with
1974 1.1 christos * their signatures.
1975 1.1 christos *
1976 1.1 christos * XXXRTH This code could be more efficient.
1977 1.1 christos */
1978 1.1 christos if (rdataset != NULL) {
1979 1.3 christos if (dns_rdataset_isassociated(rdataset)) {
1980 1.1 christos dns_rdataset_disassociate(rdataset);
1981 1.3 christos }
1982 1.1 christos } else {
1983 1.3 christos rdataset = ns_client_newrdataset(client);
1984 1.1 christos }
1985 1.1 christos if (sigrdataset != NULL) {
1986 1.3 christos if (dns_rdataset_isassociated(sigrdataset)) {
1987 1.1 christos dns_rdataset_disassociate(sigrdataset);
1988 1.3 christos }
1989 1.1 christos } else if (WANTDNSSEC(client)) {
1990 1.3 christos sigrdataset = ns_client_newrdataset(client);
1991 1.1 christos }
1992 1.3 christos if (query_isduplicate(client, fname, dns_rdatatype_a, NULL)) {
1993 1.1 christos goto aaaa_lookup;
1994 1.3 christos }
1995 1.9 christos result = dns_db_findrdataset(db, node, version, dns_rdatatype_a,
1996 1.9 christos 0, client->now, rdataset,
1997 1.9 christos sigrdataset);
1998 1.1 christos if (result == DNS_R_NCACHENXDOMAIN) {
1999 1.1 christos goto addname;
2000 1.1 christos } else if (result == DNS_R_NCACHENXRRSET) {
2001 1.1 christos dns_rdataset_disassociate(rdataset);
2002 1.1 christos if (sigrdataset != NULL &&
2003 1.16 christos dns_rdataset_isassociated(sigrdataset))
2004 1.16 christos {
2005 1.1 christos dns_rdataset_disassociate(sigrdataset);
2006 1.3 christos }
2007 1.1 christos } else if (result == ISC_R_SUCCESS) {
2008 1.3 christos bool invalid = false;
2009 1.1 christos mname = NULL;
2010 1.1 christos if (additionaltype ==
2011 1.9 christos dns_rdatasetadditional_fromcache &&
2012 1.1 christos (DNS_TRUST_PENDING(rdataset->trust) ||
2013 1.1 christos DNS_TRUST_GLUE(rdataset->trust)))
2014 1.1 christos {
2015 1.1 christos /* validate() may change rdataset->trust */
2016 1.9 christos invalid = !validate(client, db, fname, rdataset,
2017 1.9 christos sigrdataset);
2018 1.1 christos }
2019 1.1 christos if (invalid && DNS_TRUST_PENDING(rdataset->trust)) {
2020 1.1 christos dns_rdataset_disassociate(rdataset);
2021 1.1 christos if (sigrdataset != NULL &&
2022 1.16 christos dns_rdataset_isassociated(sigrdataset))
2023 1.16 christos {
2024 1.1 christos dns_rdataset_disassociate(sigrdataset);
2025 1.3 christos }
2026 1.1 christos } else if (!query_isduplicate(client, fname,
2027 1.9 christos dns_rdatatype_a, &mname))
2028 1.9 christos {
2029 1.1 christos if (mname != fname) {
2030 1.1 christos if (mname != NULL) {
2031 1.3 christos ns_client_releasename(client,
2032 1.3 christos &fname);
2033 1.1 christos fname = mname;
2034 1.3 christos } else {
2035 1.3 christos need_addname = true;
2036 1.3 christos }
2037 1.1 christos }
2038 1.1 christos ISC_LIST_APPEND(fname->list, rdataset, link);
2039 1.3 christos added_something = true;
2040 1.1 christos if (sigrdataset != NULL &&
2041 1.16 christos dns_rdataset_isassociated(sigrdataset))
2042 1.16 christos {
2043 1.1 christos ISC_LIST_APPEND(fname->list,
2044 1.1 christos sigrdataset, link);
2045 1.1 christos sigrdataset =
2046 1.3 christos ns_client_newrdataset(client);
2047 1.1 christos }
2048 1.3 christos rdataset = ns_client_newrdataset(client);
2049 1.1 christos } else {
2050 1.1 christos dns_rdataset_disassociate(rdataset);
2051 1.1 christos if (sigrdataset != NULL &&
2052 1.16 christos dns_rdataset_isassociated(sigrdataset))
2053 1.16 christos {
2054 1.1 christos dns_rdataset_disassociate(sigrdataset);
2055 1.3 christos }
2056 1.1 christos }
2057 1.1 christos }
2058 1.9 christos aaaa_lookup:
2059 1.1 christos if (query_isduplicate(client, fname, dns_rdatatype_aaaa, NULL))
2060 1.3 christos {
2061 1.1 christos goto addname;
2062 1.3 christos }
2063 1.1 christos result = dns_db_findrdataset(db, node, version,
2064 1.9 christos dns_rdatatype_aaaa, 0, client->now,
2065 1.1 christos rdataset, sigrdataset);
2066 1.1 christos if (result == DNS_R_NCACHENXDOMAIN) {
2067 1.1 christos goto addname;
2068 1.1 christos } else if (result == DNS_R_NCACHENXRRSET) {
2069 1.1 christos dns_rdataset_disassociate(rdataset);
2070 1.1 christos if (sigrdataset != NULL &&
2071 1.16 christos dns_rdataset_isassociated(sigrdataset))
2072 1.16 christos {
2073 1.1 christos dns_rdataset_disassociate(sigrdataset);
2074 1.3 christos }
2075 1.1 christos } else if (result == ISC_R_SUCCESS) {
2076 1.3 christos bool invalid = false;
2077 1.1 christos mname = NULL;
2078 1.3 christos
2079 1.1 christos if (additionaltype ==
2080 1.9 christos dns_rdatasetadditional_fromcache &&
2081 1.1 christos (DNS_TRUST_PENDING(rdataset->trust) ||
2082 1.1 christos DNS_TRUST_GLUE(rdataset->trust)))
2083 1.1 christos {
2084 1.1 christos /* validate() may change rdataset->trust */
2085 1.9 christos invalid = !validate(client, db, fname, rdataset,
2086 1.9 christos sigrdataset);
2087 1.1 christos }
2088 1.1 christos
2089 1.1 christos if (invalid && DNS_TRUST_PENDING(rdataset->trust)) {
2090 1.1 christos dns_rdataset_disassociate(rdataset);
2091 1.1 christos if (sigrdataset != NULL &&
2092 1.16 christos dns_rdataset_isassociated(sigrdataset))
2093 1.16 christos {
2094 1.1 christos dns_rdataset_disassociate(sigrdataset);
2095 1.3 christos }
2096 1.1 christos } else if (!query_isduplicate(client, fname,
2097 1.9 christos dns_rdatatype_aaaa,
2098 1.16 christos &mname))
2099 1.16 christos {
2100 1.1 christos if (mname != fname) {
2101 1.1 christos if (mname != NULL) {
2102 1.3 christos ns_client_releasename(client,
2103 1.3 christos &fname);
2104 1.1 christos fname = mname;
2105 1.3 christos } else {
2106 1.3 christos need_addname = true;
2107 1.3 christos }
2108 1.1 christos }
2109 1.1 christos ISC_LIST_APPEND(fname->list, rdataset, link);
2110 1.3 christos added_something = true;
2111 1.1 christos if (sigrdataset != NULL &&
2112 1.16 christos dns_rdataset_isassociated(sigrdataset))
2113 1.16 christos {
2114 1.1 christos ISC_LIST_APPEND(fname->list,
2115 1.1 christos sigrdataset, link);
2116 1.1 christos sigrdataset = NULL;
2117 1.1 christos }
2118 1.1 christos rdataset = NULL;
2119 1.1 christos }
2120 1.1 christos }
2121 1.1 christos }
2122 1.1 christos
2123 1.9 christos addname:
2124 1.3 christos CTRACE(ISC_LOG_DEBUG(3), "query_additional_cb: addname");
2125 1.1 christos /*
2126 1.1 christos * If we haven't added anything, then we're done.
2127 1.1 christos */
2128 1.3 christos if (!added_something) {
2129 1.1 christos goto cleanup;
2130 1.3 christos }
2131 1.1 christos
2132 1.1 christos /*
2133 1.1 christos * We may have added our rdatasets to an existing name, if so, then
2134 1.3 christos * need_addname will be false. Whether we used an existing name
2135 1.1 christos * or a new one, we must set fname to NULL to prevent cleanup.
2136 1.1 christos */
2137 1.3 christos if (need_addname) {
2138 1.1 christos dns_message_addname(client->message, fname,
2139 1.1 christos DNS_SECTION_ADDITIONAL);
2140 1.3 christos }
2141 1.1 christos
2142 1.1 christos /*
2143 1.15 christos * In some cases, a record that has been added as additional
2144 1.15 christos * data may *also* trigger the addition of additional data.
2145 1.22 christos * This cannot go more than 'max-restarts' levels deep.
2146 1.15 christos */
2147 1.15 christos if (trdataset != NULL && dns_rdatatype_followadditional(type)) {
2148 1.22 christos if (client->additionaldepth++ < client->view->max_restarts) {
2149 1.20 christos eresult = dns_rdataset_additionaldata(
2150 1.24 christos trdataset, fname, query_additional_cb, qctx,
2151 1.24 christos DNS_RDATASET_MAXADDITIONAL);
2152 1.20 christos }
2153 1.20 christos client->additionaldepth--;
2154 1.1 christos }
2155 1.1 christos
2156 1.20 christos /*
2157 1.20 christos * Don't release fname.
2158 1.20 christos */
2159 1.20 christos fname = NULL;
2160 1.20 christos
2161 1.9 christos cleanup:
2162 1.3 christos CTRACE(ISC_LOG_DEBUG(3), "query_additional_cb: cleanup");
2163 1.3 christos ns_client_putrdataset(client, &rdataset);
2164 1.3 christos if (sigrdataset != NULL) {
2165 1.3 christos ns_client_putrdataset(client, &sigrdataset);
2166 1.3 christos }
2167 1.3 christos if (fname != NULL) {
2168 1.3 christos ns_client_releasename(client, &fname);
2169 1.3 christos }
2170 1.3 christos if (node != NULL) {
2171 1.1 christos dns_db_detachnode(db, &node);
2172 1.3 christos }
2173 1.3 christos if (db != NULL) {
2174 1.1 christos dns_db_detach(&db);
2175 1.3 christos }
2176 1.1 christos
2177 1.3 christos CTRACE(ISC_LOG_DEBUG(3), "query_additional_cb: done");
2178 1.23 christos return eresult;
2179 1.1 christos }
2180 1.1 christos
2181 1.3 christos /*
2182 1.3 christos * Add 'rdataset' to 'name'.
2183 1.3 christos */
2184 1.15 christos static void
2185 1.3 christos query_addtoname(dns_name_t *name, dns_rdataset_t *rdataset) {
2186 1.3 christos ISC_LIST_APPEND(name->list, rdataset, link);
2187 1.3 christos }
2188 1.3 christos
2189 1.3 christos /*
2190 1.3 christos * Set the ordering for 'rdataset'.
2191 1.3 christos */
2192 1.1 christos static void
2193 1.3 christos query_setorder(query_ctx_t *qctx, dns_name_t *name, dns_rdataset_t *rdataset) {
2194 1.3 christos ns_client_t *client = qctx->client;
2195 1.3 christos dns_order_t *order = client->view->order;
2196 1.1 christos
2197 1.3 christos CTRACE(ISC_LOG_DEBUG(3), "query_setorder");
2198 1.1 christos
2199 1.3 christos UNUSED(client);
2200 1.1 christos
2201 1.3 christos if (order != NULL) {
2202 1.9 christos rdataset->attributes |= dns_order_find(
2203 1.9 christos order, name, rdataset->type, rdataset->rdclass);
2204 1.3 christos }
2205 1.1 christos rdataset->attributes |= DNS_RDATASETATTR_LOADORDER;
2206 1.9 christos }
2207 1.3 christos
2208 1.3 christos /*
2209 1.3 christos * Handle glue and fetch any other needed additional data for 'rdataset'.
2210 1.3 christos */
2211 1.3 christos static void
2212 1.20 christos query_additional(query_ctx_t *qctx, dns_name_t *name,
2213 1.20 christos dns_rdataset_t *rdataset) {
2214 1.3 christos ns_client_t *client = qctx->client;
2215 1.3 christos isc_result_t result;
2216 1.3 christos
2217 1.3 christos CTRACE(ISC_LOG_DEBUG(3), "query_additional");
2218 1.1 christos
2219 1.3 christos if (NOADDITIONAL(client)) {
2220 1.1 christos return;
2221 1.3 christos }
2222 1.1 christos
2223 1.1 christos /*
2224 1.1 christos * Try to process glue directly.
2225 1.1 christos */
2226 1.23 christos if (rdataset->type == dns_rdatatype_ns &&
2227 1.23 christos client->query.gluedb != NULL && dns_db_iszone(client->query.gluedb))
2228 1.1 christos {
2229 1.23 christos ns_dbversion_t *dbversion = NULL;
2230 1.1 christos
2231 1.3 christos dbversion = ns_client_findversion(client, client->query.gluedb);
2232 1.3 christos if (dbversion == NULL) {
2233 1.1 christos goto regular;
2234 1.1 christos }
2235 1.1 christos
2236 1.23 christos result = dns_db_addglue(qctx->db, dbversion->version, rdataset,
2237 1.23 christos client->message);
2238 1.3 christos if (result == ISC_R_SUCCESS) {
2239 1.1 christos return;
2240 1.3 christos }
2241 1.1 christos }
2242 1.1 christos
2243 1.9 christos regular:
2244 1.1 christos /*
2245 1.3 christos * Add other additional data if needed.
2246 1.1 christos * We don't care if dns_rdataset_additionaldata() fails.
2247 1.1 christos */
2248 1.20 christos (void)dns_rdataset_additionaldata(rdataset, name, query_additional_cb,
2249 1.24 christos qctx, DNS_RDATASET_MAXADDITIONAL);
2250 1.3 christos CTRACE(ISC_LOG_DEBUG(3), "query_additional: done");
2251 1.1 christos }
2252 1.1 christos
2253 1.1 christos static void
2254 1.3 christos query_addrrset(query_ctx_t *qctx, dns_name_t **namep,
2255 1.1 christos dns_rdataset_t **rdatasetp, dns_rdataset_t **sigrdatasetp,
2256 1.9 christos isc_buffer_t *dbuf, dns_section_t section) {
2257 1.3 christos isc_result_t result;
2258 1.3 christos ns_client_t *client = qctx->client;
2259 1.1 christos dns_name_t *name = *namep, *mname = NULL;
2260 1.1 christos dns_rdataset_t *rdataset = *rdatasetp, *mrdataset = NULL;
2261 1.1 christos dns_rdataset_t *sigrdataset = NULL;
2262 1.1 christos
2263 1.1 christos CTRACE(ISC_LOG_DEBUG(3), "query_addrrset");
2264 1.1 christos
2265 1.3 christos REQUIRE(name != NULL);
2266 1.3 christos
2267 1.3 christos if (sigrdatasetp != NULL) {
2268 1.1 christos sigrdataset = *sigrdatasetp;
2269 1.3 christos }
2270 1.1 christos
2271 1.1 christos /*%
2272 1.1 christos * To the current response for 'client', add the answer RRset
2273 1.1 christos * '*rdatasetp' and an optional signature set '*sigrdatasetp', with
2274 1.1 christos * owner name '*namep', to section 'section', unless they are
2275 1.24 christos * already there. Also add any pertinent additional data, unless
2276 1.24 christos * the query was for type ANY.
2277 1.1 christos *
2278 1.1 christos * If 'dbuf' is not NULL, then '*namep' is the name whose data is
2279 1.1 christos * stored in 'dbuf'. In this case, query_addrrset() guarantees that
2280 1.1 christos * when it returns the name will either have been kept or released.
2281 1.1 christos */
2282 1.9 christos result = dns_message_findname(client->message, section, name,
2283 1.9 christos rdataset->type, rdataset->covers, &mname,
2284 1.9 christos &mrdataset);
2285 1.1 christos if (result == ISC_R_SUCCESS) {
2286 1.1 christos /*
2287 1.1 christos * We've already got an RRset of the given name and type.
2288 1.1 christos */
2289 1.9 christos CTRACE(ISC_LOG_DEBUG(3), "query_addrrset: dns_message_findname "
2290 1.9 christos "succeeded: done");
2291 1.3 christos if (dbuf != NULL) {
2292 1.3 christos ns_client_releasename(client, namep);
2293 1.3 christos }
2294 1.3 christos if ((rdataset->attributes & DNS_RDATASETATTR_REQUIRED) != 0) {
2295 1.1 christos mrdataset->attributes |= DNS_RDATASETATTR_REQUIRED;
2296 1.3 christos }
2297 1.13 christos if ((rdataset->attributes & DNS_RDATASETATTR_STALE_ADDED) != 0)
2298 1.13 christos {
2299 1.13 christos mrdataset->attributes |= DNS_RDATASETATTR_STALE_ADDED;
2300 1.13 christos }
2301 1.1 christos return;
2302 1.1 christos } else if (result == DNS_R_NXDOMAIN) {
2303 1.1 christos /*
2304 1.1 christos * The name doesn't exist.
2305 1.1 christos */
2306 1.3 christos if (dbuf != NULL) {
2307 1.3 christos ns_client_keepname(client, name, dbuf);
2308 1.3 christos }
2309 1.1 christos dns_message_addname(client->message, name, section);
2310 1.1 christos *namep = NULL;
2311 1.1 christos mname = name;
2312 1.1 christos } else {
2313 1.1 christos RUNTIME_CHECK(result == DNS_R_NXRRSET);
2314 1.3 christos if (dbuf != NULL) {
2315 1.3 christos ns_client_releasename(client, namep);
2316 1.3 christos }
2317 1.1 christos }
2318 1.1 christos
2319 1.1 christos if (rdataset->trust != dns_trust_secure &&
2320 1.9 christos (section == DNS_SECTION_ANSWER || section == DNS_SECTION_AUTHORITY))
2321 1.3 christos {
2322 1.1 christos client->query.attributes &= ~NS_QUERYATTR_SECURE;
2323 1.3 christos }
2324 1.3 christos
2325 1.3 christos /*
2326 1.3 christos * Update message name, set rdataset order, and do additional
2327 1.3 christos * section processing if needed.
2328 1.3 christos */
2329 1.3 christos query_addtoname(mname, rdataset);
2330 1.3 christos query_setorder(qctx, mname, rdataset);
2331 1.24 christos if (qctx->qtype != dns_rdatatype_any) {
2332 1.24 christos query_additional(qctx, mname, rdataset);
2333 1.24 christos }
2334 1.1 christos
2335 1.1 christos /*
2336 1.1 christos * Note: we only add SIGs if we've added the type they cover, so
2337 1.1 christos * we do not need to check if the SIG rdataset is already in the
2338 1.1 christos * response.
2339 1.1 christos */
2340 1.1 christos *rdatasetp = NULL;
2341 1.1 christos if (sigrdataset != NULL && dns_rdataset_isassociated(sigrdataset)) {
2342 1.1 christos /*
2343 1.1 christos * We have a signature. Add it to the response.
2344 1.1 christos */
2345 1.1 christos ISC_LIST_APPEND(mname->list, sigrdataset, link);
2346 1.1 christos *sigrdatasetp = NULL;
2347 1.1 christos }
2348 1.1 christos
2349 1.1 christos CTRACE(ISC_LOG_DEBUG(3), "query_addrrset: done");
2350 1.1 christos }
2351 1.1 christos
2352 1.1 christos /*
2353 1.1 christos * Mark the RRsets as secure. Update the cache (db) to reflect the
2354 1.1 christos * change in trust level.
2355 1.1 christos */
2356 1.1 christos static void
2357 1.1 christos mark_secure(ns_client_t *client, dns_db_t *db, dns_name_t *name,
2358 1.1 christos dns_rdata_rrsig_t *rrsig, dns_rdataset_t *rdataset,
2359 1.9 christos dns_rdataset_t *sigrdataset) {
2360 1.1 christos isc_result_t result;
2361 1.1 christos dns_dbnode_t *node = NULL;
2362 1.1 christos dns_clientinfomethods_t cm;
2363 1.1 christos dns_clientinfo_t ci;
2364 1.1 christos isc_stdtime_t now;
2365 1.1 christos
2366 1.1 christos rdataset->trust = dns_trust_secure;
2367 1.1 christos sigrdataset->trust = dns_trust_secure;
2368 1.1 christos dns_clientinfomethods_init(&cm, ns_client_sourceip);
2369 1.20 christos dns_clientinfo_init(&ci, client, NULL);
2370 1.1 christos
2371 1.1 christos /*
2372 1.1 christos * Save the updated secure state. Ignore failures.
2373 1.1 christos */
2374 1.3 christos result = dns_db_findnodeext(db, name, true, &cm, &ci, &node);
2375 1.9 christos if (result != ISC_R_SUCCESS) {
2376 1.1 christos return;
2377 1.9 christos }
2378 1.1 christos
2379 1.23 christos now = isc_stdtime_now();
2380 1.1 christos dns_rdataset_trimttl(rdataset, sigrdataset, rrsig, now,
2381 1.1 christos client->view->acceptexpired);
2382 1.1 christos
2383 1.9 christos (void)dns_db_addrdataset(db, node, NULL, client->now, rdataset, 0,
2384 1.9 christos NULL);
2385 1.9 christos (void)dns_db_addrdataset(db, node, NULL, client->now, sigrdataset, 0,
2386 1.9 christos NULL);
2387 1.1 christos dns_db_detachnode(db, &node);
2388 1.1 christos }
2389 1.1 christos
2390 1.1 christos /*
2391 1.1 christos * Find the secure key that corresponds to rrsig.
2392 1.1 christos * Note: 'keyrdataset' maintains state between successive calls,
2393 1.1 christos * there may be multiple keys with the same keyid.
2394 1.3 christos * Return false if we have exhausted all the possible keys.
2395 1.1 christos */
2396 1.3 christos static bool
2397 1.1 christos get_key(ns_client_t *client, dns_db_t *db, dns_rdata_rrsig_t *rrsig,
2398 1.9 christos dns_rdataset_t *keyrdataset, dst_key_t **keyp) {
2399 1.1 christos isc_result_t result;
2400 1.1 christos dns_dbnode_t *node = NULL;
2401 1.3 christos bool secure = false;
2402 1.1 christos dns_clientinfomethods_t cm;
2403 1.1 christos dns_clientinfo_t ci;
2404 1.1 christos
2405 1.1 christos dns_clientinfomethods_init(&cm, ns_client_sourceip);
2406 1.20 christos dns_clientinfo_init(&ci, client, NULL);
2407 1.1 christos
2408 1.1 christos if (!dns_rdataset_isassociated(keyrdataset)) {
2409 1.9 christos result = dns_db_findnodeext(db, &rrsig->signer, false, &cm, &ci,
2410 1.9 christos &node);
2411 1.9 christos if (result != ISC_R_SUCCESS) {
2412 1.23 christos return false;
2413 1.9 christos }
2414 1.1 christos
2415 1.1 christos result = dns_db_findrdataset(db, node, NULL,
2416 1.1 christos dns_rdatatype_dnskey, 0,
2417 1.1 christos client->now, keyrdataset, NULL);
2418 1.1 christos dns_db_detachnode(db, &node);
2419 1.9 christos if (result != ISC_R_SUCCESS) {
2420 1.23 christos return false;
2421 1.9 christos }
2422 1.1 christos
2423 1.9 christos if (keyrdataset->trust != dns_trust_secure) {
2424 1.23 christos return false;
2425 1.9 christos }
2426 1.1 christos
2427 1.1 christos result = dns_rdataset_first(keyrdataset);
2428 1.9 christos } else {
2429 1.1 christos result = dns_rdataset_next(keyrdataset);
2430 1.9 christos }
2431 1.1 christos
2432 1.9 christos for (; result == ISC_R_SUCCESS; result = dns_rdataset_next(keyrdataset))
2433 1.9 christos {
2434 1.1 christos dns_rdata_t rdata = DNS_RDATA_INIT;
2435 1.1 christos isc_buffer_t b;
2436 1.1 christos
2437 1.1 christos dns_rdataset_current(keyrdataset, &rdata);
2438 1.1 christos isc_buffer_init(&b, rdata.data, rdata.length);
2439 1.1 christos isc_buffer_add(&b, rdata.length);
2440 1.1 christos result = dst_key_fromdns(&rrsig->signer, rdata.rdclass, &b,
2441 1.23 christos client->manager->mctx, keyp);
2442 1.9 christos if (result != ISC_R_SUCCESS) {
2443 1.1 christos continue;
2444 1.9 christos }
2445 1.1 christos if (rrsig->algorithm == (dns_secalg_t)dst_key_alg(*keyp) &&
2446 1.1 christos rrsig->keyid == (dns_keytag_t)dst_key_id(*keyp) &&
2447 1.9 christos dst_key_iszonekey(*keyp))
2448 1.9 christos {
2449 1.3 christos secure = true;
2450 1.1 christos break;
2451 1.1 christos }
2452 1.1 christos dst_key_free(keyp);
2453 1.1 christos }
2454 1.23 christos return secure;
2455 1.1 christos }
2456 1.1 christos
2457 1.3 christos static bool
2458 1.1 christos verify(dst_key_t *key, dns_name_t *name, dns_rdataset_t *rdataset,
2459 1.9 christos dns_rdata_t *rdata, ns_client_t *client) {
2460 1.1 christos isc_result_t result;
2461 1.1 christos dns_fixedname_t fixed;
2462 1.3 christos bool ignore = false;
2463 1.1 christos
2464 1.1 christos dns_fixedname_init(&fixed);
2465 1.1 christos
2466 1.1 christos again:
2467 1.3 christos result = dns_dnssec_verify(name, rdataset, key, ignore,
2468 1.23 christos client->view->maxbits, client->manager->mctx,
2469 1.23 christos rdata, NULL);
2470 1.1 christos if (result == DNS_R_SIGEXPIRED && client->view->acceptexpired) {
2471 1.3 christos ignore = true;
2472 1.1 christos goto again;
2473 1.1 christos }
2474 1.9 christos if (result == ISC_R_SUCCESS || result == DNS_R_FROMWILDCARD) {
2475 1.23 christos return true;
2476 1.9 christos }
2477 1.23 christos return false;
2478 1.1 christos }
2479 1.1 christos
2480 1.1 christos /*
2481 1.1 christos * Validate the rdataset if possible with available records.
2482 1.1 christos */
2483 1.3 christos static bool
2484 1.1 christos validate(ns_client_t *client, dns_db_t *db, dns_name_t *name,
2485 1.9 christos dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset) {
2486 1.1 christos isc_result_t result;
2487 1.1 christos dns_rdata_t rdata = DNS_RDATA_INIT;
2488 1.1 christos dns_rdata_rrsig_t rrsig;
2489 1.1 christos dst_key_t *key = NULL;
2490 1.1 christos dns_rdataset_t keyrdataset;
2491 1.1 christos
2492 1.9 christos if (sigrdataset == NULL || !dns_rdataset_isassociated(sigrdataset)) {
2493 1.23 christos return false;
2494 1.9 christos }
2495 1.1 christos
2496 1.9 christos for (result = dns_rdataset_first(sigrdataset); result == ISC_R_SUCCESS;
2497 1.9 christos result = dns_rdataset_next(sigrdataset))
2498 1.9 christos {
2499 1.1 christos dns_rdata_reset(&rdata);
2500 1.1 christos dns_rdataset_current(sigrdataset, &rdata);
2501 1.1 christos result = dns_rdata_tostruct(&rdata, &rrsig, NULL);
2502 1.3 christos RUNTIME_CHECK(result == ISC_R_SUCCESS);
2503 1.1 christos if (!dns_resolver_algorithm_supported(client->view->resolver,
2504 1.1 christos name, rrsig.algorithm))
2505 1.9 christos {
2506 1.24 christos char txt[DNS_NAME_FORMATSIZE + 32];
2507 1.24 christos isc_buffer_t buffer;
2508 1.24 christos
2509 1.24 christos isc_buffer_init(&buffer, txt, sizeof(txt));
2510 1.24 christos dns_secalg_totext(rrsig.algorithm, &buffer);
2511 1.24 christos isc_buffer_putstr(&buffer, " ");
2512 1.24 christos dns_name_totext(name, DNS_NAME_OMITFINALDOT, &buffer);
2513 1.24 christos isc_buffer_putstr(&buffer, " (cached)");
2514 1.24 christos isc_buffer_putuint8(&buffer, 0);
2515 1.24 christos
2516 1.24 christos dns_ede_add(&client->edectx, DNS_EDE_DNSKEYALG,
2517 1.24 christos isc_buffer_base(&buffer));
2518 1.1 christos continue;
2519 1.9 christos }
2520 1.9 christos if (!dns_name_issubdomain(name, &rrsig.signer)) {
2521 1.1 christos continue;
2522 1.9 christos }
2523 1.1 christos dns_rdataset_init(&keyrdataset);
2524 1.1 christos do {
2525 1.9 christos if (!get_key(client, db, &rrsig, &keyrdataset, &key)) {
2526 1.1 christos break;
2527 1.9 christos }
2528 1.1 christos if (verify(key, name, rdataset, &rdata, client)) {
2529 1.1 christos dst_key_free(&key);
2530 1.1 christos dns_rdataset_disassociate(&keyrdataset);
2531 1.9 christos mark_secure(client, db, name, &rrsig, rdataset,
2532 1.9 christos sigrdataset);
2533 1.23 christos return true;
2534 1.1 christos }
2535 1.1 christos dst_key_free(&key);
2536 1.1 christos } while (1);
2537 1.9 christos if (dns_rdataset_isassociated(&keyrdataset)) {
2538 1.1 christos dns_rdataset_disassociate(&keyrdataset);
2539 1.9 christos }
2540 1.1 christos }
2541 1.23 christos return false;
2542 1.1 christos }
2543 1.1 christos
2544 1.1 christos static void
2545 1.1 christos fixrdataset(ns_client_t *client, dns_rdataset_t **rdataset) {
2546 1.9 christos if (*rdataset == NULL) {
2547 1.3 christos *rdataset = ns_client_newrdataset(client);
2548 1.9 christos } else if (dns_rdataset_isassociated(*rdataset)) {
2549 1.1 christos dns_rdataset_disassociate(*rdataset);
2550 1.9 christos }
2551 1.1 christos }
2552 1.1 christos
2553 1.1 christos static void
2554 1.1 christos fixfname(ns_client_t *client, dns_name_t **fname, isc_buffer_t **dbuf,
2555 1.9 christos isc_buffer_t *nbuf) {
2556 1.1 christos if (*fname == NULL) {
2557 1.3 christos *dbuf = ns_client_getnamebuf(client);
2558 1.3 christos *fname = ns_client_newname(client, *dbuf, nbuf);
2559 1.1 christos }
2560 1.1 christos }
2561 1.1 christos
2562 1.1 christos static void
2563 1.23 christos free_fresp(ns_client_t *client, dns_fetchresponse_t **frespp) {
2564 1.23 christos dns_fetchresponse_t *fresp = *frespp;
2565 1.1 christos
2566 1.23 christos CTRACE(ISC_LOG_DEBUG(3), "free_fresp");
2567 1.9 christos
2568 1.23 christos if (fresp->fetch != NULL) {
2569 1.23 christos dns_resolver_destroyfetch(&fresp->fetch);
2570 1.23 christos }
2571 1.23 christos if (fresp->node != NULL) {
2572 1.23 christos dns_db_detachnode(fresp->db, &fresp->node);
2573 1.3 christos }
2574 1.23 christos if (fresp->db != NULL) {
2575 1.23 christos dns_db_detach(&fresp->db);
2576 1.3 christos }
2577 1.23 christos if (fresp->rdataset != NULL) {
2578 1.23 christos ns_client_putrdataset(client, &fresp->rdataset);
2579 1.3 christos }
2580 1.23 christos if (fresp->sigrdataset != NULL) {
2581 1.23 christos ns_client_putrdataset(client, &fresp->sigrdataset);
2582 1.3 christos }
2583 1.23 christos
2584 1.24 christos dns_resolver_freefresp(frespp);
2585 1.23 christos }
2586 1.23 christos
2587 1.23 christos static isc_result_t
2588 1.23 christos recursionquotatype_attach(ns_client_t *client, bool soft_limit) {
2589 1.23 christos isc_statscounter_t recurscount;
2590 1.23 christos isc_result_t result;
2591 1.23 christos
2592 1.23 christos result = isc_quota_acquire(&client->manager->sctx->recursionquota);
2593 1.23 christos switch (result) {
2594 1.23 christos case ISC_R_SUCCESS:
2595 1.23 christos break;
2596 1.23 christos case ISC_R_SOFTQUOTA:
2597 1.23 christos if (soft_limit) {
2598 1.23 christos /*
2599 1.23 christos * Exceeding soft quota was allowed, so continue as if
2600 1.23 christos * 'result' was ISC_R_SUCCESS while retaining the
2601 1.23 christos * original result code.
2602 1.23 christos */
2603 1.23 christos break;
2604 1.23 christos }
2605 1.23 christos
2606 1.23 christos isc_quota_release(&client->manager->sctx->recursionquota);
2607 1.23 christos FALLTHROUGH;
2608 1.23 christos default:
2609 1.23 christos return result;
2610 1.3 christos }
2611 1.9 christos
2612 1.23 christos recurscount = ns_stats_increment(client->manager->sctx->nsstats,
2613 1.23 christos ns_statscounter_recursclients);
2614 1.23 christos
2615 1.23 christos ns_stats_update_if_greater(client->manager->sctx->nsstats,
2616 1.23 christos ns_statscounter_recurshighwater,
2617 1.23 christos recurscount + 1);
2618 1.23 christos
2619 1.23 christos return result;
2620 1.23 christos }
2621 1.23 christos
2622 1.23 christos static isc_result_t
2623 1.23 christos recursionquotatype_attach_hard(ns_client_t *client) {
2624 1.23 christos return recursionquotatype_attach(client, false);
2625 1.23 christos }
2626 1.23 christos
2627 1.23 christos static isc_result_t
2628 1.23 christos recursionquotatype_attach_soft(ns_client_t *client) {
2629 1.23 christos return recursionquotatype_attach(client, true);
2630 1.23 christos }
2631 1.23 christos
2632 1.23 christos static void
2633 1.23 christos recursionquotatype_detach(ns_client_t *client) {
2634 1.23 christos isc_quota_release(&client->manager->sctx->recursionquota);
2635 1.23 christos ns_stats_decrement(client->manager->sctx->nsstats,
2636 1.23 christos ns_statscounter_recursclients);
2637 1.23 christos }
2638 1.23 christos
2639 1.23 christos static void
2640 1.23 christos stale_refresh_aftermath(ns_client_t *client, isc_result_t result) {
2641 1.23 christos dns_db_t *db = NULL;
2642 1.23 christos unsigned int dboptions;
2643 1.23 christos isc_buffer_t buffer;
2644 1.23 christos query_ctx_t qctx;
2645 1.23 christos dns_clientinfomethods_t cm;
2646 1.23 christos dns_clientinfo_t ci;
2647 1.23 christos char namebuf[DNS_NAME_FORMATSIZE];
2648 1.23 christos char typebuf[DNS_RDATATYPE_FORMATSIZE];
2649 1.23 christos
2650 1.1 christos /*
2651 1.23 christos * If refreshing a stale RRset failed, we need to set the
2652 1.23 christos * stale-refresh-time window, so that on future requests for this
2653 1.23 christos * RRset the stale entry may be used immediately.
2654 1.1 christos */
2655 1.23 christos switch (result) {
2656 1.23 christos case ISC_R_SUCCESS:
2657 1.23 christos case DNS_R_GLUE:
2658 1.23 christos case DNS_R_ZONECUT:
2659 1.23 christos case ISC_R_NOTFOUND:
2660 1.23 christos case DNS_R_DELEGATION:
2661 1.23 christos case DNS_R_EMPTYNAME:
2662 1.23 christos case DNS_R_NXRRSET:
2663 1.23 christos case DNS_R_EMPTYWILD:
2664 1.23 christos case DNS_R_NXDOMAIN:
2665 1.23 christos case DNS_R_COVERINGNSEC:
2666 1.23 christos case DNS_R_NCACHENXDOMAIN:
2667 1.23 christos case DNS_R_NCACHENXRRSET:
2668 1.23 christos case DNS_R_CNAME:
2669 1.23 christos case DNS_R_DNAME:
2670 1.23 christos break;
2671 1.23 christos default:
2672 1.23 christos dns_name_format(client->query.qname, namebuf, sizeof(namebuf));
2673 1.23 christos dns_rdatatype_format(client->query.qtype, typebuf,
2674 1.23 christos sizeof(typebuf));
2675 1.23 christos ns_client_log(client, NS_LOGCATEGORY_SERVE_STALE,
2676 1.23 christos NS_LOGMODULE_QUERY, ISC_LOG_NOTICE,
2677 1.23 christos "%s/%s stale refresh failed: timed out", namebuf,
2678 1.23 christos typebuf);
2679 1.23 christos
2680 1.23 christos /*
2681 1.23 christos * Set up a short lived query context, solely to set the
2682 1.23 christos * last refresh failure time on the RRset in the cache
2683 1.23 christos * database, starting the stale-refresh-time window for it.
2684 1.23 christos * This is a condensed form of query_lookup().
2685 1.23 christos */
2686 1.23 christos client->now = isc_stdtime_now();
2687 1.23 christos client->query.attributes &= ~NS_QUERYATTR_RECURSIONOK;
2688 1.23 christos qctx_init(client, NULL, 0, &qctx);
2689 1.23 christos
2690 1.23 christos dns_clientinfomethods_init(&cm, ns_client_sourceip);
2691 1.23 christos dns_clientinfo_init(&ci, qctx.client, NULL);
2692 1.23 christos if (HAVEECS(qctx.client)) {
2693 1.23 christos dns_clientinfo_setecs(&ci, &qctx.client->ecs);
2694 1.23 christos }
2695 1.23 christos
2696 1.23 christos result = qctx_prepare_buffers(&qctx, &buffer);
2697 1.23 christos if (result != ISC_R_SUCCESS) {
2698 1.23 christos goto cleanup;
2699 1.23 christos }
2700 1.23 christos
2701 1.23 christos dboptions = qctx.client->query.dboptions;
2702 1.23 christos dboptions |= DNS_DBFIND_STALEOK;
2703 1.23 christos dboptions |= DNS_DBFIND_STALESTART;
2704 1.23 christos
2705 1.23 christos dns_db_attach(qctx.client->view->cachedb, &db);
2706 1.23 christos (void)dns_db_findext(db, qctx.client->query.qname, NULL,
2707 1.23 christos qctx.client->query.qtype, dboptions,
2708 1.23 christos qctx.client->now, &qctx.node, qctx.fname,
2709 1.23 christos &cm, &ci, qctx.rdataset, qctx.sigrdataset);
2710 1.23 christos if (qctx.node != NULL) {
2711 1.23 christos dns_db_detachnode(db, &qctx.node);
2712 1.23 christos }
2713 1.23 christos dns_db_detach(&db);
2714 1.23 christos
2715 1.23 christos cleanup:
2716 1.23 christos qctx_freedata(&qctx);
2717 1.23 christos qctx_destroy(&qctx);
2718 1.9 christos }
2719 1.1 christos }
2720 1.1 christos
2721 1.1 christos static void
2722 1.23 christos cleanup_after_fetch(dns_fetchresponse_t *resp, const char *ctracestr,
2723 1.23 christos ns_query_rectype_t recursion_type) {
2724 1.23 christos ns_client_t *client = resp->arg;
2725 1.23 christos isc_nmhandle_t **handlep = NULL;
2726 1.23 christos dns_fetch_t **fetchp = NULL;
2727 1.23 christos isc_result_t result;
2728 1.1 christos
2729 1.23 christos REQUIRE(NS_CLIENT_VALID(client));
2730 1.1 christos
2731 1.23 christos CTRACE(ISC_LOG_DEBUG(3), ctracestr);
2732 1.1 christos
2733 1.23 christos handlep = &client->query.recursions[recursion_type].handle;
2734 1.23 christos fetchp = &client->query.recursions[recursion_type].fetch;
2735 1.23 christos result = resp->result;
2736 1.9 christos
2737 1.1 christos LOCK(&client->query.fetchlock);
2738 1.23 christos if (*fetchp != NULL) {
2739 1.23 christos INSIST(resp->fetch == *fetchp);
2740 1.23 christos *fetchp = NULL;
2741 1.1 christos }
2742 1.1 christos UNLOCK(&client->query.fetchlock);
2743 1.9 christos
2744 1.23 christos /* Some type of recursions require a bit of aftermath. */
2745 1.23 christos if (recursion_type == RECTYPE_STALE_REFRESH) {
2746 1.23 christos stale_refresh_aftermath(client, result);
2747 1.9 christos }
2748 1.9 christos
2749 1.23 christos recursionquotatype_detach(client);
2750 1.23 christos free_fresp(client, &resp);
2751 1.23 christos isc_nmhandle_detach(handlep);
2752 1.23 christos }
2753 1.23 christos
2754 1.23 christos static void
2755 1.23 christos prefetch_done(void *arg) {
2756 1.23 christos cleanup_after_fetch(arg, "prefetch_done", RECTYPE_PREFETCH);
2757 1.1 christos }
2758 1.1 christos
2759 1.1 christos static void
2760 1.23 christos rpzfetch_done(void *arg) {
2761 1.23 christos cleanup_after_fetch(arg, "rpzfetch_done", RECTYPE_RPZ);
2762 1.23 christos }
2763 1.23 christos
2764 1.23 christos static void
2765 1.23 christos stale_refresh_done(void *arg) {
2766 1.23 christos cleanup_after_fetch(arg, "stale_refresh_done", RECTYPE_STALE_REFRESH);
2767 1.23 christos }
2768 1.23 christos
2769 1.23 christos /*
2770 1.23 christos * Try initiating a fetch for the given 'qname' and 'qtype' (using the slot in
2771 1.23 christos * the 'recursions' array indicated by 'recursion_type') that will be
2772 1.23 christos * associated with 'client'. If the recursive clients quota (or even soft
2773 1.23 christos * quota) is reached or some other error occurs, just return without starting
2774 1.23 christos * the fetch. If a fetch is successfully created, its results will be cached
2775 1.23 christos * upon successful completion, but no further actions will be taken afterwards.
2776 1.23 christos */
2777 1.23 christos static void
2778 1.23 christos fetch_and_forget(ns_client_t *client, dns_name_t *qname, dns_rdatatype_t qtype,
2779 1.23 christos ns_query_rectype_t recursion_type) {
2780 1.23 christos dns_rdataset_t *tmprdataset;
2781 1.1 christos isc_sockaddr_t *peeraddr;
2782 1.1 christos unsigned int options;
2783 1.23 christos isc_job_cb cb;
2784 1.23 christos isc_nmhandle_t **handlep;
2785 1.23 christos dns_fetch_t **fetchp;
2786 1.23 christos isc_result_t result;
2787 1.1 christos
2788 1.23 christos result = recursionquotatype_attach_hard(client);
2789 1.23 christos if (result != ISC_R_SUCCESS) {
2790 1.1 christos return;
2791 1.9 christos }
2792 1.1 christos
2793 1.3 christos tmprdataset = ns_client_newrdataset(client);
2794 1.9 christos
2795 1.9 christos if (!TCP(client)) {
2796 1.1 christos peeraddr = &client->peeraddr;
2797 1.9 christos } else {
2798 1.1 christos peeraddr = NULL;
2799 1.9 christos }
2800 1.9 christos
2801 1.23 christos switch (recursion_type) {
2802 1.23 christos case RECTYPE_PREFETCH:
2803 1.23 christos options = client->query.fetchoptions | DNS_FETCHOPT_PREFETCH;
2804 1.23 christos cb = prefetch_done;
2805 1.23 christos break;
2806 1.23 christos case RECTYPE_RPZ:
2807 1.23 christos options = client->query.fetchoptions;
2808 1.23 christos cb = rpzfetch_done;
2809 1.23 christos break;
2810 1.23 christos case RECTYPE_STALE_REFRESH:
2811 1.23 christos options = client->query.fetchoptions;
2812 1.23 christos cb = stale_refresh_done;
2813 1.23 christos break;
2814 1.23 christos default:
2815 1.23 christos UNREACHABLE();
2816 1.23 christos }
2817 1.23 christos
2818 1.23 christos handlep = &client->query.recursions[recursion_type].handle;
2819 1.23 christos fetchp = &client->query.recursions[recursion_type].fetch;
2820 1.23 christos
2821 1.23 christos isc_nmhandle_attach(client->handle, handlep);
2822 1.9 christos result = dns_resolver_createfetch(
2823 1.23 christos client->view->resolver, qname, qtype, NULL, NULL, NULL,
2824 1.23 christos peeraddr, client->message->id, options, 0, NULL,
2825 1.24 christos client->query.qc, client->manager->loop, cb, client, NULL,
2826 1.24 christos tmprdataset, NULL, fetchp);
2827 1.1 christos if (result != ISC_R_SUCCESS) {
2828 1.3 christos ns_client_putrdataset(client, &tmprdataset);
2829 1.23 christos isc_nmhandle_detach(handlep);
2830 1.23 christos recursionquotatype_detach(client);
2831 1.1 christos }
2832 1.23 christos }
2833 1.23 christos
2834 1.23 christos static void
2835 1.23 christos query_prefetch(ns_client_t *client, dns_name_t *qname,
2836 1.23 christos dns_rdataset_t *rdataset) {
2837 1.23 christos CTRACE(ISC_LOG_DEBUG(3), "query_prefetch");
2838 1.23 christos
2839 1.23 christos if (FETCH_RECTYPE_PREFETCH(client) != NULL ||
2840 1.23 christos client->view->prefetch_trigger == 0U ||
2841 1.23 christos rdataset->ttl > client->view->prefetch_trigger ||
2842 1.23 christos (rdataset->attributes & DNS_RDATASETATTR_PREFETCH) == 0)
2843 1.23 christos {
2844 1.23 christos return;
2845 1.23 christos }
2846 1.23 christos
2847 1.23 christos fetch_and_forget(client, qname, rdataset->type, RECTYPE_PREFETCH);
2848 1.9 christos
2849 1.1 christos dns_rdataset_clearprefetch(rdataset);
2850 1.23 christos ns_stats_increment(client->manager->sctx->nsstats,
2851 1.23 christos ns_statscounter_prefetch);
2852 1.23 christos }
2853 1.23 christos
2854 1.23 christos static void
2855 1.23 christos query_stale_refresh(ns_client_t *client) {
2856 1.23 christos dns_name_t *qname;
2857 1.23 christos
2858 1.23 christos CTRACE(ISC_LOG_DEBUG(3), "query_stale_refresh");
2859 1.23 christos
2860 1.23 christos if (FETCH_RECTYPE_STALE_REFRESH(client) != NULL) {
2861 1.23 christos return;
2862 1.23 christos }
2863 1.23 christos
2864 1.23 christos client->query.dboptions &= ~(DNS_DBFIND_STALETIMEOUT |
2865 1.23 christos DNS_DBFIND_STALEOK |
2866 1.23 christos DNS_DBFIND_STALEENABLED);
2867 1.23 christos
2868 1.23 christos if (client->query.origqname != NULL) {
2869 1.23 christos qname = client->query.origqname;
2870 1.23 christos } else {
2871 1.23 christos qname = client->query.qname;
2872 1.23 christos }
2873 1.23 christos
2874 1.23 christos fetch_and_forget(client, qname, client->query.qtype,
2875 1.23 christos RECTYPE_STALE_REFRESH);
2876 1.1 christos }
2877 1.1 christos
2878 1.15 christos static void
2879 1.1 christos rpz_clean(dns_zone_t **zonep, dns_db_t **dbp, dns_dbnode_t **nodep,
2880 1.9 christos dns_rdataset_t **rdatasetp) {
2881 1.1 christos if (nodep != NULL && *nodep != NULL) {
2882 1.1 christos REQUIRE(dbp != NULL && *dbp != NULL);
2883 1.1 christos dns_db_detachnode(*dbp, nodep);
2884 1.1 christos }
2885 1.9 christos if (dbp != NULL && *dbp != NULL) {
2886 1.1 christos dns_db_detach(dbp);
2887 1.9 christos }
2888 1.9 christos if (zonep != NULL && *zonep != NULL) {
2889 1.1 christos dns_zone_detach(zonep);
2890 1.9 christos }
2891 1.1 christos if (rdatasetp != NULL && *rdatasetp != NULL &&
2892 1.1 christos dns_rdataset_isassociated(*rdatasetp))
2893 1.9 christos {
2894 1.1 christos dns_rdataset_disassociate(*rdatasetp);
2895 1.9 christos }
2896 1.1 christos }
2897 1.1 christos
2898 1.15 christos static void
2899 1.1 christos rpz_match_clear(dns_rpz_st_t *st) {
2900 1.1 christos rpz_clean(&st->m.zone, &st->m.db, &st->m.node, &st->m.rdataset);
2901 1.1 christos st->m.version = NULL;
2902 1.1 christos }
2903 1.1 christos
2904 1.15 christos static isc_result_t
2905 1.1 christos rpz_ready(ns_client_t *client, dns_rdataset_t **rdatasetp) {
2906 1.1 christos REQUIRE(rdatasetp != NULL);
2907 1.1 christos
2908 1.1 christos CTRACE(ISC_LOG_DEBUG(3), "rpz_ready");
2909 1.1 christos
2910 1.1 christos if (*rdatasetp == NULL) {
2911 1.3 christos *rdatasetp = ns_client_newrdataset(client);
2912 1.1 christos } else if (dns_rdataset_isassociated(*rdatasetp)) {
2913 1.1 christos dns_rdataset_disassociate(*rdatasetp);
2914 1.1 christos }
2915 1.23 christos return ISC_R_SUCCESS;
2916 1.1 christos }
2917 1.1 christos
2918 1.1 christos static void
2919 1.1 christos rpz_st_clear(ns_client_t *client) {
2920 1.1 christos dns_rpz_st_t *st = client->query.rpz_st;
2921 1.1 christos
2922 1.1 christos CTRACE(ISC_LOG_DEBUG(3), "rpz_st_clear");
2923 1.1 christos
2924 1.1 christos if (st->m.rdataset != NULL) {
2925 1.3 christos ns_client_putrdataset(client, &st->m.rdataset);
2926 1.1 christos }
2927 1.1 christos rpz_match_clear(st);
2928 1.1 christos
2929 1.1 christos rpz_clean(NULL, &st->r.db, NULL, NULL);
2930 1.1 christos if (st->r.ns_rdataset != NULL) {
2931 1.3 christos ns_client_putrdataset(client, &st->r.ns_rdataset);
2932 1.1 christos }
2933 1.1 christos if (st->r.r_rdataset != NULL) {
2934 1.3 christos ns_client_putrdataset(client, &st->r.r_rdataset);
2935 1.1 christos }
2936 1.1 christos
2937 1.1 christos rpz_clean(&st->q.zone, &st->q.db, &st->q.node, NULL);
2938 1.1 christos if (st->q.rdataset != NULL) {
2939 1.3 christos ns_client_putrdataset(client, &st->q.rdataset);
2940 1.1 christos }
2941 1.1 christos if (st->q.sigrdataset != NULL) {
2942 1.3 christos ns_client_putrdataset(client, &st->q.sigrdataset);
2943 1.1 christos }
2944 1.1 christos st->state = 0;
2945 1.1 christos st->m.type = DNS_RPZ_TYPE_BAD;
2946 1.1 christos st->m.policy = DNS_RPZ_POLICY_MISS;
2947 1.1 christos if (st->rpsdb != NULL) {
2948 1.1 christos dns_db_detach(&st->rpsdb);
2949 1.1 christos }
2950 1.1 christos }
2951 1.1 christos
2952 1.1 christos static dns_rpz_zbits_t
2953 1.9 christos rpz_get_zbits(ns_client_t *client, dns_rdatatype_t ip_type,
2954 1.9 christos dns_rpz_type_t rpz_type) {
2955 1.1 christos dns_rpz_st_t *st;
2956 1.3 christos dns_rpz_zbits_t zbits = 0;
2957 1.1 christos
2958 1.1 christos REQUIRE(client != NULL);
2959 1.1 christos REQUIRE(client->query.rpz_st != NULL);
2960 1.1 christos
2961 1.1 christos st = client->query.rpz_st;
2962 1.1 christos
2963 1.1 christos #ifdef USE_DNSRPS
2964 1.1 christos if (st->popt.dnsrps_enabled) {
2965 1.1 christos if (st->rpsdb == NULL ||
2966 1.1 christos librpz->have_trig(dns_dnsrps_type2trig(rpz_type),
2967 1.1 christos ip_type == dns_rdatatype_aaaa,
2968 1.23 christos ((dns_rpsdb_t *)st->rpsdb)->rsp))
2969 1.1 christos {
2970 1.23 christos return DNS_RPZ_ALL_ZBITS;
2971 1.1 christos }
2972 1.23 christos return 0;
2973 1.1 christos }
2974 1.9 christos #endif /* ifdef USE_DNSRPS */
2975 1.1 christos
2976 1.1 christos switch (rpz_type) {
2977 1.1 christos case DNS_RPZ_TYPE_CLIENT_IP:
2978 1.1 christos zbits = st->have.client_ip;
2979 1.1 christos break;
2980 1.1 christos case DNS_RPZ_TYPE_QNAME:
2981 1.1 christos zbits = st->have.qname;
2982 1.1 christos break;
2983 1.1 christos case DNS_RPZ_TYPE_IP:
2984 1.1 christos if (ip_type == dns_rdatatype_a) {
2985 1.1 christos zbits = st->have.ipv4;
2986 1.1 christos } else if (ip_type == dns_rdatatype_aaaa) {
2987 1.1 christos zbits = st->have.ipv6;
2988 1.1 christos } else {
2989 1.1 christos zbits = st->have.ip;
2990 1.1 christos }
2991 1.1 christos break;
2992 1.1 christos case DNS_RPZ_TYPE_NSDNAME:
2993 1.1 christos zbits = st->have.nsdname;
2994 1.1 christos break;
2995 1.1 christos case DNS_RPZ_TYPE_NSIP:
2996 1.1 christos if (ip_type == dns_rdatatype_a) {
2997 1.1 christos zbits = st->have.nsipv4;
2998 1.1 christos } else if (ip_type == dns_rdatatype_aaaa) {
2999 1.1 christos zbits = st->have.nsipv6;
3000 1.1 christos } else {
3001 1.1 christos zbits = st->have.nsip;
3002 1.1 christos }
3003 1.1 christos break;
3004 1.1 christos default:
3005 1.15 christos UNREACHABLE();
3006 1.1 christos }
3007 1.1 christos
3008 1.1 christos /*
3009 1.1 christos * Choose
3010 1.1 christos * the earliest configured policy zone (rpz->num)
3011 1.1 christos * QNAME over IP over NSDNAME over NSIP (rpz_type)
3012 1.1 christos * the smallest name,
3013 1.1 christos * the longest IP address prefix,
3014 1.1 christos * the lexically smallest address.
3015 1.1 christos */
3016 1.1 christos if (st->m.policy != DNS_RPZ_POLICY_MISS) {
3017 1.1 christos if (st->m.type >= rpz_type) {
3018 1.1 christos zbits &= DNS_RPZ_ZMASK(st->m.rpz->num);
3019 1.9 christos } else {
3020 1.1 christos zbits &= DNS_RPZ_ZMASK(st->m.rpz->num) >> 1;
3021 1.1 christos }
3022 1.1 christos }
3023 1.1 christos
3024 1.1 christos /*
3025 1.1 christos * If the client wants recursion, allow only compatible policies.
3026 1.1 christos */
3027 1.9 christos if (!RECURSIONOK(client)) {
3028 1.1 christos zbits &= st->popt.no_rd_ok;
3029 1.9 christos }
3030 1.1 christos
3031 1.23 christos return zbits;
3032 1.1 christos }
3033 1.1 christos
3034 1.1 christos static void
3035 1.1 christos query_rpzfetch(ns_client_t *client, dns_name_t *qname, dns_rdatatype_t type) {
3036 1.9 christos CTRACE(ISC_LOG_DEBUG(3), "query_rpzfetch");
3037 1.9 christos
3038 1.23 christos if (FETCH_RECTYPE_RPZ(client) != NULL) {
3039 1.1 christos return;
3040 1.9 christos }
3041 1.9 christos
3042 1.23 christos fetch_and_forget(client, qname, type, RECTYPE_RPZ);
3043 1.1 christos }
3044 1.1 christos
3045 1.1 christos /*
3046 1.1 christos * Get an NS, A, or AAAA rrset related to the response for the client
3047 1.1 christos * to check the contents of that rrset for hits by eligible policy zones.
3048 1.1 christos */
3049 1.1 christos static isc_result_t
3050 1.1 christos rpz_rrset_find(ns_client_t *client, dns_name_t *name, dns_rdatatype_t type,
3051 1.15 christos unsigned int options, dns_rpz_type_t rpz_type, dns_db_t **dbp,
3052 1.1 christos dns_dbversion_t *version, dns_rdataset_t **rdatasetp,
3053 1.9 christos bool resuming) {
3054 1.1 christos dns_rpz_st_t *st;
3055 1.3 christos bool is_zone;
3056 1.1 christos dns_dbnode_t *node;
3057 1.1 christos dns_fixedname_t fixed;
3058 1.1 christos dns_name_t *found;
3059 1.1 christos isc_result_t result;
3060 1.1 christos dns_clientinfomethods_t cm;
3061 1.1 christos dns_clientinfo_t ci;
3062 1.1 christos
3063 1.1 christos CTRACE(ISC_LOG_DEBUG(3), "rpz_rrset_find");
3064 1.1 christos
3065 1.1 christos st = client->query.rpz_st;
3066 1.1 christos if ((st->state & DNS_RPZ_RECURSING) != 0) {
3067 1.1 christos INSIST(st->r.r_type == type);
3068 1.1 christos INSIST(dns_name_equal(name, st->r_name));
3069 1.1 christos INSIST(*rdatasetp == NULL ||
3070 1.1 christos !dns_rdataset_isassociated(*rdatasetp));
3071 1.1 christos st->state &= ~DNS_RPZ_RECURSING;
3072 1.1 christos RESTORE(*dbp, st->r.db);
3073 1.3 christos if (*rdatasetp != NULL) {
3074 1.3 christos ns_client_putrdataset(client, rdatasetp);
3075 1.3 christos }
3076 1.1 christos RESTORE(*rdatasetp, st->r.r_rdataset);
3077 1.1 christos result = st->r.r_result;
3078 1.1 christos if (result == DNS_R_DELEGATION) {
3079 1.1 christos CTRACE(ISC_LOG_ERROR, "RPZ recursing");
3080 1.1 christos rpz_log_fail(client, DNS_RPZ_ERROR_LEVEL, name,
3081 1.3 christos rpz_type, "rpz_rrset_find(1)", result);
3082 1.1 christos st->m.policy = DNS_RPZ_POLICY_ERROR;
3083 1.1 christos result = DNS_R_SERVFAIL;
3084 1.1 christos }
3085 1.23 christos return result;
3086 1.1 christos }
3087 1.1 christos
3088 1.1 christos result = rpz_ready(client, rdatasetp);
3089 1.1 christos if (result != ISC_R_SUCCESS) {
3090 1.1 christos st->m.policy = DNS_RPZ_POLICY_ERROR;
3091 1.23 christos return result;
3092 1.1 christos }
3093 1.1 christos if (*dbp != NULL) {
3094 1.3 christos is_zone = false;
3095 1.1 christos } else {
3096 1.1 christos dns_zone_t *zone;
3097 1.1 christos
3098 1.1 christos version = NULL;
3099 1.1 christos zone = NULL;
3100 1.23 christos result = query_getdb(client, name, type,
3101 1.23 christos (dns_getdb_options_t){ 0 }, &zone, dbp,
3102 1.1 christos &version, &is_zone);
3103 1.1 christos if (result != ISC_R_SUCCESS) {
3104 1.1 christos rpz_log_fail(client, DNS_RPZ_ERROR_LEVEL, name,
3105 1.3 christos rpz_type, "rpz_rrset_find(2)", result);
3106 1.1 christos st->m.policy = DNS_RPZ_POLICY_ERROR;
3107 1.9 christos if (zone != NULL) {
3108 1.1 christos dns_zone_detach(&zone);
3109 1.9 christos }
3110 1.23 christos return result;
3111 1.1 christos }
3112 1.9 christos if (zone != NULL) {
3113 1.1 christos dns_zone_detach(&zone);
3114 1.9 christos }
3115 1.1 christos }
3116 1.1 christos
3117 1.1 christos node = NULL;
3118 1.1 christos found = dns_fixedname_initname(&fixed);
3119 1.1 christos dns_clientinfomethods_init(&cm, ns_client_sourceip);
3120 1.20 christos dns_clientinfo_init(&ci, client, NULL);
3121 1.15 christos result = dns_db_findext(*dbp, name, version, type, options, client->now,
3122 1.15 christos &node, found, &cm, &ci, *rdatasetp, NULL);
3123 1.1 christos if (result == DNS_R_DELEGATION && is_zone && USECACHE(client)) {
3124 1.1 christos /*
3125 1.1 christos * Try the cache if we're authoritative for an
3126 1.1 christos * ancestor but not the domain itself.
3127 1.1 christos */
3128 1.1 christos rpz_clean(NULL, dbp, &node, rdatasetp);
3129 1.1 christos version = NULL;
3130 1.1 christos dns_db_attach(client->view->cachedb, dbp);
3131 1.9 christos result = dns_db_findext(*dbp, name, version, type, 0,
3132 1.9 christos client->now, &node, found, &cm, &ci,
3133 1.9 christos *rdatasetp, NULL);
3134 1.1 christos }
3135 1.1 christos rpz_clean(NULL, dbp, &node, NULL);
3136 1.1 christos if (result == DNS_R_DELEGATION) {
3137 1.1 christos rpz_clean(NULL, NULL, NULL, rdatasetp);
3138 1.1 christos /*
3139 1.1 christos * Recurse for NS rrset or A or AAAA rrset for an NS.
3140 1.1 christos * Do not recurse for addresses for the query name.
3141 1.1 christos */
3142 1.1 christos if (rpz_type == DNS_RPZ_TYPE_IP) {
3143 1.1 christos result = DNS_R_NXRRSET;
3144 1.20 christos } else if (!client->view->rpzs->p.nsip_wait_recurse ||
3145 1.20 christos (!client->view->rpzs->p.nsdname_wait_recurse &&
3146 1.20 christos rpz_type == DNS_RPZ_TYPE_NSDNAME))
3147 1.20 christos {
3148 1.1 christos query_rpzfetch(client, name, type);
3149 1.1 christos result = DNS_R_NXRRSET;
3150 1.1 christos } else {
3151 1.20 christos dns_name_copy(name, st->r_name);
3152 1.3 christos result = ns_query_recurse(client, type, st->r_name,
3153 1.3 christos NULL, NULL, resuming);
3154 1.1 christos if (result == ISC_R_SUCCESS) {
3155 1.1 christos st->state |= DNS_RPZ_RECURSING;
3156 1.1 christos result = DNS_R_DELEGATION;
3157 1.1 christos }
3158 1.1 christos }
3159 1.1 christos }
3160 1.23 christos return result;
3161 1.1 christos }
3162 1.1 christos
3163 1.1 christos /*
3164 1.1 christos * Compute a policy owner name, p_name, in a policy zone given the needed
3165 1.1 christos * policy type and the trigger name.
3166 1.1 christos */
3167 1.1 christos static isc_result_t
3168 1.9 christos rpz_get_p_name(ns_client_t *client, dns_name_t *p_name, dns_rpz_zone_t *rpz,
3169 1.9 christos dns_rpz_type_t rpz_type, dns_name_t *trig_name) {
3170 1.1 christos dns_offsets_t prefix_offsets;
3171 1.1 christos dns_name_t prefix, *suffix;
3172 1.1 christos unsigned int first, labels;
3173 1.1 christos isc_result_t result;
3174 1.1 christos
3175 1.1 christos CTRACE(ISC_LOG_DEBUG(3), "rpz_get_p_name");
3176 1.1 christos
3177 1.1 christos /*
3178 1.1 christos * The policy owner name consists of a suffix depending on the type
3179 1.1 christos * and policy zone and a prefix that is the longest possible string
3180 1.1 christos * from the trigger name that keesp the resulting policy owner name
3181 1.1 christos * from being too long.
3182 1.1 christos */
3183 1.1 christos switch (rpz_type) {
3184 1.1 christos case DNS_RPZ_TYPE_CLIENT_IP:
3185 1.1 christos suffix = &rpz->client_ip;
3186 1.1 christos break;
3187 1.1 christos case DNS_RPZ_TYPE_QNAME:
3188 1.1 christos suffix = &rpz->origin;
3189 1.1 christos break;
3190 1.1 christos case DNS_RPZ_TYPE_IP:
3191 1.1 christos suffix = &rpz->ip;
3192 1.1 christos break;
3193 1.1 christos case DNS_RPZ_TYPE_NSDNAME:
3194 1.1 christos suffix = &rpz->nsdname;
3195 1.1 christos break;
3196 1.1 christos case DNS_RPZ_TYPE_NSIP:
3197 1.1 christos suffix = &rpz->nsip;
3198 1.1 christos break;
3199 1.1 christos default:
3200 1.15 christos UNREACHABLE();
3201 1.1 christos }
3202 1.1 christos
3203 1.1 christos /*
3204 1.1 christos * Start with relative version of the full trigger name,
3205 1.1 christos * and trim enough allow the addition of the suffix.
3206 1.1 christos */
3207 1.1 christos dns_name_init(&prefix, prefix_offsets);
3208 1.1 christos labels = dns_name_countlabels(trig_name);
3209 1.1 christos first = 0;
3210 1.1 christos for (;;) {
3211 1.9 christos dns_name_getlabelsequence(trig_name, first, labels - first - 1,
3212 1.1 christos &prefix);
3213 1.1 christos result = dns_name_concatenate(&prefix, suffix, p_name, NULL);
3214 1.9 christos if (result == ISC_R_SUCCESS) {
3215 1.1 christos break;
3216 1.9 christos }
3217 1.1 christos INSIST(result == DNS_R_NAMETOOLONG);
3218 1.1 christos /*
3219 1.1 christos * Trim the trigger name until the combination is not too long.
3220 1.1 christos */
3221 1.9 christos if (labels - first < 2) {
3222 1.1 christos rpz_log_fail(client, DNS_RPZ_ERROR_LEVEL, suffix,
3223 1.9 christos rpz_type, "concatenate()", result);
3224 1.23 christos return ISC_R_FAILURE;
3225 1.1 christos }
3226 1.1 christos /*
3227 1.1 christos * Complain once about trimming the trigger name.
3228 1.1 christos */
3229 1.1 christos if (first == 0) {
3230 1.1 christos rpz_log_fail(client, DNS_RPZ_DEBUG_LEVEL1, suffix,
3231 1.9 christos rpz_type, "concatenate()", result);
3232 1.1 christos }
3233 1.1 christos ++first;
3234 1.1 christos }
3235 1.23 christos return ISC_R_SUCCESS;
3236 1.1 christos }
3237 1.1 christos
3238 1.1 christos /*
3239 1.1 christos * Look in policy zone rpz for a policy of rpz_type by p_name.
3240 1.1 christos * The self-name (usually the client qname or an NS name) is compared with
3241 1.1 christos * the target of a CNAME policy for the old style passthru encoding.
3242 1.1 christos * If found, the policy is recorded in *zonep, *dbp, *versionp, *nodep,
3243 1.1 christos * *rdatasetp, and *policyp.
3244 1.1 christos * The target DNS type, qtype, chooses the best rdataset for *rdatasetp.
3245 1.1 christos * The caller must decide if the found policy is most suitable, including
3246 1.1 christos * better than a previously found policy.
3247 1.1 christos * If it is best, the caller records it in client->query.rpz_st->m.
3248 1.1 christos */
3249 1.1 christos static isc_result_t
3250 1.1 christos rpz_find_p(ns_client_t *client, dns_name_t *self_name, dns_rdatatype_t qtype,
3251 1.1 christos dns_name_t *p_name, dns_rpz_zone_t *rpz, dns_rpz_type_t rpz_type,
3252 1.1 christos dns_zone_t **zonep, dns_db_t **dbp, dns_dbversion_t **versionp,
3253 1.1 christos dns_dbnode_t **nodep, dns_rdataset_t **rdatasetp,
3254 1.9 christos dns_rpz_policy_t *policyp) {
3255 1.1 christos dns_fixedname_t foundf;
3256 1.1 christos dns_name_t *found;
3257 1.1 christos isc_result_t result;
3258 1.1 christos dns_clientinfomethods_t cm;
3259 1.1 christos dns_clientinfo_t ci;
3260 1.6 christos bool found_a = false;
3261 1.1 christos
3262 1.1 christos REQUIRE(nodep != NULL);
3263 1.1 christos
3264 1.1 christos CTRACE(ISC_LOG_DEBUG(3), "rpz_find_p");
3265 1.1 christos
3266 1.1 christos dns_clientinfomethods_init(&cm, ns_client_sourceip);
3267 1.20 christos dns_clientinfo_init(&ci, client, NULL);
3268 1.1 christos
3269 1.1 christos /*
3270 1.1 christos * Try to find either a CNAME or the type of record demanded by the
3271 1.1 christos * request from the policy zone.
3272 1.1 christos */
3273 1.1 christos rpz_clean(zonep, dbp, nodep, rdatasetp);
3274 1.1 christos result = rpz_ready(client, rdatasetp);
3275 1.1 christos if (result != ISC_R_SUCCESS) {
3276 1.1 christos CTRACE(ISC_LOG_ERROR, "rpz_ready() failed");
3277 1.23 christos return DNS_R_SERVFAIL;
3278 1.1 christos }
3279 1.1 christos *versionp = NULL;
3280 1.1 christos result = rpz_getdb(client, p_name, rpz_type, zonep, dbp, versionp);
3281 1.9 christos if (result != ISC_R_SUCCESS) {
3282 1.23 christos return DNS_R_NXDOMAIN;
3283 1.9 christos }
3284 1.1 christos found = dns_fixedname_initname(&foundf);
3285 1.1 christos
3286 1.1 christos result = dns_db_findext(*dbp, p_name, *versionp, dns_rdatatype_any, 0,
3287 1.9 christos client->now, nodep, found, &cm, &ci, *rdatasetp,
3288 1.9 christos NULL);
3289 1.1 christos /*
3290 1.1 christos * Choose the best rdataset if we found something.
3291 1.1 christos */
3292 1.1 christos if (result == ISC_R_SUCCESS) {
3293 1.1 christos dns_rdatasetiter_t *rdsiter;
3294 1.1 christos
3295 1.1 christos rdsiter = NULL;
3296 1.16 christos result = dns_db_allrdatasets(*dbp, *nodep, *versionp, 0, 0,
3297 1.1 christos &rdsiter);
3298 1.1 christos if (result != ISC_R_SUCCESS) {
3299 1.1 christos rpz_log_fail(client, DNS_RPZ_ERROR_LEVEL, p_name,
3300 1.3 christos rpz_type, "allrdatasets()", result);
3301 1.1 christos CTRACE(ISC_LOG_ERROR,
3302 1.1 christos "rpz_find_p: allrdatasets failed");
3303 1.23 christos return DNS_R_SERVFAIL;
3304 1.1 christos }
3305 1.6 christos if (qtype == dns_rdatatype_aaaa &&
3306 1.16 christos !ISC_LIST_EMPTY(client->view->dns64))
3307 1.16 christos {
3308 1.6 christos for (result = dns_rdatasetiter_first(rdsiter);
3309 1.6 christos result == ISC_R_SUCCESS;
3310 1.9 christos result = dns_rdatasetiter_next(rdsiter))
3311 1.9 christos {
3312 1.6 christos dns_rdatasetiter_current(rdsiter, *rdatasetp);
3313 1.6 christos if ((*rdatasetp)->type == dns_rdatatype_a) {
3314 1.6 christos found_a = true;
3315 1.6 christos }
3316 1.6 christos dns_rdataset_disassociate(*rdatasetp);
3317 1.6 christos }
3318 1.6 christos }
3319 1.1 christos for (result = dns_rdatasetiter_first(rdsiter);
3320 1.1 christos result == ISC_R_SUCCESS;
3321 1.9 christos result = dns_rdatasetiter_next(rdsiter))
3322 1.9 christos {
3323 1.1 christos dns_rdatasetiter_current(rdsiter, *rdatasetp);
3324 1.1 christos if ((*rdatasetp)->type == dns_rdatatype_cname ||
3325 1.16 christos (*rdatasetp)->type == qtype)
3326 1.16 christos {
3327 1.1 christos break;
3328 1.9 christos }
3329 1.1 christos dns_rdataset_disassociate(*rdatasetp);
3330 1.1 christos }
3331 1.1 christos dns_rdatasetiter_destroy(&rdsiter);
3332 1.1 christos if (result != ISC_R_SUCCESS) {
3333 1.1 christos if (result != ISC_R_NOMORE) {
3334 1.1 christos rpz_log_fail(client, DNS_RPZ_ERROR_LEVEL,
3335 1.9 christos p_name, rpz_type, "rdatasetiter",
3336 1.9 christos result);
3337 1.9 christos CTRACE(ISC_LOG_ERROR, "rpz_find_p: "
3338 1.9 christos "rdatasetiter failed");
3339 1.23 christos return DNS_R_SERVFAIL;
3340 1.1 christos }
3341 1.1 christos /*
3342 1.1 christos * Ask again to get the right DNS_R_DNAME/NXRRSET/...
3343 1.1 christos * result if there is neither a CNAME nor target type.
3344 1.1 christos */
3345 1.9 christos if (dns_rdataset_isassociated(*rdatasetp)) {
3346 1.1 christos dns_rdataset_disassociate(*rdatasetp);
3347 1.9 christos }
3348 1.1 christos dns_db_detachnode(*dbp, nodep);
3349 1.1 christos
3350 1.1 christos if (qtype == dns_rdatatype_rrsig ||
3351 1.16 christos qtype == dns_rdatatype_sig)
3352 1.16 christos {
3353 1.1 christos result = DNS_R_NXRRSET;
3354 1.9 christos } else {
3355 1.1 christos result = dns_db_findext(*dbp, p_name, *versionp,
3356 1.1 christos qtype, 0, client->now,
3357 1.1 christos nodep, found, &cm, &ci,
3358 1.1 christos *rdatasetp, NULL);
3359 1.9 christos }
3360 1.1 christos }
3361 1.1 christos }
3362 1.1 christos switch (result) {
3363 1.1 christos case ISC_R_SUCCESS:
3364 1.1 christos if ((*rdatasetp)->type != dns_rdatatype_cname) {
3365 1.1 christos *policyp = DNS_RPZ_POLICY_RECORD;
3366 1.1 christos } else {
3367 1.1 christos *policyp = dns_rpz_decode_cname(rpz, *rdatasetp,
3368 1.1 christos self_name);
3369 1.1 christos if ((*policyp == DNS_RPZ_POLICY_RECORD ||
3370 1.1 christos *policyp == DNS_RPZ_POLICY_WILDCNAME) &&
3371 1.1 christos qtype != dns_rdatatype_cname &&
3372 1.1 christos qtype != dns_rdatatype_any)
3373 1.9 christos {
3374 1.23 christos return DNS_R_CNAME;
3375 1.9 christos }
3376 1.1 christos }
3377 1.23 christos return ISC_R_SUCCESS;
3378 1.1 christos case DNS_R_NXRRSET:
3379 1.6 christos if (found_a) {
3380 1.6 christos *policyp = DNS_RPZ_POLICY_DNS64;
3381 1.6 christos } else {
3382 1.6 christos *policyp = DNS_RPZ_POLICY_NODATA;
3383 1.6 christos }
3384 1.23 christos return result;
3385 1.1 christos case DNS_R_DNAME:
3386 1.9 christos /*
3387 1.9 christos * DNAME policy RRs have very few if any uses that are not
3388 1.9 christos * better served with simple wildcards. Making them work would
3389 1.9 christos * require complications to get the number of labels matched
3390 1.9 christos * in the name or the found name to the main DNS_R_DNAME case
3391 1.9 christos * in query_dname(). The domain also does not appear in the
3392 1.9 christos * summary database at the right level, so this happens only
3393 1.9 christos * with a single policy zone when we have no summary database.
3394 1.9 christos * Treat it as a miss.
3395 1.9 christos */
3396 1.1 christos case DNS_R_NXDOMAIN:
3397 1.1 christos case DNS_R_EMPTYNAME:
3398 1.23 christos return DNS_R_NXDOMAIN;
3399 1.1 christos default:
3400 1.9 christos rpz_log_fail(client, DNS_RPZ_ERROR_LEVEL, p_name, rpz_type, "",
3401 1.9 christos result);
3402 1.9 christos CTRACE(ISC_LOG_ERROR, "rpz_find_p: unexpected result");
3403 1.23 christos return DNS_R_SERVFAIL;
3404 1.1 christos }
3405 1.1 christos }
3406 1.1 christos
3407 1.1 christos static void
3408 1.1 christos rpz_save_p(dns_rpz_st_t *st, dns_rpz_zone_t *rpz, dns_rpz_type_t rpz_type,
3409 1.1 christos dns_rpz_policy_t policy, dns_name_t *p_name, dns_rpz_prefix_t prefix,
3410 1.1 christos isc_result_t result, dns_zone_t **zonep, dns_db_t **dbp,
3411 1.1 christos dns_dbnode_t **nodep, dns_rdataset_t **rdatasetp,
3412 1.9 christos dns_dbversion_t *version) {
3413 1.1 christos dns_rdataset_t *trdataset = NULL;
3414 1.1 christos
3415 1.1 christos rpz_match_clear(st);
3416 1.1 christos st->m.rpz = rpz;
3417 1.1 christos st->m.type = rpz_type;
3418 1.1 christos st->m.policy = policy;
3419 1.20 christos dns_name_copy(p_name, st->p_name);
3420 1.1 christos st->m.prefix = prefix;
3421 1.1 christos st->m.result = result;
3422 1.1 christos SAVE(st->m.zone, *zonep);
3423 1.1 christos SAVE(st->m.db, *dbp);
3424 1.1 christos SAVE(st->m.node, *nodep);
3425 1.1 christos if (*rdatasetp != NULL && dns_rdataset_isassociated(*rdatasetp)) {
3426 1.1 christos /*
3427 1.1 christos * Save the replacement rdataset from the policy
3428 1.1 christos * and make the previous replacement rdataset scratch.
3429 1.1 christos */
3430 1.1 christos SAVE(trdataset, st->m.rdataset);
3431 1.1 christos SAVE(st->m.rdataset, *rdatasetp);
3432 1.1 christos SAVE(*rdatasetp, trdataset);
3433 1.1 christos st->m.ttl = ISC_MIN(st->m.rdataset->ttl, rpz->max_policy_ttl);
3434 1.1 christos } else {
3435 1.1 christos st->m.ttl = ISC_MIN(DNS_RPZ_TTL_DEFAULT, rpz->max_policy_ttl);
3436 1.1 christos }
3437 1.1 christos SAVE(st->m.version, version);
3438 1.1 christos }
3439 1.1 christos
3440 1.1 christos #ifdef USE_DNSRPS
3441 1.1 christos /*
3442 1.1 christos * Check the results of a RPZ service interface lookup.
3443 1.1 christos * Stop after an error (<0) or not a hit on a disabled zone (0).
3444 1.1 christos * Continue after a hit on a disabled zone (>0).
3445 1.1 christos */
3446 1.1 christos static int
3447 1.23 christos dnsrps_ck(librpz_emsg_t *emsg, ns_client_t *client, dns_rpsdb_t *rpsdb,
3448 1.9 christos bool recursed) {
3449 1.1 christos isc_region_t region;
3450 1.1 christos librpz_domain_buf_t pname_buf;
3451 1.1 christos
3452 1.23 christos CTRACE(ISC_LOG_DEBUG(3), "dnsrps_ck");
3453 1.23 christos
3454 1.1 christos if (!librpz->rsp_result(emsg, &rpsdb->result, recursed, rpsdb->rsp)) {
3455 1.23 christos return -1;
3456 1.1 christos }
3457 1.1 christos
3458 1.1 christos /*
3459 1.1 christos * Forget the state from before the IP address or domain check
3460 1.1 christos * if the lookup hit nothing.
3461 1.1 christos */
3462 1.1 christos if (rpsdb->result.policy == LIBRPZ_POLICY_UNDEFINED ||
3463 1.1 christos rpsdb->result.hit_id != rpsdb->hit_id ||
3464 1.1 christos rpsdb->result.policy != LIBRPZ_POLICY_DISABLED)
3465 1.1 christos {
3466 1.1 christos if (!librpz->rsp_pop_discard(emsg, rpsdb->rsp)) {
3467 1.23 christos return -1;
3468 1.1 christos }
3469 1.23 christos return 0;
3470 1.1 christos }
3471 1.1 christos
3472 1.1 christos /*
3473 1.1 christos * Log a hit on a disabled zone.
3474 1.1 christos * Forget the zone to not try it again, and restore the pre-hit state.
3475 1.1 christos */
3476 1.1 christos if (!librpz->rsp_domain(emsg, &pname_buf, rpsdb->rsp)) {
3477 1.23 christos return -1;
3478 1.1 christos }
3479 1.1 christos region.base = pname_buf.d;
3480 1.1 christos region.length = pname_buf.size;
3481 1.1 christos dns_name_fromregion(client->query.rpz_st->p_name, ®ion);
3482 1.9 christos rpz_log_rewrite(client, true, dns_dnsrps_2policy(rpsdb->result.zpolicy),
3483 1.1 christos dns_dnsrps_trig2type(rpsdb->result.trig), NULL,
3484 1.1 christos client->query.rpz_st->p_name, NULL,
3485 1.1 christos rpsdb->result.cznum);
3486 1.1 christos
3487 1.1 christos if (!librpz->rsp_forget_zone(emsg, rpsdb->result.cznum, rpsdb->rsp) ||
3488 1.1 christos !librpz->rsp_pop(emsg, &rpsdb->result, rpsdb->rsp))
3489 1.1 christos {
3490 1.23 christos return -1;
3491 1.1 christos }
3492 1.23 christos return 1;
3493 1.1 christos }
3494 1.1 christos
3495 1.1 christos /*
3496 1.1 christos * Ready the shim database and rdataset for a DNSRPS hit.
3497 1.1 christos */
3498 1.3 christos static bool
3499 1.1 christos dnsrps_set_p(librpz_emsg_t *emsg, ns_client_t *client, dns_rpz_st_t *st,
3500 1.1 christos dns_rdatatype_t qtype, dns_rdataset_t **p_rdatasetp,
3501 1.9 christos bool recursed) {
3502 1.23 christos dns_rpsdb_t *rpsdb = NULL;
3503 1.1 christos librpz_domain_buf_t pname_buf;
3504 1.1 christos isc_region_t region;
3505 1.23 christos dns_zone_t *p_zone = NULL;
3506 1.23 christos dns_db_t *p_db = NULL;
3507 1.23 christos dns_dbnode_t *p_node = NULL;
3508 1.1 christos dns_rpz_policy_t policy;
3509 1.1 christos dns_rdatatype_t foundtype, searchtype;
3510 1.1 christos isc_result_t result;
3511 1.1 christos
3512 1.23 christos CTRACE(ISC_LOG_DEBUG(3), "dnsrps_set_p");
3513 1.23 christos
3514 1.23 christos rpsdb = (dns_rpsdb_t *)st->rpsdb;
3515 1.1 christos
3516 1.1 christos if (!librpz->rsp_result(emsg, &rpsdb->result, recursed, rpsdb->rsp)) {
3517 1.23 christos return false;
3518 1.1 christos }
3519 1.1 christos
3520 1.1 christos if (rpsdb->result.policy == LIBRPZ_POLICY_UNDEFINED) {
3521 1.23 christos return true;
3522 1.1 christos }
3523 1.1 christos
3524 1.1 christos /*
3525 1.1 christos * Give the fake or shim DNSRPS database its new origin.
3526 1.1 christos */
3527 1.1 christos if (!librpz->rsp_soa(emsg, NULL, NULL, &rpsdb->origin_buf,
3528 1.1 christos &rpsdb->result, rpsdb->rsp))
3529 1.1 christos {
3530 1.23 christos return false;
3531 1.1 christos }
3532 1.1 christos region.base = rpsdb->origin_buf.d;
3533 1.1 christos region.length = rpsdb->origin_buf.size;
3534 1.1 christos dns_name_fromregion(&rpsdb->common.origin, ®ion);
3535 1.1 christos
3536 1.1 christos if (!librpz->rsp_domain(emsg, &pname_buf, rpsdb->rsp)) {
3537 1.23 christos return false;
3538 1.1 christos }
3539 1.1 christos region.base = pname_buf.d;
3540 1.1 christos region.length = pname_buf.size;
3541 1.1 christos dns_name_fromregion(st->p_name, ®ion);
3542 1.1 christos
3543 1.23 christos result = rpz_ready(client, p_rdatasetp);
3544 1.23 christos if (result != ISC_R_SUCCESS) {
3545 1.23 christos return false;
3546 1.23 christos }
3547 1.1 christos dns_db_attach(st->rpsdb, &p_db);
3548 1.1 christos policy = dns_dnsrps_2policy(rpsdb->result.policy);
3549 1.1 christos if (policy != DNS_RPZ_POLICY_RECORD) {
3550 1.1 christos result = ISC_R_SUCCESS;
3551 1.1 christos } else if (qtype == dns_rdatatype_rrsig) {
3552 1.1 christos /*
3553 1.1 christos * dns_find_db() refuses to look for and fail to
3554 1.1 christos * find dns_rdatatype_rrsig.
3555 1.1 christos */
3556 1.1 christos result = DNS_R_NXRRSET;
3557 1.1 christos policy = DNS_RPZ_POLICY_NODATA;
3558 1.1 christos } else {
3559 1.23 christos dns_fixedname_t foundf;
3560 1.23 christos dns_name_t *found = NULL;
3561 1.23 christos
3562 1.1 christos /*
3563 1.1 christos * Get the next (and so first) RR from the policy node.
3564 1.1 christos * If it is a CNAME, then look for it regardless of the
3565 1.1 christos * query type.
3566 1.1 christos */
3567 1.1 christos if (!librpz->rsp_rr(emsg, &foundtype, NULL, NULL, NULL,
3568 1.1 christos &rpsdb->result, rpsdb->qname->ndata,
3569 1.1 christos rpsdb->qname->length, rpsdb->rsp))
3570 1.1 christos {
3571 1.23 christos return false;
3572 1.1 christos }
3573 1.23 christos
3574 1.1 christos if (foundtype == dns_rdatatype_cname) {
3575 1.1 christos searchtype = dns_rdatatype_cname;
3576 1.1 christos } else {
3577 1.1 christos searchtype = qtype;
3578 1.1 christos }
3579 1.1 christos /*
3580 1.1 christos * Get the DNSPRS imitation rdataset.
3581 1.1 christos */
3582 1.1 christos found = dns_fixedname_initname(&foundf);
3583 1.9 christos result = dns_db_find(p_db, st->p_name, NULL, searchtype, 0, 0,
3584 1.9 christos &p_node, found, *p_rdatasetp, NULL);
3585 1.1 christos
3586 1.1 christos if (result == ISC_R_SUCCESS) {
3587 1.1 christos if (searchtype == dns_rdatatype_cname &&
3588 1.16 christos qtype != dns_rdatatype_cname)
3589 1.16 christos {
3590 1.1 christos result = DNS_R_CNAME;
3591 1.1 christos }
3592 1.1 christos } else if (result == DNS_R_NXRRSET) {
3593 1.1 christos policy = DNS_RPZ_POLICY_NODATA;
3594 1.1 christos } else {
3595 1.1 christos snprintf(emsg->c, sizeof(emsg->c), "dns_db_find(): %s",
3596 1.1 christos isc_result_totext(result));
3597 1.23 christos return false;
3598 1.1 christos }
3599 1.1 christos }
3600 1.1 christos
3601 1.1 christos rpz_save_p(st, client->view->rpzs->zones[rpsdb->result.cznum],
3602 1.9 christos dns_dnsrps_trig2type(rpsdb->result.trig), policy, st->p_name,
3603 1.9 christos 0, result, &p_zone, &p_db, &p_node, p_rdatasetp, NULL);
3604 1.1 christos
3605 1.1 christos rpz_clean(NULL, NULL, NULL, p_rdatasetp);
3606 1.1 christos
3607 1.23 christos return true;
3608 1.1 christos }
3609 1.1 christos
3610 1.1 christos static isc_result_t
3611 1.1 christos dnsrps_rewrite_ip(ns_client_t *client, const isc_netaddr_t *netaddr,
3612 1.9 christos dns_rpz_type_t rpz_type, dns_rdataset_t **p_rdatasetp) {
3613 1.1 christos dns_rpz_st_t *st;
3614 1.23 christos dns_rpsdb_t *rpsdb;
3615 1.1 christos librpz_trig_t trig = LIBRPZ_TRIG_CLIENT_IP;
3616 1.3 christos bool recursed = false;
3617 1.1 christos int res;
3618 1.1 christos librpz_emsg_t emsg;
3619 1.1 christos isc_result_t result;
3620 1.1 christos
3621 1.23 christos CTRACE(ISC_LOG_DEBUG(3), "dnsrps_rewrite_ip");
3622 1.23 christos
3623 1.1 christos st = client->query.rpz_st;
3624 1.23 christos rpsdb = (dns_rpsdb_t *)st->rpsdb;
3625 1.1 christos
3626 1.1 christos result = rpz_ready(client, p_rdatasetp);
3627 1.1 christos if (result != ISC_R_SUCCESS) {
3628 1.1 christos st->m.policy = DNS_RPZ_POLICY_ERROR;
3629 1.23 christos return result;
3630 1.1 christos }
3631 1.1 christos
3632 1.1 christos switch (rpz_type) {
3633 1.1 christos case DNS_RPZ_TYPE_CLIENT_IP:
3634 1.1 christos trig = LIBRPZ_TRIG_CLIENT_IP;
3635 1.3 christos recursed = false;
3636 1.1 christos break;
3637 1.1 christos case DNS_RPZ_TYPE_IP:
3638 1.1 christos trig = LIBRPZ_TRIG_IP;
3639 1.3 christos recursed = true;
3640 1.1 christos break;
3641 1.1 christos case DNS_RPZ_TYPE_NSIP:
3642 1.1 christos trig = LIBRPZ_TRIG_NSIP;
3643 1.3 christos recursed = true;
3644 1.1 christos break;
3645 1.1 christos default:
3646 1.15 christos UNREACHABLE();
3647 1.1 christos }
3648 1.1 christos
3649 1.1 christos do {
3650 1.1 christos if (!librpz->rsp_push(&emsg, rpsdb->rsp) ||
3651 1.1 christos !librpz->ck_ip(&emsg,
3652 1.1 christos netaddr->family == AF_INET
3653 1.9 christos ? (const void *)&netaddr->type.in
3654 1.9 christos : (const void *)&netaddr->type.in6,
3655 1.1 christos netaddr->family, trig, ++rpsdb->hit_id,
3656 1.1 christos recursed, rpsdb->rsp) ||
3657 1.1 christos (res = dnsrps_ck(&emsg, client, rpsdb, recursed)) < 0)
3658 1.1 christos {
3659 1.1 christos rpz_log_fail(client, DNS_RPZ_ERROR_LEVEL, NULL,
3660 1.1 christos rpz_type, emsg.c, DNS_R_SERVFAIL);
3661 1.1 christos st->m.policy = DNS_RPZ_POLICY_ERROR;
3662 1.23 christos return DNS_R_SERVFAIL;
3663 1.1 christos }
3664 1.1 christos } while (res != 0);
3665 1.23 christos return ISC_R_SUCCESS;
3666 1.1 christos }
3667 1.1 christos
3668 1.1 christos static isc_result_t
3669 1.9 christos dnsrps_rewrite_name(ns_client_t *client, dns_name_t *trig_name, bool recursed,
3670 1.9 christos dns_rpz_type_t rpz_type, dns_rdataset_t **p_rdatasetp) {
3671 1.1 christos dns_rpz_st_t *st;
3672 1.23 christos dns_rpsdb_t *rpsdb;
3673 1.1 christos librpz_trig_t trig = LIBRPZ_TRIG_CLIENT_IP;
3674 1.1 christos isc_region_t r;
3675 1.1 christos int res;
3676 1.1 christos librpz_emsg_t emsg;
3677 1.1 christos isc_result_t result;
3678 1.1 christos
3679 1.23 christos CTRACE(ISC_LOG_DEBUG(3), "dnsrps_rewrite_name");
3680 1.23 christos
3681 1.1 christos st = client->query.rpz_st;
3682 1.23 christos rpsdb = (dns_rpsdb_t *)st->rpsdb;
3683 1.1 christos
3684 1.1 christos result = rpz_ready(client, p_rdatasetp);
3685 1.1 christos if (result != ISC_R_SUCCESS) {
3686 1.1 christos st->m.policy = DNS_RPZ_POLICY_ERROR;
3687 1.23 christos return result;
3688 1.1 christos }
3689 1.1 christos
3690 1.1 christos switch (rpz_type) {
3691 1.1 christos case DNS_RPZ_TYPE_QNAME:
3692 1.1 christos trig = LIBRPZ_TRIG_QNAME;
3693 1.1 christos break;
3694 1.1 christos case DNS_RPZ_TYPE_NSDNAME:
3695 1.1 christos trig = LIBRPZ_TRIG_NSDNAME;
3696 1.1 christos break;
3697 1.1 christos default:
3698 1.15 christos UNREACHABLE();
3699 1.1 christos }
3700 1.1 christos
3701 1.1 christos dns_name_toregion(trig_name, &r);
3702 1.1 christos do {
3703 1.1 christos if (!librpz->rsp_push(&emsg, rpsdb->rsp) ||
3704 1.9 christos !librpz->ck_domain(&emsg, r.base, r.length, trig,
3705 1.9 christos ++rpsdb->hit_id, recursed, rpsdb->rsp) ||
3706 1.1 christos (res = dnsrps_ck(&emsg, client, rpsdb, recursed)) < 0)
3707 1.1 christos {
3708 1.1 christos rpz_log_fail(client, DNS_RPZ_ERROR_LEVEL, NULL,
3709 1.1 christos rpz_type, emsg.c, DNS_R_SERVFAIL);
3710 1.1 christos st->m.policy = DNS_RPZ_POLICY_ERROR;
3711 1.23 christos return DNS_R_SERVFAIL;
3712 1.1 christos }
3713 1.1 christos } while (res != 0);
3714 1.23 christos return ISC_R_SUCCESS;
3715 1.1 christos }
3716 1.1 christos #endif /* USE_DNSRPS */
3717 1.1 christos
3718 1.1 christos /*
3719 1.1 christos * Check this address in every eligible policy zone.
3720 1.1 christos */
3721 1.1 christos static isc_result_t
3722 1.1 christos rpz_rewrite_ip(ns_client_t *client, const isc_netaddr_t *netaddr,
3723 1.1 christos dns_rdatatype_t qtype, dns_rpz_type_t rpz_type,
3724 1.9 christos dns_rpz_zbits_t zbits, dns_rdataset_t **p_rdatasetp) {
3725 1.1 christos dns_rpz_zones_t *rpzs;
3726 1.1 christos dns_rpz_st_t *st;
3727 1.1 christos dns_rpz_zone_t *rpz;
3728 1.1 christos dns_rpz_prefix_t prefix;
3729 1.1 christos dns_rpz_num_t rpz_num;
3730 1.1 christos dns_fixedname_t ip_namef, p_namef;
3731 1.1 christos dns_name_t *ip_name, *p_name;
3732 1.1 christos dns_zone_t *p_zone;
3733 1.1 christos dns_db_t *p_db;
3734 1.1 christos dns_dbversion_t *p_version;
3735 1.1 christos dns_dbnode_t *p_node;
3736 1.1 christos dns_rpz_policy_t policy;
3737 1.1 christos isc_result_t result;
3738 1.1 christos
3739 1.1 christos CTRACE(ISC_LOG_DEBUG(3), "rpz_rewrite_ip");
3740 1.1 christos
3741 1.1 christos rpzs = client->view->rpzs;
3742 1.1 christos st = client->query.rpz_st;
3743 1.1 christos #ifdef USE_DNSRPS
3744 1.1 christos if (st->popt.dnsrps_enabled) {
3745 1.23 christos return dnsrps_rewrite_ip(client, netaddr, rpz_type,
3746 1.23 christos p_rdatasetp);
3747 1.1 christos }
3748 1.9 christos #endif /* ifdef USE_DNSRPS */
3749 1.1 christos
3750 1.1 christos ip_name = dns_fixedname_initname(&ip_namef);
3751 1.1 christos
3752 1.1 christos p_zone = NULL;
3753 1.1 christos p_db = NULL;
3754 1.1 christos p_node = NULL;
3755 1.1 christos
3756 1.1 christos while (zbits != 0) {
3757 1.1 christos rpz_num = dns_rpz_find_ip(rpzs, rpz_type, zbits, netaddr,
3758 1.1 christos ip_name, &prefix);
3759 1.9 christos if (rpz_num == DNS_RPZ_INVALID_NUM) {
3760 1.1 christos break;
3761 1.9 christos }
3762 1.1 christos zbits &= (DNS_RPZ_ZMASK(rpz_num) >> 1);
3763 1.1 christos
3764 1.1 christos /*
3765 1.1 christos * Do not try applying policy zones that cannot replace a
3766 1.1 christos * previously found policy zone.
3767 1.1 christos * Stop looking if the next best choice cannot
3768 1.1 christos * replace what we already have.
3769 1.1 christos */
3770 1.1 christos rpz = rpzs->zones[rpz_num];
3771 1.1 christos if (st->m.policy != DNS_RPZ_POLICY_MISS) {
3772 1.9 christos if (st->m.rpz->num < rpz->num) {
3773 1.1 christos break;
3774 1.9 christos }
3775 1.1 christos if (st->m.rpz->num == rpz->num &&
3776 1.9 christos (st->m.type < rpz_type || st->m.prefix > prefix))
3777 1.9 christos {
3778 1.1 christos break;
3779 1.9 christos }
3780 1.1 christos }
3781 1.1 christos
3782 1.1 christos /*
3783 1.1 christos * Get the policy for a prefix at least as long
3784 1.1 christos * as the prefix of the entry we had before.
3785 1.1 christos */
3786 1.1 christos p_name = dns_fixedname_initname(&p_namef);
3787 1.1 christos result = rpz_get_p_name(client, p_name, rpz, rpz_type, ip_name);
3788 1.9 christos if (result != ISC_R_SUCCESS) {
3789 1.1 christos continue;
3790 1.9 christos }
3791 1.9 christos result = rpz_find_p(client, ip_name, qtype, p_name, rpz,
3792 1.9 christos rpz_type, &p_zone, &p_db, &p_version,
3793 1.9 christos &p_node, p_rdatasetp, &policy);
3794 1.1 christos switch (result) {
3795 1.1 christos case DNS_R_NXDOMAIN:
3796 1.1 christos /*
3797 1.1 christos * Continue after a policy record that is missing
3798 1.1 christos * contrary to the summary data. The summary
3799 1.1 christos * data can out of date during races with and among
3800 1.1 christos * policy zone updates.
3801 1.1 christos */
3802 1.9 christos CTRACE(ISC_LOG_ERROR, "rpz_rewrite_ip: mismatched "
3803 1.9 christos "summary data; "
3804 1.9 christos "continuing");
3805 1.1 christos continue;
3806 1.1 christos case DNS_R_SERVFAIL:
3807 1.1 christos rpz_clean(&p_zone, &p_db, &p_node, p_rdatasetp);
3808 1.1 christos st->m.policy = DNS_RPZ_POLICY_ERROR;
3809 1.23 christos return DNS_R_SERVFAIL;
3810 1.1 christos default:
3811 1.1 christos /*
3812 1.1 christos * Forget this policy if it is not preferable
3813 1.1 christos * to the previously found policy.
3814 1.1 christos * If this policy is not good, then stop looking
3815 1.1 christos * because none of the later policy zones would work.
3816 1.1 christos *
3817 1.1 christos * With more than one applicable policy, prefer
3818 1.1 christos * the earliest configured policy,
3819 1.1 christos * client-IP over QNAME over IP over NSDNAME over NSIP,
3820 1.1 christos * the longest prefix
3821 1.1 christos * the lexically smallest address.
3822 1.1 christos * dns_rpz_find_ip() ensures st->m.rpz->num >= rpz->num.
3823 1.1 christos * We can compare new and current p_name because
3824 1.1 christos * both are of the same type and in the same zone.
3825 1.1 christos * The tests above eliminate other reasons to
3826 1.1 christos * reject this policy. If this policy can't work,
3827 1.1 christos * then neither can later zones.
3828 1.1 christos */
3829 1.1 christos if (st->m.policy != DNS_RPZ_POLICY_MISS &&
3830 1.1 christos rpz->num == st->m.rpz->num &&
3831 1.9 christos (st->m.type == rpz_type && st->m.prefix == prefix &&
3832 1.9 christos 0 > dns_name_rdatacompare(st->p_name, p_name)))
3833 1.9 christos {
3834 1.1 christos break;
3835 1.9 christos }
3836 1.1 christos
3837 1.1 christos /*
3838 1.1 christos * Stop checking after saving an enabled hit in this
3839 1.1 christos * policy zone. The radix tree in the policy zone
3840 1.1 christos * ensures that we found the longest match.
3841 1.1 christos */
3842 1.1 christos if (rpz->policy != DNS_RPZ_POLICY_DISABLED) {
3843 1.9 christos CTRACE(ISC_LOG_DEBUG(3), "rpz_rewrite_ip: "
3844 1.9 christos "rpz_save_p");
3845 1.9 christos rpz_save_p(st, rpz, rpz_type, policy, p_name,
3846 1.9 christos prefix, result, &p_zone, &p_db,
3847 1.9 christos &p_node, p_rdatasetp, p_version);
3848 1.1 christos break;
3849 1.1 christos }
3850 1.1 christos
3851 1.1 christos /*
3852 1.1 christos * Log DNS_RPZ_POLICY_DISABLED zones
3853 1.1 christos * and try the next eligible policy zone.
3854 1.1 christos */
3855 1.9 christos rpz_log_rewrite(client, true, policy, rpz_type, p_zone,
3856 1.9 christos p_name, NULL, rpz_num);
3857 1.1 christos }
3858 1.1 christos }
3859 1.1 christos
3860 1.1 christos rpz_clean(&p_zone, &p_db, &p_node, p_rdatasetp);
3861 1.23 christos return ISC_R_SUCCESS;
3862 1.1 christos }
3863 1.1 christos
3864 1.1 christos /*
3865 1.1 christos * Check the IP addresses in the A or AAAA rrsets for name against
3866 1.1 christos * all eligible rpz_type (IP or NSIP) response policy rewrite rules.
3867 1.1 christos */
3868 1.1 christos static isc_result_t
3869 1.9 christos rpz_rewrite_ip_rrset(ns_client_t *client, dns_name_t *name,
3870 1.9 christos dns_rdatatype_t qtype, dns_rpz_type_t rpz_type,
3871 1.9 christos dns_rdatatype_t ip_type, dns_db_t **ip_dbp,
3872 1.9 christos dns_dbversion_t *ip_version, dns_rdataset_t **ip_rdatasetp,
3873 1.9 christos dns_rdataset_t **p_rdatasetp, bool resuming) {
3874 1.1 christos dns_rpz_zbits_t zbits;
3875 1.1 christos isc_netaddr_t netaddr;
3876 1.1 christos struct in_addr ina;
3877 1.1 christos struct in6_addr in6a;
3878 1.1 christos isc_result_t result;
3879 1.16 christos unsigned int options = client->query.dboptions | DNS_DBFIND_GLUEOK;
3880 1.15 christos bool done = false;
3881 1.1 christos
3882 1.1 christos CTRACE(ISC_LOG_DEBUG(3), "rpz_rewrite_ip_rrset");
3883 1.1 christos
3884 1.15 christos do {
3885 1.15 christos zbits = rpz_get_zbits(client, ip_type, rpz_type);
3886 1.15 christos if (zbits == 0) {
3887 1.23 christos return ISC_R_SUCCESS;
3888 1.15 christos }
3889 1.1 christos
3890 1.15 christos /*
3891 1.15 christos * Get the A or AAAA rdataset.
3892 1.15 christos */
3893 1.15 christos result = rpz_rrset_find(client, name, ip_type, options,
3894 1.15 christos rpz_type, ip_dbp, ip_version,
3895 1.15 christos ip_rdatasetp, resuming);
3896 1.15 christos switch (result) {
3897 1.15 christos case ISC_R_SUCCESS:
3898 1.15 christos case DNS_R_GLUE:
3899 1.15 christos case DNS_R_ZONECUT:
3900 1.15 christos break;
3901 1.15 christos case DNS_R_EMPTYNAME:
3902 1.15 christos case DNS_R_EMPTYWILD:
3903 1.15 christos case DNS_R_NXDOMAIN:
3904 1.15 christos case DNS_R_NCACHENXDOMAIN:
3905 1.15 christos case DNS_R_NXRRSET:
3906 1.15 christos case DNS_R_NCACHENXRRSET:
3907 1.15 christos case ISC_R_NOTFOUND:
3908 1.23 christos return ISC_R_SUCCESS;
3909 1.15 christos case DNS_R_DELEGATION:
3910 1.15 christos case DNS_R_DUPLICATE:
3911 1.15 christos case DNS_R_DROP:
3912 1.23 christos return result;
3913 1.15 christos case DNS_R_CNAME:
3914 1.15 christos case DNS_R_DNAME:
3915 1.15 christos rpz_log_fail(client, DNS_RPZ_DEBUG_LEVEL1, name,
3916 1.3 christos rpz_type, "NS address rewrite rrset",
3917 1.1 christos result);
3918 1.23 christos return ISC_R_SUCCESS;
3919 1.15 christos default:
3920 1.15 christos if (client->query.rpz_st->m.policy !=
3921 1.16 christos DNS_RPZ_POLICY_ERROR)
3922 1.16 christos {
3923 1.15 christos client->query.rpz_st->m.policy =
3924 1.15 christos DNS_RPZ_POLICY_ERROR;
3925 1.15 christos rpz_log_fail(client, DNS_RPZ_ERROR_LEVEL, name,
3926 1.15 christos rpz_type,
3927 1.15 christos "NS address rewrite rrset",
3928 1.15 christos result);
3929 1.15 christos }
3930 1.15 christos CTRACE(ISC_LOG_ERROR,
3931 1.15 christos "rpz_rewrite_ip_rrset: unexpected "
3932 1.15 christos "result");
3933 1.23 christos return DNS_R_SERVFAIL;
3934 1.1 christos }
3935 1.1 christos
3936 1.15 christos /*
3937 1.15 christos * If we are processing glue setup for the next loop
3938 1.15 christos * otherwise we are done.
3939 1.15 christos */
3940 1.15 christos if (result == DNS_R_GLUE) {
3941 1.16 christos options = client->query.dboptions;
3942 1.15 christos } else {
3943 1.16 christos options = client->query.dboptions | DNS_DBFIND_GLUEOK;
3944 1.15 christos done = true;
3945 1.1 christos }
3946 1.1 christos
3947 1.15 christos /*
3948 1.15 christos * Check all of the IP addresses in the rdataset.
3949 1.15 christos */
3950 1.15 christos for (result = dns_rdataset_first(*ip_rdatasetp);
3951 1.15 christos result == ISC_R_SUCCESS;
3952 1.15 christos result = dns_rdataset_next(*ip_rdatasetp))
3953 1.15 christos {
3954 1.15 christos dns_rdata_t rdata = DNS_RDATA_INIT;
3955 1.15 christos dns_rdataset_current(*ip_rdatasetp, &rdata);
3956 1.15 christos switch (rdata.type) {
3957 1.15 christos case dns_rdatatype_a:
3958 1.15 christos INSIST(rdata.length == 4);
3959 1.15 christos memmove(&ina.s_addr, rdata.data, 4);
3960 1.15 christos isc_netaddr_fromin(&netaddr, &ina);
3961 1.15 christos break;
3962 1.15 christos case dns_rdatatype_aaaa:
3963 1.15 christos INSIST(rdata.length == 16);
3964 1.15 christos memmove(in6a.s6_addr, rdata.data, 16);
3965 1.15 christos isc_netaddr_fromin6(&netaddr, &in6a);
3966 1.15 christos break;
3967 1.15 christos default:
3968 1.15 christos continue;
3969 1.15 christos }
3970 1.15 christos
3971 1.15 christos result = rpz_rewrite_ip(client, &netaddr, qtype,
3972 1.15 christos rpz_type, zbits, p_rdatasetp);
3973 1.15 christos if (result != ISC_R_SUCCESS) {
3974 1.23 christos return result;
3975 1.15 christos }
3976 1.9 christos }
3977 1.15 christos } while (!done &&
3978 1.15 christos client->query.rpz_st->m.policy == DNS_RPZ_POLICY_MISS);
3979 1.1 christos
3980 1.23 christos return ISC_R_SUCCESS;
3981 1.1 christos }
3982 1.1 christos
3983 1.1 christos /*
3984 1.1 christos * Look for IP addresses in A and AAAA rdatasets
3985 1.1 christos * that trigger all eligible IP or NSIP policy rules.
3986 1.1 christos */
3987 1.1 christos static isc_result_t
3988 1.1 christos rpz_rewrite_ip_rrsets(ns_client_t *client, dns_name_t *name,
3989 1.1 christos dns_rdatatype_t qtype, dns_rpz_type_t rpz_type,
3990 1.9 christos dns_rdataset_t **ip_rdatasetp, bool resuming) {
3991 1.1 christos dns_rpz_st_t *st;
3992 1.1 christos dns_dbversion_t *ip_version;
3993 1.1 christos dns_db_t *ip_db;
3994 1.1 christos dns_rdataset_t *p_rdataset;
3995 1.1 christos isc_result_t result;
3996 1.1 christos
3997 1.1 christos CTRACE(ISC_LOG_DEBUG(3), "rpz_rewrite_ip_rrsets");
3998 1.1 christos
3999 1.1 christos st = client->query.rpz_st;
4000 1.1 christos ip_version = NULL;
4001 1.1 christos ip_db = NULL;
4002 1.1 christos p_rdataset = NULL;
4003 1.1 christos if ((st->state & DNS_RPZ_DONE_IPv4) == 0 &&
4004 1.9 christos (qtype == dns_rdatatype_a || qtype == dns_rdatatype_any ||
4005 1.9 christos rpz_type == DNS_RPZ_TYPE_NSIP))
4006 1.9 christos {
4007 1.1 christos /*
4008 1.1 christos * Rewrite based on an IPv4 address that will appear
4009 1.1 christos * in the ANSWER section or if we are checking IP addresses.
4010 1.1 christos */
4011 1.9 christos result = rpz_rewrite_ip_rrset(
4012 1.9 christos client, name, qtype, rpz_type, dns_rdatatype_a, &ip_db,
4013 1.9 christos ip_version, ip_rdatasetp, &p_rdataset, resuming);
4014 1.9 christos if (result == ISC_R_SUCCESS) {
4015 1.1 christos st->state |= DNS_RPZ_DONE_IPv4;
4016 1.9 christos }
4017 1.1 christos } else {
4018 1.1 christos result = ISC_R_SUCCESS;
4019 1.1 christos }
4020 1.1 christos if (result == ISC_R_SUCCESS &&
4021 1.9 christos (qtype == dns_rdatatype_aaaa || qtype == dns_rdatatype_any ||
4022 1.9 christos rpz_type == DNS_RPZ_TYPE_NSIP))
4023 1.9 christos {
4024 1.1 christos /*
4025 1.1 christos * Rewrite based on IPv6 addresses that will appear
4026 1.1 christos * in the ANSWER section or if we are checking IP addresses.
4027 1.1 christos */
4028 1.9 christos result = rpz_rewrite_ip_rrset(client, name, qtype, rpz_type,
4029 1.9 christos dns_rdatatype_aaaa, &ip_db,
4030 1.9 christos ip_version, ip_rdatasetp,
4031 1.1 christos &p_rdataset, resuming);
4032 1.1 christos }
4033 1.9 christos if (ip_db != NULL) {
4034 1.1 christos dns_db_detach(&ip_db);
4035 1.9 christos }
4036 1.3 christos ns_client_putrdataset(client, &p_rdataset);
4037 1.23 christos return result;
4038 1.1 christos }
4039 1.1 christos
4040 1.1 christos /*
4041 1.1 christos * Try to rewrite a request for a qtype rdataset based on the trigger name
4042 1.1 christos * trig_name and rpz_type (DNS_RPZ_TYPE_QNAME or DNS_RPZ_TYPE_NSDNAME).
4043 1.1 christos * Record the results including the replacement rdataset if any
4044 1.1 christos * in client->query.rpz_st.
4045 1.1 christos * *rdatasetp is a scratch rdataset.
4046 1.1 christos */
4047 1.1 christos static isc_result_t
4048 1.1 christos rpz_rewrite_name(ns_client_t *client, dns_name_t *trig_name,
4049 1.1 christos dns_rdatatype_t qtype, dns_rpz_type_t rpz_type,
4050 1.3 christos dns_rpz_zbits_t allowed_zbits, bool recursed,
4051 1.9 christos dns_rdataset_t **rdatasetp) {
4052 1.1 christos dns_rpz_zones_t *rpzs;
4053 1.1 christos dns_rpz_zone_t *rpz;
4054 1.1 christos dns_rpz_st_t *st;
4055 1.1 christos dns_fixedname_t p_namef;
4056 1.1 christos dns_name_t *p_name;
4057 1.1 christos dns_rpz_zbits_t zbits;
4058 1.1 christos dns_rpz_num_t rpz_num;
4059 1.1 christos dns_zone_t *p_zone;
4060 1.1 christos dns_db_t *p_db;
4061 1.1 christos dns_dbversion_t *p_version;
4062 1.1 christos dns_dbnode_t *p_node;
4063 1.1 christos dns_rpz_policy_t policy;
4064 1.1 christos isc_result_t result;
4065 1.1 christos
4066 1.1 christos #ifndef USE_DNSRPS
4067 1.1 christos UNUSED(recursed);
4068 1.9 christos #endif /* ifndef USE_DNSRPS */
4069 1.1 christos
4070 1.1 christos CTRACE(ISC_LOG_DEBUG(3), "rpz_rewrite_name");
4071 1.1 christos
4072 1.1 christos rpzs = client->view->rpzs;
4073 1.1 christos st = client->query.rpz_st;
4074 1.1 christos
4075 1.1 christos #ifdef USE_DNSRPS
4076 1.1 christos if (st->popt.dnsrps_enabled) {
4077 1.23 christos return dnsrps_rewrite_name(client, trig_name, recursed,
4078 1.23 christos rpz_type, rdatasetp);
4079 1.1 christos }
4080 1.9 christos #endif /* ifdef USE_DNSRPS */
4081 1.1 christos
4082 1.1 christos zbits = rpz_get_zbits(client, qtype, rpz_type);
4083 1.1 christos zbits &= allowed_zbits;
4084 1.9 christos if (zbits == 0) {
4085 1.23 christos return ISC_R_SUCCESS;
4086 1.9 christos }
4087 1.1 christos
4088 1.1 christos /*
4089 1.1 christos * Use the summary database to find the bit mask of policy zones
4090 1.1 christos * with policies for this trigger name. We do this even if there
4091 1.1 christos * is only one eligible policy zone so that wildcard triggers
4092 1.1 christos * are matched correctly, and not into their parent.
4093 1.1 christos */
4094 1.1 christos zbits = dns_rpz_find_name(rpzs, rpz_type, zbits, trig_name);
4095 1.9 christos if (zbits == 0) {
4096 1.23 christos return ISC_R_SUCCESS;
4097 1.9 christos }
4098 1.1 christos
4099 1.1 christos p_name = dns_fixedname_initname(&p_namef);
4100 1.1 christos
4101 1.1 christos p_zone = NULL;
4102 1.1 christos p_db = NULL;
4103 1.1 christos p_node = NULL;
4104 1.1 christos
4105 1.1 christos /*
4106 1.1 christos * Check the trigger name in every policy zone that the summary data
4107 1.1 christos * says has a hit for the trigger name.
4108 1.1 christos * Most of the time there are no eligible zones and the summary data
4109 1.1 christos * keeps us from getting this far.
4110 1.1 christos * We check the most eligible zone first and so usually check only
4111 1.1 christos * one policy zone.
4112 1.1 christos */
4113 1.1 christos for (rpz_num = 0; zbits != 0; ++rpz_num, zbits >>= 1) {
4114 1.9 christos if ((zbits & 1) == 0) {
4115 1.1 christos continue;
4116 1.9 christos }
4117 1.1 christos
4118 1.1 christos /*
4119 1.1 christos * Do not check policy zones that cannot replace a previously
4120 1.1 christos * found policy.
4121 1.1 christos */
4122 1.1 christos rpz = rpzs->zones[rpz_num];
4123 1.1 christos if (st->m.policy != DNS_RPZ_POLICY_MISS) {
4124 1.9 christos if (st->m.rpz->num < rpz->num) {
4125 1.1 christos break;
4126 1.9 christos }
4127 1.9 christos if (st->m.rpz->num == rpz->num && st->m.type < rpz_type)
4128 1.9 christos {
4129 1.1 christos break;
4130 1.9 christos }
4131 1.1 christos }
4132 1.1 christos
4133 1.1 christos /*
4134 1.1 christos * Get the next policy zone's record for this trigger name.
4135 1.1 christos */
4136 1.1 christos result = rpz_get_p_name(client, p_name, rpz, rpz_type,
4137 1.1 christos trig_name);
4138 1.9 christos if (result != ISC_R_SUCCESS) {
4139 1.1 christos continue;
4140 1.9 christos }
4141 1.9 christos result = rpz_find_p(client, trig_name, qtype, p_name, rpz,
4142 1.9 christos rpz_type, &p_zone, &p_db, &p_version,
4143 1.9 christos &p_node, rdatasetp, &policy);
4144 1.1 christos switch (result) {
4145 1.1 christos case DNS_R_NXDOMAIN:
4146 1.1 christos /*
4147 1.1 christos * Continue after a missing policy record
4148 1.1 christos * contrary to the summary data. The summary
4149 1.1 christos * data can out of date during races with and among
4150 1.1 christos * policy zone updates.
4151 1.1 christos */
4152 1.9 christos CTRACE(ISC_LOG_ERROR, "rpz_rewrite_name: mismatched "
4153 1.9 christos "summary data; "
4154 1.9 christos "continuing");
4155 1.1 christos continue;
4156 1.1 christos case DNS_R_SERVFAIL:
4157 1.1 christos rpz_clean(&p_zone, &p_db, &p_node, rdatasetp);
4158 1.1 christos st->m.policy = DNS_RPZ_POLICY_ERROR;
4159 1.23 christos return DNS_R_SERVFAIL;
4160 1.1 christos default:
4161 1.1 christos /*
4162 1.1 christos * With more than one applicable policy, prefer
4163 1.1 christos * the earliest configured policy,
4164 1.1 christos * client-IP over QNAME over IP over NSDNAME over NSIP,
4165 1.1 christos * and the smallest name.
4166 1.1 christos * We known st->m.rpz->num >= rpz->num and either
4167 1.1 christos * st->m.rpz->num > rpz->num or st->m.type >= rpz_type
4168 1.1 christos */
4169 1.1 christos if (st->m.policy != DNS_RPZ_POLICY_MISS &&
4170 1.1 christos rpz->num == st->m.rpz->num &&
4171 1.1 christos (st->m.type < rpz_type ||
4172 1.1 christos (st->m.type == rpz_type &&
4173 1.1 christos 0 >= dns_name_compare(p_name, st->p_name))))
4174 1.9 christos {
4175 1.1 christos continue;
4176 1.9 christos }
4177 1.4 christos
4178 1.1 christos if (rpz->policy != DNS_RPZ_POLICY_DISABLED) {
4179 1.9 christos CTRACE(ISC_LOG_DEBUG(3), "rpz_rewrite_name: "
4180 1.9 christos "rpz_save_p");
4181 1.9 christos rpz_save_p(st, rpz, rpz_type, policy, p_name, 0,
4182 1.9 christos result, &p_zone, &p_db, &p_node,
4183 1.1 christos rdatasetp, p_version);
4184 1.1 christos /*
4185 1.1 christos * After a hit, higher numbered policy zones
4186 1.1 christos * are irrelevant
4187 1.1 christos */
4188 1.1 christos rpz_clean(&p_zone, &p_db, &p_node, rdatasetp);
4189 1.23 christos return ISC_R_SUCCESS;
4190 1.1 christos }
4191 1.1 christos /*
4192 1.1 christos * Log DNS_RPZ_POLICY_DISABLED zones
4193 1.1 christos * and try the next eligible policy zone.
4194 1.1 christos */
4195 1.9 christos rpz_log_rewrite(client, true, policy, rpz_type, p_zone,
4196 1.9 christos p_name, NULL, rpz_num);
4197 1.1 christos break;
4198 1.1 christos }
4199 1.1 christos }
4200 1.1 christos
4201 1.1 christos rpz_clean(&p_zone, &p_db, &p_node, rdatasetp);
4202 1.23 christos return ISC_R_SUCCESS;
4203 1.1 christos }
4204 1.1 christos
4205 1.1 christos static void
4206 1.1 christos rpz_rewrite_ns_skip(ns_client_t *client, dns_name_t *nsname,
4207 1.9 christos isc_result_t result, int level, const char *str) {
4208 1.1 christos dns_rpz_st_t *st;
4209 1.1 christos
4210 1.1 christos CTRACE(ISC_LOG_DEBUG(3), "rpz_rewrite_ns_skip");
4211 1.1 christos
4212 1.1 christos st = client->query.rpz_st;
4213 1.1 christos
4214 1.9 christos if (str != NULL) {
4215 1.9 christos rpz_log_fail_helper(client, level, nsname, DNS_RPZ_TYPE_NSIP,
4216 1.9 christos DNS_RPZ_TYPE_NSDNAME, str, result);
4217 1.9 christos }
4218 1.1 christos if (st->r.ns_rdataset != NULL &&
4219 1.16 christos dns_rdataset_isassociated(st->r.ns_rdataset))
4220 1.16 christos {
4221 1.1 christos dns_rdataset_disassociate(st->r.ns_rdataset);
4222 1.9 christos }
4223 1.1 christos
4224 1.1 christos st->r.label--;
4225 1.1 christos }
4226 1.1 christos
4227 1.1 christos /*
4228 1.1 christos * RPZ query result types
4229 1.1 christos */
4230 1.1 christos typedef enum {
4231 1.1 christos qresult_type_done = 0,
4232 1.1 christos qresult_type_restart = 1,
4233 1.1 christos qresult_type_recurse = 2
4234 1.1 christos } qresult_type_t;
4235 1.1 christos
4236 1.1 christos /*
4237 1.1 christos * Look for response policy zone QNAME, NSIP, and NSDNAME rewriting.
4238 1.1 christos */
4239 1.1 christos static isc_result_t
4240 1.9 christos rpz_rewrite(ns_client_t *client, dns_rdatatype_t qtype, isc_result_t qresult,
4241 1.9 christos bool resuming, dns_rdataset_t *ordataset, dns_rdataset_t *osigset) {
4242 1.1 christos dns_rpz_zones_t *rpzs;
4243 1.1 christos dns_rpz_st_t *st;
4244 1.1 christos dns_rdataset_t *rdataset;
4245 1.1 christos dns_fixedname_t nsnamef;
4246 1.1 christos dns_name_t *nsname;
4247 1.1 christos qresult_type_t qresult_type;
4248 1.1 christos dns_rpz_zbits_t zbits;
4249 1.1 christos isc_result_t result = ISC_R_SUCCESS;
4250 1.1 christos dns_rpz_have_t have;
4251 1.1 christos dns_rpz_popt_t popt;
4252 1.1 christos int rpz_ver;
4253 1.15 christos unsigned int options;
4254 1.1 christos #ifdef USE_DNSRPS
4255 1.1 christos librpz_emsg_t emsg;
4256 1.9 christos #endif /* ifdef USE_DNSRPS */
4257 1.1 christos
4258 1.1 christos CTRACE(ISC_LOG_DEBUG(3), "rpz_rewrite");
4259 1.1 christos
4260 1.1 christos rpzs = client->view->rpzs;
4261 1.1 christos st = client->query.rpz_st;
4262 1.1 christos
4263 1.13 christos if (rpzs == NULL) {
4264 1.23 christos return ISC_R_NOTFOUND;
4265 1.13 christos }
4266 1.13 christos if (st != NULL && (st->state & DNS_RPZ_REWRITTEN) != 0) {
4267 1.23 christos return DNS_R_DISALLOWED;
4268 1.13 christos }
4269 1.13 christos if (RECURSING(client)) {
4270 1.23 christos return DNS_R_DISALLOWED;
4271 1.9 christos }
4272 1.1 christos
4273 1.1 christos RWLOCK(&rpzs->search_lock, isc_rwlocktype_read);
4274 1.1 christos if ((rpzs->p.num_zones == 0 && !rpzs->p.dnsrps_enabled) ||
4275 1.1 christos (!RECURSIONOK(client) && rpzs->p.no_rd_ok == 0) ||
4276 1.1 christos !rpz_ck_dnssec(client, qresult, ordataset, osigset))
4277 1.1 christos {
4278 1.1 christos RWUNLOCK(&rpzs->search_lock, isc_rwlocktype_read);
4279 1.23 christos return DNS_R_DISALLOWED;
4280 1.1 christos }
4281 1.1 christos have = rpzs->have;
4282 1.1 christos popt = rpzs->p;
4283 1.1 christos rpz_ver = rpzs->rpz_ver;
4284 1.1 christos RWUNLOCK(&rpzs->search_lock, isc_rwlocktype_read);
4285 1.1 christos
4286 1.1 christos #ifndef USE_DNSRPS
4287 1.1 christos INSIST(!popt.dnsrps_enabled);
4288 1.9 christos #endif /* ifndef USE_DNSRPS */
4289 1.1 christos
4290 1.1 christos if (st == NULL) {
4291 1.23 christos st = isc_mem_get(client->manager->mctx, sizeof(*st));
4292 1.1 christos st->state = 0;
4293 1.1 christos st->rpsdb = NULL;
4294 1.1 christos }
4295 1.1 christos if (st->state == 0) {
4296 1.1 christos st->state |= DNS_RPZ_ACTIVE;
4297 1.1 christos memset(&st->m, 0, sizeof(st->m));
4298 1.1 christos st->m.type = DNS_RPZ_TYPE_BAD;
4299 1.1 christos st->m.policy = DNS_RPZ_POLICY_MISS;
4300 1.1 christos st->m.ttl = ~0;
4301 1.1 christos memset(&st->r, 0, sizeof(st->r));
4302 1.1 christos memset(&st->q, 0, sizeof(st->q));
4303 1.1 christos st->p_name = dns_fixedname_initname(&st->_p_namef);
4304 1.1 christos st->r_name = dns_fixedname_initname(&st->_r_namef);
4305 1.1 christos st->fname = dns_fixedname_initname(&st->_fnamef);
4306 1.1 christos st->have = have;
4307 1.1 christos st->popt = popt;
4308 1.1 christos st->rpz_ver = rpz_ver;
4309 1.1 christos client->query.rpz_st = st;
4310 1.1 christos #ifdef USE_DNSRPS
4311 1.1 christos if (popt.dnsrps_enabled) {
4312 1.1 christos if (st->rpsdb != NULL) {
4313 1.1 christos dns_db_detach(&st->rpsdb);
4314 1.1 christos }
4315 1.23 christos CTRACE(ISC_LOG_DEBUG(3), "dns_dnsrps_rewrite_init");
4316 1.9 christos result = dns_dnsrps_rewrite_init(
4317 1.9 christos &emsg, st, rpzs, client->query.qname,
4318 1.23 christos client->manager->mctx, RECURSIONOK(client));
4319 1.1 christos if (result != ISC_R_SUCCESS) {
4320 1.9 christos rpz_log_fail(client, DNS_RPZ_ERROR_LEVEL, NULL,
4321 1.9 christos DNS_RPZ_TYPE_QNAME, emsg.c,
4322 1.9 christos result);
4323 1.1 christos st->m.policy = DNS_RPZ_POLICY_ERROR;
4324 1.23 christos return ISC_R_SUCCESS;
4325 1.1 christos }
4326 1.1 christos }
4327 1.9 christos #endif /* ifdef USE_DNSRPS */
4328 1.1 christos }
4329 1.1 christos
4330 1.1 christos /*
4331 1.1 christos * There is nothing to rewrite if the main query failed.
4332 1.1 christos */
4333 1.1 christos switch (qresult) {
4334 1.1 christos case ISC_R_SUCCESS:
4335 1.1 christos case DNS_R_GLUE:
4336 1.1 christos case DNS_R_ZONECUT:
4337 1.1 christos qresult_type = qresult_type_done;
4338 1.1 christos break;
4339 1.1 christos case DNS_R_EMPTYNAME:
4340 1.1 christos case DNS_R_NXRRSET:
4341 1.1 christos case DNS_R_NXDOMAIN:
4342 1.1 christos case DNS_R_EMPTYWILD:
4343 1.1 christos case DNS_R_NCACHENXDOMAIN:
4344 1.1 christos case DNS_R_NCACHENXRRSET:
4345 1.3 christos case DNS_R_COVERINGNSEC:
4346 1.1 christos case DNS_R_CNAME:
4347 1.1 christos case DNS_R_DNAME:
4348 1.1 christos qresult_type = qresult_type_restart;
4349 1.1 christos break;
4350 1.1 christos case DNS_R_DELEGATION:
4351 1.1 christos case ISC_R_NOTFOUND:
4352 1.1 christos /*
4353 1.1 christos * If recursion is on, do only tentative rewriting.
4354 1.1 christos * If recursion is off, this the normal and only time we
4355 1.1 christos * can rewrite.
4356 1.1 christos */
4357 1.9 christos if (RECURSIONOK(client)) {
4358 1.1 christos qresult_type = qresult_type_recurse;
4359 1.9 christos } else {
4360 1.1 christos qresult_type = qresult_type_restart;
4361 1.9 christos }
4362 1.1 christos break;
4363 1.1 christos case ISC_R_FAILURE:
4364 1.1 christos case ISC_R_TIMEDOUT:
4365 1.22 christos case ISC_R_CANCELED:
4366 1.1 christos case DNS_R_BROKENCHAIN:
4367 1.1 christos rpz_log_fail(client, DNS_RPZ_DEBUG_LEVEL3, NULL,
4368 1.1 christos DNS_RPZ_TYPE_QNAME,
4369 1.3 christos "stop on qresult in rpz_rewrite()", qresult);
4370 1.23 christos return ISC_R_SUCCESS;
4371 1.1 christos default:
4372 1.1 christos rpz_log_fail(client, DNS_RPZ_DEBUG_LEVEL1, NULL,
4373 1.1 christos DNS_RPZ_TYPE_QNAME,
4374 1.3 christos "stop on unrecognized qresult in rpz_rewrite()",
4375 1.1 christos qresult);
4376 1.23 christos return ISC_R_SUCCESS;
4377 1.1 christos }
4378 1.1 christos
4379 1.1 christos rdataset = NULL;
4380 1.1 christos
4381 1.1 christos if ((st->state & (DNS_RPZ_DONE_CLIENT_IP | DNS_RPZ_DONE_QNAME)) !=
4382 1.1 christos (DNS_RPZ_DONE_CLIENT_IP | DNS_RPZ_DONE_QNAME))
4383 1.1 christos {
4384 1.1 christos isc_netaddr_t netaddr;
4385 1.1 christos dns_rpz_zbits_t allowed;
4386 1.1 christos
4387 1.1 christos if (!st->popt.dnsrps_enabled &&
4388 1.16 christos qresult_type == qresult_type_recurse)
4389 1.16 christos {
4390 1.1 christos /*
4391 1.1 christos * This request needs recursion that has not been done.
4392 1.1 christos * Get bits for the policy zones that do not need
4393 1.1 christos * to wait for the results of recursion.
4394 1.1 christos */
4395 1.1 christos allowed = st->have.qname_skip_recurse;
4396 1.1 christos if (allowed == 0) {
4397 1.23 christos return ISC_R_SUCCESS;
4398 1.1 christos }
4399 1.1 christos } else {
4400 1.1 christos allowed = DNS_RPZ_ALL_ZBITS;
4401 1.1 christos }
4402 1.1 christos
4403 1.1 christos /*
4404 1.1 christos * Check once for triggers for the client IP address.
4405 1.1 christos */
4406 1.1 christos if ((st->state & DNS_RPZ_DONE_CLIENT_IP) == 0) {
4407 1.1 christos zbits = rpz_get_zbits(client, dns_rdatatype_none,
4408 1.1 christos DNS_RPZ_TYPE_CLIENT_IP);
4409 1.1 christos zbits &= allowed;
4410 1.1 christos if (zbits != 0) {
4411 1.1 christos isc_netaddr_fromsockaddr(&netaddr,
4412 1.1 christos &client->peeraddr);
4413 1.1 christos result = rpz_rewrite_ip(client, &netaddr, qtype,
4414 1.1 christos DNS_RPZ_TYPE_CLIENT_IP,
4415 1.1 christos zbits, &rdataset);
4416 1.9 christos if (result != ISC_R_SUCCESS) {
4417 1.1 christos goto cleanup;
4418 1.9 christos }
4419 1.1 christos }
4420 1.1 christos }
4421 1.1 christos
4422 1.1 christos /*
4423 1.1 christos * Check triggers for the query name if this is the first time
4424 1.1 christos * for the current qname.
4425 1.1 christos * There is a first time for each name in a CNAME chain
4426 1.1 christos */
4427 1.1 christos if ((st->state & DNS_RPZ_DONE_QNAME) == 0) {
4428 1.3 christos bool norec = (qresult_type != qresult_type_recurse);
4429 1.1 christos result = rpz_rewrite_name(client, client->query.qname,
4430 1.1 christos qtype, DNS_RPZ_TYPE_QNAME,
4431 1.9 christos allowed, norec, &rdataset);
4432 1.9 christos if (result != ISC_R_SUCCESS) {
4433 1.1 christos goto cleanup;
4434 1.9 christos }
4435 1.1 christos
4436 1.1 christos /*
4437 1.1 christos * Check IPv4 addresses in A RRs next.
4438 1.1 christos * Reset to the start of the NS names.
4439 1.1 christos */
4440 1.1 christos st->r.label = dns_name_countlabels(client->query.qname);
4441 1.1 christos st->state &= ~(DNS_RPZ_DONE_QNAME_IP |
4442 1.1 christos DNS_RPZ_DONE_IPv4);
4443 1.1 christos }
4444 1.1 christos
4445 1.1 christos /*
4446 1.1 christos * Quit if this was an attempt to find a qname or
4447 1.1 christos * client-IP trigger before recursion.
4448 1.1 christos * We will be back if no pre-recursion triggers hit.
4449 1.1 christos * For example, consider 2 policy zones, both with qname and
4450 1.1 christos * IP address triggers. If the qname misses the 1st zone,
4451 1.1 christos * then we cannot know whether a hit for the qname in the
4452 1.1 christos * 2nd zone matters until after recursing to get the A RRs and
4453 1.1 christos * testing them in the first zone.
4454 1.1 christos * Do not bother saving the work from this attempt,
4455 1.9 christos * because recursion is so slow.
4456 1.1 christos */
4457 1.9 christos if (qresult_type == qresult_type_recurse) {
4458 1.1 christos goto cleanup;
4459 1.9 christos }
4460 1.1 christos
4461 1.1 christos /*
4462 1.1 christos * DNS_RPZ_DONE_QNAME but not DNS_RPZ_DONE_CLIENT_IP
4463 1.1 christos * is reset at the end of dealing with each CNAME.
4464 1.1 christos */
4465 1.1 christos st->state |= (DNS_RPZ_DONE_CLIENT_IP | DNS_RPZ_DONE_QNAME);
4466 1.1 christos }
4467 1.1 christos
4468 1.1 christos /*
4469 1.1 christos * Check known IP addresses for the query name if the database lookup
4470 1.1 christos * resulted in some addresses (qresult_type == qresult_type_done)
4471 1.1 christos * and if we have not already checked them.
4472 1.1 christos * Any recursion required for the query has already happened.
4473 1.1 christos * Do not check addresses that will not be in the ANSWER section.
4474 1.1 christos */
4475 1.1 christos if ((st->state & DNS_RPZ_DONE_QNAME_IP) == 0 &&
4476 1.1 christos qresult_type == qresult_type_done &&
4477 1.9 christos rpz_get_zbits(client, qtype, DNS_RPZ_TYPE_IP) != 0)
4478 1.9 christos {
4479 1.9 christos result = rpz_rewrite_ip_rrsets(client, client->query.qname,
4480 1.9 christos qtype, DNS_RPZ_TYPE_IP,
4481 1.1 christos &rdataset, resuming);
4482 1.9 christos if (result != ISC_R_SUCCESS) {
4483 1.1 christos goto cleanup;
4484 1.9 christos }
4485 1.1 christos /*
4486 1.1 christos * We are finished checking the IP addresses for the qname.
4487 1.9 christos * Start with IPv4 if we will check NS IP addresses.
4488 1.1 christos */
4489 1.1 christos st->state |= DNS_RPZ_DONE_QNAME_IP;
4490 1.1 christos st->state &= ~DNS_RPZ_DONE_IPv4;
4491 1.1 christos }
4492 1.1 christos
4493 1.1 christos /*
4494 1.1 christos * Stop looking for rules if there are none of the other kinds
4495 1.1 christos * that could override what we already have.
4496 1.1 christos */
4497 1.9 christos if (rpz_get_zbits(client, dns_rdatatype_any, DNS_RPZ_TYPE_NSDNAME) ==
4498 1.9 christos 0 &&
4499 1.9 christos rpz_get_zbits(client, dns_rdatatype_any, DNS_RPZ_TYPE_NSIP) == 0)
4500 1.9 christos {
4501 1.1 christos result = ISC_R_SUCCESS;
4502 1.1 christos goto cleanup;
4503 1.1 christos }
4504 1.1 christos
4505 1.1 christos dns_fixedname_init(&nsnamef);
4506 1.1 christos dns_name_clone(client->query.qname, dns_fixedname_name(&nsnamef));
4507 1.16 christos options = client->query.dboptions | DNS_DBFIND_GLUEOK;
4508 1.1 christos while (st->r.label > st->popt.min_ns_labels) {
4509 1.15 christos bool was_glue = false;
4510 1.1 christos /*
4511 1.1 christos * Get NS rrset for each domain in the current qname.
4512 1.1 christos */
4513 1.1 christos if (st->r.label == dns_name_countlabels(client->query.qname)) {
4514 1.1 christos nsname = client->query.qname;
4515 1.1 christos } else {
4516 1.1 christos nsname = dns_fixedname_name(&nsnamef);
4517 1.9 christos dns_name_split(client->query.qname, st->r.label, NULL,
4518 1.9 christos nsname);
4519 1.1 christos }
4520 1.1 christos if (st->r.ns_rdataset == NULL ||
4521 1.16 christos !dns_rdataset_isassociated(st->r.ns_rdataset))
4522 1.16 christos {
4523 1.1 christos dns_db_t *db = NULL;
4524 1.1 christos result = rpz_rrset_find(client, nsname,
4525 1.15 christos dns_rdatatype_ns, options,
4526 1.9 christos DNS_RPZ_TYPE_NSDNAME, &db, NULL,
4527 1.9 christos &st->r.ns_rdataset, resuming);
4528 1.9 christos if (db != NULL) {
4529 1.1 christos dns_db_detach(&db);
4530 1.9 christos }
4531 1.9 christos if (st->m.policy == DNS_RPZ_POLICY_ERROR) {
4532 1.1 christos goto cleanup;
4533 1.9 christos }
4534 1.1 christos switch (result) {
4535 1.15 christos case DNS_R_GLUE:
4536 1.15 christos was_glue = true;
4537 1.15 christos FALLTHROUGH;
4538 1.1 christos case ISC_R_SUCCESS:
4539 1.1 christos result = dns_rdataset_first(st->r.ns_rdataset);
4540 1.9 christos if (result != ISC_R_SUCCESS) {
4541 1.1 christos goto cleanup;
4542 1.9 christos }
4543 1.1 christos st->state &= ~(DNS_RPZ_DONE_NSDNAME |
4544 1.1 christos DNS_RPZ_DONE_IPv4);
4545 1.1 christos break;
4546 1.1 christos case DNS_R_DELEGATION:
4547 1.1 christos case DNS_R_DUPLICATE:
4548 1.1 christos case DNS_R_DROP:
4549 1.1 christos goto cleanup;
4550 1.1 christos case DNS_R_EMPTYNAME:
4551 1.1 christos case DNS_R_NXRRSET:
4552 1.1 christos case DNS_R_EMPTYWILD:
4553 1.1 christos case DNS_R_NXDOMAIN:
4554 1.1 christos case DNS_R_NCACHENXDOMAIN:
4555 1.1 christos case DNS_R_NCACHENXRRSET:
4556 1.1 christos case ISC_R_NOTFOUND:
4557 1.1 christos case DNS_R_CNAME:
4558 1.1 christos case DNS_R_DNAME:
4559 1.9 christos rpz_rewrite_ns_skip(client, nsname, result, 0,
4560 1.9 christos NULL);
4561 1.1 christos continue;
4562 1.1 christos case ISC_R_TIMEDOUT:
4563 1.1 christos case DNS_R_BROKENCHAIN:
4564 1.1 christos case ISC_R_FAILURE:
4565 1.1 christos rpz_rewrite_ns_skip(client, nsname, result,
4566 1.9 christos DNS_RPZ_DEBUG_LEVEL3,
4567 1.9 christos " NS rpz_rrset_find()");
4568 1.1 christos continue;
4569 1.1 christos default:
4570 1.1 christos rpz_rewrite_ns_skip(client, nsname, result,
4571 1.9 christos DNS_RPZ_INFO_LEVEL,
4572 1.9 christos " unrecognized NS"
4573 1.9 christos " rpz_rrset_find()");
4574 1.1 christos continue;
4575 1.1 christos }
4576 1.1 christos }
4577 1.15 christos
4578 1.1 christos /*
4579 1.1 christos * Check all NS names.
4580 1.1 christos */
4581 1.1 christos do {
4582 1.1 christos dns_rdata_ns_t ns;
4583 1.1 christos dns_rdata_t nsrdata = DNS_RDATA_INIT;
4584 1.1 christos
4585 1.1 christos dns_rdataset_current(st->r.ns_rdataset, &nsrdata);
4586 1.1 christos result = dns_rdata_tostruct(&nsrdata, &ns, NULL);
4587 1.3 christos RUNTIME_CHECK(result == ISC_R_SUCCESS);
4588 1.1 christos dns_rdata_reset(&nsrdata);
4589 1.3 christos
4590 1.1 christos /*
4591 1.1 christos * Do nothing about "NS ."
4592 1.1 christos */
4593 1.1 christos if (dns_name_equal(&ns.name, dns_rootname)) {
4594 1.1 christos dns_rdata_freestruct(&ns);
4595 1.1 christos result = dns_rdataset_next(st->r.ns_rdataset);
4596 1.1 christos continue;
4597 1.1 christos }
4598 1.1 christos /*
4599 1.1 christos * Check this NS name if we did not handle it
4600 1.1 christos * during a previous recursion.
4601 1.1 christos */
4602 1.1 christos if ((st->state & DNS_RPZ_DONE_NSDNAME) == 0) {
4603 1.9 christos result = rpz_rewrite_name(
4604 1.9 christos client, &ns.name, qtype,
4605 1.9 christos DNS_RPZ_TYPE_NSDNAME, DNS_RPZ_ALL_ZBITS,
4606 1.9 christos true, &rdataset);
4607 1.1 christos if (result != ISC_R_SUCCESS) {
4608 1.1 christos dns_rdata_freestruct(&ns);
4609 1.1 christos goto cleanup;
4610 1.1 christos }
4611 1.1 christos st->state |= DNS_RPZ_DONE_NSDNAME;
4612 1.1 christos }
4613 1.1 christos /*
4614 1.1 christos * Check all IP addresses for this NS name.
4615 1.1 christos */
4616 1.1 christos result = rpz_rewrite_ip_rrsets(client, &ns.name, qtype,
4617 1.1 christos DNS_RPZ_TYPE_NSIP,
4618 1.1 christos &rdataset, resuming);
4619 1.1 christos dns_rdata_freestruct(&ns);
4620 1.9 christos if (result != ISC_R_SUCCESS) {
4621 1.1 christos goto cleanup;
4622 1.9 christos }
4623 1.1 christos st->state &= ~(DNS_RPZ_DONE_NSDNAME |
4624 1.1 christos DNS_RPZ_DONE_IPv4);
4625 1.1 christos result = dns_rdataset_next(st->r.ns_rdataset);
4626 1.1 christos } while (result == ISC_R_SUCCESS);
4627 1.1 christos dns_rdataset_disassociate(st->r.ns_rdataset);
4628 1.15 christos
4629 1.15 christos /*
4630 1.15 christos * If we just checked a glue NS RRset retry without allowing
4631 1.15 christos * glue responses, otherwise setup for the next name.
4632 1.15 christos */
4633 1.15 christos if (was_glue) {
4634 1.16 christos options = client->query.dboptions;
4635 1.15 christos } else {
4636 1.16 christos options = client->query.dboptions | DNS_DBFIND_GLUEOK;
4637 1.15 christos st->r.label--;
4638 1.15 christos }
4639 1.1 christos
4640 1.1 christos if (rpz_get_zbits(client, dns_rdatatype_any,
4641 1.1 christos DNS_RPZ_TYPE_NSDNAME) == 0 &&
4642 1.1 christos rpz_get_zbits(client, dns_rdatatype_any,
4643 1.1 christos DNS_RPZ_TYPE_NSIP) == 0)
4644 1.9 christos {
4645 1.1 christos break;
4646 1.9 christos }
4647 1.1 christos }
4648 1.1 christos
4649 1.1 christos /*
4650 1.1 christos * Use the best hit, if any.
4651 1.1 christos */
4652 1.1 christos result = ISC_R_SUCCESS;
4653 1.1 christos
4654 1.1 christos cleanup:
4655 1.1 christos #ifdef USE_DNSRPS
4656 1.9 christos if (st->popt.dnsrps_enabled && st->m.policy != DNS_RPZ_POLICY_ERROR &&
4657 1.1 christos !dnsrps_set_p(&emsg, client, st, qtype, &rdataset,
4658 1.25 christos qresult_type != qresult_type_recurse))
4659 1.1 christos {
4660 1.1 christos rpz_log_fail(client, DNS_RPZ_ERROR_LEVEL, NULL,
4661 1.1 christos DNS_RPZ_TYPE_BAD, emsg.c, DNS_R_SERVFAIL);
4662 1.1 christos st->m.policy = DNS_RPZ_POLICY_ERROR;
4663 1.1 christos }
4664 1.9 christos #endif /* ifdef USE_DNSRPS */
4665 1.1 christos if (st->m.policy != DNS_RPZ_POLICY_MISS &&
4666 1.1 christos st->m.policy != DNS_RPZ_POLICY_ERROR &&
4667 1.1 christos st->m.rpz->policy != DNS_RPZ_POLICY_GIVEN)
4668 1.9 christos {
4669 1.1 christos st->m.policy = st->m.rpz->policy;
4670 1.9 christos }
4671 1.1 christos if (st->m.policy == DNS_RPZ_POLICY_MISS ||
4672 1.1 christos st->m.policy == DNS_RPZ_POLICY_PASSTHRU ||
4673 1.9 christos st->m.policy == DNS_RPZ_POLICY_ERROR)
4674 1.9 christos {
4675 1.1 christos if (st->m.policy == DNS_RPZ_POLICY_PASSTHRU &&
4676 1.16 christos result != DNS_R_DELEGATION)
4677 1.16 christos {
4678 1.9 christos rpz_log_rewrite(client, false, st->m.policy, st->m.type,
4679 1.9 christos st->m.zone, st->p_name, NULL,
4680 1.9 christos st->m.rpz->num);
4681 1.9 christos }
4682 1.1 christos rpz_match_clear(st);
4683 1.1 christos }
4684 1.1 christos if (st->m.policy == DNS_RPZ_POLICY_ERROR) {
4685 1.1 christos CTRACE(ISC_LOG_ERROR, "SERVFAIL due to RPZ policy");
4686 1.1 christos st->m.type = DNS_RPZ_TYPE_BAD;
4687 1.1 christos result = DNS_R_SERVFAIL;
4688 1.1 christos }
4689 1.3 christos ns_client_putrdataset(client, &rdataset);
4690 1.9 christos if ((st->state & DNS_RPZ_RECURSING) == 0) {
4691 1.1 christos rpz_clean(NULL, &st->r.db, NULL, &st->r.ns_rdataset);
4692 1.9 christos }
4693 1.1 christos
4694 1.23 christos return result;
4695 1.1 christos }
4696 1.1 christos
4697 1.1 christos /*
4698 1.1 christos * See if response policy zone rewriting is allowed by a lack of interest
4699 1.1 christos * by the client in DNSSEC or a lack of signatures.
4700 1.1 christos */
4701 1.3 christos static bool
4702 1.1 christos rpz_ck_dnssec(ns_client_t *client, isc_result_t qresult,
4703 1.9 christos dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset) {
4704 1.1 christos dns_fixedname_t fixed;
4705 1.1 christos dns_name_t *found;
4706 1.1 christos dns_rdataset_t trdataset;
4707 1.1 christos dns_rdatatype_t type;
4708 1.1 christos isc_result_t result;
4709 1.1 christos
4710 1.1 christos CTRACE(ISC_LOG_DEBUG(3), "rpz_ck_dnssec");
4711 1.1 christos
4712 1.9 christos if (client->view->rpzs->p.break_dnssec || !WANTDNSSEC(client)) {
4713 1.23 christos return true;
4714 1.9 christos }
4715 1.1 christos
4716 1.1 christos /*
4717 1.1 christos * We do not know if there are signatures if we have not recursed
4718 1.1 christos * for them.
4719 1.1 christos */
4720 1.9 christos if (qresult == DNS_R_DELEGATION || qresult == ISC_R_NOTFOUND) {
4721 1.23 christos return false;
4722 1.9 christos }
4723 1.1 christos
4724 1.9 christos if (sigrdataset == NULL) {
4725 1.23 christos return true;
4726 1.9 christos }
4727 1.9 christos if (dns_rdataset_isassociated(sigrdataset)) {
4728 1.23 christos return false;
4729 1.9 christos }
4730 1.1 christos
4731 1.1 christos /*
4732 1.1 christos * We are happy to rewrite nothing.
4733 1.1 christos */
4734 1.9 christos if (rdataset == NULL || !dns_rdataset_isassociated(rdataset)) {
4735 1.23 christos return true;
4736 1.9 christos }
4737 1.1 christos /*
4738 1.1 christos * Do not rewrite if there is any sign of signatures.
4739 1.1 christos */
4740 1.1 christos if (rdataset->type == dns_rdatatype_nsec ||
4741 1.1 christos rdataset->type == dns_rdatatype_nsec3 ||
4742 1.1 christos rdataset->type == dns_rdatatype_rrsig)
4743 1.9 christos {
4744 1.23 christos return false;
4745 1.9 christos }
4746 1.1 christos
4747 1.1 christos /*
4748 1.1 christos * Look for a signature in a negative cache rdataset.
4749 1.1 christos */
4750 1.9 christos if ((rdataset->attributes & DNS_RDATASETATTR_NEGATIVE) == 0) {
4751 1.23 christos return true;
4752 1.9 christos }
4753 1.1 christos found = dns_fixedname_initname(&fixed);
4754 1.1 christos dns_rdataset_init(&trdataset);
4755 1.9 christos for (result = dns_rdataset_first(rdataset); result == ISC_R_SUCCESS;
4756 1.9 christos result = dns_rdataset_next(rdataset))
4757 1.9 christos {
4758 1.1 christos dns_ncache_current(rdataset, found, &trdataset);
4759 1.1 christos type = trdataset.type;
4760 1.1 christos dns_rdataset_disassociate(&trdataset);
4761 1.9 christos if (type == dns_rdatatype_nsec || type == dns_rdatatype_nsec3 ||
4762 1.1 christos type == dns_rdatatype_rrsig)
4763 1.9 christos {
4764 1.23 christos return false;
4765 1.9 christos }
4766 1.1 christos }
4767 1.23 christos return true;
4768 1.1 christos }
4769 1.1 christos
4770 1.1 christos /*
4771 1.1 christos * Extract a network address from the RDATA of an A or AAAA
4772 1.1 christos * record.
4773 1.1 christos *
4774 1.1 christos * Returns:
4775 1.1 christos * ISC_R_SUCCESS
4776 1.1 christos * ISC_R_NOTIMPLEMENTED The rdata is not a known address type.
4777 1.1 christos */
4778 1.1 christos static isc_result_t
4779 1.1 christos rdata_tonetaddr(const dns_rdata_t *rdata, isc_netaddr_t *netaddr) {
4780 1.1 christos struct in_addr ina;
4781 1.1 christos struct in6_addr in6a;
4782 1.1 christos
4783 1.1 christos switch (rdata->type) {
4784 1.1 christos case dns_rdatatype_a:
4785 1.1 christos INSIST(rdata->length == 4);
4786 1.1 christos memmove(&ina.s_addr, rdata->data, 4);
4787 1.1 christos isc_netaddr_fromin(netaddr, &ina);
4788 1.23 christos return ISC_R_SUCCESS;
4789 1.1 christos case dns_rdatatype_aaaa:
4790 1.1 christos INSIST(rdata->length == 16);
4791 1.1 christos memmove(in6a.s6_addr, rdata->data, 16);
4792 1.1 christos isc_netaddr_fromin6(netaddr, &in6a);
4793 1.23 christos return ISC_R_SUCCESS;
4794 1.1 christos default:
4795 1.23 christos return ISC_R_NOTIMPLEMENTED;
4796 1.1 christos }
4797 1.1 christos }
4798 1.1 christos
4799 1.1 christos static unsigned char inaddr10_offsets[] = { 0, 3, 11, 16 };
4800 1.1 christos static unsigned char inaddr172_offsets[] = { 0, 3, 7, 15, 20 };
4801 1.1 christos static unsigned char inaddr192_offsets[] = { 0, 4, 8, 16, 21 };
4802 1.1 christos
4803 1.1 christos static unsigned char inaddr10[] = "\00210\007IN-ADDR\004ARPA";
4804 1.1 christos
4805 1.1 christos static unsigned char inaddr16172[] = "\00216\003172\007IN-ADDR\004ARPA";
4806 1.1 christos static unsigned char inaddr17172[] = "\00217\003172\007IN-ADDR\004ARPA";
4807 1.1 christos static unsigned char inaddr18172[] = "\00218\003172\007IN-ADDR\004ARPA";
4808 1.1 christos static unsigned char inaddr19172[] = "\00219\003172\007IN-ADDR\004ARPA";
4809 1.1 christos static unsigned char inaddr20172[] = "\00220\003172\007IN-ADDR\004ARPA";
4810 1.1 christos static unsigned char inaddr21172[] = "\00221\003172\007IN-ADDR\004ARPA";
4811 1.1 christos static unsigned char inaddr22172[] = "\00222\003172\007IN-ADDR\004ARPA";
4812 1.1 christos static unsigned char inaddr23172[] = "\00223\003172\007IN-ADDR\004ARPA";
4813 1.1 christos static unsigned char inaddr24172[] = "\00224\003172\007IN-ADDR\004ARPA";
4814 1.1 christos static unsigned char inaddr25172[] = "\00225\003172\007IN-ADDR\004ARPA";
4815 1.1 christos static unsigned char inaddr26172[] = "\00226\003172\007IN-ADDR\004ARPA";
4816 1.1 christos static unsigned char inaddr27172[] = "\00227\003172\007IN-ADDR\004ARPA";
4817 1.1 christos static unsigned char inaddr28172[] = "\00228\003172\007IN-ADDR\004ARPA";
4818 1.1 christos static unsigned char inaddr29172[] = "\00229\003172\007IN-ADDR\004ARPA";
4819 1.1 christos static unsigned char inaddr30172[] = "\00230\003172\007IN-ADDR\004ARPA";
4820 1.1 christos static unsigned char inaddr31172[] = "\00231\003172\007IN-ADDR\004ARPA";
4821 1.1 christos
4822 1.1 christos static unsigned char inaddr168192[] = "\003168\003192\007IN-ADDR\004ARPA";
4823 1.1 christos
4824 1.1 christos static dns_name_t rfc1918names[] = {
4825 1.1 christos DNS_NAME_INITABSOLUTE(inaddr10, inaddr10_offsets),
4826 1.1 christos DNS_NAME_INITABSOLUTE(inaddr16172, inaddr172_offsets),
4827 1.1 christos DNS_NAME_INITABSOLUTE(inaddr17172, inaddr172_offsets),
4828 1.1 christos DNS_NAME_INITABSOLUTE(inaddr18172, inaddr172_offsets),
4829 1.1 christos DNS_NAME_INITABSOLUTE(inaddr19172, inaddr172_offsets),
4830 1.1 christos DNS_NAME_INITABSOLUTE(inaddr20172, inaddr172_offsets),
4831 1.1 christos DNS_NAME_INITABSOLUTE(inaddr21172, inaddr172_offsets),
4832 1.1 christos DNS_NAME_INITABSOLUTE(inaddr22172, inaddr172_offsets),
4833 1.1 christos DNS_NAME_INITABSOLUTE(inaddr23172, inaddr172_offsets),
4834 1.1 christos DNS_NAME_INITABSOLUTE(inaddr24172, inaddr172_offsets),
4835 1.1 christos DNS_NAME_INITABSOLUTE(inaddr25172, inaddr172_offsets),
4836 1.1 christos DNS_NAME_INITABSOLUTE(inaddr26172, inaddr172_offsets),
4837 1.1 christos DNS_NAME_INITABSOLUTE(inaddr27172, inaddr172_offsets),
4838 1.1 christos DNS_NAME_INITABSOLUTE(inaddr28172, inaddr172_offsets),
4839 1.1 christos DNS_NAME_INITABSOLUTE(inaddr29172, inaddr172_offsets),
4840 1.1 christos DNS_NAME_INITABSOLUTE(inaddr30172, inaddr172_offsets),
4841 1.1 christos DNS_NAME_INITABSOLUTE(inaddr31172, inaddr172_offsets),
4842 1.1 christos DNS_NAME_INITABSOLUTE(inaddr168192, inaddr192_offsets)
4843 1.1 christos };
4844 1.1 christos
4845 1.1 christos static unsigned char prisoner_data[] = "\010prisoner\004iana\003org";
4846 1.9 christos static unsigned char hostmaster_data[] = "\012hostmaster\014root-"
4847 1.9 christos "servers\003org";
4848 1.1 christos
4849 1.1 christos static unsigned char prisoner_offsets[] = { 0, 9, 14, 18 };
4850 1.1 christos static unsigned char hostmaster_offsets[] = { 0, 11, 24, 28 };
4851 1.1 christos
4852 1.9 christos static dns_name_t const prisoner = DNS_NAME_INITABSOLUTE(prisoner_data,
4853 1.9 christos prisoner_offsets);
4854 1.9 christos static dns_name_t const hostmaster = DNS_NAME_INITABSOLUTE(hostmaster_data,
4855 1.9 christos hostmaster_offsets);
4856 1.1 christos
4857 1.1 christos static void
4858 1.1 christos warn_rfc1918(ns_client_t *client, dns_name_t *fname, dns_rdataset_t *rdataset) {
4859 1.1 christos unsigned int i;
4860 1.1 christos dns_rdata_t rdata = DNS_RDATA_INIT;
4861 1.1 christos dns_rdata_soa_t soa;
4862 1.1 christos dns_rdataset_t found;
4863 1.1 christos isc_result_t result;
4864 1.1 christos
4865 1.9 christos for (i = 0; i < (sizeof(rfc1918names) / sizeof(*rfc1918names)); i++) {
4866 1.1 christos if (dns_name_issubdomain(fname, &rfc1918names[i])) {
4867 1.1 christos dns_rdataset_init(&found);
4868 1.9 christos result = dns_ncache_getrdataset(
4869 1.9 christos rdataset, &rfc1918names[i], dns_rdatatype_soa,
4870 1.9 christos &found);
4871 1.9 christos if (result != ISC_R_SUCCESS) {
4872 1.1 christos return;
4873 1.9 christos }
4874 1.1 christos
4875 1.1 christos result = dns_rdataset_first(&found);
4876 1.1 christos RUNTIME_CHECK(result == ISC_R_SUCCESS);
4877 1.1 christos dns_rdataset_current(&found, &rdata);
4878 1.1 christos result = dns_rdata_tostruct(&rdata, &soa, NULL);
4879 1.1 christos RUNTIME_CHECK(result == ISC_R_SUCCESS);
4880 1.1 christos if (dns_name_equal(&soa.origin, &prisoner) &&
4881 1.9 christos dns_name_equal(&soa.contact, &hostmaster))
4882 1.9 christos {
4883 1.1 christos char buf[DNS_NAME_FORMATSIZE];
4884 1.1 christos dns_name_format(fname, buf, sizeof(buf));
4885 1.1 christos ns_client_log(client, DNS_LOGCATEGORY_SECURITY,
4886 1.1 christos NS_LOGMODULE_QUERY,
4887 1.1 christos ISC_LOG_WARNING,
4888 1.1 christos "RFC 1918 response from "
4889 1.9 christos "Internet for %s",
4890 1.9 christos buf);
4891 1.1 christos }
4892 1.1 christos dns_rdataset_disassociate(&found);
4893 1.1 christos return;
4894 1.1 christos }
4895 1.1 christos }
4896 1.1 christos }
4897 1.1 christos
4898 1.1 christos static void
4899 1.1 christos query_findclosestnsec3(dns_name_t *qname, dns_db_t *db,
4900 1.1 christos dns_dbversion_t *version, ns_client_t *client,
4901 1.1 christos dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset,
4902 1.9 christos dns_name_t *fname, bool exact, dns_name_t *found) {
4903 1.1 christos unsigned char salt[256];
4904 1.1 christos size_t salt_length;
4905 1.3 christos uint16_t iterations;
4906 1.1 christos isc_result_t result;
4907 1.1 christos unsigned int dboptions;
4908 1.1 christos dns_fixedname_t fixed;
4909 1.1 christos dns_hash_t hash;
4910 1.1 christos dns_name_t name;
4911 1.1 christos unsigned int skip = 0, labels;
4912 1.1 christos dns_rdata_nsec3_t nsec3;
4913 1.1 christos dns_rdata_t rdata = DNS_RDATA_INIT;
4914 1.3 christos bool optout;
4915 1.1 christos dns_clientinfomethods_t cm;
4916 1.1 christos dns_clientinfo_t ci;
4917 1.1 christos
4918 1.1 christos salt_length = sizeof(salt);
4919 1.1 christos result = dns_db_getnsec3parameters(db, version, &hash, NULL,
4920 1.1 christos &iterations, salt, &salt_length);
4921 1.9 christos if (result != ISC_R_SUCCESS) {
4922 1.1 christos return;
4923 1.9 christos }
4924 1.1 christos
4925 1.1 christos dns_name_init(&name, NULL);
4926 1.1 christos dns_name_clone(qname, &name);
4927 1.1 christos labels = dns_name_countlabels(&name);
4928 1.1 christos dns_clientinfomethods_init(&cm, ns_client_sourceip);
4929 1.20 christos dns_clientinfo_init(&ci, client, NULL);
4930 1.1 christos
4931 1.1 christos /*
4932 1.1 christos * Map unknown algorithm to known value.
4933 1.1 christos */
4934 1.9 christos if (hash == DNS_NSEC3_UNKNOWNALG) {
4935 1.1 christos hash = 1;
4936 1.9 christos }
4937 1.1 christos
4938 1.9 christos again:
4939 1.1 christos dns_fixedname_init(&fixed);
4940 1.1 christos result = dns_nsec3_hashname(&fixed, NULL, NULL, &name,
4941 1.9 christos dns_db_origin(db), hash, iterations, salt,
4942 1.9 christos salt_length);
4943 1.9 christos if (result != ISC_R_SUCCESS) {
4944 1.1 christos return;
4945 1.9 christos }
4946 1.1 christos
4947 1.1 christos dboptions = client->query.dboptions | DNS_DBFIND_FORCENSEC3;
4948 1.1 christos result = dns_db_findext(db, dns_fixedname_name(&fixed), version,
4949 1.1 christos dns_rdatatype_nsec3, dboptions, client->now,
4950 1.1 christos NULL, fname, &cm, &ci, rdataset, sigrdataset);
4951 1.1 christos
4952 1.1 christos if (result == DNS_R_NXDOMAIN) {
4953 1.1 christos if (!dns_rdataset_isassociated(rdataset)) {
4954 1.1 christos return;
4955 1.1 christos }
4956 1.1 christos result = dns_rdataset_first(rdataset);
4957 1.1 christos INSIST(result == ISC_R_SUCCESS);
4958 1.1 christos dns_rdataset_current(rdataset, &rdata);
4959 1.3 christos result = dns_rdata_tostruct(&rdata, &nsec3, NULL);
4960 1.3 christos RUNTIME_CHECK(result == ISC_R_SUCCESS);
4961 1.1 christos dns_rdata_reset(&rdata);
4962 1.3 christos optout = ((nsec3.flags & DNS_NSEC3FLAG_OPTOUT) != 0);
4963 1.1 christos if (found != NULL && optout &&
4964 1.16 christos dns_name_issubdomain(&name, dns_db_origin(db)))
4965 1.16 christos {
4966 1.1 christos dns_rdataset_disassociate(rdataset);
4967 1.9 christos if (dns_rdataset_isassociated(sigrdataset)) {
4968 1.1 christos dns_rdataset_disassociate(sigrdataset);
4969 1.9 christos }
4970 1.1 christos skip++;
4971 1.1 christos dns_name_getlabelsequence(qname, skip, labels - skip,
4972 1.1 christos &name);
4973 1.1 christos ns_client_log(client, DNS_LOGCATEGORY_DNSSEC,
4974 1.1 christos NS_LOGMODULE_QUERY, ISC_LOG_DEBUG(3),
4975 1.1 christos "looking for closest provable encloser");
4976 1.1 christos goto again;
4977 1.1 christos }
4978 1.9 christos if (exact) {
4979 1.1 christos ns_client_log(client, DNS_LOGCATEGORY_DNSSEC,
4980 1.1 christos NS_LOGMODULE_QUERY, ISC_LOG_WARNING,
4981 1.1 christos "expected a exact match NSEC3, got "
4982 1.1 christos "a covering record");
4983 1.9 christos }
4984 1.1 christos } else if (result != ISC_R_SUCCESS) {
4985 1.1 christos return;
4986 1.9 christos } else if (!exact) {
4987 1.1 christos ns_client_log(client, DNS_LOGCATEGORY_DNSSEC,
4988 1.1 christos NS_LOGMODULE_QUERY, ISC_LOG_WARNING,
4989 1.1 christos "expected covering NSEC3, got an exact match");
4990 1.9 christos }
4991 1.1 christos if (found == qname) {
4992 1.9 christos if (skip != 0U) {
4993 1.1 christos dns_name_getlabelsequence(qname, skip, labels - skip,
4994 1.1 christos found);
4995 1.9 christos }
4996 1.9 christos } else if (found != NULL) {
4997 1.20 christos dns_name_copy(&name, found);
4998 1.9 christos }
4999 1.1 christos return;
5000 1.1 christos }
5001 1.1 christos
5002 1.3 christos static uint32_t
5003 1.1 christos dns64_ttl(dns_db_t *db, dns_dbversion_t *version) {
5004 1.1 christos dns_dbnode_t *node = NULL;
5005 1.1 christos dns_rdata_soa_t soa;
5006 1.1 christos dns_rdata_t rdata = DNS_RDATA_INIT;
5007 1.1 christos dns_rdataset_t rdataset;
5008 1.1 christos isc_result_t result;
5009 1.3 christos uint32_t ttl = UINT32_MAX;
5010 1.1 christos
5011 1.1 christos dns_rdataset_init(&rdataset);
5012 1.1 christos
5013 1.1 christos result = dns_db_getoriginnode(db, &node);
5014 1.9 christos if (result != ISC_R_SUCCESS) {
5015 1.1 christos goto cleanup;
5016 1.9 christos }
5017 1.1 christos
5018 1.9 christos result = dns_db_findrdataset(db, node, version, dns_rdatatype_soa, 0, 0,
5019 1.9 christos &rdataset, NULL);
5020 1.9 christos if (result != ISC_R_SUCCESS) {
5021 1.1 christos goto cleanup;
5022 1.9 christos }
5023 1.1 christos result = dns_rdataset_first(&rdataset);
5024 1.9 christos if (result != ISC_R_SUCCESS) {
5025 1.1 christos goto cleanup;
5026 1.9 christos }
5027 1.1 christos
5028 1.1 christos dns_rdataset_current(&rdataset, &rdata);
5029 1.1 christos result = dns_rdata_tostruct(&rdata, &soa, NULL);
5030 1.1 christos RUNTIME_CHECK(result == ISC_R_SUCCESS);
5031 1.1 christos ttl = ISC_MIN(rdataset.ttl, soa.minimum);
5032 1.1 christos
5033 1.1 christos cleanup:
5034 1.9 christos if (dns_rdataset_isassociated(&rdataset)) {
5035 1.1 christos dns_rdataset_disassociate(&rdataset);
5036 1.9 christos }
5037 1.9 christos if (node != NULL) {
5038 1.1 christos dns_db_detachnode(db, &node);
5039 1.9 christos }
5040 1.23 christos return ttl;
5041 1.1 christos }
5042 1.1 christos
5043 1.3 christos static bool
5044 1.1 christos dns64_aaaaok(ns_client_t *client, dns_rdataset_t *rdataset,
5045 1.9 christos dns_rdataset_t *sigrdataset) {
5046 1.1 christos isc_netaddr_t netaddr;
5047 1.20 christos dns_aclenv_t *env = client->manager->aclenv;
5048 1.1 christos dns_dns64_t *dns64 = ISC_LIST_HEAD(client->view->dns64);
5049 1.1 christos unsigned int flags = 0;
5050 1.1 christos unsigned int i, count;
5051 1.3 christos bool *aaaaok;
5052 1.1 christos
5053 1.1 christos INSIST(client->query.dns64_aaaaok == NULL);
5054 1.1 christos INSIST(client->query.dns64_aaaaoklen == 0);
5055 1.1 christos INSIST(client->query.dns64_aaaa == NULL);
5056 1.1 christos INSIST(client->query.dns64_sigaaaa == NULL);
5057 1.1 christos
5058 1.9 christos if (dns64 == NULL) {
5059 1.23 christos return true;
5060 1.9 christos }
5061 1.1 christos
5062 1.9 christos if (RECURSIONOK(client)) {
5063 1.1 christos flags |= DNS_DNS64_RECURSIVE;
5064 1.9 christos }
5065 1.1 christos
5066 1.1 christos if (WANTDNSSEC(client) && sigrdataset != NULL &&
5067 1.1 christos dns_rdataset_isassociated(sigrdataset))
5068 1.9 christos {
5069 1.1 christos flags |= DNS_DNS64_DNSSEC;
5070 1.9 christos }
5071 1.1 christos
5072 1.1 christos count = dns_rdataset_count(rdataset);
5073 1.23 christos aaaaok = isc_mem_cget(client->manager->mctx, count, sizeof(bool));
5074 1.1 christos
5075 1.1 christos isc_netaddr_fromsockaddr(&netaddr, &client->peeraddr);
5076 1.9 christos if (dns_dns64_aaaaok(dns64, &netaddr, client->signer, env, flags,
5077 1.9 christos rdataset, aaaaok, count))
5078 1.1 christos {
5079 1.1 christos for (i = 0; i < count; i++) {
5080 1.1 christos if (aaaaok != NULL && !aaaaok[i]) {
5081 1.1 christos SAVE(client->query.dns64_aaaaok, aaaaok);
5082 1.1 christos client->query.dns64_aaaaoklen = count;
5083 1.1 christos break;
5084 1.1 christos }
5085 1.1 christos }
5086 1.9 christos if (aaaaok != NULL) {
5087 1.23 christos isc_mem_cput(client->manager->mctx, aaaaok, count,
5088 1.23 christos sizeof(bool));
5089 1.9 christos }
5090 1.23 christos return true;
5091 1.1 christos }
5092 1.9 christos if (aaaaok != NULL) {
5093 1.23 christos isc_mem_cput(client->manager->mctx, aaaaok, count,
5094 1.23 christos sizeof(bool));
5095 1.9 christos }
5096 1.23 christos return false;
5097 1.1 christos }
5098 1.1 christos
5099 1.1 christos /*
5100 1.1 christos * Look for the name and type in the redirection zone. If found update
5101 1.3 christos * the arguments as appropriate. Return true if a update was
5102 1.1 christos * performed.
5103 1.1 christos *
5104 1.1 christos * Only perform the update if the client is in the allow query acl and
5105 1.1 christos * returning the update would not cause a DNSSEC validation failure.
5106 1.1 christos */
5107 1.1 christos static isc_result_t
5108 1.1 christos redirect(ns_client_t *client, dns_name_t *name, dns_rdataset_t *rdataset,
5109 1.1 christos dns_dbnode_t **nodep, dns_db_t **dbp, dns_dbversion_t **versionp,
5110 1.9 christos dns_rdatatype_t qtype) {
5111 1.1 christos dns_db_t *db = NULL;
5112 1.1 christos dns_dbnode_t *node = NULL;
5113 1.1 christos dns_fixedname_t fixed;
5114 1.1 christos dns_name_t *found;
5115 1.1 christos dns_rdataset_t trdataset;
5116 1.1 christos isc_result_t result;
5117 1.1 christos dns_rdatatype_t type;
5118 1.1 christos dns_clientinfomethods_t cm;
5119 1.1 christos dns_clientinfo_t ci;
5120 1.1 christos ns_dbversion_t *dbversion;
5121 1.1 christos
5122 1.1 christos CTRACE(ISC_LOG_DEBUG(3), "redirect");
5123 1.1 christos
5124 1.9 christos if (client->view->redirect == NULL) {
5125 1.23 christos return ISC_R_NOTFOUND;
5126 1.9 christos }
5127 1.1 christos
5128 1.1 christos found = dns_fixedname_initname(&fixed);
5129 1.1 christos dns_rdataset_init(&trdataset);
5130 1.1 christos
5131 1.1 christos dns_clientinfomethods_init(&cm, ns_client_sourceip);
5132 1.20 christos dns_clientinfo_init(&ci, client, NULL);
5133 1.20 christos dns_clientinfo_setecs(&ci, &client->ecs);
5134 1.1 christos
5135 1.1 christos if (WANTDNSSEC(client) && dns_db_iszone(*dbp) && dns_db_issecure(*dbp))
5136 1.9 christos {
5137 1.23 christos return ISC_R_NOTFOUND;
5138 1.9 christos }
5139 1.1 christos
5140 1.1 christos if (WANTDNSSEC(client) && dns_rdataset_isassociated(rdataset)) {
5141 1.9 christos if (rdataset->trust == dns_trust_secure) {
5142 1.23 christos return ISC_R_NOTFOUND;
5143 1.9 christos }
5144 1.1 christos if (rdataset->trust == dns_trust_ultimate &&
5145 1.1 christos (rdataset->type == dns_rdatatype_nsec ||
5146 1.1 christos rdataset->type == dns_rdatatype_nsec3))
5147 1.9 christos {
5148 1.23 christos return ISC_R_NOTFOUND;
5149 1.9 christos }
5150 1.1 christos if ((rdataset->attributes & DNS_RDATASETATTR_NEGATIVE) != 0) {
5151 1.1 christos for (result = dns_rdataset_first(rdataset);
5152 1.1 christos result == ISC_R_SUCCESS;
5153 1.9 christos result = dns_rdataset_next(rdataset))
5154 1.9 christos {
5155 1.1 christos dns_ncache_current(rdataset, found, &trdataset);
5156 1.1 christos type = trdataset.type;
5157 1.1 christos dns_rdataset_disassociate(&trdataset);
5158 1.1 christos if (type == dns_rdatatype_nsec ||
5159 1.1 christos type == dns_rdatatype_nsec3 ||
5160 1.1 christos type == dns_rdatatype_rrsig)
5161 1.9 christos {
5162 1.23 christos return ISC_R_NOTFOUND;
5163 1.9 christos }
5164 1.1 christos }
5165 1.1 christos }
5166 1.1 christos }
5167 1.1 christos
5168 1.9 christos result = ns_client_checkaclsilent(
5169 1.9 christos client, NULL, dns_zone_getqueryacl(client->view->redirect),
5170 1.9 christos true);
5171 1.9 christos if (result != ISC_R_SUCCESS) {
5172 1.23 christos return ISC_R_NOTFOUND;
5173 1.9 christos }
5174 1.1 christos
5175 1.1 christos result = dns_zone_getdb(client->view->redirect, &db);
5176 1.9 christos if (result != ISC_R_SUCCESS) {
5177 1.23 christos return ISC_R_NOTFOUND;
5178 1.9 christos }
5179 1.1 christos
5180 1.3 christos dbversion = ns_client_findversion(client, db);
5181 1.1 christos if (dbversion == NULL) {
5182 1.1 christos dns_db_detach(&db);
5183 1.23 christos return ISC_R_NOTFOUND;
5184 1.1 christos }
5185 1.1 christos
5186 1.1 christos /*
5187 1.1 christos * Lookup the requested data in the redirect zone.
5188 1.1 christos */
5189 1.1 christos result = dns_db_findext(db, client->query.qname, dbversion->version,
5190 1.9 christos qtype, DNS_DBFIND_NOZONECUT, client->now, &node,
5191 1.9 christos found, &cm, &ci, &trdataset, NULL);
5192 1.1 christos if (result == DNS_R_NXRRSET || result == DNS_R_NCACHENXRRSET) {
5193 1.9 christos if (dns_rdataset_isassociated(rdataset)) {
5194 1.1 christos dns_rdataset_disassociate(rdataset);
5195 1.9 christos }
5196 1.9 christos if (dns_rdataset_isassociated(&trdataset)) {
5197 1.1 christos dns_rdataset_disassociate(&trdataset);
5198 1.9 christos }
5199 1.1 christos goto nxrrset;
5200 1.1 christos } else if (result != ISC_R_SUCCESS) {
5201 1.9 christos if (dns_rdataset_isassociated(&trdataset)) {
5202 1.1 christos dns_rdataset_disassociate(&trdataset);
5203 1.9 christos }
5204 1.9 christos if (node != NULL) {
5205 1.1 christos dns_db_detachnode(db, &node);
5206 1.9 christos }
5207 1.1 christos dns_db_detach(&db);
5208 1.23 christos return ISC_R_NOTFOUND;
5209 1.1 christos }
5210 1.1 christos
5211 1.1 christos CTRACE(ISC_LOG_DEBUG(3), "redirect: found data: done");
5212 1.20 christos dns_name_copy(found, name);
5213 1.9 christos if (dns_rdataset_isassociated(rdataset)) {
5214 1.1 christos dns_rdataset_disassociate(rdataset);
5215 1.9 christos }
5216 1.1 christos if (dns_rdataset_isassociated(&trdataset)) {
5217 1.1 christos dns_rdataset_clone(&trdataset, rdataset);
5218 1.1 christos dns_rdataset_disassociate(&trdataset);
5219 1.1 christos }
5220 1.9 christos nxrrset:
5221 1.9 christos if (*nodep != NULL) {
5222 1.1 christos dns_db_detachnode(*dbp, nodep);
5223 1.9 christos }
5224 1.1 christos dns_db_detach(dbp);
5225 1.1 christos dns_db_attachnode(db, node, nodep);
5226 1.1 christos dns_db_attach(db, dbp);
5227 1.1 christos dns_db_detachnode(db, &node);
5228 1.1 christos dns_db_detach(&db);
5229 1.1 christos *versionp = dbversion->version;
5230 1.1 christos
5231 1.1 christos client->query.attributes |= (NS_QUERYATTR_NOAUTHORITY |
5232 1.1 christos NS_QUERYATTR_NOADDITIONAL);
5233 1.1 christos
5234 1.23 christos return result;
5235 1.1 christos }
5236 1.1 christos
5237 1.1 christos static isc_result_t
5238 1.1 christos redirect2(ns_client_t *client, dns_name_t *name, dns_rdataset_t *rdataset,
5239 1.1 christos dns_dbnode_t **nodep, dns_db_t **dbp, dns_dbversion_t **versionp,
5240 1.9 christos dns_rdatatype_t qtype, bool *is_zonep) {
5241 1.1 christos dns_db_t *db = NULL;
5242 1.1 christos dns_dbnode_t *node = NULL;
5243 1.1 christos dns_fixedname_t fixed;
5244 1.1 christos dns_fixedname_t fixedredirect;
5245 1.1 christos dns_name_t *found, *redirectname;
5246 1.1 christos dns_rdataset_t trdataset;
5247 1.1 christos isc_result_t result;
5248 1.1 christos dns_rdatatype_t type;
5249 1.1 christos dns_clientinfomethods_t cm;
5250 1.1 christos dns_clientinfo_t ci;
5251 1.1 christos dns_dbversion_t *version = NULL;
5252 1.1 christos dns_zone_t *zone = NULL;
5253 1.3 christos bool is_zone;
5254 1.5 christos unsigned int labels;
5255 1.1 christos
5256 1.1 christos CTRACE(ISC_LOG_DEBUG(3), "redirect2");
5257 1.1 christos
5258 1.5 christos if (client->view->redirectzone == NULL) {
5259 1.23 christos return ISC_R_NOTFOUND;
5260 1.5 christos }
5261 1.1 christos
5262 1.5 christos if (dns_name_issubdomain(name, client->view->redirectzone)) {
5263 1.23 christos return ISC_R_NOTFOUND;
5264 1.5 christos }
5265 1.1 christos
5266 1.1 christos found = dns_fixedname_initname(&fixed);
5267 1.1 christos dns_rdataset_init(&trdataset);
5268 1.1 christos
5269 1.1 christos dns_clientinfomethods_init(&cm, ns_client_sourceip);
5270 1.20 christos dns_clientinfo_init(&ci, client, NULL);
5271 1.20 christos dns_clientinfo_setecs(&ci, &client->ecs);
5272 1.1 christos
5273 1.9 christos if (WANTDNSSEC(client) && dns_db_iszone(*dbp) && dns_db_issecure(*dbp))
5274 1.9 christos {
5275 1.23 christos return ISC_R_NOTFOUND;
5276 1.5 christos }
5277 1.1 christos
5278 1.1 christos if (WANTDNSSEC(client) && dns_rdataset_isassociated(rdataset)) {
5279 1.9 christos if (rdataset->trust == dns_trust_secure) {
5280 1.23 christos return ISC_R_NOTFOUND;
5281 1.9 christos }
5282 1.1 christos if (rdataset->trust == dns_trust_ultimate &&
5283 1.1 christos (rdataset->type == dns_rdatatype_nsec ||
5284 1.1 christos rdataset->type == dns_rdatatype_nsec3))
5285 1.9 christos {
5286 1.23 christos return ISC_R_NOTFOUND;
5287 1.9 christos }
5288 1.1 christos if ((rdataset->attributes & DNS_RDATASETATTR_NEGATIVE) != 0) {
5289 1.1 christos for (result = dns_rdataset_first(rdataset);
5290 1.1 christos result == ISC_R_SUCCESS;
5291 1.9 christos result = dns_rdataset_next(rdataset))
5292 1.9 christos {
5293 1.1 christos dns_ncache_current(rdataset, found, &trdataset);
5294 1.1 christos type = trdataset.type;
5295 1.1 christos dns_rdataset_disassociate(&trdataset);
5296 1.1 christos if (type == dns_rdatatype_nsec ||
5297 1.1 christos type == dns_rdatatype_nsec3 ||
5298 1.1 christos type == dns_rdatatype_rrsig)
5299 1.9 christos {
5300 1.23 christos return ISC_R_NOTFOUND;
5301 1.9 christos }
5302 1.1 christos }
5303 1.1 christos }
5304 1.1 christos }
5305 1.1 christos
5306 1.1 christos redirectname = dns_fixedname_initname(&fixedredirect);
5307 1.5 christos labels = dns_name_countlabels(client->query.qname);
5308 1.5 christos if (labels > 1U) {
5309 1.1 christos dns_name_t prefix;
5310 1.1 christos
5311 1.1 christos dns_name_init(&prefix, NULL);
5312 1.5 christos dns_name_getlabelsequence(client->query.qname, 0, labels - 1,
5313 1.5 christos &prefix);
5314 1.1 christos result = dns_name_concatenate(&prefix,
5315 1.1 christos client->view->redirectzone,
5316 1.1 christos redirectname, NULL);
5317 1.9 christos if (result != ISC_R_SUCCESS) {
5318 1.23 christos return ISC_R_NOTFOUND;
5319 1.9 christos }
5320 1.5 christos } else {
5321 1.20 christos dns_name_copy(redirectname, client->view->redirectzone);
5322 1.5 christos }
5323 1.1 christos
5324 1.23 christos result = query_getdb(client, redirectname, qtype,
5325 1.23 christos (dns_getdb_options_t){ 0 }, &zone, &db, &version,
5326 1.23 christos &is_zone);
5327 1.5 christos if (result != ISC_R_SUCCESS) {
5328 1.23 christos return ISC_R_NOTFOUND;
5329 1.5 christos }
5330 1.5 christos if (zone != NULL) {
5331 1.1 christos dns_zone_detach(&zone);
5332 1.5 christos }
5333 1.1 christos
5334 1.1 christos /*
5335 1.1 christos * Lookup the requested data in the redirect zone.
5336 1.1 christos */
5337 1.9 christos result = dns_db_findext(db, redirectname, version, qtype, 0,
5338 1.9 christos client->now, &node, found, &cm, &ci, &trdataset,
5339 1.9 christos NULL);
5340 1.1 christos if (result == DNS_R_NXRRSET || result == DNS_R_NCACHENXRRSET) {
5341 1.9 christos if (dns_rdataset_isassociated(rdataset)) {
5342 1.1 christos dns_rdataset_disassociate(rdataset);
5343 1.9 christos }
5344 1.9 christos if (dns_rdataset_isassociated(&trdataset)) {
5345 1.1 christos dns_rdataset_disassociate(&trdataset);
5346 1.9 christos }
5347 1.1 christos goto nxrrset;
5348 1.1 christos } else if (result == ISC_R_NOTFOUND || result == DNS_R_DELEGATION) {
5349 1.1 christos /*
5350 1.1 christos * Cleanup.
5351 1.1 christos */
5352 1.9 christos if (dns_rdataset_isassociated(&trdataset)) {
5353 1.1 christos dns_rdataset_disassociate(&trdataset);
5354 1.9 christos }
5355 1.9 christos if (node != NULL) {
5356 1.1 christos dns_db_detachnode(db, &node);
5357 1.9 christos }
5358 1.1 christos dns_db_detach(&db);
5359 1.1 christos /*
5360 1.1 christos * Don't loop forever if the lookup failed last time.
5361 1.1 christos */
5362 1.1 christos if (!REDIRECT(client)) {
5363 1.3 christos result = ns_query_recurse(client, qtype, redirectname,
5364 1.3 christos NULL, NULL, true);
5365 1.1 christos if (result == ISC_R_SUCCESS) {
5366 1.1 christos client->query.attributes |=
5367 1.9 christos NS_QUERYATTR_RECURSING;
5368 1.1 christos client->query.attributes |=
5369 1.9 christos NS_QUERYATTR_REDIRECT;
5370 1.23 christos return DNS_R_CONTINUE;
5371 1.1 christos }
5372 1.1 christos }
5373 1.23 christos return ISC_R_NOTFOUND;
5374 1.1 christos } else if (result != ISC_R_SUCCESS) {
5375 1.9 christos if (dns_rdataset_isassociated(&trdataset)) {
5376 1.1 christos dns_rdataset_disassociate(&trdataset);
5377 1.9 christos }
5378 1.9 christos if (node != NULL) {
5379 1.1 christos dns_db_detachnode(db, &node);
5380 1.9 christos }
5381 1.1 christos dns_db_detach(&db);
5382 1.23 christos return ISC_R_NOTFOUND;
5383 1.1 christos }
5384 1.1 christos
5385 1.1 christos CTRACE(ISC_LOG_DEBUG(3), "redirect2: found data: done");
5386 1.1 christos /*
5387 1.1 christos * Adjust the found name to not include the redirectzone suffix.
5388 1.1 christos */
5389 1.1 christos dns_name_split(found, dns_name_countlabels(client->view->redirectzone),
5390 1.1 christos found, NULL);
5391 1.1 christos /*
5392 1.1 christos * Make the name absolute.
5393 1.1 christos */
5394 1.1 christos result = dns_name_concatenate(found, dns_rootname, found, NULL);
5395 1.1 christos RUNTIME_CHECK(result == ISC_R_SUCCESS);
5396 1.1 christos
5397 1.20 christos dns_name_copy(found, name);
5398 1.9 christos if (dns_rdataset_isassociated(rdataset)) {
5399 1.1 christos dns_rdataset_disassociate(rdataset);
5400 1.9 christos }
5401 1.1 christos if (dns_rdataset_isassociated(&trdataset)) {
5402 1.1 christos dns_rdataset_clone(&trdataset, rdataset);
5403 1.1 christos dns_rdataset_disassociate(&trdataset);
5404 1.1 christos }
5405 1.9 christos nxrrset:
5406 1.9 christos if (*nodep != NULL) {
5407 1.1 christos dns_db_detachnode(*dbp, nodep);
5408 1.9 christos }
5409 1.1 christos dns_db_detach(dbp);
5410 1.1 christos dns_db_attachnode(db, node, nodep);
5411 1.1 christos dns_db_attach(db, dbp);
5412 1.1 christos dns_db_detachnode(db, &node);
5413 1.1 christos dns_db_detach(&db);
5414 1.1 christos *is_zonep = is_zone;
5415 1.1 christos *versionp = version;
5416 1.1 christos
5417 1.1 christos client->query.attributes |= (NS_QUERYATTR_NOAUTHORITY |
5418 1.1 christos NS_QUERYATTR_NOADDITIONAL);
5419 1.1 christos
5420 1.23 christos return result;
5421 1.1 christos }
5422 1.1 christos
5423 1.1 christos /*%
5424 1.1 christos * Initialize query context 'qctx'. Run by query_setup() when
5425 1.1 christos * first handling a client query, and by query_resume() when
5426 1.1 christos * returning from recursion.
5427 1.3 christos *
5428 1.3 christos * Whenever this function is called, qctx_destroy() must be called
5429 1.3 christos * when leaving the scope or freeing the qctx.
5430 1.1 christos */
5431 1.1 christos static void
5432 1.23 christos qctx_init(ns_client_t *client, dns_fetchresponse_t **frespp,
5433 1.23 christos dns_rdatatype_t qtype, query_ctx_t *qctx) {
5434 1.1 christos REQUIRE(qctx != NULL);
5435 1.1 christos REQUIRE(client != NULL);
5436 1.1 christos
5437 1.3 christos memset(qctx, 0, sizeof(*qctx));
5438 1.3 christos
5439 1.1 christos /* Set this first so CCTRACE will work */
5440 1.1 christos qctx->client = client;
5441 1.9 christos
5442 1.3 christos dns_view_attach(client->view, &qctx->view);
5443 1.1 christos
5444 1.3 christos CCTRACE(ISC_LOG_DEBUG(3), "qctx_init");
5445 1.1 christos
5446 1.23 christos if (frespp != NULL) {
5447 1.23 christos qctx->fresp = *frespp;
5448 1.23 christos *frespp = NULL;
5449 1.11 christos } else {
5450 1.23 christos qctx->fresp = NULL;
5451 1.11 christos }
5452 1.1 christos qctx->qtype = qctx->type = qtype;
5453 1.1 christos qctx->result = ISC_R_SUCCESS;
5454 1.3 christos qctx->findcoveringnsec = qctx->view->synthfromdnssec;
5455 1.3 christos
5456 1.16 christos /*
5457 1.16 christos * If it's an RRSIG or SIG query, we'll iterate the node.
5458 1.16 christos */
5459 1.16 christos if (qctx->qtype == dns_rdatatype_rrsig ||
5460 1.16 christos qctx->qtype == dns_rdatatype_sig)
5461 1.16 christos {
5462 1.16 christos qctx->type = dns_rdatatype_any;
5463 1.16 christos }
5464 1.16 christos
5465 1.3 christos CALL_HOOK_NORETURN(NS_QUERY_QCTX_INITIALIZED, qctx);
5466 1.1 christos }
5467 1.1 christos
5468 1.1 christos /*%
5469 1.1 christos * Clean up and disassociate the rdataset and node pointers in qctx.
5470 1.1 christos */
5471 1.1 christos static void
5472 1.1 christos qctx_clean(query_ctx_t *qctx) {
5473 1.9 christos if (qctx->rdataset != NULL && dns_rdataset_isassociated(qctx->rdataset))
5474 1.1 christos {
5475 1.1 christos dns_rdataset_disassociate(qctx->rdataset);
5476 1.1 christos }
5477 1.1 christos if (qctx->sigrdataset != NULL &&
5478 1.16 christos dns_rdataset_isassociated(qctx->sigrdataset))
5479 1.16 christos {
5480 1.1 christos dns_rdataset_disassociate(qctx->sigrdataset);
5481 1.1 christos }
5482 1.1 christos if (qctx->db != NULL && qctx->node != NULL) {
5483 1.1 christos dns_db_detachnode(qctx->db, &qctx->node);
5484 1.1 christos }
5485 1.24 christos if (qctx->client != NULL && qctx->client->query.gluedb != NULL) {
5486 1.24 christos dns_db_detach(&qctx->client->query.gluedb);
5487 1.24 christos }
5488 1.1 christos }
5489 1.1 christos
5490 1.1 christos /*%
5491 1.1 christos * Free any allocated memory associated with qctx.
5492 1.1 christos */
5493 1.1 christos static void
5494 1.1 christos qctx_freedata(query_ctx_t *qctx) {
5495 1.1 christos if (qctx->rdataset != NULL) {
5496 1.3 christos ns_client_putrdataset(qctx->client, &qctx->rdataset);
5497 1.1 christos }
5498 1.1 christos
5499 1.1 christos if (qctx->sigrdataset != NULL) {
5500 1.3 christos ns_client_putrdataset(qctx->client, &qctx->sigrdataset);
5501 1.1 christos }
5502 1.1 christos
5503 1.1 christos if (qctx->fname != NULL) {
5504 1.3 christos ns_client_releasename(qctx->client, &qctx->fname);
5505 1.1 christos }
5506 1.1 christos
5507 1.1 christos if (qctx->db != NULL) {
5508 1.1 christos INSIST(qctx->node == NULL);
5509 1.1 christos dns_db_detach(&qctx->db);
5510 1.1 christos }
5511 1.1 christos
5512 1.1 christos if (qctx->zone != NULL) {
5513 1.1 christos dns_zone_detach(&qctx->zone);
5514 1.1 christos }
5515 1.1 christos
5516 1.1 christos if (qctx->zdb != NULL) {
5517 1.3 christos ns_client_putrdataset(qctx->client, &qctx->zsigrdataset);
5518 1.3 christos ns_client_putrdataset(qctx->client, &qctx->zrdataset);
5519 1.3 christos ns_client_releasename(qctx->client, &qctx->zfname);
5520 1.3 christos dns_db_detachnode(qctx->zdb, &qctx->znode);
5521 1.1 christos dns_db_detach(&qctx->zdb);
5522 1.22 christos qctx->zversion = NULL;
5523 1.1 christos }
5524 1.1 christos
5525 1.23 christos if (qctx->fresp != NULL) {
5526 1.23 christos free_fresp(qctx->client, &qctx->fresp);
5527 1.1 christos }
5528 1.1 christos }
5529 1.1 christos
5530 1.3 christos static void
5531 1.3 christos qctx_destroy(query_ctx_t *qctx) {
5532 1.3 christos CALL_HOOK_NORETURN(NS_QUERY_QCTX_DESTROYED, qctx);
5533 1.3 christos
5534 1.3 christos dns_view_detach(&qctx->view);
5535 1.3 christos }
5536 1.3 christos
5537 1.20 christos /*
5538 1.20 christos * Call SAVE but set 'a' to NULL first so as not to assert.
5539 1.20 christos */
5540 1.20 christos #define INITANDSAVE(a, b) \
5541 1.20 christos do { \
5542 1.20 christos a = NULL; \
5543 1.20 christos SAVE(a, b); \
5544 1.20 christos } while (0)
5545 1.20 christos
5546 1.20 christos /*
5547 1.20 christos * "save" qctx data from 'src' to 'tgt'.
5548 1.20 christos * It essentially moves ownership of the data from src to tgt, so the former
5549 1.20 christos * becomes unusable except for final cleanup (such as by qctx_destroy).
5550 1.20 christos * Note: this function doesn't attach to the client's handle. It's the caller's
5551 1.20 christos * responsibility to do it if it's necessary.
5552 1.20 christos */
5553 1.20 christos static void
5554 1.20 christos qctx_save(query_ctx_t *src, query_ctx_t *tgt) {
5555 1.20 christos /* First copy all fields in a straightforward way */
5556 1.20 christos *tgt = *src;
5557 1.20 christos
5558 1.20 christos /* Then "move" pointers (except client and view) */
5559 1.20 christos INITANDSAVE(tgt->dbuf, src->dbuf);
5560 1.20 christos INITANDSAVE(tgt->fname, src->fname);
5561 1.20 christos INITANDSAVE(tgt->tname, src->tname);
5562 1.20 christos INITANDSAVE(tgt->rdataset, src->rdataset);
5563 1.20 christos INITANDSAVE(tgt->sigrdataset, src->sigrdataset);
5564 1.20 christos INITANDSAVE(tgt->noqname, src->noqname);
5565 1.23 christos INITANDSAVE(tgt->fresp, src->fresp);
5566 1.20 christos INITANDSAVE(tgt->db, src->db);
5567 1.20 christos INITANDSAVE(tgt->version, src->version);
5568 1.20 christos INITANDSAVE(tgt->node, src->node);
5569 1.20 christos INITANDSAVE(tgt->zdb, src->zdb);
5570 1.20 christos INITANDSAVE(tgt->znode, src->znode);
5571 1.20 christos INITANDSAVE(tgt->zfname, src->zfname);
5572 1.20 christos INITANDSAVE(tgt->zversion, src->zversion);
5573 1.20 christos INITANDSAVE(tgt->zrdataset, src->zrdataset);
5574 1.20 christos INITANDSAVE(tgt->zsigrdataset, src->zsigrdataset);
5575 1.20 christos INITANDSAVE(tgt->rpz_st, src->rpz_st);
5576 1.20 christos INITANDSAVE(tgt->zone, src->zone);
5577 1.20 christos
5578 1.20 christos /* View has to stay in 'src' for qctx_destroy. */
5579 1.20 christos tgt->view = NULL;
5580 1.20 christos dns_view_attach(src->view, &tgt->view);
5581 1.20 christos }
5582 1.20 christos
5583 1.1 christos /*%
5584 1.1 christos * Log detailed information about the query immediately after
5585 1.1 christos * the client request or a return from recursion.
5586 1.1 christos */
5587 1.1 christos static void
5588 1.1 christos query_trace(query_ctx_t *qctx) {
5589 1.1 christos #ifdef WANT_QUERYTRACE
5590 1.6 christos char mbuf[2 * DNS_NAME_FORMATSIZE];
5591 1.1 christos char qbuf[DNS_NAME_FORMATSIZE];
5592 1.1 christos
5593 1.9 christos if (qctx->client->query.origqname != NULL) {
5594 1.1 christos dns_name_format(qctx->client->query.origqname, qbuf,
5595 1.1 christos sizeof(qbuf));
5596 1.9 christos } else {
5597 1.1 christos snprintf(qbuf, sizeof(qbuf), "<unset>");
5598 1.9 christos }
5599 1.1 christos
5600 1.1 christos snprintf(mbuf, sizeof(mbuf) - 1,
5601 1.1 christos "client attr:0x%x, query attr:0x%X, restarts:%u, "
5602 1.1 christos "origqname:%s, timer:%d, authdb:%d, referral:%d",
5603 1.9 christos qctx->client->attributes, qctx->client->query.attributes,
5604 1.1 christos qctx->client->query.restarts, qbuf,
5605 1.9 christos (int)qctx->client->query.timerset,
5606 1.9 christos (int)qctx->client->query.authdbset,
5607 1.9 christos (int)qctx->client->query.isreferral);
5608 1.1 christos CCTRACE(ISC_LOG_DEBUG(3), mbuf);
5609 1.9 christos #else /* ifdef WANT_QUERYTRACE */
5610 1.1 christos UNUSED(qctx);
5611 1.9 christos #endif /* ifdef WANT_QUERYTRACE */
5612 1.1 christos }
5613 1.1 christos
5614 1.1 christos /*
5615 1.1 christos * Set up query processing for the current query of 'client'.
5616 1.1 christos * Calls qctx_init() to initialize a query context, checks
5617 1.1 christos * the SERVFAIL cache, then hands off processing to ns__query_start().
5618 1.1 christos *
5619 1.1 christos * This is called only from ns_query_start(), to begin a query
5620 1.1 christos * for the first time. Restarting an existing query (for
5621 1.1 christos * instance, to handle CNAME lookups), is done by calling
5622 1.1 christos * ns__query_start() again with the same query context. Resuming from
5623 1.1 christos * recursion is handled by query_resume().
5624 1.1 christos */
5625 1.23 christos static void
5626 1.1 christos query_setup(ns_client_t *client, dns_rdatatype_t qtype) {
5627 1.20 christos isc_result_t result = ISC_R_UNSET;
5628 1.1 christos query_ctx_t qctx;
5629 1.1 christos
5630 1.1 christos qctx_init(client, NULL, qtype, &qctx);
5631 1.1 christos query_trace(&qctx);
5632 1.1 christos
5633 1.3 christos CALL_HOOK(NS_QUERY_SETUP, &qctx);
5634 1.3 christos
5635 1.1 christos /*
5636 1.1 christos * Check SERVFAIL cache
5637 1.1 christos */
5638 1.1 christos result = ns__query_sfcache(&qctx);
5639 1.1 christos if (result != ISC_R_COMPLETE) {
5640 1.23 christos goto cleanup;
5641 1.1 christos }
5642 1.1 christos
5643 1.23 christos (void)ns__query_start(&qctx);
5644 1.3 christos
5645 1.9 christos cleanup:
5646 1.3 christos qctx_destroy(&qctx);
5647 1.1 christos }
5648 1.1 christos
5649 1.3 christos static bool
5650 1.1 christos get_root_key_sentinel_id(query_ctx_t *qctx, const char *ndata) {
5651 1.1 christos unsigned int v = 0;
5652 1.1 christos int i;
5653 1.1 christos
5654 1.1 christos for (i = 0; i < 5; i++) {
5655 1.14 christos if (!isdigit((unsigned char)ndata[i])) {
5656 1.23 christos return false;
5657 1.1 christos }
5658 1.1 christos v *= 10;
5659 1.1 christos v += ndata[i] - '0';
5660 1.1 christos }
5661 1.1 christos if (v > 65535U) {
5662 1.23 christos return false;
5663 1.1 christos }
5664 1.1 christos qctx->client->query.root_key_sentinel_keyid = v;
5665 1.23 christos return true;
5666 1.1 christos }
5667 1.1 christos
5668 1.1 christos /*%
5669 1.1 christos * Find out if the query is for a root key sentinel and if so, record the type
5670 1.1 christos * of root key sentinel query and the key id that is being checked for.
5671 1.1 christos *
5672 1.1 christos * The code is assuming a zero padded decimal field of width 5.
5673 1.1 christos */
5674 1.1 christos static void
5675 1.1 christos root_key_sentinel_detect(query_ctx_t *qctx) {
5676 1.1 christos const char *ndata = (const char *)qctx->client->query.qname->ndata;
5677 1.1 christos
5678 1.1 christos if (qctx->client->query.qname->length > 30 && ndata[0] == 29 &&
5679 1.1 christos strncasecmp(ndata + 1, "root-key-sentinel-is-ta-", 24) == 0)
5680 1.1 christos {
5681 1.1 christos if (!get_root_key_sentinel_id(qctx, ndata + 25)) {
5682 1.1 christos return;
5683 1.1 christos }
5684 1.3 christos qctx->client->query.root_key_sentinel_is_ta = true;
5685 1.1 christos /*
5686 1.9 christos * Simplify processing by disabling aggressive
5687 1.1 christos * negative caching.
5688 1.1 christos */
5689 1.3 christos qctx->findcoveringnsec = false;
5690 1.1 christos ns_client_log(qctx->client, NS_LOGCATEGORY_TAT,
5691 1.1 christos NS_LOGMODULE_QUERY, ISC_LOG_INFO,
5692 1.1 christos "root-key-sentinel-is-ta query label found");
5693 1.1 christos } else if (qctx->client->query.qname->length > 31 && ndata[0] == 30 &&
5694 1.1 christos strncasecmp(ndata + 1, "root-key-sentinel-not-ta-", 25) == 0)
5695 1.1 christos {
5696 1.1 christos if (!get_root_key_sentinel_id(qctx, ndata + 26)) {
5697 1.1 christos return;
5698 1.1 christos }
5699 1.3 christos qctx->client->query.root_key_sentinel_not_ta = true;
5700 1.1 christos /*
5701 1.9 christos * Simplify processing by disabling aggressive
5702 1.1 christos * negative caching.
5703 1.1 christos */
5704 1.3 christos qctx->findcoveringnsec = false;
5705 1.1 christos ns_client_log(qctx->client, NS_LOGCATEGORY_TAT,
5706 1.1 christos NS_LOGMODULE_QUERY, ISC_LOG_INFO,
5707 1.1 christos "root-key-sentinel-not-ta query label found");
5708 1.1 christos }
5709 1.1 christos }
5710 1.1 christos
5711 1.1 christos /*%
5712 1.1 christos * Starting point for a client query or a chaining query.
5713 1.1 christos *
5714 1.1 christos * Called first by query_setup(), and then again as often as needed to
5715 1.1 christos * follow a CNAME chain. Determines which authoritative database to
5716 1.1 christos * search, then hands off processing to query_lookup().
5717 1.1 christos */
5718 1.1 christos isc_result_t
5719 1.1 christos ns__query_start(query_ctx_t *qctx) {
5720 1.20 christos isc_result_t result = ISC_R_UNSET;
5721 1.1 christos CCTRACE(ISC_LOG_DEBUG(3), "ns__query_start");
5722 1.3 christos qctx->want_restart = false;
5723 1.3 christos qctx->authoritative = false;
5724 1.1 christos qctx->version = NULL;
5725 1.1 christos qctx->zversion = NULL;
5726 1.3 christos qctx->need_wildcardproof = false;
5727 1.3 christos qctx->rpz = false;
5728 1.3 christos
5729 1.3 christos CALL_HOOK(NS_QUERY_START_BEGIN, qctx);
5730 1.3 christos
5731 1.3 christos /*
5732 1.23 christos * If we require a server cookie or the presented server
5733 1.23 christos * cookie was bad then send back BADCOOKIE before we have
5734 1.23 christos * done too much work.
5735 1.23 christos */
5736 1.23 christos if (!TCP(qctx->client) &&
5737 1.23 christos (BADCOOKIE(qctx->client) ||
5738 1.23 christos (qctx->view->requireservercookie && WANTCOOKIE(qctx->client) &&
5739 1.23 christos !HAVECOOKIE(qctx->client))))
5740 1.3 christos {
5741 1.3 christos qctx->client->message->flags &= ~DNS_MESSAGEFLAG_AA;
5742 1.3 christos qctx->client->message->flags &= ~DNS_MESSAGEFLAG_AD;
5743 1.3 christos qctx->client->message->rcode = dns_rcode_badcookie;
5744 1.23 christos return ns_query_done(qctx);
5745 1.3 christos }
5746 1.1 christos
5747 1.3 christos if (qctx->view->checknames &&
5748 1.1 christos !dns_rdata_checkowner(qctx->client->query.qname,
5749 1.9 christos qctx->client->message->rdclass, qctx->qtype,
5750 1.9 christos false))
5751 1.1 christos {
5752 1.1 christos char namebuf[DNS_NAME_FORMATSIZE];
5753 1.3 christos char typebuf[DNS_RDATATYPE_FORMATSIZE];
5754 1.3 christos char classbuf[DNS_RDATACLASS_FORMATSIZE];
5755 1.1 christos
5756 1.9 christos dns_name_format(qctx->client->query.qname, namebuf,
5757 1.9 christos sizeof(namebuf));
5758 1.3 christos dns_rdatatype_format(qctx->qtype, typebuf, sizeof(typebuf));
5759 1.9 christos dns_rdataclass_format(qctx->client->message->rdclass, classbuf,
5760 1.9 christos sizeof(classbuf));
5761 1.1 christos ns_client_log(qctx->client, DNS_LOGCATEGORY_SECURITY,
5762 1.1 christos NS_LOGMODULE_QUERY, ISC_LOG_ERROR,
5763 1.9 christos "check-names failure %s/%s/%s", namebuf, typebuf,
5764 1.9 christos classbuf);
5765 1.1 christos QUERY_ERROR(qctx, DNS_R_REFUSED);
5766 1.23 christos return ns_query_done(qctx);
5767 1.1 christos }
5768 1.1 christos
5769 1.1 christos /*
5770 1.1 christos * Setup for root key sentinel processing.
5771 1.1 christos */
5772 1.3 christos if (qctx->view->root_key_sentinel &&
5773 1.1 christos qctx->client->query.restarts == 0 &&
5774 1.1 christos (qctx->qtype == dns_rdatatype_a ||
5775 1.1 christos qctx->qtype == dns_rdatatype_aaaa) &&
5776 1.1 christos (qctx->client->message->flags & DNS_MESSAGEFLAG_CD) == 0)
5777 1.1 christos {
5778 1.9 christos root_key_sentinel_detect(qctx);
5779 1.1 christos }
5780 1.1 christos
5781 1.1 christos /*
5782 1.23 christos * First we must find the right database. Reset the options but preserve
5783 1.23 christos * the 'nolog' flag.
5784 1.1 christos */
5785 1.23 christos qctx->options = (dns_getdb_options_t){ .nolog = qctx->options.nolog };
5786 1.1 christos if (dns_rdatatype_atparent(qctx->qtype) &&
5787 1.1 christos !dns_name_equal(qctx->client->query.qname, dns_rootname))
5788 1.1 christos {
5789 1.1 christos /*
5790 1.1 christos * If authoritative data for this QTYPE is supposed to live in
5791 1.1 christos * the parent zone, do not look for an exact match for QNAME,
5792 1.1 christos * but rather for its containing zone (unless the QNAME is
5793 1.1 christos * root).
5794 1.1 christos */
5795 1.23 christos qctx->options.noexact = true;
5796 1.1 christos }
5797 1.1 christos
5798 1.1 christos result = query_getdb(qctx->client, qctx->client->query.qname,
5799 1.9 christos qctx->qtype, qctx->options, &qctx->zone, &qctx->db,
5800 1.9 christos &qctx->version, &qctx->is_zone);
5801 1.20 christos if ((result != ISC_R_SUCCESS || !qctx->is_zone) &&
5802 1.20 christos qctx->qtype == dns_rdatatype_ds && !RECURSIONOK(qctx->client) &&
5803 1.23 christos qctx->options.noexact)
5804 1.1 christos {
5805 1.1 christos /*
5806 1.1 christos * This is a non-recursive QTYPE=DS query with QNAME whose
5807 1.1 christos * parent we are not authoritative for. Check whether we are
5808 1.1 christos * authoritative for QNAME, because if so, we need to send a
5809 1.1 christos * "no data" response as required by RFC 4035, section 3.1.4.1.
5810 1.1 christos */
5811 1.1 christos dns_db_t *tdb = NULL;
5812 1.1 christos dns_zone_t *tzone = NULL;
5813 1.1 christos dns_dbversion_t *tversion = NULL;
5814 1.1 christos isc_result_t tresult;
5815 1.1 christos
5816 1.23 christos dns_getdb_options_t options = { .partial = true };
5817 1.9 christos tresult = query_getzonedb(
5818 1.9 christos qctx->client, qctx->client->query.qname, qctx->qtype,
5819 1.23 christos options, &tzone, &tdb, &tversion);
5820 1.1 christos if (tresult == ISC_R_SUCCESS) {
5821 1.1 christos /*
5822 1.1 christos * We are authoritative for QNAME. Attach the relevant
5823 1.1 christos * zone to query context, set result to ISC_R_SUCCESS.
5824 1.1 christos */
5825 1.23 christos qctx->options.noexact = false;
5826 1.3 christos ns_client_putrdataset(qctx->client, &qctx->rdataset);
5827 1.1 christos if (qctx->db != NULL) {
5828 1.1 christos dns_db_detach(&qctx->db);
5829 1.1 christos }
5830 1.1 christos if (qctx->zone != NULL) {
5831 1.1 christos dns_zone_detach(&qctx->zone);
5832 1.1 christos }
5833 1.1 christos qctx->version = NULL;
5834 1.1 christos RESTORE(qctx->version, tversion);
5835 1.1 christos RESTORE(qctx->db, tdb);
5836 1.1 christos RESTORE(qctx->zone, tzone);
5837 1.3 christos qctx->is_zone = true;
5838 1.1 christos result = ISC_R_SUCCESS;
5839 1.1 christos } else {
5840 1.1 christos /*
5841 1.1 christos * We are not authoritative for QNAME. Clean up and
5842 1.1 christos * leave result as it was.
5843 1.1 christos */
5844 1.1 christos if (tdb != NULL) {
5845 1.1 christos dns_db_detach(&tdb);
5846 1.1 christos }
5847 1.1 christos if (tzone != NULL) {
5848 1.1 christos dns_zone_detach(&tzone);
5849 1.1 christos }
5850 1.1 christos }
5851 1.1 christos }
5852 1.1 christos /*
5853 1.1 christos * If we did not find a database from which we can answer the query,
5854 1.1 christos * respond with either REFUSED or SERVFAIL, depending on what the
5855 1.1 christos * result of query_getdb() was.
5856 1.1 christos */
5857 1.1 christos if (result != ISC_R_SUCCESS) {
5858 1.1 christos if (result == DNS_R_REFUSED) {
5859 1.1 christos if (WANTRECURSION(qctx->client)) {
5860 1.24 christos dns_ede_add(&qctx->client->edectx,
5861 1.24 christos DNS_EDE_NOTAUTH,
5862 1.24 christos "recursion disabled");
5863 1.1 christos inc_stats(qctx->client,
5864 1.1 christos ns_statscounter_recurserej);
5865 1.1 christos } else {
5866 1.1 christos inc_stats(qctx->client,
5867 1.1 christos ns_statscounter_authrej);
5868 1.1 christos }
5869 1.1 christos if (!PARTIALANSWER(qctx->client)) {
5870 1.1 christos QUERY_ERROR(qctx, DNS_R_REFUSED);
5871 1.1 christos }
5872 1.1 christos } else {
5873 1.9 christos CCTRACE(ISC_LOG_ERROR, "ns__query_start: query_getdb "
5874 1.9 christos "failed");
5875 1.3 christos QUERY_ERROR(qctx, result);
5876 1.1 christos }
5877 1.23 christos return ns_query_done(qctx);
5878 1.1 christos }
5879 1.1 christos
5880 1.1 christos /*
5881 1.1 christos * We found a database from which we can answer the query. Update
5882 1.1 christos * relevant query context flags if the answer is to be prepared using
5883 1.1 christos * authoritative data.
5884 1.1 christos */
5885 1.3 christos qctx->is_staticstub_zone = false;
5886 1.1 christos if (qctx->is_zone) {
5887 1.3 christos qctx->authoritative = true;
5888 1.3 christos if (qctx->zone != NULL) {
5889 1.3 christos if (dns_zone_gettype(qctx->zone) == dns_zone_mirror) {
5890 1.3 christos qctx->authoritative = false;
5891 1.3 christos }
5892 1.9 christos if (dns_zone_gettype(qctx->zone) == dns_zone_staticstub)
5893 1.3 christos {
5894 1.3 christos qctx->is_staticstub_zone = true;
5895 1.3 christos }
5896 1.1 christos }
5897 1.1 christos }
5898 1.1 christos
5899 1.1 christos /*
5900 1.1 christos * Attach to the database which will be used to prepare the answer.
5901 1.1 christos * Update query statistics.
5902 1.1 christos */
5903 1.23 christos if (qctx->fresp == NULL && qctx->client->query.restarts == 0) {
5904 1.1 christos if (qctx->is_zone) {
5905 1.1 christos if (qctx->zone != NULL) {
5906 1.1 christos /*
5907 1.1 christos * if is_zone = true, zone = NULL then this is
5908 1.1 christos * a DLZ zone. Don't attempt to attach zone.
5909 1.1 christos */
5910 1.1 christos dns_zone_attach(qctx->zone,
5911 1.1 christos &qctx->client->query.authzone);
5912 1.1 christos }
5913 1.1 christos dns_db_attach(qctx->db, &qctx->client->query.authdb);
5914 1.1 christos }
5915 1.3 christos qctx->client->query.authdbset = true;
5916 1.1 christos
5917 1.1 christos /* Track TCP vs UDP stats per zone */
5918 1.1 christos if (TCP(qctx->client)) {
5919 1.1 christos inc_stats(qctx->client, ns_statscounter_tcp);
5920 1.1 christos } else {
5921 1.1 christos inc_stats(qctx->client, ns_statscounter_udp);
5922 1.1 christos }
5923 1.1 christos }
5924 1.1 christos
5925 1.25 christos /*
5926 1.25 christos * If stale answers are enabled and stale-answer-client-timeout is zero,
5927 1.25 christos * then we can promptly answer with a stale RRset if one is available in
5928 1.25 christos * cache.
5929 1.25 christos */
5930 1.25 christos qctx->options.stalefirst = (!qctx->is_zone &&
5931 1.25 christos qctx->view->staleanswerclienttimeout == 0 &&
5932 1.25 christos dns_view_staleanswerenabled(qctx->view));
5933 1.11 christos
5934 1.11 christos result = query_lookup(qctx);
5935 1.11 christos
5936 1.11 christos /*
5937 1.11 christos * Clear "look-also-for-stale-data" flag.
5938 1.11 christos * If a fetch is created to resolve this query, then,
5939 1.11 christos * when it completes, this option is not expected to be set.
5940 1.11 christos */
5941 1.23 christos qctx->options.stalefirst = false;
5942 1.3 christos
5943 1.9 christos cleanup:
5944 1.23 christos return result;
5945 1.23 christos }
5946 1.23 christos
5947 1.23 christos static void
5948 1.23 christos async_restart(void *arg) {
5949 1.23 christos query_ctx_t *qctx = arg;
5950 1.23 christos ns_client_t *client = qctx->client;
5951 1.23 christos isc_nmhandle_t *handle = client->restarthandle;
5952 1.23 christos
5953 1.23 christos client->restarthandle = NULL;
5954 1.23 christos
5955 1.23 christos ns__query_start(qctx);
5956 1.23 christos
5957 1.23 christos qctx_clean(qctx);
5958 1.23 christos qctx_freedata(qctx);
5959 1.23 christos qctx_destroy(qctx);
5960 1.23 christos isc_mem_put(client->manager->mctx, qctx, sizeof(*qctx));
5961 1.23 christos isc_nmhandle_detach(&handle);
5962 1.1 christos }
5963 1.1 christos
5964 1.11 christos /*
5965 1.11 christos * Allocate buffers in 'qctx' used to store query results.
5966 1.11 christos *
5967 1.11 christos * 'buffer' must be a pointer to an object whose lifetime
5968 1.11 christos * doesn't expire while 'qctx' is in use.
5969 1.11 christos */
5970 1.11 christos static isc_result_t
5971 1.11 christos qctx_prepare_buffers(query_ctx_t *qctx, isc_buffer_t *buffer) {
5972 1.11 christos REQUIRE(qctx != NULL);
5973 1.11 christos REQUIRE(qctx->client != NULL);
5974 1.11 christos REQUIRE(buffer != NULL);
5975 1.11 christos
5976 1.11 christos qctx->dbuf = ns_client_getnamebuf(qctx->client);
5977 1.11 christos qctx->fname = ns_client_newname(qctx->client, qctx->dbuf, buffer);
5978 1.11 christos qctx->rdataset = ns_client_newrdataset(qctx->client);
5979 1.11 christos
5980 1.11 christos if ((WANTDNSSEC(qctx->client) || qctx->findcoveringnsec) &&
5981 1.11 christos (!qctx->is_zone || dns_db_issecure(qctx->db)))
5982 1.11 christos {
5983 1.11 christos qctx->sigrdataset = ns_client_newrdataset(qctx->client);
5984 1.11 christos }
5985 1.11 christos
5986 1.23 christos return ISC_R_SUCCESS;
5987 1.11 christos }
5988 1.11 christos
5989 1.1 christos /*%
5990 1.17 christos * Depending on the db lookup result, we can respond to the
5991 1.17 christos * client this stale answer.
5992 1.17 christos */
5993 1.17 christos static bool
5994 1.17 christos stale_client_answer(isc_result_t result) {
5995 1.17 christos switch (result) {
5996 1.17 christos case ISC_R_SUCCESS:
5997 1.17 christos case DNS_R_EMPTYNAME:
5998 1.17 christos case DNS_R_NXRRSET:
5999 1.17 christos case DNS_R_NCACHENXRRSET:
6000 1.17 christos case DNS_R_CNAME:
6001 1.17 christos case DNS_R_DNAME:
6002 1.23 christos return true;
6003 1.17 christos default:
6004 1.23 christos return false;
6005 1.17 christos }
6006 1.17 christos
6007 1.17 christos UNREACHABLE();
6008 1.17 christos }
6009 1.17 christos
6010 1.17 christos /*%
6011 1.1 christos * Perform a local database lookup, in either an authoritative or
6012 1.3 christos * cache database. If unable to answer, call ns_query_done(); otherwise
6013 1.1 christos * hand off processing to query_gotanswer().
6014 1.1 christos */
6015 1.1 christos static isc_result_t
6016 1.1 christos query_lookup(query_ctx_t *qctx) {
6017 1.11 christos isc_buffer_t buffer;
6018 1.11 christos isc_result_t result = ISC_R_UNSET;
6019 1.1 christos dns_clientinfomethods_t cm;
6020 1.1 christos dns_clientinfo_t ci;
6021 1.1 christos dns_name_t *rpzqname = NULL;
6022 1.13 christos char namebuf[DNS_NAME_FORMATSIZE];
6023 1.23 christos char typebuf[DNS_RDATATYPE_FORMATSIZE];
6024 1.1 christos unsigned int dboptions;
6025 1.11 christos dns_ttl_t stale_refresh = 0;
6026 1.11 christos bool dbfind_stale = false;
6027 1.13 christos bool stale_timeout = false;
6028 1.16 christos bool answer_found = false;
6029 1.11 christos bool stale_found = false;
6030 1.11 christos bool stale_refresh_window = false;
6031 1.20 christos uint16_t ede = 0;
6032 1.1 christos
6033 1.1 christos CCTRACE(ISC_LOG_DEBUG(3), "query_lookup");
6034 1.1 christos
6035 1.3 christos CALL_HOOK(NS_QUERY_LOOKUP_BEGIN, qctx);
6036 1.1 christos
6037 1.1 christos dns_clientinfomethods_init(&cm, ns_client_sourceip);
6038 1.20 christos dns_clientinfo_init(&ci, qctx->client, NULL);
6039 1.20 christos if (HAVEECS(qctx->client)) {
6040 1.20 christos dns_clientinfo_setecs(&ci, &qctx->client->ecs);
6041 1.20 christos }
6042 1.1 christos
6043 1.1 christos /*
6044 1.1 christos * We'll need some resources...
6045 1.1 christos */
6046 1.11 christos result = qctx_prepare_buffers(qctx, &buffer);
6047 1.11 christos if (result != ISC_R_SUCCESS) {
6048 1.11 christos QUERY_ERROR(qctx, result);
6049 1.23 christos return ns_query_done(qctx);
6050 1.1 christos }
6051 1.1 christos
6052 1.1 christos /*
6053 1.1 christos * Now look for an answer in the database.
6054 1.1 christos */
6055 1.1 christos if (qctx->dns64 && qctx->rpz) {
6056 1.1 christos rpzqname = qctx->client->query.rpz_st->p_name;
6057 1.1 christos } else {
6058 1.1 christos rpzqname = qctx->client->query.qname;
6059 1.1 christos }
6060 1.1 christos
6061 1.25 christos qctx->client->query.dboptions &= ~DNS_DBFIND_STALETIMEOUT;
6062 1.25 christos
6063 1.25 christos if (qctx->options.stalefirst && !qctx->is_zone) {
6064 1.11 christos /*
6065 1.23 christos * If the 'stalefirst' flag is set, it means that a stale
6066 1.11 christos * RRset may be returned as part of this lookup. An attempt
6067 1.11 christos * to refresh the RRset will still take place if an
6068 1.11 christos * active RRset is not available.
6069 1.11 christos */
6070 1.13 christos qctx->client->query.dboptions |= DNS_DBFIND_STALETIMEOUT;
6071 1.11 christos }
6072 1.11 christos
6073 1.1 christos dboptions = qctx->client->query.dboptions;
6074 1.1 christos if (!qctx->is_zone && qctx->findcoveringnsec &&
6075 1.1 christos (qctx->type != dns_rdatatype_null || !dns_name_istat(rpzqname)))
6076 1.9 christos {
6077 1.1 christos dboptions |= DNS_DBFIND_COVERINGNSEC;
6078 1.9 christos }
6079 1.1 christos
6080 1.11 christos (void)dns_db_getservestalerefresh(qctx->client->view->cachedb,
6081 1.11 christos &stale_refresh);
6082 1.11 christos if (stale_refresh > 0 &&
6083 1.16 christos dns_view_staleanswerenabled(qctx->client->view))
6084 1.16 christos {
6085 1.11 christos dboptions |= DNS_DBFIND_STALEENABLED;
6086 1.11 christos }
6087 1.11 christos
6088 1.1 christos result = dns_db_findext(qctx->db, rpzqname, qctx->version, qctx->type,
6089 1.1 christos dboptions, qctx->client->now, &qctx->node,
6090 1.9 christos qctx->fname, &cm, &ci, qctx->rdataset,
6091 1.9 christos qctx->sigrdataset);
6092 1.1 christos
6093 1.1 christos /*
6094 1.1 christos * Fixup fname and sigrdataset.
6095 1.1 christos */
6096 1.1 christos if (qctx->dns64 && qctx->rpz) {
6097 1.20 christos dns_name_copy(qctx->client->query.qname, qctx->fname);
6098 1.1 christos if (qctx->sigrdataset != NULL &&
6099 1.16 christos dns_rdataset_isassociated(qctx->sigrdataset))
6100 1.16 christos {
6101 1.1 christos dns_rdataset_disassociate(qctx->sigrdataset);
6102 1.1 christos }
6103 1.1 christos }
6104 1.1 christos
6105 1.1 christos if (!qctx->is_zone) {
6106 1.3 christos dns_cache_updatestats(qctx->view->cache, result);
6107 1.1 christos }
6108 1.1 christos
6109 1.11 christos /*
6110 1.11 christos * If DNS_DBFIND_STALEOK is set this means we are dealing with a
6111 1.11 christos * lookup following a failed lookup and it is okay to serve a stale
6112 1.11 christos * answer. This will (re)start the 'stale-refresh-time' window in
6113 1.11 christos * rbtdb, tracking the last time the RRset lookup failed.
6114 1.11 christos */
6115 1.11 christos dbfind_stale = ((dboptions & DNS_DBFIND_STALEOK) != 0);
6116 1.11 christos
6117 1.11 christos /*
6118 1.11 christos * If DNS_DBFIND_STALEENABLED is set, this may be a normal lookup, but
6119 1.11 christos * we are allowed to immediately respond with a stale answer if the
6120 1.11 christos * request is within the 'stale-refresh-time' window.
6121 1.11 christos */
6122 1.11 christos stale_refresh_window = (STALE_WINDOW(qctx->rdataset) &&
6123 1.11 christos (dboptions & DNS_DBFIND_STALEENABLED) != 0);
6124 1.11 christos
6125 1.11 christos /*
6126 1.13 christos * If DNS_DBFIND_STALETIMEOUT is set, a stale answer is requested.
6127 1.11 christos * This can happen if 'stale-answer-client-timeout' is enabled.
6128 1.11 christos *
6129 1.23 christos * If a stale answer is found, send it to the client, and try to refresh
6130 1.23 christos * the RRset.
6131 1.11 christos */
6132 1.13 christos stale_timeout = ((dboptions & DNS_DBFIND_STALETIMEOUT) != 0);
6133 1.11 christos
6134 1.16 christos if (dns_rdataset_isassociated(qctx->rdataset) &&
6135 1.16 christos dns_rdataset_count(qctx->rdataset) > 0 && !STALE(qctx->rdataset))
6136 1.16 christos {
6137 1.16 christos /* Found non-stale usable rdataset. */
6138 1.16 christos answer_found = true;
6139 1.16 christos }
6140 1.16 christos
6141 1.13 christos if (dbfind_stale || stale_refresh_window || stale_timeout) {
6142 1.13 christos dns_name_format(qctx->client->query.qname, namebuf,
6143 1.13 christos sizeof(namebuf));
6144 1.23 christos dns_rdatatype_format(qctx->qtype, typebuf, sizeof(typebuf));
6145 1.1 christos
6146 1.11 christos inc_stats(qctx->client, ns_statscounter_trystale);
6147 1.11 christos
6148 1.1 christos if (dns_rdataset_isassociated(qctx->rdataset) &&
6149 1.1 christos dns_rdataset_count(qctx->rdataset) > 0 &&
6150 1.9 christos STALE(qctx->rdataset))
6151 1.9 christos {
6152 1.20 christos stale_found = true;
6153 1.20 christos if (result == DNS_R_NCACHENXDOMAIN ||
6154 1.20 christos result == DNS_R_NXDOMAIN)
6155 1.20 christos {
6156 1.20 christos ede = DNS_EDE_STALENXANSWER;
6157 1.20 christos } else {
6158 1.20 christos ede = DNS_EDE_STALEANSWER;
6159 1.20 christos }
6160 1.3 christos qctx->rdataset->ttl = qctx->view->staleanswerttl;
6161 1.14 christos inc_stats(qctx->client, ns_statscounter_usedstale);
6162 1.1 christos } else {
6163 1.11 christos stale_found = false;
6164 1.1 christos }
6165 1.13 christos }
6166 1.1 christos
6167 1.13 christos if (dbfind_stale) {
6168 1.13 christos isc_log_write(ns_lctx, NS_LOGCATEGORY_SERVE_STALE,
6169 1.13 christos NS_LOGMODULE_QUERY, ISC_LOG_INFO,
6170 1.23 christos "%s %s resolver failure, stale answer %s (%s)",
6171 1.23 christos namebuf, typebuf,
6172 1.23 christos stale_found ? "used" : "unavailable",
6173 1.23 christos isc_result_totext(result));
6174 1.20 christos if (stale_found) {
6175 1.24 christos dns_ede_add(&qctx->client->edectx, ede,
6176 1.24 christos "resolver failure");
6177 1.20 christos } else if (!answer_found) {
6178 1.13 christos /*
6179 1.13 christos * Resolver failure, no stale data, nothing more we
6180 1.13 christos * can do, return SERVFAIL.
6181 1.13 christos */
6182 1.13 christos QUERY_ERROR(qctx, DNS_R_SERVFAIL);
6183 1.23 christos return ns_query_done(qctx);
6184 1.13 christos }
6185 1.13 christos } else if (stale_refresh_window) {
6186 1.13 christos /*
6187 1.13 christos * A recent lookup failed, so during this time window we are
6188 1.13 christos * allowed to return stale data immediately.
6189 1.13 christos */
6190 1.13 christos isc_log_write(ns_lctx, NS_LOGCATEGORY_SERVE_STALE,
6191 1.13 christos NS_LOGMODULE_QUERY, ISC_LOG_INFO,
6192 1.23 christos "%s %s query within stale refresh time, stale "
6193 1.23 christos "answer %s (%s)",
6194 1.23 christos namebuf, typebuf,
6195 1.23 christos stale_found ? "used" : "unavailable",
6196 1.23 christos isc_result_totext(result));
6197 1.11 christos
6198 1.20 christos if (stale_found) {
6199 1.24 christos dns_ede_add(&qctx->client->edectx, ede,
6200 1.24 christos "query within stale refresh time window");
6201 1.20 christos } else if (!answer_found) {
6202 1.11 christos /*
6203 1.13 christos * During the stale refresh window explicitly do not try
6204 1.13 christos * to refresh the data, because a recent lookup failed.
6205 1.11 christos */
6206 1.13 christos QUERY_ERROR(qctx, DNS_R_SERVFAIL);
6207 1.23 christos return ns_query_done(qctx);
6208 1.13 christos }
6209 1.13 christos } else if (stale_timeout) {
6210 1.23 christos if (qctx->options.stalefirst) {
6211 1.24 christos /*
6212 1.24 christos * If 'qctx->zdb' is set, this was a cache lookup after
6213 1.24 christos * an authoritative lookup returned a delegation (in
6214 1.24 christos * order to find a better answer). But we still can
6215 1.24 christos * return without getting any usable answer here, as
6216 1.24 christos * query_notfound() should handle it from here.
6217 1.24 christos * Otherwise, if nothing useful was found in cache then
6218 1.24 christos * recursively call query_lookup() again without the
6219 1.24 christos * 'stalefirst' option set.
6220 1.24 christos */
6221 1.24 christos if (!stale_found && !answer_found && qctx->zdb == NULL)
6222 1.24 christos {
6223 1.13 christos qctx_clean(qctx);
6224 1.13 christos qctx_freedata(qctx);
6225 1.13 christos dns_db_attach(qctx->client->view->cachedb,
6226 1.13 christos &qctx->db);
6227 1.23 christos qctx->options.stalefirst = false;
6228 1.23 christos if (FETCH_RECTYPE_NORMAL(qctx->client) != NULL)
6229 1.23 christos {
6230 1.13 christos dns_resolver_destroyfetch(
6231 1.23 christos &FETCH_RECTYPE_NORMAL(
6232 1.23 christos qctx->client));
6233 1.11 christos }
6234 1.23 christos return query_lookup(qctx);
6235 1.17 christos } else if (stale_client_answer(result)) {
6236 1.11 christos /*
6237 1.13 christos * Immediately return the stale answer, start a
6238 1.13 christos * resolver fetch to refresh the data in cache.
6239 1.11 christos */
6240 1.11 christos isc_log_write(
6241 1.11 christos ns_lctx, NS_LOGCATEGORY_SERVE_STALE,
6242 1.11 christos NS_LOGMODULE_QUERY, ISC_LOG_INFO,
6243 1.23 christos "%s %s stale answer used, an attempt "
6244 1.23 christos "to refresh the RRset will still be "
6245 1.23 christos "made",
6246 1.23 christos namebuf, typebuf);
6247 1.15 christos qctx->refresh_rrset = STALE(qctx->rdataset);
6248 1.20 christos if (stale_found) {
6249 1.24 christos dns_ede_add(
6250 1.24 christos &qctx->client->edectx, ede,
6251 1.20 christos "stale data prioritized over "
6252 1.20 christos "lookup");
6253 1.20 christos }
6254 1.13 christos }
6255 1.13 christos } else {
6256 1.23 christos UNREACHABLE();
6257 1.1 christos }
6258 1.11 christos }
6259 1.11 christos
6260 1.16 christos if (stale_timeout && (answer_found || stale_found)) {
6261 1.11 christos /*
6262 1.13 christos * Mark RRsets that we are adding to the client message on a
6263 1.13 christos * lookup during 'stale-answer-client-timeout', so we can
6264 1.13 christos * clean it up if needed when we resume from recursion.
6265 1.11 christos */
6266 1.13 christos qctx->client->query.attributes |= NS_QUERYATTR_STALEOK;
6267 1.13 christos qctx->rdataset->attributes |= DNS_RDATASETATTR_STALE_ADDED;
6268 1.11 christos }
6269 1.14 christos
6270 1.11 christos result = query_gotanswer(qctx, result);
6271 1.11 christos
6272 1.9 christos cleanup:
6273 1.23 christos return result;
6274 1.1 christos }
6275 1.1 christos
6276 1.1 christos /*
6277 1.13 christos * Clear all rdatasets from the message that are in the given section and
6278 1.13 christos * that have the 'attr' attribute set.
6279 1.13 christos */
6280 1.13 christos static void
6281 1.13 christos message_clearrdataset(dns_message_t *msg, unsigned int attr) {
6282 1.13 christos unsigned int i;
6283 1.13 christos dns_name_t *name, *next_name;
6284 1.13 christos dns_rdataset_t *rds, *next_rds;
6285 1.13 christos
6286 1.13 christos /*
6287 1.13 christos * Clean up name lists by calling the rdataset disassociate function.
6288 1.13 christos */
6289 1.13 christos for (i = DNS_SECTION_ANSWER; i < DNS_SECTION_MAX; i++) {
6290 1.13 christos name = ISC_LIST_HEAD(msg->sections[i]);
6291 1.13 christos while (name != NULL) {
6292 1.13 christos next_name = ISC_LIST_NEXT(name, link);
6293 1.13 christos
6294 1.13 christos rds = ISC_LIST_HEAD(name->list);
6295 1.13 christos while (rds != NULL) {
6296 1.13 christos next_rds = ISC_LIST_NEXT(rds, link);
6297 1.13 christos if ((rds->attributes & attr) != attr) {
6298 1.13 christos rds = next_rds;
6299 1.13 christos continue;
6300 1.13 christos }
6301 1.13 christos ISC_LIST_UNLINK(name->list, rds, link);
6302 1.13 christos INSIST(dns_rdataset_isassociated(rds));
6303 1.13 christos dns_rdataset_disassociate(rds);
6304 1.13 christos isc_mempool_put(msg->rdspool, rds);
6305 1.13 christos rds = next_rds;
6306 1.13 christos }
6307 1.13 christos
6308 1.13 christos if (ISC_LIST_EMPTY(name->list)) {
6309 1.13 christos ISC_LIST_UNLINK(msg->sections[i], name, link);
6310 1.13 christos if (dns_name_dynamic(name)) {
6311 1.13 christos dns_name_free(name, msg->mctx);
6312 1.13 christos }
6313 1.13 christos isc_mempool_put(msg->namepool, name);
6314 1.13 christos }
6315 1.13 christos
6316 1.13 christos name = next_name;
6317 1.13 christos }
6318 1.13 christos }
6319 1.13 christos }
6320 1.13 christos
6321 1.13 christos /*
6322 1.13 christos * Clear any rdatasets from the client's message that were added on a lookup
6323 1.13 christos * due to a client timeout.
6324 1.13 christos */
6325 1.13 christos static void
6326 1.13 christos query_clear_stale(ns_client_t *client) {
6327 1.13 christos message_clearrdataset(client->message, DNS_RDATASETATTR_STALE_ADDED);
6328 1.13 christos }
6329 1.13 christos
6330 1.13 christos /*
6331 1.11 christos * Event handler to resume processing a query after recursion, or when a
6332 1.11 christos * client timeout is triggered. If the query has timed out or been cancelled
6333 1.11 christos * or the system is shutting down, clean up and exit. If a client timeout is
6334 1.11 christos * triggered, see if we can respond with a stale answer from cache. Otherwise,
6335 1.11 christos * call query_resume() to continue the ongoing work.
6336 1.1 christos */
6337 1.1 christos static void
6338 1.23 christos fetch_callback(void *arg) {
6339 1.23 christos dns_fetchresponse_t *resp = (dns_fetchresponse_t *)arg;
6340 1.23 christos ns_client_t *client = resp->arg;
6341 1.1 christos dns_fetch_t *fetch = NULL;
6342 1.14 christos bool fetch_canceled = false;
6343 1.14 christos isc_logcategory_t *logcategory = NS_LOGCATEGORY_QUERY_ERRORS;
6344 1.1 christos isc_result_t result;
6345 1.1 christos int errorloglevel;
6346 1.11 christos query_ctx_t qctx;
6347 1.1 christos
6348 1.1 christos REQUIRE(NS_CLIENT_VALID(client));
6349 1.1 christos REQUIRE(RECURSING(client));
6350 1.1 christos
6351 1.9 christos CTRACE(ISC_LOG_DEBUG(3), "fetch_callback");
6352 1.9 christos
6353 1.13 christos /*
6354 1.13 christos * We are resuming from recursion. Reset any attributes, options
6355 1.13 christos * that a lookup due to stale-answer-client-timeout may have set.
6356 1.13 christos */
6357 1.13 christos if (client->view->cachedb != NULL && client->view->recursion) {
6358 1.13 christos client->query.attributes |= NS_QUERYATTR_RECURSIONOK;
6359 1.13 christos }
6360 1.13 christos client->query.dboptions &= ~DNS_DBFIND_STALETIMEOUT;
6361 1.13 christos
6362 1.1 christos LOCK(&client->query.fetchlock);
6363 1.23 christos INSIST(FETCH_RECTYPE_NORMAL(client) == resp->fetch ||
6364 1.23 christos FETCH_RECTYPE_NORMAL(client) == NULL);
6365 1.23 christos if (FETCH_RECTYPE_NORMAL(client) != NULL) {
6366 1.1 christos /*
6367 1.1 christos * This is the fetch we've been waiting for.
6368 1.1 christos */
6369 1.23 christos INSIST(FETCH_RECTYPE_NORMAL(client) == resp->fetch);
6370 1.23 christos FETCH_RECTYPE_NORMAL(client) = NULL;
6371 1.14 christos
6372 1.1 christos /*
6373 1.1 christos * Update client->now.
6374 1.1 christos */
6375 1.23 christos client->now = isc_stdtime_now();
6376 1.1 christos } else {
6377 1.1 christos /*
6378 1.1 christos * This is a fetch completion event for a canceled fetch.
6379 1.1 christos * Clean up and don't resume the find.
6380 1.1 christos */
6381 1.3 christos fetch_canceled = true;
6382 1.1 christos }
6383 1.1 christos UNLOCK(&client->query.fetchlock);
6384 1.1 christos
6385 1.23 christos SAVE(fetch, resp->fetch);
6386 1.9 christos
6387 1.9 christos /*
6388 1.9 christos * We're done recursing, detach from quota and unlink from
6389 1.9 christos * the manager's recursing-clients list.
6390 1.9 christos */
6391 1.23 christos release_recursionquota(client);
6392 1.9 christos
6393 1.23 christos isc_nmhandle_detach(&HANDLE_RECTYPE_NORMAL(client));
6394 1.11 christos
6395 1.1 christos client->query.attributes &= ~NS_QUERYATTR_RECURSING;
6396 1.9 christos client->state = NS_CLIENTSTATE_WORKING;
6397 1.1 christos
6398 1.1 christos /*
6399 1.11 christos * Initialize a new qctx and use it to either resume from
6400 1.11 christos * recursion or clean up after cancelation. Transfer
6401 1.23 christos * ownership of resp to the new qctx in the process.
6402 1.1 christos */
6403 1.23 christos qctx_init(client, &resp, 0, &qctx);
6404 1.11 christos
6405 1.23 christos if (fetch_canceled) {
6406 1.11 christos /*
6407 1.11 christos * We've timed out or are shutting down. We can now
6408 1.11 christos * free the event and other resources held by qctx, but
6409 1.11 christos * don't call qctx_destroy() yet: it might destroy the
6410 1.11 christos * client, which we still need for a moment.
6411 1.11 christos */
6412 1.11 christos qctx_freedata(&qctx);
6413 1.11 christos
6414 1.11 christos /*
6415 1.23 christos * Return an error to the client.
6416 1.11 christos */
6417 1.23 christos CTRACE(ISC_LOG_ERROR, "fetch cancelled");
6418 1.23 christos query_error(client, DNS_R_SERVFAIL, __LINE__);
6419 1.11 christos
6420 1.11 christos /*
6421 1.11 christos * Free any persistent plugin data that was allocated to
6422 1.11 christos * service the client, then detach the client object.
6423 1.11 christos */
6424 1.11 christos qctx.detach_client = true;
6425 1.11 christos qctx_destroy(&qctx);
6426 1.1 christos } else {
6427 1.3 christos /*
6428 1.11 christos * Resume the find process.
6429 1.3 christos */
6430 1.1 christos query_trace(&qctx);
6431 1.1 christos
6432 1.1 christos result = query_resume(&qctx);
6433 1.1 christos if (result != ISC_R_SUCCESS) {
6434 1.1 christos if (result == DNS_R_SERVFAIL) {
6435 1.1 christos errorloglevel = ISC_LOG_DEBUG(2);
6436 1.1 christos } else {
6437 1.1 christos errorloglevel = ISC_LOG_DEBUG(4);
6438 1.1 christos }
6439 1.1 christos if (isc_log_wouldlog(ns_lctx, errorloglevel)) {
6440 1.1 christos dns_resolver_logfetch(fetch, ns_lctx,
6441 1.1 christos logcategory,
6442 1.1 christos NS_LOGMODULE_QUERY,
6443 1.3 christos errorloglevel, false);
6444 1.1 christos }
6445 1.1 christos }
6446 1.3 christos
6447 1.3 christos qctx_destroy(&qctx);
6448 1.1 christos }
6449 1.1 christos
6450 1.1 christos dns_resolver_destroyfetch(&fetch);
6451 1.1 christos }
6452 1.1 christos
6453 1.1 christos /*%
6454 1.1 christos * Check whether the recursion parameters in 'param' match the current query's
6455 1.1 christos * recursion parameters provided in 'qtype', 'qname', and 'qdomain'.
6456 1.1 christos */
6457 1.3 christos static bool
6458 1.1 christos recparam_match(const ns_query_recparam_t *param, dns_rdatatype_t qtype,
6459 1.9 christos const dns_name_t *qname, const dns_name_t *qdomain) {
6460 1.1 christos REQUIRE(param != NULL);
6461 1.1 christos
6462 1.23 christos return param->qtype == qtype && param->qname != NULL && qname != NULL &&
6463 1.23 christos param->qdomain != NULL && qdomain != NULL &&
6464 1.23 christos dns_name_equal(param->qname, qname) &&
6465 1.23 christos dns_name_equal(param->qdomain, qdomain);
6466 1.1 christos }
6467 1.1 christos
6468 1.1 christos /*%
6469 1.1 christos * Update 'param' with current query's recursion parameters provided in
6470 1.1 christos * 'qtype', 'qname', and 'qdomain'.
6471 1.1 christos */
6472 1.1 christos static void
6473 1.1 christos recparam_update(ns_query_recparam_t *param, dns_rdatatype_t qtype,
6474 1.9 christos const dns_name_t *qname, const dns_name_t *qdomain) {
6475 1.1 christos REQUIRE(param != NULL);
6476 1.1 christos
6477 1.1 christos param->qtype = qtype;
6478 1.1 christos
6479 1.1 christos if (qname == NULL) {
6480 1.1 christos param->qname = NULL;
6481 1.1 christos } else {
6482 1.3 christos param->qname = dns_fixedname_initname(¶m->fqname);
6483 1.20 christos dns_name_copy(qname, param->qname);
6484 1.1 christos }
6485 1.1 christos
6486 1.1 christos if (qdomain == NULL) {
6487 1.1 christos param->qdomain = NULL;
6488 1.1 christos } else {
6489 1.3 christos param->qdomain = dns_fixedname_initname(¶m->fqdomain);
6490 1.20 christos dns_name_copy(qdomain, param->qdomain);
6491 1.1 christos }
6492 1.1 christos }
6493 1.23 christos
6494 1.23 christos static void
6495 1.23 christos recursionquota_log(ns_client_t *client, atomic_uint_fast32_t *last_log_time,
6496 1.23 christos const char *format, isc_quota_t *quota) {
6497 1.23 christos isc_stdtime_t now = isc_stdtime_now();
6498 1.23 christos if (now == atomic_load_relaxed(last_log_time)) {
6499 1.23 christos return;
6500 1.23 christos }
6501 1.23 christos
6502 1.23 christos atomic_store_relaxed(last_log_time, now);
6503 1.23 christos ns_client_log(client, NS_LOGCATEGORY_CLIENT, NS_LOGMODULE_QUERY,
6504 1.23 christos ISC_LOG_WARNING, format, isc_quota_getused(quota),
6505 1.23 christos isc_quota_getsoft(quota), isc_quota_getmax(quota));
6506 1.23 christos }
6507 1.23 christos
6508 1.9 christos static atomic_uint_fast32_t last_soft, last_hard;
6509 1.1 christos
6510 1.20 christos /*%
6511 1.23 christos * Acquire recursion quota before making the current client "recursing".
6512 1.20 christos */
6513 1.20 christos static isc_result_t
6514 1.23 christos acquire_recursionquota(ns_client_t *client) {
6515 1.23 christos isc_result_t result;
6516 1.23 christos
6517 1.23 christos result = recursionquotatype_attach_soft(client);
6518 1.23 christos switch (result) {
6519 1.23 christos case ISC_R_SOFTQUOTA:
6520 1.23 christos recursionquota_log(client, &last_soft,
6521 1.23 christos "recursive-clients soft limit exceeded "
6522 1.23 christos "(%u/%u/%u), aborting oldest query",
6523 1.23 christos &client->manager->sctx->recursionquota);
6524 1.23 christos ns_client_killoldestquery(client);
6525 1.23 christos FALLTHROUGH;
6526 1.23 christos case ISC_R_SUCCESS:
6527 1.23 christos break;
6528 1.23 christos case ISC_R_QUOTA:
6529 1.23 christos recursionquota_log(client, &last_hard,
6530 1.23 christos "no more recursive clients (%u/%u/%u)",
6531 1.23 christos &client->manager->sctx->recursionquota);
6532 1.23 christos ns_client_killoldestquery(client);
6533 1.23 christos return result;
6534 1.23 christos default:
6535 1.23 christos UNREACHABLE();
6536 1.23 christos }
6537 1.23 christos
6538 1.23 christos dns_message_clonebuffer(client->message);
6539 1.23 christos ns_client_recursing(client);
6540 1.23 christos
6541 1.23 christos return ISC_R_SUCCESS;
6542 1.23 christos }
6543 1.1 christos
6544 1.23 christos /*%
6545 1.23 christos * Release recursion quota and remove the client from the "recursing" list.
6546 1.23 christos */
6547 1.23 christos static void
6548 1.23 christos release_recursionquota(ns_client_t *client) {
6549 1.23 christos recursionquotatype_detach(client);
6550 1.9 christos
6551 1.23 christos LOCK(&client->manager->reclock);
6552 1.23 christos if (ISC_LINK_LINKED(client, rlink)) {
6553 1.23 christos ISC_LIST_UNLINK(client->manager->recursing, client, rlink);
6554 1.1 christos }
6555 1.23 christos UNLOCK(&client->manager->reclock);
6556 1.20 christos }
6557 1.20 christos
6558 1.20 christos isc_result_t
6559 1.20 christos ns_query_recurse(ns_client_t *client, dns_rdatatype_t qtype, dns_name_t *qname,
6560 1.20 christos dns_name_t *qdomain, dns_rdataset_t *nameservers,
6561 1.20 christos bool resuming) {
6562 1.20 christos isc_result_t result;
6563 1.20 christos dns_rdataset_t *rdataset, *sigrdataset;
6564 1.20 christos isc_sockaddr_t *peeraddr = NULL;
6565 1.20 christos
6566 1.20 christos CTRACE(ISC_LOG_DEBUG(3), "ns_query_recurse");
6567 1.20 christos
6568 1.20 christos /*
6569 1.20 christos * Check recursion parameters from the previous query to see if they
6570 1.20 christos * match. If not, update recursion parameters and proceed.
6571 1.20 christos */
6572 1.20 christos if (recparam_match(&client->query.recparam, qtype, qname, qdomain)) {
6573 1.20 christos ns_client_log(client, NS_LOGCATEGORY_CLIENT, NS_LOGMODULE_QUERY,
6574 1.20 christos ISC_LOG_INFO, "recursion loop detected");
6575 1.23 christos return ISC_R_FAILURE;
6576 1.20 christos }
6577 1.20 christos
6578 1.20 christos recparam_update(&client->query.recparam, qtype, qname, qdomain);
6579 1.20 christos
6580 1.20 christos if (!resuming) {
6581 1.20 christos inc_stats(client, ns_statscounter_recursion);
6582 1.20 christos }
6583 1.20 christos
6584 1.23 christos result = acquire_recursionquota(client);
6585 1.20 christos if (result != ISC_R_SUCCESS) {
6586 1.23 christos return result;
6587 1.20 christos }
6588 1.20 christos
6589 1.1 christos /*
6590 1.1 christos * Invoke the resolver.
6591 1.1 christos */
6592 1.1 christos REQUIRE(nameservers == NULL || nameservers->type == dns_rdatatype_ns);
6593 1.23 christos REQUIRE(FETCH_RECTYPE_NORMAL(client) == NULL);
6594 1.1 christos
6595 1.3 christos rdataset = ns_client_newrdataset(client);
6596 1.1 christos
6597 1.1 christos if (WANTDNSSEC(client)) {
6598 1.3 christos sigrdataset = ns_client_newrdataset(client);
6599 1.1 christos } else {
6600 1.1 christos sigrdataset = NULL;
6601 1.1 christos }
6602 1.1 christos
6603 1.10 christos if (!client->query.timerset) {
6604 1.1 christos ns_client_settimeout(client, 60);
6605 1.1 christos }
6606 1.1 christos
6607 1.1 christos if (!TCP(client)) {
6608 1.1 christos peeraddr = &client->peeraddr;
6609 1.1 christos }
6610 1.1 christos
6611 1.23 christos isc_nmhandle_attach(client->handle, &HANDLE_RECTYPE_NORMAL(client));
6612 1.9 christos result = dns_resolver_createfetch(
6613 1.9 christos client->view->resolver, qname, qtype, qdomain, nameservers,
6614 1.9 christos NULL, peeraddr, client->message->id, client->query.fetchoptions,
6615 1.24 christos 0, NULL, client->query.qc, client->manager->loop,
6616 1.24 christos fetch_callback, client, &client->edectx, rdataset, sigrdataset,
6617 1.24 christos &FETCH_RECTYPE_NORMAL(client));
6618 1.1 christos if (result != ISC_R_SUCCESS) {
6619 1.23 christos release_recursionquota(client);
6620 1.23 christos
6621 1.3 christos ns_client_putrdataset(client, &rdataset);
6622 1.1 christos if (sigrdataset != NULL) {
6623 1.3 christos ns_client_putrdataset(client, &sigrdataset);
6624 1.1 christos }
6625 1.23 christos
6626 1.23 christos isc_nmhandle_detach(&HANDLE_RECTYPE_NORMAL(client));
6627 1.1 christos }
6628 1.1 christos
6629 1.1 christos /*
6630 1.1 christos * We're now waiting for a fetch event. A client which is
6631 1.1 christos * shutting down will not be destroyed until all the events
6632 1.1 christos * have been received.
6633 1.1 christos */
6634 1.1 christos
6635 1.23 christos return result;
6636 1.1 christos }
6637 1.1 christos
6638 1.1 christos /*%
6639 1.1 christos * Restores the query context after resuming from recursion, and
6640 1.1 christos * continues the query processing if needed.
6641 1.1 christos */
6642 1.1 christos static isc_result_t
6643 1.1 christos query_resume(query_ctx_t *qctx) {
6644 1.20 christos isc_result_t result = ISC_R_UNSET;
6645 1.1 christos dns_name_t *tname;
6646 1.1 christos isc_buffer_t b;
6647 1.1 christos #ifdef WANT_QUERYTRACE
6648 1.6 christos char mbuf[4 * DNS_NAME_FORMATSIZE];
6649 1.1 christos char qbuf[DNS_NAME_FORMATSIZE];
6650 1.1 christos char tbuf[DNS_RDATATYPE_FORMATSIZE];
6651 1.9 christos #endif /* ifdef WANT_QUERYTRACE */
6652 1.9 christos
6653 1.9 christos CCTRACE(ISC_LOG_DEBUG(3), "query_resume");
6654 1.1 christos
6655 1.3 christos CALL_HOOK(NS_QUERY_RESUME_BEGIN, qctx);
6656 1.3 christos
6657 1.3 christos qctx->want_restart = false;
6658 1.1 christos
6659 1.1 christos qctx->rpz_st = qctx->client->query.rpz_st;
6660 1.1 christos if (qctx->rpz_st != NULL &&
6661 1.16 christos (qctx->rpz_st->state & DNS_RPZ_RECURSING) != 0)
6662 1.16 christos {
6663 1.1 christos CCTRACE(ISC_LOG_DEBUG(3), "resume from RPZ recursion");
6664 1.1 christos #ifdef WANT_QUERYTRACE
6665 1.1 christos {
6666 1.1 christos char pbuf[DNS_NAME_FORMATSIZE] = "<unset>";
6667 1.1 christos char fbuf[DNS_NAME_FORMATSIZE] = "<unset>";
6668 1.9 christos if (qctx->rpz_st->r_name != NULL) {
6669 1.9 christos dns_name_format(qctx->rpz_st->r_name, qbuf,
6670 1.9 christos sizeof(qbuf));
6671 1.9 christos } else {
6672 1.9 christos snprintf(qbuf, sizeof(qbuf), "<unset>");
6673 1.9 christos }
6674 1.9 christos if (qctx->rpz_st->p_name != NULL) {
6675 1.9 christos dns_name_format(qctx->rpz_st->p_name, pbuf,
6676 1.9 christos sizeof(pbuf));
6677 1.9 christos }
6678 1.9 christos if (qctx->rpz_st->fname != NULL) {
6679 1.9 christos dns_name_format(qctx->rpz_st->fname, fbuf,
6680 1.9 christos sizeof(fbuf));
6681 1.9 christos }
6682 1.1 christos
6683 1.1 christos snprintf(mbuf, sizeof(mbuf) - 1,
6684 1.9 christos "rpz rname:%s, pname:%s, qctx->fname:%s", qbuf,
6685 1.9 christos pbuf, fbuf);
6686 1.1 christos CCTRACE(ISC_LOG_DEBUG(3), mbuf);
6687 1.1 christos }
6688 1.9 christos #endif /* ifdef WANT_QUERYTRACE */
6689 1.1 christos
6690 1.1 christos qctx->is_zone = qctx->rpz_st->q.is_zone;
6691 1.1 christos qctx->authoritative = qctx->rpz_st->q.authoritative;
6692 1.1 christos RESTORE(qctx->zone, qctx->rpz_st->q.zone);
6693 1.1 christos RESTORE(qctx->node, qctx->rpz_st->q.node);
6694 1.1 christos RESTORE(qctx->db, qctx->rpz_st->q.db);
6695 1.1 christos RESTORE(qctx->rdataset, qctx->rpz_st->q.rdataset);
6696 1.1 christos RESTORE(qctx->sigrdataset, qctx->rpz_st->q.sigrdataset);
6697 1.1 christos qctx->qtype = qctx->rpz_st->q.qtype;
6698 1.1 christos
6699 1.23 christos if (qctx->fresp->node != NULL) {
6700 1.23 christos dns_db_detachnode(qctx->fresp->db, &qctx->fresp->node);
6701 1.9 christos }
6702 1.23 christos SAVE(qctx->rpz_st->r.db, qctx->fresp->db);
6703 1.23 christos qctx->rpz_st->r.r_type = qctx->fresp->qtype;
6704 1.23 christos SAVE(qctx->rpz_st->r.r_rdataset, qctx->fresp->rdataset);
6705 1.23 christos ns_client_putrdataset(qctx->client, &qctx->fresp->sigrdataset);
6706 1.1 christos } else if (REDIRECT(qctx->client)) {
6707 1.1 christos /*
6708 1.1 christos * Restore saved state.
6709 1.1 christos */
6710 1.9 christos CCTRACE(ISC_LOG_DEBUG(3), "resume from redirect recursion");
6711 1.1 christos #ifdef WANT_QUERYTRACE
6712 1.9 christos dns_name_format(qctx->client->query.redirect.fname, qbuf,
6713 1.9 christos sizeof(qbuf));
6714 1.9 christos dns_rdatatype_format(qctx->client->query.redirect.qtype, tbuf,
6715 1.9 christos sizeof(tbuf));
6716 1.1 christos snprintf(mbuf, sizeof(mbuf) - 1,
6717 1.9 christos "redirect qctx->fname:%s, qtype:%s, auth:%d", qbuf,
6718 1.9 christos tbuf, qctx->client->query.redirect.authoritative);
6719 1.1 christos CCTRACE(ISC_LOG_DEBUG(3), mbuf);
6720 1.9 christos #endif /* ifdef WANT_QUERYTRACE */
6721 1.1 christos qctx->qtype = qctx->client->query.redirect.qtype;
6722 1.1 christos INSIST(qctx->client->query.redirect.rdataset != NULL);
6723 1.1 christos RESTORE(qctx->rdataset, qctx->client->query.redirect.rdataset);
6724 1.1 christos RESTORE(qctx->sigrdataset,
6725 1.1 christos qctx->client->query.redirect.sigrdataset);
6726 1.1 christos RESTORE(qctx->db, qctx->client->query.redirect.db);
6727 1.1 christos RESTORE(qctx->node, qctx->client->query.redirect.node);
6728 1.1 christos RESTORE(qctx->zone, qctx->client->query.redirect.zone);
6729 1.1 christos qctx->authoritative =
6730 1.1 christos qctx->client->query.redirect.authoritative;
6731 1.1 christos
6732 1.1 christos /*
6733 1.1 christos * Free resources used while recursing.
6734 1.1 christos */
6735 1.23 christos ns_client_putrdataset(qctx->client, &qctx->fresp->rdataset);
6736 1.23 christos ns_client_putrdataset(qctx->client, &qctx->fresp->sigrdataset);
6737 1.23 christos if (qctx->fresp->node != NULL) {
6738 1.23 christos dns_db_detachnode(qctx->fresp->db, &qctx->fresp->node);
6739 1.9 christos }
6740 1.23 christos if (qctx->fresp->db != NULL) {
6741 1.23 christos dns_db_detach(&qctx->fresp->db);
6742 1.9 christos }
6743 1.1 christos } else {
6744 1.9 christos CCTRACE(ISC_LOG_DEBUG(3), "resume from normal recursion");
6745 1.3 christos qctx->authoritative = false;
6746 1.1 christos
6747 1.23 christos qctx->qtype = qctx->fresp->qtype;
6748 1.23 christos SAVE(qctx->db, qctx->fresp->db);
6749 1.23 christos SAVE(qctx->node, qctx->fresp->node);
6750 1.23 christos SAVE(qctx->rdataset, qctx->fresp->rdataset);
6751 1.23 christos SAVE(qctx->sigrdataset, qctx->fresp->sigrdataset);
6752 1.1 christos }
6753 1.1 christos INSIST(qctx->rdataset != NULL);
6754 1.1 christos
6755 1.1 christos if (qctx->qtype == dns_rdatatype_rrsig ||
6756 1.16 christos qctx->qtype == dns_rdatatype_sig)
6757 1.16 christos {
6758 1.1 christos qctx->type = dns_rdatatype_any;
6759 1.1 christos } else {
6760 1.1 christos qctx->type = qctx->qtype;
6761 1.1 christos }
6762 1.1 christos
6763 1.3 christos CALL_HOOK(NS_QUERY_RESUME_RESTORED, qctx);
6764 1.3 christos
6765 1.1 christos if (DNS64(qctx->client)) {
6766 1.1 christos qctx->client->query.attributes &= ~NS_QUERYATTR_DNS64;
6767 1.3 christos qctx->dns64 = true;
6768 1.1 christos }
6769 1.1 christos
6770 1.1 christos if (DNS64EXCLUDE(qctx->client)) {
6771 1.1 christos qctx->client->query.attributes &= ~NS_QUERYATTR_DNS64EXCLUDE;
6772 1.3 christos qctx->dns64_exclude = true;
6773 1.1 christos }
6774 1.1 christos
6775 1.1 christos if (qctx->rpz_st != NULL &&
6776 1.16 christos (qctx->rpz_st->state & DNS_RPZ_RECURSING) != 0)
6777 1.16 christos {
6778 1.1 christos /*
6779 1.1 christos * Has response policy changed out from under us?
6780 1.1 christos */
6781 1.24 christos if (qctx->view->rpzs == NULL ||
6782 1.24 christos qctx->rpz_st->rpz_ver != qctx->view->rpzs->rpz_ver)
6783 1.24 christos {
6784 1.1 christos ns_client_log(qctx->client, NS_LOGCATEGORY_CLIENT,
6785 1.9 christos NS_LOGMODULE_QUERY, DNS_RPZ_INFO_LEVEL,
6786 1.24 christos "query_resume: RPZ settings out of date "
6787 1.24 christos "after of a reconfiguration");
6788 1.1 christos QUERY_ERROR(qctx, DNS_R_SERVFAIL);
6789 1.23 christos return ns_query_done(qctx);
6790 1.1 christos }
6791 1.1 christos }
6792 1.1 christos
6793 1.1 christos /*
6794 1.1 christos * We'll need some resources...
6795 1.1 christos */
6796 1.3 christos qctx->dbuf = ns_client_getnamebuf(qctx->client);
6797 1.3 christos qctx->fname = ns_client_newname(qctx->client, qctx->dbuf, &b);
6798 1.1 christos
6799 1.1 christos if (qctx->rpz_st != NULL &&
6800 1.16 christos (qctx->rpz_st->state & DNS_RPZ_RECURSING) != 0)
6801 1.16 christos {
6802 1.1 christos tname = qctx->rpz_st->fname;
6803 1.1 christos } else if (REDIRECT(qctx->client)) {
6804 1.1 christos tname = qctx->client->query.redirect.fname;
6805 1.1 christos } else {
6806 1.23 christos tname = qctx->fresp->foundname;
6807 1.1 christos }
6808 1.1 christos
6809 1.20 christos dns_name_copy(tname, qctx->fname);
6810 1.1 christos
6811 1.1 christos if (qctx->rpz_st != NULL &&
6812 1.16 christos (qctx->rpz_st->state & DNS_RPZ_RECURSING) != 0)
6813 1.16 christos {
6814 1.23 christos qctx->rpz_st->r.r_result = qctx->fresp->result;
6815 1.1 christos result = qctx->rpz_st->q.result;
6816 1.23 christos free_fresp(qctx->client, &qctx->fresp);
6817 1.1 christos } else if (REDIRECT(qctx->client)) {
6818 1.1 christos result = qctx->client->query.redirect.result;
6819 1.1 christos } else {
6820 1.23 christos result = qctx->fresp->result;
6821 1.1 christos }
6822 1.1 christos
6823 1.3 christos qctx->resuming = true;
6824 1.1 christos
6825 1.23 christos return query_gotanswer(qctx, result);
6826 1.3 christos
6827 1.9 christos cleanup:
6828 1.23 christos return result;
6829 1.1 christos }
6830 1.1 christos
6831 1.20 christos static void
6832 1.23 christos query_hookresume(void *arg) {
6833 1.23 christos ns_hook_resume_t *rev = (ns_hook_resume_t *)arg;
6834 1.20 christos ns_hookasync_t *hctx = NULL;
6835 1.23 christos ns_client_t *client = rev->arg;
6836 1.20 christos query_ctx_t *qctx = rev->saved_qctx;
6837 1.20 christos bool canceled;
6838 1.20 christos
6839 1.20 christos CTRACE(ISC_LOG_DEBUG(3), "query_hookresume");
6840 1.20 christos
6841 1.20 christos REQUIRE(NS_CLIENT_VALID(client));
6842 1.20 christos
6843 1.20 christos LOCK(&client->query.fetchlock);
6844 1.20 christos if (client->query.hookactx != NULL) {
6845 1.20 christos INSIST(rev->ctx == client->query.hookactx);
6846 1.20 christos client->query.hookactx = NULL;
6847 1.20 christos canceled = false;
6848 1.23 christos client->now = isc_stdtime_now();
6849 1.20 christos } else {
6850 1.20 christos canceled = true;
6851 1.20 christos }
6852 1.20 christos UNLOCK(&client->query.fetchlock);
6853 1.20 christos SAVE(hctx, rev->ctx);
6854 1.20 christos
6855 1.23 christos release_recursionquota(client);
6856 1.20 christos
6857 1.20 christos /*
6858 1.23 christos * The fetch handle should be detached before resuming query processing
6859 1.23 christos * below, since that may trigger another recursion or asynchronous hook
6860 1.23 christos * event.
6861 1.20 christos */
6862 1.23 christos isc_nmhandle_detach(&HANDLE_RECTYPE_HOOK(client));
6863 1.20 christos
6864 1.20 christos client->state = NS_CLIENTSTATE_WORKING;
6865 1.20 christos
6866 1.20 christos if (canceled) {
6867 1.20 christos /*
6868 1.20 christos * Note: unlike fetch_callback, this function doesn't bother
6869 1.20 christos * to check the 'shutdown' condition, as that doesn't seem to
6870 1.20 christos * happen in the latest implementation.
6871 1.20 christos */
6872 1.20 christos query_error(client, DNS_R_SERVFAIL, __LINE__);
6873 1.20 christos
6874 1.20 christos /*
6875 1.20 christos * There's no other place to free/release any data maintained
6876 1.20 christos * in qctx. We need to do it here to prevent leak.
6877 1.20 christos */
6878 1.20 christos qctx_clean(qctx);
6879 1.20 christos qctx_freedata(qctx);
6880 1.20 christos
6881 1.20 christos /*
6882 1.20 christos * As we're almost done with this client, make sure any internal
6883 1.20 christos * resource for hooks will be released (if necessary) via the
6884 1.20 christos * QCTX_DESTROYED hook.
6885 1.20 christos */
6886 1.20 christos qctx->detach_client = true;
6887 1.20 christos } else {
6888 1.20 christos switch (rev->hookpoint) {
6889 1.20 christos case NS_QUERY_SETUP:
6890 1.23 christos query_setup(client, qctx->qtype);
6891 1.20 christos break;
6892 1.20 christos case NS_QUERY_START_BEGIN:
6893 1.20 christos (void)ns__query_start(qctx);
6894 1.20 christos break;
6895 1.20 christos case NS_QUERY_LOOKUP_BEGIN:
6896 1.20 christos (void)query_lookup(qctx);
6897 1.20 christos break;
6898 1.20 christos case NS_QUERY_RESUME_BEGIN:
6899 1.20 christos case NS_QUERY_RESUME_RESTORED:
6900 1.20 christos (void)query_resume(qctx);
6901 1.20 christos break;
6902 1.20 christos case NS_QUERY_GOT_ANSWER_BEGIN:
6903 1.20 christos (void)query_gotanswer(qctx, rev->origresult);
6904 1.20 christos break;
6905 1.20 christos case NS_QUERY_RESPOND_ANY_BEGIN:
6906 1.20 christos (void)query_respond_any(qctx);
6907 1.20 christos break;
6908 1.20 christos case NS_QUERY_ADDANSWER_BEGIN:
6909 1.20 christos (void)query_addanswer(qctx);
6910 1.20 christos break;
6911 1.20 christos case NS_QUERY_NOTFOUND_BEGIN:
6912 1.20 christos (void)query_notfound(qctx);
6913 1.20 christos break;
6914 1.20 christos case NS_QUERY_PREP_DELEGATION_BEGIN:
6915 1.20 christos (void)query_prepare_delegation_response(qctx);
6916 1.20 christos break;
6917 1.20 christos case NS_QUERY_ZONE_DELEGATION_BEGIN:
6918 1.20 christos (void)query_zone_delegation(qctx);
6919 1.20 christos break;
6920 1.20 christos case NS_QUERY_DELEGATION_BEGIN:
6921 1.20 christos (void)query_delegation(qctx);
6922 1.20 christos break;
6923 1.20 christos case NS_QUERY_DELEGATION_RECURSE_BEGIN:
6924 1.20 christos (void)query_delegation_recurse(qctx);
6925 1.20 christos break;
6926 1.20 christos case NS_QUERY_NODATA_BEGIN:
6927 1.20 christos (void)query_nodata(qctx, rev->origresult);
6928 1.20 christos break;
6929 1.20 christos case NS_QUERY_NXDOMAIN_BEGIN:
6930 1.20 christos (void)query_nxdomain(qctx, rev->origresult);
6931 1.20 christos break;
6932 1.20 christos case NS_QUERY_NCACHE_BEGIN:
6933 1.20 christos (void)query_ncache(qctx, rev->origresult);
6934 1.20 christos break;
6935 1.20 christos case NS_QUERY_CNAME_BEGIN:
6936 1.20 christos (void)query_cname(qctx);
6937 1.20 christos break;
6938 1.20 christos case NS_QUERY_DNAME_BEGIN:
6939 1.20 christos (void)query_dname(qctx);
6940 1.20 christos break;
6941 1.20 christos case NS_QUERY_RESPOND_BEGIN:
6942 1.20 christos (void)query_respond(qctx);
6943 1.20 christos break;
6944 1.20 christos case NS_QUERY_PREP_RESPONSE_BEGIN:
6945 1.20 christos (void)query_prepresponse(qctx);
6946 1.20 christos break;
6947 1.20 christos case NS_QUERY_DONE_BEGIN:
6948 1.20 christos case NS_QUERY_DONE_SEND:
6949 1.20 christos (void)ns_query_done(qctx);
6950 1.20 christos break;
6951 1.20 christos
6952 1.20 christos /* Not all hookpoints can use recursion. Catch violations */
6953 1.20 christos case NS_QUERY_RESPOND_ANY_FOUND: /* due to side effect */
6954 1.20 christos case NS_QUERY_NOTFOUND_RECURSE: /* in recursion */
6955 1.20 christos case NS_QUERY_ZEROTTL_RECURSE: /* in recursion */
6956 1.20 christos default: /* catch-all just in case */
6957 1.20 christos INSIST(false);
6958 1.20 christos }
6959 1.20 christos }
6960 1.20 christos
6961 1.23 christos isc_mem_put(hctx->mctx, rev, sizeof(*rev));
6962 1.20 christos hctx->destroy(&hctx);
6963 1.20 christos qctx_destroy(qctx);
6964 1.23 christos isc_mem_put(client->manager->mctx, qctx, sizeof(*qctx));
6965 1.20 christos }
6966 1.20 christos
6967 1.20 christos isc_result_t
6968 1.20 christos ns_query_hookasync(query_ctx_t *qctx, ns_query_starthookasync_t runasync,
6969 1.20 christos void *arg) {
6970 1.20 christos isc_result_t result;
6971 1.20 christos ns_client_t *client = qctx->client;
6972 1.20 christos query_ctx_t *saved_qctx = NULL;
6973 1.20 christos
6974 1.20 christos CTRACE(ISC_LOG_DEBUG(3), "ns_query_hookasync");
6975 1.20 christos
6976 1.20 christos REQUIRE(NS_CLIENT_VALID(client));
6977 1.20 christos REQUIRE(client->query.hookactx == NULL);
6978 1.23 christos REQUIRE(FETCH_RECTYPE_NORMAL(client) == NULL);
6979 1.20 christos
6980 1.23 christos result = acquire_recursionquota(client);
6981 1.20 christos if (result != ISC_R_SUCCESS) {
6982 1.20 christos goto cleanup;
6983 1.20 christos }
6984 1.20 christos
6985 1.23 christos saved_qctx = isc_mem_get(client->manager->mctx, sizeof(*saved_qctx));
6986 1.20 christos qctx_save(qctx, saved_qctx);
6987 1.23 christos result = runasync(saved_qctx, client->manager->mctx, arg,
6988 1.23 christos client->manager->loop, query_hookresume, client,
6989 1.23 christos &client->query.hookactx);
6990 1.20 christos if (result != ISC_R_SUCCESS) {
6991 1.23 christos goto cleanup_and_detach_from_quota;
6992 1.20 christos }
6993 1.20 christos
6994 1.24 christos /* Record that an asynchronous copy of the qctx has been started */
6995 1.24 christos qctx->async = true;
6996 1.24 christos
6997 1.20 christos /*
6998 1.20 christos * Typically the runasync() function will trigger recursion, but
6999 1.20 christos * there is no need to set NS_QUERYATTR_RECURSING. The calling hook
7000 1.20 christos * is expected to return NS_HOOK_RETURN, and the RECURSING
7001 1.20 christos * attribute won't be checked anywhere.
7002 1.20 christos *
7003 1.20 christos * Hook-based asynchronous processing cannot coincide with normal
7004 1.23 christos * recursion. Unlike in ns_query_recurse(), we attach to the handle
7005 1.23 christos * only if 'runasync' succeeds. It should be safe since we're either in
7006 1.23 christos * the client task or pausing it.
7007 1.20 christos */
7008 1.23 christos isc_nmhandle_attach(client->handle, &HANDLE_RECTYPE_HOOK(client));
7009 1.23 christos return ISC_R_SUCCESS;
7010 1.20 christos
7011 1.23 christos cleanup_and_detach_from_quota:
7012 1.23 christos release_recursionquota(client);
7013 1.20 christos cleanup:
7014 1.20 christos /*
7015 1.20 christos * If we fail, send SERVFAIL now. It may be better to let the caller
7016 1.20 christos * decide what to do on failure of this function, but hooks don't have
7017 1.20 christos * access to query_error().
7018 1.20 christos */
7019 1.20 christos query_error(client, DNS_R_SERVFAIL, __LINE__);
7020 1.20 christos
7021 1.20 christos /*
7022 1.20 christos * Free all resource related to the query and set detach_client,
7023 1.20 christos * similar to the cancel case of query_hookresume; the callers will
7024 1.20 christos * simply return on failure of this function, so there's no other
7025 1.20 christos * place for this to prevent leak.
7026 1.20 christos */
7027 1.20 christos if (saved_qctx != NULL) {
7028 1.20 christos qctx_clean(saved_qctx);
7029 1.20 christos qctx_freedata(saved_qctx);
7030 1.20 christos qctx_destroy(saved_qctx);
7031 1.23 christos isc_mem_put(client->manager->mctx, saved_qctx,
7032 1.23 christos sizeof(*saved_qctx));
7033 1.20 christos }
7034 1.20 christos qctx->detach_client = true;
7035 1.23 christos return result;
7036 1.20 christos }
7037 1.20 christos
7038 1.1 christos /*%
7039 1.1 christos * If the query is recursive, check the SERVFAIL cache to see whether
7040 1.1 christos * identical queries have failed recently. If we find a match, and it was
7041 1.1 christos * from a query with CD=1, *or* if the current query has CD=0, then we just
7042 1.1 christos * return SERVFAIL again. This prevents a validation failure from eliciting a
7043 1.1 christos * SERVFAIL response to a CD=1 query.
7044 1.1 christos */
7045 1.1 christos isc_result_t
7046 1.1 christos ns__query_sfcache(query_ctx_t *qctx) {
7047 1.23 christos isc_result_t failcache;
7048 1.3 christos uint32_t flags;
7049 1.1 christos
7050 1.1 christos /*
7051 1.1 christos * The SERVFAIL cache doesn't apply to authoritative queries.
7052 1.1 christos */
7053 1.1 christos if (!RECURSIONOK(qctx->client)) {
7054 1.23 christos return ISC_R_COMPLETE;
7055 1.1 christos }
7056 1.1 christos
7057 1.1 christos flags = 0;
7058 1.1 christos #ifdef ENABLE_AFL
7059 1.23 christos if (qctx->client->manager->sctx->fuzztype == isc_fuzz_resolver) {
7060 1.23 christos failcache = ISC_R_NOTFOUND;
7061 1.23 christos } else
7062 1.23 christos #endif /* ifdef ENABLE_AFL */
7063 1.23 christos {
7064 1.9 christos failcache = dns_badcache_find(
7065 1.9 christos qctx->view->failcache, qctx->client->query.qname,
7066 1.23 christos qctx->qtype, &flags,
7067 1.23 christos isc_time_seconds(&qctx->client->tnow));
7068 1.23 christos }
7069 1.23 christos
7070 1.23 christos if (failcache != ISC_R_SUCCESS) {
7071 1.23 christos return ISC_R_COMPLETE;
7072 1.1 christos }
7073 1.23 christos
7074 1.23 christos if (((flags & NS_FAILCACHE_CD) != 0) ||
7075 1.23 christos ((qctx->client->message->flags & DNS_MESSAGEFLAG_CD) == 0))
7076 1.1 christos {
7077 1.1 christos if (isc_log_wouldlog(ns_lctx, ISC_LOG_DEBUG(1))) {
7078 1.1 christos char namebuf[DNS_NAME_FORMATSIZE];
7079 1.3 christos char typebuf[DNS_RDATATYPE_FORMATSIZE];
7080 1.1 christos
7081 1.9 christos dns_name_format(qctx->client->query.qname, namebuf,
7082 1.9 christos sizeof(namebuf));
7083 1.3 christos dns_rdatatype_format(qctx->qtype, typebuf,
7084 1.3 christos sizeof(typebuf));
7085 1.9 christos ns_client_log(qctx->client, NS_LOGCATEGORY_CLIENT,
7086 1.9 christos NS_LOGMODULE_QUERY, ISC_LOG_DEBUG(1),
7087 1.9 christos "servfail cache hit %s/%s (%s)", namebuf,
7088 1.9 christos typebuf,
7089 1.9 christos ((flags & NS_FAILCACHE_CD) != 0) ? "CD=1"
7090 1.9 christos : "CD="
7091 1.9 christos "0");
7092 1.1 christos }
7093 1.1 christos
7094 1.1 christos qctx->client->attributes |= NS_CLIENTATTR_NOSETFC;
7095 1.1 christos QUERY_ERROR(qctx, DNS_R_SERVFAIL);
7096 1.23 christos return ns_query_done(qctx);
7097 1.23 christos }
7098 1.23 christos
7099 1.23 christos return ISC_R_COMPLETE;
7100 1.23 christos }
7101 1.23 christos
7102 1.23 christos static void
7103 1.23 christos query_trace_rrldrop(query_ctx_t *qctx,
7104 1.23 christos dns_rrl_result_t rrl_result ISC_ATTR_UNUSED) {
7105 1.23 christos if (!LIBNS_RRL_DROP_ENABLED()) {
7106 1.23 christos return;
7107 1.1 christos }
7108 1.1 christos
7109 1.23 christos char peerbuf[ISC_SOCKADDR_FORMATSIZE];
7110 1.23 christos isc_netaddr_t peer;
7111 1.23 christos isc_netaddr_fromsockaddr(&peer, &qctx->client->peeraddr);
7112 1.23 christos isc_netaddr_format(&peer, peerbuf, sizeof(peerbuf));
7113 1.23 christos
7114 1.23 christos char qnamebuf[DNS_NAME_FORMATSIZE];
7115 1.23 christos char fnamebuf[DNS_NAME_FORMATSIZE];
7116 1.23 christos dns_name_format(qctx->client->query.qname, qnamebuf, sizeof(qnamebuf));
7117 1.23 christos dns_name_format(qctx->fname, fnamebuf, sizeof(fnamebuf));
7118 1.23 christos LIBNS_RRL_DROP(peerbuf, qnamebuf, fnamebuf, rrl_result);
7119 1.1 christos }
7120 1.1 christos
7121 1.1 christos /*%
7122 1.1 christos * Handle response rate limiting (RRL).
7123 1.1 christos */
7124 1.1 christos static isc_result_t
7125 1.1 christos query_checkrrl(query_ctx_t *qctx, isc_result_t result) {
7126 1.1 christos /*
7127 1.1 christos * Rate limit these responses to this client.
7128 1.1 christos * Do not delay counting and handling obvious referrals,
7129 1.1 christos * since those won't come here again.
7130 1.1 christos * Delay handling delegations for which we are certain to recurse and
7131 1.1 christos * return here (DNS_R_DELEGATION, not a child of one of our
7132 1.1 christos * own zones, and recursion enabled)
7133 1.1 christos * Don't mess with responses rewritten by RPZ
7134 1.1 christos * Count each response at most once.
7135 1.1 christos */
7136 1.3 christos
7137 1.3 christos /*
7138 1.3 christos * XXXMPA the rrl system tests fails sometimes and RRL_CHECKED
7139 1.3 christos * is set when we are called the second time preventing the
7140 1.3 christos * response being dropped.
7141 1.3 christos */
7142 1.9 christos ns_client_log(
7143 1.9 christos qctx->client, DNS_LOGCATEGORY_RRL, NS_LOGMODULE_QUERY,
7144 1.9 christos ISC_LOG_DEBUG(99),
7145 1.9 christos "rrl=%p, HAVECOOKIE=%u, result=%s, "
7146 1.9 christos "fname=%p(%u), is_zone=%u, RECURSIONOK=%u, "
7147 1.23 christos "query.rpz_st=%p(%u), RRL_CHECKED=%u",
7148 1.9 christos qctx->client->view->rrl, HAVECOOKIE(qctx->client),
7149 1.9 christos isc_result_toid(result), qctx->fname,
7150 1.9 christos qctx->fname != NULL ? dns_name_isabsolute(qctx->fname) : 0,
7151 1.9 christos qctx->is_zone, RECURSIONOK(qctx->client),
7152 1.9 christos qctx->client->query.rpz_st,
7153 1.9 christos qctx->client->query.rpz_st != NULL
7154 1.9 christos ? ((qctx->client->query.rpz_st->state &
7155 1.9 christos DNS_RPZ_REWRITTEN) != 0)
7156 1.9 christos : 0,
7157 1.9 christos (qctx->client->query.attributes & NS_QUERYATTR_RRL_CHECKED) !=
7158 1.9 christos 0);
7159 1.3 christos
7160 1.9 christos if (qctx->view->rrl != NULL && !HAVECOOKIE(qctx->client) &&
7161 1.1 christos ((qctx->fname != NULL && dns_name_isabsolute(qctx->fname)) ||
7162 1.1 christos (result == ISC_R_NOTFOUND && !RECURSIONOK(qctx->client))) &&
7163 1.9 christos !(result == DNS_R_DELEGATION && !qctx->is_zone &&
7164 1.9 christos RECURSIONOK(qctx->client)) &&
7165 1.1 christos (qctx->client->query.rpz_st == NULL ||
7166 1.1 christos (qctx->client->query.rpz_st->state & DNS_RPZ_REWRITTEN) == 0) &&
7167 1.1 christos (qctx->client->query.attributes & NS_QUERYATTR_RRL_CHECKED) == 0)
7168 1.1 christos {
7169 1.1 christos dns_rdataset_t nc_rdataset;
7170 1.3 christos bool wouldlog;
7171 1.1 christos dns_fixedname_t fixed;
7172 1.1 christos const dns_name_t *constname;
7173 1.1 christos char log_buf[DNS_RRL_LOG_BUF_LEN];
7174 1.1 christos isc_result_t nc_result, resp_result;
7175 1.1 christos dns_rrl_result_t rrl_result;
7176 1.1 christos
7177 1.1 christos qctx->client->query.attributes |= NS_QUERYATTR_RRL_CHECKED;
7178 1.1 christos
7179 1.1 christos wouldlog = isc_log_wouldlog(ns_lctx, DNS_RRL_LOG_DROP);
7180 1.1 christos constname = qctx->fname;
7181 1.1 christos if (result == DNS_R_NXDOMAIN) {
7182 1.1 christos /*
7183 1.1 christos * Use the database origin name to rate limit NXDOMAIN
7184 1.1 christos */
7185 1.9 christos if (qctx->db != NULL) {
7186 1.1 christos constname = dns_db_origin(qctx->db);
7187 1.9 christos }
7188 1.1 christos resp_result = result;
7189 1.1 christos } else if (result == DNS_R_NCACHENXDOMAIN &&
7190 1.1 christos qctx->rdataset != NULL &&
7191 1.1 christos dns_rdataset_isassociated(qctx->rdataset) &&
7192 1.1 christos (qctx->rdataset->attributes &
7193 1.9 christos DNS_RDATASETATTR_NEGATIVE) != 0)
7194 1.9 christos {
7195 1.1 christos /*
7196 1.1 christos * Try to use owner name in the negative cache SOA.
7197 1.1 christos */
7198 1.1 christos dns_fixedname_init(&fixed);
7199 1.1 christos dns_rdataset_init(&nc_rdataset);
7200 1.1 christos for (nc_result = dns_rdataset_first(qctx->rdataset);
7201 1.1 christos nc_result == ISC_R_SUCCESS;
7202 1.1 christos nc_result = dns_rdataset_next(qctx->rdataset))
7203 1.1 christos {
7204 1.1 christos dns_ncache_current(qctx->rdataset,
7205 1.1 christos dns_fixedname_name(&fixed),
7206 1.1 christos &nc_rdataset);
7207 1.1 christos if (nc_rdataset.type == dns_rdatatype_soa) {
7208 1.1 christos dns_rdataset_disassociate(&nc_rdataset);
7209 1.1 christos constname = dns_fixedname_name(&fixed);
7210 1.1 christos break;
7211 1.1 christos }
7212 1.1 christos dns_rdataset_disassociate(&nc_rdataset);
7213 1.1 christos }
7214 1.1 christos resp_result = DNS_R_NXDOMAIN;
7215 1.9 christos } else if (result == DNS_R_NXRRSET || result == DNS_R_EMPTYNAME)
7216 1.9 christos {
7217 1.1 christos resp_result = DNS_R_NXRRSET;
7218 1.1 christos } else if (result == DNS_R_DELEGATION) {
7219 1.1 christos resp_result = result;
7220 1.1 christos } else if (result == ISC_R_NOTFOUND) {
7221 1.1 christos /*
7222 1.1 christos * Handle referral to ".", including when recursion
7223 1.1 christos * is off or not requested and the hints have not
7224 1.20 christos * been loaded.
7225 1.1 christos */
7226 1.1 christos constname = dns_rootname;
7227 1.1 christos resp_result = DNS_R_DELEGATION;
7228 1.1 christos } else {
7229 1.1 christos resp_result = ISC_R_SUCCESS;
7230 1.1 christos }
7231 1.1 christos
7232 1.9 christos rrl_result = dns_rrl(
7233 1.15 christos qctx->view, qctx->zone, &qctx->client->peeraddr,
7234 1.15 christos TCP(qctx->client), qctx->client->message->rdclass,
7235 1.15 christos qctx->qtype, constname, resp_result, qctx->client->now,
7236 1.15 christos wouldlog, log_buf, sizeof(log_buf));
7237 1.1 christos if (rrl_result != DNS_RRL_RESULT_OK) {
7238 1.1 christos /*
7239 1.1 christos * Log dropped or slipped responses in the query
7240 1.1 christos * category so that requests are not silently lost.
7241 1.1 christos * Starts of rate-limited bursts are logged in
7242 1.1 christos * DNS_LOGCATEGORY_RRL.
7243 1.1 christos *
7244 1.1 christos * Dropped responses are counted with dropped queries
7245 1.1 christos * in QryDropped while slipped responses are counted
7246 1.1 christos * with other truncated responses in RespTruncated.
7247 1.1 christos */
7248 1.1 christos if (wouldlog) {
7249 1.1 christos ns_client_log(qctx->client, DNS_LOGCATEGORY_RRL,
7250 1.1 christos NS_LOGMODULE_QUERY,
7251 1.9 christos DNS_RRL_LOG_DROP, "%s", log_buf);
7252 1.1 christos }
7253 1.1 christos
7254 1.23 christos /*
7255 1.23 christos * If tracing is enabled, format some extra information
7256 1.23 christos * to pass along.
7257 1.23 christos */
7258 1.23 christos query_trace_rrldrop(qctx, rrl_result);
7259 1.23 christos
7260 1.3 christos if (!qctx->view->rrl->log_only) {
7261 1.1 christos if (rrl_result == DNS_RRL_RESULT_DROP) {
7262 1.1 christos /*
7263 1.1 christos * These will also be counted in
7264 1.1 christos * ns_statscounter_dropped
7265 1.1 christos */
7266 1.1 christos inc_stats(qctx->client,
7267 1.9 christos ns_statscounter_ratedropped);
7268 1.1 christos QUERY_ERROR(qctx, DNS_R_DROP);
7269 1.1 christos } else {
7270 1.1 christos /*
7271 1.1 christos * These will also be counted in
7272 1.1 christos * ns_statscounter_truncatedresp
7273 1.1 christos */
7274 1.1 christos inc_stats(qctx->client,
7275 1.9 christos ns_statscounter_rateslipped);
7276 1.1 christos if (WANTCOOKIE(qctx->client)) {
7277 1.1 christos qctx->client->message->flags &=
7278 1.1 christos ~DNS_MESSAGEFLAG_AA;
7279 1.1 christos qctx->client->message->flags &=
7280 1.1 christos ~DNS_MESSAGEFLAG_AD;
7281 1.1 christos qctx->client->message->rcode =
7282 1.9 christos dns_rcode_badcookie;
7283 1.1 christos } else {
7284 1.1 christos qctx->client->message->flags |=
7285 1.1 christos DNS_MESSAGEFLAG_TC;
7286 1.1 christos if (resp_result ==
7287 1.16 christos DNS_R_NXDOMAIN)
7288 1.16 christos {
7289 1.9 christos qctx->client->message
7290 1.9 christos ->rcode =
7291 1.9 christos dns_rcode_nxdomain;
7292 1.1 christos }
7293 1.1 christos }
7294 1.1 christos }
7295 1.23 christos return DNS_R_DROP;
7296 1.1 christos }
7297 1.1 christos }
7298 1.1 christos }
7299 1.1 christos
7300 1.23 christos return ISC_R_SUCCESS;
7301 1.1 christos }
7302 1.1 christos
7303 1.1 christos /*%
7304 1.1 christos * Do any RPZ rewriting that may be needed for this query.
7305 1.1 christos */
7306 1.1 christos static isc_result_t
7307 1.1 christos query_checkrpz(query_ctx_t *qctx, isc_result_t result) {
7308 1.1 christos isc_result_t rresult;
7309 1.1 christos
7310 1.9 christos CCTRACE(ISC_LOG_DEBUG(3), "query_checkrpz");
7311 1.9 christos
7312 1.9 christos rresult = rpz_rewrite(qctx->client, qctx->qtype, result, qctx->resuming,
7313 1.1 christos qctx->rdataset, qctx->sigrdataset);
7314 1.1 christos qctx->rpz_st = qctx->client->query.rpz_st;
7315 1.1 christos switch (rresult) {
7316 1.1 christos case ISC_R_SUCCESS:
7317 1.1 christos break;
7318 1.13 christos case ISC_R_NOTFOUND:
7319 1.1 christos case DNS_R_DISALLOWED:
7320 1.23 christos return result;
7321 1.1 christos case DNS_R_DELEGATION:
7322 1.1 christos /*
7323 1.1 christos * recursing for NS names or addresses,
7324 1.1 christos * so save the main query state
7325 1.1 christos */
7326 1.13 christos INSIST(!RECURSING(qctx->client));
7327 1.1 christos qctx->rpz_st->q.qtype = qctx->qtype;
7328 1.1 christos qctx->rpz_st->q.is_zone = qctx->is_zone;
7329 1.1 christos qctx->rpz_st->q.authoritative = qctx->authoritative;
7330 1.1 christos SAVE(qctx->rpz_st->q.zone, qctx->zone);
7331 1.1 christos SAVE(qctx->rpz_st->q.db, qctx->db);
7332 1.1 christos SAVE(qctx->rpz_st->q.node, qctx->node);
7333 1.1 christos SAVE(qctx->rpz_st->q.rdataset, qctx->rdataset);
7334 1.1 christos SAVE(qctx->rpz_st->q.sigrdataset, qctx->sigrdataset);
7335 1.20 christos dns_name_copy(qctx->fname, qctx->rpz_st->fname);
7336 1.1 christos qctx->rpz_st->q.result = result;
7337 1.1 christos qctx->client->query.attributes |= NS_QUERYATTR_RECURSING;
7338 1.23 christos return ISC_R_COMPLETE;
7339 1.1 christos default:
7340 1.3 christos QUERY_ERROR(qctx, rresult);
7341 1.23 christos return ISC_R_COMPLETE;
7342 1.1 christos }
7343 1.1 christos
7344 1.1 christos if (qctx->rpz_st->m.policy != DNS_RPZ_POLICY_MISS) {
7345 1.1 christos qctx->rpz_st->state |= DNS_RPZ_REWRITTEN;
7346 1.1 christos }
7347 1.1 christos
7348 1.1 christos if (qctx->rpz_st->m.policy != DNS_RPZ_POLICY_MISS &&
7349 1.1 christos qctx->rpz_st->m.policy != DNS_RPZ_POLICY_PASSTHRU &&
7350 1.1 christos (qctx->rpz_st->m.policy != DNS_RPZ_POLICY_TCP_ONLY ||
7351 1.1 christos !TCP(qctx->client)) &&
7352 1.1 christos qctx->rpz_st->m.policy != DNS_RPZ_POLICY_ERROR)
7353 1.1 christos {
7354 1.1 christos /*
7355 1.1 christos * We got a hit and are going to answer with our
7356 1.1 christos * fiction. Ensure that we answer with the name
7357 1.1 christos * we looked up even if we were stopped short
7358 1.1 christos * in recursion or for a deferral.
7359 1.1 christos */
7360 1.20 christos dns_name_copy(qctx->client->query.qname, qctx->fname);
7361 1.1 christos rpz_clean(&qctx->zone, &qctx->db, &qctx->node, NULL);
7362 1.1 christos if (qctx->rpz_st->m.rdataset != NULL) {
7363 1.3 christos ns_client_putrdataset(qctx->client, &qctx->rdataset);
7364 1.1 christos RESTORE(qctx->rdataset, qctx->rpz_st->m.rdataset);
7365 1.1 christos } else {
7366 1.1 christos qctx_clean(qctx);
7367 1.1 christos }
7368 1.1 christos qctx->version = NULL;
7369 1.1 christos
7370 1.1 christos RESTORE(qctx->node, qctx->rpz_st->m.node);
7371 1.1 christos RESTORE(qctx->db, qctx->rpz_st->m.db);
7372 1.1 christos RESTORE(qctx->version, qctx->rpz_st->m.version);
7373 1.1 christos RESTORE(qctx->zone, qctx->rpz_st->m.zone);
7374 1.1 christos
7375 1.1 christos /*
7376 1.1 christos * Add SOA record to additional section
7377 1.1 christos */
7378 1.5 christos if (qctx->rpz_st->m.rpz->addsoa) {
7379 1.22 christos rresult = query_addsoa(qctx, UINT32_MAX,
7380 1.5 christos DNS_SECTION_ADDITIONAL);
7381 1.5 christos if (rresult != ISC_R_SUCCESS) {
7382 1.5 christos QUERY_ERROR(qctx, result);
7383 1.23 christos return ISC_R_COMPLETE;
7384 1.5 christos }
7385 1.1 christos }
7386 1.1 christos
7387 1.1 christos switch (qctx->rpz_st->m.policy) {
7388 1.1 christos case DNS_RPZ_POLICY_TCP_ONLY:
7389 1.1 christos qctx->client->message->flags |= DNS_MESSAGEFLAG_TC;
7390 1.1 christos if (result == DNS_R_NXDOMAIN ||
7391 1.16 christos result == DNS_R_NCACHENXDOMAIN)
7392 1.16 christos {
7393 1.1 christos qctx->client->message->rcode =
7394 1.9 christos dns_rcode_nxdomain;
7395 1.9 christos }
7396 1.3 christos rpz_log_rewrite(qctx->client, false,
7397 1.1 christos qctx->rpz_st->m.policy,
7398 1.1 christos qctx->rpz_st->m.type, qctx->zone,
7399 1.1 christos qctx->rpz_st->p_name, NULL,
7400 1.1 christos qctx->rpz_st->m.rpz->num);
7401 1.23 christos return ISC_R_COMPLETE;
7402 1.1 christos case DNS_RPZ_POLICY_DROP:
7403 1.1 christos QUERY_ERROR(qctx, DNS_R_DROP);
7404 1.3 christos rpz_log_rewrite(qctx->client, false,
7405 1.1 christos qctx->rpz_st->m.policy,
7406 1.1 christos qctx->rpz_st->m.type, qctx->zone,
7407 1.1 christos qctx->rpz_st->p_name, NULL,
7408 1.1 christos qctx->rpz_st->m.rpz->num);
7409 1.23 christos return ISC_R_COMPLETE;
7410 1.1 christos case DNS_RPZ_POLICY_NXDOMAIN:
7411 1.1 christos result = DNS_R_NXDOMAIN;
7412 1.3 christos qctx->nxrewrite = true;
7413 1.3 christos qctx->rpz = true;
7414 1.1 christos break;
7415 1.1 christos case DNS_RPZ_POLICY_NODATA:
7416 1.6 christos qctx->nxrewrite = true;
7417 1.15 christos FALLTHROUGH;
7418 1.6 christos case DNS_RPZ_POLICY_DNS64:
7419 1.1 christos result = DNS_R_NXRRSET;
7420 1.3 christos qctx->rpz = true;
7421 1.1 christos break;
7422 1.1 christos case DNS_RPZ_POLICY_RECORD:
7423 1.1 christos result = qctx->rpz_st->m.result;
7424 1.1 christos if (qctx->qtype == dns_rdatatype_any &&
7425 1.16 christos result != DNS_R_CNAME)
7426 1.16 christos {
7427 1.1 christos /*
7428 1.1 christos * We will add all of the rdatasets of
7429 1.1 christos * the node by iterating later,
7430 1.1 christos * and set the TTL then.
7431 1.1 christos */
7432 1.9 christos if (dns_rdataset_isassociated(qctx->rdataset)) {
7433 1.9 christos dns_rdataset_disassociate(
7434 1.9 christos qctx->rdataset);
7435 1.9 christos }
7436 1.1 christos } else {
7437 1.1 christos /*
7438 1.1 christos * We will add this rdataset.
7439 1.1 christos */
7440 1.1 christos qctx->rdataset->ttl =
7441 1.1 christos ISC_MIN(qctx->rdataset->ttl,
7442 1.1 christos qctx->rpz_st->m.ttl);
7443 1.1 christos }
7444 1.3 christos qctx->rpz = true;
7445 1.1 christos break;
7446 1.1 christos case DNS_RPZ_POLICY_WILDCNAME: {
7447 1.1 christos dns_rdata_t rdata = DNS_RDATA_INIT;
7448 1.1 christos dns_rdata_cname_t cname;
7449 1.1 christos result = dns_rdataset_first(qctx->rdataset);
7450 1.1 christos RUNTIME_CHECK(result == ISC_R_SUCCESS);
7451 1.1 christos dns_rdataset_current(qctx->rdataset, &rdata);
7452 1.9 christos result = dns_rdata_tostruct(&rdata, &cname, NULL);
7453 1.1 christos RUNTIME_CHECK(result == ISC_R_SUCCESS);
7454 1.1 christos dns_rdata_reset(&rdata);
7455 1.1 christos result = query_rpzcname(qctx, &cname.cname);
7456 1.9 christos if (result != ISC_R_SUCCESS) {
7457 1.23 christos return ISC_R_COMPLETE;
7458 1.9 christos }
7459 1.1 christos qctx->fname = NULL;
7460 1.3 christos qctx->want_restart = true;
7461 1.23 christos return ISC_R_COMPLETE;
7462 1.1 christos }
7463 1.1 christos case DNS_RPZ_POLICY_CNAME:
7464 1.1 christos /*
7465 1.9 christos * Add overriding CNAME from a named.conf
7466 1.1 christos * response-policy statement
7467 1.1 christos */
7468 1.1 christos result = query_rpzcname(qctx,
7469 1.1 christos &qctx->rpz_st->m.rpz->cname);
7470 1.9 christos if (result != ISC_R_SUCCESS) {
7471 1.23 christos return ISC_R_COMPLETE;
7472 1.9 christos }
7473 1.1 christos qctx->fname = NULL;
7474 1.3 christos qctx->want_restart = true;
7475 1.23 christos return ISC_R_COMPLETE;
7476 1.1 christos default:
7477 1.15 christos UNREACHABLE();
7478 1.1 christos }
7479 1.1 christos
7480 1.23 christos if (qctx->rpz_st->m.rpz->ede != 0 &&
7481 1.23 christos qctx->rpz_st->m.rpz->ede != UINT16_MAX)
7482 1.23 christos {
7483 1.24 christos dns_ede_add(&qctx->client->edectx,
7484 1.24 christos qctx->rpz_st->m.rpz->ede, NULL);
7485 1.23 christos }
7486 1.23 christos
7487 1.1 christos /*
7488 1.1 christos * Turn off DNSSEC because the results of a
7489 1.1 christos * response policy zone cannot verify.
7490 1.1 christos */
7491 1.1 christos qctx->client->attributes &= ~(NS_CLIENTATTR_WANTDNSSEC |
7492 1.1 christos NS_CLIENTATTR_WANTAD);
7493 1.1 christos qctx->client->message->flags &= ~DNS_MESSAGEFLAG_AD;
7494 1.3 christos ns_client_putrdataset(qctx->client, &qctx->sigrdataset);
7495 1.1 christos qctx->rpz_st->q.is_zone = qctx->is_zone;
7496 1.3 christos qctx->is_zone = true;
7497 1.9 christos rpz_log_rewrite(qctx->client, false, qctx->rpz_st->m.policy,
7498 1.1 christos qctx->rpz_st->m.type, qctx->zone,
7499 1.1 christos qctx->rpz_st->p_name, NULL,
7500 1.1 christos qctx->rpz_st->m.rpz->num);
7501 1.1 christos }
7502 1.1 christos
7503 1.23 christos return result;
7504 1.1 christos }
7505 1.1 christos
7506 1.1 christos /*%
7507 1.1 christos * Add a CNAME to a query response, including translating foo.evil.com and
7508 1.1 christos * *.evil.com CNAME *.example.com
7509 1.1 christos * to
7510 1.1 christos * foo.evil.com CNAME foo.evil.com.example.com
7511 1.1 christos */
7512 1.1 christos static isc_result_t
7513 1.1 christos query_rpzcname(query_ctx_t *qctx, dns_name_t *cname) {
7514 1.6 christos ns_client_t *client;
7515 1.1 christos dns_fixedname_t prefix, suffix;
7516 1.1 christos unsigned int labels;
7517 1.1 christos isc_result_t result;
7518 1.1 christos
7519 1.6 christos REQUIRE(qctx != NULL && qctx->client != NULL);
7520 1.6 christos
7521 1.6 christos client = qctx->client;
7522 1.6 christos
7523 1.1 christos CTRACE(ISC_LOG_DEBUG(3), "query_rpzcname");
7524 1.1 christos
7525 1.1 christos labels = dns_name_countlabels(cname);
7526 1.1 christos if (labels > 2 && dns_name_iswildcard(cname)) {
7527 1.1 christos dns_fixedname_init(&prefix);
7528 1.1 christos dns_name_split(client->query.qname, 1,
7529 1.1 christos dns_fixedname_name(&prefix), NULL);
7530 1.1 christos dns_fixedname_init(&suffix);
7531 1.9 christos dns_name_split(cname, labels - 1, NULL,
7532 1.9 christos dns_fixedname_name(&suffix));
7533 1.1 christos result = dns_name_concatenate(dns_fixedname_name(&prefix),
7534 1.1 christos dns_fixedname_name(&suffix),
7535 1.1 christos qctx->fname, NULL);
7536 1.1 christos if (result == DNS_R_NAMETOOLONG) {
7537 1.1 christos client->message->rcode = dns_rcode_yxdomain;
7538 1.1 christos } else if (result != ISC_R_SUCCESS) {
7539 1.23 christos return result;
7540 1.1 christos }
7541 1.1 christos } else {
7542 1.20 christos dns_name_copy(cname, qctx->fname);
7543 1.1 christos }
7544 1.1 christos
7545 1.3 christos ns_client_keepname(client, qctx->fname, qctx->dbuf);
7546 1.23 christos query_addcname(qctx, dns_trust_authanswer, qctx->rpz_st->m.ttl);
7547 1.1 christos
7548 1.3 christos rpz_log_rewrite(client, false, qctx->rpz_st->m.policy,
7549 1.1 christos qctx->rpz_st->m.type, qctx->rpz_st->m.zone,
7550 1.1 christos qctx->rpz_st->p_name, qctx->fname,
7551 1.1 christos qctx->rpz_st->m.rpz->num);
7552 1.1 christos
7553 1.1 christos ns_client_qnamereplace(client, qctx->fname);
7554 1.1 christos
7555 1.1 christos /*
7556 1.1 christos * Turn off DNSSEC because the results of a
7557 1.1 christos * response policy zone cannot verify.
7558 1.1 christos */
7559 1.1 christos client->attributes &= ~(NS_CLIENTATTR_WANTDNSSEC |
7560 1.1 christos NS_CLIENTATTR_WANTAD);
7561 1.1 christos
7562 1.23 christos return ISC_R_SUCCESS;
7563 1.1 christos }
7564 1.1 christos
7565 1.1 christos /*%
7566 1.1 christos * Check the configured trust anchors for a root zone trust anchor
7567 1.1 christos * with a key id that matches qctx->client->query.root_key_sentinel_keyid.
7568 1.1 christos *
7569 1.3 christos * Return true when found, otherwise return false.
7570 1.1 christos */
7571 1.3 christos static bool
7572 1.1 christos has_ta(query_ctx_t *qctx) {
7573 1.1 christos dns_keytable_t *keytable = NULL;
7574 1.1 christos dns_keynode_t *keynode = NULL;
7575 1.10 christos dns_rdataset_t dsset;
7576 1.9 christos dns_keytag_t sentinel = qctx->client->query.root_key_sentinel_keyid;
7577 1.1 christos isc_result_t result;
7578 1.1 christos
7579 1.3 christos result = dns_view_getsecroots(qctx->view, &keytable);
7580 1.1 christos if (result != ISC_R_SUCCESS) {
7581 1.23 christos return false;
7582 1.1 christos }
7583 1.1 christos
7584 1.1 christos result = dns_keytable_find(keytable, dns_rootname, &keynode);
7585 1.9 christos if (result != ISC_R_SUCCESS) {
7586 1.9 christos if (keynode != NULL) {
7587 1.23 christos dns_keynode_detach(&keynode);
7588 1.1 christos }
7589 1.9 christos dns_keytable_detach(&keytable);
7590 1.23 christos return false;
7591 1.9 christos }
7592 1.9 christos
7593 1.10 christos dns_rdataset_init(&dsset);
7594 1.10 christos if (dns_keynode_dsset(keynode, &dsset)) {
7595 1.10 christos for (result = dns_rdataset_first(&dsset);
7596 1.10 christos result == ISC_R_SUCCESS;
7597 1.10 christos result = dns_rdataset_next(&dsset))
7598 1.9 christos {
7599 1.9 christos dns_rdata_t rdata = DNS_RDATA_INIT;
7600 1.9 christos dns_rdata_ds_t ds;
7601 1.9 christos
7602 1.9 christos dns_rdata_reset(&rdata);
7603 1.10 christos dns_rdataset_current(&dsset, &rdata);
7604 1.9 christos result = dns_rdata_tostruct(&rdata, &ds, NULL);
7605 1.9 christos RUNTIME_CHECK(result == ISC_R_SUCCESS);
7606 1.9 christos if (ds.key_tag == sentinel) {
7607 1.23 christos dns_keynode_detach(&keynode);
7608 1.9 christos dns_keytable_detach(&keytable);
7609 1.10 christos dns_rdataset_disassociate(&dsset);
7610 1.23 christos return true;
7611 1.9 christos }
7612 1.9 christos }
7613 1.10 christos dns_rdataset_disassociate(&dsset);
7614 1.9 christos }
7615 1.9 christos
7616 1.9 christos if (keynode != NULL) {
7617 1.23 christos dns_keynode_detach(&keynode);
7618 1.1 christos }
7619 1.9 christos
7620 1.1 christos dns_keytable_detach(&keytable);
7621 1.1 christos
7622 1.23 christos return false;
7623 1.1 christos }
7624 1.1 christos
7625 1.1 christos /*%
7626 1.1 christos * Check if a root key sentinel SERVFAIL should be returned.
7627 1.1 christos */
7628 1.3 christos static bool
7629 1.1 christos root_key_sentinel_return_servfail(query_ctx_t *qctx, isc_result_t result) {
7630 1.1 christos /*
7631 1.1 christos * Are we looking at a "root-key-sentinel" query?
7632 1.1 christos */
7633 1.1 christos if (!qctx->client->query.root_key_sentinel_is_ta &&
7634 1.1 christos !qctx->client->query.root_key_sentinel_not_ta)
7635 1.1 christos {
7636 1.23 christos return false;
7637 1.1 christos }
7638 1.1 christos
7639 1.1 christos /*
7640 1.1 christos * We only care about the query if 'result' indicates we have a cached
7641 1.1 christos * answer.
7642 1.1 christos */
7643 1.1 christos switch (result) {
7644 1.1 christos case ISC_R_SUCCESS:
7645 1.1 christos case DNS_R_CNAME:
7646 1.1 christos case DNS_R_DNAME:
7647 1.1 christos case DNS_R_NCACHENXDOMAIN:
7648 1.1 christos case DNS_R_NCACHENXRRSET:
7649 1.1 christos break;
7650 1.1 christos default:
7651 1.23 christos return false;
7652 1.1 christos }
7653 1.1 christos
7654 1.1 christos /*
7655 1.1 christos * Do we meet the specified conditions to return SERVFAIL?
7656 1.1 christos */
7657 1.9 christos if (!qctx->is_zone && qctx->rdataset->trust == dns_trust_secure &&
7658 1.1 christos ((qctx->client->query.root_key_sentinel_is_ta && !has_ta(qctx)) ||
7659 1.1 christos (qctx->client->query.root_key_sentinel_not_ta && has_ta(qctx))))
7660 1.1 christos {
7661 1.23 christos return true;
7662 1.1 christos }
7663 1.1 christos
7664 1.1 christos /*
7665 1.1 christos * As special processing may only be triggered by the original QNAME,
7666 1.1 christos * disable it after following a CNAME/DNAME.
7667 1.1 christos */
7668 1.3 christos qctx->client->query.root_key_sentinel_is_ta = false;
7669 1.3 christos qctx->client->query.root_key_sentinel_not_ta = false;
7670 1.1 christos
7671 1.23 christos return false;
7672 1.1 christos }
7673 1.1 christos
7674 1.1 christos /*%
7675 1.3 christos * If serving stale answers is allowed, set up 'qctx' to look for one and
7676 1.3 christos * return true; otherwise, return false.
7677 1.3 christos */
7678 1.3 christos static bool
7679 1.13 christos query_usestale(query_ctx_t *qctx, isc_result_t result) {
7680 1.13 christos if ((qctx->client->query.dboptions & DNS_DBFIND_STALEOK) != 0) {
7681 1.13 christos /*
7682 1.13 christos * Query was already using stale, if that didn't work the
7683 1.13 christos * last time, it won't work this time either.
7684 1.13 christos */
7685 1.23 christos return false;
7686 1.17 christos }
7687 1.17 christos
7688 1.23 christos if (result == DNS_R_DUPLICATE || result == DNS_R_DROP) {
7689 1.15 christos /*
7690 1.15 christos * Don't enable serve-stale if the result signals a duplicate
7691 1.23 christos * query or query that is being dropped.
7692 1.15 christos */
7693 1.23 christos return false;
7694 1.15 christos }
7695 1.15 christos
7696 1.3 christos qctx_clean(qctx);
7697 1.3 christos qctx_freedata(qctx);
7698 1.3 christos
7699 1.11 christos if (dns_view_staleanswerenabled(qctx->client->view)) {
7700 1.20 christos isc_result_t ret;
7701 1.20 christos ret = query_getdb(qctx->client, qctx->client->query.qname,
7702 1.20 christos qctx->client->query.qtype, qctx->options,
7703 1.20 christos &qctx->zone, &qctx->db, &qctx->version,
7704 1.20 christos &qctx->is_zone);
7705 1.20 christos if (ret != ISC_R_SUCCESS) {
7706 1.20 christos /*
7707 1.20 christos * Failed to get the database, unexpected, but let us
7708 1.20 christos * at least abandon serve-stale.
7709 1.20 christos */
7710 1.23 christos return false;
7711 1.20 christos }
7712 1.20 christos
7713 1.3 christos qctx->client->query.dboptions |= DNS_DBFIND_STALEOK;
7714 1.23 christos if (FETCH_RECTYPE_NORMAL(qctx->client) != NULL) {
7715 1.23 christos dns_resolver_destroyfetch(
7716 1.23 christos &FETCH_RECTYPE_NORMAL(qctx->client));
7717 1.3 christos }
7718 1.11 christos
7719 1.13 christos /*
7720 1.13 christos * Start the stale-refresh-time window in case there was a
7721 1.13 christos * resolver query timeout.
7722 1.13 christos */
7723 1.13 christos if (qctx->resuming && result == ISC_R_TIMEDOUT) {
7724 1.13 christos qctx->client->query.dboptions |= DNS_DBFIND_STALESTART;
7725 1.13 christos }
7726 1.23 christos return true;
7727 1.3 christos }
7728 1.3 christos
7729 1.23 christos return false;
7730 1.3 christos }
7731 1.3 christos
7732 1.3 christos /*%
7733 1.3 christos * Continue after doing a database lookup or returning from
7734 1.3 christos * recursion, and call out to the next function depending on the
7735 1.3 christos * result from the search.
7736 1.1 christos */
7737 1.1 christos static isc_result_t
7738 1.18 christos query_gotanswer(query_ctx_t *qctx, isc_result_t result) {
7739 1.1 christos char errmsg[256];
7740 1.1 christos
7741 1.1 christos CCTRACE(ISC_LOG_DEBUG(3), "query_gotanswer");
7742 1.1 christos
7743 1.3 christos CALL_HOOK(NS_QUERY_GOT_ANSWER_BEGIN, qctx);
7744 1.3 christos
7745 1.1 christos if (query_checkrrl(qctx, result) != ISC_R_SUCCESS) {
7746 1.23 christos return ns_query_done(qctx);
7747 1.1 christos }
7748 1.1 christos
7749 1.13 christos if (!dns_name_equal(qctx->client->query.qname, dns_rootname)) {
7750 1.1 christos result = query_checkrpz(qctx, result);
7751 1.13 christos if (result == ISC_R_NOTFOUND) {
7752 1.13 christos /*
7753 1.13 christos * RPZ not configured for this view.
7754 1.13 christos */
7755 1.13 christos goto root_key_sentinel;
7756 1.13 christos }
7757 1.13 christos if (RECURSING(qctx->client) && result == DNS_R_DISALLOWED) {
7758 1.13 christos /*
7759 1.13 christos * We are recursing, and thus RPZ processing is not
7760 1.13 christos * allowed at the moment. This could happen on a
7761 1.13 christos * "stale-answer-client-timeout" lookup. In this case,
7762 1.13 christos * bail out and wait for recursion to complete, as we
7763 1.13 christos * we can't perform the RPZ rewrite rules.
7764 1.13 christos */
7765 1.23 christos return result;
7766 1.13 christos }
7767 1.3 christos if (result == ISC_R_COMPLETE) {
7768 1.23 christos return ns_query_done(qctx);
7769 1.3 christos }
7770 1.1 christos }
7771 1.1 christos
7772 1.13 christos root_key_sentinel:
7773 1.1 christos /*
7774 1.1 christos * If required, handle special "root-key-sentinel-is-ta-<keyid>" and
7775 1.1 christos * "root-key-sentinel-not-ta-<keyid>" labels by returning SERVFAIL.
7776 1.1 christos */
7777 1.1 christos if (root_key_sentinel_return_servfail(qctx, result)) {
7778 1.1 christos /*
7779 1.1 christos * Don't record this response in the SERVFAIL cache.
7780 1.1 christos */
7781 1.1 christos qctx->client->attributes |= NS_CLIENTATTR_NOSETFC;
7782 1.1 christos QUERY_ERROR(qctx, DNS_R_SERVFAIL);
7783 1.23 christos return ns_query_done(qctx);
7784 1.1 christos }
7785 1.1 christos
7786 1.1 christos switch (result) {
7787 1.1 christos case ISC_R_SUCCESS:
7788 1.23 christos return query_prepresponse(qctx);
7789 1.1 christos
7790 1.1 christos case DNS_R_GLUE:
7791 1.1 christos case DNS_R_ZONECUT:
7792 1.1 christos INSIST(qctx->is_zone);
7793 1.3 christos qctx->authoritative = false;
7794 1.23 christos return query_prepresponse(qctx);
7795 1.1 christos
7796 1.1 christos case ISC_R_NOTFOUND:
7797 1.23 christos return query_notfound(qctx);
7798 1.1 christos
7799 1.1 christos case DNS_R_DELEGATION:
7800 1.23 christos return query_delegation(qctx);
7801 1.1 christos
7802 1.1 christos case DNS_R_EMPTYNAME:
7803 1.1 christos case DNS_R_NXRRSET:
7804 1.23 christos return query_nodata(qctx, result);
7805 1.1 christos
7806 1.1 christos case DNS_R_EMPTYWILD:
7807 1.1 christos case DNS_R_NXDOMAIN:
7808 1.23 christos return query_nxdomain(qctx, result);
7809 1.1 christos
7810 1.1 christos case DNS_R_COVERINGNSEC:
7811 1.23 christos return query_coveringnsec(qctx);
7812 1.1 christos
7813 1.1 christos case DNS_R_NCACHENXDOMAIN:
7814 1.18 christos result = query_redirect(qctx, result);
7815 1.9 christos if (result != ISC_R_COMPLETE) {
7816 1.23 christos return result;
7817 1.9 christos }
7818 1.23 christos return query_ncache(qctx, DNS_R_NCACHENXDOMAIN);
7819 1.1 christos
7820 1.1 christos case DNS_R_NCACHENXRRSET:
7821 1.23 christos return query_ncache(qctx, DNS_R_NCACHENXRRSET);
7822 1.1 christos
7823 1.1 christos case DNS_R_CNAME:
7824 1.23 christos return query_cname(qctx);
7825 1.1 christos
7826 1.1 christos case DNS_R_DNAME:
7827 1.23 christos return query_dname(qctx);
7828 1.1 christos
7829 1.1 christos default:
7830 1.1 christos /*
7831 1.1 christos * Something has gone wrong.
7832 1.1 christos */
7833 1.1 christos snprintf(errmsg, sizeof(errmsg) - 1,
7834 1.1 christos "query_gotanswer: unexpected error: %s",
7835 1.1 christos isc_result_totext(result));
7836 1.1 christos CCTRACE(ISC_LOG_ERROR, errmsg);
7837 1.13 christos if (query_usestale(qctx, result)) {
7838 1.3 christos /*
7839 1.3 christos * If serve-stale is enabled, query_usestale() already
7840 1.3 christos * set up 'qctx' for looking up a stale response.
7841 1.3 christos */
7842 1.23 christos return query_lookup(qctx);
7843 1.1 christos }
7844 1.6 christos
7845 1.6 christos /*
7846 1.6 christos * Regardless of the triggering result, we definitely
7847 1.6 christos * want to return SERVFAIL from here.
7848 1.6 christos */
7849 1.6 christos qctx->client->rcode_override = dns_rcode_servfail;
7850 1.6 christos
7851 1.3 christos QUERY_ERROR(qctx, result);
7852 1.23 christos return ns_query_done(qctx);
7853 1.1 christos }
7854 1.3 christos
7855 1.9 christos cleanup:
7856 1.23 christos return result;
7857 1.1 christos }
7858 1.1 christos
7859 1.1 christos static void
7860 1.1 christos query_addnoqnameproof(query_ctx_t *qctx) {
7861 1.1 christos ns_client_t *client = qctx->client;
7862 1.1 christos isc_buffer_t *dbuf, b;
7863 1.1 christos dns_name_t *fname = NULL;
7864 1.1 christos dns_rdataset_t *neg = NULL, *negsig = NULL;
7865 1.1 christos isc_result_t result = ISC_R_NOMEMORY;
7866 1.1 christos
7867 1.1 christos CTRACE(ISC_LOG_DEBUG(3), "query_addnoqnameproof");
7868 1.1 christos
7869 1.1 christos if (qctx->noqname == NULL) {
7870 1.1 christos return;
7871 1.1 christos }
7872 1.1 christos
7873 1.3 christos dbuf = ns_client_getnamebuf(client);
7874 1.3 christos fname = ns_client_newname(client, dbuf, &b);
7875 1.3 christos neg = ns_client_newrdataset(client);
7876 1.3 christos negsig = ns_client_newrdataset(client);
7877 1.1 christos
7878 1.1 christos result = dns_rdataset_getnoqname(qctx->noqname, fname, neg, negsig);
7879 1.1 christos RUNTIME_CHECK(result == ISC_R_SUCCESS);
7880 1.1 christos
7881 1.3 christos query_addrrset(qctx, &fname, &neg, &negsig, dbuf,
7882 1.1 christos DNS_SECTION_AUTHORITY);
7883 1.1 christos
7884 1.1 christos if ((qctx->noqname->attributes & DNS_RDATASETATTR_CLOSEST) == 0) {
7885 1.1 christos goto cleanup;
7886 1.1 christos }
7887 1.1 christos
7888 1.1 christos if (fname == NULL) {
7889 1.3 christos dbuf = ns_client_getnamebuf(client);
7890 1.3 christos fname = ns_client_newname(client, dbuf, &b);
7891 1.1 christos }
7892 1.1 christos
7893 1.1 christos if (neg == NULL) {
7894 1.3 christos neg = ns_client_newrdataset(client);
7895 1.1 christos } else if (dns_rdataset_isassociated(neg)) {
7896 1.1 christos dns_rdataset_disassociate(neg);
7897 1.1 christos }
7898 1.1 christos
7899 1.1 christos if (negsig == NULL) {
7900 1.3 christos negsig = ns_client_newrdataset(client);
7901 1.1 christos } else if (dns_rdataset_isassociated(negsig)) {
7902 1.1 christos dns_rdataset_disassociate(negsig);
7903 1.1 christos }
7904 1.1 christos
7905 1.1 christos result = dns_rdataset_getclosest(qctx->noqname, fname, neg, negsig);
7906 1.1 christos RUNTIME_CHECK(result == ISC_R_SUCCESS);
7907 1.1 christos
7908 1.3 christos query_addrrset(qctx, &fname, &neg, &negsig, dbuf,
7909 1.1 christos DNS_SECTION_AUTHORITY);
7910 1.1 christos
7911 1.9 christos cleanup:
7912 1.1 christos if (neg != NULL) {
7913 1.3 christos ns_client_putrdataset(client, &neg);
7914 1.1 christos }
7915 1.1 christos if (negsig != NULL) {
7916 1.3 christos ns_client_putrdataset(client, &negsig);
7917 1.1 christos }
7918 1.1 christos if (fname != NULL) {
7919 1.3 christos ns_client_releasename(client, &fname);
7920 1.1 christos }
7921 1.1 christos }
7922 1.1 christos
7923 1.1 christos /*%
7924 1.1 christos * Build the response for a query for type ANY.
7925 1.1 christos */
7926 1.1 christos static isc_result_t
7927 1.1 christos query_respond_any(query_ctx_t *qctx) {
7928 1.5 christos bool found = false, hidden = false;
7929 1.1 christos dns_rdatasetiter_t *rdsiter = NULL;
7930 1.20 christos isc_result_t result = ISC_R_UNSET;
7931 1.9 christos dns_rdatatype_t onetype = 0; /* type to use for minimal-any */
7932 1.3 christos isc_buffer_t b;
7933 1.1 christos
7934 1.9 christos CCTRACE(ISC_LOG_DEBUG(3), "query_respond_any");
7935 1.9 christos
7936 1.3 christos CALL_HOOK(NS_QUERY_RESPOND_ANY_BEGIN, qctx);
7937 1.1 christos
7938 1.16 christos result = dns_db_allrdatasets(qctx->db, qctx->node, qctx->version, 0, 0,
7939 1.9 christos &rdsiter);
7940 1.1 christos if (result != ISC_R_SUCCESS) {
7941 1.9 christos CCTRACE(ISC_LOG_ERROR, "query_respond_any: allrdatasets "
7942 1.9 christos "failed");
7943 1.3 christos QUERY_ERROR(qctx, result);
7944 1.23 christos return ns_query_done(qctx);
7945 1.1 christos }
7946 1.1 christos
7947 1.1 christos /*
7948 1.1 christos * Calling query_addrrset() with a non-NULL dbuf is going
7949 1.1 christos * to either keep or release the name. We don't want it to
7950 1.1 christos * release fname, since we may have to call query_addrrset()
7951 1.3 christos * more than once. That means we have to call ns_client_keepname()
7952 1.1 christos * now, and pass a NULL dbuf to query_addrrset().
7953 1.1 christos *
7954 1.1 christos * If we do a query_addrrset() below, we must set qctx->fname to
7955 1.1 christos * NULL before leaving this block, otherwise we might try to
7956 1.1 christos * cleanup qctx->fname even though we're using it!
7957 1.1 christos */
7958 1.3 christos ns_client_keepname(qctx->client, qctx->fname, qctx->dbuf);
7959 1.3 christos qctx->tname = qctx->fname;
7960 1.1 christos
7961 1.1 christos result = dns_rdatasetiter_first(rdsiter);
7962 1.1 christos while (result == ISC_R_SUCCESS) {
7963 1.1 christos dns_rdatasetiter_current(rdsiter, qctx->rdataset);
7964 1.1 christos
7965 1.1 christos /*
7966 1.1 christos * We found an NS RRset; no need to add one later.
7967 1.1 christos */
7968 1.1 christos if (qctx->qtype == dns_rdatatype_any &&
7969 1.1 christos qctx->rdataset->type == dns_rdatatype_ns)
7970 1.1 christos {
7971 1.3 christos qctx->answer_has_ns = true;
7972 1.1 christos }
7973 1.1 christos
7974 1.1 christos /*
7975 1.1 christos * Note: if we're in this function, then qctx->type
7976 1.1 christos * is guaranteed to be ANY, but qctx->qtype (i.e. the
7977 1.1 christos * original type requested) might have been RRSIG or
7978 1.1 christos * SIG; we need to check for that.
7979 1.1 christos */
7980 1.1 christos if (qctx->is_zone && qctx->qtype == dns_rdatatype_any &&
7981 1.1 christos !dns_db_issecure(qctx->db) &&
7982 1.1 christos dns_rdatatype_isdnssec(qctx->rdataset->type))
7983 1.1 christos {
7984 1.1 christos /*
7985 1.5 christos * The zone may be transitioning from insecure
7986 1.5 christos * to secure. Hide DNSSEC records from ANY queries.
7987 1.1 christos */
7988 1.1 christos dns_rdataset_disassociate(qctx->rdataset);
7989 1.5 christos hidden = true;
7990 1.9 christos } else if (qctx->view->minimal_any && !TCP(qctx->client) &&
7991 1.9 christos !WANTDNSSEC(qctx->client) &&
7992 1.1 christos qctx->qtype == dns_rdatatype_any &&
7993 1.1 christos (qctx->rdataset->type == dns_rdatatype_sig ||
7994 1.1 christos qctx->rdataset->type == dns_rdatatype_rrsig))
7995 1.1 christos {
7996 1.1 christos CCTRACE(ISC_LOG_DEBUG(5), "query_respond_any: "
7997 1.9 christos "minimal-any skip signature");
7998 1.1 christos dns_rdataset_disassociate(qctx->rdataset);
7999 1.9 christos } else if (qctx->view->minimal_any && !TCP(qctx->client) &&
8000 1.9 christos onetype != 0 && qctx->rdataset->type != onetype &&
8001 1.1 christos qctx->rdataset->covers != onetype)
8002 1.1 christos {
8003 1.1 christos CCTRACE(ISC_LOG_DEBUG(5), "query_respond_any: "
8004 1.9 christos "minimal-any skip rdataset");
8005 1.1 christos dns_rdataset_disassociate(qctx->rdataset);
8006 1.1 christos } else if ((qctx->qtype == dns_rdatatype_any ||
8007 1.1 christos qctx->rdataset->type == qctx->qtype) &&
8008 1.1 christos qctx->rdataset->type != 0)
8009 1.1 christos {
8010 1.9 christos if (NOQNAME(qctx->rdataset) && WANTDNSSEC(qctx->client))
8011 1.1 christos {
8012 1.1 christos qctx->noqname = qctx->rdataset;
8013 1.1 christos } else {
8014 1.1 christos qctx->noqname = NULL;
8015 1.1 christos }
8016 1.1 christos
8017 1.1 christos qctx->rpz_st = qctx->client->query.rpz_st;
8018 1.24 christos if (qctx->rpz_st != NULL &&
8019 1.24 christos qctx->rpz_st->m.policy != DNS_RPZ_POLICY_MISS &&
8020 1.24 christos qctx->rpz_st->m.policy != DNS_RPZ_POLICY_PASSTHRU)
8021 1.24 christos {
8022 1.1 christos qctx->rdataset->ttl =
8023 1.1 christos ISC_MIN(qctx->rdataset->ttl,
8024 1.1 christos qctx->rpz_st->m.ttl);
8025 1.9 christos }
8026 1.1 christos
8027 1.1 christos if (!qctx->is_zone && RECURSIONOK(qctx->client)) {
8028 1.1 christos dns_name_t *name;
8029 1.9 christos name = (qctx->fname != NULL) ? qctx->fname
8030 1.9 christos : qctx->tname;
8031 1.1 christos query_prefetch(qctx->client, name,
8032 1.1 christos qctx->rdataset);
8033 1.1 christos }
8034 1.1 christos
8035 1.1 christos /*
8036 1.1 christos * Remember the first RRtype we find so we
8037 1.1 christos * can skip others with minimal-any.
8038 1.1 christos */
8039 1.1 christos if (qctx->rdataset->type == dns_rdatatype_sig ||
8040 1.1 christos qctx->rdataset->type == dns_rdatatype_rrsig)
8041 1.3 christos {
8042 1.1 christos onetype = qctx->rdataset->covers;
8043 1.3 christos } else {
8044 1.1 christos onetype = qctx->rdataset->type;
8045 1.3 christos }
8046 1.1 christos
8047 1.3 christos query_addrrset(qctx,
8048 1.9 christos (qctx->fname != NULL) ? &qctx->fname
8049 1.9 christos : &qctx->tname,
8050 1.9 christos &qctx->rdataset, NULL, NULL,
8051 1.9 christos DNS_SECTION_ANSWER);
8052 1.1 christos
8053 1.1 christos query_addnoqnameproof(qctx);
8054 1.1 christos
8055 1.3 christos found = true;
8056 1.3 christos INSIST(qctx->tname != NULL);
8057 1.1 christos
8058 1.1 christos /*
8059 1.1 christos * rdataset is non-NULL only in certain
8060 1.1 christos * pathological cases involving DNAMEs.
8061 1.1 christos */
8062 1.3 christos if (qctx->rdataset != NULL) {
8063 1.3 christos ns_client_putrdataset(qctx->client,
8064 1.3 christos &qctx->rdataset);
8065 1.3 christos }
8066 1.1 christos
8067 1.3 christos qctx->rdataset = ns_client_newrdataset(qctx->client);
8068 1.1 christos } else {
8069 1.1 christos /*
8070 1.1 christos * We're not interested in this rdataset.
8071 1.1 christos */
8072 1.1 christos dns_rdataset_disassociate(qctx->rdataset);
8073 1.1 christos }
8074 1.1 christos
8075 1.1 christos result = dns_rdatasetiter_next(rdsiter);
8076 1.1 christos }
8077 1.1 christos
8078 1.3 christos dns_rdatasetiter_destroy(&rdsiter);
8079 1.3 christos
8080 1.3 christos if (result != ISC_R_NOMORE) {
8081 1.9 christos CCTRACE(ISC_LOG_ERROR, "query_respond_any: rdataset iterator "
8082 1.9 christos "failed");
8083 1.3 christos QUERY_ERROR(qctx, DNS_R_SERVFAIL);
8084 1.23 christos return ns_query_done(qctx);
8085 1.3 christos }
8086 1.3 christos
8087 1.3 christos if (found) {
8088 1.5 christos /*
8089 1.5 christos * Call hook if any answers were found.
8090 1.5 christos * Do this before releasing qctx->fname, in case
8091 1.5 christos * the hook function needs it.
8092 1.5 christos */
8093 1.3 christos CALL_HOOK(NS_QUERY_RESPOND_ANY_FOUND, qctx);
8094 1.3 christos }
8095 1.3 christos
8096 1.3 christos if (qctx->fname != NULL) {
8097 1.5 christos dns_message_puttempname(qctx->client->message, &qctx->fname);
8098 1.1 christos }
8099 1.1 christos
8100 1.5 christos if (found) {
8101 1.5 christos /*
8102 1.5 christos * At least one matching rdataset was found
8103 1.5 christos */
8104 1.1 christos query_addauth(qctx);
8105 1.5 christos } else if (qctx->qtype == dns_rdatatype_rrsig ||
8106 1.5 christos qctx->qtype == dns_rdatatype_sig)
8107 1.5 christos {
8108 1.5 christos /*
8109 1.5 christos * No matching rdatasets were found, but we got
8110 1.5 christos * here on a search for RRSIG/SIG, so that's okay.
8111 1.5 christos */
8112 1.5 christos if (!qctx->is_zone) {
8113 1.5 christos qctx->authoritative = false;
8114 1.5 christos qctx->client->attributes &= ~NS_CLIENTATTR_RA;
8115 1.5 christos query_addauth(qctx);
8116 1.23 christos return ns_query_done(qctx);
8117 1.5 christos }
8118 1.5 christos
8119 1.5 christos if (qctx->qtype == dns_rdatatype_rrsig &&
8120 1.16 christos dns_db_issecure(qctx->db))
8121 1.16 christos {
8122 1.5 christos char namebuf[DNS_NAME_FORMATSIZE];
8123 1.9 christos dns_name_format(qctx->client->query.qname, namebuf,
8124 1.9 christos sizeof(namebuf));
8125 1.5 christos ns_client_log(qctx->client, DNS_LOGCATEGORY_DNSSEC,
8126 1.5 christos NS_LOGMODULE_QUERY, ISC_LOG_WARNING,
8127 1.5 christos "missing signature for %s", namebuf);
8128 1.5 christos }
8129 1.1 christos
8130 1.5 christos qctx->fname = ns_client_newname(qctx->client, qctx->dbuf, &b);
8131 1.23 christos return query_sign_nodata(qctx);
8132 1.5 christos } else if (!hidden) {
8133 1.5 christos /*
8134 1.5 christos * No matching rdatasets were found and nothing was
8135 1.5 christos * deliberately hidden: something must have gone wrong.
8136 1.5 christos */
8137 1.5 christos QUERY_ERROR(qctx, DNS_R_SERVFAIL);
8138 1.3 christos }
8139 1.3 christos
8140 1.23 christos return ns_query_done(qctx);
8141 1.3 christos
8142 1.9 christos cleanup:
8143 1.23 christos return result;
8144 1.1 christos }
8145 1.1 christos
8146 1.1 christos /*
8147 1.20 christos * Set the expire time, if requested, when answering from a secondary,
8148 1.20 christos * mirror, or primary zone.
8149 1.1 christos */
8150 1.1 christos static void
8151 1.1 christos query_getexpire(query_ctx_t *qctx) {
8152 1.1 christos dns_zone_t *raw = NULL, *mayberaw;
8153 1.1 christos
8154 1.9 christos CCTRACE(ISC_LOG_DEBUG(3), "query_getexpire");
8155 1.9 christos
8156 1.1 christos if (qctx->zone == NULL || !qctx->is_zone ||
8157 1.1 christos qctx->qtype != dns_rdatatype_soa ||
8158 1.1 christos qctx->client->query.restarts != 0 ||
8159 1.1 christos (qctx->client->attributes & NS_CLIENTATTR_WANTEXPIRE) == 0)
8160 1.1 christos {
8161 1.1 christos return;
8162 1.1 christos }
8163 1.1 christos
8164 1.1 christos dns_zone_getraw(qctx->zone, &raw);
8165 1.1 christos mayberaw = (raw != NULL) ? raw : qctx->zone;
8166 1.1 christos
8167 1.15 christos if (dns_zone_gettype(mayberaw) == dns_zone_secondary ||
8168 1.3 christos dns_zone_gettype(mayberaw) == dns_zone_mirror)
8169 1.3 christos {
8170 1.1 christos isc_time_t expiretime;
8171 1.3 christos uint32_t secs;
8172 1.1 christos dns_zone_getexpiretime(qctx->zone, &expiretime);
8173 1.1 christos secs = isc_time_seconds(&expiretime);
8174 1.9 christos if (secs >= qctx->client->now && qctx->result == ISC_R_SUCCESS)
8175 1.1 christos {
8176 1.9 christos qctx->client->attributes |= NS_CLIENTATTR_HAVEEXPIRE;
8177 1.1 christos qctx->client->expire = secs - qctx->client->now;
8178 1.1 christos }
8179 1.15 christos } else if (dns_zone_gettype(mayberaw) == dns_zone_primary) {
8180 1.1 christos isc_result_t result;
8181 1.1 christos dns_rdata_t rdata = DNS_RDATA_INIT;
8182 1.1 christos dns_rdata_soa_t soa;
8183 1.1 christos
8184 1.1 christos result = dns_rdataset_first(qctx->rdataset);
8185 1.1 christos RUNTIME_CHECK(result == ISC_R_SUCCESS);
8186 1.1 christos
8187 1.1 christos dns_rdataset_current(qctx->rdataset, &rdata);
8188 1.1 christos result = dns_rdata_tostruct(&rdata, &soa, NULL);
8189 1.1 christos RUNTIME_CHECK(result == ISC_R_SUCCESS);
8190 1.1 christos
8191 1.1 christos qctx->client->expire = soa.expire;
8192 1.1 christos qctx->client->attributes |= NS_CLIENTATTR_HAVEEXPIRE;
8193 1.1 christos }
8194 1.1 christos
8195 1.1 christos if (raw != NULL) {
8196 1.1 christos dns_zone_detach(&raw);
8197 1.1 christos }
8198 1.1 christos }
8199 1.1 christos
8200 1.3 christos /*%
8201 1.3 christos * Fill the ANSWER section of a positive response.
8202 1.1 christos */
8203 1.1 christos static isc_result_t
8204 1.3 christos query_addanswer(query_ctx_t *qctx) {
8205 1.3 christos dns_rdataset_t **sigrdatasetp = NULL;
8206 1.20 christos isc_result_t result = ISC_R_UNSET;
8207 1.1 christos
8208 1.9 christos CCTRACE(ISC_LOG_DEBUG(3), "query_addanswer");
8209 1.9 christos
8210 1.3 christos CALL_HOOK(NS_QUERY_ADDANSWER_BEGIN, qctx);
8211 1.1 christos
8212 1.13 christos /*
8213 1.13 christos * On normal lookups, clear any rdatasets that were added on a
8214 1.15 christos * lookup due to stale-answer-client-timeout. Do not clear if we
8215 1.15 christos * are going to refresh the RRset, because the stale contents are
8216 1.15 christos * prioritized.
8217 1.13 christos */
8218 1.13 christos if (QUERY_STALEOK(&qctx->client->query) &&
8219 1.15 christos !QUERY_STALETIMEOUT(&qctx->client->query) && !qctx->refresh_rrset)
8220 1.13 christos {
8221 1.15 christos CCTRACE(ISC_LOG_DEBUG(3), "query_clear_stale");
8222 1.13 christos query_clear_stale(qctx->client);
8223 1.13 christos /*
8224 1.13 christos * We can clear the attribute to prevent redundant clearing
8225 1.13 christos * in subsequent lookups.
8226 1.13 christos */
8227 1.14 christos qctx->client->query.attributes &= ~NS_QUERYATTR_STALEOK;
8228 1.13 christos }
8229 1.13 christos
8230 1.3 christos if (qctx->dns64) {
8231 1.3 christos result = query_dns64(qctx);
8232 1.3 christos qctx->noqname = NULL;
8233 1.3 christos dns_rdataset_disassociate(qctx->rdataset);
8234 1.3 christos dns_message_puttemprdataset(qctx->client->message,
8235 1.3 christos &qctx->rdataset);
8236 1.3 christos if (result == ISC_R_NOMORE) {
8237 1.3 christos #ifndef dns64_bis_return_excluded_addresses
8238 1.3 christos if (qctx->dns64_exclude) {
8239 1.9 christos if (!qctx->is_zone) {
8240 1.23 christos return ns_query_done(qctx);
8241 1.9 christos }
8242 1.3 christos /*
8243 1.3 christos * Add a fake SOA record.
8244 1.3 christos */
8245 1.3 christos (void)query_addsoa(qctx, 600,
8246 1.3 christos DNS_SECTION_AUTHORITY);
8247 1.23 christos return ns_query_done(qctx);
8248 1.3 christos }
8249 1.9 christos #endif /* ifndef dns64_bis_return_excluded_addresses */
8250 1.3 christos if (qctx->is_zone) {
8251 1.23 christos return query_nodata(qctx, DNS_R_NXDOMAIN);
8252 1.3 christos } else {
8253 1.23 christos return query_ncache(qctx, DNS_R_NXDOMAIN);
8254 1.1 christos }
8255 1.3 christos } else if (result != ISC_R_SUCCESS) {
8256 1.3 christos qctx->result = result;
8257 1.23 christos return ns_query_done(qctx);
8258 1.3 christos }
8259 1.3 christos } else if (qctx->client->query.dns64_aaaaok != NULL) {
8260 1.3 christos query_filter64(qctx);
8261 1.3 christos ns_client_putrdataset(qctx->client, &qctx->rdataset);
8262 1.3 christos } else {
8263 1.11 christos if (!qctx->is_zone && RECURSIONOK(qctx->client) &&
8264 1.13 christos !QUERY_STALETIMEOUT(&qctx->client->query))
8265 1.11 christos {
8266 1.3 christos query_prefetch(qctx->client, qctx->fname,
8267 1.3 christos qctx->rdataset);
8268 1.1 christos }
8269 1.3 christos if (WANTDNSSEC(qctx->client) && qctx->sigrdataset != NULL) {
8270 1.3 christos sigrdatasetp = &qctx->sigrdataset;
8271 1.3 christos }
8272 1.9 christos query_addrrset(qctx, &qctx->fname, &qctx->rdataset,
8273 1.9 christos sigrdatasetp, qctx->dbuf, DNS_SECTION_ANSWER);
8274 1.1 christos }
8275 1.1 christos
8276 1.23 christos return ISC_R_COMPLETE;
8277 1.3 christos
8278 1.9 christos cleanup:
8279 1.23 christos return result;
8280 1.1 christos }
8281 1.1 christos
8282 1.1 christos /*%
8283 1.9 christos * Build a response for a "normal" query, for a type other than ANY,
8284 1.1 christos * for which we have an answer (either positive or negative).
8285 1.1 christos */
8286 1.1 christos static isc_result_t
8287 1.1 christos query_respond(query_ctx_t *qctx) {
8288 1.20 christos isc_result_t result = ISC_R_UNSET;
8289 1.1 christos
8290 1.9 christos CCTRACE(ISC_LOG_DEBUG(3), "query_respond");
8291 1.9 christos
8292 1.1 christos /*
8293 1.1 christos * Check to see if the AAAA RRset has non-excluded addresses
8294 1.1 christos * in it. If not look for a A RRset.
8295 1.1 christos */
8296 1.1 christos INSIST(qctx->client->query.dns64_aaaaok == NULL);
8297 1.1 christos
8298 1.1 christos if (qctx->qtype == dns_rdatatype_aaaa && !qctx->dns64_exclude &&
8299 1.3 christos !ISC_LIST_EMPTY(qctx->view->dns64) &&
8300 1.1 christos qctx->client->message->rdclass == dns_rdataclass_in &&
8301 1.1 christos !dns64_aaaaok(qctx->client, qctx->rdataset, qctx->sigrdataset))
8302 1.1 christos {
8303 1.1 christos /*
8304 1.1 christos * Look to see if there are A records for this name.
8305 1.1 christos */
8306 1.1 christos qctx->client->query.dns64_ttl = qctx->rdataset->ttl;
8307 1.1 christos SAVE(qctx->client->query.dns64_aaaa, qctx->rdataset);
8308 1.1 christos SAVE(qctx->client->query.dns64_sigaaaa, qctx->sigrdataset);
8309 1.3 christos ns_client_releasename(qctx->client, &qctx->fname);
8310 1.1 christos dns_db_detachnode(qctx->db, &qctx->node);
8311 1.1 christos qctx->type = qctx->qtype = dns_rdatatype_a;
8312 1.3 christos qctx->dns64_exclude = qctx->dns64 = true;
8313 1.1 christos
8314 1.23 christos return query_lookup(qctx);
8315 1.1 christos }
8316 1.1 christos
8317 1.3 christos /*
8318 1.3 christos * XXX: This hook is meant to be at the top of this function,
8319 1.3 christos * but is postponed until after DNS64 in order to avoid an
8320 1.3 christos * assertion if the hook causes recursion. (When DNS64 also
8321 1.3 christos * becomes a plugin, it will be necessary to find some
8322 1.3 christos * other way to prevent that assertion, since the order in
8323 1.3 christos * which plugins are configured can't be enforced.)
8324 1.3 christos */
8325 1.3 christos CALL_HOOK(NS_QUERY_RESPOND_BEGIN, qctx);
8326 1.1 christos
8327 1.1 christos if (NOQNAME(qctx->rdataset) && WANTDNSSEC(qctx->client)) {
8328 1.1 christos qctx->noqname = qctx->rdataset;
8329 1.1 christos } else {
8330 1.1 christos qctx->noqname = NULL;
8331 1.1 christos }
8332 1.1 christos
8333 1.1 christos /*
8334 1.1 christos * Special case NS handling
8335 1.1 christos */
8336 1.1 christos if (qctx->is_zone && qctx->qtype == dns_rdatatype_ns) {
8337 1.1 christos /*
8338 1.1 christos * We've already got an NS, no need to add one in
8339 1.1 christos * the authority section
8340 1.1 christos */
8341 1.1 christos if (dns_name_equal(qctx->client->query.qname,
8342 1.16 christos dns_db_origin(qctx->db)))
8343 1.16 christos {
8344 1.3 christos qctx->answer_has_ns = true;
8345 1.1 christos }
8346 1.1 christos
8347 1.1 christos /*
8348 1.6 christos * Always add glue for root priming queries, regardless
8349 1.6 christos * of "minimal-responses" setting.
8350 1.1 christos */
8351 1.1 christos if (dns_name_equal(qctx->client->query.qname, dns_rootname)) {
8352 1.1 christos qctx->client->query.attributes &=
8353 1.1 christos ~NS_QUERYATTR_NOADDITIONAL;
8354 1.6 christos dns_db_attach(qctx->db, &qctx->client->query.gluedb);
8355 1.1 christos }
8356 1.1 christos }
8357 1.1 christos
8358 1.1 christos /*
8359 1.1 christos * Set expire time
8360 1.1 christos */
8361 1.1 christos query_getexpire(qctx);
8362 1.1 christos
8363 1.3 christos result = query_addanswer(qctx);
8364 1.3 christos if (result != ISC_R_COMPLETE) {
8365 1.23 christos return result;
8366 1.1 christos }
8367 1.1 christos
8368 1.1 christos query_addnoqnameproof(qctx);
8369 1.1 christos
8370 1.1 christos /*
8371 1.13 christos * 'qctx->rdataset' will only be non-NULL here if the ANSWER section of
8372 1.13 christos * the message to be sent to the client already contains an RRset with
8373 1.13 christos * the same owner name and the same type as 'qctx->rdataset'. This
8374 1.13 christos * should never happen, with one exception: when chasing DNAME records,
8375 1.13 christos * one of the DNAME records placed in the ANSWER section may turn out
8376 1.13 christos * to be the final answer to the client's query, but we have no way of
8377 1.13 christos * knowing that until now. In such a case, 'qctx->rdataset' will be
8378 1.13 christos * freed later, so we do not need to free it here.
8379 1.1 christos */
8380 1.13 christos INSIST(qctx->rdataset == NULL || qctx->qtype == dns_rdatatype_dname);
8381 1.1 christos
8382 1.1 christos query_addauth(qctx);
8383 1.1 christos
8384 1.23 christos return ns_query_done(qctx);
8385 1.3 christos
8386 1.9 christos cleanup:
8387 1.23 christos return result;
8388 1.1 christos }
8389 1.1 christos
8390 1.1 christos static isc_result_t
8391 1.1 christos query_dns64(query_ctx_t *qctx) {
8392 1.1 christos ns_client_t *client = qctx->client;
8393 1.20 christos dns_aclenv_t *env = client->manager->aclenv;
8394 1.1 christos dns_name_t *name, *mname;
8395 1.1 christos dns_rdata_t *dns64_rdata;
8396 1.1 christos dns_rdata_t rdata = DNS_RDATA_INIT;
8397 1.1 christos dns_rdatalist_t *dns64_rdatalist;
8398 1.1 christos dns_rdataset_t *dns64_rdataset;
8399 1.1 christos dns_rdataset_t *mrdataset;
8400 1.1 christos isc_buffer_t *buffer;
8401 1.1 christos isc_region_t r;
8402 1.1 christos isc_result_t result;
8403 1.1 christos dns_view_t *view = client->view;
8404 1.1 christos isc_netaddr_t netaddr;
8405 1.1 christos dns_dns64_t *dns64;
8406 1.1 christos unsigned int flags = 0;
8407 1.1 christos const dns_section_t section = DNS_SECTION_ANSWER;
8408 1.1 christos
8409 1.1 christos /*%
8410 1.1 christos * To the current response for 'qctx->client', add the answer RRset
8411 1.1 christos * '*rdatasetp' and an optional signature set '*sigrdatasetp', with
8412 1.1 christos * owner name '*namep', to the answer section, unless they are
8413 1.1 christos * already there. Also add any pertinent additional data.
8414 1.1 christos *
8415 1.1 christos * If 'qctx->dbuf' is not NULL, then 'qctx->fname' is the name
8416 1.1 christos * whose data is stored 'qctx->dbuf'. In this case,
8417 1.1 christos * query_addrrset() guarantees that when it returns the name
8418 1.1 christos * will either have been kept or released.
8419 1.1 christos */
8420 1.1 christos CTRACE(ISC_LOG_DEBUG(3), "query_dns64");
8421 1.1 christos
8422 1.1 christos qctx->qtype = qctx->type = dns_rdatatype_aaaa;
8423 1.1 christos
8424 1.1 christos name = qctx->fname;
8425 1.1 christos mname = NULL;
8426 1.1 christos mrdataset = NULL;
8427 1.1 christos buffer = NULL;
8428 1.1 christos dns64_rdata = NULL;
8429 1.1 christos dns64_rdataset = NULL;
8430 1.1 christos dns64_rdatalist = NULL;
8431 1.9 christos result = dns_message_findname(
8432 1.9 christos client->message, section, name, dns_rdatatype_aaaa,
8433 1.9 christos qctx->rdataset->covers, &mname, &mrdataset);
8434 1.1 christos if (result == ISC_R_SUCCESS) {
8435 1.1 christos /*
8436 1.1 christos * We've already got an RRset of the given name and type.
8437 1.1 christos * There's nothing else to do;
8438 1.1 christos */
8439 1.9 christos CTRACE(ISC_LOG_DEBUG(3), "query_dns64: dns_message_findname "
8440 1.9 christos "succeeded: done");
8441 1.3 christos if (qctx->dbuf != NULL) {
8442 1.3 christos ns_client_releasename(client, &qctx->fname);
8443 1.3 christos }
8444 1.23 christos return ISC_R_SUCCESS;
8445 1.1 christos } else if (result == DNS_R_NXDOMAIN) {
8446 1.1 christos /*
8447 1.1 christos * The name doesn't exist.
8448 1.1 christos */
8449 1.3 christos if (qctx->dbuf != NULL) {
8450 1.3 christos ns_client_keepname(client, name, qctx->dbuf);
8451 1.3 christos }
8452 1.1 christos dns_message_addname(client->message, name, section);
8453 1.1 christos qctx->fname = NULL;
8454 1.1 christos mname = name;
8455 1.1 christos } else {
8456 1.1 christos RUNTIME_CHECK(result == DNS_R_NXRRSET);
8457 1.3 christos if (qctx->dbuf != NULL) {
8458 1.3 christos ns_client_releasename(client, &qctx->fname);
8459 1.3 christos }
8460 1.1 christos }
8461 1.1 christos
8462 1.1 christos if (qctx->rdataset->trust != dns_trust_secure) {
8463 1.1 christos client->query.attributes &= ~NS_QUERYATTR_SECURE;
8464 1.1 christos }
8465 1.1 christos
8466 1.1 christos isc_netaddr_fromsockaddr(&netaddr, &client->peeraddr);
8467 1.1 christos
8468 1.23 christos isc_buffer_allocate(client->manager->mctx, &buffer,
8469 1.9 christos view->dns64cnt * 16 *
8470 1.9 christos dns_rdataset_count(qctx->rdataset));
8471 1.23 christos dns_message_gettemprdataset(client->message, &dns64_rdataset);
8472 1.23 christos dns_message_gettemprdatalist(client->message, &dns64_rdatalist);
8473 1.1 christos
8474 1.1 christos dns_rdatalist_init(dns64_rdatalist);
8475 1.1 christos dns64_rdatalist->rdclass = dns_rdataclass_in;
8476 1.1 christos dns64_rdatalist->type = dns_rdatatype_aaaa;
8477 1.9 christos if (client->query.dns64_ttl != UINT32_MAX) {
8478 1.1 christos dns64_rdatalist->ttl = ISC_MIN(qctx->rdataset->ttl,
8479 1.1 christos client->query.dns64_ttl);
8480 1.9 christos } else {
8481 1.1 christos dns64_rdatalist->ttl = ISC_MIN(qctx->rdataset->ttl, 600);
8482 1.9 christos }
8483 1.1 christos
8484 1.9 christos if (RECURSIONOK(client)) {
8485 1.1 christos flags |= DNS_DNS64_RECURSIVE;
8486 1.9 christos }
8487 1.1 christos
8488 1.1 christos /*
8489 1.1 christos * We use the signatures from the A lookup to set DNS_DNS64_DNSSEC
8490 1.1 christos * as this provides a easy way to see if the answer was signed.
8491 1.1 christos */
8492 1.1 christos if (WANTDNSSEC(qctx->client) && qctx->sigrdataset != NULL &&
8493 1.1 christos dns_rdataset_isassociated(qctx->sigrdataset))
8494 1.9 christos {
8495 1.1 christos flags |= DNS_DNS64_DNSSEC;
8496 1.9 christos }
8497 1.1 christos
8498 1.1 christos for (result = dns_rdataset_first(qctx->rdataset);
8499 1.1 christos result == ISC_R_SUCCESS;
8500 1.9 christos result = dns_rdataset_next(qctx->rdataset))
8501 1.9 christos {
8502 1.9 christos for (dns64 = ISC_LIST_HEAD(client->view->dns64); dns64 != NULL;
8503 1.9 christos dns64 = dns_dns64_next(dns64))
8504 1.9 christos {
8505 1.1 christos dns_rdataset_current(qctx->rdataset, &rdata);
8506 1.1 christos isc_buffer_availableregion(buffer, &r);
8507 1.1 christos INSIST(r.length >= 16);
8508 1.1 christos result = dns_dns64_aaaafroma(dns64, &netaddr,
8509 1.1 christos client->signer, env, flags,
8510 1.1 christos rdata.data, r.base);
8511 1.1 christos if (result != ISC_R_SUCCESS) {
8512 1.1 christos dns_rdata_reset(&rdata);
8513 1.1 christos continue;
8514 1.1 christos }
8515 1.1 christos isc_buffer_add(buffer, 16);
8516 1.1 christos isc_buffer_remainingregion(buffer, &r);
8517 1.1 christos isc_buffer_forward(buffer, 16);
8518 1.23 christos dns_message_gettemprdata(client->message, &dns64_rdata);
8519 1.1 christos dns_rdata_init(dns64_rdata);
8520 1.1 christos dns_rdata_fromregion(dns64_rdata, dns_rdataclass_in,
8521 1.1 christos dns_rdatatype_aaaa, &r);
8522 1.1 christos ISC_LIST_APPEND(dns64_rdatalist->rdata, dns64_rdata,
8523 1.1 christos link);
8524 1.1 christos dns64_rdata = NULL;
8525 1.1 christos dns_rdata_reset(&rdata);
8526 1.1 christos }
8527 1.1 christos }
8528 1.9 christos if (result != ISC_R_NOMORE) {
8529 1.1 christos goto cleanup;
8530 1.9 christos }
8531 1.1 christos
8532 1.9 christos if (ISC_LIST_EMPTY(dns64_rdatalist->rdata)) {
8533 1.1 christos goto cleanup;
8534 1.9 christos }
8535 1.1 christos
8536 1.23 christos dns_rdatalist_tordataset(dns64_rdatalist, dns64_rdataset);
8537 1.1 christos dns_rdataset_setownercase(dns64_rdataset, mname);
8538 1.1 christos client->query.attributes |= NS_QUERYATTR_NOADDITIONAL;
8539 1.1 christos dns64_rdataset->trust = qctx->rdataset->trust;
8540 1.3 christos
8541 1.3 christos query_addtoname(mname, dns64_rdataset);
8542 1.3 christos query_setorder(qctx, mname, dns64_rdataset);
8543 1.3 christos
8544 1.1 christos dns64_rdataset = NULL;
8545 1.1 christos dns64_rdatalist = NULL;
8546 1.1 christos dns_message_takebuffer(client->message, &buffer);
8547 1.1 christos inc_stats(client, ns_statscounter_dns64);
8548 1.1 christos result = ISC_R_SUCCESS;
8549 1.1 christos
8550 1.9 christos cleanup:
8551 1.9 christos if (buffer != NULL) {
8552 1.1 christos isc_buffer_free(&buffer);
8553 1.9 christos }
8554 1.1 christos
8555 1.9 christos if (dns64_rdataset != NULL) {
8556 1.1 christos dns_message_puttemprdataset(client->message, &dns64_rdataset);
8557 1.9 christos }
8558 1.1 christos
8559 1.1 christos if (dns64_rdatalist != NULL) {
8560 1.1 christos for (dns64_rdata = ISC_LIST_HEAD(dns64_rdatalist->rdata);
8561 1.1 christos dns64_rdata != NULL;
8562 1.1 christos dns64_rdata = ISC_LIST_HEAD(dns64_rdatalist->rdata))
8563 1.1 christos {
8564 1.9 christos ISC_LIST_UNLINK(dns64_rdatalist->rdata, dns64_rdata,
8565 1.9 christos link);
8566 1.1 christos dns_message_puttemprdata(client->message, &dns64_rdata);
8567 1.1 christos }
8568 1.1 christos dns_message_puttemprdatalist(client->message, &dns64_rdatalist);
8569 1.1 christos }
8570 1.1 christos
8571 1.1 christos CTRACE(ISC_LOG_DEBUG(3), "query_dns64: done");
8572 1.23 christos return result;
8573 1.1 christos }
8574 1.1 christos
8575 1.1 christos static void
8576 1.1 christos query_filter64(query_ctx_t *qctx) {
8577 1.1 christos ns_client_t *client = qctx->client;
8578 1.1 christos dns_name_t *name, *mname;
8579 1.1 christos dns_rdata_t *myrdata;
8580 1.1 christos dns_rdata_t rdata = DNS_RDATA_INIT;
8581 1.1 christos dns_rdatalist_t *myrdatalist;
8582 1.1 christos dns_rdataset_t *myrdataset;
8583 1.1 christos isc_buffer_t *buffer;
8584 1.1 christos isc_region_t r;
8585 1.1 christos isc_result_t result;
8586 1.1 christos unsigned int i;
8587 1.1 christos const dns_section_t section = DNS_SECTION_ANSWER;
8588 1.1 christos
8589 1.1 christos CTRACE(ISC_LOG_DEBUG(3), "query_filter64");
8590 1.1 christos
8591 1.1 christos INSIST(client->query.dns64_aaaaok != NULL);
8592 1.1 christos INSIST(client->query.dns64_aaaaoklen ==
8593 1.1 christos dns_rdataset_count(qctx->rdataset));
8594 1.1 christos
8595 1.1 christos name = qctx->fname;
8596 1.1 christos mname = NULL;
8597 1.1 christos buffer = NULL;
8598 1.1 christos myrdata = NULL;
8599 1.1 christos myrdataset = NULL;
8600 1.1 christos myrdatalist = NULL;
8601 1.9 christos result = dns_message_findname(
8602 1.9 christos client->message, section, name, dns_rdatatype_aaaa,
8603 1.9 christos qctx->rdataset->covers, &mname, &myrdataset);
8604 1.1 christos if (result == ISC_R_SUCCESS) {
8605 1.1 christos /*
8606 1.1 christos * We've already got an RRset of the given name and type.
8607 1.1 christos * There's nothing else to do;
8608 1.1 christos */
8609 1.9 christos CTRACE(ISC_LOG_DEBUG(3), "query_filter64: dns_message_findname "
8610 1.9 christos "succeeded: done");
8611 1.3 christos if (qctx->dbuf != NULL) {
8612 1.3 christos ns_client_releasename(client, &qctx->fname);
8613 1.3 christos }
8614 1.1 christos return;
8615 1.1 christos } else if (result == DNS_R_NXDOMAIN) {
8616 1.1 christos mname = name;
8617 1.1 christos qctx->fname = NULL;
8618 1.1 christos } else {
8619 1.1 christos RUNTIME_CHECK(result == DNS_R_NXRRSET);
8620 1.3 christos if (qctx->dbuf != NULL) {
8621 1.3 christos ns_client_releasename(client, &qctx->fname);
8622 1.3 christos }
8623 1.1 christos qctx->dbuf = NULL;
8624 1.1 christos }
8625 1.1 christos
8626 1.1 christos if (qctx->rdataset->trust != dns_trust_secure) {
8627 1.1 christos client->query.attributes &= ~NS_QUERYATTR_SECURE;
8628 1.1 christos }
8629 1.1 christos
8630 1.23 christos isc_buffer_allocate(client->manager->mctx, &buffer,
8631 1.9 christos 16 * dns_rdataset_count(qctx->rdataset));
8632 1.23 christos dns_message_gettemprdataset(client->message, &myrdataset);
8633 1.23 christos dns_message_gettemprdatalist(client->message, &myrdatalist);
8634 1.1 christos
8635 1.1 christos dns_rdatalist_init(myrdatalist);
8636 1.1 christos myrdatalist->rdclass = dns_rdataclass_in;
8637 1.1 christos myrdatalist->type = dns_rdatatype_aaaa;
8638 1.1 christos myrdatalist->ttl = qctx->rdataset->ttl;
8639 1.1 christos
8640 1.1 christos i = 0;
8641 1.1 christos for (result = dns_rdataset_first(qctx->rdataset);
8642 1.1 christos result == ISC_R_SUCCESS;
8643 1.3 christos result = dns_rdataset_next(qctx->rdataset))
8644 1.3 christos {
8645 1.9 christos if (!client->query.dns64_aaaaok[i++]) {
8646 1.1 christos continue;
8647 1.9 christos }
8648 1.1 christos dns_rdataset_current(qctx->rdataset, &rdata);
8649 1.1 christos INSIST(rdata.length == 16);
8650 1.1 christos isc_buffer_putmem(buffer, rdata.data, rdata.length);
8651 1.1 christos isc_buffer_remainingregion(buffer, &r);
8652 1.1 christos isc_buffer_forward(buffer, rdata.length);
8653 1.23 christos dns_message_gettemprdata(client->message, &myrdata);
8654 1.1 christos dns_rdata_init(myrdata);
8655 1.1 christos dns_rdata_fromregion(myrdata, dns_rdataclass_in,
8656 1.1 christos dns_rdatatype_aaaa, &r);
8657 1.1 christos ISC_LIST_APPEND(myrdatalist->rdata, myrdata, link);
8658 1.1 christos myrdata = NULL;
8659 1.1 christos dns_rdata_reset(&rdata);
8660 1.1 christos }
8661 1.9 christos if (result != ISC_R_NOMORE) {
8662 1.1 christos goto cleanup;
8663 1.9 christos }
8664 1.1 christos
8665 1.23 christos dns_rdatalist_tordataset(myrdatalist, myrdataset);
8666 1.1 christos dns_rdataset_setownercase(myrdataset, name);
8667 1.1 christos client->query.attributes |= NS_QUERYATTR_NOADDITIONAL;
8668 1.1 christos if (mname == name) {
8669 1.3 christos if (qctx->dbuf != NULL) {
8670 1.3 christos ns_client_keepname(client, name, qctx->dbuf);
8671 1.3 christos }
8672 1.9 christos dns_message_addname(client->message, name, section);
8673 1.1 christos qctx->dbuf = NULL;
8674 1.1 christos }
8675 1.1 christos myrdataset->trust = qctx->rdataset->trust;
8676 1.3 christos
8677 1.3 christos query_addtoname(mname, myrdataset);
8678 1.3 christos query_setorder(qctx, mname, myrdataset);
8679 1.3 christos
8680 1.1 christos myrdataset = NULL;
8681 1.1 christos myrdatalist = NULL;
8682 1.1 christos dns_message_takebuffer(client->message, &buffer);
8683 1.1 christos
8684 1.9 christos cleanup:
8685 1.9 christos if (buffer != NULL) {
8686 1.1 christos isc_buffer_free(&buffer);
8687 1.9 christos }
8688 1.1 christos
8689 1.9 christos if (myrdataset != NULL) {
8690 1.1 christos dns_message_puttemprdataset(client->message, &myrdataset);
8691 1.9 christos }
8692 1.1 christos
8693 1.1 christos if (myrdatalist != NULL) {
8694 1.1 christos for (myrdata = ISC_LIST_HEAD(myrdatalist->rdata);
8695 1.1 christos myrdata != NULL;
8696 1.1 christos myrdata = ISC_LIST_HEAD(myrdatalist->rdata))
8697 1.1 christos {
8698 1.1 christos ISC_LIST_UNLINK(myrdatalist->rdata, myrdata, link);
8699 1.1 christos dns_message_puttemprdata(client->message, &myrdata);
8700 1.1 christos }
8701 1.1 christos dns_message_puttemprdatalist(client->message, &myrdatalist);
8702 1.1 christos }
8703 1.23 christos
8704 1.3 christos if (qctx->dbuf != NULL) {
8705 1.3 christos ns_client_releasename(client, &name);
8706 1.3 christos }
8707 1.1 christos
8708 1.1 christos CTRACE(ISC_LOG_DEBUG(3), "query_filter64: done");
8709 1.1 christos }
8710 1.1 christos
8711 1.1 christos /*%
8712 1.1 christos * Handle the case of a name not being found in a database lookup.
8713 1.1 christos * Called from query_gotanswer(). Passes off processing to
8714 1.1 christos * query_delegation() for a root referral if appropriate.
8715 1.1 christos */
8716 1.1 christos static isc_result_t
8717 1.1 christos query_notfound(query_ctx_t *qctx) {
8718 1.20 christos isc_result_t result = ISC_R_UNSET;
8719 1.1 christos
8720 1.9 christos CCTRACE(ISC_LOG_DEBUG(3), "query_notfound");
8721 1.9 christos
8722 1.3 christos CALL_HOOK(NS_QUERY_NOTFOUND_BEGIN, qctx);
8723 1.3 christos
8724 1.1 christos INSIST(!qctx->is_zone);
8725 1.1 christos
8726 1.9 christos if (qctx->db != NULL) {
8727 1.1 christos dns_db_detach(&qctx->db);
8728 1.9 christos }
8729 1.1 christos
8730 1.1 christos /*
8731 1.1 christos * If the cache doesn't even have the root NS,
8732 1.1 christos * try to get that from the hints DB.
8733 1.1 christos */
8734 1.3 christos if (qctx->view->hints != NULL) {
8735 1.1 christos dns_clientinfomethods_t cm;
8736 1.1 christos dns_clientinfo_t ci;
8737 1.1 christos
8738 1.1 christos dns_clientinfomethods_init(&cm, ns_client_sourceip);
8739 1.20 christos dns_clientinfo_init(&ci, qctx->client, NULL);
8740 1.1 christos
8741 1.3 christos dns_db_attach(qctx->view->hints, &qctx->db);
8742 1.9 christos result = dns_db_findext(qctx->db, dns_rootname, NULL,
8743 1.9 christos dns_rdatatype_ns, 0, qctx->client->now,
8744 1.9 christos &qctx->node, qctx->fname, &cm, &ci,
8745 1.1 christos qctx->rdataset, qctx->sigrdataset);
8746 1.1 christos } else {
8747 1.1 christos /* We have no hints. */
8748 1.1 christos result = ISC_R_FAILURE;
8749 1.1 christos }
8750 1.1 christos if (result != ISC_R_SUCCESS) {
8751 1.1 christos /*
8752 1.1 christos * Nonsensical root hints may require cleanup.
8753 1.1 christos */
8754 1.1 christos qctx_clean(qctx);
8755 1.1 christos
8756 1.1 christos /*
8757 1.1 christos * We don't have any root server hints, but
8758 1.1 christos * we may have working forwarders, so try to
8759 1.1 christos * recurse anyway.
8760 1.1 christos */
8761 1.1 christos if (RECURSIONOK(qctx->client)) {
8762 1.1 christos INSIST(!REDIRECT(qctx->client));
8763 1.3 christos result = ns_query_recurse(qctx->client, qctx->qtype,
8764 1.3 christos qctx->client->query.qname,
8765 1.3 christos NULL, NULL, qctx->resuming);
8766 1.1 christos if (result == ISC_R_SUCCESS) {
8767 1.3 christos CALL_HOOK(NS_QUERY_NOTFOUND_RECURSE, qctx);
8768 1.1 christos qctx->client->query.attributes |=
8769 1.9 christos NS_QUERYATTR_RECURSING;
8770 1.3 christos
8771 1.3 christos if (qctx->dns64) {
8772 1.1 christos qctx->client->query.attributes |=
8773 1.1 christos NS_QUERYATTR_DNS64;
8774 1.3 christos }
8775 1.3 christos if (qctx->dns64_exclude) {
8776 1.1 christos qctx->client->query.attributes |=
8777 1.1 christos NS_QUERYATTR_DNS64EXCLUDE;
8778 1.3 christos }
8779 1.13 christos } else if (query_usestale(qctx, result)) {
8780 1.13 christos /*
8781 1.13 christos * If serve-stale is enabled, query_usestale()
8782 1.13 christos * already set up 'qctx' for looking up a
8783 1.13 christos * stale response.
8784 1.13 christos */
8785 1.23 christos return query_lookup(qctx);
8786 1.3 christos } else {
8787 1.3 christos QUERY_ERROR(qctx, result);
8788 1.3 christos }
8789 1.23 christos return ns_query_done(qctx);
8790 1.1 christos } else {
8791 1.1 christos /* Unable to give root server referral. */
8792 1.9 christos CCTRACE(ISC_LOG_ERROR, "unable to give root server "
8793 1.9 christos "referral");
8794 1.3 christos QUERY_ERROR(qctx, result);
8795 1.23 christos return ns_query_done(qctx);
8796 1.1 christos }
8797 1.1 christos }
8798 1.1 christos
8799 1.23 christos return query_delegation(qctx);
8800 1.3 christos
8801 1.9 christos cleanup:
8802 1.23 christos return result;
8803 1.3 christos }
8804 1.3 christos
8805 1.3 christos /*%
8806 1.3 christos * We have a delegation but recursion is not allowed, so return the delegation
8807 1.3 christos * to the client.
8808 1.3 christos */
8809 1.3 christos static isc_result_t
8810 1.3 christos query_prepare_delegation_response(query_ctx_t *qctx) {
8811 1.20 christos isc_result_t result = ISC_R_UNSET;
8812 1.3 christos dns_rdataset_t **sigrdatasetp = NULL;
8813 1.3 christos bool detach = false;
8814 1.3 christos
8815 1.3 christos CALL_HOOK(NS_QUERY_PREP_DELEGATION_BEGIN, qctx);
8816 1.3 christos
8817 1.3 christos /*
8818 1.3 christos * qctx->fname could be released in query_addrrset(), so save a copy of
8819 1.3 christos * it here in case we need it.
8820 1.3 christos */
8821 1.3 christos dns_fixedname_init(&qctx->dsname);
8822 1.20 christos dns_name_copy(qctx->fname, dns_fixedname_name(&qctx->dsname));
8823 1.3 christos
8824 1.3 christos /*
8825 1.3 christos * This is the best answer.
8826 1.3 christos */
8827 1.3 christos qctx->client->query.isreferral = true;
8828 1.3 christos
8829 1.3 christos if (!dns_db_iscache(qctx->db) && qctx->client->query.gluedb == NULL) {
8830 1.3 christos dns_db_attach(qctx->db, &qctx->client->query.gluedb);
8831 1.3 christos detach = true;
8832 1.3 christos }
8833 1.3 christos
8834 1.3 christos /*
8835 1.3 christos * We must ensure NOADDITIONAL is off, because the generation of
8836 1.3 christos * additional data is required in delegations.
8837 1.3 christos */
8838 1.3 christos qctx->client->query.attributes &= ~NS_QUERYATTR_NOADDITIONAL;
8839 1.3 christos if (WANTDNSSEC(qctx->client) && qctx->sigrdataset != NULL) {
8840 1.3 christos sigrdatasetp = &qctx->sigrdataset;
8841 1.3 christos }
8842 1.9 christos query_addrrset(qctx, &qctx->fname, &qctx->rdataset, sigrdatasetp,
8843 1.9 christos qctx->dbuf, DNS_SECTION_AUTHORITY);
8844 1.3 christos if (detach) {
8845 1.3 christos dns_db_detach(&qctx->client->query.gluedb);
8846 1.3 christos }
8847 1.3 christos
8848 1.3 christos /*
8849 1.14 christos * Add DS/NSEC(3) record(s) if needed.
8850 1.3 christos */
8851 1.3 christos query_addds(qctx);
8852 1.3 christos
8853 1.23 christos return ns_query_done(qctx);
8854 1.3 christos
8855 1.9 christos cleanup:
8856 1.23 christos return result;
8857 1.1 christos }
8858 1.1 christos
8859 1.1 christos /*%
8860 1.1 christos * Handle a delegation response from an authoritative lookup. This
8861 1.1 christos * may trigger additional lookups, e.g. from the cache database to
8862 1.1 christos * see if we have a better answer; if that is not allowed, return the
8863 1.3 christos * delegation to the client and call ns_query_done().
8864 1.1 christos */
8865 1.1 christos static isc_result_t
8866 1.1 christos query_zone_delegation(query_ctx_t *qctx) {
8867 1.20 christos isc_result_t result = ISC_R_UNSET;
8868 1.3 christos
8869 1.3 christos CALL_HOOK(NS_QUERY_ZONE_DELEGATION_BEGIN, qctx);
8870 1.1 christos
8871 1.1 christos /*
8872 1.1 christos * If the query type is DS, look to see if we are
8873 1.1 christos * authoritative for the child zone
8874 1.1 christos */
8875 1.1 christos if (!RECURSIONOK(qctx->client) &&
8876 1.23 christos (qctx->options.noexact && qctx->qtype == dns_rdatatype_ds))
8877 1.1 christos {
8878 1.1 christos dns_db_t *tdb = NULL;
8879 1.1 christos dns_zone_t *tzone = NULL;
8880 1.1 christos dns_dbversion_t *tversion = NULL;
8881 1.23 christos dns_getdb_options_t options = { .partial = true };
8882 1.23 christos result = query_getzonedb(qctx->client,
8883 1.23 christos qctx->client->query.qname, qctx->qtype,
8884 1.23 christos options, &tzone, &tdb, &tversion);
8885 1.1 christos if (result != ISC_R_SUCCESS) {
8886 1.9 christos if (tdb != NULL) {
8887 1.1 christos dns_db_detach(&tdb);
8888 1.9 christos }
8889 1.9 christos if (tzone != NULL) {
8890 1.1 christos dns_zone_detach(&tzone);
8891 1.9 christos }
8892 1.1 christos } else {
8893 1.23 christos qctx->options.noexact = false;
8894 1.9 christos ns_client_putrdataset(qctx->client, &qctx->rdataset);
8895 1.3 christos if (qctx->sigrdataset != NULL) {
8896 1.3 christos ns_client_putrdataset(qctx->client,
8897 1.3 christos &qctx->sigrdataset);
8898 1.3 christos }
8899 1.3 christos if (qctx->fname != NULL) {
8900 1.3 christos ns_client_releasename(qctx->client,
8901 1.3 christos &qctx->fname);
8902 1.3 christos }
8903 1.9 christos if (qctx->node != NULL) {
8904 1.9 christos dns_db_detachnode(qctx->db, &qctx->node);
8905 1.9 christos }
8906 1.9 christos if (qctx->db != NULL) {
8907 1.1 christos dns_db_detach(&qctx->db);
8908 1.9 christos }
8909 1.9 christos if (qctx->zone != NULL) {
8910 1.1 christos dns_zone_detach(&qctx->zone);
8911 1.9 christos }
8912 1.1 christos qctx->version = NULL;
8913 1.1 christos RESTORE(qctx->version, tversion);
8914 1.1 christos RESTORE(qctx->db, tdb);
8915 1.1 christos RESTORE(qctx->zone, tzone);
8916 1.3 christos qctx->authoritative = true;
8917 1.1 christos
8918 1.23 christos return query_lookup(qctx);
8919 1.1 christos }
8920 1.1 christos }
8921 1.1 christos
8922 1.3 christos if (USECACHE(qctx->client) &&
8923 1.3 christos (RECURSIONOK(qctx->client) ||
8924 1.3 christos (qctx->zone != NULL &&
8925 1.3 christos dns_zone_gettype(qctx->zone) == dns_zone_mirror)))
8926 1.3 christos {
8927 1.1 christos /*
8928 1.1 christos * We might have a better answer or delegation in the
8929 1.1 christos * cache. We'll remember the current values of fname,
8930 1.1 christos * rdataset, and sigrdataset. We'll then go looking for
8931 1.1 christos * QNAME in the cache. If we find something better, we'll
8932 1.1 christos * use it instead. If not, then query_lookup() calls
8933 1.1 christos * query_notfound() which calls query_delegation(), and
8934 1.1 christos * we'll restore these values there.
8935 1.1 christos */
8936 1.3 christos ns_client_keepname(qctx->client, qctx->fname, qctx->dbuf);
8937 1.1 christos SAVE(qctx->zdb, qctx->db);
8938 1.3 christos SAVE(qctx->znode, qctx->node);
8939 1.1 christos SAVE(qctx->zfname, qctx->fname);
8940 1.1 christos SAVE(qctx->zversion, qctx->version);
8941 1.1 christos SAVE(qctx->zrdataset, qctx->rdataset);
8942 1.1 christos SAVE(qctx->zsigrdataset, qctx->sigrdataset);
8943 1.3 christos dns_db_attach(qctx->view->cachedb, &qctx->db);
8944 1.3 christos qctx->is_zone = false;
8945 1.1 christos
8946 1.24 christos /*
8947 1.24 christos * Since 'qctx->is_zone' is now false, we should reconsider
8948 1.24 christos * setting the 'stalefirst' option, which is usually set in
8949 1.24 christos * the beginning in ns__query_start().
8950 1.24 christos */
8951 1.25 christos qctx->options.stalefirst =
8952 1.25 christos (qctx->view->staleanswerclienttimeout == 0 &&
8953 1.25 christos dns_view_staleanswerenabled(qctx->view));
8954 1.24 christos
8955 1.24 christos result = query_lookup(qctx);
8956 1.24 christos
8957 1.24 christos /*
8958 1.24 christos * After fetch completes, this option is not expected to be set.
8959 1.24 christos */
8960 1.24 christos qctx->options.stalefirst = false;
8961 1.24 christos
8962 1.24 christos return result;
8963 1.1 christos }
8964 1.1 christos
8965 1.23 christos return query_prepare_delegation_response(qctx);
8966 1.1 christos
8967 1.9 christos cleanup:
8968 1.23 christos return result;
8969 1.1 christos }
8970 1.1 christos
8971 1.1 christos /*%
8972 1.1 christos * Handle delegation responses, including root referrals.
8973 1.1 christos *
8974 1.1 christos * If the delegation was returned from authoritative data,
8975 1.1 christos * call query_zone_delgation(). Otherwise, we can start
8976 1.1 christos * recursion if allowed; or else return the delegation to the
8977 1.3 christos * client and call ns_query_done().
8978 1.1 christos */
8979 1.1 christos static isc_result_t
8980 1.1 christos query_delegation(query_ctx_t *qctx) {
8981 1.20 christos isc_result_t result = ISC_R_UNSET;
8982 1.1 christos
8983 1.9 christos CCTRACE(ISC_LOG_DEBUG(3), "query_delegation");
8984 1.9 christos
8985 1.3 christos CALL_HOOK(NS_QUERY_DELEGATION_BEGIN, qctx);
8986 1.3 christos
8987 1.3 christos qctx->authoritative = false;
8988 1.1 christos
8989 1.1 christos if (qctx->is_zone) {
8990 1.23 christos return query_zone_delegation(qctx);
8991 1.1 christos }
8992 1.1 christos
8993 1.1 christos if (qctx->zfname != NULL &&
8994 1.1 christos (!dns_name_issubdomain(qctx->fname, qctx->zfname) ||
8995 1.1 christos (qctx->is_staticstub_zone &&
8996 1.1 christos dns_name_equal(qctx->fname, qctx->zfname))))
8997 1.1 christos {
8998 1.1 christos /*
8999 1.1 christos * In the following cases use "authoritative"
9000 1.1 christos * data instead of the cache delegation:
9001 1.1 christos * 1. We've already got a delegation from
9002 1.1 christos * authoritative data, and it is better
9003 1.1 christos * than what we found in the cache.
9004 1.1 christos * (See the comment above.)
9005 1.1 christos * 2. The query name matches the origin name
9006 1.1 christos * of a static-stub zone. This needs to be
9007 1.1 christos * considered for the case where the NS of
9008 1.1 christos * the static-stub zone and the cached NS
9009 1.1 christos * are different. We still need to contact
9010 1.1 christos * the nameservers configured in the
9011 1.1 christos * static-stub zone.
9012 1.1 christos */
9013 1.3 christos ns_client_releasename(qctx->client, &qctx->fname);
9014 1.1 christos
9015 1.1 christos /*
9016 1.3 christos * We've already done ns_client_keepname() on
9017 1.1 christos * qctx->zfname, so we must set dbuf to NULL to
9018 1.1 christos * prevent query_addrrset() from trying to
9019 1.3 christos * call ns_client_keepname() again.
9020 1.1 christos */
9021 1.1 christos qctx->dbuf = NULL;
9022 1.3 christos ns_client_putrdataset(qctx->client, &qctx->rdataset);
9023 1.3 christos if (qctx->sigrdataset != NULL) {
9024 1.9 christos ns_client_putrdataset(qctx->client, &qctx->sigrdataset);
9025 1.3 christos }
9026 1.1 christos qctx->version = NULL;
9027 1.1 christos
9028 1.3 christos dns_db_detachnode(qctx->db, &qctx->node);
9029 1.3 christos dns_db_detach(&qctx->db);
9030 1.3 christos RESTORE(qctx->db, qctx->zdb);
9031 1.3 christos RESTORE(qctx->node, qctx->znode);
9032 1.1 christos RESTORE(qctx->fname, qctx->zfname);
9033 1.1 christos RESTORE(qctx->version, qctx->zversion);
9034 1.1 christos RESTORE(qctx->rdataset, qctx->zrdataset);
9035 1.1 christos RESTORE(qctx->sigrdataset, qctx->zsigrdataset);
9036 1.3 christos }
9037 1.1 christos
9038 1.3 christos result = query_delegation_recurse(qctx);
9039 1.3 christos if (result != ISC_R_COMPLETE) {
9040 1.23 christos return result;
9041 1.1 christos }
9042 1.1 christos
9043 1.23 christos return query_prepare_delegation_response(qctx);
9044 1.1 christos
9045 1.9 christos cleanup:
9046 1.23 christos return result;
9047 1.3 christos }
9048 1.1 christos
9049 1.3 christos /*%
9050 1.3 christos * Handle recursive queries that are triggered as part of the
9051 1.3 christos * delegation process.
9052 1.3 christos */
9053 1.3 christos static isc_result_t
9054 1.3 christos query_delegation_recurse(query_ctx_t *qctx) {
9055 1.20 christos isc_result_t result = ISC_R_UNSET;
9056 1.3 christos dns_name_t *qname = qctx->client->query.qname;
9057 1.1 christos
9058 1.9 christos CCTRACE(ISC_LOG_DEBUG(3), "query_delegation_recurse");
9059 1.9 christos
9060 1.3 christos if (!RECURSIONOK(qctx->client)) {
9061 1.23 christos return ISC_R_COMPLETE;
9062 1.1 christos }
9063 1.1 christos
9064 1.3 christos CALL_HOOK(NS_QUERY_DELEGATION_RECURSE_BEGIN, qctx);
9065 1.3 christos
9066 1.1 christos /*
9067 1.3 christos * We have a delegation and recursion is allowed,
9068 1.3 christos * so we call ns_query_recurse() to follow it.
9069 1.3 christos * This phase of the query processing is done;
9070 1.3 christos * we'll resume via fetch_callback() and
9071 1.3 christos * query_resume() when the recursion is complete.
9072 1.1 christos */
9073 1.1 christos
9074 1.3 christos INSIST(!REDIRECT(qctx->client));
9075 1.1 christos
9076 1.3 christos if (dns_rdatatype_atparent(qctx->type)) {
9077 1.3 christos /*
9078 1.3 christos * Parent is authoritative for this RDATA type (i.e. DS).
9079 1.3 christos */
9080 1.3 christos result = ns_query_recurse(qctx->client, qctx->qtype, qname,
9081 1.3 christos NULL, NULL, qctx->resuming);
9082 1.3 christos } else if (qctx->dns64) {
9083 1.3 christos /*
9084 1.3 christos * Look up an A record so we can synthesize DNS64.
9085 1.3 christos */
9086 1.3 christos result = ns_query_recurse(qctx->client, dns_rdatatype_a, qname,
9087 1.3 christos NULL, NULL, qctx->resuming);
9088 1.3 christos } else {
9089 1.3 christos /*
9090 1.3 christos * Any other recursion.
9091 1.3 christos */
9092 1.3 christos result = ns_query_recurse(qctx->client, qctx->qtype, qname,
9093 1.3 christos qctx->fname, qctx->rdataset,
9094 1.3 christos qctx->resuming);
9095 1.1 christos }
9096 1.1 christos
9097 1.3 christos if (result == ISC_R_SUCCESS) {
9098 1.3 christos qctx->client->query.attributes |= NS_QUERYATTR_RECURSING;
9099 1.3 christos if (qctx->dns64) {
9100 1.3 christos qctx->client->query.attributes |= NS_QUERYATTR_DNS64;
9101 1.3 christos }
9102 1.3 christos if (qctx->dns64_exclude) {
9103 1.3 christos qctx->client->query.attributes |=
9104 1.9 christos NS_QUERYATTR_DNS64EXCLUDE;
9105 1.3 christos }
9106 1.13 christos } else if (query_usestale(qctx, result)) {
9107 1.13 christos /*
9108 1.13 christos * If serve-stale is enabled, query_usestale() already set up
9109 1.13 christos * 'qctx' for looking up a stale response.
9110 1.13 christos */
9111 1.23 christos return query_lookup(qctx);
9112 1.3 christos } else {
9113 1.3 christos QUERY_ERROR(qctx, result);
9114 1.1 christos }
9115 1.1 christos
9116 1.23 christos return ns_query_done(qctx);
9117 1.1 christos
9118 1.9 christos cleanup:
9119 1.23 christos return result;
9120 1.1 christos }
9121 1.1 christos
9122 1.1 christos /*%
9123 1.14 christos * Add DS/NSEC(3) record(s) if needed.
9124 1.1 christos */
9125 1.1 christos static void
9126 1.1 christos query_addds(query_ctx_t *qctx) {
9127 1.1 christos ns_client_t *client = qctx->client;
9128 1.1 christos dns_fixedname_t fixed;
9129 1.1 christos dns_name_t *fname = NULL;
9130 1.1 christos dns_name_t *rname = NULL;
9131 1.1 christos dns_name_t *name;
9132 1.1 christos dns_rdataset_t *rdataset = NULL, *sigrdataset = NULL;
9133 1.1 christos isc_buffer_t *dbuf, b;
9134 1.1 christos isc_result_t result;
9135 1.1 christos unsigned int count;
9136 1.1 christos
9137 1.1 christos CTRACE(ISC_LOG_DEBUG(3), "query_addds");
9138 1.1 christos
9139 1.1 christos /*
9140 1.1 christos * DS not needed.
9141 1.1 christos */
9142 1.1 christos if (!WANTDNSSEC(client)) {
9143 1.1 christos return;
9144 1.1 christos }
9145 1.1 christos
9146 1.1 christos /*
9147 1.1 christos * We'll need some resources...
9148 1.1 christos */
9149 1.3 christos rdataset = ns_client_newrdataset(client);
9150 1.3 christos sigrdataset = ns_client_newrdataset(client);
9151 1.1 christos
9152 1.1 christos /*
9153 1.1 christos * Look for the DS record, which may or may not be present.
9154 1.1 christos */
9155 1.1 christos result = dns_db_findrdataset(qctx->db, qctx->node, qctx->version,
9156 1.9 christos dns_rdatatype_ds, 0, client->now, rdataset,
9157 1.9 christos sigrdataset);
9158 1.1 christos /*
9159 1.1 christos * If we didn't find it, look for an NSEC.
9160 1.1 christos */
9161 1.9 christos if (result == ISC_R_NOTFOUND) {
9162 1.9 christos result = dns_db_findrdataset(
9163 1.9 christos qctx->db, qctx->node, qctx->version, dns_rdatatype_nsec,
9164 1.9 christos 0, client->now, rdataset, sigrdataset);
9165 1.9 christos }
9166 1.9 christos if (result != ISC_R_SUCCESS && result != ISC_R_NOTFOUND) {
9167 1.1 christos goto addnsec3;
9168 1.9 christos }
9169 1.1 christos if (!dns_rdataset_isassociated(rdataset) ||
9170 1.1 christos !dns_rdataset_isassociated(sigrdataset))
9171 1.9 christos {
9172 1.1 christos goto addnsec3;
9173 1.9 christos }
9174 1.1 christos
9175 1.1 christos /*
9176 1.1 christos * We've already added the NS record, so if the name's not there,
9177 1.14 christos * we have other problems.
9178 1.1 christos */
9179 1.1 christos result = dns_message_firstname(client->message, DNS_SECTION_AUTHORITY);
9180 1.9 christos if (result != ISC_R_SUCCESS) {
9181 1.1 christos goto cleanup;
9182 1.9 christos }
9183 1.1 christos
9184 1.14 christos /*
9185 1.14 christos * Find the delegation in the response message - it is not necessarily
9186 1.14 christos * the first name in the AUTHORITY section when wildcard processing is
9187 1.14 christos * involved.
9188 1.14 christos */
9189 1.14 christos while (result == ISC_R_SUCCESS) {
9190 1.14 christos rname = NULL;
9191 1.14 christos dns_message_currentname(client->message, DNS_SECTION_AUTHORITY,
9192 1.14 christos &rname);
9193 1.14 christos result = dns_message_findtype(rname, dns_rdatatype_ns, 0, NULL);
9194 1.14 christos if (result == ISC_R_SUCCESS) {
9195 1.14 christos break;
9196 1.14 christos }
9197 1.14 christos result = dns_message_nextname(client->message,
9198 1.14 christos DNS_SECTION_AUTHORITY);
9199 1.14 christos }
9200 1.14 christos
9201 1.9 christos if (result != ISC_R_SUCCESS) {
9202 1.1 christos goto cleanup;
9203 1.9 christos }
9204 1.1 christos
9205 1.14 christos /*
9206 1.14 christos * Add the relevant RRset (DS or NSEC) to the delegation.
9207 1.14 christos */
9208 1.14 christos query_addrrset(qctx, &rname, &rdataset, &sigrdataset, NULL,
9209 1.14 christos DNS_SECTION_AUTHORITY);
9210 1.14 christos goto cleanup;
9211 1.1 christos
9212 1.9 christos addnsec3:
9213 1.9 christos if (!dns_db_iszone(qctx->db)) {
9214 1.1 christos goto cleanup;
9215 1.9 christos }
9216 1.1 christos /*
9217 1.1 christos * Add the NSEC3 which proves the DS does not exist.
9218 1.1 christos */
9219 1.3 christos dbuf = ns_client_getnamebuf(client);
9220 1.3 christos fname = ns_client_newname(client, dbuf, &b);
9221 1.1 christos dns_fixedname_init(&fixed);
9222 1.9 christos if (dns_rdataset_isassociated(rdataset)) {
9223 1.1 christos dns_rdataset_disassociate(rdataset);
9224 1.9 christos }
9225 1.9 christos if (dns_rdataset_isassociated(sigrdataset)) {
9226 1.1 christos dns_rdataset_disassociate(sigrdataset);
9227 1.9 christos }
9228 1.1 christos name = dns_fixedname_name(&qctx->dsname);
9229 1.1 christos query_findclosestnsec3(name, qctx->db, qctx->version, client, rdataset,
9230 1.3 christos sigrdataset, fname, true,
9231 1.1 christos dns_fixedname_name(&fixed));
9232 1.9 christos if (!dns_rdataset_isassociated(rdataset)) {
9233 1.1 christos goto cleanup;
9234 1.9 christos }
9235 1.3 christos query_addrrset(qctx, &fname, &rdataset, &sigrdataset, dbuf,
9236 1.1 christos DNS_SECTION_AUTHORITY);
9237 1.1 christos /*
9238 1.1 christos * Did we find the closest provable encloser instead?
9239 1.1 christos * If so add the nearest to the closest provable encloser.
9240 1.1 christos */
9241 1.1 christos if (!dns_name_equal(name, dns_fixedname_name(&fixed))) {
9242 1.1 christos count = dns_name_countlabels(dns_fixedname_name(&fixed)) + 1;
9243 1.1 christos dns_name_getlabelsequence(name,
9244 1.1 christos dns_name_countlabels(name) - count,
9245 1.1 christos count, dns_fixedname_name(&fixed));
9246 1.1 christos fixfname(client, &fname, &dbuf, &b);
9247 1.1 christos fixrdataset(client, &rdataset);
9248 1.1 christos fixrdataset(client, &sigrdataset);
9249 1.9 christos if (fname == NULL || rdataset == NULL || sigrdataset == NULL) {
9250 1.9 christos goto cleanup;
9251 1.9 christos }
9252 1.9 christos query_findclosestnsec3(dns_fixedname_name(&fixed), qctx->db,
9253 1.9 christos qctx->version, client, rdataset,
9254 1.9 christos sigrdataset, fname, false, NULL);
9255 1.9 christos if (!dns_rdataset_isassociated(rdataset)) {
9256 1.1 christos goto cleanup;
9257 1.9 christos }
9258 1.3 christos query_addrrset(qctx, &fname, &rdataset, &sigrdataset, dbuf,
9259 1.1 christos DNS_SECTION_AUTHORITY);
9260 1.1 christos }
9261 1.1 christos
9262 1.9 christos cleanup:
9263 1.3 christos if (rdataset != NULL) {
9264 1.3 christos ns_client_putrdataset(client, &rdataset);
9265 1.3 christos }
9266 1.3 christos if (sigrdataset != NULL) {
9267 1.3 christos ns_client_putrdataset(client, &sigrdataset);
9268 1.3 christos }
9269 1.3 christos if (fname != NULL) {
9270 1.3 christos ns_client_releasename(client, &fname);
9271 1.3 christos }
9272 1.1 christos }
9273 1.1 christos
9274 1.1 christos /*%
9275 1.1 christos * Handle authoritative NOERROR/NODATA responses.
9276 1.1 christos */
9277 1.1 christos static isc_result_t
9278 1.3 christos query_nodata(query_ctx_t *qctx, isc_result_t res) {
9279 1.3 christos isc_result_t result = res;
9280 1.3 christos
9281 1.9 christos CCTRACE(ISC_LOG_DEBUG(3), "query_nodata");
9282 1.9 christos
9283 1.3 christos CALL_HOOK(NS_QUERY_NODATA_BEGIN, qctx);
9284 1.3 christos
9285 1.1 christos #ifdef dns64_bis_return_excluded_addresses
9286 1.1 christos if (qctx->dns64)
9287 1.9 christos #else /* ifdef dns64_bis_return_excluded_addresses */
9288 1.1 christos if (qctx->dns64 && !qctx->dns64_exclude)
9289 1.9 christos #endif /* ifdef dns64_bis_return_excluded_addresses */
9290 1.1 christos {
9291 1.1 christos isc_buffer_t b;
9292 1.1 christos /*
9293 1.1 christos * Restore the answers from the previous AAAA lookup.
9294 1.1 christos */
9295 1.9 christos if (qctx->rdataset != NULL) {
9296 1.3 christos ns_client_putrdataset(qctx->client, &qctx->rdataset);
9297 1.9 christos }
9298 1.9 christos if (qctx->sigrdataset != NULL) {
9299 1.3 christos ns_client_putrdataset(qctx->client, &qctx->sigrdataset);
9300 1.9 christos }
9301 1.1 christos RESTORE(qctx->rdataset, qctx->client->query.dns64_aaaa);
9302 1.1 christos RESTORE(qctx->sigrdataset, qctx->client->query.dns64_sigaaaa);
9303 1.1 christos if (qctx->fname == NULL) {
9304 1.3 christos qctx->dbuf = ns_client_getnamebuf(qctx->client);
9305 1.3 christos qctx->fname = ns_client_newname(qctx->client,
9306 1.3 christos qctx->dbuf, &b);
9307 1.1 christos }
9308 1.20 christos dns_name_copy(qctx->client->query.qname, qctx->fname);
9309 1.3 christos qctx->dns64 = false;
9310 1.1 christos #ifdef dns64_bis_return_excluded_addresses
9311 1.1 christos /*
9312 1.1 christos * Resume the diverted processing of the AAAA response?
9313 1.1 christos */
9314 1.9 christos if (qctx->dns64_exclude) {
9315 1.23 christos return query_prepresponse(qctx);
9316 1.9 christos }
9317 1.9 christos #endif /* ifdef dns64_bis_return_excluded_addresses */
9318 1.9 christos } else if ((result == DNS_R_NXRRSET || result == DNS_R_NCACHENXRRSET) &&
9319 1.9 christos !ISC_LIST_EMPTY(qctx->view->dns64) && !qctx->nxrewrite &&
9320 1.1 christos qctx->client->message->rdclass == dns_rdataclass_in &&
9321 1.1 christos qctx->qtype == dns_rdatatype_aaaa)
9322 1.1 christos {
9323 1.1 christos /*
9324 1.1 christos * Look to see if there are A records for this name.
9325 1.1 christos */
9326 1.1 christos switch (result) {
9327 1.1 christos case DNS_R_NCACHENXRRSET:
9328 1.1 christos /*
9329 1.1 christos * This is from the negative cache; if the ttl is
9330 1.1 christos * zero, we need to work out whether we have just
9331 1.1 christos * decremented to zero or there was no negative
9332 1.1 christos * cache ttl in the answer.
9333 1.1 christos */
9334 1.1 christos if (qctx->rdataset->ttl != 0) {
9335 1.1 christos qctx->client->query.dns64_ttl =
9336 1.1 christos qctx->rdataset->ttl;
9337 1.1 christos break;
9338 1.1 christos }
9339 1.1 christos if (dns_rdataset_first(qctx->rdataset) == ISC_R_SUCCESS)
9340 1.9 christos {
9341 1.1 christos qctx->client->query.dns64_ttl = 0;
9342 1.9 christos }
9343 1.1 christos break;
9344 1.1 christos case DNS_R_NXRRSET:
9345 1.1 christos qctx->client->query.dns64_ttl =
9346 1.1 christos dns64_ttl(qctx->db, qctx->version);
9347 1.1 christos break;
9348 1.1 christos default:
9349 1.15 christos UNREACHABLE();
9350 1.1 christos }
9351 1.1 christos
9352 1.1 christos SAVE(qctx->client->query.dns64_aaaa, qctx->rdataset);
9353 1.1 christos SAVE(qctx->client->query.dns64_sigaaaa, qctx->sigrdataset);
9354 1.3 christos ns_client_releasename(qctx->client, &qctx->fname);
9355 1.1 christos dns_db_detachnode(qctx->db, &qctx->node);
9356 1.1 christos qctx->type = qctx->qtype = dns_rdatatype_a;
9357 1.3 christos qctx->dns64 = true;
9358 1.23 christos return query_lookup(qctx);
9359 1.1 christos }
9360 1.1 christos
9361 1.1 christos if (qctx->is_zone) {
9362 1.23 christos return query_sign_nodata(qctx);
9363 1.1 christos } else {
9364 1.1 christos /*
9365 1.1 christos * We don't call query_addrrset() because we don't need any
9366 1.1 christos * of its extra features (and things would probably break!).
9367 1.1 christos */
9368 1.1 christos if (dns_rdataset_isassociated(qctx->rdataset)) {
9369 1.3 christos ns_client_keepname(qctx->client, qctx->fname,
9370 1.3 christos qctx->dbuf);
9371 1.9 christos dns_message_addname(qctx->client->message, qctx->fname,
9372 1.1 christos DNS_SECTION_AUTHORITY);
9373 1.9 christos ISC_LIST_APPEND(qctx->fname->list, qctx->rdataset,
9374 1.9 christos link);
9375 1.1 christos qctx->fname = NULL;
9376 1.1 christos qctx->rdataset = NULL;
9377 1.1 christos }
9378 1.1 christos }
9379 1.1 christos
9380 1.23 christos return ns_query_done(qctx);
9381 1.3 christos
9382 1.9 christos cleanup:
9383 1.23 christos return result;
9384 1.1 christos }
9385 1.1 christos
9386 1.1 christos /*%
9387 1.1 christos * Add RRSIGs for NOERROR/NODATA responses when answering authoritatively.
9388 1.1 christos */
9389 1.1 christos isc_result_t
9390 1.1 christos query_sign_nodata(query_ctx_t *qctx) {
9391 1.1 christos isc_result_t result;
9392 1.9 christos
9393 1.9 christos CCTRACE(ISC_LOG_DEBUG(3), "query_sign_nodata");
9394 1.9 christos
9395 1.1 christos /*
9396 1.1 christos * Look for a NSEC3 record if we don't have a NSEC record.
9397 1.1 christos */
9398 1.9 christos if (qctx->redirected) {
9399 1.23 christos return ns_query_done(qctx);
9400 1.9 christos }
9401 1.1 christos if (!dns_rdataset_isassociated(qctx->rdataset) &&
9402 1.16 christos WANTDNSSEC(qctx->client))
9403 1.16 christos {
9404 1.23 christos if (!qctx->fname->attributes.wildcard) {
9405 1.1 christos dns_name_t *found;
9406 1.1 christos dns_name_t *qname;
9407 1.1 christos dns_fixedname_t fixed;
9408 1.1 christos isc_buffer_t b;
9409 1.1 christos
9410 1.1 christos found = dns_fixedname_initname(&fixed);
9411 1.1 christos qname = qctx->client->query.qname;
9412 1.1 christos
9413 1.1 christos query_findclosestnsec3(qname, qctx->db, qctx->version,
9414 1.1 christos qctx->client, qctx->rdataset,
9415 1.1 christos qctx->sigrdataset, qctx->fname,
9416 1.3 christos true, found);
9417 1.1 christos /*
9418 1.1 christos * Did we find the closest provable encloser
9419 1.1 christos * instead? If so add the nearest to the
9420 1.1 christos * closest provable encloser.
9421 1.1 christos */
9422 1.1 christos if (dns_rdataset_isassociated(qctx->rdataset) &&
9423 1.1 christos !dns_name_equal(qname, found) &&
9424 1.23 christos (((qctx->client->manager->sctx->options &
9425 1.1 christos NS_SERVER_NONEAREST) == 0) ||
9426 1.1 christos qctx->qtype == dns_rdatatype_ds))
9427 1.1 christos {
9428 1.1 christos unsigned int count;
9429 1.1 christos unsigned int skip;
9430 1.1 christos
9431 1.1 christos /*
9432 1.1 christos * Add the closest provable encloser.
9433 1.1 christos */
9434 1.3 christos query_addrrset(qctx, &qctx->fname,
9435 1.1 christos &qctx->rdataset,
9436 1.9 christos &qctx->sigrdataset, qctx->dbuf,
9437 1.1 christos DNS_SECTION_AUTHORITY);
9438 1.1 christos
9439 1.9 christos count = dns_name_countlabels(found) + 1;
9440 1.9 christos skip = dns_name_countlabels(qname) - count;
9441 1.9 christos dns_name_getlabelsequence(qname, skip, count,
9442 1.1 christos found);
9443 1.1 christos
9444 1.1 christos fixfname(qctx->client, &qctx->fname,
9445 1.1 christos &qctx->dbuf, &b);
9446 1.1 christos fixrdataset(qctx->client, &qctx->rdataset);
9447 1.1 christos fixrdataset(qctx->client, &qctx->sigrdataset);
9448 1.1 christos if (qctx->fname == NULL ||
9449 1.1 christos qctx->rdataset == NULL ||
9450 1.16 christos qctx->sigrdataset == NULL)
9451 1.16 christos {
9452 1.9 christos CCTRACE(ISC_LOG_ERROR, "query_sign_"
9453 1.9 christos "nodata: "
9454 1.9 christos "failure "
9455 1.9 christos "getting "
9456 1.9 christos "closest "
9457 1.9 christos "encloser");
9458 1.3 christos QUERY_ERROR(qctx, ISC_R_NOMEMORY);
9459 1.23 christos return ns_query_done(qctx);
9460 1.1 christos }
9461 1.1 christos /*
9462 1.1 christos * 'nearest' doesn't exist so
9463 1.3 christos * 'exist' is set to false.
9464 1.1 christos */
9465 1.9 christos query_findclosestnsec3(
9466 1.9 christos found, qctx->db, qctx->version,
9467 1.9 christos qctx->client, qctx->rdataset,
9468 1.9 christos qctx->sigrdataset, qctx->fname, false,
9469 1.9 christos NULL);
9470 1.1 christos }
9471 1.1 christos } else {
9472 1.3 christos ns_client_releasename(qctx->client, &qctx->fname);
9473 1.3 christos query_addwildcardproof(qctx, false, true);
9474 1.1 christos }
9475 1.1 christos }
9476 1.1 christos if (dns_rdataset_isassociated(qctx->rdataset)) {
9477 1.1 christos /*
9478 1.1 christos * If we've got a NSEC record, we need to save the
9479 1.1 christos * name now because we're going call query_addsoa()
9480 1.1 christos * below, and it needs to use the name buffer.
9481 1.1 christos */
9482 1.3 christos ns_client_keepname(qctx->client, qctx->fname, qctx->dbuf);
9483 1.1 christos } else if (qctx->fname != NULL) {
9484 1.1 christos /*
9485 1.1 christos * We're not going to use fname, and need to release
9486 1.1 christos * our hold on the name buffer so query_addsoa()
9487 1.1 christos * may use it.
9488 1.1 christos */
9489 1.3 christos ns_client_releasename(qctx->client, &qctx->fname);
9490 1.1 christos }
9491 1.1 christos
9492 1.1 christos /*
9493 1.1 christos * The RPZ SOA has already been added to the additional section
9494 1.1 christos * if this was an RPZ rewrite, but if it wasn't, add it now.
9495 1.1 christos */
9496 1.1 christos if (!qctx->nxrewrite) {
9497 1.9 christos result = query_addsoa(qctx, UINT32_MAX, DNS_SECTION_AUTHORITY);
9498 1.1 christos if (result != ISC_R_SUCCESS) {
9499 1.1 christos QUERY_ERROR(qctx, result);
9500 1.23 christos return ns_query_done(qctx);
9501 1.1 christos }
9502 1.1 christos }
9503 1.1 christos
9504 1.1 christos /*
9505 1.1 christos * Add NSEC record if we found one.
9506 1.1 christos */
9507 1.1 christos if (WANTDNSSEC(qctx->client) &&
9508 1.16 christos dns_rdataset_isassociated(qctx->rdataset))
9509 1.16 christos {
9510 1.1 christos query_addnxrrsetnsec(qctx);
9511 1.1 christos }
9512 1.1 christos
9513 1.23 christos return ns_query_done(qctx);
9514 1.1 christos }
9515 1.1 christos
9516 1.1 christos static void
9517 1.1 christos query_addnxrrsetnsec(query_ctx_t *qctx) {
9518 1.1 christos ns_client_t *client = qctx->client;
9519 1.1 christos dns_rdata_t sigrdata;
9520 1.1 christos dns_rdata_rrsig_t sig;
9521 1.1 christos unsigned int labels;
9522 1.1 christos isc_buffer_t *dbuf, b;
9523 1.1 christos dns_name_t *fname;
9524 1.3 christos isc_result_t result;
9525 1.1 christos
9526 1.1 christos INSIST(qctx->fname != NULL);
9527 1.1 christos
9528 1.23 christos if (!qctx->fname->attributes.wildcard) {
9529 1.9 christos query_addrrset(qctx, &qctx->fname, &qctx->rdataset,
9530 1.9 christos &qctx->sigrdataset, NULL, DNS_SECTION_AUTHORITY);
9531 1.1 christos return;
9532 1.1 christos }
9533 1.1 christos
9534 1.1 christos if (qctx->sigrdataset == NULL ||
9535 1.16 christos !dns_rdataset_isassociated(qctx->sigrdataset))
9536 1.16 christos {
9537 1.1 christos return;
9538 1.1 christos }
9539 1.1 christos
9540 1.1 christos if (dns_rdataset_first(qctx->sigrdataset) != ISC_R_SUCCESS) {
9541 1.1 christos return;
9542 1.1 christos }
9543 1.1 christos
9544 1.1 christos dns_rdata_init(&sigrdata);
9545 1.1 christos dns_rdataset_current(qctx->sigrdataset, &sigrdata);
9546 1.3 christos result = dns_rdata_tostruct(&sigrdata, &sig, NULL);
9547 1.3 christos RUNTIME_CHECK(result == ISC_R_SUCCESS);
9548 1.1 christos
9549 1.1 christos labels = dns_name_countlabels(qctx->fname);
9550 1.1 christos if ((unsigned int)sig.labels + 1 >= labels) {
9551 1.1 christos return;
9552 1.1 christos }
9553 1.1 christos
9554 1.3 christos query_addwildcardproof(qctx, true, false);
9555 1.1 christos
9556 1.1 christos /*
9557 1.1 christos * We'll need some resources...
9558 1.1 christos */
9559 1.3 christos dbuf = ns_client_getnamebuf(client);
9560 1.3 christos fname = ns_client_newname(client, dbuf, &b);
9561 1.1 christos
9562 1.1 christos dns_name_split(qctx->fname, sig.labels + 1, NULL, fname);
9563 1.1 christos /* This will succeed, since we've stripped labels. */
9564 1.1 christos RUNTIME_CHECK(dns_name_concatenate(dns_wildcardname, fname, fname,
9565 1.1 christos NULL) == ISC_R_SUCCESS);
9566 1.9 christos query_addrrset(qctx, &fname, &qctx->rdataset, &qctx->sigrdataset, dbuf,
9567 1.9 christos DNS_SECTION_AUTHORITY);
9568 1.1 christos }
9569 1.1 christos
9570 1.1 christos /*%
9571 1.1 christos * Handle NXDOMAIN and empty wildcard responses.
9572 1.1 christos */
9573 1.1 christos static isc_result_t
9574 1.18 christos query_nxdomain(query_ctx_t *qctx, isc_result_t result) {
9575 1.1 christos dns_section_t section;
9576 1.3 christos uint32_t ttl;
9577 1.18 christos bool empty_wild = (result == DNS_R_EMPTYWILD);
9578 1.1 christos
9579 1.9 christos CCTRACE(ISC_LOG_DEBUG(3), "query_nxdomain");
9580 1.9 christos
9581 1.3 christos CALL_HOOK(NS_QUERY_NXDOMAIN_BEGIN, qctx);
9582 1.3 christos
9583 1.1 christos INSIST(qctx->is_zone || REDIRECT(qctx->client));
9584 1.1 christos
9585 1.1 christos if (!empty_wild) {
9586 1.18 christos result = query_redirect(qctx, result);
9587 1.9 christos if (result != ISC_R_COMPLETE) {
9588 1.23 christos return result;
9589 1.9 christos }
9590 1.1 christos }
9591 1.1 christos
9592 1.1 christos if (dns_rdataset_isassociated(qctx->rdataset)) {
9593 1.1 christos /*
9594 1.1 christos * If we've got a NSEC record, we need to save the
9595 1.1 christos * name now because we're going call query_addsoa()
9596 1.1 christos * below, and it needs to use the name buffer.
9597 1.1 christos */
9598 1.3 christos ns_client_keepname(qctx->client, qctx->fname, qctx->dbuf);
9599 1.1 christos } else if (qctx->fname != NULL) {
9600 1.1 christos /*
9601 1.1 christos * We're not going to use fname, and need to release
9602 1.1 christos * our hold on the name buffer so query_addsoa()
9603 1.1 christos * may use it.
9604 1.1 christos */
9605 1.3 christos ns_client_releasename(qctx->client, &qctx->fname);
9606 1.1 christos }
9607 1.1 christos
9608 1.1 christos /*
9609 1.1 christos * Add SOA to the additional section if generated by a
9610 1.1 christos * RPZ rewrite.
9611 1.1 christos *
9612 1.1 christos * If the query was for a SOA record force the
9613 1.1 christos * ttl to zero so that it is possible for clients to find
9614 1.1 christos * the containing zone of an arbitrary name with a stub
9615 1.1 christos * resolver and not have it cached.
9616 1.1 christos */
9617 1.1 christos section = qctx->nxrewrite ? DNS_SECTION_ADDITIONAL
9618 1.1 christos : DNS_SECTION_AUTHORITY;
9619 1.3 christos ttl = UINT32_MAX;
9620 1.1 christos if (!qctx->nxrewrite && qctx->qtype == dns_rdatatype_soa &&
9621 1.1 christos qctx->zone != NULL && dns_zone_getzeronosoattl(qctx->zone))
9622 1.1 christos {
9623 1.1 christos ttl = 0;
9624 1.1 christos }
9625 1.16 christos if (!qctx->nxrewrite ||
9626 1.16 christos (qctx->rpz_st != NULL && qctx->rpz_st->m.rpz->addsoa))
9627 1.16 christos {
9628 1.5 christos result = query_addsoa(qctx, ttl, section);
9629 1.5 christos if (result != ISC_R_SUCCESS) {
9630 1.5 christos QUERY_ERROR(qctx, result);
9631 1.23 christos return ns_query_done(qctx);
9632 1.5 christos }
9633 1.1 christos }
9634 1.1 christos
9635 1.1 christos if (WANTDNSSEC(qctx->client)) {
9636 1.1 christos /*
9637 1.1 christos * Add NSEC record if we found one.
9638 1.1 christos */
9639 1.9 christos if (dns_rdataset_isassociated(qctx->rdataset)) {
9640 1.9 christos query_addrrset(qctx, &qctx->fname, &qctx->rdataset,
9641 1.9 christos &qctx->sigrdataset, NULL,
9642 1.9 christos DNS_SECTION_AUTHORITY);
9643 1.9 christos }
9644 1.3 christos query_addwildcardproof(qctx, false, false);
9645 1.1 christos }
9646 1.1 christos
9647 1.1 christos /*
9648 1.1 christos * Set message rcode.
9649 1.1 christos */
9650 1.9 christos if (empty_wild) {
9651 1.1 christos qctx->client->message->rcode = dns_rcode_noerror;
9652 1.9 christos } else {
9653 1.1 christos qctx->client->message->rcode = dns_rcode_nxdomain;
9654 1.9 christos }
9655 1.1 christos
9656 1.23 christos return ns_query_done(qctx);
9657 1.3 christos
9658 1.9 christos cleanup:
9659 1.23 christos return result;
9660 1.1 christos }
9661 1.1 christos
9662 1.1 christos /*
9663 1.1 christos * Handle both types of NXDOMAIN redirection, calling redirect()
9664 1.1 christos * (which implements type redirect zones) and redirect2() (which
9665 1.1 christos * implements recursive nxdomain-redirect lookups).
9666 1.1 christos *
9667 1.1 christos * Any result code other than ISC_R_COMPLETE means redirection was
9668 1.1 christos * successful and the result code should be returned up the call stack.
9669 1.1 christos *
9670 1.1 christos * ISC_R_COMPLETE means we reached the end of this function without
9671 1.1 christos * redirecting, so query processing should continue past it.
9672 1.1 christos */
9673 1.1 christos static isc_result_t
9674 1.18 christos query_redirect(query_ctx_t *qctx, isc_result_t saved_result) {
9675 1.1 christos isc_result_t result;
9676 1.1 christos
9677 1.9 christos CCTRACE(ISC_LOG_DEBUG(3), "query_redirect");
9678 1.9 christos
9679 1.1 christos result = redirect(qctx->client, qctx->fname, qctx->rdataset,
9680 1.9 christos &qctx->node, &qctx->db, &qctx->version, qctx->type);
9681 1.1 christos switch (result) {
9682 1.1 christos case ISC_R_SUCCESS:
9683 1.9 christos inc_stats(qctx->client, ns_statscounter_nxdomainredirect);
9684 1.23 christos return query_prepresponse(qctx);
9685 1.1 christos case DNS_R_NXRRSET:
9686 1.3 christos qctx->redirected = true;
9687 1.3 christos qctx->is_zone = true;
9688 1.23 christos return query_nodata(qctx, DNS_R_NXRRSET);
9689 1.1 christos case DNS_R_NCACHENXRRSET:
9690 1.3 christos qctx->redirected = true;
9691 1.3 christos qctx->is_zone = false;
9692 1.23 christos return query_ncache(qctx, DNS_R_NCACHENXRRSET);
9693 1.1 christos default:
9694 1.1 christos break;
9695 1.1 christos }
9696 1.1 christos
9697 1.1 christos result = redirect2(qctx->client, qctx->fname, qctx->rdataset,
9698 1.9 christos &qctx->node, &qctx->db, &qctx->version, qctx->type,
9699 1.9 christos &qctx->is_zone);
9700 1.1 christos switch (result) {
9701 1.1 christos case ISC_R_SUCCESS:
9702 1.9 christos inc_stats(qctx->client, ns_statscounter_nxdomainredirect);
9703 1.23 christos return query_prepresponse(qctx);
9704 1.1 christos case DNS_R_CONTINUE:
9705 1.1 christos inc_stats(qctx->client,
9706 1.1 christos ns_statscounter_nxdomainredirect_rlookup);
9707 1.1 christos SAVE(qctx->client->query.redirect.db, qctx->db);
9708 1.1 christos SAVE(qctx->client->query.redirect.node, qctx->node);
9709 1.1 christos SAVE(qctx->client->query.redirect.zone, qctx->zone);
9710 1.1 christos qctx->client->query.redirect.qtype = qctx->qtype;
9711 1.1 christos INSIST(qctx->rdataset != NULL);
9712 1.1 christos SAVE(qctx->client->query.redirect.rdataset, qctx->rdataset);
9713 1.1 christos SAVE(qctx->client->query.redirect.sigrdataset,
9714 1.1 christos qctx->sigrdataset);
9715 1.18 christos qctx->client->query.redirect.result = saved_result;
9716 1.20 christos dns_name_copy(qctx->fname, qctx->client->query.redirect.fname);
9717 1.1 christos qctx->client->query.redirect.authoritative =
9718 1.1 christos qctx->authoritative;
9719 1.1 christos qctx->client->query.redirect.is_zone = qctx->is_zone;
9720 1.23 christos return ns_query_done(qctx);
9721 1.1 christos case DNS_R_NXRRSET:
9722 1.3 christos qctx->redirected = true;
9723 1.3 christos qctx->is_zone = true;
9724 1.23 christos return query_nodata(qctx, DNS_R_NXRRSET);
9725 1.1 christos case DNS_R_NCACHENXRRSET:
9726 1.3 christos qctx->redirected = true;
9727 1.3 christos qctx->is_zone = false;
9728 1.23 christos return query_ncache(qctx, DNS_R_NCACHENXRRSET);
9729 1.1 christos default:
9730 1.1 christos break;
9731 1.1 christos }
9732 1.1 christos
9733 1.23 christos return ISC_R_COMPLETE;
9734 1.1 christos }
9735 1.1 christos
9736 1.1 christos /*%
9737 1.1 christos * Logging function to be passed to dns_nsec_noexistnodata.
9738 1.1 christos */
9739 1.1 christos static void
9740 1.1 christos log_noexistnodata(void *val, int level, const char *fmt, ...) {
9741 1.1 christos query_ctx_t *qctx = val;
9742 1.1 christos va_list ap;
9743 1.1 christos
9744 1.1 christos va_start(ap, fmt);
9745 1.9 christos ns_client_logv(qctx->client, NS_LOGCATEGORY_QUERIES, NS_LOGMODULE_QUERY,
9746 1.9 christos level, fmt, ap);
9747 1.1 christos va_end(ap);
9748 1.1 christos }
9749 1.1 christos
9750 1.1 christos static dns_ttl_t
9751 1.1 christos query_synthttl(dns_rdataset_t *soardataset, dns_rdataset_t *sigsoardataset,
9752 1.1 christos dns_rdataset_t *p1rdataset, dns_rdataset_t *sigp1rdataset,
9753 1.9 christos dns_rdataset_t *p2rdataset, dns_rdataset_t *sigp2rdataset) {
9754 1.1 christos dns_rdata_soa_t soa;
9755 1.1 christos dns_rdata_t rdata = DNS_RDATA_INIT;
9756 1.1 christos dns_ttl_t ttl;
9757 1.1 christos isc_result_t result;
9758 1.1 christos
9759 1.1 christos REQUIRE(soardataset != NULL);
9760 1.1 christos REQUIRE(sigsoardataset != NULL);
9761 1.1 christos REQUIRE(p1rdataset != NULL);
9762 1.1 christos REQUIRE(sigp1rdataset != NULL);
9763 1.1 christos
9764 1.1 christos result = dns_rdataset_first(soardataset);
9765 1.1 christos RUNTIME_CHECK(result == ISC_R_SUCCESS);
9766 1.1 christos dns_rdataset_current(soardataset, &rdata);
9767 1.3 christos result = dns_rdata_tostruct(&rdata, &soa, NULL);
9768 1.3 christos RUNTIME_CHECK(result == ISC_R_SUCCESS);
9769 1.1 christos
9770 1.1 christos ttl = ISC_MIN(soa.minimum, soardataset->ttl);
9771 1.1 christos ttl = ISC_MIN(ttl, sigsoardataset->ttl);
9772 1.1 christos ttl = ISC_MIN(ttl, p1rdataset->ttl);
9773 1.1 christos ttl = ISC_MIN(ttl, sigp1rdataset->ttl);
9774 1.9 christos if (p2rdataset != NULL) {
9775 1.1 christos ttl = ISC_MIN(ttl, p2rdataset->ttl);
9776 1.9 christos }
9777 1.9 christos if (sigp2rdataset != NULL) {
9778 1.1 christos ttl = ISC_MIN(ttl, sigp2rdataset->ttl);
9779 1.9 christos }
9780 1.1 christos
9781 1.23 christos return ttl;
9782 1.1 christos }
9783 1.1 christos
9784 1.1 christos /*
9785 1.1 christos * Synthesize a NODATA response from the SOA and covering NSEC in cache.
9786 1.1 christos */
9787 1.1 christos static isc_result_t
9788 1.1 christos query_synthnodata(query_ctx_t *qctx, const dns_name_t *signer,
9789 1.1 christos dns_rdataset_t **soardatasetp,
9790 1.9 christos dns_rdataset_t **sigsoardatasetp) {
9791 1.1 christos dns_name_t *name = NULL;
9792 1.1 christos dns_ttl_t ttl;
9793 1.1 christos isc_buffer_t *dbuf, b;
9794 1.1 christos
9795 1.1 christos /*
9796 1.9 christos * Determine the correct TTL to use for the SOA and RRSIG
9797 1.1 christos */
9798 1.9 christos ttl = query_synthttl(*soardatasetp, *sigsoardatasetp, qctx->rdataset,
9799 1.9 christos qctx->sigrdataset, NULL, NULL);
9800 1.1 christos (*soardatasetp)->ttl = (*sigsoardatasetp)->ttl = ttl;
9801 1.1 christos
9802 1.1 christos /*
9803 1.1 christos * We want the SOA record to be first, so save the
9804 1.1 christos * NODATA proof's name now or else discard it.
9805 1.1 christos */
9806 1.1 christos if (WANTDNSSEC(qctx->client)) {
9807 1.3 christos ns_client_keepname(qctx->client, qctx->fname, qctx->dbuf);
9808 1.1 christos } else {
9809 1.3 christos ns_client_releasename(qctx->client, &qctx->fname);
9810 1.1 christos }
9811 1.1 christos
9812 1.3 christos dbuf = ns_client_getnamebuf(qctx->client);
9813 1.3 christos name = ns_client_newname(qctx->client, dbuf, &b);
9814 1.20 christos dns_name_copy(signer, name);
9815 1.1 christos
9816 1.1 christos /*
9817 1.1 christos * Add SOA record. Omit the RRSIG if DNSSEC was not requested.
9818 1.1 christos */
9819 1.1 christos if (!WANTDNSSEC(qctx->client)) {
9820 1.1 christos sigsoardatasetp = NULL;
9821 1.1 christos }
9822 1.9 christos query_addrrset(qctx, &name, soardatasetp, sigsoardatasetp, dbuf,
9823 1.9 christos DNS_SECTION_AUTHORITY);
9824 1.1 christos
9825 1.1 christos if (WANTDNSSEC(qctx->client)) {
9826 1.1 christos /*
9827 1.1 christos * Add NODATA proof.
9828 1.1 christos */
9829 1.9 christos query_addrrset(qctx, &qctx->fname, &qctx->rdataset,
9830 1.9 christos &qctx->sigrdataset, NULL, DNS_SECTION_AUTHORITY);
9831 1.1 christos }
9832 1.1 christos
9833 1.1 christos inc_stats(qctx->client, ns_statscounter_nodatasynth);
9834 1.1 christos
9835 1.1 christos if (name != NULL) {
9836 1.3 christos ns_client_releasename(qctx->client, &name);
9837 1.1 christos }
9838 1.23 christos return ISC_R_SUCCESS;
9839 1.1 christos }
9840 1.1 christos
9841 1.1 christos /*
9842 1.1 christos * Synthesize a wildcard answer using the contents of 'rdataset'.
9843 1.1 christos * qctx contains the NODATA proof.
9844 1.1 christos */
9845 1.1 christos static isc_result_t
9846 1.1 christos query_synthwildcard(query_ctx_t *qctx, dns_rdataset_t *rdataset,
9847 1.9 christos dns_rdataset_t *sigrdataset) {
9848 1.1 christos dns_name_t *name = NULL;
9849 1.1 christos isc_buffer_t *dbuf, b;
9850 1.3 christos dns_rdataset_t *cloneset = NULL, *clonesigset = NULL;
9851 1.1 christos dns_rdataset_t **sigrdatasetp;
9852 1.1 christos
9853 1.9 christos CCTRACE(ISC_LOG_DEBUG(3), "query_synthwildcard");
9854 1.9 christos
9855 1.1 christos /*
9856 1.1 christos * We want the answer to be first, so save the
9857 1.1 christos * NOQNAME proof's name now or else discard it.
9858 1.1 christos */
9859 1.1 christos if (WANTDNSSEC(qctx->client)) {
9860 1.3 christos ns_client_keepname(qctx->client, qctx->fname, qctx->dbuf);
9861 1.1 christos } else {
9862 1.3 christos ns_client_releasename(qctx->client, &qctx->fname);
9863 1.1 christos }
9864 1.1 christos
9865 1.3 christos dbuf = ns_client_getnamebuf(qctx->client);
9866 1.3 christos name = ns_client_newname(qctx->client, dbuf, &b);
9867 1.20 christos dns_name_copy(qctx->client->query.qname, name);
9868 1.1 christos
9869 1.3 christos cloneset = ns_client_newrdataset(qctx->client);
9870 1.3 christos dns_rdataset_clone(rdataset, cloneset);
9871 1.1 christos
9872 1.1 christos /*
9873 1.1 christos * Add answer RRset. Omit the RRSIG if DNSSEC was not requested.
9874 1.1 christos */
9875 1.1 christos if (WANTDNSSEC(qctx->client)) {
9876 1.3 christos clonesigset = ns_client_newrdataset(qctx->client);
9877 1.3 christos dns_rdataset_clone(sigrdataset, clonesigset);
9878 1.3 christos sigrdatasetp = &clonesigset;
9879 1.1 christos } else {
9880 1.1 christos sigrdatasetp = NULL;
9881 1.1 christos }
9882 1.1 christos
9883 1.9 christos query_addrrset(qctx, &name, &cloneset, sigrdatasetp, dbuf,
9884 1.9 christos DNS_SECTION_ANSWER);
9885 1.1 christos
9886 1.1 christos if (WANTDNSSEC(qctx->client)) {
9887 1.1 christos /*
9888 1.1 christos * Add NOQNAME proof.
9889 1.1 christos */
9890 1.9 christos query_addrrset(qctx, &qctx->fname, &qctx->rdataset,
9891 1.9 christos &qctx->sigrdataset, NULL, DNS_SECTION_AUTHORITY);
9892 1.1 christos }
9893 1.1 christos
9894 1.1 christos inc_stats(qctx->client, ns_statscounter_wildcardsynth);
9895 1.1 christos
9896 1.1 christos if (name != NULL) {
9897 1.3 christos ns_client_releasename(qctx->client, &name);
9898 1.1 christos }
9899 1.3 christos if (cloneset != NULL) {
9900 1.3 christos ns_client_putrdataset(qctx->client, &cloneset);
9901 1.1 christos }
9902 1.3 christos if (clonesigset != NULL) {
9903 1.3 christos ns_client_putrdataset(qctx->client, &clonesigset);
9904 1.1 christos }
9905 1.23 christos return ISC_R_SUCCESS;
9906 1.1 christos }
9907 1.1 christos
9908 1.1 christos /*
9909 1.1 christos * Add a synthesized CNAME record from the wildard RRset (rdataset)
9910 1.1 christos * and NODATA proof by calling query_synthwildcard then setup to
9911 1.1 christos * follow the CNAME.
9912 1.1 christos */
9913 1.1 christos static isc_result_t
9914 1.1 christos query_synthcnamewildcard(query_ctx_t *qctx, dns_rdataset_t *rdataset,
9915 1.9 christos dns_rdataset_t *sigrdataset) {
9916 1.1 christos isc_result_t result;
9917 1.1 christos dns_name_t *tname = NULL;
9918 1.1 christos dns_rdata_t rdata = DNS_RDATA_INIT;
9919 1.1 christos dns_rdata_cname_t cname;
9920 1.1 christos
9921 1.1 christos result = query_synthwildcard(qctx, rdataset, sigrdataset);
9922 1.1 christos if (result != ISC_R_SUCCESS) {
9923 1.23 christos return result;
9924 1.1 christos }
9925 1.1 christos
9926 1.1 christos qctx->client->query.attributes |= NS_QUERYATTR_PARTIALANSWER;
9927 1.1 christos
9928 1.1 christos /*
9929 1.1 christos * Reset qname to be the target name of the CNAME and restart
9930 1.1 christos * the query.
9931 1.1 christos */
9932 1.23 christos dns_message_gettempname(qctx->client->message, &tname);
9933 1.1 christos
9934 1.1 christos result = dns_rdataset_first(rdataset);
9935 1.1 christos if (result != ISC_R_SUCCESS) {
9936 1.1 christos dns_message_puttempname(qctx->client->message, &tname);
9937 1.23 christos return result;
9938 1.1 christos }
9939 1.1 christos
9940 1.1 christos dns_rdataset_current(rdataset, &rdata);
9941 1.1 christos result = dns_rdata_tostruct(&rdata, &cname, NULL);
9942 1.3 christos RUNTIME_CHECK(result == ISC_R_SUCCESS);
9943 1.1 christos dns_rdata_reset(&rdata);
9944 1.1 christos
9945 1.20 christos if (dns_name_equal(qctx->client->query.qname, &cname.cname)) {
9946 1.20 christos dns_message_puttempname(qctx->client->message, &tname);
9947 1.20 christos dns_rdata_freestruct(&cname);
9948 1.23 christos return ISC_R_SUCCESS;
9949 1.20 christos }
9950 1.20 christos
9951 1.20 christos dns_name_copy(&cname.cname, tname);
9952 1.1 christos
9953 1.1 christos dns_rdata_freestruct(&cname);
9954 1.1 christos ns_client_qnamereplace(qctx->client, tname);
9955 1.3 christos qctx->want_restart = true;
9956 1.1 christos if (!WANTRECURSION(qctx->client)) {
9957 1.23 christos qctx->options.nolog = true;
9958 1.1 christos }
9959 1.1 christos
9960 1.23 christos return result;
9961 1.1 christos }
9962 1.1 christos
9963 1.1 christos /*
9964 1.20 christos * Synthesize a NXDOMAIN or NODATA response from qctx (which contains the
9965 1.20 christos * NOQNAME proof), nowild + nowildrdataset + signowildrdataset (which
9966 1.20 christos * contains the NOWILDCARD proof or NODATA at wildcard) and
9967 1.20 christos * signer + soardatasetp + sigsoardatasetp which contain the
9968 1.20 christos * SOA record + RRSIG for the negative answer.
9969 1.1 christos */
9970 1.1 christos static isc_result_t
9971 1.20 christos query_synthnxdomainnodata(query_ctx_t *qctx, bool nodata, dns_name_t *nowild,
9972 1.20 christos dns_rdataset_t *nowildrdataset,
9973 1.20 christos dns_rdataset_t *signowildrdataset, dns_name_t *signer,
9974 1.20 christos dns_rdataset_t **soardatasetp,
9975 1.20 christos dns_rdataset_t **sigsoardatasetp) {
9976 1.1 christos dns_name_t *name = NULL;
9977 1.1 christos dns_ttl_t ttl;
9978 1.1 christos isc_buffer_t *dbuf, b;
9979 1.3 christos dns_rdataset_t *cloneset = NULL, *clonesigset = NULL;
9980 1.1 christos
9981 1.9 christos CCTRACE(ISC_LOG_DEBUG(3), "query_synthnxdomain");
9982 1.9 christos
9983 1.1 christos /*
9984 1.9 christos * Determine the correct TTL to use for the SOA and RRSIG
9985 1.1 christos */
9986 1.9 christos ttl = query_synthttl(*soardatasetp, *sigsoardatasetp, qctx->rdataset,
9987 1.9 christos qctx->sigrdataset, nowildrdataset,
9988 1.9 christos signowildrdataset);
9989 1.1 christos (*soardatasetp)->ttl = (*sigsoardatasetp)->ttl = ttl;
9990 1.1 christos
9991 1.1 christos /*
9992 1.1 christos * We want the SOA record to be first, so save the
9993 1.1 christos * NOQNAME proof's name now or else discard it.
9994 1.1 christos */
9995 1.1 christos if (WANTDNSSEC(qctx->client)) {
9996 1.3 christos ns_client_keepname(qctx->client, qctx->fname, qctx->dbuf);
9997 1.1 christos } else {
9998 1.3 christos ns_client_releasename(qctx->client, &qctx->fname);
9999 1.1 christos }
10000 1.1 christos
10001 1.3 christos dbuf = ns_client_getnamebuf(qctx->client);
10002 1.3 christos name = ns_client_newname(qctx->client, dbuf, &b);
10003 1.20 christos dns_name_copy(signer, name);
10004 1.1 christos
10005 1.1 christos /*
10006 1.1 christos * Add SOA record. Omit the RRSIG if DNSSEC was not requested.
10007 1.1 christos */
10008 1.1 christos if (!WANTDNSSEC(qctx->client)) {
10009 1.1 christos sigsoardatasetp = NULL;
10010 1.1 christos }
10011 1.9 christos query_addrrset(qctx, &name, soardatasetp, sigsoardatasetp, dbuf,
10012 1.9 christos DNS_SECTION_AUTHORITY);
10013 1.1 christos
10014 1.1 christos if (WANTDNSSEC(qctx->client)) {
10015 1.1 christos /*
10016 1.1 christos * Add NOQNAME proof.
10017 1.1 christos */
10018 1.9 christos query_addrrset(qctx, &qctx->fname, &qctx->rdataset,
10019 1.9 christos &qctx->sigrdataset, NULL, DNS_SECTION_AUTHORITY);
10020 1.1 christos
10021 1.3 christos dbuf = ns_client_getnamebuf(qctx->client);
10022 1.3 christos name = ns_client_newname(qctx->client, dbuf, &b);
10023 1.20 christos dns_name_copy(nowild, name);
10024 1.1 christos
10025 1.3 christos cloneset = ns_client_newrdataset(qctx->client);
10026 1.3 christos clonesigset = ns_client_newrdataset(qctx->client);
10027 1.1 christos
10028 1.3 christos dns_rdataset_clone(nowildrdataset, cloneset);
10029 1.3 christos dns_rdataset_clone(signowildrdataset, clonesigset);
10030 1.1 christos
10031 1.1 christos /*
10032 1.1 christos * Add NOWILDCARD proof.
10033 1.1 christos */
10034 1.9 christos query_addrrset(qctx, &name, &cloneset, &clonesigset, dbuf,
10035 1.9 christos DNS_SECTION_AUTHORITY);
10036 1.1 christos }
10037 1.1 christos
10038 1.20 christos if (nodata) {
10039 1.20 christos inc_stats(qctx->client, ns_statscounter_nodatasynth);
10040 1.20 christos } else {
10041 1.20 christos qctx->client->message->rcode = dns_rcode_nxdomain;
10042 1.20 christos inc_stats(qctx->client, ns_statscounter_nxdomainsynth);
10043 1.20 christos }
10044 1.1 christos
10045 1.1 christos if (name != NULL) {
10046 1.3 christos ns_client_releasename(qctx->client, &name);
10047 1.1 christos }
10048 1.3 christos if (cloneset != NULL) {
10049 1.3 christos ns_client_putrdataset(qctx->client, &cloneset);
10050 1.1 christos }
10051 1.3 christos if (clonesigset != NULL) {
10052 1.3 christos ns_client_putrdataset(qctx->client, &clonesigset);
10053 1.1 christos }
10054 1.23 christos return ISC_R_SUCCESS;
10055 1.1 christos }
10056 1.1 christos
10057 1.1 christos /*
10058 1.1 christos * Check that all signer names in sigrdataset match the expected signer.
10059 1.1 christos */
10060 1.1 christos static isc_result_t
10061 1.1 christos checksignames(dns_name_t *signer, dns_rdataset_t *sigrdataset) {
10062 1.1 christos isc_result_t result;
10063 1.1 christos
10064 1.9 christos for (result = dns_rdataset_first(sigrdataset); result == ISC_R_SUCCESS;
10065 1.9 christos result = dns_rdataset_next(sigrdataset))
10066 1.9 christos {
10067 1.1 christos dns_rdata_t rdata = DNS_RDATA_INIT;
10068 1.1 christos dns_rdata_rrsig_t rrsig;
10069 1.1 christos
10070 1.1 christos dns_rdataset_current(sigrdataset, &rdata);
10071 1.1 christos result = dns_rdata_tostruct(&rdata, &rrsig, NULL);
10072 1.1 christos RUNTIME_CHECK(result == ISC_R_SUCCESS);
10073 1.1 christos if (dns_name_countlabels(signer) == 0) {
10074 1.20 christos dns_name_copy(&rrsig.signer, signer);
10075 1.1 christos } else if (!dns_name_equal(signer, &rrsig.signer)) {
10076 1.23 christos return ISC_R_FAILURE;
10077 1.1 christos }
10078 1.1 christos }
10079 1.1 christos
10080 1.23 christos return ISC_R_SUCCESS;
10081 1.1 christos }
10082 1.1 christos
10083 1.1 christos /*%
10084 1.1 christos * Handle covering NSEC responses.
10085 1.1 christos *
10086 1.9 christos * Verify the NSEC record is appropriate for the QNAME; if not,
10087 1.1 christos * redo the initial query without DNS_DBFIND_COVERINGNSEC.
10088 1.1 christos *
10089 1.1 christos * If the covering NSEC proves that the name exists but not the type,
10090 1.1 christos * synthesize a NODATA response.
10091 1.1 christos *
10092 1.1 christos * If the name doesn't exist, compute the wildcard record and check whether
10093 1.1 christos * the wildcard name exists or not. If we can't determine this, redo the
10094 1.1 christos * initial query without DNS_DBFIND_COVERINGNSEC.
10095 1.1 christos *
10096 1.1 christos * If the wildcard name does not exist, compute the SOA name and look that
10097 1.1 christos * up. If the SOA record does not exist, redo the initial query without
10098 1.1 christos * DNS_DBFIND_COVERINGNSEC. If the SOA record exists, synthesize an
10099 1.1 christos * NXDOMAIN response from the found records.
10100 1.1 christos *
10101 1.1 christos * If the wildcard name does exist, perform a lookup for the requested
10102 1.1 christos * type at the wildcard name.
10103 1.1 christos */
10104 1.1 christos static isc_result_t
10105 1.1 christos query_coveringnsec(query_ctx_t *qctx) {
10106 1.1 christos dns_db_t *db = NULL;
10107 1.1 christos dns_clientinfo_t ci;
10108 1.1 christos dns_clientinfomethods_t cm;
10109 1.1 christos dns_dbnode_t *node = NULL;
10110 1.1 christos dns_fixedname_t fixed;
10111 1.20 christos dns_fixedname_t fnamespace;
10112 1.1 christos dns_fixedname_t fnowild;
10113 1.1 christos dns_fixedname_t fsigner;
10114 1.1 christos dns_fixedname_t fwild;
10115 1.1 christos dns_name_t *fname = NULL;
10116 1.20 christos dns_name_t *namespace = NULL;
10117 1.1 christos dns_name_t *nowild = NULL;
10118 1.1 christos dns_name_t *signer = NULL;
10119 1.1 christos dns_name_t *wild = NULL;
10120 1.20 christos dns_name_t qname;
10121 1.1 christos dns_rdataset_t *soardataset = NULL, *sigsoardataset = NULL;
10122 1.1 christos dns_rdataset_t rdataset, sigrdataset;
10123 1.3 christos bool done = false;
10124 1.3 christos bool exists = true, data = true;
10125 1.3 christos bool redirected = false;
10126 1.1 christos isc_result_t result = ISC_R_SUCCESS;
10127 1.1 christos unsigned int dboptions = qctx->client->query.dboptions;
10128 1.20 christos unsigned int labels;
10129 1.1 christos
10130 1.9 christos CCTRACE(ISC_LOG_DEBUG(3), "query_coveringnsec");
10131 1.9 christos
10132 1.20 christos dns_name_init(&qname, NULL);
10133 1.1 christos dns_rdataset_init(&rdataset);
10134 1.1 christos dns_rdataset_init(&sigrdataset);
10135 1.20 christos namespace = dns_fixedname_initname(&fnamespace);
10136 1.20 christos
10137 1.20 christos /*
10138 1.20 christos * Check that the NSEC record is from the correct namespace.
10139 1.20 christos * For records that belong to the parent zone (i.e. DS),
10140 1.20 christos * remove a label to find the correct namespace.
10141 1.20 christos */
10142 1.20 christos dns_name_clone(qctx->client->query.qname, &qname);
10143 1.20 christos labels = dns_name_countlabels(&qname);
10144 1.20 christos if (dns_rdatatype_atparent(qctx->qtype) && labels > 1) {
10145 1.20 christos dns_name_getlabelsequence(&qname, 1, labels - 1, &qname);
10146 1.20 christos }
10147 1.20 christos dns_view_sfd_find(qctx->view, &qname, namespace);
10148 1.20 christos if (!dns_name_issubdomain(qctx->fname, namespace)) {
10149 1.20 christos goto cleanup;
10150 1.20 christos }
10151 1.1 christos
10152 1.1 christos /*
10153 1.1 christos * If we have no signer name, stop immediately.
10154 1.1 christos */
10155 1.1 christos if (!dns_rdataset_isassociated(qctx->sigrdataset)) {
10156 1.1 christos goto cleanup;
10157 1.1 christos }
10158 1.1 christos
10159 1.1 christos wild = dns_fixedname_initname(&fwild);
10160 1.1 christos fname = dns_fixedname_initname(&fixed);
10161 1.1 christos signer = dns_fixedname_initname(&fsigner);
10162 1.1 christos nowild = dns_fixedname_initname(&fnowild);
10163 1.1 christos
10164 1.1 christos dns_clientinfomethods_init(&cm, ns_client_sourceip);
10165 1.20 christos dns_clientinfo_init(&ci, qctx->client, NULL);
10166 1.1 christos
10167 1.1 christos /*
10168 1.1 christos * All signer names must be the same to accept.
10169 1.1 christos */
10170 1.1 christos result = checksignames(signer, qctx->sigrdataset);
10171 1.1 christos if (result != ISC_R_SUCCESS) {
10172 1.1 christos result = ISC_R_SUCCESS;
10173 1.1 christos goto cleanup;
10174 1.1 christos }
10175 1.1 christos
10176 1.1 christos /*
10177 1.20 christos * If NSEC or RRSIG are missing from the type map
10178 1.20 christos * reject the NSEC RRset.
10179 1.20 christos */
10180 1.20 christos if (!dns_nsec_requiredtypespresent(qctx->rdataset)) {
10181 1.20 christos goto cleanup;
10182 1.20 christos }
10183 1.20 christos
10184 1.20 christos /*
10185 1.1 christos * Check that we have the correct NOQNAME NSEC record.
10186 1.1 christos */
10187 1.1 christos result = dns_nsec_noexistnodata(qctx->qtype, qctx->client->query.qname,
10188 1.9 christos qctx->fname, qctx->rdataset, &exists,
10189 1.9 christos &data, wild, log_noexistnodata, qctx);
10190 1.1 christos
10191 1.1 christos if (result != ISC_R_SUCCESS || (exists && data)) {
10192 1.1 christos goto cleanup;
10193 1.1 christos }
10194 1.1 christos
10195 1.1 christos if (exists) {
10196 1.9 christos if (qctx->type == dns_rdatatype_any) { /* XXX not yet */
10197 1.1 christos goto cleanup;
10198 1.1 christos }
10199 1.3 christos if (!ISC_LIST_EMPTY(qctx->view->dns64) &&
10200 1.1 christos (qctx->type == dns_rdatatype_a ||
10201 1.1 christos qctx->type == dns_rdatatype_aaaa)) /* XXX not yet */
10202 1.1 christos {
10203 1.1 christos goto cleanup;
10204 1.1 christos }
10205 1.1 christos if (!qctx->resuming && !STALE(qctx->rdataset) &&
10206 1.1 christos qctx->rdataset->ttl == 0 && RECURSIONOK(qctx->client))
10207 1.1 christos {
10208 1.1 christos goto cleanup;
10209 1.1 christos }
10210 1.1 christos
10211 1.3 christos soardataset = ns_client_newrdataset(qctx->client);
10212 1.3 christos sigsoardataset = ns_client_newrdataset(qctx->client);
10213 1.1 christos
10214 1.1 christos /*
10215 1.1 christos * Look for SOA record to construct NODATA response.
10216 1.1 christos */
10217 1.1 christos dns_db_attach(qctx->db, &db);
10218 1.1 christos result = dns_db_findext(db, signer, qctx->version,
10219 1.1 christos dns_rdatatype_soa, dboptions,
10220 1.9 christos qctx->client->now, &node, fname, &cm,
10221 1.9 christos &ci, soardataset, sigsoardataset);
10222 1.1 christos
10223 1.1 christos if (result != ISC_R_SUCCESS) {
10224 1.1 christos goto cleanup;
10225 1.1 christos }
10226 1.9 christos (void)query_synthnodata(qctx, signer, &soardataset,
10227 1.9 christos &sigsoardataset);
10228 1.3 christos done = true;
10229 1.1 christos goto cleanup;
10230 1.1 christos }
10231 1.1 christos
10232 1.1 christos /*
10233 1.1 christos * Look up the no-wildcard proof.
10234 1.1 christos */
10235 1.1 christos dns_db_attach(qctx->db, &db);
10236 1.1 christos result = dns_db_findext(db, wild, qctx->version, qctx->type,
10237 1.1 christos dboptions | DNS_DBFIND_COVERINGNSEC,
10238 1.9 christos qctx->client->now, &node, nowild, &cm, &ci,
10239 1.9 christos &rdataset, &sigrdataset);
10240 1.1 christos
10241 1.1 christos if (rdataset.trust != dns_trust_secure ||
10242 1.16 christos sigrdataset.trust != dns_trust_secure)
10243 1.16 christos {
10244 1.1 christos goto cleanup;
10245 1.1 christos }
10246 1.1 christos
10247 1.1 christos /*
10248 1.1 christos * Zero TTL handling of wildcard record.
10249 1.1 christos *
10250 1.3 christos * We don't yet have code to handle synthesis and type ANY or dns64
10251 1.3 christos * processing so we abort the synthesis here if there would be a
10252 1.3 christos * interaction.
10253 1.1 christos */
10254 1.1 christos switch (result) {
10255 1.1 christos case ISC_R_SUCCESS:
10256 1.9 christos if (qctx->type == dns_rdatatype_any) { /* XXX not yet */
10257 1.1 christos goto cleanup;
10258 1.1 christos }
10259 1.3 christos if (!ISC_LIST_EMPTY(qctx->view->dns64) &&
10260 1.1 christos (qctx->type == dns_rdatatype_a ||
10261 1.1 christos qctx->type == dns_rdatatype_aaaa)) /* XXX not yet */
10262 1.1 christos {
10263 1.1 christos goto cleanup;
10264 1.1 christos }
10265 1.15 christos FALLTHROUGH;
10266 1.1 christos case DNS_R_CNAME:
10267 1.9 christos if (!qctx->resuming && !STALE(&rdataset) && rdataset.ttl == 0 &&
10268 1.9 christos RECURSIONOK(qctx->client))
10269 1.1 christos {
10270 1.1 christos goto cleanup;
10271 1.1 christos }
10272 1.1 christos default:
10273 1.1 christos break;
10274 1.1 christos }
10275 1.1 christos
10276 1.1 christos switch (result) {
10277 1.1 christos case DNS_R_COVERINGNSEC:
10278 1.20 christos /*
10279 1.20 christos * Check that the covering NSEC record is from the right
10280 1.20 christos * namespace.
10281 1.20 christos */
10282 1.20 christos if (!dns_name_issubdomain(nowild, namespace)) {
10283 1.20 christos goto cleanup;
10284 1.20 christos }
10285 1.9 christos result = dns_nsec_noexistnodata(qctx->qtype, wild, nowild,
10286 1.9 christos &rdataset, &exists, &data, NULL,
10287 1.1 christos log_noexistnodata, qctx);
10288 1.20 christos if (result != ISC_R_SUCCESS || (exists && data)) {
10289 1.1 christos goto cleanup;
10290 1.1 christos }
10291 1.1 christos break;
10292 1.9 christos case ISC_R_SUCCESS: /* wild card match */
10293 1.1 christos (void)query_synthwildcard(qctx, &rdataset, &sigrdataset);
10294 1.3 christos done = true;
10295 1.1 christos goto cleanup;
10296 1.9 christos case DNS_R_CNAME: /* wild card cname */
10297 1.1 christos (void)query_synthcnamewildcard(qctx, &rdataset, &sigrdataset);
10298 1.3 christos done = true;
10299 1.1 christos goto cleanup;
10300 1.9 christos case DNS_R_NCACHENXRRSET: /* wild card nodata */
10301 1.9 christos case DNS_R_NCACHENXDOMAIN: /* direct nxdomain */
10302 1.1 christos default:
10303 1.1 christos goto cleanup;
10304 1.1 christos }
10305 1.1 christos
10306 1.1 christos /*
10307 1.1 christos * We now have the proof that we have an NXDOMAIN. Apply
10308 1.1 christos * NXDOMAIN redirection if configured.
10309 1.1 christos */
10310 1.18 christos result = query_redirect(qctx, DNS_R_COVERINGNSEC);
10311 1.1 christos if (result != ISC_R_COMPLETE) {
10312 1.3 christos redirected = true;
10313 1.1 christos goto cleanup;
10314 1.1 christos }
10315 1.1 christos
10316 1.1 christos /*
10317 1.1 christos * Must be signed to accept.
10318 1.1 christos */
10319 1.1 christos if (!dns_rdataset_isassociated(&sigrdataset)) {
10320 1.1 christos goto cleanup;
10321 1.1 christos }
10322 1.1 christos
10323 1.1 christos /*
10324 1.1 christos * Check signer signer names again.
10325 1.1 christos */
10326 1.1 christos result = checksignames(signer, &sigrdataset);
10327 1.1 christos if (result != ISC_R_SUCCESS) {
10328 1.1 christos result = ISC_R_SUCCESS;
10329 1.1 christos goto cleanup;
10330 1.1 christos }
10331 1.1 christos
10332 1.1 christos if (node != NULL) {
10333 1.1 christos dns_db_detachnode(db, &node);
10334 1.1 christos }
10335 1.1 christos
10336 1.3 christos soardataset = ns_client_newrdataset(qctx->client);
10337 1.3 christos sigsoardataset = ns_client_newrdataset(qctx->client);
10338 1.1 christos
10339 1.1 christos /*
10340 1.1 christos * Look for SOA record to construct NXDOMAIN response.
10341 1.1 christos */
10342 1.9 christos result = dns_db_findext(db, signer, qctx->version, dns_rdatatype_soa,
10343 1.9 christos dboptions, qctx->client->now, &node, fname, &cm,
10344 1.9 christos &ci, soardataset, sigsoardataset);
10345 1.1 christos
10346 1.1 christos if (result != ISC_R_SUCCESS) {
10347 1.1 christos goto cleanup;
10348 1.1 christos }
10349 1.20 christos (void)query_synthnxdomainnodata(qctx, exists, nowild, &rdataset,
10350 1.20 christos &sigrdataset, signer, &soardataset,
10351 1.20 christos &sigsoardataset);
10352 1.3 christos done = true;
10353 1.1 christos
10354 1.9 christos cleanup:
10355 1.1 christos if (dns_rdataset_isassociated(&rdataset)) {
10356 1.1 christos dns_rdataset_disassociate(&rdataset);
10357 1.1 christos }
10358 1.1 christos if (dns_rdataset_isassociated(&sigrdataset)) {
10359 1.1 christos dns_rdataset_disassociate(&sigrdataset);
10360 1.1 christos }
10361 1.1 christos if (soardataset != NULL) {
10362 1.3 christos ns_client_putrdataset(qctx->client, &soardataset);
10363 1.1 christos }
10364 1.1 christos if (sigsoardataset != NULL) {
10365 1.3 christos ns_client_putrdataset(qctx->client, &sigsoardataset);
10366 1.1 christos }
10367 1.1 christos if (db != NULL) {
10368 1.1 christos if (node != NULL) {
10369 1.1 christos dns_db_detachnode(db, &node);
10370 1.1 christos }
10371 1.1 christos dns_db_detach(&db);
10372 1.1 christos }
10373 1.1 christos
10374 1.1 christos if (redirected) {
10375 1.23 christos return result;
10376 1.1 christos }
10377 1.1 christos
10378 1.1 christos if (!done) {
10379 1.1 christos /*
10380 1.1 christos * No covering NSEC was found; proceed with recursion.
10381 1.1 christos */
10382 1.3 christos qctx->findcoveringnsec = false;
10383 1.1 christos if (qctx->fname != NULL) {
10384 1.3 christos ns_client_releasename(qctx->client, &qctx->fname);
10385 1.1 christos }
10386 1.1 christos if (qctx->node != NULL) {
10387 1.1 christos dns_db_detachnode(qctx->db, &qctx->node);
10388 1.1 christos }
10389 1.3 christos ns_client_putrdataset(qctx->client, &qctx->rdataset);
10390 1.1 christos if (qctx->sigrdataset != NULL) {
10391 1.3 christos ns_client_putrdataset(qctx->client, &qctx->sigrdataset);
10392 1.1 christos }
10393 1.23 christos return query_lookup(qctx);
10394 1.1 christos }
10395 1.1 christos
10396 1.23 christos return ns_query_done(qctx);
10397 1.1 christos }
10398 1.1 christos
10399 1.1 christos /*%
10400 1.1 christos * Handle negative cache responses, DNS_R_NCACHENXRRSET or
10401 1.1 christos * DNS_R_NCACHENXDOMAIN. (Note: may also be called with result
10402 1.1 christos * set to DNS_R_NXDOMAIN when handling DNS64 lookups.)
10403 1.1 christos */
10404 1.1 christos static isc_result_t
10405 1.1 christos query_ncache(query_ctx_t *qctx, isc_result_t result) {
10406 1.1 christos INSIST(!qctx->is_zone);
10407 1.1 christos INSIST(result == DNS_R_NCACHENXDOMAIN ||
10408 1.9 christos result == DNS_R_NCACHENXRRSET || result == DNS_R_NXDOMAIN);
10409 1.9 christos
10410 1.9 christos CCTRACE(ISC_LOG_DEBUG(3), "query_ncache");
10411 1.1 christos
10412 1.3 christos CALL_HOOK(NS_QUERY_NCACHE_BEGIN, qctx);
10413 1.3 christos
10414 1.3 christos qctx->authoritative = false;
10415 1.1 christos
10416 1.1 christos if (result == DNS_R_NCACHENXDOMAIN) {
10417 1.1 christos /*
10418 1.1 christos * Set message rcode. (This is not done when
10419 1.1 christos * result == DNS_R_NXDOMAIN because that means we're
10420 1.1 christos * being called after a DNS64 lookup and don't want
10421 1.1 christos * to update the rcode now.)
10422 1.1 christos */
10423 1.1 christos qctx->client->message->rcode = dns_rcode_nxdomain;
10424 1.1 christos
10425 1.1 christos /* Look for RFC 1918 leakage from Internet. */
10426 1.1 christos if (qctx->qtype == dns_rdatatype_ptr &&
10427 1.1 christos qctx->client->message->rdclass == dns_rdataclass_in &&
10428 1.1 christos dns_name_countlabels(qctx->fname) == 7)
10429 1.1 christos {
10430 1.1 christos warn_rfc1918(qctx->client, qctx->fname, qctx->rdataset);
10431 1.1 christos }
10432 1.1 christos }
10433 1.1 christos
10434 1.23 christos return query_nodata(qctx, result);
10435 1.3 christos
10436 1.9 christos cleanup:
10437 1.23 christos return result;
10438 1.3 christos }
10439 1.3 christos
10440 1.3 christos /*
10441 1.3 christos * If we have a zero ttl from the cache, refetch.
10442 1.3 christos */
10443 1.3 christos static isc_result_t
10444 1.3 christos query_zerottl_refetch(query_ctx_t *qctx) {
10445 1.3 christos isc_result_t result;
10446 1.3 christos
10447 1.9 christos CCTRACE(ISC_LOG_DEBUG(3), "query_zerottl_refetch");
10448 1.9 christos
10449 1.3 christos if (qctx->is_zone || qctx->resuming || STALE(qctx->rdataset) ||
10450 1.3 christos qctx->rdataset->ttl != 0 || !RECURSIONOK(qctx->client))
10451 1.3 christos {
10452 1.23 christos return ISC_R_COMPLETE;
10453 1.3 christos }
10454 1.3 christos
10455 1.3 christos qctx_clean(qctx);
10456 1.3 christos
10457 1.3 christos INSIST(!REDIRECT(qctx->client));
10458 1.3 christos
10459 1.3 christos result = ns_query_recurse(qctx->client, qctx->qtype,
10460 1.9 christos qctx->client->query.qname, NULL, NULL,
10461 1.9 christos qctx->resuming);
10462 1.3 christos if (result == ISC_R_SUCCESS) {
10463 1.3 christos CALL_HOOK(NS_QUERY_ZEROTTL_RECURSE, qctx);
10464 1.9 christos qctx->client->query.attributes |= NS_QUERYATTR_RECURSING;
10465 1.3 christos
10466 1.3 christos if (qctx->dns64) {
10467 1.9 christos qctx->client->query.attributes |= NS_QUERYATTR_DNS64;
10468 1.3 christos }
10469 1.3 christos if (qctx->dns64_exclude) {
10470 1.3 christos qctx->client->query.attributes |=
10471 1.3 christos NS_QUERYATTR_DNS64EXCLUDE;
10472 1.3 christos }
10473 1.3 christos } else {
10474 1.13 christos /*
10475 1.13 christos * There was a zero ttl from the cache, don't fallback to
10476 1.13 christos * serve-stale lookup.
10477 1.13 christos */
10478 1.3 christos QUERY_ERROR(qctx, result);
10479 1.3 christos }
10480 1.3 christos
10481 1.23 christos return ns_query_done(qctx);
10482 1.3 christos
10483 1.9 christos cleanup:
10484 1.23 christos return result;
10485 1.1 christos }
10486 1.1 christos
10487 1.1 christos /*
10488 1.1 christos * Handle CNAME responses.
10489 1.1 christos */
10490 1.1 christos static isc_result_t
10491 1.1 christos query_cname(query_ctx_t *qctx) {
10492 1.14 christos isc_result_t result = ISC_R_UNSET;
10493 1.14 christos dns_name_t *tname = NULL;
10494 1.14 christos dns_rdataset_t *trdataset = NULL;
10495 1.1 christos dns_rdataset_t **sigrdatasetp = NULL;
10496 1.1 christos dns_rdata_t rdata = DNS_RDATA_INIT;
10497 1.1 christos dns_rdata_cname_t cname;
10498 1.1 christos
10499 1.9 christos CCTRACE(ISC_LOG_DEBUG(3), "query_cname");
10500 1.9 christos
10501 1.3 christos CALL_HOOK(NS_QUERY_CNAME_BEGIN, qctx);
10502 1.1 christos
10503 1.3 christos result = query_zerottl_refetch(qctx);
10504 1.3 christos if (result != ISC_R_COMPLETE) {
10505 1.23 christos goto cleanup;
10506 1.1 christos }
10507 1.1 christos
10508 1.1 christos /*
10509 1.1 christos * Keep a copy of the rdataset. We have to do this because
10510 1.1 christos * query_addrrset may clear 'rdataset' (to prevent the
10511 1.1 christos * cleanup code from cleaning it up).
10512 1.1 christos */
10513 1.1 christos trdataset = qctx->rdataset;
10514 1.1 christos
10515 1.1 christos /*
10516 1.1 christos * Add the CNAME to the answer section.
10517 1.1 christos */
10518 1.9 christos if (WANTDNSSEC(qctx->client) && qctx->sigrdataset != NULL) {
10519 1.1 christos sigrdatasetp = &qctx->sigrdataset;
10520 1.9 christos }
10521 1.1 christos
10522 1.23 christos if (WANTDNSSEC(qctx->client) && qctx->fname->attributes.wildcard) {
10523 1.1 christos dns_fixedname_init(&qctx->wildcardname);
10524 1.20 christos dns_name_copy(qctx->fname,
10525 1.20 christos dns_fixedname_name(&qctx->wildcardname));
10526 1.3 christos qctx->need_wildcardproof = true;
10527 1.1 christos }
10528 1.1 christos
10529 1.1 christos if (NOQNAME(qctx->rdataset) && WANTDNSSEC(qctx->client)) {
10530 1.1 christos qctx->noqname = qctx->rdataset;
10531 1.1 christos } else {
10532 1.1 christos qctx->noqname = NULL;
10533 1.1 christos }
10534 1.1 christos
10535 1.9 christos if (!qctx->is_zone && RECURSIONOK(qctx->client)) {
10536 1.1 christos query_prefetch(qctx->client, qctx->fname, qctx->rdataset);
10537 1.9 christos }
10538 1.1 christos
10539 1.9 christos query_addrrset(qctx, &qctx->fname, &qctx->rdataset, sigrdatasetp,
10540 1.9 christos qctx->dbuf, DNS_SECTION_ANSWER);
10541 1.1 christos
10542 1.1 christos query_addnoqnameproof(qctx);
10543 1.1 christos
10544 1.1 christos /*
10545 1.1 christos * We set the PARTIALANSWER attribute so that if anything goes
10546 1.1 christos * wrong later on, we'll return what we've got so far.
10547 1.1 christos */
10548 1.1 christos qctx->client->query.attributes |= NS_QUERYATTR_PARTIALANSWER;
10549 1.1 christos
10550 1.1 christos /*
10551 1.1 christos * Reset qname to be the target name of the CNAME and restart
10552 1.1 christos * the query.
10553 1.1 christos */
10554 1.23 christos dns_message_gettempname(qctx->client->message, &tname);
10555 1.1 christos
10556 1.1 christos result = dns_rdataset_first(trdataset);
10557 1.1 christos if (result != ISC_R_SUCCESS) {
10558 1.1 christos dns_message_puttempname(qctx->client->message, &tname);
10559 1.23 christos (void)ns_query_done(qctx);
10560 1.23 christos goto cleanup;
10561 1.1 christos }
10562 1.1 christos
10563 1.1 christos dns_rdataset_current(trdataset, &rdata);
10564 1.1 christos result = dns_rdata_tostruct(&rdata, &cname, NULL);
10565 1.3 christos RUNTIME_CHECK(result == ISC_R_SUCCESS);
10566 1.1 christos dns_rdata_reset(&rdata);
10567 1.1 christos
10568 1.20 christos dns_name_copy(&cname.cname, tname);
10569 1.1 christos
10570 1.1 christos dns_rdata_freestruct(&cname);
10571 1.1 christos ns_client_qnamereplace(qctx->client, tname);
10572 1.3 christos qctx->want_restart = true;
10573 1.9 christos if (!WANTRECURSION(qctx->client)) {
10574 1.23 christos qctx->options.nolog = true;
10575 1.9 christos }
10576 1.1 christos
10577 1.1 christos query_addauth(qctx);
10578 1.1 christos
10579 1.23 christos return ns_query_done(qctx);
10580 1.3 christos
10581 1.9 christos cleanup:
10582 1.23 christos return result;
10583 1.1 christos }
10584 1.1 christos
10585 1.1 christos /*
10586 1.1 christos * Handle DNAME responses.
10587 1.1 christos */
10588 1.1 christos static isc_result_t
10589 1.1 christos query_dname(query_ctx_t *qctx) {
10590 1.1 christos dns_name_t *tname, *prefix;
10591 1.1 christos dns_rdata_t rdata = DNS_RDATA_INIT;
10592 1.1 christos dns_rdata_dname_t dname;
10593 1.1 christos dns_fixedname_t fixed;
10594 1.1 christos dns_rdataset_t *trdataset;
10595 1.1 christos dns_rdataset_t **sigrdatasetp = NULL;
10596 1.1 christos dns_namereln_t namereln;
10597 1.1 christos isc_buffer_t b;
10598 1.1 christos int order;
10599 1.20 christos isc_result_t result = ISC_R_UNSET;
10600 1.1 christos unsigned int nlabels;
10601 1.1 christos
10602 1.9 christos CCTRACE(ISC_LOG_DEBUG(3), "query_dname");
10603 1.9 christos
10604 1.3 christos CALL_HOOK(NS_QUERY_DNAME_BEGIN, qctx);
10605 1.3 christos
10606 1.1 christos /*
10607 1.1 christos * Compare the current qname to the found name. We need
10608 1.1 christos * to know how many labels and bits are in common because
10609 1.1 christos * we're going to have to split qname later on.
10610 1.1 christos */
10611 1.1 christos namereln = dns_name_fullcompare(qctx->client->query.qname, qctx->fname,
10612 1.1 christos &order, &nlabels);
10613 1.1 christos INSIST(namereln == dns_namereln_subdomain);
10614 1.1 christos
10615 1.1 christos /*
10616 1.1 christos * Keep a copy of the rdataset. We have to do this because
10617 1.1 christos * query_addrrset may clear 'rdataset' (to prevent the
10618 1.1 christos * cleanup code from cleaning it up).
10619 1.1 christos */
10620 1.1 christos trdataset = qctx->rdataset;
10621 1.1 christos
10622 1.1 christos /*
10623 1.1 christos * Add the DNAME to the answer section.
10624 1.1 christos */
10625 1.9 christos if (WANTDNSSEC(qctx->client) && qctx->sigrdataset != NULL) {
10626 1.1 christos sigrdatasetp = &qctx->sigrdataset;
10627 1.9 christos }
10628 1.1 christos
10629 1.23 christos if (WANTDNSSEC(qctx->client) && qctx->fname->attributes.wildcard) {
10630 1.1 christos dns_fixedname_init(&qctx->wildcardname);
10631 1.20 christos dns_name_copy(qctx->fname,
10632 1.20 christos dns_fixedname_name(&qctx->wildcardname));
10633 1.3 christos qctx->need_wildcardproof = true;
10634 1.1 christos }
10635 1.1 christos
10636 1.9 christos if (!qctx->is_zone && RECURSIONOK(qctx->client)) {
10637 1.1 christos query_prefetch(qctx->client, qctx->fname, qctx->rdataset);
10638 1.9 christos }
10639 1.9 christos query_addrrset(qctx, &qctx->fname, &qctx->rdataset, sigrdatasetp,
10640 1.9 christos qctx->dbuf, DNS_SECTION_ANSWER);
10641 1.1 christos
10642 1.1 christos /*
10643 1.1 christos * We set the PARTIALANSWER attribute so that if anything goes
10644 1.1 christos * wrong later on, we'll return what we've got so far.
10645 1.1 christos */
10646 1.1 christos qctx->client->query.attributes |= NS_QUERYATTR_PARTIALANSWER;
10647 1.1 christos
10648 1.1 christos /*
10649 1.1 christos * Get the target name of the DNAME.
10650 1.1 christos */
10651 1.1 christos tname = NULL;
10652 1.23 christos dns_message_gettempname(qctx->client->message, &tname);
10653 1.1 christos
10654 1.1 christos result = dns_rdataset_first(trdataset);
10655 1.1 christos if (result != ISC_R_SUCCESS) {
10656 1.1 christos dns_message_puttempname(qctx->client->message, &tname);
10657 1.23 christos (void)ns_query_done(qctx);
10658 1.23 christos goto cleanup;
10659 1.1 christos }
10660 1.1 christos
10661 1.1 christos dns_rdataset_current(trdataset, &rdata);
10662 1.1 christos result = dns_rdata_tostruct(&rdata, &dname, NULL);
10663 1.3 christos RUNTIME_CHECK(result == ISC_R_SUCCESS);
10664 1.1 christos dns_rdata_reset(&rdata);
10665 1.1 christos
10666 1.20 christos dns_name_copy(&dname.dname, tname);
10667 1.1 christos dns_rdata_freestruct(&dname);
10668 1.1 christos
10669 1.1 christos /*
10670 1.1 christos * Construct the new qname consisting of
10671 1.1 christos * <found name prefix>.<dname target>
10672 1.1 christos */
10673 1.1 christos prefix = dns_fixedname_initname(&fixed);
10674 1.1 christos dns_name_split(qctx->client->query.qname, nlabels, prefix, NULL);
10675 1.1 christos INSIST(qctx->fname == NULL);
10676 1.3 christos qctx->dbuf = ns_client_getnamebuf(qctx->client);
10677 1.3 christos qctx->fname = ns_client_newname(qctx->client, qctx->dbuf, &b);
10678 1.1 christos result = dns_name_concatenate(prefix, tname, qctx->fname, NULL);
10679 1.1 christos dns_message_puttempname(qctx->client->message, &tname);
10680 1.1 christos
10681 1.1 christos /*
10682 1.1 christos * RFC2672, section 4.1, subsection 3c says
10683 1.1 christos * we should return YXDOMAIN if the constructed
10684 1.1 christos * name would be too long.
10685 1.1 christos */
10686 1.9 christos if (result == DNS_R_NAMETOOLONG) {
10687 1.1 christos qctx->client->message->rcode = dns_rcode_yxdomain;
10688 1.9 christos }
10689 1.9 christos if (result != ISC_R_SUCCESS) {
10690 1.23 christos (void)ns_query_done(qctx);
10691 1.23 christos goto cleanup;
10692 1.9 christos }
10693 1.1 christos
10694 1.3 christos ns_client_keepname(qctx->client, qctx->fname, qctx->dbuf);
10695 1.1 christos
10696 1.1 christos /*
10697 1.1 christos * Synthesize a CNAME consisting of
10698 1.1 christos * <old qname> <dname ttl> CNAME <new qname>
10699 1.1 christos * with <dname trust value>
10700 1.1 christos *
10701 1.1 christos * Synthesize a CNAME so old old clients that don't understand
10702 1.1 christos * DNAME can chain.
10703 1.1 christos *
10704 1.1 christos * We do not try to synthesize a signature because we hope
10705 1.1 christos * that security aware servers will understand DNAME. Also,
10706 1.1 christos * even if we had an online key, making a signature
10707 1.1 christos * on-the-fly is costly, and not really legitimate anyway
10708 1.1 christos * since the synthesized CNAME is NOT in the zone.
10709 1.1 christos */
10710 1.23 christos query_addcname(qctx, trdataset->trust, trdataset->ttl);
10711 1.1 christos
10712 1.1 christos /*
10713 1.11 christos * If the original query was not for a CNAME or ANY then follow the
10714 1.11 christos * CNAME.
10715 1.1 christos */
10716 1.11 christos if (qctx->qtype != dns_rdatatype_cname &&
10717 1.16 christos qctx->qtype != dns_rdatatype_any)
10718 1.16 christos {
10719 1.11 christos /*
10720 1.11 christos * Switch to the new qname and restart.
10721 1.11 christos */
10722 1.11 christos ns_client_qnamereplace(qctx->client, qctx->fname);
10723 1.11 christos qctx->fname = NULL;
10724 1.11 christos qctx->want_restart = true;
10725 1.11 christos if (!WANTRECURSION(qctx->client)) {
10726 1.23 christos qctx->options.nolog = true;
10727 1.11 christos }
10728 1.9 christos }
10729 1.1 christos
10730 1.1 christos query_addauth(qctx);
10731 1.1 christos
10732 1.23 christos return ns_query_done(qctx);
10733 1.3 christos
10734 1.9 christos cleanup:
10735 1.23 christos return result;
10736 1.1 christos }
10737 1.1 christos
10738 1.1 christos /*%
10739 1.9 christos * Add CNAME to response.
10740 1.1 christos */
10741 1.23 christos static void
10742 1.1 christos query_addcname(query_ctx_t *qctx, dns_trust_t trust, dns_ttl_t ttl) {
10743 1.1 christos ns_client_t *client = qctx->client;
10744 1.1 christos dns_rdataset_t *rdataset = NULL;
10745 1.1 christos dns_rdatalist_t *rdatalist = NULL;
10746 1.1 christos dns_rdata_t *rdata = NULL;
10747 1.1 christos isc_region_t r;
10748 1.1 christos dns_name_t *aname = NULL;
10749 1.1 christos
10750 1.23 christos dns_message_gettempname(client->message, &aname);
10751 1.14 christos
10752 1.20 christos dns_name_copy(client->query.qname, aname);
10753 1.1 christos
10754 1.23 christos dns_message_gettemprdatalist(client->message, &rdatalist);
10755 1.1 christos
10756 1.23 christos dns_message_gettemprdata(client->message, &rdata);
10757 1.1 christos
10758 1.23 christos dns_message_gettemprdataset(client->message, &rdataset);
10759 1.1 christos
10760 1.1 christos rdatalist->type = dns_rdatatype_cname;
10761 1.1 christos rdatalist->rdclass = client->message->rdclass;
10762 1.1 christos rdatalist->ttl = ttl;
10763 1.1 christos
10764 1.1 christos dns_name_toregion(qctx->fname, &r);
10765 1.1 christos rdata->data = r.base;
10766 1.1 christos rdata->length = r.length;
10767 1.1 christos rdata->rdclass = client->message->rdclass;
10768 1.1 christos rdata->type = dns_rdatatype_cname;
10769 1.1 christos
10770 1.1 christos ISC_LIST_APPEND(rdatalist->rdata, rdata, link);
10771 1.23 christos dns_rdatalist_tordataset(rdatalist, rdataset);
10772 1.1 christos rdataset->trust = trust;
10773 1.1 christos dns_rdataset_setownercase(rdataset, aname);
10774 1.1 christos
10775 1.9 christos query_addrrset(qctx, &aname, &rdataset, NULL, NULL, DNS_SECTION_ANSWER);
10776 1.1 christos if (rdataset != NULL) {
10777 1.9 christos if (dns_rdataset_isassociated(rdataset)) {
10778 1.1 christos dns_rdataset_disassociate(rdataset);
10779 1.9 christos }
10780 1.1 christos dns_message_puttemprdataset(client->message, &rdataset);
10781 1.1 christos }
10782 1.9 christos if (aname != NULL) {
10783 1.1 christos dns_message_puttempname(client->message, &aname);
10784 1.9 christos }
10785 1.1 christos }
10786 1.1 christos
10787 1.1 christos /*%
10788 1.1 christos * Prepare to respond: determine whether a wildcard proof is needed,
10789 1.3 christos * then hand off to query_respond() or (for type ANY queries)
10790 1.3 christos * query_respond_any().
10791 1.1 christos */
10792 1.1 christos static isc_result_t
10793 1.1 christos query_prepresponse(query_ctx_t *qctx) {
10794 1.20 christos isc_result_t result = ISC_R_UNSET;
10795 1.3 christos
10796 1.9 christos CCTRACE(ISC_LOG_DEBUG(3), "query_prepresponse");
10797 1.9 christos
10798 1.3 christos CALL_HOOK(NS_QUERY_PREP_RESPONSE_BEGIN, qctx);
10799 1.3 christos
10800 1.23 christos if (WANTDNSSEC(qctx->client) && qctx->fname->attributes.wildcard) {
10801 1.1 christos dns_fixedname_init(&qctx->wildcardname);
10802 1.20 christos dns_name_copy(qctx->fname,
10803 1.20 christos dns_fixedname_name(&qctx->wildcardname));
10804 1.3 christos qctx->need_wildcardproof = true;
10805 1.3 christos }
10806 1.3 christos
10807 1.3 christos if (qctx->type == dns_rdatatype_any) {
10808 1.23 christos return query_respond_any(qctx);
10809 1.1 christos }
10810 1.1 christos
10811 1.3 christos result = query_zerottl_refetch(qctx);
10812 1.3 christos if (result != ISC_R_COMPLETE) {
10813 1.23 christos goto cleanup;
10814 1.1 christos }
10815 1.1 christos
10816 1.23 christos return query_respond(qctx);
10817 1.1 christos
10818 1.9 christos cleanup:
10819 1.23 christos return result;
10820 1.1 christos }
10821 1.1 christos
10822 1.1 christos /*%
10823 1.1 christos * Add SOA to the authority section when sending negative responses
10824 1.1 christos * (or to the additional section if sending negative responses triggered
10825 1.1 christos * by RPZ rewriting.)
10826 1.1 christos */
10827 1.1 christos static isc_result_t
10828 1.1 christos query_addsoa(query_ctx_t *qctx, unsigned int override_ttl,
10829 1.9 christos dns_section_t section) {
10830 1.1 christos ns_client_t *client = qctx->client;
10831 1.20 christos dns_name_t *name = NULL;
10832 1.20 christos dns_dbnode_t *node = NULL;
10833 1.20 christos isc_result_t result, eresult = ISC_R_SUCCESS;
10834 1.1 christos dns_rdataset_t *rdataset = NULL, *sigrdataset = NULL;
10835 1.1 christos dns_rdataset_t **sigrdatasetp = NULL;
10836 1.1 christos dns_clientinfomethods_t cm;
10837 1.1 christos dns_clientinfo_t ci;
10838 1.1 christos
10839 1.1 christos CTRACE(ISC_LOG_DEBUG(3), "query_addsoa");
10840 1.1 christos
10841 1.1 christos dns_clientinfomethods_init(&cm, ns_client_sourceip);
10842 1.20 christos dns_clientinfo_init(&ci, client, NULL);
10843 1.1 christos
10844 1.1 christos /*
10845 1.1 christos * Don't add the SOA record for test which set "-T nosoa".
10846 1.1 christos */
10847 1.23 christos if (((client->manager->sctx->options & NS_SERVER_NOSOA) != 0) &&
10848 1.1 christos (!WANTDNSSEC(client) || !dns_rdataset_isassociated(qctx->rdataset)))
10849 1.1 christos {
10850 1.23 christos return ISC_R_SUCCESS;
10851 1.1 christos }
10852 1.1 christos
10853 1.1 christos /*
10854 1.1 christos * Get resources and make 'name' be the database origin.
10855 1.1 christos */
10856 1.23 christos dns_message_gettempname(client->message, &name);
10857 1.14 christos
10858 1.14 christos /*
10859 1.14 christos * We'll be releasing 'name' before returning, so it's safe to
10860 1.14 christos * use clone instead of copying here.
10861 1.14 christos */
10862 1.1 christos dns_name_clone(dns_db_origin(qctx->db), name);
10863 1.14 christos
10864 1.3 christos rdataset = ns_client_newrdataset(client);
10865 1.1 christos if (WANTDNSSEC(client) && dns_db_issecure(qctx->db)) {
10866 1.3 christos sigrdataset = ns_client_newrdataset(client);
10867 1.1 christos }
10868 1.1 christos
10869 1.1 christos /*
10870 1.1 christos * Find the SOA.
10871 1.1 christos */
10872 1.1 christos result = dns_db_getoriginnode(qctx->db, &node);
10873 1.1 christos if (result == ISC_R_SUCCESS) {
10874 1.1 christos result = dns_db_findrdataset(qctx->db, node, qctx->version,
10875 1.9 christos dns_rdatatype_soa, 0, client->now,
10876 1.1 christos rdataset, sigrdataset);
10877 1.1 christos } else {
10878 1.1 christos dns_fixedname_t foundname;
10879 1.1 christos dns_name_t *fname;
10880 1.1 christos
10881 1.1 christos fname = dns_fixedname_initname(&foundname);
10882 1.1 christos
10883 1.1 christos result = dns_db_findext(qctx->db, name, qctx->version,
10884 1.1 christos dns_rdatatype_soa,
10885 1.9 christos client->query.dboptions, 0, &node,
10886 1.9 christos fname, &cm, &ci, rdataset, sigrdataset);
10887 1.1 christos }
10888 1.1 christos if (result != ISC_R_SUCCESS) {
10889 1.1 christos /*
10890 1.1 christos * This is bad. We tried to get the SOA RR at the zone top
10891 1.1 christos * and it didn't work!
10892 1.1 christos */
10893 1.1 christos CTRACE(ISC_LOG_ERROR, "unable to find SOA RR at zone apex");
10894 1.1 christos eresult = DNS_R_SERVFAIL;
10895 1.1 christos } else {
10896 1.1 christos /*
10897 1.1 christos * Extract the SOA MINIMUM.
10898 1.1 christos */
10899 1.1 christos dns_rdata_soa_t soa;
10900 1.1 christos dns_rdata_t rdata = DNS_RDATA_INIT;
10901 1.1 christos result = dns_rdataset_first(rdataset);
10902 1.1 christos RUNTIME_CHECK(result == ISC_R_SUCCESS);
10903 1.1 christos dns_rdataset_current(rdataset, &rdata);
10904 1.1 christos result = dns_rdata_tostruct(&rdata, &soa, NULL);
10905 1.3 christos RUNTIME_CHECK(result == ISC_R_SUCCESS);
10906 1.1 christos
10907 1.9 christos if (override_ttl != UINT32_MAX && override_ttl < rdataset->ttl)
10908 1.1 christos {
10909 1.1 christos rdataset->ttl = override_ttl;
10910 1.9 christos if (sigrdataset != NULL) {
10911 1.1 christos sigrdataset->ttl = override_ttl;
10912 1.9 christos }
10913 1.1 christos }
10914 1.1 christos
10915 1.1 christos /*
10916 1.1 christos * Add the SOA and its SIG to the response, with the
10917 1.1 christos * TTLs adjusted per RFC2308 section 3.
10918 1.1 christos */
10919 1.9 christos if (rdataset->ttl > soa.minimum) {
10920 1.1 christos rdataset->ttl = soa.minimum;
10921 1.9 christos }
10922 1.9 christos if (sigrdataset != NULL && sigrdataset->ttl > soa.minimum) {
10923 1.1 christos sigrdataset->ttl = soa.minimum;
10924 1.9 christos }
10925 1.1 christos
10926 1.9 christos if (sigrdataset != NULL) {
10927 1.1 christos sigrdatasetp = &sigrdataset;
10928 1.9 christos } else {
10929 1.1 christos sigrdatasetp = NULL;
10930 1.9 christos }
10931 1.1 christos
10932 1.9 christos if (section == DNS_SECTION_ADDITIONAL) {
10933 1.1 christos rdataset->attributes |= DNS_RDATASETATTR_REQUIRED;
10934 1.9 christos }
10935 1.9 christos query_addrrset(qctx, &name, &rdataset, sigrdatasetp, NULL,
10936 1.9 christos section);
10937 1.1 christos }
10938 1.1 christos
10939 1.3 christos ns_client_putrdataset(client, &rdataset);
10940 1.9 christos if (sigrdataset != NULL) {
10941 1.3 christos ns_client_putrdataset(client, &sigrdataset);
10942 1.9 christos }
10943 1.9 christos if (name != NULL) {
10944 1.3 christos ns_client_releasename(client, &name);
10945 1.9 christos }
10946 1.9 christos if (node != NULL) {
10947 1.1 christos dns_db_detachnode(qctx->db, &node);
10948 1.9 christos }
10949 1.1 christos
10950 1.23 christos return eresult;
10951 1.1 christos }
10952 1.1 christos
10953 1.1 christos /*%
10954 1.1 christos * Add NS to authority section (used when the zone apex is already known).
10955 1.1 christos */
10956 1.1 christos static isc_result_t
10957 1.1 christos query_addns(query_ctx_t *qctx) {
10958 1.1 christos ns_client_t *client = qctx->client;
10959 1.1 christos isc_result_t result, eresult;
10960 1.1 christos dns_name_t *name = NULL, *fname;
10961 1.1 christos dns_dbnode_t *node = NULL;
10962 1.1 christos dns_fixedname_t foundname;
10963 1.1 christos dns_rdataset_t *rdataset = NULL, *sigrdataset = NULL;
10964 1.1 christos dns_rdataset_t **sigrdatasetp = NULL;
10965 1.1 christos dns_clientinfomethods_t cm;
10966 1.1 christos dns_clientinfo_t ci;
10967 1.1 christos
10968 1.1 christos CTRACE(ISC_LOG_DEBUG(3), "query_addns");
10969 1.1 christos
10970 1.1 christos /*
10971 1.1 christos * Initialization.
10972 1.1 christos */
10973 1.1 christos eresult = ISC_R_SUCCESS;
10974 1.1 christos fname = dns_fixedname_initname(&foundname);
10975 1.1 christos
10976 1.1 christos dns_clientinfomethods_init(&cm, ns_client_sourceip);
10977 1.20 christos dns_clientinfo_init(&ci, client, NULL);
10978 1.1 christos
10979 1.1 christos /*
10980 1.1 christos * Get resources and make 'name' be the database origin.
10981 1.1 christos */
10982 1.23 christos dns_message_gettempname(client->message, &name);
10983 1.1 christos dns_name_clone(dns_db_origin(qctx->db), name);
10984 1.3 christos rdataset = ns_client_newrdataset(client);
10985 1.1 christos
10986 1.1 christos if (WANTDNSSEC(client) && dns_db_issecure(qctx->db)) {
10987 1.3 christos sigrdataset = ns_client_newrdataset(client);
10988 1.1 christos }
10989 1.1 christos
10990 1.1 christos /*
10991 1.1 christos * Find the NS rdataset.
10992 1.1 christos */
10993 1.1 christos result = dns_db_getoriginnode(qctx->db, &node);
10994 1.1 christos if (result == ISC_R_SUCCESS) {
10995 1.1 christos result = dns_db_findrdataset(qctx->db, node, qctx->version,
10996 1.1 christos dns_rdatatype_ns, 0, client->now,
10997 1.1 christos rdataset, sigrdataset);
10998 1.1 christos } else {
10999 1.1 christos CTRACE(ISC_LOG_DEBUG(3), "query_addns: calling dns_db_find");
11000 1.1 christos result = dns_db_findext(qctx->db, name, NULL, dns_rdatatype_ns,
11001 1.1 christos client->query.dboptions, 0, &node,
11002 1.1 christos fname, &cm, &ci, rdataset, sigrdataset);
11003 1.1 christos CTRACE(ISC_LOG_DEBUG(3), "query_addns: dns_db_find complete");
11004 1.1 christos }
11005 1.1 christos if (result != ISC_R_SUCCESS) {
11006 1.9 christos CTRACE(ISC_LOG_ERROR, "query_addns: "
11007 1.9 christos "dns_db_findrdataset or dns_db_find "
11008 1.9 christos "failed");
11009 1.1 christos /*
11010 1.1 christos * This is bad. We tried to get the NS rdataset at the zone
11011 1.1 christos * top and it didn't work!
11012 1.1 christos */
11013 1.1 christos eresult = DNS_R_SERVFAIL;
11014 1.1 christos } else {
11015 1.1 christos if (sigrdataset != NULL) {
11016 1.1 christos sigrdatasetp = &sigrdataset;
11017 1.1 christos }
11018 1.3 christos query_addrrset(qctx, &name, &rdataset, sigrdatasetp, NULL,
11019 1.1 christos DNS_SECTION_AUTHORITY);
11020 1.1 christos }
11021 1.1 christos
11022 1.1 christos CTRACE(ISC_LOG_DEBUG(3), "query_addns: cleanup");
11023 1.3 christos ns_client_putrdataset(client, &rdataset);
11024 1.1 christos if (sigrdataset != NULL) {
11025 1.3 christos ns_client_putrdataset(client, &sigrdataset);
11026 1.1 christos }
11027 1.1 christos if (name != NULL) {
11028 1.3 christos ns_client_releasename(client, &name);
11029 1.1 christos }
11030 1.1 christos if (node != NULL) {
11031 1.1 christos dns_db_detachnode(qctx->db, &node);
11032 1.1 christos }
11033 1.1 christos
11034 1.1 christos CTRACE(ISC_LOG_DEBUG(3), "query_addns: done");
11035 1.23 christos return eresult;
11036 1.1 christos }
11037 1.1 christos
11038 1.1 christos /*%
11039 1.1 christos * Find the zone cut and add the best NS rrset to the authority section.
11040 1.1 christos */
11041 1.1 christos static void
11042 1.1 christos query_addbestns(query_ctx_t *qctx) {
11043 1.1 christos ns_client_t *client = qctx->client;
11044 1.1 christos dns_db_t *db = NULL, *zdb = NULL;
11045 1.1 christos dns_dbnode_t *node = NULL;
11046 1.1 christos dns_name_t *fname = NULL, *zfname = NULL;
11047 1.1 christos dns_rdataset_t *rdataset = NULL, *sigrdataset = NULL;
11048 1.1 christos dns_rdataset_t *zrdataset = NULL, *zsigrdataset = NULL;
11049 1.3 christos bool is_zone = false, use_zone = false;
11050 1.1 christos isc_buffer_t *dbuf = NULL;
11051 1.1 christos isc_result_t result;
11052 1.1 christos dns_dbversion_t *version = NULL;
11053 1.1 christos dns_zone_t *zone = NULL;
11054 1.1 christos isc_buffer_t b;
11055 1.1 christos dns_clientinfomethods_t cm;
11056 1.1 christos dns_clientinfo_t ci;
11057 1.22 christos dns_name_t qname;
11058 1.1 christos
11059 1.1 christos CTRACE(ISC_LOG_DEBUG(3), "query_addbestns");
11060 1.1 christos
11061 1.1 christos dns_clientinfomethods_init(&cm, ns_client_sourceip);
11062 1.20 christos dns_clientinfo_init(&ci, client, NULL);
11063 1.1 christos
11064 1.22 christos dns_name_init(&qname, NULL);
11065 1.22 christos dns_name_clone(client->query.qname, &qname);
11066 1.22 christos
11067 1.1 christos /*
11068 1.1 christos * Find the right database.
11069 1.1 christos */
11070 1.22 christos do {
11071 1.23 christos result = query_getdb(client, &qname, dns_rdatatype_ns,
11072 1.23 christos (dns_getdb_options_t){ 0 }, &zone, &db,
11073 1.23 christos &version, &is_zone);
11074 1.22 christos if (result != ISC_R_SUCCESS) {
11075 1.22 christos goto cleanup;
11076 1.22 christos }
11077 1.22 christos
11078 1.22 christos /*
11079 1.22 christos * If this is a static stub zone look for a parent zone.
11080 1.22 christos */
11081 1.22 christos if (zone != NULL &&
11082 1.22 christos dns_zone_gettype(zone) == dns_zone_staticstub)
11083 1.22 christos {
11084 1.22 christos unsigned int labels = dns_name_countlabels(&qname);
11085 1.22 christos dns_db_detach(&db);
11086 1.22 christos dns_zone_detach(&zone);
11087 1.22 christos version = NULL;
11088 1.22 christos if (labels != 1) {
11089 1.22 christos dns_name_split(&qname, labels - 1, NULL,
11090 1.22 christos &qname);
11091 1.22 christos continue;
11092 1.22 christos }
11093 1.22 christos if (!USECACHE(client)) {
11094 1.22 christos goto cleanup;
11095 1.22 christos }
11096 1.22 christos dns_db_attach(client->view->cachedb, &db);
11097 1.22 christos is_zone = false;
11098 1.22 christos }
11099 1.22 christos break;
11100 1.22 christos } while (true);
11101 1.1 christos
11102 1.9 christos db_find:
11103 1.1 christos /*
11104 1.1 christos * We'll need some resources...
11105 1.1 christos */
11106 1.3 christos dbuf = ns_client_getnamebuf(client);
11107 1.3 christos fname = ns_client_newname(client, dbuf, &b);
11108 1.3 christos rdataset = ns_client_newrdataset(client);
11109 1.1 christos
11110 1.1 christos /*
11111 1.1 christos * Get the RRSIGs if the client requested them or if we may
11112 1.1 christos * need to validate answers from the cache.
11113 1.1 christos */
11114 1.1 christos if (WANTDNSSEC(client) || !is_zone) {
11115 1.3 christos sigrdataset = ns_client_newrdataset(client);
11116 1.1 christos }
11117 1.1 christos
11118 1.1 christos /*
11119 1.1 christos * Now look for the zonecut.
11120 1.1 christos */
11121 1.1 christos if (is_zone) {
11122 1.9 christos result = dns_db_findext(
11123 1.9 christos db, client->query.qname, version, dns_rdatatype_ns,
11124 1.9 christos client->query.dboptions, client->now, &node, fname, &cm,
11125 1.9 christos &ci, rdataset, sigrdataset);
11126 1.1 christos if (result != DNS_R_DELEGATION) {
11127 1.1 christos goto cleanup;
11128 1.1 christos }
11129 1.1 christos if (USECACHE(client)) {
11130 1.3 christos ns_client_keepname(client, fname, dbuf);
11131 1.1 christos dns_db_detachnode(db, &node);
11132 1.1 christos SAVE(zdb, db);
11133 1.1 christos SAVE(zfname, fname);
11134 1.1 christos SAVE(zrdataset, rdataset);
11135 1.1 christos SAVE(zsigrdataset, sigrdataset);
11136 1.1 christos version = NULL;
11137 1.1 christos dns_db_attach(client->view->cachedb, &db);
11138 1.3 christos is_zone = false;
11139 1.1 christos goto db_find;
11140 1.1 christos }
11141 1.1 christos } else {
11142 1.9 christos result = dns_db_findzonecut(
11143 1.9 christos db, client->query.qname, client->query.dboptions,
11144 1.9 christos client->now, &node, fname, NULL, rdataset, sigrdataset);
11145 1.1 christos if (result == ISC_R_SUCCESS) {
11146 1.1 christos if (zfname != NULL &&
11147 1.16 christos !dns_name_issubdomain(fname, zfname))
11148 1.16 christos {
11149 1.1 christos /*
11150 1.1 christos * We found a zonecut in the cache, but our
11151 1.1 christos * zone delegation is better.
11152 1.1 christos */
11153 1.3 christos use_zone = true;
11154 1.1 christos }
11155 1.1 christos } else if (result == ISC_R_NOTFOUND && zfname != NULL) {
11156 1.1 christos /*
11157 1.1 christos * We didn't find anything in the cache, but we
11158 1.1 christos * have a zone delegation, so use it.
11159 1.1 christos */
11160 1.3 christos use_zone = true;
11161 1.1 christos } else {
11162 1.1 christos goto cleanup;
11163 1.1 christos }
11164 1.1 christos }
11165 1.1 christos
11166 1.1 christos if (use_zone) {
11167 1.3 christos ns_client_releasename(client, &fname);
11168 1.1 christos /*
11169 1.3 christos * We've already done ns_client_keepname() on
11170 1.1 christos * zfname, so we must set dbuf to NULL to
11171 1.1 christos * prevent query_addrrset() from trying to
11172 1.3 christos * call ns_client_keepname() again.
11173 1.1 christos */
11174 1.1 christos dbuf = NULL;
11175 1.3 christos ns_client_putrdataset(client, &rdataset);
11176 1.1 christos if (sigrdataset != NULL) {
11177 1.3 christos ns_client_putrdataset(client, &sigrdataset);
11178 1.1 christos }
11179 1.1 christos
11180 1.1 christos if (node != NULL) {
11181 1.1 christos dns_db_detachnode(db, &node);
11182 1.1 christos }
11183 1.1 christos dns_db_detach(&db);
11184 1.1 christos
11185 1.1 christos RESTORE(db, zdb);
11186 1.1 christos RESTORE(fname, zfname);
11187 1.1 christos RESTORE(rdataset, zrdataset);
11188 1.1 christos RESTORE(sigrdataset, zsigrdataset);
11189 1.1 christos }
11190 1.1 christos
11191 1.1 christos /*
11192 1.1 christos * Attempt to validate RRsets that are pending or that are glue.
11193 1.1 christos */
11194 1.1 christos if ((DNS_TRUST_PENDING(rdataset->trust) ||
11195 1.1 christos (sigrdataset != NULL && DNS_TRUST_PENDING(sigrdataset->trust))) &&
11196 1.1 christos !validate(client, db, fname, rdataset, sigrdataset) &&
11197 1.1 christos !PENDINGOK(client->query.dboptions))
11198 1.1 christos {
11199 1.1 christos goto cleanup;
11200 1.1 christos }
11201 1.1 christos
11202 1.1 christos if ((DNS_TRUST_GLUE(rdataset->trust) ||
11203 1.1 christos (sigrdataset != NULL && DNS_TRUST_GLUE(sigrdataset->trust))) &&
11204 1.1 christos !validate(client, db, fname, rdataset, sigrdataset) &&
11205 1.1 christos SECURE(client) && WANTDNSSEC(client))
11206 1.1 christos {
11207 1.1 christos goto cleanup;
11208 1.1 christos }
11209 1.1 christos
11210 1.1 christos /*
11211 1.1 christos * If the answer is secure only add NS records if they are secure
11212 1.1 christos * when the client may be looking for AD in the response.
11213 1.1 christos */
11214 1.1 christos if (SECURE(client) && (WANTDNSSEC(client) || WANTAD(client)) &&
11215 1.1 christos ((rdataset->trust != dns_trust_secure) ||
11216 1.9 christos (sigrdataset != NULL && sigrdataset->trust != dns_trust_secure)))
11217 1.1 christos {
11218 1.1 christos goto cleanup;
11219 1.1 christos }
11220 1.1 christos
11221 1.1 christos /*
11222 1.1 christos * If the client doesn't want DNSSEC we can discard the sigrdataset
11223 1.1 christos * now.
11224 1.1 christos */
11225 1.1 christos if (!WANTDNSSEC(client)) {
11226 1.3 christos ns_client_putrdataset(client, &sigrdataset);
11227 1.1 christos }
11228 1.1 christos
11229 1.3 christos query_addrrset(qctx, &fname, &rdataset, &sigrdataset, dbuf,
11230 1.1 christos DNS_SECTION_AUTHORITY);
11231 1.1 christos
11232 1.9 christos cleanup:
11233 1.1 christos if (rdataset != NULL) {
11234 1.3 christos ns_client_putrdataset(client, &rdataset);
11235 1.1 christos }
11236 1.1 christos if (sigrdataset != NULL) {
11237 1.3 christos ns_client_putrdataset(client, &sigrdataset);
11238 1.1 christos }
11239 1.1 christos if (fname != NULL) {
11240 1.3 christos ns_client_releasename(client, &fname);
11241 1.1 christos }
11242 1.1 christos if (node != NULL) {
11243 1.1 christos dns_db_detachnode(db, &node);
11244 1.1 christos }
11245 1.1 christos if (db != NULL) {
11246 1.1 christos dns_db_detach(&db);
11247 1.1 christos }
11248 1.1 christos if (zone != NULL) {
11249 1.1 christos dns_zone_detach(&zone);
11250 1.1 christos }
11251 1.1 christos if (zdb != NULL) {
11252 1.3 christos ns_client_putrdataset(client, &zrdataset);
11253 1.3 christos if (zsigrdataset != NULL) {
11254 1.3 christos ns_client_putrdataset(client, &zsigrdataset);
11255 1.3 christos }
11256 1.3 christos if (zfname != NULL) {
11257 1.3 christos ns_client_releasename(client, &zfname);
11258 1.3 christos }
11259 1.1 christos dns_db_detach(&zdb);
11260 1.1 christos }
11261 1.1 christos }
11262 1.1 christos
11263 1.1 christos static void
11264 1.9 christos query_addwildcardproof(query_ctx_t *qctx, bool ispositive, bool nodata) {
11265 1.1 christos ns_client_t *client = qctx->client;
11266 1.1 christos isc_buffer_t *dbuf, b;
11267 1.1 christos dns_name_t *name;
11268 1.1 christos dns_name_t *fname = NULL;
11269 1.1 christos dns_rdataset_t *rdataset = NULL, *sigrdataset = NULL;
11270 1.1 christos dns_fixedname_t wfixed;
11271 1.1 christos dns_name_t *wname;
11272 1.1 christos dns_dbnode_t *node = NULL;
11273 1.1 christos unsigned int options;
11274 1.1 christos unsigned int olabels, nlabels, labels;
11275 1.1 christos isc_result_t result;
11276 1.1 christos dns_rdata_t rdata = DNS_RDATA_INIT;
11277 1.1 christos dns_rdata_nsec_t nsec;
11278 1.3 christos bool have_wname;
11279 1.1 christos int order;
11280 1.1 christos dns_fixedname_t cfixed;
11281 1.1 christos dns_name_t *cname;
11282 1.1 christos dns_clientinfomethods_t cm;
11283 1.1 christos dns_clientinfo_t ci;
11284 1.1 christos
11285 1.1 christos CTRACE(ISC_LOG_DEBUG(3), "query_addwildcardproof");
11286 1.1 christos
11287 1.1 christos dns_clientinfomethods_init(&cm, ns_client_sourceip);
11288 1.20 christos dns_clientinfo_init(&ci, client, NULL);
11289 1.1 christos
11290 1.1 christos /*
11291 1.1 christos * If a name has been specifically flagged as needing
11292 1.1 christos * a wildcard proof then it will have been copied to
11293 1.1 christos * qctx->wildcardname. Otherwise we just use the client
11294 1.1 christos * QNAME.
11295 1.1 christos */
11296 1.1 christos if (qctx->need_wildcardproof) {
11297 1.1 christos name = dns_fixedname_name(&qctx->wildcardname);
11298 1.1 christos } else {
11299 1.1 christos name = client->query.qname;
11300 1.1 christos }
11301 1.1 christos
11302 1.1 christos /*
11303 1.1 christos * Get the NOQNAME proof then if !ispositive
11304 1.1 christos * get the NOWILDCARD proof.
11305 1.1 christos *
11306 1.1 christos * DNS_DBFIND_NOWILD finds the NSEC records that covers the
11307 1.1 christos * name ignoring any wildcard. From the owner and next names
11308 1.1 christos * of this record you can compute which wildcard (if it exists)
11309 1.1 christos * will match by finding the longest common suffix of the
11310 1.1 christos * owner name and next names with the qname and prefixing that
11311 1.1 christos * with the wildcard label.
11312 1.1 christos *
11313 1.1 christos * e.g.
11314 1.1 christos * Given:
11315 1.1 christos * example SOA
11316 1.1 christos * example NSEC b.example
11317 1.1 christos * b.example A
11318 1.1 christos * b.example NSEC a.d.example
11319 1.1 christos * a.d.example A
11320 1.1 christos * a.d.example NSEC g.f.example
11321 1.1 christos * g.f.example A
11322 1.1 christos * g.f.example NSEC z.i.example
11323 1.1 christos * z.i.example A
11324 1.1 christos * z.i.example NSEC example
11325 1.1 christos *
11326 1.1 christos * QNAME:
11327 1.1 christos * a.example -> example NSEC b.example
11328 1.1 christos * owner common example
11329 1.1 christos * next common example
11330 1.1 christos * wild *.example
11331 1.1 christos * d.b.example -> b.example NSEC a.d.example
11332 1.1 christos * owner common b.example
11333 1.1 christos * next common example
11334 1.1 christos * wild *.b.example
11335 1.1 christos * a.f.example -> a.d.example NSEC g.f.example
11336 1.1 christos * owner common example
11337 1.1 christos * next common f.example
11338 1.1 christos * wild *.f.example
11339 1.1 christos * j.example -> z.i.example NSEC example
11340 1.1 christos * owner common example
11341 1.1 christos * next common example
11342 1.1 christos * wild *.example
11343 1.1 christos */
11344 1.1 christos options = client->query.dboptions | DNS_DBFIND_NOWILD;
11345 1.1 christos wname = dns_fixedname_initname(&wfixed);
11346 1.9 christos again:
11347 1.3 christos have_wname = false;
11348 1.1 christos /*
11349 1.1 christos * We'll need some resources...
11350 1.1 christos */
11351 1.3 christos dbuf = ns_client_getnamebuf(client);
11352 1.3 christos fname = ns_client_newname(client, dbuf, &b);
11353 1.3 christos rdataset = ns_client_newrdataset(client);
11354 1.3 christos sigrdataset = ns_client_newrdataset(client);
11355 1.1 christos
11356 1.1 christos result = dns_db_findext(qctx->db, name, qctx->version,
11357 1.9 christos dns_rdatatype_nsec, options, 0, &node, fname,
11358 1.9 christos &cm, &ci, rdataset, sigrdataset);
11359 1.9 christos if (node != NULL) {
11360 1.1 christos dns_db_detachnode(qctx->db, &node);
11361 1.9 christos }
11362 1.1 christos
11363 1.1 christos if (!dns_rdataset_isassociated(rdataset)) {
11364 1.1 christos /*
11365 1.1 christos * No NSEC proof available, return NSEC3 proofs instead.
11366 1.1 christos */
11367 1.1 christos cname = dns_fixedname_initname(&cfixed);
11368 1.1 christos /*
11369 1.24 christos * Find the closest encloser.
11370 1.24 christos */
11371 1.20 christos dns_name_copy(name, cname);
11372 1.24 christos while (result == DNS_R_NXDOMAIN) {
11373 1.24 christos labels = dns_name_countlabels(cname) - 1;
11374 1.24 christos /*
11375 1.24 christos * Sanity check.
11376 1.24 christos */
11377 1.24 christos if (labels == 0U) {
11378 1.24 christos goto cleanup;
11379 1.9 christos }
11380 1.24 christos dns_name_split(cname, labels, NULL, cname);
11381 1.23 christos result = dns_db_findext(qctx->db, cname, qctx->version,
11382 1.23 christos dns_rdatatype_nsec, options, 0,
11383 1.23 christos NULL, fname, &cm, &ci, NULL,
11384 1.23 christos NULL);
11385 1.1 christos }
11386 1.1 christos /*
11387 1.1 christos * Add closest (provable) encloser NSEC3.
11388 1.1 christos */
11389 1.9 christos query_findclosestnsec3(cname, qctx->db, qctx->version, client,
11390 1.9 christos rdataset, sigrdataset, fname, true,
11391 1.9 christos cname);
11392 1.9 christos if (!dns_rdataset_isassociated(rdataset)) {
11393 1.1 christos goto cleanup;
11394 1.9 christos }
11395 1.9 christos if (!ispositive) {
11396 1.3 christos query_addrrset(qctx, &fname, &rdataset, &sigrdataset,
11397 1.1 christos dbuf, DNS_SECTION_AUTHORITY);
11398 1.9 christos }
11399 1.1 christos
11400 1.1 christos /*
11401 1.1 christos * Replace resources which were consumed by query_addrrset.
11402 1.1 christos */
11403 1.1 christos if (fname == NULL) {
11404 1.3 christos dbuf = ns_client_getnamebuf(client);
11405 1.3 christos fname = ns_client_newname(client, dbuf, &b);
11406 1.1 christos }
11407 1.1 christos
11408 1.9 christos if (rdataset == NULL) {
11409 1.3 christos rdataset = ns_client_newrdataset(client);
11410 1.9 christos } else if (dns_rdataset_isassociated(rdataset)) {
11411 1.1 christos dns_rdataset_disassociate(rdataset);
11412 1.9 christos }
11413 1.1 christos
11414 1.9 christos if (sigrdataset == NULL) {
11415 1.3 christos sigrdataset = ns_client_newrdataset(client);
11416 1.9 christos } else if (dns_rdataset_isassociated(sigrdataset)) {
11417 1.1 christos dns_rdataset_disassociate(sigrdataset);
11418 1.9 christos }
11419 1.1 christos
11420 1.1 christos /*
11421 1.1 christos * Add no qname proof.
11422 1.1 christos */
11423 1.1 christos labels = dns_name_countlabels(cname) + 1;
11424 1.9 christos if (dns_name_countlabels(name) == labels) {
11425 1.20 christos dns_name_copy(name, wname);
11426 1.9 christos } else {
11427 1.1 christos dns_name_split(name, labels, NULL, wname);
11428 1.9 christos }
11429 1.1 christos
11430 1.9 christos query_findclosestnsec3(wname, qctx->db, qctx->version, client,
11431 1.9 christos rdataset, sigrdataset, fname, false,
11432 1.9 christos NULL);
11433 1.9 christos if (!dns_rdataset_isassociated(rdataset)) {
11434 1.1 christos goto cleanup;
11435 1.9 christos }
11436 1.9 christos query_addrrset(qctx, &fname, &rdataset, &sigrdataset, dbuf,
11437 1.9 christos DNS_SECTION_AUTHORITY);
11438 1.1 christos
11439 1.9 christos if (ispositive) {
11440 1.1 christos goto cleanup;
11441 1.9 christos }
11442 1.1 christos
11443 1.1 christos /*
11444 1.1 christos * Replace resources which were consumed by query_addrrset.
11445 1.1 christos */
11446 1.1 christos if (fname == NULL) {
11447 1.3 christos dbuf = ns_client_getnamebuf(client);
11448 1.3 christos fname = ns_client_newname(client, dbuf, &b);
11449 1.1 christos }
11450 1.1 christos
11451 1.9 christos if (rdataset == NULL) {
11452 1.3 christos rdataset = ns_client_newrdataset(client);
11453 1.9 christos } else if (dns_rdataset_isassociated(rdataset)) {
11454 1.1 christos dns_rdataset_disassociate(rdataset);
11455 1.9 christos }
11456 1.1 christos
11457 1.9 christos if (sigrdataset == NULL) {
11458 1.3 christos sigrdataset = ns_client_newrdataset(client);
11459 1.9 christos } else if (dns_rdataset_isassociated(sigrdataset)) {
11460 1.1 christos dns_rdataset_disassociate(sigrdataset);
11461 1.9 christos }
11462 1.1 christos
11463 1.1 christos /*
11464 1.1 christos * Add the no wildcard proof.
11465 1.1 christos */
11466 1.9 christos result = dns_name_concatenate(dns_wildcardname, cname, wname,
11467 1.9 christos NULL);
11468 1.9 christos if (result != ISC_R_SUCCESS) {
11469 1.1 christos goto cleanup;
11470 1.9 christos }
11471 1.1 christos
11472 1.9 christos query_findclosestnsec3(wname, qctx->db, qctx->version, client,
11473 1.9 christos rdataset, sigrdataset, fname, nodata,
11474 1.9 christos NULL);
11475 1.9 christos if (!dns_rdataset_isassociated(rdataset)) {
11476 1.1 christos goto cleanup;
11477 1.9 christos }
11478 1.9 christos query_addrrset(qctx, &fname, &rdataset, &sigrdataset, dbuf,
11479 1.9 christos DNS_SECTION_AUTHORITY);
11480 1.1 christos
11481 1.1 christos goto cleanup;
11482 1.1 christos } else if (result == DNS_R_NXDOMAIN) {
11483 1.9 christos if (!ispositive) {
11484 1.1 christos result = dns_rdataset_first(rdataset);
11485 1.9 christos }
11486 1.1 christos if (result == ISC_R_SUCCESS) {
11487 1.1 christos dns_rdataset_current(rdataset, &rdata);
11488 1.1 christos result = dns_rdata_tostruct(&rdata, &nsec, NULL);
11489 1.3 christos RUNTIME_CHECK(result == ISC_R_SUCCESS);
11490 1.1 christos (void)dns_name_fullcompare(name, fname, &order,
11491 1.1 christos &olabels);
11492 1.1 christos (void)dns_name_fullcompare(name, &nsec.next, &order,
11493 1.1 christos &nlabels);
11494 1.1 christos /*
11495 1.1 christos * Check for a pathological condition created when
11496 1.1 christos * serving some malformed signed zones and bail out.
11497 1.1 christos */
11498 1.9 christos if (dns_name_countlabels(name) == nlabels) {
11499 1.1 christos goto cleanup;
11500 1.9 christos }
11501 1.1 christos
11502 1.9 christos if (olabels > nlabels) {
11503 1.1 christos dns_name_split(name, olabels, NULL, wname);
11504 1.9 christos } else {
11505 1.1 christos dns_name_split(name, nlabels, NULL, wname);
11506 1.9 christos }
11507 1.9 christos result = dns_name_concatenate(dns_wildcardname, wname,
11508 1.9 christos wname, NULL);
11509 1.9 christos if (result == ISC_R_SUCCESS) {
11510 1.3 christos have_wname = true;
11511 1.9 christos }
11512 1.1 christos dns_rdata_freestruct(&nsec);
11513 1.1 christos }
11514 1.9 christos query_addrrset(qctx, &fname, &rdataset, &sigrdataset, dbuf,
11515 1.9 christos DNS_SECTION_AUTHORITY);
11516 1.1 christos }
11517 1.3 christos if (rdataset != NULL) {
11518 1.3 christos ns_client_putrdataset(client, &rdataset);
11519 1.3 christos }
11520 1.3 christos if (sigrdataset != NULL) {
11521 1.3 christos ns_client_putrdataset(client, &sigrdataset);
11522 1.3 christos }
11523 1.3 christos if (fname != NULL) {
11524 1.3 christos ns_client_releasename(client, &fname);
11525 1.3 christos }
11526 1.1 christos if (have_wname) {
11527 1.9 christos ispositive = true; /* prevent loop */
11528 1.1 christos if (!dns_name_equal(name, wname)) {
11529 1.1 christos name = wname;
11530 1.1 christos goto again;
11531 1.1 christos }
11532 1.1 christos }
11533 1.9 christos cleanup:
11534 1.3 christos if (rdataset != NULL) {
11535 1.3 christos ns_client_putrdataset(client, &rdataset);
11536 1.3 christos }
11537 1.3 christos if (sigrdataset != NULL) {
11538 1.3 christos ns_client_putrdataset(client, &sigrdataset);
11539 1.3 christos }
11540 1.3 christos if (fname != NULL) {
11541 1.3 christos ns_client_releasename(client, &fname);
11542 1.3 christos }
11543 1.1 christos }
11544 1.1 christos
11545 1.1 christos /*%
11546 1.1 christos * Add NS records, and NSEC/NSEC3 wildcard proof records if needed,
11547 1.1 christos * to the authority section.
11548 1.1 christos */
11549 1.1 christos static void
11550 1.1 christos query_addauth(query_ctx_t *qctx) {
11551 1.1 christos CCTRACE(ISC_LOG_DEBUG(3), "query_addauth");
11552 1.1 christos /*
11553 1.1 christos * Add NS records to the authority section (if we haven't already
11554 1.1 christos * added them to the answer section).
11555 1.1 christos */
11556 1.1 christos if (!qctx->want_restart && !NOAUTHORITY(qctx->client)) {
11557 1.1 christos if (qctx->is_zone) {
11558 1.1 christos if (!qctx->answer_has_ns) {
11559 1.1 christos (void)query_addns(qctx);
11560 1.1 christos }
11561 1.1 christos } else if (!qctx->answer_has_ns &&
11562 1.16 christos qctx->qtype != dns_rdatatype_ns)
11563 1.16 christos {
11564 1.1 christos if (qctx->fname != NULL) {
11565 1.3 christos ns_client_releasename(qctx->client,
11566 1.3 christos &qctx->fname);
11567 1.1 christos }
11568 1.1 christos query_addbestns(qctx);
11569 1.1 christos }
11570 1.1 christos }
11571 1.1 christos
11572 1.1 christos /*
11573 1.1 christos * Add NSEC records to the authority section if they're needed for
11574 1.1 christos * DNSSEC wildcard proofs.
11575 1.1 christos */
11576 1.9 christos if (qctx->need_wildcardproof && dns_db_issecure(qctx->db)) {
11577 1.3 christos query_addwildcardproof(qctx, true, false);
11578 1.9 christos }
11579 1.1 christos }
11580 1.1 christos
11581 1.1 christos /*
11582 1.1 christos * Find the sort order of 'rdata' in the topology-like
11583 1.1 christos * ACL forming the second element in a 2-element top-level
11584 1.1 christos * sortlist statement.
11585 1.1 christos */
11586 1.1 christos static int
11587 1.1 christos query_sortlist_order_2element(const dns_rdata_t *rdata, const void *arg) {
11588 1.1 christos isc_netaddr_t netaddr;
11589 1.1 christos
11590 1.9 christos if (rdata_tonetaddr(rdata, &netaddr) != ISC_R_SUCCESS) {
11591 1.23 christos return INT_MAX;
11592 1.9 christos }
11593 1.23 christos return ns_sortlist_addrorder2(&netaddr, arg);
11594 1.1 christos }
11595 1.1 christos
11596 1.1 christos /*
11597 1.1 christos * Find the sort order of 'rdata' in the matching element
11598 1.1 christos * of a 1-element top-level sortlist statement.
11599 1.1 christos */
11600 1.1 christos static int
11601 1.1 christos query_sortlist_order_1element(const dns_rdata_t *rdata, const void *arg) {
11602 1.1 christos isc_netaddr_t netaddr;
11603 1.1 christos
11604 1.9 christos if (rdata_tonetaddr(rdata, &netaddr) != ISC_R_SUCCESS) {
11605 1.23 christos return INT_MAX;
11606 1.9 christos }
11607 1.23 christos return ns_sortlist_addrorder1(&netaddr, arg);
11608 1.1 christos }
11609 1.1 christos
11610 1.1 christos /*
11611 1.1 christos * Find the sortlist statement that applies to 'client' and set up
11612 1.1 christos * the sortlist info in in client->message appropriately.
11613 1.1 christos */
11614 1.1 christos static void
11615 1.1 christos query_setup_sortlist(query_ctx_t *qctx) {
11616 1.1 christos isc_netaddr_t netaddr;
11617 1.1 christos ns_client_t *client = qctx->client;
11618 1.20 christos dns_aclenv_t *env = client->manager->aclenv;
11619 1.20 christos dns_acl_t *acl = NULL;
11620 1.20 christos dns_aclelement_t *elt = NULL;
11621 1.20 christos void *order_arg = NULL;
11622 1.1 christos
11623 1.1 christos isc_netaddr_fromsockaddr(&netaddr, &client->peeraddr);
11624 1.9 christos switch (ns_sortlist_setup(client->view->sortlist, env, &netaddr,
11625 1.16 christos &order_arg))
11626 1.16 christos {
11627 1.1 christos case NS_SORTLISTTYPE_1ELEMENT:
11628 1.20 christos elt = order_arg;
11629 1.1 christos dns_message_setsortorder(client->message,
11630 1.9 christos query_sortlist_order_1element, env,
11631 1.20 christos NULL, elt);
11632 1.1 christos break;
11633 1.1 christos case NS_SORTLISTTYPE_2ELEMENT:
11634 1.20 christos acl = order_arg;
11635 1.1 christos dns_message_setsortorder(client->message,
11636 1.9 christos query_sortlist_order_2element, env,
11637 1.20 christos acl, NULL);
11638 1.20 christos dns_acl_detach(&acl);
11639 1.1 christos break;
11640 1.1 christos case NS_SORTLISTTYPE_NONE:
11641 1.1 christos break;
11642 1.1 christos default:
11643 1.15 christos UNREACHABLE();
11644 1.1 christos }
11645 1.1 christos }
11646 1.1 christos
11647 1.1 christos /*
11648 1.1 christos * When sending a referral, if the answer to the question is
11649 1.1 christos * in the glue, sort it to the start of the additional section.
11650 1.1 christos */
11651 1.15 christos static void
11652 1.1 christos query_glueanswer(query_ctx_t *qctx) {
11653 1.1 christos const dns_namelist_t *secs = qctx->client->message->sections;
11654 1.1 christos const dns_section_t section = DNS_SECTION_ADDITIONAL;
11655 1.1 christos dns_name_t *name;
11656 1.1 christos dns_message_t *msg;
11657 1.1 christos dns_rdataset_t *rdataset = NULL;
11658 1.1 christos
11659 1.1 christos if (!ISC_LIST_EMPTY(secs[DNS_SECTION_ANSWER]) ||
11660 1.1 christos qctx->client->message->rcode != dns_rcode_noerror ||
11661 1.1 christos (qctx->qtype != dns_rdatatype_a &&
11662 1.1 christos qctx->qtype != dns_rdatatype_aaaa))
11663 1.1 christos {
11664 1.1 christos return;
11665 1.1 christos }
11666 1.1 christos
11667 1.1 christos msg = qctx->client->message;
11668 1.9 christos for (name = ISC_LIST_HEAD(msg->sections[section]); name != NULL;
11669 1.1 christos name = ISC_LIST_NEXT(name, link))
11670 1.9 christos {
11671 1.1 christos if (dns_name_equal(name, qctx->client->query.qname)) {
11672 1.1 christos for (rdataset = ISC_LIST_HEAD(name->list);
11673 1.1 christos rdataset != NULL;
11674 1.1 christos rdataset = ISC_LIST_NEXT(rdataset, link))
11675 1.9 christos {
11676 1.9 christos if (rdataset->type == qctx->qtype) {
11677 1.1 christos break;
11678 1.9 christos }
11679 1.9 christos }
11680 1.1 christos break;
11681 1.1 christos }
11682 1.9 christos }
11683 1.1 christos if (rdataset != NULL) {
11684 1.1 christos ISC_LIST_UNLINK(msg->sections[section], name, link);
11685 1.1 christos ISC_LIST_PREPEND(msg->sections[section], name, link);
11686 1.1 christos ISC_LIST_UNLINK(name->list, rdataset, link);
11687 1.1 christos ISC_LIST_PREPEND(name->list, rdataset, link);
11688 1.1 christos rdataset->attributes |= DNS_RDATASETATTR_REQUIRED;
11689 1.1 christos }
11690 1.1 christos }
11691 1.1 christos
11692 1.3 christos isc_result_t
11693 1.3 christos ns_query_done(query_ctx_t *qctx) {
11694 1.20 christos isc_result_t result = ISC_R_UNSET;
11695 1.1 christos const dns_namelist_t *secs = qctx->client->message->sections;
11696 1.23 christos bool partial_result_with_servfail = false;
11697 1.1 christos
11698 1.3 christos CCTRACE(ISC_LOG_DEBUG(3), "ns_query_done");
11699 1.3 christos
11700 1.3 christos CALL_HOOK(NS_QUERY_DONE_BEGIN, qctx);
11701 1.1 christos
11702 1.1 christos /*
11703 1.1 christos * General cleanup.
11704 1.1 christos */
11705 1.1 christos qctx->rpz_st = qctx->client->query.rpz_st;
11706 1.1 christos if (qctx->rpz_st != NULL &&
11707 1.16 christos (qctx->rpz_st->state & DNS_RPZ_RECURSING) == 0)
11708 1.16 christos {
11709 1.1 christos rpz_match_clear(qctx->rpz_st);
11710 1.1 christos qctx->rpz_st->state &= ~DNS_RPZ_DONE_QNAME;
11711 1.1 christos }
11712 1.1 christos
11713 1.1 christos qctx_clean(qctx);
11714 1.1 christos qctx_freedata(qctx);
11715 1.1 christos
11716 1.1 christos /*
11717 1.1 christos * Clear the AA bit if we're not authoritative.
11718 1.1 christos */
11719 1.1 christos if (qctx->client->query.restarts == 0 && !qctx->authoritative) {
11720 1.1 christos qctx->client->message->flags &= ~DNS_MESSAGEFLAG_AA;
11721 1.1 christos }
11722 1.1 christos
11723 1.1 christos /*
11724 1.1 christos * Do we need to restart the query (e.g. for CNAME chaining)?
11725 1.1 christos */
11726 1.22 christos if (qctx->want_restart) {
11727 1.22 christos if (qctx->client->query.restarts <
11728 1.22 christos qctx->client->view->max_restarts)
11729 1.22 christos {
11730 1.23 christos query_ctx_t *saved_qctx = NULL;
11731 1.22 christos qctx->client->query.restarts++;
11732 1.23 christos saved_qctx = isc_mem_get(qctx->client->manager->mctx,
11733 1.23 christos sizeof(*saved_qctx));
11734 1.23 christos qctx_save(qctx, saved_qctx);
11735 1.23 christos isc_nmhandle_attach(qctx->client->handle,
11736 1.23 christos &qctx->client->restarthandle);
11737 1.23 christos isc_async_run(qctx->client->manager->loop,
11738 1.23 christos async_restart, saved_qctx);
11739 1.23 christos return DNS_R_CONTINUE;
11740 1.22 christos } else {
11741 1.22 christos /*
11742 1.22 christos * This is e.g. a long CNAME chain which we cut short.
11743 1.22 christos */
11744 1.22 christos qctx->client->query.attributes |=
11745 1.22 christos NS_QUERYATTR_PARTIALANSWER;
11746 1.22 christos qctx->client->message->rcode = dns_rcode_servfail;
11747 1.22 christos qctx->result = DNS_R_SERVFAIL;
11748 1.22 christos
11749 1.22 christos /*
11750 1.22 christos * Send the answer back with a SERVFAIL result even
11751 1.22 christos * if recursion was requested.
11752 1.22 christos */
11753 1.22 christos partial_result_with_servfail = true;
11754 1.22 christos
11755 1.24 christos dns_ede_add(&qctx->client->edectx, DNS_EDE_OTHER,
11756 1.24 christos "max. restarts reached");
11757 1.22 christos ns_client_log(qctx->client, NS_LOGCATEGORY_CLIENT,
11758 1.22 christos NS_LOGMODULE_QUERY, ISC_LOG_INFO,
11759 1.22 christos "query iterations limit reached");
11760 1.22 christos }
11761 1.1 christos }
11762 1.1 christos
11763 1.1 christos if (qctx->result != ISC_R_SUCCESS &&
11764 1.22 christos (!PARTIALANSWER(qctx->client) ||
11765 1.22 christos (WANTRECURSION(qctx->client) && !partial_result_with_servfail) ||
11766 1.1 christos qctx->result == DNS_R_DROP))
11767 1.1 christos {
11768 1.1 christos if (qctx->result == DNS_R_DUPLICATE ||
11769 1.16 christos qctx->result == DNS_R_DROP)
11770 1.16 christos {
11771 1.1 christos /*
11772 1.1 christos * This was a duplicate query that we are
11773 1.1 christos * recursing on or the result of rate limiting.
11774 1.1 christos * Don't send a response now for a duplicate query,
11775 1.1 christos * because the original will still cause a response.
11776 1.1 christos */
11777 1.1 christos query_next(qctx->client, qctx->result);
11778 1.1 christos } else {
11779 1.1 christos /*
11780 1.1 christos * If we don't have any answer to give the client,
11781 1.1 christos * or if the client requested recursion and thus wanted
11782 1.1 christos * the complete answer, send an error response.
11783 1.1 christos */
11784 1.1 christos INSIST(qctx->line >= 0);
11785 1.1 christos query_error(qctx->client, qctx->result, qctx->line);
11786 1.1 christos }
11787 1.1 christos
11788 1.3 christos qctx->detach_client = true;
11789 1.23 christos return qctx->result;
11790 1.1 christos }
11791 1.1 christos
11792 1.1 christos /*
11793 1.1 christos * If we're recursing then just return; the query will
11794 1.1 christos * resume when recursion ends.
11795 1.1 christos */
11796 1.11 christos if (RECURSING(qctx->client) &&
11797 1.13 christos (!QUERY_STALETIMEOUT(&qctx->client->query) ||
11798 1.23 christos qctx->options.stalefirst))
11799 1.11 christos {
11800 1.23 christos return qctx->result;
11801 1.1 christos }
11802 1.1 christos
11803 1.1 christos /*
11804 1.1 christos * We are done. Set up sortlist data for the message
11805 1.1 christos * rendering code, sort the answer to the front of the
11806 1.1 christos * additional section if necessary, make a final tweak
11807 1.1 christos * to the AA bit if the auth-nxdomain config option
11808 1.1 christos * says so, then render and send the response.
11809 1.1 christos */
11810 1.13 christos query_setup_sortlist(qctx);
11811 1.13 christos query_glueanswer(qctx);
11812 1.1 christos
11813 1.1 christos if (qctx->client->message->rcode == dns_rcode_nxdomain &&
11814 1.10 christos qctx->view->auth_nxdomain)
11815 1.1 christos {
11816 1.1 christos qctx->client->message->flags |= DNS_MESSAGEFLAG_AA;
11817 1.1 christos }
11818 1.1 christos
11819 1.1 christos /*
11820 1.1 christos * If the response is somehow unexpected for the client and this
11821 1.1 christos * is a result of recursion, return an error to the caller
11822 1.1 christos * to indicate it may need to be logged.
11823 1.1 christos */
11824 1.1 christos if (qctx->resuming &&
11825 1.1 christos (ISC_LIST_EMPTY(secs[DNS_SECTION_ANSWER]) ||
11826 1.1 christos qctx->client->message->rcode != dns_rcode_noerror))
11827 1.1 christos {
11828 1.1 christos qctx->result = ISC_R_FAILURE;
11829 1.1 christos }
11830 1.1 christos
11831 1.3 christos CALL_HOOK(NS_QUERY_DONE_SEND, qctx);
11832 1.3 christos
11833 1.1 christos query_send(qctx->client);
11834 1.15 christos
11835 1.15 christos if (qctx->refresh_rrset) {
11836 1.15 christos /*
11837 1.15 christos * If we reached this point then it means that we have found a
11838 1.15 christos * stale RRset entry in cache and BIND is configured to allow
11839 1.15 christos * queries to be answered with stale data if no active RRset
11840 1.15 christos * is available, i.e. "stale-anwer-client-timeout 0". But, we
11841 1.15 christos * still need to refresh the RRset. To prevent adding duplicate
11842 1.15 christos * RRsets, clear the RRsets from the message before doing the
11843 1.15 christos * refresh.
11844 1.15 christos */
11845 1.15 christos message_clearrdataset(qctx->client->message, 0);
11846 1.23 christos query_stale_refresh(qctx->client);
11847 1.15 christos }
11848 1.15 christos
11849 1.23 christos qctx->detach_client = true;
11850 1.23 christos
11851 1.23 christos return qctx->result;
11852 1.3 christos
11853 1.9 christos cleanup:
11854 1.24 christos /*
11855 1.24 christos * We'd only get here if one of the hooks above
11856 1.24 christos * (NS_QUERY_DONE_BEGIN or NS_QUERY_DONE_SEND) returned
11857 1.24 christos * NS_HOOK_RETURN. Some housekeeping may be needed.
11858 1.24 christos */
11859 1.24 christos qctx_clean(qctx);
11860 1.24 christos qctx_freedata(qctx);
11861 1.24 christos if (!qctx->async) {
11862 1.24 christos qctx->detach_client = true;
11863 1.24 christos query_error(qctx->client, DNS_R_SERVFAIL, __LINE__);
11864 1.24 christos }
11865 1.23 christos return result;
11866 1.1 christos }
11867 1.1 christos
11868 1.15 christos static void
11869 1.1 christos log_tat(ns_client_t *client) {
11870 1.1 christos char namebuf[DNS_NAME_FORMATSIZE];
11871 1.1 christos char clientbuf[ISC_NETADDR_FORMATSIZE];
11872 1.3 christos char classbuf[DNS_RDATACLASS_FORMATSIZE];
11873 1.1 christos isc_netaddr_t netaddr;
11874 1.1 christos char *tags = NULL;
11875 1.1 christos size_t taglen = 0;
11876 1.1 christos
11877 1.1 christos if (!isc_log_wouldlog(ns_lctx, ISC_LOG_INFO)) {
11878 1.1 christos return;
11879 1.1 christos }
11880 1.1 christos
11881 1.1 christos if ((client->query.qtype != dns_rdatatype_null ||
11882 1.1 christos !dns_name_istat(client->query.qname)) &&
11883 1.1 christos (client->keytag == NULL ||
11884 1.1 christos client->query.qtype != dns_rdatatype_dnskey))
11885 1.1 christos {
11886 1.1 christos return;
11887 1.1 christos }
11888 1.1 christos
11889 1.1 christos isc_netaddr_fromsockaddr(&netaddr, &client->peeraddr);
11890 1.1 christos dns_name_format(client->query.qname, namebuf, sizeof(namebuf));
11891 1.3 christos isc_netaddr_format(&netaddr, clientbuf, sizeof(clientbuf));
11892 1.3 christos dns_rdataclass_format(client->view->rdclass, classbuf,
11893 1.3 christos sizeof(classbuf));
11894 1.1 christos
11895 1.1 christos if (client->query.qtype == dns_rdatatype_dnskey) {
11896 1.3 christos uint16_t keytags = client->keytag_len / 2;
11897 1.1 christos size_t len = taglen = sizeof("65000") * keytags + 1;
11898 1.23 christos char *cp = tags = isc_mem_get(client->manager->mctx, taglen);
11899 1.1 christos int i = 0;
11900 1.1 christos
11901 1.1 christos INSIST(client->keytag != NULL);
11902 1.1 christos if (tags != NULL) {
11903 1.1 christos while (keytags-- > 0U) {
11904 1.1 christos int n;
11905 1.3 christos uint16_t keytag;
11906 1.1 christos keytag = (client->keytag[i * 2] << 8) |
11907 1.1 christos client->keytag[i * 2 + 1];
11908 1.1 christos n = snprintf(cp, len, " %u", keytag);
11909 1.1 christos if (n > 0 && (size_t)n <= len) {
11910 1.1 christos cp += n;
11911 1.1 christos len -= n;
11912 1.1 christos i++;
11913 1.1 christos } else {
11914 1.1 christos break;
11915 1.1 christos }
11916 1.1 christos }
11917 1.1 christos }
11918 1.1 christos }
11919 1.1 christos
11920 1.1 christos isc_log_write(ns_lctx, NS_LOGCATEGORY_TAT, NS_LOGMODULE_QUERY,
11921 1.1 christos ISC_LOG_INFO, "trust-anchor-telemetry '%s/%s' from %s%s",
11922 1.9 christos namebuf, classbuf, clientbuf, tags != NULL ? tags : "");
11923 1.1 christos if (tags != NULL) {
11924 1.23 christos isc_mem_put(client->manager->mctx, tags, taglen);
11925 1.1 christos }
11926 1.1 christos }
11927 1.1 christos
11928 1.15 christos static void
11929 1.1 christos log_query(ns_client_t *client, unsigned int flags, unsigned int extflags) {
11930 1.1 christos char namebuf[DNS_NAME_FORMATSIZE];
11931 1.3 christos char typebuf[DNS_RDATATYPE_FORMATSIZE];
11932 1.3 christos char classbuf[DNS_RDATACLASS_FORMATSIZE];
11933 1.1 christos char onbuf[ISC_NETADDR_FORMATSIZE];
11934 1.23 christos char ecsbuf[NS_CLIENT_ECS_FORMATSIZE] = { 0 };
11935 1.23 christos char flagsbuf[NS_CLIENT_FLAGS_FORMATSIZE] = { 0 };
11936 1.1 christos dns_rdataset_t *rdataset;
11937 1.1 christos int level = ISC_LOG_INFO;
11938 1.1 christos
11939 1.9 christos if (!isc_log_wouldlog(ns_lctx, level)) {
11940 1.1 christos return;
11941 1.9 christos }
11942 1.1 christos
11943 1.1 christos rdataset = ISC_LIST_HEAD(client->query.qname->list);
11944 1.1 christos INSIST(rdataset != NULL);
11945 1.1 christos dns_name_format(client->query.qname, namebuf, sizeof(namebuf));
11946 1.3 christos dns_rdataclass_format(rdataset->rdclass, classbuf, sizeof(classbuf));
11947 1.3 christos dns_rdatatype_format(rdataset->type, typebuf, sizeof(typebuf));
11948 1.1 christos isc_netaddr_format(&client->destaddr, onbuf, sizeof(onbuf));
11949 1.1 christos
11950 1.1 christos if (HAVEECS(client)) {
11951 1.23 christos ns_client_log_ecs(client, ecsbuf, sizeof(ecsbuf));
11952 1.1 christos }
11953 1.23 christos ns_client_log_flags(client, flags, extflags, flagsbuf,
11954 1.23 christos sizeof(flagsbuf));
11955 1.1 christos
11956 1.9 christos ns_client_log(client, NS_LOGCATEGORY_QUERIES, NS_LOGMODULE_QUERY, level,
11957 1.23 christos "query: %s %s %s %s (%s)%s", namebuf, classbuf, typebuf,
11958 1.23 christos flagsbuf, onbuf, ecsbuf);
11959 1.1 christos }
11960 1.1 christos
11961 1.15 christos static void
11962 1.1 christos log_queryerror(ns_client_t *client, isc_result_t result, int line, int level) {
11963 1.1 christos char namebuf[DNS_NAME_FORMATSIZE];
11964 1.3 christos char typebuf[DNS_RDATATYPE_FORMATSIZE];
11965 1.3 christos char classbuf[DNS_RDATACLASS_FORMATSIZE];
11966 1.1 christos const char *namep, *typep, *classp, *sep1, *sep2;
11967 1.1 christos dns_rdataset_t *rdataset;
11968 1.1 christos
11969 1.9 christos if (!isc_log_wouldlog(ns_lctx, level)) {
11970 1.1 christos return;
11971 1.9 christos }
11972 1.1 christos
11973 1.1 christos namep = typep = classp = sep1 = sep2 = "";
11974 1.1 christos
11975 1.1 christos /*
11976 1.1 christos * Query errors can happen for various reasons. In some cases we cannot
11977 1.1 christos * even assume the query contains a valid question section, so we should
11978 1.1 christos * expect exceptional cases.
11979 1.1 christos */
11980 1.1 christos if (client->query.origqname != NULL) {
11981 1.1 christos dns_name_format(client->query.origqname, namebuf,
11982 1.1 christos sizeof(namebuf));
11983 1.1 christos namep = namebuf;
11984 1.1 christos sep1 = " for ";
11985 1.1 christos
11986 1.1 christos rdataset = ISC_LIST_HEAD(client->query.origqname->list);
11987 1.1 christos if (rdataset != NULL) {
11988 1.3 christos dns_rdataclass_format(rdataset->rdclass, classbuf,
11989 1.3 christos sizeof(classbuf));
11990 1.3 christos classp = classbuf;
11991 1.3 christos dns_rdatatype_format(rdataset->type, typebuf,
11992 1.3 christos sizeof(typebuf));
11993 1.3 christos typep = typebuf;
11994 1.1 christos sep2 = "/";
11995 1.1 christos }
11996 1.1 christos }
11997 1.1 christos
11998 1.1 christos ns_client_log(client, NS_LOGCATEGORY_QUERY_ERRORS, NS_LOGMODULE_QUERY,
11999 1.1 christos level, "query failed (%s)%s%s%s%s%s%s at %s:%d",
12000 1.9 christos isc_result_totext(result), sep1, namep, sep2, classp,
12001 1.9 christos sep2, typep, __FILE__, line);
12002 1.1 christos }
12003 1.1 christos
12004 1.1 christos void
12005 1.11 christos ns_query_start(ns_client_t *client, isc_nmhandle_t *handle) {
12006 1.1 christos isc_result_t result;
12007 1.8 christos dns_message_t *message;
12008 1.1 christos dns_rdataset_t *rdataset;
12009 1.1 christos dns_rdatatype_t qtype;
12010 1.8 christos unsigned int saved_extflags;
12011 1.8 christos unsigned int saved_flags;
12012 1.1 christos
12013 1.1 christos REQUIRE(NS_CLIENT_VALID(client));
12014 1.1 christos
12015 1.11 christos /*
12016 1.11 christos * Attach to the request handle
12017 1.11 christos */
12018 1.11 christos isc_nmhandle_attach(handle, &client->reqhandle);
12019 1.11 christos
12020 1.8 christos message = client->message;
12021 1.8 christos saved_extflags = client->extflags;
12022 1.8 christos saved_flags = client->message->flags;
12023 1.8 christos
12024 1.1 christos CTRACE(ISC_LOG_DEBUG(3), "ns_query_start");
12025 1.1 christos
12026 1.1 christos /*
12027 1.1 christos * Ensure that appropriate cleanups occur.
12028 1.1 christos */
12029 1.9 christos client->cleanup = query_cleanup;
12030 1.1 christos
12031 1.9 christos if ((message->flags & DNS_MESSAGEFLAG_RD) != 0) {
12032 1.9 christos client->query.attributes |= NS_QUERYATTR_WANTRECURSION;
12033 1.1 christos }
12034 1.1 christos
12035 1.9 christos if ((client->extflags & DNS_MESSAGEEXTFLAG_DO) != 0) {
12036 1.1 christos client->attributes |= NS_CLIENTATTR_WANTDNSSEC;
12037 1.9 christos }
12038 1.1 christos
12039 1.1 christos switch (client->view->minimalresponses) {
12040 1.1 christos case dns_minimal_no:
12041 1.1 christos break;
12042 1.1 christos case dns_minimal_yes:
12043 1.1 christos client->query.attributes |= (NS_QUERYATTR_NOAUTHORITY |
12044 1.1 christos NS_QUERYATTR_NOADDITIONAL);
12045 1.1 christos break;
12046 1.1 christos case dns_minimal_noauth:
12047 1.1 christos client->query.attributes |= NS_QUERYATTR_NOAUTHORITY;
12048 1.1 christos break;
12049 1.1 christos case dns_minimal_noauthrec:
12050 1.9 christos if ((message->flags & DNS_MESSAGEFLAG_RD) != 0) {
12051 1.1 christos client->query.attributes |= NS_QUERYATTR_NOAUTHORITY;
12052 1.9 christos }
12053 1.1 christos break;
12054 1.1 christos }
12055 1.1 christos
12056 1.1 christos if (client->view->cachedb == NULL || !client->view->recursion) {
12057 1.1 christos /*
12058 1.1 christos * We don't have a cache. Turn off cache support and
12059 1.1 christos * recursion.
12060 1.1 christos */
12061 1.9 christos client->query.attributes &= ~(NS_QUERYATTR_RECURSIONOK |
12062 1.9 christos NS_QUERYATTR_CACHEOK);
12063 1.1 christos client->attributes |= NS_CLIENTATTR_NOSETFC;
12064 1.1 christos } else if ((client->attributes & NS_CLIENTATTR_RA) == 0 ||
12065 1.9 christos (message->flags & DNS_MESSAGEFLAG_RD) == 0)
12066 1.9 christos {
12067 1.1 christos /*
12068 1.1 christos * If the client isn't allowed to recurse (due to
12069 1.1 christos * "recursion no", the allow-recursion ACL, or the
12070 1.1 christos * lack of a resolver in this view), or if it
12071 1.1 christos * doesn't want recursion, turn recursion off.
12072 1.1 christos */
12073 1.1 christos client->query.attributes &= ~NS_QUERYATTR_RECURSIONOK;
12074 1.1 christos client->attributes |= NS_CLIENTATTR_NOSETFC;
12075 1.1 christos }
12076 1.1 christos
12077 1.1 christos /*
12078 1.1 christos * Check for multiple question queries, since edns1 is dead.
12079 1.1 christos */
12080 1.1 christos if (message->counts[DNS_SECTION_QUESTION] > 1) {
12081 1.1 christos query_error(client, DNS_R_FORMERR, __LINE__);
12082 1.1 christos return;
12083 1.1 christos }
12084 1.1 christos
12085 1.1 christos /*
12086 1.1 christos * Get the question name.
12087 1.1 christos */
12088 1.1 christos result = dns_message_firstname(message, DNS_SECTION_QUESTION);
12089 1.1 christos if (result != ISC_R_SUCCESS) {
12090 1.1 christos query_error(client, result, __LINE__);
12091 1.1 christos return;
12092 1.1 christos }
12093 1.1 christos dns_message_currentname(message, DNS_SECTION_QUESTION,
12094 1.1 christos &client->query.qname);
12095 1.1 christos client->query.origqname = client->query.qname;
12096 1.1 christos result = dns_message_nextname(message, DNS_SECTION_QUESTION);
12097 1.1 christos if (result != ISC_R_NOMORE) {
12098 1.1 christos if (result == ISC_R_SUCCESS) {
12099 1.1 christos /*
12100 1.1 christos * There's more than one QNAME in the question
12101 1.1 christos * section.
12102 1.1 christos */
12103 1.1 christos query_error(client, DNS_R_FORMERR, __LINE__);
12104 1.9 christos } else {
12105 1.1 christos query_error(client, result, __LINE__);
12106 1.9 christos }
12107 1.1 christos return;
12108 1.1 christos }
12109 1.1 christos
12110 1.23 christos if ((client->manager->sctx->options & NS_SERVER_LOGQUERIES) != 0) {
12111 1.1 christos log_query(client, saved_flags, saved_extflags);
12112 1.9 christos }
12113 1.1 christos
12114 1.1 christos /*
12115 1.1 christos * Check for meta-queries like IXFR and AXFR.
12116 1.1 christos */
12117 1.1 christos rdataset = ISC_LIST_HEAD(client->query.qname->list);
12118 1.1 christos INSIST(rdataset != NULL);
12119 1.1 christos client->query.qtype = qtype = rdataset->type;
12120 1.23 christos dns_rdatatypestats_increment(client->manager->sctx->rcvquerystats,
12121 1.23 christos qtype);
12122 1.1 christos
12123 1.1 christos log_tat(client);
12124 1.1 christos
12125 1.1 christos if (dns_rdatatype_ismeta(qtype)) {
12126 1.1 christos switch (qtype) {
12127 1.1 christos case dns_rdatatype_any:
12128 1.1 christos break; /* Let the query logic handle it. */
12129 1.1 christos case dns_rdatatype_ixfr:
12130 1.1 christos case dns_rdatatype_axfr:
12131 1.20 christos if (isc_nm_is_http_handle(handle)) {
12132 1.20 christos /*
12133 1.20 christos * We cannot use DoH for zone transfers.
12134 1.20 christos * According to RFC 8484 a DoH request contains
12135 1.20 christos * exactly one DNS message (see Section 6:
12136 1.20 christos * Definition of the "application/dns-message"
12137 1.20 christos * Media Type).
12138 1.20 christos *
12139 1.20 christos * This makes DoH unsuitable for zone transfers
12140 1.20 christos * as often (and usually!) these need more than
12141 1.20 christos * one DNS message, especially for larger zones.
12142 1.20 christos * As zone transfers over DoH are not (yet)
12143 1.20 christos * standardised, nor discussed in RFC 8484,
12144 1.20 christos * the best thing we can do is to return "not
12145 1.20 christos * implemented".
12146 1.20 christos */
12147 1.20 christos query_error(client, DNS_R_NOTIMP, __LINE__);
12148 1.20 christos return;
12149 1.20 christos }
12150 1.23 christos if (isc_nm_socket_type(handle) ==
12151 1.23 christos isc_nm_streamdnssocket)
12152 1.23 christos {
12153 1.20 christos /*
12154 1.20 christos * Currently this code is here for DoT, which
12155 1.20 christos * has more complex requirements for zone
12156 1.20 christos * transfers compared to other stream
12157 1.20 christos * protocols. See RFC 9103 for details.
12158 1.20 christos */
12159 1.20 christos switch (isc_nm_xfr_checkperm(handle)) {
12160 1.20 christos case ISC_R_SUCCESS:
12161 1.20 christos break;
12162 1.20 christos case ISC_R_DOTALPNERROR:
12163 1.20 christos query_error(client, DNS_R_NOALPN,
12164 1.20 christos __LINE__);
12165 1.20 christos return;
12166 1.20 christos default:
12167 1.20 christos query_error(client, DNS_R_REFUSED,
12168 1.20 christos __LINE__);
12169 1.20 christos return;
12170 1.20 christos }
12171 1.20 christos }
12172 1.1 christos ns_xfr_start(client, rdataset->type);
12173 1.1 christos return;
12174 1.1 christos case dns_rdatatype_maila:
12175 1.1 christos case dns_rdatatype_mailb:
12176 1.1 christos query_error(client, DNS_R_NOTIMP, __LINE__);
12177 1.1 christos return;
12178 1.1 christos case dns_rdatatype_tkey:
12179 1.9 christos result = dns_tkey_processquery(
12180 1.23 christos client->message, client->manager->sctx->tkeyctx,
12181 1.9 christos client->view->dynamickeys);
12182 1.9 christos if (result == ISC_R_SUCCESS) {
12183 1.1 christos query_send(client);
12184 1.9 christos } else {
12185 1.1 christos query_error(client, result, __LINE__);
12186 1.9 christos }
12187 1.1 christos return;
12188 1.1 christos default: /* TSIG, etc. */
12189 1.1 christos query_error(client, DNS_R_FORMERR, __LINE__);
12190 1.1 christos return;
12191 1.1 christos }
12192 1.1 christos }
12193 1.1 christos
12194 1.1 christos /*
12195 1.1 christos * Turn on minimal response for (C)DNSKEY and (C)DS queries.
12196 1.1 christos */
12197 1.22 christos if (dns_rdatatype_iskeymaterial(qtype) || qtype == dns_rdatatype_ds) {
12198 1.1 christos client->query.attributes |= (NS_QUERYATTR_NOAUTHORITY |
12199 1.1 christos NS_QUERYATTR_NOADDITIONAL);
12200 1.11 christos } else if (qtype == dns_rdatatype_ns) {
12201 1.11 christos /*
12202 1.11 christos * Always turn on additional records for NS queries.
12203 1.11 christos */
12204 1.11 christos client->query.attributes &= ~(NS_QUERYATTR_NOAUTHORITY |
12205 1.11 christos NS_QUERYATTR_NOADDITIONAL);
12206 1.1 christos }
12207 1.1 christos
12208 1.1 christos /*
12209 1.1 christos * Maybe turn on minimal responses for ANY queries.
12210 1.1 christos */
12211 1.9 christos if (qtype == dns_rdatatype_any && client->view->minimal_any &&
12212 1.16 christos !TCP(client))
12213 1.16 christos {
12214 1.1 christos client->query.attributes |= (NS_QUERYATTR_NOAUTHORITY |
12215 1.1 christos NS_QUERYATTR_NOADDITIONAL);
12216 1.9 christos }
12217 1.1 christos
12218 1.1 christos /*
12219 1.1 christos * Turn on minimal responses for EDNS/UDP bufsize 512 queries.
12220 1.1 christos */
12221 1.1 christos if (client->ednsversion >= 0 && client->udpsize <= 512U && !TCP(client))
12222 1.9 christos {
12223 1.1 christos client->query.attributes |= (NS_QUERYATTR_NOAUTHORITY |
12224 1.1 christos NS_QUERYATTR_NOADDITIONAL);
12225 1.9 christos }
12226 1.1 christos
12227 1.1 christos /*
12228 1.1 christos * If the client has requested that DNSSEC checking be disabled,
12229 1.1 christos * allow lookups to return pending data and instruct the resolver
12230 1.1 christos * to return data before validation has completed.
12231 1.1 christos *
12232 1.1 christos * We don't need to set DNS_DBFIND_PENDINGOK when validation is
12233 1.1 christos * disabled as there will be no pending data.
12234 1.1 christos */
12235 1.3 christos if ((message->flags & DNS_MESSAGEFLAG_CD) != 0 ||
12236 1.16 christos qtype == dns_rdatatype_rrsig)
12237 1.16 christos {
12238 1.1 christos client->query.dboptions |= DNS_DBFIND_PENDINGOK;
12239 1.1 christos client->query.fetchoptions |= DNS_FETCHOPT_NOVALIDATE;
12240 1.9 christos } else if (!client->view->enablevalidation) {
12241 1.1 christos client->query.fetchoptions |= DNS_FETCHOPT_NOVALIDATE;
12242 1.9 christos }
12243 1.1 christos
12244 1.3 christos if (client->view->qminimization) {
12245 1.3 christos client->query.fetchoptions |= DNS_FETCHOPT_QMINIMIZE |
12246 1.9 christos DNS_FETCHOPT_QMIN_SKIP_IP6A;
12247 1.3 christos if (client->view->qmin_strict) {
12248 1.3 christos client->query.fetchoptions |= DNS_FETCHOPT_QMIN_STRICT;
12249 1.3 christos }
12250 1.3 christos }
12251 1.3 christos
12252 1.1 christos /*
12253 1.1 christos * Allow glue NS records to be added to the authority section
12254 1.1 christos * if the answer is secure.
12255 1.1 christos */
12256 1.3 christos if ((message->flags & DNS_MESSAGEFLAG_CD) != 0) {
12257 1.1 christos client->query.attributes &= ~NS_QUERYATTR_SECURE;
12258 1.3 christos }
12259 1.1 christos
12260 1.1 christos /*
12261 1.1 christos * Set NS_CLIENTATTR_WANTAD if the client has set AD in the query.
12262 1.1 christos * This allows AD to be returned on queries without DO set.
12263 1.1 christos */
12264 1.9 christos if ((message->flags & DNS_MESSAGEFLAG_AD) != 0) {
12265 1.1 christos client->attributes |= NS_CLIENTATTR_WANTAD;
12266 1.9 christos }
12267 1.1 christos
12268 1.1 christos /*
12269 1.1 christos * This is an ordinary query.
12270 1.1 christos */
12271 1.3 christos result = dns_message_reply(message, true);
12272 1.1 christos if (result != ISC_R_SUCCESS) {
12273 1.1 christos query_next(client, result);
12274 1.1 christos return;
12275 1.1 christos }
12276 1.1 christos
12277 1.1 christos /*
12278 1.1 christos * Assume authoritative response until it is known to be
12279 1.1 christos * otherwise.
12280 1.1 christos *
12281 1.1 christos * If "-T noaa" has been set on the command line don't set
12282 1.1 christos * AA on authoritative answers.
12283 1.1 christos */
12284 1.23 christos if ((client->manager->sctx->options & NS_SERVER_NOAA) == 0) {
12285 1.1 christos message->flags |= DNS_MESSAGEFLAG_AA;
12286 1.9 christos }
12287 1.1 christos
12288 1.1 christos /*
12289 1.1 christos * Set AD. We must clear it if we add non-validated data to a
12290 1.1 christos * response.
12291 1.1 christos */
12292 1.9 christos if (WANTDNSSEC(client) || WANTAD(client)) {
12293 1.1 christos message->flags |= DNS_MESSAGEFLAG_AD;
12294 1.9 christos }
12295 1.1 christos
12296 1.24 christos /*
12297 1.24 christos * Start global outgoing query count.
12298 1.24 christos */
12299 1.24 christos result = isc_counter_create(client->manager->mctx,
12300 1.24 christos client->view->max_queries,
12301 1.24 christos &client->query.qc);
12302 1.24 christos if (result != ISC_R_SUCCESS) {
12303 1.24 christos query_next(client, result);
12304 1.24 christos return;
12305 1.24 christos }
12306 1.24 christos
12307 1.23 christos query_setup(client, qtype);
12308 1.1 christos }
12309