diff options
author | Internet Software Consortium, Inc <@isc.org> | 2007-09-07 14:08:17 -0600 |
---|---|---|
committer | LaMont Jones <lamont@debian.org> | 2007-09-07 14:08:17 -0600 |
commit | 6257efc35455318993208bef65a551ac6039f51f (patch) | |
tree | 7a1422be299ecd74d6c04e81e9ef638d3d5be388 /bin/named | |
parent | ab47e90612dcdb02c4b134cfb1be0697007c0dac (diff) | |
download | bind9-6257efc35455318993208bef65a551ac6039f51f.tar.gz |
9.0.0b2
Diffstat (limited to 'bin/named')
-rw-r--r-- | bin/named/Makefile.in | 16 | ||||
-rw-r--r-- | bin/named/client.c | 732 | ||||
-rw-r--r-- | bin/named/include/named/client.h | 55 | ||||
-rw-r--r-- | bin/named/include/named/globals.h | 8 | ||||
-rw-r--r-- | bin/named/include/named/interfacemgr.h | 4 | ||||
-rw-r--r-- | bin/named/include/named/log.h | 11 | ||||
-rw-r--r-- | bin/named/include/named/logconf.h | 32 | ||||
-rw-r--r-- | bin/named/include/named/omapi.h | 3 | ||||
-rw-r--r-- | bin/named/include/named/server.h | 15 | ||||
-rw-r--r-- | bin/named/interfacemgr.c | 151 | ||||
-rw-r--r-- | bin/named/log.c | 72 | ||||
-rw-r--r-- | bin/named/logconf.c | 183 | ||||
-rw-r--r-- | bin/named/main.c | 66 | ||||
-rw-r--r-- | bin/named/notify.c | 6 | ||||
-rw-r--r-- | bin/named/omapi.c | 100 | ||||
-rw-r--r-- | bin/named/query.c | 45 | ||||
-rw-r--r-- | bin/named/server.c | 391 | ||||
-rw-r--r-- | bin/named/update.c | 96 | ||||
-rw-r--r-- | bin/named/xfrout.c | 90 |
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(®ion)); /* @@ -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(®ion)); 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(®ion)); 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, ¤t_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"); } |