Home | History | Annotate | Line # | Download | only in dns
      1 /*	$NetBSD: dispatch.h,v 1.11 2026/08/29 14:55:17 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 #include <isc/netmgr.h>
     19 
     20 /*****
     21 ***** Module Info
     22 *****/
     23 
     24 /*! \file dns/dispatch.h
     25  * \brief
     26  * DNS Dispatch Management
     27  *	Shared UDP and single-use TCP dispatches for queries and responses.
     28  *
     29  * MP:
     30  *
     31  *\li	All locking is performed internally to each dispatch.
     32  *	Restrictions apply to dns_dispatch_done().
     33  *
     34  * Reliability:
     35  *
     36  * Resources:
     37  *
     38  * Security:
     39  *
     40  *\li	Depends on dns_message_t for prevention of buffer overruns.
     41  *
     42  * Standards:
     43  *
     44  *\li	None.
     45  */
     46 
     47 /***
     48  *** Imports
     49  ***/
     50 
     51 #include <inttypes.h>
     52 #include <stdbool.h>
     53 
     54 #include <isc/buffer.h>
     55 #include <isc/lang.h>
     56 #include <isc/mutex.h>
     57 #include <isc/netmgr.h>
     58 #include <isc/refcount.h>
     59 #include <isc/types.h>
     60 
     61 #include <dns/types.h>
     62 
     63 /* Add -DDNS_DISPATCH_TRACE=1 to CFLAGS for detailed reference tracing */
     64 
     65 ISC_LANG_BEGINDECLS
     66 
     67 /*%
     68  * This is a set of one or more dispatches which can be retrieved
     69  * round-robin fashion.
     70  */
     71 struct dns_dispatchset {
     72 	isc_mem_t	*mctx;
     73 	dns_dispatch_t **dispatches;
     74 	uint32_t	 ndisp;
     75 };
     76 
     77 typedef enum dns_dispatchopt {
     78 	DNS_DISPATCHOPT_FIXEDID = 1 << 0,
     79 } dns_dispatchopt_t;
     80 
     81 typedef enum dns_dispatchtype {
     82 	DNS_DISPATCHTYPE_RESOLVER,
     83 	DNS_DISPATCHTYPE_REQUEST,
     84 	DNS_DISPATCHTYPE_XFRIN,
     85 } dns_dispatchtype_t;
     86 
     87 isc_result_t
     88 dns_dispatchmgr_create(isc_mem_t *mctx, isc_loopmgr_t *loopmgr, isc_nm_t *nm,
     89 		       dns_dispatchmgr_t **mgrp);
     90 /*%<
     91  * Creates a new dispatchmgr object, and sets the available ports
     92  * to the default range (1024-65535).
     93  *
     94  * Requires:
     95  *\li	'mctx' be a valid memory context.
     96  *
     97  *\li	'nm' is a valid network manager.
     98 
     99  *\li	mgrp != NULL && *mgrp == NULL
    100  *
    101  * Returns:
    102  *\li	ISC_R_SUCCESS	-- all ok
    103  *
    104  *\li	anything else	-- failure
    105  */
    106 
    107 #if DNS_DISPATCH_TRACE
    108 #define dns_dispatchmgr_ref(ptr) \
    109 	dns_dispatchmgr__ref(ptr, __func__, __FILE__, __LINE__)
    110 #define dns_dispatchmgr_unref(ptr) \
    111 	dns_dispatchmgr__unref(ptr, __func__, __FILE__, __LINE__)
    112 #define dns_dispatchmgr_attach(ptr, ptrp) \
    113 	dns_dispatchmgr__attach(ptr, ptrp, __func__, __FILE__, __LINE__)
    114 #define dns_dispatchmgr_detach(ptrp) \
    115 	dns_dispatchmgr__detach(ptrp, __func__, __FILE__, __LINE__)
    116 ISC_REFCOUNT_TRACE_DECL(dns_dispatchmgr);
    117 #else
    118 ISC_REFCOUNT_DECL(dns_dispatchmgr);
    119 #endif
    120 
    121 /*%<
    122  * Attach/Detach to a dispatch manager.
    123  */
    124 
    125 void
    126 dns_dispatchmgr_setblackhole(dns_dispatchmgr_t *mgr, dns_acl_t *blackhole);
    127 /*%<
    128  * Sets the dispatcher's "blackhole list," a list of addresses that will
    129  * be ignored by all dispatchers created by the dispatchmgr.
    130  *
    131  * Requires:
    132  * \li	mgrp is a valid dispatchmgr
    133  * \li	blackhole is a valid acl
    134  */
    135 
    136 dns_acl_t *
    137 dns_dispatchmgr_getblackhole(dns_dispatchmgr_t *mgr);
    138 /*%<
    139  * Gets a pointer to the dispatcher's current blackhole list,
    140  * without incrementing its reference count.
    141  *
    142  * Requires:
    143  *\li	mgr is a valid dispatchmgr
    144  * Returns:
    145  *\li	A pointer to the current blackhole list, or NULL.
    146  */
    147 
    148 isc_result_t
    149 dns_dispatchmgr_setavailports(dns_dispatchmgr_t *mgr, isc_portset_t *v4portset,
    150 			      isc_portset_t *v6portset);
    151 /*%<
    152  * Sets a list of UDP ports that can be used for outgoing UDP messages.
    153  *
    154  * Requires:
    155  *\li	mgr is a valid dispatchmgr
    156  *\li	v4portset is NULL or a valid port set
    157  *\li	v6portset is NULL or a valid port set
    158  */
    159 
    160 void
    161 dns_dispatchmgr_setreusetimeout(dns_dispatchmgr_t *mgr, unsigned int timeout);
    162 /*%<
    163  * Sets the idle timeout (in milliseconds) for a reused outgoing TCP connection.
    164  * While a dispatch has no outstanding responses we keep a read pending so a
    165  * peer-initiated close is noticed promptly; this bounds how long such an idle
    166  * connection is kept open for reuse.
    167  */
    168 
    169 void
    170 dns_dispatchmgr_setstats(dns_dispatchmgr_t *mgr, isc_stats_t *stats);
    171 /*%<
    172  * Sets statistics counter for the dispatchmgr.  This function is expected to
    173  * be called only on zone creation (when necessary).
    174  * Once installed, it cannot be removed or replaced.  Also, there is no
    175  * interface to get the installed stats from the zone; the caller must keep the
    176  * stats to reference (e.g. dump) it later.
    177  *
    178  * Requires:
    179  *\li	mgr is a valid dispatchmgr with no managed dispatch.
    180  *\li	stats is a valid statistics supporting resolver statistics counters
    181  *	(see dns/stats.h).
    182  */
    183 
    184 isc_result_t
    185 dns_dispatch_createudp(dns_dispatchmgr_t *mgr, const isc_sockaddr_t *localaddr,
    186 		       dns_dispatch_t **dispp);
    187 /*%<
    188  * Create a new UDP dispatch.
    189  *
    190  * Requires:
    191  *\li	All pointer parameters be valid for their respective types.
    192  *
    193  *\li	dispp != NULL && *disp == NULL
    194  *
    195  * Returns:
    196  *\li	ISC_R_SUCCESS	-- success.
    197  *
    198  *\li	Anything else	-- failure.
    199  */
    200 
    201 isc_result_t
    202 dns_dispatch_createtcp(dns_dispatchmgr_t *mgr, const isc_sockaddr_t *localaddr,
    203 		       const isc_sockaddr_t *destaddr,
    204 		       dns_transport_t *transport, dns_dispatchtype_t disptype,
    205 		       dns_dispatchopt_t options, dns_dispatch_t **dispp);
    206 /*%<
    207  * Create a new TCP dns_dispatch.
    208  *
    209  * Note: a NULL transport is different from a non-NULL transport of type
    210  *	 DNS_TRANSPORT_TCP, though currently their behavior is the same.
    211  *	 This allows for different types of transactions to be separated
    212  *	 in the future if needed.
    213  *
    214  * Requires:
    215  *
    216  *\li	mgr is a valid dispatch manager.
    217  *
    218  *\li	dstaddr to be a valid sockaddr.
    219  *
    220  *\li	localaddr to be a valid sockaddr.
    221  *
    222  *\li	transport is NULL or a valid transport.
    223  *
    224  *\li	dispp to be non NULL and *dispp to be NULL
    225  *
    226  * Returns:
    227  *\li	ISC_R_SUCCESS	-- success.
    228  *
    229  *\li	Anything else	-- failure.
    230  */
    231 
    232 #if DNS_DISPATCH_TRACE
    233 #define dns_dispatch_ref(ptr) \
    234 	dns_dispatch__ref(ptr, __func__, __FILE__, __LINE__)
    235 #define dns_dispatch_unref(ptr) \
    236 	dns_dispatch__unref(ptr, __func__, __FILE__, __LINE__)
    237 #define dns_dispatch_attach(ptr, ptrp) \
    238 	dns_dispatch__attach(ptr, ptrp, __func__, __FILE__, __LINE__)
    239 #define dns_dispatch_detach(ptrp) \
    240 	dns_dispatch__detach(ptrp, __func__, __FILE__, __LINE__)
    241 ISC_REFCOUNT_TRACE_DECL(dns_dispatch);
    242 #else
    243 ISC_REFCOUNT_DECL(dns_dispatch);
    244 #endif
    245 /*%<
    246  * Attach/Detach to a dispatch handle.
    247  *
    248  * Requires:
    249  *\li	disp is valid.
    250  *
    251  *\li	dispp != NULL && *dispp == NULL
    252  */
    253 
    254 isc_result_t
    255 dns_dispatch_connect(dns_dispentry_t *resp);
    256 /*%<
    257  * Connect to the remote server configured in 'resp' and run the
    258  * connect callback that was set up via dns_dispatch_add().
    259  *
    260  * Requires:
    261  *\li	'resp' is valid.
    262  */
    263 
    264 void
    265 dns_dispatch_send(dns_dispentry_t *resp, isc_region_t *r);
    266 /*%<
    267  * Send region 'r' using the socket in 'resp', then run the specified
    268  * callback.
    269  *
    270  * Requires:
    271  *\li	'resp' is valid.
    272  */
    273 
    274 void
    275 dns_dispatch_resume(dns_dispentry_t *resp, uint16_t timeout);
    276 /*%<
    277  * Reset the read timeout in the socket associated with 'resp' and
    278  * continue reading.
    279  *
    280  * Requires:
    281  *\li	'resp' is valid.
    282  */
    283 
    284 typedef void (*dispatch_cb_t)(isc_result_t eresult, isc_region_t *region,
    285 			      void *cbarg);
    286 
    287 isc_result_t
    288 dns_dispatch_add(dns_dispatch_t *disp, isc_loop_t *loop,
    289 		 dns_dispatchopt_t options, unsigned int timeout,
    290 		 const isc_sockaddr_t *dest, dns_transport_t *transport,
    291 		 isc_tlsctx_cache_t *tlsctx_cache, dispatch_cb_t connected,
    292 		 dispatch_cb_t sent, dispatch_cb_t response, void *arg,
    293 		 dns_messageid_t *idp, dns_dispentry_t **resp);
    294 /*%<
    295  * Add a response entry for this dispatch.
    296  *
    297  * "*idp" is filled in with the assigned message ID, and *resp is filled in
    298  * with the dispatch entry object.
    299  *
    300  * The 'connected' and 'sent' callbacks are run to inform the caller when
    301  * the connect and send functions are complete. The 'timedout' callback
    302  * is run to inform the caller that a read has timed out; it may optionally
    303  * reset the read timer. The 'response' callback is run for recv results
    304  * (response packets, timeouts, or cancellations).
    305  *
    306  * All the callback functions are sent 'arg' as a parameter.
    307  *
    308  * Requires:
    309  *\li	"idp" be non-NULL.
    310  *
    311  *\li	"response" and "arg" be set as appropriate.
    312  *
    313  *\li	"dest" be non-NULL and valid.
    314  *
    315  *\li	"resp" be non-NULL and *resp be NULL
    316  *
    317  *\li	"transport" to be the same one used with dns_dispatch_createtcp or
    318  *	dns_dispatch_gettcp.
    319  *
    320  * Ensures:
    321  *
    322  *\li	&lt;id, dest> is a unique tuple.  That means incoming messages
    323  *	are identifiable.
    324  *
    325  * Returns:
    326  *
    327  *\li	ISC_R_SUCCESS		-- all is well.
    328  *\li	ISC_R_NOMEMORY		-- memory could not be allocated.
    329  *\li	ISC_R_NOMORE		-- no more message ids can be allocated
    330  *				   for this destination.
    331  */
    332 
    333 void
    334 dns_dispatch_done(dns_dispentry_t **respp);
    335 /*<
    336  * Disconnect a dispatch response entry from its dispatch, cancel all
    337  * pending connects and reads in a dispatch entry and shut it down.
    338 
    339  *
    340  * Requires:
    341  *\li	"resp" != NULL and "*resp" contain a value previously allocated
    342  *	by dns_dispatch_add();
    343  */
    344 
    345 isc_result_t
    346 dns_dispatch_getlocaladdress(dns_dispatch_t *disp, isc_sockaddr_t *addrp);
    347 /*%<
    348  * Return the local address for this dispatch.
    349  * This currently only works for dispatches using UDP sockets.
    350  *
    351  * Requires:
    352  *\li	disp is valid.
    353  *\li	addrp to be non NULL.
    354  *
    355  * Returns:
    356  *\li	ISC_R_SUCCESS
    357  *\li	ISC_R_NOTIMPLEMENTED
    358  */
    359 
    360 isc_result_t
    361 dns_dispentry_getlocaladdress(dns_dispentry_t *resp, isc_sockaddr_t *addrp);
    362 /*%<
    363  * Return the local address for this dispatch entry.
    364  *
    365  * Requires:
    366  *\li	resp is valid.
    367  *\li	addrp to be non NULL.
    368  *
    369  * Returns:
    370  *\li	ISC_R_SUCCESS
    371  *\li	ISC_R_NOTIMPLEMENTED
    372  */
    373 
    374 dns_dispatch_t *
    375 dns_dispatchset_get(dns_dispatchset_t *dset);
    376 /*%<
    377  * Retrieve the next dispatch from dispatch set 'dset', and increment
    378  * the round-robin counter.
    379  *
    380  * Requires:
    381  *\li	dset != NULL
    382  */
    383 
    384 isc_result_t
    385 dns_dispatchset_create(isc_mem_t *mctx, dns_dispatch_t *source,
    386 		       dns_dispatchset_t **dsetp, uint32_t n);
    387 /*%<
    388  * Given a valid dispatch 'source', create a dispatch set containing
    389  * 'n' UDP dispatches, with the remainder filled out by clones of the
    390  * source.
    391  *
    392  * Requires:
    393  *\li	source is a valid UDP dispatcher
    394  *\li	dsetp != NULL, *dsetp == NULL
    395  */
    396 
    397 void
    398 dns_dispatchset_destroy(dns_dispatchset_t **dsetp);
    399 /*%<
    400  * Dereference all the dispatches in '*dsetp', free the dispatchset
    401  * memory, and set *dsetp to NULL.
    402  *
    403  * Requires:
    404  *\li	dset is valid
    405  */
    406 
    407 isc_result_t
    408 dns_dispatch_getnext(dns_dispentry_t *resp);
    409 /*%<
    410  * Trigger the sending of the next item off the dispatch queue if present.
    411  *
    412  * Requires:
    413  *\li	resp is valid
    414  */
    415 
    416 isc_result_t
    417 dns_dispatch_checkperm(dns_dispatch_t *disp);
    418 /*%<
    419  * Check whether it is permitted to do a zone transfer over a dispatch.
    420  * See isc_nm_xfr_checkperm().
    421  *
    422  * Requires:
    423  *\li	disp is valid
    424  */
    425 
    426 ISC_LANG_ENDDECLS
    427