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