client.c 110 KB
Newer Older
Bob Halley's avatar
add  
Bob Halley committed
1
/*
2
 * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
3
 *
4 5 6
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
7 8 9
 *
 * See the COPYRIGHT file distributed with this work for additional
 * information regarding copyright ownership.
Bob Halley's avatar
add  
Bob Halley committed
10 11 12 13
 */

#include <config.h>

14
#include <inttypes.h>
15
#include <stdbool.h>
16

17
#include <isc/aes.h>
18
#include <isc/formatcheck.h>
19
#include <isc/fuzz.h>
20
#include <isc/hmac.h>
Brian Wellington's avatar
Brian Wellington committed
21
#include <isc/mutex.h>
22
#include <isc/once.h>
23
#include <isc/nonce.h>
24
#include <isc/platform.h>
Andreas Gustafsson's avatar
Andreas Gustafsson committed
25
#include <isc/print.h>
26
#include <isc/queue.h>
27
#include <isc/random.h>
28
#include <isc/safe.h>
29
#include <isc/serial.h>
30
#include <isc/stats.h>
31
#include <isc/stdio.h>
32
#include <isc/string.h>
Andreas Gustafsson's avatar
Andreas Gustafsson committed
33
#include <isc/task.h>
Bob Halley's avatar
add  
Bob Halley committed
34
#include <isc/timer.h>
Michael Graff's avatar
Michael Graff committed
35
#include <isc/util.h>
Bob Halley's avatar
add  
Bob Halley committed
36

37
#include <dns/adb.h>
Evan Hunt's avatar
Evan Hunt committed
38
#include <dns/badcache.h>
39
#include <dns/db.h>
Bob Halley's avatar
add  
Bob Halley committed
40
#include <dns/dispatch.h>
Evan Hunt's avatar
Evan Hunt committed
41
#include <dns/dnstap.h>
42
#include <dns/cache.h>
43
#include <dns/edns.h>
Bob Halley's avatar
add  
Bob Halley committed
44 45
#include <dns/events.h>
#include <dns/message.h>
46
#include <dns/peer.h>
47
#include <dns/rcode.h>
Bob Halley's avatar
EDNS0  
Bob Halley committed
48
#include <dns/rdata.h>
49
#include <dns/rdataclass.h>
Bob Halley's avatar
EDNS0  
Bob Halley committed
50 51
#include <dns/rdatalist.h>
#include <dns/rdataset.h>
52
#include <dns/resolver.h>
53
#include <dns/stats.h>
54
#include <dns/tsig.h>
55
#include <dns/view.h>
56
#include <dns/zone.h>
Bob Halley's avatar
add  
Bob Halley committed
57

58 59 60 61 62 63
#include <ns/interfacemgr.h>
#include <ns/log.h>
#include <ns/notify.h>
#include <ns/server.h>
#include <ns/stats.h>
#include <ns/update.h>
64 65 66 67 68

/***
 *** Client
 ***/

69 70 71
/*! \file
 * Client Routines
 *
72 73 74 75 76 77 78 79 80
 * 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.
 */
Bob Halley's avatar
add  
Bob Halley committed
81 82 83

#define NS_CLIENT_TRACE
#ifdef NS_CLIENT_TRACE
84
#define CTRACE(m)	ns_client_log(client, \
85 86
				      NS_LOGCATEGORY_CLIENT, \
				      NS_LOGMODULE_CLIENT, \
Bob Halley's avatar
Bob Halley committed
87
				      ISC_LOG_DEBUG(3), \
88
				      "%s", (m))
89 90
#define MTRACE(m)	isc_log_write(ns_lctx, \
				      NS_LOGCATEGORY_CLIENT, \
91
				      NS_LOGMODULE_CLIENT, \
Bob Halley's avatar
Bob Halley committed
92
				      ISC_LOG_DEBUG(3), \
93
				      "clientmgr @%p: %s", manager, (m))
