client.c revision 77d048b03eec3222e283426beab46ec23ecf8371
ca41b452ede6feaa9d8739ec3cae19389a7b0d03Bob Halley * Copyright (C) 2004-2011 Internet Systems Consortium, Inc. ("ISC")
910df98b0efcbe8380b952887f4071051cc39a25Michael Graff * Copyright (C) 1999-2003 Internet Software Consortium.
910df98b0efcbe8380b952887f4071051cc39a25Michael Graff * Permission to use, copy, modify, and/or distribute this software for any
910df98b0efcbe8380b952887f4071051cc39a25Michael Graff * purpose with or without fee is hereby granted, provided that the above
910df98b0efcbe8380b952887f4071051cc39a25Michael Graff * copyright notice and this permission notice appear in all copies.
910df98b0efcbe8380b952887f4071051cc39a25Michael Graff * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
910df98b0efcbe8380b952887f4071051cc39a25Michael Graff * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
910df98b0efcbe8380b952887f4071051cc39a25Michael Graff * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
910df98b0efcbe8380b952887f4071051cc39a25Michael Graff * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
910df98b0efcbe8380b952887f4071051cc39a25Michael Graff * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
910df98b0efcbe8380b952887f4071051cc39a25Michael Graff * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
910df98b0efcbe8380b952887f4071051cc39a25Michael Graff * PERFORMANCE OF THIS SOFTWARE.
910df98b0efcbe8380b952887f4071051cc39a25Michael Graff/* $Id: client.c,v 1.284 2011/11/09 22:05:09 each Exp $ */
970cccf46e0f949a1a9edbcd8302dd2a112b43c2Michael Graff * Client Routines
970cccf46e0f949a1a9edbcd8302dd2a112b43c2Michael Graff * Important note!
970cccf46e0f949a1a9edbcd8302dd2a112b43c2Michael Graff * All client state changes, other than that from idle to listening, occur
970cccf46e0f949a1a9edbcd8302dd2a112b43c2Michael Graff * as a result of events. This guarantees serialization and avoids the
970cccf46e0f949a1a9edbcd8302dd2a112b43c2Michael Graff * need for locking.
970cccf46e0f949a1a9edbcd8302dd2a112b43c2Michael Graff * If a routine is ever created that allows someone other than the client's
86944a4c8002e80ae9b6eb5a5e29b797879be45fMichael Graff * task to change the client, then the client will have to be locked.
910df98b0efcbe8380b952887f4071051cc39a25Michael Graff#define CTRACE(m) ((void)(m))
910df98b0efcbe8380b952887f4071051cc39a25Michael Graff#define MTRACE(m) ((void)(m))
910df98b0efcbe8380b952887f4071051cc39a25Michael Graff#define TCP_CLIENT(c) (((c)->attributes & NS_CLIENTATTR_TCP) != 0)
970cccf46e0f949a1a9edbcd8302dd2a112b43c2Michael Graff * Number of 'mctx pools' for clients. (Should this be configurable?)
970cccf46e0f949a1a9edbcd8302dd2a112b43c2Michael Graff * When enabling threads, we use a pool of memory contexts shared by
970cccf46e0f949a1a9edbcd8302dd2a112b43c2Michael Graff * client objects, since concurrent access to a shared context would cause
c803787146cadcb2d7e10cbf4491f3be513dfa1aMichael Graff * heavy contentions. The above constant is expected to be enough for
970cccf46e0f949a1a9edbcd8302dd2a112b43c2Michael Graff * completely avoiding contentions among threads for an authoritative-only
970cccf46e0f949a1a9edbcd8302dd2a112b43c2Michael Graff * If named with built without thread, simply share manager's context. Using
970cccf46e0f949a1a9edbcd8302dd2a112b43c2Michael Graff * a separate context in this case would simply waste memory.
970cccf46e0f949a1a9edbcd8302dd2a112b43c2Michael Graff/*% nameserver client manager structure */
970cccf46e0f949a1a9edbcd8302dd2a112b43c2Michael Graff /* Unlocked. */
970cccf46e0f949a1a9edbcd8302dd2a112b43c2Michael Graff unsigned int magic;
970cccf46e0f949a1a9edbcd8302dd2a112b43c2Michael Graff /* The queue object has its own locks */
2bcb48cfcae36398454c98e40c563e2cde748e07Michael Graff client_queue_t inactive; /*%< To be recycled */
970cccf46e0f949a1a9edbcd8302dd2a112b43c2Michael Graff /* Lock covers manager state. */
970cccf46e0f949a1a9edbcd8302dd2a112b43c2Michael Graff /* Lock covers the clients list */
970cccf46e0f949a1a9edbcd8302dd2a112b43c2Michael Graff client_list_t clients; /*%< All active clients */
efc8a09e19dfcfafa92fd2ad113073a4f5295e9bMichael Graff /* Lock covers the recursing list */
86944a4c8002e80ae9b6eb5a5e29b797879be45fMichael Graff client_list_t recursing; /*%< Recursing clients */
86944a4c8002e80ae9b6eb5a5e29b797879be45fMichael Graff /*%< mctx pool for clients. */
897c9ddb4d745b2bfecf98b17e5487bb6656299aMichael Graff#define MANAGER_MAGIC ISC_MAGIC('N', 'S', 'C', 'm')
897c9ddb4d745b2bfecf98b17e5487bb6656299aMichael Graff#define VALID_MANAGER(m) ISC_MAGIC_VALID(m, MANAGER_MAGIC)
970cccf46e0f949a1a9edbcd8302dd2a112b43c2Michael Graff * Client object states. Ordering is significant: higher-numbered
c803787146cadcb2d7e10cbf4491f3be513dfa1aMichael Graff * states are generally "more active", meaning that the client can
c803787146cadcb2d7e10cbf4491f3be513dfa1aMichael Graff * have more dynamically allocated data, outstanding events, etc.
2bcb48cfcae36398454c98e40c563e2cde748e07Michael Graff * In the list below, any such properties listed for state N
2bcb48cfcae36398454c98e40c563e2cde748e07Michael Graff * also apply to any state > N.
970cccf46e0f949a1a9edbcd8302dd2a112b43c2Michael Graff * To force the client into a less active state, set client->newstate
970cccf46e0f949a1a9edbcd8302dd2a112b43c2Michael Graff * to that state and call exit_check(). This will cause any
86944a4c8002e80ae9b6eb5a5e29b797879be45fMichael Graff * activities defined for higher-numbered states to be aborted.
efc8a09e19dfcfafa92fd2ad113073a4f5295e9bMichael Graff * The client object no longer exists.
efc8a09e19dfcfafa92fd2ad113073a4f5295e9bMichael Graff * The client object exists and has a task and timer.
efc8a09e19dfcfafa92fd2ad113073a4f5295e9bMichael Graff * Its "query" struct and sendbuf are initialized.
efc8a09e19dfcfafa92fd2ad113073a4f5295e9bMichael Graff * It is on the client manager's list of inactive clients.
efc8a09e19dfcfafa92fd2ad113073a4f5295e9bMichael Graff * It has a message and OPT, both in the reset state.
efc8a09e19dfcfafa92fd2ad113073a4f5295e9bMichael Graff * The client object is either a TCP or a UDP one, and
efc8a09e19dfcfafa92fd2ad113073a4f5295e9bMichael Graff * it is associated with a network interface. It is on the
efc8a09e19dfcfafa92fd2ad113073a4f5295e9bMichael Graff * client manager's list of active clients.
efc8a09e19dfcfafa92fd2ad113073a4f5295e9bMichael Graff * If it is a TCP client object, it has a TCP listener socket
fd15c8e32ed0c1cfd3ed737858a81966e7fbaeacAndreas Gustafsson * and an outstanding TCP listen request.
efc8a09e19dfcfafa92fd2ad113073a4f5295e9bMichael Graff * If it is a UDP client object, it has a UDP listener socket
efc8a09e19dfcfafa92fd2ad113073a4f5295e9bMichael Graff * and an outstanding UDP receive request.
efc8a09e19dfcfafa92fd2ad113073a4f5295e9bMichael Graff * The client object is a TCP client object that has received
efc8a09e19dfcfafa92fd2ad113073a4f5295e9bMichael Graff * a connection. It has a tcpsocket, tcpmsg, TCP quota, and an
efc8a09e19dfcfafa92fd2ad113073a4f5295e9bMichael Graff * outstanding TCP read request. This state is not used for
efc8a09e19dfcfafa92fd2ad113073a4f5295e9bMichael Graff * UDP client objects.
fd15c8e32ed0c1cfd3ed737858a81966e7fbaeacAndreas Gustafsson * The client object has received a request and is working
fd15c8e32ed0c1cfd3ed737858a81966e7fbaeacAndreas Gustafsson * on it. It has a view, and it may have any of a non-reset OPT,
fd15c8e32ed0c1cfd3ed737858a81966e7fbaeacAndreas Gustafsson * recursion quota, and an outstanding write request.
efc8a09e19dfcfafa92fd2ad113073a4f5295e9bMichael Graff * The client object is recursing. It will be on the 'recursing'
efc8a09e19dfcfafa92fd2ad113073a4f5295e9bMichael Graff * Sentinel value used to indicate "no state". When client->newstate
efa4ebbff3c9f6f38ab8b55540fb696243c1172cAndreas Gustafsson * has this value, we are not attempting to exit the current state.
e592dd7c344052ee51eb707cd744b48b34f4c74eBob Halley * Must be greater than any valid state.
efc8a09e19dfcfafa92fd2ad113073a4f5295e9bMichael Graff * Enable ns_client_dropport() by default.
970cccf46e0f949a1a9edbcd8302dd2a112b43c2Michael Graffstatic void client_accept(ns_client_t *client);
910df98b0efcbe8380b952887f4071051cc39a25Michael Graffstatic void client_udprecv(ns_client_t *client);
970cccf46e0f949a1a9edbcd8302dd2a112b43c2Michael Graffstatic void clientmgr_destroy(ns_clientmgr_t *manager);
528829aa8ad69238e674cd81078bc14d4199691bMichael Graffstatic isc_boolean_t exit_check(ns_client_t *client);
970cccf46e0f949a1a9edbcd8302dd2a112b43c2Michael Graffstatic void ns_client_endrequest(ns_client_t *client);
970cccf46e0f949a1a9edbcd8302dd2a112b43c2Michael Graffstatic void client_start(isc_task_t *task, isc_event_t *event);
970cccf46e0f949a1a9edbcd8302dd2a112b43c2Michael Graffstatic void client_request(isc_task_t *task, isc_event_t *event);
970cccf46e0f949a1a9edbcd8302dd2a112b43c2Michael Graffstatic void ns_client_dumpmessage(ns_client_t *client, const char *reason);
6e49e91bd08778d7eae45a2229dcf41ed97cc636David Lawrencestatic isc_result_t get_client(ns_clientmgr_t *manager, ns_interface_t *ifp,
970cccf46e0f949a1a9edbcd8302dd2a112b43c2Michael Graff REQUIRE(client->state == NS_CLIENTSTATE_WORKING);
970cccf46e0f949a1a9edbcd8302dd2a112b43c2Michael Graff ISC_LIST_APPEND(client->manager->recursing, client, rlink);
1a0e33bc2044e1902493111db14cbf793083ac47Michael Graffns_client_killoldestquery(ns_client_t *client) {
ff9bb3fc5453bbf310b67c560fbf04a5c0fb60daMichael Graff oldest = ISC_LIST_HEAD(client->manager->recursing);
970cccf46e0f949a1a9edbcd8302dd2a112b43c2Michael Graff ISC_LIST_UNLINK(client->manager->recursing, oldest, rlink);
970cccf46e0f949a1a9edbcd8302dd2a112b43c2Michael Graffns_client_settimeout(ns_client_t *client, unsigned int seconds) {
ff9bb3fc5453bbf310b67c560fbf04a5c0fb60daMichael Graff result = isc_timer_reset(client->timer, isc_timertype_once, NULL,
86944a4c8002e80ae9b6eb5a5e29b797879be45fMichael Graff "setting timeout: %s",
910df98b0efcbe8380b952887f4071051cc39a25Michael Graff /* Continue anyway. */
970cccf46e0f949a1a9edbcd8302dd2a112b43c2Michael Graff * Check for a deactivation or shutdown request and take appropriate
970cccf46e0f949a1a9edbcd8302dd2a112b43c2Michael Graff * action. Returns ISC_TRUE if either is in progress; in this case
910df98b0efcbe8380b952887f4071051cc39a25Michael Graff * the caller must no longer use the client object as it may have been
2bcb48cfcae36398454c98e40c563e2cde748e07Michael Graff INSIST(client->newstate < NS_CLIENTSTATE_RECURSING);
ff9bb3fc5453bbf310b67c560fbf04a5c0fb60daMichael Graff * We need to detach from the view early when shutting down
ff9bb3fc5453bbf310b67c560fbf04a5c0fb60daMichael Graff * the server to break the following vicious circle:
ff9bb3fc5453bbf310b67c560fbf04a5c0fb60daMichael Graff * - The resolver will not shut down until the view refcount is zero
ff9bb3fc5453bbf310b67c560fbf04a5c0fb60daMichael Graff * - The view refcount does not go to zero until all clients detach
e198cb953c1a5bc189ae21dc3f8d622f5a08bc34Bob Halley * - The client does not detach from the view until references is zero
ff9bb3fc5453bbf310b67c560fbf04a5c0fb60daMichael Graff * - references does not go to zero until the resolver has shut down
ff9bb3fc5453bbf310b67c560fbf04a5c0fb60daMichael Graff * Keep the view attached until any outstanding updates complete.
ff9bb3fc5453bbf310b67c560fbf04a5c0fb60daMichael Graff client->newstate == NS_CLIENTSTATE_FREED && client->view != NULL)
ff9bb3fc5453bbf310b67c560fbf04a5c0fb60daMichael Graff if (client->state == NS_CLIENTSTATE_WORKING ||
ff9bb3fc5453bbf310b67c560fbf04a5c0fb60daMichael Graff INSIST(client->newstate <= NS_CLIENTSTATE_READING);
910df98b0efcbe8380b952887f4071051cc39a25Michael Graff * Let the update processing complete.
910df98b0efcbe8380b952887f4071051cc39a25Michael Graff * We are trying to abort request processing.
29f28fe573d4b3b318b3b026d567c1eb86738015Michael Graff if (! (client->nsends == 0 && client->nrecvs == 0 &&
cebd4498636d3d480f6f2a7aa2eb72bd2ed64010Michael Graff * Still waiting for I/O cancel completion.
cebd4498636d3d480f6f2a7aa2eb72bd2ed64010Michael Graff * or lingering references.
f942258b6380ba1f2c2f057a79ffc37bc3436488Michael Graff * I/O cancel is complete. Burn down all state
f942258b6380ba1f2c2f057a79ffc37bc3436488Michael Graff * related to the current request. Ensure that
f942258b6380ba1f2c2f057a79ffc37bc3436488Michael Graff * the client is no longer on the recursing list.
1a0e33bc2044e1902493111db14cbf793083ac47Michael Graff * We need to check whether the client is still linked,
f942258b6380ba1f2c2f057a79ffc37bc3436488Michael Graff * because it may already have been removed from the
f942258b6380ba1f2c2f057a79ffc37bc3436488Michael Graff * recursing list by ns_client_killoldestquery()
1a0e33bc2044e1902493111db14cbf793083ac47Michael Graff if (client->state == NS_CLIENTSTATE_RECURSING) {
f942258b6380ba1f2c2f057a79ffc37bc3436488Michael Graff if (NS_CLIENTSTATE_READING == client->newstate) {
86944a4c8002e80ae9b6eb5a5e29b797879be45fMichael Graff if (client->state == NS_CLIENTSTATE_READING) {
910df98b0efcbe8380b952887f4071051cc39a25Michael Graff * We are trying to abort the current TCP connection,
30251e07d1705d1a85b0e1d5a969496e1aed612eMichael Graff INSIST(client->newstate <= NS_CLIENTSTATE_READY);
ff9bb3fc5453bbf310b67c560fbf04a5c0fb60daMichael Graff /* Still waiting for read cancel completion. */
return (ISC_TRUE);
return (ISC_TRUE);
return (ISC_TRUE);
return (ISC_TRUE);
if (!ns_g_clienttest)
return (ISC_TRUE);
INSIST(0);
return (ISC_TRUE);
int newstate;
static isc_result_t
unsigned char *data;
goto done;
goto done;
goto done;
done:
return (result);
static isc_result_t
isc_region_t r;
int match;
match > 0)
return (DNS_R_BLACKHOLED);
return (result);
unsigned char *data;
isc_region_t r;
goto done;
goto done;
goto done;
done:
unsigned char *data;
isc_region_t r;
unsigned int render_opts;
unsigned int preferred_glue;
render_opts = 0;
#ifdef ALLOW_FILTER_AAAA_ON_V4
preferred_glue = 0;
goto done;
goto done;
goto done;
goto done;
DNS_SECTION_QUESTION, 0);
goto renderend;
goto done;
goto renderend;
goto done;
goto renderend;
goto done;
goto done;
goto done;
if (cleanup_cctx) {
if (opt_included) {
done:
if (cleanup_cctx)
#define DROPPORT_NO 0
switch (port) {
return (DROPPORT_REQUEST);
return (DROPPORT_RESPONSE);
return (DROPPORT_NO);
DROPPORT_NO) {
isc_buffer_t b;
static inline isc_result_t
return (result);
return (result);
return (result);
goto no_nsid;
goto no_nsid;
== ISC_R_SUCCESS);
return (ISC_R_SUCCESS);
static inline isc_boolean_t
int match;
return (ISC_TRUE);
return (ISC_TRUE);
return (ISC_FALSE);
return (ISC_TRUE);
return (ISC_FALSE);
if (!match)
int match;
unsigned int flags;
goto cleanup;
goto cleanup;
goto cleanup;
match > 0)
goto cleanup;
goto cleanup;
goto cleanup;
goto cleanup;
goto cleanup;
goto cleanup;
case dns_opcode_query:
case dns_opcode_update:
case dns_opcode_notify:
case dns_opcode_iquery:
goto cleanup;
goto cleanup;
goto cleanup;
&sockaddr);
goto cleanup;
view);
isc_buffer_t b;
isc_region_t *r;
sizeof(classname));
goto cleanup;
isc_buffer_t b;
goto cleanup;
case dns_opcode_query:
case dns_opcode_update:
case dns_opcode_notify:
case dns_opcode_iquery:
static isc_result_t
#if NMCTXS > 0
unsigned int nextmctx;
if (ns_g_clienttest) {
return (result);
#if NMCTXS > 0
return (result);
return (ISC_R_SUCCESS);
static isc_result_t
return (result);
return (ISC_R_NOMEMORY);
goto cleanup_client;
goto cleanup_task;
goto cleanup_timer;
sizeof(isc_socketevent_t));
goto cleanup_message;
goto cleanup_sendevent;
sizeof(isc_socketevent_t));
goto cleanup_recvbuf;
goto cleanup_recvevent;
goto cleanup_query;
return (ISC_R_SUCCESS);
return (result);
goto fail;
fail:
goto freeevent;
int match;
match > 0)
goto freeevent;
isc_region_t r;
return (result);
return (ISC_R_SUCCESS);
#if NMCTXS > 0
#if NMCTXS > 0
for (i = 0; i < NMCTXS; i++) {
#if NMCTXS > 0
return (ISC_R_NOMEMORY);
goto cleanup_manager;
goto cleanup_lock;
goto cleanup_listlock;
#if NMCTXS > 0
for (i = 0; i < NMCTXS; i++)
return (ISC_R_SUCCESS);
return (result);
if (need_destroy)
static isc_result_t
if (!ns_g_clienttest)
return (result);
if (tcp) {
return (ISC_R_SUCCESS);
unsigned int disp;
REQUIRE(n > 0);
return (result);
int match;
if (default_allow)
goto allow;
goto deny;
if (match > 0)
goto allow;
return (ISC_R_SUCCESS);
deny:
return (DNS_R_REFUSED);
return (result);
if (q != NULL) {
classbuf);
0, &buffer);
buf);
const char *name;
const char *sep;
const char *origfor;
sizeof(original));
sizeof(typebuf));
sizeof(classbuf));
return (ISC_R_SUCCESS);