tor

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

test_channeltls.c (10103B)


      1 /* Copyright (c) 2014-2021, The Tor Project, Inc. */
      2 /* See LICENSE for licensing information */
      3 
      4 #include "orconfig.h"
      5 
      6 #include <math.h>
      7 
      8 #define CHANNEL_OBJECT_PRIVATE
      9 #include "core/or/or.h"
     10 #include "lib/net/address.h"
     11 #include "lib/buf/buffers.h"
     12 #include "core/or/channel.h"
     13 #include "core/or/channeltls.h"
     14 #include "core/mainloop/connection.h"
     15 #include "core/or/connection_or.h"
     16 #include "app/config/config.h"
     17 #include "app/config/resolve_addr.h"
     18 /* For init/free stuff */
     19 #include "core/or/scheduler.h"
     20 #include "lib/tls/tortls.h"
     21 
     22 #include "core/or/or_connection_st.h"
     23 #include "core/or/congestion_control_common.h"
     24 
     25 /* Test suite stuff */
     26 #include "test/test.h"
     27 #include "test/fakechans.h"
     28 
     29 /* The channeltls unit tests */
     30 static void test_channeltls_create(void *arg);
     31 static void test_channeltls_num_bytes_queued(void *arg);
     32 static void test_channeltls_overhead_estimate(void *arg);
     33 
     34 /* Mocks used by channeltls unit tests */
     35 static size_t tlschan_buf_datalen_mock(const buf_t *buf);
     36 static or_connection_t * tlschan_connection_or_connect_mock(
     37    const tor_addr_t *addr,
     38    uint16_t port,
     39    const char *digest,
     40    const ed25519_public_key_t *ed_id,
     41    channel_tls_t *tlschan);
     42 static bool tlschan_resolved_addr_is_local_mock(const tor_addr_t *addr);
     43 
     44 /* Fake close method */
     45 static void tlschan_fake_close_method(channel_t *chan);
     46 
     47 /* Flags controlling behavior of channeltls unit test mocks */
     48 static bool tlschan_local = false;
     49 static const buf_t * tlschan_buf_datalen_mock_target = NULL;
     50 static size_t tlschan_buf_datalen_mock_size = 0;
     51 
     52 /* Thing to cast to fake tor_tls_t * to appease assert_connection_ok() */
     53 static int fake_tortls = 0; /* Bleh... */
     54 
     55 static void
     56 test_channeltls_create(void *arg)
     57 {
     58  tor_addr_t test_addr;
     59  channel_t *ch = NULL;
     60  const char test_digest[DIGEST_LEN] = {
     61    0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a,
     62    0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14 };
     63 
     64  (void)arg;
     65 
     66  /* Set up a fake address to fake-connect to */
     67  test_addr.family = AF_INET;
     68  test_addr.addr.in_addr.s_addr = htonl(0x01020304);
     69 
     70  /* For this test we always want the address to be treated as non-local */
     71  tlschan_local = false;
     72  /* Install is_local_to_resolve_addr() mock */
     73  MOCK(is_local_to_resolve_addr, tlschan_resolved_addr_is_local_mock);
     74 
     75  /* Install mock for connection_or_connect() */
     76  MOCK(connection_or_connect, tlschan_connection_or_connect_mock);
     77 
     78  /* Try connecting */
     79  ch = channel_tls_connect(&test_addr, 567, test_digest, NULL);
     80  tt_ptr_op(ch, OP_NE, NULL);
     81 
     82 done:
     83  if (ch) {
     84    MOCK(scheduler_release_channel, scheduler_release_channel_mock);
     85    /*
     86     * Use fake close method that doesn't try to do too much to fake
     87     * orconn
     88     */
     89    ch->close = tlschan_fake_close_method;
     90    channel_mark_for_close(ch);
     91    free_fake_channel(ch);
     92    UNMOCK(scheduler_release_channel);
     93  }
     94 
     95  UNMOCK(connection_or_connect);
     96  UNMOCK(is_local_to_resolve_addr);
     97 
     98  return;
     99 }
    100 
    101 static void
    102 test_channeltls_num_bytes_queued(void *arg)
    103 {
    104  tor_addr_t test_addr;
    105  channel_t *ch = NULL;
    106  const char test_digest[DIGEST_LEN] = {
    107    0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a,
    108    0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14 };
    109  channel_tls_t *tlschan = NULL;
    110  size_t len;
    111  int fake_outbuf = 0, n;
    112 
    113  (void)arg;
    114 
    115  /* Set up a fake address to fake-connect to */
    116  test_addr.family = AF_INET;
    117  test_addr.addr.in_addr.s_addr = htonl(0x01020304);
    118 
    119  /* For this test we always want the address to be treated as non-local */
    120  tlschan_local = false;
    121  /* Install is_local_to_resolve_addr() mock */
    122  MOCK(is_local_to_resolve_addr, tlschan_resolved_addr_is_local_mock);
    123 
    124  /* Install mock for connection_or_connect() */
    125  MOCK(connection_or_connect, tlschan_connection_or_connect_mock);
    126 
    127  /* Try connecting */
    128  ch = channel_tls_connect(&test_addr, 567, test_digest, NULL);
    129  tt_ptr_op(ch, OP_NE, NULL);
    130 
    131  /*
    132   * Next, we have to test ch->num_bytes_queued, which is
    133   * channel_tls_num_bytes_queued_method.  We can't mock
    134   * connection_get_outbuf_len() directly because it's static inline
    135   * in connection.h, but we can mock buf_datalen().
    136   */
    137 
    138  tt_assert(ch->num_bytes_queued != NULL);
    139  tlschan = BASE_CHAN_TO_TLS(ch);
    140  tt_ptr_op(tlschan, OP_NE, NULL);
    141  if (TO_CONN(tlschan->conn)->outbuf == NULL) {
    142    /* We need an outbuf to make sure buf_datalen() gets called */
    143    fake_outbuf = 1;
    144    TO_CONN(tlschan->conn)->outbuf = buf_new();
    145  }
    146  tlschan_buf_datalen_mock_target = TO_CONN(tlschan->conn)->outbuf;
    147  tlschan_buf_datalen_mock_size = 1024;
    148  MOCK(buf_datalen, tlschan_buf_datalen_mock);
    149  len = ch->num_bytes_queued(ch);
    150  tt_int_op(len, OP_EQ, tlschan_buf_datalen_mock_size);
    151  /*
    152   * We also cover num_cells_writeable here; since wide_circ_ids = 0 on
    153   * the fake tlschans, cell_network_size returns 512, and so with
    154   * tlschan_buf_datalen_mock_size == 1024, we should be able to write
    155   * ceil((OR_CONN_HIGHWATER - 1024) / 512) = ceil(OR_CONN_HIGHWATER / 512)
    156   * - 2 cells.
    157   */
    158  n = ch->num_cells_writeable(ch);
    159  tt_int_op(n, OP_EQ, CEIL_DIV(or_conn_highwatermark(), 512) - 2);
    160  UNMOCK(buf_datalen);
    161  tlschan_buf_datalen_mock_target = NULL;
    162  tlschan_buf_datalen_mock_size = 0;
    163  if (fake_outbuf) {
    164    buf_free(TO_CONN(tlschan->conn)->outbuf);
    165    TO_CONN(tlschan->conn)->outbuf = NULL;
    166  }
    167 
    168 done:
    169  if (ch) {
    170    MOCK(scheduler_release_channel, scheduler_release_channel_mock);
    171    /*
    172     * Use fake close method that doesn't try to do too much to fake
    173     * orconn
    174     */
    175    ch->close = tlschan_fake_close_method;
    176    channel_mark_for_close(ch);
    177    free_fake_channel(ch);
    178    UNMOCK(scheduler_release_channel);
    179  }
    180 
    181  UNMOCK(connection_or_connect);
    182  UNMOCK(is_local_to_resolve_addr);
    183 
    184  return;
    185 }
    186 
    187 static void
    188 test_channeltls_overhead_estimate(void *arg)
    189 {
    190  tor_addr_t test_addr;
    191  channel_t *ch = NULL;
    192  const char test_digest[DIGEST_LEN] = {
    193    0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a,
    194    0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14 };
    195  double r;
    196  channel_tls_t *tlschan = NULL;
    197 
    198  (void)arg;
    199 
    200  /* Set up a fake address to fake-connect to */
    201  test_addr.family = AF_INET;
    202  test_addr.addr.in_addr.s_addr = htonl(0x01020304);
    203 
    204  /* For this test we always want the address to be treated as non-local */
    205  tlschan_local = false;
    206  /* Install is_local_to_resolve_addr() mock */
    207  MOCK(is_local_to_resolve_addr, tlschan_resolved_addr_is_local_mock);
    208 
    209  /* Install mock for connection_or_connect() */
    210  MOCK(connection_or_connect, tlschan_connection_or_connect_mock);
    211 
    212  /* Try connecting */
    213  ch = channel_tls_connect(&test_addr, 567, test_digest, NULL);
    214  tt_ptr_op(ch, OP_NE, NULL);
    215 
    216  /* First case: silly low ratios should get clamped to 1.0 */
    217  tlschan = BASE_CHAN_TO_TLS(ch);
    218  tt_ptr_op(tlschan, OP_NE, NULL);
    219  tlschan->conn->bytes_xmitted = 128;
    220  tlschan->conn->bytes_xmitted_by_tls = 64;
    221  r = ch->get_overhead_estimate(ch);
    222  tt_assert(fabs(r - 1.0) < 1E-12);
    223 
    224  tlschan->conn->bytes_xmitted_by_tls = 127;
    225  r = ch->get_overhead_estimate(ch);
    226  tt_assert(fabs(r - 1.0) < 1E-12);
    227 
    228  /* Now middle of the range */
    229  tlschan->conn->bytes_xmitted_by_tls = 192;
    230  r = ch->get_overhead_estimate(ch);
    231  tt_assert(fabs(r - 1.5) < 1E-12);
    232 
    233  /* Now above the 2.0 clamp */
    234  tlschan->conn->bytes_xmitted_by_tls = 257;
    235  r = ch->get_overhead_estimate(ch);
    236  tt_assert(fabs(r - 2.0) < 1E-12);
    237 
    238  tlschan->conn->bytes_xmitted_by_tls = 512;
    239  r = ch->get_overhead_estimate(ch);
    240  tt_assert(fabs(r - 2.0) < 1E-12);
    241 
    242 done:
    243  if (ch) {
    244    MOCK(scheduler_release_channel, scheduler_release_channel_mock);
    245    /*
    246     * Use fake close method that doesn't try to do too much to fake
    247     * orconn
    248     */
    249    ch->close = tlschan_fake_close_method;
    250    channel_mark_for_close(ch);
    251    free_fake_channel(ch);
    252    UNMOCK(scheduler_release_channel);
    253  }
    254 
    255  UNMOCK(connection_or_connect);
    256  UNMOCK(is_local_to_resolve_addr);
    257 
    258  return;
    259 }
    260 
    261 static size_t
    262 tlschan_buf_datalen_mock(const buf_t *buf)
    263 {
    264  if (buf != NULL && buf == tlschan_buf_datalen_mock_target) {
    265    return tlschan_buf_datalen_mock_size;
    266  } else {
    267    return buf_datalen__real(buf);
    268  }
    269 }
    270 
    271 static or_connection_t *
    272 tlschan_connection_or_connect_mock(const tor_addr_t *addr,
    273                                   uint16_t port,
    274                                   const char *digest,
    275                                   const ed25519_public_key_t *ed_id,
    276                                   channel_tls_t *tlschan)
    277 {
    278  or_connection_t *result = NULL;
    279  (void) ed_id; // XXXX Not yet used.
    280 
    281  tt_ptr_op(addr, OP_NE, NULL);
    282  tt_uint_op(port, OP_NE, 0);
    283  tt_ptr_op(digest, OP_NE, NULL);
    284  tt_ptr_op(tlschan, OP_NE, NULL);
    285 
    286  /* Make a fake orconn */
    287  result = tor_malloc_zero(sizeof(*result));
    288  result->base_.magic = OR_CONNECTION_MAGIC;
    289  result->base_.state = OR_CONN_STATE_OPEN;
    290  result->base_.type = CONN_TYPE_OR;
    291  result->base_.socket_family = addr->family;
    292  result->base_.address = tor_strdup("<fake>");
    293  memcpy(&(result->base_.addr), addr, sizeof(tor_addr_t));
    294  result->base_.port = port;
    295  memcpy(result->identity_digest, digest, DIGEST_LEN);
    296  result->chan = tlschan;
    297  memcpy(&result->base_.addr, addr, sizeof(tor_addr_t));
    298  result->tls = (tor_tls_t *)((void *)(&fake_tortls));
    299 
    300 done:
    301  return result;
    302 }
    303 
    304 static void
    305 tlschan_fake_close_method(channel_t *chan)
    306 {
    307  channel_tls_t *tlschan = NULL;
    308 
    309  tt_ptr_op(chan, OP_NE, NULL);
    310  tt_int_op(chan->magic, OP_EQ, TLS_CHAN_MAGIC);
    311 
    312  tlschan = BASE_CHAN_TO_TLS(chan);
    313  tt_ptr_op(tlschan, OP_NE, NULL);
    314 
    315  /* Just free the fake orconn */
    316  tor_free(tlschan->conn->base_.address);
    317  tor_free(tlschan->conn);
    318 
    319  channel_closed(chan);
    320 
    321 done:
    322  return;
    323 }
    324 
    325 static bool
    326 tlschan_resolved_addr_is_local_mock(const tor_addr_t *addr)
    327 {
    328  tt_ptr_op(addr, OP_NE, NULL);
    329 
    330 done:
    331  return tlschan_local;
    332 }
    333 
    334 struct testcase_t channeltls_tests[] = {
    335  { "create", test_channeltls_create, TT_FORK, NULL, NULL },
    336  { "num_bytes_queued", test_channeltls_num_bytes_queued,
    337    TT_FORK, NULL, NULL },
    338  { "overhead_estimate", test_channeltls_overhead_estimate,
    339    TT_FORK, NULL, NULL },
    340  END_OF_TESTCASES
    341 };