Add BIND 9.2.4rc7.
[dragonfly.git] / contrib / bind-9.2.4rc7 / bin / named / client.c
blob4074fbd0e3f2457511d94962e56a3ba50adad695
1 /*
2 * Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC")
3 * Copyright (C) 1999-2003 Internet Software Consortium.
5 * Permission to use, copy, modify, and 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.
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.
18 /* $Id: client.c,v 1.176.2.16 2004/07/23 02:56:59 marka Exp $ */
20 #include <config.h>
22 #include <isc/formatcheck.h>
23 #include <isc/mutex.h>
24 #include <isc/once.h>
25 #include <isc/print.h>
26 #include <isc/stdio.h>
27 #include <isc/string.h>
28 #include <isc/task.h>
29 #include <isc/timer.h>
30 #include <isc/util.h>
32 #include <dns/db.h>
33 #include <dns/dispatch.h>
34 #include <dns/events.h>
35 #include <dns/message.h>
36 #include <dns/rdata.h>
37 #include <dns/rdataclass.h>
38 #include <dns/rdatalist.h>
39 #include <dns/rdataset.h>
40 #include <dns/tsig.h>
41 #include <dns/view.h>
42 #include <dns/zone.h>
44 #include <named/interfacemgr.h>
45 #include <named/log.h>
46 #include <named/notify.h>
47 #include <named/server.h>
48 #include <named/update.h>
50 /***
51 *** Client
52 ***/
55 * Important note!
57 * All client state changes, other than that from idle to listening, occur
58 * as a result of events. This guarantees serialization and avoids the
59 * need for locking.
61 * If a routine is ever created that allows someone other than the client's
62 * task to change the client, then the client will have to be locked.
65 #define NS_CLIENT_TRACE
66 #ifdef NS_CLIENT_TRACE
67 #define CTRACE(m) ns_client_log(client, \
68 NS_LOGCATEGORY_CLIENT, \
69 NS_LOGMODULE_CLIENT, \
70 ISC_LOG_DEBUG(3), \
71 "%s", (m))
72 #define MTRACE(m) isc_log_write(ns_g_lctx, \
73 NS_LOGCATEGORY_GENERAL, \
74 NS_LOGMODULE_CLIENT, \
75 ISC_LOG_DEBUG(3), \
76 "clientmgr @%p: %s", manager, (m))
77 #else
78 #define CTRACE(m) ((void)(m))
79 #define MTRACE(m) ((void)(m))
80 #endif
82 #define TCP_CLIENT(c) (((c)->attributes & NS_CLIENTATTR_TCP) != 0)
84 #define TCP_BUFFER_SIZE (65535 + 2)
85 #define SEND_BUFFER_SIZE 4096
86 #define RECV_BUFFER_SIZE 4096
88 struct ns_clientmgr {
89 /* Unlocked. */
90 unsigned int magic;
91 isc_mem_t * mctx;
92 isc_taskmgr_t * taskmgr;
93 isc_timermgr_t * timermgr;
94 isc_mutex_t lock;
95 /* Locked by lock. */
96 isc_boolean_t exiting;
97 client_list_t active; /* Active clients */
98 client_list_t inactive; /* To be recycled */
101 #define MANAGER_MAGIC ISC_MAGIC('N', 'S', 'C', 'm')
102 #define VALID_MANAGER(m) ISC_MAGIC_VALID(m, MANAGER_MAGIC)
105 * Client object states. Ordering is significant: higher-numbered
106 * states are generally "more active", meaning that the client can
107 * have more dynamically allocated data, outstanding events, etc.
108 * In the list below, any such properties listed for state N
109 * also apply to any state > N.
111 * To force the client into a less active state, set client->newstate
112 * to that state and call exit_check(). This will cause any
113 * activities defined for higher-numbered states to be aborted.
116 #define NS_CLIENTSTATE_FREED 0
118 * The client object no longer exists.
121 #define NS_CLIENTSTATE_INACTIVE 1
123 * The client object exists and has a task and timer.
124 * Its "query" struct and sendbuf are initialized.
125 * It is on the client manager's list of inactive clients.
126 * It has a message and OPT, both in the reset state.
129 #define NS_CLIENTSTATE_READY 2
131 * The client object is either a TCP or a UDP one, and
132 * it is associated with a network interface. It is on the
133 * client manager's list of active clients.
135 * If it is a TCP client object, it has a TCP listener socket
136 * and an outstanding TCP listen request.
138 * If it is a UDP client object, it has a UDP listener socket
139 * and an outstanding UDP receive request.
142 #define NS_CLIENTSTATE_READING 3
144 * The client object is a TCP client object that has received
145 * a connection. It has a tcpsocket, tcpmsg, TCP quota, and an
146 * outstanding TCP read request. This state is not used for
147 * UDP client objects.
150 #define NS_CLIENTSTATE_WORKING 4
152 * The client object has received a request and is working
153 * on it. It has a view, and it may have any of a non-reset OPT,
154 * recursion quota, and an outstanding write request.
157 #define NS_CLIENTSTATE_MAX 9
159 * Sentinel value used to indicate "no state". When client->newstate
160 * has this value, we are not attempting to exit the current state.
161 * Must be greater than any valid state.
165 static void client_read(ns_client_t *client);
166 static void client_accept(ns_client_t *client);
167 static void client_udprecv(ns_client_t *client);
168 static void clientmgr_destroy(ns_clientmgr_t *manager);
169 static isc_boolean_t exit_check(ns_client_t *client);
170 static void ns_client_endrequest(ns_client_t *client);
171 static void ns_client_checkactive(ns_client_t *client);
172 static void client_start(isc_task_t *task, isc_event_t *event);
173 static void client_request(isc_task_t *task, isc_event_t *event);
174 static void ns_client_dumpmessage(ns_client_t *client, const char *reason);
176 void
177 ns_client_settimeout(ns_client_t *client, unsigned int seconds) {
178 isc_result_t result;
179 isc_interval_t interval;
181 isc_interval_set(&interval, seconds, 0);
182 result = isc_timer_reset(client->timer, isc_timertype_once, NULL,
183 &interval, ISC_FALSE);
184 client->timerset = ISC_TRUE;
185 if (result != ISC_R_SUCCESS) {
186 ns_client_log(client, NS_LOGCATEGORY_CLIENT,
187 NS_LOGMODULE_CLIENT, ISC_LOG_ERROR,
188 "setting timeout: %s",
189 isc_result_totext(result));
190 /* Continue anyway. */
195 * Check for a deactivation or shutdown request and take appropriate
196 * action. Returns ISC_TRUE if either is in progress; in this case
197 * the caller must no longer use the client object as it may have been
198 * freed.
200 static isc_boolean_t
201 exit_check(ns_client_t *client) {
202 ns_clientmgr_t *locked_manager = NULL;
203 ns_clientmgr_t *destroy_manager = NULL;
205 REQUIRE(NS_CLIENT_VALID(client));
207 if (client->state <= client->newstate)
208 return (ISC_FALSE); /* Business as usual. */
210 INSIST(client->newstate < NS_CLIENTSTATE_WORKING);
213 * We need to detach from the view early when shutting down
214 * the server to break the following vicious circle:
216 * - The resolver will not shut down until the view refcount is zero
217 * - The view refcount does not go to zero until all clients detach
218 * - The client does not detach from the view until references is zero
219 * - references does not go to zero until the resolver has shut down
221 * Keep the view attached until any outstanding updates complete.
223 if (client->nupdates == 0 &&
224 client->newstate == NS_CLIENTSTATE_FREED && client->view != NULL)
225 dns_view_detach(&client->view);
227 if (client->state == NS_CLIENTSTATE_WORKING) {
228 INSIST(client->newstate <= NS_CLIENTSTATE_READING);
230 * Let the update processing complete.
232 if (client->nupdates > 0)
233 return (ISC_TRUE);
235 * We are trying to abort request processing.
237 if (client->nsends > 0) {
238 isc_socket_t *socket;
239 if (TCP_CLIENT(client))
240 socket = client->tcpsocket;
241 else
242 socket = client->udpsocket;
243 isc_socket_cancel(socket, client->task,
244 ISC_SOCKCANCEL_SEND);
247 if (! (client->nsends == 0 && client->nrecvs == 0 &&
248 client->references == 0))
251 * Still waiting for I/O cancel completion.
252 * or lingering references.
254 return (ISC_TRUE);
257 * I/O cancel is complete. Burn down all state
258 * related to the current request.
260 ns_client_endrequest(client);
262 client->state = NS_CLIENTSTATE_READING;
263 INSIST(client->recursionquota == NULL);
264 if (NS_CLIENTSTATE_READING == client->newstate) {
265 client_read(client);
266 client->newstate = NS_CLIENTSTATE_MAX;
267 return (ISC_TRUE); /* We're done. */
271 if (client->state == NS_CLIENTSTATE_READING) {
273 * We are trying to abort the current TCP connection,
274 * if any.
276 INSIST(client->recursionquota == NULL);
277 INSIST(client->newstate <= NS_CLIENTSTATE_READY);
278 if (client->nreads > 0)
279 dns_tcpmsg_cancelread(&client->tcpmsg);
280 if (! client->nreads == 0) {
281 /* Still waiting for read cancel completion. */
282 return (ISC_TRUE);
285 if (client->tcpmsg_valid) {
286 dns_tcpmsg_invalidate(&client->tcpmsg);
287 client->tcpmsg_valid = ISC_FALSE;
289 if (client->tcpsocket != NULL) {
290 CTRACE("closetcp");
291 isc_socket_detach(&client->tcpsocket);
294 if (client->tcpquota != NULL)
295 isc_quota_detach(&client->tcpquota);
297 if (client->timerset) {
298 (void) isc_timer_reset(client->timer,
299 isc_timertype_inactive,
300 NULL, NULL, ISC_TRUE);
301 client->timerset = ISC_FALSE;
304 client->peeraddr_valid = ISC_FALSE;
306 client->state = NS_CLIENTSTATE_READY;
307 INSIST(client->recursionquota == NULL);
310 * Now the client is ready to accept a new TCP connection
311 * or UDP request, but we may have enough clients doing
312 * that already. Check whether this client needs to remain
313 * active and force it to go inactive if not.
315 ns_client_checkactive(client);
317 if (NS_CLIENTSTATE_READY == client->newstate) {
318 if (TCP_CLIENT(client)) {
319 client_accept(client);
320 } else
321 client_udprecv(client);
322 client->newstate = NS_CLIENTSTATE_MAX;
323 return (ISC_TRUE);
327 if (client->state == NS_CLIENTSTATE_READY) {
328 INSIST(client->newstate <= NS_CLIENTSTATE_INACTIVE);
330 * We are trying to enter the inactive state.
332 if (client->naccepts > 0)
333 isc_socket_cancel(client->tcplistener, client->task,
334 ISC_SOCKCANCEL_ACCEPT);
336 if (! (client->naccepts == 0)) {
337 /* Still waiting for accept cancel completion. */
338 return (ISC_TRUE);
340 /* Accept cancel is complete. */
342 if (client->nrecvs > 0)
343 isc_socket_cancel(client->udpsocket, client->task,
344 ISC_SOCKCANCEL_RECV);
345 if (! (client->nrecvs == 0)) {
346 /* Still waiting for recv cancel completion. */
347 return (ISC_TRUE);
349 /* Recv cancel is complete. */
351 if (client->nctls > 0) {
352 /* Still waiting for control event to be delivered */
353 return (ISC_TRUE);
356 /* Deactivate the client. */
357 if (client->interface)
358 ns_interface_detach(&client->interface);
360 INSIST(client->naccepts == 0);
361 INSIST(client->recursionquota == NULL);
362 if (client->tcplistener != NULL)
363 isc_socket_detach(&client->tcplistener);
365 if (client->udpsocket != NULL)
366 isc_socket_detach(&client->udpsocket);
368 if (client->dispatch != NULL)
369 dns_dispatch_detach(&client->dispatch);
371 client->attributes = 0;
372 client->mortal = ISC_FALSE;
374 LOCK(&client->manager->lock);
376 * Put the client on the inactive list. If we are aiming for
377 * the "freed" state, it will be removed from the inactive
378 * list shortly, and we need to keep the manager locked until
379 * that has been done, lest the manager decide to reactivate
380 * the dying client inbetween.
382 locked_manager = client->manager;
383 ISC_LIST_UNLINK(*client->list, client, link);
384 ISC_LIST_APPEND(client->manager->inactive, client, link);
385 client->list = &client->manager->inactive;
386 client->state = NS_CLIENTSTATE_INACTIVE;
387 INSIST(client->recursionquota == NULL);
389 if (client->state == client->newstate) {
390 client->newstate = NS_CLIENTSTATE_MAX;
391 goto unlock;
395 if (client->state == NS_CLIENTSTATE_INACTIVE) {
396 INSIST(client->newstate == NS_CLIENTSTATE_FREED);
398 * We are trying to free the client.
400 * When "shuttingdown" is true, either the task has received
401 * its shutdown event or no shutdown event has ever been
402 * set up. Thus, we have no outstanding shutdown
403 * event at this point.
405 REQUIRE(client->state == NS_CLIENTSTATE_INACTIVE);
407 INSIST(client->recursionquota == NULL);
409 ns_query_free(client);
410 isc_mem_put(client->mctx, client->recvbuf, RECV_BUFFER_SIZE);
411 isc_event_free((isc_event_t **)&client->sendevent);
412 isc_event_free((isc_event_t **)&client->recvevent);
413 isc_timer_detach(&client->timer);
415 if (client->tcpbuf != NULL)
416 isc_mem_put(client->mctx, client->tcpbuf, TCP_BUFFER_SIZE);
417 if (client->opt != NULL) {
418 INSIST(dns_rdataset_isassociated(client->opt));
419 dns_rdataset_disassociate(client->opt);
420 dns_message_puttemprdataset(client->message, &client->opt);
422 dns_message_destroy(&client->message);
423 if (client->manager != NULL) {
424 ns_clientmgr_t *manager = client->manager;
425 if (locked_manager == NULL) {
426 LOCK(&manager->lock);
427 locked_manager = manager;
429 ISC_LIST_UNLINK(*client->list, client, link);
430 client->list = NULL;
431 if (manager->exiting &&
432 ISC_LIST_EMPTY(manager->active) &&
433 ISC_LIST_EMPTY(manager->inactive))
434 destroy_manager = manager;
437 * Detaching the task must be done after unlinking from
438 * the manager's lists because the manager accesses
439 * client->task.
441 if (client->task != NULL)
442 isc_task_detach(&client->task);
444 CTRACE("free");
445 client->magic = 0;
446 isc_mem_put(client->mctx, client, sizeof(*client));
448 goto unlock;
451 unlock:
452 if (locked_manager != NULL) {
453 UNLOCK(&locked_manager->lock);
454 locked_manager = NULL;
458 * Only now is it safe to destroy the client manager (if needed),
459 * because we have accessed its lock for the last time.
461 if (destroy_manager != NULL)
462 clientmgr_destroy(destroy_manager);
464 return (ISC_TRUE);
468 * The client's task has received the client's control event
469 * as part of the startup process.
471 static void
472 client_start(isc_task_t *task, isc_event_t *event) {
473 ns_client_t *client = (ns_client_t *) event->ev_arg;
475 INSIST(task == client->task);
477 UNUSED(task);
479 INSIST(client->nctls == 1);
480 client->nctls--;
482 if (exit_check(client))
483 return;
485 if (TCP_CLIENT(client)) {
486 client_accept(client);
487 } else {
488 client_udprecv(client);
494 * The client's task has received a shutdown event.
496 static void
497 client_shutdown(isc_task_t *task, isc_event_t *event) {
498 ns_client_t *client;
500 REQUIRE(event != NULL);
501 REQUIRE(event->ev_type == ISC_TASKEVENT_SHUTDOWN);
502 client = event->ev_arg;
503 REQUIRE(NS_CLIENT_VALID(client));
504 REQUIRE(task == client->task);
506 UNUSED(task);
508 CTRACE("shutdown");
510 isc_event_free(&event);
512 if (client->shutdown != NULL) {
513 (client->shutdown)(client->shutdown_arg, ISC_R_SHUTTINGDOWN);
514 client->shutdown = NULL;
515 client->shutdown_arg = NULL;
518 client->newstate = NS_CLIENTSTATE_FREED;
519 (void)exit_check(client);
523 static void
524 ns_client_endrequest(ns_client_t *client) {
525 INSIST(client->naccepts == 0);
526 INSIST(client->nreads == 0);
527 INSIST(client->nsends == 0);
528 INSIST(client->nrecvs == 0);
529 INSIST(client->nupdates == 0);
530 INSIST(client->state == NS_CLIENTSTATE_WORKING);
532 CTRACE("endrequest");
534 if (client->next != NULL) {
535 (client->next)(client);
536 client->next = NULL;
539 if (client->view != NULL)
540 dns_view_detach(&client->view);
541 if (client->opt != NULL) {
542 INSIST(dns_rdataset_isassociated(client->opt));
543 dns_rdataset_disassociate(client->opt);
544 dns_message_puttemprdataset(client->message, &client->opt);
547 client->udpsize = 512;
548 client->extflags = 0;
549 dns_message_reset(client->message, DNS_MESSAGE_INTENTPARSE);
551 if (client->recursionquota != NULL)
552 isc_quota_detach(&client->recursionquota);
555 * Clear all client attributes that are specific to
556 * the request; that's all except the TCP flag.
558 client->attributes &= NS_CLIENTATTR_TCP;
561 static void
562 ns_client_checkactive(ns_client_t *client) {
563 if (client->mortal) {
565 * This client object should normally go inactive
566 * at this point, but if we have fewer active client
567 * objects than desired due to earlier quota exhaustion,
568 * keep it active to make up for the shortage.
570 isc_boolean_t need_another_client = ISC_FALSE;
571 if (TCP_CLIENT(client)) {
572 LOCK(&client->interface->lock);
573 if (client->interface->ntcpcurrent <
574 client->interface->ntcptarget)
575 need_another_client = ISC_TRUE;
576 UNLOCK(&client->interface->lock);
577 } else {
579 * The UDP client quota is enforced by making
580 * requests fail rather than by not listening
581 * for new ones. Therefore, there is always a
582 * full set of UDP clients listening.
585 if (! need_another_client) {
587 * We don't need this client object. Recycle it.
589 if (client->newstate >= NS_CLIENTSTATE_INACTIVE)
590 client->newstate = NS_CLIENTSTATE_INACTIVE;
595 void
596 ns_client_next(ns_client_t *client, isc_result_t result) {
597 int newstate;
599 REQUIRE(NS_CLIENT_VALID(client));
600 REQUIRE(client->state == NS_CLIENTSTATE_WORKING ||
601 client->state == NS_CLIENTSTATE_READING);
603 CTRACE("next");
605 if (result != ISC_R_SUCCESS)
606 ns_client_log(client, DNS_LOGCATEGORY_SECURITY,
607 NS_LOGMODULE_CLIENT, ISC_LOG_DEBUG(3),
608 "request failed: %s", isc_result_totext(result));
611 * An error processing a TCP request may have left
612 * the connection out of sync. To be safe, we always
613 * sever the connection when result != ISC_R_SUCCESS.
615 if (result == ISC_R_SUCCESS && TCP_CLIENT(client))
616 newstate = NS_CLIENTSTATE_READING;
617 else
618 newstate = NS_CLIENTSTATE_READY;
620 if (client->newstate > newstate)
621 client->newstate = newstate;
622 (void) exit_check(client);
626 static void
627 client_senddone(isc_task_t *task, isc_event_t *event) {
628 ns_client_t *client;
629 isc_socketevent_t *sevent = (isc_socketevent_t *) event;
631 REQUIRE(sevent != NULL);
632 REQUIRE(sevent->ev_type == ISC_SOCKEVENT_SENDDONE);
633 client = sevent->ev_arg;
634 REQUIRE(NS_CLIENT_VALID(client));
635 REQUIRE(task == client->task);
636 REQUIRE(sevent == client->sendevent);
638 UNUSED(task);
640 CTRACE("senddone");
642 if (sevent->result != ISC_R_SUCCESS)
643 ns_client_log(client, NS_LOGCATEGORY_CLIENT,
644 NS_LOGMODULE_CLIENT, ISC_LOG_WARNING,
645 "error sending response: %s",
646 isc_result_totext(sevent->result));
648 INSIST(client->nsends > 0);
649 client->nsends--;
651 if (client->tcpbuf != NULL) {
652 INSIST(TCP_CLIENT(client));
653 isc_mem_put(client->mctx, client->tcpbuf, TCP_BUFFER_SIZE);
654 client->tcpbuf = NULL;
657 if (exit_check(client))
658 return;
660 ns_client_next(client, ISC_R_SUCCESS);
664 * We only want to fail with ISC_R_NOSPACE when called from
665 * ns_client_sendraw() and not when called from ns_client_send(),
666 * tcpbuffer is NULL when called from ns_client_sendraw() and
667 * length != 0. tcpbuffer != NULL when called from ns_client_send()
668 * and length == 0.
671 static isc_result_t
672 client_allocsendbuf(ns_client_t *client, isc_buffer_t *buffer,
673 isc_buffer_t *tcpbuffer, isc_uint32_t length,
674 unsigned char *sendbuf, unsigned char **datap)
676 unsigned char *data;
677 isc_uint32_t bufsize;
678 isc_result_t result;
680 INSIST(datap != NULL);
681 INSIST((tcpbuffer == NULL && length != 0) ||
682 (tcpbuffer != NULL && length == 0));
684 if (TCP_CLIENT(client)) {
685 INSIST(client->tcpbuf == NULL);
686 if (length + 2 > TCP_BUFFER_SIZE) {
687 result = ISC_R_NOSPACE;
688 goto done;
690 client->tcpbuf = isc_mem_get(client->mctx, TCP_BUFFER_SIZE);
691 if (client->tcpbuf == NULL) {
692 result = ISC_R_NOMEMORY;
693 goto done;
695 data = client->tcpbuf;
696 if (tcpbuffer != NULL) {
697 isc_buffer_init(tcpbuffer, data, TCP_BUFFER_SIZE);
698 isc_buffer_init(buffer, data + 2, TCP_BUFFER_SIZE - 2);
699 } else {
700 isc_buffer_init(buffer, data, TCP_BUFFER_SIZE);
701 INSIST(length <= 0xffff);
702 isc_buffer_putuint16(buffer, (isc_uint16_t)length);
704 } else {
705 data = sendbuf;
706 if (client->udpsize < SEND_BUFFER_SIZE)
707 bufsize = client->udpsize;
708 else
709 bufsize = SEND_BUFFER_SIZE;
710 if (length > bufsize) {
711 result = ISC_R_NOSPACE;
712 goto done;
714 isc_buffer_init(buffer, data, bufsize);
716 *datap = data;
717 result = ISC_R_SUCCESS;
719 done:
720 return (result);
723 static isc_result_t
724 client_sendpkg(ns_client_t *client, isc_buffer_t *buffer) {
725 struct in6_pktinfo *pktinfo;
726 isc_result_t result;
727 isc_region_t r;
728 isc_sockaddr_t *address;
729 isc_socket_t *socket;
730 isc_netaddr_t netaddr;
731 int match;
732 unsigned int sockflags = ISC_SOCKFLAG_IMMEDIATE;
734 if (TCP_CLIENT(client)) {
735 socket = client->tcpsocket;
736 address = NULL;
737 } else {
738 socket = client->udpsocket;
739 address = &client->peeraddr;
741 isc_netaddr_fromsockaddr(&netaddr, &client->peeraddr);
742 if (ns_g_server->blackholeacl != NULL &&
743 dns_acl_match(&netaddr, NULL,
744 ns_g_server->blackholeacl,
745 &ns_g_server->aclenv,
746 &match, NULL) == ISC_R_SUCCESS &&
747 match > 0)
748 return (DNS_R_BLACKHOLED);
749 sockflags |= ISC_SOCKFLAG_NORETRY;
752 if ((client->attributes & NS_CLIENTATTR_PKTINFO) != 0)
753 pktinfo = &client->pktinfo;
754 else
755 pktinfo = NULL;
757 isc_buffer_usedregion(buffer, &r);
759 CTRACE("sendto");
761 result = isc_socket_sendto2(socket, &r, client->task,
762 address, pktinfo,
763 client->sendevent, sockflags);
764 if (result == ISC_R_SUCCESS || result == ISC_R_INPROGRESS) {
765 client->nsends++;
766 if (result == ISC_R_SUCCESS)
767 client_senddone(client->task,
768 (isc_event_t *)client->sendevent);
769 result = ISC_R_SUCCESS;
771 return (result);
774 void
775 ns_client_sendraw(ns_client_t *client, dns_message_t *message) {
776 isc_result_t result;
777 unsigned char *data;
778 isc_buffer_t buffer;
779 isc_region_t r;
780 isc_region_t *mr;
781 unsigned char sendbuf[SEND_BUFFER_SIZE];
783 REQUIRE(NS_CLIENT_VALID(client));
785 CTRACE("sendraw");
787 mr = dns_message_getrawmessage(message);
788 if (mr == NULL) {
789 result = ISC_R_UNEXPECTEDEND;
790 goto done;
793 result = client_allocsendbuf(client, &buffer, NULL, mr->length,
794 sendbuf, &data);
795 if (result != ISC_R_SUCCESS)
796 goto done;
799 * Copy message to buffer and fixup id.
801 isc_buffer_availableregion(&buffer, &r);
802 result = isc_buffer_copyregion(&buffer, mr);
803 if (result != ISC_R_SUCCESS)
804 goto done;
805 r.base[0] = (client->message->id >> 8) & 0xff;
806 r.base[1] = client->message->id & 0xff;
808 result = client_sendpkg(client, &buffer);
809 if (result == ISC_R_SUCCESS)
810 return;
812 done:
813 if (client->tcpbuf != NULL) {
814 isc_mem_put(client->mctx, client->tcpbuf, TCP_BUFFER_SIZE);
815 client->tcpbuf = NULL;
817 ns_client_next(client, result);
820 void
821 ns_client_send(ns_client_t *client) {
822 isc_result_t result;
823 unsigned char *data;
824 isc_buffer_t buffer;
825 isc_buffer_t tcpbuffer;
826 isc_region_t r;
827 dns_compress_t cctx;
828 isc_boolean_t cleanup_cctx = ISC_FALSE;
829 unsigned char sendbuf[SEND_BUFFER_SIZE];
831 REQUIRE(NS_CLIENT_VALID(client));
833 CTRACE("send");
835 if ((client->attributes & NS_CLIENTATTR_RA) != 0)
836 client->message->flags |= DNS_MESSAGEFLAG_RA;
839 * XXXRTH The following doesn't deal with TCP buffer resizing.
841 result = client_allocsendbuf(client, &buffer, &tcpbuffer, 0,
842 sendbuf, &data);
843 if (result != ISC_R_SUCCESS)
844 goto done;
846 result = dns_compress_init(&cctx, -1, client->mctx);
847 if (result != ISC_R_SUCCESS)
848 goto done;
849 cleanup_cctx = ISC_TRUE;
851 result = dns_message_renderbegin(client->message, &cctx, &buffer);
852 if (result != ISC_R_SUCCESS)
853 goto done;
854 if (client->opt != NULL) {
855 result = dns_message_setopt(client->message, client->opt);
857 * XXXRTH dns_message_setopt() should probably do this...
859 client->opt = NULL;
860 if (result != ISC_R_SUCCESS)
861 goto done;
863 result = dns_message_rendersection(client->message,
864 DNS_SECTION_QUESTION, 0);
865 if (result == ISC_R_NOSPACE) {
866 client->message->flags |= DNS_MESSAGEFLAG_TC;
867 goto renderend;
869 if (result != ISC_R_SUCCESS)
870 goto done;
871 result = dns_message_rendersection(client->message,
872 DNS_SECTION_ANSWER,
873 DNS_MESSAGERENDER_PARTIAL);
874 if (result == ISC_R_NOSPACE) {
875 client->message->flags |= DNS_MESSAGEFLAG_TC;
876 goto renderend;
878 if (result != ISC_R_SUCCESS)
879 goto done;
880 result = dns_message_rendersection(client->message,
881 DNS_SECTION_AUTHORITY,
882 DNS_MESSAGERENDER_PARTIAL);
883 if (result == ISC_R_NOSPACE) {
884 client->message->flags |= DNS_MESSAGEFLAG_TC;
885 goto renderend;
887 if (result != ISC_R_SUCCESS)
888 goto done;
889 result = dns_message_rendersection(client->message,
890 DNS_SECTION_ADDITIONAL, 0);
891 if (result != ISC_R_SUCCESS && result != ISC_R_NOSPACE)
892 goto done;
893 renderend:
894 result = dns_message_renderend(client->message);
896 if (result != ISC_R_SUCCESS)
897 goto done;
899 if (cleanup_cctx) {
900 dns_compress_invalidate(&cctx);
901 cleanup_cctx = ISC_FALSE;
904 if (TCP_CLIENT(client)) {
905 isc_buffer_usedregion(&buffer, &r);
906 isc_buffer_putuint16(&tcpbuffer, (isc_uint16_t) r.length);
907 isc_buffer_add(&tcpbuffer, r.length);
908 result = client_sendpkg(client, &tcpbuffer);
909 } else
910 result = client_sendpkg(client, &buffer);
911 if (result == ISC_R_SUCCESS)
912 return;
914 done:
915 if (client->tcpbuf != NULL) {
916 isc_mem_put(client->mctx, client->tcpbuf, TCP_BUFFER_SIZE);
917 client->tcpbuf = NULL;
920 if (cleanup_cctx)
921 dns_compress_invalidate(&cctx);
923 ns_client_next(client, result);
926 void
927 ns_client_error(ns_client_t *client, isc_result_t result) {
928 dns_rcode_t rcode;
929 dns_message_t *message;
931 REQUIRE(NS_CLIENT_VALID(client));
933 CTRACE("error");
935 message = client->message;
936 rcode = dns_result_torcode(result);
939 * Message may be an in-progress reply that we had trouble
940 * with, in which case QR will be set. We need to clear QR before
941 * calling dns_message_reply() to avoid triggering an assertion.
943 message->flags &= ~DNS_MESSAGEFLAG_QR;
945 * AA and AD shouldn't be set.
947 message->flags &= ~(DNS_MESSAGEFLAG_AA | DNS_MESSAGEFLAG_AD);
948 result = dns_message_reply(message, ISC_TRUE);
949 if (result != ISC_R_SUCCESS) {
951 * It could be that we've got a query with a good header,
952 * but a bad question section, so we try again with
953 * want_question_section set to ISC_FALSE.
955 result = dns_message_reply(message, ISC_FALSE);
956 if (result != ISC_R_SUCCESS) {
957 ns_client_next(client, result);
958 return;
961 message->rcode = rcode;
964 * FORMERR loop avoidance: If we sent a FORMERR message
965 * with the same ID to the same client less than two
966 * seconds ago, assume that we are in an infinite error
967 * packet dialog with a server for some protocol whose
968 * error responses look enough like DNS queries to
969 * elicit a FORMERR response. Drop a packet to break
970 * the loop.
972 if (rcode == dns_rcode_formerr) {
973 if (isc_sockaddr_equal(&client->peeraddr,
974 &client->formerrcache.addr) &&
975 message->id == client->formerrcache.id &&
976 client->requesttime - client->formerrcache.time < 2) {
977 /* Drop packet. */
978 ns_client_log(client, NS_LOGCATEGORY_CLIENT,
979 NS_LOGMODULE_CLIENT, ISC_LOG_DEBUG(1),
980 "possible error packet loop, "
981 "FORMERR dropped");
982 ns_client_next(client, result);
983 return;
985 client->formerrcache.addr = client->peeraddr;
986 client->formerrcache.time = client->requesttime;
987 client->formerrcache.id = message->id;
989 ns_client_send(client);
992 static inline isc_result_t
993 client_addopt(ns_client_t *client) {
994 dns_rdataset_t *rdataset;
995 dns_rdatalist_t *rdatalist;
996 dns_rdata_t *rdata;
997 isc_result_t result;
999 REQUIRE(client->opt == NULL); /* XXXRTH free old. */
1001 rdatalist = NULL;
1002 result = dns_message_gettemprdatalist(client->message, &rdatalist);
1003 if (result != ISC_R_SUCCESS)
1004 return (result);
1005 rdata = NULL;
1006 result = dns_message_gettemprdata(client->message, &rdata);
1007 if (result != ISC_R_SUCCESS)
1008 return (result);
1009 rdataset = NULL;
1010 result = dns_message_gettemprdataset(client->message, &rdataset);
1011 if (result != ISC_R_SUCCESS)
1012 return (result);
1013 dns_rdataset_init(rdataset);
1015 rdatalist->type = dns_rdatatype_opt;
1016 rdatalist->covers = 0;
1019 * Set the maximum UDP buffer size.
1021 rdatalist->rdclass = RECV_BUFFER_SIZE;
1024 * Set EXTENDED-RCODE, VERSION, and Z to 0.
1026 #ifdef ISC_RFC2535
1027 rdatalist->ttl = (client->extflags & DNS_MESSAGEEXTFLAG_REPLYPRESERVE);
1028 #else
1029 rdatalist->ttl = 0;
1030 #endif
1033 * No ENDS options in the default case.
1035 rdata->data = NULL;
1036 rdata->length = 0;
1037 rdata->rdclass = rdatalist->rdclass;
1038 rdata->type = rdatalist->type;
1039 rdata->flags = 0;
1041 ISC_LIST_INIT(rdatalist->rdata);
1042 ISC_LIST_APPEND(rdatalist->rdata, rdata, link);
1043 dns_rdatalist_tordataset(rdatalist, rdataset);
1045 client->opt = rdataset;
1047 return (ISC_R_SUCCESS);
1050 static inline isc_boolean_t
1051 allowed(isc_netaddr_t *addr, dns_acl_t *acl) {
1052 int match;
1053 isc_result_t result;
1055 if (acl == NULL)
1056 return (ISC_TRUE);
1057 result = dns_acl_match(addr, NULL, acl, &ns_g_server->aclenv,
1058 &match, NULL);
1059 if (result == ISC_R_SUCCESS && match > 0)
1060 return (ISC_TRUE);
1061 return (ISC_FALSE);
1065 * Handle an incoming request event from the socket (UDP case)
1066 * or tcpmsg (TCP case).
1068 static void
1069 client_request(isc_task_t *task, isc_event_t *event) {
1070 ns_client_t *client;
1071 isc_socketevent_t *sevent;
1072 isc_result_t result;
1073 isc_result_t sigresult;
1074 isc_buffer_t *buffer;
1075 isc_buffer_t tbuffer;
1076 dns_view_t *view;
1077 dns_rdataset_t *opt;
1078 isc_boolean_t ra; /* Recursion available. */
1079 isc_netaddr_t netaddr;
1080 isc_netaddr_t destaddr;
1081 int match;
1082 dns_messageid_t id;
1083 unsigned int flags;
1084 isc_boolean_t notimp;
1086 REQUIRE(event != NULL);
1087 client = event->ev_arg;
1088 REQUIRE(NS_CLIENT_VALID(client));
1089 REQUIRE(task == client->task);
1091 UNUSED(task);
1093 INSIST(client->recursionquota == NULL);
1095 INSIST(client->state ==
1096 TCP_CLIENT(client) ?
1097 NS_CLIENTSTATE_READING :
1098 NS_CLIENTSTATE_READY);
1100 if (event->ev_type == ISC_SOCKEVENT_RECVDONE) {
1101 INSIST(!TCP_CLIENT(client));
1102 sevent = (isc_socketevent_t *)event;
1103 REQUIRE(sevent == client->recvevent);
1104 isc_buffer_init(&tbuffer, sevent->region.base, sevent->n);
1105 isc_buffer_add(&tbuffer, sevent->n);
1106 buffer = &tbuffer;
1107 result = sevent->result;
1108 if (result == ISC_R_SUCCESS) {
1109 client->peeraddr = sevent->address;
1110 client->peeraddr_valid = ISC_TRUE;
1112 if ((sevent->attributes & ISC_SOCKEVENTATTR_PKTINFO) != 0) {
1113 client->attributes |= NS_CLIENTATTR_PKTINFO;
1114 client->pktinfo = sevent->pktinfo;
1116 if ((sevent->attributes & ISC_SOCKEVENTATTR_MULTICAST) != 0)
1117 client->attributes |= NS_CLIENTATTR_MULTICAST;
1118 client->nrecvs--;
1119 } else {
1120 INSIST(TCP_CLIENT(client));
1121 REQUIRE(event->ev_type == DNS_EVENT_TCPMSG);
1122 REQUIRE(event->ev_sender == &client->tcpmsg);
1123 buffer = &client->tcpmsg.buffer;
1124 result = client->tcpmsg.result;
1125 INSIST(client->nreads == 1);
1127 * client->peeraddr was set when the connection was accepted.
1129 client->nreads--;
1132 if (exit_check(client))
1133 goto cleanup;
1134 client->state = client->newstate = NS_CLIENTSTATE_WORKING;
1136 isc_stdtime_get(&client->requesttime);
1137 client->now = client->requesttime;
1139 if (result != ISC_R_SUCCESS) {
1140 if (TCP_CLIENT(client)) {
1141 ns_client_next(client, result);
1142 } else {
1143 if (result != ISC_R_CANCELED)
1144 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_CLIENT,
1145 NS_LOGMODULE_CLIENT,
1146 ISC_LOG_ERROR,
1147 "UDP client handler shutting "
1148 "down due to fatal receive "
1149 "error: %s",
1150 isc_result_totext(result));
1151 isc_task_shutdown(client->task);
1153 goto cleanup;
1156 isc_netaddr_fromsockaddr(&netaddr, &client->peeraddr);
1158 ns_client_log(client, NS_LOGCATEGORY_CLIENT,
1159 NS_LOGMODULE_CLIENT, ISC_LOG_DEBUG(3),
1160 "%s request",
1161 TCP_CLIENT(client) ? "TCP" : "UDP");
1164 * Check the blackhole ACL for UDP only, since TCP is done in
1165 * client_newconn.
1167 if (!TCP_CLIENT(client)) {
1169 if (ns_g_server->blackholeacl != NULL &&
1170 dns_acl_match(&netaddr, NULL, ns_g_server->blackholeacl,
1171 &ns_g_server->aclenv,
1172 &match, NULL) == ISC_R_SUCCESS &&
1173 match > 0)
1175 ns_client_log(client, DNS_LOGCATEGORY_SECURITY,
1176 NS_LOGMODULE_CLIENT, ISC_LOG_DEBUG(10),
1177 "blackholed UDP datagram");
1178 ns_client_next(client, ISC_R_SUCCESS);
1179 goto cleanup;
1183 if ((client->attributes & NS_CLIENTATTR_MULTICAST) != 0) {
1184 ns_client_log(client, NS_LOGCATEGORY_CLIENT,
1185 NS_LOGMODULE_CLIENT, ISC_LOG_DEBUG(2),
1186 "multicast request");
1187 #if 0
1188 ns_client_error(client, DNS_R_REFUSED);
1189 #endif
1192 result = dns_message_peekheader(buffer, &id, &flags);
1193 if (result != ISC_R_SUCCESS) {
1195 * There isn't enough header to determine whether
1196 * this was a request or a response. Drop it.
1198 ns_client_next(client, result);
1199 goto cleanup;
1203 * The client object handles requests, not responses.
1204 * If this is a UDP response, forward it to the dispatcher.
1205 * If it's a TCP response, discard it here.
1207 if ((flags & DNS_MESSAGEFLAG_QR) != 0) {
1208 if (TCP_CLIENT(client)) {
1209 CTRACE("unexpected response");
1210 ns_client_next(client, DNS_R_FORMERR);
1211 goto cleanup;
1212 } else {
1213 dns_dispatch_importrecv(client->dispatch, event);
1214 ns_client_next(client, ISC_R_SUCCESS);
1215 goto cleanup;
1220 * It's a request. Parse it.
1222 result = dns_message_parse(client->message, buffer, 0);
1223 if (result != ISC_R_SUCCESS) {
1225 * Parsing the request failed. Send a response
1226 * (typically FORMERR or SERVFAIL).
1228 ns_client_error(client, result);
1229 goto cleanup;
1232 switch (client->message->opcode) {
1233 case dns_opcode_query:
1234 case dns_opcode_update:
1235 case dns_opcode_notify:
1236 notimp = ISC_FALSE;
1237 break;
1238 case dns_opcode_iquery:
1239 default:
1240 notimp = ISC_TRUE;
1241 break;
1244 client->message->rcode = dns_rcode_noerror;
1247 * Deal with EDNS.
1249 opt = dns_message_getopt(client->message);
1250 if (opt != NULL) {
1251 unsigned int version;
1254 * Set the client's UDP buffer size.
1256 client->udpsize = opt->rdclass;
1259 * If the requested UDP buffer size is less than 512,
1260 * ignore it and use 512.
1262 if (client->udpsize < 512)
1263 client->udpsize = 512;
1266 * Get the flags out of the OPT record.
1268 client->extflags = (isc_uint16_t)(opt->ttl & 0xFFFF);
1271 * Create an OPT for our reply.
1273 result = client_addopt(client);
1274 if (result != ISC_R_SUCCESS) {
1275 ns_client_error(client, result);
1276 goto cleanup;
1280 * Do we understand this version of ENDS?
1282 * XXXRTH need library support for this!
1284 version = (opt->ttl & 0x00FF0000) >> 16;
1285 if (version != 0) {
1286 ns_client_error(client, DNS_R_BADVERS);
1287 goto cleanup;
1291 if (client->message->rdclass == 0) {
1292 ns_client_log(client, NS_LOGCATEGORY_CLIENT,
1293 NS_LOGMODULE_CLIENT, ISC_LOG_DEBUG(1),
1294 "message class could not be determined");
1295 ns_client_dumpmessage(client,
1296 "message class could not be determined");
1297 ns_client_error(client, notimp ? DNS_R_NOTIMP : DNS_R_FORMERR);
1298 goto cleanup;
1302 * Determine the destination address. For TCP/IPv6, we get this from
1303 * the receiving socket. For UDP/IPv6, we get it from the pktinfo
1304 * structure (if supported). For IPv4, we have to do with
1305 * the address of the interface where the request was received.
1307 if (client->interface->addr.type.sa.sa_family == AF_INET6) {
1308 result = ISC_R_FAILURE;
1310 if (TCP_CLIENT(client)) {
1311 isc_sockaddr_t destsockaddr;
1313 result = isc_socket_getsockname(client->tcpsocket,
1314 &destsockaddr);
1315 if (result == ISC_R_SUCCESS)
1316 isc_netaddr_fromsockaddr(&destaddr,
1317 &destsockaddr);
1319 if (result != ISC_R_SUCCESS &&
1320 (client->attributes & NS_CLIENTATTR_PKTINFO) != 0) {
1321 isc_netaddr_fromin6(&destaddr, &client->pktinfo.ipi6_addr);
1322 result = ISC_R_SUCCESS;
1324 if (result != ISC_R_SUCCESS) {
1325 UNEXPECTED_ERROR(__FILE__, __LINE__,
1326 "failed to get request's "
1327 "destination: %s",
1328 isc_result_totext(result));
1329 goto cleanup;
1331 } else {
1332 isc_netaddr_fromsockaddr(&destaddr, &client->interface->addr);
1336 * Find a view that matches the client's source address.
1338 for (view = ISC_LIST_HEAD(ns_g_server->viewlist);
1339 view != NULL;
1340 view = ISC_LIST_NEXT(view, link)) {
1341 if (client->message->rdclass == view->rdclass ||
1342 client->message->rdclass == dns_rdataclass_any)
1344 if (allowed(&netaddr, view->matchclients) &&
1345 allowed(&destaddr, view->matchdestinations) &&
1346 !((flags & DNS_MESSAGEFLAG_RD) == 0 &&
1347 view->matchrecursiveonly))
1349 dns_view_attach(view, &client->view);
1350 break;
1355 if (view == NULL) {
1356 char classname[DNS_RDATACLASS_FORMATSIZE];
1359 * Do a dummy TSIG verification attempt so that the
1360 * response will have a TSIG if the query did, as
1361 * required by RFC2845.
1363 isc_buffer_t b;
1364 isc_region_t *r;
1365 r = dns_message_getrawmessage(client->message);
1366 isc_buffer_init(&b, r->base, r->length);
1367 isc_buffer_add(&b, r->length);
1368 (void)dns_tsig_verify(&b, client->message, NULL, NULL);
1370 dns_rdataclass_format(client->message->rdclass, classname,
1371 sizeof(classname));
1372 ns_client_log(client, NS_LOGCATEGORY_CLIENT,
1373 NS_LOGMODULE_CLIENT, ISC_LOG_DEBUG(1),
1374 "no matching view in class '%s'", classname);
1375 ns_client_dumpmessage(client, "no matching view in class");
1376 ns_client_error(client, notimp ? DNS_R_NOTIMP : DNS_R_REFUSED);
1377 goto cleanup;
1380 ns_client_log(client, NS_LOGCATEGORY_CLIENT,
1381 NS_LOGMODULE_CLIENT, ISC_LOG_DEBUG(5),
1382 "using view '%s'", view->name);
1385 * Check for a signature. We log bad signatures regardless of
1386 * whether they ultimately cause the request to be rejected or
1387 * not. We do not log the lack of a signature unless we are
1388 * debugging.
1390 sigresult = dns_message_checksig(client->message, client->view);
1391 client->signer = NULL;
1392 dns_name_init(&client->signername, NULL);
1393 result = dns_message_signer(client->message, &client->signername);
1394 if (result == ISC_R_SUCCESS) {
1395 ns_client_log(client, DNS_LOGCATEGORY_SECURITY,
1396 NS_LOGMODULE_CLIENT, ISC_LOG_DEBUG(3),
1397 "request has valid signature");
1398 client->signer = &client->signername;
1399 } else if (result == ISC_R_NOTFOUND) {
1400 ns_client_log(client, DNS_LOGCATEGORY_SECURITY,
1401 NS_LOGMODULE_CLIENT, ISC_LOG_DEBUG(3),
1402 "request is not signed");
1403 } else if (result == DNS_R_NOIDENTITY) {
1404 ns_client_log(client, DNS_LOGCATEGORY_SECURITY,
1405 NS_LOGMODULE_CLIENT, ISC_LOG_DEBUG(3),
1406 "request is signed by a nonauthoritative key");
1407 } else {
1408 /* There is a signature, but it is bad. */
1409 ns_client_log(client, DNS_LOGCATEGORY_SECURITY,
1410 NS_LOGMODULE_CLIENT, ISC_LOG_ERROR,
1411 "request has invalid signature: %s",
1412 isc_result_totext(result));
1414 * Accept update messages signed by unknown keys so that
1415 * update forwarding works transparently through slaves
1416 * that don't have all the same keys as the master.
1418 if (!(client->message->tsigstatus == dns_tsigerror_badkey &&
1419 client->message->opcode == dns_opcode_update)) {
1420 ns_client_error(client, sigresult);
1421 goto cleanup;
1426 * Decide whether recursive service is available to this client.
1427 * We do this here rather than in the query code so that we can
1428 * set the RA bit correctly on all kinds of responses, not just
1429 * responses to ordinary queries.
1431 ra = ISC_FALSE;
1432 if (client->view->resolver != NULL &&
1433 client->view->recursion == ISC_TRUE &&
1434 /* XXX this will log too much too early */
1435 ns_client_checkacl(client, "recursion available:",
1436 client->view->recursionacl,
1437 ISC_TRUE, ISC_LOG_DEBUG(1)) == ISC_R_SUCCESS)
1438 ra = ISC_TRUE;
1440 if (ra == ISC_TRUE)
1441 client->attributes |= NS_CLIENTATTR_RA;
1444 * Dispatch the request.
1446 switch (client->message->opcode) {
1447 case dns_opcode_query:
1448 CTRACE("query");
1449 ns_query_start(client);
1450 break;
1451 case dns_opcode_update:
1452 CTRACE("update");
1453 ns_client_settimeout(client, 60);
1454 ns_update_start(client, sigresult);
1455 break;
1456 case dns_opcode_notify:
1457 CTRACE("notify");
1458 ns_client_settimeout(client, 60);
1459 ns_notify_start(client);
1460 break;
1461 case dns_opcode_iquery:
1462 CTRACE("iquery");
1463 ns_client_error(client, DNS_R_NOTIMP);
1464 break;
1465 default:
1466 CTRACE("unknown opcode");
1467 ns_client_error(client, DNS_R_NOTIMP);
1470 cleanup:
1471 return;
1474 static void
1475 client_timeout(isc_task_t *task, isc_event_t *event) {
1476 ns_client_t *client;
1478 REQUIRE(event != NULL);
1479 REQUIRE(event->ev_type == ISC_TIMEREVENT_LIFE ||
1480 event->ev_type == ISC_TIMEREVENT_IDLE);
1481 client = event->ev_arg;
1482 REQUIRE(NS_CLIENT_VALID(client));
1483 REQUIRE(task == client->task);
1484 REQUIRE(client->timer != NULL);
1486 UNUSED(task);
1488 CTRACE("timeout");
1490 isc_event_free(&event);
1492 if (client->shutdown != NULL) {
1493 (client->shutdown)(client->shutdown_arg, ISC_R_TIMEDOUT);
1494 client->shutdown = NULL;
1495 client->shutdown_arg = NULL;
1498 if (client->newstate > NS_CLIENTSTATE_READY)
1499 client->newstate = NS_CLIENTSTATE_READY;
1500 (void) exit_check(client);
1503 static isc_result_t
1504 client_create(ns_clientmgr_t *manager, ns_client_t **clientp)
1506 ns_client_t *client;
1507 isc_result_t result;
1510 * Caller must be holding the manager lock.
1512 * Note: creating a client does not add the client to the
1513 * manager's client list or set the client's manager pointer.
1514 * The caller is responsible for that.
1517 REQUIRE(clientp != NULL && *clientp == NULL);
1519 client = isc_mem_get(manager->mctx, sizeof *client);
1520 if (client == NULL)
1521 return (ISC_R_NOMEMORY);
1523 client->task = NULL;
1524 result = isc_task_create(manager->taskmgr, 0, &client->task);
1525 if (result != ISC_R_SUCCESS)
1526 goto cleanup_client;
1527 isc_task_setname(client->task, "client", client);
1529 client->timer = NULL;
1530 result = isc_timer_create(manager->timermgr, isc_timertype_inactive,
1531 NULL, NULL, client->task, client_timeout,
1532 client, &client->timer);
1533 if (result != ISC_R_SUCCESS)
1534 goto cleanup_task;
1535 client->timerset = ISC_FALSE;
1537 client->message = NULL;
1538 result = dns_message_create(manager->mctx, DNS_MESSAGE_INTENTPARSE,
1539 &client->message);
1540 if (result != ISC_R_SUCCESS)
1541 goto cleanup_timer;
1543 /* XXXRTH Hardwired constants */
1545 client->sendevent = (isc_socketevent_t *)
1546 isc_event_allocate(manager->mctx, client,
1547 ISC_SOCKEVENT_SENDDONE,
1548 client_senddone, client,
1549 sizeof(isc_socketevent_t));
1550 if (client->sendevent == NULL) {
1551 result = ISC_R_NOMEMORY;
1552 goto cleanup_message;
1555 client->recvbuf = isc_mem_get(manager->mctx, RECV_BUFFER_SIZE);
1556 if (client->recvbuf == NULL) {
1557 result = ISC_R_NOMEMORY;
1558 goto cleanup_sendevent;
1561 client->recvevent = (isc_socketevent_t *)
1562 isc_event_allocate(manager->mctx, client,
1563 ISC_SOCKEVENT_RECVDONE,
1564 client_request, client,
1565 sizeof(isc_socketevent_t));
1566 if (client->recvevent == NULL) {
1567 result = ISC_R_NOMEMORY;
1568 goto cleanup_recvbuf;
1571 client->magic = NS_CLIENT_MAGIC;
1572 client->mctx = manager->mctx;
1573 client->manager = NULL;
1574 client->state = NS_CLIENTSTATE_INACTIVE;
1575 client->newstate = NS_CLIENTSTATE_MAX;
1576 client->naccepts = 0;
1577 client->nreads = 0;
1578 client->nsends = 0;
1579 client->nrecvs = 0;
1580 client->nupdates = 0;
1581 client->nctls = 0;
1582 client->references = 0;
1583 client->attributes = 0;
1584 client->view = NULL;
1585 client->dispatch = NULL;
1586 client->udpsocket = NULL;
1587 client->tcplistener = NULL;
1588 client->tcpsocket = NULL;
1589 client->tcpmsg_valid = ISC_FALSE;
1590 client->tcpbuf = NULL;
1591 client->opt = NULL;
1592 client->udpsize = 512;
1593 client->extflags = 0;
1594 client->next = NULL;
1595 client->shutdown = NULL;
1596 client->shutdown_arg = NULL;
1597 dns_name_init(&client->signername, NULL);
1598 client->mortal = ISC_FALSE;
1599 client->tcpquota = NULL;
1600 client->recursionquota = NULL;
1601 client->interface = NULL;
1602 client->peeraddr_valid = ISC_FALSE;
1603 ISC_EVENT_INIT(&client->ctlevent, sizeof(client->ctlevent), 0, NULL,
1604 NS_EVENT_CLIENTCONTROL, client_start, client, client,
1605 NULL, NULL);
1607 * Initialize FORMERR cache to sentinel value that will not match
1608 * any actual FORMERR response.
1610 isc_sockaddr_any(&client->formerrcache.addr);
1611 client->formerrcache.time = 0;
1612 client->formerrcache.id = 0;
1613 ISC_LINK_INIT(client, link);
1614 client->list = NULL;
1617 * We call the init routines for the various kinds of client here,
1618 * after we have created an otherwise valid client, because some
1619 * of them call routines that REQUIRE(NS_CLIENT_VALID(client)).
1621 result = ns_query_init(client);
1622 if (result != ISC_R_SUCCESS)
1623 goto cleanup_recvevent;
1625 result = isc_task_onshutdown(client->task, client_shutdown, client);
1626 if (result != ISC_R_SUCCESS)
1627 goto cleanup_query;
1629 CTRACE("create");
1631 *clientp = client;
1633 return (ISC_R_SUCCESS);
1635 cleanup_query:
1636 ns_query_free(client);
1638 cleanup_recvevent:
1639 isc_event_free((isc_event_t **)&client->recvevent);
1641 cleanup_recvbuf:
1642 isc_mem_put(manager->mctx, client->recvbuf, RECV_BUFFER_SIZE);
1644 cleanup_sendevent:
1645 isc_event_free((isc_event_t **)&client->sendevent);
1647 client->magic = 0;
1649 cleanup_message:
1650 dns_message_destroy(&client->message);
1652 cleanup_timer:
1653 isc_timer_detach(&client->timer);
1655 cleanup_task:
1656 isc_task_detach(&client->task);
1658 cleanup_client:
1659 isc_mem_put(manager->mctx, client, sizeof *client);
1661 return (result);
1664 static void
1665 client_read(ns_client_t *client) {
1666 isc_result_t result;
1668 CTRACE("read");
1670 result = dns_tcpmsg_readmessage(&client->tcpmsg, client->task,
1671 client_request, client);
1672 if (result != ISC_R_SUCCESS)
1673 goto fail;
1676 * Set a timeout to limit the amount of time we will wait
1677 * for a request on this TCP connection.
1679 ns_client_settimeout(client, 30);
1681 client->state = client->newstate = NS_CLIENTSTATE_READING;
1682 INSIST(client->nreads == 0);
1683 INSIST(client->recursionquota == NULL);
1684 client->nreads++;
1686 return;
1687 fail:
1688 ns_client_next(client, result);
1691 static void
1692 client_newconn(isc_task_t *task, isc_event_t *event) {
1693 ns_client_t *client = event->ev_arg;
1694 isc_socket_newconnev_t *nevent = (isc_socket_newconnev_t *)event;
1695 isc_result_t result;
1697 REQUIRE(event->ev_type == ISC_SOCKEVENT_NEWCONN);
1698 REQUIRE(NS_CLIENT_VALID(client));
1699 REQUIRE(client->task == task);
1701 UNUSED(task);
1703 INSIST(client->state == NS_CLIENTSTATE_READY);
1705 INSIST(client->naccepts == 1);
1706 client->naccepts--;
1708 LOCK(&client->interface->lock);
1709 INSIST(client->interface->ntcpcurrent > 0);
1710 client->interface->ntcpcurrent--;
1711 UNLOCK(&client->interface->lock);
1714 * We must take ownership of the new socket before the exit
1715 * check to make sure it gets destroyed if we decide to exit.
1717 if (nevent->result == ISC_R_SUCCESS) {
1718 client->tcpsocket = nevent->newsocket;
1719 client->state = NS_CLIENTSTATE_READING;
1720 INSIST(client->recursionquota == NULL);
1722 (void) isc_socket_getpeername(client->tcpsocket,
1723 &client->peeraddr);
1724 client->peeraddr_valid = ISC_TRUE;
1725 ns_client_log(client, NS_LOGCATEGORY_CLIENT,
1726 NS_LOGMODULE_CLIENT, ISC_LOG_DEBUG(3),
1727 "new TCP connection");
1728 } else {
1730 * XXXRTH What should we do? We're trying to accept but
1731 * it didn't work. If we just give up, then TCP
1732 * service may eventually stop.
1734 * For now, we just go idle.
1736 * Going idle is probably the right thing if the
1737 * I/O was canceled.
1739 ns_client_log(client, NS_LOGCATEGORY_CLIENT,
1740 NS_LOGMODULE_CLIENT, ISC_LOG_DEBUG(3),
1741 "accept failed: %s",
1742 isc_result_totext(nevent->result));
1745 if (exit_check(client))
1746 goto freeevent;
1748 if (nevent->result == ISC_R_SUCCESS) {
1749 int match;
1750 isc_netaddr_t netaddr;
1752 isc_netaddr_fromsockaddr(&netaddr, &client->peeraddr);
1754 if (ns_g_server->blackholeacl != NULL &&
1755 dns_acl_match(&netaddr, NULL,
1756 ns_g_server->blackholeacl,
1757 &ns_g_server->aclenv,
1758 &match, NULL) == ISC_R_SUCCESS &&
1759 match > 0)
1761 ns_client_log(client, DNS_LOGCATEGORY_SECURITY,
1762 NS_LOGMODULE_CLIENT, ISC_LOG_DEBUG(10),
1763 "blackholed connection attempt");
1764 client->newstate = NS_CLIENTSTATE_READY;
1765 (void)exit_check(client);
1766 goto freeevent;
1769 INSIST(client->tcpmsg_valid == ISC_FALSE);
1770 dns_tcpmsg_init(client->mctx, client->tcpsocket,
1771 &client->tcpmsg);
1772 client->tcpmsg_valid = ISC_TRUE;
1775 * Let a new client take our place immediately, before
1776 * we wait for a request packet. If we don't,
1777 * telnetting to port 53 (once per CPU) will
1778 * deny service to legititmate TCP clients.
1780 result = isc_quota_attach(&ns_g_server->tcpquota,
1781 &client->tcpquota);
1782 if (result == ISC_R_SUCCESS)
1783 result = ns_client_replace(client);
1784 if (result != ISC_R_SUCCESS) {
1785 ns_client_log(client, NS_LOGCATEGORY_CLIENT,
1786 NS_LOGMODULE_CLIENT, ISC_LOG_WARNING,
1787 "no more TCP clients: %s",
1788 isc_result_totext(result));
1791 client_read(client);
1794 freeevent:
1795 isc_event_free(&event);
1798 static void
1799 client_accept(ns_client_t *client) {
1800 isc_result_t result;
1802 CTRACE("accept");
1804 result = isc_socket_accept(client->tcplistener, client->task,
1805 client_newconn, client);
1806 if (result != ISC_R_SUCCESS) {
1807 UNEXPECTED_ERROR(__FILE__, __LINE__,
1808 "isc_socket_accept() failed: %s",
1809 isc_result_totext(result));
1811 * XXXRTH What should we do? We're trying to accept but
1812 * it didn't work. If we just give up, then TCP
1813 * service may eventually stop.
1815 * For now, we just go idle.
1817 return;
1819 INSIST(client->naccepts == 0);
1820 client->naccepts++;
1821 LOCK(&client->interface->lock);
1822 client->interface->ntcpcurrent++;
1823 UNLOCK(&client->interface->lock);
1826 static void
1827 client_udprecv(ns_client_t *client) {
1828 isc_result_t result;
1829 isc_region_t r;
1831 CTRACE("udprecv");
1833 r.base = client->recvbuf;
1834 r.length = RECV_BUFFER_SIZE;
1835 result = isc_socket_recv2(client->udpsocket, &r, 1,
1836 client->task, client->recvevent, 0);
1837 if (result != ISC_R_SUCCESS) {
1838 UNEXPECTED_ERROR(__FILE__, __LINE__,
1839 "isc_socket_recv() failed: %s",
1840 isc_result_totext(result));
1842 * This cannot happen in the current implementation, since
1843 * isc_socket_recv2() cannot fail if flags == 0A
1845 * If this does fail, we just go idle.
1847 return;
1849 INSIST(client->nrecvs == 0);
1850 client->nrecvs++;
1853 void
1854 ns_client_attach(ns_client_t *source, ns_client_t **targetp) {
1855 REQUIRE(NS_CLIENT_VALID(source));
1856 REQUIRE(targetp != NULL && *targetp == NULL);
1858 source->references++;
1859 ns_client_log(source, NS_LOGCATEGORY_CLIENT,
1860 NS_LOGMODULE_CLIENT, ISC_LOG_DEBUG(10),
1861 "ns_client_attach: ref = %d", source->references);
1862 *targetp = source;
1865 void
1866 ns_client_detach(ns_client_t **clientp) {
1867 ns_client_t *client = *clientp;
1869 client->references--;
1870 INSIST(client->references >= 0);
1871 *clientp = NULL;
1872 ns_client_log(client, NS_LOGCATEGORY_CLIENT,
1873 NS_LOGMODULE_CLIENT, ISC_LOG_DEBUG(10),
1874 "ns_client_detach: ref = %d", client->references);
1875 (void) exit_check(client);
1878 isc_boolean_t
1879 ns_client_shuttingdown(ns_client_t *client) {
1880 return (ISC_TF(client->newstate == NS_CLIENTSTATE_FREED));
1883 isc_result_t
1884 ns_client_replace(ns_client_t *client) {
1885 isc_result_t result;
1887 CTRACE("replace");
1889 result = ns_clientmgr_createclients(client->manager,
1890 1, client->interface,
1891 (TCP_CLIENT(client) ?
1892 ISC_TRUE : ISC_FALSE));
1893 if (result != ISC_R_SUCCESS)
1894 return (result);
1897 * The responsibility for listening for new requests is hereby
1898 * transferred to the new client. Therefore, the old client
1899 * should refrain from listening for any more requests.
1901 client->mortal = ISC_TRUE;
1903 return (ISC_R_SUCCESS);
1906 /***
1907 *** Client Manager
1908 ***/
1910 static void
1911 clientmgr_destroy(ns_clientmgr_t *manager) {
1912 REQUIRE(ISC_LIST_EMPTY(manager->active));
1913 REQUIRE(ISC_LIST_EMPTY(manager->inactive));
1915 MTRACE("clientmgr_destroy");
1917 DESTROYLOCK(&manager->lock);
1918 manager->magic = 0;
1919 isc_mem_put(manager->mctx, manager, sizeof *manager);
1922 isc_result_t
1923 ns_clientmgr_create(isc_mem_t *mctx, isc_taskmgr_t *taskmgr,
1924 isc_timermgr_t *timermgr, ns_clientmgr_t **managerp)
1926 ns_clientmgr_t *manager;
1927 isc_result_t result;
1929 manager = isc_mem_get(mctx, sizeof *manager);
1930 if (manager == NULL)
1931 return (ISC_R_NOMEMORY);
1933 result = isc_mutex_init(&manager->lock);
1934 if (result != ISC_R_SUCCESS)
1935 goto cleanup_manager;
1937 manager->mctx = mctx;
1938 manager->taskmgr = taskmgr;
1939 manager->timermgr = timermgr;
1940 manager->exiting = ISC_FALSE;
1941 ISC_LIST_INIT(manager->active);
1942 ISC_LIST_INIT(manager->inactive);
1943 manager->magic = MANAGER_MAGIC;
1945 MTRACE("create");
1947 *managerp = manager;
1949 return (ISC_R_SUCCESS);
1951 cleanup_manager:
1952 isc_mem_put(manager->mctx, manager, sizeof *manager);
1954 return (result);
1957 void
1958 ns_clientmgr_destroy(ns_clientmgr_t **managerp) {
1959 ns_clientmgr_t *manager;
1960 ns_client_t *client;
1961 isc_boolean_t need_destroy = ISC_FALSE;
1963 REQUIRE(managerp != NULL);
1964 manager = *managerp;
1965 REQUIRE(VALID_MANAGER(manager));
1967 MTRACE("destroy");
1969 LOCK(&manager->lock);
1971 manager->exiting = ISC_TRUE;
1973 for (client = ISC_LIST_HEAD(manager->active);
1974 client != NULL;
1975 client = ISC_LIST_NEXT(client, link))
1976 isc_task_shutdown(client->task);
1978 for (client = ISC_LIST_HEAD(manager->inactive);
1979 client != NULL;
1980 client = ISC_LIST_NEXT(client, link))
1981 isc_task_shutdown(client->task);
1983 if (ISC_LIST_EMPTY(manager->active) &&
1984 ISC_LIST_EMPTY(manager->inactive))
1985 need_destroy = ISC_TRUE;
1987 UNLOCK(&manager->lock);
1989 if (need_destroy)
1990 clientmgr_destroy(manager);
1992 *managerp = NULL;
1995 isc_result_t
1996 ns_clientmgr_createclients(ns_clientmgr_t *manager, unsigned int n,
1997 ns_interface_t *ifp, isc_boolean_t tcp)
1999 isc_result_t result = ISC_R_SUCCESS;
2000 unsigned int i;
2001 ns_client_t *client;
2003 REQUIRE(VALID_MANAGER(manager));
2004 REQUIRE(n > 0);
2006 MTRACE("createclients");
2009 * We MUST lock the manager lock for the entire client creation
2010 * process. If we didn't do this, then a client could get a
2011 * shutdown event and disappear out from under us.
2014 LOCK(&manager->lock);
2016 for (i = 0; i < n; i++) {
2017 isc_event_t *ev;
2019 * Allocate a client. First try to get a recycled one;
2020 * if that fails, make a new one.
2022 client = ISC_LIST_HEAD(manager->inactive);
2023 if (client != NULL) {
2024 MTRACE("recycle");
2025 ISC_LIST_UNLINK(manager->inactive, client, link);
2026 client->list = NULL;
2027 } else {
2028 MTRACE("create new");
2029 result = client_create(manager, &client);
2030 if (result != ISC_R_SUCCESS)
2031 break;
2034 ns_interface_attach(ifp, &client->interface);
2035 client->state = NS_CLIENTSTATE_READY;
2036 INSIST(client->recursionquota == NULL);
2038 if (tcp) {
2039 client->attributes |= NS_CLIENTATTR_TCP;
2040 isc_socket_attach(ifp->tcpsocket,
2041 &client->tcplistener);
2042 } else {
2043 isc_socket_t *sock;
2045 dns_dispatch_attach(ifp->udpdispatch,
2046 &client->dispatch);
2047 sock = dns_dispatch_getsocket(client->dispatch);
2048 isc_socket_attach(sock, &client->udpsocket);
2050 client->manager = manager;
2051 ISC_LIST_APPEND(manager->active, client, link);
2052 client->list = &manager->active;
2054 INSIST(client->nctls == 0);
2055 client->nctls++;
2056 ev = &client->ctlevent;
2057 isc_task_send(client->task, &ev);
2059 if (i != 0) {
2061 * We managed to create at least one client, so we
2062 * declare victory.
2064 result = ISC_R_SUCCESS;
2067 UNLOCK(&manager->lock);
2069 return (result);
2072 isc_sockaddr_t *
2073 ns_client_getsockaddr(ns_client_t *client) {
2074 return (&client->peeraddr);
2077 isc_result_t
2078 ns_client_checkaclsilent(ns_client_t *client, dns_acl_t *acl,
2079 isc_boolean_t default_allow)
2081 isc_result_t result;
2082 int match;
2083 isc_netaddr_t netaddr;
2085 if (acl == NULL) {
2086 if (default_allow)
2087 goto allow;
2088 else
2089 goto deny;
2092 isc_netaddr_fromsockaddr(&netaddr, &client->peeraddr);
2094 result = dns_acl_match(&netaddr, client->signer, acl,
2095 &ns_g_server->aclenv,
2096 &match, NULL);
2097 if (result != ISC_R_SUCCESS)
2098 goto deny; /* Internal error, already logged. */
2099 if (match > 0)
2100 goto allow;
2101 goto deny; /* Negative match or no match. */
2103 allow:
2104 return (ISC_R_SUCCESS);
2106 deny:
2107 return (DNS_R_REFUSED);
2110 isc_result_t
2111 ns_client_checkacl(ns_client_t *client,
2112 const char *opname, dns_acl_t *acl,
2113 isc_boolean_t default_allow, int log_level)
2115 isc_result_t result =
2116 ns_client_checkaclsilent(client, acl, default_allow);
2118 if (result == ISC_R_SUCCESS)
2119 ns_client_log(client, DNS_LOGCATEGORY_SECURITY,
2120 NS_LOGMODULE_CLIENT, ISC_LOG_DEBUG(3),
2121 "%s approved", opname);
2122 else
2123 ns_client_log(client, DNS_LOGCATEGORY_SECURITY,
2124 NS_LOGMODULE_CLIENT,
2125 log_level, "%s denied", opname);
2126 return (result);
2129 static void
2130 ns_client_name(ns_client_t *client, char *peerbuf, size_t len) {
2131 if (client->peeraddr_valid)
2132 isc_sockaddr_format(&client->peeraddr, peerbuf, len);
2133 else
2134 snprintf(peerbuf, len, "@%p", client);
2137 static void
2138 ns_client_logv(ns_client_t *client, isc_logcategory_t *category,
2139 isc_logmodule_t *module, int level, const char *fmt, va_list ap)
2140 ISC_FORMAT_PRINTF(5, 0);
2142 static void
2143 ns_client_logv(ns_client_t *client, isc_logcategory_t *category,
2144 isc_logmodule_t *module, int level, const char *fmt, va_list ap)
2146 char msgbuf[2048];
2147 char peerbuf[ISC_SOCKADDR_FORMATSIZE];
2149 vsnprintf(msgbuf, sizeof(msgbuf), fmt, ap);
2150 ns_client_name(client, peerbuf, sizeof peerbuf);
2152 isc_log_write(ns_g_lctx, category, module, level,
2153 "client %s: %s", peerbuf, msgbuf);
2156 void
2157 ns_client_log(ns_client_t *client, isc_logcategory_t *category,
2158 isc_logmodule_t *module, int level, const char *fmt, ...)
2160 va_list ap;
2162 if (! isc_log_wouldlog(ns_g_lctx, level))
2163 return;
2165 va_start(ap, fmt);
2166 ns_client_logv(client, category, module, level, fmt, ap);
2167 va_end(ap);
2170 void
2171 ns_client_aclmsg(const char *msg, dns_name_t *name, dns_rdataclass_t rdclass,
2172 char *buf, size_t len)
2174 char namebuf[DNS_NAME_FORMATSIZE];
2175 char classbuf[DNS_RDATACLASS_FORMATSIZE];
2177 dns_name_format(name, namebuf, sizeof(namebuf));
2178 dns_rdataclass_format(rdclass, classbuf, sizeof(classbuf));
2179 (void)snprintf(buf, len, "%s '%s/%s'", msg, namebuf, classbuf);
2182 static void
2183 ns_client_dumpmessage(ns_client_t *client, const char *reason) {
2184 isc_buffer_t buffer;
2185 char *buf = NULL;
2186 int len = 1024;
2187 isc_result_t result;
2190 * Note that these are multiline debug messages. We want a newline
2191 * to appear in the log after each message.
2194 do {
2195 buf = isc_mem_get(client->mctx, len);
2196 if (buf == NULL)
2197 break;
2198 isc_buffer_init(&buffer, buf, len);
2199 result = dns_message_totext(client->message,
2200 &dns_master_style_debug,
2201 0, &buffer);
2202 if (result == ISC_R_NOSPACE) {
2203 isc_mem_put(client->mctx, buf, len);
2204 len += 1024;
2205 } else if (result == ISC_R_SUCCESS)
2206 ns_client_log(client, NS_LOGCATEGORY_UNMATCHED,
2207 NS_LOGMODULE_CLIENT, ISC_LOG_DEBUG(1),
2208 "%s\n%.*s", reason,
2209 (int)isc_buffer_usedlength(&buffer),
2210 buf);
2211 } while (result == ISC_R_NOSPACE);
2213 if (buf != NULL)
2214 isc_mem_put(client->mctx, buf, len);