client.c revision 0618287859d99c2fc69790df28500fb37324d43d
cefd68008fbba3488a077052ae62aa12b6de502bMichael Sawyer/*
cefd68008fbba3488a077052ae62aa12b6de502bMichael Sawyer * Copyright (C) 2009-2013 Internet Systems Consortium, Inc. ("ISC")
40f53fa8d9c6a4fc38c0014495e7a42b08f52481David Lawrence *
cefd68008fbba3488a077052ae62aa12b6de502bMichael Sawyer * Permission to use, copy, modify, and/or distribute this software for any
cefd68008fbba3488a077052ae62aa12b6de502bMichael Sawyer * purpose with or without fee is hereby granted, provided that the above
cefd68008fbba3488a077052ae62aa12b6de502bMichael Sawyer * copyright notice and this permission notice appear in all copies.
40f53fa8d9c6a4fc38c0014495e7a42b08f52481David Lawrence *
15a44745412679c30a6d022733925af70a38b715David Lawrence * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
15a44745412679c30a6d022733925af70a38b715David Lawrence * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
15a44745412679c30a6d022733925af70a38b715David Lawrence * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
15a44745412679c30a6d022733925af70a38b715David Lawrence * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
15a44745412679c30a6d022733925af70a38b715David Lawrence * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
15a44745412679c30a6d022733925af70a38b715David Lawrence * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
15a44745412679c30a6d022733925af70a38b715David Lawrence * PERFORMANCE OF THIS SOFTWARE.
15a44745412679c30a6d022733925af70a38b715David Lawrence */
cefd68008fbba3488a077052ae62aa12b6de502bMichael Sawyer
cefd68008fbba3488a077052ae62aa12b6de502bMichael Sawyer/* $Id: client.c,v 1.14 2011/03/12 04:59:47 tbox Exp $ */
b266f8fc42702debc6bd89365273223fa89cd8ddBrian Wellington
47058d17266420179fa294de6b82d8fb5b918df4Michael Sawyer#include <config.h>
cefd68008fbba3488a077052ae62aa12b6de502bMichael Sawyer
cefd68008fbba3488a077052ae62aa12b6de502bMichael Sawyer#include <stddef.h>
cefd68008fbba3488a077052ae62aa12b6de502bMichael Sawyer
cefd68008fbba3488a077052ae62aa12b6de502bMichael Sawyer#include <isc/app.h>
cefd68008fbba3488a077052ae62aa12b6de502bMichael Sawyer#include <isc/mem.h>
cefd68008fbba3488a077052ae62aa12b6de502bMichael Sawyer#include <isc/mutex.h>
c9defbf4b968e8a61f391246431ac63d0d6a39abMichael Sawyer#include <isc/sockaddr.h>
c9defbf4b968e8a61f391246431ac63d0d6a39abMichael Sawyer#include <isc/socket.h>
c9defbf4b968e8a61f391246431ac63d0d6a39abMichael Sawyer#include <isc/task.h>
b266f8fc42702debc6bd89365273223fa89cd8ddBrian Wellington#include <isc/timer.h>
c9defbf4b968e8a61f391246431ac63d0d6a39abMichael Sawyer#include <isc/util.h>
c9defbf4b968e8a61f391246431ac63d0d6a39abMichael Sawyer
c9defbf4b968e8a61f391246431ac63d0d6a39abMichael Sawyer#include <dns/adb.h>
1893b56ef9f5f2bc2a0fbe80d3c6b69df1bdc7c2Michael Sawyer#include <dns/client.h>
cefd68008fbba3488a077052ae62aa12b6de502bMichael Sawyer#include <dns/db.h>
aa6054ec74819f754bcf19442ca9b39d948171adMichael Sawyer#include <dns/dispatch.h>
aa6054ec74819f754bcf19442ca9b39d948171adMichael Sawyer#include <dns/events.h>
aa6054ec74819f754bcf19442ca9b39d948171adMichael Sawyer#include <dns/forward.h>
aa6054ec74819f754bcf19442ca9b39d948171adMichael Sawyer#include <dns/keytable.h>
aa6054ec74819f754bcf19442ca9b39d948171adMichael Sawyer#include <dns/message.h>
aa6054ec74819f754bcf19442ca9b39d948171adMichael Sawyer#include <dns/name.h>
aa6054ec74819f754bcf19442ca9b39d948171adMichael Sawyer#include <dns/rdata.h>
cefd68008fbba3488a077052ae62aa12b6de502bMichael Sawyer#include <dns/rdatalist.h>
cefd68008fbba3488a077052ae62aa12b6de502bMichael Sawyer#include <dns/rdataset.h>
cefd68008fbba3488a077052ae62aa12b6de502bMichael Sawyer#include <dns/rdatatype.h>
cefd68008fbba3488a077052ae62aa12b6de502bMichael Sawyer#include <dns/rdatasetiter.h>
cefd68008fbba3488a077052ae62aa12b6de502bMichael Sawyer#include <dns/rdatastruct.h>
cefd68008fbba3488a077052ae62aa12b6de502bMichael Sawyer#include <dns/request.h>
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer#include <dns/resolver.h>
d821f1cd7e97552401296e880e7518c98c9ebea1Michael Sawyer#include <dns/result.h>
cefd68008fbba3488a077052ae62aa12b6de502bMichael Sawyer#include <dns/tsec.h>
cefd68008fbba3488a077052ae62aa12b6de502bMichael Sawyer#include <dns/tsig.h>
cefd68008fbba3488a077052ae62aa12b6de502bMichael Sawyer#include <dns/view.h>
cefd68008fbba3488a077052ae62aa12b6de502bMichael Sawyer
cefd68008fbba3488a077052ae62aa12b6de502bMichael Sawyer#include <dst/dst.h>
cefd68008fbba3488a077052ae62aa12b6de502bMichael Sawyer
cefd68008fbba3488a077052ae62aa12b6de502bMichael Sawyer#define DNS_CLIENT_MAGIC ISC_MAGIC('D', 'N', 'S', 'c')
cefd68008fbba3488a077052ae62aa12b6de502bMichael Sawyer#define DNS_CLIENT_VALID(c) ISC_MAGIC_VALID(c, DNS_CLIENT_MAGIC)
cefd68008fbba3488a077052ae62aa12b6de502bMichael Sawyer
cefd68008fbba3488a077052ae62aa12b6de502bMichael Sawyer#define RCTX_MAGIC ISC_MAGIC('R', 'c', 't', 'x')
cefd68008fbba3488a077052ae62aa12b6de502bMichael Sawyer#define RCTX_VALID(c) ISC_MAGIC_VALID(c, RCTX_MAGIC)
cefd68008fbba3488a077052ae62aa12b6de502bMichael Sawyer
1893b56ef9f5f2bc2a0fbe80d3c6b69df1bdc7c2Michael Sawyer#define REQCTX_MAGIC ISC_MAGIC('R', 'q', 'c', 'x')
b266f8fc42702debc6bd89365273223fa89cd8ddBrian Wellington#define REQCTX_VALID(c) ISC_MAGIC_VALID(c, REQCTX_MAGIC)
38cf6e52ce4b33795713388824b69d78e430b115Michael Sawyer
cefd68008fbba3488a077052ae62aa12b6de502bMichael Sawyer#define UCTX_MAGIC ISC_MAGIC('U', 'c', 't', 'x')
844eaa56d6d647b38b2a5cf08f7ea5ab7b752690Michael Sawyer#define UCTX_VALID(c) ISC_MAGIC_VALID(c, UCTX_MAGIC)
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer
6c6a62933dda281cb9193de1d54d4c9e74515f5aMichael Sawyer#define MAX_RESTARTS 16
cefd68008fbba3488a077052ae62aa12b6de502bMichael Sawyer
cefd68008fbba3488a077052ae62aa12b6de502bMichael Sawyer/*%
cefd68008fbba3488a077052ae62aa12b6de502bMichael Sawyer * DNS client object
cefd68008fbba3488a077052ae62aa12b6de502bMichael Sawyer */
cefd68008fbba3488a077052ae62aa12b6de502bMichael Sawyerstruct dns_client {
cefd68008fbba3488a077052ae62aa12b6de502bMichael Sawyer /* Unlocked */
cefd68008fbba3488a077052ae62aa12b6de502bMichael Sawyer unsigned int magic;
cefd68008fbba3488a077052ae62aa12b6de502bMichael Sawyer unsigned int attributes;
cefd68008fbba3488a077052ae62aa12b6de502bMichael Sawyer isc_mutex_t lock;
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer isc_mem_t *mctx;
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer isc_appctx_t *actx;
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer isc_taskmgr_t *taskmgr;
b266f8fc42702debc6bd89365273223fa89cd8ddBrian Wellington isc_task_t *task;
cefd68008fbba3488a077052ae62aa12b6de502bMichael Sawyer isc_socketmgr_t *socketmgr;
a5ed46c9fd270775c39770bfd0250a52d374ebf2Michael Sawyer isc_timermgr_t *timermgr;
cefd68008fbba3488a077052ae62aa12b6de502bMichael Sawyer dns_dispatchmgr_t *dispatchmgr;
cefd68008fbba3488a077052ae62aa12b6de502bMichael Sawyer dns_dispatch_t *dispatchv4;
cefd68008fbba3488a077052ae62aa12b6de502bMichael Sawyer dns_dispatch_t *dispatchv6;
cefd68008fbba3488a077052ae62aa12b6de502bMichael Sawyer
cefd68008fbba3488a077052ae62aa12b6de502bMichael Sawyer unsigned int update_timeout;
cefd68008fbba3488a077052ae62aa12b6de502bMichael Sawyer unsigned int update_udptimeout;
cefd68008fbba3488a077052ae62aa12b6de502bMichael Sawyer unsigned int update_udpretries;
cefd68008fbba3488a077052ae62aa12b6de502bMichael Sawyer unsigned int find_timeout;
cefd68008fbba3488a077052ae62aa12b6de502bMichael Sawyer unsigned int find_udpretries;
cefd68008fbba3488a077052ae62aa12b6de502bMichael Sawyer
cefd68008fbba3488a077052ae62aa12b6de502bMichael Sawyer /* Locked */
cefd68008fbba3488a077052ae62aa12b6de502bMichael Sawyer unsigned int references;
cefd68008fbba3488a077052ae62aa12b6de502bMichael Sawyer dns_viewlist_t viewlist;
cefd68008fbba3488a077052ae62aa12b6de502bMichael Sawyer ISC_LIST(struct resctx) resctxs;
cefd68008fbba3488a077052ae62aa12b6de502bMichael Sawyer ISC_LIST(struct reqctx) reqctxs;
cefd68008fbba3488a077052ae62aa12b6de502bMichael Sawyer ISC_LIST(struct updatectx) updatectxs;
cefd68008fbba3488a077052ae62aa12b6de502bMichael Sawyer};
cefd68008fbba3488a077052ae62aa12b6de502bMichael Sawyer
cefd68008fbba3488a077052ae62aa12b6de502bMichael Sawyer/*%
a5ed46c9fd270775c39770bfd0250a52d374ebf2Michael Sawyer * Timeout/retry constants for dynamic update borrowed from nsupdate
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer */
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer#define DEF_UPDATE_TIMEOUT 300
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer#define MIN_UPDATE_TIMEOUT 30
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer#define DEF_UPDATE_UDPTIMEOUT 3
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer#define DEF_UPDATE_UDPRETRIES 3
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer#define DEF_FIND_TIMEOUT 5
40f53fa8d9c6a4fc38c0014495e7a42b08f52481David Lawrence#define DEF_FIND_UDPRETRIES 3
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer#define DNS_CLIENTATTR_OWNCTX 0x01
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer#define DNS_CLIENTVIEW_NAME "dnsclient"
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer/*%
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer * Internal state for a single name resolution procedure
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer */
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyertypedef struct resctx {
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer /* Unlocked */
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer unsigned int magic;
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer isc_mutex_t lock;
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer dns_client_t *client;
e32394a2ac3466a2235f79ee32c247a11be42a8dAndreas Gustafsson isc_boolean_t want_dnssec;
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer /* Locked */
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer ISC_LINK(struct resctx) link;
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer isc_task_t *task;
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer dns_view_t *view;
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer unsigned int restarts;
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer dns_fixedname_t name;
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer dns_rdatatype_t type;
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer dns_fetch_t *fetch;
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer dns_namelist_t namelist;
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer isc_result_t result;
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer dns_clientresevent_t *event;
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer isc_boolean_t canceled;
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer dns_rdataset_t *rdataset;
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer dns_rdataset_t *sigrdataset;
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer} resctx_t;
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer/*%
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer * Argument of an internal event for synchronous name resolution.
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer */
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyertypedef struct resarg {
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer /* Unlocked */
b266f8fc42702debc6bd89365273223fa89cd8ddBrian Wellington isc_appctx_t *actx;
b266f8fc42702debc6bd89365273223fa89cd8ddBrian Wellington dns_client_t *client;
b266f8fc42702debc6bd89365273223fa89cd8ddBrian Wellington isc_mutex_t lock;
cefd68008fbba3488a077052ae62aa12b6de502bMichael Sawyer
cd720113a2fc8a781d4e33350b8a2b62857b31d8David Lawrence /* Locked */
37e6e0ca1337351642798b1a6aa24ae40bf86399Andreas Gustafsson isc_result_t result;
40f53fa8d9c6a4fc38c0014495e7a42b08f52481David Lawrence isc_result_t vresult;
cefd68008fbba3488a077052ae62aa12b6de502bMichael Sawyer dns_namelist_t *namelist;
cefd68008fbba3488a077052ae62aa12b6de502bMichael Sawyer dns_clientrestrans_t *trans;
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer isc_boolean_t canceled;
b266f8fc42702debc6bd89365273223fa89cd8ddBrian Wellington} resarg_t;
b266f8fc42702debc6bd89365273223fa89cd8ddBrian Wellington
b266f8fc42702debc6bd89365273223fa89cd8ddBrian Wellington/*%
cc48bb397fa6ba889f25157840492e68114dec8fBrian Wellington * Internal state for a single DNS request
b266f8fc42702debc6bd89365273223fa89cd8ddBrian Wellington */
b266f8fc42702debc6bd89365273223fa89cd8ddBrian Wellingtontypedef struct reqctx {
b266f8fc42702debc6bd89365273223fa89cd8ddBrian Wellington /* Unlocked */
b266f8fc42702debc6bd89365273223fa89cd8ddBrian Wellington unsigned int magic;
b266f8fc42702debc6bd89365273223fa89cd8ddBrian Wellington isc_mutex_t lock;
b266f8fc42702debc6bd89365273223fa89cd8ddBrian Wellington dns_client_t *client;
b266f8fc42702debc6bd89365273223fa89cd8ddBrian Wellington unsigned int parseoptions;
cefd68008fbba3488a077052ae62aa12b6de502bMichael Sawyer
cc48bb397fa6ba889f25157840492e68114dec8fBrian Wellington /* Locked */
cefd68008fbba3488a077052ae62aa12b6de502bMichael Sawyer ISC_LINK(struct reqctx) link;
cefd68008fbba3488a077052ae62aa12b6de502bMichael Sawyer isc_boolean_t canceled;
37e6e0ca1337351642798b1a6aa24ae40bf86399Andreas Gustafsson dns_tsigkey_t *tsigkey;
37e6e0ca1337351642798b1a6aa24ae40bf86399Andreas Gustafsson dns_request_t *request;
37e6e0ca1337351642798b1a6aa24ae40bf86399Andreas Gustafsson dns_clientreqevent_t *event;
37e6e0ca1337351642798b1a6aa24ae40bf86399Andreas Gustafsson} reqctx_t;
cefd68008fbba3488a077052ae62aa12b6de502bMichael Sawyer
cefd68008fbba3488a077052ae62aa12b6de502bMichael Sawyer/*%
cefd68008fbba3488a077052ae62aa12b6de502bMichael Sawyer * Argument of an internal event for synchronous DNS request.
cefd68008fbba3488a077052ae62aa12b6de502bMichael Sawyer */
37e6e0ca1337351642798b1a6aa24ae40bf86399Andreas Gustafssontypedef struct reqarg {
37e6e0ca1337351642798b1a6aa24ae40bf86399Andreas Gustafsson /* Unlocked */
37e6e0ca1337351642798b1a6aa24ae40bf86399Andreas Gustafsson isc_appctx_t *actx;
cefd68008fbba3488a077052ae62aa12b6de502bMichael Sawyer dns_client_t *client;
cefd68008fbba3488a077052ae62aa12b6de502bMichael Sawyer isc_mutex_t lock;
cefd68008fbba3488a077052ae62aa12b6de502bMichael Sawyer
cefd68008fbba3488a077052ae62aa12b6de502bMichael Sawyer /* Locked */
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer isc_result_t result;
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer dns_clientreqtrans_t *trans;
cefd68008fbba3488a077052ae62aa12b6de502bMichael Sawyer isc_boolean_t canceled;
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer} reqarg_t;
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer/*%
cefd68008fbba3488a077052ae62aa12b6de502bMichael Sawyer * Argument of an internal event for synchronous name resolution.
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer */
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyertypedef struct updatearg {
37e6e0ca1337351642798b1a6aa24ae40bf86399Andreas Gustafsson /* Unlocked */
37e6e0ca1337351642798b1a6aa24ae40bf86399Andreas Gustafsson isc_appctx_t *actx;
cefd68008fbba3488a077052ae62aa12b6de502bMichael Sawyer dns_client_t *client;
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer isc_mutex_t lock;
cefd68008fbba3488a077052ae62aa12b6de502bMichael Sawyer
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer /* Locked */
cefd68008fbba3488a077052ae62aa12b6de502bMichael Sawyer isc_result_t result;
cefd68008fbba3488a077052ae62aa12b6de502bMichael Sawyer dns_clientupdatetrans_t *trans;
cefd68008fbba3488a077052ae62aa12b6de502bMichael Sawyer isc_boolean_t canceled;
cefd68008fbba3488a077052ae62aa12b6de502bMichael Sawyer} updatearg_t;
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer/*%
cefd68008fbba3488a077052ae62aa12b6de502bMichael Sawyer * Internal state for a single dynamic update procedure
cefd68008fbba3488a077052ae62aa12b6de502bMichael Sawyer */
40f53fa8d9c6a4fc38c0014495e7a42b08f52481David Lawrencetypedef struct updatectx {
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer /* Unlocked */
cefd68008fbba3488a077052ae62aa12b6de502bMichael Sawyer unsigned int magic;
cefd68008fbba3488a077052ae62aa12b6de502bMichael Sawyer isc_mutex_t lock;
cefd68008fbba3488a077052ae62aa12b6de502bMichael Sawyer dns_client_t *client;
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer /* Locked */
37e6e0ca1337351642798b1a6aa24ae40bf86399Andreas Gustafsson dns_request_t *updatereq;
37e6e0ca1337351642798b1a6aa24ae40bf86399Andreas Gustafsson dns_request_t *soareq;
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer dns_clientrestrans_t *restrans;
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer dns_clientrestrans_t *restrans2;
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer isc_boolean_t canceled;
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer /* Task Locked */
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer ISC_LINK(struct updatectx) link;
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer dns_clientupdatestate_t state;
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer dns_rdataclass_t rdclass;
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer dns_view_t *view;
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer dns_message_t *updatemsg;
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer dns_message_t *soaquery;
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer dns_clientupdateevent_t *event;
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer dns_tsigkey_t *tsigkey;
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer dst_key_t *sig0key;
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer dns_name_t *firstname;
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer dns_name_t soaqname;
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer dns_fixedname_t zonefname;
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer dns_name_t *zonename;
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer isc_sockaddrlist_t servers;
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer unsigned int nservers;
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer isc_sockaddr_t *currentserver;
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer struct updatectx *bp4;
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer struct updatectx *bp6;
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer} updatectx_t;
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyerstatic isc_result_t request_soa(updatectx_t *uctx);
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyerstatic void client_resfind(resctx_t *rctx, dns_fetchevent_t *event);
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyerstatic isc_result_t send_update(updatectx_t *uctx);
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyerstatic isc_result_t
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyergetudpdispatch(int family, dns_dispatchmgr_t *dispatchmgr,
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer isc_socketmgr_t *socketmgr, isc_taskmgr_t *taskmgr,
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer isc_boolean_t is_shared, dns_dispatch_t **dispp,
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer isc_sockaddr_t *localaddr)
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer{
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer unsigned int attrs, attrmask;
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer dns_dispatch_t *disp;
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer unsigned buffersize, maxbuffers, maxrequests, buckets, increment;
a5ed46c9fd270775c39770bfd0250a52d374ebf2Michael Sawyer isc_result_t result;
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer isc_sockaddr_t anyaddr;
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer attrs = 0;
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer attrs |= DNS_DISPATCHATTR_UDP;
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer switch (family) {
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer case AF_INET:
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer attrs |= DNS_DISPATCHATTR_IPV4;
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer break;
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer case AF_INET6:
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer attrs |= DNS_DISPATCHATTR_IPV6;
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer break;
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer default:
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer INSIST(0);
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer }
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer attrmask = 0;
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer attrmask |= DNS_DISPATCHATTR_UDP;
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer attrmask |= DNS_DISPATCHATTR_TCP;
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer attrmask |= DNS_DISPATCHATTR_IPV4;
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer attrmask |= DNS_DISPATCHATTR_IPV6;
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer if (localaddr == NULL) {
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer localaddr = &anyaddr;
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer isc_sockaddr_anyofpf(localaddr, family);
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer }
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer buffersize = 4096;
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer maxbuffers = is_shared ? 1000 : 8;
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer maxrequests = 32768;
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer buckets = is_shared ? 16411 : 3;
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer increment = is_shared ? 16433 : 5;
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer disp = NULL;
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer result = dns_dispatch_getudp(dispatchmgr, socketmgr,
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer taskmgr, localaddr,
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer buffersize, maxbuffers, maxrequests,
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer buckets, increment,
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer attrs, attrmask, &disp);
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer if (result == ISC_R_SUCCESS)
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer *dispp = disp;
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer return (result);
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer}
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyerstatic isc_result_t
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyerdns_client_createview(isc_mem_t *mctx, dns_rdataclass_t rdclass,
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer unsigned int options, isc_taskmgr_t *taskmgr,
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer unsigned int ntasks, isc_socketmgr_t *socketmgr,
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer isc_timermgr_t *timermgr, dns_dispatchmgr_t *dispatchmgr,
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer dns_dispatch_t *dispatchv4, dns_dispatch_t *dispatchv6,
37e6e0ca1337351642798b1a6aa24ae40bf86399Andreas Gustafsson dns_view_t **viewp)
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer{
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer isc_result_t result;
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer dns_view_t *view = NULL;
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer const char *dbtype;
37e6e0ca1337351642798b1a6aa24ae40bf86399Andreas Gustafsson
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer result = dns_view_create(mctx, rdclass, DNS_CLIENTVIEW_NAME, &view);
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer if (result != ISC_R_SUCCESS)
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer return (result);
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer
40f53fa8d9c6a4fc38c0014495e7a42b08f52481David Lawrence /* Initialize view security roots */
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer result = dns_view_initsecroots(view, mctx);
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer if (result != ISC_R_SUCCESS) {
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer dns_view_detach(&view);
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer return (result);
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer }
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer
40f53fa8d9c6a4fc38c0014495e7a42b08f52481David Lawrence result = dns_view_createresolver(view, taskmgr, ntasks, 1, socketmgr,
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer timermgr, 0, dispatchmgr,
cefd68008fbba3488a077052ae62aa12b6de502bMichael Sawyer dispatchv4, dispatchv6);
cefd68008fbba3488a077052ae62aa12b6de502bMichael Sawyer if (result != ISC_R_SUCCESS) {
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer dns_view_detach(&view);
cefd68008fbba3488a077052ae62aa12b6de502bMichael Sawyer return (result);
cefd68008fbba3488a077052ae62aa12b6de502bMichael Sawyer }
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer /*
cefd68008fbba3488a077052ae62aa12b6de502bMichael Sawyer * Set cache DB.
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer * XXX: it may be better if specific DB implementations can be
cefd68008fbba3488a077052ae62aa12b6de502bMichael Sawyer * specified via some configuration knob.
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer */
cefd68008fbba3488a077052ae62aa12b6de502bMichael Sawyer if ((options & DNS_CLIENTCREATEOPT_USECACHE) != 0)
cefd68008fbba3488a077052ae62aa12b6de502bMichael Sawyer dbtype = "rbt";
cefd68008fbba3488a077052ae62aa12b6de502bMichael Sawyer else
844eaa56d6d647b38b2a5cf08f7ea5ab7b752690Michael Sawyer dbtype = "ecdb";
844eaa56d6d647b38b2a5cf08f7ea5ab7b752690Michael Sawyer result = dns_db_create(mctx, dbtype, dns_rootname, dns_dbtype_cache,
844eaa56d6d647b38b2a5cf08f7ea5ab7b752690Michael Sawyer rdclass, 0, NULL, &view->cachedb);
844eaa56d6d647b38b2a5cf08f7ea5ab7b752690Michael Sawyer if (result != ISC_R_SUCCESS) {
844eaa56d6d647b38b2a5cf08f7ea5ab7b752690Michael Sawyer dns_view_detach(&view);
844eaa56d6d647b38b2a5cf08f7ea5ab7b752690Michael Sawyer return (result);
844eaa56d6d647b38b2a5cf08f7ea5ab7b752690Michael Sawyer }
844eaa56d6d647b38b2a5cf08f7ea5ab7b752690Michael Sawyer
844eaa56d6d647b38b2a5cf08f7ea5ab7b752690Michael Sawyer *viewp = view;
844eaa56d6d647b38b2a5cf08f7ea5ab7b752690Michael Sawyer return (ISC_R_SUCCESS);
37e6e0ca1337351642798b1a6aa24ae40bf86399Andreas Gustafsson}
844eaa56d6d647b38b2a5cf08f7ea5ab7b752690Michael Sawyer
38cf6e52ce4b33795713388824b69d78e430b115Michael Sawyerisc_result_t
844eaa56d6d647b38b2a5cf08f7ea5ab7b752690Michael Sawyerdns_client_create(dns_client_t **clientp, unsigned int options) {
844eaa56d6d647b38b2a5cf08f7ea5ab7b752690Michael Sawyer isc_result_t result;
844eaa56d6d647b38b2a5cf08f7ea5ab7b752690Michael Sawyer isc_mem_t *mctx = NULL;
844eaa56d6d647b38b2a5cf08f7ea5ab7b752690Michael Sawyer isc_appctx_t *actx = NULL;
37e6e0ca1337351642798b1a6aa24ae40bf86399Andreas Gustafsson isc_taskmgr_t *taskmgr = NULL;
844eaa56d6d647b38b2a5cf08f7ea5ab7b752690Michael Sawyer isc_socketmgr_t *socketmgr = NULL;
844eaa56d6d647b38b2a5cf08f7ea5ab7b752690Michael Sawyer isc_timermgr_t *timermgr = NULL;
37e6e0ca1337351642798b1a6aa24ae40bf86399Andreas Gustafsson#if 0
844eaa56d6d647b38b2a5cf08f7ea5ab7b752690Michael Sawyer /* XXXMPA add debug logging support */
844eaa56d6d647b38b2a5cf08f7ea5ab7b752690Michael Sawyer isc_log_t *lctx = NULL;
37e6e0ca1337351642798b1a6aa24ae40bf86399Andreas Gustafsson isc_logconfig_t *logconfig = NULL;
844eaa56d6d647b38b2a5cf08f7ea5ab7b752690Michael Sawyer unsigned int logdebuglevel = 0;
844eaa56d6d647b38b2a5cf08f7ea5ab7b752690Michael Sawyer#endif
37e6e0ca1337351642798b1a6aa24ae40bf86399Andreas Gustafsson
844eaa56d6d647b38b2a5cf08f7ea5ab7b752690Michael Sawyer result = isc_mem_create(0, 0, &mctx);
844eaa56d6d647b38b2a5cf08f7ea5ab7b752690Michael Sawyer if (result != ISC_R_SUCCESS)
844eaa56d6d647b38b2a5cf08f7ea5ab7b752690Michael Sawyer return (result);
844eaa56d6d647b38b2a5cf08f7ea5ab7b752690Michael Sawyer result = isc_appctx_create(mctx, &actx);
844eaa56d6d647b38b2a5cf08f7ea5ab7b752690Michael Sawyer if (result != ISC_R_SUCCESS)
844eaa56d6d647b38b2a5cf08f7ea5ab7b752690Michael Sawyer goto cleanup;
844eaa56d6d647b38b2a5cf08f7ea5ab7b752690Michael Sawyer result = isc_app_ctxstart(actx);
844eaa56d6d647b38b2a5cf08f7ea5ab7b752690Michael Sawyer if (result != ISC_R_SUCCESS)
844eaa56d6d647b38b2a5cf08f7ea5ab7b752690Michael Sawyer goto cleanup;
844eaa56d6d647b38b2a5cf08f7ea5ab7b752690Michael Sawyer result = isc_taskmgr_createinctx(mctx, actx, 1, 0, &taskmgr);
844eaa56d6d647b38b2a5cf08f7ea5ab7b752690Michael Sawyer if (result != ISC_R_SUCCESS)
844eaa56d6d647b38b2a5cf08f7ea5ab7b752690Michael Sawyer goto cleanup;
844eaa56d6d647b38b2a5cf08f7ea5ab7b752690Michael Sawyer result = isc_socketmgr_createinctx(mctx, actx, &socketmgr);
40f53fa8d9c6a4fc38c0014495e7a42b08f52481David Lawrence if (result != ISC_R_SUCCESS)
844eaa56d6d647b38b2a5cf08f7ea5ab7b752690Michael Sawyer goto cleanup;
844eaa56d6d647b38b2a5cf08f7ea5ab7b752690Michael Sawyer result = isc_timermgr_createinctx(mctx, actx, &timermgr);
844eaa56d6d647b38b2a5cf08f7ea5ab7b752690Michael Sawyer if (result != ISC_R_SUCCESS)
844eaa56d6d647b38b2a5cf08f7ea5ab7b752690Michael Sawyer goto cleanup;
844eaa56d6d647b38b2a5cf08f7ea5ab7b752690Michael Sawyer#if 0
844eaa56d6d647b38b2a5cf08f7ea5ab7b752690Michael Sawyer result = isc_log_create(mctx, &lctx, &logconfig);
844eaa56d6d647b38b2a5cf08f7ea5ab7b752690Michael Sawyer if (result != ISC_R_SUCCESS)
844eaa56d6d647b38b2a5cf08f7ea5ab7b752690Michael Sawyer goto cleanup;
844eaa56d6d647b38b2a5cf08f7ea5ab7b752690Michael Sawyer isc_log_setcontext(lctx);
844eaa56d6d647b38b2a5cf08f7ea5ab7b752690Michael Sawyer dns_log_init(lctx);
844eaa56d6d647b38b2a5cf08f7ea5ab7b752690Michael Sawyer dns_log_setcontext(lctx);
844eaa56d6d647b38b2a5cf08f7ea5ab7b752690Michael Sawyer result = isc_log_usechannel(logconfig, "default_debug", NULL, NULL);
844eaa56d6d647b38b2a5cf08f7ea5ab7b752690Michael Sawyer if (result != ISC_R_SUCCESS)
844eaa56d6d647b38b2a5cf08f7ea5ab7b752690Michael Sawyer goto cleanup;
844eaa56d6d647b38b2a5cf08f7ea5ab7b752690Michael Sawyer isc_log_setdebuglevel(lctx, logdebuglevel);
844eaa56d6d647b38b2a5cf08f7ea5ab7b752690Michael Sawyer#endif
844eaa56d6d647b38b2a5cf08f7ea5ab7b752690Michael Sawyer result = dns_client_createx(mctx, actx, taskmgr, socketmgr, timermgr,
844eaa56d6d647b38b2a5cf08f7ea5ab7b752690Michael Sawyer options, clientp);
844eaa56d6d647b38b2a5cf08f7ea5ab7b752690Michael Sawyer if (result != ISC_R_SUCCESS)
844eaa56d6d647b38b2a5cf08f7ea5ab7b752690Michael Sawyer goto cleanup;
844eaa56d6d647b38b2a5cf08f7ea5ab7b752690Michael Sawyer
844eaa56d6d647b38b2a5cf08f7ea5ab7b752690Michael Sawyer (*clientp)->attributes |= DNS_CLIENTATTR_OWNCTX;
844eaa56d6d647b38b2a5cf08f7ea5ab7b752690Michael Sawyer
844eaa56d6d647b38b2a5cf08f7ea5ab7b752690Michael Sawyer /* client has its own reference to mctx, so we can detach it here */
a5ed46c9fd270775c39770bfd0250a52d374ebf2Michael Sawyer isc_mem_detach(&mctx);
844eaa56d6d647b38b2a5cf08f7ea5ab7b752690Michael Sawyer
844eaa56d6d647b38b2a5cf08f7ea5ab7b752690Michael Sawyer return (ISC_R_SUCCESS);
844eaa56d6d647b38b2a5cf08f7ea5ab7b752690Michael Sawyer
844eaa56d6d647b38b2a5cf08f7ea5ab7b752690Michael Sawyer cleanup:
844eaa56d6d647b38b2a5cf08f7ea5ab7b752690Michael Sawyer if (taskmgr != NULL)
844eaa56d6d647b38b2a5cf08f7ea5ab7b752690Michael Sawyer isc_taskmgr_destroy(&taskmgr);
844eaa56d6d647b38b2a5cf08f7ea5ab7b752690Michael Sawyer if (timermgr != NULL)
844eaa56d6d647b38b2a5cf08f7ea5ab7b752690Michael Sawyer isc_timermgr_destroy(&timermgr);
844eaa56d6d647b38b2a5cf08f7ea5ab7b752690Michael Sawyer if (socketmgr != NULL)
844eaa56d6d647b38b2a5cf08f7ea5ab7b752690Michael Sawyer isc_socketmgr_destroy(&socketmgr);
844eaa56d6d647b38b2a5cf08f7ea5ab7b752690Michael Sawyer if (actx != NULL)
844eaa56d6d647b38b2a5cf08f7ea5ab7b752690Michael Sawyer isc_appctx_destroy(&actx);
844eaa56d6d647b38b2a5cf08f7ea5ab7b752690Michael Sawyer isc_mem_detach(&mctx);
844eaa56d6d647b38b2a5cf08f7ea5ab7b752690Michael Sawyer
844eaa56d6d647b38b2a5cf08f7ea5ab7b752690Michael Sawyer return (result);
844eaa56d6d647b38b2a5cf08f7ea5ab7b752690Michael Sawyer}
844eaa56d6d647b38b2a5cf08f7ea5ab7b752690Michael Sawyer
844eaa56d6d647b38b2a5cf08f7ea5ab7b752690Michael Sawyerisc_result_t
844eaa56d6d647b38b2a5cf08f7ea5ab7b752690Michael Sawyerdns_client_createx(isc_mem_t *mctx, isc_appctx_t *actx, isc_taskmgr_t *taskmgr,
844eaa56d6d647b38b2a5cf08f7ea5ab7b752690Michael Sawyer isc_socketmgr_t *socketmgr, isc_timermgr_t *timermgr,
844eaa56d6d647b38b2a5cf08f7ea5ab7b752690Michael Sawyer unsigned int options, dns_client_t **clientp)
844eaa56d6d647b38b2a5cf08f7ea5ab7b752690Michael Sawyer{
844eaa56d6d647b38b2a5cf08f7ea5ab7b752690Michael Sawyer isc_result_t result;
844eaa56d6d647b38b2a5cf08f7ea5ab7b752690Michael Sawyer result = dns_client_createx2(mctx, actx, taskmgr, socketmgr, timermgr,
844eaa56d6d647b38b2a5cf08f7ea5ab7b752690Michael Sawyer options, clientp, NULL, NULL);
844eaa56d6d647b38b2a5cf08f7ea5ab7b752690Michael Sawyer return (result);
844eaa56d6d647b38b2a5cf08f7ea5ab7b752690Michael Sawyer}
844eaa56d6d647b38b2a5cf08f7ea5ab7b752690Michael Sawyer
844eaa56d6d647b38b2a5cf08f7ea5ab7b752690Michael Sawyerisc_result_t
844eaa56d6d647b38b2a5cf08f7ea5ab7b752690Michael Sawyerdns_client_createx2(isc_mem_t *mctx, isc_appctx_t *actx,
844eaa56d6d647b38b2a5cf08f7ea5ab7b752690Michael Sawyer isc_taskmgr_t *taskmgr, isc_socketmgr_t *socketmgr,
844eaa56d6d647b38b2a5cf08f7ea5ab7b752690Michael Sawyer isc_timermgr_t *timermgr, unsigned int options,
844eaa56d6d647b38b2a5cf08f7ea5ab7b752690Michael Sawyer dns_client_t **clientp, isc_sockaddr_t *localaddr4,
844eaa56d6d647b38b2a5cf08f7ea5ab7b752690Michael Sawyer isc_sockaddr_t *localaddr6)
844eaa56d6d647b38b2a5cf08f7ea5ab7b752690Michael Sawyer{
844eaa56d6d647b38b2a5cf08f7ea5ab7b752690Michael Sawyer dns_client_t *client;
844eaa56d6d647b38b2a5cf08f7ea5ab7b752690Michael Sawyer isc_result_t result;
844eaa56d6d647b38b2a5cf08f7ea5ab7b752690Michael Sawyer dns_dispatchmgr_t *dispatchmgr = NULL;
844eaa56d6d647b38b2a5cf08f7ea5ab7b752690Michael Sawyer dns_dispatch_t *dispatchv4 = NULL;
844eaa56d6d647b38b2a5cf08f7ea5ab7b752690Michael Sawyer dns_dispatch_t *dispatchv6 = NULL;
844eaa56d6d647b38b2a5cf08f7ea5ab7b752690Michael Sawyer dns_view_t *view = NULL;
844eaa56d6d647b38b2a5cf08f7ea5ab7b752690Michael Sawyer
844eaa56d6d647b38b2a5cf08f7ea5ab7b752690Michael Sawyer REQUIRE(mctx != NULL);
37e6e0ca1337351642798b1a6aa24ae40bf86399Andreas Gustafsson REQUIRE(taskmgr != NULL);
844eaa56d6d647b38b2a5cf08f7ea5ab7b752690Michael Sawyer REQUIRE(timermgr != NULL);
844eaa56d6d647b38b2a5cf08f7ea5ab7b752690Michael Sawyer REQUIRE(socketmgr != NULL);
37e6e0ca1337351642798b1a6aa24ae40bf86399Andreas Gustafsson REQUIRE(clientp != NULL && *clientp == NULL);
844eaa56d6d647b38b2a5cf08f7ea5ab7b752690Michael Sawyer
844eaa56d6d647b38b2a5cf08f7ea5ab7b752690Michael Sawyer client = isc_mem_get(mctx, sizeof(*client));
40f53fa8d9c6a4fc38c0014495e7a42b08f52481David Lawrence if (client == NULL)
844eaa56d6d647b38b2a5cf08f7ea5ab7b752690Michael Sawyer return (ISC_R_NOMEMORY);
844eaa56d6d647b38b2a5cf08f7ea5ab7b752690Michael Sawyer
844eaa56d6d647b38b2a5cf08f7ea5ab7b752690Michael Sawyer result = isc_mutex_init(&client->lock);
844eaa56d6d647b38b2a5cf08f7ea5ab7b752690Michael Sawyer if (result != ISC_R_SUCCESS) {
844eaa56d6d647b38b2a5cf08f7ea5ab7b752690Michael Sawyer isc_mem_put(mctx, client, sizeof(*client));
844eaa56d6d647b38b2a5cf08f7ea5ab7b752690Michael Sawyer return (result);
40f53fa8d9c6a4fc38c0014495e7a42b08f52481David Lawrence }
844eaa56d6d647b38b2a5cf08f7ea5ab7b752690Michael Sawyer
844eaa56d6d647b38b2a5cf08f7ea5ab7b752690Michael Sawyer client->actx = actx;
844eaa56d6d647b38b2a5cf08f7ea5ab7b752690Michael Sawyer client->taskmgr = taskmgr;
844eaa56d6d647b38b2a5cf08f7ea5ab7b752690Michael Sawyer client->socketmgr = socketmgr;
844eaa56d6d647b38b2a5cf08f7ea5ab7b752690Michael Sawyer client->timermgr = timermgr;
844eaa56d6d647b38b2a5cf08f7ea5ab7b752690Michael Sawyer
844eaa56d6d647b38b2a5cf08f7ea5ab7b752690Michael Sawyer client->task = NULL;
844eaa56d6d647b38b2a5cf08f7ea5ab7b752690Michael Sawyer result = isc_task_create(client->taskmgr, 0, &client->task);
844eaa56d6d647b38b2a5cf08f7ea5ab7b752690Michael Sawyer if (result != ISC_R_SUCCESS)
844eaa56d6d647b38b2a5cf08f7ea5ab7b752690Michael Sawyer goto cleanup;
844eaa56d6d647b38b2a5cf08f7ea5ab7b752690Michael Sawyer
844eaa56d6d647b38b2a5cf08f7ea5ab7b752690Michael Sawyer result = dns_dispatchmgr_create(mctx, NULL, &dispatchmgr);
844eaa56d6d647b38b2a5cf08f7ea5ab7b752690Michael Sawyer if (result != ISC_R_SUCCESS)
844eaa56d6d647b38b2a5cf08f7ea5ab7b752690Michael Sawyer goto cleanup;
844eaa56d6d647b38b2a5cf08f7ea5ab7b752690Michael Sawyer client->dispatchmgr = dispatchmgr;
cefd68008fbba3488a077052ae62aa12b6de502bMichael Sawyer
cefd68008fbba3488a077052ae62aa12b6de502bMichael Sawyer /*
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer * If only one address family is specified, use it.
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer * If neither family is specified, or if both are, use both.
cefd68008fbba3488a077052ae62aa12b6de502bMichael Sawyer */
cefd68008fbba3488a077052ae62aa12b6de502bMichael Sawyer client->dispatchv4 = NULL;
37e6e0ca1337351642798b1a6aa24ae40bf86399Andreas Gustafsson if (localaddr4 != NULL || localaddr6 == NULL) {
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer result = getudpdispatch(AF_INET, dispatchmgr, socketmgr,
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer taskmgr, ISC_TRUE,
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer &dispatchv4, localaddr4);
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer if (result == ISC_R_SUCCESS)
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer client->dispatchv4 = dispatchv4;
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer }
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer client->dispatchv6 = NULL;
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer if (localaddr6 != NULL || localaddr4 == NULL) {
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer result = getudpdispatch(AF_INET6, dispatchmgr, socketmgr,
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer taskmgr, ISC_TRUE,
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer &dispatchv6, localaddr6);
37e6e0ca1337351642798b1a6aa24ae40bf86399Andreas Gustafsson if (result == ISC_R_SUCCESS)
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer client->dispatchv6 = dispatchv6;
cefd68008fbba3488a077052ae62aa12b6de502bMichael Sawyer }
37e6e0ca1337351642798b1a6aa24ae40bf86399Andreas Gustafsson
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer /* We need at least one of the dispatchers */
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer if (dispatchv4 == NULL && dispatchv6 == NULL) {
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer INSIST(result != ISC_R_SUCCESS);
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer goto cleanup;
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer }
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer /* Create the default view for class IN */
844eaa56d6d647b38b2a5cf08f7ea5ab7b752690Michael Sawyer result = dns_client_createview(mctx, dns_rdataclass_in, options,
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer taskmgr, 31, socketmgr, timermgr,
844eaa56d6d647b38b2a5cf08f7ea5ab7b752690Michael Sawyer dispatchmgr, dispatchv4, dispatchv6,
37e6e0ca1337351642798b1a6aa24ae40bf86399Andreas Gustafsson &view);
844eaa56d6d647b38b2a5cf08f7ea5ab7b752690Michael Sawyer if (result != ISC_R_SUCCESS)
844eaa56d6d647b38b2a5cf08f7ea5ab7b752690Michael Sawyer goto cleanup;
844eaa56d6d647b38b2a5cf08f7ea5ab7b752690Michael Sawyer ISC_LIST_INIT(client->viewlist);
844eaa56d6d647b38b2a5cf08f7ea5ab7b752690Michael Sawyer ISC_LIST_APPEND(client->viewlist, view, link);
844eaa56d6d647b38b2a5cf08f7ea5ab7b752690Michael Sawyer
37e6e0ca1337351642798b1a6aa24ae40bf86399Andreas Gustafsson dns_view_freeze(view); /* too early? */
844eaa56d6d647b38b2a5cf08f7ea5ab7b752690Michael Sawyer
40f53fa8d9c6a4fc38c0014495e7a42b08f52481David Lawrence ISC_LIST_INIT(client->resctxs);
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer ISC_LIST_INIT(client->reqctxs);
37e6e0ca1337351642798b1a6aa24ae40bf86399Andreas Gustafsson ISC_LIST_INIT(client->updatectxs);
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer
40f53fa8d9c6a4fc38c0014495e7a42b08f52481David Lawrence client->mctx = NULL;
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer isc_mem_attach(mctx, &client->mctx);
aa6054ec74819f754bcf19442ca9b39d948171adMichael Sawyer
37e6e0ca1337351642798b1a6aa24ae40bf86399Andreas Gustafsson client->update_timeout = DEF_UPDATE_TIMEOUT;
844eaa56d6d647b38b2a5cf08f7ea5ab7b752690Michael Sawyer client->update_udptimeout = DEF_UPDATE_UDPTIMEOUT;
844eaa56d6d647b38b2a5cf08f7ea5ab7b752690Michael Sawyer client->update_udpretries = DEF_UPDATE_UDPRETRIES;
844eaa56d6d647b38b2a5cf08f7ea5ab7b752690Michael Sawyer client->find_timeout = DEF_FIND_TIMEOUT;
844eaa56d6d647b38b2a5cf08f7ea5ab7b752690Michael Sawyer client->find_udpretries = DEF_FIND_UDPRETRIES;
cefd68008fbba3488a077052ae62aa12b6de502bMichael Sawyer client->attributes = 0;
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer
cefd68008fbba3488a077052ae62aa12b6de502bMichael Sawyer client->references = 1;
cefd68008fbba3488a077052ae62aa12b6de502bMichael Sawyer client->magic = DNS_CLIENT_MAGIC;
cefd68008fbba3488a077052ae62aa12b6de502bMichael Sawyer
844eaa56d6d647b38b2a5cf08f7ea5ab7b752690Michael Sawyer *clientp = client;
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer
844eaa56d6d647b38b2a5cf08f7ea5ab7b752690Michael Sawyer return (ISC_R_SUCCESS);
844eaa56d6d647b38b2a5cf08f7ea5ab7b752690Michael Sawyer
844eaa56d6d647b38b2a5cf08f7ea5ab7b752690Michael Sawyer cleanup:
40f53fa8d9c6a4fc38c0014495e7a42b08f52481David Lawrence if (dispatchv4 != NULL)
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer dns_dispatch_detach(&dispatchv4);
844eaa56d6d647b38b2a5cf08f7ea5ab7b752690Michael Sawyer if (dispatchv6 != NULL)
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer dns_dispatch_detach(&dispatchv6);
844eaa56d6d647b38b2a5cf08f7ea5ab7b752690Michael Sawyer if (dispatchmgr != NULL)
844eaa56d6d647b38b2a5cf08f7ea5ab7b752690Michael Sawyer dns_dispatchmgr_destroy(&dispatchmgr);
844eaa56d6d647b38b2a5cf08f7ea5ab7b752690Michael Sawyer if (client->task != NULL)
844eaa56d6d647b38b2a5cf08f7ea5ab7b752690Michael Sawyer isc_task_detach(&client->task);
844eaa56d6d647b38b2a5cf08f7ea5ab7b752690Michael Sawyer isc_mem_put(mctx, client, sizeof(*client));
37e6e0ca1337351642798b1a6aa24ae40bf86399Andreas Gustafsson
844eaa56d6d647b38b2a5cf08f7ea5ab7b752690Michael Sawyer return (result);
844eaa56d6d647b38b2a5cf08f7ea5ab7b752690Michael Sawyer}
844eaa56d6d647b38b2a5cf08f7ea5ab7b752690Michael Sawyer
844eaa56d6d647b38b2a5cf08f7ea5ab7b752690Michael Sawyerstatic void
844eaa56d6d647b38b2a5cf08f7ea5ab7b752690Michael Sawyerdestroyclient(dns_client_t **clientp) {
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer dns_client_t *client = *clientp;
cefd68008fbba3488a077052ae62aa12b6de502bMichael Sawyer dns_view_t *view;
37e6e0ca1337351642798b1a6aa24ae40bf86399Andreas Gustafsson
37e6e0ca1337351642798b1a6aa24ae40bf86399Andreas Gustafsson while ((view = ISC_LIST_HEAD(client->viewlist)) != NULL) {
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer ISC_LIST_UNLINK(client->viewlist, view, link);
d821f1cd7e97552401296e880e7518c98c9ebea1Michael Sawyer dns_view_detach(&view);
37e6e0ca1337351642798b1a6aa24ae40bf86399Andreas Gustafsson }
844eaa56d6d647b38b2a5cf08f7ea5ab7b752690Michael Sawyer
aa6054ec74819f754bcf19442ca9b39d948171adMichael Sawyer if (client->dispatchv4 != NULL)
d821f1cd7e97552401296e880e7518c98c9ebea1Michael Sawyer dns_dispatch_detach(&client->dispatchv4);
37e6e0ca1337351642798b1a6aa24ae40bf86399Andreas Gustafsson if (client->dispatchv6 != NULL)
d821f1cd7e97552401296e880e7518c98c9ebea1Michael Sawyer dns_dispatch_detach(&client->dispatchv6);
37e6e0ca1337351642798b1a6aa24ae40bf86399Andreas Gustafsson
d821f1cd7e97552401296e880e7518c98c9ebea1Michael Sawyer dns_dispatchmgr_destroy(&client->dispatchmgr);
37e6e0ca1337351642798b1a6aa24ae40bf86399Andreas Gustafsson
d821f1cd7e97552401296e880e7518c98c9ebea1Michael Sawyer isc_task_detach(&client->task);
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer
cefd68008fbba3488a077052ae62aa12b6de502bMichael Sawyer /*
cefd68008fbba3488a077052ae62aa12b6de502bMichael Sawyer * If the client has created its own running environments,
aa6054ec74819f754bcf19442ca9b39d948171adMichael Sawyer * destroy them.
aa6054ec74819f754bcf19442ca9b39d948171adMichael Sawyer */
aa6054ec74819f754bcf19442ca9b39d948171adMichael Sawyer if ((client->attributes & DNS_CLIENTATTR_OWNCTX) != 0) {
aa6054ec74819f754bcf19442ca9b39d948171adMichael Sawyer isc_taskmgr_destroy(&client->taskmgr);
aa6054ec74819f754bcf19442ca9b39d948171adMichael Sawyer isc_timermgr_destroy(&client->timermgr);
aa6054ec74819f754bcf19442ca9b39d948171adMichael Sawyer isc_socketmgr_destroy(&client->socketmgr);
aa6054ec74819f754bcf19442ca9b39d948171adMichael Sawyer
aa6054ec74819f754bcf19442ca9b39d948171adMichael Sawyer isc_app_ctxfinish(client->actx);
aa6054ec74819f754bcf19442ca9b39d948171adMichael Sawyer isc_appctx_destroy(&client->actx);
5564b21be5cf3e7b8f751af268f2c1522c1744e3David Lawrence }
aa6054ec74819f754bcf19442ca9b39d948171adMichael Sawyer
aa6054ec74819f754bcf19442ca9b39d948171adMichael Sawyer DESTROYLOCK(&client->lock);
aa6054ec74819f754bcf19442ca9b39d948171adMichael Sawyer client->magic = 0;
aa6054ec74819f754bcf19442ca9b39d948171adMichael Sawyer
aa6054ec74819f754bcf19442ca9b39d948171adMichael Sawyer isc_mem_putanddetach(&client->mctx, client, sizeof(*client));
aa6054ec74819f754bcf19442ca9b39d948171adMichael Sawyer
aa6054ec74819f754bcf19442ca9b39d948171adMichael Sawyer *clientp = NULL;
aa6054ec74819f754bcf19442ca9b39d948171adMichael Sawyer}
aa6054ec74819f754bcf19442ca9b39d948171adMichael Sawyer
aa6054ec74819f754bcf19442ca9b39d948171adMichael Sawyervoid
aa6054ec74819f754bcf19442ca9b39d948171adMichael Sawyerdns_client_destroy(dns_client_t **clientp) {
5564b21be5cf3e7b8f751af268f2c1522c1744e3David Lawrence dns_client_t *client;
aa6054ec74819f754bcf19442ca9b39d948171adMichael Sawyer isc_boolean_t destroyok = ISC_FALSE;
aa6054ec74819f754bcf19442ca9b39d948171adMichael Sawyer
aa6054ec74819f754bcf19442ca9b39d948171adMichael Sawyer REQUIRE(clientp != NULL);
cefd68008fbba3488a077052ae62aa12b6de502bMichael Sawyer client = *clientp;
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer REQUIRE(DNS_CLIENT_VALID(client));
48674819ebf9176b5d5582ae851e485c324c1159Michael Sawyer
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer LOCK(&client->lock);
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer client->references--;
844eaa56d6d647b38b2a5cf08f7ea5ab7b752690Michael Sawyer if (client->references == 0 && ISC_LIST_EMPTY(client->resctxs) &&
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer ISC_LIST_EMPTY(client->reqctxs) &&
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer ISC_LIST_EMPTY(client->updatectxs)) {
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer destroyok = ISC_TRUE;
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer }
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer UNLOCK(&client->lock);
aa6054ec74819f754bcf19442ca9b39d948171adMichael Sawyer
aa6054ec74819f754bcf19442ca9b39d948171adMichael Sawyer if (destroyok)
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer destroyclient(&client);
aa6054ec74819f754bcf19442ca9b39d948171adMichael Sawyer
aa6054ec74819f754bcf19442ca9b39d948171adMichael Sawyer *clientp = NULL;
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer}
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyerisc_result_t
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyerdns_client_setservers(dns_client_t *client, dns_rdataclass_t rdclass,
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer dns_name_t *namespace, isc_sockaddrlist_t *addrs)
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer{
d821f1cd7e97552401296e880e7518c98c9ebea1Michael Sawyer isc_result_t result;
d821f1cd7e97552401296e880e7518c98c9ebea1Michael Sawyer dns_view_t *view = NULL;
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer REQUIRE(DNS_CLIENT_VALID(client));
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer REQUIRE(addrs != NULL);
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer
d821f1cd7e97552401296e880e7518c98c9ebea1Michael Sawyer if (namespace == NULL)
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer namespace = dns_rootname;
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer LOCK(&client->lock);
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer result = dns_viewlist_find(&client->viewlist, DNS_CLIENTVIEW_NAME,
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer rdclass, &view);
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer if (result != ISC_R_SUCCESS) {
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer UNLOCK(&client->lock);
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer return (result);
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer }
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer UNLOCK(&client->lock);
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer result = dns_fwdtable_add(view->fwdtable, namespace, addrs,
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer dns_fwdpolicy_only);
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer dns_view_detach(&view);
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer return (result);
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer}
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyerisc_result_t
d821f1cd7e97552401296e880e7518c98c9ebea1Michael Sawyerdns_client_clearservers(dns_client_t *client, dns_rdataclass_t rdclass,
d821f1cd7e97552401296e880e7518c98c9ebea1Michael Sawyer dns_name_t *namespace)
d821f1cd7e97552401296e880e7518c98c9ebea1Michael Sawyer{
d821f1cd7e97552401296e880e7518c98c9ebea1Michael Sawyer isc_result_t result;
f8fec75ee8f429821137aee090f56ab678404a56Michael Sawyer dns_view_t *view = NULL;
6c6a62933dda281cb9193de1d54d4c9e74515f5aMichael Sawyer
48674819ebf9176b5d5582ae851e485c324c1159Michael Sawyer REQUIRE(DNS_CLIENT_VALID(client));
48674819ebf9176b5d5582ae851e485c324c1159Michael Sawyer
48674819ebf9176b5d5582ae851e485c324c1159Michael Sawyer if (namespace == NULL)
48674819ebf9176b5d5582ae851e485c324c1159Michael Sawyer namespace = dns_rootname;
cefd68008fbba3488a077052ae62aa12b6de502bMichael Sawyer
cefd68008fbba3488a077052ae62aa12b6de502bMichael Sawyer LOCK(&client->lock);
cefd68008fbba3488a077052ae62aa12b6de502bMichael Sawyer result = dns_viewlist_find(&client->viewlist, DNS_CLIENTVIEW_NAME,
48674819ebf9176b5d5582ae851e485c324c1159Michael Sawyer rdclass, &view);
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer if (result != ISC_R_SUCCESS) {
cefd68008fbba3488a077052ae62aa12b6de502bMichael Sawyer UNLOCK(&client->lock);
aa6054ec74819f754bcf19442ca9b39d948171adMichael Sawyer return (result);
aa6054ec74819f754bcf19442ca9b39d948171adMichael Sawyer }
aa6054ec74819f754bcf19442ca9b39d948171adMichael Sawyer UNLOCK(&client->lock);
aa6054ec74819f754bcf19442ca9b39d948171adMichael Sawyer
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer result = dns_fwdtable_delete(view->fwdtable, namespace);
37e6e0ca1337351642798b1a6aa24ae40bf86399Andreas Gustafsson
aa6054ec74819f754bcf19442ca9b39d948171adMichael Sawyer dns_view_detach(&view);
aa6054ec74819f754bcf19442ca9b39d948171adMichael Sawyer
aa6054ec74819f754bcf19442ca9b39d948171adMichael Sawyer return (result);
aa6054ec74819f754bcf19442ca9b39d948171adMichael Sawyer}
aa6054ec74819f754bcf19442ca9b39d948171adMichael Sawyer
aa6054ec74819f754bcf19442ca9b39d948171adMichael Sawyerstatic isc_result_t
aa6054ec74819f754bcf19442ca9b39d948171adMichael Sawyergetrdataset(isc_mem_t *mctx, dns_rdataset_t **rdatasetp) {
aa6054ec74819f754bcf19442ca9b39d948171adMichael Sawyer dns_rdataset_t *rdataset;
aa6054ec74819f754bcf19442ca9b39d948171adMichael Sawyer
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer REQUIRE(mctx != NULL);
aa6054ec74819f754bcf19442ca9b39d948171adMichael Sawyer REQUIRE(rdatasetp != NULL && *rdatasetp == NULL);
aa6054ec74819f754bcf19442ca9b39d948171adMichael Sawyer
cd720113a2fc8a781d4e33350b8a2b62857b31d8David Lawrence rdataset = isc_mem_get(mctx, sizeof(*rdataset));
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer if (rdataset == NULL)
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer return (ISC_R_NOMEMORY);
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer dns_rdataset_init(rdataset);
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer
cefd68008fbba3488a077052ae62aa12b6de502bMichael Sawyer *rdatasetp = rdataset;
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer return (ISC_R_SUCCESS);
9fe3676b8490319aa65182f2072cbf5086097979Michael Sawyer}
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyerstatic void
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyerputrdataset(isc_mem_t *mctx, dns_rdataset_t **rdatasetp) {
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer dns_rdataset_t *rdataset;
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer
17747cd5ee98901b435cd2b3019c52937955a981Michael Sawyer REQUIRE(rdatasetp != NULL);
cefd68008fbba3488a077052ae62aa12b6de502bMichael Sawyer rdataset = *rdatasetp;
cefd68008fbba3488a077052ae62aa12b6de502bMichael Sawyer REQUIRE(rdataset != NULL);
cefd68008fbba3488a077052ae62aa12b6de502bMichael Sawyer
cefd68008fbba3488a077052ae62aa12b6de502bMichael Sawyer if (dns_rdataset_isassociated(rdataset))
38cf6e52ce4b33795713388824b69d78e430b115Michael Sawyer dns_rdataset_disassociate(rdataset);
48674819ebf9176b5d5582ae851e485c324c1159Michael Sawyer
cefd68008fbba3488a077052ae62aa12b6de502bMichael Sawyer isc_mem_put(mctx, rdataset, sizeof(*rdataset));
cefd68008fbba3488a077052ae62aa12b6de502bMichael Sawyer
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer *rdatasetp = NULL;
cd720113a2fc8a781d4e33350b8a2b62857b31d8David Lawrence}
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyerstatic void
b266f8fc42702debc6bd89365273223fa89cd8ddBrian Wellingtonfetch_done(isc_task_t *task, isc_event_t *event) {
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer resctx_t *rctx = event->ev_arg;
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer dns_fetchevent_t *fevent;
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer REQUIRE(event->ev_type == DNS_EVENT_FETCHDONE);
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer REQUIRE(RCTX_VALID(rctx));
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer REQUIRE(rctx->task == task);
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer fevent = (dns_fetchevent_t *)event;
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer client_resfind(rctx, fevent);
40f53fa8d9c6a4fc38c0014495e7a42b08f52481David Lawrence}
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyerstatic inline isc_result_t
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyerstart_fetch(resctx_t *rctx) {
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer isc_result_t result;
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer /*
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer * The caller must be holding the rctx's lock.
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer */
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer REQUIRE(rctx->fetch == NULL);
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer result = dns_resolver_createfetch(rctx->view->resolver,
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer dns_fixedname_name(&rctx->name),
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer rctx->type,
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer NULL, NULL, NULL, 0,
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer rctx->task, fetch_done, rctx,
cd720113a2fc8a781d4e33350b8a2b62857b31d8David Lawrence rctx->rdataset,
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer rctx->sigrdataset,
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer &rctx->fetch);
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer return (result);
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer}
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyerstatic isc_result_t
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyerview_find(resctx_t *rctx, dns_db_t **dbp, dns_dbnode_t **nodep,
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer dns_name_t *foundname)
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer{
5f01e77fc23fe9665fa2b8acd0a0c5bfbf61d61dBrian Wellington isc_result_t result;
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer dns_name_t *name = dns_fixedname_name(&rctx->name);
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer dns_rdatatype_t type;
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer if (rctx->type == dns_rdatatype_rrsig)
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer type = dns_rdatatype_any;
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer else
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer type = rctx->type;
40f53fa8d9c6a4fc38c0014495e7a42b08f52481David Lawrence
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer result = dns_view_find(rctx->view, name, type, 0, 0, ISC_FALSE,
6e3a8e17fdf108f47bbba17474fd3d120d356b2fBrian Wellington dbp, nodep, foundname, rctx->rdataset,
6e3a8e17fdf108f47bbba17474fd3d120d356b2fBrian Wellington rctx->sigrdataset);
6e3a8e17fdf108f47bbba17474fd3d120d356b2fBrian Wellington
5f01e77fc23fe9665fa2b8acd0a0c5bfbf61d61dBrian Wellington return (result);
5f01e77fc23fe9665fa2b8acd0a0c5bfbf61d61dBrian Wellington}
5f01e77fc23fe9665fa2b8acd0a0c5bfbf61d61dBrian Wellington
5f01e77fc23fe9665fa2b8acd0a0c5bfbf61d61dBrian Wellingtonstatic void
5f01e77fc23fe9665fa2b8acd0a0c5bfbf61d61dBrian Wellingtonclient_resfind(resctx_t *rctx, dns_fetchevent_t *event) {
5f01e77fc23fe9665fa2b8acd0a0c5bfbf61d61dBrian Wellington isc_mem_t *mctx;
5f01e77fc23fe9665fa2b8acd0a0c5bfbf61d61dBrian Wellington isc_result_t tresult, result = ISC_R_SUCCESS;
5f01e77fc23fe9665fa2b8acd0a0c5bfbf61d61dBrian Wellington isc_result_t vresult = ISC_R_SUCCESS;
5f01e77fc23fe9665fa2b8acd0a0c5bfbf61d61dBrian Wellington isc_boolean_t want_restart;
5f01e77fc23fe9665fa2b8acd0a0c5bfbf61d61dBrian Wellington isc_boolean_t send_event = ISC_FALSE;
5f01e77fc23fe9665fa2b8acd0a0c5bfbf61d61dBrian Wellington dns_name_t *name, *prefix;
5f01e77fc23fe9665fa2b8acd0a0c5bfbf61d61dBrian Wellington dns_fixedname_t foundname, fixed;
40f53fa8d9c6a4fc38c0014495e7a42b08f52481David Lawrence dns_rdataset_t *trdataset;
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer dns_rdata_t rdata = DNS_RDATA_INIT;
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer unsigned int nlabels;
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer int order;
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer dns_namereln_t namereln;
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer dns_rdata_cname_t cname;
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer dns_rdata_dname_t dname;
19c8df90f1f23c3df870c1771c89c1acdb15020eMichael Sawyer
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer REQUIRE(RCTX_VALID(rctx));
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer
37e6e0ca1337351642798b1a6aa24ae40bf86399Andreas Gustafsson LOCK(&rctx->lock);
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer mctx = rctx->view->mctx;
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer name = dns_fixedname_name(&rctx->name);
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer do {
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer dns_name_t *fname = NULL;
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer dns_name_t *ansname = NULL;
19c8df90f1f23c3df870c1771c89c1acdb15020eMichael Sawyer dns_db_t *db = NULL;
19c8df90f1f23c3df870c1771c89c1acdb15020eMichael Sawyer dns_dbnode_t *node = NULL;
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer
19c8df90f1f23c3df870c1771c89c1acdb15020eMichael Sawyer rctx->restarts++;
19c8df90f1f23c3df870c1771c89c1acdb15020eMichael Sawyer want_restart = ISC_FALSE;
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer
19c8df90f1f23c3df870c1771c89c1acdb15020eMichael Sawyer if (event == NULL && !rctx->canceled) {
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer dns_fixedname_init(&foundname);
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer fname = dns_fixedname_name(&foundname);
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer INSIST(!dns_rdataset_isassociated(rctx->rdataset));
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer INSIST(rctx->sigrdataset == NULL ||
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer !dns_rdataset_isassociated(rctx->sigrdataset));
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer result = view_find(rctx, &db, &node, fname);
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer if (result == ISC_R_NOTFOUND) {
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer /*
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer * We don't know anything about the name.
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer * Launch a fetch.
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer */
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer if (node != NULL) {
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer INSIST(db != NULL);
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer dns_db_detachnode(db, &node);
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer }
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer if (db != NULL)
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer dns_db_detach(&db);
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer result = start_fetch(rctx);
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer if (result != ISC_R_SUCCESS) {
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer putrdataset(mctx, &rctx->rdataset);
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer if (rctx->sigrdataset != NULL)
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer putrdataset(mctx,
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer &rctx->sigrdataset);
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer send_event = ISC_TRUE;
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer }
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer goto done;
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer }
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer } else {
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer INSIST(event != NULL);
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer INSIST(event->fetch == rctx->fetch);
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer dns_resolver_destroyfetch(&rctx->fetch);
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer db = event->db;
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer node = event->node;
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer result = event->result;
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer vresult = event->vresult;
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer fname = dns_fixedname_name(&event->foundname);
e715e011788a529446b8013239c33599542ece32Michael Sawyer INSIST(event->rdataset == rctx->rdataset);
e715e011788a529446b8013239c33599542ece32Michael Sawyer INSIST(event->sigrdataset == rctx->sigrdataset);
e715e011788a529446b8013239c33599542ece32Michael Sawyer }
e715e011788a529446b8013239c33599542ece32Michael Sawyer
e715e011788a529446b8013239c33599542ece32Michael Sawyer /*
e715e011788a529446b8013239c33599542ece32Michael Sawyer * If we've been canceled, forget about the result.
40f53fa8d9c6a4fc38c0014495e7a42b08f52481David Lawrence */
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer if (rctx->canceled)
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer result = ISC_R_CANCELED;
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer else {
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer /*
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer * Otherwise, get some resource for copying the
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer * result.
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer */
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer ansname = isc_mem_get(mctx, sizeof(*ansname));
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer if (ansname == NULL)
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer tresult = ISC_R_NOMEMORY;
40f53fa8d9c6a4fc38c0014495e7a42b08f52481David Lawrence else {
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer dns_name_t *aname;
b266f8fc42702debc6bd89365273223fa89cd8ddBrian Wellington
b266f8fc42702debc6bd89365273223fa89cd8ddBrian Wellington aname = dns_fixedname_name(&rctx->name);
b266f8fc42702debc6bd89365273223fa89cd8ddBrian Wellington dns_name_init(ansname, NULL);
b266f8fc42702debc6bd89365273223fa89cd8ddBrian Wellington tresult = dns_name_dup(aname, mctx, ansname);
b266f8fc42702debc6bd89365273223fa89cd8ddBrian Wellington if (tresult != ISC_R_SUCCESS)
b266f8fc42702debc6bd89365273223fa89cd8ddBrian Wellington isc_mem_put(mctx, ansname,
b266f8fc42702debc6bd89365273223fa89cd8ddBrian Wellington sizeof(*ansname));
b266f8fc42702debc6bd89365273223fa89cd8ddBrian Wellington }
b266f8fc42702debc6bd89365273223fa89cd8ddBrian Wellington if (tresult != ISC_R_SUCCESS)
b266f8fc42702debc6bd89365273223fa89cd8ddBrian Wellington result = tresult;
b266f8fc42702debc6bd89365273223fa89cd8ddBrian Wellington }
b266f8fc42702debc6bd89365273223fa89cd8ddBrian Wellington
b266f8fc42702debc6bd89365273223fa89cd8ddBrian Wellington switch (result) {
b266f8fc42702debc6bd89365273223fa89cd8ddBrian Wellington case ISC_R_SUCCESS:
cefd68008fbba3488a077052ae62aa12b6de502bMichael Sawyer send_event = ISC_TRUE;
cefd68008fbba3488a077052ae62aa12b6de502bMichael Sawyer /*
cefd68008fbba3488a077052ae62aa12b6de502bMichael Sawyer * This case is handled in the main line below.
cefd68008fbba3488a077052ae62aa12b6de502bMichael Sawyer */
cefd68008fbba3488a077052ae62aa12b6de502bMichael Sawyer break;
cefd68008fbba3488a077052ae62aa12b6de502bMichael Sawyer case DNS_R_CNAME:
cefd68008fbba3488a077052ae62aa12b6de502bMichael Sawyer /*
cefd68008fbba3488a077052ae62aa12b6de502bMichael Sawyer * Add the CNAME to the answer list.
b266f8fc42702debc6bd89365273223fa89cd8ddBrian Wellington */
b266f8fc42702debc6bd89365273223fa89cd8ddBrian Wellington trdataset = rctx->rdataset;
b266f8fc42702debc6bd89365273223fa89cd8ddBrian Wellington ISC_LIST_APPEND(ansname->list, rctx->rdataset, link);
cefd68008fbba3488a077052ae62aa12b6de502bMichael Sawyer rctx->rdataset = NULL;
38cf6e52ce4b33795713388824b69d78e430b115Michael Sawyer if (rctx->sigrdataset != NULL) {
cefd68008fbba3488a077052ae62aa12b6de502bMichael Sawyer ISC_LIST_APPEND(ansname->list,
6fe03d6c83ec02d4494edc870f5e892d419b6885Michael Sawyer rctx->sigrdataset, link);
f8fec75ee8f429821137aee090f56ab678404a56Michael Sawyer rctx->sigrdataset = NULL;
6c6a62933dda281cb9193de1d54d4c9e74515f5aMichael Sawyer }
88301f84d1391e96ec87a9a308aa18f45553a56bAndreas Gustafsson ISC_LIST_APPEND(rctx->namelist, ansname, link);
6c6a62933dda281cb9193de1d54d4c9e74515f5aMichael Sawyer ansname = NULL;
ad7bb5bff3e796f5648835bf87a203d23d8319e4David Lawrence
88301f84d1391e96ec87a9a308aa18f45553a56bAndreas Gustafsson /*
f8fec75ee8f429821137aee090f56ab678404a56Michael Sawyer * Copy the CNAME's target into the lookup's
cefd68008fbba3488a077052ae62aa12b6de502bMichael Sawyer * query name and start over.
cefd68008fbba3488a077052ae62aa12b6de502bMichael Sawyer */
b266f8fc42702debc6bd89365273223fa89cd8ddBrian Wellington tresult = dns_rdataset_first(trdataset);
b266f8fc42702debc6bd89365273223fa89cd8ddBrian Wellington if (tresult != ISC_R_SUCCESS)
b266f8fc42702debc6bd89365273223fa89cd8ddBrian Wellington goto done;
b266f8fc42702debc6bd89365273223fa89cd8ddBrian Wellington dns_rdataset_current(trdataset, &rdata);
b266f8fc42702debc6bd89365273223fa89cd8ddBrian Wellington tresult = dns_rdata_tostruct(&rdata, &cname, NULL);
b266f8fc42702debc6bd89365273223fa89cd8ddBrian Wellington dns_rdata_reset(&rdata);
b266f8fc42702debc6bd89365273223fa89cd8ddBrian Wellington if (tresult != ISC_R_SUCCESS)
cefd68008fbba3488a077052ae62aa12b6de502bMichael Sawyer goto done;
b266f8fc42702debc6bd89365273223fa89cd8ddBrian Wellington tresult = dns_name_copy(&cname.cname, name, NULL);
cefd68008fbba3488a077052ae62aa12b6de502bMichael Sawyer dns_rdata_freestruct(&cname);
37e6e0ca1337351642798b1a6aa24ae40bf86399Andreas Gustafsson if (tresult == ISC_R_SUCCESS)
37e6e0ca1337351642798b1a6aa24ae40bf86399Andreas Gustafsson want_restart = ISC_TRUE;
b266f8fc42702debc6bd89365273223fa89cd8ddBrian Wellington else
b266f8fc42702debc6bd89365273223fa89cd8ddBrian Wellington result = tresult;
aa6054ec74819f754bcf19442ca9b39d948171adMichael Sawyer goto done;
db8b100cae62de849ecf4ba9ad3be811fb375b53Michael Sawyer case DNS_R_DNAME:
40f53fa8d9c6a4fc38c0014495e7a42b08f52481David Lawrence /*
cefd68008fbba3488a077052ae62aa12b6de502bMichael Sawyer * Add the DNAME to the answer list.
cefd68008fbba3488a077052ae62aa12b6de502bMichael Sawyer */
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
suspend(isc_task_t *task, isc_event_t *event) {
isc_appctx_t *actx = event->ev_arg;
UNUSED(task);
isc_app_ctxsuspend(actx);
isc_event_free(&event);
}
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;
isc_result_t result;
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);
/*
* We may or may not be running. isc__appctx_onrun will
* fail if we are currently running otherwise we post a
* action to call isc_app_ctxsuspend when we do start
* running.
*/
result = isc_app_ctxonrun(resarg->actx, resarg->client->mctx,
task, suspend, resarg->actx);
if (result == ISC_R_ALREADYRUNNING)
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);
*transp = (dns_clientrestrans_t *)rctx;
client_resfind(rctx, NULL);
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;
}
}