tor

The Tor anonymity network
git clone https://git.dasho.dev/tor.git
Log | Files | Refs | README | LICENSE

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 };