summaryrefslogtreecommitdiffstats
path: root/contrib/bind9/lib/dns/client.c
diff options
context:
space:
mode:
authordes <des@FreeBSD.org>2013-09-30 17:23:45 +0000
committerdes <des@FreeBSD.org>2013-09-30 17:23:45 +0000
commitaa2e4b623cdc1d9d2b44a103d24ecb7e0c984de9 (patch)
tree1a2886b0de387ddff665d0e370f40ffc32778840 /contrib/bind9/lib/dns/client.c
parent9e2a5c1c0e7dbd2e8116aa8f1ce21759dec75295 (diff)
downloadFreeBSD-src-aa2e4b623cdc1d9d2b44a103d24ecb7e0c984de9.zip
FreeBSD-src-aa2e4b623cdc1d9d2b44a103d24ecb7e0c984de9.tar.gz
Remove BIND.
Approved by: re (gjb)
Diffstat (limited to 'contrib/bind9/lib/dns/client.c')
-rw-r--r--contrib/bind9/lib/dns/client.c3043
1 files changed, 0 insertions, 3043 deletions
diff --git a/contrib/bind9/lib/dns/client.c b/contrib/bind9/lib/dns/client.c
deleted file mode 100644
index fc551cf..0000000
--- a/contrib/bind9/lib/dns/client.c
+++ /dev/null
@@ -1,3043 +0,0 @@
-/*
- * Copyright (C) 2009-2013 Internet Systems Consortium, Inc. ("ISC")
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
- * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
- * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
- * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
- * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
- * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
- * PERFORMANCE OF THIS SOFTWARE.
- */
-
-/* $Id: client.c,v 1.14 2011/03/12 04:59:47 tbox Exp $ */
-
-#include <config.h>
-
-#include <stddef.h>
-
-#include <isc/app.h>
-#include <isc/mem.h>
-#include <isc/mutex.h>
-#include <isc/sockaddr.h>
-#include <isc/socket.h>
-#include <isc/task.h>
-#include <isc/timer.h>
-#include <isc/util.h>
-
-#include <dns/adb.h>
-#include <dns/client.h>
-#include <dns/db.h>
-#include <dns/dispatch.h>
-#include <dns/events.h>
-#include <dns/forward.h>
-#include <dns/keytable.h>
-#include <dns/message.h>
-#include <dns/name.h>
-#include <dns/rdata.h>
-#include <dns/rdatalist.h>
-#include <dns/rdataset.h>
-#include <dns/rdatatype.h>
-#include <dns/rdatasetiter.h>
-#include <dns/rdatastruct.h>
-#include <dns/request.h>
-#include <dns/resolver.h>
-#include <dns/result.h>
-#include <dns/tsec.h>
-#include <dns/tsig.h>
-#include <dns/view.h>
-
-#include <dst/dst.h>
-
-#define DNS_CLIENT_MAGIC ISC_MAGIC('D', 'N', 'S', 'c')
-#define DNS_CLIENT_VALID(c) ISC_MAGIC_VALID(c, DNS_CLIENT_MAGIC)
-
-#define RCTX_MAGIC ISC_MAGIC('R', 'c', 't', 'x')
-#define RCTX_VALID(c) ISC_MAGIC_VALID(c, RCTX_MAGIC)
-
-#define REQCTX_MAGIC ISC_MAGIC('R', 'q', 'c', 'x')
-#define REQCTX_VALID(c) ISC_MAGIC_VALID(c, REQCTX_MAGIC)
-
-#define UCTX_MAGIC ISC_MAGIC('U', 'c', 't', 'x')
-#define UCTX_VALID(c) ISC_MAGIC_VALID(c, UCTX_MAGIC)
-
-#define MAX_RESTARTS 16
-
-/*%
- * DNS client object
- */
-struct dns_client {
- /* Unlocked */
- unsigned int magic;
- unsigned int attributes;
- isc_mutex_t lock;
- isc_mem_t *mctx;
- isc_appctx_t *actx;
- isc_taskmgr_t *taskmgr;
- isc_task_t *task;
- isc_socketmgr_t *socketmgr;
- isc_timermgr_t *timermgr;
- dns_dispatchmgr_t *dispatchmgr;
- dns_dispatch_t *dispatchv4;
- dns_dispatch_t *dispatchv6;
-
- unsigned int update_timeout;
- unsigned int update_udptimeout;
- unsigned int update_udpretries;
- unsigned int find_timeout;
- unsigned int find_udpretries;
-
- /* Locked */
- unsigned int references;
- dns_viewlist_t viewlist;
- ISC_LIST(struct resctx) resctxs;
- ISC_LIST(struct reqctx) reqctxs;
- ISC_LIST(struct updatectx) updatectxs;
-};
-
-/*%
- * Timeout/retry constants for dynamic update borrowed from nsupdate
- */
-#define DEF_UPDATE_TIMEOUT 300
-#define MIN_UPDATE_TIMEOUT 30
-#define DEF_UPDATE_UDPTIMEOUT 3
-#define DEF_UPDATE_UDPRETRIES 3
-
-#define DEF_FIND_TIMEOUT 5
-#define DEF_FIND_UDPRETRIES 3
-
-#define DNS_CLIENTATTR_OWNCTX 0x01
-
-#define DNS_CLIENTVIEW_NAME "dnsclient"
-
-/*%
- * Internal state for a single name resolution procedure
- */
-typedef struct resctx {
- /* Unlocked */
- unsigned int magic;
- isc_mutex_t lock;
- dns_client_t *client;
- isc_boolean_t want_dnssec;
-
- /* Locked */
- ISC_LINK(struct resctx) link;
- isc_task_t *task;
- dns_view_t *view;
- unsigned int restarts;
- dns_fixedname_t name;
- dns_rdatatype_t type;
- dns_fetch_t *fetch;
- dns_namelist_t namelist;
- isc_result_t result;
- dns_clientresevent_t *event;
- isc_boolean_t canceled;
- dns_rdataset_t *rdataset;
- dns_rdataset_t *sigrdataset;
-} resctx_t;
-
-/*%
- * Argument of an internal event for synchronous name resolution.
- */
-typedef struct resarg {
- /* Unlocked */
- isc_appctx_t *actx;
- dns_client_t *client;
- isc_mutex_t lock;
-
- /* Locked */
- isc_result_t result;
- isc_result_t vresult;
- dns_namelist_t *namelist;
- dns_clientrestrans_t *trans;
- isc_boolean_t canceled;
-} resarg_t;
-
-/*%
- * Internal state for a single DNS request
- */
-typedef struct reqctx {
- /* Unlocked */
- unsigned int magic;
- isc_mutex_t lock;
- dns_client_t *client;
- unsigned int parseoptions;
-
- /* Locked */
- ISC_LINK(struct reqctx) link;
- isc_boolean_t canceled;
- dns_tsigkey_t *tsigkey;
- dns_request_t *request;
- dns_clientreqevent_t *event;
-} reqctx_t;
-
-/*%
- * Argument of an internal event for synchronous DNS request.
- */
-typedef struct reqarg {
- /* Unlocked */
- isc_appctx_t *actx;
- dns_client_t *client;
- isc_mutex_t lock;
-
- /* Locked */
- isc_result_t result;
- dns_clientreqtrans_t *trans;
- isc_boolean_t canceled;
-} reqarg_t;
-
-/*%
- * Argument of an internal event for synchronous name resolution.
- */
-typedef struct updatearg {
- /* Unlocked */
- isc_appctx_t *actx;
- dns_client_t *client;
- isc_mutex_t lock;
-
- /* Locked */
- isc_result_t result;
- dns_clientupdatetrans_t *trans;
- isc_boolean_t canceled;
-} updatearg_t;
-
-/*%
- * Internal state for a single dynamic update procedure
- */
-typedef struct updatectx {
- /* Unlocked */
- unsigned int magic;
- isc_mutex_t lock;
- dns_client_t *client;
-
- /* Locked */
- dns_request_t *updatereq;
- dns_request_t *soareq;
- dns_clientrestrans_t *restrans;
- dns_clientrestrans_t *restrans2;
- isc_boolean_t canceled;
-
- /* Task Locked */
- ISC_LINK(struct updatectx) link;
- dns_clientupdatestate_t state;
- dns_rdataclass_t rdclass;
- dns_view_t *view;
- dns_message_t *updatemsg;
- dns_message_t *soaquery;
- dns_clientupdateevent_t *event;
- dns_tsigkey_t *tsigkey;
- dst_key_t *sig0key;
- dns_name_t *firstname;
- dns_name_t soaqname;
- dns_fixedname_t zonefname;
- dns_name_t *zonename;
- isc_sockaddrlist_t servers;
- unsigned int nservers;
- isc_sockaddr_t *currentserver;
- struct updatectx *bp4;
- struct updatectx *bp6;
-} updatectx_t;
-
-static isc_result_t request_soa(updatectx_t *uctx);
-static void client_resfind(resctx_t *rctx, dns_fetchevent_t *event);
-static isc_result_t send_update(updatectx_t *uctx);
-
-static isc_result_t
-getudpdispatch(int family, dns_dispatchmgr_t *dispatchmgr,
- isc_socketmgr_t *socketmgr, isc_taskmgr_t *taskmgr,
- isc_boolean_t is_shared, dns_dispatch_t **dispp)
-{
- unsigned int attrs, attrmask;
- isc_sockaddr_t sa;
- dns_dispatch_t *disp;
- unsigned buffersize, maxbuffers, maxrequests, buckets, increment;
- isc_result_t result;
-
- attrs = 0;
- attrs |= DNS_DISPATCHATTR_UDP;
- switch (family) {
- case AF_INET:
- attrs |= DNS_DISPATCHATTR_IPV4;
- break;
- case AF_INET6:
- attrs |= DNS_DISPATCHATTR_IPV6;
- break;
- default:
- INSIST(0);
- }
- attrmask = 0;
- attrmask |= DNS_DISPATCHATTR_UDP;
- attrmask |= DNS_DISPATCHATTR_TCP;
- attrmask |= DNS_DISPATCHATTR_IPV4;
- attrmask |= DNS_DISPATCHATTR_IPV6;
-
- isc_sockaddr_anyofpf(&sa, family);
-
- buffersize = 4096;
- maxbuffers = is_shared ? 1000 : 8;
- maxrequests = 32768;
- buckets = is_shared ? 16411 : 3;
- increment = is_shared ? 16433 : 5;
-
- disp = NULL;
- result = dns_dispatch_getudp(dispatchmgr, socketmgr,
- taskmgr, &sa,
- buffersize, maxbuffers, maxrequests,
- buckets, increment,
- attrs, attrmask, &disp);
- if (result == ISC_R_SUCCESS)
- *dispp = disp;
-
- return (result);
-}
-
-static isc_result_t
-dns_client_createview(isc_mem_t *mctx, dns_rdataclass_t rdclass,
- unsigned int options, isc_taskmgr_t *taskmgr,
- unsigned int ntasks, isc_socketmgr_t *socketmgr,
- isc_timermgr_t *timermgr, dns_dispatchmgr_t *dispatchmgr,
- dns_dispatch_t *dispatchv4, dns_dispatch_t *dispatchv6,
- dns_view_t **viewp)
-{
- isc_result_t result;
- dns_view_t *view = NULL;
- const char *dbtype;
-
- result = dns_view_create(mctx, rdclass, DNS_CLIENTVIEW_NAME, &view);
- if (result != ISC_R_SUCCESS)
- return (result);
-
- /* Initialize view security roots */
- result = dns_view_initsecroots(view, mctx);
- if (result != ISC_R_SUCCESS) {
- dns_view_detach(&view);
- return (result);
- }
-
- result = dns_view_createresolver(view, taskmgr, ntasks, 1, socketmgr,
- timermgr, 0, dispatchmgr,
- dispatchv4, dispatchv6);
- if (result != ISC_R_SUCCESS) {
- dns_view_detach(&view);
- return (result);
- }
-
- /*
- * Set cache DB.
- * XXX: it may be better if specific DB implementations can be
- * specified via some configuration knob.
- */
- if ((options & DNS_CLIENTCREATEOPT_USECACHE) != 0)
- dbtype = "rbt";
- else
- dbtype = "ecdb";
- result = dns_db_create(mctx, dbtype, dns_rootname, dns_dbtype_cache,
- rdclass, 0, NULL, &view->cachedb);
- if (result != ISC_R_SUCCESS) {
- dns_view_detach(&view);
- return (result);
- }
-
- *viewp = view;
- return (ISC_R_SUCCESS);
-}
-
-isc_result_t
-dns_client_create(dns_client_t **clientp, unsigned int options) {
- isc_result_t result;
- isc_mem_t *mctx = NULL;
- isc_appctx_t *actx = NULL;
- isc_taskmgr_t *taskmgr = NULL;
- isc_socketmgr_t *socketmgr = NULL;
- isc_timermgr_t *timermgr = NULL;
-#if 0
- /* XXXMPA add debug logging support */
- isc_log_t *lctx = NULL;
- isc_logconfig_t *logconfig = NULL;
- unsigned int logdebuglevel = 0;
-#endif
-
- result = isc_mem_create(0, 0, &mctx);
- if (result != ISC_R_SUCCESS)
- return (result);
- result = isc_appctx_create(mctx, &actx);
- if (result != ISC_R_SUCCESS)
- goto cleanup;
- result = isc_app_ctxstart(actx);
- if (result != ISC_R_SUCCESS)
- goto cleanup;
- result = isc_taskmgr_createinctx(mctx, actx, 1, 0, &taskmgr);
- if (result != ISC_R_SUCCESS)
- goto cleanup;
- result = isc_socketmgr_createinctx(mctx, actx, &socketmgr);
- if (result != ISC_R_SUCCESS)
- goto cleanup;
- result = isc_timermgr_createinctx(mctx, actx, &timermgr);
- if (result != ISC_R_SUCCESS)
- goto cleanup;
-#if 0
- result = isc_log_create(mctx, &lctx, &logconfig);
- if (result != ISC_R_SUCCESS)
- goto cleanup;
- isc_log_setcontext(lctx);
- dns_log_init(lctx);
- dns_log_setcontext(lctx);
- result = isc_log_usechannel(logconfig, "default_debug", NULL, NULL);
- if (result != ISC_R_SUCCESS)
- goto cleanup;
- isc_log_setdebuglevel(lctx, logdebuglevel);
-#endif
- result = dns_client_createx(mctx, actx, taskmgr, socketmgr, timermgr,
- options, clientp);
- if (result != ISC_R_SUCCESS)
- goto cleanup;
-
- (*clientp)->attributes |= DNS_CLIENTATTR_OWNCTX;
-
- /* client has its own reference to mctx, so we can detach it here */
- isc_mem_detach(&mctx);
-
- return (ISC_R_SUCCESS);
-
- cleanup:
- if (taskmgr != NULL)
- isc_taskmgr_destroy(&taskmgr);
- if (timermgr != NULL)
- isc_timermgr_destroy(&timermgr);
- if (socketmgr != NULL)
- isc_socketmgr_destroy(&socketmgr);
- if (actx != NULL)
- isc_appctx_destroy(&actx);
- isc_mem_detach(&mctx);
-
- return (result);
-}
-
-isc_result_t
-dns_client_createx(isc_mem_t *mctx, isc_appctx_t *actx, isc_taskmgr_t *taskmgr,
- isc_socketmgr_t *socketmgr, isc_timermgr_t *timermgr,
- unsigned int options, dns_client_t **clientp)
-{
- dns_client_t *client;
- isc_result_t result;
- dns_dispatchmgr_t *dispatchmgr = NULL;
- dns_dispatch_t *dispatchv4 = NULL;
- dns_dispatch_t *dispatchv6 = NULL;
- dns_view_t *view = NULL;
-
- REQUIRE(mctx != NULL);
- REQUIRE(taskmgr != NULL);
- REQUIRE(timermgr != NULL);
- REQUIRE(socketmgr != NULL);
- REQUIRE(clientp != NULL && *clientp == NULL);
-
- client = isc_mem_get(mctx, sizeof(*client));
- if (client == NULL)
- return (ISC_R_NOMEMORY);
-
- result = isc_mutex_init(&client->lock);
- if (result != ISC_R_SUCCESS) {
- isc_mem_put(mctx, client, sizeof(*client));
- return (result);
- }
-
- client->actx = actx;
- client->taskmgr = taskmgr;
- client->socketmgr = socketmgr;
- client->timermgr = timermgr;
-
- client->task = NULL;
- result = isc_task_create(client->taskmgr, 0, &client->task);
- if (result != ISC_R_SUCCESS)
- goto cleanup;
-
- result = dns_dispatchmgr_create(mctx, NULL, &dispatchmgr);
- if (result != ISC_R_SUCCESS)
- goto cleanup;
- client->dispatchmgr = dispatchmgr;
-
- /* TODO: whether to use dispatch v4 or v6 should be configurable */
- client->dispatchv4 = NULL;
- client->dispatchv6 = NULL;
- result = getudpdispatch(AF_INET, dispatchmgr, socketmgr,
- taskmgr, ISC_TRUE, &dispatchv4);
- if (result == ISC_R_SUCCESS)
- client->dispatchv4 = dispatchv4;
- result = getudpdispatch(AF_INET6, dispatchmgr, socketmgr,
- taskmgr, ISC_TRUE, &dispatchv6);
- if (result == ISC_R_SUCCESS)
- client->dispatchv6 = dispatchv6;
-
- /* We need at least one of the dispatchers */
- if (dispatchv4 == NULL && dispatchv6 == NULL) {
- INSIST(result != ISC_R_SUCCESS);
- goto cleanup;
- }
-
- /* Create the default view for class IN */
- result = dns_client_createview(mctx, dns_rdataclass_in, options,
- taskmgr, 31, socketmgr, timermgr,
- dispatchmgr, dispatchv4, dispatchv6,
- &view);
- if (result != ISC_R_SUCCESS)
- goto cleanup;
- ISC_LIST_INIT(client->viewlist);
- ISC_LIST_APPEND(client->viewlist, view, link);
-
- dns_view_freeze(view); /* too early? */
-
- ISC_LIST_INIT(client->resctxs);
- ISC_LIST_INIT(client->reqctxs);
- ISC_LIST_INIT(client->updatectxs);
-
- client->mctx = NULL;
- isc_mem_attach(mctx, &client->mctx);
-
- client->update_timeout = DEF_UPDATE_TIMEOUT;
- client->update_udptimeout = DEF_UPDATE_UDPTIMEOUT;
- client->update_udpretries = DEF_UPDATE_UDPRETRIES;
- client->find_timeout = DEF_FIND_TIMEOUT;
- client->find_udpretries = DEF_FIND_UDPRETRIES;
- client->attributes = 0;
-
- client->references = 1;
- client->magic = DNS_CLIENT_MAGIC;
-
- *clientp = client;
-
- return (ISC_R_SUCCESS);
-
- cleanup:
- if (dispatchv4 != NULL)
- dns_dispatch_detach(&dispatchv4);
- if (dispatchv6 != NULL)
- dns_dispatch_detach(&dispatchv6);
- if (dispatchmgr != NULL)
- dns_dispatchmgr_destroy(&dispatchmgr);
- if (client->task != NULL)
- isc_task_detach(&client->task);
- isc_mem_put(mctx, client, sizeof(*client));
-
- return (result);
-}
-
-static void
-destroyclient(dns_client_t **clientp) {
- dns_client_t *client = *clientp;
- dns_view_t *view;
-
- while ((view = ISC_LIST_HEAD(client->viewlist)) != NULL) {
- ISC_LIST_UNLINK(client->viewlist, view, link);
- dns_view_detach(&view);
- }
-
- if (client->dispatchv4 != NULL)
- dns_dispatch_detach(&client->dispatchv4);
- if (client->dispatchv6 != NULL)
- dns_dispatch_detach(&client->dispatchv6);
-
- dns_dispatchmgr_destroy(&client->dispatchmgr);
-
- isc_task_detach(&client->task);
-
- /*
- * If the client has created its own running environments,
- * destroy them.
- */
- if ((client->attributes & DNS_CLIENTATTR_OWNCTX) != 0) {
- isc_taskmgr_destroy(&client->taskmgr);
- isc_timermgr_destroy(&client->timermgr);
- isc_socketmgr_destroy(&client->socketmgr);
-
- isc_app_ctxfinish(client->actx);
- isc_appctx_destroy(&client->actx);
- }
-
- DESTROYLOCK(&client->lock);
- client->magic = 0;
-
- isc_mem_putanddetach(&client->mctx, client, sizeof(*client));
-
- *clientp = NULL;
-}
-
-void
-dns_client_destroy(dns_client_t **clientp) {
- dns_client_t *client;
- isc_boolean_t destroyok = ISC_FALSE;
-
- REQUIRE(clientp != NULL);
- client = *clientp;
- REQUIRE(DNS_CLIENT_VALID(client));
-
- LOCK(&client->lock);
- client->references--;
- if (client->references == 0 && ISC_LIST_EMPTY(client->resctxs) &&
- ISC_LIST_EMPTY(client->reqctxs) &&
- ISC_LIST_EMPTY(client->updatectxs)) {
- destroyok = ISC_TRUE;
- }
- UNLOCK(&client->lock);
-
- if (destroyok)
- destroyclient(&client);
-
- *clientp = NULL;
-}
-
-isc_result_t
-dns_client_setservers(dns_client_t *client, dns_rdataclass_t rdclass,
- dns_name_t *namespace, isc_sockaddrlist_t *addrs)
-{
- isc_result_t result;
- dns_view_t *view = NULL;
-
- REQUIRE(DNS_CLIENT_VALID(client));
- REQUIRE(addrs != NULL);
-
- if (namespace == NULL)
- namespace = dns_rootname;
-
- LOCK(&client->lock);
- result = dns_viewlist_find(&client->viewlist, DNS_CLIENTVIEW_NAME,
- rdclass, &view);
- if (result != ISC_R_SUCCESS) {
- UNLOCK(&client->lock);
- return (result);
- }
- UNLOCK(&client->lock);
-
- result = dns_fwdtable_add(view->fwdtable, namespace, addrs,
- dns_fwdpolicy_only);
-
- dns_view_detach(&view);
-
- return (result);
-}
-
-isc_result_t
-dns_client_clearservers(dns_client_t *client, dns_rdataclass_t rdclass,
- dns_name_t *namespace)
-{
- isc_result_t result;
- dns_view_t *view = NULL;
-
- REQUIRE(DNS_CLIENT_VALID(client));
-
- if (namespace == NULL)
- namespace = dns_rootname;
-
- LOCK(&client->lock);
- result = dns_viewlist_find(&client->viewlist, DNS_CLIENTVIEW_NAME,
- rdclass, &view);
- if (result != ISC_R_SUCCESS) {
- UNLOCK(&client->lock);
- return (result);
- }
- UNLOCK(&client->lock);
-
- result = dns_fwdtable_delete(view->fwdtable, namespace);
-
- dns_view_detach(&view);
-
- return (result);
-}
-
-static isc_result_t
-getrdataset(isc_mem_t *mctx, dns_rdataset_t **rdatasetp) {
- dns_rdataset_t *rdataset;
-
- REQUIRE(mctx != NULL);
- REQUIRE(rdatasetp != NULL && *rdatasetp == NULL);
-
- rdataset = isc_mem_get(mctx, sizeof(*rdataset));
- if (rdataset == NULL)
- return (ISC_R_NOMEMORY);
-
- dns_rdataset_init(rdataset);
-
- *rdatasetp = rdataset;
-
- return (ISC_R_SUCCESS);
-}
-
-static void
-putrdataset(isc_mem_t *mctx, dns_rdataset_t **rdatasetp) {
- dns_rdataset_t *rdataset;
-
- REQUIRE(rdatasetp != NULL);
- rdataset = *rdatasetp;
- REQUIRE(rdataset != NULL);
-
- if (dns_rdataset_isassociated(rdataset))
- dns_rdataset_disassociate(rdataset);
-
- isc_mem_put(mctx, rdataset, sizeof(*rdataset));
-
- *rdatasetp = NULL;
-}
-
-static void
-fetch_done(isc_task_t *task, isc_event_t *event) {
- resctx_t *rctx = event->ev_arg;
- dns_fetchevent_t *fevent;
-
- REQUIRE(event->ev_type == DNS_EVENT_FETCHDONE);
- REQUIRE(RCTX_VALID(rctx));
- REQUIRE(rctx->task == task);
- fevent = (dns_fetchevent_t *)event;
-
- client_resfind(rctx, fevent);
-}
-
-static inline isc_result_t
-start_fetch(resctx_t *rctx) {
- isc_result_t result;
-
- /*
- * The caller must be holding the rctx's lock.
- */
-
- REQUIRE(rctx->fetch == NULL);
-
- result = dns_resolver_createfetch(rctx->view->resolver,
- dns_fixedname_name(&rctx->name),
- rctx->type,
- NULL, NULL, NULL, 0,
- rctx->task, fetch_done, rctx,
- rctx->rdataset,
- rctx->sigrdataset,
- &rctx->fetch);
-
- return (result);
-}
-
-static isc_result_t
-view_find(resctx_t *rctx, dns_db_t **dbp, dns_dbnode_t **nodep,
- dns_name_t *foundname)
-{
- isc_result_t result;
- dns_name_t *name = dns_fixedname_name(&rctx->name);
- dns_rdatatype_t type;
-
- if (rctx->type == dns_rdatatype_rrsig)
- type = dns_rdatatype_any;
- else
- type = rctx->type;
-
- result = dns_view_find(rctx->view, name, type, 0, 0, ISC_FALSE,
- dbp, nodep, foundname, rctx->rdataset,
- rctx->sigrdataset);
-
- return (result);
-}
-
-static void
-client_resfind(resctx_t *rctx, dns_fetchevent_t *event) {
- isc_mem_t *mctx;
- isc_result_t tresult, result = ISC_R_SUCCESS;
- isc_result_t vresult = ISC_R_SUCCESS;
- isc_boolean_t want_restart;
- isc_boolean_t send_event = ISC_FALSE;
- dns_name_t *name, *prefix;
- dns_fixedname_t foundname, fixed;
- dns_rdataset_t *trdataset;
- dns_rdata_t rdata = DNS_RDATA_INIT;
- unsigned int nlabels;
- int order;
- dns_namereln_t namereln;
- dns_rdata_cname_t cname;
- dns_rdata_dname_t dname;
-
- REQUIRE(RCTX_VALID(rctx));
-
- LOCK(&rctx->lock);
-
- mctx = rctx->view->mctx;
-
- name = dns_fixedname_name(&rctx->name);
-
- do {
- dns_name_t *fname = NULL;
- dns_name_t *ansname = NULL;
- dns_db_t *db = NULL;
- dns_dbnode_t *node = NULL;
-
- rctx->restarts++;
- want_restart = ISC_FALSE;
-
- if (event == NULL && !rctx->canceled) {
- dns_fixedname_init(&foundname);
- fname = dns_fixedname_name(&foundname);
- INSIST(!dns_rdataset_isassociated(rctx->rdataset));
- INSIST(rctx->sigrdataset == NULL ||
- !dns_rdataset_isassociated(rctx->sigrdataset));
- result = view_find(rctx, &db, &node, fname);
- if (result == ISC_R_NOTFOUND) {
- /*
- * We don't know anything about the name.
- * Launch a fetch.
- */
- if (node != NULL) {
- INSIST(db != NULL);
- dns_db_detachnode(db, &node);
- }
- if (db != NULL)
- dns_db_detach(&db);
- result = start_fetch(rctx);
- if (result != ISC_R_SUCCESS) {
- putrdataset(mctx, &rctx->rdataset);
- if (rctx->sigrdataset != NULL)
- putrdataset(mctx,
- &rctx->sigrdataset);
- send_event = ISC_TRUE;
- }
- goto done;
- }
- } else {
- INSIST(event != NULL);
- INSIST(event->fetch == rctx->fetch);
- dns_resolver_destroyfetch(&rctx->fetch);
- db = event->db;
- node = event->node;
- result = event->result;
- vresult = event->vresult;
- fname = dns_fixedname_name(&event->foundname);
- INSIST(event->rdataset == rctx->rdataset);
- INSIST(event->sigrdataset == rctx->sigrdataset);
- }
-
- /*
- * If we've been canceled, forget about the result.
- */
- if (rctx->canceled)
- result = ISC_R_CANCELED;
- else {
- /*
- * Otherwise, get some resource for copying the
- * result.
- */
- ansname = isc_mem_get(mctx, sizeof(*ansname));
- if (ansname == NULL)
- tresult = ISC_R_NOMEMORY;
- else {
- dns_name_t *aname;
-
- aname = dns_fixedname_name(&rctx->name);
- dns_name_init(ansname, NULL);
- tresult = dns_name_dup(aname, mctx, ansname);
- if (tresult != ISC_R_SUCCESS)
- isc_mem_put(mctx, ansname,
- sizeof(*ansname));
- }
- if (tresult != ISC_R_SUCCESS)
- result = tresult;
- }
-
- switch (result) {
- case ISC_R_SUCCESS:
- send_event = ISC_TRUE;
- /*
- * This case is handled in the main line below.
- */
- break;
- case DNS_R_CNAME:
- /*
- * Add the CNAME to the answer list.
- */
- trdataset = rctx->rdataset;
- ISC_LIST_APPEND(ansname->list, rctx->rdataset, link);
- rctx->rdataset = NULL;
- if (rctx->sigrdataset != NULL) {
- ISC_LIST_APPEND(ansname->list,
- rctx->sigrdataset, link);
- rctx->sigrdataset = NULL;
- }
- ISC_LIST_APPEND(rctx->namelist, ansname, link);
- ansname = NULL;
-
- /*
- * Copy the CNAME's target into the lookup's
- * query name and start over.
- */
- tresult = dns_rdataset_first(trdataset);
- if (tresult != ISC_R_SUCCESS)
- goto done;
- dns_rdataset_current(trdataset, &rdata);
- tresult = dns_rdata_tostruct(&rdata, &cname, NULL);
- dns_rdata_reset(&rdata);
- if (tresult != ISC_R_SUCCESS)
- goto done;
- tresult = dns_name_copy(&cname.cname, name, NULL);
- dns_rdata_freestruct(&cname);
- if (tresult == ISC_R_SUCCESS)
- want_restart = ISC_TRUE;
- else
- result = tresult;
- goto done;
- case DNS_R_DNAME:
- /*
- * Add the DNAME to the answer list.
- */
- trdataset = rctx->rdataset;
- ISC_LIST_APPEND(ansname->list, rctx->rdataset, link);
- rctx->rdataset = NULL;
- if (rctx->sigrdataset != NULL) {
- ISC_LIST_APPEND(ansname->list,
- rctx->sigrdataset, link);
- rctx->sigrdataset = NULL;
- }
- ISC_LIST_APPEND(rctx->namelist, ansname, link);
- ansname = NULL;
-
- namereln = dns_name_fullcompare(name, fname, &order,
- &nlabels);
- INSIST(namereln == dns_namereln_subdomain);
- /*
- * Get the target name of the DNAME.
- */
- tresult = dns_rdataset_first(trdataset);
- if (tresult != ISC_R_SUCCESS) {
- result = tresult;
- goto done;
- }
- dns_rdataset_current(trdataset, &rdata);
- tresult = dns_rdata_tostruct(&rdata, &dname, NULL);
- dns_rdata_reset(&rdata);
- if (tresult != ISC_R_SUCCESS) {
- result = tresult;
- goto done;
- }
- /*
- * Construct the new query name and start over.
- */
- dns_fixedname_init(&fixed);
- prefix = dns_fixedname_name(&fixed);
- dns_name_split(name, nlabels, prefix, NULL);
- tresult = dns_name_concatenate(prefix, &dname.dname,
- name, NULL);
- dns_rdata_freestruct(&dname);
- if (tresult == ISC_R_SUCCESS)
- want_restart = ISC_TRUE;
- else
- result = tresult;
- goto done;
- case DNS_R_NCACHENXDOMAIN:
- case DNS_R_NCACHENXRRSET:
- ISC_LIST_APPEND(ansname->list, rctx->rdataset, link);
- ISC_LIST_APPEND(rctx->namelist, ansname, link);
- ansname = NULL;
- rctx->rdataset = NULL;
- /* What about sigrdataset? */
- if (rctx->sigrdataset != NULL)
- putrdataset(mctx, &rctx->sigrdataset);
- send_event = ISC_TRUE;
- goto done;
- default:
- if (rctx->rdataset != NULL)
- putrdataset(mctx, &rctx->rdataset);
- if (rctx->sigrdataset != NULL)
- putrdataset(mctx, &rctx->sigrdataset);
- send_event = ISC_TRUE;
- goto done;
- }
-
- if (rctx->type == dns_rdatatype_any) {
- int n = 0;
- dns_rdatasetiter_t *rdsiter = NULL;
-
- tresult = dns_db_allrdatasets(db, node, NULL, 0,
- &rdsiter);
- if (tresult != ISC_R_SUCCESS) {
- result = tresult;
- goto done;
- }
-
- tresult = dns_rdatasetiter_first(rdsiter);
- while (tresult == ISC_R_SUCCESS) {
- dns_rdatasetiter_current(rdsiter,
- rctx->rdataset);
- if (rctx->rdataset->type != 0) {
- ISC_LIST_APPEND(ansname->list,
- rctx->rdataset,
- link);
- n++;
- rctx->rdataset = NULL;
- } else {
- /*
- * We're not interested in this
- * rdataset.
- */
- dns_rdataset_disassociate(
- rctx->rdataset);
- }
- tresult = dns_rdatasetiter_next(rdsiter);
-
- if (tresult == ISC_R_SUCCESS &&
- rctx->rdataset == NULL) {
- tresult = getrdataset(mctx,
- &rctx->rdataset);
- if (tresult != ISC_R_SUCCESS) {
- result = tresult;
- POST(result);
- break;
- }
- }
- }
- if (n == 0) {
- /*
- * We didn't match any rdatasets (which means
- * something went wrong in this
- * implementation).
- */
- result = DNS_R_SERVFAIL; /* better code? */
- POST(result);
- } else {
- ISC_LIST_APPEND(rctx->namelist, ansname, link);
- ansname = NULL;
- }
- dns_rdatasetiter_destroy(&rdsiter);
- if (tresult != ISC_R_NOMORE)
- result = DNS_R_SERVFAIL; /* ditto */
- else
- result = ISC_R_SUCCESS;
- goto done;
- } else {
- /*
- * This is the "normal" case -- an ordinary question
- * to which we've got the answer.
- */
- ISC_LIST_APPEND(ansname->list, rctx->rdataset, link);
- rctx->rdataset = NULL;
- if (rctx->sigrdataset != NULL) {
- ISC_LIST_APPEND(ansname->list,
- rctx->sigrdataset, link);
- rctx->sigrdataset = NULL;
- }
- ISC_LIST_APPEND(rctx->namelist, ansname, link);
- ansname = NULL;
- }
-
- done:
- /*
- * Free temporary resources
- */
- if (ansname != NULL) {
- dns_rdataset_t *rdataset;
-
- while ((rdataset = ISC_LIST_HEAD(ansname->list))
- != NULL) {
- ISC_LIST_UNLINK(ansname->list, rdataset, link);
- putrdataset(mctx, &rdataset);
- }
- dns_name_free(ansname, mctx);
- isc_mem_put(mctx, ansname, sizeof(*ansname));
- }
-
- if (node != NULL)
- dns_db_detachnode(db, &node);
- if (db != NULL)
- dns_db_detach(&db);
- if (event != NULL)
- isc_event_free(ISC_EVENT_PTR(&event));
-
- /*
- * Limit the number of restarts.
- */
- if (want_restart && rctx->restarts == MAX_RESTARTS) {
- want_restart = ISC_FALSE;
- result = ISC_R_QUOTA;
- send_event = ISC_TRUE;
- }
-
- /*
- * Prepare further find with new resources
- */
- if (want_restart) {
- INSIST(rctx->rdataset == NULL &&
- rctx->sigrdataset == NULL);
-
- result = getrdataset(mctx, &rctx->rdataset);
- if (result == ISC_R_SUCCESS && rctx->want_dnssec) {
- result = getrdataset(mctx, &rctx->sigrdataset);
- if (result != ISC_R_SUCCESS) {
- putrdataset(mctx, &rctx->rdataset);
- }
- }
-
- if (result != ISC_R_SUCCESS) {
- want_restart = ISC_FALSE;
- send_event = ISC_TRUE;
- }
- }
- } while (want_restart);
-
- if (send_event) {
- isc_task_t *task;
-
- while ((name = ISC_LIST_HEAD(rctx->namelist)) != NULL) {
- ISC_LIST_UNLINK(rctx->namelist, name, link);
- ISC_LIST_APPEND(rctx->event->answerlist, name, link);
- }
-
- rctx->event->result = result;
- rctx->event->vresult = vresult;
- task = rctx->event->ev_sender;
- rctx->event->ev_sender = rctx;
- isc_task_sendanddetach(&task, ISC_EVENT_PTR(&rctx->event));
- }
-
- UNLOCK(&rctx->lock);
-}
-
-static void
-resolve_done(isc_task_t *task, isc_event_t *event) {
- resarg_t *resarg = event->ev_arg;
- dns_clientresevent_t *rev = (dns_clientresevent_t *)event;
- dns_name_t *name;
-
- UNUSED(task);
-
- LOCK(&resarg->lock);
-
- resarg->result = rev->result;
- resarg->vresult = rev->vresult;
- while ((name = ISC_LIST_HEAD(rev->answerlist)) != NULL) {
- ISC_LIST_UNLINK(rev->answerlist, name, link);
- ISC_LIST_APPEND(*resarg->namelist, name, link);
- }
-
- dns_client_destroyrestrans(&resarg->trans);
- isc_event_free(&event);
-
- if (!resarg->canceled) {
- UNLOCK(&resarg->lock);
-
- /* Exit from the internal event loop */
- isc_app_ctxsuspend(resarg->actx);
- } else {
- /*
- * We have already exited from the loop (due to some
- * unexpected event). Just clean the arg up.
- */
- UNLOCK(&resarg->lock);
- DESTROYLOCK(&resarg->lock);
- isc_mem_put(resarg->client->mctx, resarg, sizeof(*resarg));
- }
-}
-
-isc_result_t
-dns_client_resolve(dns_client_t *client, dns_name_t *name,
- dns_rdataclass_t rdclass, dns_rdatatype_t type,
- unsigned int options, dns_namelist_t *namelist)
-{
- isc_result_t result;
- isc_appctx_t *actx;
- resarg_t *resarg;
-
- REQUIRE(DNS_CLIENT_VALID(client));
- REQUIRE(namelist != NULL && ISC_LIST_EMPTY(*namelist));
-
- if ((client->attributes & DNS_CLIENTATTR_OWNCTX) == 0 &&
- (options & DNS_CLIENTRESOPT_ALLOWRUN) == 0) {
- /*
- * If the client is run under application's control, we need
- * to create a new running (sub)environment for this
- * particular resolution.
- */
- return (ISC_R_NOTIMPLEMENTED); /* XXXTBD */
- } else
- actx = client->actx;
-
- resarg = isc_mem_get(client->mctx, sizeof(*resarg));
- if (resarg == NULL)
- return (ISC_R_NOMEMORY);
-
- result = isc_mutex_init(&resarg->lock);
- if (result != ISC_R_SUCCESS) {
- isc_mem_put(client->mctx, resarg, sizeof(*resarg));
- return (result);
- }
-
- resarg->actx = actx;
- resarg->client = client;
- resarg->result = DNS_R_SERVFAIL;
- resarg->namelist = namelist;
- resarg->trans = NULL;
- resarg->canceled = ISC_FALSE;
- result = dns_client_startresolve(client, name, rdclass, type, options,
- client->task, resolve_done, resarg,
- &resarg->trans);
- if (result != ISC_R_SUCCESS) {
- DESTROYLOCK(&resarg->lock);
- isc_mem_put(client->mctx, resarg, sizeof(*resarg));
- return (result);
- }
-
- /*
- * Start internal event loop. It blocks until the entire process
- * is completed.
- */
- result = isc_app_ctxrun(actx);
-
- LOCK(&resarg->lock);
- if (result == ISC_R_SUCCESS || result == ISC_R_SUSPEND)
- result = resarg->result;
- if (result != ISC_R_SUCCESS && resarg->vresult != ISC_R_SUCCESS) {
- /*
- * If this lookup failed due to some error in DNSSEC
- * validation, return the validation error code.
- * XXX: or should we pass the validation result separately?
- */
- result = resarg->vresult;
- }
- if (resarg->trans != NULL) {
- /*
- * Unusual termination (perhaps due to signal). We need some
- * tricky cleanup process.
- */
- resarg->canceled = ISC_TRUE;
- dns_client_cancelresolve(resarg->trans);
-
- UNLOCK(&resarg->lock);
-
- /* resarg will be freed in the event handler. */
- } else {
- UNLOCK(&resarg->lock);
-
- DESTROYLOCK(&resarg->lock);
- isc_mem_put(client->mctx, resarg, sizeof(*resarg));
- }
-
- return (result);
-}
-
-isc_result_t
-dns_client_startresolve(dns_client_t *client, dns_name_t *name,
- dns_rdataclass_t rdclass, dns_rdatatype_t type,
- unsigned int options, isc_task_t *task,
- isc_taskaction_t action, void *arg,
- dns_clientrestrans_t **transp)
-{
- dns_view_t *view = NULL;
- dns_clientresevent_t *event = NULL;
- resctx_t *rctx = NULL;
- isc_task_t *clone = NULL;
- isc_mem_t *mctx;
- isc_result_t result;
- dns_rdataset_t *rdataset, *sigrdataset;
- isc_boolean_t want_dnssec;
-
- REQUIRE(DNS_CLIENT_VALID(client));
- REQUIRE(transp != NULL && *transp == NULL);
-
- LOCK(&client->lock);
- result = dns_viewlist_find(&client->viewlist, DNS_CLIENTVIEW_NAME,
- rdclass, &view);
- UNLOCK(&client->lock);
- if (result != ISC_R_SUCCESS)
- return (result);
-
- mctx = client->mctx;
- rdataset = NULL;
- sigrdataset = NULL;
- want_dnssec = ISC_TF((options & DNS_CLIENTRESOPT_NODNSSEC) == 0);
-
- /*
- * Prepare some intermediate resources
- */
- clone = NULL;
- isc_task_attach(task, &clone);
- event = (dns_clientresevent_t *)
- isc_event_allocate(mctx, clone, DNS_EVENT_CLIENTRESDONE,
- action, arg, sizeof(*event));
- if (event == NULL) {
- result = ISC_R_NOMEMORY;
- goto cleanup;
- }
- event->result = DNS_R_SERVFAIL;
- ISC_LIST_INIT(event->answerlist);
-
- rctx = isc_mem_get(mctx, sizeof(*rctx));
- if (rctx == NULL)
- result = ISC_R_NOMEMORY;
- else {
- result = isc_mutex_init(&rctx->lock);
- if (result != ISC_R_SUCCESS) {
- isc_mem_put(mctx, rctx, sizeof(*rctx));
- rctx = NULL;
- }
- }
- if (result != ISC_R_SUCCESS)
- goto cleanup;
-
- result = getrdataset(mctx, &rdataset);
- if (result != ISC_R_SUCCESS)
- goto cleanup;
- rctx->rdataset = rdataset;
-
- if (want_dnssec) {
- result = getrdataset(mctx, &sigrdataset);
- if (result != ISC_R_SUCCESS)
- goto cleanup;
- }
- rctx->sigrdataset = sigrdataset;
-
- dns_fixedname_init(&rctx->name);
- result = dns_name_copy(name, dns_fixedname_name(&rctx->name), NULL);
- if (result != ISC_R_SUCCESS)
- goto cleanup;
-
- rctx->client = client;
- ISC_LINK_INIT(rctx, link);
- rctx->canceled = ISC_FALSE;
- rctx->task = client->task;
- rctx->type = type;
- rctx->view = view;
- rctx->restarts = 0;
- rctx->fetch = NULL;
- rctx->want_dnssec = want_dnssec;
- ISC_LIST_INIT(rctx->namelist);
- rctx->event = event;
-
- rctx->magic = RCTX_MAGIC;
-
- LOCK(&client->lock);
- ISC_LIST_APPEND(client->resctxs, rctx, link);
- UNLOCK(&client->lock);
-
- client_resfind(rctx, NULL);
-
- *transp = (dns_clientrestrans_t *)rctx;
-
- return (ISC_R_SUCCESS);
-
- cleanup:
- if (rdataset != NULL)
- putrdataset(client->mctx, &rdataset);
- if (sigrdataset != NULL)
- putrdataset(client->mctx, &sigrdataset);
- if (rctx != NULL) {
- DESTROYLOCK(&rctx->lock);
- isc_mem_put(mctx, rctx, sizeof(*rctx));
- }
- if (event != NULL)
- isc_event_free(ISC_EVENT_PTR(&event));
- isc_task_detach(&clone);
- dns_view_detach(&view);
-
- return (result);
-}
-
-void
-dns_client_cancelresolve(dns_clientrestrans_t *trans) {
- resctx_t *rctx;
-
- REQUIRE(trans != NULL);
- rctx = (resctx_t *)trans;
- REQUIRE(RCTX_VALID(rctx));
-
- LOCK(&rctx->lock);
-
- if (!rctx->canceled) {
- rctx->canceled = ISC_TRUE;
- if (rctx->fetch != NULL)
- dns_resolver_cancelfetch(rctx->fetch);
- }
-
- UNLOCK(&rctx->lock);
-}
-
-void
-dns_client_freeresanswer(dns_client_t *client, dns_namelist_t *namelist) {
- dns_name_t *name;
- dns_rdataset_t *rdataset;
-
- REQUIRE(DNS_CLIENT_VALID(client));
- REQUIRE(namelist != NULL);
-
- while ((name = ISC_LIST_HEAD(*namelist)) != NULL) {
- ISC_LIST_UNLINK(*namelist, name, link);
- while ((rdataset = ISC_LIST_HEAD(name->list)) != NULL) {
- ISC_LIST_UNLINK(name->list, rdataset, link);
- putrdataset(client->mctx, &rdataset);
- }
- dns_name_free(name, client->mctx);
- isc_mem_put(client->mctx, name, sizeof(*name));
- }
-}
-
-void
-dns_client_destroyrestrans(dns_clientrestrans_t **transp) {
- resctx_t *rctx;
- isc_mem_t *mctx;
- dns_client_t *client;
- isc_boolean_t need_destroyclient = ISC_FALSE;
-
- REQUIRE(transp != NULL);
- rctx = (resctx_t *)*transp;
- REQUIRE(RCTX_VALID(rctx));
- REQUIRE(rctx->fetch == NULL);
- REQUIRE(rctx->event == NULL);
- client = rctx->client;
- REQUIRE(DNS_CLIENT_VALID(client));
-
- mctx = client->mctx;
- dns_view_detach(&rctx->view);
-
- LOCK(&client->lock);
-
- INSIST(ISC_LINK_LINKED(rctx, link));
- ISC_LIST_UNLINK(client->resctxs, rctx, link);
-
- if (client->references == 0 && ISC_LIST_EMPTY(client->resctxs) &&
- ISC_LIST_EMPTY(client->reqctxs) &&
- ISC_LIST_EMPTY(client->updatectxs))
- need_destroyclient = ISC_TRUE;
-
- UNLOCK(&client->lock);
-
- INSIST(ISC_LIST_EMPTY(rctx->namelist));
-
- DESTROYLOCK(&rctx->lock);
- rctx->magic = 0;
-
- isc_mem_put(mctx, rctx, sizeof(*rctx));
-
- if (need_destroyclient)
- destroyclient(&client);
-
- *transp = NULL;
-}
-
-isc_result_t
-dns_client_addtrustedkey(dns_client_t *client, dns_rdataclass_t rdclass,
- dns_name_t *keyname, isc_buffer_t *keydatabuf)
-{
- isc_result_t result;
- dns_view_t *view = NULL;
- dst_key_t *dstkey = NULL;
- dns_keytable_t *secroots = NULL;
-
- REQUIRE(DNS_CLIENT_VALID(client));
-
- LOCK(&client->lock);
- result = dns_viewlist_find(&client->viewlist, DNS_CLIENTVIEW_NAME,
- rdclass, &view);
- UNLOCK(&client->lock);
- if (result != ISC_R_SUCCESS)
- goto cleanup;
-
- result = dns_view_getsecroots(view, &secroots);
- if (result != ISC_R_SUCCESS)
- goto cleanup;
-
- result = dst_key_fromdns(keyname, rdclass, keydatabuf, client->mctx,
- &dstkey);
- if (result != ISC_R_SUCCESS)
- goto cleanup;
-
- result = dns_keytable_add(secroots, ISC_FALSE, &dstkey);
-
- cleanup:
- if (dstkey != NULL)
- dst_key_free(&dstkey);
- if (view != NULL)
- dns_view_detach(&view);
- if (secroots != NULL)
- dns_keytable_detach(&secroots);
- return (result);
-}
-
-/*%
- * Simple request routines
- */
-static void
-request_done(isc_task_t *task, isc_event_t *event) {
- dns_requestevent_t *reqev = NULL;
- dns_request_t *request;
- isc_result_t result, eresult;
- reqctx_t *ctx;
-
- UNUSED(task);
-
- REQUIRE(event->ev_type == DNS_EVENT_REQUESTDONE);
- reqev = (dns_requestevent_t *)event;
- request = reqev->request;
- result = eresult = reqev->result;
- ctx = reqev->ev_arg;
- REQUIRE(REQCTX_VALID(ctx));
-
- isc_event_free(&event);
-
- LOCK(&ctx->lock);
-
- if (eresult == ISC_R_SUCCESS) {
- result = dns_request_getresponse(request, ctx->event->rmessage,
- ctx->parseoptions);
- }
-
- if (ctx->tsigkey != NULL)
- dns_tsigkey_detach(&ctx->tsigkey);
-
- if (ctx->canceled)
- ctx->event->result = ISC_R_CANCELED;
- else
- ctx->event->result = result;
- task = ctx->event->ev_sender;
- ctx->event->ev_sender = ctx;
- isc_task_sendanddetach(&task, ISC_EVENT_PTR(&ctx->event));
-
- UNLOCK(&ctx->lock);
-}
-
-static void
-localrequest_done(isc_task_t *task, isc_event_t *event) {
- reqarg_t *reqarg = event->ev_arg;
- dns_clientreqevent_t *rev =(dns_clientreqevent_t *)event;
-
- UNUSED(task);
-
- REQUIRE(event->ev_type == DNS_EVENT_CLIENTREQDONE);
-
- LOCK(&reqarg->lock);
-
- reqarg->result = rev->result;
- dns_client_destroyreqtrans(&reqarg->trans);
- isc_event_free(&event);
-
- if (!reqarg->canceled) {
- UNLOCK(&reqarg->lock);
-
- /* Exit from the internal event loop */
- isc_app_ctxsuspend(reqarg->actx);
- } else {
- /*
- * We have already exited from the loop (due to some
- * unexpected event). Just clean the arg up.
- */
- UNLOCK(&reqarg->lock);
- DESTROYLOCK(&reqarg->lock);
- isc_mem_put(reqarg->client->mctx, reqarg, sizeof(*reqarg));
- }
-}
-
-isc_result_t
-dns_client_request(dns_client_t *client, dns_message_t *qmessage,
- dns_message_t *rmessage, isc_sockaddr_t *server,
- unsigned int options, unsigned int parseoptions,
- dns_tsec_t *tsec, unsigned int timeout,
- unsigned int udptimeout, unsigned int udpretries)
-{
- isc_appctx_t *actx;
- reqarg_t *reqarg;
- isc_result_t result;
-
- REQUIRE(DNS_CLIENT_VALID(client));
- REQUIRE(qmessage != NULL);
- REQUIRE(rmessage != NULL);
-
- if ((client->attributes & DNS_CLIENTATTR_OWNCTX) == 0 &&
- (options & DNS_CLIENTREQOPT_ALLOWRUN) == 0) {
- /*
- * If the client is run under application's control, we need
- * to create a new running (sub)environment for this
- * particular resolution.
- */
- return (ISC_R_NOTIMPLEMENTED); /* XXXTBD */
- } else
- actx = client->actx;
-
- reqarg = isc_mem_get(client->mctx, sizeof(*reqarg));
- if (reqarg == NULL)
- return (ISC_R_NOMEMORY);
-
- result = isc_mutex_init(&reqarg->lock);
- if (result != ISC_R_SUCCESS) {
- isc_mem_put(client->mctx, reqarg, sizeof(*reqarg));
- return (result);
- }
-
- reqarg->actx = actx;
- reqarg->client = client;
- reqarg->trans = NULL;
- reqarg->canceled = ISC_FALSE;
-
- result = dns_client_startrequest(client, qmessage, rmessage, server,
- options, parseoptions, tsec, timeout,
- udptimeout, udpretries,
- client->task, localrequest_done,
- reqarg, &reqarg->trans);
- if (result != ISC_R_SUCCESS) {
- DESTROYLOCK(&reqarg->lock);
- isc_mem_put(client->mctx, reqarg, sizeof(*reqarg));
- return (result);
- }
-
- /*
- * Start internal event loop. It blocks until the entire process
- * is completed.
- */
- result = isc_app_ctxrun(actx);
-
- LOCK(&reqarg->lock);
- if (result == ISC_R_SUCCESS || result == ISC_R_SUSPEND)
- result = reqarg->result;
- if (reqarg->trans != NULL) {
- /*
- * Unusual termination (perhaps due to signal). We need some
- * tricky cleanup process.
- */
- reqarg->canceled = ISC_TRUE;
- dns_client_cancelresolve(reqarg->trans);
-
- UNLOCK(&reqarg->lock);
-
- /* reqarg will be freed in the event handler. */
- } else {
- UNLOCK(&reqarg->lock);
-
- DESTROYLOCK(&reqarg->lock);
- isc_mem_put(client->mctx, reqarg, sizeof(*reqarg));
- }
-
- return (result);
-}
-
-isc_result_t
-dns_client_startrequest(dns_client_t *client, dns_message_t *qmessage,
- dns_message_t *rmessage, isc_sockaddr_t *server,
- unsigned int options, unsigned int parseoptions,
- dns_tsec_t *tsec, unsigned int timeout,
- unsigned int udptimeout, unsigned int udpretries,
- isc_task_t *task, isc_taskaction_t action, void *arg,
- dns_clientreqtrans_t **transp)
-{
- isc_result_t result;
- dns_view_t *view = NULL;
- isc_task_t *clone = NULL;
- dns_clientreqevent_t *event = NULL;
- reqctx_t *ctx = NULL;
- dns_tsectype_t tsectype = dns_tsectype_none;
-
- UNUSED(options);
-
- REQUIRE(DNS_CLIENT_VALID(client));
- REQUIRE(qmessage != NULL);
- REQUIRE(rmessage != NULL);
- REQUIRE(transp != NULL && *transp == NULL);
-
- if (tsec != NULL) {
- tsectype = dns_tsec_gettype(tsec);
- if (tsectype != dns_tsectype_tsig)
- return (ISC_R_NOTIMPLEMENTED); /* XXX */
- }
-
- LOCK(&client->lock);
- result = dns_viewlist_find(&client->viewlist, DNS_CLIENTVIEW_NAME,
- qmessage->rdclass, &view);
- UNLOCK(&client->lock);
- if (result != ISC_R_SUCCESS)
- return (result);
-
- clone = NULL;
- isc_task_attach(task, &clone);
- event = (dns_clientreqevent_t *)
- isc_event_allocate(client->mctx, clone,
- DNS_EVENT_CLIENTREQDONE,
- action, arg, sizeof(*event));
- if (event == NULL) {
- result = ISC_R_NOMEMORY;
- goto cleanup;
- }
-
- ctx = isc_mem_get(client->mctx, sizeof(*ctx));
- if (ctx == NULL)
- result = ISC_R_NOMEMORY;
- else {
- result = isc_mutex_init(&ctx->lock);
- if (result != ISC_R_SUCCESS) {
- isc_mem_put(client->mctx, ctx, sizeof(*ctx));
- ctx = NULL;
- }
- }
- if (result != ISC_R_SUCCESS)
- goto cleanup;
-
- ctx->client = client;
- ISC_LINK_INIT(ctx, link);
- ctx->parseoptions = parseoptions;
- ctx->canceled = ISC_FALSE;
- ctx->event = event;
- ctx->event->rmessage = rmessage;
- ctx->tsigkey = NULL;
- if (tsec != NULL)
- dns_tsec_getkey(tsec, &ctx->tsigkey);
-
- ctx->magic = REQCTX_MAGIC;
-
- LOCK(&client->lock);
- ISC_LIST_APPEND(client->reqctxs, ctx, link);
- UNLOCK(&client->lock);
-
- ctx->request = NULL;
- result = dns_request_createvia3(view->requestmgr, qmessage, NULL,
- server, options, ctx->tsigkey,
- timeout, udptimeout, udpretries,
- client->task, request_done, ctx,
- &ctx->request);
- if (result == ISC_R_SUCCESS) {
- dns_view_detach(&view);
- *transp = (dns_clientreqtrans_t *)ctx;
- return (ISC_R_SUCCESS);
- }
-
- cleanup:
- if (ctx != NULL) {
- LOCK(&client->lock);
- ISC_LIST_UNLINK(client->reqctxs, ctx, link);
- UNLOCK(&client->lock);
- DESTROYLOCK(&ctx->lock);
- isc_mem_put(client->mctx, ctx, sizeof(*ctx));
- }
- if (event != NULL)
- isc_event_free(ISC_EVENT_PTR(&event));
- isc_task_detach(&clone);
- dns_view_detach(&view);
-
- return (result);
-}
-
-void
-dns_client_cancelrequest(dns_clientreqtrans_t *trans) {
- reqctx_t *ctx;
-
- REQUIRE(trans != NULL);
- ctx = (reqctx_t *)trans;
- REQUIRE(REQCTX_VALID(ctx));
-
- LOCK(&ctx->lock);
-
- if (!ctx->canceled) {
- ctx->canceled = ISC_TRUE;
- if (ctx->request != NULL)
- dns_request_cancel(ctx->request);
- }
-
- UNLOCK(&ctx->lock);
-}
-
-void
-dns_client_destroyreqtrans(dns_clientreqtrans_t **transp) {
- reqctx_t *ctx;
- isc_mem_t *mctx;
- dns_client_t *client;
- isc_boolean_t need_destroyclient = ISC_FALSE;
-
- REQUIRE(transp != NULL);
- ctx = (reqctx_t *)*transp;
- REQUIRE(REQCTX_VALID(ctx));
- client = ctx->client;
- REQUIRE(DNS_CLIENT_VALID(client));
- REQUIRE(ctx->event == NULL);
- REQUIRE(ctx->request != NULL);
-
- dns_request_destroy(&ctx->request);
- mctx = client->mctx;
-
- LOCK(&client->lock);
-
- INSIST(ISC_LINK_LINKED(ctx, link));
- ISC_LIST_UNLINK(client->reqctxs, ctx, link);
-
- if (client->references == 0 && ISC_LIST_EMPTY(client->resctxs) &&
- ISC_LIST_EMPTY(client->reqctxs) &&
- ISC_LIST_EMPTY(client->updatectxs)) {
- need_destroyclient = ISC_TRUE;
- }
-
- UNLOCK(&client->lock);
-
- DESTROYLOCK(&ctx->lock);
- ctx->magic = 0;
-
- isc_mem_put(mctx, ctx, sizeof(*ctx));
-
- if (need_destroyclient)
- destroyclient(&client);
-
- *transp = NULL;
-}
-
-/*%
- * Dynamic update routines
- */
-static isc_result_t
-rcode2result(dns_rcode_t rcode) {
- /* XXX: isn't there a similar function? */
- switch (rcode) {
- case dns_rcode_formerr:
- return (DNS_R_FORMERR);
- case dns_rcode_servfail:
- return (DNS_R_SERVFAIL);
- case dns_rcode_nxdomain:
- return (DNS_R_NXDOMAIN);
- case dns_rcode_notimp:
- return (DNS_R_NOTIMP);
- case dns_rcode_refused:
- return (DNS_R_REFUSED);
- case dns_rcode_yxdomain:
- return (DNS_R_YXDOMAIN);
- case dns_rcode_yxrrset:
- return (DNS_R_YXRRSET);
- case dns_rcode_nxrrset:
- return (DNS_R_NXRRSET);
- case dns_rcode_notauth:
- return (DNS_R_NOTAUTH);
- case dns_rcode_notzone:
- return (DNS_R_NOTZONE);
- case dns_rcode_badvers:
- return (DNS_R_BADVERS);
- }
-
- return (ISC_R_FAILURE);
-}
-
-static void
-update_sendevent(updatectx_t *uctx, isc_result_t result) {
- isc_task_t *task;
-
- dns_message_destroy(&uctx->updatemsg);
- if (uctx->tsigkey != NULL)
- dns_tsigkey_detach(&uctx->tsigkey);
- if (uctx->sig0key != NULL)
- dst_key_free(&uctx->sig0key);
-
- if (uctx->canceled)
- uctx->event->result = ISC_R_CANCELED;
- else
- uctx->event->result = result;
- uctx->event->state = uctx->state;
- task = uctx->event->ev_sender;
- uctx->event->ev_sender = uctx;
- isc_task_sendanddetach(&task, ISC_EVENT_PTR(&uctx->event));
-}
-
-static void
-update_done(isc_task_t *task, isc_event_t *event) {
- isc_result_t result;
- dns_requestevent_t *reqev = NULL;
- dns_request_t *request;
- dns_message_t *answer = NULL;
- updatectx_t *uctx = event->ev_arg;
- dns_client_t *client;
- unsigned int timeout;
-
- UNUSED(task);
-
- REQUIRE(event->ev_type == DNS_EVENT_REQUESTDONE);
- reqev = (dns_requestevent_t *)event;
- request = reqev->request;
- REQUIRE(UCTX_VALID(uctx));
- client = uctx->client;
- REQUIRE(DNS_CLIENT_VALID(client));
-
- result = reqev->result;
- if (result != ISC_R_SUCCESS)
- goto out;
-
- result = dns_message_create(client->mctx, DNS_MESSAGE_INTENTPARSE,
- &answer);
- if (result != ISC_R_SUCCESS)
- goto out;
- uctx->state = dns_clientupdatestate_done;
- result = dns_request_getresponse(request, answer,
- DNS_MESSAGEPARSE_PRESERVEORDER);
- if (result == ISC_R_SUCCESS && answer->rcode != dns_rcode_noerror)
- result = rcode2result(answer->rcode);
-
- out:
- if (answer != NULL)
- dns_message_destroy(&answer);
- isc_event_free(&event);
-
- LOCK(&uctx->lock);
- uctx->currentserver = ISC_LIST_NEXT(uctx->currentserver, link);
- dns_request_destroy(&uctx->updatereq);
- if (result != ISC_R_SUCCESS && !uctx->canceled &&
- uctx->currentserver != NULL) {
- dns_message_renderreset(uctx->updatemsg);
- dns_message_settsigkey(uctx->updatemsg, NULL);
-
- timeout = client->update_timeout / uctx->nservers;
- if (timeout < MIN_UPDATE_TIMEOUT)
- timeout = MIN_UPDATE_TIMEOUT;
- result = dns_request_createvia3(uctx->view->requestmgr,
- uctx->updatemsg,
- NULL,
- uctx->currentserver, 0,
- uctx->tsigkey,
- timeout,
- client->update_udptimeout,
- client->update_udpretries,
- client->task,
- update_done, uctx,
- &uctx->updatereq);
- UNLOCK(&uctx->lock);
-
- if (result == ISC_R_SUCCESS) {
- /* XXX: should we keep the 'done' state here? */
- uctx->state = dns_clientupdatestate_sent;
- return;
- }
- } else
- UNLOCK(&uctx->lock);
-
- update_sendevent(uctx, result);
-}
-
-static isc_result_t
-send_update(updatectx_t *uctx) {
- isc_result_t result;
- dns_name_t *name = NULL;
- dns_rdataset_t *rdataset = NULL;
- dns_client_t *client = uctx->client;
- unsigned int timeout;
-
- REQUIRE(uctx->zonename != NULL && uctx->currentserver != NULL);
-
- result = dns_message_gettempname(uctx->updatemsg, &name);
- if (result != ISC_R_SUCCESS)
- return (result);
- dns_name_init(name, NULL);
- dns_name_clone(uctx->zonename, name);
- result = dns_message_gettemprdataset(uctx->updatemsg, &rdataset);
- if (result != ISC_R_SUCCESS) {
- dns_message_puttempname(uctx->updatemsg, &name);
- return (result);
- }
- dns_rdataset_makequestion(rdataset, uctx->rdclass, dns_rdatatype_soa);
- ISC_LIST_INIT(name->list);
- ISC_LIST_APPEND(name->list, rdataset, link);
- dns_message_addname(uctx->updatemsg, name, DNS_SECTION_ZONE);
- if (uctx->tsigkey == NULL && uctx->sig0key != NULL) {
- result = dns_message_setsig0key(uctx->updatemsg,
- uctx->sig0key);
- if (result != ISC_R_SUCCESS)
- return (result);
- }
- timeout = client->update_timeout / uctx->nservers;
- if (timeout < MIN_UPDATE_TIMEOUT)
- timeout = MIN_UPDATE_TIMEOUT;
- result = dns_request_createvia3(uctx->view->requestmgr,
- uctx->updatemsg,
- NULL, uctx->currentserver, 0,
- uctx->tsigkey, timeout,
- client->update_udptimeout,
- client->update_udpretries,
- client->task, update_done, uctx,
- &uctx->updatereq);
- if (result == ISC_R_SUCCESS &&
- uctx->state == dns_clientupdatestate_prepare) {
- uctx->state = dns_clientupdatestate_sent;
- }
-
- return (result);
-}
-
-static void
-resolveaddr_done(isc_task_t *task, isc_event_t *event) {
- isc_result_t result;
- int family;
- dns_rdatatype_t qtype;
- dns_clientresevent_t *rev = (dns_clientresevent_t *)event;
- dns_name_t *name;
- dns_rdataset_t *rdataset;
- updatectx_t *uctx;
- isc_boolean_t completed = ISC_FALSE;
-
- UNUSED(task);
-
- REQUIRE(event->ev_arg != NULL);
- uctx = *(updatectx_t **)event->ev_arg;
- REQUIRE(UCTX_VALID(uctx));
-
- if (event->ev_arg == &uctx->bp4) {
- family = AF_INET;
- qtype = dns_rdatatype_a;
- LOCK(&uctx->lock);
- dns_client_destroyrestrans(&uctx->restrans);
- UNLOCK(&uctx->lock);
- } else {
- INSIST(event->ev_arg == &uctx->bp6);
- family = AF_INET6;
- qtype = dns_rdatatype_aaaa;
- LOCK(&uctx->lock);
- dns_client_destroyrestrans(&uctx->restrans2);
- UNLOCK(&uctx->lock);
- }
-
- result = rev->result;
- if (result != ISC_R_SUCCESS)
- goto done;
-
- for (name = ISC_LIST_HEAD(rev->answerlist); name != NULL;
- name = ISC_LIST_NEXT(name, link)) {
- for (rdataset = ISC_LIST_HEAD(name->list);
- rdataset != NULL;
- rdataset = ISC_LIST_NEXT(rdataset, link)) {
- if (!dns_rdataset_isassociated(rdataset))
- continue;
- if (rdataset->type != qtype)
- continue;
-
- for (result = dns_rdataset_first(rdataset);
- result == ISC_R_SUCCESS;
- result = dns_rdataset_next(rdataset)) {
- dns_rdata_t rdata;
- dns_rdata_in_a_t rdata_a;
- dns_rdata_in_aaaa_t rdata_aaaa;
- isc_sockaddr_t *sa;
-
- sa = isc_mem_get(uctx->client->mctx,
- sizeof(*sa));
- if (sa == NULL) {
- /*
- * If we fail to get a sockaddr,
- we simply move forward with the
- * addresses we've got so far.
- */
- goto done;
- }
-
- dns_rdata_init(&rdata);
- switch (family) {
- case AF_INET:
- dns_rdataset_current(rdataset, &rdata);
- result = dns_rdata_tostruct(&rdata, &rdata_a,
- NULL);
- RUNTIME_CHECK(result == ISC_R_SUCCESS);
- isc_sockaddr_fromin(sa,
- &rdata_a.in_addr,
- 53);
- dns_rdata_freestruct(&rdata_a);
- break;
- case AF_INET6:
- dns_rdataset_current(rdataset, &rdata);
- result = dns_rdata_tostruct(&rdata, &rdata_aaaa,
- NULL);
- RUNTIME_CHECK(result == ISC_R_SUCCESS);
- isc_sockaddr_fromin6(sa,
- &rdata_aaaa.in6_addr,
- 53);
- dns_rdata_freestruct(&rdata_aaaa);
- break;
- }
-
- ISC_LINK_INIT(sa, link);
- ISC_LIST_APPEND(uctx->servers, sa, link);
- uctx->nservers++;
- }
- }
- }
-
- done:
- dns_client_freeresanswer(uctx->client, &rev->answerlist);
- isc_event_free(&event);
-
- LOCK(&uctx->lock);
- if (uctx->restrans == NULL && uctx->restrans2 == NULL)
- completed = ISC_TRUE;
- UNLOCK(&uctx->lock);
-
- if (completed) {
- INSIST(uctx->currentserver == NULL);
- uctx->currentserver = ISC_LIST_HEAD(uctx->servers);
- if (uctx->currentserver != NULL && !uctx->canceled)
- send_update(uctx);
- else {
- if (result == ISC_R_SUCCESS)
- result = ISC_R_NOTFOUND;
- update_sendevent(uctx, result);
- }
- }
-}
-
-static isc_result_t
-process_soa(updatectx_t *uctx, dns_rdataset_t *soaset, dns_name_t *soaname) {
- isc_result_t result;
- dns_rdata_t soarr = DNS_RDATA_INIT;
- dns_rdata_soa_t soa;
- dns_name_t primary;
-
- result = dns_rdataset_first(soaset);
- if (result != ISC_R_SUCCESS)
- return (result);
- dns_rdata_init(&soarr);
- dns_rdataset_current(soaset, &soarr);
- result = dns_rdata_tostruct(&soarr, &soa, NULL);
- if (result != ISC_R_SUCCESS)
- return (result);
-
- dns_name_init(&primary, NULL);
- dns_name_clone(&soa.origin, &primary);
-
- if (uctx->zonename == NULL) {
- uctx->zonename = dns_fixedname_name(&uctx->zonefname);
- result = dns_name_copy(soaname, uctx->zonename, NULL);
- if (result != ISC_R_SUCCESS)
- goto out;
- }
-
- if (uctx->currentserver != NULL)
- result = send_update(uctx);
- else {
- /*
- * Get addresses of the primary server. We don't use the ADB
- * feature so that we could avoid caching data.
- */
- LOCK(&uctx->lock);
- uctx->bp4 = uctx;
- result = dns_client_startresolve(uctx->client, &primary,
- uctx->rdclass,
- dns_rdatatype_a,
- 0, uctx->client->task,
- resolveaddr_done, &uctx->bp4,
- &uctx->restrans);
- if (result == ISC_R_SUCCESS) {
- uctx->bp6 = uctx;
- result = dns_client_startresolve(uctx->client,
- &primary,
- uctx->rdclass,
- dns_rdatatype_aaaa,
- 0, uctx->client->task,
- resolveaddr_done,
- &uctx->bp6,
- &uctx->restrans2);
- }
- UNLOCK(&uctx->lock);
- }
-
- out:
- dns_rdata_freestruct(&soa);
-
- return (result);
-}
-
-static void
-receive_soa(isc_task_t *task, isc_event_t *event) {
- dns_requestevent_t *reqev = NULL;
- updatectx_t *uctx;
- dns_client_t *client;
- isc_result_t result, eresult;
- dns_request_t *request;
- dns_message_t *rcvmsg = NULL;
- dns_section_t section;
- dns_rdataset_t *soaset = NULL;
- int pass = 0;
- dns_name_t *name;
- dns_message_t *soaquery = NULL;
- isc_sockaddr_t *addr;
- isc_boolean_t seencname = ISC_FALSE;
- isc_boolean_t droplabel = ISC_FALSE;
- dns_name_t tname;
- unsigned int nlabels;
-
- UNUSED(task);
-
- REQUIRE(event->ev_type == DNS_EVENT_REQUESTDONE);
- reqev = (dns_requestevent_t *)event;
- request = reqev->request;
- result = eresult = reqev->result;
- POST(result);
- uctx = reqev->ev_arg;
- client = uctx->client;
- soaquery = uctx->soaquery;
- addr = uctx->currentserver;
- INSIST(addr != NULL);
-
- isc_event_free(&event);
-
- if (eresult != ISC_R_SUCCESS) {
- result = eresult;
- goto out;
- }
-
- result = dns_message_create(uctx->client->mctx,
- DNS_MESSAGE_INTENTPARSE, &rcvmsg);
- if (result != ISC_R_SUCCESS)
- goto out;
- result = dns_request_getresponse(request, rcvmsg,
- DNS_MESSAGEPARSE_PRESERVEORDER);
-
- if (result == DNS_R_TSIGERRORSET) {
- dns_request_t *newrequest = NULL;
-
- /* Retry SOA request without TSIG */
- dns_message_destroy(&rcvmsg);
- dns_message_renderreset(uctx->soaquery);
- result = dns_request_createvia3(uctx->view->requestmgr,
- uctx->soaquery, NULL, addr, 0,
- NULL,
- client->find_timeout * 20,
- client->find_timeout, 3,
- uctx->client->task,
- receive_soa, uctx,
- &newrequest);
- if (result == ISC_R_SUCCESS) {
- LOCK(&uctx->lock);
- dns_request_destroy(&uctx->soareq);
- uctx->soareq = newrequest;
- UNLOCK(&uctx->lock);
-
- return;
- }
- goto out;
- }
-
- section = DNS_SECTION_ANSWER;
- POST(section);
-
- if (rcvmsg->rcode != dns_rcode_noerror &&
- rcvmsg->rcode != dns_rcode_nxdomain) {
- result = rcode2result(rcvmsg->rcode);
- goto out;
- }
-
- lookforsoa:
- if (pass == 0)
- section = DNS_SECTION_ANSWER;
- else if (pass == 1)
- section = DNS_SECTION_AUTHORITY;
- else {
- droplabel = ISC_TRUE;
- goto out;
- }
-
- result = dns_message_firstname(rcvmsg, section);
- if (result != ISC_R_SUCCESS) {
- pass++;
- goto lookforsoa;
- }
- while (result == ISC_R_SUCCESS) {
- name = NULL;
- dns_message_currentname(rcvmsg, section, &name);
- soaset = NULL;
- result = dns_message_findtype(name, dns_rdatatype_soa, 0,
- &soaset);
- if (result == ISC_R_SUCCESS)
- break;
- if (section == DNS_SECTION_ANSWER) {
- dns_rdataset_t *tset = NULL;
- if (dns_message_findtype(name, dns_rdatatype_cname, 0,
- &tset) == ISC_R_SUCCESS
- ||
- dns_message_findtype(name, dns_rdatatype_dname, 0,
- &tset) == ISC_R_SUCCESS
- )
- {
- seencname = ISC_TRUE;
- break;
- }
- }
-
- result = dns_message_nextname(rcvmsg, section);
- }
-
- if (soaset == NULL && !seencname) {
- pass++;
- goto lookforsoa;
- }
-
- if (seencname) {
- droplabel = ISC_TRUE;
- goto out;
- }
-
- result = process_soa(uctx, soaset, name);
-
- out:
- if (droplabel) {
- result = dns_message_firstname(soaquery, DNS_SECTION_QUESTION);
- INSIST(result == ISC_R_SUCCESS);
- name = NULL;
- dns_message_currentname(soaquery, DNS_SECTION_QUESTION, &name);
- nlabels = dns_name_countlabels(name);
- if (nlabels == 1)
- result = DNS_R_SERVFAIL; /* is there a better error? */
- else {
- dns_name_init(&tname, NULL);
- dns_name_getlabelsequence(name, 1, nlabels - 1,
- &tname);
- dns_name_clone(&tname, name);
- dns_request_destroy(&request);
- LOCK(&uctx->lock);
- uctx->soareq = NULL;
- UNLOCK(&uctx->lock);
- dns_message_renderreset(soaquery);
- dns_message_settsigkey(soaquery, NULL);
- result = dns_request_createvia3(uctx->view->requestmgr,
- soaquery, NULL,
- uctx->currentserver, 0,
- uctx->tsigkey,
- client->find_timeout *
- 20,
- client->find_timeout,
- 3, client->task,
- receive_soa, uctx,
- &uctx->soareq);
- }
- }
-
- if (!droplabel || result != ISC_R_SUCCESS) {
- dns_message_destroy(&uctx->soaquery);
- LOCK(&uctx->lock);
- dns_request_destroy(&uctx->soareq);
- UNLOCK(&uctx->lock);
- }
-
- if (rcvmsg != NULL)
- dns_message_destroy(&rcvmsg);
-
- if (result != ISC_R_SUCCESS)
- update_sendevent(uctx, result);
-}
-
-static isc_result_t
-request_soa(updatectx_t *uctx) {
- isc_result_t result;
- dns_message_t *soaquery = uctx->soaquery;
- dns_name_t *name = NULL;
- dns_rdataset_t *rdataset = NULL;
-
- if (soaquery == NULL) {
- result = dns_message_create(uctx->client->mctx,
- DNS_MESSAGE_INTENTRENDER,
- &soaquery);
- if (result != ISC_R_SUCCESS)
- return (result);
- }
- soaquery->flags |= DNS_MESSAGEFLAG_RD;
- result = dns_message_gettempname(soaquery, &name);
- if (result != ISC_R_SUCCESS)
- goto fail;
- result = dns_message_gettemprdataset(soaquery, &rdataset);
- if (result != ISC_R_SUCCESS)
- goto fail;
- dns_rdataset_makequestion(rdataset, uctx->rdclass, dns_rdatatype_soa);
- dns_name_clone(uctx->firstname, name);
- ISC_LIST_APPEND(name->list, rdataset, link);
- dns_message_addname(soaquery, name, DNS_SECTION_QUESTION);
- rdataset = NULL;
- name = NULL;
-
- result = dns_request_createvia3(uctx->view->requestmgr,
- soaquery, NULL, uctx->currentserver, 0,
- uctx->tsigkey,
- uctx->client->find_timeout * 20,
- uctx->client->find_timeout, 3,
- uctx->client->task, receive_soa, uctx,
- &uctx->soareq);
- if (result == ISC_R_SUCCESS) {
- uctx->soaquery = soaquery;
- return (ISC_R_SUCCESS);
- }
-
- fail:
- if (rdataset != NULL) {
- ISC_LIST_UNLINK(name->list, rdataset, link); /* for safety */
- dns_message_puttemprdataset(soaquery, &rdataset);
- }
- if (name != NULL)
- dns_message_puttempname(soaquery, &name);
- dns_message_destroy(&soaquery);
-
- return (result);
-}
-
-static void
-resolvesoa_done(isc_task_t *task, isc_event_t *event) {
- dns_clientresevent_t *rev = (dns_clientresevent_t *)event;
- updatectx_t *uctx;
- dns_name_t *name, tname;
- dns_rdataset_t *rdataset = NULL;
- isc_result_t result = rev->result;
- unsigned int nlabels;
-
- UNUSED(task);
-
- uctx = event->ev_arg;
- REQUIRE(UCTX_VALID(uctx));
-
- LOCK(&uctx->lock);
- dns_client_destroyrestrans(&uctx->restrans);
- UNLOCK(&uctx->lock);
-
- uctx = event->ev_arg;
- if (result != ISC_R_SUCCESS &&
- result != DNS_R_NCACHENXDOMAIN &&
- result != DNS_R_NCACHENXRRSET) {
- /* XXX: what about DNSSEC failure? */
- goto out;
- }
-
- for (name = ISC_LIST_HEAD(rev->answerlist); name != NULL;
- name = ISC_LIST_NEXT(name, link)) {
- for (rdataset = ISC_LIST_HEAD(name->list);
- rdataset != NULL;
- rdataset = ISC_LIST_NEXT(rdataset, link)) {
- if (dns_rdataset_isassociated(rdataset) &&
- rdataset->type == dns_rdatatype_soa)
- break;
- }
- }
-
- if (rdataset == NULL) {
- /* Drop one label and retry resolution. */
- nlabels = dns_name_countlabels(&uctx->soaqname);
- if (nlabels == 1) {
- result = DNS_R_SERVFAIL; /* is there a better error? */
- goto out;
- }
- dns_name_init(&tname, NULL);
- dns_name_getlabelsequence(&uctx->soaqname, 1, nlabels - 1,
- &tname);
- dns_name_clone(&tname, &uctx->soaqname);
-
- result = dns_client_startresolve(uctx->client, &uctx->soaqname,
- uctx->rdclass,
- dns_rdatatype_soa, 0,
- uctx->client->task,
- resolvesoa_done, uctx,
- &uctx->restrans);
- } else
- result = process_soa(uctx, rdataset, &uctx->soaqname);
-
- out:
- dns_client_freeresanswer(uctx->client, &rev->answerlist);
- isc_event_free(&event);
-
- if (result != ISC_R_SUCCESS)
- update_sendevent(uctx, result);
-}
-
-static isc_result_t
-copy_name(isc_mem_t *mctx, dns_message_t *msg, dns_name_t *name,
- dns_name_t **newnamep)
-{
- isc_result_t result;
- dns_name_t *newname = NULL;
- isc_region_t r;
- isc_buffer_t *namebuf = NULL, *rdatabuf = NULL;
- dns_rdatalist_t *rdatalist;
- dns_rdataset_t *rdataset, *newrdataset;
- dns_rdata_t rdata = DNS_RDATA_INIT, *newrdata;
-
- result = dns_message_gettempname(msg, &newname);
- if (result != ISC_R_SUCCESS)
- return (result);
- result = isc_buffer_allocate(mctx, &namebuf, DNS_NAME_MAXWIRE);
- if (result != ISC_R_SUCCESS)
- goto fail;
- dns_name_init(newname, NULL);
- dns_name_setbuffer(newname, namebuf);
- dns_message_takebuffer(msg, &namebuf);
- result = dns_name_copy(name, newname, NULL);
- if (result != ISC_R_SUCCESS)
- goto fail;
-
- for (rdataset = ISC_LIST_HEAD(name->list); rdataset != NULL;
- rdataset = ISC_LIST_NEXT(rdataset, link)) {
- rdatalist = NULL;
- result = dns_message_gettemprdatalist(msg, &rdatalist);
- if (result != ISC_R_SUCCESS)
- goto fail;
- dns_rdatalist_init(rdatalist);
- rdatalist->type = rdataset->type;
- rdatalist->rdclass = rdataset->rdclass;
- rdatalist->covers = rdataset->covers;
- rdatalist->ttl = rdataset->ttl;
-
- result = dns_rdataset_first(rdataset);
- while (result == ISC_R_SUCCESS) {
- dns_rdata_reset(&rdata);
- dns_rdataset_current(rdataset, &rdata);
-
- newrdata = NULL;
- result = dns_message_gettemprdata(msg, &newrdata);
- if (result != ISC_R_SUCCESS)
- goto fail;
- dns_rdata_toregion(&rdata, &r);
- rdatabuf = NULL;
- result = isc_buffer_allocate(mctx, &rdatabuf,
- r.length);
- if (result != ISC_R_SUCCESS)
- goto fail;
- isc_buffer_putmem(rdatabuf, r.base, r.length);
- isc_buffer_usedregion(rdatabuf, &r);
- dns_rdata_init(newrdata);
- dns_rdata_fromregion(newrdata, rdata.rdclass,
- rdata.type, &r);
- newrdata->flags = rdata.flags;
-
- ISC_LIST_APPEND(rdatalist->rdata, newrdata, link);
- dns_message_takebuffer(msg, &rdatabuf);
-
- result = dns_rdataset_next(rdataset);
- }
-
- newrdataset = NULL;
- result = dns_message_gettemprdataset(msg, &newrdataset);
- if (result != ISC_R_SUCCESS)
- goto fail;
- dns_rdataset_init(newrdataset);
- dns_rdatalist_tordataset(rdatalist, newrdataset);
-
- ISC_LIST_APPEND(newname->list, newrdataset, link);
- }
-
- *newnamep = newname;
-
- return (ISC_R_SUCCESS);
-
- fail:
- dns_message_puttempname(msg, &newname);
-
- return (result);
-
-}
-
-static void
-internal_update_callback(isc_task_t *task, isc_event_t *event) {
- updatearg_t *uarg = event->ev_arg;
- dns_clientupdateevent_t *uev = (dns_clientupdateevent_t *)event;
-
- UNUSED(task);
-
- LOCK(&uarg->lock);
-
- uarg->result = uev->result;
-
- dns_client_destroyupdatetrans(&uarg->trans);
- isc_event_free(&event);
-
- if (!uarg->canceled) {
- UNLOCK(&uarg->lock);
-
- /* Exit from the internal event loop */
- isc_app_ctxsuspend(uarg->actx);
- } else {
- /*
- * We have already exited from the loop (due to some
- * unexpected event). Just clean the arg up.
- */
- UNLOCK(&uarg->lock);
- DESTROYLOCK(&uarg->lock);
- isc_mem_put(uarg->client->mctx, uarg, sizeof(*uarg));
- }
-}
-
-isc_result_t
-dns_client_update(dns_client_t *client, dns_rdataclass_t rdclass,
- dns_name_t *zonename, dns_namelist_t *prerequisites,
- dns_namelist_t *updates, isc_sockaddrlist_t *servers,
- dns_tsec_t *tsec, unsigned int options)
-{
- isc_result_t result;
- isc_appctx_t *actx;
- updatearg_t *uarg;
-
- REQUIRE(DNS_CLIENT_VALID(client));
-
- if ((client->attributes & DNS_CLIENTATTR_OWNCTX) == 0 &&
- (options & DNS_CLIENTRESOPT_ALLOWRUN) == 0) {
- /*
- * If the client is run under application's control, we need
- * to create a new running (sub)environment for this
- * particular resolution.
- */
- return (ISC_R_NOTIMPLEMENTED); /* XXXTBD */
- } else
- actx = client->actx;
-
- uarg = isc_mem_get(client->mctx, sizeof(*uarg));
- if (uarg == NULL)
- return (ISC_R_NOMEMORY);
-
- result = isc_mutex_init(&uarg->lock);
- if (result != ISC_R_SUCCESS) {
- isc_mem_put(client->mctx, uarg, sizeof(*uarg));
- return (result);
- }
-
- uarg->actx = actx;
- uarg->client = client;
- uarg->result = ISC_R_FAILURE;
- uarg->trans = NULL;
- uarg->canceled = ISC_FALSE;
-
- result = dns_client_startupdate(client, rdclass, zonename,
- prerequisites, updates, servers,
- tsec, options, client->task,
- internal_update_callback, uarg,
- &uarg->trans);
- if (result != ISC_R_SUCCESS) {
- DESTROYLOCK(&uarg->lock);
- isc_mem_put(client->mctx, uarg, sizeof(*uarg));
- return (result);
- }
-
- /*
- * Start internal event loop. It blocks until the entire process
- * is completed.
- */
- result = isc_app_ctxrun(actx);
-
- LOCK(&uarg->lock);
- if (result == ISC_R_SUCCESS || result == ISC_R_SUSPEND)
- result = uarg->result;
-
- if (uarg->trans != NULL) {
- /*
- * Unusual termination (perhaps due to signal). We need some
- * tricky cleanup process.
- */
- uarg->canceled = ISC_TRUE;
- dns_client_cancelupdate(uarg->trans);
-
- UNLOCK(&uarg->lock);
-
- /* uarg will be freed in the event handler. */
- } else {
- UNLOCK(&uarg->lock);
-
- DESTROYLOCK(&uarg->lock);
- isc_mem_put(client->mctx, uarg, sizeof(*uarg));
- }
-
- return (result);
-}
-
-isc_result_t
-dns_client_startupdate(dns_client_t *client, dns_rdataclass_t rdclass,
- dns_name_t *zonename, dns_namelist_t *prerequisites,
- dns_namelist_t *updates, isc_sockaddrlist_t *servers,
- dns_tsec_t *tsec, unsigned int options,
- isc_task_t *task, isc_taskaction_t action, void *arg,
- dns_clientupdatetrans_t **transp)
-{
- dns_view_t *view = NULL;
- isc_result_t result;
- dns_name_t *name, *newname;
- updatectx_t *uctx;
- isc_task_t *clone = NULL;
- dns_section_t section = DNS_SECTION_UPDATE;
- isc_sockaddr_t *server, *sa = NULL;
- dns_tsectype_t tsectype = dns_tsectype_none;
-
- UNUSED(options);
-
- REQUIRE(DNS_CLIENT_VALID(client));
- REQUIRE(transp != NULL && *transp == NULL);
- REQUIRE(updates != NULL);
- REQUIRE(task != NULL);
-
- if (tsec != NULL) {
- tsectype = dns_tsec_gettype(tsec);
- if (tsectype != dns_tsectype_tsig)
- return (ISC_R_NOTIMPLEMENTED); /* XXX */
- }
-
- LOCK(&client->lock);
- result = dns_viewlist_find(&client->viewlist, DNS_CLIENTVIEW_NAME,
- rdclass, &view);
- UNLOCK(&client->lock);
- if (result != ISC_R_SUCCESS)
- return (result);
-
- /* Create a context and prepare some resources */
- uctx = isc_mem_get(client->mctx, sizeof(*uctx));
- if (uctx == NULL) {
- dns_view_detach(&view);
- return (ISC_R_NOMEMORY);
- }
- result = isc_mutex_init(&uctx->lock);
- if (result != ISC_R_SUCCESS) {
- dns_view_detach(&view);
- isc_mem_put(client->mctx, uctx, sizeof(*uctx));
- return (ISC_R_NOMEMORY);
- }
- clone = NULL;
- isc_task_attach(task, &clone);
- uctx->client = client;
- ISC_LINK_INIT(uctx, link);
- uctx->state = dns_clientupdatestate_prepare;
- uctx->view = view;
- uctx->rdclass = rdclass;
- uctx->canceled = ISC_FALSE;
- uctx->updatemsg = NULL;
- uctx->soaquery = NULL;
- uctx->updatereq = NULL;
- uctx->restrans = NULL;
- uctx->restrans2 = NULL;
- uctx->bp4 = NULL;
- uctx->bp6 = NULL;
- uctx->soareq = NULL;
- uctx->event = NULL;
- uctx->tsigkey = NULL;
- uctx->sig0key = NULL;
- uctx->zonename = NULL;
- dns_name_init(&uctx->soaqname, NULL);
- ISC_LIST_INIT(uctx->servers);
- uctx->nservers = 0;
- uctx->currentserver = NULL;
- dns_fixedname_init(&uctx->zonefname);
- if (tsec != NULL)
- dns_tsec_getkey(tsec, &uctx->tsigkey);
- uctx->event = (dns_clientupdateevent_t *)
- isc_event_allocate(client->mctx, clone, DNS_EVENT_UPDATEDONE,
- action, arg, sizeof(*uctx->event));
- if (uctx->event == NULL)
- goto fail;
- if (zonename != NULL) {
- uctx->zonename = dns_fixedname_name(&uctx->zonefname);
- result = dns_name_copy(zonename, uctx->zonename, NULL);
- }
- if (servers != NULL) {
- for (server = ISC_LIST_HEAD(*servers);
- server != NULL;
- server = ISC_LIST_NEXT(server, link)) {
- sa = isc_mem_get(client->mctx, sizeof(*sa));
- if (sa == NULL)
- goto fail;
- sa->type = server->type;
- sa->length = server->length;
- ISC_LINK_INIT(sa, link);
- ISC_LIST_APPEND(uctx->servers, sa, link);
- if (uctx->currentserver == NULL)
- uctx->currentserver = sa;
- uctx->nservers++;
- }
- }
-
- /* Make update message */
- result = dns_message_create(client->mctx, DNS_MESSAGE_INTENTRENDER,
- &uctx->updatemsg);
- if (result != ISC_R_SUCCESS)
- goto fail;
- uctx->updatemsg->opcode = dns_opcode_update;
-
- if (prerequisites != NULL) {
- for (name = ISC_LIST_HEAD(*prerequisites); name != NULL;
- name = ISC_LIST_NEXT(name, link)) {
- newname = NULL;
- result = copy_name(client->mctx, uctx->updatemsg,
- name, &newname);
- if (result != ISC_R_SUCCESS)
- goto fail;
- dns_message_addname(uctx->updatemsg, newname,
- DNS_SECTION_PREREQUISITE);
- }
- }
-
- for (name = ISC_LIST_HEAD(*updates); name != NULL;
- name = ISC_LIST_NEXT(name, link)) {
- newname = NULL;
- result = copy_name(client->mctx, uctx->updatemsg, name,
- &newname);
- if (result != ISC_R_SUCCESS)
- goto fail;
- dns_message_addname(uctx->updatemsg, newname,
- DNS_SECTION_UPDATE);
- }
-
- uctx->firstname = NULL;
- result = dns_message_firstname(uctx->updatemsg, section);
- if (result == ISC_R_NOMORE) {
- section = DNS_SECTION_PREREQUISITE;
- result = dns_message_firstname(uctx->updatemsg, section);
- }
- if (result != ISC_R_SUCCESS)
- goto fail;
- dns_message_currentname(uctx->updatemsg, section, &uctx->firstname);
-
- uctx->magic = UCTX_MAGIC;
-
- LOCK(&client->lock);
- ISC_LIST_APPEND(client->updatectxs, uctx, link);
- UNLOCK(&client->lock);
-
- if (uctx->zonename != NULL && uctx->currentserver != NULL) {
- result = send_update(uctx);
- if (result != ISC_R_SUCCESS)
- goto fail;
- } else if (uctx->currentserver != NULL) {
- result = request_soa(uctx);
- if (result != ISC_R_SUCCESS)
- goto fail;
- } else {
- dns_name_clone(uctx->firstname, &uctx->soaqname);
- result = dns_client_startresolve(uctx->client, &uctx->soaqname,
- uctx->rdclass,
- dns_rdatatype_soa, 0,
- client->task, resolvesoa_done,
- uctx, &uctx->restrans);
- if (result != ISC_R_SUCCESS)
- goto fail;
- }
-
- *transp = (dns_clientupdatetrans_t *)uctx;
-
- return (ISC_R_SUCCESS);
-
- fail:
- if (ISC_LINK_LINKED(uctx, link)) {
- LOCK(&client->lock);
- ISC_LIST_UNLINK(client->updatectxs, uctx, link);
- UNLOCK(&client->lock);
- }
- if (uctx->updatemsg != NULL)
- dns_message_destroy(&uctx->updatemsg);
- while ((sa = ISC_LIST_HEAD(uctx->servers)) != NULL) {
- ISC_LIST_UNLINK(uctx->servers, sa, link);
- isc_mem_put(client->mctx, sa, sizeof(*sa));
- }
- if (uctx->event != NULL)
- isc_event_free(ISC_EVENT_PTR(&uctx->event));
- if (uctx->tsigkey != NULL)
- dns_tsigkey_detach(&uctx->tsigkey);
- isc_task_detach(&clone);
- DESTROYLOCK(&uctx->lock);
- uctx->magic = 0;
- isc_mem_put(client->mctx, uctx, sizeof(*uctx));
- dns_view_detach(&view);
-
- return (result);
-}
-
-void
-dns_client_cancelupdate(dns_clientupdatetrans_t *trans) {
- updatectx_t *uctx;
-
- REQUIRE(trans != NULL);
- uctx = (updatectx_t *)trans;
- REQUIRE(UCTX_VALID(uctx));
-
- LOCK(&uctx->lock);
-
- if (!uctx->canceled) {
- uctx->canceled = ISC_TRUE;
- if (uctx->updatereq != NULL)
- dns_request_cancel(uctx->updatereq);
- if (uctx->soareq != NULL)
- dns_request_cancel(uctx->soareq);
- if (uctx->restrans != NULL)
- dns_client_cancelresolve(uctx->restrans);
- if (uctx->restrans2 != NULL)
- dns_client_cancelresolve(uctx->restrans2);
- }
-
- UNLOCK(&uctx->lock);
-}
-
-void
-dns_client_destroyupdatetrans(dns_clientupdatetrans_t **transp) {
- updatectx_t *uctx;
- isc_mem_t *mctx;
- dns_client_t *client;
- isc_boolean_t need_destroyclient = ISC_FALSE;
- isc_sockaddr_t *sa;
-
- REQUIRE(transp != NULL);
- uctx = (updatectx_t *)*transp;
- REQUIRE(UCTX_VALID(uctx));
- client = uctx->client;
- REQUIRE(DNS_CLIENT_VALID(client));
- REQUIRE(uctx->updatereq == NULL && uctx->updatemsg == NULL &&
- uctx->soareq == NULL && uctx->soaquery == NULL &&
- uctx->event == NULL && uctx->tsigkey == NULL &&
- uctx->sig0key == NULL);
-
- mctx = client->mctx;
- dns_view_detach(&uctx->view);
- while ((sa = ISC_LIST_HEAD(uctx->servers)) != NULL) {
- ISC_LIST_UNLINK(uctx->servers, sa, link);
- isc_mem_put(mctx, sa, sizeof(*sa));
- }
-
- LOCK(&client->lock);
-
- INSIST(ISC_LINK_LINKED(uctx, link));
- ISC_LIST_UNLINK(client->updatectxs, uctx, link);
-
- if (client->references == 0 && ISC_LIST_EMPTY(client->resctxs) &&
- ISC_LIST_EMPTY(client->reqctxs) &&
- ISC_LIST_EMPTY(client->updatectxs))
- need_destroyclient = ISC_TRUE;
-
- UNLOCK(&client->lock);
-
- DESTROYLOCK(&uctx->lock);
- uctx->magic = 0;
-
- isc_mem_put(mctx, uctx, sizeof(*uctx));
-
- if (need_destroyclient)
- destroyclient(&client);
-
- *transp = NULL;
-}
-
-isc_mem_t *
-dns_client_mctx(dns_client_t *client) {
-
- REQUIRE(DNS_CLIENT_VALID(client));
- return (client->mctx);
-}
-
-typedef struct {
- isc_buffer_t buffer;
- dns_rdataset_t rdataset;
- dns_rdatalist_t rdatalist;
- dns_rdata_t rdata;
- size_t size;
- isc_mem_t * mctx;
- unsigned char data[FLEXIBLE_ARRAY_MEMBER];
-} dns_client_updaterec_t;
-
-isc_result_t
-dns_client_updaterec(dns_client_updateop_t op, dns_name_t *owner,
- dns_rdatatype_t type, dns_rdata_t *source,
- dns_ttl_t ttl, dns_name_t *target,
- dns_rdataset_t *rdataset, dns_rdatalist_t *rdatalist,
- dns_rdata_t *rdata, isc_mem_t *mctx)
-{
- dns_client_updaterec_t *updaterec = NULL;
- size_t size = offsetof(dns_client_updaterec_t, data);
-
- REQUIRE(op < updateop_max);
- REQUIRE(owner != NULL);
- REQUIRE((rdataset != NULL && rdatalist != NULL && rdata != NULL) ||
- (rdataset == NULL && rdatalist == NULL && rdata == NULL &&
- mctx != NULL));
- if (op == updateop_add)
- REQUIRE(source != NULL);
- if (source != NULL) {
- REQUIRE(source->type == type);
- REQUIRE(op == updateop_add || op == updateop_delete ||
- op == updateop_exist);
- }
-
- size += owner->length;
- if (source != NULL)
- size += source->length;
-
- if (rdataset == NULL) {
- updaterec = isc_mem_get(mctx, size);
- if (updaterec == NULL)
- return (ISC_R_NOMEMORY);
- rdataset = &updaterec->rdataset;
- rdatalist = &updaterec->rdatalist;
- rdata = &updaterec->rdata;
- dns_rdataset_init(rdataset);
- dns_rdatalist_init(&updaterec->rdatalist);
- dns_rdata_init(&updaterec->rdata);
- isc_buffer_init(&updaterec->buffer, updaterec->data,
- size - offsetof(dns_client_updaterec_t, data));
- dns_name_copy(owner, target, &updaterec->buffer);
- if (source != NULL) {
- isc_region_t r;
- dns_rdata_clone(source, rdata);
- dns_rdata_toregion(rdata, &r);
- rdata->data = isc_buffer_used(&updaterec->buffer);
- isc_buffer_copyregion(&updaterec->buffer, &r);
- }
- updaterec->mctx = NULL;
- isc_mem_attach(mctx, &updaterec->mctx);
- } else if (source != NULL)
- dns_rdata_clone(source, rdata);
-
- switch (op) {
- case updateop_add:
- break;
- case updateop_delete:
- if (source != NULL) {
- ttl = 0;
- dns_rdata_makedelete(rdata);
- } else
- dns_rdata_deleterrset(rdata, type);
- break;
- case updateop_notexist:
- dns_rdata_notexist(rdata, type);
- break;
- case updateop_exist:
- if (source == NULL) {
- ttl = 0;
- dns_rdata_exists(rdata, type);
- }
- case updateop_none:
- break;
- default:
- INSIST(0);
- }
-
- rdatalist->type = rdata->type;
- rdatalist->rdclass = rdata->rdclass;
- if (source != NULL) {
- rdatalist->covers = dns_rdata_covers(rdata);
- rdatalist->ttl = ttl;
- }
- ISC_LIST_APPEND(rdatalist->rdata, rdata, link);
- dns_rdatalist_tordataset(rdatalist, rdataset);
- ISC_LIST_APPEND(target->list, rdataset, link);
- if (updaterec != NULL) {
- target->attributes |= DNS_NAMEATTR_HASUPDATEREC;
- dns_name_setbuffer(target, &updaterec->buffer);
- }
- if (op == updateop_add || op == updateop_delete)
- target->attributes |= DNS_NAMEATTR_UPDATE;
- else
- target->attributes |= DNS_NAMEATTR_PREREQUISITE;
- return (ISC_R_SUCCESS);
-}
-
-void
-dns_client_freeupdate(dns_name_t **namep) {
- dns_client_updaterec_t *updaterec;
- dns_rdatalist_t *rdatalist;
- dns_rdataset_t *rdataset;
- dns_rdata_t *rdata;
- dns_name_t *name;
-
- REQUIRE(namep != NULL && *namep != NULL);
-
- name = *namep;
- for (rdataset = ISC_LIST_HEAD(name->list);
- rdataset != NULL;
- rdataset = ISC_LIST_HEAD(name->list)) {
- ISC_LIST_UNLINK(name->list, rdataset, link);
- rdatalist = NULL;
- dns_rdatalist_fromrdataset(rdataset, &rdatalist);
- if (rdatalist == NULL) {
- dns_rdataset_disassociate(rdataset);
- continue;
- }
- for (rdata = ISC_LIST_HEAD(rdatalist->rdata);
- rdata != NULL;
- rdata = ISC_LIST_HEAD(rdatalist->rdata))
- ISC_LIST_UNLINK(rdatalist->rdata, rdata, link);
- dns_rdataset_disassociate(rdataset);
- }
-
- if ((name->attributes & DNS_NAMEATTR_HASUPDATEREC) != 0) {
- updaterec = (dns_client_updaterec_t *)name->buffer;
- INSIST(updaterec != NULL);
- isc_mem_putanddetach(&updaterec->mctx, updaterec,
- updaterec->size);
- *namep = NULL;
- }
-}
OpenPOWER on IntegriCloud