test_extorport.c 20.2 KB
Newer Older
1
/* Copyright (c) 2013-2017, The Tor Project, Inc. */
Nick Mathewson's avatar
Nick Mathewson committed
2
3
4
/* See LICENSE for licensing information */

#define CONNECTION_PRIVATE
5
#define EXT_ORPORT_PRIVATE
6
#define MAIN_PRIVATE
Nick Mathewson's avatar
Nick Mathewson committed
7
#include "or.h"
8
#include "buffers.h"
Nick Mathewson's avatar
Nick Mathewson committed
9
#include "connection.h"
10
#include "connection_or.h"
11
#include "config.h"
12
#include "control.h"
Nick Mathewson's avatar
Nick Mathewson committed
13
#include "ext_orport.h"
14
#include "main.h"
Nick Mathewson's avatar
Nick Mathewson committed
15
16
17
18
19
20
21
22
23
24
25
26
#include "test.h"

/* Test connection_or_remove_from_ext_or_id_map and
 * connection_or_set_ext_or_identifier */
static void
test_ext_or_id_map(void *arg)
{
  or_connection_t *c1 = NULL, *c2 = NULL, *c3 = NULL;
  char *idp = NULL, *idp2 = NULL;
  (void)arg;

  /* pre-initialization */
Nick Mathewson's avatar
Nick Mathewson committed
27
28
  tt_ptr_op(NULL, OP_EQ,
            connection_or_get_by_ext_or_id("xxxxxxxxxxxxxxxxxxxx"));
Nick Mathewson's avatar
Nick Mathewson committed
29
30
31
32
33

  c1 = or_connection_new(CONN_TYPE_EXT_OR, AF_INET);
  c2 = or_connection_new(CONN_TYPE_EXT_OR, AF_INET);
  c3 = or_connection_new(CONN_TYPE_OR, AF_INET);

34
35
36
  tt_ptr_op(c1->ext_or_conn_id, OP_NE, NULL);
  tt_ptr_op(c2->ext_or_conn_id, OP_NE, NULL);
  tt_ptr_op(c3->ext_or_conn_id, OP_EQ, NULL);
Nick Mathewson's avatar
Nick Mathewson committed
37

38
39
  tt_ptr_op(c1, OP_EQ, connection_or_get_by_ext_or_id(c1->ext_or_conn_id));
  tt_ptr_op(c2, OP_EQ, connection_or_get_by_ext_or_id(c2->ext_or_conn_id));
Nick Mathewson's avatar
Nick Mathewson committed
40
41
  tt_ptr_op(NULL, OP_EQ,
            connection_or_get_by_ext_or_id("xxxxxxxxxxxxxxxxxxxx"));
Nick Mathewson's avatar
Nick Mathewson committed
42
43
44
45
46

  idp = tor_memdup(c2->ext_or_conn_id, EXT_OR_CONN_ID_LEN);

  /* Give c2 a new ID. */
  connection_or_set_ext_or_identifier(c2);
47
  tt_mem_op(idp, OP_NE, c2->ext_or_conn_id, EXT_OR_CONN_ID_LEN);
Nick Mathewson's avatar
Nick Mathewson committed
48
49
50
  idp2 = tor_memdup(c2->ext_or_conn_id, EXT_OR_CONN_ID_LEN);
  tt_assert(!tor_digest_is_zero(idp2));

51
52
  tt_ptr_op(NULL, OP_EQ, connection_or_get_by_ext_or_id(idp));
  tt_ptr_op(c2, OP_EQ, connection_or_get_by_ext_or_id(idp2));
Nick Mathewson's avatar
Nick Mathewson committed
53
54
55

  /* Now remove it. */
  connection_or_remove_from_ext_or_id_map(c2);
56
57
  tt_ptr_op(NULL, OP_EQ, connection_or_get_by_ext_or_id(idp));
  tt_ptr_op(NULL, OP_EQ, connection_or_get_by_ext_or_id(idp2));
Nick Mathewson's avatar
Nick Mathewson committed
58
59
60

 done:
  if (c1)
61
    connection_free_minimal(TO_CONN(c1));
Nick Mathewson's avatar
Nick Mathewson committed
62
  if (c2)
63
    connection_free_minimal(TO_CONN(c2));
Nick Mathewson's avatar
Nick Mathewson committed
64
  if (c3)
65
    connection_free_minimal(TO_CONN(c3));
Nick Mathewson's avatar
Nick Mathewson committed
66
67
68
69
70
  tor_free(idp);
  tor_free(idp2);
  connection_or_clear_ext_or_id_map();
}

