00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019 #include <config.h>
00020
00021 #include <stddef.h>
00022
00023 #include <isc/app.h>
00024 #include <isc/buffer.h>
00025 #include <isc/mem.h>
00026 #include <isc/mutex.h>
00027 #include <isc/sockaddr.h>
00028 #include <isc/socket.h>
00029 #include <isc/task.h>
00030 #include <isc/timer.h>
00031 #include <isc/util.h>
00032
00033 #include <dns/adb.h>
00034 #include <dns/client.h>
00035 #include <dns/db.h>
00036 #include <dns/dispatch.h>
00037 #include <dns/events.h>
00038 #include <dns/forward.h>
00039 #include <dns/keytable.h>
00040 #include <dns/message.h>
00041 #include <dns/name.h>
00042 #include <dns/rdata.h>
00043 #include <dns/rdatalist.h>
00044 #include <dns/rdataset.h>
00045 #include <dns/rdatatype.h>
00046 #include <dns/rdatasetiter.h>
00047 #include <dns/rdatastruct.h>
00048 #include <dns/request.h>
00049 #include <dns/resolver.h>
00050 #include <dns/result.h>
00051 #include <dns/tsec.h>
00052 #include <dns/tsig.h>
00053 #include <dns/view.h>
00054
00055 #include <dst/dst.h>
00056
00057 #define DNS_CLIENT_MAGIC ISC_MAGIC('D', 'N', 'S', 'c')
00058 #define DNS_CLIENT_VALID(c) ISC_MAGIC_VALID(c, DNS_CLIENT_MAGIC)
00059
00060 #define RCTX_MAGIC ISC_MAGIC('R', 'c', 't', 'x')
00061 #define RCTX_VALID(c) ISC_MAGIC_VALID(c, RCTX_MAGIC)
00062
00063 #define REQCTX_MAGIC ISC_MAGIC('R', 'q', 'c', 'x')
00064 #define REQCTX_VALID(c) ISC_MAGIC_VALID(c, REQCTX_MAGIC)
00065
00066 #define UCTX_MAGIC ISC_MAGIC('U', 'c', 't', 'x')
00067 #define UCTX_VALID(c) ISC_MAGIC_VALID(c, UCTX_MAGIC)
00068
00069 #define MAX_RESTARTS 16
00070
00071 #ifdef TUNE_LARGE
00072 #define RESOLVER_NTASKS 523
00073 #else
00074 #define RESOLVER_NTASKS 31
00075 #endif
00076
00077
00078
00079
00080 struct dns_client {
00081
00082 unsigned int magic;
00083 unsigned int attributes;
00084 isc_mutex_t lock;
00085 isc_mem_t *mctx;
00086 isc_appctx_t *actx;
00087 isc_taskmgr_t *taskmgr;
00088 isc_task_t *task;
00089 isc_socketmgr_t *socketmgr;
00090 isc_timermgr_t *timermgr;
00091 dns_dispatchmgr_t *dispatchmgr;
00092 dns_dispatch_t *dispatchv4;
00093 dns_dispatch_t *dispatchv6;
00094
00095 unsigned int update_timeout;
00096 unsigned int update_udptimeout;
00097 unsigned int update_udpretries;
00098 unsigned int find_timeout;
00099 unsigned int find_udpretries;
00100
00101
00102 unsigned int references;
00103 dns_viewlist_t viewlist;
00104 ISC_LIST(struct resctx) resctxs;
00105 ISC_LIST(struct reqctx) reqctxs;
00106 ISC_LIST(struct updatectx) updatectxs;
00107 };
00108
00109
00110
00111
00112 #define DEF_UPDATE_TIMEOUT 300
00113 #define MIN_UPDATE_TIMEOUT 30
00114 #define DEF_UPDATE_UDPTIMEOUT 3
00115 #define DEF_UPDATE_UDPRETRIES 3
00116
00117 #define DEF_FIND_TIMEOUT 5
00118 #define DEF_FIND_UDPRETRIES 3
00119
00120 #define DNS_CLIENTATTR_OWNCTX 0x01
00121
00122 #define DNS_CLIENTVIEW_NAME "dnsclient"
00123
00124
00125
00126
00127 typedef struct resctx {
00128
00129 unsigned int magic;
00130 isc_mutex_t lock;
00131 dns_client_t *client;
00132 isc_boolean_t want_dnssec;
00133 isc_boolean_t want_validation;
00134 isc_boolean_t want_cdflag;
00135 isc_boolean_t want_tcp;
00136
00137
00138 ISC_LINK(struct resctx) link;
00139 isc_task_t *task;
00140 dns_view_t *view;
00141 unsigned int restarts;
00142 dns_fixedname_t name;
00143 dns_rdatatype_t type;
00144 dns_fetch_t *fetch;
00145 dns_namelist_t namelist;
00146 isc_result_t result;
00147 dns_clientresevent_t *event;
00148 isc_boolean_t canceled;
00149 dns_rdataset_t *rdataset;
00150 dns_rdataset_t *sigrdataset;
00151 } resctx_t;
00152
00153
00154
00155
00156 typedef struct resarg {
00157
00158 isc_appctx_t *actx;
00159 dns_client_t *client;
00160 isc_mutex_t lock;
00161
00162
00163 isc_result_t result;
00164 isc_result_t vresult;
00165 dns_namelist_t *namelist;
00166 dns_clientrestrans_t *trans;
00167 isc_boolean_t canceled;
00168 } resarg_t;
00169
00170
00171
00172
00173 typedef struct reqctx {
00174
00175 unsigned int magic;
00176 isc_mutex_t lock;
00177 dns_client_t *client;
00178 unsigned int parseoptions;
00179
00180
00181 ISC_LINK(struct reqctx) link;
00182 isc_boolean_t canceled;
00183 dns_tsigkey_t *tsigkey;
00184 dns_request_t *request;
00185 dns_clientreqevent_t *event;
00186 } reqctx_t;
00187
00188
00189
00190
00191 typedef struct reqarg {
00192
00193 isc_appctx_t *actx;
00194 dns_client_t *client;
00195 isc_mutex_t lock;
00196
00197
00198 isc_result_t result;
00199 dns_clientreqtrans_t *trans;
00200 isc_boolean_t canceled;
00201 } reqarg_t;
00202
00203
00204
00205
00206 typedef struct updatearg {
00207
00208 isc_appctx_t *actx;
00209 dns_client_t *client;
00210 isc_mutex_t lock;
00211
00212
00213 isc_result_t result;
00214 dns_clientupdatetrans_t *trans;
00215 isc_boolean_t canceled;
00216 } updatearg_t;
00217
00218
00219
00220
00221 typedef struct updatectx {
00222
00223 unsigned int magic;
00224 isc_mutex_t lock;
00225 dns_client_t *client;
00226 isc_boolean_t want_tcp;
00227
00228
00229 dns_request_t *updatereq;
00230 dns_request_t *soareq;
00231 dns_clientrestrans_t *restrans;
00232 dns_clientrestrans_t *restrans2;
00233 isc_boolean_t canceled;
00234
00235
00236 ISC_LINK(struct updatectx) link;
00237 dns_clientupdatestate_t state;
00238 dns_rdataclass_t rdclass;
00239 dns_view_t *view;
00240 dns_message_t *updatemsg;
00241 dns_message_t *soaquery;
00242 dns_clientupdateevent_t *event;
00243 dns_tsigkey_t *tsigkey;
00244 dst_key_t *sig0key;
00245 dns_name_t *firstname;
00246 dns_name_t soaqname;
00247 dns_fixedname_t zonefname;
00248 dns_name_t *zonename;
00249 isc_sockaddrlist_t servers;
00250 unsigned int nservers;
00251 isc_sockaddr_t *currentserver;
00252 struct updatectx *bp4;
00253 struct updatectx *bp6;
00254 } updatectx_t;
00255
00256 static isc_result_t request_soa(updatectx_t *uctx);
00257 static void client_resfind(resctx_t *rctx, dns_fetchevent_t *event);
00258 static isc_result_t send_update(updatectx_t *uctx);
00259
00260 static isc_result_t
00261 getudpdispatch(int family, dns_dispatchmgr_t *dispatchmgr,
00262 isc_socketmgr_t *socketmgr, isc_taskmgr_t *taskmgr,
00263 isc_boolean_t is_shared, dns_dispatch_t **dispp,
00264 isc_sockaddr_t *localaddr)
00265 {
00266 unsigned int attrs, attrmask;
00267 dns_dispatch_t *disp;
00268 unsigned buffersize, maxbuffers, maxrequests, buckets, increment;
00269 isc_result_t result;
00270 isc_sockaddr_t anyaddr;
00271
00272 attrs = 0;
00273 attrs |= DNS_DISPATCHATTR_UDP;
00274 switch (family) {
00275 case AF_INET:
00276 attrs |= DNS_DISPATCHATTR_IPV4;
00277 break;
00278 case AF_INET6:
00279 attrs |= DNS_DISPATCHATTR_IPV6;
00280 break;
00281 default:
00282 INSIST(0);
00283 }
00284 attrmask = 0;
00285 attrmask |= DNS_DISPATCHATTR_UDP;
00286 attrmask |= DNS_DISPATCHATTR_TCP;
00287 attrmask |= DNS_DISPATCHATTR_IPV4;
00288 attrmask |= DNS_DISPATCHATTR_IPV6;
00289
00290 if (localaddr == NULL) {
00291 localaddr = &anyaddr;
00292 isc_sockaddr_anyofpf(localaddr, family);
00293 }
00294
00295 buffersize = 4096;
00296 maxbuffers = is_shared ? 1000 : 8;
00297 maxrequests = 32768;
00298 buckets = is_shared ? 16411 : 3;
00299 increment = is_shared ? 16433 : 5;
00300
00301 disp = NULL;
00302 result = dns_dispatch_getudp(dispatchmgr, socketmgr,
00303 taskmgr, localaddr,
00304 buffersize, maxbuffers, maxrequests,
00305 buckets, increment,
00306 attrs, attrmask, &disp);
00307 if (result == ISC_R_SUCCESS)
00308 *dispp = disp;
00309
00310 return (result);
00311 }
00312
00313 static isc_result_t
00314 createview(isc_mem_t *mctx, dns_rdataclass_t rdclass,
00315 unsigned int options, isc_taskmgr_t *taskmgr,
00316 unsigned int ntasks, isc_socketmgr_t *socketmgr,
00317 isc_timermgr_t *timermgr, dns_dispatchmgr_t *dispatchmgr,
00318 dns_dispatch_t *dispatchv4, dns_dispatch_t *dispatchv6,
00319 dns_view_t **viewp)
00320 {
00321 isc_result_t result;
00322 dns_view_t *view = NULL;
00323 const char *dbtype;
00324
00325 result = dns_view_create(mctx, rdclass, DNS_CLIENTVIEW_NAME, &view);
00326 if (result != ISC_R_SUCCESS)
00327 return (result);
00328
00329
00330 result = dns_view_initsecroots(view, mctx);
00331 if (result != ISC_R_SUCCESS) {
00332 dns_view_detach(&view);
00333 return (result);
00334 }
00335
00336 result = dns_view_createresolver(view, taskmgr, ntasks, 1,
00337 socketmgr, timermgr, 0,
00338 dispatchmgr, dispatchv4, dispatchv6);
00339 if (result != ISC_R_SUCCESS) {
00340 dns_view_detach(&view);
00341 return (result);
00342 }
00343
00344
00345
00346
00347
00348
00349 if ((options & DNS_CLIENTCREATEOPT_USECACHE) != 0)
00350 dbtype = "rbt";
00351 else
00352 dbtype = "ecdb";
00353 result = dns_db_create(mctx, dbtype, dns_rootname, dns_dbtype_cache,
00354 rdclass, 0, NULL, &view->cachedb);
00355 if (result != ISC_R_SUCCESS) {
00356 dns_view_detach(&view);
00357 return (result);
00358 }
00359
00360 *viewp = view;
00361 return (ISC_R_SUCCESS);
00362 }
00363
00364 isc_result_t
00365 dns_client_create(dns_client_t **clientp, unsigned int options) {
00366 isc_result_t result;
00367 isc_mem_t *mctx = NULL;
00368 isc_appctx_t *actx = NULL;
00369 isc_taskmgr_t *taskmgr = NULL;
00370 isc_socketmgr_t *socketmgr = NULL;
00371 isc_timermgr_t *timermgr = NULL;
00372 #if 0
00373
00374 isc_log_t *lctx = NULL;
00375 isc_logconfig_t *logconfig = NULL;
00376 unsigned int logdebuglevel = 0;
00377 #endif
00378
00379 result = isc_mem_create(0, 0, &mctx);
00380 if (result != ISC_R_SUCCESS)
00381 return (result);
00382 result = isc_appctx_create(mctx, &actx);
00383 if (result != ISC_R_SUCCESS)
00384 goto cleanup;
00385 result = isc_app_ctxstart(actx);
00386 if (result != ISC_R_SUCCESS)
00387 goto cleanup;
00388 result = isc_taskmgr_createinctx(mctx, actx, 1, 0, &taskmgr);
00389 if (result != ISC_R_SUCCESS)
00390 goto cleanup;
00391 result = isc_socketmgr_createinctx(mctx, actx, &socketmgr);
00392 if (result != ISC_R_SUCCESS)
00393 goto cleanup;
00394 result = isc_timermgr_createinctx(mctx, actx, &timermgr);
00395 if (result != ISC_R_SUCCESS)
00396 goto cleanup;
00397 #if 0
00398 result = isc_log_create(mctx, &lctx, &logconfig);
00399 if (result != ISC_R_SUCCESS)
00400 goto cleanup;
00401 isc_log_setcontext(lctx);
00402 dns_log_init(lctx);
00403 dns_log_setcontext(lctx);
00404 result = isc_log_usechannel(logconfig, "default_debug", NULL, NULL);
00405 if (result != ISC_R_SUCCESS)
00406 goto cleanup;
00407 isc_log_setdebuglevel(lctx, logdebuglevel);
00408 #endif
00409 result = dns_client_createx(mctx, actx, taskmgr, socketmgr, timermgr,
00410 options, clientp);
00411 if (result != ISC_R_SUCCESS)
00412 goto cleanup;
00413
00414 (*clientp)->attributes |= DNS_CLIENTATTR_OWNCTX;
00415
00416
00417 isc_mem_detach(&mctx);
00418
00419 return (ISC_R_SUCCESS);
00420
00421 cleanup:
00422 if (taskmgr != NULL)
00423 isc_taskmgr_destroy(&taskmgr);
00424 if (timermgr != NULL)
00425 isc_timermgr_destroy(&timermgr);
00426 if (socketmgr != NULL)
00427 isc_socketmgr_destroy(&socketmgr);
00428 if (actx != NULL)
00429 isc_appctx_destroy(&actx);
00430 isc_mem_detach(&mctx);
00431
00432 return (result);
00433 }
00434
00435 isc_result_t
00436 dns_client_createx(isc_mem_t *mctx, isc_appctx_t *actx, isc_taskmgr_t *taskmgr,
00437 isc_socketmgr_t *socketmgr, isc_timermgr_t *timermgr,
00438 unsigned int options, dns_client_t **clientp)
00439 {
00440 isc_result_t result;
00441 result = dns_client_createx2(mctx, actx, taskmgr, socketmgr, timermgr,
00442 options, clientp, NULL, NULL);
00443 return (result);
00444 }
00445
00446 isc_result_t
00447 dns_client_createx2(isc_mem_t *mctx, isc_appctx_t *actx,
00448 isc_taskmgr_t *taskmgr, isc_socketmgr_t *socketmgr,
00449 isc_timermgr_t *timermgr, unsigned int options,
00450 dns_client_t **clientp, isc_sockaddr_t *localaddr4,
00451 isc_sockaddr_t *localaddr6)
00452 {
00453 dns_client_t *client;
00454 isc_result_t result;
00455 dns_dispatchmgr_t *dispatchmgr = NULL;
00456 dns_dispatch_t *dispatchv4 = NULL;
00457 dns_dispatch_t *dispatchv6 = NULL;
00458 dns_view_t *view = NULL;
00459
00460 REQUIRE(mctx != NULL);
00461 REQUIRE(taskmgr != NULL);
00462 REQUIRE(timermgr != NULL);
00463 REQUIRE(socketmgr != NULL);
00464 REQUIRE(clientp != NULL && *clientp == NULL);
00465
00466 client = isc_mem_get(mctx, sizeof(*client));
00467 if (client == NULL)
00468 return (ISC_R_NOMEMORY);
00469
00470 result = isc_mutex_init(&client->lock);
00471 if (result != ISC_R_SUCCESS) {
00472 isc_mem_put(mctx, client, sizeof(*client));
00473 return (result);
00474 }
00475
00476 client->actx = actx;
00477 client->taskmgr = taskmgr;
00478 client->socketmgr = socketmgr;
00479 client->timermgr = timermgr;
00480
00481 client->task = NULL;
00482 result = isc_task_create(client->taskmgr, 0, &client->task);
00483 if (result != ISC_R_SUCCESS)
00484 goto cleanup;
00485
00486 result = dns_dispatchmgr_create(mctx, NULL, &dispatchmgr);
00487 if (result != ISC_R_SUCCESS)
00488 goto cleanup;
00489 client->dispatchmgr = dispatchmgr;
00490
00491
00492
00493
00494
00495 client->dispatchv4 = NULL;
00496 if (localaddr4 != NULL || localaddr6 == NULL) {
00497 result = getudpdispatch(AF_INET, dispatchmgr, socketmgr,
00498 taskmgr, ISC_TRUE,
00499 &dispatchv4, localaddr4);
00500 if (result == ISC_R_SUCCESS)
00501 client->dispatchv4 = dispatchv4;
00502 }
00503
00504 client->dispatchv6 = NULL;
00505 if (localaddr6 != NULL || localaddr4 == NULL) {
00506 result = getudpdispatch(AF_INET6, dispatchmgr, socketmgr,
00507 taskmgr, ISC_TRUE,
00508 &dispatchv6, localaddr6);
00509 if (result == ISC_R_SUCCESS)
00510 client->dispatchv6 = dispatchv6;
00511 }
00512
00513
00514 if (dispatchv4 == NULL && dispatchv6 == NULL) {
00515 INSIST(result != ISC_R_SUCCESS);
00516 goto cleanup;
00517 }
00518
00519
00520 result = createview(mctx, dns_rdataclass_in, options, taskmgr,
00521 RESOLVER_NTASKS, socketmgr, timermgr,
00522 dispatchmgr, dispatchv4, dispatchv6, &view);
00523 if (result != ISC_R_SUCCESS)
00524 goto cleanup;
00525 ISC_LIST_INIT(client->viewlist);
00526 ISC_LIST_APPEND(client->viewlist, view, link);
00527
00528 dns_view_freeze(view);
00529
00530 ISC_LIST_INIT(client->resctxs);
00531 ISC_LIST_INIT(client->reqctxs);
00532 ISC_LIST_INIT(client->updatectxs);
00533
00534 client->mctx = NULL;
00535 isc_mem_attach(mctx, &client->mctx);
00536
00537 client->update_timeout = DEF_UPDATE_TIMEOUT;
00538 client->update_udptimeout = DEF_UPDATE_UDPTIMEOUT;
00539 client->update_udpretries = DEF_UPDATE_UDPRETRIES;
00540 client->find_timeout = DEF_FIND_TIMEOUT;
00541 client->find_udpretries = DEF_FIND_UDPRETRIES;
00542 client->attributes = 0;
00543
00544 client->references = 1;
00545 client->magic = DNS_CLIENT_MAGIC;
00546
00547 *clientp = client;
00548
00549 return (ISC_R_SUCCESS);
00550
00551 cleanup:
00552 if (dispatchv4 != NULL)
00553 dns_dispatch_detach(&dispatchv4);
00554 if (dispatchv6 != NULL)
00555 dns_dispatch_detach(&dispatchv6);
00556 if (dispatchmgr != NULL)
00557 dns_dispatchmgr_destroy(&dispatchmgr);
00558 if (client->task != NULL)
00559 isc_task_detach(&client->task);
00560 isc_mem_put(mctx, client, sizeof(*client));
00561
00562 return (result);
00563 }
00564
00565 static void
00566 destroyclient(dns_client_t **clientp) {
00567 dns_client_t *client = *clientp;
00568 dns_view_t *view;
00569
00570 while ((view = ISC_LIST_HEAD(client->viewlist)) != NULL) {
00571 ISC_LIST_UNLINK(client->viewlist, view, link);
00572 dns_view_detach(&view);
00573 }
00574
00575 if (client->dispatchv4 != NULL)
00576 dns_dispatch_detach(&client->dispatchv4);
00577 if (client->dispatchv6 != NULL)
00578 dns_dispatch_detach(&client->dispatchv6);
00579
00580 dns_dispatchmgr_destroy(&client->dispatchmgr);
00581
00582 isc_task_detach(&client->task);
00583
00584
00585
00586
00587
00588 if ((client->attributes & DNS_CLIENTATTR_OWNCTX) != 0) {
00589 isc_taskmgr_destroy(&client->taskmgr);
00590 isc_timermgr_destroy(&client->timermgr);
00591 isc_socketmgr_destroy(&client->socketmgr);
00592
00593 isc_app_ctxfinish(client->actx);
00594 isc_appctx_destroy(&client->actx);
00595 }
00596
00597 DESTROYLOCK(&client->lock);
00598 client->magic = 0;
00599
00600 isc_mem_putanddetach(&client->mctx, client, sizeof(*client));
00601
00602 *clientp = NULL;
00603 }
00604
00605 void
00606 dns_client_destroy(dns_client_t **clientp) {
00607 dns_client_t *client;
00608 isc_boolean_t destroyok = ISC_FALSE;
00609
00610 REQUIRE(clientp != NULL);
00611 client = *clientp;
00612 REQUIRE(DNS_CLIENT_VALID(client));
00613
00614 LOCK(&client->lock);
00615 client->references--;
00616 if (client->references == 0 && ISC_LIST_EMPTY(client->resctxs) &&
00617 ISC_LIST_EMPTY(client->reqctxs) &&
00618 ISC_LIST_EMPTY(client->updatectxs)) {
00619 destroyok = ISC_TRUE;
00620 }
00621 UNLOCK(&client->lock);
00622
00623 if (destroyok)
00624 destroyclient(&client);
00625
00626 *clientp = NULL;
00627 }
00628
00629 isc_result_t
00630 dns_client_setservers(dns_client_t *client, dns_rdataclass_t rdclass,
00631 dns_name_t *namespace, isc_sockaddrlist_t *addrs)
00632 {
00633 isc_result_t result;
00634 dns_view_t *view = NULL;
00635
00636 REQUIRE(DNS_CLIENT_VALID(client));
00637 REQUIRE(addrs != NULL);
00638
00639 if (namespace == NULL)
00640 namespace = dns_rootname;
00641
00642 LOCK(&client->lock);
00643 result = dns_viewlist_find(&client->viewlist, DNS_CLIENTVIEW_NAME,
00644 rdclass, &view);
00645 if (result != ISC_R_SUCCESS) {
00646 UNLOCK(&client->lock);
00647 return (result);
00648 }
00649 UNLOCK(&client->lock);
00650
00651 result = dns_fwdtable_add(view->fwdtable, namespace, addrs,
00652 dns_fwdpolicy_only);
00653
00654 dns_view_detach(&view);
00655
00656 return (result);
00657 }
00658
00659 isc_result_t
00660 dns_client_clearservers(dns_client_t *client, dns_rdataclass_t rdclass,
00661 dns_name_t *namespace)
00662 {
00663 isc_result_t result;
00664 dns_view_t *view = NULL;
00665
00666 REQUIRE(DNS_CLIENT_VALID(client));
00667
00668 if (namespace == NULL)
00669 namespace = dns_rootname;
00670
00671 LOCK(&client->lock);
00672 result = dns_viewlist_find(&client->viewlist, DNS_CLIENTVIEW_NAME,
00673 rdclass, &view);
00674 if (result != ISC_R_SUCCESS) {
00675 UNLOCK(&client->lock);
00676 return (result);
00677 }
00678 UNLOCK(&client->lock);
00679
00680 result = dns_fwdtable_delete(view->fwdtable, namespace);
00681
00682 dns_view_detach(&view);
00683
00684 return (result);
00685 }
00686
00687 isc_result_t
00688 dns_client_setdlv(dns_client_t *client, dns_rdataclass_t rdclass,
00689 const char *dlvname)
00690 {
00691 isc_result_t result;
00692 isc_buffer_t b;
00693 dns_view_t *view = NULL;
00694
00695 REQUIRE(DNS_CLIENT_VALID(client));
00696
00697 LOCK(&client->lock);
00698 result = dns_viewlist_find(&client->viewlist, DNS_CLIENTVIEW_NAME,
00699 rdclass, &view);
00700 UNLOCK(&client->lock);
00701 if (result != ISC_R_SUCCESS)
00702 goto cleanup;
00703
00704 if (dlvname == NULL)
00705 view->dlv = NULL;
00706 else {
00707 dns_name_t *newdlv;
00708
00709 isc_buffer_constinit(&b, dlvname, strlen(dlvname));
00710 isc_buffer_add(&b, strlen(dlvname));
00711 newdlv = dns_fixedname_name(&view->dlv_fixed);
00712 result = dns_name_fromtext(newdlv, &b, dns_rootname,
00713 DNS_NAME_DOWNCASE, NULL);
00714 if (result != ISC_R_SUCCESS)
00715 goto cleanup;
00716
00717 view->dlv = dns_fixedname_name(&view->dlv_fixed);
00718 }
00719
00720 cleanup:
00721 if (view != NULL)
00722 dns_view_detach(&view);
00723
00724 return (result);
00725 }
00726
00727 static isc_result_t
00728 getrdataset(isc_mem_t *mctx, dns_rdataset_t **rdatasetp) {
00729 dns_rdataset_t *rdataset;
00730
00731 REQUIRE(mctx != NULL);
00732 REQUIRE(rdatasetp != NULL && *rdatasetp == NULL);
00733
00734 rdataset = isc_mem_get(mctx, sizeof(*rdataset));
00735 if (rdataset == NULL)
00736 return (ISC_R_NOMEMORY);
00737
00738 dns_rdataset_init(rdataset);
00739
00740 *rdatasetp = rdataset;
00741
00742 return (ISC_R_SUCCESS);
00743 }
00744
00745 static void
00746 putrdataset(isc_mem_t *mctx, dns_rdataset_t **rdatasetp) {
00747 dns_rdataset_t *rdataset;
00748
00749 REQUIRE(rdatasetp != NULL);
00750 rdataset = *rdatasetp;
00751 REQUIRE(rdataset != NULL);
00752
00753 if (dns_rdataset_isassociated(rdataset))
00754 dns_rdataset_disassociate(rdataset);
00755
00756 isc_mem_put(mctx, rdataset, sizeof(*rdataset));
00757
00758 *rdatasetp = NULL;
00759 }
00760
00761 static void
00762 fetch_done(isc_task_t *task, isc_event_t *event) {
00763 resctx_t *rctx = event->ev_arg;
00764 dns_fetchevent_t *fevent;
00765
00766 REQUIRE(event->ev_type == DNS_EVENT_FETCHDONE);
00767 REQUIRE(RCTX_VALID(rctx));
00768 REQUIRE(rctx->task == task);
00769 fevent = (dns_fetchevent_t *)event;
00770
00771 client_resfind(rctx, fevent);
00772 }
00773
00774 static inline isc_result_t
00775 start_fetch(resctx_t *rctx) {
00776 isc_result_t result;
00777 int fopts = 0;
00778
00779
00780
00781
00782
00783 REQUIRE(rctx->fetch == NULL);
00784
00785 if (!rctx->want_cdflag)
00786 fopts |= DNS_FETCHOPT_NOCDFLAG;
00787 if (!rctx->want_validation)
00788 fopts |= DNS_FETCHOPT_NOVALIDATE;
00789 if (rctx->want_tcp)
00790 fopts |= DNS_FETCHOPT_TCP;
00791
00792 result = dns_resolver_createfetch(rctx->view->resolver,
00793 dns_fixedname_name(&rctx->name),
00794 rctx->type,
00795 NULL, NULL, NULL, fopts,
00796 rctx->task, fetch_done, rctx,
00797 rctx->rdataset,
00798 rctx->sigrdataset,
00799 &rctx->fetch);
00800
00801 return (result);
00802 }
00803
00804 static isc_result_t
00805 view_find(resctx_t *rctx, dns_db_t **dbp, dns_dbnode_t **nodep,
00806 dns_name_t *foundname)
00807 {
00808 isc_result_t result;
00809 dns_name_t *name = dns_fixedname_name(&rctx->name);
00810 dns_rdatatype_t type;
00811
00812 if (rctx->type == dns_rdatatype_rrsig)
00813 type = dns_rdatatype_any;
00814 else
00815 type = rctx->type;
00816
00817 result = dns_view_find(rctx->view, name, type, 0, 0, ISC_FALSE,
00818 dbp, nodep, foundname, rctx->rdataset,
00819 rctx->sigrdataset);
00820
00821 return (result);
00822 }
00823
00824 static void
00825 client_resfind(resctx_t *rctx, dns_fetchevent_t *event) {
00826 isc_mem_t *mctx;
00827 isc_result_t tresult, result = ISC_R_SUCCESS;
00828 isc_result_t vresult = ISC_R_SUCCESS;
00829 isc_boolean_t want_restart;
00830 isc_boolean_t send_event = ISC_FALSE;
00831 dns_name_t *name, *prefix;
00832 dns_fixedname_t foundname, fixed;
00833 dns_rdataset_t *trdataset;
00834 dns_rdata_t rdata = DNS_RDATA_INIT;
00835 unsigned int nlabels;
00836 int order;
00837 dns_namereln_t namereln;
00838 dns_rdata_cname_t cname;
00839 dns_rdata_dname_t dname;
00840
00841 REQUIRE(RCTX_VALID(rctx));
00842
00843 LOCK(&rctx->lock);
00844
00845 mctx = rctx->view->mctx;
00846
00847 name = dns_fixedname_name(&rctx->name);
00848
00849 do {
00850 dns_name_t *fname = NULL;
00851 dns_name_t *ansname = NULL;
00852 dns_db_t *db = NULL;
00853 dns_dbnode_t *node = NULL;
00854
00855 rctx->restarts++;
00856 want_restart = ISC_FALSE;
00857
00858 if (event == NULL && !rctx->canceled) {
00859 dns_fixedname_init(&foundname);
00860 fname = dns_fixedname_name(&foundname);
00861 INSIST(!dns_rdataset_isassociated(rctx->rdataset));
00862 INSIST(rctx->sigrdataset == NULL ||
00863 !dns_rdataset_isassociated(rctx->sigrdataset));
00864 result = view_find(rctx, &db, &node, fname);
00865 if (result == ISC_R_NOTFOUND) {
00866
00867
00868
00869
00870 if (node != NULL) {
00871 INSIST(db != NULL);
00872 dns_db_detachnode(db, &node);
00873 }
00874 if (db != NULL)
00875 dns_db_detach(&db);
00876 result = start_fetch(rctx);
00877 if (result != ISC_R_SUCCESS) {
00878 putrdataset(mctx, &rctx->rdataset);
00879 if (rctx->sigrdataset != NULL)
00880 putrdataset(mctx,
00881 &rctx->sigrdataset);
00882 send_event = ISC_TRUE;
00883 }
00884 goto done;
00885 }
00886 } else {
00887 INSIST(event != NULL);
00888 INSIST(event->fetch == rctx->fetch);
00889 dns_resolver_destroyfetch(&rctx->fetch);
00890 db = event->db;
00891 node = event->node;
00892 result = event->result;
00893 vresult = event->vresult;
00894 fname = dns_fixedname_name(&event->foundname);
00895 INSIST(event->rdataset == rctx->rdataset);
00896 INSIST(event->sigrdataset == rctx->sigrdataset);
00897 }
00898
00899
00900
00901
00902 if (rctx->canceled)
00903 result = ISC_R_CANCELED;
00904 else {
00905
00906
00907
00908
00909 ansname = isc_mem_get(mctx, sizeof(*ansname));
00910 if (ansname == NULL)
00911 tresult = ISC_R_NOMEMORY;
00912 else {
00913 dns_name_t *aname;
00914
00915 aname = dns_fixedname_name(&rctx->name);
00916 dns_name_init(ansname, NULL);
00917 tresult = dns_name_dup(aname, mctx, ansname);
00918 if (tresult != ISC_R_SUCCESS)
00919 isc_mem_put(mctx, ansname,
00920 sizeof(*ansname));
00921 }
00922 if (tresult != ISC_R_SUCCESS)
00923 result = tresult;
00924 }
00925
00926 switch (result) {
00927 case ISC_R_SUCCESS:
00928 send_event = ISC_TRUE;
00929
00930
00931
00932 break;
00933 case DNS_R_CNAME:
00934
00935
00936
00937 trdataset = rctx->rdataset;
00938 ISC_LIST_APPEND(ansname->list, rctx->rdataset, link);
00939 rctx->rdataset = NULL;
00940 if (rctx->sigrdataset != NULL) {
00941 ISC_LIST_APPEND(ansname->list,
00942 rctx->sigrdataset, link);
00943 rctx->sigrdataset = NULL;
00944 }
00945 ISC_LIST_APPEND(rctx->namelist, ansname, link);
00946 ansname = NULL;
00947
00948
00949
00950
00951
00952 tresult = dns_rdataset_first(trdataset);
00953 if (tresult != ISC_R_SUCCESS)
00954 goto done;
00955 dns_rdataset_current(trdataset, &rdata);
00956 tresult = dns_rdata_tostruct(&rdata, &cname, NULL);
00957 dns_rdata_reset(&rdata);
00958 if (tresult != ISC_R_SUCCESS)
00959 goto done;
00960 tresult = dns_name_copy(&cname.cname, name, NULL);
00961 dns_rdata_freestruct(&cname);
00962 if (tresult == ISC_R_SUCCESS)
00963 want_restart = ISC_TRUE;
00964 else
00965 result = tresult;
00966 goto done;
00967 case DNS_R_DNAME:
00968
00969
00970
00971 trdataset = rctx->rdataset;
00972 ISC_LIST_APPEND(ansname->list, rctx->rdataset, link);
00973 rctx->rdataset = NULL;
00974 if (rctx->sigrdataset != NULL) {
00975 ISC_LIST_APPEND(ansname->list,
00976 rctx->sigrdataset, link);
00977 rctx->sigrdataset = NULL;
00978 }
00979 ISC_LIST_APPEND(rctx->namelist, ansname, link);
00980 ansname = NULL;
00981
00982 namereln = dns_name_fullcompare(name, fname, &order,
00983 &nlabels);
00984 INSIST(namereln == dns_namereln_subdomain);
00985
00986
00987
00988 tresult = dns_rdataset_first(trdataset);
00989 if (tresult != ISC_R_SUCCESS) {
00990 result = tresult;
00991 goto done;
00992 }
00993 dns_rdataset_current(trdataset, &rdata);
00994 tresult = dns_rdata_tostruct(&rdata, &dname, NULL);
00995 dns_rdata_reset(&rdata);
00996 if (tresult != ISC_R_SUCCESS) {
00997 result = tresult;
00998 goto done;
00999 }
01000
01001
01002
01003 dns_fixedname_init(&fixed);
01004 prefix = dns_fixedname_name(&fixed);
01005 dns_name_split(name, nlabels, prefix, NULL);
01006 tresult = dns_name_concatenate(prefix, &dname.dname,
01007 name, NULL);
01008 dns_rdata_freestruct(&dname);
01009 if (tresult == ISC_R_SUCCESS)
01010 want_restart = ISC_TRUE;
01011 else
01012 result = tresult;
01013 goto done;
01014 case DNS_R_NCACHENXDOMAIN:
01015 case DNS_R_NCACHENXRRSET:
01016 ISC_LIST_APPEND(ansname->list, rctx->rdataset, link);
01017 ISC_LIST_APPEND(rctx->namelist, ansname, link);
01018 ansname = NULL;
01019 rctx->rdataset = NULL;
01020
01021 if (rctx->sigrdataset != NULL)
01022 putrdataset(mctx, &rctx->sigrdataset);
01023 send_event = ISC_TRUE;
01024 goto done;
01025 default:
01026 if (rctx->rdataset != NULL)
01027 putrdataset(mctx, &rctx->rdataset);
01028 if (rctx->sigrdataset != NULL)
01029 putrdataset(mctx, &rctx->sigrdataset);
01030 send_event = ISC_TRUE;
01031 goto done;
01032 }
01033
01034 if (rctx->type == dns_rdatatype_any) {
01035 int n = 0;
01036 dns_rdatasetiter_t *rdsiter = NULL;
01037
01038 tresult = dns_db_allrdatasets(db, node, NULL, 0,
01039 &rdsiter);
01040 if (tresult != ISC_R_SUCCESS) {
01041 result = tresult;
01042 goto done;
01043 }
01044
01045 tresult = dns_rdatasetiter_first(rdsiter);
01046 while (tresult == ISC_R_SUCCESS) {
01047 dns_rdatasetiter_current(rdsiter,
01048 rctx->rdataset);
01049 if (rctx->rdataset->type != 0) {
01050 ISC_LIST_APPEND(ansname->list,
01051 rctx->rdataset,
01052 link);
01053 n++;
01054 rctx->rdataset = NULL;
01055 } else {
01056
01057
01058
01059
01060 dns_rdataset_disassociate(
01061 rctx->rdataset);
01062 }
01063 tresult = dns_rdatasetiter_next(rdsiter);
01064
01065 if (tresult == ISC_R_SUCCESS &&
01066 rctx->rdataset == NULL) {
01067 tresult = getrdataset(mctx,
01068 &rctx->rdataset);
01069 if (tresult != ISC_R_SUCCESS) {
01070 result = tresult;
01071 POST(result);
01072 break;
01073 }
01074 }
01075 }
01076 if (n == 0) {
01077
01078
01079
01080
01081
01082 result = DNS_R_SERVFAIL;
01083 POST(result);
01084 } else {
01085 ISC_LIST_APPEND(rctx->namelist, ansname, link);
01086 ansname = NULL;
01087 }
01088 dns_rdatasetiter_destroy(&rdsiter);
01089 if (tresult != ISC_R_NOMORE)
01090 result = DNS_R_SERVFAIL;
01091 else
01092 result = ISC_R_SUCCESS;
01093 goto done;
01094 } else {
01095
01096
01097
01098
01099 ISC_LIST_APPEND(ansname->list, rctx->rdataset, link);
01100 rctx->rdataset = NULL;
01101 if (rctx->sigrdataset != NULL) {
01102 ISC_LIST_APPEND(ansname->list,
01103 rctx->sigrdataset, link);
01104 rctx->sigrdataset = NULL;
01105 }
01106 ISC_LIST_APPEND(rctx->namelist, ansname, link);
01107 ansname = NULL;
01108 }
01109
01110 done:
01111
01112
01113
01114 if (ansname != NULL) {
01115 dns_rdataset_t *rdataset;
01116
01117 while ((rdataset = ISC_LIST_HEAD(ansname->list))
01118 != NULL) {
01119 ISC_LIST_UNLINK(ansname->list, rdataset, link);
01120 putrdataset(mctx, &rdataset);
01121 }
01122 dns_name_free(ansname, mctx);
01123 isc_mem_put(mctx, ansname, sizeof(*ansname));
01124 }
01125
01126 if (node != NULL)
01127 dns_db_detachnode(db, &node);
01128 if (db != NULL)
01129 dns_db_detach(&db);
01130 if (event != NULL)
01131 isc_event_free(ISC_EVENT_PTR(&event));
01132
01133
01134
01135
01136 if (want_restart && rctx->restarts == MAX_RESTARTS) {
01137 want_restart = ISC_FALSE;
01138 result = ISC_R_QUOTA;
01139 send_event = ISC_TRUE;
01140 }
01141
01142
01143
01144
01145 if (want_restart) {
01146 INSIST(rctx->rdataset == NULL &&
01147 rctx->sigrdataset == NULL);
01148
01149 result = getrdataset(mctx, &rctx->rdataset);
01150 if (result == ISC_R_SUCCESS && rctx->want_dnssec) {
01151 result = getrdataset(mctx, &rctx->sigrdataset);
01152 if (result != ISC_R_SUCCESS) {
01153 putrdataset(mctx, &rctx->rdataset);
01154 }
01155 }
01156
01157 if (result != ISC_R_SUCCESS) {
01158 want_restart = ISC_FALSE;
01159 send_event = ISC_TRUE;
01160 }
01161 }
01162 } while (want_restart);
01163
01164 if (send_event) {
01165 isc_task_t *task;
01166
01167 while ((name = ISC_LIST_HEAD(rctx->namelist)) != NULL) {
01168 ISC_LIST_UNLINK(rctx->namelist, name, link);
01169 ISC_LIST_APPEND(rctx->event->answerlist, name, link);
01170 }
01171
01172 rctx->event->result = result;
01173 rctx->event->vresult = vresult;
01174 task = rctx->event->ev_sender;
01175 rctx->event->ev_sender = rctx;
01176 isc_task_sendanddetach(&task, ISC_EVENT_PTR(&rctx->event));
01177 }
01178
01179 UNLOCK(&rctx->lock);
01180 }
01181
01182
01183 static void
01184 suspend(isc_task_t *task, isc_event_t *event) {
01185 isc_appctx_t *actx = event->ev_arg;
01186
01187 UNUSED(task);
01188
01189 isc_app_ctxsuspend(actx);
01190 isc_event_free(&event);
01191 }
01192
01193 static void
01194 resolve_done(isc_task_t *task, isc_event_t *event) {
01195 resarg_t *resarg = event->ev_arg;
01196 dns_clientresevent_t *rev = (dns_clientresevent_t *)event;
01197 dns_name_t *name;
01198 isc_result_t result;
01199
01200 UNUSED(task);
01201
01202 LOCK(&resarg->lock);
01203
01204 resarg->result = rev->result;
01205 resarg->vresult = rev->vresult;
01206 while ((name = ISC_LIST_HEAD(rev->answerlist)) != NULL) {
01207 ISC_LIST_UNLINK(rev->answerlist, name, link);
01208 ISC_LIST_APPEND(*resarg->namelist, name, link);
01209 }
01210
01211 dns_client_destroyrestrans(&resarg->trans);
01212 isc_event_free(&event);
01213
01214 if (!resarg->canceled) {
01215 UNLOCK(&resarg->lock);
01216
01217
01218
01219
01220
01221
01222
01223 result = isc_app_ctxonrun(resarg->actx, resarg->client->mctx,
01224 task, suspend, resarg->actx);
01225 if (result == ISC_R_ALREADYRUNNING)
01226 isc_app_ctxsuspend(resarg->actx);
01227 } else {
01228
01229
01230
01231
01232 UNLOCK(&resarg->lock);
01233 DESTROYLOCK(&resarg->lock);
01234 isc_mem_put(resarg->client->mctx, resarg, sizeof(*resarg));
01235 }
01236 }
01237
01238 isc_result_t
01239 dns_client_resolve(dns_client_t *client, dns_name_t *name,
01240 dns_rdataclass_t rdclass, dns_rdatatype_t type,
01241 unsigned int options, dns_namelist_t *namelist)
01242 {
01243 isc_result_t result;
01244 isc_appctx_t *actx;
01245 resarg_t *resarg;
01246
01247 REQUIRE(DNS_CLIENT_VALID(client));
01248 REQUIRE(namelist != NULL && ISC_LIST_EMPTY(*namelist));
01249
01250 if ((client->attributes & DNS_CLIENTATTR_OWNCTX) == 0 &&
01251 (options & DNS_CLIENTRESOPT_ALLOWRUN) == 0) {
01252
01253
01254
01255
01256
01257 return (ISC_R_NOTIMPLEMENTED);
01258 } else
01259 actx = client->actx;
01260
01261 resarg = isc_mem_get(client->mctx, sizeof(*resarg));
01262 if (resarg == NULL)
01263 return (ISC_R_NOMEMORY);
01264
01265 result = isc_mutex_init(&resarg->lock);
01266 if (result != ISC_R_SUCCESS) {
01267 isc_mem_put(client->mctx, resarg, sizeof(*resarg));
01268 return (result);
01269 }
01270
01271 resarg->actx = actx;
01272 resarg->client = client;
01273 resarg->result = DNS_R_SERVFAIL;
01274 resarg->namelist = namelist;
01275 resarg->trans = NULL;
01276 resarg->canceled = ISC_FALSE;
01277 result = dns_client_startresolve(client, name, rdclass, type, options,
01278 client->task, resolve_done, resarg,
01279 &resarg->trans);
01280 if (result != ISC_R_SUCCESS) {
01281 DESTROYLOCK(&resarg->lock);
01282 isc_mem_put(client->mctx, resarg, sizeof(*resarg));
01283 return (result);
01284 }
01285
01286
01287
01288
01289
01290 result = isc_app_ctxrun(actx);
01291
01292 LOCK(&resarg->lock);
01293 if (result == ISC_R_SUCCESS || result == ISC_R_SUSPEND)
01294 result = resarg->result;
01295 if (result != ISC_R_SUCCESS && resarg->vresult != ISC_R_SUCCESS) {
01296
01297
01298
01299
01300
01301 result = resarg->vresult;
01302 }
01303 if (resarg->trans != NULL) {
01304
01305
01306
01307
01308 resarg->canceled = ISC_TRUE;
01309 dns_client_cancelresolve(resarg->trans);
01310
01311 UNLOCK(&resarg->lock);
01312
01313
01314 } else {
01315 UNLOCK(&resarg->lock);
01316
01317 DESTROYLOCK(&resarg->lock);
01318 isc_mem_put(client->mctx, resarg, sizeof(*resarg));
01319 }
01320
01321 return (result);
01322 }
01323
01324 isc_result_t
01325 dns_client_startresolve(dns_client_t *client, dns_name_t *name,
01326 dns_rdataclass_t rdclass, dns_rdatatype_t type,
01327 unsigned int options, isc_task_t *task,
01328 isc_taskaction_t action, void *arg,
01329 dns_clientrestrans_t **transp)
01330 {
01331 dns_view_t *view = NULL;
01332 dns_clientresevent_t *event = NULL;
01333 resctx_t *rctx = NULL;
01334 isc_task_t *clone = NULL;
01335 isc_mem_t *mctx;
01336 isc_result_t result;
01337 dns_rdataset_t *rdataset, *sigrdataset;
01338 isc_boolean_t want_dnssec, want_validation, want_cdflag, want_tcp;
01339
01340 REQUIRE(DNS_CLIENT_VALID(client));
01341 REQUIRE(transp != NULL && *transp == NULL);
01342
01343 LOCK(&client->lock);
01344 result = dns_viewlist_find(&client->viewlist, DNS_CLIENTVIEW_NAME,
01345 rdclass, &view);
01346 UNLOCK(&client->lock);
01347 if (result != ISC_R_SUCCESS)
01348 return (result);
01349
01350 mctx = client->mctx;
01351 rdataset = NULL;
01352 sigrdataset = NULL;
01353 want_dnssec = ISC_TF((options & DNS_CLIENTRESOPT_NODNSSEC) == 0);
01354 want_validation = ISC_TF((options & DNS_CLIENTRESOPT_NOVALIDATE) == 0);
01355 want_cdflag = ISC_TF((options & DNS_CLIENTRESOPT_NOCDFLAG) == 0);
01356 want_tcp = ISC_TF((options & DNS_CLIENTRESOPT_TCP) != 0);
01357
01358
01359
01360
01361 clone = NULL;
01362 isc_task_attach(task, &clone);
01363 event = (dns_clientresevent_t *)
01364 isc_event_allocate(mctx, clone, DNS_EVENT_CLIENTRESDONE,
01365 action, arg, sizeof(*event));
01366 if (event == NULL) {
01367 result = ISC_R_NOMEMORY;
01368 goto cleanup;
01369 }
01370 event->result = DNS_R_SERVFAIL;
01371 ISC_LIST_INIT(event->answerlist);
01372
01373 rctx = isc_mem_get(mctx, sizeof(*rctx));
01374 if (rctx == NULL)
01375 result = ISC_R_NOMEMORY;
01376 else {
01377 result = isc_mutex_init(&rctx->lock);
01378 if (result != ISC_R_SUCCESS) {
01379 isc_mem_put(mctx, rctx, sizeof(*rctx));
01380 rctx = NULL;
01381 }
01382 }
01383 if (result != ISC_R_SUCCESS)
01384 goto cleanup;
01385
01386 result = getrdataset(mctx, &rdataset);
01387 if (result != ISC_R_SUCCESS)
01388 goto cleanup;
01389 rctx->rdataset = rdataset;
01390
01391 if (want_dnssec) {
01392 result = getrdataset(mctx, &sigrdataset);
01393 if (result != ISC_R_SUCCESS)
01394 goto cleanup;
01395 }
01396 rctx->sigrdataset = sigrdataset;
01397
01398 dns_fixedname_init(&rctx->name);
01399 result = dns_name_copy(name, dns_fixedname_name(&rctx->name), NULL);
01400 if (result != ISC_R_SUCCESS)
01401 goto cleanup;
01402
01403 rctx->client = client;
01404 ISC_LINK_INIT(rctx, link);
01405 rctx->canceled = ISC_FALSE;
01406 rctx->task = client->task;
01407 rctx->type = type;
01408 rctx->view = view;
01409 rctx->restarts = 0;
01410 rctx->fetch = NULL;
01411 rctx->want_dnssec = want_dnssec;
01412 rctx->want_validation = want_validation;
01413 rctx->want_cdflag = want_cdflag;
01414 rctx->want_tcp = want_tcp;
01415 ISC_LIST_INIT(rctx->namelist);
01416 rctx->event = event;
01417
01418 rctx->magic = RCTX_MAGIC;
01419
01420 LOCK(&client->lock);
01421 ISC_LIST_APPEND(client->resctxs, rctx, link);
01422 UNLOCK(&client->lock);
01423
01424 *transp = (dns_clientrestrans_t *)rctx;
01425 client_resfind(rctx, NULL);
01426
01427 return (ISC_R_SUCCESS);
01428
01429 cleanup:
01430 if (rdataset != NULL)
01431 putrdataset(client->mctx, &rdataset);
01432 if (sigrdataset != NULL)
01433 putrdataset(client->mctx, &sigrdataset);
01434 if (rctx != NULL) {
01435 DESTROYLOCK(&rctx->lock);
01436 isc_mem_put(mctx, rctx, sizeof(*rctx));
01437 }
01438 if (event != NULL)
01439 isc_event_free(ISC_EVENT_PTR(&event));
01440 isc_task_detach(&clone);
01441 dns_view_detach(&view);
01442
01443 return (result);
01444 }
01445
01446 void
01447 dns_client_cancelresolve(dns_clientrestrans_t *trans) {
01448 resctx_t *rctx;
01449
01450 REQUIRE(trans != NULL);
01451 rctx = (resctx_t *)trans;
01452 REQUIRE(RCTX_VALID(rctx));
01453
01454 LOCK(&rctx->lock);
01455
01456 if (!rctx->canceled) {
01457 rctx->canceled = ISC_TRUE;
01458 if (rctx->fetch != NULL)
01459 dns_resolver_cancelfetch(rctx->fetch);
01460 }
01461
01462 UNLOCK(&rctx->lock);
01463 }
01464
01465 void
01466 dns_client_freeresanswer(dns_client_t *client, dns_namelist_t *namelist) {
01467 dns_name_t *name;
01468 dns_rdataset_t *rdataset;
01469
01470 REQUIRE(DNS_CLIENT_VALID(client));
01471 REQUIRE(namelist != NULL);
01472
01473 while ((name = ISC_LIST_HEAD(*namelist)) != NULL) {
01474 ISC_LIST_UNLINK(*namelist, name, link);
01475 while ((rdataset = ISC_LIST_HEAD(name->list)) != NULL) {
01476 ISC_LIST_UNLINK(name->list, rdataset, link);
01477 putrdataset(client->mctx, &rdataset);
01478 }
01479 dns_name_free(name, client->mctx);
01480 isc_mem_put(client->mctx, name, sizeof(*name));
01481 }
01482 }
01483
01484 void
01485 dns_client_destroyrestrans(dns_clientrestrans_t **transp) {
01486 resctx_t *rctx;
01487 isc_mem_t *mctx;
01488 dns_client_t *client;
01489 isc_boolean_t need_destroyclient = ISC_FALSE;
01490
01491 REQUIRE(transp != NULL);
01492 rctx = (resctx_t *)*transp;
01493 REQUIRE(RCTX_VALID(rctx));
01494 REQUIRE(rctx->fetch == NULL);
01495 REQUIRE(rctx->event == NULL);
01496 client = rctx->client;
01497 REQUIRE(DNS_CLIENT_VALID(client));
01498
01499 mctx = client->mctx;
01500 dns_view_detach(&rctx->view);
01501
01502 LOCK(&client->lock);
01503
01504 INSIST(ISC_LINK_LINKED(rctx, link));
01505 ISC_LIST_UNLINK(client->resctxs, rctx, link);
01506
01507 if (client->references == 0 && ISC_LIST_EMPTY(client->resctxs) &&
01508 ISC_LIST_EMPTY(client->reqctxs) &&
01509 ISC_LIST_EMPTY(client->updatectxs))
01510 need_destroyclient = ISC_TRUE;
01511
01512 UNLOCK(&client->lock);
01513
01514 INSIST(ISC_LIST_EMPTY(rctx->namelist));
01515
01516 DESTROYLOCK(&rctx->lock);
01517 rctx->magic = 0;
01518
01519 isc_mem_put(mctx, rctx, sizeof(*rctx));
01520
01521 if (need_destroyclient)
01522 destroyclient(&client);
01523
01524 *transp = NULL;
01525 }
01526
01527 isc_result_t
01528 dns_client_addtrustedkey(dns_client_t *client, dns_rdataclass_t rdclass,
01529 dns_name_t *keyname, isc_buffer_t *keydatabuf)
01530 {
01531 isc_result_t result;
01532 dns_view_t *view = NULL;
01533 dst_key_t *dstkey = NULL;
01534 dns_keytable_t *secroots = NULL;
01535
01536 REQUIRE(DNS_CLIENT_VALID(client));
01537
01538 LOCK(&client->lock);
01539 result = dns_viewlist_find(&client->viewlist, DNS_CLIENTVIEW_NAME,
01540 rdclass, &view);
01541 UNLOCK(&client->lock);
01542 if (result != ISC_R_SUCCESS)
01543 goto cleanup;
01544
01545 result = dns_view_getsecroots(view, &secroots);
01546 if (result != ISC_R_SUCCESS)
01547 goto cleanup;
01548
01549 result = dst_key_fromdns(keyname, rdclass, keydatabuf, client->mctx,
01550 &dstkey);
01551 if (result != ISC_R_SUCCESS)
01552 goto cleanup;
01553
01554 result = dns_keytable_add(secroots, ISC_FALSE, &dstkey);
01555
01556 cleanup:
01557 if (dstkey != NULL)
01558 dst_key_free(&dstkey);
01559 if (view != NULL)
01560 dns_view_detach(&view);
01561 if (secroots != NULL)
01562 dns_keytable_detach(&secroots);
01563 return (result);
01564 }
01565
01566
01567
01568
01569 static void
01570 request_done(isc_task_t *task, isc_event_t *event) {
01571 dns_requestevent_t *reqev = NULL;
01572 dns_request_t *request;
01573 isc_result_t result, eresult;
01574 reqctx_t *ctx;
01575
01576 UNUSED(task);
01577
01578 REQUIRE(event->ev_type == DNS_EVENT_REQUESTDONE);
01579 reqev = (dns_requestevent_t *)event;
01580 request = reqev->request;
01581 result = eresult = reqev->result;
01582 ctx = reqev->ev_arg;
01583 REQUIRE(REQCTX_VALID(ctx));
01584
01585 isc_event_free(&event);
01586
01587 LOCK(&ctx->lock);
01588
01589 if (eresult == ISC_R_SUCCESS) {
01590 result = dns_request_getresponse(request, ctx->event->rmessage,
01591 ctx->parseoptions);
01592 }
01593
01594 if (ctx->tsigkey != NULL)
01595 dns_tsigkey_detach(&ctx->tsigkey);
01596
01597 if (ctx->canceled)
01598 ctx->event->result = ISC_R_CANCELED;
01599 else
01600 ctx->event->result = result;
01601 task = ctx->event->ev_sender;
01602 ctx->event->ev_sender = ctx;
01603 isc_task_sendanddetach(&task, ISC_EVENT_PTR(&ctx->event));
01604
01605 UNLOCK(&ctx->lock);
01606 }
01607
01608 static void
01609 localrequest_done(isc_task_t *task, isc_event_t *event) {
01610 reqarg_t *reqarg = event->ev_arg;
01611 dns_clientreqevent_t *rev =(dns_clientreqevent_t *)event;
01612
01613 UNUSED(task);
01614
01615 REQUIRE(event->ev_type == DNS_EVENT_CLIENTREQDONE);
01616
01617 LOCK(&reqarg->lock);
01618
01619 reqarg->result = rev->result;
01620 dns_client_destroyreqtrans(&reqarg->trans);
01621 isc_event_free(&event);
01622
01623 if (!reqarg->canceled) {
01624 UNLOCK(&reqarg->lock);
01625
01626
01627 isc_app_ctxsuspend(reqarg->actx);
01628 } else {
01629
01630
01631
01632
01633 UNLOCK(&reqarg->lock);
01634 DESTROYLOCK(&reqarg->lock);
01635 isc_mem_put(reqarg->client->mctx, reqarg, sizeof(*reqarg));
01636 }
01637 }
01638
01639 isc_result_t
01640 dns_client_request(dns_client_t *client, dns_message_t *qmessage,
01641 dns_message_t *rmessage, isc_sockaddr_t *server,
01642 unsigned int options, unsigned int parseoptions,
01643 dns_tsec_t *tsec, unsigned int timeout,
01644 unsigned int udptimeout, unsigned int udpretries)
01645 {
01646 isc_appctx_t *actx;
01647 reqarg_t *reqarg;
01648 isc_result_t result;
01649
01650 REQUIRE(DNS_CLIENT_VALID(client));
01651 REQUIRE(qmessage != NULL);
01652 REQUIRE(rmessage != NULL);
01653
01654 if ((client->attributes & DNS_CLIENTATTR_OWNCTX) == 0 &&
01655 (options & DNS_CLIENTREQOPT_ALLOWRUN) == 0) {
01656
01657
01658
01659
01660
01661 return (ISC_R_NOTIMPLEMENTED);
01662 } else
01663 actx = client->actx;
01664
01665 reqarg = isc_mem_get(client->mctx, sizeof(*reqarg));
01666 if (reqarg == NULL)
01667 return (ISC_R_NOMEMORY);
01668
01669 result = isc_mutex_init(&reqarg->lock);
01670 if (result != ISC_R_SUCCESS) {
01671 isc_mem_put(client->mctx, reqarg, sizeof(*reqarg));
01672 return (result);
01673 }
01674
01675 reqarg->actx = actx;
01676 reqarg->client = client;
01677 reqarg->trans = NULL;
01678 reqarg->canceled = ISC_FALSE;
01679
01680 result = dns_client_startrequest(client, qmessage, rmessage, server,
01681 options, parseoptions, tsec, timeout,
01682 udptimeout, udpretries,
01683 client->task, localrequest_done,
01684 reqarg, &reqarg->trans);
01685 if (result != ISC_R_SUCCESS) {
01686 DESTROYLOCK(&reqarg->lock);
01687 isc_mem_put(client->mctx, reqarg, sizeof(*reqarg));
01688 return (result);
01689 }
01690
01691
01692
01693
01694
01695 result = isc_app_ctxrun(actx);
01696
01697 LOCK(&reqarg->lock);
01698 if (result == ISC_R_SUCCESS || result == ISC_R_SUSPEND)
01699 result = reqarg->result;
01700 if (reqarg->trans != NULL) {
01701
01702
01703
01704
01705 reqarg->canceled = ISC_TRUE;
01706 dns_client_cancelresolve(reqarg->trans);
01707
01708 UNLOCK(&reqarg->lock);
01709
01710
01711 } else {
01712 UNLOCK(&reqarg->lock);
01713
01714 DESTROYLOCK(&reqarg->lock);
01715 isc_mem_put(client->mctx, reqarg, sizeof(*reqarg));
01716 }
01717
01718 return (result);
01719 }
01720
01721 isc_result_t
01722 dns_client_startrequest(dns_client_t *client, dns_message_t *qmessage,
01723 dns_message_t *rmessage, isc_sockaddr_t *server,
01724 unsigned int options, unsigned int parseoptions,
01725 dns_tsec_t *tsec, unsigned int timeout,
01726 unsigned int udptimeout, unsigned int udpretries,
01727 isc_task_t *task, isc_taskaction_t action, void *arg,
01728 dns_clientreqtrans_t **transp)
01729 {
01730 isc_result_t result;
01731 dns_view_t *view = NULL;
01732 isc_task_t *clone = NULL;
01733 dns_clientreqevent_t *event = NULL;
01734 reqctx_t *ctx = NULL;
01735 dns_tsectype_t tsectype = dns_tsectype_none;
01736 unsigned int reqoptions;
01737
01738 REQUIRE(DNS_CLIENT_VALID(client));
01739 REQUIRE(qmessage != NULL);
01740 REQUIRE(rmessage != NULL);
01741 REQUIRE(transp != NULL && *transp == NULL);
01742
01743 if (tsec != NULL) {
01744 tsectype = dns_tsec_gettype(tsec);
01745 if (tsectype != dns_tsectype_tsig)
01746 return (ISC_R_NOTIMPLEMENTED);
01747 }
01748
01749 LOCK(&client->lock);
01750 result = dns_viewlist_find(&client->viewlist, DNS_CLIENTVIEW_NAME,
01751 qmessage->rdclass, &view);
01752 UNLOCK(&client->lock);
01753 if (result != ISC_R_SUCCESS)
01754 return (result);
01755
01756 reqoptions = 0;
01757 if ((options & DNS_CLIENTREQOPT_TCP) != 0)
01758 reqoptions |= DNS_REQUESTOPT_TCP;
01759
01760 clone = NULL;
01761 isc_task_attach(task, &clone);
01762 event = (dns_clientreqevent_t *)
01763 isc_event_allocate(client->mctx, clone,
01764 DNS_EVENT_CLIENTREQDONE,
01765 action, arg, sizeof(*event));
01766 if (event == NULL) {
01767 result = ISC_R_NOMEMORY;
01768 goto cleanup;
01769 }
01770
01771 ctx = isc_mem_get(client->mctx, sizeof(*ctx));
01772 if (ctx == NULL)
01773 result = ISC_R_NOMEMORY;
01774 else {
01775 result = isc_mutex_init(&ctx->lock);
01776 if (result != ISC_R_SUCCESS) {
01777 isc_mem_put(client->mctx, ctx, sizeof(*ctx));
01778 ctx = NULL;
01779 }
01780 }
01781 if (result != ISC_R_SUCCESS)
01782 goto cleanup;
01783
01784 ctx->client = client;
01785 ISC_LINK_INIT(ctx, link);
01786 ctx->parseoptions = parseoptions;
01787 ctx->canceled = ISC_FALSE;
01788 ctx->event = event;
01789 ctx->event->rmessage = rmessage;
01790 ctx->tsigkey = NULL;
01791 if (tsec != NULL)
01792 dns_tsec_getkey(tsec, &ctx->tsigkey);
01793
01794 ctx->magic = REQCTX_MAGIC;
01795
01796 LOCK(&client->lock);
01797 ISC_LIST_APPEND(client->reqctxs, ctx, link);
01798 UNLOCK(&client->lock);
01799
01800 ctx->request = NULL;
01801 result = dns_request_createvia3(view->requestmgr, qmessage, NULL,
01802 server, reqoptions, ctx->tsigkey,
01803 timeout, udptimeout, udpretries,
01804 client->task, request_done, ctx,
01805 &ctx->request);
01806 if (result == ISC_R_SUCCESS) {
01807 dns_view_detach(&view);
01808 *transp = (dns_clientreqtrans_t *)ctx;
01809 return (ISC_R_SUCCESS);
01810 }
01811
01812 cleanup:
01813 if (ctx != NULL) {
01814 LOCK(&client->lock);
01815 ISC_LIST_UNLINK(client->reqctxs, ctx, link);
01816 UNLOCK(&client->lock);
01817 DESTROYLOCK(&ctx->lock);
01818 isc_mem_put(client->mctx, ctx, sizeof(*ctx));
01819 }
01820 if (event != NULL)
01821 isc_event_free(ISC_EVENT_PTR(&event));
01822 isc_task_detach(&clone);
01823 dns_view_detach(&view);
01824
01825 return (result);
01826 }
01827
01828 void
01829 dns_client_cancelrequest(dns_clientreqtrans_t *trans) {
01830 reqctx_t *ctx;
01831
01832 REQUIRE(trans != NULL);
01833 ctx = (reqctx_t *)trans;
01834 REQUIRE(REQCTX_VALID(ctx));
01835
01836 LOCK(&ctx->lock);
01837
01838 if (!ctx->canceled) {
01839 ctx->canceled = ISC_TRUE;
01840 if (ctx->request != NULL)
01841 dns_request_cancel(ctx->request);
01842 }
01843
01844 UNLOCK(&ctx->lock);
01845 }
01846
01847 void
01848 dns_client_destroyreqtrans(dns_clientreqtrans_t **transp) {
01849 reqctx_t *ctx;
01850 isc_mem_t *mctx;
01851 dns_client_t *client;
01852 isc_boolean_t need_destroyclient = ISC_FALSE;
01853
01854 REQUIRE(transp != NULL);
01855 ctx = (reqctx_t *)*transp;
01856 REQUIRE(REQCTX_VALID(ctx));
01857 client = ctx->client;
01858 REQUIRE(DNS_CLIENT_VALID(client));
01859 REQUIRE(ctx->event == NULL);
01860 REQUIRE(ctx->request != NULL);
01861
01862 dns_request_destroy(&ctx->request);
01863 mctx = client->mctx;
01864
01865 LOCK(&client->lock);
01866
01867 INSIST(ISC_LINK_LINKED(ctx, link));
01868 ISC_LIST_UNLINK(client->reqctxs, ctx, link);
01869
01870 if (client->references == 0 && ISC_LIST_EMPTY(client->resctxs) &&
01871 ISC_LIST_EMPTY(client->reqctxs) &&
01872 ISC_LIST_EMPTY(client->updatectxs)) {
01873 need_destroyclient = ISC_TRUE;
01874 }
01875
01876 UNLOCK(&client->lock);
01877
01878 DESTROYLOCK(&ctx->lock);
01879 ctx->magic = 0;
01880
01881 isc_mem_put(mctx, ctx, sizeof(*ctx));
01882
01883 if (need_destroyclient)
01884 destroyclient(&client);
01885
01886 *transp = NULL;
01887 }
01888
01889
01890
01891
01892 static isc_result_t
01893 rcode2result(dns_rcode_t rcode) {
01894
01895 switch (rcode) {
01896 case dns_rcode_formerr:
01897 return (DNS_R_FORMERR);
01898 case dns_rcode_servfail:
01899 return (DNS_R_SERVFAIL);
01900 case dns_rcode_nxdomain:
01901 return (DNS_R_NXDOMAIN);
01902 case dns_rcode_notimp:
01903 return (DNS_R_NOTIMP);
01904 case dns_rcode_refused:
01905 return (DNS_R_REFUSED);
01906 case dns_rcode_yxdomain:
01907 return (DNS_R_YXDOMAIN);
01908 case dns_rcode_yxrrset:
01909 return (DNS_R_YXRRSET);
01910 case dns_rcode_nxrrset:
01911 return (DNS_R_NXRRSET);
01912 case dns_rcode_notauth:
01913 return (DNS_R_NOTAUTH);
01914 case dns_rcode_notzone:
01915 return (DNS_R_NOTZONE);
01916 case dns_rcode_badvers:
01917 return (DNS_R_BADVERS);
01918 }
01919
01920 return (ISC_R_FAILURE);
01921 }
01922
01923 static void
01924 update_sendevent(updatectx_t *uctx, isc_result_t result) {
01925 isc_task_t *task;
01926
01927 dns_message_destroy(&uctx->updatemsg);
01928 if (uctx->tsigkey != NULL)
01929 dns_tsigkey_detach(&uctx->tsigkey);
01930 if (uctx->sig0key != NULL)
01931 dst_key_free(&uctx->sig0key);
01932
01933 if (uctx->canceled)
01934 uctx->event->result = ISC_R_CANCELED;
01935 else
01936 uctx->event->result = result;
01937 uctx->event->state = uctx->state;
01938 task = uctx->event->ev_sender;
01939 uctx->event->ev_sender = uctx;
01940 isc_task_sendanddetach(&task, ISC_EVENT_PTR(&uctx->event));
01941 }
01942
01943 static void
01944 update_done(isc_task_t *task, isc_event_t *event) {
01945 isc_result_t result;
01946 dns_requestevent_t *reqev = NULL;
01947 dns_request_t *request;
01948 dns_message_t *answer = NULL;
01949 updatectx_t *uctx = event->ev_arg;
01950 dns_client_t *client;
01951 unsigned int timeout, reqoptions;
01952
01953 UNUSED(task);
01954
01955 REQUIRE(event->ev_type == DNS_EVENT_REQUESTDONE);
01956 reqev = (dns_requestevent_t *)event;
01957 request = reqev->request;
01958 REQUIRE(UCTX_VALID(uctx));
01959 client = uctx->client;
01960 REQUIRE(DNS_CLIENT_VALID(client));
01961
01962 result = reqev->result;
01963 if (result != ISC_R_SUCCESS)
01964 goto out;
01965
01966 result = dns_message_create(client->mctx, DNS_MESSAGE_INTENTPARSE,
01967 &answer);
01968 if (result != ISC_R_SUCCESS)
01969 goto out;
01970 uctx->state = dns_clientupdatestate_done;
01971 result = dns_request_getresponse(request, answer,
01972 DNS_MESSAGEPARSE_PRESERVEORDER);
01973 if (result == ISC_R_SUCCESS && answer->rcode != dns_rcode_noerror)
01974 result = rcode2result(answer->rcode);
01975
01976 out:
01977 if (answer != NULL)
01978 dns_message_destroy(&answer);
01979 isc_event_free(&event);
01980
01981 LOCK(&uctx->lock);
01982 uctx->currentserver = ISC_LIST_NEXT(uctx->currentserver, link);
01983 dns_request_destroy(&uctx->updatereq);
01984 if (result != ISC_R_SUCCESS && !uctx->canceled &&
01985 uctx->currentserver != NULL) {
01986 dns_message_renderreset(uctx->updatemsg);
01987 dns_message_settsigkey(uctx->updatemsg, NULL);
01988
01989 timeout = client->update_timeout / uctx->nservers;
01990 if (timeout < MIN_UPDATE_TIMEOUT)
01991 timeout = MIN_UPDATE_TIMEOUT;
01992 reqoptions = 0;
01993 if (uctx->want_tcp)
01994 reqoptions |= DNS_REQUESTOPT_TCP;
01995 result = dns_request_createvia3(uctx->view->requestmgr,
01996 uctx->updatemsg,
01997 NULL,
01998 uctx->currentserver,
01999 reqoptions,
02000 uctx->tsigkey,
02001 timeout,
02002 client->update_udptimeout,
02003 client->update_udpretries,
02004 client->task,
02005 update_done, uctx,
02006 &uctx->updatereq);
02007 UNLOCK(&uctx->lock);
02008
02009 if (result == ISC_R_SUCCESS) {
02010
02011 uctx->state = dns_clientupdatestate_sent;
02012 return;
02013 }
02014 } else
02015 UNLOCK(&uctx->lock);
02016
02017 update_sendevent(uctx, result);
02018 }
02019
02020 static isc_result_t
02021 send_update(updatectx_t *uctx) {
02022 isc_result_t result;
02023 dns_name_t *name = NULL;
02024 dns_rdataset_t *rdataset = NULL;
02025 dns_client_t *client = uctx->client;
02026 unsigned int timeout, reqoptions;
02027
02028 REQUIRE(uctx->zonename != NULL && uctx->currentserver != NULL);
02029
02030 result = dns_message_gettempname(uctx->updatemsg, &name);
02031 if (result != ISC_R_SUCCESS)
02032 return (result);
02033 dns_name_init(name, NULL);
02034 dns_name_clone(uctx->zonename, name);
02035 result = dns_message_gettemprdataset(uctx->updatemsg, &rdataset);
02036 if (result != ISC_R_SUCCESS) {
02037 dns_message_puttempname(uctx->updatemsg, &name);
02038 return (result);
02039 }
02040 dns_rdataset_makequestion(rdataset, uctx->rdclass, dns_rdatatype_soa);
02041 ISC_LIST_INIT(name->list);
02042 ISC_LIST_APPEND(name->list, rdataset, link);
02043 dns_message_addname(uctx->updatemsg, name, DNS_SECTION_ZONE);
02044 if (uctx->tsigkey == NULL && uctx->sig0key != NULL) {
02045 result = dns_message_setsig0key(uctx->updatemsg,
02046 uctx->sig0key);
02047 if (result != ISC_R_SUCCESS)
02048 return (result);
02049 }
02050 timeout = client->update_timeout / uctx->nservers;
02051 if (timeout < MIN_UPDATE_TIMEOUT)
02052 timeout = MIN_UPDATE_TIMEOUT;
02053 reqoptions = 0;
02054 if (uctx->want_tcp)
02055 reqoptions |= DNS_REQUESTOPT_TCP;
02056 result = dns_request_createvia3(uctx->view->requestmgr,
02057 uctx->updatemsg,
02058 NULL, uctx->currentserver,
02059 reqoptions, uctx->tsigkey, timeout,
02060 client->update_udptimeout,
02061 client->update_udpretries,
02062 client->task, update_done, uctx,
02063 &uctx->updatereq);
02064 if (result == ISC_R_SUCCESS &&
02065 uctx->state == dns_clientupdatestate_prepare) {
02066 uctx->state = dns_clientupdatestate_sent;
02067 }
02068
02069 return (result);
02070 }
02071
02072 static void
02073 resolveaddr_done(isc_task_t *task, isc_event_t *event) {
02074 isc_result_t result;
02075 int family;
02076 dns_rdatatype_t qtype;
02077 dns_clientresevent_t *rev = (dns_clientresevent_t *)event;
02078 dns_name_t *name;
02079 dns_rdataset_t *rdataset;
02080 updatectx_t *uctx;
02081 isc_boolean_t completed = ISC_FALSE;
02082
02083 UNUSED(task);
02084
02085 REQUIRE(event->ev_arg != NULL);
02086 uctx = *(updatectx_t **)event->ev_arg;
02087 REQUIRE(UCTX_VALID(uctx));
02088
02089 if (event->ev_arg == &uctx->bp4) {
02090 family = AF_INET;
02091 qtype = dns_rdatatype_a;
02092 LOCK(&uctx->lock);
02093 dns_client_destroyrestrans(&uctx->restrans);
02094 UNLOCK(&uctx->lock);
02095 } else {
02096 INSIST(event->ev_arg == &uctx->bp6);
02097 family = AF_INET6;
02098 qtype = dns_rdatatype_aaaa;
02099 LOCK(&uctx->lock);
02100 dns_client_destroyrestrans(&uctx->restrans2);
02101 UNLOCK(&uctx->lock);
02102 }
02103
02104 result = rev->result;
02105 if (result != ISC_R_SUCCESS)
02106 goto done;
02107
02108 for (name = ISC_LIST_HEAD(rev->answerlist); name != NULL;
02109 name = ISC_LIST_NEXT(name, link)) {
02110 for (rdataset = ISC_LIST_HEAD(name->list);
02111 rdataset != NULL;
02112 rdataset = ISC_LIST_NEXT(rdataset, link)) {
02113 if (!dns_rdataset_isassociated(rdataset))
02114 continue;
02115 if (rdataset->type != qtype)
02116 continue;
02117
02118 for (result = dns_rdataset_first(rdataset);
02119 result == ISC_R_SUCCESS;
02120 result = dns_rdataset_next(rdataset)) {
02121 dns_rdata_t rdata;
02122 dns_rdata_in_a_t rdata_a;
02123 dns_rdata_in_aaaa_t rdata_aaaa;
02124 isc_sockaddr_t *sa;
02125
02126 sa = isc_mem_get(uctx->client->mctx,
02127 sizeof(*sa));
02128 if (sa == NULL) {
02129
02130
02131
02132
02133
02134 goto done;
02135 }
02136
02137 dns_rdata_init(&rdata);
02138 switch (family) {
02139 case AF_INET:
02140 dns_rdataset_current(rdataset, &rdata);
02141 result = dns_rdata_tostruct(&rdata, &rdata_a,
02142 NULL);
02143 RUNTIME_CHECK(result == ISC_R_SUCCESS);
02144 isc_sockaddr_fromin(sa,
02145 &rdata_a.in_addr,
02146 53);
02147 dns_rdata_freestruct(&rdata_a);
02148 break;
02149 case AF_INET6:
02150 dns_rdataset_current(rdataset, &rdata);
02151 result = dns_rdata_tostruct(&rdata, &rdata_aaaa,
02152 NULL);
02153 RUNTIME_CHECK(result == ISC_R_SUCCESS);
02154 isc_sockaddr_fromin6(sa,
02155 &rdata_aaaa.in6_addr,
02156 53);
02157 dns_rdata_freestruct(&rdata_aaaa);
02158 break;
02159 }
02160
02161 ISC_LINK_INIT(sa, link);
02162 ISC_LIST_APPEND(uctx->servers, sa, link);
02163 uctx->nservers++;
02164 }
02165 }
02166 }
02167
02168 done:
02169 dns_client_freeresanswer(uctx->client, &rev->answerlist);
02170 isc_event_free(&event);
02171
02172 LOCK(&uctx->lock);
02173 if (uctx->restrans == NULL && uctx->restrans2 == NULL)
02174 completed = ISC_TRUE;
02175 UNLOCK(&uctx->lock);
02176
02177 if (completed) {
02178 INSIST(uctx->currentserver == NULL);
02179 uctx->currentserver = ISC_LIST_HEAD(uctx->servers);
02180 if (uctx->currentserver != NULL && !uctx->canceled)
02181 send_update(uctx);
02182 else {
02183 if (result == ISC_R_SUCCESS)
02184 result = ISC_R_NOTFOUND;
02185 update_sendevent(uctx, result);
02186 }
02187 }
02188 }
02189
02190 static isc_result_t
02191 process_soa(updatectx_t *uctx, dns_rdataset_t *soaset, dns_name_t *soaname) {
02192 isc_result_t result;
02193 dns_rdata_t soarr = DNS_RDATA_INIT;
02194 dns_rdata_soa_t soa;
02195 dns_name_t primary;
02196 unsigned int resoptions;
02197
02198 result = dns_rdataset_first(soaset);
02199 if (result != ISC_R_SUCCESS)
02200 return (result);
02201 dns_rdata_init(&soarr);
02202 dns_rdataset_current(soaset, &soarr);
02203 result = dns_rdata_tostruct(&soarr, &soa, NULL);
02204 if (result != ISC_R_SUCCESS)
02205 return (result);
02206
02207 dns_name_init(&primary, NULL);
02208 dns_name_clone(&soa.origin, &primary);
02209
02210 if (uctx->zonename == NULL) {
02211 uctx->zonename = dns_fixedname_name(&uctx->zonefname);
02212 result = dns_name_copy(soaname, uctx->zonename, NULL);
02213 if (result != ISC_R_SUCCESS)
02214 goto out;
02215 }
02216
02217 if (uctx->currentserver != NULL)
02218 result = send_update(uctx);
02219 else {
02220
02221
02222
02223
02224 LOCK(&uctx->lock);
02225 uctx->bp4 = uctx;
02226 resoptions = 0;
02227 if (uctx->want_tcp)
02228 resoptions |= DNS_CLIENTRESOPT_TCP;
02229 result = dns_client_startresolve(uctx->client, &primary,
02230 uctx->rdclass,
02231 dns_rdatatype_a,
02232 resoptions,
02233 uctx->client->task,
02234 resolveaddr_done, &uctx->bp4,
02235 &uctx->restrans);
02236 if (result == ISC_R_SUCCESS) {
02237 uctx->bp6 = uctx;
02238 result = dns_client_startresolve(uctx->client,
02239 &primary,
02240 uctx->rdclass,
02241 dns_rdatatype_aaaa,
02242 resoptions,
02243 uctx->client->task,
02244 resolveaddr_done,
02245 &uctx->bp6,
02246 &uctx->restrans2);
02247 }
02248 UNLOCK(&uctx->lock);
02249 }
02250
02251 out:
02252 dns_rdata_freestruct(&soa);
02253
02254 return (result);
02255 }
02256
02257 static void
02258 receive_soa(isc_task_t *task, isc_event_t *event) {
02259 dns_requestevent_t *reqev = NULL;
02260 updatectx_t *uctx;
02261 dns_client_t *client;
02262 isc_result_t result, eresult;
02263 dns_request_t *request;
02264 dns_message_t *rcvmsg = NULL;
02265 dns_section_t section;
02266 dns_rdataset_t *soaset = NULL;
02267 int pass = 0;
02268 dns_name_t *name;
02269 dns_message_t *soaquery = NULL;
02270 isc_sockaddr_t *addr;
02271 isc_boolean_t seencname = ISC_FALSE;
02272 isc_boolean_t droplabel = ISC_FALSE;
02273 dns_name_t tname;
02274 unsigned int nlabels, reqoptions;
02275
02276 UNUSED(task);
02277
02278 REQUIRE(event->ev_type == DNS_EVENT_REQUESTDONE);
02279 reqev = (dns_requestevent_t *)event;
02280 request = reqev->request;
02281 result = eresult = reqev->result;
02282 POST(result);
02283 uctx = reqev->ev_arg;
02284 client = uctx->client;
02285 soaquery = uctx->soaquery;
02286 addr = uctx->currentserver;
02287 INSIST(addr != NULL);
02288
02289 isc_event_free(&event);
02290
02291 if (eresult != ISC_R_SUCCESS) {
02292 result = eresult;
02293 goto out;
02294 }
02295
02296 result = dns_message_create(uctx->client->mctx,
02297 DNS_MESSAGE_INTENTPARSE, &rcvmsg);
02298 if (result != ISC_R_SUCCESS)
02299 goto out;
02300 result = dns_request_getresponse(request, rcvmsg,
02301 DNS_MESSAGEPARSE_PRESERVEORDER);
02302
02303 if (result == DNS_R_TSIGERRORSET) {
02304 dns_request_t *newrequest = NULL;
02305
02306
02307 dns_message_destroy(&rcvmsg);
02308 dns_message_renderreset(uctx->soaquery);
02309 reqoptions = 0;
02310 if (uctx->want_tcp)
02311 reqoptions |= DNS_REQUESTOPT_TCP;
02312 result = dns_request_createvia3(uctx->view->requestmgr,
02313 uctx->soaquery, NULL, addr,
02314 reqoptions, NULL,
02315 client->find_timeout * 20,
02316 client->find_timeout, 3,
02317 uctx->client->task,
02318 receive_soa, uctx,
02319 &newrequest);
02320 if (result == ISC_R_SUCCESS) {
02321 LOCK(&uctx->lock);
02322 dns_request_destroy(&uctx->soareq);
02323 uctx->soareq = newrequest;
02324 UNLOCK(&uctx->lock);
02325
02326 return;
02327 }
02328 goto out;
02329 }
02330
02331 section = DNS_SECTION_ANSWER;
02332 POST(section);
02333
02334 if (rcvmsg->rcode != dns_rcode_noerror &&
02335 rcvmsg->rcode != dns_rcode_nxdomain) {
02336 result = rcode2result(rcvmsg->rcode);
02337 goto out;
02338 }
02339
02340 lookforsoa:
02341 if (pass == 0)
02342 section = DNS_SECTION_ANSWER;
02343 else if (pass == 1)
02344 section = DNS_SECTION_AUTHORITY;
02345 else {
02346 droplabel = ISC_TRUE;
02347 goto out;
02348 }
02349
02350 result = dns_message_firstname(rcvmsg, section);
02351 if (result != ISC_R_SUCCESS) {
02352 pass++;
02353 goto lookforsoa;
02354 }
02355 while (result == ISC_R_SUCCESS) {
02356 name = NULL;
02357 dns_message_currentname(rcvmsg, section, &name);
02358 soaset = NULL;
02359 result = dns_message_findtype(name, dns_rdatatype_soa, 0,
02360 &soaset);
02361 if (result == ISC_R_SUCCESS)
02362 break;
02363 if (section == DNS_SECTION_ANSWER) {
02364 dns_rdataset_t *tset = NULL;
02365 if (dns_message_findtype(name, dns_rdatatype_cname, 0,
02366 &tset) == ISC_R_SUCCESS
02367 ||
02368 dns_message_findtype(name, dns_rdatatype_dname, 0,
02369 &tset) == ISC_R_SUCCESS
02370 )
02371 {
02372 seencname = ISC_TRUE;
02373 break;
02374 }
02375 }
02376
02377 result = dns_message_nextname(rcvmsg, section);
02378 }
02379
02380 if (soaset == NULL && !seencname) {
02381 pass++;
02382 goto lookforsoa;
02383 }
02384
02385 if (seencname) {
02386 droplabel = ISC_TRUE;
02387 goto out;
02388 }
02389
02390 result = process_soa(uctx, soaset, name);
02391
02392 out:
02393 if (droplabel) {
02394 result = dns_message_firstname(soaquery, DNS_SECTION_QUESTION);
02395 INSIST(result == ISC_R_SUCCESS);
02396 name = NULL;
02397 dns_message_currentname(soaquery, DNS_SECTION_QUESTION, &name);
02398 nlabels = dns_name_countlabels(name);
02399 if (nlabels == 1)
02400 result = DNS_R_SERVFAIL;
02401 else {
02402 dns_name_init(&tname, NULL);
02403 dns_name_getlabelsequence(name, 1, nlabels - 1,
02404 &tname);
02405 dns_name_clone(&tname, name);
02406 dns_request_destroy(&request);
02407 LOCK(&uctx->lock);
02408 uctx->soareq = NULL;
02409 UNLOCK(&uctx->lock);
02410 dns_message_renderreset(soaquery);
02411 dns_message_settsigkey(soaquery, NULL);
02412 reqoptions = 0;
02413 if (uctx->want_tcp)
02414 reqoptions |= DNS_REQUESTOPT_TCP;
02415 result = dns_request_createvia3(uctx->view->requestmgr,
02416 soaquery, NULL,
02417 uctx->currentserver,
02418 reqoptions,
02419 uctx->tsigkey,
02420 client->find_timeout *
02421 20,
02422 client->find_timeout,
02423 3, client->task,
02424 receive_soa, uctx,
02425 &uctx->soareq);
02426 }
02427 }
02428
02429 if (!droplabel || result != ISC_R_SUCCESS) {
02430 dns_message_destroy(&uctx->soaquery);
02431 LOCK(&uctx->lock);
02432 dns_request_destroy(&uctx->soareq);
02433 UNLOCK(&uctx->lock);
02434 }
02435
02436 if (rcvmsg != NULL)
02437 dns_message_destroy(&rcvmsg);
02438
02439 if (result != ISC_R_SUCCESS)
02440 update_sendevent(uctx, result);
02441 }
02442
02443 static isc_result_t
02444 request_soa(updatectx_t *uctx) {
02445 isc_result_t result;
02446 dns_message_t *soaquery = uctx->soaquery;
02447 dns_name_t *name = NULL;
02448 dns_rdataset_t *rdataset = NULL;
02449 unsigned int reqoptions;
02450
02451 if (soaquery == NULL) {
02452 result = dns_message_create(uctx->client->mctx,
02453 DNS_MESSAGE_INTENTRENDER,
02454 &soaquery);
02455 if (result != ISC_R_SUCCESS)
02456 return (result);
02457 }
02458 soaquery->flags |= DNS_MESSAGEFLAG_RD;
02459 result = dns_message_gettempname(soaquery, &name);
02460 if (result != ISC_R_SUCCESS)
02461 goto fail;
02462 result = dns_message_gettemprdataset(soaquery, &rdataset);
02463 if (result != ISC_R_SUCCESS)
02464 goto fail;
02465 dns_rdataset_makequestion(rdataset, uctx->rdclass, dns_rdatatype_soa);
02466 dns_name_clone(uctx->firstname, name);
02467 ISC_LIST_APPEND(name->list, rdataset, link);
02468 dns_message_addname(soaquery, name, DNS_SECTION_QUESTION);
02469 rdataset = NULL;
02470 name = NULL;
02471 reqoptions = 0;
02472 if (uctx->want_tcp)
02473 reqoptions |= DNS_REQUESTOPT_TCP;
02474
02475 result = dns_request_createvia3(uctx->view->requestmgr,
02476 soaquery, NULL, uctx->currentserver,
02477 reqoptions, uctx->tsigkey,
02478 uctx->client->find_timeout * 20,
02479 uctx->client->find_timeout, 3,
02480 uctx->client->task, receive_soa, uctx,
02481 &uctx->soareq);
02482 if (result == ISC_R_SUCCESS) {
02483 uctx->soaquery = soaquery;
02484 return (ISC_R_SUCCESS);
02485 }
02486
02487 fail:
02488 if (rdataset != NULL) {
02489 ISC_LIST_UNLINK(name->list, rdataset, link);
02490 dns_message_puttemprdataset(soaquery, &rdataset);
02491 }
02492 if (name != NULL)
02493 dns_message_puttempname(soaquery, &name);
02494 dns_message_destroy(&soaquery);
02495
02496 return (result);
02497 }
02498
02499 static void
02500 resolvesoa_done(isc_task_t *task, isc_event_t *event) {
02501 dns_clientresevent_t *rev = (dns_clientresevent_t *)event;
02502 updatectx_t *uctx;
02503 dns_name_t *name, tname;
02504 dns_rdataset_t *rdataset = NULL;
02505 isc_result_t result = rev->result;
02506 unsigned int nlabels, resoptions;
02507
02508 UNUSED(task);
02509
02510 uctx = event->ev_arg;
02511 REQUIRE(UCTX_VALID(uctx));
02512
02513 LOCK(&uctx->lock);
02514 dns_client_destroyrestrans(&uctx->restrans);
02515 UNLOCK(&uctx->lock);
02516
02517 uctx = event->ev_arg;
02518 if (result != ISC_R_SUCCESS &&
02519 result != DNS_R_NCACHENXDOMAIN &&
02520 result != DNS_R_NCACHENXRRSET) {
02521
02522 goto out;
02523 }
02524
02525 for (name = ISC_LIST_HEAD(rev->answerlist); name != NULL;
02526 name = ISC_LIST_NEXT(name, link)) {
02527 for (rdataset = ISC_LIST_HEAD(name->list);
02528 rdataset != NULL;
02529 rdataset = ISC_LIST_NEXT(rdataset, link)) {
02530 if (dns_rdataset_isassociated(rdataset) &&
02531 rdataset->type == dns_rdatatype_soa)
02532 break;
02533 }
02534 }
02535
02536 if (rdataset == NULL) {
02537
02538 nlabels = dns_name_countlabels(&uctx->soaqname);
02539 if (nlabels == 1) {
02540 result = DNS_R_SERVFAIL;
02541 goto out;
02542 }
02543 dns_name_init(&tname, NULL);
02544 dns_name_getlabelsequence(&uctx->soaqname, 1, nlabels - 1,
02545 &tname);
02546 dns_name_clone(&tname, &uctx->soaqname);
02547 resoptions = 0;
02548 if (uctx->want_tcp)
02549 resoptions |= DNS_CLIENTRESOPT_TCP;
02550
02551 result = dns_client_startresolve(uctx->client, &uctx->soaqname,
02552 uctx->rdclass,
02553 dns_rdatatype_soa,
02554 resoptions,
02555 uctx->client->task,
02556 resolvesoa_done, uctx,
02557 &uctx->restrans);
02558 } else
02559 result = process_soa(uctx, rdataset, &uctx->soaqname);
02560
02561 out:
02562 dns_client_freeresanswer(uctx->client, &rev->answerlist);
02563 isc_event_free(&event);
02564
02565 if (result != ISC_R_SUCCESS)
02566 update_sendevent(uctx, result);
02567 }
02568
02569 static isc_result_t
02570 copy_name(isc_mem_t *mctx, dns_message_t *msg, dns_name_t *name,
02571 dns_name_t **newnamep)
02572 {
02573 isc_result_t result;
02574 dns_name_t *newname = NULL;
02575 isc_region_t r;
02576 isc_buffer_t *namebuf = NULL, *rdatabuf = NULL;
02577 dns_rdatalist_t *rdatalist;
02578 dns_rdataset_t *rdataset, *newrdataset;
02579 dns_rdata_t rdata = DNS_RDATA_INIT, *newrdata;
02580
02581 result = dns_message_gettempname(msg, &newname);
02582 if (result != ISC_R_SUCCESS)
02583 return (result);
02584 result = isc_buffer_allocate(mctx, &namebuf, DNS_NAME_MAXWIRE);
02585 if (result != ISC_R_SUCCESS)
02586 goto fail;
02587 dns_name_init(newname, NULL);
02588 dns_name_setbuffer(newname, namebuf);
02589 dns_message_takebuffer(msg, &namebuf);
02590 result = dns_name_copy(name, newname, NULL);
02591 if (result != ISC_R_SUCCESS)
02592 goto fail;
02593
02594 for (rdataset = ISC_LIST_HEAD(name->list); rdataset != NULL;
02595 rdataset = ISC_LIST_NEXT(rdataset, link)) {
02596 rdatalist = NULL;
02597 result = dns_message_gettemprdatalist(msg, &rdatalist);
02598 if (result != ISC_R_SUCCESS)
02599 goto fail;
02600 dns_rdatalist_init(rdatalist);
02601 rdatalist->type = rdataset->type;
02602 rdatalist->rdclass = rdataset->rdclass;
02603 rdatalist->covers = rdataset->covers;
02604 rdatalist->ttl = rdataset->ttl;
02605
02606 result = dns_rdataset_first(rdataset);
02607 while (result == ISC_R_SUCCESS) {
02608 dns_rdata_reset(&rdata);
02609 dns_rdataset_current(rdataset, &rdata);
02610
02611 newrdata = NULL;
02612 result = dns_message_gettemprdata(msg, &newrdata);
02613 if (result != ISC_R_SUCCESS)
02614 goto fail;
02615 dns_rdata_toregion(&rdata, &r);
02616 rdatabuf = NULL;
02617 result = isc_buffer_allocate(mctx, &rdatabuf,
02618 r.length);
02619 if (result != ISC_R_SUCCESS)
02620 goto fail;
02621 isc_buffer_putmem(rdatabuf, r.base, r.length);
02622 isc_buffer_usedregion(rdatabuf, &r);
02623 dns_rdata_init(newrdata);
02624 dns_rdata_fromregion(newrdata, rdata.rdclass,
02625 rdata.type, &r);
02626 newrdata->flags = rdata.flags;
02627
02628 ISC_LIST_APPEND(rdatalist->rdata, newrdata, link);
02629 dns_message_takebuffer(msg, &rdatabuf);
02630
02631 result = dns_rdataset_next(rdataset);
02632 }
02633
02634 newrdataset = NULL;
02635 result = dns_message_gettemprdataset(msg, &newrdataset);
02636 if (result != ISC_R_SUCCESS)
02637 goto fail;
02638 dns_rdataset_init(newrdataset);
02639 dns_rdatalist_tordataset(rdatalist, newrdataset);
02640
02641 ISC_LIST_APPEND(newname->list, newrdataset, link);
02642 }
02643
02644 *newnamep = newname;
02645
02646 return (ISC_R_SUCCESS);
02647
02648 fail:
02649 dns_message_puttempname(msg, &newname);
02650
02651 return (result);
02652
02653 }
02654
02655 static void
02656 internal_update_callback(isc_task_t *task, isc_event_t *event) {
02657 updatearg_t *uarg = event->ev_arg;
02658 dns_clientupdateevent_t *uev = (dns_clientupdateevent_t *)event;
02659
02660 UNUSED(task);
02661
02662 LOCK(&uarg->lock);
02663
02664 uarg->result = uev->result;
02665
02666 dns_client_destroyupdatetrans(&uarg->trans);
02667 isc_event_free(&event);
02668
02669 if (!uarg->canceled) {
02670 UNLOCK(&uarg->lock);
02671
02672
02673 isc_app_ctxsuspend(uarg->actx);
02674 } else {
02675
02676
02677
02678
02679 UNLOCK(&uarg->lock);
02680 DESTROYLOCK(&uarg->lock);
02681 isc_mem_put(uarg->client->mctx, uarg, sizeof(*uarg));
02682 }
02683 }
02684
02685 isc_result_t
02686 dns_client_update(dns_client_t *client, dns_rdataclass_t rdclass,
02687 dns_name_t *zonename, dns_namelist_t *prerequisites,
02688 dns_namelist_t *updates, isc_sockaddrlist_t *servers,
02689 dns_tsec_t *tsec, unsigned int options)
02690 {
02691 isc_result_t result;
02692 isc_appctx_t *actx;
02693 updatearg_t *uarg;
02694
02695 REQUIRE(DNS_CLIENT_VALID(client));
02696
02697 if ((client->attributes & DNS_CLIENTATTR_OWNCTX) == 0 &&
02698 (options & DNS_CLIENTUPDOPT_ALLOWRUN) == 0) {
02699
02700
02701
02702
02703
02704 return (ISC_R_NOTIMPLEMENTED);
02705 } else
02706 actx = client->actx;
02707
02708 uarg = isc_mem_get(client->mctx, sizeof(*uarg));
02709 if (uarg == NULL)
02710 return (ISC_R_NOMEMORY);
02711
02712 result = isc_mutex_init(&uarg->lock);
02713 if (result != ISC_R_SUCCESS) {
02714 isc_mem_put(client->mctx, uarg, sizeof(*uarg));
02715 return (result);
02716 }
02717
02718 uarg->actx = actx;
02719 uarg->client = client;
02720 uarg->result = ISC_R_FAILURE;
02721 uarg->trans = NULL;
02722 uarg->canceled = ISC_FALSE;
02723
02724 result = dns_client_startupdate(client, rdclass, zonename,
02725 prerequisites, updates, servers,
02726 tsec, options, client->task,
02727 internal_update_callback, uarg,
02728 &uarg->trans);
02729 if (result != ISC_R_SUCCESS) {
02730 DESTROYLOCK(&uarg->lock);
02731 isc_mem_put(client->mctx, uarg, sizeof(*uarg));
02732 return (result);
02733 }
02734
02735
02736
02737
02738
02739 result = isc_app_ctxrun(actx);
02740
02741 LOCK(&uarg->lock);
02742 if (result == ISC_R_SUCCESS || result == ISC_R_SUSPEND)
02743 result = uarg->result;
02744
02745 if (uarg->trans != NULL) {
02746
02747
02748
02749
02750 uarg->canceled = ISC_TRUE;
02751 dns_client_cancelupdate(uarg->trans);
02752
02753 UNLOCK(&uarg->lock);
02754
02755
02756 } else {
02757 UNLOCK(&uarg->lock);
02758
02759 DESTROYLOCK(&uarg->lock);
02760 isc_mem_put(client->mctx, uarg, sizeof(*uarg));
02761 }
02762
02763 return (result);
02764 }
02765
02766 isc_result_t
02767 dns_client_startupdate(dns_client_t *client, dns_rdataclass_t rdclass,
02768 dns_name_t *zonename, dns_namelist_t *prerequisites,
02769 dns_namelist_t *updates, isc_sockaddrlist_t *servers,
02770 dns_tsec_t *tsec, unsigned int options,
02771 isc_task_t *task, isc_taskaction_t action, void *arg,
02772 dns_clientupdatetrans_t **transp)
02773 {
02774 dns_view_t *view = NULL;
02775 isc_result_t result;
02776 dns_name_t *name, *newname;
02777 updatectx_t *uctx;
02778 isc_task_t *clone = NULL;
02779 dns_section_t section = DNS_SECTION_UPDATE;
02780 isc_sockaddr_t *server, *sa = NULL;
02781 dns_tsectype_t tsectype = dns_tsectype_none;
02782 isc_boolean_t want_tcp;
02783 unsigned int resoptions;
02784
02785 UNUSED(options);
02786
02787 REQUIRE(DNS_CLIENT_VALID(client));
02788 REQUIRE(transp != NULL && *transp == NULL);
02789 REQUIRE(updates != NULL);
02790 REQUIRE(task != NULL);
02791
02792 if (tsec != NULL) {
02793 tsectype = dns_tsec_gettype(tsec);
02794 if (tsectype != dns_tsectype_tsig)
02795 return (ISC_R_NOTIMPLEMENTED);
02796 }
02797
02798 LOCK(&client->lock);
02799 result = dns_viewlist_find(&client->viewlist, DNS_CLIENTVIEW_NAME,
02800 rdclass, &view);
02801 UNLOCK(&client->lock);
02802 if (result != ISC_R_SUCCESS)
02803 return (result);
02804 want_tcp = ISC_TF((options & DNS_CLIENTUPDOPT_TCP) != 0);
02805
02806
02807 uctx = isc_mem_get(client->mctx, sizeof(*uctx));
02808 if (uctx == NULL) {
02809 dns_view_detach(&view);
02810 return (ISC_R_NOMEMORY);
02811 }
02812 result = isc_mutex_init(&uctx->lock);
02813 if (result != ISC_R_SUCCESS) {
02814 dns_view_detach(&view);
02815 isc_mem_put(client->mctx, uctx, sizeof(*uctx));
02816 return (ISC_R_NOMEMORY);
02817 }
02818 clone = NULL;
02819 isc_task_attach(task, &clone);
02820 uctx->client = client;
02821 ISC_LINK_INIT(uctx, link);
02822 uctx->state = dns_clientupdatestate_prepare;
02823 uctx->view = view;
02824 uctx->rdclass = rdclass;
02825 uctx->canceled = ISC_FALSE;
02826 uctx->updatemsg = NULL;
02827 uctx->soaquery = NULL;
02828 uctx->updatereq = NULL;
02829 uctx->restrans = NULL;
02830 uctx->restrans2 = NULL;
02831 uctx->bp4 = NULL;
02832 uctx->bp6 = NULL;
02833 uctx->soareq = NULL;
02834 uctx->event = NULL;
02835 uctx->tsigkey = NULL;
02836 uctx->sig0key = NULL;
02837 uctx->zonename = NULL;
02838 uctx->want_tcp = want_tcp;
02839 dns_name_init(&uctx->soaqname, NULL);
02840 ISC_LIST_INIT(uctx->servers);
02841 uctx->nservers = 0;
02842 uctx->currentserver = NULL;
02843 dns_fixedname_init(&uctx->zonefname);
02844 if (tsec != NULL)
02845 dns_tsec_getkey(tsec, &uctx->tsigkey);
02846 uctx->event = (dns_clientupdateevent_t *)
02847 isc_event_allocate(client->mctx, clone, DNS_EVENT_UPDATEDONE,
02848 action, arg, sizeof(*uctx->event));
02849 if (uctx->event == NULL)
02850 goto fail;
02851 if (zonename != NULL) {
02852 uctx->zonename = dns_fixedname_name(&uctx->zonefname);
02853 result = dns_name_copy(zonename, uctx->zonename, NULL);
02854 }
02855 if (servers != NULL) {
02856 for (server = ISC_LIST_HEAD(*servers);
02857 server != NULL;
02858 server = ISC_LIST_NEXT(server, link)) {
02859 sa = isc_mem_get(client->mctx, sizeof(*sa));
02860 if (sa == NULL)
02861 goto fail;
02862 sa->type = server->type;
02863 sa->length = server->length;
02864 ISC_LINK_INIT(sa, link);
02865 ISC_LIST_APPEND(uctx->servers, sa, link);
02866 if (uctx->currentserver == NULL)
02867 uctx->currentserver = sa;
02868 uctx->nservers++;
02869 }
02870 }
02871
02872
02873 result = dns_message_create(client->mctx, DNS_MESSAGE_INTENTRENDER,
02874 &uctx->updatemsg);
02875 if (result != ISC_R_SUCCESS)
02876 goto fail;
02877 uctx->updatemsg->opcode = dns_opcode_update;
02878
02879 if (prerequisites != NULL) {
02880 for (name = ISC_LIST_HEAD(*prerequisites); name != NULL;
02881 name = ISC_LIST_NEXT(name, link)) {
02882 newname = NULL;
02883 result = copy_name(client->mctx, uctx->updatemsg,
02884 name, &newname);
02885 if (result != ISC_R_SUCCESS)
02886 goto fail;
02887 dns_message_addname(uctx->updatemsg, newname,
02888 DNS_SECTION_PREREQUISITE);
02889 }
02890 }
02891
02892 for (name = ISC_LIST_HEAD(*updates); name != NULL;
02893 name = ISC_LIST_NEXT(name, link)) {
02894 newname = NULL;
02895 result = copy_name(client->mctx, uctx->updatemsg, name,
02896 &newname);
02897 if (result != ISC_R_SUCCESS)
02898 goto fail;
02899 dns_message_addname(uctx->updatemsg, newname,
02900 DNS_SECTION_UPDATE);
02901 }
02902
02903 uctx->firstname = NULL;
02904 result = dns_message_firstname(uctx->updatemsg, section);
02905 if (result == ISC_R_NOMORE) {
02906 section = DNS_SECTION_PREREQUISITE;
02907 result = dns_message_firstname(uctx->updatemsg, section);
02908 }
02909 if (result != ISC_R_SUCCESS)
02910 goto fail;
02911 dns_message_currentname(uctx->updatemsg, section, &uctx->firstname);
02912
02913 uctx->magic = UCTX_MAGIC;
02914
02915 LOCK(&client->lock);
02916 ISC_LIST_APPEND(client->updatectxs, uctx, link);
02917 UNLOCK(&client->lock);
02918
02919 if (uctx->zonename != NULL && uctx->currentserver != NULL) {
02920 result = send_update(uctx);
02921 if (result != ISC_R_SUCCESS)
02922 goto fail;
02923 } else if (uctx->currentserver != NULL) {
02924 result = request_soa(uctx);
02925 if (result != ISC_R_SUCCESS)
02926 goto fail;
02927 } else {
02928 resoptions = 0;
02929 if (want_tcp)
02930 resoptions |= DNS_CLIENTRESOPT_TCP;
02931 dns_name_clone(uctx->firstname, &uctx->soaqname);
02932 result = dns_client_startresolve(uctx->client, &uctx->soaqname,
02933 uctx->rdclass,
02934 dns_rdatatype_soa, resoptions,
02935 client->task, resolvesoa_done,
02936 uctx, &uctx->restrans);
02937 if (result != ISC_R_SUCCESS)
02938 goto fail;
02939 }
02940
02941 *transp = (dns_clientupdatetrans_t *)uctx;
02942
02943 return (ISC_R_SUCCESS);
02944
02945 fail:
02946 if (ISC_LINK_LINKED(uctx, link)) {
02947 LOCK(&client->lock);
02948 ISC_LIST_UNLINK(client->updatectxs, uctx, link);
02949 UNLOCK(&client->lock);
02950 }
02951 if (uctx->updatemsg != NULL)
02952 dns_message_destroy(&uctx->updatemsg);
02953 while ((sa = ISC_LIST_HEAD(uctx->servers)) != NULL) {
02954 ISC_LIST_UNLINK(uctx->servers, sa, link);
02955 isc_mem_put(client->mctx, sa, sizeof(*sa));
02956 }
02957 if (uctx->event != NULL)
02958 isc_event_free(ISC_EVENT_PTR(&uctx->event));
02959 if (uctx->tsigkey != NULL)
02960 dns_tsigkey_detach(&uctx->tsigkey);
02961 isc_task_detach(&clone);
02962 DESTROYLOCK(&uctx->lock);
02963 uctx->magic = 0;
02964 isc_mem_put(client->mctx, uctx, sizeof(*uctx));
02965 dns_view_detach(&view);
02966
02967 return (result);
02968 }
02969
02970 void
02971 dns_client_cancelupdate(dns_clientupdatetrans_t *trans) {
02972 updatectx_t *uctx;
02973
02974 REQUIRE(trans != NULL);
02975 uctx = (updatectx_t *)trans;
02976 REQUIRE(UCTX_VALID(uctx));
02977
02978 LOCK(&uctx->lock);
02979
02980 if (!uctx->canceled) {
02981 uctx->canceled = ISC_TRUE;
02982 if (uctx->updatereq != NULL)
02983 dns_request_cancel(uctx->updatereq);
02984 if (uctx->soareq != NULL)
02985 dns_request_cancel(uctx->soareq);
02986 if (uctx->restrans != NULL)
02987 dns_client_cancelresolve(uctx->restrans);
02988 if (uctx->restrans2 != NULL)
02989 dns_client_cancelresolve(uctx->restrans2);
02990 }
02991
02992 UNLOCK(&uctx->lock);
02993 }
02994
02995 void
02996 dns_client_destroyupdatetrans(dns_clientupdatetrans_t **transp) {
02997 updatectx_t *uctx;
02998 isc_mem_t *mctx;
02999 dns_client_t *client;
03000 isc_boolean_t need_destroyclient = ISC_FALSE;
03001 isc_sockaddr_t *sa;
03002
03003 REQUIRE(transp != NULL);
03004 uctx = (updatectx_t *)*transp;
03005 REQUIRE(UCTX_VALID(uctx));
03006 client = uctx->client;
03007 REQUIRE(DNS_CLIENT_VALID(client));
03008 REQUIRE(uctx->updatereq == NULL && uctx->updatemsg == NULL &&
03009 uctx->soareq == NULL && uctx->soaquery == NULL &&
03010 uctx->event == NULL && uctx->tsigkey == NULL &&
03011 uctx->sig0key == NULL);
03012
03013 mctx = client->mctx;
03014 dns_view_detach(&uctx->view);
03015 while ((sa = ISC_LIST_HEAD(uctx->servers)) != NULL) {
03016 ISC_LIST_UNLINK(uctx->servers, sa, link);
03017 isc_mem_put(mctx, sa, sizeof(*sa));
03018 }
03019
03020 LOCK(&client->lock);
03021
03022 INSIST(ISC_LINK_LINKED(uctx, link));
03023 ISC_LIST_UNLINK(client->updatectxs, uctx, link);
03024
03025 if (client->references == 0 && ISC_LIST_EMPTY(client->resctxs) &&
03026 ISC_LIST_EMPTY(client->reqctxs) &&
03027 ISC_LIST_EMPTY(client->updatectxs))
03028 need_destroyclient = ISC_TRUE;
03029
03030 UNLOCK(&client->lock);
03031
03032 DESTROYLOCK(&uctx->lock);
03033 uctx->magic = 0;
03034
03035 isc_mem_put(mctx, uctx, sizeof(*uctx));
03036
03037 if (need_destroyclient)
03038 destroyclient(&client);
03039
03040 *transp = NULL;
03041 }
03042
03043 isc_mem_t *
03044 dns_client_mctx(dns_client_t *client) {
03045
03046 REQUIRE(DNS_CLIENT_VALID(client));
03047 return (client->mctx);
03048 }
03049
03050 typedef struct {
03051 isc_buffer_t buffer;
03052 dns_rdataset_t rdataset;
03053 dns_rdatalist_t rdatalist;
03054 dns_rdata_t rdata;
03055 size_t size;
03056 isc_mem_t * mctx;
03057 unsigned char data[FLEXIBLE_ARRAY_MEMBER];
03058 } dns_client_updaterec_t;
03059
03060 isc_result_t
03061 dns_client_updaterec(dns_client_updateop_t op, dns_name_t *owner,
03062 dns_rdatatype_t type, dns_rdata_t *source,
03063 dns_ttl_t ttl, dns_name_t *target,
03064 dns_rdataset_t *rdataset, dns_rdatalist_t *rdatalist,
03065 dns_rdata_t *rdata, isc_mem_t *mctx)
03066 {
03067 dns_client_updaterec_t *updaterec = NULL;
03068 size_t size = offsetof(dns_client_updaterec_t, data);
03069
03070 REQUIRE(op < updateop_max);
03071 REQUIRE(owner != NULL);
03072 REQUIRE((rdataset != NULL && rdatalist != NULL && rdata != NULL) ||
03073 (rdataset == NULL && rdatalist == NULL && rdata == NULL &&
03074 mctx != NULL));
03075 if (op == updateop_add)
03076 REQUIRE(source != NULL);
03077 if (source != NULL) {
03078 REQUIRE(source->type == type);
03079 REQUIRE(op == updateop_add || op == updateop_delete ||
03080 op == updateop_exist);
03081 }
03082
03083 size += owner->length;
03084 if (source != NULL)
03085 size += source->length;
03086
03087 if (rdataset == NULL) {
03088 updaterec = isc_mem_get(mctx, size);
03089 if (updaterec == NULL)
03090 return (ISC_R_NOMEMORY);
03091 rdataset = &updaterec->rdataset;
03092 rdatalist = &updaterec->rdatalist;
03093 rdata = &updaterec->rdata;
03094 dns_rdataset_init(rdataset);
03095 dns_rdatalist_init(&updaterec->rdatalist);
03096 dns_rdata_init(&updaterec->rdata);
03097 isc_buffer_init(&updaterec->buffer, updaterec->data,
03098 (unsigned int)
03099 (size -
03100 offsetof(dns_client_updaterec_t, data)));
03101 dns_name_copy(owner, target, &updaterec->buffer);
03102 if (source != NULL) {
03103 isc_region_t r;
03104 dns_rdata_clone(source, rdata);
03105 dns_rdata_toregion(rdata, &r);
03106 rdata->data = isc_buffer_used(&updaterec->buffer);
03107 isc_buffer_copyregion(&updaterec->buffer, &r);
03108 }
03109 updaterec->mctx = NULL;
03110 isc_mem_attach(mctx, &updaterec->mctx);
03111 } else if (source != NULL)
03112 dns_rdata_clone(source, rdata);
03113
03114 switch (op) {
03115 case updateop_add:
03116 break;
03117 case updateop_delete:
03118 if (source != NULL) {
03119 ttl = 0;
03120 dns_rdata_makedelete(rdata);
03121 } else
03122 dns_rdata_deleterrset(rdata, type);
03123 break;
03124 case updateop_notexist:
03125 dns_rdata_notexist(rdata, type);
03126 break;
03127 case updateop_exist:
03128 if (source == NULL) {
03129 ttl = 0;
03130 dns_rdata_exists(rdata, type);
03131 }
03132 case updateop_none:
03133 break;
03134 default:
03135 INSIST(0);
03136 }
03137
03138 rdatalist->type = rdata->type;
03139 rdatalist->rdclass = rdata->rdclass;
03140 if (source != NULL) {
03141 rdatalist->covers = dns_rdata_covers(rdata);
03142 rdatalist->ttl = ttl;
03143 }
03144 ISC_LIST_APPEND(rdatalist->rdata, rdata, link);
03145 dns_rdatalist_tordataset(rdatalist, rdataset);
03146 ISC_LIST_APPEND(target->list, rdataset, link);
03147 if (updaterec != NULL) {
03148 target->attributes |= DNS_NAMEATTR_HASUPDATEREC;
03149 dns_name_setbuffer(target, &updaterec->buffer);
03150 }
03151 if (op == updateop_add || op == updateop_delete)
03152 target->attributes |= DNS_NAMEATTR_UPDATE;
03153 else
03154 target->attributes |= DNS_NAMEATTR_PREREQUISITE;
03155 return (ISC_R_SUCCESS);
03156 }
03157
03158 void
03159 dns_client_freeupdate(dns_name_t **namep) {
03160 dns_client_updaterec_t *updaterec;
03161 dns_rdatalist_t *rdatalist;
03162 dns_rdataset_t *rdataset;
03163 dns_rdata_t *rdata;
03164 dns_name_t *name;
03165
03166 REQUIRE(namep != NULL && *namep != NULL);
03167
03168 name = *namep;
03169 for (rdataset = ISC_LIST_HEAD(name->list);
03170 rdataset != NULL;
03171 rdataset = ISC_LIST_HEAD(name->list)) {
03172 ISC_LIST_UNLINK(name->list, rdataset, link);
03173 rdatalist = NULL;
03174 dns_rdatalist_fromrdataset(rdataset, &rdatalist);
03175 if (rdatalist == NULL) {
03176 dns_rdataset_disassociate(rdataset);
03177 continue;
03178 }
03179 for (rdata = ISC_LIST_HEAD(rdatalist->rdata);
03180 rdata != NULL;
03181 rdata = ISC_LIST_HEAD(rdatalist->rdata))
03182 ISC_LIST_UNLINK(rdatalist->rdata, rdata, link);
03183 dns_rdataset_disassociate(rdataset);
03184 }
03185
03186 if ((name->attributes & DNS_NAMEATTR_HASUPDATEREC) != 0) {
03187 updaterec = (dns_client_updaterec_t *)name->buffer;
03188 INSIST(updaterec != NULL);
03189 isc_mem_putanddetach(&updaterec->mctx, updaterec,
03190 updaterec->size);
03191 *namep = NULL;
03192 }
03193 }