/*% * Destroy any finds. This can be used to "start over from scratch" and * should only be called when events are _not_ being generated by the finds. */ static void cleanup_gabn(ns_lwdclient_t *client) { ns_lwdclient_log(50, "cleaning up client %p", client); if (client->v6find != NULL) { if (client->v6find == client->v4find) client->v6find = NULL; else dns_adb_destroyfind(&client->v6find); } if (client->v4find != NULL) dns_adb_destroyfind(&client->v4find); }
static void lookup_callback(isc_task_t *task, isc_event_t *ev) { client_t *client; client = ev->ev_arg; INSIST(client->find == ev->ev_sender); printf("NAME %s:\n\tTask %p got event %p type %08x from %p, client %p\n\terr4: %s err6: %s\n", client->target, task, ev, ev->ev_type, client->find, client, isc_result_totext(client->find->result_v4), isc_result_totext(client->find->result_v6)); isc_event_free(&ev); ev = NULL; CLOCK(); dns_adb_dumpfind(client->find, stderr); dns_adb_destroyfind(&client->find); ISC_LIST_UNLINK(clients, client, link); free_client(&client); CUNLOCK(); }
static void do_find(isc_boolean_t want_event) { isc_result_t result; isc_boolean_t done = ISC_FALSE; unsigned int options; options = DNS_ADBFIND_INET | DNS_ADBFIND_INET6; if (want_event) options |= DNS_ADBFIND_WANTEVENT | DNS_ADBFIND_EMPTYEVENT; dns_fixedname_init(&target); result = dns_adb_createfind(view->adb, task, adb_callback, NULL, dns_fixedname_name(&fixed), dns_rootname, 0, options, 0, dns_fixedname_name(&target), 0, &find); if (result == ISC_R_SUCCESS) { if (!ISC_LIST_EMPTY(find->list)) { /* * We have at least some of the addresses for the * name. */ INSIST((find->options & DNS_ADBFIND_WANTEVENT) == 0); print_addresses(find); done = ISC_TRUE; } else { /* * We don't know any of the addresses for this * name. */ if ((find->options & DNS_ADBFIND_WANTEVENT) == 0) { /* * And ADB isn't going to send us any events * either. This query loses. */ done = ISC_TRUE; } /* * If the DNS_ADBFIND_WANTEVENT flag was set, we'll * get an event when something happens. */ } } else if (result == DNS_R_ALIAS) { print_name(dns_fixedname_name(&target)); done = ISC_TRUE; } else { printf("dns_adb_createfind() returned %s\n", isc_result_totext(result)); done = ISC_TRUE; } if (done) { if (find != NULL) dns_adb_destroyfind(&find); isc_app_shutdown(); } }
static void lookup(const char *target) { dns_name_t name; unsigned char namedata[256]; client_t *client; isc_buffer_t t, namebuf; isc_result_t result; unsigned int options; INSIST(target != NULL); client = new_client(); isc_buffer_init(&t, target, strlen(target)); isc_buffer_add(&t, strlen(target)); isc_buffer_init(&namebuf, namedata, sizeof(namedata)); dns_name_init(&name, NULL); result = dns_name_fromtext(&name, &t, dns_rootname, ISC_FALSE, &namebuf); check_result(result, "dns_name_fromtext %s", target); result = dns_name_dup(&name, mctx, &client->name); check_result(result, "dns_name_dup %s", target); options = 0; options |= DNS_ADBFIND_INET; options |= DNS_ADBFIND_INET6; options |= DNS_ADBFIND_WANTEVENT; options |= DNS_ADBFIND_HINTOK; options |= DNS_ADBFIND_GLUEOK; result = dns_adb_createfind(adb, t2, lookup_callback, client, &client->name, dns_rootname, options, now, NULL, view->dstport, &client->find); #if 0 check_result(result, "dns_adb_createfind()"); #endif dns_adb_dumpfind(client->find, stderr); if ((client->find->options & DNS_ADBFIND_WANTEVENT) != 0) { client->target = target; ISC_LIST_APPEND(clients, client, link); } else { printf("NAME %s: err4 %s, err6 %s\n", target, isc_result_totext(client->find->result_v4), isc_result_totext(client->find->result_v6)); dns_adb_destroyfind(&client->find); free_client(&client); } }
static void adb_callback(isc_task_t *etask, isc_event_t *event) { unsigned int type = event->ev_type; REQUIRE(etask == task); isc_event_free(&event); dns_adb_destroyfind(&find); if (type == DNS_EVENT_ADBMOREADDRESSES) do_find(ISC_FALSE); else if (type == DNS_EVENT_ADBNOMOREADDRESSES) { printf("no more addresses\n"); isc_app_shutdown(); } else { printf("unexpected ADB event type %u\n", type); isc_app_shutdown(); } }
static void restart_find(ns_lwdclient_t *client) { unsigned int options; isc_result_t result; isc_boolean_t claimed; ns_lwdclient_log(50, "starting find for client %p", client); /* * Issue a find for the name contained in the request. We won't * set the bit that says "anything is good enough" -- we want it * all. */ options = 0; options |= DNS_ADBFIND_WANTEVENT; options |= DNS_ADBFIND_RETURNLAME; /* * Set the bits up here to mark that we want this address family * and that we do not currently have a find pending. We will * set that bit again below if it turns out we will get an event. */ if (NEED_V4(client)) options |= DNS_ADBFIND_INET; if (NEED_V6(client)) options |= DNS_ADBFIND_INET6; find_again: INSIST(client->find == NULL); result = dns_adb_createfind(client->clientmgr->view->adb, client->clientmgr->task, process_gabn_finddone, client, dns_fixedname_name(&client->target_name), dns_rootname, 0, options, 0, dns_fixedname_name(&client->target_name), client->clientmgr->view->dstport, &client->find); /* * Did we get an alias? If so, save it and re-issue the query. */ if (result == DNS_R_ALIAS) { ns_lwdclient_log(50, "found alias, restarting query"); dns_adb_destroyfind(&client->find); cleanup_gabn(client); result = add_alias(client); if (result != ISC_R_SUCCESS) { ns_lwdclient_log(50, "out of buffer space adding alias"); ns_lwdclient_errorpktsend(client, LWRES_R_FAILURE); return; } goto find_again; } ns_lwdclient_log(50, "find returned %d (%s)", result, isc_result_totext(result)); /* * Did we get an error? */ if (result != ISC_R_SUCCESS) { if (client->find != NULL) dns_adb_destroyfind(&client->find); cleanup_gabn(client); ns_lwdclient_errorpktsend(client, LWRES_R_FAILURE); return; } claimed = ISC_FALSE; /* * Did we get our answer to V4 addresses? */ if (NEED_V4(client) && ((client->find->query_pending & DNS_ADBFIND_INET) == 0)) { ns_lwdclient_log(50, "client %p ipv4 satisfied by find %p", client, client->find); claimed = ISC_TRUE; client->v4find = client->find; } /* * Did we get our answer to V6 addresses? */ if (NEED_V6(client) && ((client->find->query_pending & DNS_ADBFIND_INET6) == 0)) { ns_lwdclient_log(50, "client %p ipv6 satisfied by find %p", client, client->find); claimed = ISC_TRUE; client->v6find = client->find; } /* * If we're going to get an event, set our internal pending flag * and return. When we get an event back we'll do the right * thing, basically by calling this function again, perhaps with a * new target name. * * If we have both v4 and v6, and we are still getting an event, * we have a programming error, so die hard. */ if ((client->find->options & DNS_ADBFIND_WANTEVENT) != 0) { ns_lwdclient_log(50, "event will be sent"); INSIST(client->v4find == NULL || client->v6find == NULL); return; } ns_lwdclient_log(50, "no event will be sent"); if (claimed) client->find = NULL; else dns_adb_destroyfind(&client->find); /* * We seem to have everything we asked for, or at least we are * able to respond with things we've learned. */ generate_reply(client); }
static void process_gabn_finddone(isc_task_t *task, isc_event_t *ev) { ns_lwdclient_t *client = ev->ev_arg; isc_eventtype_t evtype; isc_boolean_t claimed; ns_lwdclient_log(50, "find done for task %p, client %p", task, client); evtype = ev->ev_type; isc_event_free(&ev); /* * No more info to be had? If so, we have all the good stuff * right now, so we can render things. */ claimed = ISC_FALSE; if (evtype == DNS_EVENT_ADBNOMOREADDRESSES) { if (NEED_V4(client)) { client->v4find = client->find; claimed = ISC_TRUE; } if (NEED_V6(client)) { client->v6find = client->find; claimed = ISC_TRUE; } if (client->find != NULL) { if (claimed) client->find = NULL; else dns_adb_destroyfind(&client->find); } generate_reply(client); return; } /* * We probably don't need this find anymore. We're either going to * reissue it, or an error occurred. Either way, we're done with * it. */ if ((client->find != client->v4find) && (client->find != client->v6find)) { dns_adb_destroyfind(&client->find); } else { client->find = NULL; } /* * We have some new information we can gather. Run off and fetch * it. */ if (evtype == DNS_EVENT_ADBMOREADDRESSES) { restart_find(client); return; } /* * An error or other strangeness happened. Drop this query. */ cleanup_gabn(client); ns_lwdclient_errorpktsend(client, LWRES_R_FAILURE); }
static void generate_reply(ns_lwdclient_t *client) { isc_result_t result; int lwres; isc_region_t r; lwres_buffer_t lwb; ns_lwdclientmgr_t *cm; cm = client->clientmgr; lwb.base = NULL; ns_lwdclient_log(50, "generating gabn reply for client %p", client); /* * We must make certain the client->find is not still active. * If it is either the v4 or v6 answer, just set it to NULL and * let the cleanup code destroy it. Otherwise, destroy it now. */ if (client->find == client->v4find || client->find == client->v6find) client->find = NULL; else if (client->find != NULL) dns_adb_destroyfind(&client->find); /* * perhaps there are some here? */ if (NEED_V6(client) && client->v4find != NULL) client->v6find = client->v4find; /* * Run through the finds we have and wire them up to the gabn * structure. */ LWRES_LIST_INIT(client->gabn.addrs); if (client->v4find != NULL) setup_addresses(client, client->v4find, DNS_ADBFIND_INET); if (client->v6find != NULL) setup_addresses(client, client->v6find, DNS_ADBFIND_INET6); /* * If there are no addresses, try the next element in the search * path, if there are any more. Otherwise, fall through into * the error handling code below. */ if (client->gabn.naddrs == 0) { do { result = ns_lwsearchctx_next(&client->searchctx); if (result == ISC_R_SUCCESS) { cleanup_gabn(client); result = start_find(client); if (result == ISC_R_SUCCESS) return; } } while (result == ISC_R_SUCCESS); } /* * Render the packet. */ client->pkt.recvlength = LWRES_RECVLENGTH; client->pkt.authtype = 0; /* XXXMLG */ client->pkt.authlength = 0; /* * If there are no addresses, return failure. */ if (client->gabn.naddrs != 0) client->pkt.result = LWRES_R_SUCCESS; else client->pkt.result = LWRES_R_NOTFOUND; sort_addresses(client); lwres = lwres_gabnresponse_render(cm->lwctx, &client->gabn, &client->pkt, &lwb); if (lwres != LWRES_R_SUCCESS) goto out; r.base = lwb.base; r.length = lwb.used; client->sendbuf = r.base; client->sendlength = r.length; result = ns_lwdclient_sendreply(client, &r); if (result != ISC_R_SUCCESS) goto out; NS_LWDCLIENT_SETSEND(client); /* * All done! */ cleanup_gabn(client); return; out: cleanup_gabn(client); if (lwb.base != NULL) lwres_context_freemem(client->clientmgr->lwctx, lwb.base, lwb.length); ns_lwdclient_errorpktsend(client, LWRES_R_FAILURE); }