94 95 96
#else
#define CTRACE(m)	((void)(m))
#define MTRACE(m)	((void)(m))
Bob Halley's avatar
add  
Bob Halley committed
97 98
#endif

Bob Halley's avatar
Bob Halley committed
99 100
#define TCP_CLIENT(c)	(((c)->attributes & NS_CLIENTATTR_TCP) != 0)

101
#define TCP_BUFFER_SIZE			(65535 + 2)
102 103
#define SEND_BUFFER_SIZE		4096
#define RECV_BUFFER_SIZE		4096
Bob Halley's avatar
add  
Bob Halley committed
104

105 106 107 108 109 110 111 112 113 114
#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.
 */

115
#define COOKIE_SIZE 24U /* 8 + 4 + 4 + 8 */
Evan Hunt's avatar
Evan Hunt committed
116
#define ECS_SIZE 20U /* 2 + 1 + 1 + [0..16] */
117

118 119
#define WANTNSID(x) (((x)->attributes & NS_CLIENTATTR_WANTNSID) != 0)
#define WANTEXPIRE(x) (((x)->attributes & NS_CLIENTATTR_WANTEXPIRE) != 0)
120 121
#define WANTPAD(x) (((x)->attributes & NS_CLIENTATTR_WANTPAD) != 0)
#define USEKEEPALIVE(x) (((x)->attributes & NS_CLIENTATTR_USEKEEPALIVE) != 0)
122

123
/*% nameserver client manager structure */
Bob Halley's avatar
add  
Bob Halley committed
124 125 126
struct ns_clientmgr {
	/* Unlocked. */
	unsigned int			magic;
127 128 129 130

	/* The queue object has its own locks */
	client_queue_t			inactive;     /*%< To be recycled */

Bob Halley's avatar
add  
Bob Halley committed
131
	isc_mem_t *			mctx;
132
	ns_server_t *			sctx;
Bob Halley's avatar
add  
Bob Halley committed
133 134
	isc_taskmgr_t *			taskmgr;
	isc_timermgr_t *		timermgr;
135
	isc_task_t *			excl;
136 137

	/* Lock covers manager state. */
Bob Halley's avatar
add  
Bob Halley committed
138
	isc_mutex_t			lock;
139
	bool			exiting;
140 141 142 143 144 145 146 147 148

	/* Lock covers the clients list */
	isc_mutex_t			listlock;
	client_list_t			clients;      /*%< All active clients */

	/* Lock covers the recursing list */
	isc_mutex_t			reclock;
	client_list_t			recursing;    /*%< Recursing clients */

149 150 151 152 153
#if NMCTXS > 0
	/*%< mctx pool for clients. */
	unsigned int			nextmctx;
	isc_mem_t *			mctxpool[NMCTXS];
#endif
Bob Halley's avatar
add  
Bob Halley committed
154 155
};

156 157
#define MANAGER_MAGIC			ISC_MAGIC('N', 'S', 'C', 'm')
#define VALID_MANAGER(m)		ISC_MAGIC_VALID(m, MANAGER_MAGIC)
Bob Halley's avatar
add  
Bob Halley committed
158

Automatic Updater's avatar
Automatic Updater committed
159
/*!
160 161 162 163 164 165 166 167 168 169
 * 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.
 */
Bob Halley's avatar
add  
Bob Halley committed
170

171
#define NS_CLIENTSTATE_FREED    0
172
/*%<
173 174
 * The client object no longer exists.
 */
Bob Halley's avatar
add  
Bob Halley committed
175

176
#define NS_CLIENTSTATE_INACTIVE 1
177
/*%<
178
 * The client object exists and has a task and timer.
179 180 181 182
 * 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.
 */
Bob Halley's avatar
add  
Bob Halley committed
183

