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