📄 lwdgabn.c
字号:
/* * Copyright (C) 2000, 2001 Internet Software Consortium. * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL * INTERNET SOFTWARE CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. *//* $Id: lwdgabn.c,v 1.13 2001/01/22 22:12:16 bwelling Exp $ */#include <config.h>#include <stdlib.h>#include <isc/netaddr.h>#include <isc/sockaddr.h>#include <isc/socket.h>#include <isc/string.h> /* Required for HP/UX (and others?) */#include <isc/util.h>#include <dns/adb.h>#include <dns/events.h>#include <dns/result.h>#include <named/types.h>#include <named/lwaddr.h>#include <named/lwdclient.h>#include <named/lwresd.h>#include <named/lwsearch.h>#include <named/sortlist.h>#define NEED_V4(c) ((((c)->find_wanted & LWRES_ADDRTYPE_V4) != 0) \ && ((c)->v4find == NULL))#define NEED_V6(c) ((((c)->find_wanted & LWRES_ADDRTYPE_V6) != 0) \ && ((c)->v6find == NULL))static isc_result_t start_find(ns_lwdclient_t *);static void restart_find(ns_lwdclient_t *);static void init_gabn(ns_lwdclient_t *);/* * 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 voidcleanup_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 voidsetup_addresses(ns_lwdclient_t *client, dns_adbfind_t *find, unsigned int at) { dns_adbaddrinfo_t *ai; lwres_addr_t *addr; int af; const struct sockaddr *sa; isc_result_t result; if (at == DNS_ADBFIND_INET) af = AF_INET; else af = AF_INET6; ai = ISC_LIST_HEAD(find->list); while (ai != NULL && client->gabn.naddrs < LWRES_MAX_ADDRS) { sa = &ai->sockaddr.type.sa; if (sa->sa_family != af) goto next; addr = &client->addrs[client->gabn.naddrs]; result = lwaddr_lwresaddr_fromsockaddr(addr, &ai->sockaddr); if (result != ISC_R_SUCCESS) goto next; ns_lwdclient_log(50, "adding address %p, family %d, length %d", addr->address, addr->family, addr->length); client->gabn.naddrs++; REQUIRE(!LWRES_LINK_LINKED(addr, link)); LWRES_LIST_APPEND(client->gabn.addrs, addr, link); next: ai = ISC_LIST_NEXT(ai, publink); }}typedef struct { isc_netaddr_t address; int rank;} rankedaddress;static intaddr_compare(const void *av, const void *bv) { const rankedaddress *a = (const rankedaddress *) av; const rankedaddress *b = (const rankedaddress *) bv; return (a->rank - b->rank);}static voidsort_addresses(ns_lwdclient_t *client) { unsigned int naddrs; rankedaddress *addrs; isc_netaddr_t remote; dns_addressorderfunc_t order; void *arg; ns_lwresd_t *lwresd = client->clientmgr->listener->manager; unsigned int i; isc_result_t result; naddrs = client->gabn.naddrs; if (naddrs <= 1 || lwresd->view->sortlist == NULL) return; addrs = isc_mem_get(lwresd->mctx, sizeof(rankedaddress) * naddrs); if (addrs == NULL) return; isc_netaddr_fromsockaddr(&remote, &client->address); ns_sortlist_byaddrsetup(lwresd->view->sortlist, &remote, &order, &arg); if (order == NULL) { isc_mem_put(lwresd->mctx, addrs, sizeof(rankedaddress) * naddrs); return; } for (i = 0; i < naddrs; i++) { result = lwaddr_netaddr_fromlwresaddr(&addrs[i].address, &client->addrs[i]); INSIST(result == ISC_R_SUCCESS); addrs[i].rank = (*order)(&addrs[i].address, arg); } qsort(addrs, naddrs, sizeof(rankedaddress), addr_compare); for (i = 0; i < naddrs; i++) { result = lwaddr_lwresaddr_fromnetaddr(&client->addrs[i], &addrs[i].address); INSIST(result == ISC_R_SUCCESS); } isc_mem_put(lwresd->mctx, addrs, sizeof(rankedaddress) * naddrs);}static voidgenerate_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);}/* * Take the current real name, move it to an alias slot (if any are * open) then put this new name in as the real name for the target. * * Return success if it can be rendered, otherwise failure. Note that * not having enough alias slots open is NOT a failure. */static isc_result_tadd_alias(ns_lwdclient_t *client) { isc_buffer_t b; isc_result_t result; isc_uint16_t naliases; b = client->recv_buffer; /* * Render the new name to the buffer. */ result = dns_name_totext(dns_fixedname_name(&client->target_name), ISC_TRUE, &client->recv_buffer); if (result != ISC_R_SUCCESS) return (result); /* * Are there any open slots? */ naliases = client->gabn.naliases; if (naliases < LWRES_MAX_ALIASES) { client->gabn.aliases[naliases] = client->gabn.realname; client->gabn.aliaslen[naliases] = client->gabn.realnamelen; client->gabn.naliases++; } /* * Save this name away as the current real name. */ client->gabn.realname = (char *)(b.base) + b.used; client->gabn.realnamelen = client->recv_buffer.used - b.used; return (ISC_R_SUCCESS);}static isc_result_tstore_realname(ns_lwdclient_t *client) { isc_buffer_t b; isc_result_t result; dns_name_t *tname; b = client->recv_buffer; tname = dns_fixedname_name(&client->target_name); result = ns_lwsearchctx_current(&client->searchctx, tname); if (result != ISC_R_SUCCESS) return (result); /* * Render the new name to the buffer. */ result = dns_name_totext(tname, ISC_TRUE, &client->recv_buffer); if (result != ISC_R_SUCCESS) return (result);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -