Home | History | Annotate | Line # | Download | only in netmgr
      1 /*	$NetBSD: streamdns.c,v 1.5 2026/09/17 18:01:17 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 #include <limits.h>
     17 #include <unistd.h>
     18 
     19 #include <isc/async.h>
     20 #include <isc/atomic.h>
     21 #include <isc/log.h>
     22 #include <isc/result.h>
     23 #include <isc/thread.h>
     24 
     25 #include "netmgr-int.h"
     26 
     27 /*
     28  * Stream DNS is a unified transport capable of serving both DNS over
     29  * TCP and DNS over TLS.  It is built on top of
     30  * 'isc_dnsstream_assembler_t' which is used for assembling DNS
     31  * messages in the format used for DNS over TCP out of incoming data.
     32  * It is built on top of 'isc_buffer_t' optimised for small (>= 512
     33  * bytes) DNS messages. For small messages it uses a small static
     34  * memory buffer, but it can automatically switch to a larger
     35  * dynamically allocated memory buffer for larger ones. This way we
     36  * avoid unnecessary memory allocation requests in most cases, as most
     37  * DNS messages are small.
     38  *
     39  * The use of 'isc_dnsstream_assembler_t' allows decoupling DNS
     40  * message assembling code from networking code itself, making it
     41  * easier to test.
     42  *
     43  * To understand how the part responsible for reading of data works,
     44  * start by looking at 'streamdns_on_dnsmessage_data_cb()' (the DNS
     45  * message data processing callback) and
     46  * 'streamdns_handle_incoming_data()' which passes incoming data to
     47  * the 'isc_dnsstream_assembler_t' object within the socket.
     48  *
     49  * The writing is done in a simpler manner due to the fact that we
     50  * have full control over the data. For each write request we attempt
     51  * to allocate a 'streamdns_send_req_t' structure, whose main purpose
     52  * is to keep the data required for the send request processing.
     53  *
     54  * When processing write requests there is an important optimisation:
     55  * we attempt to reuse 'streamdns_send_req_t' objects again, in order
     56  * to avoid memory allocations when requesting memory for the new
     57  * 'streamdns_send_req_t' object.
     58  *
     59  * To understand how sending is done, start by looking at
     60  * 'isc__nm_streamdns_send()'. Additionally also take a look at
     61  * 'streamdns_get_send_req()' and 'streamdns_put_send_req()' which are
     62  * responsible for send requests allocation/reuse and initialisation.
     63  *
     64  * The rest of the code is mostly wrapping code to expose the
     65  * functionality of the underlying transport, which at the moment
     66  * could be either TCP or TLS.
     67  */
     68 
     69 typedef struct streamdns_send_req {
     70 	isc_nm_cb_t cb;		   /* send callback */
     71 	void *cbarg;		   /* send callback argument */
     72 	isc_nmhandle_t *dnshandle; /* Stream DNS socket handle */
     73 } streamdns_send_req_t;
     74 
     75 static streamdns_send_req_t *
     76 streamdns_get_send_req(isc_nmsocket_t *sock, isc_mem_t *mctx,
     77 		       isc__nm_uvreq_t *req);
     78 
     79 static void
     80 streamdns_put_send_req(isc_mem_t *mctx, streamdns_send_req_t *send_req,
     81 		       const bool force_destroy);
     82 
     83 static void
     84 streamdns_readcb(isc_nmhandle_t *handle, isc_result_t result,
     85 		 isc_region_t *region, void *cbarg);
     86 
     87 static void
     88 streamdns_failed_read_cb(isc_nmsocket_t *sock, const isc_result_t result,
     89 			 const bool async);
     90 
     91 static void
     92 streamdns_try_close_unused(isc_nmsocket_t *sock);
     93 
     94 static bool
     95 streamdns_closing(isc_nmsocket_t *sock);
     96 
     97 static void
     98 streamdns_resume_processing(void *arg);
     99 static void
    100 async_streamdns_resume_processing(void *arg);
    101 
    102 static void
    103 streamdns_resumeread(isc_nmsocket_t *sock, isc_nmhandle_t *transphandle) {
    104 	if (!sock->streamdns.reading) {
    105 		sock->streamdns.reading = true;
    106 		isc_nm_read(transphandle, streamdns_readcb, (void *)sock);
    107 	}
    108 }
    109 
    110 static void
    111 streamdns_readmore(isc_nmsocket_t *sock, isc_nmhandle_t *transphandle) {
    112 	streamdns_resumeread(sock, transphandle);
    113 
    114 	/* Restart the timer only if there's a last single active handle */
    115 	isc_nmhandle_t *handle = ISC_LIST_HEAD(sock->active_handles);
    116 	INSIST(handle != NULL);
    117 	if (ISC_LIST_NEXT(handle, active_link) == NULL) {
    118 		isc__nmsocket_timer_start(sock);
    119 	}
    120 }
    121 
    122 static void
    123 streamdns_pauseread(isc_nmsocket_t *sock, isc_nmhandle_t *transphandle) {
    124 	if (sock->streamdns.reading) {
    125 		sock->streamdns.reading = false;
    126 		isc_nm_read_stop(transphandle);
    127 	}
    128 }
    129 
    130 static bool
    131 streamdns_on_complete_dnsmessage(isc_dnsstream_assembler_t *dnsasm,
    132 				 isc_region_t *restrict region,
    133 				 isc_nmsocket_t *sock,
    134 				 isc_nmhandle_t *transphandle) {
    135 	const bool last_datum = isc_dnsstream_assembler_remaininglength(
    136 					dnsasm) == region->length;
    137 	/*
    138 	 * Stop after one message if a client connection.
    139 	 */
    140 	bool stop = sock->client;
    141 
    142 	sock->reading = false;
    143 	if (sock->recv_cb != NULL) {
    144 		if (!sock->client) {
    145 			/*
    146 			 * We must allocate a new handle object, as we
    147 			 * need to ensure that after processing of this
    148 			 * message has been completed and the handle
    149 			 * gets destroyed, 'nsock->closehandle_cb'
    150 			 * (streamdns_resume_processing()) is invoked.
    151 			 * That is required for pipelining support.
    152 			 */
    153 			isc_nmhandle_t *handle = isc__nmhandle_get(
    154 				sock, &sock->peer, &sock->iface);
    155 			sock->recv_cb(handle, ISC_R_SUCCESS, region,
    156 				      sock->recv_cbarg);
    157 			isc_nmhandle_detach(&handle);
    158 		} else {
    159 			/*
    160 			 * As on the client side we are supposed to stop
    161 			 * reading/processing after receiving one
    162 			 * message, we can use the 'sock->recv_handle'
    163 			 * from which we would need to detach before
    164 			 * calling the read callback anyway.
    165 			 */
    166 			isc_nmhandle_t *recv_handle = sock->recv_handle;
    167 			sock->recv_handle = NULL;
    168 			sock->recv_cb(recv_handle, ISC_R_SUCCESS, region,
    169 				      sock->recv_cbarg);
    170 			isc_nmhandle_detach(&recv_handle);
    171 		}
    172 
    173 		if (streamdns_closing(sock)) {
    174 			stop = true;
    175 		}
    176 	} else {
    177 		stop = true;
    178 	}
    179 
    180 	if (sock->active_handles_max != 0 &&
    181 	    (sock->active_handles_cur >= sock->active_handles_max))
    182 	{
    183 		stop = true;
    184 	}
    185 	INSIST(sock->active_handles_cur <= sock->active_handles_max);
    186 
    187 	isc__nmsocket_timer_stop(sock);
    188 	if (stop) {
    189 		streamdns_pauseread(sock, transphandle);
    190 	} else if (last_datum) {
    191 		/*
    192 		 * We have processed all data, need to read more.
    193 		 * The call also restarts the timer.
    194 		 */
    195 		streamdns_readmore(sock, transphandle);
    196 	} else {
    197 		/*
    198 		 * Process more DNS messages in the next loop tick.
    199 		 */
    200 		streamdns_pauseread(sock, transphandle);
    201 		isc__nmsocket_attach(sock, &(isc_nmsocket_t *){ NULL });
    202 		isc_async_run(sock->worker->loop,
    203 			      async_streamdns_resume_processing, sock);
    204 	}
    205 
    206 	return false;
    207 }
    208 
    209 /*
    210  * This function, alongside 'streamdns_handle_incoming_data()',
    211  * connects networking code to the 'isc_dnsstream_assembler_t'. It is
    212  * responsible for making decisions regarding reading from the
    213  * underlying transport socket as well as controlling the read timer.
    214  */
    215 static bool
    216 streamdns_on_dnsmessage_data_cb(isc_dnsstream_assembler_t *dnsasm,
    217 				const isc_result_t result,
    218 				isc_region_t *restrict region, void *cbarg,
    219 				void *userarg) {
    220 	isc_nmsocket_t *sock = (isc_nmsocket_t *)cbarg;
    221 	isc_nmhandle_t *transphandle = (isc_nmhandle_t *)userarg;
    222 
    223 	switch (result) {
    224 	case ISC_R_SUCCESS:
    225 		/*
    226 		 * A complete DNS message has been assembled from the incoming
    227 		 * data. Let's process it.
    228 		 */
    229 		return streamdns_on_complete_dnsmessage(dnsasm, region, sock,
    230 							transphandle);
    231 	case ISC_R_RANGE:
    232 		/*
    233 		 * It seems that someone attempts to send us some binary junk
    234 		 * over the socket, as the beginning of the next message tells
    235 		 * us the there is an empty (0-sized) DNS message to receive.
    236 		 * We should treat it as a hard error.
    237 		 */
    238 		streamdns_failed_read_cb(sock, result, false);
    239 		return false;
    240 	case ISC_R_NOMORE:
    241 		/*
    242 		 * We do not have enough data to process the next message and
    243 		 * thus we need to resume reading from the socket.
    244 		 */
    245 		if (sock->recv_handle != NULL) {
    246 			streamdns_readmore(sock, transphandle);
    247 		}
    248 		return false;
    249 	default:
    250 		UNREACHABLE();
    251 	};
    252 }
    253 
    254 static void
    255 streamdns_handle_incoming_data(isc_nmsocket_t *sock,
    256 			       isc_nmhandle_t *transphandle,
    257 			       void *restrict data, size_t len) {
    258 	isc_dnsstream_assembler_t *dnsasm = sock->streamdns.input;
    259 
    260 	/*
    261 	 * Try to process the received data or, when 'data == NULL' and
    262 	 * 'len == 0', try to resume processing of the data within the
    263 	 * internal buffers or resume reading, if there is no any.
    264 	 */
    265 	isc_dnsstream_assembler_incoming(dnsasm, transphandle, data, len);
    266 	streamdns_try_close_unused(sock);
    267 }
    268 
    269 static isc_nmsocket_t *
    270 streamdns_sock_new(isc__networker_t *worker, const isc_nmsocket_type_t type,
    271 		   isc_sockaddr_t *addr, const bool is_server) {
    272 	isc_nmsocket_t *sock;
    273 	INSIST(type == isc_nm_streamdnssocket ||
    274 	       type == isc_nm_streamdnslistener);
    275 
    276 	sock = isc_mempool_get(worker->nmsocket_pool);
    277 	isc__nmsocket_init(sock, worker, type, addr, NULL);
    278 	sock->result = ISC_R_UNSET;
    279 	if (type == isc_nm_streamdnssocket) {
    280 		uint32_t initial = 0;
    281 		isc_nm_gettimeouts(worker->netmgr, &initial, NULL, NULL, NULL);
    282 		sock->read_timeout = initial;
    283 		sock->client = !is_server;
    284 		sock->connecting = !is_server;
    285 		sock->streamdns.input = isc_dnsstream_assembler_new(
    286 			sock->worker->mctx, streamdns_on_dnsmessage_data_cb,
    287 			sock);
    288 	}
    289 
    290 	return sock;
    291 }
    292 
    293 static void
    294 streamdns_call_connect_cb(isc_nmsocket_t *sock, isc_nmhandle_t *handle,
    295 			  const isc_result_t result) {
    296 	sock->connecting = false;
    297 	INSIST(sock->connect_cb != NULL);
    298 	sock->connect_cb(handle, result, sock->connect_cbarg);
    299 	if (result != ISC_R_SUCCESS) {
    300 		isc__nmsocket_clearcb(handle->sock);
    301 	} else {
    302 		sock->connected = true;
    303 	}
    304 	streamdns_try_close_unused(sock);
    305 }
    306 
    307 static void
    308 streamdns_save_alpn_status(isc_nmsocket_t *dnssock,
    309 			   isc_nmhandle_t *transp_handle) {
    310 	const unsigned char *alpn = NULL;
    311 	unsigned int alpnlen = 0;
    312 
    313 	isc__nmhandle_get_selected_alpn(transp_handle, &alpn, &alpnlen);
    314 	if (alpn != NULL && alpnlen == ISC_TLS_DOT_PROTO_ALPN_ID_LEN &&
    315 	    memcmp(ISC_TLS_DOT_PROTO_ALPN_ID, alpn,
    316 		   ISC_TLS_DOT_PROTO_ALPN_ID_LEN) == 0)
    317 	{
    318 		dnssock->streamdns.dot_alpn_negotiated = true;
    319 	}
    320 }
    321 
    322 static void
    323 streamdns_transport_connected(isc_nmhandle_t *handle, isc_result_t result,
    324 			      void *cbarg) {
    325 	isc_nmsocket_t *sock = (isc_nmsocket_t *)cbarg;
    326 	isc_nmhandle_t *streamhandle = NULL;
    327 
    328 	REQUIRE(VALID_NMSOCK(sock));
    329 
    330 	sock->tid = isc_tid();
    331 	if (result == ISC_R_EOF) {
    332 		/*
    333 		 * The transport layer (probably TLS) has returned EOF during
    334 		 * connection establishment. That means that connection has
    335 		 * been "cancelled" (for compatibility with old transport
    336 		 * behaviour).
    337 		 */
    338 		result = ISC_R_CANCELED;
    339 		goto error;
    340 	} else if (result == ISC_R_TLSERROR) {
    341 		/*
    342 		 * In some of the cases when the old code would return
    343 		 * ISC_R_CANCELLED, the new code could return generic
    344 		 * ISC_R_TLSERROR code. However, the old code does not expect
    345 		 * that.
    346 		 */
    347 		result = ISC_R_CANCELED;
    348 		goto error;
    349 	} else if (result != ISC_R_SUCCESS) {
    350 		goto error;
    351 	}
    352 
    353 	INSIST(VALID_NMHANDLE(handle));
    354 
    355 	sock->iface = isc_nmhandle_localaddr(handle);
    356 	sock->peer = isc_nmhandle_peeraddr(handle);
    357 	if (isc__nmsocket_closing(handle->sock)) {
    358 		result = ISC_R_SHUTTINGDOWN;
    359 		goto error;
    360 	}
    361 
    362 	isc_nmhandle_attach(handle, &sock->outerhandle);
    363 	sock->active = true;
    364 
    365 	handle->sock->streamdns.sock = sock;
    366 
    367 	streamdns_save_alpn_status(sock, handle);
    368 	isc__nmhandle_set_manual_timer(sock->outerhandle, true);
    369 	streamhandle = isc__nmhandle_get(sock, &sock->peer, &sock->iface);
    370 	(void)isc_nmhandle_set_tcp_nodelay(sock->outerhandle, true);
    371 	streamdns_call_connect_cb(sock, streamhandle, result);
    372 	isc_nmhandle_detach(&streamhandle);
    373 
    374 	return;
    375 error:
    376 	if (handle != NULL) {
    377 		/*
    378 		 * Let's save the error description (if any) so that
    379 		 * e.g. 'dig' could produce a usable error message.
    380 		 */
    381 		INSIST(VALID_NMHANDLE(handle));
    382 		sock->streamdns.tls_verify_error =
    383 			isc_nm_verify_tls_peer_result_string(handle);
    384 	}
    385 	streamhandle = isc__nmhandle_get(sock, NULL, NULL);
    386 	sock->closed = true;
    387 	streamdns_call_connect_cb(sock, streamhandle, result);
    388 	isc_nmhandle_detach(&streamhandle);
    389 	isc__nmsocket_detach(&sock);
    390 }
    391 
    392 void
    393 isc_nm_streamdnsconnect(isc_nm_t *mgr, isc_sockaddr_t *local,
    394 			isc_sockaddr_t *peer, isc_nm_cb_t cb, void *cbarg,
    395 			unsigned int timeout, isc_tlsctx_t *tlsctx,
    396 			const char *sni_hostname,
    397 			isc_tlsctx_client_session_cache_t *client_sess_cache,
    398 			isc_nm_proxy_type_t proxy_type,
    399 			isc_nm_proxyheader_info_t *proxy_info) {
    400 	isc_nmsocket_t *nsock = NULL;
    401 	isc__networker_t *worker = NULL;
    402 
    403 	REQUIRE(VALID_NM(mgr));
    404 
    405 	worker = &mgr->workers[isc_tid()];
    406 
    407 	if (isc__nm_closing(worker)) {
    408 		cb(NULL, ISC_R_SHUTTINGDOWN, cbarg);
    409 		return;
    410 	}
    411 
    412 	nsock = streamdns_sock_new(worker, isc_nm_streamdnssocket, local,
    413 				   false);
    414 	nsock->connect_cb = cb;
    415 	nsock->connect_cbarg = cbarg;
    416 	nsock->connect_timeout = timeout;
    417 
    418 	switch (proxy_type) {
    419 	case ISC_NM_PROXY_NONE:
    420 		if (tlsctx == NULL) {
    421 			INSIST(client_sess_cache == NULL);
    422 			isc_nm_tcpconnect(mgr, local, peer,
    423 					  streamdns_transport_connected, nsock,
    424 					  nsock->connect_timeout);
    425 		} else {
    426 			isc_nm_tlsconnect(
    427 				mgr, local, peer, streamdns_transport_connected,
    428 				nsock, tlsctx, sni_hostname, client_sess_cache,
    429 				nsock->connect_timeout, false, proxy_info);
    430 		}
    431 		break;
    432 	case ISC_NM_PROXY_PLAIN:
    433 		if (tlsctx == NULL) {
    434 			isc_nm_proxystreamconnect(mgr, local, peer,
    435 						  streamdns_transport_connected,
    436 						  nsock, nsock->connect_timeout,
    437 						  NULL, NULL, NULL, proxy_info);
    438 		} else {
    439 			isc_nm_tlsconnect(
    440 				mgr, local, peer, streamdns_transport_connected,
    441 				nsock, tlsctx, sni_hostname, client_sess_cache,
    442 				nsock->connect_timeout, true, proxy_info);
    443 		}
    444 		break;
    445 	case ISC_NM_PROXY_ENCRYPTED:
    446 		INSIST(tlsctx != NULL);
    447 		isc_nm_proxystreamconnect(
    448 			mgr, local, peer, streamdns_transport_connected, nsock,
    449 			nsock->connect_timeout, tlsctx, sni_hostname,
    450 			client_sess_cache, proxy_info);
    451 		break;
    452 	default:
    453 		UNREACHABLE();
    454 	}
    455 }
    456 
    457 bool
    458 isc__nmsocket_streamdns_timer_running(isc_nmsocket_t *sock) {
    459 	isc_nmsocket_t *transp_sock;
    460 
    461 	REQUIRE(VALID_NMSOCK(sock));
    462 	REQUIRE(sock->type == isc_nm_streamdnssocket);
    463 
    464 	if (sock->outerhandle == NULL) {
    465 		return false;
    466 	}
    467 
    468 	INSIST(VALID_NMHANDLE(sock->outerhandle));
    469 	transp_sock = sock->outerhandle->sock;
    470 	INSIST(VALID_NMSOCK(transp_sock));
    471 
    472 	return isc__nmsocket_timer_running(transp_sock);
    473 }
    474 
    475 void
    476 isc__nmsocket_streamdns_timer_stop(isc_nmsocket_t *sock) {
    477 	isc_nmsocket_t *transp_sock;
    478 
    479 	REQUIRE(VALID_NMSOCK(sock));
    480 	REQUIRE(sock->type == isc_nm_streamdnssocket);
    481 
    482 	if (sock->outerhandle == NULL) {
    483 		return;
    484 	}
    485 
    486 	INSIST(VALID_NMHANDLE(sock->outerhandle));
    487 	transp_sock = sock->outerhandle->sock;
    488 	INSIST(VALID_NMSOCK(transp_sock));
    489 
    490 	isc__nmsocket_timer_stop(transp_sock);
    491 }
    492 
    493 void
    494 isc__nmsocket_streamdns_timer_restart(isc_nmsocket_t *sock) {
    495 	isc_nmsocket_t *transp_sock;
    496 
    497 	REQUIRE(VALID_NMSOCK(sock));
    498 	REQUIRE(sock->type == isc_nm_streamdnssocket);
    499 
    500 	if (sock->outerhandle == NULL) {
    501 		return;
    502 	}
    503 
    504 	INSIST(VALID_NMHANDLE(sock->outerhandle));
    505 	transp_sock = sock->outerhandle->sock;
    506 	INSIST(VALID_NMSOCK(transp_sock));
    507 
    508 	isc__nmsocket_timer_restart(transp_sock);
    509 }
    510 
    511 static void
    512 streamdns_failed_read_cb(isc_nmsocket_t *sock, const isc_result_t result,
    513 			 const bool async) {
    514 	REQUIRE(VALID_NMSOCK(sock));
    515 	REQUIRE(result != ISC_R_SUCCESS);
    516 
    517 	/* Nobody is reading from the socket yet */
    518 	if (sock->recv_handle == NULL) {
    519 		goto destroy;
    520 	}
    521 
    522 	if (sock->client && result == ISC_R_TIMEDOUT) {
    523 		if (sock->recv_cb != NULL) {
    524 			isc__nm_uvreq_t *req = isc__nm_get_read_req(sock, NULL);
    525 			isc__nm_readcb(sock, req, ISC_R_TIMEDOUT, false);
    526 		}
    527 
    528 		if (isc__nmsocket_timer_running(sock)) {
    529 			/* Timer was restarted, bail-out */
    530 			return;
    531 		}
    532 
    533 		isc__nmsocket_clearcb(sock);
    534 
    535 		goto destroy;
    536 	}
    537 
    538 	isc_dnsstream_assembler_clear(sock->streamdns.input);
    539 
    540 	/* Nobody expects the callback if isc_nm_read() wasn't called */
    541 	if (!sock->client || sock->reading) {
    542 		sock->reading = false;
    543 
    544 		if (sock->recv_cb != NULL) {
    545 			isc__nm_uvreq_t *req = isc__nm_get_read_req(sock, NULL);
    546 			isc__nmsocket_clearcb(sock);
    547 			isc__nm_readcb(sock, req, result, async);
    548 		}
    549 	}
    550 
    551 destroy:
    552 	isc__nmsocket_prep_destroy(sock);
    553 }
    554 
    555 void
    556 isc__nm_streamdns_failed_read_cb(isc_nmsocket_t *sock, isc_result_t result,
    557 				 const bool async) {
    558 	REQUIRE(result != ISC_R_SUCCESS);
    559 	REQUIRE(sock->type == isc_nm_streamdnssocket);
    560 	sock->streamdns.reading = false;
    561 	streamdns_failed_read_cb(sock, result, async);
    562 }
    563 
    564 static void
    565 streamdns_readcb(isc_nmhandle_t *handle, isc_result_t result,
    566 		 isc_region_t *region, void *cbarg) {
    567 	isc_nmsocket_t *sock = (isc_nmsocket_t *)cbarg;
    568 
    569 	REQUIRE(VALID_NMHANDLE(handle));
    570 	REQUIRE(VALID_NMSOCK(sock));
    571 	REQUIRE(sock->tid == isc_tid());
    572 
    573 	if (result != ISC_R_SUCCESS) {
    574 		streamdns_failed_read_cb(sock, result, false);
    575 		return;
    576 	} else if (streamdns_closing(sock)) {
    577 		streamdns_failed_read_cb(sock, ISC_R_CANCELED, false);
    578 		return;
    579 	}
    580 
    581 	streamdns_handle_incoming_data(sock, handle, region->base,
    582 				       region->length);
    583 }
    584 
    585 static void
    586 streamdns_try_close_unused(isc_nmsocket_t *sock) {
    587 	if (sock->recv_handle == NULL && sock->streamdns.nsending == 0) {
    588 		/*
    589 		 * The socket is unused after calling the callback. Let's close
    590 		 * the underlying connection.
    591 		 */
    592 		/* FIXME: call failed_read_cb(?) */
    593 		if (sock->outerhandle != NULL) {
    594 			isc_nmhandle_detach(&sock->outerhandle);
    595 		}
    596 		isc__nmsocket_prep_destroy(sock);
    597 	}
    598 }
    599 
    600 static streamdns_send_req_t *
    601 streamdns_get_send_req(isc_nmsocket_t *sock, isc_mem_t *mctx,
    602 		       isc__nm_uvreq_t *req) {
    603 	streamdns_send_req_t *send_req;
    604 
    605 	if (sock->streamdns.send_req != NULL) {
    606 		/*
    607 		 * We have a previously allocated object - let's use that.
    608 		 * That should help reducing stress on the memory allocator.
    609 		 */
    610 		send_req = (streamdns_send_req_t *)sock->streamdns.send_req;
    611 		sock->streamdns.send_req = NULL;
    612 	} else {
    613 		/* Allocate a new object. */
    614 		send_req = isc_mem_get(mctx, sizeof(*send_req));
    615 		*send_req = (streamdns_send_req_t){ 0 };
    616 	}
    617 
    618 	/* Initialise the send request object */
    619 	send_req->cb = req->cb.send;
    620 	send_req->cbarg = req->cbarg;
    621 	isc_nmhandle_attach(req->handle, &send_req->dnshandle);
    622 
    623 	sock->streamdns.nsending++;
    624 
    625 	return send_req;
    626 }
    627 
    628 static void
    629 streamdns_put_send_req(isc_mem_t *mctx, streamdns_send_req_t *send_req,
    630 		       const bool force_destroy) {
    631 	/*
    632 	 * Attempt to put the object for reuse later if we are not
    633 	 * wrapping up.
    634 	 */
    635 	if (!force_destroy) {
    636 		isc_nmsocket_t *sock = send_req->dnshandle->sock;
    637 		sock->streamdns.nsending--;
    638 		isc_nmhandle_detach(&send_req->dnshandle);
    639 		if (sock->streamdns.send_req == NULL) {
    640 			sock->streamdns.send_req = send_req;
    641 			/*
    642 			 * An object has been recycled,
    643 			 * if not - we are going to destroy it.
    644 			 */
    645 			return;
    646 		}
    647 	}
    648 
    649 	isc_mem_put(mctx, send_req, sizeof(*send_req));
    650 }
    651 
    652 static void
    653 streamdns_writecb(isc_nmhandle_t *handle, isc_result_t result, void *cbarg) {
    654 	streamdns_send_req_t *send_req = (streamdns_send_req_t *)cbarg;
    655 	isc_mem_t *mctx;
    656 	isc_nm_cb_t cb;
    657 	void *send_cbarg;
    658 	isc_nmhandle_t *dnshandle = NULL;
    659 
    660 	REQUIRE(VALID_NMHANDLE(handle));
    661 	REQUIRE(VALID_NMHANDLE(send_req->dnshandle));
    662 	REQUIRE(VALID_NMSOCK(send_req->dnshandle->sock));
    663 	REQUIRE(send_req->dnshandle->sock->tid == isc_tid());
    664 
    665 	mctx = send_req->dnshandle->sock->worker->mctx;
    666 	cb = send_req->cb;
    667 	send_cbarg = send_req->cbarg;
    668 
    669 	isc_nmhandle_attach(send_req->dnshandle, &dnshandle);
    670 	/* try to keep the send request object for reuse */
    671 	streamdns_put_send_req(mctx, send_req, false);
    672 	cb(dnshandle, result, send_cbarg);
    673 	streamdns_try_close_unused(dnshandle->sock);
    674 	isc_nmhandle_detach(&dnshandle);
    675 }
    676 
    677 static bool
    678 streamdns_closing(isc_nmsocket_t *sock) {
    679 	return isc__nmsocket_closing(sock) || isc__nm_closing(sock->worker) ||
    680 	       sock->outerhandle == NULL ||
    681 	       (sock->outerhandle != NULL &&
    682 		isc__nmsocket_closing(sock->outerhandle->sock));
    683 }
    684 
    685 static void
    686 streamdns_resume_processing(void *arg) {
    687 	isc_nmsocket_t *sock = (isc_nmsocket_t *)arg;
    688 
    689 	REQUIRE(VALID_NMSOCK(sock));
    690 	REQUIRE(sock->tid == isc_tid());
    691 	REQUIRE(!sock->client);
    692 
    693 	if (streamdns_closing(sock)) {
    694 		return;
    695 	}
    696 
    697 	if (sock->active_handles_max != 0 &&
    698 	    (sock->active_handles_cur >= sock->active_handles_max))
    699 	{
    700 		return;
    701 	}
    702 
    703 	streamdns_handle_incoming_data(sock, sock->outerhandle, NULL, 0);
    704 }
    705 
    706 static void
    707 async_streamdns_resume_processing(void *arg) {
    708 	isc_nmsocket_t *sock = (isc_nmsocket_t *)arg;
    709 
    710 	streamdns_resume_processing(sock);
    711 
    712 	isc__nmsocket_detach(&sock);
    713 }
    714 
    715 static isc_result_t
    716 streamdns_accept_cb(isc_nmhandle_t *handle, isc_result_t result, void *cbarg) {
    717 	isc_nmsocket_t *listensock = (isc_nmsocket_t *)cbarg;
    718 	isc_nmsocket_t *nsock;
    719 	isc_sockaddr_t iface;
    720 	int tid = isc_tid();
    721 	uint32_t initial = 0;
    722 
    723 	REQUIRE(VALID_NMHANDLE(handle));
    724 	REQUIRE(VALID_NMSOCK(handle->sock));
    725 
    726 	if (isc__nm_closing(handle->sock->worker)) {
    727 		return ISC_R_SHUTTINGDOWN;
    728 	} else if (result != ISC_R_SUCCESS) {
    729 		return result;
    730 	}
    731 
    732 	REQUIRE(VALID_NMSOCK(listensock));
    733 	REQUIRE(listensock->type == isc_nm_streamdnslistener);
    734 
    735 	iface = isc_nmhandle_localaddr(handle);
    736 	nsock = streamdns_sock_new(handle->sock->worker, isc_nm_streamdnssocket,
    737 				   &iface, true);
    738 	nsock->recv_cb = listensock->recv_cb;
    739 	nsock->recv_cbarg = listensock->recv_cbarg;
    740 
    741 	nsock->peer = isc_nmhandle_peeraddr(handle);
    742 	nsock->tid = tid;
    743 	isc_nm_gettimeouts(handle->sock->worker->netmgr, &initial, NULL, NULL,
    744 			   NULL);
    745 	nsock->read_timeout = initial;
    746 	nsock->accepting = true;
    747 	nsock->active = true;
    748 
    749 	isc__nmsocket_attach(handle->sock, &nsock->listener);
    750 	isc_nmhandle_attach(handle, &nsock->outerhandle);
    751 	handle->sock->streamdns.sock = nsock;
    752 
    753 	streamdns_save_alpn_status(nsock, handle);
    754 
    755 	nsock->recv_handle = isc__nmhandle_get(nsock, NULL, &iface);
    756 	INSIST(listensock->accept_cb != NULL);
    757 	result = listensock->accept_cb(nsock->recv_handle, result,
    758 				       listensock->accept_cbarg);
    759 	if (result != ISC_R_SUCCESS) {
    760 		isc_nmhandle_detach(&nsock->recv_handle);
    761 		isc__nmsocket_detach(&nsock->listener);
    762 		isc_nmhandle_detach(&nsock->outerhandle);
    763 		nsock->closed = true;
    764 		goto exit;
    765 	}
    766 
    767 	nsock->closehandle_cb = streamdns_resume_processing;
    768 	isc__nmhandle_set_manual_timer(nsock->outerhandle, true);
    769 	isc_nm_gettimeouts(nsock->worker->netmgr, &initial, NULL, NULL, NULL);
    770 	/* settimeout restarts the timer */
    771 	isc_nmhandle_settimeout(nsock->outerhandle, initial);
    772 	(void)isc_nmhandle_set_tcp_nodelay(nsock->outerhandle, true);
    773 	streamdns_handle_incoming_data(nsock, nsock->outerhandle, NULL, 0);
    774 
    775 exit:
    776 	nsock->accepting = false;
    777 
    778 	return result;
    779 }
    780 
    781 isc_result_t
    782 isc_nm_listenstreamdns(isc_nm_t *mgr, uint32_t workers, isc_sockaddr_t *iface,
    783 		       isc_nm_recv_cb_t recv_cb, void *recv_cbarg,
    784 		       isc_nm_accept_cb_t accept_cb, void *accept_cbarg,
    785 		       int backlog, isc_quota_t *quota, isc_tlsctx_t *tlsctx,
    786 		       isc_nm_proxy_type_t proxy_type, isc_nmsocket_t **sockp) {
    787 	isc_result_t result = ISC_R_FAILURE;
    788 	isc_nmsocket_t *listener = NULL;
    789 	isc__networker_t *worker = NULL;
    790 
    791 	REQUIRE(VALID_NM(mgr));
    792 	REQUIRE(isc_tid() == 0);
    793 
    794 	worker = &mgr->workers[isc_tid()];
    795 
    796 	if (isc__nm_closing(worker)) {
    797 		return ISC_R_SHUTTINGDOWN;
    798 	}
    799 
    800 	listener = streamdns_sock_new(worker, isc_nm_streamdnslistener, iface,
    801 				      true);
    802 	listener->accept_cb = accept_cb;
    803 	listener->accept_cbarg = accept_cbarg;
    804 	listener->recv_cb = recv_cb;
    805 	listener->recv_cbarg = recv_cbarg;
    806 
    807 	switch (proxy_type) {
    808 	case ISC_NM_PROXY_NONE:
    809 		if (tlsctx == NULL) {
    810 			result = isc_nm_listentcp(
    811 				mgr, workers, iface, streamdns_accept_cb,
    812 				listener, backlog, quota, &listener->outer);
    813 		} else {
    814 			result = isc_nm_listentls(mgr, workers, iface,
    815 						  streamdns_accept_cb, listener,
    816 						  backlog, quota, tlsctx, false,
    817 						  &listener->outer);
    818 		}
    819 		break;
    820 	case ISC_NM_PROXY_PLAIN:
    821 		if (tlsctx == NULL) {
    822 			result = isc_nm_listenproxystream(
    823 				mgr, workers, iface, streamdns_accept_cb,
    824 				listener, backlog, quota, NULL,
    825 				&listener->outer);
    826 		} else {
    827 			result = isc_nm_listentls(mgr, workers, iface,
    828 						  streamdns_accept_cb, listener,
    829 						  backlog, quota, tlsctx, true,
    830 						  &listener->outer);
    831 		}
    832 		break;
    833 	case ISC_NM_PROXY_ENCRYPTED:
    834 		INSIST(tlsctx != NULL);
    835 		result = isc_nm_listenproxystream(
    836 			mgr, workers, iface, streamdns_accept_cb, listener,
    837 			backlog, quota, tlsctx, &listener->outer);
    838 		break;
    839 	default:
    840 		UNREACHABLE();
    841 	};
    842 
    843 	if (result != ISC_R_SUCCESS) {
    844 		listener->closed = true;
    845 		isc__nmsocket_detach(&listener);
    846 		return result;
    847 	}
    848 
    849 	/* copy the actual port we're listening on into sock->iface */
    850 	if (isc_sockaddr_getport(iface) == 0) {
    851 		listener->iface = listener->outer->iface;
    852 	}
    853 
    854 	listener->result = result;
    855 	listener->active = true;
    856 	INSIST(listener->outer->streamdns.listener == NULL);
    857 	listener->nchildren = listener->outer->nchildren;
    858 	isc__nmsocket_attach(listener, &listener->outer->streamdns.listener);
    859 
    860 	*sockp = listener;
    861 
    862 	return result;
    863 }
    864 
    865 void
    866 isc__nm_streamdns_cleanup_data(isc_nmsocket_t *sock) {
    867 	switch (sock->type) {
    868 	case isc_nm_streamdnssocket:
    869 		isc_dnsstream_assembler_free(&sock->streamdns.input);
    870 		INSIST(sock->streamdns.nsending == 0);
    871 		if (sock->streamdns.send_req != NULL) {
    872 			isc_mem_t *mctx = sock->worker->mctx;
    873 			streamdns_put_send_req(mctx,
    874 					       (streamdns_send_req_t *)
    875 						       sock->streamdns.send_req,
    876 					       true);
    877 		}
    878 		break;
    879 	case isc_nm_streamdnslistener:
    880 		if (sock->outer) {
    881 			isc__nmsocket_detach(&sock->outer);
    882 		}
    883 		break;
    884 	case isc_nm_tlslistener:
    885 	case isc_nm_tcplistener:
    886 	case isc_nm_proxystreamlistener:
    887 		if (sock->streamdns.listener != NULL) {
    888 			isc__nmsocket_detach(&sock->streamdns.listener);
    889 		}
    890 		break;
    891 	case isc_nm_tlssocket:
    892 	case isc_nm_tcpsocket:
    893 	case isc_nm_proxystreamsocket:
    894 		if (sock->streamdns.sock != NULL) {
    895 			isc__nmsocket_detach(&sock->streamdns.sock);
    896 		}
    897 		break;
    898 	default:
    899 		return;
    900 	}
    901 }
    902 
    903 static void
    904 streamdns_read_cb(void *arg) {
    905 	isc_nmsocket_t *sock = arg;
    906 
    907 	REQUIRE(VALID_NMSOCK(sock));
    908 	REQUIRE(sock->tid == isc_tid());
    909 
    910 	sock->processing = false;
    911 
    912 	if (streamdns_closing(sock)) {
    913 		streamdns_failed_read_cb(sock, ISC_R_CANCELED, false);
    914 		goto detach;
    915 	}
    916 
    917 	if (sock->streamdns.reading) {
    918 		goto detach;
    919 	}
    920 
    921 	INSIST(VALID_NMHANDLE(sock->outerhandle));
    922 	streamdns_handle_incoming_data(sock, sock->outerhandle, NULL, 0);
    923 detach:
    924 	isc__nmsocket_detach(&sock);
    925 }
    926 
    927 void
    928 isc__nm_streamdns_read(isc_nmhandle_t *handle, isc_nm_recv_cb_t cb,
    929 		       void *cbarg) {
    930 	isc_nmsocket_t *sock = NULL;
    931 	bool closing = false;
    932 
    933 	REQUIRE(VALID_NMHANDLE(handle));
    934 	sock = handle->sock;
    935 	REQUIRE(VALID_NMSOCK(sock));
    936 	REQUIRE(sock->type == isc_nm_streamdnssocket);
    937 	REQUIRE(sock->recv_handle == handle || sock->recv_handle == NULL);
    938 	REQUIRE(sock->tid == isc_tid());
    939 
    940 	closing = streamdns_closing(sock);
    941 
    942 	sock->recv_cb = cb;
    943 	sock->recv_cbarg = cbarg;
    944 	sock->reading = true;
    945 	if (sock->recv_handle == NULL) {
    946 		isc_nmhandle_attach(handle, &sock->recv_handle);
    947 	}
    948 
    949 	/*
    950 	 * Prevent scheduling the job or processing data if streamdns_read_cb
    951 	 * has been already scheduled.
    952 	 */
    953 	if (sock->processing) {
    954 		return;
    955 	}
    956 
    957 	/*
    958 	 * In some cases there is little sense in making the operation
    959 	 * asynchronous as we just want to start reading from the
    960 	 * underlying transport.
    961 	 */
    962 	if (!closing && isc_dnsstream_assembler_result(sock->streamdns.input) ==
    963 				ISC_R_UNSET)
    964 	{
    965 		isc__nmsocket_attach(sock, &(isc_nmsocket_t *){ NULL });
    966 		streamdns_read_cb(sock);
    967 		return;
    968 	}
    969 
    970 	/*
    971 	 * We want the read operation to be asynchronous in most cases
    972 	 * because:
    973 	 *
    974 	 * 1. A read operation might be initiated from within the read
    975 	 *    callback itself.
    976 	 *
    977 	 * 2. Due to the above, we need to make the operation
    978 	 *    asynchronous to keep the socket state consistent.
    979 	 */
    980 
    981 	isc__nmsocket_attach(sock, &(isc_nmsocket_t *){ NULL });
    982 	sock->processing = true;
    983 	isc_job_run(sock->worker->loop, &sock->job, streamdns_read_cb, sock);
    984 }
    985 
    986 void
    987 isc__nm_streamdns_send(isc_nmhandle_t *handle, const isc_region_t *region,
    988 		       isc_nm_cb_t cb, void *cbarg) {
    989 	isc__nm_uvreq_t *uvreq = NULL;
    990 	isc_nmsocket_t *sock = NULL;
    991 	streamdns_send_req_t *send_req;
    992 	isc_mem_t *mctx;
    993 	isc_region_t data = { 0 };
    994 
    995 	REQUIRE(VALID_NMHANDLE(handle));
    996 	REQUIRE(VALID_NMSOCK(handle->sock));
    997 	REQUIRE(region->length <= UINT16_MAX);
    998 
    999 	sock = handle->sock;
   1000 
   1001 	REQUIRE(sock->type == isc_nm_streamdnssocket);
   1002 	REQUIRE(sock->tid == isc_tid());
   1003 
   1004 	uvreq = isc__nm_uvreq_get(sock);
   1005 	isc_nmhandle_attach(handle, &uvreq->handle);
   1006 	uvreq->cb.send = cb;
   1007 	uvreq->cbarg = cbarg;
   1008 	uvreq->uvbuf.base = (char *)region->base;
   1009 	uvreq->uvbuf.len = region->length;
   1010 
   1011 	if (streamdns_closing(sock)) {
   1012 		isc__nm_failed_send_cb(sock, uvreq, ISC_R_CANCELED, true);
   1013 		return;
   1014 	}
   1015 
   1016 	/*
   1017 	 * As when sending, we, basically, handing data to the underlying
   1018 	 * transport, we can treat the operation synchronously, as the
   1019 	 * transport code will take care of the asynchronicity if required.
   1020 	 */
   1021 	mctx = sock->worker->mctx;
   1022 	send_req = streamdns_get_send_req(sock, mctx, uvreq);
   1023 	data.base = (unsigned char *)uvreq->uvbuf.base;
   1024 	data.length = uvreq->uvbuf.len;
   1025 	isc__nm_senddns(sock->outerhandle, &data, streamdns_writecb,
   1026 			(void *)send_req);
   1027 
   1028 	isc__nm_uvreq_put(&uvreq);
   1029 }
   1030 
   1031 static void
   1032 streamdns_close_direct(isc_nmsocket_t *sock) {
   1033 	REQUIRE(VALID_NMSOCK(sock));
   1034 	REQUIRE(sock->tid == isc_tid());
   1035 
   1036 	if (sock->outerhandle != NULL) {
   1037 		sock->streamdns.reading = false;
   1038 		isc__nmsocket_timer_stop(sock);
   1039 		isc_nm_read_stop(sock->outerhandle);
   1040 		isc_nmhandle_close(sock->outerhandle);
   1041 		isc_nmhandle_detach(&sock->outerhandle);
   1042 	}
   1043 
   1044 	if (sock->listener != NULL) {
   1045 		isc__nmsocket_detach(&sock->listener);
   1046 	}
   1047 
   1048 	if (sock->recv_handle != NULL) {
   1049 		isc_nmhandle_detach(&sock->recv_handle);
   1050 	}
   1051 
   1052 	/* Further cleanup performed in isc__nm_streamdns_cleanup_data() */
   1053 	isc_dnsstream_assembler_clear(sock->streamdns.input);
   1054 	sock->closed = true;
   1055 	sock->active = false;
   1056 }
   1057 
   1058 void
   1059 isc__nm_streamdns_close(isc_nmsocket_t *sock) {
   1060 	REQUIRE(VALID_NMSOCK(sock));
   1061 	REQUIRE(sock->type == isc_nm_streamdnssocket);
   1062 	REQUIRE(sock->tid == isc_tid());
   1063 	REQUIRE(!sock->closing);
   1064 
   1065 	sock->closing = true;
   1066 
   1067 	streamdns_close_direct(sock);
   1068 }
   1069 
   1070 void
   1071 isc__nm_streamdns_stoplistening(isc_nmsocket_t *sock) {
   1072 	REQUIRE(VALID_NMSOCK(sock));
   1073 	REQUIRE(sock->type == isc_nm_streamdnslistener);
   1074 
   1075 	isc__nmsocket_stop(sock);
   1076 }
   1077 
   1078 void
   1079 isc__nmhandle_streamdns_cleartimeout(isc_nmhandle_t *handle) {
   1080 	isc_nmsocket_t *sock = NULL;
   1081 
   1082 	REQUIRE(VALID_NMHANDLE(handle));
   1083 	REQUIRE(VALID_NMSOCK(handle->sock));
   1084 	REQUIRE(handle->sock->type == isc_nm_streamdnssocket);
   1085 
   1086 	sock = handle->sock;
   1087 	if (sock->outerhandle != NULL) {
   1088 		INSIST(VALID_NMHANDLE(sock->outerhandle));
   1089 		isc_nmhandle_cleartimeout(sock->outerhandle);
   1090 	}
   1091 }
   1092 
   1093 void
   1094 isc__nmhandle_streamdns_settimeout(isc_nmhandle_t *handle, uint32_t timeout) {
   1095 	isc_nmsocket_t *sock = NULL;
   1096 
   1097 	REQUIRE(VALID_NMHANDLE(handle));
   1098 	REQUIRE(VALID_NMSOCK(handle->sock));
   1099 	REQUIRE(handle->sock->type == isc_nm_streamdnssocket);
   1100 
   1101 	sock = handle->sock;
   1102 	if (sock->outerhandle != NULL) {
   1103 		INSIST(VALID_NMHANDLE(sock->outerhandle));
   1104 		isc_nmhandle_settimeout(sock->outerhandle, timeout);
   1105 	}
   1106 }
   1107 
   1108 void
   1109 isc__nmhandle_streamdns_keepalive(isc_nmhandle_t *handle, bool value) {
   1110 	isc_nmsocket_t *sock = NULL;
   1111 
   1112 	REQUIRE(VALID_NMHANDLE(handle));
   1113 	REQUIRE(VALID_NMSOCK(handle->sock));
   1114 	REQUIRE(handle->sock->type == isc_nm_streamdnssocket);
   1115 
   1116 	sock = handle->sock;
   1117 	if (sock->outerhandle != NULL) {
   1118 		INSIST(VALID_NMHANDLE(sock->outerhandle));
   1119 		isc_nmhandle_keepalive(sock->outerhandle, value);
   1120 	}
   1121 }
   1122 
   1123 void
   1124 isc__nmhandle_streamdns_setwritetimeout(isc_nmhandle_t *handle,
   1125 					uint32_t timeout) {
   1126 	isc_nmsocket_t *sock = NULL;
   1127 
   1128 	REQUIRE(VALID_NMHANDLE(handle));
   1129 	REQUIRE(VALID_NMSOCK(handle->sock));
   1130 	REQUIRE(handle->sock->type == isc_nm_streamdnssocket);
   1131 
   1132 	sock = handle->sock;
   1133 	if (sock->outerhandle != NULL) {
   1134 		INSIST(VALID_NMHANDLE(sock->outerhandle));
   1135 		isc_nmhandle_setwritetimeout(sock->outerhandle, timeout);
   1136 	}
   1137 }
   1138 
   1139 bool
   1140 isc__nm_streamdns_has_encryption(const isc_nmhandle_t *handle) {
   1141 	isc_nmsocket_t *sock = NULL;
   1142 
   1143 	REQUIRE(VALID_NMHANDLE(handle));
   1144 	REQUIRE(VALID_NMSOCK(handle->sock));
   1145 	REQUIRE(handle->sock->type == isc_nm_streamdnssocket);
   1146 
   1147 	sock = handle->sock;
   1148 	if (sock->outerhandle != NULL) {
   1149 		INSIST(VALID_NMHANDLE(sock->outerhandle));
   1150 		return isc_nm_has_encryption(sock->outerhandle);
   1151 	}
   1152 
   1153 	return false;
   1154 }
   1155 
   1156 const char *
   1157 isc__nm_streamdns_verify_tls_peer_result_string(const isc_nmhandle_t *handle) {
   1158 	isc_nmsocket_t *sock = NULL;
   1159 
   1160 	REQUIRE(VALID_NMHANDLE(handle));
   1161 	REQUIRE(VALID_NMSOCK(handle->sock));
   1162 	REQUIRE(handle->sock->type == isc_nm_streamdnssocket);
   1163 
   1164 	sock = handle->sock;
   1165 	if (sock->outerhandle != NULL) {
   1166 		INSIST(VALID_NMHANDLE(sock->outerhandle));
   1167 		return isc_nm_verify_tls_peer_result_string(sock->outerhandle);
   1168 	} else if (sock->streamdns.tls_verify_error != NULL) {
   1169 		return sock->streamdns.tls_verify_error;
   1170 	}
   1171 
   1172 	return NULL;
   1173 }
   1174 
   1175 void
   1176 isc__nm_streamdns_set_tlsctx(isc_nmsocket_t *listener, isc_tlsctx_t *tlsctx) {
   1177 	REQUIRE(VALID_NMSOCK(listener));
   1178 	REQUIRE(listener->type == isc_nm_streamdnslistener);
   1179 
   1180 	if (listener->outer != NULL) {
   1181 		INSIST(VALID_NMSOCK(listener->outer));
   1182 		isc_nmsocket_set_tlsctx(listener->outer, tlsctx);
   1183 	}
   1184 }
   1185 
   1186 isc_result_t
   1187 isc__nm_streamdns_xfr_checkperm(isc_nmsocket_t *sock) {
   1188 	isc_result_t result = ISC_R_NOPERM;
   1189 
   1190 	REQUIRE(VALID_NMSOCK(sock));
   1191 	REQUIRE(sock->type == isc_nm_streamdnssocket);
   1192 
   1193 	if (sock->outerhandle != NULL) {
   1194 		if (isc_nm_has_encryption(sock->outerhandle) &&
   1195 		    !sock->streamdns.dot_alpn_negotiated)
   1196 		{
   1197 			result = ISC_R_DOTALPNERROR;
   1198 		} else {
   1199 			result = ISC_R_SUCCESS;
   1200 		}
   1201 	}
   1202 
   1203 	return result;
   1204 }
   1205 
   1206 void
   1207 isc__nmsocket_streamdns_reset(isc_nmsocket_t *sock) {
   1208 	REQUIRE(VALID_NMSOCK(sock));
   1209 	REQUIRE(sock->type == isc_nm_streamdnssocket);
   1210 
   1211 	if (sock->outerhandle == NULL) {
   1212 		return;
   1213 	}
   1214 
   1215 	INSIST(VALID_NMHANDLE(sock->outerhandle));
   1216 	isc__nmsocket_reset(sock->outerhandle->sock);
   1217 }
   1218