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