184
#define NS_CLIENTSTATE_READY    2
185
/*%<
186 187 188
 * 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.
Bob Halley's avatar
add  
Bob Halley committed
189
 *
190
 * If it is a TCP client object, it has a TCP listener socket
191
 * and an outstanding TCP listen request.
Bob Halley's avatar
add  
Bob Halley committed
192
 *
193 194
 * If it is a UDP client object, it has a UDP listener socket
 * and an outstanding UDP receive request.
Bob Halley's avatar
add  
Bob Halley committed
195 196
 */

197
#define NS_CLIENTSTATE_READING  3
198
/*%<
199
 * The client object is a TCP client object that has received
200
 * a connection.  It has a tcpsocket, tcpmsg, TCP quota, and an
201 202 203 204 205
 * outstanding TCP read request.  This state is not used for
 * UDP client objects.
 */

#define NS_CLIENTSTATE_WORKING  4
206
/*%<
207
 * The client object has received a request and is working
Andreas Gustafsson's avatar
spacing  
Andreas Gustafsson committed
208
 * on it.  It has a view, and it may have any of a non-reset OPT,
209
 * recursion quota, and an outstanding write request.
210
 */
211

212 213 214 215 216 217
#define NS_CLIENTSTATE_RECURSING  5
/*%<
 * The client object is recursing.  It will be on the 'recursing'
 * list.
 */

218
#define NS_CLIENTSTATE_MAX      9
219
/*%<
220 221 222 223 224
 * 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.
 */

225 226 227 228 229 230 231
/*
 * Enable ns_client_dropport() by default.
 */
#ifndef NS_CLIENT_DROPPORT
#define NS_CLIENT_DROPPORT 1
#endif

232
LIBNS_EXTERNAL_DATA unsigned int ns_client_requests;
233

234 235
static void read_settimeout(ns_client_t *client, bool newconn);
static void client_read(ns_client_t *client, bool newconn);
236
static void client_accept(ns_client_t *client);
237
static void client_udprecv(ns_client_t *client);
238
static void clientmgr_destroy(ns_clientmgr_t *manager);
239
static bool exit_check(ns_client_t *client);
240
static void ns_client_endrequest(ns_client_t *client);
241
static void client_start(isc_task_t *task, isc_event_t *event);
242
static void ns_client_dumpmessage(ns_client_t *client, const char *reason);
243
static isc_result_t get_client(ns_clientmgr_t *manager, ns_interface_t *ifp,
244
			       dns_dispatch_t *disp, bool tcp);
245
static isc_result_t get_worker(ns_clientmgr_t *manager, ns_interface_t *ifp,
246
			       isc_socket_t *sock);
247 248
static void compute_cookie(ns_client_t *client, uint32_t when,
			   uint32_t nonce, const unsigned char *secret,
249
			   isc_buffer_t *buf);
250

251
void
252
ns_client_recursing(ns_client_t *client) {
253
	REQUIRE(NS_CLIENT_VALID(client));
254
	REQUIRE(client->state == NS_CLIENTSTATE_WORKING);
255

256
	LOCK(&client->manager->reclock);
257
	client->newstate = client->state = NS_CLIENTSTATE_RECURSING;
258
	ISC_LIST_APPEND(client->manager->recursing, client, rlink);
259
	UNLOCK(&client->manager->reclock);
260 261
}

262 263 264 265 266
void
ns_client_killoldestquery(ns_client_t *client) {
	ns_client_t *oldest;
	REQUIRE(NS_CLIENT_VALID(client));

267
	LOCK(&client->manager->reclock);
268 269
	oldest = ISC_LIST_HEAD(client->manager->recursing);
	if (oldest != NULL) {
270 271
		ISC_LIST_UNLINK(client->manager->recursing, oldest, rlink);
		UNLOCK(&client->manager->reclock);
272
		ns_query_cancel(oldest);
273 274
	} else
		UNLOCK(&client->manager->reclock);
275 276
}

