test_dns.c 19.4 KB
Newer Older
1
2
3
/* Copyright (c) 2015-2017, The Tor Project, Inc. */
/* See LICENSE for licensing information */

4
5
6
7
8
9
10
#include "or.h"
#include "test.h"

#define DNS_PRIVATE

#include "dns.h"
#include "connection.h"
11
#include "router.h"
12

rl1987's avatar
rl1987 committed
13
14
15
16
#define NS_MODULE dns

#define NS_SUBMODULE clip_ttl

17
static void
rl1987's avatar
rl1987 committed
18
NS(test_main)(void *arg)
19
20
21
{
  (void)arg;

22
  uint32_t ttl_mid = MIN_DNS_TTL_AT_EXIT / 2 + MAX_DNS_TTL_AT_EXIT / 2;
23

24
25
26
  tt_int_op(dns_clip_ttl(MIN_DNS_TTL_AT_EXIT - 1),OP_EQ,MIN_DNS_TTL_AT_EXIT);
  tt_int_op(dns_clip_ttl(ttl_mid),OP_EQ,MAX_DNS_TTL_AT_EXIT);
  tt_int_op(dns_clip_ttl(MAX_DNS_TTL_AT_EXIT + 1),OP_EQ,MAX_DNS_TTL_AT_EXIT);
27
28
29
30
31

  done:
  return;
}

rl1987's avatar
rl1987 committed
32
33
34
35
#undef NS_SUBMODULE

#define NS_SUBMODULE resolve

36
37
38
static int resolve_retval = 0;
static int resolve_made_conn_pending = 0;
static char *resolved_name = NULL;
39
static cached_resolve_t *cache_entry_mock = NULL;
40
41
42

static int n_fake_impl = 0;

43
44
45
46
47
NS_DECL(int, dns_resolve_impl, (edge_connection_t *exitconn, int is_resolve,
                                or_circuit_t *oncirc, char **hostname_out,
                                int *made_connection_pending_out,
                                cached_resolve_t **resolve_out));

48
49
50
51
52
53
54
55
/** This will be our configurable substitute for <b>dns_resolve_impl</b> in
 * dns.c. It will return <b>resolve_retval</b>,
 * and set <b>resolve_made_conn_pending</b> to
 * <b>made_connection_pending_out</b>. It will set <b>hostname_out</b>
 * to a duplicate of <b>resolved_name</b> and it will set <b>resolve_out</b>
 * to <b>cache_entry</b>. Lastly, it will increment <b>n_fake_impl</b< by
 * 1.
 */
56
static int
57
58
59
60
NS(dns_resolve_impl)(edge_connection_t *exitconn, int is_resolve,
                     or_circuit_t *oncirc, char **hostname_out,
                     int *made_connection_pending_out,
                     cached_resolve_t **resolve_out)
61
{
62
63
64
65
  (void)oncirc;
  (void)exitconn;
  (void)is_resolve;

66
67
68
69
70
71
  if (made_connection_pending_out)
    *made_connection_pending_out = resolve_made_conn_pending;

  if (hostname_out && resolved_name)
    *hostname_out = tor_strdup(resolved_name);

72
73
  if (resolve_out && cache_entry_mock)
    *resolve_out = cache_entry_mock;
74
75
76
77
78
79
80
81
82
83
84
85
86

  n_fake_impl++;

  return resolve_retval;
}

static edge_connection_t *conn_for_resolved_cell = NULL;

static int n_send_resolved_cell_replacement = 0;
static uint8_t last_answer_type = 0;
static cached_resolve_t *last_resolved;

static void
87
88
NS(send_resolved_cell)(edge_connection_t *conn, uint8_t answer_type,
                       const cached_resolve_t *resolved)
89
90
{
  conn_for_resolved_cell = conn;
91

92
93
94
95
96
97
98
99
100
101
102
  last_answer_type = answer_type;
  last_resolved = (cached_resolve_t *)resolved;

  n_send_resolved_cell_replacement++;
}

static int n_send_resolved_hostname_cell_replacement = 0;

static char *last_resolved_hostname = NULL;

static void
103
104
NS(send_resolved_hostname_cell)(edge_connection_t *conn,
                                const char *hostname)
