7 #include "connection.h"
12 #define NS_SUBMODULE clip_ttl
15 NS(test_main
)(void *arg
)
19 uint32_t ttl_mid
= MIN_DNS_TTL
/ 2 + MAX_DNS_TTL
/ 2;
21 tt_int_op(dns_clip_ttl(MIN_DNS_TTL
- 1),==,MIN_DNS_TTL
);
22 tt_int_op(dns_clip_ttl(ttl_mid
),==,ttl_mid
);
23 tt_int_op(dns_clip_ttl(MAX_DNS_TTL
+ 1),==,MAX_DNS_TTL
);
31 #define NS_SUBMODULE expiry_ttl
34 NS(test_main
)(void *arg
)
38 uint32_t ttl_mid
= MIN_DNS_TTL
/ 2 + MAX_DNS_ENTRY_AGE
/ 2;
40 tt_int_op(dns_get_expiry_ttl(MIN_DNS_TTL
- 1),==,MIN_DNS_TTL
);
41 tt_int_op(dns_get_expiry_ttl(ttl_mid
),==,ttl_mid
);
42 tt_int_op(dns_get_expiry_ttl(MAX_DNS_ENTRY_AGE
+ 1),==,MAX_DNS_ENTRY_AGE
);
50 #define NS_SUBMODULE resolve
52 static int resolve_retval
= 0;
53 static int resolve_made_conn_pending
= 0;
54 static char *resolved_name
= NULL
;
55 static cached_resolve_t
*cache_entry
= NULL
;
57 static int n_fake_impl
= 0;
59 NS_DECL(int, dns_resolve_impl
, (edge_connection_t
*exitconn
, int is_resolve
,
60 or_circuit_t
*oncirc
, char **hostname_out
,
61 int *made_connection_pending_out
,
62 cached_resolve_t
**resolve_out
));
64 /** This will be our configurable substitute for <b>dns_resolve_impl</b> in
65 * dns.c. It will return <b>resolve_retval</b>,
66 * and set <b>resolve_made_conn_pending</b> to
67 * <b>made_connection_pending_out</b>. It will set <b>hostname_out</b>
68 * to a duplicate of <b>resolved_name</b> and it will set <b>resolve_out</b>
69 * to <b>cache_entry</b>. Lastly, it will increment <b>n_fake_impl</b< by
73 NS(dns_resolve_impl
)(edge_connection_t
*exitconn
, int is_resolve
,
74 or_circuit_t
*oncirc
, char **hostname_out
,
75 int *made_connection_pending_out
,
76 cached_resolve_t
**resolve_out
)
82 if (made_connection_pending_out
)
83 *made_connection_pending_out
= resolve_made_conn_pending
;
85 if (hostname_out
&& resolved_name
)
86 *hostname_out
= tor_strdup(resolved_name
);
88 if (resolve_out
&& cache_entry
)
89 *resolve_out
= cache_entry
;
93 return resolve_retval
;
96 static edge_connection_t
*conn_for_resolved_cell
= NULL
;
98 static int n_send_resolved_cell_replacement
= 0;
99 static uint8_t last_answer_type
= 0;
100 static cached_resolve_t
*last_resolved
;
103 NS(send_resolved_cell
)(edge_connection_t
*conn
, uint8_t answer_type
,
104 const cached_resolve_t
*resolved
)
106 conn_for_resolved_cell
= conn
;
108 last_answer_type
= answer_type
;
109 last_resolved
= (cached_resolve_t
*)resolved
;
111 n_send_resolved_cell_replacement
++;
114 static int n_send_resolved_hostname_cell_replacement
= 0;
116 static char *last_resolved_hostname
= NULL
;
119 NS(send_resolved_hostname_cell
)(edge_connection_t
*conn
,
120 const char *hostname
)
122 conn_for_resolved_cell
= conn
;
124 tor_free(last_resolved_hostname
);
125 last_resolved_hostname
= tor_strdup(hostname
);
127 n_send_resolved_hostname_cell_replacement
++;
130 static int n_dns_cancel_pending_resolve_replacement
= 0;
133 NS(dns_cancel_pending_resolve
)(const char *address
)
136 n_dns_cancel_pending_resolve_replacement
++;
139 static int n_connection_free
= 0;
140 static connection_t
*last_freed_conn
= NULL
;
143 NS(connection_free
)(connection_t
*conn
)
147 last_freed_conn
= conn
;
151 NS(test_main
)(void *arg
)
155 int prev_n_send_resolved_hostname_cell_replacement
;
156 int prev_n_send_resolved_cell_replacement
;
157 int prev_n_connection_free
;
158 cached_resolve_t
*fake_resolved
= tor_malloc(sizeof(cached_resolve_t
));
159 edge_connection_t
*exitconn
= tor_malloc(sizeof(edge_connection_t
));
160 edge_connection_t
*nextconn
= tor_malloc(sizeof(edge_connection_t
));
162 or_circuit_t
*on_circuit
= tor_malloc(sizeof(or_circuit_t
));
163 memset(on_circuit
,0,sizeof(or_circuit_t
));
164 on_circuit
->base_
.magic
= OR_CIRCUIT_MAGIC
;
166 memset(fake_resolved
,0,sizeof(cached_resolve_t
));
167 memset(exitconn
,0,sizeof(edge_connection_t
));
168 memset(nextconn
,0,sizeof(edge_connection_t
));
170 NS_MOCK(dns_resolve_impl
);
171 NS_MOCK(send_resolved_cell
);
172 NS_MOCK(send_resolved_hostname_cell
);
175 * CASE 1: dns_resolve_impl returns 1 and sets a hostname. purpose is
176 * EXIT_PURPOSE_RESOLVE.
178 * We want dns_resolve() to call send_resolved_hostname_cell() for a
179 * given exit connection (represented by edge_connection_t object)
180 * with a hostname it received from _impl.
183 prev_n_send_resolved_hostname_cell_replacement
=
184 n_send_resolved_hostname_cell_replacement
;
186 exitconn
->base_
.purpose
= EXIT_PURPOSE_RESOLVE
;
187 exitconn
->on_circuit
= &(on_circuit
->base_
);
190 resolved_name
= tor_strdup("www.torproject.org");
192 retval
= dns_resolve(exitconn
);
194 tt_int_op(retval
,==,1);
195 tt_str_op(resolved_name
,==,last_resolved_hostname
);
196 tt_assert(conn_for_resolved_cell
== exitconn
);
197 tt_int_op(n_send_resolved_hostname_cell_replacement
,==,
198 prev_n_send_resolved_hostname_cell_replacement
+ 1);
199 tt_assert(exitconn
->on_circuit
== NULL
);
201 tor_free(last_resolved_hostname
);
202 // implies last_resolved_hostname = NULL;
204 /* CASE 2: dns_resolve_impl returns 1, but does not set hostname.
205 * Instead, it yields cached_resolve_t object.
207 * We want dns_resolve to call send_resolved_cell on exitconn with
208 * RESOLVED_TYPE_AUTO and the cached_resolve_t object from _impl.
211 tor_free(resolved_name
);
212 resolved_name
= NULL
;
214 exitconn
->on_circuit
= &(on_circuit
->base_
);
216 cache_entry
= fake_resolved
;
218 prev_n_send_resolved_cell_replacement
=
219 n_send_resolved_cell_replacement
;
221 retval
= dns_resolve(exitconn
);
223 tt_int_op(retval
,==,1);
224 tt_assert(conn_for_resolved_cell
== exitconn
);
225 tt_int_op(n_send_resolved_cell_replacement
,==,
226 prev_n_send_resolved_cell_replacement
+ 1);
227 tt_assert(last_resolved
== fake_resolved
);
228 tt_int_op(last_answer_type
,==,0xff);
229 tt_assert(exitconn
->on_circuit
== NULL
);
231 /* CASE 3: The purpose of exit connection is not EXIT_PURPOSE_RESOLVE
232 * and _impl returns 1.
234 * We want dns_resolve to prepend exitconn to n_streams linked list.
235 * We don't want it to send any cells about hostname being resolved.
238 exitconn
->base_
.purpose
= EXIT_PURPOSE_CONNECT
;
239 exitconn
->on_circuit
= &(on_circuit
->base_
);
241 on_circuit
->n_streams
= nextconn
;
243 prev_n_send_resolved_cell_replacement
=
244 n_send_resolved_cell_replacement
;
246 prev_n_send_resolved_hostname_cell_replacement
=
247 n_send_resolved_hostname_cell_replacement
;
249 retval
= dns_resolve(exitconn
);
251 tt_int_op(retval
,==,1);
252 tt_assert(on_circuit
->n_streams
== exitconn
);
253 tt_assert(exitconn
->next_stream
== nextconn
);
254 tt_int_op(prev_n_send_resolved_cell_replacement
,==,
255 n_send_resolved_cell_replacement
);
256 tt_int_op(prev_n_send_resolved_hostname_cell_replacement
,==,
257 n_send_resolved_hostname_cell_replacement
);
259 /* CASE 4: _impl returns 0.
261 * We want dns_resolve() to set exitconn state to
262 * EXIT_CONN_STATE_RESOLVING and prepend exitconn to resolving_streams
266 exitconn
->on_circuit
= &(on_circuit
->base_
);
270 exitconn
->next_stream
= NULL
;
271 on_circuit
->resolving_streams
= nextconn
;
273 retval
= dns_resolve(exitconn
);
275 tt_int_op(retval
,==,0);
276 tt_int_op(exitconn
->base_
.state
,==,EXIT_CONN_STATE_RESOLVING
);
277 tt_assert(on_circuit
->resolving_streams
== exitconn
);
278 tt_assert(exitconn
->next_stream
== nextconn
);
280 /* CASE 5: _impl returns -1 when purpose of exitconn is
281 * EXIT_PURPOSE_RESOLVE. We want dns_resolve to call send_resolved_cell
282 * on exitconn with type being RESOLVED_TYPE_ERROR.
285 NS_MOCK(dns_cancel_pending_resolve
);
286 NS_MOCK(connection_free
);
288 exitconn
->on_circuit
= &(on_circuit
->base_
);
289 exitconn
->base_
.purpose
= EXIT_PURPOSE_RESOLVE
;
293 prev_n_send_resolved_cell_replacement
=
294 n_send_resolved_cell_replacement
;
296 prev_n_connection_free
= n_connection_free
;
298 retval
= dns_resolve(exitconn
);
300 tt_int_op(retval
,==,-1);
301 tt_int_op(n_send_resolved_cell_replacement
,==,
302 prev_n_send_resolved_cell_replacement
+ 1);
303 tt_int_op(last_answer_type
,==,RESOLVED_TYPE_ERROR
);
304 tt_int_op(n_dns_cancel_pending_resolve_replacement
,==,1);
305 tt_int_op(n_connection_free
,==,prev_n_connection_free
+ 1);
306 tt_assert(last_freed_conn
== TO_CONN(exitconn
));
309 NS_UNMOCK(dns_resolve_impl
);
310 NS_UNMOCK(send_resolved_cell
);
311 NS_UNMOCK(send_resolved_hostname_cell
);
312 NS_UNMOCK(dns_cancel_pending_resolve
);
313 NS_UNMOCK(connection_free
);
314 tor_free(on_circuit
);
317 tor_free(resolved_name
);
318 tor_free(fake_resolved
);
319 tor_free(last_resolved_hostname
);
325 /** Create an <b>edge_connection_t</b> instance that is considered a
326 * valid exit connection by asserts in dns_resolve_impl.
328 static edge_connection_t
*
329 create_valid_exitconn(void)
331 edge_connection_t
*exitconn
= tor_malloc_zero(sizeof(edge_connection_t
));
332 TO_CONN(exitconn
)->type
= CONN_TYPE_EXIT
;
333 TO_CONN(exitconn
)->magic
= EDGE_CONNECTION_MAGIC
;
334 TO_CONN(exitconn
)->purpose
= EXIT_PURPOSE_RESOLVE
;
335 TO_CONN(exitconn
)->state
= EXIT_CONN_STATE_RESOLVING
;
336 exitconn
->base_
.s
= TOR_INVALID_SOCKET
;
341 #define NS_SUBMODULE ASPECT(resolve_impl, addr_is_ip_no_need_to_resolve)
344 * Given that <b>exitconn->base_.address</b> is IP address string, we
345 * want dns_resolve_impl() to parse it and store in
346 * <b>exitconn->base_.addr</b>. We expect dns_resolve_impl to return 1.
347 * Lastly, we want it to set the TTL value to default one for DNS queries.
351 NS(test_main
)(void *arg
)
355 const tor_addr_t
*resolved_addr
;
356 tor_addr_t addr_to_compare
;
360 tor_addr_parse(&addr_to_compare
, "8.8.8.8");
362 or_circuit_t
*on_circ
= tor_malloc_zero(sizeof(or_circuit_t
));
364 edge_connection_t
*exitconn
= create_valid_exitconn();
366 TO_CONN(exitconn
)->address
= tor_strdup("8.8.8.8");
368 retval
= dns_resolve_impl(exitconn
, 1, on_circ
, NULL
, &made_pending
,
371 resolved_addr
= &(exitconn
->base_
.addr
);
373 tt_int_op(retval
,==,1);
374 tt_assert(tor_addr_eq(resolved_addr
, (const tor_addr_t
*)&addr_to_compare
));
375 tt_int_op(exitconn
->address_ttl
,==,DEFAULT_DNS_TTL
);
379 tor_free(TO_CONN(exitconn
)->address
);
386 #define NS_SUBMODULE ASPECT(resolve_impl, non_exit)
388 /** Given that Tor instance is not configured as an exit node, we want
389 * dns_resolve_impl() to fail with return value -1.
392 NS(router_my_exit_policy_is_reject_star
)(void)
398 NS(test_main
)(void *arg
)
403 edge_connection_t
*exitconn
= create_valid_exitconn();
404 or_circuit_t
*on_circ
= tor_malloc_zero(sizeof(or_circuit_t
));
408 TO_CONN(exitconn
)->address
= tor_strdup("torproject.org");
410 NS_MOCK(router_my_exit_policy_is_reject_star
);
412 retval
= dns_resolve_impl(exitconn
, 1, on_circ
, NULL
, &made_pending
,
415 tt_int_op(retval
,==,-1);
418 tor_free(TO_CONN(exitconn
)->address
);
421 NS_UNMOCK(router_my_exit_policy_is_reject_star
);
427 #define NS_SUBMODULE ASPECT(resolve_impl, addr_is_invalid_dest)
429 /** Given that address is not a valid destination (as judged by
430 * address_is_invalid_destination() function), we want dns_resolve_impl()
431 * function to fail with return value -1.
435 NS(router_my_exit_policy_is_reject_star
)(void)
441 NS(test_main
)(void *arg
)
446 edge_connection_t
*exitconn
= create_valid_exitconn();
447 or_circuit_t
*on_circ
= tor_malloc_zero(sizeof(or_circuit_t
));
451 NS_MOCK(router_my_exit_policy_is_reject_star
);
453 TO_CONN(exitconn
)->address
= tor_strdup("invalid#@!.org");
455 retval
= dns_resolve_impl(exitconn
, 1, on_circ
, NULL
, &made_pending
,
458 tt_int_op(retval
,==,-1);
461 NS_UNMOCK(router_my_exit_policy_is_reject_star
);
462 tor_free(TO_CONN(exitconn
)->address
);
470 #define NS_SUBMODULE ASPECT(resolve_impl, malformed_ptr)
472 /** Given that address is a malformed PTR name, we want dns_resolve_impl to
477 NS(router_my_exit_policy_is_reject_star
)(void)
483 NS(test_main
)(void *arg
)
488 edge_connection_t
*exitconn
= create_valid_exitconn();
489 or_circuit_t
*on_circ
= tor_malloc_zero(sizeof(or_circuit_t
));
493 TO_CONN(exitconn
)->address
= tor_strdup("1.0.0.127.in-addr.arpa");
495 NS_MOCK(router_my_exit_policy_is_reject_star
);
497 retval
= dns_resolve_impl(exitconn
, 1, on_circ
, NULL
, &made_pending
,
500 tt_int_op(retval
,==,-1);
502 tor_free(TO_CONN(exitconn
)->address
);
504 TO_CONN(exitconn
)->address
=
505 tor_strdup("z01234567890123456789.in-addr.arpa");
507 retval
= dns_resolve_impl(exitconn
, 1, on_circ
, NULL
, &made_pending
,
510 tt_int_op(retval
,==,-1);
513 NS_UNMOCK(router_my_exit_policy_is_reject_star
);
514 tor_free(TO_CONN(exitconn
)->address
);
522 #define NS_SUBMODULE ASPECT(resolve_impl, cache_hit_pending)
524 /* Given that there is already a pending resolve for the given address,
525 * we want dns_resolve_impl to append our exit connection to list
526 * of pending connections for the pending DNS request and return 0.
530 NS(router_my_exit_policy_is_reject_star
)(void)
536 NS(test_main
)(void *arg
)
539 int made_pending
= 0;
541 pending_connection_t
*pending_conn
= NULL
;
543 edge_connection_t
*exitconn
= create_valid_exitconn();
544 or_circuit_t
*on_circ
= tor_malloc_zero(sizeof(or_circuit_t
));
546 cached_resolve_t
*cache_entry
= tor_malloc_zero(sizeof(cached_resolve_t
));
547 cache_entry
->magic
= CACHED_RESOLVE_MAGIC
;
548 cache_entry
->state
= CACHE_STATE_PENDING
;
549 cache_entry
->minheap_idx
= -1;
550 cache_entry
->expire
= time(NULL
) + 60 * 60;
554 TO_CONN(exitconn
)->address
= tor_strdup("torproject.org");
556 strlcpy(cache_entry
->address
, TO_CONN(exitconn
)->address
,
557 sizeof(cache_entry
->address
));
559 NS_MOCK(router_my_exit_policy_is_reject_star
);
563 dns_insert_cache_entry(cache_entry
);
565 retval
= dns_resolve_impl(exitconn
, 1, on_circ
, NULL
, &made_pending
,
568 tt_int_op(retval
,==,0);
569 tt_int_op(made_pending
,==,1);
571 pending_conn
= cache_entry
->pending_connections
;
573 tt_assert(pending_conn
!= NULL
);
574 tt_assert(pending_conn
->conn
== exitconn
);
577 NS_UNMOCK(router_my_exit_policy_is_reject_star
);
579 tor_free(TO_CONN(exitconn
)->address
);
580 tor_free(cache_entry
->pending_connections
);
581 tor_free(cache_entry
);
588 #define NS_SUBMODULE ASPECT(resolve_impl, cache_hit_cached)
590 /* Given that a finished DNS resolve is available in our cache, we want
591 * dns_resolve_impl() return it to called via resolve_out and pass the
592 * handling to set_exitconn_info_from_resolve function.
595 NS(router_my_exit_policy_is_reject_star
)(void)
600 static edge_connection_t
*last_exitconn
= NULL
;
601 static cached_resolve_t
*last_resolve
= NULL
;
604 NS(set_exitconn_info_from_resolve
)(edge_connection_t
*exitconn
,
605 const cached_resolve_t
*resolve
,
608 last_exitconn
= exitconn
;
609 last_resolve
= (cached_resolve_t
*)resolve
;
617 NS(test_main
)(void *arg
)
620 int made_pending
= 0;
622 edge_connection_t
*exitconn
= create_valid_exitconn();
623 or_circuit_t
*on_circ
= tor_malloc_zero(sizeof(or_circuit_t
));
625 cached_resolve_t
*resolve_out
= NULL
;
627 cached_resolve_t
*cache_entry
= tor_malloc_zero(sizeof(cached_resolve_t
));
628 cache_entry
->magic
= CACHED_RESOLVE_MAGIC
;
629 cache_entry
->state
= CACHE_STATE_CACHED
;
630 cache_entry
->minheap_idx
= -1;
631 cache_entry
->expire
= time(NULL
) + 60 * 60;
635 TO_CONN(exitconn
)->address
= tor_strdup("torproject.org");
637 strlcpy(cache_entry
->address
, TO_CONN(exitconn
)->address
,
638 sizeof(cache_entry
->address
));
640 NS_MOCK(router_my_exit_policy_is_reject_star
);
641 NS_MOCK(set_exitconn_info_from_resolve
);
645 dns_insert_cache_entry(cache_entry
);
647 retval
= dns_resolve_impl(exitconn
, 1, on_circ
, NULL
, &made_pending
,
650 tt_int_op(retval
,==,0);
651 tt_int_op(made_pending
,==,0);
652 tt_assert(resolve_out
== cache_entry
);
654 tt_assert(last_exitconn
== exitconn
);
655 tt_assert(last_resolve
== cache_entry
);
658 NS_UNMOCK(router_my_exit_policy_is_reject_star
);
659 NS_UNMOCK(set_exitconn_info_from_resolve
);
661 tor_free(TO_CONN(exitconn
)->address
);
662 tor_free(cache_entry
->pending_connections
);
663 tor_free(cache_entry
);
669 #define NS_SUBMODULE ASPECT(resolve_impl, cache_miss)
671 /* Given that there are neither pending nor pre-cached resolve for a given
672 * address, we want dns_resolve_impl() to create a new cached_resolve_t
673 * object, mark it as pending, insert it into the cache, attach the exit
674 * connection to list of pending connections and call launch_resolve()
675 * with the cached_resolve_t object it created.
678 NS(router_my_exit_policy_is_reject_star
)(void)
683 static cached_resolve_t
*last_launched_resolve
= NULL
;
686 NS(launch_resolve
)(cached_resolve_t
*resolve
)
688 last_launched_resolve
= resolve
;
694 NS(test_main
)(void *arg
)
697 int made_pending
= 0;
699 pending_connection_t
*pending_conn
= NULL
;
701 edge_connection_t
*exitconn
= create_valid_exitconn();
702 or_circuit_t
*on_circ
= tor_malloc_zero(sizeof(or_circuit_t
));
704 cached_resolve_t
*cache_entry
= NULL
;
705 cached_resolve_t query
;
709 TO_CONN(exitconn
)->address
= tor_strdup("torproject.org");
711 strlcpy(query
.address
, TO_CONN(exitconn
)->address
, sizeof(query
.address
));
713 NS_MOCK(router_my_exit_policy_is_reject_star
);
714 NS_MOCK(launch_resolve
);
718 retval
= dns_resolve_impl(exitconn
, 1, on_circ
, NULL
, &made_pending
,
721 tt_int_op(retval
,==,0);
722 tt_int_op(made_pending
,==,1);
724 cache_entry
= dns_get_cache_entry(&query
);
726 tt_assert(cache_entry
);
728 pending_conn
= cache_entry
->pending_connections
;
730 tt_assert(pending_conn
!= NULL
);
731 tt_assert(pending_conn
->conn
== exitconn
);
733 tt_assert(last_launched_resolve
== cache_entry
);
734 tt_str_op(cache_entry
->address
,==,TO_CONN(exitconn
)->address
);
737 NS_UNMOCK(router_my_exit_policy_is_reject_star
);
738 NS_UNMOCK(launch_resolve
);
740 tor_free(TO_CONN(exitconn
)->address
);
742 tor_free(cache_entry
->pending_connections
);
743 tor_free(cache_entry
);
750 struct testcase_t dns_tests
[] = {
752 TEST_CASE(expiry_ttl
),
754 TEST_CASE_ASPECT(resolve_impl
, addr_is_ip_no_need_to_resolve
),
755 TEST_CASE_ASPECT(resolve_impl
, non_exit
),
756 TEST_CASE_ASPECT(resolve_impl
, addr_is_invalid_dest
),
757 TEST_CASE_ASPECT(resolve_impl
, malformed_ptr
),
758 TEST_CASE_ASPECT(resolve_impl
, cache_hit_pending
),
759 TEST_CASE_ASPECT(resolve_impl
, cache_hit_cached
),
760 TEST_CASE_ASPECT(resolve_impl
, cache_miss
),