00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include <config.h>
00023
00024 #include <stdlib.h>
00025
00026 #include <isc/netaddr.h>
00027 #include <isc/sockaddr.h>
00028 #include <isc/socket.h>
00029 #include <isc/string.h>
00030 #include <isc/util.h>
00031
00032 #include <dns/adb.h>
00033 #include <dns/events.h>
00034 #include <dns/result.h>
00035
00036 #include <named/types.h>
00037 #include <named/lwaddr.h>
00038 #include <named/lwdclient.h>
00039 #include <named/lwresd.h>
00040 #include <named/lwsearch.h>
00041 #include <named/sortlist.h>
00042
00043 #define NEED_V4(c) ((((c)->find_wanted & LWRES_ADDRTYPE_V4) != 0) \
00044 && ((c)->v4find == NULL))
00045 #define NEED_V6(c) ((((c)->find_wanted & LWRES_ADDRTYPE_V6) != 0) \
00046 && ((c)->v6find == NULL))
00047
00048 static isc_result_t start_find(ns_lwdclient_t *);
00049 static void restart_find(ns_lwdclient_t *);
00050 static void init_gabn(ns_lwdclient_t *);
00051
00052
00053
00054
00055
00056 static void
00057 cleanup_gabn(ns_lwdclient_t *client) {
00058 ns_lwdclient_log(50, "cleaning up client %p", client);
00059
00060 if (client->v6find != NULL) {
00061 if (client->v6find == client->v4find)
00062 client->v6find = NULL;
00063 else
00064 dns_adb_destroyfind(&client->v6find);
00065 }
00066 if (client->v4find != NULL)
00067 dns_adb_destroyfind(&client->v4find);
00068 }
00069
00070 static void
00071 setup_addresses(ns_lwdclient_t *client, dns_adbfind_t *find, unsigned int at) {
00072 dns_adbaddrinfo_t *ai;
00073 lwres_addr_t *addr;
00074 int af;
00075 const struct sockaddr *sa;
00076 isc_result_t result;
00077
00078 if (at == DNS_ADBFIND_INET)
00079 af = AF_INET;
00080 else
00081 af = AF_INET6;
00082
00083 ai = ISC_LIST_HEAD(find->list);
00084 while (ai != NULL && client->gabn.naddrs < LWRES_MAX_ADDRS) {
00085 sa = &ai->sockaddr.type.sa;
00086 if (sa->sa_family != af)
00087 goto next;
00088
00089 addr = &client->addrs[client->gabn.naddrs];
00090
00091 result = lwaddr_lwresaddr_fromsockaddr(addr, &ai->sockaddr);
00092 if (result != ISC_R_SUCCESS)
00093 goto next;
00094
00095 ns_lwdclient_log(50, "adding address %p, family %d, length %d",
00096 addr->address, addr->family, addr->length);
00097
00098 client->gabn.naddrs++;
00099 REQUIRE(!LWRES_LINK_LINKED(addr, link));
00100 LWRES_LIST_APPEND(client->gabn.addrs, addr, link);
00101
00102 next:
00103 ai = ISC_LIST_NEXT(ai, publink);
00104 }
00105 }
00106
00107 typedef struct {
00108 isc_netaddr_t address;
00109 int rank;
00110 } rankedaddress;
00111
00112 static int
00113 addr_compare(const void *av, const void *bv) {
00114 const rankedaddress *a = (const rankedaddress *) av;
00115 const rankedaddress *b = (const rankedaddress *) bv;
00116 return (a->rank - b->rank);
00117 }
00118
00119 static void
00120 sort_addresses(ns_lwdclient_t *client) {
00121 unsigned int naddrs;
00122 rankedaddress *addrs;
00123 isc_netaddr_t remote;
00124 dns_addressorderfunc_t order;
00125 const void *arg;
00126 ns_lwresd_t *lwresd = client->clientmgr->listener->manager;
00127 unsigned int i;
00128 isc_result_t result;
00129
00130 naddrs = client->gabn.naddrs;
00131
00132 if (naddrs <= 1 || lwresd->view->sortlist == NULL)
00133 return;
00134
00135 addrs = isc_mem_get(lwresd->mctx, sizeof(rankedaddress) * naddrs);
00136 if (addrs == NULL)
00137 return;
00138
00139 isc_netaddr_fromsockaddr(&remote, &client->address);
00140 ns_sortlist_byaddrsetup(lwresd->view->sortlist,
00141 &remote, &order, &arg);
00142 if (order == NULL) {
00143 isc_mem_put(lwresd->mctx, addrs,
00144 sizeof(rankedaddress) * naddrs);
00145 return;
00146 }
00147 for (i = 0; i < naddrs; i++) {
00148 result = lwaddr_netaddr_fromlwresaddr(&addrs[i].address,
00149 &client->addrs[i]);
00150 INSIST(result == ISC_R_SUCCESS);
00151 addrs[i].rank = (*order)(&addrs[i].address, arg);
00152 }
00153 qsort(addrs, naddrs, sizeof(rankedaddress), addr_compare);
00154 for (i = 0; i < naddrs; i++) {
00155 result = lwaddr_lwresaddr_fromnetaddr(&client->addrs[i],
00156 &addrs[i].address);
00157 INSIST(result == ISC_R_SUCCESS);
00158 }
00159
00160 isc_mem_put(lwresd->mctx, addrs, sizeof(rankedaddress) * naddrs);
00161 }
00162
00163 static void
00164 generate_reply(ns_lwdclient_t *client) {
00165 isc_result_t result;
00166 int lwres;
00167 isc_region_t r;
00168 lwres_buffer_t lwb;
00169 ns_lwdclientmgr_t *cm;
00170
00171 cm = client->clientmgr;
00172 lwb.base = NULL;
00173
00174 ns_lwdclient_log(50, "generating gabn reply for client %p", client);
00175
00176
00177
00178
00179
00180
00181 if (client->find == client->v4find || client->find == client->v6find)
00182 client->find = NULL;
00183 else
00184 if (client->find != NULL)
00185 dns_adb_destroyfind(&client->find);
00186
00187
00188
00189
00190 if (NEED_V6(client) && client->v4find != NULL)
00191 client->v6find = client->v4find;
00192
00193
00194
00195
00196
00197 LWRES_LIST_INIT(client->gabn.addrs);
00198 if (client->v4find != NULL)
00199 setup_addresses(client, client->v4find, DNS_ADBFIND_INET);
00200 if (client->v6find != NULL)
00201 setup_addresses(client, client->v6find, DNS_ADBFIND_INET6);
00202
00203
00204
00205
00206
00207
00208 if (client->gabn.naddrs == 0) {
00209 do {
00210 result = ns_lwsearchctx_next(&client->searchctx);
00211 if (result == ISC_R_SUCCESS) {
00212 cleanup_gabn(client);
00213 result = start_find(client);
00214 if (result == ISC_R_SUCCESS)
00215 return;
00216 }
00217 } while (result == ISC_R_SUCCESS);
00218 }
00219
00220
00221
00222
00223 client->pkt.recvlength = LWRES_RECVLENGTH;
00224 client->pkt.authtype = 0;
00225 client->pkt.authlength = 0;
00226
00227
00228
00229
00230 if (client->gabn.naddrs != 0)
00231 client->pkt.result = LWRES_R_SUCCESS;
00232 else
00233 client->pkt.result = LWRES_R_NOTFOUND;
00234
00235 sort_addresses(client);
00236
00237 lwres = lwres_gabnresponse_render(cm->lwctx, &client->gabn,
00238 &client->pkt, &lwb);
00239 if (lwres != LWRES_R_SUCCESS)
00240 goto out;
00241
00242 r.base = lwb.base;
00243 r.length = lwb.used;
00244 client->sendbuf = r.base;
00245 client->sendlength = r.length;
00246 result = ns_lwdclient_sendreply(client, &r);
00247 if (result != ISC_R_SUCCESS)
00248 goto out;
00249
00250 NS_LWDCLIENT_SETSEND(client);
00251
00252
00253
00254
00255 cleanup_gabn(client);
00256
00257 return;
00258
00259 out:
00260 cleanup_gabn(client);
00261
00262 if (lwb.base != NULL)
00263 lwres_context_freemem(client->clientmgr->lwctx,
00264 lwb.base, lwb.length);
00265
00266 ns_lwdclient_errorpktsend(client, LWRES_R_FAILURE);
00267 }
00268
00269
00270
00271
00272
00273
00274
00275
00276 static isc_result_t
00277 add_alias(ns_lwdclient_t *client) {
00278 isc_buffer_t b;
00279 isc_result_t result;
00280 isc_uint16_t naliases;
00281
00282 b = client->recv_buffer;
00283
00284
00285
00286
00287 result = dns_name_totext(dns_fixedname_name(&client->target_name),
00288 ISC_TRUE, &client->recv_buffer);
00289 if (result != ISC_R_SUCCESS)
00290 return (result);
00291
00292
00293
00294
00295 naliases = client->gabn.naliases;
00296 if (naliases < LWRES_MAX_ALIASES) {
00297 client->gabn.aliases[naliases] = client->gabn.realname;
00298 client->gabn.aliaslen[naliases] = client->gabn.realnamelen;
00299 client->gabn.naliases++;
00300 }
00301
00302
00303
00304
00305 client->gabn.realname = (char *)(b.base) + b.used;
00306 client->gabn.realnamelen = client->recv_buffer.used - b.used;
00307
00308 return (ISC_R_SUCCESS);
00309 }
00310
00311 static isc_result_t
00312 store_realname(ns_lwdclient_t *client) {
00313 isc_buffer_t b;
00314 isc_result_t result;
00315 dns_name_t *tname;
00316
00317 b = client->recv_buffer;
00318
00319 tname = dns_fixedname_name(&client->target_name);
00320 result = ns_lwsearchctx_current(&client->searchctx, tname);
00321 if (result != ISC_R_SUCCESS)
00322 return (result);
00323
00324
00325
00326
00327 result = dns_name_totext(tname, ISC_TRUE, &client->recv_buffer);
00328 if (result != ISC_R_SUCCESS)
00329 return (result);
00330
00331
00332
00333
00334 client->gabn.realname = (char *) b.base + b.used;
00335 client->gabn.realnamelen = client->recv_buffer.used - b.used;
00336
00337 return (ISC_R_SUCCESS);
00338 }
00339
00340 static void
00341 process_gabn_finddone(isc_task_t *task, isc_event_t *ev) {
00342 ns_lwdclient_t *client = ev->ev_arg;
00343 isc_eventtype_t evtype;
00344 isc_boolean_t claimed;
00345
00346 ns_lwdclient_log(50, "find done for task %p, client %p", task, client);
00347
00348 evtype = ev->ev_type;
00349 isc_event_free(&ev);
00350
00351
00352
00353
00354
00355 claimed = ISC_FALSE;
00356 if (evtype == DNS_EVENT_ADBNOMOREADDRESSES) {
00357 if (NEED_V4(client)) {
00358 client->v4find = client->find;
00359 claimed = ISC_TRUE;
00360 }
00361 if (NEED_V6(client)) {
00362 client->v6find = client->find;
00363 claimed = ISC_TRUE;
00364 }
00365 if (client->find != NULL) {
00366 if (claimed)
00367 client->find = NULL;
00368 else
00369 dns_adb_destroyfind(&client->find);
00370
00371 }
00372 generate_reply(client);
00373 return;
00374 }
00375
00376
00377
00378
00379
00380
00381 if ((client->find != client->v4find)
00382 && (client->find != client->v6find)) {
00383 dns_adb_destroyfind(&client->find);
00384 } else {
00385 client->find = NULL;
00386 }
00387
00388
00389
00390
00391
00392 if (evtype == DNS_EVENT_ADBMOREADDRESSES) {
00393 restart_find(client);
00394 return;
00395 }
00396
00397
00398
00399
00400 cleanup_gabn(client);
00401 ns_lwdclient_errorpktsend(client, LWRES_R_FAILURE);
00402 }
00403
00404 static void
00405 restart_find(ns_lwdclient_t *client) {
00406 unsigned int options;
00407 isc_result_t result;
00408 isc_boolean_t claimed;
00409
00410 ns_lwdclient_log(50, "starting find for client %p", client);
00411
00412
00413
00414
00415
00416
00417 options = 0;
00418 options |= DNS_ADBFIND_WANTEVENT;
00419 options |= DNS_ADBFIND_RETURNLAME;
00420
00421
00422
00423
00424
00425
00426 if (NEED_V4(client))
00427 options |= DNS_ADBFIND_INET;
00428 if (NEED_V6(client))
00429 options |= DNS_ADBFIND_INET6;
00430
00431 find_again:
00432 INSIST(client->find == NULL);
00433 result = dns_adb_createfind(client->clientmgr->view->adb,
00434 client->clientmgr->task,
00435 process_gabn_finddone, client,
00436 dns_fixedname_name(&client->target_name),
00437 dns_rootname, 0, options, 0,
00438 dns_fixedname_name(&client->target_name),
00439 client->clientmgr->view->dstport,
00440 &client->find);
00441
00442
00443
00444
00445 if (result == DNS_R_ALIAS) {
00446 ns_lwdclient_log(50, "found alias, restarting query");
00447 dns_adb_destroyfind(&client->find);
00448 cleanup_gabn(client);
00449 result = add_alias(client);
00450 if (result != ISC_R_SUCCESS) {
00451 ns_lwdclient_log(50,
00452 "out of buffer space adding alias");
00453 ns_lwdclient_errorpktsend(client, LWRES_R_FAILURE);
00454 return;
00455 }
00456 goto find_again;
00457 }
00458
00459 ns_lwdclient_log(50, "find returned %d (%s)", result,
00460 isc_result_totext(result));
00461
00462
00463
00464
00465 if (result != ISC_R_SUCCESS) {
00466 if (client->find != NULL)
00467 dns_adb_destroyfind(&client->find);
00468 cleanup_gabn(client);
00469 ns_lwdclient_errorpktsend(client, LWRES_R_FAILURE);
00470 return;
00471 }
00472
00473 claimed = ISC_FALSE;
00474
00475
00476
00477
00478 if (NEED_V4(client)
00479 && ((client->find->query_pending & DNS_ADBFIND_INET) == 0)) {
00480 ns_lwdclient_log(50, "client %p ipv4 satisfied by find %p",
00481 client, client->find);
00482 claimed = ISC_TRUE;
00483 client->v4find = client->find;
00484 }
00485
00486
00487
00488
00489 if (NEED_V6(client)
00490 && ((client->find->query_pending & DNS_ADBFIND_INET6) == 0)) {
00491 ns_lwdclient_log(50, "client %p ipv6 satisfied by find %p",
00492 client, client->find);
00493 claimed = ISC_TRUE;
00494 client->v6find = client->find;
00495 }
00496
00497
00498
00499
00500
00501
00502
00503
00504
00505
00506 if ((client->find->options & DNS_ADBFIND_WANTEVENT) != 0) {
00507 ns_lwdclient_log(50, "event will be sent");
00508 INSIST(client->v4find == NULL || client->v6find == NULL);
00509 return;
00510 }
00511 ns_lwdclient_log(50, "no event will be sent");
00512 if (claimed)
00513 client->find = NULL;
00514 else
00515 dns_adb_destroyfind(&client->find);
00516
00517
00518
00519
00520
00521
00522 generate_reply(client);
00523 }
00524
00525 static isc_result_t
00526 start_find(ns_lwdclient_t *client) {
00527 isc_result_t result;
00528
00529
00530
00531
00532
00533 init_gabn(client);
00534
00535 result = store_realname(client);
00536 if (result != ISC_R_SUCCESS)
00537 return (result);
00538 restart_find(client);
00539 return (ISC_R_SUCCESS);
00540
00541 }
00542
00543 static void
00544 init_gabn(ns_lwdclient_t *client) {
00545 int i;
00546
00547
00548
00549
00550
00551 for (i = 0; i < LWRES_MAX_ALIASES; i++) {
00552 client->aliases[i] = NULL;
00553 client->aliaslen[i] = 0;
00554 }
00555 for (i = 0; i < LWRES_MAX_ADDRS; i++) {
00556 client->addrs[i].family = 0;
00557 client->addrs[i].length = 0;
00558 memset(client->addrs[i].address, 0, LWRES_ADDR_MAXLEN);
00559 LWRES_LINK_INIT(&client->addrs[i], link);
00560 }
00561
00562 client->gabn.naliases = 0;
00563 client->gabn.naddrs = 0;
00564 client->gabn.realname = NULL;
00565 client->gabn.aliases = client->aliases;
00566 client->gabn.realnamelen = 0;
00567 client->gabn.aliaslen = client->aliaslen;
00568 LWRES_LIST_INIT(client->gabn.addrs);
00569 client->gabn.base = NULL;
00570 client->gabn.baselen = 0;
00571
00572
00573
00574
00575 isc_buffer_init(&client->recv_buffer, client->buffer, LWRES_RECVLENGTH);
00576 }
00577
00578
00579
00580
00581
00582
00583
00584
00585
00586
00587
00588
00589
00590
00591
00592
00593
00594
00595
00596
00597 void
00598 ns_lwdclient_processgabn(ns_lwdclient_t *client, lwres_buffer_t *b) {
00599 isc_result_t result;
00600 lwres_gabnrequest_t *req;
00601 ns_lwdclientmgr_t *cm;
00602 isc_buffer_t namebuf;
00603
00604 REQUIRE(NS_LWDCLIENT_ISRECVDONE(client));
00605
00606 cm = client->clientmgr;
00607 req = NULL;
00608
00609 result = lwres_gabnrequest_parse(client->clientmgr->lwctx,
00610 b, &client->pkt, &req);
00611 if (result != LWRES_R_SUCCESS)
00612 goto out;
00613 if (req->name == NULL)
00614 goto out;
00615
00616 isc_buffer_init(&namebuf, req->name, req->namelen);
00617 isc_buffer_add(&namebuf, req->namelen);
00618
00619 dns_fixedname_init(&client->target_name);
00620 dns_fixedname_init(&client->query_name);
00621 result = dns_name_fromtext(dns_fixedname_name(&client->query_name),
00622 &namebuf, NULL, 0, NULL);
00623 if (result != ISC_R_SUCCESS)
00624 goto out;
00625 ns_lwsearchctx_init(&client->searchctx,
00626 cm->listener->manager->search,
00627 dns_fixedname_name(&client->query_name),
00628 cm->listener->manager->ndots);
00629 ns_lwsearchctx_first(&client->searchctx);
00630
00631 client->find_wanted = req->addrtypes;
00632 ns_lwdclient_log(50, "client %p looking for addrtypes %08x",
00633 client, client->find_wanted);
00634
00635
00636
00637
00638 lwres_gabnrequest_free(client->clientmgr->lwctx, &req);
00639
00640
00641
00642
00643 result = start_find(client);
00644 if (result != ISC_R_SUCCESS)
00645 goto out;
00646
00647 return;
00648
00649
00650
00651
00652 out:
00653 if (req != NULL)
00654 lwres_gabnrequest_free(client->clientmgr->lwctx, &req);
00655
00656 ns_lwdclient_errorpktsend(client, LWRES_R_FAILURE);
00657 }