1/*	$NetBSD: client.c,v 1.13 2024/02/21 22:52:05 christos Exp $	*/
2
3/*
4 * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
5 *
6 * SPDX-License-Identifier: MPL-2.0
7 *
8 * This Source Code Form is subject to the terms of the Mozilla Public
9 * License, v. 2.0. If a copy of the MPL was not distributed with this
10 * file, you can obtain one at https://mozilla.org/MPL/2.0/.
11 *
12 * See the COPYRIGHT file distributed with this work for additional
13 * information regarding copyright ownership.
14 */
15
16#include <stdbool.h>
17#include <stddef.h>
18
19#include <isc/app.h>
20#include <isc/buffer.h>
21#include <isc/md.h>
22#include <isc/mem.h>
23#include <isc/mutex.h>
24#include <isc/portset.h>
25#include <isc/refcount.h>
26#include <isc/result.h>
27#include <isc/safe.h>
28#include <isc/sockaddr.h>
29#include <isc/task.h>
30#include <isc/timer.h>
31#include <isc/util.h>
32
33#include <dns/adb.h>
34#include <dns/client.h>
35#include <dns/db.h>
36#include <dns/dispatch.h>
37#include <dns/events.h>
38#include <dns/forward.h>
39#include <dns/keytable.h>
40#include <dns/message.h>
41#include <dns/name.h>
42#include <dns/rdata.h>
43#include <dns/rdatalist.h>
44#include <dns/rdataset.h>
45#include <dns/rdatasetiter.h>
46#include <dns/rdatastruct.h>
47#include <dns/rdatatype.h>
48#include <dns/request.h>
49#include <dns/resolver.h>
50#include <dns/tsec.h>
51#include <dns/tsig.h>
52#include <dns/view.h>
53
54#include <dst/dst.h>
55
56#define DNS_CLIENT_MAGIC    ISC_MAGIC('D', 'N', 'S', 'c')
57#define DNS_CLIENT_VALID(c) ISC_MAGIC_VALID(c, DNS_CLIENT_MAGIC)
58
59#define RCTX_MAGIC    ISC_MAGIC('R', 'c', 't', 'x')
60#define RCTX_VALID(c) ISC_MAGIC_VALID(c, RCTX_MAGIC)
61
62#define UCTX_MAGIC    ISC_MAGIC('U', 'c', 't', 'x')
63#define UCTX_VALID(c) ISC_MAGIC_VALID(c, UCTX_MAGIC)
64
65#define MAX_RESTARTS 16
66
67#ifdef TUNE_LARGE
68#define RESOLVER_NTASKS 523
69#else /* ifdef TUNE_LARGE */
70#define RESOLVER_NTASKS 31
71#endif /* TUNE_LARGE */
72
73#define CHECK(r)                             \
74	do {                                 \
75		result = (r);                \
76		if (result != ISC_R_SUCCESS) \
77			goto cleanup;        \
78	} while (0)
79
80/*%
81 * DNS client object
82 */
83struct dns_client {
84	/* Unlocked */
85	unsigned int magic;
86	unsigned int attributes;
87	isc_mutex_t lock;
88	isc_mem_t *mctx;
89	isc_appctx_t *actx;
90	isc_taskmgr_t *taskmgr;
91	isc_task_t *task;
92	isc_nm_t *nm;
93	isc_timermgr_t *timermgr;
94	dns_dispatchmgr_t *dispatchmgr;
95	dns_dispatch_t *dispatchv4;
96	dns_dispatch_t *dispatchv6;
97
98	unsigned int find_timeout;
99	unsigned int find_udpretries;
100
101	isc_refcount_t references;
102
103	/* Locked */
104	dns_viewlist_t viewlist;
105	ISC_LIST(struct resctx) resctxs;
106};
107
108#define DEF_FIND_TIMEOUT    5
109#define DEF_FIND_UDPRETRIES 3
110
111/*%
112 * Internal state for a single name resolution procedure
113 */
114typedef struct resctx {
115	/* Unlocked */
116	unsigned int magic;
117	isc_mutex_t lock;
118	dns_client_t *client;
119	bool want_dnssec;
120	bool want_validation;
121	bool want_cdflag;
122	bool want_tcp;
123
124	/* Locked */
125	ISC_LINK(struct resctx) link;
126	isc_task_t *task;
127	dns_view_t *view;
128	unsigned int restarts;
129	dns_fixedname_t name;
130	dns_rdatatype_t type;
131	dns_fetch_t *fetch;
132	dns_namelist_t namelist;
133	isc_result_t result;
134	dns_clientresevent_t *event;
135	bool canceled;
136	dns_rdataset_t *rdataset;
137	dns_rdataset_t *sigrdataset;
138} resctx_t;
139
140/*%
141 * Argument of an internal event for synchronous name resolution.
142 */
143typedef struct resarg {
144	/* Unlocked */
145	isc_appctx_t *actx;
146	dns_client_t *client;
147	isc_mutex_t lock;
148
149	/* Locked */
150	isc_result_t result;
151	isc_result_t vresult;
152	dns_namelist_t *namelist;
153	dns_clientrestrans_t *trans;
154	bool canceled;
155} resarg_t;
156
157static void
158client_resfind(resctx_t *rctx, dns_fetchevent_t *event);
159static void
160cancelresolve(dns_clientrestrans_t *trans);
161static void
162destroyrestrans(dns_clientrestrans_t **transp);
163
164/*
165 * Try honoring the operating system's preferred ephemeral port range.
166 */
167static isc_result_t
168setsourceports(isc_mem_t *mctx, dns_dispatchmgr_t *manager) {
169	isc_portset_t *v4portset = NULL, *v6portset = NULL;
170	in_port_t udpport_low, udpport_high;
171	isc_result_t result;
172
173	result = isc_portset_create(mctx, &v4portset);
174	if (result != ISC_R_SUCCESS) {
175		goto cleanup;
176	}
177	result = isc_net_getudpportrange(AF_INET, &udpport_low, &udpport_high);
178	if (result != ISC_R_SUCCESS) {
179		goto cleanup;
180	}
181	isc_portset_addrange(v4portset, udpport_low, udpport_high);
182
183	result = isc_portset_create(mctx, &v6portset);
184	if (result != ISC_R_SUCCESS) {
185		goto cleanup;
186	}
187	result = isc_net_getudpportrange(AF_INET6, &udpport_low, &udpport_high);
188	if (result != ISC_R_SUCCESS) {
189		goto cleanup;
190	}
191	isc_portset_addrange(v6portset, udpport_low, udpport_high);
192
193	result = dns_dispatchmgr_setavailports(manager, v4portset, v6portset);
194
195cleanup:
196	if (v4portset != NULL) {
197		isc_portset_destroy(mctx, &v4portset);
198	}
199	if (v6portset != NULL) {
200		isc_portset_destroy(mctx, &v6portset);
201	}
202
203	return (result);
204}
205
206static isc_result_t
207getudpdispatch(int family, dns_dispatchmgr_t *dispatchmgr,
208	       dns_dispatch_t **dispp, const isc_sockaddr_t *localaddr) {
209	dns_dispatch_t *disp = NULL;
210	isc_result_t result;
211	isc_sockaddr_t anyaddr;
212
213	if (localaddr == NULL) {
214		isc_sockaddr_anyofpf(&anyaddr, family);
215		localaddr = &anyaddr;
216	}
217
218	result = dns_dispatch_createudp(dispatchmgr, localaddr, &disp);
219	if (result == ISC_R_SUCCESS) {
220		*dispp = disp;
221	}
222
223	return (result);
224}
225
226static isc_result_t
227createview(isc_mem_t *mctx, dns_rdataclass_t rdclass, isc_taskmgr_t *taskmgr,
228	   unsigned int ntasks, isc_nm_t *nm, isc_timermgr_t *timermgr,
229	   dns_dispatchmgr_t *dispatchmgr, dns_dispatch_t *dispatchv4,
230	   dns_dispatch_t *dispatchv6, dns_view_t **viewp) {
231	isc_result_t result;
232	dns_view_t *view = NULL;
233
234	result = dns_view_create(mctx, rdclass, DNS_CLIENTVIEW_NAME, &view);
235	if (result != ISC_R_SUCCESS) {
236		return (result);
237	}
238
239	/* Initialize view security roots */
240	result = dns_view_initsecroots(view, mctx);
241	if (result != ISC_R_SUCCESS) {
242		dns_view_detach(&view);
243		return (result);
244	}
245
246	result = dns_view_createresolver(view, taskmgr, ntasks, 1, nm, timermgr,
247					 0, dispatchmgr, dispatchv4,
248					 dispatchv6);
249	if (result != ISC_R_SUCCESS) {
250		dns_view_detach(&view);
251		return (result);
252	}
253
254	result = dns_db_create(mctx, "rbt", dns_rootname, dns_dbtype_cache,
255			       rdclass, 0, NULL, &view->cachedb);
256	if (result != ISC_R_SUCCESS) {
257		dns_view_detach(&view);
258		return (result);
259	}
260
261	*viewp = view;
262	return (ISC_R_SUCCESS);
263}
264
265isc_result_t
266dns_client_create(isc_mem_t *mctx, isc_appctx_t *actx, isc_taskmgr_t *taskmgr,
267		  isc_nm_t *nm, isc_timermgr_t *timermgr, unsigned int options,
268		  dns_client_t **clientp, const isc_sockaddr_t *localaddr4,
269		  const isc_sockaddr_t *localaddr6) {
270	isc_result_t result;
271	dns_client_t *client = NULL;
272	dns_dispatch_t *dispatchv4 = NULL;
273	dns_dispatch_t *dispatchv6 = NULL;
274	dns_view_t *view = NULL;
275
276	REQUIRE(mctx != NULL);
277	REQUIRE(taskmgr != NULL);
278	REQUIRE(timermgr != NULL);
279	REQUIRE(nm != NULL);
280	REQUIRE(clientp != NULL && *clientp == NULL);
281
282	UNUSED(options);
283
284	client = isc_mem_get(mctx, sizeof(*client));
285	*client = (dns_client_t){
286		.actx = actx, .taskmgr = taskmgr, .timermgr = timermgr, .nm = nm
287	};
288
289	isc_mutex_init(&client->lock);
290
291	result = isc_task_create(client->taskmgr, 0, &client->task);
292	if (result != ISC_R_SUCCESS) {
293		goto cleanup_lock;
294	}
295
296	result = dns_dispatchmgr_create(mctx, nm, &client->dispatchmgr);
297	if (result != ISC_R_SUCCESS) {
298		goto cleanup_task;
299	}
300	(void)setsourceports(mctx, client->dispatchmgr);
301
302	/*
303	 * If only one address family is specified, use it.
304	 * If neither family is specified, or if both are, use both.
305	 */
306	client->dispatchv4 = NULL;
307	if (localaddr4 != NULL || localaddr6 == NULL) {
308		result = getudpdispatch(AF_INET, client->dispatchmgr,
309					&dispatchv4, localaddr4);
310		if (result == ISC_R_SUCCESS) {
311			client->dispatchv4 = dispatchv4;
312		}
313	}
314
315	client->dispatchv6 = NULL;
316	if (localaddr6 != NULL || localaddr4 == NULL) {
317		result = getudpdispatch(AF_INET6, client->dispatchmgr,
318					&dispatchv6, localaddr6);
319		if (result == ISC_R_SUCCESS) {
320			client->dispatchv6 = dispatchv6;
321		}
322	}
323
324	/* We need at least one of the dispatchers */
325	if (dispatchv4 == NULL && dispatchv6 == NULL) {
326		INSIST(result != ISC_R_SUCCESS);
327		goto cleanup_dispatchmgr;
328	}
329
330	isc_refcount_init(&client->references, 1);
331
332	/* Create the default view for class IN */
333	result = createview(mctx, dns_rdataclass_in, taskmgr, RESOLVER_NTASKS,
334			    nm, timermgr, client->dispatchmgr, dispatchv4,
335			    dispatchv6, &view);
336	if (result != ISC_R_SUCCESS) {
337		goto cleanup_references;
338	}
339
340	ISC_LIST_INIT(client->viewlist);
341	ISC_LIST_APPEND(client->viewlist, view, link);
342
343	dns_view_freeze(view); /* too early? */
344
345	ISC_LIST_INIT(client->resctxs);
346
347	isc_mem_attach(mctx, &client->mctx);
348
349	client->find_timeout = DEF_FIND_TIMEOUT;
350	client->find_udpretries = DEF_FIND_UDPRETRIES;
351
352	client->magic = DNS_CLIENT_MAGIC;
353
354	*clientp = client;
355
356	return (ISC_R_SUCCESS);
357
358cleanup_references:
359	isc_refcount_decrementz(&client->references);
360	isc_refcount_destroy(&client->references);
361cleanup_dispatchmgr:
362	if (dispatchv4 != NULL) {
363		dns_dispatch_detach(&dispatchv4);
364	}
365	if (dispatchv6 != NULL) {
366		dns_dispatch_detach(&dispatchv6);
367	}
368	dns_dispatchmgr_detach(&client->dispatchmgr);
369cleanup_task:
370	isc_task_detach(&client->task);
371cleanup_lock:
372	isc_mutex_destroy(&client->lock);
373	isc_mem_put(mctx, client, sizeof(*client));
374
375	return (result);
376}
377
378static void
379destroyclient(dns_client_t *client) {
380	dns_view_t *view = NULL;
381
382	isc_refcount_destroy(&client->references);
383
384	while ((view = ISC_LIST_HEAD(client->viewlist)) != NULL) {
385		ISC_LIST_UNLINK(client->viewlist, view, link);
386		dns_view_detach(&view);
387	}
388
389	if (client->dispatchv4 != NULL) {
390		dns_dispatch_detach(&client->dispatchv4);
391	}
392	if (client->dispatchv6 != NULL) {
393		dns_dispatch_detach(&client->dispatchv6);
394	}
395
396	dns_dispatchmgr_detach(&client->dispatchmgr);
397
398	isc_task_detach(&client->task);
399
400	isc_mutex_destroy(&client->lock);
401	client->magic = 0;
402
403	isc_mem_putanddetach(&client->mctx, client, sizeof(*client));
404}
405
406void
407dns_client_detach(dns_client_t **clientp) {
408	dns_client_t *client = NULL;
409
410	REQUIRE(clientp != NULL);
411	REQUIRE(DNS_CLIENT_VALID(*clientp));
412
413	client = *clientp;
414	*clientp = NULL;
415
416	if (isc_refcount_decrement(&client->references) == 1) {
417		destroyclient(client);
418	}
419}
420
421isc_result_t
422dns_client_setservers(dns_client_t *client, dns_rdataclass_t rdclass,
423		      const dns_name_t *name_space, isc_sockaddrlist_t *addrs) {
424	isc_result_t result;
425	dns_view_t *view = NULL;
426
427	REQUIRE(DNS_CLIENT_VALID(client));
428	REQUIRE(addrs != NULL);
429
430	if (name_space == NULL) {
431		name_space = dns_rootname;
432	}
433
434	LOCK(&client->lock);
435	result = dns_viewlist_find(&client->viewlist, DNS_CLIENTVIEW_NAME,
436				   rdclass, &view);
437	if (result != ISC_R_SUCCESS) {
438		UNLOCK(&client->lock);
439		return (result);
440	}
441	UNLOCK(&client->lock);
442
443	result = dns_fwdtable_add(view->fwdtable, name_space, addrs,
444				  dns_fwdpolicy_only);
445
446	dns_view_detach(&view);
447
448	return (result);
449}
450
451isc_result_t
452dns_client_clearservers(dns_client_t *client, dns_rdataclass_t rdclass,
453			const dns_name_t *name_space) {
454	isc_result_t result;
455	dns_view_t *view = NULL;
456
457	REQUIRE(DNS_CLIENT_VALID(client));
458
459	if (name_space == NULL) {
460		name_space = dns_rootname;
461	}
462
463	LOCK(&client->lock);
464	result = dns_viewlist_find(&client->viewlist, DNS_CLIENTVIEW_NAME,
465				   rdclass, &view);
466	if (result != ISC_R_SUCCESS) {
467		UNLOCK(&client->lock);
468		return (result);
469	}
470	UNLOCK(&client->lock);
471
472	result = dns_fwdtable_delete(view->fwdtable, name_space);
473
474	dns_view_detach(&view);
475
476	return (result);
477}
478
479static isc_result_t
480getrdataset(isc_mem_t *mctx, dns_rdataset_t **rdatasetp) {
481	dns_rdataset_t *rdataset;
482
483	REQUIRE(mctx != NULL);
484	REQUIRE(rdatasetp != NULL && *rdatasetp == NULL);
485
486	rdataset = isc_mem_get(mctx, sizeof(*rdataset));
487
488	dns_rdataset_init(rdataset);
489
490	*rdatasetp = rdataset;
491
492	return (ISC_R_SUCCESS);
493}
494
495static void
496putrdataset(isc_mem_t *mctx, dns_rdataset_t **rdatasetp) {
497	dns_rdataset_t *rdataset;
498
499	REQUIRE(rdatasetp != NULL);
500	rdataset = *rdatasetp;
501	*rdatasetp = NULL;
502	REQUIRE(rdataset != NULL);
503
504	if (dns_rdataset_isassociated(rdataset)) {
505		dns_rdataset_disassociate(rdataset);
506	}
507
508	isc_mem_put(mctx, rdataset, sizeof(*rdataset));
509}
510
511static void
512fetch_done(isc_task_t *task, isc_event_t *event) {
513	resctx_t *rctx = event->ev_arg;
514	dns_fetchevent_t *fevent;
515
516	REQUIRE(event->ev_type == DNS_EVENT_FETCHDONE);
517	REQUIRE(RCTX_VALID(rctx));
518	REQUIRE(rctx->task == task);
519	fevent = (dns_fetchevent_t *)event;
520
521	client_resfind(rctx, fevent);
522}
523
524static isc_result_t
525start_fetch(resctx_t *rctx) {
526	isc_result_t result;
527	int fopts = 0;
528
529	/*
530	 * The caller must be holding the rctx's lock.
531	 */
532
533	REQUIRE(rctx->fetch == NULL);
534
535	if (!rctx->want_cdflag) {
536		fopts |= DNS_FETCHOPT_NOCDFLAG;
537	}
538	if (!rctx->want_validation) {
539		fopts |= DNS_FETCHOPT_NOVALIDATE;
540	}
541	if (rctx->want_tcp) {
542		fopts |= DNS_FETCHOPT_TCP;
543	}
544
545	result = dns_resolver_createfetch(
546		rctx->view->resolver, dns_fixedname_name(&rctx->name),
547		rctx->type, NULL, NULL, NULL, NULL, 0, fopts, 0, NULL,
548		rctx->task, fetch_done, rctx, rctx->rdataset, rctx->sigrdataset,
549		&rctx->fetch);
550
551	return (result);
552}
553
554static isc_result_t
555view_find(resctx_t *rctx, dns_db_t **dbp, dns_dbnode_t **nodep,
556	  dns_name_t *foundname) {
557	isc_result_t result;
558	dns_name_t *name = dns_fixedname_name(&rctx->name);
559	dns_rdatatype_t type;
560
561	if (rctx->type == dns_rdatatype_rrsig) {
562		type = dns_rdatatype_any;
563	} else {
564		type = rctx->type;
565	}
566
567	result = dns_view_find(rctx->view, name, type, 0, 0, false, false, dbp,
568			       nodep, foundname, rctx->rdataset,
569			       rctx->sigrdataset);
570
571	return (result);
572}
573
574static void
575client_resfind(resctx_t *rctx, dns_fetchevent_t *event) {
576	isc_mem_t *mctx;
577	isc_result_t tresult, result = ISC_R_SUCCESS;
578	isc_result_t vresult = ISC_R_SUCCESS;
579	bool want_restart;
580	bool send_event = false;
581	dns_name_t *name = NULL, *prefix = NULL;
582	dns_fixedname_t foundname, fixed;
583	dns_rdataset_t *trdataset = NULL;
584	dns_rdata_t rdata = DNS_RDATA_INIT;
585	unsigned int nlabels;
586	int order;
587	dns_namereln_t namereln;
588	dns_rdata_cname_t cname;
589	dns_rdata_dname_t dname;
590
591	REQUIRE(RCTX_VALID(rctx));
592
593	LOCK(&rctx->lock);
594
595	mctx = rctx->view->mctx;
596
597	name = dns_fixedname_name(&rctx->name);
598
599	do {
600		dns_name_t *fname = NULL;
601		dns_name_t *ansname = NULL;
602		dns_db_t *db = NULL;
603		dns_dbnode_t *node = NULL;
604
605		rctx->restarts++;
606		want_restart = false;
607
608		if (event == NULL && !rctx->canceled) {
609			fname = dns_fixedname_initname(&foundname);
610			INSIST(!dns_rdataset_isassociated(rctx->rdataset));
611			INSIST(rctx->sigrdataset == NULL ||
612			       !dns_rdataset_isassociated(rctx->sigrdataset));
613			result = view_find(rctx, &db, &node, fname);
614			if (result == ISC_R_NOTFOUND) {
615				/*
616				 * We don't know anything about the name.
617				 * Launch a fetch.
618				 */
619				if (node != NULL) {
620					INSIST(db != NULL);
621					dns_db_detachnode(db, &node);
622				}
623				if (db != NULL) {
624					dns_db_detach(&db);
625				}
626				result = start_fetch(rctx);
627				if (result != ISC_R_SUCCESS) {
628					putrdataset(mctx, &rctx->rdataset);
629					if (rctx->sigrdataset != NULL) {
630						putrdataset(mctx,
631							    &rctx->sigrdataset);
632					}
633					send_event = true;
634				}
635				goto done;
636			}
637		} else {
638			INSIST(event != NULL);
639			INSIST(event->fetch == rctx->fetch);
640			dns_resolver_destroyfetch(&rctx->fetch);
641			db = event->db;
642			node = event->node;
643			result = event->result;
644			vresult = event->vresult;
645			fname = event->foundname;
646			INSIST(event->rdataset == rctx->rdataset);
647			INSIST(event->sigrdataset == rctx->sigrdataset);
648		}
649
650		/*
651		 * If we've been canceled, forget about the result.
652		 */
653		if (rctx->canceled) {
654			result = ISC_R_CANCELED;
655		} else {
656			/*
657			 * Otherwise, get some resource for copying the
658			 * result.
659			 */
660			dns_name_t *aname = dns_fixedname_name(&rctx->name);
661
662			ansname = isc_mem_get(mctx, sizeof(*ansname));
663			dns_name_init(ansname, NULL);
664
665			dns_name_dup(aname, mctx, ansname);
666		}
667
668		switch (result) {
669		case ISC_R_SUCCESS:
670			send_event = true;
671			/*
672			 * This case is handled in the main line below.
673			 */
674			break;
675		case DNS_R_CNAME:
676			/*
677			 * Add the CNAME to the answer list.
678			 */
679			trdataset = rctx->rdataset;
680			ISC_LIST_APPEND(ansname->list, rctx->rdataset, link);
681			rctx->rdataset = NULL;
682			if (rctx->sigrdataset != NULL) {
683				ISC_LIST_APPEND(ansname->list,
684						rctx->sigrdataset, link);
685				rctx->sigrdataset = NULL;
686			}
687			ISC_LIST_APPEND(rctx->namelist, ansname, link);
688			ansname = NULL;
689
690			/*
691			 * Copy the CNAME's target into the lookup's
692			 * query name and start over.
693			 */
694			tresult = dns_rdataset_first(trdataset);
695			if (tresult != ISC_R_SUCCESS) {
696				goto done;
697			}
698			dns_rdataset_current(trdataset, &rdata);
699			tresult = dns_rdata_tostruct(&rdata, &cname, NULL);
700			dns_rdata_reset(&rdata);
701			if (tresult != ISC_R_SUCCESS) {
702				goto done;
703			}
704			dns_name_copy(&cname.cname, name);
705			dns_rdata_freestruct(&cname);
706			want_restart = true;
707			goto done;
708		case DNS_R_DNAME:
709			/*
710			 * Add the DNAME to the answer list.
711			 */
712			trdataset = rctx->rdataset;
713			ISC_LIST_APPEND(ansname->list, rctx->rdataset, link);
714			rctx->rdataset = NULL;
715			if (rctx->sigrdataset != NULL) {
716				ISC_LIST_APPEND(ansname->list,
717						rctx->sigrdataset, link);
718				rctx->sigrdataset = NULL;
719			}
720			ISC_LIST_APPEND(rctx->namelist, ansname, link);
721			ansname = NULL;
722
723			namereln = dns_name_fullcompare(name, fname, &order,
724							&nlabels);
725			INSIST(namereln == dns_namereln_subdomain);
726			/*
727			 * Get the target name of the DNAME.
728			 */
729			tresult = dns_rdataset_first(trdataset);
730			if (tresult != ISC_R_SUCCESS) {
731				result = tresult;
732				goto done;
733			}
734			dns_rdataset_current(trdataset, &rdata);
735			tresult = dns_rdata_tostruct(&rdata, &dname, NULL);
736			dns_rdata_reset(&rdata);
737			if (tresult != ISC_R_SUCCESS) {
738				result = tresult;
739				goto done;
740			}
741			/*
742			 * Construct the new query name and start over.
743			 */
744			prefix = dns_fixedname_initname(&fixed);
745			dns_name_split(name, nlabels, prefix, NULL);
746			tresult = dns_name_concatenate(prefix, &dname.dname,
747						       name, NULL);
748			dns_rdata_freestruct(&dname);
749			if (tresult == ISC_R_SUCCESS) {
750				want_restart = true;
751			} else {
752				result = tresult;
753			}
754			goto done;
755		case DNS_R_NCACHENXDOMAIN:
756		case DNS_R_NCACHENXRRSET:
757			ISC_LIST_APPEND(ansname->list, rctx->rdataset, link);
758			ISC_LIST_APPEND(rctx->namelist, ansname, link);
759			ansname = NULL;
760			rctx->rdataset = NULL;
761			/* What about sigrdataset? */
762			if (rctx->sigrdataset != NULL) {
763				putrdataset(mctx, &rctx->sigrdataset);
764			}
765			send_event = true;
766			goto done;
767		default:
768			if (rctx->rdataset != NULL) {
769				putrdataset(mctx, &rctx->rdataset);
770			}
771			if (rctx->sigrdataset != NULL) {
772				putrdataset(mctx, &rctx->sigrdataset);
773			}
774			send_event = true;
775			goto done;
776		}
777
778		if (rctx->type == dns_rdatatype_any) {
779			int n = 0;
780			dns_rdatasetiter_t *rdsiter = NULL;
781
782			tresult = dns_db_allrdatasets(db, node, NULL, 0, 0,
783						      &rdsiter);
784			if (tresult != ISC_R_SUCCESS) {
785				result = tresult;
786				goto done;
787			}
788
789			tresult = dns_rdatasetiter_first(rdsiter);
790			while (tresult == ISC_R_SUCCESS) {
791				dns_rdatasetiter_current(rdsiter,
792							 rctx->rdataset);
793				if (rctx->rdataset->type != 0) {
794					ISC_LIST_APPEND(ansname->list,
795							rctx->rdataset, link);
796					n++;
797					rctx->rdataset = NULL;
798				} else {
799					/*
800					 * We're not interested in this
801					 * rdataset.
802					 */
803					dns_rdataset_disassociate(
804						rctx->rdataset);
805				}
806				tresult = dns_rdatasetiter_next(rdsiter);
807
808				if (tresult == ISC_R_SUCCESS &&
809				    rctx->rdataset == NULL)
810				{
811					tresult = getrdataset(mctx,
812							      &rctx->rdataset);
813					if (tresult != ISC_R_SUCCESS) {
814						result = tresult;
815						POST(result);
816						break;
817					}
818				}
819			}
820			if (rctx->rdataset != NULL) {
821				putrdataset(mctx, &rctx->rdataset);
822			}
823			if (rctx->sigrdataset != NULL) {
824				putrdataset(mctx, &rctx->sigrdataset);
825			}
826			if (n == 0) {
827				/*
828				 * We didn't match any rdatasets (which means
829				 * something went wrong in this
830				 * implementation).
831				 */
832				result = DNS_R_SERVFAIL; /* better code? */
833				POST(result);
834			} else {
835				ISC_LIST_APPEND(rctx->namelist, ansname, link);
836				ansname = NULL;
837			}
838			dns_rdatasetiter_destroy(&rdsiter);
839			if (tresult != ISC_R_NOMORE) {
840				result = DNS_R_SERVFAIL; /* ditto */
841			} else {
842				result = ISC_R_SUCCESS;
843			}
844			goto done;
845		} else {
846			/*
847			 * This is the "normal" case -- an ordinary question
848			 * to which we've got the answer.
849			 */
850			ISC_LIST_APPEND(ansname->list, rctx->rdataset, link);
851			rctx->rdataset = NULL;
852			if (rctx->sigrdataset != NULL) {
853				ISC_LIST_APPEND(ansname->list,
854						rctx->sigrdataset, link);
855				rctx->sigrdataset = NULL;
856			}
857			ISC_LIST_APPEND(rctx->namelist, ansname, link);
858			ansname = NULL;
859		}
860
861	done:
862		/*
863		 * Free temporary resources
864		 */
865		if (ansname != NULL) {
866			dns_rdataset_t *rdataset;
867
868			while ((rdataset = ISC_LIST_HEAD(ansname->list)) !=
869			       NULL)
870			{
871				ISC_LIST_UNLINK(ansname->list, rdataset, link);
872				putrdataset(mctx, &rdataset);
873			}
874			dns_name_free(ansname, mctx);
875			isc_mem_put(mctx, ansname, sizeof(*ansname));
876		}
877
878		if (node != NULL) {
879			dns_db_detachnode(db, &node);
880		}
881		if (db != NULL) {
882			dns_db_detach(&db);
883		}
884		if (event != NULL) {
885			isc_event_free(ISC_EVENT_PTR(&event));
886		}
887
888		/*
889		 * Limit the number of restarts.
890		 */
891		if (want_restart && rctx->restarts == MAX_RESTARTS) {
892			want_restart = false;
893			result = ISC_R_QUOTA;
894			send_event = true;
895		}
896
897		/*
898		 * Prepare further find with new resources
899		 */
900		if (want_restart) {
901			INSIST(rctx->rdataset == NULL &&
902			       rctx->sigrdataset == NULL);
903
904			result = getrdataset(mctx, &rctx->rdataset);
905			if (result == ISC_R_SUCCESS && rctx->want_dnssec) {
906				result = getrdataset(mctx, &rctx->sigrdataset);
907				if (result != ISC_R_SUCCESS) {
908					putrdataset(mctx, &rctx->rdataset);
909				}
910			}
911
912			if (result != ISC_R_SUCCESS) {
913				want_restart = false;
914				send_event = true;
915			}
916		}
917	} while (want_restart);
918
919	if (send_event) {
920		isc_task_t *task;
921
922		while ((name = ISC_LIST_HEAD(rctx->namelist)) != NULL) {
923			ISC_LIST_UNLINK(rctx->namelist, name, link);
924			ISC_LIST_APPEND(rctx->event->answerlist, name, link);
925		}
926
927		rctx->event->result = result;
928		rctx->event->vresult = vresult;
929		task = rctx->event->ev_sender;
930		rctx->event->ev_sender = rctx;
931		isc_task_sendanddetach(&task, ISC_EVENT_PTR(&rctx->event));
932	}
933
934	UNLOCK(&rctx->lock);
935}
936
937static void
938suspend(isc_task_t *task, isc_event_t *event) {
939	isc_appctx_t *actx = event->ev_arg;
940
941	UNUSED(task);
942
943	isc_app_ctxsuspend(actx);
944	isc_event_free(&event);
945}
946
947static void
948resolve_done(isc_task_t *task, isc_event_t *event) {
949	resarg_t *resarg = event->ev_arg;
950	dns_clientresevent_t *rev = (dns_clientresevent_t *)event;
951	dns_name_t *name = NULL;
952	dns_client_t *client = resarg->client;
953	isc_result_t result;
954
955	UNUSED(task);
956
957	LOCK(&resarg->lock);
958
959	resarg->result = rev->result;
960	resarg->vresult = rev->vresult;
961	while ((name = ISC_LIST_HEAD(rev->answerlist)) != NULL) {
962		ISC_LIST_UNLINK(rev->answerlist, name, link);
963		ISC_LIST_APPEND(*resarg->namelist, name, link);
964	}
965
966	destroyrestrans(&resarg->trans);
967	isc_event_free(&event);
968	resarg->client = NULL;
969
970	if (!resarg->canceled) {
971		UNLOCK(&resarg->lock);
972
973		/*
974		 * We may or may not be running.  isc__appctx_onrun will
975		 * fail if we are currently running otherwise we post a
976		 * action to call isc_app_ctxsuspend when we do start
977		 * running.
978		 */
979		result = isc_app_ctxonrun(resarg->actx, client->mctx, task,
980					  suspend, resarg->actx);
981		if (result == ISC_R_ALREADYRUNNING) {
982			isc_app_ctxsuspend(resarg->actx);
983		}
984	} else {
985		/*
986		 * We have already exited from the loop (due to some
987		 * unexpected event).  Just clean the arg up.
988		 */
989		UNLOCK(&resarg->lock);
990		isc_mutex_destroy(&resarg->lock);
991		isc_mem_put(client->mctx, resarg, sizeof(*resarg));
992	}
993
994	dns_client_detach(&client);
995}
996
997isc_result_t
998dns_client_resolve(dns_client_t *client, const dns_name_t *name,
999		   dns_rdataclass_t rdclass, dns_rdatatype_t type,
1000		   unsigned int options, dns_namelist_t *namelist) {
1001	isc_result_t result;
1002	resarg_t *resarg = NULL;
1003
1004	REQUIRE(DNS_CLIENT_VALID(client));
1005	REQUIRE(client->actx != NULL);
1006	REQUIRE(namelist != NULL && ISC_LIST_EMPTY(*namelist));
1007
1008	resarg = isc_mem_get(client->mctx, sizeof(*resarg));
1009
1010	*resarg = (resarg_t){
1011		.actx = client->actx,
1012		.client = client,
1013		.result = DNS_R_SERVFAIL,
1014		.namelist = namelist,
1015	};
1016
1017	isc_mutex_init(&resarg->lock);
1018
1019	result = dns_client_startresolve(client, name, rdclass, type, options,
1020					 client->task, resolve_done, resarg,
1021					 &resarg->trans);
1022	if (result != ISC_R_SUCCESS) {
1023		isc_mutex_destroy(&resarg->lock);
1024		isc_mem_put(client->mctx, resarg, sizeof(*resarg));
1025		return (result);
1026	}
1027
1028	/*
1029	 * Start internal event loop.  It blocks until the entire process
1030	 * is completed.
1031	 */
1032	result = isc_app_ctxrun(client->actx);
1033
1034	LOCK(&resarg->lock);
1035	if (result == ISC_R_SUCCESS || result == ISC_R_SUSPEND) {
1036		result = resarg->result;
1037	}
1038	if (result != ISC_R_SUCCESS && resarg->vresult != ISC_R_SUCCESS) {
1039		/*
1040		 * If this lookup failed due to some error in DNSSEC
1041		 * validation, return the validation error code.
1042		 * XXX: or should we pass the validation result separately?
1043		 */
1044		result = resarg->vresult;
1045	}
1046	if (resarg->trans != NULL) {
1047		/*
1048		 * Unusual termination (perhaps due to signal).  We need some
1049		 * tricky cleanup process.
1050		 */
1051		resarg->canceled = true;
1052		cancelresolve(resarg->trans);
1053
1054		UNLOCK(&resarg->lock);
1055
1056		/* resarg will be freed in the event handler. */
1057	} else {
1058		UNLOCK(&resarg->lock);
1059
1060		isc_mutex_destroy(&resarg->lock);
1061		isc_mem_put(client->mctx, resarg, sizeof(*resarg));
1062	}
1063
1064	return (result);
1065}
1066
1067isc_result_t
1068dns_client_startresolve(dns_client_t *client, const dns_name_t *name,
1069			dns_rdataclass_t rdclass, dns_rdatatype_t type,
1070			unsigned int options, isc_task_t *task,
1071			isc_taskaction_t action, void *arg,
1072			dns_clientrestrans_t **transp) {
1073	dns_view_t *view = NULL;
1074	dns_clientresevent_t *event = NULL;
1075	resctx_t *rctx = NULL;
1076	isc_task_t *tclone = NULL;
1077	isc_mem_t *mctx;
1078	isc_result_t result;
1079	dns_rdataset_t *rdataset, *sigrdataset;
1080	bool want_dnssec, want_validation, want_cdflag, want_tcp;
1081
1082	REQUIRE(DNS_CLIENT_VALID(client));
1083	REQUIRE(transp != NULL && *transp == NULL);
1084
1085	LOCK(&client->lock);
1086	result = dns_viewlist_find(&client->viewlist, DNS_CLIENTVIEW_NAME,
1087				   rdclass, &view);
1088	UNLOCK(&client->lock);
1089	if (result != ISC_R_SUCCESS) {
1090		return (result);
1091	}
1092
1093	mctx = client->mctx;
1094	rdataset = NULL;
1095	sigrdataset = NULL;
1096	want_dnssec = ((options & DNS_CLIENTRESOPT_NODNSSEC) == 0);
1097	want_validation = ((options & DNS_CLIENTRESOPT_NOVALIDATE) == 0);
1098	want_cdflag = ((options & DNS_CLIENTRESOPT_NOCDFLAG) == 0);
1099	want_tcp = ((options & DNS_CLIENTRESOPT_TCP) != 0);
1100
1101	/*
1102	 * Prepare some intermediate resources
1103	 */
1104	tclone = NULL;
1105	isc_task_attach(task, &tclone);
1106	event = (dns_clientresevent_t *)isc_event_allocate(
1107		mctx, tclone, DNS_EVENT_CLIENTRESDONE, action, arg,
1108		sizeof(*event));
1109	event->result = DNS_R_SERVFAIL;
1110	ISC_LIST_INIT(event->answerlist);
1111
1112	rctx = isc_mem_get(mctx, sizeof(*rctx));
1113	isc_mutex_init(&rctx->lock);
1114
1115	result = getrdataset(mctx, &rdataset);
1116	if (result != ISC_R_SUCCESS) {
1117		goto cleanup;
1118	}
1119	rctx->rdataset = rdataset;
1120
1121	if (want_dnssec) {
1122		result = getrdataset(mctx, &sigrdataset);
1123		if (result != ISC_R_SUCCESS) {
1124			goto cleanup;
1125		}
1126	}
1127	rctx->sigrdataset = sigrdataset;
1128
1129	dns_fixedname_init(&rctx->name);
1130	dns_name_copy(name, dns_fixedname_name(&rctx->name));
1131
1132	rctx->client = client;
1133	ISC_LINK_INIT(rctx, link);
1134	rctx->canceled = false;
1135	rctx->task = client->task;
1136	rctx->type = type;
1137	rctx->view = view;
1138	rctx->restarts = 0;
1139	rctx->fetch = NULL;
1140	rctx->want_dnssec = want_dnssec;
1141	rctx->want_validation = want_validation;
1142	rctx->want_cdflag = want_cdflag;
1143	rctx->want_tcp = want_tcp;
1144	ISC_LIST_INIT(rctx->namelist);
1145	rctx->event = event;
1146
1147	rctx->magic = RCTX_MAGIC;
1148	isc_refcount_increment(&client->references);
1149
1150	LOCK(&client->lock);
1151	ISC_LIST_APPEND(client->resctxs, rctx, link);
1152	UNLOCK(&client->lock);
1153
1154	*transp = (dns_clientrestrans_t *)rctx;
1155	client_resfind(rctx, NULL);
1156
1157	return (ISC_R_SUCCESS);
1158
1159cleanup:
1160	if (rdataset != NULL) {
1161		putrdataset(client->mctx, &rdataset);
1162	}
1163	if (sigrdataset != NULL) {
1164		putrdataset(client->mctx, &sigrdataset);
1165	}
1166	isc_mutex_destroy(&rctx->lock);
1167	isc_mem_put(mctx, rctx, sizeof(*rctx));
1168	isc_event_free(ISC_EVENT_PTR(&event));
1169	isc_task_detach(&tclone);
1170	dns_view_detach(&view);
1171
1172	return (result);
1173}
1174
1175/*%<
1176 * Cancel an ongoing resolution procedure started via
1177 * dns_client_startresolve().
1178 *
1179 * If the resolution procedure has not completed, post its CLIENTRESDONE
1180 * event with a result code of #ISC_R_CANCELED.
1181 */
1182static void
1183cancelresolve(dns_clientrestrans_t *trans) {
1184	resctx_t *rctx = NULL;
1185
1186	REQUIRE(trans != NULL);
1187	rctx = (resctx_t *)trans;
1188	REQUIRE(RCTX_VALID(rctx));
1189
1190	LOCK(&rctx->lock);
1191
1192	if (!rctx->canceled) {
1193		rctx->canceled = true;
1194		if (rctx->fetch != NULL) {
1195			dns_resolver_cancelfetch(rctx->fetch);
1196		}
1197	}
1198
1199	UNLOCK(&rctx->lock);
1200}
1201
1202void
1203dns_client_freeresanswer(dns_client_t *client, dns_namelist_t *namelist) {
1204	dns_name_t *name;
1205	dns_rdataset_t *rdataset;
1206
1207	REQUIRE(DNS_CLIENT_VALID(client));
1208	REQUIRE(namelist != NULL);
1209
1210	while ((name = ISC_LIST_HEAD(*namelist)) != NULL) {
1211		ISC_LIST_UNLINK(*namelist, name, link);
1212		while ((rdataset = ISC_LIST_HEAD(name->list)) != NULL) {
1213			ISC_LIST_UNLINK(name->list, rdataset, link);
1214			putrdataset(client->mctx, &rdataset);
1215		}
1216		dns_name_free(name, client->mctx);
1217		isc_mem_put(client->mctx, name, sizeof(*name));
1218	}
1219}
1220
1221/*%
1222 * Destroy name resolution transaction state identified by '*transp'.
1223 *
1224 * The caller must have received the CLIENTRESDONE event (either because the
1225 * resolution completed or because cancelresolve() was called).
1226 */
1227static void
1228destroyrestrans(dns_clientrestrans_t **transp) {
1229	resctx_t *rctx = NULL;
1230	isc_mem_t *mctx = NULL;
1231	dns_client_t *client = NULL;
1232
1233	REQUIRE(transp != NULL);
1234
1235	rctx = (resctx_t *)*transp;
1236	*transp = NULL;
1237
1238	REQUIRE(RCTX_VALID(rctx));
1239	REQUIRE(rctx->fetch == NULL);
1240	REQUIRE(rctx->event == NULL);
1241
1242	client = rctx->client;
1243
1244	REQUIRE(DNS_CLIENT_VALID(client));
1245
1246	mctx = client->mctx;
1247	dns_view_detach(&rctx->view);
1248
1249	/*
1250	 * Wait for the lock in client_resfind to be released before
1251	 * destroying the lock.
1252	 */
1253	LOCK(&rctx->lock);
1254	UNLOCK(&rctx->lock);
1255
1256	LOCK(&client->lock);
1257
1258	INSIST(ISC_LINK_LINKED(rctx, link));
1259	ISC_LIST_UNLINK(client->resctxs, rctx, link);
1260
1261	UNLOCK(&client->lock);
1262
1263	INSIST(ISC_LIST_EMPTY(rctx->namelist));
1264
1265	isc_mutex_destroy(&rctx->lock);
1266	rctx->magic = 0;
1267
1268	isc_mem_put(mctx, rctx, sizeof(*rctx));
1269}
1270
1271isc_result_t
1272dns_client_addtrustedkey(dns_client_t *client, dns_rdataclass_t rdclass,
1273			 dns_rdatatype_t rdtype, const dns_name_t *keyname,
1274			 isc_buffer_t *databuf) {
1275	isc_result_t result;
1276	dns_view_t *view = NULL;
1277	dns_keytable_t *secroots = NULL;
1278	dns_name_t *name = NULL;
1279	char rdatabuf[DST_KEY_MAXSIZE];
1280	unsigned char digest[ISC_MAX_MD_SIZE];
1281	dns_rdata_ds_t ds;
1282	dns_decompress_t dctx;
1283	dns_rdata_t rdata;
1284	isc_buffer_t b;
1285
1286	REQUIRE(DNS_CLIENT_VALID(client));
1287
1288	LOCK(&client->lock);
1289	result = dns_viewlist_find(&client->viewlist, DNS_CLIENTVIEW_NAME,
1290				   rdclass, &view);
1291	UNLOCK(&client->lock);
1292	CHECK(result);
1293
1294	CHECK(dns_view_getsecroots(view, &secroots));
1295
1296	DE_CONST(keyname, name);
1297
1298	if (rdtype != dns_rdatatype_dnskey && rdtype != dns_rdatatype_ds) {
1299		result = ISC_R_NOTIMPLEMENTED;
1300		goto cleanup;
1301	}
1302
1303	isc_buffer_init(&b, rdatabuf, sizeof(rdatabuf));
1304	dns_decompress_init(&dctx, -1, DNS_DECOMPRESS_NONE);
1305	dns_rdata_init(&rdata);
1306	isc_buffer_setactive(databuf, isc_buffer_usedlength(databuf));
1307	CHECK(dns_rdata_fromwire(&rdata, rdclass, rdtype, databuf, &dctx, 0,
1308				 &b));
1309	dns_decompress_invalidate(&dctx);
1310
1311	if (rdtype == dns_rdatatype_ds) {
1312		CHECK(dns_rdata_tostruct(&rdata, &ds, NULL));
1313	} else {
1314		CHECK(dns_ds_fromkeyrdata(name, &rdata, DNS_DSDIGEST_SHA256,
1315					  digest, &ds));
1316	}
1317
1318	CHECK(dns_keytable_add(secroots, false, false, name, &ds, NULL, NULL));
1319
1320cleanup:
1321	if (view != NULL) {
1322		dns_view_detach(&view);
1323	}
1324	if (secroots != NULL) {
1325		dns_keytable_detach(&secroots);
1326	}
1327	return (result);
1328}
1329