105
106
107
{
  conn_for_resolved_cell = conn;

108
109
  tor_free(last_resolved_hostname);
  last_resolved_hostname = tor_strdup(hostname);
110
111
112
113
114
115
116

  n_send_resolved_hostname_cell_replacement++;
}

static int n_dns_cancel_pending_resolve_replacement = 0;

static void
117
NS(dns_cancel_pending_resolve)(const char *address)
118
{
119
  (void) address;
120
121
122
123
124
125
126
  n_dns_cancel_pending_resolve_replacement++;
}

static int n_connection_free = 0;
static connection_t *last_freed_conn = NULL;

static void
127
NS(connection_free_)(connection_t *conn)
128
129
130
131
132
133
134
{
   n_connection_free++;

   last_freed_conn = conn;
}

static void
rl1987's avatar
rl1987 committed
135
NS(test_main)(void *arg)
136
{
137
  (void) arg;
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
  int retval;
  int prev_n_send_resolved_hostname_cell_replacement;
  int prev_n_send_resolved_cell_replacement;
  int prev_n_connection_free;
  cached_resolve_t *fake_resolved = tor_malloc(sizeof(cached_resolve_t));
  edge_connection_t *exitconn = tor_malloc(sizeof(edge_connection_t));
  edge_connection_t *nextconn = tor_malloc(sizeof(edge_connection_t));

  or_circuit_t *on_circuit = tor_malloc(sizeof(or_circuit_t));
  memset(on_circuit,0,sizeof(or_circuit_t));
  on_circuit->base_.magic = OR_CIRCUIT_MAGIC;

  memset(fake_resolved,0,sizeof(cached_resolve_t));
  memset(exitconn,0,sizeof(edge_connection_t));
  memset(nextconn,0,sizeof(edge_connection_t));

154
155
156
  NS_MOCK(dns_resolve_impl);
  NS_MOCK(send_resolved_cell);
  NS_MOCK(send_resolved_hostname_cell);
157
158
159
160
161
162
163
164

  /*
   * CASE 1: dns_resolve_impl returns 1 and sets a hostname. purpose is
   * EXIT_PURPOSE_RESOLVE.
   *
   * We want dns_resolve() to call send_resolved_hostname_cell() for a
   * given exit connection (represented by edge_connection_t object)
   * with a hostname it received from _impl.
165
   */
166

167
  prev_n_send_resolved_hostname_cell_replacement =
168
169
170
171
172
173
174
175
176
  n_send_resolved_hostname_cell_replacement;

  exitconn->base_.purpose = EXIT_PURPOSE_RESOLVE;
  exitconn->on_circuit = &(on_circuit->base_);

  resolve_retval = 1;
  resolved_name = tor_strdup("www.torproject.org");

  retval = dns_resolve(exitconn);
177

178
179
  tt_int_op(retval,OP_EQ,1);
  tt_str_op(resolved_name,OP_EQ,last_resolved_hostname);
180
  tt_assert(conn_for_resolved_cell == exitconn);
181
  tt_int_op(n_send_resolved_hostname_cell_replacement,OP_EQ,
182
183
184
            prev_n_send_resolved_hostname_cell_replacement + 1);
  tt_assert(exitconn->on_circuit == NULL);

185
186
  tor_free(last_resolved_hostname);
  // implies last_resolved_hostname = NULL;
187
188
189
190

  /* CASE 2: dns_resolve_impl returns 1, but does not set hostname.
   * Instead, it yields cached_resolve_t object.
   *
191
   * We want dns_resolve to call send_resolved_cell on exitconn with
192
193
194
195
196
197
198
199
   * RESOLVED_TYPE_AUTO and the cached_resolve_t object from _impl.
   */

  tor_free(resolved_name);
  resolved_name = NULL;

  exitconn->on_circuit = &(on_circuit->base_);

200
  cache_entry_mock = fake_resolved;
201
202
203
204
205
206

  prev_n_send_resolved_cell_replacement =
  n_send_resolved_cell_replacement;

  retval = dns_resolve(exitconn);

207
  tt_int_op(retval,OP_EQ,1);
208
  tt_assert(conn_for_resolved_cell == exitconn);
209
  tt_int_op(n_send_resolved_cell_replacement,OP_EQ,
210
211
            prev_n_send_resolved_cell_replacement + 1);
  tt_assert(last_resolved == fake_resolved);
212
  tt_int_op(last_answer_type,OP_EQ,0xff);
213
214
215
216
  tt_assert(exitconn->on_circuit == NULL);

  /* CASE 3: The purpose of exit connection is not EXIT_PURPOSE_RESOLVE
   * and _impl returns 1.
217
   *
218
219
220
221
222
223
224
225
226
227
228
229
   * We want dns_resolve to prepend exitconn to n_streams linked list.
   * We don't want it to send any cells about hostname being resolved.
   */

  exitconn->base_.purpose = EXIT_PURPOSE_CONNECT;
  exitconn->on_circuit = &(on_circuit->base_);

  on_circuit->n_streams = nextconn;

  prev_n_send_resolved_cell_replacement =
  n_send_resolved_cell_replacement;

230
  prev_n_send_resolved_hostname_cell_replacement =
231
232
233
234
  n_send_resolved_hostname_cell_replacement;

  retval = dns_resolve(exitconn);

235
  tt_int_op(retval,OP_EQ,1);
236
237
  tt_assert(on_circuit->n_streams == exitconn);
  tt_assert(exitconn->next_stream == nextconn);
238
  tt_int_op(prev_n_send_resolved_cell_replacement,OP_EQ,
239
            n_send_resolved_cell_replacement);
240
  tt_int_op(prev_n_send_resolved_hostname_cell_replacement,OP_EQ,
241
242
            n_send_resolved_hostname_cell_replacement);

243
244
245
  /* CASE 4: _impl returns 0.
   *
   * We want dns_resolve() to set exitconn state to
246
247
   * EXIT_CONN_STATE_RESOLVING and prepend exitconn to resolving_streams
   * linked list.
248
   */
249
250
251
252
253
254
255
256
257
258

  exitconn->on_circuit = &(on_circuit->base_);

  resolve_retval = 0;

  exitconn->next_stream = NULL;
  on_circuit->resolving_streams = nextconn;

  retval = dns_resolve(exitconn);

259
260
  tt_int_op(retval,OP_EQ,0);
  tt_int_op(exitconn->base_.state,OP_EQ,EXIT_CONN_STATE_RESOLVING);
261
262
263
  tt_assert(on_circuit->resolving_streams == exitconn);
  tt_assert(exitconn->next_stream == nextconn);

264
  /* CASE 5: _impl returns -1 when purpose of exitconn is
265
266
   * EXIT_PURPOSE_RESOLVE. We want dns_resolve to call send_resolved_cell
   * on exitconn with type being RESOLVED_TYPE_ERROR.
267
   */
268

269
  NS_MOCK(dns_cancel_pending_resolve);
270
  NS_MOCK(connection_free_);
271
272
273
274
275
276
277
278
279
280
281
282
283

  exitconn->on_circuit = &(on_circuit->base_);
  exitconn->base_.purpose = EXIT_PURPOSE_RESOLVE;

  resolve_retval = -1;

  prev_n_send_resolved_cell_replacement =
  n_send_resolved_cell_replacement;

  prev_n_connection_free = n_connection_free;

  retval = dns_resolve(exitconn);

284
285
  tt_int_op(retval,OP_EQ,-1);
  tt_int_op(n_send_resolved_cell_replacement,OP_EQ,
286
            prev_n_send_resolved_cell_replacement + 1);
287
288
289
  tt_int_op(last_answer_type,OP_EQ,RESOLVED_TYPE_ERROR);
  tt_int_op(n_dns_cancel_pending_resolve_replacement,OP_EQ,1);
  tt_int_op(n_connection_free,OP_EQ,prev_n_connection_free + 1);
290
291
292
  tt_assert(last_freed_conn == TO_CONN(exitconn));

  done:
293
294
295
296
  NS_UNMOCK(dns_resolve_impl);
  NS_UNMOCK(send_resolved_cell);
  NS_UNMOCK(send_resolved_hostname_cell);
  NS_UNMOCK(dns_cancel_pending_resolve);
297
  NS_UNMOCK(connection_free_);
298
299
300
301
302
  tor_free(on_circuit);
  tor_free(exitconn);
  tor_free(nextconn);
  tor_free(resolved_name);
  tor_free(fake_resolved);
303
  tor_free(last_resolved_hostname);
304
305
306
  return;
}

