Merge branch 'manpage-typos' into 'main'
[tor.git] / src / test / test_dns.c
blob66123911275be83ece63e67b7d3329f01f5ff37c
1 /* Copyright (c) 2015-2021, The Tor Project, Inc. */
2 /* See LICENSE for licensing information */
4 #include "orconfig.h"
5 #include "core/or/or.h"
6 #include "test/test.h"
8 #define DNS_PRIVATE
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"
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"
20 #include <event2/event.h>
21 #include <event2/dns.h>
23 #ifdef HAVE_EVDNS_BASE_GET_NAMESERVER_ADDR
25 static or_options_t options = {
26 .ORPort_set = 1,
29 static const or_options_t *
30 mock_get_options(void)
32 return &options;
35 static void
36 test_dns_configure_ns_fallback(void *arg)
38 (void)arg;
39 tor_addr_t *nameserver_addr = NULL;
41 MOCK(get_options, mock_get_options);
43 options.ServerDNSResolvConfFile = (char *)"no_such_file!!!";
45 dns_init(); // calls configure_nameservers()
47 tt_int_op(number_of_configured_nameservers(), OP_EQ, 1);
49 nameserver_addr = configured_nameserver_address(0);
51 tt_assert(tor_addr_family(nameserver_addr) == AF_INET);
52 tt_assert(tor_addr_eq_ipv4h(nameserver_addr, 0x7f000001));
54 #ifndef _WIN32
55 tor_free(nameserver_addr);
57 options.ServerDNSResolvConfFile = (char *)"/dev/null";
59 dns_init();
61 tt_int_op(number_of_configured_nameservers(), OP_EQ, 1);
63 nameserver_addr = configured_nameserver_address(0);
65 tt_assert(tor_addr_family(nameserver_addr) == AF_INET);
66 tt_assert(tor_addr_eq_ipv4h(nameserver_addr, 0x7f000001));
67 #endif /* !defined(_WIN32) */
69 UNMOCK(get_options);
71 done:
72 tor_free(nameserver_addr);
73 return;
76 #endif /* defined(HAVE_EVDNS_BASE_GET_NAMESERVER_ADDR) */
78 static void
79 test_dns_clip_ttl(void *arg)
81 (void)arg;
83 uint32_t ttl_mid = MIN_DNS_TTL / 2 + MAX_DNS_TTL / 2;
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);
89 done:
90 return;
93 static void
94 test_dns_clip_fuzzy_ttl(void *arg)
96 (void)arg;
98 /* Case 0: check that the fuzzy TTL constant is valid
100 tt_int_op(FUZZY_DNS_TTL, OP_LE, MIN_DNS_TTL);
101 tt_int_op(FUZZY_DNS_TTL, OP_LE, MAX_DNS_TTL);
103 /* Case 1: low clips
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);
111 /* Case 2: high clips
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);
119 done:
120 return;
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;
128 static int n_fake_impl = 0;
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;
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.
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)
150 (void)oncirc;
151 (void)exitconn;
152 (void)is_resolve;
154 if (made_connection_pending_out)
155 *made_connection_pending_out = resolve_made_conn_pending;
157 if (hostname_out && resolved_name)
158 *hostname_out = tor_strdup(resolved_name);
160 if (resolve_out && cache_entry_mock)
161 *resolve_out = cache_entry_mock;
163 n_fake_impl++;
165 return resolve_retval;
168 static edge_connection_t *conn_for_resolved_cell = NULL;
170 static int n_send_resolved_cell_replacement = 0;
171 static uint8_t last_answer_type = 0;
172 static cached_resolve_t *last_resolved;
174 static void
175 dns_resolve_send_resolved_cell(edge_connection_t *conn, uint8_t answer_type,
176 const cached_resolve_t *resolved)
178 conn_for_resolved_cell = conn;
180 last_answer_type = answer_type;
181 last_resolved = (cached_resolve_t *)resolved;
183 n_send_resolved_cell_replacement++;
186 static int n_send_resolved_hostname_cell_replacement = 0;
188 static char *last_resolved_hostname = NULL;
190 static void
191 dns_resolve_send_resolved_hostname_cell(edge_connection_t *conn,
192 const char *hostname)
194 conn_for_resolved_cell = conn;
196 tor_free(last_resolved_hostname);
197 last_resolved_hostname = tor_strdup(hostname);
199 n_send_resolved_hostname_cell_replacement++;
202 static int n_dns_cancel_pending_resolve_replacement = 0;
204 static void
205 dns_resolve_dns_cancel_pending_resolve(const char *address)
207 (void) address;
208 n_dns_cancel_pending_resolve_replacement++;
211 static int n_connection_free = 0;
212 static connection_t *last_freed_conn = NULL;
214 static void
215 dns_resolve_connection_free_(connection_t *conn)
217 n_connection_free++;
219 last_freed_conn = conn;
222 static void
223 test_dns_resolve(void *arg)
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));
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;
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));
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);
250 * CASE 1: dns_resolve_impl returns 1 and sets a hostname. purpose is
251 * EXIT_PURPOSE_RESOLVE.
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.
258 prev_n_send_resolved_hostname_cell_replacement =
259 n_send_resolved_hostname_cell_replacement;
261 exitconn->base_.purpose = EXIT_PURPOSE_RESOLVE;
262 exitconn->on_circuit = &(on_circuit->base_);
264 resolve_retval = 1;
265 resolved_name = tor_strdup("www.torproject.org");
267 retval = dns_resolve(exitconn);
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);
276 tor_free(last_resolved_hostname);
277 // implies last_resolved_hostname = NULL;
279 /* CASE 2: dns_resolve_impl returns 1, but does not set hostname.
280 * Instead, it yields cached_resolve_t object.
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.
286 tor_free(resolved_name);
287 resolved_name = NULL;
289 exitconn->on_circuit = &(on_circuit->base_);
291 cache_entry_mock = fake_resolved;
293 prev_n_send_resolved_cell_replacement =
294 n_send_resolved_cell_replacement;
296 retval = dns_resolve(exitconn);
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);
306 /* CASE 3: The purpose of exit connection is not EXIT_PURPOSE_RESOLVE
307 * and _impl returns 1.
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.
313 exitconn->base_.purpose = EXIT_PURPOSE_CONNECT;
314 exitconn->on_circuit = &(on_circuit->base_);
316 on_circuit->n_streams = nextconn;
318 prev_n_send_resolved_cell_replacement =
319 n_send_resolved_cell_replacement;
321 prev_n_send_resolved_hostname_cell_replacement =
322 n_send_resolved_hostname_cell_replacement;
324 retval = dns_resolve(exitconn);
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);
334 /* CASE 4: _impl returns 0.
336 * We want dns_resolve() to set exitconn state to
337 * EXIT_CONN_STATE_RESOLVING and prepend exitconn to resolving_streams
338 * linked list.
341 exitconn->on_circuit = &(on_circuit->base_);
343 resolve_retval = 0;
345 exitconn->next_stream = NULL;
346 on_circuit->resolving_streams = nextconn;
348 retval = dns_resolve(exitconn);
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);
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.
360 MOCK(dns_cancel_pending_resolve,
361 dns_resolve_dns_cancel_pending_resolve);
362 MOCK(connection_free_,
363 dns_resolve_connection_free_);
365 exitconn->on_circuit = &(on_circuit->base_);
366 exitconn->base_.purpose = EXIT_PURPOSE_RESOLVE;
368 resolve_retval = -1;
370 prev_n_send_resolved_cell_replacement =
371 n_send_resolved_cell_replacement;
373 prev_n_connection_free = n_connection_free;
375 retval = dns_resolve(exitconn);
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));
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;
400 /** Create an <b>edge_connection_t</b> instance that is considered a
401 * valid exit connection by asserts in dns_resolve_impl.
403 static edge_connection_t *
404 create_valid_exitconn(void)
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;
413 return exitconn;
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.
423 static void
424 test_dns_impl_addr_is_ip(void *arg)
426 int retval;
427 int made_pending;
428 const tor_addr_t *resolved_addr;
429 tor_addr_t addr_to_compare;
431 (void)arg;
433 tor_addr_parse(&addr_to_compare, "8.8.8.8");
435 or_circuit_t *on_circ = tor_malloc_zero(sizeof(or_circuit_t));
437 edge_connection_t *exitconn = create_valid_exitconn();
439 TO_CONN(exitconn)->address = tor_strdup("8.8.8.8");
441 retval = dns_resolve_impl(exitconn, 1, on_circ, NULL, &made_pending,
442 NULL);
444 resolved_addr = &(exitconn->base_.addr);
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);
450 done:
451 tor_free(on_circ);
452 tor_free(TO_CONN(exitconn)->address);
453 tor_free(exitconn);
454 return;
457 /** Given that Tor instance is not configured as an exit node, we want
458 * dns_resolve_impl() to fail with return value -1.
460 static int
461 dns_impl_non_exit_router_my_exit_policy_is_reject_star(void)
463 return 1;
466 static void
467 test_dns_impl_non_exit(void *arg)
469 int retval;
470 int made_pending;
472 edge_connection_t *exitconn = create_valid_exitconn();
473 or_circuit_t *on_circ = tor_malloc_zero(sizeof(or_circuit_t));
475 (void)arg;
477 TO_CONN(exitconn)->address = tor_strdup("torproject.org");
479 MOCK(router_my_exit_policy_is_reject_star,
480 dns_impl_non_exit_router_my_exit_policy_is_reject_star);
482 retval = dns_resolve_impl(exitconn, 1, on_circ, NULL, &made_pending,
483 NULL);
485 tt_int_op(retval,OP_EQ,-1);
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;
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.
500 static int
501 dns_impl_addr_is_invalid_dest_router_my_exit_policy_is_reject_star(void)
503 return 0;
506 static void
507 test_dns_impl_addr_is_invalid_dest(void *arg)
509 int retval;
510 int made_pending;
512 edge_connection_t *exitconn = create_valid_exitconn();
513 or_circuit_t *on_circ = tor_malloc_zero(sizeof(or_circuit_t));
515 (void)arg;
517 MOCK(router_my_exit_policy_is_reject_star,
518 dns_impl_addr_is_invalid_dest_router_my_exit_policy_is_reject_star);
520 TO_CONN(exitconn)->address = tor_strdup("invalid#@!.org");
522 retval = dns_resolve_impl(exitconn, 1, on_circ, NULL, &made_pending,
523 NULL);
525 tt_int_op(retval,OP_EQ,-1);
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;
535 /** Given that address is a malformed PTR name, we want dns_resolve_impl to
536 * fail.
539 static int
540 dns_impl_malformed_ptr_router_my_exit_policy_is_reject_star(void)
542 return 0;
545 static void
546 test_dns_impl_malformed_ptr(void *arg)
548 int retval;
549 int made_pending;
551 edge_connection_t *exitconn = create_valid_exitconn();
552 or_circuit_t *on_circ = tor_malloc_zero(sizeof(or_circuit_t));
554 (void)arg;
556 TO_CONN(exitconn)->address = tor_strdup("1.0.0.127.in-addr.arpa");
558 MOCK(router_my_exit_policy_is_reject_star,
559 dns_impl_malformed_ptr_router_my_exit_policy_is_reject_star);
561 retval = dns_resolve_impl(exitconn, 1, on_circ, NULL, &made_pending,
562 NULL);
564 tt_int_op(retval,OP_EQ,-1);
566 tor_free(TO_CONN(exitconn)->address);
568 TO_CONN(exitconn)->address =
569 tor_strdup("z01234567890123456789.in-addr.arpa");
571 retval = dns_resolve_impl(exitconn, 1, on_circ, NULL, &made_pending,
572 NULL);
574 tt_int_op(retval,OP_EQ,-1);
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;
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.
589 static int
590 dns_impl_cache_hit_pending_router_my_exit_policy_is_reject_star(void)
592 return 0;
595 static void
596 test_dns_impl_cache_hit_pending(void *arg)
598 int retval;
599 int made_pending = 0;
601 pending_connection_t *pending_conn = NULL;
603 edge_connection_t *exitconn = create_valid_exitconn();
604 or_circuit_t *on_circ = tor_malloc_zero(sizeof(or_circuit_t));
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;
612 (void)arg;
614 TO_CONN(exitconn)->address = tor_strdup("torproject.org");
616 strlcpy(cache_entry->address, TO_CONN(exitconn)->address,
617 sizeof(cache_entry->address));
619 MOCK(router_my_exit_policy_is_reject_star,
620 dns_impl_cache_hit_pending_router_my_exit_policy_is_reject_star);
622 dns_init();
624 dns_insert_cache_entry(cache_entry);
626 retval = dns_resolve_impl(exitconn, 1, on_circ, NULL, &made_pending,
627 NULL);
629 tt_int_op(retval,OP_EQ,0);
630 tt_int_op(made_pending,OP_EQ,1);
632 pending_conn = cache_entry->pending_connections;
634 tt_assert(pending_conn != NULL);
635 tt_assert(pending_conn->conn == exitconn);
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;
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.
651 static int
652 dns_impl_cache_hit_cached_router_my_exit_policy_is_reject_star(void)
654 return 0;
657 static edge_connection_t *last_exitconn = NULL;
658 static cached_resolve_t *last_resolve = NULL;
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)
666 last_exitconn = exitconn;
667 last_resolve = (cached_resolve_t *)resolve;
669 (void)hostname_out;
671 return 0;
674 static void
675 test_dns_impl_cache_hit_cached(void *arg)
677 int retval;
678 int made_pending = 0;
680 edge_connection_t *exitconn = create_valid_exitconn();
681 or_circuit_t *on_circ = tor_malloc_zero(sizeof(or_circuit_t));
683 cached_resolve_t *resolve_out = NULL;
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;
691 (void)arg;
693 TO_CONN(exitconn)->address = tor_strdup("torproject.org");
695 strlcpy(cache_entry->address, TO_CONN(exitconn)->address,
696 sizeof(cache_entry->address));
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);
703 dns_init();
705 dns_insert_cache_entry(cache_entry);
707 retval = dns_resolve_impl(exitconn, 1, on_circ, NULL, &made_pending,
708 &resolve_out);
710 tt_int_op(retval,OP_EQ,0);
711 tt_int_op(made_pending,OP_EQ,0);
712 tt_assert(resolve_out == cache_entry);
714 tt_assert(last_exitconn == exitconn);
715 tt_assert(last_resolve == cache_entry);
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;
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.
733 static int
734 dns_impl_cache_miss_router_my_exit_policy_is_reject_star(void)
736 return 0;
739 static cached_resolve_t *last_launched_resolve = NULL;
741 static int
742 dns_impl_cache_miss_launch_resolve(cached_resolve_t *resolve)
744 last_launched_resolve = resolve;
746 return 0;
749 static void
750 test_dns_impl_cache_miss(void *arg)
752 int retval;
753 int made_pending = 0;
755 pending_connection_t *pending_conn = NULL;
757 edge_connection_t *exitconn = create_valid_exitconn();
758 or_circuit_t *on_circ = tor_malloc_zero(sizeof(or_circuit_t));
760 cached_resolve_t *cache_entry = NULL;
761 cached_resolve_t query;
763 (void)arg;
765 TO_CONN(exitconn)->address = tor_strdup("torproject.org");
767 strlcpy(query.address, TO_CONN(exitconn)->address, sizeof(query.address));
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);
774 dns_init();
776 retval = dns_resolve_impl(exitconn, 1, on_circ, NULL, &made_pending,
777 NULL);
779 tt_int_op(retval,OP_EQ,0);
780 tt_int_op(made_pending,OP_EQ,1);
782 cache_entry = dns_get_cache_entry(&query);
784 tt_assert(cache_entry);
786 pending_conn = cache_entry->pending_connections;
788 tt_assert(pending_conn != NULL);
789 tt_assert(pending_conn->conn == exitconn);
791 tt_assert(last_launched_resolve == cache_entry);
792 tt_str_op(cache_entry->address,OP_EQ,TO_CONN(exitconn)->address);
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;
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