277 278
void
ns_client_settimeout(ns_client_t *client, unsigned int seconds) {
279 280
	isc_result_t result;
	isc_interval_t interval;
281

282 283
	isc_interval_set(&interval, seconds, 0);
	result = isc_timer_reset(client->timer, isc_timertype_once, NULL,
284 285
				 &interval, false);
	client->timerset = true;
286
	if (result != ISC_R_SUCCESS) {
287
		ns_client_log(client, NS_LOGCATEGORY_CLIENT,
288
			      NS_LOGMODULE_CLIENT, ISC_LOG_ERROR,
289
			      "setting timeout: %s",
290 291 292 293 294
			      isc_result_totext(result));
		/* Continue anyway. */
	}
}

295
static void
296
read_settimeout(ns_client_t *client, bool newconn) {
297 298 299 300 301
	isc_result_t result;
	isc_interval_t interval;
	unsigned int ds;

	if (newconn)
302
		ds = client->sctx->initialtimo;
303
	else if (USEKEEPALIVE(client))
304
		ds = client->sctx->keepalivetimo;
305
	else
306
		ds = client->sctx->idletimo;
307 308 309

	isc_interval_set(&interval, ds / 10, 100000000 * (ds % 10));
	result = isc_timer_reset(client->timer, isc_timertype_once, NULL,
310 311
				 &interval, false);
	client->timerset = true;
312 313 314 315 316 317 318 319 320
	if (result != ISC_R_SUCCESS) {
		ns_client_log(client, NS_LOGCATEGORY_CLIENT,
			      NS_LOGMODULE_CLIENT, ISC_LOG_ERROR,
			      "setting timeout: %s",
			      isc_result_totext(result));
		/* Continue anyway. */
	}
}

321
/*%
322
 * Check for a deactivation or shutdown request and take appropriate
323
 * action.  Returns true if either is in progress; in this case
324 325 326
 * the caller must no longer use the client object as it may have been
 * freed.
 */