rl1987's avatar
rl1987 committed
307
308
#undef NS_SUBMODULE

rl1987's avatar
rl1987 committed
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
/** Create an <b>edge_connection_t</b> instance that is considered a
 * valid exit connection by asserts in dns_resolve_impl.
 */
static edge_connection_t *
create_valid_exitconn(void)
{
  edge_connection_t *exitconn = tor_malloc_zero(sizeof(edge_connection_t));
  TO_CONN(exitconn)->type = CONN_TYPE_EXIT;
  TO_CONN(exitconn)->magic = EDGE_CONNECTION_MAGIC;
  TO_CONN(exitconn)->purpose = EXIT_PURPOSE_RESOLVE;
  TO_CONN(exitconn)->state = EXIT_CONN_STATE_RESOLVING;
  exitconn->base_.s = TOR_INVALID_SOCKET;

  return exitconn;
}

325
326
327
328
#define NS_SUBMODULE ASPECT(resolve_impl, addr_is_ip_no_need_to_resolve)

/*
 * Given that <b>exitconn->base_.address</b> is IP address string, we
rl1987's avatar
rl1987 committed
329
 * want dns_resolve_impl() to parse it and store in
330
331
332
333
334
335
336
337
338
339
340
341
 * <b>exitconn->base_.addr</b>. We expect dns_resolve_impl to return 1.
 * Lastly, we want it to set the TTL value to default one for DNS queries.
 */

