LCOV - code coverage report
Current view: top level - test - test_extorport.c (source / functions) Hit Total Coverage
Test: lcov.info Lines: 289 291 99.3 %
Date: 2021-11-24 03:28:48 Functions: 12 12 100.0 %

          Line data    Source code
       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          22 : connection_write_to_buf_impl_replacement(const char *string, size_t len,
      31             :                                          connection_t *conn, int compressed)
      32             : {
      33          22 :   (void) compressed;
      34             : 
      35          22 :   tor_assert(string);
      36          22 :   tor_assert(conn);
      37          22 :   buf_add(conn->outbuf, string, len);
      38          22 : }
      39             : 
      40             : static void
      41           1 : test_ext_or_write_command(void *arg)
      42             : {
      43           1 :   or_connection_t *c1;
      44           1 :   char *cp = NULL;
      45           1 :   char *buf = NULL;
      46           1 :   size_t sz;
      47             : 
      48           1 :   (void) arg;
      49           1 :   MOCK(connection_write_to_buf_impl_,
      50             :        connection_write_to_buf_impl_replacement);
      51             : 
      52           1 :   c1 = or_connection_new(CONN_TYPE_EXT_OR, AF_INET);
      53           1 :   tt_assert(c1);
      54             : 
      55             :   /* Length too long */
      56           1 :   tt_int_op(connection_write_ext_or_command(TO_CONN(c1), 100, "X", 100000),
      57             :             OP_LT, 0);
      58             : 
      59             :   /* Empty command */
      60           1 :   tt_int_op(connection_write_ext_or_command(TO_CONN(c1), 0x99, NULL, 0),
      61             :             OP_EQ, 0);
      62           1 :   cp = buf_get_contents(TO_CONN(c1)->outbuf, &sz);
      63           1 :   tt_int_op(sz, OP_EQ, 4);
      64           1 :   tt_mem_op(cp, OP_EQ, "\x00\x99\x00\x00", 4);
      65           1 :   tor_free(cp);
      66             : 
      67             :   /* Medium command. */
      68           1 :   tt_int_op(connection_write_ext_or_command(TO_CONN(c1), 0x99,
      69             :                                             "Wai\0Hello", 9), OP_EQ, 0);
      70           1 :   cp = buf_get_contents(TO_CONN(c1)->outbuf, &sz);
      71           1 :   tt_int_op(sz, OP_EQ, 13);
      72           1 :   tt_mem_op(cp, OP_EQ, "\x00\x99\x00\x09Wai\x00Hello", 13);
      73           1 :   tor_free(cp);
      74             : 
      75             :   /* Long command */
      76           1 :   buf = tor_malloc(65535);
      77           1 :   memset(buf, 'x', 65535);
      78           1 :   tt_int_op(connection_write_ext_or_command(TO_CONN(c1), 0xf00d,
      79             :                                             buf, 65535), OP_EQ, 0);
      80           1 :   cp = buf_get_contents(TO_CONN(c1)->outbuf, &sz);
      81           1 :   tt_int_op(sz, OP_EQ, 65539);
      82           1 :   tt_mem_op(cp, OP_EQ, "\xf0\x0d\xff\xff", 4);
      83           1 :   tt_mem_op(cp+4, OP_EQ, buf, 65535);
      84           1 :   tor_free(cp);
      85             : 
      86           1 :  done:
      87           1 :   if (c1)
      88           1 :     connection_free_minimal(TO_CONN(c1));
      89           1 :   tor_free(cp);
      90           1 :   tor_free(buf);
      91           1 :   UNMOCK(connection_write_to_buf_impl_);
      92           1 : }
      93             : 
      94             : static int
      95           1 : write_bytes_to_file_fail(const char *fname, const char *str, size_t len,
      96             :                          int bin)
      97             : {
      98           1 :   (void) fname;
      99           1 :   (void) str;
     100           1 :   (void) len;
     101           1 :   (void) bin;
     102             : 
     103           1 :   return -1;
     104             : }
     105             : 
     106             : static void
     107           1 : test_ext_or_init_auth(void *arg)
     108             : {
     109           1 :   or_options_t *options = get_options_mutable();
     110           1 :   const char *fn;
     111           1 :   char *cp = NULL;
     112           1 :   struct stat st;
     113           1 :   char cookie0[32];
     114           1 :   (void)arg;
     115             : 
     116             :   /* Check default filename location */
     117           1 :   tor_free(options->DataDirectory);
     118           1 :   options->DataDirectory = tor_strdup("foo");
     119           1 :   cp = get_ext_or_auth_cookie_file_name();
     120           1 :   tt_str_op(cp, OP_EQ, "foo"PATH_SEPARATOR"extended_orport_auth_cookie");
     121           1 :   tor_free(cp);
     122             : 
     123             :   /* Shouldn't be initialized already, or our tests will be a bit
     124             :    * meaningless */
     125           1 :   ext_or_auth_cookie = tor_malloc_zero(32);
     126           1 :   tt_assert(fast_mem_is_zero((char*)ext_or_auth_cookie, 32));
     127             : 
     128             :   /* Now make sure we use a temporary file */
     129           1 :   fn = get_fname("ext_cookie_file");
     130           1 :   options->ExtORPortCookieAuthFile = tor_strdup(fn);
     131           1 :   cp = get_ext_or_auth_cookie_file_name();
     132           1 :   tt_str_op(cp, OP_EQ, fn);
     133           1 :   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           1 :   MOCK(write_bytes_to_file, write_bytes_to_file_fail);
     138           1 :   tt_int_op(-1, OP_EQ, init_ext_or_cookie_authentication(1));
     139           1 :   tt_int_op(ext_or_auth_cookie_is_set, OP_EQ, 0);
     140           1 :   UNMOCK(write_bytes_to_file);
     141             : 
     142             :   /* Now do the actual initialization. */
     143           1 :   tt_int_op(0, OP_EQ, init_ext_or_cookie_authentication(1));
     144           1 :   tt_int_op(ext_or_auth_cookie_is_set, OP_EQ, 1);
     145           1 :   cp = read_file_to_str(fn, RFTS_BIN, &st);
     146           1 :   tt_ptr_op(cp, OP_NE, NULL);
     147           1 :   tt_u64_op((uint64_t)st.st_size, OP_EQ, 64);
     148           1 :   tt_mem_op(cp,OP_EQ, "! Extended ORPort Auth Cookie !\x0a", 32);
     149           1 :   tt_mem_op(cp+32,OP_EQ, ext_or_auth_cookie, 32);
     150           1 :   memcpy(cookie0, ext_or_auth_cookie, 32);
     151           1 :   tt_assert(!fast_mem_is_zero((char*)ext_or_auth_cookie, 32));
     152             : 
     153             :   /* Operation should be idempotent. */
     154           1 :   tt_int_op(0, OP_EQ, init_ext_or_cookie_authentication(1));
     155           1 :   tt_mem_op(cookie0,OP_EQ, ext_or_auth_cookie, 32);
     156             : 
     157           1 :  done:
     158           1 :   tor_free(cp);
     159           1 :   ext_orport_free_all();
     160           1 : }
     161             : 
     162             : static void
     163           1 : test_ext_or_cookie_auth(void *arg)
     164             : {
     165           1 :   char *reply=NULL, *reply2=NULL, *client_hash=NULL, *client_hash2=NULL;
     166           1 :   size_t reply_len=0;
     167           1 :   char hmac1[32], hmac2[32];
     168             : 
     169           1 :   const char client_nonce[32] =
     170             :     "Who is the third who walks alway";
     171           1 :   char server_hash_input[] =
     172             :     "ExtORPort authentication server-to-client hash"
     173             :     "Who is the third who walks alway"
     174             :     "................................";
     175           1 :   char client_hash_input[] =
     176             :     "ExtORPort authentication client-to-server hash"
     177             :     "Who is the third who walks alway"
     178             :     "................................";
     179             : 
     180           1 :   (void)arg;
     181             : 
     182           1 :   tt_int_op(strlen(client_hash_input), OP_EQ, 46+32+32);
     183           1 :   tt_int_op(strlen(server_hash_input), OP_EQ, 46+32+32);
     184             : 
     185           1 :   ext_or_auth_cookie = tor_malloc_zero(32);
     186           1 :   memcpy(ext_or_auth_cookie, "s beside you? When I count, ther", 32);
     187           1 :   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           1 :   tt_int_op(-1, OP_EQ,
     204             :             handle_client_auth_nonce(client_nonce, 33, &client_hash, &reply,
     205             :                                      &reply_len));
     206           1 :   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           1 :   tt_int_op(0, OP_EQ,
     212             :             handle_client_auth_nonce(client_nonce, 32, &client_hash, &reply,
     213             :                                      &reply_len));
     214           1 :   tt_int_op(reply_len, OP_EQ, 64);
     215           1 :   tt_ptr_op(reply, OP_NE, NULL);
     216           1 :   tt_ptr_op(client_hash, OP_NE, NULL);
     217             :   /* Fill in the server nonce into the hash inputs... */
     218           1 :   memcpy(server_hash_input+46+32, reply+32, 32);
     219           1 :   memcpy(client_hash_input+46+32, reply+32, 32);
     220             :   /* Check the HMACs are correct... */
     221           1 :   crypto_hmac_sha256(hmac1, (char*)ext_or_auth_cookie, 32, server_hash_input,
     222             :                      46+32+32);
     223           1 :   crypto_hmac_sha256(hmac2, (char*)ext_or_auth_cookie, 32, client_hash_input,
     224             :                      46+32+32);
     225           1 :   tt_mem_op(hmac1,OP_EQ, reply, 32);
     226           1 :   tt_mem_op(hmac2,OP_EQ, client_hash, 32);
     227             : 
     228             :   /* Now do it again and make sure that the results are *different* */
     229           1 :   tt_int_op(0, OP_EQ,
     230             :             handle_client_auth_nonce(client_nonce, 32, &client_hash2, &reply2,
     231             :                                      &reply_len));
     232           1 :   tt_mem_op(reply2,OP_NE, reply, reply_len);
     233           1 :   tt_mem_op(client_hash2,OP_NE, client_hash, 32);
     234             :   /* But that this one checks out too. */
     235           1 :   memcpy(server_hash_input+46+32, reply2+32, 32);
     236           1 :   memcpy(client_hash_input+46+32, reply2+32, 32);
     237             :   /* Check the HMACs are correct... */
     238           1 :   crypto_hmac_sha256(hmac1, (char*)ext_or_auth_cookie, 32, server_hash_input,
     239             :                      46+32+32);
     240           1 :   crypto_hmac_sha256(hmac2, (char*)ext_or_auth_cookie, 32, client_hash_input,
     241             :                      46+32+32);
     242           1 :   tt_mem_op(hmac1,OP_EQ, reply2, 32);
     243           1 :   tt_mem_op(hmac2,OP_EQ, client_hash2, 32);
     244             : 
     245           1 :  done:
     246           1 :   tor_free(reply);
     247           1 :   tor_free(client_hash);
     248           1 :   tor_free(reply2);
     249           1 :   tor_free(client_hash2);
     250           1 : }
     251             : 
     252             : static void
     253           1 : test_ext_or_cookie_auth_testvec(void *arg)
     254             : {
     255           1 :   char *reply=NULL, *client_hash=NULL;
     256           1 :   size_t reply_len;
     257           1 :   char *mem_op_hex_tmp=NULL;
     258             : 
     259           1 :   const char client_nonce[] = "But when I look ahead up the whi";
     260           1 :   (void)arg;
     261             : 
     262           1 :   ext_or_auth_cookie = tor_malloc_zero(32);
     263           1 :   memcpy(ext_or_auth_cookie, "Gliding wrapt in a brown mantle," , 32);
     264           1 :   ext_or_auth_cookie_is_set = 1;
     265             : 
     266           1 :   testing_enable_prefilled_rng("te road There is always another ", 32);
     267             : 
     268           1 :   tt_int_op(0, OP_EQ,
     269             :             handle_client_auth_nonce(client_nonce, 32, &client_hash, &reply,
     270             :                                      &reply_len));
     271           1 :   tt_ptr_op(reply, OP_NE, NULL );
     272           1 :   tt_uint_op(reply_len, OP_EQ, 64);
     273           1 :   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           1 :   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           1 :   test_memeq_hex(client_hash,
     287             :                  "ab391732dd2ed968cd40c087d1b1f25b"
     288             :                  "33b3cd77ff79bd80c2074bbf438119a2");
     289             : 
     290           1 :  done:
     291           1 :   testing_disable_prefilled_rng();
     292           1 :   tor_free(reply);
     293           1 :   tor_free(client_hash);
     294           1 :   tor_free(mem_op_hex_tmp);
     295           1 : }
     296             : 
     297             : static void
     298           4 : ignore_bootstrap_problem(const char *warn, int reason,
     299             :                          or_connection_t *conn)
     300             : {
     301           4 :   (void)warn;
     302           4 :   (void)reason;
     303           4 :   (void)conn;
     304           4 : }
     305             : 
     306             : static int is_reading = 1;
     307             : static int handshake_start_called = 0;
     308             : 
     309             : static void
     310           1 : note_read_stopped(connection_t *conn)
     311             : {
     312           1 :   (void)conn;
     313           1 :   is_reading=0;
     314           1 : }
     315             : static void
     316           1 : note_read_started(connection_t *conn)
     317             : {
     318           1 :   (void)conn;
     319           1 :   is_reading=1;
     320           1 : }
     321             : static int
     322           1 : handshake_start(or_connection_t *conn, int receiving)
     323             : {
     324           1 :   if (!conn || !receiving)
     325           0 :     TT_FAIL(("Bad arguments to handshake_start"));
     326           1 :   handshake_start_called = 1;
     327           1 :   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           4 : do_ext_or_handshake(or_connection_t *conn)
     347             : {
     348           4 :   char b[256];
     349             : 
     350           4 :   tt_int_op(0, OP_EQ, connection_ext_or_start_auth(conn));
     351           4 :   CONTAINS("\x01\x00", 2);
     352           4 :   WRITE("\x01", 1);
     353           4 :   WRITE("But when I look ahead up the whi", 32);
     354           4 :   testing_enable_prefilled_rng("te road There is always another ", 32);
     355           4 :   tt_int_op(0, OP_EQ, connection_ext_or_process_inbuf(conn));
     356           4 :   testing_disable_prefilled_rng();
     357           4 :   tt_int_op(TO_CONN(conn)->state, OP_EQ,
     358             :             EXT_OR_CONN_STATE_AUTH_WAIT_CLIENT_HASH);
     359           4 :   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           4 :   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           4 :   tt_int_op(0, OP_EQ, connection_ext_or_process_inbuf(conn));
     367           4 :   CONTAINS("\x01", 1);
     368           4 :   tt_assert(! TO_CONN(conn)->marked_for_close);
     369           4 :   tt_int_op(TO_CONN(conn)->state, OP_EQ, EXT_OR_CONN_STATE_OPEN);
     370             : 
     371           4 :  done: ;
     372           4 : }
     373             : 
     374             : static void
     375           1 : test_ext_or_handshake(void *arg)
     376             : {
     377           1 :   or_connection_t *conn=NULL;
     378           1 :   char b[256];
     379             : 
     380           1 :   (void) arg;
     381           1 :   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           1 :   ext_or_auth_cookie = tor_malloc_zero(32);
     385           1 :   memcpy(ext_or_auth_cookie, "Gliding wrapt in a brown mantle," , 32);
     386           1 :   ext_or_auth_cookie_is_set = 1;
     387             : 
     388           1 :   tor_init_connection_lists();
     389             : 
     390           1 :   conn = or_connection_new(CONN_TYPE_EXT_OR, AF_INET);
     391           1 :   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           1 :   CONTAINS("\x01\x00", 2);
     394             :   /* Say the client hasn't responded yet. */
     395           1 :   tt_int_op(0, OP_EQ, connection_ext_or_process_inbuf(conn));
     396             :   /* Let's say the client replies badly. */
     397           1 :   WRITE("\x99", 1);
     398           1 :   tt_int_op(-1, OP_EQ, connection_ext_or_process_inbuf(conn));
     399           1 :   CONTAINS("", 0);
     400           1 :   tt_assert(TO_CONN(conn)->marked_for_close);
     401           1 :   close_closeable_connections();
     402           1 :   conn = NULL;
     403             : 
     404             :   /* Okay, try again. */
     405           1 :   conn = or_connection_new(CONN_TYPE_EXT_OR, AF_INET);
     406           1 :   tt_int_op(0, OP_EQ, connection_ext_or_start_auth(conn));
     407           1 :   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           1 :   WRITE("\x01", 1);
     411             :   /* Let's say that the client also sends part of a nonce. */
     412           1 :   WRITE("But when I look ", 16);
     413           1 :   tt_int_op(0, OP_EQ, connection_ext_or_process_inbuf(conn));
     414           1 :   CONTAINS("", 0);
     415           1 :   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           1 :   tt_int_op(0, OP_EQ, connection_ext_or_process_inbuf(conn));
     419             :   /* send the rest of the nonce. */
     420           1 :   WRITE("ahead up the whi", 16);
     421           1 :   testing_enable_prefilled_rng("te road There is always another ", 32);
     422           1 :   tt_int_op(0, OP_EQ, connection_ext_or_process_inbuf(conn));
     423           1 :   testing_disable_prefilled_rng();
     424             :   /* We should get the right reply from the server. */
     425           1 :   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           1 :   WRITE("not with a bang but a whimper...", 32);
     430           1 :   MOCK(control_event_bootstrap_prob_or, ignore_bootstrap_problem);
     431           1 :   tt_int_op(-1, OP_EQ, connection_ext_or_process_inbuf(conn));
     432           1 :   CONTAINS("\x00", 1);
     433           1 :   tt_assert(TO_CONN(conn)->marked_for_close);
     434             :   /* XXXX Hold-open-until-flushed. */
     435           1 :   close_closeable_connections();
     436           1 :   conn = NULL;
     437           1 :   UNMOCK(control_event_bootstrap_prob_or);
     438             : 
     439           1 :   MOCK(connection_start_reading, note_read_started);
     440           1 :   MOCK(connection_stop_reading, note_read_stopped);
     441           1 :   MOCK(connection_tls_start_handshake, handshake_start);
     442             : 
     443             :   /* Okay, this time let's succeed. */
     444           1 :   conn = or_connection_new(CONN_TYPE_EXT_OR, AF_INET);
     445           1 :   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           1 :   WRITE("\xff\xf0\x00\x03""ABC", 7);
     450           1 :   tt_int_op(0, OP_EQ, connection_ext_or_process_inbuf(conn));
     451           1 :   CONTAINS("", 0);
     452             :   /* Now let's send a USERADDR command. */
     453           1 :   WRITE("\x00\x01\x00\x0c""1.2.3.4:5678", 16);
     454           1 :   tt_int_op(0, OP_EQ, connection_ext_or_process_inbuf(conn));
     455           1 :   tt_int_op(TO_CONN(conn)->port, OP_EQ, 5678);
     456           1 :   tt_int_op(tor_addr_to_ipv4h(&TO_CONN(conn)->addr), OP_EQ, 0x01020304);
     457             :   /* Now let's send a TRANSPORT command. */
     458           1 :   WRITE("\x00\x02\x00\x07""rfc1149", 11);
     459           1 :   tt_int_op(0, OP_EQ, connection_ext_or_process_inbuf(conn));
     460           1 :   tt_ptr_op(NULL, OP_NE, conn->ext_or_transport);
     461           1 :   tt_str_op("rfc1149", OP_EQ, conn->ext_or_transport);
     462           1 :   tt_int_op(is_reading,OP_EQ,1);
     463           1 :   tt_int_op(TO_CONN(conn)->state, OP_EQ, EXT_OR_CONN_STATE_OPEN);
     464             :   /* DONE */
     465           1 :   WRITE("\x00\x00\x00\x00", 4);
     466           1 :   tt_int_op(0, OP_EQ, connection_ext_or_process_inbuf(conn));
     467           1 :   tt_int_op(TO_CONN(conn)->state, OP_EQ, EXT_OR_CONN_STATE_FLUSHING);
     468           1 :   tt_int_op(is_reading,OP_EQ,0);
     469           1 :   CONTAINS("\x10\x00\x00\x00", 4);
     470           1 :   tt_int_op(handshake_start_called,OP_EQ,0);
     471           1 :   tt_int_op(0, OP_EQ, connection_ext_or_finished_flushing(conn));
     472           1 :   tt_int_op(is_reading,OP_EQ,1);
     473           1 :   tt_int_op(handshake_start_called,OP_EQ,1);
     474           1 :   tt_int_op(TO_CONN(conn)->type, OP_EQ, CONN_TYPE_OR);
     475           1 :   tt_int_op(TO_CONN(conn)->state, OP_EQ, 0);
     476           1 :   connection_free_(TO_CONN(conn));
     477           1 :   conn = NULL;
     478             : 
     479             :   /* Okay, this time let's succeed the handshake but fail the USERADDR
     480             :      command. */
     481           1 :   conn = or_connection_new(CONN_TYPE_EXT_OR, AF_INET);
     482           1 :   do_ext_or_handshake(conn);
     483             :   /* USERADDR command with an extra NUL byte */
     484           1 :   WRITE("\x00\x01\x00\x0d""1.2.3.4:5678\x00", 17);
     485           1 :   MOCK(control_event_bootstrap_prob_or, ignore_bootstrap_problem);
     486           1 :   tt_int_op(-1, OP_EQ, connection_ext_or_process_inbuf(conn));
     487           1 :   CONTAINS("", 0);
     488           1 :   tt_assert(TO_CONN(conn)->marked_for_close);
     489           1 :   close_closeable_connections();
     490           1 :   conn = NULL;
     491           1 :   UNMOCK(control_event_bootstrap_prob_or);
     492             : 
     493             :   /* Now fail the TRANSPORT command. */
     494           1 :   conn = or_connection_new(CONN_TYPE_EXT_OR, AF_INET);
     495           1 :   do_ext_or_handshake(conn);
     496             :   /* TRANSPORT command with an extra NUL byte */
     497           1 :   WRITE("\x00\x02\x00\x08""rfc1149\x00", 12);
     498           1 :   MOCK(control_event_bootstrap_prob_or, ignore_bootstrap_problem);
     499           1 :   tt_int_op(-1, OP_EQ, connection_ext_or_process_inbuf(conn));
     500           1 :   CONTAINS("", 0);
     501           1 :   tt_assert(TO_CONN(conn)->marked_for_close);
     502           1 :   close_closeable_connections();
     503           1 :   conn = NULL;
     504           1 :   UNMOCK(control_event_bootstrap_prob_or);
     505             : 
     506             :   /* Now fail the TRANSPORT command. */
     507           1 :   conn = or_connection_new(CONN_TYPE_EXT_OR, AF_INET);
     508           1 :   do_ext_or_handshake(conn);
     509             :   /* TRANSPORT command with transport name with symbols (not a
     510             :      C-identifier) */
     511           1 :   WRITE("\x00\x02\x00\x07""rf*1149", 11);
     512           1 :   MOCK(control_event_bootstrap_prob_or, ignore_bootstrap_problem);
     513           1 :   tt_int_op(-1, OP_EQ, connection_ext_or_process_inbuf(conn));
     514           1 :   CONTAINS("", 0);
     515           1 :   tt_assert(TO_CONN(conn)->marked_for_close);
     516           1 :   close_closeable_connections();
     517           1 :   conn = NULL;
     518           1 :   UNMOCK(control_event_bootstrap_prob_or);
     519             : 
     520           1 :  done:
     521           1 :   UNMOCK(connection_write_to_buf_impl_);
     522           1 :   testing_disable_prefilled_rng();
     523           1 :   if (conn)
     524           0 :     connection_free_minimal(TO_CONN(conn));
     525             : #undef CONTAINS
     526             : #undef WRITE
     527           1 : }
     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             : };

Generated by: LCOV version 1.14