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