static void
NS(test_main)(void *arg)
{
  int retval;
  int made_pending;
  const tor_addr_t *resolved_addr;
  tor_addr_t addr_to_compare;

rl1987's avatar
rl1987 committed
342
343
  (void)arg;

344
345
346
347
  tor_addr_parse(&addr_to_compare, "8.8.8.8");

  or_circuit_t *on_circ = tor_malloc_zero(sizeof(or_circuit_t));

rl1987's avatar
rl1987 committed
348
  edge_connection_t *exitconn = create_valid_exitconn();
349

rl1987's avatar
rl1987 committed
350
  TO_CONN(exitconn)->address = tor_strdup("8.8.8.8");
351
352
353
354
355
356

  retval = dns_resolve_impl(exitconn, 1, on_circ, NULL, &made_pending,
                            NULL);

  resolved_addr = &(exitconn->base_.addr);

357
  tt_int_op(retval,OP_EQ,1);
rl1987's avatar
rl1987 committed
358
  tt_assert(tor_addr_eq(resolved_addr, (const tor_addr_t *)&addr_to_compare));
359
  tt_int_op(exitconn->address_ttl,OP_EQ,DEFAULT_DNS_TTL);
rl1987's avatar
rl1987 committed
360

361
362
363
364
365
366
367
368
369
370
371
  done:
  tor_free(on_circ);
  tor_free(TO_CONN(exitconn)->address);
  tor_free(exitconn);
  return;
}

#undef NS_SUBMODULE

#define NS_SUBMODULE ASPECT(resolve_impl, non_exit)

372
373
374
375
376
377
378
379
380
/** Given that Tor instance is not configured as an exit node, we want
 * dns_resolve_impl() to fail with return value -1.
 */
static int
NS(router_my_exit_policy_is_reject_star)(void)
{
  return 1;
}

381
382
383
static void
NS(test_main)(void *arg)
{
384
385
386
387
388
389
  int retval;
  int made_pending;

  edge_connection_t *exitconn = create_valid_exitconn();
  or_circuit_t *on_circ = tor_malloc_zero(sizeof(or_circuit_t));

rl1987's avatar
rl1987 committed
390
391
  (void)arg;

rl1987's avatar
rl1987 committed
392
  TO_CONN(exitconn)->address = tor_strdup("torproject.org");
393
394
395
396
397
398

  NS_MOCK(router_my_exit_policy_is_reject_star);

  retval = dns_resolve_impl(exitconn, 1, on_circ, NULL, &made_pending,
                            NULL);

399
  tt_int_op(retval,OP_EQ,-1);
400
401

  done:
402
403
404
405
  tor_free(TO_CONN(exitconn)->address);
  tor_free(exitconn);
  tor_free(on_circ);
  NS_UNMOCK(router_my_exit_policy_is_reject_star);
406
407
408
409
410
411
412
  return;
}

#undef NS_SUBMODULE

#define NS_SUBMODULE ASPECT(resolve_impl, addr_is_invalid_dest)

