static void lookup_done(isc_task_t *task, isc_event_t *event) { ns_lwdclient_t *client; ns_lwdclientmgr_t *cm; dns_lookupevent_t *levent; lwres_buffer_t lwb; dns_name_t *name; dns_rdataset_t *rdataset; dns_rdataset_t *sigrdataset; isc_result_t result; lwres_result_t lwresult; isc_region_t r; isc_buffer_t b; lwres_grbnresponse_t *grbn; int i; REQUIRE(event != NULL); UNUSED(task); lwb.base = NULL; client = event->ev_arg; cm = client->clientmgr; INSIST(client->lookup == (dns_lookup_t *)event->ev_sender); levent = (dns_lookupevent_t *)event; grbn = &client->grbn; ns_lwdclient_log(50, "lookup event result = %s", isc_result_totext(levent->result)); result = levent->result; if (result != ISC_R_SUCCESS) { dns_lookup_destroy(&client->lookup); isc_event_free(&event); levent = NULL; switch (result) { case DNS_R_NXDOMAIN: case DNS_R_NCACHENXDOMAIN: result = ns_lwsearchctx_next(&client->searchctx); if (result != ISC_R_SUCCESS) lwresult = LWRES_R_NOTFOUND; else { start_lookup(client); return; } break; case DNS_R_NXRRSET: case DNS_R_NCACHENXRRSET: lwresult = LWRES_R_TYPENOTFOUND; break; default: lwresult = LWRES_R_FAILURE; } ns_lwdclient_errorpktsend(client, lwresult); return; } name = levent->name; b = client->recv_buffer; grbn->flags = 0; grbn->nrdatas = 0; grbn->rdatas = NULL; grbn->rdatalen = NULL; grbn->nsigs = 0; grbn->sigs = NULL; grbn->siglen = NULL; result = dns_name_totext(name, ISC_TRUE, &client->recv_buffer); if (result != ISC_R_SUCCESS) goto out; grbn->realname = (char *)isc_buffer_used(&b); grbn->realnamelen = isc_buffer_usedlength(&client->recv_buffer) - isc_buffer_usedlength(&b); ns_lwdclient_log(50, "found name '%.*s'", grbn->realnamelen, grbn->realname); grbn->rdclass = cm->view->rdclass; grbn->rdtype = client->rdtype; rdataset = levent->rdataset; if (rdataset != NULL) { /* The normal case */ grbn->nrdatas = dns_rdataset_count(rdataset); grbn->rdatas = isc_mem_get(cm->mctx, grbn->nrdatas * sizeof(unsigned char *)); if (grbn->rdatas == NULL) goto out; grbn->rdatalen = isc_mem_get(cm->mctx, grbn->nrdatas * sizeof(lwres_uint16_t)); if (grbn->rdatalen == NULL) goto out; i = 0; result = fill_array(&i, rdataset, grbn->nrdatas, grbn->rdatas, grbn->rdatalen); if (result != ISC_R_SUCCESS) goto out; INSIST(i == grbn->nrdatas); grbn->ttl = rdataset->ttl; if (rdataset->trust == dns_trust_secure) grbn->flags |= LWRDATA_VALIDATED; } else { /* The SIG query case */ result = iterate_node(grbn, levent->db, levent->node, cm->mctx); if (result != ISC_R_SUCCESS) goto out; } ns_lwdclient_log(50, "filled in %d rdata%s", grbn->nrdatas, (grbn->nrdatas == 1) ? "" : "s"); sigrdataset = levent->sigrdataset; if (sigrdataset != NULL) { grbn->nsigs = dns_rdataset_count(sigrdataset); grbn->sigs = isc_mem_get(cm->mctx, grbn->nsigs * sizeof(unsigned char *)); if (grbn->sigs == NULL) goto out; grbn->siglen = isc_mem_get(cm->mctx, grbn->nsigs * sizeof(lwres_uint16_t)); if (grbn->siglen == NULL) goto out; i = 0; result = fill_array(&i, sigrdataset, grbn->nsigs, grbn->sigs, grbn->siglen); if (result != ISC_R_SUCCESS) goto out; INSIST(i == grbn->nsigs); ns_lwdclient_log(50, "filled in %d signature%s", grbn->nsigs, (grbn->nsigs == 1) ? "" : "s"); } /* * Render the packet. */ client->pkt.recvlength = LWRES_RECVLENGTH; client->pkt.authtype = 0; /* XXXMLG */ client->pkt.authlength = 0; client->pkt.result = LWRES_R_SUCCESS; lwresult = lwres_grbnresponse_render(cm->lwctx, grbn, &client->pkt, &lwb); if (lwresult != LWRES_R_SUCCESS) goto out; isc_mem_put(cm->mctx, grbn->rdatas, grbn->nrdatas * sizeof(unsigned char *)); isc_mem_put(cm->mctx, grbn->rdatalen, grbn->nrdatas * sizeof(lwres_uint16_t)); if (grbn->sigs != NULL) isc_mem_put(cm->mctx, grbn->sigs, grbn->nsigs * sizeof(unsigned char *)); if (grbn->siglen != NULL) isc_mem_put(cm->mctx, grbn->siglen, grbn->nsigs * sizeof(lwres_uint16_t)); 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 out2; NS_LWDCLIENT_SETSEND(client); dns_lookup_destroy(&client->lookup); isc_event_free(&event); return; out: if (grbn->rdatas != NULL) isc_mem_put(cm->mctx, grbn->rdatas, grbn->nrdatas * sizeof(unsigned char *)); if (grbn->rdatalen != NULL) isc_mem_put(cm->mctx, grbn->rdatalen, grbn->nrdatas * sizeof(lwres_uint16_t)); if (grbn->sigs != NULL) isc_mem_put(cm->mctx, grbn->sigs, grbn->nsigs * sizeof(unsigned char *)); if (grbn->siglen != NULL) isc_mem_put(cm->mctx, grbn->siglen, grbn->nsigs * sizeof(lwres_uint16_t)); out2: if (client->lookup != NULL) dns_lookup_destroy(&client->lookup); if (lwb.base != NULL) lwres_context_freemem(cm->lwctx, lwb.base, lwb.length); isc_event_free(&event); ns_lwdclient_log(50, "error constructing getrrsetbyname response"); 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); }