327
static bool
328
exit_check(ns_client_t *client) {
329
	bool destroy_manager = false;
330
	ns_clientmgr_t *manager = NULL;
331

332
	REQUIRE(NS_CLIENT_VALID(client));
333
	manager = client->manager;
334 335

	if (client->state <= client->newstate)
336
		return (false); /* Business as usual. */
337

338
	INSIST(client->newstate < NS_CLIENTSTATE_RECURSING);
339

340 341 342 343 344 345
	/*
	 * 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
346 347
	 *  - The client does not detach from the view until references is zero
	 *  - references does not go to zero until the resolver has shut down
348
	 *
349
	 * Keep the view attached until any outstanding updates complete.
350
	 */
Automatic Updater's avatar
Automatic Updater committed
351
	if (client->nupdates == 0 &&
352
	    client->newstate == NS_CLIENTSTATE_FREED && client->view != NULL)
353
		dns_view_detach(&client->view);
354

355 356 357
	if (client->state == NS_CLIENTSTATE_WORKING ||
	    client->state == NS_CLIENTSTATE_RECURSING)
	{
358
		INSIST(client->newstate <= NS_CLIENTSTATE_READING);
359 360 361 362
		/*
		 * Let the update processing complete.
		 */
		if (client->nupdates > 0)
363
			return (true);
364

365 366 367 368
		/*
		 * We are trying to abort request processing.
		 */
		if (client->nsends > 0) {
369
			isc_socket_t *sock;
370
			if (TCP_CLIENT(client))
371
				sock = client->tcpsocket;
372
			else
373 374
				sock = client->udpsocket;
			isc_socket_cancel(sock, client->task,
375 376
					  ISC_SOCKCANCEL_SEND);
		}
377

378 379 380
		if (! (client->nsends == 0 && client->nrecvs == 0 &&
		       client->references == 0))
		{
381 382 383 384
			/*
			 * Still waiting for I/O cancel completion.
			 * or lingering references.
			 */
385
			return (true);
386
		}
387

388 389
		/*
		 * I/O cancel is complete.  Burn down all state
390
		 * related to the current request.  Ensure that
391
		 * the client is no longer on the recursing list.
392 393 394 395
		 *
		 * We need to check whether the client is still linked,
		 * because it may already have been removed from the
		 * recursing list by ns_client_killoldestquery()
396
		 */
397 398
		if (client->state == NS_CLIENTSTATE_RECURSING) {
			LOCK(&manager->reclock);
399 400 401
			if (ISC_LINK_LINKED(client, rlink))
				ISC_LIST_UNLINK(manager->recursing,
						client, rlink);
402
			UNLOCK(&manager->reclock);
403
		}
404 405 406
		ns_client_endrequest(client);

		client->state = NS_CLIENTSTATE_READING;
407
		INSIST(client->recursionquota == NULL);
408

409
		if (NS_CLIENTSTATE_READING == client->newstate) {
410
			if (!client->pipelined) {
411
				client_read(client, false);
412
				client->newstate = NS_CLIENTSTATE_MAX;
413
				return (true); /* We're done. */
414 415
			} else if (client->mortal) {
				client->newstate = NS_CLIENTSTATE_INACTIVE;
416
			} else
417
				return (false);
418 419 420 421 422 423 424 425
		}
	}

	if (client->state == NS_CLIENTSTATE_READING) {
		/*
		 * We are trying to abort the current TCP connection,
		 * if any.
		 */
426
		INSIST(client->recursionquota == NULL);
427 428 429
		INSIST(client->newstate <= NS_CLIENTSTATE_READY);
		if (client->nreads > 0)
			dns_tcpmsg_cancelread(&client->tcpmsg);
430
		if (client->nreads != 0) {
431
			/* Still waiting for read cancel completion. */
432
			return (true);
433 434 435 436
		}

		if (client->tcpmsg_valid) {
			dns_tcpmsg_invalidate(&client->tcpmsg);
437
			client->tcpmsg_valid = false;
438
		}
439 440
		if (client->tcpsocket != NULL) {
			CTRACE("closetcp");
441
			isc_socket_detach(&client->tcpsocket);
442
		}
443 444 445

		if (client->tcpquota != NULL)
			isc_quota_detach(&client->tcpquota);
446

447
		if (client->timerset) {
Andreas Gustafsson's avatar
spacing  
Andreas Gustafsson committed
448 449
			(void)isc_timer_reset(client->timer,
					      isc_timertype_inactive,
450 451
					      NULL, NULL, true);
			client->timerset = false;
452
		}
453

454
		client->pipelined = false;
455

456
		client->peeraddr_valid = false;
457

458
		client->state = NS_CLIENTSTATE_READY;
459
		INSIST(client->recursionquota == NULL);
460 461 462 463 464 465

		/*
		 * 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.
466 467 468 469
		 *
		 * UDP clients go inactive at this point, but TCP clients
		 * may remain active if we have fewer active TCP client
		 * objects than desired due to an earlier quota exhaustion.
470
		 */
471 472 473
		if (client->mortal && TCP_CLIENT(client) &&
		    ((client->sctx->options & NS_SERVER_CLIENTTEST) == 0))
		{
474 475 476
			LOCK(&client->interface->lock);
			if (client->interface->ntcpcurrent <
				    client->interface->ntcptarget)
477
				client->mortal = false;
478 479 480 481 482 483 484 485 486 487 488
			UNLOCK(&client->interface->lock);
		}

		/*
		 * We don't need the client; send it to the inactive
		 * queue for recycling.
		 */
		if (client->mortal) {
			if (client->newstate > NS_CLIENTSTATE_INACTIVE)
				client->newstate = NS_CLIENTSTATE_INACTIVE;
		}
489

490 491 492
		if (NS_CLIENTSTATE_READY == client->newstate) {
			if (TCP_CLIENT(client)) {
				client_accept(client);
493 494
			} else
				client_udprecv(client);
495
			client->newstate = NS_CLIENTSTATE_MAX;
496
			return (true);
497 498 499 500
		}
	}

	if (client->state == NS_CLIENTSTATE_READY) {
501
		INSIST(client->newstate <= NS_CLIENTSTATE_INACTIVE);
502

503 504 505 506 507 508
		/*
		 * We are trying to enter the inactive state.
		 */
		if (client->naccepts > 0)
			isc_socket_cancel(client->tcplistener, client->task,
					  ISC_SOCKCANCEL_ACCEPT);
509

510 511
		/* Still waiting for accept cancel completion. */
		if (! (client->naccepts == 0))
512
			return (true);
513

514
		/* Accept cancel is complete. */
515 516 517
		if (client->nrecvs > 0)
			isc_socket_cancel(client->udpsocket, client->task,
					  ISC_SOCKCANCEL_RECV);
518 519 520

		/* Still waiting for recv cancel completion. */
		if (! (client->nrecvs == 0))
521
			return (true);
522

523 524
		/* Still waiting for control event to be delivered */
		if (client->nctls > 0)
525
			return (true);
526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542

		/* Deactivate the client. */
		if (client->interface)
			ns_interface_detach(&client->interface);

		INSIST(client->naccepts == 0);
		INSIST(client->recursionquota == NULL);
		if (client->tcplistener != NULL)
			isc_socket_detach(&client->tcplistener);

		if (client->udpsocket != NULL)
			isc_socket_detach(&client->udpsocket);

		if (client->dispatch != NULL)
			dns_dispatch_detach(&client->dispatch);

		client->attributes = 0;
543
		client->mortal = false;
544
		client->sendcb = NULL;
545

546 547 548 549 550 551
		if (client->keytag != NULL) {
			isc_mem_put(client->mctx, client->keytag,
				    client->keytag_len);
			client->keytag_len = 0;
		}

552 553 554 555 556 557 558
		/*
		 * Put the client on the inactive list.  If we are aiming for
		 * the "freed" state, it will be removed from the inactive
		 * list shortly, and we need to keep the manager locked until
		 * that has been done, lest the manager decide to reactivate
		 * the dying client inbetween.
		 */
559
		client->state = NS_CLIENTSTATE_INACTIVE;
560
		INSIST(client->recursionquota == NULL);
561

562 563
		if (client->state == client->newstate) {
			client->newstate = NS_CLIENTSTATE_MAX;
564 565 566 567
			if ((client->sctx->options &
			     NS_SERVER_CLIENTTEST) == 0 &&
			    manager != NULL && !manager->exiting)
			{
568 569
				ISC_QUEUE_PUSH(manager->inactive, client,
					       ilink);
570
			}
571 572
			if (client->needshutdown)
				isc_task_shutdown(client->task);
573
			return (true);
574 575 576 577 578 579 580
		}
	}

	if (client->state == NS_CLIENTSTATE_INACTIVE) {
		INSIST(client->newstate == NS_CLIENTSTATE_FREED);
		/*
		 * We are trying to free the client.
581 582 583 584 585
		 *
		 * When "shuttingdown" is true, either the task has received
		 * its shutdown event or no shutdown event has ever been
		 * set up.  Thus, we have no outstanding shutdown
		 * event at this point.
586
		 */
587 588 589
		REQUIRE(client->state == NS_CLIENTSTATE_INACTIVE);

		INSIST(client->recursionquota == NULL);
590
		INSIST(!ISC_QLINK_LINKED(client, ilink));
591

592 593 594 595 596 597
		if (manager != NULL) {
			LOCK(&manager->listlock);
			ISC_LIST_UNLINK(manager->clients, client, link);
			LOCK(&manager->lock);
			if (manager->exiting &&
			    ISC_LIST_EMPTY(manager->clients))
598
				destroy_manager = true;
599 600 601 602
			UNLOCK(&manager->lock);
			UNLOCK(&manager->listlock);
		}

603 604 605 606 607
		ns_query_free(client);
		isc_mem_put(client->mctx, client->recvbuf, RECV_BUFFER_SIZE);
		isc_event_free((isc_event_t **)&client->sendevent);
		isc_event_free((isc_event_t **)&client->recvevent);
		isc_timer_detach(&client->timer);
608 609
		if (client->delaytimer != NULL)
			isc_timer_detach(&client->delaytimer);
610 611

		if (client->tcpbuf != NULL)
612 613
			isc_mem_put(client->mctx, client->tcpbuf,
				    TCP_BUFFER_SIZE);
614 615 616
		if (client->opt != NULL) {
			INSIST(dns_rdataset_isassociated(client->opt));
			dns_rdataset_disassociate(client->opt);
617 618
			dns_message_puttemprdataset(client->message,
						    &client->opt);
619
		}
620 621 622 623 624
		if (client->keytag != NULL) {
			isc_mem_put(client->mctx, client->keytag,
				    client->keytag_len);
			client->keytag_len = 0;
		}
625

626
		dns_message_destroy(&client->message);
627

628 629 630 631 632 633 634 635 636 637
		/*
		 * Detaching the task must be done after unlinking from
		 * the manager's lists because the manager accesses
		 * client->task.
		 */
		if (client->task != NULL)
			isc_task_detach(&client->task);

		CTRACE("free");
		client->magic = 0;
638

639 640 641 642
		/*
		 * Check that there are no other external references to
		 * the memory context.
		 */
643 644 645
		if ((client->sctx->options & NS_SERVER_CLIENTTEST) != 0 &&
		    isc_mem_references(client->mctx) != 1)
		{
646 647
			isc_mem_stats(client->mctx, stderr);
			INSIST(0);
648
			ISC_UNREACHABLE();
649
		}
650 651 652 653 654

		/*
		 * Destroy the fetchlock mutex that was created in
		 * ns_query_init().
		 */
655
		isc_mutex_destroy(&client->query.fetchlock);
656

657 658 659
		if (client->sctx != NULL)
			ns_server_detach(&client->sctx);

660
		isc_mem_putanddetach(&client->mctx, client, sizeof(*client));
661 662
	}

663 664
	if (destroy_manager && manager != NULL)
		clientmgr_destroy(manager);
665

666
	return (true);
667 668
}

