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