xref: /netbsd-src/external/mpl/bind/dist/lib/dns/client.c (revision 9fb66d812c00ebfb445c0b47dea128f32aa6fe96)
1 /*	$NetBSD: client.c,v 1.9 2021/04/05 11:27:01 rillig Exp $	*/
2 
3 /*
4  * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
5  *
6  * This Source Code Form is subject to the terms of the Mozilla Public
7  * License, v. 2.0. If a copy of the MPL was not distributed with this
8  * file, you can obtain one at https://mozilla.org/MPL/2.0/.
9  *
10  * See the COPYRIGHT file distributed with this work for additional
11  * information regarding copyright ownership.
12  */
13 
14 #include <stdbool.h>
15 #include <stddef.h>
16 
17 #include <isc/app.h>
18 #include <isc/buffer.h>
19 #include <isc/md.h>
20 #include <isc/mem.h>
21 #include <isc/mutex.h>
22 #include <isc/portset.h>
23 #include <isc/refcount.h>
24 #include <isc/safe.h>
25 #include <isc/sockaddr.h>
26 #include <isc/socket.h>
27 #include <isc/task.h>
28 #include <isc/timer.h>
29 #include <isc/util.h>
30 
31 #include <dns/adb.h>
32 #include <dns/client.h>
33 #include <dns/db.h>
34 #include <dns/dispatch.h>
35 #include <dns/events.h>
36 #include <dns/forward.h>
37 #include <dns/keytable.h>
38 #include <dns/message.h>
39 #include <dns/name.h>
40 #include <dns/rdata.h>
41 #include <dns/rdatalist.h>
42 #include <dns/rdataset.h>
43 #include <dns/rdatasetiter.h>
44 #include <dns/rdatastruct.h>
45 #include <dns/rdatatype.h>
46 #include <dns/request.h>
47 #include <dns/resolver.h>
48 #include <dns/result.h>
49 #include <dns/tsec.h>
50 #include <dns/tsig.h>
51 #include <dns/view.h>
52 
53 #include <dst/dst.h>
54 
55 #define DNS_CLIENT_MAGIC    ISC_MAGIC('D', 'N', 'S', 'c')
56 #define DNS_CLIENT_VALID(c) ISC_MAGIC_VALID(c, DNS_CLIENT_MAGIC)
57 
58 #define RCTX_MAGIC    ISC_MAGIC('R', 'c', 't', 'x')
59 #define RCTX_VALID(c) ISC_MAGIC_VALID(c, RCTX_MAGIC)
60 
61 #define REQCTX_MAGIC	ISC_MAGIC('R', 'q', 'c', 'x')
62 #define REQCTX_VALID(c) ISC_MAGIC_VALID(c, REQCTX_MAGIC)
63 
64 #define UCTX_MAGIC    ISC_MAGIC('U', 'c', 't', 'x')
65 #define UCTX_VALID(c) ISC_MAGIC_VALID(c, UCTX_MAGIC)
66 
67 #define MAX_RESTARTS 16
68 
69 #ifdef TUNE_LARGE
70 #define RESOLVER_NTASKS 523
71 #else /* ifdef TUNE_LARGE */
72 #define RESOLVER_NTASKS 31
73 #endif /* TUNE_LARGE */
74 
75 #define CHECK(r)                             \
76 	do {                                 \
77 		result = (r);                \
78 		if (result != ISC_R_SUCCESS) \
79 			goto cleanup;        \
80 	} while (0)
81 
82 /*%
83  * DNS client object
84  */
85 struct dns_client {
86 	/* Unlocked */
87 	unsigned int magic;
88 	unsigned int attributes;
89 	isc_mutex_t lock;
90 	isc_mem_t *mctx;
91 	isc_appctx_t *actx;
92 	isc_taskmgr_t *taskmgr;
93 	isc_task_t *task;
94 	isc_socketmgr_t *socketmgr;
95 	isc_timermgr_t *timermgr;
96 	dns_dispatchmgr_t *dispatchmgr;
97 	dns_dispatch_t *dispatchv4;
98 	dns_dispatch_t *dispatchv6;
99 
100 	unsigned int update_timeout;
101 	unsigned int update_udptimeout;
102 	unsigned int update_udpretries;
103 	unsigned int find_timeout;
104 	unsigned int find_udpretries;
105 
106 	isc_refcount_t references;
107 
108 	/* Locked */
109 	dns_viewlist_t viewlist;
110 	ISC_LIST(struct resctx) resctxs;
111 	ISC_LIST(struct reqctx) reqctxs;
112 	ISC_LIST(struct updatectx) updatectxs;
113 };
114 
115 /*%
116  * Timeout/retry constants for dynamic update borrowed from nsupdate
117  */
118 #define DEF_UPDATE_TIMEOUT    300
119 #define MIN_UPDATE_TIMEOUT    30
120 #define DEF_UPDATE_UDPTIMEOUT 3
121 #define DEF_UPDATE_UDPRETRIES 3
122 
123 #define DEF_FIND_TIMEOUT    5
124 #define DEF_FIND_UDPRETRIES 3
125 
126 #define DNS_CLIENTATTR_OWNCTX 0x01
127 
128 /*%
129  * Internal state for a single name resolution procedure
130  */
131 typedef struct resctx {
132 	/* Unlocked */
133 	unsigned int magic;
134 	isc_mutex_t lock;
135 	dns_client_t *client;
136 	bool want_dnssec;
137 	bool want_validation;
138 	bool want_cdflag;
139 	bool want_tcp;
140 
141 	/* Locked */
142 	ISC_LINK(struct resctx) link;
143 	isc_task_t *task;
144 	dns_view_t *view;
145 	unsigned int restarts;
146 	dns_fixedname_t name;
147 	dns_rdatatype_t type;
148 	dns_fetch_t *fetch;
149 	dns_namelist_t namelist;
150 	isc_result_t result;
151 	dns_clientresevent_t *event;
152 	bool canceled;
153 	dns_rdataset_t *rdataset;
154 	dns_rdataset_t *sigrdataset;
155 } resctx_t;
156 
157 /*%
158  * Argument of an internal event for synchronous name resolution.
159  */
160 typedef struct resarg {
161 	/* Unlocked */
162 	isc_appctx_t *actx;
163 	dns_client_t *client;
164 	isc_mutex_t lock;
165 
166 	/* Locked */
167 	isc_result_t result;
168 	isc_result_t vresult;
169 	dns_namelist_t *namelist;
170 	dns_clientrestrans_t *trans;
171 	bool canceled;
172 } resarg_t;
173 
174 /*%
175  * Internal state for a single DNS request
176  */
177 typedef struct reqctx {
178 	/* Unlocked */
179 	unsigned int magic;
180 	isc_mutex_t lock;
181 	dns_client_t *client;
182 	unsigned int parseoptions;
183 
184 	/* Locked */
185 	ISC_LINK(struct reqctx) link;
186 	bool canceled;
187 	dns_tsigkey_t *tsigkey;
188 	dns_request_t *request;
189 	dns_clientreqevent_t *event;
190 } reqctx_t;
191 
192 /*%
193  * Argument of an internal event for synchronous DNS request.
194  */
195 typedef struct reqarg {
196 	/* Unlocked */
197 	isc_appctx_t *actx;
198 	dns_client_t *client;
199 	isc_mutex_t lock;
200 
201 	/* Locked */
202 	isc_result_t result;
203 	dns_clientreqtrans_t *trans;
204 	bool canceled;
205 } reqarg_t;
206 
207 /*%
208  * Argument of an internal event for synchronous name resolution.
209  */
210 typedef struct updatearg {
211 	/* Unlocked */
212 	isc_appctx_t *actx;
213 	dns_client_t *client;
214 	isc_mutex_t lock;
215 
216 	/* Locked */
217 	isc_result_t result;
218 	dns_clientupdatetrans_t *trans;
219 	bool canceled;
220 } updatearg_t;
221 
222 /*%
223  * Internal state for a single dynamic update procedure
224  */
225 typedef struct updatectx {
226 	/* Unlocked */
227 	unsigned int magic;
228 	isc_mutex_t lock;
229 	dns_client_t *client;
230 	bool want_tcp;
231 
232 	/* Locked */
233 	dns_request_t *updatereq;
234 	dns_request_t *soareq;
235 	dns_clientrestrans_t *restrans;
236 	dns_clientrestrans_t *restrans2;
237 	bool canceled;
238 
239 	/* Task Locked */
240 	ISC_LINK(struct updatectx) link;
241 	dns_clientupdatestate_t state;
242 	dns_rdataclass_t rdclass;
243 	dns_view_t *view;
244 	dns_message_t *updatemsg;
245 	dns_message_t *soaquery;
246 	dns_clientupdateevent_t *event;
247 	dns_tsigkey_t *tsigkey;
248 	dst_key_t *sig0key;
249 	dns_name_t *firstname;
250 	dns_name_t soaqname;
251 	dns_fixedname_t zonefname;
252 	dns_name_t *zonename;
253 	isc_sockaddrlist_t servers;
254 	unsigned int nservers;
255 	isc_sockaddr_t *currentserver;
256 	struct updatectx *bp4;
257 	struct updatectx *bp6;
258 } updatectx_t;
259 
260 static isc_result_t
261 request_soa(updatectx_t *uctx);
262 static void
263 client_resfind(resctx_t *rctx, dns_fetchevent_t *event);
264 static isc_result_t
265 send_update(updatectx_t *uctx);
266 
267 /*
268  * Try honoring the operating system's preferred ephemeral port range.
269  */
270 static isc_result_t
271 setsourceports(isc_mem_t *mctx, dns_dispatchmgr_t *manager) {
272 	isc_portset_t *v4portset = NULL, *v6portset = NULL;
273 	in_port_t udpport_low, udpport_high;
274 	isc_result_t result;
275 
276 	result = isc_portset_create(mctx, &v4portset);
277 	if (result != ISC_R_SUCCESS) {
278 		goto cleanup;
279 	}
280 	result = isc_net_getudpportrange(AF_INET, &udpport_low, &udpport_high);
281 	if (result != ISC_R_SUCCESS) {
282 		goto cleanup;
283 	}
284 	isc_portset_addrange(v4portset, udpport_low, udpport_high);
285 
286 	result = isc_portset_create(mctx, &v6portset);
287 	if (result != ISC_R_SUCCESS) {
288 		goto cleanup;
289 	}
290 	result = isc_net_getudpportrange(AF_INET6, &udpport_low, &udpport_high);
291 	if (result != ISC_R_SUCCESS) {
292 		goto cleanup;
293 	}
294 	isc_portset_addrange(v6portset, udpport_low, udpport_high);
295 
296 	result = dns_dispatchmgr_setavailports(manager, v4portset, v6portset);
297 
298 cleanup:
299 	if (v4portset != NULL) {
300 		isc_portset_destroy(mctx, &v4portset);
301 	}
302 	if (v6portset != NULL) {
303 		isc_portset_destroy(mctx, &v6portset);
304 	}
305 
306 	return (result);
307 }
308 
309 static isc_result_t
310 getudpdispatch(int family, dns_dispatchmgr_t *dispatchmgr,
311 	       isc_socketmgr_t *socketmgr, isc_taskmgr_t *taskmgr,
312 	       bool is_shared, dns_dispatch_t **dispp,
313 	       const isc_sockaddr_t *localaddr) {
314 	unsigned int attrs, attrmask;
315 	dns_dispatch_t *disp;
316 	unsigned buffersize, maxbuffers, maxrequests, buckets, increment;
317 	isc_result_t result;
318 	isc_sockaddr_t anyaddr;
319 
320 	attrs = 0;
321 	attrs |= DNS_DISPATCHATTR_UDP;
322 	switch (family) {
323 	case AF_INET:
324 		attrs |= DNS_DISPATCHATTR_IPV4;
325 		break;
326 	case AF_INET6:
327 		attrs |= DNS_DISPATCHATTR_IPV6;
328 		break;
329 	default:
330 		INSIST(0);
331 		ISC_UNREACHABLE();
332 	}
333 	attrmask = 0;
334 	attrmask |= DNS_DISPATCHATTR_UDP;
335 	attrmask |= DNS_DISPATCHATTR_TCP;
336 	attrmask |= DNS_DISPATCHATTR_IPV4;
337 	attrmask |= DNS_DISPATCHATTR_IPV6;
338 
339 	if (localaddr == NULL) {
340 		isc_sockaddr_anyofpf(&anyaddr, family);
341 		localaddr = &anyaddr;
342 	}
343 
344 	buffersize = 4096;
345 	maxbuffers = is_shared ? 1000 : 8;
346 	maxrequests = 32768;
347 	buckets = is_shared ? 16411 : 3;
348 	increment = is_shared ? 16433 : 5;
349 
350 	disp = NULL;
351 	result = dns_dispatch_getudp(dispatchmgr, socketmgr, taskmgr, localaddr,
352 				     buffersize, maxbuffers, maxrequests,
353 				     buckets, increment, attrs, attrmask,
354 				     &disp);
355 	if (result == ISC_R_SUCCESS) {
356 		*dispp = disp;
357 	}
358 
359 	return (result);
360 }
361 
362 static isc_result_t
363 createview(isc_mem_t *mctx, dns_rdataclass_t rdclass, unsigned int options,
364 	   isc_taskmgr_t *taskmgr, unsigned int ntasks,
365 	   isc_socketmgr_t *socketmgr, isc_timermgr_t *timermgr,
366 	   dns_dispatchmgr_t *dispatchmgr, dns_dispatch_t *dispatchv4,
367 	   dns_dispatch_t *dispatchv6, dns_view_t **viewp) {
368 	isc_result_t result;
369 	dns_view_t *view = NULL;
370 	const char *dbtype;
371 
372 	result = dns_view_create(mctx, rdclass, DNS_CLIENTVIEW_NAME, &view);
373 	if (result != ISC_R_SUCCESS) {
374 		return (result);
375 	}
376 
377 	/* Initialize view security roots */
378 	result = dns_view_initsecroots(view, mctx);
379 	if (result != ISC_R_SUCCESS) {
380 		dns_view_detach(&view);
381 		return (result);
382 	}
383 
384 	result = dns_view_createresolver(view, taskmgr, ntasks, 1, socketmgr,
385 					 timermgr, 0, dispatchmgr, dispatchv4,
386 					 dispatchv6);
387 	if (result != ISC_R_SUCCESS) {
388 		dns_view_detach(&view);
389 		return (result);
390 	}
391 
392 	/*
393 	 * Set cache DB.
394 	 * XXX: it may be better if specific DB implementations can be
395 	 * specified via some configuration knob.
396 	 */
397 	if ((options & DNS_CLIENTCREATEOPT_USECACHE) != 0) {
398 		dbtype = "rbt";
399 	} else {
400 		dbtype = "ecdb";
401 	}
402 	result = dns_db_create(mctx, dbtype, dns_rootname, dns_dbtype_cache,
403 			       rdclass, 0, NULL, &view->cachedb);
404 	if (result != ISC_R_SUCCESS) {
405 		dns_view_detach(&view);
406 		return (result);
407 	}
408 
409 	*viewp = view;
410 	return (ISC_R_SUCCESS);
411 }
412 
413 isc_result_t
414 dns_client_create(dns_client_t **clientp, unsigned int options) {
415 	isc_result_t result;
416 	isc_mem_t *mctx = NULL;
417 	isc_appctx_t *actx = NULL;
418 	isc_taskmgr_t *taskmgr = NULL;
419 	isc_socketmgr_t *socketmgr = NULL;
420 	isc_timermgr_t *timermgr = NULL;
421 #if 0
422 	/* XXXMPA add debug logging support */
423 	isc_log_t *lctx = NULL;
424 	isc_logconfig_t *logconfig = NULL;
425 	unsigned int logdebuglevel = 0;
426 #endif /* if 0 */
427 
428 	isc_mem_create(&mctx);
429 	result = isc_appctx_create(mctx, &actx);
430 	if (result != ISC_R_SUCCESS) {
431 		goto cleanup;
432 	}
433 	result = isc_app_ctxstart(actx);
434 	if (result != ISC_R_SUCCESS) {
435 		goto cleanup;
436 	}
437 	result = isc_taskmgr_createinctx(mctx, 1, 0, &taskmgr);
438 	if (result != ISC_R_SUCCESS) {
439 		goto cleanup;
440 	}
441 	result = isc_socketmgr_createinctx(mctx, &socketmgr);
442 	if (result != ISC_R_SUCCESS) {
443 		goto cleanup;
444 	}
445 	result = isc_timermgr_createinctx(mctx, &timermgr);
446 	if (result != ISC_R_SUCCESS) {
447 		goto cleanup;
448 	}
449 #if 0
450 	isc_log_create(mctx, &lctx, &logconfig);
451 	isc_log_setcontext(lctx);
452 	dns_log_init(lctx);
453 	dns_log_setcontext(lctx);
454 	result = isc_log_usechannel(logconfig, "default_debug", NULL, NULL);
455 	if (result != ISC_R_SUCCESS) {
456 		goto cleanup;
457 	}
458 	isc_log_setdebuglevel(lctx, logdebuglevel);
459 #endif /* if 0 */
460 	result = dns_client_createx(mctx, actx, taskmgr, socketmgr, timermgr,
461 				    options, clientp, NULL, NULL);
462 	if (result != ISC_R_SUCCESS) {
463 		goto cleanup;
464 	}
465 
466 	(*clientp)->attributes |= DNS_CLIENTATTR_OWNCTX;
467 
468 	/* client has its own reference to mctx, so we can detach it here */
469 	isc_mem_detach(&mctx);
470 
471 	return (ISC_R_SUCCESS);
472 
473 cleanup:
474 	if (taskmgr != NULL) {
475 		isc_taskmgr_destroy(&taskmgr);
476 	}
477 	if (timermgr != NULL) {
478 		isc_timermgr_destroy(&timermgr);
479 	}
480 	if (socketmgr != NULL) {
481 		isc_socketmgr_destroy(&socketmgr);
482 	}
483 	if (actx != NULL) {
484 		isc_appctx_destroy(&actx);
485 	}
486 	isc_mem_detach(&mctx);
487 
488 	return (result);
489 }
490 
491 isc_result_t
492 dns_client_createx(isc_mem_t *mctx, isc_appctx_t *actx, isc_taskmgr_t *taskmgr,
493 		   isc_socketmgr_t *socketmgr, isc_timermgr_t *timermgr,
494 		   unsigned int options, dns_client_t **clientp,
495 		   const isc_sockaddr_t *localaddr4,
496 		   const isc_sockaddr_t *localaddr6) {
497 	dns_client_t *client;
498 	isc_result_t result;
499 	dns_dispatchmgr_t *dispatchmgr = NULL;
500 	dns_dispatch_t *dispatchv4 = NULL;
501 	dns_dispatch_t *dispatchv6 = NULL;
502 	dns_view_t *view = NULL;
503 
504 	REQUIRE(mctx != NULL);
505 	REQUIRE(taskmgr != NULL);
506 	REQUIRE(timermgr != NULL);
507 	REQUIRE(socketmgr != NULL);
508 	REQUIRE(clientp != NULL && *clientp == NULL);
509 
510 	client = isc_mem_get(mctx, sizeof(*client));
511 
512 	isc_mutex_init(&client->lock);
513 
514 	client->actx = actx;
515 	client->taskmgr = taskmgr;
516 	client->socketmgr = socketmgr;
517 	client->timermgr = timermgr;
518 
519 	client->task = NULL;
520 	result = isc_task_create(client->taskmgr, 0, &client->task);
521 	if (result != ISC_R_SUCCESS) {
522 		goto cleanup_lock;
523 	}
524 
525 	result = dns_dispatchmgr_create(mctx, &dispatchmgr);
526 	if (result != ISC_R_SUCCESS) {
527 		goto cleanup_task;
528 	}
529 	client->dispatchmgr = dispatchmgr;
530 	(void)setsourceports(mctx, dispatchmgr);
531 
532 	/*
533 	 * If only one address family is specified, use it.
534 	 * If neither family is specified, or if both are, use both.
535 	 */
536 	client->dispatchv4 = NULL;
537 	if (localaddr4 != NULL || localaddr6 == NULL) {
538 		result = getudpdispatch(AF_INET, dispatchmgr, socketmgr,
539 					taskmgr, true, &dispatchv4, localaddr4);
540 		if (result == ISC_R_SUCCESS) {
541 			client->dispatchv4 = dispatchv4;
542 		}
543 	}
544 
545 	client->dispatchv6 = NULL;
546 	if (localaddr6 != NULL || localaddr4 == NULL) {
547 		result = getudpdispatch(AF_INET6, dispatchmgr, socketmgr,
548 					taskmgr, true, &dispatchv6, localaddr6);
549 		if (result == ISC_R_SUCCESS) {
550 			client->dispatchv6 = dispatchv6;
551 		}
552 	}
553 
554 	/* We need at least one of the dispatchers */
555 	if (dispatchv4 == NULL && dispatchv6 == NULL) {
556 		INSIST(result != ISC_R_SUCCESS);
557 		goto cleanup_dispatchmgr;
558 	}
559 
560 	isc_refcount_init(&client->references, 1);
561 
562 	/* Create the default view for class IN */
563 	result = createview(mctx, dns_rdataclass_in, options, taskmgr,
564 			    RESOLVER_NTASKS, socketmgr, timermgr, dispatchmgr,
565 			    dispatchv4, dispatchv6, &view);
566 	if (result != ISC_R_SUCCESS) {
567 		goto cleanup_references;
568 	}
569 
570 	ISC_LIST_INIT(client->viewlist);
571 	ISC_LIST_APPEND(client->viewlist, view, link);
572 
573 	dns_view_freeze(view); /* too early? */
574 
575 	ISC_LIST_INIT(client->resctxs);
576 	ISC_LIST_INIT(client->reqctxs);
577 	ISC_LIST_INIT(client->updatectxs);
578 
579 	client->mctx = NULL;
580 	isc_mem_attach(mctx, &client->mctx);
581 
582 	client->update_timeout = DEF_UPDATE_TIMEOUT;
583 	client->update_udptimeout = DEF_UPDATE_UDPTIMEOUT;
584 	client->update_udpretries = DEF_UPDATE_UDPRETRIES;
585 	client->find_timeout = DEF_FIND_TIMEOUT;
586 	client->find_udpretries = DEF_FIND_UDPRETRIES;
587 	client->attributes = 0;
588 
589 	client->magic = DNS_CLIENT_MAGIC;
590 
591 	*clientp = client;
592 
593 	return (ISC_R_SUCCESS);
594 
595 cleanup_references:
596 	isc_refcount_decrementz(&client->references);
597 	isc_refcount_destroy(&client->references);
598 cleanup_dispatchmgr:
599 	if (dispatchv4 != NULL) {
600 		dns_dispatch_detach(&dispatchv4);
601 	}
602 	if (dispatchv6 != NULL) {
603 		dns_dispatch_detach(&dispatchv6);
604 	}
605 	dns_dispatchmgr_destroy(&dispatchmgr);
606 cleanup_task:
607 	isc_task_detach(&client->task);
608 cleanup_lock:
609 	isc_mutex_destroy(&client->lock);
610 	isc_mem_put(mctx, client, sizeof(*client));
611 
612 	return (result);
613 }
614 
615 static void
616 destroyclient(dns_client_t *client) {
617 	dns_view_t *view;
618 
619 	isc_refcount_destroy(&client->references);
620 
621 	while ((view = ISC_LIST_HEAD(client->viewlist)) != NULL) {
622 		ISC_LIST_UNLINK(client->viewlist, view, link);
623 		dns_view_detach(&view);
624 	}
625 
626 	if (client->dispatchv4 != NULL) {
627 		dns_dispatch_detach(&client->dispatchv4);
628 	}
629 	if (client->dispatchv6 != NULL) {
630 		dns_dispatch_detach(&client->dispatchv6);
631 	}
632 
633 	dns_dispatchmgr_destroy(&client->dispatchmgr);
634 
635 	isc_task_detach(&client->task);
636 
637 	/*
638 	 * If the client has created its own running environments,
639 	 * destroy them.
640 	 */
641 	if ((client->attributes & DNS_CLIENTATTR_OWNCTX) != 0) {
642 		isc_taskmgr_destroy(&client->taskmgr);
643 		isc_timermgr_destroy(&client->timermgr);
644 		isc_socketmgr_destroy(&client->socketmgr);
645 
646 		isc_app_ctxfinish(client->actx);
647 		isc_appctx_destroy(&client->actx);
648 	}
649 
650 	isc_mutex_destroy(&client->lock);
651 	client->magic = 0;
652 
653 	isc_mem_putanddetach(&client->mctx, client, sizeof(*client));
654 }
655 
656 void
657 dns_client_destroy(dns_client_t **clientp) {
658 	dns_client_t *client;
659 
660 	REQUIRE(clientp != NULL);
661 	client = *clientp;
662 	*clientp = NULL;
663 	REQUIRE(DNS_CLIENT_VALID(client));
664 
665 	if (isc_refcount_decrement(&client->references) == 1) {
666 		destroyclient(client);
667 	}
668 }
669 
670 isc_result_t
671 dns_client_setservers(dns_client_t *client, dns_rdataclass_t rdclass,
672 		      const dns_name_t *name_space, isc_sockaddrlist_t *addrs) {
673 	isc_result_t result;
674 	dns_view_t *view = NULL;
675 
676 	REQUIRE(DNS_CLIENT_VALID(client));
677 	REQUIRE(addrs != NULL);
678 
679 	if (name_space == NULL) {
680 		name_space = dns_rootname;
681 	}
682 
683 	LOCK(&client->lock);
684 	result = dns_viewlist_find(&client->viewlist, DNS_CLIENTVIEW_NAME,
685 				   rdclass, &view);
686 	if (result != ISC_R_SUCCESS) {
687 		UNLOCK(&client->lock);
688 		return (result);
689 	}
690 	UNLOCK(&client->lock);
691 
692 	result = dns_fwdtable_add(view->fwdtable, name_space, addrs,
693 				  dns_fwdpolicy_only);
694 
695 	dns_view_detach(&view);
696 
697 	return (result);
698 }
699 
700 isc_result_t
701 dns_client_clearservers(dns_client_t *client, dns_rdataclass_t rdclass,
702 			const dns_name_t *name_space) {
703 	isc_result_t result;
704 	dns_view_t *view = NULL;
705 
706 	REQUIRE(DNS_CLIENT_VALID(client));
707 
708 	if (name_space == NULL) {
709 		name_space = dns_rootname;
710 	}
711 
712 	LOCK(&client->lock);
713 	result = dns_viewlist_find(&client->viewlist, DNS_CLIENTVIEW_NAME,
714 				   rdclass, &view);
715 	if (result != ISC_R_SUCCESS) {
716 		UNLOCK(&client->lock);
717 		return (result);
718 	}
719 	UNLOCK(&client->lock);
720 
721 	result = dns_fwdtable_delete(view->fwdtable, name_space);
722 
723 	dns_view_detach(&view);
724 
725 	return (result);
726 }
727 
728 static isc_result_t
729 getrdataset(isc_mem_t *mctx, dns_rdataset_t **rdatasetp) {
730 	dns_rdataset_t *rdataset;
731 
732 	REQUIRE(mctx != NULL);
733 	REQUIRE(rdatasetp != NULL && *rdatasetp == NULL);
734 
735 	rdataset = isc_mem_get(mctx, sizeof(*rdataset));
736 
737 	dns_rdataset_init(rdataset);
738 
739 	*rdatasetp = rdataset;
740 
741 	return (ISC_R_SUCCESS);
742 }
743 
744 static void
745 putrdataset(isc_mem_t *mctx, dns_rdataset_t **rdatasetp) {
746 	dns_rdataset_t *rdataset;
747 
748 	REQUIRE(rdatasetp != NULL);
749 	rdataset = *rdatasetp;
750 	*rdatasetp = NULL;
751 	REQUIRE(rdataset != NULL);
752 
753 	if (dns_rdataset_isassociated(rdataset)) {
754 		dns_rdataset_disassociate(rdataset);
755 	}
756 
757 	isc_mem_put(mctx, rdataset, sizeof(*rdataset));
758 }
759 
760 static void
761 fetch_done(isc_task_t *task, isc_event_t *event) {
762 	resctx_t *rctx = event->ev_arg;
763 	dns_fetchevent_t *fevent;
764 
765 	REQUIRE(event->ev_type == DNS_EVENT_FETCHDONE);
766 	REQUIRE(RCTX_VALID(rctx));
767 	REQUIRE(rctx->task == task);
768 	fevent = (dns_fetchevent_t *)event;
769 
770 	client_resfind(rctx, fevent);
771 }
772 
773 static inline isc_result_t
774 start_fetch(resctx_t *rctx) {
775 	isc_result_t result;
776 	int fopts = 0;
777 
778 	/*
779 	 * The caller must be holding the rctx's lock.
780 	 */
781 
782 	REQUIRE(rctx->fetch == NULL);
783 
784 	if (!rctx->want_cdflag) {
785 		fopts |= DNS_FETCHOPT_NOCDFLAG;
786 	}
787 	if (!rctx->want_validation) {
788 		fopts |= DNS_FETCHOPT_NOVALIDATE;
789 	}
790 	if (rctx->want_tcp) {
791 		fopts |= DNS_FETCHOPT_TCP;
792 	}
793 
794 	result = dns_resolver_createfetch(
795 		rctx->view->resolver, dns_fixedname_name(&rctx->name),
796 		rctx->type, NULL, NULL, NULL, NULL, 0, fopts, 0, NULL,
797 		rctx->task, fetch_done, rctx, rctx->rdataset, rctx->sigrdataset,
798 		&rctx->fetch);
799 
800 	return (result);
801 }
802 
803 static isc_result_t
804 view_find(resctx_t *rctx, dns_db_t **dbp, dns_dbnode_t **nodep,
805 	  dns_name_t *foundname) {
806 	isc_result_t result;
807 	dns_name_t *name = dns_fixedname_name(&rctx->name);
808 	dns_rdatatype_t type;
809 
810 	if (rctx->type == dns_rdatatype_rrsig) {
811 		type = dns_rdatatype_any;
812 	} else {
813 		type = rctx->type;
814 	}
815 
816 	result = dns_view_find(rctx->view, name, type, 0, 0, false, false, dbp,
817 			       nodep, foundname, rctx->rdataset,
818 			       rctx->sigrdataset);
819 
820 	return (result);
821 }
822 
823 static void
824 client_resfind(resctx_t *rctx, dns_fetchevent_t *event) {
825 	isc_mem_t *mctx;
826 	isc_result_t tresult, result = ISC_R_SUCCESS;
827 	isc_result_t vresult = ISC_R_SUCCESS;
828 	bool want_restart;
829 	bool send_event = false;
830 	dns_name_t *name, *prefix;
831 	dns_fixedname_t foundname, fixed;
832 	dns_rdataset_t *trdataset;
833 	dns_rdata_t rdata = DNS_RDATA_INIT;
834 	unsigned int nlabels;
835 	int order;
836 	dns_namereln_t namereln;
837 	dns_rdata_cname_t cname;
838 	dns_rdata_dname_t dname;
839 
840 	REQUIRE(RCTX_VALID(rctx));
841 
842 	LOCK(&rctx->lock);
843 
844 	mctx = rctx->view->mctx;
845 
846 	name = dns_fixedname_name(&rctx->name);
847 
848 	do {
849 		dns_name_t *fname = NULL;
850 		dns_name_t *ansname = NULL;
851 		dns_db_t *db = NULL;
852 		dns_dbnode_t *node = NULL;
853 
854 		rctx->restarts++;
855 		want_restart = false;
856 
857 		if (event == NULL && !rctx->canceled) {
858 			fname = dns_fixedname_initname(&foundname);
859 			INSIST(!dns_rdataset_isassociated(rctx->rdataset));
860 			INSIST(rctx->sigrdataset == NULL ||
861 			       !dns_rdataset_isassociated(rctx->sigrdataset));
862 			result = view_find(rctx, &db, &node, fname);
863 			if (result == ISC_R_NOTFOUND) {
864 				/*
865 				 * We don't know anything about the name.
866 				 * Launch a fetch.
867 				 */
868 				if (node != NULL) {
869 					INSIST(db != NULL);
870 					dns_db_detachnode(db, &node);
871 				}
872 				if (db != NULL) {
873 					dns_db_detach(&db);
874 				}
875 				result = start_fetch(rctx);
876 				if (result != ISC_R_SUCCESS) {
877 					putrdataset(mctx, &rctx->rdataset);
878 					if (rctx->sigrdataset != NULL) {
879 						putrdataset(mctx,
880 							    &rctx->sigrdataset);
881 					}
882 					send_event = true;
883 				}
884 				goto done;
885 			}
886 		} else {
887 			INSIST(event != NULL);
888 			INSIST(event->fetch == rctx->fetch);
889 			dns_resolver_destroyfetch(&rctx->fetch);
890 			db = event->db;
891 			node = event->node;
892 			result = event->result;
893 			vresult = event->vresult;
894 			fname = dns_fixedname_name(&event->foundname);
895 			INSIST(event->rdataset == rctx->rdataset);
896 			INSIST(event->sigrdataset == rctx->sigrdataset);
897 		}
898 
899 		/*
900 		 * If we've been canceled, forget about the result.
901 		 */
902 		if (rctx->canceled) {
903 			result = ISC_R_CANCELED;
904 		} else {
905 			/*
906 			 * Otherwise, get some resource for copying the
907 			 * result.
908 			 */
909 			dns_name_t *aname = dns_fixedname_name(&rctx->name);
910 
911 			ansname = isc_mem_get(mctx, sizeof(*ansname));
912 			dns_name_init(ansname, NULL);
913 
914 			dns_name_dup(aname, mctx, ansname);
915 		}
916 
917 		switch (result) {
918 		case ISC_R_SUCCESS:
919 			send_event = true;
920 			/*
921 			 * This case is handled in the main line below.
922 			 */
923 			break;
924 		case DNS_R_CNAME:
925 			/*
926 			 * Add the CNAME to the answer list.
927 			 */
928 			trdataset = rctx->rdataset;
929 			ISC_LIST_APPEND(ansname->list, rctx->rdataset, link);
930 			rctx->rdataset = NULL;
931 			if (rctx->sigrdataset != NULL) {
932 				ISC_LIST_APPEND(ansname->list,
933 						rctx->sigrdataset, link);
934 				rctx->sigrdataset = NULL;
935 			}
936 			ISC_LIST_APPEND(rctx->namelist, ansname, link);
937 			ansname = NULL;
938 
939 			/*
940 			 * Copy the CNAME's target into the lookup's
941 			 * query name and start over.
942 			 */
943 			tresult = dns_rdataset_first(trdataset);
944 			if (tresult != ISC_R_SUCCESS) {
945 				goto done;
946 			}
947 			dns_rdataset_current(trdataset, &rdata);
948 			tresult = dns_rdata_tostruct(&rdata, &cname, NULL);
949 			dns_rdata_reset(&rdata);
950 			if (tresult != ISC_R_SUCCESS) {
951 				goto done;
952 			}
953 			dns_name_copynf(&cname.cname, name);
954 			dns_rdata_freestruct(&cname);
955 			want_restart = true;
956 			goto done;
957 		case DNS_R_DNAME:
958 			/*
959 			 * Add the DNAME to the answer list.
960 			 */
961 			trdataset = rctx->rdataset;
962 			ISC_LIST_APPEND(ansname->list, rctx->rdataset, link);
963 			rctx->rdataset = NULL;
964 			if (rctx->sigrdataset != NULL) {
965 				ISC_LIST_APPEND(ansname->list,
966 						rctx->sigrdataset, link);
967 				rctx->sigrdataset = NULL;
968 			}
969 			ISC_LIST_APPEND(rctx->namelist, ansname, link);
970 			ansname = NULL;
971 
972 			namereln = dns_name_fullcompare(name, fname, &order,
973 							&nlabels);
974 			INSIST(namereln == dns_namereln_subdomain);
975 			/*
976 			 * Get the target name of the DNAME.
977 			 */
978 			tresult = dns_rdataset_first(trdataset);
979 			if (tresult != ISC_R_SUCCESS) {
980 				result = tresult;
981 				goto done;
982 			}
983 			dns_rdataset_current(trdataset, &rdata);
984 			tresult = dns_rdata_tostruct(&rdata, &dname, NULL);
985 			dns_rdata_reset(&rdata);
986 			if (tresult != ISC_R_SUCCESS) {
987 				result = tresult;
988 				goto done;
989 			}
990 			/*
991 			 * Construct the new query name and start over.
992 			 */
993 			prefix = dns_fixedname_initname(&fixed);
994 			dns_name_split(name, nlabels, prefix, NULL);
995 			tresult = dns_name_concatenate(prefix, &dname.dname,
996 						       name, NULL);
997 			dns_rdata_freestruct(&dname);
998 			if (tresult == ISC_R_SUCCESS) {
999 				want_restart = true;
1000 			} else {
1001 				result = tresult;
1002 			}
1003 			goto done;
1004 		case DNS_R_NCACHENXDOMAIN:
1005 		case DNS_R_NCACHENXRRSET:
1006 			ISC_LIST_APPEND(ansname->list, rctx->rdataset, link);
1007 			ISC_LIST_APPEND(rctx->namelist, ansname, link);
1008 			ansname = NULL;
1009 			rctx->rdataset = NULL;
1010 			/* What about sigrdataset? */
1011 			if (rctx->sigrdataset != NULL) {
1012 				putrdataset(mctx, &rctx->sigrdataset);
1013 			}
1014 			send_event = true;
1015 			goto done;
1016 		default:
1017 			if (rctx->rdataset != NULL) {
1018 				putrdataset(mctx, &rctx->rdataset);
1019 			}
1020 			if (rctx->sigrdataset != NULL) {
1021 				putrdataset(mctx, &rctx->sigrdataset);
1022 			}
1023 			send_event = true;
1024 			goto done;
1025 		}
1026 
1027 		if (rctx->type == dns_rdatatype_any) {
1028 			int n = 0;
1029 			dns_rdatasetiter_t *rdsiter = NULL;
1030 
1031 			tresult = dns_db_allrdatasets(db, node, NULL, 0,
1032 						      &rdsiter);
1033 			if (tresult != ISC_R_SUCCESS) {
1034 				result = tresult;
1035 				goto done;
1036 			}
1037 
1038 			tresult = dns_rdatasetiter_first(rdsiter);
1039 			while (tresult == ISC_R_SUCCESS) {
1040 				dns_rdatasetiter_current(rdsiter,
1041 							 rctx->rdataset);
1042 				if (rctx->rdataset->type != 0) {
1043 					ISC_LIST_APPEND(ansname->list,
1044 							rctx->rdataset, link);
1045 					n++;
1046 					rctx->rdataset = NULL;
1047 				} else {
1048 					/*
1049 					 * We're not interested in this
1050 					 * rdataset.
1051 					 */
1052 					dns_rdataset_disassociate(
1053 						rctx->rdataset);
1054 				}
1055 				tresult = dns_rdatasetiter_next(rdsiter);
1056 
1057 				if (tresult == ISC_R_SUCCESS &&
1058 				    rctx->rdataset == NULL) {
1059 					tresult = getrdataset(mctx,
1060 							      &rctx->rdataset);
1061 					if (tresult != ISC_R_SUCCESS) {
1062 						result = tresult;
1063 						POST(result);
1064 						break;
1065 					}
1066 				}
1067 			}
1068 			if (rctx->rdataset != NULL) {
1069 				putrdataset(mctx, &rctx->rdataset);
1070 			}
1071 			if (rctx->sigrdataset != NULL) {
1072 				putrdataset(mctx, &rctx->sigrdataset);
1073 			}
1074 			if (n == 0) {
1075 				/*
1076 				 * We didn't match any rdatasets (which means
1077 				 * something went wrong in this
1078 				 * implementation).
1079 				 */
1080 				result = DNS_R_SERVFAIL; /* better code? */
1081 				POST(result);
1082 			} else {
1083 				ISC_LIST_APPEND(rctx->namelist, ansname, link);
1084 				ansname = NULL;
1085 			}
1086 			dns_rdatasetiter_destroy(&rdsiter);
1087 			if (tresult != ISC_R_NOMORE) {
1088 				result = DNS_R_SERVFAIL; /* ditto */
1089 			} else {
1090 				result = ISC_R_SUCCESS;
1091 			}
1092 			goto done;
1093 		} else {
1094 			/*
1095 			 * This is the "normal" case -- an ordinary question
1096 			 * to which we've got the answer.
1097 			 */
1098 			ISC_LIST_APPEND(ansname->list, rctx->rdataset, link);
1099 			rctx->rdataset = NULL;
1100 			if (rctx->sigrdataset != NULL) {
1101 				ISC_LIST_APPEND(ansname->list,
1102 						rctx->sigrdataset, link);
1103 				rctx->sigrdataset = NULL;
1104 			}
1105 			ISC_LIST_APPEND(rctx->namelist, ansname, link);
1106 			ansname = NULL;
1107 		}
1108 
1109 	done:
1110 		/*
1111 		 * Free temporary resources
1112 		 */
1113 		if (ansname != NULL) {
1114 			dns_rdataset_t *rdataset;
1115 
1116 			while ((rdataset = ISC_LIST_HEAD(ansname->list)) !=
1117 			       NULL) {
1118 				ISC_LIST_UNLINK(ansname->list, rdataset, link);
1119 				putrdataset(mctx, &rdataset);
1120 			}
1121 			dns_name_free(ansname, mctx);
1122 			isc_mem_put(mctx, ansname, sizeof(*ansname));
1123 		}
1124 
1125 		if (node != NULL) {
1126 			dns_db_detachnode(db, &node);
1127 		}
1128 		if (db != NULL) {
1129 			dns_db_detach(&db);
1130 		}
1131 		if (event != NULL) {
1132 			isc_event_free(ISC_EVENT_PTR(&event));
1133 		}
1134 
1135 		/*
1136 		 * Limit the number of restarts.
1137 		 */
1138 		if (want_restart && rctx->restarts == MAX_RESTARTS) {
1139 			want_restart = false;
1140 			result = ISC_R_QUOTA;
1141 			send_event = true;
1142 		}
1143 
1144 		/*
1145 		 * Prepare further find with new resources
1146 		 */
1147 		if (want_restart) {
1148 			INSIST(rctx->rdataset == NULL &&
1149 			       rctx->sigrdataset == NULL);
1150 
1151 			result = getrdataset(mctx, &rctx->rdataset);
1152 			if (result == ISC_R_SUCCESS && rctx->want_dnssec) {
1153 				result = getrdataset(mctx, &rctx->sigrdataset);
1154 				if (result != ISC_R_SUCCESS) {
1155 					putrdataset(mctx, &rctx->rdataset);
1156 				}
1157 			}
1158 
1159 			if (result != ISC_R_SUCCESS) {
1160 				want_restart = false;
1161 				send_event = true;
1162 			}
1163 		}
1164 	} while (want_restart);
1165 
1166 	if (send_event) {
1167 		isc_task_t *task;
1168 
1169 		while ((name = ISC_LIST_HEAD(rctx->namelist)) != NULL) {
1170 			ISC_LIST_UNLINK(rctx->namelist, name, link);
1171 			ISC_LIST_APPEND(rctx->event->answerlist, name, link);
1172 		}
1173 
1174 		rctx->event->result = result;
1175 		rctx->event->vresult = vresult;
1176 		task = rctx->event->ev_sender;
1177 		rctx->event->ev_sender = rctx;
1178 		isc_task_sendanddetach(&task, ISC_EVENT_PTR(&rctx->event));
1179 	}
1180 
1181 	UNLOCK(&rctx->lock);
1182 }
1183 
1184 static void
1185 suspend(isc_task_t *task, isc_event_t *event) {
1186 	isc_appctx_t *actx = event->ev_arg;
1187 
1188 	UNUSED(task);
1189 
1190 	isc_app_ctxsuspend(actx);
1191 	isc_event_free(&event);
1192 }
1193 
1194 static void
1195 resolve_done(isc_task_t *task, isc_event_t *event) {
1196 	resarg_t *resarg = event->ev_arg;
1197 	dns_clientresevent_t *rev = (dns_clientresevent_t *)event;
1198 	dns_name_t *name;
1199 	isc_result_t result;
1200 
1201 	UNUSED(task);
1202 
1203 	LOCK(&resarg->lock);
1204 
1205 	resarg->result = rev->result;
1206 	resarg->vresult = rev->vresult;
1207 	while ((name = ISC_LIST_HEAD(rev->answerlist)) != NULL) {
1208 		ISC_LIST_UNLINK(rev->answerlist, name, link);
1209 		ISC_LIST_APPEND(*resarg->namelist, name, link);
1210 	}
1211 
1212 	dns_client_destroyrestrans(&resarg->trans);
1213 	isc_event_free(&event);
1214 
1215 	if (!resarg->canceled) {
1216 		UNLOCK(&resarg->lock);
1217 
1218 		/*
1219 		 * We may or may not be running.  isc__appctx_onrun will
1220 		 * fail if we are currently running otherwise we post a
1221 		 * action to call isc_app_ctxsuspend when we do start
1222 		 * running.
1223 		 */
1224 		result = isc_app_ctxonrun(resarg->actx, resarg->client->mctx,
1225 					  task, suspend, resarg->actx);
1226 		if (result == ISC_R_ALREADYRUNNING) {
1227 			isc_app_ctxsuspend(resarg->actx);
1228 		}
1229 	} else {
1230 		/*
1231 		 * We have already exited from the loop (due to some
1232 		 * unexpected event).  Just clean the arg up.
1233 		 */
1234 		UNLOCK(&resarg->lock);
1235 		isc_mutex_destroy(&resarg->lock);
1236 		isc_mem_put(resarg->client->mctx, resarg, sizeof(*resarg));
1237 	}
1238 }
1239 
1240 isc_result_t
1241 dns_client_resolve(dns_client_t *client, const dns_name_t *name,
1242 		   dns_rdataclass_t rdclass, dns_rdatatype_t type,
1243 		   unsigned int options, dns_namelist_t *namelist) {
1244 	isc_result_t result;
1245 	isc_appctx_t *actx;
1246 	resarg_t *resarg;
1247 
1248 	REQUIRE(DNS_CLIENT_VALID(client));
1249 	REQUIRE(namelist != NULL && ISC_LIST_EMPTY(*namelist));
1250 
1251 	if ((client->attributes & DNS_CLIENTATTR_OWNCTX) == 0 &&
1252 	    (options & DNS_CLIENTRESOPT_ALLOWRUN) == 0)
1253 	{
1254 		/*
1255 		 * If the client is run under application's control, we need
1256 		 * to create a new running (sub)environment for this
1257 		 * particular resolution.
1258 		 */
1259 		return (ISC_R_NOTIMPLEMENTED); /* XXXTBD */
1260 	} else {
1261 		actx = client->actx;
1262 	}
1263 
1264 	resarg = isc_mem_get(client->mctx, sizeof(*resarg));
1265 
1266 	isc_mutex_init(&resarg->lock);
1267 
1268 	resarg->actx = actx;
1269 	resarg->client = client;
1270 	resarg->result = DNS_R_SERVFAIL;
1271 	resarg->namelist = namelist;
1272 	resarg->trans = NULL;
1273 	resarg->canceled = false;
1274 	result = dns_client_startresolve(client, name, rdclass, type, options,
1275 					 client->task, resolve_done, resarg,
1276 					 &resarg->trans);
1277 	if (result != ISC_R_SUCCESS) {
1278 		isc_mutex_destroy(&resarg->lock);
1279 		isc_mem_put(client->mctx, resarg, sizeof(*resarg));
1280 		return (result);
1281 	}
1282 
1283 	/*
1284 	 * Start internal event loop.  It blocks until the entire process
1285 	 * is completed.
1286 	 */
1287 	result = isc_app_ctxrun(actx);
1288 
1289 	LOCK(&resarg->lock);
1290 	if (result == ISC_R_SUCCESS || result == ISC_R_SUSPEND) {
1291 		result = resarg->result;
1292 	}
1293 	if (result != ISC_R_SUCCESS && resarg->vresult != ISC_R_SUCCESS) {
1294 		/*
1295 		 * If this lookup failed due to some error in DNSSEC
1296 		 * validation, return the validation error code.
1297 		 * XXX: or should we pass the validation result separately?
1298 		 */
1299 		result = resarg->vresult;
1300 	}
1301 	if (resarg->trans != NULL) {
1302 		/*
1303 		 * Unusual termination (perhaps due to signal).  We need some
1304 		 * tricky cleanup process.
1305 		 */
1306 		resarg->canceled = true;
1307 		dns_client_cancelresolve(resarg->trans);
1308 
1309 		UNLOCK(&resarg->lock);
1310 
1311 		/* resarg will be freed in the event handler. */
1312 	} else {
1313 		UNLOCK(&resarg->lock);
1314 
1315 		isc_mutex_destroy(&resarg->lock);
1316 		isc_mem_put(client->mctx, resarg, sizeof(*resarg));
1317 	}
1318 
1319 	return (result);
1320 }
1321 
1322 isc_result_t
1323 dns_client_startresolve(dns_client_t *client, const dns_name_t *name,
1324 			dns_rdataclass_t rdclass, dns_rdatatype_t type,
1325 			unsigned int options, isc_task_t *task,
1326 			isc_taskaction_t action, void *arg,
1327 			dns_clientrestrans_t **transp) {
1328 	dns_view_t *view = NULL;
1329 	dns_clientresevent_t *event = NULL;
1330 	resctx_t *rctx = NULL;
1331 	isc_task_t *tclone = NULL;
1332 	isc_mem_t *mctx;
1333 	isc_result_t result;
1334 	dns_rdataset_t *rdataset, *sigrdataset;
1335 	bool want_dnssec, want_validation, want_cdflag, want_tcp;
1336 
1337 	REQUIRE(DNS_CLIENT_VALID(client));
1338 	REQUIRE(transp != NULL && *transp == NULL);
1339 
1340 	LOCK(&client->lock);
1341 	result = dns_viewlist_find(&client->viewlist, DNS_CLIENTVIEW_NAME,
1342 				   rdclass, &view);
1343 	UNLOCK(&client->lock);
1344 	if (result != ISC_R_SUCCESS) {
1345 		return (result);
1346 	}
1347 
1348 	mctx = client->mctx;
1349 	rdataset = NULL;
1350 	sigrdataset = NULL;
1351 	want_dnssec = ((options & DNS_CLIENTRESOPT_NODNSSEC) == 0);
1352 	want_validation = ((options & DNS_CLIENTRESOPT_NOVALIDATE) == 0);
1353 	want_cdflag = ((options & DNS_CLIENTRESOPT_NOCDFLAG) == 0);
1354 	want_tcp = ((options & DNS_CLIENTRESOPT_TCP) != 0);
1355 
1356 	/*
1357 	 * Prepare some intermediate resources
1358 	 */
1359 	tclone = NULL;
1360 	isc_task_attach(task, &tclone);
1361 	event = (dns_clientresevent_t *)isc_event_allocate(
1362 		mctx, tclone, DNS_EVENT_CLIENTRESDONE, action, arg,
1363 		sizeof(*event));
1364 	event->result = DNS_R_SERVFAIL;
1365 	ISC_LIST_INIT(event->answerlist);
1366 
1367 	rctx = isc_mem_get(mctx, sizeof(*rctx));
1368 	isc_mutex_init(&rctx->lock);
1369 
1370 	result = getrdataset(mctx, &rdataset);
1371 	if (result != ISC_R_SUCCESS) {
1372 		goto cleanup;
1373 	}
1374 	rctx->rdataset = rdataset;
1375 
1376 	if (want_dnssec) {
1377 		result = getrdataset(mctx, &sigrdataset);
1378 		if (result != ISC_R_SUCCESS) {
1379 			goto cleanup;
1380 		}
1381 	}
1382 	rctx->sigrdataset = sigrdataset;
1383 
1384 	dns_fixedname_init(&rctx->name);
1385 	dns_name_copynf(name, dns_fixedname_name(&rctx->name));
1386 
1387 	rctx->client = client;
1388 	ISC_LINK_INIT(rctx, link);
1389 	rctx->canceled = false;
1390 	rctx->task = client->task;
1391 	rctx->type = type;
1392 	rctx->view = view;
1393 	rctx->restarts = 0;
1394 	rctx->fetch = NULL;
1395 	rctx->want_dnssec = want_dnssec;
1396 	rctx->want_validation = want_validation;
1397 	rctx->want_cdflag = want_cdflag;
1398 	rctx->want_tcp = want_tcp;
1399 	ISC_LIST_INIT(rctx->namelist);
1400 	rctx->event = event;
1401 
1402 	rctx->magic = RCTX_MAGIC;
1403 	isc_refcount_increment(&client->references);
1404 
1405 	LOCK(&client->lock);
1406 	ISC_LIST_APPEND(client->resctxs, rctx, link);
1407 	UNLOCK(&client->lock);
1408 
1409 	*transp = (dns_clientrestrans_t *)rctx;
1410 	client_resfind(rctx, NULL);
1411 
1412 	return (ISC_R_SUCCESS);
1413 
1414 cleanup:
1415 	if (rdataset != NULL) {
1416 		putrdataset(client->mctx, &rdataset);
1417 	}
1418 	if (sigrdataset != NULL) {
1419 		putrdataset(client->mctx, &sigrdataset);
1420 	}
1421 	isc_mutex_destroy(&rctx->lock);
1422 	isc_mem_put(mctx, rctx, sizeof(*rctx));
1423 	isc_event_free(ISC_EVENT_PTR(&event));
1424 	isc_task_detach(&tclone);
1425 	dns_view_detach(&view);
1426 
1427 	return (result);
1428 }
1429 
1430 void
1431 dns_client_cancelresolve(dns_clientrestrans_t *trans) {
1432 	resctx_t *rctx;
1433 
1434 	REQUIRE(trans != NULL);
1435 	rctx = (resctx_t *)trans;
1436 	REQUIRE(RCTX_VALID(rctx));
1437 
1438 	LOCK(&rctx->lock);
1439 
1440 	if (!rctx->canceled) {
1441 		rctx->canceled = true;
1442 		if (rctx->fetch != NULL) {
1443 			dns_resolver_cancelfetch(rctx->fetch);
1444 		}
1445 	}
1446 
1447 	UNLOCK(&rctx->lock);
1448 }
1449 
1450 void
1451 dns_client_freeresanswer(dns_client_t *client, dns_namelist_t *namelist) {
1452 	dns_name_t *name;
1453 	dns_rdataset_t *rdataset;
1454 
1455 	REQUIRE(DNS_CLIENT_VALID(client));
1456 	REQUIRE(namelist != NULL);
1457 
1458 	while ((name = ISC_LIST_HEAD(*namelist)) != NULL) {
1459 		ISC_LIST_UNLINK(*namelist, name, link);
1460 		while ((rdataset = ISC_LIST_HEAD(name->list)) != NULL) {
1461 			ISC_LIST_UNLINK(name->list, rdataset, link);
1462 			putrdataset(client->mctx, &rdataset);
1463 		}
1464 		dns_name_free(name, client->mctx);
1465 		isc_mem_put(client->mctx, name, sizeof(*name));
1466 	}
1467 }
1468 
1469 void
1470 dns_client_destroyrestrans(dns_clientrestrans_t **transp) {
1471 	resctx_t *rctx;
1472 	isc_mem_t *mctx;
1473 	dns_client_t *client;
1474 
1475 	REQUIRE(transp != NULL);
1476 	rctx = (resctx_t *)*transp;
1477 	*transp = NULL;
1478 	REQUIRE(RCTX_VALID(rctx));
1479 	REQUIRE(rctx->fetch == NULL);
1480 	REQUIRE(rctx->event == NULL);
1481 	client = rctx->client;
1482 	REQUIRE(DNS_CLIENT_VALID(client));
1483 
1484 	mctx = client->mctx;
1485 	dns_view_detach(&rctx->view);
1486 
1487 	/*
1488 	 * Wait for the lock in client_resfind to be released before
1489 	 * destroying the lock.
1490 	 */
1491 	LOCK(&rctx->lock);
1492 	UNLOCK(&rctx->lock);
1493 
1494 	LOCK(&client->lock);
1495 
1496 	INSIST(ISC_LINK_LINKED(rctx, link));
1497 	ISC_LIST_UNLINK(client->resctxs, rctx, link);
1498 
1499 	UNLOCK(&client->lock);
1500 
1501 	INSIST(ISC_LIST_EMPTY(rctx->namelist));
1502 
1503 	isc_mutex_destroy(&rctx->lock);
1504 	rctx->magic = 0;
1505 
1506 	isc_mem_put(mctx, rctx, sizeof(*rctx));
1507 
1508 	dns_client_destroy(&client);
1509 }
1510 
1511 isc_result_t
1512 dns_client_addtrustedkey(dns_client_t *client, dns_rdataclass_t rdclass,
1513 			 dns_rdatatype_t rdtype, const dns_name_t *keyname,
1514 			 isc_buffer_t *databuf) {
1515 	isc_result_t result;
1516 	dns_view_t *view = NULL;
1517 	dns_keytable_t *secroots = NULL;
1518 	dns_name_t *name = NULL;
1519 	char rdatabuf[DST_KEY_MAXSIZE];
1520 	unsigned char digest[ISC_MAX_MD_SIZE];
1521 	dns_rdata_ds_t ds;
1522 	dns_decompress_t dctx;
1523 	dns_rdata_t rdata;
1524 	isc_buffer_t b;
1525 
1526 	REQUIRE(DNS_CLIENT_VALID(client));
1527 
1528 	LOCK(&client->lock);
1529 	result = dns_viewlist_find(&client->viewlist, DNS_CLIENTVIEW_NAME,
1530 				   rdclass, &view);
1531 	UNLOCK(&client->lock);
1532 	CHECK(result);
1533 
1534 	CHECK(dns_view_getsecroots(view, &secroots));
1535 
1536 	DE_CONST(keyname, name);
1537 
1538 	if (rdtype != dns_rdatatype_dnskey && rdtype != dns_rdatatype_ds) {
1539 		result = ISC_R_NOTIMPLEMENTED;
1540 		goto cleanup;
1541 	}
1542 
1543 	isc_buffer_init(&b, rdatabuf, sizeof(rdatabuf));
1544 	dns_decompress_init(&dctx, -1, DNS_DECOMPRESS_NONE);
1545 	dns_rdata_init(&rdata);
1546 	isc_buffer_setactive(databuf, isc_buffer_usedlength(databuf));
1547 	CHECK(dns_rdata_fromwire(&rdata, rdclass, rdtype, databuf, &dctx, 0,
1548 				 &b));
1549 	dns_decompress_invalidate(&dctx);
1550 
1551 	if (rdtype == dns_rdatatype_ds) {
1552 		CHECK(dns_rdata_tostruct(&rdata, &ds, NULL));
1553 	} else {
1554 		CHECK(dns_ds_fromkeyrdata(name, &rdata, DNS_DSDIGEST_SHA256,
1555 					  digest, &ds));
1556 	}
1557 
1558 	CHECK(dns_keytable_add(secroots, false, false, name, &ds));
1559 
1560 cleanup:
1561 	if (view != NULL) {
1562 		dns_view_detach(&view);
1563 	}
1564 	if (secroots != NULL) {
1565 		dns_keytable_detach(&secroots);
1566 	}
1567 	return (result);
1568 }
1569 
1570 /*%
1571  * Simple request routines
1572  */
1573 static void
1574 request_done(isc_task_t *task, isc_event_t *event) {
1575 	dns_requestevent_t *reqev = NULL;
1576 	dns_request_t *request;
1577 	isc_result_t result, eresult;
1578 	reqctx_t *ctx;
1579 
1580 	UNUSED(task);
1581 
1582 	REQUIRE(event->ev_type == DNS_EVENT_REQUESTDONE);
1583 	reqev = (dns_requestevent_t *)event;
1584 	request = reqev->request;
1585 	result = eresult = reqev->result;
1586 	ctx = reqev->ev_arg;
1587 	REQUIRE(REQCTX_VALID(ctx));
1588 
1589 	isc_event_free(&event);
1590 
1591 	LOCK(&ctx->lock);
1592 
1593 	if (eresult == ISC_R_SUCCESS) {
1594 		result = dns_request_getresponse(request, ctx->event->rmessage,
1595 						 ctx->parseoptions);
1596 	}
1597 
1598 	if (ctx->tsigkey != NULL) {
1599 		dns_tsigkey_detach(&ctx->tsigkey);
1600 	}
1601 
1602 	if (ctx->canceled) {
1603 		ctx->event->result = ISC_R_CANCELED;
1604 	} else {
1605 		ctx->event->result = result;
1606 	}
1607 	task = ctx->event->ev_sender;
1608 	ctx->event->ev_sender = ctx;
1609 	isc_task_sendanddetach(&task, ISC_EVENT_PTR(&ctx->event));
1610 
1611 	UNLOCK(&ctx->lock);
1612 }
1613 
1614 static void
1615 localrequest_done(isc_task_t *task, isc_event_t *event) {
1616 	reqarg_t *reqarg = event->ev_arg;
1617 	dns_clientreqevent_t *rev = (dns_clientreqevent_t *)event;
1618 
1619 	UNUSED(task);
1620 
1621 	REQUIRE(event->ev_type == DNS_EVENT_CLIENTREQDONE);
1622 
1623 	LOCK(&reqarg->lock);
1624 
1625 	reqarg->result = rev->result;
1626 	dns_client_destroyreqtrans(&reqarg->trans);
1627 	isc_event_free(&event);
1628 
1629 	if (!reqarg->canceled) {
1630 		UNLOCK(&reqarg->lock);
1631 
1632 		/* Exit from the internal event loop */
1633 		isc_app_ctxsuspend(reqarg->actx);
1634 	} else {
1635 		/*
1636 		 * We have already exited from the loop (due to some
1637 		 * unexpected event).  Just clean the arg up.
1638 		 */
1639 		UNLOCK(&reqarg->lock);
1640 		isc_mutex_destroy(&reqarg->lock);
1641 		isc_mem_put(reqarg->client->mctx, reqarg, sizeof(*reqarg));
1642 	}
1643 }
1644 
1645 isc_result_t
1646 dns_client_request(dns_client_t *client, dns_message_t *qmessage,
1647 		   dns_message_t *rmessage, const isc_sockaddr_t *server,
1648 		   unsigned int options, unsigned int parseoptions,
1649 		   dns_tsec_t *tsec, unsigned int timeout,
1650 		   unsigned int udptimeout, unsigned int udpretries) {
1651 	isc_appctx_t *actx;
1652 	reqarg_t *reqarg;
1653 	isc_result_t result;
1654 
1655 	REQUIRE(DNS_CLIENT_VALID(client));
1656 	REQUIRE(qmessage != NULL);
1657 	REQUIRE(rmessage != NULL);
1658 
1659 	if ((client->attributes & DNS_CLIENTATTR_OWNCTX) == 0 &&
1660 	    (options & DNS_CLIENTREQOPT_ALLOWRUN) == 0)
1661 	{
1662 		/*
1663 		 * If the client is run under application's control, we need
1664 		 * to create a new running (sub)environment for this
1665 		 * particular resolution.
1666 		 */
1667 		return (ISC_R_NOTIMPLEMENTED); /* XXXTBD */
1668 	} else {
1669 		actx = client->actx;
1670 	}
1671 
1672 	reqarg = isc_mem_get(client->mctx, sizeof(*reqarg));
1673 
1674 	isc_mutex_init(&reqarg->lock);
1675 
1676 	reqarg->actx = actx;
1677 	reqarg->client = client;
1678 	reqarg->trans = NULL;
1679 	reqarg->canceled = false;
1680 
1681 	result = dns_client_startrequest(
1682 		client, qmessage, rmessage, server, options, parseoptions, tsec,
1683 		timeout, udptimeout, udpretries, client->task,
1684 		localrequest_done, reqarg, &reqarg->trans);
1685 	if (result != ISC_R_SUCCESS) {
1686 		isc_mutex_destroy(&reqarg->lock);
1687 		isc_mem_put(client->mctx, reqarg, sizeof(*reqarg));
1688 		return (result);
1689 	}
1690 
1691 	/*
1692 	 * Start internal event loop.  It blocks until the entire process
1693 	 * is completed.
1694 	 */
1695 	result = isc_app_ctxrun(actx);
1696 
1697 	LOCK(&reqarg->lock);
1698 	if (result == ISC_R_SUCCESS || result == ISC_R_SUSPEND) {
1699 		result = reqarg->result;
1700 	}
1701 	if (reqarg->trans != NULL) {
1702 		/*
1703 		 * Unusual termination (perhaps due to signal).  We need some
1704 		 * tricky cleanup process.
1705 		 */
1706 		reqarg->canceled = true;
1707 		dns_client_cancelresolve(reqarg->trans);
1708 
1709 		UNLOCK(&reqarg->lock);
1710 
1711 		/* reqarg will be freed in the event handler. */
1712 	} else {
1713 		UNLOCK(&reqarg->lock);
1714 
1715 		isc_mutex_destroy(&reqarg->lock);
1716 		isc_mem_put(client->mctx, reqarg, sizeof(*reqarg));
1717 	}
1718 
1719 	return (result);
1720 }
1721 
1722 isc_result_t
1723 dns_client_startrequest(dns_client_t *client, dns_message_t *qmessage,
1724 			dns_message_t *rmessage, const isc_sockaddr_t *server,
1725 			unsigned int options, unsigned int parseoptions,
1726 			dns_tsec_t *tsec, unsigned int timeout,
1727 			unsigned int udptimeout, unsigned int udpretries,
1728 			isc_task_t *task, isc_taskaction_t action, void *arg,
1729 			dns_clientreqtrans_t **transp) {
1730 	isc_result_t result;
1731 	dns_view_t *view = NULL;
1732 	isc_task_t *tclone = NULL;
1733 	dns_clientreqevent_t *event = NULL;
1734 	reqctx_t *ctx = NULL;
1735 	dns_tsectype_t tsectype = dns_tsectype_none;
1736 	unsigned int reqoptions;
1737 
1738 	REQUIRE(DNS_CLIENT_VALID(client));
1739 	REQUIRE(qmessage != NULL);
1740 	REQUIRE(rmessage != NULL);
1741 	REQUIRE(transp != NULL && *transp == NULL);
1742 
1743 	if (tsec != NULL) {
1744 		tsectype = dns_tsec_gettype(tsec);
1745 		if (tsectype != dns_tsectype_tsig) {
1746 			return (ISC_R_NOTIMPLEMENTED); /* XXX */
1747 		}
1748 	}
1749 
1750 	LOCK(&client->lock);
1751 	result = dns_viewlist_find(&client->viewlist, DNS_CLIENTVIEW_NAME,
1752 				   qmessage->rdclass, &view);
1753 	UNLOCK(&client->lock);
1754 	if (result != ISC_R_SUCCESS) {
1755 		return (result);
1756 	}
1757 
1758 	reqoptions = 0;
1759 	if ((options & DNS_CLIENTREQOPT_TCP) != 0) {
1760 		reqoptions |= DNS_REQUESTOPT_TCP;
1761 	}
1762 
1763 	tclone = NULL;
1764 	isc_task_attach(task, &tclone);
1765 	event = (dns_clientreqevent_t *)isc_event_allocate(
1766 		client->mctx, tclone, DNS_EVENT_CLIENTREQDONE, action, arg,
1767 		sizeof(*event));
1768 
1769 	ctx = isc_mem_get(client->mctx, sizeof(*ctx));
1770 	isc_mutex_init(&ctx->lock);
1771 
1772 	ctx->client = client;
1773 	ISC_LINK_INIT(ctx, link);
1774 	ctx->parseoptions = parseoptions;
1775 	ctx->canceled = false;
1776 	ctx->event = event;
1777 	ctx->event->rmessage = rmessage;
1778 	ctx->tsigkey = NULL;
1779 	if (tsec != NULL) {
1780 		dns_tsec_getkey(tsec, &ctx->tsigkey);
1781 	}
1782 
1783 	ctx->magic = REQCTX_MAGIC;
1784 
1785 	LOCK(&client->lock);
1786 	ISC_LIST_APPEND(client->reqctxs, ctx, link);
1787 	isc_refcount_increment(&client->references);
1788 	UNLOCK(&client->lock);
1789 
1790 	ctx->request = NULL;
1791 	result = dns_request_createvia(view->requestmgr, qmessage, NULL, server,
1792 				       -1, reqoptions, ctx->tsigkey, timeout,
1793 				       udptimeout, udpretries, client->task,
1794 				       request_done, ctx, &ctx->request);
1795 	if (result == ISC_R_SUCCESS) {
1796 		dns_view_detach(&view);
1797 		*transp = (dns_clientreqtrans_t *)ctx;
1798 		return (ISC_R_SUCCESS);
1799 	}
1800 
1801 	isc_refcount_decrement1(&client->references);
1802 
1803 	LOCK(&client->lock);
1804 	ISC_LIST_UNLINK(client->reqctxs, ctx, link);
1805 	UNLOCK(&client->lock);
1806 	isc_mutex_destroy(&ctx->lock);
1807 	isc_mem_put(client->mctx, ctx, sizeof(*ctx));
1808 
1809 	isc_event_free(ISC_EVENT_PTR(&event));
1810 	isc_task_detach(&tclone);
1811 	dns_view_detach(&view);
1812 
1813 	return (result);
1814 }
1815 
1816 void
1817 dns_client_cancelrequest(dns_clientreqtrans_t *trans) {
1818 	reqctx_t *ctx;
1819 
1820 	REQUIRE(trans != NULL);
1821 	ctx = (reqctx_t *)trans;
1822 	REQUIRE(REQCTX_VALID(ctx));
1823 
1824 	LOCK(&ctx->lock);
1825 
1826 	if (!ctx->canceled) {
1827 		ctx->canceled = true;
1828 		if (ctx->request != NULL) {
1829 			dns_request_cancel(ctx->request);
1830 		}
1831 	}
1832 
1833 	UNLOCK(&ctx->lock);
1834 }
1835 
1836 void
1837 dns_client_destroyreqtrans(dns_clientreqtrans_t **transp) {
1838 	reqctx_t *ctx;
1839 	isc_mem_t *mctx;
1840 	dns_client_t *client;
1841 
1842 	REQUIRE(transp != NULL);
1843 	ctx = (reqctx_t *)*transp;
1844 	*transp = NULL;
1845 	REQUIRE(REQCTX_VALID(ctx));
1846 	client = ctx->client;
1847 	REQUIRE(DNS_CLIENT_VALID(client));
1848 	REQUIRE(ctx->event == NULL);
1849 	REQUIRE(ctx->request != NULL);
1850 
1851 	dns_request_destroy(&ctx->request);
1852 	mctx = client->mctx;
1853 
1854 	LOCK(&client->lock);
1855 
1856 	INSIST(ISC_LINK_LINKED(ctx, link));
1857 	ISC_LIST_UNLINK(client->reqctxs, ctx, link);
1858 
1859 	UNLOCK(&client->lock);
1860 
1861 	isc_mutex_destroy(&ctx->lock);
1862 	ctx->magic = 0;
1863 
1864 	isc_mem_put(mctx, ctx, sizeof(*ctx));
1865 
1866 	dns_client_destroy(&client);
1867 }
1868 
1869 /*%
1870  * Dynamic update routines
1871  */
1872 static isc_result_t
1873 rcode2result(dns_rcode_t rcode) {
1874 	/* XXX: isn't there a similar function? */
1875 	switch (rcode) {
1876 	case dns_rcode_formerr:
1877 		return (DNS_R_FORMERR);
1878 	case dns_rcode_servfail:
1879 		return (DNS_R_SERVFAIL);
1880 	case dns_rcode_nxdomain:
1881 		return (DNS_R_NXDOMAIN);
1882 	case dns_rcode_notimp:
1883 		return (DNS_R_NOTIMP);
1884 	case dns_rcode_refused:
1885 		return (DNS_R_REFUSED);
1886 	case dns_rcode_yxdomain:
1887 		return (DNS_R_YXDOMAIN);
1888 	case dns_rcode_yxrrset:
1889 		return (DNS_R_YXRRSET);
1890 	case dns_rcode_nxrrset:
1891 		return (DNS_R_NXRRSET);
1892 	case dns_rcode_notauth:
1893 		return (DNS_R_NOTAUTH);
1894 	case dns_rcode_notzone:
1895 		return (DNS_R_NOTZONE);
1896 	case dns_rcode_badvers:
1897 		return (DNS_R_BADVERS);
1898 	}
1899 
1900 	return (ISC_R_FAILURE);
1901 }
1902 
1903 static void
1904 update_sendevent(updatectx_t *uctx, isc_result_t result) {
1905 	isc_task_t *task;
1906 
1907 	dns_message_detach(&uctx->updatemsg);
1908 	if (uctx->tsigkey != NULL) {
1909 		dns_tsigkey_detach(&uctx->tsigkey);
1910 	}
1911 	if (uctx->sig0key != NULL) {
1912 		dst_key_free(&uctx->sig0key);
1913 	}
1914 
1915 	if (uctx->canceled) {
1916 		uctx->event->result = ISC_R_CANCELED;
1917 	} else {
1918 		uctx->event->result = result;
1919 	}
1920 	uctx->event->state = uctx->state;
1921 	task = uctx->event->ev_sender;
1922 	uctx->event->ev_sender = uctx;
1923 	isc_task_sendanddetach(&task, ISC_EVENT_PTR(&uctx->event));
1924 }
1925 
1926 static void
1927 update_done(isc_task_t *task, isc_event_t *event) {
1928 	isc_result_t result;
1929 	dns_requestevent_t *reqev = NULL;
1930 	dns_request_t *request;
1931 	dns_message_t *answer = NULL;
1932 	updatectx_t *uctx = event->ev_arg;
1933 	dns_client_t *client;
1934 	unsigned int timeout, reqoptions;
1935 
1936 	UNUSED(task);
1937 
1938 	REQUIRE(event->ev_type == DNS_EVENT_REQUESTDONE);
1939 	reqev = (dns_requestevent_t *)event;
1940 	request = reqev->request;
1941 	REQUIRE(UCTX_VALID(uctx));
1942 	client = uctx->client;
1943 	REQUIRE(DNS_CLIENT_VALID(client));
1944 
1945 	result = reqev->result;
1946 	if (result != ISC_R_SUCCESS) {
1947 		goto out;
1948 	}
1949 
1950 	dns_message_create(client->mctx, DNS_MESSAGE_INTENTPARSE, &answer);
1951 	uctx->state = dns_clientupdatestate_done;
1952 	result = dns_request_getresponse(request, answer,
1953 					 DNS_MESSAGEPARSE_PRESERVEORDER);
1954 	if (result == ISC_R_SUCCESS && answer->rcode != dns_rcode_noerror) {
1955 		result = rcode2result(answer->rcode);
1956 	}
1957 
1958 out:
1959 	if (answer != NULL) {
1960 		dns_message_detach(&answer);
1961 	}
1962 	isc_event_free(&event);
1963 
1964 	LOCK(&uctx->lock);
1965 	uctx->currentserver = ISC_LIST_NEXT(uctx->currentserver, link);
1966 	dns_request_destroy(&uctx->updatereq);
1967 	/*
1968 	 * Moving on to the next server shouldn't change the result
1969 	 * for NXDOMAIN, YXDOMAIN, NXRRSET and YXRRSET as they
1970 	 * indicate a prerequisite failure.  REFUSED should also
1971 	 * be consistent across all servers but often isn't as that
1972 	 * is policy rather that zone content driven (slaves that
1973 	 * aren't willing to forward should return NOTIMPL).  NOTZONE
1974 	 * indicates that we stuffed up the request construction so
1975 	 * don't retry.
1976 	 */
1977 	if (result != ISC_R_SUCCESS && result != DNS_R_NXDOMAIN &&
1978 	    result != DNS_R_YXDOMAIN && result != DNS_R_YXRRSET &&
1979 	    result != DNS_R_NXRRSET && result != DNS_R_NOTZONE &&
1980 	    !uctx->canceled && uctx->currentserver != NULL)
1981 	{
1982 		dns_message_renderreset(uctx->updatemsg);
1983 		dns_message_settsigkey(uctx->updatemsg, NULL);
1984 
1985 		timeout = client->update_timeout / uctx->nservers;
1986 		if (timeout < MIN_UPDATE_TIMEOUT) {
1987 			timeout = MIN_UPDATE_TIMEOUT;
1988 		}
1989 		reqoptions = 0;
1990 		if (uctx->want_tcp) {
1991 			reqoptions |= DNS_REQUESTOPT_TCP;
1992 		}
1993 		result = dns_request_createvia(
1994 			uctx->view->requestmgr, uctx->updatemsg, NULL,
1995 			uctx->currentserver, -1, reqoptions, uctx->tsigkey,
1996 			timeout, client->update_udptimeout,
1997 			client->update_udpretries, client->task, update_done,
1998 			uctx, &uctx->updatereq);
1999 		UNLOCK(&uctx->lock);
2000 
2001 		if (result == ISC_R_SUCCESS) {
2002 			/* XXX: should we keep the 'done' state here? */
2003 			uctx->state = dns_clientupdatestate_sent;
2004 			return;
2005 		}
2006 	} else {
2007 		UNLOCK(&uctx->lock);
2008 	}
2009 
2010 	update_sendevent(uctx, result);
2011 }
2012 
2013 static isc_result_t
2014 send_update(updatectx_t *uctx) {
2015 	isc_result_t result;
2016 	dns_name_t *name = NULL;
2017 	dns_rdataset_t *rdataset = NULL;
2018 	dns_client_t *client = uctx->client;
2019 	unsigned int timeout, reqoptions;
2020 
2021 	REQUIRE(uctx->zonename != NULL && uctx->currentserver != NULL);
2022 
2023 	result = dns_message_gettempname(uctx->updatemsg, &name);
2024 	if (result != ISC_R_SUCCESS) {
2025 		return (result);
2026 	}
2027 	dns_name_init(name, NULL);
2028 	dns_name_clone(uctx->zonename, name);
2029 	result = dns_message_gettemprdataset(uctx->updatemsg, &rdataset);
2030 	if (result != ISC_R_SUCCESS) {
2031 		dns_message_puttempname(uctx->updatemsg, &name);
2032 		return (result);
2033 	}
2034 	dns_rdataset_makequestion(rdataset, uctx->rdclass, dns_rdatatype_soa);
2035 	ISC_LIST_INIT(name->list);
2036 	ISC_LIST_APPEND(name->list, rdataset, link);
2037 	dns_message_addname(uctx->updatemsg, name, DNS_SECTION_ZONE);
2038 	if (uctx->tsigkey == NULL && uctx->sig0key != NULL) {
2039 		result = dns_message_setsig0key(uctx->updatemsg, uctx->sig0key);
2040 		if (result != ISC_R_SUCCESS) {
2041 			return (result);
2042 		}
2043 	}
2044 	timeout = client->update_timeout / uctx->nservers;
2045 	if (timeout < MIN_UPDATE_TIMEOUT) {
2046 		timeout = MIN_UPDATE_TIMEOUT;
2047 	}
2048 	reqoptions = 0;
2049 	if (uctx->want_tcp) {
2050 		reqoptions |= DNS_REQUESTOPT_TCP;
2051 	}
2052 	result = dns_request_createvia(
2053 		uctx->view->requestmgr, uctx->updatemsg, NULL,
2054 		uctx->currentserver, -1, reqoptions, uctx->tsigkey, timeout,
2055 		client->update_udptimeout, client->update_udpretries,
2056 		client->task, update_done, uctx, &uctx->updatereq);
2057 	if (result == ISC_R_SUCCESS &&
2058 	    uctx->state == dns_clientupdatestate_prepare) {
2059 		uctx->state = dns_clientupdatestate_sent;
2060 	}
2061 
2062 	return (result);
2063 }
2064 
2065 static void
2066 resolveaddr_done(isc_task_t *task, isc_event_t *event) {
2067 	isc_result_t result;
2068 	int family;
2069 	dns_rdatatype_t qtype;
2070 	dns_clientresevent_t *rev = (dns_clientresevent_t *)event;
2071 	dns_name_t *name;
2072 	dns_rdataset_t *rdataset;
2073 	updatectx_t *uctx;
2074 	bool completed = false;
2075 
2076 	UNUSED(task);
2077 
2078 	REQUIRE(event->ev_arg != NULL);
2079 	uctx = *(updatectx_t **)event->ev_arg;
2080 	REQUIRE(UCTX_VALID(uctx));
2081 
2082 	if (event->ev_arg == &uctx->bp4) {
2083 		family = AF_INET;
2084 		qtype = dns_rdatatype_a;
2085 		LOCK(&uctx->lock);
2086 		dns_client_destroyrestrans(&uctx->restrans);
2087 		UNLOCK(&uctx->lock);
2088 	} else {
2089 		INSIST(event->ev_arg == &uctx->bp6);
2090 		family = AF_INET6;
2091 		qtype = dns_rdatatype_aaaa;
2092 		LOCK(&uctx->lock);
2093 		dns_client_destroyrestrans(&uctx->restrans2);
2094 		UNLOCK(&uctx->lock);
2095 	}
2096 
2097 	result = rev->result;
2098 	if (result != ISC_R_SUCCESS) {
2099 		goto done;
2100 	}
2101 
2102 	for (name = ISC_LIST_HEAD(rev->answerlist); name != NULL;
2103 	     name = ISC_LIST_NEXT(name, link))
2104 	{
2105 		for (rdataset = ISC_LIST_HEAD(name->list); rdataset != NULL;
2106 		     rdataset = ISC_LIST_NEXT(rdataset, link))
2107 		{
2108 			if (!dns_rdataset_isassociated(rdataset)) {
2109 				continue;
2110 			}
2111 			if (rdataset->type != qtype) {
2112 				continue;
2113 			}
2114 
2115 			for (result = dns_rdataset_first(rdataset);
2116 			     result == ISC_R_SUCCESS;
2117 			     result = dns_rdataset_next(rdataset))
2118 			{
2119 				dns_rdata_t rdata;
2120 				dns_rdata_in_a_t rdata_a;
2121 				dns_rdata_in_aaaa_t rdata_aaaa;
2122 				isc_sockaddr_t *sa;
2123 
2124 				sa = isc_mem_get(uctx->client->mctx,
2125 						 sizeof(*sa));
2126 
2127 				dns_rdata_init(&rdata);
2128 				switch (family) {
2129 				case AF_INET:
2130 					dns_rdataset_current(rdataset, &rdata);
2131 					result = dns_rdata_tostruct(
2132 						&rdata, &rdata_a, NULL);
2133 					RUNTIME_CHECK(result == ISC_R_SUCCESS);
2134 					isc_sockaddr_fromin(
2135 						sa, &rdata_a.in_addr, 53);
2136 					dns_rdata_freestruct(&rdata_a);
2137 					break;
2138 				case AF_INET6:
2139 					dns_rdataset_current(rdataset, &rdata);
2140 					result = dns_rdata_tostruct(
2141 						&rdata, &rdata_aaaa, NULL);
2142 					RUNTIME_CHECK(result == ISC_R_SUCCESS);
2143 					isc_sockaddr_fromin6(
2144 						sa, &rdata_aaaa.in6_addr, 53);
2145 					dns_rdata_freestruct(&rdata_aaaa);
2146 					break;
2147 				}
2148 
2149 				ISC_LINK_INIT(sa, link);
2150 				ISC_LIST_APPEND(uctx->servers, sa, link);
2151 				uctx->nservers++;
2152 			}
2153 		}
2154 	}
2155 
2156 done:
2157 	dns_client_freeresanswer(uctx->client, &rev->answerlist);
2158 	isc_event_free(&event);
2159 
2160 	LOCK(&uctx->lock);
2161 	if (uctx->restrans == NULL && uctx->restrans2 == NULL) {
2162 		completed = true;
2163 	}
2164 	UNLOCK(&uctx->lock);
2165 
2166 	if (completed) {
2167 		INSIST(uctx->currentserver == NULL);
2168 		uctx->currentserver = ISC_LIST_HEAD(uctx->servers);
2169 		if (uctx->currentserver != NULL && !uctx->canceled) {
2170 			send_update(uctx);
2171 		} else {
2172 			if (result == ISC_R_SUCCESS) {
2173 				result = ISC_R_NOTFOUND;
2174 			}
2175 			update_sendevent(uctx, result);
2176 		}
2177 	}
2178 }
2179 
2180 static isc_result_t
2181 process_soa(updatectx_t *uctx, dns_rdataset_t *soaset,
2182 	    const dns_name_t *soaname) {
2183 	isc_result_t result;
2184 	dns_rdata_t soarr = DNS_RDATA_INIT;
2185 	dns_rdata_soa_t soa;
2186 	dns_name_t primary;
2187 	unsigned int resoptions;
2188 
2189 	result = dns_rdataset_first(soaset);
2190 	if (result != ISC_R_SUCCESS) {
2191 		return (result);
2192 	}
2193 	dns_rdata_init(&soarr);
2194 	dns_rdataset_current(soaset, &soarr);
2195 	result = dns_rdata_tostruct(&soarr, &soa, NULL);
2196 	if (result != ISC_R_SUCCESS) {
2197 		return (result);
2198 	}
2199 
2200 	dns_name_init(&primary, NULL);
2201 	dns_name_clone(&soa.origin, &primary);
2202 
2203 	if (uctx->zonename == NULL) {
2204 		uctx->zonename = dns_fixedname_name(&uctx->zonefname);
2205 		dns_name_copynf(soaname, uctx->zonename);
2206 	}
2207 
2208 	if (uctx->currentserver != NULL) {
2209 		result = send_update(uctx);
2210 	} else {
2211 		/*
2212 		 * Get addresses of the primary server.  We don't use the ADB
2213 		 * feature so that we could avoid caching data.
2214 		 */
2215 		LOCK(&uctx->lock);
2216 		uctx->bp4 = uctx;
2217 		resoptions = 0;
2218 		if (uctx->want_tcp) {
2219 			resoptions |= DNS_CLIENTRESOPT_TCP;
2220 		}
2221 		result = dns_client_startresolve(
2222 			uctx->client, &primary, uctx->rdclass, dns_rdatatype_a,
2223 			resoptions, uctx->client->task, resolveaddr_done,
2224 			&uctx->bp4, &uctx->restrans);
2225 		if (result == ISC_R_SUCCESS) {
2226 			uctx->bp6 = uctx;
2227 			result = dns_client_startresolve(
2228 				uctx->client, &primary, uctx->rdclass,
2229 				dns_rdatatype_aaaa, resoptions,
2230 				uctx->client->task, resolveaddr_done,
2231 				&uctx->bp6, &uctx->restrans2);
2232 		}
2233 		UNLOCK(&uctx->lock);
2234 	}
2235 
2236 	dns_rdata_freestruct(&soa);
2237 
2238 	return (result);
2239 }
2240 
2241 static void
2242 receive_soa(isc_task_t *task, isc_event_t *event) {
2243 	dns_requestevent_t *reqev = NULL;
2244 	updatectx_t *uctx;
2245 	dns_client_t *client;
2246 	isc_result_t result, eresult;
2247 	dns_request_t *request;
2248 	dns_message_t *rcvmsg = NULL;
2249 	dns_section_t section;
2250 	dns_rdataset_t *soaset = NULL;
2251 	int pass = 0;
2252 	dns_name_t *name;
2253 	dns_message_t *soaquery = NULL;
2254 	isc_sockaddr_t *addr;
2255 	bool seencname = false;
2256 	bool droplabel = false;
2257 	dns_name_t tname;
2258 	unsigned int nlabels, reqoptions;
2259 
2260 	UNUSED(task);
2261 
2262 	REQUIRE(event->ev_type == DNS_EVENT_REQUESTDONE);
2263 	reqev = (dns_requestevent_t *)event;
2264 	request = reqev->request;
2265 	result = eresult = reqev->result;
2266 	POST(result);
2267 	uctx = reqev->ev_arg;
2268 	client = uctx->client;
2269 	soaquery = uctx->soaquery;
2270 	addr = uctx->currentserver;
2271 	INSIST(addr != NULL);
2272 
2273 	isc_event_free(&event);
2274 
2275 	if (eresult != ISC_R_SUCCESS) {
2276 		result = eresult;
2277 		goto out;
2278 	}
2279 
2280 	dns_message_create(uctx->client->mctx, DNS_MESSAGE_INTENTPARSE,
2281 			   &rcvmsg);
2282 	result = dns_request_getresponse(request, rcvmsg,
2283 					 DNS_MESSAGEPARSE_PRESERVEORDER);
2284 
2285 	if (result == DNS_R_TSIGERRORSET) {
2286 		dns_request_t *newrequest = NULL;
2287 
2288 		/* Retry SOA request without TSIG */
2289 		dns_message_detach(&rcvmsg);
2290 		dns_message_renderreset(uctx->soaquery);
2291 		reqoptions = 0;
2292 		if (uctx->want_tcp) {
2293 			reqoptions |= DNS_REQUESTOPT_TCP;
2294 		}
2295 		result = dns_request_createvia(
2296 			uctx->view->requestmgr, uctx->soaquery, NULL, addr, -1,
2297 			reqoptions, NULL, client->find_timeout * 20,
2298 			client->find_timeout, 3, uctx->client->task,
2299 			receive_soa, uctx, &newrequest);
2300 		if (result == ISC_R_SUCCESS) {
2301 			LOCK(&uctx->lock);
2302 			dns_request_destroy(&uctx->soareq);
2303 			uctx->soareq = newrequest;
2304 			UNLOCK(&uctx->lock);
2305 
2306 			return;
2307 		}
2308 		goto out;
2309 	}
2310 
2311 	section = DNS_SECTION_ANSWER;
2312 	POST(section);
2313 
2314 	if (rcvmsg->rcode != dns_rcode_noerror &&
2315 	    rcvmsg->rcode != dns_rcode_nxdomain) {
2316 		result = rcode2result(rcvmsg->rcode);
2317 		goto out;
2318 	}
2319 
2320 lookforsoa:
2321 	if (pass == 0) {
2322 		section = DNS_SECTION_ANSWER;
2323 	} else if (pass == 1) {
2324 		section = DNS_SECTION_AUTHORITY;
2325 	} else {
2326 		droplabel = true;
2327 		goto out;
2328 	}
2329 
2330 	result = dns_message_firstname(rcvmsg, section);
2331 	if (result != ISC_R_SUCCESS) {
2332 		pass++;
2333 		goto lookforsoa;
2334 	}
2335 	while (result == ISC_R_SUCCESS) {
2336 		name = NULL;
2337 		dns_message_currentname(rcvmsg, section, &name);
2338 		soaset = NULL;
2339 		result = dns_message_findtype(name, dns_rdatatype_soa, 0,
2340 					      &soaset);
2341 		if (result == ISC_R_SUCCESS) {
2342 			break;
2343 		}
2344 		if (section == DNS_SECTION_ANSWER) {
2345 			dns_rdataset_t *tset = NULL;
2346 			if (dns_message_findtype(name, dns_rdatatype_cname, 0,
2347 						 &tset) == ISC_R_SUCCESS ||
2348 			    dns_message_findtype(name, dns_rdatatype_dname, 0,
2349 						 &tset) == ISC_R_SUCCESS)
2350 			{
2351 				seencname = true;
2352 				break;
2353 			}
2354 		}
2355 
2356 		result = dns_message_nextname(rcvmsg, section);
2357 	}
2358 
2359 	if (soaset == NULL && !seencname) {
2360 		pass++;
2361 		goto lookforsoa;
2362 	}
2363 
2364 	if (seencname) {
2365 		droplabel = true;
2366 		goto out;
2367 	}
2368 
2369 	result = process_soa(uctx, soaset, name);
2370 
2371 out:
2372 	if (droplabel) {
2373 		result = dns_message_firstname(soaquery, DNS_SECTION_QUESTION);
2374 		INSIST(result == ISC_R_SUCCESS);
2375 		name = NULL;
2376 		dns_message_currentname(soaquery, DNS_SECTION_QUESTION, &name);
2377 		nlabels = dns_name_countlabels(name);
2378 		if (nlabels == 1) {
2379 			result = DNS_R_SERVFAIL; /* is there a better error? */
2380 		} else {
2381 			dns_name_init(&tname, NULL);
2382 			dns_name_getlabelsequence(name, 1, nlabels - 1, &tname);
2383 			dns_name_clone(&tname, name);
2384 			dns_request_destroy(&request);
2385 			LOCK(&uctx->lock);
2386 			uctx->soareq = NULL;
2387 			UNLOCK(&uctx->lock);
2388 			dns_message_renderreset(soaquery);
2389 			dns_message_settsigkey(soaquery, NULL);
2390 			reqoptions = 0;
2391 			if (uctx->want_tcp) {
2392 				reqoptions |= DNS_REQUESTOPT_TCP;
2393 			}
2394 			result = dns_request_createvia(
2395 				uctx->view->requestmgr, soaquery, NULL,
2396 				uctx->currentserver, -1, reqoptions,
2397 				uctx->tsigkey, client->find_timeout * 20,
2398 				client->find_timeout, 3, client->task,
2399 				receive_soa, uctx, &uctx->soareq);
2400 		}
2401 	}
2402 
2403 	if (!droplabel || result != ISC_R_SUCCESS) {
2404 		dns_message_detach(&uctx->soaquery);
2405 		LOCK(&uctx->lock);
2406 		dns_request_destroy(&uctx->soareq);
2407 		UNLOCK(&uctx->lock);
2408 	}
2409 
2410 	if (rcvmsg != NULL) {
2411 		dns_message_detach(&rcvmsg);
2412 	}
2413 
2414 	if (result != ISC_R_SUCCESS) {
2415 		update_sendevent(uctx, result);
2416 	}
2417 }
2418 
2419 static isc_result_t
2420 request_soa(updatectx_t *uctx) {
2421 	isc_result_t result;
2422 	dns_message_t *soaquery = uctx->soaquery;
2423 	dns_name_t *name = NULL;
2424 	dns_rdataset_t *rdataset = NULL;
2425 	unsigned int reqoptions;
2426 
2427 	if (soaquery == NULL) {
2428 		dns_message_create(uctx->client->mctx, DNS_MESSAGE_INTENTRENDER,
2429 				   &soaquery);
2430 	}
2431 	soaquery->flags |= DNS_MESSAGEFLAG_RD;
2432 	result = dns_message_gettempname(soaquery, &name);
2433 	if (result != ISC_R_SUCCESS) {
2434 		goto fail;
2435 	}
2436 	result = dns_message_gettemprdataset(soaquery, &rdataset);
2437 	if (result != ISC_R_SUCCESS) {
2438 		goto fail;
2439 	}
2440 	dns_rdataset_makequestion(rdataset, uctx->rdclass, dns_rdatatype_soa);
2441 	dns_name_clone(uctx->firstname, name);
2442 	ISC_LIST_APPEND(name->list, rdataset, link);
2443 	dns_message_addname(soaquery, name, DNS_SECTION_QUESTION);
2444 	rdataset = NULL;
2445 	name = NULL;
2446 	reqoptions = 0;
2447 	if (uctx->want_tcp) {
2448 		reqoptions |= DNS_REQUESTOPT_TCP;
2449 	}
2450 
2451 	result = dns_request_createvia(
2452 		uctx->view->requestmgr, soaquery, NULL, uctx->currentserver, -1,
2453 		reqoptions, uctx->tsigkey, uctx->client->find_timeout * 20,
2454 		uctx->client->find_timeout, 3, uctx->client->task, receive_soa,
2455 		uctx, &uctx->soareq);
2456 	if (result == ISC_R_SUCCESS) {
2457 		uctx->soaquery = soaquery;
2458 		return (ISC_R_SUCCESS);
2459 	}
2460 
2461 fail:
2462 	if (rdataset != NULL) {
2463 		ISC_LIST_UNLINK(name->list, rdataset, link); /* for safety */
2464 		dns_message_puttemprdataset(soaquery, &rdataset);
2465 	}
2466 	if (name != NULL) {
2467 		dns_message_puttempname(soaquery, &name);
2468 	}
2469 	dns_message_detach(&soaquery);
2470 
2471 	return (result);
2472 }
2473 
2474 static void
2475 resolvesoa_done(isc_task_t *task, isc_event_t *event) {
2476 	dns_clientresevent_t *rev = (dns_clientresevent_t *)event;
2477 	updatectx_t *uctx;
2478 	dns_name_t *name, tname;
2479 	dns_rdataset_t *rdataset = NULL;
2480 	isc_result_t result = rev->result;
2481 	unsigned int nlabels, resoptions;
2482 
2483 	UNUSED(task);
2484 
2485 	uctx = event->ev_arg;
2486 	REQUIRE(UCTX_VALID(uctx));
2487 
2488 	LOCK(&uctx->lock);
2489 	dns_client_destroyrestrans(&uctx->restrans);
2490 	UNLOCK(&uctx->lock);
2491 
2492 	uctx = event->ev_arg;
2493 	if (result != ISC_R_SUCCESS && result != DNS_R_NCACHENXDOMAIN &&
2494 	    result != DNS_R_NCACHENXRRSET)
2495 	{
2496 		/* XXX: what about DNSSEC failure? */
2497 		goto out;
2498 	}
2499 
2500 	for (name = ISC_LIST_HEAD(rev->answerlist); name != NULL;
2501 	     name = ISC_LIST_NEXT(name, link))
2502 	{
2503 		for (rdataset = ISC_LIST_HEAD(name->list); rdataset != NULL;
2504 		     rdataset = ISC_LIST_NEXT(rdataset, link))
2505 		{
2506 			if (dns_rdataset_isassociated(rdataset) &&
2507 			    rdataset->type == dns_rdatatype_soa) {
2508 				break;
2509 			}
2510 		}
2511 	}
2512 
2513 	if (rdataset == NULL) {
2514 		/* Drop one label and retry resolution. */
2515 		nlabels = dns_name_countlabels(&uctx->soaqname);
2516 		if (nlabels == 1) {
2517 			result = DNS_R_SERVFAIL; /* is there a better error? */
2518 			goto out;
2519 		}
2520 		dns_name_init(&tname, NULL);
2521 		dns_name_getlabelsequence(&uctx->soaqname, 1, nlabels - 1,
2522 					  &tname);
2523 		dns_name_clone(&tname, &uctx->soaqname);
2524 		resoptions = 0;
2525 		if (uctx->want_tcp) {
2526 			resoptions |= DNS_CLIENTRESOPT_TCP;
2527 		}
2528 
2529 		result = dns_client_startresolve(
2530 			uctx->client, &uctx->soaqname, uctx->rdclass,
2531 			dns_rdatatype_soa, resoptions, uctx->client->task,
2532 			resolvesoa_done, uctx, &uctx->restrans);
2533 	} else {
2534 		result = process_soa(uctx, rdataset, &uctx->soaqname);
2535 	}
2536 
2537 out:
2538 	dns_client_freeresanswer(uctx->client, &rev->answerlist);
2539 	isc_event_free(&event);
2540 
2541 	if (result != ISC_R_SUCCESS) {
2542 		update_sendevent(uctx, result);
2543 	}
2544 }
2545 
2546 static isc_result_t
2547 copy_name(isc_mem_t *mctx, dns_message_t *msg, const dns_name_t *name,
2548 	  dns_name_t **newnamep) {
2549 	isc_result_t result;
2550 	dns_name_t *newname = NULL;
2551 	isc_region_t r;
2552 	isc_buffer_t *namebuf = NULL, *rdatabuf = NULL;
2553 	dns_rdatalist_t *rdatalist;
2554 	dns_rdataset_t *rdataset, *newrdataset;
2555 	dns_rdata_t rdata = DNS_RDATA_INIT, *newrdata;
2556 
2557 	result = dns_message_gettempname(msg, &newname);
2558 	if (result != ISC_R_SUCCESS) {
2559 		return (result);
2560 	}
2561 	isc_buffer_allocate(mctx, &namebuf, DNS_NAME_MAXWIRE);
2562 	dns_name_init(newname, NULL);
2563 	dns_name_setbuffer(newname, namebuf);
2564 	dns_message_takebuffer(msg, &namebuf);
2565 	dns_name_copynf(name, newname);
2566 
2567 	for (rdataset = ISC_LIST_HEAD(name->list); rdataset != NULL;
2568 	     rdataset = ISC_LIST_NEXT(rdataset, link))
2569 	{
2570 		rdatalist = NULL;
2571 		result = dns_message_gettemprdatalist(msg, &rdatalist);
2572 		if (result != ISC_R_SUCCESS) {
2573 			goto fail;
2574 		}
2575 		dns_rdatalist_init(rdatalist);
2576 		rdatalist->type = rdataset->type;
2577 		rdatalist->rdclass = rdataset->rdclass;
2578 		rdatalist->covers = rdataset->covers;
2579 		rdatalist->ttl = rdataset->ttl;
2580 
2581 		result = dns_rdataset_first(rdataset);
2582 		while (result == ISC_R_SUCCESS) {
2583 			dns_rdata_reset(&rdata);
2584 			dns_rdataset_current(rdataset, &rdata);
2585 
2586 			newrdata = NULL;
2587 			result = dns_message_gettemprdata(msg, &newrdata);
2588 			if (result != ISC_R_SUCCESS) {
2589 				goto fail;
2590 			}
2591 			dns_rdata_toregion(&rdata, &r);
2592 			rdatabuf = NULL;
2593 			isc_buffer_allocate(mctx, &rdatabuf, r.length);
2594 			isc_buffer_putmem(rdatabuf, r.base, r.length);
2595 			isc_buffer_usedregion(rdatabuf, &r);
2596 			dns_rdata_init(newrdata);
2597 			dns_rdata_fromregion(newrdata, rdata.rdclass,
2598 					     rdata.type, &r);
2599 			newrdata->flags = rdata.flags;
2600 
2601 			ISC_LIST_APPEND(rdatalist->rdata, newrdata, link);
2602 			dns_message_takebuffer(msg, &rdatabuf);
2603 
2604 			result = dns_rdataset_next(rdataset);
2605 		}
2606 
2607 		newrdataset = NULL;
2608 		result = dns_message_gettemprdataset(msg, &newrdataset);
2609 		if (result != ISC_R_SUCCESS) {
2610 			goto fail;
2611 		}
2612 		dns_rdatalist_tordataset(rdatalist, newrdataset);
2613 
2614 		ISC_LIST_APPEND(newname->list, newrdataset, link);
2615 	}
2616 
2617 	*newnamep = newname;
2618 
2619 	return (ISC_R_SUCCESS);
2620 
2621 fail:
2622 	dns_message_puttempname(msg, &newname);
2623 
2624 	return (result);
2625 }
2626 
2627 static void
2628 internal_update_callback(isc_task_t *task, isc_event_t *event) {
2629 	updatearg_t *uarg = event->ev_arg;
2630 	dns_clientupdateevent_t *uev = (dns_clientupdateevent_t *)event;
2631 
2632 	UNUSED(task);
2633 
2634 	LOCK(&uarg->lock);
2635 
2636 	uarg->result = uev->result;
2637 
2638 	dns_client_destroyupdatetrans(&uarg->trans);
2639 	isc_event_free(&event);
2640 
2641 	if (!uarg->canceled) {
2642 		UNLOCK(&uarg->lock);
2643 
2644 		/* Exit from the internal event loop */
2645 		isc_app_ctxsuspend(uarg->actx);
2646 	} else {
2647 		/*
2648 		 * We have already exited from the loop (due to some
2649 		 * unexpected event).  Just clean the arg up.
2650 		 */
2651 		UNLOCK(&uarg->lock);
2652 		isc_mutex_destroy(&uarg->lock);
2653 		isc_mem_put(uarg->client->mctx, uarg, sizeof(*uarg));
2654 	}
2655 }
2656 
2657 isc_result_t
2658 dns_client_update(dns_client_t *client, dns_rdataclass_t rdclass,
2659 		  const dns_name_t *zonename, dns_namelist_t *prerequisites,
2660 		  dns_namelist_t *updates, isc_sockaddrlist_t *servers,
2661 		  dns_tsec_t *tsec, unsigned int options) {
2662 	isc_result_t result;
2663 	isc_appctx_t *actx;
2664 	updatearg_t *uarg;
2665 
2666 	REQUIRE(DNS_CLIENT_VALID(client));
2667 
2668 	if ((client->attributes & DNS_CLIENTATTR_OWNCTX) == 0 &&
2669 	    (options & DNS_CLIENTUPDOPT_ALLOWRUN) == 0)
2670 	{
2671 		/*
2672 		 * If the client is run under application's control, we need
2673 		 * to create a new running (sub)environment for this
2674 		 * particular update.
2675 		 */
2676 		return (ISC_R_NOTIMPLEMENTED); /* XXXTBD */
2677 	} else {
2678 		actx = client->actx;
2679 	}
2680 
2681 	uarg = isc_mem_get(client->mctx, sizeof(*uarg));
2682 
2683 	isc_mutex_init(&uarg->lock);
2684 
2685 	uarg->actx = actx;
2686 	uarg->client = client;
2687 	uarg->result = ISC_R_FAILURE;
2688 	uarg->trans = NULL;
2689 	uarg->canceled = false;
2690 
2691 	result = dns_client_startupdate(
2692 		client, rdclass, zonename, prerequisites, updates, servers,
2693 		tsec, options, client->task, internal_update_callback, uarg,
2694 		&uarg->trans);
2695 	if (result != ISC_R_SUCCESS) {
2696 		isc_mutex_destroy(&uarg->lock);
2697 		isc_mem_put(client->mctx, uarg, sizeof(*uarg));
2698 		return (result);
2699 	}
2700 
2701 	/*
2702 	 * Start internal event loop.  It blocks until the entire process
2703 	 * is completed.
2704 	 */
2705 	result = isc_app_ctxrun(actx);
2706 
2707 	LOCK(&uarg->lock);
2708 	if (result == ISC_R_SUCCESS || result == ISC_R_SUSPEND) {
2709 		result = uarg->result;
2710 	}
2711 
2712 	if (uarg->trans != NULL) {
2713 		/*
2714 		 * Unusual termination (perhaps due to signal).  We need some
2715 		 * tricky cleanup process.
2716 		 */
2717 		uarg->canceled = true;
2718 		dns_client_cancelupdate(uarg->trans);
2719 
2720 		UNLOCK(&uarg->lock);
2721 
2722 		/* uarg will be freed in the event handler. */
2723 	} else {
2724 		UNLOCK(&uarg->lock);
2725 
2726 		isc_mutex_destroy(&uarg->lock);
2727 		isc_mem_put(client->mctx, uarg, sizeof(*uarg));
2728 	}
2729 
2730 	return (result);
2731 }
2732 
2733 static void
2734 startupdate(isc_task_t *task, isc_event_t *event) {
2735 	updatectx_t *uctx;
2736 	isc_result_t result;
2737 	unsigned int resoptions;
2738 
2739 	REQUIRE(event != NULL);
2740 
2741 	UNUSED(task);
2742 
2743 	uctx = event->ev_arg;
2744 
2745 	if (uctx->zonename != NULL && uctx->currentserver != NULL) {
2746 		result = send_update(uctx);
2747 		if (result != ISC_R_SUCCESS) {
2748 			goto fail;
2749 		}
2750 	} else if (uctx->currentserver != NULL) {
2751 		result = request_soa(uctx);
2752 		if (result != ISC_R_SUCCESS) {
2753 			goto fail;
2754 		}
2755 	} else {
2756 		resoptions = 0;
2757 		if (uctx->want_tcp) {
2758 			resoptions |= DNS_CLIENTRESOPT_TCP;
2759 		}
2760 		dns_name_clone(uctx->firstname, &uctx->soaqname);
2761 		result = dns_client_startresolve(
2762 			uctx->client, &uctx->soaqname, uctx->rdclass,
2763 			dns_rdatatype_soa, resoptions, uctx->client->task,
2764 			resolvesoa_done, uctx, &uctx->restrans);
2765 		if (result != ISC_R_SUCCESS) {
2766 			goto fail;
2767 		}
2768 	}
2769 
2770 	isc_event_free(&event);
2771 
2772 fail:
2773 	if (result != ISC_R_SUCCESS) {
2774 		update_sendevent(uctx, result);
2775 	}
2776 }
2777 
2778 isc_result_t
2779 dns_client_startupdate(dns_client_t *client, dns_rdataclass_t rdclass,
2780 		       const dns_name_t *zonename,
2781 		       dns_namelist_t *prerequisites, dns_namelist_t *updates,
2782 		       isc_sockaddrlist_t *servers, dns_tsec_t *tsec,
2783 		       unsigned int options, isc_task_t *task,
2784 		       isc_taskaction_t action, void *arg,
2785 		       dns_clientupdatetrans_t **transp) {
2786 	dns_view_t *view = NULL;
2787 	isc_result_t result;
2788 	dns_name_t *name, *newname;
2789 	updatectx_t *uctx;
2790 	isc_task_t *tclone = NULL;
2791 	dns_section_t section = DNS_SECTION_UPDATE;
2792 	isc_sockaddr_t *server, *sa = NULL;
2793 	dns_tsectype_t tsectype = dns_tsectype_none;
2794 	bool want_tcp;
2795 
2796 	UNUSED(options);
2797 
2798 	REQUIRE(DNS_CLIENT_VALID(client));
2799 	REQUIRE(transp != NULL && *transp == NULL);
2800 	REQUIRE(updates != NULL);
2801 	REQUIRE(task != NULL);
2802 
2803 	if (tsec != NULL) {
2804 		tsectype = dns_tsec_gettype(tsec);
2805 		if (tsectype != dns_tsectype_tsig) {
2806 			return (ISC_R_NOTIMPLEMENTED); /* XXX */
2807 		}
2808 	}
2809 
2810 	LOCK(&client->lock);
2811 	result = dns_viewlist_find(&client->viewlist, DNS_CLIENTVIEW_NAME,
2812 				   rdclass, &view);
2813 	UNLOCK(&client->lock);
2814 	if (result != ISC_R_SUCCESS) {
2815 		return (result);
2816 	}
2817 
2818 	want_tcp = ((options & DNS_CLIENTUPDOPT_TCP) != 0);
2819 
2820 	/*
2821 	 * Create a context and prepare some resources.
2822 	 */
2823 
2824 	uctx = isc_mem_get(client->mctx, sizeof(*uctx));
2825 
2826 	isc_mutex_init(&uctx->lock);
2827 
2828 	tclone = NULL;
2829 	isc_task_attach(task, &tclone);
2830 	uctx->client = client;
2831 	ISC_LINK_INIT(uctx, link);
2832 	uctx->state = dns_clientupdatestate_prepare;
2833 	uctx->view = view;
2834 	uctx->rdclass = rdclass;
2835 	uctx->canceled = false;
2836 	uctx->updatemsg = NULL;
2837 	uctx->soaquery = NULL;
2838 	uctx->updatereq = NULL;
2839 	uctx->restrans = NULL;
2840 	uctx->restrans2 = NULL;
2841 	uctx->bp4 = NULL;
2842 	uctx->bp6 = NULL;
2843 	uctx->soareq = NULL;
2844 	uctx->event = NULL;
2845 	uctx->tsigkey = NULL;
2846 	uctx->sig0key = NULL;
2847 	uctx->zonename = NULL;
2848 	uctx->want_tcp = want_tcp;
2849 	dns_name_init(&uctx->soaqname, NULL);
2850 	ISC_LIST_INIT(uctx->servers);
2851 	uctx->nservers = 0;
2852 	uctx->currentserver = NULL;
2853 	dns_fixedname_init(&uctx->zonefname);
2854 	if (tsec != NULL) {
2855 		dns_tsec_getkey(tsec, &uctx->tsigkey);
2856 	}
2857 	uctx->event = (dns_clientupdateevent_t *)isc_event_allocate(
2858 		client->mctx, tclone, DNS_EVENT_UPDATEDONE, action, arg,
2859 		sizeof(*uctx->event));
2860 	if (zonename != NULL) {
2861 		uctx->zonename = dns_fixedname_name(&uctx->zonefname);
2862 		dns_name_copynf(zonename, uctx->zonename);
2863 	}
2864 	if (servers != NULL) {
2865 		for (server = ISC_LIST_HEAD(*servers); server != NULL;
2866 		     server = ISC_LIST_NEXT(server, link))
2867 		{
2868 			sa = isc_mem_get(client->mctx, sizeof(*sa));
2869 			sa->type = server->type;
2870 			sa->length = server->length;
2871 			ISC_LINK_INIT(sa, link);
2872 			ISC_LIST_APPEND(uctx->servers, sa, link);
2873 			if (uctx->currentserver == NULL) {
2874 				uctx->currentserver = sa;
2875 			}
2876 			uctx->nservers++;
2877 		}
2878 	}
2879 
2880 	/* Make update message */
2881 	dns_message_create(client->mctx, DNS_MESSAGE_INTENTRENDER,
2882 			   &uctx->updatemsg);
2883 	uctx->updatemsg->opcode = dns_opcode_update;
2884 
2885 	if (prerequisites != NULL) {
2886 		for (name = ISC_LIST_HEAD(*prerequisites); name != NULL;
2887 		     name = ISC_LIST_NEXT(name, link))
2888 		{
2889 			newname = NULL;
2890 			result = copy_name(client->mctx, uctx->updatemsg, name,
2891 					   &newname);
2892 			if (result != ISC_R_SUCCESS) {
2893 				goto fail;
2894 			}
2895 			dns_message_addname(uctx->updatemsg, newname,
2896 					    DNS_SECTION_PREREQUISITE);
2897 		}
2898 	}
2899 
2900 	for (name = ISC_LIST_HEAD(*updates); name != NULL;
2901 	     name = ISC_LIST_NEXT(name, link))
2902 	{
2903 		newname = NULL;
2904 		result = copy_name(client->mctx, uctx->updatemsg, name,
2905 				   &newname);
2906 		if (result != ISC_R_SUCCESS) {
2907 			goto fail;
2908 		}
2909 		dns_message_addname(uctx->updatemsg, newname,
2910 				    DNS_SECTION_UPDATE);
2911 	}
2912 
2913 	uctx->firstname = NULL;
2914 	result = dns_message_firstname(uctx->updatemsg, section);
2915 	if (result == ISC_R_NOMORE) {
2916 		section = DNS_SECTION_PREREQUISITE;
2917 		result = dns_message_firstname(uctx->updatemsg, section);
2918 	}
2919 	if (result != ISC_R_SUCCESS) {
2920 		goto fail;
2921 	}
2922 	dns_message_currentname(uctx->updatemsg, section, &uctx->firstname);
2923 
2924 	uctx->magic = UCTX_MAGIC;
2925 
2926 	LOCK(&client->lock);
2927 	ISC_LIST_APPEND(client->updatectxs, uctx, link);
2928 	isc_refcount_increment(&client->references);
2929 	UNLOCK(&client->lock);
2930 
2931 	*transp = (dns_clientupdatetrans_t *)uctx;
2932 	result = isc_app_ctxonrun(client->actx, client->mctx, client->task,
2933 				  startupdate, uctx);
2934 	if (result == ISC_R_ALREADYRUNNING) {
2935 		isc_event_t *event;
2936 		event = isc_event_allocate(client->mctx, dns_client_startupdate,
2937 					   DNS_EVENT_STARTUPDATE, startupdate,
2938 					   uctx, sizeof(*event));
2939 		result = ISC_R_SUCCESS;
2940 		isc_task_send(task, &event);
2941 	}
2942 	if (result == ISC_R_SUCCESS) {
2943 		return (result);
2944 	}
2945 
2946 	isc_refcount_decrement1(&client->references);
2947 	*transp = NULL;
2948 
2949 fail:
2950 	if (ISC_LINK_LINKED(uctx, link)) {
2951 		LOCK(&client->lock);
2952 		ISC_LIST_UNLINK(client->updatectxs, uctx, link);
2953 		UNLOCK(&client->lock);
2954 	}
2955 	if (uctx->updatemsg != NULL) {
2956 		dns_message_detach(&uctx->updatemsg);
2957 	}
2958 	while ((sa = ISC_LIST_HEAD(uctx->servers)) != NULL) {
2959 		ISC_LIST_UNLINK(uctx->servers, sa, link);
2960 		isc_mem_put(client->mctx, sa, sizeof(*sa));
2961 	}
2962 	if (uctx->event != NULL) {
2963 		isc_event_free(ISC_EVENT_PTR(&uctx->event));
2964 	}
2965 	if (uctx->tsigkey != NULL) {
2966 		dns_tsigkey_detach(&uctx->tsigkey);
2967 	}
2968 	isc_task_detach(&tclone);
2969 	isc_mutex_destroy(&uctx->lock);
2970 	uctx->magic = 0;
2971 	isc_mem_put(client->mctx, uctx, sizeof(*uctx));
2972 	dns_view_detach(&view);
2973 
2974 	return (result);
2975 }
2976 
2977 void
2978 dns_client_cancelupdate(dns_clientupdatetrans_t *trans) {
2979 	updatectx_t *uctx;
2980 
2981 	REQUIRE(trans != NULL);
2982 	uctx = (updatectx_t *)trans;
2983 	REQUIRE(UCTX_VALID(uctx));
2984 
2985 	LOCK(&uctx->lock);
2986 
2987 	if (!uctx->canceled) {
2988 		uctx->canceled = true;
2989 		if (uctx->updatereq != NULL) {
2990 			dns_request_cancel(uctx->updatereq);
2991 		}
2992 		if (uctx->soareq != NULL) {
2993 			dns_request_cancel(uctx->soareq);
2994 		}
2995 		if (uctx->restrans != NULL) {
2996 			dns_client_cancelresolve(uctx->restrans);
2997 		}
2998 		if (uctx->restrans2 != NULL) {
2999 			dns_client_cancelresolve(uctx->restrans2);
3000 		}
3001 	}
3002 
3003 	UNLOCK(&uctx->lock);
3004 }
3005 
3006 void
3007 dns_client_destroyupdatetrans(dns_clientupdatetrans_t **transp) {
3008 	updatectx_t *uctx;
3009 	isc_mem_t *mctx;
3010 	dns_client_t *client;
3011 	isc_sockaddr_t *sa;
3012 
3013 	REQUIRE(transp != NULL);
3014 	uctx = (updatectx_t *)*transp;
3015 	*transp = NULL;
3016 	REQUIRE(UCTX_VALID(uctx));
3017 	client = uctx->client;
3018 	REQUIRE(DNS_CLIENT_VALID(client));
3019 	REQUIRE(uctx->updatereq == NULL && uctx->updatemsg == NULL &&
3020 		uctx->soareq == NULL && uctx->soaquery == NULL &&
3021 		uctx->event == NULL && uctx->tsigkey == NULL &&
3022 		uctx->sig0key == NULL);
3023 
3024 	mctx = client->mctx;
3025 	dns_view_detach(&uctx->view);
3026 	while ((sa = ISC_LIST_HEAD(uctx->servers)) != NULL) {
3027 		ISC_LIST_UNLINK(uctx->servers, sa, link);
3028 		isc_mem_put(mctx, sa, sizeof(*sa));
3029 	}
3030 
3031 	LOCK(&client->lock);
3032 
3033 	INSIST(ISC_LINK_LINKED(uctx, link));
3034 	ISC_LIST_UNLINK(client->updatectxs, uctx, link);
3035 
3036 	UNLOCK(&client->lock);
3037 
3038 	isc_mutex_destroy(&uctx->lock);
3039 	uctx->magic = 0;
3040 
3041 	isc_mem_put(mctx, uctx, sizeof(*uctx));
3042 
3043 	dns_client_destroy(&client);
3044 }
3045 
3046 isc_mem_t *
3047 dns_client_mctx(dns_client_t *client) {
3048 	REQUIRE(DNS_CLIENT_VALID(client));
3049 	return (client->mctx);
3050 }
3051 
3052 typedef struct {
3053 	isc_buffer_t buffer;
3054 	dns_rdataset_t rdataset;
3055 	dns_rdatalist_t rdatalist;
3056 	dns_rdata_t rdata;
3057 	size_t size;
3058 	isc_mem_t *mctx;
3059 	unsigned char data[FLEXIBLE_ARRAY_MEMBER];
3060 } dns_client_updaterec_t;
3061 
3062 isc_result_t
3063 dns_client_updaterec(dns_client_updateop_t op, const dns_name_t *owner,
3064 		     dns_rdatatype_t type, dns_rdata_t *source, dns_ttl_t ttl,
3065 		     dns_name_t *target, dns_rdataset_t *rdataset,
3066 		     dns_rdatalist_t *rdatalist, dns_rdata_t *rdata,
3067 		     isc_mem_t *mctx) {
3068 	dns_client_updaterec_t *updaterec = NULL;
3069 	size_t size = offsetof(dns_client_updaterec_t, data);
3070 
3071 	REQUIRE(op < updateop_max);
3072 	REQUIRE(owner != NULL);
3073 	REQUIRE((rdataset != NULL && rdatalist != NULL && rdata != NULL) ||
3074 		(rdataset == NULL && rdatalist == NULL && rdata == NULL &&
3075 		 mctx != NULL));
3076 	if (op == updateop_add) {
3077 		REQUIRE(source != NULL);
3078 	}
3079 	if (source != NULL) {
3080 		REQUIRE(source->type == type);
3081 		REQUIRE(op == updateop_add || op == updateop_delete ||
3082 			op == updateop_exist);
3083 	}
3084 
3085 	size += owner->length;
3086 	if (source != NULL) {
3087 		size += source->length;
3088 	}
3089 
3090 	if (rdataset == NULL) {
3091 		updaterec = isc_mem_get(mctx, size);
3092 		rdataset = &updaterec->rdataset;
3093 		rdatalist = &updaterec->rdatalist;
3094 		rdata = &updaterec->rdata;
3095 		dns_rdataset_init(rdataset);
3096 		dns_rdatalist_init(&updaterec->rdatalist);
3097 		dns_rdata_init(&updaterec->rdata);
3098 		isc_buffer_init(
3099 			&updaterec->buffer, updaterec->data,
3100 			(unsigned int)(size -
3101 				       offsetof(dns_client_updaterec_t, data)));
3102 		dns_name_copy(owner, target, &updaterec->buffer);
3103 		if (source != NULL) {
3104 			isc_region_t r;
3105 			dns_rdata_clone(source, rdata);
3106 			dns_rdata_toregion(rdata, &r);
3107 			rdata->data = isc_buffer_used(&updaterec->buffer);
3108 			isc_buffer_copyregion(&updaterec->buffer, &r);
3109 		}
3110 		updaterec->mctx = NULL;
3111 		isc_mem_attach(mctx, &updaterec->mctx);
3112 	} else if (source != NULL) {
3113 		dns_rdata_clone(source, rdata);
3114 	}
3115 
3116 	switch (op) {
3117 	case updateop_add:
3118 		break;
3119 	case updateop_delete:
3120 		if (source != NULL) {
3121 			ttl = 0;
3122 			dns_rdata_makedelete(rdata);
3123 		} else {
3124 			dns_rdata_deleterrset(rdata, type);
3125 		}
3126 		break;
3127 	case updateop_notexist:
3128 		dns_rdata_notexist(rdata, type);
3129 		break;
3130 	case updateop_exist:
3131 		if (source == NULL) {
3132 			ttl = 0;
3133 			dns_rdata_exists(rdata, type);
3134 		}
3135 	case updateop_none:
3136 		break;
3137 	default:
3138 		INSIST(0);
3139 		ISC_UNREACHABLE();
3140 	}
3141 
3142 	rdatalist->type = rdata->type;
3143 	rdatalist->rdclass = rdata->rdclass;
3144 	if (source != NULL) {
3145 		rdatalist->covers = dns_rdata_covers(rdata);
3146 		rdatalist->ttl = ttl;
3147 	}
3148 	ISC_LIST_APPEND(rdatalist->rdata, rdata, link);
3149 	dns_rdatalist_tordataset(rdatalist, rdataset);
3150 	ISC_LIST_APPEND(target->list, rdataset, link);
3151 	if (updaterec != NULL) {
3152 		target->attributes |= DNS_NAMEATTR_HASUPDATEREC;
3153 		dns_name_setbuffer(target, &updaterec->buffer);
3154 	}
3155 	if (op == updateop_add || op == updateop_delete) {
3156 		target->attributes |= DNS_NAMEATTR_UPDATE;
3157 	} else {
3158 		target->attributes |= DNS_NAMEATTR_PREREQUISITE;
3159 	}
3160 	return (ISC_R_SUCCESS);
3161 }
3162 
3163 void
3164 dns_client_freeupdate(dns_name_t **namep) {
3165 	dns_client_updaterec_t *updaterec;
3166 	dns_rdatalist_t *rdatalist;
3167 	dns_rdataset_t *rdataset;
3168 	dns_rdata_t *rdata;
3169 	dns_name_t *name;
3170 
3171 	REQUIRE(namep != NULL && *namep != NULL);
3172 
3173 	name = *namep;
3174 	for (rdataset = ISC_LIST_HEAD(name->list); rdataset != NULL;
3175 	     rdataset = ISC_LIST_HEAD(name->list))
3176 	{
3177 		ISC_LIST_UNLINK(name->list, rdataset, link);
3178 		rdatalist = NULL;
3179 		dns_rdatalist_fromrdataset(rdataset, &rdatalist);
3180 		if (rdatalist == NULL) {
3181 			dns_rdataset_disassociate(rdataset);
3182 			continue;
3183 		}
3184 		for (rdata = ISC_LIST_HEAD(rdatalist->rdata); rdata != NULL;
3185 		     rdata = ISC_LIST_HEAD(rdatalist->rdata))
3186 		{
3187 			ISC_LIST_UNLINK(rdatalist->rdata, rdata, link);
3188 		}
3189 		dns_rdataset_disassociate(rdataset);
3190 	}
3191 
3192 	if ((name->attributes & DNS_NAMEATTR_HASUPDATEREC) != 0) {
3193 		updaterec = (dns_client_updaterec_t *)name->buffer;
3194 		INSIST(updaterec != NULL);
3195 		isc_mem_putanddetach(&updaterec->mctx, updaterec,
3196 				     updaterec->size);
3197 		*namep = NULL;
3198 	}
3199 }
3200