LCOV - code coverage report
Current view: top level - test - test_relaycell.c (source / functions) Hit Total Coverage
Test: lcov.info Lines: 541 548 98.7 %
Date: 2021-11-24 03:28:48 Functions: 16 16 100.0 %

          Line data    Source code
       1             : /* Copyright (c) 2014-2021, The Tor Project, Inc. */
       2             : /* See LICENSE for licensing information */
       3             : 
       4             : /* Unit tests for handling different kinds of relay cell */
       5             : 
       6             : #define RELAY_PRIVATE
       7             : #define CIRCUITLIST_PRIVATE
       8             : #define CONNECTION_EDGE_PRIVATE
       9             : #define CONNECTION_PRIVATE
      10             : 
      11             : #include "core/or/or.h"
      12             : #include "core/mainloop/mainloop.h"
      13             : #include "app/config/config.h"
      14             : #include "core/mainloop/connection.h"
      15             : #include "lib/crypt_ops/crypto_cipher.h"
      16             : #include "lib/crypt_ops/crypto_rand.h"
      17             : #include "core/or/circuitbuild.h"
      18             : #include "core/or/circuitlist.h"
      19             : #include "core/or/connection_edge.h"
      20             : #include "core/or/sendme.h"
      21             : #include "core/or/relay.h"
      22             : #include "test/test.h"
      23             : #include "test/log_test_helpers.h"
      24             : 
      25             : #include "core/or/cell_st.h"
      26             : #include "core/or/crypt_path_st.h"
      27             : #include "core/or/entry_connection_st.h"
      28             : #include "core/or/origin_circuit_st.h"
      29             : #include "core/or/socks_request_st.h"
      30             : #include "core/or/half_edge_st.h"
      31             : 
      32             : #include "feature/client/circpathbias.h"
      33             : 
      34             : static int srm_ncalls;
      35             : static entry_connection_t *srm_conn;
      36             : static int srm_atype;
      37             : static size_t srm_alen;
      38             : static int srm_answer_is_set;
      39             : static uint8_t srm_answer[512];
      40             : static int srm_ttl;
      41             : static time_t srm_expires;
      42             : 
      43             : /* Mock replacement for connection_ap_hannshake_socks_resolved() */
      44             : static void
      45           9 : socks_resolved_mock(entry_connection_t *conn,
      46             :                     int answer_type,
      47             :                     size_t answer_len,
      48             :                     const uint8_t *answer,
      49             :                     int ttl,
      50             :                     time_t expires)
      51             : {
      52           9 :   srm_ncalls++;
      53           9 :   srm_conn = conn;
      54           9 :   srm_atype = answer_type;
      55           9 :   srm_alen = answer_len;
      56           9 :   if (answer) {
      57           5 :     memset(srm_answer, 0, sizeof(srm_answer));
      58           5 :     memcpy(srm_answer, answer, answer_len < 512 ? answer_len : 512);
      59           5 :     srm_answer_is_set = 1;
      60             :   } else {
      61           4 :     srm_answer_is_set = 0;
      62             :   }
      63           9 :   srm_ttl = ttl;
      64           9 :   srm_expires = expires;
      65           9 : }
      66             : 
      67             : static int mum_ncalls;
      68             : static entry_connection_t *mum_conn;
      69             : static int mum_endreason;
      70             : 
      71             : /* Mock replacement for connection_mark_unattached_ap_() */
      72             : static void
      73          10 : mark_unattached_mock(entry_connection_t *conn, int endreason,
      74             :                      int line, const char *file)
      75             : {
      76          10 :   ++mum_ncalls;
      77          10 :   mum_conn = conn;
      78          10 :   mum_endreason = endreason;
      79          10 :   (void) line;
      80          10 :   (void) file;
      81          10 : }
      82             : 
      83             : /* Helper: Return a newly allocated and initialized origin circuit with
      84             :  * purpose and flags. A default HS identifier is set to an ed25519
      85             :  * authentication key for introduction point. */
      86             : static origin_circuit_t *
      87           5 : helper_create_origin_circuit(int purpose, int flags)
      88             : {
      89           5 :   origin_circuit_t *circ = NULL;
      90             : 
      91           5 :   circ = origin_circuit_init(purpose, flags);
      92           5 :   tor_assert(circ);
      93           5 :   circ->cpath = tor_malloc_zero(sizeof(crypt_path_t));
      94           5 :   circ->cpath->magic = CRYPT_PATH_MAGIC;
      95           5 :   circ->cpath->state = CPATH_STATE_OPEN;
      96           5 :   circ->cpath->package_window = circuit_initial_package_window();
      97           5 :   circ->cpath->deliver_window = CIRCWINDOW_START;
      98           5 :   circ->cpath->prev = circ->cpath;
      99             :   /* Create a default HS identifier. */
     100           5 :   circ->hs_ident = tor_malloc_zero(sizeof(hs_ident_circuit_t));
     101             : 
     102           5 :   return circ;
     103             : }
     104             : 
     105             : static void
     106           2 : mock_connection_mark_unattached_ap_(entry_connection_t *conn, int endreason,
     107             :                                     int line, const char *file)
     108             : {
     109           2 :   (void) line;
     110           2 :   (void) file;
     111           2 :   conn->edge_.end_reason = endreason;
     112           2 : }
     113             : 
     114             : static void
     115           1 : mock_mark_circ_for_close(circuit_t *circ, int reason, int line,
     116             :                           const char *file)
     117             : {
     118           1 :   (void)reason; (void)line; (void)file;
     119             : 
     120           1 :   circ->marked_for_close = 1;
     121           1 :   return;
     122             : }
     123             : 
     124             : static void
     125           8 : mock_mark_for_close(connection_t *conn,
     126             :                         int line, const char *file)
     127             : {
     128           8 :   (void)line;
     129           8 :   (void)file;
     130             : 
     131           8 :   conn->marked_for_close = 1;
     132           8 :   return;
     133             : }
     134             : 
     135             : static void
     136           1 : mock_start_reading(connection_t *conn)
     137             : {
     138           1 :   (void)conn;
     139           1 :   return;
     140             : }
     141             : 
     142             : static int
     143          11 : mock_send_command(streamid_t stream_id, circuit_t *circ,
     144             :                                uint8_t relay_command, const char *payload,
     145             :                                size_t payload_len, crypt_path_t *cpath_layer,
     146             :                                const char *filename, int lineno)
     147             : {
     148          11 :  (void)stream_id; (void)circ;
     149          11 :  (void)relay_command; (void)payload;
     150          11 :  (void)payload_len; (void)cpath_layer;
     151          11 :  (void)filename; (void)lineno;
     152             : 
     153          11 :  return 0;
     154             : }
     155             : 
     156             : static entry_connection_t *
     157          11 : fake_entry_conn(origin_circuit_t *oncirc, streamid_t id)
     158             : {
     159          11 :   edge_connection_t *edgeconn;
     160          11 :   entry_connection_t *entryconn;
     161             : 
     162          11 :   entryconn = entry_connection_new(CONN_TYPE_AP, AF_INET);
     163          11 :   edgeconn = ENTRY_TO_EDGE_CONN(entryconn);
     164          11 :   edgeconn->base_.state = AP_CONN_STATE_CONNECT_WAIT;
     165          11 :   edgeconn->deliver_window = STREAMWINDOW_START;
     166          11 :   edgeconn->package_window = STREAMWINDOW_START;
     167             : 
     168          11 :   edgeconn->stream_id = id;
     169          11 :   edgeconn->on_circuit = TO_CIRCUIT(oncirc);
     170          11 :   edgeconn->cpath_layer = oncirc->cpath;
     171             : 
     172          11 :   return entryconn;
     173             : }
     174             : 
     175             : #define PACK_CELL(id, cmd, body_s) do {                                  \
     176             :     memset(&cell, 0, sizeof(cell));                                     \
     177             :     memset(&rh, 0, sizeof(rh));                                         \
     178             :     memcpy(cell.payload+RELAY_HEADER_SIZE, (body_s), sizeof((body_s))-1); \
     179             :     rh.length = sizeof((body_s))-1;                                     \
     180             :     rh.command = (cmd);                                                 \
     181             :     rh.stream_id = (id);                                                \
     182             :     relay_header_pack((uint8_t*)&cell.payload, &rh);                    \
     183             :   } while (0)
     184             : #define ASSERT_COUNTED_BW() do { \
     185             :     tt_int_op(circ->n_delivered_read_circ_bw, OP_EQ, delivered+rh.length); \
     186             :     tt_int_op(circ->n_overhead_read_circ_bw, OP_EQ,                      \
     187             :               overhead+RELAY_PAYLOAD_SIZE-rh.length);               \
     188             :     delivered = circ->n_delivered_read_circ_bw;                          \
     189             :     overhead = circ->n_overhead_read_circ_bw;                            \
     190             :  } while (0)
     191             : #define ASSERT_UNCOUNTED_BW() do { \
     192             :     tt_int_op(circ->n_delivered_read_circ_bw, OP_EQ, delivered); \
     193             :     tt_int_op(circ->n_overhead_read_circ_bw, OP_EQ, overhead); \
     194             :  } while (0)
     195             : 
     196             : static int
     197           2 : subtest_circbw_halfclosed(origin_circuit_t *circ, streamid_t init_id)
     198             : {
     199           2 :   cell_t cell;
     200           2 :   relay_header_t rh;
     201           2 :   edge_connection_t *edgeconn;
     202           2 :   entry_connection_t *entryconn2=NULL;
     203           2 :   entry_connection_t *entryconn3=NULL;
     204           2 :   entry_connection_t *entryconn4=NULL;
     205           2 :   int delivered = circ->n_delivered_read_circ_bw;
     206           2 :   int overhead = circ->n_overhead_read_circ_bw;
     207             : 
     208             :   /* Make new entryconns */
     209           2 :   entryconn2 = fake_entry_conn(circ, init_id);
     210           2 :   entryconn2->socks_request->has_finished = 1;
     211           2 :   entryconn3 = fake_entry_conn(circ, init_id+1);
     212           2 :   entryconn3->socks_request->has_finished = 1;
     213           2 :   entryconn4 = fake_entry_conn(circ, init_id+2);
     214           2 :   entryconn4->socks_request->has_finished = 1;
     215           2 :   edgeconn = ENTRY_TO_EDGE_CONN(entryconn2);
     216           2 :   edgeconn->package_window = 23;
     217           2 :   edgeconn->base_.state = AP_CONN_STATE_OPEN;
     218             : 
     219           2 :   int data_cells = edgeconn->deliver_window;
     220           2 :   int sendme_cells = (STREAMWINDOW_START-edgeconn->package_window)
     221             :                              /STREAMWINDOW_INCREMENT;
     222           2 :   ENTRY_TO_CONN(entryconn2)->marked_for_close = 0;
     223           2 :   connection_edge_reached_eof(edgeconn);
     224             : 
     225             :   /* Data cell not in the half-opened list */
     226           2 :   PACK_CELL(4000, RELAY_COMMAND_DATA, "Data1234");
     227           2 :   if (circ->base_.purpose == CIRCUIT_PURPOSE_PATH_BIAS_TESTING)
     228           1 :     pathbias_count_valid_cells(TO_CIRCUIT(circ), &cell);
     229             :   else
     230           1 :     connection_edge_process_relay_cell(&cell, TO_CIRCUIT(circ), NULL,
     231             :                                        circ->cpath);
     232           2 :   ASSERT_UNCOUNTED_BW();
     233             : 
     234             :   /* Sendme cell not in the half-opened list */
     235           2 :   PACK_CELL(4000, RELAY_COMMAND_SENDME, "Data1234");
     236           2 :   if (circ->base_.purpose == CIRCUIT_PURPOSE_PATH_BIAS_TESTING)
     237           1 :     pathbias_count_valid_cells(TO_CIRCUIT(circ), &cell);
     238             :   else
     239           1 :     connection_edge_process_relay_cell(&cell, TO_CIRCUIT(circ), NULL,
     240             :                                      circ->cpath);
     241           2 :   ASSERT_UNCOUNTED_BW();
     242             : 
     243             :   /* Connected cell not in the half-opened list */
     244           2 :   PACK_CELL(4000, RELAY_COMMAND_CONNECTED, "Data1234");
     245           2 :   if (circ->base_.purpose == CIRCUIT_PURPOSE_PATH_BIAS_TESTING)
     246           1 :     pathbias_count_valid_cells(TO_CIRCUIT(circ), &cell);
     247             :   else
     248           1 :     connection_edge_process_relay_cell(&cell, TO_CIRCUIT(circ), NULL,
     249             :                                      circ->cpath);
     250           2 :   ASSERT_UNCOUNTED_BW();
     251             : 
     252             :   /* Resolved cell not in the half-opened list */
     253           2 :   PACK_CELL(4000, RELAY_COMMAND_RESOLVED, "Data1234");
     254           2 :   if (circ->base_.purpose == CIRCUIT_PURPOSE_PATH_BIAS_TESTING)
     255           1 :     pathbias_count_valid_cells(TO_CIRCUIT(circ), &cell);
     256             :   else
     257           1 :     connection_edge_process_relay_cell(&cell, TO_CIRCUIT(circ), NULL,
     258             :                                      circ->cpath);
     259           2 :   ASSERT_UNCOUNTED_BW();
     260             : 
     261             :   /* Connected cell: not counted -- we were open */
     262           2 :   edgeconn = ENTRY_TO_EDGE_CONN(entryconn2);
     263           2 :   PACK_CELL(edgeconn->stream_id, RELAY_COMMAND_CONNECTED, "Data1234");
     264           2 :   if (circ->base_.purpose == CIRCUIT_PURPOSE_PATH_BIAS_TESTING)
     265           1 :     pathbias_count_valid_cells(TO_CIRCUIT(circ), &cell);
     266             :   else
     267           1 :     connection_edge_process_relay_cell(&cell, TO_CIRCUIT(circ), NULL,
     268             :                                      circ->cpath);
     269           2 :   ASSERT_UNCOUNTED_BW();
     270             : 
     271             :   /* DATA cells up to limit */
     272        1002 :   while (data_cells > 0) {
     273        1000 :     ENTRY_TO_CONN(entryconn2)->marked_for_close = 0;
     274        1000 :     PACK_CELL(edgeconn->stream_id, RELAY_COMMAND_DATA, "Data1234");
     275        1000 :     if (circ->base_.purpose == CIRCUIT_PURPOSE_PATH_BIAS_TESTING)
     276         500 :       pathbias_count_valid_cells(TO_CIRCUIT(circ), &cell);
     277             :     else
     278         500 :       connection_edge_process_relay_cell(&cell, TO_CIRCUIT(circ), NULL,
     279             :                                        circ->cpath);
     280        1000 :     ASSERT_COUNTED_BW();
     281        1000 :     data_cells--;
     282             :   }
     283           2 :   ENTRY_TO_CONN(entryconn2)->marked_for_close = 0;
     284           2 :   PACK_CELL(edgeconn->stream_id, RELAY_COMMAND_DATA, "Data1234");
     285           2 :   if (circ->base_.purpose == CIRCUIT_PURPOSE_PATH_BIAS_TESTING)
     286           1 :     pathbias_count_valid_cells(TO_CIRCUIT(circ), &cell);
     287             :   else
     288           1 :     connection_edge_process_relay_cell(&cell, TO_CIRCUIT(circ), NULL,
     289             :                                      circ->cpath);
     290           2 :   ASSERT_UNCOUNTED_BW();
     291             : 
     292             :   /* SENDME cells up to limit */
     293          20 :   while (sendme_cells > 0) {
     294          18 :     ENTRY_TO_CONN(entryconn2)->marked_for_close = 0;
     295          18 :     PACK_CELL(edgeconn->stream_id, RELAY_COMMAND_SENDME, "Data1234");
     296          18 :     if (circ->base_.purpose == CIRCUIT_PURPOSE_PATH_BIAS_TESTING)
     297           9 :       pathbias_count_valid_cells(TO_CIRCUIT(circ), &cell);
     298             :     else
     299           9 :       connection_edge_process_relay_cell(&cell, TO_CIRCUIT(circ), NULL,
     300             :                                        circ->cpath);
     301          18 :     ASSERT_COUNTED_BW();
     302          18 :     sendme_cells--;
     303             :   }
     304           2 :   ENTRY_TO_CONN(entryconn2)->marked_for_close = 0;
     305           2 :   PACK_CELL(edgeconn->stream_id, RELAY_COMMAND_SENDME, "Data1234");
     306           2 :   if (circ->base_.purpose == CIRCUIT_PURPOSE_PATH_BIAS_TESTING)
     307           1 :     pathbias_count_valid_cells(TO_CIRCUIT(circ), &cell);
     308             :   else
     309           1 :     connection_edge_process_relay_cell(&cell, TO_CIRCUIT(circ), NULL,
     310             :                                      circ->cpath);
     311           2 :   ASSERT_UNCOUNTED_BW();
     312             : 
     313             :   /* Only one END cell */
     314           2 :   ENTRY_TO_CONN(entryconn2)->marked_for_close = 0;
     315           2 :   PACK_CELL(edgeconn->stream_id, RELAY_COMMAND_END, "Data1234");
     316           2 :   if (circ->base_.purpose == CIRCUIT_PURPOSE_PATH_BIAS_TESTING)
     317           1 :     pathbias_count_valid_cells(TO_CIRCUIT(circ), &cell);
     318             :   else
     319           1 :     connection_edge_process_relay_cell(&cell, TO_CIRCUIT(circ), NULL,
     320             :                                      circ->cpath);
     321           2 :   ASSERT_COUNTED_BW();
     322             : 
     323           2 :   ENTRY_TO_CONN(entryconn2)->marked_for_close = 0;
     324           2 :   PACK_CELL(edgeconn->stream_id, RELAY_COMMAND_END, "Data1234");
     325           2 :   if (circ->base_.purpose == CIRCUIT_PURPOSE_PATH_BIAS_TESTING)
     326           1 :     pathbias_count_valid_cells(TO_CIRCUIT(circ), &cell);
     327             :   else
     328           1 :     connection_edge_process_relay_cell(&cell, TO_CIRCUIT(circ), NULL,
     329             :                                      circ->cpath);
     330           2 :   ASSERT_UNCOUNTED_BW();
     331             : 
     332           2 :   edgeconn = ENTRY_TO_EDGE_CONN(entryconn3);
     333           2 :   edgeconn->base_.state = AP_CONN_STATE_OPEN;
     334           2 :   ENTRY_TO_CONN(entryconn3)->marked_for_close = 0;
     335             :   /* sendme cell on open entryconn with full window */
     336           2 :   PACK_CELL(edgeconn->stream_id, RELAY_COMMAND_SENDME, "Data1234");
     337           2 :   int ret =
     338           2 :     connection_edge_process_relay_cell(&cell, TO_CIRCUIT(circ), edgeconn,
     339             :                                      circ->cpath);
     340           2 :   tt_int_op(ret, OP_EQ, -END_CIRC_REASON_TORPROTOCOL);
     341           2 :   ASSERT_UNCOUNTED_BW();
     342             : 
     343             :   /* connected cell on a after EOF */
     344           2 :   ENTRY_TO_CONN(entryconn3)->marked_for_close = 0;
     345           2 :   edgeconn->base_.state = AP_CONN_STATE_CONNECT_WAIT;
     346           2 :   connection_edge_reached_eof(edgeconn);
     347           2 :   PACK_CELL(edgeconn->stream_id, RELAY_COMMAND_CONNECTED, "Data1234");
     348           2 :   if (circ->base_.purpose == CIRCUIT_PURPOSE_PATH_BIAS_TESTING)
     349           1 :     pathbias_count_valid_cells(TO_CIRCUIT(circ), &cell);
     350             :   else
     351           1 :     connection_edge_process_relay_cell(&cell, TO_CIRCUIT(circ),  NULL,
     352             :                                      circ->cpath);
     353           2 :   ASSERT_COUNTED_BW();
     354             : 
     355           2 :   ENTRY_TO_CONN(entryconn3)->marked_for_close = 0;
     356           2 :   PACK_CELL(edgeconn->stream_id, RELAY_COMMAND_CONNECTED, "Data1234");
     357           2 :   if (circ->base_.purpose == CIRCUIT_PURPOSE_PATH_BIAS_TESTING)
     358           1 :     pathbias_count_valid_cells(TO_CIRCUIT(circ), &cell);
     359             :   else
     360           1 :     connection_edge_process_relay_cell(&cell, TO_CIRCUIT(circ),  NULL,
     361             :                                      circ->cpath);
     362           2 :   ASSERT_UNCOUNTED_BW();
     363             : 
     364             :   /* DATA and SENDME after END cell */
     365           2 :   ENTRY_TO_CONN(entryconn3)->marked_for_close = 0;
     366           2 :   PACK_CELL(edgeconn->stream_id, RELAY_COMMAND_END, "Data1234");
     367           2 :   if (circ->base_.purpose == CIRCUIT_PURPOSE_PATH_BIAS_TESTING)
     368           1 :     pathbias_count_valid_cells(TO_CIRCUIT(circ), &cell);
     369             :   else
     370           1 :     connection_edge_process_relay_cell(&cell, TO_CIRCUIT(circ),  NULL,
     371             :                                      circ->cpath);
     372           2 :   ASSERT_COUNTED_BW();
     373             : 
     374           2 :   ENTRY_TO_CONN(entryconn3)->marked_for_close = 0;
     375           2 :   PACK_CELL(edgeconn->stream_id, RELAY_COMMAND_SENDME, "Data1234");
     376           2 :   ret =
     377           2 :     connection_edge_process_relay_cell(&cell, TO_CIRCUIT(circ), NULL,
     378             :                                      circ->cpath);
     379           2 :   tt_int_op(ret, OP_NE, -END_CIRC_REASON_TORPROTOCOL);
     380           2 :   ASSERT_UNCOUNTED_BW();
     381             : 
     382           2 :   ENTRY_TO_CONN(entryconn3)->marked_for_close = 0;
     383           2 :   PACK_CELL(edgeconn->stream_id, RELAY_COMMAND_DATA, "Data1234");
     384           2 :   if (circ->base_.purpose == CIRCUIT_PURPOSE_PATH_BIAS_TESTING)
     385           1 :     pathbias_count_valid_cells(TO_CIRCUIT(circ), &cell);
     386             :   else
     387           1 :     connection_edge_process_relay_cell(&cell, TO_CIRCUIT(circ), NULL,
     388             :                                      circ->cpath);
     389           2 :   ASSERT_UNCOUNTED_BW();
     390             : 
     391             :   /* Resolved: 1 counted, more not */
     392           2 :   edgeconn = ENTRY_TO_EDGE_CONN(entryconn4);
     393           2 :   entryconn4->socks_request->command = SOCKS_COMMAND_RESOLVE;
     394           2 :   edgeconn->base_.state = AP_CONN_STATE_RESOLVE_WAIT;
     395           2 :   edgeconn->on_circuit = TO_CIRCUIT(circ);
     396           2 :   ENTRY_TO_CONN(entryconn4)->marked_for_close = 0;
     397           2 :   connection_edge_reached_eof(edgeconn);
     398             : 
     399           2 :   ENTRY_TO_CONN(entryconn4)->marked_for_close = 0;
     400           2 :   PACK_CELL(edgeconn->stream_id, RELAY_COMMAND_RESOLVED,
     401             :             "\x04\x04\x12\x00\x00\x01\x00\x00\x02\x00");
     402           2 :   if (circ->base_.purpose == CIRCUIT_PURPOSE_PATH_BIAS_TESTING)
     403           1 :     pathbias_count_valid_cells(TO_CIRCUIT(circ), &cell);
     404             :   else
     405           1 :     connection_edge_process_relay_cell(&cell, TO_CIRCUIT(circ), NULL,
     406             :                                      circ->cpath);
     407           2 :   ASSERT_COUNTED_BW();
     408             : 
     409           2 :   ENTRY_TO_CONN(entryconn4)->marked_for_close = 0;
     410           2 :   PACK_CELL(edgeconn->stream_id, RELAY_COMMAND_RESOLVED,
     411             :             "\x04\x04\x12\x00\x00\x01\x00\x00\x02\x00");
     412           2 :   connection_edge_process_relay_cell(&cell, TO_CIRCUIT(circ), NULL,
     413             :                                      circ->cpath);
     414           2 :   ASSERT_UNCOUNTED_BW();
     415             : 
     416             :   /* Data not counted after resolved */
     417           2 :   ENTRY_TO_CONN(entryconn4)->marked_for_close = 0;
     418           2 :   PACK_CELL(edgeconn->stream_id, RELAY_COMMAND_DATA, "Data1234");
     419           2 :   if (circ->base_.purpose == CIRCUIT_PURPOSE_PATH_BIAS_TESTING)
     420           1 :     pathbias_count_valid_cells(TO_CIRCUIT(circ), &cell);
     421             :   else
     422           1 :     connection_edge_process_relay_cell(&cell, TO_CIRCUIT(circ), NULL,
     423             :                                      circ->cpath);
     424           2 :   ASSERT_UNCOUNTED_BW();
     425             : 
     426             :   /* End not counted after resolved */
     427           2 :   ENTRY_TO_CONN(entryconn4)->marked_for_close = 0;
     428           2 :   PACK_CELL(edgeconn->stream_id, RELAY_COMMAND_END, "Data1234");
     429           2 :   if (circ->base_.purpose == CIRCUIT_PURPOSE_PATH_BIAS_TESTING)
     430           1 :     pathbias_count_valid_cells(TO_CIRCUIT(circ), &cell);
     431             :   else
     432           1 :     connection_edge_process_relay_cell(&cell, TO_CIRCUIT(circ), NULL,
     433             :                                      circ->cpath);
     434           2 :   ASSERT_UNCOUNTED_BW();
     435             : 
     436           2 :   connection_free_minimal(ENTRY_TO_CONN(entryconn2));
     437           2 :   connection_free_minimal(ENTRY_TO_CONN(entryconn3));
     438           2 :   connection_free_minimal(ENTRY_TO_CONN(entryconn4));
     439           2 :   return 1;
     440           0 :  done:
     441           0 :   connection_free_minimal(ENTRY_TO_CONN(entryconn2));
     442           0 :   connection_free_minimal(ENTRY_TO_CONN(entryconn3));
     443           0 :   connection_free_minimal(ENTRY_TO_CONN(entryconn4));
     444           0 :   return 0;
     445             : }
     446             : 
     447             : static int
     448           8 : halfstream_insert(origin_circuit_t *circ, edge_connection_t *edgeconn,
     449             :                   streamid_t *streams, int num, int random)
     450             : {
     451           8 :   int inserted = 0;
     452             : 
     453             :   /* Insert num random elements */
     454       66688 :   while (inserted < num) {
     455       66680 :     streamid_t id;
     456             : 
     457       66680 :     if (random)
     458        1116 :       id = (streamid_t)crypto_rand_int(65535)+1;
     459             :     else
     460       65564 :       id = get_unique_stream_id_by_circ(circ);
     461             : 
     462       66680 :     edgeconn->stream_id = id;
     463             : 
     464             :     /* Ensure it isn't there */
     465       66680 :     if (connection_half_edge_find_stream_id(circ->half_streams, id)) {
     466           6 :       continue;
     467             :     }
     468             : 
     469       66674 :     connection_half_edge_add(edgeconn, circ);
     470       66674 :     if (streams)
     471        1110 :       streams[inserted] = id;
     472       66674 :     inserted++;
     473             :   }
     474             : 
     475           8 :   return inserted;
     476             : }
     477             : 
     478             : static void
     479           3 : subtest_halfstream_insertremove(int num)
     480             : {
     481           3 :   origin_circuit_t *circ =
     482           3 :       helper_create_origin_circuit(CIRCUIT_PURPOSE_C_GENERAL, 0);
     483           3 :   edge_connection_t *edgeconn;
     484           3 :   entry_connection_t *entryconn;
     485           3 :   streamid_t *streams = tor_malloc_zero(num*sizeof(streamid_t));
     486           3 :   int i = 0;
     487             : 
     488           3 :   circ->cpath->state = CPATH_STATE_AWAITING_KEYS;
     489           3 :   circ->cpath->deliver_window = CIRCWINDOW_START;
     490             : 
     491           3 :   entryconn = fake_entry_conn(circ, 23);
     492           3 :   edgeconn = ENTRY_TO_EDGE_CONN(entryconn);
     493             : 
     494             :   /* Explicitly test all operations on an absent stream list */
     495           3 :   tt_int_op(connection_half_edge_is_valid_data(circ->half_streams,
     496             :             23), OP_EQ, 0);
     497           3 :   tt_int_op(connection_half_edge_is_valid_connected(circ->half_streams,
     498             :             23), OP_EQ, 0);
     499           3 :   tt_int_op(connection_half_edge_is_valid_sendme(circ->half_streams,
     500             :             23), OP_EQ, 0);
     501           3 :   tt_int_op(connection_half_edge_is_valid_resolved(circ->half_streams,
     502             :             23), OP_EQ, 0);
     503           3 :   tt_int_op(connection_half_edge_is_valid_end(circ->half_streams,
     504             :             23), OP_EQ, 0);
     505             : 
     506             :   /* Insert a duplicate element; verify that other elements absent;
     507             :    * ensure removing it once works */
     508           3 :   edgeconn->stream_id = 23;
     509           3 :   connection_half_edge_add(edgeconn, circ);
     510           3 :   connection_half_edge_add(edgeconn, circ);
     511           3 :   connection_half_edge_add(edgeconn, circ);
     512             : 
     513             :   /* Verify that other elements absent */
     514           3 :   tt_int_op(connection_half_edge_is_valid_data(circ->half_streams,
     515             :             22), OP_EQ, 0);
     516           3 :   tt_int_op(connection_half_edge_is_valid_connected(circ->half_streams,
     517             :             22), OP_EQ, 0);
     518           3 :   tt_int_op(connection_half_edge_is_valid_sendme(circ->half_streams,
     519             :             22), OP_EQ, 0);
     520           3 :   tt_int_op(connection_half_edge_is_valid_resolved(circ->half_streams,
     521             :             22), OP_EQ, 0);
     522           3 :   tt_int_op(connection_half_edge_is_valid_end(circ->half_streams,
     523             :             22), OP_EQ, 0);
     524             : 
     525           3 :   tt_int_op(connection_half_edge_is_valid_data(circ->half_streams,
     526             :             24), OP_EQ, 0);
     527           3 :   tt_int_op(connection_half_edge_is_valid_connected(circ->half_streams,
     528             :             24), OP_EQ, 0);
     529           3 :   tt_int_op(connection_half_edge_is_valid_sendme(circ->half_streams,
     530             :             24), OP_EQ, 0);
     531           3 :   tt_int_op(connection_half_edge_is_valid_resolved(circ->half_streams,
     532             :             24), OP_EQ, 0);
     533           3 :   tt_int_op(connection_half_edge_is_valid_end(circ->half_streams,
     534             :             24), OP_EQ, 0);
     535             : 
     536             :   /* Verify we only remove it once */
     537           3 :   tt_int_op(connection_half_edge_is_valid_end(circ->half_streams,
     538             :             23), OP_EQ, 1);
     539           3 :   tt_int_op(connection_half_edge_is_valid_end(circ->half_streams,
     540             :             23), OP_EQ, 0);
     541             : 
     542           3 :   halfstream_insert(circ, edgeconn, streams, num, 1);
     543             : 
     544             :   /* Remove half of them */
     545         561 :   for (i = 0; i < num/2; i++) {
     546         555 :     tt_int_op(connection_half_edge_is_valid_end(circ->half_streams,
     547             :                                                 streams[i]),
     548             :               OP_EQ, 1);
     549             :   }
     550             : 
     551             :   /* Verify first half of list is gone */
     552         558 :   for (i = 0; i < num/2; i++) {
     553         555 :     tt_ptr_op(connection_half_edge_find_stream_id(circ->half_streams,
     554             :                                                   streams[i]),
     555             :               OP_EQ, NULL);
     556             :   }
     557             : 
     558             :   /* Verify second half of list is present */
     559         558 :   for (; i < num; i++) {
     560         555 :     tt_ptr_op(connection_half_edge_find_stream_id(circ->half_streams,
     561             :                                                   streams[i]),
     562             :               OP_NE, NULL);
     563             :   }
     564             : 
     565             :   /* Remove other half. Verify list is empty. */
     566         558 :   for (i = num/2; i < num; i++) {
     567         555 :     tt_int_op(connection_half_edge_is_valid_end(circ->half_streams,
     568             :                                                 streams[i]),
     569             :               OP_EQ, 1);
     570             :   }
     571           3 :   tt_int_op(smartlist_len(circ->half_streams), OP_EQ, 0);
     572             : 
     573             :   /* Explicitly test all operations on an empty stream list */
     574           3 :   tt_int_op(connection_half_edge_is_valid_data(circ->half_streams,
     575             :             23), OP_EQ, 0);
     576           3 :   tt_int_op(connection_half_edge_is_valid_connected(circ->half_streams,
     577             :             23), OP_EQ, 0);
     578           3 :   tt_int_op(connection_half_edge_is_valid_sendme(circ->half_streams,
     579             :             23), OP_EQ, 0);
     580           3 :   tt_int_op(connection_half_edge_is_valid_resolved(circ->half_streams,
     581             :             23), OP_EQ, 0);
     582           3 :   tt_int_op(connection_half_edge_is_valid_end(circ->half_streams,
     583             :             23), OP_EQ, 0);
     584             : 
     585             :   /* For valgrind, leave some around then free the circ */
     586           3 :   halfstream_insert(circ, edgeconn, NULL, 10, 0);
     587             : 
     588           3 :  done:
     589           3 :   tor_free(streams);
     590           3 :   circuit_free_(TO_CIRCUIT(circ));
     591           3 :   connection_free_minimal(ENTRY_TO_CONN(entryconn));
     592           3 : }
     593             : 
     594             : static void
     595           1 : test_halfstream_insertremove(void *arg)
     596             : {
     597           1 :   (void)arg;
     598             : 
     599             :   /* Suppress the WARN message we generate in this test */
     600           1 :   setup_full_capture_of_logs(LOG_WARN);
     601             : 
     602             :   /* Test insertion and removal with a few different sizes */
     603           1 :   subtest_halfstream_insertremove(10);
     604           1 :   subtest_halfstream_insertremove(100);
     605           1 :   subtest_halfstream_insertremove(1000);
     606           1 : }
     607             : 
     608             : static void
     609           1 : test_halfstream_wrap(void *arg)
     610             : {
     611           1 :   origin_circuit_t *circ =
     612           1 :       helper_create_origin_circuit(CIRCUIT_PURPOSE_C_GENERAL, 0);
     613           1 :   edge_connection_t *edgeconn;
     614           1 :   entry_connection_t *entryconn;
     615             : 
     616           1 :   circ->cpath->state = CPATH_STATE_AWAITING_KEYS;
     617           1 :   circ->cpath->deliver_window = CIRCWINDOW_START;
     618             : 
     619           1 :   entryconn = fake_entry_conn(circ, 23);
     620           1 :   edgeconn = ENTRY_TO_EDGE_CONN(entryconn);
     621             : 
     622           1 :   (void)arg;
     623             : 
     624             :   /* Suppress the WARN message we generate in this test */
     625           1 :   setup_full_capture_of_logs(LOG_WARN);
     626           1 :   MOCK(connection_mark_for_close_internal_, mock_mark_for_close);
     627             : 
     628             :   /* Verify that get_unique_stream_id_by_circ() can wrap uint16_t */
     629           1 :   circ->next_stream_id = 65530;
     630           1 :   halfstream_insert(circ, edgeconn, NULL, 7, 0);
     631           1 :   tt_int_op(circ->next_stream_id, OP_EQ, 2);
     632           1 :   tt_int_op(smartlist_len(circ->half_streams), OP_EQ, 7);
     633             : 
     634             :   /* Insert full-1 */
     635           1 :   halfstream_insert(circ, edgeconn, NULL,
     636           1 :                     65534-smartlist_len(circ->half_streams), 0);
     637           1 :   tt_int_op(smartlist_len(circ->half_streams), OP_EQ, 65534);
     638             : 
     639             :   /* Verify that we can get_unique_stream_id_by_circ() successfully */
     640           1 :   edgeconn->stream_id = get_unique_stream_id_by_circ(circ);
     641           1 :   tt_int_op(edgeconn->stream_id, OP_NE, 0); /* 0 is failure */
     642             : 
     643             :   /* Insert an opened stream on the circ with that id */
     644           1 :   ENTRY_TO_CONN(entryconn)->marked_for_close = 0;
     645           1 :   edgeconn->base_.state = AP_CONN_STATE_CONNECT_WAIT;
     646           1 :   circ->p_streams = edgeconn;
     647             : 
     648             :   /* Verify that get_unique_stream_id_by_circ() fails */
     649           1 :   tt_int_op(get_unique_stream_id_by_circ(circ), OP_EQ, 0); /* 0 is failure */
     650             : 
     651             :   /* eof the one opened stream. Verify it is now in half-closed */
     652           1 :   tt_int_op(smartlist_len(circ->half_streams), OP_EQ, 65534);
     653           1 :   connection_edge_reached_eof(edgeconn);
     654           1 :   tt_int_op(smartlist_len(circ->half_streams), OP_EQ, 65535);
     655             : 
     656             :   /* Verify get_unique_stream_id_by_circ() fails due to full half-closed */
     657           1 :   circ->p_streams = NULL;
     658           1 :   tt_int_op(get_unique_stream_id_by_circ(circ), OP_EQ, 0); /* 0 is failure */
     659             : 
     660           1 :  done:
     661           1 :   circuit_free_(TO_CIRCUIT(circ));
     662           1 :   connection_free_minimal(ENTRY_TO_CONN(entryconn));
     663           1 :   UNMOCK(connection_mark_for_close_internal_);
     664           1 : }
     665             : 
     666             : static void
     667           1 : test_circbw_relay(void *arg)
     668             : {
     669           1 :   cell_t cell;
     670           1 :   relay_header_t rh;
     671           1 :   tor_addr_t addr;
     672           1 :   edge_connection_t *edgeconn;
     673           1 :   entry_connection_t *entryconn1=NULL;
     674           1 :   origin_circuit_t *circ;
     675           1 :   int delivered = 0;
     676           1 :   int overhead = 0;
     677             : 
     678           1 :   (void)arg;
     679             : 
     680           1 :   MOCK(connection_mark_unattached_ap_, mock_connection_mark_unattached_ap_);
     681           1 :   MOCK(connection_start_reading, mock_start_reading);
     682           1 :   MOCK(connection_mark_for_close_internal_, mock_mark_for_close);
     683           1 :   MOCK(relay_send_command_from_edge_, mock_send_command);
     684           1 :   MOCK(circuit_mark_for_close_, mock_mark_circ_for_close);
     685             : 
     686           1 :   circ = helper_create_origin_circuit(CIRCUIT_PURPOSE_C_GENERAL, 0);
     687           1 :   circ->cpath->state = CPATH_STATE_AWAITING_KEYS;
     688           1 :   circ->cpath->deliver_window = CIRCWINDOW_START;
     689             : 
     690           1 :   entryconn1 = fake_entry_conn(circ, 1);
     691           1 :   edgeconn = ENTRY_TO_EDGE_CONN(entryconn1);
     692             : 
     693             :   /* Stream id 0: Not counted */
     694           1 :   PACK_CELL(0, RELAY_COMMAND_END, "Data1234");
     695           1 :   connection_edge_process_relay_cell(&cell, TO_CIRCUIT(circ), edgeconn,
     696             :                                      circ->cpath);
     697           1 :   ASSERT_UNCOUNTED_BW();
     698             : 
     699             :   /* Stream id 1: Counted */
     700           1 :   PACK_CELL(1, RELAY_COMMAND_END, "Data1234");
     701           1 :   connection_edge_process_relay_cell(&cell, TO_CIRCUIT(circ), edgeconn,
     702             :                                      circ->cpath);
     703           1 :   ASSERT_COUNTED_BW();
     704             : 
     705             :   /* Properly formatted connect cell: counted */
     706           1 :   PACK_CELL(1, RELAY_COMMAND_CONNECTED, "Data1234");
     707           1 :   tor_addr_parse(&addr, "30.40.50.60");
     708           1 :   rh.length = connected_cell_format_payload(cell.payload+RELAY_HEADER_SIZE,
     709             :                                             &addr, 1024);
     710           1 :   relay_header_pack((uint8_t*)&cell.payload, &rh);                    \
     711           1 :   connection_edge_process_relay_cell(&cell, TO_CIRCUIT(circ), edgeconn,
     712             :                                      circ->cpath);
     713           1 :   ASSERT_COUNTED_BW();
     714             : 
     715             :   /* Properly formatted resolved cell in correct state: counted */
     716           1 :   edgeconn->base_.state = AP_CONN_STATE_RESOLVE_WAIT;
     717           1 :   entryconn1->socks_request->command = SOCKS_COMMAND_RESOLVE;
     718           1 :   edgeconn->on_circuit = TO_CIRCUIT(circ);
     719           1 :   PACK_CELL(1, RELAY_COMMAND_RESOLVED,
     720             :             "\x04\x04\x12\x00\x00\x01\x00\x00\x02\x00");
     721           1 :   connection_edge_process_relay_cell(&cell, TO_CIRCUIT(circ), edgeconn,
     722             :                                      circ->cpath);
     723           1 :   ASSERT_COUNTED_BW();
     724             : 
     725           1 :   edgeconn->base_.state = AP_CONN_STATE_OPEN;
     726           1 :   entryconn1->socks_request->has_finished = 1;
     727             : 
     728             :   /* Connected cell after open: not counted */
     729           1 :   PACK_CELL(1, RELAY_COMMAND_CONNECTED, "Data1234");
     730           1 :   connection_edge_process_relay_cell(&cell, TO_CIRCUIT(circ), edgeconn,
     731             :                                      circ->cpath);
     732           1 :   ASSERT_UNCOUNTED_BW();
     733             : 
     734             :   /* Resolved cell after open: not counted */
     735           1 :   PACK_CELL(1, RELAY_COMMAND_RESOLVED, "Data1234");
     736           1 :   connection_edge_process_relay_cell(&cell, TO_CIRCUIT(circ), edgeconn,
     737             :                                      circ->cpath);
     738           1 :   ASSERT_UNCOUNTED_BW();
     739             : 
     740             :   /* Drop cell: not counted */
     741           1 :   PACK_CELL(1, RELAY_COMMAND_DROP, "Data1234");
     742           1 :   connection_edge_process_relay_cell(&cell, TO_CIRCUIT(circ), edgeconn,
     743             :                                      circ->cpath);
     744           1 :   ASSERT_UNCOUNTED_BW();
     745             : 
     746             :   /* Data cell on stream 0: not counted */
     747           1 :   PACK_CELL(0, RELAY_COMMAND_DATA, "Data1234");
     748           1 :   connection_edge_process_relay_cell(&cell, TO_CIRCUIT(circ), edgeconn,
     749             :                                      circ->cpath);
     750           1 :   ASSERT_UNCOUNTED_BW();
     751             : 
     752             :   /* Data cell on open connection: counted */
     753           1 :   ENTRY_TO_CONN(entryconn1)->marked_for_close = 0;
     754           1 :   PACK_CELL(1, RELAY_COMMAND_DATA, "Data1234");
     755           1 :   connection_edge_process_relay_cell(&cell, TO_CIRCUIT(circ), edgeconn,
     756             :                                      circ->cpath);
     757           1 :   ASSERT_COUNTED_BW();
     758             : 
     759             :   /* Empty Data cell on open connection: not counted */
     760           1 :   ENTRY_TO_CONN(entryconn1)->marked_for_close = 0;
     761           1 :   PACK_CELL(1, RELAY_COMMAND_DATA, "");
     762           1 :   connection_edge_process_relay_cell(&cell, TO_CIRCUIT(circ), edgeconn,
     763             :                                      circ->cpath);
     764           1 :   ASSERT_UNCOUNTED_BW();
     765             : 
     766             :   /* Sendme on valid stream: counted */
     767           1 :   edgeconn->package_window -= STREAMWINDOW_INCREMENT;
     768           1 :   PACK_CELL(1, RELAY_COMMAND_SENDME, "Data1234");
     769           1 :   connection_edge_process_relay_cell(&cell, TO_CIRCUIT(circ), edgeconn,
     770             :                                      circ->cpath);
     771           1 :   ASSERT_COUNTED_BW();
     772             : 
     773             :   /* Sendme on valid stream with full window: not counted */
     774           1 :   PACK_CELL(1, RELAY_COMMAND_SENDME, "Data1234");
     775           1 :   edgeconn->package_window = STREAMWINDOW_START;
     776           1 :   connection_edge_process_relay_cell(&cell, TO_CIRCUIT(circ), edgeconn,
     777             :                                      circ->cpath);
     778           1 :   ASSERT_UNCOUNTED_BW();
     779             : 
     780             :   /* Sendme on unknown stream: not counted */
     781           1 :   PACK_CELL(1, RELAY_COMMAND_SENDME, "Data1234");
     782           1 :   connection_edge_process_relay_cell(&cell, TO_CIRCUIT(circ), NULL,
     783             :                                      circ->cpath);
     784           1 :   ASSERT_UNCOUNTED_BW();
     785             : 
     786             :   /* Sendme on circuit with full window: not counted */
     787           1 :   PACK_CELL(0, RELAY_COMMAND_SENDME, "Data1234");
     788           1 :   connection_edge_process_relay_cell(&cell, TO_CIRCUIT(circ), edgeconn,
     789             :                                      circ->cpath);
     790           1 :   ASSERT_UNCOUNTED_BW();
     791             : 
     792             :   /* Sendme on circuit with non-full window: counted */
     793           1 :   PACK_CELL(0, RELAY_COMMAND_SENDME, "");
     794             :   /* Recording a cell, the window is updated after decryption so off by one in
     795             :    * order to record and then we process it with the proper window. */
     796           1 :   circ->cpath->package_window = 901;
     797           1 :   sendme_record_cell_digest_on_circ(TO_CIRCUIT(circ), circ->cpath);
     798           1 :   circ->cpath->package_window = 900;
     799           1 :   connection_edge_process_relay_cell(&cell, TO_CIRCUIT(circ), edgeconn,
     800             :                                      circ->cpath);
     801           1 :   ASSERT_COUNTED_BW();
     802             : 
     803             :   /* Invalid extended cell: not counted */
     804           1 :   PACK_CELL(1, RELAY_COMMAND_EXTENDED2, "Data1234");
     805           1 :   connection_edge_process_relay_cell(&cell, TO_CIRCUIT(circ), NULL,
     806             :                                      circ->cpath);
     807           1 :   ASSERT_UNCOUNTED_BW();
     808             : 
     809             :   /* Invalid extended cell: not counted */
     810           1 :   PACK_CELL(1, RELAY_COMMAND_EXTENDED, "Data1234");
     811           1 :   connection_edge_process_relay_cell(&cell, TO_CIRCUIT(circ), NULL,
     812             :                                      circ->cpath);
     813           1 :   ASSERT_UNCOUNTED_BW();
     814             : 
     815             :   /* Invalid HS cell: not counted */
     816           1 :   PACK_CELL(1, RELAY_COMMAND_ESTABLISH_INTRO, "Data1234");
     817           1 :   connection_edge_process_relay_cell(&cell, TO_CIRCUIT(circ), NULL,
     818             :                                      circ->cpath);
     819           1 :   ASSERT_UNCOUNTED_BW();
     820             : 
     821             :   /* "Valid" HS cell in expected state: counted */
     822           1 :   TO_CIRCUIT(circ)->purpose = CIRCUIT_PURPOSE_C_ESTABLISH_REND;
     823           1 :   PACK_CELL(1, RELAY_COMMAND_RENDEZVOUS_ESTABLISHED, "Data1234");
     824           1 :   connection_edge_process_relay_cell(&cell, TO_CIRCUIT(circ), NULL,
     825             :                                      circ->cpath);
     826           1 :   ASSERT_COUNTED_BW();
     827             : 
     828             :   /* End cell on non-closed connection: counted */
     829           1 :   PACK_CELL(1, RELAY_COMMAND_END, "Data1234");
     830           1 :   connection_edge_process_relay_cell(&cell, TO_CIRCUIT(circ), edgeconn,
     831             :                                      circ->cpath);
     832           1 :   ASSERT_COUNTED_BW();
     833             : 
     834             :   /* End cell on connection that already got one: not counted */
     835           1 :   PACK_CELL(1, RELAY_COMMAND_END, "Data1234");
     836           1 :   connection_edge_process_relay_cell(&cell, TO_CIRCUIT(circ), NULL,
     837             :                                      circ->cpath);
     838           1 :   ASSERT_UNCOUNTED_BW();
     839             : 
     840             :   /* Simulate closed stream on entryconn, then test: */
     841           1 :   if (!subtest_circbw_halfclosed(circ, 2))
     842           0 :     goto done;
     843             : 
     844           1 :   circ->base_.purpose = CIRCUIT_PURPOSE_PATH_BIAS_TESTING;
     845           1 :   if (!subtest_circbw_halfclosed(circ, 6))
     846           0 :     goto done;
     847             : 
     848             :   /* Path bias: truncated */
     849           1 :   tt_int_op(circ->base_.marked_for_close, OP_EQ, 0);
     850           1 :   PACK_CELL(0, RELAY_COMMAND_TRUNCATED, "Data1234");
     851           1 :   pathbias_count_valid_cells(TO_CIRCUIT(circ), &cell);
     852           1 :   tt_int_op(circ->base_.marked_for_close, OP_EQ, 1);
     853             : 
     854           1 :  done:
     855           1 :   UNMOCK(connection_start_reading);
     856           1 :   UNMOCK(connection_mark_unattached_ap_);
     857           1 :   UNMOCK(connection_mark_for_close_internal_);
     858           1 :   UNMOCK(relay_send_command_from_edge_);
     859           1 :   UNMOCK(circuit_mark_for_close_);
     860           1 :   circuit_free_(TO_CIRCUIT(circ));
     861           1 :   connection_free_minimal(ENTRY_TO_CONN(entryconn1));
     862           1 : }
     863             : 
     864             : /* Tests for connection_edge_process_resolved_cell().
     865             : 
     866             :    The point of ..process_resolved_cell() is to handle an incoming cell
     867             :    on an entry connection, and call connection_mark_unattached_ap() and/or
     868             :    connection_ap_handshake_socks_resolved().
     869             :  */
     870             : static void
     871           1 : test_relaycell_resolved(void *arg)
     872             : {
     873           1 :   entry_connection_t *entryconn;
     874           1 :   edge_connection_t *edgeconn;
     875           1 :   cell_t cell;
     876           1 :   relay_header_t rh;
     877           1 :   int r;
     878           1 :   or_options_t *options = get_options_mutable();
     879             : 
     880             : #define SET_CELL(s) do {                                                \
     881             :     memset(&cell, 0, sizeof(cell));                                     \
     882             :     memset(&rh, 0, sizeof(rh));                                         \
     883             :     memcpy(cell.payload + RELAY_HEADER_SIZE, (s), sizeof((s))-1);       \
     884             :     rh.length = sizeof((s))-1;                                          \
     885             :     rh.command = RELAY_COMMAND_RESOLVED;                                \
     886             :   } while (0)
     887             : #define MOCK_RESET() do {                       \
     888             :     srm_ncalls = mum_ncalls = 0;                \
     889             :   } while (0)
     890             : #define ASSERT_MARK_CALLED(reason) do {         \
     891             :     tt_int_op(mum_ncalls, OP_EQ, 1);               \
     892             :     tt_ptr_op(mum_conn, OP_EQ, entryconn);         \
     893             :     tt_int_op(mum_endreason, OP_EQ, (reason));     \
     894             :   } while (0)
     895             : #define ASSERT_RESOLVED_CALLED(atype, answer, ttl, expires) do {  \
     896             :     tt_int_op(srm_ncalls, OP_EQ, 1);                                 \
     897             :     tt_ptr_op(srm_conn, OP_EQ, entryconn);                           \
     898             :     tt_int_op(srm_atype, OP_EQ, (atype));                            \
     899             :     if ((answer) != NULL) {                                          \
     900             :       tt_int_op(srm_alen, OP_EQ, sizeof(answer)-1);                  \
     901             :       tt_int_op(srm_alen, OP_LT, 512);                                \
     902             :       tt_int_op(srm_answer_is_set, OP_EQ, 1);                        \
     903             :       tt_mem_op(srm_answer, OP_EQ, answer, sizeof(answer)-1);        \
     904             :     } else {                                                      \
     905             :       tt_int_op(srm_answer_is_set, OP_EQ, 0);                        \
     906             :     }                                                             \
     907             :     tt_int_op(srm_ttl, OP_EQ, ttl);                                  \
     908             :     tt_i64_op(srm_expires, OP_EQ, expires);                          \
     909             :   } while (0)
     910             : 
     911           1 :   (void)arg;
     912             : 
     913           1 :   MOCK(connection_mark_unattached_ap_, mark_unattached_mock);
     914           1 :   MOCK(connection_ap_handshake_socks_resolved, socks_resolved_mock);
     915             : 
     916           1 :   options->ClientDNSRejectInternalAddresses = 0;
     917             : 
     918           1 :   SET_CELL(/* IPv4: 127.0.1.2, ttl 256 */
     919             :            "\x04\x04\x7f\x00\x01\x02\x00\x00\x01\x00"
     920             :            /* IPv4: 18.0.0.1, ttl 512 */
     921             :            "\x04\x04\x12\x00\x00\x01\x00\x00\x02\x00"
     922             :            /* IPv6: 2003::3, ttl 1024 */
     923             :            "\x06\x10"
     924             :            "\x20\x02\x00\x00\x00\x00\x00\x00"
     925             :            "\x00\x00\x00\x00\x00\x00\x00\x03"
     926             :            "\x00\x00\x04\x00");
     927             : 
     928           1 :   entryconn = entry_connection_new(CONN_TYPE_AP, AF_INET);
     929           1 :   edgeconn = ENTRY_TO_EDGE_CONN(entryconn);
     930             : 
     931             :   /* Try with connection in non-RESOLVE_WAIT state: cell gets ignored */
     932           1 :   MOCK_RESET();
     933           1 :   r = connection_edge_process_resolved_cell(edgeconn, &cell, &rh);
     934           1 :   tt_int_op(r, OP_EQ, 0);
     935           1 :   tt_int_op(srm_ncalls, OP_EQ, 0);
     936           1 :   tt_int_op(mum_ncalls, OP_EQ, 0);
     937             : 
     938             :   /* Now put it in the right state. */
     939           1 :   ENTRY_TO_CONN(entryconn)->state = AP_CONN_STATE_RESOLVE_WAIT;
     940           1 :   entryconn->socks_request->command = SOCKS_COMMAND_RESOLVE;
     941           1 :   entryconn->entry_cfg.ipv4_traffic = 1;
     942           1 :   entryconn->entry_cfg.ipv6_traffic = 1;
     943           1 :   entryconn->entry_cfg.prefer_ipv6 = 0;
     944             : 
     945             :   /* We prefer ipv4, so we should get the first ipv4 answer */
     946           1 :   MOCK_RESET();
     947           1 :   r = connection_edge_process_resolved_cell(edgeconn, &cell, &rh);
     948           1 :   tt_int_op(r, OP_EQ, 0);
     949           1 :   ASSERT_MARK_CALLED(END_STREAM_REASON_DONE|
     950             :                      END_STREAM_REASON_FLAG_ALREADY_SOCKS_REPLIED);
     951           1 :   ASSERT_RESOLVED_CALLED(RESOLVED_TYPE_IPV4, "\x7f\x00\x01\x02", 256, -1);
     952             : 
     953             :   /* But we may be discarding private answers. */
     954           1 :   MOCK_RESET();
     955           1 :   options->ClientDNSRejectInternalAddresses = 1;
     956           1 :   r = connection_edge_process_resolved_cell(edgeconn, &cell, &rh);
     957           1 :   tt_int_op(r, OP_EQ, 0);
     958           1 :   ASSERT_MARK_CALLED(END_STREAM_REASON_DONE|
     959             :                      END_STREAM_REASON_FLAG_ALREADY_SOCKS_REPLIED);
     960           1 :   ASSERT_RESOLVED_CALLED(RESOLVED_TYPE_IPV4, "\x12\x00\x00\x01", 512, -1);
     961             : 
     962             :   /* now prefer ipv6, and get the first ipv6 answer */
     963           1 :   entryconn->entry_cfg.prefer_ipv6 = 1;
     964           1 :   MOCK_RESET();
     965           1 :   r = connection_edge_process_resolved_cell(edgeconn, &cell, &rh);
     966           1 :   tt_int_op(r, OP_EQ, 0);
     967           1 :   ASSERT_MARK_CALLED(END_STREAM_REASON_DONE|
     968             :                      END_STREAM_REASON_FLAG_ALREADY_SOCKS_REPLIED);
     969           1 :   ASSERT_RESOLVED_CALLED(RESOLVED_TYPE_IPV6,
     970             :                          "\x20\x02\x00\x00\x00\x00\x00\x00"
     971             :                          "\x00\x00\x00\x00\x00\x00\x00\x03",
     972             :                          1024, -1);
     973             : 
     974             :   /* With a cell that only has IPv4, we report IPv4 even if we prefer IPv6 */
     975           1 :   MOCK_RESET();
     976           1 :   SET_CELL("\x04\x04\x12\x00\x00\x01\x00\x00\x02\x00");
     977           1 :   r = connection_edge_process_resolved_cell(edgeconn, &cell, &rh);
     978           1 :   tt_int_op(r, OP_EQ, 0);
     979           1 :   ASSERT_MARK_CALLED(END_STREAM_REASON_DONE|
     980             :                      END_STREAM_REASON_FLAG_ALREADY_SOCKS_REPLIED);
     981           1 :   ASSERT_RESOLVED_CALLED(RESOLVED_TYPE_IPV4, "\x12\x00\x00\x01", 512, -1);
     982             : 
     983             :   /* But if we don't allow IPv4, we report nothing if the cell contains only
     984             :    * ipv4 */
     985           1 :   MOCK_RESET();
     986           1 :   entryconn->entry_cfg.ipv4_traffic = 0;
     987           1 :   r = connection_edge_process_resolved_cell(edgeconn, &cell, &rh);
     988           1 :   tt_int_op(r, OP_EQ, 0);
     989           1 :   ASSERT_MARK_CALLED(END_STREAM_REASON_DONE|
     990             :                      END_STREAM_REASON_FLAG_ALREADY_SOCKS_REPLIED);
     991           1 :   ASSERT_RESOLVED_CALLED(RESOLVED_TYPE_ERROR, NULL, -1, -1);
     992             : 
     993             :   /* If we wanted hostnames, we report nothing, since we only had IPs. */
     994           1 :   MOCK_RESET();
     995           1 :   entryconn->entry_cfg.ipv4_traffic = 1;
     996           1 :   entryconn->socks_request->command = SOCKS_COMMAND_RESOLVE_PTR;
     997           1 :   r = connection_edge_process_resolved_cell(edgeconn, &cell, &rh);
     998           1 :   tt_int_op(r, OP_EQ, 0);
     999           1 :   ASSERT_MARK_CALLED(END_STREAM_REASON_DONE|
    1000             :                      END_STREAM_REASON_FLAG_ALREADY_SOCKS_REPLIED);
    1001           1 :   ASSERT_RESOLVED_CALLED(RESOLVED_TYPE_ERROR, NULL, -1, -1);
    1002             : 
    1003             :   /* A hostname cell is fine though. */
    1004           1 :   MOCK_RESET();
    1005           1 :   SET_CELL("\x00\x0fwww.example.com\x00\x01\x00\x00");
    1006           1 :   r = connection_edge_process_resolved_cell(edgeconn, &cell, &rh);
    1007           1 :   tt_int_op(r, OP_EQ, 0);
    1008           1 :   ASSERT_MARK_CALLED(END_STREAM_REASON_DONE|
    1009             :                      END_STREAM_REASON_FLAG_ALREADY_SOCKS_REPLIED);
    1010           1 :   ASSERT_RESOLVED_CALLED(RESOLVED_TYPE_HOSTNAME, "www.example.com", 65536, -1);
    1011             : 
    1012             :   /* error on malformed cell */
    1013           1 :   MOCK_RESET();
    1014           1 :   entryconn->socks_request->command = SOCKS_COMMAND_RESOLVE;
    1015           1 :   SET_CELL("\x04\x04\x01\x02\x03\x04"); /* no ttl */
    1016           1 :   r = connection_edge_process_resolved_cell(edgeconn, &cell, &rh);
    1017           1 :   tt_int_op(r, OP_EQ, 0);
    1018           1 :   ASSERT_MARK_CALLED(END_STREAM_REASON_TORPROTOCOL);
    1019           1 :   tt_int_op(srm_ncalls, OP_EQ, 0);
    1020             : 
    1021             :   /* error on all addresses private */
    1022           1 :   MOCK_RESET();
    1023           1 :   SET_CELL(/* IPv4: 127.0.1.2, ttl 256 */
    1024             :            "\x04\x04\x7f\x00\x01\x02\x00\x00\x01\x00"
    1025             :            /* IPv4: 192.168.1.1, ttl 256 */
    1026             :            "\x04\x04\xc0\xa8\x01\x01\x00\x00\x01\x00");
    1027           1 :   r = connection_edge_process_resolved_cell(edgeconn, &cell, &rh);
    1028           1 :   tt_int_op(r, OP_EQ, 0);
    1029           1 :   ASSERT_MARK_CALLED(END_STREAM_REASON_TORPROTOCOL);
    1030           1 :   ASSERT_RESOLVED_CALLED(RESOLVED_TYPE_ERROR_TRANSIENT, NULL, 0, TIME_MAX);
    1031             : 
    1032             :   /* Legit error code */
    1033           1 :   MOCK_RESET();
    1034           1 :   SET_CELL("\xf0\x15" "quiet and meaningless" "\x00\x00\x0f\xff");
    1035           1 :   r = connection_edge_process_resolved_cell(edgeconn, &cell, &rh);
    1036           1 :   tt_int_op(r, OP_EQ, 0);
    1037           1 :   ASSERT_MARK_CALLED(END_STREAM_REASON_DONE|
    1038             :                      END_STREAM_REASON_FLAG_ALREADY_SOCKS_REPLIED);
    1039           1 :   ASSERT_RESOLVED_CALLED(RESOLVED_TYPE_ERROR_TRANSIENT, NULL, -1, -1);
    1040             : 
    1041           1 :  done:
    1042           1 :   UNMOCK(connection_mark_unattached_ap_);
    1043           1 :   UNMOCK(connection_ap_handshake_socks_resolved);
    1044           1 : }
    1045             : 
    1046             : struct testcase_t relaycell_tests[] = {
    1047             :   { "resolved", test_relaycell_resolved, TT_FORK, NULL, NULL },
    1048             :   { "circbw", test_circbw_relay, TT_FORK, NULL, NULL },
    1049             :   { "halfstream", test_halfstream_insertremove, TT_FORK, NULL, NULL },
    1050             :   { "streamwrap", test_halfstream_wrap, TT_FORK, NULL, NULL },
    1051             :   END_OF_TESTCASES
    1052             : };

Generated by: LCOV version 1.14