71
72
73
74
/* Simple connection_write_to_buf_impl_ replacement that unconditionally
 * writes to outbuf. */
static void
connection_write_to_buf_impl_replacement(const char *string, size_t len,
75
                                         connection_t *conn, int compressed)
76
{
77
  (void) compressed;
78
79
80

  tor_assert(string);
  tor_assert(conn);
81
  buf_add(conn->outbuf, string, len);
82
83
84
85
86
87
88
89
90
91
}

static char *
buf_get_contents(buf_t *buf, size_t *sz_out)
{
  char *out;
  *sz_out = buf_datalen(buf);
  if (*sz_out >= ULONG_MAX)
    return NULL; /* C'mon, really? */
  out = tor_malloc(*sz_out + 1);
92
  if (buf_get_bytes(buf, out, (unsigned long)*sz_out) != 0) {
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
    tor_free(out);
    return NULL;
  }
  out[*sz_out] = '\0'; /* Hopefully gratuitous. */
  return out;
}

static void
test_ext_or_write_command(void *arg)
{
  or_connection_t *c1;
  char *cp = NULL;
  char *buf = NULL;
  size_t sz;

  (void) arg;
  MOCK(connection_write_to_buf_impl_,
       connection_write_to_buf_impl_replacement);

  c1 = or_connection_new(CONN_TYPE_EXT_OR, AF_INET);
  tt_assert(c1);

  /* Length too long */
  tt_int_op(connection_write_ext_or_command(TO_CONN(c1), 100, "X", 100000),
117
            OP_LT, 0);
118
119
120

  /* Empty command */
  tt_int_op(connection_write_ext_or_command(TO_CONN(c1), 0x99, NULL, 0),
121
            OP_EQ, 0);
122
  cp = buf_get_contents(TO_CONN(c1)->outbuf, &sz);
123
124
  tt_int_op(sz, OP_EQ, 4);
  tt_mem_op(cp, OP_EQ, "\x00\x99\x00\x00", 4);
125
126
127
128
  tor_free(cp);

  /* Medium command. */
  tt_int_op(connection_write_ext_or_command(TO_CONN(c1), 0x99,
129
                                            "Wai\0Hello", 9), OP_EQ, 0);
130
  cp = buf_get_contents(TO_CONN(c1)->outbuf, &sz);
131
132
  tt_int_op(sz, OP_EQ, 13);
  tt_mem_op(cp, OP_EQ, "\x00\x99\x00\x09Wai\x00Hello", 13);
133
134
135
136
137
138
  tor_free(cp);

  /* Long command */
  buf = tor_malloc(65535);
  memset(buf, 'x', 65535);
  tt_int_op(connection_write_ext_or_command(TO_CONN(c1), 0xf00d,
139
                                            buf, 65535), OP_EQ, 0);
140
  cp = buf_get_contents(TO_CONN(c1)->outbuf, &sz);
141
142
143
  tt_int_op(sz, OP_EQ, 65539);
  tt_mem_op(cp, OP_EQ, "\xf0\x0d\xff\xff", 4);
  tt_mem_op(cp+4, OP_EQ, buf, 65535);
144
145
146
147
  tor_free(cp);

 done:
  if (c1)
148
    connection_free_minimal(TO_CONN(c1));
149
150
151
152
153
  tor_free(cp);
  tor_free(buf);
  UNMOCK(connection_write_to_buf_impl_);
}

