2 * Copyright (C) 2009-2013, 2015 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.
23 #include <isc/mutex.h>
25 #include <isc/sockaddr.h>
26 #include <isc/socket.h>
28 #include <isc/timer.h>
32 #include <dns/client.h>
34 #include <dns/dispatch.h>
35 #include <dns/events.h>
36 #include <dns/forward.h>
37 #include <dns/keytable.h>
38 #include <dns/message.h>
40 #include <dns/rdata.h>
41 #include <dns/rdatalist.h>
42 #include <dns/rdataset.h>
43 #include <dns/rdatatype.h>
44 #include <dns/rdatasetiter.h>
45 #include <dns/rdatastruct.h>
46 #include <dns/request.h>
47 #include <dns/resolver.h>
48 #include <dns/result.h>
55 #define DNS_CLIENT_MAGIC ISC_MAGIC('D', 'N', 'S', 'c')
56 #define DNS_CLIENT_VALID(c) ISC_MAGIC_VALID(c, DNS_CLIENT_MAGIC)
58 #define RCTX_MAGIC ISC_MAGIC('R', 'c', 't', 'x')
59 #define RCTX_VALID(c) ISC_MAGIC_VALID(c, RCTX_MAGIC)
61 #define REQCTX_MAGIC ISC_MAGIC('R', 'q', 'c', 'x')
62 #define REQCTX_VALID(c) ISC_MAGIC_VALID(c, REQCTX_MAGIC)
64 #define UCTX_MAGIC ISC_MAGIC('U', 'c', 't', 'x')
65 #define UCTX_VALID(c) ISC_MAGIC_VALID(c, UCTX_MAGIC)
67 #define MAX_RESTARTS 16
75 unsigned int attributes;
79 isc_taskmgr_t *taskmgr;
81 isc_socketmgr_t *socketmgr;
82 isc_timermgr_t *timermgr;
83 dns_dispatchmgr_t *dispatchmgr;
84 dns_dispatch_t *dispatchv4;
85 dns_dispatch_t *dispatchv6;
87 unsigned int update_timeout;
88 unsigned int update_udptimeout;
89 unsigned int update_udpretries;
90 unsigned int find_timeout;
91 unsigned int find_udpretries;
94 unsigned int references;
95 dns_viewlist_t viewlist;
96 ISC_LIST(struct resctx) resctxs;
97 ISC_LIST(struct reqctx) reqctxs;
98 ISC_LIST(struct updatectx) updatectxs;
102 * Timeout/retry constants for dynamic update borrowed from nsupdate
104 #define DEF_UPDATE_TIMEOUT 300
105 #define MIN_UPDATE_TIMEOUT 30
106 #define DEF_UPDATE_UDPTIMEOUT 3
107 #define DEF_UPDATE_UDPRETRIES 3
109 #define DEF_FIND_TIMEOUT 5
110 #define DEF_FIND_UDPRETRIES 3
112 #define DNS_CLIENTATTR_OWNCTX 0x01
114 #define DNS_CLIENTVIEW_NAME "dnsclient"
117 * Internal state for a single name resolution procedure
119 typedef struct resctx {
123 dns_client_t *client;
124 isc_boolean_t want_dnssec;
127 ISC_LINK(struct resctx) link;
130 unsigned int restarts;
131 dns_fixedname_t name;
132 dns_rdatatype_t type;
134 dns_namelist_t namelist;
136 dns_clientresevent_t *event;
137 isc_boolean_t canceled;
138 dns_rdataset_t *rdataset;
139 dns_rdataset_t *sigrdataset;
143 * Argument of an internal event for synchronous name resolution.
145 typedef struct resarg {
148 dns_client_t *client;
153 isc_result_t vresult;
154 dns_namelist_t *namelist;
155 dns_clientrestrans_t *trans;
156 isc_boolean_t canceled;
160 * Internal state for a single DNS request
162 typedef struct reqctx {
166 dns_client_t *client;
167 unsigned int parseoptions;
170 ISC_LINK(struct reqctx) link;
171 isc_boolean_t canceled;
172 dns_tsigkey_t *tsigkey;
173 dns_request_t *request;
174 dns_clientreqevent_t *event;
178 * Argument of an internal event for synchronous DNS request.
180 typedef struct reqarg {
183 dns_client_t *client;
188 dns_clientreqtrans_t *trans;
189 isc_boolean_t canceled;
193 * Argument of an internal event for synchronous name resolution.
195 typedef struct updatearg {
198 dns_client_t *client;
203 dns_clientupdatetrans_t *trans;
204 isc_boolean_t canceled;
208 * Internal state for a single dynamic update procedure
210 typedef struct updatectx {
214 dns_client_t *client;
217 dns_request_t *updatereq;
218 dns_request_t *soareq;
219 dns_clientrestrans_t *restrans;
220 dns_clientrestrans_t *restrans2;
221 isc_boolean_t canceled;
224 ISC_LINK(struct updatectx) link;
225 dns_clientupdatestate_t state;
226 dns_rdataclass_t rdclass;
228 dns_message_t *updatemsg;
229 dns_message_t *soaquery;
230 dns_clientupdateevent_t *event;
231 dns_tsigkey_t *tsigkey;
233 dns_name_t *firstname;
235 dns_fixedname_t zonefname;
236 dns_name_t *zonename;
237 isc_sockaddrlist_t servers;
238 unsigned int nservers;
239 isc_sockaddr_t *currentserver;
240 struct updatectx *bp4;
241 struct updatectx *bp6;
244 static isc_result_t request_soa(updatectx_t *uctx);
245 static void client_resfind(resctx_t *rctx, dns_fetchevent_t *event);
246 static isc_result_t send_update(updatectx_t *uctx);
249 getudpdispatch(int family, dns_dispatchmgr_t *dispatchmgr,
250 isc_socketmgr_t *socketmgr, isc_taskmgr_t *taskmgr,
251 isc_boolean_t is_shared, dns_dispatch_t **dispp,
252 isc_sockaddr_t *localaddr)
254 unsigned int attrs, attrmask;
255 dns_dispatch_t *disp;
256 unsigned buffersize, maxbuffers, maxrequests, buckets, increment;
258 isc_sockaddr_t anyaddr;
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 if (localaddr == NULL) {
279 localaddr = &anyaddr;
280 isc_sockaddr_anyofpf(localaddr, family);
284 maxbuffers = is_shared ? 1000 : 8;
286 buckets = is_shared ? 16411 : 3;
287 increment = is_shared ? 16433 : 5;
290 result = dns_dispatch_getudp(dispatchmgr, socketmgr,
292 buffersize, maxbuffers, maxrequests,
294 attrs, attrmask, &disp);
295 if (result == ISC_R_SUCCESS)
302 dns_client_createview(isc_mem_t *mctx, dns_rdataclass_t rdclass,
303 unsigned int options, isc_taskmgr_t *taskmgr,
304 unsigned int ntasks, isc_socketmgr_t *socketmgr,
305 isc_timermgr_t *timermgr, dns_dispatchmgr_t *dispatchmgr,
306 dns_dispatch_t *dispatchv4, dns_dispatch_t *dispatchv6,
310 dns_view_t *view = NULL;
313 result = dns_view_create(mctx, rdclass, DNS_CLIENTVIEW_NAME, &view);
314 if (result != ISC_R_SUCCESS)
317 /* Initialize view security roots */
318 result = dns_view_initsecroots(view, mctx);
319 if (result != ISC_R_SUCCESS) {
320 dns_view_detach(&view);
324 result = dns_view_createresolver(view, taskmgr, ntasks, 1, socketmgr,
325 timermgr, 0, dispatchmgr,
326 dispatchv4, dispatchv6);
327 if (result != ISC_R_SUCCESS) {
328 dns_view_detach(&view);
334 * XXX: it may be better if specific DB implementations can be
335 * specified via some configuration knob.
337 if ((options & DNS_CLIENTCREATEOPT_USECACHE) != 0)
341 result = dns_db_create(mctx, dbtype, dns_rootname, dns_dbtype_cache,
342 rdclass, 0, NULL, &view->cachedb);
343 if (result != ISC_R_SUCCESS) {
344 dns_view_detach(&view);
349 return (ISC_R_SUCCESS);
353 dns_client_create(dns_client_t **clientp, unsigned int options) {
355 isc_mem_t *mctx = NULL;
356 isc_appctx_t *actx = NULL;
357 isc_taskmgr_t *taskmgr = NULL;
358 isc_socketmgr_t *socketmgr = NULL;
359 isc_timermgr_t *timermgr = NULL;
361 /* XXXMPA add debug logging support */
362 isc_log_t *lctx = NULL;
363 isc_logconfig_t *logconfig = NULL;
364 unsigned int logdebuglevel = 0;
367 result = isc_mem_create(0, 0, &mctx);
368 if (result != ISC_R_SUCCESS)
370 result = isc_appctx_create(mctx, &actx);
371 if (result != ISC_R_SUCCESS)
373 result = isc_app_ctxstart(actx);
374 if (result != ISC_R_SUCCESS)
376 result = isc_taskmgr_createinctx(mctx, actx, 1, 0, &taskmgr);
377 if (result != ISC_R_SUCCESS)
379 result = isc_socketmgr_createinctx(mctx, actx, &socketmgr);
380 if (result != ISC_R_SUCCESS)
382 result = isc_timermgr_createinctx(mctx, actx, &timermgr);
383 if (result != ISC_R_SUCCESS)
386 result = isc_log_create(mctx, &lctx, &logconfig);
387 if (result != ISC_R_SUCCESS)
389 isc_log_setcontext(lctx);
391 dns_log_setcontext(lctx);
392 result = isc_log_usechannel(logconfig, "default_debug", NULL, NULL);
393 if (result != ISC_R_SUCCESS)
395 isc_log_setdebuglevel(lctx, logdebuglevel);
397 result = dns_client_createx(mctx, actx, taskmgr, socketmgr, timermgr,
399 if (result != ISC_R_SUCCESS)
402 (*clientp)->attributes |= DNS_CLIENTATTR_OWNCTX;
404 /* client has its own reference to mctx, so we can detach it here */
405 isc_mem_detach(&mctx);
407 return (ISC_R_SUCCESS);
411 isc_taskmgr_destroy(&taskmgr);
412 if (timermgr != NULL)
413 isc_timermgr_destroy(&timermgr);
414 if (socketmgr != NULL)
415 isc_socketmgr_destroy(&socketmgr);
417 isc_appctx_destroy(&actx);
418 isc_mem_detach(&mctx);
424 dns_client_createx(isc_mem_t *mctx, isc_appctx_t *actx, isc_taskmgr_t *taskmgr,
425 isc_socketmgr_t *socketmgr, isc_timermgr_t *timermgr,
426 unsigned int options, dns_client_t **clientp)
429 result = dns_client_createx2(mctx, actx, taskmgr, socketmgr, timermgr,
430 options, clientp, NULL, NULL);
435 dns_client_createx2(isc_mem_t *mctx, isc_appctx_t *actx,
436 isc_taskmgr_t *taskmgr, isc_socketmgr_t *socketmgr,
437 isc_timermgr_t *timermgr, unsigned int options,
438 dns_client_t **clientp, isc_sockaddr_t *localaddr4,
439 isc_sockaddr_t *localaddr6)
441 dns_client_t *client;
443 dns_dispatchmgr_t *dispatchmgr = NULL;
444 dns_dispatch_t *dispatchv4 = NULL;
445 dns_dispatch_t *dispatchv6 = NULL;
446 dns_view_t *view = NULL;
448 REQUIRE(mctx != NULL);
449 REQUIRE(taskmgr != NULL);
450 REQUIRE(timermgr != NULL);
451 REQUIRE(socketmgr != NULL);
452 REQUIRE(clientp != NULL && *clientp == NULL);
454 client = isc_mem_get(mctx, sizeof(*client));
456 return (ISC_R_NOMEMORY);
458 result = isc_mutex_init(&client->lock);
459 if (result != ISC_R_SUCCESS) {
460 isc_mem_put(mctx, client, sizeof(*client));
465 client->taskmgr = taskmgr;
466 client->socketmgr = socketmgr;
467 client->timermgr = timermgr;
470 result = isc_task_create(client->taskmgr, 0, &client->task);
471 if (result != ISC_R_SUCCESS)
474 result = dns_dispatchmgr_create(mctx, NULL, &dispatchmgr);
475 if (result != ISC_R_SUCCESS)
477 client->dispatchmgr = dispatchmgr;
480 * If only one address family is specified, use it.
481 * If neither family is specified, or if both are, use both.
483 client->dispatchv4 = NULL;
484 if (localaddr4 != NULL || localaddr6 == NULL) {
485 result = getudpdispatch(AF_INET, dispatchmgr, socketmgr,
487 &dispatchv4, localaddr4);
488 if (result == ISC_R_SUCCESS)
489 client->dispatchv4 = dispatchv4;
492 client->dispatchv6 = NULL;
493 if (localaddr6 != NULL || localaddr4 == NULL) {
494 result = getudpdispatch(AF_INET6, dispatchmgr, socketmgr,
496 &dispatchv6, localaddr6);
497 if (result == ISC_R_SUCCESS)
498 client->dispatchv6 = dispatchv6;
501 /* We need at least one of the dispatchers */
502 if (dispatchv4 == NULL && dispatchv6 == NULL) {
503 INSIST(result != ISC_R_SUCCESS);
507 /* Create the default view for class IN */
508 result = dns_client_createview(mctx, dns_rdataclass_in, options,
509 taskmgr, 31, socketmgr, timermgr,
510 dispatchmgr, dispatchv4, dispatchv6,
512 if (result != ISC_R_SUCCESS)
514 ISC_LIST_INIT(client->viewlist);
515 ISC_LIST_APPEND(client->viewlist, view, link);
517 dns_view_freeze(view); /* too early? */
519 ISC_LIST_INIT(client->resctxs);
520 ISC_LIST_INIT(client->reqctxs);
521 ISC_LIST_INIT(client->updatectxs);
524 isc_mem_attach(mctx, &client->mctx);
526 client->update_timeout = DEF_UPDATE_TIMEOUT;
527 client->update_udptimeout = DEF_UPDATE_UDPTIMEOUT;
528 client->update_udpretries = DEF_UPDATE_UDPRETRIES;
529 client->find_timeout = DEF_FIND_TIMEOUT;
530 client->find_udpretries = DEF_FIND_UDPRETRIES;
531 client->attributes = 0;
533 client->references = 1;
534 client->magic = DNS_CLIENT_MAGIC;
538 return (ISC_R_SUCCESS);
541 if (dispatchv4 != NULL)
542 dns_dispatch_detach(&dispatchv4);
543 if (dispatchv6 != NULL)
544 dns_dispatch_detach(&dispatchv6);
545 if (dispatchmgr != NULL)
546 dns_dispatchmgr_destroy(&dispatchmgr);
547 if (client->task != NULL)
548 isc_task_detach(&client->task);
549 isc_mem_put(mctx, client, sizeof(*client));
555 destroyclient(dns_client_t **clientp) {
556 dns_client_t *client = *clientp;
559 while ((view = ISC_LIST_HEAD(client->viewlist)) != NULL) {
560 ISC_LIST_UNLINK(client->viewlist, view, link);
561 dns_view_detach(&view);
564 if (client->dispatchv4 != NULL)
565 dns_dispatch_detach(&client->dispatchv4);
566 if (client->dispatchv6 != NULL)
567 dns_dispatch_detach(&client->dispatchv6);
569 dns_dispatchmgr_destroy(&client->dispatchmgr);
571 isc_task_detach(&client->task);
574 * If the client has created its own running environments,
577 if ((client->attributes & DNS_CLIENTATTR_OWNCTX) != 0) {
578 isc_taskmgr_destroy(&client->taskmgr);
579 isc_timermgr_destroy(&client->timermgr);
580 isc_socketmgr_destroy(&client->socketmgr);
582 isc_app_ctxfinish(client->actx);
583 isc_appctx_destroy(&client->actx);
586 DESTROYLOCK(&client->lock);
589 isc_mem_putanddetach(&client->mctx, client, sizeof(*client));
595 dns_client_destroy(dns_client_t **clientp) {
596 dns_client_t *client;
597 isc_boolean_t destroyok = ISC_FALSE;
599 REQUIRE(clientp != NULL);
601 REQUIRE(DNS_CLIENT_VALID(client));
604 client->references--;
605 if (client->references == 0 && ISC_LIST_EMPTY(client->resctxs) &&
606 ISC_LIST_EMPTY(client->reqctxs) &&
607 ISC_LIST_EMPTY(client->updatectxs)) {
608 destroyok = ISC_TRUE;
610 UNLOCK(&client->lock);
613 destroyclient(&client);
619 dns_client_setservers(dns_client_t *client, dns_rdataclass_t rdclass,
620 dns_name_t *namespace, isc_sockaddrlist_t *addrs)
623 dns_view_t *view = NULL;
625 REQUIRE(DNS_CLIENT_VALID(client));
626 REQUIRE(addrs != NULL);
628 if (namespace == NULL)
629 namespace = dns_rootname;
632 result = dns_viewlist_find(&client->viewlist, DNS_CLIENTVIEW_NAME,
634 if (result != ISC_R_SUCCESS) {
635 UNLOCK(&client->lock);
638 UNLOCK(&client->lock);
640 result = dns_fwdtable_add(view->fwdtable, namespace, addrs,
643 dns_view_detach(&view);
649 dns_client_clearservers(dns_client_t *client, dns_rdataclass_t rdclass,
650 dns_name_t *namespace)
653 dns_view_t *view = NULL;
655 REQUIRE(DNS_CLIENT_VALID(client));
657 if (namespace == NULL)
658 namespace = dns_rootname;
661 result = dns_viewlist_find(&client->viewlist, DNS_CLIENTVIEW_NAME,
663 if (result != ISC_R_SUCCESS) {
664 UNLOCK(&client->lock);
667 UNLOCK(&client->lock);
669 result = dns_fwdtable_delete(view->fwdtable, namespace);
671 dns_view_detach(&view);
677 getrdataset(isc_mem_t *mctx, dns_rdataset_t **rdatasetp) {
678 dns_rdataset_t *rdataset;
680 REQUIRE(mctx != NULL);
681 REQUIRE(rdatasetp != NULL && *rdatasetp == NULL);
683 rdataset = isc_mem_get(mctx, sizeof(*rdataset));
684 if (rdataset == NULL)
685 return (ISC_R_NOMEMORY);
687 dns_rdataset_init(rdataset);
689 *rdatasetp = rdataset;
691 return (ISC_R_SUCCESS);
695 putrdataset(isc_mem_t *mctx, dns_rdataset_t **rdatasetp) {
696 dns_rdataset_t *rdataset;
698 REQUIRE(rdatasetp != NULL);
699 rdataset = *rdatasetp;
700 REQUIRE(rdataset != NULL);
702 if (dns_rdataset_isassociated(rdataset))
703 dns_rdataset_disassociate(rdataset);
705 isc_mem_put(mctx, rdataset, sizeof(*rdataset));
711 fetch_done(isc_task_t *task, isc_event_t *event) {
712 resctx_t *rctx = event->ev_arg;
713 dns_fetchevent_t *fevent;
715 REQUIRE(event->ev_type == DNS_EVENT_FETCHDONE);
716 REQUIRE(RCTX_VALID(rctx));
717 REQUIRE(rctx->task == task);
718 fevent = (dns_fetchevent_t *)event;
720 client_resfind(rctx, fevent);
723 static inline isc_result_t
724 start_fetch(resctx_t *rctx) {
728 * The caller must be holding the rctx's lock.
731 REQUIRE(rctx->fetch == NULL);
733 result = dns_resolver_createfetch(rctx->view->resolver,
734 dns_fixedname_name(&rctx->name),
737 rctx->task, fetch_done, rctx,
746 view_find(resctx_t *rctx, dns_db_t **dbp, dns_dbnode_t **nodep,
747 dns_name_t *foundname)
750 dns_name_t *name = dns_fixedname_name(&rctx->name);
751 dns_rdatatype_t type;
753 if (rctx->type == dns_rdatatype_rrsig)
754 type = dns_rdatatype_any;
758 result = dns_view_find(rctx->view, name, type, 0, 0, ISC_FALSE,
759 dbp, nodep, foundname, rctx->rdataset,
766 client_resfind(resctx_t *rctx, dns_fetchevent_t *event) {
768 isc_result_t tresult, result = ISC_R_SUCCESS;
769 isc_result_t vresult = ISC_R_SUCCESS;
770 isc_boolean_t want_restart;
771 isc_boolean_t send_event = ISC_FALSE;
772 dns_name_t *name, *prefix;
773 dns_fixedname_t foundname, fixed;
774 dns_rdataset_t *trdataset;
775 dns_rdata_t rdata = DNS_RDATA_INIT;
776 unsigned int nlabels;
778 dns_namereln_t namereln;
779 dns_rdata_cname_t cname;
780 dns_rdata_dname_t dname;
782 REQUIRE(RCTX_VALID(rctx));
786 mctx = rctx->view->mctx;
788 name = dns_fixedname_name(&rctx->name);
791 dns_name_t *fname = NULL;
792 dns_name_t *ansname = NULL;
794 dns_dbnode_t *node = NULL;
797 want_restart = ISC_FALSE;
799 if (event == NULL && !rctx->canceled) {
800 dns_fixedname_init(&foundname);
801 fname = dns_fixedname_name(&foundname);
802 INSIST(!dns_rdataset_isassociated(rctx->rdataset));
803 INSIST(rctx->sigrdataset == NULL ||
804 !dns_rdataset_isassociated(rctx->sigrdataset));
805 result = view_find(rctx, &db, &node, fname);
806 if (result == ISC_R_NOTFOUND) {
808 * We don't know anything about the name.
813 dns_db_detachnode(db, &node);
817 result = start_fetch(rctx);
818 if (result != ISC_R_SUCCESS) {
819 putrdataset(mctx, &rctx->rdataset);
820 if (rctx->sigrdataset != NULL)
823 send_event = ISC_TRUE;
828 INSIST(event != NULL);
829 INSIST(event->fetch == rctx->fetch);
830 dns_resolver_destroyfetch(&rctx->fetch);
833 result = event->result;
834 vresult = event->vresult;
835 fname = dns_fixedname_name(&event->foundname);
836 INSIST(event->rdataset == rctx->rdataset);
837 INSIST(event->sigrdataset == rctx->sigrdataset);
841 * If we've been canceled, forget about the result.
844 result = ISC_R_CANCELED;
847 * Otherwise, get some resource for copying the
850 ansname = isc_mem_get(mctx, sizeof(*ansname));
852 tresult = ISC_R_NOMEMORY;
856 aname = dns_fixedname_name(&rctx->name);
857 dns_name_init(ansname, NULL);
858 tresult = dns_name_dup(aname, mctx, ansname);
859 if (tresult != ISC_R_SUCCESS)
860 isc_mem_put(mctx, ansname,
863 if (tresult != ISC_R_SUCCESS)
869 send_event = ISC_TRUE;
871 * This case is handled in the main line below.
876 * Add the CNAME to the answer list.
878 trdataset = rctx->rdataset;
879 ISC_LIST_APPEND(ansname->list, rctx->rdataset, link);
880 rctx->rdataset = NULL;
881 if (rctx->sigrdataset != NULL) {
882 ISC_LIST_APPEND(ansname->list,
883 rctx->sigrdataset, link);
884 rctx->sigrdataset = NULL;
886 ISC_LIST_APPEND(rctx->namelist, ansname, link);
890 * Copy the CNAME's target into the lookup's
891 * query name and start over.
893 tresult = dns_rdataset_first(trdataset);
894 if (tresult != ISC_R_SUCCESS)
896 dns_rdataset_current(trdataset, &rdata);
897 tresult = dns_rdata_tostruct(&rdata, &cname, NULL);
898 dns_rdata_reset(&rdata);
899 if (tresult != ISC_R_SUCCESS)
901 tresult = dns_name_copy(&cname.cname, name, NULL);
902 dns_rdata_freestruct(&cname);
903 if (tresult == ISC_R_SUCCESS)
904 want_restart = ISC_TRUE;
910 * Add the DNAME to the answer list.
912 trdataset = rctx->rdataset;
913 ISC_LIST_APPEND(ansname->list, rctx->rdataset, link);
914 rctx->rdataset = NULL;
915 if (rctx->sigrdataset != NULL) {
916 ISC_LIST_APPEND(ansname->list,
917 rctx->sigrdataset, link);
918 rctx->sigrdataset = NULL;
920 ISC_LIST_APPEND(rctx->namelist, ansname, link);
923 namereln = dns_name_fullcompare(name, fname, &order,
925 INSIST(namereln == dns_namereln_subdomain);
927 * Get the target name of the DNAME.
929 tresult = dns_rdataset_first(trdataset);
930 if (tresult != ISC_R_SUCCESS) {
934 dns_rdataset_current(trdataset, &rdata);
935 tresult = dns_rdata_tostruct(&rdata, &dname, NULL);
936 dns_rdata_reset(&rdata);
937 if (tresult != ISC_R_SUCCESS) {
942 * Construct the new query name and start over.
944 dns_fixedname_init(&fixed);
945 prefix = dns_fixedname_name(&fixed);
946 dns_name_split(name, nlabels, prefix, NULL);
947 tresult = dns_name_concatenate(prefix, &dname.dname,
949 dns_rdata_freestruct(&dname);
950 if (tresult == ISC_R_SUCCESS)
951 want_restart = ISC_TRUE;
955 case DNS_R_NCACHENXDOMAIN:
956 case DNS_R_NCACHENXRRSET:
957 ISC_LIST_APPEND(ansname->list, rctx->rdataset, link);
958 ISC_LIST_APPEND(rctx->namelist, ansname, link);
960 rctx->rdataset = NULL;
961 /* What about sigrdataset? */
962 if (rctx->sigrdataset != NULL)
963 putrdataset(mctx, &rctx->sigrdataset);
964 send_event = ISC_TRUE;
967 if (rctx->rdataset != NULL)
968 putrdataset(mctx, &rctx->rdataset);
969 if (rctx->sigrdataset != NULL)
970 putrdataset(mctx, &rctx->sigrdataset);
971 send_event = ISC_TRUE;
975 if (rctx->type == dns_rdatatype_any) {
977 dns_rdatasetiter_t *rdsiter = NULL;
979 tresult = dns_db_allrdatasets(db, node, NULL, 0,
981 if (tresult != ISC_R_SUCCESS) {
986 tresult = dns_rdatasetiter_first(rdsiter);
987 while (tresult == ISC_R_SUCCESS) {
988 dns_rdatasetiter_current(rdsiter,
990 if (rctx->rdataset->type != 0) {
991 ISC_LIST_APPEND(ansname->list,
995 rctx->rdataset = NULL;
998 * We're not interested in this
1001 dns_rdataset_disassociate(
1004 tresult = dns_rdatasetiter_next(rdsiter);
1006 if (tresult == ISC_R_SUCCESS &&
1007 rctx->rdataset == NULL) {
1008 tresult = getrdataset(mctx,
1010 if (tresult != ISC_R_SUCCESS) {
1019 * We didn't match any rdatasets (which means
1020 * something went wrong in this
1023 result = DNS_R_SERVFAIL; /* better code? */
1026 ISC_LIST_APPEND(rctx->namelist, ansname, link);
1029 dns_rdatasetiter_destroy(&rdsiter);
1030 if (tresult != ISC_R_NOMORE)
1031 result = DNS_R_SERVFAIL; /* ditto */
1033 result = ISC_R_SUCCESS;
1037 * This is the "normal" case -- an ordinary question
1038 * to which we've got the answer.
1040 ISC_LIST_APPEND(ansname->list, rctx->rdataset, link);
1041 rctx->rdataset = NULL;
1042 if (rctx->sigrdataset != NULL) {
1043 ISC_LIST_APPEND(ansname->list,
1044 rctx->sigrdataset, link);
1045 rctx->sigrdataset = NULL;
1047 ISC_LIST_APPEND(rctx->namelist, ansname, link);
1053 * Free temporary resources
1055 if (ansname != NULL) {
1056 dns_rdataset_t *rdataset;
1058 while ((rdataset = ISC_LIST_HEAD(ansname->list))
1060 ISC_LIST_UNLINK(ansname->list, rdataset, link);
1061 putrdataset(mctx, &rdataset);
1063 dns_name_free(ansname, mctx);
1064 isc_mem_put(mctx, ansname, sizeof(*ansname));
1068 dns_db_detachnode(db, &node);
1072 isc_event_free(ISC_EVENT_PTR(&event));
1075 * Limit the number of restarts.
1077 if (want_restart && rctx->restarts == MAX_RESTARTS) {
1078 want_restart = ISC_FALSE;
1079 result = ISC_R_QUOTA;
1080 send_event = ISC_TRUE;
1084 * Prepare further find with new resources
1087 INSIST(rctx->rdataset == NULL &&
1088 rctx->sigrdataset == NULL);
1090 result = getrdataset(mctx, &rctx->rdataset);
1091 if (result == ISC_R_SUCCESS && rctx->want_dnssec) {
1092 result = getrdataset(mctx, &rctx->sigrdataset);
1093 if (result != ISC_R_SUCCESS) {
1094 putrdataset(mctx, &rctx->rdataset);
1098 if (result != ISC_R_SUCCESS) {
1099 want_restart = ISC_FALSE;
1100 send_event = ISC_TRUE;
1103 } while (want_restart);
1108 while ((name = ISC_LIST_HEAD(rctx->namelist)) != NULL) {
1109 ISC_LIST_UNLINK(rctx->namelist, name, link);
1110 ISC_LIST_APPEND(rctx->event->answerlist, name, link);
1113 rctx->event->result = result;
1114 rctx->event->vresult = vresult;
1115 task = rctx->event->ev_sender;
1116 rctx->event->ev_sender = rctx;
1117 isc_task_sendanddetach(&task, ISC_EVENT_PTR(&rctx->event));
1120 UNLOCK(&rctx->lock);
1125 suspend(isc_task_t *task, isc_event_t *event) {
1126 isc_appctx_t *actx = event->ev_arg;
1130 isc_app_ctxsuspend(actx);
1131 isc_event_free(&event);
1135 resolve_done(isc_task_t *task, isc_event_t *event) {
1136 resarg_t *resarg = event->ev_arg;
1137 dns_clientresevent_t *rev = (dns_clientresevent_t *)event;
1139 isc_result_t result;
1143 LOCK(&resarg->lock);
1145 resarg->result = rev->result;
1146 resarg->vresult = rev->vresult;
1147 while ((name = ISC_LIST_HEAD(rev->answerlist)) != NULL) {
1148 ISC_LIST_UNLINK(rev->answerlist, name, link);
1149 ISC_LIST_APPEND(*resarg->namelist, name, link);
1152 dns_client_destroyrestrans(&resarg->trans);
1153 isc_event_free(&event);
1155 if (!resarg->canceled) {
1156 UNLOCK(&resarg->lock);
1159 * We may or may not be running. isc__appctx_onrun will
1160 * fail if we are currently running otherwise we post a
1161 * action to call isc_app_ctxsuspend when we do start
1164 result = isc_app_ctxonrun(resarg->actx, resarg->client->mctx,
1165 task, suspend, resarg->actx);
1166 if (result == ISC_R_ALREADYRUNNING)
1167 isc_app_ctxsuspend(resarg->actx);
1170 * We have already exited from the loop (due to some
1171 * unexpected event). Just clean the arg up.
1173 UNLOCK(&resarg->lock);
1174 DESTROYLOCK(&resarg->lock);
1175 isc_mem_put(resarg->client->mctx, resarg, sizeof(*resarg));
1180 dns_client_resolve(dns_client_t *client, dns_name_t *name,
1181 dns_rdataclass_t rdclass, dns_rdatatype_t type,
1182 unsigned int options, dns_namelist_t *namelist)
1184 isc_result_t result;
1188 REQUIRE(DNS_CLIENT_VALID(client));
1189 REQUIRE(namelist != NULL && ISC_LIST_EMPTY(*namelist));
1191 if ((client->attributes & DNS_CLIENTATTR_OWNCTX) == 0 &&
1192 (options & DNS_CLIENTRESOPT_ALLOWRUN) == 0) {
1194 * If the client is run under application's control, we need
1195 * to create a new running (sub)environment for this
1196 * particular resolution.
1198 return (ISC_R_NOTIMPLEMENTED); /* XXXTBD */
1200 actx = client->actx;
1202 resarg = isc_mem_get(client->mctx, sizeof(*resarg));
1204 return (ISC_R_NOMEMORY);
1206 result = isc_mutex_init(&resarg->lock);
1207 if (result != ISC_R_SUCCESS) {
1208 isc_mem_put(client->mctx, resarg, sizeof(*resarg));
1212 resarg->actx = actx;
1213 resarg->client = client;
1214 resarg->result = DNS_R_SERVFAIL;
1215 resarg->namelist = namelist;
1216 resarg->trans = NULL;
1217 resarg->canceled = ISC_FALSE;
1218 result = dns_client_startresolve(client, name, rdclass, type, options,
1219 client->task, resolve_done, resarg,
1221 if (result != ISC_R_SUCCESS) {
1222 DESTROYLOCK(&resarg->lock);
1223 isc_mem_put(client->mctx, resarg, sizeof(*resarg));
1228 * Start internal event loop. It blocks until the entire process
1231 result = isc_app_ctxrun(actx);
1233 LOCK(&resarg->lock);
1234 if (result == ISC_R_SUCCESS || result == ISC_R_SUSPEND)
1235 result = resarg->result;
1236 if (result != ISC_R_SUCCESS && resarg->vresult != ISC_R_SUCCESS) {
1238 * If this lookup failed due to some error in DNSSEC
1239 * validation, return the validation error code.
1240 * XXX: or should we pass the validation result separately?
1242 result = resarg->vresult;
1244 if (resarg->trans != NULL) {
1246 * Unusual termination (perhaps due to signal). We need some
1247 * tricky cleanup process.
1249 resarg->canceled = ISC_TRUE;
1250 dns_client_cancelresolve(resarg->trans);
1252 UNLOCK(&resarg->lock);
1254 /* resarg will be freed in the event handler. */
1256 UNLOCK(&resarg->lock);
1258 DESTROYLOCK(&resarg->lock);
1259 isc_mem_put(client->mctx, resarg, sizeof(*resarg));
1266 dns_client_startresolve(dns_client_t *client, dns_name_t *name,
1267 dns_rdataclass_t rdclass, dns_rdatatype_t type,
1268 unsigned int options, isc_task_t *task,
1269 isc_taskaction_t action, void *arg,
1270 dns_clientrestrans_t **transp)
1272 dns_view_t *view = NULL;
1273 dns_clientresevent_t *event = NULL;
1274 resctx_t *rctx = NULL;
1275 isc_task_t *clone = NULL;
1277 isc_result_t result;
1278 dns_rdataset_t *rdataset, *sigrdataset;
1279 isc_boolean_t want_dnssec;
1281 REQUIRE(DNS_CLIENT_VALID(client));
1282 REQUIRE(transp != NULL && *transp == NULL);
1284 LOCK(&client->lock);
1285 result = dns_viewlist_find(&client->viewlist, DNS_CLIENTVIEW_NAME,
1287 UNLOCK(&client->lock);
1288 if (result != ISC_R_SUCCESS)
1291 mctx = client->mctx;
1294 want_dnssec = ISC_TF((options & DNS_CLIENTRESOPT_NODNSSEC) == 0);
1297 * Prepare some intermediate resources
1300 isc_task_attach(task, &clone);
1301 event = (dns_clientresevent_t *)
1302 isc_event_allocate(mctx, clone, DNS_EVENT_CLIENTRESDONE,
1303 action, arg, sizeof(*event));
1304 if (event == NULL) {
1305 result = ISC_R_NOMEMORY;
1308 event->result = DNS_R_SERVFAIL;
1309 ISC_LIST_INIT(event->answerlist);
1311 rctx = isc_mem_get(mctx, sizeof(*rctx));
1313 result = ISC_R_NOMEMORY;
1315 result = isc_mutex_init(&rctx->lock);
1316 if (result != ISC_R_SUCCESS) {
1317 isc_mem_put(mctx, rctx, sizeof(*rctx));
1321 if (result != ISC_R_SUCCESS)
1324 result = getrdataset(mctx, &rdataset);
1325 if (result != ISC_R_SUCCESS)
1327 rctx->rdataset = rdataset;
1330 result = getrdataset(mctx, &sigrdataset);
1331 if (result != ISC_R_SUCCESS)
1334 rctx->sigrdataset = sigrdataset;
1336 dns_fixedname_init(&rctx->name);
1337 result = dns_name_copy(name, dns_fixedname_name(&rctx->name), NULL);
1338 if (result != ISC_R_SUCCESS)
1341 rctx->client = client;
1342 ISC_LINK_INIT(rctx, link);
1343 rctx->canceled = ISC_FALSE;
1344 rctx->task = client->task;
1349 rctx->want_dnssec = want_dnssec;
1350 ISC_LIST_INIT(rctx->namelist);
1351 rctx->event = event;
1353 rctx->magic = RCTX_MAGIC;
1355 LOCK(&client->lock);
1356 ISC_LIST_APPEND(client->resctxs, rctx, link);
1357 UNLOCK(&client->lock);
1359 *transp = (dns_clientrestrans_t *)rctx;
1360 client_resfind(rctx, NULL);
1362 return (ISC_R_SUCCESS);
1365 if (rdataset != NULL)
1366 putrdataset(client->mctx, &rdataset);
1367 if (sigrdataset != NULL)
1368 putrdataset(client->mctx, &sigrdataset);
1370 DESTROYLOCK(&rctx->lock);
1371 isc_mem_put(mctx, rctx, sizeof(*rctx));
1374 isc_event_free(ISC_EVENT_PTR(&event));
1375 isc_task_detach(&clone);
1376 dns_view_detach(&view);
1382 dns_client_cancelresolve(dns_clientrestrans_t *trans) {
1385 REQUIRE(trans != NULL);
1386 rctx = (resctx_t *)trans;
1387 REQUIRE(RCTX_VALID(rctx));
1391 if (!rctx->canceled) {
1392 rctx->canceled = ISC_TRUE;
1393 if (rctx->fetch != NULL)
1394 dns_resolver_cancelfetch(rctx->fetch);
1397 UNLOCK(&rctx->lock);
1401 dns_client_freeresanswer(dns_client_t *client, dns_namelist_t *namelist) {
1403 dns_rdataset_t *rdataset;
1405 REQUIRE(DNS_CLIENT_VALID(client));
1406 REQUIRE(namelist != NULL);
1408 while ((name = ISC_LIST_HEAD(*namelist)) != NULL) {
1409 ISC_LIST_UNLINK(*namelist, name, link);
1410 while ((rdataset = ISC_LIST_HEAD(name->list)) != NULL) {
1411 ISC_LIST_UNLINK(name->list, rdataset, link);
1412 putrdataset(client->mctx, &rdataset);
1414 dns_name_free(name, client->mctx);
1415 isc_mem_put(client->mctx, name, sizeof(*name));
1420 dns_client_destroyrestrans(dns_clientrestrans_t **transp) {
1423 dns_client_t *client;
1424 isc_boolean_t need_destroyclient = ISC_FALSE;
1426 REQUIRE(transp != NULL);
1427 rctx = (resctx_t *)*transp;
1428 REQUIRE(RCTX_VALID(rctx));
1429 REQUIRE(rctx->fetch == NULL);
1430 REQUIRE(rctx->event == NULL);
1431 client = rctx->client;
1432 REQUIRE(DNS_CLIENT_VALID(client));
1434 mctx = client->mctx;
1435 dns_view_detach(&rctx->view);
1437 LOCK(&client->lock);
1439 INSIST(ISC_LINK_LINKED(rctx, link));
1440 ISC_LIST_UNLINK(client->resctxs, rctx, link);
1442 if (client->references == 0 && ISC_LIST_EMPTY(client->resctxs) &&
1443 ISC_LIST_EMPTY(client->reqctxs) &&
1444 ISC_LIST_EMPTY(client->updatectxs))
1445 need_destroyclient = ISC_TRUE;
1447 UNLOCK(&client->lock);
1449 INSIST(ISC_LIST_EMPTY(rctx->namelist));
1451 DESTROYLOCK(&rctx->lock);
1454 isc_mem_put(mctx, rctx, sizeof(*rctx));
1456 if (need_destroyclient)
1457 destroyclient(&client);
1463 dns_client_addtrustedkey(dns_client_t *client, dns_rdataclass_t rdclass,
1464 dns_name_t *keyname, isc_buffer_t *keydatabuf)
1466 isc_result_t result;
1467 dns_view_t *view = NULL;
1468 dst_key_t *dstkey = NULL;
1469 dns_keytable_t *secroots = NULL;
1471 REQUIRE(DNS_CLIENT_VALID(client));
1473 LOCK(&client->lock);
1474 result = dns_viewlist_find(&client->viewlist, DNS_CLIENTVIEW_NAME,
1476 UNLOCK(&client->lock);
1477 if (result != ISC_R_SUCCESS)
1480 result = dns_view_getsecroots(view, &secroots);
1481 if (result != ISC_R_SUCCESS)
1484 result = dst_key_fromdns(keyname, rdclass, keydatabuf, client->mctx,
1486 if (result != ISC_R_SUCCESS)
1489 result = dns_keytable_add(secroots, ISC_FALSE, &dstkey);
1493 dst_key_free(&dstkey);
1495 dns_view_detach(&view);
1496 if (secroots != NULL)
1497 dns_keytable_detach(&secroots);
1502 * Simple request routines
1505 request_done(isc_task_t *task, isc_event_t *event) {
1506 dns_requestevent_t *reqev = NULL;
1507 dns_request_t *request;
1508 isc_result_t result, eresult;
1513 REQUIRE(event->ev_type == DNS_EVENT_REQUESTDONE);
1514 reqev = (dns_requestevent_t *)event;
1515 request = reqev->request;
1516 result = eresult = reqev->result;
1517 ctx = reqev->ev_arg;
1518 REQUIRE(REQCTX_VALID(ctx));
1520 isc_event_free(&event);
1524 if (eresult == ISC_R_SUCCESS) {
1525 result = dns_request_getresponse(request, ctx->event->rmessage,
1529 if (ctx->tsigkey != NULL)
1530 dns_tsigkey_detach(&ctx->tsigkey);
1533 ctx->event->result = ISC_R_CANCELED;
1535 ctx->event->result = result;
1536 task = ctx->event->ev_sender;
1537 ctx->event->ev_sender = ctx;
1538 isc_task_sendanddetach(&task, ISC_EVENT_PTR(&ctx->event));
1544 localrequest_done(isc_task_t *task, isc_event_t *event) {
1545 reqarg_t *reqarg = event->ev_arg;
1546 dns_clientreqevent_t *rev =(dns_clientreqevent_t *)event;
1550 REQUIRE(event->ev_type == DNS_EVENT_CLIENTREQDONE);
1552 LOCK(&reqarg->lock);
1554 reqarg->result = rev->result;
1555 dns_client_destroyreqtrans(&reqarg->trans);
1556 isc_event_free(&event);
1558 if (!reqarg->canceled) {
1559 UNLOCK(&reqarg->lock);
1561 /* Exit from the internal event loop */
1562 isc_app_ctxsuspend(reqarg->actx);
1565 * We have already exited from the loop (due to some
1566 * unexpected event). Just clean the arg up.
1568 UNLOCK(&reqarg->lock);
1569 DESTROYLOCK(&reqarg->lock);
1570 isc_mem_put(reqarg->client->mctx, reqarg, sizeof(*reqarg));
1575 dns_client_request(dns_client_t *client, dns_message_t *qmessage,
1576 dns_message_t *rmessage, isc_sockaddr_t *server,
1577 unsigned int options, unsigned int parseoptions,
1578 dns_tsec_t *tsec, unsigned int timeout,
1579 unsigned int udptimeout, unsigned int udpretries)
1583 isc_result_t result;
1585 REQUIRE(DNS_CLIENT_VALID(client));
1586 REQUIRE(qmessage != NULL);
1587 REQUIRE(rmessage != NULL);
1589 if ((client->attributes & DNS_CLIENTATTR_OWNCTX) == 0 &&
1590 (options & DNS_CLIENTREQOPT_ALLOWRUN) == 0) {
1592 * If the client is run under application's control, we need
1593 * to create a new running (sub)environment for this
1594 * particular resolution.
1596 return (ISC_R_NOTIMPLEMENTED); /* XXXTBD */
1598 actx = client->actx;
1600 reqarg = isc_mem_get(client->mctx, sizeof(*reqarg));
1602 return (ISC_R_NOMEMORY);
1604 result = isc_mutex_init(&reqarg->lock);
1605 if (result != ISC_R_SUCCESS) {
1606 isc_mem_put(client->mctx, reqarg, sizeof(*reqarg));
1610 reqarg->actx = actx;
1611 reqarg->client = client;
1612 reqarg->trans = NULL;
1613 reqarg->canceled = ISC_FALSE;
1615 result = dns_client_startrequest(client, qmessage, rmessage, server,
1616 options, parseoptions, tsec, timeout,
1617 udptimeout, udpretries,
1618 client->task, localrequest_done,
1619 reqarg, &reqarg->trans);
1620 if (result != ISC_R_SUCCESS) {
1621 DESTROYLOCK(&reqarg->lock);
1622 isc_mem_put(client->mctx, reqarg, sizeof(*reqarg));
1627 * Start internal event loop. It blocks until the entire process
1630 result = isc_app_ctxrun(actx);
1632 LOCK(&reqarg->lock);
1633 if (result == ISC_R_SUCCESS || result == ISC_R_SUSPEND)
1634 result = reqarg->result;
1635 if (reqarg->trans != NULL) {
1637 * Unusual termination (perhaps due to signal). We need some
1638 * tricky cleanup process.
1640 reqarg->canceled = ISC_TRUE;
1641 dns_client_cancelresolve(reqarg->trans);
1643 UNLOCK(&reqarg->lock);
1645 /* reqarg will be freed in the event handler. */
1647 UNLOCK(&reqarg->lock);
1649 DESTROYLOCK(&reqarg->lock);
1650 isc_mem_put(client->mctx, reqarg, sizeof(*reqarg));
1657 dns_client_startrequest(dns_client_t *client, dns_message_t *qmessage,
1658 dns_message_t *rmessage, isc_sockaddr_t *server,
1659 unsigned int options, unsigned int parseoptions,
1660 dns_tsec_t *tsec, unsigned int timeout,
1661 unsigned int udptimeout, unsigned int udpretries,
1662 isc_task_t *task, isc_taskaction_t action, void *arg,
1663 dns_clientreqtrans_t **transp)
1665 isc_result_t result;
1666 dns_view_t *view = NULL;
1667 isc_task_t *clone = NULL;
1668 dns_clientreqevent_t *event = NULL;
1669 reqctx_t *ctx = NULL;
1670 dns_tsectype_t tsectype = dns_tsectype_none;
1674 REQUIRE(DNS_CLIENT_VALID(client));
1675 REQUIRE(qmessage != NULL);
1676 REQUIRE(rmessage != NULL);
1677 REQUIRE(transp != NULL && *transp == NULL);
1680 tsectype = dns_tsec_gettype(tsec);
1681 if (tsectype != dns_tsectype_tsig)
1682 return (ISC_R_NOTIMPLEMENTED); /* XXX */
1685 LOCK(&client->lock);
1686 result = dns_viewlist_find(&client->viewlist, DNS_CLIENTVIEW_NAME,
1687 qmessage->rdclass, &view);
1688 UNLOCK(&client->lock);
1689 if (result != ISC_R_SUCCESS)
1693 isc_task_attach(task, &clone);
1694 event = (dns_clientreqevent_t *)
1695 isc_event_allocate(client->mctx, clone,
1696 DNS_EVENT_CLIENTREQDONE,
1697 action, arg, sizeof(*event));
1698 if (event == NULL) {
1699 result = ISC_R_NOMEMORY;
1703 ctx = isc_mem_get(client->mctx, sizeof(*ctx));
1705 result = ISC_R_NOMEMORY;
1707 result = isc_mutex_init(&ctx->lock);
1708 if (result != ISC_R_SUCCESS) {
1709 isc_mem_put(client->mctx, ctx, sizeof(*ctx));
1713 if (result != ISC_R_SUCCESS)
1716 ctx->client = client;
1717 ISC_LINK_INIT(ctx, link);
1718 ctx->parseoptions = parseoptions;
1719 ctx->canceled = ISC_FALSE;
1721 ctx->event->rmessage = rmessage;
1722 ctx->tsigkey = NULL;
1724 dns_tsec_getkey(tsec, &ctx->tsigkey);
1726 ctx->magic = REQCTX_MAGIC;
1728 LOCK(&client->lock);
1729 ISC_LIST_APPEND(client->reqctxs, ctx, link);
1730 UNLOCK(&client->lock);
1732 ctx->request = NULL;
1733 result = dns_request_createvia3(view->requestmgr, qmessage, NULL,
1734 server, options, ctx->tsigkey,
1735 timeout, udptimeout, udpretries,
1736 client->task, request_done, ctx,
1738 if (result == ISC_R_SUCCESS) {
1739 dns_view_detach(&view);
1740 *transp = (dns_clientreqtrans_t *)ctx;
1741 return (ISC_R_SUCCESS);
1746 LOCK(&client->lock);
1747 ISC_LIST_UNLINK(client->reqctxs, ctx, link);
1748 UNLOCK(&client->lock);
1749 DESTROYLOCK(&ctx->lock);
1750 isc_mem_put(client->mctx, ctx, sizeof(*ctx));
1753 isc_event_free(ISC_EVENT_PTR(&event));
1754 isc_task_detach(&clone);
1755 dns_view_detach(&view);
1761 dns_client_cancelrequest(dns_clientreqtrans_t *trans) {
1764 REQUIRE(trans != NULL);
1765 ctx = (reqctx_t *)trans;
1766 REQUIRE(REQCTX_VALID(ctx));
1770 if (!ctx->canceled) {
1771 ctx->canceled = ISC_TRUE;
1772 if (ctx->request != NULL)
1773 dns_request_cancel(ctx->request);
1780 dns_client_destroyreqtrans(dns_clientreqtrans_t **transp) {
1783 dns_client_t *client;
1784 isc_boolean_t need_destroyclient = ISC_FALSE;
1786 REQUIRE(transp != NULL);
1787 ctx = (reqctx_t *)*transp;
1788 REQUIRE(REQCTX_VALID(ctx));
1789 client = ctx->client;
1790 REQUIRE(DNS_CLIENT_VALID(client));
1791 REQUIRE(ctx->event == NULL);
1792 REQUIRE(ctx->request != NULL);
1794 dns_request_destroy(&ctx->request);
1795 mctx = client->mctx;
1797 LOCK(&client->lock);
1799 INSIST(ISC_LINK_LINKED(ctx, link));
1800 ISC_LIST_UNLINK(client->reqctxs, ctx, link);
1802 if (client->references == 0 && ISC_LIST_EMPTY(client->resctxs) &&
1803 ISC_LIST_EMPTY(client->reqctxs) &&
1804 ISC_LIST_EMPTY(client->updatectxs)) {
1805 need_destroyclient = ISC_TRUE;
1808 UNLOCK(&client->lock);
1810 DESTROYLOCK(&ctx->lock);
1813 isc_mem_put(mctx, ctx, sizeof(*ctx));
1815 if (need_destroyclient)
1816 destroyclient(&client);
1822 * Dynamic update routines
1825 rcode2result(dns_rcode_t rcode) {
1826 /* XXX: isn't there a similar function? */
1828 case dns_rcode_formerr:
1829 return (DNS_R_FORMERR);
1830 case dns_rcode_servfail:
1831 return (DNS_R_SERVFAIL);
1832 case dns_rcode_nxdomain:
1833 return (DNS_R_NXDOMAIN);
1834 case dns_rcode_notimp:
1835 return (DNS_R_NOTIMP);
1836 case dns_rcode_refused:
1837 return (DNS_R_REFUSED);
1838 case dns_rcode_yxdomain:
1839 return (DNS_R_YXDOMAIN);
1840 case dns_rcode_yxrrset:
1841 return (DNS_R_YXRRSET);
1842 case dns_rcode_nxrrset:
1843 return (DNS_R_NXRRSET);
1844 case dns_rcode_notauth:
1845 return (DNS_R_NOTAUTH);
1846 case dns_rcode_notzone:
1847 return (DNS_R_NOTZONE);
1848 case dns_rcode_badvers:
1849 return (DNS_R_BADVERS);
1852 return (ISC_R_FAILURE);
1856 update_sendevent(updatectx_t *uctx, isc_result_t result) {
1859 dns_message_destroy(&uctx->updatemsg);
1860 if (uctx->tsigkey != NULL)
1861 dns_tsigkey_detach(&uctx->tsigkey);
1862 if (uctx->sig0key != NULL)
1863 dst_key_free(&uctx->sig0key);
1866 uctx->event->result = ISC_R_CANCELED;
1868 uctx->event->result = result;
1869 uctx->event->state = uctx->state;
1870 task = uctx->event->ev_sender;
1871 uctx->event->ev_sender = uctx;
1872 isc_task_sendanddetach(&task, ISC_EVENT_PTR(&uctx->event));
1876 update_done(isc_task_t *task, isc_event_t *event) {
1877 isc_result_t result;
1878 dns_requestevent_t *reqev = NULL;
1879 dns_request_t *request;
1880 dns_message_t *answer = NULL;
1881 updatectx_t *uctx = event->ev_arg;
1882 dns_client_t *client;
1883 unsigned int timeout;
1887 REQUIRE(event->ev_type == DNS_EVENT_REQUESTDONE);
1888 reqev = (dns_requestevent_t *)event;
1889 request = reqev->request;
1890 REQUIRE(UCTX_VALID(uctx));
1891 client = uctx->client;
1892 REQUIRE(DNS_CLIENT_VALID(client));
1894 result = reqev->result;
1895 if (result != ISC_R_SUCCESS)
1898 result = dns_message_create(client->mctx, DNS_MESSAGE_INTENTPARSE,
1900 if (result != ISC_R_SUCCESS)
1902 uctx->state = dns_clientupdatestate_done;
1903 result = dns_request_getresponse(request, answer,
1904 DNS_MESSAGEPARSE_PRESERVEORDER);
1905 if (result == ISC_R_SUCCESS && answer->rcode != dns_rcode_noerror)
1906 result = rcode2result(answer->rcode);
1910 dns_message_destroy(&answer);
1911 isc_event_free(&event);
1914 uctx->currentserver = ISC_LIST_NEXT(uctx->currentserver, link);
1915 dns_request_destroy(&uctx->updatereq);
1916 if (result != ISC_R_SUCCESS && !uctx->canceled &&
1917 uctx->currentserver != NULL) {
1918 dns_message_renderreset(uctx->updatemsg);
1919 dns_message_settsigkey(uctx->updatemsg, NULL);
1921 timeout = client->update_timeout / uctx->nservers;
1922 if (timeout < MIN_UPDATE_TIMEOUT)
1923 timeout = MIN_UPDATE_TIMEOUT;
1924 result = dns_request_createvia3(uctx->view->requestmgr,
1927 uctx->currentserver, 0,
1930 client->update_udptimeout,
1931 client->update_udpretries,
1935 UNLOCK(&uctx->lock);
1937 if (result == ISC_R_SUCCESS) {
1938 /* XXX: should we keep the 'done' state here? */
1939 uctx->state = dns_clientupdatestate_sent;
1943 UNLOCK(&uctx->lock);
1945 update_sendevent(uctx, result);
1949 send_update(updatectx_t *uctx) {
1950 isc_result_t result;
1951 dns_name_t *name = NULL;
1952 dns_rdataset_t *rdataset = NULL;
1953 dns_client_t *client = uctx->client;
1954 unsigned int timeout;
1956 REQUIRE(uctx->zonename != NULL && uctx->currentserver != NULL);
1958 result = dns_message_gettempname(uctx->updatemsg, &name);
1959 if (result != ISC_R_SUCCESS)
1961 dns_name_init(name, NULL);
1962 dns_name_clone(uctx->zonename, name);
1963 result = dns_message_gettemprdataset(uctx->updatemsg, &rdataset);
1964 if (result != ISC_R_SUCCESS) {
1965 dns_message_puttempname(uctx->updatemsg, &name);
1968 dns_rdataset_makequestion(rdataset, uctx->rdclass, dns_rdatatype_soa);
1969 ISC_LIST_INIT(name->list);
1970 ISC_LIST_APPEND(name->list, rdataset, link);
1971 dns_message_addname(uctx->updatemsg, name, DNS_SECTION_ZONE);
1972 if (uctx->tsigkey == NULL && uctx->sig0key != NULL) {
1973 result = dns_message_setsig0key(uctx->updatemsg,
1975 if (result != ISC_R_SUCCESS)
1978 timeout = client->update_timeout / uctx->nservers;
1979 if (timeout < MIN_UPDATE_TIMEOUT)
1980 timeout = MIN_UPDATE_TIMEOUT;
1981 result = dns_request_createvia3(uctx->view->requestmgr,
1983 NULL, uctx->currentserver, 0,
1984 uctx->tsigkey, timeout,
1985 client->update_udptimeout,
1986 client->update_udpretries,
1987 client->task, update_done, uctx,
1989 if (result == ISC_R_SUCCESS &&
1990 uctx->state == dns_clientupdatestate_prepare) {
1991 uctx->state = dns_clientupdatestate_sent;
1998 resolveaddr_done(isc_task_t *task, isc_event_t *event) {
1999 isc_result_t result;
2001 dns_rdatatype_t qtype;
2002 dns_clientresevent_t *rev = (dns_clientresevent_t *)event;
2004 dns_rdataset_t *rdataset;
2006 isc_boolean_t completed = ISC_FALSE;
2010 REQUIRE(event->ev_arg != NULL);
2011 uctx = *(updatectx_t **)event->ev_arg;
2012 REQUIRE(UCTX_VALID(uctx));
2014 if (event->ev_arg == &uctx->bp4) {
2016 qtype = dns_rdatatype_a;
2018 dns_client_destroyrestrans(&uctx->restrans);
2019 UNLOCK(&uctx->lock);
2021 INSIST(event->ev_arg == &uctx->bp6);
2023 qtype = dns_rdatatype_aaaa;
2025 dns_client_destroyrestrans(&uctx->restrans2);
2026 UNLOCK(&uctx->lock);
2029 result = rev->result;
2030 if (result != ISC_R_SUCCESS)
2033 for (name = ISC_LIST_HEAD(rev->answerlist); name != NULL;
2034 name = ISC_LIST_NEXT(name, link)) {
2035 for (rdataset = ISC_LIST_HEAD(name->list);
2037 rdataset = ISC_LIST_NEXT(rdataset, link)) {
2038 if (!dns_rdataset_isassociated(rdataset))
2040 if (rdataset->type != qtype)
2043 for (result = dns_rdataset_first(rdataset);
2044 result == ISC_R_SUCCESS;
2045 result = dns_rdataset_next(rdataset)) {
2047 dns_rdata_in_a_t rdata_a;
2048 dns_rdata_in_aaaa_t rdata_aaaa;
2051 sa = isc_mem_get(uctx->client->mctx,
2055 * If we fail to get a sockaddr,
2056 we simply move forward with the
2057 * addresses we've got so far.
2062 dns_rdata_init(&rdata);
2065 dns_rdataset_current(rdataset, &rdata);
2066 result = dns_rdata_tostruct(&rdata, &rdata_a,
2068 RUNTIME_CHECK(result == ISC_R_SUCCESS);
2069 isc_sockaddr_fromin(sa,
2072 dns_rdata_freestruct(&rdata_a);
2075 dns_rdataset_current(rdataset, &rdata);
2076 result = dns_rdata_tostruct(&rdata, &rdata_aaaa,
2078 RUNTIME_CHECK(result == ISC_R_SUCCESS);
2079 isc_sockaddr_fromin6(sa,
2080 &rdata_aaaa.in6_addr,
2082 dns_rdata_freestruct(&rdata_aaaa);
2086 ISC_LINK_INIT(sa, link);
2087 ISC_LIST_APPEND(uctx->servers, sa, link);
2094 dns_client_freeresanswer(uctx->client, &rev->answerlist);
2095 isc_event_free(&event);
2098 if (uctx->restrans == NULL && uctx->restrans2 == NULL)
2099 completed = ISC_TRUE;
2100 UNLOCK(&uctx->lock);
2103 INSIST(uctx->currentserver == NULL);
2104 uctx->currentserver = ISC_LIST_HEAD(uctx->servers);
2105 if (uctx->currentserver != NULL && !uctx->canceled)
2108 if (result == ISC_R_SUCCESS)
2109 result = ISC_R_NOTFOUND;
2110 update_sendevent(uctx, result);
2116 process_soa(updatectx_t *uctx, dns_rdataset_t *soaset, dns_name_t *soaname) {
2117 isc_result_t result;
2118 dns_rdata_t soarr = DNS_RDATA_INIT;
2119 dns_rdata_soa_t soa;
2122 result = dns_rdataset_first(soaset);
2123 if (result != ISC_R_SUCCESS)
2125 dns_rdata_init(&soarr);
2126 dns_rdataset_current(soaset, &soarr);
2127 result = dns_rdata_tostruct(&soarr, &soa, NULL);
2128 if (result != ISC_R_SUCCESS)
2131 dns_name_init(&primary, NULL);
2132 dns_name_clone(&soa.origin, &primary);
2134 if (uctx->zonename == NULL) {
2135 uctx->zonename = dns_fixedname_name(&uctx->zonefname);
2136 result = dns_name_copy(soaname, uctx->zonename, NULL);
2137 if (result != ISC_R_SUCCESS)
2141 if (uctx->currentserver != NULL)
2142 result = send_update(uctx);
2145 * Get addresses of the primary server. We don't use the ADB
2146 * feature so that we could avoid caching data.
2150 result = dns_client_startresolve(uctx->client, &primary,
2153 0, uctx->client->task,
2154 resolveaddr_done, &uctx->bp4,
2156 if (result == ISC_R_SUCCESS) {
2158 result = dns_client_startresolve(uctx->client,
2162 0, uctx->client->task,
2167 UNLOCK(&uctx->lock);
2171 dns_rdata_freestruct(&soa);
2177 receive_soa(isc_task_t *task, isc_event_t *event) {
2178 dns_requestevent_t *reqev = NULL;
2180 dns_client_t *client;
2181 isc_result_t result, eresult;
2182 dns_request_t *request;
2183 dns_message_t *rcvmsg = NULL;
2184 dns_section_t section;
2185 dns_rdataset_t *soaset = NULL;
2188 dns_message_t *soaquery = NULL;
2189 isc_sockaddr_t *addr;
2190 isc_boolean_t seencname = ISC_FALSE;
2191 isc_boolean_t droplabel = ISC_FALSE;
2193 unsigned int nlabels;
2197 REQUIRE(event->ev_type == DNS_EVENT_REQUESTDONE);
2198 reqev = (dns_requestevent_t *)event;
2199 request = reqev->request;
2200 result = eresult = reqev->result;
2202 uctx = reqev->ev_arg;
2203 client = uctx->client;
2204 soaquery = uctx->soaquery;
2205 addr = uctx->currentserver;
2206 INSIST(addr != NULL);
2208 isc_event_free(&event);
2210 if (eresult != ISC_R_SUCCESS) {
2215 result = dns_message_create(uctx->client->mctx,
2216 DNS_MESSAGE_INTENTPARSE, &rcvmsg);
2217 if (result != ISC_R_SUCCESS)
2219 result = dns_request_getresponse(request, rcvmsg,
2220 DNS_MESSAGEPARSE_PRESERVEORDER);
2222 if (result == DNS_R_TSIGERRORSET) {
2223 dns_request_t *newrequest = NULL;
2225 /* Retry SOA request without TSIG */
2226 dns_message_destroy(&rcvmsg);
2227 dns_message_renderreset(uctx->soaquery);
2228 result = dns_request_createvia3(uctx->view->requestmgr,
2229 uctx->soaquery, NULL, addr, 0,
2231 client->find_timeout * 20,
2232 client->find_timeout, 3,
2236 if (result == ISC_R_SUCCESS) {
2238 dns_request_destroy(&uctx->soareq);
2239 uctx->soareq = newrequest;
2240 UNLOCK(&uctx->lock);
2247 section = DNS_SECTION_ANSWER;
2250 if (rcvmsg->rcode != dns_rcode_noerror &&
2251 rcvmsg->rcode != dns_rcode_nxdomain) {
2252 result = rcode2result(rcvmsg->rcode);
2258 section = DNS_SECTION_ANSWER;
2260 section = DNS_SECTION_AUTHORITY;
2262 droplabel = ISC_TRUE;
2266 result = dns_message_firstname(rcvmsg, section);
2267 if (result != ISC_R_SUCCESS) {
2271 while (result == ISC_R_SUCCESS) {
2273 dns_message_currentname(rcvmsg, section, &name);
2275 result = dns_message_findtype(name, dns_rdatatype_soa, 0,
2277 if (result == ISC_R_SUCCESS)
2279 if (section == DNS_SECTION_ANSWER) {
2280 dns_rdataset_t *tset = NULL;
2281 if (dns_message_findtype(name, dns_rdatatype_cname, 0,
2282 &tset) == ISC_R_SUCCESS
2284 dns_message_findtype(name, dns_rdatatype_dname, 0,
2285 &tset) == ISC_R_SUCCESS
2288 seencname = ISC_TRUE;
2293 result = dns_message_nextname(rcvmsg, section);
2296 if (soaset == NULL && !seencname) {
2302 droplabel = ISC_TRUE;
2306 result = process_soa(uctx, soaset, name);
2310 result = dns_message_firstname(soaquery, DNS_SECTION_QUESTION);
2311 INSIST(result == ISC_R_SUCCESS);
2313 dns_message_currentname(soaquery, DNS_SECTION_QUESTION, &name);
2314 nlabels = dns_name_countlabels(name);
2316 result = DNS_R_SERVFAIL; /* is there a better error? */
2318 dns_name_init(&tname, NULL);
2319 dns_name_getlabelsequence(name, 1, nlabels - 1,
2321 dns_name_clone(&tname, name);
2322 dns_request_destroy(&request);
2324 uctx->soareq = NULL;
2325 UNLOCK(&uctx->lock);
2326 dns_message_renderreset(soaquery);
2327 dns_message_settsigkey(soaquery, NULL);
2328 result = dns_request_createvia3(uctx->view->requestmgr,
2330 uctx->currentserver, 0,
2332 client->find_timeout *
2334 client->find_timeout,
2341 if (!droplabel || result != ISC_R_SUCCESS) {
2342 dns_message_destroy(&uctx->soaquery);
2344 dns_request_destroy(&uctx->soareq);
2345 UNLOCK(&uctx->lock);
2349 dns_message_destroy(&rcvmsg);
2351 if (result != ISC_R_SUCCESS)
2352 update_sendevent(uctx, result);
2356 request_soa(updatectx_t *uctx) {
2357 isc_result_t result;
2358 dns_message_t *soaquery = uctx->soaquery;
2359 dns_name_t *name = NULL;
2360 dns_rdataset_t *rdataset = NULL;
2362 if (soaquery == NULL) {
2363 result = dns_message_create(uctx->client->mctx,
2364 DNS_MESSAGE_INTENTRENDER,
2366 if (result != ISC_R_SUCCESS)
2369 soaquery->flags |= DNS_MESSAGEFLAG_RD;
2370 result = dns_message_gettempname(soaquery, &name);
2371 if (result != ISC_R_SUCCESS)
2373 result = dns_message_gettemprdataset(soaquery, &rdataset);
2374 if (result != ISC_R_SUCCESS)
2376 dns_rdataset_makequestion(rdataset, uctx->rdclass, dns_rdatatype_soa);
2377 dns_name_clone(uctx->firstname, name);
2378 ISC_LIST_APPEND(name->list, rdataset, link);
2379 dns_message_addname(soaquery, name, DNS_SECTION_QUESTION);
2383 result = dns_request_createvia3(uctx->view->requestmgr,
2384 soaquery, NULL, uctx->currentserver, 0,
2386 uctx->client->find_timeout * 20,
2387 uctx->client->find_timeout, 3,
2388 uctx->client->task, receive_soa, uctx,
2390 if (result == ISC_R_SUCCESS) {
2391 uctx->soaquery = soaquery;
2392 return (ISC_R_SUCCESS);
2396 if (rdataset != NULL) {
2397 ISC_LIST_UNLINK(name->list, rdataset, link); /* for safety */
2398 dns_message_puttemprdataset(soaquery, &rdataset);
2401 dns_message_puttempname(soaquery, &name);
2402 dns_message_destroy(&soaquery);
2408 resolvesoa_done(isc_task_t *task, isc_event_t *event) {
2409 dns_clientresevent_t *rev = (dns_clientresevent_t *)event;
2411 dns_name_t *name, tname;
2412 dns_rdataset_t *rdataset = NULL;
2413 isc_result_t result = rev->result;
2414 unsigned int nlabels;
2418 uctx = event->ev_arg;
2419 REQUIRE(UCTX_VALID(uctx));
2422 dns_client_destroyrestrans(&uctx->restrans);
2423 UNLOCK(&uctx->lock);
2425 uctx = event->ev_arg;
2426 if (result != ISC_R_SUCCESS &&
2427 result != DNS_R_NCACHENXDOMAIN &&
2428 result != DNS_R_NCACHENXRRSET) {
2429 /* XXX: what about DNSSEC failure? */
2433 for (name = ISC_LIST_HEAD(rev->answerlist); name != NULL;
2434 name = ISC_LIST_NEXT(name, link)) {
2435 for (rdataset = ISC_LIST_HEAD(name->list);
2437 rdataset = ISC_LIST_NEXT(rdataset, link)) {
2438 if (dns_rdataset_isassociated(rdataset) &&
2439 rdataset->type == dns_rdatatype_soa)
2444 if (rdataset == NULL) {
2445 /* Drop one label and retry resolution. */
2446 nlabels = dns_name_countlabels(&uctx->soaqname);
2448 result = DNS_R_SERVFAIL; /* is there a better error? */
2451 dns_name_init(&tname, NULL);
2452 dns_name_getlabelsequence(&uctx->soaqname, 1, nlabels - 1,
2454 dns_name_clone(&tname, &uctx->soaqname);
2456 result = dns_client_startresolve(uctx->client, &uctx->soaqname,
2458 dns_rdatatype_soa, 0,
2460 resolvesoa_done, uctx,
2463 result = process_soa(uctx, rdataset, &uctx->soaqname);
2466 dns_client_freeresanswer(uctx->client, &rev->answerlist);
2467 isc_event_free(&event);
2469 if (result != ISC_R_SUCCESS)
2470 update_sendevent(uctx, result);
2474 copy_name(isc_mem_t *mctx, dns_message_t *msg, dns_name_t *name,
2475 dns_name_t **newnamep)
2477 isc_result_t result;
2478 dns_name_t *newname = NULL;
2480 isc_buffer_t *namebuf = NULL, *rdatabuf = NULL;
2481 dns_rdatalist_t *rdatalist;
2482 dns_rdataset_t *rdataset, *newrdataset;
2483 dns_rdata_t rdata = DNS_RDATA_INIT, *newrdata;
2485 result = dns_message_gettempname(msg, &newname);
2486 if (result != ISC_R_SUCCESS)
2488 result = isc_buffer_allocate(mctx, &namebuf, DNS_NAME_MAXWIRE);
2489 if (result != ISC_R_SUCCESS)
2491 dns_name_init(newname, NULL);
2492 dns_name_setbuffer(newname, namebuf);
2493 dns_message_takebuffer(msg, &namebuf);
2494 result = dns_name_copy(name, newname, NULL);
2495 if (result != ISC_R_SUCCESS)
2498 for (rdataset = ISC_LIST_HEAD(name->list); rdataset != NULL;
2499 rdataset = ISC_LIST_NEXT(rdataset, link)) {
2501 result = dns_message_gettemprdatalist(msg, &rdatalist);
2502 if (result != ISC_R_SUCCESS)
2504 dns_rdatalist_init(rdatalist);
2505 rdatalist->type = rdataset->type;
2506 rdatalist->rdclass = rdataset->rdclass;
2507 rdatalist->covers = rdataset->covers;
2508 rdatalist->ttl = rdataset->ttl;
2510 result = dns_rdataset_first(rdataset);
2511 while (result == ISC_R_SUCCESS) {
2512 dns_rdata_reset(&rdata);
2513 dns_rdataset_current(rdataset, &rdata);
2516 result = dns_message_gettemprdata(msg, &newrdata);
2517 if (result != ISC_R_SUCCESS)
2519 dns_rdata_toregion(&rdata, &r);
2521 result = isc_buffer_allocate(mctx, &rdatabuf,
2523 if (result != ISC_R_SUCCESS)
2525 isc_buffer_putmem(rdatabuf, r.base, r.length);
2526 isc_buffer_usedregion(rdatabuf, &r);
2527 dns_rdata_init(newrdata);
2528 dns_rdata_fromregion(newrdata, rdata.rdclass,
2530 newrdata->flags = rdata.flags;
2532 ISC_LIST_APPEND(rdatalist->rdata, newrdata, link);
2533 dns_message_takebuffer(msg, &rdatabuf);
2535 result = dns_rdataset_next(rdataset);
2539 result = dns_message_gettemprdataset(msg, &newrdataset);
2540 if (result != ISC_R_SUCCESS)
2542 dns_rdataset_init(newrdataset);
2543 dns_rdatalist_tordataset(rdatalist, newrdataset);
2545 ISC_LIST_APPEND(newname->list, newrdataset, link);
2548 *newnamep = newname;
2550 return (ISC_R_SUCCESS);
2553 dns_message_puttempname(msg, &newname);
2560 internal_update_callback(isc_task_t *task, isc_event_t *event) {
2561 updatearg_t *uarg = event->ev_arg;
2562 dns_clientupdateevent_t *uev = (dns_clientupdateevent_t *)event;
2568 uarg->result = uev->result;
2570 dns_client_destroyupdatetrans(&uarg->trans);
2571 isc_event_free(&event);
2573 if (!uarg->canceled) {
2574 UNLOCK(&uarg->lock);
2576 /* Exit from the internal event loop */
2577 isc_app_ctxsuspend(uarg->actx);
2580 * We have already exited from the loop (due to some
2581 * unexpected event). Just clean the arg up.
2583 UNLOCK(&uarg->lock);
2584 DESTROYLOCK(&uarg->lock);
2585 isc_mem_put(uarg->client->mctx, uarg, sizeof(*uarg));
2590 dns_client_update(dns_client_t *client, dns_rdataclass_t rdclass,
2591 dns_name_t *zonename, dns_namelist_t *prerequisites,
2592 dns_namelist_t *updates, isc_sockaddrlist_t *servers,
2593 dns_tsec_t *tsec, unsigned int options)
2595 isc_result_t result;
2599 REQUIRE(DNS_CLIENT_VALID(client));
2601 if ((client->attributes & DNS_CLIENTATTR_OWNCTX) == 0 &&
2602 (options & DNS_CLIENTRESOPT_ALLOWRUN) == 0) {
2604 * If the client is run under application's control, we need
2605 * to create a new running (sub)environment for this
2606 * particular resolution.
2608 return (ISC_R_NOTIMPLEMENTED); /* XXXTBD */
2610 actx = client->actx;
2612 uarg = isc_mem_get(client->mctx, sizeof(*uarg));
2614 return (ISC_R_NOMEMORY);
2616 result = isc_mutex_init(&uarg->lock);
2617 if (result != ISC_R_SUCCESS) {
2618 isc_mem_put(client->mctx, uarg, sizeof(*uarg));
2623 uarg->client = client;
2624 uarg->result = ISC_R_FAILURE;
2626 uarg->canceled = ISC_FALSE;
2628 result = dns_client_startupdate(client, rdclass, zonename,
2629 prerequisites, updates, servers,
2630 tsec, options, client->task,
2631 internal_update_callback, uarg,
2633 if (result != ISC_R_SUCCESS) {
2634 DESTROYLOCK(&uarg->lock);
2635 isc_mem_put(client->mctx, uarg, sizeof(*uarg));
2640 * Start internal event loop. It blocks until the entire process
2643 result = isc_app_ctxrun(actx);
2646 if (result == ISC_R_SUCCESS || result == ISC_R_SUSPEND)
2647 result = uarg->result;
2649 if (uarg->trans != NULL) {
2651 * Unusual termination (perhaps due to signal). We need some
2652 * tricky cleanup process.
2654 uarg->canceled = ISC_TRUE;
2655 dns_client_cancelupdate(uarg->trans);
2657 UNLOCK(&uarg->lock);
2659 /* uarg will be freed in the event handler. */
2661 UNLOCK(&uarg->lock);
2663 DESTROYLOCK(&uarg->lock);
2664 isc_mem_put(client->mctx, uarg, sizeof(*uarg));
2671 dns_client_startupdate(dns_client_t *client, dns_rdataclass_t rdclass,
2672 dns_name_t *zonename, dns_namelist_t *prerequisites,
2673 dns_namelist_t *updates, isc_sockaddrlist_t *servers,
2674 dns_tsec_t *tsec, unsigned int options,
2675 isc_task_t *task, isc_taskaction_t action, void *arg,
2676 dns_clientupdatetrans_t **transp)
2678 dns_view_t *view = NULL;
2679 isc_result_t result;
2680 dns_name_t *name, *newname;
2682 isc_task_t *clone = NULL;
2683 dns_section_t section = DNS_SECTION_UPDATE;
2684 isc_sockaddr_t *server, *sa = NULL;
2685 dns_tsectype_t tsectype = dns_tsectype_none;
2689 REQUIRE(DNS_CLIENT_VALID(client));
2690 REQUIRE(transp != NULL && *transp == NULL);
2691 REQUIRE(updates != NULL);
2692 REQUIRE(task != NULL);
2695 tsectype = dns_tsec_gettype(tsec);
2696 if (tsectype != dns_tsectype_tsig)
2697 return (ISC_R_NOTIMPLEMENTED); /* XXX */
2700 LOCK(&client->lock);
2701 result = dns_viewlist_find(&client->viewlist, DNS_CLIENTVIEW_NAME,
2703 UNLOCK(&client->lock);
2704 if (result != ISC_R_SUCCESS)
2707 /* Create a context and prepare some resources */
2708 uctx = isc_mem_get(client->mctx, sizeof(*uctx));
2710 dns_view_detach(&view);
2711 return (ISC_R_NOMEMORY);
2713 result = isc_mutex_init(&uctx->lock);
2714 if (result != ISC_R_SUCCESS) {
2715 dns_view_detach(&view);
2716 isc_mem_put(client->mctx, uctx, sizeof(*uctx));
2717 return (ISC_R_NOMEMORY);
2720 isc_task_attach(task, &clone);
2721 uctx->client = client;
2722 ISC_LINK_INIT(uctx, link);
2723 uctx->state = dns_clientupdatestate_prepare;
2725 uctx->rdclass = rdclass;
2726 uctx->canceled = ISC_FALSE;
2727 uctx->updatemsg = NULL;
2728 uctx->soaquery = NULL;
2729 uctx->updatereq = NULL;
2730 uctx->restrans = NULL;
2731 uctx->restrans2 = NULL;
2734 uctx->soareq = NULL;
2736 uctx->tsigkey = NULL;
2737 uctx->sig0key = NULL;
2738 uctx->zonename = NULL;
2739 dns_name_init(&uctx->soaqname, NULL);
2740 ISC_LIST_INIT(uctx->servers);
2742 uctx->currentserver = NULL;
2743 dns_fixedname_init(&uctx->zonefname);
2745 dns_tsec_getkey(tsec, &uctx->tsigkey);
2746 uctx->event = (dns_clientupdateevent_t *)
2747 isc_event_allocate(client->mctx, clone, DNS_EVENT_UPDATEDONE,
2748 action, arg, sizeof(*uctx->event));
2749 if (uctx->event == NULL)
2751 if (zonename != NULL) {
2752 uctx->zonename = dns_fixedname_name(&uctx->zonefname);
2753 result = dns_name_copy(zonename, uctx->zonename, NULL);
2755 if (servers != NULL) {
2756 for (server = ISC_LIST_HEAD(*servers);
2758 server = ISC_LIST_NEXT(server, link)) {
2759 sa = isc_mem_get(client->mctx, sizeof(*sa));
2762 sa->type = server->type;
2763 sa->length = server->length;
2764 ISC_LINK_INIT(sa, link);
2765 ISC_LIST_APPEND(uctx->servers, sa, link);
2766 if (uctx->currentserver == NULL)
2767 uctx->currentserver = sa;
2772 /* Make update message */
2773 result = dns_message_create(client->mctx, DNS_MESSAGE_INTENTRENDER,
2775 if (result != ISC_R_SUCCESS)
2777 uctx->updatemsg->opcode = dns_opcode_update;
2779 if (prerequisites != NULL) {
2780 for (name = ISC_LIST_HEAD(*prerequisites); name != NULL;
2781 name = ISC_LIST_NEXT(name, link)) {
2783 result = copy_name(client->mctx, uctx->updatemsg,
2785 if (result != ISC_R_SUCCESS)
2787 dns_message_addname(uctx->updatemsg, newname,
2788 DNS_SECTION_PREREQUISITE);
2792 for (name = ISC_LIST_HEAD(*updates); name != NULL;
2793 name = ISC_LIST_NEXT(name, link)) {
2795 result = copy_name(client->mctx, uctx->updatemsg, name,
2797 if (result != ISC_R_SUCCESS)
2799 dns_message_addname(uctx->updatemsg, newname,
2800 DNS_SECTION_UPDATE);
2803 uctx->firstname = NULL;
2804 result = dns_message_firstname(uctx->updatemsg, section);
2805 if (result == ISC_R_NOMORE) {
2806 section = DNS_SECTION_PREREQUISITE;
2807 result = dns_message_firstname(uctx->updatemsg, section);
2809 if (result != ISC_R_SUCCESS)
2811 dns_message_currentname(uctx->updatemsg, section, &uctx->firstname);
2813 uctx->magic = UCTX_MAGIC;
2815 LOCK(&client->lock);
2816 ISC_LIST_APPEND(client->updatectxs, uctx, link);
2817 UNLOCK(&client->lock);
2819 if (uctx->zonename != NULL && uctx->currentserver != NULL) {
2820 result = send_update(uctx);
2821 if (result != ISC_R_SUCCESS)
2823 } else if (uctx->currentserver != NULL) {
2824 result = request_soa(uctx);
2825 if (result != ISC_R_SUCCESS)
2828 dns_name_clone(uctx->firstname, &uctx->soaqname);
2829 result = dns_client_startresolve(uctx->client, &uctx->soaqname,
2831 dns_rdatatype_soa, 0,
2832 client->task, resolvesoa_done,
2833 uctx, &uctx->restrans);
2834 if (result != ISC_R_SUCCESS)
2838 *transp = (dns_clientupdatetrans_t *)uctx;
2840 return (ISC_R_SUCCESS);
2843 if (ISC_LINK_LINKED(uctx, link)) {
2844 LOCK(&client->lock);
2845 ISC_LIST_UNLINK(client->updatectxs, uctx, link);
2846 UNLOCK(&client->lock);
2848 if (uctx->updatemsg != NULL)
2849 dns_message_destroy(&uctx->updatemsg);
2850 while ((sa = ISC_LIST_HEAD(uctx->servers)) != NULL) {
2851 ISC_LIST_UNLINK(uctx->servers, sa, link);
2852 isc_mem_put(client->mctx, sa, sizeof(*sa));
2854 if (uctx->event != NULL)
2855 isc_event_free(ISC_EVENT_PTR(&uctx->event));
2856 if (uctx->tsigkey != NULL)
2857 dns_tsigkey_detach(&uctx->tsigkey);
2858 isc_task_detach(&clone);
2859 DESTROYLOCK(&uctx->lock);
2861 isc_mem_put(client->mctx, uctx, sizeof(*uctx));
2862 dns_view_detach(&view);
2868 dns_client_cancelupdate(dns_clientupdatetrans_t *trans) {
2871 REQUIRE(trans != NULL);
2872 uctx = (updatectx_t *)trans;
2873 REQUIRE(UCTX_VALID(uctx));
2877 if (!uctx->canceled) {
2878 uctx->canceled = ISC_TRUE;
2879 if (uctx->updatereq != NULL)
2880 dns_request_cancel(uctx->updatereq);
2881 if (uctx->soareq != NULL)
2882 dns_request_cancel(uctx->soareq);
2883 if (uctx->restrans != NULL)
2884 dns_client_cancelresolve(uctx->restrans);
2885 if (uctx->restrans2 != NULL)
2886 dns_client_cancelresolve(uctx->restrans2);
2889 UNLOCK(&uctx->lock);
2893 dns_client_destroyupdatetrans(dns_clientupdatetrans_t **transp) {
2896 dns_client_t *client;
2897 isc_boolean_t need_destroyclient = ISC_FALSE;
2900 REQUIRE(transp != NULL);
2901 uctx = (updatectx_t *)*transp;
2902 REQUIRE(UCTX_VALID(uctx));
2903 client = uctx->client;
2904 REQUIRE(DNS_CLIENT_VALID(client));
2905 REQUIRE(uctx->updatereq == NULL && uctx->updatemsg == NULL &&
2906 uctx->soareq == NULL && uctx->soaquery == NULL &&
2907 uctx->event == NULL && uctx->tsigkey == NULL &&
2908 uctx->sig0key == NULL);
2910 mctx = client->mctx;
2911 dns_view_detach(&uctx->view);
2912 while ((sa = ISC_LIST_HEAD(uctx->servers)) != NULL) {
2913 ISC_LIST_UNLINK(uctx->servers, sa, link);
2914 isc_mem_put(mctx, sa, sizeof(*sa));
2917 LOCK(&client->lock);
2919 INSIST(ISC_LINK_LINKED(uctx, link));
2920 ISC_LIST_UNLINK(client->updatectxs, uctx, link);
2922 if (client->references == 0 && ISC_LIST_EMPTY(client->resctxs) &&
2923 ISC_LIST_EMPTY(client->reqctxs) &&
2924 ISC_LIST_EMPTY(client->updatectxs))
2925 need_destroyclient = ISC_TRUE;
2927 UNLOCK(&client->lock);
2929 DESTROYLOCK(&uctx->lock);
2932 isc_mem_put(mctx, uctx, sizeof(*uctx));
2934 if (need_destroyclient)
2935 destroyclient(&client);
2941 dns_client_mctx(dns_client_t *client) {
2943 REQUIRE(DNS_CLIENT_VALID(client));
2944 return (client->mctx);
2948 isc_buffer_t buffer;
2949 dns_rdataset_t rdataset;
2950 dns_rdatalist_t rdatalist;
2954 unsigned char data[FLEXIBLE_ARRAY_MEMBER];
2955 } dns_client_updaterec_t;
2958 dns_client_updaterec(dns_client_updateop_t op, dns_name_t *owner,
2959 dns_rdatatype_t type, dns_rdata_t *source,
2960 dns_ttl_t ttl, dns_name_t *target,
2961 dns_rdataset_t *rdataset, dns_rdatalist_t *rdatalist,
2962 dns_rdata_t *rdata, isc_mem_t *mctx)
2964 dns_client_updaterec_t *updaterec = NULL;
2965 size_t size = offsetof(dns_client_updaterec_t, data);
2967 REQUIRE(op < updateop_max);
2968 REQUIRE(owner != NULL);
2969 REQUIRE((rdataset != NULL && rdatalist != NULL && rdata != NULL) ||
2970 (rdataset == NULL && rdatalist == NULL && rdata == NULL &&
2972 if (op == updateop_add)
2973 REQUIRE(source != NULL);
2974 if (source != NULL) {
2975 REQUIRE(source->type == type);
2976 REQUIRE(op == updateop_add || op == updateop_delete ||
2977 op == updateop_exist);
2980 size += owner->length;
2982 size += source->length;
2984 if (rdataset == NULL) {
2985 updaterec = isc_mem_get(mctx, size);
2986 if (updaterec == NULL)
2987 return (ISC_R_NOMEMORY);
2988 rdataset = &updaterec->rdataset;
2989 rdatalist = &updaterec->rdatalist;
2990 rdata = &updaterec->rdata;
2991 dns_rdataset_init(rdataset);
2992 dns_rdatalist_init(&updaterec->rdatalist);
2993 dns_rdata_init(&updaterec->rdata);
2994 isc_buffer_init(&updaterec->buffer, updaterec->data,
2995 size - offsetof(dns_client_updaterec_t, data));
2996 dns_name_copy(owner, target, &updaterec->buffer);
2997 if (source != NULL) {
2999 dns_rdata_clone(source, rdata);
3000 dns_rdata_toregion(rdata, &r);
3001 rdata->data = isc_buffer_used(&updaterec->buffer);
3002 isc_buffer_copyregion(&updaterec->buffer, &r);
3004 updaterec->mctx = NULL;
3005 isc_mem_attach(mctx, &updaterec->mctx);
3006 } else if (source != NULL)
3007 dns_rdata_clone(source, rdata);
3012 case updateop_delete:
3013 if (source != NULL) {
3015 dns_rdata_makedelete(rdata);
3017 dns_rdata_deleterrset(rdata, type);
3019 case updateop_notexist:
3020 dns_rdata_notexist(rdata, type);
3022 case updateop_exist:
3023 if (source == NULL) {
3025 dns_rdata_exists(rdata, type);
3033 rdatalist->type = rdata->type;
3034 rdatalist->rdclass = rdata->rdclass;
3035 if (source != NULL) {
3036 rdatalist->covers = dns_rdata_covers(rdata);
3037 rdatalist->ttl = ttl;
3039 ISC_LIST_APPEND(rdatalist->rdata, rdata, link);
3040 dns_rdatalist_tordataset(rdatalist, rdataset);
3041 ISC_LIST_APPEND(target->list, rdataset, link);
3042 if (updaterec != NULL) {
3043 target->attributes |= DNS_NAMEATTR_HASUPDATEREC;
3044 dns_name_setbuffer(target, &updaterec->buffer);
3046 if (op == updateop_add || op == updateop_delete)
3047 target->attributes |= DNS_NAMEATTR_UPDATE;
3049 target->attributes |= DNS_NAMEATTR_PREREQUISITE;
3050 return (ISC_R_SUCCESS);
3054 dns_client_freeupdate(dns_name_t **namep) {
3055 dns_client_updaterec_t *updaterec;
3056 dns_rdatalist_t *rdatalist;
3057 dns_rdataset_t *rdataset;
3061 REQUIRE(namep != NULL && *namep != NULL);
3064 for (rdataset = ISC_LIST_HEAD(name->list);
3066 rdataset = ISC_LIST_HEAD(name->list)) {
3067 ISC_LIST_UNLINK(name->list, rdataset, link);
3069 dns_rdatalist_fromrdataset(rdataset, &rdatalist);
3070 if (rdatalist == NULL) {
3071 dns_rdataset_disassociate(rdataset);
3074 for (rdata = ISC_LIST_HEAD(rdatalist->rdata);
3076 rdata = ISC_LIST_HEAD(rdatalist->rdata))
3077 ISC_LIST_UNLINK(rdatalist->rdata, rdata, link);
3078 dns_rdataset_disassociate(rdataset);
3081 if ((name->attributes & DNS_NAMEATTR_HASUPDATEREC) != 0) {
3082 updaterec = (dns_client_updaterec_t *)name->buffer;
3083 INSIST(updaterec != NULL);
3084 isc_mem_putanddetach(&updaterec->mctx, updaterec,