1 /* $NetBSD: dispatch.h,v 1.9 2026/05/20 16:53:46 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_setstats(dns_dispatchmgr_t *mgr, isc_stats_t *stats); 162 /*%< 163 * Sets statistics counter for the dispatchmgr. This function is expected to 164 * be called only on zone creation (when necessary). 165 * Once installed, it cannot be removed or replaced. Also, there is no 166 * interface to get the installed stats from the zone; the caller must keep the 167 * stats to reference (e.g. dump) it later. 168 * 169 * Requires: 170 *\li mgr is a valid dispatchmgr with no managed dispatch. 171 *\li stats is a valid statistics supporting resolver statistics counters 172 * (see dns/stats.h). 173 */ 174 175 isc_result_t 176 dns_dispatch_createudp(dns_dispatchmgr_t *mgr, const isc_sockaddr_t *localaddr, 177 dns_dispatch_t **dispp); 178 /*%< 179 * Create a new UDP dispatch. 180 * 181 * Requires: 182 *\li All pointer parameters be valid for their respective types. 183 * 184 *\li dispp != NULL && *disp == NULL 185 * 186 * Returns: 187 *\li ISC_R_SUCCESS -- success. 188 * 189 *\li Anything else -- failure. 190 */ 191 192 isc_result_t 193 dns_dispatch_createtcp(dns_dispatchmgr_t *mgr, const isc_sockaddr_t *localaddr, 194 const isc_sockaddr_t *destaddr, 195 dns_transport_t *transport, dns_dispatchtype_t disptype, 196 dns_dispatchopt_t options, dns_dispatch_t **dispp); 197 /*%< 198 * Create a new TCP dns_dispatch. 199 * 200 * Note: a NULL transport is different from a non-NULL transport of type 201 * DNS_TRANSPORT_TCP, though currently their behavior is the same. 202 * This allows for different types of transactions to be seperated 203 * in the future if needed. 204 * 205 * Requires: 206 * 207 *\li mgr is a valid dispatch manager. 208 * 209 *\li dstaddr to be a valid sockaddr. 210 * 211 *\li localaddr to be a valid sockaddr. 212 * 213 *\li transport is NULL or a valid transport. 214 * 215 *\li dispp to be non NULL and *dispp to be NULL 216 * 217 * Returns: 218 *\li ISC_R_SUCCESS -- success. 219 * 220 *\li Anything else -- failure. 221 */ 222 223 #if DNS_DISPATCH_TRACE 224 #define dns_dispatch_ref(ptr) \ 225 dns_dispatch__ref(ptr, __func__, __FILE__, __LINE__) 226 #define dns_dispatch_unref(ptr) \ 227 dns_dispatch__unref(ptr, __func__, __FILE__, __LINE__) 228 #define dns_dispatch_attach(ptr, ptrp) \ 229 dns_dispatch__attach(ptr, ptrp, __func__, __FILE__, __LINE__) 230 #define dns_dispatch_detach(ptrp) \ 231 dns_dispatch__detach(ptrp, __func__, __FILE__, __LINE__) 232 ISC_REFCOUNT_TRACE_DECL(dns_dispatch); 233 #else 234 ISC_REFCOUNT_DECL(dns_dispatch); 235 #endif 236 /*%< 237 * Attach/Detach to a dispatch handle. 238 * 239 * Requires: 240 *\li disp is valid. 241 * 242 *\li dispp != NULL && *dispp == NULL 243 */ 244 245 isc_result_t 246 dns_dispatch_connect(dns_dispentry_t *resp); 247 /*%< 248 * Connect to the remote server configured in 'resp' and run the 249 * connect callback that was set up via dns_dispatch_add(). 250 * 251 * Requires: 252 *\li 'resp' is valid. 253 */ 254 255 void 256 dns_dispatch_send(dns_dispentry_t *resp, isc_region_t *r); 257 /*%< 258 * Send region 'r' using the socket in 'resp', then run the specified 259 * callback. 260 * 261 * Requires: 262 *\li 'resp' is valid. 263 */ 264 265 void 266 dns_dispatch_resume(dns_dispentry_t *resp, uint16_t timeout); 267 /*%< 268 * Reset the read timeout in the socket associated with 'resp' and 269 * continue reading. 270 * 271 * Requires: 272 *\li 'resp' is valid. 273 */ 274 275 typedef void (*dispatch_cb_t)(isc_result_t eresult, isc_region_t *region, 276 void *cbarg); 277 278 isc_result_t 279 dns_dispatch_add(dns_dispatch_t *disp, isc_loop_t *loop, 280 dns_dispatchopt_t options, unsigned int timeout, 281 const isc_sockaddr_t *dest, dns_transport_t *transport, 282 isc_tlsctx_cache_t *tlsctx_cache, dispatch_cb_t connected, 283 dispatch_cb_t sent, dispatch_cb_t response, void *arg, 284 dns_messageid_t *idp, dns_dispentry_t **resp); 285 /*%< 286 * Add a response entry for this dispatch. 287 * 288 * "*idp" is filled in with the assigned message ID, and *resp is filled in 289 * with the dispatch entry object. 290 * 291 * The 'connected' and 'sent' callbacks are run to inform the caller when 292 * the connect and send functions are complete. The 'timedout' callback 293 * is run to inform the caller that a read has timed out; it may optionally 294 * reset the read timer. The 'response' callback is run for recv results 295 * (response packets, timeouts, or cancellations). 296 * 297 * All the callback functions are sent 'arg' as a parameter. 298 * 299 * Requires: 300 *\li "idp" be non-NULL. 301 * 302 *\li "response" and "arg" be set as appropriate. 303 * 304 *\li "dest" be non-NULL and valid. 305 * 306 *\li "resp" be non-NULL and *resp be NULL 307 * 308 *\li "transport" to be the same one used with dns_dispatch_createtcp or 309 * dns_dispatch_gettcp. 310 * 311 * Ensures: 312 * 313 *\li <id, dest> is a unique tuple. That means incoming messages 314 * are identifiable. 315 * 316 * Returns: 317 * 318 *\li ISC_R_SUCCESS -- all is well. 319 *\li ISC_R_NOMEMORY -- memory could not be allocated. 320 *\li ISC_R_NOMORE -- no more message ids can be allocated 321 * for this destination. 322 */ 323 324 void 325 dns_dispatch_done(dns_dispentry_t **respp); 326 /*< 327 * Disconnect a dispatch response entry from its dispatch, cancel all 328 * pending connects and reads in a dispatch entry and shut it down. 329 330 * 331 * Requires: 332 *\li "resp" != NULL and "*resp" contain a value previously allocated 333 * by dns_dispatch_add(); 334 */ 335 336 isc_result_t 337 dns_dispatch_getlocaladdress(dns_dispatch_t *disp, isc_sockaddr_t *addrp); 338 /*%< 339 * Return the local address for this dispatch. 340 * This currently only works for dispatches using UDP sockets. 341 * 342 * Requires: 343 *\li disp is valid. 344 *\li addrp to be non NULL. 345 * 346 * Returns: 347 *\li ISC_R_SUCCESS 348 *\li ISC_R_NOTIMPLEMENTED 349 */ 350 351 isc_result_t 352 dns_dispentry_getlocaladdress(dns_dispentry_t *resp, isc_sockaddr_t *addrp); 353 /*%< 354 * Return the local address for this dispatch entry. 355 * 356 * Requires: 357 *\li resp is valid. 358 *\li addrp to be non NULL. 359 * 360 * Returns: 361 *\li ISC_R_SUCCESS 362 *\li ISC_R_NOTIMPLEMENTED 363 */ 364 365 dns_dispatch_t * 366 dns_dispatchset_get(dns_dispatchset_t *dset); 367 /*%< 368 * Retrieve the next dispatch from dispatch set 'dset', and increment 369 * the round-robin counter. 370 * 371 * Requires: 372 *\li dset != NULL 373 */ 374 375 isc_result_t 376 dns_dispatchset_create(isc_mem_t *mctx, dns_dispatch_t *source, 377 dns_dispatchset_t **dsetp, uint32_t n); 378 /*%< 379 * Given a valid dispatch 'source', create a dispatch set containing 380 * 'n' UDP dispatches, with the remainder filled out by clones of the 381 * source. 382 * 383 * Requires: 384 *\li source is a valid UDP dispatcher 385 *\li dsetp != NULL, *dsetp == NULL 386 */ 387 388 void 389 dns_dispatchset_destroy(dns_dispatchset_t **dsetp); 390 /*%< 391 * Dereference all the dispatches in '*dsetp', free the dispatchset 392 * memory, and set *dsetp to NULL. 393 * 394 * Requires: 395 *\li dset is valid 396 */ 397 398 isc_result_t 399 dns_dispatch_getnext(dns_dispentry_t *resp); 400 /*%< 401 * Trigger the sending of the next item off the dispatch queue if present. 402 * 403 * Requires: 404 *\li resp is valid 405 */ 406 407 isc_result_t 408 dns_dispatch_checkperm(dns_dispatch_t *disp); 409 /*%< 410 * Check whether it is permitted to do a zone transfer over a dispatch. 411 * See isc_nm_xfr_checkperm(). 412 * 413 * Requires: 414 *\li disp is valid 415 */ 416 417 ISC_LANG_ENDDECLS 418