summaryrefslogtreecommitdiff
path: root/bin/named
diff options
context:
space:
mode:
authorInternet Software Consortium, Inc <@isc.org>2007-09-07 14:08:17 -0600
committerLaMont Jones <lamont@debian.org>2007-09-07 14:08:17 -0600
commit6257efc35455318993208bef65a551ac6039f51f (patch)
tree7a1422be299ecd74d6c04e81e9ef638d3d5be388 /bin/named
parentab47e90612dcdb02c4b134cfb1be0697007c0dac (diff)
downloadbind9-6257efc35455318993208bef65a551ac6039f51f.tar.gz
9.0.0b2
Diffstat (limited to 'bin/named')
-rw-r--r--bin/named/Makefile.in16
-rw-r--r--bin/named/client.c732
-rw-r--r--bin/named/include/named/client.h55
-rw-r--r--bin/named/include/named/globals.h8
-rw-r--r--bin/named/include/named/interfacemgr.h4
-rw-r--r--bin/named/include/named/log.h11
-rw-r--r--bin/named/include/named/logconf.h32
-rw-r--r--bin/named/include/named/omapi.h3
-rw-r--r--bin/named/include/named/server.h15
-rw-r--r--bin/named/interfacemgr.c151
-rw-r--r--bin/named/log.c72
-rw-r--r--bin/named/logconf.c183
-rw-r--r--bin/named/main.c66
-rw-r--r--bin/named/notify.c6
-rw-r--r--bin/named/omapi.c100
-rw-r--r--bin/named/query.c45
-rw-r--r--bin/named/server.c391
-rw-r--r--bin/named/update.c96
-rw-r--r--bin/named/xfrout.c90
19 files changed, 1543 insertions, 533 deletions
diff --git a/bin/named/Makefile.in b/bin/named/Makefile.in
index 6f5f10c0..98db3754 100644
--- a/bin/named/Makefile.in
+++ b/bin/named/Makefile.in
@@ -39,30 +39,32 @@ SUBDIRS = unix
TARGETS = named
OBJS = client.@O@ interfacemgr.@O@ listenlist.@O@ \
- log.@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@
UOBJS = unix/os.@O@
SRCS = client.c interfacemgr.c listenlist.c \
- log.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
@BIND9_MAKE_RULES@
main.@O@: main.c
- ${CC} ${ALL_CFLAGS} -DVERSION=\"${VERSION}\" -c ${srcdir}/main.c
+ ${CC} ${ALL_CFLAGS} -DVERSION=\"${VERSION}\" \
+ -DNS_LOCALSTATEDIR=\"${localstatedir}\" \
+ -DNS_SYSCONFDIR=\"${sysconfdir}\" -c ${srcdir}/main.c
named: ${OBJS} ${UOBJS} ${DEPLIBS}
- ${LIBTOOL} ${CC} -o $@ ${OBJS} ${UOBJS} ${LIBS}
+ ${LIBTOOL} ${CC} ${CFLAGS} -o $@ ${OBJS} ${UOBJS} ${LIBS}
clean distclean::
rm -f ${TARGETS}
installdirs:
- if [ ! -d ${sbindir} ]; then \
- mkdir ${sbindir}; \
+ if [ ! -d ${DESTDIR}${sbindir} ]; then \
+ mkdir ${DESTDIR}${sbindir}; \
fi
install:: named installdirs
- ${LIBTOOL} ${INSTALL_PROGRAM} named ${sbindir}
+ ${LIBTOOL} ${INSTALL_PROGRAM} named ${DESTDIR}${sbindir}
diff --git a/bin/named/client.c b/bin/named/client.c
index 6866c6a8..7061ce05 100644
--- a/bin/named/client.c
+++ b/bin/named/client.c
@@ -17,6 +17,8 @@
#include <config.h>
+#include <string.h>
+
#include <isc/assertions.h>
#include <isc/mem.h>
#include <isc/mutex.h>
@@ -33,17 +35,31 @@
#include <dns/rdatalist.h>
#include <dns/rdataset.h>
#include <dns/view.h>
-#include <dns/xfrin.h>
#include <dns/zone.h>
-#include <named/globals.h>
#include <named/client.h>
+#include <named/globals.h>
+#include <named/interfacemgr.h>
#include <named/log.h>
+#include <named/notify.h>
#include <named/query.h>
#include <named/server.h>
#include <named/update.h>
-#include <named/notify.h>
-#include <named/interfacemgr.h>
+
+/***
+ *** Client
+ ***/
+
+/*
+ * Important note!
+ *
+ * All client state changes, other than that from idle to listening, occur
+ * as a result of events. This guarantees serialization and avoids the
+ * need for locking.
+ *
+ * If a routine is ever created that allows someone other than the client's
+ * task to change the client, then the client will have to be locked.
+ */
#define NS_CLIENT_TRACE
#ifdef NS_CLIENT_TRACE
@@ -73,53 +89,116 @@ struct ns_clientmgr {
/* Locked by lock. */
isc_boolean_t exiting;
client_list_t active; /* Active clients */
- client_list_t inactive; /* Recycling center */
+ client_list_t inactive; /* To be recycled */
};
#define MANAGER_MAGIC 0x4E53436DU /* NSCm */
#define VALID_MANAGER(m) ((m) != NULL && \
(m)->magic == MANAGER_MAGIC)
+/*
+ * Client object states. Ordering is significant: higher-numbered
+ * states are generally "more active", meaning that the client can
+ * have more dynamically allocated data, outstanding events, etc.
+ * In the list below, any such properties listed for state N
+ * also apply to any state > N.
+ *
+ * To force the client into a less active state, set client->newstate
+ * to that state and call exit_check(). This will cause any
+ * activities defined for higher-numbered states to be aborted.
+ */
-static void client_read(ns_client_t *client);
-static void client_accept(ns_client_t *client);
-static void clientmgr_destroy(ns_clientmgr_t *manager);
-
+#define NS_CLIENTSTATE_FREED 0
+/*
+ * The client object no longer exists.
+ */
-/***
- *** Client
- ***/
+#define NS_CLIENTSTATE_INACTIVE 1
+/*
+ * The client object exists and has a task and timer.
+ * Its "query" struct and sendbuf are initialized.
+ * It is on the client manager's list of inactive clients.
+ * It has a message and OPT, both in the reset state.
+ */
+#define NS_CLIENTSTATE_READY 2
/*
- * Important note!
+ * The client object is either a TCP or a UDP one, and
+ * it is associated with a network interface. It is on the
+ * client manager's list of active clients.
*
- * All client state changes, other than that from idle to listening, occur
- * as a result of events. This guarantees serialization and avoids the
- * need for locking.
+ * If it is a TCP client object, it has a TCP listener socket
+ * and an outstading TCP listen request.
*
- * If a routine is ever created that allows someone other than the client's
- * task to change the client, then the client will have to be locked.
+ * If it is a UDP client object, it is associated with a
+ * dispatch and has an outstanding dispatch request.
+ */
+
+#define NS_CLIENTSTATE_READING 3
+/*
+ * The client object is a TCP client object that has received
+ * a connection. It has a tcpsocket, tcpmsg, TCP quota, and an
+ * outstanding TCP read request. This state is not used for
+ * UDP client objects.
*/
+#define NS_CLIENTSTATE_WORKING 4
+/*
+ * The client object has received a request and is working
+ * on it. It has a view, and it may have any of a non-reset OPT,
+ * recursion quota, and an outstanding write request. If it
+ * is a UDP client object, it has a dispatch event.
+ */
+
+#define NS_CLIENTSTATE_MAX 9
+/*
+ * Sentinel value used to indicate "no state". When client->newstate
+ * has this value, we are not attempting to exit the current state.
+ * Must be greater than any valid state.
+ */
+
+
+static void client_read(ns_client_t *client);
+static void client_accept(ns_client_t *client);
+static void clientmgr_destroy(ns_clientmgr_t *manager);
+static isc_boolean_t exit_check(ns_client_t *client);
+static void ns_client_endrequest(ns_client_t *client);
+static void ns_client_checkactive(ns_client_t *client);
+
+/*
+ * Format a human-readable representation of the socket address '*sa'
+ * into the character array 'array', which is of size 'size'.
+ * The resulting string is guaranteed to be null-terminated.
+ */
static void
-release_quotas(ns_client_t *client) {
- if (client->tcpquota != NULL)
- isc_quota_detach(&client->tcpquota);
- if (client->recursionquota != NULL)
- isc_quota_detach(&client->recursionquota);
+sockaddr_format(isc_sockaddr_t *sa, char *array, unsigned int size)
+{
+ isc_result_t result;
+ isc_buffer_t buf;
+ isc_buffer_init(&buf, array, size, ISC_BUFFERTYPE_TEXT);
+ result = isc_sockaddr_totext(sa, &buf);
+ if (result != ISC_R_SUCCESS) {
+ strncpy(array, "<unknown address>", size);
+ array[size-1] = '\0';
+ }
}
/*
- * Enter an inactive state identical to that of a newly created client.
+ * Enter the inactive state.
+ *
+ * Requires:
+ * No requests are outstanding.
*/
static void
-deactivate(ns_client_t *client)
-{
- CTRACE("deactivate");
-
+client_deactivate(ns_client_t *client) {
+ REQUIRE(NS_CLIENT_VALID(client));
if (client->interface)
ns_interface_detach(&client->interface);
+ INSIST(client->naccepts == 0);
+ if (client->tcplistener != NULL)
+ isc_socket_detach(&client->tcplistener);
+
if (client->dispentry != NULL) {
dns_dispatchevent_t **deventp;
if (client->dispevent != NULL)
@@ -130,31 +209,27 @@ deactivate(ns_client_t *client)
&client->dispentry,
deventp);
}
-
if (client->dispatch != NULL)
dns_dispatch_detach(&client->dispatch);
-
- INSIST(client->naccepts == 0);
- if (client->tcplistener != NULL)
- isc_socket_detach(&client->tcplistener);
-
- if (client->tcpmsg_valid) {
- dns_tcpmsg_invalidate(&client->tcpmsg);
- client->tcpmsg_valid = ISC_FALSE;
- }
- if (client->tcpsocket != NULL)
- isc_socket_detach(&client->tcpsocket);
client->attributes = 0;
client->mortal = ISC_FALSE;
+
+ LOCK(&client->manager->lock);
+ ISC_LIST_UNLINK(client->manager->active, client, link);
+ ISC_LIST_APPEND(client->manager->inactive, client, link);
+ client->list = &client->manager->inactive;
+ UNLOCK(&client->manager->lock);
}
/*
- * Free a client immediately if possible, otherwise start
- * shutting it down and postpone freeing to later.
+ * Clean up a client object and free its memory.
+ * Requires:
+ * The client is in the inactive state.
*/
+
static void
-maybe_free(ns_client_t *client) {
+client_free(ns_client_t *client) {
isc_boolean_t need_clientmgr_destroy = ISC_FALSE;
ns_clientmgr_t *manager = NULL;
@@ -166,40 +241,8 @@ maybe_free(ns_client_t *client) {
* set up. Thus, we have no outstanding shutdown
* event at this point.
*/
- REQUIRE(client->shuttingdown == ISC_TRUE);
-
- if (client->naccepts > 0)
- isc_socket_cancel(client->tcplistener, client->task,
- ISC_SOCKCANCEL_ACCEPT);
- if (client->nreads > 0)
- dns_tcpmsg_cancelread(&client->tcpmsg);
- if (client->nsends > 0) {
- isc_socket_t *socket;
- if (TCP_CLIENT(client))
- socket = client->tcpsocket;
- else
- socket = dns_dispatch_getsocket(client->dispatch);
- isc_socket_cancel(socket, client->task, ISC_SOCKCANCEL_SEND);
- }
-
- /*
- * We need to detach from the view early, because when shutting
- * down the server, resolver shutdown does not begin until
- * the view refcount goes to zero.
- */
- if (client->view != NULL)
- dns_view_detach(&client->view);
+ REQUIRE(client->state == NS_CLIENTSTATE_INACTIVE);
- if (!(client->nreads == 0 && client->naccepts == 0 &&
- client->nsends == 0 && client->nwaiting == 0)) {
- /* Still waiting for events. */
- return;
- }
-
- /* We have received our last event. */
-
- deactivate(client);
-
ns_query_free(client);
isc_mem_put(client->mctx, client->sendbuf, SEND_BUFFER_SIZE);
isc_timer_detach(&client->timer);
@@ -218,14 +261,12 @@ maybe_free(ns_client_t *client) {
ISC_LIST_UNLINK(*client->list, client, link);
client->list = NULL;
if (manager->exiting &&
- (ISC_LIST_EMPTY(manager->active) &&
- ISC_LIST_EMPTY(manager->inactive)))
- need_clientmgr_destroy = ISC_TRUE;
+ ISC_LIST_EMPTY(manager->active) &&
+ ISC_LIST_EMPTY(manager->inactive))
+ need_clientmgr_destroy = ISC_TRUE;
UNLOCK(&manager->lock);
}
- release_quotas(client);
-
CTRACE("free");
client->magic = 0;
isc_mem_put(client->mctx, client, sizeof *client);
@@ -234,6 +275,176 @@ maybe_free(ns_client_t *client) {
clientmgr_destroy(manager);
}
+static void
+set_timeout(ns_client_t *client, unsigned int seconds) {
+ isc_result_t result;
+ isc_interval_t interval;
+ isc_interval_set(&interval, seconds, 0);
+ result = isc_timer_reset(client->timer, isc_timertype_once, NULL,
+ &interval, ISC_FALSE);
+ if (result != ISC_R_SUCCESS) {
+ isc_log_write(dns_lctx, NS_LOGCATEGORY_CLIENT,
+ NS_LOGMODULE_CLIENT, ISC_LOG_ERROR,
+ "setting timouet: %s",
+ isc_result_totext(result));
+ /* Continue anyway. */
+ }
+}
+
+/*
+ * Check for a deactivation or shutdown request and take appropriate
+ * action. Returns ISC_TRUE if either is in progress; in this case
+ * the caller must no longer use the client object as it may have been
+ * freed.
+ */
+static isc_boolean_t
+exit_check(ns_client_t *client) {
+ REQUIRE(NS_CLIENT_VALID(client));
+
+ if (client->state <= client->newstate)
+ return (ISC_FALSE); /* Business as usual. */
+
+ INSIST(client->newstate < NS_CLIENTSTATE_WORKING);
+
+ /*
+ * We need to detach from the view early when shutting down
+ * the server to break the following vicious circle:
+ *
+ * - The resolver will not shut down until the view refcount is zero
+ * - The view refcount does not go to zero until all clients detach
+ * - The client does not detach from the view until references is zero
+ * - references does not go to zero until the resolver has shut down
+ *
+ */
+ if (client->newstate == NS_CLIENTSTATE_FREED && client->view != NULL)
+ dns_view_detach(&client->view);
+
+ if (client->state == NS_CLIENTSTATE_WORKING) {
+ INSIST(client->newstate <= NS_CLIENTSTATE_READING);
+ /*
+ * We are trying to abort request processing.
+ */
+ if (client->nsends > 0) {
+ isc_socket_t *socket;
+ if (TCP_CLIENT(client))
+ socket = client->tcpsocket;
+ else
+ socket =
+ dns_dispatch_getsocket(client->dispatch);
+ isc_socket_cancel(socket, client->task,
+ ISC_SOCKCANCEL_SEND);
+ }
+
+ if (! (client->nsends == 0 && client->references == 0)) {
+ /*
+ * Still waiting for I/O cancel completion.
+ * or lingering references.
+ */
+ return (ISC_TRUE);
+ }
+ /*
+ * I/O cancel is complete. Burn down all state
+ * related to the current request.
+ */
+ ns_client_endrequest(client);
+
+ client->state = NS_CLIENTSTATE_READING;
+ if (NS_CLIENTSTATE_READING == client->newstate) {
+ client_read(client);
+ client->newstate = NS_CLIENTSTATE_MAX;
+ return (ISC_TRUE); /* We're done. */
+ }
+ }
+
+ if (client->state == NS_CLIENTSTATE_READING) {
+ /*
+ * We are trying to abort the current TCP connection,
+ * if any.
+ */
+ INSIST(client->newstate <= NS_CLIENTSTATE_READY);
+ CTRACE("closetcp");
+ if (client->nreads > 0)
+ dns_tcpmsg_cancelread(&client->tcpmsg);
+ if (! client->nreads == 0) {
+ /* Still waiting for read cancel completion. */
+ return (ISC_TRUE);
+ }
+
+ if (client->tcpmsg_valid) {
+ dns_tcpmsg_invalidate(&client->tcpmsg);
+ client->tcpmsg_valid = ISC_FALSE;
+ }
+ if (client->tcpsocket != NULL)
+ isc_socket_detach(&client->tcpsocket);
+
+ if (client->tcpquota != NULL)
+ isc_quota_detach(&client->tcpquota);
+
+ (void) isc_timer_reset(client->timer, isc_timertype_inactive,
+ NULL, NULL, ISC_TRUE);
+
+ client->state = NS_CLIENTSTATE_READY;
+
+ /*
+ * Now the client is ready to accept a new TCP connection
+ * or UDP request, but we may have enough clients doing
+ * that already. Check whether this client needs to remain
+ * active and force it to go inactive if not.
+ */
+ ns_client_checkactive(client);
+
+ if (NS_CLIENTSTATE_READY == client->newstate) {
+ if (TCP_CLIENT(client)) {
+ client_accept(client);
+ } else {
+ /*
+ * Give the processed dispatch event back to
+ * the dispatch. This tells the dispatch
+ * that we are ready to receive the next event.
+ */
+ dns_dispatch_freeevent(client->dispatch,
+ client->dispentry,
+ &client->dispevent);
+ }
+ client->newstate = NS_CLIENTSTATE_MAX;
+ return (ISC_TRUE);
+ }
+ }
+
+ if (client->state == NS_CLIENTSTATE_READY) {
+ INSIST(client->newstate <= NS_CLIENTSTATE_INACTIVE);
+ /*
+ * We are trying to enter the inactive state.
+ */
+ if (client->naccepts > 0)
+ isc_socket_cancel(client->tcplistener, client->task,
+ ISC_SOCKCANCEL_ACCEPT);
+
+ if (! (client->naccepts == 0)) {
+ /* Still waiting for accept cancel completion. */
+ return (ISC_TRUE);
+ }
+ /* Accept cancel is complete. */
+ client_deactivate(client);
+ client->state = NS_CLIENTSTATE_INACTIVE;
+ if (client->state == client->newstate) {
+ client->newstate = NS_CLIENTSTATE_MAX;
+ return (ISC_TRUE); /* We're done. */
+ }
+ }
+
+ if (client->state == NS_CLIENTSTATE_INACTIVE) {
+ INSIST(client->newstate == NS_CLIENTSTATE_FREED);
+ /*
+ * We are trying to free the client.
+ */
+ client_free(client);
+ return (ISC_TRUE);
+ }
+
+ return (ISC_TRUE);
+}
+
/*
* The client's task has received a shutdown event.
*/
@@ -249,41 +460,34 @@ client_shutdown(isc_task_t *task, isc_event_t *event) {
CTRACE("shutdown");
- client->shuttingdown = ISC_TRUE;
-
- if (client->shutdown != NULL)
- (client->shutdown)(client->shutdown_arg);
+ isc_event_free(&event);
- maybe_free(client);
+ if (client->shutdown != NULL) {
+ (client->shutdown)(client->shutdown_arg, ISC_R_SHUTTINGDOWN);
+ client->shutdown = NULL;
+ client->shutdown_arg = NULL;
+ }
- isc_event_free(&event);
+ client->newstate = NS_CLIENTSTATE_FREED;
+ (void) exit_check(client);
}
-/*
- * Wrap up after a finished client request and prepare for
- * handling the next one.
- */
-void
-ns_client_next(ns_client_t *client, isc_result_t result) {
- REQUIRE(NS_CLIENT_VALID(client));
-
- CTRACE("next");
+static void
+ns_client_endrequest(ns_client_t *client) {
INSIST(client->naccepts == 0);
INSIST(client->nreads == 0);
INSIST(client->nsends == 0);
INSIST(client->lockview == NULL);
+ CTRACE("endrequest");
+
+ INSIST(client->state == NS_CLIENTSTATE_WORKING);
if (client->next != NULL) {
- (client->next)(client, result);
+ (client->next)(client);
client->next = NULL;
}
- /*
- * XXXRTH If result != ISC_R_SUCCESS:
- * Log result if there is interest in doing so.
- */
-
if (client->view != NULL)
dns_view_detach(&client->view);
if (client->opt != NULL) {
@@ -295,13 +499,18 @@ ns_client_next(ns_client_t *client, isc_result_t result) {
client->udpsize = 512;
dns_message_reset(client->message, DNS_MESSAGE_INTENTPARSE);
- release_quotas(client);
+ if (client->recursionquota != NULL)
+ isc_quota_detach(&client->recursionquota);
+}
+static void
+ns_client_checkactive(ns_client_t *client) {
if (client->mortal) {
/*
- * This client object is supposed to die now, but if we
- * have fewer client objects than planned due to
- * quota exhaustion, don't.
+ * This client object should normally go inactive
+ * at this point, but if we have fewer active client
+ * objects than desired due to earlier quota exhaustion,
+ * keep it active to make up for the shortage.
*/
isc_boolean_t need_another_client = ISC_FALSE;
if (TCP_CLIENT(client)) {
@@ -322,52 +531,41 @@ ns_client_next(ns_client_t *client, isc_result_t result) {
/*
* We don't need this client object. Recycle it.
*/
- LOCK(&client->manager->lock);
- ISC_LIST_UNLINK(client->manager->active, client, link);
- deactivate(client);
- ISC_LIST_APPEND(client->manager->inactive, client, link);
- client->list = &client->manager->inactive;
- UNLOCK(&client->manager->lock);
- return;
+ if (client->newstate >= NS_CLIENTSTATE_INACTIVE)
+ client->newstate = NS_CLIENTSTATE_INACTIVE;
}
- client->mortal = ISC_FALSE;
}
+}
- if (client->dispevent != NULL) {
- /*
- * Give the processed dispatch event back to the dispatch.
- * This tells the dispatch that we are ready to receive
- * the next event.
- */
- dns_dispatch_freeevent(client->dispatch, client->dispentry,
- &client->dispevent);
- } else if (TCP_CLIENT(client)) {
- if (result == ISC_R_SUCCESS) {
- client_read(client);
- } else {
- /*
- * There was an error processing a TCP request.
- * It may have have left the connection out of
- * sync. Close the connection and listen for a
- * new one.
- */
- if (client->tcpsocket != NULL) {
- /*
- * There should be no outstanding read
- * request on the TCP socket at this point,
- * therefore invalidating the tcpmsg is safe.
- */
- INSIST(client->nreads == 0);
- INSIST(client->tcpmsg_valid == ISC_TRUE);
- dns_tcpmsg_invalidate(&client->tcpmsg);
- client->tcpmsg_valid = ISC_FALSE;
- isc_socket_detach(&client->tcpsocket);
- }
- client_accept(client);
- }
+void
+ns_client_next(ns_client_t *client, isc_result_t result) {
+ int newstate;
+ REQUIRE(NS_CLIENT_VALID(client));
+ REQUIRE(client->state == NS_CLIENTSTATE_WORKING);
+ CTRACE("next");
+
+ if (result != ISC_R_SUCCESS) {
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_SECURITY,
+ NS_LOGMODULE_CLIENT, ISC_LOG_DEBUG(3),
+ "request failed: %s", isc_result_totext(result));
}
+
+ /*
+ * An error processing a TCP request may have left
+ * the connection out of sync. To be safe, we always
+ * sever the connection when result != ISC_R_SUCCESS.
+ */
+ if (result == ISC_R_SUCCESS && TCP_CLIENT(client))
+ newstate = NS_CLIENTSTATE_READING;
+ else
+ newstate = NS_CLIENTSTATE_READY;
+
+ if (client->newstate > newstate)
+ client->newstate = newstate;
+ (void) exit_check(client);
}
+
static void
client_senddone(isc_task_t *task, isc_event_t *event) {
ns_client_t *client;
@@ -386,10 +584,8 @@ client_senddone(isc_task_t *task, isc_event_t *event) {
isc_event_free(&event);
- if (client->shuttingdown) {
- maybe_free(client);
+ if (exit_check(client))
return;
- }
ns_client_next(client, ISC_R_SUCCESS);
}
@@ -403,6 +599,7 @@ ns_client_send(ns_client_t *client) {
isc_region_t r;
isc_socket_t *socket;
isc_sockaddr_t *address;
+ struct in6_pktinfo *pktinfo;
unsigned int bufsize = 512;
REQUIRE(NS_CLIENT_VALID(client));
@@ -478,7 +675,7 @@ ns_client_send(ns_client_t *client) {
socket = client->tcpsocket;
address = NULL;
isc_buffer_used(&buffer, &r);
- isc_buffer_putuint16(&tcpbuffer, (isc_uint16_t)r.length);
+ isc_buffer_putuint16(&tcpbuffer, (isc_uint16_t) r.length);
isc_buffer_add(&tcpbuffer, r.length);
isc_buffer_used(&tcpbuffer, &r);
} else {
@@ -487,8 +684,12 @@ ns_client_send(ns_client_t *client) {
isc_buffer_used(&buffer, &r);
}
CTRACE("sendto");
+ if ((client->attributes & NS_CLIENTATTR_PKTINFO) != 0)
+ pktinfo = &client->pktinfo;
+ else
+ pktinfo = NULL;
result = isc_socket_sendto(socket, &r, client->task, client_senddone,
- client, address, NULL);
+ client, address, pktinfo);
if (result == ISC_R_SUCCESS) {
client->nsends++;
return;
@@ -528,12 +729,6 @@ ns_client_error(ns_client_t *client, isc_result_t result) {
*/
result = dns_message_reply(message, ISC_FALSE);
if (result != ISC_R_SUCCESS) {
- /*
- * There's no hope of replying to this request.
- *
- * XXXRTH Mark this client to that if it is a
- * TCP session, the session will be closed.
- */
ns_client_next(client, result);
return;
}
@@ -606,6 +801,7 @@ client_request(isc_task_t *task, isc_event_t *event) {
dns_view_t *view;
dns_rdataset_t *opt;
isc_boolean_t ra; /* Recursion available. */
+ char peerbuf[256];
REQUIRE(event != NULL);
client = event->arg;
@@ -614,34 +810,59 @@ client_request(isc_task_t *task, isc_event_t *event) {
INSIST(client->recursionquota == NULL);
+ INSIST(client->state ==
+ TCP_CLIENT(client) ?
+ NS_CLIENTSTATE_READING :
+ NS_CLIENTSTATE_READY);
+
RWLOCK(&ns_g_server->conflock, isc_rwlocktype_read);
dns_zonemgr_lockconf(ns_g_server->zonemgr, isc_rwlocktype_read);
-
+
if (event->type == DNS_EVENT_DISPATCH) {
+ INSIST(!TCP_CLIENT(client));
devent = (dns_dispatchevent_t *)event;
REQUIRE(client->dispentry != NULL);
client->dispevent = devent;
buffer = &devent->buffer;
result = devent->result;
+ client->peeraddr = devent->addr;
+ if ((devent->attributes & DNS_DISPATCHATTR_PKTINFO) != 0) {
+ client->attributes |= NS_CLIENTATTR_PKTINFO;
+ client->pktinfo = devent->pktinfo;
+ printf("client: interface %u\n",
+ client->pktinfo.ipi6_ifindex);
+ } else {
+ client->attributes &= ~NS_CLIENTATTR_PKTINFO;
+ }
} else {
+ INSIST(TCP_CLIENT(client));
REQUIRE(event->type == DNS_EVENT_TCPMSG);
REQUIRE(event->sender == &client->tcpmsg);
buffer = &client->tcpmsg.buffer;
result = client->tcpmsg.result;
INSIST(client->nreads == 1);
+ /*
+ * client->peeraddr was set when the connection was accepted.
+ */
client->nreads--;
}
- CTRACE("request");
+ sockaddr_format(&client->peeraddr, peerbuf, sizeof(peerbuf));
+ isc_log_write(ns_g_lctx, NS_LOGCATEGORY_CLIENT,
+ NS_LOGMODULE_CLIENT, ISC_LOG_DEBUG(3),
+ "client %p: %s request from %s",
+ client, TCP_CLIENT(client) ? "TCP" : "UDP",
+ peerbuf);
- if (client->shuttingdown) {
- maybe_free(client);
+ if (exit_check(client))
goto cleanup_serverlock;
- }
+ client->state = NS_CLIENTSTATE_WORKING;
isc_stdtime_get(&client->requesttime);
client->now = client->requesttime;
+ set_timeout(client, 60);
+
if (result != ISC_R_SUCCESS) {
if (TCP_CLIENT(client))
ns_client_next(client, result);
@@ -785,11 +1006,9 @@ client_request(isc_task_t *task, isc_event_t *event) {
if (ns_g_server->recursion == ISC_TRUE) {
/* XXX ACL should be view specific. */
/* XXX this will log too much too early */
- result = dns_acl_checkrequest(client->signer,
- ns_client_getsockaddr(client),
- "recursion",
- ns_g_server->recursionacl,
- NULL, ISC_TRUE);
+ result = ns_client_checkacl(client, "recursion",
+ ns_g_server->recursionacl,
+ ISC_TRUE);
if (result != DNS_R_SUCCESS)
ra = ISC_FALSE;
}
@@ -846,7 +1065,15 @@ client_timeout(isc_task_t *task, isc_event_t *event) {
isc_event_free(&event);
- ns_client_next(client, ISC_R_TIMEDOUT);
+ if (client->shutdown != NULL) {
+ (client->shutdown)(client->shutdown_arg, ISC_R_TIMEDOUT);
+ client->shutdown = NULL;
+ client->shutdown_arg = NULL;
+ }
+
+ if (client->newstate > NS_CLIENTSTATE_READY)
+ client->newstate = NS_CLIENTSTATE_READY;
+ (void) exit_check(client);
}
static isc_result_t
@@ -900,11 +1127,12 @@ client_create(ns_clientmgr_t *manager, ns_client_t **clientp)
client->magic = NS_CLIENT_MAGIC;
client->mctx = manager->mctx;
client->manager = NULL;
- client->shuttingdown = ISC_FALSE;
+ client->state = NS_CLIENTSTATE_INACTIVE;
+ client->newstate = NS_CLIENTSTATE_MAX;
client->naccepts = 0;
client->nreads = 0;
client->nsends = 0;
- client->nwaiting = 0;
+ client->references = 0;
client->attributes = 0;
client->view = NULL;
client->lockview = NULL;
@@ -965,15 +1193,27 @@ client_create(ns_clientmgr_t *manager, ns_client_t **clientp)
static void
client_read(ns_client_t *client) {
isc_result_t result;
-
+
CTRACE("read");
result = dns_tcpmsg_readmessage(&client->tcpmsg, client->task,
client_request, client);
if (result != ISC_R_SUCCESS)
- ns_client_next(client, result);
+ goto fail;
+
+ /*
+ * Set a timeout to limit the amount of time we will wait
+ * for a request on this TCP connection.
+ */
+ set_timeout(client, 30);
+
+ client->state = client->newstate = NS_CLIENTSTATE_READING;
INSIST(client->nreads == 0);
client->nreads++;
+
+ return;
+ fail:
+ ns_client_next(client, result);
}
static void
@@ -981,11 +1221,14 @@ client_newconn(isc_task_t *task, isc_event_t *event) {
ns_client_t *client = event->arg;
isc_socket_newconnev_t *nevent = (isc_socket_newconnev_t *)event;
isc_result_t result;
-
+ char peerbuf[256];
+
REQUIRE(event->type == ISC_SOCKEVENT_NEWCONN);
REQUIRE(NS_CLIENT_VALID(client));
REQUIRE(client->task == task);
+ INSIST(client->state == NS_CLIENTSTATE_READY);
+
CTRACE("newconn");
INSIST(client->naccepts == 1);
@@ -996,10 +1239,42 @@ client_newconn(isc_task_t *task, isc_event_t *event) {
client->interface->ntcpcurrent--;
UNLOCK(&client->interface->lock);
- if (client->shuttingdown) {
- maybe_free(client);
- } else if (nevent->result == ISC_R_SUCCESS) {
+ /*
+ * We must take ownership of the new socket before the exit
+ * check to make sure it gets destroyed if we decide to exit.
+ */
+ if (nevent->result == ISC_R_SUCCESS) {
client->tcpsocket = nevent->newsocket;
+ client->state = NS_CLIENTSTATE_READING;
+
+ (void) isc_socket_getpeername(client->tcpsocket,
+ &client->peeraddr);
+ sockaddr_format(&client->peeraddr, peerbuf, sizeof(peerbuf));
+ isc_log_write(ns_g_lctx, NS_LOGCATEGORY_CLIENT,
+ NS_LOGMODULE_CLIENT, ISC_LOG_DEBUG(3),
+ "client %p: TCP connection from %s",
+ client, peerbuf);
+ } else {
+ /*
+ * XXXRTH What should we do? We're trying to accept but
+ * it didn't work. If we just give up, then TCP
+ * service may eventually stop.
+ *
+ * For now, we just go idle.
+ *
+ * Going idle is probably the right thing if the
+ * I/O was canceled.
+ */
+ isc_log_write(ns_g_lctx, NS_LOGCATEGORY_CLIENT,
+ NS_LOGMODULE_CLIENT, ISC_LOG_DEBUG(3),
+ "client %p: accept failed: %s", client,
+ isc_result_totext(nevent->result));
+ }
+
+ if (exit_check(client))
+ goto freeevent;
+
+ if (nevent->result == ISC_R_SUCCESS) {
INSIST(client->tcpmsg_valid == ISC_FALSE);
dns_tcpmsg_init(client->mctx, client->tcpsocket,
&client->tcpmsg);
@@ -1022,18 +1297,9 @@ client_newconn(isc_task_t *task, isc_event_t *event) {
isc_result_totext(result));
}
client_read(client);
- } else {
- /*
- * XXXRTH What should we do? We're trying to accept but
- * it didn't work. If we just give up, then TCP
- * service may eventually stop.
- *
- * For now, we just go idle.
- *
- * Going idle is probably the right thing if the
- * I/O was canceled.
- */
}
+
+ freeevent:
isc_event_free(&event);
}
@@ -1066,21 +1332,25 @@ client_accept(ns_client_t *client) {
}
void
-ns_client_wait(ns_client_t *client) {
- client->nwaiting++;
+ns_client_attach(ns_client_t *source, ns_client_t **targetp) {
+ REQUIRE(NS_CLIENT_VALID(source));
+ REQUIRE(targetp != NULL && *targetp == NULL);
+ source->references++;
+ *targetp = source;
}
-isc_boolean_t
-ns_client_shuttingdown(ns_client_t *client) {
- return (client->shuttingdown);
+void
+ns_client_detach(ns_client_t **clientp) {
+ ns_client_t *client = *clientp;
+ client->references--;
+ INSIST(client->references >= 0);
+ *clientp = NULL;
+ (void) exit_check(client);
}
-void
-ns_client_unwait(ns_client_t *client) {
- client->nwaiting--;
- INSIST(client->nwaiting >= 0);
- if (client->shuttingdown)
- maybe_free(client);
+isc_boolean_t
+ns_client_shuttingdown(ns_client_t *client) {
+ return (client->newstate == NS_CLIENTSTATE_FREED);
}
isc_result_t
@@ -1231,22 +1501,30 @@ ns_clientmgr_createclients(ns_clientmgr_t *manager, unsigned int n,
break;
}
+ client->state = NS_CLIENTSTATE_READY;
+
ns_interface_attach(ifp, &client->interface);
if (tcp) {
client->attributes |= NS_CLIENTATTR_TCP;
- isc_socket_attach(ifp->tcpsocket, &client->tcplistener);
+ isc_socket_attach(ifp->tcpsocket,
+ &client->tcplistener);
client_accept(client);
} else {
- dns_dispatch_attach(ifp->udpdispatch, &client->dispatch);
+ dns_dispatch_attach(ifp->udpdispatch,
+ &client->dispatch);
result = dns_dispatch_addrequest(client->dispatch,
client->task,
client_request,
- client, &client->dispentry);
+ client,
+ &client->dispentry);
if (result != ISC_R_SUCCESS) {
- isc_log_write(dns_lctx, DNS_LOGCATEGORY_SECURITY,
- NS_LOGMODULE_CLIENT, ISC_LOG_DEBUG(3),
- "dns_dispatch_addrequest() failed: %s",
+ isc_log_write(dns_lctx,
+ DNS_LOGCATEGORY_SECURITY,
+ NS_LOGMODULE_CLIENT,
+ ISC_LOG_DEBUG(3),
+ "dns_dispatch_addrequest() "
+ "failed: %s",
isc_result_totext(result));
isc_task_shutdown(client->task);
break;
@@ -1271,8 +1549,46 @@ ns_clientmgr_createclients(ns_clientmgr_t *manager, unsigned int n,
isc_sockaddr_t *
ns_client_getsockaddr(ns_client_t *client) {
- if (TCP_CLIENT(client))
- return (&client->tcpmsg.address);
- else
- return (&client->dispevent->addr);
+ return (&client->peeraddr);
}
+
+isc_result_t
+ns_client_checkacl(ns_client_t *client,
+ const char *opname, dns_acl_t *acl,
+ isc_boolean_t default_allow)
+{
+ isc_result_t result;
+ int match;
+ isc_netaddr_t netaddr;
+
+ if (acl == NULL) {
+ if (default_allow)
+ goto allow;
+ else
+ goto deny;
+ }
+
+ isc_netaddr_fromsockaddr(&netaddr, &client->peeraddr);
+
+ result = dns_acl_match(&netaddr, client->signer, acl,
+ &ns_g_server->aclenv,
+ &match, NULL);
+ if (result != DNS_R_SUCCESS)
+ goto deny; /* Internal error, already logged. */
+ if (match > 0)
+ goto allow;
+ goto deny; /* Negative match or no match. */
+
+ allow:
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_SECURITY,
+ NS_LOGMODULE_CLIENT, ISC_LOG_DEBUG(3),
+ "%s approved", opname);
+ return (DNS_R_SUCCESS);
+
+ deny:
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_SECURITY,
+ NS_LOGMODULE_CLIENT, ISC_LOG_ERROR,
+ "%s denied", opname);
+ return (DNS_R_REFUSED);
+}
+
diff --git a/bin/named/include/named/client.h b/bin/named/include/named/client.h
index 8e04ce30..b2637cf4 100644
--- a/bin/named/include/named/client.h
+++ b/bin/named/include/named/client.h
@@ -77,16 +77,18 @@
***/
typedef ISC_LIST(ns_client_t) client_list_t;
-
+
struct ns_client {
unsigned int magic;
isc_mem_t * mctx;
ns_clientmgr_t * manager;
- isc_boolean_t shuttingdown;
+ int state;
+ int newstate;
+ isc_boolean_t disconnect;
int naccepts;
int nreads;
int nsends;
- int nwaiting;
+ int references;
unsigned int attributes;
isc_task_t * task;
dns_view_t * view;
@@ -103,8 +105,8 @@ struct ns_client {
unsigned char * sendbuf;
dns_rdataset_t * opt;
isc_uint16_t udpsize;
- void (*next)(ns_client_t *, isc_result_t);
- void (*shutdown)(void *arg);
+ void (*next)(ns_client_t *);
+ void (*shutdown)(void *arg, isc_result_t result);
void *shutdown_arg;
ns_query_t query;
isc_stdtime_t requesttime;
@@ -115,6 +117,8 @@ struct ns_client {
isc_quota_t *tcpquota;
isc_quota_t *recursionquota;
ns_interface_t *interface;
+ isc_sockaddr_t peeraddr;
+ struct in6_pktinfo pktinfo;
ISC_LINK(ns_client_t) link;
client_list_t *list; /* The list 'link' is part of,
or NULL if not on any list. */
@@ -126,6 +130,7 @@ struct ns_client {
#define NS_CLIENTATTR_TCP 0x01
#define NS_CLIENTATTR_RA 0x02 /* Client gets recusive service */
+#define NS_CLIENTATTR_PKTINFO 0x04 /* pktinfo is valid */
/***
*** Functions
@@ -165,16 +170,15 @@ ns_client_shuttingdown(ns_client_t *client);
*/
void
-ns_client_wait(ns_client_t *client);
+ns_client_attach(ns_client_t *source, ns_client_t **target);
/*
- * Increment reference count. The client object will
- * not be destroyed while the reference count is nonzero.
+ * Attach '*targetp' to 'source'.
*/
void
-ns_client_unwait(ns_client_t *client);
+ns_client_detach(ns_client_t **clientp);
/*
- * Decrement reference count.
+ * Detach '*clientp' from its client.
*/
isc_result_t
@@ -215,4 +219,35 @@ ns_client_getsockaddr(ns_client_t *client);
* currently being processed.
*/
+isc_result_t
+ns_client_checkacl(ns_client_t *client,
+ const char *opname, dns_acl_t *acl,
+ isc_boolean_t default_allow);
+/*
+ * Convenience function for client request ACL checking.
+ *
+ * Check the current client request against 'acl'. If 'acl'
+ * is NULL, allow the request iff 'default_allow' is ISC_TRUE.
+ * Log the outcome of the check if deemed appropriate.
+ * Log messages will refer to the request as an 'opname' request.
+ *
+ * Notes:
+ * This is appropriate for checking allow-update,
+ * allow-query, allow-transfer, etc. It is not appropriate
+ * for checking the blackhole list because we treat positive
+ * matches as "allow" and negative matches as "deny"; in
+ * the case of the blackhole list this would be backwards.
+ *
+ * Requires:
+ * 'client' points to a valid client.
+ * 'opname' points to a null-terminated string.
+ * 'acl' points to a valid ACL, or is NULL.
+ *
+ * Returns:
+ * ISC_R_SUCCESS if the request should be allowed
+ * ISC_R_REFUSED if the request should be denied
+ * No other return values are possible.
+ */
+
+
#endif /* NS_CLIENT_H */
diff --git a/bin/named/include/named/globals.h b/bin/named/include/named/globals.h
index ec65b810..66681e06 100644
--- a/bin/named/include/named/globals.h
+++ b/bin/named/include/named/globals.h
@@ -66,7 +66,8 @@ EXTERN unsigned int ns_g_debuglevel INIT(0);
/*
* Current config information
*/
-EXTERN const char * ns_g_conffile INIT("/etc/named.conf");
+EXTERN const char * ns_g_conffile INIT(NS_SYSCONFDIR
+ "/named.conf");
/*
* Misc.
@@ -74,9 +75,10 @@ EXTERN const char * ns_g_conffile INIT("/etc/named.conf");
EXTERN isc_boolean_t ns_g_coreok INIT(ISC_TRUE);
EXTERN const char * ns_g_chrootdir INIT(NULL);
EXTERN isc_boolean_t ns_g_foreground INIT(ISC_FALSE);
+EXTERN isc_boolean_t ns_g_logstderr INIT(ISC_FALSE);
-EXTERN const char * ns_g_defaultpidfile INIT("/var/run/named.pid");
-EXTERN char * ns_g_pidfile INIT(NULL);
+EXTERN char * ns_g_defaultpidfile INIT(NS_LOCALSTATEDIR
+ "/run/named.pid");
EXTERN const char * ns_g_username INIT(NULL);
/*
diff --git a/bin/named/include/named/interfacemgr.h b/bin/named/include/named/interfacemgr.h
index 4121db89..df896633 100644
--- a/bin/named/include/named/interfacemgr.h
+++ b/bin/named/include/named/interfacemgr.h
@@ -71,6 +71,7 @@ struct ns_interface {
int references; /* Locked */
unsigned int generation; /* Generation number. */
isc_sockaddr_t addr; /* Address and port. */
+ char name[32]; /* Null terminated. */
isc_socket_t * udpsocket; /* UDP socket. */
dns_dispatch_t * udpdispatch; /* UDP dispatcher. */
isc_socket_t * tcpsocket; /* TCP socket. */
@@ -129,6 +130,9 @@ ns_interfacemgr_findudpdispatcher(ns_interfacemgr_t *mgr,
* Find a UDP dispatcher matching 'address', if it exists.
*/
+dns_aclenv_t *
+ns_interfacemgr_getaclenv(ns_interfacemgr_t *mgr);
+
void
ns_interface_attach(ns_interface_t *source,
ns_interface_t **target);
diff --git a/bin/named/include/named/log.h b/bin/named/include/named/log.h
index c9a7bb72..74aac91d 100644
--- a/bin/named/include/named/log.h
+++ b/bin/named/include/named/log.h
@@ -25,13 +25,13 @@
#include <named/globals.h>
-#define NS_LOGCATEGORY_GENERAL (&ns_g_categories[0])
+/* Unused slot */
#define NS_LOGCATEGORY_CLIENT (&ns_g_categories[1])
#define NS_LOGCATEGORY_NETWORK (&ns_g_categories[2])
#define NS_LOGCATEGORY_UPDATE (&ns_g_categories[3])
-#define NS_LOGCATEGORY_XFER_IN (&ns_g_categories[4])
-#define NS_LOGCATEGORY_XFER_OUT (&ns_g_categories[5])
-#define NS_LOGCATEGORY_NOTIFY (&ns_g_categories[6])
+
+/* Backwards compatibility. */
+#define NS_LOGCATEGORY_GENERAL ISC_LOGCATEGORY_GENERAL
#define NS_LOGMODULE_MAIN (&ns_g_modules[0])
#define NS_LOGMODULE_CLIENT (&ns_g_modules[1])
@@ -47,6 +47,9 @@
isc_result_t
ns_log_init(void);
+isc_result_t
+ns_log_setdefaults(isc_logconfig_t *lcfg);
+
void
ns_log_shutdown(void);
diff --git a/bin/named/include/named/logconf.h b/bin/named/include/named/logconf.h
new file mode 100644
index 00000000..d456a951
--- /dev/null
+++ b/bin/named/include/named/logconf.h
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 1999, 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 NS_LOGCONF_H
+#define NS_LOGCONF_H 1
+
+#include <isc/log.h>
+
+#include <dns/conflog.h>
+
+isc_result_t
+ns_log_configure(isc_logconfig_t *logconf, dns_c_logginglist_t *clog);
+/*
+ * Set up the logging configuration in '*logconf' according to
+ * the named.conf data in 'clog'.
+ */
+
+#endif /* NS_LOGCONF_H */
diff --git a/bin/named/include/named/omapi.h b/bin/named/include/named/omapi.h
index 142f6344..828106e4 100644
--- a/bin/named/include/named/omapi.h
+++ b/bin/named/include/named/omapi.h
@@ -29,5 +29,8 @@
#define NS_OMAPI_COMMAND_RELOADZONES "reload-zones"
isc_result_t
+ns_omapi_init(void);
+
+isc_result_t
ns_omapi_listen(omapi_object_t **managerp);
diff --git a/bin/named/include/named/server.h b/bin/named/include/named/server.h
index 3022b05d..56ce3389 100644
--- a/bin/named/include/named/server.h
+++ b/bin/named/include/named/server.h
@@ -24,6 +24,7 @@
#include <isc/quota.h>
#include <dns/types.h>
+#include <dns/acl.h>
#define NS_EVENTCLASS ISC_EVENTCLASS(0x4E43)
#define NS_EVENT_RELOAD (NS_EVENTCLASS + 0)
@@ -46,10 +47,13 @@ struct ns_server {
dns_transfer_format_t transfer_format;
dns_acl_t * queryacl;
dns_acl_t * recursionacl;
- dns_acl_t * transferacl;
isc_quota_t xfroutquota;
isc_quota_t tcpquota;
isc_quota_t recursionquota;
+ isc_boolean_t provide_ixfr;
+
+ /* Not really configurable, but covered by conflock. */
+ dns_aclenv_t aclenv;
/* Server data structures. */
dns_zonemgr_t * zonemgr;
@@ -58,9 +62,12 @@ struct ns_server {
ns_interfacemgr_t * interfacemgr;
dns_db_t * roothints;
dns_tkey_ctx_t * tkeyctx;
- isc_sockaddr_t querysrc_address;
- dns_dispatch_t * querysrc_dispatch;
-
+ isc_sockaddr_t querysrc_addressv4;
+ dns_dispatch_t * querysrc_dispatchv4;
+ isc_sockaddr_t querysrc_addressv6;
+ dns_dispatch_t * querysrc_dispatchv6;
+ isc_timer_t * interface_timer;
+
isc_mutex_t reload_event_lock;
isc_event_t * reload_event;
};
diff --git a/bin/named/interfacemgr.c b/bin/named/interfacemgr.c
index 0407ab89..b33ff244 100644
--- a/bin/named/interfacemgr.c
+++ b/bin/named/interfacemgr.c
@@ -58,11 +58,30 @@ struct ns_interfacemgr {
ns_clientmgr_t * clientmgr; /* Client manager. */
unsigned int generation; /* Current generation no. */
ns_listenlist_t * listenon;
+ dns_aclenv_t aclenv; /* Localhost/localnets ACLs */
ISC_LIST(ns_interface_t) interfaces; /* List of interfaces. */
};
static void purge_old_interfaces(ns_interfacemgr_t *mgr);
+/*
+ * Format a human-readable representation of the socket address '*sa'
+ * into the character array 'array', which is of size 'size'.
+ * The resulting string is guaranteed to be null-terminated.
+ */
+static void
+sockaddr_format(isc_sockaddr_t *sa, char *array, unsigned int size)
+{
+ isc_result_t result;
+ isc_buffer_t buf;
+ isc_buffer_init(&buf, array, size, ISC_BUFFERTYPE_TEXT);
+ result = isc_sockaddr_totext(sa, &buf);
+ if (result != ISC_R_SUCCESS) {
+ strncpy(array, "<unknown address>", size);
+ array[size-1] = '\0';
+ }
+}
+
isc_result_t
ns_interfacemgr_create(isc_mem_t *mctx, isc_taskmgr_t *taskmgr,
isc_socketmgr_t *socketmgr, ns_clientmgr_t *clientmgr,
@@ -81,7 +100,7 @@ ns_interfacemgr_create(isc_mem_t *mctx, isc_taskmgr_t *taskmgr,
result = isc_mutex_init(&mgr->lock);
if (result != ISC_R_SUCCESS)
- goto cleanup;
+ goto cleanup_mem;
mgr->mctx = mctx;
mgr->taskmgr = taskmgr;
@@ -94,14 +113,20 @@ ns_interfacemgr_create(isc_mem_t *mctx, isc_taskmgr_t *taskmgr,
result = ns_listenlist_default(mctx, ns_g_port,
&mgr->listenon);
if (result != DNS_R_SUCCESS)
- goto cleanup;
+ goto cleanup_mem;
+
+ result = dns_aclenv_init(mctx, &mgr->aclenv);
+ if (result != ISC_R_SUCCESS)
+ goto cleanup_listenon;
mgr->references = 1;
mgr->magic = IFMGR_MAGIC;
*mgrp = mgr;
return (DNS_R_SUCCESS);
- cleanup:
+ cleanup_listenon:
+ ns_listenlist_detach(&mgr->listenon);
+ cleanup_mem:
isc_mem_put(mctx, mgr, sizeof(*mgr));
return (result);
}
@@ -110,12 +135,19 @@ static void
ns_interfacemgr_destroy(ns_interfacemgr_t *mgr)
{
REQUIRE(NS_INTERFACEMGR_VALID(mgr));
+ dns_aclenv_destroy(&mgr->aclenv);
ns_listenlist_detach(&mgr->listenon);
isc_mutex_destroy(&mgr->lock);
mgr->magic = 0;
isc_mem_put(mgr->mctx, mgr, sizeof *mgr);
}
+dns_aclenv_t *
+ns_interfacemgr_getaclenv(ns_interfacemgr_t *mgr)
+{
+ return (&mgr->aclenv);
+}
+
void
ns_interfacemgr_attach(ns_interfacemgr_t *source,
ns_interfacemgr_t **target)
@@ -166,7 +198,7 @@ ns_interfacemgr_shutdown(ns_interfacemgr_t *mgr)
static isc_result_t
ns_interface_create(ns_interfacemgr_t *mgr, isc_sockaddr_t *addr,
- ns_interface_t **ifpret)
+ char *name, ns_interface_t **ifpret)
{
ns_interface_t *ifp;
isc_result_t result;
@@ -178,6 +210,8 @@ ns_interface_create(ns_interfacemgr_t *mgr, isc_sockaddr_t *addr,
ifp->mgr = NULL;
ifp->generation = mgr->generation;
ifp->addr = *addr;
+ strncpy(ifp->name, name, sizeof(ifp->name));
+ ifp->name[sizeof(ifp->name)-1] = '\0';
result = isc_mutex_init(&ifp->lock);
if (result != ISC_R_SUCCESS)
@@ -333,13 +367,13 @@ ns_interface_accepttcp(ns_interface_t *ifp) {
static isc_result_t
ns_interface_setup(ns_interfacemgr_t *mgr, isc_sockaddr_t *addr,
- ns_interface_t **ifpret)
+ char *name, ns_interface_t **ifpret)
{
isc_result_t result;
ns_interface_t *ifp = NULL;
REQUIRE(ifpret != NULL && *ifpret == NULL);
- result = ns_interface_create(mgr, addr, &ifp);
+ result = ns_interface_create(mgr, addr, name, &ifp);
if (result != DNS_R_SUCCESS)
return (result);
@@ -446,12 +480,30 @@ purge_old_interfaces(ns_interfacemgr_t *mgr) {
INSIST(NS_INTERFACE_VALID(ifp));
next = ISC_LIST_NEXT(ifp, link);
if (ifp->generation != mgr->generation) {
+ char sabuf[256];
ISC_LIST_UNLINK(ifp->mgr->interfaces, ifp, link);
+ sockaddr_format(&ifp->addr, sabuf, sizeof(sabuf));
+ isc_log_write(IFMGR_COMMON_LOGARGS,
+ ISC_LOG_INFO,
+ "no longer listening on %s", sabuf);
ns_interface_detach(&ifp);
}
}
}
+static isc_result_t
+clearacl(isc_mem_t *mctx, dns_acl_t **aclp) {
+ dns_acl_t *newacl = NULL;
+ isc_result_t result;
+ result = dns_acl_create(mctx, 10, &newacl);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+ dns_acl_detach(aclp);
+ dns_acl_attach(newacl, aclp);
+ dns_acl_detach(&newacl);
+ return (ISC_R_SUCCESS);
+}
+
static void
do_ipv4(ns_interfacemgr_t *mgr) {
isc_interfaceiter_t *iter = NULL;
@@ -461,6 +513,13 @@ do_ipv4(ns_interfacemgr_t *mgr) {
if (result != ISC_R_SUCCESS)
return;
+ result = clearacl(mgr->mctx, &mgr->aclenv.localhost);
+ if (result != ISC_R_SUCCESS)
+ goto cleanup_iter;
+ result = clearacl(mgr->mctx, &mgr->aclenv.localnets);
+ if (result != ISC_R_SUCCESS)
+ goto cleanup_iter;
+
for (result = isc_interfaceiter_first(iter);
result == ISC_R_SUCCESS;
result = isc_interfaceiter_next(iter))
@@ -468,12 +527,9 @@ do_ipv4(ns_interfacemgr_t *mgr) {
ns_interface_t *ifp;
isc_interface_t interface;
ns_listenelt_t *le;
+ dns_aclelement_t elt;
+ unsigned int prefixlen;
- /*
- * XXX insert code to match against named.conf
- * "listen-on" statements here. Also build list of
- * local addresses and local networks.
- */
result = isc_interfaceiter_current(iter, &interface);
if (result != ISC_R_SUCCESS)
break;
@@ -481,55 +537,70 @@ do_ipv4(ns_interfacemgr_t *mgr) {
if (interface.address.family != AF_INET)
continue;
+ if ((interface.flags & INTERFACE_F_UP) == 0)
+ continue;
+
+ result = isc_netaddr_masktoprefixlen(&interface.netmask,
+ &prefixlen);
+ if (result != ISC_R_SUCCESS)
+ goto ignore_interface;
+ elt.type = dns_aclelementtype_ipprefix;
+ elt.negative = ISC_FALSE;
+ elt.u.ip_prefix.address = interface.address;
+ elt.u.ip_prefix.prefixlen = prefixlen;
+ /* XXX suppress duplicates */
+ result = dns_acl_appendelement(mgr->aclenv.localnets, &elt);
+ if (result != ISC_R_SUCCESS)
+ goto ignore_interface;
+ elt.u.ip_prefix.prefixlen = 32;
+ result = dns_acl_appendelement(mgr->aclenv.localhost, &elt);
+ if (result != ISC_R_SUCCESS)
+ goto ignore_interface;
+
for (le = ISC_LIST_HEAD(mgr->listenon->elts);
le != NULL;
le = ISC_LIST_NEXT(le, link))
{
int match;
- isc_sockaddr_t listen_addr;
- char buf[128];
- const char *addrstr;
+ isc_netaddr_t listen_netaddr;
+ isc_sockaddr_t listen_sockaddr;
/*
* Construct a socket address for this IP/port
* combination.
*/
- isc_sockaddr_fromin(&listen_addr,
- &interface.address.type.in,
- le->port);
-
- /*
- * Construct a human-readable version of same.
- */
- addrstr = inet_ntop(listen_addr.type.sin.sin_family,
- &listen_addr.type.sin.sin_addr,
- buf, sizeof(buf));
- if (addrstr == NULL)
- addrstr = "(bad address)";
+ isc_netaddr_fromin(&listen_netaddr,
+ &interface.address.type.in);
+ isc_sockaddr_fromnetaddr(&listen_sockaddr,
+ &listen_netaddr,
+ le->port);
/*
* See if the address matches the listen-on statement;
* if not, ignore the interface.
*/
- result = dns_acl_match(&listen_addr, NULL,
- le->acl, &match, NULL);
+ result = dns_acl_match(&listen_netaddr, NULL,
+ le->acl, &mgr->aclenv,
+ &match, NULL);
if (match <= 0)
continue;
- ifp = find_matching_interface(mgr, &listen_addr);
+ ifp = find_matching_interface(mgr, &listen_sockaddr);
if (ifp != NULL) {
ifp->generation = mgr->generation;
} else {
+ char sabuf[256];
+ sockaddr_format(&listen_sockaddr,
+ sabuf, sizeof(sabuf));
isc_log_write(IFMGR_COMMON_LOGARGS,
ISC_LOG_INFO,
"listening on IPv4 interface "
- "%s, %s port %u",
- interface.name, addrstr,
- ntohs(listen_addr.type.
- sin.sin_port));
+ "%s, %s", interface.name, sabuf);
result = ns_interface_setup(mgr,
- &listen_addr, &ifp);
+ &listen_sockaddr,
+ interface.name,
+ &ifp);
if (result != DNS_R_SUCCESS) {
isc_log_write(IFMGR_COMMON_LOGARGS,
ISC_LOG_ERROR,
@@ -541,12 +612,20 @@ do_ipv4(ns_interfacemgr_t *mgr) {
}
}
+ continue;
+
+ ignore_interface:
+ isc_log_write(IFMGR_COMMON_LOGARGS,
+ ISC_LOG_ERROR,
+ "ignoring IPv4 interface %s: %s",
+ interface.name, isc_result_totext(result));
+ continue;
}
if (result != ISC_R_NOMORE)
UNEXPECTED_ERROR(__FILE__, __LINE__,
"IPv4: interface iteration failed: %s",
isc_result_totext(result));
-
+ cleanup_iter:
isc_interfaceiter_destroy(&iter);
}
@@ -567,7 +646,7 @@ do_ipv6(ns_interfacemgr_t *mgr) {
isc_log_write(IFMGR_COMMON_LOGARGS, ISC_LOG_INFO,
"listening on IPv6 interfaces, port %u",
ns_g_port);
- result = ns_interface_setup(mgr, &listen_addr, &ifp);
+ result = ns_interface_setup(mgr, &listen_addr, "<any>", &ifp);
if (result != DNS_R_SUCCESS) {
isc_log_write(IFMGR_COMMON_LOGARGS,
ISC_LOG_ERROR,
diff --git a/bin/named/log.c b/bin/named/log.c
index fdfd61d2..f9c11bb9 100644
--- a/bin/named/log.c
+++ b/bin/named/log.c
@@ -31,13 +31,10 @@
* #define to <named/log.h>.
*/
static isc_logcategory_t categories[] = {
- { "general", 0 },
+ { "", 0 },
{ "client", 0 },
{ "network", 0 },
{ "update", 0 },
- { "xfer-in", 0 },
- { "xfer-out", 0 },
- { "notify", 0 },
{ NULL, 0 }
};
@@ -61,8 +58,7 @@ static isc_logmodule_t modules[] = {
isc_result_t
ns_log_init(void) {
isc_result_t result;
- isc_logdestination_t destination;
- unsigned int flags;
+ isc_logconfig_t *lcfg;
ns_g_categories = categories;
ns_g_modules = modules;
@@ -75,42 +71,58 @@ ns_log_init(void) {
/*
* Setup a logging context.
*/
- result = isc_log_create(ns_g_mctx, &ns_g_lctx);
+ result = isc_log_create(ns_g_mctx, &ns_g_lctx, &lcfg);
if (result != ISC_R_SUCCESS)
return (result);
- result = isc_log_registercategories(ns_g_lctx, ns_g_categories);
- if (result != ISC_R_SUCCESS)
- goto cleanup;
+
+ isc_log_registercategories(ns_g_lctx, ns_g_categories);
isc_log_registermodules(ns_g_lctx, ns_g_modules);
- result = dns_log_init(ns_g_lctx);
+ dns_log_init(ns_g_lctx);
+
+ result = ns_log_setdefaults(lcfg);
if (result != ISC_R_SUCCESS)
goto cleanup;
+ return (ISC_R_SUCCESS);
+
+ cleanup:
+ isc_log_destroy(&ns_g_lctx);
+
+ return (result);
+}
+
+isc_result_t
+ns_log_setdefaults(isc_logconfig_t *lcfg) {
+ isc_result_t result;
+ isc_logdestination_t destination;
+
/*
- * Create and install the default channel.
+ * By default, the logging library makes "default_debug" log to
+ * stderr. In BIND, we want to override this and log to named.run
+ * instead, unless the the -g option was given.
*/
- if (ns_g_foreground) {
- destination.file.stream = stderr;
- destination.file.name = NULL;
+ if (! ns_g_logstderr) {
+ destination.file.stream = NULL;
+ destination.file.name = "named.run";
destination.file.versions = ISC_LOG_ROLLNEVER;
destination.file.maximum_size = 0;
- flags = ISC_LOG_PRINTTIME;
- result = isc_log_createchannel(ns_g_lctx, "_default",
- ISC_LOG_TOFILEDESC,
- ISC_LOG_DYNAMIC,
- &destination, flags);
- } else {
- destination.facility = LOG_DAEMON;
- flags = ISC_LOG_PRINTTIME;
- result = isc_log_createchannel(ns_g_lctx, "_default",
- ISC_LOG_TOSYSLOG,
- ISC_LOG_DYNAMIC,
- &destination, flags);
+ result = isc_log_createchannel(lcfg, "default_debug",
+ ISC_LOG_TOFILE,
+ ISC_LOG_DYNAMIC,
+ &destination,
+ ISC_LOG_PRINTTIME|
+ ISC_LOG_DEBUGONLY);
+ if (result != ISC_R_SUCCESS)
+ goto cleanup;
}
-
+
+ result = isc_log_usechannel(lcfg, "default_syslog",
+ ISC_LOGCATEGORY_DEFAULT, NULL);
if (result != ISC_R_SUCCESS)
goto cleanup;
- result = isc_log_usechannel(ns_g_lctx, "_default", NULL, NULL);
+
+ result = isc_log_usechannel(lcfg, "default_debug",
+ ISC_LOGCATEGORY_DEFAULT, NULL);
if (result != ISC_R_SUCCESS)
goto cleanup;
@@ -122,8 +134,6 @@ ns_log_init(void) {
return (ISC_R_SUCCESS);
cleanup:
- isc_log_destroy(&ns_g_lctx);
-
return (result);
}
diff --git a/bin/named/logconf.c b/bin/named/logconf.c
new file mode 100644
index 00000000..042380b8
--- /dev/null
+++ b/bin/named/logconf.c
@@ -0,0 +1,183 @@
+/*
+ * Copyright (C) 1999, 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/result.h>
+
+#include <named/globals.h>
+#include <named/log.h>
+#include <named/logconf.h>
+
+#define CHECK(op) \
+ do { result = (op); \
+ if (result != ISC_R_SUCCESS) goto cleanup; \
+ } while (0)
+
+
+/*
+ * Set up a logging category according to the named.conf data
+ * in 'ccat' and add it to 'lctx'.
+ */
+static isc_result_t
+category_fromconf(dns_c_logcat_t *ccat, isc_logconfig_t *lctx)
+{
+ isc_result_t result;
+ unsigned int i;
+ isc_logcategory_t *category;
+ isc_logmodule_t *module;
+
+ category = isc_log_categorybyname(ns_g_lctx, ccat->catname);
+#ifdef notyet
+ module = isc_log_modulebyname(ns_g_lctx, ccat->modname);
+#else
+ module = NULL;
+#endif
+
+ for (i = 0; i < ccat->nextcname; i++) {
+ char *channelname = ccat->channel_names[i];
+
+ result = isc_log_usechannel(lctx, channelname, category,
+ module);
+ if (result != ISC_R_SUCCESS) {
+ isc_log_write(ns_g_lctx, DNS_LOGCATEGORY_CONFIG,
+ NS_LOGMODULE_SERVER, ISC_LOG_ERROR,
+ "logging channel '%s': %s", channelname,
+ isc_result_totext(result));
+ return (result);
+ }
+ }
+ return (ISC_R_SUCCESS);
+}
+
+/*
+ * Set up a logging channel according to the named.conf data
+ * in 'cchan' and add it to 'lctx'.
+ */
+static isc_result_t
+channel_fromconf(dns_c_logchan_t *cchan, isc_logconfig_t *lctx)
+{
+ isc_result_t result;
+ isc_logdestination_t dest;
+ unsigned int type;
+ int flags = 0;
+ int level;
+
+ type = ISC_LOG_TONULL;
+ switch (cchan->ctype) {
+ case dns_c_logchan_file:
+ type = ISC_LOG_TOFILE;
+ {
+ const char *path = NULL;
+ isc_uint32_t versions = ISC_LOG_ROLLNEVER;
+ isc_uint32_t size = 0;
+ (void) dns_c_logchan_getpath(cchan, &path);
+ if (path == NULL) {
+ isc_log_write(ns_g_lctx,
+ DNS_LOGCATEGORY_CONFIG,
+ NS_LOGMODULE_SERVER,
+ ISC_LOG_ERROR,
+ "file log channel has "
+ "no file name");
+ return (ISC_R_UNEXPECTED);
+ }
+ (void) dns_c_logchan_getversions(cchan, &versions);
+ (void) dns_c_logchan_getsize(cchan, &size);
+ dest.file.stream = NULL;
+ dest.file.name = cchan->u.filec.path;
+ dest.file.versions = (int)versions;
+ dest.file.maximum_size = size;
+ }
+ break;
+
+ case dns_c_logchan_syslog:
+ type = ISC_LOG_TOSYSLOG;
+ {
+ int facility = LOG_DAEMON;
+ (void) dns_c_logchan_getfacility(cchan, &facility);
+ dest.facility = facility;
+ }
+ break;
+
+ case dns_c_logchan_null:
+ break;
+ }
+
+ /*
+ * Munge flags.
+ */
+ {
+ isc_boolean_t printcat = ISC_FALSE;
+ isc_boolean_t printsev = ISC_FALSE;
+ isc_boolean_t printtime = ISC_FALSE;
+
+ (void) dns_c_logchan_getprintcat(cchan, &printcat);
+ (void) dns_c_logchan_getprintsev(cchan, &printsev);
+ (void) dns_c_logchan_getprinttime(cchan, &printtime);
+
+ if (printcat)
+ flags |= ISC_LOG_PRINTCATEGORY;
+ if (printtime)
+ flags |= ISC_LOG_PRINTTIME;
+ if (printsev)
+ flags |= ISC_LOG_PRINTLEVEL;
+ /* XXX ISC_LOG_PRINTMODULE */
+ }
+
+ level = ISC_LOG_INFO;
+ (void) dns_c_logchan_getdebuglevel(cchan, &level);
+
+ result = isc_log_createchannel(lctx, cchan->name,
+ type, level, &dest, flags);
+ return (result);
+}
+
+isc_result_t
+ns_log_configure(isc_logconfig_t *lcctx, dns_c_logginglist_t *clog)
+{
+ isc_result_t result;
+ dns_c_logchan_t *cchan;
+ dns_c_logcat_t *ccat;
+ isc_boolean_t default_set = ISC_FALSE;
+
+ for (cchan = ISC_LIST_HEAD(clog->channels);
+ cchan != NULL;
+ cchan = ISC_LIST_NEXT(cchan, next)) {
+ CHECK(channel_fromconf(cchan, lcctx));
+ }
+
+ for (ccat = ISC_LIST_HEAD(clog->categories);
+ ccat != NULL;
+ ccat = ISC_LIST_NEXT(ccat, next)) {
+ CHECK(category_fromconf(ccat, lcctx));
+ if (! default_set)
+ default_set =
+ ISC_TF(strcmp(ccat->catname, "default") == 0);
+ }
+
+ if (! default_set)
+ CHECK(ns_log_setdefaults(lcctx));
+
+ return (ISC_R_SUCCESS);
+
+ cleanup:
+ if (lcctx != NULL)
+ isc_logconfig_destroy(&lcctx);
+ return (result);
+}
+
+
diff --git a/bin/named/main.c b/bin/named/main.c
index 29731df8..3b5e16aa 100644
--- a/bin/named/main.c
+++ b/bin/named/main.c
@@ -120,7 +120,7 @@ library_fatal_error(char *file, int line, char *format, va_list args) {
isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
NS_LOGMODULE_MAIN, ISC_LOG_CRITICAL,
- "%s:%d: fatal error", file, line);
+ "%s:%d: fatal error:", file, line);
isc_log_vwrite(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
NS_LOGMODULE_MAIN, ISC_LOG_CRITICAL,
format, args);
@@ -140,11 +140,32 @@ library_fatal_error(char *file, int line, char *format, va_list args) {
}
static void
+library_unexpected_error(char *file, int line, char *format, va_list args) {
+ /*
+ * Handle isc_error_unexpected() calls from our libraries.
+ */
+
+ if (ns_g_lctx != NULL) {
+ isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
+ NS_LOGMODULE_MAIN, ISC_LOG_ERROR,
+ "%s:%d: unexpected error:", file, line);
+ isc_log_vwrite(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
+ NS_LOGMODULE_MAIN, ISC_LOG_ERROR,
+ format, args);
+ } else {
+ fprintf(stderr, "%s:%d: fatal error: ", file, line);
+ vfprintf(stderr, format, args);
+ fprintf(stderr, "\n");
+ fflush(stderr);
+ }
+}
+
+static void
usage(void) {
fprintf(stderr,
- "usage: named [[-c cachefile] ...] [[-z zonefile] ...]\n");
- fprintf(stderr,
- " [-p port] [-s] [-N number of cpus]\n");
+ "usage: named [-c conffile] [-d debuglevel] "
+ "[-f|-g] [-n number_of_cpus]\n"
+ " [-p port] [-s] [-t chrootdir] [-u username]\n");
}
static void
@@ -154,10 +175,9 @@ parse_command_line(int argc, char *argv[]) {
isc_commandline_errprint = ISC_FALSE;
while ((ch = isc_commandline_parse(argc, argv,
- "b:c:d:fN:p:st:u:x:")) !=
+ "c:d:fgn:N:p:st:u:x:")) !=
-1) {
switch (ch) {
- case 'b':
case 'c':
ns_g_conffile = isc_commandline_argument;
break;
@@ -167,7 +187,12 @@ parse_command_line(int argc, char *argv[]) {
case 'f':
ns_g_foreground = ISC_TRUE;
break;
- case 'N':
+ case 'g':
+ ns_g_foreground = ISC_TRUE;
+ ns_g_logstderr = ISC_TRUE;
+ break;
+ case 'N': /* Deprecated. */
+ case 'n':
ns_g_cpus = atoi(isc_commandline_argument);
if (ns_g_cpus == 0)
ns_g_cpus = 1;
@@ -175,7 +200,7 @@ parse_command_line(int argc, char *argv[]) {
case 'p':
port = atoi(isc_commandline_argument);
if (port < 1 || port > 65535)
- ns_main_earlyfatal("port \"%s\" out of range",
+ ns_main_earlyfatal("port '%s' out of range",
isc_commandline_argument);
ns_g_port = port;
break;
@@ -195,7 +220,8 @@ parse_command_line(int argc, char *argv[]) {
ns_g_cachefile = isc_commandline_argument;
break;
case '?':
- ns_main_earlyfatal("unknown option `-%c'",
+ usage();
+ ns_main_earlyfatal("unknown option '-%c'",
isc_commandline_option);
default:
ns_main_earlyfatal("parsing options returned %d", ch);
@@ -205,7 +231,7 @@ parse_command_line(int argc, char *argv[]) {
argc -= isc_commandline_index;
argv += isc_commandline_index;
- if (argc > 1) {
+ if (argc > 0) {
usage();
ns_main_earlyfatal("extra command line arguments");
}
@@ -218,7 +244,7 @@ create_managers() {
result = isc_taskmgr_create(ns_g_mctx, ns_g_cpus, 0, &ns_g_taskmgr);
if (result != ISC_R_SUCCESS) {
UNEXPECTED_ERROR(__FILE__, __LINE__,
- "ns_taskmgr_create() failed: %s\n",
+ "ns_taskmgr_create() failed: %s",
isc_result_totext(result));
return (ISC_R_UNEXPECTED);
}
@@ -226,7 +252,7 @@ create_managers() {
result = isc_timermgr_create(ns_g_mctx, &ns_g_timermgr);
if (result != ISC_R_SUCCESS) {
UNEXPECTED_ERROR(__FILE__, __LINE__,
- "ns_timermgr_create() failed: %s\n",
+ "ns_timermgr_create() failed: %s",
isc_result_totext(result));
return (ISC_R_UNEXPECTED);
}
@@ -234,7 +260,7 @@ create_managers() {
result = isc_socketmgr_create(ns_g_mctx, &ns_g_socketmgr);
if (result != ISC_R_SUCCESS) {
UNEXPECTED_ERROR(__FILE__, __LINE__,
- "isc_socketmgr_create() failed: %s\n",
+ "isc_socketmgr_create() failed: %s",
isc_result_totext(result));
return (ISC_R_UNEXPECTED);
}
@@ -244,17 +270,17 @@ create_managers() {
static void
destroy_managers(void) {
+ if (ns_g_omapimgr != NULL)
+ omapi_listener_shutdown(ns_g_omapimgr);
+ else
+ omapi_lib_destroy();
+
/*
* isc_taskmgr_destroy() will block until all tasks have exited,
*/
isc_taskmgr_destroy(&ns_g_taskmgr);
isc_timermgr_destroy(&ns_g_timermgr);
isc_socketmgr_destroy(&ns_g_socketmgr);
-
- if (ns_g_omapimgr != NULL) {
- omapi_listener_shutdown(ns_g_omapimgr);
- omapi_object_dereference(&ns_g_omapimgr);
- }
}
static void
@@ -288,7 +314,7 @@ setup() {
ns_server_create(ns_g_mctx, &ns_g_server);
- result = omapi_lib_init(ns_g_mctx);
+ result = ns_omapi_init();
if (result != ISC_R_SUCCESS)
ns_main_earlyfatal("omapi_lib_init() failed: %s",
isc_result_totext(result));
@@ -308,7 +334,6 @@ setup() {
static void
cleanup() {
destroy_managers();
- omapi_lib_destroy();
ns_server_destroy(&ns_g_server);
isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_MAIN,
ISC_LOG_NOTICE, "exiting");
@@ -322,6 +347,7 @@ main(int argc, char *argv[]) {
program_name = argv[0];
isc_assertion_setcallback(assertion_failed);
isc_error_setfatal(library_fatal_error);
+ isc_error_setunexpected(library_unexpected_error);
ns_os_init();
diff --git a/bin/named/notify.c b/bin/named/notify.c
index 318e50eb..082b20e7 100644
--- a/bin/named/notify.c
+++ b/bin/named/notify.c
@@ -65,7 +65,7 @@
* to use in reportings server errors.
*/
#define NOTIFY_ERROR_LOGARGS \
- ns_g_lctx, NS_LOGCATEGORY_NOTIFY, NS_LOGMODULE_NOTIFY, \
+ ns_g_lctx, DNS_LOGCATEGORY_NOTIFY, NS_LOGMODULE_NOTIFY, \
ISC_LOG_ERROR
/*
@@ -73,7 +73,7 @@
* to use in tracing notify protocol requests.
*/
#define NOTIFY_PROTOCOL_LOGARGS \
- ns_g_lctx, NS_LOGCATEGORY_NOTIFY, NS_LOGMODULE_NOTIFY, \
+ ns_g_lctx, DNS_LOGCATEGORY_NOTIFY, NS_LOGMODULE_NOTIFY, \
ISC_LOG_INFO
/*
@@ -81,7 +81,7 @@
* to use in low-level debug tracing.
*/
#define NOTIFY_DEBUG_LOGARGS \
- ns_g_lctx, NS_LOGCATEGORY_NOTIFY, NS_LOGMODULE_NOTIFY, \
+ ns_g_lctx, DNS_LOGCATEGORY_NOTIFY, NS_LOGMODULE_NOTIFY, \
ISC_LOG_DEBUG(8)
/*
diff --git a/bin/named/omapi.c b/bin/named/omapi.c
index d0116cbc..3107a029 100644
--- a/bin/named/omapi.c
+++ b/bin/named/omapi.c
@@ -15,7 +15,7 @@
* SOFTWARE.
*/
-/* $Id: omapi.c,v 1.3 2000/02/02 02:16:59 halley Exp $ */
+/* $Id: omapi.c,v 1.10 2000/03/18 02:38:20 tale Exp $ */
/*
* Principal Author: DCL
@@ -44,6 +44,9 @@ typedef struct control_object {
static control_object_t control;
static omapi_objecttype_t *control_type;
+static void
+listen_done(isc_task_t *task, isc_event_t *event);
+
#undef REGION_FMT
/*
* Ok, kind of gross. Sorry. A little.
@@ -69,7 +72,7 @@ control_setvalue(omapi_object_t *handle, omapi_string_t *name,
isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
NS_LOGMODULE_OMAPI, ISC_LOG_DEBUG(1),
- "control_setvalue: '%.*s' control command received\n",
+ "control_setvalue: '%.*s' control command received",
REGION_FMT(&region));
/*
@@ -87,14 +90,14 @@ control_setvalue(omapi_object_t *handle, omapi_string_t *name,
NS_OMAPI_COMMAND_RELOADZONES) == 0) {
isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
NS_LOGMODULE_OMAPI, ISC_LOG_WARNING,
- "control_setvalue: '%.*s' not yet implemented\n",
+ "control_setvalue: '%.*s' not yet implemented",
REGION_FMT(&region));
result = ISC_R_NOTIMPLEMENTED;
} else {
isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
NS_LOGMODULE_OMAPI, ISC_LOG_WARNING,
- "control_setvalue: unknown name: '%.*s'\n",
+ "control_setvalue: unknown name: '%.*s'",
REGION_FMT(&region));
result = omapi_object_passsetvalue(handle, name, value);
}
@@ -139,10 +142,47 @@ control_stuffvalues(omapi_object_t *connection, omapi_object_t *handle) {
}
isc_result_t
+ns_omapi_init(void) {
+ isc_result_t result;
+
+ result = omapi_lib_init(ns_g_mctx, ns_g_taskmgr, ns_g_socketmgr);
+
+ if (result == ISC_R_SUCCESS)
+ /*
+ * Register the control_object. NS_OMAPI_CONTROL is
+ * what a client would need to specify as a value for
+ * the value of "type" in a message when contacting
+ * the server to perform a control function.
+ */
+ result = omapi_object_register(&control_type, NS_OMAPI_CONTROL,
+ control_setvalue,
+ NULL, /* getvalue */
+ NULL, /* destroy */
+ NULL, /* signalhandler */
+ control_stuffvalues,
+ control_lookup,
+ NULL, /* create */
+ NULL); /* remove */
+
+ if (result == ISC_R_SUCCESS) {
+ /*
+ * Initialize the static control object.
+ */
+ control.refcnt = 1;
+ control.type = control_type;
+ }
+
+ return (result);
+}
+
+isc_result_t
ns_omapi_listen(omapi_object_t **managerp) {
omapi_object_t *manager = NULL;
isc_result_t result;
isc_sockaddr_t sockaddr;
+ isc_netaddr_t netaddr;
+ dns_acl_t *acl; /* XXXDCL make a parameter */
+ dns_aclelement_t elt;
struct in_addr inaddr4;
REQUIRE(managerp != NULL && *managerp == NULL);
@@ -155,47 +195,53 @@ ns_omapi_listen(omapi_object_t **managerp) {
isc_sockaddr_fromin(&sockaddr, &inaddr4, NS_OMAPI_PORT);
/*
- * Register the control_object. NS_OMAPI_CONTROL is what a client
- * would need to specify as a value for the value of "type" in
- * a message when contacting the server to perform a control function.
+ * XXXDCL this is not right either
*/
- result = omapi_object_register(&control_type, NS_OMAPI_CONTROL,
- control_setvalue,
- NULL, /* getvalue */
- NULL, /* destroy */
- NULL, /* signalhandler */
- control_stuffvalues,
- control_lookup,
- NULL, /* create */
- NULL); /* remove */
+ isc_netaddr_fromsockaddr(&netaddr, &sockaddr);
+ elt.type = dns_aclelementtype_ipprefix;
+ elt.negative = ISC_FALSE;
+ elt.u.ip_prefix.address = netaddr;
+ elt.u.ip_prefix.prefixlen = 32;
- if (result == ISC_R_SUCCESS) {
- /*
- * Initialize the static control object.
- */
- control.refcnt = 1;
- control.type = control_type;
+ result = dns_acl_create(ns_g_mctx, 1, &acl);
+
+ if (result == ISC_R_SUCCESS)
+ result = dns_acl_appendelement(acl, &elt);
+ if (result == ISC_R_SUCCESS)
/*
* Create a generic object to be the manager for handling
* incoming server connections.
*/
result = omapi_object_create(&manager, NULL, 0);
- }
- if (result == ISC_R_SUCCESS)
+ if (result == ISC_R_SUCCESS) {
/*
* Start listening for connections.
*/
- result = omapi_protocol_listen(manager, &sockaddr, 1);
+ result = omapi_protocol_listen(manager, &sockaddr, acl, 1,
+ listen_done, ns_g_omapimgr);
+ dns_acl_detach(&acl);
+ }
if (result == ISC_R_SUCCESS)
*managerp = manager;
- else {
+ else
if (manager != NULL)
omapi_object_dereference(&manager);
- }
return (result);
}
+
+static void
+listen_done(isc_task_t *task, isc_event_t *event) {
+ isc_event_free(&event);
+
+ UNUSED(task);
+
+ if (ns_g_omapimgr != NULL)
+ omapi_object_dereference(&ns_g_omapimgr);
+
+ omapi_lib_destroy();
+}
diff --git a/bin/named/query.c b/bin/named/query.c
index 634d0a9c..1a775d57 100644
--- a/bin/named/query.c
+++ b/bin/named/query.c
@@ -183,8 +183,7 @@ query_reset(ns_client_t *client, isc_boolean_t everything) {
}
static void
-query_next(ns_client_t *client, isc_result_t result) {
- (void)result;
+query_next(ns_client_t *client) {
query_reset(client, ISC_FALSE);
}
@@ -902,8 +901,11 @@ query_addadditional(void *arg, dns_name_t *name, dns_rdatatype_t qtype) {
rdataset = query_newrdataset(client);
if (rdataset == NULL || sigrdataset == NULL)
goto addname;
- } else
+ } else {
dns_rdataset_disassociate(rdataset);
+ if (sigrdataset->methods != NULL)
+ dns_rdataset_disassociate(sigrdataset);
+ }
}
result = dns_db_findrdataset(db, node, version,
dns_rdatatype_a6, 0,
@@ -1678,11 +1680,10 @@ query_resume(isc_task_t *task, isc_event_t *event) {
query_putrdataset(client, &devent->rdataset);
query_putrdataset(client, &devent->sigrdataset);
isc_event_free(&event);
+ ns_client_next(client, ISC_R_CANCELED);
/* This may destroy the client. */
- ns_client_unwait(client);
+ ns_client_detach(&client);
} else {
- ns_client_unwait(client);
-
RWLOCK(&ns_g_server->conflock, isc_rwlocktype_read);
dns_zonemgr_lockconf(ns_g_server->zonemgr, isc_rwlocktype_read);
dns_view_attach(client->view, &client->lockview);
@@ -1759,7 +1760,6 @@ query_recurse(ns_client_t *client, dns_rdatatype_t qtype, dns_name_t *qdomain,
* is shutting down will not be destroyed until all the
* events have been received.
*/
- ns_client_wait(client);
} else {
query_putrdataset(client, &rdataset);
query_putrdataset(client, &sigrdataset);
@@ -1798,6 +1798,7 @@ query_find(ns_client_t *client, dns_fetchevent_t *event) {
dns_fixedname_t fixed;
dns_dbversion_t *version;
dns_zone_t *zone;
+ dns_acl_t *queryacl;
CTRACE("query_find");
@@ -1923,18 +1924,16 @@ query_find(ns_client_t *client, dns_fetchevent_t *event) {
} else
version = NULL;
+ queryacl = NULL;
+ if (is_zone)
+ queryacl = dns_zone_getqueryacl(zone);
+ if (queryacl == NULL)
+ queryacl = ns_g_server->queryacl;
/*
* Check the query against the "allow-query" AMLs.
* XXX there should also be a per-view one.
*/
- result = dns_acl_checkrequest(client->signer,
- ns_client_getsockaddr(client),
- "query",
- (is_zone ?
- dns_zone_getqueryacl(zone) :
- ns_g_server->queryacl),
- ns_g_server->queryacl,
- ISC_TRUE);
+ result = ns_client_checkacl(client, "query", queryacl, ISC_TRUE);
if (result != DNS_R_SUCCESS) {
QUERY_ERROR(result);
goto cleanup;
@@ -2039,7 +2038,8 @@ query_find(ns_client_t *client, dns_fetchevent_t *event) {
*/
INSIST(!is_zone);
INSIST(client->view->hints != NULL);
- dns_db_detach(&db);
+ if (db != NULL)
+ dns_db_detach(&db);
dns_db_attach(client->view->hints, &db);
result = dns_db_find(db, dns_rootname, NULL, dns_rdatatype_ns,
0, client->now, &node, fname,
@@ -2597,9 +2597,10 @@ query_find(ns_client_t *client, dns_fetchevent_t *event) {
goto restart;
}
- if (eresult != ISC_R_SUCCESS && !PARTIALANSWER(client))
+ if (eresult != ISC_R_SUCCESS && !PARTIALANSWER(client)) {
ns_client_error(client, eresult);
- else if (!RECURSING(client)) {
+ ns_client_detach(&client);
+ } else if (!RECURSING(client)) {
/*
* We are done. Make a final tweak to the AA bit if the
* auth-nxdomain config option says so, then send the
@@ -2610,6 +2611,7 @@ query_find(ns_client_t *client, dns_fetchevent_t *event) {
client->message->flags |= DNS_MESSAGEFLAG_AA;
ns_client_send(client);
+ ns_client_detach(&client);
}
CTRACE("query_find: done");
}
@@ -2672,7 +2674,8 @@ ns_query_start(ns_client_t *client) {
dns_message_t *message = client->message;
dns_rdataset_t *rdataset;
isc_boolean_t set_ra = ISC_TRUE;
-
+ ns_client_t *qclient;
+
CTRACE("ns_query_start");
/*
@@ -2802,5 +2805,7 @@ ns_query_start(ns_client_t *client) {
*/
message->flags |= DNS_MESSAGEFLAG_AD;
- query_find(client, NULL);
+ qclient = NULL;
+ ns_client_attach(client, &qclient);
+ query_find(qclient, NULL);
}
diff --git a/bin/named/server.c b/bin/named/server.c
index 2c7b0f83..dea952f2 100644
--- a/bin/named/server.c
+++ b/bin/named/server.c
@@ -39,6 +39,7 @@
#include <isc/timer.h>
#include <isc/util.h>
+#include <dns/acl.h>
#include <dns/aclconf.h>
#include <dns/cache.h>
#include <dns/confacl.h>
@@ -67,6 +68,7 @@
#include <named/interfacemgr.h>
#include <named/listenlist.h>
#include <named/log.h>
+#include <named/logconf.h>
#include <named/os.h>
#include <named/server.h>
#include <named/types.h>
@@ -119,14 +121,12 @@ ns_listenlist_fromconfig(dns_c_lstnlist_t *clist, dns_c_ctx_t *cctx,
/*
* Configure 'view' according to 'cctx'.
- *
- * XXX reconfiguration should preserve cache contents.
*/
static isc_result_t
configure_view(dns_view_t *view, dns_c_ctx_t *cctx, isc_mem_t *mctx,
- dns_dispatch_t *dispatch)
+ dns_dispatch_t *dispatchv4, dns_dispatch_t *dispatchv6)
{
- dns_cache_t *cache;
+ dns_cache_t *cache = NULL;
isc_result_t result;
isc_int32_t cleaning_interval;
dns_tsig_keyring_t *ring;
@@ -135,8 +135,9 @@ configure_view(dns_view_t *view, dns_c_ctx_t *cctx, isc_mem_t *mctx,
dns_fwdpolicy_t fwdpolicy;
isc_sockaddrlist_t addresses;
isc_sockaddr_t *sa, *next_sa;
+ dns_view_t *pview = NULL; /* Production view */
unsigned int i;
-
+
REQUIRE(DNS_VIEW_VALID(view));
ISC_LIST_INIT(addresses);
@@ -144,11 +145,34 @@ configure_view(dns_view_t *view, dns_c_ctx_t *cctx, isc_mem_t *mctx,
RWLOCK(&view->conflock, isc_rwlocktype_write);
/*
- * Cache.
+ * Configure the view's cache. Try to reuse an existing
+ * cache if possible, otherwise create a new cache.
+ * Note that the ADB is not preserved in either case.
+ *
+ * XXX Determining when it is safe to reuse a cache is
+ * tricky. When the view's configuration changes, the cached
+ * data may become invalid because it reflects our old
+ * view of the world. As more view attributes become
+ * configurable, we will have to add code here to check
+ * whether they have changed in ways that could
+ * invalidate the cache.
*/
- cache = NULL;
- CHECK(dns_cache_create(mctx, ns_g_taskmgr, ns_g_timermgr,
- view->rdclass, "rbt", 0, NULL, &cache));
+ result = dns_viewlist_find(&ns_g_server->viewlist,
+ view->name, view->rdclass,
+ &pview);
+ if (result != ISC_R_NOTFOUND && result != ISC_R_SUCCESS)
+ goto cleanup;
+ if (pview != NULL) {
+ INSIST(pview->cache != NULL);
+ isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
+ NS_LOGMODULE_SERVER,
+ ISC_LOG_DEBUG(3), "reusing existing cache");
+ dns_cache_attach(pview->cache, &cache);
+ dns_view_detach(&pview);
+ } else {
+ CHECK(dns_cache_create(mctx, ns_g_taskmgr, ns_g_timermgr,
+ view->rdclass, "rbt", 0, NULL, &cache));
+ }
dns_view_setcache(view, cache);
cleaning_interval = 3600; /* Default is 1 hour. */
(void) dns_c_ctx_getcleaninterval(cctx, &cleaning_interval);
@@ -173,7 +197,7 @@ configure_view(dns_view_t *view, dns_c_ctx_t *cctx, isc_mem_t *mctx,
*/
CHECK(dns_view_createresolver(view, ns_g_taskmgr, 31,
ns_g_socketmgr, ns_g_timermgr,
- 0, dispatch, NULL));
+ 0, dispatchv4, dispatchv6));
/*
* Set resolver forwarding policy.
@@ -195,6 +219,7 @@ configure_view(dns_view_t *view, dns_c_ctx_t *cctx, isc_mem_t *mctx,
ISC_LIST_APPEND(addresses, sa, link);
}
INSIST(!ISC_LIST_EMPTY(addresses));
+ dns_c_iplist_detach(&forwarders);
CHECK(dns_resolver_setforwarders(view->resolver, &addresses));
/*
* XXXRTH The configuration type 'dns_c_forw_t' should be
@@ -222,6 +247,20 @@ configure_view(dns_view_t *view, dns_c_ctx_t *cctx, isc_mem_t *mctx,
CHECK(dns_tsigkeyring_fromconfig(cctx, view->mctx, &ring));
dns_view_setkeyring(view, ring);
+ /*
+ * Configure the view's peer list.
+ */
+ {
+ dns_peerlist_t *newpeers = NULL;
+ if (cctx->peers != NULL) {
+ dns_peerlist_attach(cctx->peers, &newpeers);
+ } else {
+ CHECK(dns_peerlist_new(mctx, &newpeers));
+ }
+ dns_peerlist_detach(&view->peers);
+ view->peers = newpeers; /* Transfer ownership. */
+ }
+
cleanup:
RWUNLOCK(&view->conflock, isc_rwlocktype_write);
@@ -513,13 +552,6 @@ configure_zone(dns_c_ctx_t *cctx, dns_c_zone_t *czone, dns_c_view_t *cview,
CHECK(dns_zone_configure(cctx, lctx->aclconf, czone, zone));
/*
- * XXX Why was this here?
- *
- * if (dns_zone_gettype(zone) == dns_zone_hint)
- * INSIST(0);
- */
-
- /*
* Add the zone to its view in the new view list.
*/
CHECK(dns_view_addzone(view, zone));
@@ -572,41 +604,63 @@ configure_server_quota(dns_c_ctx_t *cctx,
}
static isc_result_t
-configure_server_querysource(dns_c_ctx_t *cctx, ns_server_t *server,
+configure_server_querysource(dns_c_ctx_t *cctx, ns_server_t *server, int af,
dns_dispatch_t **dispatchp) {
isc_result_t result;
struct in_addr ina;
- isc_sockaddr_t sa, any;
- in_port_t port;
+ isc_sockaddr_t sa, any4, any6, *any;
isc_socket_t *socket;
+ dns_dispatch_t **server_dispatchp;
+ isc_sockaddr_t *server_dispatchaddr;
- ina.s_addr = htonl(INADDR_ANY);
- isc_sockaddr_fromin(&any, &ina, 0);
+ /*
+ * Make compiler happy.
+ */
+ result = ISC_R_FAILURE;
+ any = NULL;
+ server_dispatchp = NULL;
+ server_dispatchaddr = NULL;
+ ina.s_addr = htonl(INADDR_ANY);
+ isc_sockaddr_fromin(&any4, &ina, 0);
+ isc_sockaddr_fromin6(&any6, &in6addr_any, 0);
+
*dispatchp = NULL;
- if (dns_c_ctx_getquerysourceaddr(cctx, &sa) != ISC_R_SUCCESS)
- sa = any;
- if (dns_c_ctx_getquerysourceport(cctx, &port) != ISC_R_SUCCESS)
- port = 0;
- isc_sockaddr_setport(&sa, port);
-
- /*
- * XXX We need to have separate query source options for v4 and v6,
- * but right now we only have one option, and the parser allows
- * v6 addresses for it. Until we have a separate v6 option,
- * make sure that the query source is v4.
- */
- if (isc_sockaddr_pf(&sa) != PF_INET)
- return (DNS_R_NOTIMPLEMENTED);
+ switch (af) {
+ case AF_INET:
+ any = &any4;
+ result = dns_c_ctx_getquerysource(cctx, &sa);
+ break;
+ case AF_INET6:
+ any = &any6;
+ result = dns_c_ctx_getquerysourcev6(cctx, &sa);
+ break;
+ default:
+ INSIST(0);
+ }
+ if (result != ISC_R_SUCCESS)
+ sa = *any;
+
+ INSIST(isc_sockaddr_pf(&sa) == af);
/*
- * If we don't support IPv4, we're done!
+ * If we don't support this address family, we're done!
*/
- if (isc_net_probeipv4() != ISC_R_SUCCESS)
+ switch (af) {
+ case AF_INET:
+ result = isc_net_probeipv4();
+ break;
+ case AF_INET6:
+ result = isc_net_probeipv6();
+ break;
+ default:
+ INSIST(0);
+ }
+ if (result != ISC_R_SUCCESS)
return (ISC_R_SUCCESS);
- if (isc_sockaddr_equal(&sa, &any)) {
+ if (isc_sockaddr_equal(&sa, any)) {
/*
* The query source is fully wild. No special dispatcher
* work needs to be done.
@@ -618,20 +672,32 @@ configure_server_querysource(dns_c_ctx_t *cctx, ns_server_t *server,
* If the interface manager has a dispatcher for this address,
* use it.
*/
+ switch (af) {
+ case AF_INET:
+ server_dispatchp = &server->querysrc_dispatchv4;
+ server_dispatchaddr = &server->querysrc_addressv4;
+ break;
+ case AF_INET6:
+ server_dispatchp = &server->querysrc_dispatchv6;
+ server_dispatchaddr = &server->querysrc_addressv6;
+ break;
+ default:
+ INSIST(0);
+ }
if (ns_interfacemgr_findudpdispatcher(server->interfacemgr, &sa,
dispatchp) !=
ISC_R_SUCCESS) {
/*
* The interface manager doesn't have a matching dispatcher.
*/
- if (server->querysrc_dispatch != NULL) {
+ if (*server_dispatchp != NULL) {
/*
* We've already got a custom dispatcher. If it is
* compatible with the new configuration, use it.
*/
- if (isc_sockaddr_equal(&server->querysrc_address,
+ if (isc_sockaddr_equal(server_dispatchaddr,
&sa)) {
- dns_dispatch_attach(server->querysrc_dispatch,
+ dns_dispatch_attach(*server_dispatchp,
dispatchp);
return (ISC_R_SUCCESS);
}
@@ -639,15 +705,15 @@ configure_server_querysource(dns_c_ctx_t *cctx, ns_server_t *server,
* The existing custom dispatcher is not compatible.
* We don't need it anymore.
*/
- dns_dispatch_detach(&server->querysrc_dispatch);
+ dns_dispatch_detach(server_dispatchp);
}
/*
* Create a custom dispatcher.
*/
- INSIST(server->querysrc_dispatch == NULL);
- server->querysrc_address = sa;
+ INSIST(*server_dispatchp == NULL);
+ *server_dispatchaddr = sa;
socket = NULL;
- result = isc_socket_create(ns_g_socketmgr, AF_INET,
+ result = isc_socket_create(ns_g_socketmgr, af,
isc_sockettype_udp,
&socket);
if (result != ISC_R_SUCCESS)
@@ -660,7 +726,7 @@ configure_server_querysource(dns_c_ctx_t *cctx, ns_server_t *server,
result = dns_dispatch_create(ns_g_mctx, socket,
server->task, 4096,
1000, 32768, 16411, 16433, NULL,
- &server->querysrc_dispatch);
+ server_dispatchp);
/*
* Regardless of whether dns_dispatch_create() succeeded or
* failed, we don't need to keep the reference to the socket.
@@ -668,19 +734,71 @@ configure_server_querysource(dns_c_ctx_t *cctx, ns_server_t *server,
isc_socket_detach(&socket);
if (result != ISC_R_SUCCESS)
return (result);
- dns_dispatch_attach(server->querysrc_dispatch, dispatchp);
+ dns_dispatch_attach(*server_dispatchp, dispatchp);
} else {
/*
* We're sharing a UDP dispatcher with the interface manager
* now. Any prior custom dispatcher can be discarded.
*/
- if (server->querysrc_dispatch != NULL)
- dns_dispatch_detach(&server->querysrc_dispatch);
+ if (*server_dispatchp != NULL)
+ dns_dispatch_detach(server_dispatchp);
+ }
+
+ return (ISC_R_SUCCESS);
+}
+
+/*
+ * This function is called as soon as the 'options' statement has been
+ * parsed.
+ */
+static isc_result_t
+options_callback(dns_c_ctx_t *cctx, void *uap) {
+ isc_result_t result;
+
+ UNUSED(uap);
+
+ /*
+ * Change directory.
+ */
+ if (cctx->options != NULL &&
+ cctx->options->directory != NULL) {
+ result = isc_dir_chdir(cctx->options->directory);
+ if (result != ISC_R_SUCCESS) {
+ isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
+ NS_LOGMODULE_SERVER,
+ ISC_LOG_ERROR, "change directory "
+ "to '%s' failed: %s",
+ cctx->options->directory,
+ isc_result_totext(result));
+ return (result);
+ }
}
return (ISC_R_SUCCESS);
}
+
+static void
+scan_interfaces(ns_server_t *server) {
+ ns_interfacemgr_scan(server->interfacemgr);
+ dns_aclenv_copy(&server->aclenv,
+ ns_interfacemgr_getaclenv(server->interfacemgr));
+}
+
+/*
+ * This event callback is invoked to do periodic network
+ * interface scanning.
+ */
+static void
+interface_timer_tick(isc_task_t *task, isc_event_t *event) {
+ ns_server_t *server = (ns_server_t *) event->arg;
+ UNUSED(task);
+ isc_event_free(&event);
+ RWLOCK(&server->conflock, isc_rwlocktype_write);
+ scan_interfaces(server);
+ RWUNLOCK(&server->conflock, isc_rwlocktype_write);
+}
+
static isc_result_t
load_configuration(const char *filename, ns_server_t *server,
isc_boolean_t first_time)
@@ -692,9 +810,11 @@ load_configuration(const char *filename, ns_server_t *server,
dns_view_t *view, *view_next;
dns_viewlist_t tmpviewlist;
dns_aclconfctx_t aclconfctx;
- dns_dispatch_t *dispatch;
+ dns_dispatch_t *dispatchv4 = NULL;
+ dns_dispatch_t *dispatchv6 = NULL;
char *pidfilename;
-
+ isc_int32_t interface_interval;
+
dns_aclconfctx_init(&aclconfctx);
RWLOCK(&server->conflock, isc_rwlocktype_write);
@@ -706,7 +826,7 @@ load_configuration(const char *filename, ns_server_t *server,
callbacks.zonecbk = configure_zone;
callbacks.zonecbkuap = &lctx;
- callbacks.optscbk = NULL;
+ callbacks.optscbk = options_callback;
callbacks.optscbkuap = NULL;
isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_SERVER,
@@ -737,10 +857,6 @@ load_configuration(const char *filename, ns_server_t *server,
dns_c_ctx_getrecursionacl,
&server->recursionacl));
- CHECK(configure_server_acl(configctx, &aclconfctx, ns_g_mctx,
- dns_c_ctx_gettransferacl,
- &server->transferacl));
-
configure_server_quota(configctx, dns_c_ctx_gettransfersout,
&server->xfroutquota, 10);
configure_server_quota(configctx, dns_c_ctx_gettcpclients,
@@ -748,6 +864,29 @@ load_configuration(const char *filename, ns_server_t *server,
configure_server_quota(configctx, dns_c_ctx_getrecursiveclients,
&server->recursionquota, 100);
+ (void) dns_c_ctx_getprovideixfr(configctx, &server->provide_ixfr);
+
+
+ /*
+ * Configure the zone manager.
+ */
+ {
+ isc_int32_t transfersin = 10;
+ (void) dns_c_ctx_gettransfersin(configctx, &transfersin);
+ dns_zonemgr_settransfersin(server->zonemgr, transfersin);
+ }
+ {
+ isc_int32_t transfersperns = 2;
+ (void) dns_c_ctx_gettransfersperns(configctx, &transfersperns);
+ dns_zonemgr_settransfersperns(server->zonemgr, transfersperns);
+ }
+ {
+ isc_boolean_t requestixfr = ISC_TRUE;
+ (void) dns_c_ctx_getrequestixfr(configctx, &requestixfr);
+ dns_zonemgr_setrequestixfr(server->zonemgr, requestixfr);
+ }
+
+
/*
* Configure the interface manager according to the "listen-on"
* statement.
@@ -778,10 +917,28 @@ load_configuration(const char *filename, ns_server_t *server,
* to configure the query source, since the dispatcher we use might
* be shared with an interface.
*/
- ns_interfacemgr_scan(server->interfacemgr);
+ scan_interfaces(server);
- dispatch = NULL;
- CHECK(configure_server_querysource(configctx, server, &dispatch));
+ /*
+ * Arrange for further interface scanning to occur periodically
+ * as specified by the "interface-interval" option.
+ */
+ interface_interval = 3600; /* Default is 1 hour. */
+ (void) dns_c_ctx_getinterfaceinterval(configctx, &interface_interval);
+ if (interface_interval == 0) {
+ isc_timer_reset(server->interface_timer, isc_timertype_inactive,
+ NULL, NULL, ISC_TRUE);
+ } else {
+ isc_interval_t interval;
+ isc_interval_set(&interval, interface_interval, 0);
+ isc_timer_reset(server->interface_timer, isc_timertype_ticker,
+ NULL, &interval, ISC_FALSE);
+ }
+
+ CHECK(configure_server_querysource(configctx, server,
+ AF_INET, &dispatchv4));
+ CHECK(configure_server_querysource(configctx, server,
+ AF_INET6, &dispatchv6));
/*
* If we haven't created any views, create a default view for class
@@ -804,17 +961,12 @@ load_configuration(const char *filename, ns_server_t *server,
view != NULL;
view = ISC_LIST_NEXT(view, link))
{
- CHECK(configure_view(view, configctx, ns_g_mctx, dispatch));
+ CHECK(configure_view(view, configctx, ns_g_mctx,
+ dispatchv4, dispatchv6));
dns_view_freeze(view);
}
/*
- * We don't need dispatch anymore.
- */
- if (dispatch != NULL)
- dns_dispatch_detach(&dispatch);
-
- /*
* Create (or recreate) the version view.
*/
view = NULL;
@@ -823,24 +975,6 @@ load_configuration(const char *filename, ns_server_t *server,
view = NULL;
/*
- * Change directory.
- */
- if (configctx->options != NULL &&
- configctx->options->directory != NULL) {
- result = isc_dir_chdir(configctx->options->directory);
- if (result != ISC_R_SUCCESS) {
- isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
- NS_LOGMODULE_SERVER,
- ISC_LOG_ERROR, "change directory "
- "to '%s' failed: %s",
- configctx->options->directory,
- isc_result_totext(result));
- CHECK(result);
- }
- }
-
-
- /*
* Swap our new view list with the production one.
*/
tmpviewlist = server->viewlist;
@@ -859,12 +993,42 @@ load_configuration(const char *filename, ns_server_t *server,
server->tkeyctx = t;
}
+ /*
+ * Configure the logging system.
+ */
+ if (ns_g_logstderr) {
+ isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
+ NS_LOGMODULE_SERVER, ISC_LOG_INFO,
+ "ignoring named.conf logging statement "
+ "due to -g option");
+ } else {
+ dns_c_logginglist_t *clog = NULL;
+ isc_logconfig_t *logc = NULL;
+
+ CHECKM(isc_logconfig_create(ns_g_lctx, &logc),
+ "creating new logging configuration");
+
+ (void) dns_c_ctx_getlogging(configctx, &clog);
+ if (clog != NULL)
+ CHECKM(ns_log_configure(logc, clog),
+ "configuring logging");
+ else
+ CHECKM(ns_log_setdefaults(logc),
+ "setting up default logging defaults");
+
+ result = isc_logconfig_use(ns_g_lctx, logc);
+ if (result != ISC_R_SUCCESS) {
+ isc_logconfig_destroy(&logc);
+ CHECKM(result, "intalling logging configuration");
+ }
+ }
+
if (first_time)
ns_os_changeuser(ns_g_username);
if (dns_c_ctx_getpidfilename(configctx, &pidfilename) ==
ISC_R_NOTFOUND)
- pidfilename = "/var/run/named.pid";
+ pidfilename = ns_g_defaultpidfile;
ns_os_writepidfile(pidfilename);
dns_aclconfctx_destroy(&aclconfctx);
@@ -886,8 +1050,13 @@ load_configuration(const char *filename, ns_server_t *server,
}
+ if (dispatchv4 != NULL)
+ dns_dispatch_detach(&dispatchv4);
+ if (dispatchv6 != NULL)
+ dns_dispatch_detach(&dispatchv6);
+
dns_zonemgr_unlockconf(server->zonemgr, isc_rwlocktype_write);
- RWUNLOCK(&server->conflock, isc_rwlocktype_write);
+ RWUNLOCK(&server->conflock, isc_rwlocktype_write);
return (result);
}
@@ -924,7 +1093,7 @@ run_server(isc_task_t *task, isc_event_t *event) {
isc_result_t result;
ns_server_t *server = (ns_server_t *) event->arg;
- (void)task;
+ UNUSED(task);
isc_event_free(&event);
@@ -937,6 +1106,12 @@ run_server(isc_task_t *task, isc_event_t *event) {
&server->interfacemgr),
"creating interface manager");
+ CHECKFATAL(isc_timer_create(ns_g_timermgr, isc_timertype_inactive,
+ NULL, NULL, server->task,
+ interface_timer_tick,
+ server, &server->interface_timer),
+ "creating interface timer");
+
CHECKFATAL(load_configuration(ns_g_conffile, server, ISC_TRUE),
"loading configuration");
@@ -967,9 +1142,12 @@ shutdown_server(isc_task_t *task, isc_event_t *event) {
dns_view_detach(&view);
}
- if (server->querysrc_dispatch != NULL)
- dns_dispatch_detach(&server->querysrc_dispatch);
+ if (server->querysrc_dispatchv4 != NULL)
+ dns_dispatch_detach(&server->querysrc_dispatchv4);
+ if (server->querysrc_dispatchv6 != NULL)
+ dns_dispatch_detach(&server->querysrc_dispatchv6);
ns_clientmgr_destroy(&server->clientmgr);
+ isc_timer_detach(&server->interface_timer);
ns_interfacemgr_shutdown(server->interfacemgr);
ns_interfacemgr_detach(&server->interfacemgr);
dns_zonemgr_shutdown(server->zonemgr);
@@ -1002,7 +1180,6 @@ ns_server_create(isc_mem_t *mctx, ns_server_t **serverp) {
server->queryacl = NULL;
server->recursionacl = NULL;
- server->transferacl = NULL;
result = isc_quota_init(&server->xfroutquota, 10);
RUNTIME_CHECK(result == ISC_R_SUCCESS);
@@ -1010,7 +1187,12 @@ ns_server_create(isc_mem_t *mctx, ns_server_t **serverp) {
RUNTIME_CHECK(result == ISC_R_SUCCESS);
result = isc_quota_init(&server->recursionquota, 100);
RUNTIME_CHECK(result == ISC_R_SUCCESS);
-
+
+ server->provide_ixfr = ISC_TRUE;
+
+ result = dns_aclenv_init(mctx, &server->aclenv);
+ RUNTIME_CHECK(result == ISC_R_SUCCESS);
+
/* Initialize server data structures. */
server->zonemgr = NULL;
server->clientmgr = NULL;
@@ -1037,7 +1219,8 @@ ns_server_create(isc_mem_t *mctx, ns_server_t **serverp) {
server->tkeyctx = NULL;
CHECKFATAL(dns_tkeyctx_create(ns_g_mctx, &server->tkeyctx),
"creating TKEY context");
- server->querysrc_dispatch = NULL;
+ server->querysrc_dispatchv4 = NULL;
+ server->querysrc_dispatchv6 = NULL;
/*
* Setup the server task, which is responsible for coordinating
@@ -1051,6 +1234,10 @@ ns_server_create(isc_mem_t *mctx, ns_server_t **serverp) {
CHECKFATAL(isc_app_onrun(ns_g_mctx, server->task, run_server, server),
"isc_app_onrun");
+ server->interface_timer = NULL;
+ /*
+ * Create a timer for periodic interface scanning.
+ */
CHECKFATAL(dns_zonemgr_create(ns_g_mctx, ns_g_taskmgr, ns_g_timermgr,
ns_g_socketmgr, &server->zonemgr),
"dns_zonemgr_create");
@@ -1064,7 +1251,8 @@ ns_server_destroy(ns_server_t **serverp) {
ns_server_t *server = *serverp;
REQUIRE(NS_SERVER_VALID(server));
- REQUIRE(server->querysrc_dispatch == NULL);
+ REQUIRE(server->querysrc_dispatchv4 == NULL);
+ REQUIRE(server->querysrc_dispatchv6 == NULL);
if (server->tkeyctx != NULL)
dns_tkeyctx_destroy(&server->tkeyctx);
@@ -1074,15 +1262,15 @@ ns_server_destroy(ns_server_t **serverp) {
dns_zonemgr_destroy(&server->zonemgr);
server->zonemgr = NULL;
-
+
dns_db_detach(&server->roothints);
if (server->queryacl != NULL)
dns_acl_detach(&server->queryacl);
if (server->recursionacl != NULL)
dns_acl_detach(&server->recursionacl);
- if (server->transferacl != NULL)
- dns_acl_detach(&server->transferacl);
+
+ dns_aclenv_destroy(&server->aclenv);
isc_quota_destroy(&server->recursionquota);
isc_quota_destroy(&server->tcpquota);
@@ -1094,10 +1282,10 @@ ns_server_destroy(ns_server_t **serverp) {
}
static void
-fatal(char *msg, isc_result_t result)
-{
+fatal(char *msg, isc_result_t result) {
isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_SERVER,
- ISC_LOG_CRITICAL, "%s: %s", msg, isc_result_totext(result));
+ ISC_LOG_CRITICAL, "%s: %s", msg,
+ isc_result_totext(result));
isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_SERVER,
ISC_LOG_CRITICAL, "exiting (due to fatal error)");
exit(1);
@@ -1106,7 +1294,7 @@ fatal(char *msg, isc_result_t result)
static void
ns_server_reload(isc_task_t *task, isc_event_t *event) {
isc_result_t result;
- ns_server_t *server = (ns_server_t *) event->arg;
+ ns_server_t *server = (ns_server_t *)event->arg;
UNUSED(task);
result = load_configuration(ns_g_conffile, server, ISC_FALSE);
@@ -1194,4 +1382,3 @@ ns_listenelt_fromconfig(dns_c_lstnon_t *celt, dns_c_ctx_t *cctx,
*target = delt;
return (ISC_R_SUCCESS);
}
-
diff --git a/bin/named/update.c b/bin/named/update.c
index 8c993f34..67054c55 100644
--- a/bin/named/update.c
+++ b/bin/named/update.c
@@ -46,15 +46,17 @@
#include <dns/rdatasetiter.h>
#include <dns/rdatastruct.h>
#include <dns/result.h>
+#include <dns/ssu.h>
#include <dns/types.h>
#include <dns/view.h>
#include <dns/zone.h>
#include <dns/zt.h>
-#include <named/globals.h>
#include <named/client.h>
-#include <named/update.h>
+#include <named/globals.h>
#include <named/log.h>
+#include <named/server.h>
+#include <named/update.h>
/*
* This module implements dynamic update as in RFC2136.
@@ -596,6 +598,43 @@ name_exists(dns_db_t *db, dns_dbversion_t *ver, dns_name_t *name,
RETURN_EXISTENCE_FLAG;
}
+typedef struct {
+ dns_name_t *name, *signer;
+ dns_ssutable_t *table;
+} ssu_check_t;
+
+static isc_result_t
+ssu_checkrule(void *data, dns_rdataset_t *rrset) /*ARGSUSED*/
+{
+ ssu_check_t *ssuinfo = data;
+ isc_boolean_t result;
+
+ /*
+ * If we're deleting all records, it's ok to delete SIG and NXT even
+ * if we're normally not allowed to.
+ */
+ if (rrset->type == dns_rdatatype_sig ||
+ rrset->type == dns_rdatatype_nxt)
+ return (ISC_TRUE);
+ result = dns_ssutable_checkrules(ssuinfo->table, ssuinfo->signer,
+ ssuinfo->name, rrset->type);
+ return (result == ISC_TRUE ? ISC_R_SUCCESS : ISC_R_FAILURE);
+}
+
+static isc_boolean_t
+ssu_checkall(dns_db_t *db, dns_dbversion_t *ver, dns_name_t *name,
+ dns_ssutable_t *ssutable, dns_name_t *signer)
+{
+ isc_result_t result;
+ ssu_check_t ssuinfo;
+
+ ssuinfo.name = name;
+ ssuinfo.table = ssutable;
+ ssuinfo.signer = signer;
+ result = foreach_rrset(db, ver, name, ssu_checkrule, &ssuinfo);
+ return (ISC_TF(result == ISC_R_SUCCESS));
+}
+
/**************************************************************************/
/*
* Checking of "RRset exists (value dependent)" prerequisites.
@@ -1702,15 +1741,20 @@ send_update_event(ns_client_t *client, dns_zone_t *zone) {
isc_result_t result = DNS_R_SUCCESS;
update_event_t *event = NULL;
isc_task_t *zonetask = NULL;
+ ns_client_t *evclient;
event = (update_event_t *)
isc_event_allocate(client->mctx, client, DNS_EVENT_UPDATE,
- update_action, client, sizeof(*event));
+ update_action, NULL, sizeof(*event));
if (event == NULL)
FAIL(DNS_R_NOMEMORY);
event->zone = zone;
event->result = DNS_R_SUCCESS;
+ evclient = NULL;
+ ns_client_attach(client, &evclient);
+ event->arg = evclient;
+
dns_zone_gettask(zone, &zonetask);
isc_task_send(zonetask, (isc_event_t **) &event);
@@ -1723,21 +1767,12 @@ send_update_event(ns_client_t *client, dns_zone_t *zone) {
static void
respond(ns_client_t *client, isc_result_t result) {
isc_result_t msg_result;
- dns_message_t *response = NULL;
- msg_result = dns_message_create(client->mctx, DNS_MESSAGE_INTENTRENDER,
- &response);
+ msg_result = dns_message_reply(client->message, ISC_TRUE);
if (msg_result != DNS_R_SUCCESS)
goto msg_failure;
-
- response->id = client->message->id;
- response->rcode = dns_result_torcode(result);
- response->flags = client->message->flags;
- response->flags |= DNS_MESSAGEFLAG_QR;
- response->opcode = client->message->opcode;
-
- dns_message_destroy(&client->message);
- client->message = response;
+ client->message->rcode = dns_result_torcode(result);
+
ns_client_send(client);
return;
@@ -1834,6 +1869,7 @@ update_action(isc_task_t *task, isc_event_t *event)
dns_message_t *request = client->message;
dns_rdataclass_t zoneclass;
dns_name_t *zonename;
+ dns_ssutable_t *ssutable = NULL;
INSIST(event->type == DNS_EVENT_UPDATE);
@@ -1843,6 +1879,7 @@ update_action(isc_task_t *task, isc_event_t *event)
CHECK(dns_zone_getdb(zone, &db));
zonename = dns_db_origin(db);
zoneclass = dns_db_class(db);
+ dns_zone_getssutable(zone, &ssutable);
dns_db_currentversion(db, &oldver);
CHECK(dns_db_newversion(db, &ver));
@@ -1943,10 +1980,14 @@ update_action(isc_task_t *task, isc_event_t *event)
* Check Requestor's Permissions. It seems a bit silly to do this
* only after prerequisite testing, but that is what RFC2136 says.
*/
- CHECK(dns_acl_checkrequest(client->signer,
- ns_client_getsockaddr(client),
- "update", dns_zone_getupdateacl(zone),
- NULL, ISC_FALSE));
+ if (ssutable == NULL)
+ CHECK(ns_client_checkacl(client, "update",
+ dns_zone_getupdateacl(zone),
+ ISC_FALSE));
+ else if (client->signer == NULL) {
+ /* This gets us a free log message. */
+ CHECK(ns_client_checkacl(client, "update", NULL, ISC_FALSE));
+ }
/* Perform the Update Section Prescan. */
@@ -2002,6 +2043,22 @@ update_action(isc_task_t *task, isc_event_t *event)
"explicit NXT updates are not allowed "
"in secure zones");
}
+
+ if (ssutable != NULL && client->signer != NULL) {
+ if (rdata.type != dns_rdatatype_any) {
+ if (!dns_ssutable_checkrules(ssutable,
+ client->signer,
+ name, rdata.type))
+ FAILC(DNS_R_REFUSED,
+ "rejected by secure update");
+ }
+ else {
+ if (!ssu_checkall(db, ver, name, ssutable,
+ client->signer))
+ FAILC(DNS_R_REFUSED,
+ "rejected by secure update");
+ }
+ }
}
if (result != DNS_R_NOMORE)
FAIL(result);
@@ -2253,5 +2310,6 @@ updatedone_action(isc_task_t *task, isc_event_t *event)
INSIST(task == client->task);
respond(client, uev->result);
+ ns_client_detach(&client);
isc_event_free(&event);
}
diff --git a/bin/named/xfrout.c b/bin/named/xfrout.c
index 16fb61b4..91800a30 100644
--- a/bin/named/xfrout.c
+++ b/bin/named/xfrout.c
@@ -15,7 +15,7 @@
* SOFTWARE.
*/
- /* $Id: xfrout.c,v 1.41 2000/02/03 22:29:54 halley Exp $ */
+/* $Id: xfrout.c,v 1.49 2000/03/23 00:54:44 gson Exp $ */
#include <config.h>
@@ -39,6 +39,7 @@
#include <dns/journal.h>
#include <dns/message.h>
#include <dns/name.h>
+#include <dns/peer.h>
#include <dns/rdata.h>
#include <dns/rdatalist.h>
#include <dns/rdataset.h>
@@ -66,7 +67,7 @@
*/
#define XFROUT_COMMON_LOGARGS \
- ns_g_lctx, NS_LOGCATEGORY_XFER_OUT, NS_LOGMODULE_XFER_OUT
+ ns_g_lctx, DNS_LOGCATEGORY_XFER_OUT, NS_LOGMODULE_XFER_OUT
#define XFROUT_PROTOCOL_LOGARGS \
XFROUT_COMMON_LOGARGS, ISC_LOG_INFO
@@ -745,7 +746,6 @@ typedef struct {
dns_tsigkey_t *tsigkey; /* Key used to create TSIG */
dns_rdata_any_tsig_t *lasttsig; /* the last TSIG */
isc_boolean_t many_answers;
- isc_timer_t *timer;
int sends; /* Send in progress */
isc_boolean_t shuttingdown;
} xfrout_ctx_t;
@@ -758,16 +758,16 @@ xfrout_ctx_create(isc_mem_t *mctx, ns_client_t *client,
dns_rdata_any_tsig_t *lasttsig,
unsigned int maxtime,
unsigned int idletime,
+ isc_boolean_t many_answers,
xfrout_ctx_t **xfrp);
static void sendstream(xfrout_ctx_t *xfr);
static void xfrout_senddone(isc_task_t *task, isc_event_t *event);
-static void xfrout_timeout(isc_task_t *task, isc_event_t *event);
static void xfrout_fail(xfrout_ctx_t *xfr, isc_result_t result, char *msg);
static void xfrout_maybe_destroy(xfrout_ctx_t *xfr);
static void xfrout_ctx_destroy(xfrout_ctx_t **xfrp);
-static void xfrout_client_shutdown(void *arg);
+static void xfrout_client_shutdown(void *arg, isc_result_t result);
/**************************************************************************/
@@ -794,6 +794,9 @@ ns_xfr_start(ns_client_t *client, dns_rdatatype_t reqtype)
dns_message_t *request = client->message;
xfrout_ctx_t *xfr = NULL;
isc_quota_t *quota = NULL;
+ dns_transfer_format_t format = ns_g_server->transfer_format;
+ isc_netaddr_t na;
+ dns_peer_t *peer = NULL;
switch (reqtype) {
case dns_rdatatype_axfr:
@@ -906,26 +909,43 @@ ns_xfr_start(ns_client_t *client, dns_rdatatype_t reqtype)
mnemonic);
/* Decide whether to allow this transfer. */
- CHECK(dns_acl_checkrequest(client->signer,
- ns_client_getsockaddr(client),
- "zone transfer",
- dns_zone_getxfracl(zone),
- ns_g_server->transferacl,
- ISC_TRUE));
+ CHECK(ns_client_checkacl(client, "zone transfer",
+ dns_zone_getxfracl(zone),
+ ISC_TRUE));
/* AXFR over UDP is not possible. */
if (reqtype == dns_rdatatype_axfr &&
(client->attributes & NS_CLIENTATTR_TCP) == 0) {
FAILC(DNS_R_FORMERR, "attempted AXFR over UDP");
}
-
+
+ /* Look up the requesting server in the peer table. */
+ isc_netaddr_fromsockaddr(&na, &client->peeraddr);
+ (void) dns_peerlist_peerbyaddr(client->view->peers,
+ &na, &peer);
+
+ /* Decide on the transfer format (one-answer or many-answers). */
+ if (peer != NULL)
+ (void) dns_peer_gettransferformat(peer, &format);
+
/* Get a dynamically allocated copy of the current SOA. */
CHECK(dns_db_createsoatuple(db, ver, mctx, DNS_DIFFOP_EXISTS,
&current_soa_tuple));
if (reqtype == dns_rdatatype_ixfr) {
isc_uint32_t begin_serial, current_serial;
-
+ isc_boolean_t provide_ixfr;
+
+ /*
+ * Outgoing IXFR may have been disabled for this peer
+ * or globally.
+ */
+ provide_ixfr = ns_g_server->provide_ixfr;
+ if (peer != NULL)
+ (void) dns_peer_getprovideixfr(peer, &provide_ixfr);
+ if (provide_ixfr == ISC_FALSE)
+ goto axfr_fallback;
+
if (! have_soa)
FAILC(DNS_R_FORMERR,
"IXFR request missing SOA");
@@ -986,6 +1006,8 @@ ns_xfr_start(ns_client_t *client, dns_rdatatype_t reqtype)
request->tsigkey, request->tsig,
dns_zone_getmaxxfrout(zone),
dns_zone_getidleout(zone),
+ (format == dns_many_answers) ?
+ ISC_TRUE : ISC_FALSE,
&xfr));
stream = NULL;
db = NULL;
@@ -1031,13 +1053,17 @@ ns_xfr_start(ns_client_t *client, dns_rdatatype_t reqtype)
}
}
+
+
+
static isc_result_t
xfrout_ctx_create(isc_mem_t *mctx, ns_client_t *client, unsigned int id,
dns_name_t *qname, dns_rdatatype_t qtype,
dns_db_t *db, dns_dbversion_t *ver, isc_quota_t *quota,
rrstream_t *stream, dns_tsigkey_t *tsigkey,
dns_rdata_any_tsig_t *lasttsig, unsigned int maxtime,
- unsigned int idletime, xfrout_ctx_t **xfrp)
+ unsigned int idletime, isc_boolean_t many_answers,
+ xfrout_ctx_t **xfrp)
{
xfrout_ctx_t *xfr;
isc_result_t result;
@@ -1051,8 +1077,8 @@ xfrout_ctx_create(isc_mem_t *mctx, ns_client_t *client, unsigned int id,
if (xfr == NULL)
return (DNS_R_NOMEMORY);
xfr->mctx = mctx;
- xfr->client = client;
- ns_client_wait(client);
+ xfr->client = NULL;
+ ns_client_attach(client, &xfr->client);
xfr->id = id;
xfr->qname = qname;
xfr->qtype = qtype;
@@ -1066,10 +1092,7 @@ xfrout_ctx_create(isc_mem_t *mctx, ns_client_t *client, unsigned int id,
xfr->txmem = NULL;
xfr->txmemlen = 0;
xfr->nmsg = 0;
- xfr->timer = NULL;
- xfr->many_answers =
- (ns_g_server->transfer_format == dns_many_answers) ?
- ISC_TRUE : ISC_FALSE;
+ xfr->many_answers = many_answers,
xfr->sends = 0;
xfr->shuttingdown = ISC_FALSE;
@@ -1111,10 +1134,10 @@ xfrout_ctx_create(isc_mem_t *mctx, ns_client_t *client, unsigned int id,
CHECK(isc_time_nowplusinterval(&expires, &maxinterval));
isc_interval_set(&idleinterval, idletime, 0);
- CHECK(isc_timer_create(ns_g_timermgr, isc_timertype_once,
- &expires, &idleinterval,
- xfr->client->task,
- xfrout_timeout, xfr, &xfr->timer));
+ CHECK(isc_timer_reset(xfr->client->timer,
+ isc_timertype_once,
+ &expires, &idleinterval,
+ ISC_FALSE));
/*
* Register a shutdown callback with the client, so that we
@@ -1377,8 +1400,6 @@ xfrout_ctx_destroy(xfrout_ctx_t **xfrp) {
xfr->client->shutdown = NULL;
xfr->client->shutdown_arg = NULL;
- if (xfr->timer != NULL)
- isc_timer_detach(&xfr->timer);
if (xfr->stream != NULL)
xfr->stream->methods->destroy(&xfr->stream);
if (xfr->buf.base != NULL)
@@ -1396,7 +1417,7 @@ xfrout_ctx_destroy(xfrout_ctx_t **xfrp) {
if (xfr->db != NULL)
dns_db_detach(&xfr->db);
- ns_client_unwait(xfr->client);
+ ns_client_detach(&xfr->client);
isc_mem_put(xfr->mctx, xfr, sizeof(*xfr));
@@ -1413,7 +1434,7 @@ xfrout_senddone(isc_task_t *task, isc_event_t *event) {
isc_event_free(&event);
xfr->sends--;
INSIST(xfr->sends == 0);
- (void) isc_timer_touch(xfr->timer);
+ (void) isc_timer_touch(xfr->client->timer);
if (xfr->shuttingdown == ISC_TRUE) {
xfrout_maybe_destroy(xfr);
} else if (evresult != ISC_R_SUCCESS) {
@@ -1430,15 +1451,6 @@ xfrout_senddone(isc_task_t *task, isc_event_t *event) {
}
static void
-xfrout_timeout(isc_task_t *task, isc_event_t *event) {
- xfrout_ctx_t *xfr = (xfrout_ctx_t *) event->arg;
- UNUSED(task);
- /* This will log "giving up: timeout". */
- xfrout_fail(xfr, ISC_R_TIMEDOUT, "giving up");
- isc_event_free(&event);
-}
-
-static void
xfrout_fail(xfrout_ctx_t *xfr, isc_result_t result, char *msg)
{
xfr->shuttingdown = ISC_TRUE;
@@ -1465,8 +1477,8 @@ xfrout_maybe_destroy(xfrout_ctx_t *xfr) {
}
static void
-xfrout_client_shutdown(void *arg)
+xfrout_client_shutdown(void *arg, isc_result_t result)
{
xfrout_ctx_t *xfr = (xfrout_ctx_t *) arg;
- xfrout_fail(xfr, ISC_R_SHUTTINGDOWN, "aborted");
+ xfrout_fail(xfr, result, "aborted");
}