aboutsummaryrefslogtreecommitdiff
path: root/src/test/test_proto_misc.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/test/test_proto_misc.c')
-rw-r--r--src/test/test_proto_misc.c263
1 files changed, 263 insertions, 0 deletions
diff --git a/src/test/test_proto_misc.c b/src/test/test_proto_misc.c
new file mode 100644
index 0000000000..263ca47447
--- /dev/null
+++ b/src/test/test_proto_misc.c
@@ -0,0 +1,263 @@
+/* Copyright (c) 2017, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * \file test_proto_misc.c
+ * \brief Test our smaller buffer-based protocol functions
+ */
+
+#include "or.h"
+#include "test.h"
+#include "buffers.h"
+#include "connection_or.h"
+#include "ext_orport.h"
+#include "proto_cell.h"
+#include "proto_control0.h"
+#include "proto_ext_or.h"
+
+static void
+test_proto_var_cell(void *arg)
+{
+ (void)arg;
+ char *mem_op_hex_tmp = NULL;
+ char tmp[1024];
+ buf_t *buf = NULL;
+ var_cell_t *cell = NULL;
+
+ buf = buf_new();
+ memset(tmp, 0xf0, sizeof(tmp));
+
+ /* Short little commands will make us say "no cell yet." */
+ tt_int_op(0, OP_EQ, fetch_var_cell_from_buf(buf, &cell, 4));
+ tt_ptr_op(cell, OP_EQ, NULL);
+ buf_add(buf, "\x01\x02\x02\0x2", 4);
+ tt_int_op(0, OP_EQ, fetch_var_cell_from_buf(buf, &cell, 4));
+ /* An incomplete fixed-length cell makes us say "no cell yet". */
+ buf_add(buf, "\x03", 1);
+ tt_int_op(0, OP_EQ, fetch_var_cell_from_buf(buf, &cell, 4));
+ /* A complete fixed length-cell makes us say "not a variable-length cell" */
+ buf_add(buf, tmp, 509);
+ tt_int_op(0, OP_EQ, fetch_var_cell_from_buf(buf, &cell, 4));
+ buf_clear(buf);
+
+ /* An incomplete versions cell is a variable-length cell that isn't ready
+ * yet. */
+ buf_add(buf,
+ "\x01\x02\x03\x04" /* circid */
+ "\x07" /* VERSIONS */
+ "\x00\x04" /* 4 bytes long */
+ "\x00" /* incomplete */, 8);
+ tt_int_op(1, OP_EQ, fetch_var_cell_from_buf(buf, &cell, 4));
+ tt_ptr_op(cell, OP_EQ, NULL);
+ /* Complete it, and it's a variable-length cell. Leave a byte on the end for
+ * fun. */
+ buf_add(buf, "\x09\x00\x25\ff", 4);
+ tt_int_op(1, OP_EQ, fetch_var_cell_from_buf(buf, &cell, 4));
+ tt_ptr_op(cell, OP_NE, NULL);
+ tt_int_op(cell->command, OP_EQ, CELL_VERSIONS);
+ tt_uint_op(cell->circ_id, OP_EQ, 0x01020304);
+ tt_int_op(cell->payload_len, OP_EQ, 4);
+ test_mem_op_hex(cell->payload, OP_EQ, "00090025");
+ var_cell_free(cell);
+ cell = NULL;
+ tt_int_op(buf_datalen(buf), OP_EQ, 1);
+ buf_clear(buf);
+
+ /* In link protocol 3 and earlier, circid fields were two bytes long. Let's
+ * ensure that gets handled correctly. */
+ buf_add(buf,
+ "\x23\x45\x81\x00\x06" /* command 81; 6 bytes long */
+ "coraje", 11);
+ tt_int_op(1, OP_EQ, fetch_var_cell_from_buf(buf, &cell, 3));
+ tt_ptr_op(cell, OP_NE, NULL);
+ tt_int_op(cell->command, OP_EQ, 129);
+ tt_uint_op(cell->circ_id, OP_EQ, 0x2345);
+ tt_int_op(cell->payload_len, OP_EQ, 6);
+ tt_mem_op(cell->payload, OP_EQ, "coraje", 6);
+ var_cell_free(cell);
+ cell = NULL;
+ tt_int_op(buf_datalen(buf), OP_EQ, 0);
+
+ /* In link protocol 2, only VERSIONS cells counted as variable-length */
+ buf_add(buf,
+ "\x23\x45\x81\x00\x06"
+ "coraje", 11); /* As above */
+ tt_int_op(0, OP_EQ, fetch_var_cell_from_buf(buf, &cell, 2));
+ buf_clear(buf);
+ buf_add(buf,
+ "\x23\x45\x07\x00\x06"
+ "futuro", 11);
+ tt_int_op(1, OP_EQ, fetch_var_cell_from_buf(buf, &cell, 2));
+ tt_ptr_op(cell, OP_NE, NULL);
+ tt_int_op(cell->command, OP_EQ, 7);
+ tt_uint_op(cell->circ_id, OP_EQ, 0x2345);
+ tt_int_op(cell->payload_len, OP_EQ, 6);
+ tt_mem_op(cell->payload, OP_EQ, "futuro", 6);
+ var_cell_free(cell);
+ cell = NULL;
+
+ done:
+ buf_free(buf);
+ var_cell_free(cell);
+ tor_free(mem_op_hex_tmp);
+}
+
+static void
+test_proto_control0(void *arg)
+{
+ (void)arg;
+ buf_t *buf = buf_new();
+
+ /* The only remaining function for the v0 control protocol is the function
+ that detects whether the user has stumbled across an old controller
+ that's using it. The format was:
+ u16 length;
+ u16 command;
+ u8 body[length];
+ */
+
+ /* Empty buffer -- nothing to do. */
+ tt_int_op(0, OP_EQ, peek_buf_has_control0_command(buf));
+ /* 3 chars in buf -- can't tell */
+ buf_add(buf, "AUT", 3);
+ tt_int_op(0, OP_EQ, peek_buf_has_control0_command(buf));
+ /* command in buf -- easy to tell */
+ buf_add(buf, "HENTICATE ", 10);
+ tt_int_op(0, OP_EQ, peek_buf_has_control0_command(buf));
+
+ /* Control0 command header in buf: make sure we detect it. */
+ buf_clear(buf);
+ buf_add(buf, "\x09\x05" "\x00\x05" "blah", 8);
+ tt_int_op(1, OP_EQ, peek_buf_has_control0_command(buf));
+
+ done:
+ buf_free(buf);
+}
+
+static void
+test_proto_ext_or_cmd(void *arg)
+{
+ ext_or_cmd_t *cmd = NULL;
+ buf_t *buf = buf_new();
+ char *tmp = NULL;
+ (void) arg;
+
+ /* Empty -- should give "not there. */
+ tt_int_op(0, OP_EQ, fetch_ext_or_command_from_buf(buf, &cmd));
+ tt_ptr_op(NULL, OP_EQ, cmd);
+
+ /* Three bytes: shouldn't work. */
+ buf_add(buf, "\x00\x20\x00", 3);
+ tt_int_op(0, OP_EQ, fetch_ext_or_command_from_buf(buf, &cmd));
+ tt_ptr_op(NULL, OP_EQ, cmd);
+ tt_int_op(3, OP_EQ, buf_datalen(buf));
+
+ /* 0020 0000: That's a nil command. It should work. */
+ buf_add(buf, "\x00", 1);
+ tt_int_op(1, OP_EQ, fetch_ext_or_command_from_buf(buf, &cmd));
+ tt_ptr_op(NULL, OP_NE, cmd);
+ tt_int_op(0x20, OP_EQ, cmd->cmd);
+ tt_int_op(0, OP_EQ, cmd->len);
+ tt_int_op(0, OP_EQ, buf_datalen(buf));
+ ext_or_cmd_free(cmd);
+ cmd = NULL;
+
+ /* Now try a length-6 command with one byte missing. */
+ buf_add(buf, "\x10\x21\x00\x06""abcde", 9);
+ tt_int_op(0, OP_EQ, fetch_ext_or_command_from_buf(buf, &cmd));
+ tt_ptr_op(NULL, OP_EQ, cmd);
+ buf_add(buf, "f", 1);
+ tt_int_op(1, OP_EQ, fetch_ext_or_command_from_buf(buf, &cmd));
+ tt_ptr_op(NULL, OP_NE, cmd);
+ tt_int_op(0x1021, OP_EQ, cmd->cmd);
+ tt_int_op(6, OP_EQ, cmd->len);
+ tt_mem_op("abcdef", OP_EQ, cmd->body, 6);
+ tt_int_op(0, OP_EQ, buf_datalen(buf));
+ ext_or_cmd_free(cmd);
+ cmd = NULL;
+
+ /* Now try a length-10 command with 4 extra bytes. */
+ buf_add(buf, "\xff\xff\x00\x0aloremipsum\x10\x00\xff\xff", 18);
+ tt_int_op(1, OP_EQ, fetch_ext_or_command_from_buf(buf, &cmd));
+ tt_ptr_op(NULL, OP_NE, cmd);
+ tt_int_op(0xffff, OP_EQ, cmd->cmd);
+ tt_int_op(10, OP_EQ, cmd->len);
+ tt_mem_op("loremipsum", OP_EQ, cmd->body, 10);
+ tt_int_op(4, OP_EQ, buf_datalen(buf));
+ ext_or_cmd_free(cmd);
+ cmd = NULL;
+
+ /* Finally, let's try a maximum-length command. We already have the header
+ * waiting. */
+ tt_int_op(0, OP_EQ, fetch_ext_or_command_from_buf(buf, &cmd));
+ tmp = tor_malloc_zero(65535);
+ buf_add(buf, tmp, 65535);
+ tt_int_op(1, OP_EQ, fetch_ext_or_command_from_buf(buf, &cmd));
+ tt_ptr_op(NULL, OP_NE, cmd);
+ tt_int_op(0x1000, OP_EQ, cmd->cmd);
+ tt_int_op(0xffff, OP_EQ, cmd->len);
+ tt_mem_op(tmp, OP_EQ, cmd->body, 65535);
+ tt_int_op(0, OP_EQ, buf_datalen(buf));
+ ext_or_cmd_free(cmd);
+ cmd = NULL;
+
+ done:
+ ext_or_cmd_free(cmd);
+ buf_free(buf);
+ tor_free(tmp);
+}
+
+static void
+test_proto_line(void *arg)
+{
+ (void)arg;
+ char tmp[60];
+ buf_t *buf = buf_new();
+#define S(str) str, sizeof(str)-1
+ const struct {
+ const char *input;
+ size_t input_len;
+ size_t line_len;
+ const char *output;
+ int returnval;
+ } cases[] = {
+ { S("Hello world"), 0, NULL, 0 },
+ { S("Hello world\n"), 12, "Hello world\n", 1 },
+ { S("Hello world\nMore"), 12, "Hello world\n", 1 },
+ { S("\n oh hello world\nMore"), 1, "\n", 1 },
+ { S("Hello worpd\n\nMore"), 12, "Hello worpd\n", 1 },
+ { S("------------------------------------------------------------\n"), 0,
+ NULL, -1 },
+ };
+ unsigned i;
+ for (i = 0; i < ARRAY_LENGTH(cases); ++i) {
+ buf_add(buf, cases[i].input, cases[i].input_len);
+ memset(tmp, 0xfe, sizeof(tmp));
+ size_t sz = sizeof(tmp);
+ int rv = buf_get_line(buf, tmp, &sz);
+ tt_int_op(rv, OP_EQ, cases[i].returnval);
+ if (rv == 1) {
+ tt_int_op(sz, OP_LT, sizeof(tmp));
+ tt_mem_op(cases[i].output, OP_EQ, tmp, sz+1);
+ tt_int_op(buf_datalen(buf), OP_EQ, cases[i].input_len - strlen(tmp));
+ tt_int_op(sz, OP_EQ, cases[i].line_len);
+ } else {
+ tt_int_op(buf_datalen(buf), OP_EQ, cases[i].input_len);
+ // tt_int_op(sz, OP_EQ, sizeof(tmp));
+ }
+ buf_clear(buf);
+ }
+
+ done:
+ buf_free(buf);
+}
+
+struct testcase_t proto_misc_tests[] = {
+ { "var_cell", test_proto_var_cell, 0, NULL, NULL },
+ { "control0", test_proto_control0, 0, NULL, NULL },
+ { "ext_or_cmd", test_proto_ext_or_cmd, TT_FORK, NULL, NULL },
+ { "line", test_proto_line, 0, NULL, NULL },
+
+ END_OF_TESTCASES
+};
+