Merge branch 'maint-0.4.6'
[tor.git] / src / test / test_dns.c
blobdc38b53e0f615212d8baa8a9efaf67975d302446
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 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;
98 static int n_fake_impl = 0;
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;
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.
114 static int
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)
120 (void)oncirc;
121 (void)exitconn;
122 (void)is_resolve;
124 if (made_connection_pending_out)
125 *made_connection_pending_out = resolve_made_conn_pending;
127 if (hostname_out && resolved_name)
128 *hostname_out = tor_strdup(resolved_name);
130 if (resolve_out && cache_entry_mock)
131 *resolve_out = cache_entry_mock;
133 n_fake_impl++;
135 return resolve_retval;
138 static edge_connection_t *conn_for_resolved_cell = NULL;
140 static int n_send_resolved_cell_replacement = 0;
141 static uint8_t last_answer_type = 0;
142 static cached_resolve_t *last_resolved;
144 static void
145 dns_resolve_send_resolved_cell(edge_connection_t *conn, uint8_t answer_type,
146 const cached_resolve_t *resolved)
148 conn_for_resolved_cell = conn;
150 last_answer_type = answer_type;
151 last_resolved = (cached_resolve_t *)resolved;
153 n_send_resolved_cell_replacement++;
156 static int n_send_resolved_hostname_cell_replacement = 0;
158 static char *last_resolved_hostname = NULL;
160 static void
161 dns_resolve_send_resolved_hostname_cell(edge_connection_t *conn,
162 const char *hostname)
164 conn_for_resolved_cell = conn;
166 tor_free(last_resolved_hostname);
167 last_resolved_hostname = tor_strdup(hostname);
169 n_send_resolved_hostname_cell_replacement++;
172 static int n_dns_cancel_pending_resolve_replacement = 0;
174 static void
175 dns_resolve_dns_cancel_pending_resolve(const char *address)
177 (void) address;
178 n_dns_cancel_pending_resolve_replacement++;
181 static int n_connection_free = 0;
182 static connection_t *last_freed_conn = NULL;
184 static void
185 dns_resolve_connection_free_(connection_t *conn)
187 n_connection_free++;
189 last_freed_conn = conn;
192 static void
193 test_dns_resolve(void *arg)
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));
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;
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));
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);
220 * CASE 1: dns_resolve_impl returns 1 and sets a hostname. purpose is
221 * EXIT_PURPOSE_RESOLVE.
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.
228 prev_n_send_resolved_hostname_cell_replacement =
229 n_send_resolved_hostname_cell_replacement;
231 exitconn->base_.purpose = EXIT_PURPOSE_RESOLVE;
232 exitconn->on_circuit = &(on_circuit->base_);
234 resolve_retval = 1;
235 resolved_name = tor_strdup("www.torproject.org");
237 retval = dns_resolve(exitconn);
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);
246 tor_free(last_resolved_hostname);
247 // implies last_resolved_hostname = NULL;
249 /* CASE 2: dns_resolve_impl returns 1, but does not set hostname.
250 * Instead, it yields cached_resolve_t object.
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.
256 tor_free(resolved_name);
257 resolved_name = NULL;
259 exitconn->on_circuit = &(on_circuit->base_);
261 cache_entry_mock = fake_resolved;
263 prev_n_send_resolved_cell_replacement =
264 n_send_resolved_cell_replacement;
266 retval = dns_resolve(exitconn);
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);
276 /* CASE 3: The purpose of exit connection is not EXIT_PURPOSE_RESOLVE
277 * and _impl returns 1.
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.
283 exitconn->base_.purpose = EXIT_PURPOSE_CONNECT;
284 exitconn->on_circuit = &(on_circuit->base_);
286 on_circuit->n_streams = nextconn;
288 prev_n_send_resolved_cell_replacement =
289 n_send_resolved_cell_replacement;
291 prev_n_send_resolved_hostname_cell_replacement =
292 n_send_resolved_hostname_cell_replacement;
294 retval = dns_resolve(exitconn);
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);
304 /* CASE 4: _impl returns 0.
306 * We want dns_resolve() to set exitconn state to
307 * EXIT_CONN_STATE_RESOLVING and prepend exitconn to resolving_streams
308 * linked list.
311 exitconn->on_circuit = &(on_circuit->base_);
313 resolve_retval = 0;
315 exitconn->next_stream = NULL;
316 on_circuit->resolving_streams = nextconn;
318 retval = dns_resolve(exitconn);
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);
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.
330 MOCK(dns_cancel_pending_resolve,
331 dns_resolve_dns_cancel_pending_resolve);
332 MOCK(connection_free_,
333 dns_resolve_connection_free_);
335 exitconn->on_circuit = &(on_circuit->base_);
336 exitconn->base_.purpose = EXIT_PURPOSE_RESOLVE;
338 resolve_retval = -1;
340 prev_n_send_resolved_cell_replacement =
341 n_send_resolved_cell_replacement;
343 prev_n_connection_free = n_connection_free;
345 retval = dns_resolve(exitconn);
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));
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;
370 /** Create an <b>edge_connection_t</b> instance that is considered a
371 * valid exit connection by asserts in dns_resolve_impl.
373 static edge_connection_t *
374 create_valid_exitconn(void)
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;
383 return exitconn;
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.
393 static void
394 test_dns_impl_addr_is_ip(void *arg)
396 int retval;
397 int made_pending;
398 const tor_addr_t *resolved_addr;
399 tor_addr_t addr_to_compare;
401 (void)arg;
403 tor_addr_parse(&addr_to_compare, "8.8.8.8");
405 or_circuit_t *on_circ = tor_malloc_zero(sizeof(or_circuit_t));
407 edge_connection_t *exitconn = create_valid_exitconn();
409 TO_CONN(exitconn)->address = tor_strdup("8.8.8.8");
411 retval = dns_resolve_impl(exitconn, 1, on_circ, NULL, &made_pending,
412 NULL);
414 resolved_addr = &(exitconn->base_.addr);
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);
420 done:
421 tor_free(on_circ);
422 tor_free(TO_CONN(exitconn)->address);
423 tor_free(exitconn);
424 return;
427 /** Given that Tor instance is not configured as an exit node, we want
428 * dns_resolve_impl() to fail with return value -1.
430 static int
431 dns_impl_non_exit_router_my_exit_policy_is_reject_star(void)
433 return 1;
436 static void
437 test_dns_impl_non_exit(void *arg)
439 int retval;
440 int made_pending;
442 edge_connection_t *exitconn = create_valid_exitconn();
443 or_circuit_t *on_circ = tor_malloc_zero(sizeof(or_circuit_t));
445 (void)arg;
447 TO_CONN(exitconn)->address = tor_strdup("torproject.org");
449 MOCK(router_my_exit_policy_is_reject_star,
450 dns_impl_non_exit_router_my_exit_policy_is_reject_star);
452 retval = dns_resolve_impl(exitconn, 1, on_circ, NULL, &made_pending,
453 NULL);
455 tt_int_op(retval,OP_EQ,-1);
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;
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.
470 static int
471 dns_impl_addr_is_invalid_dest_router_my_exit_policy_is_reject_star(void)
473 return 0;
476 static void
477 test_dns_impl_addr_is_invalid_dest(void *arg)
479 int retval;
480 int made_pending;
482 edge_connection_t *exitconn = create_valid_exitconn();
483 or_circuit_t *on_circ = tor_malloc_zero(sizeof(or_circuit_t));
485 (void)arg;
487 MOCK(router_my_exit_policy_is_reject_star,
488 dns_impl_addr_is_invalid_dest_router_my_exit_policy_is_reject_star);
490 TO_CONN(exitconn)->address = tor_strdup("invalid#@!.org");
492 retval = dns_resolve_impl(exitconn, 1, on_circ, NULL, &made_pending,
493 NULL);
495 tt_int_op(retval,OP_EQ,-1);
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;
505 /** Given that address is a malformed PTR name, we want dns_resolve_impl to
506 * fail.
509 static int
510 dns_impl_malformed_ptr_router_my_exit_policy_is_reject_star(void)
512 return 0;
515 static void
516 test_dns_impl_malformed_ptr(void *arg)
518 int retval;
519 int made_pending;
521 edge_connection_t *exitconn = create_valid_exitconn();
522 or_circuit_t *on_circ = tor_malloc_zero(sizeof(or_circuit_t));
524 (void)arg;
526 TO_CONN(exitconn)->address = tor_strdup("1.0.0.127.in-addr.arpa");
528 MOCK(router_my_exit_policy_is_reject_star,
529 dns_impl_malformed_ptr_router_my_exit_policy_is_reject_star);
531 retval = dns_resolve_impl(exitconn, 1, on_circ, NULL, &made_pending,
532 NULL);
534 tt_int_op(retval,OP_EQ,-1);
536 tor_free(TO_CONN(exitconn)->address);
538 TO_CONN(exitconn)->address =
539 tor_strdup("z01234567890123456789.in-addr.arpa");
541 retval = dns_resolve_impl(exitconn, 1, on_circ, NULL, &made_pending,
542 NULL);
544 tt_int_op(retval,OP_EQ,-1);
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;
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.
559 static int
560 dns_impl_cache_hit_pending_router_my_exit_policy_is_reject_star(void)
562 return 0;
565 static void
566 test_dns_impl_cache_hit_pending(void *arg)
568 int retval;
569 int made_pending = 0;
571 pending_connection_t *pending_conn = NULL;
573 edge_connection_t *exitconn = create_valid_exitconn();
574 or_circuit_t *on_circ = tor_malloc_zero(sizeof(or_circuit_t));
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;
582 (void)arg;
584 TO_CONN(exitconn)->address = tor_strdup("torproject.org");
586 strlcpy(cache_entry->address, TO_CONN(exitconn)->address,
587 sizeof(cache_entry->address));
589 MOCK(router_my_exit_policy_is_reject_star,
590 dns_impl_cache_hit_pending_router_my_exit_policy_is_reject_star);
592 dns_init();
594 dns_insert_cache_entry(cache_entry);
596 retval = dns_resolve_impl(exitconn, 1, on_circ, NULL, &made_pending,
597 NULL);
599 tt_int_op(retval,OP_EQ,0);
600 tt_int_op(made_pending,OP_EQ,1);
602 pending_conn = cache_entry->pending_connections;
604 tt_assert(pending_conn != NULL);
605 tt_assert(pending_conn->conn == exitconn);
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;
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.
621 static int
622 dns_impl_cache_hit_cached_router_my_exit_policy_is_reject_star(void)
624 return 0;
627 static edge_connection_t *last_exitconn = NULL;
628 static cached_resolve_t *last_resolve = NULL;
630 static int
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)
636 last_exitconn = exitconn;
637 last_resolve = (cached_resolve_t *)resolve;
639 (void)hostname_out;
641 return 0;
644 static void
645 test_dns_impl_cache_hit_cached(void *arg)
647 int retval;
648 int made_pending = 0;
650 edge_connection_t *exitconn = create_valid_exitconn();
651 or_circuit_t *on_circ = tor_malloc_zero(sizeof(or_circuit_t));
653 cached_resolve_t *resolve_out = NULL;
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;
661 (void)arg;
663 TO_CONN(exitconn)->address = tor_strdup("torproject.org");
665 strlcpy(cache_entry->address, TO_CONN(exitconn)->address,
666 sizeof(cache_entry->address));
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);
673 dns_init();
675 dns_insert_cache_entry(cache_entry);
677 retval = dns_resolve_impl(exitconn, 1, on_circ, NULL, &made_pending,
678 &resolve_out);
680 tt_int_op(retval,OP_EQ,0);
681 tt_int_op(made_pending,OP_EQ,0);
682 tt_assert(resolve_out == cache_entry);
684 tt_assert(last_exitconn == exitconn);
685 tt_assert(last_resolve == cache_entry);
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;
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.
703 static int
704 dns_impl_cache_miss_router_my_exit_policy_is_reject_star(void)
706 return 0;
709 static cached_resolve_t *last_launched_resolve = NULL;
711 static int
712 dns_impl_cache_miss_launch_resolve(cached_resolve_t *resolve)
714 last_launched_resolve = resolve;
716 return 0;
719 static void
720 test_dns_impl_cache_miss(void *arg)
722 int retval;
723 int made_pending = 0;
725 pending_connection_t *pending_conn = NULL;
727 edge_connection_t *exitconn = create_valid_exitconn();
728 or_circuit_t *on_circ = tor_malloc_zero(sizeof(or_circuit_t));
730 cached_resolve_t *cache_entry = NULL;
731 cached_resolve_t query;
733 (void)arg;
735 TO_CONN(exitconn)->address = tor_strdup("torproject.org");
737 strlcpy(query.address, TO_CONN(exitconn)->address, sizeof(query.address));
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);
744 dns_init();
746 retval = dns_resolve_impl(exitconn, 1, on_circ, NULL, &made_pending,
747 NULL);
749 tt_int_op(retval,OP_EQ,0);
750 tt_int_op(made_pending,OP_EQ,1);
752 cache_entry = dns_get_cache_entry(&query);
754 tt_assert(cache_entry);
756 pending_conn = cache_entry->pending_connections;
758 tt_assert(pending_conn != NULL);
759 tt_assert(pending_conn->conn == exitconn);
761 tt_assert(last_launched_resolve == cache_entry);
762 tt_str_op(cache_entry->address,OP_EQ,TO_CONN(exitconn)->address);
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;
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