669
/*%
670 671 672 673 674 675 676 677
 * The client's task has received the client's control event
 * as part of the startup process.
 */
static void
client_start(isc_task_t *task, isc_event_t *event) {
	ns_client_t *client = (ns_client_t *) event->ev_arg;

	INSIST(task == client->task);
678

679 680
	UNUSED(task);

681 682 683 684 685 686
	INSIST(client->nctls == 1);
	client->nctls--;

	if (exit_check(client))
		return;

687
	if (TCP_CLIENT(client)) {
688
		if (client->pipelined) {
689
			client_read(client, false);
690 691 692
		} else {
			client_accept(client);
		}
693
	} else {
694
		client_udprecv(client);
695 696 697 698
	}
}


699
/*%
700 701
 * The client's task has received a shutdown event.
 */
Bob Halley's avatar
add  
Bob Halley committed
702 703 704 705 706
static void
client_shutdown(isc_task_t *task, isc_event_t *event) {
	ns_client_t *client;

	REQUIRE(event != NULL);
707 708
	REQUIRE(event->ev_type == ISC_TASKEVENT_SHUTDOWN);
	client = event->ev_arg;
Bob Halley's avatar
add  
Bob Halley committed
709 710 711
	REQUIRE(NS_CLIENT_VALID(client));
	REQUIRE(task == client->task);

Andreas Gustafsson's avatar
style  
Andreas Gustafsson committed
712 713
	UNUSED(task);

Bob Halley's avatar
add  
Bob Halley committed
714 715 716 717
	CTRACE("shutdown");

	isc_event_free(&event);

718 719 720 721 722 723
	if (client->shutdown != NULL) {
		(client->shutdown)(client->shutdown_arg, ISC_R_SHUTTINGDOWN);
		client->shutdown = NULL;
		client->shutdown_arg = NULL;
	}

724 725 726
	if (ISC_QLINK_LINKED(client, ilink))
		ISC_QUEUE_UNLINK(client->manager->inactive, client, ilink);

727
	client->newstate = NS_CLIENTSTATE_FREED;
728
	client->needshutdown = false;
729
	(void)exit_check(client);
730
}
Bob Halley's avatar
add  
Bob Halley committed
731