rl1987's avatar
rl1987 committed
413
414
415
416
417
418
419
420
421
422
423
/** Given that address is not a valid destination (as judged by
 * address_is_invalid_destination() function), we want dns_resolve_impl()
 * function to fail with return value -1.
 */

static int
NS(router_my_exit_policy_is_reject_star)(void)
{
  return 0;
}

424
425
426
static void
NS(test_main)(void *arg)
{
rl1987's avatar
rl1987 committed
427
428
429
430
431
432
  int retval;
  int made_pending;

  edge_connection_t *exitconn = create_valid_exitconn();
  or_circuit_t *on_circ = tor_malloc_zero(sizeof(or_circuit_t));

rl1987's avatar
rl1987 committed
433
434
  (void)arg;

rl1987's avatar
rl1987 committed
435
436
437
438
439
440
441
  NS_MOCK(router_my_exit_policy_is_reject_star);

  TO_CONN(exitconn)->address = tor_strdup("invalid#@!.org");

  retval = dns_resolve_impl(exitconn, 1, on_circ, NULL, &made_pending,
                            NULL);

442
  tt_int_op(retval,OP_EQ,-1);
443
444

  done:
rl1987's avatar
rl1987 committed
445
446
447
448
  NS_UNMOCK(router_my_exit_policy_is_reject_star);
  tor_free(TO_CONN(exitconn)->address);
  tor_free(exitconn);
  tor_free(on_circ);
449
450
451
452
453
454
455
  return;
}

#undef NS_SUBMODULE

#define NS_SUBMODULE ASPECT(resolve_impl, malformed_ptr)

rl1987's avatar
rl1987 committed
456
457
458
459
460
461
462
463
464
465
/** Given that address is a malformed PTR name, we want dns_resolve_impl to
 * fail.
 */

static int
NS(router_my_exit_policy_is_reject_star)(void)
{
  return 0;
}

466
467
468
static void
NS(test_main)(void *arg)
{
rl1987's avatar
rl1987 committed
469
470
471
472
473
474
  int retval;
  int made_pending;

  edge_connection_t *exitconn = create_valid_exitconn();
  or_circuit_t *on_circ = tor_malloc_zero(sizeof(or_circuit_t));

rl1987's avatar
rl1987 committed
475
476
  (void)arg;

477
  TO_CONN(exitconn)->address = tor_strdup("1.0.0.127.in-addr.arpa");
rl1987's avatar
rl1987 committed
478
479
480
481
482
483

  NS_MOCK(router_my_exit_policy_is_reject_star);

  retval = dns_resolve_impl(exitconn, 1, on_circ, NULL, &made_pending,
                            NULL);

484
  tt_int_op(retval,OP_EQ,-1);
rl1987's avatar
rl1987 committed
485
486
487
488
489
490
491
492
493

  tor_free(TO_CONN(exitconn)->address);

  TO_CONN(exitconn)->address =
  tor_strdup("z01234567890123456789.in-addr.arpa");

  retval = dns_resolve_impl(exitconn, 1, on_circ, NULL, &made_pending,
                            NULL);

494
  tt_int_op(retval,OP_EQ,-1);
495
496

  done:
rl1987's avatar
rl1987 committed
497
498
499
500
  NS_UNMOCK(router_my_exit_policy_is_reject_star);
  tor_free(TO_CONN(exitconn)->address);
  tor_free(exitconn);
  tor_free(on_circ);
501
502
503
504
505
506
507
  return;
}

#undef NS_SUBMODULE

#define NS_SUBMODULE ASPECT(resolve_impl, cache_hit_pending)

rl1987's avatar
rl1987 committed
508
509
510
511
512
513
514
515
516
517
518
/* Given that there is already a pending resolve for the given address,
 * we want dns_resolve_impl to append our exit connection to list
 * of pending connections for the pending DNS request and return 0.
 */

static int
NS(router_my_exit_policy_is_reject_star)(void)
{
  return 0;
}

