2 * Copyright (C) 2009-2013 Internet Systems Consortium, Inc. ("ISC")
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.
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.
17 /* $Id: client.c,v 1.14 2011/03/12 04:59:47 tbox Exp $ */
25 #include <isc/mutex.h>
26 #include <isc/sockaddr.h>
27 #include <isc/socket.h>
29 #include <isc/timer.h>
33 #include <dns/client.h>
35 #include <dns/dispatch.h>
36 #include <dns/events.h>
37 #include <dns/forward.h>
38 #include <dns/keytable.h>
39 #include <dns/message.h>
41 #include <dns/rdata.h>
42 #include <dns/rdatalist.h>
43 #include <dns/rdataset.h>
44 #include <dns/rdatatype.h>
45 #include <dns/rdatasetiter.h>
46 #include <dns/rdatastruct.h>
47 #include <dns/request.h>
48 #include <dns/resolver.h>
49 #include <dns/result.h>
56 #define DNS_CLIENT_MAGIC ISC_MAGIC('D', 'N', 'S', 'c')
57 #define DNS_CLIENT_VALID(c) ISC_MAGIC_VALID(c, DNS_CLIENT_MAGIC)
59 #define RCTX_MAGIC ISC_MAGIC('R', 'c', 't', 'x')
60 #define RCTX_VALID(c) ISC_MAGIC_VALID(c, RCTX_MAGIC)
62 #define REQCTX_MAGIC ISC_MAGIC('R', 'q', 'c', 'x')
63 #define REQCTX_VALID(c) ISC_MAGIC_VALID(c, REQCTX_MAGIC)
65 #define UCTX_MAGIC ISC_MAGIC('U', 'c', 't', 'x')
66 #define UCTX_VALID(c) ISC_MAGIC_VALID(c, UCTX_MAGIC)
68 #define MAX_RESTARTS 16
76 unsigned int attributes;
80 isc_taskmgr_t *taskmgr;
82 isc_socketmgr_t *socketmgr;
83 isc_timermgr_t *timermgr;
84 dns_dispatchmgr_t *dispatchmgr;
85 dns_dispatch_t *dispatchv4;
86 dns_dispatch_t *dispatchv6;
88 unsigned int update_timeout;
89 unsigned int update_udptimeout;
90 unsigned int update_udpretries;
91 unsigned int find_timeout;
92 unsigned int find_udpretries;
95 unsigned int references;
96 dns_viewlist_t viewlist;
97 ISC_LIST(struct resctx) resctxs;
98 ISC_LIST(struct reqctx) reqctxs;
99 ISC_LIST(struct updatectx) updatectxs;
103 * Timeout/retry constants for dynamic update borrowed from nsupdate
105 #define DEF_UPDATE_TIMEOUT 300
106 #define MIN_UPDATE_TIMEOUT 30
107 #define DEF_UPDATE_UDPTIMEOUT 3
108 #define DEF_UPDATE_UDPRETRIES 3
110 #define DEF_FIND_TIMEOUT 5
111 #define DEF_FIND_UDPRETRIES 3
113 #define DNS_CLIENTATTR_OWNCTX 0x01
115 #define DNS_CLIENTVIEW_NAME "dnsclient"
118 * Internal state for a single name resolution procedure
120 typedef struct resctx {
124 dns_client_t *client;
125 isc_boolean_t want_dnssec;
128 ISC_LINK(struct resctx) link;
131 unsigned int restarts;
132 dns_fixedname_t name;
133 dns_rdatatype_t type;
135 dns_namelist_t namelist;
137 dns_clientresevent_t *event;
138 isc_boolean_t canceled;
139 dns_rdataset_t *rdataset;
140 dns_rdataset_t *sigrdataset;
144 * Argument of an internal event for synchronous name resolution.
146 typedef struct resarg {
149 dns_client_t *client;
154 isc_result_t vresult;
155 dns_namelist_t *namelist;
156 dns_clientrestrans_t *trans;
157 isc_boolean_t canceled;
161 * Internal state for a single DNS request
163 typedef struct reqctx {
167 dns_client_t *client;
168 unsigned int parseoptions;
171 ISC_LINK(struct reqctx) link;
172 isc_boolean_t canceled;
173 dns_tsigkey_t *tsigkey;
174 dns_request_t *request;
175 dns_clientreqevent_t *event;
179 * Argument of an internal event for synchronous DNS request.
181 typedef struct reqarg {
184 dns_client_t *client;
189 dns_clientreqtrans_t *trans;
190 isc_boolean_t canceled;
194 * Argument of an internal event for synchronous name resolution.
196 typedef struct updatearg {
199 dns_client_t *client;
204 dns_clientupdatetrans_t *trans;
205 isc_boolean_t canceled;
209 * Internal state for a single dynamic update procedure
211 typedef struct updatectx {
215 dns_client_t *client;
218 dns_request_t *updatereq;
219 dns_request_t *soareq;
220 dns_clientrestrans_t *restrans;
221 dns_clientrestrans_t *restrans2;
222 isc_boolean_t canceled;
225 ISC_LINK(struct updatectx) link;
226 dns_clientupdatestate_t state;
227 dns_rdataclass_t rdclass;
229 dns_message_t *updatemsg;
230 dns_message_t *soaquery;
231 dns_clientupdateevent_t *event;
232 dns_tsigkey_t *tsigkey;
234 dns_name_t *firstname;
236 dns_fixedname_t zonefname;
237 dns_name_t *zonename;
238 isc_sockaddrlist_t servers;
239 unsigned int nservers;
240 isc_sockaddr_t *currentserver;
241 struct updatectx *bp4;
242 struct updatectx *bp6;
245 static isc_result_t request_soa(updatectx_t *uctx);
246 static void client_resfind(resctx_t *rctx, dns_fetchevent_t *event);
247 static isc_result_t send_update(updatectx_t *uctx);
250 getudpdispatch(int family, dns_dispatchmgr_t *dispatchmgr,
251 isc_socketmgr_t *socketmgr, isc_taskmgr_t *taskmgr,
252 isc_boolean_t is_shared, dns_dispatch_t **dispp,
253 isc_sockaddr_t *localaddr)
255 unsigned int attrs, attrmask;
256 dns_dispatch_t *disp;
257 unsigned buffersize, maxbuffers, maxrequests, buckets, increment;
259 isc_sockaddr_t anyaddr;
262 attrs |= DNS_DISPATCHATTR_UDP;
265 attrs |= DNS_DISPATCHATTR_IPV4;
268 attrs |= DNS_DISPATCHATTR_IPV6;
274 attrmask |= DNS_DISPATCHATTR_UDP;
275 attrmask |= DNS_DISPATCHATTR_TCP;
276 attrmask |= DNS_DISPATCHATTR_IPV4;
277 attrmask |= DNS_DISPATCHATTR_IPV6;
279 if (localaddr == NULL) {
280 localaddr = &anyaddr;
281 isc_sockaddr_anyofpf(localaddr, family);
285 maxbuffers = is_shared ? 1000 : 8;
287 buckets = is_shared ? 16411 : 3;
288 increment = is_shared ? 16433 : 5;
291 result = dns_dispatch_getudp(dispatchmgr, socketmgr,
293 buffersize, maxbuffers, maxrequests,
295 attrs, attrmask, &disp);
296 if (result == ISC_R_SUCCESS)
303 dns_client_createview(isc_mem_t *mctx, dns_rdataclass_t rdclass,
304 unsigned int options, isc_taskmgr_t *taskmgr,
305 unsigned int ntasks, isc_socketmgr_t *socketmgr,
306 isc_timermgr_t *timermgr, dns_dispatchmgr_t *dispatchmgr,
307 dns_dispatch_t *dispatchv4, dns_dispatch_t *dispatchv6,
311 dns_view_t *view = NULL;
314 result = dns_view_create(mctx, rdclass, DNS_CLIENTVIEW_NAME, &view);
315 if (result != ISC_R_SUCCESS)
318 /* Initialize view security roots */
319 result = dns_view_initsecroots(view, mctx);
320 if (result != ISC_R_SUCCESS) {
321 dns_view_detach(&view);
325 result = dns_view_createresolver(view, taskmgr, ntasks, 1, socketmgr,
326 timermgr, 0, dispatchmgr,
327 dispatchv4, dispatchv6);
328 if (result != ISC_R_SUCCESS) {
329 dns_view_detach(&view);
335 * XXX: it may be better if specific DB implementations can be
336 * specified via some configuration knob.
338 if ((options & DNS_CLIENTCREATEOPT_USECACHE) != 0)
342 result = dns_db_create(mctx, dbtype, dns_rootname, dns_dbtype_cache,
343 rdclass, 0, NULL, &view->cachedb);
344 if (result != ISC_R_SUCCESS) {
345 dns_view_detach(&view);
350 return (ISC_R_SUCCESS);
354 dns_client_create(dns_client_t **clientp, unsigned int options) {
356 isc_mem_t *mctx = NULL;
357 isc_appctx_t *actx = NULL;
358 isc_taskmgr_t *taskmgr = NULL;
359 isc_socketmgr_t *socketmgr = NULL;
360 isc_timermgr_t *timermgr = NULL;
362 /* XXXMPA add debug logging support */
363 isc_log_t *lctx = NULL;
364 isc_logconfig_t *logconfig = NULL;
365 unsigned int logdebuglevel = 0;
368 result = isc_mem_create(0, 0, &mctx);
369 if (result != ISC_R_SUCCESS)
371 result = isc_appctx_create(mctx, &actx);
372 if (result != ISC_R_SUCCESS)
374 result = isc_app_ctxstart(actx);
375 if (result != ISC_R_SUCCESS)
377 result = isc_taskmgr_createinctx(mctx, actx, 1, 0, &taskmgr);
378 if (result != ISC_R_SUCCESS)
380 result = isc_socketmgr_createinctx(mctx, actx, &socketmgr);
381 if (result != ISC_R_SUCCESS)
383 result = isc_timermgr_createinctx(mctx, actx, &timermgr);
384 if (result != ISC_R_SUCCESS)
387 result = isc_log_create(mctx, &lctx, &logconfig);
388 if (result != ISC_R_SUCCESS)
390 isc_log_setcontext(lctx);
392 dns_log_setcontext(lctx);
393 result = isc_log_usechannel(logconfig, "default_debug", NULL, NULL);
394 if (result != ISC_R_SUCCESS)
396 isc_log_setdebuglevel(lctx, logdebuglevel);
398 result = dns_client_createx(mctx, actx, taskmgr, socketmgr, timermgr,
400 if (result != ISC_R_SUCCESS)
403 (*clientp)->attributes |= DNS_CLIENTATTR_OWNCTX;
405 /* client has its own reference to mctx, so we can detach it here */
406 isc_mem_detach(&mctx);
408 return (ISC_R_SUCCESS);
412 isc_taskmgr_destroy(&taskmgr);
413 if (timermgr != NULL)
414 isc_timermgr_destroy(&timermgr);
415 if (socketmgr != NULL)
416 isc_socketmgr_destroy(&socketmgr);
418 isc_appctx_destroy(&actx);
419 isc_mem_detach(&mctx);
425 dns_client_createx(isc_mem_t *mctx, isc_appctx_t *actx, isc_taskmgr_t *taskmgr,
426 isc_socketmgr_t *socketmgr, isc_timermgr_t *timermgr,
427 unsigned int options, dns_client_t **clientp)
430 result = dns_client_createx2(mctx, actx, taskmgr, socketmgr, timermgr,
431 options, clientp, NULL, NULL);
436 dns_client_createx2(isc_mem_t *mctx, isc_appctx_t *actx,
437 isc_taskmgr_t *taskmgr, isc_socketmgr_t *socketmgr,
438 isc_timermgr_t *timermgr, unsigned int options,
439 dns_client_t **clientp, isc_sockaddr_t *localaddr4,
440 isc_sockaddr_t *localaddr6)
442 dns_client_t *client;
444 dns_dispatchmgr_t *dispatchmgr = NULL;
445 dns_dispatch_t *dispatchv4 = NULL;
446 dns_dispatch_t *dispatchv6 = NULL;
447 dns_view_t *view = NULL;
449 REQUIRE(mctx != NULL);
450 REQUIRE(taskmgr != NULL);
451 REQUIRE(timermgr != NULL);
452 REQUIRE(socketmgr != NULL);
453 REQUIRE(clientp != NULL && *clientp == NULL);
455 client = isc_mem_get(mctx, sizeof(*client));
457 return (ISC_R_NOMEMORY);
459 result = isc_mutex_init(&client->lock);
460 if (result != ISC_R_SUCCESS) {
461 isc_mem_put(mctx, client, sizeof(*client));
466 client->taskmgr = taskmgr;
467 client->socketmgr = socketmgr;
468 client->timermgr = timermgr;
471 result = isc_task_create(client->taskmgr, 0, &client->task);
472 if (result != ISC_R_SUCCESS)
475 result = dns_dispatchmgr_create(mctx, NULL, &dispatchmgr);
476 if (result != ISC_R_SUCCESS)
478 client->dispatchmgr = dispatchmgr;
481 * If only one address family is specified, use it.
482 * If neither family is specified, or if both are, use both.
484 client->dispatchv4 = NULL;
485 if (localaddr4 != NULL || localaddr6 == NULL) {
486 result = getudpdispatch(AF_INET, dispatchmgr, socketmgr,
488 &dispatchv4, localaddr4);
489 if (result == ISC_R_SUCCESS)
490 client->dispatchv4 = dispatchv4;
493 client->dispatchv6 = NULL;
494 if (localaddr6 != NULL || localaddr4 == NULL) {
495 result = getudpdispatch(AF_INET6, dispatchmgr, socketmgr,
497 &dispatchv6, localaddr6);
498 if (result == ISC_R_SUCCESS)
499 client->dispatchv6 = dispatchv6;
502 /* We need at least one of the dispatchers */
503 if (dispatchv4 == NULL && dispatchv6 == NULL) {
504 INSIST(result != ISC_R_SUCCESS);
508 /* Create the default view for class IN */
509 result = dns_client_createview(mctx, dns_rdataclass_in, options,
510 taskmgr, 31, socketmgr, timermgr,
511 dispatchmgr, dispatchv4, dispatchv6,
513 if (result != ISC_R_SUCCESS)
515 ISC_LIST_INIT(client->viewlist);
516 ISC_LIST_APPEND(client->viewlist, view, link);
518 dns_view_freeze(view); /* too early? */
520 ISC_LIST_INIT(client->resctxs);
521 ISC_LIST_INIT(client->reqctxs);
522 ISC_LIST_INIT(client->updatectxs);
525 isc_mem_attach(mctx, &client->mctx);
527 client->update_timeout = DEF_UPDATE_TIMEOUT;
528 client->update_udptimeout = DEF_UPDATE_UDPTIMEOUT;
529 client->update_udpretries = DEF_UPDATE_UDPRETRIES;
530 client->find_timeout = DEF_FIND_TIMEOUT;
531 client->find_udpretries = DEF_FIND_UDPRETRIES;
532 client->attributes = 0;
534 client->references = 1;
535 client->magic = DNS_CLIENT_MAGIC;
539 return (ISC_R_SUCCESS);
542 if (dispatchv4 != NULL)
543 dns_dispatch_detach(&dispatchv4);
544 if (dispatchv6 != NULL)
545 dns_dispatch_detach(&dispatchv6);
546 if (dispatchmgr != NULL)
547 dns_dispatchmgr_destroy(&dispatchmgr);
548 if (client->task != NULL)
549 isc_task_detach(&client->task);
550 isc_mem_put(mctx, client, sizeof(*client));
556 destroyclient(dns_client_t **clientp) {
557 dns_client_t *client = *clientp;
560 while ((view = ISC_LIST_HEAD(client->viewlist)) != NULL) {
561 ISC_LIST_UNLINK(client->viewlist, view, link);
562 dns_view_detach(&view);
565 if (client->dispatchv4 != NULL)
566 dns_dispatch_detach(&client->dispatchv4);
567 if (client->dispatchv6 != NULL)
568 dns_dispatch_detach(&client->dispatchv6);
570 dns_dispatchmgr_destroy(&client->dispatchmgr);
572 isc_task_detach(&client->task);
575 * If the client has created its own running environments,
578 if ((client->attributes & DNS_CLIENTATTR_OWNCTX) != 0) {
579 isc_taskmgr_destroy(&client->taskmgr);
580 isc_timermgr_destroy(&client->timermgr);
581 isc_socketmgr_destroy(&client->socketmgr);
583 isc_app_ctxfinish(client->actx);
584 isc_appctx_destroy(&client->actx);
587 DESTROYLOCK(&client->lock);
590 isc_mem_putanddetach(&client->mctx, client, sizeof(*client));
596 dns_client_destroy(dns_client_t **clientp) {
597 dns_client_t *client;
598 isc_boolean_t destroyok = ISC_FALSE;
600 REQUIRE(clientp != NULL);
602 REQUIRE(DNS_CLIENT_VALID(client));
605 client->references--;
606 if (client->references == 0 && ISC_LIST_EMPTY(client->resctxs) &&
607 ISC_LIST_EMPTY(client->reqctxs) &&
608 ISC_LIST_EMPTY(client->updatectxs)) {
609 destroyok = ISC_TRUE;
611 UNLOCK(&client->lock);
614 destroyclient(&client);
620 dns_client_setservers(dns_client_t *client, dns_rdataclass_t rdclass,
621 dns_name_t *namespace, isc_sockaddrlist_t *addrs)
624 dns_view_t *view = NULL;
626 REQUIRE(DNS_CLIENT_VALID(client));
627 REQUIRE(addrs != NULL);
629 if (namespace == NULL)
630 namespace = dns_rootname;
633 result = dns_viewlist_find(&client->viewlist, DNS_CLIENTVIEW_NAME,
635 if (result != ISC_R_SUCCESS) {
636 UNLOCK(&client->lock);
639 UNLOCK(&client->lock);
641 result = dns_fwdtable_add(view->fwdtable, namespace, addrs,
644 dns_view_detach(&view);
650 dns_client_clearservers(dns_client_t *client, dns_rdataclass_t rdclass,
651 dns_name_t *namespace)
654 dns_view_t *view = NULL;
656 REQUIRE(DNS_CLIENT_VALID(client));
658 if (namespace == NULL)
659 namespace = dns_rootname;
662 result = dns_viewlist_find(&client->viewlist, DNS_CLIENTVIEW_NAME,
664 if (result != ISC_R_SUCCESS) {
665 UNLOCK(&client->lock);
668 UNLOCK(&client->lock);
670 result = dns_fwdtable_delete(view->fwdtable, namespace);
672 dns_view_detach(&view);
678 getrdataset(isc_mem_t *mctx, dns_rdataset_t **rdatasetp) {
679 dns_rdataset_t *rdataset;
681 REQUIRE(mctx != NULL);
682 REQUIRE(rdatasetp != NULL && *rdatasetp == NULL);
684 rdataset = isc_mem_get(mctx, sizeof(*rdataset));
685 if (rdataset == NULL)
686 return (ISC_R_NOMEMORY);
688 dns_rdataset_init(rdataset);
690 *rdatasetp = rdataset;
692 return (ISC_R_SUCCESS);
696 putrdataset(isc_mem_t *mctx, dns_rdataset_t **rdatasetp) {
697 dns_rdataset_t *rdataset;
699 REQUIRE(rdatasetp != NULL);
700 rdataset = *rdatasetp;
701 REQUIRE(rdataset != NULL);
703 if (dns_rdataset_isassociated(rdataset))
704 dns_rdataset_disassociate(rdataset);
706 isc_mem_put(mctx, rdataset, sizeof(*rdataset));
712 fetch_done(isc_task_t *task, isc_event_t *event) {
713 resctx_t *rctx = event->ev_arg;
714 dns_fetchevent_t *fevent;
716 REQUIRE(event->ev_type == DNS_EVENT_FETCHDONE);
717 REQUIRE(RCTX_VALID(rctx));
718 REQUIRE(rctx->task == task);
719 fevent = (dns_fetchevent_t *)event;
721 client_resfind(rctx, fevent);
724 static inline isc_result_t
725 start_fetch(resctx_t *rctx) {
729 * The caller must be holding the rctx's lock.
732 REQUIRE(rctx->fetch == NULL);
734 result = dns_resolver_createfetch(rctx->view->resolver,
735 dns_fixedname_name(&rctx->name),
738 rctx->task, fetch_done, rctx,
747 view_find(resctx_t *rctx, dns_db_t **dbp, dns_dbnode_t **nodep,
748 dns_name_t *foundname)
751 dns_name_t *name = dns_fixedname_name(&rctx->name);
752 dns_rdatatype_t type;
754 if (rctx->type == dns_rdatatype_rrsig)
755 type = dns_rdatatype_any;
759 result = dns_view_find(rctx->view, name, type, 0, 0, ISC_FALSE,
760 dbp, nodep, foundname, rctx->rdataset,
767 client_resfind(resctx_t *rctx, dns_fetchevent_t *event) {
769 isc_result_t tresult, result = ISC_R_SUCCESS;
770 isc_result_t vresult = ISC_R_SUCCESS;
771 isc_boolean_t want_restart;
772 isc_boolean_t send_event = ISC_FALSE;
773 dns_name_t *name, *prefix;
774 dns_fixedname_t foundname, fixed;
775 dns_rdataset_t *trdataset;
776 dns_rdata_t rdata = DNS_RDATA_INIT;
777 unsigned int nlabels;
779 dns_namereln_t namereln;
780 dns_rdata_cname_t cname;
781 dns_rdata_dname_t dname;
783 REQUIRE(RCTX_VALID(rctx));
787 mctx = rctx->view->mctx;
789 name = dns_fixedname_name(&rctx->name);
792 dns_name_t *fname = NULL;
793 dns_name_t *ansname = NULL;
795 dns_dbnode_t *node = NULL;
798 want_restart = ISC_FALSE;
800 if (event == NULL && !rctx->canceled) {
801 dns_fixedname_init(&foundname);
802 fname = dns_fixedname_name(&foundname);
803 INSIST(!dns_rdataset_isassociated(rctx->rdataset));
804 INSIST(rctx->sigrdataset == NULL ||
805 !dns_rdataset_isassociated(rctx->sigrdataset));
806 result = view_find(rctx, &db, &node, fname);
807 if (result == ISC_R_NOTFOUND) {
809 * We don't know anything about the name.
814 dns_db_detachnode(db, &node);
818 result = start_fetch(rctx);
819 if (result != ISC_R_SUCCESS) {
820 putrdataset(mctx, &rctx->rdataset);
821 if (rctx->sigrdataset != NULL)
824 send_event = ISC_TRUE;
829 INSIST(event != NULL);
830 INSIST(event->fetch == rctx->fetch);
831 dns_resolver_destroyfetch(&rctx->fetch);
834 result = event->result;
835 vresult = event->vresult;
836 fname = dns_fixedname_name(&event->foundname);
837 INSIST(event->rdataset == rctx->rdataset);
838 INSIST(event->sigrdataset == rctx->sigrdataset);
842 * If we've been canceled, forget about the result.
845 result = ISC_R_CANCELED;
848 * Otherwise, get some resource for copying the
851 ansname = isc_mem_get(mctx, sizeof(*ansname));
853 tresult = ISC_R_NOMEMORY;
857 aname = dns_fixedname_name(&rctx->name);
858 dns_name_init(ansname, NULL);
859 tresult = dns_name_dup(aname, mctx, ansname);
860 if (tresult != ISC_R_SUCCESS)
861 isc_mem_put(mctx, ansname,
864 if (tresult != ISC_R_SUCCESS)
870 send_event = ISC_TRUE;
872 * This case is handled in the main line below.
877 * Add the CNAME to the answer list.
879 trdataset = rctx->rdataset;
880 ISC_LIST_APPEND(ansname->list, rctx->rdataset, link);
881 rctx->rdataset = NULL;
882 if (rctx->sigrdataset != NULL) {
883 ISC_LIST_APPEND(ansname->list,
884 rctx->sigrdataset, link);
885 rctx->sigrdataset = NULL;
887 ISC_LIST_APPEND(rctx->namelist, ansname, link);
891 * Copy the CNAME's target into the lookup's
892 * query name and start over.
894 tresult = dns_rdataset_first(trdataset);
895 if (tresult != ISC_R_SUCCESS)
897 dns_rdataset_current(trdataset, &rdata);
898 tresult = dns_rdata_tostruct(&rdata, &cname, NULL);
899 dns_rdata_reset(&rdata);
900 if (tresult != ISC_R_SUCCESS)
902 tresult = dns_name_copy(&cname.cname, name, NULL);
903 dns_rdata_freestruct(&cname);
904 if (tresult == ISC_R_SUCCESS)
905 want_restart = ISC_TRUE;
911 * Add the DNAME to the answer list.
913 trdataset = rctx->rdataset;
914 ISC_LIST_APPEND(ansname->list, rctx->rdataset, link);
915 rctx->rdataset = NULL;
916 if (rctx->sigrdataset != NULL) {
917 ISC_LIST_APPEND(ansname->list,
918 rctx->sigrdataset, link);
919 rctx->sigrdataset = NULL;
921 ISC_LIST_APPEND(rctx->namelist, ansname, link);
924 namereln = dns_name_fullcompare(name, fname, &order,
926 INSIST(namereln == dns_namereln_subdomain);
928 * Get the target name of the DNAME.
930 tresult = dns_rdataset_first(trdataset);
931 if (tresult != ISC_R_SUCCESS) {
935 dns_rdataset_current(trdataset, &rdata);
936 tresult = dns_rdata_tostruct(&rdata, &dname, NULL);
937 dns_rdata_reset(&rdata);
938 if (tresult != ISC_R_SUCCESS) {
943 * Construct the new query name and start over.
945 dns_fixedname_init(&fixed);
946 prefix = dns_fixedname_name(&fixed);
947 dns_name_split(name, nlabels, prefix, NULL);
948 tresult = dns_name_concatenate(prefix, &dname.dname,
950 dns_rdata_freestruct(&dname);
951 if (tresult == ISC_R_SUCCESS)
952 want_restart = ISC_TRUE;
956 case DNS_R_NCACHENXDOMAIN:
957 case DNS_R_NCACHENXRRSET:
958 ISC_LIST_APPEND(ansname->list, rctx->rdataset, link);
959 ISC_LIST_APPEND(rctx->namelist, ansname, link);
961 rctx->rdataset = NULL;
962 /* What about sigrdataset? */
963 if (rctx->sigrdataset != NULL)
964 putrdataset(mctx, &rctx->sigrdataset);
965 send_event = ISC_TRUE;
968 if (rctx->rdataset != NULL)
969 putrdataset(mctx, &rctx->rdataset);
970 if (rctx->sigrdataset != NULL)
971 putrdataset(mctx, &rctx->sigrdataset);
972 send_event = ISC_TRUE;
976 if (rctx->type == dns_rdatatype_any) {
978 dns_rdatasetiter_t *rdsiter = NULL;
980 tresult = dns_db_allrdatasets(db, node, NULL, 0,
982 if (tresult != ISC_R_SUCCESS) {
987 tresult = dns_rdatasetiter_first(rdsiter);
988 while (tresult == ISC_R_SUCCESS) {
989 dns_rdatasetiter_current(rdsiter,
991 if (rctx->rdataset->type != 0) {
992 ISC_LIST_APPEND(ansname->list,
996 rctx->rdataset = NULL;
999 * We're not interested in this
1002 dns_rdataset_disassociate(
1005 tresult = dns_rdatasetiter_next(rdsiter);
1007 if (tresult == ISC_R_SUCCESS &&
1008 rctx->rdataset == NULL) {
1009 tresult = getrdataset(mctx,
1011 if (tresult != ISC_R_SUCCESS) {
1020 * We didn't match any rdatasets (which means
1021 * something went wrong in this
1024 result = DNS_R_SERVFAIL; /* better code? */
1027 ISC_LIST_APPEND(rctx->namelist, ansname, link);
1030 dns_rdatasetiter_destroy(&rdsiter);
1031 if (tresult != ISC_R_NOMORE)
1032 result = DNS_R_SERVFAIL; /* ditto */
1034 result = ISC_R_SUCCESS;
1038 * This is the "normal" case -- an ordinary question
1039 * to which we've got the answer.
1041 ISC_LIST_APPEND(ansname->list, rctx->rdataset, link);
1042 rctx->rdataset = NULL;
1043 if (rctx->sigrdataset != NULL) {
1044 ISC_LIST_APPEND(ansname->list,
1045 rctx->sigrdataset, link);
1046 rctx->sigrdataset = NULL;
1048 ISC_LIST_APPEND(rctx->namelist, ansname, link);
1054 * Free temporary resources
1056 if (ansname != NULL) {
1057 dns_rdataset_t *rdataset;
1059 while ((rdataset = ISC_LIST_HEAD(ansname->list))
1061 ISC_LIST_UNLINK(ansname->list, rdataset, link);
1062 putrdataset(mctx, &rdataset);
1064 dns_name_free(ansname, mctx);
1065 isc_mem_put(mctx, ansname, sizeof(*ansname));
1069 dns_db_detachnode(db, &node);
1073 isc_event_free(ISC_EVENT_PTR(&event));
1076 * Limit the number of restarts.
1078 if (want_restart && rctx->restarts == MAX_RESTARTS) {
1079 want_restart = ISC_FALSE;
1080 result = ISC_R_QUOTA;
1081 send_event = ISC_TRUE;
1085 * Prepare further find with new resources
1088 INSIST(rctx->rdataset == NULL &&
1089 rctx->sigrdataset == NULL);
1091 result = getrdataset(mctx, &rctx->rdataset);
1092 if (result == ISC_R_SUCCESS && rctx->want_dnssec) {
1093 result = getrdataset(mctx, &rctx->sigrdataset);
1094 if (result != ISC_R_SUCCESS) {
1095 putrdataset(mctx, &rctx->rdataset);
1099 if (result != ISC_R_SUCCESS) {
1100 want_restart = ISC_FALSE;
1101 send_event = ISC_TRUE;
1104 } while (want_restart);
1109 while ((name = ISC_LIST_HEAD(rctx->namelist)) != NULL) {
1110 ISC_LIST_UNLINK(rctx->namelist, name, link);
1111 ISC_LIST_APPEND(rctx->event->answerlist, name, link);
1114 rctx->event->result = result;
1115 rctx->event->vresult = vresult;
1116 task = rctx->event->ev_sender;
1117 rctx->event->ev_sender = rctx;
1118 isc_task_sendanddetach(&task, ISC_EVENT_PTR(&rctx->event));
1121 UNLOCK(&rctx->lock);
1126 suspend(isc_task_t *task, isc_event_t *event) {
1127 isc_appctx_t *actx = event->ev_arg;
1131 isc_app_ctxsuspend(actx);
1132 isc_event_free(&event);
1136 resolve_done(isc_task_t *task, isc_event_t *event) {
1137 resarg_t *resarg = event->ev_arg;
1138 dns_clientresevent_t *rev = (dns_clientresevent_t *)event;
1140 isc_result_t result;
1144 LOCK(&resarg->lock);
1146 resarg->result = rev->result;
1147 resarg->vresult = rev->vresult;
1148 while ((name = ISC_LIST_HEAD(rev->answerlist)) != NULL) {
1149 ISC_LIST_UNLINK(rev->answerlist, name, link);
1150 ISC_LIST_APPEND(*resarg->namelist, name, link);
1153 dns_client_destroyrestrans(&resarg->trans);
1154 isc_event_free(&event);
1156 if (!resarg->canceled) {
1157 UNLOCK(&resarg->lock);
1160 * We may or may not be running. isc__appctx_onrun will
1161 * fail if we are currently running otherwise we post a
1162 * action to call isc_app_ctxsuspend when we do start
1165 result = isc_app_ctxonrun(resarg->actx, resarg->client->mctx,
1166 task, suspend, resarg->actx);
1167 if (result == ISC_R_ALREADYRUNNING)
1168 isc_app_ctxsuspend(resarg->actx);
1171 * We have already exited from the loop (due to some
1172 * unexpected event). Just clean the arg up.
1174 UNLOCK(&resarg->lock);
1175 DESTROYLOCK(&resarg->lock);
1176 isc_mem_put(resarg->client->mctx, resarg, sizeof(*resarg));
1181 dns_client_resolve(dns_client_t *client, dns_name_t *name,
1182 dns_rdataclass_t rdclass, dns_rdatatype_t type,
1183 unsigned int options, dns_namelist_t *namelist)
1185 isc_result_t result;
1189 REQUIRE(DNS_CLIENT_VALID(client));
1190 REQUIRE(namelist != NULL && ISC_LIST_EMPTY(*namelist));
1192 if ((client->attributes & DNS_CLIENTATTR_OWNCTX) == 0 &&
1193 (options & DNS_CLIENTRESOPT_ALLOWRUN) == 0) {
1195 * If the client is run under application's control, we need
1196 * to create a new running (sub)environment for this
1197 * particular resolution.
1199 return (ISC_R_NOTIMPLEMENTED); /* XXXTBD */
1201 actx = client->actx;
1203 resarg = isc_mem_get(client->mctx, sizeof(*resarg));
1205 return (ISC_R_NOMEMORY);
1207 result = isc_mutex_init(&resarg->lock);
1208 if (result != ISC_R_SUCCESS) {
1209 isc_mem_put(client->mctx, resarg, sizeof(*resarg));
1213 resarg->actx = actx;
1214 resarg->client = client;
1215 resarg->result = DNS_R_SERVFAIL;
1216 resarg->namelist = namelist;
1217 resarg->trans = NULL;
1218 resarg->canceled = ISC_FALSE;
1219 result = dns_client_startresolve(client, name, rdclass, type, options,
1220 client->task, resolve_done, resarg,
1222 if (result != ISC_R_SUCCESS) {
1223 DESTROYLOCK(&resarg->lock);
1224 isc_mem_put(client->mctx, resarg, sizeof(*resarg));
1229 * Start internal event loop. It blocks until the entire process
1232 result = isc_app_ctxrun(actx);
1234 LOCK(&resarg->lock);
1235 if (result == ISC_R_SUCCESS || result == ISC_R_SUSPEND)
1236 result = resarg->result;
1237 if (result != ISC_R_SUCCESS && resarg->vresult != ISC_R_SUCCESS) {
1239 * If this lookup failed due to some error in DNSSEC
1240 * validation, return the validation error code.
1241 * XXX: or should we pass the validation result separately?
1243 result = resarg->vresult;
1245 if (resarg->trans != NULL) {
1247 * Unusual termination (perhaps due to signal). We need some
1248 * tricky cleanup process.
1250 resarg->canceled = ISC_TRUE;
1251 dns_client_cancelresolve(resarg->trans);
1253 UNLOCK(&resarg->lock);
1255 /* resarg will be freed in the event handler. */
1257 UNLOCK(&resarg->lock);
1259 DESTROYLOCK(&resarg->lock);
1260 isc_mem_put(client->mctx, resarg, sizeof(*resarg));
1267 dns_client_startresolve(dns_client_t *client, dns_name_t *name,
1268 dns_rdataclass_t rdclass, dns_rdatatype_t type,
1269 unsigned int options, isc_task_t *task,
1270 isc_taskaction_t action, void *arg,
1271 dns_clientrestrans_t **transp)
1273 dns_view_t *view = NULL;
1274 dns_clientresevent_t *event = NULL;
1275 resctx_t *rctx = NULL;
1276 isc_task_t *clone = NULL;
1278 isc_result_t result;
1279 dns_rdataset_t *rdataset, *sigrdataset;
1280 isc_boolean_t want_dnssec;
1282 REQUIRE(DNS_CLIENT_VALID(client));
1283 REQUIRE(transp != NULL && *transp == NULL);
1285 LOCK(&client->lock);
1286 result = dns_viewlist_find(&client->viewlist, DNS_CLIENTVIEW_NAME,
1288 UNLOCK(&client->lock);
1289 if (result != ISC_R_SUCCESS)
1292 mctx = client->mctx;
1295 want_dnssec = ISC_TF((options & DNS_CLIENTRESOPT_NODNSSEC) == 0);
1298 * Prepare some intermediate resources
1301 isc_task_attach(task, &clone);
1302 event = (dns_clientresevent_t *)
1303 isc_event_allocate(mctx, clone, DNS_EVENT_CLIENTRESDONE,
1304 action, arg, sizeof(*event));
1305 if (event == NULL) {
1306 result = ISC_R_NOMEMORY;
1309 event->result = DNS_R_SERVFAIL;
1310 ISC_LIST_INIT(event->answerlist);
1312 rctx = isc_mem_get(mctx, sizeof(*rctx));
1314 result = ISC_R_NOMEMORY;
1316 result = isc_mutex_init(&rctx->lock);
1317 if (result != ISC_R_SUCCESS) {
1318 isc_mem_put(mctx, rctx, sizeof(*rctx));
1322 if (result != ISC_R_SUCCESS)
1325 result = getrdataset(mctx, &rdataset);
1326 if (result != ISC_R_SUCCESS)
1328 rctx->rdataset = rdataset;
1331 result = getrdataset(mctx, &sigrdataset);
1332 if (result != ISC_R_SUCCESS)
1335 rctx->sigrdataset = sigrdataset;
1337 dns_fixedname_init(&rctx->name);
1338 result = dns_name_copy(name, dns_fixedname_name(&rctx->name), NULL);
1339 if (result != ISC_R_SUCCESS)
1342 rctx->client = client;
1343 ISC_LINK_INIT(rctx, link);
1344 rctx->canceled = ISC_FALSE;
1345 rctx->task = client->task;
1350 rctx->want_dnssec = want_dnssec;
1351 ISC_LIST_INIT(rctx->namelist);
1352 rctx->event = event;
1354 rctx->magic = RCTX_MAGIC;
1356 LOCK(&client->lock);
1357 ISC_LIST_APPEND(client->resctxs, rctx, link);
1358 UNLOCK(&client->lock);
1360 *transp = (dns_clientrestrans_t *)rctx;
1361 client_resfind(rctx, NULL);
1363 return (ISC_R_SUCCESS);
1366 if (rdataset != NULL)
1367 putrdataset(client->mctx, &rdataset);
1368 if (sigrdataset != NULL)
1369 putrdataset(client->mctx, &sigrdataset);
1371 DESTROYLOCK(&rctx->lock);
1372 isc_mem_put(mctx, rctx, sizeof(*rctx));
1375 isc_event_free(ISC_EVENT_PTR(&event));
1376 isc_task_detach(&clone);
1377 dns_view_detach(&view);
1383 dns_client_cancelresolve(dns_clientrestrans_t *trans) {
1386 REQUIRE(trans != NULL);
1387 rctx = (resctx_t *)trans;
1388 REQUIRE(RCTX_VALID(rctx));
1392 if (!rctx->canceled) {
1393 rctx->canceled = ISC_TRUE;
1394 if (rctx->fetch != NULL)
1395 dns_resolver_cancelfetch(rctx->fetch);
1398 UNLOCK(&rctx->lock);
1402 dns_client_freeresanswer(dns_client_t *client, dns_namelist_t *namelist) {
1404 dns_rdataset_t *rdataset;
1406 REQUIRE(DNS_CLIENT_VALID(client));
1407 REQUIRE(namelist != NULL);
1409 while ((name = ISC_LIST_HEAD(*namelist)) != NULL) {
1410 ISC_LIST_UNLINK(*namelist, name, link);
1411 while ((rdataset = ISC_LIST_HEAD(name->list)) != NULL) {
1412 ISC_LIST_UNLINK(name->list, rdataset, link);
1413 putrdataset(client->mctx, &rdataset);
1415 dns_name_free(name, client->mctx);
1416 isc_mem_put(client->mctx, name, sizeof(*name));
1421 dns_client_destroyrestrans(dns_clientrestrans_t **transp) {
1424 dns_client_t *client;
1425 isc_boolean_t need_destroyclient = ISC_FALSE;
1427 REQUIRE(transp != NULL);
1428 rctx = (resctx_t *)*transp;
1429 REQUIRE(RCTX_VALID(rctx));
1430 REQUIRE(rctx->fetch == NULL);
1431 REQUIRE(rctx->event == NULL);
1432 client = rctx->client;
1433 REQUIRE(DNS_CLIENT_VALID(client));
1435 mctx = client->mctx;
1436 dns_view_detach(&rctx->view);
1438 LOCK(&client->lock);
1440 INSIST(ISC_LINK_LINKED(rctx, link));
1441 ISC_LIST_UNLINK(client->resctxs, rctx, link);
1443 if (client->references == 0 && ISC_LIST_EMPTY(client->resctxs) &&
1444 ISC_LIST_EMPTY(client->reqctxs) &&
1445 ISC_LIST_EMPTY(client->updatectxs))
1446 need_destroyclient = ISC_TRUE;
1448 UNLOCK(&client->lock);
1450 INSIST(ISC_LIST_EMPTY(rctx->namelist));
1452 DESTROYLOCK(&rctx->lock);
1455 isc_mem_put(mctx, rctx, sizeof(*rctx));
1457 if (need_destroyclient)
1458 destroyclient(&client);
1464 dns_client_addtrustedkey(dns_client_t *client, dns_rdataclass_t rdclass,
1465 dns_name_t *keyname, isc_buffer_t *keydatabuf)
1467 isc_result_t result;
1468 dns_view_t *view = NULL;
1469 dst_key_t *dstkey = NULL;
1470 dns_keytable_t *secroots = NULL;
1472 REQUIRE(DNS_CLIENT_VALID(client));
1474 LOCK(&client->lock);
1475 result = dns_viewlist_find(&client->viewlist, DNS_CLIENTVIEW_NAME,
1477 UNLOCK(&client->lock);
1478 if (result != ISC_R_SUCCESS)
1481 result = dns_view_getsecroots(view, &secroots);
1482 if (result != ISC_R_SUCCESS)
1485 result = dst_key_fromdns(keyname, rdclass, keydatabuf, client->mctx,
1487 if (result != ISC_R_SUCCESS)
1490 result = dns_keytable_add(secroots, ISC_FALSE, &dstkey);
1494 dst_key_free(&dstkey);
1496 dns_view_detach(&view);
1497 if (secroots != NULL)
1498 dns_keytable_detach(&secroots);
1503 * Simple request routines
1506 request_done(isc_task_t *task, isc_event_t *event) {
1507 dns_requestevent_t *reqev = NULL;
1508 dns_request_t *request;
1509 isc_result_t result, eresult;
1514 REQUIRE(event->ev_type == DNS_EVENT_REQUESTDONE);
1515 reqev = (dns_requestevent_t *)event;
1516 request = reqev->request;
1517 result = eresult = reqev->result;
1518 ctx = reqev->ev_arg;
1519 REQUIRE(REQCTX_VALID(ctx));
1521 isc_event_free(&event);
1525 if (eresult == ISC_R_SUCCESS) {
1526 result = dns_request_getresponse(request, ctx->event->rmessage,
1530 if (ctx->tsigkey != NULL)
1531 dns_tsigkey_detach(&ctx->tsigkey);
1534 ctx->event->result = ISC_R_CANCELED;
1536 ctx->event->result = result;
1537 task = ctx->event->ev_sender;
1538 ctx->event->ev_sender = ctx;
1539 isc_task_sendanddetach(&task, ISC_EVENT_PTR(&ctx->event));
1545 localrequest_done(isc_task_t *task, isc_event_t *event) {
1546 reqarg_t *reqarg = event->ev_arg;
1547 dns_clientreqevent_t *rev =(dns_clientreqevent_t *)event;
1551 REQUIRE(event->ev_type == DNS_EVENT_CLIENTREQDONE);
1553 LOCK(&reqarg->lock);
1555 reqarg->result = rev->result;
1556 dns_client_destroyreqtrans(&reqarg->trans);
1557 isc_event_free(&event);
1559 if (!reqarg->canceled) {
1560 UNLOCK(&reqarg->lock);
1562 /* Exit from the internal event loop */
1563 isc_app_ctxsuspend(reqarg->actx);
1566 * We have already exited from the loop (due to some
1567 * unexpected event). Just clean the arg up.
1569 UNLOCK(&reqarg->lock);
1570 DESTROYLOCK(&reqarg->lock);
1571 isc_mem_put(reqarg->client->mctx, reqarg, sizeof(*reqarg));
1576 dns_client_request(dns_client_t *client, dns_message_t *qmessage,
1577 dns_message_t *rmessage, isc_sockaddr_t *server,
1578 unsigned int options, unsigned int parseoptions,
1579 dns_tsec_t *tsec, unsigned int timeout,
1580 unsigned int udptimeout, unsigned int udpretries)
1584 isc_result_t result;
1586 REQUIRE(DNS_CLIENT_VALID(client));
1587 REQUIRE(qmessage != NULL);
1588 REQUIRE(rmessage != NULL);
1590 if ((client->attributes & DNS_CLIENTATTR_OWNCTX) == 0 &&
1591 (options & DNS_CLIENTREQOPT_ALLOWRUN) == 0) {
1593 * If the client is run under application's control, we need
1594 * to create a new running (sub)environment for this
1595 * particular resolution.
1597 return (ISC_R_NOTIMPLEMENTED); /* XXXTBD */
1599 actx = client->actx;
1601 reqarg = isc_mem_get(client->mctx, sizeof(*reqarg));
1603 return (ISC_R_NOMEMORY);
1605 result = isc_mutex_init(&reqarg->lock);
1606 if (result != ISC_R_SUCCESS) {
1607 isc_mem_put(client->mctx, reqarg, sizeof(*reqarg));
1611 reqarg->actx = actx;
1612 reqarg->client = client;
1613 reqarg->trans = NULL;
1614 reqarg->canceled = ISC_FALSE;
1616 result = dns_client_startrequest(client, qmessage, rmessage, server,
1617 options, parseoptions, tsec, timeout,
1618 udptimeout, udpretries,
1619 client->task, localrequest_done,
1620 reqarg, &reqarg->trans);
1621 if (result != ISC_R_SUCCESS) {
1622 DESTROYLOCK(&reqarg->lock);
1623 isc_mem_put(client->mctx, reqarg, sizeof(*reqarg));
1628 * Start internal event loop. It blocks until the entire process
1631 result = isc_app_ctxrun(actx);
1633 LOCK(&reqarg->lock);
1634 if (result == ISC_R_SUCCESS || result == ISC_R_SUSPEND)
1635 result = reqarg->result;
1636 if (reqarg->trans != NULL) {
1638 * Unusual termination (perhaps due to signal). We need some
1639 * tricky cleanup process.
1641 reqarg->canceled = ISC_TRUE;
1642 dns_client_cancelresolve(reqarg->trans);
1644 UNLOCK(&reqarg->lock);
1646 /* reqarg will be freed in the event handler. */
1648 UNLOCK(&reqarg->lock);
1650 DESTROYLOCK(&reqarg->lock);
1651 isc_mem_put(client->mctx, reqarg, sizeof(*reqarg));
1658 dns_client_startrequest(dns_client_t *client, dns_message_t *qmessage,
1659 dns_message_t *rmessage, isc_sockaddr_t *server,
1660 unsigned int options, unsigned int parseoptions,
1661 dns_tsec_t *tsec, unsigned int timeout,
1662 unsigned int udptimeout, unsigned int udpretries,
1663 isc_task_t *task, isc_taskaction_t action, void *arg,
1664 dns_clientreqtrans_t **transp)
1666 isc_result_t result;
1667 dns_view_t *view = NULL;
1668 isc_task_t *clone = NULL;
1669 dns_clientreqevent_t *event = NULL;
1670 reqctx_t *ctx = NULL;
1671 dns_tsectype_t tsectype = dns_tsectype_none;
1675 REQUIRE(DNS_CLIENT_VALID(client));
1676 REQUIRE(qmessage != NULL);
1677 REQUIRE(rmessage != NULL);
1678 REQUIRE(transp != NULL && *transp == NULL);
1681 tsectype = dns_tsec_gettype(tsec);
1682 if (tsectype != dns_tsectype_tsig)
1683 return (ISC_R_NOTIMPLEMENTED); /* XXX */
1686 LOCK(&client->lock);
1687 result = dns_viewlist_find(&client->viewlist, DNS_CLIENTVIEW_NAME,
1688 qmessage->rdclass, &view);
1689 UNLOCK(&client->lock);
1690 if (result != ISC_R_SUCCESS)
1694 isc_task_attach(task, &clone);
1695 event = (dns_clientreqevent_t *)
1696 isc_event_allocate(client->mctx, clone,
1697 DNS_EVENT_CLIENTREQDONE,
1698 action, arg, sizeof(*event));
1699 if (event == NULL) {
1700 result = ISC_R_NOMEMORY;
1704 ctx = isc_mem_get(client->mctx, sizeof(*ctx));
1706 result = ISC_R_NOMEMORY;
1708 result = isc_mutex_init(&ctx->lock);
1709 if (result != ISC_R_SUCCESS) {
1710 isc_mem_put(client->mctx, ctx, sizeof(*ctx));
1714 if (result != ISC_R_SUCCESS)
1717 ctx->client = client;
1718 ISC_LINK_INIT(ctx, link);
1719 ctx->parseoptions = parseoptions;
1720 ctx->canceled = ISC_FALSE;
1722 ctx->event->rmessage = rmessage;
1723 ctx->tsigkey = NULL;
1725 dns_tsec_getkey(tsec, &ctx->tsigkey);
1727 ctx->magic = REQCTX_MAGIC;
1729 LOCK(&client->lock);
1730 ISC_LIST_APPEND(client->reqctxs, ctx, link);
1731 UNLOCK(&client->lock);
1733 ctx->request = NULL;
1734 result = dns_request_createvia3(view->requestmgr, qmessage, NULL,
1735 server, options, ctx->tsigkey,
1736 timeout, udptimeout, udpretries,
1737 client->task, request_done, ctx,
1739 if (result == ISC_R_SUCCESS) {
1740 dns_view_detach(&view);
1741 *transp = (dns_clientreqtrans_t *)ctx;
1742 return (ISC_R_SUCCESS);
1747 LOCK(&client->lock);
1748 ISC_LIST_UNLINK(client->reqctxs, ctx, link);
1749 UNLOCK(&client->lock);
1750 DESTROYLOCK(&ctx->lock);
1751 isc_mem_put(client->mctx, ctx, sizeof(*ctx));
1754 isc_event_free(ISC_EVENT_PTR(&event));
1755 isc_task_detach(&clone);
1756 dns_view_detach(&view);
1762 dns_client_cancelrequest(dns_clientreqtrans_t *trans) {
1765 REQUIRE(trans != NULL);
1766 ctx = (reqctx_t *)trans;
1767 REQUIRE(REQCTX_VALID(ctx));
1771 if (!ctx->canceled) {
1772 ctx->canceled = ISC_TRUE;
1773 if (ctx->request != NULL)
1774 dns_request_cancel(ctx->request);
1781 dns_client_destroyreqtrans(dns_clientreqtrans_t **transp) {
1784 dns_client_t *client;
1785 isc_boolean_t need_destroyclient = ISC_FALSE;
1787 REQUIRE(transp != NULL);
1788 ctx = (reqctx_t *)*transp;
1789 REQUIRE(REQCTX_VALID(ctx));
1790 client = ctx->client;
1791 REQUIRE(DNS_CLIENT_VALID(client));
1792 REQUIRE(ctx->event == NULL);
1793 REQUIRE(ctx->request != NULL);
1795 dns_request_destroy(&ctx->request);
1796 mctx = client->mctx;
1798 LOCK(&client->lock);
1800 INSIST(ISC_LINK_LINKED(ctx, link));
1801 ISC_LIST_UNLINK(client->reqctxs, ctx, link);
1803 if (client->references == 0 && ISC_LIST_EMPTY(client->resctxs) &&
1804 ISC_LIST_EMPTY(client->reqctxs) &&
1805 ISC_LIST_EMPTY(client->updatectxs)) {
1806 need_destroyclient = ISC_TRUE;
1809 UNLOCK(&client->lock);
1811 DESTROYLOCK(&ctx->lock);
1814 isc_mem_put(mctx, ctx, sizeof(*ctx));
1816 if (need_destroyclient)
1817 destroyclient(&client);
1823 * Dynamic update routines
1826 rcode2result(dns_rcode_t rcode) {
1827 /* XXX: isn't there a similar function? */
1829 case dns_rcode_formerr:
1830 return (DNS_R_FORMERR);
1831 case dns_rcode_servfail:
1832 return (DNS_R_SERVFAIL);
1833 case dns_rcode_nxdomain:
1834 return (DNS_R_NXDOMAIN);
1835 case dns_rcode_notimp:
1836 return (DNS_R_NOTIMP);
1837 case dns_rcode_refused:
1838 return (DNS_R_REFUSED);
1839 case dns_rcode_yxdomain:
1840 return (DNS_R_YXDOMAIN);
1841 case dns_rcode_yxrrset:
1842 return (DNS_R_YXRRSET);
1843 case dns_rcode_nxrrset:
1844 return (DNS_R_NXRRSET);
1845 case dns_rcode_notauth:
1846 return (DNS_R_NOTAUTH);
1847 case dns_rcode_notzone:
1848 return (DNS_R_NOTZONE);
1849 case dns_rcode_badvers:
1850 return (DNS_R_BADVERS);
1853 return (ISC_R_FAILURE);
1857 update_sendevent(updatectx_t *uctx, isc_result_t result) {
1860 dns_message_destroy(&uctx->updatemsg);
1861 if (uctx->tsigkey != NULL)
1862 dns_tsigkey_detach(&uctx->tsigkey);
1863 if (uctx->sig0key != NULL)
1864 dst_key_free(&uctx->sig0key);
1867 uctx->event->result = ISC_R_CANCELED;
1869 uctx->event->result = result;
1870 uctx->event->state = uctx->state;
1871 task = uctx->event->ev_sender;
1872 uctx->event->ev_sender = uctx;
1873 isc_task_sendanddetach(&task, ISC_EVENT_PTR(&uctx->event));
1877 update_done(isc_task_t *task, isc_event_t *event) {
1878 isc_result_t result;
1879 dns_requestevent_t *reqev = NULL;
1880 dns_request_t *request;
1881 dns_message_t *answer = NULL;
1882 updatectx_t *uctx = event->ev_arg;
1883 dns_client_t *client;
1884 unsigned int timeout;
1888 REQUIRE(event->ev_type == DNS_EVENT_REQUESTDONE);
1889 reqev = (dns_requestevent_t *)event;
1890 request = reqev->request;
1891 REQUIRE(UCTX_VALID(uctx));
1892 client = uctx->client;
1893 REQUIRE(DNS_CLIENT_VALID(client));
1895 result = reqev->result;
1896 if (result != ISC_R_SUCCESS)
1899 result = dns_message_create(client->mctx, DNS_MESSAGE_INTENTPARSE,
1901 if (result != ISC_R_SUCCESS)
1903 uctx->state = dns_clientupdatestate_done;
1904 result = dns_request_getresponse(request, answer,
1905 DNS_MESSAGEPARSE_PRESERVEORDER);
1906 if (result == ISC_R_SUCCESS && answer->rcode != dns_rcode_noerror)
1907 result = rcode2result(answer->rcode);
1911 dns_message_destroy(&answer);
1912 isc_event_free(&event);
1915 uctx->currentserver = ISC_LIST_NEXT(uctx->currentserver, link);
1916 dns_request_destroy(&uctx->updatereq);
1917 if (result != ISC_R_SUCCESS && !uctx->canceled &&
1918 uctx->currentserver != NULL) {
1919 dns_message_renderreset(uctx->updatemsg);
1920 dns_message_settsigkey(uctx->updatemsg, NULL);
1922 timeout = client->update_timeout / uctx->nservers;
1923 if (timeout < MIN_UPDATE_TIMEOUT)
1924 timeout = MIN_UPDATE_TIMEOUT;
1925 result = dns_request_createvia3(uctx->view->requestmgr,
1928 uctx->currentserver, 0,
1931 client->update_udptimeout,
1932 client->update_udpretries,
1936 UNLOCK(&uctx->lock);
1938 if (result == ISC_R_SUCCESS) {
1939 /* XXX: should we keep the 'done' state here? */
1940 uctx->state = dns_clientupdatestate_sent;
1944 UNLOCK(&uctx->lock);
1946 update_sendevent(uctx, result);
1950 send_update(updatectx_t *uctx) {
1951 isc_result_t result;
1952 dns_name_t *name = NULL;
1953 dns_rdataset_t *rdataset = NULL;
1954 dns_client_t *client = uctx->client;
1955 unsigned int timeout;
1957 REQUIRE(uctx->zonename != NULL && uctx->currentserver != NULL);
1959 result = dns_message_gettempname(uctx->updatemsg, &name);
1960 if (result != ISC_R_SUCCESS)
1962 dns_name_init(name, NULL);
1963 dns_name_clone(uctx->zonename, name);
1964 result = dns_message_gettemprdataset(uctx->updatemsg, &rdataset);
1965 if (result != ISC_R_SUCCESS) {
1966 dns_message_puttempname(uctx->updatemsg, &name);
1969 dns_rdataset_makequestion(rdataset, uctx->rdclass, dns_rdatatype_soa);
1970 ISC_LIST_INIT(name->list);
1971 ISC_LIST_APPEND(name->list, rdataset, link);
1972 dns_message_addname(uctx->updatemsg, name, DNS_SECTION_ZONE);
1973 if (uctx->tsigkey == NULL && uctx->sig0key != NULL) {
1974 result = dns_message_setsig0key(uctx->updatemsg,
1976 if (result != ISC_R_SUCCESS)
1979 timeout = client->update_timeout / uctx->nservers;
1980 if (timeout < MIN_UPDATE_TIMEOUT)
1981 timeout = MIN_UPDATE_TIMEOUT;
1982 result = dns_request_createvia3(uctx->view->requestmgr,
1984 NULL, uctx->currentserver, 0,
1985 uctx->tsigkey, timeout,
1986 client->update_udptimeout,
1987 client->update_udpretries,
1988 client->task, update_done, uctx,
1990 if (result == ISC_R_SUCCESS &&
1991 uctx->state == dns_clientupdatestate_prepare) {
1992 uctx->state = dns_clientupdatestate_sent;
1999 resolveaddr_done(isc_task_t *task, isc_event_t *event) {
2000 isc_result_t result;
2002 dns_rdatatype_t qtype;
2003 dns_clientresevent_t *rev = (dns_clientresevent_t *)event;
2005 dns_rdataset_t *rdataset;
2007 isc_boolean_t completed = ISC_FALSE;
2011 REQUIRE(event->ev_arg != NULL);
2012 uctx = *(updatectx_t **)event->ev_arg;
2013 REQUIRE(UCTX_VALID(uctx));
2015 if (event->ev_arg == &uctx->bp4) {
2017 qtype = dns_rdatatype_a;
2019 dns_client_destroyrestrans(&uctx->restrans);
2020 UNLOCK(&uctx->lock);
2022 INSIST(event->ev_arg == &uctx->bp6);
2024 qtype = dns_rdatatype_aaaa;
2026 dns_client_destroyrestrans(&uctx->restrans2);
2027 UNLOCK(&uctx->lock);
2030 result = rev->result;
2031 if (result != ISC_R_SUCCESS)
2034 for (name = ISC_LIST_HEAD(rev->answerlist); name != NULL;
2035 name = ISC_LIST_NEXT(name, link)) {
2036 for (rdataset = ISC_LIST_HEAD(name->list);
2038 rdataset = ISC_LIST_NEXT(rdataset, link)) {
2039 if (!dns_rdataset_isassociated(rdataset))
2041 if (rdataset->type != qtype)
2044 for (result = dns_rdataset_first(rdataset);
2045 result == ISC_R_SUCCESS;
2046 result = dns_rdataset_next(rdataset)) {
2048 dns_rdata_in_a_t rdata_a;
2049 dns_rdata_in_aaaa_t rdata_aaaa;
2052 sa = isc_mem_get(uctx->client->mctx,
2056 * If we fail to get a sockaddr,
2057 we simply move forward with the
2058 * addresses we've got so far.
2063 dns_rdata_init(&rdata);
2066 dns_rdataset_current(rdataset, &rdata);
2067 result = dns_rdata_tostruct(&rdata, &rdata_a,
2069 RUNTIME_CHECK(result == ISC_R_SUCCESS);
2070 isc_sockaddr_fromin(sa,
2073 dns_rdata_freestruct(&rdata_a);
2076 dns_rdataset_current(rdataset, &rdata);
2077 result = dns_rdata_tostruct(&rdata, &rdata_aaaa,
2079 RUNTIME_CHECK(result == ISC_R_SUCCESS);
2080 isc_sockaddr_fromin6(sa,
2081 &rdata_aaaa.in6_addr,
2083 dns_rdata_freestruct(&rdata_aaaa);
2087 ISC_LINK_INIT(sa, link);
2088 ISC_LIST_APPEND(uctx->servers, sa, link);
2095 dns_client_freeresanswer(uctx->client, &rev->answerlist);
2096 isc_event_free(&event);
2099 if (uctx->restrans == NULL && uctx->restrans2 == NULL)
2100 completed = ISC_TRUE;
2101 UNLOCK(&uctx->lock);
2104 INSIST(uctx->currentserver == NULL);
2105 uctx->currentserver = ISC_LIST_HEAD(uctx->servers);
2106 if (uctx->currentserver != NULL && !uctx->canceled)
2109 if (result == ISC_R_SUCCESS)
2110 result = ISC_R_NOTFOUND;
2111 update_sendevent(uctx, result);
2117 process_soa(updatectx_t *uctx, dns_rdataset_t *soaset, dns_name_t *soaname) {
2118 isc_result_t result;
2119 dns_rdata_t soarr = DNS_RDATA_INIT;
2120 dns_rdata_soa_t soa;
2123 result = dns_rdataset_first(soaset);
2124 if (result != ISC_R_SUCCESS)
2126 dns_rdata_init(&soarr);
2127 dns_rdataset_current(soaset, &soarr);
2128 result = dns_rdata_tostruct(&soarr, &soa, NULL);
2129 if (result != ISC_R_SUCCESS)
2132 dns_name_init(&primary, NULL);
2133 dns_name_clone(&soa.origin, &primary);
2135 if (uctx->zonename == NULL) {
2136 uctx->zonename = dns_fixedname_name(&uctx->zonefname);
2137 result = dns_name_copy(soaname, uctx->zonename, NULL);
2138 if (result != ISC_R_SUCCESS)
2142 if (uctx->currentserver != NULL)
2143 result = send_update(uctx);
2146 * Get addresses of the primary server. We don't use the ADB
2147 * feature so that we could avoid caching data.
2151 result = dns_client_startresolve(uctx->client, &primary,
2154 0, uctx->client->task,
2155 resolveaddr_done, &uctx->bp4,
2157 if (result == ISC_R_SUCCESS) {
2159 result = dns_client_startresolve(uctx->client,
2163 0, uctx->client->task,
2168 UNLOCK(&uctx->lock);
2172 dns_rdata_freestruct(&soa);
2178 receive_soa(isc_task_t *task, isc_event_t *event) {
2179 dns_requestevent_t *reqev = NULL;
2181 dns_client_t *client;
2182 isc_result_t result, eresult;
2183 dns_request_t *request;
2184 dns_message_t *rcvmsg = NULL;
2185 dns_section_t section;
2186 dns_rdataset_t *soaset = NULL;
2189 dns_message_t *soaquery = NULL;
2190 isc_sockaddr_t *addr;
2191 isc_boolean_t seencname = ISC_FALSE;
2192 isc_boolean_t droplabel = ISC_FALSE;
2194 unsigned int nlabels;
2198 REQUIRE(event->ev_type == DNS_EVENT_REQUESTDONE);
2199 reqev = (dns_requestevent_t *)event;
2200 request = reqev->request;
2201 result = eresult = reqev->result;
2203 uctx = reqev->ev_arg;
2204 client = uctx->client;
2205 soaquery = uctx->soaquery;
2206 addr = uctx->currentserver;
2207 INSIST(addr != NULL);
2209 isc_event_free(&event);
2211 if (eresult != ISC_R_SUCCESS) {
2216 result = dns_message_create(uctx->client->mctx,
2217 DNS_MESSAGE_INTENTPARSE, &rcvmsg);
2218 if (result != ISC_R_SUCCESS)
2220 result = dns_request_getresponse(request, rcvmsg,
2221 DNS_MESSAGEPARSE_PRESERVEORDER);
2223 if (result == DNS_R_TSIGERRORSET) {
2224 dns_request_t *newrequest = NULL;
2226 /* Retry SOA request without TSIG */
2227 dns_message_destroy(&rcvmsg);
2228 dns_message_renderreset(uctx->soaquery);
2229 result = dns_request_createvia3(uctx->view->requestmgr,
2230 uctx->soaquery, NULL, addr, 0,
2232 client->find_timeout * 20,
2233 client->find_timeout, 3,
2237 if (result == ISC_R_SUCCESS) {
2239 dns_request_destroy(&uctx->soareq);
2240 uctx->soareq = newrequest;
2241 UNLOCK(&uctx->lock);
2248 section = DNS_SECTION_ANSWER;
2251 if (rcvmsg->rcode != dns_rcode_noerror &&
2252 rcvmsg->rcode != dns_rcode_nxdomain) {
2253 result = rcode2result(rcvmsg->rcode);
2259 section = DNS_SECTION_ANSWER;
2261 section = DNS_SECTION_AUTHORITY;
2263 droplabel = ISC_TRUE;
2267 result = dns_message_firstname(rcvmsg, section);
2268 if (result != ISC_R_SUCCESS) {
2272 while (result == ISC_R_SUCCESS) {
2274 dns_message_currentname(rcvmsg, section, &name);
2276 result = dns_message_findtype(name, dns_rdatatype_soa, 0,
2278 if (result == ISC_R_SUCCESS)
2280 if (section == DNS_SECTION_ANSWER) {
2281 dns_rdataset_t *tset = NULL;
2282 if (dns_message_findtype(name, dns_rdatatype_cname, 0,
2283 &tset) == ISC_R_SUCCESS
2285 dns_message_findtype(name, dns_rdatatype_dname, 0,
2286 &tset) == ISC_R_SUCCESS
2289 seencname = ISC_TRUE;
2294 result = dns_message_nextname(rcvmsg, section);
2297 if (soaset == NULL && !seencname) {
2303 droplabel = ISC_TRUE;
2307 result = process_soa(uctx, soaset, name);
2311 result = dns_message_firstname(soaquery, DNS_SECTION_QUESTION);
2312 INSIST(result == ISC_R_SUCCESS);
2314 dns_message_currentname(soaquery, DNS_SECTION_QUESTION, &name);
2315 nlabels = dns_name_countlabels(name);
2317 result = DNS_R_SERVFAIL; /* is there a better error? */
2319 dns_name_init(&tname, NULL);
2320 dns_name_getlabelsequence(name, 1, nlabels - 1,
2322 dns_name_clone(&tname, name);
2323 dns_request_destroy(&request);
2325 uctx->soareq = NULL;
2326 UNLOCK(&uctx->lock);
2327 dns_message_renderreset(soaquery);
2328 dns_message_settsigkey(soaquery, NULL);
2329 result = dns_request_createvia3(uctx->view->requestmgr,
2331 uctx->currentserver, 0,
2333 client->find_timeout *
2335 client->find_timeout,
2342 if (!droplabel || result != ISC_R_SUCCESS) {
2343 dns_message_destroy(&uctx->soaquery);
2345 dns_request_destroy(&uctx->soareq);
2346 UNLOCK(&uctx->lock);
2350 dns_message_destroy(&rcvmsg);
2352 if (result != ISC_R_SUCCESS)
2353 update_sendevent(uctx, result);
2357 request_soa(updatectx_t *uctx) {
2358 isc_result_t result;
2359 dns_message_t *soaquery = uctx->soaquery;
2360 dns_name_t *name = NULL;
2361 dns_rdataset_t *rdataset = NULL;
2363 if (soaquery == NULL) {
2364 result = dns_message_create(uctx->client->mctx,
2365 DNS_MESSAGE_INTENTRENDER,
2367 if (result != ISC_R_SUCCESS)
2370 soaquery->flags |= DNS_MESSAGEFLAG_RD;
2371 result = dns_message_gettempname(soaquery, &name);
2372 if (result != ISC_R_SUCCESS)
2374 result = dns_message_gettemprdataset(soaquery, &rdataset);
2375 if (result != ISC_R_SUCCESS)
2377 dns_rdataset_makequestion(rdataset, uctx->rdclass, dns_rdatatype_soa);
2378 dns_name_clone(uctx->firstname, name);
2379 ISC_LIST_APPEND(name->list, rdataset, link);
2380 dns_message_addname(soaquery, name, DNS_SECTION_QUESTION);
2384 result = dns_request_createvia3(uctx->view->requestmgr,
2385 soaquery, NULL, uctx->currentserver, 0,
2387 uctx->client->find_timeout * 20,
2388 uctx->client->find_timeout, 3,
2389 uctx->client->task, receive_soa, uctx,
2391 if (result == ISC_R_SUCCESS) {
2392 uctx->soaquery = soaquery;
2393 return (ISC_R_SUCCESS);
2397 if (rdataset != NULL) {
2398 ISC_LIST_UNLINK(name->list, rdataset, link); /* for safety */
2399 dns_message_puttemprdataset(soaquery, &rdataset);
2402 dns_message_puttempname(soaquery, &name);
2403 dns_message_destroy(&soaquery);
2409 resolvesoa_done(isc_task_t *task, isc_event_t *event) {
2410 dns_clientresevent_t *rev = (dns_clientresevent_t *)event;
2412 dns_name_t *name, tname;
2413 dns_rdataset_t *rdataset = NULL;
2414 isc_result_t result = rev->result;
2415 unsigned int nlabels;
2419 uctx = event->ev_arg;
2420 REQUIRE(UCTX_VALID(uctx));
2423 dns_client_destroyrestrans(&uctx->restrans);
2424 UNLOCK(&uctx->lock);
2426 uctx = event->ev_arg;
2427 if (result != ISC_R_SUCCESS &&
2428 result != DNS_R_NCACHENXDOMAIN &&
2429 result != DNS_R_NCACHENXRRSET) {
2430 /* XXX: what about DNSSEC failure? */
2434 for (name = ISC_LIST_HEAD(rev->answerlist); name != NULL;
2435 name = ISC_LIST_NEXT(name, link)) {
2436 for (rdataset = ISC_LIST_HEAD(name->list);
2438 rdataset = ISC_LIST_NEXT(rdataset, link)) {
2439 if (dns_rdataset_isassociated(rdataset) &&
2440 rdataset->type == dns_rdatatype_soa)
2445 if (rdataset == NULL) {
2446 /* Drop one label and retry resolution. */
2447 nlabels = dns_name_countlabels(&uctx->soaqname);
2449 result = DNS_R_SERVFAIL; /* is there a better error? */
2452 dns_name_init(&tname, NULL);
2453 dns_name_getlabelsequence(&uctx->soaqname, 1, nlabels - 1,
2455 dns_name_clone(&tname, &uctx->soaqname);
2457 result = dns_client_startresolve(uctx->client, &uctx->soaqname,
2459 dns_rdatatype_soa, 0,
2461 resolvesoa_done, uctx,
2464 result = process_soa(uctx, rdataset, &uctx->soaqname);
2467 dns_client_freeresanswer(uctx->client, &rev->answerlist);
2468 isc_event_free(&event);
2470 if (result != ISC_R_SUCCESS)
2471 update_sendevent(uctx, result);
2475 copy_name(isc_mem_t *mctx, dns_message_t *msg, dns_name_t *name,
2476 dns_name_t **newnamep)
2478 isc_result_t result;
2479 dns_name_t *newname = NULL;
2481 isc_buffer_t *namebuf = NULL, *rdatabuf = NULL;
2482 dns_rdatalist_t *rdatalist;
2483 dns_rdataset_t *rdataset, *newrdataset;
2484 dns_rdata_t rdata = DNS_RDATA_INIT, *newrdata;
2486 result = dns_message_gettempname(msg, &newname);
2487 if (result != ISC_R_SUCCESS)
2489 result = isc_buffer_allocate(mctx, &namebuf, DNS_NAME_MAXWIRE);
2490 if (result != ISC_R_SUCCESS)
2492 dns_name_init(newname, NULL);
2493 dns_name_setbuffer(newname, namebuf);
2494 dns_message_takebuffer(msg, &namebuf);
2495 result = dns_name_copy(name, newname, NULL);
2496 if (result != ISC_R_SUCCESS)
2499 for (rdataset = ISC_LIST_HEAD(name->list); rdataset != NULL;
2500 rdataset = ISC_LIST_NEXT(rdataset, link)) {
2502 result = dns_message_gettemprdatalist(msg, &rdatalist);
2503 if (result != ISC_R_SUCCESS)
2505 dns_rdatalist_init(rdatalist);
2506 rdatalist->type = rdataset->type;
2507 rdatalist->rdclass = rdataset->rdclass;
2508 rdatalist->covers = rdataset->covers;
2509 rdatalist->ttl = rdataset->ttl;
2511 result = dns_rdataset_first(rdataset);
2512 while (result == ISC_R_SUCCESS) {
2513 dns_rdata_reset(&rdata);
2514 dns_rdataset_current(rdataset, &rdata);
2517 result = dns_message_gettemprdata(msg, &newrdata);
2518 if (result != ISC_R_SUCCESS)
2520 dns_rdata_toregion(&rdata, &r);
2522 result = isc_buffer_allocate(mctx, &rdatabuf,
2524 if (result != ISC_R_SUCCESS)
2526 isc_buffer_putmem(rdatabuf, r.base, r.length);
2527 isc_buffer_usedregion(rdatabuf, &r);
2528 dns_rdata_init(newrdata);
2529 dns_rdata_fromregion(newrdata, rdata.rdclass,
2531 newrdata->flags = rdata.flags;
2533 ISC_LIST_APPEND(rdatalist->rdata, newrdata, link);
2534 dns_message_takebuffer(msg, &rdatabuf);
2536 result = dns_rdataset_next(rdataset);
2540 result = dns_message_gettemprdataset(msg, &newrdataset);
2541 if (result != ISC_R_SUCCESS)
2543 dns_rdataset_init(newrdataset);
2544 dns_rdatalist_tordataset(rdatalist, newrdataset);
2546 ISC_LIST_APPEND(newname->list, newrdataset, link);
2549 *newnamep = newname;
2551 return (ISC_R_SUCCESS);
2554 dns_message_puttempname(msg, &newname);
2561 internal_update_callback(isc_task_t *task, isc_event_t *event) {
2562 updatearg_t *uarg = event->ev_arg;
2563 dns_clientupdateevent_t *uev = (dns_clientupdateevent_t *)event;
2569 uarg->result = uev->result;
2571 dns_client_destroyupdatetrans(&uarg->trans);
2572 isc_event_free(&event);
2574 if (!uarg->canceled) {
2575 UNLOCK(&uarg->lock);
2577 /* Exit from the internal event loop */
2578 isc_app_ctxsuspend(uarg->actx);
2581 * We have already exited from the loop (due to some
2582 * unexpected event). Just clean the arg up.
2584 UNLOCK(&uarg->lock);
2585 DESTROYLOCK(&uarg->lock);
2586 isc_mem_put(uarg->client->mctx, uarg, sizeof(*uarg));
2591 dns_client_update(dns_client_t *client, dns_rdataclass_t rdclass,
2592 dns_name_t *zonename, dns_namelist_t *prerequisites,
2593 dns_namelist_t *updates, isc_sockaddrlist_t *servers,
2594 dns_tsec_t *tsec, unsigned int options)
2596 isc_result_t result;
2600 REQUIRE(DNS_CLIENT_VALID(client));
2602 if ((client->attributes & DNS_CLIENTATTR_OWNCTX) == 0 &&
2603 (options & DNS_CLIENTRESOPT_ALLOWRUN) == 0) {
2605 * If the client is run under application's control, we need
2606 * to create a new running (sub)environment for this
2607 * particular resolution.
2609 return (ISC_R_NOTIMPLEMENTED); /* XXXTBD */
2611 actx = client->actx;
2613 uarg = isc_mem_get(client->mctx, sizeof(*uarg));
2615 return (ISC_R_NOMEMORY);
2617 result = isc_mutex_init(&uarg->lock);
2618 if (result != ISC_R_SUCCESS) {
2619 isc_mem_put(client->mctx, uarg, sizeof(*uarg));
2624 uarg->client = client;
2625 uarg->result = ISC_R_FAILURE;
2627 uarg->canceled = ISC_FALSE;
2629 result = dns_client_startupdate(client, rdclass, zonename,
2630 prerequisites, updates, servers,
2631 tsec, options, client->task,
2632 internal_update_callback, uarg,
2634 if (result != ISC_R_SUCCESS) {
2635 DESTROYLOCK(&uarg->lock);
2636 isc_mem_put(client->mctx, uarg, sizeof(*uarg));
2641 * Start internal event loop. It blocks until the entire process
2644 result = isc_app_ctxrun(actx);
2647 if (result == ISC_R_SUCCESS || result == ISC_R_SUSPEND)
2648 result = uarg->result;
2650 if (uarg->trans != NULL) {
2652 * Unusual termination (perhaps due to signal). We need some
2653 * tricky cleanup process.
2655 uarg->canceled = ISC_TRUE;
2656 dns_client_cancelupdate(uarg->trans);
2658 UNLOCK(&uarg->lock);
2660 /* uarg will be freed in the event handler. */
2662 UNLOCK(&uarg->lock);
2664 DESTROYLOCK(&uarg->lock);
2665 isc_mem_put(client->mctx, uarg, sizeof(*uarg));
2672 dns_client_startupdate(dns_client_t *client, dns_rdataclass_t rdclass,
2673 dns_name_t *zonename, dns_namelist_t *prerequisites,
2674 dns_namelist_t *updates, isc_sockaddrlist_t *servers,
2675 dns_tsec_t *tsec, unsigned int options,
2676 isc_task_t *task, isc_taskaction_t action, void *arg,
2677 dns_clientupdatetrans_t **transp)
2679 dns_view_t *view = NULL;
2680 isc_result_t result;
2681 dns_name_t *name, *newname;
2683 isc_task_t *clone = NULL;
2684 dns_section_t section = DNS_SECTION_UPDATE;
2685 isc_sockaddr_t *server, *sa = NULL;
2686 dns_tsectype_t tsectype = dns_tsectype_none;
2690 REQUIRE(DNS_CLIENT_VALID(client));
2691 REQUIRE(transp != NULL && *transp == NULL);
2692 REQUIRE(updates != NULL);
2693 REQUIRE(task != NULL);
2696 tsectype = dns_tsec_gettype(tsec);
2697 if (tsectype != dns_tsectype_tsig)
2698 return (ISC_R_NOTIMPLEMENTED); /* XXX */
2701 LOCK(&client->lock);
2702 result = dns_viewlist_find(&client->viewlist, DNS_CLIENTVIEW_NAME,
2704 UNLOCK(&client->lock);
2705 if (result != ISC_R_SUCCESS)
2708 /* Create a context and prepare some resources */
2709 uctx = isc_mem_get(client->mctx, sizeof(*uctx));
2711 dns_view_detach(&view);
2712 return (ISC_R_NOMEMORY);
2714 result = isc_mutex_init(&uctx->lock);
2715 if (result != ISC_R_SUCCESS) {
2716 dns_view_detach(&view);
2717 isc_mem_put(client->mctx, uctx, sizeof(*uctx));
2718 return (ISC_R_NOMEMORY);
2721 isc_task_attach(task, &clone);
2722 uctx->client = client;
2723 ISC_LINK_INIT(uctx, link);
2724 uctx->state = dns_clientupdatestate_prepare;
2726 uctx->rdclass = rdclass;
2727 uctx->canceled = ISC_FALSE;
2728 uctx->updatemsg = NULL;
2729 uctx->soaquery = NULL;
2730 uctx->updatereq = NULL;
2731 uctx->restrans = NULL;
2732 uctx->restrans2 = NULL;
2735 uctx->soareq = NULL;
2737 uctx->tsigkey = NULL;
2738 uctx->sig0key = NULL;
2739 uctx->zonename = NULL;
2740 dns_name_init(&uctx->soaqname, NULL);
2741 ISC_LIST_INIT(uctx->servers);
2743 uctx->currentserver = NULL;
2744 dns_fixedname_init(&uctx->zonefname);
2746 dns_tsec_getkey(tsec, &uctx->tsigkey);
2747 uctx->event = (dns_clientupdateevent_t *)
2748 isc_event_allocate(client->mctx, clone, DNS_EVENT_UPDATEDONE,
2749 action, arg, sizeof(*uctx->event));
2750 if (uctx->event == NULL)
2752 if (zonename != NULL) {
2753 uctx->zonename = dns_fixedname_name(&uctx->zonefname);
2754 result = dns_name_copy(zonename, uctx->zonename, NULL);
2756 if (servers != NULL) {
2757 for (server = ISC_LIST_HEAD(*servers);
2759 server = ISC_LIST_NEXT(server, link)) {
2760 sa = isc_mem_get(client->mctx, sizeof(*sa));
2763 sa->type = server->type;
2764 sa->length = server->length;
2765 ISC_LINK_INIT(sa, link);
2766 ISC_LIST_APPEND(uctx->servers, sa, link);
2767 if (uctx->currentserver == NULL)
2768 uctx->currentserver = sa;
2773 /* Make update message */
2774 result = dns_message_create(client->mctx, DNS_MESSAGE_INTENTRENDER,
2776 if (result != ISC_R_SUCCESS)
2778 uctx->updatemsg->opcode = dns_opcode_update;
2780 if (prerequisites != NULL) {
2781 for (name = ISC_LIST_HEAD(*prerequisites); name != NULL;
2782 name = ISC_LIST_NEXT(name, link)) {
2784 result = copy_name(client->mctx, uctx->updatemsg,
2786 if (result != ISC_R_SUCCESS)
2788 dns_message_addname(uctx->updatemsg, newname,
2789 DNS_SECTION_PREREQUISITE);
2793 for (name = ISC_LIST_HEAD(*updates); name != NULL;
2794 name = ISC_LIST_NEXT(name, link)) {
2796 result = copy_name(client->mctx, uctx->updatemsg, name,
2798 if (result != ISC_R_SUCCESS)
2800 dns_message_addname(uctx->updatemsg, newname,
2801 DNS_SECTION_UPDATE);
2804 uctx->firstname = NULL;
2805 result = dns_message_firstname(uctx->updatemsg, section);
2806 if (result == ISC_R_NOMORE) {
2807 section = DNS_SECTION_PREREQUISITE;
2808 result = dns_message_firstname(uctx->updatemsg, section);
2810 if (result != ISC_R_SUCCESS)
2812 dns_message_currentname(uctx->updatemsg, section, &uctx->firstname);
2814 uctx->magic = UCTX_MAGIC;
2816 LOCK(&client->lock);
2817 ISC_LIST_APPEND(client->updatectxs, uctx, link);
2818 UNLOCK(&client->lock);
2820 if (uctx->zonename != NULL && uctx->currentserver != NULL) {
2821 result = send_update(uctx);
2822 if (result != ISC_R_SUCCESS)
2824 } else if (uctx->currentserver != NULL) {
2825 result = request_soa(uctx);
2826 if (result != ISC_R_SUCCESS)
2829 dns_name_clone(uctx->firstname, &uctx->soaqname);
2830 result = dns_client_startresolve(uctx->client, &uctx->soaqname,
2832 dns_rdatatype_soa, 0,
2833 client->task, resolvesoa_done,
2834 uctx, &uctx->restrans);
2835 if (result != ISC_R_SUCCESS)
2839 *transp = (dns_clientupdatetrans_t *)uctx;
2841 return (ISC_R_SUCCESS);
2844 if (ISC_LINK_LINKED(uctx, link)) {
2845 LOCK(&client->lock);
2846 ISC_LIST_UNLINK(client->updatectxs, uctx, link);
2847 UNLOCK(&client->lock);
2849 if (uctx->updatemsg != NULL)
2850 dns_message_destroy(&uctx->updatemsg);
2851 while ((sa = ISC_LIST_HEAD(uctx->servers)) != NULL) {
2852 ISC_LIST_UNLINK(uctx->servers, sa, link);
2853 isc_mem_put(client->mctx, sa, sizeof(*sa));
2855 if (uctx->event != NULL)
2856 isc_event_free(ISC_EVENT_PTR(&uctx->event));
2857 if (uctx->tsigkey != NULL)
2858 dns_tsigkey_detach(&uctx->tsigkey);
2859 isc_task_detach(&clone);
2860 DESTROYLOCK(&uctx->lock);
2862 isc_mem_put(client->mctx, uctx, sizeof(*uctx));
2863 dns_view_detach(&view);
2869 dns_client_cancelupdate(dns_clientupdatetrans_t *trans) {
2872 REQUIRE(trans != NULL);
2873 uctx = (updatectx_t *)trans;
2874 REQUIRE(UCTX_VALID(uctx));
2878 if (!uctx->canceled) {
2879 uctx->canceled = ISC_TRUE;
2880 if (uctx->updatereq != NULL)
2881 dns_request_cancel(uctx->updatereq);
2882 if (uctx->soareq != NULL)
2883 dns_request_cancel(uctx->soareq);
2884 if (uctx->restrans != NULL)
2885 dns_client_cancelresolve(uctx->restrans);
2886 if (uctx->restrans2 != NULL)
2887 dns_client_cancelresolve(uctx->restrans2);
2890 UNLOCK(&uctx->lock);
2894 dns_client_destroyupdatetrans(dns_clientupdatetrans_t **transp) {
2897 dns_client_t *client;
2898 isc_boolean_t need_destroyclient = ISC_FALSE;
2901 REQUIRE(transp != NULL);
2902 uctx = (updatectx_t *)*transp;
2903 REQUIRE(UCTX_VALID(uctx));
2904 client = uctx->client;
2905 REQUIRE(DNS_CLIENT_VALID(client));
2906 REQUIRE(uctx->updatereq == NULL && uctx->updatemsg == NULL &&
2907 uctx->soareq == NULL && uctx->soaquery == NULL &&
2908 uctx->event == NULL && uctx->tsigkey == NULL &&
2909 uctx->sig0key == NULL);
2911 mctx = client->mctx;
2912 dns_view_detach(&uctx->view);
2913 while ((sa = ISC_LIST_HEAD(uctx->servers)) != NULL) {
2914 ISC_LIST_UNLINK(uctx->servers, sa, link);
2915 isc_mem_put(mctx, sa, sizeof(*sa));
2918 LOCK(&client->lock);
2920 INSIST(ISC_LINK_LINKED(uctx, link));
2921 ISC_LIST_UNLINK(client->updatectxs, uctx, link);
2923 if (client->references == 0 && ISC_LIST_EMPTY(client->resctxs) &&
2924 ISC_LIST_EMPTY(client->reqctxs) &&
2925 ISC_LIST_EMPTY(client->updatectxs))
2926 need_destroyclient = ISC_TRUE;
2928 UNLOCK(&client->lock);
2930 DESTROYLOCK(&uctx->lock);
2933 isc_mem_put(mctx, uctx, sizeof(*uctx));
2935 if (need_destroyclient)
2936 destroyclient(&client);
2942 dns_client_mctx(dns_client_t *client) {
2944 REQUIRE(DNS_CLIENT_VALID(client));
2945 return (client->mctx);
2949 isc_buffer_t buffer;
2950 dns_rdataset_t rdataset;
2951 dns_rdatalist_t rdatalist;
2955 unsigned char data[FLEXIBLE_ARRAY_MEMBER];
2956 } dns_client_updaterec_t;
2959 dns_client_updaterec(dns_client_updateop_t op, dns_name_t *owner,
2960 dns_rdatatype_t type, dns_rdata_t *source,
2961 dns_ttl_t ttl, dns_name_t *target,
2962 dns_rdataset_t *rdataset, dns_rdatalist_t *rdatalist,
2963 dns_rdata_t *rdata, isc_mem_t *mctx)
2965 dns_client_updaterec_t *updaterec = NULL;
2966 size_t size = offsetof(dns_client_updaterec_t, data);
2968 REQUIRE(op < updateop_max);
2969 REQUIRE(owner != NULL);
2970 REQUIRE((rdataset != NULL && rdatalist != NULL && rdata != NULL) ||
2971 (rdataset == NULL && rdatalist == NULL && rdata == NULL &&
2973 if (op == updateop_add)
2974 REQUIRE(source != NULL);
2975 if (source != NULL) {
2976 REQUIRE(source->type == type);
2977 REQUIRE(op == updateop_add || op == updateop_delete ||
2978 op == updateop_exist);
2981 size += owner->length;
2983 size += source->length;
2985 if (rdataset == NULL) {
2986 updaterec = isc_mem_get(mctx, size);
2987 if (updaterec == NULL)
2988 return (ISC_R_NOMEMORY);
2989 rdataset = &updaterec->rdataset;
2990 rdatalist = &updaterec->rdatalist;
2991 rdata = &updaterec->rdata;
2992 dns_rdataset_init(rdataset);
2993 dns_rdatalist_init(&updaterec->rdatalist);
2994 dns_rdata_init(&updaterec->rdata);
2995 isc_buffer_init(&updaterec->buffer, updaterec->data,
2996 size - offsetof(dns_client_updaterec_t, data));
2997 dns_name_copy(owner, target, &updaterec->buffer);
2998 if (source != NULL) {
3000 dns_rdata_clone(source, rdata);
3001 dns_rdata_toregion(rdata, &r);
3002 rdata->data = isc_buffer_used(&updaterec->buffer);
3003 isc_buffer_copyregion(&updaterec->buffer, &r);
3005 updaterec->mctx = NULL;
3006 isc_mem_attach(mctx, &updaterec->mctx);
3007 } else if (source != NULL)
3008 dns_rdata_clone(source, rdata);
3013 case updateop_delete:
3014 if (source != NULL) {
3016 dns_rdata_makedelete(rdata);
3018 dns_rdata_deleterrset(rdata, type);
3020 case updateop_notexist:
3021 dns_rdata_notexist(rdata, type);
3023 case updateop_exist:
3024 if (source == NULL) {
3026 dns_rdata_exists(rdata, type);
3034 rdatalist->type = rdata->type;
3035 rdatalist->rdclass = rdata->rdclass;
3036 if (source != NULL) {
3037 rdatalist->covers = dns_rdata_covers(rdata);
3038 rdatalist->ttl = ttl;
3040 ISC_LIST_APPEND(rdatalist->rdata, rdata, link);
3041 dns_rdatalist_tordataset(rdatalist, rdataset);
3042 ISC_LIST_APPEND(target->list, rdataset, link);
3043 if (updaterec != NULL) {
3044 target->attributes |= DNS_NAMEATTR_HASUPDATEREC;
3045 dns_name_setbuffer(target, &updaterec->buffer);
3047 if (op == updateop_add || op == updateop_delete)
3048 target->attributes |= DNS_NAMEATTR_UPDATE;
3050 target->attributes |= DNS_NAMEATTR_PREREQUISITE;
3051 return (ISC_R_SUCCESS);
3055 dns_client_freeupdate(dns_name_t **namep) {
3056 dns_client_updaterec_t *updaterec;
3057 dns_rdatalist_t *rdatalist;
3058 dns_rdataset_t *rdataset;
3062 REQUIRE(namep != NULL && *namep != NULL);
3065 for (rdataset = ISC_LIST_HEAD(name->list);
3067 rdataset = ISC_LIST_HEAD(name->list)) {
3068 ISC_LIST_UNLINK(name->list, rdataset, link);
3070 dns_rdatalist_fromrdataset(rdataset, &rdatalist);
3071 if (rdatalist == NULL) {
3072 dns_rdataset_disassociate(rdataset);
3075 for (rdata = ISC_LIST_HEAD(rdatalist->rdata);
3077 rdata = ISC_LIST_HEAD(rdatalist->rdata))
3078 ISC_LIST_UNLINK(rdatalist->rdata, rdata, link);
3079 dns_rdataset_disassociate(rdataset);
3082 if ((name->attributes & DNS_NAMEATTR_HASUPDATEREC) != 0) {
3083 updaterec = (dns_client_updaterec_t *)name->buffer;
3084 INSIST(updaterec != NULL);
3085 isc_mem_putanddetach(&updaterec->mctx, updaterec,