client.c revision 193149
1/*
2 * Copyright (C) 2004-2009  Internet Systems Consortium, Inc. ("ISC")
3 * Copyright (C) 1999-2003  Internet Software Consortium.
4 *
5 * Permission to use, copy, modify, and/or distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
8 *
9 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
10 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
11 * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
12 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
13 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
14 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
15 * PERFORMANCE OF THIS SOFTWARE.
16 */
17
18/* $Id: client.c,v 1.259.12.3 2009/01/29 22:40:33 jinmei Exp $ */
19
20#include <config.h>
21
22#include <isc/formatcheck.h>
23#include <isc/mutex.h>
24#include <isc/once.h>
25#include <isc/platform.h>
26#include <isc/print.h>
27#include <isc/stats.h>
28#include <isc/stdio.h>
29#include <isc/string.h>
30#include <isc/task.h>
31#include <isc/timer.h>
32#include <isc/util.h>
33
34#include <dns/db.h>
35#include <dns/dispatch.h>
36#include <dns/events.h>
37#include <dns/message.h>
38#include <dns/peer.h>
39#include <dns/rcode.h>
40#include <dns/rdata.h>
41#include <dns/rdataclass.h>
42#include <dns/rdatalist.h>
43#include <dns/rdataset.h>
44#include <dns/resolver.h>
45#include <dns/stats.h>
46#include <dns/tsig.h>
47#include <dns/view.h>
48#include <dns/zone.h>
49
50#include <named/interfacemgr.h>
51#include <named/log.h>
52#include <named/notify.h>
53#include <named/os.h>
54#include <named/server.h>
55#include <named/update.h>
56
57/***
58 *** Client
59 ***/
60
61/*! \file
62 * Client Routines
63 *
64 * Important note!
65 *
66 * All client state changes, other than that from idle to listening, occur
67 * as a result of events.  This guarantees serialization and avoids the
68 * need for locking.
69 *
70 * If a routine is ever created that allows someone other than the client's
71 * task to change the client, then the client will have to be locked.
72 */
73
74#define NS_CLIENT_TRACE
75#ifdef NS_CLIENT_TRACE
76#define CTRACE(m)	ns_client_log(client, \
77				      NS_LOGCATEGORY_CLIENT, \
78				      NS_LOGMODULE_CLIENT, \
79				      ISC_LOG_DEBUG(3), \
80				      "%s", (m))
81#define MTRACE(m)	isc_log_write(ns_g_lctx, \
82				      NS_LOGCATEGORY_GENERAL, \
83				      NS_LOGMODULE_CLIENT, \
84				      ISC_LOG_DEBUG(3), \
85				      "clientmgr @%p: %s", manager, (m))
86#else
87#define CTRACE(m)	((void)(m))
88#define MTRACE(m)	((void)(m))
89#endif
90
91#define TCP_CLIENT(c)	(((c)->attributes & NS_CLIENTATTR_TCP) != 0)
92
93#define TCP_BUFFER_SIZE			(65535 + 2)
94#define SEND_BUFFER_SIZE		4096
95#define RECV_BUFFER_SIZE		4096
96
97#ifdef ISC_PLATFORM_USETHREADS
98#define NMCTXS				100
99/*%<
100 * Number of 'mctx pools' for clients. (Should this be configurable?)
101 * When enabling threads, we use a pool of memory contexts shared by
102 * client objects, since concurrent access to a shared context would cause
103 * heavy contentions.  The above constant is expected to be enough for
104 * completely avoiding contentions among threads for an authoritative-only
105 * server.
106 */
107#else
108#define NMCTXS				0
109/*%<
110 * If named with built without thread, simply share manager's context.  Using
111 * a separate context in this case would simply waste memory.
112 */
113#endif
114
115/*% nameserver client manager structure */
116struct ns_clientmgr {
117	/* Unlocked. */
118	unsigned int			magic;
119	isc_mem_t *			mctx;
120	isc_taskmgr_t *			taskmgr;
121	isc_timermgr_t *		timermgr;
122	isc_mutex_t			lock;
123	/* Locked by lock. */
124	isc_boolean_t			exiting;
125	client_list_t			active;		/*%< Active clients */
126	client_list_t			recursing;	/*%< Recursing clients */
127	client_list_t			inactive;	/*%< To be recycled */
128#if NMCTXS > 0
129	/*%< mctx pool for clients. */
130	unsigned int			nextmctx;
131	isc_mem_t *			mctxpool[NMCTXS];
132#endif
133};
134
135#define MANAGER_MAGIC			ISC_MAGIC('N', 'S', 'C', 'm')
136#define VALID_MANAGER(m)		ISC_MAGIC_VALID(m, MANAGER_MAGIC)
137
138/*!
139 * Client object states.  Ordering is significant: higher-numbered
140 * states are generally "more active", meaning that the client can
141 * have more dynamically allocated data, outstanding events, etc.
142 * In the list below, any such properties listed for state N
143 * also apply to any state > N.
144 *
145 * To force the client into a less active state, set client->newstate
146 * to that state and call exit_check().  This will cause any
147 * activities defined for higher-numbered states to be aborted.
148 */
149
150#define NS_CLIENTSTATE_FREED    0
151/*%<
152 * The client object no longer exists.
153 */
154
155#define NS_CLIENTSTATE_INACTIVE 1
156/*%<
157 * The client object exists and has a task and timer.
158 * Its "query" struct and sendbuf are initialized.
159 * It is on the client manager's list of inactive clients.
160 * It has a message and OPT, both in the reset state.
161 */
162
163#define NS_CLIENTSTATE_READY    2
164/*%<
165 * The client object is either a TCP or a UDP one, and
166 * it is associated with a network interface.  It is on the
167 * client manager's list of active clients.
168 *
169 * If it is a TCP client object, it has a TCP listener socket
170 * and an outstanding TCP listen request.
171 *
172 * If it is a UDP client object, it has a UDP listener socket
173 * and an outstanding UDP receive request.
174 */
175
176#define NS_CLIENTSTATE_READING  3
177/*%<
178 * The client object is a TCP client object that has received
179 * a connection.  It has a tcpsocket, tcpmsg, TCP quota, and an
180 * outstanding TCP read request.  This state is not used for
181 * UDP client objects.
182 */
183
184#define NS_CLIENTSTATE_WORKING  4
185/*%<
186 * The client object has received a request and is working
187 * on it.  It has a view, and it may have any of a non-reset OPT,
188 * recursion quota, and an outstanding write request.
189 */
190
191#define NS_CLIENTSTATE_MAX      9
192/*%<
193 * Sentinel value used to indicate "no state".  When client->newstate
194 * has this value, we are not attempting to exit the current state.
195 * Must be greater than any valid state.
196 */
197
198/*
199 * Enable ns_client_dropport() by default.
200 */
201#ifndef NS_CLIENT_DROPPORT
202#define NS_CLIENT_DROPPORT 1
203#endif
204
205unsigned int ns_client_requests;
206
207static void client_read(ns_client_t *client);
208static void client_accept(ns_client_t *client);
209static void client_udprecv(ns_client_t *client);
210static void clientmgr_destroy(ns_clientmgr_t *manager);
211static isc_boolean_t exit_check(ns_client_t *client);
212static void ns_client_endrequest(ns_client_t *client);
213static void ns_client_checkactive(ns_client_t *client);
214static void client_start(isc_task_t *task, isc_event_t *event);
215static void client_request(isc_task_t *task, isc_event_t *event);
216static void ns_client_dumpmessage(ns_client_t *client, const char *reason);
217
218void
219ns_client_recursing(ns_client_t *client) {
220	REQUIRE(NS_CLIENT_VALID(client));
221
222	LOCK(&client->manager->lock);
223	ISC_LIST_UNLINK(*client->list, client, link);
224	ISC_LIST_APPEND(client->manager->recursing, client, link);
225	client->list = &client->manager->recursing;
226	UNLOCK(&client->manager->lock);
227}
228
229void
230ns_client_killoldestquery(ns_client_t *client) {
231	ns_client_t *oldest;
232	REQUIRE(NS_CLIENT_VALID(client));
233
234	LOCK(&client->manager->lock);
235	oldest = ISC_LIST_HEAD(client->manager->recursing);
236	if (oldest != NULL) {
237		ns_query_cancel(oldest);
238		ISC_LIST_UNLINK(*oldest->list, oldest, link);
239		ISC_LIST_APPEND(client->manager->active, oldest, link);
240		oldest->list = &client->manager->active;
241	}
242	UNLOCK(&client->manager->lock);
243}
244
245void
246ns_client_settimeout(ns_client_t *client, unsigned int seconds) {
247	isc_result_t result;
248	isc_interval_t interval;
249
250	isc_interval_set(&interval, seconds, 0);
251	result = isc_timer_reset(client->timer, isc_timertype_once, NULL,
252				 &interval, ISC_FALSE);
253	client->timerset = ISC_TRUE;
254	if (result != ISC_R_SUCCESS) {
255		ns_client_log(client, NS_LOGCATEGORY_CLIENT,
256			      NS_LOGMODULE_CLIENT, ISC_LOG_ERROR,
257			      "setting timeout: %s",
258			      isc_result_totext(result));
259		/* Continue anyway. */
260	}
261}
262
263/*%
264 * Check for a deactivation or shutdown request and take appropriate
265 * action.  Returns ISC_TRUE if either is in progress; in this case
266 * the caller must no longer use the client object as it may have been
267 * freed.
268 */
269static isc_boolean_t
270exit_check(ns_client_t *client) {
271	ns_clientmgr_t *locked_manager = NULL;
272	ns_clientmgr_t *destroy_manager = NULL;
273
274	REQUIRE(NS_CLIENT_VALID(client));
275
276	if (client->state <= client->newstate)
277		return (ISC_FALSE); /* Business as usual. */
278
279	INSIST(client->newstate < NS_CLIENTSTATE_WORKING);
280
281	/*
282	 * We need to detach from the view early when shutting down
283	 * the server to break the following vicious circle:
284	 *
285	 *  - The resolver will not shut down until the view refcount is zero
286	 *  - The view refcount does not go to zero until all clients detach
287	 *  - The client does not detach from the view until references is zero
288	 *  - references does not go to zero until the resolver has shut down
289	 *
290	 * Keep the view attached until any outstanding updates complete.
291	 */
292	if (client->nupdates == 0 &&
293	    client->newstate == NS_CLIENTSTATE_FREED && client->view != NULL)
294		dns_view_detach(&client->view);
295
296	if (client->state == NS_CLIENTSTATE_WORKING) {
297		INSIST(client->newstate <= NS_CLIENTSTATE_READING);
298		/*
299		 * Let the update processing complete.
300		 */
301		if (client->nupdates > 0)
302			return (ISC_TRUE);
303		/*
304		 * We are trying to abort request processing.
305		 */
306		if (client->nsends > 0) {
307			isc_socket_t *socket;
308			if (TCP_CLIENT(client))
309				socket = client->tcpsocket;
310			else
311				socket = client->udpsocket;
312			isc_socket_cancel(socket, client->task,
313					  ISC_SOCKCANCEL_SEND);
314		}
315
316		if (! (client->nsends == 0 && client->nrecvs == 0 &&
317		       client->references == 0))
318		{
319			/*
320			 * Still waiting for I/O cancel completion.
321			 * or lingering references.
322			 */
323			return (ISC_TRUE);
324		}
325		/*
326		 * I/O cancel is complete.  Burn down all state
327		 * related to the current request.  Ensure that
328		 * the client is on the active list and not the
329		 * recursing list.
330		 */
331		LOCK(&client->manager->lock);
332		if (client->list == &client->manager->recursing) {
333			ISC_LIST_UNLINK(*client->list, client, link);
334			ISC_LIST_APPEND(client->manager->active, client, link);
335			client->list = &client->manager->active;
336		}
337		UNLOCK(&client->manager->lock);
338		ns_client_endrequest(client);
339
340		client->state = NS_CLIENTSTATE_READING;
341		INSIST(client->recursionquota == NULL);
342		if (NS_CLIENTSTATE_READING == client->newstate) {
343			client_read(client);
344			client->newstate = NS_CLIENTSTATE_MAX;
345			return (ISC_TRUE); /* We're done. */
346		}
347	}
348
349	if (client->state == NS_CLIENTSTATE_READING) {
350		/*
351		 * We are trying to abort the current TCP connection,
352		 * if any.
353		 */
354		INSIST(client->recursionquota == NULL);
355		INSIST(client->newstate <= NS_CLIENTSTATE_READY);
356		if (client->nreads > 0)
357			dns_tcpmsg_cancelread(&client->tcpmsg);
358		if (! client->nreads == 0) {
359			/* Still waiting for read cancel completion. */
360			return (ISC_TRUE);
361		}
362
363		if (client->tcpmsg_valid) {
364			dns_tcpmsg_invalidate(&client->tcpmsg);
365			client->tcpmsg_valid = ISC_FALSE;
366		}
367		if (client->tcpsocket != NULL) {
368			CTRACE("closetcp");
369			isc_socket_detach(&client->tcpsocket);
370		}
371
372		if (client->tcpquota != NULL)
373			isc_quota_detach(&client->tcpquota);
374
375		if (client->timerset) {
376			(void)isc_timer_reset(client->timer,
377					      isc_timertype_inactive,
378					      NULL, NULL, ISC_TRUE);
379			client->timerset = ISC_FALSE;
380		}
381
382		client->peeraddr_valid = ISC_FALSE;
383
384		client->state = NS_CLIENTSTATE_READY;
385		INSIST(client->recursionquota == NULL);
386
387		/*
388		 * Now the client is ready to accept a new TCP connection
389		 * or UDP request, but we may have enough clients doing
390		 * that already.  Check whether this client needs to remain
391		 * active and force it to go inactive if not.
392		 */
393		ns_client_checkactive(client);
394
395		if (NS_CLIENTSTATE_READY == client->newstate) {
396			if (TCP_CLIENT(client)) {
397				client_accept(client);
398			} else
399				client_udprecv(client);
400			client->newstate = NS_CLIENTSTATE_MAX;
401			return (ISC_TRUE);
402		}
403	}
404
405	if (client->state == NS_CLIENTSTATE_READY) {
406		INSIST(client->newstate <= NS_CLIENTSTATE_INACTIVE);
407		/*
408		 * We are trying to enter the inactive state.
409		 */
410		if (client->naccepts > 0)
411			isc_socket_cancel(client->tcplistener, client->task,
412					  ISC_SOCKCANCEL_ACCEPT);
413
414		if (! (client->naccepts == 0)) {
415			/* Still waiting for accept cancel completion. */
416			return (ISC_TRUE);
417		}
418		/* Accept cancel is complete. */
419
420		if (client->nrecvs > 0)
421			isc_socket_cancel(client->udpsocket, client->task,
422					  ISC_SOCKCANCEL_RECV);
423		if (! (client->nrecvs == 0)) {
424			/* Still waiting for recv cancel completion. */
425			return (ISC_TRUE);
426		}
427		/* Recv cancel is complete. */
428
429		if (client->nctls > 0) {
430			/* Still waiting for control event to be delivered */
431			return (ISC_TRUE);
432		}
433
434		/* Deactivate the client. */
435		if (client->interface)
436			ns_interface_detach(&client->interface);
437
438		INSIST(client->naccepts == 0);
439		INSIST(client->recursionquota == NULL);
440		if (client->tcplistener != NULL)
441			isc_socket_detach(&client->tcplistener);
442
443		if (client->udpsocket != NULL)
444			isc_socket_detach(&client->udpsocket);
445
446		if (client->dispatch != NULL)
447			dns_dispatch_detach(&client->dispatch);
448
449		client->attributes = 0;
450		client->mortal = ISC_FALSE;
451
452		LOCK(&client->manager->lock);
453		/*
454		 * Put the client on the inactive list.  If we are aiming for
455		 * the "freed" state, it will be removed from the inactive
456		 * list shortly, and we need to keep the manager locked until
457		 * that has been done, lest the manager decide to reactivate
458		 * the dying client inbetween.
459		 */
460		locked_manager = client->manager;
461		ISC_LIST_UNLINK(*client->list, client, link);
462		ISC_LIST_APPEND(client->manager->inactive, client, link);
463		client->list = &client->manager->inactive;
464		client->state = NS_CLIENTSTATE_INACTIVE;
465		INSIST(client->recursionquota == NULL);
466
467		if (client->state == client->newstate) {
468			client->newstate = NS_CLIENTSTATE_MAX;
469			if (client->needshutdown)
470				isc_task_shutdown(client->task);
471			goto unlock;
472		}
473	}
474
475	if (client->state == NS_CLIENTSTATE_INACTIVE) {
476		INSIST(client->newstate == NS_CLIENTSTATE_FREED);
477		/*
478		 * We are trying to free the client.
479		 *
480		 * When "shuttingdown" is true, either the task has received
481		 * its shutdown event or no shutdown event has ever been
482		 * set up.  Thus, we have no outstanding shutdown
483		 * event at this point.
484		 */
485		REQUIRE(client->state == NS_CLIENTSTATE_INACTIVE);
486
487		INSIST(client->recursionquota == NULL);
488
489		ns_query_free(client);
490		isc_mem_put(client->mctx, client->recvbuf, RECV_BUFFER_SIZE);
491		isc_event_free((isc_event_t **)&client->sendevent);
492		isc_event_free((isc_event_t **)&client->recvevent);
493		isc_timer_detach(&client->timer);
494
495		if (client->tcpbuf != NULL)
496			isc_mem_put(client->mctx, client->tcpbuf, TCP_BUFFER_SIZE);
497		if (client->opt != NULL) {
498			INSIST(dns_rdataset_isassociated(client->opt));
499			dns_rdataset_disassociate(client->opt);
500			dns_message_puttemprdataset(client->message, &client->opt);
501		}
502		dns_message_destroy(&client->message);
503		if (client->manager != NULL) {
504			ns_clientmgr_t *manager = client->manager;
505			if (locked_manager == NULL) {
506				LOCK(&manager->lock);
507				locked_manager = manager;
508			}
509			ISC_LIST_UNLINK(*client->list, client, link);
510			client->list = NULL;
511			if (manager->exiting &&
512			    ISC_LIST_EMPTY(manager->active) &&
513			    ISC_LIST_EMPTY(manager->inactive) &&
514			    ISC_LIST_EMPTY(manager->recursing))
515				destroy_manager = manager;
516		}
517		/*
518		 * Detaching the task must be done after unlinking from
519		 * the manager's lists because the manager accesses
520		 * client->task.
521		 */
522		if (client->task != NULL)
523			isc_task_detach(&client->task);
524
525		CTRACE("free");
526		client->magic = 0;
527		/*
528		 * Check that there are no other external references to
529		 * the memory context.
530		 */
531		if (ns_g_clienttest && isc_mem_references(client->mctx) != 1) {
532			isc_mem_stats(client->mctx, stderr);
533			INSIST(0);
534		}
535		isc_mem_putanddetach(&client->mctx, client, sizeof(*client));
536
537		goto unlock;
538	}
539
540 unlock:
541	if (locked_manager != NULL) {
542		UNLOCK(&locked_manager->lock);
543		locked_manager = NULL;
544	}
545
546	/*
547	 * Only now is it safe to destroy the client manager (if needed),
548	 * because we have accessed its lock for the last time.
549	 */
550	if (destroy_manager != NULL)
551		clientmgr_destroy(destroy_manager);
552
553	return (ISC_TRUE);
554}
555
556/*%
557 * The client's task has received the client's control event
558 * as part of the startup process.
559 */
560static void
561client_start(isc_task_t *task, isc_event_t *event) {
562	ns_client_t *client = (ns_client_t *) event->ev_arg;
563
564	INSIST(task == client->task);
565
566	UNUSED(task);
567
568	INSIST(client->nctls == 1);
569	client->nctls--;
570
571	if (exit_check(client))
572		return;
573
574	if (TCP_CLIENT(client)) {
575		client_accept(client);
576	} else {
577		client_udprecv(client);
578	}
579}
580
581
582/*%
583 * The client's task has received a shutdown event.
584 */
585static void
586client_shutdown(isc_task_t *task, isc_event_t *event) {
587	ns_client_t *client;
588
589	REQUIRE(event != NULL);
590	REQUIRE(event->ev_type == ISC_TASKEVENT_SHUTDOWN);
591	client = event->ev_arg;
592	REQUIRE(NS_CLIENT_VALID(client));
593	REQUIRE(task == client->task);
594
595	UNUSED(task);
596
597	CTRACE("shutdown");
598
599	isc_event_free(&event);
600
601	if (client->shutdown != NULL) {
602		(client->shutdown)(client->shutdown_arg, ISC_R_SHUTTINGDOWN);
603		client->shutdown = NULL;
604		client->shutdown_arg = NULL;
605	}
606
607	client->newstate = NS_CLIENTSTATE_FREED;
608	client->needshutdown = ISC_FALSE;
609	(void)exit_check(client);
610}
611
612static void
613ns_client_endrequest(ns_client_t *client) {
614	INSIST(client->naccepts == 0);
615	INSIST(client->nreads == 0);
616	INSIST(client->nsends == 0);
617	INSIST(client->nrecvs == 0);
618	INSIST(client->nupdates == 0);
619	INSIST(client->state == NS_CLIENTSTATE_WORKING);
620
621	CTRACE("endrequest");
622
623	if (client->next != NULL) {
624		(client->next)(client);
625		client->next = NULL;
626	}
627
628	if (client->view != NULL)
629		dns_view_detach(&client->view);
630	if (client->opt != NULL) {
631		INSIST(dns_rdataset_isassociated(client->opt));
632		dns_rdataset_disassociate(client->opt);
633		dns_message_puttemprdataset(client->message, &client->opt);
634	}
635
636	client->udpsize = 512;
637	client->extflags = 0;
638	client->ednsversion = -1;
639	dns_message_reset(client->message, DNS_MESSAGE_INTENTPARSE);
640
641	if (client->recursionquota != NULL)
642		isc_quota_detach(&client->recursionquota);
643
644	/*
645	 * Clear all client attributes that are specific to
646	 * the request; that's all except the TCP flag.
647	 */
648	client->attributes &= NS_CLIENTATTR_TCP;
649}
650
651static void
652ns_client_checkactive(ns_client_t *client) {
653	if (client->mortal) {
654		/*
655		 * This client object should normally go inactive
656		 * at this point, but if we have fewer active client
657		 * objects than desired due to earlier quota exhaustion,
658		 * keep it active to make up for the shortage.
659		 */
660		isc_boolean_t need_another_client = ISC_FALSE;
661		if (TCP_CLIENT(client) && !ns_g_clienttest) {
662			LOCK(&client->interface->lock);
663			if (client->interface->ntcpcurrent <
664			    client->interface->ntcptarget)
665				need_another_client = ISC_TRUE;
666			UNLOCK(&client->interface->lock);
667		} else {
668			/*
669			 * The UDP client quota is enforced by making
670			 * requests fail rather than by not listening
671			 * for new ones.  Therefore, there is always a
672			 * full set of UDP clients listening.
673			 */
674		}
675		if (! need_another_client) {
676			/*
677			 * We don't need this client object.  Recycle it.
678			 */
679			if (client->newstate >= NS_CLIENTSTATE_INACTIVE)
680				client->newstate = NS_CLIENTSTATE_INACTIVE;
681		}
682	}
683}
684
685void
686ns_client_next(ns_client_t *client, isc_result_t result) {
687	int newstate;
688
689	REQUIRE(NS_CLIENT_VALID(client));
690	REQUIRE(client->state == NS_CLIENTSTATE_WORKING ||
691		client->state == NS_CLIENTSTATE_READING);
692
693	CTRACE("next");
694
695	if (result != ISC_R_SUCCESS)
696		ns_client_log(client, DNS_LOGCATEGORY_SECURITY,
697			      NS_LOGMODULE_CLIENT, ISC_LOG_DEBUG(3),
698			      "request failed: %s", isc_result_totext(result));
699
700	/*
701	 * An error processing a TCP request may have left
702	 * the connection out of sync.  To be safe, we always
703	 * sever the connection when result != ISC_R_SUCCESS.
704	 */
705	if (result == ISC_R_SUCCESS && TCP_CLIENT(client))
706		newstate = NS_CLIENTSTATE_READING;
707	else
708		newstate = NS_CLIENTSTATE_READY;
709
710	if (client->newstate > newstate)
711		client->newstate = newstate;
712	(void)exit_check(client);
713}
714
715
716static void
717client_senddone(isc_task_t *task, isc_event_t *event) {
718	ns_client_t *client;
719	isc_socketevent_t *sevent = (isc_socketevent_t *) event;
720
721	REQUIRE(sevent != NULL);
722	REQUIRE(sevent->ev_type == ISC_SOCKEVENT_SENDDONE);
723	client = sevent->ev_arg;
724	REQUIRE(NS_CLIENT_VALID(client));
725	REQUIRE(task == client->task);
726	REQUIRE(sevent == client->sendevent);
727
728	UNUSED(task);
729
730	CTRACE("senddone");
731
732	if (sevent->result != ISC_R_SUCCESS)
733		ns_client_log(client, NS_LOGCATEGORY_CLIENT,
734			      NS_LOGMODULE_CLIENT, ISC_LOG_WARNING,
735			      "error sending response: %s",
736			      isc_result_totext(sevent->result));
737
738	INSIST(client->nsends > 0);
739	client->nsends--;
740
741	if (client->tcpbuf != NULL) {
742		INSIST(TCP_CLIENT(client));
743		isc_mem_put(client->mctx, client->tcpbuf, TCP_BUFFER_SIZE);
744		client->tcpbuf = NULL;
745	}
746
747	if (exit_check(client))
748		return;
749
750	ns_client_next(client, ISC_R_SUCCESS);
751}
752
753/*%
754 * We only want to fail with ISC_R_NOSPACE when called from
755 * ns_client_sendraw() and not when called from ns_client_send(),
756 * tcpbuffer is NULL when called from ns_client_sendraw() and
757 * length != 0.  tcpbuffer != NULL when called from ns_client_send()
758 * and length == 0.
759 */
760
761static isc_result_t
762client_allocsendbuf(ns_client_t *client, isc_buffer_t *buffer,
763		    isc_buffer_t *tcpbuffer, isc_uint32_t length,
764		    unsigned char *sendbuf, unsigned char **datap)
765{
766	unsigned char *data;
767	isc_uint32_t bufsize;
768	isc_result_t result;
769
770	INSIST(datap != NULL);
771	INSIST((tcpbuffer == NULL && length != 0) ||
772	       (tcpbuffer != NULL && length == 0));
773
774	if (TCP_CLIENT(client)) {
775		INSIST(client->tcpbuf == NULL);
776		if (length + 2 > TCP_BUFFER_SIZE) {
777			result = ISC_R_NOSPACE;
778			goto done;
779		}
780		client->tcpbuf = isc_mem_get(client->mctx, TCP_BUFFER_SIZE);
781		if (client->tcpbuf == NULL) {
782			result = ISC_R_NOMEMORY;
783			goto done;
784		}
785		data = client->tcpbuf;
786		if (tcpbuffer != NULL) {
787			isc_buffer_init(tcpbuffer, data, TCP_BUFFER_SIZE);
788			isc_buffer_init(buffer, data + 2, TCP_BUFFER_SIZE - 2);
789		} else {
790			isc_buffer_init(buffer, data, TCP_BUFFER_SIZE);
791			INSIST(length <= 0xffff);
792			isc_buffer_putuint16(buffer, (isc_uint16_t)length);
793		}
794	} else {
795		data = sendbuf;
796		if (client->udpsize < SEND_BUFFER_SIZE)
797			bufsize = client->udpsize;
798		else
799			bufsize = SEND_BUFFER_SIZE;
800		if (length > bufsize) {
801			result = ISC_R_NOSPACE;
802			goto done;
803		}
804		isc_buffer_init(buffer, data, bufsize);
805	}
806	*datap = data;
807	result = ISC_R_SUCCESS;
808
809 done:
810	return (result);
811}
812
813static isc_result_t
814client_sendpkg(ns_client_t *client, isc_buffer_t *buffer) {
815	struct in6_pktinfo *pktinfo;
816	isc_result_t result;
817	isc_region_t r;
818	isc_sockaddr_t *address;
819	isc_socket_t *socket;
820	isc_netaddr_t netaddr;
821	int match;
822	unsigned int sockflags = ISC_SOCKFLAG_IMMEDIATE;
823
824	if (TCP_CLIENT(client)) {
825		socket = client->tcpsocket;
826		address = NULL;
827	} else {
828		socket = client->udpsocket;
829		address = &client->peeraddr;
830
831		isc_netaddr_fromsockaddr(&netaddr, &client->peeraddr);
832		if (ns_g_server->blackholeacl != NULL &&
833		    dns_acl_match(&netaddr, NULL,
834				  ns_g_server->blackholeacl,
835				  &ns_g_server->aclenv,
836				  &match, NULL) == ISC_R_SUCCESS &&
837		    match > 0)
838			return (DNS_R_BLACKHOLED);
839		sockflags |= ISC_SOCKFLAG_NORETRY;
840	}
841
842	if ((client->attributes & NS_CLIENTATTR_PKTINFO) != 0 &&
843	    (client->attributes & NS_CLIENTATTR_MULTICAST) == 0)
844		pktinfo = &client->pktinfo;
845	else
846		pktinfo = NULL;
847
848	isc_buffer_usedregion(buffer, &r);
849
850	CTRACE("sendto");
851
852	result = isc_socket_sendto2(socket, &r, client->task,
853				    address, pktinfo,
854				    client->sendevent, sockflags);
855	if (result == ISC_R_SUCCESS || result == ISC_R_INPROGRESS) {
856		client->nsends++;
857		if (result == ISC_R_SUCCESS)
858			client_senddone(client->task,
859					(isc_event_t *)client->sendevent);
860		result = ISC_R_SUCCESS;
861	}
862	return (result);
863}
864
865void
866ns_client_sendraw(ns_client_t *client, dns_message_t *message) {
867	isc_result_t result;
868	unsigned char *data;
869	isc_buffer_t buffer;
870	isc_region_t r;
871	isc_region_t *mr;
872	unsigned char sendbuf[SEND_BUFFER_SIZE];
873
874	REQUIRE(NS_CLIENT_VALID(client));
875
876	CTRACE("sendraw");
877
878	mr = dns_message_getrawmessage(message);
879	if (mr == NULL) {
880		result = ISC_R_UNEXPECTEDEND;
881		goto done;
882	}
883
884	result = client_allocsendbuf(client, &buffer, NULL, mr->length,
885				     sendbuf, &data);
886	if (result != ISC_R_SUCCESS)
887		goto done;
888
889	/*
890	 * Copy message to buffer and fixup id.
891	 */
892	isc_buffer_availableregion(&buffer, &r);
893	result = isc_buffer_copyregion(&buffer, mr);
894	if (result != ISC_R_SUCCESS)
895		goto done;
896	r.base[0] = (client->message->id >> 8) & 0xff;
897	r.base[1] = client->message->id & 0xff;
898
899	result = client_sendpkg(client, &buffer);
900	if (result == ISC_R_SUCCESS)
901		return;
902
903 done:
904	if (client->tcpbuf != NULL) {
905		isc_mem_put(client->mctx, client->tcpbuf, TCP_BUFFER_SIZE);
906		client->tcpbuf = NULL;
907	}
908	ns_client_next(client, result);
909}
910
911void
912ns_client_send(ns_client_t *client) {
913	isc_result_t result;
914	unsigned char *data;
915	isc_buffer_t buffer;
916	isc_buffer_t tcpbuffer;
917	isc_region_t r;
918	dns_compress_t cctx;
919	isc_boolean_t cleanup_cctx = ISC_FALSE;
920	unsigned char sendbuf[SEND_BUFFER_SIZE];
921	unsigned int dnssec_opts;
922	unsigned int preferred_glue;
923	isc_boolean_t opt_included = ISC_FALSE;
924
925	REQUIRE(NS_CLIENT_VALID(client));
926
927	CTRACE("send");
928
929	if ((client->attributes & NS_CLIENTATTR_RA) != 0)
930		client->message->flags |= DNS_MESSAGEFLAG_RA;
931
932	if ((client->attributes & NS_CLIENTATTR_WANTDNSSEC) != 0)
933		dnssec_opts = 0;
934	else
935		dnssec_opts = DNS_MESSAGERENDER_OMITDNSSEC;
936
937	preferred_glue = 0;
938	if (client->view != NULL) {
939		if (client->view->preferred_glue == dns_rdatatype_a)
940			preferred_glue = DNS_MESSAGERENDER_PREFER_A;
941		else if (client->view->preferred_glue == dns_rdatatype_aaaa)
942			preferred_glue = DNS_MESSAGERENDER_PREFER_AAAA;
943	}
944
945	/*
946	 * XXXRTH  The following doesn't deal with TCP buffer resizing.
947	 */
948	result = client_allocsendbuf(client, &buffer, &tcpbuffer, 0,
949				     sendbuf, &data);
950	if (result != ISC_R_SUCCESS)
951		goto done;
952
953	result = dns_compress_init(&cctx, -1, client->mctx);
954	if (result != ISC_R_SUCCESS)
955		goto done;
956	cleanup_cctx = ISC_TRUE;
957
958	result = dns_message_renderbegin(client->message, &cctx, &buffer);
959	if (result != ISC_R_SUCCESS)
960		goto done;
961
962	if (client->opt != NULL) {
963		result = dns_message_setopt(client->message, client->opt);
964		opt_included = ISC_TRUE;
965		client->opt = NULL;
966		if (result != ISC_R_SUCCESS)
967			goto done;
968	}
969	result = dns_message_rendersection(client->message,
970					   DNS_SECTION_QUESTION, 0);
971	if (result == ISC_R_NOSPACE) {
972		client->message->flags |= DNS_MESSAGEFLAG_TC;
973		goto renderend;
974	}
975	if (result != ISC_R_SUCCESS)
976		goto done;
977	result = dns_message_rendersection(client->message,
978					   DNS_SECTION_ANSWER,
979					   DNS_MESSAGERENDER_PARTIAL |
980					   dnssec_opts);
981	if (result == ISC_R_NOSPACE) {
982		client->message->flags |= DNS_MESSAGEFLAG_TC;
983		goto renderend;
984	}
985	if (result != ISC_R_SUCCESS)
986		goto done;
987	result = dns_message_rendersection(client->message,
988					   DNS_SECTION_AUTHORITY,
989					   DNS_MESSAGERENDER_PARTIAL |
990					   dnssec_opts);
991	if (result == ISC_R_NOSPACE) {
992		client->message->flags |= DNS_MESSAGEFLAG_TC;
993		goto renderend;
994	}
995	if (result != ISC_R_SUCCESS)
996		goto done;
997	result = dns_message_rendersection(client->message,
998					   DNS_SECTION_ADDITIONAL,
999					   preferred_glue | dnssec_opts);
1000	if (result != ISC_R_SUCCESS && result != ISC_R_NOSPACE)
1001		goto done;
1002 renderend:
1003	result = dns_message_renderend(client->message);
1004
1005	if (result != ISC_R_SUCCESS)
1006		goto done;
1007
1008	if (cleanup_cctx) {
1009		dns_compress_invalidate(&cctx);
1010		cleanup_cctx = ISC_FALSE;
1011	}
1012
1013	if (TCP_CLIENT(client)) {
1014		isc_buffer_usedregion(&buffer, &r);
1015		isc_buffer_putuint16(&tcpbuffer, (isc_uint16_t) r.length);
1016		isc_buffer_add(&tcpbuffer, r.length);
1017		result = client_sendpkg(client, &tcpbuffer);
1018	} else
1019		result = client_sendpkg(client, &buffer);
1020
1021	/* update statistics (XXXJT: is it okay to access message->xxxkey?) */
1022	isc_stats_increment(ns_g_server->nsstats, dns_nsstatscounter_response);
1023	if (opt_included) {
1024		isc_stats_increment(ns_g_server->nsstats,
1025				    dns_nsstatscounter_edns0out);
1026	}
1027	if (client->message->tsigkey != NULL) {
1028		isc_stats_increment(ns_g_server->nsstats,
1029				    dns_nsstatscounter_tsigout);
1030	}
1031	if (client->message->sig0key != NULL) {
1032		isc_stats_increment(ns_g_server->nsstats,
1033				    dns_nsstatscounter_sig0out);
1034	}
1035	if ((client->message->flags & DNS_MESSAGEFLAG_TC) != 0)
1036		isc_stats_increment(ns_g_server->nsstats,
1037				    dns_nsstatscounter_truncatedresp);
1038
1039	if (result == ISC_R_SUCCESS)
1040		return;
1041
1042 done:
1043	if (client->tcpbuf != NULL) {
1044		isc_mem_put(client->mctx, client->tcpbuf, TCP_BUFFER_SIZE);
1045		client->tcpbuf = NULL;
1046	}
1047
1048	if (cleanup_cctx)
1049		dns_compress_invalidate(&cctx);
1050
1051	ns_client_next(client, result);
1052}
1053
1054#if NS_CLIENT_DROPPORT
1055#define DROPPORT_NO		0
1056#define DROPPORT_REQUEST	1
1057#define DROPPORT_RESPONSE	2
1058/*%
1059 * ns_client_dropport determines if certain requests / responses
1060 * should be dropped based on the port number.
1061 *
1062 * Returns:
1063 * \li	0:	Don't drop.
1064 * \li	1:	Drop request.
1065 * \li	2:	Drop (error) response.
1066 */
1067static int
1068ns_client_dropport(in_port_t port) {
1069	switch (port) {
1070	case 7: /* echo */
1071	case 13: /* daytime */
1072	case 19: /* chargen */
1073	case 37: /* time */
1074		return (DROPPORT_REQUEST);
1075	case 464: /* kpasswd */
1076		return (DROPPORT_RESPONSE);
1077	}
1078	return (DROPPORT_NO);
1079}
1080#endif
1081
1082void
1083ns_client_error(ns_client_t *client, isc_result_t result) {
1084	dns_rcode_t rcode;
1085	dns_message_t *message;
1086
1087	REQUIRE(NS_CLIENT_VALID(client));
1088
1089	CTRACE("error");
1090
1091	message = client->message;
1092	rcode = dns_result_torcode(result);
1093
1094#if NS_CLIENT_DROPPORT
1095	/*
1096	 * Don't send FORMERR to ports on the drop port list.
1097	 */
1098	if (rcode == dns_rcode_formerr &&
1099	    ns_client_dropport(isc_sockaddr_getport(&client->peeraddr)) !=
1100	    DROPPORT_NO) {
1101		char buf[64];
1102		isc_buffer_t b;
1103
1104		isc_buffer_init(&b, buf, sizeof(buf) - 1);
1105		if (dns_rcode_totext(rcode, &b) != ISC_R_SUCCESS)
1106			isc_buffer_putstr(&b, "UNKNOWN RCODE");
1107		ns_client_log(client, DNS_LOGCATEGORY_SECURITY,
1108			      NS_LOGMODULE_CLIENT, ISC_LOG_DEBUG(10),
1109			      "dropped error (%.*s) response: suspicious port",
1110			      (int)isc_buffer_usedlength(&b), buf);
1111		ns_client_next(client, ISC_R_SUCCESS);
1112		return;
1113	}
1114#endif
1115
1116	/*
1117	 * Message may be an in-progress reply that we had trouble
1118	 * with, in which case QR will be set.  We need to clear QR before
1119	 * calling dns_message_reply() to avoid triggering an assertion.
1120	 */
1121	message->flags &= ~DNS_MESSAGEFLAG_QR;
1122	/*
1123	 * AA and AD shouldn't be set.
1124	 */
1125	message->flags &= ~(DNS_MESSAGEFLAG_AA | DNS_MESSAGEFLAG_AD);
1126	result = dns_message_reply(message, ISC_TRUE);
1127	if (result != ISC_R_SUCCESS) {
1128		/*
1129		 * It could be that we've got a query with a good header,
1130		 * but a bad question section, so we try again with
1131		 * want_question_section set to ISC_FALSE.
1132		 */
1133		result = dns_message_reply(message, ISC_FALSE);
1134		if (result != ISC_R_SUCCESS) {
1135			ns_client_next(client, result);
1136			return;
1137		}
1138	}
1139	message->rcode = rcode;
1140
1141	/*
1142	 * FORMERR loop avoidance:  If we sent a FORMERR message
1143	 * with the same ID to the same client less than two
1144	 * seconds ago, assume that we are in an infinite error
1145	 * packet dialog with a server for some protocol whose
1146	 * error responses look enough like DNS queries to
1147	 * elicit a FORMERR response.  Drop a packet to break
1148	 * the loop.
1149	 */
1150	if (rcode == dns_rcode_formerr) {
1151		if (isc_sockaddr_equal(&client->peeraddr,
1152				       &client->formerrcache.addr) &&
1153		    message->id == client->formerrcache.id &&
1154		    client->requesttime - client->formerrcache.time < 2) {
1155			/* Drop packet. */
1156			ns_client_log(client, NS_LOGCATEGORY_CLIENT,
1157				      NS_LOGMODULE_CLIENT, ISC_LOG_DEBUG(1),
1158				      "possible error packet loop, "
1159				      "FORMERR dropped");
1160			ns_client_next(client, result);
1161			return;
1162		}
1163		client->formerrcache.addr = client->peeraddr;
1164		client->formerrcache.time = client->requesttime;
1165		client->formerrcache.id = message->id;
1166	}
1167	ns_client_send(client);
1168}
1169
1170static inline isc_result_t
1171client_addopt(ns_client_t *client) {
1172	dns_rdataset_t *rdataset;
1173	dns_rdatalist_t *rdatalist;
1174	dns_rdata_t *rdata;
1175	isc_result_t result;
1176	dns_view_t *view;
1177	dns_resolver_t *resolver;
1178	isc_uint16_t udpsize;
1179
1180	REQUIRE(client->opt == NULL);	/* XXXRTH free old. */
1181
1182	rdatalist = NULL;
1183	result = dns_message_gettemprdatalist(client->message, &rdatalist);
1184	if (result != ISC_R_SUCCESS)
1185		return (result);
1186	rdata = NULL;
1187	result = dns_message_gettemprdata(client->message, &rdata);
1188	if (result != ISC_R_SUCCESS)
1189		return (result);
1190	rdataset = NULL;
1191	result = dns_message_gettemprdataset(client->message, &rdataset);
1192	if (result != ISC_R_SUCCESS)
1193		return (result);
1194	dns_rdataset_init(rdataset);
1195
1196	rdatalist->type = dns_rdatatype_opt;
1197	rdatalist->covers = 0;
1198
1199	/*
1200	 * Set the maximum UDP buffer size.
1201	 */
1202	view = client->view;
1203	resolver = (view != NULL) ? view->resolver : NULL;
1204	if (resolver != NULL)
1205		udpsize = dns_resolver_getudpsize(resolver);
1206	else
1207		udpsize = ns_g_udpsize;
1208	rdatalist->rdclass = udpsize;
1209
1210	/*
1211	 * Set EXTENDED-RCODE, VERSION and Z to 0.
1212	 */
1213	rdatalist->ttl = (client->extflags & DNS_MESSAGEEXTFLAG_REPLYPRESERVE);
1214
1215	/* Set EDNS options if applicable */
1216	if (client->attributes & NS_CLIENTATTR_WANTNSID &&
1217	    (ns_g_server->server_id != NULL ||
1218	     ns_g_server->server_usehostname)) {
1219		/*
1220		 * Space required for NSID data:
1221		 *   2 bytes for opt code
1222		 * + 2 bytes for NSID length
1223		 * + NSID itself
1224		 */
1225		char nsid[BUFSIZ], *nsidp;
1226		isc_buffer_t *buffer = NULL;
1227
1228		if (ns_g_server->server_usehostname) {
1229			isc_result_t result;
1230			result = ns_os_gethostname(nsid, sizeof(nsid));
1231			if (result != ISC_R_SUCCESS) {
1232				goto no_nsid;
1233			}
1234			nsidp = nsid;
1235		} else
1236			nsidp = ns_g_server->server_id;
1237
1238		rdata->length = strlen(nsidp) + 4;
1239		result = isc_buffer_allocate(client->mctx, &buffer,
1240					     rdata->length);
1241		if (result != ISC_R_SUCCESS)
1242			goto no_nsid;
1243
1244		isc_buffer_putuint16(buffer, DNS_OPT_NSID);
1245		isc_buffer_putuint16(buffer, strlen(nsidp));
1246		isc_buffer_putstr(buffer, nsidp);
1247		rdata->data = buffer->base;
1248		dns_message_takebuffer(client->message, &buffer);
1249	} else {
1250no_nsid:
1251		rdata->data = NULL;
1252		rdata->length = 0;
1253	}
1254
1255	rdata->rdclass = rdatalist->rdclass;
1256	rdata->type = rdatalist->type;
1257	rdata->flags = 0;
1258
1259	ISC_LIST_INIT(rdatalist->rdata);
1260	ISC_LIST_APPEND(rdatalist->rdata, rdata, link);
1261	RUNTIME_CHECK(dns_rdatalist_tordataset(rdatalist, rdataset)
1262		      == ISC_R_SUCCESS);
1263
1264	client->opt = rdataset;
1265
1266	return (ISC_R_SUCCESS);
1267}
1268
1269static inline isc_boolean_t
1270allowed(isc_netaddr_t *addr, dns_name_t *signer, dns_acl_t *acl) {
1271	int match;
1272	isc_result_t result;
1273
1274	if (acl == NULL)
1275		return (ISC_TRUE);
1276	result = dns_acl_match(addr, signer, acl, &ns_g_server->aclenv,
1277			       &match, NULL);
1278	if (result == ISC_R_SUCCESS && match > 0)
1279		return (ISC_TRUE);
1280	return (ISC_FALSE);
1281}
1282
1283/*
1284 * Callback to see if a non-recursive query coming from 'srcaddr' to
1285 * 'destaddr', with optional key 'mykey' for class 'rdclass' would be
1286 * delivered to 'myview'.
1287 *
1288 * We run this unlocked as both the view list and the interface list
1289 * are updated when the appropriate task has exclusivity.
1290 */
1291isc_boolean_t
1292ns_client_isself(dns_view_t *myview, dns_tsigkey_t *mykey,
1293		 isc_sockaddr_t *srcaddr, isc_sockaddr_t *dstaddr,
1294		 dns_rdataclass_t rdclass, void *arg)
1295{
1296	dns_view_t *view;
1297	dns_tsigkey_t *key = NULL;
1298	dns_name_t *tsig = NULL;
1299	isc_netaddr_t netsrc;
1300	isc_netaddr_t netdst;
1301
1302	UNUSED(arg);
1303
1304	if (!ns_interfacemgr_listeningon(ns_g_server->interfacemgr, dstaddr))
1305		return (ISC_FALSE);
1306
1307	isc_netaddr_fromsockaddr(&netsrc, srcaddr);
1308	isc_netaddr_fromsockaddr(&netdst, dstaddr);
1309
1310	for (view = ISC_LIST_HEAD(ns_g_server->viewlist);
1311	     view != NULL;
1312	     view = ISC_LIST_NEXT(view, link)) {
1313
1314		if (view->matchrecursiveonly)
1315			continue;
1316
1317		if (rdclass != view->rdclass)
1318			continue;
1319
1320		if (mykey != NULL) {
1321			isc_boolean_t match;
1322			isc_result_t result;
1323
1324			result = dns_view_gettsig(view, &mykey->name, &key);
1325			if (result != ISC_R_SUCCESS)
1326				continue;
1327			match = dst_key_compare(mykey->key, key->key);
1328			dns_tsigkey_detach(&key);
1329			if (!match)
1330				continue;
1331			tsig = dns_tsigkey_identity(mykey);
1332		}
1333
1334		if (allowed(&netsrc, tsig, view->matchclients) &&
1335		    allowed(&netdst, tsig, view->matchdestinations))
1336			break;
1337	}
1338	return (ISC_TF(view == myview));
1339}
1340
1341/*
1342 * Handle an incoming request event from the socket (UDP case)
1343 * or tcpmsg (TCP case).
1344 */
1345static void
1346client_request(isc_task_t *task, isc_event_t *event) {
1347	ns_client_t *client;
1348	isc_socketevent_t *sevent;
1349	isc_result_t result;
1350	isc_result_t sigresult = ISC_R_SUCCESS;
1351	isc_buffer_t *buffer;
1352	isc_buffer_t tbuffer;
1353	dns_view_t *view;
1354	dns_rdataset_t *opt;
1355	dns_name_t *signame;
1356	isc_boolean_t ra;	/* Recursion available. */
1357	isc_netaddr_t netaddr;
1358	isc_netaddr_t destaddr;
1359	int match;
1360	dns_messageid_t id;
1361	unsigned int flags;
1362	isc_boolean_t notimp;
1363	dns_rdata_t rdata;
1364	isc_uint16_t optcode;
1365
1366	REQUIRE(event != NULL);
1367	client = event->ev_arg;
1368	REQUIRE(NS_CLIENT_VALID(client));
1369	REQUIRE(task == client->task);
1370
1371	INSIST(client->recursionquota == NULL);
1372
1373	INSIST(client->state ==
1374	       TCP_CLIENT(client) ?
1375	       NS_CLIENTSTATE_READING :
1376	       NS_CLIENTSTATE_READY);
1377
1378	ns_client_requests++;
1379
1380	if (event->ev_type == ISC_SOCKEVENT_RECVDONE) {
1381		INSIST(!TCP_CLIENT(client));
1382		sevent = (isc_socketevent_t *)event;
1383		REQUIRE(sevent == client->recvevent);
1384		isc_buffer_init(&tbuffer, sevent->region.base, sevent->n);
1385		isc_buffer_add(&tbuffer, sevent->n);
1386		buffer = &tbuffer;
1387		result = sevent->result;
1388		if (result == ISC_R_SUCCESS) {
1389			client->peeraddr = sevent->address;
1390			client->peeraddr_valid = ISC_TRUE;
1391		}
1392		if ((sevent->attributes & ISC_SOCKEVENTATTR_PKTINFO) != 0) {
1393			client->attributes |= NS_CLIENTATTR_PKTINFO;
1394			client->pktinfo = sevent->pktinfo;
1395		}
1396		if ((sevent->attributes & ISC_SOCKEVENTATTR_MULTICAST) != 0)
1397			client->attributes |= NS_CLIENTATTR_MULTICAST;
1398		client->nrecvs--;
1399	} else {
1400		INSIST(TCP_CLIENT(client));
1401		REQUIRE(event->ev_type == DNS_EVENT_TCPMSG);
1402		REQUIRE(event->ev_sender == &client->tcpmsg);
1403		buffer = &client->tcpmsg.buffer;
1404		result = client->tcpmsg.result;
1405		INSIST(client->nreads == 1);
1406		/*
1407		 * client->peeraddr was set when the connection was accepted.
1408		 */
1409		client->nreads--;
1410	}
1411
1412	if (exit_check(client))
1413		goto cleanup;
1414	client->state = client->newstate = NS_CLIENTSTATE_WORKING;
1415
1416	isc_task_getcurrenttime(task, &client->requesttime);
1417	client->now = client->requesttime;
1418
1419	if (result != ISC_R_SUCCESS) {
1420		if (TCP_CLIENT(client)) {
1421			ns_client_next(client, result);
1422		} else {
1423			if  (result != ISC_R_CANCELED)
1424				isc_log_write(ns_g_lctx, NS_LOGCATEGORY_CLIENT,
1425					      NS_LOGMODULE_CLIENT,
1426					      ISC_LOG_ERROR,
1427					      "UDP client handler shutting "
1428					      "down due to fatal receive "
1429					      "error: %s",
1430					      isc_result_totext(result));
1431			isc_task_shutdown(client->task);
1432		}
1433		goto cleanup;
1434	}
1435
1436	isc_netaddr_fromsockaddr(&netaddr, &client->peeraddr);
1437
1438#if NS_CLIENT_DROPPORT
1439	if (ns_client_dropport(isc_sockaddr_getport(&client->peeraddr)) ==
1440	    DROPPORT_REQUEST) {
1441		ns_client_log(client, DNS_LOGCATEGORY_SECURITY,
1442			      NS_LOGMODULE_CLIENT, ISC_LOG_DEBUG(10),
1443			      "dropped request: suspicious port");
1444		ns_client_next(client, ISC_R_SUCCESS);
1445		goto cleanup;
1446	}
1447#endif
1448
1449	ns_client_log(client, NS_LOGCATEGORY_CLIENT,
1450		      NS_LOGMODULE_CLIENT, ISC_LOG_DEBUG(3),
1451		      "%s request",
1452		      TCP_CLIENT(client) ? "TCP" : "UDP");
1453
1454	/*
1455	 * Check the blackhole ACL for UDP only, since TCP is done in
1456	 * client_newconn.
1457	 */
1458	if (!TCP_CLIENT(client)) {
1459
1460		if (ns_g_server->blackholeacl != NULL &&
1461		    dns_acl_match(&netaddr, NULL, ns_g_server->blackholeacl,
1462				  &ns_g_server->aclenv,
1463				  &match, NULL) == ISC_R_SUCCESS &&
1464		    match > 0)
1465		{
1466			ns_client_log(client, DNS_LOGCATEGORY_SECURITY,
1467				      NS_LOGMODULE_CLIENT, ISC_LOG_DEBUG(10),
1468				      "blackholed UDP datagram");
1469			ns_client_next(client, ISC_R_SUCCESS);
1470			goto cleanup;
1471		}
1472	}
1473
1474	/*
1475	 * Silently drop multicast requests for the present.
1476	 * XXXMPA look at when/if mDNS spec stabilizes.
1477	 */
1478	if ((client->attributes & NS_CLIENTATTR_MULTICAST) != 0) {
1479		ns_client_log(client, NS_LOGCATEGORY_CLIENT,
1480			      NS_LOGMODULE_CLIENT, ISC_LOG_DEBUG(2),
1481			      "dropping multicast request");
1482		ns_client_next(client, DNS_R_REFUSED);
1483		goto cleanup;
1484	}
1485
1486	result = dns_message_peekheader(buffer, &id, &flags);
1487	if (result != ISC_R_SUCCESS) {
1488		/*
1489		 * There isn't enough header to determine whether
1490		 * this was a request or a response.  Drop it.
1491		 */
1492		ns_client_next(client, result);
1493		goto cleanup;
1494	}
1495
1496	/*
1497	 * The client object handles requests, not responses.
1498	 * If this is a UDP response, forward it to the dispatcher.
1499	 * If it's a TCP response, discard it here.
1500	 */
1501	if ((flags & DNS_MESSAGEFLAG_QR) != 0) {
1502		if (TCP_CLIENT(client)) {
1503			CTRACE("unexpected response");
1504			ns_client_next(client, DNS_R_FORMERR);
1505			goto cleanup;
1506		} else {
1507			dns_dispatch_importrecv(client->dispatch, event);
1508			ns_client_next(client, ISC_R_SUCCESS);
1509			goto cleanup;
1510		}
1511	}
1512
1513	/*
1514	 * Update some statistics counters.  Don't count responses.
1515	 */
1516	if (isc_sockaddr_pf(&client->peeraddr) == PF_INET) {
1517		isc_stats_increment(ns_g_server->nsstats,
1518				    dns_nsstatscounter_requestv4);
1519	} else {
1520		isc_stats_increment(ns_g_server->nsstats,
1521				    dns_nsstatscounter_requestv6);
1522	}
1523	if (TCP_CLIENT(client))
1524		isc_stats_increment(ns_g_server->nsstats,
1525				    dns_nsstatscounter_tcp);
1526
1527	/*
1528	 * It's a request.  Parse it.
1529	 */
1530	result = dns_message_parse(client->message, buffer, 0);
1531	if (result != ISC_R_SUCCESS) {
1532		/*
1533		 * Parsing the request failed.  Send a response
1534		 * (typically FORMERR or SERVFAIL).
1535		 */
1536		ns_client_error(client, result);
1537		goto cleanup;
1538	}
1539
1540	dns_opcodestats_increment(ns_g_server->opcodestats,
1541				  client->message->opcode);
1542	switch (client->message->opcode) {
1543	case dns_opcode_query:
1544	case dns_opcode_update:
1545	case dns_opcode_notify:
1546		notimp = ISC_FALSE;
1547		break;
1548	case dns_opcode_iquery:
1549	default:
1550		notimp = ISC_TRUE;
1551		break;
1552	}
1553
1554	client->message->rcode = dns_rcode_noerror;
1555
1556	/* RFC1123 section 6.1.3.2 */
1557	if ((client->attributes & NS_CLIENTATTR_MULTICAST) != 0)
1558		client->message->flags &= ~DNS_MESSAGEFLAG_RD;
1559
1560	/*
1561	 * Deal with EDNS.
1562	 */
1563	opt = dns_message_getopt(client->message);
1564	if (opt != NULL) {
1565		/*
1566		 * Set the client's UDP buffer size.
1567		 */
1568		client->udpsize = opt->rdclass;
1569
1570		/*
1571		 * If the requested UDP buffer size is less than 512,
1572		 * ignore it and use 512.
1573		 */
1574		if (client->udpsize < 512)
1575			client->udpsize = 512;
1576
1577		/*
1578		 * Get the flags out of the OPT record.
1579		 */
1580		client->extflags = (isc_uint16_t)(opt->ttl & 0xFFFF);
1581
1582		/*
1583		 * Do we understand this version of EDNS?
1584		 *
1585		 * XXXRTH need library support for this!
1586		 */
1587		client->ednsversion = (opt->ttl & 0x00FF0000) >> 16;
1588		if (client->ednsversion > 0) {
1589			isc_stats_increment(ns_g_server->nsstats,
1590					    dns_nsstatscounter_badednsver);
1591			result = client_addopt(client);
1592			if (result == ISC_R_SUCCESS)
1593				result = DNS_R_BADVERS;
1594			ns_client_error(client, result);
1595			goto cleanup;
1596		}
1597
1598		/* Check for NSID request */
1599		result = dns_rdataset_first(opt);
1600		if (result == ISC_R_SUCCESS) {
1601			dns_rdata_init(&rdata);
1602			dns_rdataset_current(opt, &rdata);
1603			if (rdata.length >= 2) {
1604				isc_buffer_t nsidbuf;
1605				isc_buffer_init(&nsidbuf,
1606						rdata.data, rdata.length);
1607				isc_buffer_add(&nsidbuf, rdata.length);
1608				optcode = isc_buffer_getuint16(&nsidbuf);
1609				if (optcode == DNS_OPT_NSID)
1610					client->attributes |=
1611						NS_CLIENTATTR_WANTNSID;
1612			}
1613		}
1614
1615		isc_stats_increment(ns_g_server->nsstats,
1616				    dns_nsstatscounter_edns0in);
1617
1618		/*
1619		 * Create an OPT for our reply.
1620		 */
1621		result = client_addopt(client);
1622		if (result != ISC_R_SUCCESS) {
1623			ns_client_error(client, result);
1624			goto cleanup;
1625		}
1626	}
1627
1628	if (client->message->rdclass == 0) {
1629		ns_client_log(client, NS_LOGCATEGORY_CLIENT,
1630			      NS_LOGMODULE_CLIENT, ISC_LOG_DEBUG(1),
1631			      "message class could not be determined");
1632		ns_client_dumpmessage(client,
1633				      "message class could not be determined");
1634		ns_client_error(client, notimp ? DNS_R_NOTIMP : DNS_R_FORMERR);
1635		goto cleanup;
1636	}
1637
1638	/*
1639	 * Determine the destination address.  If the receiving interface is
1640	 * bound to a specific address, we simply use it regardless of the
1641	 * address family.  All IPv4 queries should fall into this case.
1642	 * Otherwise, if this is a TCP query, get the address from the
1643	 * receiving socket (this needs a system call and can be heavy).
1644	 * For IPv6 UDP queries, we get this from the pktinfo structure (if
1645	 * supported).
1646	 * If all the attempts fail (this can happen due to memory shortage,
1647	 * etc), we regard this as an error for safety.
1648	 */
1649	if ((client->interface->flags & NS_INTERFACEFLAG_ANYADDR) == 0)
1650		isc_netaddr_fromsockaddr(&destaddr, &client->interface->addr);
1651	else {
1652		result = ISC_R_FAILURE;
1653
1654		if (TCP_CLIENT(client)) {
1655			isc_sockaddr_t destsockaddr;
1656
1657			result = isc_socket_getsockname(client->tcpsocket,
1658							&destsockaddr);
1659			if (result == ISC_R_SUCCESS)
1660				isc_netaddr_fromsockaddr(&destaddr,
1661							 &destsockaddr);
1662		}
1663		if (result != ISC_R_SUCCESS &&
1664		    client->interface->addr.type.sa.sa_family == AF_INET6 &&
1665		    (client->attributes & NS_CLIENTATTR_PKTINFO) != 0) {
1666			isc_uint32_t zone = 0;
1667
1668			/*
1669			 * XXXJT technically, we should convert the receiving
1670			 * interface ID to a proper scope zone ID.  However,
1671			 * due to the fact there is no standard API for this,
1672			 * we only handle link-local addresses and use the
1673			 * interface index as link ID.  Despite the assumption,
1674			 * it should cover most typical cases.
1675			 */
1676			if (IN6_IS_ADDR_LINKLOCAL(&client->pktinfo.ipi6_addr))
1677				zone = (isc_uint32_t)client->pktinfo.ipi6_ifindex;
1678
1679			isc_netaddr_fromin6(&destaddr,
1680					    &client->pktinfo.ipi6_addr);
1681			isc_netaddr_setzone(&destaddr, zone);
1682			result = ISC_R_SUCCESS;
1683		}
1684		if (result != ISC_R_SUCCESS) {
1685			UNEXPECTED_ERROR(__FILE__, __LINE__,
1686					 "failed to get request's "
1687					 "destination: %s",
1688					 isc_result_totext(result));
1689			ns_client_next(client, ISC_R_SUCCESS);
1690			goto cleanup;
1691		}
1692	}
1693
1694	/*
1695	 * Find a view that matches the client's source address.
1696	 */
1697	for (view = ISC_LIST_HEAD(ns_g_server->viewlist);
1698	     view != NULL;
1699	     view = ISC_LIST_NEXT(view, link)) {
1700		if (client->message->rdclass == view->rdclass ||
1701		    client->message->rdclass == dns_rdataclass_any)
1702		{
1703			dns_name_t *tsig = NULL;
1704
1705			sigresult = dns_message_rechecksig(client->message,
1706							   view);
1707			if (sigresult == ISC_R_SUCCESS)
1708				tsig = dns_tsigkey_identity(client->message->tsigkey);
1709
1710			if (allowed(&netaddr, tsig, view->matchclients) &&
1711			    allowed(&destaddr, tsig, view->matchdestinations) &&
1712			    !((client->message->flags & DNS_MESSAGEFLAG_RD)
1713			      == 0 && view->matchrecursiveonly))
1714			{
1715				dns_view_attach(view, &client->view);
1716				break;
1717			}
1718		}
1719	}
1720
1721	if (view == NULL) {
1722		char classname[DNS_RDATACLASS_FORMATSIZE];
1723
1724		/*
1725		 * Do a dummy TSIG verification attempt so that the
1726		 * response will have a TSIG if the query did, as
1727		 * required by RFC2845.
1728		 */
1729		isc_buffer_t b;
1730		isc_region_t *r;
1731
1732		dns_message_resetsig(client->message);
1733
1734		r = dns_message_getrawmessage(client->message);
1735		isc_buffer_init(&b, r->base, r->length);
1736		isc_buffer_add(&b, r->length);
1737		(void)dns_tsig_verify(&b, client->message, NULL, NULL);
1738
1739		dns_rdataclass_format(client->message->rdclass, classname,
1740				      sizeof(classname));
1741		ns_client_log(client, NS_LOGCATEGORY_CLIENT,
1742			      NS_LOGMODULE_CLIENT, ISC_LOG_DEBUG(1),
1743			      "no matching view in class '%s'", classname);
1744		ns_client_dumpmessage(client, "no matching view in class");
1745		ns_client_error(client, notimp ? DNS_R_NOTIMP : DNS_R_REFUSED);
1746		goto cleanup;
1747	}
1748
1749	ns_client_log(client, NS_LOGCATEGORY_CLIENT,
1750		      NS_LOGMODULE_CLIENT, ISC_LOG_DEBUG(5),
1751		      "using view '%s'", view->name);
1752
1753	/*
1754	 * Check for a signature.  We log bad signatures regardless of
1755	 * whether they ultimately cause the request to be rejected or
1756	 * not.  We do not log the lack of a signature unless we are
1757	 * debugging.
1758	 */
1759	client->signer = NULL;
1760	dns_name_init(&client->signername, NULL);
1761	result = dns_message_signer(client->message, &client->signername);
1762	if (result != ISC_R_NOTFOUND) {
1763		signame = NULL;
1764		if (dns_message_gettsig(client->message, &signame) != NULL) {
1765			isc_stats_increment(ns_g_server->nsstats,
1766					    dns_nsstatscounter_tsigin);
1767		} else {
1768			isc_stats_increment(ns_g_server->nsstats,
1769					    dns_nsstatscounter_sig0in);
1770		}
1771
1772	}
1773	if (result == ISC_R_SUCCESS) {
1774		ns_client_log(client, DNS_LOGCATEGORY_SECURITY,
1775			      NS_LOGMODULE_CLIENT, ISC_LOG_DEBUG(3),
1776			      "request has valid signature");
1777		client->signer = &client->signername;
1778	} else if (result == ISC_R_NOTFOUND) {
1779		ns_client_log(client, DNS_LOGCATEGORY_SECURITY,
1780			      NS_LOGMODULE_CLIENT, ISC_LOG_DEBUG(3),
1781			      "request is not signed");
1782	} else if (result == DNS_R_NOIDENTITY) {
1783		ns_client_log(client, DNS_LOGCATEGORY_SECURITY,
1784			      NS_LOGMODULE_CLIENT, ISC_LOG_DEBUG(3),
1785			      "request is signed by a nonauthoritative key");
1786	} else {
1787		char tsigrcode[64];
1788		isc_buffer_t b;
1789		dns_rcode_t status;
1790		isc_result_t tresult;
1791
1792		/* There is a signature, but it is bad. */
1793		isc_stats_increment(ns_g_server->nsstats,
1794				    dns_nsstatscounter_invalidsig);
1795		signame = NULL;
1796		if (dns_message_gettsig(client->message, &signame) != NULL) {
1797			char namebuf[DNS_NAME_FORMATSIZE];
1798			char cnamebuf[DNS_NAME_FORMATSIZE];
1799			dns_name_format(signame, namebuf, sizeof(namebuf));
1800			status = client->message->tsigstatus;
1801			isc_buffer_init(&b, tsigrcode, sizeof(tsigrcode) - 1);
1802			tresult = dns_tsigrcode_totext(status, &b);
1803			INSIST(tresult == ISC_R_SUCCESS);
1804			tsigrcode[isc_buffer_usedlength(&b)] = '\0';
1805			if (client->message->tsigkey->generated) {
1806				dns_name_format(client->message->tsigkey->creator,
1807						cnamebuf, sizeof(cnamebuf));
1808				ns_client_log(client, DNS_LOGCATEGORY_SECURITY,
1809					      NS_LOGMODULE_CLIENT,
1810					      ISC_LOG_ERROR,
1811					      "request has invalid signature: "
1812					      "TSIG %s (%s): %s (%s)", namebuf,
1813					      cnamebuf,
1814					      isc_result_totext(result),
1815					      tsigrcode);
1816			} else {
1817				ns_client_log(client, DNS_LOGCATEGORY_SECURITY,
1818					      NS_LOGMODULE_CLIENT,
1819					      ISC_LOG_ERROR,
1820					      "request has invalid signature: "
1821					      "TSIG %s: %s (%s)", namebuf,
1822					      isc_result_totext(result),
1823					      tsigrcode);
1824			}
1825		} else {
1826			status = client->message->sig0status;
1827			isc_buffer_init(&b, tsigrcode, sizeof(tsigrcode) - 1);
1828			tresult = dns_tsigrcode_totext(status, &b);
1829			INSIST(tresult == ISC_R_SUCCESS);
1830			tsigrcode[isc_buffer_usedlength(&b)] = '\0';
1831			ns_client_log(client, DNS_LOGCATEGORY_SECURITY,
1832				      NS_LOGMODULE_CLIENT, ISC_LOG_ERROR,
1833				      "request has invalid signature: %s (%s)",
1834				      isc_result_totext(result), tsigrcode);
1835		}
1836		/*
1837		 * Accept update messages signed by unknown keys so that
1838		 * update forwarding works transparently through slaves
1839		 * that don't have all the same keys as the master.
1840		 */
1841		if (!(client->message->tsigstatus == dns_tsigerror_badkey &&
1842		      client->message->opcode == dns_opcode_update)) {
1843			ns_client_error(client, sigresult);
1844			goto cleanup;
1845		}
1846	}
1847
1848	/*
1849	 * Decide whether recursive service is available to this client.
1850	 * We do this here rather than in the query code so that we can
1851	 * set the RA bit correctly on all kinds of responses, not just
1852	 * responses to ordinary queries.  Note if you can't query the
1853	 * cache there is no point in setting RA.
1854	 */
1855	ra = ISC_FALSE;
1856	if (client->view->resolver != NULL &&
1857	    client->view->recursion == ISC_TRUE &&
1858	    ns_client_checkaclsilent(client, NULL,
1859				     client->view->recursionacl,
1860				     ISC_TRUE) == ISC_R_SUCCESS &&
1861	    ns_client_checkaclsilent(client, NULL,
1862				     client->view->queryacl,
1863				     ISC_TRUE) == ISC_R_SUCCESS &&
1864	    ns_client_checkaclsilent(client, &client->interface->addr,
1865				     client->view->recursiononacl,
1866				     ISC_TRUE) == ISC_R_SUCCESS &&
1867	    ns_client_checkaclsilent(client, &client->interface->addr,
1868				     client->view->queryonacl,
1869				     ISC_TRUE) == ISC_R_SUCCESS)
1870		ra = ISC_TRUE;
1871
1872	if (ra == ISC_TRUE)
1873		client->attributes |= NS_CLIENTATTR_RA;
1874
1875	ns_client_log(client, DNS_LOGCATEGORY_SECURITY, NS_LOGMODULE_CLIENT,
1876		      ISC_LOG_DEBUG(3), ra ? "recursion available" :
1877					     "recursion not available");
1878
1879	/*
1880	 * Adjust maximum UDP response size for this client.
1881	 */
1882	if (client->udpsize > 512) {
1883		dns_peer_t *peer = NULL;
1884		isc_uint16_t udpsize = view->maxudp;
1885		(void) dns_peerlist_peerbyaddr(view->peers, &netaddr, &peer);
1886		if (peer != NULL)
1887			dns_peer_getmaxudp(peer, &udpsize);
1888		if (client->udpsize > udpsize)
1889			client->udpsize = udpsize;
1890	}
1891
1892	/*
1893	 * Dispatch the request.
1894	 */
1895	switch (client->message->opcode) {
1896	case dns_opcode_query:
1897		CTRACE("query");
1898		ns_query_start(client);
1899		break;
1900	case dns_opcode_update:
1901		CTRACE("update");
1902		ns_client_settimeout(client, 60);
1903		ns_update_start(client, sigresult);
1904		break;
1905	case dns_opcode_notify:
1906		CTRACE("notify");
1907		ns_client_settimeout(client, 60);
1908		ns_notify_start(client);
1909		break;
1910	case dns_opcode_iquery:
1911		CTRACE("iquery");
1912		ns_client_error(client, DNS_R_NOTIMP);
1913		break;
1914	default:
1915		CTRACE("unknown opcode");
1916		ns_client_error(client, DNS_R_NOTIMP);
1917	}
1918
1919 cleanup:
1920	return;
1921}
1922
1923static void
1924client_timeout(isc_task_t *task, isc_event_t *event) {
1925	ns_client_t *client;
1926
1927	REQUIRE(event != NULL);
1928	REQUIRE(event->ev_type == ISC_TIMEREVENT_LIFE ||
1929		event->ev_type == ISC_TIMEREVENT_IDLE);
1930	client = event->ev_arg;
1931	REQUIRE(NS_CLIENT_VALID(client));
1932	REQUIRE(task == client->task);
1933	REQUIRE(client->timer != NULL);
1934
1935	UNUSED(task);
1936
1937	CTRACE("timeout");
1938
1939	isc_event_free(&event);
1940
1941	if (client->shutdown != NULL) {
1942		(client->shutdown)(client->shutdown_arg, ISC_R_TIMEDOUT);
1943		client->shutdown = NULL;
1944		client->shutdown_arg = NULL;
1945	}
1946
1947	if (client->newstate > NS_CLIENTSTATE_READY)
1948		client->newstate = NS_CLIENTSTATE_READY;
1949	(void)exit_check(client);
1950}
1951
1952static isc_result_t
1953get_clientmctx(ns_clientmgr_t *manager, isc_mem_t **mctxp) {
1954	isc_mem_t *clientmctx;
1955	isc_result_t result;
1956
1957	/*
1958	 * Caller must be holding the manager lock.
1959	 */
1960	if (ns_g_clienttest) {
1961		result = isc_mem_create(0, 0, mctxp);
1962		if (result == ISC_R_SUCCESS)
1963			isc_mem_setname(*mctxp, "client", NULL);
1964		return (result);
1965	}
1966#if NMCTXS > 0
1967	INSIST(manager->nextmctx < NMCTXS);
1968	clientmctx = manager->mctxpool[manager->nextmctx];
1969	if (clientmctx == NULL) {
1970		result = isc_mem_create(0, 0, &clientmctx);
1971		if (result != ISC_R_SUCCESS)
1972			return (result);
1973		isc_mem_setname(clientmctx, "client", NULL);
1974
1975		manager->mctxpool[manager->nextmctx] = clientmctx;
1976	}
1977	manager->nextmctx++;
1978	if (manager->nextmctx == NMCTXS)
1979		manager->nextmctx = 0;
1980#else
1981	clientmctx = manager->mctx;
1982#endif
1983
1984	isc_mem_attach(clientmctx, mctxp);
1985
1986	return (ISC_R_SUCCESS);
1987}
1988
1989static isc_result_t
1990client_create(ns_clientmgr_t *manager, ns_client_t **clientp) {
1991	ns_client_t *client;
1992	isc_result_t result;
1993	isc_mem_t *mctx = NULL;
1994
1995	/*
1996	 * Caller must be holding the manager lock.
1997	 *
1998	 * Note: creating a client does not add the client to the
1999	 * manager's client list or set the client's manager pointer.
2000	 * The caller is responsible for that.
2001	 */
2002
2003	REQUIRE(clientp != NULL && *clientp == NULL);
2004
2005	result = get_clientmctx(manager, &mctx);
2006	if (result != ISC_R_SUCCESS)
2007		return (result);
2008
2009	client = isc_mem_get(mctx, sizeof(*client));
2010	if (client == NULL) {
2011		isc_mem_detach(&mctx);
2012		return (ISC_R_NOMEMORY);
2013	}
2014	client->mctx = mctx;
2015
2016	client->task = NULL;
2017	result = isc_task_create(manager->taskmgr, 0, &client->task);
2018	if (result != ISC_R_SUCCESS)
2019		goto cleanup_client;
2020	isc_task_setname(client->task, "client", client);
2021
2022	client->timer = NULL;
2023	result = isc_timer_create(manager->timermgr, isc_timertype_inactive,
2024				  NULL, NULL, client->task, client_timeout,
2025				  client, &client->timer);
2026	if (result != ISC_R_SUCCESS)
2027		goto cleanup_task;
2028	client->timerset = ISC_FALSE;
2029
2030	client->message = NULL;
2031	result = dns_message_create(client->mctx, DNS_MESSAGE_INTENTPARSE,
2032				    &client->message);
2033	if (result != ISC_R_SUCCESS)
2034		goto cleanup_timer;
2035
2036	/* XXXRTH  Hardwired constants */
2037
2038	client->sendevent = (isc_socketevent_t *)
2039			    isc_event_allocate(client->mctx, client,
2040					       ISC_SOCKEVENT_SENDDONE,
2041					       client_senddone, client,
2042					       sizeof(isc_socketevent_t));
2043	if (client->sendevent == NULL) {
2044		result = ISC_R_NOMEMORY;
2045		goto cleanup_message;
2046	}
2047
2048	client->recvbuf = isc_mem_get(client->mctx, RECV_BUFFER_SIZE);
2049	if  (client->recvbuf == NULL) {
2050		result = ISC_R_NOMEMORY;
2051		goto cleanup_sendevent;
2052	}
2053
2054	client->recvevent = (isc_socketevent_t *)
2055			    isc_event_allocate(client->mctx, client,
2056					       ISC_SOCKEVENT_RECVDONE,
2057					       client_request, client,
2058					       sizeof(isc_socketevent_t));
2059	if (client->recvevent == NULL) {
2060		result = ISC_R_NOMEMORY;
2061		goto cleanup_recvbuf;
2062	}
2063
2064	client->magic = NS_CLIENT_MAGIC;
2065	client->manager = NULL;
2066	client->state = NS_CLIENTSTATE_INACTIVE;
2067	client->newstate = NS_CLIENTSTATE_MAX;
2068	client->naccepts = 0;
2069	client->nreads = 0;
2070	client->nsends = 0;
2071	client->nrecvs = 0;
2072	client->nupdates = 0;
2073	client->nctls = 0;
2074	client->references = 0;
2075	client->attributes = 0;
2076	client->view = NULL;
2077	client->dispatch = NULL;
2078	client->udpsocket = NULL;
2079	client->tcplistener = NULL;
2080	client->tcpsocket = NULL;
2081	client->tcpmsg_valid = ISC_FALSE;
2082	client->tcpbuf = NULL;
2083	client->opt = NULL;
2084	client->udpsize = 512;
2085	client->extflags = 0;
2086	client->ednsversion = -1;
2087	client->next = NULL;
2088	client->shutdown = NULL;
2089	client->shutdown_arg = NULL;
2090	dns_name_init(&client->signername, NULL);
2091	client->mortal = ISC_FALSE;
2092	client->tcpquota = NULL;
2093	client->recursionquota = NULL;
2094	client->interface = NULL;
2095	client->peeraddr_valid = ISC_FALSE;
2096	ISC_EVENT_INIT(&client->ctlevent, sizeof(client->ctlevent), 0, NULL,
2097		       NS_EVENT_CLIENTCONTROL, client_start, client, client,
2098		       NULL, NULL);
2099	/*
2100	 * Initialize FORMERR cache to sentinel value that will not match
2101	 * any actual FORMERR response.
2102	 */
2103	isc_sockaddr_any(&client->formerrcache.addr);
2104	client->formerrcache.time = 0;
2105	client->formerrcache.id = 0;
2106	ISC_LINK_INIT(client, link);
2107	client->list = NULL;
2108
2109	/*
2110	 * We call the init routines for the various kinds of client here,
2111	 * after we have created an otherwise valid client, because some
2112	 * of them call routines that REQUIRE(NS_CLIENT_VALID(client)).
2113	 */
2114	result = ns_query_init(client);
2115	if (result != ISC_R_SUCCESS)
2116		goto cleanup_recvevent;
2117
2118	result = isc_task_onshutdown(client->task, client_shutdown, client);
2119	if (result != ISC_R_SUCCESS)
2120		goto cleanup_query;
2121
2122	client->needshutdown = ns_g_clienttest;
2123
2124	CTRACE("create");
2125
2126	*clientp = client;
2127
2128	return (ISC_R_SUCCESS);
2129
2130 cleanup_query:
2131	ns_query_free(client);
2132
2133 cleanup_recvevent:
2134	isc_event_free((isc_event_t **)&client->recvevent);
2135
2136 cleanup_recvbuf:
2137	isc_mem_put(client->mctx, client->recvbuf, RECV_BUFFER_SIZE);
2138
2139 cleanup_sendevent:
2140	isc_event_free((isc_event_t **)&client->sendevent);
2141
2142	client->magic = 0;
2143
2144 cleanup_message:
2145	dns_message_destroy(&client->message);
2146
2147 cleanup_timer:
2148	isc_timer_detach(&client->timer);
2149
2150 cleanup_task:
2151	isc_task_detach(&client->task);
2152
2153 cleanup_client:
2154	isc_mem_putanddetach(&client->mctx, client, sizeof(*client));
2155
2156	return (result);
2157}
2158
2159static void
2160client_read(ns_client_t *client) {
2161	isc_result_t result;
2162
2163	CTRACE("read");
2164
2165	result = dns_tcpmsg_readmessage(&client->tcpmsg, client->task,
2166					client_request, client);
2167	if (result != ISC_R_SUCCESS)
2168		goto fail;
2169
2170	/*
2171	 * Set a timeout to limit the amount of time we will wait
2172	 * for a request on this TCP connection.
2173	 */
2174	ns_client_settimeout(client, 30);
2175
2176	client->state = client->newstate = NS_CLIENTSTATE_READING;
2177	INSIST(client->nreads == 0);
2178	INSIST(client->recursionquota == NULL);
2179	client->nreads++;
2180
2181	return;
2182 fail:
2183	ns_client_next(client, result);
2184}
2185
2186static void
2187client_newconn(isc_task_t *task, isc_event_t *event) {
2188	ns_client_t *client = event->ev_arg;
2189	isc_socket_newconnev_t *nevent = (isc_socket_newconnev_t *)event;
2190	isc_result_t result;
2191
2192	REQUIRE(event->ev_type == ISC_SOCKEVENT_NEWCONN);
2193	REQUIRE(NS_CLIENT_VALID(client));
2194	REQUIRE(client->task == task);
2195
2196	UNUSED(task);
2197
2198	INSIST(client->state == NS_CLIENTSTATE_READY);
2199
2200	INSIST(client->naccepts == 1);
2201	client->naccepts--;
2202
2203	LOCK(&client->interface->lock);
2204	INSIST(client->interface->ntcpcurrent > 0);
2205	client->interface->ntcpcurrent--;
2206	UNLOCK(&client->interface->lock);
2207
2208	/*
2209	 * We must take ownership of the new socket before the exit
2210	 * check to make sure it gets destroyed if we decide to exit.
2211	 */
2212	if (nevent->result == ISC_R_SUCCESS) {
2213		client->tcpsocket = nevent->newsocket;
2214		isc_socket_setname(client->tcpsocket, "client-tcp", NULL);
2215		client->state = NS_CLIENTSTATE_READING;
2216		INSIST(client->recursionquota == NULL);
2217
2218		(void)isc_socket_getpeername(client->tcpsocket,
2219					     &client->peeraddr);
2220		client->peeraddr_valid = ISC_TRUE;
2221		ns_client_log(client, NS_LOGCATEGORY_CLIENT,
2222			   NS_LOGMODULE_CLIENT, ISC_LOG_DEBUG(3),
2223			   "new TCP connection");
2224	} else {
2225		/*
2226		 * XXXRTH  What should we do?  We're trying to accept but
2227		 *	   it didn't work.  If we just give up, then TCP
2228		 *	   service may eventually stop.
2229		 *
2230		 *	   For now, we just go idle.
2231		 *
2232		 *	   Going idle is probably the right thing if the
2233		 *	   I/O was canceled.
2234		 */
2235		ns_client_log(client, NS_LOGCATEGORY_CLIENT,
2236			      NS_LOGMODULE_CLIENT, ISC_LOG_DEBUG(3),
2237			      "accept failed: %s",
2238			      isc_result_totext(nevent->result));
2239	}
2240
2241	if (exit_check(client))
2242		goto freeevent;
2243
2244	if (nevent->result == ISC_R_SUCCESS) {
2245		int match;
2246		isc_netaddr_t netaddr;
2247
2248		isc_netaddr_fromsockaddr(&netaddr, &client->peeraddr);
2249
2250		if (ns_g_server->blackholeacl != NULL &&
2251		    dns_acl_match(&netaddr, NULL,
2252				  ns_g_server->blackholeacl,
2253				  &ns_g_server->aclenv,
2254				  &match, NULL) == ISC_R_SUCCESS &&
2255		    match > 0)
2256		{
2257			ns_client_log(client, DNS_LOGCATEGORY_SECURITY,
2258				      NS_LOGMODULE_CLIENT, ISC_LOG_DEBUG(10),
2259				      "blackholed connection attempt");
2260			client->newstate = NS_CLIENTSTATE_READY;
2261			(void)exit_check(client);
2262			goto freeevent;
2263		}
2264
2265		INSIST(client->tcpmsg_valid == ISC_FALSE);
2266		dns_tcpmsg_init(client->mctx, client->tcpsocket,
2267				&client->tcpmsg);
2268		client->tcpmsg_valid = ISC_TRUE;
2269
2270		/*
2271		 * Let a new client take our place immediately, before
2272		 * we wait for a request packet.  If we don't,
2273		 * telnetting to port 53 (once per CPU) will
2274		 * deny service to legitimate TCP clients.
2275		 */
2276		result = isc_quota_attach(&ns_g_server->tcpquota,
2277					  &client->tcpquota);
2278		if (result == ISC_R_SUCCESS)
2279			result = ns_client_replace(client);
2280		if (result != ISC_R_SUCCESS) {
2281			ns_client_log(client, NS_LOGCATEGORY_CLIENT,
2282				      NS_LOGMODULE_CLIENT, ISC_LOG_WARNING,
2283				      "no more TCP clients: %s",
2284				      isc_result_totext(result));
2285		}
2286
2287		client_read(client);
2288	}
2289
2290 freeevent:
2291	isc_event_free(&event);
2292}
2293
2294static void
2295client_accept(ns_client_t *client) {
2296	isc_result_t result;
2297
2298	CTRACE("accept");
2299
2300	result = isc_socket_accept(client->tcplistener, client->task,
2301				   client_newconn, client);
2302	if (result != ISC_R_SUCCESS) {
2303		UNEXPECTED_ERROR(__FILE__, __LINE__,
2304				 "isc_socket_accept() failed: %s",
2305				 isc_result_totext(result));
2306		/*
2307		 * XXXRTH  What should we do?  We're trying to accept but
2308		 *	   it didn't work.  If we just give up, then TCP
2309		 *	   service may eventually stop.
2310		 *
2311		 *	   For now, we just go idle.
2312		 */
2313		return;
2314	}
2315	INSIST(client->naccepts == 0);
2316	client->naccepts++;
2317	LOCK(&client->interface->lock);
2318	client->interface->ntcpcurrent++;
2319	UNLOCK(&client->interface->lock);
2320}
2321
2322static void
2323client_udprecv(ns_client_t *client) {
2324	isc_result_t result;
2325	isc_region_t r;
2326
2327	CTRACE("udprecv");
2328
2329	r.base = client->recvbuf;
2330	r.length = RECV_BUFFER_SIZE;
2331	result = isc_socket_recv2(client->udpsocket, &r, 1,
2332				  client->task, client->recvevent, 0);
2333	if (result != ISC_R_SUCCESS) {
2334		UNEXPECTED_ERROR(__FILE__, __LINE__,
2335				 "isc_socket_recv2() failed: %s",
2336				 isc_result_totext(result));
2337		/*
2338		 * This cannot happen in the current implementation, since
2339		 * isc_socket_recv2() cannot fail if flags == 0.
2340		 *
2341		 * If this does fail, we just go idle.
2342		 */
2343		return;
2344	}
2345	INSIST(client->nrecvs == 0);
2346	client->nrecvs++;
2347}
2348
2349void
2350ns_client_attach(ns_client_t *source, ns_client_t **targetp) {
2351	REQUIRE(NS_CLIENT_VALID(source));
2352	REQUIRE(targetp != NULL && *targetp == NULL);
2353
2354	source->references++;
2355	ns_client_log(source, NS_LOGCATEGORY_CLIENT,
2356		      NS_LOGMODULE_CLIENT, ISC_LOG_DEBUG(10),
2357		      "ns_client_attach: ref = %d", source->references);
2358	*targetp = source;
2359}
2360
2361void
2362ns_client_detach(ns_client_t **clientp) {
2363	ns_client_t *client = *clientp;
2364
2365	client->references--;
2366	INSIST(client->references >= 0);
2367	*clientp = NULL;
2368	ns_client_log(client, NS_LOGCATEGORY_CLIENT,
2369		      NS_LOGMODULE_CLIENT, ISC_LOG_DEBUG(10),
2370		      "ns_client_detach: ref = %d", client->references);
2371	(void)exit_check(client);
2372}
2373
2374isc_boolean_t
2375ns_client_shuttingdown(ns_client_t *client) {
2376	return (ISC_TF(client->newstate == NS_CLIENTSTATE_FREED));
2377}
2378
2379isc_result_t
2380ns_client_replace(ns_client_t *client) {
2381	isc_result_t result;
2382
2383	CTRACE("replace");
2384
2385	result = ns_clientmgr_createclients(client->manager,
2386					    1, client->interface,
2387					    (TCP_CLIENT(client) ?
2388					     ISC_TRUE : ISC_FALSE));
2389	if (result != ISC_R_SUCCESS)
2390		return (result);
2391
2392	/*
2393	 * The responsibility for listening for new requests is hereby
2394	 * transferred to the new client.  Therefore, the old client
2395	 * should refrain from listening for any more requests.
2396	 */
2397	client->mortal = ISC_TRUE;
2398
2399	return (ISC_R_SUCCESS);
2400}
2401
2402/***
2403 *** Client Manager
2404 ***/
2405
2406static void
2407clientmgr_destroy(ns_clientmgr_t *manager) {
2408#if NMCTXS > 0
2409	int i;
2410#endif
2411
2412	REQUIRE(ISC_LIST_EMPTY(manager->active));
2413	REQUIRE(ISC_LIST_EMPTY(manager->inactive));
2414	REQUIRE(ISC_LIST_EMPTY(manager->recursing));
2415
2416	MTRACE("clientmgr_destroy");
2417
2418#if NMCTXS > 0
2419	for (i = 0; i < NMCTXS; i++) {
2420		if (manager->mctxpool[i] != NULL)
2421			isc_mem_detach(&manager->mctxpool[i]);
2422	}
2423#endif
2424
2425	DESTROYLOCK(&manager->lock);
2426	manager->magic = 0;
2427	isc_mem_put(manager->mctx, manager, sizeof(*manager));
2428}
2429
2430isc_result_t
2431ns_clientmgr_create(isc_mem_t *mctx, isc_taskmgr_t *taskmgr,
2432		    isc_timermgr_t *timermgr, ns_clientmgr_t **managerp)
2433{
2434	ns_clientmgr_t *manager;
2435	isc_result_t result;
2436#if NMCTXS > 0
2437	int i;
2438#endif
2439
2440	manager = isc_mem_get(mctx, sizeof(*manager));
2441	if (manager == NULL)
2442		return (ISC_R_NOMEMORY);
2443
2444	result = isc_mutex_init(&manager->lock);
2445	if (result != ISC_R_SUCCESS)
2446		goto cleanup_manager;
2447
2448	manager->mctx = mctx;
2449	manager->taskmgr = taskmgr;
2450	manager->timermgr = timermgr;
2451	manager->exiting = ISC_FALSE;
2452	ISC_LIST_INIT(manager->active);
2453	ISC_LIST_INIT(manager->inactive);
2454	ISC_LIST_INIT(manager->recursing);
2455#if NMCTXS > 0
2456	manager->nextmctx = 0;
2457	for (i = 0; i < NMCTXS; i++)
2458		manager->mctxpool[i] = NULL; /* will be created on-demand */
2459#endif
2460	manager->magic = MANAGER_MAGIC;
2461
2462	MTRACE("create");
2463
2464	*managerp = manager;
2465
2466	return (ISC_R_SUCCESS);
2467
2468 cleanup_manager:
2469	isc_mem_put(manager->mctx, manager, sizeof(*manager));
2470
2471	return (result);
2472}
2473
2474void
2475ns_clientmgr_destroy(ns_clientmgr_t **managerp) {
2476	ns_clientmgr_t *manager;
2477	ns_client_t *client;
2478	isc_boolean_t need_destroy = ISC_FALSE;
2479
2480	REQUIRE(managerp != NULL);
2481	manager = *managerp;
2482	REQUIRE(VALID_MANAGER(manager));
2483
2484	MTRACE("destroy");
2485
2486	LOCK(&manager->lock);
2487
2488	manager->exiting = ISC_TRUE;
2489
2490	for (client = ISC_LIST_HEAD(manager->recursing);
2491	     client != NULL;
2492	     client = ISC_LIST_NEXT(client, link))
2493		isc_task_shutdown(client->task);
2494
2495	for (client = ISC_LIST_HEAD(manager->active);
2496	     client != NULL;
2497	     client = ISC_LIST_NEXT(client, link))
2498		isc_task_shutdown(client->task);
2499
2500	for (client = ISC_LIST_HEAD(manager->inactive);
2501	     client != NULL;
2502	     client = ISC_LIST_NEXT(client, link))
2503		isc_task_shutdown(client->task);
2504
2505	if (ISC_LIST_EMPTY(manager->active) &&
2506	    ISC_LIST_EMPTY(manager->inactive) &&
2507	    ISC_LIST_EMPTY(manager->recursing))
2508		need_destroy = ISC_TRUE;
2509
2510	UNLOCK(&manager->lock);
2511
2512	if (need_destroy)
2513		clientmgr_destroy(manager);
2514
2515	*managerp = NULL;
2516}
2517
2518isc_result_t
2519ns_clientmgr_createclients(ns_clientmgr_t *manager, unsigned int n,
2520			   ns_interface_t *ifp, isc_boolean_t tcp)
2521{
2522	isc_result_t result = ISC_R_SUCCESS;
2523	unsigned int i;
2524	ns_client_t *client;
2525
2526	REQUIRE(VALID_MANAGER(manager));
2527	REQUIRE(n > 0);
2528
2529	MTRACE("createclients");
2530
2531	/*
2532	 * We MUST lock the manager lock for the entire client creation
2533	 * process.  If we didn't do this, then a client could get a
2534	 * shutdown event and disappear out from under us.
2535	 */
2536
2537	LOCK(&manager->lock);
2538
2539	for (i = 0; i < n; i++) {
2540		isc_event_t *ev;
2541		/*
2542		 * Allocate a client.  First try to get a recycled one;
2543		 * if that fails, make a new one.
2544		 */
2545		client = NULL;
2546		if (!ns_g_clienttest)
2547			client = ISC_LIST_HEAD(manager->inactive);
2548		if (client != NULL) {
2549			MTRACE("recycle");
2550			ISC_LIST_UNLINK(manager->inactive, client, link);
2551			client->list = NULL;
2552		} else {
2553			MTRACE("create new");
2554			result = client_create(manager, &client);
2555			if (result != ISC_R_SUCCESS)
2556				break;
2557		}
2558
2559		ns_interface_attach(ifp, &client->interface);
2560		client->state = NS_CLIENTSTATE_READY;
2561		INSIST(client->recursionquota == NULL);
2562
2563		if (tcp) {
2564			client->attributes |= NS_CLIENTATTR_TCP;
2565			isc_socket_attach(ifp->tcpsocket,
2566					  &client->tcplistener);
2567		} else {
2568			isc_socket_t *sock;
2569
2570			dns_dispatch_attach(ifp->udpdispatch,
2571					    &client->dispatch);
2572			sock = dns_dispatch_getsocket(client->dispatch);
2573			isc_socket_attach(sock, &client->udpsocket);
2574		}
2575		client->manager = manager;
2576		ISC_LIST_APPEND(manager->active, client, link);
2577		client->list = &manager->active;
2578
2579		INSIST(client->nctls == 0);
2580		client->nctls++;
2581		ev = &client->ctlevent;
2582		isc_task_send(client->task, &ev);
2583	}
2584	if (i != 0) {
2585		/*
2586		 * We managed to create at least one client, so we
2587		 * declare victory.
2588		 */
2589		result = ISC_R_SUCCESS;
2590	}
2591
2592	UNLOCK(&manager->lock);
2593
2594	return (result);
2595}
2596
2597isc_sockaddr_t *
2598ns_client_getsockaddr(ns_client_t *client) {
2599	return (&client->peeraddr);
2600}
2601
2602isc_result_t
2603ns_client_checkaclsilent(ns_client_t *client, isc_sockaddr_t *sockaddr,
2604			 dns_acl_t *acl, isc_boolean_t default_allow)
2605{
2606	isc_result_t result;
2607	int match;
2608	isc_netaddr_t netaddr;
2609
2610	if (acl == NULL) {
2611		if (default_allow)
2612			goto allow;
2613		else
2614			goto deny;
2615	}
2616
2617
2618	if (sockaddr == NULL)
2619		isc_netaddr_fromsockaddr(&netaddr, &client->peeraddr);
2620	else
2621		isc_netaddr_fromsockaddr(&netaddr, sockaddr);
2622
2623	result = dns_acl_match(&netaddr, client->signer, acl,
2624			       &ns_g_server->aclenv,
2625			       &match, NULL);
2626
2627	if (result != ISC_R_SUCCESS)
2628		goto deny; /* Internal error, already logged. */
2629	if (match > 0)
2630		goto allow;
2631	goto deny; /* Negative match or no match. */
2632
2633 allow:
2634	return (ISC_R_SUCCESS);
2635
2636 deny:
2637	return (DNS_R_REFUSED);
2638}
2639
2640isc_result_t
2641ns_client_checkacl(ns_client_t *client, isc_sockaddr_t *sockaddr,
2642		   const char *opname, dns_acl_t *acl,
2643		   isc_boolean_t default_allow, int log_level)
2644{
2645	isc_result_t result =
2646		ns_client_checkaclsilent(client, sockaddr, acl, default_allow);
2647
2648	if (result == ISC_R_SUCCESS)
2649		ns_client_log(client, DNS_LOGCATEGORY_SECURITY,
2650			      NS_LOGMODULE_CLIENT, ISC_LOG_DEBUG(3),
2651			      "%s approved", opname);
2652	else
2653		ns_client_log(client, DNS_LOGCATEGORY_SECURITY,
2654			      NS_LOGMODULE_CLIENT,
2655			      log_level, "%s denied", opname);
2656	return (result);
2657}
2658
2659static void
2660ns_client_name(ns_client_t *client, char *peerbuf, size_t len) {
2661	if (client->peeraddr_valid)
2662		isc_sockaddr_format(&client->peeraddr, peerbuf, len);
2663	else
2664		snprintf(peerbuf, len, "@%p", client);
2665}
2666
2667void
2668ns_client_logv(ns_client_t *client, isc_logcategory_t *category,
2669	       isc_logmodule_t *module, int level, const char *fmt, va_list ap)
2670{
2671	char msgbuf[2048];
2672	char peerbuf[ISC_SOCKADDR_FORMATSIZE];
2673	const char *name = "";
2674	const char *sep = "";
2675
2676	vsnprintf(msgbuf, sizeof(msgbuf), fmt, ap);
2677	ns_client_name(client, peerbuf, sizeof(peerbuf));
2678	if (client->view != NULL && strcmp(client->view->name, "_bind") != 0 &&
2679	    strcmp(client->view->name, "_default") != 0) {
2680		name = client->view->name;
2681		sep = ": view ";
2682	}
2683
2684	isc_log_write(ns_g_lctx, category, module, level,
2685		      "client %s%s%s: %s", peerbuf, sep, name, msgbuf);
2686}
2687
2688void
2689ns_client_log(ns_client_t *client, isc_logcategory_t *category,
2690	   isc_logmodule_t *module, int level, const char *fmt, ...)
2691{
2692	va_list ap;
2693
2694	if (! isc_log_wouldlog(ns_g_lctx, level))
2695		return;
2696
2697	va_start(ap, fmt);
2698	ns_client_logv(client, category, module, level, fmt, ap);
2699	va_end(ap);
2700}
2701
2702void
2703ns_client_aclmsg(const char *msg, dns_name_t *name, dns_rdatatype_t type,
2704		 dns_rdataclass_t rdclass, char *buf, size_t len)
2705{
2706	char namebuf[DNS_NAME_FORMATSIZE];
2707	char typebuf[DNS_RDATATYPE_FORMATSIZE];
2708	char classbuf[DNS_RDATACLASS_FORMATSIZE];
2709
2710	dns_name_format(name, namebuf, sizeof(namebuf));
2711	dns_rdatatype_format(type, typebuf, sizeof(typebuf));
2712	dns_rdataclass_format(rdclass, classbuf, sizeof(classbuf));
2713	(void)snprintf(buf, len, "%s '%s/%s/%s'", msg, namebuf, typebuf,
2714		       classbuf);
2715}
2716
2717static void
2718ns_client_dumpmessage(ns_client_t *client, const char *reason) {
2719	isc_buffer_t buffer;
2720	char *buf = NULL;
2721	int len = 1024;
2722	isc_result_t result;
2723
2724	/*
2725	 * Note that these are multiline debug messages.  We want a newline
2726	 * to appear in the log after each message.
2727	 */
2728
2729	do {
2730		buf = isc_mem_get(client->mctx, len);
2731		if (buf == NULL)
2732			break;
2733		isc_buffer_init(&buffer, buf, len);
2734		result = dns_message_totext(client->message,
2735					    &dns_master_style_debug,
2736					    0, &buffer);
2737		if (result == ISC_R_NOSPACE) {
2738			isc_mem_put(client->mctx, buf, len);
2739			len += 1024;
2740		} else if (result == ISC_R_SUCCESS)
2741			ns_client_log(client, NS_LOGCATEGORY_UNMATCHED,
2742				      NS_LOGMODULE_CLIENT, ISC_LOG_DEBUG(1),
2743				      "%s\n%.*s", reason,
2744				       (int)isc_buffer_usedlength(&buffer),
2745				       buf);
2746	} while (result == ISC_R_NOSPACE);
2747
2748	if (buf != NULL)
2749		isc_mem_put(client->mctx, buf, len);
2750}
2751
2752void
2753ns_client_dumprecursing(FILE *f, ns_clientmgr_t *manager) {
2754	ns_client_t *client;
2755	char namebuf[DNS_NAME_FORMATSIZE];
2756	char peerbuf[ISC_SOCKADDR_FORMATSIZE];
2757	const char *name;
2758	const char *sep;
2759
2760	REQUIRE(VALID_MANAGER(manager));
2761
2762	LOCK(&manager->lock);
2763	client = ISC_LIST_HEAD(manager->recursing);
2764	while (client != NULL) {
2765		ns_client_name(client, peerbuf, sizeof(peerbuf));
2766		if (client->view != NULL &&
2767		    strcmp(client->view->name, "_bind") != 0 &&
2768		    strcmp(client->view->name, "_default") != 0) {
2769			name = client->view->name;
2770			sep = ": view ";
2771		} else {
2772			name = "";
2773			sep = "";
2774		}
2775		dns_name_format(client->query.qname, namebuf, sizeof(namebuf));
2776		fprintf(f, "; client %s%s%s: '%s' requesttime %d\n",
2777			peerbuf, sep, name, namebuf, client->requesttime);
2778		client = ISC_LIST_NEXT(client, link);
2779	}
2780	UNLOCK(&manager->lock);
2781}
2782
2783void
2784ns_client_qnamereplace(ns_client_t *client, dns_name_t *name) {
2785
2786	if (client->manager != NULL)
2787		LOCK(&client->manager->lock);
2788	if (client->query.restarts > 0) {
2789		/*
2790		 * client->query.qname was dynamically allocated.
2791		 */
2792		dns_message_puttempname(client->message,
2793					&client->query.qname);
2794	}
2795	client->query.qname = name;
2796	if (client->manager != NULL)
2797		UNLOCK(&client->manager->lock);
2798}
2799