519
520
521
static void
NS(test_main)(void *arg)
{
rl1987's avatar
rl1987 committed
522
523
524
525
526
527
528
529
530
531
532
533
534
535
  int retval;
  int made_pending = 0;

  pending_connection_t *pending_conn = NULL;

  edge_connection_t *exitconn = create_valid_exitconn();
  or_circuit_t *on_circ = tor_malloc_zero(sizeof(or_circuit_t));

  cached_resolve_t *cache_entry = tor_malloc_zero(sizeof(cached_resolve_t));
  cache_entry->magic = CACHED_RESOLVE_MAGIC;
  cache_entry->state = CACHE_STATE_PENDING;
  cache_entry->minheap_idx = -1;
  cache_entry->expire = time(NULL) + 60 * 60;

rl1987's avatar
rl1987 committed
536
537
  (void)arg;

rl1987's avatar
rl1987 committed
538
539
540
541
542
543
544
545
546
547
548
549
550
551
  TO_CONN(exitconn)->address = tor_strdup("torproject.org");

  strlcpy(cache_entry->address, TO_CONN(exitconn)->address,
          sizeof(cache_entry->address));

  NS_MOCK(router_my_exit_policy_is_reject_star);

  dns_init();

  dns_insert_cache_entry(cache_entry);

  retval = dns_resolve_impl(exitconn, 1, on_circ, NULL, &made_pending,
                            NULL);

552
553
  tt_int_op(retval,OP_EQ,0);
  tt_int_op(made_pending,OP_EQ,1);
rl1987's avatar
rl1987 committed
554
555
556
557
558

  pending_conn = cache_entry->pending_connections;

  tt_assert(pending_conn != NULL);
  tt_assert(pending_conn->conn == exitconn);
559
560

  done:
rl1987's avatar
rl1987 committed
561
562
563
564
565
  NS_UNMOCK(router_my_exit_policy_is_reject_star);
  tor_free(on_circ);
  tor_free(TO_CONN(exitconn)->address);
  tor_free(cache_entry->pending_connections);
  tor_free(cache_entry);
566
  tor_free(exitconn);
567
568
569
570
571
572
573
  return;
}

#undef NS_SUBMODULE

#define NS_SUBMODULE ASPECT(resolve_impl, cache_hit_cached)

rl1987's avatar
rl1987 committed
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
/* Given that a finished DNS resolve is available in our cache, we want
 * dns_resolve_impl() return it to called via resolve_out and pass the
 * handling to set_exitconn_info_from_resolve function.
 */
static int
NS(router_my_exit_policy_is_reject_star)(void)
{
  return 0;
}

static edge_connection_t *last_exitconn = NULL;
static cached_resolve_t *last_resolve = NULL;

static int
NS(set_exitconn_info_from_resolve)(edge_connection_t *exitconn,
                                   const cached_resolve_t *resolve,
                                   char **hostname_out)
{
  last_exitconn = exitconn;
  last_resolve = (cached_resolve_t *)resolve;

rl1987's avatar
rl1987 committed
595
596
  (void)hostname_out;

rl1987's avatar
rl1987 committed
597
598
599
  return 0;
}

600
601
602
static void
NS(test_main)(void *arg)
{
rl1987's avatar
rl1987 committed
603
604
605
606
607
608
609
610
611
612
613
614
615
616
  int retval;
  int made_pending = 0;

  edge_connection_t *exitconn = create_valid_exitconn();
  or_circuit_t *on_circ = tor_malloc_zero(sizeof(or_circuit_t));

  cached_resolve_t *resolve_out = NULL;

  cached_resolve_t *cache_entry = tor_malloc_zero(sizeof(cached_resolve_t));
  cache_entry->magic = CACHED_RESOLVE_MAGIC;
  cache_entry->state = CACHE_STATE_CACHED;
  cache_entry->minheap_idx = -1;
  cache_entry->expire = time(NULL) + 60 * 60;

rl1987's avatar
rl1987 committed
617
618
  (void)arg;

rl1987's avatar
rl1987 committed
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
  TO_CONN(exitconn)->address = tor_strdup("torproject.org");

  strlcpy(cache_entry->address, TO_CONN(exitconn)->address,
          sizeof(cache_entry->address));

  NS_MOCK(router_my_exit_policy_is_reject_star);
  NS_MOCK(set_exitconn_info_from_resolve);

  dns_init();

  dns_insert_cache_entry(cache_entry);

  retval = dns_resolve_impl(exitconn, 1, on_circ, NULL, &made_pending,
                            &resolve_out);

634
635
  tt_int_op(retval,OP_EQ,0);
  tt_int_op(made_pending,OP_EQ,0);
rl1987's avatar
rl1987 committed
636
637
638
639
  tt_assert(resolve_out == cache_entry);

  tt_assert(last_exitconn == exitconn);
  tt_assert(last_resolve == cache_entry);
640
641

  done:
rl1987's avatar
rl1987 committed
642
643
644
645
646
647
  NS_UNMOCK(router_my_exit_policy_is_reject_star);
  NS_UNMOCK(set_exitconn_info_from_resolve);
  tor_free(on_circ);
  tor_free(TO_CONN(exitconn)->address);
  tor_free(cache_entry->pending_connections);
  tor_free(cache_entry);
648
649
650
651
652
653
654
  return;
}

