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 *
mock_get_options(void)30 mock_get_options(void)
31 {
32   return &options;
33 }
34 
35 static void
test_dns_configure_ns_fallback(void * arg)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
test_dns_clip_ttl(void * arg)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 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
dns_resolve_dns_resolve_impl(edge_connection_t * exitconn,int is_resolve,or_circuit_t * oncirc,char ** hostname_out,int * made_connection_pending_out,cached_resolve_t ** resolve_out)115 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   (void)oncirc;
121   (void)exitconn;
122   (void)is_resolve;
123 
124   if (made_connection_pending_out)
125     *made_connection_pending_out = resolve_made_conn_pending;
126 
127   if (hostname_out && resolved_name)
128     *hostname_out = tor_strdup(resolved_name);
129 
130   if (resolve_out && cache_entry_mock)
131     *resolve_out = cache_entry_mock;
132 
133   n_fake_impl++;
134 
135   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
dns_resolve_send_resolved_cell(edge_connection_t * conn,uint8_t answer_type,const cached_resolve_t * resolved)145 dns_resolve_send_resolved_cell(edge_connection_t *conn, uint8_t answer_type,
146                        const cached_resolve_t *resolved)
147 {
148   conn_for_resolved_cell = conn;
149 
150   last_answer_type = answer_type;
151   last_resolved = (cached_resolve_t *)resolved;
152 
153   n_send_resolved_cell_replacement++;
154 }
155 
156 static int n_send_resolved_hostname_cell_replacement = 0;
157 
158 static char *last_resolved_hostname = NULL;
159 
160 static void
dns_resolve_send_resolved_hostname_cell(edge_connection_t * conn,const char * hostname)161 dns_resolve_send_resolved_hostname_cell(edge_connection_t *conn,
162                                 const char *hostname)
163 {
164   conn_for_resolved_cell = conn;
165 
166   tor_free(last_resolved_hostname);
167   last_resolved_hostname = tor_strdup(hostname);
168 
169   n_send_resolved_hostname_cell_replacement++;
170 }
171 
172 static int n_dns_cancel_pending_resolve_replacement = 0;
173 
174 static void
dns_resolve_dns_cancel_pending_resolve(const char * address)175 dns_resolve_dns_cancel_pending_resolve(const char *address)
176 {
177   (void) address;
178   n_dns_cancel_pending_resolve_replacement++;
179 }
180 
181 static int n_connection_free = 0;
182 static connection_t *last_freed_conn = NULL;
183 
184 static void
dns_resolve_connection_free_(connection_t * conn)185 dns_resolve_connection_free_(connection_t *conn)
186 {
187    n_connection_free++;
188 
189    last_freed_conn = conn;
190 }
191 
192 static void
test_dns_resolve(void * arg)193 test_dns_resolve(void *arg)
194 {
195   (void) arg;
196   int retval;
197   int prev_n_send_resolved_hostname_cell_replacement;
198   int prev_n_send_resolved_cell_replacement;
199   int prev_n_connection_free;
200   cached_resolve_t *fake_resolved = tor_malloc(sizeof(cached_resolve_t));
201   edge_connection_t *exitconn = tor_malloc(sizeof(edge_connection_t));
202   edge_connection_t *nextconn = tor_malloc(sizeof(edge_connection_t));
203 
204   or_circuit_t *on_circuit = tor_malloc(sizeof(or_circuit_t));
205   memset(on_circuit,0,sizeof(or_circuit_t));
206   on_circuit->base_.magic = OR_CIRCUIT_MAGIC;
207 
208   memset(fake_resolved,0,sizeof(cached_resolve_t));
209   memset(exitconn,0,sizeof(edge_connection_t));
210   memset(nextconn,0,sizeof(edge_connection_t));
211 
212   MOCK(dns_resolve_impl,
213        dns_resolve_dns_resolve_impl);
214   MOCK(send_resolved_cell,
215        dns_resolve_send_resolved_cell);
216   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   prev_n_send_resolved_hostname_cell_replacement =
229   n_send_resolved_hostname_cell_replacement;
230 
231   exitconn->base_.purpose = EXIT_PURPOSE_RESOLVE;
232   exitconn->on_circuit = &(on_circuit->base_);
233 
234   resolve_retval = 1;
235   resolved_name = tor_strdup("www.torproject.org");
236 
237   retval = dns_resolve(exitconn);
238 
239   tt_int_op(retval,OP_EQ,1);
240   tt_str_op(resolved_name,OP_EQ,last_resolved_hostname);
241   tt_assert(conn_for_resolved_cell == exitconn);
242   tt_int_op(n_send_resolved_hostname_cell_replacement,OP_EQ,
243             prev_n_send_resolved_hostname_cell_replacement + 1);
244   tt_assert(exitconn->on_circuit == NULL);
245 
246   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   tor_free(resolved_name);
257   resolved_name = NULL;
258 
259   exitconn->on_circuit = &(on_circuit->base_);
260 
261   cache_entry_mock = fake_resolved;
262 
263   prev_n_send_resolved_cell_replacement =
264   n_send_resolved_cell_replacement;
265 
266   retval = dns_resolve(exitconn);
267 
268   tt_int_op(retval,OP_EQ,1);
269   tt_assert(conn_for_resolved_cell == exitconn);
270   tt_int_op(n_send_resolved_cell_replacement,OP_EQ,
271             prev_n_send_resolved_cell_replacement + 1);
272   tt_assert(last_resolved == fake_resolved);
273   tt_int_op(last_answer_type,OP_EQ,0xff);
274   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   exitconn->base_.purpose = EXIT_PURPOSE_CONNECT;
284   exitconn->on_circuit = &(on_circuit->base_);
285 
286   on_circuit->n_streams = nextconn;
287 
288   prev_n_send_resolved_cell_replacement =
289   n_send_resolved_cell_replacement;
290 
291   prev_n_send_resolved_hostname_cell_replacement =
292   n_send_resolved_hostname_cell_replacement;
293 
294   retval = dns_resolve(exitconn);
295 
296   tt_int_op(retval,OP_EQ,1);
297   tt_assert(on_circuit->n_streams == exitconn);
298   tt_assert(exitconn->next_stream == nextconn);
299   tt_int_op(prev_n_send_resolved_cell_replacement,OP_EQ,
300             n_send_resolved_cell_replacement);
301   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   exitconn->on_circuit = &(on_circuit->base_);
312 
313   resolve_retval = 0;
314 
315   exitconn->next_stream = NULL;
316   on_circuit->resolving_streams = nextconn;
317 
318   retval = dns_resolve(exitconn);
319 
320   tt_int_op(retval,OP_EQ,0);
321   tt_int_op(exitconn->base_.state,OP_EQ,EXIT_CONN_STATE_RESOLVING);
322   tt_assert(on_circuit->resolving_streams == exitconn);
323   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   MOCK(dns_cancel_pending_resolve,
331        dns_resolve_dns_cancel_pending_resolve);
332   MOCK(connection_free_,
333        dns_resolve_connection_free_);
334 
335   exitconn->on_circuit = &(on_circuit->base_);
336   exitconn->base_.purpose = EXIT_PURPOSE_RESOLVE;
337 
338   resolve_retval = -1;
339 
340   prev_n_send_resolved_cell_replacement =
341   n_send_resolved_cell_replacement;
342 
343   prev_n_connection_free = n_connection_free;
344 
345   retval = dns_resolve(exitconn);
346 
347   tt_int_op(retval,OP_EQ,-1);
348   tt_int_op(n_send_resolved_cell_replacement,OP_EQ,
349             prev_n_send_resolved_cell_replacement + 1);
350   tt_int_op(last_answer_type,OP_EQ,RESOLVED_TYPE_ERROR);
351   tt_int_op(n_dns_cancel_pending_resolve_replacement,OP_EQ,1);
352   tt_int_op(n_connection_free,OP_EQ,prev_n_connection_free + 1);
353   tt_assert(last_freed_conn == TO_CONN(exitconn));
354 
355   done:
356   UNMOCK(dns_resolve_impl);
357   UNMOCK(send_resolved_cell);
358   UNMOCK(send_resolved_hostname_cell);
359   UNMOCK(dns_cancel_pending_resolve);
360   UNMOCK(connection_free_);
361   tor_free(on_circuit);
362   tor_free(exitconn);
363   tor_free(nextconn);
364   tor_free(resolved_name);
365   tor_free(fake_resolved);
366   tor_free(last_resolved_hostname);
367   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 *
create_valid_exitconn(void)374 create_valid_exitconn(void)
375 {
376   edge_connection_t *exitconn = tor_malloc_zero(sizeof(edge_connection_t));
377   TO_CONN(exitconn)->type = CONN_TYPE_EXIT;
378   TO_CONN(exitconn)->magic = EDGE_CONNECTION_MAGIC;
379   TO_CONN(exitconn)->purpose = EXIT_PURPOSE_RESOLVE;
380   TO_CONN(exitconn)->state = EXIT_CONN_STATE_RESOLVING;
381   exitconn->base_.s = TOR_INVALID_SOCKET;
382 
383   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
test_dns_impl_addr_is_ip(void * arg)394 test_dns_impl_addr_is_ip(void *arg)
395 {
396   int retval;
397   int made_pending;
398   const tor_addr_t *resolved_addr;
399   tor_addr_t addr_to_compare;
400 
401   (void)arg;
402 
403   tor_addr_parse(&addr_to_compare, "8.8.8.8");
404 
405   or_circuit_t *on_circ = tor_malloc_zero(sizeof(or_circuit_t));
406 
407   edge_connection_t *exitconn = create_valid_exitconn();
408 
409   TO_CONN(exitconn)->address = tor_strdup("8.8.8.8");
410 
411   retval = dns_resolve_impl(exitconn, 1, on_circ, NULL, &made_pending,
412                             NULL);
413 
414   resolved_addr = &(exitconn->base_.addr);
415 
416   tt_int_op(retval,OP_EQ,1);
417   tt_assert(tor_addr_eq(resolved_addr, (const tor_addr_t *)&addr_to_compare));
418   tt_int_op(exitconn->address_ttl,OP_EQ,DEFAULT_DNS_TTL);
419 
420   done:
421   tor_free(on_circ);
422   tor_free(TO_CONN(exitconn)->address);
423   tor_free(exitconn);
424   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
dns_impl_non_exit_router_my_exit_policy_is_reject_star(void)431 dns_impl_non_exit_router_my_exit_policy_is_reject_star(void)
432 {
433   return 1;
434 }
435 
436 static void
test_dns_impl_non_exit(void * arg)437 test_dns_impl_non_exit(void *arg)
438 {
439   int retval;
440   int made_pending;
441 
442   edge_connection_t *exitconn = create_valid_exitconn();
443   or_circuit_t *on_circ = tor_malloc_zero(sizeof(or_circuit_t));
444 
445   (void)arg;
446 
447   TO_CONN(exitconn)->address = tor_strdup("torproject.org");
448 
449   MOCK(router_my_exit_policy_is_reject_star,
450        dns_impl_non_exit_router_my_exit_policy_is_reject_star);
451 
452   retval = dns_resolve_impl(exitconn, 1, on_circ, NULL, &made_pending,
453                             NULL);
454 
455   tt_int_op(retval,OP_EQ,-1);
456 
457   done:
458   tor_free(TO_CONN(exitconn)->address);
459   tor_free(exitconn);
460   tor_free(on_circ);
461   UNMOCK(router_my_exit_policy_is_reject_star);
462   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
dns_impl_addr_is_invalid_dest_router_my_exit_policy_is_reject_star(void)471 dns_impl_addr_is_invalid_dest_router_my_exit_policy_is_reject_star(void)
472 {
473   return 0;
474 }
475 
476 static void
test_dns_impl_addr_is_invalid_dest(void * arg)477 test_dns_impl_addr_is_invalid_dest(void *arg)
478 {
479   int retval;
480   int made_pending;
481 
482   edge_connection_t *exitconn = create_valid_exitconn();
483   or_circuit_t *on_circ = tor_malloc_zero(sizeof(or_circuit_t));
484 
485   (void)arg;
486 
487   MOCK(router_my_exit_policy_is_reject_star,
488        dns_impl_addr_is_invalid_dest_router_my_exit_policy_is_reject_star);
489 
490   TO_CONN(exitconn)->address = tor_strdup("invalid#@!.org");
491 
492   retval = dns_resolve_impl(exitconn, 1, on_circ, NULL, &made_pending,
493                             NULL);
494 
495   tt_int_op(retval,OP_EQ,-1);
496 
497   done:
498   UNMOCK(router_my_exit_policy_is_reject_star);
499   tor_free(TO_CONN(exitconn)->address);
500   tor_free(exitconn);
501   tor_free(on_circ);
502   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
dns_impl_malformed_ptr_router_my_exit_policy_is_reject_star(void)510 dns_impl_malformed_ptr_router_my_exit_policy_is_reject_star(void)
511 {
512   return 0;
513 }
514 
515 static void
test_dns_impl_malformed_ptr(void * arg)516 test_dns_impl_malformed_ptr(void *arg)
517 {
518   int retval;
519   int made_pending;
520 
521   edge_connection_t *exitconn = create_valid_exitconn();
522   or_circuit_t *on_circ = tor_malloc_zero(sizeof(or_circuit_t));
523 
524   (void)arg;
525 
526   TO_CONN(exitconn)->address = tor_strdup("1.0.0.127.in-addr.arpa");
527 
528   MOCK(router_my_exit_policy_is_reject_star,
529        dns_impl_malformed_ptr_router_my_exit_policy_is_reject_star);
530 
531   retval = dns_resolve_impl(exitconn, 1, on_circ, NULL, &made_pending,
532                             NULL);
533 
534   tt_int_op(retval,OP_EQ,-1);
535 
536   tor_free(TO_CONN(exitconn)->address);
537 
538   TO_CONN(exitconn)->address =
539   tor_strdup("z01234567890123456789.in-addr.arpa");
540 
541   retval = dns_resolve_impl(exitconn, 1, on_circ, NULL, &made_pending,
542                             NULL);
543 
544   tt_int_op(retval,OP_EQ,-1);
545 
546   done:
547   UNMOCK(router_my_exit_policy_is_reject_star);
548   tor_free(TO_CONN(exitconn)->address);
549   tor_free(exitconn);
550   tor_free(on_circ);
551   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
dns_impl_cache_hit_pending_router_my_exit_policy_is_reject_star(void)560 dns_impl_cache_hit_pending_router_my_exit_policy_is_reject_star(void)
561 {
562   return 0;
563 }
564 
565 static void
test_dns_impl_cache_hit_pending(void * arg)566 test_dns_impl_cache_hit_pending(void *arg)
567 {
568   int retval;
569   int made_pending = 0;
570 
571   pending_connection_t *pending_conn = NULL;
572 
573   edge_connection_t *exitconn = create_valid_exitconn();
574   or_circuit_t *on_circ = tor_malloc_zero(sizeof(or_circuit_t));
575 
576   cached_resolve_t *cache_entry = tor_malloc_zero(sizeof(cached_resolve_t));
577   cache_entry->magic = CACHED_RESOLVE_MAGIC;
578   cache_entry->state = CACHE_STATE_PENDING;
579   cache_entry->minheap_idx = -1;
580   cache_entry->expire = time(NULL) + 60 * 60;
581 
582   (void)arg;
583 
584   TO_CONN(exitconn)->address = tor_strdup("torproject.org");
585 
586   strlcpy(cache_entry->address, TO_CONN(exitconn)->address,
587           sizeof(cache_entry->address));
588 
589   MOCK(router_my_exit_policy_is_reject_star,
590        dns_impl_cache_hit_pending_router_my_exit_policy_is_reject_star);
591 
592   dns_init();
593 
594   dns_insert_cache_entry(cache_entry);
595 
596   retval = dns_resolve_impl(exitconn, 1, on_circ, NULL, &made_pending,
597                             NULL);
598 
599   tt_int_op(retval,OP_EQ,0);
600   tt_int_op(made_pending,OP_EQ,1);
601 
602   pending_conn = cache_entry->pending_connections;
603 
604   tt_assert(pending_conn != NULL);
605   tt_assert(pending_conn->conn == exitconn);
606 
607   done:
608   UNMOCK(router_my_exit_policy_is_reject_star);
609   tor_free(on_circ);
610   tor_free(TO_CONN(exitconn)->address);
611   tor_free(cache_entry->pending_connections);
612   tor_free(cache_entry);
613   tor_free(exitconn);
614   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
dns_impl_cache_hit_cached_router_my_exit_policy_is_reject_star(void)622 dns_impl_cache_hit_cached_router_my_exit_policy_is_reject_star(void)
623 {
624   return 0;
625 }
626 
627 static edge_connection_t *last_exitconn = NULL;
628 static cached_resolve_t *last_resolve = NULL;
629 
630 static int
dns_impl_cache_hit_cached_set_exitconn_info_from_resolve(edge_connection_t * exitconn,const cached_resolve_t * resolve,char ** hostname_out)631 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   last_exitconn = exitconn;
637   last_resolve = (cached_resolve_t *)resolve;
638 
639   (void)hostname_out;
640 
641   return 0;
642 }
643 
644 static void
test_dns_impl_cache_hit_cached(void * arg)645 test_dns_impl_cache_hit_cached(void *arg)
646 {
647   int retval;
648   int made_pending = 0;
649 
650   edge_connection_t *exitconn = create_valid_exitconn();
651   or_circuit_t *on_circ = tor_malloc_zero(sizeof(or_circuit_t));
652 
653   cached_resolve_t *resolve_out = NULL;
654 
655   cached_resolve_t *cache_entry = tor_malloc_zero(sizeof(cached_resolve_t));
656   cache_entry->magic = CACHED_RESOLVE_MAGIC;
657   cache_entry->state = CACHE_STATE_CACHED;
658   cache_entry->minheap_idx = -1;
659   cache_entry->expire = time(NULL) + 60 * 60;
660 
661   (void)arg;
662 
663   TO_CONN(exitconn)->address = tor_strdup("torproject.org");
664 
665   strlcpy(cache_entry->address, TO_CONN(exitconn)->address,
666           sizeof(cache_entry->address));
667 
668   MOCK(router_my_exit_policy_is_reject_star,
669        dns_impl_cache_hit_cached_router_my_exit_policy_is_reject_star);
670   MOCK(set_exitconn_info_from_resolve,
671        dns_impl_cache_hit_cached_set_exitconn_info_from_resolve);
672 
673   dns_init();
674 
675   dns_insert_cache_entry(cache_entry);
676 
677   retval = dns_resolve_impl(exitconn, 1, on_circ, NULL, &made_pending,
678                             &resolve_out);
679 
680   tt_int_op(retval,OP_EQ,0);
681   tt_int_op(made_pending,OP_EQ,0);
682   tt_assert(resolve_out == cache_entry);
683 
684   tt_assert(last_exitconn == exitconn);
685   tt_assert(last_resolve == cache_entry);
686 
687   done:
688   UNMOCK(router_my_exit_policy_is_reject_star);
689   UNMOCK(set_exitconn_info_from_resolve);
690   tor_free(on_circ);
691   tor_free(TO_CONN(exitconn)->address);
692   tor_free(cache_entry->pending_connections);
693   tor_free(cache_entry);
694   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
dns_impl_cache_miss_router_my_exit_policy_is_reject_star(void)704 dns_impl_cache_miss_router_my_exit_policy_is_reject_star(void)
705 {
706   return 0;
707 }
708 
709 static cached_resolve_t *last_launched_resolve = NULL;
710 
711 static int
dns_impl_cache_miss_launch_resolve(cached_resolve_t * resolve)712 dns_impl_cache_miss_launch_resolve(cached_resolve_t *resolve)
713 {
714   last_launched_resolve = resolve;
715 
716   return 0;
717 }
718 
719 static void
test_dns_impl_cache_miss(void * arg)720 test_dns_impl_cache_miss(void *arg)
721 {
722   int retval;
723   int made_pending = 0;
724 
725   pending_connection_t *pending_conn = NULL;
726 
727   edge_connection_t *exitconn = create_valid_exitconn();
728   or_circuit_t *on_circ = tor_malloc_zero(sizeof(or_circuit_t));
729 
730   cached_resolve_t *cache_entry = NULL;
731   cached_resolve_t query;
732 
733   (void)arg;
734 
735   TO_CONN(exitconn)->address = tor_strdup("torproject.org");
736 
737   strlcpy(query.address, TO_CONN(exitconn)->address, sizeof(query.address));
738 
739   MOCK(router_my_exit_policy_is_reject_star,
740        dns_impl_cache_miss_router_my_exit_policy_is_reject_star);
741   MOCK(launch_resolve,
742        dns_impl_cache_miss_launch_resolve);
743 
744   dns_init();
745 
746   retval = dns_resolve_impl(exitconn, 1, on_circ, NULL, &made_pending,
747                             NULL);
748 
749   tt_int_op(retval,OP_EQ,0);
750   tt_int_op(made_pending,OP_EQ,1);
751 
752   cache_entry = dns_get_cache_entry(&query);
753 
754   tt_assert(cache_entry);
755 
756   pending_conn = cache_entry->pending_connections;
757 
758   tt_assert(pending_conn != NULL);
759   tt_assert(pending_conn->conn == exitconn);
760 
761   tt_assert(last_launched_resolve == cache_entry);
762   tt_str_op(cache_entry->address,OP_EQ,TO_CONN(exitconn)->address);
763 
764   done:
765   UNMOCK(router_my_exit_policy_is_reject_star);
766   UNMOCK(launch_resolve);
767   tor_free(on_circ);
768   tor_free(TO_CONN(exitconn)->address);
769   if (cache_entry)
770     tor_free(cache_entry->pending_connections);
771   tor_free(cache_entry);
772   tor_free(exitconn);
773   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 };
795