1135446Strhodes/* 2262706Serwin * Copyright (C) 2004-2013 Internet Systems Consortium, Inc. ("ISC") 3135446Strhodes * Copyright (C) 1999-2003 Internet Software Consortium. 4135446Strhodes * 5174187Sdougb * Permission to use, copy, modify, and/or distribute this software for any 6135446Strhodes * purpose with or without fee is hereby granted, provided that the above 7135446Strhodes * copyright notice and this permission notice appear in all copies. 8135446Strhodes * 9135446Strhodes * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH 10135446Strhodes * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 11135446Strhodes * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, 12135446Strhodes * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 13135446Strhodes * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE 14135446Strhodes * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 15135446Strhodes * PERFORMANCE OF THIS SOFTWARE. 16135446Strhodes */ 17135446Strhodes 18254897Serwin/* $Id$ */ 19135446Strhodes 20135446Strhodes#include <config.h> 21135446Strhodes 22135446Strhodes#include <isc/formatcheck.h> 23135446Strhodes#include <isc/mutex.h> 24135446Strhodes#include <isc/once.h> 25170222Sdougb#include <isc/platform.h> 26135446Strhodes#include <isc/print.h> 27254897Serwin#include <isc/queue.h> 28193149Sdougb#include <isc/stats.h> 29135446Strhodes#include <isc/stdio.h> 30135446Strhodes#include <isc/string.h> 31135446Strhodes#include <isc/task.h> 32135446Strhodes#include <isc/timer.h> 33135446Strhodes#include <isc/util.h> 34135446Strhodes 35135446Strhodes#include <dns/db.h> 36135446Strhodes#include <dns/dispatch.h> 37135446Strhodes#include <dns/events.h> 38135446Strhodes#include <dns/message.h> 39170222Sdougb#include <dns/peer.h> 40135446Strhodes#include <dns/rcode.h> 41135446Strhodes#include <dns/rdata.h> 42135446Strhodes#include <dns/rdataclass.h> 43135446Strhodes#include <dns/rdatalist.h> 44135446Strhodes#include <dns/rdataset.h> 45170222Sdougb#include <dns/resolver.h> 46193149Sdougb#include <dns/stats.h> 47135446Strhodes#include <dns/tsig.h> 48135446Strhodes#include <dns/view.h> 49135446Strhodes#include <dns/zone.h> 50135446Strhodes 51135446Strhodes#include <named/interfacemgr.h> 52135446Strhodes#include <named/log.h> 53135446Strhodes#include <named/notify.h> 54193149Sdougb#include <named/os.h> 55135446Strhodes#include <named/server.h> 56135446Strhodes#include <named/update.h> 57135446Strhodes 58135446Strhodes/*** 59135446Strhodes *** Client 60135446Strhodes ***/ 61135446Strhodes 62170222Sdougb/*! \file 63170222Sdougb * Client Routines 64170222Sdougb * 65135446Strhodes * Important note! 66135446Strhodes * 67135446Strhodes * All client state changes, other than that from idle to listening, occur 68135446Strhodes * as a result of events. This guarantees serialization and avoids the 69135446Strhodes * need for locking. 70135446Strhodes * 71135446Strhodes * If a routine is ever created that allows someone other than the client's 72135446Strhodes * task to change the client, then the client will have to be locked. 73135446Strhodes */ 74135446Strhodes 75135446Strhodes#define NS_CLIENT_TRACE 76135446Strhodes#ifdef NS_CLIENT_TRACE 77135446Strhodes#define CTRACE(m) ns_client_log(client, \ 78135446Strhodes NS_LOGCATEGORY_CLIENT, \ 79135446Strhodes NS_LOGMODULE_CLIENT, \ 80135446Strhodes ISC_LOG_DEBUG(3), \ 81135446Strhodes "%s", (m)) 82135446Strhodes#define MTRACE(m) isc_log_write(ns_g_lctx, \ 83135446Strhodes NS_LOGCATEGORY_GENERAL, \ 84135446Strhodes NS_LOGMODULE_CLIENT, \ 85135446Strhodes ISC_LOG_DEBUG(3), \ 86135446Strhodes "clientmgr @%p: %s", manager, (m)) 87135446Strhodes#else 88135446Strhodes#define CTRACE(m) ((void)(m)) 89135446Strhodes#define MTRACE(m) ((void)(m)) 90135446Strhodes#endif 91135446Strhodes 92135446Strhodes#define TCP_CLIENT(c) (((c)->attributes & NS_CLIENTATTR_TCP) != 0) 93135446Strhodes 94135446Strhodes#define TCP_BUFFER_SIZE (65535 + 2) 95135446Strhodes#define SEND_BUFFER_SIZE 4096 96135446Strhodes#define RECV_BUFFER_SIZE 4096 97135446Strhodes 98170222Sdougb#ifdef ISC_PLATFORM_USETHREADS 99170222Sdougb#define NMCTXS 100 100170222Sdougb/*%< 101170222Sdougb * Number of 'mctx pools' for clients. (Should this be configurable?) 102170222Sdougb * When enabling threads, we use a pool of memory contexts shared by 103170222Sdougb * client objects, since concurrent access to a shared context would cause 104170222Sdougb * heavy contentions. The above constant is expected to be enough for 105170222Sdougb * completely avoiding contentions among threads for an authoritative-only 106170222Sdougb * server. 107170222Sdougb */ 108170222Sdougb#else 109170222Sdougb#define NMCTXS 0 110170222Sdougb/*%< 111170222Sdougb * If named with built without thread, simply share manager's context. Using 112170222Sdougb * a separate context in this case would simply waste memory. 113170222Sdougb */ 114170222Sdougb#endif 115170222Sdougb 116170222Sdougb/*% nameserver client manager structure */ 117135446Strhodesstruct ns_clientmgr { 118135446Strhodes /* Unlocked. */ 119135446Strhodes unsigned int magic; 120254897Serwin 121254897Serwin /* The queue object has its own locks */ 122254897Serwin client_queue_t inactive; /*%< To be recycled */ 123254897Serwin 124135446Strhodes isc_mem_t * mctx; 125135446Strhodes isc_taskmgr_t * taskmgr; 126135446Strhodes isc_timermgr_t * timermgr; 127254897Serwin 128254897Serwin /* Lock covers manager state. */ 129135446Strhodes isc_mutex_t lock; 130135446Strhodes isc_boolean_t exiting; 131254897Serwin 132254897Serwin /* Lock covers the clients list */ 133254897Serwin isc_mutex_t listlock; 134254897Serwin client_list_t clients; /*%< All active clients */ 135254897Serwin 136254897Serwin /* Lock covers the recursing list */ 137254897Serwin isc_mutex_t reclock; 138254897Serwin client_list_t recursing; /*%< Recursing clients */ 139254897Serwin 140170222Sdougb#if NMCTXS > 0 141170222Sdougb /*%< mctx pool for clients. */ 142170222Sdougb unsigned int nextmctx; 143170222Sdougb isc_mem_t * mctxpool[NMCTXS]; 144170222Sdougb#endif 145135446Strhodes}; 146135446Strhodes 147135446Strhodes#define MANAGER_MAGIC ISC_MAGIC('N', 'S', 'C', 'm') 148135446Strhodes#define VALID_MANAGER(m) ISC_MAGIC_VALID(m, MANAGER_MAGIC) 149135446Strhodes 150186462Sdougb/*! 151135446Strhodes * Client object states. Ordering is significant: higher-numbered 152135446Strhodes * states are generally "more active", meaning that the client can 153135446Strhodes * have more dynamically allocated data, outstanding events, etc. 154135446Strhodes * In the list below, any such properties listed for state N 155135446Strhodes * also apply to any state > N. 156135446Strhodes * 157135446Strhodes * To force the client into a less active state, set client->newstate 158135446Strhodes * to that state and call exit_check(). This will cause any 159135446Strhodes * activities defined for higher-numbered states to be aborted. 160135446Strhodes */ 161135446Strhodes 162135446Strhodes#define NS_CLIENTSTATE_FREED 0 163170222Sdougb/*%< 164135446Strhodes * The client object no longer exists. 165135446Strhodes */ 166135446Strhodes 167135446Strhodes#define NS_CLIENTSTATE_INACTIVE 1 168170222Sdougb/*%< 169135446Strhodes * The client object exists and has a task and timer. 170135446Strhodes * Its "query" struct and sendbuf are initialized. 171135446Strhodes * It is on the client manager's list of inactive clients. 172135446Strhodes * It has a message and OPT, both in the reset state. 173135446Strhodes */ 174135446Strhodes 175135446Strhodes#define NS_CLIENTSTATE_READY 2 176170222Sdougb/*%< 177135446Strhodes * The client object is either a TCP or a UDP one, and 178135446Strhodes * it is associated with a network interface. It is on the 179135446Strhodes * client manager's list of active clients. 180135446Strhodes * 181135446Strhodes * If it is a TCP client object, it has a TCP listener socket 182135446Strhodes * and an outstanding TCP listen request. 183135446Strhodes * 184135446Strhodes * If it is a UDP client object, it has a UDP listener socket 185135446Strhodes * and an outstanding UDP receive request. 186135446Strhodes */ 187135446Strhodes 188135446Strhodes#define NS_CLIENTSTATE_READING 3 189170222Sdougb/*%< 190135446Strhodes * The client object is a TCP client object that has received 191135446Strhodes * a connection. It has a tcpsocket, tcpmsg, TCP quota, and an 192135446Strhodes * outstanding TCP read request. This state is not used for 193135446Strhodes * UDP client objects. 194135446Strhodes */ 195135446Strhodes 196135446Strhodes#define NS_CLIENTSTATE_WORKING 4 197170222Sdougb/*%< 198135446Strhodes * The client object has received a request and is working 199135446Strhodes * on it. It has a view, and it may have any of a non-reset OPT, 200135446Strhodes * recursion quota, and an outstanding write request. 201135446Strhodes */ 202135446Strhodes 203254897Serwin#define NS_CLIENTSTATE_RECURSING 5 204254897Serwin/*%< 205254897Serwin * The client object is recursing. It will be on the 'recursing' 206254897Serwin * list. 207254897Serwin */ 208254897Serwin 209135446Strhodes#define NS_CLIENTSTATE_MAX 9 210170222Sdougb/*%< 211135446Strhodes * Sentinel value used to indicate "no state". When client->newstate 212135446Strhodes * has this value, we are not attempting to exit the current state. 213135446Strhodes * Must be greater than any valid state. 214135446Strhodes */ 215135446Strhodes 216165071Sdougb/* 217165071Sdougb * Enable ns_client_dropport() by default. 218165071Sdougb */ 219165071Sdougb#ifndef NS_CLIENT_DROPPORT 220165071Sdougb#define NS_CLIENT_DROPPORT 1 221165071Sdougb#endif 222135446Strhodes 223170222Sdougbunsigned int ns_client_requests; 224170222Sdougb 225135446Strhodesstatic void client_read(ns_client_t *client); 226135446Strhodesstatic void client_accept(ns_client_t *client); 227135446Strhodesstatic void client_udprecv(ns_client_t *client); 228135446Strhodesstatic void clientmgr_destroy(ns_clientmgr_t *manager); 229135446Strhodesstatic isc_boolean_t exit_check(ns_client_t *client); 230135446Strhodesstatic void ns_client_endrequest(ns_client_t *client); 231135446Strhodesstatic void client_start(isc_task_t *task, isc_event_t *event); 232135446Strhodesstatic void client_request(isc_task_t *task, isc_event_t *event); 233135446Strhodesstatic void ns_client_dumpmessage(ns_client_t *client, const char *reason); 234254897Serwinstatic isc_result_t get_client(ns_clientmgr_t *manager, ns_interface_t *ifp, 235254897Serwin dns_dispatch_t *disp, isc_boolean_t tcp); 236135446Strhodes 237135446Strhodesvoid 238153816Sdougbns_client_recursing(ns_client_t *client) { 239135446Strhodes REQUIRE(NS_CLIENT_VALID(client)); 240254897Serwin REQUIRE(client->state == NS_CLIENTSTATE_WORKING); 241135446Strhodes 242254897Serwin LOCK(&client->manager->reclock); 243254897Serwin client->newstate = client->state = NS_CLIENTSTATE_RECURSING; 244254897Serwin ISC_LIST_APPEND(client->manager->recursing, client, rlink); 245254897Serwin UNLOCK(&client->manager->reclock); 246135446Strhodes} 247135446Strhodes 248135446Strhodesvoid 249153816Sdougbns_client_killoldestquery(ns_client_t *client) { 250153816Sdougb ns_client_t *oldest; 251153816Sdougb REQUIRE(NS_CLIENT_VALID(client)); 252153816Sdougb 253254897Serwin LOCK(&client->manager->reclock); 254153816Sdougb oldest = ISC_LIST_HEAD(client->manager->recursing); 255153816Sdougb if (oldest != NULL) { 256254897Serwin ISC_LIST_UNLINK(client->manager->recursing, oldest, rlink); 257254897Serwin UNLOCK(&client->manager->reclock); 258153816Sdougb ns_query_cancel(oldest); 259254897Serwin } else 260254897Serwin UNLOCK(&client->manager->reclock); 261153816Sdougb} 262153816Sdougb 263153816Sdougbvoid 264135446Strhodesns_client_settimeout(ns_client_t *client, unsigned int seconds) { 265135446Strhodes isc_result_t result; 266135446Strhodes isc_interval_t interval; 267135446Strhodes 268135446Strhodes isc_interval_set(&interval, seconds, 0); 269135446Strhodes result = isc_timer_reset(client->timer, isc_timertype_once, NULL, 270135446Strhodes &interval, ISC_FALSE); 271135446Strhodes client->timerset = ISC_TRUE; 272135446Strhodes if (result != ISC_R_SUCCESS) { 273135446Strhodes ns_client_log(client, NS_LOGCATEGORY_CLIENT, 274135446Strhodes NS_LOGMODULE_CLIENT, ISC_LOG_ERROR, 275135446Strhodes "setting timeout: %s", 276135446Strhodes isc_result_totext(result)); 277135446Strhodes /* Continue anyway. */ 278135446Strhodes } 279135446Strhodes} 280135446Strhodes 281170222Sdougb/*% 282135446Strhodes * Check for a deactivation or shutdown request and take appropriate 283135446Strhodes * action. Returns ISC_TRUE if either is in progress; in this case 284135446Strhodes * the caller must no longer use the client object as it may have been 285135446Strhodes * freed. 286135446Strhodes */ 287135446Strhodesstatic isc_boolean_t 288135446Strhodesexit_check(ns_client_t *client) { 289254897Serwin isc_boolean_t destroy_manager = ISC_FALSE; 290254897Serwin ns_clientmgr_t *manager = NULL; 291135446Strhodes 292135446Strhodes REQUIRE(NS_CLIENT_VALID(client)); 293254897Serwin manager = client->manager; 294135446Strhodes 295135446Strhodes if (client->state <= client->newstate) 296135446Strhodes return (ISC_FALSE); /* Business as usual. */ 297135446Strhodes 298254897Serwin INSIST(client->newstate < NS_CLIENTSTATE_RECURSING); 299135446Strhodes 300135446Strhodes /* 301135446Strhodes * We need to detach from the view early when shutting down 302135446Strhodes * the server to break the following vicious circle: 303135446Strhodes * 304135446Strhodes * - The resolver will not shut down until the view refcount is zero 305135446Strhodes * - The view refcount does not go to zero until all clients detach 306135446Strhodes * - The client does not detach from the view until references is zero 307135446Strhodes * - references does not go to zero until the resolver has shut down 308135446Strhodes * 309135446Strhodes * Keep the view attached until any outstanding updates complete. 310135446Strhodes */ 311186462Sdougb if (client->nupdates == 0 && 312135446Strhodes client->newstate == NS_CLIENTSTATE_FREED && client->view != NULL) 313135446Strhodes dns_view_detach(&client->view); 314135446Strhodes 315254897Serwin if (client->state == NS_CLIENTSTATE_WORKING || 316254897Serwin client->state == NS_CLIENTSTATE_RECURSING) 317254897Serwin { 318135446Strhodes INSIST(client->newstate <= NS_CLIENTSTATE_READING); 319135446Strhodes /* 320135446Strhodes * Let the update processing complete. 321135446Strhodes */ 322135446Strhodes if (client->nupdates > 0) 323135446Strhodes return (ISC_TRUE); 324254897Serwin 325135446Strhodes /* 326135446Strhodes * We are trying to abort request processing. 327135446Strhodes */ 328135446Strhodes if (client->nsends > 0) { 329135446Strhodes isc_socket_t *socket; 330135446Strhodes if (TCP_CLIENT(client)) 331135446Strhodes socket = client->tcpsocket; 332135446Strhodes else 333135446Strhodes socket = client->udpsocket; 334135446Strhodes isc_socket_cancel(socket, client->task, 335135446Strhodes ISC_SOCKCANCEL_SEND); 336135446Strhodes } 337135446Strhodes 338135446Strhodes if (! (client->nsends == 0 && client->nrecvs == 0 && 339135446Strhodes client->references == 0)) 340135446Strhodes { 341135446Strhodes /* 342135446Strhodes * Still waiting for I/O cancel completion. 343135446Strhodes * or lingering references. 344135446Strhodes */ 345135446Strhodes return (ISC_TRUE); 346135446Strhodes } 347254897Serwin 348135446Strhodes /* 349135446Strhodes * I/O cancel is complete. Burn down all state 350165071Sdougb * related to the current request. Ensure that 351254897Serwin * the client is no longer on the recursing list. 352254897Serwin * 353254897Serwin * We need to check whether the client is still linked, 354254897Serwin * because it may already have been removed from the 355254897Serwin * recursing list by ns_client_killoldestquery() 356135446Strhodes */ 357254897Serwin if (client->state == NS_CLIENTSTATE_RECURSING) { 358254897Serwin LOCK(&manager->reclock); 359254897Serwin if (ISC_LINK_LINKED(client, rlink)) 360254897Serwin ISC_LIST_UNLINK(manager->recursing, 361254897Serwin client, rlink); 362254897Serwin UNLOCK(&manager->reclock); 363165071Sdougb } 364135446Strhodes ns_client_endrequest(client); 365135446Strhodes 366135446Strhodes client->state = NS_CLIENTSTATE_READING; 367135446Strhodes INSIST(client->recursionquota == NULL); 368254897Serwin 369135446Strhodes if (NS_CLIENTSTATE_READING == client->newstate) { 370135446Strhodes client_read(client); 371135446Strhodes client->newstate = NS_CLIENTSTATE_MAX; 372135446Strhodes return (ISC_TRUE); /* We're done. */ 373135446Strhodes } 374135446Strhodes } 375135446Strhodes 376135446Strhodes if (client->state == NS_CLIENTSTATE_READING) { 377135446Strhodes /* 378135446Strhodes * We are trying to abort the current TCP connection, 379135446Strhodes * if any. 380135446Strhodes */ 381135446Strhodes INSIST(client->recursionquota == NULL); 382135446Strhodes INSIST(client->newstate <= NS_CLIENTSTATE_READY); 383135446Strhodes if (client->nreads > 0) 384135446Strhodes dns_tcpmsg_cancelread(&client->tcpmsg); 385135446Strhodes if (! client->nreads == 0) { 386135446Strhodes /* Still waiting for read cancel completion. */ 387135446Strhodes return (ISC_TRUE); 388135446Strhodes } 389135446Strhodes 390135446Strhodes if (client->tcpmsg_valid) { 391135446Strhodes dns_tcpmsg_invalidate(&client->tcpmsg); 392135446Strhodes client->tcpmsg_valid = ISC_FALSE; 393135446Strhodes } 394135446Strhodes if (client->tcpsocket != NULL) { 395135446Strhodes CTRACE("closetcp"); 396135446Strhodes isc_socket_detach(&client->tcpsocket); 397135446Strhodes } 398135446Strhodes 399135446Strhodes if (client->tcpquota != NULL) 400135446Strhodes isc_quota_detach(&client->tcpquota); 401135446Strhodes 402135446Strhodes if (client->timerset) { 403135446Strhodes (void)isc_timer_reset(client->timer, 404135446Strhodes isc_timertype_inactive, 405135446Strhodes NULL, NULL, ISC_TRUE); 406135446Strhodes client->timerset = ISC_FALSE; 407135446Strhodes } 408135446Strhodes 409135446Strhodes client->peeraddr_valid = ISC_FALSE; 410135446Strhodes 411135446Strhodes client->state = NS_CLIENTSTATE_READY; 412135446Strhodes INSIST(client->recursionquota == NULL); 413135446Strhodes 414135446Strhodes /* 415135446Strhodes * Now the client is ready to accept a new TCP connection 416135446Strhodes * or UDP request, but we may have enough clients doing 417135446Strhodes * that already. Check whether this client needs to remain 418135446Strhodes * active and force it to go inactive if not. 419254897Serwin * 420254897Serwin * UDP clients go inactive at this point, but TCP clients 421254897Serwin * may remain active if we have fewer active TCP client 422254897Serwin * objects than desired due to an earlier quota exhaustion. 423135446Strhodes */ 424254897Serwin if (client->mortal && TCP_CLIENT(client) && !ns_g_clienttest) { 425254897Serwin LOCK(&client->interface->lock); 426254897Serwin if (client->interface->ntcpcurrent < 427254897Serwin client->interface->ntcptarget) 428254897Serwin client->mortal = ISC_FALSE; 429254897Serwin UNLOCK(&client->interface->lock); 430254897Serwin } 431135446Strhodes 432254897Serwin /* 433254897Serwin * We don't need the client; send it to the inactive 434254897Serwin * queue for recycling. 435254897Serwin */ 436254897Serwin if (client->mortal) { 437254897Serwin if (client->newstate > NS_CLIENTSTATE_INACTIVE) 438254897Serwin client->newstate = NS_CLIENTSTATE_INACTIVE; 439254897Serwin } 440254897Serwin 441135446Strhodes if (NS_CLIENTSTATE_READY == client->newstate) { 442135446Strhodes if (TCP_CLIENT(client)) { 443135446Strhodes client_accept(client); 444135446Strhodes } else 445135446Strhodes client_udprecv(client); 446135446Strhodes client->newstate = NS_CLIENTSTATE_MAX; 447135446Strhodes return (ISC_TRUE); 448135446Strhodes } 449135446Strhodes } 450135446Strhodes 451135446Strhodes if (client->state == NS_CLIENTSTATE_READY) { 452135446Strhodes INSIST(client->newstate <= NS_CLIENTSTATE_INACTIVE); 453254897Serwin 454135446Strhodes /* 455135446Strhodes * We are trying to enter the inactive state. 456135446Strhodes */ 457135446Strhodes if (client->naccepts > 0) 458135446Strhodes isc_socket_cancel(client->tcplistener, client->task, 459135446Strhodes ISC_SOCKCANCEL_ACCEPT); 460135446Strhodes 461254897Serwin /* Still waiting for accept cancel completion. */ 462254897Serwin if (! (client->naccepts == 0)) 463135446Strhodes return (ISC_TRUE); 464254897Serwin 465135446Strhodes /* Accept cancel is complete. */ 466135446Strhodes if (client->nrecvs > 0) 467135446Strhodes isc_socket_cancel(client->udpsocket, client->task, 468135446Strhodes ISC_SOCKCANCEL_RECV); 469254897Serwin 470254897Serwin /* Still waiting for recv cancel completion. */ 471254897Serwin if (! (client->nrecvs == 0)) 472135446Strhodes return (ISC_TRUE); 473135446Strhodes 474254897Serwin /* Still waiting for control event to be delivered */ 475254897Serwin if (client->nctls > 0) 476135446Strhodes return (ISC_TRUE); 477135446Strhodes 478135446Strhodes /* Deactivate the client. */ 479135446Strhodes if (client->interface) 480135446Strhodes ns_interface_detach(&client->interface); 481135446Strhodes 482135446Strhodes INSIST(client->naccepts == 0); 483135446Strhodes INSIST(client->recursionquota == NULL); 484135446Strhodes if (client->tcplistener != NULL) 485135446Strhodes isc_socket_detach(&client->tcplistener); 486135446Strhodes 487135446Strhodes if (client->udpsocket != NULL) 488135446Strhodes isc_socket_detach(&client->udpsocket); 489135446Strhodes 490135446Strhodes if (client->dispatch != NULL) 491135446Strhodes dns_dispatch_detach(&client->dispatch); 492135446Strhodes 493135446Strhodes client->attributes = 0; 494135446Strhodes client->mortal = ISC_FALSE; 495135446Strhodes 496135446Strhodes /* 497135446Strhodes * Put the client on the inactive list. If we are aiming for 498135446Strhodes * the "freed" state, it will be removed from the inactive 499135446Strhodes * list shortly, and we need to keep the manager locked until 500135446Strhodes * that has been done, lest the manager decide to reactivate 501135446Strhodes * the dying client inbetween. 502135446Strhodes */ 503135446Strhodes client->state = NS_CLIENTSTATE_INACTIVE; 504135446Strhodes INSIST(client->recursionquota == NULL); 505135446Strhodes 506135446Strhodes if (client->state == client->newstate) { 507135446Strhodes client->newstate = NS_CLIENTSTATE_MAX; 508254897Serwin if (!ns_g_clienttest && manager != NULL && 509254897Serwin !manager->exiting) 510254897Serwin ISC_QUEUE_PUSH(manager->inactive, client, 511254897Serwin ilink); 512193149Sdougb if (client->needshutdown) 513193149Sdougb isc_task_shutdown(client->task); 514254897Serwin return (ISC_TRUE); 515135446Strhodes } 516135446Strhodes } 517135446Strhodes 518135446Strhodes if (client->state == NS_CLIENTSTATE_INACTIVE) { 519135446Strhodes INSIST(client->newstate == NS_CLIENTSTATE_FREED); 520135446Strhodes /* 521135446Strhodes * We are trying to free the client. 522135446Strhodes * 523135446Strhodes * When "shuttingdown" is true, either the task has received 524135446Strhodes * its shutdown event or no shutdown event has ever been 525135446Strhodes * set up. Thus, we have no outstanding shutdown 526135446Strhodes * event at this point. 527135446Strhodes */ 528135446Strhodes REQUIRE(client->state == NS_CLIENTSTATE_INACTIVE); 529135446Strhodes 530135446Strhodes INSIST(client->recursionquota == NULL); 531254897Serwin INSIST(!ISC_QLINK_LINKED(client, ilink)); 532135446Strhodes 533135446Strhodes ns_query_free(client); 534135446Strhodes isc_mem_put(client->mctx, client->recvbuf, RECV_BUFFER_SIZE); 535135446Strhodes isc_event_free((isc_event_t **)&client->sendevent); 536135446Strhodes isc_event_free((isc_event_t **)&client->recvevent); 537135446Strhodes isc_timer_detach(&client->timer); 538135446Strhodes 539135446Strhodes if (client->tcpbuf != NULL) 540254897Serwin isc_mem_put(client->mctx, client->tcpbuf, 541254897Serwin TCP_BUFFER_SIZE); 542135446Strhodes if (client->opt != NULL) { 543135446Strhodes INSIST(dns_rdataset_isassociated(client->opt)); 544135446Strhodes dns_rdataset_disassociate(client->opt); 545254897Serwin dns_message_puttemprdataset(client->message, 546254897Serwin &client->opt); 547135446Strhodes } 548254897Serwin 549135446Strhodes dns_message_destroy(&client->message); 550254897Serwin if (manager != NULL) { 551254897Serwin LOCK(&manager->listlock); 552254897Serwin ISC_LIST_UNLINK(manager->clients, client, link); 553254897Serwin LOCK(&manager->lock); 554135446Strhodes if (manager->exiting && 555254897Serwin ISC_LIST_EMPTY(manager->clients)) 556254897Serwin destroy_manager = ISC_TRUE; 557254897Serwin UNLOCK(&manager->lock); 558254897Serwin UNLOCK(&manager->listlock); 559135446Strhodes } 560254897Serwin 561135446Strhodes /* 562135446Strhodes * Detaching the task must be done after unlinking from 563135446Strhodes * the manager's lists because the manager accesses 564135446Strhodes * client->task. 565135446Strhodes */ 566135446Strhodes if (client->task != NULL) 567135446Strhodes isc_task_detach(&client->task); 568135446Strhodes 569135446Strhodes CTRACE("free"); 570135446Strhodes client->magic = 0; 571254897Serwin 572193149Sdougb /* 573193149Sdougb * Check that there are no other external references to 574193149Sdougb * the memory context. 575193149Sdougb */ 576193149Sdougb if (ns_g_clienttest && isc_mem_references(client->mctx) != 1) { 577193149Sdougb isc_mem_stats(client->mctx, stderr); 578193149Sdougb INSIST(0); 579193149Sdougb } 580170222Sdougb isc_mem_putanddetach(&client->mctx, client, sizeof(*client)); 581135446Strhodes } 582135446Strhodes 583254897Serwin if (destroy_manager && manager != NULL) 584254897Serwin clientmgr_destroy(manager); 585135446Strhodes 586135446Strhodes return (ISC_TRUE); 587135446Strhodes} 588135446Strhodes 589170222Sdougb/*% 590135446Strhodes * The client's task has received the client's control event 591135446Strhodes * as part of the startup process. 592135446Strhodes */ 593135446Strhodesstatic void 594135446Strhodesclient_start(isc_task_t *task, isc_event_t *event) { 595135446Strhodes ns_client_t *client = (ns_client_t *) event->ev_arg; 596135446Strhodes 597135446Strhodes INSIST(task == client->task); 598135446Strhodes 599135446Strhodes UNUSED(task); 600135446Strhodes 601135446Strhodes INSIST(client->nctls == 1); 602135446Strhodes client->nctls--; 603135446Strhodes 604135446Strhodes if (exit_check(client)) 605135446Strhodes return; 606135446Strhodes 607135446Strhodes if (TCP_CLIENT(client)) { 608135446Strhodes client_accept(client); 609135446Strhodes } else { 610135446Strhodes client_udprecv(client); 611135446Strhodes } 612135446Strhodes} 613135446Strhodes 614135446Strhodes 615170222Sdougb/*% 616135446Strhodes * The client's task has received a shutdown event. 617135446Strhodes */ 618135446Strhodesstatic void 619135446Strhodesclient_shutdown(isc_task_t *task, isc_event_t *event) { 620135446Strhodes ns_client_t *client; 621135446Strhodes 622135446Strhodes REQUIRE(event != NULL); 623135446Strhodes REQUIRE(event->ev_type == ISC_TASKEVENT_SHUTDOWN); 624135446Strhodes client = event->ev_arg; 625135446Strhodes REQUIRE(NS_CLIENT_VALID(client)); 626135446Strhodes REQUIRE(task == client->task); 627135446Strhodes 628135446Strhodes UNUSED(task); 629135446Strhodes 630135446Strhodes CTRACE("shutdown"); 631135446Strhodes 632135446Strhodes isc_event_free(&event); 633135446Strhodes 634135446Strhodes if (client->shutdown != NULL) { 635135446Strhodes (client->shutdown)(client->shutdown_arg, ISC_R_SHUTTINGDOWN); 636135446Strhodes client->shutdown = NULL; 637135446Strhodes client->shutdown_arg = NULL; 638135446Strhodes } 639135446Strhodes 640254897Serwin if (ISC_QLINK_LINKED(client, ilink)) 641254897Serwin ISC_QUEUE_UNLINK(client->manager->inactive, client, ilink); 642254897Serwin 643135446Strhodes client->newstate = NS_CLIENTSTATE_FREED; 644193149Sdougb client->needshutdown = ISC_FALSE; 645135446Strhodes (void)exit_check(client); 646135446Strhodes} 647135446Strhodes 648135446Strhodesstatic void 649135446Strhodesns_client_endrequest(ns_client_t *client) { 650135446Strhodes INSIST(client->naccepts == 0); 651135446Strhodes INSIST(client->nreads == 0); 652135446Strhodes INSIST(client->nsends == 0); 653135446Strhodes INSIST(client->nrecvs == 0); 654135446Strhodes INSIST(client->nupdates == 0); 655254897Serwin INSIST(client->state == NS_CLIENTSTATE_WORKING || 656254897Serwin client->state == NS_CLIENTSTATE_RECURSING); 657135446Strhodes 658135446Strhodes CTRACE("endrequest"); 659135446Strhodes 660135446Strhodes if (client->next != NULL) { 661135446Strhodes (client->next)(client); 662135446Strhodes client->next = NULL; 663135446Strhodes } 664135446Strhodes 665135446Strhodes if (client->view != NULL) 666135446Strhodes dns_view_detach(&client->view); 667135446Strhodes if (client->opt != NULL) { 668135446Strhodes INSIST(dns_rdataset_isassociated(client->opt)); 669135446Strhodes dns_rdataset_disassociate(client->opt); 670135446Strhodes dns_message_puttemprdataset(client->message, &client->opt); 671135446Strhodes } 672135446Strhodes 673225361Sdougb client->signer = NULL; 674135446Strhodes client->udpsize = 512; 675135446Strhodes client->extflags = 0; 676170222Sdougb client->ednsversion = -1; 677135446Strhodes dns_message_reset(client->message, DNS_MESSAGE_INTENTPARSE); 678135446Strhodes 679135446Strhodes if (client->recursionquota != NULL) 680135446Strhodes isc_quota_detach(&client->recursionquota); 681135446Strhodes 682135446Strhodes /* 683135446Strhodes * Clear all client attributes that are specific to 684135446Strhodes * the request; that's all except the TCP flag. 685135446Strhodes */ 686135446Strhodes client->attributes &= NS_CLIENTATTR_TCP; 687135446Strhodes} 688135446Strhodes 689135446Strhodesvoid 690135446Strhodesns_client_next(ns_client_t *client, isc_result_t result) { 691135446Strhodes int newstate; 692135446Strhodes 693135446Strhodes REQUIRE(NS_CLIENT_VALID(client)); 694135446Strhodes REQUIRE(client->state == NS_CLIENTSTATE_WORKING || 695254897Serwin client->state == NS_CLIENTSTATE_RECURSING || 696135446Strhodes client->state == NS_CLIENTSTATE_READING); 697135446Strhodes 698135446Strhodes CTRACE("next"); 699135446Strhodes 700135446Strhodes if (result != ISC_R_SUCCESS) 701135446Strhodes ns_client_log(client, DNS_LOGCATEGORY_SECURITY, 702135446Strhodes NS_LOGMODULE_CLIENT, ISC_LOG_DEBUG(3), 703135446Strhodes "request failed: %s", isc_result_totext(result)); 704135446Strhodes 705135446Strhodes /* 706135446Strhodes * An error processing a TCP request may have left 707135446Strhodes * the connection out of sync. To be safe, we always 708135446Strhodes * sever the connection when result != ISC_R_SUCCESS. 709135446Strhodes */ 710135446Strhodes if (result == ISC_R_SUCCESS && TCP_CLIENT(client)) 711135446Strhodes newstate = NS_CLIENTSTATE_READING; 712135446Strhodes else 713135446Strhodes newstate = NS_CLIENTSTATE_READY; 714135446Strhodes 715135446Strhodes if (client->newstate > newstate) 716135446Strhodes client->newstate = newstate; 717135446Strhodes (void)exit_check(client); 718135446Strhodes} 719135446Strhodes 720135446Strhodes 721135446Strhodesstatic void 722135446Strhodesclient_senddone(isc_task_t *task, isc_event_t *event) { 723135446Strhodes ns_client_t *client; 724135446Strhodes isc_socketevent_t *sevent = (isc_socketevent_t *) event; 725135446Strhodes 726135446Strhodes REQUIRE(sevent != NULL); 727135446Strhodes REQUIRE(sevent->ev_type == ISC_SOCKEVENT_SENDDONE); 728135446Strhodes client = sevent->ev_arg; 729135446Strhodes REQUIRE(NS_CLIENT_VALID(client)); 730135446Strhodes REQUIRE(task == client->task); 731135446Strhodes REQUIRE(sevent == client->sendevent); 732135446Strhodes 733135446Strhodes UNUSED(task); 734135446Strhodes 735135446Strhodes CTRACE("senddone"); 736135446Strhodes 737135446Strhodes if (sevent->result != ISC_R_SUCCESS) 738135446Strhodes ns_client_log(client, NS_LOGCATEGORY_CLIENT, 739135446Strhodes NS_LOGMODULE_CLIENT, ISC_LOG_WARNING, 740135446Strhodes "error sending response: %s", 741135446Strhodes isc_result_totext(sevent->result)); 742135446Strhodes 743135446Strhodes INSIST(client->nsends > 0); 744135446Strhodes client->nsends--; 745135446Strhodes 746135446Strhodes if (client->tcpbuf != NULL) { 747135446Strhodes INSIST(TCP_CLIENT(client)); 748135446Strhodes isc_mem_put(client->mctx, client->tcpbuf, TCP_BUFFER_SIZE); 749135446Strhodes client->tcpbuf = NULL; 750135446Strhodes } 751135446Strhodes 752135446Strhodes ns_client_next(client, ISC_R_SUCCESS); 753135446Strhodes} 754135446Strhodes 755170222Sdougb/*% 756135446Strhodes * We only want to fail with ISC_R_NOSPACE when called from 757135446Strhodes * ns_client_sendraw() and not when called from ns_client_send(), 758135446Strhodes * tcpbuffer is NULL when called from ns_client_sendraw() and 759135446Strhodes * length != 0. tcpbuffer != NULL when called from ns_client_send() 760135446Strhodes * and length == 0. 761135446Strhodes */ 762135446Strhodes 763135446Strhodesstatic isc_result_t 764135446Strhodesclient_allocsendbuf(ns_client_t *client, isc_buffer_t *buffer, 765135446Strhodes isc_buffer_t *tcpbuffer, isc_uint32_t length, 766135446Strhodes unsigned char *sendbuf, unsigned char **datap) 767135446Strhodes{ 768135446Strhodes unsigned char *data; 769135446Strhodes isc_uint32_t bufsize; 770135446Strhodes isc_result_t result; 771135446Strhodes 772135446Strhodes INSIST(datap != NULL); 773135446Strhodes INSIST((tcpbuffer == NULL && length != 0) || 774135446Strhodes (tcpbuffer != NULL && length == 0)); 775135446Strhodes 776135446Strhodes if (TCP_CLIENT(client)) { 777135446Strhodes INSIST(client->tcpbuf == NULL); 778135446Strhodes if (length + 2 > TCP_BUFFER_SIZE) { 779135446Strhodes result = ISC_R_NOSPACE; 780135446Strhodes goto done; 781135446Strhodes } 782135446Strhodes client->tcpbuf = isc_mem_get(client->mctx, TCP_BUFFER_SIZE); 783135446Strhodes if (client->tcpbuf == NULL) { 784135446Strhodes result = ISC_R_NOMEMORY; 785135446Strhodes goto done; 786135446Strhodes } 787135446Strhodes data = client->tcpbuf; 788135446Strhodes if (tcpbuffer != NULL) { 789135446Strhodes isc_buffer_init(tcpbuffer, data, TCP_BUFFER_SIZE); 790135446Strhodes isc_buffer_init(buffer, data + 2, TCP_BUFFER_SIZE - 2); 791135446Strhodes } else { 792135446Strhodes isc_buffer_init(buffer, data, TCP_BUFFER_SIZE); 793135446Strhodes INSIST(length <= 0xffff); 794135446Strhodes isc_buffer_putuint16(buffer, (isc_uint16_t)length); 795135446Strhodes } 796135446Strhodes } else { 797135446Strhodes data = sendbuf; 798135446Strhodes if (client->udpsize < SEND_BUFFER_SIZE) 799135446Strhodes bufsize = client->udpsize; 800135446Strhodes else 801135446Strhodes bufsize = SEND_BUFFER_SIZE; 802135446Strhodes if (length > bufsize) { 803135446Strhodes result = ISC_R_NOSPACE; 804135446Strhodes goto done; 805135446Strhodes } 806135446Strhodes isc_buffer_init(buffer, data, bufsize); 807135446Strhodes } 808135446Strhodes *datap = data; 809135446Strhodes result = ISC_R_SUCCESS; 810135446Strhodes 811135446Strhodes done: 812135446Strhodes return (result); 813135446Strhodes} 814135446Strhodes 815135446Strhodesstatic isc_result_t 816135446Strhodesclient_sendpkg(ns_client_t *client, isc_buffer_t *buffer) { 817135446Strhodes struct in6_pktinfo *pktinfo; 818135446Strhodes isc_result_t result; 819135446Strhodes isc_region_t r; 820135446Strhodes isc_sockaddr_t *address; 821135446Strhodes isc_socket_t *socket; 822135446Strhodes isc_netaddr_t netaddr; 823135446Strhodes int match; 824135446Strhodes unsigned int sockflags = ISC_SOCKFLAG_IMMEDIATE; 825135446Strhodes 826135446Strhodes if (TCP_CLIENT(client)) { 827135446Strhodes socket = client->tcpsocket; 828135446Strhodes address = NULL; 829135446Strhodes } else { 830135446Strhodes socket = client->udpsocket; 831135446Strhodes address = &client->peeraddr; 832135446Strhodes 833135446Strhodes isc_netaddr_fromsockaddr(&netaddr, &client->peeraddr); 834135446Strhodes if (ns_g_server->blackholeacl != NULL && 835135446Strhodes dns_acl_match(&netaddr, NULL, 836186462Sdougb ns_g_server->blackholeacl, 837135446Strhodes &ns_g_server->aclenv, 838135446Strhodes &match, NULL) == ISC_R_SUCCESS && 839135446Strhodes match > 0) 840135446Strhodes return (DNS_R_BLACKHOLED); 841135446Strhodes sockflags |= ISC_SOCKFLAG_NORETRY; 842135446Strhodes } 843135446Strhodes 844135446Strhodes if ((client->attributes & NS_CLIENTATTR_PKTINFO) != 0 && 845135446Strhodes (client->attributes & NS_CLIENTATTR_MULTICAST) == 0) 846135446Strhodes pktinfo = &client->pktinfo; 847135446Strhodes else 848135446Strhodes pktinfo = NULL; 849135446Strhodes 850135446Strhodes isc_buffer_usedregion(buffer, &r); 851135446Strhodes 852135446Strhodes CTRACE("sendto"); 853186462Sdougb 854135446Strhodes result = isc_socket_sendto2(socket, &r, client->task, 855135446Strhodes address, pktinfo, 856135446Strhodes client->sendevent, sockflags); 857135446Strhodes if (result == ISC_R_SUCCESS || result == ISC_R_INPROGRESS) { 858135446Strhodes client->nsends++; 859135446Strhodes if (result == ISC_R_SUCCESS) 860135446Strhodes client_senddone(client->task, 861135446Strhodes (isc_event_t *)client->sendevent); 862135446Strhodes result = ISC_R_SUCCESS; 863135446Strhodes } 864135446Strhodes return (result); 865135446Strhodes} 866135446Strhodes 867135446Strhodesvoid 868135446Strhodesns_client_sendraw(ns_client_t *client, dns_message_t *message) { 869135446Strhodes isc_result_t result; 870135446Strhodes unsigned char *data; 871135446Strhodes isc_buffer_t buffer; 872135446Strhodes isc_region_t r; 873135446Strhodes isc_region_t *mr; 874135446Strhodes unsigned char sendbuf[SEND_BUFFER_SIZE]; 875135446Strhodes 876135446Strhodes REQUIRE(NS_CLIENT_VALID(client)); 877135446Strhodes 878135446Strhodes CTRACE("sendraw"); 879135446Strhodes 880135446Strhodes mr = dns_message_getrawmessage(message); 881135446Strhodes if (mr == NULL) { 882135446Strhodes result = ISC_R_UNEXPECTEDEND; 883135446Strhodes goto done; 884135446Strhodes } 885135446Strhodes 886135446Strhodes result = client_allocsendbuf(client, &buffer, NULL, mr->length, 887135446Strhodes sendbuf, &data); 888135446Strhodes if (result != ISC_R_SUCCESS) 889135446Strhodes goto done; 890135446Strhodes 891135446Strhodes /* 892135446Strhodes * Copy message to buffer and fixup id. 893135446Strhodes */ 894135446Strhodes isc_buffer_availableregion(&buffer, &r); 895135446Strhodes result = isc_buffer_copyregion(&buffer, mr); 896135446Strhodes if (result != ISC_R_SUCCESS) 897135446Strhodes goto done; 898135446Strhodes r.base[0] = (client->message->id >> 8) & 0xff; 899135446Strhodes r.base[1] = client->message->id & 0xff; 900135446Strhodes 901135446Strhodes result = client_sendpkg(client, &buffer); 902135446Strhodes if (result == ISC_R_SUCCESS) 903135446Strhodes return; 904135446Strhodes 905135446Strhodes done: 906135446Strhodes if (client->tcpbuf != NULL) { 907135446Strhodes isc_mem_put(client->mctx, client->tcpbuf, TCP_BUFFER_SIZE); 908135446Strhodes client->tcpbuf = NULL; 909135446Strhodes } 910135446Strhodes ns_client_next(client, result); 911135446Strhodes} 912135446Strhodes 913135446Strhodesvoid 914135446Strhodesns_client_send(ns_client_t *client) { 915135446Strhodes isc_result_t result; 916135446Strhodes unsigned char *data; 917135446Strhodes isc_buffer_t buffer; 918135446Strhodes isc_buffer_t tcpbuffer; 919135446Strhodes isc_region_t r; 920135446Strhodes dns_compress_t cctx; 921135446Strhodes isc_boolean_t cleanup_cctx = ISC_FALSE; 922135446Strhodes unsigned char sendbuf[SEND_BUFFER_SIZE]; 923224092Sdougb unsigned int render_opts; 924135446Strhodes unsigned int preferred_glue; 925193149Sdougb isc_boolean_t opt_included = ISC_FALSE; 926135446Strhodes 927135446Strhodes REQUIRE(NS_CLIENT_VALID(client)); 928135446Strhodes 929135446Strhodes CTRACE("send"); 930135446Strhodes 931135446Strhodes if ((client->attributes & NS_CLIENTATTR_RA) != 0) 932135446Strhodes client->message->flags |= DNS_MESSAGEFLAG_RA; 933135446Strhodes 934135446Strhodes if ((client->attributes & NS_CLIENTATTR_WANTDNSSEC) != 0) 935224092Sdougb render_opts = 0; 936135446Strhodes else 937224092Sdougb render_opts = DNS_MESSAGERENDER_OMITDNSSEC; 938234010Sdougb 939234010Sdougb preferred_glue = 0; 940234010Sdougb if (client->view != NULL) { 941234010Sdougb if (client->view->preferred_glue == dns_rdatatype_a) 942234010Sdougb preferred_glue = DNS_MESSAGERENDER_PREFER_A; 943234010Sdougb else if (client->view->preferred_glue == dns_rdatatype_aaaa) 944234010Sdougb preferred_glue = DNS_MESSAGERENDER_PREFER_AAAA; 945234010Sdougb } 946234010Sdougb 947224092Sdougb#ifdef ALLOW_FILTER_AAAA_ON_V4 948224092Sdougb /* 949224092Sdougb * filter-aaaa-on-v4 yes or break-dnssec option to suppress 950224092Sdougb * AAAA records 951224092Sdougb * We already know that request came via IPv4, 952224092Sdougb * that we have both AAAA and A records, 953224092Sdougb * and that we either have no signatures that the client wants 954224092Sdougb * or we are supposed to break DNSSEC. 955234010Sdougb * 956234010Sdougb * Override preferred glue if necessary. 957224092Sdougb */ 958234010Sdougb if ((client->attributes & NS_CLIENTATTR_FILTER_AAAA) != 0) { 959224092Sdougb render_opts |= DNS_MESSAGERENDER_FILTER_AAAA; 960234010Sdougb if (preferred_glue == DNS_MESSAGERENDER_PREFER_AAAA) 961135446Strhodes preferred_glue = DNS_MESSAGERENDER_PREFER_A; 962135446Strhodes } 963234010Sdougb#endif 964135446Strhodes 965135446Strhodes /* 966135446Strhodes * XXXRTH The following doesn't deal with TCP buffer resizing. 967135446Strhodes */ 968135446Strhodes result = client_allocsendbuf(client, &buffer, &tcpbuffer, 0, 969135446Strhodes sendbuf, &data); 970135446Strhodes if (result != ISC_R_SUCCESS) 971135446Strhodes goto done; 972135446Strhodes 973135446Strhodes result = dns_compress_init(&cctx, -1, client->mctx); 974135446Strhodes if (result != ISC_R_SUCCESS) 975135446Strhodes goto done; 976262706Serwin dns_compress_setsensitive(&cctx, ISC_TRUE); 977135446Strhodes cleanup_cctx = ISC_TRUE; 978135446Strhodes 979135446Strhodes result = dns_message_renderbegin(client->message, &cctx, &buffer); 980135446Strhodes if (result != ISC_R_SUCCESS) 981135446Strhodes goto done; 982193149Sdougb 983135446Strhodes if (client->opt != NULL) { 984135446Strhodes result = dns_message_setopt(client->message, client->opt); 985193149Sdougb opt_included = ISC_TRUE; 986135446Strhodes client->opt = NULL; 987135446Strhodes if (result != ISC_R_SUCCESS) 988135446Strhodes goto done; 989135446Strhodes } 990135446Strhodes result = dns_message_rendersection(client->message, 991135446Strhodes DNS_SECTION_QUESTION, 0); 992135446Strhodes if (result == ISC_R_NOSPACE) { 993135446Strhodes client->message->flags |= DNS_MESSAGEFLAG_TC; 994135446Strhodes goto renderend; 995135446Strhodes } 996135446Strhodes if (result != ISC_R_SUCCESS) 997135446Strhodes goto done; 998262706Serwin#ifdef USE_RRL 999262706Serwin /* 1000262706Serwin * Stop after the question if TC was set for rate limiting. 1001262706Serwin */ 1002262706Serwin if ((client->message->flags & DNS_MESSAGEFLAG_TC) != 0) 1003262706Serwin goto renderend; 1004262706Serwin#endif /* USE_RRL */ 1005135446Strhodes result = dns_message_rendersection(client->message, 1006135446Strhodes DNS_SECTION_ANSWER, 1007135446Strhodes DNS_MESSAGERENDER_PARTIAL | 1008224092Sdougb render_opts); 1009135446Strhodes if (result == ISC_R_NOSPACE) { 1010135446Strhodes client->message->flags |= DNS_MESSAGEFLAG_TC; 1011135446Strhodes goto renderend; 1012135446Strhodes } 1013135446Strhodes if (result != ISC_R_SUCCESS) 1014135446Strhodes goto done; 1015135446Strhodes result = dns_message_rendersection(client->message, 1016135446Strhodes DNS_SECTION_AUTHORITY, 1017135446Strhodes DNS_MESSAGERENDER_PARTIAL | 1018224092Sdougb render_opts); 1019135446Strhodes if (result == ISC_R_NOSPACE) { 1020135446Strhodes client->message->flags |= DNS_MESSAGEFLAG_TC; 1021135446Strhodes goto renderend; 1022135446Strhodes } 1023135446Strhodes if (result != ISC_R_SUCCESS) 1024135446Strhodes goto done; 1025135446Strhodes result = dns_message_rendersection(client->message, 1026135446Strhodes DNS_SECTION_ADDITIONAL, 1027224092Sdougb preferred_glue | render_opts); 1028135446Strhodes if (result != ISC_R_SUCCESS && result != ISC_R_NOSPACE) 1029135446Strhodes goto done; 1030135446Strhodes renderend: 1031135446Strhodes result = dns_message_renderend(client->message); 1032135446Strhodes 1033135446Strhodes if (result != ISC_R_SUCCESS) 1034135446Strhodes goto done; 1035135446Strhodes 1036135446Strhodes if (cleanup_cctx) { 1037135446Strhodes dns_compress_invalidate(&cctx); 1038135446Strhodes cleanup_cctx = ISC_FALSE; 1039135446Strhodes } 1040135446Strhodes 1041135446Strhodes if (TCP_CLIENT(client)) { 1042135446Strhodes isc_buffer_usedregion(&buffer, &r); 1043135446Strhodes isc_buffer_putuint16(&tcpbuffer, (isc_uint16_t) r.length); 1044135446Strhodes isc_buffer_add(&tcpbuffer, r.length); 1045135446Strhodes result = client_sendpkg(client, &tcpbuffer); 1046135446Strhodes } else 1047135446Strhodes result = client_sendpkg(client, &buffer); 1048193149Sdougb 1049193149Sdougb /* update statistics (XXXJT: is it okay to access message->xxxkey?) */ 1050193149Sdougb isc_stats_increment(ns_g_server->nsstats, dns_nsstatscounter_response); 1051193149Sdougb if (opt_included) { 1052193149Sdougb isc_stats_increment(ns_g_server->nsstats, 1053193149Sdougb dns_nsstatscounter_edns0out); 1054193149Sdougb } 1055193149Sdougb if (client->message->tsigkey != NULL) { 1056193149Sdougb isc_stats_increment(ns_g_server->nsstats, 1057193149Sdougb dns_nsstatscounter_tsigout); 1058193149Sdougb } 1059193149Sdougb if (client->message->sig0key != NULL) { 1060193149Sdougb isc_stats_increment(ns_g_server->nsstats, 1061193149Sdougb dns_nsstatscounter_sig0out); 1062193149Sdougb } 1063193149Sdougb if ((client->message->flags & DNS_MESSAGEFLAG_TC) != 0) 1064193149Sdougb isc_stats_increment(ns_g_server->nsstats, 1065193149Sdougb dns_nsstatscounter_truncatedresp); 1066193149Sdougb 1067135446Strhodes if (result == ISC_R_SUCCESS) 1068135446Strhodes return; 1069135446Strhodes 1070135446Strhodes done: 1071135446Strhodes if (client->tcpbuf != NULL) { 1072135446Strhodes isc_mem_put(client->mctx, client->tcpbuf, TCP_BUFFER_SIZE); 1073135446Strhodes client->tcpbuf = NULL; 1074135446Strhodes } 1075135446Strhodes 1076135446Strhodes if (cleanup_cctx) 1077135446Strhodes dns_compress_invalidate(&cctx); 1078135446Strhodes 1079135446Strhodes ns_client_next(client, result); 1080135446Strhodes} 1081135446Strhodes 1082165071Sdougb#if NS_CLIENT_DROPPORT 1083165071Sdougb#define DROPPORT_NO 0 1084165071Sdougb#define DROPPORT_REQUEST 1 1085165071Sdougb#define DROPPORT_RESPONSE 2 1086165071Sdougb/*% 1087165071Sdougb * ns_client_dropport determines if certain requests / responses 1088165071Sdougb * should be dropped based on the port number. 1089165071Sdougb * 1090165071Sdougb * Returns: 1091165071Sdougb * \li 0: Don't drop. 1092165071Sdougb * \li 1: Drop request. 1093165071Sdougb * \li 2: Drop (error) response. 1094165071Sdougb */ 1095165071Sdougbstatic int 1096165071Sdougbns_client_dropport(in_port_t port) { 1097165071Sdougb switch (port) { 1098165071Sdougb case 7: /* echo */ 1099165071Sdougb case 13: /* daytime */ 1100165071Sdougb case 19: /* chargen */ 1101165071Sdougb case 37: /* time */ 1102165071Sdougb return (DROPPORT_REQUEST); 1103165071Sdougb case 464: /* kpasswd */ 1104165071Sdougb return (DROPPORT_RESPONSE); 1105165071Sdougb } 1106165071Sdougb return (DROPPORT_NO); 1107165071Sdougb} 1108165071Sdougb#endif 1109165071Sdougb 1110135446Strhodesvoid 1111135446Strhodesns_client_error(ns_client_t *client, isc_result_t result) { 1112135446Strhodes dns_rcode_t rcode; 1113135446Strhodes dns_message_t *message; 1114135446Strhodes 1115135446Strhodes REQUIRE(NS_CLIENT_VALID(client)); 1116135446Strhodes 1117135446Strhodes CTRACE("error"); 1118135446Strhodes 1119135446Strhodes message = client->message; 1120135446Strhodes rcode = dns_result_torcode(result); 1121135446Strhodes 1122165071Sdougb#if NS_CLIENT_DROPPORT 1123135446Strhodes /* 1124165071Sdougb * Don't send FORMERR to ports on the drop port list. 1125165071Sdougb */ 1126165071Sdougb if (rcode == dns_rcode_formerr && 1127165071Sdougb ns_client_dropport(isc_sockaddr_getport(&client->peeraddr)) != 1128165071Sdougb DROPPORT_NO) { 1129165071Sdougb char buf[64]; 1130165071Sdougb isc_buffer_t b; 1131165071Sdougb 1132165071Sdougb isc_buffer_init(&b, buf, sizeof(buf) - 1); 1133165071Sdougb if (dns_rcode_totext(rcode, &b) != ISC_R_SUCCESS) 1134165071Sdougb isc_buffer_putstr(&b, "UNKNOWN RCODE"); 1135165071Sdougb ns_client_log(client, DNS_LOGCATEGORY_SECURITY, 1136165071Sdougb NS_LOGMODULE_CLIENT, ISC_LOG_DEBUG(10), 1137165071Sdougb "dropped error (%.*s) response: suspicious port", 1138165071Sdougb (int)isc_buffer_usedlength(&b), buf); 1139165071Sdougb ns_client_next(client, ISC_R_SUCCESS); 1140165071Sdougb return; 1141165071Sdougb } 1142165071Sdougb#endif 1143165071Sdougb 1144262706Serwin#ifdef USE_RRL 1145165071Sdougb /* 1146262706Serwin * Try to rate limit error responses. 1147262706Serwin */ 1148262706Serwin if (client->view != NULL && client->view->rrl != NULL) { 1149262706Serwin isc_boolean_t wouldlog; 1150262706Serwin char log_buf[DNS_RRL_LOG_BUF_LEN]; 1151262706Serwin dns_rrl_result_t rrl_result; 1152262706Serwin 1153262706Serwin INSIST(rcode != dns_rcode_noerror && 1154262706Serwin rcode != dns_rcode_nxdomain); 1155262706Serwin wouldlog = isc_log_wouldlog(ns_g_lctx, DNS_RRL_LOG_DROP); 1156262706Serwin rrl_result = dns_rrl(client->view, &client->peeraddr, 1157262706Serwin TCP_CLIENT(client), 1158262706Serwin dns_rdataclass_in, dns_rdatatype_none, 1159262706Serwin NULL, result, client->now, 1160262706Serwin wouldlog, log_buf, sizeof(log_buf)); 1161262706Serwin if (rrl_result != DNS_RRL_RESULT_OK) { 1162262706Serwin /* 1163262706Serwin * Log dropped errors in the query category 1164262706Serwin * so that they are not lost in silence. 1165262706Serwin * Starts of rate-limited bursts are logged in 1166262706Serwin * NS_LOGCATEGORY_RRL. 1167262706Serwin */ 1168262706Serwin if (wouldlog) { 1169262706Serwin ns_client_log(client, 1170262706Serwin NS_LOGCATEGORY_QUERY_EERRORS, 1171262706Serwin NS_LOGMODULE_CLIENT, 1172262706Serwin DNS_RRL_LOG_DROP, 1173262706Serwin "%s", log_buf); 1174262706Serwin } 1175262706Serwin /* 1176262706Serwin * Some error responses cannot be 'slipped', 1177262706Serwin * so don't try to slip any error responses. 1178262706Serwin */ 1179262706Serwin if (!client->view->rrl->log_only) { 1180262706Serwin isc_stats_increment(ns_g_server->nsstats, 1181262706Serwin dns_nsstatscounter_ratedropped); 1182262706Serwin isc_stats_increment(ns_g_server->nsstats, 1183262706Serwin dns_nsstatscounter_dropped); 1184262706Serwin ns_client_next(client, DNS_R_DROP); 1185262706Serwin return; 1186262706Serwin } 1187262706Serwin } 1188262706Serwin } 1189262706Serwin#endif /* USE_RRL */ 1190262706Serwin 1191262706Serwin /* 1192135446Strhodes * Message may be an in-progress reply that we had trouble 1193135446Strhodes * with, in which case QR will be set. We need to clear QR before 1194135446Strhodes * calling dns_message_reply() to avoid triggering an assertion. 1195135446Strhodes */ 1196135446Strhodes message->flags &= ~DNS_MESSAGEFLAG_QR; 1197135446Strhodes /* 1198135446Strhodes * AA and AD shouldn't be set. 1199135446Strhodes */ 1200135446Strhodes message->flags &= ~(DNS_MESSAGEFLAG_AA | DNS_MESSAGEFLAG_AD); 1201135446Strhodes result = dns_message_reply(message, ISC_TRUE); 1202135446Strhodes if (result != ISC_R_SUCCESS) { 1203135446Strhodes /* 1204135446Strhodes * It could be that we've got a query with a good header, 1205135446Strhodes * but a bad question section, so we try again with 1206135446Strhodes * want_question_section set to ISC_FALSE. 1207135446Strhodes */ 1208135446Strhodes result = dns_message_reply(message, ISC_FALSE); 1209135446Strhodes if (result != ISC_R_SUCCESS) { 1210135446Strhodes ns_client_next(client, result); 1211135446Strhodes return; 1212135446Strhodes } 1213135446Strhodes } 1214135446Strhodes message->rcode = rcode; 1215135446Strhodes 1216135446Strhodes /* 1217135446Strhodes * FORMERR loop avoidance: If we sent a FORMERR message 1218135446Strhodes * with the same ID to the same client less than two 1219186462Sdougb * seconds ago, assume that we are in an infinite error 1220186462Sdougb * packet dialog with a server for some protocol whose 1221135446Strhodes * error responses look enough like DNS queries to 1222135446Strhodes * elicit a FORMERR response. Drop a packet to break 1223135446Strhodes * the loop. 1224135446Strhodes */ 1225135446Strhodes if (rcode == dns_rcode_formerr) { 1226135446Strhodes if (isc_sockaddr_equal(&client->peeraddr, 1227135446Strhodes &client->formerrcache.addr) && 1228135446Strhodes message->id == client->formerrcache.id && 1229135446Strhodes client->requesttime - client->formerrcache.time < 2) { 1230135446Strhodes /* Drop packet. */ 1231135446Strhodes ns_client_log(client, NS_LOGCATEGORY_CLIENT, 1232135446Strhodes NS_LOGMODULE_CLIENT, ISC_LOG_DEBUG(1), 1233135446Strhodes "possible error packet loop, " 1234135446Strhodes "FORMERR dropped"); 1235135446Strhodes ns_client_next(client, result); 1236135446Strhodes return; 1237135446Strhodes } 1238135446Strhodes client->formerrcache.addr = client->peeraddr; 1239135446Strhodes client->formerrcache.time = client->requesttime; 1240135446Strhodes client->formerrcache.id = message->id; 1241135446Strhodes } 1242135446Strhodes ns_client_send(client); 1243135446Strhodes} 1244135446Strhodes 1245135446Strhodesstatic inline isc_result_t 1246135446Strhodesclient_addopt(ns_client_t *client) { 1247262706Serwin char nsid[BUFSIZ], *nsidp; 1248135446Strhodes isc_result_t result; 1249135446Strhodes dns_view_t *view; 1250135446Strhodes dns_resolver_t *resolver; 1251135446Strhodes isc_uint16_t udpsize; 1252262706Serwin dns_ednsopt_t ednsopts[2]; 1253262706Serwin int count = 0; 1254262706Serwin unsigned int flags; 1255135446Strhodes 1256135446Strhodes REQUIRE(client->opt == NULL); /* XXXRTH free old. */ 1257135446Strhodes 1258135446Strhodes view = client->view; 1259135446Strhodes resolver = (view != NULL) ? view->resolver : NULL; 1260135446Strhodes if (resolver != NULL) 1261135446Strhodes udpsize = dns_resolver_getudpsize(resolver); 1262135446Strhodes else 1263135446Strhodes udpsize = ns_g_udpsize; 1264135446Strhodes 1265262706Serwin flags = client->extflags & DNS_MESSAGEEXTFLAG_REPLYPRESERVE; 1266135446Strhodes 1267193149Sdougb /* Set EDNS options if applicable */ 1268262706Serwin if ((client->attributes & NS_CLIENTATTR_WANTNSID) != 0 && 1269193149Sdougb (ns_g_server->server_id != NULL || 1270193149Sdougb ns_g_server->server_usehostname)) { 1271193149Sdougb if (ns_g_server->server_usehostname) { 1272193149Sdougb isc_result_t result; 1273193149Sdougb result = ns_os_gethostname(nsid, sizeof(nsid)); 1274193149Sdougb if (result != ISC_R_SUCCESS) { 1275193149Sdougb goto no_nsid; 1276193149Sdougb } 1277193149Sdougb nsidp = nsid; 1278193149Sdougb } else 1279193149Sdougb nsidp = ns_g_server->server_id; 1280193149Sdougb 1281262706Serwin ednsopts[count].code = DNS_OPT_NSID; 1282262706Serwin ednsopts[count].length = strlen(nsidp); 1283262706Serwin ednsopts[count].value = (unsigned char *)nsidp; 1284262706Serwin count++; 1285193149Sdougb } 1286262706Serwin no_nsid: 1287262706Serwin result = dns_message_buildopt(client->message, &client->opt, 0, 1288262706Serwin udpsize, flags, ednsopts, count); 1289262706Serwin return (result); 1290135446Strhodes} 1291135446Strhodes 1292135446Strhodesstatic inline isc_boolean_t 1293135446Strhodesallowed(isc_netaddr_t *addr, dns_name_t *signer, dns_acl_t *acl) { 1294135446Strhodes int match; 1295135446Strhodes isc_result_t result; 1296135446Strhodes 1297135446Strhodes if (acl == NULL) 1298135446Strhodes return (ISC_TRUE); 1299135446Strhodes result = dns_acl_match(addr, signer, acl, &ns_g_server->aclenv, 1300135446Strhodes &match, NULL); 1301135446Strhodes if (result == ISC_R_SUCCESS && match > 0) 1302135446Strhodes return (ISC_TRUE); 1303135446Strhodes return (ISC_FALSE); 1304135446Strhodes} 1305135446Strhodes 1306135446Strhodes/* 1307170222Sdougb * Callback to see if a non-recursive query coming from 'srcaddr' to 1308170222Sdougb * 'destaddr', with optional key 'mykey' for class 'rdclass' would be 1309170222Sdougb * delivered to 'myview'. 1310170222Sdougb * 1311170222Sdougb * We run this unlocked as both the view list and the interface list 1312193149Sdougb * are updated when the appropriate task has exclusivity. 1313170222Sdougb */ 1314170222Sdougbisc_boolean_t 1315170222Sdougbns_client_isself(dns_view_t *myview, dns_tsigkey_t *mykey, 1316170222Sdougb isc_sockaddr_t *srcaddr, isc_sockaddr_t *dstaddr, 1317170222Sdougb dns_rdataclass_t rdclass, void *arg) 1318170222Sdougb{ 1319170222Sdougb dns_view_t *view; 1320174187Sdougb dns_tsigkey_t *key = NULL; 1321174187Sdougb dns_name_t *tsig = NULL; 1322170222Sdougb isc_netaddr_t netsrc; 1323170222Sdougb isc_netaddr_t netdst; 1324170222Sdougb 1325170222Sdougb UNUSED(arg); 1326170222Sdougb 1327225361Sdougb /* 1328225361Sdougb * ns_g_server->interfacemgr is task exclusive locked. 1329225361Sdougb */ 1330225361Sdougb if (ns_g_server->interfacemgr == NULL) 1331225361Sdougb return (ISC_TRUE); 1332225361Sdougb 1333170222Sdougb if (!ns_interfacemgr_listeningon(ns_g_server->interfacemgr, dstaddr)) 1334170222Sdougb return (ISC_FALSE); 1335170222Sdougb 1336170222Sdougb isc_netaddr_fromsockaddr(&netsrc, srcaddr); 1337170222Sdougb isc_netaddr_fromsockaddr(&netdst, dstaddr); 1338170222Sdougb 1339170222Sdougb for (view = ISC_LIST_HEAD(ns_g_server->viewlist); 1340170222Sdougb view != NULL; 1341170222Sdougb view = ISC_LIST_NEXT(view, link)) { 1342170222Sdougb 1343170222Sdougb if (view->matchrecursiveonly) 1344170222Sdougb continue; 1345170222Sdougb 1346170222Sdougb if (rdclass != view->rdclass) 1347170222Sdougb continue; 1348170222Sdougb 1349170222Sdougb if (mykey != NULL) { 1350170222Sdougb isc_boolean_t match; 1351170222Sdougb isc_result_t result; 1352170222Sdougb 1353193149Sdougb result = dns_view_gettsig(view, &mykey->name, &key); 1354170222Sdougb if (result != ISC_R_SUCCESS) 1355170222Sdougb continue; 1356170222Sdougb match = dst_key_compare(mykey->key, key->key); 1357170222Sdougb dns_tsigkey_detach(&key); 1358170222Sdougb if (!match) 1359170222Sdougb continue; 1360193149Sdougb tsig = dns_tsigkey_identity(mykey); 1361170222Sdougb } 1362170222Sdougb 1363170222Sdougb if (allowed(&netsrc, tsig, view->matchclients) && 1364170222Sdougb allowed(&netdst, tsig, view->matchdestinations)) 1365170222Sdougb break; 1366170222Sdougb } 1367170222Sdougb return (ISC_TF(view == myview)); 1368170222Sdougb} 1369170222Sdougb 1370262706Serwinstatic isc_result_t 1371262706Serwinprocess_opt(ns_client_t *client, dns_rdataset_t *opt) { 1372262706Serwin dns_rdata_t rdata; 1373262706Serwin isc_buffer_t optbuf; 1374262706Serwin isc_result_t result; 1375262706Serwin isc_uint16_t optcode; 1376262706Serwin isc_uint16_t optlen; 1377262706Serwin 1378262706Serwin /* 1379262706Serwin * Set the client's UDP buffer size. 1380262706Serwin */ 1381262706Serwin client->udpsize = opt->rdclass; 1382262706Serwin 1383262706Serwin /* 1384262706Serwin * If the requested UDP buffer size is less than 512, 1385262706Serwin * ignore it and use 512. 1386262706Serwin */ 1387262706Serwin if (client->udpsize < 512) 1388262706Serwin client->udpsize = 512; 1389262706Serwin 1390262706Serwin /* 1391262706Serwin * Get the flags out of the OPT record. 1392262706Serwin */ 1393262706Serwin client->extflags = (isc_uint16_t)(opt->ttl & 0xFFFF); 1394262706Serwin 1395262706Serwin /* 1396262706Serwin * Do we understand this version of EDNS? 1397262706Serwin * 1398262706Serwin * XXXRTH need library support for this! 1399262706Serwin */ 1400262706Serwin client->ednsversion = (opt->ttl & 0x00FF0000) >> 16; 1401262706Serwin if (client->ednsversion > 0) { 1402262706Serwin isc_stats_increment(ns_g_server->nsstats, 1403262706Serwin dns_nsstatscounter_badednsver); 1404262706Serwin result = client_addopt(client); 1405262706Serwin if (result == ISC_R_SUCCESS) 1406262706Serwin result = DNS_R_BADVERS; 1407262706Serwin ns_client_error(client, result); 1408262706Serwin goto cleanup; 1409262706Serwin } 1410262706Serwin 1411262706Serwin /* Check for NSID request */ 1412262706Serwin result = dns_rdataset_first(opt); 1413262706Serwin if (result == ISC_R_SUCCESS) { 1414262706Serwin dns_rdata_init(&rdata); 1415262706Serwin dns_rdataset_current(opt, &rdata); 1416262706Serwin isc_buffer_init(&optbuf, rdata.data, rdata.length); 1417262706Serwin isc_buffer_add(&optbuf, rdata.length); 1418262706Serwin while (isc_buffer_remaininglength(&optbuf) >= 4) { 1419262706Serwin optcode = isc_buffer_getuint16(&optbuf); 1420262706Serwin optlen = isc_buffer_getuint16(&optbuf); 1421262706Serwin switch (optcode) { 1422262706Serwin case DNS_OPT_NSID: 1423262706Serwin client->attributes |= NS_CLIENTATTR_WANTNSID; 1424262706Serwin isc_buffer_forward(&optbuf, optlen); 1425262706Serwin break; 1426262706Serwin default: 1427262706Serwin isc_buffer_forward(&optbuf, optlen); 1428262706Serwin break; 1429262706Serwin } 1430262706Serwin } 1431262706Serwin } 1432262706Serwin 1433262706Serwin isc_stats_increment(ns_g_server->nsstats, dns_nsstatscounter_edns0in); 1434262706Serwin 1435262706Serwin /* 1436262706Serwin * Create an OPT for our reply. 1437262706Serwin */ 1438262706Serwin result = client_addopt(client); 1439262706Serwin if (result != ISC_R_SUCCESS) { 1440262706Serwin ns_client_error(client, result); 1441262706Serwin goto cleanup; 1442262706Serwin } 1443262706Serwin cleanup: 1444262706Serwin return (result); 1445262706Serwin} 1446262706Serwin 1447170222Sdougb/* 1448135446Strhodes * Handle an incoming request event from the socket (UDP case) 1449135446Strhodes * or tcpmsg (TCP case). 1450135446Strhodes */ 1451135446Strhodesstatic void 1452135446Strhodesclient_request(isc_task_t *task, isc_event_t *event) { 1453135446Strhodes ns_client_t *client; 1454135446Strhodes isc_socketevent_t *sevent; 1455135446Strhodes isc_result_t result; 1456135446Strhodes isc_result_t sigresult = ISC_R_SUCCESS; 1457135446Strhodes isc_buffer_t *buffer; 1458135446Strhodes isc_buffer_t tbuffer; 1459135446Strhodes dns_view_t *view; 1460135446Strhodes dns_rdataset_t *opt; 1461193149Sdougb dns_name_t *signame; 1462193149Sdougb isc_boolean_t ra; /* Recursion available. */ 1463135446Strhodes isc_netaddr_t netaddr; 1464135446Strhodes int match; 1465135446Strhodes dns_messageid_t id; 1466135446Strhodes unsigned int flags; 1467135446Strhodes isc_boolean_t notimp; 1468135446Strhodes 1469135446Strhodes REQUIRE(event != NULL); 1470135446Strhodes client = event->ev_arg; 1471135446Strhodes REQUIRE(NS_CLIENT_VALID(client)); 1472135446Strhodes REQUIRE(task == client->task); 1473135446Strhodes 1474135446Strhodes INSIST(client->recursionquota == NULL); 1475135446Strhodes 1476254402Serwin INSIST(client->state == (TCP_CLIENT(client) ? 1477254402Serwin NS_CLIENTSTATE_READING : 1478254402Serwin NS_CLIENTSTATE_READY)); 1479135446Strhodes 1480170222Sdougb ns_client_requests++; 1481170222Sdougb 1482135446Strhodes if (event->ev_type == ISC_SOCKEVENT_RECVDONE) { 1483135446Strhodes INSIST(!TCP_CLIENT(client)); 1484135446Strhodes sevent = (isc_socketevent_t *)event; 1485135446Strhodes REQUIRE(sevent == client->recvevent); 1486135446Strhodes isc_buffer_init(&tbuffer, sevent->region.base, sevent->n); 1487135446Strhodes isc_buffer_add(&tbuffer, sevent->n); 1488135446Strhodes buffer = &tbuffer; 1489135446Strhodes result = sevent->result; 1490135446Strhodes if (result == ISC_R_SUCCESS) { 1491135446Strhodes client->peeraddr = sevent->address; 1492135446Strhodes client->peeraddr_valid = ISC_TRUE; 1493135446Strhodes } 1494135446Strhodes if ((sevent->attributes & ISC_SOCKEVENTATTR_PKTINFO) != 0) { 1495135446Strhodes client->attributes |= NS_CLIENTATTR_PKTINFO; 1496135446Strhodes client->pktinfo = sevent->pktinfo; 1497135446Strhodes } 1498135446Strhodes if ((sevent->attributes & ISC_SOCKEVENTATTR_MULTICAST) != 0) 1499135446Strhodes client->attributes |= NS_CLIENTATTR_MULTICAST; 1500135446Strhodes client->nrecvs--; 1501135446Strhodes } else { 1502135446Strhodes INSIST(TCP_CLIENT(client)); 1503135446Strhodes REQUIRE(event->ev_type == DNS_EVENT_TCPMSG); 1504135446Strhodes REQUIRE(event->ev_sender == &client->tcpmsg); 1505135446Strhodes buffer = &client->tcpmsg.buffer; 1506135446Strhodes result = client->tcpmsg.result; 1507135446Strhodes INSIST(client->nreads == 1); 1508135446Strhodes /* 1509135446Strhodes * client->peeraddr was set when the connection was accepted. 1510135446Strhodes */ 1511135446Strhodes client->nreads--; 1512135446Strhodes } 1513135446Strhodes 1514135446Strhodes if (exit_check(client)) 1515135446Strhodes goto cleanup; 1516135446Strhodes client->state = client->newstate = NS_CLIENTSTATE_WORKING; 1517135446Strhodes 1518135446Strhodes isc_task_getcurrenttime(task, &client->requesttime); 1519135446Strhodes client->now = client->requesttime; 1520135446Strhodes 1521135446Strhodes if (result != ISC_R_SUCCESS) { 1522135446Strhodes if (TCP_CLIENT(client)) { 1523135446Strhodes ns_client_next(client, result); 1524135446Strhodes } else { 1525135446Strhodes if (result != ISC_R_CANCELED) 1526135446Strhodes isc_log_write(ns_g_lctx, NS_LOGCATEGORY_CLIENT, 1527135446Strhodes NS_LOGMODULE_CLIENT, 1528135446Strhodes ISC_LOG_ERROR, 1529135446Strhodes "UDP client handler shutting " 1530135446Strhodes "down due to fatal receive " 1531135446Strhodes "error: %s", 1532135446Strhodes isc_result_totext(result)); 1533135446Strhodes isc_task_shutdown(client->task); 1534135446Strhodes } 1535135446Strhodes goto cleanup; 1536135446Strhodes } 1537135446Strhodes 1538135446Strhodes isc_netaddr_fromsockaddr(&netaddr, &client->peeraddr); 1539135446Strhodes 1540165071Sdougb#if NS_CLIENT_DROPPORT 1541165071Sdougb if (ns_client_dropport(isc_sockaddr_getport(&client->peeraddr)) == 1542165071Sdougb DROPPORT_REQUEST) { 1543165071Sdougb ns_client_log(client, DNS_LOGCATEGORY_SECURITY, 1544165071Sdougb NS_LOGMODULE_CLIENT, ISC_LOG_DEBUG(10), 1545165071Sdougb "dropped request: suspicious port"); 1546165071Sdougb ns_client_next(client, ISC_R_SUCCESS); 1547165071Sdougb goto cleanup; 1548165071Sdougb } 1549165071Sdougb#endif 1550165071Sdougb 1551135446Strhodes ns_client_log(client, NS_LOGCATEGORY_CLIENT, 1552135446Strhodes NS_LOGMODULE_CLIENT, ISC_LOG_DEBUG(3), 1553135446Strhodes "%s request", 1554135446Strhodes TCP_CLIENT(client) ? "TCP" : "UDP"); 1555135446Strhodes 1556135446Strhodes /* 1557135446Strhodes * Check the blackhole ACL for UDP only, since TCP is done in 1558135446Strhodes * client_newconn. 1559135446Strhodes */ 1560135446Strhodes if (!TCP_CLIENT(client)) { 1561135446Strhodes 1562135446Strhodes if (ns_g_server->blackholeacl != NULL && 1563135446Strhodes dns_acl_match(&netaddr, NULL, ns_g_server->blackholeacl, 1564135446Strhodes &ns_g_server->aclenv, 1565135446Strhodes &match, NULL) == ISC_R_SUCCESS && 1566135446Strhodes match > 0) 1567135446Strhodes { 1568135446Strhodes ns_client_log(client, DNS_LOGCATEGORY_SECURITY, 1569135446Strhodes NS_LOGMODULE_CLIENT, ISC_LOG_DEBUG(10), 1570135446Strhodes "blackholed UDP datagram"); 1571135446Strhodes ns_client_next(client, ISC_R_SUCCESS); 1572135446Strhodes goto cleanup; 1573135446Strhodes } 1574135446Strhodes } 1575135446Strhodes 1576135446Strhodes /* 1577135446Strhodes * Silently drop multicast requests for the present. 1578224092Sdougb * XXXMPA revisit this as mDNS spec was published. 1579135446Strhodes */ 1580135446Strhodes if ((client->attributes & NS_CLIENTATTR_MULTICAST) != 0) { 1581135446Strhodes ns_client_log(client, NS_LOGCATEGORY_CLIENT, 1582135446Strhodes NS_LOGMODULE_CLIENT, ISC_LOG_DEBUG(2), 1583135446Strhodes "dropping multicast request"); 1584135446Strhodes ns_client_next(client, DNS_R_REFUSED); 1585165071Sdougb goto cleanup; 1586135446Strhodes } 1587135446Strhodes 1588135446Strhodes result = dns_message_peekheader(buffer, &id, &flags); 1589135446Strhodes if (result != ISC_R_SUCCESS) { 1590135446Strhodes /* 1591135446Strhodes * There isn't enough header to determine whether 1592135446Strhodes * this was a request or a response. Drop it. 1593135446Strhodes */ 1594135446Strhodes ns_client_next(client, result); 1595135446Strhodes goto cleanup; 1596135446Strhodes } 1597135446Strhodes 1598135446Strhodes /* 1599135446Strhodes * The client object handles requests, not responses. 1600135446Strhodes * If this is a UDP response, forward it to the dispatcher. 1601135446Strhodes * If it's a TCP response, discard it here. 1602135446Strhodes */ 1603135446Strhodes if ((flags & DNS_MESSAGEFLAG_QR) != 0) { 1604135446Strhodes if (TCP_CLIENT(client)) { 1605135446Strhodes CTRACE("unexpected response"); 1606135446Strhodes ns_client_next(client, DNS_R_FORMERR); 1607135446Strhodes goto cleanup; 1608135446Strhodes } else { 1609135446Strhodes dns_dispatch_importrecv(client->dispatch, event); 1610135446Strhodes ns_client_next(client, ISC_R_SUCCESS); 1611135446Strhodes goto cleanup; 1612135446Strhodes } 1613135446Strhodes } 1614135446Strhodes 1615135446Strhodes /* 1616193149Sdougb * Update some statistics counters. Don't count responses. 1617193149Sdougb */ 1618193149Sdougb if (isc_sockaddr_pf(&client->peeraddr) == PF_INET) { 1619193149Sdougb isc_stats_increment(ns_g_server->nsstats, 1620193149Sdougb dns_nsstatscounter_requestv4); 1621193149Sdougb } else { 1622193149Sdougb isc_stats_increment(ns_g_server->nsstats, 1623193149Sdougb dns_nsstatscounter_requestv6); 1624193149Sdougb } 1625193149Sdougb if (TCP_CLIENT(client)) 1626193149Sdougb isc_stats_increment(ns_g_server->nsstats, 1627193149Sdougb dns_nsstatscounter_tcp); 1628193149Sdougb 1629193149Sdougb /* 1630135446Strhodes * It's a request. Parse it. 1631135446Strhodes */ 1632135446Strhodes result = dns_message_parse(client->message, buffer, 0); 1633135446Strhodes if (result != ISC_R_SUCCESS) { 1634135446Strhodes /* 1635135446Strhodes * Parsing the request failed. Send a response 1636135446Strhodes * (typically FORMERR or SERVFAIL). 1637135446Strhodes */ 1638135446Strhodes ns_client_error(client, result); 1639135446Strhodes goto cleanup; 1640135446Strhodes } 1641135446Strhodes 1642193149Sdougb dns_opcodestats_increment(ns_g_server->opcodestats, 1643193149Sdougb client->message->opcode); 1644135446Strhodes switch (client->message->opcode) { 1645135446Strhodes case dns_opcode_query: 1646135446Strhodes case dns_opcode_update: 1647135446Strhodes case dns_opcode_notify: 1648135446Strhodes notimp = ISC_FALSE; 1649135446Strhodes break; 1650135446Strhodes case dns_opcode_iquery: 1651135446Strhodes default: 1652135446Strhodes notimp = ISC_TRUE; 1653135446Strhodes break; 1654135446Strhodes } 1655135446Strhodes 1656135446Strhodes client->message->rcode = dns_rcode_noerror; 1657135446Strhodes 1658135446Strhodes /* RFC1123 section 6.1.3.2 */ 1659135446Strhodes if ((client->attributes & NS_CLIENTATTR_MULTICAST) != 0) 1660135446Strhodes client->message->flags &= ~DNS_MESSAGEFLAG_RD; 1661135446Strhodes 1662135446Strhodes /* 1663135446Strhodes * Deal with EDNS. 1664135446Strhodes */ 1665135446Strhodes opt = dns_message_getopt(client->message); 1666135446Strhodes if (opt != NULL) { 1667262706Serwin result = process_opt(client, opt); 1668262706Serwin if (result != ISC_R_SUCCESS) 1669135446Strhodes goto cleanup; 1670135446Strhodes } 1671135446Strhodes 1672135446Strhodes if (client->message->rdclass == 0) { 1673135446Strhodes ns_client_log(client, NS_LOGCATEGORY_CLIENT, 1674135446Strhodes NS_LOGMODULE_CLIENT, ISC_LOG_DEBUG(1), 1675135446Strhodes "message class could not be determined"); 1676135446Strhodes ns_client_dumpmessage(client, 1677135446Strhodes "message class could not be determined"); 1678135446Strhodes ns_client_error(client, notimp ? DNS_R_NOTIMP : DNS_R_FORMERR); 1679135446Strhodes goto cleanup; 1680135446Strhodes } 1681135446Strhodes 1682135446Strhodes /* 1683135446Strhodes * Determine the destination address. If the receiving interface is 1684135446Strhodes * bound to a specific address, we simply use it regardless of the 1685135446Strhodes * address family. All IPv4 queries should fall into this case. 1686135446Strhodes * Otherwise, if this is a TCP query, get the address from the 1687135446Strhodes * receiving socket (this needs a system call and can be heavy). 1688135446Strhodes * For IPv6 UDP queries, we get this from the pktinfo structure (if 1689135446Strhodes * supported). 1690135446Strhodes * If all the attempts fail (this can happen due to memory shortage, 1691186462Sdougb * etc), we regard this as an error for safety. 1692135446Strhodes */ 1693135446Strhodes if ((client->interface->flags & NS_INTERFACEFLAG_ANYADDR) == 0) 1694224092Sdougb isc_netaddr_fromsockaddr(&client->destaddr, 1695224092Sdougb &client->interface->addr); 1696135446Strhodes else { 1697224092Sdougb isc_sockaddr_t sockaddr; 1698135446Strhodes result = ISC_R_FAILURE; 1699135446Strhodes 1700224092Sdougb if (TCP_CLIENT(client)) 1701135446Strhodes result = isc_socket_getsockname(client->tcpsocket, 1702224092Sdougb &sockaddr); 1703224092Sdougb if (result == ISC_R_SUCCESS) 1704224092Sdougb isc_netaddr_fromsockaddr(&client->destaddr, &sockaddr); 1705135446Strhodes if (result != ISC_R_SUCCESS && 1706135446Strhodes client->interface->addr.type.sa.sa_family == AF_INET6 && 1707135446Strhodes (client->attributes & NS_CLIENTATTR_PKTINFO) != 0) { 1708135446Strhodes /* 1709135446Strhodes * XXXJT technically, we should convert the receiving 1710135446Strhodes * interface ID to a proper scope zone ID. However, 1711135446Strhodes * due to the fact there is no standard API for this, 1712135446Strhodes * we only handle link-local addresses and use the 1713135446Strhodes * interface index as link ID. Despite the assumption, 1714135446Strhodes * it should cover most typical cases. 1715135446Strhodes */ 1716224092Sdougb isc_netaddr_fromin6(&client->destaddr, 1717224092Sdougb &client->pktinfo.ipi6_addr); 1718135446Strhodes if (IN6_IS_ADDR_LINKLOCAL(&client->pktinfo.ipi6_addr)) 1719224092Sdougb isc_netaddr_setzone(&client->destaddr, 1720224092Sdougb client->pktinfo.ipi6_ifindex); 1721135446Strhodes result = ISC_R_SUCCESS; 1722135446Strhodes } 1723135446Strhodes if (result != ISC_R_SUCCESS) { 1724135446Strhodes UNEXPECTED_ERROR(__FILE__, __LINE__, 1725135446Strhodes "failed to get request's " 1726135446Strhodes "destination: %s", 1727135446Strhodes isc_result_totext(result)); 1728174187Sdougb ns_client_next(client, ISC_R_SUCCESS); 1729135446Strhodes goto cleanup; 1730135446Strhodes } 1731135446Strhodes } 1732135446Strhodes 1733135446Strhodes /* 1734135446Strhodes * Find a view that matches the client's source address. 1735135446Strhodes */ 1736135446Strhodes for (view = ISC_LIST_HEAD(ns_g_server->viewlist); 1737135446Strhodes view != NULL; 1738135446Strhodes view = ISC_LIST_NEXT(view, link)) { 1739135446Strhodes if (client->message->rdclass == view->rdclass || 1740135446Strhodes client->message->rdclass == dns_rdataclass_any) 1741135446Strhodes { 1742135446Strhodes dns_name_t *tsig = NULL; 1743193149Sdougb 1744135446Strhodes sigresult = dns_message_rechecksig(client->message, 1745135446Strhodes view); 1746135446Strhodes if (sigresult == ISC_R_SUCCESS) 1747193149Sdougb tsig = dns_tsigkey_identity(client->message->tsigkey); 1748186462Sdougb 1749135446Strhodes if (allowed(&netaddr, tsig, view->matchclients) && 1750224092Sdougb allowed(&client->destaddr, tsig, 1751224092Sdougb view->matchdestinations) && 1752135446Strhodes !((client->message->flags & DNS_MESSAGEFLAG_RD) 1753135446Strhodes == 0 && view->matchrecursiveonly)) 1754135446Strhodes { 1755135446Strhodes dns_view_attach(view, &client->view); 1756135446Strhodes break; 1757135446Strhodes } 1758135446Strhodes } 1759135446Strhodes } 1760135446Strhodes 1761135446Strhodes if (view == NULL) { 1762135446Strhodes char classname[DNS_RDATACLASS_FORMATSIZE]; 1763135446Strhodes 1764135446Strhodes /* 1765135446Strhodes * Do a dummy TSIG verification attempt so that the 1766135446Strhodes * response will have a TSIG if the query did, as 1767135446Strhodes * required by RFC2845. 1768135446Strhodes */ 1769135446Strhodes isc_buffer_t b; 1770135446Strhodes isc_region_t *r; 1771135446Strhodes 1772135446Strhodes dns_message_resetsig(client->message); 1773135446Strhodes 1774135446Strhodes r = dns_message_getrawmessage(client->message); 1775135446Strhodes isc_buffer_init(&b, r->base, r->length); 1776135446Strhodes isc_buffer_add(&b, r->length); 1777135446Strhodes (void)dns_tsig_verify(&b, client->message, NULL, NULL); 1778135446Strhodes 1779135446Strhodes dns_rdataclass_format(client->message->rdclass, classname, 1780135446Strhodes sizeof(classname)); 1781135446Strhodes ns_client_log(client, NS_LOGCATEGORY_CLIENT, 1782135446Strhodes NS_LOGMODULE_CLIENT, ISC_LOG_DEBUG(1), 1783135446Strhodes "no matching view in class '%s'", classname); 1784135446Strhodes ns_client_dumpmessage(client, "no matching view in class"); 1785135446Strhodes ns_client_error(client, notimp ? DNS_R_NOTIMP : DNS_R_REFUSED); 1786135446Strhodes goto cleanup; 1787135446Strhodes } 1788135446Strhodes 1789135446Strhodes ns_client_log(client, NS_LOGCATEGORY_CLIENT, 1790135446Strhodes NS_LOGMODULE_CLIENT, ISC_LOG_DEBUG(5), 1791135446Strhodes "using view '%s'", view->name); 1792135446Strhodes 1793135446Strhodes /* 1794135446Strhodes * Check for a signature. We log bad signatures regardless of 1795135446Strhodes * whether they ultimately cause the request to be rejected or 1796135446Strhodes * not. We do not log the lack of a signature unless we are 1797135446Strhodes * debugging. 1798135446Strhodes */ 1799135446Strhodes client->signer = NULL; 1800135446Strhodes dns_name_init(&client->signername, NULL); 1801135446Strhodes result = dns_message_signer(client->message, &client->signername); 1802193149Sdougb if (result != ISC_R_NOTFOUND) { 1803193149Sdougb signame = NULL; 1804193149Sdougb if (dns_message_gettsig(client->message, &signame) != NULL) { 1805193149Sdougb isc_stats_increment(ns_g_server->nsstats, 1806193149Sdougb dns_nsstatscounter_tsigin); 1807193149Sdougb } else { 1808193149Sdougb isc_stats_increment(ns_g_server->nsstats, 1809193149Sdougb dns_nsstatscounter_sig0in); 1810193149Sdougb } 1811193149Sdougb 1812193149Sdougb } 1813135446Strhodes if (result == ISC_R_SUCCESS) { 1814224092Sdougb char namebuf[DNS_NAME_FORMATSIZE]; 1815224092Sdougb dns_name_format(&client->signername, namebuf, sizeof(namebuf)); 1816135446Strhodes ns_client_log(client, DNS_LOGCATEGORY_SECURITY, 1817135446Strhodes NS_LOGMODULE_CLIENT, ISC_LOG_DEBUG(3), 1818224092Sdougb "request has valid signature: %s", namebuf); 1819135446Strhodes client->signer = &client->signername; 1820135446Strhodes } else if (result == ISC_R_NOTFOUND) { 1821135446Strhodes ns_client_log(client, DNS_LOGCATEGORY_SECURITY, 1822135446Strhodes NS_LOGMODULE_CLIENT, ISC_LOG_DEBUG(3), 1823135446Strhodes "request is not signed"); 1824135446Strhodes } else if (result == DNS_R_NOIDENTITY) { 1825135446Strhodes ns_client_log(client, DNS_LOGCATEGORY_SECURITY, 1826135446Strhodes NS_LOGMODULE_CLIENT, ISC_LOG_DEBUG(3), 1827135446Strhodes "request is signed by a nonauthoritative key"); 1828135446Strhodes } else { 1829135446Strhodes char tsigrcode[64]; 1830135446Strhodes isc_buffer_t b; 1831174187Sdougb dns_rcode_t status; 1832174187Sdougb isc_result_t tresult; 1833135446Strhodes 1834135446Strhodes /* There is a signature, but it is bad. */ 1835193149Sdougb isc_stats_increment(ns_g_server->nsstats, 1836193149Sdougb dns_nsstatscounter_invalidsig); 1837193149Sdougb signame = NULL; 1838193149Sdougb if (dns_message_gettsig(client->message, &signame) != NULL) { 1839135446Strhodes char namebuf[DNS_NAME_FORMATSIZE]; 1840193149Sdougb char cnamebuf[DNS_NAME_FORMATSIZE]; 1841193149Sdougb dns_name_format(signame, namebuf, sizeof(namebuf)); 1842174187Sdougb status = client->message->tsigstatus; 1843174187Sdougb isc_buffer_init(&b, tsigrcode, sizeof(tsigrcode) - 1); 1844174187Sdougb tresult = dns_tsigrcode_totext(status, &b); 1845174187Sdougb INSIST(tresult == ISC_R_SUCCESS); 1846174187Sdougb tsigrcode[isc_buffer_usedlength(&b)] = '\0'; 1847193149Sdougb if (client->message->tsigkey->generated) { 1848193149Sdougb dns_name_format(client->message->tsigkey->creator, 1849193149Sdougb cnamebuf, sizeof(cnamebuf)); 1850193149Sdougb ns_client_log(client, DNS_LOGCATEGORY_SECURITY, 1851193149Sdougb NS_LOGMODULE_CLIENT, 1852193149Sdougb ISC_LOG_ERROR, 1853193149Sdougb "request has invalid signature: " 1854193149Sdougb "TSIG %s (%s): %s (%s)", namebuf, 1855193149Sdougb cnamebuf, 1856193149Sdougb isc_result_totext(result), 1857193149Sdougb tsigrcode); 1858193149Sdougb } else { 1859193149Sdougb ns_client_log(client, DNS_LOGCATEGORY_SECURITY, 1860193149Sdougb NS_LOGMODULE_CLIENT, 1861193149Sdougb ISC_LOG_ERROR, 1862193149Sdougb "request has invalid signature: " 1863193149Sdougb "TSIG %s: %s (%s)", namebuf, 1864193149Sdougb isc_result_totext(result), 1865193149Sdougb tsigrcode); 1866193149Sdougb } 1867135446Strhodes } else { 1868174187Sdougb status = client->message->sig0status; 1869174187Sdougb isc_buffer_init(&b, tsigrcode, sizeof(tsigrcode) - 1); 1870174187Sdougb tresult = dns_tsigrcode_totext(status, &b); 1871174187Sdougb INSIST(tresult == ISC_R_SUCCESS); 1872174187Sdougb tsigrcode[isc_buffer_usedlength(&b)] = '\0'; 1873135446Strhodes ns_client_log(client, DNS_LOGCATEGORY_SECURITY, 1874135446Strhodes NS_LOGMODULE_CLIENT, ISC_LOG_ERROR, 1875135446Strhodes "request has invalid signature: %s (%s)", 1876135446Strhodes isc_result_totext(result), tsigrcode); 1877135446Strhodes } 1878135446Strhodes /* 1879135446Strhodes * Accept update messages signed by unknown keys so that 1880135446Strhodes * update forwarding works transparently through slaves 1881135446Strhodes * that don't have all the same keys as the master. 1882135446Strhodes */ 1883135446Strhodes if (!(client->message->tsigstatus == dns_tsigerror_badkey && 1884135446Strhodes client->message->opcode == dns_opcode_update)) { 1885135446Strhodes ns_client_error(client, sigresult); 1886135446Strhodes goto cleanup; 1887135446Strhodes } 1888135446Strhodes } 1889135446Strhodes 1890135446Strhodes /* 1891135446Strhodes * Decide whether recursive service is available to this client. 1892135446Strhodes * We do this here rather than in the query code so that we can 1893135446Strhodes * set the RA bit correctly on all kinds of responses, not just 1894165071Sdougb * responses to ordinary queries. Note if you can't query the 1895165071Sdougb * cache there is no point in setting RA. 1896135446Strhodes */ 1897135446Strhodes ra = ISC_FALSE; 1898135446Strhodes if (client->view->resolver != NULL && 1899135446Strhodes client->view->recursion == ISC_TRUE && 1900193149Sdougb ns_client_checkaclsilent(client, NULL, 1901193149Sdougb client->view->recursionacl, 1902165071Sdougb ISC_TRUE) == ISC_R_SUCCESS && 1903193149Sdougb ns_client_checkaclsilent(client, NULL, 1904216175Sdougb client->view->cacheacl, 1905193149Sdougb ISC_TRUE) == ISC_R_SUCCESS && 1906224092Sdougb ns_client_checkaclsilent(client, &client->destaddr, 1907193149Sdougb client->view->recursiononacl, 1908193149Sdougb ISC_TRUE) == ISC_R_SUCCESS && 1909224092Sdougb ns_client_checkaclsilent(client, &client->destaddr, 1910216175Sdougb client->view->cacheonacl, 1911135446Strhodes ISC_TRUE) == ISC_R_SUCCESS) 1912135446Strhodes ra = ISC_TRUE; 1913135446Strhodes 1914135446Strhodes if (ra == ISC_TRUE) 1915135446Strhodes client->attributes |= NS_CLIENTATTR_RA; 1916135446Strhodes 1917135446Strhodes ns_client_log(client, DNS_LOGCATEGORY_SECURITY, NS_LOGMODULE_CLIENT, 1918135446Strhodes ISC_LOG_DEBUG(3), ra ? "recursion available" : 1919186462Sdougb "recursion not available"); 1920135446Strhodes 1921135446Strhodes /* 1922170222Sdougb * Adjust maximum UDP response size for this client. 1923170222Sdougb */ 1924170222Sdougb if (client->udpsize > 512) { 1925170222Sdougb dns_peer_t *peer = NULL; 1926170222Sdougb isc_uint16_t udpsize = view->maxudp; 1927170222Sdougb (void) dns_peerlist_peerbyaddr(view->peers, &netaddr, &peer); 1928170222Sdougb if (peer != NULL) 1929170222Sdougb dns_peer_getmaxudp(peer, &udpsize); 1930170222Sdougb if (client->udpsize > udpsize) 1931170222Sdougb client->udpsize = udpsize; 1932170222Sdougb } 1933170222Sdougb 1934170222Sdougb /* 1935135446Strhodes * Dispatch the request. 1936135446Strhodes */ 1937135446Strhodes switch (client->message->opcode) { 1938135446Strhodes case dns_opcode_query: 1939135446Strhodes CTRACE("query"); 1940135446Strhodes ns_query_start(client); 1941135446Strhodes break; 1942135446Strhodes case dns_opcode_update: 1943135446Strhodes CTRACE("update"); 1944135446Strhodes ns_client_settimeout(client, 60); 1945135446Strhodes ns_update_start(client, sigresult); 1946135446Strhodes break; 1947135446Strhodes case dns_opcode_notify: 1948135446Strhodes CTRACE("notify"); 1949135446Strhodes ns_client_settimeout(client, 60); 1950135446Strhodes ns_notify_start(client); 1951135446Strhodes break; 1952135446Strhodes case dns_opcode_iquery: 1953135446Strhodes CTRACE("iquery"); 1954135446Strhodes ns_client_error(client, DNS_R_NOTIMP); 1955135446Strhodes break; 1956135446Strhodes default: 1957135446Strhodes CTRACE("unknown opcode"); 1958135446Strhodes ns_client_error(client, DNS_R_NOTIMP); 1959135446Strhodes } 1960135446Strhodes 1961135446Strhodes cleanup: 1962135446Strhodes return; 1963135446Strhodes} 1964135446Strhodes 1965135446Strhodesstatic void 1966135446Strhodesclient_timeout(isc_task_t *task, isc_event_t *event) { 1967135446Strhodes ns_client_t *client; 1968135446Strhodes 1969135446Strhodes REQUIRE(event != NULL); 1970135446Strhodes REQUIRE(event->ev_type == ISC_TIMEREVENT_LIFE || 1971135446Strhodes event->ev_type == ISC_TIMEREVENT_IDLE); 1972135446Strhodes client = event->ev_arg; 1973135446Strhodes REQUIRE(NS_CLIENT_VALID(client)); 1974135446Strhodes REQUIRE(task == client->task); 1975135446Strhodes REQUIRE(client->timer != NULL); 1976135446Strhodes 1977135446Strhodes UNUSED(task); 1978135446Strhodes 1979135446Strhodes CTRACE("timeout"); 1980135446Strhodes 1981135446Strhodes isc_event_free(&event); 1982135446Strhodes 1983135446Strhodes if (client->shutdown != NULL) { 1984135446Strhodes (client->shutdown)(client->shutdown_arg, ISC_R_TIMEDOUT); 1985135446Strhodes client->shutdown = NULL; 1986135446Strhodes client->shutdown_arg = NULL; 1987135446Strhodes } 1988135446Strhodes 1989135446Strhodes if (client->newstate > NS_CLIENTSTATE_READY) 1990135446Strhodes client->newstate = NS_CLIENTSTATE_READY; 1991135446Strhodes (void)exit_check(client); 1992135446Strhodes} 1993135446Strhodes 1994135446Strhodesstatic isc_result_t 1995170222Sdougbget_clientmctx(ns_clientmgr_t *manager, isc_mem_t **mctxp) { 1996170222Sdougb isc_mem_t *clientmctx; 1997170222Sdougb isc_result_t result; 1998254897Serwin#if NMCTXS > 0 1999254897Serwin unsigned int nextmctx; 2000254897Serwin#endif 2001170222Sdougb 2002254897Serwin MTRACE("clientmctx"); 2003254897Serwin 2004170222Sdougb /* 2005170222Sdougb * Caller must be holding the manager lock. 2006170222Sdougb */ 2007193149Sdougb if (ns_g_clienttest) { 2008193149Sdougb result = isc_mem_create(0, 0, mctxp); 2009193149Sdougb if (result == ISC_R_SUCCESS) 2010193149Sdougb isc_mem_setname(*mctxp, "client", NULL); 2011193149Sdougb return (result); 2012193149Sdougb } 2013170222Sdougb#if NMCTXS > 0 2014254897Serwin nextmctx = manager->nextmctx++; 2015254897Serwin if (manager->nextmctx == NMCTXS) 2016254897Serwin manager->nextmctx = 0; 2017254897Serwin 2018254897Serwin INSIST(nextmctx < NMCTXS); 2019254897Serwin 2020254897Serwin clientmctx = manager->mctxpool[nextmctx]; 2021170222Sdougb if (clientmctx == NULL) { 2022170222Sdougb result = isc_mem_create(0, 0, &clientmctx); 2023170222Sdougb if (result != ISC_R_SUCCESS) 2024170222Sdougb return (result); 2025193149Sdougb isc_mem_setname(clientmctx, "client", NULL); 2026170222Sdougb 2027254897Serwin manager->mctxpool[nextmctx] = clientmctx; 2028170222Sdougb } 2029170222Sdougb#else 2030170222Sdougb clientmctx = manager->mctx; 2031170222Sdougb#endif 2032170222Sdougb 2033170222Sdougb isc_mem_attach(clientmctx, mctxp); 2034170222Sdougb 2035170222Sdougb return (ISC_R_SUCCESS); 2036170222Sdougb} 2037170222Sdougb 2038170222Sdougbstatic isc_result_t 2039153816Sdougbclient_create(ns_clientmgr_t *manager, ns_client_t **clientp) { 2040135446Strhodes ns_client_t *client; 2041135446Strhodes isc_result_t result; 2042170222Sdougb isc_mem_t *mctx = NULL; 2043135446Strhodes 2044135446Strhodes /* 2045135446Strhodes * Caller must be holding the manager lock. 2046135446Strhodes * 2047135446Strhodes * Note: creating a client does not add the client to the 2048135446Strhodes * manager's client list or set the client's manager pointer. 2049135446Strhodes * The caller is responsible for that. 2050135446Strhodes */ 2051135446Strhodes 2052135446Strhodes REQUIRE(clientp != NULL && *clientp == NULL); 2053135446Strhodes 2054170222Sdougb result = get_clientmctx(manager, &mctx); 2055170222Sdougb if (result != ISC_R_SUCCESS) 2056170222Sdougb return (result); 2057170222Sdougb 2058170222Sdougb client = isc_mem_get(mctx, sizeof(*client)); 2059170222Sdougb if (client == NULL) { 2060170222Sdougb isc_mem_detach(&mctx); 2061135446Strhodes return (ISC_R_NOMEMORY); 2062170222Sdougb } 2063170222Sdougb client->mctx = mctx; 2064135446Strhodes 2065135446Strhodes client->task = NULL; 2066135446Strhodes result = isc_task_create(manager->taskmgr, 0, &client->task); 2067135446Strhodes if (result != ISC_R_SUCCESS) 2068135446Strhodes goto cleanup_client; 2069135446Strhodes isc_task_setname(client->task, "client", client); 2070135446Strhodes 2071135446Strhodes client->timer = NULL; 2072135446Strhodes result = isc_timer_create(manager->timermgr, isc_timertype_inactive, 2073135446Strhodes NULL, NULL, client->task, client_timeout, 2074135446Strhodes client, &client->timer); 2075135446Strhodes if (result != ISC_R_SUCCESS) 2076135446Strhodes goto cleanup_task; 2077135446Strhodes client->timerset = ISC_FALSE; 2078135446Strhodes 2079135446Strhodes client->message = NULL; 2080170222Sdougb result = dns_message_create(client->mctx, DNS_MESSAGE_INTENTPARSE, 2081135446Strhodes &client->message); 2082135446Strhodes if (result != ISC_R_SUCCESS) 2083135446Strhodes goto cleanup_timer; 2084135446Strhodes 2085135446Strhodes /* XXXRTH Hardwired constants */ 2086135446Strhodes 2087135446Strhodes client->sendevent = (isc_socketevent_t *) 2088170222Sdougb isc_event_allocate(client->mctx, client, 2089135446Strhodes ISC_SOCKEVENT_SENDDONE, 2090135446Strhodes client_senddone, client, 2091135446Strhodes sizeof(isc_socketevent_t)); 2092135446Strhodes if (client->sendevent == NULL) { 2093135446Strhodes result = ISC_R_NOMEMORY; 2094135446Strhodes goto cleanup_message; 2095135446Strhodes } 2096135446Strhodes 2097170222Sdougb client->recvbuf = isc_mem_get(client->mctx, RECV_BUFFER_SIZE); 2098135446Strhodes if (client->recvbuf == NULL) { 2099135446Strhodes result = ISC_R_NOMEMORY; 2100135446Strhodes goto cleanup_sendevent; 2101135446Strhodes } 2102135446Strhodes 2103135446Strhodes client->recvevent = (isc_socketevent_t *) 2104170222Sdougb isc_event_allocate(client->mctx, client, 2105135446Strhodes ISC_SOCKEVENT_RECVDONE, 2106135446Strhodes client_request, client, 2107135446Strhodes sizeof(isc_socketevent_t)); 2108135446Strhodes if (client->recvevent == NULL) { 2109135446Strhodes result = ISC_R_NOMEMORY; 2110135446Strhodes goto cleanup_recvbuf; 2111135446Strhodes } 2112135446Strhodes 2113135446Strhodes client->magic = NS_CLIENT_MAGIC; 2114135446Strhodes client->manager = NULL; 2115135446Strhodes client->state = NS_CLIENTSTATE_INACTIVE; 2116135446Strhodes client->newstate = NS_CLIENTSTATE_MAX; 2117135446Strhodes client->naccepts = 0; 2118135446Strhodes client->nreads = 0; 2119135446Strhodes client->nsends = 0; 2120135446Strhodes client->nrecvs = 0; 2121135446Strhodes client->nupdates = 0; 2122135446Strhodes client->nctls = 0; 2123135446Strhodes client->references = 0; 2124135446Strhodes client->attributes = 0; 2125135446Strhodes client->view = NULL; 2126135446Strhodes client->dispatch = NULL; 2127135446Strhodes client->udpsocket = NULL; 2128135446Strhodes client->tcplistener = NULL; 2129135446Strhodes client->tcpsocket = NULL; 2130135446Strhodes client->tcpmsg_valid = ISC_FALSE; 2131135446Strhodes client->tcpbuf = NULL; 2132135446Strhodes client->opt = NULL; 2133135446Strhodes client->udpsize = 512; 2134135446Strhodes client->extflags = 0; 2135170222Sdougb client->ednsversion = -1; 2136135446Strhodes client->next = NULL; 2137135446Strhodes client->shutdown = NULL; 2138135446Strhodes client->shutdown_arg = NULL; 2139225361Sdougb client->signer = NULL; 2140135446Strhodes dns_name_init(&client->signername, NULL); 2141135446Strhodes client->mortal = ISC_FALSE; 2142135446Strhodes client->tcpquota = NULL; 2143135446Strhodes client->recursionquota = NULL; 2144135446Strhodes client->interface = NULL; 2145135446Strhodes client->peeraddr_valid = ISC_FALSE; 2146234010Sdougb#ifdef ALLOW_FILTER_AAAA_ON_V4 2147234010Sdougb client->filter_aaaa = dns_v4_aaaa_ok; 2148234010Sdougb#endif 2149254897Serwin client->needshutdown = ns_g_clienttest; 2150254897Serwin 2151135446Strhodes ISC_EVENT_INIT(&client->ctlevent, sizeof(client->ctlevent), 0, NULL, 2152135446Strhodes NS_EVENT_CLIENTCONTROL, client_start, client, client, 2153135446Strhodes NULL, NULL); 2154135446Strhodes /* 2155135446Strhodes * Initialize FORMERR cache to sentinel value that will not match 2156135446Strhodes * any actual FORMERR response. 2157135446Strhodes */ 2158135446Strhodes isc_sockaddr_any(&client->formerrcache.addr); 2159135446Strhodes client->formerrcache.time = 0; 2160135446Strhodes client->formerrcache.id = 0; 2161135446Strhodes ISC_LINK_INIT(client, link); 2162254897Serwin ISC_LINK_INIT(client, rlink); 2163254897Serwin ISC_QLINK_INIT(client, ilink); 2164135446Strhodes 2165135446Strhodes /* 2166135446Strhodes * We call the init routines for the various kinds of client here, 2167135446Strhodes * after we have created an otherwise valid client, because some 2168135446Strhodes * of them call routines that REQUIRE(NS_CLIENT_VALID(client)). 2169135446Strhodes */ 2170135446Strhodes result = ns_query_init(client); 2171135446Strhodes if (result != ISC_R_SUCCESS) 2172135446Strhodes goto cleanup_recvevent; 2173135446Strhodes 2174135446Strhodes result = isc_task_onshutdown(client->task, client_shutdown, client); 2175135446Strhodes if (result != ISC_R_SUCCESS) 2176135446Strhodes goto cleanup_query; 2177135446Strhodes 2178135446Strhodes CTRACE("create"); 2179135446Strhodes 2180135446Strhodes *clientp = client; 2181135446Strhodes 2182135446Strhodes return (ISC_R_SUCCESS); 2183135446Strhodes 2184135446Strhodes cleanup_query: 2185135446Strhodes ns_query_free(client); 2186135446Strhodes 2187135446Strhodes cleanup_recvevent: 2188135446Strhodes isc_event_free((isc_event_t **)&client->recvevent); 2189135446Strhodes 2190135446Strhodes cleanup_recvbuf: 2191170222Sdougb isc_mem_put(client->mctx, client->recvbuf, RECV_BUFFER_SIZE); 2192135446Strhodes 2193135446Strhodes cleanup_sendevent: 2194135446Strhodes isc_event_free((isc_event_t **)&client->sendevent); 2195135446Strhodes 2196135446Strhodes client->magic = 0; 2197135446Strhodes 2198135446Strhodes cleanup_message: 2199135446Strhodes dns_message_destroy(&client->message); 2200135446Strhodes 2201135446Strhodes cleanup_timer: 2202135446Strhodes isc_timer_detach(&client->timer); 2203135446Strhodes 2204135446Strhodes cleanup_task: 2205135446Strhodes isc_task_detach(&client->task); 2206135446Strhodes 2207135446Strhodes cleanup_client: 2208170222Sdougb isc_mem_putanddetach(&client->mctx, client, sizeof(*client)); 2209135446Strhodes 2210135446Strhodes return (result); 2211135446Strhodes} 2212135446Strhodes 2213135446Strhodesstatic void 2214135446Strhodesclient_read(ns_client_t *client) { 2215135446Strhodes isc_result_t result; 2216135446Strhodes 2217135446Strhodes CTRACE("read"); 2218135446Strhodes 2219135446Strhodes result = dns_tcpmsg_readmessage(&client->tcpmsg, client->task, 2220135446Strhodes client_request, client); 2221135446Strhodes if (result != ISC_R_SUCCESS) 2222135446Strhodes goto fail; 2223135446Strhodes 2224135446Strhodes /* 2225135446Strhodes * Set a timeout to limit the amount of time we will wait 2226135446Strhodes * for a request on this TCP connection. 2227135446Strhodes */ 2228135446Strhodes ns_client_settimeout(client, 30); 2229135446Strhodes 2230135446Strhodes client->state = client->newstate = NS_CLIENTSTATE_READING; 2231135446Strhodes INSIST(client->nreads == 0); 2232135446Strhodes INSIST(client->recursionquota == NULL); 2233135446Strhodes client->nreads++; 2234135446Strhodes 2235135446Strhodes return; 2236135446Strhodes fail: 2237135446Strhodes ns_client_next(client, result); 2238135446Strhodes} 2239135446Strhodes 2240135446Strhodesstatic void 2241135446Strhodesclient_newconn(isc_task_t *task, isc_event_t *event) { 2242135446Strhodes ns_client_t *client = event->ev_arg; 2243135446Strhodes isc_socket_newconnev_t *nevent = (isc_socket_newconnev_t *)event; 2244135446Strhodes isc_result_t result; 2245135446Strhodes 2246135446Strhodes REQUIRE(event->ev_type == ISC_SOCKEVENT_NEWCONN); 2247135446Strhodes REQUIRE(NS_CLIENT_VALID(client)); 2248135446Strhodes REQUIRE(client->task == task); 2249135446Strhodes 2250135446Strhodes UNUSED(task); 2251135446Strhodes 2252135446Strhodes INSIST(client->state == NS_CLIENTSTATE_READY); 2253135446Strhodes 2254135446Strhodes INSIST(client->naccepts == 1); 2255135446Strhodes client->naccepts--; 2256135446Strhodes 2257135446Strhodes LOCK(&client->interface->lock); 2258135446Strhodes INSIST(client->interface->ntcpcurrent > 0); 2259135446Strhodes client->interface->ntcpcurrent--; 2260135446Strhodes UNLOCK(&client->interface->lock); 2261135446Strhodes 2262135446Strhodes /* 2263135446Strhodes * We must take ownership of the new socket before the exit 2264135446Strhodes * check to make sure it gets destroyed if we decide to exit. 2265135446Strhodes */ 2266135446Strhodes if (nevent->result == ISC_R_SUCCESS) { 2267135446Strhodes client->tcpsocket = nevent->newsocket; 2268193149Sdougb isc_socket_setname(client->tcpsocket, "client-tcp", NULL); 2269135446Strhodes client->state = NS_CLIENTSTATE_READING; 2270135446Strhodes INSIST(client->recursionquota == NULL); 2271135446Strhodes 2272135446Strhodes (void)isc_socket_getpeername(client->tcpsocket, 2273135446Strhodes &client->peeraddr); 2274135446Strhodes client->peeraddr_valid = ISC_TRUE; 2275135446Strhodes ns_client_log(client, NS_LOGCATEGORY_CLIENT, 2276135446Strhodes NS_LOGMODULE_CLIENT, ISC_LOG_DEBUG(3), 2277135446Strhodes "new TCP connection"); 2278135446Strhodes } else { 2279135446Strhodes /* 2280135446Strhodes * XXXRTH What should we do? We're trying to accept but 2281193149Sdougb * it didn't work. If we just give up, then TCP 2282135446Strhodes * service may eventually stop. 2283135446Strhodes * 2284135446Strhodes * For now, we just go idle. 2285135446Strhodes * 2286135446Strhodes * Going idle is probably the right thing if the 2287135446Strhodes * I/O was canceled. 2288135446Strhodes */ 2289135446Strhodes ns_client_log(client, NS_LOGCATEGORY_CLIENT, 2290135446Strhodes NS_LOGMODULE_CLIENT, ISC_LOG_DEBUG(3), 2291135446Strhodes "accept failed: %s", 2292135446Strhodes isc_result_totext(nevent->result)); 2293135446Strhodes } 2294135446Strhodes 2295135446Strhodes if (exit_check(client)) 2296135446Strhodes goto freeevent; 2297135446Strhodes 2298135446Strhodes if (nevent->result == ISC_R_SUCCESS) { 2299135446Strhodes int match; 2300135446Strhodes isc_netaddr_t netaddr; 2301135446Strhodes 2302135446Strhodes isc_netaddr_fromsockaddr(&netaddr, &client->peeraddr); 2303135446Strhodes 2304135446Strhodes if (ns_g_server->blackholeacl != NULL && 2305135446Strhodes dns_acl_match(&netaddr, NULL, 2306186462Sdougb ns_g_server->blackholeacl, 2307135446Strhodes &ns_g_server->aclenv, 2308135446Strhodes &match, NULL) == ISC_R_SUCCESS && 2309135446Strhodes match > 0) 2310135446Strhodes { 2311135446Strhodes ns_client_log(client, DNS_LOGCATEGORY_SECURITY, 2312135446Strhodes NS_LOGMODULE_CLIENT, ISC_LOG_DEBUG(10), 2313135446Strhodes "blackholed connection attempt"); 2314135446Strhodes client->newstate = NS_CLIENTSTATE_READY; 2315135446Strhodes (void)exit_check(client); 2316135446Strhodes goto freeevent; 2317135446Strhodes } 2318135446Strhodes 2319135446Strhodes INSIST(client->tcpmsg_valid == ISC_FALSE); 2320135446Strhodes dns_tcpmsg_init(client->mctx, client->tcpsocket, 2321135446Strhodes &client->tcpmsg); 2322135446Strhodes client->tcpmsg_valid = ISC_TRUE; 2323135446Strhodes 2324135446Strhodes /* 2325135446Strhodes * Let a new client take our place immediately, before 2326135446Strhodes * we wait for a request packet. If we don't, 2327135446Strhodes * telnetting to port 53 (once per CPU) will 2328193149Sdougb * deny service to legitimate TCP clients. 2329135446Strhodes */ 2330135446Strhodes result = isc_quota_attach(&ns_g_server->tcpquota, 2331135446Strhodes &client->tcpquota); 2332135446Strhodes if (result == ISC_R_SUCCESS) 2333135446Strhodes result = ns_client_replace(client); 2334135446Strhodes if (result != ISC_R_SUCCESS) { 2335135446Strhodes ns_client_log(client, NS_LOGCATEGORY_CLIENT, 2336135446Strhodes NS_LOGMODULE_CLIENT, ISC_LOG_WARNING, 2337135446Strhodes "no more TCP clients: %s", 2338135446Strhodes isc_result_totext(result)); 2339135446Strhodes } 2340135446Strhodes 2341135446Strhodes client_read(client); 2342135446Strhodes } 2343135446Strhodes 2344135446Strhodes freeevent: 2345135446Strhodes isc_event_free(&event); 2346135446Strhodes} 2347135446Strhodes 2348135446Strhodesstatic void 2349135446Strhodesclient_accept(ns_client_t *client) { 2350135446Strhodes isc_result_t result; 2351135446Strhodes 2352135446Strhodes CTRACE("accept"); 2353135446Strhodes 2354135446Strhodes result = isc_socket_accept(client->tcplistener, client->task, 2355135446Strhodes client_newconn, client); 2356135446Strhodes if (result != ISC_R_SUCCESS) { 2357135446Strhodes UNEXPECTED_ERROR(__FILE__, __LINE__, 2358135446Strhodes "isc_socket_accept() failed: %s", 2359135446Strhodes isc_result_totext(result)); 2360135446Strhodes /* 2361135446Strhodes * XXXRTH What should we do? We're trying to accept but 2362193149Sdougb * it didn't work. If we just give up, then TCP 2363135446Strhodes * service may eventually stop. 2364135446Strhodes * 2365135446Strhodes * For now, we just go idle. 2366135446Strhodes */ 2367135446Strhodes return; 2368135446Strhodes } 2369135446Strhodes INSIST(client->naccepts == 0); 2370135446Strhodes client->naccepts++; 2371135446Strhodes LOCK(&client->interface->lock); 2372135446Strhodes client->interface->ntcpcurrent++; 2373135446Strhodes UNLOCK(&client->interface->lock); 2374135446Strhodes} 2375135446Strhodes 2376135446Strhodesstatic void 2377135446Strhodesclient_udprecv(ns_client_t *client) { 2378135446Strhodes isc_result_t result; 2379135446Strhodes isc_region_t r; 2380135446Strhodes 2381135446Strhodes CTRACE("udprecv"); 2382135446Strhodes 2383135446Strhodes r.base = client->recvbuf; 2384135446Strhodes r.length = RECV_BUFFER_SIZE; 2385135446Strhodes result = isc_socket_recv2(client->udpsocket, &r, 1, 2386135446Strhodes client->task, client->recvevent, 0); 2387135446Strhodes if (result != ISC_R_SUCCESS) { 2388135446Strhodes UNEXPECTED_ERROR(__FILE__, __LINE__, 2389143731Sdougb "isc_socket_recv2() failed: %s", 2390135446Strhodes isc_result_totext(result)); 2391135446Strhodes /* 2392135446Strhodes * This cannot happen in the current implementation, since 2393135446Strhodes * isc_socket_recv2() cannot fail if flags == 0. 2394135446Strhodes * 2395135446Strhodes * If this does fail, we just go idle. 2396135446Strhodes */ 2397135446Strhodes return; 2398135446Strhodes } 2399135446Strhodes INSIST(client->nrecvs == 0); 2400135446Strhodes client->nrecvs++; 2401135446Strhodes} 2402135446Strhodes 2403135446Strhodesvoid 2404135446Strhodesns_client_attach(ns_client_t *source, ns_client_t **targetp) { 2405135446Strhodes REQUIRE(NS_CLIENT_VALID(source)); 2406135446Strhodes REQUIRE(targetp != NULL && *targetp == NULL); 2407135446Strhodes 2408135446Strhodes source->references++; 2409135446Strhodes ns_client_log(source, NS_LOGCATEGORY_CLIENT, 2410135446Strhodes NS_LOGMODULE_CLIENT, ISC_LOG_DEBUG(10), 2411135446Strhodes "ns_client_attach: ref = %d", source->references); 2412135446Strhodes *targetp = source; 2413135446Strhodes} 2414135446Strhodes 2415135446Strhodesvoid 2416135446Strhodesns_client_detach(ns_client_t **clientp) { 2417135446Strhodes ns_client_t *client = *clientp; 2418135446Strhodes 2419135446Strhodes client->references--; 2420135446Strhodes INSIST(client->references >= 0); 2421135446Strhodes *clientp = NULL; 2422135446Strhodes ns_client_log(client, NS_LOGCATEGORY_CLIENT, 2423135446Strhodes NS_LOGMODULE_CLIENT, ISC_LOG_DEBUG(10), 2424135446Strhodes "ns_client_detach: ref = %d", client->references); 2425135446Strhodes (void)exit_check(client); 2426135446Strhodes} 2427135446Strhodes 2428135446Strhodesisc_boolean_t 2429135446Strhodesns_client_shuttingdown(ns_client_t *client) { 2430135446Strhodes return (ISC_TF(client->newstate == NS_CLIENTSTATE_FREED)); 2431135446Strhodes} 2432135446Strhodes 2433135446Strhodesisc_result_t 2434135446Strhodesns_client_replace(ns_client_t *client) { 2435135446Strhodes isc_result_t result; 2436135446Strhodes 2437135446Strhodes CTRACE("replace"); 2438135446Strhodes 2439254402Serwin REQUIRE(client != NULL); 2440254402Serwin REQUIRE(client->manager != NULL); 2441254402Serwin 2442254897Serwin result = get_client(client->manager, client->interface, 2443254897Serwin client->dispatch, TCP_CLIENT(client)); 2444135446Strhodes if (result != ISC_R_SUCCESS) 2445135446Strhodes return (result); 2446135446Strhodes 2447135446Strhodes /* 2448135446Strhodes * The responsibility for listening for new requests is hereby 2449135446Strhodes * transferred to the new client. Therefore, the old client 2450135446Strhodes * should refrain from listening for any more requests. 2451135446Strhodes */ 2452135446Strhodes client->mortal = ISC_TRUE; 2453135446Strhodes 2454135446Strhodes return (ISC_R_SUCCESS); 2455135446Strhodes} 2456135446Strhodes 2457135446Strhodes/*** 2458135446Strhodes *** Client Manager 2459135446Strhodes ***/ 2460135446Strhodes 2461135446Strhodesstatic void 2462135446Strhodesclientmgr_destroy(ns_clientmgr_t *manager) { 2463170222Sdougb#if NMCTXS > 0 2464170222Sdougb int i; 2465170222Sdougb#endif 2466170222Sdougb 2467254897Serwin REQUIRE(ISC_LIST_EMPTY(manager->clients)); 2468135446Strhodes 2469135446Strhodes MTRACE("clientmgr_destroy"); 2470135446Strhodes 2471170222Sdougb#if NMCTXS > 0 2472170222Sdougb for (i = 0; i < NMCTXS; i++) { 2473170222Sdougb if (manager->mctxpool[i] != NULL) 2474170222Sdougb isc_mem_detach(&manager->mctxpool[i]); 2475170222Sdougb } 2476170222Sdougb#endif 2477170222Sdougb 2478254897Serwin ISC_QUEUE_DESTROY(manager->inactive); 2479135446Strhodes DESTROYLOCK(&manager->lock); 2480254897Serwin DESTROYLOCK(&manager->listlock); 2481254897Serwin DESTROYLOCK(&manager->reclock); 2482135446Strhodes manager->magic = 0; 2483135446Strhodes isc_mem_put(manager->mctx, manager, sizeof(*manager)); 2484135446Strhodes} 2485135446Strhodes 2486135446Strhodesisc_result_t 2487135446Strhodesns_clientmgr_create(isc_mem_t *mctx, isc_taskmgr_t *taskmgr, 2488135446Strhodes isc_timermgr_t *timermgr, ns_clientmgr_t **managerp) 2489135446Strhodes{ 2490135446Strhodes ns_clientmgr_t *manager; 2491135446Strhodes isc_result_t result; 2492170222Sdougb#if NMCTXS > 0 2493170222Sdougb int i; 2494170222Sdougb#endif 2495135446Strhodes 2496135446Strhodes manager = isc_mem_get(mctx, sizeof(*manager)); 2497135446Strhodes if (manager == NULL) 2498135446Strhodes return (ISC_R_NOMEMORY); 2499135446Strhodes 2500135446Strhodes result = isc_mutex_init(&manager->lock); 2501135446Strhodes if (result != ISC_R_SUCCESS) 2502135446Strhodes goto cleanup_manager; 2503135446Strhodes 2504254897Serwin result = isc_mutex_init(&manager->listlock); 2505254897Serwin if (result != ISC_R_SUCCESS) 2506254897Serwin goto cleanup_lock; 2507254897Serwin 2508254897Serwin result = isc_mutex_init(&manager->reclock); 2509254897Serwin if (result != ISC_R_SUCCESS) 2510254897Serwin goto cleanup_listlock; 2511254897Serwin 2512135446Strhodes manager->mctx = mctx; 2513135446Strhodes manager->taskmgr = taskmgr; 2514135446Strhodes manager->timermgr = timermgr; 2515135446Strhodes manager->exiting = ISC_FALSE; 2516254897Serwin ISC_LIST_INIT(manager->clients); 2517135446Strhodes ISC_LIST_INIT(manager->recursing); 2518254897Serwin ISC_QUEUE_INIT(manager->inactive, ilink); 2519170222Sdougb#if NMCTXS > 0 2520170222Sdougb manager->nextmctx = 0; 2521170222Sdougb for (i = 0; i < NMCTXS; i++) 2522170222Sdougb manager->mctxpool[i] = NULL; /* will be created on-demand */ 2523170222Sdougb#endif 2524135446Strhodes manager->magic = MANAGER_MAGIC; 2525135446Strhodes 2526135446Strhodes MTRACE("create"); 2527135446Strhodes 2528135446Strhodes *managerp = manager; 2529135446Strhodes 2530135446Strhodes return (ISC_R_SUCCESS); 2531135446Strhodes 2532254897Serwin cleanup_listlock: 2533254897Serwin (void) isc_mutex_destroy(&manager->listlock); 2534254897Serwin 2535254897Serwin cleanup_lock: 2536254897Serwin (void) isc_mutex_destroy(&manager->lock); 2537254897Serwin 2538135446Strhodes cleanup_manager: 2539135446Strhodes isc_mem_put(manager->mctx, manager, sizeof(*manager)); 2540135446Strhodes 2541135446Strhodes return (result); 2542135446Strhodes} 2543135446Strhodes 2544135446Strhodesvoid 2545135446Strhodesns_clientmgr_destroy(ns_clientmgr_t **managerp) { 2546254897Serwin isc_result_t result; 2547135446Strhodes ns_clientmgr_t *manager; 2548135446Strhodes ns_client_t *client; 2549254897Serwin isc_boolean_t need_destroy = ISC_FALSE, unlock = ISC_FALSE; 2550135446Strhodes 2551135446Strhodes REQUIRE(managerp != NULL); 2552135446Strhodes manager = *managerp; 2553135446Strhodes REQUIRE(VALID_MANAGER(manager)); 2554135446Strhodes 2555135446Strhodes MTRACE("destroy"); 2556135446Strhodes 2557254897Serwin /* 2558254897Serwin * Check for success because we may already be task-exclusive 2559254897Serwin * at this point. Only if we succeed at obtaining an exclusive 2560254897Serwin * lock now will we need to relinquish it later. 2561254897Serwin */ 2562254897Serwin result = isc_task_beginexclusive(ns_g_server->task); 2563254897Serwin if (result == ISC_R_SUCCESS) 2564254897Serwin unlock = ISC_TRUE; 2565135446Strhodes 2566135446Strhodes manager->exiting = ISC_TRUE; 2567135446Strhodes 2568254897Serwin for (client = ISC_LIST_HEAD(manager->clients); 2569135446Strhodes client != NULL; 2570135446Strhodes client = ISC_LIST_NEXT(client, link)) 2571135446Strhodes isc_task_shutdown(client->task); 2572135446Strhodes 2573254897Serwin if (ISC_LIST_EMPTY(manager->clients)) 2574135446Strhodes need_destroy = ISC_TRUE; 2575135446Strhodes 2576254897Serwin if (unlock) 2577254897Serwin isc_task_endexclusive(ns_g_server->task); 2578135446Strhodes 2579135446Strhodes if (need_destroy) 2580135446Strhodes clientmgr_destroy(manager); 2581135446Strhodes 2582135446Strhodes *managerp = NULL; 2583135446Strhodes} 2584135446Strhodes 2585254897Serwinstatic isc_result_t 2586254897Serwinget_client(ns_clientmgr_t *manager, ns_interface_t *ifp, 2587254897Serwin dns_dispatch_t *disp, isc_boolean_t tcp) 2588135446Strhodes{ 2589135446Strhodes isc_result_t result = ISC_R_SUCCESS; 2590254897Serwin isc_event_t *ev; 2591135446Strhodes ns_client_t *client; 2592254897Serwin MTRACE("get client"); 2593135446Strhodes 2594254897Serwin REQUIRE(manager != NULL); 2595135446Strhodes 2596254897Serwin if (manager->exiting) 2597254897Serwin return (ISC_R_SHUTTINGDOWN); 2598135446Strhodes 2599135446Strhodes /* 2600254897Serwin * Allocate a client. First try to get a recycled one; 2601254897Serwin * if that fails, make a new one. 2602135446Strhodes */ 2603254897Serwin client = NULL; 2604254897Serwin if (!ns_g_clienttest) 2605254897Serwin ISC_QUEUE_POP(manager->inactive, ilink, client); 2606135446Strhodes 2607254897Serwin if (client != NULL) 2608254897Serwin MTRACE("recycle"); 2609254897Serwin else { 2610254897Serwin MTRACE("create new"); 2611135446Strhodes 2612254897Serwin LOCK(&manager->lock); 2613254897Serwin result = client_create(manager, &client); 2614254897Serwin UNLOCK(&manager->lock); 2615254897Serwin if (result != ISC_R_SUCCESS) 2616254897Serwin return (result); 2617135446Strhodes 2618254897Serwin LOCK(&manager->listlock); 2619254897Serwin ISC_LIST_APPEND(manager->clients, client, link); 2620254897Serwin UNLOCK(&manager->listlock); 2621254897Serwin } 2622135446Strhodes 2623254897Serwin client->manager = manager; 2624254897Serwin ns_interface_attach(ifp, &client->interface); 2625254897Serwin client->state = NS_CLIENTSTATE_READY; 2626254897Serwin INSIST(client->recursionquota == NULL); 2627135446Strhodes 2628254897Serwin if (tcp) { 2629254897Serwin client->attributes |= NS_CLIENTATTR_TCP; 2630254897Serwin isc_socket_attach(ifp->tcpsocket, 2631254897Serwin &client->tcplistener); 2632254897Serwin } else { 2633254897Serwin isc_socket_t *sock; 2634135446Strhodes 2635254897Serwin dns_dispatch_attach(disp, &client->dispatch); 2636254897Serwin sock = dns_dispatch_getsocket(client->dispatch); 2637254897Serwin isc_socket_attach(sock, &client->udpsocket); 2638135446Strhodes } 2639254897Serwin 2640254897Serwin INSIST(client->nctls == 0); 2641254897Serwin client->nctls++; 2642254897Serwin ev = &client->ctlevent; 2643254897Serwin isc_task_send(client->task, &ev); 2644254897Serwin 2645254897Serwin return (ISC_R_SUCCESS); 2646254897Serwin} 2647254897Serwin 2648254897Serwinisc_result_t 2649254897Serwinns_clientmgr_createclients(ns_clientmgr_t *manager, unsigned int n, 2650254897Serwin ns_interface_t *ifp, isc_boolean_t tcp) 2651254897Serwin{ 2652254897Serwin isc_result_t result = ISC_R_SUCCESS; 2653254897Serwin unsigned int disp; 2654254897Serwin 2655254897Serwin REQUIRE(VALID_MANAGER(manager)); 2656254897Serwin REQUIRE(n > 0); 2657254897Serwin 2658254897Serwin MTRACE("createclients"); 2659254897Serwin 2660254897Serwin for (disp = 0; disp < n; disp++) { 2661254897Serwin result = get_client(manager, ifp, ifp->udpdispatch[disp], tcp); 2662254897Serwin if (result != ISC_R_SUCCESS) 2663254897Serwin break; 2664135446Strhodes } 2665135446Strhodes 2666135446Strhodes return (result); 2667135446Strhodes} 2668135446Strhodes 2669135446Strhodesisc_sockaddr_t * 2670135446Strhodesns_client_getsockaddr(ns_client_t *client) { 2671135446Strhodes return (&client->peeraddr); 2672135446Strhodes} 2673135446Strhodes 2674135446Strhodesisc_result_t 2675224092Sdougbns_client_checkaclsilent(ns_client_t *client, isc_netaddr_t *netaddr, 2676193149Sdougb dns_acl_t *acl, isc_boolean_t default_allow) 2677135446Strhodes{ 2678135446Strhodes isc_result_t result; 2679224092Sdougb isc_netaddr_t tmpnetaddr; 2680135446Strhodes int match; 2681135446Strhodes 2682135446Strhodes if (acl == NULL) { 2683135446Strhodes if (default_allow) 2684135446Strhodes goto allow; 2685135446Strhodes else 2686135446Strhodes goto deny; 2687135446Strhodes } 2688135446Strhodes 2689224092Sdougb if (netaddr == NULL) { 2690224092Sdougb isc_netaddr_fromsockaddr(&tmpnetaddr, &client->peeraddr); 2691224092Sdougb netaddr = &tmpnetaddr; 2692224092Sdougb } 2693135446Strhodes 2694224092Sdougb result = dns_acl_match(netaddr, client->signer, acl, 2695224092Sdougb &ns_g_server->aclenv, &match, NULL); 2696193149Sdougb 2697135446Strhodes if (result != ISC_R_SUCCESS) 2698135446Strhodes goto deny; /* Internal error, already logged. */ 2699135446Strhodes if (match > 0) 2700135446Strhodes goto allow; 2701135446Strhodes goto deny; /* Negative match or no match. */ 2702135446Strhodes 2703135446Strhodes allow: 2704135446Strhodes return (ISC_R_SUCCESS); 2705135446Strhodes 2706135446Strhodes deny: 2707135446Strhodes return (DNS_R_REFUSED); 2708135446Strhodes} 2709135446Strhodes 2710135446Strhodesisc_result_t 2711193149Sdougbns_client_checkacl(ns_client_t *client, isc_sockaddr_t *sockaddr, 2712135446Strhodes const char *opname, dns_acl_t *acl, 2713135446Strhodes isc_boolean_t default_allow, int log_level) 2714135446Strhodes{ 2715224092Sdougb isc_result_t result; 2716224092Sdougb isc_netaddr_t netaddr; 2717135446Strhodes 2718224092Sdougb if (sockaddr != NULL) 2719224092Sdougb isc_netaddr_fromsockaddr(&netaddr, sockaddr); 2720224092Sdougb 2721224092Sdougb result = ns_client_checkaclsilent(client, sockaddr ? &netaddr : NULL, 2722224092Sdougb acl, default_allow); 2723224092Sdougb 2724186462Sdougb if (result == ISC_R_SUCCESS) 2725135446Strhodes ns_client_log(client, DNS_LOGCATEGORY_SECURITY, 2726135446Strhodes NS_LOGMODULE_CLIENT, ISC_LOG_DEBUG(3), 2727135446Strhodes "%s approved", opname); 2728135446Strhodes else 2729135446Strhodes ns_client_log(client, DNS_LOGCATEGORY_SECURITY, 2730135446Strhodes NS_LOGMODULE_CLIENT, 2731135446Strhodes log_level, "%s denied", opname); 2732135446Strhodes return (result); 2733135446Strhodes} 2734135446Strhodes 2735135446Strhodesstatic void 2736135446Strhodesns_client_name(ns_client_t *client, char *peerbuf, size_t len) { 2737135446Strhodes if (client->peeraddr_valid) 2738262706Serwin isc_sockaddr_format(&client->peeraddr, peerbuf, 2739262706Serwin (unsigned int)len); 2740135446Strhodes else 2741135446Strhodes snprintf(peerbuf, len, "@%p", client); 2742135446Strhodes} 2743135446Strhodes 2744135446Strhodesvoid 2745135446Strhodesns_client_logv(ns_client_t *client, isc_logcategory_t *category, 2746193149Sdougb isc_logmodule_t *module, int level, const char *fmt, va_list ap) 2747135446Strhodes{ 2748135446Strhodes char msgbuf[2048]; 2749135446Strhodes char peerbuf[ISC_SOCKADDR_FORMATSIZE]; 2750254897Serwin char signerbuf[DNS_NAME_FORMATSIZE], qnamebuf[DNS_NAME_FORMATSIZE]; 2751254897Serwin const char *viewname = ""; 2752254897Serwin const char *sep1 = "", *sep2 = "", *sep3 = "", *sep4 = ""; 2753254897Serwin const char *signer = "", *qname = ""; 2754254897Serwin dns_name_t *q = NULL; 2755135446Strhodes 2756135446Strhodes vsnprintf(msgbuf, sizeof(msgbuf), fmt, ap); 2757254897Serwin 2758135446Strhodes ns_client_name(client, peerbuf, sizeof(peerbuf)); 2759254897Serwin 2760254897Serwin if (client->signer != NULL) { 2761254897Serwin dns_name_format(client->signer, signerbuf, sizeof(signerbuf)); 2762254897Serwin sep1 = "/key "; 2763254897Serwin signer = signerbuf; 2764254897Serwin } 2765254897Serwin 2766254897Serwin q = client->query.origqname != NULL 2767254897Serwin ? client->query.origqname : client->query.qname; 2768254897Serwin if (q != NULL) { 2769254897Serwin dns_name_format(q, qnamebuf, sizeof(qnamebuf)); 2770254897Serwin sep2 = " ("; 2771254897Serwin sep3 = ")"; 2772254897Serwin qname = qnamebuf; 2773254897Serwin } 2774254897Serwin 2775135446Strhodes if (client->view != NULL && strcmp(client->view->name, "_bind") != 0 && 2776135446Strhodes strcmp(client->view->name, "_default") != 0) { 2777254897Serwin sep4 = ": view "; 2778254897Serwin viewname = client->view->name; 2779135446Strhodes } 2780135446Strhodes 2781135446Strhodes isc_log_write(ns_g_lctx, category, module, level, 2782254897Serwin "client %s%s%s%s%s%s%s%s: %s", 2783254897Serwin peerbuf, sep1, signer, sep2, qname, sep3, 2784254897Serwin sep4, viewname, msgbuf); 2785135446Strhodes} 2786135446Strhodes 2787135446Strhodesvoid 2788135446Strhodesns_client_log(ns_client_t *client, isc_logcategory_t *category, 2789135446Strhodes isc_logmodule_t *module, int level, const char *fmt, ...) 2790135446Strhodes{ 2791135446Strhodes va_list ap; 2792135446Strhodes 2793135446Strhodes if (! isc_log_wouldlog(ns_g_lctx, level)) 2794135446Strhodes return; 2795135446Strhodes 2796135446Strhodes va_start(ap, fmt); 2797135446Strhodes ns_client_logv(client, category, module, level, fmt, ap); 2798135446Strhodes va_end(ap); 2799135446Strhodes} 2800135446Strhodes 2801135446Strhodesvoid 2802135446Strhodesns_client_aclmsg(const char *msg, dns_name_t *name, dns_rdatatype_t type, 2803186462Sdougb dns_rdataclass_t rdclass, char *buf, size_t len) 2804135446Strhodes{ 2805186462Sdougb char namebuf[DNS_NAME_FORMATSIZE]; 2806186462Sdougb char typebuf[DNS_RDATATYPE_FORMATSIZE]; 2807186462Sdougb char classbuf[DNS_RDATACLASS_FORMATSIZE]; 2808135446Strhodes 2809186462Sdougb dns_name_format(name, namebuf, sizeof(namebuf)); 2810186462Sdougb dns_rdatatype_format(type, typebuf, sizeof(typebuf)); 2811186462Sdougb dns_rdataclass_format(rdclass, classbuf, sizeof(classbuf)); 2812186462Sdougb (void)snprintf(buf, len, "%s '%s/%s/%s'", msg, namebuf, typebuf, 2813135446Strhodes classbuf); 2814135446Strhodes} 2815135446Strhodes 2816135446Strhodesstatic void 2817135446Strhodesns_client_dumpmessage(ns_client_t *client, const char *reason) { 2818135446Strhodes isc_buffer_t buffer; 2819135446Strhodes char *buf = NULL; 2820135446Strhodes int len = 1024; 2821135446Strhodes isc_result_t result; 2822135446Strhodes 2823135446Strhodes /* 2824135446Strhodes * Note that these are multiline debug messages. We want a newline 2825135446Strhodes * to appear in the log after each message. 2826135446Strhodes */ 2827135446Strhodes 2828135446Strhodes do { 2829135446Strhodes buf = isc_mem_get(client->mctx, len); 2830135446Strhodes if (buf == NULL) 2831135446Strhodes break; 2832135446Strhodes isc_buffer_init(&buffer, buf, len); 2833135446Strhodes result = dns_message_totext(client->message, 2834135446Strhodes &dns_master_style_debug, 2835135446Strhodes 0, &buffer); 2836135446Strhodes if (result == ISC_R_NOSPACE) { 2837135446Strhodes isc_mem_put(client->mctx, buf, len); 2838135446Strhodes len += 1024; 2839135446Strhodes } else if (result == ISC_R_SUCCESS) 2840186462Sdougb ns_client_log(client, NS_LOGCATEGORY_UNMATCHED, 2841135446Strhodes NS_LOGMODULE_CLIENT, ISC_LOG_DEBUG(1), 2842135446Strhodes "%s\n%.*s", reason, 2843135446Strhodes (int)isc_buffer_usedlength(&buffer), 2844135446Strhodes buf); 2845135446Strhodes } while (result == ISC_R_NOSPACE); 2846135446Strhodes 2847135446Strhodes if (buf != NULL) 2848135446Strhodes isc_mem_put(client->mctx, buf, len); 2849135446Strhodes} 2850135446Strhodes 2851135446Strhodesvoid 2852135446Strhodesns_client_dumprecursing(FILE *f, ns_clientmgr_t *manager) { 2853135446Strhodes ns_client_t *client; 2854135446Strhodes char namebuf[DNS_NAME_FORMATSIZE]; 2855224092Sdougb char original[DNS_NAME_FORMATSIZE]; 2856135446Strhodes char peerbuf[ISC_SOCKADDR_FORMATSIZE]; 2857224092Sdougb char typebuf[DNS_RDATATYPE_FORMATSIZE]; 2858224092Sdougb char classbuf[DNS_RDATACLASS_FORMATSIZE]; 2859135446Strhodes const char *name; 2860135446Strhodes const char *sep; 2861224092Sdougb const char *origfor; 2862224092Sdougb dns_rdataset_t *rdataset; 2863135446Strhodes 2864135446Strhodes REQUIRE(VALID_MANAGER(manager)); 2865186462Sdougb 2866254897Serwin LOCK(&manager->reclock); 2867135446Strhodes client = ISC_LIST_HEAD(manager->recursing); 2868135446Strhodes while (client != NULL) { 2869254897Serwin INSIST(client->state == NS_CLIENTSTATE_RECURSING); 2870254897Serwin 2871135446Strhodes ns_client_name(client, peerbuf, sizeof(peerbuf)); 2872135446Strhodes if (client->view != NULL && 2873135446Strhodes strcmp(client->view->name, "_bind") != 0 && 2874135446Strhodes strcmp(client->view->name, "_default") != 0) { 2875135446Strhodes name = client->view->name; 2876135446Strhodes sep = ": view "; 2877135446Strhodes } else { 2878135446Strhodes name = ""; 2879135446Strhodes sep = ""; 2880135446Strhodes } 2881254897Serwin 2882254897Serwin LOCK(&client->query.fetchlock); 2883254897Serwin INSIST(client->query.qname != NULL); 2884135446Strhodes dns_name_format(client->query.qname, namebuf, sizeof(namebuf)); 2885224092Sdougb if (client->query.qname != client->query.origqname && 2886224092Sdougb client->query.origqname != NULL) { 2887224092Sdougb origfor = " for "; 2888224092Sdougb dns_name_format(client->query.origqname, original, 2889224092Sdougb sizeof(original)); 2890224092Sdougb } else { 2891224092Sdougb origfor = ""; 2892224092Sdougb original[0] = '\0'; 2893224092Sdougb } 2894224092Sdougb rdataset = ISC_LIST_HEAD(client->query.qname->list); 2895224092Sdougb if (rdataset == NULL && client->query.origqname != NULL) 2896224092Sdougb rdataset = ISC_LIST_HEAD(client->query.origqname->list); 2897224092Sdougb if (rdataset != NULL) { 2898224092Sdougb dns_rdatatype_format(rdataset->type, typebuf, 2899224092Sdougb sizeof(typebuf)); 2900224092Sdougb dns_rdataclass_format(rdataset->rdclass, classbuf, 2901224092Sdougb sizeof(classbuf)); 2902224092Sdougb } else { 2903224092Sdougb strcpy(typebuf, "-"); 2904224092Sdougb strcpy(classbuf, "-"); 2905224092Sdougb } 2906254897Serwin UNLOCK(&client->query.fetchlock); 2907224092Sdougb fprintf(f, "; client %s%s%s: id %u '%s/%s/%s'%s%s " 2908224092Sdougb "requesttime %d\n", peerbuf, sep, name, 2909224092Sdougb client->message->id, namebuf, typebuf, classbuf, 2910224092Sdougb origfor, original, client->requesttime); 2911254897Serwin client = ISC_LIST_NEXT(client, rlink); 2912135446Strhodes } 2913254897Serwin UNLOCK(&manager->reclock); 2914135446Strhodes} 2915165071Sdougb 2916165071Sdougbvoid 2917165071Sdougbns_client_qnamereplace(ns_client_t *client, dns_name_t *name) { 2918254897Serwin LOCK(&client->query.fetchlock); 2919165071Sdougb if (client->query.restarts > 0) { 2920165071Sdougb /* 2921165071Sdougb * client->query.qname was dynamically allocated. 2922165071Sdougb */ 2923165071Sdougb dns_message_puttempname(client->message, 2924165071Sdougb &client->query.qname); 2925165071Sdougb } 2926165071Sdougb client->query.qname = name; 2927254897Serwin UNLOCK(&client->query.fetchlock); 2928165071Sdougb} 2929254897Serwin 2930254897Serwinisc_result_t 2931254897Serwinns_client_sourceip(dns_clientinfo_t *ci, isc_sockaddr_t **addrp) { 2932254897Serwin ns_client_t *client = (ns_client_t *) ci->data; 2933254897Serwin 2934254897Serwin REQUIRE(NS_CLIENT_VALID(client)); 2935254897Serwin REQUIRE(addrp != NULL); 2936254897Serwin 2937254897Serwin *addrp = &client->peeraddr; 2938254897Serwin return (ISC_R_SUCCESS); 2939254897Serwin} 2940