diff --git a/src/or/proto_cell.c b/src/or/proto_cell.c index 4485ab4e9e..75eb2a7e7f 100644 --- a/src/or/proto_cell.c +++ b/src/or/proto_cell.c @@ -66,6 +66,7 @@ fetch_var_cell_from_buf(buf_t *buf, var_cell_t **out, int linkproto) length = ntohs(get_uint16(hdr + circ_id_len + 1)); if (buf_datalen(buf) < (size_t)(header_len+length)) return 1; + result = var_cell_new(length); result->command = command; if (wide_circ_ids) diff --git a/src/test/include.am b/src/test/include.am index 8e8c9ca0da..95efe4e795 100644 --- a/src/test/include.am +++ b/src/test/include.am @@ -137,6 +137,7 @@ src_test_test_SOURCES = \ src/test/test_options.c \ src/test/test_policy.c \ src/test/test_procmon.c \ + src/test/test_proto_misc.c \ src/test/test_protover.c \ src/test/test_pt.c \ src/test/test_pubsub.c \ diff --git a/src/test/test.c b/src/test/test.c index 70436002ee..27c776b304 100644 --- a/src/test/test.c +++ b/src/test/test.c @@ -1215,6 +1215,7 @@ struct testgroup_t testgroups[] = { { "options/", options_tests }, { "policy/" , policy_tests }, { "procmon/", procmon_tests }, + { "proto/misc/", proto_misc_tests }, { "protover/", protover_tests }, { "pt/", pt_tests }, { "relay/" , relay_tests }, diff --git a/src/test/test.h b/src/test/test.h index 109607cb36..ba7b767c37 100644 --- a/src/test/test.h +++ b/src/test/test.h @@ -226,6 +226,7 @@ extern struct testcase_t oos_tests[]; extern struct testcase_t options_tests[]; extern struct testcase_t policy_tests[]; extern struct testcase_t procmon_tests[]; +extern struct testcase_t proto_misc_tests[]; extern struct testcase_t protover_tests[]; extern struct testcase_t pubsub_tests[]; extern struct testcase_t pt_tests[]; diff --git a/src/test/test_proto_misc.c b/src/test/test_proto_misc.c new file mode 100644 index 0000000000..b64a965c1d --- /dev/null +++ b/src/test/test_proto_misc.c @@ -0,0 +1,143 @@ +/* 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 "proto_cell.h" +#include "proto_control0.h" +#include "proto_http.h" +#include "proto_socks.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); +} + +struct testcase_t proto_misc_tests[] = { + { "var_cell", test_proto_var_cell, 0, NULL, NULL }, + { "control0", test_proto_control0, 0, NULL, NULL }, + + END_OF_TESTCASES +}; +