tor

The Tor anonymity network
git clone https://git.dasho.dev/tor.git
Log | Files | Refs | README | LICENSE

test_extorport.c (18741B)


      1 /* Copyright (c) 2013-2021, The Tor Project, Inc. */
      2 /* See LICENSE for licensing information */
      3 
      4 #define CONNECTION_PRIVATE
      5 #define EXT_ORPORT_PRIVATE
      6 #define MAINLOOP_PRIVATE
      7 #include "core/or/or.h"
      8 #include "lib/buf/buffers.h"
      9 #include "core/mainloop/connection.h"
     10 #include "core/or/connection_or.h"
     11 #include "app/config/config.h"
     12 #include "feature/control/control_events.h"
     13 #include "lib/crypt_ops/crypto_rand.h"
     14 #include "feature/relay/ext_orport.h"
     15 #include "core/mainloop/mainloop.h"
     16 
     17 #include "core/or/or_connection_st.h"
     18 
     19 #include "test/test.h"
     20 #include "test/test_helpers.h"
     21 #include "test/rng_test_helpers.h"
     22 
     23 #ifdef HAVE_SYS_STAT_H
     24 #include <sys/stat.h>
     25 #endif
     26 
     27 /* Simple connection_write_to_buf_impl_ replacement that unconditionally
     28 * writes to outbuf. */
     29 static void
     30 connection_write_to_buf_impl_replacement(const char *string, size_t len,
     31                                         connection_t *conn, int compressed)
     32 {
     33  (void) compressed;
     34 
     35  tor_assert(string);
     36  tor_assert(conn);
     37  buf_add(conn->outbuf, string, len);
     38 }
     39 
     40 static void
     41 test_ext_or_write_command(void *arg)
     42 {
     43  or_connection_t *c1;
     44  char *cp = NULL;
     45  char *buf = NULL;
     46  size_t sz;
     47 
     48  (void) arg;
     49  MOCK(connection_write_to_buf_impl_,
     50       connection_write_to_buf_impl_replacement);
     51 
     52  c1 = or_connection_new(CONN_TYPE_EXT_OR, AF_INET);
     53  tt_assert(c1);
     54 
     55  /* Length too long */
     56  tt_int_op(connection_write_ext_or_command(TO_CONN(c1), 100, "X", 100000),
     57            OP_LT, 0);
     58 
     59  /* Empty command */
     60  tt_int_op(connection_write_ext_or_command(TO_CONN(c1), 0x99, NULL, 0),
     61            OP_EQ, 0);
     62  cp = buf_get_contents(TO_CONN(c1)->outbuf, &sz);
     63  tt_int_op(sz, OP_EQ, 4);
     64  tt_mem_op(cp, OP_EQ, "\x00\x99\x00\x00", 4);
     65  tor_free(cp);
     66 
     67  /* Medium command. */
     68  tt_int_op(connection_write_ext_or_command(TO_CONN(c1), 0x99,
     69                                            "Wai\0Hello", 9), OP_EQ, 0);
     70  cp = buf_get_contents(TO_CONN(c1)->outbuf, &sz);
     71  tt_int_op(sz, OP_EQ, 13);
     72  tt_mem_op(cp, OP_EQ, "\x00\x99\x00\x09Wai\x00Hello", 13);
     73  tor_free(cp);
     74 
     75  /* Long command */
     76  buf = tor_malloc(65535);
     77  memset(buf, 'x', 65535);
     78  tt_int_op(connection_write_ext_or_command(TO_CONN(c1), 0xf00d,
     79                                            buf, 65535), OP_EQ, 0);
     80  cp = buf_get_contents(TO_CONN(c1)->outbuf, &sz);
     81  tt_int_op(sz, OP_EQ, 65539);
     82  tt_mem_op(cp, OP_EQ, "\xf0\x0d\xff\xff", 4);
     83  tt_mem_op(cp+4, OP_EQ, buf, 65535);
     84  tor_free(cp);
     85 
     86 done:
     87  if (c1)
     88    connection_free_minimal(TO_CONN(c1));
     89  tor_free(cp);
     90  tor_free(buf);
     91  UNMOCK(connection_write_to_buf_impl_);
     92 }
     93 
     94 static int
     95 write_bytes_to_file_fail(const char *fname, const char *str, size_t len,
     96                         int bin)
     97 {
     98  (void) fname;
     99  (void) str;
    100  (void) len;
    101  (void) bin;
    102 
    103  return -1;
    104 }
    105 
    106 static void
    107 test_ext_or_init_auth(void *arg)
    108 {
    109  or_options_t *options = get_options_mutable();
    110  const char *fn;
    111  char *cp = NULL;
    112  struct stat st;
    113  char cookie0[32];
    114  (void)arg;
    115 
    116  /* Check default filename location */
    117  tor_free(options->DataDirectory);
    118  options->DataDirectory = tor_strdup("foo");
    119  cp = get_ext_or_auth_cookie_file_name();
    120  tt_str_op(cp, OP_EQ, "foo"PATH_SEPARATOR"extended_orport_auth_cookie");
    121  tor_free(cp);
    122 
    123  /* Shouldn't be initialized already, or our tests will be a bit
    124   * meaningless */
    125  ext_or_auth_cookie = tor_malloc_zero(32);
    126  tt_assert(fast_mem_is_zero((char*)ext_or_auth_cookie, 32));
    127 
    128  /* Now make sure we use a temporary file */
    129  fn = get_fname("ext_cookie_file");
    130  options->ExtORPortCookieAuthFile = tor_strdup(fn);
    131  cp = get_ext_or_auth_cookie_file_name();
    132  tt_str_op(cp, OP_EQ, fn);
    133  tor_free(cp);
    134 
    135  /* Test the initialization function with a broken
    136     write_bytes_to_file(). See if the problem is handled properly. */
    137  MOCK(write_bytes_to_file, write_bytes_to_file_fail);
    138  tt_int_op(-1, OP_EQ, init_ext_or_cookie_authentication(1));
    139  tt_int_op(ext_or_auth_cookie_is_set, OP_EQ, 0);
    140  UNMOCK(write_bytes_to_file);
    141 
    142  /* Now do the actual initialization. */
    143  tt_int_op(0, OP_EQ, init_ext_or_cookie_authentication(1));
    144  tt_int_op(ext_or_auth_cookie_is_set, OP_EQ, 1);
    145  cp = read_file_to_str(fn, RFTS_BIN, &st);
    146  tt_ptr_op(cp, OP_NE, NULL);
    147  tt_u64_op((uint64_t)st.st_size, OP_EQ, 64);
    148  tt_mem_op(cp,OP_EQ, "! Extended ORPort Auth Cookie !\x0a", 32);
    149  tt_mem_op(cp+32,OP_EQ, ext_or_auth_cookie, 32);
    150  memcpy(cookie0, ext_or_auth_cookie, 32);
    151  tt_assert(!fast_mem_is_zero((char*)ext_or_auth_cookie, 32));
    152 
    153  /* Operation should be idempotent. */
    154  tt_int_op(0, OP_EQ, init_ext_or_cookie_authentication(1));
    155  tt_mem_op(cookie0,OP_EQ, ext_or_auth_cookie, 32);
    156 
    157 done:
    158  tor_free(cp);
    159  ext_orport_free_all();
    160 }
    161 
    162 static void
    163 test_ext_or_cookie_auth(void *arg)
    164 {
    165  char *reply=NULL, *reply2=NULL, *client_hash=NULL, *client_hash2=NULL;
    166  size_t reply_len=0;
    167  char hmac1[32], hmac2[32];
    168 
    169  NONSTRING const char client_nonce[32] =
    170    "Who is the third who walks alway";
    171  char server_hash_input[] =
    172    "ExtORPort authentication server-to-client hash"
    173    "Who is the third who walks alway"
    174    "................................";
    175  char client_hash_input[] =
    176    "ExtORPort authentication client-to-server hash"
    177    "Who is the third who walks alway"
    178    "................................";
    179 
    180  (void)arg;
    181 
    182  tt_int_op(strlen(client_hash_input), OP_EQ, 46+32+32);
    183  tt_int_op(strlen(server_hash_input), OP_EQ, 46+32+32);
    184 
    185  ext_or_auth_cookie = tor_malloc_zero(32);
    186  memcpy(ext_or_auth_cookie, "s beside you? When I count, ther", 32);
    187  ext_or_auth_cookie_is_set = 1;
    188 
    189  /* For this authentication, the client sends 32 random bytes (ClientNonce)
    190   * The server replies with 32 byte ServerHash and 32 byte ServerNonce,
    191   * where ServerHash is:
    192   * HMAC-SHA256(CookieString,
    193   *   "ExtORPort authentication server-to-client hash" | ClientNonce |
    194   *    ServerNonce)"
    195   * The client must reply with 32-byte ClientHash, which we compute as:
    196   *   ClientHash is computed as:
    197   *        HMAC-SHA256(CookieString,
    198   *           "ExtORPort authentication client-to-server hash" | ClientNonce |
    199   *            ServerNonce)
    200   */
    201 
    202  /* Wrong length */
    203  tt_int_op(-1, OP_EQ,
    204            handle_client_auth_nonce(client_nonce, 33, &client_hash, &reply,
    205                                     &reply_len));
    206  tt_int_op(-1, OP_EQ,
    207            handle_client_auth_nonce(client_nonce, 31, &client_hash, &reply,
    208                                     &reply_len));
    209 
    210  /* Now let's try this for real! */
    211  tt_int_op(0, OP_EQ,
    212            handle_client_auth_nonce(client_nonce, 32, &client_hash, &reply,
    213                                     &reply_len));
    214  tt_int_op(reply_len, OP_EQ, 64);
    215  tt_ptr_op(reply, OP_NE, NULL);
    216  tt_ptr_op(client_hash, OP_NE, NULL);
    217  /* Fill in the server nonce into the hash inputs... */
    218  memcpy(server_hash_input+46+32, reply+32, 32);
    219  memcpy(client_hash_input+46+32, reply+32, 32);
    220  /* Check the HMACs are correct... */
    221  crypto_hmac_sha256(hmac1, (char*)ext_or_auth_cookie, 32, server_hash_input,
    222                     46+32+32);
    223  crypto_hmac_sha256(hmac2, (char*)ext_or_auth_cookie, 32, client_hash_input,
    224                     46+32+32);
    225  tt_mem_op(hmac1,OP_EQ, reply, 32);
    226  tt_mem_op(hmac2,OP_EQ, client_hash, 32);
    227 
    228  /* Now do it again and make sure that the results are *different* */
    229  tt_int_op(0, OP_EQ,
    230            handle_client_auth_nonce(client_nonce, 32, &client_hash2, &reply2,
    231                                     &reply_len));
    232  tt_mem_op(reply2,OP_NE, reply, reply_len);
    233  tt_mem_op(client_hash2,OP_NE, client_hash, 32);
    234  /* But that this one checks out too. */
    235  memcpy(server_hash_input+46+32, reply2+32, 32);
    236  memcpy(client_hash_input+46+32, reply2+32, 32);
    237  /* Check the HMACs are correct... */
    238  crypto_hmac_sha256(hmac1, (char*)ext_or_auth_cookie, 32, server_hash_input,
    239                     46+32+32);
    240  crypto_hmac_sha256(hmac2, (char*)ext_or_auth_cookie, 32, client_hash_input,
    241                     46+32+32);
    242  tt_mem_op(hmac1,OP_EQ, reply2, 32);
    243  tt_mem_op(hmac2,OP_EQ, client_hash2, 32);
    244 
    245 done:
    246  tor_free(reply);
    247  tor_free(client_hash);
    248  tor_free(reply2);
    249  tor_free(client_hash2);
    250 }
    251 
    252 static void
    253 test_ext_or_cookie_auth_testvec(void *arg)
    254 {
    255  char *reply=NULL, *client_hash=NULL;
    256  size_t reply_len;
    257  char *mem_op_hex_tmp=NULL;
    258 
    259  const char client_nonce[] = "But when I look ahead up the whi";
    260  (void)arg;
    261 
    262  ext_or_auth_cookie = tor_malloc_zero(32);
    263  memcpy(ext_or_auth_cookie, "Gliding wrapt in a brown mantle," , 32);
    264  ext_or_auth_cookie_is_set = 1;
    265 
    266  testing_enable_prefilled_rng("te road There is always another ", 32);
    267 
    268  tt_int_op(0, OP_EQ,
    269            handle_client_auth_nonce(client_nonce, 32, &client_hash, &reply,
    270                                     &reply_len));
    271  tt_ptr_op(reply, OP_NE, NULL );
    272  tt_uint_op(reply_len, OP_EQ, 64);
    273  tt_mem_op(reply+32,OP_EQ, "te road There is always another ", 32);
    274  /* HMACSHA256("Gliding wrapt in a brown mantle,"
    275   *     "ExtORPort authentication server-to-client hash"
    276   *     "But when I look ahead up the write road There is always another ");
    277   */
    278  test_memeq_hex(reply,
    279                 "ec80ed6e546d3b36fdfc22fe1315416b"
    280                 "029f1ade7610d910878b62eeb7403821");
    281  /* HMACSHA256("Gliding wrapt in a brown mantle,"
    282   *     "ExtORPort authentication client-to-server hash"
    283   *     "But when I look ahead up the write road There is always another ");
    284   * (Both values computed using Python CLI.)
    285   */
    286  test_memeq_hex(client_hash,
    287                 "ab391732dd2ed968cd40c087d1b1f25b"
    288                 "33b3cd77ff79bd80c2074bbf438119a2");
    289 
    290 done:
    291  testing_disable_prefilled_rng();
    292  tor_free(reply);
    293  tor_free(client_hash);
    294  tor_free(mem_op_hex_tmp);
    295 }
    296 
    297 static void
    298 ignore_bootstrap_problem(const char *warn, int reason,
    299                         or_connection_t *conn)
    300 {
    301  (void)warn;
    302  (void)reason;
    303  (void)conn;
    304 }
    305 
    306 static int is_reading = 1;
    307 static int handshake_start_called = 0;
    308 
    309 static void
    310 note_read_stopped(connection_t *conn)
    311 {
    312  (void)conn;
    313  is_reading=0;
    314 }
    315 static void
    316 note_read_started(connection_t *conn)
    317 {
    318  (void)conn;
    319  is_reading=1;
    320 }
    321 static int
    322 handshake_start(or_connection_t *conn, int receiving)
    323 {
    324  if (!conn || !receiving)
    325    TT_FAIL(("Bad arguments to handshake_start"));
    326  handshake_start_called = 1;
    327  return 0;
    328 }
    329 
    330 #define WRITE(s,n)                                                      \
    331  do {                                                                  \
    332    buf_add(TO_CONN(conn)->inbuf, (s), (n));                           \
    333  } while (0)
    334 #define CONTAINS(s,n)                                           \
    335  do {                                                          \
    336    tt_int_op((n), OP_LE, sizeof(b));                              \
    337    tt_int_op(buf_datalen(TO_CONN(conn)->outbuf), OP_EQ, (n));     \
    338    if ((n)) {                                                  \
    339      buf_get_bytes(TO_CONN(conn)->outbuf, b, (n));                \
    340      tt_mem_op(b, OP_EQ, (s), (n));                               \
    341    }                                                           \
    342  } while (0)
    343 
    344 /* Helper: Do a successful Extended ORPort authentication handshake. */
    345 static void
    346 do_ext_or_handshake(or_connection_t *conn)
    347 {
    348  char b[256];
    349 
    350  tt_int_op(0, OP_EQ, connection_ext_or_start_auth(conn));
    351  CONTAINS("\x01\x00", 2);
    352  WRITE("\x01", 1);
    353  WRITE("But when I look ahead up the whi", 32);
    354  testing_enable_prefilled_rng("te road There is always another ", 32);
    355  tt_int_op(0, OP_EQ, connection_ext_or_process_inbuf(conn));
    356  testing_disable_prefilled_rng();
    357  tt_int_op(TO_CONN(conn)->state, OP_EQ,
    358            EXT_OR_CONN_STATE_AUTH_WAIT_CLIENT_HASH);
    359  CONTAINS("\xec\x80\xed\x6e\x54\x6d\x3b\x36\xfd\xfc\x22\xfe\x13\x15\x41\x6b"
    360           "\x02\x9f\x1a\xde\x76\x10\xd9\x10\x87\x8b\x62\xee\xb7\x40\x38\x21"
    361           "te road There is always another ", 64);
    362  /* Send the right response this time. */
    363  WRITE("\xab\x39\x17\x32\xdd\x2e\xd9\x68\xcd\x40\xc0\x87\xd1\xb1\xf2\x5b"
    364        "\x33\xb3\xcd\x77\xff\x79\xbd\x80\xc2\x07\x4b\xbf\x43\x81\x19\xa2",
    365        32);
    366  tt_int_op(0, OP_EQ, connection_ext_or_process_inbuf(conn));
    367  CONTAINS("\x01", 1);
    368  tt_assert(! TO_CONN(conn)->marked_for_close);
    369  tt_int_op(TO_CONN(conn)->state, OP_EQ, EXT_OR_CONN_STATE_OPEN);
    370 
    371 done: ;
    372 }
    373 
    374 static void
    375 test_ext_or_handshake(void *arg)
    376 {
    377  or_connection_t *conn=NULL;
    378  char b[256];
    379 
    380  (void) arg;
    381  MOCK(connection_write_to_buf_impl_,
    382       connection_write_to_buf_impl_replacement);
    383  /* Use same authenticators as for test_ext_or_cookie_auth_testvec */
    384  ext_or_auth_cookie = tor_malloc_zero(32);
    385  memcpy(ext_or_auth_cookie, "Gliding wrapt in a brown mantle," , 32);
    386  ext_or_auth_cookie_is_set = 1;
    387 
    388  tor_init_connection_lists();
    389 
    390  conn = or_connection_new(CONN_TYPE_EXT_OR, AF_INET);
    391  tt_int_op(0, OP_EQ, connection_ext_or_start_auth(conn));
    392  /* The server starts by telling us about the one supported authtype. */
    393  CONTAINS("\x01\x00", 2);
    394  /* Say the client hasn't responded yet. */
    395  tt_int_op(0, OP_EQ, connection_ext_or_process_inbuf(conn));
    396  /* Let's say the client replies badly. */
    397  WRITE("\x99", 1);
    398  tt_int_op(-1, OP_EQ, connection_ext_or_process_inbuf(conn));
    399  CONTAINS("", 0);
    400  tt_assert(TO_CONN(conn)->marked_for_close);
    401  close_closeable_connections();
    402  conn = NULL;
    403 
    404  /* Okay, try again. */
    405  conn = or_connection_new(CONN_TYPE_EXT_OR, AF_INET);
    406  tt_int_op(0, OP_EQ, connection_ext_or_start_auth(conn));
    407  CONTAINS("\x01\x00", 2);
    408  /* Let's say the client replies sensibly this time. "Yes, AUTHTYPE_COOKIE
    409   * sounds delicious. Let's have some of that!" */
    410  WRITE("\x01", 1);
    411  /* Let's say that the client also sends part of a nonce. */
    412  WRITE("But when I look ", 16);
    413  tt_int_op(0, OP_EQ, connection_ext_or_process_inbuf(conn));
    414  CONTAINS("", 0);
    415  tt_int_op(TO_CONN(conn)->state, OP_EQ,
    416            EXT_OR_CONN_STATE_AUTH_WAIT_CLIENT_NONCE);
    417  /* Pump it again. Nothing should happen. */
    418  tt_int_op(0, OP_EQ, connection_ext_or_process_inbuf(conn));
    419  /* send the rest of the nonce. */
    420  WRITE("ahead up the whi", 16);
    421  testing_enable_prefilled_rng("te road There is always another ", 32);
    422  tt_int_op(0, OP_EQ, connection_ext_or_process_inbuf(conn));
    423  testing_disable_prefilled_rng();
    424  /* We should get the right reply from the server. */
    425  CONTAINS("\xec\x80\xed\x6e\x54\x6d\x3b\x36\xfd\xfc\x22\xfe\x13\x15\x41\x6b"
    426           "\x02\x9f\x1a\xde\x76\x10\xd9\x10\x87\x8b\x62\xee\xb7\x40\x38\x21"
    427           "te road There is always another ", 64);
    428  /* Send the wrong response. */
    429  WRITE("not with a bang but a whimper...", 32);
    430  MOCK(control_event_bootstrap_prob_or, ignore_bootstrap_problem);
    431  tt_int_op(-1, OP_EQ, connection_ext_or_process_inbuf(conn));
    432  CONTAINS("\x00", 1);
    433  tt_assert(TO_CONN(conn)->marked_for_close);
    434  /* XXXX Hold-open-until-flushed. */
    435  close_closeable_connections();
    436  conn = NULL;
    437  UNMOCK(control_event_bootstrap_prob_or);
    438 
    439  MOCK(connection_start_reading, note_read_started);
    440  MOCK(connection_stop_reading, note_read_stopped);
    441  MOCK(connection_tls_start_handshake, handshake_start);
    442 
    443  /* Okay, this time let's succeed. */
    444  conn = or_connection_new(CONN_TYPE_EXT_OR, AF_INET);
    445  do_ext_or_handshake(conn);
    446 
    447  /* Now let's run through some messages. */
    448  /* First let's send some junk and make sure it's ignored. */
    449  WRITE("\xff\xf0\x00\x03""ABC", 7);
    450  tt_int_op(0, OP_EQ, connection_ext_or_process_inbuf(conn));
    451  CONTAINS("", 0);
    452  /* Now let's send a USERADDR command. */
    453  WRITE("\x00\x01\x00\x0c""1.2.3.4:5678", 16);
    454  tt_int_op(0, OP_EQ, connection_ext_or_process_inbuf(conn));
    455  tt_int_op(TO_CONN(conn)->port, OP_EQ, 5678);
    456  tt_int_op(tor_addr_to_ipv4h(&TO_CONN(conn)->addr), OP_EQ, 0x01020304);
    457  /* Now let's send a TRANSPORT command. */
    458  WRITE("\x00\x02\x00\x07""rfc1149", 11);
    459  tt_int_op(0, OP_EQ, connection_ext_or_process_inbuf(conn));
    460  tt_ptr_op(NULL, OP_NE, conn->ext_or_transport);
    461  tt_str_op("rfc1149", OP_EQ, conn->ext_or_transport);
    462  tt_int_op(is_reading,OP_EQ,1);
    463  tt_int_op(TO_CONN(conn)->state, OP_EQ, EXT_OR_CONN_STATE_OPEN);
    464  /* DONE */
    465  WRITE("\x00\x00\x00\x00", 4);
    466  tt_int_op(0, OP_EQ, connection_ext_or_process_inbuf(conn));
    467  tt_int_op(TO_CONN(conn)->state, OP_EQ, EXT_OR_CONN_STATE_FLUSHING);
    468  tt_int_op(is_reading,OP_EQ,0);
    469  CONTAINS("\x10\x00\x00\x00", 4);
    470  tt_int_op(handshake_start_called,OP_EQ,0);
    471  tt_int_op(0, OP_EQ, connection_ext_or_finished_flushing(conn));
    472  tt_int_op(is_reading,OP_EQ,1);
    473  tt_int_op(handshake_start_called,OP_EQ,1);
    474  tt_int_op(TO_CONN(conn)->type, OP_EQ, CONN_TYPE_OR);
    475  tt_int_op(TO_CONN(conn)->state, OP_EQ, 0);
    476  connection_free_(TO_CONN(conn));
    477  conn = NULL;
    478 
    479  /* Okay, this time let's succeed the handshake but fail the USERADDR
    480     command. */
    481  conn = or_connection_new(CONN_TYPE_EXT_OR, AF_INET);
    482  do_ext_or_handshake(conn);
    483  /* USERADDR command with an extra NUL byte */
    484  WRITE("\x00\x01\x00\x0d""1.2.3.4:5678\x00", 17);
    485  MOCK(control_event_bootstrap_prob_or, ignore_bootstrap_problem);
    486  tt_int_op(-1, OP_EQ, connection_ext_or_process_inbuf(conn));
    487  CONTAINS("", 0);
    488  tt_assert(TO_CONN(conn)->marked_for_close);
    489  close_closeable_connections();
    490  conn = NULL;
    491  UNMOCK(control_event_bootstrap_prob_or);
    492 
    493  /* Now fail the TRANSPORT command. */
    494  conn = or_connection_new(CONN_TYPE_EXT_OR, AF_INET);
    495  do_ext_or_handshake(conn);
    496  /* TRANSPORT command with an extra NUL byte */
    497  WRITE("\x00\x02\x00\x08""rfc1149\x00", 12);
    498  MOCK(control_event_bootstrap_prob_or, ignore_bootstrap_problem);
    499  tt_int_op(-1, OP_EQ, connection_ext_or_process_inbuf(conn));
    500  CONTAINS("", 0);
    501  tt_assert(TO_CONN(conn)->marked_for_close);
    502  close_closeable_connections();
    503  conn = NULL;
    504  UNMOCK(control_event_bootstrap_prob_or);
    505 
    506  /* Now fail the TRANSPORT command. */
    507  conn = or_connection_new(CONN_TYPE_EXT_OR, AF_INET);
    508  do_ext_or_handshake(conn);
    509  /* TRANSPORT command with transport name with symbols (not a
    510     C-identifier) */
    511  WRITE("\x00\x02\x00\x07""rf*1149", 11);
    512  MOCK(control_event_bootstrap_prob_or, ignore_bootstrap_problem);
    513  tt_int_op(-1, OP_EQ, connection_ext_or_process_inbuf(conn));
    514  CONTAINS("", 0);
    515  tt_assert(TO_CONN(conn)->marked_for_close);
    516  close_closeable_connections();
    517  conn = NULL;
    518  UNMOCK(control_event_bootstrap_prob_or);
    519 
    520 done:
    521  UNMOCK(connection_write_to_buf_impl_);
    522  testing_disable_prefilled_rng();
    523  if (conn)
    524    connection_free_minimal(TO_CONN(conn));
    525 #undef CONTAINS
    526 #undef WRITE
    527 }
    528 
    529 struct testcase_t extorport_tests[] = {
    530  { "write_command", test_ext_or_write_command, TT_FORK, NULL, NULL },
    531  { "init_auth", test_ext_or_init_auth, TT_FORK, NULL, NULL },
    532  { "cookie_auth", test_ext_or_cookie_auth, TT_FORK, NULL, NULL },
    533  { "cookie_auth_testvec", test_ext_or_cookie_auth_testvec, TT_FORK,
    534    NULL, NULL },
    535  { "handshake", test_ext_or_handshake, TT_FORK, &helper_pubsub_setup, NULL },
    536  END_OF_TESTCASES
    537 };