]> CyberLeo.Net >> Repos - FreeBSD/releng/8.1.git/blob - contrib/bind9/bin/named/client.c
Copy stable/8 to releng/8.1 in preparation for 8.1-RC1.
[FreeBSD/releng/8.1.git] / contrib / bind9 / bin / named / client.c
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 */
116 struct 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
205 unsigned int ns_client_requests;
206
207 static void client_read(ns_client_t *client);
208 static void client_accept(ns_client_t *client);
209 static void client_udprecv(ns_client_t *client);
210 static void clientmgr_destroy(ns_clientmgr_t *manager);
211 static isc_boolean_t exit_check(ns_client_t *client);
212 static void ns_client_endrequest(ns_client_t *client);
213 static void ns_client_checkactive(ns_client_t *client);
214 static void client_start(isc_task_t *task, isc_event_t *event);
215 static void client_request(isc_task_t *task, isc_event_t *event);
216 static void ns_client_dumpmessage(ns_client_t *client, const char *reason);
217
218 void
219 ns_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
229 void
230 ns_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
245 void
246 ns_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  */
269 static isc_boolean_t
270 exit_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  */
560 static void
561 client_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  */
585 static void
586 client_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
612 static void
613 ns_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
651 static void
652 ns_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
685 void
686 ns_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
716 static void
717 client_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
761 static isc_result_t
762 client_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
813 static isc_result_t
814 client_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
865 void
866 ns_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
911 void
912 ns_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  */
1067 static int
1068 ns_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
1082 void
1083 ns_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
1170 static inline isc_result_t
1171 client_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 {
1250 no_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
1269 static inline isc_boolean_t
1270 allowed(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  */
1291 isc_boolean_t
1292 ns_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  */
1345 static void
1346 client_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
1923 static void
1924 client_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
1952 static isc_result_t
1953 get_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
1989 static isc_result_t
1990 client_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
2159 static void
2160 client_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
2186 static void
2187 client_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
2294 static void
2295 client_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
2322 static void
2323 client_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
2349 void
2350 ns_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
2361 void
2362 ns_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
2374 isc_boolean_t
2375 ns_client_shuttingdown(ns_client_t *client) {
2376         return (ISC_TF(client->newstate == NS_CLIENTSTATE_FREED));
2377 }
2378
2379 isc_result_t
2380 ns_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
2406 static void
2407 clientmgr_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
2430 isc_result_t
2431 ns_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
2474 void
2475 ns_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
2518 isc_result_t
2519 ns_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
2597 isc_sockaddr_t *
2598 ns_client_getsockaddr(ns_client_t *client) {
2599         return (&client->peeraddr);
2600 }
2601
2602 isc_result_t
2603 ns_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
2640 isc_result_t
2641 ns_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
2659 static void
2660 ns_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
2667 void
2668 ns_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
2688 void
2689 ns_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
2702 void
2703 ns_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
2717 static void
2718 ns_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
2752 void
2753 ns_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
2783 void
2784 ns_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 }