2009-09-01 00:22:28 +00:00
|
|
|
/*
|
2018-02-23 09:53:12 +01:00
|
|
|
* Copyright (C) Internet Systems Consortium, Inc. ("ISC")
|
2009-09-01 00:22:28 +00:00
|
|
|
*
|
2016-06-27 14:56:38 +10:00
|
|
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
2018-02-23 09:53:12 +01:00
|
|
|
*
|
|
|
|
* See the COPYRIGHT file distributed with this work for additional
|
|
|
|
* information regarding copyright ownership.
|
2009-09-01 00:22:28 +00:00
|
|
|
*/
|
|
|
|
|
2018-04-17 08:29:14 -07:00
|
|
|
#include <stdbool.h>
|
2010-05-19 07:13:15 +00:00
|
|
|
#include <stddef.h>
|
|
|
|
|
2009-09-01 00:22:28 +00:00
|
|
|
#include <isc/app.h>
|
2014-02-16 13:03:17 -08:00
|
|
|
#include <isc/buffer.h>
|
2019-12-20 11:37:11 -08:00
|
|
|
#include <isc/md.h>
|
2009-09-01 00:22:28 +00:00
|
|
|
#include <isc/mem.h>
|
|
|
|
#include <isc/mutex.h>
|
2019-03-08 13:13:32 +01:00
|
|
|
#include <isc/portset.h>
|
2019-08-06 17:35:20 +02:00
|
|
|
#include <isc/refcount.h>
|
2015-08-17 18:26:44 -07:00
|
|
|
#include <isc/safe.h>
|
2009-09-01 00:22:28 +00:00
|
|
|
#include <isc/sockaddr.h>
|
|
|
|
#include <isc/socket.h>
|
|
|
|
#include <isc/task.h>
|
|
|
|
#include <isc/timer.h>
|
|
|
|
#include <isc/util.h>
|
|
|
|
|
|
|
|
#include <dns/adb.h>
|
|
|
|
#include <dns/client.h>
|
|
|
|
#include <dns/db.h>
|
|
|
|
#include <dns/dispatch.h>
|
|
|
|
#include <dns/events.h>
|
|
|
|
#include <dns/forward.h>
|
|
|
|
#include <dns/keytable.h>
|
|
|
|
#include <dns/message.h>
|
|
|
|
#include <dns/name.h>
|
|
|
|
#include <dns/rdata.h>
|
|
|
|
#include <dns/rdatalist.h>
|
|
|
|
#include <dns/rdataset.h>
|
|
|
|
#include <dns/rdatatype.h>
|
|
|
|
#include <dns/rdatasetiter.h>
|
|
|
|
#include <dns/rdatastruct.h>
|
|
|
|
#include <dns/request.h>
|
|
|
|
#include <dns/resolver.h>
|
|
|
|
#include <dns/result.h>
|
|
|
|
#include <dns/tsec.h>
|
|
|
|
#include <dns/tsig.h>
|
|
|
|
#include <dns/view.h>
|
|
|
|
|
|
|
|
#include <dst/dst.h>
|
|
|
|
|
|
|
|
#define DNS_CLIENT_MAGIC ISC_MAGIC('D', 'N', 'S', 'c')
|
|
|
|
#define DNS_CLIENT_VALID(c) ISC_MAGIC_VALID(c, DNS_CLIENT_MAGIC)
|
|
|
|
|
|
|
|
#define RCTX_MAGIC ISC_MAGIC('R', 'c', 't', 'x')
|
|
|
|
#define RCTX_VALID(c) ISC_MAGIC_VALID(c, RCTX_MAGIC)
|
|
|
|
|
|
|
|
#define REQCTX_MAGIC ISC_MAGIC('R', 'q', 'c', 'x')
|
|
|
|
#define REQCTX_VALID(c) ISC_MAGIC_VALID(c, REQCTX_MAGIC)
|
|
|
|
|
|
|
|
#define UCTX_MAGIC ISC_MAGIC('U', 'c', 't', 'x')
|
|
|
|
#define UCTX_VALID(c) ISC_MAGIC_VALID(c, UCTX_MAGIC)
|
|
|
|
|
|
|
|
#define MAX_RESTARTS 16
|
|
|
|
|
2014-02-18 22:36:14 -08:00
|
|
|
#ifdef TUNE_LARGE
|
|
|
|
#define RESOLVER_NTASKS 523
|
|
|
|
#else
|
|
|
|
#define RESOLVER_NTASKS 31
|
|
|
|
#endif /* TUNE_LARGE */
|
|
|
|
|
2019-09-18 19:45:20 -07:00
|
|
|
#define CHECK(r) \
|
|
|
|
do { \
|
|
|
|
result = (r); \
|
|
|
|
if (result != ISC_R_SUCCESS) \
|
|
|
|
goto cleanup; \
|
|
|
|
} while (0)
|
|
|
|
|
2009-09-01 00:22:28 +00:00
|
|
|
/*%
|
|
|
|
* DNS client object
|
|
|
|
*/
|
|
|
|
struct dns_client {
|
|
|
|
/* Unlocked */
|
|
|
|
unsigned int magic;
|
|
|
|
unsigned int attributes;
|
|
|
|
isc_mutex_t lock;
|
|
|
|
isc_mem_t *mctx;
|
|
|
|
isc_appctx_t *actx;
|
|
|
|
isc_taskmgr_t *taskmgr;
|
|
|
|
isc_task_t *task;
|
|
|
|
isc_socketmgr_t *socketmgr;
|
|
|
|
isc_timermgr_t *timermgr;
|
|
|
|
dns_dispatchmgr_t *dispatchmgr;
|
|
|
|
dns_dispatch_t *dispatchv4;
|
|
|
|
dns_dispatch_t *dispatchv6;
|
|
|
|
|
|
|
|
unsigned int update_timeout;
|
|
|
|
unsigned int update_udptimeout;
|
|
|
|
unsigned int update_udpretries;
|
|
|
|
unsigned int find_timeout;
|
|
|
|
unsigned int find_udpretries;
|
|
|
|
|
2019-08-06 17:35:20 +02:00
|
|
|
isc_refcount_t references;
|
|
|
|
|
2009-09-01 00:22:28 +00:00
|
|
|
/* Locked */
|
|
|
|
dns_viewlist_t viewlist;
|
|
|
|
ISC_LIST(struct resctx) resctxs;
|
|
|
|
ISC_LIST(struct reqctx) reqctxs;
|
|
|
|
ISC_LIST(struct updatectx) updatectxs;
|
|
|
|
};
|
|
|
|
|
|
|
|
/*%
|
|
|
|
* Timeout/retry constants for dynamic update borrowed from nsupdate
|
|
|
|
*/
|
|
|
|
#define DEF_UPDATE_TIMEOUT 300
|
|
|
|
#define MIN_UPDATE_TIMEOUT 30
|
|
|
|
#define DEF_UPDATE_UDPTIMEOUT 3
|
|
|
|
#define DEF_UPDATE_UDPRETRIES 3
|
|
|
|
|
|
|
|
#define DEF_FIND_TIMEOUT 5
|
|
|
|
#define DEF_FIND_UDPRETRIES 3
|
|
|
|
|
|
|
|
#define DNS_CLIENTATTR_OWNCTX 0x01
|
|
|
|
|
|
|
|
/*%
|
|
|
|
* Internal state for a single name resolution procedure
|
|
|
|
*/
|
|
|
|
typedef struct resctx {
|
|
|
|
/* Unlocked */
|
|
|
|
unsigned int magic;
|
|
|
|
isc_mutex_t lock;
|
|
|
|
dns_client_t *client;
|
2019-04-17 12:48:21 +10:00
|
|
|
bool want_dnssec;
|
|
|
|
bool want_validation;
|
|
|
|
bool want_cdflag;
|
|
|
|
bool want_tcp;
|
2009-09-01 00:22:28 +00:00
|
|
|
|
|
|
|
/* Locked */
|
|
|
|
ISC_LINK(struct resctx) link;
|
|
|
|
isc_task_t *task;
|
|
|
|
dns_view_t *view;
|
|
|
|
unsigned int restarts;
|
|
|
|
dns_fixedname_t name;
|
|
|
|
dns_rdatatype_t type;
|
|
|
|
dns_fetch_t *fetch;
|
|
|
|
dns_namelist_t namelist;
|
|
|
|
isc_result_t result;
|
|
|
|
dns_clientresevent_t *event;
|
2019-04-17 12:48:21 +10:00
|
|
|
bool canceled;
|
2009-09-01 00:22:28 +00:00
|
|
|
dns_rdataset_t *rdataset;
|
|
|
|
dns_rdataset_t *sigrdataset;
|
|
|
|
} resctx_t;
|
|
|
|
|
|
|
|
/*%
|
|
|
|
* Argument of an internal event for synchronous name resolution.
|
|
|
|
*/
|
|
|
|
typedef struct resarg {
|
|
|
|
/* Unlocked */
|
|
|
|
isc_appctx_t *actx;
|
|
|
|
dns_client_t *client;
|
|
|
|
isc_mutex_t lock;
|
|
|
|
|
|
|
|
/* Locked */
|
|
|
|
isc_result_t result;
|
|
|
|
isc_result_t vresult;
|
|
|
|
dns_namelist_t *namelist;
|
|
|
|
dns_clientrestrans_t *trans;
|
2019-04-17 12:48:21 +10:00
|
|
|
bool canceled;
|
2009-09-01 00:22:28 +00:00
|
|
|
} resarg_t;
|
|
|
|
|
|
|
|
/*%
|
|
|
|
* Internal state for a single DNS request
|
|
|
|
*/
|
|
|
|
typedef struct reqctx {
|
|
|
|
/* Unlocked */
|
|
|
|
unsigned int magic;
|
|
|
|
isc_mutex_t lock;
|
|
|
|
dns_client_t *client;
|
|
|
|
unsigned int parseoptions;
|
|
|
|
|
|
|
|
/* Locked */
|
|
|
|
ISC_LINK(struct reqctx) link;
|
2019-04-17 12:48:21 +10:00
|
|
|
bool canceled;
|
2009-09-01 00:22:28 +00:00
|
|
|
dns_tsigkey_t *tsigkey;
|
|
|
|
dns_request_t *request;
|
|
|
|
dns_clientreqevent_t *event;
|
|
|
|
} reqctx_t;
|
|
|
|
|
|
|
|
/*%
|
|
|
|
* Argument of an internal event for synchronous DNS request.
|
|
|
|
*/
|
|
|
|
typedef struct reqarg {
|
|
|
|
/* Unlocked */
|
|
|
|
isc_appctx_t *actx;
|
|
|
|
dns_client_t *client;
|
|
|
|
isc_mutex_t lock;
|
|
|
|
|
|
|
|
/* Locked */
|
|
|
|
isc_result_t result;
|
|
|
|
dns_clientreqtrans_t *trans;
|
2019-04-17 12:48:21 +10:00
|
|
|
bool canceled;
|
2009-09-01 00:22:28 +00:00
|
|
|
} reqarg_t;
|
|
|
|
|
|
|
|
/*%
|
|
|
|
* Argument of an internal event for synchronous name resolution.
|
|
|
|
*/
|
|
|
|
typedef struct updatearg {
|
|
|
|
/* Unlocked */
|
|
|
|
isc_appctx_t *actx;
|
|
|
|
dns_client_t *client;
|
|
|
|
isc_mutex_t lock;
|
|
|
|
|
|
|
|
/* Locked */
|
|
|
|
isc_result_t result;
|
|
|
|
dns_clientupdatetrans_t *trans;
|
2019-04-17 12:48:21 +10:00
|
|
|
bool canceled;
|
2009-09-01 00:22:28 +00:00
|
|
|
} updatearg_t;
|
|
|
|
|
|
|
|
/*%
|
|
|
|
* Internal state for a single dynamic update procedure
|
|
|
|
*/
|
|
|
|
typedef struct updatectx {
|
|
|
|
/* Unlocked */
|
|
|
|
unsigned int magic;
|
|
|
|
isc_mutex_t lock;
|
|
|
|
dns_client_t *client;
|
2019-04-17 12:48:21 +10:00
|
|
|
bool want_tcp;
|
2009-09-01 00:22:28 +00:00
|
|
|
|
|
|
|
/* Locked */
|
|
|
|
dns_request_t *updatereq;
|
|
|
|
dns_request_t *soareq;
|
|
|
|
dns_clientrestrans_t *restrans;
|
|
|
|
dns_clientrestrans_t *restrans2;
|
2019-04-17 12:48:21 +10:00
|
|
|
bool canceled;
|
2009-09-01 00:22:28 +00:00
|
|
|
|
|
|
|
/* Task Locked */
|
|
|
|
ISC_LINK(struct updatectx) link;
|
|
|
|
dns_clientupdatestate_t state;
|
|
|
|
dns_rdataclass_t rdclass;
|
|
|
|
dns_view_t *view;
|
|
|
|
dns_message_t *updatemsg;
|
|
|
|
dns_message_t *soaquery;
|
|
|
|
dns_clientupdateevent_t *event;
|
|
|
|
dns_tsigkey_t *tsigkey;
|
|
|
|
dst_key_t *sig0key;
|
|
|
|
dns_name_t *firstname;
|
|
|
|
dns_name_t soaqname;
|
|
|
|
dns_fixedname_t zonefname;
|
|
|
|
dns_name_t *zonename;
|
|
|
|
isc_sockaddrlist_t servers;
|
|
|
|
unsigned int nservers;
|
|
|
|
isc_sockaddr_t *currentserver;
|
|
|
|
struct updatectx *bp4;
|
|
|
|
struct updatectx *bp6;
|
|
|
|
} updatectx_t;
|
|
|
|
|
|
|
|
static isc_result_t request_soa(updatectx_t *uctx);
|
|
|
|
static void client_resfind(resctx_t *rctx, dns_fetchevent_t *event);
|
|
|
|
static isc_result_t send_update(updatectx_t *uctx);
|
|
|
|
|
2019-03-08 13:13:32 +01:00
|
|
|
/*
|
|
|
|
* Try honoring the operating system's preferred ephemeral port range.
|
|
|
|
*/
|
|
|
|
static isc_result_t
|
|
|
|
setsourceports(isc_mem_t *mctx, dns_dispatchmgr_t *manager) {
|
|
|
|
isc_portset_t *v4portset = NULL, *v6portset = NULL;
|
|
|
|
in_port_t udpport_low, udpport_high;
|
|
|
|
isc_result_t result;
|
|
|
|
|
|
|
|
result = isc_portset_create(mctx, &v4portset);
|
|
|
|
if (result != ISC_R_SUCCESS) {
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
result = isc_net_getudpportrange(AF_INET, &udpport_low, &udpport_high);
|
|
|
|
if (result != ISC_R_SUCCESS) {
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
isc_portset_addrange(v4portset, udpport_low, udpport_high);
|
|
|
|
|
|
|
|
result = isc_portset_create(mctx, &v6portset);
|
|
|
|
if (result != ISC_R_SUCCESS) {
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
result = isc_net_getudpportrange(AF_INET6, &udpport_low, &udpport_high);
|
|
|
|
if (result != ISC_R_SUCCESS) {
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
isc_portset_addrange(v6portset, udpport_low, udpport_high);
|
|
|
|
|
|
|
|
result = dns_dispatchmgr_setavailports(manager, v4portset, v6portset);
|
|
|
|
|
|
|
|
cleanup:
|
|
|
|
if (v4portset != NULL) {
|
|
|
|
isc_portset_destroy(mctx, &v4portset);
|
|
|
|
}
|
|
|
|
if (v6portset != NULL) {
|
|
|
|
isc_portset_destroy(mctx, &v6portset);
|
|
|
|
}
|
|
|
|
|
|
|
|
return (result);
|
|
|
|
}
|
|
|
|
|
2009-09-01 00:22:28 +00:00
|
|
|
static isc_result_t
|
|
|
|
getudpdispatch(int family, dns_dispatchmgr_t *dispatchmgr,
|
|
|
|
isc_socketmgr_t *socketmgr, isc_taskmgr_t *taskmgr,
|
2018-04-17 08:29:14 -07:00
|
|
|
bool is_shared, dns_dispatch_t **dispp,
|
2016-12-30 15:45:08 +11:00
|
|
|
const isc_sockaddr_t *localaddr)
|
2009-09-01 00:22:28 +00:00
|
|
|
{
|
|
|
|
unsigned int attrs, attrmask;
|
|
|
|
dns_dispatch_t *disp;
|
|
|
|
unsigned buffersize, maxbuffers, maxrequests, buckets, increment;
|
|
|
|
isc_result_t result;
|
2013-11-13 10:52:22 -08:00
|
|
|
isc_sockaddr_t anyaddr;
|
2009-09-01 00:22:28 +00:00
|
|
|
|
|
|
|
attrs = 0;
|
|
|
|
attrs |= DNS_DISPATCHATTR_UDP;
|
|
|
|
switch (family) {
|
|
|
|
case AF_INET:
|
|
|
|
attrs |= DNS_DISPATCHATTR_IPV4;
|
|
|
|
break;
|
|
|
|
case AF_INET6:
|
|
|
|
attrs |= DNS_DISPATCHATTR_IPV6;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
INSIST(0);
|
2018-11-07 15:00:07 +07:00
|
|
|
ISC_UNREACHABLE();
|
2009-09-01 00:22:28 +00:00
|
|
|
}
|
|
|
|
attrmask = 0;
|
|
|
|
attrmask |= DNS_DISPATCHATTR_UDP;
|
|
|
|
attrmask |= DNS_DISPATCHATTR_TCP;
|
|
|
|
attrmask |= DNS_DISPATCHATTR_IPV4;
|
|
|
|
attrmask |= DNS_DISPATCHATTR_IPV6;
|
|
|
|
|
2013-11-13 10:52:22 -08:00
|
|
|
if (localaddr == NULL) {
|
2016-12-30 15:45:08 +11:00
|
|
|
isc_sockaddr_anyofpf(&anyaddr, family);
|
2013-11-13 10:52:22 -08:00
|
|
|
localaddr = &anyaddr;
|
|
|
|
}
|
2009-09-01 00:22:28 +00:00
|
|
|
|
|
|
|
buffersize = 4096;
|
|
|
|
maxbuffers = is_shared ? 1000 : 8;
|
|
|
|
maxrequests = 32768;
|
|
|
|
buckets = is_shared ? 16411 : 3;
|
|
|
|
increment = is_shared ? 16433 : 5;
|
|
|
|
|
|
|
|
disp = NULL;
|
|
|
|
result = dns_dispatch_getudp(dispatchmgr, socketmgr,
|
2013-11-13 10:52:22 -08:00
|
|
|
taskmgr, localaddr,
|
2009-09-01 00:22:28 +00:00
|
|
|
buffersize, maxbuffers, maxrequests,
|
|
|
|
buckets, increment,
|
|
|
|
attrs, attrmask, &disp);
|
|
|
|
if (result == ISC_R_SUCCESS)
|
|
|
|
*dispp = disp;
|
|
|
|
|
|
|
|
return (result);
|
|
|
|
}
|
|
|
|
|
|
|
|
static isc_result_t
|
2014-02-16 13:03:17 -08:00
|
|
|
createview(isc_mem_t *mctx, dns_rdataclass_t rdclass,
|
|
|
|
unsigned int options, isc_taskmgr_t *taskmgr,
|
|
|
|
unsigned int ntasks, isc_socketmgr_t *socketmgr,
|
|
|
|
isc_timermgr_t *timermgr, dns_dispatchmgr_t *dispatchmgr,
|
|
|
|
dns_dispatch_t *dispatchv4, dns_dispatch_t *dispatchv6,
|
|
|
|
dns_view_t **viewp)
|
2009-09-01 00:22:28 +00:00
|
|
|
{
|
|
|
|
isc_result_t result;
|
|
|
|
dns_view_t *view = NULL;
|
|
|
|
const char *dbtype;
|
|
|
|
|
|
|
|
result = dns_view_create(mctx, rdclass, DNS_CLIENTVIEW_NAME, &view);
|
|
|
|
if (result != ISC_R_SUCCESS)
|
2009-09-03 21:45:46 +00:00
|
|
|
return (result);
|
|
|
|
|
2009-10-27 22:46:13 +00:00
|
|
|
/* Initialize view security roots */
|
|
|
|
result = dns_view_initsecroots(view, mctx);
|
|
|
|
if (result != ISC_R_SUCCESS) {
|
|
|
|
dns_view_detach(&view);
|
|
|
|
return (result);
|
2009-09-03 21:45:46 +00:00
|
|
|
}
|
2009-09-01 00:22:28 +00:00
|
|
|
|
2014-02-16 13:03:17 -08:00
|
|
|
result = dns_view_createresolver(view, taskmgr, ntasks, 1,
|
|
|
|
socketmgr, timermgr, 0,
|
|
|
|
dispatchmgr, dispatchv4, dispatchv6);
|
2009-09-01 00:22:28 +00:00
|
|
|
if (result != ISC_R_SUCCESS) {
|
|
|
|
dns_view_detach(&view);
|
|
|
|
return (result);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Set cache DB.
|
|
|
|
* XXX: it may be better if specific DB implementations can be
|
|
|
|
* specified via some configuration knob.
|
|
|
|
*/
|
|
|
|
if ((options & DNS_CLIENTCREATEOPT_USECACHE) != 0)
|
|
|
|
dbtype = "rbt";
|
|
|
|
else
|
|
|
|
dbtype = "ecdb";
|
|
|
|
result = dns_db_create(mctx, dbtype, dns_rootname, dns_dbtype_cache,
|
|
|
|
rdclass, 0, NULL, &view->cachedb);
|
|
|
|
if (result != ISC_R_SUCCESS) {
|
|
|
|
dns_view_detach(&view);
|
|
|
|
return (result);
|
|
|
|
}
|
|
|
|
|
|
|
|
*viewp = view;
|
|
|
|
return (ISC_R_SUCCESS);
|
|
|
|
}
|
|
|
|
|
|
|
|
isc_result_t
|
|
|
|
dns_client_create(dns_client_t **clientp, unsigned int options) {
|
|
|
|
isc_result_t result;
|
|
|
|
isc_mem_t *mctx = NULL;
|
|
|
|
isc_appctx_t *actx = NULL;
|
|
|
|
isc_taskmgr_t *taskmgr = NULL;
|
|
|
|
isc_socketmgr_t *socketmgr = NULL;
|
|
|
|
isc_timermgr_t *timermgr = NULL;
|
2013-04-03 17:27:40 +11:00
|
|
|
#if 0
|
|
|
|
/* XXXMPA add debug logging support */
|
|
|
|
isc_log_t *lctx = NULL;
|
|
|
|
isc_logconfig_t *logconfig = NULL;
|
|
|
|
unsigned int logdebuglevel = 0;
|
|
|
|
#endif
|
2009-09-01 00:22:28 +00:00
|
|
|
|
2019-09-05 18:40:57 +02:00
|
|
|
isc_mem_create(&mctx);
|
2009-09-01 00:22:28 +00:00
|
|
|
result = isc_appctx_create(mctx, &actx);
|
|
|
|
if (result != ISC_R_SUCCESS)
|
|
|
|
goto cleanup;
|
|
|
|
result = isc_app_ctxstart(actx);
|
|
|
|
if (result != ISC_R_SUCCESS)
|
|
|
|
goto cleanup;
|
2019-05-13 20:58:20 +07:00
|
|
|
result = isc_taskmgr_createinctx(mctx, 1, 0, &taskmgr);
|
2009-09-01 00:22:28 +00:00
|
|
|
if (result != ISC_R_SUCCESS)
|
|
|
|
goto cleanup;
|
2019-05-13 20:58:20 +07:00
|
|
|
result = isc_socketmgr_createinctx(mctx, &socketmgr);
|
2009-09-01 00:22:28 +00:00
|
|
|
if (result != ISC_R_SUCCESS)
|
|
|
|
goto cleanup;
|
2019-05-13 20:58:20 +07:00
|
|
|
result = isc_timermgr_createinctx(mctx, &timermgr);
|
2009-09-01 00:22:28 +00:00
|
|
|
if (result != ISC_R_SUCCESS)
|
|
|
|
goto cleanup;
|
2013-04-03 17:27:40 +11:00
|
|
|
#if 0
|
2013-04-03 23:46:07 +00:00
|
|
|
result = isc_log_create(mctx, &lctx, &logconfig);
|
2013-04-03 17:27:40 +11:00
|
|
|
if (result != ISC_R_SUCCESS)
|
|
|
|
goto cleanup;
|
2013-04-03 23:46:07 +00:00
|
|
|
isc_log_setcontext(lctx);
|
|
|
|
dns_log_init(lctx);
|
|
|
|
dns_log_setcontext(lctx);
|
|
|
|
result = isc_log_usechannel(logconfig, "default_debug", NULL, NULL);
|
2013-04-03 17:27:40 +11:00
|
|
|
if (result != ISC_R_SUCCESS)
|
|
|
|
goto cleanup;
|
2013-04-03 23:46:07 +00:00
|
|
|
isc_log_setdebuglevel(lctx, logdebuglevel);
|
2013-04-03 17:27:40 +11:00
|
|
|
#endif
|
2009-09-01 00:22:28 +00:00
|
|
|
result = dns_client_createx(mctx, actx, taskmgr, socketmgr, timermgr,
|
2018-04-03 13:15:16 +02:00
|
|
|
options, clientp, NULL, NULL);
|
2009-09-01 00:22:28 +00:00
|
|
|
if (result != ISC_R_SUCCESS)
|
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
(*clientp)->attributes |= DNS_CLIENTATTR_OWNCTX;
|
|
|
|
|
|
|
|
/* client has its own reference to mctx, so we can detach it here */
|
|
|
|
isc_mem_detach(&mctx);
|
|
|
|
|
|
|
|
return (ISC_R_SUCCESS);
|
|
|
|
|
|
|
|
cleanup:
|
2010-04-13 19:06:48 +00:00
|
|
|
if (taskmgr != NULL)
|
|
|
|
isc_taskmgr_destroy(&taskmgr);
|
2009-09-01 00:22:28 +00:00
|
|
|
if (timermgr != NULL)
|
|
|
|
isc_timermgr_destroy(&timermgr);
|
|
|
|
if (socketmgr != NULL)
|
|
|
|
isc_socketmgr_destroy(&socketmgr);
|
|
|
|
if (actx != NULL)
|
|
|
|
isc_appctx_destroy(&actx);
|
|
|
|
isc_mem_detach(&mctx);
|
|
|
|
|
|
|
|
return (result);
|
|
|
|
}
|
|
|
|
|
|
|
|
isc_result_t
|
2018-04-03 13:15:16 +02:00
|
|
|
dns_client_createx(isc_mem_t *mctx, isc_appctx_t *actx,
|
|
|
|
isc_taskmgr_t *taskmgr, isc_socketmgr_t *socketmgr,
|
|
|
|
isc_timermgr_t *timermgr, unsigned int options,
|
|
|
|
dns_client_t **clientp, const isc_sockaddr_t *localaddr4,
|
|
|
|
const isc_sockaddr_t *localaddr6)
|
2009-09-01 00:22:28 +00:00
|
|
|
{
|
|
|
|
dns_client_t *client;
|
|
|
|
isc_result_t result;
|
|
|
|
dns_dispatchmgr_t *dispatchmgr = NULL;
|
|
|
|
dns_dispatch_t *dispatchv4 = NULL;
|
|
|
|
dns_dispatch_t *dispatchv6 = NULL;
|
|
|
|
dns_view_t *view = NULL;
|
|
|
|
|
|
|
|
REQUIRE(mctx != NULL);
|
|
|
|
REQUIRE(taskmgr != NULL);
|
|
|
|
REQUIRE(timermgr != NULL);
|
|
|
|
REQUIRE(socketmgr != NULL);
|
|
|
|
REQUIRE(clientp != NULL && *clientp == NULL);
|
|
|
|
|
|
|
|
client = isc_mem_get(mctx, sizeof(*client));
|
|
|
|
|
2018-11-16 15:33:22 +01:00
|
|
|
isc_mutex_init(&client->lock);
|
2009-09-01 00:22:28 +00:00
|
|
|
|
|
|
|
client->actx = actx;
|
|
|
|
client->taskmgr = taskmgr;
|
|
|
|
client->socketmgr = socketmgr;
|
|
|
|
client->timermgr = timermgr;
|
|
|
|
|
|
|
|
client->task = NULL;
|
2018-11-21 09:50:50 +00:00
|
|
|
result = isc_task_create(client->taskmgr, 0, &client->task);
|
2019-08-06 17:35:20 +02:00
|
|
|
if (result != ISC_R_SUCCESS) {
|
|
|
|
goto cleanup_lock;
|
|
|
|
}
|
2009-09-01 00:22:28 +00:00
|
|
|
|
2018-04-22 14:56:28 +02:00
|
|
|
result = dns_dispatchmgr_create(mctx, &dispatchmgr);
|
2009-09-01 00:22:28 +00:00
|
|
|
if (result != ISC_R_SUCCESS)
|
2019-08-06 17:35:20 +02:00
|
|
|
goto cleanup_task;
|
2009-09-01 00:22:28 +00:00
|
|
|
client->dispatchmgr = dispatchmgr;
|
2019-03-08 13:13:32 +01:00
|
|
|
(void)setsourceports(mctx, dispatchmgr);
|
2009-09-01 00:22:28 +00:00
|
|
|
|
2013-11-13 10:52:22 -08:00
|
|
|
/*
|
|
|
|
* If only one address family is specified, use it.
|
|
|
|
* If neither family is specified, or if both are, use both.
|
|
|
|
*/
|
2010-04-13 19:06:48 +00:00
|
|
|
client->dispatchv4 = NULL;
|
2013-11-13 10:52:22 -08:00
|
|
|
if (localaddr4 != NULL || localaddr6 == NULL) {
|
|
|
|
result = getudpdispatch(AF_INET, dispatchmgr, socketmgr,
|
2018-04-17 08:29:14 -07:00
|
|
|
taskmgr, true,
|
2013-11-13 10:52:22 -08:00
|
|
|
&dispatchv4, localaddr4);
|
2019-08-06 17:35:20 +02:00
|
|
|
if (result == ISC_R_SUCCESS) {
|
2013-11-13 10:52:22 -08:00
|
|
|
client->dispatchv4 = dispatchv4;
|
2019-08-06 17:35:20 +02:00
|
|
|
}
|
2013-11-13 10:52:22 -08:00
|
|
|
}
|
|
|
|
|
2010-04-13 19:06:48 +00:00
|
|
|
client->dispatchv6 = NULL;
|
2013-11-13 10:52:22 -08:00
|
|
|
if (localaddr6 != NULL || localaddr4 == NULL) {
|
|
|
|
result = getudpdispatch(AF_INET6, dispatchmgr, socketmgr,
|
2018-04-17 08:29:14 -07:00
|
|
|
taskmgr, true,
|
2013-11-13 10:52:22 -08:00
|
|
|
&dispatchv6, localaddr6);
|
2019-08-06 17:35:20 +02:00
|
|
|
if (result == ISC_R_SUCCESS) {
|
2013-11-13 10:52:22 -08:00
|
|
|
client->dispatchv6 = dispatchv6;
|
2019-08-06 17:35:20 +02:00
|
|
|
}
|
2013-11-13 10:52:22 -08:00
|
|
|
}
|
2010-04-13 19:06:48 +00:00
|
|
|
|
|
|
|
/* We need at least one of the dispatchers */
|
|
|
|
if (dispatchv4 == NULL && dispatchv6 == NULL) {
|
|
|
|
INSIST(result != ISC_R_SUCCESS);
|
2019-08-06 17:35:20 +02:00
|
|
|
goto cleanup_dispatchmgr;
|
2010-04-13 19:06:48 +00:00
|
|
|
}
|
2009-09-01 00:22:28 +00:00
|
|
|
|
2019-08-06 17:35:20 +02:00
|
|
|
isc_refcount_init(&client->references, 1);
|
|
|
|
|
2009-09-01 00:22:28 +00:00
|
|
|
/* Create the default view for class IN */
|
2014-02-18 22:36:14 -08:00
|
|
|
result = createview(mctx, dns_rdataclass_in, options, taskmgr,
|
|
|
|
RESOLVER_NTASKS, socketmgr, timermgr,
|
|
|
|
dispatchmgr, dispatchv4, dispatchv6, &view);
|
2019-08-06 17:35:20 +02:00
|
|
|
if (result != ISC_R_SUCCESS) {
|
|
|
|
goto cleanup_references;
|
|
|
|
}
|
|
|
|
|
2009-09-01 00:22:28 +00:00
|
|
|
ISC_LIST_INIT(client->viewlist);
|
|
|
|
ISC_LIST_APPEND(client->viewlist, view, link);
|
|
|
|
|
|
|
|
dns_view_freeze(view); /* too early? */
|
|
|
|
|
|
|
|
ISC_LIST_INIT(client->resctxs);
|
|
|
|
ISC_LIST_INIT(client->reqctxs);
|
|
|
|
ISC_LIST_INIT(client->updatectxs);
|
|
|
|
|
|
|
|
client->mctx = NULL;
|
|
|
|
isc_mem_attach(mctx, &client->mctx);
|
|
|
|
|
|
|
|
client->update_timeout = DEF_UPDATE_TIMEOUT;
|
|
|
|
client->update_udptimeout = DEF_UPDATE_UDPTIMEOUT;
|
|
|
|
client->update_udpretries = DEF_UPDATE_UDPRETRIES;
|
|
|
|
client->find_timeout = DEF_FIND_TIMEOUT;
|
|
|
|
client->find_udpretries = DEF_FIND_UDPRETRIES;
|
2013-04-03 17:27:40 +11:00
|
|
|
client->attributes = 0;
|
2009-09-01 00:22:28 +00:00
|
|
|
|
|
|
|
client->magic = DNS_CLIENT_MAGIC;
|
|
|
|
|
|
|
|
*clientp = client;
|
|
|
|
|
|
|
|
return (ISC_R_SUCCESS);
|
|
|
|
|
2019-08-06 17:35:20 +02:00
|
|
|
cleanup_references:
|
|
|
|
isc_refcount_decrement(&client->references);
|
|
|
|
isc_refcount_destroy(&client->references);
|
|
|
|
cleanup_dispatchmgr:
|
|
|
|
if (dispatchv4 != NULL) {
|
2009-09-01 00:22:28 +00:00
|
|
|
dns_dispatch_detach(&dispatchv4);
|
2019-08-06 17:35:20 +02:00
|
|
|
}
|
|
|
|
if (dispatchv6 != NULL) {
|
2009-09-01 00:22:28 +00:00
|
|
|
dns_dispatch_detach(&dispatchv6);
|
2019-08-06 17:35:20 +02:00
|
|
|
}
|
|
|
|
dns_dispatchmgr_destroy(&dispatchmgr);
|
|
|
|
cleanup_task:
|
|
|
|
isc_task_detach(&client->task);
|
|
|
|
cleanup_lock:
|
|
|
|
isc_mutex_destroy(&client->lock);
|
2009-09-01 00:22:28 +00:00
|
|
|
isc_mem_put(mctx, client, sizeof(*client));
|
|
|
|
|
|
|
|
return (result);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2019-08-06 17:35:20 +02:00
|
|
|
destroyclient(dns_client_t *client) {
|
2009-09-01 00:22:28 +00:00
|
|
|
dns_view_t *view;
|
|
|
|
|
2019-08-06 17:35:20 +02:00
|
|
|
isc_refcount_destroy(&client->references);
|
|
|
|
|
2009-09-01 00:22:28 +00:00
|
|
|
while ((view = ISC_LIST_HEAD(client->viewlist)) != NULL) {
|
|
|
|
ISC_LIST_UNLINK(client->viewlist, view, link);
|
|
|
|
dns_view_detach(&view);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (client->dispatchv4 != NULL)
|
|
|
|
dns_dispatch_detach(&client->dispatchv4);
|
|
|
|
if (client->dispatchv6 != NULL)
|
|
|
|
dns_dispatch_detach(&client->dispatchv6);
|
|
|
|
|
|
|
|
dns_dispatchmgr_destroy(&client->dispatchmgr);
|
|
|
|
|
|
|
|
isc_task_detach(&client->task);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* If the client has created its own running environments,
|
|
|
|
* destroy them.
|
|
|
|
*/
|
|
|
|
if ((client->attributes & DNS_CLIENTATTR_OWNCTX) != 0) {
|
|
|
|
isc_taskmgr_destroy(&client->taskmgr);
|
|
|
|
isc_timermgr_destroy(&client->timermgr);
|
|
|
|
isc_socketmgr_destroy(&client->socketmgr);
|
|
|
|
|
|
|
|
isc_app_ctxfinish(client->actx);
|
|
|
|
isc_appctx_destroy(&client->actx);
|
|
|
|
}
|
|
|
|
|
2018-11-19 10:31:09 +00:00
|
|
|
isc_mutex_destroy(&client->lock);
|
2009-09-01 00:22:28 +00:00
|
|
|
client->magic = 0;
|
2009-09-02 23:48:03 +00:00
|
|
|
|
2009-09-01 00:22:28 +00:00
|
|
|
isc_mem_putanddetach(&client->mctx, client, sizeof(*client));
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
dns_client_destroy(dns_client_t **clientp) {
|
|
|
|
dns_client_t *client;
|
|
|
|
|
|
|
|
REQUIRE(clientp != NULL);
|
|
|
|
client = *clientp;
|
2019-08-06 17:35:20 +02:00
|
|
|
*clientp = NULL;
|
2009-09-01 00:22:28 +00:00
|
|
|
REQUIRE(DNS_CLIENT_VALID(client));
|
|
|
|
|
2019-08-06 17:35:20 +02:00
|
|
|
if (isc_refcount_decrement(&client->references) == 1) {
|
|
|
|
destroyclient(client);
|
2009-09-01 00:22:28 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
isc_result_t
|
|
|
|
dns_client_setservers(dns_client_t *client, dns_rdataclass_t rdclass,
|
2017-07-21 11:52:24 +10:00
|
|
|
const dns_name_t *name_space, isc_sockaddrlist_t *addrs)
|
2009-09-01 00:22:28 +00:00
|
|
|
{
|
|
|
|
isc_result_t result;
|
|
|
|
dns_view_t *view = NULL;
|
|
|
|
|
|
|
|
REQUIRE(DNS_CLIENT_VALID(client));
|
|
|
|
REQUIRE(addrs != NULL);
|
|
|
|
|
2017-07-21 11:52:24 +10:00
|
|
|
if (name_space == NULL)
|
|
|
|
name_space = dns_rootname;
|
2009-09-01 00:22:28 +00:00
|
|
|
|
|
|
|
LOCK(&client->lock);
|
|
|
|
result = dns_viewlist_find(&client->viewlist, DNS_CLIENTVIEW_NAME,
|
|
|
|
rdclass, &view);
|
|
|
|
if (result != ISC_R_SUCCESS) {
|
|
|
|
UNLOCK(&client->lock);
|
|
|
|
return (result);
|
|
|
|
}
|
|
|
|
UNLOCK(&client->lock);
|
|
|
|
|
2017-07-21 11:52:24 +10:00
|
|
|
result = dns_fwdtable_add(view->fwdtable, name_space, addrs,
|
2009-09-01 00:22:28 +00:00
|
|
|
dns_fwdpolicy_only);
|
|
|
|
|
|
|
|
dns_view_detach(&view);
|
|
|
|
|
|
|
|
return (result);
|
|
|
|
}
|
|
|
|
|
|
|
|
isc_result_t
|
|
|
|
dns_client_clearservers(dns_client_t *client, dns_rdataclass_t rdclass,
|
2017-07-21 11:52:24 +10:00
|
|
|
const dns_name_t *name_space)
|
2009-09-01 00:22:28 +00:00
|
|
|
{
|
|
|
|
isc_result_t result;
|
|
|
|
dns_view_t *view = NULL;
|
|
|
|
|
|
|
|
REQUIRE(DNS_CLIENT_VALID(client));
|
|
|
|
|
2017-07-21 11:52:24 +10:00
|
|
|
if (name_space == NULL)
|
|
|
|
name_space = dns_rootname;
|
2009-09-01 00:22:28 +00:00
|
|
|
|
|
|
|
LOCK(&client->lock);
|
|
|
|
result = dns_viewlist_find(&client->viewlist, DNS_CLIENTVIEW_NAME,
|
|
|
|
rdclass, &view);
|
|
|
|
if (result != ISC_R_SUCCESS) {
|
|
|
|
UNLOCK(&client->lock);
|
|
|
|
return (result);
|
|
|
|
}
|
|
|
|
UNLOCK(&client->lock);
|
|
|
|
|
2017-07-21 11:52:24 +10:00
|
|
|
result = dns_fwdtable_delete(view->fwdtable, name_space);
|
2009-09-01 00:22:28 +00:00
|
|
|
|
|
|
|
dns_view_detach(&view);
|
|
|
|
|
|
|
|
return (result);
|
|
|
|
}
|
|
|
|
|
|
|
|
static isc_result_t
|
|
|
|
getrdataset(isc_mem_t *mctx, dns_rdataset_t **rdatasetp) {
|
|
|
|
dns_rdataset_t *rdataset;
|
|
|
|
|
|
|
|
REQUIRE(mctx != NULL);
|
|
|
|
REQUIRE(rdatasetp != NULL && *rdatasetp == NULL);
|
|
|
|
|
|
|
|
rdataset = isc_mem_get(mctx, sizeof(*rdataset));
|
|
|
|
|
|
|
|
dns_rdataset_init(rdataset);
|
|
|
|
|
|
|
|
*rdatasetp = rdataset;
|
|
|
|
|
|
|
|
return (ISC_R_SUCCESS);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
putrdataset(isc_mem_t *mctx, dns_rdataset_t **rdatasetp) {
|
|
|
|
dns_rdataset_t *rdataset;
|
|
|
|
|
|
|
|
REQUIRE(rdatasetp != NULL);
|
|
|
|
rdataset = *rdatasetp;
|
2020-02-08 04:37:54 -08:00
|
|
|
*rdatasetp = NULL;
|
2009-09-01 00:22:28 +00:00
|
|
|
REQUIRE(rdataset != NULL);
|
|
|
|
|
|
|
|
if (dns_rdataset_isassociated(rdataset))
|
|
|
|
dns_rdataset_disassociate(rdataset);
|
|
|
|
|
|
|
|
isc_mem_put(mctx, rdataset, sizeof(*rdataset));
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
fetch_done(isc_task_t *task, isc_event_t *event) {
|
|
|
|
resctx_t *rctx = event->ev_arg;
|
|
|
|
dns_fetchevent_t *fevent;
|
|
|
|
|
|
|
|
REQUIRE(event->ev_type == DNS_EVENT_FETCHDONE);
|
|
|
|
REQUIRE(RCTX_VALID(rctx));
|
|
|
|
REQUIRE(rctx->task == task);
|
|
|
|
fevent = (dns_fetchevent_t *)event;
|
|
|
|
|
|
|
|
client_resfind(rctx, fevent);
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline isc_result_t
|
|
|
|
start_fetch(resctx_t *rctx) {
|
|
|
|
isc_result_t result;
|
2014-02-16 13:03:17 -08:00
|
|
|
int fopts = 0;
|
2009-09-01 00:22:28 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* The caller must be holding the rctx's lock.
|
|
|
|
*/
|
|
|
|
|
|
|
|
REQUIRE(rctx->fetch == NULL);
|
|
|
|
|
2014-02-16 13:03:17 -08:00
|
|
|
if (!rctx->want_cdflag)
|
|
|
|
fopts |= DNS_FETCHOPT_NOCDFLAG;
|
|
|
|
if (!rctx->want_validation)
|
|
|
|
fopts |= DNS_FETCHOPT_NOVALIDATE;
|
2014-11-21 09:37:04 -08:00
|
|
|
if (rctx->want_tcp)
|
|
|
|
fopts |= DNS_FETCHOPT_TCP;
|
2014-02-16 13:03:17 -08:00
|
|
|
|
2009-09-01 00:22:28 +00:00
|
|
|
result = dns_resolver_createfetch(rctx->view->resolver,
|
|
|
|
dns_fixedname_name(&rctx->name),
|
|
|
|
rctx->type,
|
2018-04-03 16:05:11 +02:00
|
|
|
NULL, NULL, NULL, NULL, 0,
|
|
|
|
fopts, 0, NULL,
|
2009-09-01 00:22:28 +00:00
|
|
|
rctx->task, fetch_done, rctx,
|
|
|
|
rctx->rdataset,
|
|
|
|
rctx->sigrdataset,
|
|
|
|
&rctx->fetch);
|
|
|
|
|
|
|
|
return (result);
|
|
|
|
}
|
|
|
|
|
|
|
|
static isc_result_t
|
|
|
|
view_find(resctx_t *rctx, dns_db_t **dbp, dns_dbnode_t **nodep,
|
|
|
|
dns_name_t *foundname)
|
|
|
|
{
|
|
|
|
isc_result_t result;
|
|
|
|
dns_name_t *name = dns_fixedname_name(&rctx->name);
|
|
|
|
dns_rdatatype_t type;
|
|
|
|
|
|
|
|
if (rctx->type == dns_rdatatype_rrsig)
|
|
|
|
type = dns_rdatatype_any;
|
|
|
|
else
|
|
|
|
type = rctx->type;
|
|
|
|
|
2018-04-17 08:29:14 -07:00
|
|
|
result = dns_view_find(rctx->view, name, type, 0, 0, false,
|
|
|
|
false, dbp, nodep, foundname,
|
2018-04-04 09:51:42 +02:00
|
|
|
rctx->rdataset,
|
2009-09-01 00:22:28 +00:00
|
|
|
rctx->sigrdataset);
|
|
|
|
|
|
|
|
return (result);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
client_resfind(resctx_t *rctx, dns_fetchevent_t *event) {
|
|
|
|
isc_mem_t *mctx;
|
2011-03-11 06:11:27 +00:00
|
|
|
isc_result_t tresult, result = ISC_R_SUCCESS;
|
2009-09-01 00:22:28 +00:00
|
|
|
isc_result_t vresult = ISC_R_SUCCESS;
|
2018-04-17 08:29:14 -07:00
|
|
|
bool want_restart;
|
|
|
|
bool send_event = false;
|
2009-09-01 00:22:28 +00:00
|
|
|
dns_name_t *name, *prefix;
|
|
|
|
dns_fixedname_t foundname, fixed;
|
|
|
|
dns_rdataset_t *trdataset;
|
|
|
|
dns_rdata_t rdata = DNS_RDATA_INIT;
|
|
|
|
unsigned int nlabels;
|
|
|
|
int order;
|
|
|
|
dns_namereln_t namereln;
|
|
|
|
dns_rdata_cname_t cname;
|
|
|
|
dns_rdata_dname_t dname;
|
|
|
|
|
|
|
|
REQUIRE(RCTX_VALID(rctx));
|
|
|
|
|
|
|
|
LOCK(&rctx->lock);
|
|
|
|
|
|
|
|
mctx = rctx->view->mctx;
|
|
|
|
|
|
|
|
name = dns_fixedname_name(&rctx->name);
|
|
|
|
|
|
|
|
do {
|
|
|
|
dns_name_t *fname = NULL;
|
|
|
|
dns_name_t *ansname = NULL;
|
|
|
|
dns_db_t *db = NULL;
|
|
|
|
dns_dbnode_t *node = NULL;
|
|
|
|
|
|
|
|
rctx->restarts++;
|
2018-04-17 08:29:14 -07:00
|
|
|
want_restart = false;
|
2009-09-01 00:22:28 +00:00
|
|
|
|
|
|
|
if (event == NULL && !rctx->canceled) {
|
2018-03-28 14:38:09 +02:00
|
|
|
fname = dns_fixedname_initname(&foundname);
|
2009-09-01 00:22:28 +00:00
|
|
|
INSIST(!dns_rdataset_isassociated(rctx->rdataset));
|
|
|
|
INSIST(rctx->sigrdataset == NULL ||
|
|
|
|
!dns_rdataset_isassociated(rctx->sigrdataset));
|
|
|
|
result = view_find(rctx, &db, &node, fname);
|
|
|
|
if (result == ISC_R_NOTFOUND) {
|
|
|
|
/*
|
|
|
|
* We don't know anything about the name.
|
|
|
|
* Launch a fetch.
|
|
|
|
*/
|
|
|
|
if (node != NULL) {
|
|
|
|
INSIST(db != NULL);
|
|
|
|
dns_db_detachnode(db, &node);
|
|
|
|
}
|
|
|
|
if (db != NULL)
|
|
|
|
dns_db_detach(&db);
|
|
|
|
result = start_fetch(rctx);
|
|
|
|
if (result != ISC_R_SUCCESS) {
|
|
|
|
putrdataset(mctx, &rctx->rdataset);
|
|
|
|
if (rctx->sigrdataset != NULL)
|
|
|
|
putrdataset(mctx,
|
|
|
|
&rctx->sigrdataset);
|
2018-04-17 08:29:14 -07:00
|
|
|
send_event = true;
|
2009-09-01 00:22:28 +00:00
|
|
|
}
|
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
} else {
|
2011-03-11 06:11:27 +00:00
|
|
|
INSIST(event != NULL);
|
2009-09-01 00:22:28 +00:00
|
|
|
INSIST(event->fetch == rctx->fetch);
|
|
|
|
dns_resolver_destroyfetch(&rctx->fetch);
|
|
|
|
db = event->db;
|
|
|
|
node = event->node;
|
|
|
|
result = event->result;
|
|
|
|
vresult = event->vresult;
|
|
|
|
fname = dns_fixedname_name(&event->foundname);
|
|
|
|
INSIST(event->rdataset == rctx->rdataset);
|
|
|
|
INSIST(event->sigrdataset == rctx->sigrdataset);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* If we've been canceled, forget about the result.
|
|
|
|
*/
|
|
|
|
if (rctx->canceled)
|
|
|
|
result = ISC_R_CANCELED;
|
|
|
|
else {
|
|
|
|
/*
|
|
|
|
* Otherwise, get some resource for copying the
|
|
|
|
* result.
|
|
|
|
*/
|
2019-10-12 00:15:51 +02:00
|
|
|
dns_name_t *aname = dns_fixedname_name(&rctx->name);
|
|
|
|
|
2009-09-01 00:22:28 +00:00
|
|
|
ansname = isc_mem_get(mctx, sizeof(*ansname));
|
2019-10-12 00:15:51 +02:00
|
|
|
dns_name_init(ansname, NULL);
|
|
|
|
|
2019-11-01 08:31:13 -05:00
|
|
|
dns_name_dup(aname, mctx, ansname);
|
2009-09-01 00:22:28 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
switch (result) {
|
|
|
|
case ISC_R_SUCCESS:
|
2018-04-17 08:29:14 -07:00
|
|
|
send_event = true;
|
2009-09-01 00:22:28 +00:00
|
|
|
/*
|
|
|
|
* This case is handled in the main line below.
|
|
|
|
*/
|
|
|
|
break;
|
|
|
|
case DNS_R_CNAME:
|
|
|
|
/*
|
|
|
|
* Add the CNAME to the answer list.
|
|
|
|
*/
|
|
|
|
trdataset = rctx->rdataset;
|
|
|
|
ISC_LIST_APPEND(ansname->list, rctx->rdataset, link);
|
|
|
|
rctx->rdataset = NULL;
|
|
|
|
if (rctx->sigrdataset != NULL) {
|
|
|
|
ISC_LIST_APPEND(ansname->list,
|
|
|
|
rctx->sigrdataset, link);
|
|
|
|
rctx->sigrdataset = NULL;
|
|
|
|
}
|
|
|
|
ISC_LIST_APPEND(rctx->namelist, ansname, link);
|
|
|
|
ansname = NULL;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Copy the CNAME's target into the lookup's
|
|
|
|
* query name and start over.
|
|
|
|
*/
|
|
|
|
tresult = dns_rdataset_first(trdataset);
|
|
|
|
if (tresult != ISC_R_SUCCESS)
|
|
|
|
goto done;
|
|
|
|
dns_rdataset_current(trdataset, &rdata);
|
|
|
|
tresult = dns_rdata_tostruct(&rdata, &cname, NULL);
|
|
|
|
dns_rdata_reset(&rdata);
|
|
|
|
if (tresult != ISC_R_SUCCESS)
|
|
|
|
goto done;
|
2019-09-10 14:42:41 +02:00
|
|
|
dns_name_copynf(&cname.cname, name);
|
2009-09-01 00:22:28 +00:00
|
|
|
dns_rdata_freestruct(&cname);
|
2019-09-27 08:37:26 +02:00
|
|
|
want_restart = true;
|
2009-09-01 00:22:28 +00:00
|
|
|
goto done;
|
|
|
|
case DNS_R_DNAME:
|
|
|
|
/*
|
|
|
|
* Add the DNAME to the answer list.
|
|
|
|
*/
|
|
|
|
trdataset = rctx->rdataset;
|
|
|
|
ISC_LIST_APPEND(ansname->list, rctx->rdataset, link);
|
|
|
|
rctx->rdataset = NULL;
|
|
|
|
if (rctx->sigrdataset != NULL) {
|
|
|
|
ISC_LIST_APPEND(ansname->list,
|
|
|
|
rctx->sigrdataset, link);
|
|
|
|
rctx->sigrdataset = NULL;
|
|
|
|
}
|
|
|
|
ISC_LIST_APPEND(rctx->namelist, ansname, link);
|
|
|
|
ansname = NULL;
|
|
|
|
|
|
|
|
namereln = dns_name_fullcompare(name, fname, &order,
|
|
|
|
&nlabels);
|
|
|
|
INSIST(namereln == dns_namereln_subdomain);
|
|
|
|
/*
|
|
|
|
* Get the target name of the DNAME.
|
|
|
|
*/
|
|
|
|
tresult = dns_rdataset_first(trdataset);
|
|
|
|
if (tresult != ISC_R_SUCCESS) {
|
|
|
|
result = tresult;
|
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
dns_rdataset_current(trdataset, &rdata);
|
|
|
|
tresult = dns_rdata_tostruct(&rdata, &dname, NULL);
|
|
|
|
dns_rdata_reset(&rdata);
|
|
|
|
if (tresult != ISC_R_SUCCESS) {
|
|
|
|
result = tresult;
|
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
/*
|
|
|
|
* Construct the new query name and start over.
|
|
|
|
*/
|
2018-03-28 14:38:09 +02:00
|
|
|
prefix = dns_fixedname_initname(&fixed);
|
2009-09-01 00:22:28 +00:00
|
|
|
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)
|
2018-04-17 08:29:14 -07:00
|
|
|
want_restart = true;
|
2009-09-01 00:22:28 +00:00
|
|
|
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);
|
2018-04-17 08:29:14 -07:00
|
|
|
send_event = true;
|
2009-09-01 00:22:28 +00:00
|
|
|
goto done;
|
|
|
|
default:
|
|
|
|
if (rctx->rdataset != NULL)
|
|
|
|
putrdataset(mctx, &rctx->rdataset);
|
|
|
|
if (rctx->sigrdataset != NULL)
|
|
|
|
putrdataset(mctx, &rctx->sigrdataset);
|
2018-04-17 08:29:14 -07:00
|
|
|
send_event = true;
|
2009-09-01 00:22:28 +00:00
|
|
|
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;
|
2011-03-11 06:11:27 +00:00
|
|
|
POST(result);
|
2009-09-01 00:22:28 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2019-04-17 00:13:14 +10:00
|
|
|
if (rctx->rdataset != NULL) {
|
|
|
|
putrdataset(mctx, &rctx->rdataset);
|
|
|
|
}
|
|
|
|
if (rctx->sigrdataset != NULL) {
|
|
|
|
putrdataset(mctx, &rctx->sigrdataset);
|
|
|
|
}
|
2009-09-01 00:22:28 +00:00
|
|
|
if (n == 0) {
|
|
|
|
/*
|
|
|
|
* We didn't match any rdatasets (which means
|
|
|
|
* something went wrong in this
|
|
|
|
* implementation).
|
|
|
|
*/
|
|
|
|
result = DNS_R_SERVFAIL; /* better code? */
|
2011-03-11 06:11:27 +00:00
|
|
|
POST(result);
|
2009-09-01 00:22:28 +00:00
|
|
|
} 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) {
|
2018-04-17 08:29:14 -07:00
|
|
|
want_restart = false;
|
2009-09-01 00:22:28 +00:00
|
|
|
result = ISC_R_QUOTA;
|
2018-04-17 08:29:14 -07:00
|
|
|
send_event = true;
|
2009-09-01 00:22:28 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* 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) {
|
2018-04-17 08:29:14 -07:00
|
|
|
want_restart = false;
|
|
|
|
send_event = true;
|
2009-09-01 00:22:28 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
} 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);
|
|
|
|
}
|
|
|
|
|
2013-05-09 08:41:24 +10:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2009-09-01 00:22:28 +00:00
|
|
|
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;
|
2013-05-09 08:41:24 +10:00
|
|
|
isc_result_t result;
|
2009-09-01 00:22:28 +00:00
|
|
|
|
|
|
|
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);
|
|
|
|
|
2013-05-09 08:41:24 +10:00
|
|
|
/*
|
|
|
|
* 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);
|
2009-09-01 00:22:28 +00:00
|
|
|
} else {
|
|
|
|
/*
|
|
|
|
* We have already exited from the loop (due to some
|
|
|
|
* unexpected event). Just clean the arg up.
|
|
|
|
*/
|
|
|
|
UNLOCK(&resarg->lock);
|
2018-11-19 10:31:09 +00:00
|
|
|
isc_mutex_destroy(&resarg->lock);
|
2009-09-01 00:22:28 +00:00
|
|
|
isc_mem_put(resarg->client->mctx, resarg, sizeof(*resarg));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
isc_result_t
|
2016-12-30 15:45:08 +11:00
|
|
|
dns_client_resolve(dns_client_t *client, const dns_name_t *name,
|
2009-09-01 00:22:28 +00:00
|
|
|
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
|
2009-09-02 23:48:03 +00:00
|
|
|
* particular resolution.
|
2009-09-01 00:22:28 +00:00
|
|
|
*/
|
|
|
|
return (ISC_R_NOTIMPLEMENTED); /* XXXTBD */
|
|
|
|
} else
|
|
|
|
actx = client->actx;
|
|
|
|
|
|
|
|
resarg = isc_mem_get(client->mctx, sizeof(*resarg));
|
|
|
|
|
2018-11-16 15:33:22 +01:00
|
|
|
isc_mutex_init(&resarg->lock);
|
2009-09-01 00:22:28 +00:00
|
|
|
|
|
|
|
resarg->actx = actx;
|
|
|
|
resarg->client = client;
|
|
|
|
resarg->result = DNS_R_SERVFAIL;
|
|
|
|
resarg->namelist = namelist;
|
|
|
|
resarg->trans = NULL;
|
2018-04-17 08:29:14 -07:00
|
|
|
resarg->canceled = false;
|
2009-09-01 00:22:28 +00:00
|
|
|
result = dns_client_startresolve(client, name, rdclass, type, options,
|
|
|
|
client->task, resolve_done, resarg,
|
|
|
|
&resarg->trans);
|
|
|
|
if (result != ISC_R_SUCCESS) {
|
2018-11-19 10:31:09 +00:00
|
|
|
isc_mutex_destroy(&resarg->lock);
|
2009-09-01 00:22:28 +00:00
|
|
|
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.
|
2009-09-02 23:48:03 +00:00
|
|
|
* XXX: or should we pass the validation result separately?
|
2009-09-01 00:22:28 +00:00
|
|
|
*/
|
|
|
|
result = resarg->vresult;
|
|
|
|
}
|
|
|
|
if (resarg->trans != NULL) {
|
|
|
|
/*
|
|
|
|
* Unusual termination (perhaps due to signal). We need some
|
|
|
|
* tricky cleanup process.
|
|
|
|
*/
|
2018-04-17 08:29:14 -07:00
|
|
|
resarg->canceled = true;
|
2009-09-01 00:22:28 +00:00
|
|
|
dns_client_cancelresolve(resarg->trans);
|
|
|
|
|
|
|
|
UNLOCK(&resarg->lock);
|
|
|
|
|
|
|
|
/* resarg will be freed in the event handler. */
|
|
|
|
} else {
|
|
|
|
UNLOCK(&resarg->lock);
|
|
|
|
|
2018-11-19 10:31:09 +00:00
|
|
|
isc_mutex_destroy(&resarg->lock);
|
2009-09-01 00:22:28 +00:00
|
|
|
isc_mem_put(client->mctx, resarg, sizeof(*resarg));
|
|
|
|
}
|
|
|
|
|
|
|
|
return (result);
|
|
|
|
}
|
|
|
|
|
|
|
|
isc_result_t
|
2016-12-30 15:45:08 +11:00
|
|
|
dns_client_startresolve(dns_client_t *client, const dns_name_t *name,
|
2009-09-01 00:22:28 +00:00
|
|
|
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;
|
2016-06-28 21:25:30 -04:00
|
|
|
isc_task_t *tclone = NULL;
|
2009-09-01 00:22:28 +00:00
|
|
|
isc_mem_t *mctx;
|
|
|
|
isc_result_t result;
|
|
|
|
dns_rdataset_t *rdataset, *sigrdataset;
|
2018-04-17 08:29:14 -07:00
|
|
|
bool want_dnssec, want_validation, want_cdflag, want_tcp;
|
2009-09-01 00:22:28 +00:00
|
|
|
|
|
|
|
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;
|
2018-10-11 11:57:57 +02:00
|
|
|
want_dnssec = ((options & DNS_CLIENTRESOPT_NODNSSEC) == 0);
|
|
|
|
want_validation = ((options & DNS_CLIENTRESOPT_NOVALIDATE) == 0);
|
|
|
|
want_cdflag = ((options & DNS_CLIENTRESOPT_NOCDFLAG) == 0);
|
|
|
|
want_tcp = ((options & DNS_CLIENTRESOPT_TCP) != 0);
|
2009-09-01 00:22:28 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Prepare some intermediate resources
|
|
|
|
*/
|
2016-06-28 21:25:30 -04:00
|
|
|
tclone = NULL;
|
|
|
|
isc_task_attach(task, &tclone);
|
2009-09-01 00:22:28 +00:00
|
|
|
event = (dns_clientresevent_t *)
|
2016-06-28 21:25:30 -04:00
|
|
|
isc_event_allocate(mctx, tclone, DNS_EVENT_CLIENTRESDONE,
|
2009-09-01 00:22:28 +00:00
|
|
|
action, arg, sizeof(*event));
|
|
|
|
event->result = DNS_R_SERVFAIL;
|
|
|
|
ISC_LIST_INIT(event->answerlist);
|
|
|
|
|
|
|
|
rctx = isc_mem_get(mctx, sizeof(*rctx));
|
2020-01-30 19:41:32 +11:00
|
|
|
isc_mutex_init(&rctx->lock);
|
2009-09-01 00:22:28 +00:00
|
|
|
|
|
|
|
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);
|
2019-09-10 14:42:41 +02:00
|
|
|
dns_name_copynf(name, dns_fixedname_name(&rctx->name));
|
2009-09-01 00:22:28 +00:00
|
|
|
|
|
|
|
rctx->client = client;
|
|
|
|
ISC_LINK_INIT(rctx, link);
|
2018-04-17 08:29:14 -07:00
|
|
|
rctx->canceled = false;
|
2009-09-01 00:22:28 +00:00
|
|
|
rctx->task = client->task;
|
|
|
|
rctx->type = type;
|
|
|
|
rctx->view = view;
|
|
|
|
rctx->restarts = 0;
|
|
|
|
rctx->fetch = NULL;
|
|
|
|
rctx->want_dnssec = want_dnssec;
|
2014-02-16 13:03:17 -08:00
|
|
|
rctx->want_validation = want_validation;
|
|
|
|
rctx->want_cdflag = want_cdflag;
|
2014-11-21 09:37:04 -08:00
|
|
|
rctx->want_tcp = want_tcp;
|
2009-09-01 00:22:28 +00:00
|
|
|
ISC_LIST_INIT(rctx->namelist);
|
|
|
|
rctx->event = event;
|
|
|
|
|
|
|
|
rctx->magic = RCTX_MAGIC;
|
2019-08-06 17:35:20 +02:00
|
|
|
isc_refcount_increment(&client->references);
|
2009-09-01 00:22:28 +00:00
|
|
|
|
|
|
|
LOCK(&client->lock);
|
|
|
|
ISC_LIST_APPEND(client->resctxs, rctx, link);
|
|
|
|
UNLOCK(&client->lock);
|
|
|
|
|
|
|
|
*transp = (dns_clientrestrans_t *)rctx;
|
2013-05-09 08:41:24 +10:00
|
|
|
client_resfind(rctx, NULL);
|
2009-09-01 00:22:28 +00:00
|
|
|
|
|
|
|
return (ISC_R_SUCCESS);
|
|
|
|
|
|
|
|
cleanup:
|
|
|
|
if (rdataset != NULL)
|
|
|
|
putrdataset(client->mctx, &rdataset);
|
|
|
|
if (sigrdataset != NULL)
|
|
|
|
putrdataset(client->mctx, &sigrdataset);
|
|
|
|
if (rctx != NULL) {
|
2018-11-19 10:31:09 +00:00
|
|
|
isc_mutex_destroy(&rctx->lock);
|
2009-09-01 00:22:28 +00:00
|
|
|
isc_mem_put(mctx, rctx, sizeof(*rctx));
|
|
|
|
}
|
2020-02-05 16:11:11 +11:00
|
|
|
isc_event_free(ISC_EVENT_PTR(&event));
|
2016-06-28 21:25:30 -04:00
|
|
|
isc_task_detach(&tclone);
|
2009-09-01 00:22:28 +00:00
|
|
|
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) {
|
2018-04-17 08:29:14 -07:00
|
|
|
rctx->canceled = true;
|
2009-09-01 00:22:28 +00:00
|
|
|
if (rctx->fetch != NULL)
|
|
|
|
dns_resolver_cancelfetch(rctx->fetch);
|
|
|
|
}
|
|
|
|
|
|
|
|
UNLOCK(&rctx->lock);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2009-09-02 23:48:03 +00:00
|
|
|
dns_client_freeresanswer(dns_client_t *client, dns_namelist_t *namelist) {
|
2009-09-01 00:22:28 +00:00
|
|
|
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;
|
|
|
|
|
|
|
|
REQUIRE(transp != NULL);
|
|
|
|
rctx = (resctx_t *)*transp;
|
2019-08-06 17:35:20 +02:00
|
|
|
*transp = NULL;
|
2009-09-01 00:22:28 +00:00
|
|
|
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);
|
|
|
|
|
2015-09-30 14:58:31 +10:00
|
|
|
/*
|
|
|
|
* Wait for the lock in client_resfind to be released before
|
|
|
|
* destroying the lock.
|
|
|
|
*/
|
|
|
|
LOCK(&rctx->lock);
|
|
|
|
UNLOCK(&rctx->lock);
|
|
|
|
|
2009-09-01 00:22:28 +00:00
|
|
|
LOCK(&client->lock);
|
|
|
|
|
|
|
|
INSIST(ISC_LINK_LINKED(rctx, link));
|
|
|
|
ISC_LIST_UNLINK(client->resctxs, rctx, link);
|
|
|
|
|
|
|
|
UNLOCK(&client->lock);
|
|
|
|
|
|
|
|
INSIST(ISC_LIST_EMPTY(rctx->namelist));
|
|
|
|
|
2018-11-19 10:31:09 +00:00
|
|
|
isc_mutex_destroy(&rctx->lock);
|
2009-09-01 00:22:28 +00:00
|
|
|
rctx->magic = 0;
|
|
|
|
|
|
|
|
isc_mem_put(mctx, rctx, sizeof(*rctx));
|
|
|
|
|
2019-08-06 17:35:20 +02:00
|
|
|
dns_client_destroy(&client);
|
2009-09-01 00:22:28 +00:00
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
isc_result_t
|
|
|
|
dns_client_addtrustedkey(dns_client_t *client, dns_rdataclass_t rdclass,
|
2019-09-18 19:45:20 -07:00
|
|
|
dns_rdatatype_t rdtype, const dns_name_t *keyname,
|
|
|
|
isc_buffer_t *databuf)
|
2009-09-01 00:22:28 +00:00
|
|
|
{
|
|
|
|
isc_result_t result;
|
|
|
|
dns_view_t *view = NULL;
|
2009-10-27 22:46:13 +00:00
|
|
|
dns_keytable_t *secroots = NULL;
|
2019-09-18 19:45:20 -07:00
|
|
|
dns_name_t *name = NULL;
|
|
|
|
char dsbuf[DNS_DS_BUFFERSIZE];
|
2019-12-20 11:37:11 -08:00
|
|
|
unsigned char digest[ISC_MAX_MD_SIZE];
|
2019-09-18 19:45:20 -07:00
|
|
|
dns_rdata_ds_t ds;
|
|
|
|
dns_decompress_t dctx;
|
|
|
|
dns_rdata_t rdata;
|
|
|
|
isc_buffer_t b;
|
2009-09-01 00:22:28 +00:00
|
|
|
|
|
|
|
REQUIRE(DNS_CLIENT_VALID(client));
|
|
|
|
|
|
|
|
LOCK(&client->lock);
|
|
|
|
result = dns_viewlist_find(&client->viewlist, DNS_CLIENTVIEW_NAME,
|
|
|
|
rdclass, &view);
|
|
|
|
UNLOCK(&client->lock);
|
2019-09-18 19:45:20 -07:00
|
|
|
CHECK(result);
|
2009-10-27 22:46:13 +00:00
|
|
|
|
2019-09-18 19:45:20 -07:00
|
|
|
CHECK(dns_view_getsecroots(view, &secroots));
|
2009-09-01 00:22:28 +00:00
|
|
|
|
2019-09-18 19:45:20 -07:00
|
|
|
DE_CONST(keyname, name);
|
2009-09-01 00:22:28 +00:00
|
|
|
|
2019-12-20 11:37:11 -08:00
|
|
|
if (rdtype != dns_rdatatype_dnskey && rdtype != dns_rdatatype_ds) {
|
2019-09-18 19:45:20 -07:00
|
|
|
result = ISC_R_NOTIMPLEMENTED;
|
2019-12-20 11:37:11 -08:00
|
|
|
goto cleanup;
|
2019-09-18 19:45:20 -07:00
|
|
|
}
|
2009-09-01 00:22:28 +00:00
|
|
|
|
2019-12-20 11:37:11 -08:00
|
|
|
isc_buffer_init(&b, dsbuf, sizeof(dsbuf));
|
|
|
|
dns_decompress_init(&dctx, -1, DNS_DECOMPRESS_NONE);
|
|
|
|
dns_rdata_init(&rdata);
|
|
|
|
isc_buffer_setactive(databuf, isc_buffer_usedlength(databuf));
|
|
|
|
CHECK(dns_rdata_fromwire(&rdata, rdclass, rdtype,
|
|
|
|
databuf, &dctx, 0, &b));
|
|
|
|
dns_decompress_invalidate(&dctx);
|
|
|
|
|
|
|
|
if (rdtype == dns_rdatatype_ds) {
|
|
|
|
CHECK(dns_rdata_tostruct(&rdata, &ds, NULL));
|
|
|
|
} else {
|
|
|
|
CHECK(dns_ds_fromkeyrdata(name, &rdata, DNS_DSDIGEST_SHA256,
|
|
|
|
digest, &ds));
|
|
|
|
}
|
|
|
|
|
|
|
|
CHECK(dns_keytable_add(secroots, false, false, name, &ds));
|
|
|
|
|
2009-10-27 22:46:13 +00:00
|
|
|
cleanup:
|
2019-09-18 19:45:20 -07:00
|
|
|
if (view != NULL) {
|
2009-10-27 22:46:13 +00:00
|
|
|
dns_view_detach(&view);
|
2019-09-18 19:45:20 -07:00
|
|
|
}
|
|
|
|
if (secroots != NULL) {
|
2009-10-27 22:46:13 +00:00
|
|
|
dns_keytable_detach(&secroots);
|
2019-09-18 19:45:20 -07:00
|
|
|
}
|
2009-09-01 00:22:28 +00:00
|
|
|
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;
|
2009-09-02 23:48:03 +00:00
|
|
|
dns_clientreqevent_t *rev =(dns_clientreqevent_t *)event;
|
2009-09-01 00:22:28 +00:00
|
|
|
|
|
|
|
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);
|
2018-11-19 10:31:09 +00:00
|
|
|
isc_mutex_destroy(&reqarg->lock);
|
2009-09-01 00:22:28 +00:00
|
|
|
isc_mem_put(reqarg->client->mctx, reqarg, sizeof(*reqarg));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
isc_result_t
|
|
|
|
dns_client_request(dns_client_t *client, dns_message_t *qmessage,
|
2016-12-30 15:45:08 +11:00
|
|
|
dns_message_t *rmessage, const isc_sockaddr_t *server,
|
2009-09-01 00:22:28 +00:00
|
|
|
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
|
2009-09-02 23:48:03 +00:00
|
|
|
* particular resolution.
|
2009-09-01 00:22:28 +00:00
|
|
|
*/
|
|
|
|
return (ISC_R_NOTIMPLEMENTED); /* XXXTBD */
|
|
|
|
} else
|
|
|
|
actx = client->actx;
|
|
|
|
|
|
|
|
reqarg = isc_mem_get(client->mctx, sizeof(*reqarg));
|
|
|
|
|
2018-11-16 15:33:22 +01:00
|
|
|
isc_mutex_init(&reqarg->lock);
|
2009-09-01 00:22:28 +00:00
|
|
|
|
|
|
|
reqarg->actx = actx;
|
|
|
|
reqarg->client = client;
|
|
|
|
reqarg->trans = NULL;
|
2018-04-17 08:29:14 -07:00
|
|
|
reqarg->canceled = false;
|
2009-09-01 00:22:28 +00:00
|
|
|
|
|
|
|
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) {
|
2018-11-19 10:31:09 +00:00
|
|
|
isc_mutex_destroy(&reqarg->lock);
|
2009-09-01 00:22:28 +00:00
|
|
|
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.
|
|
|
|
*/
|
2018-04-17 08:29:14 -07:00
|
|
|
reqarg->canceled = true;
|
2009-09-01 00:22:28 +00:00
|
|
|
dns_client_cancelresolve(reqarg->trans);
|
|
|
|
|
|
|
|
UNLOCK(&reqarg->lock);
|
|
|
|
|
|
|
|
/* reqarg will be freed in the event handler. */
|
|
|
|
} else {
|
|
|
|
UNLOCK(&reqarg->lock);
|
|
|
|
|
2018-11-19 10:31:09 +00:00
|
|
|
isc_mutex_destroy(&reqarg->lock);
|
2009-09-01 00:22:28 +00:00
|
|
|
isc_mem_put(client->mctx, reqarg, sizeof(*reqarg));
|
|
|
|
}
|
|
|
|
|
|
|
|
return (result);
|
|
|
|
}
|
|
|
|
|
|
|
|
isc_result_t
|
|
|
|
dns_client_startrequest(dns_client_t *client, dns_message_t *qmessage,
|
2016-12-30 15:45:08 +11:00
|
|
|
dns_message_t *rmessage, const isc_sockaddr_t *server,
|
2009-09-01 00:22:28 +00:00
|
|
|
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;
|
2016-06-28 21:25:30 -04:00
|
|
|
isc_task_t *tclone = NULL;
|
2009-09-01 00:22:28 +00:00
|
|
|
dns_clientreqevent_t *event = NULL;
|
|
|
|
reqctx_t *ctx = NULL;
|
|
|
|
dns_tsectype_t tsectype = dns_tsectype_none;
|
2014-11-21 09:37:04 -08:00
|
|
|
unsigned int reqoptions;
|
2009-09-01 00:22:28 +00:00
|
|
|
|
|
|
|
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);
|
|
|
|
|
2014-11-21 09:37:04 -08:00
|
|
|
reqoptions = 0;
|
|
|
|
if ((options & DNS_CLIENTREQOPT_TCP) != 0)
|
|
|
|
reqoptions |= DNS_REQUESTOPT_TCP;
|
|
|
|
|
2016-06-28 21:25:30 -04:00
|
|
|
tclone = NULL;
|
|
|
|
isc_task_attach(task, &tclone);
|
2009-09-01 00:22:28 +00:00
|
|
|
event = (dns_clientreqevent_t *)
|
2016-06-28 21:25:30 -04:00
|
|
|
isc_event_allocate(client->mctx, tclone,
|
2009-09-01 00:22:28 +00:00
|
|
|
DNS_EVENT_CLIENTREQDONE,
|
|
|
|
action, arg, sizeof(*event));
|
|
|
|
|
|
|
|
ctx = isc_mem_get(client->mctx, sizeof(*ctx));
|
2020-01-30 19:41:32 +11:00
|
|
|
isc_mutex_init(&ctx->lock);
|
2009-09-01 00:22:28 +00:00
|
|
|
|
|
|
|
ctx->client = client;
|
|
|
|
ISC_LINK_INIT(ctx, link);
|
|
|
|
ctx->parseoptions = parseoptions;
|
2018-04-17 08:29:14 -07:00
|
|
|
ctx->canceled = false;
|
2009-09-01 00:22:28 +00:00
|
|
|
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);
|
2019-08-06 17:35:20 +02:00
|
|
|
isc_refcount_increment(&client->references);
|
2009-09-01 00:22:28 +00:00
|
|
|
UNLOCK(&client->lock);
|
|
|
|
|
|
|
|
ctx->request = NULL;
|
2018-04-03 15:12:27 +02:00
|
|
|
result = dns_request_createvia(view->requestmgr, qmessage, NULL,
|
|
|
|
server, -1, reqoptions, ctx->tsigkey,
|
|
|
|
timeout, udptimeout, udpretries,
|
|
|
|
client->task, request_done, ctx,
|
|
|
|
&ctx->request);
|
2009-09-01 00:22:28 +00:00
|
|
|
if (result == ISC_R_SUCCESS) {
|
|
|
|
dns_view_detach(&view);
|
|
|
|
*transp = (dns_clientreqtrans_t *)ctx;
|
|
|
|
return (ISC_R_SUCCESS);
|
|
|
|
}
|
|
|
|
|
2019-08-06 17:35:20 +02:00
|
|
|
isc_refcount_decrement(&client->references);
|
|
|
|
|
2020-01-30 19:41:32 +11:00
|
|
|
LOCK(&client->lock);
|
|
|
|
ISC_LIST_UNLINK(client->reqctxs, ctx, link);
|
|
|
|
UNLOCK(&client->lock);
|
|
|
|
isc_mutex_destroy(&ctx->lock);
|
|
|
|
isc_mem_put(client->mctx, ctx, sizeof(*ctx));
|
|
|
|
|
|
|
|
isc_event_free(ISC_EVENT_PTR(&event));
|
2016-06-28 21:25:30 -04:00
|
|
|
isc_task_detach(&tclone);
|
2009-09-01 00:22:28 +00:00
|
|
|
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) {
|
2018-04-17 08:29:14 -07:00
|
|
|
ctx->canceled = true;
|
2009-09-01 00:22:28 +00:00
|
|
|
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;
|
|
|
|
|
|
|
|
REQUIRE(transp != NULL);
|
|
|
|
ctx = (reqctx_t *)*transp;
|
2019-08-06 17:35:20 +02:00
|
|
|
*transp = NULL;
|
2009-09-01 00:22:28 +00:00
|
|
|
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);
|
|
|
|
|
|
|
|
UNLOCK(&client->lock);
|
|
|
|
|
2018-11-19 10:31:09 +00:00
|
|
|
isc_mutex_destroy(&ctx->lock);
|
2009-09-01 00:22:28 +00:00
|
|
|
ctx->magic = 0;
|
|
|
|
|
|
|
|
isc_mem_put(mctx, ctx, sizeof(*ctx));
|
|
|
|
|
2019-08-06 17:35:20 +02:00
|
|
|
dns_client_destroy(&client);
|
2009-09-01 00:22:28 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*%
|
|
|
|
* 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;
|
2014-11-21 09:37:04 -08:00
|
|
|
unsigned int timeout, reqoptions;
|
2009-09-01 00:22:28 +00:00
|
|
|
|
|
|
|
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);
|
2016-12-13 15:47:03 +11:00
|
|
|
/*
|
|
|
|
* Moving on to the next server shouldn't change the result
|
|
|
|
* for NXDOMAIN, YXDOMAIN, NXRRSET and YXRRSET as they
|
|
|
|
* indicate a prerequisite failure. REFUSED should also
|
|
|
|
* be consistent across all servers but often isn't as that
|
|
|
|
* is policy rather that zone content driven (slaves that
|
|
|
|
* aren't willing to forward should return NOTIMPL). NOTZONE
|
|
|
|
* indicates that we stuffed up the request construction so
|
|
|
|
* don't retry.
|
|
|
|
*/
|
|
|
|
if (result != ISC_R_SUCCESS && result != DNS_R_NXDOMAIN &&
|
|
|
|
result != DNS_R_YXDOMAIN && result != DNS_R_YXRRSET &&
|
|
|
|
result != DNS_R_NXRRSET && result != DNS_R_NOTZONE &&
|
|
|
|
!uctx->canceled && uctx->currentserver != NULL)
|
|
|
|
{
|
2009-09-01 00:22:28 +00:00
|
|
|
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;
|
2014-11-21 09:37:04 -08:00
|
|
|
reqoptions = 0;
|
|
|
|
if (uctx->want_tcp)
|
|
|
|
reqoptions |= DNS_REQUESTOPT_TCP;
|
2018-04-03 15:12:27 +02:00
|
|
|
result = dns_request_createvia(uctx->view->requestmgr,
|
|
|
|
uctx->updatemsg,
|
|
|
|
NULL,
|
|
|
|
uctx->currentserver,
|
|
|
|
-1,
|
|
|
|
reqoptions,
|
|
|
|
uctx->tsigkey,
|
|
|
|
timeout,
|
|
|
|
client->update_udptimeout,
|
|
|
|
client->update_udpretries,
|
|
|
|
client->task,
|
|
|
|
update_done, uctx,
|
|
|
|
&uctx->updatereq);
|
2009-09-01 00:22:28 +00:00
|
|
|
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;
|
2014-11-21 09:37:04 -08:00
|
|
|
unsigned int timeout, reqoptions;
|
2009-09-01 00:22:28 +00:00
|
|
|
|
|
|
|
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;
|
2014-11-21 09:37:04 -08:00
|
|
|
reqoptions = 0;
|
|
|
|
if (uctx->want_tcp)
|
|
|
|
reqoptions |= DNS_REQUESTOPT_TCP;
|
2018-04-03 15:12:27 +02:00
|
|
|
result = dns_request_createvia(uctx->view->requestmgr,
|
|
|
|
uctx->updatemsg,
|
|
|
|
NULL, uctx->currentserver,
|
|
|
|
-1, reqoptions, uctx->tsigkey, timeout,
|
|
|
|
client->update_udptimeout,
|
|
|
|
client->update_udpretries,
|
|
|
|
client->task, update_done, uctx,
|
|
|
|
&uctx->updatereq);
|
2009-09-01 00:22:28 +00:00
|
|
|
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;
|
2018-04-17 08:29:14 -07:00
|
|
|
bool completed = false;
|
2009-09-01 00:22:28 +00:00
|
|
|
|
|
|
|
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));
|
|
|
|
|
|
|
|
dns_rdata_init(&rdata);
|
|
|
|
switch (family) {
|
|
|
|
case AF_INET:
|
|
|
|
dns_rdataset_current(rdataset, &rdata);
|
2013-04-11 17:07:50 +10:00
|
|
|
result = dns_rdata_tostruct(&rdata, &rdata_a,
|
2013-04-11 23:46:07 +00:00
|
|
|
NULL);
|
2013-04-11 17:07:50 +10:00
|
|
|
RUNTIME_CHECK(result == ISC_R_SUCCESS);
|
2009-09-01 00:22:28 +00:00
|
|
|
isc_sockaddr_fromin(sa,
|
|
|
|
&rdata_a.in_addr,
|
|
|
|
53);
|
|
|
|
dns_rdata_freestruct(&rdata_a);
|
|
|
|
break;
|
|
|
|
case AF_INET6:
|
|
|
|
dns_rdataset_current(rdataset, &rdata);
|
2013-04-11 17:07:50 +10:00
|
|
|
result = dns_rdata_tostruct(&rdata, &rdata_aaaa,
|
2013-04-11 23:46:07 +00:00
|
|
|
NULL);
|
2013-04-11 17:07:50 +10:00
|
|
|
RUNTIME_CHECK(result == ISC_R_SUCCESS);
|
2009-09-01 00:22:28 +00:00
|
|
|
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)
|
2018-04-17 08:29:14 -07:00
|
|
|
completed = true;
|
2009-09-01 00:22:28 +00:00
|
|
|
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
|
2016-12-30 15:45:08 +11:00
|
|
|
process_soa(updatectx_t *uctx, dns_rdataset_t *soaset,
|
|
|
|
const dns_name_t *soaname)
|
|
|
|
{
|
2009-09-01 00:22:28 +00:00
|
|
|
isc_result_t result;
|
|
|
|
dns_rdata_t soarr = DNS_RDATA_INIT;
|
|
|
|
dns_rdata_soa_t soa;
|
|
|
|
dns_name_t primary;
|
2014-11-21 09:37:04 -08:00
|
|
|
unsigned int resoptions;
|
2009-09-01 00:22:28 +00:00
|
|
|
|
|
|
|
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);
|
2019-09-10 14:42:41 +02:00
|
|
|
dns_name_copynf(soaname, uctx->zonename);
|
2009-09-01 00:22:28 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
2014-11-21 09:37:04 -08:00
|
|
|
resoptions = 0;
|
|
|
|
if (uctx->want_tcp)
|
|
|
|
resoptions |= DNS_CLIENTRESOPT_TCP;
|
2009-09-01 00:22:28 +00:00
|
|
|
result = dns_client_startresolve(uctx->client, &primary,
|
|
|
|
uctx->rdclass,
|
|
|
|
dns_rdatatype_a,
|
2014-11-21 09:37:04 -08:00
|
|
|
resoptions,
|
|
|
|
uctx->client->task,
|
2009-09-01 00:22:28 +00:00
|
|
|
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,
|
2014-11-21 09:37:04 -08:00
|
|
|
resoptions,
|
|
|
|
uctx->client->task,
|
2009-09-01 00:22:28 +00:00
|
|
|
resolveaddr_done,
|
|
|
|
&uctx->bp6,
|
|
|
|
&uctx->restrans2);
|
|
|
|
}
|
|
|
|
UNLOCK(&uctx->lock);
|
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
2018-04-17 08:29:14 -07:00
|
|
|
bool seencname = false;
|
|
|
|
bool droplabel = false;
|
2009-09-01 00:22:28 +00:00
|
|
|
dns_name_t tname;
|
2014-11-21 09:37:04 -08:00
|
|
|
unsigned int nlabels, reqoptions;
|
2009-09-01 00:22:28 +00:00
|
|
|
|
|
|
|
UNUSED(task);
|
|
|
|
|
|
|
|
REQUIRE(event->ev_type == DNS_EVENT_REQUESTDONE);
|
|
|
|
reqev = (dns_requestevent_t *)event;
|
|
|
|
request = reqev->request;
|
|
|
|
result = eresult = reqev->result;
|
2011-03-11 06:11:27 +00:00
|
|
|
POST(result);
|
2009-09-01 00:22:28 +00:00
|
|
|
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);
|
2014-11-21 09:37:04 -08:00
|
|
|
reqoptions = 0;
|
|
|
|
if (uctx->want_tcp)
|
|
|
|
reqoptions |= DNS_REQUESTOPT_TCP;
|
2018-04-03 15:12:27 +02:00
|
|
|
result = dns_request_createvia(uctx->view->requestmgr,
|
|
|
|
uctx->soaquery, NULL, addr, -1,
|
|
|
|
reqoptions, NULL,
|
|
|
|
client->find_timeout * 20,
|
|
|
|
client->find_timeout, 3,
|
|
|
|
uctx->client->task,
|
|
|
|
receive_soa, uctx,
|
|
|
|
&newrequest);
|
2009-09-01 00:22:28 +00:00
|
|
|
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;
|
2011-03-11 06:11:27 +00:00
|
|
|
POST(section);
|
2009-09-01 00:22:28 +00:00
|
|
|
|
|
|
|
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 {
|
2018-04-17 08:29:14 -07:00
|
|
|
droplabel = true;
|
2009-09-01 00:22:28 +00:00
|
|
|
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
|
|
|
|
)
|
|
|
|
{
|
2018-04-17 08:29:14 -07:00
|
|
|
seencname = true;
|
2009-09-01 00:22:28 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
result = dns_message_nextname(rcvmsg, section);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (soaset == NULL && !seencname) {
|
|
|
|
pass++;
|
|
|
|
goto lookforsoa;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (seencname) {
|
2018-04-17 08:29:14 -07:00
|
|
|
droplabel = true;
|
2009-09-01 00:22:28 +00:00
|
|
|
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);
|
2014-11-21 09:37:04 -08:00
|
|
|
reqoptions = 0;
|
|
|
|
if (uctx->want_tcp)
|
|
|
|
reqoptions |= DNS_REQUESTOPT_TCP;
|
2018-04-03 15:12:27 +02:00
|
|
|
result = dns_request_createvia(uctx->view->requestmgr,
|
|
|
|
soaquery, NULL,
|
|
|
|
uctx->currentserver,
|
|
|
|
-1,
|
|
|
|
reqoptions,
|
|
|
|
uctx->tsigkey,
|
|
|
|
client->find_timeout *
|
|
|
|
20,
|
|
|
|
client->find_timeout,
|
|
|
|
3, client->task,
|
|
|
|
receive_soa, uctx,
|
|
|
|
&uctx->soareq);
|
2009-09-01 00:22:28 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
2014-11-21 09:37:04 -08:00
|
|
|
unsigned int reqoptions;
|
2009-09-01 00:22:28 +00:00
|
|
|
|
|
|
|
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;
|
2014-11-21 09:37:04 -08:00
|
|
|
reqoptions = 0;
|
|
|
|
if (uctx->want_tcp)
|
|
|
|
reqoptions |= DNS_REQUESTOPT_TCP;
|
2009-09-01 00:22:28 +00:00
|
|
|
|
2018-04-03 15:12:27 +02:00
|
|
|
result = dns_request_createvia(uctx->view->requestmgr,
|
|
|
|
soaquery, NULL, uctx->currentserver,
|
|
|
|
-1, reqoptions, uctx->tsigkey,
|
|
|
|
uctx->client->find_timeout * 20,
|
|
|
|
uctx->client->find_timeout, 3,
|
|
|
|
uctx->client->task, receive_soa, uctx,
|
|
|
|
&uctx->soareq);
|
2009-09-01 00:22:28 +00:00
|
|
|
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;
|
2014-11-21 09:37:04 -08:00
|
|
|
unsigned int nlabels, resoptions;
|
2009-09-01 00:22:28 +00:00
|
|
|
|
|
|
|
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);
|
2014-11-21 09:37:04 -08:00
|
|
|
resoptions = 0;
|
|
|
|
if (uctx->want_tcp)
|
|
|
|
resoptions |= DNS_CLIENTRESOPT_TCP;
|
2009-09-01 00:22:28 +00:00
|
|
|
|
|
|
|
result = dns_client_startresolve(uctx->client, &uctx->soaqname,
|
|
|
|
uctx->rdclass,
|
2014-11-21 09:37:04 -08:00
|
|
|
dns_rdatatype_soa,
|
|
|
|
resoptions,
|
2009-09-01 00:22:28 +00:00
|
|
|
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
|
2016-12-30 15:45:08 +11:00
|
|
|
copy_name(isc_mem_t *mctx, dns_message_t *msg, const dns_name_t *name,
|
2009-09-01 00:22:28 +00:00
|
|
|
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);
|
2020-02-02 08:35:46 +01:00
|
|
|
isc_buffer_allocate(mctx, &namebuf, DNS_NAME_MAXWIRE);
|
2009-09-01 00:22:28 +00:00
|
|
|
dns_name_init(newname, NULL);
|
|
|
|
dns_name_setbuffer(newname, namebuf);
|
|
|
|
dns_message_takebuffer(msg, &namebuf);
|
2019-09-10 14:42:41 +02:00
|
|
|
dns_name_copynf(name, newname);
|
2009-09-01 00:22:28 +00:00
|
|
|
|
|
|
|
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;
|
2020-02-02 08:35:46 +01:00
|
|
|
isc_buffer_allocate(mctx, &rdatabuf, r.length);
|
2009-09-01 00:22:28 +00:00
|
|
|
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_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);
|
2018-11-19 10:31:09 +00:00
|
|
|
isc_mutex_destroy(&uarg->lock);
|
2009-09-01 00:22:28 +00:00
|
|
|
isc_mem_put(uarg->client->mctx, uarg, sizeof(*uarg));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
isc_result_t
|
|
|
|
dns_client_update(dns_client_t *client, dns_rdataclass_t rdclass,
|
2016-12-30 15:45:08 +11:00
|
|
|
const dns_name_t *zonename, dns_namelist_t *prerequisites,
|
2009-09-01 00:22:28 +00:00
|
|
|
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));
|
2009-09-02 23:48:03 +00:00
|
|
|
|
2009-09-01 00:22:28 +00:00
|
|
|
if ((client->attributes & DNS_CLIENTATTR_OWNCTX) == 0 &&
|
2014-11-21 09:37:04 -08:00
|
|
|
(options & DNS_CLIENTUPDOPT_ALLOWRUN) == 0) {
|
2009-09-01 00:22:28 +00:00
|
|
|
/*
|
|
|
|
* If the client is run under application's control, we need
|
|
|
|
* to create a new running (sub)environment for this
|
2014-11-21 09:37:04 -08:00
|
|
|
* particular update.
|
2009-09-01 00:22:28 +00:00
|
|
|
*/
|
|
|
|
return (ISC_R_NOTIMPLEMENTED); /* XXXTBD */
|
|
|
|
} else
|
|
|
|
actx = client->actx;
|
|
|
|
|
|
|
|
uarg = isc_mem_get(client->mctx, sizeof(*uarg));
|
|
|
|
|
2018-11-16 15:33:22 +01:00
|
|
|
isc_mutex_init(&uarg->lock);
|
2009-09-01 00:22:28 +00:00
|
|
|
|
|
|
|
uarg->actx = actx;
|
|
|
|
uarg->client = client;
|
|
|
|
uarg->result = ISC_R_FAILURE;
|
|
|
|
uarg->trans = NULL;
|
2018-04-17 08:29:14 -07:00
|
|
|
uarg->canceled = false;
|
2009-09-01 00:22:28 +00:00
|
|
|
|
|
|
|
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) {
|
2018-11-19 10:31:09 +00:00
|
|
|
isc_mutex_destroy(&uarg->lock);
|
2009-09-01 00:22:28 +00:00
|
|
|
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.
|
|
|
|
*/
|
2018-04-17 08:29:14 -07:00
|
|
|
uarg->canceled = true;
|
2009-09-01 00:22:28 +00:00
|
|
|
dns_client_cancelupdate(uarg->trans);
|
|
|
|
|
|
|
|
UNLOCK(&uarg->lock);
|
|
|
|
|
|
|
|
/* uarg will be freed in the event handler. */
|
|
|
|
} else {
|
|
|
|
UNLOCK(&uarg->lock);
|
|
|
|
|
2018-11-19 10:31:09 +00:00
|
|
|
isc_mutex_destroy(&uarg->lock);
|
2009-09-01 00:22:28 +00:00
|
|
|
isc_mem_put(client->mctx, uarg, sizeof(*uarg));
|
|
|
|
}
|
|
|
|
|
|
|
|
return (result);
|
|
|
|
}
|
|
|
|
|
2016-12-27 07:02:33 +11:00
|
|
|
static void
|
2016-12-28 15:50:22 +11:00
|
|
|
startupdate(isc_task_t *task, isc_event_t *event) {
|
2016-12-27 07:02:33 +11:00
|
|
|
updatectx_t *uctx;
|
|
|
|
isc_result_t result;
|
|
|
|
unsigned int resoptions;
|
|
|
|
|
|
|
|
REQUIRE(event != NULL);
|
|
|
|
|
|
|
|
UNUSED(task);
|
|
|
|
|
|
|
|
uctx = event->ev_arg;
|
|
|
|
|
|
|
|
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 {
|
|
|
|
resoptions = 0;
|
|
|
|
if (uctx->want_tcp)
|
|
|
|
resoptions |= DNS_CLIENTRESOPT_TCP;
|
|
|
|
dns_name_clone(uctx->firstname, &uctx->soaqname);
|
|
|
|
result = dns_client_startresolve(uctx->client, &uctx->soaqname,
|
|
|
|
uctx->rdclass,
|
|
|
|
dns_rdatatype_soa, resoptions,
|
|
|
|
uctx->client->task,
|
|
|
|
resolvesoa_done, uctx,
|
|
|
|
&uctx->restrans);
|
|
|
|
if (result != ISC_R_SUCCESS)
|
|
|
|
goto fail;
|
|
|
|
}
|
|
|
|
|
|
|
|
isc_event_free(&event);
|
|
|
|
|
|
|
|
fail:
|
|
|
|
if (result != ISC_R_SUCCESS)
|
|
|
|
update_sendevent(uctx, result);
|
|
|
|
}
|
|
|
|
|
2009-09-01 00:22:28 +00:00
|
|
|
isc_result_t
|
|
|
|
dns_client_startupdate(dns_client_t *client, dns_rdataclass_t rdclass,
|
2016-12-30 15:45:08 +11:00
|
|
|
const dns_name_t *zonename,
|
|
|
|
dns_namelist_t *prerequisites,
|
2009-09-01 00:22:28 +00:00
|
|
|
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;
|
2016-06-28 21:25:30 -04:00
|
|
|
isc_task_t *tclone = NULL;
|
2009-09-01 00:22:28 +00:00
|
|
|
dns_section_t section = DNS_SECTION_UPDATE;
|
|
|
|
isc_sockaddr_t *server, *sa = NULL;
|
|
|
|
dns_tsectype_t tsectype = dns_tsectype_none;
|
2018-04-17 08:29:14 -07:00
|
|
|
bool want_tcp;
|
2009-09-01 00:22:28 +00:00
|
|
|
|
|
|
|
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);
|
2016-12-27 07:02:33 +11:00
|
|
|
|
2018-10-11 11:57:57 +02:00
|
|
|
want_tcp = ((options & DNS_CLIENTUPDOPT_TCP) != 0);
|
2009-09-01 00:22:28 +00:00
|
|
|
|
2016-12-27 07:02:33 +11:00
|
|
|
/*
|
|
|
|
* Create a context and prepare some resources.
|
|
|
|
*/
|
|
|
|
|
2009-09-01 00:22:28 +00:00
|
|
|
uctx = isc_mem_get(client->mctx, sizeof(*uctx));
|
2016-12-27 07:02:33 +11:00
|
|
|
|
2018-11-16 15:33:22 +01:00
|
|
|
isc_mutex_init(&uctx->lock);
|
2016-12-27 07:02:33 +11:00
|
|
|
|
2016-06-28 21:25:30 -04:00
|
|
|
tclone = NULL;
|
|
|
|
isc_task_attach(task, &tclone);
|
2009-09-01 00:22:28 +00:00
|
|
|
uctx->client = client;
|
|
|
|
ISC_LINK_INIT(uctx, link);
|
|
|
|
uctx->state = dns_clientupdatestate_prepare;
|
|
|
|
uctx->view = view;
|
|
|
|
uctx->rdclass = rdclass;
|
2018-04-17 08:29:14 -07:00
|
|
|
uctx->canceled = false;
|
2009-09-01 00:22:28 +00:00
|
|
|
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;
|
2014-11-21 09:37:04 -08:00
|
|
|
uctx->want_tcp = want_tcp;
|
2009-09-01 00:22:28 +00:00
|
|
|
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 *)
|
2016-06-28 21:25:30 -04:00
|
|
|
isc_event_allocate(client->mctx, tclone, DNS_EVENT_UPDATEDONE,
|
2009-09-01 00:22:28 +00:00
|
|
|
action, arg, sizeof(*uctx->event));
|
|
|
|
if (zonename != NULL) {
|
|
|
|
uctx->zonename = dns_fixedname_name(&uctx->zonefname);
|
2019-09-10 14:42:41 +02:00
|
|
|
dns_name_copynf(zonename, uctx->zonename);
|
2009-09-01 00:22:28 +00:00
|
|
|
}
|
|
|
|
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));
|
|
|
|
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);
|
2019-08-06 17:35:20 +02:00
|
|
|
isc_refcount_increment(&client->references);
|
2009-09-01 00:22:28 +00:00
|
|
|
UNLOCK(&client->lock);
|
|
|
|
|
|
|
|
*transp = (dns_clientupdatetrans_t *)uctx;
|
2016-12-28 15:50:22 +11:00
|
|
|
result = isc_app_ctxonrun(client->actx, client->mctx, client->task,
|
|
|
|
startupdate, uctx);
|
2017-05-30 09:47:41 +10:00
|
|
|
if (result == ISC_R_ALREADYRUNNING) {
|
|
|
|
isc_event_t *event;
|
|
|
|
event = isc_event_allocate(client->mctx, dns_client_startupdate,
|
|
|
|
DNS_EVENT_STARTUPDATE, startupdate,
|
|
|
|
uctx, sizeof(*event));
|
2019-08-29 10:29:53 +02:00
|
|
|
result = ISC_R_SUCCESS;
|
|
|
|
isc_task_send(task, &event);
|
2017-05-30 09:47:41 +10:00
|
|
|
}
|
2016-12-28 15:50:22 +11:00
|
|
|
if (result == ISC_R_SUCCESS)
|
|
|
|
return (result);
|
2019-08-06 17:35:20 +02:00
|
|
|
|
|
|
|
isc_refcount_decrement(&client->references);
|
2016-12-28 15:50:22 +11:00
|
|
|
*transp = NULL;
|
2009-09-01 00:22:28 +00:00
|
|
|
|
|
|
|
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);
|
2016-06-28 21:25:30 -04:00
|
|
|
isc_task_detach(&tclone);
|
2018-11-19 10:31:09 +00:00
|
|
|
isc_mutex_destroy(&uctx->lock);
|
2009-09-01 00:22:28 +00:00
|
|
|
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) {
|
2018-04-17 08:29:14 -07:00
|
|
|
uctx->canceled = true;
|
2009-09-01 00:22:28 +00:00
|
|
|
if (uctx->updatereq != NULL)
|
|
|
|
dns_request_cancel(uctx->updatereq);
|
|
|
|
if (uctx->soareq != NULL)
|
|
|
|
dns_request_cancel(uctx->soareq);
|
|
|
|
if (uctx->restrans != NULL)
|
2010-04-14 22:08:47 +00:00
|
|
|
dns_client_cancelresolve(uctx->restrans);
|
2009-09-01 00:22:28 +00:00
|
|
|
if (uctx->restrans2 != NULL)
|
2010-04-14 22:08:47 +00:00
|
|
|
dns_client_cancelresolve(uctx->restrans2);
|
2009-09-01 00:22:28 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
UNLOCK(&uctx->lock);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
dns_client_destroyupdatetrans(dns_clientupdatetrans_t **transp) {
|
|
|
|
updatectx_t *uctx;
|
|
|
|
isc_mem_t *mctx;
|
|
|
|
dns_client_t *client;
|
|
|
|
isc_sockaddr_t *sa;
|
|
|
|
|
|
|
|
REQUIRE(transp != NULL);
|
|
|
|
uctx = (updatectx_t *)*transp;
|
2019-08-06 17:35:20 +02:00
|
|
|
*transp = NULL;
|
2009-09-01 00:22:28 +00:00
|
|
|
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);
|
|
|
|
|
|
|
|
UNLOCK(&client->lock);
|
|
|
|
|
2018-11-19 10:31:09 +00:00
|
|
|
isc_mutex_destroy(&uctx->lock);
|
2009-09-01 00:22:28 +00:00
|
|
|
uctx->magic = 0;
|
|
|
|
|
|
|
|
isc_mem_put(mctx, uctx, sizeof(*uctx));
|
|
|
|
|
2019-08-06 17:35:20 +02:00
|
|
|
dns_client_destroy(&client);
|
2009-09-01 00:22:28 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
2010-05-19 07:13:15 +00:00
|
|
|
unsigned char data[FLEXIBLE_ARRAY_MEMBER];
|
2009-09-01 00:22:28 +00:00
|
|
|
} dns_client_updaterec_t;
|
|
|
|
|
|
|
|
isc_result_t
|
2016-12-30 15:45:08 +11:00
|
|
|
dns_client_updaterec(dns_client_updateop_t op, const dns_name_t *owner,
|
2009-09-01 00:22:28 +00:00
|
|
|
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)
|
|
|
|
{
|
2010-05-19 07:13:15 +00:00
|
|
|
dns_client_updaterec_t *updaterec = NULL;
|
|
|
|
size_t size = offsetof(dns_client_updaterec_t, data);
|
2009-09-01 00:22:28 +00:00
|
|
|
|
|
|
|
REQUIRE(op < updateop_max);
|
|
|
|
REQUIRE(owner != NULL);
|
|
|
|
REQUIRE((rdataset != NULL && rdatalist != NULL && rdata != NULL) ||
|
|
|
|
(rdataset == NULL && rdatalist == NULL && rdata == NULL &&
|
2009-09-02 23:48:03 +00:00
|
|
|
mctx != NULL));
|
2009-09-01 00:22:28 +00:00
|
|
|
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);
|
|
|
|
rdataset = &updaterec->rdataset;
|
|
|
|
rdatalist = &updaterec->rdatalist;
|
|
|
|
rdata = &updaterec->rdata;
|
|
|
|
dns_rdataset_init(rdataset);
|
|
|
|
dns_rdatalist_init(&updaterec->rdatalist);
|
|
|
|
dns_rdata_init(&updaterec->rdata);
|
2010-05-19 07:13:15 +00:00
|
|
|
isc_buffer_init(&updaterec->buffer, updaterec->data,
|
2014-02-26 19:00:05 -08:00
|
|
|
(unsigned int)
|
|
|
|
(size -
|
|
|
|
offsetof(dns_client_updaterec_t, data)));
|
2010-05-19 07:13:15 +00:00
|
|
|
dns_name_copy(owner, target, &updaterec->buffer);
|
2009-09-01 00:22:28 +00:00
|
|
|
if (source != NULL) {
|
|
|
|
isc_region_t r;
|
|
|
|
dns_rdata_clone(source, rdata);
|
|
|
|
dns_rdata_toregion(rdata, &r);
|
2010-05-19 07:13:15 +00:00
|
|
|
rdata->data = isc_buffer_used(&updaterec->buffer);
|
|
|
|
isc_buffer_copyregion(&updaterec->buffer, &r);
|
2009-09-01 00:22:28 +00:00
|
|
|
}
|
|
|
|
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);
|
2018-11-07 15:00:07 +07:00
|
|
|
ISC_UNREACHABLE();
|
2009-09-01 00:22:28 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
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);
|
2010-05-19 07:13:15 +00:00
|
|
|
if (updaterec != NULL) {
|
2009-09-01 00:22:28 +00:00
|
|
|
target->attributes |= DNS_NAMEATTR_HASUPDATEREC;
|
2010-05-19 07:13:15 +00:00
|
|
|
dns_name_setbuffer(target, &updaterec->buffer);
|
2009-09-01 00:22:28 +00:00
|
|
|
}
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|