summaryrefslogtreecommitdiffstats
path: root/contrib/bind9/bin/named/client.c
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/bind9/bin/named/client.c')
-rw-r--r--contrib/bind9/bin/named/client.c241
1 files changed, 202 insertions, 39 deletions
diff --git a/contrib/bind9/bin/named/client.c b/contrib/bind9/bin/named/client.c
index b0ce793..d69e44b 100644
--- a/contrib/bind9/bin/named/client.c
+++ b/contrib/bind9/bin/named/client.c
@@ -15,13 +15,14 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
-/* $Id: client.c,v 1.176.2.13.4.31 2006/07/22 01:09:38 marka Exp $ */
+/* $Id: client.c,v 1.219.18.20 2006/07/22 01:02:36 marka Exp $ */
#include <config.h>
#include <isc/formatcheck.h>
#include <isc/mutex.h>
#include <isc/once.h>
+#include <isc/platform.h>
#include <isc/print.h>
#include <isc/stdio.h>
#include <isc/string.h>
@@ -33,12 +34,13 @@
#include <dns/dispatch.h>
#include <dns/events.h>
#include <dns/message.h>
+#include <dns/peer.h>
#include <dns/rcode.h>
-#include <dns/resolver.h>
#include <dns/rdata.h>
#include <dns/rdataclass.h>
#include <dns/rdatalist.h>
#include <dns/rdataset.h>
+#include <dns/resolver.h>
#include <dns/tsig.h>
#include <dns/view.h>
#include <dns/zone.h>
@@ -53,7 +55,9 @@
*** Client
***/
-/*
+/*! \file
+ * Client Routines
+ *
* Important note!
*
* All client state changes, other than that from idle to listening, occur
@@ -87,6 +91,25 @@
#define SEND_BUFFER_SIZE 4096
#define RECV_BUFFER_SIZE 4096
+#ifdef ISC_PLATFORM_USETHREADS
+#define NMCTXS 100
+/*%<
+ * Number of 'mctx pools' for clients. (Should this be configurable?)
+ * When enabling threads, we use a pool of memory contexts shared by
+ * client objects, since concurrent access to a shared context would cause
+ * heavy contentions. The above constant is expected to be enough for
+ * completely avoiding contentions among threads for an authoritative-only
+ * server.
+ */
+#else
+#define NMCTXS 0
+/*%<
+ * If named with built without thread, simply share manager's context. Using
+ * a separate context in this case would simply waste memory.
+ */
+#endif
+
+/*% nameserver client manager structure */
struct ns_clientmgr {
/* Unlocked. */
unsigned int magic;
@@ -96,15 +119,20 @@ struct ns_clientmgr {
isc_mutex_t lock;
/* Locked by lock. */
isc_boolean_t exiting;
- client_list_t active; /* Active clients */
- client_list_t recursing; /* Recursing clients */
- client_list_t inactive; /* To be recycled */
+ client_list_t active; /*%< Active clients */
+ client_list_t recursing; /*%< Recursing clients */
+ client_list_t inactive; /*%< To be recycled */
+#if NMCTXS > 0
+ /*%< mctx pool for clients. */
+ unsigned int nextmctx;
+ isc_mem_t * mctxpool[NMCTXS];
+#endif
};
#define MANAGER_MAGIC ISC_MAGIC('N', 'S', 'C', 'm')
#define VALID_MANAGER(m) ISC_MAGIC_VALID(m, 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.
@@ -117,12 +145,12 @@ struct ns_clientmgr {
*/
#define NS_CLIENTSTATE_FREED 0
-/*
+/*%<
* The client object no longer exists.
*/
#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.
@@ -130,7 +158,7 @@ struct ns_clientmgr {
*/
#define NS_CLIENTSTATE_READY 2
-/*
+/*%<
* 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.
@@ -143,7 +171,7 @@ struct ns_clientmgr {
*/
#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
@@ -151,14 +179,14 @@ struct ns_clientmgr {
*/
#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.
*/
#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.
@@ -171,6 +199,8 @@ struct ns_clientmgr {
#define NS_CLIENT_DROPPORT 1
#endif
+unsigned int ns_client_requests;
+
static void client_read(ns_client_t *client);
static void client_accept(ns_client_t *client);
static void client_udprecv(ns_client_t *client);
@@ -227,7 +257,7 @@ ns_client_settimeout(ns_client_t *client, unsigned int seconds) {
}
}
-/*
+/*%
* 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
@@ -489,7 +519,7 @@ exit_check(ns_client_t *client) {
CTRACE("free");
client->magic = 0;
- isc_mem_put(client->mctx, client, sizeof(*client));
+ isc_mem_putanddetach(&client->mctx, client, sizeof(*client));
goto unlock;
}
@@ -510,7 +540,7 @@ exit_check(ns_client_t *client) {
return (ISC_TRUE);
}
-/*
+/*%
* The client's task has received the client's control event
* as part of the startup process.
*/
@@ -536,7 +566,7 @@ client_start(isc_task_t *task, isc_event_t *event) {
}
-/*
+/*%
* The client's task has received a shutdown event.
*/
static void
@@ -591,6 +621,7 @@ ns_client_endrequest(ns_client_t *client) {
client->udpsize = 512;
client->extflags = 0;
+ client->ednsversion = -1;
dns_message_reset(client->message, DNS_MESSAGE_INTENTPARSE);
if (client->recursionquota != NULL)
@@ -705,7 +736,7 @@ client_senddone(isc_task_t *task, isc_event_t *event) {
ns_client_next(client, ISC_R_SUCCESS);
}
-/*
+/*%
* We only want to fail with ISC_R_NOSPACE when called from
* ns_client_sendraw() and not when called from ns_client_send(),
* tcpbuffer is NULL when called from ns_client_sendraw() and
@@ -1182,6 +1213,64 @@ allowed(isc_netaddr_t *addr, dns_name_t *signer, dns_acl_t *acl) {
}
/*
+ * Callback to see if a non-recursive query coming from 'srcaddr' to
+ * 'destaddr', with optional key 'mykey' for class 'rdclass' would be
+ * delivered to 'myview'.
+ *
+ * We run this unlocked as both the view list and the interface list
+ * are updated when the approprite task has exclusivity.
+ */
+isc_boolean_t
+ns_client_isself(dns_view_t *myview, dns_tsigkey_t *mykey,
+ isc_sockaddr_t *srcaddr, isc_sockaddr_t *dstaddr,
+ dns_rdataclass_t rdclass, void *arg)
+{
+ dns_view_t *view;
+ dns_tsigkey_t *key;
+ isc_netaddr_t netsrc;
+ isc_netaddr_t netdst;
+
+ UNUSED(arg);
+
+ if (!ns_interfacemgr_listeningon(ns_g_server->interfacemgr, dstaddr))
+ return (ISC_FALSE);
+
+ isc_netaddr_fromsockaddr(&netsrc, srcaddr);
+ isc_netaddr_fromsockaddr(&netdst, dstaddr);
+
+ for (view = ISC_LIST_HEAD(ns_g_server->viewlist);
+ view != NULL;
+ view = ISC_LIST_NEXT(view, link)) {
+ dns_name_t *tsig = NULL;
+
+ if (view->matchrecursiveonly)
+ continue;
+
+ if (rdclass != view->rdclass)
+ continue;
+
+ if (mykey != NULL) {
+ isc_boolean_t match;
+ isc_result_t result;
+
+ tsig = &mykey->name;
+ result = dns_view_gettsig(view, tsig, &key);
+ if (result != ISC_R_SUCCESS)
+ continue;
+ match = dst_key_compare(mykey->key, key->key);
+ dns_tsigkey_detach(&key);
+ if (!match)
+ continue;
+ }
+
+ if (allowed(&netsrc, tsig, view->matchclients) &&
+ allowed(&netdst, tsig, view->matchdestinations))
+ break;
+ }
+ return (ISC_TF(view == myview));
+}
+
+/*
* Handle an incoming request event from the socket (UDP case)
* or tcpmsg (TCP case).
*/
@@ -1215,6 +1304,8 @@ client_request(isc_task_t *task, isc_event_t *event) {
NS_CLIENTSTATE_READING :
NS_CLIENTSTATE_READY);
+ ns_client_requests++;
+
if (event->ev_type == ISC_SOCKEVENT_RECVDONE) {
INSIST(!TCP_CLIENT(client));
sevent = (isc_socketevent_t *)event;
@@ -1384,8 +1475,6 @@ client_request(isc_task_t *task, isc_event_t *event) {
*/
opt = dns_message_getopt(client->message);
if (opt != NULL) {
- unsigned int version;
-
/*
* Set the client's UDP buffer size.
*/
@@ -1404,22 +1493,24 @@ client_request(isc_task_t *task, isc_event_t *event) {
client->extflags = (isc_uint16_t)(opt->ttl & 0xFFFF);
/*
- * Create an OPT for our reply.
+ * Do we understand this version of EDNS?
+ *
+ * XXXRTH need library support for this!
*/
- result = client_addopt(client);
- if (result != ISC_R_SUCCESS) {
+ client->ednsversion = (opt->ttl & 0x00FF0000) >> 16;
+ if (client->ednsversion > 0) {
+ result = client_addopt(client);
+ if (result == ISC_R_SUCCESS)
+ result = DNS_R_BADVERS;
ns_client_error(client, result);
goto cleanup;
}
-
/*
- * Do we understand this version of ENDS?
- *
- * XXXRTH need library support for this!
+ * Create an OPT for our reply.
*/
- version = (opt->ttl & 0x00FF0000) >> 16;
- if (version != 0) {
- ns_client_error(client, DNS_R_BADVERS);
+ result = client_addopt(client);
+ if (result != ISC_R_SUCCESS) {
+ ns_client_error(client, result);
goto cleanup;
}
}
@@ -1629,6 +1720,19 @@ client_request(isc_task_t *task, isc_event_t *event) {
"recursion not available");
/*
+ * Adjust maximum UDP response size for this client.
+ */
+ if (client->udpsize > 512) {
+ dns_peer_t *peer = NULL;
+ isc_uint16_t udpsize = view->maxudp;
+ (void) dns_peerlist_peerbyaddr(view->peers, &netaddr, &peer);
+ if (peer != NULL)
+ dns_peer_getmaxudp(peer, &udpsize);
+ if (client->udpsize > udpsize)
+ client->udpsize = udpsize;
+ }
+
+ /*
* Dispatch the request.
*/
switch (client->message->opcode) {
@@ -1689,9 +1793,42 @@ client_timeout(isc_task_t *task, isc_event_t *event) {
}
static isc_result_t
+get_clientmctx(ns_clientmgr_t *manager, isc_mem_t **mctxp) {
+ isc_mem_t *clientmctx;
+#if NMCTXS > 0
+ isc_result_t result;
+#endif
+
+ /*
+ * Caller must be holding the manager lock.
+ */
+#if NMCTXS > 0
+ INSIST(manager->nextmctx < NMCTXS);
+ clientmctx = manager->mctxpool[manager->nextmctx];
+ if (clientmctx == NULL) {
+ result = isc_mem_create(0, 0, &clientmctx);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+
+ manager->mctxpool[manager->nextmctx] = clientmctx;
+ manager->nextmctx++;
+ if (manager->nextmctx == NMCTXS)
+ manager->nextmctx = 0;
+ }
+#else
+ clientmctx = manager->mctx;
+#endif
+
+ isc_mem_attach(clientmctx, mctxp);
+
+ return (ISC_R_SUCCESS);
+}
+
+static isc_result_t
client_create(ns_clientmgr_t *manager, ns_client_t **clientp) {
ns_client_t *client;
isc_result_t result;
+ isc_mem_t *mctx = NULL;
/*
* Caller must be holding the manager lock.
@@ -1703,9 +1840,16 @@ client_create(ns_clientmgr_t *manager, ns_client_t **clientp) {
REQUIRE(clientp != NULL && *clientp == NULL);
- client = isc_mem_get(manager->mctx, sizeof(*client));
- if (client == NULL)
+ result = get_clientmctx(manager, &mctx);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+
+ client = isc_mem_get(mctx, sizeof(*client));
+ if (client == NULL) {
+ isc_mem_detach(&mctx);
return (ISC_R_NOMEMORY);
+ }
+ client->mctx = mctx;
client->task = NULL;
result = isc_task_create(manager->taskmgr, 0, &client->task);
@@ -1722,7 +1866,7 @@ client_create(ns_clientmgr_t *manager, ns_client_t **clientp) {
client->timerset = ISC_FALSE;
client->message = NULL;
- result = dns_message_create(manager->mctx, DNS_MESSAGE_INTENTPARSE,
+ result = dns_message_create(client->mctx, DNS_MESSAGE_INTENTPARSE,
&client->message);
if (result != ISC_R_SUCCESS)
goto cleanup_timer;
@@ -1730,7 +1874,7 @@ client_create(ns_clientmgr_t *manager, ns_client_t **clientp) {
/* XXXRTH Hardwired constants */
client->sendevent = (isc_socketevent_t *)
- isc_event_allocate(manager->mctx, client,
+ isc_event_allocate(client->mctx, client,
ISC_SOCKEVENT_SENDDONE,
client_senddone, client,
sizeof(isc_socketevent_t));
@@ -1739,14 +1883,14 @@ client_create(ns_clientmgr_t *manager, ns_client_t **clientp) {
goto cleanup_message;
}
- client->recvbuf = isc_mem_get(manager->mctx, RECV_BUFFER_SIZE);
+ client->recvbuf = isc_mem_get(client->mctx, RECV_BUFFER_SIZE);
if (client->recvbuf == NULL) {
result = ISC_R_NOMEMORY;
goto cleanup_sendevent;
}
client->recvevent = (isc_socketevent_t *)
- isc_event_allocate(manager->mctx, client,
+ isc_event_allocate(client->mctx, client,
ISC_SOCKEVENT_RECVDONE,
client_request, client,
sizeof(isc_socketevent_t));
@@ -1756,7 +1900,6 @@ client_create(ns_clientmgr_t *manager, ns_client_t **clientp) {
}
client->magic = NS_CLIENT_MAGIC;
- client->mctx = manager->mctx;
client->manager = NULL;
client->state = NS_CLIENTSTATE_INACTIVE;
client->newstate = NS_CLIENTSTATE_MAX;
@@ -1778,6 +1921,7 @@ client_create(ns_clientmgr_t *manager, ns_client_t **clientp) {
client->opt = NULL;
client->udpsize = 512;
client->extflags = 0;
+ client->ednsversion = -1;
client->next = NULL;
client->shutdown = NULL;
client->shutdown_arg = NULL;
@@ -1826,7 +1970,7 @@ client_create(ns_clientmgr_t *manager, ns_client_t **clientp) {
isc_event_free((isc_event_t **)&client->recvevent);
cleanup_recvbuf:
- isc_mem_put(manager->mctx, client->recvbuf, RECV_BUFFER_SIZE);
+ isc_mem_put(client->mctx, client->recvbuf, RECV_BUFFER_SIZE);
cleanup_sendevent:
isc_event_free((isc_event_t **)&client->sendevent);
@@ -1843,7 +1987,7 @@ client_create(ns_clientmgr_t *manager, ns_client_t **clientp) {
isc_task_detach(&client->task);
cleanup_client:
- isc_mem_put(manager->mctx, client, sizeof(*client));
+ isc_mem_putanddetach(&client->mctx, client, sizeof(*client));
return (result);
}
@@ -2096,12 +2240,23 @@ ns_client_replace(ns_client_t *client) {
static void
clientmgr_destroy(ns_clientmgr_t *manager) {
+#if NMCTXS > 0
+ int i;
+#endif
+
REQUIRE(ISC_LIST_EMPTY(manager->active));
REQUIRE(ISC_LIST_EMPTY(manager->inactive));
REQUIRE(ISC_LIST_EMPTY(manager->recursing));
MTRACE("clientmgr_destroy");
+#if NMCTXS > 0
+ for (i = 0; i < NMCTXS; i++) {
+ if (manager->mctxpool[i] != NULL)
+ isc_mem_detach(&manager->mctxpool[i]);
+ }
+#endif
+
DESTROYLOCK(&manager->lock);
manager->magic = 0;
isc_mem_put(manager->mctx, manager, sizeof(*manager));
@@ -2113,6 +2268,9 @@ ns_clientmgr_create(isc_mem_t *mctx, isc_taskmgr_t *taskmgr,
{
ns_clientmgr_t *manager;
isc_result_t result;
+#if NMCTXS > 0
+ int i;
+#endif
manager = isc_mem_get(mctx, sizeof(*manager));
if (manager == NULL)
@@ -2129,6 +2287,11 @@ ns_clientmgr_create(isc_mem_t *mctx, isc_taskmgr_t *taskmgr,
ISC_LIST_INIT(manager->active);
ISC_LIST_INIT(manager->inactive);
ISC_LIST_INIT(manager->recursing);
+#if NMCTXS > 0
+ manager->nextmctx = 0;
+ for (i = 0; i < NMCTXS; i++)
+ manager->mctxpool[i] = NULL; /* will be created on-demand */
+#endif
manager->magic = MANAGER_MAGIC;
MTRACE("create");
OpenPOWER on IntegriCloud