client.c revision 254402
1224090Sdougb/* 2254402Serwin * Copyright (C) 2009-2013 Internet Systems Consortium, Inc. ("ISC") 3224090Sdougb * 4224090Sdougb * Permission to use, copy, modify, and/or distribute this software for any 5224090Sdougb * purpose with or without fee is hereby granted, provided that the above 6224090Sdougb * copyright notice and this permission notice appear in all copies. 7224090Sdougb * 8224090Sdougb * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH 9224090Sdougb * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 10224090Sdougb * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, 11224090Sdougb * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 12224090Sdougb * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE 13224090Sdougb * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 14224090Sdougb * PERFORMANCE OF THIS SOFTWARE. 15224090Sdougb */ 16224090Sdougb 17234010Sdougb/* $Id$ */ 18224090Sdougb 19224090Sdougb#include <config.h> 20224090Sdougb 21224090Sdougb#include <stddef.h> 22224090Sdougb 23224090Sdougb#include <isc/app.h> 24224090Sdougb#include <isc/mem.h> 25224090Sdougb#include <isc/mutex.h> 26224090Sdougb#include <isc/sockaddr.h> 27224090Sdougb#include <isc/socket.h> 28224090Sdougb#include <isc/task.h> 29224090Sdougb#include <isc/timer.h> 30224090Sdougb#include <isc/util.h> 31224090Sdougb 32224090Sdougb#include <dns/adb.h> 33224090Sdougb#include <dns/client.h> 34224090Sdougb#include <dns/db.h> 35224090Sdougb#include <dns/dispatch.h> 36224090Sdougb#include <dns/events.h> 37224090Sdougb#include <dns/forward.h> 38224090Sdougb#include <dns/keytable.h> 39224090Sdougb#include <dns/message.h> 40224090Sdougb#include <dns/name.h> 41224090Sdougb#include <dns/rdata.h> 42224090Sdougb#include <dns/rdatalist.h> 43224090Sdougb#include <dns/rdataset.h> 44224090Sdougb#include <dns/rdatatype.h> 45224090Sdougb#include <dns/rdatasetiter.h> 46224090Sdougb#include <dns/rdatastruct.h> 47224090Sdougb#include <dns/request.h> 48224090Sdougb#include <dns/resolver.h> 49224090Sdougb#include <dns/result.h> 50224090Sdougb#include <dns/tsec.h> 51224090Sdougb#include <dns/tsig.h> 52224090Sdougb#include <dns/view.h> 53224090Sdougb 54224090Sdougb#include <dst/dst.h> 55224090Sdougb 56224090Sdougb#define DNS_CLIENT_MAGIC ISC_MAGIC('D', 'N', 'S', 'c') 57224090Sdougb#define DNS_CLIENT_VALID(c) ISC_MAGIC_VALID(c, DNS_CLIENT_MAGIC) 58224090Sdougb 59224090Sdougb#define RCTX_MAGIC ISC_MAGIC('R', 'c', 't', 'x') 60224090Sdougb#define RCTX_VALID(c) ISC_MAGIC_VALID(c, RCTX_MAGIC) 61224090Sdougb 62224090Sdougb#define REQCTX_MAGIC ISC_MAGIC('R', 'q', 'c', 'x') 63224090Sdougb#define REQCTX_VALID(c) ISC_MAGIC_VALID(c, REQCTX_MAGIC) 64224090Sdougb 65224090Sdougb#define UCTX_MAGIC ISC_MAGIC('U', 'c', 't', 'x') 66224090Sdougb#define UCTX_VALID(c) ISC_MAGIC_VALID(c, UCTX_MAGIC) 67224090Sdougb 68224090Sdougb#define MAX_RESTARTS 16 69224090Sdougb 70224090Sdougb/*% 71224090Sdougb * DNS client object 72224090Sdougb */ 73224090Sdougbstruct dns_client { 74224090Sdougb /* Unlocked */ 75224090Sdougb unsigned int magic; 76224090Sdougb unsigned int attributes; 77224090Sdougb isc_mutex_t lock; 78224090Sdougb isc_mem_t *mctx; 79224090Sdougb isc_appctx_t *actx; 80224090Sdougb isc_taskmgr_t *taskmgr; 81224090Sdougb isc_task_t *task; 82224090Sdougb isc_socketmgr_t *socketmgr; 83224090Sdougb isc_timermgr_t *timermgr; 84224090Sdougb dns_dispatchmgr_t *dispatchmgr; 85224090Sdougb dns_dispatch_t *dispatchv4; 86224090Sdougb dns_dispatch_t *dispatchv6; 87224090Sdougb 88224090Sdougb unsigned int update_timeout; 89224090Sdougb unsigned int update_udptimeout; 90224090Sdougb unsigned int update_udpretries; 91224090Sdougb unsigned int find_timeout; 92224090Sdougb unsigned int find_udpretries; 93224090Sdougb 94224090Sdougb /* Locked */ 95224090Sdougb unsigned int references; 96224090Sdougb dns_viewlist_t viewlist; 97224090Sdougb ISC_LIST(struct resctx) resctxs; 98224090Sdougb ISC_LIST(struct reqctx) reqctxs; 99224090Sdougb ISC_LIST(struct updatectx) updatectxs; 100224090Sdougb}; 101224090Sdougb 102224090Sdougb/*% 103224090Sdougb * Timeout/retry constants for dynamic update borrowed from nsupdate 104224090Sdougb */ 105224090Sdougb#define DEF_UPDATE_TIMEOUT 300 106224090Sdougb#define MIN_UPDATE_TIMEOUT 30 107224090Sdougb#define DEF_UPDATE_UDPTIMEOUT 3 108224090Sdougb#define DEF_UPDATE_UDPRETRIES 3 109224090Sdougb 110224090Sdougb#define DEF_FIND_TIMEOUT 5 111224090Sdougb#define DEF_FIND_UDPRETRIES 3 112224090Sdougb 113224090Sdougb#define DNS_CLIENTATTR_OWNCTX 0x01 114224090Sdougb 115224090Sdougb#define DNS_CLIENTVIEW_NAME "dnsclient" 116224090Sdougb 117224090Sdougb/*% 118224090Sdougb * Internal state for a single name resolution procedure 119224090Sdougb */ 120224090Sdougbtypedef struct resctx { 121224090Sdougb /* Unlocked */ 122224090Sdougb unsigned int magic; 123224090Sdougb isc_mutex_t lock; 124224090Sdougb dns_client_t *client; 125224090Sdougb isc_boolean_t want_dnssec; 126224090Sdougb 127224090Sdougb /* Locked */ 128224090Sdougb ISC_LINK(struct resctx) link; 129224090Sdougb isc_task_t *task; 130224090Sdougb dns_view_t *view; 131224090Sdougb unsigned int restarts; 132224090Sdougb dns_fixedname_t name; 133224090Sdougb dns_rdatatype_t type; 134224090Sdougb dns_fetch_t *fetch; 135224090Sdougb dns_namelist_t namelist; 136224090Sdougb isc_result_t result; 137224090Sdougb dns_clientresevent_t *event; 138224090Sdougb isc_boolean_t canceled; 139224090Sdougb dns_rdataset_t *rdataset; 140224090Sdougb dns_rdataset_t *sigrdataset; 141224090Sdougb} resctx_t; 142224090Sdougb 143224090Sdougb/*% 144224090Sdougb * Argument of an internal event for synchronous name resolution. 145224090Sdougb */ 146224090Sdougbtypedef struct resarg { 147224090Sdougb /* Unlocked */ 148224090Sdougb isc_appctx_t *actx; 149224090Sdougb dns_client_t *client; 150224090Sdougb isc_mutex_t lock; 151224090Sdougb 152224090Sdougb /* Locked */ 153224090Sdougb isc_result_t result; 154224090Sdougb isc_result_t vresult; 155224090Sdougb dns_namelist_t *namelist; 156224090Sdougb dns_clientrestrans_t *trans; 157224090Sdougb isc_boolean_t canceled; 158224090Sdougb} resarg_t; 159224090Sdougb 160224090Sdougb/*% 161224090Sdougb * Internal state for a single DNS request 162224090Sdougb */ 163224090Sdougbtypedef struct reqctx { 164224090Sdougb /* Unlocked */ 165224090Sdougb unsigned int magic; 166224090Sdougb isc_mutex_t lock; 167224090Sdougb dns_client_t *client; 168224090Sdougb unsigned int parseoptions; 169224090Sdougb 170224090Sdougb /* Locked */ 171224090Sdougb ISC_LINK(struct reqctx) link; 172224090Sdougb isc_boolean_t canceled; 173224090Sdougb dns_tsigkey_t *tsigkey; 174224090Sdougb dns_request_t *request; 175224090Sdougb dns_clientreqevent_t *event; 176224090Sdougb} reqctx_t; 177224090Sdougb 178224090Sdougb/*% 179224090Sdougb * Argument of an internal event for synchronous DNS request. 180224090Sdougb */ 181224090Sdougbtypedef struct reqarg { 182224090Sdougb /* Unlocked */ 183224090Sdougb isc_appctx_t *actx; 184224090Sdougb dns_client_t *client; 185224090Sdougb isc_mutex_t lock; 186224090Sdougb 187224090Sdougb /* Locked */ 188224090Sdougb isc_result_t result; 189224090Sdougb dns_clientreqtrans_t *trans; 190224090Sdougb isc_boolean_t canceled; 191224090Sdougb} reqarg_t; 192224090Sdougb 193224090Sdougb/*% 194224090Sdougb * Argument of an internal event for synchronous name resolution. 195224090Sdougb */ 196224090Sdougbtypedef struct updatearg { 197224090Sdougb /* Unlocked */ 198224090Sdougb isc_appctx_t *actx; 199224090Sdougb dns_client_t *client; 200224090Sdougb isc_mutex_t lock; 201224090Sdougb 202224090Sdougb /* Locked */ 203224090Sdougb isc_result_t result; 204224090Sdougb dns_clientupdatetrans_t *trans; 205224090Sdougb isc_boolean_t canceled; 206224090Sdougb} updatearg_t; 207224090Sdougb 208224090Sdougb/*% 209224090Sdougb * Internal state for a single dynamic update procedure 210224090Sdougb */ 211224090Sdougbtypedef struct updatectx { 212224090Sdougb /* Unlocked */ 213224090Sdougb unsigned int magic; 214224090Sdougb isc_mutex_t lock; 215224090Sdougb dns_client_t *client; 216224090Sdougb 217224090Sdougb /* Locked */ 218224090Sdougb dns_request_t *updatereq; 219224090Sdougb dns_request_t *soareq; 220224090Sdougb dns_clientrestrans_t *restrans; 221224090Sdougb dns_clientrestrans_t *restrans2; 222224090Sdougb isc_boolean_t canceled; 223224090Sdougb 224224090Sdougb /* Task Locked */ 225224090Sdougb ISC_LINK(struct updatectx) link; 226224090Sdougb dns_clientupdatestate_t state; 227224090Sdougb dns_rdataclass_t rdclass; 228224090Sdougb dns_view_t *view; 229224090Sdougb dns_message_t *updatemsg; 230224090Sdougb dns_message_t *soaquery; 231224090Sdougb dns_clientupdateevent_t *event; 232224090Sdougb dns_tsigkey_t *tsigkey; 233224090Sdougb dst_key_t *sig0key; 234224090Sdougb dns_name_t *firstname; 235224090Sdougb dns_name_t soaqname; 236224090Sdougb dns_fixedname_t zonefname; 237224090Sdougb dns_name_t *zonename; 238224090Sdougb isc_sockaddrlist_t servers; 239224090Sdougb unsigned int nservers; 240224090Sdougb isc_sockaddr_t *currentserver; 241224090Sdougb struct updatectx *bp4; 242224090Sdougb struct updatectx *bp6; 243224090Sdougb} updatectx_t; 244224090Sdougb 245224090Sdougbstatic isc_result_t request_soa(updatectx_t *uctx); 246224090Sdougbstatic void client_resfind(resctx_t *rctx, dns_fetchevent_t *event); 247224090Sdougbstatic isc_result_t send_update(updatectx_t *uctx); 248224090Sdougb 249224090Sdougbstatic isc_result_t 250224090Sdougbgetudpdispatch(int family, dns_dispatchmgr_t *dispatchmgr, 251224090Sdougb isc_socketmgr_t *socketmgr, isc_taskmgr_t *taskmgr, 252224090Sdougb isc_boolean_t is_shared, dns_dispatch_t **dispp) 253224090Sdougb{ 254224090Sdougb unsigned int attrs, attrmask; 255224090Sdougb isc_sockaddr_t sa; 256224090Sdougb dns_dispatch_t *disp; 257224090Sdougb unsigned buffersize, maxbuffers, maxrequests, buckets, increment; 258224090Sdougb isc_result_t result; 259224090Sdougb 260224090Sdougb attrs = 0; 261224090Sdougb attrs |= DNS_DISPATCHATTR_UDP; 262224090Sdougb switch (family) { 263224090Sdougb case AF_INET: 264224090Sdougb attrs |= DNS_DISPATCHATTR_IPV4; 265224090Sdougb break; 266224090Sdougb case AF_INET6: 267224090Sdougb attrs |= DNS_DISPATCHATTR_IPV6; 268224090Sdougb break; 269224090Sdougb default: 270224090Sdougb INSIST(0); 271224090Sdougb } 272224090Sdougb attrmask = 0; 273224090Sdougb attrmask |= DNS_DISPATCHATTR_UDP; 274224090Sdougb attrmask |= DNS_DISPATCHATTR_TCP; 275224090Sdougb attrmask |= DNS_DISPATCHATTR_IPV4; 276224090Sdougb attrmask |= DNS_DISPATCHATTR_IPV6; 277224090Sdougb 278224090Sdougb isc_sockaddr_anyofpf(&sa, family); 279224090Sdougb 280224090Sdougb buffersize = 4096; 281224090Sdougb maxbuffers = is_shared ? 1000 : 8; 282224090Sdougb maxrequests = 32768; 283224090Sdougb buckets = is_shared ? 16411 : 3; 284224090Sdougb increment = is_shared ? 16433 : 5; 285224090Sdougb 286224090Sdougb disp = NULL; 287224090Sdougb result = dns_dispatch_getudp(dispatchmgr, socketmgr, 288224090Sdougb taskmgr, &sa, 289224090Sdougb buffersize, maxbuffers, maxrequests, 290224090Sdougb buckets, increment, 291224090Sdougb attrs, attrmask, &disp); 292224090Sdougb if (result == ISC_R_SUCCESS) 293224090Sdougb *dispp = disp; 294224090Sdougb 295224090Sdougb return (result); 296224090Sdougb} 297224090Sdougb 298224090Sdougbstatic isc_result_t 299224090Sdougbdns_client_createview(isc_mem_t *mctx, dns_rdataclass_t rdclass, 300224090Sdougb unsigned int options, isc_taskmgr_t *taskmgr, 301224090Sdougb unsigned int ntasks, isc_socketmgr_t *socketmgr, 302224090Sdougb isc_timermgr_t *timermgr, dns_dispatchmgr_t *dispatchmgr, 303224090Sdougb dns_dispatch_t *dispatchv4, dns_dispatch_t *dispatchv6, 304224090Sdougb dns_view_t **viewp) 305224090Sdougb{ 306224090Sdougb isc_result_t result; 307224090Sdougb dns_view_t *view = NULL; 308224090Sdougb const char *dbtype; 309224090Sdougb 310224090Sdougb result = dns_view_create(mctx, rdclass, DNS_CLIENTVIEW_NAME, &view); 311224090Sdougb if (result != ISC_R_SUCCESS) 312224090Sdougb return (result); 313224090Sdougb 314224090Sdougb /* Initialize view security roots */ 315224090Sdougb result = dns_view_initsecroots(view, mctx); 316224090Sdougb if (result != ISC_R_SUCCESS) { 317224090Sdougb dns_view_detach(&view); 318224090Sdougb return (result); 319224090Sdougb } 320224090Sdougb 321224090Sdougb result = dns_view_createresolver(view, taskmgr, ntasks, socketmgr, 322224090Sdougb timermgr, 0, dispatchmgr, 323224090Sdougb dispatchv4, dispatchv6); 324224090Sdougb if (result != ISC_R_SUCCESS) { 325224090Sdougb dns_view_detach(&view); 326224090Sdougb return (result); 327224090Sdougb } 328224090Sdougb 329224090Sdougb /* 330224090Sdougb * Set cache DB. 331224090Sdougb * XXX: it may be better if specific DB implementations can be 332224090Sdougb * specified via some configuration knob. 333224090Sdougb */ 334224090Sdougb if ((options & DNS_CLIENTCREATEOPT_USECACHE) != 0) 335224090Sdougb dbtype = "rbt"; 336224090Sdougb else 337224090Sdougb dbtype = "ecdb"; 338224090Sdougb result = dns_db_create(mctx, dbtype, dns_rootname, dns_dbtype_cache, 339224090Sdougb rdclass, 0, NULL, &view->cachedb); 340224090Sdougb if (result != ISC_R_SUCCESS) { 341224090Sdougb dns_view_detach(&view); 342224090Sdougb return (result); 343224090Sdougb } 344224090Sdougb 345224090Sdougb *viewp = view; 346224090Sdougb return (ISC_R_SUCCESS); 347224090Sdougb} 348224090Sdougb 349224090Sdougbisc_result_t 350224090Sdougbdns_client_create(dns_client_t **clientp, unsigned int options) { 351224090Sdougb isc_result_t result; 352224090Sdougb isc_mem_t *mctx = NULL; 353224090Sdougb isc_appctx_t *actx = NULL; 354224090Sdougb isc_taskmgr_t *taskmgr = NULL; 355224090Sdougb isc_socketmgr_t *socketmgr = NULL; 356224090Sdougb isc_timermgr_t *timermgr = NULL; 357254402Serwin#if 0 358254402Serwin /* XXXMPA add debug logging support */ 359254402Serwin isc_log_t *lctx = NULL; 360254402Serwin isc_logconfig_t *logconfig = NULL; 361254402Serwin unsigned int logdebuglevel = 0; 362254402Serwin#endif 363224090Sdougb 364224090Sdougb result = isc_mem_create(0, 0, &mctx); 365224090Sdougb if (result != ISC_R_SUCCESS) 366224090Sdougb return (result); 367224090Sdougb result = isc_appctx_create(mctx, &actx); 368224090Sdougb if (result != ISC_R_SUCCESS) 369224090Sdougb goto cleanup; 370224090Sdougb result = isc_app_ctxstart(actx); 371224090Sdougb if (result != ISC_R_SUCCESS) 372224090Sdougb goto cleanup; 373224090Sdougb result = isc_taskmgr_createinctx(mctx, actx, 1, 0, &taskmgr); 374224090Sdougb if (result != ISC_R_SUCCESS) 375224090Sdougb goto cleanup; 376224090Sdougb result = isc_socketmgr_createinctx(mctx, actx, &socketmgr); 377224090Sdougb if (result != ISC_R_SUCCESS) 378224090Sdougb goto cleanup; 379224090Sdougb result = isc_timermgr_createinctx(mctx, actx, &timermgr); 380224090Sdougb if (result != ISC_R_SUCCESS) 381224090Sdougb goto cleanup; 382254402Serwin#if 0 383254402Serwin result = isc_log_create(mctx, &lctx, &logconfig); 384254402Serwin if (result != ISC_R_SUCCESS) 385254402Serwin goto cleanup; 386254402Serwin isc_log_setcontext(lctx); 387254402Serwin dns_log_init(lctx); 388254402Serwin dns_log_setcontext(lctx); 389254402Serwin result = isc_log_usechannel(logconfig, "default_debug", NULL, NULL); 390254402Serwin if (result != ISC_R_SUCCESS) 391254402Serwin goto cleanup; 392254402Serwin isc_log_setdebuglevel(lctx, logdebuglevel); 393254402Serwin#endif 394224090Sdougb result = dns_client_createx(mctx, actx, taskmgr, socketmgr, timermgr, 395224090Sdougb options, clientp); 396224090Sdougb if (result != ISC_R_SUCCESS) 397224090Sdougb goto cleanup; 398224090Sdougb 399224090Sdougb (*clientp)->attributes |= DNS_CLIENTATTR_OWNCTX; 400224090Sdougb 401224090Sdougb /* client has its own reference to mctx, so we can detach it here */ 402224090Sdougb isc_mem_detach(&mctx); 403224090Sdougb 404224090Sdougb return (ISC_R_SUCCESS); 405224090Sdougb 406224090Sdougb cleanup: 407224090Sdougb if (taskmgr != NULL) 408224090Sdougb isc_taskmgr_destroy(&taskmgr); 409224090Sdougb if (timermgr != NULL) 410224090Sdougb isc_timermgr_destroy(&timermgr); 411224090Sdougb if (socketmgr != NULL) 412224090Sdougb isc_socketmgr_destroy(&socketmgr); 413224090Sdougb if (actx != NULL) 414224090Sdougb isc_appctx_destroy(&actx); 415224090Sdougb isc_mem_detach(&mctx); 416224090Sdougb 417224090Sdougb return (result); 418224090Sdougb} 419224090Sdougb 420224090Sdougbisc_result_t 421224090Sdougbdns_client_createx(isc_mem_t *mctx, isc_appctx_t *actx, isc_taskmgr_t *taskmgr, 422224090Sdougb isc_socketmgr_t *socketmgr, isc_timermgr_t *timermgr, 423224090Sdougb unsigned int options, dns_client_t **clientp) 424224090Sdougb{ 425224090Sdougb dns_client_t *client; 426224090Sdougb isc_result_t result; 427224090Sdougb dns_dispatchmgr_t *dispatchmgr = NULL; 428224090Sdougb dns_dispatch_t *dispatchv4 = NULL; 429224090Sdougb dns_dispatch_t *dispatchv6 = NULL; 430224090Sdougb dns_view_t *view = NULL; 431224090Sdougb 432224090Sdougb REQUIRE(mctx != NULL); 433224090Sdougb REQUIRE(taskmgr != NULL); 434224090Sdougb REQUIRE(timermgr != NULL); 435224090Sdougb REQUIRE(socketmgr != NULL); 436224090Sdougb REQUIRE(clientp != NULL && *clientp == NULL); 437224090Sdougb 438224090Sdougb client = isc_mem_get(mctx, sizeof(*client)); 439224090Sdougb if (client == NULL) 440224090Sdougb return (ISC_R_NOMEMORY); 441224090Sdougb 442224090Sdougb result = isc_mutex_init(&client->lock); 443224090Sdougb if (result != ISC_R_SUCCESS) { 444224090Sdougb isc_mem_put(mctx, client, sizeof(*client)); 445224090Sdougb return (result); 446224090Sdougb } 447224090Sdougb 448224090Sdougb client->actx = actx; 449224090Sdougb client->taskmgr = taskmgr; 450224090Sdougb client->socketmgr = socketmgr; 451224090Sdougb client->timermgr = timermgr; 452224090Sdougb 453224090Sdougb client->task = NULL; 454224090Sdougb result = isc_task_create(client->taskmgr, 0, &client->task); 455224090Sdougb if (result != ISC_R_SUCCESS) 456224090Sdougb goto cleanup; 457224090Sdougb 458224090Sdougb result = dns_dispatchmgr_create(mctx, NULL, &dispatchmgr); 459224090Sdougb if (result != ISC_R_SUCCESS) 460224090Sdougb goto cleanup; 461224090Sdougb client->dispatchmgr = dispatchmgr; 462224090Sdougb 463224090Sdougb /* TODO: whether to use dispatch v4 or v6 should be configurable */ 464224090Sdougb client->dispatchv4 = NULL; 465224090Sdougb client->dispatchv6 = NULL; 466224090Sdougb result = getudpdispatch(AF_INET, dispatchmgr, socketmgr, 467224090Sdougb taskmgr, ISC_TRUE, &dispatchv4); 468224090Sdougb if (result == ISC_R_SUCCESS) 469224090Sdougb client->dispatchv4 = dispatchv4; 470224090Sdougb result = getudpdispatch(AF_INET6, dispatchmgr, socketmgr, 471224090Sdougb taskmgr, ISC_TRUE, &dispatchv6); 472224090Sdougb if (result == ISC_R_SUCCESS) 473224090Sdougb client->dispatchv6 = dispatchv6; 474224090Sdougb 475224090Sdougb /* We need at least one of the dispatchers */ 476224090Sdougb if (dispatchv4 == NULL && dispatchv6 == NULL) { 477224090Sdougb INSIST(result != ISC_R_SUCCESS); 478224090Sdougb goto cleanup; 479224090Sdougb } 480224090Sdougb 481224090Sdougb /* Create the default view for class IN */ 482224090Sdougb result = dns_client_createview(mctx, dns_rdataclass_in, options, 483224090Sdougb taskmgr, 31, socketmgr, timermgr, 484224090Sdougb dispatchmgr, dispatchv4, dispatchv6, 485224090Sdougb &view); 486224090Sdougb if (result != ISC_R_SUCCESS) 487224090Sdougb goto cleanup; 488224090Sdougb ISC_LIST_INIT(client->viewlist); 489224090Sdougb ISC_LIST_APPEND(client->viewlist, view, link); 490224090Sdougb 491224090Sdougb dns_view_freeze(view); /* too early? */ 492224090Sdougb 493224090Sdougb ISC_LIST_INIT(client->resctxs); 494224090Sdougb ISC_LIST_INIT(client->reqctxs); 495224090Sdougb ISC_LIST_INIT(client->updatectxs); 496224090Sdougb 497224090Sdougb client->mctx = NULL; 498224090Sdougb isc_mem_attach(mctx, &client->mctx); 499224090Sdougb 500224090Sdougb client->update_timeout = DEF_UPDATE_TIMEOUT; 501224090Sdougb client->update_udptimeout = DEF_UPDATE_UDPTIMEOUT; 502224090Sdougb client->update_udpretries = DEF_UPDATE_UDPRETRIES; 503224090Sdougb client->find_timeout = DEF_FIND_TIMEOUT; 504224090Sdougb client->find_udpretries = DEF_FIND_UDPRETRIES; 505254402Serwin client->attributes = 0; 506224090Sdougb 507224090Sdougb client->references = 1; 508224090Sdougb client->magic = DNS_CLIENT_MAGIC; 509224090Sdougb 510224090Sdougb *clientp = client; 511224090Sdougb 512224090Sdougb return (ISC_R_SUCCESS); 513224090Sdougb 514224090Sdougb cleanup: 515224090Sdougb if (dispatchv4 != NULL) 516224090Sdougb dns_dispatch_detach(&dispatchv4); 517224090Sdougb if (dispatchv6 != NULL) 518224090Sdougb dns_dispatch_detach(&dispatchv6); 519224090Sdougb if (dispatchmgr != NULL) 520224090Sdougb dns_dispatchmgr_destroy(&dispatchmgr); 521224090Sdougb if (client->task != NULL) 522224090Sdougb isc_task_detach(&client->task); 523224090Sdougb isc_mem_put(mctx, client, sizeof(*client)); 524224090Sdougb 525224090Sdougb return (result); 526224090Sdougb} 527224090Sdougb 528224090Sdougbstatic void 529224090Sdougbdestroyclient(dns_client_t **clientp) { 530224090Sdougb dns_client_t *client = *clientp; 531224090Sdougb dns_view_t *view; 532224090Sdougb 533224090Sdougb while ((view = ISC_LIST_HEAD(client->viewlist)) != NULL) { 534224090Sdougb ISC_LIST_UNLINK(client->viewlist, view, link); 535224090Sdougb dns_view_detach(&view); 536224090Sdougb } 537224090Sdougb 538224090Sdougb if (client->dispatchv4 != NULL) 539224090Sdougb dns_dispatch_detach(&client->dispatchv4); 540224090Sdougb if (client->dispatchv6 != NULL) 541224090Sdougb dns_dispatch_detach(&client->dispatchv6); 542224090Sdougb 543224090Sdougb dns_dispatchmgr_destroy(&client->dispatchmgr); 544224090Sdougb 545224090Sdougb isc_task_detach(&client->task); 546224090Sdougb 547224090Sdougb /* 548224090Sdougb * If the client has created its own running environments, 549224090Sdougb * destroy them. 550224090Sdougb */ 551224090Sdougb if ((client->attributes & DNS_CLIENTATTR_OWNCTX) != 0) { 552224090Sdougb isc_taskmgr_destroy(&client->taskmgr); 553224090Sdougb isc_timermgr_destroy(&client->timermgr); 554224090Sdougb isc_socketmgr_destroy(&client->socketmgr); 555224090Sdougb 556224090Sdougb isc_app_ctxfinish(client->actx); 557224090Sdougb isc_appctx_destroy(&client->actx); 558224090Sdougb } 559224090Sdougb 560224090Sdougb DESTROYLOCK(&client->lock); 561224090Sdougb client->magic = 0; 562224090Sdougb 563224090Sdougb isc_mem_putanddetach(&client->mctx, client, sizeof(*client)); 564224090Sdougb 565224090Sdougb *clientp = NULL; 566224090Sdougb} 567224090Sdougb 568224090Sdougbvoid 569224090Sdougbdns_client_destroy(dns_client_t **clientp) { 570224090Sdougb dns_client_t *client; 571224090Sdougb isc_boolean_t destroyok = ISC_FALSE; 572224090Sdougb 573224090Sdougb REQUIRE(clientp != NULL); 574224090Sdougb client = *clientp; 575224090Sdougb REQUIRE(DNS_CLIENT_VALID(client)); 576224090Sdougb 577224090Sdougb LOCK(&client->lock); 578224090Sdougb client->references--; 579224090Sdougb if (client->references == 0 && ISC_LIST_EMPTY(client->resctxs) && 580224090Sdougb ISC_LIST_EMPTY(client->reqctxs) && 581224090Sdougb ISC_LIST_EMPTY(client->updatectxs)) { 582224090Sdougb destroyok = ISC_TRUE; 583224090Sdougb } 584224090Sdougb UNLOCK(&client->lock); 585224090Sdougb 586224090Sdougb if (destroyok) 587224090Sdougb destroyclient(&client); 588224090Sdougb 589224090Sdougb *clientp = NULL; 590224090Sdougb} 591224090Sdougb 592224090Sdougbisc_result_t 593224090Sdougbdns_client_setservers(dns_client_t *client, dns_rdataclass_t rdclass, 594224090Sdougb dns_name_t *namespace, isc_sockaddrlist_t *addrs) 595224090Sdougb{ 596224090Sdougb isc_result_t result; 597224090Sdougb dns_view_t *view = NULL; 598224090Sdougb 599224090Sdougb REQUIRE(DNS_CLIENT_VALID(client)); 600224090Sdougb REQUIRE(addrs != NULL); 601224090Sdougb 602224090Sdougb if (namespace == NULL) 603224090Sdougb namespace = dns_rootname; 604224090Sdougb 605224090Sdougb LOCK(&client->lock); 606224090Sdougb result = dns_viewlist_find(&client->viewlist, DNS_CLIENTVIEW_NAME, 607224090Sdougb rdclass, &view); 608224090Sdougb if (result != ISC_R_SUCCESS) { 609224090Sdougb UNLOCK(&client->lock); 610224090Sdougb return (result); 611224090Sdougb } 612224090Sdougb UNLOCK(&client->lock); 613224090Sdougb 614224090Sdougb result = dns_fwdtable_add(view->fwdtable, namespace, addrs, 615224090Sdougb dns_fwdpolicy_only); 616224090Sdougb 617224090Sdougb dns_view_detach(&view); 618224090Sdougb 619224090Sdougb return (result); 620224090Sdougb} 621224090Sdougb 622224090Sdougbisc_result_t 623224090Sdougbdns_client_clearservers(dns_client_t *client, dns_rdataclass_t rdclass, 624224090Sdougb dns_name_t *namespace) 625224090Sdougb{ 626224090Sdougb isc_result_t result; 627224090Sdougb dns_view_t *view = NULL; 628224090Sdougb 629224090Sdougb REQUIRE(DNS_CLIENT_VALID(client)); 630224090Sdougb 631224090Sdougb if (namespace == NULL) 632224090Sdougb namespace = dns_rootname; 633224090Sdougb 634224090Sdougb LOCK(&client->lock); 635224090Sdougb result = dns_viewlist_find(&client->viewlist, DNS_CLIENTVIEW_NAME, 636224090Sdougb rdclass, &view); 637224090Sdougb if (result != ISC_R_SUCCESS) { 638224090Sdougb UNLOCK(&client->lock); 639224090Sdougb return (result); 640224090Sdougb } 641224090Sdougb UNLOCK(&client->lock); 642224090Sdougb 643224090Sdougb result = dns_fwdtable_delete(view->fwdtable, namespace); 644224090Sdougb 645224090Sdougb dns_view_detach(&view); 646224090Sdougb 647224090Sdougb return (result); 648224090Sdougb} 649224090Sdougb 650224090Sdougbstatic isc_result_t 651224090Sdougbgetrdataset(isc_mem_t *mctx, dns_rdataset_t **rdatasetp) { 652224090Sdougb dns_rdataset_t *rdataset; 653224090Sdougb 654224090Sdougb REQUIRE(mctx != NULL); 655224090Sdougb REQUIRE(rdatasetp != NULL && *rdatasetp == NULL); 656224090Sdougb 657224090Sdougb rdataset = isc_mem_get(mctx, sizeof(*rdataset)); 658224090Sdougb if (rdataset == NULL) 659224090Sdougb return (ISC_R_NOMEMORY); 660224090Sdougb 661224090Sdougb dns_rdataset_init(rdataset); 662224090Sdougb 663224090Sdougb *rdatasetp = rdataset; 664224090Sdougb 665224090Sdougb return (ISC_R_SUCCESS); 666224090Sdougb} 667224090Sdougb 668224090Sdougbstatic void 669224090Sdougbputrdataset(isc_mem_t *mctx, dns_rdataset_t **rdatasetp) { 670224090Sdougb dns_rdataset_t *rdataset; 671224090Sdougb 672224090Sdougb REQUIRE(rdatasetp != NULL); 673224090Sdougb rdataset = *rdatasetp; 674224090Sdougb REQUIRE(rdataset != NULL); 675224090Sdougb 676224090Sdougb if (dns_rdataset_isassociated(rdataset)) 677224090Sdougb dns_rdataset_disassociate(rdataset); 678224090Sdougb 679224090Sdougb isc_mem_put(mctx, rdataset, sizeof(*rdataset)); 680224090Sdougb 681224090Sdougb *rdatasetp = NULL; 682224090Sdougb} 683224090Sdougb 684224090Sdougbstatic void 685224090Sdougbfetch_done(isc_task_t *task, isc_event_t *event) { 686224090Sdougb resctx_t *rctx = event->ev_arg; 687224090Sdougb dns_fetchevent_t *fevent; 688224090Sdougb 689224090Sdougb REQUIRE(event->ev_type == DNS_EVENT_FETCHDONE); 690224090Sdougb REQUIRE(RCTX_VALID(rctx)); 691224090Sdougb REQUIRE(rctx->task == task); 692224090Sdougb fevent = (dns_fetchevent_t *)event; 693224090Sdougb 694224090Sdougb client_resfind(rctx, fevent); 695224090Sdougb} 696224090Sdougb 697224090Sdougbstatic inline isc_result_t 698224090Sdougbstart_fetch(resctx_t *rctx) { 699224090Sdougb isc_result_t result; 700224090Sdougb 701224090Sdougb /* 702224090Sdougb * The caller must be holding the rctx's lock. 703224090Sdougb */ 704224090Sdougb 705224090Sdougb REQUIRE(rctx->fetch == NULL); 706224090Sdougb 707224090Sdougb result = dns_resolver_createfetch(rctx->view->resolver, 708224090Sdougb dns_fixedname_name(&rctx->name), 709224090Sdougb rctx->type, 710224090Sdougb NULL, NULL, NULL, 0, 711224090Sdougb rctx->task, fetch_done, rctx, 712224090Sdougb rctx->rdataset, 713224090Sdougb rctx->sigrdataset, 714224090Sdougb &rctx->fetch); 715224090Sdougb 716224090Sdougb return (result); 717224090Sdougb} 718224090Sdougb 719224090Sdougbstatic isc_result_t 720224090Sdougbview_find(resctx_t *rctx, dns_db_t **dbp, dns_dbnode_t **nodep, 721224090Sdougb dns_name_t *foundname) 722224090Sdougb{ 723224090Sdougb isc_result_t result; 724224090Sdougb dns_name_t *name = dns_fixedname_name(&rctx->name); 725224090Sdougb dns_rdatatype_t type; 726224090Sdougb 727224090Sdougb if (rctx->type == dns_rdatatype_rrsig) 728224090Sdougb type = dns_rdatatype_any; 729224090Sdougb else 730224090Sdougb type = rctx->type; 731224090Sdougb 732224090Sdougb result = dns_view_find(rctx->view, name, type, 0, 0, ISC_FALSE, 733224090Sdougb dbp, nodep, foundname, rctx->rdataset, 734224090Sdougb rctx->sigrdataset); 735224090Sdougb 736224090Sdougb return (result); 737224090Sdougb} 738224090Sdougb 739224090Sdougbstatic void 740224090Sdougbclient_resfind(resctx_t *rctx, dns_fetchevent_t *event) { 741224090Sdougb isc_mem_t *mctx; 742225361Sdougb isc_result_t tresult, result = ISC_R_SUCCESS; 743224090Sdougb isc_result_t vresult = ISC_R_SUCCESS; 744224090Sdougb isc_boolean_t want_restart; 745224090Sdougb isc_boolean_t send_event = ISC_FALSE; 746224090Sdougb dns_name_t *name, *prefix; 747224090Sdougb dns_fixedname_t foundname, fixed; 748224090Sdougb dns_rdataset_t *trdataset; 749224090Sdougb dns_rdata_t rdata = DNS_RDATA_INIT; 750224090Sdougb unsigned int nlabels; 751224090Sdougb int order; 752224090Sdougb dns_namereln_t namereln; 753224090Sdougb dns_rdata_cname_t cname; 754224090Sdougb dns_rdata_dname_t dname; 755224090Sdougb 756224090Sdougb REQUIRE(RCTX_VALID(rctx)); 757224090Sdougb 758224090Sdougb LOCK(&rctx->lock); 759224090Sdougb 760224090Sdougb mctx = rctx->view->mctx; 761224090Sdougb 762224090Sdougb name = dns_fixedname_name(&rctx->name); 763224090Sdougb 764224090Sdougb do { 765224090Sdougb dns_name_t *fname = NULL; 766224090Sdougb dns_name_t *ansname = NULL; 767224090Sdougb dns_db_t *db = NULL; 768224090Sdougb dns_dbnode_t *node = NULL; 769224090Sdougb 770224090Sdougb rctx->restarts++; 771224090Sdougb want_restart = ISC_FALSE; 772224090Sdougb 773224090Sdougb if (event == NULL && !rctx->canceled) { 774224090Sdougb dns_fixedname_init(&foundname); 775224090Sdougb fname = dns_fixedname_name(&foundname); 776224090Sdougb INSIST(!dns_rdataset_isassociated(rctx->rdataset)); 777224090Sdougb INSIST(rctx->sigrdataset == NULL || 778224090Sdougb !dns_rdataset_isassociated(rctx->sigrdataset)); 779224090Sdougb result = view_find(rctx, &db, &node, fname); 780224090Sdougb if (result == ISC_R_NOTFOUND) { 781224090Sdougb /* 782224090Sdougb * We don't know anything about the name. 783224090Sdougb * Launch a fetch. 784224090Sdougb */ 785224090Sdougb if (node != NULL) { 786224090Sdougb INSIST(db != NULL); 787224090Sdougb dns_db_detachnode(db, &node); 788224090Sdougb } 789224090Sdougb if (db != NULL) 790224090Sdougb dns_db_detach(&db); 791224090Sdougb result = start_fetch(rctx); 792224090Sdougb if (result != ISC_R_SUCCESS) { 793224090Sdougb putrdataset(mctx, &rctx->rdataset); 794224090Sdougb if (rctx->sigrdataset != NULL) 795224090Sdougb putrdataset(mctx, 796224090Sdougb &rctx->sigrdataset); 797224090Sdougb send_event = ISC_TRUE; 798224090Sdougb } 799224090Sdougb goto done; 800224090Sdougb } 801224090Sdougb } else { 802225361Sdougb INSIST(event != NULL); 803224090Sdougb INSIST(event->fetch == rctx->fetch); 804224090Sdougb dns_resolver_destroyfetch(&rctx->fetch); 805224090Sdougb db = event->db; 806224090Sdougb node = event->node; 807224090Sdougb result = event->result; 808224090Sdougb vresult = event->vresult; 809224090Sdougb fname = dns_fixedname_name(&event->foundname); 810224090Sdougb INSIST(event->rdataset == rctx->rdataset); 811224090Sdougb INSIST(event->sigrdataset == rctx->sigrdataset); 812224090Sdougb } 813224090Sdougb 814224090Sdougb /* 815224090Sdougb * If we've been canceled, forget about the result. 816224090Sdougb */ 817224090Sdougb if (rctx->canceled) 818224090Sdougb result = ISC_R_CANCELED; 819224090Sdougb else { 820224090Sdougb /* 821224090Sdougb * Otherwise, get some resource for copying the 822224090Sdougb * result. 823224090Sdougb */ 824224090Sdougb ansname = isc_mem_get(mctx, sizeof(*ansname)); 825224090Sdougb if (ansname == NULL) 826224090Sdougb tresult = ISC_R_NOMEMORY; 827224090Sdougb else { 828224090Sdougb dns_name_t *aname; 829224090Sdougb 830224090Sdougb aname = dns_fixedname_name(&rctx->name); 831224090Sdougb dns_name_init(ansname, NULL); 832224090Sdougb tresult = dns_name_dup(aname, mctx, ansname); 833224090Sdougb if (tresult != ISC_R_SUCCESS) 834224090Sdougb isc_mem_put(mctx, ansname, 835224090Sdougb sizeof(*ansname)); 836224090Sdougb } 837224090Sdougb if (tresult != ISC_R_SUCCESS) 838224090Sdougb result = tresult; 839224090Sdougb } 840224090Sdougb 841224090Sdougb switch (result) { 842224090Sdougb case ISC_R_SUCCESS: 843224090Sdougb send_event = ISC_TRUE; 844224090Sdougb /* 845224090Sdougb * This case is handled in the main line below. 846224090Sdougb */ 847224090Sdougb break; 848224090Sdougb case DNS_R_CNAME: 849224090Sdougb /* 850224090Sdougb * Add the CNAME to the answer list. 851224090Sdougb */ 852224090Sdougb trdataset = rctx->rdataset; 853224090Sdougb ISC_LIST_APPEND(ansname->list, rctx->rdataset, link); 854224090Sdougb rctx->rdataset = NULL; 855224090Sdougb if (rctx->sigrdataset != NULL) { 856224090Sdougb ISC_LIST_APPEND(ansname->list, 857224090Sdougb rctx->sigrdataset, link); 858224090Sdougb rctx->sigrdataset = NULL; 859224090Sdougb } 860224090Sdougb ISC_LIST_APPEND(rctx->namelist, ansname, link); 861224090Sdougb ansname = NULL; 862224090Sdougb 863224090Sdougb /* 864224090Sdougb * Copy the CNAME's target into the lookup's 865224090Sdougb * query name and start over. 866224090Sdougb */ 867224090Sdougb tresult = dns_rdataset_first(trdataset); 868224090Sdougb if (tresult != ISC_R_SUCCESS) 869224090Sdougb goto done; 870224090Sdougb dns_rdataset_current(trdataset, &rdata); 871224090Sdougb tresult = dns_rdata_tostruct(&rdata, &cname, NULL); 872224090Sdougb dns_rdata_reset(&rdata); 873224090Sdougb if (tresult != ISC_R_SUCCESS) 874224090Sdougb goto done; 875224090Sdougb tresult = dns_name_copy(&cname.cname, name, NULL); 876224090Sdougb dns_rdata_freestruct(&cname); 877224090Sdougb if (tresult == ISC_R_SUCCESS) 878224090Sdougb want_restart = ISC_TRUE; 879224090Sdougb else 880224090Sdougb result = tresult; 881224090Sdougb goto done; 882224090Sdougb case DNS_R_DNAME: 883224090Sdougb /* 884224090Sdougb * Add the DNAME to the answer list. 885224090Sdougb */ 886224090Sdougb trdataset = rctx->rdataset; 887224090Sdougb ISC_LIST_APPEND(ansname->list, rctx->rdataset, link); 888224090Sdougb rctx->rdataset = NULL; 889224090Sdougb if (rctx->sigrdataset != NULL) { 890224090Sdougb ISC_LIST_APPEND(ansname->list, 891224090Sdougb rctx->sigrdataset, link); 892224090Sdougb rctx->sigrdataset = NULL; 893224090Sdougb } 894224090Sdougb ISC_LIST_APPEND(rctx->namelist, ansname, link); 895224090Sdougb ansname = NULL; 896224090Sdougb 897224090Sdougb namereln = dns_name_fullcompare(name, fname, &order, 898224090Sdougb &nlabels); 899224090Sdougb INSIST(namereln == dns_namereln_subdomain); 900224090Sdougb /* 901224090Sdougb * Get the target name of the DNAME. 902224090Sdougb */ 903224090Sdougb tresult = dns_rdataset_first(trdataset); 904224090Sdougb if (tresult != ISC_R_SUCCESS) { 905224090Sdougb result = tresult; 906224090Sdougb goto done; 907224090Sdougb } 908224090Sdougb dns_rdataset_current(trdataset, &rdata); 909224090Sdougb tresult = dns_rdata_tostruct(&rdata, &dname, NULL); 910224090Sdougb dns_rdata_reset(&rdata); 911224090Sdougb if (tresult != ISC_R_SUCCESS) { 912224090Sdougb result = tresult; 913224090Sdougb goto done; 914224090Sdougb } 915224090Sdougb /* 916224090Sdougb * Construct the new query name and start over. 917224090Sdougb */ 918224090Sdougb dns_fixedname_init(&fixed); 919224090Sdougb prefix = dns_fixedname_name(&fixed); 920224090Sdougb dns_name_split(name, nlabels, prefix, NULL); 921224090Sdougb tresult = dns_name_concatenate(prefix, &dname.dname, 922224090Sdougb name, NULL); 923224090Sdougb dns_rdata_freestruct(&dname); 924224090Sdougb if (tresult == ISC_R_SUCCESS) 925224090Sdougb want_restart = ISC_TRUE; 926224090Sdougb else 927224090Sdougb result = tresult; 928224090Sdougb goto done; 929224090Sdougb case DNS_R_NCACHENXDOMAIN: 930224090Sdougb case DNS_R_NCACHENXRRSET: 931224090Sdougb ISC_LIST_APPEND(ansname->list, rctx->rdataset, link); 932224090Sdougb ISC_LIST_APPEND(rctx->namelist, ansname, link); 933224090Sdougb ansname = NULL; 934224090Sdougb rctx->rdataset = NULL; 935224090Sdougb /* What about sigrdataset? */ 936224090Sdougb if (rctx->sigrdataset != NULL) 937224090Sdougb putrdataset(mctx, &rctx->sigrdataset); 938224090Sdougb send_event = ISC_TRUE; 939224090Sdougb goto done; 940224090Sdougb default: 941224090Sdougb if (rctx->rdataset != NULL) 942224090Sdougb putrdataset(mctx, &rctx->rdataset); 943224090Sdougb if (rctx->sigrdataset != NULL) 944224090Sdougb putrdataset(mctx, &rctx->sigrdataset); 945224090Sdougb send_event = ISC_TRUE; 946224090Sdougb goto done; 947224090Sdougb } 948224090Sdougb 949224090Sdougb if (rctx->type == dns_rdatatype_any) { 950224090Sdougb int n = 0; 951224090Sdougb dns_rdatasetiter_t *rdsiter = NULL; 952224090Sdougb 953224090Sdougb tresult = dns_db_allrdatasets(db, node, NULL, 0, 954224090Sdougb &rdsiter); 955224090Sdougb if (tresult != ISC_R_SUCCESS) { 956224090Sdougb result = tresult; 957224090Sdougb goto done; 958224090Sdougb } 959224090Sdougb 960224090Sdougb tresult = dns_rdatasetiter_first(rdsiter); 961224090Sdougb while (tresult == ISC_R_SUCCESS) { 962224090Sdougb dns_rdatasetiter_current(rdsiter, 963224090Sdougb rctx->rdataset); 964224090Sdougb if (rctx->rdataset->type != 0) { 965224090Sdougb ISC_LIST_APPEND(ansname->list, 966224090Sdougb rctx->rdataset, 967224090Sdougb link); 968224090Sdougb n++; 969224090Sdougb rctx->rdataset = NULL; 970224090Sdougb } else { 971224090Sdougb /* 972224090Sdougb * We're not interested in this 973224090Sdougb * rdataset. 974224090Sdougb */ 975224090Sdougb dns_rdataset_disassociate( 976224090Sdougb rctx->rdataset); 977224090Sdougb } 978224090Sdougb tresult = dns_rdatasetiter_next(rdsiter); 979224090Sdougb 980224090Sdougb if (tresult == ISC_R_SUCCESS && 981224090Sdougb rctx->rdataset == NULL) { 982224090Sdougb tresult = getrdataset(mctx, 983224090Sdougb &rctx->rdataset); 984224090Sdougb if (tresult != ISC_R_SUCCESS) { 985224090Sdougb result = tresult; 986225361Sdougb POST(result); 987224090Sdougb break; 988224090Sdougb } 989224090Sdougb } 990224090Sdougb } 991224090Sdougb if (n == 0) { 992224090Sdougb /* 993224090Sdougb * We didn't match any rdatasets (which means 994224090Sdougb * something went wrong in this 995224090Sdougb * implementation). 996224090Sdougb */ 997224090Sdougb result = DNS_R_SERVFAIL; /* better code? */ 998225361Sdougb POST(result); 999224090Sdougb } else { 1000224090Sdougb ISC_LIST_APPEND(rctx->namelist, ansname, link); 1001224090Sdougb ansname = NULL; 1002224090Sdougb } 1003224090Sdougb dns_rdatasetiter_destroy(&rdsiter); 1004224090Sdougb if (tresult != ISC_R_NOMORE) 1005224090Sdougb result = DNS_R_SERVFAIL; /* ditto */ 1006224090Sdougb else 1007224090Sdougb result = ISC_R_SUCCESS; 1008224090Sdougb goto done; 1009224090Sdougb } else { 1010224090Sdougb /* 1011224090Sdougb * This is the "normal" case -- an ordinary question 1012224090Sdougb * to which we've got the answer. 1013224090Sdougb */ 1014224090Sdougb ISC_LIST_APPEND(ansname->list, rctx->rdataset, link); 1015224090Sdougb rctx->rdataset = NULL; 1016224090Sdougb if (rctx->sigrdataset != NULL) { 1017224090Sdougb ISC_LIST_APPEND(ansname->list, 1018224090Sdougb rctx->sigrdataset, link); 1019224090Sdougb rctx->sigrdataset = NULL; 1020224090Sdougb } 1021224090Sdougb ISC_LIST_APPEND(rctx->namelist, ansname, link); 1022224090Sdougb ansname = NULL; 1023224090Sdougb } 1024224090Sdougb 1025224090Sdougb done: 1026224090Sdougb /* 1027224090Sdougb * Free temporary resources 1028224090Sdougb */ 1029224090Sdougb if (ansname != NULL) { 1030224090Sdougb dns_rdataset_t *rdataset; 1031224090Sdougb 1032224090Sdougb while ((rdataset = ISC_LIST_HEAD(ansname->list)) 1033224090Sdougb != NULL) { 1034224090Sdougb ISC_LIST_UNLINK(ansname->list, rdataset, link); 1035224090Sdougb putrdataset(mctx, &rdataset); 1036224090Sdougb } 1037224090Sdougb dns_name_free(ansname, mctx); 1038224090Sdougb isc_mem_put(mctx, ansname, sizeof(*ansname)); 1039224090Sdougb } 1040224090Sdougb 1041224090Sdougb if (node != NULL) 1042224090Sdougb dns_db_detachnode(db, &node); 1043224090Sdougb if (db != NULL) 1044224090Sdougb dns_db_detach(&db); 1045224090Sdougb if (event != NULL) 1046224090Sdougb isc_event_free(ISC_EVENT_PTR(&event)); 1047224090Sdougb 1048224090Sdougb /* 1049224090Sdougb * Limit the number of restarts. 1050224090Sdougb */ 1051224090Sdougb if (want_restart && rctx->restarts == MAX_RESTARTS) { 1052224090Sdougb want_restart = ISC_FALSE; 1053224090Sdougb result = ISC_R_QUOTA; 1054224090Sdougb send_event = ISC_TRUE; 1055224090Sdougb } 1056224090Sdougb 1057224090Sdougb /* 1058224090Sdougb * Prepare further find with new resources 1059224090Sdougb */ 1060224090Sdougb if (want_restart) { 1061224090Sdougb INSIST(rctx->rdataset == NULL && 1062224090Sdougb rctx->sigrdataset == NULL); 1063224090Sdougb 1064224090Sdougb result = getrdataset(mctx, &rctx->rdataset); 1065224090Sdougb if (result == ISC_R_SUCCESS && rctx->want_dnssec) { 1066224090Sdougb result = getrdataset(mctx, &rctx->sigrdataset); 1067224090Sdougb if (result != ISC_R_SUCCESS) { 1068224090Sdougb putrdataset(mctx, &rctx->rdataset); 1069224090Sdougb } 1070224090Sdougb } 1071224090Sdougb 1072224090Sdougb if (result != ISC_R_SUCCESS) { 1073224090Sdougb want_restart = ISC_FALSE; 1074224090Sdougb send_event = ISC_TRUE; 1075224090Sdougb } 1076224090Sdougb } 1077224090Sdougb } while (want_restart); 1078224090Sdougb 1079224090Sdougb if (send_event) { 1080224090Sdougb isc_task_t *task; 1081224090Sdougb 1082224090Sdougb while ((name = ISC_LIST_HEAD(rctx->namelist)) != NULL) { 1083224090Sdougb ISC_LIST_UNLINK(rctx->namelist, name, link); 1084224090Sdougb ISC_LIST_APPEND(rctx->event->answerlist, name, link); 1085224090Sdougb } 1086224090Sdougb 1087224090Sdougb rctx->event->result = result; 1088224090Sdougb rctx->event->vresult = vresult; 1089224090Sdougb task = rctx->event->ev_sender; 1090224090Sdougb rctx->event->ev_sender = rctx; 1091224090Sdougb isc_task_sendanddetach(&task, ISC_EVENT_PTR(&rctx->event)); 1092224090Sdougb } 1093224090Sdougb 1094224090Sdougb UNLOCK(&rctx->lock); 1095224090Sdougb} 1096224090Sdougb 1097224090Sdougbstatic void 1098224090Sdougbresolve_done(isc_task_t *task, isc_event_t *event) { 1099224090Sdougb resarg_t *resarg = event->ev_arg; 1100224090Sdougb dns_clientresevent_t *rev = (dns_clientresevent_t *)event; 1101224090Sdougb dns_name_t *name; 1102224090Sdougb 1103224090Sdougb UNUSED(task); 1104224090Sdougb 1105224090Sdougb LOCK(&resarg->lock); 1106224090Sdougb 1107224090Sdougb resarg->result = rev->result; 1108224090Sdougb resarg->vresult = rev->vresult; 1109224090Sdougb while ((name = ISC_LIST_HEAD(rev->answerlist)) != NULL) { 1110224090Sdougb ISC_LIST_UNLINK(rev->answerlist, name, link); 1111224090Sdougb ISC_LIST_APPEND(*resarg->namelist, name, link); 1112224090Sdougb } 1113224090Sdougb 1114224090Sdougb dns_client_destroyrestrans(&resarg->trans); 1115224090Sdougb isc_event_free(&event); 1116224090Sdougb 1117224090Sdougb if (!resarg->canceled) { 1118224090Sdougb UNLOCK(&resarg->lock); 1119224090Sdougb 1120224090Sdougb /* Exit from the internal event loop */ 1121224090Sdougb isc_app_ctxsuspend(resarg->actx); 1122224090Sdougb } else { 1123224090Sdougb /* 1124224090Sdougb * We have already exited from the loop (due to some 1125224090Sdougb * unexpected event). Just clean the arg up. 1126224090Sdougb */ 1127224090Sdougb UNLOCK(&resarg->lock); 1128224090Sdougb DESTROYLOCK(&resarg->lock); 1129224090Sdougb isc_mem_put(resarg->client->mctx, resarg, sizeof(*resarg)); 1130224090Sdougb } 1131224090Sdougb} 1132224090Sdougb 1133224090Sdougbisc_result_t 1134224090Sdougbdns_client_resolve(dns_client_t *client, dns_name_t *name, 1135224090Sdougb dns_rdataclass_t rdclass, dns_rdatatype_t type, 1136224090Sdougb unsigned int options, dns_namelist_t *namelist) 1137224090Sdougb{ 1138224090Sdougb isc_result_t result; 1139224090Sdougb isc_appctx_t *actx; 1140224090Sdougb resarg_t *resarg; 1141224090Sdougb 1142224090Sdougb REQUIRE(DNS_CLIENT_VALID(client)); 1143224090Sdougb REQUIRE(namelist != NULL && ISC_LIST_EMPTY(*namelist)); 1144224090Sdougb 1145224090Sdougb if ((client->attributes & DNS_CLIENTATTR_OWNCTX) == 0 && 1146224090Sdougb (options & DNS_CLIENTRESOPT_ALLOWRUN) == 0) { 1147224090Sdougb /* 1148224090Sdougb * If the client is run under application's control, we need 1149224090Sdougb * to create a new running (sub)environment for this 1150224090Sdougb * particular resolution. 1151224090Sdougb */ 1152224090Sdougb return (ISC_R_NOTIMPLEMENTED); /* XXXTBD */ 1153224090Sdougb } else 1154224090Sdougb actx = client->actx; 1155224090Sdougb 1156224090Sdougb resarg = isc_mem_get(client->mctx, sizeof(*resarg)); 1157224090Sdougb if (resarg == NULL) 1158224090Sdougb return (ISC_R_NOMEMORY); 1159224090Sdougb 1160224090Sdougb result = isc_mutex_init(&resarg->lock); 1161224090Sdougb if (result != ISC_R_SUCCESS) { 1162224090Sdougb isc_mem_put(client->mctx, resarg, sizeof(*resarg)); 1163224090Sdougb return (result); 1164224090Sdougb } 1165224090Sdougb 1166224090Sdougb resarg->actx = actx; 1167224090Sdougb resarg->client = client; 1168224090Sdougb resarg->result = DNS_R_SERVFAIL; 1169224090Sdougb resarg->namelist = namelist; 1170224090Sdougb resarg->trans = NULL; 1171224090Sdougb resarg->canceled = ISC_FALSE; 1172224090Sdougb result = dns_client_startresolve(client, name, rdclass, type, options, 1173224090Sdougb client->task, resolve_done, resarg, 1174224090Sdougb &resarg->trans); 1175224090Sdougb if (result != ISC_R_SUCCESS) { 1176224090Sdougb DESTROYLOCK(&resarg->lock); 1177224090Sdougb isc_mem_put(client->mctx, resarg, sizeof(*resarg)); 1178224090Sdougb return (result); 1179224090Sdougb } 1180224090Sdougb 1181224090Sdougb /* 1182224090Sdougb * Start internal event loop. It blocks until the entire process 1183224090Sdougb * is completed. 1184224090Sdougb */ 1185224090Sdougb result = isc_app_ctxrun(actx); 1186224090Sdougb 1187224090Sdougb LOCK(&resarg->lock); 1188224090Sdougb if (result == ISC_R_SUCCESS || result == ISC_R_SUSPEND) 1189224090Sdougb result = resarg->result; 1190224090Sdougb if (result != ISC_R_SUCCESS && resarg->vresult != ISC_R_SUCCESS) { 1191224090Sdougb /* 1192224090Sdougb * If this lookup failed due to some error in DNSSEC 1193224090Sdougb * validation, return the validation error code. 1194224090Sdougb * XXX: or should we pass the validation result separately? 1195224090Sdougb */ 1196224090Sdougb result = resarg->vresult; 1197224090Sdougb } 1198224090Sdougb if (resarg->trans != NULL) { 1199224090Sdougb /* 1200224090Sdougb * Unusual termination (perhaps due to signal). We need some 1201224090Sdougb * tricky cleanup process. 1202224090Sdougb */ 1203224090Sdougb resarg->canceled = ISC_TRUE; 1204224090Sdougb dns_client_cancelresolve(resarg->trans); 1205224090Sdougb 1206224090Sdougb UNLOCK(&resarg->lock); 1207224090Sdougb 1208224090Sdougb /* resarg will be freed in the event handler. */ 1209224090Sdougb } else { 1210224090Sdougb UNLOCK(&resarg->lock); 1211224090Sdougb 1212224090Sdougb DESTROYLOCK(&resarg->lock); 1213224090Sdougb isc_mem_put(client->mctx, resarg, sizeof(*resarg)); 1214224090Sdougb } 1215224090Sdougb 1216224090Sdougb return (result); 1217224090Sdougb} 1218224090Sdougb 1219224090Sdougbisc_result_t 1220224090Sdougbdns_client_startresolve(dns_client_t *client, dns_name_t *name, 1221224090Sdougb dns_rdataclass_t rdclass, dns_rdatatype_t type, 1222224090Sdougb unsigned int options, isc_task_t *task, 1223224090Sdougb isc_taskaction_t action, void *arg, 1224224090Sdougb dns_clientrestrans_t **transp) 1225224090Sdougb{ 1226224090Sdougb dns_view_t *view = NULL; 1227224090Sdougb dns_clientresevent_t *event = NULL; 1228224090Sdougb resctx_t *rctx = NULL; 1229224090Sdougb isc_task_t *clone = NULL; 1230224090Sdougb isc_mem_t *mctx; 1231224090Sdougb isc_result_t result; 1232224090Sdougb dns_rdataset_t *rdataset, *sigrdataset; 1233224090Sdougb isc_boolean_t want_dnssec; 1234224090Sdougb 1235224090Sdougb REQUIRE(DNS_CLIENT_VALID(client)); 1236224090Sdougb REQUIRE(transp != NULL && *transp == NULL); 1237224090Sdougb 1238224090Sdougb LOCK(&client->lock); 1239224090Sdougb result = dns_viewlist_find(&client->viewlist, DNS_CLIENTVIEW_NAME, 1240224090Sdougb rdclass, &view); 1241224090Sdougb UNLOCK(&client->lock); 1242224090Sdougb if (result != ISC_R_SUCCESS) 1243224090Sdougb return (result); 1244224090Sdougb 1245224090Sdougb mctx = client->mctx; 1246224090Sdougb rdataset = NULL; 1247224090Sdougb sigrdataset = NULL; 1248224090Sdougb want_dnssec = ISC_TF((options & DNS_CLIENTRESOPT_NODNSSEC) == 0); 1249224090Sdougb 1250224090Sdougb /* 1251224090Sdougb * Prepare some intermediate resources 1252224090Sdougb */ 1253224090Sdougb clone = NULL; 1254224090Sdougb isc_task_attach(task, &clone); 1255224090Sdougb event = (dns_clientresevent_t *) 1256224090Sdougb isc_event_allocate(mctx, clone, DNS_EVENT_CLIENTRESDONE, 1257224090Sdougb action, arg, sizeof(*event)); 1258224090Sdougb if (event == NULL) { 1259224090Sdougb result = ISC_R_NOMEMORY; 1260224090Sdougb goto cleanup; 1261224090Sdougb } 1262224090Sdougb event->result = DNS_R_SERVFAIL; 1263224090Sdougb ISC_LIST_INIT(event->answerlist); 1264224090Sdougb 1265224090Sdougb rctx = isc_mem_get(mctx, sizeof(*rctx)); 1266224090Sdougb if (rctx == NULL) 1267224090Sdougb result = ISC_R_NOMEMORY; 1268224090Sdougb else { 1269224090Sdougb result = isc_mutex_init(&rctx->lock); 1270224090Sdougb if (result != ISC_R_SUCCESS) { 1271224090Sdougb isc_mem_put(mctx, rctx, sizeof(*rctx)); 1272224090Sdougb rctx = NULL; 1273224090Sdougb } 1274224090Sdougb } 1275224090Sdougb if (result != ISC_R_SUCCESS) 1276224090Sdougb goto cleanup; 1277224090Sdougb 1278224090Sdougb result = getrdataset(mctx, &rdataset); 1279224090Sdougb if (result != ISC_R_SUCCESS) 1280224090Sdougb goto cleanup; 1281224090Sdougb rctx->rdataset = rdataset; 1282224090Sdougb 1283224090Sdougb if (want_dnssec) { 1284224090Sdougb result = getrdataset(mctx, &sigrdataset); 1285224090Sdougb if (result != ISC_R_SUCCESS) 1286224090Sdougb goto cleanup; 1287224090Sdougb } 1288224090Sdougb rctx->sigrdataset = sigrdataset; 1289224090Sdougb 1290224090Sdougb dns_fixedname_init(&rctx->name); 1291224090Sdougb result = dns_name_copy(name, dns_fixedname_name(&rctx->name), NULL); 1292224090Sdougb if (result != ISC_R_SUCCESS) 1293224090Sdougb goto cleanup; 1294224090Sdougb 1295224090Sdougb rctx->client = client; 1296224090Sdougb ISC_LINK_INIT(rctx, link); 1297224090Sdougb rctx->canceled = ISC_FALSE; 1298224090Sdougb rctx->task = client->task; 1299224090Sdougb rctx->type = type; 1300224090Sdougb rctx->view = view; 1301224090Sdougb rctx->restarts = 0; 1302224090Sdougb rctx->fetch = NULL; 1303224090Sdougb rctx->want_dnssec = want_dnssec; 1304224090Sdougb ISC_LIST_INIT(rctx->namelist); 1305224090Sdougb rctx->event = event; 1306224090Sdougb 1307224090Sdougb rctx->magic = RCTX_MAGIC; 1308224090Sdougb 1309224090Sdougb LOCK(&client->lock); 1310224090Sdougb ISC_LIST_APPEND(client->resctxs, rctx, link); 1311224090Sdougb UNLOCK(&client->lock); 1312224090Sdougb 1313224090Sdougb client_resfind(rctx, NULL); 1314224090Sdougb 1315224090Sdougb *transp = (dns_clientrestrans_t *)rctx; 1316224090Sdougb 1317224090Sdougb return (ISC_R_SUCCESS); 1318224090Sdougb 1319224090Sdougb cleanup: 1320224090Sdougb if (rdataset != NULL) 1321224090Sdougb putrdataset(client->mctx, &rdataset); 1322224090Sdougb if (sigrdataset != NULL) 1323224090Sdougb putrdataset(client->mctx, &sigrdataset); 1324224090Sdougb if (rctx != NULL) { 1325224090Sdougb DESTROYLOCK(&rctx->lock); 1326224090Sdougb isc_mem_put(mctx, rctx, sizeof(*rctx)); 1327224090Sdougb } 1328224090Sdougb if (event != NULL) 1329224090Sdougb isc_event_free(ISC_EVENT_PTR(&event)); 1330224090Sdougb isc_task_detach(&clone); 1331224090Sdougb dns_view_detach(&view); 1332224090Sdougb 1333224090Sdougb return (result); 1334224090Sdougb} 1335224090Sdougb 1336224090Sdougbvoid 1337224090Sdougbdns_client_cancelresolve(dns_clientrestrans_t *trans) { 1338224090Sdougb resctx_t *rctx; 1339224090Sdougb 1340224090Sdougb REQUIRE(trans != NULL); 1341224090Sdougb rctx = (resctx_t *)trans; 1342224090Sdougb REQUIRE(RCTX_VALID(rctx)); 1343224090Sdougb 1344224090Sdougb LOCK(&rctx->lock); 1345224090Sdougb 1346224090Sdougb if (!rctx->canceled) { 1347224090Sdougb rctx->canceled = ISC_TRUE; 1348224090Sdougb if (rctx->fetch != NULL) 1349224090Sdougb dns_resolver_cancelfetch(rctx->fetch); 1350224090Sdougb } 1351224090Sdougb 1352224090Sdougb UNLOCK(&rctx->lock); 1353224090Sdougb} 1354224090Sdougb 1355224090Sdougbvoid 1356224090Sdougbdns_client_freeresanswer(dns_client_t *client, dns_namelist_t *namelist) { 1357224090Sdougb dns_name_t *name; 1358224090Sdougb dns_rdataset_t *rdataset; 1359224090Sdougb 1360224090Sdougb REQUIRE(DNS_CLIENT_VALID(client)); 1361224090Sdougb REQUIRE(namelist != NULL); 1362224090Sdougb 1363224090Sdougb while ((name = ISC_LIST_HEAD(*namelist)) != NULL) { 1364224090Sdougb ISC_LIST_UNLINK(*namelist, name, link); 1365224090Sdougb while ((rdataset = ISC_LIST_HEAD(name->list)) != NULL) { 1366224090Sdougb ISC_LIST_UNLINK(name->list, rdataset, link); 1367224090Sdougb putrdataset(client->mctx, &rdataset); 1368224090Sdougb } 1369224090Sdougb dns_name_free(name, client->mctx); 1370224090Sdougb isc_mem_put(client->mctx, name, sizeof(*name)); 1371224090Sdougb } 1372224090Sdougb} 1373224090Sdougb 1374224090Sdougbvoid 1375224090Sdougbdns_client_destroyrestrans(dns_clientrestrans_t **transp) { 1376224090Sdougb resctx_t *rctx; 1377224090Sdougb isc_mem_t *mctx; 1378224090Sdougb dns_client_t *client; 1379224090Sdougb isc_boolean_t need_destroyclient = ISC_FALSE; 1380224090Sdougb 1381224090Sdougb REQUIRE(transp != NULL); 1382224090Sdougb rctx = (resctx_t *)*transp; 1383224090Sdougb REQUIRE(RCTX_VALID(rctx)); 1384224090Sdougb REQUIRE(rctx->fetch == NULL); 1385224090Sdougb REQUIRE(rctx->event == NULL); 1386224090Sdougb client = rctx->client; 1387224090Sdougb REQUIRE(DNS_CLIENT_VALID(client)); 1388224090Sdougb 1389224090Sdougb mctx = client->mctx; 1390224090Sdougb dns_view_detach(&rctx->view); 1391224090Sdougb 1392224090Sdougb LOCK(&client->lock); 1393224090Sdougb 1394224090Sdougb INSIST(ISC_LINK_LINKED(rctx, link)); 1395224090Sdougb ISC_LIST_UNLINK(client->resctxs, rctx, link); 1396224090Sdougb 1397224090Sdougb if (client->references == 0 && ISC_LIST_EMPTY(client->resctxs) && 1398224090Sdougb ISC_LIST_EMPTY(client->reqctxs) && 1399224090Sdougb ISC_LIST_EMPTY(client->updatectxs)) 1400224090Sdougb need_destroyclient = ISC_TRUE; 1401224090Sdougb 1402224090Sdougb UNLOCK(&client->lock); 1403224090Sdougb 1404224090Sdougb INSIST(ISC_LIST_EMPTY(rctx->namelist)); 1405224090Sdougb 1406224090Sdougb DESTROYLOCK(&rctx->lock); 1407224090Sdougb rctx->magic = 0; 1408224090Sdougb 1409224090Sdougb isc_mem_put(mctx, rctx, sizeof(*rctx)); 1410224090Sdougb 1411224090Sdougb if (need_destroyclient) 1412224090Sdougb destroyclient(&client); 1413224090Sdougb 1414224090Sdougb *transp = NULL; 1415224090Sdougb} 1416224090Sdougb 1417224090Sdougbisc_result_t 1418224090Sdougbdns_client_addtrustedkey(dns_client_t *client, dns_rdataclass_t rdclass, 1419224090Sdougb dns_name_t *keyname, isc_buffer_t *keydatabuf) 1420224090Sdougb{ 1421224090Sdougb isc_result_t result; 1422224090Sdougb dns_view_t *view = NULL; 1423224090Sdougb dst_key_t *dstkey = NULL; 1424224090Sdougb dns_keytable_t *secroots = NULL; 1425224090Sdougb 1426224090Sdougb REQUIRE(DNS_CLIENT_VALID(client)); 1427224090Sdougb 1428224090Sdougb LOCK(&client->lock); 1429224090Sdougb result = dns_viewlist_find(&client->viewlist, DNS_CLIENTVIEW_NAME, 1430224090Sdougb rdclass, &view); 1431224090Sdougb UNLOCK(&client->lock); 1432224090Sdougb if (result != ISC_R_SUCCESS) 1433224090Sdougb goto cleanup; 1434224090Sdougb 1435224090Sdougb result = dns_view_getsecroots(view, &secroots); 1436224090Sdougb if (result != ISC_R_SUCCESS) 1437224090Sdougb goto cleanup; 1438224090Sdougb 1439224090Sdougb result = dst_key_fromdns(keyname, rdclass, keydatabuf, client->mctx, 1440224090Sdougb &dstkey); 1441224090Sdougb if (result != ISC_R_SUCCESS) 1442224090Sdougb goto cleanup; 1443224090Sdougb 1444224090Sdougb result = dns_keytable_add(secroots, ISC_FALSE, &dstkey); 1445224090Sdougb 1446224090Sdougb cleanup: 1447224090Sdougb if (dstkey != NULL) 1448224090Sdougb dst_key_free(&dstkey); 1449224090Sdougb if (view != NULL) 1450224090Sdougb dns_view_detach(&view); 1451224090Sdougb if (secroots != NULL) 1452224090Sdougb dns_keytable_detach(&secroots); 1453224090Sdougb return (result); 1454224090Sdougb} 1455224090Sdougb 1456224090Sdougb/*% 1457224090Sdougb * Simple request routines 1458224090Sdougb */ 1459224090Sdougbstatic void 1460224090Sdougbrequest_done(isc_task_t *task, isc_event_t *event) { 1461224090Sdougb dns_requestevent_t *reqev = NULL; 1462224090Sdougb dns_request_t *request; 1463224090Sdougb isc_result_t result, eresult; 1464224090Sdougb reqctx_t *ctx; 1465224090Sdougb 1466224090Sdougb UNUSED(task); 1467224090Sdougb 1468224090Sdougb REQUIRE(event->ev_type == DNS_EVENT_REQUESTDONE); 1469224090Sdougb reqev = (dns_requestevent_t *)event; 1470224090Sdougb request = reqev->request; 1471224090Sdougb result = eresult = reqev->result; 1472224090Sdougb ctx = reqev->ev_arg; 1473224090Sdougb REQUIRE(REQCTX_VALID(ctx)); 1474224090Sdougb 1475224090Sdougb isc_event_free(&event); 1476224090Sdougb 1477224090Sdougb LOCK(&ctx->lock); 1478224090Sdougb 1479224090Sdougb if (eresult == ISC_R_SUCCESS) { 1480224090Sdougb result = dns_request_getresponse(request, ctx->event->rmessage, 1481224090Sdougb ctx->parseoptions); 1482224090Sdougb } 1483224090Sdougb 1484224090Sdougb if (ctx->tsigkey != NULL) 1485224090Sdougb dns_tsigkey_detach(&ctx->tsigkey); 1486224090Sdougb 1487224090Sdougb if (ctx->canceled) 1488224090Sdougb ctx->event->result = ISC_R_CANCELED; 1489224090Sdougb else 1490224090Sdougb ctx->event->result = result; 1491224090Sdougb task = ctx->event->ev_sender; 1492224090Sdougb ctx->event->ev_sender = ctx; 1493224090Sdougb isc_task_sendanddetach(&task, ISC_EVENT_PTR(&ctx->event)); 1494224090Sdougb 1495224090Sdougb UNLOCK(&ctx->lock); 1496224090Sdougb} 1497224090Sdougb 1498224090Sdougbstatic void 1499224090Sdougblocalrequest_done(isc_task_t *task, isc_event_t *event) { 1500224090Sdougb reqarg_t *reqarg = event->ev_arg; 1501224090Sdougb dns_clientreqevent_t *rev =(dns_clientreqevent_t *)event; 1502224090Sdougb 1503224090Sdougb UNUSED(task); 1504224090Sdougb 1505224090Sdougb REQUIRE(event->ev_type == DNS_EVENT_CLIENTREQDONE); 1506224090Sdougb 1507224090Sdougb LOCK(&reqarg->lock); 1508224090Sdougb 1509224090Sdougb reqarg->result = rev->result; 1510224090Sdougb dns_client_destroyreqtrans(&reqarg->trans); 1511224090Sdougb isc_event_free(&event); 1512224090Sdougb 1513224090Sdougb if (!reqarg->canceled) { 1514224090Sdougb UNLOCK(&reqarg->lock); 1515224090Sdougb 1516224090Sdougb /* Exit from the internal event loop */ 1517224090Sdougb isc_app_ctxsuspend(reqarg->actx); 1518224090Sdougb } else { 1519224090Sdougb /* 1520224090Sdougb * We have already exited from the loop (due to some 1521224090Sdougb * unexpected event). Just clean the arg up. 1522224090Sdougb */ 1523224090Sdougb UNLOCK(&reqarg->lock); 1524224090Sdougb DESTROYLOCK(&reqarg->lock); 1525224090Sdougb isc_mem_put(reqarg->client->mctx, reqarg, sizeof(*reqarg)); 1526224090Sdougb } 1527224090Sdougb} 1528224090Sdougb 1529224090Sdougbisc_result_t 1530224090Sdougbdns_client_request(dns_client_t *client, dns_message_t *qmessage, 1531224090Sdougb dns_message_t *rmessage, isc_sockaddr_t *server, 1532224090Sdougb unsigned int options, unsigned int parseoptions, 1533224090Sdougb dns_tsec_t *tsec, unsigned int timeout, 1534224090Sdougb unsigned int udptimeout, unsigned int udpretries) 1535224090Sdougb{ 1536224090Sdougb isc_appctx_t *actx; 1537224090Sdougb reqarg_t *reqarg; 1538224090Sdougb isc_result_t result; 1539224090Sdougb 1540224090Sdougb REQUIRE(DNS_CLIENT_VALID(client)); 1541224090Sdougb REQUIRE(qmessage != NULL); 1542224090Sdougb REQUIRE(rmessage != NULL); 1543224090Sdougb 1544224090Sdougb if ((client->attributes & DNS_CLIENTATTR_OWNCTX) == 0 && 1545224090Sdougb (options & DNS_CLIENTREQOPT_ALLOWRUN) == 0) { 1546224090Sdougb /* 1547224090Sdougb * If the client is run under application's control, we need 1548224090Sdougb * to create a new running (sub)environment for this 1549224090Sdougb * particular resolution. 1550224090Sdougb */ 1551224090Sdougb return (ISC_R_NOTIMPLEMENTED); /* XXXTBD */ 1552224090Sdougb } else 1553224090Sdougb actx = client->actx; 1554224090Sdougb 1555224090Sdougb reqarg = isc_mem_get(client->mctx, sizeof(*reqarg)); 1556224090Sdougb if (reqarg == NULL) 1557224090Sdougb return (ISC_R_NOMEMORY); 1558224090Sdougb 1559224090Sdougb result = isc_mutex_init(&reqarg->lock); 1560224090Sdougb if (result != ISC_R_SUCCESS) { 1561224090Sdougb isc_mem_put(client->mctx, reqarg, sizeof(*reqarg)); 1562224090Sdougb return (result); 1563224090Sdougb } 1564224090Sdougb 1565224090Sdougb reqarg->actx = actx; 1566224090Sdougb reqarg->client = client; 1567224090Sdougb reqarg->trans = NULL; 1568224090Sdougb reqarg->canceled = ISC_FALSE; 1569224090Sdougb 1570224090Sdougb result = dns_client_startrequest(client, qmessage, rmessage, server, 1571224090Sdougb options, parseoptions, tsec, timeout, 1572224090Sdougb udptimeout, udpretries, 1573224090Sdougb client->task, localrequest_done, 1574224090Sdougb reqarg, &reqarg->trans); 1575224090Sdougb if (result != ISC_R_SUCCESS) { 1576224090Sdougb DESTROYLOCK(&reqarg->lock); 1577224090Sdougb isc_mem_put(client->mctx, reqarg, sizeof(*reqarg)); 1578224090Sdougb return (result); 1579224090Sdougb } 1580224090Sdougb 1581224090Sdougb /* 1582224090Sdougb * Start internal event loop. It blocks until the entire process 1583224090Sdougb * is completed. 1584224090Sdougb */ 1585224090Sdougb result = isc_app_ctxrun(actx); 1586224090Sdougb 1587224090Sdougb LOCK(&reqarg->lock); 1588224090Sdougb if (result == ISC_R_SUCCESS || result == ISC_R_SUSPEND) 1589224090Sdougb result = reqarg->result; 1590224090Sdougb if (reqarg->trans != NULL) { 1591224090Sdougb /* 1592224090Sdougb * Unusual termination (perhaps due to signal). We need some 1593224090Sdougb * tricky cleanup process. 1594224090Sdougb */ 1595224090Sdougb reqarg->canceled = ISC_TRUE; 1596224090Sdougb dns_client_cancelresolve(reqarg->trans); 1597224090Sdougb 1598224090Sdougb UNLOCK(&reqarg->lock); 1599224090Sdougb 1600224090Sdougb /* reqarg will be freed in the event handler. */ 1601224090Sdougb } else { 1602224090Sdougb UNLOCK(&reqarg->lock); 1603224090Sdougb 1604224090Sdougb DESTROYLOCK(&reqarg->lock); 1605224090Sdougb isc_mem_put(client->mctx, reqarg, sizeof(*reqarg)); 1606224090Sdougb } 1607224090Sdougb 1608224090Sdougb return (result); 1609224090Sdougb} 1610224090Sdougb 1611224090Sdougbisc_result_t 1612224090Sdougbdns_client_startrequest(dns_client_t *client, dns_message_t *qmessage, 1613224090Sdougb dns_message_t *rmessage, isc_sockaddr_t *server, 1614224090Sdougb unsigned int options, unsigned int parseoptions, 1615224090Sdougb dns_tsec_t *tsec, unsigned int timeout, 1616224090Sdougb unsigned int udptimeout, unsigned int udpretries, 1617224090Sdougb isc_task_t *task, isc_taskaction_t action, void *arg, 1618224090Sdougb dns_clientreqtrans_t **transp) 1619224090Sdougb{ 1620224090Sdougb isc_result_t result; 1621224090Sdougb dns_view_t *view = NULL; 1622224090Sdougb isc_task_t *clone = NULL; 1623224090Sdougb dns_clientreqevent_t *event = NULL; 1624224090Sdougb reqctx_t *ctx = NULL; 1625224090Sdougb dns_tsectype_t tsectype = dns_tsectype_none; 1626224090Sdougb 1627224090Sdougb UNUSED(options); 1628224090Sdougb 1629224090Sdougb REQUIRE(DNS_CLIENT_VALID(client)); 1630224090Sdougb REQUIRE(qmessage != NULL); 1631224090Sdougb REQUIRE(rmessage != NULL); 1632224090Sdougb REQUIRE(transp != NULL && *transp == NULL); 1633224090Sdougb 1634224090Sdougb if (tsec != NULL) { 1635224090Sdougb tsectype = dns_tsec_gettype(tsec); 1636224090Sdougb if (tsectype != dns_tsectype_tsig) 1637224090Sdougb return (ISC_R_NOTIMPLEMENTED); /* XXX */ 1638224090Sdougb } 1639224090Sdougb 1640224090Sdougb LOCK(&client->lock); 1641224090Sdougb result = dns_viewlist_find(&client->viewlist, DNS_CLIENTVIEW_NAME, 1642224090Sdougb qmessage->rdclass, &view); 1643224090Sdougb UNLOCK(&client->lock); 1644224090Sdougb if (result != ISC_R_SUCCESS) 1645224090Sdougb return (result); 1646224090Sdougb 1647224090Sdougb clone = NULL; 1648224090Sdougb isc_task_attach(task, &clone); 1649224090Sdougb event = (dns_clientreqevent_t *) 1650224090Sdougb isc_event_allocate(client->mctx, clone, 1651224090Sdougb DNS_EVENT_CLIENTREQDONE, 1652224090Sdougb action, arg, sizeof(*event)); 1653224090Sdougb if (event == NULL) { 1654224090Sdougb result = ISC_R_NOMEMORY; 1655224090Sdougb goto cleanup; 1656224090Sdougb } 1657224090Sdougb 1658224090Sdougb ctx = isc_mem_get(client->mctx, sizeof(*ctx)); 1659224090Sdougb if (ctx == NULL) 1660224090Sdougb result = ISC_R_NOMEMORY; 1661224090Sdougb else { 1662224090Sdougb result = isc_mutex_init(&ctx->lock); 1663224090Sdougb if (result != ISC_R_SUCCESS) { 1664224090Sdougb isc_mem_put(client->mctx, ctx, sizeof(*ctx)); 1665224090Sdougb ctx = NULL; 1666224090Sdougb } 1667224090Sdougb } 1668224090Sdougb if (result != ISC_R_SUCCESS) 1669224090Sdougb goto cleanup; 1670224090Sdougb 1671224090Sdougb ctx->client = client; 1672224090Sdougb ISC_LINK_INIT(ctx, link); 1673224090Sdougb ctx->parseoptions = parseoptions; 1674224090Sdougb ctx->canceled = ISC_FALSE; 1675224090Sdougb ctx->event = event; 1676224090Sdougb ctx->event->rmessage = rmessage; 1677224090Sdougb ctx->tsigkey = NULL; 1678224090Sdougb if (tsec != NULL) 1679224090Sdougb dns_tsec_getkey(tsec, &ctx->tsigkey); 1680224090Sdougb 1681224090Sdougb ctx->magic = REQCTX_MAGIC; 1682224090Sdougb 1683224090Sdougb LOCK(&client->lock); 1684224090Sdougb ISC_LIST_APPEND(client->reqctxs, ctx, link); 1685224090Sdougb UNLOCK(&client->lock); 1686224090Sdougb 1687224090Sdougb ctx->request = NULL; 1688224090Sdougb result = dns_request_createvia3(view->requestmgr, qmessage, NULL, 1689224090Sdougb server, options, ctx->tsigkey, 1690224090Sdougb timeout, udptimeout, udpretries, 1691224090Sdougb client->task, request_done, ctx, 1692224090Sdougb &ctx->request); 1693224090Sdougb if (result == ISC_R_SUCCESS) { 1694224090Sdougb dns_view_detach(&view); 1695224090Sdougb *transp = (dns_clientreqtrans_t *)ctx; 1696224090Sdougb return (ISC_R_SUCCESS); 1697224090Sdougb } 1698224090Sdougb 1699224090Sdougb cleanup: 1700224090Sdougb if (ctx != NULL) { 1701224090Sdougb LOCK(&client->lock); 1702224090Sdougb ISC_LIST_UNLINK(client->reqctxs, ctx, link); 1703224090Sdougb UNLOCK(&client->lock); 1704224090Sdougb DESTROYLOCK(&ctx->lock); 1705224090Sdougb isc_mem_put(client->mctx, ctx, sizeof(*ctx)); 1706224090Sdougb } 1707224090Sdougb if (event != NULL) 1708224090Sdougb isc_event_free(ISC_EVENT_PTR(&event)); 1709224090Sdougb isc_task_detach(&clone); 1710224090Sdougb dns_view_detach(&view); 1711224090Sdougb 1712224090Sdougb return (result); 1713224090Sdougb} 1714224090Sdougb 1715224090Sdougbvoid 1716224090Sdougbdns_client_cancelrequest(dns_clientreqtrans_t *trans) { 1717224090Sdougb reqctx_t *ctx; 1718224090Sdougb 1719224090Sdougb REQUIRE(trans != NULL); 1720224090Sdougb ctx = (reqctx_t *)trans; 1721224090Sdougb REQUIRE(REQCTX_VALID(ctx)); 1722224090Sdougb 1723224090Sdougb LOCK(&ctx->lock); 1724224090Sdougb 1725224090Sdougb if (!ctx->canceled) { 1726224090Sdougb ctx->canceled = ISC_TRUE; 1727224090Sdougb if (ctx->request != NULL) 1728224090Sdougb dns_request_cancel(ctx->request); 1729224090Sdougb } 1730224090Sdougb 1731224090Sdougb UNLOCK(&ctx->lock); 1732224090Sdougb} 1733224090Sdougb 1734224090Sdougbvoid 1735224090Sdougbdns_client_destroyreqtrans(dns_clientreqtrans_t **transp) { 1736224090Sdougb reqctx_t *ctx; 1737224090Sdougb isc_mem_t *mctx; 1738224090Sdougb dns_client_t *client; 1739224090Sdougb isc_boolean_t need_destroyclient = ISC_FALSE; 1740224090Sdougb 1741224090Sdougb REQUIRE(transp != NULL); 1742224090Sdougb ctx = (reqctx_t *)*transp; 1743224090Sdougb REQUIRE(REQCTX_VALID(ctx)); 1744224090Sdougb client = ctx->client; 1745224090Sdougb REQUIRE(DNS_CLIENT_VALID(client)); 1746224090Sdougb REQUIRE(ctx->event == NULL); 1747224090Sdougb REQUIRE(ctx->request != NULL); 1748224090Sdougb 1749224090Sdougb dns_request_destroy(&ctx->request); 1750224090Sdougb mctx = client->mctx; 1751224090Sdougb 1752224090Sdougb LOCK(&client->lock); 1753224090Sdougb 1754224090Sdougb INSIST(ISC_LINK_LINKED(ctx, link)); 1755224090Sdougb ISC_LIST_UNLINK(client->reqctxs, ctx, link); 1756224090Sdougb 1757224090Sdougb if (client->references == 0 && ISC_LIST_EMPTY(client->resctxs) && 1758224090Sdougb ISC_LIST_EMPTY(client->reqctxs) && 1759224090Sdougb ISC_LIST_EMPTY(client->updatectxs)) { 1760224090Sdougb need_destroyclient = ISC_TRUE; 1761224090Sdougb } 1762224090Sdougb 1763224090Sdougb UNLOCK(&client->lock); 1764224090Sdougb 1765224090Sdougb DESTROYLOCK(&ctx->lock); 1766224090Sdougb ctx->magic = 0; 1767224090Sdougb 1768224090Sdougb isc_mem_put(mctx, ctx, sizeof(*ctx)); 1769224090Sdougb 1770224090Sdougb if (need_destroyclient) 1771224090Sdougb destroyclient(&client); 1772224090Sdougb 1773224090Sdougb *transp = NULL; 1774224090Sdougb} 1775224090Sdougb 1776224090Sdougb/*% 1777224090Sdougb * Dynamic update routines 1778224090Sdougb */ 1779224090Sdougbstatic isc_result_t 1780224090Sdougbrcode2result(dns_rcode_t rcode) { 1781224090Sdougb /* XXX: isn't there a similar function? */ 1782224090Sdougb switch (rcode) { 1783224090Sdougb case dns_rcode_formerr: 1784224090Sdougb return (DNS_R_FORMERR); 1785224090Sdougb case dns_rcode_servfail: 1786224090Sdougb return (DNS_R_SERVFAIL); 1787224090Sdougb case dns_rcode_nxdomain: 1788224090Sdougb return (DNS_R_NXDOMAIN); 1789224090Sdougb case dns_rcode_notimp: 1790224090Sdougb return (DNS_R_NOTIMP); 1791224090Sdougb case dns_rcode_refused: 1792224090Sdougb return (DNS_R_REFUSED); 1793224090Sdougb case dns_rcode_yxdomain: 1794224090Sdougb return (DNS_R_YXDOMAIN); 1795224090Sdougb case dns_rcode_yxrrset: 1796224090Sdougb return (DNS_R_YXRRSET); 1797224090Sdougb case dns_rcode_nxrrset: 1798224090Sdougb return (DNS_R_NXRRSET); 1799224090Sdougb case dns_rcode_notauth: 1800224090Sdougb return (DNS_R_NOTAUTH); 1801224090Sdougb case dns_rcode_notzone: 1802224090Sdougb return (DNS_R_NOTZONE); 1803224090Sdougb case dns_rcode_badvers: 1804224090Sdougb return (DNS_R_BADVERS); 1805224090Sdougb } 1806224090Sdougb 1807224090Sdougb return (ISC_R_FAILURE); 1808224090Sdougb} 1809224090Sdougb 1810224090Sdougbstatic void 1811224090Sdougbupdate_sendevent(updatectx_t *uctx, isc_result_t result) { 1812224090Sdougb isc_task_t *task; 1813224090Sdougb 1814224090Sdougb dns_message_destroy(&uctx->updatemsg); 1815224090Sdougb if (uctx->tsigkey != NULL) 1816224090Sdougb dns_tsigkey_detach(&uctx->tsigkey); 1817224090Sdougb if (uctx->sig0key != NULL) 1818224090Sdougb dst_key_free(&uctx->sig0key); 1819224090Sdougb 1820224090Sdougb if (uctx->canceled) 1821224090Sdougb uctx->event->result = ISC_R_CANCELED; 1822224090Sdougb else 1823224090Sdougb uctx->event->result = result; 1824224090Sdougb uctx->event->state = uctx->state; 1825224090Sdougb task = uctx->event->ev_sender; 1826224090Sdougb uctx->event->ev_sender = uctx; 1827224090Sdougb isc_task_sendanddetach(&task, ISC_EVENT_PTR(&uctx->event)); 1828224090Sdougb} 1829224090Sdougb 1830224090Sdougbstatic void 1831224090Sdougbupdate_done(isc_task_t *task, isc_event_t *event) { 1832224090Sdougb isc_result_t result; 1833224090Sdougb dns_requestevent_t *reqev = NULL; 1834224090Sdougb dns_request_t *request; 1835224090Sdougb dns_message_t *answer = NULL; 1836224090Sdougb updatectx_t *uctx = event->ev_arg; 1837224090Sdougb dns_client_t *client; 1838224090Sdougb unsigned int timeout; 1839224090Sdougb 1840224090Sdougb UNUSED(task); 1841224090Sdougb 1842224090Sdougb REQUIRE(event->ev_type == DNS_EVENT_REQUESTDONE); 1843224090Sdougb reqev = (dns_requestevent_t *)event; 1844224090Sdougb request = reqev->request; 1845224090Sdougb REQUIRE(UCTX_VALID(uctx)); 1846224090Sdougb client = uctx->client; 1847224090Sdougb REQUIRE(DNS_CLIENT_VALID(client)); 1848224090Sdougb 1849224090Sdougb result = reqev->result; 1850224090Sdougb if (result != ISC_R_SUCCESS) 1851224090Sdougb goto out; 1852224090Sdougb 1853224090Sdougb result = dns_message_create(client->mctx, DNS_MESSAGE_INTENTPARSE, 1854224090Sdougb &answer); 1855224090Sdougb if (result != ISC_R_SUCCESS) 1856224090Sdougb goto out; 1857224090Sdougb uctx->state = dns_clientupdatestate_done; 1858224090Sdougb result = dns_request_getresponse(request, answer, 1859224090Sdougb DNS_MESSAGEPARSE_PRESERVEORDER); 1860224090Sdougb if (result == ISC_R_SUCCESS && answer->rcode != dns_rcode_noerror) 1861224090Sdougb result = rcode2result(answer->rcode); 1862224090Sdougb 1863224090Sdougb out: 1864224090Sdougb if (answer != NULL) 1865224090Sdougb dns_message_destroy(&answer); 1866224090Sdougb isc_event_free(&event); 1867224090Sdougb 1868224090Sdougb LOCK(&uctx->lock); 1869224090Sdougb uctx->currentserver = ISC_LIST_NEXT(uctx->currentserver, link); 1870224090Sdougb dns_request_destroy(&uctx->updatereq); 1871224090Sdougb if (result != ISC_R_SUCCESS && !uctx->canceled && 1872224090Sdougb uctx->currentserver != NULL) { 1873224090Sdougb dns_message_renderreset(uctx->updatemsg); 1874224090Sdougb dns_message_settsigkey(uctx->updatemsg, NULL); 1875224090Sdougb 1876224090Sdougb timeout = client->update_timeout / uctx->nservers; 1877224090Sdougb if (timeout < MIN_UPDATE_TIMEOUT) 1878224090Sdougb timeout = MIN_UPDATE_TIMEOUT; 1879224090Sdougb result = dns_request_createvia3(uctx->view->requestmgr, 1880224090Sdougb uctx->updatemsg, 1881224090Sdougb NULL, 1882224090Sdougb uctx->currentserver, 0, 1883224090Sdougb uctx->tsigkey, 1884224090Sdougb timeout, 1885224090Sdougb client->update_udptimeout, 1886224090Sdougb client->update_udpretries, 1887224090Sdougb client->task, 1888224090Sdougb update_done, uctx, 1889224090Sdougb &uctx->updatereq); 1890224090Sdougb UNLOCK(&uctx->lock); 1891224090Sdougb 1892224090Sdougb if (result == ISC_R_SUCCESS) { 1893224090Sdougb /* XXX: should we keep the 'done' state here? */ 1894224090Sdougb uctx->state = dns_clientupdatestate_sent; 1895224090Sdougb return; 1896224090Sdougb } 1897224090Sdougb } else 1898224090Sdougb UNLOCK(&uctx->lock); 1899224090Sdougb 1900224090Sdougb update_sendevent(uctx, result); 1901224090Sdougb} 1902224090Sdougb 1903224090Sdougbstatic isc_result_t 1904224090Sdougbsend_update(updatectx_t *uctx) { 1905224090Sdougb isc_result_t result; 1906224090Sdougb dns_name_t *name = NULL; 1907224090Sdougb dns_rdataset_t *rdataset = NULL; 1908224090Sdougb dns_client_t *client = uctx->client; 1909224090Sdougb unsigned int timeout; 1910224090Sdougb 1911224090Sdougb REQUIRE(uctx->zonename != NULL && uctx->currentserver != NULL); 1912224090Sdougb 1913224090Sdougb result = dns_message_gettempname(uctx->updatemsg, &name); 1914224090Sdougb if (result != ISC_R_SUCCESS) 1915224090Sdougb return (result); 1916224090Sdougb dns_name_init(name, NULL); 1917224090Sdougb dns_name_clone(uctx->zonename, name); 1918224090Sdougb result = dns_message_gettemprdataset(uctx->updatemsg, &rdataset); 1919224090Sdougb if (result != ISC_R_SUCCESS) { 1920224090Sdougb dns_message_puttempname(uctx->updatemsg, &name); 1921224090Sdougb return (result); 1922224090Sdougb } 1923224090Sdougb dns_rdataset_makequestion(rdataset, uctx->rdclass, dns_rdatatype_soa); 1924224090Sdougb ISC_LIST_INIT(name->list); 1925224090Sdougb ISC_LIST_APPEND(name->list, rdataset, link); 1926224090Sdougb dns_message_addname(uctx->updatemsg, name, DNS_SECTION_ZONE); 1927224090Sdougb if (uctx->tsigkey == NULL && uctx->sig0key != NULL) { 1928224090Sdougb result = dns_message_setsig0key(uctx->updatemsg, 1929224090Sdougb uctx->sig0key); 1930224090Sdougb if (result != ISC_R_SUCCESS) 1931224090Sdougb return (result); 1932224090Sdougb } 1933224090Sdougb timeout = client->update_timeout / uctx->nservers; 1934224090Sdougb if (timeout < MIN_UPDATE_TIMEOUT) 1935224090Sdougb timeout = MIN_UPDATE_TIMEOUT; 1936224090Sdougb result = dns_request_createvia3(uctx->view->requestmgr, 1937224090Sdougb uctx->updatemsg, 1938224090Sdougb NULL, uctx->currentserver, 0, 1939224090Sdougb uctx->tsigkey, timeout, 1940224090Sdougb client->update_udptimeout, 1941224090Sdougb client->update_udpretries, 1942224090Sdougb client->task, update_done, uctx, 1943224090Sdougb &uctx->updatereq); 1944224090Sdougb if (result == ISC_R_SUCCESS && 1945224090Sdougb uctx->state == dns_clientupdatestate_prepare) { 1946224090Sdougb uctx->state = dns_clientupdatestate_sent; 1947224090Sdougb } 1948224090Sdougb 1949224090Sdougb return (result); 1950224090Sdougb} 1951224090Sdougb 1952224090Sdougbstatic void 1953224090Sdougbresolveaddr_done(isc_task_t *task, isc_event_t *event) { 1954224090Sdougb isc_result_t result; 1955224090Sdougb int family; 1956224090Sdougb dns_rdatatype_t qtype; 1957224090Sdougb dns_clientresevent_t *rev = (dns_clientresevent_t *)event; 1958224090Sdougb dns_name_t *name; 1959224090Sdougb dns_rdataset_t *rdataset; 1960224090Sdougb updatectx_t *uctx; 1961224090Sdougb isc_boolean_t completed = ISC_FALSE; 1962224090Sdougb 1963224090Sdougb UNUSED(task); 1964224090Sdougb 1965224090Sdougb REQUIRE(event->ev_arg != NULL); 1966224090Sdougb uctx = *(updatectx_t **)event->ev_arg; 1967224090Sdougb REQUIRE(UCTX_VALID(uctx)); 1968224090Sdougb 1969224090Sdougb if (event->ev_arg == &uctx->bp4) { 1970224090Sdougb family = AF_INET; 1971224090Sdougb qtype = dns_rdatatype_a; 1972224090Sdougb LOCK(&uctx->lock); 1973224090Sdougb dns_client_destroyrestrans(&uctx->restrans); 1974224090Sdougb UNLOCK(&uctx->lock); 1975224090Sdougb } else { 1976224090Sdougb INSIST(event->ev_arg == &uctx->bp6); 1977224090Sdougb family = AF_INET6; 1978224090Sdougb qtype = dns_rdatatype_aaaa; 1979224090Sdougb LOCK(&uctx->lock); 1980224090Sdougb dns_client_destroyrestrans(&uctx->restrans2); 1981224090Sdougb UNLOCK(&uctx->lock); 1982224090Sdougb } 1983224090Sdougb 1984224090Sdougb result = rev->result; 1985224090Sdougb if (result != ISC_R_SUCCESS) 1986224090Sdougb goto done; 1987224090Sdougb 1988224090Sdougb for (name = ISC_LIST_HEAD(rev->answerlist); name != NULL; 1989224090Sdougb name = ISC_LIST_NEXT(name, link)) { 1990224090Sdougb for (rdataset = ISC_LIST_HEAD(name->list); 1991224090Sdougb rdataset != NULL; 1992224090Sdougb rdataset = ISC_LIST_NEXT(rdataset, link)) { 1993224090Sdougb if (!dns_rdataset_isassociated(rdataset)) 1994224090Sdougb continue; 1995224090Sdougb if (rdataset->type != qtype) 1996224090Sdougb continue; 1997224090Sdougb 1998224090Sdougb for (result = dns_rdataset_first(rdataset); 1999224090Sdougb result == ISC_R_SUCCESS; 2000224090Sdougb result = dns_rdataset_next(rdataset)) { 2001224090Sdougb dns_rdata_t rdata; 2002224090Sdougb dns_rdata_in_a_t rdata_a; 2003224090Sdougb dns_rdata_in_aaaa_t rdata_aaaa; 2004224090Sdougb isc_sockaddr_t *sa; 2005224090Sdougb 2006224090Sdougb sa = isc_mem_get(uctx->client->mctx, 2007224090Sdougb sizeof(*sa)); 2008224090Sdougb if (sa == NULL) { 2009224090Sdougb /* 2010224090Sdougb * If we fail to get a sockaddr, 2011224090Sdougb we simply move forward with the 2012224090Sdougb * addresses we've got so far. 2013224090Sdougb */ 2014224090Sdougb goto done; 2015224090Sdougb } 2016224090Sdougb 2017224090Sdougb dns_rdata_init(&rdata); 2018224090Sdougb switch (family) { 2019224090Sdougb case AF_INET: 2020224090Sdougb dns_rdataset_current(rdataset, &rdata); 2021254402Serwin result = dns_rdata_tostruct(&rdata, &rdata_a, 2022254402Serwin NULL); 2023254402Serwin RUNTIME_CHECK(result == ISC_R_SUCCESS); 2024224090Sdougb isc_sockaddr_fromin(sa, 2025224090Sdougb &rdata_a.in_addr, 2026224090Sdougb 53); 2027224090Sdougb dns_rdata_freestruct(&rdata_a); 2028224090Sdougb break; 2029224090Sdougb case AF_INET6: 2030224090Sdougb dns_rdataset_current(rdataset, &rdata); 2031254402Serwin result = dns_rdata_tostruct(&rdata, &rdata_aaaa, 2032254402Serwin NULL); 2033254402Serwin RUNTIME_CHECK(result == ISC_R_SUCCESS); 2034224090Sdougb isc_sockaddr_fromin6(sa, 2035224090Sdougb &rdata_aaaa.in6_addr, 2036224090Sdougb 53); 2037224090Sdougb dns_rdata_freestruct(&rdata_aaaa); 2038224090Sdougb break; 2039224090Sdougb } 2040224090Sdougb 2041224090Sdougb ISC_LINK_INIT(sa, link); 2042224090Sdougb ISC_LIST_APPEND(uctx->servers, sa, link); 2043224090Sdougb uctx->nservers++; 2044224090Sdougb } 2045224090Sdougb } 2046224090Sdougb } 2047224090Sdougb 2048224090Sdougb done: 2049224090Sdougb dns_client_freeresanswer(uctx->client, &rev->answerlist); 2050224090Sdougb isc_event_free(&event); 2051224090Sdougb 2052224090Sdougb LOCK(&uctx->lock); 2053224090Sdougb if (uctx->restrans == NULL && uctx->restrans2 == NULL) 2054224090Sdougb completed = ISC_TRUE; 2055224090Sdougb UNLOCK(&uctx->lock); 2056224090Sdougb 2057224090Sdougb if (completed) { 2058224090Sdougb INSIST(uctx->currentserver == NULL); 2059224090Sdougb uctx->currentserver = ISC_LIST_HEAD(uctx->servers); 2060224090Sdougb if (uctx->currentserver != NULL && !uctx->canceled) 2061224090Sdougb send_update(uctx); 2062224090Sdougb else { 2063224090Sdougb if (result == ISC_R_SUCCESS) 2064224090Sdougb result = ISC_R_NOTFOUND; 2065224090Sdougb update_sendevent(uctx, result); 2066224090Sdougb } 2067224090Sdougb } 2068224090Sdougb} 2069224090Sdougb 2070224090Sdougbstatic isc_result_t 2071224090Sdougbprocess_soa(updatectx_t *uctx, dns_rdataset_t *soaset, dns_name_t *soaname) { 2072224090Sdougb isc_result_t result; 2073224090Sdougb dns_rdata_t soarr = DNS_RDATA_INIT; 2074224090Sdougb dns_rdata_soa_t soa; 2075224090Sdougb dns_name_t primary; 2076224090Sdougb 2077224090Sdougb result = dns_rdataset_first(soaset); 2078224090Sdougb if (result != ISC_R_SUCCESS) 2079224090Sdougb return (result); 2080224090Sdougb dns_rdata_init(&soarr); 2081224090Sdougb dns_rdataset_current(soaset, &soarr); 2082224090Sdougb result = dns_rdata_tostruct(&soarr, &soa, NULL); 2083224090Sdougb if (result != ISC_R_SUCCESS) 2084224090Sdougb return (result); 2085224090Sdougb 2086224090Sdougb dns_name_init(&primary, NULL); 2087224090Sdougb dns_name_clone(&soa.origin, &primary); 2088224090Sdougb 2089224090Sdougb if (uctx->zonename == NULL) { 2090224090Sdougb uctx->zonename = dns_fixedname_name(&uctx->zonefname); 2091224090Sdougb result = dns_name_copy(soaname, uctx->zonename, NULL); 2092224090Sdougb if (result != ISC_R_SUCCESS) 2093224090Sdougb goto out; 2094224090Sdougb } 2095224090Sdougb 2096224090Sdougb if (uctx->currentserver != NULL) 2097224090Sdougb result = send_update(uctx); 2098224090Sdougb else { 2099224090Sdougb /* 2100224090Sdougb * Get addresses of the primary server. We don't use the ADB 2101224090Sdougb * feature so that we could avoid caching data. 2102224090Sdougb */ 2103224090Sdougb LOCK(&uctx->lock); 2104224090Sdougb uctx->bp4 = uctx; 2105224090Sdougb result = dns_client_startresolve(uctx->client, &primary, 2106224090Sdougb uctx->rdclass, 2107224090Sdougb dns_rdatatype_a, 2108224090Sdougb 0, uctx->client->task, 2109224090Sdougb resolveaddr_done, &uctx->bp4, 2110224090Sdougb &uctx->restrans); 2111224090Sdougb if (result == ISC_R_SUCCESS) { 2112224090Sdougb uctx->bp6 = uctx; 2113224090Sdougb result = dns_client_startresolve(uctx->client, 2114224090Sdougb &primary, 2115224090Sdougb uctx->rdclass, 2116224090Sdougb dns_rdatatype_aaaa, 2117224090Sdougb 0, uctx->client->task, 2118224090Sdougb resolveaddr_done, 2119224090Sdougb &uctx->bp6, 2120224090Sdougb &uctx->restrans2); 2121224090Sdougb } 2122224090Sdougb UNLOCK(&uctx->lock); 2123224090Sdougb } 2124224090Sdougb 2125224090Sdougb out: 2126224090Sdougb dns_rdata_freestruct(&soa); 2127224090Sdougb 2128224090Sdougb return (result); 2129224090Sdougb} 2130224090Sdougb 2131224090Sdougbstatic void 2132224090Sdougbreceive_soa(isc_task_t *task, isc_event_t *event) { 2133224090Sdougb dns_requestevent_t *reqev = NULL; 2134224090Sdougb updatectx_t *uctx; 2135224090Sdougb dns_client_t *client; 2136224090Sdougb isc_result_t result, eresult; 2137224090Sdougb dns_request_t *request; 2138224090Sdougb dns_message_t *rcvmsg = NULL; 2139224090Sdougb dns_section_t section; 2140224090Sdougb dns_rdataset_t *soaset = NULL; 2141224090Sdougb int pass = 0; 2142224090Sdougb dns_name_t *name; 2143224090Sdougb dns_message_t *soaquery = NULL; 2144224090Sdougb isc_sockaddr_t *addr; 2145224090Sdougb isc_boolean_t seencname = ISC_FALSE; 2146224090Sdougb isc_boolean_t droplabel = ISC_FALSE; 2147224090Sdougb dns_name_t tname; 2148224090Sdougb unsigned int nlabels; 2149224090Sdougb 2150224090Sdougb UNUSED(task); 2151224090Sdougb 2152224090Sdougb REQUIRE(event->ev_type == DNS_EVENT_REQUESTDONE); 2153224090Sdougb reqev = (dns_requestevent_t *)event; 2154224090Sdougb request = reqev->request; 2155224090Sdougb result = eresult = reqev->result; 2156225361Sdougb POST(result); 2157224090Sdougb uctx = reqev->ev_arg; 2158224090Sdougb client = uctx->client; 2159224090Sdougb soaquery = uctx->soaquery; 2160224090Sdougb addr = uctx->currentserver; 2161224090Sdougb INSIST(addr != NULL); 2162224090Sdougb 2163224090Sdougb isc_event_free(&event); 2164224090Sdougb 2165224090Sdougb if (eresult != ISC_R_SUCCESS) { 2166224090Sdougb result = eresult; 2167224090Sdougb goto out; 2168224090Sdougb } 2169224090Sdougb 2170224090Sdougb result = dns_message_create(uctx->client->mctx, 2171224090Sdougb DNS_MESSAGE_INTENTPARSE, &rcvmsg); 2172224090Sdougb if (result != ISC_R_SUCCESS) 2173224090Sdougb goto out; 2174224090Sdougb result = dns_request_getresponse(request, rcvmsg, 2175224090Sdougb DNS_MESSAGEPARSE_PRESERVEORDER); 2176224090Sdougb 2177224090Sdougb if (result == DNS_R_TSIGERRORSET) { 2178224090Sdougb dns_request_t *newrequest = NULL; 2179224090Sdougb 2180224090Sdougb /* Retry SOA request without TSIG */ 2181224090Sdougb dns_message_destroy(&rcvmsg); 2182224090Sdougb dns_message_renderreset(uctx->soaquery); 2183224090Sdougb result = dns_request_createvia3(uctx->view->requestmgr, 2184224090Sdougb uctx->soaquery, NULL, addr, 0, 2185224090Sdougb NULL, 2186224090Sdougb client->find_timeout * 20, 2187224090Sdougb client->find_timeout, 3, 2188224090Sdougb uctx->client->task, 2189224090Sdougb receive_soa, uctx, 2190224090Sdougb &newrequest); 2191224090Sdougb if (result == ISC_R_SUCCESS) { 2192224090Sdougb LOCK(&uctx->lock); 2193224090Sdougb dns_request_destroy(&uctx->soareq); 2194224090Sdougb uctx->soareq = newrequest; 2195224090Sdougb UNLOCK(&uctx->lock); 2196224090Sdougb 2197224090Sdougb return; 2198224090Sdougb } 2199224090Sdougb goto out; 2200224090Sdougb } 2201224090Sdougb 2202224090Sdougb section = DNS_SECTION_ANSWER; 2203225361Sdougb POST(section); 2204224090Sdougb 2205224090Sdougb if (rcvmsg->rcode != dns_rcode_noerror && 2206224090Sdougb rcvmsg->rcode != dns_rcode_nxdomain) { 2207224090Sdougb result = rcode2result(rcvmsg->rcode); 2208224090Sdougb goto out; 2209224090Sdougb } 2210224090Sdougb 2211224090Sdougb lookforsoa: 2212224090Sdougb if (pass == 0) 2213224090Sdougb section = DNS_SECTION_ANSWER; 2214224090Sdougb else if (pass == 1) 2215224090Sdougb section = DNS_SECTION_AUTHORITY; 2216224090Sdougb else { 2217224090Sdougb droplabel = ISC_TRUE; 2218224090Sdougb goto out; 2219224090Sdougb } 2220224090Sdougb 2221224090Sdougb result = dns_message_firstname(rcvmsg, section); 2222224090Sdougb if (result != ISC_R_SUCCESS) { 2223224090Sdougb pass++; 2224224090Sdougb goto lookforsoa; 2225224090Sdougb } 2226224090Sdougb while (result == ISC_R_SUCCESS) { 2227224090Sdougb name = NULL; 2228224090Sdougb dns_message_currentname(rcvmsg, section, &name); 2229224090Sdougb soaset = NULL; 2230224090Sdougb result = dns_message_findtype(name, dns_rdatatype_soa, 0, 2231224090Sdougb &soaset); 2232224090Sdougb if (result == ISC_R_SUCCESS) 2233224090Sdougb break; 2234224090Sdougb if (section == DNS_SECTION_ANSWER) { 2235224090Sdougb dns_rdataset_t *tset = NULL; 2236224090Sdougb if (dns_message_findtype(name, dns_rdatatype_cname, 0, 2237224090Sdougb &tset) == ISC_R_SUCCESS 2238224090Sdougb || 2239224090Sdougb dns_message_findtype(name, dns_rdatatype_dname, 0, 2240224090Sdougb &tset) == ISC_R_SUCCESS 2241224090Sdougb ) 2242224090Sdougb { 2243224090Sdougb seencname = ISC_TRUE; 2244224090Sdougb break; 2245224090Sdougb } 2246224090Sdougb } 2247224090Sdougb 2248224090Sdougb result = dns_message_nextname(rcvmsg, section); 2249224090Sdougb } 2250224090Sdougb 2251224090Sdougb if (soaset == NULL && !seencname) { 2252224090Sdougb pass++; 2253224090Sdougb goto lookforsoa; 2254224090Sdougb } 2255224090Sdougb 2256224090Sdougb if (seencname) { 2257224090Sdougb droplabel = ISC_TRUE; 2258224090Sdougb goto out; 2259224090Sdougb } 2260224090Sdougb 2261224090Sdougb result = process_soa(uctx, soaset, name); 2262224090Sdougb 2263224090Sdougb out: 2264224090Sdougb if (droplabel) { 2265224090Sdougb result = dns_message_firstname(soaquery, DNS_SECTION_QUESTION); 2266224090Sdougb INSIST(result == ISC_R_SUCCESS); 2267224090Sdougb name = NULL; 2268224090Sdougb dns_message_currentname(soaquery, DNS_SECTION_QUESTION, &name); 2269224090Sdougb nlabels = dns_name_countlabels(name); 2270224090Sdougb if (nlabels == 1) 2271224090Sdougb result = DNS_R_SERVFAIL; /* is there a better error? */ 2272224090Sdougb else { 2273224090Sdougb dns_name_init(&tname, NULL); 2274224090Sdougb dns_name_getlabelsequence(name, 1, nlabels - 1, 2275224090Sdougb &tname); 2276224090Sdougb dns_name_clone(&tname, name); 2277224090Sdougb dns_request_destroy(&request); 2278224090Sdougb LOCK(&uctx->lock); 2279224090Sdougb uctx->soareq = NULL; 2280224090Sdougb UNLOCK(&uctx->lock); 2281224090Sdougb dns_message_renderreset(soaquery); 2282224090Sdougb dns_message_settsigkey(soaquery, NULL); 2283224090Sdougb result = dns_request_createvia3(uctx->view->requestmgr, 2284224090Sdougb soaquery, NULL, 2285224090Sdougb uctx->currentserver, 0, 2286224090Sdougb uctx->tsigkey, 2287224090Sdougb client->find_timeout * 2288224090Sdougb 20, 2289224090Sdougb client->find_timeout, 2290224090Sdougb 3, client->task, 2291224090Sdougb receive_soa, uctx, 2292224090Sdougb &uctx->soareq); 2293224090Sdougb } 2294224090Sdougb } 2295224090Sdougb 2296224090Sdougb if (!droplabel || result != ISC_R_SUCCESS) { 2297224090Sdougb dns_message_destroy(&uctx->soaquery); 2298224090Sdougb LOCK(&uctx->lock); 2299224090Sdougb dns_request_destroy(&uctx->soareq); 2300224090Sdougb UNLOCK(&uctx->lock); 2301224090Sdougb } 2302224090Sdougb 2303224090Sdougb if (rcvmsg != NULL) 2304224090Sdougb dns_message_destroy(&rcvmsg); 2305224090Sdougb 2306224090Sdougb if (result != ISC_R_SUCCESS) 2307224090Sdougb update_sendevent(uctx, result); 2308224090Sdougb} 2309224090Sdougb 2310224090Sdougbstatic isc_result_t 2311224090Sdougbrequest_soa(updatectx_t *uctx) { 2312224090Sdougb isc_result_t result; 2313224090Sdougb dns_message_t *soaquery = uctx->soaquery; 2314224090Sdougb dns_name_t *name = NULL; 2315224090Sdougb dns_rdataset_t *rdataset = NULL; 2316224090Sdougb 2317224090Sdougb if (soaquery == NULL) { 2318224090Sdougb result = dns_message_create(uctx->client->mctx, 2319224090Sdougb DNS_MESSAGE_INTENTRENDER, 2320224090Sdougb &soaquery); 2321224090Sdougb if (result != ISC_R_SUCCESS) 2322224090Sdougb return (result); 2323224090Sdougb } 2324224090Sdougb soaquery->flags |= DNS_MESSAGEFLAG_RD; 2325224090Sdougb result = dns_message_gettempname(soaquery, &name); 2326224090Sdougb if (result != ISC_R_SUCCESS) 2327224090Sdougb goto fail; 2328224090Sdougb result = dns_message_gettemprdataset(soaquery, &rdataset); 2329224090Sdougb if (result != ISC_R_SUCCESS) 2330224090Sdougb goto fail; 2331224090Sdougb dns_rdataset_makequestion(rdataset, uctx->rdclass, dns_rdatatype_soa); 2332224090Sdougb dns_name_clone(uctx->firstname, name); 2333224090Sdougb ISC_LIST_APPEND(name->list, rdataset, link); 2334224090Sdougb dns_message_addname(soaquery, name, DNS_SECTION_QUESTION); 2335224090Sdougb rdataset = NULL; 2336224090Sdougb name = NULL; 2337224090Sdougb 2338224090Sdougb result = dns_request_createvia3(uctx->view->requestmgr, 2339224090Sdougb soaquery, NULL, uctx->currentserver, 0, 2340224090Sdougb uctx->tsigkey, 2341224090Sdougb uctx->client->find_timeout * 20, 2342224090Sdougb uctx->client->find_timeout, 3, 2343224090Sdougb uctx->client->task, receive_soa, uctx, 2344224090Sdougb &uctx->soareq); 2345224090Sdougb if (result == ISC_R_SUCCESS) { 2346224090Sdougb uctx->soaquery = soaquery; 2347224090Sdougb return (ISC_R_SUCCESS); 2348224090Sdougb } 2349224090Sdougb 2350224090Sdougb fail: 2351224090Sdougb if (rdataset != NULL) { 2352224090Sdougb ISC_LIST_UNLINK(name->list, rdataset, link); /* for safety */ 2353224090Sdougb dns_message_puttemprdataset(soaquery, &rdataset); 2354224090Sdougb } 2355224090Sdougb if (name != NULL) 2356224090Sdougb dns_message_puttempname(soaquery, &name); 2357224090Sdougb dns_message_destroy(&soaquery); 2358224090Sdougb 2359224090Sdougb return (result); 2360224090Sdougb} 2361224090Sdougb 2362224090Sdougbstatic void 2363224090Sdougbresolvesoa_done(isc_task_t *task, isc_event_t *event) { 2364224090Sdougb dns_clientresevent_t *rev = (dns_clientresevent_t *)event; 2365224090Sdougb updatectx_t *uctx; 2366224090Sdougb dns_name_t *name, tname; 2367224090Sdougb dns_rdataset_t *rdataset = NULL; 2368224090Sdougb isc_result_t result = rev->result; 2369224090Sdougb unsigned int nlabels; 2370224090Sdougb 2371224090Sdougb UNUSED(task); 2372224090Sdougb 2373224090Sdougb uctx = event->ev_arg; 2374224090Sdougb REQUIRE(UCTX_VALID(uctx)); 2375224090Sdougb 2376224090Sdougb LOCK(&uctx->lock); 2377224090Sdougb dns_client_destroyrestrans(&uctx->restrans); 2378224090Sdougb UNLOCK(&uctx->lock); 2379224090Sdougb 2380224090Sdougb uctx = event->ev_arg; 2381224090Sdougb if (result != ISC_R_SUCCESS && 2382224090Sdougb result != DNS_R_NCACHENXDOMAIN && 2383224090Sdougb result != DNS_R_NCACHENXRRSET) { 2384224090Sdougb /* XXX: what about DNSSEC failure? */ 2385224090Sdougb goto out; 2386224090Sdougb } 2387224090Sdougb 2388224090Sdougb for (name = ISC_LIST_HEAD(rev->answerlist); name != NULL; 2389224090Sdougb name = ISC_LIST_NEXT(name, link)) { 2390224090Sdougb for (rdataset = ISC_LIST_HEAD(name->list); 2391224090Sdougb rdataset != NULL; 2392224090Sdougb rdataset = ISC_LIST_NEXT(rdataset, link)) { 2393224090Sdougb if (dns_rdataset_isassociated(rdataset) && 2394224090Sdougb rdataset->type == dns_rdatatype_soa) 2395224090Sdougb break; 2396224090Sdougb } 2397224090Sdougb } 2398224090Sdougb 2399224090Sdougb if (rdataset == NULL) { 2400224090Sdougb /* Drop one label and retry resolution. */ 2401224090Sdougb nlabels = dns_name_countlabels(&uctx->soaqname); 2402224090Sdougb if (nlabels == 1) { 2403224090Sdougb result = DNS_R_SERVFAIL; /* is there a better error? */ 2404224090Sdougb goto out; 2405224090Sdougb } 2406224090Sdougb dns_name_init(&tname, NULL); 2407224090Sdougb dns_name_getlabelsequence(&uctx->soaqname, 1, nlabels - 1, 2408224090Sdougb &tname); 2409224090Sdougb dns_name_clone(&tname, &uctx->soaqname); 2410224090Sdougb 2411224090Sdougb result = dns_client_startresolve(uctx->client, &uctx->soaqname, 2412224090Sdougb uctx->rdclass, 2413224090Sdougb dns_rdatatype_soa, 0, 2414224090Sdougb uctx->client->task, 2415224090Sdougb resolvesoa_done, uctx, 2416224090Sdougb &uctx->restrans); 2417224090Sdougb } else 2418224090Sdougb result = process_soa(uctx, rdataset, &uctx->soaqname); 2419224090Sdougb 2420224090Sdougb out: 2421224090Sdougb dns_client_freeresanswer(uctx->client, &rev->answerlist); 2422224090Sdougb isc_event_free(&event); 2423224090Sdougb 2424224090Sdougb if (result != ISC_R_SUCCESS) 2425224090Sdougb update_sendevent(uctx, result); 2426224090Sdougb} 2427224090Sdougb 2428224090Sdougbstatic isc_result_t 2429224090Sdougbcopy_name(isc_mem_t *mctx, dns_message_t *msg, dns_name_t *name, 2430224090Sdougb dns_name_t **newnamep) 2431224090Sdougb{ 2432224090Sdougb isc_result_t result; 2433224090Sdougb dns_name_t *newname = NULL; 2434224090Sdougb isc_region_t r; 2435224090Sdougb isc_buffer_t *namebuf = NULL, *rdatabuf = NULL; 2436224090Sdougb dns_rdatalist_t *rdatalist; 2437224090Sdougb dns_rdataset_t *rdataset, *newrdataset; 2438224090Sdougb dns_rdata_t rdata = DNS_RDATA_INIT, *newrdata; 2439224090Sdougb 2440224090Sdougb result = dns_message_gettempname(msg, &newname); 2441224090Sdougb if (result != ISC_R_SUCCESS) 2442224090Sdougb return (result); 2443224090Sdougb result = isc_buffer_allocate(mctx, &namebuf, DNS_NAME_MAXWIRE); 2444224090Sdougb if (result != ISC_R_SUCCESS) 2445224090Sdougb goto fail; 2446224090Sdougb dns_name_init(newname, NULL); 2447224090Sdougb dns_name_setbuffer(newname, namebuf); 2448224090Sdougb dns_message_takebuffer(msg, &namebuf); 2449224090Sdougb result = dns_name_copy(name, newname, NULL); 2450224090Sdougb if (result != ISC_R_SUCCESS) 2451224090Sdougb goto fail; 2452224090Sdougb 2453224090Sdougb for (rdataset = ISC_LIST_HEAD(name->list); rdataset != NULL; 2454224090Sdougb rdataset = ISC_LIST_NEXT(rdataset, link)) { 2455224090Sdougb rdatalist = NULL; 2456224090Sdougb result = dns_message_gettemprdatalist(msg, &rdatalist); 2457224090Sdougb if (result != ISC_R_SUCCESS) 2458224090Sdougb goto fail; 2459224090Sdougb dns_rdatalist_init(rdatalist); 2460224090Sdougb rdatalist->type = rdataset->type; 2461224090Sdougb rdatalist->rdclass = rdataset->rdclass; 2462224090Sdougb rdatalist->covers = rdataset->covers; 2463224090Sdougb rdatalist->ttl = rdataset->ttl; 2464224090Sdougb 2465224090Sdougb result = dns_rdataset_first(rdataset); 2466224090Sdougb while (result == ISC_R_SUCCESS) { 2467224090Sdougb dns_rdata_reset(&rdata); 2468224090Sdougb dns_rdataset_current(rdataset, &rdata); 2469224090Sdougb 2470224090Sdougb newrdata = NULL; 2471224090Sdougb result = dns_message_gettemprdata(msg, &newrdata); 2472224090Sdougb if (result != ISC_R_SUCCESS) 2473224090Sdougb goto fail; 2474224090Sdougb dns_rdata_toregion(&rdata, &r); 2475224090Sdougb rdatabuf = NULL; 2476224090Sdougb result = isc_buffer_allocate(mctx, &rdatabuf, 2477224090Sdougb r.length); 2478224090Sdougb if (result != ISC_R_SUCCESS) 2479224090Sdougb goto fail; 2480224090Sdougb isc_buffer_putmem(rdatabuf, r.base, r.length); 2481224090Sdougb isc_buffer_usedregion(rdatabuf, &r); 2482224090Sdougb dns_rdata_init(newrdata); 2483224090Sdougb dns_rdata_fromregion(newrdata, rdata.rdclass, 2484224090Sdougb rdata.type, &r); 2485224090Sdougb newrdata->flags = rdata.flags; 2486224090Sdougb 2487224090Sdougb ISC_LIST_APPEND(rdatalist->rdata, newrdata, link); 2488224090Sdougb dns_message_takebuffer(msg, &rdatabuf); 2489224090Sdougb 2490224090Sdougb result = dns_rdataset_next(rdataset); 2491224090Sdougb } 2492224090Sdougb 2493224090Sdougb newrdataset = NULL; 2494224090Sdougb result = dns_message_gettemprdataset(msg, &newrdataset); 2495224090Sdougb if (result != ISC_R_SUCCESS) 2496224090Sdougb goto fail; 2497224090Sdougb dns_rdataset_init(newrdataset); 2498224090Sdougb dns_rdatalist_tordataset(rdatalist, newrdataset); 2499224090Sdougb 2500224090Sdougb ISC_LIST_APPEND(newname->list, newrdataset, link); 2501224090Sdougb } 2502224090Sdougb 2503224090Sdougb *newnamep = newname; 2504224090Sdougb 2505224090Sdougb return (ISC_R_SUCCESS); 2506224090Sdougb 2507224090Sdougb fail: 2508224090Sdougb dns_message_puttempname(msg, &newname); 2509224090Sdougb 2510224090Sdougb return (result); 2511224090Sdougb 2512224090Sdougb} 2513224090Sdougb 2514224090Sdougbstatic void 2515224090Sdougbinternal_update_callback(isc_task_t *task, isc_event_t *event) { 2516224090Sdougb updatearg_t *uarg = event->ev_arg; 2517224090Sdougb dns_clientupdateevent_t *uev = (dns_clientupdateevent_t *)event; 2518224090Sdougb 2519224090Sdougb UNUSED(task); 2520224090Sdougb 2521224090Sdougb LOCK(&uarg->lock); 2522224090Sdougb 2523224090Sdougb uarg->result = uev->result; 2524224090Sdougb 2525224090Sdougb dns_client_destroyupdatetrans(&uarg->trans); 2526224090Sdougb isc_event_free(&event); 2527224090Sdougb 2528224090Sdougb if (!uarg->canceled) { 2529224090Sdougb UNLOCK(&uarg->lock); 2530224090Sdougb 2531224090Sdougb /* Exit from the internal event loop */ 2532224090Sdougb isc_app_ctxsuspend(uarg->actx); 2533224090Sdougb } else { 2534224090Sdougb /* 2535224090Sdougb * We have already exited from the loop (due to some 2536224090Sdougb * unexpected event). Just clean the arg up. 2537224090Sdougb */ 2538224090Sdougb UNLOCK(&uarg->lock); 2539224090Sdougb DESTROYLOCK(&uarg->lock); 2540224090Sdougb isc_mem_put(uarg->client->mctx, uarg, sizeof(*uarg)); 2541224090Sdougb } 2542224090Sdougb} 2543224090Sdougb 2544224090Sdougbisc_result_t 2545224090Sdougbdns_client_update(dns_client_t *client, dns_rdataclass_t rdclass, 2546224090Sdougb dns_name_t *zonename, dns_namelist_t *prerequisites, 2547224090Sdougb dns_namelist_t *updates, isc_sockaddrlist_t *servers, 2548224090Sdougb dns_tsec_t *tsec, unsigned int options) 2549224090Sdougb{ 2550224090Sdougb isc_result_t result; 2551224090Sdougb isc_appctx_t *actx; 2552224090Sdougb updatearg_t *uarg; 2553224090Sdougb 2554224090Sdougb REQUIRE(DNS_CLIENT_VALID(client)); 2555224090Sdougb 2556224090Sdougb if ((client->attributes & DNS_CLIENTATTR_OWNCTX) == 0 && 2557224090Sdougb (options & DNS_CLIENTRESOPT_ALLOWRUN) == 0) { 2558224090Sdougb /* 2559224090Sdougb * If the client is run under application's control, we need 2560224090Sdougb * to create a new running (sub)environment for this 2561224090Sdougb * particular resolution. 2562224090Sdougb */ 2563224090Sdougb return (ISC_R_NOTIMPLEMENTED); /* XXXTBD */ 2564224090Sdougb } else 2565224090Sdougb actx = client->actx; 2566224090Sdougb 2567224090Sdougb uarg = isc_mem_get(client->mctx, sizeof(*uarg)); 2568224090Sdougb if (uarg == NULL) 2569224090Sdougb return (ISC_R_NOMEMORY); 2570224090Sdougb 2571224090Sdougb result = isc_mutex_init(&uarg->lock); 2572224090Sdougb if (result != ISC_R_SUCCESS) { 2573224090Sdougb isc_mem_put(client->mctx, uarg, sizeof(*uarg)); 2574224090Sdougb return (result); 2575224090Sdougb } 2576224090Sdougb 2577224090Sdougb uarg->actx = actx; 2578224090Sdougb uarg->client = client; 2579224090Sdougb uarg->result = ISC_R_FAILURE; 2580224090Sdougb uarg->trans = NULL; 2581224090Sdougb uarg->canceled = ISC_FALSE; 2582224090Sdougb 2583224090Sdougb result = dns_client_startupdate(client, rdclass, zonename, 2584224090Sdougb prerequisites, updates, servers, 2585224090Sdougb tsec, options, client->task, 2586224090Sdougb internal_update_callback, uarg, 2587224090Sdougb &uarg->trans); 2588224090Sdougb if (result != ISC_R_SUCCESS) { 2589224090Sdougb DESTROYLOCK(&uarg->lock); 2590224090Sdougb isc_mem_put(client->mctx, uarg, sizeof(*uarg)); 2591224090Sdougb return (result); 2592224090Sdougb } 2593224090Sdougb 2594224090Sdougb /* 2595224090Sdougb * Start internal event loop. It blocks until the entire process 2596224090Sdougb * is completed. 2597224090Sdougb */ 2598224090Sdougb result = isc_app_ctxrun(actx); 2599224090Sdougb 2600224090Sdougb LOCK(&uarg->lock); 2601224090Sdougb if (result == ISC_R_SUCCESS || result == ISC_R_SUSPEND) 2602224090Sdougb result = uarg->result; 2603224090Sdougb 2604224090Sdougb if (uarg->trans != NULL) { 2605224090Sdougb /* 2606224090Sdougb * Unusual termination (perhaps due to signal). We need some 2607224090Sdougb * tricky cleanup process. 2608224090Sdougb */ 2609224090Sdougb uarg->canceled = ISC_TRUE; 2610224090Sdougb dns_client_cancelupdate(uarg->trans); 2611224090Sdougb 2612224090Sdougb UNLOCK(&uarg->lock); 2613224090Sdougb 2614224090Sdougb /* uarg will be freed in the event handler. */ 2615224090Sdougb } else { 2616224090Sdougb UNLOCK(&uarg->lock); 2617224090Sdougb 2618224090Sdougb DESTROYLOCK(&uarg->lock); 2619224090Sdougb isc_mem_put(client->mctx, uarg, sizeof(*uarg)); 2620224090Sdougb } 2621224090Sdougb 2622224090Sdougb return (result); 2623224090Sdougb} 2624224090Sdougb 2625224090Sdougbisc_result_t 2626224090Sdougbdns_client_startupdate(dns_client_t *client, dns_rdataclass_t rdclass, 2627224090Sdougb dns_name_t *zonename, dns_namelist_t *prerequisites, 2628224090Sdougb dns_namelist_t *updates, isc_sockaddrlist_t *servers, 2629224090Sdougb dns_tsec_t *tsec, unsigned int options, 2630224090Sdougb isc_task_t *task, isc_taskaction_t action, void *arg, 2631224090Sdougb dns_clientupdatetrans_t **transp) 2632224090Sdougb{ 2633224090Sdougb dns_view_t *view = NULL; 2634224090Sdougb isc_result_t result; 2635224090Sdougb dns_name_t *name, *newname; 2636224090Sdougb updatectx_t *uctx; 2637224090Sdougb isc_task_t *clone = NULL; 2638224090Sdougb dns_section_t section = DNS_SECTION_UPDATE; 2639224090Sdougb isc_sockaddr_t *server, *sa = NULL; 2640224090Sdougb dns_tsectype_t tsectype = dns_tsectype_none; 2641224090Sdougb 2642224090Sdougb UNUSED(options); 2643224090Sdougb 2644224090Sdougb REQUIRE(DNS_CLIENT_VALID(client)); 2645224090Sdougb REQUIRE(transp != NULL && *transp == NULL); 2646224090Sdougb REQUIRE(updates != NULL); 2647224090Sdougb REQUIRE(task != NULL); 2648224090Sdougb 2649224090Sdougb if (tsec != NULL) { 2650224090Sdougb tsectype = dns_tsec_gettype(tsec); 2651224090Sdougb if (tsectype != dns_tsectype_tsig) 2652224090Sdougb return (ISC_R_NOTIMPLEMENTED); /* XXX */ 2653224090Sdougb } 2654224090Sdougb 2655224090Sdougb LOCK(&client->lock); 2656224090Sdougb result = dns_viewlist_find(&client->viewlist, DNS_CLIENTVIEW_NAME, 2657224090Sdougb rdclass, &view); 2658224090Sdougb UNLOCK(&client->lock); 2659224090Sdougb if (result != ISC_R_SUCCESS) 2660224090Sdougb return (result); 2661224090Sdougb 2662224090Sdougb /* Create a context and prepare some resources */ 2663224090Sdougb uctx = isc_mem_get(client->mctx, sizeof(*uctx)); 2664224090Sdougb if (uctx == NULL) { 2665224090Sdougb dns_view_detach(&view); 2666224090Sdougb return (ISC_R_NOMEMORY); 2667224090Sdougb } 2668224090Sdougb result = isc_mutex_init(&uctx->lock); 2669224090Sdougb if (result != ISC_R_SUCCESS) { 2670224090Sdougb dns_view_detach(&view); 2671224090Sdougb isc_mem_put(client->mctx, uctx, sizeof(*uctx)); 2672224090Sdougb return (ISC_R_NOMEMORY); 2673224090Sdougb } 2674224090Sdougb clone = NULL; 2675224090Sdougb isc_task_attach(task, &clone); 2676224090Sdougb uctx->client = client; 2677224090Sdougb ISC_LINK_INIT(uctx, link); 2678224090Sdougb uctx->state = dns_clientupdatestate_prepare; 2679224090Sdougb uctx->view = view; 2680224090Sdougb uctx->rdclass = rdclass; 2681224090Sdougb uctx->canceled = ISC_FALSE; 2682224090Sdougb uctx->updatemsg = NULL; 2683224090Sdougb uctx->soaquery = NULL; 2684224090Sdougb uctx->updatereq = NULL; 2685224090Sdougb uctx->restrans = NULL; 2686224090Sdougb uctx->restrans2 = NULL; 2687224090Sdougb uctx->bp4 = NULL; 2688224090Sdougb uctx->bp6 = NULL; 2689224090Sdougb uctx->soareq = NULL; 2690224090Sdougb uctx->event = NULL; 2691224090Sdougb uctx->tsigkey = NULL; 2692224090Sdougb uctx->sig0key = NULL; 2693224090Sdougb uctx->zonename = NULL; 2694224090Sdougb dns_name_init(&uctx->soaqname, NULL); 2695224090Sdougb ISC_LIST_INIT(uctx->servers); 2696224090Sdougb uctx->nservers = 0; 2697224090Sdougb uctx->currentserver = NULL; 2698224090Sdougb dns_fixedname_init(&uctx->zonefname); 2699224090Sdougb if (tsec != NULL) 2700224090Sdougb dns_tsec_getkey(tsec, &uctx->tsigkey); 2701224090Sdougb uctx->event = (dns_clientupdateevent_t *) 2702224090Sdougb isc_event_allocate(client->mctx, clone, DNS_EVENT_UPDATEDONE, 2703224090Sdougb action, arg, sizeof(*uctx->event)); 2704224090Sdougb if (uctx->event == NULL) 2705224090Sdougb goto fail; 2706224090Sdougb if (zonename != NULL) { 2707224090Sdougb uctx->zonename = dns_fixedname_name(&uctx->zonefname); 2708224090Sdougb result = dns_name_copy(zonename, uctx->zonename, NULL); 2709224090Sdougb } 2710224090Sdougb if (servers != NULL) { 2711224090Sdougb for (server = ISC_LIST_HEAD(*servers); 2712224090Sdougb server != NULL; 2713224090Sdougb server = ISC_LIST_NEXT(server, link)) { 2714224090Sdougb sa = isc_mem_get(client->mctx, sizeof(*sa)); 2715224090Sdougb if (sa == NULL) 2716224090Sdougb goto fail; 2717224090Sdougb sa->type = server->type; 2718224090Sdougb sa->length = server->length; 2719224090Sdougb ISC_LINK_INIT(sa, link); 2720224090Sdougb ISC_LIST_APPEND(uctx->servers, sa, link); 2721224090Sdougb if (uctx->currentserver == NULL) 2722224090Sdougb uctx->currentserver = sa; 2723224090Sdougb uctx->nservers++; 2724224090Sdougb } 2725224090Sdougb } 2726224090Sdougb 2727224090Sdougb /* Make update message */ 2728224090Sdougb result = dns_message_create(client->mctx, DNS_MESSAGE_INTENTRENDER, 2729224090Sdougb &uctx->updatemsg); 2730224090Sdougb if (result != ISC_R_SUCCESS) 2731224090Sdougb goto fail; 2732224090Sdougb uctx->updatemsg->opcode = dns_opcode_update; 2733224090Sdougb 2734224090Sdougb if (prerequisites != NULL) { 2735224090Sdougb for (name = ISC_LIST_HEAD(*prerequisites); name != NULL; 2736224090Sdougb name = ISC_LIST_NEXT(name, link)) { 2737224090Sdougb newname = NULL; 2738224090Sdougb result = copy_name(client->mctx, uctx->updatemsg, 2739224090Sdougb name, &newname); 2740224090Sdougb if (result != ISC_R_SUCCESS) 2741224090Sdougb goto fail; 2742224090Sdougb dns_message_addname(uctx->updatemsg, newname, 2743224090Sdougb DNS_SECTION_PREREQUISITE); 2744224090Sdougb } 2745224090Sdougb } 2746224090Sdougb 2747224090Sdougb for (name = ISC_LIST_HEAD(*updates); name != NULL; 2748224090Sdougb name = ISC_LIST_NEXT(name, link)) { 2749224090Sdougb newname = NULL; 2750224090Sdougb result = copy_name(client->mctx, uctx->updatemsg, name, 2751224090Sdougb &newname); 2752224090Sdougb if (result != ISC_R_SUCCESS) 2753224090Sdougb goto fail; 2754224090Sdougb dns_message_addname(uctx->updatemsg, newname, 2755224090Sdougb DNS_SECTION_UPDATE); 2756224090Sdougb } 2757224090Sdougb 2758224090Sdougb uctx->firstname = NULL; 2759224090Sdougb result = dns_message_firstname(uctx->updatemsg, section); 2760224090Sdougb if (result == ISC_R_NOMORE) { 2761224090Sdougb section = DNS_SECTION_PREREQUISITE; 2762224090Sdougb result = dns_message_firstname(uctx->updatemsg, section); 2763224090Sdougb } 2764224090Sdougb if (result != ISC_R_SUCCESS) 2765224090Sdougb goto fail; 2766224090Sdougb dns_message_currentname(uctx->updatemsg, section, &uctx->firstname); 2767224090Sdougb 2768224090Sdougb uctx->magic = UCTX_MAGIC; 2769224090Sdougb 2770224090Sdougb LOCK(&client->lock); 2771224090Sdougb ISC_LIST_APPEND(client->updatectxs, uctx, link); 2772224090Sdougb UNLOCK(&client->lock); 2773224090Sdougb 2774224090Sdougb if (uctx->zonename != NULL && uctx->currentserver != NULL) { 2775224090Sdougb result = send_update(uctx); 2776224090Sdougb if (result != ISC_R_SUCCESS) 2777224090Sdougb goto fail; 2778224090Sdougb } else if (uctx->currentserver != NULL) { 2779224090Sdougb result = request_soa(uctx); 2780224090Sdougb if (result != ISC_R_SUCCESS) 2781224090Sdougb goto fail; 2782224090Sdougb } else { 2783224090Sdougb dns_name_clone(uctx->firstname, &uctx->soaqname); 2784224090Sdougb result = dns_client_startresolve(uctx->client, &uctx->soaqname, 2785224090Sdougb uctx->rdclass, 2786224090Sdougb dns_rdatatype_soa, 0, 2787224090Sdougb client->task, resolvesoa_done, 2788224090Sdougb uctx, &uctx->restrans); 2789224090Sdougb if (result != ISC_R_SUCCESS) 2790224090Sdougb goto fail; 2791224090Sdougb } 2792224090Sdougb 2793224090Sdougb *transp = (dns_clientupdatetrans_t *)uctx; 2794224090Sdougb 2795224090Sdougb return (ISC_R_SUCCESS); 2796224090Sdougb 2797224090Sdougb fail: 2798224090Sdougb if (ISC_LINK_LINKED(uctx, link)) { 2799224090Sdougb LOCK(&client->lock); 2800224090Sdougb ISC_LIST_UNLINK(client->updatectxs, uctx, link); 2801224090Sdougb UNLOCK(&client->lock); 2802224090Sdougb } 2803224090Sdougb if (uctx->updatemsg != NULL) 2804224090Sdougb dns_message_destroy(&uctx->updatemsg); 2805224090Sdougb while ((sa = ISC_LIST_HEAD(uctx->servers)) != NULL) { 2806224090Sdougb ISC_LIST_UNLINK(uctx->servers, sa, link); 2807224090Sdougb isc_mem_put(client->mctx, sa, sizeof(*sa)); 2808224090Sdougb } 2809224090Sdougb if (uctx->event != NULL) 2810224090Sdougb isc_event_free(ISC_EVENT_PTR(&uctx->event)); 2811224090Sdougb if (uctx->tsigkey != NULL) 2812224090Sdougb dns_tsigkey_detach(&uctx->tsigkey); 2813224090Sdougb isc_task_detach(&clone); 2814224090Sdougb DESTROYLOCK(&uctx->lock); 2815224090Sdougb uctx->magic = 0; 2816224090Sdougb isc_mem_put(client->mctx, uctx, sizeof(*uctx)); 2817224090Sdougb dns_view_detach(&view); 2818224090Sdougb 2819224090Sdougb return (result); 2820224090Sdougb} 2821224090Sdougb 2822224090Sdougbvoid 2823224090Sdougbdns_client_cancelupdate(dns_clientupdatetrans_t *trans) { 2824224090Sdougb updatectx_t *uctx; 2825224090Sdougb 2826224090Sdougb REQUIRE(trans != NULL); 2827224090Sdougb uctx = (updatectx_t *)trans; 2828224090Sdougb REQUIRE(UCTX_VALID(uctx)); 2829224090Sdougb 2830224090Sdougb LOCK(&uctx->lock); 2831224090Sdougb 2832224090Sdougb if (!uctx->canceled) { 2833224090Sdougb uctx->canceled = ISC_TRUE; 2834224090Sdougb if (uctx->updatereq != NULL) 2835224090Sdougb dns_request_cancel(uctx->updatereq); 2836224090Sdougb if (uctx->soareq != NULL) 2837224090Sdougb dns_request_cancel(uctx->soareq); 2838224090Sdougb if (uctx->restrans != NULL) 2839224090Sdougb dns_client_cancelresolve(uctx->restrans); 2840224090Sdougb if (uctx->restrans2 != NULL) 2841224090Sdougb dns_client_cancelresolve(uctx->restrans2); 2842224090Sdougb } 2843224090Sdougb 2844224090Sdougb UNLOCK(&uctx->lock); 2845224090Sdougb} 2846224090Sdougb 2847224090Sdougbvoid 2848224090Sdougbdns_client_destroyupdatetrans(dns_clientupdatetrans_t **transp) { 2849224090Sdougb updatectx_t *uctx; 2850224090Sdougb isc_mem_t *mctx; 2851224090Sdougb dns_client_t *client; 2852224090Sdougb isc_boolean_t need_destroyclient = ISC_FALSE; 2853224090Sdougb isc_sockaddr_t *sa; 2854224090Sdougb 2855224090Sdougb REQUIRE(transp != NULL); 2856224090Sdougb uctx = (updatectx_t *)*transp; 2857224090Sdougb REQUIRE(UCTX_VALID(uctx)); 2858224090Sdougb client = uctx->client; 2859224090Sdougb REQUIRE(DNS_CLIENT_VALID(client)); 2860224090Sdougb REQUIRE(uctx->updatereq == NULL && uctx->updatemsg == NULL && 2861224090Sdougb uctx->soareq == NULL && uctx->soaquery == NULL && 2862224090Sdougb uctx->event == NULL && uctx->tsigkey == NULL && 2863224090Sdougb uctx->sig0key == NULL); 2864224090Sdougb 2865224090Sdougb mctx = client->mctx; 2866224090Sdougb dns_view_detach(&uctx->view); 2867224090Sdougb while ((sa = ISC_LIST_HEAD(uctx->servers)) != NULL) { 2868224090Sdougb ISC_LIST_UNLINK(uctx->servers, sa, link); 2869224090Sdougb isc_mem_put(mctx, sa, sizeof(*sa)); 2870224090Sdougb } 2871224090Sdougb 2872224090Sdougb LOCK(&client->lock); 2873224090Sdougb 2874224090Sdougb INSIST(ISC_LINK_LINKED(uctx, link)); 2875224090Sdougb ISC_LIST_UNLINK(client->updatectxs, uctx, link); 2876224090Sdougb 2877224090Sdougb if (client->references == 0 && ISC_LIST_EMPTY(client->resctxs) && 2878224090Sdougb ISC_LIST_EMPTY(client->reqctxs) && 2879224090Sdougb ISC_LIST_EMPTY(client->updatectxs)) 2880224090Sdougb need_destroyclient = ISC_TRUE; 2881224090Sdougb 2882224090Sdougb UNLOCK(&client->lock); 2883224090Sdougb 2884224090Sdougb DESTROYLOCK(&uctx->lock); 2885224090Sdougb uctx->magic = 0; 2886224090Sdougb 2887224090Sdougb isc_mem_put(mctx, uctx, sizeof(*uctx)); 2888224090Sdougb 2889224090Sdougb if (need_destroyclient) 2890224090Sdougb destroyclient(&client); 2891224090Sdougb 2892224090Sdougb *transp = NULL; 2893224090Sdougb} 2894224090Sdougb 2895224090Sdougbisc_mem_t * 2896224090Sdougbdns_client_mctx(dns_client_t *client) { 2897224090Sdougb 2898224090Sdougb REQUIRE(DNS_CLIENT_VALID(client)); 2899224090Sdougb return (client->mctx); 2900224090Sdougb} 2901224090Sdougb 2902224090Sdougbtypedef struct { 2903224090Sdougb isc_buffer_t buffer; 2904224090Sdougb dns_rdataset_t rdataset; 2905224090Sdougb dns_rdatalist_t rdatalist; 2906224090Sdougb dns_rdata_t rdata; 2907224090Sdougb size_t size; 2908224090Sdougb isc_mem_t * mctx; 2909224090Sdougb unsigned char data[FLEXIBLE_ARRAY_MEMBER]; 2910224090Sdougb} dns_client_updaterec_t; 2911224090Sdougb 2912224090Sdougbisc_result_t 2913224090Sdougbdns_client_updaterec(dns_client_updateop_t op, dns_name_t *owner, 2914224090Sdougb dns_rdatatype_t type, dns_rdata_t *source, 2915224090Sdougb dns_ttl_t ttl, dns_name_t *target, 2916224090Sdougb dns_rdataset_t *rdataset, dns_rdatalist_t *rdatalist, 2917224090Sdougb dns_rdata_t *rdata, isc_mem_t *mctx) 2918224090Sdougb{ 2919224090Sdougb dns_client_updaterec_t *updaterec = NULL; 2920224090Sdougb size_t size = offsetof(dns_client_updaterec_t, data); 2921224090Sdougb 2922224090Sdougb REQUIRE(op < updateop_max); 2923224090Sdougb REQUIRE(owner != NULL); 2924224090Sdougb REQUIRE((rdataset != NULL && rdatalist != NULL && rdata != NULL) || 2925224090Sdougb (rdataset == NULL && rdatalist == NULL && rdata == NULL && 2926224090Sdougb mctx != NULL)); 2927224090Sdougb if (op == updateop_add) 2928224090Sdougb REQUIRE(source != NULL); 2929224090Sdougb if (source != NULL) { 2930224090Sdougb REQUIRE(source->type == type); 2931224090Sdougb REQUIRE(op == updateop_add || op == updateop_delete || 2932224090Sdougb op == updateop_exist); 2933224090Sdougb } 2934224090Sdougb 2935224090Sdougb size += owner->length; 2936224090Sdougb if (source != NULL) 2937224090Sdougb size += source->length; 2938224090Sdougb 2939224090Sdougb if (rdataset == NULL) { 2940224090Sdougb updaterec = isc_mem_get(mctx, size); 2941224090Sdougb if (updaterec == NULL) 2942224090Sdougb return (ISC_R_NOMEMORY); 2943224090Sdougb rdataset = &updaterec->rdataset; 2944224090Sdougb rdatalist = &updaterec->rdatalist; 2945224090Sdougb rdata = &updaterec->rdata; 2946224090Sdougb dns_rdataset_init(rdataset); 2947224090Sdougb dns_rdatalist_init(&updaterec->rdatalist); 2948224090Sdougb dns_rdata_init(&updaterec->rdata); 2949224090Sdougb isc_buffer_init(&updaterec->buffer, updaterec->data, 2950224090Sdougb size - offsetof(dns_client_updaterec_t, data)); 2951224090Sdougb dns_name_copy(owner, target, &updaterec->buffer); 2952224090Sdougb if (source != NULL) { 2953224090Sdougb isc_region_t r; 2954224090Sdougb dns_rdata_clone(source, rdata); 2955224090Sdougb dns_rdata_toregion(rdata, &r); 2956224090Sdougb rdata->data = isc_buffer_used(&updaterec->buffer); 2957224090Sdougb isc_buffer_copyregion(&updaterec->buffer, &r); 2958224090Sdougb } 2959224090Sdougb updaterec->mctx = NULL; 2960224090Sdougb isc_mem_attach(mctx, &updaterec->mctx); 2961224090Sdougb } else if (source != NULL) 2962224090Sdougb dns_rdata_clone(source, rdata); 2963224090Sdougb 2964224090Sdougb switch (op) { 2965224090Sdougb case updateop_add: 2966224090Sdougb break; 2967224090Sdougb case updateop_delete: 2968224090Sdougb if (source != NULL) { 2969224090Sdougb ttl = 0; 2970224090Sdougb dns_rdata_makedelete(rdata); 2971224090Sdougb } else 2972224090Sdougb dns_rdata_deleterrset(rdata, type); 2973224090Sdougb break; 2974224090Sdougb case updateop_notexist: 2975224090Sdougb dns_rdata_notexist(rdata, type); 2976224090Sdougb break; 2977224090Sdougb case updateop_exist: 2978224090Sdougb if (source == NULL) { 2979224090Sdougb ttl = 0; 2980224090Sdougb dns_rdata_exists(rdata, type); 2981224090Sdougb } 2982224090Sdougb case updateop_none: 2983224090Sdougb break; 2984224090Sdougb default: 2985224090Sdougb INSIST(0); 2986224090Sdougb } 2987224090Sdougb 2988224090Sdougb rdatalist->type = rdata->type; 2989224090Sdougb rdatalist->rdclass = rdata->rdclass; 2990224090Sdougb if (source != NULL) { 2991224090Sdougb rdatalist->covers = dns_rdata_covers(rdata); 2992224090Sdougb rdatalist->ttl = ttl; 2993224090Sdougb } 2994224090Sdougb ISC_LIST_APPEND(rdatalist->rdata, rdata, link); 2995224090Sdougb dns_rdatalist_tordataset(rdatalist, rdataset); 2996224090Sdougb ISC_LIST_APPEND(target->list, rdataset, link); 2997224090Sdougb if (updaterec != NULL) { 2998224090Sdougb target->attributes |= DNS_NAMEATTR_HASUPDATEREC; 2999224090Sdougb dns_name_setbuffer(target, &updaterec->buffer); 3000224090Sdougb } 3001224090Sdougb if (op == updateop_add || op == updateop_delete) 3002224090Sdougb target->attributes |= DNS_NAMEATTR_UPDATE; 3003224090Sdougb else 3004224090Sdougb target->attributes |= DNS_NAMEATTR_PREREQUISITE; 3005224090Sdougb return (ISC_R_SUCCESS); 3006224090Sdougb} 3007224090Sdougb 3008224090Sdougbvoid 3009224090Sdougbdns_client_freeupdate(dns_name_t **namep) { 3010224090Sdougb dns_client_updaterec_t *updaterec; 3011224090Sdougb dns_rdatalist_t *rdatalist; 3012224090Sdougb dns_rdataset_t *rdataset; 3013224090Sdougb dns_rdata_t *rdata; 3014224090Sdougb dns_name_t *name; 3015224090Sdougb 3016224090Sdougb REQUIRE(namep != NULL && *namep != NULL); 3017224090Sdougb 3018224090Sdougb name = *namep; 3019224090Sdougb for (rdataset = ISC_LIST_HEAD(name->list); 3020224090Sdougb rdataset != NULL; 3021224090Sdougb rdataset = ISC_LIST_HEAD(name->list)) { 3022224090Sdougb ISC_LIST_UNLINK(name->list, rdataset, link); 3023224090Sdougb rdatalist = NULL; 3024224090Sdougb dns_rdatalist_fromrdataset(rdataset, &rdatalist); 3025224090Sdougb if (rdatalist == NULL) { 3026224090Sdougb dns_rdataset_disassociate(rdataset); 3027224090Sdougb continue; 3028224090Sdougb } 3029224090Sdougb for (rdata = ISC_LIST_HEAD(rdatalist->rdata); 3030224090Sdougb rdata != NULL; 3031224090Sdougb rdata = ISC_LIST_HEAD(rdatalist->rdata)) 3032224090Sdougb ISC_LIST_UNLINK(rdatalist->rdata, rdata, link); 3033224090Sdougb dns_rdataset_disassociate(rdataset); 3034224090Sdougb } 3035224090Sdougb 3036224090Sdougb if ((name->attributes & DNS_NAMEATTR_HASUPDATEREC) != 0) { 3037224090Sdougb updaterec = (dns_client_updaterec_t *)name->buffer; 3038224090Sdougb INSIST(updaterec != NULL); 3039224090Sdougb isc_mem_putanddetach(&updaterec->mctx, updaterec, 3040224090Sdougb updaterec->size); 3041224090Sdougb *namep = NULL; 3042224090Sdougb } 3043224090Sdougb} 3044