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
test_proto_var_cell(void * arg)21 test_proto_var_cell(void *arg)
22 {
23   (void)arg;
24   char *mem_op_hex_tmp = NULL;
25   char tmp[1024];
26   buf_t *buf = NULL;
27   var_cell_t *cell = NULL;
28 
29   buf = buf_new();
30   memset(tmp, 0xf0, sizeof(tmp));
31 
32   /* Short little commands will make us say "no cell yet." */
33   tt_int_op(0, OP_EQ, fetch_var_cell_from_buf(buf, &cell, 4));
34   tt_ptr_op(cell, OP_EQ, NULL);
35   buf_add(buf, "\x01\x02\x02\0x2", 4);
36   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   buf_add(buf, "\x03", 1);
39   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   buf_add(buf, tmp, 509);
42   tt_int_op(0, OP_EQ, fetch_var_cell_from_buf(buf, &cell, 4));
43   buf_clear(buf);
44 
45   /* An incomplete versions cell is a variable-length cell that isn't ready
46    * yet. */
47   buf_add(buf,
48           "\x01\x02\x03\x04" /* circid */
49           "\x07" /* VERSIONS */
50           "\x00\x04" /* 4 bytes long */
51           "\x00" /* incomplete */, 8);
52   tt_int_op(1, OP_EQ, fetch_var_cell_from_buf(buf, &cell, 4));
53   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   buf_add(buf, "\x09\x00\x25\ff", 4);
57   tt_int_op(1, OP_EQ, fetch_var_cell_from_buf(buf, &cell, 4));
58   tt_ptr_op(cell, OP_NE, NULL);
59   tt_int_op(cell->command, OP_EQ, CELL_VERSIONS);
60   tt_uint_op(cell->circ_id, OP_EQ, 0x01020304);
61   tt_int_op(cell->payload_len, OP_EQ, 4);
62   test_mem_op_hex(cell->payload, OP_EQ, "00090025");
63   var_cell_free(cell);
64   cell = NULL;
65   tt_int_op(buf_datalen(buf), OP_EQ, 1);
66   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   buf_add(buf,
71           "\x23\x45\x81\x00\x06" /* command 81; 6 bytes long */
72           "coraje", 11);
73   tt_int_op(1, OP_EQ, fetch_var_cell_from_buf(buf, &cell, 3));
74   tt_ptr_op(cell, OP_NE, NULL);
75   tt_int_op(cell->command, OP_EQ, 129);
76   tt_uint_op(cell->circ_id, OP_EQ, 0x2345);
77   tt_int_op(cell->payload_len, OP_EQ, 6);
78   tt_mem_op(cell->payload, OP_EQ, "coraje", 6);
79   var_cell_free(cell);
80   cell = NULL;
81   tt_int_op(buf_datalen(buf), OP_EQ, 0);
82 
83   /* In link protocol 2, only VERSIONS cells counted as variable-length */
84   buf_add(buf,
85           "\x23\x45\x81\x00\x06"
86           "coraje", 11); /* As above */
87   tt_int_op(0, OP_EQ, fetch_var_cell_from_buf(buf, &cell, 2));
88   buf_clear(buf);
89   buf_add(buf,
90           "\x23\x45\x07\x00\x06"
91           "futuro", 11);
92   tt_int_op(1, OP_EQ, fetch_var_cell_from_buf(buf, &cell, 2));
93   tt_ptr_op(cell, OP_NE, NULL);
94   tt_int_op(cell->command, OP_EQ, 7);
95   tt_uint_op(cell->circ_id, OP_EQ, 0x2345);
96   tt_int_op(cell->payload_len, OP_EQ, 6);
97   tt_mem_op(cell->payload, OP_EQ, "futuro", 6);
98   var_cell_free(cell);
99   cell = NULL;
100 
101  done:
102   buf_free(buf);
103   var_cell_free(cell);
104   tor_free(mem_op_hex_tmp);
105 }
106 
107 static void
test_proto_control0(void * arg)108 test_proto_control0(void *arg)
109 {
110   (void)arg;
111   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   tt_int_op(0, OP_EQ, peek_buf_has_control0_command(buf));
123   /* 3 chars in buf -- can't tell */
124   buf_add(buf, "AUT", 3);
125   tt_int_op(0, OP_EQ, peek_buf_has_control0_command(buf));
126   /* command in buf -- easy to tell */
127   buf_add(buf, "HENTICATE ", 10);
128   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   buf_clear(buf);
132   buf_add(buf, "\x09\x05" "\x00\x05" "blah", 8);
133   tt_int_op(1, OP_EQ, peek_buf_has_control0_command(buf));
134 
135  done:
136   buf_free(buf);
137 }
138 
139 static void
test_proto_ext_or_cmd(void * arg)140 test_proto_ext_or_cmd(void *arg)
141 {
142   ext_or_cmd_t *cmd = NULL;
143   buf_t *buf = buf_new();
144   char *tmp = NULL;
145   (void) arg;
146 
147   /* Empty -- should give "not there. */
148   tt_int_op(0, OP_EQ, fetch_ext_or_command_from_buf(buf, &cmd));
149   tt_ptr_op(NULL, OP_EQ, cmd);
150 
151   /* Three bytes: shouldn't work. */
152   buf_add(buf, "\x00\x20\x00", 3);
153   tt_int_op(0, OP_EQ, fetch_ext_or_command_from_buf(buf, &cmd));
154   tt_ptr_op(NULL, OP_EQ, cmd);
155   tt_int_op(3, OP_EQ, buf_datalen(buf));
156 
157   /* 0020 0000: That's a nil command. It should work. */
158   buf_add(buf, "\x00", 1);
159   tt_int_op(1, OP_EQ, fetch_ext_or_command_from_buf(buf, &cmd));
160   tt_ptr_op(NULL, OP_NE, cmd);
161   tt_int_op(0x20, OP_EQ, cmd->cmd);
162   tt_int_op(0, OP_EQ, cmd->len);
163   tt_int_op(0, OP_EQ, buf_datalen(buf));
164   ext_or_cmd_free(cmd);
165   cmd = NULL;
166 
167   /* Now try a length-6 command with one byte missing. */
168   buf_add(buf, "\x10\x21\x00\x06""abcde", 9);
169   tt_int_op(0, OP_EQ, fetch_ext_or_command_from_buf(buf, &cmd));
170   tt_ptr_op(NULL, OP_EQ, cmd);
171   buf_add(buf, "f", 1);
172   tt_int_op(1, OP_EQ, fetch_ext_or_command_from_buf(buf, &cmd));
173   tt_ptr_op(NULL, OP_NE, cmd);
174   tt_int_op(0x1021, OP_EQ, cmd->cmd);
175   tt_int_op(6, OP_EQ, cmd->len);
176   tt_mem_op("abcdef", OP_EQ, cmd->body, 6);
177   tt_int_op(0, OP_EQ, buf_datalen(buf));
178   ext_or_cmd_free(cmd);
179   cmd = NULL;
180 
181   /* Now try a length-10 command with 4 extra bytes. */
182   buf_add(buf, "\xff\xff\x00\x0aloremipsum\x10\x00\xff\xff", 18);
183   tt_int_op(1, OP_EQ, fetch_ext_or_command_from_buf(buf, &cmd));
184   tt_ptr_op(NULL, OP_NE, cmd);
185   tt_int_op(0xffff, OP_EQ, cmd->cmd);
186   tt_int_op(10, OP_EQ, cmd->len);
187   tt_mem_op("loremipsum", OP_EQ, cmd->body, 10);
188   tt_int_op(4, OP_EQ, buf_datalen(buf));
189   ext_or_cmd_free(cmd);
190   cmd = NULL;
191 
192   /* Finally, let's try a maximum-length command. We already have the header
193    * waiting. */
194   tt_int_op(0, OP_EQ, fetch_ext_or_command_from_buf(buf, &cmd));
195   tmp = tor_malloc_zero(65535);
196   buf_add(buf, tmp, 65535);
197   tt_int_op(1, OP_EQ, fetch_ext_or_command_from_buf(buf, &cmd));
198   tt_ptr_op(NULL, OP_NE, cmd);
199   tt_int_op(0x1000, OP_EQ, cmd->cmd);
200   tt_int_op(0xffff, OP_EQ, cmd->len);
201   tt_mem_op(tmp, OP_EQ, cmd->body, 65535);
202   tt_int_op(0, OP_EQ, buf_datalen(buf));
203   ext_or_cmd_free(cmd);
204   cmd = NULL;
205 
206  done:
207   ext_or_cmd_free(cmd);
208   buf_free(buf);
209   tor_free(tmp);
210 }
211 
212 static void
test_proto_line(void * arg)213 test_proto_line(void *arg)
214 {
215   (void)arg;
216   char tmp[60];
217   buf_t *buf = buf_new();
218 #define S(str) str, sizeof(str)-1
219   const struct {
220     const char *input;
221     size_t input_len;
222     size_t line_len;
223     const char *output;
224     int returnval;
225   } 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   unsigned i;
235   for (i = 0; i < ARRAY_LENGTH(cases); ++i) {
236     buf_add(buf, cases[i].input, cases[i].input_len);
237     memset(tmp, 0xfe, sizeof(tmp));
238     size_t sz = sizeof(tmp);
239     int rv = buf_get_line(buf, tmp, &sz);
240     tt_int_op(rv, OP_EQ, cases[i].returnval);
241     if (rv == 1) {
242       tt_int_op(sz, OP_LT, sizeof(tmp));
243       tt_mem_op(cases[i].output, OP_EQ, tmp, sz+1);
244       tt_int_op(buf_datalen(buf), OP_EQ, cases[i].input_len - strlen(tmp));
245       tt_int_op(sz, OP_EQ, cases[i].line_len);
246     } else {
247       tt_int_op(buf_datalen(buf), OP_EQ, cases[i].input_len);
248       // tt_int_op(sz, OP_EQ, sizeof(tmp));
249     }
250     buf_clear(buf);
251   }
252 
253  done:
254   buf_free(buf);
255 }
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 
266