2
0
mirror of https://gitlab.isc.org/isc-projects/bind9 synced 2025-09-03 16:15:27 +00:00

First pass at merging lwresd into named. Seems to work, but doesn't shut down

properly.  Run named with 'named -r' to test.
This commit is contained in:
Brian Wellington
2000-06-16 01:39:02 +00:00
parent e92d6ed5e7
commit 878d3073b1
15 changed files with 2076 additions and 13 deletions

View File

@@ -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@

View File

@@ -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.

View File

@@ -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);

View File

@@ -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 <isc/event.h>
#include <isc/eventclass.h>
#include <isc/netaddr.h>
#include <isc/sockaddr.h>
#include <isc/types.h>
#include <dns/fixedname.h>
#include <dns/types.h>
#include <lwres/lwres.h>
#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 */

View File

@@ -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 <isc/types.h>
#include <isc/sockaddr.h>
#include <dns/types.h>
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 */

View File

@@ -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 */

View File

@@ -45,6 +45,8 @@ static isc_logmodule_t modules[] = {
{ "xfer-in", 0 },
{ "xfer-out", 0 },
{ "notify", 0 },
{ "omapi", 0 },
{ "lwresd", 0 },
{ NULL, 0 }
};

328
bin/named/lwdclient.c Normal file
View File

@@ -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 <config.h>
#include <isc/socket.h>
#include <isc/string.h>
#include <isc/task.h>
#include <isc/util.h>
#include <dns/view.h>
#include <dns/log.h>
#include <named/types.h>
#include <named/lwdclient.h>
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);
}

80
bin/named/lwderror.c Normal file
View File

@@ -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 <config.h>
#include <isc/socket.h>
#include <isc/util.h>
#include <named/types.h>
#include <named/lwdclient.h>
/*
* 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);
}

561
bin/named/lwdgabn.c Normal file
View File

@@ -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 <config.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/lwdclient.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 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);
}

292
bin/named/lwdgnba.c Normal file
View File

@@ -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 <config.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/byaddr.h>
#include <dns/result.h>
#include <named/types.h>
#include <named/lwdclient.h>
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);
}

86
bin/named/lwdnoop.c Normal file
View File

@@ -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 <config.h>
#include <isc/socket.h>
#include <isc/util.h>
#include <named/types.h>
#include <named/lwdclient.h>
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);
}

430
bin/named/lwresd.c Normal file
View File

@@ -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 <config.h>
#include <stdlib.h>
#include <isc/app.h>
#include <isc/magic.h>
#include <isc/mem.h>
#include <isc/string.h>
#include <isc/task.h>
#include <isc/timer.h>
#include <isc/util.h>
#include <dns/cache.h>
#include <dns/db.h>
#include <dns/dispatch.h>
#include <dns/log.h>
#include <dns/resolver.h>
#include <dns/result.h>
#include <dns/rootns.h>
#include <dns/view.h>
#include <named/globals.h>
#include <named/log.h>
#include <named/lwresd.h>
#include <named/lwdclient.h>
#include <named/server.h>
#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;
}

View File

@@ -41,9 +41,11 @@
#include <named/omapi.h>
#include <named/os.h>
#include <named/server.h>
#include <named/lwresd.h>
#include <named/main.h>
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,6 +337,15 @@ setup(void) {
ns_main_earlyfatal("create_managers() failed: %s",
isc_result_totext(result));
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();
@@ -345,6 +368,9 @@ setup(void) {
static void
cleanup(void) {
destroy_managers();
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");

View File

@@ -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");