154
155
156
157
158
159
160
161
162
163
164
165
static int
write_bytes_to_file_fail(const char *fname, const char *str, size_t len,
                         int bin)
{
  (void) fname;
  (void) str;
  (void) len;
  (void) bin;

  return -1;
}

166
167
168
169
170
171
172
173
174
175
176
static void
test_ext_or_init_auth(void *arg)
{
  or_options_t *options = get_options_mutable();
  const char *fn;
  char *cp = NULL;
  struct stat st;
  char cookie0[32];
  (void)arg;

  /* Check default filename location */
177
  tor_free(options->DataDirectory);
178
179
  options->DataDirectory = tor_strdup("foo");
  cp = get_ext_or_auth_cookie_file_name();
180
  tt_str_op(cp, OP_EQ, "foo"PATH_SEPARATOR"extended_orport_auth_cookie");
181
182
183
184
  tor_free(cp);

  /* Shouldn't be initialized already, or our tests will be a bit
   * meaningless */
185
  ext_or_auth_cookie = tor_malloc_zero(32);
186
  tt_assert(tor_mem_is_zero((char*)ext_or_auth_cookie, 32));
187
188
189
190
191

  /* Now make sure we use a temporary file */
  fn = get_fname("ext_cookie_file");
  options->ExtORPortCookieAuthFile = tor_strdup(fn);
  cp = get_ext_or_auth_cookie_file_name();
192
  tt_str_op(cp, OP_EQ, fn);
193
194
  tor_free(cp);

195
196
197
  /* Test the initialization function with a broken
     write_bytes_to_file(). See if the problem is handled properly. */
  MOCK(write_bytes_to_file, write_bytes_to_file_fail);
198
199
  tt_int_op(-1, OP_EQ, init_ext_or_cookie_authentication(1));
  tt_int_op(ext_or_auth_cookie_is_set, OP_EQ, 0);
200
201
202
  UNMOCK(write_bytes_to_file);

  /* Now do the actual initialization. */
203
204
  tt_int_op(0, OP_EQ, init_ext_or_cookie_authentication(1));
  tt_int_op(ext_or_auth_cookie_is_set, OP_EQ, 1);
205
  cp = read_file_to_str(fn, RFTS_BIN, &st);
206
207
208
209
  tt_ptr_op(cp, OP_NE, NULL);
  tt_u64_op((uint64_t)st.st_size, OP_EQ, 64);
  tt_mem_op(cp,OP_EQ, "! Extended ORPort Auth Cookie !\x0a", 32);
  tt_mem_op(cp+32,OP_EQ, ext_or_auth_cookie, 32);
210
  memcpy(cookie0, ext_or_auth_cookie, 32);
211
  tt_assert(!tor_mem_is_zero((char*)ext_or_auth_cookie, 32));
212
213

  /* Operation should be idempotent. */
214
215
  tt_int_op(0, OP_EQ, init_ext_or_cookie_authentication(1));
  tt_mem_op(cookie0,OP_EQ, ext_or_auth_cookie, 32);
216
217
218

 done:
  tor_free(cp);
219
  ext_orport_free_all();
220
221
}