732 733
static void
ns_client_endrequest(ns_client_t *client) {
734 735 736
	INSIST(client->naccepts == 0);
	INSIST(client->nreads == 0);
	INSIST(client->nsends == 0);
737
	INSIST(client->nrecvs == 0);
738
	INSIST(client->nupdates == 0);
739 740
	INSIST(client->state == NS_CLIENTSTATE_WORKING ||
	       client->state == NS_CLIENTSTATE_RECURSING);
Bob Halley's avatar
add  
Bob Halley committed
741

Andreas Gustafsson's avatar
style  
Andreas Gustafsson committed
742 743
	CTRACE("endrequest");

744
	if (client->next != NULL) {
745
		(client->next)(client);
746 747 748
		client->next = NULL;
	}

749 750
	if (client->view != NULL) {
#ifdef ENABLE_AFL
751
		if (client->sctx->fuzztype == isc_fuzz_resolver) {
752 753 754 755
			dns_cache_clean(client->view->cache, INT_MAX);
			dns_adb_flush(client->view->adb);
		}
#endif
756
		dns_view_detach(&client->view);
757
	}
Bob Halley's avatar
Bob Halley committed
758 759 760 761 762
	if (client->opt != NULL) {
		INSIST(dns_rdataset_isassociated(client->opt));
		dns_rdataset_disassociate(client->opt);
		dns_message_puttemprdataset(client->message, &client->opt);
	}
763

764
	client->signer = NULL;
765
	client->udpsize = 512;
766
	client->extflags = 0;
767
	client->ednsversion = -1;
Bob Halley's avatar
add  
Bob Halley committed
768
	dns_message_reset(client->message, DNS_MESSAGE_INTENTPARSE);
769

770
	if (client->recursionquota != NULL) {
771
		isc_quota_detach(&client->recursionquota);
772 773
		ns_stats_decrement(client->sctx->nsstats,
				   ns_statscounter_recursclients);
774
	}
775 776

	/*
777
	 * Clear all client attributes that are specific to
778 779 780
	 * the request; that's all except the TCP flag.
	 */
	client->attributes &= NS_CLIENTATTR_TCP;
781
#ifdef ENABLE_AFL
782 783 784 785 786 787
	if (client->sctx->fuzznotify != NULL &&
	    (client->sctx->fuzztype == isc_fuzz_client ||
	     client->sctx->fuzztype == isc_fuzz_tcpclient ||
	     client->sctx->fuzztype == isc_fuzz_resolver))
	{
		client->sctx->fuzznotify();
788 789 790
	}
#endif /* ENABLE_AFL */

791
}
792

793 794 795
void
ns_client_next(ns_client_t *client, isc_result_t result) {
	int newstate;
796

797
	REQUIRE(NS_CLIENT_VALID(client));
798
	REQUIRE(client->state == NS_CLIENTSTATE_WORKING ||
799
		client->state == NS_CLIENTSTATE_RECURSING ||
800
		client->state == NS_CLIENTSTATE_READING);
Andreas Gustafsson's avatar
style  
Andreas Gustafsson committed
801

802
	CTRACE("next");
803

804
	if (result != ISC_R_SUCCESS)
805
		ns_client_log(client, DNS_LOGCATEGORY_SECURITY,