From 878d3073b13833ee1a50dfeabf8e400b6fdfc754 Mon Sep 17 00:00:00 2001 From: Brian Wellington Date: Fri, 16 Jun 2000 01:39:02 +0000 Subject: [PATCH] First pass at merging lwresd into named. Seems to work, but doesn't shut down properly. Run named with 'named -r' to test. --- bin/named/Makefile.in | 17 +- bin/named/include/named/globals.h | 1 + bin/named/include/named/log.h | 1 + bin/named/include/named/lwdclient.h | 205 ++++++++++ bin/named/include/named/lwresd.h | 45 +++ bin/named/include/named/types.h | 3 + bin/named/log.c | 2 + bin/named/lwdclient.c | 328 ++++++++++++++++ bin/named/lwderror.c | 80 ++++ bin/named/lwdgabn.c | 561 ++++++++++++++++++++++++++++ bin/named/lwdgnba.c | 292 +++++++++++++++ bin/named/lwdnoop.c | 86 +++++ bin/named/lwresd.c | 430 +++++++++++++++++++++ bin/named/main.c | 32 +- bin/named/server.c | 6 +- 15 files changed, 2076 insertions(+), 13 deletions(-) create mode 100644 bin/named/include/named/lwdclient.h create mode 100644 bin/named/include/named/lwresd.h create mode 100644 bin/named/lwdclient.c create mode 100644 bin/named/lwderror.c create mode 100644 bin/named/lwdgabn.c create mode 100644 bin/named/lwdgnba.c create mode 100644 bin/named/lwdnoop.c create mode 100644 bin/named/lwresd.c diff --git a/bin/named/Makefile.in b/bin/named/Makefile.in index ca9d2de9c5..4e708e070a 100644 --- a/bin/named/Makefile.in +++ b/bin/named/Makefile.in @@ -22,7 +22,8 @@ top_srcdir = @top_srcdir@ @BIND9_INCLUDES@ CINCLUDES = -I${srcdir}/include -I${srcdir}/unix/include \ - ${DNS_INCLUDES} ${ISC_INCLUDES} ${OMAPI_INCLUDES} + ${LWRES_INCLUDES} ${DNS_INCLUDES} ${ISC_INCLUDES} \ + ${OMAPI_INCLUDES} CDEFINES = CWARNINGS = @@ -30,14 +31,16 @@ CWARNINGS = OMAPILIBS = ../../lib/omapi/libomapi.@A@ DNSLIBS = ../../lib/dns/libdns.@A@ @DNS_OPENSSL_LIBS@ ISCLIBS = ../../lib/isc/libisc.@A@ +LWRESLIBS = ../../lib/lwres/liblwres.@A@ OMAPIDEPLIBS = ../../lib/omapi/libomapi.@A@ DNSDEPLIBS = ../../lib/dns/libdns.@A@ ISCDEPLIBS = ../../lib/isc/libisc.@A@ +LWRESDEPLIBS = ../../lib/lwres/liblwres.@A@ -DEPLIBS = ${OMAPIDEPLIBS} ${DNSDEPLIBS} ${ISCDEPLIBS} +DEPLIBS = ${LWRESDEPLIBS} ${OMAPIDEPLIBS} ${DNSDEPLIBS} ${ISCDEPLIBS} -LIBS = ${OMAPILIBS} ${DNSLIBS} ${ISCLIBS} @LIBS@ +LIBS = ${LWRESLIBS} ${OMAPILIBS} ${DNSLIBS} ${ISCLIBS} @LIBS@ SUBDIRS = unix @@ -45,13 +48,17 @@ TARGETS = named OBJS = client.@O@ interfacemgr.@O@ listenlist.@O@ \ log.@O@ logconf.@O@ main.@O@ notify.@O@ omapi.@O@ \ - query.@O@ server.@O@ update.@O@ xfrout.@O@ + query.@O@ server.@O@ update.@O@ xfrout.@O@ \ + lwresd.@O@ lwdclient.@O@ lwderror.@O@ lwdgabn.@O@ \ + lwdgnba.@O@ lwdnoop.@O@ UOBJS = unix/os.@O@ SRCS = client.c interfacemgr.c listenlist.c \ log.c logconf.c main.c notify.c omapi.c \ - query.c server.c update.c xfrout.c + query.c server.c update.c xfrout.c \ + lwresd.c lwdclient.c lwderror.c lwdgabn.c \ + lwdgnba.c lwdnoop.c @BIND9_MAKE_RULES@ diff --git a/bin/named/include/named/globals.h b/bin/named/include/named/globals.h index 045beaf43d..4f1020d016 100644 --- a/bin/named/include/named/globals.h +++ b/bin/named/include/named/globals.h @@ -52,6 +52,7 @@ EXTERN const char * ns_g_version INIT(VERSION); EXTERN in_port_t ns_g_port INIT(0); EXTERN ns_server_t * ns_g_server INIT(NULL); +EXTERN ns_lwresd_t * ns_g_lwresd INIT(NULL); /* * Logging. diff --git a/bin/named/include/named/log.h b/bin/named/include/named/log.h index 0ce529c90b..430553341a 100644 --- a/bin/named/include/named/log.h +++ b/bin/named/include/named/log.h @@ -45,6 +45,7 @@ #define NS_LOGMODULE_XFER_OUT (&ns_g_modules[7]) #define NS_LOGMODULE_NOTIFY (&ns_g_modules[8]) #define NS_LOGMODULE_OMAPI (&ns_g_modules[9]) +#define NS_LOGMODULE_LWRESD (&ns_g_modules[10]) isc_result_t ns_log_init(isc_boolean_t safe); diff --git a/bin/named/include/named/lwdclient.h b/bin/named/include/named/lwdclient.h new file mode 100644 index 0000000000..92a0462820 --- /dev/null +++ b/bin/named/include/named/lwdclient.h @@ -0,0 +1,205 @@ +/* + * Copyright (C) 2000 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. + */ + +#ifndef NAMED_LWDCLIENT_H +#define NAMED_LWDCLIENT_H 1 + +#include +#include +#include +#include +#include + +#include +#include + +#include + +#define LWRD_EVENTCLASS ISC_EVENTCLASS(4242) + +#define LWRD_SHUTDOWN (LWRD_EVENTCLASS + 0x0001) + +struct ns_lwdclient { + isc_sockaddr_t address; /* where to reply */ + ns_lwdclientmgr_t *clientmgr; /* our parent */ + ISC_LINK(ns_lwdclient_t) link; + unsigned int state; + void *arg; /* packet processing state */ + + /* + * Received data info. + */ + unsigned char buffer[LWRES_RECVLENGTH]; /* receive buffer */ + isc_uint32_t recvlength; /* length recv'd */ + lwres_lwpacket_t pkt; + + /* + * Send data state. If sendbuf != buffer (that is, the send buffer + * isn't our receive buffer) it will be freed to the lwres_context_t. + */ + unsigned char *sendbuf; + isc_uint32_t sendlength; + isc_buffer_t recv_buffer; + + /* + * gabn (get address by name) state info. + */ + dns_adbfind_t *find; + dns_adbfind_t *v4find; + dns_adbfind_t *v6find; + unsigned int find_wanted; /* Addresses we want */ + dns_fixedname_t target_name; + lwres_gabnresponse_t gabn; + + /* + * gnba (get name by address) state info. + */ + lwres_gnbaresponse_t gnba; + dns_byaddr_t *byaddr; + unsigned int options; + isc_netaddr_t na; + dns_adbaddrinfo_t *addrinfo; + + /* + * Alias and address info. This is copied up to the gabn/gnba + * structures eventually. + * + * XXXMLG We can keep all of this in a client since we only service + * three packet types right now. If we started handling more, + * we'd need to use "arg" above and allocate/destroy things. + */ + char *aliases[LWRES_MAX_ALIASES]; + isc_uint16_t aliaslen[LWRES_MAX_ALIASES]; + lwres_addr_t addrs[LWRES_MAX_ADDRS]; +}; + +/* + * Client states. + * + * _IDLE The client is not doing anything at all. + * + * _RECV The client is waiting for data after issuing a socket recv(). + * + * _RECVDONE Data has been received, and is being processed. + * + * _FINDWAIT An adb (or other) request was made that cannot be satisfied + * immediately. An event will wake the client up. + * + * _SEND All data for a response has completed, and a reply was + * sent via a socket send() call. + * + * Badly formatted state table: + * + * IDLE -> RECV when client has a recv() queued. + * + * RECV -> RECVDONE when recvdone event received. + * + * RECVDONE -> SEND if the data for a reply is at hand. + * RECVDONE -> FINDWAIT if more searching is needed, and events will + * eventually wake us up again. + * + * FINDWAIT -> SEND when enough data was received to reply. + * + * SEND -> IDLE when a senddone event was received. + * + * At any time -> IDLE on error. Sometimes this will be -> SEND + * instead, if enough data is on hand to reply with a meaningful + * error. + * + * Packets which are badly formatted may or may not get error returns. + */ +#define NS_LWDCLIENT_STATEIDLE 1 +#define NS_LWDCLIENT_STATERECV 2 +#define NS_LWDCLIENT_STATERECVDONE 3 +#define NS_LWDCLIENT_STATEFINDWAIT 4 +#define NS_LWDCLIENT_STATESEND 5 +#define NS_LWDCLIENT_STATESENDDONE 6 + +#define NS_LWDCLIENT_ISIDLE(c) \ + ((c)->state == NS_LWDCLIENT_STATEIDLE) +#define NS_LWDCLIENT_ISRECV(c) \ + ((c)->state == NS_LWDCLIENT_STATERECV) +#define NS_LWDCLIENT_ISRECVDONE(c) \ + ((c)->state == NS_LWDCLIENT_STATERECVDONE) +#define NS_LWDCLIENT_ISFINDWAIT(c) \ + ((c)->state == NS_LWDCLIENT_STATEFINDWAIT) +#define NS_LWDCLIENT_ISSEND(c) \ + ((c)->state == NS_LWDCLIENT_STATESEND) + +/* + * Overall magic test that means we're not idle. + */ +#define NS_LWDCLIENT_ISRUNNING(c) (!NS_LWDCLIENT_ISIDLE(c)) + +#define NS_LWDCLIENT_SETIDLE(c) \ + ((c)->state = NS_LWDCLIENT_STATEIDLE) +#define NS_LWDCLIENT_SETRECV(c) \ + ((c)->state = NS_LWDCLIENT_STATERECV) +#define NS_LWDCLIENT_SETRECVDONE(c) \ + ((c)->state = NS_LWDCLIENT_STATERECVDONE) +#define NS_LWDCLIENT_SETFINDWAIT(c) \ + ((c)->state = NS_LWDCLIENT_STATEFINDWAIT) +#define NS_LWDCLIENT_SETSEND(c) \ + ((c)->state = NS_LWDCLIENT_STATESEND) +#define NS_LWDCLIENT_SETSENDDONE(c) \ + ((c)->state = NS_LWDCLIENT_STATESENDDONE) + +struct ns_lwdclientmgr { + isc_mem_t *mctx; + isc_task_t *task; /* owning task */ + isc_socket_t *sock; /* socket to use */ + dns_view_t *view; + unsigned int flags; + lwres_context_t *lwctx; /* lightweight proto context */ + ISC_LIST(ns_lwdclient_t) idle; /* idle client slots */ + ISC_LIST(ns_lwdclient_t) running; /* running clients */ +}; + +#define NS_LWDCLIENTMGR_FLAGRECVPENDING 0x00000001 +#define NS_LWDCLIENTMGR_FLAGSHUTTINGDOWN 0x00000002 + +void +ns_lwdclient_initialize(ns_lwdclient_t *, ns_lwdclientmgr_t *); + +isc_result_t +ns_lwdclient_startrecv(ns_lwdclientmgr_t *); + +void +ns_lwdclient_stateidle(ns_lwdclient_t *); + +void +ns_lwdclient_recv(isc_task_t *, isc_event_t *); + +void +ns_lwdclient_shutdown(isc_task_t *, isc_event_t *); + +void +ns_lwdclient_send(isc_task_t *, isc_event_t *); + +/* + * Processing functions of various types. + */ +void ns_lwdclient_processgabn(ns_lwdclient_t *, lwres_buffer_t *); +void ns_lwdclient_processgnba(ns_lwdclient_t *, lwres_buffer_t *); +void ns_lwdclient_processnoop(ns_lwdclient_t *, lwres_buffer_t *); + +void ns_lwdclient_errorpktsend(ns_lwdclient_t *, isc_uint32_t); + +void DP(int level, const char *format, ...); +void hexdump(char *msg, void *base, size_t len); + +#endif /* NAMED_LWDCLIENT_H */ diff --git a/bin/named/include/named/lwresd.h b/bin/named/include/named/lwresd.h new file mode 100644 index 0000000000..6492a204ea --- /dev/null +++ b/bin/named/include/named/lwresd.h @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2000 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. + */ + +#ifndef NAMED_LWRESD_H +#define NAMED_LWRESD_H 1 + +#include +#include + +#include + +struct ns_lwresd { + isc_uint32_t magic; + ns_lwdclientmgr_t *cmgr; + isc_socket_t *sock; + unsigned int ntasks; + dns_view_t *view; + isc_mem_t *mctx; + isc_task_t *task; +}; + +void +ns_lwresd_create(isc_mem_t *mctx, dns_view_t *view, ns_lwresd_t **lwresdp); + +isc_result_t +ns_lwresd_createview(isc_mem_t *mctx, dns_view_t **viewp); + +void +ns_lwresd_destroy(ns_lwresd_t **lwresdp); + +#endif /* NAMED_LWRESD_H */ diff --git a/bin/named/include/named/types.h b/bin/named/include/named/types.h index cc061ab3e8..dac107cf4a 100644 --- a/bin/named/include/named/types.h +++ b/bin/named/include/named/types.h @@ -26,5 +26,8 @@ typedef struct ns_query ns_query_t; typedef struct ns_server ns_server_t; typedef struct ns_interface ns_interface_t; typedef struct ns_interfacemgr ns_interfacemgr_t; +typedef struct ns_lwresd ns_lwresd_t; +typedef struct ns_lwdclient ns_lwdclient_t; +typedef struct ns_lwdclientmgr ns_lwdclientmgr_t; #endif /* NAMED_TYPES_H */ diff --git a/bin/named/log.c b/bin/named/log.c index 4811a4d0bb..efa3504e27 100644 --- a/bin/named/log.c +++ b/bin/named/log.c @@ -45,6 +45,8 @@ static isc_logmodule_t modules[] = { { "xfer-in", 0 }, { "xfer-out", 0 }, { "notify", 0 }, + { "omapi", 0 }, + { "lwresd", 0 }, { NULL, 0 } }; diff --git a/bin/named/lwdclient.c b/bin/named/lwdclient.c new file mode 100644 index 0000000000..56712021ad --- /dev/null +++ b/bin/named/lwdclient.c @@ -0,0 +1,328 @@ +/* + * Copyright (C) 2000 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. + */ + +#include + +#include +#include +#include +#include + +#include +#include + +#include +#include + +void +DP(int level, const char *format, ...) { + va_list args; + +level = 1; + va_start(args, format); + isc_log_vwrite(dns_lctx, + DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_ADB, + ISC_LOG_DEBUG(level), format, args); + va_end(args); +} + +void +hexdump(char *msg, void *base, size_t len) { + unsigned char *p; + unsigned int cnt; + char buffer[180]; + char *n; + + p = base; + cnt = 0; + n = buffer; + *n = 0; + + printf("*** %s (%u bytes @ %p)\n", msg, len, base); + + while (cnt < len) { + if (cnt % 16 == 0) { + n = buffer; + n += sprintf(buffer, "%p: ", p); + } else if (cnt % 8 == 0) { + *n++ = ' '; + *n++ = '|'; + *n = 0; + } + n += sprintf(n, " %02x", *p++); + cnt++; + + if (cnt % 16 == 0) { + DP(80, buffer); + n = buffer; + *n = 0; + } + } + + if (n != buffer) { + DP(80, buffer); + n = buffer; + *n = 0; + } +} + +static void +clientmgr_can_die(ns_lwdclientmgr_t *cm) { + if ((cm->flags & NS_LWDCLIENTMGR_FLAGSHUTTINGDOWN) == 0) + return; + + if (ISC_LIST_HEAD(cm->running) != NULL) + return; + + lwres_context_destroy(&cm->lwctx); + dns_view_detach(&cm->view); + isc_task_detach(&cm->task); +} + +static void +process_request(ns_lwdclient_t *client) { + lwres_buffer_t b; + isc_result_t result; + + lwres_buffer_init(&b, client->buffer, client->recvlength); + lwres_buffer_add(&b, client->recvlength); + + result = lwres_lwpacket_parseheader(&b, &client->pkt); + if (result != ISC_R_SUCCESS) { + DP(50, "invalid packet header received"); + goto restart; + } + + DP(50, "opcode %08x", client->pkt.opcode); + + switch (client->pkt.opcode) { + case LWRES_OPCODE_GETADDRSBYNAME: + ns_lwdclient_processgabn(client, &b); + return; + case LWRES_OPCODE_GETNAMEBYADDR: + ns_lwdclient_processgnba(client, &b); + return; + case LWRES_OPCODE_NOOP: + ns_lwdclient_processnoop(client, &b); + return; + default: + DP(50, "unknown opcode %08x", client->pkt.opcode); + goto restart; + } + + /* + * Drop the packet. + */ + restart: + DP(50, "restarting client %p...", client); + ns_lwdclient_stateidle(client); +} + +void +ns_lwdclient_recv(isc_task_t *task, isc_event_t *ev) { + ns_lwdclient_t *client = ev->ev_arg; + ns_lwdclientmgr_t *cm = client->clientmgr; + isc_socketevent_t *dev = (isc_socketevent_t *)ev; + + INSIST(dev->region.base == client->buffer); + INSIST(NS_LWDCLIENT_ISRECV(client)); + + NS_LWDCLIENT_SETRECVDONE(client); + + INSIST((cm->flags & NS_LWDCLIENTMGR_FLAGRECVPENDING) != 0); + cm->flags &= ~NS_LWDCLIENTMGR_FLAGRECVPENDING; + + DP(50, "event received: task %p, length %u, result %u (%s)", + task, dev->n, dev->result, isc_result_totext(dev->result)); + + if (dev->result != ISC_R_SUCCESS) { + isc_event_free(&ev); + dev = NULL; + + /* + * Go idle. + */ + ns_lwdclient_stateidle(client); + + return; + } + + /* + * XXXMLG If we wanted to run on ipv6 as well, we'd need the pktinfo + * bits. Right now we don't, so don't remember them. + */ + client->recvlength = dev->n; + client->address = dev->address; + isc_event_free(&ev); + dev = NULL; + + ns_lwdclient_startrecv(cm); + + process_request(client); +} + +/* + * This function will start a new recv() on a socket for this client manager. + */ +isc_result_t +ns_lwdclient_startrecv(ns_lwdclientmgr_t *cm) { + ns_lwdclient_t *client; + isc_result_t result; + isc_region_t r; + + if ((cm->flags & NS_LWDCLIENTMGR_FLAGSHUTTINGDOWN) != 0) + return (ISC_R_SUCCESS); + + /* + * If a recv is already running, don't bother. + */ + if ((cm->flags & NS_LWDCLIENTMGR_FLAGRECVPENDING) != 0) + return (ISC_R_SUCCESS); + + /* + * If we have no idle slots, just return success. + */ + client = ISC_LIST_HEAD(cm->idle); + if (client == NULL) + return (ISC_R_SUCCESS); + INSIST(NS_LWDCLIENT_ISIDLE(client)); + + /* + * Issue the recv. If it fails, return that it did. + */ + r.base = client->buffer; + r.length = LWRES_RECVLENGTH; + result = isc_socket_recv(cm->sock, &r, 0, cm->task, ns_lwdclient_recv, + client); + if (result != ISC_R_SUCCESS) + return (result); + + /* + * Set the flag to say we've issued a recv() call. + */ + cm->flags |= NS_LWDCLIENTMGR_FLAGRECVPENDING; + + /* + * Remove the client from the idle list, and put it on the running + * list. + */ + NS_LWDCLIENT_SETRECV(client); + ISC_LIST_UNLINK(cm->idle, client, link); + ISC_LIST_APPEND(cm->running, client, link); + + return (ISC_R_SUCCESS); +} + +void +ns_lwdclient_shutdown(isc_task_t *task, isc_event_t *ev) { + ns_lwdclientmgr_t *cm = ev->ev_arg; + + REQUIRE((cm->flags & NS_LWDCLIENTMGR_FLAGSHUTTINGDOWN) == 0); + + DP(50, "got shutdown event, task %p", task); + + /* + * Cancel any pending I/O. + */ + if ((cm->flags & NS_LWDCLIENTMGR_FLAGRECVPENDING) != 0) + isc_socket_cancel(cm->sock, task, ISC_SOCKCANCEL_ALL); + + /* + * Run through the running client list and kill off any finds + * in progress. + */ + /* XXXMLG */ + + cm->flags |= NS_LWDCLIENTMGR_FLAGSHUTTINGDOWN; + + isc_event_free(&ev); +} + +/* + * Do all the crap needed to move a client from the run queue to the idle + * queue. + */ +void +ns_lwdclient_stateidle(ns_lwdclient_t *client) { + ns_lwdclientmgr_t *cm; + + cm = client->clientmgr; + + INSIST(client->sendbuf == NULL); + INSIST(client->sendlength == 0); + INSIST(client->arg == NULL); + INSIST(client->v4find == NULL); + INSIST(client->v6find == NULL); + + ISC_LIST_UNLINK(cm->running, client, link); + ISC_LIST_PREPEND(cm->idle, client, link); + + NS_LWDCLIENT_SETIDLE(client); + + clientmgr_can_die(cm); + + ns_lwdclient_startrecv(cm); +} + +void +ns_lwdclient_send(isc_task_t *task, isc_event_t *ev) { + ns_lwdclient_t *client = ev->ev_arg; + ns_lwdclientmgr_t *cm = client->clientmgr; + isc_socketevent_t *dev = (isc_socketevent_t *)ev; + + UNUSED(task); + UNUSED(dev); + + INSIST(NS_LWDCLIENT_ISSEND(client)); + INSIST(client->sendbuf == dev->region.base); + + DP(50, "task %p for client %p got send-done event", task, client); + + if (client->sendbuf != client->buffer) + lwres_context_freemem(cm->lwctx, client->sendbuf, + client->sendlength); + client->sendbuf = NULL; + client->sendlength = 0; + + ns_lwdclient_stateidle(client); + + isc_event_free(&ev); +} + +void +ns_lwdclient_initialize(ns_lwdclient_t *client, ns_lwdclientmgr_t *cmgr) { + client->clientmgr = cmgr; + ISC_LINK_INIT(client, link); + NS_LWDCLIENT_SETIDLE(client); + client->arg = NULL; + + client->recvlength = 0; + + client->sendbuf = NULL; + client->sendlength = 0; + + client->find = NULL; + client->v4find = NULL; + client->v6find = NULL; + client->find_wanted = 0; + + client->options = 0; + client->byaddr = NULL; + client->addrinfo = NULL; + + ISC_LIST_APPEND(cmgr->idle, client, link); +} diff --git a/bin/named/lwderror.c b/bin/named/lwderror.c new file mode 100644 index 0000000000..41e94b47f0 --- /dev/null +++ b/bin/named/lwderror.c @@ -0,0 +1,80 @@ +/* + * Copyright (C) 2000 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. + */ + +#include + +#include +#include + +#include +#include + +/* + * Generate an error packet for the client, schedule a send, and put us in + * the SEND state. + * + * The client->pkt structure will be modified to form an error return. + * The receiver needs to verify that it is in fact an error, and do the + * right thing with it. The opcode will be unchanged. The result needs + * to be set before calling this function. + * + * The only change this code makes is to set the receive buffer size to the + * size we use, set the reply bit, and recompute any security information. + */ +void +ns_lwdclient_errorpktsend(ns_lwdclient_t *client, isc_uint32_t _result) { + isc_result_t result; + int lwres; + isc_region_t r; + lwres_buffer_t b; + ns_lwdclientmgr_t *cm; + + cm = client->clientmgr; + + REQUIRE(NS_LWDCLIENT_ISRUNNING(client)); + + /* + * Since we are only sending the packet header, we can safely toss + * the receive buffer. This means we won't need to allocate space + * for sending an error reply. This is a Good Thing. + */ + client->pkt.length = LWRES_LWPACKET_LENGTH; + client->pkt.pktflags |= LWRES_LWPACKETFLAG_RESPONSE; + client->pkt.recvlength = LWRES_RECVLENGTH; + client->pkt.authtype = 0; /* XXXMLG */ + client->pkt.authlength = 0; + client->pkt.result = _result; + + lwres_buffer_init(&b, client->buffer, LWRES_RECVLENGTH); + lwres = lwres_lwpacket_renderheader(&b, &client->pkt); + if (lwres != LWRES_R_SUCCESS) { + ns_lwdclient_stateidle(client); + return; + } + + r.base = client->buffer; + r.length = b.used; + client->sendbuf = client->buffer; + result = isc_socket_sendto(cm->sock, &r, cm->task, ns_lwdclient_send, + client, &client->address, NULL); + if (result != ISC_R_SUCCESS) { + ns_lwdclient_stateidle(client); + return; + } + + NS_LWDCLIENT_SETSEND(client); +} diff --git a/bin/named/lwdgabn.c b/bin/named/lwdgabn.c new file mode 100644 index 0000000000..67f455dd9d --- /dev/null +++ b/bin/named/lwdgabn.c @@ -0,0 +1,561 @@ +/* + * Copyright (C) 2000 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. + */ + +#include + +#include +#include /* Required for HP/UX (and others?) */ +#include + +#include +#include +#include + +#include +#include + +#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 void start_find(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 void +cleanup_gabn(ns_lwdclient_t *client) { + dns_adbfind_t *v4; + + DP(50, "cleaning up client %p", client); + + v4 = client->v4find; + + if (client->v4find != NULL) + dns_adb_destroyfind(&client->v4find); + if (client->v6find != NULL) { + if (client->v6find == v4) + client->v6find = NULL; + else + dns_adb_destroyfind(&client->v6find); + } +} + +static void +setup_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; + const struct sockaddr_in *sin; + const struct sockaddr_in6 *sin6; + + 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]; + + switch (sa->sa_family) { + case AF_INET: + sin = &ai->sockaddr.type.sin; + addr->family = LWRES_ADDRTYPE_V4; + memcpy(addr->address, &sin->sin_addr, 4); + addr->length = 4; + break; + case AF_INET6: + sin6 = &ai->sockaddr.type.sin6; + addr->family = LWRES_ADDRTYPE_V6; + memcpy(addr->address, &sin6->sin6_addr, 16); + addr->length = 16; + break; + default: + goto next; + } + + DP(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); + } +} + +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; + + DP(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); + + /* + * Render the packet. + */ + client->pkt.recvlength = LWRES_RECVLENGTH; + client->pkt.authtype = 0; /* XXXMLG */ + client->pkt.authlength = 0; + + /* + * If there are no addresses and no aliases, return failure. + */ + if (client->gabn.naddrs == 0 && client->gabn.naliases == 0) + client->pkt.result = LWRES_R_NOTFOUND; + else + client->pkt.result = LWRES_R_SUCCESS; + + 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 = isc_socket_sendto(cm->sock, &r, cm->task, ns_lwdclient_send, + client, &client->address, NULL); + 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_t +add_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_t +store_realname(ns_lwdclient_t *client) { + isc_buffer_t b; + isc_result_t result; + + 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); + + /* + * 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 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; + + DP(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) { + start_find(client); + return; + } + + /* + * An error or other strangeness happened. Drop this query. + */ + cleanup_gabn(client); + ns_lwdclient_errorpktsend(client, LWRES_R_FAILURE); +} + +static void +start_find(ns_lwdclient_t *client) { + unsigned int options; + isc_result_t result; + isc_boolean_t claimed; + + DP(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, 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) { + DP(50, "found alias, restarting query"); + dns_adb_destroyfind(&client->find); + cleanup_gabn(client); + result = add_alias(client); + if (result != ISC_R_SUCCESS) { + DP(50, "out of buffer space adding alias"); + ns_lwdclient_errorpktsend(client, LWRES_R_FAILURE); + return; + } + goto find_again; + } + + DP(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)) { + DP(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)) { + DP(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) { + DP(50, "event will be sent"); + INSIST(client->v4find == NULL || client->v6find == NULL); + return; + } + DP(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 +init_gabn(ns_lwdclient_t *client) { + int i; + + /* + * Initialize the real name and alias arrays in the reply we're + * going to build up. + */ + for (i = 0 ; i < LWRES_MAX_ALIASES ; i++) { + client->aliases[i] = NULL; + client->aliaslen[i] = 0; + } + for (i = 0 ; i < LWRES_MAX_ADDRS ; i++) { + client->addrs[i].family = 0; + client->addrs[i].length = 0; + memset(client->addrs[i].address, 0, LWRES_ADDR_MAXLEN); + LWRES_LINK_INIT(&client->addrs[i], link); + } + + client->gabn.naliases = 0; + client->gabn.naddrs = 0; + client->gabn.realname = NULL; + client->gabn.aliases = client->aliases; + client->gabn.realnamelen = 0; + client->gabn.aliaslen = client->aliaslen; + LWRES_LIST_INIT(client->gabn.addrs); + client->gabn.base = NULL; + client->gabn.baselen = 0; + + /* + * Set up the internal buffer to point to the receive region. + */ + isc_buffer_init(&client->recv_buffer, client->buffer, LWRES_RECVLENGTH); +} + +/* + * When we are called, we can be assured that: + * + * client->sockaddr contains the address we need to reply to, + * + * client->pkt contains the packet header data, + * + * the packet "checks out" overall -- any MD5 hashes or crypto + * bits have been verified, + * + * "b" points to the remaining data after the packet header + * was parsed off. + * + * We are in a the RECVDONE state. + * + * From this state we will enter the SEND state if we happen to have + * everything we need or we need to return an error packet, or to the + * FINDWAIT state if we need to look things up. + */ +void +ns_lwdclient_processgabn(ns_lwdclient_t *client, lwres_buffer_t *b) { + isc_result_t result; + lwres_gabnrequest_t *req; + isc_buffer_t namebuf; + + REQUIRE(NS_LWDCLIENT_ISRECVDONE(client)); + + req = NULL; + + result = lwres_gabnrequest_parse(client->clientmgr->lwctx, + b, &client->pkt, &req); + if (result != LWRES_R_SUCCESS) + goto out; + + isc_buffer_init(&namebuf, req->name, req->namelen); + isc_buffer_add(&namebuf, req->namelen); + + dns_fixedname_init(&client->target_name); + result = dns_name_fromtext(dns_fixedname_name(&client->target_name), + &namebuf, dns_rootname, ISC_FALSE, NULL); + if (result != ISC_R_SUCCESS) + goto out; + + client->find_wanted = req->addrtypes; + DP(50, "client %p looking for addrtypes %08x", + client, client->find_wanted); + + /* + * We no longer need to keep this around. + */ + lwres_gabnrequest_free(client->clientmgr->lwctx, &req); + + /* + * Initialize the real name and alias arrays in the reply we're + * going to build up. + */ + init_gabn(client); + + result = store_realname(client); + if (result != ISC_R_SUCCESS) + goto out; + + /* + * Start the find. + */ + start_find(client); + + return; + + /* + * We're screwed. Return an error packet to our caller. + */ + out: + if (req != NULL) + lwres_gabnrequest_free(client->clientmgr->lwctx, &req); + + ns_lwdclient_errorpktsend(client, LWRES_R_FAILURE); +} diff --git a/bin/named/lwdgnba.c b/bin/named/lwdgnba.c new file mode 100644 index 0000000000..4c1ad429fc --- /dev/null +++ b/bin/named/lwdgnba.c @@ -0,0 +1,292 @@ +/* + * Copyright (C) 2000 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. + */ + +#include + +#include +#include /* Required for HP/UX (and others?) */ +#include + +#include +#include +#include + +#include +#include + +static void start_byaddr(ns_lwdclient_t *); + +static void +byaddr_done(isc_task_t *task, isc_event_t *event) { + ns_lwdclient_t *client; + ns_lwdclientmgr_t *cm; + dns_byaddrevent_t *bevent; + int lwres; + lwres_buffer_t lwb; + dns_name_t *name; + isc_result_t result; + isc_region_t r; + isc_buffer_t b; + lwres_gnbaresponse_t *gnba; + isc_uint16_t naliases; + isc_stdtime_t now; + + UNUSED(task); + + lwb.base = NULL; + client = event->ev_arg; + cm = client->clientmgr; + INSIST(client->byaddr == (dns_byaddr_t *)event->ev_sender); + + bevent = (dns_byaddrevent_t *)event; + gnba = &client->gnba; + + DP(50, "byaddr event result = %s", + isc_result_totext(bevent->result)); + + result = bevent->result; + if (result != ISC_R_SUCCESS) { + dns_byaddr_destroy(&client->byaddr); + isc_event_free(&event); + bevent = NULL; + + /* + * Were we trying bitstring or nibble mode? If bitstring, + * and we got FORMERROR or SERVFAIL, set the flag to + * avoid bitstring lables for 10 minutes. If we got any + * other error (NXDOMAIN, etc) just try again without + * bitstrings, and let our cache handle the negative answer + * for bitstrings. + */ + if ((client->options & DNS_BYADDROPT_IPV6NIBBLE) != 0) { + dns_adb_freeaddrinfo(cm->view->adb, &client->addrinfo); + ns_lwdclient_errorpktsend(client, LWRES_R_FAILURE); + return; + } + + isc_stdtime_get(&now); + if (result == DNS_R_FORMERR || + result == DNS_R_SERVFAIL || + result == ISC_R_FAILURE) + dns_adb_setavoidbitstring(cm->view->adb, + client->addrinfo, now + 600); + + /* + * Fall back to nibble reverse if the default of bitstrings + * fails. + */ + client->options |= DNS_BYADDROPT_IPV6NIBBLE; + + start_byaddr(client); + return; + } + + name = ISC_LIST_HEAD(bevent->names); + while (name != NULL) { + b = client->recv_buffer; + + result = dns_name_totext(name, ISC_TRUE, &client->recv_buffer); + if (result != ISC_R_SUCCESS) + goto out; + DP(50, "found name '%.*s'", + client->recv_buffer.used - b.used, + (char *)(b.base) + b.used); + if (gnba->realname == NULL) { + gnba->realname = (char *)(b.base) + b.used; + gnba->realnamelen = client->recv_buffer.used - b.used; + } else { + naliases = gnba->naliases; + if (naliases >= LWRES_MAX_ALIASES) + break; + gnba->aliases[naliases] = (char *)(b.base) + b.used; + gnba->aliaslen[naliases] = + client->recv_buffer.used - b.used; + gnba->naliases++; + } + name = ISC_LIST_NEXT(name, link); + } + + dns_byaddr_destroy(&client->byaddr); + dns_adb_freeaddrinfo(cm->view->adb, &client->addrinfo); + isc_event_free(&event); + + /* + * Render the packet. + */ + client->pkt.recvlength = LWRES_RECVLENGTH; + client->pkt.authtype = 0; /* XXXMLG */ + client->pkt.authlength = 0; + client->pkt.result = LWRES_R_SUCCESS; + + lwres = lwres_gnbaresponse_render(cm->lwctx, + gnba, &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 = isc_socket_sendto(cm->sock, &r, + cm->task, ns_lwdclient_send, + client, &client->address, NULL); + if (result != ISC_R_SUCCESS) + goto out; + + NS_LWDCLIENT_SETSEND(client); + + return; + + out: + if (client->byaddr != NULL) + dns_byaddr_destroy(&client->byaddr); + if (client->addrinfo != NULL) + dns_adb_freeaddrinfo(cm->view->adb, &client->addrinfo); + if (lwb.base != NULL) + lwres_context_freemem(cm->lwctx, + lwb.base, lwb.length); + + isc_event_free(&event); +} + +static void +start_byaddr(ns_lwdclient_t *client) { + isc_result_t result; + ns_lwdclientmgr_t *cm; + + cm = client->clientmgr; + + INSIST(client->byaddr == NULL); + + result = dns_byaddr_create(cm->mctx, &client->na, cm->view, + client->options, cm->task, byaddr_done, + client, &client->byaddr); + if (result != ISC_R_SUCCESS) { + dns_adb_freeaddrinfo(cm->view->adb, &client->addrinfo); + ns_lwdclient_errorpktsend(client, LWRES_R_FAILURE); + return; + } +} + +static void +init_gnba(ns_lwdclient_t *client) { + int i; + + /* + * Initialize the real name and alias arrays in the reply we're + * going to build up. + */ + for (i = 0 ; i < LWRES_MAX_ALIASES ; i++) { + client->aliases[i] = NULL; + client->aliaslen[i] = 0; + } + for (i = 0 ; i < LWRES_MAX_ADDRS ; i++) { + client->addrs[i].family = 0; + client->addrs[i].length = 0; + memset(client->addrs[i].address, 0, LWRES_ADDR_MAXLEN); + LWRES_LINK_INIT(&client->addrs[i], link); + } + + client->gnba.naliases = 0; + client->gnba.realname = NULL; + client->gnba.aliases = client->aliases; + client->gnba.realnamelen = 0; + client->gnba.aliaslen = client->aliaslen; + client->gnba.base = NULL; + client->gnba.baselen = 0; + isc_buffer_init(&client->recv_buffer, client->buffer, LWRES_RECVLENGTH); +} + +void +ns_lwdclient_processgnba(ns_lwdclient_t *client, lwres_buffer_t *b) { + lwres_gnbarequest_t *req; + isc_result_t result; + isc_sockaddr_t sa; + ns_lwdclientmgr_t *cm; + + REQUIRE(NS_LWDCLIENT_ISRECVDONE(client)); + INSIST(client->byaddr == NULL); + + cm = client->clientmgr; + req = NULL; + + result = lwres_gnbarequest_parse(cm->lwctx, + b, &client->pkt, &req); + if (result != LWRES_R_SUCCESS) + goto out; + if (req->addr.address == NULL) + goto out; + + client->options = 0; + if (req->addr.family == LWRES_ADDRTYPE_V4) { + client->na.family = AF_INET; + if (req->addr.length != 4) + goto out; + memcpy(&client->na.type.in, req->addr.address, 4); + } else if (req->addr.family == LWRES_ADDRTYPE_V6) { + client->na.family = AF_INET6; + if (req->addr.length != 16) + goto out; + memcpy(&client->na.type.in6, req->addr.address, 16); + } else { + goto out; + } + isc_sockaddr_fromnetaddr(&sa, &client->na, 53); + + DP(50, "client %p looking for addrtype %08x", + client, req->addr.family); + + /* + * We no longer need to keep this around. + */ + lwres_gnbarequest_free(cm->lwctx, &req); + + /* + * Initialize the real name and alias arrays in the reply we're + * going to build up. + */ + init_gnba(client); + client->options = 0; + + /* + * See if we should skip the byaddr bit. + */ + INSIST(client->addrinfo == NULL); + result = dns_adb_findaddrinfo(cm->view->adb, &sa, + &client->addrinfo, 0); + if (result != ISC_R_SUCCESS) + goto out; + + if (client->addrinfo->avoid_bitstring > 0) + client->options |= DNS_BYADDROPT_IPV6NIBBLE; + + /* + * Start the find. + */ + start_byaddr(client); + + return; + + /* + * We're screwed. Return an error packet to our caller. + */ + out: + if (req != NULL) + lwres_gnbarequest_free(cm->lwctx, &req); + + ns_lwdclient_errorpktsend(client, LWRES_R_FAILURE); +} diff --git a/bin/named/lwdnoop.c b/bin/named/lwdnoop.c new file mode 100644 index 0000000000..7afc98ddc8 --- /dev/null +++ b/bin/named/lwdnoop.c @@ -0,0 +1,86 @@ +/* + * Copyright (C) 2000 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. + */ + +#include + +#include +#include + +#include +#include + +void +ns_lwdclient_processnoop(ns_lwdclient_t *client, lwres_buffer_t *b) { + lwres_nooprequest_t *req; + lwres_noopresponse_t resp; + isc_result_t result; + lwres_result_t lwres; + isc_region_t r; + lwres_buffer_t lwb; + + REQUIRE(NS_LWDCLIENT_ISRECVDONE(client)); + INSIST(client->byaddr == NULL); + + req = NULL; + + result = lwres_nooprequest_parse(client->clientmgr->lwctx, + b, &client->pkt, &req); + if (result != LWRES_R_SUCCESS) + goto out; + + client->pkt.recvlength = LWRES_RECVLENGTH; + client->pkt.authtype = 0; /* XXXMLG */ + client->pkt.authlength = 0; + client->pkt.result = LWRES_R_SUCCESS; + + resp.datalength = req->datalength; + resp.data = req->data; + + lwres = lwres_noopresponse_render(client->clientmgr->lwctx, &resp, + &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 = isc_socket_sendto(client->clientmgr->sock, &r, + client->clientmgr->task, ns_lwdclient_send, + client, &client->address, NULL); + if (result != ISC_R_SUCCESS) + goto out; + + /* + * We can now destroy request. + */ + lwres_nooprequest_free(client->clientmgr->lwctx, &req); + + NS_LWDCLIENT_SETSEND(client); + + return; + + out: + if (req != NULL) + lwres_nooprequest_free(client->clientmgr->lwctx, &req); + + if (lwb.base != NULL) + lwres_context_freemem(client->clientmgr->lwctx, + lwb.base, lwb.length); + + ns_lwdclient_errorpktsend(client, LWRES_R_FAILURE); +} diff --git a/bin/named/lwresd.c b/bin/named/lwresd.c new file mode 100644 index 0000000000..d285ea9065 --- /dev/null +++ b/bin/named/lwresd.c @@ -0,0 +1,430 @@ +/* + * Copyright (C) 2000 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. + */ + +/* + * Main program for the Lightweight Resolver Daemon. + * + * To paraphrase the old saying about X11, "It's not a lightweight deamon + * for resolvers, it's a deamon for lightweight resolvers". + */ + +#include + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#define LWRESD_MAGIC ISC_MAGIC('L', 'W', 'R', 'D') +#define VALID_LWRESD(l) ISC_MAGIC_VALID(l, LWRESD_MAGIC) + +/* + * The goal number of clients we can handle will be NTASKS * NRECVS. + */ +#define NTASKS 20 /* tasks to create to handle lwres queries */ +#define NRECVS 5 /* max clients per task */ +#define NTHREADS 1 /* # threads to create in thread manager */ + +static void +fatal(const char *msg, isc_result_t result) { + isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_LWRESD, + ISC_LOG_CRITICAL, "%s: %s", msg, + isc_result_totext(result)); + isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_LWRESD, + ISC_LOG_CRITICAL, "exiting (due to fatal error)"); + exit(1); +} + +/* + * Wrappers around our memory management stuff, for the lwres functions. + */ +static void * +mem_alloc(void *arg, size_t size) { + return (isc_mem_get(arg, size)); +} + +static void +mem_free(void *arg, void *mem, size_t size) { + isc_mem_put(arg, mem, size); +} + +static void +shutdown_lwresd(isc_task_t *task, isc_event_t *event) { + ns_lwresd_t *lwresd = event->ev_arg; + unsigned int i; + + UNUSED(task); + + for (i = 0; i < lwresd->ntasks; i++) + isc_task_shutdown(lwresd->cmgr[i].task); + + /* + * Kill off the view. + */ + dns_view_detach(&lwresd->view); + + isc_task_detach(&lwresd->task); + + isc_event_free(&event); +} + + +static void +parse_resolv_conf(isc_mem_t *mctx, isc_sockaddrlist_t forwarders) { + lwres_context_t *lwctx; + lwres_conf_t *lwc; + int lwresult; + struct in_addr ina; + struct in6_addr ina6; + isc_sockaddr_t *sa; + int i; + + lwctx = NULL; + lwresult = lwres_context_create(&lwctx, mctx, mem_alloc, mem_free, + LWRES_CONTEXT_SERVERMODE); + if (lwresult != LWRES_R_SUCCESS) + return; + + lwresult = lwres_conf_parse(lwctx, "/etc/resolv.conf"); + if (lwresult != LWRES_R_SUCCESS) + goto out; + +#if 1 + lwres_conf_print(lwctx, stderr); +#endif + + lwc = lwres_conf_get(lwctx); + INSIST(lwc != NULL); + + /* + * Run through the list of nameservers, and set them to be our + * forwarders. + */ + for (i = 0 ; i < lwc->nsnext ; i++) { + switch (lwc->nameservers[i].family) { + case AF_INET: + sa = isc_mem_get(mctx, sizeof *sa); + INSIST(sa != NULL); + memcpy(&ina.s_addr, lwc->nameservers[i].address, 4); + isc_sockaddr_fromin(sa, &ina, 53); + ISC_LIST_APPEND(forwarders, sa, link); + sa = NULL; + break; + case AF_INET6: + sa = isc_mem_get(mctx, sizeof *sa); + INSIST(sa != NULL); + memcpy(&ina6.s6_addr, lwc->nameservers[i].address, 16); + isc_sockaddr_fromin6(sa, &ina6, 53); + ISC_LIST_APPEND(forwarders, sa, link); + sa = NULL; + break; + default: + break; + } + } + + out: + lwres_conf_clear(lwctx); + lwres_context_destroy(&lwctx); +} + +isc_result_t +ns_lwresd_createview(isc_mem_t *mctx, dns_view_t **viewp) { + dns_cache_t *cache; + isc_result_t result; + dns_db_t *rootdb; + unsigned int attrs; + isc_sockaddr_t any4, any6; + dns_dispatch_t *disp4 = NULL; + dns_dispatch_t *disp6 = NULL; + isc_sockaddrlist_t forwarders; + dns_view_t *view; + + REQUIRE(viewp != NULL && *viewp == NULL); + cache = NULL; + + /* + * View. + */ + view = NULL; + result = dns_view_create(mctx, dns_rdataclass_in, "_default", &view); + if (result != ISC_R_SUCCESS) + return (result); + + /* + * Cache. + */ + result = dns_cache_create(mctx, ns_g_taskmgr, ns_g_timermgr, + dns_rdataclass_in, "rbt", 0, NULL, &cache); + if (result != ISC_R_SUCCESS) + goto out; + dns_view_setcache(view, cache); + dns_cache_detach(&cache); + + /* + * Resolver. + * + * XXXMLG hardwired number of tasks. + */ + + if (isc_net_probeipv6() == ISC_R_SUCCESS) { + isc_sockaddr_any6(&any6); + + attrs = DNS_DISPATCHATTR_IPV6 | DNS_DISPATCHATTR_UDP; + result = dns_dispatch_getudp(ns_g_dispatchmgr, ns_g_socketmgr, + ns_g_taskmgr, &any6, 512, 6, 1024, + 17, 19, attrs, attrs, &disp6); + if (result != ISC_R_SUCCESS) + goto out; + } + if (isc_net_probeipv4() == ISC_R_SUCCESS) { + isc_sockaddr_any(&any4); + + attrs = DNS_DISPATCHATTR_IPV4 | DNS_DISPATCHATTR_UDP; + result = dns_dispatch_getudp(ns_g_dispatchmgr, ns_g_socketmgr, + ns_g_taskmgr, &any4, 512, 6, 1024, + 17, 19, attrs, attrs, &disp4); + if (result != ISC_R_SUCCESS) + goto out; + } + if (disp4 == NULL && disp6 == NULL) + fatal("not listening on IPv4 or IPv6", ISC_R_FAILURE); + + result = dns_view_createresolver(view, ns_g_taskmgr, 16, + ns_g_socketmgr, ns_g_timermgr, 0, + ns_g_dispatchmgr, disp4, disp6); + if (disp4 != NULL) + dns_dispatch_detach(&disp4); + if (disp6 != NULL) + dns_dispatch_detach(&disp6); + + if (result != ISC_R_SUCCESS) + goto out; + + rootdb = NULL; + result = dns_rootns_create(mctx, dns_rdataclass_in, NULL, &rootdb); + if (result != ISC_R_SUCCESS) + goto out; + dns_view_sethints(view, rootdb); + dns_db_detach(&rootdb); + + /* + * If we have forwarders, set them here. + */ + ISC_LIST_INIT(forwarders); + parse_resolv_conf(mctx, forwarders); + if (ISC_LIST_HEAD(forwarders) != NULL) { + isc_sockaddr_t *sa; + + dns_resolver_setforwarders(view->resolver, &forwarders); + dns_resolver_setfwdpolicy(view->resolver, dns_fwdpolicy_only); + sa = ISC_LIST_HEAD(forwarders); + while (sa != NULL) { + ISC_LIST_UNLINK(forwarders, sa, link); + isc_mem_put(mctx, sa, sizeof (*sa)); + sa = ISC_LIST_HEAD(forwarders); + } + } + + dns_view_freeze(view); + *viewp = view; + + return (ISC_R_SUCCESS); + +out: + dns_view_detach(&view); + return (result); +} + +void +ns_lwresd_create(isc_mem_t *mctx, dns_view_t *view, ns_lwresd_t **lwresdp) { + ns_lwresd_t *lwresd; + isc_sockaddr_t localhost; + struct in_addr lh_addr; + unsigned int i, j; + ns_lwdclient_t *client; + isc_socket_t *sock; + isc_result_t result; + + sock = NULL; + result = isc_socket_create(ns_g_socketmgr, AF_INET, isc_sockettype_udp, + &sock); + if (result != ISC_R_SUCCESS) { + isc_log_write(ns_g_lctx, NS_LOGCATEGORY_NETWORK, + NS_LOGMODULE_LWRESD, ISC_LOG_ERROR, + "failed to create socket: %s", + isc_result_totext(result)); + return; + } + + lh_addr.s_addr = htonl(INADDR_LOOPBACK); + isc_sockaddr_fromin(&localhost, &lh_addr, LWRES_UDP_PORT); + + result = isc_socket_bind(sock, &localhost); + if (result != ISC_R_SUCCESS) { + isc_log_write(ns_g_lctx, NS_LOGCATEGORY_NETWORK, + NS_LOGMODULE_LWRESD, ISC_LOG_ERROR, + "binding lwres protocol socket to port %d: %s", + LWRES_UDP_PORT, isc_result_totext(result)); + isc_socket_detach(&sock); + return; + } + + lwresd = isc_mem_get(mctx, sizeof(*lwresd)); + if (lwresd == NULL) + fatal("allocating lightweight resolver object", ISC_R_NOMEMORY); + + lwresd->mctx = NULL; + isc_mem_attach(mctx, &lwresd->mctx); + + lwresd->sock = sock; + + lwresd->view = NULL; + dns_view_attach(view, &lwresd->view); + + lwresd->task = NULL; + result = isc_task_create(ns_g_taskmgr, 0, &lwresd->task); + if (result != ISC_R_SUCCESS) + fatal("allocating lightweight resolver task", result); + isc_task_setname(lwresd->task, "lwresd", lwresd); + result = isc_task_onshutdown(lwresd->task, shutdown_lwresd, lwresd); + if (result != ISC_R_SUCCESS) + fatal("allocating lwresd onshutdown event", result); + + lwresd->cmgr = isc_mem_get(lwresd->mctx, + sizeof(ns_lwdclientmgr_t) * NTASKS); + if (lwresd->cmgr == NULL) + fatal("allocating lwresd client manager", ISC_R_NOMEMORY); + + /* + * Create one task for each client manager. + */ + for (i = 0 ; i < NTASKS ; i++) { + char name[16]; + lwresd->cmgr[i].task = NULL; + lwresd->cmgr[i].sock = lwresd->sock; + lwresd->cmgr[i].view = NULL; + lwresd->cmgr[i].flags = 0; + result = isc_task_create(ns_g_taskmgr, 0, + &lwresd->cmgr[i].task); + if (result != ISC_R_SUCCESS) + break; + result = isc_task_onshutdown(lwresd->cmgr[i].task, + ns_lwdclient_shutdown, + &lwresd->cmgr[i]); + if (result != ISC_R_SUCCESS) + break; + ISC_LIST_INIT(lwresd->cmgr[i].idle); + ISC_LIST_INIT(lwresd->cmgr[i].running); + snprintf(name, sizeof(name), "lwd client %d", i); + isc_task_setname(lwresd->cmgr[i].task, name, &lwresd->cmgr[i]); + lwresd->cmgr[i].mctx = lwresd->mctx; + lwresd->cmgr[i].lwctx = NULL; + result = lwres_context_create(&lwresd->cmgr[i].lwctx, + lwresd->mctx, + mem_alloc, mem_free, + LWRES_CONTEXT_SERVERMODE); + if (result != ISC_R_SUCCESS) { + isc_task_detach(&lwresd->cmgr[i].task); + break; + } + dns_view_attach(lwresd->view, &lwresd->cmgr[i].view); + } + INSIST(i > 0); + lwresd->ntasks = i; /* remember how many we managed to create */ + + /* + * Now, run through each client manager and populate it with + * client structures. Do this by creating one receive for each + * task, in a loop, so each task has a chance of getting at least + * one client structure. + */ + for (i = 0 ; i < NRECVS ; i++) { + client = isc_mem_get(lwresd->mctx, + sizeof(ns_lwdclient_t) * lwresd->ntasks); + if (client == NULL) + break; + for (j = 0 ; j < lwresd->ntasks ; j++) + ns_lwdclient_initialize(&client[j], &lwresd->cmgr[j]); + } + INSIST(i > 0); + + /* + * Issue one read request for each task we have. + */ + for (j = 0 ; j < lwresd->ntasks ; j++) { + result = ns_lwdclient_startrecv(&lwresd->cmgr[j]); + INSIST(result == ISC_R_SUCCESS); + } + + lwresd->magic = LWRESD_MAGIC; + *lwresdp = lwresd; +} + +void +ns_lwresd_destroy(ns_lwresd_t **lwresdp) { + ns_lwresd_t *lwresd; + ns_lwdclient_t *client; + + REQUIRE(lwresdp != NULL); + lwresd = *lwresdp; + REQUIRE(VALID_LWRESD(lwresd)); + + /* + * Wait for everything to die off by waiting for the sockets + * to be detached. + */ + isc_socket_detach(&lwresd->sock); + + /* + * Free up memory allocated. This is somewhat magical. We allocated + * the ns_lwdclient_t's in blocks, but the first task always has the + * first pointer. Just loop here, freeing them. + */ + client = ISC_LIST_HEAD(lwresd->cmgr[0].idle); + while (client != NULL) { + ISC_LIST_UNLINK(lwresd->cmgr[0].idle, client, link); + isc_mem_put(lwresd->mctx, client, + sizeof(ns_lwdclient_t) * lwresd->ntasks); + client = ISC_LIST_HEAD(lwresd->cmgr[0].idle); + } + INSIST(ISC_LIST_EMPTY(lwresd->cmgr[0].running)); + + lwresd->magic = 0; + isc_mem_put(lwresd->mctx, lwresd, sizeof(*lwresd)); + *lwresdp = NULL; +} diff --git a/bin/named/main.c b/bin/named/main.c index cc3c8c801d..b1476ee3fb 100644 --- a/bin/named/main.c +++ b/bin/named/main.c @@ -41,9 +41,11 @@ #include #include #include +#include #include static isc_boolean_t want_stats = ISC_FALSE; +static isc_boolean_t lwresd_only = ISC_FALSE; static const char * program_name = "named"; void @@ -176,7 +178,7 @@ parse_command_line(int argc, char *argv[]) { isc_commandline_errprint = ISC_FALSE; while ((ch = isc_commandline_parse(argc, argv, - "c:d:fgn:N:p:st:u:x:")) != + "c:d:fgn:N:p:rst:u:x:")) != -1) { switch (ch) { case 'c': @@ -205,6 +207,9 @@ parse_command_line(int argc, char *argv[]) { isc_commandline_argument); ns_g_port = port; break; + case 'r': + lwresd_only = ISC_TRUE; + break; case 's': /* XXXRTH temporary syntax */ want_stats = ISC_TRUE; @@ -266,6 +271,14 @@ create_managers(void) { return (ISC_R_UNEXPECTED); } + result = dns_dispatchmgr_create(ns_g_mctx, &ns_g_dispatchmgr); + if (result != ISC_R_SUCCESS) { + UNEXPECTED_ERROR(__FILE__, __LINE__, + "dns_dispatchmgr_create() failed: %s", + isc_result_totext(result)); + return (ISC_R_UNEXPECTED); + } + return (ISC_R_SUCCESS); } @@ -276,6 +289,7 @@ destroy_managers(void) { else omapi_lib_destroy(); + dns_dispatchmgr_destroy(&ns_g_dispatchmgr); /* * isc_taskmgr_destroy() will block until all tasks have exited, */ @@ -323,7 +337,16 @@ setup(void) { ns_main_earlyfatal("create_managers() failed: %s", isc_result_totext(result)); - ns_server_create(ns_g_mctx, &ns_g_server); + if (lwresd_only) { + dns_view_t *view = NULL; + result = ns_lwresd_createview(ns_g_mctx, &view); + if (result != ISC_R_SUCCESS) + ns_main_earlyfatal("ns_lwresd_createview() failed: %s", + isc_result_totext(result)); + ns_lwresd_create(ns_g_mctx, view, &ns_g_lwresd); + dns_view_detach(&view); + } else + ns_server_create(ns_g_mctx, &ns_g_server); result = ns_omapi_init(); if (result != ISC_R_SUCCESS) @@ -345,7 +368,10 @@ setup(void) { static void cleanup(void) { destroy_managers(); - ns_server_destroy(&ns_g_server); + if (lwresd_only) + ns_lwresd_destroy(&ns_g_lwresd); + else + ns_server_destroy(&ns_g_server); isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_MAIN, ISC_LOG_NOTICE, "exiting"); ns_log_shutdown(); diff --git a/bin/named/server.c b/bin/named/server.c index 97b671d9e3..eb40068004 100644 --- a/bin/named/server.c +++ b/bin/named/server.c @@ -1443,9 +1443,6 @@ run_server(isc_task_t *task, isc_event_t *event) { isc_event_free(&event); - CHECKFATAL(dns_dispatchmgr_create(ns_g_mctx, &ns_g_dispatchmgr), - "creating dispatch manager"); - CHECKFATAL(ns_clientmgr_create(ns_g_mctx, ns_g_taskmgr, ns_g_timermgr, &server->clientmgr), "creating client manager"); @@ -1498,8 +1495,6 @@ shutdown_server(isc_task_t *task, isc_event_t *event) { ns_interfacemgr_shutdown(server->interfacemgr); ns_interfacemgr_detach(&server->interfacemgr); - dns_dispatchmgr_destroy(&ns_g_dispatchmgr); - dns_zonemgr_shutdown(server->zonemgr); isc_task_detach(&server->task); @@ -1561,6 +1556,7 @@ ns_server_create(isc_mem_t *mctx, ns_server_t **serverp) { server->entropy = NULL; CHECKFATAL(isc_entropy_create(ns_g_mctx, &server->entropy), "initializing entropy pool"); + (void) isc_entropy_createfilesource(server->entropy, "/dev/random", 0); CHECKFATAL(dst_lib_init(ns_g_mctx, server->entropy, 0), "initializing DST");