222
223
224
static void
test_ext_or_cookie_auth(void *arg)
{
225
  char *reply=NULL, *reply2=NULL, *client_hash=NULL, *client_hash2=NULL;
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
  size_t reply_len=0;
  char hmac1[32], hmac2[32];

  const char client_nonce[32] =
    "Who is the third who walks alway";
  char server_hash_input[] =
    "ExtORPort authentication server-to-client hash"
    "Who is the third who walks alway"
    "................................";
  char client_hash_input[] =
    "ExtORPort authentication client-to-server hash"
    "Who is the third who walks alway"
    "................................";

  (void)arg;

242
243
  tt_int_op(strlen(client_hash_input), OP_EQ, 46+32+32);
  tt_int_op(strlen(server_hash_input), OP_EQ, 46+32+32);
244

245
  ext_or_auth_cookie = tor_malloc_zero(32);
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
  memcpy(ext_or_auth_cookie, "s beside you? When I count, ther", 32);
  ext_or_auth_cookie_is_set = 1;

  /* For this authentication, the client sends 32 random bytes (ClientNonce)
   * The server replies with 32 byte ServerHash and 32 byte ServerNonce,
   * where ServerHash is:
   * HMAC-SHA256(CookieString,
   *   "ExtORPort authentication server-to-client hash" | ClientNonce |
   *    ServerNonce)"
   * The client must reply with 32-byte ClientHash, which we compute as:
   *   ClientHash is computed as:
   *        HMAC-SHA256(CookieString,
   *           "ExtORPort authentication client-to-server hash" | ClientNonce |
   *            ServerNonce)
   */

  /* Wrong length */
263
  tt_int_op(-1, OP_EQ,
264
265
            handle_client_auth_nonce(client_nonce, 33, &client_hash, &reply,
                                     &reply_len));
266
  tt_int_op(-1, OP_EQ,
267
268
269
270
            handle_client_auth_nonce(client_nonce, 31, &client_hash, &reply,
                                     &reply_len));

  /* Now let's try this for real! */
271
  tt_int_op(0, OP_EQ,
272
273
            handle_client_auth_nonce(client_nonce, 32, &client_hash, &reply,
                                     &reply_len));
274
275
276
  tt_int_op(reply_len, OP_EQ, 64);
  tt_ptr_op(reply, OP_NE, NULL);
  tt_ptr_op(client_hash, OP_NE, NULL);
277
278
279
280
  /* Fill in the server nonce into the hash inputs... */
  memcpy(server_hash_input+46+32, reply+32, 32);
  memcpy(client_hash_input+46+32, reply+32, 32);
  /* Check the HMACs are correct... */
281
  crypto_hmac_sha256(hmac1, (char*)ext_or_auth_cookie, 32, server_hash_input,
282
                     46+32+32);
283
  crypto_hmac_sha256(hmac2, (char*)ext_or_auth_cookie, 32, client_hash_input,
284
                     46+32+32);
285
286
  tt_mem_op(hmac1,OP_EQ, reply, 32);
  tt_mem_op(hmac2,OP_EQ, client_hash, 32);
287

288
  /* Now do it again and make sure that the results are *different* */
289
  tt_int_op(0, OP_EQ,
290
291
            handle_client_auth_nonce(client_nonce, 32, &client_hash2, &reply2,
                                     &reply_len));
292
293
  tt_mem_op(reply2,OP_NE, reply, reply_len);
  tt_mem_op(client_hash2,OP_NE, client_hash, 32);
294
295
296
297
  /* But that this one checks out too. */
  memcpy(server_hash_input+46+32, reply2+32, 32);
  memcpy(client_hash_input+46+32, reply2+32, 32);
  /* Check the HMACs are correct... */
298
  crypto_hmac_sha256(hmac1, (char*)ext_or_auth_cookie, 32, server_hash_input,
299
                     46+32+32);
300
  crypto_hmac_sha256(hmac2, (char*)ext_or_auth_cookie, 32, client_hash_input,
301
                     46+32+32);
302
303
  tt_mem_op(hmac1,OP_EQ, reply2, 32);
  tt_mem_op(hmac2,OP_EQ, client_hash2, 32);
304
305
306
307
308
309
310
311

 done:
  tor_free(reply);
  tor_free(client_hash);
  tor_free(reply2);
  tor_free(client_hash2);
}

