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.
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)
254 unsigned int attrs, attrmask;
256 dns_dispatch_t *disp;
257 unsigned buffersize, maxbuffers, maxrequests, buckets, increment;
261 attrs |= DNS_DISPATCHATTR_UDP;
264 attrs |= DNS_DISPATCHATTR_IPV4;
267 attrs |= DNS_DISPATCHATTR_IPV6;
273 attrmask |= DNS_DISPATCHATTR_UDP;
274 attrmask |= DNS_DISPATCHATTR_TCP;
275 attrmask |= DNS_DISPATCHATTR_IPV4;
276 attrmask |= DNS_DISPATCHATTR_IPV6;
278 isc_sockaddr_anyofpf(&sa, family);
281 maxbuffers = is_shared ? 1000 : 8;
283 buckets = is_shared ? 16411 : 3;
284 increment = is_shared ? 16433 : 5;
287 result = dns_dispatch_getudp(dispatchmgr, socketmgr,
289 buffersize, maxbuffers, maxrequests,
291 attrs, attrmask, &disp);
292 if (result == ISC_R_SUCCESS)
299 dns_client_createview(isc_mem_t *mctx, dns_rdataclass_t rdclass,
300 unsigned int options, isc_taskmgr_t *taskmgr,
301 unsigned int ntasks, isc_socketmgr_t *socketmgr,
302 isc_timermgr_t *timermgr, dns_dispatchmgr_t *dispatchmgr,
303 dns_dispatch_t *dispatchv4, dns_dispatch_t *dispatchv6,
307 dns_view_t *view = NULL;
310 result = dns_view_create(mctx, rdclass, DNS_CLIENTVIEW_NAME, &view);
311 if (result != ISC_R_SUCCESS)
314 /* Initialize view security roots */
315 result = dns_view_initsecroots(view, mctx);
316 if (result != ISC_R_SUCCESS) {
317 dns_view_detach(&view);
321 result = dns_view_createresolver(view, taskmgr, ntasks, socketmgr,
322 timermgr, 0, dispatchmgr,
323 dispatchv4, dispatchv6);
324 if (result != ISC_R_SUCCESS) {
325 dns_view_detach(&view);
331 * XXX: it may be better if specific DB implementations can be
332 * specified via some configuration knob.
334 if ((options & DNS_CLIENTCREATEOPT_USECACHE) != 0)
338 result = dns_db_create(mctx, dbtype, dns_rootname, dns_dbtype_cache,
339 rdclass, 0, NULL, &view->cachedb);
340 if (result != ISC_R_SUCCESS) {
341 dns_view_detach(&view);
346 return (ISC_R_SUCCESS);
350 dns_client_create(dns_client_t **clientp, unsigned int options) {
352 isc_mem_t *mctx = NULL;
353 isc_appctx_t *actx = NULL;
354 isc_taskmgr_t *taskmgr = NULL;
355 isc_socketmgr_t *socketmgr = NULL;
356 isc_timermgr_t *timermgr = NULL;
358 /* XXXMPA add debug logging support */
359 isc_log_t *lctx = NULL;
360 isc_logconfig_t *logconfig = NULL;
361 unsigned int logdebuglevel = 0;
364 result = isc_mem_create(0, 0, &mctx);
365 if (result != ISC_R_SUCCESS)
367 result = isc_appctx_create(mctx, &actx);
368 if (result != ISC_R_SUCCESS)
370 result = isc_app_ctxstart(actx);
371 if (result != ISC_R_SUCCESS)
373 result = isc_taskmgr_createinctx(mctx, actx, 1, 0, &taskmgr);
374 if (result != ISC_R_SUCCESS)
376 result = isc_socketmgr_createinctx(mctx, actx, &socketmgr);
377 if (result != ISC_R_SUCCESS)
379 result = isc_timermgr_createinctx(mctx, actx, &timermgr);
380 if (result != ISC_R_SUCCESS)
383 result = isc_log_create(mctx, &lctx, &logconfig);
384 if (result != ISC_R_SUCCESS)
386 isc_log_setcontext(lctx);
388 dns_log_setcontext(lctx);
389 result = isc_log_usechannel(logconfig, "default_debug", NULL, NULL);
390 if (result != ISC_R_SUCCESS)
392 isc_log_setdebuglevel(lctx, logdebuglevel);
394 result = dns_client_createx(mctx, actx, taskmgr, socketmgr, timermgr,
396 if (result != ISC_R_SUCCESS)
399 (*clientp)->attributes |= DNS_CLIENTATTR_OWNCTX;
401 /* client has its own reference to mctx, so we can detach it here */
402 isc_mem_detach(&mctx);
404 return (ISC_R_SUCCESS);
408 isc_taskmgr_destroy(&taskmgr);
409 if (timermgr != NULL)
410 isc_timermgr_destroy(&timermgr);
411 if (socketmgr != NULL)
412 isc_socketmgr_destroy(&socketmgr);
414 isc_appctx_destroy(&actx);
415 isc_mem_detach(&mctx);
421 dns_client_createx(isc_mem_t *mctx, isc_appctx_t *actx, isc_taskmgr_t *taskmgr,
422 isc_socketmgr_t *socketmgr, isc_timermgr_t *timermgr,
423 unsigned int options, dns_client_t **clientp)
425 dns_client_t *client;
427 dns_dispatchmgr_t *dispatchmgr = NULL;
428 dns_dispatch_t *dispatchv4 = NULL;
429 dns_dispatch_t *dispatchv6 = NULL;
430 dns_view_t *view = NULL;
432 REQUIRE(mctx != NULL);
433 REQUIRE(taskmgr != NULL);
434 REQUIRE(timermgr != NULL);
435 REQUIRE(socketmgr != NULL);
436 REQUIRE(clientp != NULL && *clientp == NULL);
438 client = isc_mem_get(mctx, sizeof(*client));
440 return (ISC_R_NOMEMORY);
442 result = isc_mutex_init(&client->lock);
443 if (result != ISC_R_SUCCESS) {
444 isc_mem_put(mctx, client, sizeof(*client));
449 client->taskmgr = taskmgr;
450 client->socketmgr = socketmgr;
451 client->timermgr = timermgr;
454 result = isc_task_create(client->taskmgr, 0, &client->task);
455 if (result != ISC_R_SUCCESS)
458 result = dns_dispatchmgr_create(mctx, NULL, &dispatchmgr);
459 if (result != ISC_R_SUCCESS)
461 client->dispatchmgr = dispatchmgr;
463 /* TODO: whether to use dispatch v4 or v6 should be configurable */
464 client->dispatchv4 = NULL;
465 client->dispatchv6 = NULL;
466 result = getudpdispatch(AF_INET, dispatchmgr, socketmgr,
467 taskmgr, ISC_TRUE, &dispatchv4);
468 if (result == ISC_R_SUCCESS)
469 client->dispatchv4 = dispatchv4;
470 result = getudpdispatch(AF_INET6, dispatchmgr, socketmgr,
471 taskmgr, ISC_TRUE, &dispatchv6);
472 if (result == ISC_R_SUCCESS)
473 client->dispatchv6 = dispatchv6;
475 /* We need at least one of the dispatchers */
476 if (dispatchv4 == NULL && dispatchv6 == NULL) {
477 INSIST(result != ISC_R_SUCCESS);
481 /* Create the default view for class IN */
482 result = dns_client_createview(mctx, dns_rdataclass_in, options,
483 taskmgr, 31, socketmgr, timermgr,
484 dispatchmgr, dispatchv4, dispatchv6,
486 if (result != ISC_R_SUCCESS)
488 ISC_LIST_INIT(client->viewlist);
489 ISC_LIST_APPEND(client->viewlist, view, link);
491 dns_view_freeze(view); /* too early? */
493 ISC_LIST_INIT(client->resctxs);
494 ISC_LIST_INIT(client->reqctxs);
495 ISC_LIST_INIT(client->updatectxs);
498 isc_mem_attach(mctx, &client->mctx);
500 client->update_timeout = DEF_UPDATE_TIMEOUT;
501 client->update_udptimeout = DEF_UPDATE_UDPTIMEOUT;
502 client->update_udpretries = DEF_UPDATE_UDPRETRIES;
503 client->find_timeout = DEF_FIND_TIMEOUT;
504 client->find_udpretries = DEF_FIND_UDPRETRIES;
505 client->attributes = 0;
507 client->references = 1;
508 client->magic = DNS_CLIENT_MAGIC;
512 return (ISC_R_SUCCESS);
515 if (dispatchv4 != NULL)
516 dns_dispatch_detach(&dispatchv4);
517 if (dispatchv6 != NULL)
518 dns_dispatch_detach(&dispatchv6);
519 if (dispatchmgr != NULL)
520 dns_dispatchmgr_destroy(&dispatchmgr);
521 if (client->task != NULL)
522 isc_task_detach(&client->task);
523 isc_mem_put(mctx, client, sizeof(*client));
529 destroyclient(dns_client_t **clientp) {
530 dns_client_t *client = *clientp;
533 while ((view = ISC_LIST_HEAD(client->viewlist)) != NULL) {
534 ISC_LIST_UNLINK(client->viewlist, view, link);
535 dns_view_detach(&view);
538 if (client->dispatchv4 != NULL)
539 dns_dispatch_detach(&client->dispatchv4);
540 if (client->dispatchv6 != NULL)
541 dns_dispatch_detach(&client->dispatchv6);
543 dns_dispatchmgr_destroy(&client->dispatchmgr);
545 isc_task_detach(&client->task);
548 * If the client has created its own running environments,
551 if ((client->attributes & DNS_CLIENTATTR_OWNCTX) != 0) {
552 isc_taskmgr_destroy(&client->taskmgr);
553 isc_timermgr_destroy(&client->timermgr);
554 isc_socketmgr_destroy(&client->socketmgr);
556 isc_app_ctxfinish(client->actx);
557 isc_appctx_destroy(&client->actx);
560 DESTROYLOCK(&client->lock);
563 isc_mem_putanddetach(&client->mctx, client, sizeof(*client));
569 dns_client_destroy(dns_client_t **clientp) {
570 dns_client_t *client;
571 isc_boolean_t destroyok = ISC_FALSE;
573 REQUIRE(clientp != NULL);
575 REQUIRE(DNS_CLIENT_VALID(client));
578 client->references--;
579 if (client->references == 0 && ISC_LIST_EMPTY(client->resctxs) &&
580 ISC_LIST_EMPTY(client->reqctxs) &&
581 ISC_LIST_EMPTY(client->updatectxs)) {
582 destroyok = ISC_TRUE;
584 UNLOCK(&client->lock);
587 destroyclient(&client);
593 dns_client_setservers(dns_client_t *client, dns_rdataclass_t rdclass,
594 dns_name_t *namespace, isc_sockaddrlist_t *addrs)
597 dns_view_t *view = NULL;
599 REQUIRE(DNS_CLIENT_VALID(client));
600 REQUIRE(addrs != NULL);
602 if (namespace == NULL)
603 namespace = dns_rootname;
606 result = dns_viewlist_find(&client->viewlist, DNS_CLIENTVIEW_NAME,
608 if (result != ISC_R_SUCCESS) {
609 UNLOCK(&client->lock);
612 UNLOCK(&client->lock);
614 result = dns_fwdtable_add(view->fwdtable, namespace, addrs,
617 dns_view_detach(&view);
623 dns_client_clearservers(dns_client_t *client, dns_rdataclass_t rdclass,
624 dns_name_t *namespace)
627 dns_view_t *view = NULL;
629 REQUIRE(DNS_CLIENT_VALID(client));
631 if (namespace == NULL)
632 namespace = dns_rootname;
635 result = dns_viewlist_find(&client->viewlist, DNS_CLIENTVIEW_NAME,
637 if (result != ISC_R_SUCCESS) {
638 UNLOCK(&client->lock);
641 UNLOCK(&client->lock);
643 result = dns_fwdtable_delete(view->fwdtable, namespace);
645 dns_view_detach(&view);
651 getrdataset(isc_mem_t *mctx, dns_rdataset_t **rdatasetp) {
652 dns_rdataset_t *rdataset;
654 REQUIRE(mctx != NULL);
655 REQUIRE(rdatasetp != NULL && *rdatasetp == NULL);
657 rdataset = isc_mem_get(mctx, sizeof(*rdataset));
658 if (rdataset == NULL)
659 return (ISC_R_NOMEMORY);
661 dns_rdataset_init(rdataset);
663 *rdatasetp = rdataset;
665 return (ISC_R_SUCCESS);
669 putrdataset(isc_mem_t *mctx, dns_rdataset_t **rdatasetp) {
670 dns_rdataset_t *rdataset;
672 REQUIRE(rdatasetp != NULL);
673 rdataset = *rdatasetp;
674 REQUIRE(rdataset != NULL);
676 if (dns_rdataset_isassociated(rdataset))
677 dns_rdataset_disassociate(rdataset);
679 isc_mem_put(mctx, rdataset, sizeof(*rdataset));
685 fetch_done(isc_task_t *task, isc_event_t *event) {
686 resctx_t *rctx = event->ev_arg;
687 dns_fetchevent_t *fevent;
689 REQUIRE(event->ev_type == DNS_EVENT_FETCHDONE);
690 REQUIRE(RCTX_VALID(rctx));
691 REQUIRE(rctx->task == task);
692 fevent = (dns_fetchevent_t *)event;
694 client_resfind(rctx, fevent);
697 static inline isc_result_t
698 start_fetch(resctx_t *rctx) {
702 * The caller must be holding the rctx's lock.
705 REQUIRE(rctx->fetch == NULL);
707 result = dns_resolver_createfetch(rctx->view->resolver,
708 dns_fixedname_name(&rctx->name),
711 rctx->task, fetch_done, rctx,
720 view_find(resctx_t *rctx, dns_db_t **dbp, dns_dbnode_t **nodep,
721 dns_name_t *foundname)
724 dns_name_t *name = dns_fixedname_name(&rctx->name);
725 dns_rdatatype_t type;
727 if (rctx->type == dns_rdatatype_rrsig)
728 type = dns_rdatatype_any;
732 result = dns_view_find(rctx->view, name, type, 0, 0, ISC_FALSE,
733 dbp, nodep, foundname, rctx->rdataset,
740 client_resfind(resctx_t *rctx, dns_fetchevent_t *event) {
742 isc_result_t tresult, result = ISC_R_SUCCESS;
743 isc_result_t vresult = ISC_R_SUCCESS;
744 isc_boolean_t want_restart;
745 isc_boolean_t send_event = ISC_FALSE;
746 dns_name_t *name, *prefix;
747 dns_fixedname_t foundname, fixed;
748 dns_rdataset_t *trdataset;
749 dns_rdata_t rdata = DNS_RDATA_INIT;
750 unsigned int nlabels;
752 dns_namereln_t namereln;
753 dns_rdata_cname_t cname;
754 dns_rdata_dname_t dname;
756 REQUIRE(RCTX_VALID(rctx));
760 mctx = rctx->view->mctx;
762 name = dns_fixedname_name(&rctx->name);
765 dns_name_t *fname = NULL;
766 dns_name_t *ansname = NULL;
768 dns_dbnode_t *node = NULL;
771 want_restart = ISC_FALSE;
773 if (event == NULL && !rctx->canceled) {
774 dns_fixedname_init(&foundname);
775 fname = dns_fixedname_name(&foundname);
776 INSIST(!dns_rdataset_isassociated(rctx->rdataset));
777 INSIST(rctx->sigrdataset == NULL ||
778 !dns_rdataset_isassociated(rctx->sigrdataset));
779 result = view_find(rctx, &db, &node, fname);
780 if (result == ISC_R_NOTFOUND) {
782 * We don't know anything about the name.
787 dns_db_detachnode(db, &node);
791 result = start_fetch(rctx);
792 if (result != ISC_R_SUCCESS) {
793 putrdataset(mctx, &rctx->rdataset);
794 if (rctx->sigrdataset != NULL)
797 send_event = ISC_TRUE;
802 INSIST(event != NULL);
803 INSIST(event->fetch == rctx->fetch);
804 dns_resolver_destroyfetch(&rctx->fetch);
807 result = event->result;
808 vresult = event->vresult;
809 fname = dns_fixedname_name(&event->foundname);
810 INSIST(event->rdataset == rctx->rdataset);
811 INSIST(event->sigrdataset == rctx->sigrdataset);
815 * If we've been canceled, forget about the result.
818 result = ISC_R_CANCELED;
821 * Otherwise, get some resource for copying the
824 ansname = isc_mem_get(mctx, sizeof(*ansname));
826 tresult = ISC_R_NOMEMORY;
830 aname = dns_fixedname_name(&rctx->name);
831 dns_name_init(ansname, NULL);
832 tresult = dns_name_dup(aname, mctx, ansname);
833 if (tresult != ISC_R_SUCCESS)
834 isc_mem_put(mctx, ansname,
837 if (tresult != ISC_R_SUCCESS)
843 send_event = ISC_TRUE;
845 * This case is handled in the main line below.
850 * Add the CNAME to the answer list.
852 trdataset = rctx->rdataset;
853 ISC_LIST_APPEND(ansname->list, rctx->rdataset, link);
854 rctx->rdataset = NULL;
855 if (rctx->sigrdataset != NULL) {
856 ISC_LIST_APPEND(ansname->list,
857 rctx->sigrdataset, link);
858 rctx->sigrdataset = NULL;
860 ISC_LIST_APPEND(rctx->namelist, ansname, link);
864 * Copy the CNAME's target into the lookup's
865 * query name and start over.
867 tresult = dns_rdataset_first(trdataset);
868 if (tresult != ISC_R_SUCCESS)
870 dns_rdataset_current(trdataset, &rdata);
871 tresult = dns_rdata_tostruct(&rdata, &cname, NULL);
872 dns_rdata_reset(&rdata);
873 if (tresult != ISC_R_SUCCESS)
875 tresult = dns_name_copy(&cname.cname, name, NULL);
876 dns_rdata_freestruct(&cname);
877 if (tresult == ISC_R_SUCCESS)
878 want_restart = ISC_TRUE;
884 * Add the DNAME to the answer list.
886 trdataset = rctx->rdataset;
887 ISC_LIST_APPEND(ansname->list, rctx->rdataset, link);
888 rctx->rdataset = NULL;
889 if (rctx->sigrdataset != NULL) {
890 ISC_LIST_APPEND(ansname->list,
891 rctx->sigrdataset, link);
892 rctx->sigrdataset = NULL;
894 ISC_LIST_APPEND(rctx->namelist, ansname, link);
897 namereln = dns_name_fullcompare(name, fname, &order,
899 INSIST(namereln == dns_namereln_subdomain);
901 * Get the target name of the DNAME.
903 tresult = dns_rdataset_first(trdataset);
904 if (tresult != ISC_R_SUCCESS) {
908 dns_rdataset_current(trdataset, &rdata);
909 tresult = dns_rdata_tostruct(&rdata, &dname, NULL);
910 dns_rdata_reset(&rdata);
911 if (tresult != ISC_R_SUCCESS) {
916 * Construct the new query name and start over.
918 dns_fixedname_init(&fixed);
919 prefix = dns_fixedname_name(&fixed);
920 dns_name_split(name, nlabels, prefix, NULL);
921 tresult = dns_name_concatenate(prefix, &dname.dname,
923 dns_rdata_freestruct(&dname);
924 if (tresult == ISC_R_SUCCESS)
925 want_restart = ISC_TRUE;
929 case DNS_R_NCACHENXDOMAIN:
930 case DNS_R_NCACHENXRRSET:
931 ISC_LIST_APPEND(ansname->list, rctx->rdataset, link);
932 ISC_LIST_APPEND(rctx->namelist, ansname, link);
934 rctx->rdataset = NULL;
935 /* What about sigrdataset? */
936 if (rctx->sigrdataset != NULL)
937 putrdataset(mctx, &rctx->sigrdataset);
938 send_event = ISC_TRUE;
941 if (rctx->rdataset != NULL)
942 putrdataset(mctx, &rctx->rdataset);
943 if (rctx->sigrdataset != NULL)
944 putrdataset(mctx, &rctx->sigrdataset);
945 send_event = ISC_TRUE;
949 if (rctx->type == dns_rdatatype_any) {
951 dns_rdatasetiter_t *rdsiter = NULL;
953 tresult = dns_db_allrdatasets(db, node, NULL, 0,
955 if (tresult != ISC_R_SUCCESS) {
960 tresult = dns_rdatasetiter_first(rdsiter);
961 while (tresult == ISC_R_SUCCESS) {
962 dns_rdatasetiter_current(rdsiter,
964 if (rctx->rdataset->type != 0) {
965 ISC_LIST_APPEND(ansname->list,
969 rctx->rdataset = NULL;
972 * We're not interested in this
975 dns_rdataset_disassociate(
978 tresult = dns_rdatasetiter_next(rdsiter);
980 if (tresult == ISC_R_SUCCESS &&
981 rctx->rdataset == NULL) {
982 tresult = getrdataset(mctx,
984 if (tresult != ISC_R_SUCCESS) {
993 * We didn't match any rdatasets (which means
994 * something went wrong in this
997 result = DNS_R_SERVFAIL; /* better code? */
1000 ISC_LIST_APPEND(rctx->namelist, ansname, link);
1003 dns_rdatasetiter_destroy(&rdsiter);
1004 if (tresult != ISC_R_NOMORE)
1005 result = DNS_R_SERVFAIL; /* ditto */
1007 result = ISC_R_SUCCESS;
1011 * This is the "normal" case -- an ordinary question
1012 * to which we've got the answer.
1014 ISC_LIST_APPEND(ansname->list, rctx->rdataset, link);
1015 rctx->rdataset = NULL;
1016 if (rctx->sigrdataset != NULL) {
1017 ISC_LIST_APPEND(ansname->list,
1018 rctx->sigrdataset, link);
1019 rctx->sigrdataset = NULL;
1021 ISC_LIST_APPEND(rctx->namelist, ansname, link);
1027 * Free temporary resources
1029 if (ansname != NULL) {
1030 dns_rdataset_t *rdataset;
1032 while ((rdataset = ISC_LIST_HEAD(ansname->list))
1034 ISC_LIST_UNLINK(ansname->list, rdataset, link);
1035 putrdataset(mctx, &rdataset);
1037 dns_name_free(ansname, mctx);
1038 isc_mem_put(mctx, ansname, sizeof(*ansname));
1042 dns_db_detachnode(db, &node);
1046 isc_event_free(ISC_EVENT_PTR(&event));
1049 * Limit the number of restarts.
1051 if (want_restart && rctx->restarts == MAX_RESTARTS) {
1052 want_restart = ISC_FALSE;
1053 result = ISC_R_QUOTA;
1054 send_event = ISC_TRUE;
1058 * Prepare further find with new resources
1061 INSIST(rctx->rdataset == NULL &&
1062 rctx->sigrdataset == NULL);
1064 result = getrdataset(mctx, &rctx->rdataset);
1065 if (result == ISC_R_SUCCESS && rctx->want_dnssec) {
1066 result = getrdataset(mctx, &rctx->sigrdataset);
1067 if (result != ISC_R_SUCCESS) {
1068 putrdataset(mctx, &rctx->rdataset);
1072 if (result != ISC_R_SUCCESS) {
1073 want_restart = ISC_FALSE;
1074 send_event = ISC_TRUE;
1077 } while (want_restart);
1082 while ((name = ISC_LIST_HEAD(rctx->namelist)) != NULL) {
1083 ISC_LIST_UNLINK(rctx->namelist, name, link);
1084 ISC_LIST_APPEND(rctx->event->answerlist, name, link);
1087 rctx->event->result = result;
1088 rctx->event->vresult = vresult;
1089 task = rctx->event->ev_sender;
1090 rctx->event->ev_sender = rctx;
1091 isc_task_sendanddetach(&task, ISC_EVENT_PTR(&rctx->event));
1094 UNLOCK(&rctx->lock);
1099 suspend(isc_task_t *task, isc_event_t *event) {
1100 isc_appctx_t *actx = event->ev_arg;
1104 isc_app_ctxsuspend(actx);
1105 isc_event_free(&event);
1109 resolve_done(isc_task_t *task, isc_event_t *event) {
1110 resarg_t *resarg = event->ev_arg;
1111 dns_clientresevent_t *rev = (dns_clientresevent_t *)event;
1113 isc_result_t result;
1117 LOCK(&resarg->lock);
1119 resarg->result = rev->result;
1120 resarg->vresult = rev->vresult;
1121 while ((name = ISC_LIST_HEAD(rev->answerlist)) != NULL) {
1122 ISC_LIST_UNLINK(rev->answerlist, name, link);
1123 ISC_LIST_APPEND(*resarg->namelist, name, link);
1126 dns_client_destroyrestrans(&resarg->trans);
1127 isc_event_free(&event);
1129 if (!resarg->canceled) {
1130 UNLOCK(&resarg->lock);
1133 * We may or may not be running. isc__appctx_onrun will
1134 * fail if we are currently running otherwise we post a
1135 * action to call isc_app_ctxsuspend when we do start
1138 result = isc_app_ctxonrun(resarg->actx, resarg->client->mctx,
1139 task, suspend, resarg->actx);
1140 if (result == ISC_R_ALREADYRUNNING)
1141 isc_app_ctxsuspend(resarg->actx);
1144 * We have already exited from the loop (due to some
1145 * unexpected event). Just clean the arg up.
1147 UNLOCK(&resarg->lock);
1148 DESTROYLOCK(&resarg->lock);
1149 isc_mem_put(resarg->client->mctx, resarg, sizeof(*resarg));
1154 dns_client_resolve(dns_client_t *client, dns_name_t *name,
1155 dns_rdataclass_t rdclass, dns_rdatatype_t type,
1156 unsigned int options, dns_namelist_t *namelist)
1158 isc_result_t result;
1162 REQUIRE(DNS_CLIENT_VALID(client));
1163 REQUIRE(namelist != NULL && ISC_LIST_EMPTY(*namelist));
1165 if ((client->attributes & DNS_CLIENTATTR_OWNCTX) == 0 &&
1166 (options & DNS_CLIENTRESOPT_ALLOWRUN) == 0) {
1168 * If the client is run under application's control, we need
1169 * to create a new running (sub)environment for this
1170 * particular resolution.
1172 return (ISC_R_NOTIMPLEMENTED); /* XXXTBD */
1174 actx = client->actx;
1176 resarg = isc_mem_get(client->mctx, sizeof(*resarg));
1178 return (ISC_R_NOMEMORY);
1180 result = isc_mutex_init(&resarg->lock);
1181 if (result != ISC_R_SUCCESS) {
1182 isc_mem_put(client->mctx, resarg, sizeof(*resarg));
1186 resarg->actx = actx;
1187 resarg->client = client;
1188 resarg->result = DNS_R_SERVFAIL;
1189 resarg->namelist = namelist;
1190 resarg->trans = NULL;
1191 resarg->canceled = ISC_FALSE;
1192 result = dns_client_startresolve(client, name, rdclass, type, options,
1193 client->task, resolve_done, resarg,
1195 if (result != ISC_R_SUCCESS) {
1196 DESTROYLOCK(&resarg->lock);
1197 isc_mem_put(client->mctx, resarg, sizeof(*resarg));
1202 * Start internal event loop. It blocks until the entire process
1205 result = isc_app_ctxrun(actx);
1207 LOCK(&resarg->lock);
1208 if (result == ISC_R_SUCCESS || result == ISC_R_SUSPEND)
1209 result = resarg->result;
1210 if (result != ISC_R_SUCCESS && resarg->vresult != ISC_R_SUCCESS) {
1212 * If this lookup failed due to some error in DNSSEC
1213 * validation, return the validation error code.
1214 * XXX: or should we pass the validation result separately?
1216 result = resarg->vresult;
1218 if (resarg->trans != NULL) {
1220 * Unusual termination (perhaps due to signal). We need some
1221 * tricky cleanup process.
1223 resarg->canceled = ISC_TRUE;
1224 dns_client_cancelresolve(resarg->trans);
1226 UNLOCK(&resarg->lock);
1228 /* resarg will be freed in the event handler. */
1230 UNLOCK(&resarg->lock);
1232 DESTROYLOCK(&resarg->lock);
1233 isc_mem_put(client->mctx, resarg, sizeof(*resarg));
1240 dns_client_startresolve(dns_client_t *client, dns_name_t *name,
1241 dns_rdataclass_t rdclass, dns_rdatatype_t type,
1242 unsigned int options, isc_task_t *task,
1243 isc_taskaction_t action, void *arg,
1244 dns_clientrestrans_t **transp)
1246 dns_view_t *view = NULL;
1247 dns_clientresevent_t *event = NULL;
1248 resctx_t *rctx = NULL;
1249 isc_task_t *clone = NULL;
1251 isc_result_t result;
1252 dns_rdataset_t *rdataset, *sigrdataset;
1253 isc_boolean_t want_dnssec;
1255 REQUIRE(DNS_CLIENT_VALID(client));
1256 REQUIRE(transp != NULL && *transp == NULL);
1258 LOCK(&client->lock);
1259 result = dns_viewlist_find(&client->viewlist, DNS_CLIENTVIEW_NAME,
1261 UNLOCK(&client->lock);
1262 if (result != ISC_R_SUCCESS)
1265 mctx = client->mctx;
1268 want_dnssec = ISC_TF((options & DNS_CLIENTRESOPT_NODNSSEC) == 0);
1271 * Prepare some intermediate resources
1274 isc_task_attach(task, &clone);
1275 event = (dns_clientresevent_t *)
1276 isc_event_allocate(mctx, clone, DNS_EVENT_CLIENTRESDONE,
1277 action, arg, sizeof(*event));
1278 if (event == NULL) {
1279 result = ISC_R_NOMEMORY;
1282 event->result = DNS_R_SERVFAIL;
1283 ISC_LIST_INIT(event->answerlist);
1285 rctx = isc_mem_get(mctx, sizeof(*rctx));
1287 result = ISC_R_NOMEMORY;
1289 result = isc_mutex_init(&rctx->lock);
1290 if (result != ISC_R_SUCCESS) {
1291 isc_mem_put(mctx, rctx, sizeof(*rctx));
1295 if (result != ISC_R_SUCCESS)
1298 result = getrdataset(mctx, &rdataset);
1299 if (result != ISC_R_SUCCESS)
1301 rctx->rdataset = rdataset;
1304 result = getrdataset(mctx, &sigrdataset);
1305 if (result != ISC_R_SUCCESS)
1308 rctx->sigrdataset = sigrdataset;
1310 dns_fixedname_init(&rctx->name);
1311 result = dns_name_copy(name, dns_fixedname_name(&rctx->name), NULL);
1312 if (result != ISC_R_SUCCESS)
1315 rctx->client = client;
1316 ISC_LINK_INIT(rctx, link);
1317 rctx->canceled = ISC_FALSE;
1318 rctx->task = client->task;
1323 rctx->want_dnssec = want_dnssec;
1324 ISC_LIST_INIT(rctx->namelist);
1325 rctx->event = event;
1327 rctx->magic = RCTX_MAGIC;
1329 LOCK(&client->lock);
1330 ISC_LIST_APPEND(client->resctxs, rctx, link);
1331 UNLOCK(&client->lock);
1333 *transp = (dns_clientrestrans_t *)rctx;
1334 client_resfind(rctx, NULL);
1336 return (ISC_R_SUCCESS);
1339 if (rdataset != NULL)
1340 putrdataset(client->mctx, &rdataset);
1341 if (sigrdataset != NULL)
1342 putrdataset(client->mctx, &sigrdataset);
1344 DESTROYLOCK(&rctx->lock);
1345 isc_mem_put(mctx, rctx, sizeof(*rctx));
1348 isc_event_free(ISC_EVENT_PTR(&event));
1349 isc_task_detach(&clone);
1350 dns_view_detach(&view);
1356 dns_client_cancelresolve(dns_clientrestrans_t *trans) {
1359 REQUIRE(trans != NULL);
1360 rctx = (resctx_t *)trans;
1361 REQUIRE(RCTX_VALID(rctx));
1365 if (!rctx->canceled) {
1366 rctx->canceled = ISC_TRUE;
1367 if (rctx->fetch != NULL)
1368 dns_resolver_cancelfetch(rctx->fetch);
1371 UNLOCK(&rctx->lock);
1375 dns_client_freeresanswer(dns_client_t *client, dns_namelist_t *namelist) {
1377 dns_rdataset_t *rdataset;
1379 REQUIRE(DNS_CLIENT_VALID(client));
1380 REQUIRE(namelist != NULL);
1382 while ((name = ISC_LIST_HEAD(*namelist)) != NULL) {
1383 ISC_LIST_UNLINK(*namelist, name, link);
1384 while ((rdataset = ISC_LIST_HEAD(name->list)) != NULL) {
1385 ISC_LIST_UNLINK(name->list, rdataset, link);
1386 putrdataset(client->mctx, &rdataset);
1388 dns_name_free(name, client->mctx);
1389 isc_mem_put(client->mctx, name, sizeof(*name));
1394 dns_client_destroyrestrans(dns_clientrestrans_t **transp) {
1397 dns_client_t *client;
1398 isc_boolean_t need_destroyclient = ISC_FALSE;
1400 REQUIRE(transp != NULL);
1401 rctx = (resctx_t *)*transp;
1402 REQUIRE(RCTX_VALID(rctx));
1403 REQUIRE(rctx->fetch == NULL);
1404 REQUIRE(rctx->event == NULL);
1405 client = rctx->client;
1406 REQUIRE(DNS_CLIENT_VALID(client));
1408 mctx = client->mctx;
1409 dns_view_detach(&rctx->view);
1411 LOCK(&client->lock);
1413 INSIST(ISC_LINK_LINKED(rctx, link));
1414 ISC_LIST_UNLINK(client->resctxs, rctx, link);
1416 if (client->references == 0 && ISC_LIST_EMPTY(client->resctxs) &&
1417 ISC_LIST_EMPTY(client->reqctxs) &&
1418 ISC_LIST_EMPTY(client->updatectxs))
1419 need_destroyclient = ISC_TRUE;
1421 UNLOCK(&client->lock);
1423 INSIST(ISC_LIST_EMPTY(rctx->namelist));
1425 DESTROYLOCK(&rctx->lock);
1428 isc_mem_put(mctx, rctx, sizeof(*rctx));
1430 if (need_destroyclient)
1431 destroyclient(&client);
1437 dns_client_addtrustedkey(dns_client_t *client, dns_rdataclass_t rdclass,
1438 dns_name_t *keyname, isc_buffer_t *keydatabuf)
1440 isc_result_t result;
1441 dns_view_t *view = NULL;
1442 dst_key_t *dstkey = NULL;
1443 dns_keytable_t *secroots = NULL;
1445 REQUIRE(DNS_CLIENT_VALID(client));
1447 LOCK(&client->lock);
1448 result = dns_viewlist_find(&client->viewlist, DNS_CLIENTVIEW_NAME,
1450 UNLOCK(&client->lock);
1451 if (result != ISC_R_SUCCESS)
1454 result = dns_view_getsecroots(view, &secroots);
1455 if (result != ISC_R_SUCCESS)
1458 result = dst_key_fromdns(keyname, rdclass, keydatabuf, client->mctx,
1460 if (result != ISC_R_SUCCESS)
1463 result = dns_keytable_add(secroots, ISC_FALSE, &dstkey);
1467 dst_key_free(&dstkey);
1469 dns_view_detach(&view);
1470 if (secroots != NULL)
1471 dns_keytable_detach(&secroots);
1476 * Simple request routines
1479 request_done(isc_task_t *task, isc_event_t *event) {
1480 dns_requestevent_t *reqev = NULL;
1481 dns_request_t *request;
1482 isc_result_t result, eresult;
1487 REQUIRE(event->ev_type == DNS_EVENT_REQUESTDONE);
1488 reqev = (dns_requestevent_t *)event;
1489 request = reqev->request;
1490 result = eresult = reqev->result;
1491 ctx = reqev->ev_arg;
1492 REQUIRE(REQCTX_VALID(ctx));
1494 isc_event_free(&event);
1498 if (eresult == ISC_R_SUCCESS) {
1499 result = dns_request_getresponse(request, ctx->event->rmessage,
1503 if (ctx->tsigkey != NULL)
1504 dns_tsigkey_detach(&ctx->tsigkey);
1507 ctx->event->result = ISC_R_CANCELED;
1509 ctx->event->result = result;
1510 task = ctx->event->ev_sender;
1511 ctx->event->ev_sender = ctx;
1512 isc_task_sendanddetach(&task, ISC_EVENT_PTR(&ctx->event));
1518 localrequest_done(isc_task_t *task, isc_event_t *event) {
1519 reqarg_t *reqarg = event->ev_arg;
1520 dns_clientreqevent_t *rev =(dns_clientreqevent_t *)event;
1524 REQUIRE(event->ev_type == DNS_EVENT_CLIENTREQDONE);
1526 LOCK(&reqarg->lock);
1528 reqarg->result = rev->result;
1529 dns_client_destroyreqtrans(&reqarg->trans);
1530 isc_event_free(&event);
1532 if (!reqarg->canceled) {
1533 UNLOCK(&reqarg->lock);
1535 /* Exit from the internal event loop */
1536 isc_app_ctxsuspend(reqarg->actx);
1539 * We have already exited from the loop (due to some
1540 * unexpected event). Just clean the arg up.
1542 UNLOCK(&reqarg->lock);
1543 DESTROYLOCK(&reqarg->lock);
1544 isc_mem_put(reqarg->client->mctx, reqarg, sizeof(*reqarg));
1549 dns_client_request(dns_client_t *client, dns_message_t *qmessage,
1550 dns_message_t *rmessage, isc_sockaddr_t *server,
1551 unsigned int options, unsigned int parseoptions,
1552 dns_tsec_t *tsec, unsigned int timeout,
1553 unsigned int udptimeout, unsigned int udpretries)
1557 isc_result_t result;
1559 REQUIRE(DNS_CLIENT_VALID(client));
1560 REQUIRE(qmessage != NULL);
1561 REQUIRE(rmessage != NULL);
1563 if ((client->attributes & DNS_CLIENTATTR_OWNCTX) == 0 &&
1564 (options & DNS_CLIENTREQOPT_ALLOWRUN) == 0) {
1566 * If the client is run under application's control, we need
1567 * to create a new running (sub)environment for this
1568 * particular resolution.
1570 return (ISC_R_NOTIMPLEMENTED); /* XXXTBD */
1572 actx = client->actx;
1574 reqarg = isc_mem_get(client->mctx, sizeof(*reqarg));
1576 return (ISC_R_NOMEMORY);
1578 result = isc_mutex_init(&reqarg->lock);
1579 if (result != ISC_R_SUCCESS) {
1580 isc_mem_put(client->mctx, reqarg, sizeof(*reqarg));
1584 reqarg->actx = actx;
1585 reqarg->client = client;
1586 reqarg->trans = NULL;
1587 reqarg->canceled = ISC_FALSE;
1589 result = dns_client_startrequest(client, qmessage, rmessage, server,
1590 options, parseoptions, tsec, timeout,
1591 udptimeout, udpretries,
1592 client->task, localrequest_done,
1593 reqarg, &reqarg->trans);
1594 if (result != ISC_R_SUCCESS) {
1595 DESTROYLOCK(&reqarg->lock);
1596 isc_mem_put(client->mctx, reqarg, sizeof(*reqarg));
1601 * Start internal event loop. It blocks until the entire process
1604 result = isc_app_ctxrun(actx);
1606 LOCK(&reqarg->lock);
1607 if (result == ISC_R_SUCCESS || result == ISC_R_SUSPEND)
1608 result = reqarg->result;
1609 if (reqarg->trans != NULL) {
1611 * Unusual termination (perhaps due to signal). We need some
1612 * tricky cleanup process.
1614 reqarg->canceled = ISC_TRUE;
1615 dns_client_cancelresolve(reqarg->trans);
1617 UNLOCK(&reqarg->lock);
1619 /* reqarg will be freed in the event handler. */
1621 UNLOCK(&reqarg->lock);
1623 DESTROYLOCK(&reqarg->lock);
1624 isc_mem_put(client->mctx, reqarg, sizeof(*reqarg));
1631 dns_client_startrequest(dns_client_t *client, dns_message_t *qmessage,
1632 dns_message_t *rmessage, isc_sockaddr_t *server,
1633 unsigned int options, unsigned int parseoptions,
1634 dns_tsec_t *tsec, unsigned int timeout,
1635 unsigned int udptimeout, unsigned int udpretries,
1636 isc_task_t *task, isc_taskaction_t action, void *arg,
1637 dns_clientreqtrans_t **transp)
1639 isc_result_t result;
1640 dns_view_t *view = NULL;
1641 isc_task_t *clone = NULL;
1642 dns_clientreqevent_t *event = NULL;
1643 reqctx_t *ctx = NULL;
1644 dns_tsectype_t tsectype = dns_tsectype_none;
1648 REQUIRE(DNS_CLIENT_VALID(client));
1649 REQUIRE(qmessage != NULL);
1650 REQUIRE(rmessage != NULL);
1651 REQUIRE(transp != NULL && *transp == NULL);
1654 tsectype = dns_tsec_gettype(tsec);
1655 if (tsectype != dns_tsectype_tsig)
1656 return (ISC_R_NOTIMPLEMENTED); /* XXX */
1659 LOCK(&client->lock);
1660 result = dns_viewlist_find(&client->viewlist, DNS_CLIENTVIEW_NAME,
1661 qmessage->rdclass, &view);
1662 UNLOCK(&client->lock);
1663 if (result != ISC_R_SUCCESS)
1667 isc_task_attach(task, &clone);
1668 event = (dns_clientreqevent_t *)
1669 isc_event_allocate(client->mctx, clone,
1670 DNS_EVENT_CLIENTREQDONE,
1671 action, arg, sizeof(*event));
1672 if (event == NULL) {
1673 result = ISC_R_NOMEMORY;
1677 ctx = isc_mem_get(client->mctx, sizeof(*ctx));
1679 result = ISC_R_NOMEMORY;
1681 result = isc_mutex_init(&ctx->lock);
1682 if (result != ISC_R_SUCCESS) {
1683 isc_mem_put(client->mctx, ctx, sizeof(*ctx));
1687 if (result != ISC_R_SUCCESS)
1690 ctx->client = client;
1691 ISC_LINK_INIT(ctx, link);
1692 ctx->parseoptions = parseoptions;
1693 ctx->canceled = ISC_FALSE;
1695 ctx->event->rmessage = rmessage;
1696 ctx->tsigkey = NULL;
1698 dns_tsec_getkey(tsec, &ctx->tsigkey);
1700 ctx->magic = REQCTX_MAGIC;
1702 LOCK(&client->lock);
1703 ISC_LIST_APPEND(client->reqctxs, ctx, link);
1704 UNLOCK(&client->lock);
1706 ctx->request = NULL;
1707 result = dns_request_createvia3(view->requestmgr, qmessage, NULL,
1708 server, options, ctx->tsigkey,
1709 timeout, udptimeout, udpretries,
1710 client->task, request_done, ctx,
1712 if (result == ISC_R_SUCCESS) {
1713 dns_view_detach(&view);
1714 *transp = (dns_clientreqtrans_t *)ctx;
1715 return (ISC_R_SUCCESS);
1720 LOCK(&client->lock);
1721 ISC_LIST_UNLINK(client->reqctxs, ctx, link);
1722 UNLOCK(&client->lock);
1723 DESTROYLOCK(&ctx->lock);
1724 isc_mem_put(client->mctx, ctx, sizeof(*ctx));
1727 isc_event_free(ISC_EVENT_PTR(&event));
1728 isc_task_detach(&clone);
1729 dns_view_detach(&view);
1735 dns_client_cancelrequest(dns_clientreqtrans_t *trans) {
1738 REQUIRE(trans != NULL);
1739 ctx = (reqctx_t *)trans;
1740 REQUIRE(REQCTX_VALID(ctx));
1744 if (!ctx->canceled) {
1745 ctx->canceled = ISC_TRUE;
1746 if (ctx->request != NULL)
1747 dns_request_cancel(ctx->request);
1754 dns_client_destroyreqtrans(dns_clientreqtrans_t **transp) {
1757 dns_client_t *client;
1758 isc_boolean_t need_destroyclient = ISC_FALSE;
1760 REQUIRE(transp != NULL);
1761 ctx = (reqctx_t *)*transp;
1762 REQUIRE(REQCTX_VALID(ctx));
1763 client = ctx->client;
1764 REQUIRE(DNS_CLIENT_VALID(client));
1765 REQUIRE(ctx->event == NULL);
1766 REQUIRE(ctx->request != NULL);
1768 dns_request_destroy(&ctx->request);
1769 mctx = client->mctx;
1771 LOCK(&client->lock);
1773 INSIST(ISC_LINK_LINKED(ctx, link));
1774 ISC_LIST_UNLINK(client->reqctxs, ctx, link);
1776 if (client->references == 0 && ISC_LIST_EMPTY(client->resctxs) &&
1777 ISC_LIST_EMPTY(client->reqctxs) &&
1778 ISC_LIST_EMPTY(client->updatectxs)) {
1779 need_destroyclient = ISC_TRUE;
1782 UNLOCK(&client->lock);
1784 DESTROYLOCK(&ctx->lock);
1787 isc_mem_put(mctx, ctx, sizeof(*ctx));
1789 if (need_destroyclient)
1790 destroyclient(&client);
1796 * Dynamic update routines
1799 rcode2result(dns_rcode_t rcode) {
1800 /* XXX: isn't there a similar function? */
1802 case dns_rcode_formerr:
1803 return (DNS_R_FORMERR);
1804 case dns_rcode_servfail:
1805 return (DNS_R_SERVFAIL);
1806 case dns_rcode_nxdomain:
1807 return (DNS_R_NXDOMAIN);
1808 case dns_rcode_notimp:
1809 return (DNS_R_NOTIMP);
1810 case dns_rcode_refused:
1811 return (DNS_R_REFUSED);
1812 case dns_rcode_yxdomain:
1813 return (DNS_R_YXDOMAIN);
1814 case dns_rcode_yxrrset:
1815 return (DNS_R_YXRRSET);
1816 case dns_rcode_nxrrset:
1817 return (DNS_R_NXRRSET);
1818 case dns_rcode_notauth:
1819 return (DNS_R_NOTAUTH);
1820 case dns_rcode_notzone:
1821 return (DNS_R_NOTZONE);
1822 case dns_rcode_badvers:
1823 return (DNS_R_BADVERS);
1826 return (ISC_R_FAILURE);
1830 update_sendevent(updatectx_t *uctx, isc_result_t result) {
1833 dns_message_destroy(&uctx->updatemsg);
1834 if (uctx->tsigkey != NULL)
1835 dns_tsigkey_detach(&uctx->tsigkey);
1836 if (uctx->sig0key != NULL)
1837 dst_key_free(&uctx->sig0key);
1840 uctx->event->result = ISC_R_CANCELED;
1842 uctx->event->result = result;
1843 uctx->event->state = uctx->state;
1844 task = uctx->event->ev_sender;
1845 uctx->event->ev_sender = uctx;
1846 isc_task_sendanddetach(&task, ISC_EVENT_PTR(&uctx->event));
1850 update_done(isc_task_t *task, isc_event_t *event) {
1851 isc_result_t result;
1852 dns_requestevent_t *reqev = NULL;
1853 dns_request_t *request;
1854 dns_message_t *answer = NULL;
1855 updatectx_t *uctx = event->ev_arg;
1856 dns_client_t *client;
1857 unsigned int timeout;
1861 REQUIRE(event->ev_type == DNS_EVENT_REQUESTDONE);
1862 reqev = (dns_requestevent_t *)event;
1863 request = reqev->request;
1864 REQUIRE(UCTX_VALID(uctx));
1865 client = uctx->client;
1866 REQUIRE(DNS_CLIENT_VALID(client));
1868 result = reqev->result;
1869 if (result != ISC_R_SUCCESS)
1872 result = dns_message_create(client->mctx, DNS_MESSAGE_INTENTPARSE,
1874 if (result != ISC_R_SUCCESS)
1876 uctx->state = dns_clientupdatestate_done;
1877 result = dns_request_getresponse(request, answer,
1878 DNS_MESSAGEPARSE_PRESERVEORDER);
1879 if (result == ISC_R_SUCCESS && answer->rcode != dns_rcode_noerror)
1880 result = rcode2result(answer->rcode);
1884 dns_message_destroy(&answer);
1885 isc_event_free(&event);
1888 uctx->currentserver = ISC_LIST_NEXT(uctx->currentserver, link);
1889 dns_request_destroy(&uctx->updatereq);
1890 if (result != ISC_R_SUCCESS && !uctx->canceled &&
1891 uctx->currentserver != NULL) {
1892 dns_message_renderreset(uctx->updatemsg);
1893 dns_message_settsigkey(uctx->updatemsg, NULL);
1895 timeout = client->update_timeout / uctx->nservers;
1896 if (timeout < MIN_UPDATE_TIMEOUT)
1897 timeout = MIN_UPDATE_TIMEOUT;
1898 result = dns_request_createvia3(uctx->view->requestmgr,
1901 uctx->currentserver, 0,
1904 client->update_udptimeout,
1905 client->update_udpretries,
1909 UNLOCK(&uctx->lock);
1911 if (result == ISC_R_SUCCESS) {
1912 /* XXX: should we keep the 'done' state here? */
1913 uctx->state = dns_clientupdatestate_sent;
1917 UNLOCK(&uctx->lock);
1919 update_sendevent(uctx, result);
1923 send_update(updatectx_t *uctx) {
1924 isc_result_t result;
1925 dns_name_t *name = NULL;
1926 dns_rdataset_t *rdataset = NULL;
1927 dns_client_t *client = uctx->client;
1928 unsigned int timeout;
1930 REQUIRE(uctx->zonename != NULL && uctx->currentserver != NULL);
1932 result = dns_message_gettempname(uctx->updatemsg, &name);
1933 if (result != ISC_R_SUCCESS)
1935 dns_name_init(name, NULL);
1936 dns_name_clone(uctx->zonename, name);
1937 result = dns_message_gettemprdataset(uctx->updatemsg, &rdataset);
1938 if (result != ISC_R_SUCCESS) {
1939 dns_message_puttempname(uctx->updatemsg, &name);
1942 dns_rdataset_makequestion(rdataset, uctx->rdclass, dns_rdatatype_soa);
1943 ISC_LIST_INIT(name->list);
1944 ISC_LIST_APPEND(name->list, rdataset, link);
1945 dns_message_addname(uctx->updatemsg, name, DNS_SECTION_ZONE);
1946 if (uctx->tsigkey == NULL && uctx->sig0key != NULL) {
1947 result = dns_message_setsig0key(uctx->updatemsg,
1949 if (result != ISC_R_SUCCESS)
1952 timeout = client->update_timeout / uctx->nservers;
1953 if (timeout < MIN_UPDATE_TIMEOUT)
1954 timeout = MIN_UPDATE_TIMEOUT;
1955 result = dns_request_createvia3(uctx->view->requestmgr,
1957 NULL, uctx->currentserver, 0,
1958 uctx->tsigkey, timeout,
1959 client->update_udptimeout,
1960 client->update_udpretries,
1961 client->task, update_done, uctx,
1963 if (result == ISC_R_SUCCESS &&
1964 uctx->state == dns_clientupdatestate_prepare) {
1965 uctx->state = dns_clientupdatestate_sent;
1972 resolveaddr_done(isc_task_t *task, isc_event_t *event) {
1973 isc_result_t result;
1975 dns_rdatatype_t qtype;
1976 dns_clientresevent_t *rev = (dns_clientresevent_t *)event;
1978 dns_rdataset_t *rdataset;
1980 isc_boolean_t completed = ISC_FALSE;
1984 REQUIRE(event->ev_arg != NULL);
1985 uctx = *(updatectx_t **)event->ev_arg;
1986 REQUIRE(UCTX_VALID(uctx));
1988 if (event->ev_arg == &uctx->bp4) {
1990 qtype = dns_rdatatype_a;
1992 dns_client_destroyrestrans(&uctx->restrans);
1993 UNLOCK(&uctx->lock);
1995 INSIST(event->ev_arg == &uctx->bp6);
1997 qtype = dns_rdatatype_aaaa;
1999 dns_client_destroyrestrans(&uctx->restrans2);
2000 UNLOCK(&uctx->lock);
2003 result = rev->result;
2004 if (result != ISC_R_SUCCESS)
2007 for (name = ISC_LIST_HEAD(rev->answerlist); name != NULL;
2008 name = ISC_LIST_NEXT(name, link)) {
2009 for (rdataset = ISC_LIST_HEAD(name->list);
2011 rdataset = ISC_LIST_NEXT(rdataset, link)) {
2012 if (!dns_rdataset_isassociated(rdataset))
2014 if (rdataset->type != qtype)
2017 for (result = dns_rdataset_first(rdataset);
2018 result == ISC_R_SUCCESS;
2019 result = dns_rdataset_next(rdataset)) {
2021 dns_rdata_in_a_t rdata_a;
2022 dns_rdata_in_aaaa_t rdata_aaaa;
2025 sa = isc_mem_get(uctx->client->mctx,
2029 * If we fail to get a sockaddr,
2030 we simply move forward with the
2031 * addresses we've got so far.
2036 dns_rdata_init(&rdata);
2039 dns_rdataset_current(rdataset, &rdata);
2040 result = dns_rdata_tostruct(&rdata, &rdata_a,
2042 RUNTIME_CHECK(result == ISC_R_SUCCESS);
2043 isc_sockaddr_fromin(sa,
2046 dns_rdata_freestruct(&rdata_a);
2049 dns_rdataset_current(rdataset, &rdata);
2050 result = dns_rdata_tostruct(&rdata, &rdata_aaaa,
2052 RUNTIME_CHECK(result == ISC_R_SUCCESS);
2053 isc_sockaddr_fromin6(sa,
2054 &rdata_aaaa.in6_addr,
2056 dns_rdata_freestruct(&rdata_aaaa);
2060 ISC_LINK_INIT(sa, link);
2061 ISC_LIST_APPEND(uctx->servers, sa, link);
2068 dns_client_freeresanswer(uctx->client, &rev->answerlist);
2069 isc_event_free(&event);
2072 if (uctx->restrans == NULL && uctx->restrans2 == NULL)
2073 completed = ISC_TRUE;
2074 UNLOCK(&uctx->lock);
2077 INSIST(uctx->currentserver == NULL);
2078 uctx->currentserver = ISC_LIST_HEAD(uctx->servers);
2079 if (uctx->currentserver != NULL && !uctx->canceled)
2082 if (result == ISC_R_SUCCESS)
2083 result = ISC_R_NOTFOUND;
2084 update_sendevent(uctx, result);
2090 process_soa(updatectx_t *uctx, dns_rdataset_t *soaset, dns_name_t *soaname) {
2091 isc_result_t result;
2092 dns_rdata_t soarr = DNS_RDATA_INIT;
2093 dns_rdata_soa_t soa;
2096 result = dns_rdataset_first(soaset);
2097 if (result != ISC_R_SUCCESS)
2099 dns_rdata_init(&soarr);
2100 dns_rdataset_current(soaset, &soarr);
2101 result = dns_rdata_tostruct(&soarr, &soa, NULL);
2102 if (result != ISC_R_SUCCESS)
2105 dns_name_init(&primary, NULL);
2106 dns_name_clone(&soa.origin, &primary);
2108 if (uctx->zonename == NULL) {
2109 uctx->zonename = dns_fixedname_name(&uctx->zonefname);
2110 result = dns_name_copy(soaname, uctx->zonename, NULL);
2111 if (result != ISC_R_SUCCESS)
2115 if (uctx->currentserver != NULL)
2116 result = send_update(uctx);
2119 * Get addresses of the primary server. We don't use the ADB
2120 * feature so that we could avoid caching data.
2124 result = dns_client_startresolve(uctx->client, &primary,
2127 0, uctx->client->task,
2128 resolveaddr_done, &uctx->bp4,
2130 if (result == ISC_R_SUCCESS) {
2132 result = dns_client_startresolve(uctx->client,
2136 0, uctx->client->task,
2141 UNLOCK(&uctx->lock);
2145 dns_rdata_freestruct(&soa);
2151 receive_soa(isc_task_t *task, isc_event_t *event) {
2152 dns_requestevent_t *reqev = NULL;
2154 dns_client_t *client;
2155 isc_result_t result, eresult;
2156 dns_request_t *request;
2157 dns_message_t *rcvmsg = NULL;
2158 dns_section_t section;
2159 dns_rdataset_t *soaset = NULL;
2162 dns_message_t *soaquery = NULL;
2163 isc_sockaddr_t *addr;
2164 isc_boolean_t seencname = ISC_FALSE;
2165 isc_boolean_t droplabel = ISC_FALSE;
2167 unsigned int nlabels;
2171 REQUIRE(event->ev_type == DNS_EVENT_REQUESTDONE);
2172 reqev = (dns_requestevent_t *)event;
2173 request = reqev->request;
2174 result = eresult = reqev->result;
2176 uctx = reqev->ev_arg;
2177 client = uctx->client;
2178 soaquery = uctx->soaquery;
2179 addr = uctx->currentserver;
2180 INSIST(addr != NULL);
2182 isc_event_free(&event);
2184 if (eresult != ISC_R_SUCCESS) {
2189 result = dns_message_create(uctx->client->mctx,
2190 DNS_MESSAGE_INTENTPARSE, &rcvmsg);
2191 if (result != ISC_R_SUCCESS)
2193 result = dns_request_getresponse(request, rcvmsg,
2194 DNS_MESSAGEPARSE_PRESERVEORDER);
2196 if (result == DNS_R_TSIGERRORSET) {
2197 dns_request_t *newrequest = NULL;
2199 /* Retry SOA request without TSIG */
2200 dns_message_destroy(&rcvmsg);
2201 dns_message_renderreset(uctx->soaquery);
2202 result = dns_request_createvia3(uctx->view->requestmgr,
2203 uctx->soaquery, NULL, addr, 0,
2205 client->find_timeout * 20,
2206 client->find_timeout, 3,
2210 if (result == ISC_R_SUCCESS) {
2212 dns_request_destroy(&uctx->soareq);
2213 uctx->soareq = newrequest;
2214 UNLOCK(&uctx->lock);
2221 section = DNS_SECTION_ANSWER;
2224 if (rcvmsg->rcode != dns_rcode_noerror &&
2225 rcvmsg->rcode != dns_rcode_nxdomain) {
2226 result = rcode2result(rcvmsg->rcode);
2232 section = DNS_SECTION_ANSWER;
2234 section = DNS_SECTION_AUTHORITY;
2236 droplabel = ISC_TRUE;
2240 result = dns_message_firstname(rcvmsg, section);
2241 if (result != ISC_R_SUCCESS) {
2245 while (result == ISC_R_SUCCESS) {
2247 dns_message_currentname(rcvmsg, section, &name);
2249 result = dns_message_findtype(name, dns_rdatatype_soa, 0,
2251 if (result == ISC_R_SUCCESS)
2253 if (section == DNS_SECTION_ANSWER) {
2254 dns_rdataset_t *tset = NULL;
2255 if (dns_message_findtype(name, dns_rdatatype_cname, 0,
2256 &tset) == ISC_R_SUCCESS
2258 dns_message_findtype(name, dns_rdatatype_dname, 0,
2259 &tset) == ISC_R_SUCCESS
2262 seencname = ISC_TRUE;
2267 result = dns_message_nextname(rcvmsg, section);
2270 if (soaset == NULL && !seencname) {
2276 droplabel = ISC_TRUE;
2280 result = process_soa(uctx, soaset, name);
2284 result = dns_message_firstname(soaquery, DNS_SECTION_QUESTION);
2285 INSIST(result == ISC_R_SUCCESS);
2287 dns_message_currentname(soaquery, DNS_SECTION_QUESTION, &name);
2288 nlabels = dns_name_countlabels(name);
2290 result = DNS_R_SERVFAIL; /* is there a better error? */
2292 dns_name_init(&tname, NULL);
2293 dns_name_getlabelsequence(name, 1, nlabels - 1,
2295 dns_name_clone(&tname, name);
2296 dns_request_destroy(&request);
2298 uctx->soareq = NULL;
2299 UNLOCK(&uctx->lock);
2300 dns_message_renderreset(soaquery);
2301 dns_message_settsigkey(soaquery, NULL);
2302 result = dns_request_createvia3(uctx->view->requestmgr,
2304 uctx->currentserver, 0,
2306 client->find_timeout *
2308 client->find_timeout,
2315 if (!droplabel || result != ISC_R_SUCCESS) {
2316 dns_message_destroy(&uctx->soaquery);
2318 dns_request_destroy(&uctx->soareq);
2319 UNLOCK(&uctx->lock);
2323 dns_message_destroy(&rcvmsg);
2325 if (result != ISC_R_SUCCESS)
2326 update_sendevent(uctx, result);
2330 request_soa(updatectx_t *uctx) {
2331 isc_result_t result;
2332 dns_message_t *soaquery = uctx->soaquery;
2333 dns_name_t *name = NULL;
2334 dns_rdataset_t *rdataset = NULL;
2336 if (soaquery == NULL) {
2337 result = dns_message_create(uctx->client->mctx,
2338 DNS_MESSAGE_INTENTRENDER,
2340 if (result != ISC_R_SUCCESS)
2343 soaquery->flags |= DNS_MESSAGEFLAG_RD;
2344 result = dns_message_gettempname(soaquery, &name);
2345 if (result != ISC_R_SUCCESS)
2347 result = dns_message_gettemprdataset(soaquery, &rdataset);
2348 if (result != ISC_R_SUCCESS)
2350 dns_rdataset_makequestion(rdataset, uctx->rdclass, dns_rdatatype_soa);
2351 dns_name_clone(uctx->firstname, name);
2352 ISC_LIST_APPEND(name->list, rdataset, link);
2353 dns_message_addname(soaquery, name, DNS_SECTION_QUESTION);
2357 result = dns_request_createvia3(uctx->view->requestmgr,
2358 soaquery, NULL, uctx->currentserver, 0,
2360 uctx->client->find_timeout * 20,
2361 uctx->client->find_timeout, 3,
2362 uctx->client->task, receive_soa, uctx,
2364 if (result == ISC_R_SUCCESS) {
2365 uctx->soaquery = soaquery;
2366 return (ISC_R_SUCCESS);
2370 if (rdataset != NULL) {
2371 ISC_LIST_UNLINK(name->list, rdataset, link); /* for safety */
2372 dns_message_puttemprdataset(soaquery, &rdataset);
2375 dns_message_puttempname(soaquery, &name);
2376 dns_message_destroy(&soaquery);
2382 resolvesoa_done(isc_task_t *task, isc_event_t *event) {
2383 dns_clientresevent_t *rev = (dns_clientresevent_t *)event;
2385 dns_name_t *name, tname;
2386 dns_rdataset_t *rdataset = NULL;
2387 isc_result_t result = rev->result;
2388 unsigned int nlabels;
2392 uctx = event->ev_arg;
2393 REQUIRE(UCTX_VALID(uctx));
2396 dns_client_destroyrestrans(&uctx->restrans);
2397 UNLOCK(&uctx->lock);
2399 uctx = event->ev_arg;
2400 if (result != ISC_R_SUCCESS &&
2401 result != DNS_R_NCACHENXDOMAIN &&
2402 result != DNS_R_NCACHENXRRSET) {
2403 /* XXX: what about DNSSEC failure? */
2407 for (name = ISC_LIST_HEAD(rev->answerlist); name != NULL;
2408 name = ISC_LIST_NEXT(name, link)) {
2409 for (rdataset = ISC_LIST_HEAD(name->list);
2411 rdataset = ISC_LIST_NEXT(rdataset, link)) {
2412 if (dns_rdataset_isassociated(rdataset) &&
2413 rdataset->type == dns_rdatatype_soa)
2418 if (rdataset == NULL) {
2419 /* Drop one label and retry resolution. */
2420 nlabels = dns_name_countlabels(&uctx->soaqname);
2422 result = DNS_R_SERVFAIL; /* is there a better error? */
2425 dns_name_init(&tname, NULL);
2426 dns_name_getlabelsequence(&uctx->soaqname, 1, nlabels - 1,
2428 dns_name_clone(&tname, &uctx->soaqname);
2430 result = dns_client_startresolve(uctx->client, &uctx->soaqname,
2432 dns_rdatatype_soa, 0,
2434 resolvesoa_done, uctx,
2437 result = process_soa(uctx, rdataset, &uctx->soaqname);
2440 dns_client_freeresanswer(uctx->client, &rev->answerlist);
2441 isc_event_free(&event);
2443 if (result != ISC_R_SUCCESS)
2444 update_sendevent(uctx, result);
2448 copy_name(isc_mem_t *mctx, dns_message_t *msg, dns_name_t *name,
2449 dns_name_t **newnamep)
2451 isc_result_t result;
2452 dns_name_t *newname = NULL;
2454 isc_buffer_t *namebuf = NULL, *rdatabuf = NULL;
2455 dns_rdatalist_t *rdatalist;
2456 dns_rdataset_t *rdataset, *newrdataset;
2457 dns_rdata_t rdata = DNS_RDATA_INIT, *newrdata;
2459 result = dns_message_gettempname(msg, &newname);
2460 if (result != ISC_R_SUCCESS)
2462 result = isc_buffer_allocate(mctx, &namebuf, DNS_NAME_MAXWIRE);
2463 if (result != ISC_R_SUCCESS)
2465 dns_name_init(newname, NULL);
2466 dns_name_setbuffer(newname, namebuf);
2467 dns_message_takebuffer(msg, &namebuf);
2468 result = dns_name_copy(name, newname, NULL);
2469 if (result != ISC_R_SUCCESS)
2472 for (rdataset = ISC_LIST_HEAD(name->list); rdataset != NULL;
2473 rdataset = ISC_LIST_NEXT(rdataset, link)) {
2475 result = dns_message_gettemprdatalist(msg, &rdatalist);
2476 if (result != ISC_R_SUCCESS)
2478 dns_rdatalist_init(rdatalist);
2479 rdatalist->type = rdataset->type;
2480 rdatalist->rdclass = rdataset->rdclass;
2481 rdatalist->covers = rdataset->covers;
2482 rdatalist->ttl = rdataset->ttl;
2484 result = dns_rdataset_first(rdataset);
2485 while (result == ISC_R_SUCCESS) {
2486 dns_rdata_reset(&rdata);
2487 dns_rdataset_current(rdataset, &rdata);
2490 result = dns_message_gettemprdata(msg, &newrdata);
2491 if (result != ISC_R_SUCCESS)
2493 dns_rdata_toregion(&rdata, &r);
2495 result = isc_buffer_allocate(mctx, &rdatabuf,
2497 if (result != ISC_R_SUCCESS)
2499 isc_buffer_putmem(rdatabuf, r.base, r.length);
2500 isc_buffer_usedregion(rdatabuf, &r);
2501 dns_rdata_init(newrdata);
2502 dns_rdata_fromregion(newrdata, rdata.rdclass,
2504 newrdata->flags = rdata.flags;
2506 ISC_LIST_APPEND(rdatalist->rdata, newrdata, link);
2507 dns_message_takebuffer(msg, &rdatabuf);
2509 result = dns_rdataset_next(rdataset);
2513 result = dns_message_gettemprdataset(msg, &newrdataset);
2514 if (result != ISC_R_SUCCESS)
2516 dns_rdataset_init(newrdataset);
2517 dns_rdatalist_tordataset(rdatalist, newrdataset);
2519 ISC_LIST_APPEND(newname->list, newrdataset, link);
2522 *newnamep = newname;
2524 return (ISC_R_SUCCESS);
2527 dns_message_puttempname(msg, &newname);
2534 internal_update_callback(isc_task_t *task, isc_event_t *event) {
2535 updatearg_t *uarg = event->ev_arg;
2536 dns_clientupdateevent_t *uev = (dns_clientupdateevent_t *)event;
2542 uarg->result = uev->result;
2544 dns_client_destroyupdatetrans(&uarg->trans);
2545 isc_event_free(&event);
2547 if (!uarg->canceled) {
2548 UNLOCK(&uarg->lock);
2550 /* Exit from the internal event loop */
2551 isc_app_ctxsuspend(uarg->actx);
2554 * We have already exited from the loop (due to some
2555 * unexpected event). Just clean the arg up.
2557 UNLOCK(&uarg->lock);
2558 DESTROYLOCK(&uarg->lock);
2559 isc_mem_put(uarg->client->mctx, uarg, sizeof(*uarg));
2564 dns_client_update(dns_client_t *client, dns_rdataclass_t rdclass,
2565 dns_name_t *zonename, dns_namelist_t *prerequisites,
2566 dns_namelist_t *updates, isc_sockaddrlist_t *servers,
2567 dns_tsec_t *tsec, unsigned int options)
2569 isc_result_t result;
2573 REQUIRE(DNS_CLIENT_VALID(client));
2575 if ((client->attributes & DNS_CLIENTATTR_OWNCTX) == 0 &&
2576 (options & DNS_CLIENTRESOPT_ALLOWRUN) == 0) {
2578 * If the client is run under application's control, we need
2579 * to create a new running (sub)environment for this
2580 * particular resolution.
2582 return (ISC_R_NOTIMPLEMENTED); /* XXXTBD */
2584 actx = client->actx;
2586 uarg = isc_mem_get(client->mctx, sizeof(*uarg));
2588 return (ISC_R_NOMEMORY);
2590 result = isc_mutex_init(&uarg->lock);
2591 if (result != ISC_R_SUCCESS) {
2592 isc_mem_put(client->mctx, uarg, sizeof(*uarg));
2597 uarg->client = client;
2598 uarg->result = ISC_R_FAILURE;
2600 uarg->canceled = ISC_FALSE;
2602 result = dns_client_startupdate(client, rdclass, zonename,
2603 prerequisites, updates, servers,
2604 tsec, options, client->task,
2605 internal_update_callback, uarg,
2607 if (result != ISC_R_SUCCESS) {
2608 DESTROYLOCK(&uarg->lock);
2609 isc_mem_put(client->mctx, uarg, sizeof(*uarg));
2614 * Start internal event loop. It blocks until the entire process
2617 result = isc_app_ctxrun(actx);
2620 if (result == ISC_R_SUCCESS || result == ISC_R_SUSPEND)
2621 result = uarg->result;
2623 if (uarg->trans != NULL) {
2625 * Unusual termination (perhaps due to signal). We need some
2626 * tricky cleanup process.
2628 uarg->canceled = ISC_TRUE;
2629 dns_client_cancelupdate(uarg->trans);
2631 UNLOCK(&uarg->lock);
2633 /* uarg will be freed in the event handler. */
2635 UNLOCK(&uarg->lock);
2637 DESTROYLOCK(&uarg->lock);
2638 isc_mem_put(client->mctx, uarg, sizeof(*uarg));
2645 dns_client_startupdate(dns_client_t *client, dns_rdataclass_t rdclass,
2646 dns_name_t *zonename, dns_namelist_t *prerequisites,
2647 dns_namelist_t *updates, isc_sockaddrlist_t *servers,
2648 dns_tsec_t *tsec, unsigned int options,
2649 isc_task_t *task, isc_taskaction_t action, void *arg,
2650 dns_clientupdatetrans_t **transp)
2652 dns_view_t *view = NULL;
2653 isc_result_t result;
2654 dns_name_t *name, *newname;
2656 isc_task_t *clone = NULL;
2657 dns_section_t section = DNS_SECTION_UPDATE;
2658 isc_sockaddr_t *server, *sa = NULL;
2659 dns_tsectype_t tsectype = dns_tsectype_none;
2663 REQUIRE(DNS_CLIENT_VALID(client));
2664 REQUIRE(transp != NULL && *transp == NULL);
2665 REQUIRE(updates != NULL);
2666 REQUIRE(task != NULL);
2669 tsectype = dns_tsec_gettype(tsec);
2670 if (tsectype != dns_tsectype_tsig)
2671 return (ISC_R_NOTIMPLEMENTED); /* XXX */
2674 LOCK(&client->lock);
2675 result = dns_viewlist_find(&client->viewlist, DNS_CLIENTVIEW_NAME,
2677 UNLOCK(&client->lock);
2678 if (result != ISC_R_SUCCESS)
2681 /* Create a context and prepare some resources */
2682 uctx = isc_mem_get(client->mctx, sizeof(*uctx));
2684 dns_view_detach(&view);
2685 return (ISC_R_NOMEMORY);
2687 result = isc_mutex_init(&uctx->lock);
2688 if (result != ISC_R_SUCCESS) {
2689 dns_view_detach(&view);
2690 isc_mem_put(client->mctx, uctx, sizeof(*uctx));
2691 return (ISC_R_NOMEMORY);
2694 isc_task_attach(task, &clone);
2695 uctx->client = client;
2696 ISC_LINK_INIT(uctx, link);
2697 uctx->state = dns_clientupdatestate_prepare;
2699 uctx->rdclass = rdclass;
2700 uctx->canceled = ISC_FALSE;
2701 uctx->updatemsg = NULL;
2702 uctx->soaquery = NULL;
2703 uctx->updatereq = NULL;
2704 uctx->restrans = NULL;
2705 uctx->restrans2 = NULL;
2708 uctx->soareq = NULL;
2710 uctx->tsigkey = NULL;
2711 uctx->sig0key = NULL;
2712 uctx->zonename = NULL;
2713 dns_name_init(&uctx->soaqname, NULL);
2714 ISC_LIST_INIT(uctx->servers);
2716 uctx->currentserver = NULL;
2717 dns_fixedname_init(&uctx->zonefname);
2719 dns_tsec_getkey(tsec, &uctx->tsigkey);
2720 uctx->event = (dns_clientupdateevent_t *)
2721 isc_event_allocate(client->mctx, clone, DNS_EVENT_UPDATEDONE,
2722 action, arg, sizeof(*uctx->event));
2723 if (uctx->event == NULL)
2725 if (zonename != NULL) {
2726 uctx->zonename = dns_fixedname_name(&uctx->zonefname);
2727 result = dns_name_copy(zonename, uctx->zonename, NULL);
2729 if (servers != NULL) {
2730 for (server = ISC_LIST_HEAD(*servers);
2732 server = ISC_LIST_NEXT(server, link)) {
2733 sa = isc_mem_get(client->mctx, sizeof(*sa));
2736 sa->type = server->type;
2737 sa->length = server->length;
2738 ISC_LINK_INIT(sa, link);
2739 ISC_LIST_APPEND(uctx->servers, sa, link);
2740 if (uctx->currentserver == NULL)
2741 uctx->currentserver = sa;
2746 /* Make update message */
2747 result = dns_message_create(client->mctx, DNS_MESSAGE_INTENTRENDER,
2749 if (result != ISC_R_SUCCESS)
2751 uctx->updatemsg->opcode = dns_opcode_update;
2753 if (prerequisites != NULL) {
2754 for (name = ISC_LIST_HEAD(*prerequisites); name != NULL;
2755 name = ISC_LIST_NEXT(name, link)) {
2757 result = copy_name(client->mctx, uctx->updatemsg,
2759 if (result != ISC_R_SUCCESS)
2761 dns_message_addname(uctx->updatemsg, newname,
2762 DNS_SECTION_PREREQUISITE);
2766 for (name = ISC_LIST_HEAD(*updates); name != NULL;
2767 name = ISC_LIST_NEXT(name, link)) {
2769 result = copy_name(client->mctx, uctx->updatemsg, name,
2771 if (result != ISC_R_SUCCESS)
2773 dns_message_addname(uctx->updatemsg, newname,
2774 DNS_SECTION_UPDATE);
2777 uctx->firstname = NULL;
2778 result = dns_message_firstname(uctx->updatemsg, section);
2779 if (result == ISC_R_NOMORE) {
2780 section = DNS_SECTION_PREREQUISITE;
2781 result = dns_message_firstname(uctx->updatemsg, section);
2783 if (result != ISC_R_SUCCESS)
2785 dns_message_currentname(uctx->updatemsg, section, &uctx->firstname);
2787 uctx->magic = UCTX_MAGIC;
2789 LOCK(&client->lock);
2790 ISC_LIST_APPEND(client->updatectxs, uctx, link);
2791 UNLOCK(&client->lock);
2793 if (uctx->zonename != NULL && uctx->currentserver != NULL) {
2794 result = send_update(uctx);
2795 if (result != ISC_R_SUCCESS)
2797 } else if (uctx->currentserver != NULL) {
2798 result = request_soa(uctx);
2799 if (result != ISC_R_SUCCESS)
2802 dns_name_clone(uctx->firstname, &uctx->soaqname);
2803 result = dns_client_startresolve(uctx->client, &uctx->soaqname,
2805 dns_rdatatype_soa, 0,
2806 client->task, resolvesoa_done,
2807 uctx, &uctx->restrans);
2808 if (result != ISC_R_SUCCESS)
2812 *transp = (dns_clientupdatetrans_t *)uctx;
2814 return (ISC_R_SUCCESS);
2817 if (ISC_LINK_LINKED(uctx, link)) {
2818 LOCK(&client->lock);
2819 ISC_LIST_UNLINK(client->updatectxs, uctx, link);
2820 UNLOCK(&client->lock);
2822 if (uctx->updatemsg != NULL)
2823 dns_message_destroy(&uctx->updatemsg);
2824 while ((sa = ISC_LIST_HEAD(uctx->servers)) != NULL) {
2825 ISC_LIST_UNLINK(uctx->servers, sa, link);
2826 isc_mem_put(client->mctx, sa, sizeof(*sa));
2828 if (uctx->event != NULL)
2829 isc_event_free(ISC_EVENT_PTR(&uctx->event));
2830 if (uctx->tsigkey != NULL)
2831 dns_tsigkey_detach(&uctx->tsigkey);
2832 isc_task_detach(&clone);
2833 DESTROYLOCK(&uctx->lock);
2835 isc_mem_put(client->mctx, uctx, sizeof(*uctx));
2836 dns_view_detach(&view);
2842 dns_client_cancelupdate(dns_clientupdatetrans_t *trans) {
2845 REQUIRE(trans != NULL);
2846 uctx = (updatectx_t *)trans;
2847 REQUIRE(UCTX_VALID(uctx));
2851 if (!uctx->canceled) {
2852 uctx->canceled = ISC_TRUE;
2853 if (uctx->updatereq != NULL)
2854 dns_request_cancel(uctx->updatereq);
2855 if (uctx->soareq != NULL)
2856 dns_request_cancel(uctx->soareq);
2857 if (uctx->restrans != NULL)
2858 dns_client_cancelresolve(uctx->restrans);
2859 if (uctx->restrans2 != NULL)
2860 dns_client_cancelresolve(uctx->restrans2);
2863 UNLOCK(&uctx->lock);
2867 dns_client_destroyupdatetrans(dns_clientupdatetrans_t **transp) {
2870 dns_client_t *client;
2871 isc_boolean_t need_destroyclient = ISC_FALSE;
2874 REQUIRE(transp != NULL);
2875 uctx = (updatectx_t *)*transp;
2876 REQUIRE(UCTX_VALID(uctx));
2877 client = uctx->client;
2878 REQUIRE(DNS_CLIENT_VALID(client));
2879 REQUIRE(uctx->updatereq == NULL && uctx->updatemsg == NULL &&
2880 uctx->soareq == NULL && uctx->soaquery == NULL &&
2881 uctx->event == NULL && uctx->tsigkey == NULL &&
2882 uctx->sig0key == NULL);
2884 mctx = client->mctx;
2885 dns_view_detach(&uctx->view);
2886 while ((sa = ISC_LIST_HEAD(uctx->servers)) != NULL) {
2887 ISC_LIST_UNLINK(uctx->servers, sa, link);
2888 isc_mem_put(mctx, sa, sizeof(*sa));
2891 LOCK(&client->lock);
2893 INSIST(ISC_LINK_LINKED(uctx, link));
2894 ISC_LIST_UNLINK(client->updatectxs, uctx, link);
2896 if (client->references == 0 && ISC_LIST_EMPTY(client->resctxs) &&
2897 ISC_LIST_EMPTY(client->reqctxs) &&
2898 ISC_LIST_EMPTY(client->updatectxs))
2899 need_destroyclient = ISC_TRUE;
2901 UNLOCK(&client->lock);
2903 DESTROYLOCK(&uctx->lock);
2906 isc_mem_put(mctx, uctx, sizeof(*uctx));
2908 if (need_destroyclient)
2909 destroyclient(&client);
2915 dns_client_mctx(dns_client_t *client) {
2917 REQUIRE(DNS_CLIENT_VALID(client));
2918 return (client->mctx);
2922 isc_buffer_t buffer;
2923 dns_rdataset_t rdataset;
2924 dns_rdatalist_t rdatalist;
2928 unsigned char data[FLEXIBLE_ARRAY_MEMBER];
2929 } dns_client_updaterec_t;
2932 dns_client_updaterec(dns_client_updateop_t op, dns_name_t *owner,
2933 dns_rdatatype_t type, dns_rdata_t *source,
2934 dns_ttl_t ttl, dns_name_t *target,
2935 dns_rdataset_t *rdataset, dns_rdatalist_t *rdatalist,
2936 dns_rdata_t *rdata, isc_mem_t *mctx)
2938 dns_client_updaterec_t *updaterec = NULL;
2939 size_t size = offsetof(dns_client_updaterec_t, data);
2941 REQUIRE(op < updateop_max);
2942 REQUIRE(owner != NULL);
2943 REQUIRE((rdataset != NULL && rdatalist != NULL && rdata != NULL) ||
2944 (rdataset == NULL && rdatalist == NULL && rdata == NULL &&
2946 if (op == updateop_add)
2947 REQUIRE(source != NULL);
2948 if (source != NULL) {
2949 REQUIRE(source->type == type);
2950 REQUIRE(op == updateop_add || op == updateop_delete ||
2951 op == updateop_exist);
2954 size += owner->length;
2956 size += source->length;
2958 if (rdataset == NULL) {
2959 updaterec = isc_mem_get(mctx, size);
2960 if (updaterec == NULL)
2961 return (ISC_R_NOMEMORY);
2962 rdataset = &updaterec->rdataset;
2963 rdatalist = &updaterec->rdatalist;
2964 rdata = &updaterec->rdata;
2965 dns_rdataset_init(rdataset);
2966 dns_rdatalist_init(&updaterec->rdatalist);
2967 dns_rdata_init(&updaterec->rdata);
2968 isc_buffer_init(&updaterec->buffer, updaterec->data,
2969 size - offsetof(dns_client_updaterec_t, data));
2970 dns_name_copy(owner, target, &updaterec->buffer);
2971 if (source != NULL) {
2973 dns_rdata_clone(source, rdata);
2974 dns_rdata_toregion(rdata, &r);
2975 rdata->data = isc_buffer_used(&updaterec->buffer);
2976 isc_buffer_copyregion(&updaterec->buffer, &r);
2978 updaterec->mctx = NULL;
2979 isc_mem_attach(mctx, &updaterec->mctx);
2980 } else if (source != NULL)
2981 dns_rdata_clone(source, rdata);
2986 case updateop_delete:
2987 if (source != NULL) {
2989 dns_rdata_makedelete(rdata);
2991 dns_rdata_deleterrset(rdata, type);
2993 case updateop_notexist:
2994 dns_rdata_notexist(rdata, type);
2996 case updateop_exist:
2997 if (source == NULL) {
2999 dns_rdata_exists(rdata, type);
3007 rdatalist->type = rdata->type;
3008 rdatalist->rdclass = rdata->rdclass;
3009 if (source != NULL) {
3010 rdatalist->covers = dns_rdata_covers(rdata);
3011 rdatalist->ttl = ttl;
3013 ISC_LIST_APPEND(rdatalist->rdata, rdata, link);
3014 dns_rdatalist_tordataset(rdatalist, rdataset);
3015 ISC_LIST_APPEND(target->list, rdataset, link);
3016 if (updaterec != NULL) {
3017 target->attributes |= DNS_NAMEATTR_HASUPDATEREC;
3018 dns_name_setbuffer(target, &updaterec->buffer);
3020 if (op == updateop_add || op == updateop_delete)
3021 target->attributes |= DNS_NAMEATTR_UPDATE;
3023 target->attributes |= DNS_NAMEATTR_PREREQUISITE;
3024 return (ISC_R_SUCCESS);
3028 dns_client_freeupdate(dns_name_t **namep) {
3029 dns_client_updaterec_t *updaterec;
3030 dns_rdatalist_t *rdatalist;
3031 dns_rdataset_t *rdataset;
3035 REQUIRE(namep != NULL && *namep != NULL);
3038 for (rdataset = ISC_LIST_HEAD(name->list);
3040 rdataset = ISC_LIST_HEAD(name->list)) {
3041 ISC_LIST_UNLINK(name->list, rdataset, link);
3043 dns_rdatalist_fromrdataset(rdataset, &rdatalist);
3044 if (rdatalist == NULL) {
3045 dns_rdataset_disassociate(rdataset);
3048 for (rdata = ISC_LIST_HEAD(rdatalist->rdata);
3050 rdata = ISC_LIST_HEAD(rdatalist->rdata))
3051 ISC_LIST_UNLINK(rdatalist->rdata, rdata, link);
3052 dns_rdataset_disassociate(rdataset);
3055 if ((name->attributes & DNS_NAMEATTR_HASUPDATEREC) != 0) {
3056 updaterec = (dns_client_updaterec_t *)name->buffer;
3057 INSIST(updaterec != NULL);
3058 isc_mem_putanddetach(&updaterec->mctx, updaterec,