1 /* $NetBSD: dispatch.h,v 1.8 2025/01/26 16:25:26 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_UNSHARED = 1 << 1, /* Don't share this connection */ 80 } dns_dispatchopt_t; 81 82 isc_result_t 83 dns_dispatchmgr_create(isc_mem_t *mctx, isc_loopmgr_t *loopmgr, isc_nm_t *nm, 84 dns_dispatchmgr_t **mgrp); 85 /*%< 86 * Creates a new dispatchmgr object, and sets the available ports 87 * to the default range (1024-65535). 88 * 89 * Requires: 90 *\li 'mctx' be a valid memory context. 91 * 92 *\li 'nm' is a valid network manager. 93 94 *\li mgrp != NULL && *mgrp == NULL 95 * 96 * Returns: 97 *\li ISC_R_SUCCESS -- all ok 98 * 99 *\li anything else -- failure 100 */ 101 102 #if DNS_DISPATCH_TRACE 103 #define dns_dispatchmgr_ref(ptr) \ 104 dns_dispatchmgr__ref(ptr, __func__, __FILE__, __LINE__) 105 #define dns_dispatchmgr_unref(ptr) \ 106 dns_dispatchmgr__unref(ptr, __func__, __FILE__, __LINE__) 107 #define dns_dispatchmgr_attach(ptr, ptrp) \ 108 dns_dispatchmgr__attach(ptr, ptrp, __func__, __FILE__, __LINE__) 109 #define dns_dispatchmgr_detach(ptrp) \ 110 dns_dispatchmgr__detach(ptrp, __func__, __FILE__, __LINE__) 111 ISC_REFCOUNT_TRACE_DECL(dns_dispatchmgr); 112 #else 113 ISC_REFCOUNT_DECL(dns_dispatchmgr); 114 #endif 115 116 /*%< 117 * Attach/Detach to a dispatch manager. 118 */ 119 120 void 121 dns_dispatchmgr_setblackhole(dns_dispatchmgr_t *mgr, dns_acl_t *blackhole); 122 /*%< 123 * Sets the dispatcher's "blackhole list," a list of addresses that will 124 * be ignored by all dispatchers created by the dispatchmgr. 125 * 126 * Requires: 127 * \li mgrp is a valid dispatchmgr 128 * \li blackhole is a valid acl 129 */ 130 131 dns_acl_t * 132 dns_dispatchmgr_getblackhole(dns_dispatchmgr_t *mgr); 133 /*%< 134 * Gets a pointer to the dispatcher's current blackhole list, 135 * without incrementing its reference count. 136 * 137 * Requires: 138 *\li mgr is a valid dispatchmgr 139 * Returns: 140 *\li A pointer to the current blackhole list, or NULL. 141 */ 142 143 isc_result_t 144 dns_dispatchmgr_setavailports(dns_dispatchmgr_t *mgr, isc_portset_t *v4portset, 145 isc_portset_t *v6portset); 146 /*%< 147 * Sets a list of UDP ports that can be used for outgoing UDP messages. 148 * 149 * Requires: 150 *\li mgr is a valid dispatchmgr 151 *\li v4portset is NULL or a valid port set 152 *\li v6portset is NULL or a valid port set 153 */ 154 155 void 156 dns_dispatchmgr_setstats(dns_dispatchmgr_t *mgr, isc_stats_t *stats); 157 /*%< 158 * Sets statistics counter for the dispatchmgr. This function is expected to 159 * be called only on zone creation (when necessary). 160 * Once installed, it cannot be removed or replaced. Also, there is no 161 * interface to get the installed stats from the zone; the caller must keep the 162 * stats to reference (e.g. dump) it later. 163 * 164 * Requires: 165 *\li mgr is a valid dispatchmgr with no managed dispatch. 166 *\li stats is a valid statistics supporting resolver statistics counters 167 * (see dns/stats.h). 168 */ 169 170 isc_result_t 171 dns_dispatch_createudp(dns_dispatchmgr_t *mgr, const isc_sockaddr_t *localaddr, 172 dns_dispatch_t **dispp); 173 /*%< 174 * Create a new UDP dispatch. 175 * 176 * Requires: 177 *\li All pointer parameters be valid for their respective types. 178 * 179 *\li dispp != NULL && *disp == NULL 180 * 181 * Returns: 182 *\li ISC_R_SUCCESS -- success. 183 * 184 *\li Anything else -- failure. 185 */ 186 187 isc_result_t 188 dns_dispatch_createtcp(dns_dispatchmgr_t *mgr, const isc_sockaddr_t *localaddr, 189 const isc_sockaddr_t *destaddr, 190 dns_transport_t *transport, dns_dispatchopt_t options, 191 dns_dispatch_t **dispp); 192 /*%< 193 * Create a new TCP dns_dispatch. 194 * 195 * Note: a NULL transport is different from a non-NULL transport of type 196 * DNS_TRANSPORT_TCP, though currently their behavior is the same. 197 * This allows for different types of transactions to be seperated 198 * in the future if needed. 199 * 200 * Requires: 201 * 202 *\li mgr is a valid dispatch manager. 203 * 204 *\li dstaddr to be a valid sockaddr. 205 * 206 *\li localaddr to be a valid sockaddr. 207 * 208 *\li transport is NULL or a valid transport. 209 * 210 *\li dispp to be non NULL and *dispp to be NULL 211 * 212 * Returns: 213 *\li ISC_R_SUCCESS -- success. 214 * 215 *\li Anything else -- failure. 216 */ 217 218 #if DNS_DISPATCH_TRACE 219 #define dns_dispatch_ref(ptr) \ 220 dns_dispatch__ref(ptr, __func__, __FILE__, __LINE__) 221 #define dns_dispatch_unref(ptr) \ 222 dns_dispatch__unref(ptr, __func__, __FILE__, __LINE__) 223 #define dns_dispatch_attach(ptr, ptrp) \ 224 dns_dispatch__attach(ptr, ptrp, __func__, __FILE__, __LINE__) 225 #define dns_dispatch_detach(ptrp) \ 226 dns_dispatch__detach(ptrp, __func__, __FILE__, __LINE__) 227 ISC_REFCOUNT_TRACE_DECL(dns_dispatch); 228 #else 229 ISC_REFCOUNT_DECL(dns_dispatch); 230 #endif 231 /*%< 232 * Attach/Detach to a dispatch handle. 233 * 234 * Requires: 235 *\li disp is valid. 236 * 237 *\li dispp != NULL && *dispp == NULL 238 */ 239 240 isc_result_t 241 dns_dispatch_connect(dns_dispentry_t *resp); 242 /*%< 243 * Connect to the remote server configured in 'resp' and run the 244 * connect callback that was set up via dns_dispatch_add(). 245 * 246 * Requires: 247 *\li 'resp' is valid. 248 */ 249 250 void 251 dns_dispatch_send(dns_dispentry_t *resp, isc_region_t *r); 252 /*%< 253 * Send region 'r' using the socket in 'resp', then run the specified 254 * callback. 255 * 256 * Requires: 257 *\li 'resp' is valid. 258 */ 259 260 void 261 dns_dispatch_resume(dns_dispentry_t *resp, uint16_t timeout); 262 /*%< 263 * Reset the read timeout in the socket associated with 'resp' and 264 * continue reading. 265 * 266 * Requires: 267 *\li 'resp' is valid. 268 */ 269 270 isc_result_t 271 dns_dispatch_gettcp(dns_dispatchmgr_t *mgr, const isc_sockaddr_t *destaddr, 272 const isc_sockaddr_t *localaddr, dns_transport_t *transport, 273 dns_dispatch_t **dispp); 274 /* 275 * Attempt to connect to a existing TCP connection that was created with 276 * parameters that match destaddr, localaddr and transport. 277 * 278 * If localaddr is NULL, we ignore the dispatch's localaddr when looking 279 * for a match. However, if transport is NULL, then the matching dispatch 280 * must also have been created with a NULL transport. 281 * 282 * Requires: 283 *\li mgr to be valid dispatch manager. 284 * 285 *\li dstaddr to be a valid sockaddr. 286 * 287 *\li localaddr to be NULL or a valid sockaddr. 288 * 289 *\li transport is NULL or a valid transport. 290 * 291 *\li dispp to be non NULL and *dispp to be NULL 292 * 293 * Returns: 294 *\li ISC_R_SUCCESS -- success. 295 * 296 *\li Anything else -- failure. 297 */ 298 299 typedef void (*dispatch_cb_t)(isc_result_t eresult, isc_region_t *region, 300 void *cbarg); 301 302 isc_result_t 303 dns_dispatch_add(dns_dispatch_t *disp, isc_loop_t *loop, 304 dns_dispatchopt_t options, unsigned int timeout, 305 const isc_sockaddr_t *dest, dns_transport_t *transport, 306 isc_tlsctx_cache_t *tlsctx_cache, dispatch_cb_t connected, 307 dispatch_cb_t sent, dispatch_cb_t response, void *arg, 308 dns_messageid_t *idp, dns_dispentry_t **resp); 309 /*%< 310 * Add a response entry for this dispatch. 311 * 312 * "*idp" is filled in with the assigned message ID, and *resp is filled in 313 * with the dispatch entry object. 314 * 315 * The 'connected' and 'sent' callbacks are run to inform the caller when 316 * the connect and send functions are complete. The 'timedout' callback 317 * is run to inform the caller that a read has timed out; it may optionally 318 * reset the read timer. The 'response' callback is run for recv results 319 * (response packets, timeouts, or cancellations). 320 * 321 * All the callback functions are sent 'arg' as a parameter. 322 * 323 * Requires: 324 *\li "idp" be non-NULL. 325 * 326 *\li "response" and "arg" be set as appropriate. 327 * 328 *\li "dest" be non-NULL and valid. 329 * 330 *\li "resp" be non-NULL and *resp be NULL 331 * 332 *\li "transport" to be the same one used with dns_dispatch_createtcp or 333 * dns_dispatch_gettcp. 334 * 335 * Ensures: 336 * 337 *\li <id, dest> is a unique tuple. That means incoming messages 338 * are identifiable. 339 * 340 * Returns: 341 * 342 *\li ISC_R_SUCCESS -- all is well. 343 *\li ISC_R_NOMEMORY -- memory could not be allocated. 344 *\li ISC_R_NOMORE -- no more message ids can be allocated 345 * for this destination. 346 */ 347 348 void 349 dns_dispatch_done(dns_dispentry_t **respp); 350 /*< 351 * Disconnect a dispatch response entry from its dispatch, cancel all 352 * pending connects and reads in a dispatch entry and shut it down. 353 354 * 355 * Requires: 356 *\li "resp" != NULL and "*resp" contain a value previously allocated 357 * by dns_dispatch_add(); 358 */ 359 360 isc_result_t 361 dns_dispatch_getlocaladdress(dns_dispatch_t *disp, isc_sockaddr_t *addrp); 362 /*%< 363 * Return the local address for this dispatch. 364 * This currently only works for dispatches using UDP sockets. 365 * 366 * Requires: 367 *\li disp is valid. 368 *\li addrp to be non NULL. 369 * 370 * Returns: 371 *\li ISC_R_SUCCESS 372 *\li ISC_R_NOTIMPLEMENTED 373 */ 374 375 isc_result_t 376 dns_dispentry_getlocaladdress(dns_dispentry_t *resp, isc_sockaddr_t *addrp); 377 /*%< 378 * Return the local address for this dispatch entry. 379 * 380 * Requires: 381 *\li resp is valid. 382 *\li addrp to be non NULL. 383 * 384 * Returns: 385 *\li ISC_R_SUCCESS 386 *\li ISC_R_NOTIMPLEMENTED 387 */ 388 389 dns_dispatch_t * 390 dns_dispatchset_get(dns_dispatchset_t *dset); 391 /*%< 392 * Retrieve the next dispatch from dispatch set 'dset', and increment 393 * the round-robin counter. 394 * 395 * Requires: 396 *\li dset != NULL 397 */ 398 399 isc_result_t 400 dns_dispatchset_create(isc_mem_t *mctx, dns_dispatch_t *source, 401 dns_dispatchset_t **dsetp, uint32_t n); 402 /*%< 403 * Given a valid dispatch 'source', create a dispatch set containing 404 * 'n' UDP dispatches, with the remainder filled out by clones of the 405 * source. 406 * 407 * Requires: 408 *\li source is a valid UDP dispatcher 409 *\li dsetp != NULL, *dsetp == NULL 410 */ 411 412 void 413 dns_dispatchset_destroy(dns_dispatchset_t **dsetp); 414 /*%< 415 * Dereference all the dispatches in '*dsetp', free the dispatchset 416 * memory, and set *dsetp to NULL. 417 * 418 * Requires: 419 *\li dset is valid 420 */ 421 422 isc_result_t 423 dns_dispatch_getnext(dns_dispentry_t *resp); 424 /*%< 425 * Trigger the sending of the next item off the dispatch queue if present. 426 * 427 * Requires: 428 *\li resp is valid 429 */ 430 431 isc_result_t 432 dns_dispatch_checkperm(dns_dispatch_t *disp); 433 /*%< 434 * Check whether it is permitted to do a zone transfer over a dispatch. 435 * See isc_nm_xfr_checkperm(). 436 * 437 * Requires: 438 *\li disp is valid 439 */ 440 441 ISC_LANG_ENDDECLS 442