bind9/lib/dns/include/dns/dispatch.h
Mark Andrews d5da28d1ca Fix TCP dispatches and transport
Dispatch needs to know the transport that is being used over the
TCP connection to correctly allow for it to be reused.  Add a
transport parameter to dns_dispatch_createtcp and dns_dispatch_gettcp
and use it when selecting a TCP socket for reuse.

(cherry picked from commit baab8a5d75)
2024-10-24 01:21:37 +00:00

439 lines
11 KiB
C

/*
* Copyright (C) Internet Systems Consortium, Inc. ("ISC")
*
* SPDX-License-Identifier: MPL-2.0
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, you can obtain one at https://mozilla.org/MPL/2.0/.
*
* See the COPYRIGHT file distributed with this work for additional
* information regarding copyright ownership.
*/
#pragma once
#include <isc/netmgr.h>
/*****
***** Module Info
*****/
/*! \file dns/dispatch.h
* \brief
* DNS Dispatch Management
* Shared UDP and single-use TCP dispatches for queries and responses.
*
* MP:
*
*\li All locking is performed internally to each dispatch.
* Restrictions apply to dns_dispatch_done().
*
* Reliability:
*
* Resources:
*
* Security:
*
*\li Depends on dns_message_t for prevention of buffer overruns.
*
* Standards:
*
*\li None.
*/
/***
*** Imports
***/
#include <inttypes.h>
#include <stdbool.h>
#include <isc/buffer.h>
#include <isc/lang.h>
#include <isc/mutex.h>
#include <isc/netmgr.h>
#include <isc/refcount.h>
#include <isc/types.h>
#include <dns/types.h>
/* Add -DDNS_DISPATCH_TRACE=1 to CFLAGS for detailed reference tracing */
ISC_LANG_BEGINDECLS
/*%
* This is a set of one or more dispatches which can be retrieved
* round-robin fashion.
*/
struct dns_dispatchset {
isc_mem_t *mctx;
dns_dispatch_t **dispatches;
uint32_t ndisp;
};
typedef enum dns_dispatchopt {
DNS_DISPATCHOPT_FIXEDID = 1 << 0,
DNS_DISPATCHOPT_UNSHARED = 1 << 1, /* Don't share this connection */
} dns_dispatchopt_t;
isc_result_t
dns_dispatchmgr_create(isc_mem_t *mctx, isc_loopmgr_t *loopmgr, isc_nm_t *nm,
dns_dispatchmgr_t **mgrp);
/*%<
* Creates a new dispatchmgr object, and sets the available ports
* to the default range (1024-65535).
*
* Requires:
*\li 'mctx' be a valid memory context.
*
*\li 'nm' is a valid network manager.
*\li mgrp != NULL && *mgrp == NULL
*
* Returns:
*\li ISC_R_SUCCESS -- all ok
*
*\li anything else -- failure
*/
#if DNS_DISPATCH_TRACE
#define dns_dispatchmgr_ref(ptr) \
dns_dispatchmgr__ref(ptr, __func__, __FILE__, __LINE__)
#define dns_dispatchmgr_unref(ptr) \
dns_dispatchmgr__unref(ptr, __func__, __FILE__, __LINE__)
#define dns_dispatchmgr_attach(ptr, ptrp) \
dns_dispatchmgr__attach(ptr, ptrp, __func__, __FILE__, __LINE__)
#define dns_dispatchmgr_detach(ptrp) \
dns_dispatchmgr__detach(ptrp, __func__, __FILE__, __LINE__)
ISC_REFCOUNT_TRACE_DECL(dns_dispatchmgr);
#else
ISC_REFCOUNT_DECL(dns_dispatchmgr);
#endif
/*%<
* Attach/Detach to a dispatch manager.
*/
void
dns_dispatchmgr_setblackhole(dns_dispatchmgr_t *mgr, dns_acl_t *blackhole);
/*%<
* Sets the dispatcher's "blackhole list," a list of addresses that will
* be ignored by all dispatchers created by the dispatchmgr.
*
* Requires:
* \li mgrp is a valid dispatchmgr
* \li blackhole is a valid acl
*/
dns_acl_t *
dns_dispatchmgr_getblackhole(dns_dispatchmgr_t *mgr);
/*%<
* Gets a pointer to the dispatcher's current blackhole list,
* without incrementing its reference count.
*
* Requires:
*\li mgr is a valid dispatchmgr
* Returns:
*\li A pointer to the current blackhole list, or NULL.
*/
isc_result_t
dns_dispatchmgr_setavailports(dns_dispatchmgr_t *mgr, isc_portset_t *v4portset,
isc_portset_t *v6portset);
/*%<
* Sets a list of UDP ports that can be used for outgoing UDP messages.
*
* Requires:
*\li mgr is a valid dispatchmgr
*\li v4portset is NULL or a valid port set
*\li v6portset is NULL or a valid port set
*/
void
dns_dispatchmgr_setstats(dns_dispatchmgr_t *mgr, isc_stats_t *stats);
/*%<
* Sets statistics counter for the dispatchmgr. This function is expected to
* be called only on zone creation (when necessary).
* Once installed, it cannot be removed or replaced. Also, there is no
* interface to get the installed stats from the zone; the caller must keep the
* stats to reference (e.g. dump) it later.
*
* Requires:
*\li mgr is a valid dispatchmgr with no managed dispatch.
*\li stats is a valid statistics supporting resolver statistics counters
* (see dns/stats.h).
*/
isc_result_t
dns_dispatch_createudp(dns_dispatchmgr_t *mgr, const isc_sockaddr_t *localaddr,
dns_dispatch_t **dispp);
/*%<
* Create a new UDP dispatch.
*
* Requires:
*\li All pointer parameters be valid for their respective types.
*
*\li dispp != NULL && *disp == NULL
*
* Returns:
*\li ISC_R_SUCCESS -- success.
*
*\li Anything else -- failure.
*/
isc_result_t
dns_dispatch_createtcp(dns_dispatchmgr_t *mgr, const isc_sockaddr_t *localaddr,
const isc_sockaddr_t *destaddr,
dns_transport_t *transport, dns_dispatchopt_t options,
dns_dispatch_t **dispp);
/*%<
* Create a new TCP dns_dispatch.
*
* Note: a NULL transport is different from a non-NULL transport of type
* DNS_TRANSPORT_TCP, though currently their behavior is the same.
* This allows for different types of transactions to be seperated
* in the future if needed.
*
* Requires:
*
*\li mgr is a valid dispatch manager.
*
*\li dstaddr to be a valid sockaddr.
*
*\li localaddr to be a valid sockaddr.
*
*\li transport is NULL or a valid transport.
*
*\li dispp to be non NULL and *dispp to be NULL
*
* Returns:
*\li ISC_R_SUCCESS -- success.
*
*\li Anything else -- failure.
*/
#if DNS_DISPATCH_TRACE
#define dns_dispatch_ref(ptr) \
dns_dispatch__ref(ptr, __func__, __FILE__, __LINE__)
#define dns_dispatch_unref(ptr) \
dns_dispatch__unref(ptr, __func__, __FILE__, __LINE__)
#define dns_dispatch_attach(ptr, ptrp) \
dns_dispatch__attach(ptr, ptrp, __func__, __FILE__, __LINE__)
#define dns_dispatch_detach(ptrp) \
dns_dispatch__detach(ptrp, __func__, __FILE__, __LINE__)
ISC_REFCOUNT_TRACE_DECL(dns_dispatch);
#else
ISC_REFCOUNT_DECL(dns_dispatch);
#endif
/*%<
* Attach/Detach to a dispatch handle.
*
* Requires:
*\li disp is valid.
*
*\li dispp != NULL && *dispp == NULL
*/
isc_result_t
dns_dispatch_connect(dns_dispentry_t *resp);
/*%<
* Connect to the remote server configured in 'resp' and run the
* connect callback that was set up via dns_dispatch_add().
*
* Requires:
*\li 'resp' is valid.
*/
void
dns_dispatch_send(dns_dispentry_t *resp, isc_region_t *r);
/*%<
* Send region 'r' using the socket in 'resp', then run the specified
* callback.
*
* Requires:
*\li 'resp' is valid.
*/
void
dns_dispatch_resume(dns_dispentry_t *resp, uint16_t timeout);
/*%<
* Reset the read timeout in the socket associated with 'resp' and
* continue reading.
*
* Requires:
*\li 'resp' is valid.
*/
isc_result_t
dns_dispatch_gettcp(dns_dispatchmgr_t *mgr, const isc_sockaddr_t *destaddr,
const isc_sockaddr_t *localaddr, dns_transport_t *transport,
dns_dispatch_t **dispp);
/*
* Attempt to connect to a existing TCP connection that was created with
* parameters that match destaddr, localaddr and transport.
*
* If localaddr is NULL, we ignore the dispatch's localaddr when looking
* for a match. However, if transport is NULL, then the matching dispatch
* must also have been created with a NULL transport.
*
* Requires:
*\li mgr to be valid dispatch manager.
*
*\li dstaddr to be a valid sockaddr.
*
*\li localaddr to be NULL or a valid sockaddr.
*
*\li transport is NULL or a valid transport.
*
*\li dispp to be non NULL and *dispp to be NULL
*
* Returns:
*\li ISC_R_SUCCESS -- success.
*
*\li Anything else -- failure.
*/
typedef void (*dispatch_cb_t)(isc_result_t eresult, isc_region_t *region,
void *cbarg);
isc_result_t
dns_dispatch_add(dns_dispatch_t *disp, isc_loop_t *loop,
dns_dispatchopt_t options, unsigned int timeout,
const isc_sockaddr_t *dest, dns_transport_t *transport,
isc_tlsctx_cache_t *tlsctx_cache, dispatch_cb_t connected,
dispatch_cb_t sent, dispatch_cb_t response, void *arg,
dns_messageid_t *idp, dns_dispentry_t **resp);
/*%<
* Add a response entry for this dispatch.
*
* "*idp" is filled in with the assigned message ID, and *resp is filled in
* with the dispatch entry object.
*
* The 'connected' and 'sent' callbacks are run to inform the caller when
* the connect and send functions are complete. The 'timedout' callback
* is run to inform the caller that a read has timed out; it may optionally
* reset the read timer. The 'response' callback is run for recv results
* (response packets, timeouts, or cancellations).
*
* All the callback functions are sent 'arg' as a parameter.
*
* Requires:
*\li "idp" be non-NULL.
*
*\li "response" and "arg" be set as appropriate.
*
*\li "dest" be non-NULL and valid.
*
*\li "resp" be non-NULL and *resp be NULL
*
*\li "transport" to be the same one used with dns_dispatch_createtcp or
* dns_dispatch_gettcp.
*
* Ensures:
*
*\li &lt;id, dest> is a unique tuple. That means incoming messages
* are identifiable.
*
* Returns:
*
*\li ISC_R_SUCCESS -- all is well.
*\li ISC_R_NOMEMORY -- memory could not be allocated.
*\li ISC_R_NOMORE -- no more message ids can be allocated
* for this destination.
*/
void
dns_dispatch_done(dns_dispentry_t **respp);
/*<
* Disconnect a dispatch response entry from its dispatch, cancel all
* pending connects and reads in a dispatch entry and shut it down.
*
* Requires:
*\li "resp" != NULL and "*resp" contain a value previously allocated
* by dns_dispatch_add();
*/
isc_result_t
dns_dispatch_getlocaladdress(dns_dispatch_t *disp, isc_sockaddr_t *addrp);
/*%<
* Return the local address for this dispatch.
* This currently only works for dispatches using UDP sockets.
*
* Requires:
*\li disp is valid.
*\li addrp to be non NULL.
*
* Returns:
*\li ISC_R_SUCCESS
*\li ISC_R_NOTIMPLEMENTED
*/
isc_result_t
dns_dispentry_getlocaladdress(dns_dispentry_t *resp, isc_sockaddr_t *addrp);
/*%<
* Return the local address for this dispatch entry.
*
* Requires:
*\li resp is valid.
*\li addrp to be non NULL.
*
* Returns:
*\li ISC_R_SUCCESS
*\li ISC_R_NOTIMPLEMENTED
*/
dns_dispatch_t *
dns_dispatchset_get(dns_dispatchset_t *dset);
/*%<
* Retrieve the next dispatch from dispatch set 'dset', and increment
* the round-robin counter.
*
* Requires:
*\li dset != NULL
*/
isc_result_t
dns_dispatchset_create(isc_mem_t *mctx, dns_dispatch_t *source,
dns_dispatchset_t **dsetp, uint32_t n);
/*%<
* Given a valid dispatch 'source', create a dispatch set containing
* 'n' UDP dispatches, with the remainder filled out by clones of the
* source.
*
* Requires:
*\li source is a valid UDP dispatcher
*\li dsetp != NULL, *dsetp == NULL
*/
void
dns_dispatchset_destroy(dns_dispatchset_t **dsetp);
/*%<
* Dereference all the dispatches in '*dsetp', free the dispatchset
* memory, and set *dsetp to NULL.
*
* Requires:
*\li dset is valid
*/
isc_result_t
dns_dispatch_getnext(dns_dispentry_t *resp);
/*%<
* Trigger the sending of the next item off the dispatch queue if present.
*
* Requires:
*\li resp is valid
*/
isc_result_t
dns_dispatch_checkperm(dns_dispatch_t *disp);
/*%<
* Check whether it is permitted to do a zone transfer over a dispatch.
* See isc_nm_xfr_checkperm().
*
* Requires:
*\li disp is valid
*/
ISC_LANG_ENDDECLS