2 * Copyright (C) 2009, 2010 Internet Systems Consortium, Inc. ("ISC")
4 * Permission to use, copy, modify, and/or distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
8 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
9 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
10 * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
11 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
12 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
13 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
14 * PERFORMANCE OF THIS SOFTWARE.
17 /* $Id: client.c,v 1.12 2010-12-03 12:03:22 marka Exp $ */
25 #include <isc/mutex.h>
26 #include <isc/sockaddr.h>
27 #include <isc/socket.h>
29 #include <isc/timer.h>
33 #include <dns/client.h>
35 #include <dns/dispatch.h>
36 #include <dns/events.h>
37 #include <dns/forward.h>
38 #include <dns/keytable.h>
39 #include <dns/message.h>
41 #include <dns/rdata.h>
42 #include <dns/rdatalist.h>
43 #include <dns/rdataset.h>
44 #include <dns/rdatatype.h>
45 #include <dns/rdatasetiter.h>
46 #include <dns/rdatastruct.h>
47 #include <dns/request.h>
48 #include <dns/resolver.h>
49 #include <dns/result.h>
56 #define DNS_CLIENT_MAGIC ISC_MAGIC('D', 'N', 'S', 'c')
57 #define DNS_CLIENT_VALID(c) ISC_MAGIC_VALID(c, DNS_CLIENT_MAGIC)
59 #define RCTX_MAGIC ISC_MAGIC('R', 'c', 't', 'x')
60 #define RCTX_VALID(c) ISC_MAGIC_VALID(c, RCTX_MAGIC)
62 #define REQCTX_MAGIC ISC_MAGIC('R', 'q', 'c', 'x')
63 #define REQCTX_VALID(c) ISC_MAGIC_VALID(c, REQCTX_MAGIC)
65 #define UCTX_MAGIC ISC_MAGIC('U', 'c', 't', 'x')
66 #define UCTX_VALID(c) ISC_MAGIC_VALID(c, UCTX_MAGIC)
68 #define MAX_RESTARTS 16
76 unsigned int attributes;
80 isc_taskmgr_t *taskmgr;
82 isc_socketmgr_t *socketmgr;
83 isc_timermgr_t *timermgr;
84 dns_dispatchmgr_t *dispatchmgr;
85 dns_dispatch_t *dispatchv4;
86 dns_dispatch_t *dispatchv6;
88 unsigned int update_timeout;
89 unsigned int update_udptimeout;
90 unsigned int update_udpretries;
91 unsigned int find_timeout;
92 unsigned int find_udpretries;
95 unsigned int references;
96 dns_viewlist_t viewlist;
97 ISC_LIST(struct resctx) resctxs;
98 ISC_LIST(struct reqctx) reqctxs;
99 ISC_LIST(struct updatectx) updatectxs;
103 * Timeout/retry constants for dynamic update borrowed from nsupdate
105 #define DEF_UPDATE_TIMEOUT 300
106 #define MIN_UPDATE_TIMEOUT 30
107 #define DEF_UPDATE_UDPTIMEOUT 3
108 #define DEF_UPDATE_UDPRETRIES 3
110 #define DEF_FIND_TIMEOUT 5
111 #define DEF_FIND_UDPRETRIES 3
113 #define DNS_CLIENTATTR_OWNCTX 0x01
115 #define DNS_CLIENTVIEW_NAME "dnsclient"
118 * Internal state for a single name resolution procedure
120 typedef struct resctx {
124 dns_client_t *client;
125 isc_boolean_t want_dnssec;
128 ISC_LINK(struct resctx) link;
131 unsigned int restarts;
132 dns_fixedname_t name;
133 dns_rdatatype_t type;
135 dns_namelist_t namelist;
137 dns_clientresevent_t *event;
138 isc_boolean_t canceled;
139 dns_rdataset_t *rdataset;
140 dns_rdataset_t *sigrdataset;
144 * Argument of an internal event for synchronous name resolution.
146 typedef struct resarg {
149 dns_client_t *client;
154 isc_result_t vresult;
155 dns_namelist_t *namelist;
156 dns_clientrestrans_t *trans;
157 isc_boolean_t canceled;
161 * Internal state for a single DNS request
163 typedef struct reqctx {
167 dns_client_t *client;
168 unsigned int parseoptions;
171 ISC_LINK(struct reqctx) link;
172 isc_boolean_t canceled;
173 dns_tsigkey_t *tsigkey;
174 dns_request_t *request;
175 dns_clientreqevent_t *event;
179 * Argument of an internal event for synchronous DNS request.
181 typedef struct reqarg {
184 dns_client_t *client;
189 dns_clientreqtrans_t *trans;
190 isc_boolean_t canceled;
194 * Argument of an internal event for synchronous name resolution.
196 typedef struct updatearg {
199 dns_client_t *client;
204 dns_clientupdatetrans_t *trans;
205 isc_boolean_t canceled;
209 * Internal state for a single dynamic update procedure
211 typedef struct updatectx {
215 dns_client_t *client;
218 dns_request_t *updatereq;
219 dns_request_t *soareq;
220 dns_clientrestrans_t *restrans;
221 dns_clientrestrans_t *restrans2;
222 isc_boolean_t canceled;
225 ISC_LINK(struct updatectx) link;
226 dns_clientupdatestate_t state;
227 dns_rdataclass_t rdclass;
229 dns_message_t *updatemsg;
230 dns_message_t *soaquery;
231 dns_clientupdateevent_t *event;
232 dns_tsigkey_t *tsigkey;
234 dns_name_t *firstname;
236 dns_fixedname_t zonefname;
237 dns_name_t *zonename;
238 isc_sockaddrlist_t servers;
239 unsigned int nservers;
240 isc_sockaddr_t *currentserver;
241 struct updatectx *bp4;
242 struct updatectx *bp6;
245 static isc_result_t request_soa(updatectx_t *uctx);
246 static void client_resfind(resctx_t *rctx, dns_fetchevent_t *event);
247 static isc_result_t send_update(updatectx_t *uctx);
250 getudpdispatch(int family, dns_dispatchmgr_t *dispatchmgr,
251 isc_socketmgr_t *socketmgr, isc_taskmgr_t *taskmgr,
252 isc_boolean_t is_shared, dns_dispatch_t **dispp)
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 result = isc_mem_create(0, 0, &mctx);
359 if (result != ISC_R_SUCCESS)
361 result = isc_appctx_create(mctx, &actx);
362 if (result != ISC_R_SUCCESS)
364 result = isc_app_ctxstart(actx);
365 if (result != ISC_R_SUCCESS)
367 result = isc_taskmgr_createinctx(mctx, actx, 1, 0, &taskmgr);
368 if (result != ISC_R_SUCCESS)
370 result = isc_socketmgr_createinctx(mctx, actx, &socketmgr);
371 if (result != ISC_R_SUCCESS)
373 result = isc_timermgr_createinctx(mctx, actx, &timermgr);
374 if (result != ISC_R_SUCCESS)
377 result = dns_client_createx(mctx, actx, taskmgr, socketmgr, timermgr,
379 if (result != ISC_R_SUCCESS)
382 (*clientp)->attributes |= DNS_CLIENTATTR_OWNCTX;
384 /* client has its own reference to mctx, so we can detach it here */
385 isc_mem_detach(&mctx);
387 return (ISC_R_SUCCESS);
391 isc_taskmgr_destroy(&taskmgr);
392 if (timermgr != NULL)
393 isc_timermgr_destroy(&timermgr);
394 if (socketmgr != NULL)
395 isc_socketmgr_destroy(&socketmgr);
397 isc_appctx_destroy(&actx);
398 isc_mem_detach(&mctx);
404 dns_client_createx(isc_mem_t *mctx, isc_appctx_t *actx, isc_taskmgr_t *taskmgr,
405 isc_socketmgr_t *socketmgr, isc_timermgr_t *timermgr,
406 unsigned int options, dns_client_t **clientp)
408 dns_client_t *client;
410 dns_dispatchmgr_t *dispatchmgr = NULL;
411 dns_dispatch_t *dispatchv4 = NULL;
412 dns_dispatch_t *dispatchv6 = NULL;
413 dns_view_t *view = NULL;
415 REQUIRE(mctx != NULL);
416 REQUIRE(taskmgr != NULL);
417 REQUIRE(timermgr != NULL);
418 REQUIRE(socketmgr != NULL);
419 REQUIRE(clientp != NULL && *clientp == NULL);
421 client = isc_mem_get(mctx, sizeof(*client));
423 return (ISC_R_NOMEMORY);
425 result = isc_mutex_init(&client->lock);
426 if (result != ISC_R_SUCCESS) {
427 isc_mem_put(mctx, client, sizeof(*client));
432 client->taskmgr = taskmgr;
433 client->socketmgr = socketmgr;
434 client->timermgr = timermgr;
437 result = isc_task_create(client->taskmgr, 0, &client->task);
438 if (result != ISC_R_SUCCESS)
441 result = dns_dispatchmgr_create(mctx, NULL, &dispatchmgr);
442 if (result != ISC_R_SUCCESS)
444 client->dispatchmgr = dispatchmgr;
446 /* TODO: whether to use dispatch v4 or v6 should be configurable */
447 client->dispatchv4 = NULL;
448 client->dispatchv6 = NULL;
449 result = getudpdispatch(AF_INET, dispatchmgr, socketmgr,
450 taskmgr, ISC_TRUE, &dispatchv4);
451 if (result == ISC_R_SUCCESS)
452 client->dispatchv4 = dispatchv4;
453 result = getudpdispatch(AF_INET6, dispatchmgr, socketmgr,
454 taskmgr, ISC_TRUE, &dispatchv6);
455 if (result == ISC_R_SUCCESS)
456 client->dispatchv6 = dispatchv6;
458 /* We need at least one of the dispatchers */
459 if (dispatchv4 == NULL && dispatchv6 == NULL) {
460 INSIST(result != ISC_R_SUCCESS);
464 /* Create the default view for class IN */
465 result = dns_client_createview(mctx, dns_rdataclass_in, options,
466 taskmgr, 31, socketmgr, timermgr,
467 dispatchmgr, dispatchv4, dispatchv6,
469 if (result != ISC_R_SUCCESS)
471 ISC_LIST_INIT(client->viewlist);
472 ISC_LIST_APPEND(client->viewlist, view, link);
474 dns_view_freeze(view); /* too early? */
476 ISC_LIST_INIT(client->resctxs);
477 ISC_LIST_INIT(client->reqctxs);
478 ISC_LIST_INIT(client->updatectxs);
481 isc_mem_attach(mctx, &client->mctx);
483 client->update_timeout = DEF_UPDATE_TIMEOUT;
484 client->update_udptimeout = DEF_UPDATE_UDPTIMEOUT;
485 client->update_udpretries = DEF_UPDATE_UDPRETRIES;
486 client->find_timeout = DEF_FIND_TIMEOUT;
487 client->find_udpretries = DEF_FIND_UDPRETRIES;
489 client->references = 1;
490 client->magic = DNS_CLIENT_MAGIC;
494 return (ISC_R_SUCCESS);
497 if (dispatchv4 != NULL)
498 dns_dispatch_detach(&dispatchv4);
499 if (dispatchv6 != NULL)
500 dns_dispatch_detach(&dispatchv6);
501 if (dispatchmgr != NULL)
502 dns_dispatchmgr_destroy(&dispatchmgr);
503 if (client->task != NULL)
504 isc_task_detach(&client->task);
505 isc_mem_put(mctx, client, sizeof(*client));
511 destroyclient(dns_client_t **clientp) {
512 dns_client_t *client = *clientp;
515 while ((view = ISC_LIST_HEAD(client->viewlist)) != NULL) {
516 ISC_LIST_UNLINK(client->viewlist, view, link);
517 dns_view_detach(&view);
520 if (client->dispatchv4 != NULL)
521 dns_dispatch_detach(&client->dispatchv4);
522 if (client->dispatchv6 != NULL)
523 dns_dispatch_detach(&client->dispatchv6);
525 dns_dispatchmgr_destroy(&client->dispatchmgr);
527 isc_task_detach(&client->task);
530 * If the client has created its own running environments,
533 if ((client->attributes & DNS_CLIENTATTR_OWNCTX) != 0) {
534 isc_taskmgr_destroy(&client->taskmgr);
535 isc_timermgr_destroy(&client->timermgr);
536 isc_socketmgr_destroy(&client->socketmgr);
538 isc_app_ctxfinish(client->actx);
539 isc_appctx_destroy(&client->actx);
542 DESTROYLOCK(&client->lock);
545 isc_mem_putanddetach(&client->mctx, client, sizeof(*client));
551 dns_client_destroy(dns_client_t **clientp) {
552 dns_client_t *client;
553 isc_boolean_t destroyok = ISC_FALSE;
555 REQUIRE(clientp != NULL);
557 REQUIRE(DNS_CLIENT_VALID(client));
560 client->references--;
561 if (client->references == 0 && ISC_LIST_EMPTY(client->resctxs) &&
562 ISC_LIST_EMPTY(client->reqctxs) &&
563 ISC_LIST_EMPTY(client->updatectxs)) {
564 destroyok = ISC_TRUE;
566 UNLOCK(&client->lock);
569 destroyclient(&client);
575 dns_client_setservers(dns_client_t *client, dns_rdataclass_t rdclass,
576 dns_name_t *namespace, isc_sockaddrlist_t *addrs)
579 dns_view_t *view = NULL;
581 REQUIRE(DNS_CLIENT_VALID(client));
582 REQUIRE(addrs != NULL);
584 if (namespace == NULL)
585 namespace = dns_rootname;
588 result = dns_viewlist_find(&client->viewlist, DNS_CLIENTVIEW_NAME,
590 if (result != ISC_R_SUCCESS) {
591 UNLOCK(&client->lock);
594 UNLOCK(&client->lock);
596 result = dns_fwdtable_add(view->fwdtable, namespace, addrs,
599 dns_view_detach(&view);
605 dns_client_clearservers(dns_client_t *client, dns_rdataclass_t rdclass,
606 dns_name_t *namespace)
609 dns_view_t *view = NULL;
611 REQUIRE(DNS_CLIENT_VALID(client));
613 if (namespace == NULL)
614 namespace = dns_rootname;
617 result = dns_viewlist_find(&client->viewlist, DNS_CLIENTVIEW_NAME,
619 if (result != ISC_R_SUCCESS) {
620 UNLOCK(&client->lock);
623 UNLOCK(&client->lock);
625 result = dns_fwdtable_delete(view->fwdtable, namespace);
627 dns_view_detach(&view);
633 getrdataset(isc_mem_t *mctx, dns_rdataset_t **rdatasetp) {
634 dns_rdataset_t *rdataset;
636 REQUIRE(mctx != NULL);
637 REQUIRE(rdatasetp != NULL && *rdatasetp == NULL);
639 rdataset = isc_mem_get(mctx, sizeof(*rdataset));
640 if (rdataset == NULL)
641 return (ISC_R_NOMEMORY);
643 dns_rdataset_init(rdataset);
645 *rdatasetp = rdataset;
647 return (ISC_R_SUCCESS);
651 putrdataset(isc_mem_t *mctx, dns_rdataset_t **rdatasetp) {
652 dns_rdataset_t *rdataset;
654 REQUIRE(rdatasetp != NULL);
655 rdataset = *rdatasetp;
656 REQUIRE(rdataset != NULL);
658 if (dns_rdataset_isassociated(rdataset))
659 dns_rdataset_disassociate(rdataset);
661 isc_mem_put(mctx, rdataset, sizeof(*rdataset));
667 fetch_done(isc_task_t *task, isc_event_t *event) {
668 resctx_t *rctx = event->ev_arg;
669 dns_fetchevent_t *fevent;
671 REQUIRE(event->ev_type == DNS_EVENT_FETCHDONE);
672 REQUIRE(RCTX_VALID(rctx));
673 REQUIRE(rctx->task == task);
674 fevent = (dns_fetchevent_t *)event;
676 client_resfind(rctx, fevent);
679 static inline isc_result_t
680 start_fetch(resctx_t *rctx) {
684 * The caller must be holding the rctx's lock.
687 REQUIRE(rctx->fetch == NULL);
689 result = dns_resolver_createfetch(rctx->view->resolver,
690 dns_fixedname_name(&rctx->name),
693 rctx->task, fetch_done, rctx,
702 view_find(resctx_t *rctx, dns_db_t **dbp, dns_dbnode_t **nodep,
703 dns_name_t *foundname)
706 dns_name_t *name = dns_fixedname_name(&rctx->name);
707 dns_rdatatype_t type;
709 if (rctx->type == dns_rdatatype_rrsig)
710 type = dns_rdatatype_any;
714 result = dns_view_find(rctx->view, name, type, 0, 0, ISC_FALSE,
715 dbp, nodep, foundname, rctx->rdataset,
722 client_resfind(resctx_t *rctx, dns_fetchevent_t *event) {
724 isc_result_t result, tresult;
725 isc_result_t vresult = ISC_R_SUCCESS;
726 isc_boolean_t want_restart;
727 isc_boolean_t send_event = ISC_FALSE;
728 dns_name_t *name, *prefix;
729 dns_fixedname_t foundname, fixed;
730 dns_rdataset_t *trdataset;
731 dns_rdata_t rdata = DNS_RDATA_INIT;
732 unsigned int nlabels;
734 dns_namereln_t namereln;
735 dns_rdata_cname_t cname;
736 dns_rdata_dname_t dname;
738 REQUIRE(RCTX_VALID(rctx));
742 mctx = rctx->view->mctx;
744 result = ISC_R_SUCCESS;
745 name = dns_fixedname_name(&rctx->name);
748 dns_name_t *fname = NULL;
749 dns_name_t *ansname = NULL;
751 dns_dbnode_t *node = NULL;
754 want_restart = ISC_FALSE;
756 if (event == NULL && !rctx->canceled) {
757 dns_fixedname_init(&foundname);
758 fname = dns_fixedname_name(&foundname);
759 INSIST(!dns_rdataset_isassociated(rctx->rdataset));
760 INSIST(rctx->sigrdataset == NULL ||
761 !dns_rdataset_isassociated(rctx->sigrdataset));
762 result = view_find(rctx, &db, &node, fname);
763 if (result == ISC_R_NOTFOUND) {
765 * We don't know anything about the name.
770 dns_db_detachnode(db, &node);
774 result = start_fetch(rctx);
775 if (result != ISC_R_SUCCESS) {
776 putrdataset(mctx, &rctx->rdataset);
777 if (rctx->sigrdataset != NULL)
780 send_event = ISC_TRUE;
785 INSIST(event->fetch == rctx->fetch);
786 dns_resolver_destroyfetch(&rctx->fetch);
789 result = event->result;
790 vresult = event->vresult;
791 fname = dns_fixedname_name(&event->foundname);
792 INSIST(event->rdataset == rctx->rdataset);
793 INSIST(event->sigrdataset == rctx->sigrdataset);
797 * If we've been canceled, forget about the result.
800 result = ISC_R_CANCELED;
803 * Otherwise, get some resource for copying the
806 ansname = isc_mem_get(mctx, sizeof(*ansname));
808 tresult = ISC_R_NOMEMORY;
812 aname = dns_fixedname_name(&rctx->name);
813 dns_name_init(ansname, NULL);
814 tresult = dns_name_dup(aname, mctx, ansname);
815 if (tresult != ISC_R_SUCCESS)
816 isc_mem_put(mctx, ansname,
819 if (tresult != ISC_R_SUCCESS)
825 send_event = ISC_TRUE;
827 * This case is handled in the main line below.
832 * Add the CNAME to the answer list.
834 trdataset = rctx->rdataset;
835 ISC_LIST_APPEND(ansname->list, rctx->rdataset, link);
836 rctx->rdataset = NULL;
837 if (rctx->sigrdataset != NULL) {
838 ISC_LIST_APPEND(ansname->list,
839 rctx->sigrdataset, link);
840 rctx->sigrdataset = NULL;
842 ISC_LIST_APPEND(rctx->namelist, ansname, link);
846 * Copy the CNAME's target into the lookup's
847 * query name and start over.
849 tresult = dns_rdataset_first(trdataset);
850 if (tresult != ISC_R_SUCCESS)
852 dns_rdataset_current(trdataset, &rdata);
853 tresult = dns_rdata_tostruct(&rdata, &cname, NULL);
854 dns_rdata_reset(&rdata);
855 if (tresult != ISC_R_SUCCESS)
857 tresult = dns_name_copy(&cname.cname, name, NULL);
858 dns_rdata_freestruct(&cname);
859 if (tresult == ISC_R_SUCCESS)
860 want_restart = ISC_TRUE;
866 * Add the DNAME to the answer list.
868 trdataset = rctx->rdataset;
869 ISC_LIST_APPEND(ansname->list, rctx->rdataset, link);
870 rctx->rdataset = NULL;
871 if (rctx->sigrdataset != NULL) {
872 ISC_LIST_APPEND(ansname->list,
873 rctx->sigrdataset, link);
874 rctx->sigrdataset = NULL;
876 ISC_LIST_APPEND(rctx->namelist, ansname, link);
879 namereln = dns_name_fullcompare(name, fname, &order,
881 INSIST(namereln == dns_namereln_subdomain);
883 * Get the target name of the DNAME.
885 tresult = dns_rdataset_first(trdataset);
886 if (tresult != ISC_R_SUCCESS) {
890 dns_rdataset_current(trdataset, &rdata);
891 tresult = dns_rdata_tostruct(&rdata, &dname, NULL);
892 dns_rdata_reset(&rdata);
893 if (tresult != ISC_R_SUCCESS) {
898 * Construct the new query name and start over.
900 dns_fixedname_init(&fixed);
901 prefix = dns_fixedname_name(&fixed);
902 dns_name_split(name, nlabels, prefix, NULL);
903 tresult = dns_name_concatenate(prefix, &dname.dname,
905 dns_rdata_freestruct(&dname);
906 if (tresult == ISC_R_SUCCESS)
907 want_restart = ISC_TRUE;
911 case DNS_R_NCACHENXDOMAIN:
912 case DNS_R_NCACHENXRRSET:
913 ISC_LIST_APPEND(ansname->list, rctx->rdataset, link);
914 ISC_LIST_APPEND(rctx->namelist, ansname, link);
916 rctx->rdataset = NULL;
917 /* What about sigrdataset? */
918 if (rctx->sigrdataset != NULL)
919 putrdataset(mctx, &rctx->sigrdataset);
920 send_event = ISC_TRUE;
923 if (rctx->rdataset != NULL)
924 putrdataset(mctx, &rctx->rdataset);
925 if (rctx->sigrdataset != NULL)
926 putrdataset(mctx, &rctx->sigrdataset);
927 send_event = ISC_TRUE;
931 if (rctx->type == dns_rdatatype_any) {
933 dns_rdatasetiter_t *rdsiter = NULL;
935 tresult = dns_db_allrdatasets(db, node, NULL, 0,
937 if (tresult != ISC_R_SUCCESS) {
942 tresult = dns_rdatasetiter_first(rdsiter);
943 while (tresult == ISC_R_SUCCESS) {
944 dns_rdatasetiter_current(rdsiter,
946 if (rctx->rdataset->type != 0) {
947 ISC_LIST_APPEND(ansname->list,
951 rctx->rdataset = NULL;
954 * We're not interested in this
957 dns_rdataset_disassociate(
960 tresult = dns_rdatasetiter_next(rdsiter);
962 if (tresult == ISC_R_SUCCESS &&
963 rctx->rdataset == NULL) {
964 tresult = getrdataset(mctx,
966 if (tresult != ISC_R_SUCCESS) {
974 * We didn't match any rdatasets (which means
975 * something went wrong in this
978 result = DNS_R_SERVFAIL; /* better code? */
980 ISC_LIST_APPEND(rctx->namelist, ansname, link);
983 dns_rdatasetiter_destroy(&rdsiter);
984 if (tresult != ISC_R_NOMORE)
985 result = DNS_R_SERVFAIL; /* ditto */
987 result = ISC_R_SUCCESS;
991 * This is the "normal" case -- an ordinary question
992 * to which we've got the answer.
994 ISC_LIST_APPEND(ansname->list, rctx->rdataset, link);
995 rctx->rdataset = NULL;
996 if (rctx->sigrdataset != NULL) {
997 ISC_LIST_APPEND(ansname->list,
998 rctx->sigrdataset, link);
999 rctx->sigrdataset = NULL;
1001 ISC_LIST_APPEND(rctx->namelist, ansname, link);
1007 * Free temporary resources
1009 if (ansname != NULL) {
1010 dns_rdataset_t *rdataset;
1012 while ((rdataset = ISC_LIST_HEAD(ansname->list))
1014 ISC_LIST_UNLINK(ansname->list, rdataset, link);
1015 putrdataset(mctx, &rdataset);
1017 dns_name_free(ansname, mctx);
1018 isc_mem_put(mctx, ansname, sizeof(*ansname));
1022 dns_db_detachnode(db, &node);
1026 isc_event_free(ISC_EVENT_PTR(&event));
1029 * Limit the number of restarts.
1031 if (want_restart && rctx->restarts == MAX_RESTARTS) {
1032 want_restart = ISC_FALSE;
1033 result = ISC_R_QUOTA;
1034 send_event = ISC_TRUE;
1038 * Prepare further find with new resources
1041 INSIST(rctx->rdataset == NULL &&
1042 rctx->sigrdataset == NULL);
1044 result = getrdataset(mctx, &rctx->rdataset);
1045 if (result == ISC_R_SUCCESS && rctx->want_dnssec) {
1046 result = getrdataset(mctx, &rctx->sigrdataset);
1047 if (result != ISC_R_SUCCESS) {
1048 putrdataset(mctx, &rctx->rdataset);
1052 if (result != ISC_R_SUCCESS) {
1053 want_restart = ISC_FALSE;
1054 send_event = ISC_TRUE;
1057 } while (want_restart);
1062 while ((name = ISC_LIST_HEAD(rctx->namelist)) != NULL) {
1063 ISC_LIST_UNLINK(rctx->namelist, name, link);
1064 ISC_LIST_APPEND(rctx->event->answerlist, name, link);
1067 rctx->event->result = result;
1068 rctx->event->vresult = vresult;
1069 task = rctx->event->ev_sender;
1070 rctx->event->ev_sender = rctx;
1071 isc_task_sendanddetach(&task, ISC_EVENT_PTR(&rctx->event));
1074 UNLOCK(&rctx->lock);
1078 resolve_done(isc_task_t *task, isc_event_t *event) {
1079 resarg_t *resarg = event->ev_arg;
1080 dns_clientresevent_t *rev = (dns_clientresevent_t *)event;
1085 LOCK(&resarg->lock);
1087 resarg->result = rev->result;
1088 resarg->vresult = rev->vresult;
1089 while ((name = ISC_LIST_HEAD(rev->answerlist)) != NULL) {
1090 ISC_LIST_UNLINK(rev->answerlist, name, link);
1091 ISC_LIST_APPEND(*resarg->namelist, name, link);
1094 dns_client_destroyrestrans(&resarg->trans);
1095 isc_event_free(&event);
1097 if (!resarg->canceled) {
1098 UNLOCK(&resarg->lock);
1100 /* Exit from the internal event loop */
1101 isc_app_ctxsuspend(resarg->actx);
1104 * We have already exited from the loop (due to some
1105 * unexpected event). Just clean the arg up.
1107 UNLOCK(&resarg->lock);
1108 DESTROYLOCK(&resarg->lock);
1109 isc_mem_put(resarg->client->mctx, resarg, sizeof(*resarg));
1114 dns_client_resolve(dns_client_t *client, dns_name_t *name,
1115 dns_rdataclass_t rdclass, dns_rdatatype_t type,
1116 unsigned int options, dns_namelist_t *namelist)
1118 isc_result_t result;
1122 REQUIRE(DNS_CLIENT_VALID(client));
1123 REQUIRE(namelist != NULL && ISC_LIST_EMPTY(*namelist));
1125 if ((client->attributes & DNS_CLIENTATTR_OWNCTX) == 0 &&
1126 (options & DNS_CLIENTRESOPT_ALLOWRUN) == 0) {
1128 * If the client is run under application's control, we need
1129 * to create a new running (sub)environment for this
1130 * particular resolution.
1132 return (ISC_R_NOTIMPLEMENTED); /* XXXTBD */
1134 actx = client->actx;
1136 resarg = isc_mem_get(client->mctx, sizeof(*resarg));
1138 return (ISC_R_NOMEMORY);
1140 result = isc_mutex_init(&resarg->lock);
1141 if (result != ISC_R_SUCCESS) {
1142 isc_mem_put(client->mctx, resarg, sizeof(*resarg));
1146 resarg->actx = actx;
1147 resarg->client = client;
1148 resarg->result = DNS_R_SERVFAIL;
1149 resarg->namelist = namelist;
1150 resarg->trans = NULL;
1151 resarg->canceled = ISC_FALSE;
1152 result = dns_client_startresolve(client, name, rdclass, type, options,
1153 client->task, resolve_done, resarg,
1155 if (result != ISC_R_SUCCESS) {
1156 DESTROYLOCK(&resarg->lock);
1157 isc_mem_put(client->mctx, resarg, sizeof(*resarg));
1162 * Start internal event loop. It blocks until the entire process
1165 result = isc_app_ctxrun(actx);
1167 LOCK(&resarg->lock);
1168 if (result == ISC_R_SUCCESS || result == ISC_R_SUSPEND)
1169 result = resarg->result;
1170 if (result != ISC_R_SUCCESS && resarg->vresult != ISC_R_SUCCESS) {
1172 * If this lookup failed due to some error in DNSSEC
1173 * validation, return the validation error code.
1174 * XXX: or should we pass the validation result separately?
1176 result = resarg->vresult;
1178 if (resarg->trans != NULL) {
1180 * Unusual termination (perhaps due to signal). We need some
1181 * tricky cleanup process.
1183 resarg->canceled = ISC_TRUE;
1184 dns_client_cancelresolve(resarg->trans);
1186 UNLOCK(&resarg->lock);
1188 /* resarg will be freed in the event handler. */
1190 UNLOCK(&resarg->lock);
1192 DESTROYLOCK(&resarg->lock);
1193 isc_mem_put(client->mctx, resarg, sizeof(*resarg));
1200 dns_client_startresolve(dns_client_t *client, dns_name_t *name,
1201 dns_rdataclass_t rdclass, dns_rdatatype_t type,
1202 unsigned int options, isc_task_t *task,
1203 isc_taskaction_t action, void *arg,
1204 dns_clientrestrans_t **transp)
1206 dns_view_t *view = NULL;
1207 dns_clientresevent_t *event = NULL;
1208 resctx_t *rctx = NULL;
1209 isc_task_t *clone = NULL;
1211 isc_result_t result;
1212 dns_rdataset_t *rdataset, *sigrdataset;
1213 isc_boolean_t want_dnssec;
1215 REQUIRE(DNS_CLIENT_VALID(client));
1216 REQUIRE(transp != NULL && *transp == NULL);
1218 LOCK(&client->lock);
1219 result = dns_viewlist_find(&client->viewlist, DNS_CLIENTVIEW_NAME,
1221 UNLOCK(&client->lock);
1222 if (result != ISC_R_SUCCESS)
1225 mctx = client->mctx;
1228 want_dnssec = ISC_TF((options & DNS_CLIENTRESOPT_NODNSSEC) == 0);
1231 * Prepare some intermediate resources
1234 isc_task_attach(task, &clone);
1235 event = (dns_clientresevent_t *)
1236 isc_event_allocate(mctx, clone, DNS_EVENT_CLIENTRESDONE,
1237 action, arg, sizeof(*event));
1238 if (event == NULL) {
1239 result = ISC_R_NOMEMORY;
1242 event->result = DNS_R_SERVFAIL;
1243 ISC_LIST_INIT(event->answerlist);
1245 rctx = isc_mem_get(mctx, sizeof(*rctx));
1247 result = ISC_R_NOMEMORY;
1249 result = isc_mutex_init(&rctx->lock);
1250 if (result != ISC_R_SUCCESS) {
1251 isc_mem_put(mctx, rctx, sizeof(*rctx));
1255 if (result != ISC_R_SUCCESS)
1258 result = getrdataset(mctx, &rdataset);
1259 if (result != ISC_R_SUCCESS)
1261 rctx->rdataset = rdataset;
1264 result = getrdataset(mctx, &sigrdataset);
1265 if (result != ISC_R_SUCCESS)
1268 rctx->sigrdataset = sigrdataset;
1270 dns_fixedname_init(&rctx->name);
1271 result = dns_name_copy(name, dns_fixedname_name(&rctx->name), NULL);
1272 if (result != ISC_R_SUCCESS)
1275 rctx->client = client;
1276 ISC_LINK_INIT(rctx, link);
1277 rctx->canceled = ISC_FALSE;
1278 rctx->task = client->task;
1283 rctx->want_dnssec = want_dnssec;
1284 ISC_LIST_INIT(rctx->namelist);
1285 rctx->event = event;
1287 rctx->magic = RCTX_MAGIC;
1289 LOCK(&client->lock);
1290 ISC_LIST_APPEND(client->resctxs, rctx, link);
1291 UNLOCK(&client->lock);
1293 client_resfind(rctx, NULL);
1295 *transp = (dns_clientrestrans_t *)rctx;
1297 return (ISC_R_SUCCESS);
1300 if (rdataset != NULL)
1301 putrdataset(client->mctx, &rdataset);
1302 if (sigrdataset != NULL)
1303 putrdataset(client->mctx, &sigrdataset);
1305 DESTROYLOCK(&rctx->lock);
1306 isc_mem_put(mctx, rctx, sizeof(*rctx));
1309 isc_event_free(ISC_EVENT_PTR(&event));
1310 isc_task_detach(&clone);
1311 dns_view_detach(&view);
1317 dns_client_cancelresolve(dns_clientrestrans_t *trans) {
1320 REQUIRE(trans != NULL);
1321 rctx = (resctx_t *)trans;
1322 REQUIRE(RCTX_VALID(rctx));
1326 if (!rctx->canceled) {
1327 rctx->canceled = ISC_TRUE;
1328 if (rctx->fetch != NULL)
1329 dns_resolver_cancelfetch(rctx->fetch);
1332 UNLOCK(&rctx->lock);
1336 dns_client_freeresanswer(dns_client_t *client, dns_namelist_t *namelist) {
1338 dns_rdataset_t *rdataset;
1340 REQUIRE(DNS_CLIENT_VALID(client));
1341 REQUIRE(namelist != NULL);
1343 while ((name = ISC_LIST_HEAD(*namelist)) != NULL) {
1344 ISC_LIST_UNLINK(*namelist, name, link);
1345 while ((rdataset = ISC_LIST_HEAD(name->list)) != NULL) {
1346 ISC_LIST_UNLINK(name->list, rdataset, link);
1347 putrdataset(client->mctx, &rdataset);
1349 dns_name_free(name, client->mctx);
1350 isc_mem_put(client->mctx, name, sizeof(*name));
1355 dns_client_destroyrestrans(dns_clientrestrans_t **transp) {
1358 dns_client_t *client;
1359 isc_boolean_t need_destroyclient = ISC_FALSE;
1361 REQUIRE(transp != NULL);
1362 rctx = (resctx_t *)*transp;
1363 REQUIRE(RCTX_VALID(rctx));
1364 REQUIRE(rctx->fetch == NULL);
1365 REQUIRE(rctx->event == NULL);
1366 client = rctx->client;
1367 REQUIRE(DNS_CLIENT_VALID(client));
1369 mctx = client->mctx;
1370 dns_view_detach(&rctx->view);
1372 LOCK(&client->lock);
1374 INSIST(ISC_LINK_LINKED(rctx, link));
1375 ISC_LIST_UNLINK(client->resctxs, rctx, link);
1377 if (client->references == 0 && ISC_LIST_EMPTY(client->resctxs) &&
1378 ISC_LIST_EMPTY(client->reqctxs) &&
1379 ISC_LIST_EMPTY(client->updatectxs))
1380 need_destroyclient = ISC_TRUE;
1382 UNLOCK(&client->lock);
1384 INSIST(ISC_LIST_EMPTY(rctx->namelist));
1386 DESTROYLOCK(&rctx->lock);
1389 isc_mem_put(mctx, rctx, sizeof(*rctx));
1391 if (need_destroyclient)
1392 destroyclient(&client);
1398 dns_client_addtrustedkey(dns_client_t *client, dns_rdataclass_t rdclass,
1399 dns_name_t *keyname, isc_buffer_t *keydatabuf)
1401 isc_result_t result;
1402 dns_view_t *view = NULL;
1403 dst_key_t *dstkey = NULL;
1404 dns_keytable_t *secroots = NULL;
1406 REQUIRE(DNS_CLIENT_VALID(client));
1408 LOCK(&client->lock);
1409 result = dns_viewlist_find(&client->viewlist, DNS_CLIENTVIEW_NAME,
1411 UNLOCK(&client->lock);
1412 if (result != ISC_R_SUCCESS)
1415 result = dns_view_getsecroots(view, &secroots);
1416 if (result != ISC_R_SUCCESS)
1419 result = dst_key_fromdns(keyname, rdclass, keydatabuf, client->mctx,
1421 if (result != ISC_R_SUCCESS)
1424 result = dns_keytable_add(secroots, ISC_FALSE, &dstkey);
1428 dst_key_free(&dstkey);
1430 dns_view_detach(&view);
1431 if (secroots != NULL)
1432 dns_keytable_detach(&secroots);
1437 * Simple request routines
1440 request_done(isc_task_t *task, isc_event_t *event) {
1441 dns_requestevent_t *reqev = NULL;
1442 dns_request_t *request;
1443 isc_result_t result, eresult;
1448 REQUIRE(event->ev_type == DNS_EVENT_REQUESTDONE);
1449 reqev = (dns_requestevent_t *)event;
1450 request = reqev->request;
1451 result = eresult = reqev->result;
1452 ctx = reqev->ev_arg;
1453 REQUIRE(REQCTX_VALID(ctx));
1455 isc_event_free(&event);
1459 if (eresult == ISC_R_SUCCESS) {
1460 result = dns_request_getresponse(request, ctx->event->rmessage,
1464 if (ctx->tsigkey != NULL)
1465 dns_tsigkey_detach(&ctx->tsigkey);
1468 ctx->event->result = ISC_R_CANCELED;
1470 ctx->event->result = result;
1471 task = ctx->event->ev_sender;
1472 ctx->event->ev_sender = ctx;
1473 isc_task_sendanddetach(&task, ISC_EVENT_PTR(&ctx->event));
1479 localrequest_done(isc_task_t *task, isc_event_t *event) {
1480 reqarg_t *reqarg = event->ev_arg;
1481 dns_clientreqevent_t *rev =(dns_clientreqevent_t *)event;
1485 REQUIRE(event->ev_type == DNS_EVENT_CLIENTREQDONE);
1487 LOCK(&reqarg->lock);
1489 reqarg->result = rev->result;
1490 dns_client_destroyreqtrans(&reqarg->trans);
1491 isc_event_free(&event);
1493 if (!reqarg->canceled) {
1494 UNLOCK(&reqarg->lock);
1496 /* Exit from the internal event loop */
1497 isc_app_ctxsuspend(reqarg->actx);
1500 * We have already exited from the loop (due to some
1501 * unexpected event). Just clean the arg up.
1503 UNLOCK(&reqarg->lock);
1504 DESTROYLOCK(&reqarg->lock);
1505 isc_mem_put(reqarg->client->mctx, reqarg, sizeof(*reqarg));
1510 dns_client_request(dns_client_t *client, dns_message_t *qmessage,
1511 dns_message_t *rmessage, isc_sockaddr_t *server,
1512 unsigned int options, unsigned int parseoptions,
1513 dns_tsec_t *tsec, unsigned int timeout,
1514 unsigned int udptimeout, unsigned int udpretries)
1518 isc_result_t result;
1520 REQUIRE(DNS_CLIENT_VALID(client));
1521 REQUIRE(qmessage != NULL);
1522 REQUIRE(rmessage != NULL);
1524 if ((client->attributes & DNS_CLIENTATTR_OWNCTX) == 0 &&
1525 (options & DNS_CLIENTREQOPT_ALLOWRUN) == 0) {
1527 * If the client is run under application's control, we need
1528 * to create a new running (sub)environment for this
1529 * particular resolution.
1531 return (ISC_R_NOTIMPLEMENTED); /* XXXTBD */
1533 actx = client->actx;
1535 reqarg = isc_mem_get(client->mctx, sizeof(*reqarg));
1537 return (ISC_R_NOMEMORY);
1539 result = isc_mutex_init(&reqarg->lock);
1540 if (result != ISC_R_SUCCESS) {
1541 isc_mem_put(client->mctx, reqarg, sizeof(*reqarg));
1545 reqarg->actx = actx;
1546 reqarg->client = client;
1547 reqarg->trans = NULL;
1548 reqarg->canceled = ISC_FALSE;
1550 result = dns_client_startrequest(client, qmessage, rmessage, server,
1551 options, parseoptions, tsec, timeout,
1552 udptimeout, udpretries,
1553 client->task, localrequest_done,
1554 reqarg, &reqarg->trans);
1555 if (result != ISC_R_SUCCESS) {
1556 DESTROYLOCK(&reqarg->lock);
1557 isc_mem_put(client->mctx, reqarg, sizeof(*reqarg));
1562 * Start internal event loop. It blocks until the entire process
1565 result = isc_app_ctxrun(actx);
1567 LOCK(&reqarg->lock);
1568 if (result == ISC_R_SUCCESS || result == ISC_R_SUSPEND)
1569 result = reqarg->result;
1570 if (reqarg->trans != NULL) {
1572 * Unusual termination (perhaps due to signal). We need some
1573 * tricky cleanup process.
1575 reqarg->canceled = ISC_TRUE;
1576 dns_client_cancelresolve(reqarg->trans);
1578 UNLOCK(&reqarg->lock);
1580 /* reqarg will be freed in the event handler. */
1582 UNLOCK(&reqarg->lock);
1584 DESTROYLOCK(&reqarg->lock);
1585 isc_mem_put(client->mctx, reqarg, sizeof(*reqarg));
1592 dns_client_startrequest(dns_client_t *client, dns_message_t *qmessage,
1593 dns_message_t *rmessage, isc_sockaddr_t *server,
1594 unsigned int options, unsigned int parseoptions,
1595 dns_tsec_t *tsec, unsigned int timeout,
1596 unsigned int udptimeout, unsigned int udpretries,
1597 isc_task_t *task, isc_taskaction_t action, void *arg,
1598 dns_clientreqtrans_t **transp)
1600 isc_result_t result;
1601 dns_view_t *view = NULL;
1602 isc_task_t *clone = NULL;
1603 dns_clientreqevent_t *event = NULL;
1604 reqctx_t *ctx = NULL;
1605 dns_tsectype_t tsectype = dns_tsectype_none;
1609 REQUIRE(DNS_CLIENT_VALID(client));
1610 REQUIRE(qmessage != NULL);
1611 REQUIRE(rmessage != NULL);
1612 REQUIRE(transp != NULL && *transp == NULL);
1615 tsectype = dns_tsec_gettype(tsec);
1616 if (tsectype != dns_tsectype_tsig)
1617 return (ISC_R_NOTIMPLEMENTED); /* XXX */
1620 LOCK(&client->lock);
1621 result = dns_viewlist_find(&client->viewlist, DNS_CLIENTVIEW_NAME,
1622 qmessage->rdclass, &view);
1623 UNLOCK(&client->lock);
1624 if (result != ISC_R_SUCCESS)
1628 isc_task_attach(task, &clone);
1629 event = (dns_clientreqevent_t *)
1630 isc_event_allocate(client->mctx, clone,
1631 DNS_EVENT_CLIENTREQDONE,
1632 action, arg, sizeof(*event));
1633 if (event == NULL) {
1634 result = ISC_R_NOMEMORY;
1638 ctx = isc_mem_get(client->mctx, sizeof(*ctx));
1640 result = ISC_R_NOMEMORY;
1642 result = isc_mutex_init(&ctx->lock);
1643 if (result != ISC_R_SUCCESS) {
1644 isc_mem_put(client->mctx, ctx, sizeof(*ctx));
1648 if (result != ISC_R_SUCCESS)
1651 ctx->client = client;
1652 ISC_LINK_INIT(ctx, link);
1653 ctx->parseoptions = parseoptions;
1654 ctx->canceled = ISC_FALSE;
1656 ctx->event->rmessage = rmessage;
1657 ctx->tsigkey = NULL;
1659 dns_tsec_getkey(tsec, &ctx->tsigkey);
1661 ctx->magic = REQCTX_MAGIC;
1663 LOCK(&client->lock);
1664 ISC_LIST_APPEND(client->reqctxs, ctx, link);
1665 UNLOCK(&client->lock);
1667 ctx->request = NULL;
1668 result = dns_request_createvia3(view->requestmgr, qmessage, NULL,
1669 server, options, ctx->tsigkey,
1670 timeout, udptimeout, udpretries,
1671 client->task, request_done, ctx,
1673 if (result == ISC_R_SUCCESS) {
1674 dns_view_detach(&view);
1675 *transp = (dns_clientreqtrans_t *)ctx;
1676 return (ISC_R_SUCCESS);
1681 LOCK(&client->lock);
1682 ISC_LIST_UNLINK(client->reqctxs, ctx, link);
1683 UNLOCK(&client->lock);
1684 DESTROYLOCK(&ctx->lock);
1685 isc_mem_put(client->mctx, ctx, sizeof(*ctx));
1688 isc_event_free(ISC_EVENT_PTR(&event));
1689 isc_task_detach(&clone);
1690 dns_view_detach(&view);
1696 dns_client_cancelrequest(dns_clientreqtrans_t *trans) {
1699 REQUIRE(trans != NULL);
1700 ctx = (reqctx_t *)trans;
1701 REQUIRE(REQCTX_VALID(ctx));
1705 if (!ctx->canceled) {
1706 ctx->canceled = ISC_TRUE;
1707 if (ctx->request != NULL)
1708 dns_request_cancel(ctx->request);
1715 dns_client_destroyreqtrans(dns_clientreqtrans_t **transp) {
1718 dns_client_t *client;
1719 isc_boolean_t need_destroyclient = ISC_FALSE;
1721 REQUIRE(transp != NULL);
1722 ctx = (reqctx_t *)*transp;
1723 REQUIRE(REQCTX_VALID(ctx));
1724 client = ctx->client;
1725 REQUIRE(DNS_CLIENT_VALID(client));
1726 REQUIRE(ctx->event == NULL);
1727 REQUIRE(ctx->request != NULL);
1729 dns_request_destroy(&ctx->request);
1730 mctx = client->mctx;
1732 LOCK(&client->lock);
1734 INSIST(ISC_LINK_LINKED(ctx, link));
1735 ISC_LIST_UNLINK(client->reqctxs, ctx, link);
1737 if (client->references == 0 && ISC_LIST_EMPTY(client->resctxs) &&
1738 ISC_LIST_EMPTY(client->reqctxs) &&
1739 ISC_LIST_EMPTY(client->updatectxs)) {
1740 need_destroyclient = ISC_TRUE;
1743 UNLOCK(&client->lock);
1745 DESTROYLOCK(&ctx->lock);
1748 isc_mem_put(mctx, ctx, sizeof(*ctx));
1750 if (need_destroyclient)
1751 destroyclient(&client);
1757 * Dynamic update routines
1760 rcode2result(dns_rcode_t rcode) {
1761 /* XXX: isn't there a similar function? */
1763 case dns_rcode_formerr:
1764 return (DNS_R_FORMERR);
1765 case dns_rcode_servfail:
1766 return (DNS_R_SERVFAIL);
1767 case dns_rcode_nxdomain:
1768 return (DNS_R_NXDOMAIN);
1769 case dns_rcode_notimp:
1770 return (DNS_R_NOTIMP);
1771 case dns_rcode_refused:
1772 return (DNS_R_REFUSED);
1773 case dns_rcode_yxdomain:
1774 return (DNS_R_YXDOMAIN);
1775 case dns_rcode_yxrrset:
1776 return (DNS_R_YXRRSET);
1777 case dns_rcode_nxrrset:
1778 return (DNS_R_NXRRSET);
1779 case dns_rcode_notauth:
1780 return (DNS_R_NOTAUTH);
1781 case dns_rcode_notzone:
1782 return (DNS_R_NOTZONE);
1783 case dns_rcode_badvers:
1784 return (DNS_R_BADVERS);
1787 return (ISC_R_FAILURE);
1791 update_sendevent(updatectx_t *uctx, isc_result_t result) {
1794 dns_message_destroy(&uctx->updatemsg);
1795 if (uctx->tsigkey != NULL)
1796 dns_tsigkey_detach(&uctx->tsigkey);
1797 if (uctx->sig0key != NULL)
1798 dst_key_free(&uctx->sig0key);
1801 uctx->event->result = ISC_R_CANCELED;
1803 uctx->event->result = result;
1804 uctx->event->state = uctx->state;
1805 task = uctx->event->ev_sender;
1806 uctx->event->ev_sender = uctx;
1807 isc_task_sendanddetach(&task, ISC_EVENT_PTR(&uctx->event));
1811 update_done(isc_task_t *task, isc_event_t *event) {
1812 isc_result_t result;
1813 dns_requestevent_t *reqev = NULL;
1814 dns_request_t *request;
1815 dns_message_t *answer = NULL;
1816 updatectx_t *uctx = event->ev_arg;
1817 dns_client_t *client;
1818 unsigned int timeout;
1822 REQUIRE(event->ev_type == DNS_EVENT_REQUESTDONE);
1823 reqev = (dns_requestevent_t *)event;
1824 request = reqev->request;
1825 REQUIRE(UCTX_VALID(uctx));
1826 client = uctx->client;
1827 REQUIRE(DNS_CLIENT_VALID(client));
1829 result = reqev->result;
1830 if (result != ISC_R_SUCCESS)
1833 result = dns_message_create(client->mctx, DNS_MESSAGE_INTENTPARSE,
1835 if (result != ISC_R_SUCCESS)
1837 uctx->state = dns_clientupdatestate_done;
1838 result = dns_request_getresponse(request, answer,
1839 DNS_MESSAGEPARSE_PRESERVEORDER);
1840 if (result == ISC_R_SUCCESS && answer->rcode != dns_rcode_noerror)
1841 result = rcode2result(answer->rcode);
1845 dns_message_destroy(&answer);
1846 isc_event_free(&event);
1849 uctx->currentserver = ISC_LIST_NEXT(uctx->currentserver, link);
1850 dns_request_destroy(&uctx->updatereq);
1851 if (result != ISC_R_SUCCESS && !uctx->canceled &&
1852 uctx->currentserver != NULL) {
1853 dns_message_renderreset(uctx->updatemsg);
1854 dns_message_settsigkey(uctx->updatemsg, NULL);
1856 timeout = client->update_timeout / uctx->nservers;
1857 if (timeout < MIN_UPDATE_TIMEOUT)
1858 timeout = MIN_UPDATE_TIMEOUT;
1859 result = dns_request_createvia3(uctx->view->requestmgr,
1862 uctx->currentserver, 0,
1865 client->update_udptimeout,
1866 client->update_udpretries,
1870 UNLOCK(&uctx->lock);
1872 if (result == ISC_R_SUCCESS) {
1873 /* XXX: should we keep the 'done' state here? */
1874 uctx->state = dns_clientupdatestate_sent;
1878 UNLOCK(&uctx->lock);
1880 update_sendevent(uctx, result);
1884 send_update(updatectx_t *uctx) {
1885 isc_result_t result;
1886 dns_name_t *name = NULL;
1887 dns_rdataset_t *rdataset = NULL;
1888 dns_client_t *client = uctx->client;
1889 unsigned int timeout;
1891 REQUIRE(uctx->zonename != NULL && uctx->currentserver != NULL);
1893 result = dns_message_gettempname(uctx->updatemsg, &name);
1894 if (result != ISC_R_SUCCESS)
1896 dns_name_init(name, NULL);
1897 dns_name_clone(uctx->zonename, name);
1898 result = dns_message_gettemprdataset(uctx->updatemsg, &rdataset);
1899 if (result != ISC_R_SUCCESS) {
1900 dns_message_puttempname(uctx->updatemsg, &name);
1903 dns_rdataset_makequestion(rdataset, uctx->rdclass, dns_rdatatype_soa);
1904 ISC_LIST_INIT(name->list);
1905 ISC_LIST_APPEND(name->list, rdataset, link);
1906 dns_message_addname(uctx->updatemsg, name, DNS_SECTION_ZONE);
1907 if (uctx->tsigkey == NULL && uctx->sig0key != NULL) {
1908 result = dns_message_setsig0key(uctx->updatemsg,
1910 if (result != ISC_R_SUCCESS)
1913 timeout = client->update_timeout / uctx->nservers;
1914 if (timeout < MIN_UPDATE_TIMEOUT)
1915 timeout = MIN_UPDATE_TIMEOUT;
1916 result = dns_request_createvia3(uctx->view->requestmgr,
1918 NULL, uctx->currentserver, 0,
1919 uctx->tsigkey, timeout,
1920 client->update_udptimeout,
1921 client->update_udpretries,
1922 client->task, update_done, uctx,
1924 if (result == ISC_R_SUCCESS &&
1925 uctx->state == dns_clientupdatestate_prepare) {
1926 uctx->state = dns_clientupdatestate_sent;
1933 resolveaddr_done(isc_task_t *task, isc_event_t *event) {
1934 isc_result_t result;
1936 dns_rdatatype_t qtype;
1937 dns_clientresevent_t *rev = (dns_clientresevent_t *)event;
1939 dns_rdataset_t *rdataset;
1941 isc_boolean_t completed = ISC_FALSE;
1945 REQUIRE(event->ev_arg != NULL);
1946 uctx = *(updatectx_t **)event->ev_arg;
1947 REQUIRE(UCTX_VALID(uctx));
1949 if (event->ev_arg == &uctx->bp4) {
1951 qtype = dns_rdatatype_a;
1953 dns_client_destroyrestrans(&uctx->restrans);
1954 UNLOCK(&uctx->lock);
1956 INSIST(event->ev_arg == &uctx->bp6);
1958 qtype = dns_rdatatype_aaaa;
1960 dns_client_destroyrestrans(&uctx->restrans2);
1961 UNLOCK(&uctx->lock);
1964 result = rev->result;
1965 if (result != ISC_R_SUCCESS)
1968 for (name = ISC_LIST_HEAD(rev->answerlist); name != NULL;
1969 name = ISC_LIST_NEXT(name, link)) {
1970 for (rdataset = ISC_LIST_HEAD(name->list);
1972 rdataset = ISC_LIST_NEXT(rdataset, link)) {
1973 if (!dns_rdataset_isassociated(rdataset))
1975 if (rdataset->type != qtype)
1978 for (result = dns_rdataset_first(rdataset);
1979 result == ISC_R_SUCCESS;
1980 result = dns_rdataset_next(rdataset)) {
1982 dns_rdata_in_a_t rdata_a;
1983 dns_rdata_in_aaaa_t rdata_aaaa;
1986 sa = isc_mem_get(uctx->client->mctx,
1990 * If we fail to get a sockaddr,
1991 we simply move forward with the
1992 * addresses we've got so far.
1997 dns_rdata_init(&rdata);
2000 dns_rdataset_current(rdataset, &rdata);
2001 dns_rdata_tostruct(&rdata, &rdata_a,
2003 isc_sockaddr_fromin(sa,
2006 dns_rdata_freestruct(&rdata_a);
2009 dns_rdataset_current(rdataset, &rdata);
2010 dns_rdata_tostruct(&rdata, &rdata_aaaa,
2012 isc_sockaddr_fromin6(sa,
2013 &rdata_aaaa.in6_addr,
2015 dns_rdata_freestruct(&rdata_aaaa);
2019 ISC_LINK_INIT(sa, link);
2020 ISC_LIST_APPEND(uctx->servers, sa, link);
2027 dns_client_freeresanswer(uctx->client, &rev->answerlist);
2028 isc_event_free(&event);
2031 if (uctx->restrans == NULL && uctx->restrans2 == NULL)
2032 completed = ISC_TRUE;
2033 UNLOCK(&uctx->lock);
2036 INSIST(uctx->currentserver == NULL);
2037 uctx->currentserver = ISC_LIST_HEAD(uctx->servers);
2038 if (uctx->currentserver != NULL && !uctx->canceled)
2041 if (result == ISC_R_SUCCESS)
2042 result = ISC_R_NOTFOUND;
2043 update_sendevent(uctx, result);
2049 process_soa(updatectx_t *uctx, dns_rdataset_t *soaset, dns_name_t *soaname) {
2050 isc_result_t result;
2051 dns_rdata_t soarr = DNS_RDATA_INIT;
2052 dns_rdata_soa_t soa;
2055 result = dns_rdataset_first(soaset);
2056 if (result != ISC_R_SUCCESS)
2058 dns_rdata_init(&soarr);
2059 dns_rdataset_current(soaset, &soarr);
2060 result = dns_rdata_tostruct(&soarr, &soa, NULL);
2061 if (result != ISC_R_SUCCESS)
2064 dns_name_init(&primary, NULL);
2065 dns_name_clone(&soa.origin, &primary);
2067 if (uctx->zonename == NULL) {
2068 uctx->zonename = dns_fixedname_name(&uctx->zonefname);
2069 result = dns_name_copy(soaname, uctx->zonename, NULL);
2070 if (result != ISC_R_SUCCESS)
2074 if (uctx->currentserver != NULL)
2075 result = send_update(uctx);
2078 * Get addresses of the primary server. We don't use the ADB
2079 * feature so that we could avoid caching data.
2083 result = dns_client_startresolve(uctx->client, &primary,
2086 0, uctx->client->task,
2087 resolveaddr_done, &uctx->bp4,
2089 if (result == ISC_R_SUCCESS) {
2091 result = dns_client_startresolve(uctx->client,
2095 0, uctx->client->task,
2100 UNLOCK(&uctx->lock);
2104 dns_rdata_freestruct(&soa);
2110 receive_soa(isc_task_t *task, isc_event_t *event) {
2111 dns_requestevent_t *reqev = NULL;
2113 dns_client_t *client;
2114 isc_result_t result, eresult;
2115 dns_request_t *request;
2116 dns_message_t *rcvmsg = NULL;
2117 dns_section_t section;
2118 dns_rdataset_t *soaset = NULL;
2121 dns_message_t *soaquery = NULL;
2122 isc_sockaddr_t *addr;
2123 isc_boolean_t seencname = ISC_FALSE;
2124 isc_boolean_t droplabel = ISC_FALSE;
2126 unsigned int nlabels;
2130 REQUIRE(event->ev_type == DNS_EVENT_REQUESTDONE);
2131 reqev = (dns_requestevent_t *)event;
2132 request = reqev->request;
2133 result = eresult = reqev->result;
2134 uctx = reqev->ev_arg;
2135 client = uctx->client;
2136 soaquery = uctx->soaquery;
2137 addr = uctx->currentserver;
2138 INSIST(addr != NULL);
2140 isc_event_free(&event);
2142 if (eresult != ISC_R_SUCCESS) {
2147 result = dns_message_create(uctx->client->mctx,
2148 DNS_MESSAGE_INTENTPARSE, &rcvmsg);
2149 if (result != ISC_R_SUCCESS)
2151 result = dns_request_getresponse(request, rcvmsg,
2152 DNS_MESSAGEPARSE_PRESERVEORDER);
2154 if (result == DNS_R_TSIGERRORSET) {
2155 dns_request_t *newrequest = NULL;
2157 /* Retry SOA request without TSIG */
2158 dns_message_destroy(&rcvmsg);
2159 dns_message_renderreset(uctx->soaquery);
2160 result = dns_request_createvia3(uctx->view->requestmgr,
2161 uctx->soaquery, NULL, addr, 0,
2163 client->find_timeout * 20,
2164 client->find_timeout, 3,
2168 if (result == ISC_R_SUCCESS) {
2170 dns_request_destroy(&uctx->soareq);
2171 uctx->soareq = newrequest;
2172 UNLOCK(&uctx->lock);
2179 section = DNS_SECTION_ANSWER;
2181 if (rcvmsg->rcode != dns_rcode_noerror &&
2182 rcvmsg->rcode != dns_rcode_nxdomain) {
2183 result = rcode2result(rcvmsg->rcode);
2189 section = DNS_SECTION_ANSWER;
2191 section = DNS_SECTION_AUTHORITY;
2193 droplabel = ISC_TRUE;
2197 result = dns_message_firstname(rcvmsg, section);
2198 if (result != ISC_R_SUCCESS) {
2202 while (result == ISC_R_SUCCESS) {
2204 dns_message_currentname(rcvmsg, section, &name);
2206 result = dns_message_findtype(name, dns_rdatatype_soa, 0,
2208 if (result == ISC_R_SUCCESS)
2210 if (section == DNS_SECTION_ANSWER) {
2211 dns_rdataset_t *tset = NULL;
2212 if (dns_message_findtype(name, dns_rdatatype_cname, 0,
2213 &tset) == ISC_R_SUCCESS
2215 dns_message_findtype(name, dns_rdatatype_dname, 0,
2216 &tset) == ISC_R_SUCCESS
2219 seencname = ISC_TRUE;
2224 result = dns_message_nextname(rcvmsg, section);
2227 if (soaset == NULL && !seencname) {
2233 droplabel = ISC_TRUE;
2237 result = process_soa(uctx, soaset, name);
2241 result = dns_message_firstname(soaquery, DNS_SECTION_QUESTION);
2242 INSIST(result == ISC_R_SUCCESS);
2244 dns_message_currentname(soaquery, DNS_SECTION_QUESTION, &name);
2245 nlabels = dns_name_countlabels(name);
2247 result = DNS_R_SERVFAIL; /* is there a better error? */
2249 dns_name_init(&tname, NULL);
2250 dns_name_getlabelsequence(name, 1, nlabels - 1,
2252 dns_name_clone(&tname, name);
2253 dns_request_destroy(&request);
2255 uctx->soareq = NULL;
2256 UNLOCK(&uctx->lock);
2257 dns_message_renderreset(soaquery);
2258 dns_message_settsigkey(soaquery, NULL);
2259 result = dns_request_createvia3(uctx->view->requestmgr,
2261 uctx->currentserver, 0,
2263 client->find_timeout *
2265 client->find_timeout,
2272 if (!droplabel || result != ISC_R_SUCCESS) {
2273 dns_message_destroy(&uctx->soaquery);
2275 dns_request_destroy(&uctx->soareq);
2276 UNLOCK(&uctx->lock);
2280 dns_message_destroy(&rcvmsg);
2282 if (result != ISC_R_SUCCESS)
2283 update_sendevent(uctx, result);
2287 request_soa(updatectx_t *uctx) {
2288 isc_result_t result;
2289 dns_message_t *soaquery = uctx->soaquery;
2290 dns_name_t *name = NULL;
2291 dns_rdataset_t *rdataset = NULL;
2293 if (soaquery == NULL) {
2294 result = dns_message_create(uctx->client->mctx,
2295 DNS_MESSAGE_INTENTRENDER,
2297 if (result != ISC_R_SUCCESS)
2300 soaquery->flags |= DNS_MESSAGEFLAG_RD;
2301 result = dns_message_gettempname(soaquery, &name);
2302 if (result != ISC_R_SUCCESS)
2304 result = dns_message_gettemprdataset(soaquery, &rdataset);
2305 if (result != ISC_R_SUCCESS)
2307 dns_rdataset_makequestion(rdataset, uctx->rdclass, dns_rdatatype_soa);
2308 dns_name_clone(uctx->firstname, name);
2309 ISC_LIST_APPEND(name->list, rdataset, link);
2310 dns_message_addname(soaquery, name, DNS_SECTION_QUESTION);
2314 result = dns_request_createvia3(uctx->view->requestmgr,
2315 soaquery, NULL, uctx->currentserver, 0,
2317 uctx->client->find_timeout * 20,
2318 uctx->client->find_timeout, 3,
2319 uctx->client->task, receive_soa, uctx,
2321 if (result == ISC_R_SUCCESS) {
2322 uctx->soaquery = soaquery;
2323 return (ISC_R_SUCCESS);
2327 if (rdataset != NULL) {
2328 ISC_LIST_UNLINK(name->list, rdataset, link); /* for safety */
2329 dns_message_puttemprdataset(soaquery, &rdataset);
2332 dns_message_puttempname(soaquery, &name);
2333 dns_message_destroy(&soaquery);
2339 resolvesoa_done(isc_task_t *task, isc_event_t *event) {
2340 dns_clientresevent_t *rev = (dns_clientresevent_t *)event;
2342 dns_name_t *name, tname;
2343 dns_rdataset_t *rdataset = NULL;
2344 isc_result_t result = rev->result;
2345 unsigned int nlabels;
2349 uctx = event->ev_arg;
2350 REQUIRE(UCTX_VALID(uctx));
2353 dns_client_destroyrestrans(&uctx->restrans);
2354 UNLOCK(&uctx->lock);
2356 uctx = event->ev_arg;
2357 if (result != ISC_R_SUCCESS &&
2358 result != DNS_R_NCACHENXDOMAIN &&
2359 result != DNS_R_NCACHENXRRSET) {
2360 /* XXX: what about DNSSEC failure? */
2364 for (name = ISC_LIST_HEAD(rev->answerlist); name != NULL;
2365 name = ISC_LIST_NEXT(name, link)) {
2366 for (rdataset = ISC_LIST_HEAD(name->list);
2368 rdataset = ISC_LIST_NEXT(rdataset, link)) {
2369 if (dns_rdataset_isassociated(rdataset) &&
2370 rdataset->type == dns_rdatatype_soa)
2375 if (rdataset == NULL) {
2376 /* Drop one label and retry resolution. */
2377 nlabels = dns_name_countlabels(&uctx->soaqname);
2379 result = DNS_R_SERVFAIL; /* is there a better error? */
2382 dns_name_init(&tname, NULL);
2383 dns_name_getlabelsequence(&uctx->soaqname, 1, nlabels - 1,
2385 dns_name_clone(&tname, &uctx->soaqname);
2387 result = dns_client_startresolve(uctx->client, &uctx->soaqname,
2389 dns_rdatatype_soa, 0,
2391 resolvesoa_done, uctx,
2394 result = process_soa(uctx, rdataset, &uctx->soaqname);
2397 dns_client_freeresanswer(uctx->client, &rev->answerlist);
2398 isc_event_free(&event);
2400 if (result != ISC_R_SUCCESS)
2401 update_sendevent(uctx, result);
2405 copy_name(isc_mem_t *mctx, dns_message_t *msg, dns_name_t *name,
2406 dns_name_t **newnamep)
2408 isc_result_t result;
2409 dns_name_t *newname = NULL;
2411 isc_buffer_t *namebuf = NULL, *rdatabuf = NULL;
2412 dns_rdatalist_t *rdatalist;
2413 dns_rdataset_t *rdataset, *newrdataset;
2414 dns_rdata_t rdata = DNS_RDATA_INIT, *newrdata;
2416 result = dns_message_gettempname(msg, &newname);
2417 if (result != ISC_R_SUCCESS)
2419 result = isc_buffer_allocate(mctx, &namebuf, DNS_NAME_MAXWIRE);
2420 if (result != ISC_R_SUCCESS)
2422 dns_name_init(newname, NULL);
2423 dns_name_setbuffer(newname, namebuf);
2424 dns_message_takebuffer(msg, &namebuf);
2425 result = dns_name_copy(name, newname, NULL);
2426 if (result != ISC_R_SUCCESS)
2429 for (rdataset = ISC_LIST_HEAD(name->list); rdataset != NULL;
2430 rdataset = ISC_LIST_NEXT(rdataset, link)) {
2432 result = dns_message_gettemprdatalist(msg, &rdatalist);
2433 if (result != ISC_R_SUCCESS)
2435 dns_rdatalist_init(rdatalist);
2436 rdatalist->type = rdataset->type;
2437 rdatalist->rdclass = rdataset->rdclass;
2438 rdatalist->covers = rdataset->covers;
2439 rdatalist->ttl = rdataset->ttl;
2441 result = dns_rdataset_first(rdataset);
2442 while (result == ISC_R_SUCCESS) {
2443 dns_rdata_reset(&rdata);
2444 dns_rdataset_current(rdataset, &rdata);
2447 result = dns_message_gettemprdata(msg, &newrdata);
2448 if (result != ISC_R_SUCCESS)
2450 dns_rdata_toregion(&rdata, &r);
2452 result = isc_buffer_allocate(mctx, &rdatabuf,
2454 if (result != ISC_R_SUCCESS)
2456 isc_buffer_putmem(rdatabuf, r.base, r.length);
2457 isc_buffer_usedregion(rdatabuf, &r);
2458 dns_rdata_init(newrdata);
2459 dns_rdata_fromregion(newrdata, rdata.rdclass,
2461 newrdata->flags = rdata.flags;
2463 ISC_LIST_APPEND(rdatalist->rdata, newrdata, link);
2464 dns_message_takebuffer(msg, &rdatabuf);
2466 result = dns_rdataset_next(rdataset);
2470 result = dns_message_gettemprdataset(msg, &newrdataset);
2471 if (result != ISC_R_SUCCESS)
2473 dns_rdataset_init(newrdataset);
2474 dns_rdatalist_tordataset(rdatalist, newrdataset);
2476 ISC_LIST_APPEND(newname->list, newrdataset, link);
2479 *newnamep = newname;
2481 return (ISC_R_SUCCESS);
2484 dns_message_puttempname(msg, &newname);
2491 internal_update_callback(isc_task_t *task, isc_event_t *event) {
2492 updatearg_t *uarg = event->ev_arg;
2493 dns_clientupdateevent_t *uev = (dns_clientupdateevent_t *)event;
2499 uarg->result = uev->result;
2501 dns_client_destroyupdatetrans(&uarg->trans);
2502 isc_event_free(&event);
2504 if (!uarg->canceled) {
2505 UNLOCK(&uarg->lock);
2507 /* Exit from the internal event loop */
2508 isc_app_ctxsuspend(uarg->actx);
2511 * We have already exited from the loop (due to some
2512 * unexpected event). Just clean the arg up.
2514 UNLOCK(&uarg->lock);
2515 DESTROYLOCK(&uarg->lock);
2516 isc_mem_put(uarg->client->mctx, uarg, sizeof(*uarg));
2521 dns_client_update(dns_client_t *client, dns_rdataclass_t rdclass,
2522 dns_name_t *zonename, dns_namelist_t *prerequisites,
2523 dns_namelist_t *updates, isc_sockaddrlist_t *servers,
2524 dns_tsec_t *tsec, unsigned int options)
2526 isc_result_t result;
2530 REQUIRE(DNS_CLIENT_VALID(client));
2532 if ((client->attributes & DNS_CLIENTATTR_OWNCTX) == 0 &&
2533 (options & DNS_CLIENTRESOPT_ALLOWRUN) == 0) {
2535 * If the client is run under application's control, we need
2536 * to create a new running (sub)environment for this
2537 * particular resolution.
2539 return (ISC_R_NOTIMPLEMENTED); /* XXXTBD */
2541 actx = client->actx;
2543 uarg = isc_mem_get(client->mctx, sizeof(*uarg));
2545 return (ISC_R_NOMEMORY);
2547 result = isc_mutex_init(&uarg->lock);
2548 if (result != ISC_R_SUCCESS) {
2549 isc_mem_put(client->mctx, uarg, sizeof(*uarg));
2554 uarg->client = client;
2555 uarg->result = ISC_R_FAILURE;
2557 uarg->canceled = ISC_FALSE;
2559 result = dns_client_startupdate(client, rdclass, zonename,
2560 prerequisites, updates, servers,
2561 tsec, options, client->task,
2562 internal_update_callback, uarg,
2564 if (result != ISC_R_SUCCESS) {
2565 DESTROYLOCK(&uarg->lock);
2566 isc_mem_put(client->mctx, uarg, sizeof(*uarg));
2571 * Start internal event loop. It blocks until the entire process
2574 result = isc_app_ctxrun(actx);
2577 if (result == ISC_R_SUCCESS || result == ISC_R_SUSPEND)
2578 result = uarg->result;
2580 if (uarg->trans != NULL) {
2582 * Unusual termination (perhaps due to signal). We need some
2583 * tricky cleanup process.
2585 uarg->canceled = ISC_TRUE;
2586 dns_client_cancelupdate(uarg->trans);
2588 UNLOCK(&uarg->lock);
2590 /* uarg will be freed in the event handler. */
2592 UNLOCK(&uarg->lock);
2594 DESTROYLOCK(&uarg->lock);
2595 isc_mem_put(client->mctx, uarg, sizeof(*uarg));
2602 dns_client_startupdate(dns_client_t *client, dns_rdataclass_t rdclass,
2603 dns_name_t *zonename, dns_namelist_t *prerequisites,
2604 dns_namelist_t *updates, isc_sockaddrlist_t *servers,
2605 dns_tsec_t *tsec, unsigned int options,
2606 isc_task_t *task, isc_taskaction_t action, void *arg,
2607 dns_clientupdatetrans_t **transp)
2609 dns_view_t *view = NULL;
2610 isc_result_t result;
2611 dns_name_t *name, *newname;
2613 isc_task_t *clone = NULL;
2614 dns_section_t section = DNS_SECTION_UPDATE;
2615 isc_sockaddr_t *server, *sa = NULL;
2616 dns_tsectype_t tsectype = dns_tsectype_none;
2620 REQUIRE(DNS_CLIENT_VALID(client));
2621 REQUIRE(transp != NULL && *transp == NULL);
2622 REQUIRE(updates != NULL);
2623 REQUIRE(task != NULL);
2626 tsectype = dns_tsec_gettype(tsec);
2627 if (tsectype != dns_tsectype_tsig)
2628 return (ISC_R_NOTIMPLEMENTED); /* XXX */
2631 LOCK(&client->lock);
2632 result = dns_viewlist_find(&client->viewlist, DNS_CLIENTVIEW_NAME,
2634 UNLOCK(&client->lock);
2635 if (result != ISC_R_SUCCESS)
2638 /* Create a context and prepare some resources */
2639 uctx = isc_mem_get(client->mctx, sizeof(*uctx));
2641 dns_view_detach(&view);
2642 return (ISC_R_NOMEMORY);
2644 result = isc_mutex_init(&uctx->lock);
2645 if (result != ISC_R_SUCCESS) {
2646 dns_view_detach(&view);
2647 isc_mem_put(client->mctx, uctx, sizeof(*uctx));
2648 return (ISC_R_NOMEMORY);
2651 isc_task_attach(task, &clone);
2652 uctx->client = client;
2653 ISC_LINK_INIT(uctx, link);
2654 uctx->state = dns_clientupdatestate_prepare;
2656 uctx->rdclass = rdclass;
2657 uctx->canceled = ISC_FALSE;
2658 uctx->updatemsg = NULL;
2659 uctx->soaquery = NULL;
2660 uctx->updatereq = NULL;
2661 uctx->restrans = NULL;
2662 uctx->restrans2 = NULL;
2665 uctx->soareq = NULL;
2667 uctx->tsigkey = NULL;
2668 uctx->sig0key = NULL;
2669 uctx->zonename = NULL;
2670 dns_name_init(&uctx->soaqname, NULL);
2671 ISC_LIST_INIT(uctx->servers);
2673 uctx->currentserver = NULL;
2674 dns_fixedname_init(&uctx->zonefname);
2676 dns_tsec_getkey(tsec, &uctx->tsigkey);
2677 uctx->event = (dns_clientupdateevent_t *)
2678 isc_event_allocate(client->mctx, clone, DNS_EVENT_UPDATEDONE,
2679 action, arg, sizeof(*uctx->event));
2680 if (uctx->event == NULL)
2682 if (zonename != NULL) {
2683 uctx->zonename = dns_fixedname_name(&uctx->zonefname);
2684 result = dns_name_copy(zonename, uctx->zonename, NULL);
2686 if (servers != NULL) {
2687 for (server = ISC_LIST_HEAD(*servers);
2689 server = ISC_LIST_NEXT(server, link)) {
2690 sa = isc_mem_get(client->mctx, sizeof(*sa));
2693 sa->type = server->type;
2694 sa->length = server->length;
2695 ISC_LINK_INIT(sa, link);
2696 ISC_LIST_APPEND(uctx->servers, sa, link);
2697 if (uctx->currentserver == NULL)
2698 uctx->currentserver = sa;
2703 /* Make update message */
2704 result = dns_message_create(client->mctx, DNS_MESSAGE_INTENTRENDER,
2706 if (result != ISC_R_SUCCESS)
2708 uctx->updatemsg->opcode = dns_opcode_update;
2710 if (prerequisites != NULL) {
2711 for (name = ISC_LIST_HEAD(*prerequisites); name != NULL;
2712 name = ISC_LIST_NEXT(name, link)) {
2714 result = copy_name(client->mctx, uctx->updatemsg,
2716 if (result != ISC_R_SUCCESS)
2718 dns_message_addname(uctx->updatemsg, newname,
2719 DNS_SECTION_PREREQUISITE);
2723 for (name = ISC_LIST_HEAD(*updates); name != NULL;
2724 name = ISC_LIST_NEXT(name, link)) {
2726 result = copy_name(client->mctx, uctx->updatemsg, name,
2728 if (result != ISC_R_SUCCESS)
2730 dns_message_addname(uctx->updatemsg, newname,
2731 DNS_SECTION_UPDATE);
2734 uctx->firstname = NULL;
2735 result = dns_message_firstname(uctx->updatemsg, section);
2736 if (result == ISC_R_NOMORE) {
2737 section = DNS_SECTION_PREREQUISITE;
2738 result = dns_message_firstname(uctx->updatemsg, section);
2740 if (result != ISC_R_SUCCESS)
2742 dns_message_currentname(uctx->updatemsg, section, &uctx->firstname);
2744 uctx->magic = UCTX_MAGIC;
2746 LOCK(&client->lock);
2747 ISC_LIST_APPEND(client->updatectxs, uctx, link);
2748 UNLOCK(&client->lock);
2750 if (uctx->zonename != NULL && uctx->currentserver != NULL) {
2751 result = send_update(uctx);
2752 if (result != ISC_R_SUCCESS)
2754 } else if (uctx->currentserver != NULL) {
2755 result = request_soa(uctx);
2756 if (result != ISC_R_SUCCESS)
2759 dns_name_clone(uctx->firstname, &uctx->soaqname);
2760 result = dns_client_startresolve(uctx->client, &uctx->soaqname,
2762 dns_rdatatype_soa, 0,
2763 client->task, resolvesoa_done,
2764 uctx, &uctx->restrans);
2765 if (result != ISC_R_SUCCESS)
2769 *transp = (dns_clientupdatetrans_t *)uctx;
2771 return (ISC_R_SUCCESS);
2774 if (ISC_LINK_LINKED(uctx, link)) {
2775 LOCK(&client->lock);
2776 ISC_LIST_UNLINK(client->updatectxs, uctx, link);
2777 UNLOCK(&client->lock);
2779 if (uctx->updatemsg != NULL)
2780 dns_message_destroy(&uctx->updatemsg);
2781 while ((sa = ISC_LIST_HEAD(uctx->servers)) != NULL) {
2782 ISC_LIST_UNLINK(uctx->servers, sa, link);
2783 isc_mem_put(client->mctx, sa, sizeof(*sa));
2785 if (uctx->event != NULL)
2786 isc_event_free(ISC_EVENT_PTR(&uctx->event));
2787 if (uctx->tsigkey != NULL)
2788 dns_tsigkey_detach(&uctx->tsigkey);
2789 isc_task_detach(&clone);
2790 DESTROYLOCK(&uctx->lock);
2792 isc_mem_put(client->mctx, uctx, sizeof(*uctx));
2793 dns_view_detach(&view);
2799 dns_client_cancelupdate(dns_clientupdatetrans_t *trans) {
2802 REQUIRE(trans != NULL);
2803 uctx = (updatectx_t *)trans;
2804 REQUIRE(UCTX_VALID(uctx));
2808 if (!uctx->canceled) {
2809 uctx->canceled = ISC_TRUE;
2810 if (uctx->updatereq != NULL)
2811 dns_request_cancel(uctx->updatereq);
2812 if (uctx->soareq != NULL)
2813 dns_request_cancel(uctx->soareq);
2814 if (uctx->restrans != NULL)
2815 dns_client_cancelresolve(uctx->restrans);
2816 if (uctx->restrans2 != NULL)
2817 dns_client_cancelresolve(uctx->restrans2);
2820 UNLOCK(&uctx->lock);
2824 dns_client_destroyupdatetrans(dns_clientupdatetrans_t **transp) {
2827 dns_client_t *client;
2828 isc_boolean_t need_destroyclient = ISC_FALSE;
2831 REQUIRE(transp != NULL);
2832 uctx = (updatectx_t *)*transp;
2833 REQUIRE(UCTX_VALID(uctx));
2834 client = uctx->client;
2835 REQUIRE(DNS_CLIENT_VALID(client));
2836 REQUIRE(uctx->updatereq == NULL && uctx->updatemsg == NULL &&
2837 uctx->soareq == NULL && uctx->soaquery == NULL &&
2838 uctx->event == NULL && uctx->tsigkey == NULL &&
2839 uctx->sig0key == NULL);
2841 mctx = client->mctx;
2842 dns_view_detach(&uctx->view);
2843 while ((sa = ISC_LIST_HEAD(uctx->servers)) != NULL) {
2844 ISC_LIST_UNLINK(uctx->servers, sa, link);
2845 isc_mem_put(mctx, sa, sizeof(*sa));
2848 LOCK(&client->lock);
2850 INSIST(ISC_LINK_LINKED(uctx, link));
2851 ISC_LIST_UNLINK(client->updatectxs, uctx, link);
2853 if (client->references == 0 && ISC_LIST_EMPTY(client->resctxs) &&
2854 ISC_LIST_EMPTY(client->reqctxs) &&
2855 ISC_LIST_EMPTY(client->updatectxs))
2856 need_destroyclient = ISC_TRUE;
2858 UNLOCK(&client->lock);
2860 DESTROYLOCK(&uctx->lock);
2863 isc_mem_put(mctx, uctx, sizeof(*uctx));
2865 if (need_destroyclient)
2866 destroyclient(&client);
2872 dns_client_mctx(dns_client_t *client) {
2874 REQUIRE(DNS_CLIENT_VALID(client));
2875 return (client->mctx);
2879 isc_buffer_t buffer;
2880 dns_rdataset_t rdataset;
2881 dns_rdatalist_t rdatalist;
2885 unsigned char data[FLEXIBLE_ARRAY_MEMBER];
2886 } dns_client_updaterec_t;
2889 dns_client_updaterec(dns_client_updateop_t op, dns_name_t *owner,
2890 dns_rdatatype_t type, dns_rdata_t *source,
2891 dns_ttl_t ttl, dns_name_t *target,
2892 dns_rdataset_t *rdataset, dns_rdatalist_t *rdatalist,
2893 dns_rdata_t *rdata, isc_mem_t *mctx)
2895 dns_client_updaterec_t *updaterec = NULL;
2896 size_t size = offsetof(dns_client_updaterec_t, data);
2898 REQUIRE(op < updateop_max);
2899 REQUIRE(owner != NULL);
2900 REQUIRE((rdataset != NULL && rdatalist != NULL && rdata != NULL) ||
2901 (rdataset == NULL && rdatalist == NULL && rdata == NULL &&
2903 if (op == updateop_add)
2904 REQUIRE(source != NULL);
2905 if (source != NULL) {
2906 REQUIRE(source->type == type);
2907 REQUIRE(op == updateop_add || op == updateop_delete ||
2908 op == updateop_exist);
2911 size += owner->length;
2913 size += source->length;
2915 if (rdataset == NULL) {
2916 updaterec = isc_mem_get(mctx, size);
2917 if (updaterec == NULL)
2918 return (ISC_R_NOMEMORY);
2919 rdataset = &updaterec->rdataset;
2920 rdatalist = &updaterec->rdatalist;
2921 rdata = &updaterec->rdata;
2922 dns_rdataset_init(rdataset);
2923 dns_rdatalist_init(&updaterec->rdatalist);
2924 dns_rdata_init(&updaterec->rdata);
2925 isc_buffer_init(&updaterec->buffer, updaterec->data,
2926 size - offsetof(dns_client_updaterec_t, data));
2927 dns_name_copy(owner, target, &updaterec->buffer);
2928 if (source != NULL) {
2930 dns_rdata_clone(source, rdata);
2931 dns_rdata_toregion(rdata, &r);
2932 rdata->data = isc_buffer_used(&updaterec->buffer);
2933 isc_buffer_copyregion(&updaterec->buffer, &r);
2935 updaterec->mctx = NULL;
2936 isc_mem_attach(mctx, &updaterec->mctx);
2937 } else if (source != NULL)
2938 dns_rdata_clone(source, rdata);
2943 case updateop_delete:
2944 if (source != NULL) {
2946 dns_rdata_makedelete(rdata);
2948 dns_rdata_deleterrset(rdata, type);
2950 case updateop_notexist:
2951 dns_rdata_notexist(rdata, type);
2953 case updateop_exist:
2954 if (source == NULL) {
2956 dns_rdata_exists(rdata, type);
2964 rdatalist->type = rdata->type;
2965 rdatalist->rdclass = rdata->rdclass;
2966 if (source != NULL) {
2967 rdatalist->covers = dns_rdata_covers(rdata);
2968 rdatalist->ttl = ttl;
2970 ISC_LIST_APPEND(rdatalist->rdata, rdata, link);
2971 dns_rdatalist_tordataset(rdatalist, rdataset);
2972 ISC_LIST_APPEND(target->list, rdataset, link);
2973 if (updaterec != NULL) {
2974 target->attributes |= DNS_NAMEATTR_HASUPDATEREC;
2975 dns_name_setbuffer(target, &updaterec->buffer);
2977 if (op == updateop_add || op == updateop_delete)
2978 target->attributes |= DNS_NAMEATTR_UPDATE;
2980 target->attributes |= DNS_NAMEATTR_PREREQUISITE;
2981 return (ISC_R_SUCCESS);
2985 dns_client_freeupdate(dns_name_t **namep) {
2986 dns_client_updaterec_t *updaterec;
2987 dns_rdatalist_t *rdatalist;
2988 dns_rdataset_t *rdataset;
2992 REQUIRE(namep != NULL && *namep != NULL);
2995 for (rdataset = ISC_LIST_HEAD(name->list);
2997 rdataset = ISC_LIST_HEAD(name->list)) {
2998 ISC_LIST_UNLINK(name->list, rdataset, link);
3000 dns_rdatalist_fromrdataset(rdataset, &rdatalist);
3001 if (rdatalist == NULL) {
3002 dns_rdataset_disassociate(rdataset);
3005 for (rdata = ISC_LIST_HEAD(rdatalist->rdata);
3007 rdata = ISC_LIST_HEAD(rdatalist->rdata))
3008 ISC_LIST_UNLINK(rdatalist->rdata, rdata, link);
3009 dns_rdataset_disassociate(rdataset);
3012 if ((name->attributes & DNS_NAMEATTR_HASUPDATEREC) != 0) {
3013 updaterec = (dns_client_updaterec_t *)name->buffer;
3014 INSIST(updaterec != NULL);
3015 isc_mem_putanddetach(&updaterec->mctx, updaterec,