LCOV - code coverage report
Current view: top level - test - test_dns.c (source / functions) Hit Total Coverage
Test: lcov.info Lines: 350 350 100.0 %
Date: 2021-11-24 03:28:48 Functions: 25 25 100.0 %

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

Generated by: LCOV version 1.14