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