xref: /netbsd-src/external/mpl/bind/dist/lib/dns/include/dns/dispatch.h (revision bcda20f65a8566e103791ec395f7f499ef322704)
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	&lt;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