1135446Strhodes/* 2224092Sdougb * Copyright (C) 2004-2007, 2009 Internet Systems Consortium, Inc. ("ISC") 3135446Strhodes * Copyright (C) 2000, 2001 Internet Software Consortium. 4135446Strhodes * 5193149Sdougb * Permission to use, copy, modify, and/or distribute this software for any 6135446Strhodes * purpose with or without fee is hereby granted, provided that the above 7135446Strhodes * copyright notice and this permission notice appear in all copies. 8135446Strhodes * 9135446Strhodes * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH 10135446Strhodes * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 11135446Strhodes * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, 12135446Strhodes * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 13135446Strhodes * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE 14135446Strhodes * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 15135446Strhodes * PERFORMANCE OF THIS SOFTWARE. 16135446Strhodes */ 17135446Strhodes 18234010Sdougb/* $Id: lwdgabn.c,v 1.24 2009/09/02 23:48:01 tbox Exp $ */ 19135446Strhodes 20170222Sdougb/*! \file */ 21170222Sdougb 22135446Strhodes#include <config.h> 23135446Strhodes 24135446Strhodes#include <stdlib.h> 25135446Strhodes 26135446Strhodes#include <isc/netaddr.h> 27135446Strhodes#include <isc/sockaddr.h> 28135446Strhodes#include <isc/socket.h> 29135446Strhodes#include <isc/string.h> /* Required for HP/UX (and others?) */ 30135446Strhodes#include <isc/util.h> 31135446Strhodes 32135446Strhodes#include <dns/adb.h> 33135446Strhodes#include <dns/events.h> 34135446Strhodes#include <dns/result.h> 35135446Strhodes 36135446Strhodes#include <named/types.h> 37135446Strhodes#include <named/lwaddr.h> 38135446Strhodes#include <named/lwdclient.h> 39135446Strhodes#include <named/lwresd.h> 40135446Strhodes#include <named/lwsearch.h> 41135446Strhodes#include <named/sortlist.h> 42135446Strhodes 43135446Strhodes#define NEED_V4(c) ((((c)->find_wanted & LWRES_ADDRTYPE_V4) != 0) \ 44135446Strhodes && ((c)->v4find == NULL)) 45135446Strhodes#define NEED_V6(c) ((((c)->find_wanted & LWRES_ADDRTYPE_V6) != 0) \ 46135446Strhodes && ((c)->v6find == NULL)) 47135446Strhodes 48135446Strhodesstatic isc_result_t start_find(ns_lwdclient_t *); 49135446Strhodesstatic void restart_find(ns_lwdclient_t *); 50135446Strhodesstatic void init_gabn(ns_lwdclient_t *); 51135446Strhodes 52170222Sdougb/*% 53135446Strhodes * Destroy any finds. This can be used to "start over from scratch" and 54135446Strhodes * should only be called when events are _not_ being generated by the finds. 55135446Strhodes */ 56135446Strhodesstatic void 57135446Strhodescleanup_gabn(ns_lwdclient_t *client) { 58135446Strhodes ns_lwdclient_log(50, "cleaning up client %p", client); 59135446Strhodes 60135446Strhodes if (client->v6find != NULL) { 61135446Strhodes if (client->v6find == client->v4find) 62135446Strhodes client->v6find = NULL; 63135446Strhodes else 64135446Strhodes dns_adb_destroyfind(&client->v6find); 65135446Strhodes } 66135446Strhodes if (client->v4find != NULL) 67135446Strhodes dns_adb_destroyfind(&client->v4find); 68135446Strhodes} 69135446Strhodes 70135446Strhodesstatic void 71135446Strhodessetup_addresses(ns_lwdclient_t *client, dns_adbfind_t *find, unsigned int at) { 72135446Strhodes dns_adbaddrinfo_t *ai; 73135446Strhodes lwres_addr_t *addr; 74135446Strhodes int af; 75135446Strhodes const struct sockaddr *sa; 76135446Strhodes isc_result_t result; 77135446Strhodes 78135446Strhodes if (at == DNS_ADBFIND_INET) 79135446Strhodes af = AF_INET; 80135446Strhodes else 81135446Strhodes af = AF_INET6; 82135446Strhodes 83135446Strhodes ai = ISC_LIST_HEAD(find->list); 84135446Strhodes while (ai != NULL && client->gabn.naddrs < LWRES_MAX_ADDRS) { 85135446Strhodes sa = &ai->sockaddr.type.sa; 86135446Strhodes if (sa->sa_family != af) 87135446Strhodes goto next; 88135446Strhodes 89135446Strhodes addr = &client->addrs[client->gabn.naddrs]; 90135446Strhodes 91135446Strhodes result = lwaddr_lwresaddr_fromsockaddr(addr, &ai->sockaddr); 92135446Strhodes if (result != ISC_R_SUCCESS) 93135446Strhodes goto next; 94135446Strhodes 95135446Strhodes ns_lwdclient_log(50, "adding address %p, family %d, length %d", 96135446Strhodes addr->address, addr->family, addr->length); 97135446Strhodes 98135446Strhodes client->gabn.naddrs++; 99135446Strhodes REQUIRE(!LWRES_LINK_LINKED(addr, link)); 100135446Strhodes LWRES_LIST_APPEND(client->gabn.addrs, addr, link); 101135446Strhodes 102135446Strhodes next: 103135446Strhodes ai = ISC_LIST_NEXT(ai, publink); 104135446Strhodes } 105135446Strhodes} 106135446Strhodes 107135446Strhodestypedef struct { 108135446Strhodes isc_netaddr_t address; 109135446Strhodes int rank; 110135446Strhodes} rankedaddress; 111135446Strhodes 112135446Strhodesstatic int 113135446Strhodesaddr_compare(const void *av, const void *bv) { 114135446Strhodes const rankedaddress *a = (const rankedaddress *) av; 115135446Strhodes const rankedaddress *b = (const rankedaddress *) bv; 116135446Strhodes return (a->rank - b->rank); 117135446Strhodes} 118135446Strhodes 119135446Strhodesstatic void 120135446Strhodessort_addresses(ns_lwdclient_t *client) { 121135446Strhodes unsigned int naddrs; 122135446Strhodes rankedaddress *addrs; 123135446Strhodes isc_netaddr_t remote; 124135446Strhodes dns_addressorderfunc_t order; 125165071Sdougb const void *arg; 126135446Strhodes ns_lwresd_t *lwresd = client->clientmgr->listener->manager; 127135446Strhodes unsigned int i; 128135446Strhodes isc_result_t result; 129135446Strhodes 130135446Strhodes naddrs = client->gabn.naddrs; 131135446Strhodes 132135446Strhodes if (naddrs <= 1 || lwresd->view->sortlist == NULL) 133135446Strhodes return; 134135446Strhodes 135135446Strhodes addrs = isc_mem_get(lwresd->mctx, sizeof(rankedaddress) * naddrs); 136135446Strhodes if (addrs == NULL) 137135446Strhodes return; 138135446Strhodes 139135446Strhodes isc_netaddr_fromsockaddr(&remote, &client->address); 140135446Strhodes ns_sortlist_byaddrsetup(lwresd->view->sortlist, 141135446Strhodes &remote, &order, &arg); 142135446Strhodes if (order == NULL) { 143135446Strhodes isc_mem_put(lwresd->mctx, addrs, 144135446Strhodes sizeof(rankedaddress) * naddrs); 145135446Strhodes return; 146135446Strhodes } 147135446Strhodes for (i = 0; i < naddrs; i++) { 148135446Strhodes result = lwaddr_netaddr_fromlwresaddr(&addrs[i].address, 149135446Strhodes &client->addrs[i]); 150135446Strhodes INSIST(result == ISC_R_SUCCESS); 151135446Strhodes addrs[i].rank = (*order)(&addrs[i].address, arg); 152135446Strhodes } 153135446Strhodes qsort(addrs, naddrs, sizeof(rankedaddress), addr_compare); 154135446Strhodes for (i = 0; i < naddrs; i++) { 155135446Strhodes result = lwaddr_lwresaddr_fromnetaddr(&client->addrs[i], 156135446Strhodes &addrs[i].address); 157135446Strhodes INSIST(result == ISC_R_SUCCESS); 158135446Strhodes } 159135446Strhodes 160135446Strhodes isc_mem_put(lwresd->mctx, addrs, sizeof(rankedaddress) * naddrs); 161135446Strhodes} 162135446Strhodes 163135446Strhodesstatic void 164135446Strhodesgenerate_reply(ns_lwdclient_t *client) { 165135446Strhodes isc_result_t result; 166135446Strhodes int lwres; 167135446Strhodes isc_region_t r; 168135446Strhodes lwres_buffer_t lwb; 169135446Strhodes ns_lwdclientmgr_t *cm; 170135446Strhodes 171135446Strhodes cm = client->clientmgr; 172135446Strhodes lwb.base = NULL; 173135446Strhodes 174135446Strhodes ns_lwdclient_log(50, "generating gabn reply for client %p", client); 175135446Strhodes 176135446Strhodes /* 177135446Strhodes * We must make certain the client->find is not still active. 178135446Strhodes * If it is either the v4 or v6 answer, just set it to NULL and 179135446Strhodes * let the cleanup code destroy it. Otherwise, destroy it now. 180135446Strhodes */ 181135446Strhodes if (client->find == client->v4find || client->find == client->v6find) 182135446Strhodes client->find = NULL; 183135446Strhodes else 184135446Strhodes if (client->find != NULL) 185135446Strhodes dns_adb_destroyfind(&client->find); 186135446Strhodes 187135446Strhodes /* 188135446Strhodes * perhaps there are some here? 189135446Strhodes */ 190135446Strhodes if (NEED_V6(client) && client->v4find != NULL) 191135446Strhodes client->v6find = client->v4find; 192135446Strhodes 193135446Strhodes /* 194135446Strhodes * Run through the finds we have and wire them up to the gabn 195135446Strhodes * structure. 196135446Strhodes */ 197135446Strhodes LWRES_LIST_INIT(client->gabn.addrs); 198135446Strhodes if (client->v4find != NULL) 199135446Strhodes setup_addresses(client, client->v4find, DNS_ADBFIND_INET); 200135446Strhodes if (client->v6find != NULL) 201135446Strhodes setup_addresses(client, client->v6find, DNS_ADBFIND_INET6); 202135446Strhodes 203135446Strhodes /* 204135446Strhodes * If there are no addresses, try the next element in the search 205135446Strhodes * path, if there are any more. Otherwise, fall through into 206135446Strhodes * the error handling code below. 207135446Strhodes */ 208135446Strhodes if (client->gabn.naddrs == 0) { 209135446Strhodes do { 210135446Strhodes result = ns_lwsearchctx_next(&client->searchctx); 211135446Strhodes if (result == ISC_R_SUCCESS) { 212135446Strhodes cleanup_gabn(client); 213135446Strhodes result = start_find(client); 214135446Strhodes if (result == ISC_R_SUCCESS) 215135446Strhodes return; 216135446Strhodes } 217135446Strhodes } while (result == ISC_R_SUCCESS); 218135446Strhodes } 219135446Strhodes 220135446Strhodes /* 221135446Strhodes * Render the packet. 222135446Strhodes */ 223135446Strhodes client->pkt.recvlength = LWRES_RECVLENGTH; 224135446Strhodes client->pkt.authtype = 0; /* XXXMLG */ 225135446Strhodes client->pkt.authlength = 0; 226135446Strhodes 227135446Strhodes /* 228135446Strhodes * If there are no addresses, return failure. 229135446Strhodes */ 230135446Strhodes if (client->gabn.naddrs != 0) 231135446Strhodes client->pkt.result = LWRES_R_SUCCESS; 232135446Strhodes else 233135446Strhodes client->pkt.result = LWRES_R_NOTFOUND; 234135446Strhodes 235135446Strhodes sort_addresses(client); 236135446Strhodes 237135446Strhodes lwres = lwres_gabnresponse_render(cm->lwctx, &client->gabn, 238135446Strhodes &client->pkt, &lwb); 239135446Strhodes if (lwres != LWRES_R_SUCCESS) 240135446Strhodes goto out; 241135446Strhodes 242135446Strhodes r.base = lwb.base; 243135446Strhodes r.length = lwb.used; 244135446Strhodes client->sendbuf = r.base; 245135446Strhodes client->sendlength = r.length; 246135446Strhodes result = ns_lwdclient_sendreply(client, &r); 247135446Strhodes if (result != ISC_R_SUCCESS) 248135446Strhodes goto out; 249135446Strhodes 250135446Strhodes NS_LWDCLIENT_SETSEND(client); 251135446Strhodes 252135446Strhodes /* 253135446Strhodes * All done! 254135446Strhodes */ 255135446Strhodes cleanup_gabn(client); 256135446Strhodes 257135446Strhodes return; 258135446Strhodes 259135446Strhodes out: 260135446Strhodes cleanup_gabn(client); 261135446Strhodes 262135446Strhodes if (lwb.base != NULL) 263135446Strhodes lwres_context_freemem(client->clientmgr->lwctx, 264135446Strhodes lwb.base, lwb.length); 265135446Strhodes 266135446Strhodes ns_lwdclient_errorpktsend(client, LWRES_R_FAILURE); 267135446Strhodes} 268135446Strhodes 269135446Strhodes/* 270135446Strhodes * Take the current real name, move it to an alias slot (if any are 271135446Strhodes * open) then put this new name in as the real name for the target. 272135446Strhodes * 273135446Strhodes * Return success if it can be rendered, otherwise failure. Note that 274135446Strhodes * not having enough alias slots open is NOT a failure. 275135446Strhodes */ 276135446Strhodesstatic isc_result_t 277135446Strhodesadd_alias(ns_lwdclient_t *client) { 278135446Strhodes isc_buffer_t b; 279135446Strhodes isc_result_t result; 280135446Strhodes isc_uint16_t naliases; 281135446Strhodes 282135446Strhodes b = client->recv_buffer; 283135446Strhodes 284135446Strhodes /* 285135446Strhodes * Render the new name to the buffer. 286135446Strhodes */ 287135446Strhodes result = dns_name_totext(dns_fixedname_name(&client->target_name), 288135446Strhodes ISC_TRUE, &client->recv_buffer); 289135446Strhodes if (result != ISC_R_SUCCESS) 290135446Strhodes return (result); 291135446Strhodes 292135446Strhodes /* 293135446Strhodes * Are there any open slots? 294135446Strhodes */ 295135446Strhodes naliases = client->gabn.naliases; 296135446Strhodes if (naliases < LWRES_MAX_ALIASES) { 297135446Strhodes client->gabn.aliases[naliases] = client->gabn.realname; 298135446Strhodes client->gabn.aliaslen[naliases] = client->gabn.realnamelen; 299135446Strhodes client->gabn.naliases++; 300135446Strhodes } 301135446Strhodes 302135446Strhodes /* 303135446Strhodes * Save this name away as the current real name. 304135446Strhodes */ 305135446Strhodes client->gabn.realname = (char *)(b.base) + b.used; 306135446Strhodes client->gabn.realnamelen = client->recv_buffer.used - b.used; 307135446Strhodes 308135446Strhodes return (ISC_R_SUCCESS); 309135446Strhodes} 310135446Strhodes 311135446Strhodesstatic isc_result_t 312135446Strhodesstore_realname(ns_lwdclient_t *client) { 313135446Strhodes isc_buffer_t b; 314135446Strhodes isc_result_t result; 315135446Strhodes dns_name_t *tname; 316135446Strhodes 317135446Strhodes b = client->recv_buffer; 318135446Strhodes 319135446Strhodes tname = dns_fixedname_name(&client->target_name); 320135446Strhodes result = ns_lwsearchctx_current(&client->searchctx, tname); 321135446Strhodes if (result != ISC_R_SUCCESS) 322135446Strhodes return (result); 323135446Strhodes 324135446Strhodes /* 325135446Strhodes * Render the new name to the buffer. 326135446Strhodes */ 327135446Strhodes result = dns_name_totext(tname, ISC_TRUE, &client->recv_buffer); 328135446Strhodes if (result != ISC_R_SUCCESS) 329135446Strhodes return (result); 330135446Strhodes 331135446Strhodes /* 332135446Strhodes * Save this name away as the current real name. 333135446Strhodes */ 334135446Strhodes client->gabn.realname = (char *) b.base + b.used; 335135446Strhodes client->gabn.realnamelen = client->recv_buffer.used - b.used; 336135446Strhodes 337135446Strhodes return (ISC_R_SUCCESS); 338135446Strhodes} 339135446Strhodes 340135446Strhodesstatic void 341135446Strhodesprocess_gabn_finddone(isc_task_t *task, isc_event_t *ev) { 342135446Strhodes ns_lwdclient_t *client = ev->ev_arg; 343135446Strhodes isc_eventtype_t evtype; 344135446Strhodes isc_boolean_t claimed; 345135446Strhodes 346135446Strhodes ns_lwdclient_log(50, "find done for task %p, client %p", task, client); 347135446Strhodes 348135446Strhodes evtype = ev->ev_type; 349135446Strhodes isc_event_free(&ev); 350135446Strhodes 351135446Strhodes /* 352135446Strhodes * No more info to be had? If so, we have all the good stuff 353135446Strhodes * right now, so we can render things. 354135446Strhodes */ 355135446Strhodes claimed = ISC_FALSE; 356135446Strhodes if (evtype == DNS_EVENT_ADBNOMOREADDRESSES) { 357135446Strhodes if (NEED_V4(client)) { 358135446Strhodes client->v4find = client->find; 359135446Strhodes claimed = ISC_TRUE; 360135446Strhodes } 361135446Strhodes if (NEED_V6(client)) { 362135446Strhodes client->v6find = client->find; 363135446Strhodes claimed = ISC_TRUE; 364135446Strhodes } 365135446Strhodes if (client->find != NULL) { 366135446Strhodes if (claimed) 367135446Strhodes client->find = NULL; 368135446Strhodes else 369135446Strhodes dns_adb_destroyfind(&client->find); 370135446Strhodes 371135446Strhodes } 372135446Strhodes generate_reply(client); 373135446Strhodes return; 374135446Strhodes } 375135446Strhodes 376135446Strhodes /* 377135446Strhodes * We probably don't need this find anymore. We're either going to 378135446Strhodes * reissue it, or an error occurred. Either way, we're done with 379135446Strhodes * it. 380135446Strhodes */ 381135446Strhodes if ((client->find != client->v4find) 382135446Strhodes && (client->find != client->v6find)) { 383135446Strhodes dns_adb_destroyfind(&client->find); 384135446Strhodes } else { 385135446Strhodes client->find = NULL; 386135446Strhodes } 387135446Strhodes 388135446Strhodes /* 389135446Strhodes * We have some new information we can gather. Run off and fetch 390135446Strhodes * it. 391135446Strhodes */ 392135446Strhodes if (evtype == DNS_EVENT_ADBMOREADDRESSES) { 393135446Strhodes restart_find(client); 394135446Strhodes return; 395135446Strhodes } 396135446Strhodes 397135446Strhodes /* 398135446Strhodes * An error or other strangeness happened. Drop this query. 399135446Strhodes */ 400135446Strhodes cleanup_gabn(client); 401135446Strhodes ns_lwdclient_errorpktsend(client, LWRES_R_FAILURE); 402135446Strhodes} 403135446Strhodes 404135446Strhodesstatic void 405135446Strhodesrestart_find(ns_lwdclient_t *client) { 406135446Strhodes unsigned int options; 407135446Strhodes isc_result_t result; 408135446Strhodes isc_boolean_t claimed; 409135446Strhodes 410135446Strhodes ns_lwdclient_log(50, "starting find for client %p", client); 411135446Strhodes 412135446Strhodes /* 413135446Strhodes * Issue a find for the name contained in the request. We won't 414135446Strhodes * set the bit that says "anything is good enough" -- we want it 415135446Strhodes * all. 416135446Strhodes */ 417135446Strhodes options = 0; 418135446Strhodes options |= DNS_ADBFIND_WANTEVENT; 419135446Strhodes options |= DNS_ADBFIND_RETURNLAME; 420135446Strhodes 421135446Strhodes /* 422135446Strhodes * Set the bits up here to mark that we want this address family 423135446Strhodes * and that we do not currently have a find pending. We will 424135446Strhodes * set that bit again below if it turns out we will get an event. 425135446Strhodes */ 426135446Strhodes if (NEED_V4(client)) 427135446Strhodes options |= DNS_ADBFIND_INET; 428135446Strhodes if (NEED_V6(client)) 429135446Strhodes options |= DNS_ADBFIND_INET6; 430135446Strhodes 431135446Strhodes find_again: 432135446Strhodes INSIST(client->find == NULL); 433135446Strhodes result = dns_adb_createfind(client->clientmgr->view->adb, 434135446Strhodes client->clientmgr->task, 435135446Strhodes process_gabn_finddone, client, 436135446Strhodes dns_fixedname_name(&client->target_name), 437170222Sdougb dns_rootname, 0, options, 0, 438135446Strhodes dns_fixedname_name(&client->target_name), 439135446Strhodes client->clientmgr->view->dstport, 440135446Strhodes &client->find); 441135446Strhodes 442135446Strhodes /* 443135446Strhodes * Did we get an alias? If so, save it and re-issue the query. 444135446Strhodes */ 445135446Strhodes if (result == DNS_R_ALIAS) { 446135446Strhodes ns_lwdclient_log(50, "found alias, restarting query"); 447135446Strhodes dns_adb_destroyfind(&client->find); 448135446Strhodes cleanup_gabn(client); 449135446Strhodes result = add_alias(client); 450135446Strhodes if (result != ISC_R_SUCCESS) { 451135446Strhodes ns_lwdclient_log(50, 452135446Strhodes "out of buffer space adding alias"); 453135446Strhodes ns_lwdclient_errorpktsend(client, LWRES_R_FAILURE); 454135446Strhodes return; 455135446Strhodes } 456135446Strhodes goto find_again; 457135446Strhodes } 458135446Strhodes 459135446Strhodes ns_lwdclient_log(50, "find returned %d (%s)", result, 460135446Strhodes isc_result_totext(result)); 461135446Strhodes 462135446Strhodes /* 463135446Strhodes * Did we get an error? 464135446Strhodes */ 465135446Strhodes if (result != ISC_R_SUCCESS) { 466135446Strhodes if (client->find != NULL) 467135446Strhodes dns_adb_destroyfind(&client->find); 468135446Strhodes cleanup_gabn(client); 469135446Strhodes ns_lwdclient_errorpktsend(client, LWRES_R_FAILURE); 470135446Strhodes return; 471135446Strhodes } 472135446Strhodes 473135446Strhodes claimed = ISC_FALSE; 474135446Strhodes 475135446Strhodes /* 476135446Strhodes * Did we get our answer to V4 addresses? 477135446Strhodes */ 478135446Strhodes if (NEED_V4(client) 479135446Strhodes && ((client->find->query_pending & DNS_ADBFIND_INET) == 0)) { 480135446Strhodes ns_lwdclient_log(50, "client %p ipv4 satisfied by find %p", 481135446Strhodes client, client->find); 482135446Strhodes claimed = ISC_TRUE; 483135446Strhodes client->v4find = client->find; 484135446Strhodes } 485135446Strhodes 486135446Strhodes /* 487135446Strhodes * Did we get our answer to V6 addresses? 488135446Strhodes */ 489135446Strhodes if (NEED_V6(client) 490135446Strhodes && ((client->find->query_pending & DNS_ADBFIND_INET6) == 0)) { 491135446Strhodes ns_lwdclient_log(50, "client %p ipv6 satisfied by find %p", 492135446Strhodes client, client->find); 493135446Strhodes claimed = ISC_TRUE; 494135446Strhodes client->v6find = client->find; 495135446Strhodes } 496135446Strhodes 497135446Strhodes /* 498135446Strhodes * If we're going to get an event, set our internal pending flag 499135446Strhodes * and return. When we get an event back we'll do the right 500135446Strhodes * thing, basically by calling this function again, perhaps with a 501135446Strhodes * new target name. 502135446Strhodes * 503135446Strhodes * If we have both v4 and v6, and we are still getting an event, 504135446Strhodes * we have a programming error, so die hard. 505135446Strhodes */ 506135446Strhodes if ((client->find->options & DNS_ADBFIND_WANTEVENT) != 0) { 507135446Strhodes ns_lwdclient_log(50, "event will be sent"); 508135446Strhodes INSIST(client->v4find == NULL || client->v6find == NULL); 509135446Strhodes return; 510135446Strhodes } 511135446Strhodes ns_lwdclient_log(50, "no event will be sent"); 512135446Strhodes if (claimed) 513135446Strhodes client->find = NULL; 514135446Strhodes else 515135446Strhodes dns_adb_destroyfind(&client->find); 516135446Strhodes 517135446Strhodes /* 518135446Strhodes * We seem to have everything we asked for, or at least we are 519135446Strhodes * able to respond with things we've learned. 520135446Strhodes */ 521135446Strhodes 522135446Strhodes generate_reply(client); 523135446Strhodes} 524135446Strhodes 525135446Strhodesstatic isc_result_t 526135446Strhodesstart_find(ns_lwdclient_t *client) { 527135446Strhodes isc_result_t result; 528135446Strhodes 529135446Strhodes /* 530135446Strhodes * Initialize the real name and alias arrays in the reply we're 531135446Strhodes * going to build up. 532135446Strhodes */ 533135446Strhodes init_gabn(client); 534135446Strhodes 535135446Strhodes result = store_realname(client); 536135446Strhodes if (result != ISC_R_SUCCESS) 537135446Strhodes return (result); 538135446Strhodes restart_find(client); 539135446Strhodes return (ISC_R_SUCCESS); 540135446Strhodes 541135446Strhodes} 542135446Strhodes 543135446Strhodesstatic void 544135446Strhodesinit_gabn(ns_lwdclient_t *client) { 545135446Strhodes int i; 546135446Strhodes 547135446Strhodes /* 548135446Strhodes * Initialize the real name and alias arrays in the reply we're 549135446Strhodes * going to build up. 550135446Strhodes */ 551135446Strhodes for (i = 0; i < LWRES_MAX_ALIASES; i++) { 552135446Strhodes client->aliases[i] = NULL; 553135446Strhodes client->aliaslen[i] = 0; 554135446Strhodes } 555135446Strhodes for (i = 0; i < LWRES_MAX_ADDRS; i++) { 556135446Strhodes client->addrs[i].family = 0; 557135446Strhodes client->addrs[i].length = 0; 558135446Strhodes memset(client->addrs[i].address, 0, LWRES_ADDR_MAXLEN); 559135446Strhodes LWRES_LINK_INIT(&client->addrs[i], link); 560135446Strhodes } 561135446Strhodes 562135446Strhodes client->gabn.naliases = 0; 563135446Strhodes client->gabn.naddrs = 0; 564135446Strhodes client->gabn.realname = NULL; 565135446Strhodes client->gabn.aliases = client->aliases; 566135446Strhodes client->gabn.realnamelen = 0; 567135446Strhodes client->gabn.aliaslen = client->aliaslen; 568135446Strhodes LWRES_LIST_INIT(client->gabn.addrs); 569135446Strhodes client->gabn.base = NULL; 570135446Strhodes client->gabn.baselen = 0; 571135446Strhodes 572135446Strhodes /* 573135446Strhodes * Set up the internal buffer to point to the receive region. 574135446Strhodes */ 575135446Strhodes isc_buffer_init(&client->recv_buffer, client->buffer, LWRES_RECVLENGTH); 576135446Strhodes} 577135446Strhodes 578135446Strhodes/* 579135446Strhodes * When we are called, we can be assured that: 580135446Strhodes * 581135446Strhodes * client->sockaddr contains the address we need to reply to, 582135446Strhodes * 583135446Strhodes * client->pkt contains the packet header data, 584135446Strhodes * 585135446Strhodes * the packet "checks out" overall -- any MD5 hashes or crypto 586135446Strhodes * bits have been verified, 587135446Strhodes * 588135446Strhodes * "b" points to the remaining data after the packet header 589135446Strhodes * was parsed off. 590135446Strhodes * 591135446Strhodes * We are in a the RECVDONE state. 592135446Strhodes * 593135446Strhodes * From this state we will enter the SEND state if we happen to have 594135446Strhodes * everything we need or we need to return an error packet, or to the 595135446Strhodes * FINDWAIT state if we need to look things up. 596135446Strhodes */ 597135446Strhodesvoid 598135446Strhodesns_lwdclient_processgabn(ns_lwdclient_t *client, lwres_buffer_t *b) { 599135446Strhodes isc_result_t result; 600135446Strhodes lwres_gabnrequest_t *req; 601135446Strhodes ns_lwdclientmgr_t *cm; 602135446Strhodes isc_buffer_t namebuf; 603135446Strhodes 604135446Strhodes REQUIRE(NS_LWDCLIENT_ISRECVDONE(client)); 605135446Strhodes 606135446Strhodes cm = client->clientmgr; 607135446Strhodes req = NULL; 608135446Strhodes 609135446Strhodes result = lwres_gabnrequest_parse(client->clientmgr->lwctx, 610135446Strhodes b, &client->pkt, &req); 611135446Strhodes if (result != LWRES_R_SUCCESS) 612135446Strhodes goto out; 613135446Strhodes if (req->name == NULL) 614135446Strhodes goto out; 615135446Strhodes 616135446Strhodes isc_buffer_init(&namebuf, req->name, req->namelen); 617135446Strhodes isc_buffer_add(&namebuf, req->namelen); 618135446Strhodes 619135446Strhodes dns_fixedname_init(&client->target_name); 620135446Strhodes dns_fixedname_init(&client->query_name); 621135446Strhodes result = dns_name_fromtext(dns_fixedname_name(&client->query_name), 622224092Sdougb &namebuf, NULL, 0, NULL); 623135446Strhodes if (result != ISC_R_SUCCESS) 624135446Strhodes goto out; 625135446Strhodes ns_lwsearchctx_init(&client->searchctx, 626135446Strhodes cm->listener->manager->search, 627135446Strhodes dns_fixedname_name(&client->query_name), 628135446Strhodes cm->listener->manager->ndots); 629135446Strhodes ns_lwsearchctx_first(&client->searchctx); 630135446Strhodes 631135446Strhodes client->find_wanted = req->addrtypes; 632135446Strhodes ns_lwdclient_log(50, "client %p looking for addrtypes %08x", 633135446Strhodes client, client->find_wanted); 634135446Strhodes 635135446Strhodes /* 636135446Strhodes * We no longer need to keep this around. 637135446Strhodes */ 638135446Strhodes lwres_gabnrequest_free(client->clientmgr->lwctx, &req); 639135446Strhodes 640135446Strhodes /* 641135446Strhodes * Start the find. 642135446Strhodes */ 643135446Strhodes result = start_find(client); 644135446Strhodes if (result != ISC_R_SUCCESS) 645135446Strhodes goto out; 646135446Strhodes 647135446Strhodes return; 648135446Strhodes 649135446Strhodes /* 650135446Strhodes * We're screwed. Return an error packet to our caller. 651135446Strhodes */ 652135446Strhodes out: 653135446Strhodes if (req != NULL) 654135446Strhodes lwres_gabnrequest_free(client->clientmgr->lwctx, &req); 655135446Strhodes 656135446Strhodes ns_lwdclient_errorpktsend(client, LWRES_R_FAILURE); 657135446Strhodes} 658