test_dns.c (22856B)
1 /* Copyright (c) 2015-2021, The Tor Project, Inc. */ 2 /* See LICENSE for licensing information */ 3 4 #include "orconfig.h" 5 #include "core/or/or.h" 6 #include "test/test.h" 7 8 #define DNS_PRIVATE 9 10 #include "feature/relay/dns.h" 11 #include "core/mainloop/connection.h" 12 #include "core/or/connection_edge.h" 13 #include "feature/relay/router.h" 14 15 #include "core/or/edge_connection_st.h" 16 #include "core/or/or_circuit_st.h" 17 #include "app/config/or_options_st.h" 18 #include "app/config/config.h" 19 20 #include <event2/event.h> 21 #include <event2/dns.h> 22 23 #ifdef HAVE_EVDNS_BASE_GET_NAMESERVER_ADDR 24 25 static or_options_t options = { 26 .ORPort_set = 1, 27 }; 28 29 static const or_options_t * 30 mock_get_options(void) 31 { 32 return &options; 33 } 34 35 static void 36 test_dns_configure_ns_fallback(void *arg) 37 { 38 (void)arg; 39 tor_addr_t *nameserver_addr = NULL; 40 41 MOCK(get_options, mock_get_options); 42 43 options.ServerDNSResolvConfFile = (char *)"no_such_file!!!"; 44 45 dns_init(); // calls configure_nameservers() 46 47 tt_int_op(number_of_configured_nameservers(), OP_EQ, 1); 48 49 nameserver_addr = configured_nameserver_address(0); 50 51 tt_assert(tor_addr_family(nameserver_addr) == AF_INET); 52 tt_assert(tor_addr_eq_ipv4h(nameserver_addr, 0x7f000001)); 53 54 #ifndef _WIN32 55 tor_free(nameserver_addr); 56 57 options.ServerDNSResolvConfFile = (char *)"/dev/null"; 58 59 dns_init(); 60 61 tt_int_op(number_of_configured_nameservers(), OP_EQ, 1); 62 63 nameserver_addr = configured_nameserver_address(0); 64 65 tt_assert(tor_addr_family(nameserver_addr) == AF_INET); 66 tt_assert(tor_addr_eq_ipv4h(nameserver_addr, 0x7f000001)); 67 #endif /* !defined(_WIN32) */ 68 69 UNMOCK(get_options); 70 71 done: 72 tor_free(nameserver_addr); 73 return; 74 } 75 76 #endif /* defined(HAVE_EVDNS_BASE_GET_NAMESERVER_ADDR) */ 77 78 static void 79 test_dns_clip_ttl(void *arg) 80 { 81 (void)arg; 82 83 uint32_t ttl_mid = MIN_DNS_TTL / 2 + MAX_DNS_TTL / 2; 84 85 tt_int_op(clip_dns_ttl(MIN_DNS_TTL - 1),OP_EQ,MIN_DNS_TTL); 86 tt_int_op(clip_dns_ttl(ttl_mid),OP_EQ,MAX_DNS_TTL); 87 tt_int_op(clip_dns_ttl(MAX_DNS_TTL + 1),OP_EQ,MAX_DNS_TTL); 88 89 done: 90 return; 91 } 92 93 static void 94 test_dns_clip_fuzzy_ttl(void *arg) 95 { 96 (void)arg; 97 98 /* Case 0: check that the fuzzy TTL constant is valid 99 */ 100 tt_int_op(FUZZY_DNS_TTL, OP_LE, MIN_DNS_TTL); 101 tt_int_op(FUZZY_DNS_TTL, OP_LE, MAX_DNS_TTL); 102 103 /* Case 1: low clips 104 */ 105 for (int i = 0; i < 1024; i++) { 106 int fuzzy_ttl = clip_dns_fuzzy_ttl(MIN_DNS_TTL - 1); 107 tt_int_op(fuzzy_ttl, OP_GE, MIN_DNS_TTL-FUZZY_DNS_TTL); 108 tt_int_op(fuzzy_ttl, OP_LE, MIN_DNS_TTL+FUZZY_DNS_TTL); 109 } 110 111 /* Case 2: high clips 112 */ 113 for (int i = 0; i < 1024; i++) { 114 int fuzzy_ttl = clip_dns_fuzzy_ttl(MIN_DNS_TTL); 115 tt_int_op(fuzzy_ttl, OP_GE, MAX_DNS_TTL-FUZZY_DNS_TTL); 116 tt_int_op(fuzzy_ttl, OP_LE, MAX_DNS_TTL+FUZZY_DNS_TTL); 117 } 118 119 done: 120 return; 121 } 122 123 static int resolve_retval = 0; 124 static int resolve_made_conn_pending = 0; 125 static char *resolved_name = NULL; 126 static cached_resolve_t *cache_entry_mock = NULL; 127 128 static int n_fake_impl = 0; 129 130 static int dns_resolve_dns_resolve_impl(edge_connection_t *exitconn, 131 int is_resolve, or_circuit_t *oncirc, 132 char **hostname_out, int *made_connection_pending_out, 133 cached_resolve_t **resolve_out); 134 ATTR_UNUSED static int dns_resolve_dns_resolve_impl_called = 0; 135 136 /** This will be our configurable substitute for <b>dns_resolve_impl</b> in 137 * dns.c. It will return <b>resolve_retval</b>, 138 * and set <b>resolve_made_conn_pending</b> to 139 * <b>made_connection_pending_out</b>. It will set <b>hostname_out</b> 140 * to a duplicate of <b>resolved_name</b> and it will set <b>resolve_out</b> 141 * to <b>cache_entry</b>. Lastly, it will increment <b>n_fake_impl</b< by 142 * 1. 143 */ 144 static int 145 dns_resolve_dns_resolve_impl(edge_connection_t *exitconn, int is_resolve, 146 or_circuit_t *oncirc, char **hostname_out, 147 int *made_connection_pending_out, 148 cached_resolve_t **resolve_out) 149 { 150 (void)oncirc; 151 (void)exitconn; 152 (void)is_resolve; 153 154 if (made_connection_pending_out) 155 *made_connection_pending_out = resolve_made_conn_pending; 156 157 if (hostname_out && resolved_name) 158 *hostname_out = tor_strdup(resolved_name); 159 160 if (resolve_out && cache_entry_mock) 161 *resolve_out = cache_entry_mock; 162 163 n_fake_impl++; 164 165 return resolve_retval; 166 } 167 168 static edge_connection_t *conn_for_resolved_cell = NULL; 169 170 static int n_send_resolved_cell_replacement = 0; 171 static uint8_t last_answer_type = 0; 172 static cached_resolve_t *last_resolved; 173 174 static void 175 dns_resolve_send_resolved_cell(edge_connection_t *conn, uint8_t answer_type, 176 const cached_resolve_t *resolved) 177 { 178 conn_for_resolved_cell = conn; 179 180 last_answer_type = answer_type; 181 last_resolved = (cached_resolve_t *)resolved; 182 183 n_send_resolved_cell_replacement++; 184 } 185 186 static int n_send_resolved_hostname_cell_replacement = 0; 187 188 static char *last_resolved_hostname = NULL; 189 190 static void 191 dns_resolve_send_resolved_hostname_cell(edge_connection_t *conn, 192 const char *hostname) 193 { 194 conn_for_resolved_cell = conn; 195 196 tor_free(last_resolved_hostname); 197 last_resolved_hostname = tor_strdup(hostname); 198 199 n_send_resolved_hostname_cell_replacement++; 200 } 201 202 static int n_dns_cancel_pending_resolve_replacement = 0; 203 204 static void 205 dns_resolve_dns_cancel_pending_resolve(const char *address) 206 { 207 (void) address; 208 n_dns_cancel_pending_resolve_replacement++; 209 } 210 211 static int n_connection_free = 0; 212 static connection_t *last_freed_conn = NULL; 213 214 static void 215 dns_resolve_connection_free_(connection_t *conn) 216 { 217 n_connection_free++; 218 219 last_freed_conn = conn; 220 } 221 222 static void 223 test_dns_resolve(void *arg) 224 { 225 (void) arg; 226 int retval; 227 int prev_n_send_resolved_hostname_cell_replacement; 228 int prev_n_send_resolved_cell_replacement; 229 int prev_n_connection_free; 230 cached_resolve_t *fake_resolved = tor_malloc(sizeof(cached_resolve_t)); 231 edge_connection_t *exitconn = tor_malloc(sizeof(edge_connection_t)); 232 edge_connection_t *nextconn = tor_malloc(sizeof(edge_connection_t)); 233 234 or_circuit_t *on_circuit = tor_malloc(sizeof(or_circuit_t)); 235 memset(on_circuit,0,sizeof(or_circuit_t)); 236 on_circuit->base_.magic = OR_CIRCUIT_MAGIC; 237 238 memset(fake_resolved,0,sizeof(cached_resolve_t)); 239 memset(exitconn,0,sizeof(edge_connection_t)); 240 memset(nextconn,0,sizeof(edge_connection_t)); 241 242 MOCK(dns_resolve_impl, 243 dns_resolve_dns_resolve_impl); 244 MOCK(send_resolved_cell, 245 dns_resolve_send_resolved_cell); 246 MOCK(send_resolved_hostname_cell, 247 dns_resolve_send_resolved_hostname_cell); 248 249 /* 250 * CASE 1: dns_resolve_impl returns 1 and sets a hostname. purpose is 251 * EXIT_PURPOSE_RESOLVE. 252 * 253 * We want dns_resolve() to call send_resolved_hostname_cell() for a 254 * given exit connection (represented by edge_connection_t object) 255 * with a hostname it received from _impl. 256 */ 257 258 prev_n_send_resolved_hostname_cell_replacement = 259 n_send_resolved_hostname_cell_replacement; 260 261 exitconn->base_.purpose = EXIT_PURPOSE_RESOLVE; 262 exitconn->on_circuit = &(on_circuit->base_); 263 264 resolve_retval = 1; 265 resolved_name = tor_strdup("www.torproject.org"); 266 267 retval = dns_resolve(exitconn); 268 269 tt_int_op(retval,OP_EQ,1); 270 tt_str_op(resolved_name,OP_EQ,last_resolved_hostname); 271 tt_assert(conn_for_resolved_cell == exitconn); 272 tt_int_op(n_send_resolved_hostname_cell_replacement,OP_EQ, 273 prev_n_send_resolved_hostname_cell_replacement + 1); 274 tt_assert(exitconn->on_circuit == NULL); 275 276 tor_free(last_resolved_hostname); 277 // implies last_resolved_hostname = NULL; 278 279 /* CASE 2: dns_resolve_impl returns 1, but does not set hostname. 280 * Instead, it yields cached_resolve_t object. 281 * 282 * We want dns_resolve to call send_resolved_cell on exitconn with 283 * RESOLVED_TYPE_AUTO and the cached_resolve_t object from _impl. 284 */ 285 286 tor_free(resolved_name); 287 resolved_name = NULL; 288 289 exitconn->on_circuit = &(on_circuit->base_); 290 291 cache_entry_mock = fake_resolved; 292 293 prev_n_send_resolved_cell_replacement = 294 n_send_resolved_cell_replacement; 295 296 retval = dns_resolve(exitconn); 297 298 tt_int_op(retval,OP_EQ,1); 299 tt_assert(conn_for_resolved_cell == exitconn); 300 tt_int_op(n_send_resolved_cell_replacement,OP_EQ, 301 prev_n_send_resolved_cell_replacement + 1); 302 tt_assert(last_resolved == fake_resolved); 303 tt_int_op(last_answer_type,OP_EQ,0xff); 304 tt_assert(exitconn->on_circuit == NULL); 305 306 /* CASE 3: The purpose of exit connection is not EXIT_PURPOSE_RESOLVE 307 * and _impl returns 1. 308 * 309 * We want dns_resolve to prepend exitconn to n_streams linked list. 310 * We don't want it to send any cells about hostname being resolved. 311 */ 312 313 exitconn->base_.purpose = EXIT_PURPOSE_CONNECT; 314 exitconn->on_circuit = &(on_circuit->base_); 315 316 on_circuit->n_streams = nextconn; 317 318 prev_n_send_resolved_cell_replacement = 319 n_send_resolved_cell_replacement; 320 321 prev_n_send_resolved_hostname_cell_replacement = 322 n_send_resolved_hostname_cell_replacement; 323 324 retval = dns_resolve(exitconn); 325 326 tt_int_op(retval,OP_EQ,1); 327 tt_assert(on_circuit->n_streams == exitconn); 328 tt_assert(exitconn->next_stream == nextconn); 329 tt_int_op(prev_n_send_resolved_cell_replacement,OP_EQ, 330 n_send_resolved_cell_replacement); 331 tt_int_op(prev_n_send_resolved_hostname_cell_replacement,OP_EQ, 332 n_send_resolved_hostname_cell_replacement); 333 334 /* CASE 4: _impl returns 0. 335 * 336 * We want dns_resolve() to set exitconn state to 337 * EXIT_CONN_STATE_RESOLVING and prepend exitconn to resolving_streams 338 * linked list. 339 */ 340 341 exitconn->on_circuit = &(on_circuit->base_); 342 343 resolve_retval = 0; 344 345 exitconn->next_stream = NULL; 346 on_circuit->resolving_streams = nextconn; 347 348 retval = dns_resolve(exitconn); 349 350 tt_int_op(retval,OP_EQ,0); 351 tt_int_op(exitconn->base_.state,OP_EQ,EXIT_CONN_STATE_RESOLVING); 352 tt_assert(on_circuit->resolving_streams == exitconn); 353 tt_assert(exitconn->next_stream == nextconn); 354 355 /* CASE 5: _impl returns -1 when purpose of exitconn is 356 * EXIT_PURPOSE_RESOLVE. We want dns_resolve to call send_resolved_cell 357 * on exitconn with type being RESOLVED_TYPE_ERROR. 358 */ 359 360 MOCK(dns_cancel_pending_resolve, 361 dns_resolve_dns_cancel_pending_resolve); 362 MOCK(connection_free_, 363 dns_resolve_connection_free_); 364 365 exitconn->on_circuit = &(on_circuit->base_); 366 exitconn->base_.purpose = EXIT_PURPOSE_RESOLVE; 367 368 resolve_retval = -1; 369 370 prev_n_send_resolved_cell_replacement = 371 n_send_resolved_cell_replacement; 372 373 prev_n_connection_free = n_connection_free; 374 375 retval = dns_resolve(exitconn); 376 377 tt_int_op(retval,OP_EQ,-1); 378 tt_int_op(n_send_resolved_cell_replacement,OP_EQ, 379 prev_n_send_resolved_cell_replacement + 1); 380 tt_int_op(last_answer_type,OP_EQ,RESOLVED_TYPE_ERROR); 381 tt_int_op(n_dns_cancel_pending_resolve_replacement,OP_EQ,1); 382 tt_int_op(n_connection_free,OP_EQ,prev_n_connection_free + 1); 383 tt_assert(last_freed_conn == TO_CONN(exitconn)); 384 385 done: 386 UNMOCK(dns_resolve_impl); 387 UNMOCK(send_resolved_cell); 388 UNMOCK(send_resolved_hostname_cell); 389 UNMOCK(dns_cancel_pending_resolve); 390 UNMOCK(connection_free_); 391 tor_free(on_circuit); 392 tor_free(exitconn); 393 tor_free(nextconn); 394 tor_free(resolved_name); 395 tor_free(fake_resolved); 396 tor_free(last_resolved_hostname); 397 return; 398 } 399 400 /** Create an <b>edge_connection_t</b> instance that is considered a 401 * valid exit connection by asserts in dns_resolve_impl. 402 */ 403 static edge_connection_t * 404 create_valid_exitconn(void) 405 { 406 edge_connection_t *exitconn = tor_malloc_zero(sizeof(edge_connection_t)); 407 TO_CONN(exitconn)->type = CONN_TYPE_EXIT; 408 TO_CONN(exitconn)->magic = EDGE_CONNECTION_MAGIC; 409 TO_CONN(exitconn)->purpose = EXIT_PURPOSE_RESOLVE; 410 TO_CONN(exitconn)->state = EXIT_CONN_STATE_RESOLVING; 411 exitconn->base_.s = TOR_INVALID_SOCKET; 412 413 return exitconn; 414 } 415 416 /* 417 * Given that <b>exitconn->base_.address</b> is IP address string, we 418 * want dns_resolve_impl() to parse it and store in 419 * <b>exitconn->base_.addr</b>. We expect dns_resolve_impl to return 1. 420 * Lastly, we want it to set the TTL value to default one for DNS queries. 421 */ 422 423 static void 424 test_dns_impl_addr_is_ip(void *arg) 425 { 426 int retval; 427 int made_pending; 428 const tor_addr_t *resolved_addr; 429 tor_addr_t addr_to_compare; 430 431 (void)arg; 432 433 tor_addr_parse(&addr_to_compare, "8.8.8.8"); 434 435 or_circuit_t *on_circ = tor_malloc_zero(sizeof(or_circuit_t)); 436 437 edge_connection_t *exitconn = create_valid_exitconn(); 438 439 TO_CONN(exitconn)->address = tor_strdup("8.8.8.8"); 440 441 retval = dns_resolve_impl(exitconn, 1, on_circ, NULL, &made_pending, 442 NULL); 443 444 resolved_addr = &(exitconn->base_.addr); 445 446 tt_int_op(retval,OP_EQ,1); 447 tt_assert(tor_addr_eq(resolved_addr, (const tor_addr_t *)&addr_to_compare)); 448 tt_int_op(exitconn->address_ttl,OP_EQ,DEFAULT_DNS_TTL); 449 450 done: 451 tor_free(on_circ); 452 tor_free(TO_CONN(exitconn)->address); 453 tor_free(exitconn); 454 return; 455 } 456 457 /** Given that Tor instance is not configured as an exit node, we want 458 * dns_resolve_impl() to fail with return value -1. 459 */ 460 static int 461 dns_impl_non_exit_router_my_exit_policy_is_reject_star(void) 462 { 463 return 1; 464 } 465 466 static void 467 test_dns_impl_non_exit(void *arg) 468 { 469 int retval; 470 int made_pending; 471 472 edge_connection_t *exitconn = create_valid_exitconn(); 473 or_circuit_t *on_circ = tor_malloc_zero(sizeof(or_circuit_t)); 474 475 (void)arg; 476 477 TO_CONN(exitconn)->address = tor_strdup("torproject.org"); 478 479 MOCK(router_my_exit_policy_is_reject_star, 480 dns_impl_non_exit_router_my_exit_policy_is_reject_star); 481 482 retval = dns_resolve_impl(exitconn, 1, on_circ, NULL, &made_pending, 483 NULL); 484 485 tt_int_op(retval,OP_EQ,-1); 486 487 done: 488 tor_free(TO_CONN(exitconn)->address); 489 tor_free(exitconn); 490 tor_free(on_circ); 491 UNMOCK(router_my_exit_policy_is_reject_star); 492 return; 493 } 494 495 /** Given that address is not a valid destination (as judged by 496 * address_is_invalid_destination() function), we want dns_resolve_impl() 497 * function to fail with return value -1. 498 */ 499 500 static int 501 dns_impl_addr_is_invalid_dest_router_my_exit_policy_is_reject_star(void) 502 { 503 return 0; 504 } 505 506 static void 507 test_dns_impl_addr_is_invalid_dest(void *arg) 508 { 509 int retval; 510 int made_pending; 511 512 edge_connection_t *exitconn = create_valid_exitconn(); 513 or_circuit_t *on_circ = tor_malloc_zero(sizeof(or_circuit_t)); 514 515 (void)arg; 516 517 MOCK(router_my_exit_policy_is_reject_star, 518 dns_impl_addr_is_invalid_dest_router_my_exit_policy_is_reject_star); 519 520 TO_CONN(exitconn)->address = tor_strdup("invalid#@!.org"); 521 522 retval = dns_resolve_impl(exitconn, 1, on_circ, NULL, &made_pending, 523 NULL); 524 525 tt_int_op(retval,OP_EQ,-1); 526 527 done: 528 UNMOCK(router_my_exit_policy_is_reject_star); 529 tor_free(TO_CONN(exitconn)->address); 530 tor_free(exitconn); 531 tor_free(on_circ); 532 return; 533 } 534 535 /** Given that address is a malformed PTR name, we want dns_resolve_impl to 536 * fail. 537 */ 538 539 static int 540 dns_impl_malformed_ptr_router_my_exit_policy_is_reject_star(void) 541 { 542 return 0; 543 } 544 545 static void 546 test_dns_impl_malformed_ptr(void *arg) 547 { 548 int retval; 549 int made_pending; 550 551 edge_connection_t *exitconn = create_valid_exitconn(); 552 or_circuit_t *on_circ = tor_malloc_zero(sizeof(or_circuit_t)); 553 554 (void)arg; 555 556 TO_CONN(exitconn)->address = tor_strdup("1.0.0.127.in-addr.arpa"); 557 558 MOCK(router_my_exit_policy_is_reject_star, 559 dns_impl_malformed_ptr_router_my_exit_policy_is_reject_star); 560 561 retval = dns_resolve_impl(exitconn, 1, on_circ, NULL, &made_pending, 562 NULL); 563 564 tt_int_op(retval,OP_EQ,-1); 565 566 tor_free(TO_CONN(exitconn)->address); 567 568 TO_CONN(exitconn)->address = 569 tor_strdup("z01234567890123456789.in-addr.arpa"); 570 571 retval = dns_resolve_impl(exitconn, 1, on_circ, NULL, &made_pending, 572 NULL); 573 574 tt_int_op(retval,OP_EQ,-1); 575 576 done: 577 UNMOCK(router_my_exit_policy_is_reject_star); 578 tor_free(TO_CONN(exitconn)->address); 579 tor_free(exitconn); 580 tor_free(on_circ); 581 return; 582 } 583 584 /* Given that there is already a pending resolve for the given address, 585 * we want dns_resolve_impl to append our exit connection to list 586 * of pending connections for the pending DNS request and return 0. 587 */ 588 589 static int 590 dns_impl_cache_hit_pending_router_my_exit_policy_is_reject_star(void) 591 { 592 return 0; 593 } 594 595 static void 596 test_dns_impl_cache_hit_pending(void *arg) 597 { 598 int retval; 599 int made_pending = 0; 600 601 pending_connection_t *pending_conn = NULL; 602 603 edge_connection_t *exitconn = create_valid_exitconn(); 604 or_circuit_t *on_circ = tor_malloc_zero(sizeof(or_circuit_t)); 605 606 cached_resolve_t *cache_entry = tor_malloc_zero(sizeof(cached_resolve_t)); 607 cache_entry->magic = CACHED_RESOLVE_MAGIC; 608 cache_entry->state = CACHE_STATE_PENDING; 609 cache_entry->minheap_idx = -1; 610 cache_entry->expire = time(NULL) + 60 * 60; 611 612 (void)arg; 613 614 TO_CONN(exitconn)->address = tor_strdup("torproject.org"); 615 616 strlcpy(cache_entry->address, TO_CONN(exitconn)->address, 617 sizeof(cache_entry->address)); 618 619 MOCK(router_my_exit_policy_is_reject_star, 620 dns_impl_cache_hit_pending_router_my_exit_policy_is_reject_star); 621 622 dns_init(); 623 624 dns_insert_cache_entry(cache_entry); 625 626 retval = dns_resolve_impl(exitconn, 1, on_circ, NULL, &made_pending, 627 NULL); 628 629 tt_int_op(retval,OP_EQ,0); 630 tt_int_op(made_pending,OP_EQ,1); 631 632 pending_conn = cache_entry->pending_connections; 633 634 tt_assert(pending_conn != NULL); 635 tt_assert(pending_conn->conn == exitconn); 636 637 done: 638 UNMOCK(router_my_exit_policy_is_reject_star); 639 tor_free(on_circ); 640 tor_free(TO_CONN(exitconn)->address); 641 tor_free(cache_entry->pending_connections); 642 tor_free(cache_entry); 643 tor_free(exitconn); 644 return; 645 } 646 647 /* Given that a finished DNS resolve is available in our cache, we want 648 * dns_resolve_impl() return it to called via resolve_out and pass the 649 * handling to set_exitconn_info_from_resolve function. 650 */ 651 static int 652 dns_impl_cache_hit_cached_router_my_exit_policy_is_reject_star(void) 653 { 654 return 0; 655 } 656 657 static edge_connection_t *last_exitconn = NULL; 658 static cached_resolve_t *last_resolve = NULL; 659 660 static int 661 dns_impl_cache_hit_cached_set_exitconn_info_from_resolve( 662 edge_connection_t *exitconn, 663 const cached_resolve_t *resolve, 664 char **hostname_out) 665 { 666 last_exitconn = exitconn; 667 last_resolve = (cached_resolve_t *)resolve; 668 669 (void)hostname_out; 670 671 return 0; 672 } 673 674 static void 675 test_dns_impl_cache_hit_cached(void *arg) 676 { 677 int retval; 678 int made_pending = 0; 679 680 edge_connection_t *exitconn = create_valid_exitconn(); 681 or_circuit_t *on_circ = tor_malloc_zero(sizeof(or_circuit_t)); 682 683 cached_resolve_t *resolve_out = NULL; 684 685 cached_resolve_t *cache_entry = tor_malloc_zero(sizeof(cached_resolve_t)); 686 cache_entry->magic = CACHED_RESOLVE_MAGIC; 687 cache_entry->state = CACHE_STATE_CACHED; 688 cache_entry->minheap_idx = -1; 689 cache_entry->expire = time(NULL) + 60 * 60; 690 691 (void)arg; 692 693 TO_CONN(exitconn)->address = tor_strdup("torproject.org"); 694 695 strlcpy(cache_entry->address, TO_CONN(exitconn)->address, 696 sizeof(cache_entry->address)); 697 698 MOCK(router_my_exit_policy_is_reject_star, 699 dns_impl_cache_hit_cached_router_my_exit_policy_is_reject_star); 700 MOCK(set_exitconn_info_from_resolve, 701 dns_impl_cache_hit_cached_set_exitconn_info_from_resolve); 702 703 dns_init(); 704 705 dns_insert_cache_entry(cache_entry); 706 707 retval = dns_resolve_impl(exitconn, 1, on_circ, NULL, &made_pending, 708 &resolve_out); 709 710 tt_int_op(retval,OP_EQ,0); 711 tt_int_op(made_pending,OP_EQ,0); 712 tt_assert(resolve_out == cache_entry); 713 714 tt_assert(last_exitconn == exitconn); 715 tt_assert(last_resolve == cache_entry); 716 717 done: 718 UNMOCK(router_my_exit_policy_is_reject_star); 719 UNMOCK(set_exitconn_info_from_resolve); 720 tor_free(on_circ); 721 tor_free(TO_CONN(exitconn)->address); 722 tor_free(cache_entry->pending_connections); 723 tor_free(cache_entry); 724 return; 725 } 726 727 /* Given that there are neither pending nor pre-cached resolve for a given 728 * address, we want dns_resolve_impl() to create a new cached_resolve_t 729 * object, mark it as pending, insert it into the cache, attach the exit 730 * connection to list of pending connections and call launch_resolve() 731 * with the cached_resolve_t object it created. 732 */ 733 static int 734 dns_impl_cache_miss_router_my_exit_policy_is_reject_star(void) 735 { 736 return 0; 737 } 738 739 static cached_resolve_t *last_launched_resolve = NULL; 740 741 static int 742 dns_impl_cache_miss_launch_resolve(cached_resolve_t *resolve) 743 { 744 last_launched_resolve = resolve; 745 746 return 0; 747 } 748 749 static void 750 test_dns_impl_cache_miss(void *arg) 751 { 752 int retval; 753 int made_pending = 0; 754 755 pending_connection_t *pending_conn = NULL; 756 757 edge_connection_t *exitconn = create_valid_exitconn(); 758 or_circuit_t *on_circ = tor_malloc_zero(sizeof(or_circuit_t)); 759 760 cached_resolve_t *cache_entry = NULL; 761 cached_resolve_t query; 762 763 (void)arg; 764 765 TO_CONN(exitconn)->address = tor_strdup("torproject.org"); 766 767 strlcpy(query.address, TO_CONN(exitconn)->address, sizeof(query.address)); 768 769 MOCK(router_my_exit_policy_is_reject_star, 770 dns_impl_cache_miss_router_my_exit_policy_is_reject_star); 771 MOCK(launch_resolve, 772 dns_impl_cache_miss_launch_resolve); 773 774 dns_init(); 775 776 retval = dns_resolve_impl(exitconn, 1, on_circ, NULL, &made_pending, 777 NULL); 778 779 tt_int_op(retval,OP_EQ,0); 780 tt_int_op(made_pending,OP_EQ,1); 781 782 cache_entry = dns_get_cache_entry(&query); 783 784 tt_assert(cache_entry); 785 786 pending_conn = cache_entry->pending_connections; 787 788 tt_assert(pending_conn != NULL); 789 tt_assert(pending_conn->conn == exitconn); 790 791 tt_assert(last_launched_resolve == cache_entry); 792 tt_str_op(cache_entry->address,OP_EQ,TO_CONN(exitconn)->address); 793 794 done: 795 UNMOCK(router_my_exit_policy_is_reject_star); 796 UNMOCK(launch_resolve); 797 tor_free(on_circ); 798 tor_free(TO_CONN(exitconn)->address); 799 if (cache_entry) 800 tor_free(cache_entry->pending_connections); 801 tor_free(cache_entry); 802 tor_free(exitconn); 803 return; 804 } 805 806 struct testcase_t dns_tests[] = { 807 #ifdef HAVE_EVDNS_BASE_GET_NAMESERVER_ADDR 808 { "configure_ns_fallback", test_dns_configure_ns_fallback, 809 TT_FORK, NULL, NULL }, 810 #endif 811 { "clip_ttl", test_dns_clip_ttl, TT_FORK, NULL, NULL }, 812 { "clip_fuzzy_ttl", test_dns_clip_fuzzy_ttl, TT_FORK, NULL, NULL }, 813 { "resolve", test_dns_resolve, TT_FORK, NULL, NULL }, 814 { "impl_addr_is_ip", test_dns_impl_addr_is_ip, TT_FORK, NULL, NULL }, 815 { "impl_non_exit", test_dns_impl_non_exit, TT_FORK, NULL, NULL }, 816 { "impl_addr_is_invalid_dest", test_dns_impl_addr_is_invalid_dest, 817 TT_FORK, NULL, NULL }, 818 { "impl_malformed_ptr", test_dns_impl_malformed_ptr, TT_FORK, NULL, NULL }, 819 { "impl_cache_hit_pending", test_dns_impl_cache_hit_pending, 820 TT_FORK, NULL, NULL }, 821 { "impl_cache_hit_cached", test_dns_impl_cache_hit_cached, 822 TT_FORK, NULL, NULL }, 823 { "impl_cache_miss", test_dns_impl_cache_miss, TT_FORK, NULL, NULL }, 824 END_OF_TESTCASES 825 };