312
static void
313
314
315
316
crypto_rand_return_tse_str(char *to, size_t n)
{
  if (n != 32) {
    TT_FAIL(("Asked for %d bytes, not 32", (int)n));
317
    return;
318
319
320
321
322
323
324
325
326
327
328
329
330
331
  }
  memcpy(to, "te road There is always another ", 32);
}

static void
test_ext_or_cookie_auth_testvec(void *arg)
{
  char *reply=NULL, *client_hash=NULL;
  size_t reply_len;
  char *mem_op_hex_tmp=NULL;

  const char client_nonce[] = "But when I look ahead up the whi";
  (void)arg;

332
  ext_or_auth_cookie = tor_malloc_zero(32);
333
334
335
336
337
  memcpy(ext_or_auth_cookie, "Gliding wrapt in a brown mantle," , 32);
  ext_or_auth_cookie_is_set = 1;

  MOCK(crypto_rand, crypto_rand_return_tse_str);

338
  tt_int_op(0, OP_EQ,
339
340
            handle_client_auth_nonce(client_nonce, 32, &client_hash, &reply,
                                     &reply_len));
341
342
343
  tt_ptr_op(reply, OP_NE, NULL );
  tt_uint_op(reply_len, OP_EQ, 64);
  tt_mem_op(reply+32,OP_EQ, "te road There is always another ", 32);
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
  /* HMACSHA256("Gliding wrapt in a brown mantle,"
   *     "ExtORPort authentication server-to-client hash"
   *     "But when I look ahead up the write road There is always another ");
   */
  test_memeq_hex(reply,
                 "ec80ed6e546d3b36fdfc22fe1315416b"
                 "029f1ade7610d910878b62eeb7403821");
  /* HMACSHA256("Gliding wrapt in a brown mantle,"
   *     "ExtORPort authentication client-to-server hash"
   *     "But when I look ahead up the write road There is always another ");
   * (Both values computed using Python CLI.)
   */
  test_memeq_hex(client_hash,
                 "ab391732dd2ed968cd40c087d1b1f25b"
                 "33b3cd77ff79bd80c2074bbf438119a2");

360
 done:
361
  UNMOCK(crypto_rand);
362
363
  tor_free(reply);
  tor_free(client_hash);
364
  tor_free(mem_op_hex_tmp);
365
366
}

367
static void
368
ignore_bootstrap_problem(const char *warn, int reason,
369
                         or_connection_t *conn)
370
371
372
{
  (void)warn;
  (void)reason;
373
  (void)conn;
374
375
}

376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
static int is_reading = 1;
static int handshake_start_called = 0;

static void
note_read_stopped(connection_t *conn)
{
  (void)conn;
  is_reading=0;
}
static void
note_read_started(connection_t *conn)
{
  (void)conn;
  is_reading=1;
}
static int
handshake_start(or_connection_t *conn, int receiving)
{
  if (!conn || !receiving)
    TT_FAIL(("Bad arguments to handshake_start"));
  handshake_start_called = 1;
  return 0;
}

400
401
#define WRITE(s,n)                                                      \
  do {                                                                  \
402
    buf_add(TO_CONN(conn)->inbuf, (s), (n));                           \
403
404
405
  } while (0)
#define CONTAINS(s,n)                                           \
  do {                                                          \
406
407
    tt_int_op((n), OP_LE, sizeof(b));                              \
    tt_int_op(buf_datalen(TO_CONN(conn)->outbuf), OP_EQ, (n));     \
408
    if ((n)) {                                                  \
409
      buf_get_bytes(TO_CONN(conn)->outbuf, b, (n));                \
410
      tt_mem_op(b, OP_EQ, (s), (n));                               \
411
412
413
    }                                                           \
  } while (0)

