Line data Source code
1 : /* Copyright (c) 2017-2021, The Tor Project, Inc. */
2 : /* See LICENSE for licensing information */
3 :
4 : /**
5 : * \file test_proto_misc.c
6 : * \brief Test our smaller buffer-based protocol functions
7 : */
8 :
9 : #include "core/or/or.h"
10 : #include "test/test.h"
11 : #include "lib/buf/buffers.h"
12 : #include "core/or/connection_or.h"
13 : #include "feature/relay/ext_orport.h"
14 : #include "core/proto/proto_cell.h"
15 : #include "core/proto/proto_control0.h"
16 : #include "core/proto/proto_ext_or.h"
17 :
18 : #include "core/or/var_cell_st.h"
19 :
20 : static void
21 1 : test_proto_var_cell(void *arg)
22 : {
23 1 : (void)arg;
24 1 : char *mem_op_hex_tmp = NULL;
25 1 : char tmp[1024];
26 1 : buf_t *buf = NULL;
27 1 : var_cell_t *cell = NULL;
28 :
29 1 : buf = buf_new();
30 1 : memset(tmp, 0xf0, sizeof(tmp));
31 :
32 : /* Short little commands will make us say "no cell yet." */
33 1 : tt_int_op(0, OP_EQ, fetch_var_cell_from_buf(buf, &cell, 4));
34 1 : tt_ptr_op(cell, OP_EQ, NULL);
35 1 : buf_add(buf, "\x01\x02\x02\0x2", 4);
36 1 : tt_int_op(0, OP_EQ, fetch_var_cell_from_buf(buf, &cell, 4));
37 : /* An incomplete fixed-length cell makes us say "no cell yet". */
38 1 : buf_add(buf, "\x03", 1);
39 1 : tt_int_op(0, OP_EQ, fetch_var_cell_from_buf(buf, &cell, 4));
40 : /* A complete fixed length-cell makes us say "not a variable-length cell" */
41 1 : buf_add(buf, tmp, 509);
42 1 : tt_int_op(0, OP_EQ, fetch_var_cell_from_buf(buf, &cell, 4));
43 1 : buf_clear(buf);
44 :
45 : /* An incomplete versions cell is a variable-length cell that isn't ready
46 : * yet. */
47 1 : buf_add(buf,
48 : "\x01\x02\x03\x04" /* circid */
49 : "\x07" /* VERSIONS */
50 : "\x00\x04" /* 4 bytes long */
51 : "\x00" /* incomplete */, 8);
52 1 : tt_int_op(1, OP_EQ, fetch_var_cell_from_buf(buf, &cell, 4));
53 1 : tt_ptr_op(cell, OP_EQ, NULL);
54 : /* Complete it, and it's a variable-length cell. Leave a byte on the end for
55 : * fun. */
56 1 : buf_add(buf, "\x09\x00\x25\ff", 4);
57 1 : tt_int_op(1, OP_EQ, fetch_var_cell_from_buf(buf, &cell, 4));
58 1 : tt_ptr_op(cell, OP_NE, NULL);
59 1 : tt_int_op(cell->command, OP_EQ, CELL_VERSIONS);
60 1 : tt_uint_op(cell->circ_id, OP_EQ, 0x01020304);
61 1 : tt_int_op(cell->payload_len, OP_EQ, 4);
62 1 : test_mem_op_hex(cell->payload, OP_EQ, "00090025");
63 1 : var_cell_free(cell);
64 1 : cell = NULL;
65 1 : tt_int_op(buf_datalen(buf), OP_EQ, 1);
66 1 : buf_clear(buf);
67 :
68 : /* In link protocol 3 and earlier, circid fields were two bytes long. Let's
69 : * ensure that gets handled correctly. */
70 1 : buf_add(buf,
71 : "\x23\x45\x81\x00\x06" /* command 81; 6 bytes long */
72 : "coraje", 11);
73 1 : tt_int_op(1, OP_EQ, fetch_var_cell_from_buf(buf, &cell, 3));
74 1 : tt_ptr_op(cell, OP_NE, NULL);
75 1 : tt_int_op(cell->command, OP_EQ, 129);
76 1 : tt_uint_op(cell->circ_id, OP_EQ, 0x2345);
77 1 : tt_int_op(cell->payload_len, OP_EQ, 6);
78 1 : tt_mem_op(cell->payload, OP_EQ, "coraje", 6);
79 1 : var_cell_free(cell);
80 1 : cell = NULL;
81 1 : tt_int_op(buf_datalen(buf), OP_EQ, 0);
82 :
83 : /* In link protocol 2, only VERSIONS cells counted as variable-length */
84 1 : buf_add(buf,
85 : "\x23\x45\x81\x00\x06"
86 : "coraje", 11); /* As above */
87 1 : tt_int_op(0, OP_EQ, fetch_var_cell_from_buf(buf, &cell, 2));
88 1 : buf_clear(buf);
89 1 : buf_add(buf,
90 : "\x23\x45\x07\x00\x06"
91 : "futuro", 11);
92 1 : tt_int_op(1, OP_EQ, fetch_var_cell_from_buf(buf, &cell, 2));
93 1 : tt_ptr_op(cell, OP_NE, NULL);
94 1 : tt_int_op(cell->command, OP_EQ, 7);
95 1 : tt_uint_op(cell->circ_id, OP_EQ, 0x2345);
96 1 : tt_int_op(cell->payload_len, OP_EQ, 6);
97 1 : tt_mem_op(cell->payload, OP_EQ, "futuro", 6);
98 1 : var_cell_free(cell);
99 1 : cell = NULL;
100 :
101 1 : done:
102 1 : buf_free(buf);
103 1 : var_cell_free(cell);
104 1 : tor_free(mem_op_hex_tmp);
105 1 : }
106 :
107 : static void
108 1 : test_proto_control0(void *arg)
109 : {
110 1 : (void)arg;
111 1 : buf_t *buf = buf_new();
112 :
113 : /* The only remaining function for the v0 control protocol is the function
114 : that detects whether the user has stumbled across an old controller
115 : that's using it. The format was:
116 : u16 length;
117 : u16 command;
118 : u8 body[length];
119 : */
120 :
121 : /* Empty buffer -- nothing to do. */
122 1 : tt_int_op(0, OP_EQ, peek_buf_has_control0_command(buf));
123 : /* 3 chars in buf -- can't tell */
124 1 : buf_add(buf, "AUT", 3);
125 1 : tt_int_op(0, OP_EQ, peek_buf_has_control0_command(buf));
126 : /* command in buf -- easy to tell */
127 1 : buf_add(buf, "HENTICATE ", 10);
128 1 : tt_int_op(0, OP_EQ, peek_buf_has_control0_command(buf));
129 :
130 : /* Control0 command header in buf: make sure we detect it. */
131 1 : buf_clear(buf);
132 1 : buf_add(buf, "\x09\x05" "\x00\x05" "blah", 8);
133 1 : tt_int_op(1, OP_EQ, peek_buf_has_control0_command(buf));
134 :
135 1 : done:
136 1 : buf_free(buf);
137 1 : }
138 :
139 : static void
140 1 : test_proto_ext_or_cmd(void *arg)
141 : {
142 1 : ext_or_cmd_t *cmd = NULL;
143 1 : buf_t *buf = buf_new();
144 1 : char *tmp = NULL;
145 1 : (void) arg;
146 :
147 : /* Empty -- should give "not there. */
148 1 : tt_int_op(0, OP_EQ, fetch_ext_or_command_from_buf(buf, &cmd));
149 1 : tt_ptr_op(NULL, OP_EQ, cmd);
150 :
151 : /* Three bytes: shouldn't work. */
152 1 : buf_add(buf, "\x00\x20\x00", 3);
153 1 : tt_int_op(0, OP_EQ, fetch_ext_or_command_from_buf(buf, &cmd));
154 1 : tt_ptr_op(NULL, OP_EQ, cmd);
155 1 : tt_int_op(3, OP_EQ, buf_datalen(buf));
156 :
157 : /* 0020 0000: That's a nil command. It should work. */
158 1 : buf_add(buf, "\x00", 1);
159 1 : tt_int_op(1, OP_EQ, fetch_ext_or_command_from_buf(buf, &cmd));
160 1 : tt_ptr_op(NULL, OP_NE, cmd);
161 1 : tt_int_op(0x20, OP_EQ, cmd->cmd);
162 1 : tt_int_op(0, OP_EQ, cmd->len);
163 1 : tt_int_op(0, OP_EQ, buf_datalen(buf));
164 1 : ext_or_cmd_free(cmd);
165 1 : cmd = NULL;
166 :
167 : /* Now try a length-6 command with one byte missing. */
168 1 : buf_add(buf, "\x10\x21\x00\x06""abcde", 9);
169 1 : tt_int_op(0, OP_EQ, fetch_ext_or_command_from_buf(buf, &cmd));
170 1 : tt_ptr_op(NULL, OP_EQ, cmd);
171 1 : buf_add(buf, "f", 1);
172 1 : tt_int_op(1, OP_EQ, fetch_ext_or_command_from_buf(buf, &cmd));
173 1 : tt_ptr_op(NULL, OP_NE, cmd);
174 1 : tt_int_op(0x1021, OP_EQ, cmd->cmd);
175 1 : tt_int_op(6, OP_EQ, cmd->len);
176 1 : tt_mem_op("abcdef", OP_EQ, cmd->body, 6);
177 1 : tt_int_op(0, OP_EQ, buf_datalen(buf));
178 1 : ext_or_cmd_free(cmd);
179 1 : cmd = NULL;
180 :
181 : /* Now try a length-10 command with 4 extra bytes. */
182 1 : buf_add(buf, "\xff\xff\x00\x0aloremipsum\x10\x00\xff\xff", 18);
183 1 : tt_int_op(1, OP_EQ, fetch_ext_or_command_from_buf(buf, &cmd));
184 1 : tt_ptr_op(NULL, OP_NE, cmd);
185 1 : tt_int_op(0xffff, OP_EQ, cmd->cmd);
186 1 : tt_int_op(10, OP_EQ, cmd->len);
187 1 : tt_mem_op("loremipsum", OP_EQ, cmd->body, 10);
188 1 : tt_int_op(4, OP_EQ, buf_datalen(buf));
189 1 : ext_or_cmd_free(cmd);
190 1 : cmd = NULL;
191 :
192 : /* Finally, let's try a maximum-length command. We already have the header
193 : * waiting. */
194 1 : tt_int_op(0, OP_EQ, fetch_ext_or_command_from_buf(buf, &cmd));
195 1 : tmp = tor_malloc_zero(65535);
196 1 : buf_add(buf, tmp, 65535);
197 1 : tt_int_op(1, OP_EQ, fetch_ext_or_command_from_buf(buf, &cmd));
198 1 : tt_ptr_op(NULL, OP_NE, cmd);
199 1 : tt_int_op(0x1000, OP_EQ, cmd->cmd);
200 1 : tt_int_op(0xffff, OP_EQ, cmd->len);
201 1 : tt_mem_op(tmp, OP_EQ, cmd->body, 65535);
202 1 : tt_int_op(0, OP_EQ, buf_datalen(buf));
203 1 : ext_or_cmd_free(cmd);
204 1 : cmd = NULL;
205 :
206 1 : done:
207 1 : ext_or_cmd_free(cmd);
208 1 : buf_free(buf);
209 1 : tor_free(tmp);
210 1 : }
211 :
212 : static void
213 1 : test_proto_line(void *arg)
214 : {
215 1 : (void)arg;
216 1 : char tmp[60];
217 1 : buf_t *buf = buf_new();
218 : #define S(str) str, sizeof(str)-1
219 1 : const struct {
220 : const char *input;
221 : size_t input_len;
222 : size_t line_len;
223 : const char *output;
224 : int returnval;
225 1 : } cases[] = {
226 : { S("Hello world"), 0, NULL, 0 },
227 : { S("Hello world\n"), 12, "Hello world\n", 1 },
228 : { S("Hello world\nMore"), 12, "Hello world\n", 1 },
229 : { S("\n oh hello world\nMore"), 1, "\n", 1 },
230 : { S("Hello worpd\n\nMore"), 12, "Hello worpd\n", 1 },
231 : { S("------------------------------------------------------------\n"), 0,
232 : NULL, -1 },
233 : };
234 1 : unsigned i;
235 7 : for (i = 0; i < ARRAY_LENGTH(cases); ++i) {
236 6 : buf_add(buf, cases[i].input, cases[i].input_len);
237 6 : memset(tmp, 0xfe, sizeof(tmp));
238 6 : size_t sz = sizeof(tmp);
239 6 : int rv = buf_get_line(buf, tmp, &sz);
240 6 : tt_int_op(rv, OP_EQ, cases[i].returnval);
241 6 : if (rv == 1) {
242 4 : tt_int_op(sz, OP_LT, sizeof(tmp));
243 4 : tt_mem_op(cases[i].output, OP_EQ, tmp, sz+1);
244 4 : tt_int_op(buf_datalen(buf), OP_EQ, cases[i].input_len - strlen(tmp));
245 4 : tt_int_op(sz, OP_EQ, cases[i].line_len);
246 : } else {
247 2 : tt_int_op(buf_datalen(buf), OP_EQ, cases[i].input_len);
248 : // tt_int_op(sz, OP_EQ, sizeof(tmp));
249 : }
250 6 : buf_clear(buf);
251 : }
252 :
253 1 : done:
254 1 : buf_free(buf);
255 1 : }
256 :
257 : struct testcase_t proto_misc_tests[] = {
258 : { "var_cell", test_proto_var_cell, 0, NULL, NULL },
259 : { "control0", test_proto_control0, 0, NULL, NULL },
260 : { "ext_or_cmd", test_proto_ext_or_cmd, TT_FORK, NULL, NULL },
261 : { "line", test_proto_line, 0, NULL, NULL },
262 :
263 : END_OF_TESTCASES
264 : };
265 :
|