7 #include "connection.h"
12 #define NS_SUBMODULE clip_ttl
15 NS(test_main
)(void *arg
)
19 uint32_t ttl_mid
= MIN_DNS_TTL_AT_EXIT
/ 2 + MAX_DNS_TTL_AT_EXIT
/ 2;
21 tt_int_op(dns_clip_ttl(MIN_DNS_TTL_AT_EXIT
- 1),==,MIN_DNS_TTL_AT_EXIT
);
22 tt_int_op(dns_clip_ttl(ttl_mid
),==,MAX_DNS_TTL_AT_EXIT
);
23 tt_int_op(dns_clip_ttl(MAX_DNS_TTL_AT_EXIT
+ 1),==,MAX_DNS_TTL_AT_EXIT
);
31 #define NS_SUBMODULE resolve
33 static int resolve_retval
= 0;
34 static int resolve_made_conn_pending
= 0;
35 static char *resolved_name
= NULL
;
36 static cached_resolve_t
*cache_entry_mock
= NULL
;
38 static int n_fake_impl
= 0;
40 NS_DECL(int, dns_resolve_impl
, (edge_connection_t
*exitconn
, int is_resolve
,
41 or_circuit_t
*oncirc
, char **hostname_out
,
42 int *made_connection_pending_out
,
43 cached_resolve_t
**resolve_out
));
45 /** This will be our configurable substitute for <b>dns_resolve_impl</b> in
46 * dns.c. It will return <b>resolve_retval</b>,
47 * and set <b>resolve_made_conn_pending</b> to
48 * <b>made_connection_pending_out</b>. It will set <b>hostname_out</b>
49 * to a duplicate of <b>resolved_name</b> and it will set <b>resolve_out</b>
50 * to <b>cache_entry</b>. Lastly, it will increment <b>n_fake_impl</b< by
54 NS(dns_resolve_impl
)(edge_connection_t
*exitconn
, int is_resolve
,
55 or_circuit_t
*oncirc
, char **hostname_out
,
56 int *made_connection_pending_out
,
57 cached_resolve_t
**resolve_out
)
63 if (made_connection_pending_out
)
64 *made_connection_pending_out
= resolve_made_conn_pending
;
66 if (hostname_out
&& resolved_name
)
67 *hostname_out
= tor_strdup(resolved_name
);
69 if (resolve_out
&& cache_entry_mock
)
70 *resolve_out
= cache_entry_mock
;
74 return resolve_retval
;
77 static edge_connection_t
*conn_for_resolved_cell
= NULL
;
79 static int n_send_resolved_cell_replacement
= 0;
80 static uint8_t last_answer_type
= 0;
81 static cached_resolve_t
*last_resolved
;
84 NS(send_resolved_cell
)(edge_connection_t
*conn
, uint8_t answer_type
,
85 const cached_resolve_t
*resolved
)
87 conn_for_resolved_cell
= conn
;
89 last_answer_type
= answer_type
;
90 last_resolved
= (cached_resolve_t
*)resolved
;
92 n_send_resolved_cell_replacement
++;
95 static int n_send_resolved_hostname_cell_replacement
= 0;
97 static char *last_resolved_hostname
= NULL
;
100 NS(send_resolved_hostname_cell
)(edge_connection_t
*conn
,
101 const char *hostname
)
103 conn_for_resolved_cell
= conn
;
105 tor_free(last_resolved_hostname
);
106 last_resolved_hostname
= tor_strdup(hostname
);
108 n_send_resolved_hostname_cell_replacement
++;
111 static int n_dns_cancel_pending_resolve_replacement
= 0;
114 NS(dns_cancel_pending_resolve
)(const char *address
)
117 n_dns_cancel_pending_resolve_replacement
++;
120 static int n_connection_free
= 0;
121 static connection_t
*last_freed_conn
= NULL
;
124 NS(connection_free
)(connection_t
*conn
)
128 last_freed_conn
= conn
;
132 NS(test_main
)(void *arg
)
136 int prev_n_send_resolved_hostname_cell_replacement
;
137 int prev_n_send_resolved_cell_replacement
;
138 int prev_n_connection_free
;
139 cached_resolve_t
*fake_resolved
= tor_malloc(sizeof(cached_resolve_t
));
140 edge_connection_t
*exitconn
= tor_malloc(sizeof(edge_connection_t
));
141 edge_connection_t
*nextconn
= tor_malloc(sizeof(edge_connection_t
));
143 or_circuit_t
*on_circuit
= tor_malloc(sizeof(or_circuit_t
));
144 memset(on_circuit
,0,sizeof(or_circuit_t
));
145 on_circuit
->base_
.magic
= OR_CIRCUIT_MAGIC
;
147 memset(fake_resolved
,0,sizeof(cached_resolve_t
));
148 memset(exitconn
,0,sizeof(edge_connection_t
));
149 memset(nextconn
,0,sizeof(edge_connection_t
));
151 NS_MOCK(dns_resolve_impl
);
152 NS_MOCK(send_resolved_cell
);
153 NS_MOCK(send_resolved_hostname_cell
);
156 * CASE 1: dns_resolve_impl returns 1 and sets a hostname. purpose is
157 * EXIT_PURPOSE_RESOLVE.
159 * We want dns_resolve() to call send_resolved_hostname_cell() for a
160 * given exit connection (represented by edge_connection_t object)
161 * with a hostname it received from _impl.
164 prev_n_send_resolved_hostname_cell_replacement
=
165 n_send_resolved_hostname_cell_replacement
;
167 exitconn
->base_
.purpose
= EXIT_PURPOSE_RESOLVE
;
168 exitconn
->on_circuit
= &(on_circuit
->base_
);
171 resolved_name
= tor_strdup("www.torproject.org");
173 retval
= dns_resolve(exitconn
);
175 tt_int_op(retval
,==,1);
176 tt_str_op(resolved_name
,==,last_resolved_hostname
);
177 tt_assert(conn_for_resolved_cell
== exitconn
);
178 tt_int_op(n_send_resolved_hostname_cell_replacement
,==,
179 prev_n_send_resolved_hostname_cell_replacement
+ 1);
180 tt_assert(exitconn
->on_circuit
== NULL
);
182 tor_free(last_resolved_hostname
);
183 // implies last_resolved_hostname = NULL;
185 /* CASE 2: dns_resolve_impl returns 1, but does not set hostname.
186 * Instead, it yields cached_resolve_t object.
188 * We want dns_resolve to call send_resolved_cell on exitconn with
189 * RESOLVED_TYPE_AUTO and the cached_resolve_t object from _impl.
192 tor_free(resolved_name
);
193 resolved_name
= NULL
;
195 exitconn
->on_circuit
= &(on_circuit
->base_
);
197 cache_entry_mock
= fake_resolved
;
199 prev_n_send_resolved_cell_replacement
=
200 n_send_resolved_cell_replacement
;
202 retval
= dns_resolve(exitconn
);
204 tt_int_op(retval
,==,1);
205 tt_assert(conn_for_resolved_cell
== exitconn
);
206 tt_int_op(n_send_resolved_cell_replacement
,==,
207 prev_n_send_resolved_cell_replacement
+ 1);
208 tt_assert(last_resolved
== fake_resolved
);
209 tt_int_op(last_answer_type
,==,0xff);
210 tt_assert(exitconn
->on_circuit
== NULL
);
212 /* CASE 3: The purpose of exit connection is not EXIT_PURPOSE_RESOLVE
213 * and _impl returns 1.
215 * We want dns_resolve to prepend exitconn to n_streams linked list.
216 * We don't want it to send any cells about hostname being resolved.
219 exitconn
->base_
.purpose
= EXIT_PURPOSE_CONNECT
;
220 exitconn
->on_circuit
= &(on_circuit
->base_
);
222 on_circuit
->n_streams
= nextconn
;
224 prev_n_send_resolved_cell_replacement
=
225 n_send_resolved_cell_replacement
;
227 prev_n_send_resolved_hostname_cell_replacement
=
228 n_send_resolved_hostname_cell_replacement
;
230 retval
= dns_resolve(exitconn
);
232 tt_int_op(retval
,==,1);
233 tt_assert(on_circuit
->n_streams
== exitconn
);
234 tt_assert(exitconn
->next_stream
== nextconn
);
235 tt_int_op(prev_n_send_resolved_cell_replacement
,==,
236 n_send_resolved_cell_replacement
);
237 tt_int_op(prev_n_send_resolved_hostname_cell_replacement
,==,
238 n_send_resolved_hostname_cell_replacement
);
240 /* CASE 4: _impl returns 0.
242 * We want dns_resolve() to set exitconn state to
243 * EXIT_CONN_STATE_RESOLVING and prepend exitconn to resolving_streams
247 exitconn
->on_circuit
= &(on_circuit
->base_
);
251 exitconn
->next_stream
= NULL
;
252 on_circuit
->resolving_streams
= nextconn
;
254 retval
= dns_resolve(exitconn
);
256 tt_int_op(retval
,==,0);
257 tt_int_op(exitconn
->base_
.state
,==,EXIT_CONN_STATE_RESOLVING
);
258 tt_assert(on_circuit
->resolving_streams
== exitconn
);
259 tt_assert(exitconn
->next_stream
== nextconn
);
261 /* CASE 5: _impl returns -1 when purpose of exitconn is
262 * EXIT_PURPOSE_RESOLVE. We want dns_resolve to call send_resolved_cell
263 * on exitconn with type being RESOLVED_TYPE_ERROR.
266 NS_MOCK(dns_cancel_pending_resolve
);
267 NS_MOCK(connection_free
);
269 exitconn
->on_circuit
= &(on_circuit
->base_
);
270 exitconn
->base_
.purpose
= EXIT_PURPOSE_RESOLVE
;
274 prev_n_send_resolved_cell_replacement
=
275 n_send_resolved_cell_replacement
;
277 prev_n_connection_free
= n_connection_free
;
279 retval
= dns_resolve(exitconn
);
281 tt_int_op(retval
,==,-1);
282 tt_int_op(n_send_resolved_cell_replacement
,==,
283 prev_n_send_resolved_cell_replacement
+ 1);
284 tt_int_op(last_answer_type
,==,RESOLVED_TYPE_ERROR
);
285 tt_int_op(n_dns_cancel_pending_resolve_replacement
,==,1);
286 tt_int_op(n_connection_free
,==,prev_n_connection_free
+ 1);
287 tt_assert(last_freed_conn
== TO_CONN(exitconn
));
290 NS_UNMOCK(dns_resolve_impl
);
291 NS_UNMOCK(send_resolved_cell
);
292 NS_UNMOCK(send_resolved_hostname_cell
);
293 NS_UNMOCK(dns_cancel_pending_resolve
);
294 NS_UNMOCK(connection_free
);
295 tor_free(on_circuit
);
298 tor_free(resolved_name
);
299 tor_free(fake_resolved
);
300 tor_free(last_resolved_hostname
);
306 /** Create an <b>edge_connection_t</b> instance that is considered a
307 * valid exit connection by asserts in dns_resolve_impl.
309 static edge_connection_t
*
310 create_valid_exitconn(void)
312 edge_connection_t
*exitconn
= tor_malloc_zero(sizeof(edge_connection_t
));
313 TO_CONN(exitconn
)->type
= CONN_TYPE_EXIT
;
314 TO_CONN(exitconn
)->magic
= EDGE_CONNECTION_MAGIC
;
315 TO_CONN(exitconn
)->purpose
= EXIT_PURPOSE_RESOLVE
;
316 TO_CONN(exitconn
)->state
= EXIT_CONN_STATE_RESOLVING
;
317 exitconn
->base_
.s
= TOR_INVALID_SOCKET
;
322 #define NS_SUBMODULE ASPECT(resolve_impl, addr_is_ip_no_need_to_resolve)
325 * Given that <b>exitconn->base_.address</b> is IP address string, we
326 * want dns_resolve_impl() to parse it and store in
327 * <b>exitconn->base_.addr</b>. We expect dns_resolve_impl to return 1.
328 * Lastly, we want it to set the TTL value to default one for DNS queries.
332 NS(test_main
)(void *arg
)
336 const tor_addr_t
*resolved_addr
;
337 tor_addr_t addr_to_compare
;
341 tor_addr_parse(&addr_to_compare
, "8.8.8.8");
343 or_circuit_t
*on_circ
= tor_malloc_zero(sizeof(or_circuit_t
));
345 edge_connection_t
*exitconn
= create_valid_exitconn();
347 TO_CONN(exitconn
)->address
= tor_strdup("8.8.8.8");
349 retval
= dns_resolve_impl(exitconn
, 1, on_circ
, NULL
, &made_pending
,
352 resolved_addr
= &(exitconn
->base_
.addr
);
354 tt_int_op(retval
,==,1);
355 tt_assert(tor_addr_eq(resolved_addr
, (const tor_addr_t
*)&addr_to_compare
));
356 tt_int_op(exitconn
->address_ttl
,==,DEFAULT_DNS_TTL
);
360 tor_free(TO_CONN(exitconn
)->address
);
367 #define NS_SUBMODULE ASPECT(resolve_impl, non_exit)
369 /** Given that Tor instance is not configured as an exit node, we want
370 * dns_resolve_impl() to fail with return value -1.
373 NS(router_my_exit_policy_is_reject_star
)(void)
379 NS(test_main
)(void *arg
)
384 edge_connection_t
*exitconn
= create_valid_exitconn();
385 or_circuit_t
*on_circ
= tor_malloc_zero(sizeof(or_circuit_t
));
389 TO_CONN(exitconn
)->address
= tor_strdup("torproject.org");
391 NS_MOCK(router_my_exit_policy_is_reject_star
);
393 retval
= dns_resolve_impl(exitconn
, 1, on_circ
, NULL
, &made_pending
,
396 tt_int_op(retval
,==,-1);
399 tor_free(TO_CONN(exitconn
)->address
);
402 NS_UNMOCK(router_my_exit_policy_is_reject_star
);
408 #define NS_SUBMODULE ASPECT(resolve_impl, addr_is_invalid_dest)
410 /** Given that address is not a valid destination (as judged by
411 * address_is_invalid_destination() function), we want dns_resolve_impl()
412 * function to fail with return value -1.
416 NS(router_my_exit_policy_is_reject_star
)(void)
422 NS(test_main
)(void *arg
)
427 edge_connection_t
*exitconn
= create_valid_exitconn();
428 or_circuit_t
*on_circ
= tor_malloc_zero(sizeof(or_circuit_t
));
432 NS_MOCK(router_my_exit_policy_is_reject_star
);
434 TO_CONN(exitconn
)->address
= tor_strdup("invalid#@!.org");
436 retval
= dns_resolve_impl(exitconn
, 1, on_circ
, NULL
, &made_pending
,
439 tt_int_op(retval
,==,-1);
442 NS_UNMOCK(router_my_exit_policy_is_reject_star
);
443 tor_free(TO_CONN(exitconn
)->address
);
451 #define NS_SUBMODULE ASPECT(resolve_impl, malformed_ptr)
453 /** Given that address is a malformed PTR name, we want dns_resolve_impl to
458 NS(router_my_exit_policy_is_reject_star
)(void)
464 NS(test_main
)(void *arg
)
469 edge_connection_t
*exitconn
= create_valid_exitconn();
470 or_circuit_t
*on_circ
= tor_malloc_zero(sizeof(or_circuit_t
));
474 TO_CONN(exitconn
)->address
= tor_strdup("1.0.0.127.in-addr.arpa");
476 NS_MOCK(router_my_exit_policy_is_reject_star
);
478 retval
= dns_resolve_impl(exitconn
, 1, on_circ
, NULL
, &made_pending
,
481 tt_int_op(retval
,==,-1);
483 tor_free(TO_CONN(exitconn
)->address
);
485 TO_CONN(exitconn
)->address
=
486 tor_strdup("z01234567890123456789.in-addr.arpa");
488 retval
= dns_resolve_impl(exitconn
, 1, on_circ
, NULL
, &made_pending
,
491 tt_int_op(retval
,==,-1);
494 NS_UNMOCK(router_my_exit_policy_is_reject_star
);
495 tor_free(TO_CONN(exitconn
)->address
);
503 #define NS_SUBMODULE ASPECT(resolve_impl, cache_hit_pending)
505 /* Given that there is already a pending resolve for the given address,
506 * we want dns_resolve_impl to append our exit connection to list
507 * of pending connections for the pending DNS request and return 0.
511 NS(router_my_exit_policy_is_reject_star
)(void)
517 NS(test_main
)(void *arg
)
520 int made_pending
= 0;
522 pending_connection_t
*pending_conn
= NULL
;
524 edge_connection_t
*exitconn
= create_valid_exitconn();
525 or_circuit_t
*on_circ
= tor_malloc_zero(sizeof(or_circuit_t
));
527 cached_resolve_t
*cache_entry
= tor_malloc_zero(sizeof(cached_resolve_t
));
528 cache_entry
->magic
= CACHED_RESOLVE_MAGIC
;
529 cache_entry
->state
= CACHE_STATE_PENDING
;
530 cache_entry
->minheap_idx
= -1;
531 cache_entry
->expire
= time(NULL
) + 60 * 60;
535 TO_CONN(exitconn
)->address
= tor_strdup("torproject.org");
537 strlcpy(cache_entry
->address
, TO_CONN(exitconn
)->address
,
538 sizeof(cache_entry
->address
));
540 NS_MOCK(router_my_exit_policy_is_reject_star
);
544 dns_insert_cache_entry(cache_entry
);
546 retval
= dns_resolve_impl(exitconn
, 1, on_circ
, NULL
, &made_pending
,
549 tt_int_op(retval
,==,0);
550 tt_int_op(made_pending
,==,1);
552 pending_conn
= cache_entry
->pending_connections
;
554 tt_assert(pending_conn
!= NULL
);
555 tt_assert(pending_conn
->conn
== exitconn
);
558 NS_UNMOCK(router_my_exit_policy_is_reject_star
);
560 tor_free(TO_CONN(exitconn
)->address
);
561 tor_free(cache_entry
->pending_connections
);
562 tor_free(cache_entry
);
569 #define NS_SUBMODULE ASPECT(resolve_impl, cache_hit_cached)
571 /* Given that a finished DNS resolve is available in our cache, we want
572 * dns_resolve_impl() return it to called via resolve_out and pass the
573 * handling to set_exitconn_info_from_resolve function.
576 NS(router_my_exit_policy_is_reject_star
)(void)
581 static edge_connection_t
*last_exitconn
= NULL
;
582 static cached_resolve_t
*last_resolve
= NULL
;
585 NS(set_exitconn_info_from_resolve
)(edge_connection_t
*exitconn
,
586 const cached_resolve_t
*resolve
,
589 last_exitconn
= exitconn
;
590 last_resolve
= (cached_resolve_t
*)resolve
;
598 NS(test_main
)(void *arg
)
601 int made_pending
= 0;
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
*resolve_out
= NULL
;
608 cached_resolve_t
*cache_entry
= tor_malloc_zero(sizeof(cached_resolve_t
));
609 cache_entry
->magic
= CACHED_RESOLVE_MAGIC
;
610 cache_entry
->state
= CACHE_STATE_CACHED
;
611 cache_entry
->minheap_idx
= -1;
612 cache_entry
->expire
= time(NULL
) + 60 * 60;
616 TO_CONN(exitconn
)->address
= tor_strdup("torproject.org");
618 strlcpy(cache_entry
->address
, TO_CONN(exitconn
)->address
,
619 sizeof(cache_entry
->address
));
621 NS_MOCK(router_my_exit_policy_is_reject_star
);
622 NS_MOCK(set_exitconn_info_from_resolve
);
626 dns_insert_cache_entry(cache_entry
);
628 retval
= dns_resolve_impl(exitconn
, 1, on_circ
, NULL
, &made_pending
,
631 tt_int_op(retval
,==,0);
632 tt_int_op(made_pending
,==,0);
633 tt_assert(resolve_out
== cache_entry
);
635 tt_assert(last_exitconn
== exitconn
);
636 tt_assert(last_resolve
== cache_entry
);
639 NS_UNMOCK(router_my_exit_policy_is_reject_star
);
640 NS_UNMOCK(set_exitconn_info_from_resolve
);
642 tor_free(TO_CONN(exitconn
)->address
);
643 tor_free(cache_entry
->pending_connections
);
644 tor_free(cache_entry
);
650 #define NS_SUBMODULE ASPECT(resolve_impl, cache_miss)
652 /* Given that there are neither pending nor pre-cached resolve for a given
653 * address, we want dns_resolve_impl() to create a new cached_resolve_t
654 * object, mark it as pending, insert it into the cache, attach the exit
655 * connection to list of pending connections and call launch_resolve()
656 * with the cached_resolve_t object it created.
659 NS(router_my_exit_policy_is_reject_star
)(void)
664 static cached_resolve_t
*last_launched_resolve
= NULL
;
667 NS(launch_resolve
)(cached_resolve_t
*resolve
)
669 last_launched_resolve
= resolve
;
675 NS(test_main
)(void *arg
)
678 int made_pending
= 0;
680 pending_connection_t
*pending_conn
= NULL
;
682 edge_connection_t
*exitconn
= create_valid_exitconn();
683 or_circuit_t
*on_circ
= tor_malloc_zero(sizeof(or_circuit_t
));
685 cached_resolve_t
*cache_entry
= NULL
;
686 cached_resolve_t query
;
690 TO_CONN(exitconn
)->address
= tor_strdup("torproject.org");
692 strlcpy(query
.address
, TO_CONN(exitconn
)->address
, sizeof(query
.address
));
694 NS_MOCK(router_my_exit_policy_is_reject_star
);
695 NS_MOCK(launch_resolve
);
699 retval
= dns_resolve_impl(exitconn
, 1, on_circ
, NULL
, &made_pending
,
702 tt_int_op(retval
,==,0);
703 tt_int_op(made_pending
,==,1);
705 cache_entry
= dns_get_cache_entry(&query
);
707 tt_assert(cache_entry
);
709 pending_conn
= cache_entry
->pending_connections
;
711 tt_assert(pending_conn
!= NULL
);
712 tt_assert(pending_conn
->conn
== exitconn
);
714 tt_assert(last_launched_resolve
== cache_entry
);
715 tt_str_op(cache_entry
->address
,==,TO_CONN(exitconn
)->address
);
718 NS_UNMOCK(router_my_exit_policy_is_reject_star
);
719 NS_UNMOCK(launch_resolve
);
721 tor_free(TO_CONN(exitconn
)->address
);
723 tor_free(cache_entry
->pending_connections
);
724 tor_free(cache_entry
);
731 struct testcase_t dns_tests
[] = {
734 TEST_CASE_ASPECT(resolve_impl
, addr_is_ip_no_need_to_resolve
),
735 TEST_CASE_ASPECT(resolve_impl
, non_exit
),
736 TEST_CASE_ASPECT(resolve_impl
, addr_is_invalid_dest
),
737 TEST_CASE_ASPECT(resolve_impl
, malformed_ptr
),
738 TEST_CASE_ASPECT(resolve_impl
, cache_hit_pending
),
739 TEST_CASE_ASPECT(resolve_impl
, cache_hit_cached
),
740 TEST_CASE_ASPECT(resolve_impl
, cache_miss
),