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