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 : };
|