Home | History | Annotate | Line # | Download | only in isc
      1 /*	$NetBSD: netmgr.h,v 1.12 2026/04/08 00:16:16 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 <sys/socket.h>
     19 #include <sys/types.h>
     20 #include <unistd.h>
     21 
     22 #include <isc/mem.h>
     23 #include <isc/refcount.h>
     24 #include <isc/region.h>
     25 #include <isc/result.h>
     26 #include <isc/sockaddr.h>
     27 #include <isc/tls.h>
     28 #include <isc/types.h>
     29 
     30 /* Add -DISC_NETMGR_TRACE=1 to CFLAGS for detailed reference tracing */
     31 
     32 #if defined(SO_REUSEPORT_LB) || (defined(SO_REUSEPORT) && defined(__linux__))
     33 #define HAVE_SO_REUSEPORT_LB 1
     34 #endif
     35 
     36 /*
     37  * Convenience macros to specify on how many threads should socket listen
     38  */
     39 #define ISC_NM_LISTEN_ALL 0
     40 #define ISC_NM_LISTEN_ONE 1
     41 
     42 /*
     43  * Replacement for isc_sockettype_t provided by socket.h.
     44  */
     45 typedef enum {
     46 	isc_socktype_tcp = 1,
     47 	isc_socktype_udp = 2,
     48 	isc_socktype_unix = 3,
     49 	isc_socktype_raw = 4
     50 } isc_socktype_t;
     51 
     52 typedef void (*isc_nm_recv_cb_t)(isc_nmhandle_t *handle, isc_result_t eresult,
     53 				 isc_region_t *region, void *cbarg);
     54 /*%<
     55  * Callback function to be used when receiving a packet.
     56  *
     57  * 'handle' the handle that can be used to send back the answer.
     58  * 'eresult' the result of the event.
     59  * 'region' contains the received data, if any. It will be freed
     60  *          after return by caller.
     61  * 'cbarg'  the callback argument passed to isc_nm_listenudp(),
     62  *          isc_nm_listenstreamdns(), or isc_nm_read().
     63  */
     64 typedef isc_result_t (*isc_nm_accept_cb_t)(isc_nmhandle_t *handle,
     65 					   isc_result_t result, void *cbarg);
     66 /*%<
     67  * Callback function to be used when accepting a connection. (This differs
     68  * from isc_nm_cb_t below in that it returns a result code.)
     69  *
     70  * 'handle' the handle that can be used to send back the answer.
     71  * 'eresult' the result of the event.
     72  * 'cbarg'  the callback argument passed to isc_nm_listentcp() or
     73  * isc_nm_listenstreamdns().
     74  */
     75 
     76 typedef void (*isc_nm_cb_t)(isc_nmhandle_t *handle, isc_result_t result,
     77 			    void *cbarg);
     78 /*%<
     79  * Callback function for other network completion events (send, connect).
     80  *
     81  * 'handle' the handle on which the event took place.
     82  * 'eresult' the result of the event.
     83  * 'cbarg'  the callback argument passed to isc_nm_send(),
     84  *          isc_nm_tcp_connect(), or isc_nm_listentcp()
     85  */
     86 
     87 typedef void (*isc_nm_opaquecb_t)(void *arg);
     88 /*%<
     89  * Opaque callback function, used for isc_nmhandle 'reset' and 'free'
     90  * callbacks.
     91  */
     92 
     93 typedef struct isc_nm_proxyheader_info {
     94 	bool complete;
     95 	union {
     96 		isc_region_t complete_header; /* complete header data */
     97 		struct {
     98 			isc_sockaddr_t src_addr;
     99 			isc_sockaddr_t dst_addr;
    100 			isc_region_t   tlv_data;
    101 		} proxy_info; /* information to put into the new header */
    102 	};
    103 } isc_nm_proxyheader_info_t;
    104 /*%<
    105  * Information to put into the PROXYv2 header when establishing a connection.
    106  */
    107 
    108 typedef enum isc_nm_proxy_type {
    109 	ISC_NM_PROXY_NONE = 0,
    110 	ISC_NM_PROXY_PLAIN = 1,
    111 	ISC_NM_PROXY_ENCRYPTED = 2
    112 } isc_nm_proxy_type_t;
    113 /*%<
    114  * PROXYv2 support type:
    115  *
    116  * - ISC_NM_PROXY_NONE - no PROXY headers are expected;
    117  * - ISC_NM_PROXY_PLAIN - PROXY headers are sent ahead of any encryption, right
    118  *                        after TCP connection establishment;
    119  * - ISC_NM_PROXY_ENCRYPTED - PROXY headers are sent after TLS handshakes.
    120  */
    121 
    122 void
    123 isc_netmgr_create(isc_mem_t *mctx, isc_loopmgr_t *loopmgr, isc_nm_t **netgmrp);
    124 /*%<
    125  * Creates a new network manager and starts it running when loopmgr is started.
    126  */
    127 
    128 void
    129 isc_netmgr_destroy(isc_nm_t **netmgrp);
    130 /*%<
    131  * Similar to isc_nm_detach(), but requires all other references to be gone.
    132  */
    133 
    134 void
    135 isc_nm_attach(isc_nm_t *mgr, isc_nm_t **dst);
    136 void
    137 isc_nm_detach(isc_nm_t **mgr0);
    138 /*%<
    139  * Attach/detach a network manager. When all references have been
    140  * released, the network manager is shut down, freeing all resources.
    141  */
    142 
    143 void
    144 isc_nmsocket_close(isc_nmsocket_t **sockp);
    145 /*%<
    146  * isc_nmsocket_close() detaches a listening socket that was
    147  * created by isc_nm_listenudp(), isc_nm_listentcp(), or
    148  * isc_nm_listentcpdns(). Once there are no remaining child
    149  * sockets with active handles, the socket will be closed.
    150  */
    151 
    152 void
    153 isc_nmsocket_set_tlsctx(isc_nmsocket_t *listener, isc_tlsctx_t *tlsctx);
    154 /*%<
    155  * Asynchronously replace the TLS context within the listener socket object.
    156  * The function is intended to be used during reconfiguration.
    157  *
    158  * Requires:
    159  * \li	'listener' is a pointer to a valid network manager listener socket
    160  object with TLS support;
    161  * \li	'tlsctx' is a valid pointer to a TLS context object.
    162  */
    163 
    164 void
    165 isc_nmsocket_set_max_streams(isc_nmsocket_t *listener,
    166 			     const uint32_t  max_streams);
    167 /*%<
    168  * Set the maximum allowed number of concurrent streams for accepted
    169  * client connections. The implementation might be asynchronous
    170  * depending on the listener socket type.
    171  *
    172  * The call is a no-op for any listener socket type that does not
    173  * support concept of multiple sessions per a client
    174  * connection. Currently, it works only for HTTP/2 listeners.
    175  *
    176  * Setting 'max_streams' to '0' instructs the listener that there is
    177  * no limit for concurrent streams.
    178  *
    179  * Requires:
    180  * \li	'listener' is a pointer to a valid network manager listener socket.
    181  */
    182 
    183 #if ISC_NETMGR_TRACE
    184 #define isc_nmhandle_ref(ptr) \
    185 	isc_nmhandle__ref(ptr, __func__, __FILE__, __LINE__)
    186 #define isc_nmhandle_unref(ptr) \
    187 	isc_nmhandle__unref(ptr, __func__, __FILE__, __LINE__)
    188 #define isc_nmhandle_attach(ptr, ptrp) \
    189 	isc_nmhandle__attach(ptr, ptrp, __func__, __FILE__, __LINE__)
    190 #define isc_nmhandle_detach(ptrp) \
    191 	isc_nmhandle__detach(ptrp, __func__, __FILE__, __LINE__)
    192 ISC_REFCOUNT_TRACE_DECL(isc_nmhandle);
    193 #else
    194 ISC_REFCOUNT_DECL(isc_nmhandle);
    195 #endif
    196 /*%<
    197  * Increment/decrement the reference counter in a netmgr handle.
    198  *
    199  * When the detach function is called on a thread other than the one that
    200  * created the handle, it is scheduled to asynchronously by the handle's
    201  * event loop. When references go to zero, the associated socket will be
    202  * closed and deleted.
    203  */
    204 
    205 int
    206 isc_nmhandle_getfd(isc_nmhandle_t *handle);
    207 
    208 void *
    209 isc_nmhandle_getdata(isc_nmhandle_t *handle);
    210 
    211 bool
    212 isc_nmhandle_is_stream(isc_nmhandle_t *handle);
    213 
    214 void
    215 isc_nmhandle_setdata(isc_nmhandle_t *handle, void *arg,
    216 		     isc_nm_opaquecb_t doreset, isc_nm_opaquecb_t dofree);
    217 /*%<
    218  * isc_nmhandle_t has a void* opaque field (for example, ns_client_t).
    219  * We reuse handle and `opaque` can also be reused between calls.
    220  * This function sets this field and two callbacks:
    221  * - doreset resets the `opaque` to initial state
    222  * - dofree frees everything associated with `opaque`
    223  */
    224 
    225 void
    226 isc_nmhandle_settimeout(isc_nmhandle_t *handle, uint32_t timeout);
    227 void
    228 isc_nmhandle_cleartimeout(isc_nmhandle_t *handle);
    229 /*%<
    230  * Set/clear the read/recv timeout for the socket connected to 'handle'
    231  * to 'timeout' (in milliseconds), and reset the timer.
    232  *
    233  * When this is called on a 'wrapper' socket handle (for example,
    234  * a TCPDNS socket wrapping a TCP connection), the timer is set for
    235  * both socket layers.
    236  */
    237 bool
    238 isc_nmhandle_timer_running(isc_nmhandle_t *handle);
    239 /*%<
    240  * Return true if the timer for the socket connected to 'handle'
    241  * is running.
    242  */
    243 
    244 void
    245 isc_nmhandle_keepalive(isc_nmhandle_t *handle, bool value);
    246 /*%<
    247  * Enable/disable keepalive on this connection by setting it to 'value'.
    248  *
    249  * When keepalive is active, we switch to using the keepalive timeout
    250  * to determine when to close a connection, rather than the idle timeout.
    251  *
    252  * This applies only to TCP-based DNS connections (i.e., TCPDNS or
    253  * TLSDNS). On other types of connection it has no effect.
    254  */
    255 
    256 isc_sockaddr_t
    257 isc_nmhandle_peeraddr(isc_nmhandle_t *handle);
    258 /*%<
    259  * Return the peer address for the given handle.
    260  */
    261 isc_sockaddr_t
    262 isc_nmhandle_localaddr(isc_nmhandle_t *handle);
    263 /*%<
    264  * Return the local address for the given handle.
    265  */
    266 
    267 isc_sockaddr_t
    268 isc_nmhandle_real_peeraddr(isc_nmhandle_t *handle);
    269 /*%<
    270  * Return the real (as seen by the OS) peer address for the given
    271  * handle even when PROXY protocol is used.
    272  *
    273  * NOTE: This function is intended mostly for a) implementing PROXYv2
    274  * access control facilities and b) logging. Using it for anything
    275  * else WILL break PROXYv2 support. Please consider using
    276  * 'isc_nmhandle_peeraddr()' instead.
    277  */
    278 isc_sockaddr_t
    279 isc_nmhandle_real_localaddr(isc_nmhandle_t *handle);
    280 /*%<
    281  * Return the real (as seen by the OS) local address for the given
    282  * handle even when PROXY protocol is used.
    283  *
    284  * NOTE: This function is intended mostly for a) implementing PROXYv2
    285  * access control facilities and b) logging. Using it for anything
    286  * else WILL break PROXYv2 support. Please consider using
    287  * 'isc_nmhandle_localaddr()' instead.
    288  */
    289 
    290 isc_nm_t *
    291 isc_nmhandle_netmgr(isc_nmhandle_t *handle);
    292 /*%<
    293  * Return a pointer to the netmgr object for the given handle.
    294  */
    295 
    296 isc_result_t
    297 isc_nm_listenudp(isc_nm_t *mgr, uint32_t workers, isc_sockaddr_t *iface,
    298 		 isc_nm_recv_cb_t cb, void *cbarg, isc_nmsocket_t **sockp);
    299 /*%<
    300  * Start listening for UDP packets on interface 'iface' using net manager
    301  * 'mgr'.
    302  *
    303  * On success, 'sockp' will be updated to contain a new listening UDP socket.
    304  *
    305  * When a packet is received on the socket, 'cb' will be called with 'cbarg'
    306  * as its argument.
    307  */
    308 
    309 void
    310 isc_nm_udpconnect(isc_nm_t *mgr, isc_sockaddr_t *local, isc_sockaddr_t *peer,
    311 		  isc_nm_cb_t cb, void *cbarg, unsigned int timeout);
    312 /*%<
    313  * Open a UDP socket, bind to 'local' and connect to 'peer', and
    314  * immediately call 'cb' with a handle so that the caller can begin
    315  * sending packets over UDP.
    316  *
    317  * 'timeout' specifies the timeout interval in milliseconds.
    318  *
    319  * The connected socket can only be accessed via the handle passed to
    320  * 'cb'.
    321  */
    322 
    323 isc_result_t
    324 isc_nm_routeconnect(isc_nm_t *mgr, isc_nm_cb_t cb, void *cbarg);
    325 /*%<
    326  * Open a route/netlink socket and call 'cb', so the caller can be
    327  * begin listening for interface changes.  This behaves similarly to
    328  * isc_nm_udpconnect().
    329  *
    330  * Returns ISC_R_NOTIMPLEMENTED on systems where route/netlink sockets
    331  * are not supported.
    332  */
    333 
    334 isc_result_t
    335 isc_nm_listenproxyudp(isc_nm_t *mgr, uint32_t workers, isc_sockaddr_t *iface,
    336 		      isc_nm_recv_cb_t cb, void *cbarg, isc_nmsocket_t **sockp);
    337 /*%<
    338  * The same as `isc_nm_listenudp()`, but PROXYv2 headers are
    339  * expected at the beginning of the received datagrams.
    340  */
    341 
    342 void
    343 isc_nm_proxyudpconnect(isc_nm_t *mgr, isc_sockaddr_t *local,
    344 		       isc_sockaddr_t *peer, isc_nm_cb_t cb, void *cbarg,
    345 		       unsigned int		  timeout,
    346 		       isc_nm_proxyheader_info_t *proxy_info);
    347 /*%<
    348  * The same as `isc_nm_udpconnect()`, but PROXYv2 headers are added
    349  * at the beginning of each sent datagram. The PROXYv2 headers are
    350  * created using the data from the `proxy_info` object. If the
    351  * object is omitted, then LOCAL PROXYv2 headers are used.
    352  */
    353 
    354 void
    355 isc_nm_stoplistening(isc_nmsocket_t *sock);
    356 /*%<
    357  * Stop listening on socket 'sock'.
    358  */
    359 
    360 void
    361 isc_nm_read(isc_nmhandle_t *handle, isc_nm_recv_cb_t cb, void *cbarg);
    362 /*
    363  * Begin (or continue) reading on the socket associated with 'handle', and
    364  * update its recv callback to 'cb', which will be called as soon as there
    365  * is data to process.
    366  */
    367 
    368 void
    369 isc_nm_read_stop(isc_nmhandle_t *handle);
    370 /*%<
    371  * Stop reading on this handle's socket.
    372  *
    373  * Requires:
    374  * \li	'handle' is a valid netmgr handle.
    375  */
    376 
    377 void
    378 isc_nm_cancelread(isc_nmhandle_t *handle);
    379 /*%<
    380  * Cancel reading on a connected socket. Calls the read/recv callback on
    381  * active handles with a result code of ISC_R_CANCELED.
    382  *
    383  * Requires:
    384  * \li	'handle' is a valid netmgr handle
    385  * \li	...for which a read/recv callback has been defined.
    386  */
    387 
    388 void
    389 isc_nmhandle_close(isc_nmhandle_t *handle);
    390 /*%<
    391  * Close the active handle - no further read callbacks will happen.
    392  *
    393  * Requires:
    394  * 'li	'handle' is a valid netmgr handle
    395  */
    396 
    397 void
    398 isc_nm_send(isc_nmhandle_t *handle, isc_region_t *region, isc_nm_cb_t cb,
    399 	    void *cbarg);
    400 /*%<
    401  * Send the data in 'region' via 'handle'. Afterward, the callback 'cb' is
    402  * called with the argument 'cbarg'.
    403  *
    404  * 'region' is not copied; it has to be allocated beforehand and freed
    405  * in 'cb'.
    406  */
    407 
    408 isc_result_t
    409 isc_nm_listentcp(isc_nm_t *mgr, uint32_t workers, isc_sockaddr_t *iface,
    410 		 isc_nm_accept_cb_t accept_cb, void *accept_cbarg, int backlog,
    411 		 isc_quota_t *quota, isc_nmsocket_t **sockp);
    412 /*%<
    413  * Start listening for raw messages over the TCP interface 'iface', using
    414  * net manager 'mgr'.
    415  *
    416  * On success, 'sockp' will be updated to contain a new listening TCP
    417  * socket.
    418  *
    419  * When connection is accepted on the socket, 'accept_cb' will be called with
    420  * 'accept_cbarg' as its argument. The callback is expected to start a read.
    421  *
    422  * If 'quota' is not NULL, then the socket is attached to the specified
    423  * quota. This allows us to enforce TCP client quota limits.
    424  *
    425  */
    426 
    427 void
    428 isc_nm_tcpconnect(isc_nm_t *mgr, isc_sockaddr_t *local, isc_sockaddr_t *peer,
    429 		  isc_nm_cb_t connect_cb, void *connect_cbarg,
    430 		  unsigned int timeout);
    431 /*%<
    432  * Create a socket using netmgr 'mgr', bind it to the address 'local',
    433  * and connect it to the address 'peer'.
    434  *
    435  * When the connection is complete or has timed out, call 'cb' with
    436  * argument 'cbarg'.
    437  *
    438  * 'timeout' specifies the timeout interval in milliseconds.
    439  *
    440  * The connected socket can only be accessed via the handle passed to
    441  * 'cb'.
    442  */
    443 
    444 isc_result_t
    445 isc_nm_listenstreamdns(isc_nm_t *mgr, uint32_t workers, isc_sockaddr_t *iface,
    446 		       isc_nm_recv_cb_t recv_cb, void *recv_cbarg,
    447 		       isc_nm_accept_cb_t accept_cb, void *accept_cbarg,
    448 		       int backlog, isc_quota_t *quota, isc_tlsctx_t *tlsctx,
    449 		       isc_nm_proxy_type_t proxy_type, isc_nmsocket_t **sockp);
    450 /*%<
    451  * Start listening for DNS messages over the TCP interface 'iface', using
    452  * net manager 'mgr'.
    453  *
    454  * On success, 'sockp' will be updated to contain a new listening TCPDNS
    455  * socket. This is a wrapper around a raw TCP socket, which sends and
    456  * receives DNS messages via that socket. It handles message buffering
    457  * and pipelining, and automatically prepends messages with a two-byte
    458  * length field.
    459  *
    460  * When a complete DNS message is received on the socket, 'cb' will be
    461  * called with 'cbarg' as its argument.
    462  *
    463  * When a new connection is accepted, 'accept_cb' will be called with
    464  * 'accept_cbarg' as its argument.
    465  *
    466  * Passing a non-NULL value as 'tlsctx' instructs the underlying code
    467  * to create a DNS over TLS listener.
    468  *
    469  * Passing 'proxy == true' instruct the code that a PROXY header is
    470  * sent before any data after the connection is accepted.
    471  *
    472  * 'quota' is passed to isc_nm_listentcp() when opening the raw TCP socket.
    473  */
    474 
    475 isc_result_t
    476 isc_nm_listenproxystream(isc_nm_t *mgr, uint32_t workers, isc_sockaddr_t *iface,
    477 			 isc_nm_accept_cb_t accept_cb, void *accept_cbarg,
    478 			 int backlog, isc_quota_t *quota, isc_tlsctx_t *tlsctx,
    479 			 isc_nmsocket_t **sockp);
    480 /*%<
    481  * Start listening for data preceded by a PROXYv2 header over the
    482  * TCP or TLS on interface 'iface', using net manager 'mgr'.
    483  *
    484  * On success, 'sockp' will be updated to contain a new listening TCP
    485  * socket.
    486  *
    487  * When connection is accepted on the socket, 'accept_cb' will be called with
    488  * 'accept_cbarg' as its argument. The callback is expected to start a read.
    489  *
    490  * If 'quota' is not NULL, then the socket is attached to the specified
    491  * quota. This allows us to enforce TCP client quota limits.
    492  *
    493  * If 'tlsctx' is not NULL, then listen for TLS connections. In that
    494  * case PROXYv2 headers are expected to be sent encrypted right after
    495  * the TLS handshake.
    496  */
    497 
    498 void
    499 isc_nm_proxystreamconnect(isc_nm_t *mgr, isc_sockaddr_t *local,
    500 			  isc_sockaddr_t *peer, isc_nm_cb_t cb, void *cbarg,
    501 			  unsigned int timeout, isc_tlsctx_t *tlsctx,
    502 			  const char			    *sni_hostname,
    503 			  isc_tlsctx_client_session_cache_t *client_sess_cache,
    504 			  isc_nm_proxyheader_info_t	    *proxy_info);
    505 /*%<
    506  * Create a TCP socket using netmgr 'mgr', bind it to the address
    507  * 'local', and connect it to the address 'peer'. Right after the
    508  * connection has been established, send PROXYv2 header using the
    509  * information provided via the 'proxy_info' to the remote peer. Then
    510  * the connection is considered established.
    511  *
    512  * If 'proxy_info' is omitted, then a LOCAL PROXYv2 header is sent.
    513  *
    514  * When the connection is established or has timed out, call 'cb' with
    515  * argument 'cbarg'.
    516  *
    517  * 'timeout' specifies the timeout interval in milliseconds.
    518  *
    519  * The connected socket can only be accessed via the handle passed to
    520  * 'cb'.
    521  */
    522 
    523 void
    524 isc_nm_proxyheader_info_init(isc_nm_proxyheader_info_t *restrict info,
    525 			     isc_sockaddr_t *restrict src_addr,
    526 			     isc_sockaddr_t *restrict dst_addr,
    527 			     isc_region_t *restrict tlv_data);
    528 /*%<
    529  * Initialize a 'isc_nm_proxyheader_info_t' object with user
    530  * provided addresses and a TLVs blob, that can be omitted (the rest
    531  * of the data is REQUIRE()d).
    532  */
    533 
    534 void
    535 isc_nm_proxyheader_info_init_complete(isc_nm_proxyheader_info_t *restrict info,
    536 				      isc_region_t *restrict header_data);
    537 /*%<
    538  * Initialize a 'isc_nm_proxyheader_info_t' with user provided data
    539  * blob (e.g. a pre-rendered PROXYv2 header for forwarding or
    540  * testing).
    541  */
    542 
    543 void
    544 isc_nm_settimeouts(isc_nm_t *mgr, uint32_t init, uint32_t idle,
    545 		   uint32_t keepalive, uint32_t advertised);
    546 /*%<
    547  * Sets the initial, idle, and keepalive timeout values (in milliseconds) to use
    548  * for TCP connections, and the timeout value to advertise in responses using
    549  * the EDNS TCP Keepalive option (which should ordinarily be the same
    550  * as 'keepalive'), in milliseconds.
    551  *
    552  * Requires:
    553  * \li	'mgr' is a valid netmgr.
    554  */
    555 
    556 void
    557 isc_nm_setnetbuffers(isc_nm_t *mgr, int32_t recv_tcp, int32_t send_tcp,
    558 		     int32_t recv_udp, int32_t send_udp);
    559 /*%<
    560  * If not 0, sets the SO_RCVBUF and SO_SNDBUF socket options for TCP and UDP
    561  * respectively.
    562  *
    563  * Requires:
    564  * \li	'mgr' is a valid netmgr.
    565  */
    566 
    567 bool
    568 isc_nm_getloadbalancesockets(isc_nm_t *mgr);
    569 void
    570 isc_nm_setloadbalancesockets(isc_nm_t *mgr, bool enabled);
    571 /*%<
    572  * Get and set value of load balancing of the sockets.
    573  *
    574  * Requires:
    575  * \li	'mgr' is a valid netmgr.
    576  */
    577 
    578 void
    579 isc_nm_gettimeouts(isc_nm_t *mgr, uint32_t *initial, uint32_t *idle,
    580 		   uint32_t *keepalive, uint32_t *advertised);
    581 /*%<
    582  * Gets the initial, idle, keepalive, or advertised timeout values,
    583  * in milliseconds.
    584  *
    585  * Any integer pointer parameter not set to NULL will be updated to
    586  * contain the corresponding timeout value.
    587  *
    588  * Requires:
    589  * \li	'mgr' is a valid netmgr.
    590  */
    591 
    592 void
    593 isc_nm_maxudp(isc_nm_t *mgr, uint32_t maxudp);
    594 /*%<
    595  * Simulate a broken firewall that blocks UDP messages larger than a given
    596  * size.
    597  */
    598 
    599 void
    600 isc_nm_setstats(isc_nm_t *mgr, isc_stats_t *stats);
    601 /*%<
    602  * Set a socket statistics counter set 'stats' for 'mgr'.
    603  *
    604  * Requires:
    605  *\li	'mgr' is valid and doesn't have stats already set.
    606  *
    607  *\li	stats is a valid set of statistics counters supporting the
    608  *	full range of socket-related stats counter numbers.
    609  */
    610 
    611 isc_result_t
    612 isc_nm_checkaddr(const isc_sockaddr_t *addr, isc_socktype_t type);
    613 /*%<
    614  * Check whether the specified address is available on the local system
    615  * by opening a socket and immediately closing it.
    616  *
    617  * Requires:
    618  *\li	'addr' is not NULL.
    619  */
    620 
    621 void
    622 isc_nm_streamdnsconnect(isc_nm_t *mgr, isc_sockaddr_t *local,
    623 			isc_sockaddr_t *peer, isc_nm_cb_t cb, void *cbarg,
    624 			unsigned int timeout, isc_tlsctx_t *tlsctx,
    625 			const char			  *sni_hostname,
    626 			isc_tlsctx_client_session_cache_t *client_sess_cache,
    627 			isc_nm_proxy_type_t		   proxy_type,
    628 			isc_nm_proxyheader_info_t	  *proxy_info);
    629 /*%<
    630  * Establish a DNS client connection via a TCP or TLS connection, bound to
    631  * the address 'local' and connected to the address 'peer'.
    632  *
    633  * When the connection is complete or has timed out, call 'cb' with
    634  * argument 'cbarg'.
    635  *
    636  * 'timeout' specifies the timeout interval in milliseconds.
    637  *
    638  * The connected socket can only be accessed via the handle passed to
    639  * 'cb'.
    640  */
    641 
    642 /*%<
    643  * Returns 'true' iff 'handle' is associated with a socket of type
    644  * 'isc_nm_tlsdnssocket'.
    645  */
    646 
    647 bool
    648 isc_nm_is_http_handle(isc_nmhandle_t *handle);
    649 /*%<
    650  * Returns 'true' iff 'handle' is associated with a socket of type
    651  * 'isc_nm_httpsocket'.
    652  */
    653 
    654 bool
    655 isc_nm_is_proxy_unspec(isc_nmhandle_t *handle);
    656 /*%<
    657  * Returns 'true' iff 'handle' is associated with a peer who send
    658  * a PROXYv2 header with unsupported address type.
    659  */
    660 
    661 bool
    662 isc_nm_is_proxy_handle(isc_nmhandle_t *handle);
    663 /*%< Returns 'true' iff 'handle' is associated is with a PROXYv2
    664  * connection.
    665  */
    666 
    667 isc_result_t
    668 isc_nm_listentls(isc_nm_t *mgr, uint32_t workers, isc_sockaddr_t *iface,
    669 		 isc_nm_accept_cb_t accept_cb, void *accept_cbarg, int backlog,
    670 		 isc_quota_t *quota, isc_tlsctx_t *sslctx, bool proxy,
    671 		 isc_nmsocket_t **sockp);
    672 
    673 void
    674 isc_nm_tlsconnect(isc_nm_t *mgr, isc_sockaddr_t *local, isc_sockaddr_t *peer,
    675 		  isc_nm_cb_t connect_cb, void *connect_cbarg,
    676 		  isc_tlsctx_t *ctx, const char *sni_hostname,
    677 		  isc_tlsctx_client_session_cache_t *client_sess_cache,
    678 		  unsigned int timeout, bool proxy,
    679 		  isc_nm_proxyheader_info_t *proxy_info);
    680 
    681 #if HAVE_LIBNGHTTP2
    682 
    683 #define ISC_NM_HTTP_DEFAULT_PATH "/dns-query"
    684 
    685 void
    686 isc_nm_httpconnect(isc_nm_t *mgr, isc_sockaddr_t *local, isc_sockaddr_t *peer,
    687 		   const char *uri, bool POST, isc_nm_cb_t cb, void *cbarg,
    688 		   isc_tlsctx_t *ctx, const char *sni_hostname,
    689 		   isc_tlsctx_client_session_cache_t *client_sess_cache,
    690 		   unsigned int timeout, isc_nm_proxy_type_t proxy_type,
    691 		   isc_nm_proxyheader_info_t *proxy_info);
    692 
    693 isc_result_t
    694 isc_nm_listenhttp(isc_nm_t *mgr, uint32_t workers, isc_sockaddr_t *iface,
    695 		  int backlog, isc_quota_t *quota, isc_tlsctx_t *ctx,
    696 		  isc_nm_http_endpoints_t *eps, uint32_t max_concurrent_streams,
    697 		  isc_nm_proxy_type_t proxy_type, isc_nmsocket_t **sockp);
    698 
    699 isc_nm_http_endpoints_t *
    700 isc_nm_http_endpoints_new(isc_mem_t *mctx);
    701 /*%<
    702  * Create a new, empty HTTP endpoints set object.
    703  *
    704  * Requires:
    705  * \li 'mctx' a valid memory context object.
    706  */
    707 
    708 isc_result_t
    709 isc_nm_http_endpoints_add(isc_nm_http_endpoints_t *restrict eps,
    710 			  const char *uri, const isc_nm_recv_cb_t cb,
    711 			  void *cbarg);
    712 /*%< Adds a new endpoint to the given HTTP endpoints set object.
    713  *
    714  * NOTE: adding an endpoint is allowed only if the endpoint object has
    715  * not been passed to isc_nm_listenhttp() yet.
    716  *
    717  * Requires:
    718  * \li 'eps' is a valid pointer to a valid isc_nm_http_endpoints_t
    719  * object;
    720  * \li 'uri' is a valid pointer to a string of length > 0;
    721  * \li 'cb' is a valid pointer to a read callback function.
    722  */
    723 
    724 void
    725 isc_nm_http_endpoints_attach(isc_nm_http_endpoints_t  *source,
    726 			     isc_nm_http_endpoints_t **targetp);
    727 /*%<
    728  * Attaches to an HTTP endpoints set object.
    729  *
    730  * Requires:
    731  * \li 'source' is a non-NULL pointer to a valid
    732  * isc_nm_http_endpoints_t object;
    733  * \li 'target' is a pointer to a pointer, containing NULL.
    734  */
    735 
    736 void
    737 isc_nm_http_endpoints_detach(isc_nm_http_endpoints_t **restrict epsp);
    738 /*%<
    739  * Detaches from an HTTP endpoints set object. When reference count
    740  * reaches 0, the object get deleted.
    741  *
    742  * Requires:
    743  * \li 'epsp' is a pointer to a pointer to a valid
    744  * isc_nm_http_endpoints_t object.
    745  */
    746 
    747 bool
    748 isc_nm_http_path_isvalid(const char *path);
    749 /*%<
    750  * Returns 'true' if 'path' matches the format requirements for
    751  * the path component of a URI as defined in RFC 3986 section 3.3.
    752  */
    753 
    754 void
    755 isc_nm_http_makeuri(const bool https, const isc_sockaddr_t *sa,
    756 		    const char *hostname, const uint16_t http_port,
    757 		    const char *abs_path, char *outbuf,
    758 		    const size_t outbuf_len);
    759 /*%<
    760  * Makes a URI connection string out of na isc_sockaddr_t object 'sa'
    761  * or the specified 'hostname' and 'http_port'.
    762  *
    763  * Requires:
    764  * \li 'abs_path' is a valid absolute HTTP path string;
    765  * \li 'outbuf' is a valid pointer to a buffer which will get the result;
    766  * \li 'outbuf_len' is a size of the result buffer and is greater than zero.
    767  */
    768 
    769 void
    770 isc_nm_http_set_endpoints(isc_nmsocket_t	  *listener,
    771 			  isc_nm_http_endpoints_t *eps);
    772 /*%<
    773  * Asynchronously replace the set of HTTP endpoints (paths) within
    774  * the listener socket object.  The function is intended to be used
    775  * during reconfiguration.
    776  *
    777  * Requires:
    778  * \li	'listener' is a pointer to a valid network manager HTTP listener socket;
    779  * \li	'eps' is a valid pointer to an HTTP endpoints set.
    780  */
    781 
    782 #endif /* HAVE_LIBNGHTTP2 */
    783 
    784 void
    785 isc_nm_bad_request(isc_nmhandle_t *handle);
    786 /*%<
    787  * Perform a transport protocol specific action on the handle in case of a
    788  * bad/malformed incoming DNS message.
    789  *
    790  * NOTE: The function currently is no-op for any protocol except HTTP/2.
    791  *
    792  * Requires:
    793  *  \li 'handle' is a valid netmgr handle object.
    794  */
    795 
    796 isc_result_t
    797 isc_nm_xfr_checkperm(isc_nmhandle_t *handle);
    798 /*%<
    799  * Check if it is permitted to do a zone transfer over the given handle.
    800  *
    801  * Returns:
    802  * \li	#ISC_R_SUCCESS		Success, permission check passed successfully
    803  * \li	#ISC_R_DOTALPNERROR	No permission because of ALPN tag mismatch
    804  * \li	#ISC_R_NOPERM		No permission because of other restrictions
    805  * \li  any other result indicates failure (i.e. no permission)
    806  *
    807  * Requires:
    808  * \li	'handle' is a valid connection handle.
    809  */
    810 
    811 void
    812 isc_nm_set_maxage(isc_nmhandle_t *handle, const uint32_t ttl);
    813 /*%<
    814  * Set the minimal time to live from the server's response Answer
    815  * section as a hint to the underlying transport.
    816  *
    817  * NOTE: The function currently is no-op for any protocol except HTTP/2.
    818  *
    819  * Requires:
    820  *
    821  * \li 'handle' is a valid netmgr handle object associated with an accepted
    822  * connection.
    823  */
    824 
    825 isc_nmsocket_type
    826 isc_nm_socket_type(const isc_nmhandle_t *handle);
    827 /*%<
    828  * Returns the handle's underlying socket type.
    829  *
    830  * Requires:
    831  *  \li 'handle' is a valid netmgr handle object.
    832  */
    833 
    834 bool
    835 isc_nm_has_encryption(const isc_nmhandle_t *handle);
    836 /*%<
    837  * Returns 'true' iff the handle's underlying transport does encryption.
    838  *
    839  * Requires:
    840  *  \li 'handle' is a valid netmgr handle object.
    841  */
    842 
    843 const char *
    844 isc_nm_verify_tls_peer_result_string(const isc_nmhandle_t *handle);
    845 /*%<
    846  * Returns user-readable message describing TLS peer's certificate
    847  * validation result. Returns 'NULL' for the transport handles for
    848  * which peer verification was not performed.
    849  *
    850  * Requires:
    851  *  \li 'handle' is a valid netmgr handle object.
    852  */
    853 
    854 void
    855 isc__nm_force_tid(int tid);
    856 /*%<
    857  * Force the thread ID to 'tid'. This is STRICTLY for use in unit
    858  * tests and should not be used in any production code.
    859  */
    860 
    861 void
    862 isc_nmhandle_setwritetimeout(isc_nmhandle_t *handle, uint64_t write_timeout);
    863 
    864 /*
    865  * Timer related functions
    866  */
    867 
    868 typedef struct isc_nm_timer isc_nm_timer_t;
    869 
    870 typedef void (*isc_nm_timer_cb)(void *, isc_result_t);
    871 
    872 void
    873 isc_nm_timer_create(isc_nmhandle_t *, isc_nm_timer_cb, void *,
    874 		    isc_nm_timer_t **);
    875 
    876 void
    877 isc_nm_timer_attach(isc_nm_timer_t *, isc_nm_timer_t **);
    878 
    879 void
    880 isc_nm_timer_detach(isc_nm_timer_t **);
    881 
    882 void
    883 isc_nm_timer_start(isc_nm_timer_t *, uint64_t);
    884 
    885 void
    886 isc_nm_timer_stop(isc_nm_timer_t *);
    887 
    888 isc_result_t
    889 isc_nmhandle_set_tcp_nodelay(isc_nmhandle_t *handle, const bool value);
    890 /*%<
    891  * Disables/Enables Nagle's algorithm on a TCP socket for a
    892  * transport backed by TCP (sets TCP_NODELAY if 'value' equals 'true'
    893  * or vice versa).
    894  *
    895  * Requires:
    896  *
    897  * \li 'handle' is a valid netmgr handle object.
    898  */
    899 
    900 isc_sockaddr_t
    901 isc_nmsocket_getaddr(isc_nmsocket_t *sock);
    902 /*%<
    903  * Return the local address of 'sock'.
    904  */
    905 
    906 void
    907 isc_netmgr_portrange(isc_nm_t *netmgr, sa_family_t af, in_port_t low,
    908 		     in_port_t high);
    909 /*%<
    910  * Set the ephemeral port range <low, high> for 'af' family.
    911  */
    912