1 /* $NetBSD: client.c,v 1.10 2015/07/08 17:28:58 christos Exp $ */
4 * Copyright (C) 2009-2015 Internet Systems Consortium, Inc. ("ISC")
6 * Permission to use, copy, modify, and/or distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
10 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
11 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
12 * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
13 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
14 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
15 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
16 * PERFORMANCE OF THIS SOFTWARE.
19 /* Id: client.c,v 1.14 2011/03/12 04:59:47 tbox Exp */
26 #include <isc/buffer.h>
28 #include <isc/mutex.h>
29 #include <isc/sockaddr.h>
30 #include <isc/socket.h>
32 #include <isc/timer.h>
36 #include <dns/client.h>
38 #include <dns/dispatch.h>
39 #include <dns/events.h>
40 #include <dns/forward.h>
41 #include <dns/keytable.h>
42 #include <dns/message.h>
44 #include <dns/rdata.h>
45 #include <dns/rdatalist.h>
46 #include <dns/rdataset.h>
47 #include <dns/rdatatype.h>
48 #include <dns/rdatasetiter.h>
49 #include <dns/rdatastruct.h>
50 #include <dns/request.h>
51 #include <dns/resolver.h>
52 #include <dns/result.h>
59 #define DNS_CLIENT_MAGIC ISC_MAGIC('D', 'N', 'S', 'c')
60 #define DNS_CLIENT_VALID(c) ISC_MAGIC_VALID(c, DNS_CLIENT_MAGIC)
62 #define RCTX_MAGIC ISC_MAGIC('R', 'c', 't', 'x')
63 #define RCTX_VALID(c) ISC_MAGIC_VALID(c, RCTX_MAGIC)
65 #define REQCTX_MAGIC ISC_MAGIC('R', 'q', 'c', 'x')
66 #define REQCTX_VALID(c) ISC_MAGIC_VALID(c, REQCTX_MAGIC)
68 #define UCTX_MAGIC ISC_MAGIC('U', 'c', 't', 'x')
69 #define UCTX_VALID(c) ISC_MAGIC_VALID(c, UCTX_MAGIC)
71 #define MAX_RESTARTS 16
74 #define RESOLVER_NTASKS 523
76 #define RESOLVER_NTASKS 31
77 #endif /* TUNE_LARGE */
85 unsigned int attributes
;
89 isc_taskmgr_t
*taskmgr
;
91 isc_socketmgr_t
*socketmgr
;
92 isc_timermgr_t
*timermgr
;
93 dns_dispatchmgr_t
*dispatchmgr
;
94 dns_dispatch_t
*dispatchv4
;
95 dns_dispatch_t
*dispatchv6
;
97 unsigned int update_timeout
;
98 unsigned int update_udptimeout
;
99 unsigned int update_udpretries
;
100 unsigned int find_timeout
;
101 unsigned int find_udpretries
;
104 unsigned int references
;
105 dns_viewlist_t viewlist
;
106 ISC_LIST(struct resctx
) resctxs
;
107 ISC_LIST(struct reqctx
) reqctxs
;
108 ISC_LIST(struct updatectx
) updatectxs
;
112 * Timeout/retry constants for dynamic update borrowed from nsupdate
114 #define DEF_UPDATE_TIMEOUT 300
115 #define MIN_UPDATE_TIMEOUT 30
116 #define DEF_UPDATE_UDPTIMEOUT 3
117 #define DEF_UPDATE_UDPRETRIES 3
119 #define DEF_FIND_TIMEOUT 5
120 #define DEF_FIND_UDPRETRIES 3
122 #define DNS_CLIENTATTR_OWNCTX 0x01
124 #define DNS_CLIENTVIEW_NAME "dnsclient"
127 * Internal state for a single name resolution procedure
129 typedef struct resctx
{
133 dns_client_t
*client
;
134 isc_boolean_t want_dnssec
;
135 isc_boolean_t want_validation
;
136 isc_boolean_t want_cdflag
;
139 ISC_LINK(struct resctx
) link
;
142 unsigned int restarts
;
143 dns_fixedname_t name
;
144 dns_rdatatype_t type
;
146 dns_namelist_t namelist
;
148 dns_clientresevent_t
*event
;
149 isc_boolean_t canceled
;
150 dns_rdataset_t
*rdataset
;
151 dns_rdataset_t
*sigrdataset
;
155 * Argument of an internal event for synchronous name resolution.
157 typedef struct resarg
{
160 dns_client_t
*client
;
165 isc_result_t vresult
;
166 dns_namelist_t
*namelist
;
167 dns_clientrestrans_t
*trans
;
168 isc_boolean_t canceled
;
172 * Internal state for a single DNS request
174 typedef struct reqctx
{
178 dns_client_t
*client
;
179 unsigned int parseoptions
;
182 ISC_LINK(struct reqctx
) link
;
183 isc_boolean_t canceled
;
184 dns_tsigkey_t
*tsigkey
;
185 dns_request_t
*request
;
186 dns_clientreqevent_t
*event
;
190 * Argument of an internal event for synchronous DNS request.
192 typedef struct reqarg
{
195 dns_client_t
*client
;
200 dns_clientreqtrans_t
*trans
;
201 isc_boolean_t canceled
;
205 * Argument of an internal event for synchronous name resolution.
207 typedef struct updatearg
{
210 dns_client_t
*client
;
215 dns_clientupdatetrans_t
*trans
;
216 isc_boolean_t canceled
;
220 * Internal state for a single dynamic update procedure
222 typedef struct updatectx
{
226 dns_client_t
*client
;
229 dns_request_t
*updatereq
;
230 dns_request_t
*soareq
;
231 dns_clientrestrans_t
*restrans
;
232 dns_clientrestrans_t
*restrans2
;
233 isc_boolean_t canceled
;
236 ISC_LINK(struct updatectx
) link
;
237 dns_clientupdatestate_t state
;
238 dns_rdataclass_t rdclass
;
240 dns_message_t
*updatemsg
;
241 dns_message_t
*soaquery
;
242 dns_clientupdateevent_t
*event
;
243 dns_tsigkey_t
*tsigkey
;
245 dns_name_t
*firstname
;
247 dns_fixedname_t zonefname
;
248 dns_name_t
*zonename
;
249 isc_sockaddrlist_t servers
;
250 unsigned int nservers
;
251 isc_sockaddr_t
*currentserver
;
252 struct updatectx
*bp4
;
253 struct updatectx
*bp6
;
256 static isc_result_t
request_soa(updatectx_t
*uctx
);
257 static void client_resfind(resctx_t
*rctx
, dns_fetchevent_t
*event
);
258 static isc_result_t
send_update(updatectx_t
*uctx
);
261 getudpdispatch(int family
, dns_dispatchmgr_t
*dispatchmgr
,
262 isc_socketmgr_t
*socketmgr
, isc_taskmgr_t
*taskmgr
,
263 isc_boolean_t is_shared
, dns_dispatch_t
**dispp
,
264 isc_sockaddr_t
*localaddr
)
266 unsigned int attrs
, attrmask
;
267 dns_dispatch_t
*disp
;
268 unsigned buffersize
, maxbuffers
, maxrequests
, buckets
, increment
;
270 isc_sockaddr_t anyaddr
;
273 attrs
|= DNS_DISPATCHATTR_UDP
;
276 attrs
|= DNS_DISPATCHATTR_IPV4
;
279 attrs
|= DNS_DISPATCHATTR_IPV6
;
285 attrmask
|= DNS_DISPATCHATTR_UDP
;
286 attrmask
|= DNS_DISPATCHATTR_TCP
;
287 attrmask
|= DNS_DISPATCHATTR_IPV4
;
288 attrmask
|= DNS_DISPATCHATTR_IPV6
;
290 if (localaddr
== NULL
) {
291 localaddr
= &anyaddr
;
292 isc_sockaddr_anyofpf(localaddr
, family
);
296 maxbuffers
= is_shared
? 1000 : 8;
298 buckets
= is_shared
? 16411 : 3;
299 increment
= is_shared
? 16433 : 5;
302 result
= dns_dispatch_getudp(dispatchmgr
, socketmgr
,
304 buffersize
, maxbuffers
, maxrequests
,
306 attrs
, attrmask
, &disp
);
307 if (result
== ISC_R_SUCCESS
)
314 createview(isc_mem_t
*mctx
, dns_rdataclass_t rdclass
,
315 unsigned int options
, isc_taskmgr_t
*taskmgr
,
316 unsigned int ntasks
, isc_socketmgr_t
*socketmgr
,
317 isc_timermgr_t
*timermgr
, dns_dispatchmgr_t
*dispatchmgr
,
318 dns_dispatch_t
*dispatchv4
, dns_dispatch_t
*dispatchv6
,
322 dns_view_t
*view
= NULL
;
325 result
= dns_view_create(mctx
, rdclass
, DNS_CLIENTVIEW_NAME
, &view
);
326 if (result
!= ISC_R_SUCCESS
)
329 /* Initialize view security roots */
330 result
= dns_view_initsecroots(view
, mctx
);
331 if (result
!= ISC_R_SUCCESS
) {
332 dns_view_detach(&view
);
336 result
= dns_view_createresolver(view
, taskmgr
, ntasks
, 1,
337 socketmgr
, timermgr
, 0,
338 dispatchmgr
, dispatchv4
, dispatchv6
);
339 if (result
!= ISC_R_SUCCESS
) {
340 dns_view_detach(&view
);
346 * XXX: it may be better if specific DB implementations can be
347 * specified via some configuration knob.
349 if ((options
& DNS_CLIENTCREATEOPT_USECACHE
) != 0)
353 result
= dns_db_create(mctx
, dbtype
, dns_rootname
, dns_dbtype_cache
,
354 rdclass
, 0, NULL
, &view
->cachedb
);
355 if (result
!= ISC_R_SUCCESS
) {
356 dns_view_detach(&view
);
361 return (ISC_R_SUCCESS
);
365 dns_client_create(dns_client_t
**clientp
, unsigned int options
) {
367 isc_mem_t
*mctx
= NULL
;
368 isc_appctx_t
*actx
= NULL
;
369 isc_taskmgr_t
*taskmgr
= NULL
;
370 isc_socketmgr_t
*socketmgr
= NULL
;
371 isc_timermgr_t
*timermgr
= NULL
;
373 /* XXXMPA add debug logging support */
374 isc_log_t
*lctx
= NULL
;
375 isc_logconfig_t
*logconfig
= NULL
;
376 unsigned int logdebuglevel
= 0;
379 result
= isc_mem_create(0, 0, &mctx
);
380 if (result
!= ISC_R_SUCCESS
)
382 result
= isc_appctx_create(mctx
, &actx
);
383 if (result
!= ISC_R_SUCCESS
)
385 result
= isc_app_ctxstart(actx
);
386 if (result
!= ISC_R_SUCCESS
)
388 result
= isc_taskmgr_createinctx(mctx
, actx
, 1, 0, &taskmgr
);
389 if (result
!= ISC_R_SUCCESS
)
391 result
= isc_socketmgr_createinctx(mctx
, actx
, &socketmgr
);
392 if (result
!= ISC_R_SUCCESS
)
394 result
= isc_timermgr_createinctx(mctx
, actx
, &timermgr
);
395 if (result
!= ISC_R_SUCCESS
)
398 result
= isc_log_create(mctx
, &lctx
, &logconfig
);
399 if (result
!= ISC_R_SUCCESS
)
401 isc_log_setcontext(lctx
);
403 dns_log_setcontext(lctx
);
404 result
= isc_log_usechannel(logconfig
, "default_debug", NULL
, NULL
);
405 if (result
!= ISC_R_SUCCESS
)
407 isc_log_setdebuglevel(lctx
, logdebuglevel
);
409 result
= dns_client_createx(mctx
, actx
, taskmgr
, socketmgr
, timermgr
,
411 if (result
!= ISC_R_SUCCESS
)
414 (*clientp
)->attributes
|= DNS_CLIENTATTR_OWNCTX
;
416 /* client has its own reference to mctx, so we can detach it here */
417 isc_mem_detach(&mctx
);
419 return (ISC_R_SUCCESS
);
423 isc_taskmgr_destroy(&taskmgr
);
424 if (timermgr
!= NULL
)
425 isc_timermgr_destroy(&timermgr
);
426 if (socketmgr
!= NULL
)
427 isc_socketmgr_destroy(&socketmgr
);
429 isc_appctx_destroy(&actx
);
430 isc_mem_detach(&mctx
);
436 dns_client_createx(isc_mem_t
*mctx
, isc_appctx_t
*actx
, isc_taskmgr_t
*taskmgr
,
437 isc_socketmgr_t
*socketmgr
, isc_timermgr_t
*timermgr
,
438 unsigned int options
, dns_client_t
**clientp
)
441 result
= dns_client_createx2(mctx
, actx
, taskmgr
, socketmgr
, timermgr
,
442 options
, clientp
, NULL
, NULL
);
447 dns_client_createx2(isc_mem_t
*mctx
, isc_appctx_t
*actx
,
448 isc_taskmgr_t
*taskmgr
, isc_socketmgr_t
*socketmgr
,
449 isc_timermgr_t
*timermgr
, unsigned int options
,
450 dns_client_t
**clientp
, isc_sockaddr_t
*localaddr4
,
451 isc_sockaddr_t
*localaddr6
)
453 dns_client_t
*client
;
455 dns_dispatchmgr_t
*dispatchmgr
= NULL
;
456 dns_dispatch_t
*dispatchv4
= NULL
;
457 dns_dispatch_t
*dispatchv6
= NULL
;
458 dns_view_t
*view
= NULL
;
460 REQUIRE(mctx
!= NULL
);
461 REQUIRE(taskmgr
!= NULL
);
462 REQUIRE(timermgr
!= NULL
);
463 REQUIRE(socketmgr
!= NULL
);
464 REQUIRE(clientp
!= NULL
&& *clientp
== NULL
);
466 client
= isc_mem_get(mctx
, sizeof(*client
));
468 return (ISC_R_NOMEMORY
);
470 result
= isc_mutex_init(&client
->lock
);
471 if (result
!= ISC_R_SUCCESS
) {
472 isc_mem_put(mctx
, client
, sizeof(*client
));
477 client
->taskmgr
= taskmgr
;
478 client
->socketmgr
= socketmgr
;
479 client
->timermgr
= timermgr
;
482 result
= isc_task_create(client
->taskmgr
, 0, &client
->task
);
483 if (result
!= ISC_R_SUCCESS
)
486 result
= dns_dispatchmgr_create(mctx
, NULL
, &dispatchmgr
);
487 if (result
!= ISC_R_SUCCESS
)
489 client
->dispatchmgr
= dispatchmgr
;
492 * If only one address family is specified, use it.
493 * If neither family is specified, or if both are, use both.
495 client
->dispatchv4
= NULL
;
496 if (localaddr4
!= NULL
|| localaddr6
== NULL
) {
497 result
= getudpdispatch(AF_INET
, dispatchmgr
, socketmgr
,
499 &dispatchv4
, localaddr4
);
500 if (result
== ISC_R_SUCCESS
)
501 client
->dispatchv4
= dispatchv4
;
504 client
->dispatchv6
= NULL
;
505 if (localaddr6
!= NULL
|| localaddr4
== NULL
) {
506 result
= getudpdispatch(AF_INET6
, dispatchmgr
, socketmgr
,
508 &dispatchv6
, localaddr6
);
509 if (result
== ISC_R_SUCCESS
)
510 client
->dispatchv6
= dispatchv6
;
513 /* We need at least one of the dispatchers */
514 if (dispatchv4
== NULL
&& dispatchv6
== NULL
) {
515 INSIST(result
!= ISC_R_SUCCESS
);
519 /* Create the default view for class IN */
520 result
= createview(mctx
, dns_rdataclass_in
, options
, taskmgr
,
521 RESOLVER_NTASKS
, socketmgr
, timermgr
,
522 dispatchmgr
, dispatchv4
, dispatchv6
, &view
);
523 if (result
!= ISC_R_SUCCESS
)
525 ISC_LIST_INIT(client
->viewlist
);
526 ISC_LIST_APPEND(client
->viewlist
, view
, link
);
528 dns_view_freeze(view
); /* too early? */
530 ISC_LIST_INIT(client
->resctxs
);
531 ISC_LIST_INIT(client
->reqctxs
);
532 ISC_LIST_INIT(client
->updatectxs
);
535 isc_mem_attach(mctx
, &client
->mctx
);
537 client
->update_timeout
= DEF_UPDATE_TIMEOUT
;
538 client
->update_udptimeout
= DEF_UPDATE_UDPTIMEOUT
;
539 client
->update_udpretries
= DEF_UPDATE_UDPRETRIES
;
540 client
->find_timeout
= DEF_FIND_TIMEOUT
;
541 client
->find_udpretries
= DEF_FIND_UDPRETRIES
;
542 client
->attributes
= 0;
544 client
->references
= 1;
545 client
->magic
= DNS_CLIENT_MAGIC
;
549 return (ISC_R_SUCCESS
);
552 if (dispatchv4
!= NULL
)
553 dns_dispatch_detach(&dispatchv4
);
554 if (dispatchv6
!= NULL
)
555 dns_dispatch_detach(&dispatchv6
);
556 if (dispatchmgr
!= NULL
)
557 dns_dispatchmgr_destroy(&dispatchmgr
);
558 if (client
->task
!= NULL
)
559 isc_task_detach(&client
->task
);
560 isc_mem_put(mctx
, client
, sizeof(*client
));
566 destroyclient(dns_client_t
**clientp
) {
567 dns_client_t
*client
= *clientp
;
570 while ((view
= ISC_LIST_HEAD(client
->viewlist
)) != NULL
) {
571 ISC_LIST_UNLINK(client
->viewlist
, view
, link
);
572 dns_view_detach(&view
);
575 if (client
->dispatchv4
!= NULL
)
576 dns_dispatch_detach(&client
->dispatchv4
);
577 if (client
->dispatchv6
!= NULL
)
578 dns_dispatch_detach(&client
->dispatchv6
);
580 dns_dispatchmgr_destroy(&client
->dispatchmgr
);
582 isc_task_detach(&client
->task
);
585 * If the client has created its own running environments,
588 if ((client
->attributes
& DNS_CLIENTATTR_OWNCTX
) != 0) {
589 isc_taskmgr_destroy(&client
->taskmgr
);
590 isc_timermgr_destroy(&client
->timermgr
);
591 isc_socketmgr_destroy(&client
->socketmgr
);
593 isc_app_ctxfinish(client
->actx
);
594 isc_appctx_destroy(&client
->actx
);
597 DESTROYLOCK(&client
->lock
);
600 isc_mem_putanddetach(&client
->mctx
, client
, sizeof(*client
));
606 dns_client_destroy(dns_client_t
**clientp
) {
607 dns_client_t
*client
;
608 isc_boolean_t destroyok
= ISC_FALSE
;
610 REQUIRE(clientp
!= NULL
);
612 REQUIRE(DNS_CLIENT_VALID(client
));
615 client
->references
--;
616 if (client
->references
== 0 && ISC_LIST_EMPTY(client
->resctxs
) &&
617 ISC_LIST_EMPTY(client
->reqctxs
) &&
618 ISC_LIST_EMPTY(client
->updatectxs
)) {
619 destroyok
= ISC_TRUE
;
621 UNLOCK(&client
->lock
);
624 destroyclient(&client
);
630 dns_client_setservers(dns_client_t
*client
, dns_rdataclass_t rdclass
,
631 dns_name_t
*namespace, isc_sockaddrlist_t
*addrs
)
634 dns_view_t
*view
= NULL
;
636 REQUIRE(DNS_CLIENT_VALID(client
));
637 REQUIRE(addrs
!= NULL
);
639 if (namespace == NULL
)
640 namespace = dns_rootname
;
643 result
= dns_viewlist_find(&client
->viewlist
, DNS_CLIENTVIEW_NAME
,
645 if (result
!= ISC_R_SUCCESS
) {
646 UNLOCK(&client
->lock
);
649 UNLOCK(&client
->lock
);
651 result
= dns_fwdtable_add(view
->fwdtable
, namespace, addrs
,
654 dns_view_detach(&view
);
660 dns_client_clearservers(dns_client_t
*client
, dns_rdataclass_t rdclass
,
661 dns_name_t
*namespace)
664 dns_view_t
*view
= NULL
;
666 REQUIRE(DNS_CLIENT_VALID(client
));
668 if (namespace == NULL
)
669 namespace = dns_rootname
;
672 result
= dns_viewlist_find(&client
->viewlist
, DNS_CLIENTVIEW_NAME
,
674 if (result
!= ISC_R_SUCCESS
) {
675 UNLOCK(&client
->lock
);
678 UNLOCK(&client
->lock
);
680 result
= dns_fwdtable_delete(view
->fwdtable
, namespace);
682 dns_view_detach(&view
);
688 dns_client_setdlv(dns_client_t
*client
, dns_rdataclass_t rdclass
,
693 dns_view_t
*view
= NULL
;
695 REQUIRE(DNS_CLIENT_VALID(client
));
698 result
= dns_viewlist_find(&client
->viewlist
, DNS_CLIENTVIEW_NAME
,
700 UNLOCK(&client
->lock
);
701 if (result
!= ISC_R_SUCCESS
)
709 isc_buffer_constinit(&b
, dlvname
, strlen(dlvname
));
710 isc_buffer_add(&b
, strlen(dlvname
));
711 newdlv
= dns_fixedname_name(&view
->dlv_fixed
);
712 result
= dns_name_fromtext(newdlv
, &b
, dns_rootname
,
713 DNS_NAME_DOWNCASE
, NULL
);
714 if (result
!= ISC_R_SUCCESS
)
717 view
->dlv
= dns_fixedname_name(&view
->dlv_fixed
);
722 dns_view_detach(&view
);
728 getrdataset(isc_mem_t
*mctx
, dns_rdataset_t
**rdatasetp
) {
729 dns_rdataset_t
*rdataset
;
731 REQUIRE(mctx
!= NULL
);
732 REQUIRE(rdatasetp
!= NULL
&& *rdatasetp
== NULL
);
734 rdataset
= isc_mem_get(mctx
, sizeof(*rdataset
));
735 if (rdataset
== NULL
)
736 return (ISC_R_NOMEMORY
);
738 dns_rdataset_init(rdataset
);
740 *rdatasetp
= rdataset
;
742 return (ISC_R_SUCCESS
);
746 putrdataset(isc_mem_t
*mctx
, dns_rdataset_t
**rdatasetp
) {
747 dns_rdataset_t
*rdataset
;
749 REQUIRE(rdatasetp
!= NULL
);
750 rdataset
= *rdatasetp
;
751 REQUIRE(rdataset
!= NULL
);
753 if (dns_rdataset_isassociated(rdataset
))
754 dns_rdataset_disassociate(rdataset
);
756 isc_mem_put(mctx
, rdataset
, sizeof(*rdataset
));
762 fetch_done(isc_task_t
*task
, isc_event_t
*event
) {
763 resctx_t
*rctx
= event
->ev_arg
;
764 dns_fetchevent_t
*fevent
;
766 REQUIRE(event
->ev_type
== DNS_EVENT_FETCHDONE
);
767 REQUIRE(RCTX_VALID(rctx
));
768 REQUIRE(rctx
->task
== task
);
769 fevent
= (dns_fetchevent_t
*)event
;
771 client_resfind(rctx
, fevent
);
774 static inline isc_result_t
775 start_fetch(resctx_t
*rctx
) {
780 * The caller must be holding the rctx's lock.
783 REQUIRE(rctx
->fetch
== NULL
);
785 if (!rctx
->want_cdflag
)
786 fopts
|= DNS_FETCHOPT_NOCDFLAG
;
787 if (!rctx
->want_validation
)
788 fopts
|= DNS_FETCHOPT_NOVALIDATE
;
790 result
= dns_resolver_createfetch(rctx
->view
->resolver
,
791 dns_fixedname_name(&rctx
->name
),
793 NULL
, NULL
, NULL
, fopts
,
794 rctx
->task
, fetch_done
, rctx
,
803 view_find(resctx_t
*rctx
, dns_db_t
**dbp
, dns_dbnode_t
**nodep
,
804 dns_name_t
*foundname
)
807 dns_name_t
*name
= dns_fixedname_name(&rctx
->name
);
808 dns_rdatatype_t type
;
810 if (rctx
->type
== dns_rdatatype_rrsig
)
811 type
= dns_rdatatype_any
;
815 result
= dns_view_find(rctx
->view
, name
, type
, 0, 0, ISC_FALSE
,
816 dbp
, nodep
, foundname
, rctx
->rdataset
,
823 client_resfind(resctx_t
*rctx
, dns_fetchevent_t
*event
) {
825 isc_result_t tresult
, result
= ISC_R_SUCCESS
;
826 isc_result_t vresult
= ISC_R_SUCCESS
;
827 isc_boolean_t want_restart
;
828 isc_boolean_t send_event
= ISC_FALSE
;
829 dns_name_t
*name
, *prefix
;
830 dns_fixedname_t foundname
, fixed
;
831 dns_rdataset_t
*trdataset
;
832 dns_rdata_t rdata
= DNS_RDATA_INIT
;
833 unsigned int nlabels
;
835 dns_namereln_t namereln
;
836 dns_rdata_cname_t cname
;
837 dns_rdata_dname_t dname
;
839 REQUIRE(RCTX_VALID(rctx
));
843 mctx
= rctx
->view
->mctx
;
845 name
= dns_fixedname_name(&rctx
->name
);
848 dns_name_t
*fname
= NULL
;
849 dns_name_t
*ansname
= NULL
;
851 dns_dbnode_t
*node
= NULL
;
854 want_restart
= ISC_FALSE
;
856 if (event
== NULL
&& !rctx
->canceled
) {
857 dns_fixedname_init(&foundname
);
858 fname
= dns_fixedname_name(&foundname
);
859 INSIST(!dns_rdataset_isassociated(rctx
->rdataset
));
860 INSIST(rctx
->sigrdataset
== NULL
||
861 !dns_rdataset_isassociated(rctx
->sigrdataset
));
862 result
= view_find(rctx
, &db
, &node
, fname
);
863 if (result
== ISC_R_NOTFOUND
) {
865 * We don't know anything about the name.
870 dns_db_detachnode(db
, &node
);
874 result
= start_fetch(rctx
);
875 if (result
!= ISC_R_SUCCESS
) {
876 putrdataset(mctx
, &rctx
->rdataset
);
877 if (rctx
->sigrdataset
!= NULL
)
880 send_event
= ISC_TRUE
;
885 INSIST(event
!= NULL
);
886 INSIST(event
->fetch
== rctx
->fetch
);
887 dns_resolver_destroyfetch(&rctx
->fetch
);
890 result
= event
->result
;
891 vresult
= event
->vresult
;
892 fname
= dns_fixedname_name(&event
->foundname
);
893 INSIST(event
->rdataset
== rctx
->rdataset
);
894 INSIST(event
->sigrdataset
== rctx
->sigrdataset
);
898 * If we've been canceled, forget about the result.
901 result
= ISC_R_CANCELED
;
904 * Otherwise, get some resource for copying the
907 ansname
= isc_mem_get(mctx
, sizeof(*ansname
));
909 tresult
= ISC_R_NOMEMORY
;
913 aname
= dns_fixedname_name(&rctx
->name
);
914 dns_name_init(ansname
, NULL
);
915 tresult
= dns_name_dup(aname
, mctx
, ansname
);
916 if (tresult
!= ISC_R_SUCCESS
)
917 isc_mem_put(mctx
, ansname
,
920 if (tresult
!= ISC_R_SUCCESS
)
926 send_event
= ISC_TRUE
;
928 * This case is handled in the main line below.
933 * Add the CNAME to the answer list.
935 trdataset
= rctx
->rdataset
;
936 ISC_LIST_APPEND(ansname
->list
, rctx
->rdataset
, link
);
937 rctx
->rdataset
= NULL
;
938 if (rctx
->sigrdataset
!= NULL
) {
939 ISC_LIST_APPEND(ansname
->list
,
940 rctx
->sigrdataset
, link
);
941 rctx
->sigrdataset
= NULL
;
943 ISC_LIST_APPEND(rctx
->namelist
, ansname
, link
);
947 * Copy the CNAME's target into the lookup's
948 * query name and start over.
950 tresult
= dns_rdataset_first(trdataset
);
951 if (tresult
!= ISC_R_SUCCESS
)
953 dns_rdataset_current(trdataset
, &rdata
);
954 tresult
= dns_rdata_tostruct(&rdata
, &cname
, NULL
);
955 dns_rdata_reset(&rdata
);
956 if (tresult
!= ISC_R_SUCCESS
)
958 tresult
= dns_name_copy(&cname
.cname
, name
, NULL
);
959 dns_rdata_freestruct(&cname
);
960 if (tresult
== ISC_R_SUCCESS
)
961 want_restart
= ISC_TRUE
;
967 * Add the DNAME to the answer list.
969 trdataset
= rctx
->rdataset
;
970 ISC_LIST_APPEND(ansname
->list
, rctx
->rdataset
, link
);
971 rctx
->rdataset
= NULL
;
972 if (rctx
->sigrdataset
!= NULL
) {
973 ISC_LIST_APPEND(ansname
->list
,
974 rctx
->sigrdataset
, link
);
975 rctx
->sigrdataset
= NULL
;
977 ISC_LIST_APPEND(rctx
->namelist
, ansname
, link
);
980 namereln
= dns_name_fullcompare(name
, fname
, &order
,
982 INSIST(namereln
== dns_namereln_subdomain
);
984 * Get the target name of the DNAME.
986 tresult
= dns_rdataset_first(trdataset
);
987 if (tresult
!= ISC_R_SUCCESS
) {
991 dns_rdataset_current(trdataset
, &rdata
);
992 tresult
= dns_rdata_tostruct(&rdata
, &dname
, NULL
);
993 dns_rdata_reset(&rdata
);
994 if (tresult
!= ISC_R_SUCCESS
) {
999 * Construct the new query name and start over.
1001 dns_fixedname_init(&fixed
);
1002 prefix
= dns_fixedname_name(&fixed
);
1003 dns_name_split(name
, nlabels
, prefix
, NULL
);
1004 tresult
= dns_name_concatenate(prefix
, &dname
.dname
,
1006 dns_rdata_freestruct(&dname
);
1007 if (tresult
== ISC_R_SUCCESS
)
1008 want_restart
= ISC_TRUE
;
1012 case DNS_R_NCACHENXDOMAIN
:
1013 case DNS_R_NCACHENXRRSET
:
1014 ISC_LIST_APPEND(ansname
->list
, rctx
->rdataset
, link
);
1015 ISC_LIST_APPEND(rctx
->namelist
, ansname
, link
);
1017 rctx
->rdataset
= NULL
;
1018 /* What about sigrdataset? */
1019 if (rctx
->sigrdataset
!= NULL
)
1020 putrdataset(mctx
, &rctx
->sigrdataset
);
1021 send_event
= ISC_TRUE
;
1024 if (rctx
->rdataset
!= NULL
)
1025 putrdataset(mctx
, &rctx
->rdataset
);
1026 if (rctx
->sigrdataset
!= NULL
)
1027 putrdataset(mctx
, &rctx
->sigrdataset
);
1028 send_event
= ISC_TRUE
;
1032 if (rctx
->type
== dns_rdatatype_any
) {
1034 dns_rdatasetiter_t
*rdsiter
= NULL
;
1036 tresult
= dns_db_allrdatasets(db
, node
, NULL
, 0,
1038 if (tresult
!= ISC_R_SUCCESS
) {
1043 tresult
= dns_rdatasetiter_first(rdsiter
);
1044 while (tresult
== ISC_R_SUCCESS
) {
1045 dns_rdatasetiter_current(rdsiter
,
1047 if (rctx
->rdataset
->type
!= 0) {
1048 ISC_LIST_APPEND(ansname
->list
,
1052 rctx
->rdataset
= NULL
;
1055 * We're not interested in this
1058 dns_rdataset_disassociate(
1061 tresult
= dns_rdatasetiter_next(rdsiter
);
1063 if (tresult
== ISC_R_SUCCESS
&&
1064 rctx
->rdataset
== NULL
) {
1065 tresult
= getrdataset(mctx
,
1067 if (tresult
!= ISC_R_SUCCESS
) {
1076 * We didn't match any rdatasets (which means
1077 * something went wrong in this
1080 result
= DNS_R_SERVFAIL
; /* better code? */
1083 ISC_LIST_APPEND(rctx
->namelist
, ansname
, link
);
1086 dns_rdatasetiter_destroy(&rdsiter
);
1087 if (tresult
!= ISC_R_NOMORE
)
1088 result
= DNS_R_SERVFAIL
; /* ditto */
1090 result
= ISC_R_SUCCESS
;
1094 * This is the "normal" case -- an ordinary question
1095 * to which we've got the answer.
1097 ISC_LIST_APPEND(ansname
->list
, rctx
->rdataset
, link
);
1098 rctx
->rdataset
= NULL
;
1099 if (rctx
->sigrdataset
!= NULL
) {
1100 ISC_LIST_APPEND(ansname
->list
,
1101 rctx
->sigrdataset
, link
);
1102 rctx
->sigrdataset
= NULL
;
1104 ISC_LIST_APPEND(rctx
->namelist
, ansname
, link
);
1110 * Free temporary resources
1112 if (ansname
!= NULL
) {
1113 dns_rdataset_t
*rdataset
;
1115 while ((rdataset
= ISC_LIST_HEAD(ansname
->list
))
1117 ISC_LIST_UNLINK(ansname
->list
, rdataset
, link
);
1118 putrdataset(mctx
, &rdataset
);
1120 dns_name_free(ansname
, mctx
);
1121 isc_mem_put(mctx
, ansname
, sizeof(*ansname
));
1125 dns_db_detachnode(db
, &node
);
1129 isc_event_free(ISC_EVENT_PTR(&event
));
1132 * Limit the number of restarts.
1134 if (want_restart
&& rctx
->restarts
== MAX_RESTARTS
) {
1135 want_restart
= ISC_FALSE
;
1136 result
= ISC_R_QUOTA
;
1137 send_event
= ISC_TRUE
;
1141 * Prepare further find with new resources
1144 INSIST(rctx
->rdataset
== NULL
&&
1145 rctx
->sigrdataset
== NULL
);
1147 result
= getrdataset(mctx
, &rctx
->rdataset
);
1148 if (result
== ISC_R_SUCCESS
&& rctx
->want_dnssec
) {
1149 result
= getrdataset(mctx
, &rctx
->sigrdataset
);
1150 if (result
!= ISC_R_SUCCESS
) {
1151 putrdataset(mctx
, &rctx
->rdataset
);
1155 if (result
!= ISC_R_SUCCESS
) {
1156 want_restart
= ISC_FALSE
;
1157 send_event
= ISC_TRUE
;
1160 } while (want_restart
);
1165 while ((name
= ISC_LIST_HEAD(rctx
->namelist
)) != NULL
) {
1166 ISC_LIST_UNLINK(rctx
->namelist
, name
, link
);
1167 ISC_LIST_APPEND(rctx
->event
->answerlist
, name
, link
);
1170 rctx
->event
->result
= result
;
1171 rctx
->event
->vresult
= vresult
;
1172 task
= rctx
->event
->ev_sender
;
1173 rctx
->event
->ev_sender
= rctx
;
1174 isc_task_sendanddetach(&task
, ISC_EVENT_PTR(&rctx
->event
));
1177 UNLOCK(&rctx
->lock
);
1182 suspend(isc_task_t
*task
, isc_event_t
*event
) {
1183 isc_appctx_t
*actx
= event
->ev_arg
;
1187 isc_app_ctxsuspend(actx
);
1188 isc_event_free(&event
);
1192 resolve_done(isc_task_t
*task
, isc_event_t
*event
) {
1193 resarg_t
*resarg
= event
->ev_arg
;
1194 dns_clientresevent_t
*rev
= (dns_clientresevent_t
*)event
;
1196 isc_result_t result
;
1200 LOCK(&resarg
->lock
);
1202 resarg
->result
= rev
->result
;
1203 resarg
->vresult
= rev
->vresult
;
1204 while ((name
= ISC_LIST_HEAD(rev
->answerlist
)) != NULL
) {
1205 ISC_LIST_UNLINK(rev
->answerlist
, name
, link
);
1206 ISC_LIST_APPEND(*resarg
->namelist
, name
, link
);
1209 dns_client_destroyrestrans(&resarg
->trans
);
1210 isc_event_free(&event
);
1212 if (!resarg
->canceled
) {
1213 UNLOCK(&resarg
->lock
);
1216 * We may or may not be running. isc__appctx_onrun will
1217 * fail if we are currently running otherwise we post a
1218 * action to call isc_app_ctxsuspend when we do start
1221 result
= isc_app_ctxonrun(resarg
->actx
, resarg
->client
->mctx
,
1222 task
, suspend
, resarg
->actx
);
1223 if (result
== ISC_R_ALREADYRUNNING
)
1224 isc_app_ctxsuspend(resarg
->actx
);
1227 * We have already exited from the loop (due to some
1228 * unexpected event). Just clean the arg up.
1230 UNLOCK(&resarg
->lock
);
1231 DESTROYLOCK(&resarg
->lock
);
1232 isc_mem_put(resarg
->client
->mctx
, resarg
, sizeof(*resarg
));
1237 dns_client_resolve(dns_client_t
*client
, dns_name_t
*name
,
1238 dns_rdataclass_t rdclass
, dns_rdatatype_t type
,
1239 unsigned int options
, dns_namelist_t
*namelist
)
1241 isc_result_t result
;
1245 REQUIRE(DNS_CLIENT_VALID(client
));
1246 REQUIRE(namelist
!= NULL
&& ISC_LIST_EMPTY(*namelist
));
1248 if ((client
->attributes
& DNS_CLIENTATTR_OWNCTX
) == 0 &&
1249 (options
& DNS_CLIENTRESOPT_ALLOWRUN
) == 0) {
1251 * If the client is run under application's control, we need
1252 * to create a new running (sub)environment for this
1253 * particular resolution.
1255 return (ISC_R_NOTIMPLEMENTED
); /* XXXTBD */
1257 actx
= client
->actx
;
1259 resarg
= isc_mem_get(client
->mctx
, sizeof(*resarg
));
1261 return (ISC_R_NOMEMORY
);
1263 result
= isc_mutex_init(&resarg
->lock
);
1264 if (result
!= ISC_R_SUCCESS
) {
1265 isc_mem_put(client
->mctx
, resarg
, sizeof(*resarg
));
1269 resarg
->actx
= actx
;
1270 resarg
->client
= client
;
1271 resarg
->result
= DNS_R_SERVFAIL
;
1272 resarg
->namelist
= namelist
;
1273 resarg
->trans
= NULL
;
1274 resarg
->canceled
= ISC_FALSE
;
1275 result
= dns_client_startresolve(client
, name
, rdclass
, type
, options
,
1276 client
->task
, resolve_done
, resarg
,
1278 if (result
!= ISC_R_SUCCESS
) {
1279 DESTROYLOCK(&resarg
->lock
);
1280 isc_mem_put(client
->mctx
, resarg
, sizeof(*resarg
));
1285 * Start internal event loop. It blocks until the entire process
1288 result
= isc_app_ctxrun(actx
);
1290 LOCK(&resarg
->lock
);
1291 if (result
== ISC_R_SUCCESS
|| result
== ISC_R_SUSPEND
)
1292 result
= resarg
->result
;
1293 if (result
!= ISC_R_SUCCESS
&& resarg
->vresult
!= ISC_R_SUCCESS
) {
1295 * If this lookup failed due to some error in DNSSEC
1296 * validation, return the validation error code.
1297 * XXX: or should we pass the validation result separately?
1299 result
= resarg
->vresult
;
1301 if (resarg
->trans
!= NULL
) {
1303 * Unusual termination (perhaps due to signal). We need some
1304 * tricky cleanup process.
1306 resarg
->canceled
= ISC_TRUE
;
1307 dns_client_cancelresolve(resarg
->trans
);
1309 UNLOCK(&resarg
->lock
);
1311 /* resarg will be freed in the event handler. */
1313 UNLOCK(&resarg
->lock
);
1315 DESTROYLOCK(&resarg
->lock
);
1316 isc_mem_put(client
->mctx
, resarg
, sizeof(*resarg
));
1323 dns_client_startresolve(dns_client_t
*client
, dns_name_t
*name
,
1324 dns_rdataclass_t rdclass
, dns_rdatatype_t type
,
1325 unsigned int options
, isc_task_t
*task
,
1326 isc_taskaction_t action
, void *arg
,
1327 dns_clientrestrans_t
**transp
)
1329 dns_view_t
*view
= NULL
;
1330 dns_clientresevent_t
*event
= NULL
;
1331 resctx_t
*rctx
= NULL
;
1332 isc_task_t
*clone
= NULL
;
1334 isc_result_t result
;
1335 dns_rdataset_t
*rdataset
, *sigrdataset
;
1336 isc_boolean_t want_dnssec
, want_validation
, want_cdflag
;
1338 REQUIRE(DNS_CLIENT_VALID(client
));
1339 REQUIRE(transp
!= NULL
&& *transp
== NULL
);
1341 LOCK(&client
->lock
);
1342 result
= dns_viewlist_find(&client
->viewlist
, DNS_CLIENTVIEW_NAME
,
1344 UNLOCK(&client
->lock
);
1345 if (result
!= ISC_R_SUCCESS
)
1348 mctx
= client
->mctx
;
1351 want_dnssec
= ISC_TF((options
& DNS_CLIENTRESOPT_NODNSSEC
) == 0);
1352 want_validation
= ISC_TF((options
& DNS_CLIENTRESOPT_NOVALIDATE
) == 0);
1353 want_cdflag
= ISC_TF((options
& DNS_CLIENTRESOPT_NOCDFLAG
) == 0);
1356 * Prepare some intermediate resources
1359 isc_task_attach(task
, &clone
);
1360 event
= (dns_clientresevent_t
*)
1361 isc_event_allocate(mctx
, clone
, DNS_EVENT_CLIENTRESDONE
,
1362 action
, arg
, sizeof(*event
));
1363 if (event
== NULL
) {
1364 result
= ISC_R_NOMEMORY
;
1367 event
->result
= DNS_R_SERVFAIL
;
1368 ISC_LIST_INIT(event
->answerlist
);
1370 rctx
= isc_mem_get(mctx
, sizeof(*rctx
));
1372 result
= ISC_R_NOMEMORY
;
1374 result
= isc_mutex_init(&rctx
->lock
);
1375 if (result
!= ISC_R_SUCCESS
) {
1376 isc_mem_put(mctx
, rctx
, sizeof(*rctx
));
1380 if (result
!= ISC_R_SUCCESS
)
1383 result
= getrdataset(mctx
, &rdataset
);
1384 if (result
!= ISC_R_SUCCESS
)
1386 rctx
->rdataset
= rdataset
;
1389 result
= getrdataset(mctx
, &sigrdataset
);
1390 if (result
!= ISC_R_SUCCESS
)
1393 rctx
->sigrdataset
= sigrdataset
;
1395 dns_fixedname_init(&rctx
->name
);
1396 result
= dns_name_copy(name
, dns_fixedname_name(&rctx
->name
), NULL
);
1397 if (result
!= ISC_R_SUCCESS
)
1400 rctx
->client
= client
;
1401 ISC_LINK_INIT(rctx
, link
);
1402 rctx
->canceled
= ISC_FALSE
;
1403 rctx
->task
= client
->task
;
1408 rctx
->want_dnssec
= want_dnssec
;
1409 rctx
->want_validation
= want_validation
;
1410 rctx
->want_cdflag
= want_cdflag
;
1411 ISC_LIST_INIT(rctx
->namelist
);
1412 rctx
->event
= event
;
1414 rctx
->magic
= RCTX_MAGIC
;
1416 LOCK(&client
->lock
);
1417 ISC_LIST_APPEND(client
->resctxs
, rctx
, link
);
1418 UNLOCK(&client
->lock
);
1420 *transp
= (dns_clientrestrans_t
*)rctx
;
1421 client_resfind(rctx
, NULL
);
1423 return (ISC_R_SUCCESS
);
1426 if (rdataset
!= NULL
)
1427 putrdataset(client
->mctx
, &rdataset
);
1428 if (sigrdataset
!= NULL
)
1429 putrdataset(client
->mctx
, &sigrdataset
);
1431 DESTROYLOCK(&rctx
->lock
);
1432 isc_mem_put(mctx
, rctx
, sizeof(*rctx
));
1435 isc_event_free(ISC_EVENT_PTR(&event
));
1436 isc_task_detach(&clone
);
1437 dns_view_detach(&view
);
1443 dns_client_cancelresolve(dns_clientrestrans_t
*trans
) {
1446 REQUIRE(trans
!= NULL
);
1447 rctx
= (resctx_t
*)trans
;
1448 REQUIRE(RCTX_VALID(rctx
));
1452 if (!rctx
->canceled
) {
1453 rctx
->canceled
= ISC_TRUE
;
1454 if (rctx
->fetch
!= NULL
)
1455 dns_resolver_cancelfetch(rctx
->fetch
);
1458 UNLOCK(&rctx
->lock
);
1462 dns_client_freeresanswer(dns_client_t
*client
, dns_namelist_t
*namelist
) {
1464 dns_rdataset_t
*rdataset
;
1466 REQUIRE(DNS_CLIENT_VALID(client
));
1467 REQUIRE(namelist
!= NULL
);
1469 while ((name
= ISC_LIST_HEAD(*namelist
)) != NULL
) {
1470 ISC_LIST_UNLINK(*namelist
, name
, link
);
1471 while ((rdataset
= ISC_LIST_HEAD(name
->list
)) != NULL
) {
1472 ISC_LIST_UNLINK(name
->list
, rdataset
, link
);
1473 putrdataset(client
->mctx
, &rdataset
);
1475 dns_name_free(name
, client
->mctx
);
1476 isc_mem_put(client
->mctx
, name
, sizeof(*name
));
1481 dns_client_destroyrestrans(dns_clientrestrans_t
**transp
) {
1484 dns_client_t
*client
;
1485 isc_boolean_t need_destroyclient
= ISC_FALSE
;
1487 REQUIRE(transp
!= NULL
);
1488 rctx
= (resctx_t
*)*transp
;
1489 REQUIRE(RCTX_VALID(rctx
));
1490 REQUIRE(rctx
->fetch
== NULL
);
1491 REQUIRE(rctx
->event
== NULL
);
1492 client
= rctx
->client
;
1493 REQUIRE(DNS_CLIENT_VALID(client
));
1495 mctx
= client
->mctx
;
1496 dns_view_detach(&rctx
->view
);
1498 LOCK(&client
->lock
);
1500 INSIST(ISC_LINK_LINKED(rctx
, link
));
1501 ISC_LIST_UNLINK(client
->resctxs
, rctx
, link
);
1503 if (client
->references
== 0 && ISC_LIST_EMPTY(client
->resctxs
) &&
1504 ISC_LIST_EMPTY(client
->reqctxs
) &&
1505 ISC_LIST_EMPTY(client
->updatectxs
))
1506 need_destroyclient
= ISC_TRUE
;
1508 UNLOCK(&client
->lock
);
1510 INSIST(ISC_LIST_EMPTY(rctx
->namelist
));
1512 DESTROYLOCK(&rctx
->lock
);
1515 isc_mem_put(mctx
, rctx
, sizeof(*rctx
));
1517 if (need_destroyclient
)
1518 destroyclient(&client
);
1524 dns_client_addtrustedkey(dns_client_t
*client
, dns_rdataclass_t rdclass
,
1525 dns_name_t
*keyname
, isc_buffer_t
*keydatabuf
)
1527 isc_result_t result
;
1528 dns_view_t
*view
= NULL
;
1529 dst_key_t
*dstkey
= NULL
;
1530 dns_keytable_t
*secroots
= NULL
;
1532 REQUIRE(DNS_CLIENT_VALID(client
));
1534 LOCK(&client
->lock
);
1535 result
= dns_viewlist_find(&client
->viewlist
, DNS_CLIENTVIEW_NAME
,
1537 UNLOCK(&client
->lock
);
1538 if (result
!= ISC_R_SUCCESS
)
1541 result
= dns_view_getsecroots(view
, &secroots
);
1542 if (result
!= ISC_R_SUCCESS
)
1545 result
= dst_key_fromdns(keyname
, rdclass
, keydatabuf
, client
->mctx
,
1547 if (result
!= ISC_R_SUCCESS
)
1550 result
= dns_keytable_add(secroots
, ISC_FALSE
, &dstkey
);
1554 dst_key_free(&dstkey
);
1556 dns_view_detach(&view
);
1557 if (secroots
!= NULL
)
1558 dns_keytable_detach(&secroots
);
1563 * Simple request routines
1566 request_done(isc_task_t
*task
, isc_event_t
*event
) {
1567 dns_requestevent_t
*reqev
= NULL
;
1568 dns_request_t
*request
;
1569 isc_result_t result
, eresult
;
1574 REQUIRE(event
->ev_type
== DNS_EVENT_REQUESTDONE
);
1575 reqev
= (dns_requestevent_t
*)event
;
1576 request
= reqev
->request
;
1577 result
= eresult
= reqev
->result
;
1578 ctx
= reqev
->ev_arg
;
1579 REQUIRE(REQCTX_VALID(ctx
));
1581 isc_event_free(&event
);
1585 if (eresult
== ISC_R_SUCCESS
) {
1586 result
= dns_request_getresponse(request
, ctx
->event
->rmessage
,
1590 if (ctx
->tsigkey
!= NULL
)
1591 dns_tsigkey_detach(&ctx
->tsigkey
);
1594 ctx
->event
->result
= ISC_R_CANCELED
;
1596 ctx
->event
->result
= result
;
1597 task
= ctx
->event
->ev_sender
;
1598 ctx
->event
->ev_sender
= ctx
;
1599 isc_task_sendanddetach(&task
, ISC_EVENT_PTR(&ctx
->event
));
1605 localrequest_done(isc_task_t
*task
, isc_event_t
*event
) {
1606 reqarg_t
*reqarg
= event
->ev_arg
;
1607 dns_clientreqevent_t
*rev
=(dns_clientreqevent_t
*)event
;
1611 REQUIRE(event
->ev_type
== DNS_EVENT_CLIENTREQDONE
);
1613 LOCK(&reqarg
->lock
);
1615 reqarg
->result
= rev
->result
;
1616 dns_client_destroyreqtrans(&reqarg
->trans
);
1617 isc_event_free(&event
);
1619 if (!reqarg
->canceled
) {
1620 UNLOCK(&reqarg
->lock
);
1622 /* Exit from the internal event loop */
1623 isc_app_ctxsuspend(reqarg
->actx
);
1626 * We have already exited from the loop (due to some
1627 * unexpected event). Just clean the arg up.
1629 UNLOCK(&reqarg
->lock
);
1630 DESTROYLOCK(&reqarg
->lock
);
1631 isc_mem_put(reqarg
->client
->mctx
, reqarg
, sizeof(*reqarg
));
1636 dns_client_request(dns_client_t
*client
, dns_message_t
*qmessage
,
1637 dns_message_t
*rmessage
, isc_sockaddr_t
*server
,
1638 unsigned int options
, unsigned int parseoptions
,
1639 dns_tsec_t
*tsec
, unsigned int timeout
,
1640 unsigned int udptimeout
, unsigned int udpretries
)
1644 isc_result_t result
;
1646 REQUIRE(DNS_CLIENT_VALID(client
));
1647 REQUIRE(qmessage
!= NULL
);
1648 REQUIRE(rmessage
!= NULL
);
1650 if ((client
->attributes
& DNS_CLIENTATTR_OWNCTX
) == 0 &&
1651 (options
& DNS_CLIENTREQOPT_ALLOWRUN
) == 0) {
1653 * If the client is run under application's control, we need
1654 * to create a new running (sub)environment for this
1655 * particular resolution.
1657 return (ISC_R_NOTIMPLEMENTED
); /* XXXTBD */
1659 actx
= client
->actx
;
1661 reqarg
= isc_mem_get(client
->mctx
, sizeof(*reqarg
));
1663 return (ISC_R_NOMEMORY
);
1665 result
= isc_mutex_init(&reqarg
->lock
);
1666 if (result
!= ISC_R_SUCCESS
) {
1667 isc_mem_put(client
->mctx
, reqarg
, sizeof(*reqarg
));
1671 reqarg
->actx
= actx
;
1672 reqarg
->client
= client
;
1673 reqarg
->trans
= NULL
;
1674 reqarg
->canceled
= ISC_FALSE
;
1676 result
= dns_client_startrequest(client
, qmessage
, rmessage
, server
,
1677 options
, parseoptions
, tsec
, timeout
,
1678 udptimeout
, udpretries
,
1679 client
->task
, localrequest_done
,
1680 reqarg
, &reqarg
->trans
);
1681 if (result
!= ISC_R_SUCCESS
) {
1682 DESTROYLOCK(&reqarg
->lock
);
1683 isc_mem_put(client
->mctx
, reqarg
, sizeof(*reqarg
));
1688 * Start internal event loop. It blocks until the entire process
1691 result
= isc_app_ctxrun(actx
);
1693 LOCK(&reqarg
->lock
);
1694 if (result
== ISC_R_SUCCESS
|| result
== ISC_R_SUSPEND
)
1695 result
= reqarg
->result
;
1696 if (reqarg
->trans
!= NULL
) {
1698 * Unusual termination (perhaps due to signal). We need some
1699 * tricky cleanup process.
1701 reqarg
->canceled
= ISC_TRUE
;
1702 dns_client_cancelresolve(reqarg
->trans
);
1704 UNLOCK(&reqarg
->lock
);
1706 /* reqarg will be freed in the event handler. */
1708 UNLOCK(&reqarg
->lock
);
1710 DESTROYLOCK(&reqarg
->lock
);
1711 isc_mem_put(client
->mctx
, reqarg
, sizeof(*reqarg
));
1718 dns_client_startrequest(dns_client_t
*client
, dns_message_t
*qmessage
,
1719 dns_message_t
*rmessage
, isc_sockaddr_t
*server
,
1720 unsigned int options
, unsigned int parseoptions
,
1721 dns_tsec_t
*tsec
, unsigned int timeout
,
1722 unsigned int udptimeout
, unsigned int udpretries
,
1723 isc_task_t
*task
, isc_taskaction_t action
, void *arg
,
1724 dns_clientreqtrans_t
**transp
)
1726 isc_result_t result
;
1727 dns_view_t
*view
= NULL
;
1728 isc_task_t
*clone
= NULL
;
1729 dns_clientreqevent_t
*event
= NULL
;
1730 reqctx_t
*ctx
= NULL
;
1731 dns_tsectype_t tsectype
= dns_tsectype_none
;
1735 REQUIRE(DNS_CLIENT_VALID(client
));
1736 REQUIRE(qmessage
!= NULL
);
1737 REQUIRE(rmessage
!= NULL
);
1738 REQUIRE(transp
!= NULL
&& *transp
== NULL
);
1741 tsectype
= dns_tsec_gettype(tsec
);
1742 if (tsectype
!= dns_tsectype_tsig
)
1743 return (ISC_R_NOTIMPLEMENTED
); /* XXX */
1746 LOCK(&client
->lock
);
1747 result
= dns_viewlist_find(&client
->viewlist
, DNS_CLIENTVIEW_NAME
,
1748 qmessage
->rdclass
, &view
);
1749 UNLOCK(&client
->lock
);
1750 if (result
!= ISC_R_SUCCESS
)
1754 isc_task_attach(task
, &clone
);
1755 event
= (dns_clientreqevent_t
*)
1756 isc_event_allocate(client
->mctx
, clone
,
1757 DNS_EVENT_CLIENTREQDONE
,
1758 action
, arg
, sizeof(*event
));
1759 if (event
== NULL
) {
1760 result
= ISC_R_NOMEMORY
;
1764 ctx
= isc_mem_get(client
->mctx
, sizeof(*ctx
));
1766 result
= ISC_R_NOMEMORY
;
1768 result
= isc_mutex_init(&ctx
->lock
);
1769 if (result
!= ISC_R_SUCCESS
) {
1770 isc_mem_put(client
->mctx
, ctx
, sizeof(*ctx
));
1774 if (result
!= ISC_R_SUCCESS
)
1777 ctx
->client
= client
;
1778 ISC_LINK_INIT(ctx
, link
);
1779 ctx
->parseoptions
= parseoptions
;
1780 ctx
->canceled
= ISC_FALSE
;
1782 ctx
->event
->rmessage
= rmessage
;
1783 ctx
->tsigkey
= NULL
;
1785 dns_tsec_getkey(tsec
, &ctx
->tsigkey
);
1787 ctx
->magic
= REQCTX_MAGIC
;
1789 LOCK(&client
->lock
);
1790 ISC_LIST_APPEND(client
->reqctxs
, ctx
, link
);
1791 UNLOCK(&client
->lock
);
1793 ctx
->request
= NULL
;
1794 result
= dns_request_createvia3(view
->requestmgr
, qmessage
, NULL
,
1795 server
, options
, ctx
->tsigkey
,
1796 timeout
, udptimeout
, udpretries
,
1797 client
->task
, request_done
, ctx
,
1799 if (result
== ISC_R_SUCCESS
) {
1800 dns_view_detach(&view
);
1801 *transp
= (dns_clientreqtrans_t
*)ctx
;
1802 return (ISC_R_SUCCESS
);
1807 LOCK(&client
->lock
);
1808 ISC_LIST_UNLINK(client
->reqctxs
, ctx
, link
);
1809 UNLOCK(&client
->lock
);
1810 DESTROYLOCK(&ctx
->lock
);
1811 isc_mem_put(client
->mctx
, ctx
, sizeof(*ctx
));
1814 isc_event_free(ISC_EVENT_PTR(&event
));
1815 isc_task_detach(&clone
);
1816 dns_view_detach(&view
);
1822 dns_client_cancelrequest(dns_clientreqtrans_t
*trans
) {
1825 REQUIRE(trans
!= NULL
);
1826 ctx
= (reqctx_t
*)trans
;
1827 REQUIRE(REQCTX_VALID(ctx
));
1831 if (!ctx
->canceled
) {
1832 ctx
->canceled
= ISC_TRUE
;
1833 if (ctx
->request
!= NULL
)
1834 dns_request_cancel(ctx
->request
);
1841 dns_client_destroyreqtrans(dns_clientreqtrans_t
**transp
) {
1844 dns_client_t
*client
;
1845 isc_boolean_t need_destroyclient
= ISC_FALSE
;
1847 REQUIRE(transp
!= NULL
);
1848 ctx
= (reqctx_t
*)*transp
;
1849 REQUIRE(REQCTX_VALID(ctx
));
1850 client
= ctx
->client
;
1851 REQUIRE(DNS_CLIENT_VALID(client
));
1852 REQUIRE(ctx
->event
== NULL
);
1853 REQUIRE(ctx
->request
!= NULL
);
1855 dns_request_destroy(&ctx
->request
);
1856 mctx
= client
->mctx
;
1858 LOCK(&client
->lock
);
1860 INSIST(ISC_LINK_LINKED(ctx
, link
));
1861 ISC_LIST_UNLINK(client
->reqctxs
, ctx
, link
);
1863 if (client
->references
== 0 && ISC_LIST_EMPTY(client
->resctxs
) &&
1864 ISC_LIST_EMPTY(client
->reqctxs
) &&
1865 ISC_LIST_EMPTY(client
->updatectxs
)) {
1866 need_destroyclient
= ISC_TRUE
;
1869 UNLOCK(&client
->lock
);
1871 DESTROYLOCK(&ctx
->lock
);
1874 isc_mem_put(mctx
, ctx
, sizeof(*ctx
));
1876 if (need_destroyclient
)
1877 destroyclient(&client
);
1883 * Dynamic update routines
1886 rcode2result(dns_rcode_t rcode
) {
1887 /* XXX: isn't there a similar function? */
1889 case dns_rcode_formerr
:
1890 return (DNS_R_FORMERR
);
1891 case dns_rcode_servfail
:
1892 return (DNS_R_SERVFAIL
);
1893 case dns_rcode_nxdomain
:
1894 return (DNS_R_NXDOMAIN
);
1895 case dns_rcode_notimp
:
1896 return (DNS_R_NOTIMP
);
1897 case dns_rcode_refused
:
1898 return (DNS_R_REFUSED
);
1899 case dns_rcode_yxdomain
:
1900 return (DNS_R_YXDOMAIN
);
1901 case dns_rcode_yxrrset
:
1902 return (DNS_R_YXRRSET
);
1903 case dns_rcode_nxrrset
:
1904 return (DNS_R_NXRRSET
);
1905 case dns_rcode_notauth
:
1906 return (DNS_R_NOTAUTH
);
1907 case dns_rcode_notzone
:
1908 return (DNS_R_NOTZONE
);
1909 case dns_rcode_badvers
:
1910 return (DNS_R_BADVERS
);
1913 return (ISC_R_FAILURE
);
1917 update_sendevent(updatectx_t
*uctx
, isc_result_t result
) {
1920 dns_message_destroy(&uctx
->updatemsg
);
1921 if (uctx
->tsigkey
!= NULL
)
1922 dns_tsigkey_detach(&uctx
->tsigkey
);
1923 if (uctx
->sig0key
!= NULL
)
1924 dst_key_free(&uctx
->sig0key
);
1927 uctx
->event
->result
= ISC_R_CANCELED
;
1929 uctx
->event
->result
= result
;
1930 uctx
->event
->state
= uctx
->state
;
1931 task
= uctx
->event
->ev_sender
;
1932 uctx
->event
->ev_sender
= uctx
;
1933 isc_task_sendanddetach(&task
, ISC_EVENT_PTR(&uctx
->event
));
1937 update_done(isc_task_t
*task
, isc_event_t
*event
) {
1938 isc_result_t result
;
1939 dns_requestevent_t
*reqev
= NULL
;
1940 dns_request_t
*request
;
1941 dns_message_t
*answer
= NULL
;
1942 updatectx_t
*uctx
= event
->ev_arg
;
1943 dns_client_t
*client
;
1944 unsigned int timeout
;
1948 REQUIRE(event
->ev_type
== DNS_EVENT_REQUESTDONE
);
1949 reqev
= (dns_requestevent_t
*)event
;
1950 request
= reqev
->request
;
1951 REQUIRE(UCTX_VALID(uctx
));
1952 client
= uctx
->client
;
1953 REQUIRE(DNS_CLIENT_VALID(client
));
1955 result
= reqev
->result
;
1956 if (result
!= ISC_R_SUCCESS
)
1959 result
= dns_message_create(client
->mctx
, DNS_MESSAGE_INTENTPARSE
,
1961 if (result
!= ISC_R_SUCCESS
)
1963 uctx
->state
= dns_clientupdatestate_done
;
1964 result
= dns_request_getresponse(request
, answer
,
1965 DNS_MESSAGEPARSE_PRESERVEORDER
);
1966 if (result
== ISC_R_SUCCESS
&& answer
->rcode
!= dns_rcode_noerror
)
1967 result
= rcode2result(answer
->rcode
);
1971 dns_message_destroy(&answer
);
1972 isc_event_free(&event
);
1975 uctx
->currentserver
= ISC_LIST_NEXT(uctx
->currentserver
, link
);
1976 dns_request_destroy(&uctx
->updatereq
);
1977 if (result
!= ISC_R_SUCCESS
&& !uctx
->canceled
&&
1978 uctx
->currentserver
!= NULL
) {
1979 dns_message_renderreset(uctx
->updatemsg
);
1980 dns_message_settsigkey(uctx
->updatemsg
, NULL
);
1982 timeout
= client
->update_timeout
/ uctx
->nservers
;
1983 if (timeout
< MIN_UPDATE_TIMEOUT
)
1984 timeout
= MIN_UPDATE_TIMEOUT
;
1985 result
= dns_request_createvia3(uctx
->view
->requestmgr
,
1988 uctx
->currentserver
, 0,
1991 client
->update_udptimeout
,
1992 client
->update_udpretries
,
1996 UNLOCK(&uctx
->lock
);
1998 if (result
== ISC_R_SUCCESS
) {
1999 /* XXX: should we keep the 'done' state here? */
2000 uctx
->state
= dns_clientupdatestate_sent
;
2004 UNLOCK(&uctx
->lock
);
2006 update_sendevent(uctx
, result
);
2010 send_update(updatectx_t
*uctx
) {
2011 isc_result_t result
;
2012 dns_name_t
*name
= NULL
;
2013 dns_rdataset_t
*rdataset
= NULL
;
2014 dns_client_t
*client
= uctx
->client
;
2015 unsigned int timeout
;
2017 REQUIRE(uctx
->zonename
!= NULL
&& uctx
->currentserver
!= NULL
);
2019 result
= dns_message_gettempname(uctx
->updatemsg
, &name
);
2020 if (result
!= ISC_R_SUCCESS
)
2022 dns_name_init(name
, NULL
);
2023 dns_name_clone(uctx
->zonename
, name
);
2024 result
= dns_message_gettemprdataset(uctx
->updatemsg
, &rdataset
);
2025 if (result
!= ISC_R_SUCCESS
) {
2026 dns_message_puttempname(uctx
->updatemsg
, &name
);
2029 dns_rdataset_makequestion(rdataset
, uctx
->rdclass
, dns_rdatatype_soa
);
2030 ISC_LIST_INIT(name
->list
);
2031 ISC_LIST_APPEND(name
->list
, rdataset
, link
);
2032 dns_message_addname(uctx
->updatemsg
, name
, DNS_SECTION_ZONE
);
2033 if (uctx
->tsigkey
== NULL
&& uctx
->sig0key
!= NULL
) {
2034 result
= dns_message_setsig0key(uctx
->updatemsg
,
2036 if (result
!= ISC_R_SUCCESS
)
2039 timeout
= client
->update_timeout
/ uctx
->nservers
;
2040 if (timeout
< MIN_UPDATE_TIMEOUT
)
2041 timeout
= MIN_UPDATE_TIMEOUT
;
2042 result
= dns_request_createvia3(uctx
->view
->requestmgr
,
2044 NULL
, uctx
->currentserver
, 0,
2045 uctx
->tsigkey
, timeout
,
2046 client
->update_udptimeout
,
2047 client
->update_udpretries
,
2048 client
->task
, update_done
, uctx
,
2050 if (result
== ISC_R_SUCCESS
&&
2051 uctx
->state
== dns_clientupdatestate_prepare
) {
2052 uctx
->state
= dns_clientupdatestate_sent
;
2059 resolveaddr_done(isc_task_t
*task
, isc_event_t
*event
) {
2060 isc_result_t result
;
2062 dns_rdatatype_t qtype
;
2063 dns_clientresevent_t
*rev
= (dns_clientresevent_t
*)event
;
2065 dns_rdataset_t
*rdataset
;
2067 isc_boolean_t completed
= ISC_FALSE
;
2071 REQUIRE(event
->ev_arg
!= NULL
);
2072 uctx
= *(updatectx_t
**)event
->ev_arg
;
2073 REQUIRE(UCTX_VALID(uctx
));
2075 if (event
->ev_arg
== &uctx
->bp4
) {
2077 qtype
= dns_rdatatype_a
;
2079 dns_client_destroyrestrans(&uctx
->restrans
);
2080 UNLOCK(&uctx
->lock
);
2082 INSIST(event
->ev_arg
== &uctx
->bp6
);
2084 qtype
= dns_rdatatype_aaaa
;
2086 dns_client_destroyrestrans(&uctx
->restrans2
);
2087 UNLOCK(&uctx
->lock
);
2090 result
= rev
->result
;
2091 if (result
!= ISC_R_SUCCESS
)
2094 for (name
= ISC_LIST_HEAD(rev
->answerlist
); name
!= NULL
;
2095 name
= ISC_LIST_NEXT(name
, link
)) {
2096 for (rdataset
= ISC_LIST_HEAD(name
->list
);
2098 rdataset
= ISC_LIST_NEXT(rdataset
, link
)) {
2099 if (!dns_rdataset_isassociated(rdataset
))
2101 if (rdataset
->type
!= qtype
)
2104 for (result
= dns_rdataset_first(rdataset
);
2105 result
== ISC_R_SUCCESS
;
2106 result
= dns_rdataset_next(rdataset
)) {
2108 dns_rdata_in_a_t rdata_a
;
2109 dns_rdata_in_aaaa_t rdata_aaaa
;
2112 sa
= isc_mem_get(uctx
->client
->mctx
,
2116 * If we fail to get a sockaddr,
2117 we simply move forward with the
2118 * addresses we've got so far.
2123 dns_rdata_init(&rdata
);
2126 dns_rdataset_current(rdataset
, &rdata
);
2127 result
= dns_rdata_tostruct(&rdata
, &rdata_a
,
2129 RUNTIME_CHECK(result
== ISC_R_SUCCESS
);
2130 isc_sockaddr_fromin(sa
,
2133 dns_rdata_freestruct(&rdata_a
);
2136 dns_rdataset_current(rdataset
, &rdata
);
2137 result
= dns_rdata_tostruct(&rdata
, &rdata_aaaa
,
2139 RUNTIME_CHECK(result
== ISC_R_SUCCESS
);
2140 isc_sockaddr_fromin6(sa
,
2141 &rdata_aaaa
.in6_addr
,
2143 dns_rdata_freestruct(&rdata_aaaa
);
2147 ISC_LINK_INIT(sa
, link
);
2148 ISC_LIST_APPEND(uctx
->servers
, sa
, link
);
2155 dns_client_freeresanswer(uctx
->client
, &rev
->answerlist
);
2156 isc_event_free(&event
);
2159 if (uctx
->restrans
== NULL
&& uctx
->restrans2
== NULL
)
2160 completed
= ISC_TRUE
;
2161 UNLOCK(&uctx
->lock
);
2164 INSIST(uctx
->currentserver
== NULL
);
2165 uctx
->currentserver
= ISC_LIST_HEAD(uctx
->servers
);
2166 if (uctx
->currentserver
!= NULL
&& !uctx
->canceled
)
2169 if (result
== ISC_R_SUCCESS
)
2170 result
= ISC_R_NOTFOUND
;
2171 update_sendevent(uctx
, result
);
2177 process_soa(updatectx_t
*uctx
, dns_rdataset_t
*soaset
, dns_name_t
*soaname
) {
2178 isc_result_t result
;
2179 dns_rdata_t soarr
= DNS_RDATA_INIT
;
2180 dns_rdata_soa_t soa
;
2183 result
= dns_rdataset_first(soaset
);
2184 if (result
!= ISC_R_SUCCESS
)
2186 dns_rdata_init(&soarr
);
2187 dns_rdataset_current(soaset
, &soarr
);
2188 result
= dns_rdata_tostruct(&soarr
, &soa
, NULL
);
2189 if (result
!= ISC_R_SUCCESS
)
2192 dns_name_init(&primary
, NULL
);
2193 dns_name_clone(&soa
.origin
, &primary
);
2195 if (uctx
->zonename
== NULL
) {
2196 uctx
->zonename
= dns_fixedname_name(&uctx
->zonefname
);
2197 result
= dns_name_copy(soaname
, uctx
->zonename
, NULL
);
2198 if (result
!= ISC_R_SUCCESS
)
2202 if (uctx
->currentserver
!= NULL
)
2203 result
= send_update(uctx
);
2206 * Get addresses of the primary server. We don't use the ADB
2207 * feature so that we could avoid caching data.
2211 result
= dns_client_startresolve(uctx
->client
, &primary
,
2214 0, uctx
->client
->task
,
2215 resolveaddr_done
, &uctx
->bp4
,
2217 if (result
== ISC_R_SUCCESS
) {
2219 result
= dns_client_startresolve(uctx
->client
,
2223 0, uctx
->client
->task
,
2228 UNLOCK(&uctx
->lock
);
2232 dns_rdata_freestruct(&soa
);
2238 receive_soa(isc_task_t
*task
, isc_event_t
*event
) {
2239 dns_requestevent_t
*reqev
= NULL
;
2241 dns_client_t
*client
;
2242 isc_result_t result
, eresult
;
2243 dns_request_t
*request
;
2244 dns_message_t
*rcvmsg
= NULL
;
2245 dns_section_t section
;
2246 dns_rdataset_t
*soaset
= NULL
;
2249 dns_message_t
*soaquery
= NULL
;
2250 isc_sockaddr_t
*addr
;
2251 isc_boolean_t seencname
= ISC_FALSE
;
2252 isc_boolean_t droplabel
= ISC_FALSE
;
2254 unsigned int nlabels
;
2258 REQUIRE(event
->ev_type
== DNS_EVENT_REQUESTDONE
);
2259 reqev
= (dns_requestevent_t
*)event
;
2260 request
= reqev
->request
;
2261 result
= eresult
= reqev
->result
;
2263 uctx
= reqev
->ev_arg
;
2264 client
= uctx
->client
;
2265 soaquery
= uctx
->soaquery
;
2266 addr
= uctx
->currentserver
;
2267 INSIST(addr
!= NULL
);
2269 isc_event_free(&event
);
2271 if (eresult
!= ISC_R_SUCCESS
) {
2276 result
= dns_message_create(uctx
->client
->mctx
,
2277 DNS_MESSAGE_INTENTPARSE
, &rcvmsg
);
2278 if (result
!= ISC_R_SUCCESS
)
2280 result
= dns_request_getresponse(request
, rcvmsg
,
2281 DNS_MESSAGEPARSE_PRESERVEORDER
);
2283 if (result
== DNS_R_TSIGERRORSET
) {
2284 dns_request_t
*newrequest
= NULL
;
2286 /* Retry SOA request without TSIG */
2287 dns_message_destroy(&rcvmsg
);
2288 dns_message_renderreset(uctx
->soaquery
);
2289 result
= dns_request_createvia3(uctx
->view
->requestmgr
,
2290 uctx
->soaquery
, NULL
, addr
, 0,
2292 client
->find_timeout
* 20,
2293 client
->find_timeout
, 3,
2297 if (result
== ISC_R_SUCCESS
) {
2299 dns_request_destroy(&uctx
->soareq
);
2300 uctx
->soareq
= newrequest
;
2301 UNLOCK(&uctx
->lock
);
2308 section
= DNS_SECTION_ANSWER
;
2311 if (rcvmsg
->rcode
!= dns_rcode_noerror
&&
2312 rcvmsg
->rcode
!= dns_rcode_nxdomain
) {
2313 result
= rcode2result(rcvmsg
->rcode
);
2319 section
= DNS_SECTION_ANSWER
;
2321 section
= DNS_SECTION_AUTHORITY
;
2323 droplabel
= ISC_TRUE
;
2327 result
= dns_message_firstname(rcvmsg
, section
);
2328 if (result
!= ISC_R_SUCCESS
) {
2332 while (result
== ISC_R_SUCCESS
) {
2334 dns_message_currentname(rcvmsg
, section
, &name
);
2336 result
= dns_message_findtype(name
, dns_rdatatype_soa
, 0,
2338 if (result
== ISC_R_SUCCESS
)
2340 if (section
== DNS_SECTION_ANSWER
) {
2341 dns_rdataset_t
*tset
= NULL
;
2342 if (dns_message_findtype(name
, dns_rdatatype_cname
, 0,
2343 &tset
) == ISC_R_SUCCESS
2345 dns_message_findtype(name
, dns_rdatatype_dname
, 0,
2346 &tset
) == ISC_R_SUCCESS
2349 seencname
= ISC_TRUE
;
2354 result
= dns_message_nextname(rcvmsg
, section
);
2357 if (soaset
== NULL
&& !seencname
) {
2363 droplabel
= ISC_TRUE
;
2367 result
= process_soa(uctx
, soaset
, name
);
2371 result
= dns_message_firstname(soaquery
, DNS_SECTION_QUESTION
);
2372 INSIST(result
== ISC_R_SUCCESS
);
2374 dns_message_currentname(soaquery
, DNS_SECTION_QUESTION
, &name
);
2375 nlabels
= dns_name_countlabels(name
);
2377 result
= DNS_R_SERVFAIL
; /* is there a better error? */
2379 dns_name_init(&tname
, NULL
);
2380 dns_name_getlabelsequence(name
, 1, nlabels
- 1,
2382 dns_name_clone(&tname
, name
);
2383 dns_request_destroy(&request
);
2385 uctx
->soareq
= NULL
;
2386 UNLOCK(&uctx
->lock
);
2387 dns_message_renderreset(soaquery
);
2388 dns_message_settsigkey(soaquery
, NULL
);
2389 result
= dns_request_createvia3(uctx
->view
->requestmgr
,
2391 uctx
->currentserver
, 0,
2393 client
->find_timeout
*
2395 client
->find_timeout
,
2402 if (!droplabel
|| result
!= ISC_R_SUCCESS
) {
2403 dns_message_destroy(&uctx
->soaquery
);
2405 dns_request_destroy(&uctx
->soareq
);
2406 UNLOCK(&uctx
->lock
);
2410 dns_message_destroy(&rcvmsg
);
2412 if (result
!= ISC_R_SUCCESS
)
2413 update_sendevent(uctx
, result
);
2417 request_soa(updatectx_t
*uctx
) {
2418 isc_result_t result
;
2419 dns_message_t
*soaquery
= uctx
->soaquery
;
2420 dns_name_t
*name
= NULL
;
2421 dns_rdataset_t
*rdataset
= NULL
;
2423 if (soaquery
== NULL
) {
2424 result
= dns_message_create(uctx
->client
->mctx
,
2425 DNS_MESSAGE_INTENTRENDER
,
2427 if (result
!= ISC_R_SUCCESS
)
2430 soaquery
->flags
|= DNS_MESSAGEFLAG_RD
;
2431 result
= dns_message_gettempname(soaquery
, &name
);
2432 if (result
!= ISC_R_SUCCESS
)
2434 result
= dns_message_gettemprdataset(soaquery
, &rdataset
);
2435 if (result
!= ISC_R_SUCCESS
)
2437 dns_rdataset_makequestion(rdataset
, uctx
->rdclass
, dns_rdatatype_soa
);
2438 dns_name_clone(uctx
->firstname
, name
);
2439 ISC_LIST_APPEND(name
->list
, rdataset
, link
);
2440 dns_message_addname(soaquery
, name
, DNS_SECTION_QUESTION
);
2444 result
= dns_request_createvia3(uctx
->view
->requestmgr
,
2445 soaquery
, NULL
, uctx
->currentserver
, 0,
2447 uctx
->client
->find_timeout
* 20,
2448 uctx
->client
->find_timeout
, 3,
2449 uctx
->client
->task
, receive_soa
, uctx
,
2451 if (result
== ISC_R_SUCCESS
) {
2452 uctx
->soaquery
= soaquery
;
2453 return (ISC_R_SUCCESS
);
2457 if (rdataset
!= NULL
) {
2458 ISC_LIST_UNLINK(name
->list
, rdataset
, link
); /* for safety */
2459 dns_message_puttemprdataset(soaquery
, &rdataset
);
2462 dns_message_puttempname(soaquery
, &name
);
2463 dns_message_destroy(&soaquery
);
2469 resolvesoa_done(isc_task_t
*task
, isc_event_t
*event
) {
2470 dns_clientresevent_t
*rev
= (dns_clientresevent_t
*)event
;
2472 dns_name_t
*name
, tname
;
2473 dns_rdataset_t
*rdataset
= NULL
;
2474 isc_result_t result
= rev
->result
;
2475 unsigned int nlabels
;
2479 uctx
= event
->ev_arg
;
2480 REQUIRE(UCTX_VALID(uctx
));
2483 dns_client_destroyrestrans(&uctx
->restrans
);
2484 UNLOCK(&uctx
->lock
);
2486 uctx
= event
->ev_arg
;
2487 if (result
!= ISC_R_SUCCESS
&&
2488 result
!= DNS_R_NCACHENXDOMAIN
&&
2489 result
!= DNS_R_NCACHENXRRSET
) {
2490 /* XXX: what about DNSSEC failure? */
2494 for (name
= ISC_LIST_HEAD(rev
->answerlist
); name
!= NULL
;
2495 name
= ISC_LIST_NEXT(name
, link
)) {
2496 for (rdataset
= ISC_LIST_HEAD(name
->list
);
2498 rdataset
= ISC_LIST_NEXT(rdataset
, link
)) {
2499 if (dns_rdataset_isassociated(rdataset
) &&
2500 rdataset
->type
== dns_rdatatype_soa
)
2505 if (rdataset
== NULL
) {
2506 /* Drop one label and retry resolution. */
2507 nlabels
= dns_name_countlabels(&uctx
->soaqname
);
2509 result
= DNS_R_SERVFAIL
; /* is there a better error? */
2512 dns_name_init(&tname
, NULL
);
2513 dns_name_getlabelsequence(&uctx
->soaqname
, 1, nlabels
- 1,
2515 dns_name_clone(&tname
, &uctx
->soaqname
);
2517 result
= dns_client_startresolve(uctx
->client
, &uctx
->soaqname
,
2519 dns_rdatatype_soa
, 0,
2521 resolvesoa_done
, uctx
,
2524 result
= process_soa(uctx
, rdataset
, &uctx
->soaqname
);
2527 dns_client_freeresanswer(uctx
->client
, &rev
->answerlist
);
2528 isc_event_free(&event
);
2530 if (result
!= ISC_R_SUCCESS
)
2531 update_sendevent(uctx
, result
);
2535 copy_name(isc_mem_t
*mctx
, dns_message_t
*msg
, dns_name_t
*name
,
2536 dns_name_t
**newnamep
)
2538 isc_result_t result
;
2539 dns_name_t
*newname
= NULL
;
2541 isc_buffer_t
*namebuf
= NULL
, *rdatabuf
= NULL
;
2542 dns_rdatalist_t
*rdatalist
;
2543 dns_rdataset_t
*rdataset
, *newrdataset
;
2544 dns_rdata_t rdata
= DNS_RDATA_INIT
, *newrdata
;
2546 result
= dns_message_gettempname(msg
, &newname
);
2547 if (result
!= ISC_R_SUCCESS
)
2549 result
= isc_buffer_allocate(mctx
, &namebuf
, DNS_NAME_MAXWIRE
);
2550 if (result
!= ISC_R_SUCCESS
)
2552 dns_name_init(newname
, NULL
);
2553 dns_name_setbuffer(newname
, namebuf
);
2554 dns_message_takebuffer(msg
, &namebuf
);
2555 result
= dns_name_copy(name
, newname
, NULL
);
2556 if (result
!= ISC_R_SUCCESS
)
2559 for (rdataset
= ISC_LIST_HEAD(name
->list
); rdataset
!= NULL
;
2560 rdataset
= ISC_LIST_NEXT(rdataset
, link
)) {
2562 result
= dns_message_gettemprdatalist(msg
, &rdatalist
);
2563 if (result
!= ISC_R_SUCCESS
)
2565 dns_rdatalist_init(rdatalist
);
2566 rdatalist
->type
= rdataset
->type
;
2567 rdatalist
->rdclass
= rdataset
->rdclass
;
2568 rdatalist
->covers
= rdataset
->covers
;
2569 rdatalist
->ttl
= rdataset
->ttl
;
2571 result
= dns_rdataset_first(rdataset
);
2572 while (result
== ISC_R_SUCCESS
) {
2573 dns_rdata_reset(&rdata
);
2574 dns_rdataset_current(rdataset
, &rdata
);
2577 result
= dns_message_gettemprdata(msg
, &newrdata
);
2578 if (result
!= ISC_R_SUCCESS
)
2580 dns_rdata_toregion(&rdata
, &r
);
2582 result
= isc_buffer_allocate(mctx
, &rdatabuf
,
2584 if (result
!= ISC_R_SUCCESS
)
2586 isc_buffer_putmem(rdatabuf
, r
.base
, r
.length
);
2587 isc_buffer_usedregion(rdatabuf
, &r
);
2588 dns_rdata_init(newrdata
);
2589 dns_rdata_fromregion(newrdata
, rdata
.rdclass
,
2591 newrdata
->flags
= rdata
.flags
;
2593 ISC_LIST_APPEND(rdatalist
->rdata
, newrdata
, link
);
2594 dns_message_takebuffer(msg
, &rdatabuf
);
2596 result
= dns_rdataset_next(rdataset
);
2600 result
= dns_message_gettemprdataset(msg
, &newrdataset
);
2601 if (result
!= ISC_R_SUCCESS
)
2603 dns_rdatalist_tordataset(rdatalist
, newrdataset
);
2605 ISC_LIST_APPEND(newname
->list
, newrdataset
, link
);
2608 *newnamep
= newname
;
2610 return (ISC_R_SUCCESS
);
2613 dns_message_puttempname(msg
, &newname
);
2620 internal_update_callback(isc_task_t
*task
, isc_event_t
*event
) {
2621 updatearg_t
*uarg
= event
->ev_arg
;
2622 dns_clientupdateevent_t
*uev
= (dns_clientupdateevent_t
*)event
;
2628 uarg
->result
= uev
->result
;
2630 dns_client_destroyupdatetrans(&uarg
->trans
);
2631 isc_event_free(&event
);
2633 if (!uarg
->canceled
) {
2634 UNLOCK(&uarg
->lock
);
2636 /* Exit from the internal event loop */
2637 isc_app_ctxsuspend(uarg
->actx
);
2640 * We have already exited from the loop (due to some
2641 * unexpected event). Just clean the arg up.
2643 UNLOCK(&uarg
->lock
);
2644 DESTROYLOCK(&uarg
->lock
);
2645 isc_mem_put(uarg
->client
->mctx
, uarg
, sizeof(*uarg
));
2650 dns_client_update(dns_client_t
*client
, dns_rdataclass_t rdclass
,
2651 dns_name_t
*zonename
, dns_namelist_t
*prerequisites
,
2652 dns_namelist_t
*updates
, isc_sockaddrlist_t
*servers
,
2653 dns_tsec_t
*tsec
, unsigned int options
)
2655 isc_result_t result
;
2659 REQUIRE(DNS_CLIENT_VALID(client
));
2661 if ((client
->attributes
& DNS_CLIENTATTR_OWNCTX
) == 0 &&
2662 (options
& DNS_CLIENTRESOPT_ALLOWRUN
) == 0) {
2664 * If the client is run under application's control, we need
2665 * to create a new running (sub)environment for this
2666 * particular resolution.
2668 return (ISC_R_NOTIMPLEMENTED
); /* XXXTBD */
2670 actx
= client
->actx
;
2672 uarg
= isc_mem_get(client
->mctx
, sizeof(*uarg
));
2674 return (ISC_R_NOMEMORY
);
2676 result
= isc_mutex_init(&uarg
->lock
);
2677 if (result
!= ISC_R_SUCCESS
) {
2678 isc_mem_put(client
->mctx
, uarg
, sizeof(*uarg
));
2683 uarg
->client
= client
;
2684 uarg
->result
= ISC_R_FAILURE
;
2686 uarg
->canceled
= ISC_FALSE
;
2688 result
= dns_client_startupdate(client
, rdclass
, zonename
,
2689 prerequisites
, updates
, servers
,
2690 tsec
, options
, client
->task
,
2691 internal_update_callback
, uarg
,
2693 if (result
!= ISC_R_SUCCESS
) {
2694 DESTROYLOCK(&uarg
->lock
);
2695 isc_mem_put(client
->mctx
, uarg
, sizeof(*uarg
));
2700 * Start internal event loop. It blocks until the entire process
2703 result
= isc_app_ctxrun(actx
);
2706 if (result
== ISC_R_SUCCESS
|| result
== ISC_R_SUSPEND
)
2707 result
= uarg
->result
;
2709 if (uarg
->trans
!= NULL
) {
2711 * Unusual termination (perhaps due to signal). We need some
2712 * tricky cleanup process.
2714 uarg
->canceled
= ISC_TRUE
;
2715 dns_client_cancelupdate(uarg
->trans
);
2717 UNLOCK(&uarg
->lock
);
2719 /* uarg will be freed in the event handler. */
2721 UNLOCK(&uarg
->lock
);
2723 DESTROYLOCK(&uarg
->lock
);
2724 isc_mem_put(client
->mctx
, uarg
, sizeof(*uarg
));
2731 dns_client_startupdate(dns_client_t
*client
, dns_rdataclass_t rdclass
,
2732 dns_name_t
*zonename
, dns_namelist_t
*prerequisites
,
2733 dns_namelist_t
*updates
, isc_sockaddrlist_t
*servers
,
2734 dns_tsec_t
*tsec
, unsigned int options
,
2735 isc_task_t
*task
, isc_taskaction_t action
, void *arg
,
2736 dns_clientupdatetrans_t
**transp
)
2738 dns_view_t
*view
= NULL
;
2739 isc_result_t result
;
2740 dns_name_t
*name
, *newname
;
2742 isc_task_t
*clone
= NULL
;
2743 dns_section_t section
= DNS_SECTION_UPDATE
;
2744 isc_sockaddr_t
*server
, *sa
= NULL
;
2745 dns_tsectype_t tsectype
= dns_tsectype_none
;
2749 REQUIRE(DNS_CLIENT_VALID(client
));
2750 REQUIRE(transp
!= NULL
&& *transp
== NULL
);
2751 REQUIRE(updates
!= NULL
);
2752 REQUIRE(task
!= NULL
);
2755 tsectype
= dns_tsec_gettype(tsec
);
2756 if (tsectype
!= dns_tsectype_tsig
)
2757 return (ISC_R_NOTIMPLEMENTED
); /* XXX */
2760 LOCK(&client
->lock
);
2761 result
= dns_viewlist_find(&client
->viewlist
, DNS_CLIENTVIEW_NAME
,
2763 UNLOCK(&client
->lock
);
2764 if (result
!= ISC_R_SUCCESS
)
2767 /* Create a context and prepare some resources */
2768 uctx
= isc_mem_get(client
->mctx
, sizeof(*uctx
));
2770 dns_view_detach(&view
);
2771 return (ISC_R_NOMEMORY
);
2773 result
= isc_mutex_init(&uctx
->lock
);
2774 if (result
!= ISC_R_SUCCESS
) {
2775 dns_view_detach(&view
);
2776 isc_mem_put(client
->mctx
, uctx
, sizeof(*uctx
));
2777 return (ISC_R_NOMEMORY
);
2780 isc_task_attach(task
, &clone
);
2781 uctx
->client
= client
;
2782 ISC_LINK_INIT(uctx
, link
);
2783 uctx
->state
= dns_clientupdatestate_prepare
;
2785 uctx
->rdclass
= rdclass
;
2786 uctx
->canceled
= ISC_FALSE
;
2787 uctx
->updatemsg
= NULL
;
2788 uctx
->soaquery
= NULL
;
2789 uctx
->updatereq
= NULL
;
2790 uctx
->restrans
= NULL
;
2791 uctx
->restrans2
= NULL
;
2794 uctx
->soareq
= NULL
;
2796 uctx
->tsigkey
= NULL
;
2797 uctx
->sig0key
= NULL
;
2798 uctx
->zonename
= NULL
;
2799 dns_name_init(&uctx
->soaqname
, NULL
);
2800 ISC_LIST_INIT(uctx
->servers
);
2802 uctx
->currentserver
= NULL
;
2803 dns_fixedname_init(&uctx
->zonefname
);
2805 dns_tsec_getkey(tsec
, &uctx
->tsigkey
);
2806 uctx
->event
= (dns_clientupdateevent_t
*)
2807 isc_event_allocate(client
->mctx
, clone
, DNS_EVENT_UPDATEDONE
,
2808 action
, arg
, sizeof(*uctx
->event
));
2809 if (uctx
->event
== NULL
)
2811 if (zonename
!= NULL
) {
2812 uctx
->zonename
= dns_fixedname_name(&uctx
->zonefname
);
2813 result
= dns_name_copy(zonename
, uctx
->zonename
, NULL
);
2815 if (servers
!= NULL
) {
2816 for (server
= ISC_LIST_HEAD(*servers
);
2818 server
= ISC_LIST_NEXT(server
, link
)) {
2819 sa
= isc_mem_get(client
->mctx
, sizeof(*sa
));
2822 sa
->type
= server
->type
;
2823 sa
->length
= server
->length
;
2824 ISC_LINK_INIT(sa
, link
);
2825 ISC_LIST_APPEND(uctx
->servers
, sa
, link
);
2826 if (uctx
->currentserver
== NULL
)
2827 uctx
->currentserver
= sa
;
2832 /* Make update message */
2833 result
= dns_message_create(client
->mctx
, DNS_MESSAGE_INTENTRENDER
,
2835 if (result
!= ISC_R_SUCCESS
)
2837 uctx
->updatemsg
->opcode
= dns_opcode_update
;
2839 if (prerequisites
!= NULL
) {
2840 for (name
= ISC_LIST_HEAD(*prerequisites
); name
!= NULL
;
2841 name
= ISC_LIST_NEXT(name
, link
)) {
2843 result
= copy_name(client
->mctx
, uctx
->updatemsg
,
2845 if (result
!= ISC_R_SUCCESS
)
2847 dns_message_addname(uctx
->updatemsg
, newname
,
2848 DNS_SECTION_PREREQUISITE
);
2852 for (name
= ISC_LIST_HEAD(*updates
); name
!= NULL
;
2853 name
= ISC_LIST_NEXT(name
, link
)) {
2855 result
= copy_name(client
->mctx
, uctx
->updatemsg
, name
,
2857 if (result
!= ISC_R_SUCCESS
)
2859 dns_message_addname(uctx
->updatemsg
, newname
,
2860 DNS_SECTION_UPDATE
);
2863 uctx
->firstname
= NULL
;
2864 result
= dns_message_firstname(uctx
->updatemsg
, section
);
2865 if (result
== ISC_R_NOMORE
) {
2866 section
= DNS_SECTION_PREREQUISITE
;
2867 result
= dns_message_firstname(uctx
->updatemsg
, section
);
2869 if (result
!= ISC_R_SUCCESS
)
2871 dns_message_currentname(uctx
->updatemsg
, section
, &uctx
->firstname
);
2873 uctx
->magic
= UCTX_MAGIC
;
2875 LOCK(&client
->lock
);
2876 ISC_LIST_APPEND(client
->updatectxs
, uctx
, link
);
2877 UNLOCK(&client
->lock
);
2879 if (uctx
->zonename
!= NULL
&& uctx
->currentserver
!= NULL
) {
2880 result
= send_update(uctx
);
2881 if (result
!= ISC_R_SUCCESS
)
2883 } else if (uctx
->currentserver
!= NULL
) {
2884 result
= request_soa(uctx
);
2885 if (result
!= ISC_R_SUCCESS
)
2888 dns_name_clone(uctx
->firstname
, &uctx
->soaqname
);
2889 result
= dns_client_startresolve(uctx
->client
, &uctx
->soaqname
,
2891 dns_rdatatype_soa
, 0,
2892 client
->task
, resolvesoa_done
,
2893 uctx
, &uctx
->restrans
);
2894 if (result
!= ISC_R_SUCCESS
)
2898 *transp
= (dns_clientupdatetrans_t
*)uctx
;
2900 return (ISC_R_SUCCESS
);
2903 if (ISC_LINK_LINKED(uctx
, link
)) {
2904 LOCK(&client
->lock
);
2905 ISC_LIST_UNLINK(client
->updatectxs
, uctx
, link
);
2906 UNLOCK(&client
->lock
);
2908 if (uctx
->updatemsg
!= NULL
)
2909 dns_message_destroy(&uctx
->updatemsg
);
2910 while ((sa
= ISC_LIST_HEAD(uctx
->servers
)) != NULL
) {
2911 ISC_LIST_UNLINK(uctx
->servers
, sa
, link
);
2912 isc_mem_put(client
->mctx
, sa
, sizeof(*sa
));
2914 if (uctx
->event
!= NULL
)
2915 isc_event_free(ISC_EVENT_PTR(&uctx
->event
));
2916 if (uctx
->tsigkey
!= NULL
)
2917 dns_tsigkey_detach(&uctx
->tsigkey
);
2918 isc_task_detach(&clone
);
2919 DESTROYLOCK(&uctx
->lock
);
2921 isc_mem_put(client
->mctx
, uctx
, sizeof(*uctx
));
2922 dns_view_detach(&view
);
2928 dns_client_cancelupdate(dns_clientupdatetrans_t
*trans
) {
2931 REQUIRE(trans
!= NULL
);
2932 uctx
= (updatectx_t
*)trans
;
2933 REQUIRE(UCTX_VALID(uctx
));
2937 if (!uctx
->canceled
) {
2938 uctx
->canceled
= ISC_TRUE
;
2939 if (uctx
->updatereq
!= NULL
)
2940 dns_request_cancel(uctx
->updatereq
);
2941 if (uctx
->soareq
!= NULL
)
2942 dns_request_cancel(uctx
->soareq
);
2943 if (uctx
->restrans
!= NULL
)
2944 dns_client_cancelresolve(uctx
->restrans
);
2945 if (uctx
->restrans2
!= NULL
)
2946 dns_client_cancelresolve(uctx
->restrans2
);
2949 UNLOCK(&uctx
->lock
);
2953 dns_client_destroyupdatetrans(dns_clientupdatetrans_t
**transp
) {
2956 dns_client_t
*client
;
2957 isc_boolean_t need_destroyclient
= ISC_FALSE
;
2960 REQUIRE(transp
!= NULL
);
2961 uctx
= (updatectx_t
*)*transp
;
2962 REQUIRE(UCTX_VALID(uctx
));
2963 client
= uctx
->client
;
2964 REQUIRE(DNS_CLIENT_VALID(client
));
2965 REQUIRE(uctx
->updatereq
== NULL
&& uctx
->updatemsg
== NULL
&&
2966 uctx
->soareq
== NULL
&& uctx
->soaquery
== NULL
&&
2967 uctx
->event
== NULL
&& uctx
->tsigkey
== NULL
&&
2968 uctx
->sig0key
== NULL
);
2970 mctx
= client
->mctx
;
2971 dns_view_detach(&uctx
->view
);
2972 while ((sa
= ISC_LIST_HEAD(uctx
->servers
)) != NULL
) {
2973 ISC_LIST_UNLINK(uctx
->servers
, sa
, link
);
2974 isc_mem_put(mctx
, sa
, sizeof(*sa
));
2977 LOCK(&client
->lock
);
2979 INSIST(ISC_LINK_LINKED(uctx
, link
));
2980 ISC_LIST_UNLINK(client
->updatectxs
, uctx
, link
);
2982 if (client
->references
== 0 && ISC_LIST_EMPTY(client
->resctxs
) &&
2983 ISC_LIST_EMPTY(client
->reqctxs
) &&
2984 ISC_LIST_EMPTY(client
->updatectxs
))
2985 need_destroyclient
= ISC_TRUE
;
2987 UNLOCK(&client
->lock
);
2989 DESTROYLOCK(&uctx
->lock
);
2992 isc_mem_put(mctx
, uctx
, sizeof(*uctx
));
2994 if (need_destroyclient
)
2995 destroyclient(&client
);
3001 dns_client_mctx(dns_client_t
*client
) {
3003 REQUIRE(DNS_CLIENT_VALID(client
));
3004 return (client
->mctx
);
3008 isc_buffer_t buffer
;
3009 dns_rdataset_t rdataset
;
3010 dns_rdatalist_t rdatalist
;
3014 unsigned char data
[FLEXIBLE_ARRAY_MEMBER
];
3015 } dns_client_updaterec_t
;
3018 dns_client_updaterec(dns_client_updateop_t op
, dns_name_t
*owner
,
3019 dns_rdatatype_t type
, dns_rdata_t
*source
,
3020 dns_ttl_t ttl
, dns_name_t
*target
,
3021 dns_rdataset_t
*rdataset
, dns_rdatalist_t
*rdatalist
,
3022 dns_rdata_t
*rdata
, isc_mem_t
*mctx
)
3024 dns_client_updaterec_t
*updaterec
= NULL
;
3025 size_t size
= offsetof(dns_client_updaterec_t
, data
);
3027 REQUIRE(op
< updateop_max
);
3028 REQUIRE(owner
!= NULL
);
3029 REQUIRE((rdataset
!= NULL
&& rdatalist
!= NULL
&& rdata
!= NULL
) ||
3030 (rdataset
== NULL
&& rdatalist
== NULL
&& rdata
== NULL
&&
3032 if (op
== updateop_add
)
3033 REQUIRE(source
!= NULL
);
3034 if (source
!= NULL
) {
3035 REQUIRE(source
->type
== type
);
3036 REQUIRE(op
== updateop_add
|| op
== updateop_delete
||
3037 op
== updateop_exist
);
3040 size
+= owner
->length
;
3042 size
+= source
->length
;
3044 if (rdataset
== NULL
) {
3045 updaterec
= isc_mem_get(mctx
, size
);
3046 if (updaterec
== NULL
)
3047 return (ISC_R_NOMEMORY
);
3048 rdataset
= &updaterec
->rdataset
;
3049 rdatalist
= &updaterec
->rdatalist
;
3050 rdata
= &updaterec
->rdata
;
3051 dns_rdataset_init(rdataset
);
3052 dns_rdatalist_init(&updaterec
->rdatalist
);
3053 dns_rdata_init(&updaterec
->rdata
);
3054 isc_buffer_init(&updaterec
->buffer
, updaterec
->data
,
3057 offsetof(dns_client_updaterec_t
, data
)));
3058 dns_name_copy(owner
, target
, &updaterec
->buffer
);
3059 if (source
!= NULL
) {
3061 dns_rdata_clone(source
, rdata
);
3062 dns_rdata_toregion(rdata
, &r
);
3063 rdata
->data
= isc_buffer_used(&updaterec
->buffer
);
3064 isc_buffer_copyregion(&updaterec
->buffer
, &r
);
3066 updaterec
->mctx
= NULL
;
3067 isc_mem_attach(mctx
, &updaterec
->mctx
);
3068 } else if (source
!= NULL
)
3069 dns_rdata_clone(source
, rdata
);
3074 case updateop_delete
:
3075 if (source
!= NULL
) {
3077 dns_rdata_makedelete(rdata
);
3079 dns_rdata_deleterrset(rdata
, type
);
3081 case updateop_notexist
:
3082 dns_rdata_notexist(rdata
, type
);
3084 case updateop_exist
:
3085 if (source
== NULL
) {
3087 dns_rdata_exists(rdata
, type
);
3095 rdatalist
->type
= rdata
->type
;
3096 rdatalist
->rdclass
= rdata
->rdclass
;
3097 if (source
!= NULL
) {
3098 rdatalist
->covers
= dns_rdata_covers(rdata
);
3099 rdatalist
->ttl
= ttl
;
3101 ISC_LIST_APPEND(rdatalist
->rdata
, rdata
, link
);
3102 dns_rdatalist_tordataset(rdatalist
, rdataset
);
3103 ISC_LIST_APPEND(target
->list
, rdataset
, link
);
3104 if (updaterec
!= NULL
) {
3105 target
->attributes
|= DNS_NAMEATTR_HASUPDATEREC
;
3106 dns_name_setbuffer(target
, &updaterec
->buffer
);
3108 if (op
== updateop_add
|| op
== updateop_delete
)
3109 target
->attributes
|= DNS_NAMEATTR_UPDATE
;
3111 target
->attributes
|= DNS_NAMEATTR_PREREQUISITE
;
3112 return (ISC_R_SUCCESS
);
3116 dns_client_freeupdate(dns_name_t
**namep
) {
3117 dns_client_updaterec_t
*updaterec
;
3118 dns_rdatalist_t
*rdatalist
;
3119 dns_rdataset_t
*rdataset
;
3123 REQUIRE(namep
!= NULL
&& *namep
!= NULL
);
3126 for (rdataset
= ISC_LIST_HEAD(name
->list
);
3128 rdataset
= ISC_LIST_HEAD(name
->list
)) {
3129 ISC_LIST_UNLINK(name
->list
, rdataset
, link
);
3131 dns_rdatalist_fromrdataset(rdataset
, &rdatalist
);
3132 if (rdatalist
== NULL
) {
3133 dns_rdataset_disassociate(rdataset
);
3136 for (rdata
= ISC_LIST_HEAD(rdatalist
->rdata
);
3138 rdata
= ISC_LIST_HEAD(rdatalist
->rdata
))
3139 ISC_LIST_UNLINK(rdatalist
->rdata
, rdata
, link
);
3140 dns_rdataset_disassociate(rdataset
);
3143 if ((name
->attributes
& DNS_NAMEATTR_HASUPDATEREC
) != 0) {
3144 updaterec
= (dns_client_updaterec_t
*)name
->buffer
;
3145 INSIST(updaterec
!= NULL
);
3146 isc_mem_putanddetach(&updaterec
->mctx
, updaterec
,