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