#undef NS_SUBMODULE

#define NS_SUBMODULE ASPECT(resolve_impl, cache_miss)

655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
/* Given that there are neither pending nor pre-cached resolve for a given
 * address, we want dns_resolve_impl() to create a new cached_resolve_t
 * object, mark it as pending, insert it into the cache, attach the exit
 * connection to list of pending connections and call launch_resolve()
 * with the cached_resolve_t object it created.
 */
static int
NS(router_my_exit_policy_is_reject_star)(void)
{
  return 0;
}

static cached_resolve_t *last_launched_resolve = NULL;

static int
NS(launch_resolve)(cached_resolve_t *resolve)
{
  last_launched_resolve = resolve;

  return 0;
}

677
678
679
static void
NS(test_main)(void *arg)
{
680
681
682
683
684
685
686
687
688
689
690
  int retval;
  int made_pending = 0;

  pending_connection_t *pending_conn = NULL;

  edge_connection_t *exitconn = create_valid_exitconn();
  or_circuit_t *on_circ = tor_malloc_zero(sizeof(or_circuit_t));

  cached_resolve_t *cache_entry = NULL;
  cached_resolve_t query;

rl1987's avatar
rl1987 committed
691
692
  (void)arg;

693
694
695
696
697
698
699
700
701
702
703
704
  TO_CONN(exitconn)->address = tor_strdup("torproject.org");

  strlcpy(query.address, TO_CONN(exitconn)->address, sizeof(query.address));

  NS_MOCK(router_my_exit_policy_is_reject_star);
  NS_MOCK(launch_resolve);

  dns_init();

  retval = dns_resolve_impl(exitconn, 1, on_circ, NULL, &made_pending,
                            NULL);

705
706
  tt_int_op(retval,OP_EQ,0);
  tt_int_op(made_pending,OP_EQ,1);
707
708
709
710
711
712
713
714
715
716
717

  cache_entry = dns_get_cache_entry(&query);

  tt_assert(cache_entry);

  pending_conn = cache_entry->pending_connections;

  tt_assert(pending_conn != NULL);
  tt_assert(pending_conn->conn == exitconn);

  tt_assert(last_launched_resolve == cache_entry);
718
  tt_str_op(cache_entry->address,OP_EQ,TO_CONN(exitconn)->address);
719
720

  done:
721
722
723
724
  NS_UNMOCK(router_my_exit_policy_is_reject_star);
  NS_UNMOCK(launch_resolve);
  tor_free(on_circ);
  tor_free(TO_CONN(exitconn)->address);
725
726
  if (cache_entry)
    tor_free(cache_entry->pending_connections);
727
  tor_free(cache_entry);
728
  tor_free(exitconn);
729
730
731
732
733
  return;
}

#undef NS_SUBMODULE

734
struct testcase_t dns_tests[] = {
rl1987's avatar
rl1987 committed
735
736
   TEST_CASE(clip_ttl),
   TEST_CASE(resolve),
737
738
739
740
741
742
743
   TEST_CASE_ASPECT(resolve_impl, addr_is_ip_no_need_to_resolve),
   TEST_CASE_ASPECT(resolve_impl, non_exit),
   TEST_CASE_ASPECT(resolve_impl, addr_is_invalid_dest),
   TEST_CASE_ASPECT(resolve_impl, malformed_ptr),
   TEST_CASE_ASPECT(resolve_impl, cache_hit_pending),
   TEST_CASE_ASPECT(resolve_impl, cache_hit_cached),
   TEST_CASE_ASPECT(resolve_impl, cache_miss),
744
745
746
   END_OF_TESTCASES
};

rl1987's avatar
rl1987 committed
747
748
#undef NS_MODULE