mirror of
https://gitlab.isc.org/isc-projects/bind9
synced 2025-09-03 08:05:21 +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:
@@ -22,7 +22,8 @@ top_srcdir = @top_srcdir@
|
|||||||
@BIND9_INCLUDES@
|
@BIND9_INCLUDES@
|
||||||
|
|
||||||
CINCLUDES = -I${srcdir}/include -I${srcdir}/unix/include \
|
CINCLUDES = -I${srcdir}/include -I${srcdir}/unix/include \
|
||||||
${DNS_INCLUDES} ${ISC_INCLUDES} ${OMAPI_INCLUDES}
|
${LWRES_INCLUDES} ${DNS_INCLUDES} ${ISC_INCLUDES} \
|
||||||
|
${OMAPI_INCLUDES}
|
||||||
|
|
||||||
CDEFINES =
|
CDEFINES =
|
||||||
CWARNINGS =
|
CWARNINGS =
|
||||||
@@ -30,14 +31,16 @@ CWARNINGS =
|
|||||||
OMAPILIBS = ../../lib/omapi/libomapi.@A@
|
OMAPILIBS = ../../lib/omapi/libomapi.@A@
|
||||||
DNSLIBS = ../../lib/dns/libdns.@A@ @DNS_OPENSSL_LIBS@
|
DNSLIBS = ../../lib/dns/libdns.@A@ @DNS_OPENSSL_LIBS@
|
||||||
ISCLIBS = ../../lib/isc/libisc.@A@
|
ISCLIBS = ../../lib/isc/libisc.@A@
|
||||||
|
LWRESLIBS = ../../lib/lwres/liblwres.@A@
|
||||||
|
|
||||||
OMAPIDEPLIBS = ../../lib/omapi/libomapi.@A@
|
OMAPIDEPLIBS = ../../lib/omapi/libomapi.@A@
|
||||||
DNSDEPLIBS = ../../lib/dns/libdns.@A@
|
DNSDEPLIBS = ../../lib/dns/libdns.@A@
|
||||||
ISCDEPLIBS = ../../lib/isc/libisc.@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
|
SUBDIRS = unix
|
||||||
|
|
||||||
@@ -45,13 +48,17 @@ TARGETS = named
|
|||||||
|
|
||||||
OBJS = client.@O@ interfacemgr.@O@ listenlist.@O@ \
|
OBJS = client.@O@ interfacemgr.@O@ listenlist.@O@ \
|
||||||
log.@O@ logconf.@O@ main.@O@ notify.@O@ omapi.@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@
|
UOBJS = unix/os.@O@
|
||||||
|
|
||||||
SRCS = client.c interfacemgr.c listenlist.c \
|
SRCS = client.c interfacemgr.c listenlist.c \
|
||||||
log.c logconf.c main.c notify.c omapi.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@
|
@BIND9_MAKE_RULES@
|
||||||
|
|
||||||
|
@@ -52,6 +52,7 @@ EXTERN const char * ns_g_version INIT(VERSION);
|
|||||||
EXTERN in_port_t ns_g_port INIT(0);
|
EXTERN in_port_t ns_g_port INIT(0);
|
||||||
|
|
||||||
EXTERN ns_server_t * ns_g_server INIT(NULL);
|
EXTERN ns_server_t * ns_g_server INIT(NULL);
|
||||||
|
EXTERN ns_lwresd_t * ns_g_lwresd INIT(NULL);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Logging.
|
* Logging.
|
||||||
|
@@ -45,6 +45,7 @@
|
|||||||
#define NS_LOGMODULE_XFER_OUT (&ns_g_modules[7])
|
#define NS_LOGMODULE_XFER_OUT (&ns_g_modules[7])
|
||||||
#define NS_LOGMODULE_NOTIFY (&ns_g_modules[8])
|
#define NS_LOGMODULE_NOTIFY (&ns_g_modules[8])
|
||||||
#define NS_LOGMODULE_OMAPI (&ns_g_modules[9])
|
#define NS_LOGMODULE_OMAPI (&ns_g_modules[9])
|
||||||
|
#define NS_LOGMODULE_LWRESD (&ns_g_modules[10])
|
||||||
|
|
||||||
isc_result_t
|
isc_result_t
|
||||||
ns_log_init(isc_boolean_t safe);
|
ns_log_init(isc_boolean_t safe);
|
||||||
|
205
bin/named/include/named/lwdclient.h
Normal file
205
bin/named/include/named/lwdclient.h
Normal 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 */
|
45
bin/named/include/named/lwresd.h
Normal file
45
bin/named/include/named/lwresd.h
Normal 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 */
|
@@ -26,5 +26,8 @@ typedef struct ns_query ns_query_t;
|
|||||||
typedef struct ns_server ns_server_t;
|
typedef struct ns_server ns_server_t;
|
||||||
typedef struct ns_interface ns_interface_t;
|
typedef struct ns_interface ns_interface_t;
|
||||||
typedef struct ns_interfacemgr ns_interfacemgr_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 */
|
#endif /* NAMED_TYPES_H */
|
||||||
|
@@ -45,6 +45,8 @@ static isc_logmodule_t modules[] = {
|
|||||||
{ "xfer-in", 0 },
|
{ "xfer-in", 0 },
|
||||||
{ "xfer-out", 0 },
|
{ "xfer-out", 0 },
|
||||||
{ "notify", 0 },
|
{ "notify", 0 },
|
||||||
|
{ "omapi", 0 },
|
||||||
|
{ "lwresd", 0 },
|
||||||
{ NULL, 0 }
|
{ NULL, 0 }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
328
bin/named/lwdclient.c
Normal file
328
bin/named/lwdclient.c
Normal 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
80
bin/named/lwderror.c
Normal 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
561
bin/named/lwdgabn.c
Normal 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
292
bin/named/lwdgnba.c
Normal 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
86
bin/named/lwdnoop.c
Normal 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
430
bin/named/lwresd.c
Normal 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;
|
||||||
|
}
|
@@ -41,9 +41,11 @@
|
|||||||
#include <named/omapi.h>
|
#include <named/omapi.h>
|
||||||
#include <named/os.h>
|
#include <named/os.h>
|
||||||
#include <named/server.h>
|
#include <named/server.h>
|
||||||
|
#include <named/lwresd.h>
|
||||||
#include <named/main.h>
|
#include <named/main.h>
|
||||||
|
|
||||||
static isc_boolean_t want_stats = ISC_FALSE;
|
static isc_boolean_t want_stats = ISC_FALSE;
|
||||||
|
static isc_boolean_t lwresd_only = ISC_FALSE;
|
||||||
static const char * program_name = "named";
|
static const char * program_name = "named";
|
||||||
|
|
||||||
void
|
void
|
||||||
@@ -176,7 +178,7 @@ parse_command_line(int argc, char *argv[]) {
|
|||||||
|
|
||||||
isc_commandline_errprint = ISC_FALSE;
|
isc_commandline_errprint = ISC_FALSE;
|
||||||
while ((ch = isc_commandline_parse(argc, argv,
|
while ((ch = isc_commandline_parse(argc, argv,
|
||||||
"c:d:fgn:N:p:st:u:x:")) !=
|
"c:d:fgn:N:p:rst:u:x:")) !=
|
||||||
-1) {
|
-1) {
|
||||||
switch (ch) {
|
switch (ch) {
|
||||||
case 'c':
|
case 'c':
|
||||||
@@ -205,6 +207,9 @@ parse_command_line(int argc, char *argv[]) {
|
|||||||
isc_commandline_argument);
|
isc_commandline_argument);
|
||||||
ns_g_port = port;
|
ns_g_port = port;
|
||||||
break;
|
break;
|
||||||
|
case 'r':
|
||||||
|
lwresd_only = ISC_TRUE;
|
||||||
|
break;
|
||||||
case 's':
|
case 's':
|
||||||
/* XXXRTH temporary syntax */
|
/* XXXRTH temporary syntax */
|
||||||
want_stats = ISC_TRUE;
|
want_stats = ISC_TRUE;
|
||||||
@@ -266,6 +271,14 @@ create_managers(void) {
|
|||||||
return (ISC_R_UNEXPECTED);
|
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);
|
return (ISC_R_SUCCESS);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -276,6 +289,7 @@ destroy_managers(void) {
|
|||||||
else
|
else
|
||||||
omapi_lib_destroy();
|
omapi_lib_destroy();
|
||||||
|
|
||||||
|
dns_dispatchmgr_destroy(&ns_g_dispatchmgr);
|
||||||
/*
|
/*
|
||||||
* isc_taskmgr_destroy() will block until all tasks have exited,
|
* isc_taskmgr_destroy() will block until all tasks have exited,
|
||||||
*/
|
*/
|
||||||
@@ -323,7 +337,16 @@ setup(void) {
|
|||||||
ns_main_earlyfatal("create_managers() failed: %s",
|
ns_main_earlyfatal("create_managers() failed: %s",
|
||||||
isc_result_totext(result));
|
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();
|
result = ns_omapi_init();
|
||||||
if (result != ISC_R_SUCCESS)
|
if (result != ISC_R_SUCCESS)
|
||||||
@@ -345,7 +368,10 @@ setup(void) {
|
|||||||
static void
|
static void
|
||||||
cleanup(void) {
|
cleanup(void) {
|
||||||
destroy_managers();
|
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_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_MAIN,
|
||||||
ISC_LOG_NOTICE, "exiting");
|
ISC_LOG_NOTICE, "exiting");
|
||||||
ns_log_shutdown();
|
ns_log_shutdown();
|
||||||
|
@@ -1443,9 +1443,6 @@ run_server(isc_task_t *task, isc_event_t *event) {
|
|||||||
|
|
||||||
isc_event_free(&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,
|
CHECKFATAL(ns_clientmgr_create(ns_g_mctx, ns_g_taskmgr, ns_g_timermgr,
|
||||||
&server->clientmgr),
|
&server->clientmgr),
|
||||||
"creating client manager");
|
"creating client manager");
|
||||||
@@ -1498,8 +1495,6 @@ shutdown_server(isc_task_t *task, isc_event_t *event) {
|
|||||||
ns_interfacemgr_shutdown(server->interfacemgr);
|
ns_interfacemgr_shutdown(server->interfacemgr);
|
||||||
ns_interfacemgr_detach(&server->interfacemgr);
|
ns_interfacemgr_detach(&server->interfacemgr);
|
||||||
|
|
||||||
dns_dispatchmgr_destroy(&ns_g_dispatchmgr);
|
|
||||||
|
|
||||||
dns_zonemgr_shutdown(server->zonemgr);
|
dns_zonemgr_shutdown(server->zonemgr);
|
||||||
|
|
||||||
isc_task_detach(&server->task);
|
isc_task_detach(&server->task);
|
||||||
@@ -1561,6 +1556,7 @@ ns_server_create(isc_mem_t *mctx, ns_server_t **serverp) {
|
|||||||
server->entropy = NULL;
|
server->entropy = NULL;
|
||||||
CHECKFATAL(isc_entropy_create(ns_g_mctx, &server->entropy),
|
CHECKFATAL(isc_entropy_create(ns_g_mctx, &server->entropy),
|
||||||
"initializing entropy pool");
|
"initializing entropy pool");
|
||||||
|
(void) isc_entropy_createfilesource(server->entropy, "/dev/random", 0);
|
||||||
|
|
||||||
CHECKFATAL(dst_lib_init(ns_g_mctx, server->entropy, 0),
|
CHECKFATAL(dst_lib_init(ns_g_mctx, server->entropy, 0),
|
||||||
"initializing DST");
|
"initializing DST");
|
||||||
|
Reference in New Issue
Block a user