Home | History | Annotate | Line # | Download | only in ns
      1 /*	$NetBSD: client.h,v 1.23 2026/09/17 18:01:18 christos Exp $	*/
      2 
      3 /*
      4  * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
      5  *
      6  * SPDX-License-Identifier: MPL-2.0
      7  *
      8  * This Source Code Form is subject to the terms of the Mozilla Public
      9  * License, v. 2.0. If a copy of the MPL was not distributed with this
     10  * file, you can obtain one at https://mozilla.org/MPL/2.0/.
     11  *
     12  * See the COPYRIGHT file distributed with this work for additional
     13  * information regarding copyright ownership.
     14  */
     15 
     16 #pragma once
     17 
     18 /*****
     19 ***** Module Info
     20 *****/
     21 
     22 /*! \file
     23  * \brief
     24  * This module defines two objects, ns_client_t and ns_clientmgr_t.
     25  *
     26  * An ns_client_t object handles incoming DNS requests from clients
     27  * on a given network interface.
     28  *
     29  * Each ns_client_t object can handle only one TCP connection or UDP
     30  * request at a time.  Therefore, several ns_client_t objects are
     31  * typically created to serve each network interface, e.g., one
     32  * for handling TCP requests and a few (one per CPU) for handling
     33  * UDP requests.
     34  *
     35  * Incoming requests are classified as queries, zone transfer
     36  * requests, update requests, notify requests, etc, and handed off
     37  * to the appropriate request handler.  When the request has been
     38  * fully handled (which can be much later), the ns_client_t must be
     39  * notified of this by calling one of the following functions
     40  * exactly once in the context of its task:
     41  * \code
     42  *   ns_client_send()	 (sending a non-error response)
     43  *   ns_client_sendraw() (sending a raw response)
     44  *   ns_client_error()	 (sending an error response)
     45  *   ns_client_drop() (sending no response, logging the reason)
     46  *\endcode
     47  * This will release any resources used by the request and
     48  * and allow the ns_client_t to listen for the next request.
     49  *
     50  * A ns_clientmgr_t manages a number of ns_client_t objects.
     51  * New ns_client_t objects are created by calling
     52  * ns_clientmgr_createclients(). They are destroyed by
     53  * destroying their manager.
     54  */
     55 
     56 /***
     57  *** Imports
     58  ***/
     59 
     60 #include <inttypes.h>
     61 #include <stdbool.h>
     62 
     63 #include <isc/atomic.h>
     64 #include <isc/buffer.h>
     65 #include <isc/magic.h>
     66 #include <isc/netmgr.h>
     67 #include <isc/quota.h>
     68 #include <isc/stdtime.h>
     69 
     70 #include <dns/db.h>
     71 #include <dns/ecs.h>
     72 #include <dns/fixedname.h>
     73 #include <dns/name.h>
     74 #include <dns/rdataclass.h>
     75 #include <dns/rdatatype.h>
     76 #include <dns/types.h>
     77 
     78 #include <ns/query.h>
     79 #include <ns/types.h>
     80 
     81 /***
     82  *** Types
     83  ***/
     84 
     85 #define NS_CLIENT_TCP_BUFFER_SIZE  65535
     86 #define NS_CLIENT_SEND_BUFFER_SIZE 4096
     87 
     88 /*!
     89  * Client object states.  Ordering is significant: higher-numbered
     90  * states are generally "more active", meaning that the client can
     91  * have more dynamically allocated data, outstanding events, etc.
     92  * In the list below, any such properties listed for state N
     93  * also apply to any state > N.
     94  */
     95 
     96 typedef enum {
     97 	NS_CLIENTSTATE_FREED = 0,
     98 	/*%<
     99 	 * The client object no longer exists.
    100 	 */
    101 
    102 	NS_CLIENTSTATE_INACTIVE = 1,
    103 	/*%<
    104 	 * The client object exists and has a task and timer.
    105 	 * Its "query" struct and sendbuf are initialized.
    106 	 * It has a message and OPT, both in the reset state.
    107 	 */
    108 
    109 	NS_CLIENTSTATE_READY = 2,
    110 	/*%<
    111 	 * The client object is either a TCP or a UDP one, and
    112 	 * it is associated with a network interface.  It is on the
    113 	 * client manager's list of active clients.
    114 	 *
    115 	 * If it is a TCP client object, it has a TCP listener socket
    116 	 * and an outstanding TCP listen request.
    117 	 *
    118 	 * If it is a UDP client object, it has a UDP listener socket
    119 	 * and an outstanding UDP receive request.
    120 	 */
    121 
    122 	NS_CLIENTSTATE_WORKING = 3,
    123 	/*%<
    124 	 * The client object has received a request and is working
    125 	 * on it.  It has a view, and it may have any of a non-reset OPT,
    126 	 * recursion quota, and an outstanding write request.
    127 	 */
    128 
    129 	NS_CLIENTSTATE_RECURSING = 4,
    130 	/*%<
    131 	 * The client object is recursing.  It will be on the
    132 	 * 'recursing' list.
    133 	 */
    134 
    135 	NS_CLIENTSTATE_MAX = 5
    136 	/*%<
    137 	 * Sentinel value used to indicate "no state".
    138 	 */
    139 } ns_clientstate_t;
    140 
    141 typedef ISC_LIST(ns_client_t) client_list_t;
    142 
    143 /*% nameserver client manager structure */
    144 struct ns_clientmgr {
    145 	/* Unlocked. */
    146 	unsigned int magic;
    147 
    148 	isc_mem_t     *mctx;
    149 	isc_mempool_t *namepool;
    150 	isc_mempool_t *rdspool;
    151 
    152 	ns_server_t   *sctx;
    153 	isc_refcount_t references;
    154 	uint32_t       tid;
    155 	isc_loop_t    *loop;
    156 
    157 	dns_aclenv_t *aclenv;
    158 
    159 	/* Lock covers the recursing list */
    160 	isc_mutex_t   reclock;
    161 	client_list_t recursing; /*%< Recursing clients */
    162 
    163 	uint8_t tcp_buffer[NS_CLIENT_TCP_BUFFER_SIZE];
    164 };
    165 
    166 /*% nameserver client structure */
    167 struct ns_client {
    168 	unsigned int	 magic;
    169 	ns_clientmgr_t	*manager;
    170 	ns_clientstate_t state;
    171 	bool		 async;
    172 	unsigned int	 attributes;
    173 	dns_view_t	*view;
    174 	dns_dispatch_t	*dispatch;
    175 	isc_nmhandle_t	*handle;       /* Permanent pointer to handle */
    176 	isc_nmhandle_t	*sendhandle;   /* Waiting for send callback */
    177 	isc_nmhandle_t	*reqhandle;    /* Waiting for request callback
    178 					  (query, update, notify) */
    179 	isc_nmhandle_t *updatehandle;  /* Waiting for update callback */
    180 	isc_nmhandle_t *restarthandle; /* Waiting for restart callback */
    181 	unsigned char  *tcpbuf;
    182 	size_t		tcpbuf_size;
    183 	dns_message_t  *message;
    184 	dns_rdataset_t *opt;
    185 	dns_edectx_t	edectx;
    186 	uint16_t	udpsize;
    187 	uint16_t	extflags;
    188 	int16_t		ednsversion; /* -1 noedns */
    189 	uint16_t	additionaldepth;
    190 	uint16_t	additionaltotal;
    191 	void (*cleanup)(ns_client_t *);
    192 	ns_query_t     query;
    193 	isc_time_t     requesttime;
    194 	isc_stdtime_t  now;
    195 	isc_time_t     tnow;
    196 	dns_name_t     signername; /*%< [T]SIG key name */
    197 	dns_name_t    *signer;	   /*%< NULL if not valid sig */
    198 	isc_result_t   sigresult;
    199 	isc_result_t   viewmatchresult;
    200 	isc_buffer_t  *buffer;
    201 	isc_buffer_t   tbuffer;
    202 	unsigned char *reqbuf; /*%< request copy for async path */
    203 	size_t	       reqbuf_size;
    204 
    205 	isc_sockaddr_t peeraddr;
    206 	bool	       peeraddr_valid;
    207 	isc_netaddr_t  destaddr;
    208 	isc_sockaddr_t destsockaddr;
    209 
    210 	dns_ecs_t ecs; /*%< EDNS client subnet sent by client */
    211 
    212 	/*%
    213 	 * Information about recent FORMERR response(s), for
    214 	 * FORMERR loop avoidance.  This is separate for each
    215 	 * client object rather than global only to avoid
    216 	 * the need for locking.
    217 	 */
    218 	struct {
    219 		isc_sockaddr_t	addr;
    220 		isc_stdtime_t	time;
    221 		dns_messageid_t id;
    222 	} formerrcache;
    223 
    224 	/*% Callback function to send a response when unit testing */
    225 	void (*sendcb)(isc_buffer_t *buf);
    226 
    227 	ISC_LINK(ns_client_t) rlink;
    228 	unsigned char  cookie[8];
    229 	uint32_t       expire;
    230 	unsigned char *keytag;
    231 	uint16_t       keytag_len;
    232 
    233 	/*%
    234 	 * Used to override the DNS response code in ns_client_error().
    235 	 * If set to -1, the rcode is determined from the result code,
    236 	 * but if set to any other value, the least significant 12
    237 	 * bits will be used as the rcode in the response message.
    238 	 */
    239 	int32_t rcode_override;
    240 
    241 	uint8_t sendbuf[NS_CLIENT_SEND_BUFFER_SIZE];
    242 };
    243 
    244 #define NS_CLIENT_MAGIC	   ISC_MAGIC('N', 'S', 'C', 'c')
    245 #define NS_CLIENT_VALID(c) ISC_MAGIC_VALID(c, NS_CLIENT_MAGIC)
    246 
    247 #define NS_CLIENTATTR_TCP	 0x00001
    248 #define NS_CLIENTATTR_RA	 0x00002 /*%< Client gets recursive service */
    249 #define NS_CLIENTATTR_PKTINFO	 0x00004 /*%< pktinfo is valid */
    250 #define NS_CLIENTATTR_MULTICAST	 0x00008 /*%< recv'd from multicast */
    251 #define NS_CLIENTATTR_WANTDNSSEC 0x00010 /*%< include dnssec records */
    252 #define NS_CLIENTATTR_WANTNSID	 0x00020 /*%< include nameserver ID */
    253 #define NS_CLIENTATTR_BADCOOKIE \
    254 	0x00040 /*%< Presented cookie is bad/out-of-date */
    255 /* Obsolete: NS_CLIENTATTR_FILTER_AAAA_RC 0x00080 */
    256 #define NS_CLIENTATTR_WANTAD	 0x00100 /*%< want AD in response if possible */
    257 #define NS_CLIENTATTR_WANTCOOKIE 0x00200 /*%< return a COOKIE */
    258 #define NS_CLIENTATTR_HAVECOOKIE 0x00400 /*%< has a valid COOKIE */
    259 #define NS_CLIENTATTR_WANTEXPIRE 0x00800 /*%< return seconds to expire */
    260 #define NS_CLIENTATTR_HAVEEXPIRE 0x01000 /*%< return seconds to expire */
    261 #define NS_CLIENTATTR_WANTOPT	 0x02000 /*%< add opt to reply */
    262 #define NS_CLIENTATTR_HAVEECS	 0x04000 /*%< received an ECS option */
    263 #define NS_CLIENTATTR_WANTPAD	 0x08000 /*%< pad reply */
    264 #define NS_CLIENTATTR_USEKEEPALIVE 0x10000 /*%< use TCP keepalive */
    265 
    266 #define NS_CLIENTATTR_NOSETFC 0x20000 /*%< don't set servfail cache */
    267 
    268 /*
    269  * Flag to use with the SERVFAIL cache to indicate
    270  * that a query had the CD bit set.
    271  */
    272 #define NS_FAILCACHE_CD 0x01
    273 
    274 #ifdef _LP64
    275 extern atomic_uint_fast64_t ns_client_requests;
    276 #else
    277 extern atomic_uint_fast32_t ns_client_requests;
    278 #endif
    279 
    280 /***
    281  *** Functions
    282  ***/
    283 
    284 /*
    285  * Note!  These ns_client_ routines MUST be called ONLY from the client's
    286  * task in order to ensure synchronization.
    287  */
    288 
    289 void
    290 ns_client_send(ns_client_t *client);
    291 /*%<
    292  * Finish processing the current client request and
    293  * send client->message as a response.
    294  * \brief
    295  * Note!  These ns_client_ routines MUST be called ONLY from the client's
    296  * task in order to ensure synchronization.
    297  */
    298 
    299 void
    300 ns_client_sendraw(ns_client_t *client, dns_message_t *msg);
    301 /*%<
    302  * Finish processing the current client request and
    303  * send msg as a response using client->message->id for the id.
    304  */
    305 
    306 void
    307 ns_client_error(ns_client_t *client, isc_result_t result);
    308 /*%<
    309  * Finish processing the current client request and return
    310  * an error response to the client.  The error response
    311  * will have an RCODE determined by 'result'.
    312  */
    313 
    314 void
    315 ns_client_drop(ns_client_t *client, isc_result_t result);
    316 /*%<
    317  * Log the reason the current client request has failed; no response
    318  * will be sent.
    319  */
    320 
    321 isc_result_t
    322 ns_client_replace(ns_client_t *client);
    323 /*%<
    324  * Try to replace the current client with a new one, so that the
    325  * current one can go off and do some lengthy work without
    326  * leaving the dispatch/socket without service.
    327  */
    328 
    329 void
    330 ns_client_settimeout(ns_client_t *client, unsigned int seconds);
    331 /*%<
    332  * Set a timer in the client to go off in the specified amount of time.
    333  */
    334 
    335 isc_result_t
    336 ns_clientmgr_create(ns_server_t *sctx, isc_loopmgr_t *loopmgr,
    337 		    dns_aclenv_t *aclenv, int tid, ns_clientmgr_t **managerp);
    338 /*%<
    339  * Create a client manager.
    340  */
    341 
    342 void
    343 ns_clientmgr_shutdown(ns_clientmgr_t *manager);
    344 /*%<
    345  * Shutdown a client manager and all ns_client_t objects
    346  * managed by it
    347  */
    348 
    349 isc_sockaddr_t *
    350 ns_client_getsockaddr(ns_client_t *client);
    351 /*%<
    352  * Get the socket address of the client whose request is
    353  * currently being processed.
    354  */
    355 
    356 isc_sockaddr_t *
    357 ns_client_getdestaddr(ns_client_t *client);
    358 /*%<
    359  * Get the destination address (server) for the request that is
    360  * currently being processed.
    361  */
    362 
    363 isc_result_t
    364 ns_client_checkaclsilent(ns_client_t *client, isc_netaddr_t *netaddr,
    365 			 dns_acl_t *acl, bool default_allow);
    366 
    367 /*%<
    368  * Convenience function for client request ACL checking.
    369  *
    370  * Check the current client request against 'acl'.  If 'acl'
    371  * is NULL, allow the request iff 'default_allow' is true.
    372  * If netaddr is NULL, check the ACL against client->peeraddr;
    373  * otherwise check it against netaddr.
    374  *
    375  * Notes:
    376  *\li	This is appropriate for checking allow-update,
    377  * 	allow-query, allow-transfer, etc.  It is not appropriate
    378  * 	for checking the blackhole list because we treat positive
    379  * 	matches as "allow" and negative matches as "deny"; in
    380  *	the case of the blackhole list this would be backwards.
    381  *
    382  * Requires:
    383  *\li	'client' points to a valid client.
    384  *\li	'netaddr' points to a valid address, or is NULL.
    385  *\li	'acl' points to a valid ACL, or is NULL.
    386  *
    387  * Returns:
    388  *\li	ISC_R_SUCCESS	if the request should be allowed
    389  * \li	DNS_R_REFUSED	if the request should be denied
    390  *\li	No other return values are possible.
    391  */
    392 
    393 isc_result_t
    394 ns_client_checkacl(ns_client_t *client, isc_sockaddr_t *sockaddr,
    395 		   const char *opname, dns_acl_t *acl, bool default_allow,
    396 		   int log_level);
    397 /*%<
    398  * Like ns_client_checkaclsilent, except the outcome of the check is
    399  * logged at log level 'log_level' if denied, and at debug 3 if approved.
    400  * Log messages will refer to the request as an 'opname' request.
    401  *
    402  * Requires:
    403  *\li	'client' points to a valid client.
    404  *\li	'sockaddr' points to a valid address, or is NULL.
    405  *\li	'acl' points to a valid ACL, or is NULL.
    406  *\li	'opname' points to a null-terminated string.
    407  */
    408 
    409 void
    410 ns_client_log(ns_client_t *client, isc_logcategory_t *category,
    411 	      isc_logmodule_t *module, int level, const char *fmt, ...)
    412 	ISC_FORMAT_PRINTF(5, 6);
    413 
    414 void
    415 ns_client_logv(ns_client_t *client, isc_logcategory_t *category,
    416 	       isc_logmodule_t *module, int level, const char *fmt, va_list ap)
    417 	ISC_FORMAT_PRINTF(5, 0);
    418 
    419 void
    420 ns_client_aclmsg(const char *msg, const dns_name_t *name, dns_rdatatype_t type,
    421 		 dns_rdataclass_t rdclass, char *buf, size_t len);
    422 
    423 #define NS_CLIENT_ACLMSGSIZE(x)                           \
    424 	(DNS_NAME_FORMATSIZE + DNS_RDATATYPE_FORMATSIZE + \
    425 	 DNS_RDATACLASS_FORMATSIZE + sizeof(x) + sizeof("'/'"))
    426 
    427 void
    428 ns_client_recursing(ns_client_t *client);
    429 /*%<
    430  * Add client to end of th recursing list.
    431  */
    432 
    433 void
    434 ns_client_killoldestquery(ns_client_t *client);
    435 /*%<
    436  * Kill the oldest recursive query (recursing list head).
    437  */
    438 
    439 void
    440 ns_client_dumprecursing(FILE *f, ns_clientmgr_t *manager);
    441 /*%<
    442  * Dump the outstanding recursive queries to 'f'.
    443  */
    444 
    445 void
    446 ns_client_qnamereplace(ns_client_t *client, dns_name_t *name);
    447 /*%<
    448  * Replace the qname.
    449  */
    450 
    451 isc_result_t
    452 ns_client_sourceip(dns_clientinfo_t *ci, isc_sockaddr_t **addrp);
    453 
    454 isc_result_t
    455 ns_client_addopt(ns_client_t *client, dns_message_t *message,
    456 		 dns_rdataset_t **opt);
    457 
    458 /*%<
    459  * Get a client object from the inactive queue, or create one, as needed.
    460  * (Not intended for use outside this module and associated tests.)
    461  */
    462 
    463 void
    464 ns_client_request(isc_nmhandle_t *handle, isc_result_t eresult,
    465 		  isc_region_t *region, void *arg);
    466 
    467 /*%<
    468  * Handle client requests.
    469  * (Not intended for use outside this module and associated tests.)
    470  */
    471 
    472 isc_result_t
    473 ns__client_tcpconn(isc_nmhandle_t *handle, isc_result_t result, void *arg);
    474 
    475 /*%<
    476  * Called every time a TCP connection is establish.  This is used for
    477  * updating TCP statistics.
    478  */
    479 
    480 dns_rdataset_t *
    481 ns_client_newrdataset(ns_client_t *client);
    482 
    483 void
    484 ns_client_putrdataset(ns_client_t *client, dns_rdataset_t **rdatasetp);
    485 /*%<
    486  * Get and release temporary rdatasets in the client message;
    487  * used in query.c and in plugins.
    488  */
    489 
    490 isc_result_t
    491 ns_client_newnamebuf(ns_client_t *client);
    492 /*%<
    493  * Allocate a name buffer for the client message.
    494  */
    495 
    496 dns_name_t *
    497 ns_client_newname(ns_client_t *client, isc_buffer_t *dbuf, isc_buffer_t *nbuf);
    498 /*%<
    499  * Get a temporary name for the client message.
    500  */
    501 
    502 isc_buffer_t *
    503 ns_client_getnamebuf(ns_client_t *client);
    504 /*%<
    505  * Get a name buffer from the pool, or allocate a new one if needed.
    506  */
    507 
    508 void
    509 ns_client_keepname(ns_client_t *client, dns_name_t *name, isc_buffer_t *dbuf);
    510 /*%<
    511  * Adjust buffer 'dbuf' to reflect that 'name' is using space in it,
    512  * and set client attributes appropriately.
    513  */
    514 
    515 void
    516 ns_client_releasename(ns_client_t *client, dns_name_t **namep);
    517 /*%<
    518  * Release 'name' back to the pool of temporary names for the client
    519  * message. If it is using a name buffer, relinquish its exclusive
    520  * rights on the buffer.
    521  */
    522 
    523 isc_result_t
    524 ns_client_newdbversion(ns_client_t *client, unsigned int n);
    525 /*%<
    526  * Allocate 'n' new database versions for use by client queries.
    527  */
    528 
    529 ns_dbversion_t *
    530 ns_client_getdbversion(ns_client_t *client);
    531 /*%<
    532  * Get a free database version for use by a client query, allocating
    533  * a new one if necessary.
    534  */
    535 
    536 ns_dbversion_t *
    537 ns_client_findversion(ns_client_t *client, dns_db_t *db);
    538 /*%<
    539  * Find the correct database version to use with a client query.
    540  * If we have already done a query related to the database 'db',
    541  * make sure subsequent queries are from the same version;
    542  * otherwise, take a database version from the list of dbversions
    543  * allocated by ns_client_newdbversion().
    544  */
    545 
    546 ISC_REFCOUNT_DECL(ns_clientmgr);
    547 
    548 void
    549 ns__client_setup(ns_client_t *client, ns_clientmgr_t *manager, bool new);
    550 /*%<
    551  * Perform initial setup of an allocated client.
    552  */
    553 
    554 void
    555 ns__client_reset_cb(void *client0);
    556 /*%<
    557  * Reset the client object so that it can be reused.
    558  */
    559 
    560 void
    561 ns__client_put_cb(void *client0);
    562 /*%<
    563  * Free all resources allocated to this client object, so that
    564  * it can be freed.
    565  */
    566