1 /* $NetBSD: doh_test.c,v 1.2 2024/02/21 22:52:50 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 <inttypes.h> 17 #include <sched.h> /* IWYU pragma: keep */ 18 #include <setjmp.h> 19 #include <stdarg.h> 20 #include <stdbool.h> 21 #include <stddef.h> 22 #include <stdlib.h> 23 #include <time.h> 24 #include <unistd.h> 25 #include <uv.h> 26 27 /* 28 * As a workaround, include an OpenSSL header file before including cmocka.h, 29 * because OpenSSL 3.1.0 uses __attribute__(malloc), conflicting with a 30 * redefined malloc in cmocka.h. 31 */ 32 #include <openssl/err.h> 33 34 #define UNIT_TESTING 35 #include <cmocka.h> 36 37 #include <isc/atomic.h> 38 #include <isc/buffer.h> 39 #include <isc/condition.h> 40 #include <isc/mutex.h> 41 #include <isc/netmgr.h> 42 #include <isc/nonce.h> 43 #include <isc/os.h> 44 #include <isc/print.h> 45 #include <isc/refcount.h> 46 #include <isc/sockaddr.h> 47 #include <isc/thread.h> 48 49 #include "uv_wrap.h" 50 #define KEEP_BEFORE 51 52 #include "netmgr/http.c" 53 #include "netmgr/netmgr-int.h" 54 #include "netmgr/uv-compat.c" 55 #include "netmgr/uv-compat.h" 56 #include "netmgr_p.h" 57 58 #include <tests/isc.h> 59 60 #define MAX_NM 2 61 62 static isc_sockaddr_t tcp_listen_addr; 63 64 static uint64_t send_magic = 0; 65 static uint64_t stop_magic = 0; 66 67 static uv_buf_t send_msg = { .base = (char *)&send_magic, 68 .len = sizeof(send_magic) }; 69 70 static atomic_int_fast64_t active_cconnects = 0; 71 static atomic_int_fast64_t nsends = 0; 72 static atomic_int_fast64_t ssends = 0; 73 static atomic_int_fast64_t sreads = 0; 74 static atomic_int_fast64_t csends = 0; 75 static atomic_int_fast64_t creads = 0; 76 static atomic_int_fast64_t ctimeouts = 0; 77 static atomic_int_fast64_t total_sends = 0; 78 79 static atomic_bool was_error = false; 80 81 static bool reuse_supported = true; 82 static bool noanswer = false; 83 84 static atomic_bool POST = true; 85 86 static atomic_bool slowdown = false; 87 88 static atomic_bool use_TLS = false; 89 static isc_tlsctx_t *server_tlsctx = NULL; 90 static isc_tlsctx_t *client_tlsctx = NULL; 91 static isc_tlsctx_client_session_cache_t *client_sess_cache = NULL; 92 93 static isc_quota_t listener_quota; 94 static atomic_bool check_listener_quota = false; 95 96 static isc_nm_http_endpoints_t *endpoints = NULL; 97 98 static bool skip_long_tests = false; 99 100 /* Timeout for soft-timeout tests (0.05 seconds) */ 101 #define T_SOFT 50 102 103 #define NSENDS 100 104 #define NWRITES 10 105 106 #define CHECK_RANGE_FULL(v) \ 107 { \ 108 int __v = atomic_load(&v); \ 109 assert_true(__v >= atomic_load(&total_sends)); \ 110 } 111 112 #define CHECK_RANGE_HALF(v) \ 113 { \ 114 int __v = atomic_load(&v); \ 115 assert_true(__v >= atomic_load(&total_sends) / 2); \ 116 } 117 118 /* Enable this to print values while running tests */ 119 #undef PRINT_DEBUG 120 #ifdef PRINT_DEBUG 121 #define X(v) fprintf(stderr, #v " = %" PRIu64 "\n", atomic_load(&v)) 122 #else 123 #define X(v) 124 #endif 125 126 #define SKIP_IN_CI \ 127 if (skip_long_tests) { \ 128 skip(); \ 129 return; \ 130 } 131 132 typedef struct csdata { 133 isc_nm_recv_cb_t reply_cb; 134 void *cb_arg; 135 isc_region_t region; 136 } csdata_t; 137 138 static void 139 connect_send_cb(isc_nmhandle_t *handle, isc_result_t result, void *arg) { 140 csdata_t data; 141 142 (void)atomic_fetch_sub(&active_cconnects, 1); 143 memmove(&data, arg, sizeof(data)); 144 isc_mem_put(handle->sock->mgr->mctx, arg, sizeof(data)); 145 if (result != ISC_R_SUCCESS) { 146 goto error; 147 } 148 149 REQUIRE(VALID_NMHANDLE(handle)); 150 151 result = isc__nm_http_request(handle, &data.region, data.reply_cb, 152 data.cb_arg); 153 if (result != ISC_R_SUCCESS) { 154 goto error; 155 } 156 157 isc_mem_put(handle->sock->mgr->mctx, data.region.base, 158 data.region.length); 159 return; 160 error: 161 data.reply_cb(handle, result, NULL, data.cb_arg); 162 isc_mem_put(handle->sock->mgr->mctx, data.region.base, 163 data.region.length); 164 if (result == ISC_R_TOOMANYOPENFILES) { 165 atomic_store(&slowdown, true); 166 } else { 167 atomic_store(&was_error, true); 168 } 169 } 170 171 static void 172 connect_send_request(isc_nm_t *mgr, const char *uri, bool post, 173 isc_region_t *region, isc_nm_recv_cb_t cb, void *cbarg, 174 bool tls, unsigned int timeout) { 175 isc_region_t copy; 176 csdata_t *data = NULL; 177 isc_tlsctx_t *ctx = NULL; 178 179 copy = (isc_region_t){ .base = isc_mem_get(mgr->mctx, region->length), 180 .length = region->length }; 181 memmove(copy.base, region->base, region->length); 182 data = isc_mem_get(mgr->mctx, sizeof(*data)); 183 *data = (csdata_t){ .reply_cb = cb, .cb_arg = cbarg, .region = copy }; 184 if (tls) { 185 ctx = client_tlsctx; 186 } 187 188 isc_nm_httpconnect(mgr, NULL, &tcp_listen_addr, uri, post, 189 connect_send_cb, data, ctx, client_sess_cache, 190 timeout, 0); 191 } 192 193 static int 194 setup_ephemeral_port(isc_sockaddr_t *addr, sa_family_t family) { 195 isc_result_t result; 196 socklen_t addrlen = sizeof(*addr); 197 int fd; 198 int r; 199 200 isc_sockaddr_fromin6(addr, &in6addr_loopback, 0); 201 202 fd = socket(AF_INET6, family, 0); 203 if (fd < 0) { 204 perror("setup_ephemeral_port: socket()"); 205 return (-1); 206 } 207 208 r = bind(fd, (const struct sockaddr *)&addr->type.sa, 209 sizeof(addr->type.sin6)); 210 if (r != 0) { 211 perror("setup_ephemeral_port: bind()"); 212 isc__nm_closesocket(fd); 213 return (r); 214 } 215 216 r = getsockname(fd, (struct sockaddr *)&addr->type.sa, &addrlen); 217 if (r != 0) { 218 perror("setup_ephemeral_port: getsockname()"); 219 isc__nm_closesocket(fd); 220 return (r); 221 } 222 223 result = isc__nm_socket_reuse(fd); 224 if (result != ISC_R_SUCCESS && result != ISC_R_NOTIMPLEMENTED) { 225 fprintf(stderr, 226 "setup_ephemeral_port: isc__nm_socket_reuse(): %s", 227 isc_result_totext(result)); 228 close(fd); 229 return (-1); 230 } 231 232 result = isc__nm_socket_reuse_lb(fd); 233 if (result != ISC_R_SUCCESS && result != ISC_R_NOTIMPLEMENTED) { 234 fprintf(stderr, 235 "setup_ephemeral_port: isc__nm_socket_reuse_lb(): %s", 236 isc_result_totext(result)); 237 close(fd); 238 return (-1); 239 } 240 if (result == ISC_R_NOTIMPLEMENTED) { 241 reuse_supported = false; 242 } 243 244 #if IPV6_RECVERR 245 #define setsockopt_on(socket, level, name) \ 246 setsockopt(socket, level, name, &(int){ 1 }, sizeof(int)) 247 248 r = setsockopt_on(fd, IPPROTO_IPV6, IPV6_RECVERR); 249 if (r != 0) { 250 perror("setup_ephemeral_port"); 251 close(fd); 252 return (r); 253 } 254 #endif 255 256 return (fd); 257 } 258 259 /* Generic */ 260 261 static void 262 noop_read_cb(isc_nmhandle_t *handle, isc_result_t result, isc_region_t *region, 263 void *cbarg) { 264 UNUSED(handle); 265 UNUSED(result); 266 UNUSED(region); 267 UNUSED(cbarg); 268 } 269 270 thread_local uint8_t tcp_buffer_storage[4096]; 271 thread_local size_t tcp_buffer_length = 0; 272 273 static int 274 setup_test(void **state) { 275 char *env_workers = getenv("ISC_TASK_WORKERS"); 276 size_t nworkers; 277 uv_os_sock_t tcp_listen_sock = -1; 278 isc_nm_t **nm = NULL; 279 280 tcp_listen_addr = (isc_sockaddr_t){ .length = 0 }; 281 tcp_listen_sock = setup_ephemeral_port(&tcp_listen_addr, SOCK_STREAM); 282 if (tcp_listen_sock < 0) { 283 return (-1); 284 } 285 close(tcp_listen_sock); 286 tcp_listen_sock = -1; 287 288 if (env_workers != NULL) { 289 workers = atoi(env_workers); 290 } else { 291 workers = isc_os_ncpus(); 292 } 293 INSIST(workers > 0); 294 nworkers = ISC_MAX(ISC_MIN(workers, 32), 1); 295 296 if (!reuse_supported || getenv("CI") != NULL) { 297 skip_long_tests = true; 298 } 299 300 atomic_store(&total_sends, NSENDS * NWRITES); 301 atomic_store(&nsends, atomic_load(&total_sends)); 302 303 atomic_store(&csends, 0); 304 atomic_store(&creads, 0); 305 atomic_store(&sreads, 0); 306 atomic_store(&ssends, 0); 307 atomic_store(&ctimeouts, 0); 308 atomic_store(&active_cconnects, 0); 309 310 atomic_store(&was_error, false); 311 312 atomic_store(&POST, false); 313 atomic_store(&use_TLS, false); 314 315 noanswer = false; 316 317 isc_nonce_buf(&send_magic, sizeof(send_magic)); 318 isc_nonce_buf(&stop_magic, sizeof(stop_magic)); 319 if (send_magic == stop_magic) { 320 return (-1); 321 } 322 323 nm = isc_mem_get(mctx, MAX_NM * sizeof(nm[0])); 324 for (size_t i = 0; i < MAX_NM; i++) { 325 isc__netmgr_create(mctx, nworkers, &nm[i]); 326 assert_non_null(nm[i]); 327 } 328 329 server_tlsctx = NULL; 330 isc_tlsctx_createserver(NULL, NULL, &server_tlsctx); 331 isc_tlsctx_enable_http2server_alpn(server_tlsctx); 332 client_tlsctx = NULL; 333 isc_tlsctx_createclient(&client_tlsctx); 334 isc_tlsctx_enable_http2client_alpn(client_tlsctx); 335 isc_tlsctx_client_session_cache_create( 336 mctx, client_tlsctx, 337 ISC_TLSCTX_CLIENT_SESSION_CACHE_DEFAULT_SIZE, 338 &client_sess_cache); 339 340 isc_quota_init(&listener_quota, 0); 341 atomic_store(&check_listener_quota, false); 342 343 INSIST(endpoints == NULL); 344 endpoints = isc_nm_http_endpoints_new(mctx); 345 346 *state = nm; 347 348 return (0); 349 } 350 351 static int 352 teardown_test(void **state) { 353 isc_nm_t **nm = (isc_nm_t **)*state; 354 355 for (size_t i = 0; i < MAX_NM; i++) { 356 isc__netmgr_destroy(&nm[i]); 357 assert_null(nm[i]); 358 } 359 isc_mem_put(mctx, nm, MAX_NM * sizeof(nm[0])); 360 361 if (server_tlsctx != NULL) { 362 isc_tlsctx_free(&server_tlsctx); 363 } 364 if (client_tlsctx != NULL) { 365 isc_tlsctx_free(&client_tlsctx); 366 } 367 368 isc_tlsctx_client_session_cache_detach(&client_sess_cache); 369 370 isc_quota_destroy(&listener_quota); 371 372 isc_nm_http_endpoints_detach(&endpoints); 373 374 return (0); 375 } 376 377 thread_local size_t nwrites = NWRITES; 378 379 static void 380 sockaddr_to_url(isc_sockaddr_t *sa, const bool https, char *outbuf, 381 size_t outbuf_len, const char *append) { 382 isc_nm_http_makeuri(https, sa, NULL, 0, append, outbuf, outbuf_len); 383 } 384 385 static isc_quota_t * 386 init_listener_quota(size_t nthreads) { 387 isc_quota_t *quotap = NULL; 388 if (atomic_load(&check_listener_quota)) { 389 unsigned max_quota = ISC_MAX(nthreads / 2, 1); 390 isc_quota_max(&listener_quota, max_quota); 391 quotap = &listener_quota; 392 } 393 return (quotap); 394 } 395 396 static void 397 doh_receive_reply_cb(isc_nmhandle_t *handle, isc_result_t eresult, 398 isc_region_t *region, void *cbarg) { 399 assert_non_null(handle); 400 UNUSED(cbarg); 401 UNUSED(region); 402 403 if (eresult == ISC_R_SUCCESS) { 404 (void)atomic_fetch_sub(&nsends, 1); 405 atomic_fetch_add(&csends, 1); 406 atomic_fetch_add(&creads, 1); 407 } else { 408 /* We failed to connect; try again */ 409 atomic_store(&was_error, true); 410 } 411 } 412 413 static void 414 doh_reply_sent_cb(isc_nmhandle_t *handle, isc_result_t eresult, void *cbarg) { 415 UNUSED(eresult); 416 UNUSED(cbarg); 417 418 assert_non_null(handle); 419 420 if (eresult == ISC_R_SUCCESS) { 421 atomic_fetch_add(&ssends, 1); 422 } 423 } 424 425 static void 426 doh_receive_request_cb(isc_nmhandle_t *handle, isc_result_t eresult, 427 isc_region_t *region, void *cbarg) { 428 uint64_t magic = 0; 429 430 UNUSED(cbarg); 431 assert_non_null(handle); 432 433 if (eresult != ISC_R_SUCCESS) { 434 atomic_store(&was_error, true); 435 return; 436 } 437 438 atomic_fetch_add(&sreads, 1); 439 440 memmove(tcp_buffer_storage + tcp_buffer_length, region->base, 441 region->length); 442 tcp_buffer_length += region->length; 443 444 while (tcp_buffer_length >= sizeof(magic)) { 445 magic = *(uint64_t *)tcp_buffer_storage; 446 assert_true(magic == stop_magic || magic == send_magic); 447 448 tcp_buffer_length -= sizeof(magic); 449 memmove(tcp_buffer_storage, tcp_buffer_storage + sizeof(magic), 450 tcp_buffer_length); 451 452 if (magic == send_magic) { 453 if (!noanswer) { 454 isc_nm_send(handle, region, doh_reply_sent_cb, 455 NULL); 456 } 457 return; 458 } else if (magic == stop_magic) { 459 /* 460 * We are done, so we don't send anything back. 461 * There should be no more packets in the buffer. 462 */ 463 assert_int_equal(tcp_buffer_length, 0); 464 } 465 } 466 } 467 468 ISC_RUN_TEST_IMPL(mock_doh_uv_tcp_bind) { 469 isc_nm_t **nm = (isc_nm_t **)*state; 470 isc_nm_t *listen_nm = nm[0]; 471 isc_result_t result = ISC_R_SUCCESS; 472 isc_nmsocket_t *listen_sock = NULL; 473 474 WILL_RETURN(uv_tcp_bind, UV_EADDRINUSE); 475 476 result = isc_nm_http_endpoints_add(endpoints, ISC_NM_HTTP_DEFAULT_PATH, 477 noop_read_cb, NULL, 0); 478 assert_int_equal(result, ISC_R_SUCCESS); 479 result = isc_nm_listenhttp(listen_nm, &tcp_listen_addr, 0, NULL, NULL, 480 endpoints, 0, &listen_sock); 481 assert_int_not_equal(result, ISC_R_SUCCESS); 482 assert_null(listen_sock); 483 484 RESET_RETURN; 485 } 486 487 static void 488 doh_noop(void **state) { 489 isc_nm_t **nm = (isc_nm_t **)*state; 490 isc_nm_t *listen_nm = nm[0]; 491 isc_nm_t *connect_nm = nm[1]; 492 isc_result_t result = ISC_R_SUCCESS; 493 isc_nmsocket_t *listen_sock = NULL; 494 char req_url[256]; 495 496 result = isc_nm_http_endpoints_add(endpoints, ISC_NM_HTTP_DEFAULT_PATH, 497 noop_read_cb, NULL, 0); 498 assert_int_equal(result, ISC_R_SUCCESS); 499 500 result = isc_nm_listenhttp(listen_nm, &tcp_listen_addr, 0, NULL, NULL, 501 endpoints, 0, &listen_sock); 502 assert_int_equal(result, ISC_R_SUCCESS); 503 504 isc_nm_stoplistening(listen_sock); 505 isc_nmsocket_close(&listen_sock); 506 assert_null(listen_sock); 507 508 sockaddr_to_url(&tcp_listen_addr, false, req_url, sizeof(req_url), 509 ISC_NM_HTTP_DEFAULT_PATH); 510 connect_send_request(connect_nm, req_url, atomic_load(&POST), 511 &(isc_region_t){ .base = (uint8_t *)send_msg.base, 512 .length = send_msg.len }, 513 noop_read_cb, NULL, atomic_load(&use_TLS), 30000); 514 515 isc__netmgr_shutdown(connect_nm); 516 517 assert_int_equal(0, atomic_load(&csends)); 518 assert_int_equal(0, atomic_load(&creads)); 519 assert_int_equal(0, atomic_load(&sreads)); 520 assert_int_equal(0, atomic_load(&ssends)); 521 } 522 523 ISC_RUN_TEST_IMPL(doh_noop_POST) { 524 atomic_store(&POST, true); 525 doh_noop(state); 526 } 527 528 ISC_RUN_TEST_IMPL(doh_noop_GET) { 529 atomic_store(&POST, false); 530 doh_noop(state); 531 } 532 533 static void 534 doh_noresponse(void **state) { 535 isc_nm_t **nm = (isc_nm_t **)*state; 536 isc_nm_t *listen_nm = nm[0]; 537 isc_nm_t *connect_nm = nm[1]; 538 isc_result_t result = ISC_R_SUCCESS; 539 isc_nmsocket_t *listen_sock = NULL; 540 char req_url[256]; 541 542 result = isc_nm_http_endpoints_add(endpoints, ISC_NM_HTTP_DEFAULT_PATH, 543 noop_read_cb, NULL, 0); 544 assert_int_equal(result, ISC_R_SUCCESS); 545 546 result = isc_nm_listenhttp(listen_nm, &tcp_listen_addr, 0, NULL, NULL, 547 endpoints, 0, &listen_sock); 548 assert_int_equal(result, ISC_R_SUCCESS); 549 550 sockaddr_to_url(&tcp_listen_addr, false, req_url, sizeof(req_url), 551 ISC_NM_HTTP_DEFAULT_PATH); 552 connect_send_request(connect_nm, req_url, atomic_load(&POST), 553 &(isc_region_t){ .base = (uint8_t *)send_msg.base, 554 .length = send_msg.len }, 555 noop_read_cb, NULL, atomic_load(&use_TLS), 30000); 556 557 isc_nm_stoplistening(listen_sock); 558 isc_nmsocket_close(&listen_sock); 559 assert_null(listen_sock); 560 isc__netmgr_shutdown(connect_nm); 561 } 562 563 ISC_RUN_TEST_IMPL(doh_noresponse_POST) { 564 atomic_store(&POST, true); 565 doh_noresponse(state); 566 } 567 568 ISC_RUN_TEST_IMPL(doh_noresponse_GET) { 569 atomic_store(&POST, false); 570 doh_noresponse(state); 571 } 572 573 static void 574 timeout_query_sent_cb(isc_nmhandle_t *handle, isc_result_t eresult, 575 void *cbarg) { 576 UNUSED(eresult); 577 UNUSED(cbarg); 578 579 assert_non_null(handle); 580 581 if (eresult == ISC_R_SUCCESS) { 582 atomic_fetch_add(&csends, 1); 583 } 584 585 isc_nmhandle_detach(&handle); 586 } 587 588 static void 589 timeout_retry_cb(isc_nmhandle_t *handle, isc_result_t eresult, 590 isc_region_t *region, void *arg) { 591 UNUSED(region); 592 UNUSED(arg); 593 594 assert_non_null(handle); 595 596 atomic_fetch_add(&ctimeouts, 1); 597 598 if (eresult == ISC_R_TIMEDOUT && atomic_load(&ctimeouts) < 5) { 599 isc_nmhandle_settimeout(handle, T_SOFT); 600 return; 601 } 602 603 isc_nmhandle_detach(&handle); 604 } 605 606 static void 607 timeout_request_cb(isc_nmhandle_t *handle, isc_result_t result, void *arg) { 608 isc_nmhandle_t *sendhandle = NULL; 609 isc_nmhandle_t *readhandle = NULL; 610 611 REQUIRE(VALID_NMHANDLE(handle)); 612 613 if (result != ISC_R_SUCCESS) { 614 goto error; 615 } 616 617 isc_nmhandle_attach(handle, &sendhandle); 618 isc_nm_send(handle, 619 &(isc_region_t){ .base = (uint8_t *)send_msg.base, 620 .length = send_msg.len }, 621 timeout_query_sent_cb, arg); 622 623 isc_nmhandle_attach(handle, &readhandle); 624 isc_nm_read(handle, timeout_retry_cb, NULL); 625 return; 626 627 error: 628 atomic_store(&was_error, true); 629 } 630 631 static void 632 doh_timeout_recovery(void **state) { 633 isc_nm_t **nm = (isc_nm_t **)*state; 634 isc_nm_t *listen_nm = nm[0]; 635 isc_nm_t *connect_nm = nm[1]; 636 isc_result_t result = ISC_R_SUCCESS; 637 isc_nmsocket_t *listen_sock = NULL; 638 isc_tlsctx_t *ctx = atomic_load(&use_TLS) ? server_tlsctx : NULL; 639 char req_url[256]; 640 641 result = isc_nm_http_endpoints_add(endpoints, ISC_NM_HTTP_DEFAULT_PATH, 642 doh_receive_request_cb, NULL, 0); 643 assert_int_equal(result, ISC_R_SUCCESS); 644 645 result = isc_nm_listenhttp(listen_nm, &tcp_listen_addr, 0, NULL, NULL, 646 endpoints, 0, &listen_sock); 647 assert_int_equal(result, ISC_R_SUCCESS); 648 649 /* 650 * Accept connections but don't send responses, forcing client 651 * reads to time out. 652 */ 653 noanswer = true; 654 655 /* 656 * Shorten all the TCP client timeouts to 0.05 seconds. 657 * timeout_retry_cb() will give up after five timeouts. 658 */ 659 isc_nm_settimeouts(connect_nm, T_SOFT, T_SOFT, T_SOFT, T_SOFT); 660 sockaddr_to_url(&tcp_listen_addr, false, req_url, sizeof(req_url), 661 ISC_NM_HTTP_DEFAULT_PATH); 662 isc_nm_httpconnect(connect_nm, NULL, &tcp_listen_addr, req_url, 663 atomic_load(&POST), timeout_request_cb, NULL, ctx, 664 client_sess_cache, T_SOFT, 0); 665 666 /* 667 * Sleep until sends reaches 5. 668 */ 669 for (size_t i = 0; i < 1000; i++) { 670 if (atomic_load(&ctimeouts) == 5) { 671 break; 672 } 673 isc_test_nap(1); 674 } 675 assert_true(atomic_load(&ctimeouts) == 5); 676 677 isc_nm_stoplistening(listen_sock); 678 isc_nmsocket_close(&listen_sock); 679 assert_null(listen_sock); 680 isc__netmgr_shutdown(connect_nm); 681 } 682 683 ISC_RUN_TEST_IMPL(doh_timeout_recovery_POST) { 684 SKIP_IN_CI; 685 686 atomic_store(&POST, true); 687 doh_timeout_recovery(state); 688 } 689 690 ISC_RUN_TEST_IMPL(doh_timeout_recovery_GET) { 691 SKIP_IN_CI; 692 693 atomic_store(&POST, false); 694 doh_timeout_recovery(state); 695 } 696 697 static void 698 doh_receive_send_reply_cb(isc_nmhandle_t *handle, isc_result_t eresult, 699 isc_region_t *region, void *cbarg) { 700 UNUSED(region); 701 702 if (eresult != ISC_R_SUCCESS) { 703 atomic_store(&was_error, true); 704 return; 705 } 706 707 assert_non_null(handle); 708 709 int_fast64_t sends = atomic_fetch_sub(&nsends, 1); 710 atomic_fetch_add(&csends, 1); 711 atomic_fetch_add(&creads, 1); 712 if (sends > 0 && cbarg == NULL) { 713 size_t i; 714 for (i = 0; i < NWRITES / 2; i++) { 715 eresult = isc__nm_http_request( 716 handle, 717 &(isc_region_t){ 718 .base = (uint8_t *)send_msg.base, 719 .length = send_msg.len }, 720 doh_receive_send_reply_cb, (void *)1); 721 if (eresult == ISC_R_CANCELED) { 722 break; 723 } 724 assert_true(eresult == ISC_R_SUCCESS); 725 } 726 } 727 } 728 729 static isc_threadresult_t 730 doh_connect_thread(isc_threadarg_t arg) { 731 isc_nm_t *connect_nm = (isc_nm_t *)arg; 732 char req_url[256]; 733 int64_t sends = atomic_load(&nsends); 734 735 sockaddr_to_url(&tcp_listen_addr, atomic_load(&use_TLS), req_url, 736 sizeof(req_url), ISC_NM_HTTP_DEFAULT_PATH); 737 738 while (sends > 0) { 739 /* 740 * We need to back off and slow down if we start getting 741 * errors, to prevent a thundering herd problem. 742 */ 743 int_fast64_t active = atomic_fetch_add(&active_cconnects, 1); 744 if (atomic_load(&slowdown) || active > workers) { 745 isc_test_nap(active - workers); 746 atomic_store(&slowdown, false); 747 } 748 connect_send_request( 749 connect_nm, req_url, atomic_load(&POST), 750 &(isc_region_t){ .base = (uint8_t *)send_msg.base, 751 .length = send_msg.len }, 752 doh_receive_send_reply_cb, NULL, atomic_load(&use_TLS), 753 30000); 754 sends = atomic_load(&nsends); 755 } 756 757 return ((isc_threadresult_t)0); 758 } 759 760 static void 761 doh_recv_one(void **state) { 762 isc_nm_t **nm = (isc_nm_t **)*state; 763 isc_nm_t *listen_nm = nm[0]; 764 isc_nm_t *connect_nm = nm[1]; 765 isc_result_t result = ISC_R_SUCCESS; 766 isc_nmsocket_t *listen_sock = NULL; 767 char req_url[256]; 768 isc_quota_t *quotap = init_listener_quota(workers); 769 770 atomic_store(&total_sends, 1); 771 772 atomic_store(&nsends, atomic_load(&total_sends)); 773 774 result = isc_nm_http_endpoints_add(endpoints, ISC_NM_HTTP_DEFAULT_PATH, 775 doh_receive_request_cb, NULL, 0); 776 assert_int_equal(result, ISC_R_SUCCESS); 777 778 result = isc_nm_listenhttp(listen_nm, &tcp_listen_addr, 0, quotap, 779 atomic_load(&use_TLS) ? server_tlsctx : NULL, 780 endpoints, 0, &listen_sock); 781 assert_int_equal(result, ISC_R_SUCCESS); 782 783 sockaddr_to_url(&tcp_listen_addr, atomic_load(&use_TLS), req_url, 784 sizeof(req_url), ISC_NM_HTTP_DEFAULT_PATH); 785 connect_send_request(connect_nm, req_url, atomic_load(&POST), 786 &(isc_region_t){ .base = (uint8_t *)send_msg.base, 787 .length = send_msg.len }, 788 doh_receive_reply_cb, NULL, atomic_load(&use_TLS), 789 30000); 790 791 while (atomic_load(&nsends) > 0) { 792 if (atomic_load(&was_error)) { 793 break; 794 } 795 isc_thread_yield(); 796 } 797 798 while (atomic_load(&ssends) != 1 || atomic_load(&sreads) != 1 || 799 atomic_load(&csends) != 1) 800 { 801 if (atomic_load(&was_error)) { 802 break; 803 } 804 isc_thread_yield(); 805 } 806 807 isc_nm_stoplistening(listen_sock); 808 isc_nmsocket_close(&listen_sock); 809 assert_null(listen_sock); 810 isc__netmgr_shutdown(connect_nm); 811 812 X(total_sends); 813 X(csends); 814 X(creads); 815 X(sreads); 816 X(ssends); 817 818 assert_int_equal(atomic_load(&csends), 1); 819 assert_int_equal(atomic_load(&creads), 1); 820 assert_int_equal(atomic_load(&sreads), 1); 821 assert_int_equal(atomic_load(&ssends), 1); 822 } 823 824 ISC_RUN_TEST_IMPL(doh_recv_one_POST) { 825 SKIP_IN_CI; 826 827 atomic_store(&POST, true); 828 doh_recv_one(state); 829 } 830 831 ISC_RUN_TEST_IMPL(doh_recv_one_GET) { 832 SKIP_IN_CI; 833 834 atomic_store(&POST, false); 835 doh_recv_one(state); 836 } 837 838 ISC_RUN_TEST_IMPL(doh_recv_one_POST_TLS) { 839 SKIP_IN_CI; 840 841 atomic_store(&use_TLS, true); 842 atomic_store(&POST, true); 843 doh_recv_one(state); 844 } 845 846 ISC_RUN_TEST_IMPL(doh_recv_one_GET_TLS) { 847 SKIP_IN_CI; 848 849 atomic_store(&use_TLS, true); 850 atomic_store(&POST, false); 851 doh_recv_one(state); 852 } 853 854 ISC_RUN_TEST_IMPL(doh_recv_one_POST_quota) { 855 SKIP_IN_CI; 856 857 atomic_store(&POST, true); 858 atomic_store(&check_listener_quota, true); 859 doh_recv_one(state); 860 } 861 862 ISC_RUN_TEST_IMPL(doh_recv_one_GET_quota) { 863 SKIP_IN_CI; 864 865 atomic_store(&POST, false); 866 atomic_store(&check_listener_quota, true); 867 doh_recv_one(state); 868 } 869 870 ISC_RUN_TEST_IMPL(doh_recv_one_POST_TLS_quota) { 871 SKIP_IN_CI; 872 873 atomic_store(&use_TLS, true); 874 atomic_store(&POST, true); 875 atomic_store(&check_listener_quota, true); 876 doh_recv_one(state); 877 } 878 879 ISC_RUN_TEST_IMPL(doh_recv_one_GET_TLS_quota) { 880 SKIP_IN_CI; 881 882 atomic_store(&use_TLS, true); 883 atomic_store(&POST, false); 884 atomic_store(&check_listener_quota, true); 885 doh_recv_one(state); 886 } 887 888 static void 889 doh_connect_send_two_requests_cb(isc_nmhandle_t *handle, isc_result_t result, 890 void *arg) { 891 REQUIRE(VALID_NMHANDLE(handle)); 892 if (result != ISC_R_SUCCESS) { 893 goto error; 894 } 895 896 result = isc__nm_http_request( 897 handle, 898 &(isc_region_t){ .base = (uint8_t *)send_msg.base, 899 .length = send_msg.len }, 900 doh_receive_reply_cb, arg); 901 if (result != ISC_R_SUCCESS) { 902 goto error; 903 } 904 905 result = isc__nm_http_request( 906 handle, 907 &(isc_region_t){ .base = (uint8_t *)send_msg.base, 908 .length = send_msg.len }, 909 doh_receive_reply_cb, arg); 910 if (result != ISC_R_SUCCESS) { 911 goto error; 912 } 913 return; 914 error: 915 atomic_store(&was_error, true); 916 } 917 918 static void 919 doh_recv_two(void **state) { 920 isc_nm_t **nm = (isc_nm_t **)*state; 921 isc_nm_t *listen_nm = nm[0]; 922 isc_nm_t *connect_nm = nm[1]; 923 isc_result_t result = ISC_R_SUCCESS; 924 isc_nmsocket_t *listen_sock = NULL; 925 char req_url[256]; 926 isc_tlsctx_t *ctx = NULL; 927 isc_quota_t *quotap = init_listener_quota(workers); 928 929 atomic_store(&total_sends, 2); 930 931 atomic_store(&nsends, atomic_load(&total_sends)); 932 933 result = isc_nm_http_endpoints_add(endpoints, ISC_NM_HTTP_DEFAULT_PATH, 934 doh_receive_request_cb, NULL, 0); 935 assert_int_equal(result, ISC_R_SUCCESS); 936 937 result = isc_nm_listenhttp(listen_nm, &tcp_listen_addr, 0, quotap, 938 atomic_load(&use_TLS) ? server_tlsctx : NULL, 939 endpoints, 0, &listen_sock); 940 assert_int_equal(result, ISC_R_SUCCESS); 941 942 sockaddr_to_url(&tcp_listen_addr, atomic_load(&use_TLS), req_url, 943 sizeof(req_url), ISC_NM_HTTP_DEFAULT_PATH); 944 945 if (atomic_load(&use_TLS)) { 946 ctx = client_tlsctx; 947 } 948 949 isc_nm_httpconnect(connect_nm, NULL, &tcp_listen_addr, req_url, 950 atomic_load(&POST), doh_connect_send_two_requests_cb, 951 NULL, ctx, client_sess_cache, 5000, 0); 952 953 while (atomic_load(&nsends) > 0) { 954 if (atomic_load(&was_error)) { 955 break; 956 } 957 isc_thread_yield(); 958 } 959 960 while (atomic_load(&ssends) != 2 || atomic_load(&sreads) != 2 || 961 atomic_load(&csends) != 2) 962 { 963 if (atomic_load(&was_error)) { 964 break; 965 } 966 isc_thread_yield(); 967 } 968 969 isc_nm_stoplistening(listen_sock); 970 isc_nmsocket_close(&listen_sock); 971 assert_null(listen_sock); 972 isc__netmgr_shutdown(connect_nm); 973 974 X(total_sends); 975 X(csends); 976 X(creads); 977 X(sreads); 978 X(ssends); 979 980 assert_int_equal(atomic_load(&csends), 2); 981 assert_int_equal(atomic_load(&creads), 2); 982 assert_int_equal(atomic_load(&sreads), 2); 983 assert_int_equal(atomic_load(&ssends), 2); 984 } 985 986 ISC_RUN_TEST_IMPL(doh_recv_two_POST) { 987 SKIP_IN_CI; 988 989 atomic_store(&POST, true); 990 doh_recv_two(state); 991 } 992 993 ISC_RUN_TEST_IMPL(doh_recv_two_GET) { 994 SKIP_IN_CI; 995 996 atomic_store(&POST, false); 997 doh_recv_two(state); 998 } 999 1000 ISC_RUN_TEST_IMPL(doh_recv_two_POST_TLS) { 1001 SKIP_IN_CI; 1002 1003 atomic_store(&use_TLS, true); 1004 atomic_store(&POST, true); 1005 doh_recv_two(state); 1006 } 1007 1008 ISC_RUN_TEST_IMPL(doh_recv_two_GET_TLS) { 1009 SKIP_IN_CI; 1010 1011 atomic_store(&use_TLS, true); 1012 atomic_store(&POST, false); 1013 doh_recv_two(state); 1014 } 1015 1016 ISC_RUN_TEST_IMPL(doh_recv_two_POST_quota) { 1017 SKIP_IN_CI; 1018 1019 atomic_store(&POST, true); 1020 atomic_store(&check_listener_quota, true); 1021 doh_recv_two(state); 1022 } 1023 1024 ISC_RUN_TEST_IMPL(doh_recv_two_GET_quota) { 1025 SKIP_IN_CI; 1026 1027 atomic_store(&POST, false); 1028 atomic_store(&check_listener_quota, true); 1029 doh_recv_two(state); 1030 } 1031 1032 ISC_RUN_TEST_IMPL(doh_recv_two_POST_TLS_quota) { 1033 SKIP_IN_CI; 1034 1035 atomic_store(&use_TLS, true); 1036 atomic_store(&POST, true); 1037 atomic_store(&check_listener_quota, true); 1038 doh_recv_two(state); 1039 } 1040 1041 ISC_RUN_TEST_IMPL(doh_recv_two_GET_TLS_quota) { 1042 SKIP_IN_CI; 1043 1044 atomic_store(&use_TLS, true); 1045 atomic_store(&POST, false); 1046 atomic_store(&check_listener_quota, true); 1047 doh_recv_two(state); 1048 } 1049 1050 static void 1051 doh_recv_send(void **state) { 1052 isc_nm_t **nm = (isc_nm_t **)*state; 1053 isc_nm_t *listen_nm = nm[0]; 1054 isc_nm_t *connect_nm = nm[1]; 1055 isc_result_t result = ISC_R_SUCCESS; 1056 isc_nmsocket_t *listen_sock = NULL; 1057 size_t nthreads = ISC_MAX(ISC_MIN(workers, 32), 1); 1058 isc_thread_t threads[32] = { 0 }; 1059 isc_quota_t *quotap = init_listener_quota(workers); 1060 1061 result = isc_nm_http_endpoints_add(endpoints, ISC_NM_HTTP_DEFAULT_PATH, 1062 doh_receive_request_cb, NULL, 0); 1063 assert_int_equal(result, ISC_R_SUCCESS); 1064 1065 result = isc_nm_listenhttp(listen_nm, &tcp_listen_addr, 0, quotap, 1066 atomic_load(&use_TLS) ? server_tlsctx : NULL, 1067 endpoints, 0, &listen_sock); 1068 assert_int_equal(result, ISC_R_SUCCESS); 1069 1070 for (size_t i = 0; i < nthreads; i++) { 1071 isc_thread_create(doh_connect_thread, connect_nm, &threads[i]); 1072 } 1073 1074 /* wait for the all responses from the server */ 1075 while (atomic_load(&ssends) < atomic_load(&total_sends)) { 1076 if (atomic_load(&was_error)) { 1077 break; 1078 } 1079 isc_test_nap(1); 1080 } 1081 1082 for (size_t i = 0; i < nthreads; i++) { 1083 isc_thread_join(threads[i], NULL); 1084 } 1085 1086 isc__netmgr_shutdown(connect_nm); 1087 isc_nm_stoplistening(listen_sock); 1088 isc_nmsocket_close(&listen_sock); 1089 assert_null(listen_sock); 1090 1091 X(total_sends); 1092 X(csends); 1093 X(creads); 1094 X(sreads); 1095 X(ssends); 1096 1097 CHECK_RANGE_FULL(csends); 1098 CHECK_RANGE_FULL(creads); 1099 CHECK_RANGE_FULL(sreads); 1100 CHECK_RANGE_FULL(ssends); 1101 } 1102 1103 ISC_RUN_TEST_IMPL(doh_recv_send_POST) { 1104 SKIP_IN_CI; 1105 1106 atomic_store(&POST, true); 1107 doh_recv_send(state); 1108 } 1109 1110 ISC_RUN_TEST_IMPL(doh_recv_send_GET) { 1111 SKIP_IN_CI; 1112 1113 atomic_store(&POST, false); 1114 doh_recv_send(state); 1115 } 1116 1117 ISC_RUN_TEST_IMPL(doh_recv_send_POST_TLS) { 1118 SKIP_IN_CI; 1119 1120 atomic_store(&POST, true); 1121 atomic_store(&use_TLS, true); 1122 doh_recv_send(state); 1123 } 1124 1125 ISC_RUN_TEST_IMPL(doh_recv_send_GET_TLS) { 1126 SKIP_IN_CI; 1127 1128 atomic_store(&POST, false); 1129 atomic_store(&use_TLS, true); 1130 doh_recv_send(state); 1131 } 1132 1133 ISC_RUN_TEST_IMPL(doh_recv_send_POST_quota) { 1134 SKIP_IN_CI; 1135 1136 atomic_store(&POST, true); 1137 atomic_store(&check_listener_quota, true); 1138 doh_recv_send(state); 1139 } 1140 1141 ISC_RUN_TEST_IMPL(doh_recv_send_GET_quota) { 1142 SKIP_IN_CI; 1143 1144 atomic_store(&POST, false); 1145 atomic_store(&check_listener_quota, true); 1146 doh_recv_send(state); 1147 } 1148 1149 ISC_RUN_TEST_IMPL(doh_recv_send_POST_TLS_quota) { 1150 SKIP_IN_CI; 1151 1152 atomic_store(&POST, true); 1153 atomic_store(&use_TLS, true); 1154 atomic_store(&check_listener_quota, true); 1155 doh_recv_send(state); 1156 } 1157 1158 ISC_RUN_TEST_IMPL(doh_recv_send_GET_TLS_quota) { 1159 SKIP_IN_CI; 1160 1161 atomic_store(&POST, false); 1162 atomic_store(&use_TLS, true); 1163 atomic_store(&check_listener_quota, true); 1164 doh_recv_send(state); 1165 } 1166 1167 static void 1168 doh_recv_half_send(void **state) { 1169 isc_nm_t **nm = (isc_nm_t **)*state; 1170 isc_nm_t *listen_nm = nm[0]; 1171 isc_nm_t *connect_nm = nm[1]; 1172 isc_result_t result = ISC_R_SUCCESS; 1173 isc_nmsocket_t *listen_sock = NULL; 1174 size_t nthreads = ISC_MAX(ISC_MIN(workers, 32), 1); 1175 isc_thread_t threads[32] = { 0 }; 1176 isc_quota_t *quotap = init_listener_quota(workers); 1177 1178 atomic_store(&total_sends, atomic_load(&total_sends) / 2); 1179 1180 atomic_store(&nsends, atomic_load(&total_sends)); 1181 1182 result = isc_nm_http_endpoints_add(endpoints, ISC_NM_HTTP_DEFAULT_PATH, 1183 doh_receive_request_cb, NULL, 0); 1184 assert_int_equal(result, ISC_R_SUCCESS); 1185 1186 result = isc_nm_listenhttp(listen_nm, &tcp_listen_addr, 0, quotap, 1187 atomic_load(&use_TLS) ? server_tlsctx : NULL, 1188 endpoints, 0, &listen_sock); 1189 assert_int_equal(result, ISC_R_SUCCESS); 1190 1191 for (size_t i = 0; i < nthreads; i++) { 1192 isc_thread_create(doh_connect_thread, connect_nm, &threads[i]); 1193 } 1194 1195 while (atomic_load(&nsends) > 0) { 1196 isc_thread_yield(); 1197 } 1198 1199 isc__netmgr_shutdown(connect_nm); 1200 1201 for (size_t i = 0; i < nthreads; i++) { 1202 isc_thread_join(threads[i], NULL); 1203 } 1204 1205 isc_nm_stoplistening(listen_sock); 1206 isc_nmsocket_close(&listen_sock); 1207 assert_null(listen_sock); 1208 1209 X(total_sends); 1210 X(csends); 1211 X(creads); 1212 X(sreads); 1213 X(ssends); 1214 1215 CHECK_RANGE_HALF(csends); 1216 CHECK_RANGE_HALF(creads); 1217 CHECK_RANGE_HALF(sreads); 1218 CHECK_RANGE_HALF(ssends); 1219 } 1220 1221 ISC_RUN_TEST_IMPL(doh_recv_half_send_POST) { 1222 SKIP_IN_CI; 1223 1224 atomic_store(&POST, true); 1225 doh_recv_half_send(state); 1226 } 1227 1228 ISC_RUN_TEST_IMPL(doh_recv_half_send_GET) { 1229 SKIP_IN_CI; 1230 1231 atomic_store(&POST, false); 1232 doh_recv_half_send(state); 1233 } 1234 1235 ISC_RUN_TEST_IMPL(doh_recv_half_send_POST_TLS) { 1236 SKIP_IN_CI; 1237 1238 atomic_store(&use_TLS, true); 1239 atomic_store(&POST, true); 1240 doh_recv_half_send(state); 1241 } 1242 1243 ISC_RUN_TEST_IMPL(doh_recv_half_send_GET_TLS) { 1244 SKIP_IN_CI; 1245 1246 atomic_store(&use_TLS, true); 1247 atomic_store(&POST, false); 1248 doh_recv_half_send(state); 1249 } 1250 1251 ISC_RUN_TEST_IMPL(doh_recv_half_send_POST_quota) { 1252 SKIP_IN_CI; 1253 1254 atomic_store(&POST, true); 1255 atomic_store(&check_listener_quota, true); 1256 doh_recv_half_send(state); 1257 } 1258 1259 ISC_RUN_TEST_IMPL(doh_recv_half_send_GET_quota) { 1260 SKIP_IN_CI; 1261 1262 atomic_store(&POST, false); 1263 atomic_store(&check_listener_quota, true); 1264 doh_recv_half_send(state); 1265 } 1266 1267 ISC_RUN_TEST_IMPL(doh_recv_half_send_POST_TLS_quota) { 1268 SKIP_IN_CI; 1269 1270 atomic_store(&use_TLS, true); 1271 atomic_store(&POST, true); 1272 atomic_store(&check_listener_quota, true); 1273 doh_recv_half_send(state); 1274 } 1275 1276 ISC_RUN_TEST_IMPL(doh_recv_half_send_GET_TLS_quota) { 1277 SKIP_IN_CI; 1278 1279 atomic_store(&use_TLS, true); 1280 atomic_store(&POST, false); 1281 atomic_store(&check_listener_quota, true); 1282 doh_recv_half_send(state); 1283 } 1284 1285 static void 1286 doh_half_recv_send(void **state) { 1287 isc_nm_t **nm = (isc_nm_t **)*state; 1288 isc_nm_t *listen_nm = nm[0]; 1289 isc_nm_t *connect_nm = nm[1]; 1290 isc_result_t result = ISC_R_SUCCESS; 1291 isc_nmsocket_t *listen_sock = NULL; 1292 size_t nthreads = ISC_MAX(ISC_MIN(workers, 32), 1); 1293 isc_thread_t threads[32] = { 0 }; 1294 isc_quota_t *quotap = init_listener_quota(workers); 1295 1296 atomic_store(&total_sends, atomic_load(&total_sends) / 2); 1297 1298 atomic_store(&nsends, atomic_load(&total_sends)); 1299 1300 result = isc_nm_http_endpoints_add(endpoints, ISC_NM_HTTP_DEFAULT_PATH, 1301 doh_receive_request_cb, NULL, 0); 1302 assert_int_equal(result, ISC_R_SUCCESS); 1303 1304 result = isc_nm_listenhttp(listen_nm, &tcp_listen_addr, 0, quotap, 1305 atomic_load(&use_TLS) ? server_tlsctx : NULL, 1306 endpoints, 0, &listen_sock); 1307 assert_int_equal(result, ISC_R_SUCCESS); 1308 1309 for (size_t i = 0; i < nthreads; i++) { 1310 isc_thread_create(doh_connect_thread, connect_nm, &threads[i]); 1311 } 1312 1313 while (atomic_load(&nsends) > 0) { 1314 isc_thread_yield(); 1315 } 1316 1317 isc_nm_stoplistening(listen_sock); 1318 isc_nmsocket_close(&listen_sock); 1319 assert_null(listen_sock); 1320 1321 for (size_t i = 0; i < nthreads; i++) { 1322 isc_thread_join(threads[i], NULL); 1323 } 1324 1325 isc__netmgr_shutdown(connect_nm); 1326 1327 X(total_sends); 1328 X(csends); 1329 X(creads); 1330 X(sreads); 1331 X(ssends); 1332 1333 CHECK_RANGE_HALF(csends); 1334 CHECK_RANGE_HALF(creads); 1335 CHECK_RANGE_HALF(sreads); 1336 CHECK_RANGE_HALF(ssends); 1337 } 1338 1339 ISC_RUN_TEST_IMPL(doh_half_recv_send_POST) { 1340 SKIP_IN_CI; 1341 1342 atomic_store(&POST, true); 1343 doh_half_recv_send(state); 1344 } 1345 1346 ISC_RUN_TEST_IMPL(doh_half_recv_send_GET) { 1347 SKIP_IN_CI; 1348 1349 atomic_store(&POST, false); 1350 doh_half_recv_send(state); 1351 } 1352 1353 ISC_RUN_TEST_IMPL(doh_half_recv_send_POST_TLS) { 1354 SKIP_IN_CI; 1355 1356 atomic_store(&use_TLS, true); 1357 atomic_store(&POST, true); 1358 doh_half_recv_send(state); 1359 } 1360 1361 ISC_RUN_TEST_IMPL(doh_half_recv_send_GET_TLS) { 1362 SKIP_IN_CI; 1363 1364 atomic_store(&use_TLS, true); 1365 atomic_store(&POST, false); 1366 doh_half_recv_send(state); 1367 } 1368 1369 ISC_RUN_TEST_IMPL(doh_half_recv_send_POST_quota) { 1370 SKIP_IN_CI; 1371 1372 atomic_store(&POST, true); 1373 atomic_store(&check_listener_quota, true); 1374 doh_half_recv_send(state); 1375 } 1376 1377 ISC_RUN_TEST_IMPL(doh_half_recv_send_GET_quota) { 1378 SKIP_IN_CI; 1379 1380 atomic_store(&POST, false); 1381 atomic_store(&check_listener_quota, true); 1382 doh_half_recv_send(state); 1383 } 1384 1385 ISC_RUN_TEST_IMPL(doh_half_recv_send_POST_TLS_quota) { 1386 SKIP_IN_CI; 1387 1388 atomic_store(&use_TLS, true); 1389 atomic_store(&POST, true); 1390 atomic_store(&check_listener_quota, true); 1391 doh_half_recv_send(state); 1392 } 1393 1394 ISC_RUN_TEST_IMPL(doh_half_recv_send_GET_TLS_quota) { 1395 SKIP_IN_CI; 1396 1397 atomic_store(&use_TLS, true); 1398 atomic_store(&POST, false); 1399 atomic_store(&check_listener_quota, true); 1400 doh_half_recv_send(state); 1401 } 1402 1403 static void 1404 doh_half_recv_half_send(void **state) { 1405 isc_nm_t **nm = (isc_nm_t **)*state; 1406 isc_nm_t *listen_nm = nm[0]; 1407 isc_nm_t *connect_nm = nm[1]; 1408 isc_result_t result = ISC_R_SUCCESS; 1409 isc_nmsocket_t *listen_sock = NULL; 1410 size_t nthreads = ISC_MAX(ISC_MIN(workers, 32), 1); 1411 isc_thread_t threads[32] = { 0 }; 1412 isc_quota_t *quotap = init_listener_quota(workers); 1413 1414 atomic_store(&total_sends, atomic_load(&total_sends) / 2); 1415 1416 atomic_store(&nsends, atomic_load(&total_sends)); 1417 1418 result = isc_nm_http_endpoints_add(endpoints, ISC_NM_HTTP_DEFAULT_PATH, 1419 doh_receive_request_cb, NULL, 0); 1420 assert_int_equal(result, ISC_R_SUCCESS); 1421 1422 result = isc_nm_listenhttp(listen_nm, &tcp_listen_addr, 0, quotap, 1423 atomic_load(&use_TLS) ? server_tlsctx : NULL, 1424 endpoints, 0, &listen_sock); 1425 assert_int_equal(result, ISC_R_SUCCESS); 1426 1427 for (size_t i = 0; i < nthreads; i++) { 1428 isc_thread_create(doh_connect_thread, connect_nm, &threads[i]); 1429 } 1430 1431 while (atomic_load(&nsends) > 0) { 1432 isc_thread_yield(); 1433 } 1434 1435 isc__netmgr_shutdown(connect_nm); 1436 isc_nm_stoplistening(listen_sock); 1437 isc_nmsocket_close(&listen_sock); 1438 assert_null(listen_sock); 1439 1440 for (size_t i = 0; i < nthreads; i++) { 1441 isc_thread_join(threads[i], NULL); 1442 } 1443 1444 X(total_sends); 1445 X(csends); 1446 X(creads); 1447 X(sreads); 1448 X(ssends); 1449 1450 CHECK_RANGE_HALF(csends); 1451 CHECK_RANGE_HALF(creads); 1452 CHECK_RANGE_HALF(sreads); 1453 CHECK_RANGE_HALF(ssends); 1454 } 1455 1456 ISC_RUN_TEST_IMPL(doh_half_recv_half_send_POST) { 1457 SKIP_IN_CI; 1458 1459 atomic_store(&POST, true); 1460 doh_half_recv_half_send(state); 1461 } 1462 1463 ISC_RUN_TEST_IMPL(doh_half_recv_half_send_GET) { 1464 SKIP_IN_CI; 1465 1466 atomic_store(&POST, false); 1467 doh_half_recv_half_send(state); 1468 } 1469 1470 ISC_RUN_TEST_IMPL(doh_half_recv_half_send_POST_TLS) { 1471 SKIP_IN_CI; 1472 1473 atomic_store(&use_TLS, true); 1474 atomic_store(&POST, true); 1475 doh_half_recv_half_send(state); 1476 } 1477 1478 ISC_RUN_TEST_IMPL(doh_half_recv_half_send_GET_TLS) { 1479 SKIP_IN_CI; 1480 1481 atomic_store(&use_TLS, true); 1482 atomic_store(&POST, false); 1483 doh_half_recv_half_send(state); 1484 } 1485 1486 ISC_RUN_TEST_IMPL(doh_half_recv_half_send_POST_quota) { 1487 SKIP_IN_CI; 1488 1489 atomic_store(&POST, true); 1490 atomic_store(&check_listener_quota, true); 1491 doh_half_recv_half_send(state); 1492 } 1493 1494 ISC_RUN_TEST_IMPL(doh_half_recv_half_send_GET_quota) { 1495 SKIP_IN_CI; 1496 1497 atomic_store(&POST, false); 1498 atomic_store(&check_listener_quota, true); 1499 doh_half_recv_half_send(state); 1500 } 1501 1502 ISC_RUN_TEST_IMPL(doh_half_recv_half_send_POST_TLS_quota) { 1503 SKIP_IN_CI; 1504 1505 atomic_store(&use_TLS, true); 1506 atomic_store(&POST, true); 1507 atomic_store(&check_listener_quota, true); 1508 doh_half_recv_half_send(state); 1509 } 1510 1511 ISC_RUN_TEST_IMPL(doh_half_recv_half_send_GET_TLS_quota) { 1512 SKIP_IN_CI; 1513 1514 atomic_store(&use_TLS, true); 1515 atomic_store(&POST, false); 1516 atomic_store(&check_listener_quota, true); 1517 doh_half_recv_half_send(state); 1518 } 1519 1520 /* See: GL #2858, !5319 */ 1521 ISC_RUN_TEST_IMPL(doh_bad_connect_uri) { 1522 isc_nm_t **nm = (isc_nm_t **)*state; 1523 isc_nm_t *listen_nm = nm[0]; 1524 isc_nm_t *connect_nm = nm[1]; 1525 isc_result_t result = ISC_R_SUCCESS; 1526 isc_nmsocket_t *listen_sock = NULL; 1527 char req_url[256]; 1528 isc_quota_t *quotap = init_listener_quota(workers); 1529 1530 atomic_store(&total_sends, 1); 1531 1532 atomic_store(&nsends, atomic_load(&total_sends)); 1533 1534 result = isc_nm_http_endpoints_add(endpoints, ISC_NM_HTTP_DEFAULT_PATH, 1535 doh_receive_request_cb, NULL, 0); 1536 assert_int_equal(result, ISC_R_SUCCESS); 1537 1538 result = isc_nm_listenhttp(listen_nm, &tcp_listen_addr, 0, quotap, 1539 server_tlsctx, endpoints, 0, &listen_sock); 1540 assert_int_equal(result, ISC_R_SUCCESS); 1541 1542 /* 1543 * "https://::1:XXXX/dns-query" is a bad URI, it should be 1544 * "https://[::1]:XXXX/dns-query" 1545 */ 1546 (void)snprintf(req_url, sizeof(req_url), "https://::1:%u/%s", 1547 isc_sockaddr_getport(&tcp_listen_addr), 1548 ISC_NM_HTTP_DEFAULT_PATH); 1549 connect_send_request(connect_nm, req_url, atomic_load(&POST), 1550 &(isc_region_t){ .base = (uint8_t *)send_msg.base, 1551 .length = send_msg.len }, 1552 doh_receive_reply_cb, NULL, true, 30000); 1553 1554 while (atomic_load(&nsends) > 0) { 1555 if (atomic_load(&was_error)) { 1556 break; 1557 } 1558 isc_thread_yield(); 1559 } 1560 1561 isc_nm_stoplistening(listen_sock); 1562 isc_nmsocket_close(&listen_sock); 1563 assert_null(listen_sock); 1564 isc__netmgr_shutdown(connect_nm); 1565 1566 X(total_sends); 1567 X(csends); 1568 X(creads); 1569 X(sreads); 1570 X(ssends); 1571 1572 /* As we used an ill-formed URI, there ought to be an error. */ 1573 assert_true(atomic_load(&was_error)); 1574 assert_int_equal(atomic_load(&csends), 0); 1575 assert_int_equal(atomic_load(&creads), 0); 1576 assert_int_equal(atomic_load(&sreads), 0); 1577 assert_int_equal(atomic_load(&ssends), 0); 1578 } 1579 1580 ISC_RUN_TEST_IMPL(doh_parse_GET_query_string) { 1581 UNUSED(state); 1582 /* valid */ 1583 { 1584 bool ret; 1585 const char *queryp = NULL; 1586 size_t len = 0; 1587 char str[] = 1588 "dns=AAABAAABAAAAAAAAAWE-" 1589 "NjJjaGFyYWN0ZXJsYWJlbC1tYWtlcy1iYXNlNjR1cmwtZGlzdGluY3" 1590 "QtZnJvbS1zdGFuZGFyZC1iYXNlNjQHZXhhbXBsZQNjb20AAAEAAQ"; 1591 1592 ret = isc__nm_parse_httpquery(str, &queryp, &len); 1593 assert_true(ret); 1594 assert_non_null(queryp); 1595 assert_true(len > 0); 1596 assert_true(len == strlen(str) - 4); 1597 assert_true(memcmp(queryp, str + 4, len) == 0); 1598 } 1599 /* valid */ 1600 { 1601 bool ret; 1602 const char *queryp = NULL; 1603 size_t len = 0; 1604 char str[] = 1605 "?dns=AAABAAABAAAAAAAAAWE-" 1606 "NjJjaGFyYWN0ZXJsYWJlbC1tYWtlcy1iYXNlNjR1cmwtZGlzdGluY3" 1607 "QtZnJvbS1zdGFuZGFyZC1iYXNlNjQHZXhhbXBsZQNjb20AAAEAAQ&"; 1608 1609 ret = isc__nm_parse_httpquery(str, &queryp, &len); 1610 assert_true(ret); 1611 assert_non_null(queryp); 1612 assert_true(len > 0); 1613 assert_true(len == strlen(str) - 6); 1614 assert_true(memcmp(queryp, str + 5, len) == 0); 1615 } 1616 /* valid */ 1617 { 1618 bool ret; 1619 const char *queryp = NULL; 1620 size_t len = 0; 1621 char str[] = "?dns=123&dns=567"; 1622 1623 ret = isc__nm_parse_httpquery(str, &queryp, &len); 1624 assert_true(ret); 1625 assert_non_null(queryp); 1626 assert_true(len > 0); 1627 assert_true(len == 3); 1628 assert_true(memcmp(queryp, "567", 3) == 0); 1629 } 1630 /* valid */ 1631 { 1632 bool ret; 1633 const char *queryp = NULL; 1634 size_t len = 0; 1635 char str[] = "?name1=123&dns=567&name2=123&"; 1636 1637 ret = isc__nm_parse_httpquery(str, &queryp, &len); 1638 assert_true(ret); 1639 assert_non_null(queryp); 1640 assert_true(len > 0); 1641 assert_true(len == 3); 1642 assert_true(memcmp(queryp, "567", 3) == 0); 1643 } 1644 /* complex, but still valid */ 1645 { 1646 bool ret; 1647 const char *queryp = NULL; 1648 size_t len = 0; 1649 char str[] = 1650 "?title=%D0%92%D1%96%D0%B4%D1%81%D0%BE%D1%82%D0%BA%D0%" 1651 "BE%D0%B2%D0%B5_%D0%BA%D0%BE%D0%B4%D1%83%D0%B2%D0%B0%" 1652 "D0%BD%D0%BD%D1%8F&dns=123&veaction=edit§ion=0"; 1653 1654 ret = isc__nm_parse_httpquery(str, &queryp, &len); 1655 assert_true(ret); 1656 assert_non_null(queryp); 1657 assert_true(len > 0); 1658 assert_true(len == 3); 1659 assert_true(memcmp(queryp, "123", 3) == 0); 1660 } 1661 /* invalid */ 1662 { 1663 bool ret; 1664 const char *queryp = NULL; 1665 size_t len = 0; 1666 char str[] = 1667 "?title=%D0%92%D1%96%D0%B4%D1%81%D0%BE%D1%82%D0%BA%D0%" 1668 "BE%D0%B2%D0%B5_%D0%BA%D0%BE%D0%B4%D1%83%D0%B2%D0%B0%" 1669 "D0%BD%D0%BD%D1%8F&veaction=edit§ion=0"; 1670 1671 ret = isc__nm_parse_httpquery(str, &queryp, &len); 1672 assert_false(ret); 1673 assert_null(queryp); 1674 assert_true(len == 0); 1675 } 1676 /* invalid */ 1677 { 1678 bool ret; 1679 const char *queryp = NULL; 1680 size_t len = 0; 1681 char str[] = ""; 1682 1683 ret = isc__nm_parse_httpquery(str, &queryp, &len); 1684 assert_false(ret); 1685 assert_null(queryp); 1686 assert_true(len == 0); 1687 } 1688 /* invalid */ 1689 { 1690 bool ret; 1691 const char *queryp = NULL; 1692 size_t len = 0; 1693 char str[] = "?&"; 1694 1695 ret = isc__nm_parse_httpquery(str, &queryp, &len); 1696 assert_false(ret); 1697 assert_null(queryp); 1698 assert_true(len == 0); 1699 } 1700 /* invalid */ 1701 { 1702 bool ret; 1703 const char *queryp = NULL; 1704 size_t len = 0; 1705 char str[] = "?dns&"; 1706 1707 ret = isc__nm_parse_httpquery(str, &queryp, &len); 1708 assert_false(ret); 1709 assert_null(queryp); 1710 assert_true(len == 0); 1711 } 1712 /* invalid */ 1713 { 1714 bool ret; 1715 const char *queryp = NULL; 1716 size_t len = 0; 1717 char str[] = "?dns=&"; 1718 1719 ret = isc__nm_parse_httpquery(str, &queryp, &len); 1720 assert_false(ret); 1721 assert_null(queryp); 1722 assert_true(len == 0); 1723 } 1724 /* invalid */ 1725 { 1726 bool ret; 1727 const char *queryp = NULL; 1728 size_t len = 0; 1729 char str[] = "?dns=123&&"; 1730 1731 ret = isc__nm_parse_httpquery(str, &queryp, &len); 1732 assert_false(ret); 1733 assert_null(queryp); 1734 assert_true(len == 0); 1735 } 1736 /* valid */ 1737 { 1738 bool ret; 1739 const char *queryp = NULL; 1740 size_t len = 0; 1741 char str[] = "?dns=123%12&"; 1742 1743 ret = isc__nm_parse_httpquery(str, &queryp, &len); 1744 assert_true(ret); 1745 assert_non_null(queryp); 1746 assert_true(len > 0); 1747 assert_true(len == 6); 1748 assert_true(memcmp(queryp, "123%12", 6) == 0); 1749 } 1750 /* invalid */ 1751 { 1752 bool ret; 1753 const char *queryp = NULL; 1754 size_t len = 0; 1755 char str[] = "?dns=123%ZZ&"; 1756 1757 ret = isc__nm_parse_httpquery(str, &queryp, &len); 1758 assert_false(ret); 1759 assert_null(queryp); 1760 assert_true(len == 0); 1761 } 1762 /* invalid */ 1763 { 1764 bool ret; 1765 const char *queryp = NULL; 1766 size_t len = 0; 1767 char str[] = "?dns=123%%&"; 1768 1769 ret = isc__nm_parse_httpquery(str, &queryp, &len); 1770 assert_false(ret); 1771 assert_null(queryp); 1772 assert_true(len == 0); 1773 } 1774 /* invalid */ 1775 { 1776 bool ret; 1777 const char *queryp = NULL; 1778 size_t len = 0; 1779 char str[] = "?dns=123%AZ&"; 1780 1781 ret = isc__nm_parse_httpquery(str, &queryp, &len); 1782 assert_false(ret); 1783 assert_null(queryp); 1784 assert_true(len == 0); 1785 } 1786 /* valid */ 1787 { 1788 bool ret; 1789 const char *queryp = NULL; 1790 size_t len = 0; 1791 char str[] = "?dns=123%0AZ&"; 1792 1793 ret = isc__nm_parse_httpquery(str, &queryp, &len); 1794 assert_true(ret); 1795 assert_non_null(queryp); 1796 assert_true(len > 0); 1797 assert_true(len == 7); 1798 assert_true(memcmp(queryp, "123%0AZ", 7) == 0); 1799 } 1800 } 1801 1802 ISC_RUN_TEST_IMPL(doh_base64url_to_base64) { 1803 UNUSED(state); 1804 char *res; 1805 size_t res_len = 0; 1806 /* valid */ 1807 { 1808 char test[] = "YW55IGNhcm5hbCBwbGVhc3VyZS4"; 1809 char res_test[] = "YW55IGNhcm5hbCBwbGVhc3VyZS4="; 1810 1811 res = isc__nm_base64url_to_base64(mctx, test, strlen(test), 1812 &res_len); 1813 assert_non_null(res); 1814 assert_true(res_len == strlen(res_test)); 1815 assert_true(strcmp(res, res_test) == 0); 1816 isc_mem_free(mctx, res); 1817 } 1818 /* valid */ 1819 { 1820 char test[] = "YW55IGNhcm5hbCBwbGVhcw"; 1821 char res_test[] = "YW55IGNhcm5hbCBwbGVhcw=="; 1822 1823 res = isc__nm_base64url_to_base64(mctx, test, strlen(test), 1824 &res_len); 1825 assert_non_null(res); 1826 assert_true(res_len == strlen(res_test)); 1827 assert_true(strcmp(res, res_test) == 0); 1828 isc_mem_free(mctx, res); 1829 } 1830 /* valid */ 1831 { 1832 char test[] = "YW55IGNhcm5hbCBwbGVhc3Vy"; 1833 char res_test[] = "YW55IGNhcm5hbCBwbGVhc3Vy"; 1834 1835 res = isc__nm_base64url_to_base64(mctx, test, strlen(test), 1836 &res_len); 1837 assert_non_null(res); 1838 assert_true(res_len == strlen(res_test)); 1839 assert_true(strcmp(res, res_test) == 0); 1840 isc_mem_free(mctx, res); 1841 } 1842 /* valid */ 1843 { 1844 char test[] = "YW55IGNhcm5hbCBwbGVhc3U"; 1845 char res_test[] = "YW55IGNhcm5hbCBwbGVhc3U="; 1846 1847 res = isc__nm_base64url_to_base64(mctx, test, strlen(test), 1848 &res_len); 1849 assert_non_null(res); 1850 assert_true(res_len == strlen(res_test)); 1851 assert_true(strcmp(res, res_test) == 0); 1852 isc_mem_free(mctx, res); 1853 } 1854 /* valid */ 1855 { 1856 char test[] = "YW55IGNhcm5hbCBwbGVhcw"; 1857 char res_test[] = "YW55IGNhcm5hbCBwbGVhcw=="; 1858 1859 res = isc__nm_base64url_to_base64(mctx, test, strlen(test), 1860 &res_len); 1861 assert_non_null(res); 1862 assert_true(res_len == strlen(res_test)); 1863 assert_true(strcmp(res, res_test) == 0); 1864 isc_mem_free(mctx, res); 1865 } 1866 /* valid */ 1867 { 1868 char test[] = "PDw_Pz8-Pg"; 1869 char res_test[] = "PDw/Pz8+Pg=="; 1870 1871 res = isc__nm_base64url_to_base64(mctx, test, strlen(test), 1872 &res_len); 1873 assert_non_null(res); 1874 assert_true(res_len == strlen(res_test)); 1875 assert_true(strcmp(res, res_test) == 0); 1876 isc_mem_free(mctx, res); 1877 } 1878 /* valid */ 1879 { 1880 char test[] = "PDw_Pz8-Pg"; 1881 char res_test[] = "PDw/Pz8+Pg=="; 1882 1883 res = isc__nm_base64url_to_base64(mctx, test, strlen(test), 1884 NULL); 1885 assert_non_null(res); 1886 assert_true(strcmp(res, res_test) == 0); 1887 isc_mem_free(mctx, res); 1888 } 1889 /* invalid */ 1890 { 1891 char test[] = "YW55IGNhcm5hbCBwbGVhcw"; 1892 res_len = 0; 1893 1894 res = isc__nm_base64url_to_base64(mctx, test, 0, &res_len); 1895 assert_null(res); 1896 assert_true(res_len == 0); 1897 } 1898 /* invalid */ 1899 { 1900 char test[] = ""; 1901 res_len = 0; 1902 1903 res = isc__nm_base64url_to_base64(mctx, test, strlen(test), 1904 &res_len); 1905 assert_null(res); 1906 assert_true(res_len == 0); 1907 } 1908 /* invalid */ 1909 { 1910 char test[] = "PDw_Pz8-Pg=="; 1911 res_len = 0; 1912 1913 res = isc__nm_base64url_to_base64(mctx, test, strlen(test), 1914 &res_len); 1915 assert_null(res); 1916 assert_true(res_len == 0); 1917 } 1918 /* invalid */ 1919 { 1920 char test[] = "PDw_Pz8-Pg%3D%3D"; /* percent encoded "==" at the 1921 end */ 1922 res_len = 0; 1923 1924 res = isc__nm_base64url_to_base64(mctx, test, strlen(test), 1925 &res_len); 1926 assert_null(res); 1927 assert_true(res_len == 0); 1928 } 1929 /* invalid */ 1930 { 1931 res_len = 0; 1932 1933 res = isc__nm_base64url_to_base64(mctx, NULL, 31231, &res_len); 1934 assert_null(res); 1935 assert_true(res_len == 0); 1936 } 1937 } 1938 1939 ISC_RUN_TEST_IMPL(doh_base64_to_base64url) { 1940 char *res; 1941 size_t res_len = 0; 1942 UNUSED(state); 1943 /* valid */ 1944 { 1945 char res_test[] = "YW55IGNhcm5hbCBwbGVhc3VyZS4"; 1946 char test[] = "YW55IGNhcm5hbCBwbGVhc3VyZS4="; 1947 1948 res = isc__nm_base64_to_base64url(mctx, test, strlen(test), 1949 &res_len); 1950 assert_non_null(res); 1951 assert_true(res_len == strlen(res_test)); 1952 assert_true(strcmp(res, res_test) == 0); 1953 isc_mem_free(mctx, res); 1954 } 1955 /* valid */ 1956 { 1957 char res_test[] = "YW55IGNhcm5hbCBwbGVhcw"; 1958 char test[] = "YW55IGNhcm5hbCBwbGVhcw=="; 1959 1960 res = isc__nm_base64_to_base64url(mctx, test, strlen(test), 1961 &res_len); 1962 assert_non_null(res); 1963 assert_true(res_len == strlen(res_test)); 1964 assert_true(strcmp(res, res_test) == 0); 1965 isc_mem_free(mctx, res); 1966 } 1967 /* valid */ 1968 { 1969 char res_test[] = "YW55IGNhcm5hbCBwbGVhc3Vy"; 1970 char test[] = "YW55IGNhcm5hbCBwbGVhc3Vy"; 1971 1972 res = isc__nm_base64_to_base64url(mctx, test, strlen(test), 1973 &res_len); 1974 assert_non_null(res); 1975 assert_true(res_len == strlen(res_test)); 1976 assert_true(strcmp(res, res_test) == 0); 1977 isc_mem_free(mctx, res); 1978 } 1979 /* valid */ 1980 { 1981 char res_test[] = "YW55IGNhcm5hbCBwbGVhc3U"; 1982 char test[] = "YW55IGNhcm5hbCBwbGVhc3U="; 1983 1984 res = isc__nm_base64_to_base64url(mctx, test, strlen(test), 1985 &res_len); 1986 assert_non_null(res); 1987 assert_true(res_len == strlen(res_test)); 1988 assert_true(strcmp(res, res_test) == 0); 1989 isc_mem_free(mctx, res); 1990 } 1991 /* valid */ 1992 { 1993 char res_test[] = "YW55IGNhcm5hbCBwbGVhcw"; 1994 char test[] = "YW55IGNhcm5hbCBwbGVhcw=="; 1995 1996 res = isc__nm_base64_to_base64url(mctx, test, strlen(test), 1997 &res_len); 1998 assert_non_null(res); 1999 assert_true(res_len == strlen(res_test)); 2000 assert_true(strcmp(res, res_test) == 0); 2001 isc_mem_free(mctx, res); 2002 } 2003 /* valid */ 2004 { 2005 char res_test[] = "PDw_Pz8-Pg"; 2006 char test[] = "PDw/Pz8+Pg=="; 2007 2008 res = isc__nm_base64_to_base64url(mctx, test, strlen(test), 2009 &res_len); 2010 assert_non_null(res); 2011 assert_true(res_len == strlen(res_test)); 2012 assert_true(strcmp(res, res_test) == 0); 2013 isc_mem_free(mctx, res); 2014 } 2015 /* valid */ 2016 { 2017 char res_test[] = "PDw_Pz8-Pg"; 2018 char test[] = "PDw/Pz8+Pg=="; 2019 2020 res = isc__nm_base64_to_base64url(mctx, test, strlen(test), 2021 NULL); 2022 assert_non_null(res); 2023 assert_true(strcmp(res, res_test) == 0); 2024 isc_mem_free(mctx, res); 2025 } 2026 /* invalid */ 2027 { 2028 char test[] = "YW55IGNhcm5hbCBwbGVhcw"; 2029 res_len = 0; 2030 2031 res = isc__nm_base64_to_base64url(mctx, test, 0, &res_len); 2032 assert_null(res); 2033 assert_true(res_len == 0); 2034 } 2035 /* invalid */ 2036 { 2037 char test[] = ""; 2038 res_len = 0; 2039 2040 res = isc__nm_base64_to_base64url(mctx, test, strlen(test), 2041 &res_len); 2042 assert_null(res); 2043 assert_true(res_len == 0); 2044 } 2045 /* invalid */ 2046 { 2047 char test[] = "PDw_Pz8-Pg=="; 2048 res_len = 0; 2049 2050 res = isc__nm_base64_to_base64url(mctx, test, strlen(test), 2051 &res_len); 2052 assert_null(res); 2053 assert_true(res_len == 0); 2054 } 2055 /* invalid */ 2056 { 2057 char test[] = "PDw_Pz8-Pg%3D%3D"; /* percent encoded "==" at the 2058 end */ 2059 res_len = 0; 2060 2061 res = isc__nm_base64_to_base64url(mctx, test, strlen(test), 2062 &res_len); 2063 assert_null(res); 2064 assert_true(res_len == 0); 2065 } 2066 /* invalid */ 2067 { 2068 res_len = 0; 2069 2070 res = isc__nm_base64_to_base64url(mctx, NULL, 31231, &res_len); 2071 assert_null(res); 2072 assert_true(res_len == 0); 2073 } 2074 } 2075 2076 ISC_RUN_TEST_IMPL(doh_path_validation) { 2077 UNUSED(state); 2078 2079 assert_true(isc_nm_http_path_isvalid("/")); 2080 assert_true(isc_nm_http_path_isvalid(ISC_NM_HTTP_DEFAULT_PATH)); 2081 assert_false(isc_nm_http_path_isvalid("laaaa")); 2082 assert_false(isc_nm_http_path_isvalid("")); 2083 assert_false(isc_nm_http_path_isvalid("//")); 2084 assert_true(isc_nm_http_path_isvalid("/lala///")); 2085 assert_true(isc_nm_http_path_isvalid("/lalaaaaaa")); 2086 assert_true(isc_nm_http_path_isvalid("/lalaaa/la/la/la")); 2087 assert_true(isc_nm_http_path_isvalid("/la/a")); 2088 assert_true(isc_nm_http_path_isvalid("/la+la")); 2089 assert_true(isc_nm_http_path_isvalid("/la&la/la*la/l-a_/la!/la\'")); 2090 assert_true(isc_nm_http_path_isvalid("/la/(la)/la")); 2091 assert_true(isc_nm_http_path_isvalid("/la,la,la")); 2092 assert_true(isc_nm_http_path_isvalid("/la-'la'-la")); 2093 assert_true(isc_nm_http_path_isvalid("/la:la=la")); 2094 assert_true(isc_nm_http_path_isvalid("/l@l@l@")); 2095 assert_false(isc_nm_http_path_isvalid("/#lala")); 2096 assert_true(isc_nm_http_path_isvalid("/lala;la")); 2097 assert_false( 2098 isc_nm_http_path_isvalid("la&la/laalaala*lala/l-al_a/lal!/")); 2099 assert_true(isc_nm_http_path_isvalid("/Lal/lAla.jpg")); 2100 2101 /* had to replace ? with ! because it does not verify a query string */ 2102 assert_true(isc_nm_http_path_isvalid("/watch!v=oavMtUWDBTM")); 2103 assert_false(isc_nm_http_path_isvalid("/watch?v=dQw4w9WgXcQ")); 2104 assert_true(isc_nm_http_path_isvalid("/datatracker.ietf.org/doc/html/" 2105 "rfc2616")); 2106 assert_true(isc_nm_http_path_isvalid("/doc/html/rfc8484")); 2107 assert_true(isc_nm_http_path_isvalid("/123")); 2108 } 2109 2110 ISC_RUN_TEST_IMPL(doh_connect_makeuri) { 2111 struct in_addr localhostv4 = { .s_addr = ntohl(INADDR_LOOPBACK) }; 2112 isc_sockaddr_t sa; 2113 char uri[256]; 2114 UNUSED(state); 2115 2116 /* Firstly, test URI generation using isc_sockaddr_t */ 2117 isc_sockaddr_fromin(&sa, &localhostv4, 0); 2118 uri[0] = '\0'; 2119 isc_nm_http_makeuri(true, &sa, NULL, 0, ISC_NM_HTTP_DEFAULT_PATH, uri, 2120 sizeof(uri)); 2121 assert_true(strcmp("https://127.0.0.1:443/dns-query", uri) == 0); 2122 2123 uri[0] = '\0'; 2124 isc_nm_http_makeuri(false, &sa, NULL, 0, ISC_NM_HTTP_DEFAULT_PATH, uri, 2125 sizeof(uri)); 2126 assert_true(strcmp("http://127.0.0.1:80/dns-query", uri) == 0); 2127 2128 /* 2129 * The port value should be ignored, because we can get one from 2130 * the isc_sockaddr_t object. 2131 */ 2132 uri[0] = '\0'; 2133 isc_nm_http_makeuri(true, &sa, NULL, 44343, ISC_NM_HTTP_DEFAULT_PATH, 2134 uri, sizeof(uri)); 2135 assert_true(strcmp("https://127.0.0.1:443/dns-query", uri) == 0); 2136 2137 uri[0] = '\0'; 2138 isc_nm_http_makeuri(false, &sa, NULL, 8080, ISC_NM_HTTP_DEFAULT_PATH, 2139 uri, sizeof(uri)); 2140 assert_true(strcmp("http://127.0.0.1:80/dns-query", uri) == 0); 2141 2142 /* IPv6 */ 2143 isc_sockaddr_fromin6(&sa, &in6addr_loopback, 0); 2144 uri[0] = '\0'; 2145 isc_nm_http_makeuri(true, &sa, NULL, 0, ISC_NM_HTTP_DEFAULT_PATH, uri, 2146 sizeof(uri)); 2147 assert_true(strcmp("https://[::1]:443/dns-query", uri) == 0); 2148 2149 uri[0] = '\0'; 2150 isc_nm_http_makeuri(false, &sa, NULL, 0, ISC_NM_HTTP_DEFAULT_PATH, uri, 2151 sizeof(uri)); 2152 assert_true(strcmp("http://[::1]:80/dns-query", uri) == 0); 2153 2154 /* 2155 * The port value should be ignored, because we can get one from 2156 * the isc_sockaddr_t object. 2157 */ 2158 uri[0] = '\0'; 2159 isc_nm_http_makeuri(true, &sa, NULL, 44343, ISC_NM_HTTP_DEFAULT_PATH, 2160 uri, sizeof(uri)); 2161 assert_true(strcmp("https://[::1]:443/dns-query", uri) == 0); 2162 2163 uri[0] = '\0'; 2164 isc_nm_http_makeuri(false, &sa, NULL, 8080, ISC_NM_HTTP_DEFAULT_PATH, 2165 uri, sizeof(uri)); 2166 assert_true(strcmp("http://[::1]:80/dns-query", uri) == 0); 2167 2168 /* Try to set the port numbers. */ 2169 isc_sockaddr_setport(&sa, 44343); 2170 uri[0] = '\0'; 2171 isc_nm_http_makeuri(true, &sa, NULL, 0, ISC_NM_HTTP_DEFAULT_PATH, uri, 2172 sizeof(uri)); 2173 assert_true(strcmp("https://[::1]:44343/dns-query", uri) == 0); 2174 2175 isc_sockaddr_setport(&sa, 8080); 2176 uri[0] = '\0'; 2177 isc_nm_http_makeuri(false, &sa, NULL, 0, ISC_NM_HTTP_DEFAULT_PATH, uri, 2178 sizeof(uri)); 2179 assert_true(strcmp("http://[::1]:8080/dns-query", uri) == 0); 2180 2181 /* 2182 * Try to make a URI using a hostname and a port number. The 2183 * isc_sockaddr_t object will be ignored. 2184 */ 2185 isc_sockaddr_any(&sa); 2186 uri[0] = '\0'; 2187 isc_nm_http_makeuri(true, &sa, "example.com", 0, 2188 ISC_NM_HTTP_DEFAULT_PATH, uri, sizeof(uri)); 2189 assert_true(strcmp("https://example.com:443/dns-query", uri) == 0); 2190 2191 uri[0] = '\0'; 2192 isc_nm_http_makeuri(false, &sa, "example.com", 0, 2193 ISC_NM_HTTP_DEFAULT_PATH, uri, sizeof(uri)); 2194 assert_true(strcmp("http://example.com:80/dns-query", uri) == 0); 2195 2196 /* Try to set the port numbers. */ 2197 isc_sockaddr_setport(&sa, 443); 2198 uri[0] = '\0'; 2199 isc_nm_http_makeuri(true, &sa, "example.com", 44343, 2200 ISC_NM_HTTP_DEFAULT_PATH, uri, sizeof(uri)); 2201 assert_true(strcmp("https://example.com:44343/dns-query", uri) == 0); 2202 2203 isc_sockaddr_setport(&sa, 80); 2204 uri[0] = '\0'; 2205 isc_nm_http_makeuri(false, &sa, "example.com", 8080, 2206 ISC_NM_HTTP_DEFAULT_PATH, uri, sizeof(uri)); 2207 assert_true(strcmp("http://example.com:8080/dns-query", uri) == 0); 2208 2209 /* IPv4 as the hostname - nothing fancy here */ 2210 uri[0] = '\0'; 2211 isc_nm_http_makeuri(false, NULL, "127.0.0.1", 8080, 2212 ISC_NM_HTTP_DEFAULT_PATH, uri, sizeof(uri)); 2213 assert_true(strcmp("http://127.0.0.1:8080/dns-query", uri) == 0); 2214 2215 uri[0] = '\0'; 2216 isc_nm_http_makeuri(true, NULL, "127.0.0.1", 44343, 2217 ISC_NM_HTTP_DEFAULT_PATH, uri, sizeof(uri)); 2218 assert_true(strcmp("https://127.0.0.1:44343/dns-query", uri) == 0); 2219 2220 /* 2221 * A peculiar edge case: IPv6 given as the hostname (notice 2222 * the brackets) 2223 */ 2224 uri[0] = '\0'; 2225 isc_nm_http_makeuri(false, NULL, "::1", 8080, ISC_NM_HTTP_DEFAULT_PATH, 2226 uri, sizeof(uri)); 2227 assert_true(strcmp("http://[::1]:8080/dns-query", uri) == 0); 2228 2229 uri[0] = '\0'; 2230 isc_nm_http_makeuri(true, NULL, "[::1]", 44343, 2231 ISC_NM_HTTP_DEFAULT_PATH, uri, sizeof(uri)); 2232 assert_true(strcmp("https://[::1]:44343/dns-query", uri) == 0); 2233 } 2234 2235 ISC_TEST_LIST_START 2236 ISC_TEST_ENTRY_CUSTOM(mock_doh_uv_tcp_bind, setup_test, teardown_test) 2237 ISC_TEST_ENTRY(doh_parse_GET_query_string) 2238 ISC_TEST_ENTRY(doh_base64url_to_base64) 2239 ISC_TEST_ENTRY(doh_base64_to_base64url) 2240 ISC_TEST_ENTRY(doh_path_validation) 2241 ISC_TEST_ENTRY(doh_connect_makeuri) 2242 ISC_TEST_ENTRY_CUSTOM(doh_noop_POST, setup_test, teardown_test) 2243 ISC_TEST_ENTRY_CUSTOM(doh_noop_GET, setup_test, teardown_test) 2244 ISC_TEST_ENTRY_CUSTOM(doh_noresponse_POST, setup_test, teardown_test) 2245 ISC_TEST_ENTRY_CUSTOM(doh_noresponse_GET, setup_test, teardown_test) 2246 ISC_TEST_ENTRY_CUSTOM(doh_timeout_recovery_POST, setup_test, teardown_test) 2247 ISC_TEST_ENTRY_CUSTOM(doh_timeout_recovery_GET, setup_test, teardown_test) 2248 ISC_TEST_ENTRY_CUSTOM(doh_recv_one_POST, setup_test, teardown_test) 2249 ISC_TEST_ENTRY_CUSTOM(doh_recv_one_GET, setup_test, teardown_test) 2250 ISC_TEST_ENTRY_CUSTOM(doh_recv_one_POST_TLS, setup_test, teardown_test) 2251 ISC_TEST_ENTRY_CUSTOM(doh_recv_one_GET_TLS, setup_test, teardown_test) 2252 ISC_TEST_ENTRY_CUSTOM(doh_recv_one_POST_quota, setup_test, teardown_test) 2253 ISC_TEST_ENTRY_CUSTOM(doh_recv_one_GET_quota, setup_test, teardown_test) 2254 ISC_TEST_ENTRY_CUSTOM(doh_recv_one_POST_TLS_quota, setup_test, teardown_test) 2255 ISC_TEST_ENTRY_CUSTOM(doh_recv_one_GET_TLS_quota, setup_test, teardown_test) 2256 ISC_TEST_ENTRY_CUSTOM(doh_recv_two_POST, setup_test, teardown_test) 2257 ISC_TEST_ENTRY_CUSTOM(doh_recv_two_GET, setup_test, teardown_test) 2258 ISC_TEST_ENTRY_CUSTOM(doh_recv_two_POST_TLS, setup_test, teardown_test) 2259 ISC_TEST_ENTRY_CUSTOM(doh_recv_two_GET_TLS, setup_test, teardown_test) 2260 ISC_TEST_ENTRY_CUSTOM(doh_recv_two_POST_quota, setup_test, teardown_test) 2261 ISC_TEST_ENTRY_CUSTOM(doh_recv_two_GET_quota, setup_test, teardown_test) 2262 ISC_TEST_ENTRY_CUSTOM(doh_recv_two_POST_TLS_quota, setup_test, teardown_test) 2263 ISC_TEST_ENTRY_CUSTOM(doh_recv_two_GET_TLS_quota, setup_test, teardown_test) 2264 ISC_TEST_ENTRY_CUSTOM(doh_recv_send_GET, setup_test, teardown_test) 2265 ISC_TEST_ENTRY_CUSTOM(doh_recv_send_POST, setup_test, teardown_test) 2266 ISC_TEST_ENTRY_CUSTOM(doh_recv_send_GET_TLS, setup_test, teardown_test) 2267 ISC_TEST_ENTRY_CUSTOM(doh_recv_send_POST_TLS, setup_test, teardown_test) 2268 ISC_TEST_ENTRY_CUSTOM(doh_recv_send_GET_quota, setup_test, teardown_test) 2269 ISC_TEST_ENTRY_CUSTOM(doh_recv_send_POST_quota, setup_test, teardown_test) 2270 ISC_TEST_ENTRY_CUSTOM(doh_recv_send_GET_TLS_quota, setup_test, teardown_test) 2271 ISC_TEST_ENTRY_CUSTOM(doh_recv_send_POST_TLS_quota, setup_test, teardown_test) 2272 ISC_TEST_ENTRY_CUSTOM(doh_recv_half_send_GET, setup_test, teardown_test) 2273 ISC_TEST_ENTRY_CUSTOM(doh_recv_half_send_POST, setup_test, teardown_test) 2274 ISC_TEST_ENTRY_CUSTOM(doh_recv_half_send_GET_TLS, setup_test, teardown_test) 2275 ISC_TEST_ENTRY_CUSTOM(doh_recv_half_send_POST_TLS, setup_test, teardown_test) 2276 ISC_TEST_ENTRY_CUSTOM(doh_recv_half_send_GET_quota, setup_test, teardown_test) 2277 ISC_TEST_ENTRY_CUSTOM(doh_recv_half_send_POST_quota, setup_test, teardown_test) 2278 ISC_TEST_ENTRY_CUSTOM(doh_recv_half_send_GET_TLS_quota, setup_test, 2279 teardown_test) 2280 ISC_TEST_ENTRY_CUSTOM(doh_recv_half_send_POST_TLS_quota, setup_test, 2281 teardown_test) 2282 ISC_TEST_ENTRY_CUSTOM(doh_half_recv_send_GET, setup_test, teardown_test) 2283 ISC_TEST_ENTRY_CUSTOM(doh_half_recv_send_POST, setup_test, teardown_test) 2284 ISC_TEST_ENTRY_CUSTOM(doh_half_recv_send_GET_TLS, setup_test, teardown_test) 2285 ISC_TEST_ENTRY_CUSTOM(doh_half_recv_send_POST_TLS, setup_test, teardown_test) 2286 ISC_TEST_ENTRY_CUSTOM(doh_half_recv_send_GET_quota, setup_test, teardown_test) 2287 ISC_TEST_ENTRY_CUSTOM(doh_half_recv_send_POST_quota, setup_test, teardown_test) 2288 ISC_TEST_ENTRY_CUSTOM(doh_half_recv_send_GET_TLS_quota, setup_test, 2289 teardown_test) 2290 ISC_TEST_ENTRY_CUSTOM(doh_half_recv_send_POST_TLS_quota, setup_test, 2291 teardown_test) 2292 ISC_TEST_ENTRY_CUSTOM(doh_half_recv_half_send_GET, setup_test, teardown_test) 2293 ISC_TEST_ENTRY_CUSTOM(doh_half_recv_half_send_POST, setup_test, teardown_test) 2294 ISC_TEST_ENTRY_CUSTOM(doh_half_recv_half_send_GET_TLS, setup_test, 2295 teardown_test) 2296 ISC_TEST_ENTRY_CUSTOM(doh_half_recv_half_send_POST_TLS, setup_test, 2297 teardown_test) 2298 ISC_TEST_ENTRY_CUSTOM(doh_half_recv_half_send_GET_quota, setup_test, 2299 teardown_test) 2300 ISC_TEST_ENTRY_CUSTOM(doh_half_recv_half_send_POST_quota, setup_test, 2301 teardown_test) 2302 ISC_TEST_ENTRY_CUSTOM(doh_half_recv_half_send_GET_TLS_quota, setup_test, 2303 teardown_test) 2304 ISC_TEST_ENTRY_CUSTOM(doh_half_recv_half_send_POST_TLS_quota, setup_test, 2305 teardown_test) 2306 ISC_TEST_ENTRY_CUSTOM(doh_bad_connect_uri, setup_test, teardown_test) 2307 ISC_TEST_LIST_END 2308 2309 ISC_TEST_MAIN 2310