LCOV - code coverage report
Current view: top level - test - test_channeltls.c (source / functions) Hit Total Coverage
Test: lcov.info Lines: 146 148 98.6 %
Date: 2021-11-24 03:28:48 Functions: 7 7 100.0 %

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

Generated by: LCOV version 1.14