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