diff options
Diffstat (limited to 'contrib/bind9/bin/named/client.c')
-rw-r--r-- | contrib/bind9/bin/named/client.c | 241 |
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"); |