414
415
416
417
418
419
/* Helper: Do a successful Extended ORPort authentication handshake. */
static void
do_ext_or_handshake(or_connection_t *conn)
{
  char b[256];

420
  tt_int_op(0, OP_EQ, connection_ext_or_start_auth(conn));
421
422
423
424
  CONTAINS("\x01\x00", 2);
  WRITE("\x01", 1);
  WRITE("But when I look ahead up the whi", 32);
  MOCK(crypto_rand, crypto_rand_return_tse_str);
425
  tt_int_op(0, OP_EQ, connection_ext_or_process_inbuf(conn));
426
  UNMOCK(crypto_rand);
Nick Mathewson's avatar
Nick Mathewson committed
427
428
  tt_int_op(TO_CONN(conn)->state, OP_EQ,
            EXT_OR_CONN_STATE_AUTH_WAIT_CLIENT_HASH);
429
430
431
432
433
434
435
  CONTAINS("\xec\x80\xed\x6e\x54\x6d\x3b\x36\xfd\xfc\x22\xfe\x13\x15\x41\x6b"
           "\x02\x9f\x1a\xde\x76\x10\xd9\x10\x87\x8b\x62\xee\xb7\x40\x38\x21"
           "te road There is always another ", 64);
  /* Send the right response this time. */
  WRITE("\xab\x39\x17\x32\xdd\x2e\xd9\x68\xcd\x40\xc0\x87\xd1\xb1\xf2\x5b"
        "\x33\xb3\xcd\x77\xff\x79\xbd\x80\xc2\x07\x4b\xbf\x43\x81\x19\xa2",
        32);
436
  tt_int_op(0, OP_EQ, connection_ext_or_process_inbuf(conn));
437
438
  CONTAINS("\x01", 1);
  tt_assert(! TO_CONN(conn)->marked_for_close);
439
  tt_int_op(TO_CONN(conn)->state, OP_EQ, EXT_OR_CONN_STATE_OPEN);
440
441
442
443
444
445
446
447
448
449

 done: ;
}

