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