static void
test_ext_or_handshake(void *arg)
{
  or_connection_t *conn=NULL;
  char b[256];

450
451
452
453
  (void) arg;
  MOCK(connection_write_to_buf_impl_,
       connection_write_to_buf_impl_replacement);
  /* Use same authenticators as for test_ext_or_cookie_auth_testvec */
454
  ext_or_auth_cookie = tor_malloc_zero(32);
455
456
457
458
459
460
  memcpy(ext_or_auth_cookie, "Gliding wrapt in a brown mantle," , 32);
  ext_or_auth_cookie_is_set = 1;

  init_connection_lists();

  conn = or_connection_new(CONN_TYPE_EXT_OR, AF_INET);
461
  tt_int_op(0, OP_EQ, connection_ext_or_start_auth(conn));
462
463
464
  /* The server starts by telling us about the one supported authtype. */
  CONTAINS("\x01\x00", 2);
  /* Say the client hasn't responded yet. */
465
  tt_int_op(0, OP_EQ, connection_ext_or_process_inbuf(conn));
466
467
  /* Let's say the client replies badly. */
  WRITE("\x99", 1);
468
  tt_int_op(-1, OP_EQ, connection_ext_or_process_inbuf(conn));
469
470
471
472
473
474
475
  CONTAINS("", 0);
  tt_assert(TO_CONN(conn)->marked_for_close);
  close_closeable_connections();
  conn = NULL;

  /* Okay, try again. */
  conn = or_connection_new(CONN_TYPE_EXT_OR, AF_INET);
476
  tt_int_op(0, OP_EQ, connection_ext_or_start_auth(conn));
477
478
479
480
481
482
  CONTAINS("\x01\x00", 2);
  /* Let's say the client replies sensibly this time. "Yes, AUTHTYPE_COOKIE
   * sounds delicious. Let's have some of that!" */
  WRITE("\x01", 1);
  /* Let's say that the client also sends part of a nonce. */
  WRITE("But when I look ", 16);
483
  tt_int_op(0, OP_EQ, connection_ext_or_process_inbuf(conn));
484
  CONTAINS("", 0);
485
  tt_int_op(TO_CONN(conn)->state, OP_EQ,
486
487
            EXT_OR_CONN_STATE_AUTH_WAIT_CLIENT_NONCE);
  /* Pump it again. Nothing should happen. */
488
  tt_int_op(0, OP_EQ, connection_ext_or_process_inbuf(conn));
489
490
491
  /* send the rest of the nonce. */
  WRITE("ahead up the whi", 16);
  MOCK(crypto_rand, crypto_rand_return_tse_str);
492
  tt_int_op(0, OP_EQ, connection_ext_or_process_inbuf(conn));
493
494
495
496
497
498
499
  UNMOCK(crypto_rand);
  /* We should get the right reply from the server. */
  CONTAINS("\xec\x80\xed\x6e\x54\x6d\x3b\x36\xfd\xfc\x22\xfe\x13\x15\x41\x6b"
           "\x02\x9f\x1a\xde\x76\x10\xd9\x10\x87\x8b\x62\xee\xb7\x40\x38\x21"
           "te road There is always another ", 64);
  /* Send the wrong response. */
  WRITE("not with a bang but a whimper...", 32);
500
  MOCK(control_event_bootstrap_prob_or, ignore_bootstrap_problem);
501
  tt_int_op(-1, OP_EQ, connection_ext_or_process_inbuf(conn));
502
503
504
505
506
  CONTAINS("\x00", 1);
  tt_assert(TO_CONN(conn)->marked_for_close);
  /* XXXX Hold-open-until-flushed. */
  close_closeable_connections();
  conn = NULL;
507
  UNMOCK(control_event_bootstrap_prob_or);
508

509
510
511
512
  MOCK(connection_start_reading, note_read_started);
  MOCK(connection_stop_reading, note_read_stopped);
  MOCK(connection_tls_start_handshake, handshake_start);

513
514
  /* Okay, this time let's succeed. */
  conn = or_connection_new(CONN_TYPE_EXT_OR, AF_INET);
515
  do_ext_or_handshake(conn);
516

517
518
519
  /* Now let's run through some messages. */
  /* First let's send some junk and make sure it's ignored. */
  WRITE("\xff\xf0\x00\x03""ABC", 7);
520
  tt_int_op(0, OP_EQ, connection_ext_or_process_inbuf(conn));
521
522
523
  CONTAINS("", 0);
  /* Now let's send a USERADDR command. */
  WRITE("\x00\x01\x00\x0c""1.2.3.4:5678", 16);
524
525
526
  tt_int_op(0, OP_EQ, connection_ext_or_process_inbuf(conn));
  tt_int_op(TO_CONN(conn)->port, OP_EQ, 5678);
  tt_int_op(tor_addr_to_ipv4h(&TO_CONN(conn)->addr), OP_EQ, 0x01020304);
527
528
  /* Now let's send a TRANSPORT command. */
  WRITE("\x00\x02\x00\x07""rfc1149", 11);
529
530
531
532
533
  tt_int_op(0, OP_EQ, connection_ext_or_process_inbuf(conn));
  tt_ptr_op(NULL, OP_NE, conn->ext_or_transport);
  tt_str_op("rfc1149", OP_EQ, conn->ext_or_transport);
  tt_int_op(is_reading,OP_EQ,1);
  tt_int_op(TO_CONN(conn)->state, OP_EQ, EXT_OR_CONN_STATE_OPEN);
534
535
  /* DONE */
  WRITE("\x00\x00\x00\x00", 4);
536
537
538
  tt_int_op(0, OP_EQ, connection_ext_or_process_inbuf(conn));
  tt_int_op(TO_CONN(conn)->state, OP_EQ, EXT_OR_CONN_STATE_FLUSHING);
  tt_int_op(is_reading,OP_EQ,0);
539
  CONTAINS("\x10\x00\x00\x00", 4);
540
541
542
543
544
545
  tt_int_op(handshake_start_called,OP_EQ,0);
  tt_int_op(0, OP_EQ, connection_ext_or_finished_flushing(conn));
  tt_int_op(is_reading,OP_EQ,1);
  tt_int_op(handshake_start_called,OP_EQ,1);
  tt_int_op(TO_CONN(conn)->type, OP_EQ, CONN_TYPE_OR);
  tt_int_op(TO_CONN(conn)->state, OP_EQ, 0);
546
547
548
549
550
551
552
553
554
  close_closeable_connections();
  conn = NULL;

  /* Okay, this time let's succeed the handshake but fail the USERADDR
     command. */
  conn = or_connection_new(CONN_TYPE_EXT_OR, AF_INET);
  do_ext_or_handshake(conn);
  /* USERADDR command with an extra NUL byte */
  WRITE("\x00\x01\x00\x0d""1.2.3.4:5678\x00", 17);
555
  MOCK(control_event_bootstrap_prob_or, ignore_bootstrap_problem);
556
  tt_int_op(-1, OP_EQ, connection_ext_or_process_inbuf(conn));
557
558
559
560
  CONTAINS("", 0);
  tt_assert(TO_CONN(conn)->marked_for_close);
  close_closeable_connections();
  conn = NULL;
561
  UNMOCK(control_event_bootstrap_prob_or);
562
563
564
565
566
567

  /* Now fail the TRANSPORT command. */
  conn = or_connection_new(CONN_TYPE_EXT_OR, AF_INET);
  do_ext_or_handshake(conn);
  /* TRANSPORT command with an extra NUL byte */
  WRITE("\x00\x02\x00\x08""rfc1149\x00", 12);
568
  MOCK(control_event_bootstrap_prob_or, ignore_bootstrap_problem);
569
  tt_int_op(-1, OP_EQ, connection_ext_or_process_inbuf(conn));
570
571
572
573
  CONTAINS("", 0);
  tt_assert(TO_CONN(conn)->marked_for_close);
  close_closeable_connections();
  conn = NULL;
574
  UNMOCK(control_event_bootstrap_prob_or);
575
576
577
578
579
580
581

  /* Now fail the TRANSPORT command. */
  conn = or_connection_new(CONN_TYPE_EXT_OR, AF_INET);
  do_ext_or_handshake(conn);
  /* TRANSPORT command with transport name with symbols (not a
     C-identifier) */
  WRITE("\x00\x02\x00\x07""rf*1149", 11);
582
  MOCK(control_event_bootstrap_prob_or, ignore_bootstrap_problem);
583
  tt_int_op(-1, OP_EQ, connection_ext_or_process_inbuf(conn));
584
585
586
587
  CONTAINS("", 0);
  tt_assert(TO_CONN(conn)->marked_for_close);
  close_closeable_connections();
  conn = NULL;
588
  UNMOCK(control_event_bootstrap_prob_or);
589

590
591
592
593
 done:
  UNMOCK(connection_write_to_buf_impl_);
  UNMOCK(crypto_rand);
  if (conn)
594
    connection_free_minimal(TO_CONN(conn));
595
#undef CONTAINS
596
597
598
#undef WRITE
}

Nick Mathewson's avatar
Nick Mathewson committed
599
600
struct testcase_t extorport_tests[] = {
  { "id_map", test_ext_or_id_map, TT_FORK, NULL, NULL },
601
  { "write_command", test_ext_or_write_command, TT_FORK, NULL, NULL },
602
  { "init_auth", test_ext_or_init_auth, TT_FORK, NULL, NULL },
603
  { "cookie_auth", test_ext_or_cookie_auth, TT_FORK, NULL, NULL },
604
605
  { "cookie_auth_testvec", test_ext_or_cookie_auth_testvec, TT_FORK,
    NULL, NULL },
606
  { "handshake", test_ext_or_handshake, TT_FORK, NULL, NULL },
Nick Mathewson's avatar
Nick Mathewson committed
607
608
  END_OF_TESTCASES
};
609