diff options
author | Mike Perry <mikeperry-git@torproject.org> | 2016-09-06 11:35:53 -0700 |
---|---|---|
committer | Nick Mathewson <nickm@torproject.org> | 2017-05-08 13:49:21 -0400 |
commit | b0e92634d85a3bf7612a6ce0339b96e4aad1e0bb (patch) | |
tree | 43a2d03fb5c35e203b5d284882c05c1d273dd887 /src/trunnel/channelpadding_negotiation.c | |
parent | 515e1f663ad4a5f1023ef2d2bbcb2de0152d0a47 (diff) | |
download | tor-b0e92634d85a3bf7612a6ce0339b96e4aad1e0bb.tar.gz tor-b0e92634d85a3bf7612a6ce0339b96e4aad1e0bb.zip |
Netflow record collapsing defense.
This defense will cause Cisco, Juniper, Fortinet, and other routers operating
in the default configuration to collapse netflow records that would normally
be split due to the 15 second flow idle timeout.
Collapsing these records should greatly reduce the utility of default netflow
data for correlation attacks, since all client-side records should become 30
minute chunks of total bytes sent/received, rather than creating multiple
separate records for every webpage load/ssh command interaction/XMPP chat/whatever
else happens to be inactive for more than 15 seconds.
The defense adds consensus parameters to govern the range of timeout values
for sending padding packets, as well as for keeping connections open.
The defense only sends padding when connections are otherwise inactive, and it
does not pad connections used solely for directory traffic at all. By default
it also doesn't pad inter-relay connections.
Statistics on the total padding in the last 24 hours are exported to the
extra-info descriptors.
Diffstat (limited to 'src/trunnel/channelpadding_negotiation.c')
-rw-r--r-- | src/trunnel/channelpadding_negotiation.c | 281 |
1 files changed, 281 insertions, 0 deletions
diff --git a/src/trunnel/channelpadding_negotiation.c b/src/trunnel/channelpadding_negotiation.c new file mode 100644 index 0000000000..172d6f8a03 --- /dev/null +++ b/src/trunnel/channelpadding_negotiation.c @@ -0,0 +1,281 @@ +/* channelpadding_negotiation.c -- generated by Trunnel v1.4.3. + * https://gitweb.torproject.org/trunnel.git + * You probably shouldn't edit this file. + */ +#include <stdlib.h> +#include "trunnel-impl.h" + +#include "channelpadding_negotiation.h" + +#define TRUNNEL_SET_ERROR_CODE(obj) \ + do { \ + (obj)->trunnel_error_code_ = 1; \ + } while (0) + +#if defined(__COVERITY__) || defined(__clang_analyzer__) +/* If we're runnning a static analysis tool, we don't want it to complain + * that some of our remaining-bytes checks are dead-code. */ +int channelpaddingnegotiation_deadcode_dummy__ = 0; +#define OR_DEADCODE_DUMMY || channelpaddingnegotiation_deadcode_dummy__ +#else +#define OR_DEADCODE_DUMMY +#endif + +#define CHECK_REMAINING(nbytes, label) \ + do { \ + if (remaining < (nbytes) OR_DEADCODE_DUMMY) { \ + goto label; \ + } \ + } while (0) + +channelpadding_negotiate_t * +channelpadding_negotiate_new(void) +{ + channelpadding_negotiate_t *val = trunnel_calloc(1, sizeof(channelpadding_negotiate_t)); + if (NULL == val) + return NULL; + val->command = CHANNELPADDING_COMMAND_START; + return val; +} + +/** Release all storage held inside 'obj', but do not free 'obj'. + */ +static void +channelpadding_negotiate_clear(channelpadding_negotiate_t *obj) +{ + (void) obj; +} + +void +channelpadding_negotiate_free(channelpadding_negotiate_t *obj) +{ + if (obj == NULL) + return; + channelpadding_negotiate_clear(obj); + trunnel_memwipe(obj, sizeof(channelpadding_negotiate_t)); + trunnel_free_(obj); +} + +uint8_t +channelpadding_negotiate_get_version(channelpadding_negotiate_t *inp) +{ + return inp->version; +} +int +channelpadding_negotiate_set_version(channelpadding_negotiate_t *inp, uint8_t val) +{ + if (! ((val == 0))) { + TRUNNEL_SET_ERROR_CODE(inp); + return -1; + } + inp->version = val; + return 0; +} +uint8_t +channelpadding_negotiate_get_command(channelpadding_negotiate_t *inp) +{ + return inp->command; +} +int +channelpadding_negotiate_set_command(channelpadding_negotiate_t *inp, uint8_t val) +{ + if (! ((val == CHANNELPADDING_COMMAND_START || val == CHANNELPADDING_COMMAND_STOP))) { + TRUNNEL_SET_ERROR_CODE(inp); + return -1; + } + inp->command = val; + return 0; +} +uint16_t +channelpadding_negotiate_get_ito_low_ms(channelpadding_negotiate_t *inp) +{ + return inp->ito_low_ms; +} +int +channelpadding_negotiate_set_ito_low_ms(channelpadding_negotiate_t *inp, uint16_t val) +{ + inp->ito_low_ms = val; + return 0; +} +uint16_t +channelpadding_negotiate_get_ito_high_ms(channelpadding_negotiate_t *inp) +{ + return inp->ito_high_ms; +} +int +channelpadding_negotiate_set_ito_high_ms(channelpadding_negotiate_t *inp, uint16_t val) +{ + inp->ito_high_ms = val; + return 0; +} +const char * +channelpadding_negotiate_check(const channelpadding_negotiate_t *obj) +{ + if (obj == NULL) + return "Object was NULL"; + if (obj->trunnel_error_code_) + return "A set function failed on this object"; + if (! (obj->version == 0)) + return "Integer out of bounds"; + if (! (obj->command == CHANNELPADDING_COMMAND_START || obj->command == CHANNELPADDING_COMMAND_STOP)) + return "Integer out of bounds"; + return NULL; +} + +ssize_t +channelpadding_negotiate_encoded_len(const channelpadding_negotiate_t *obj) +{ + ssize_t result = 0; + + if (NULL != channelpadding_negotiate_check(obj)) + return -1; + + + /* Length of u8 version IN [0] */ + result += 1; + + /* Length of u8 command IN [CHANNELPADDING_COMMAND_START, CHANNELPADDING_COMMAND_STOP] */ + result += 1; + + /* Length of u16 ito_low_ms */ + result += 2; + + /* Length of u16 ito_high_ms */ + result += 2; + return result; +} +int +channelpadding_negotiate_clear_errors(channelpadding_negotiate_t *obj) +{ + int r = obj->trunnel_error_code_; + obj->trunnel_error_code_ = 0; + return r; +} +ssize_t +channelpadding_negotiate_encode(uint8_t *output, const size_t avail, const channelpadding_negotiate_t *obj) +{ + ssize_t result = 0; + size_t written = 0; + uint8_t *ptr = output; + const char *msg; +#ifdef TRUNNEL_CHECK_ENCODED_LEN + const ssize_t encoded_len = channelpadding_negotiate_encoded_len(obj); +#endif + + if (NULL != (msg = channelpadding_negotiate_check(obj))) + goto check_failed; + +#ifdef TRUNNEL_CHECK_ENCODED_LEN + trunnel_assert(encoded_len >= 0); +#endif + + /* Encode u8 version IN [0] */ + trunnel_assert(written <= avail); + if (avail - written < 1) + goto truncated; + trunnel_set_uint8(ptr, (obj->version)); + written += 1; ptr += 1; + + /* Encode u8 command IN [CHANNELPADDING_COMMAND_START, CHANNELPADDING_COMMAND_STOP] */ + trunnel_assert(written <= avail); + if (avail - written < 1) + goto truncated; + trunnel_set_uint8(ptr, (obj->command)); + written += 1; ptr += 1; + + /* Encode u16 ito_low_ms */ + trunnel_assert(written <= avail); + if (avail - written < 2) + goto truncated; + trunnel_set_uint16(ptr, trunnel_htons(obj->ito_low_ms)); + written += 2; ptr += 2; + + /* Encode u16 ito_high_ms */ + trunnel_assert(written <= avail); + if (avail - written < 2) + goto truncated; + trunnel_set_uint16(ptr, trunnel_htons(obj->ito_high_ms)); + written += 2; ptr += 2; + + + trunnel_assert(ptr == output + written); +#ifdef TRUNNEL_CHECK_ENCODED_LEN + { + trunnel_assert(encoded_len >= 0); + trunnel_assert((size_t)encoded_len == written); + } + +#endif + + return written; + + truncated: + result = -2; + goto fail; + check_failed: + (void)msg; + result = -1; + goto fail; + fail: + trunnel_assert(result < 0); + return result; +} + +/** As channelpadding_negotiate_parse(), but do not allocate the + * output object. + */ +static ssize_t +channelpadding_negotiate_parse_into(channelpadding_negotiate_t *obj, const uint8_t *input, const size_t len_in) +{ + const uint8_t *ptr = input; + size_t remaining = len_in; + ssize_t result = 0; + (void)result; + + /* Parse u8 version IN [0] */ + CHECK_REMAINING(1, truncated); + obj->version = (trunnel_get_uint8(ptr)); + remaining -= 1; ptr += 1; + if (! (obj->version == 0)) + goto fail; + + /* Parse u8 command IN [CHANNELPADDING_COMMAND_START, CHANNELPADDING_COMMAND_STOP] */ + CHECK_REMAINING(1, truncated); + obj->command = (trunnel_get_uint8(ptr)); + remaining -= 1; ptr += 1; + if (! (obj->command == CHANNELPADDING_COMMAND_START || obj->command == CHANNELPADDING_COMMAND_STOP)) + goto fail; + + /* Parse u16 ito_low_ms */ + CHECK_REMAINING(2, truncated); + obj->ito_low_ms = trunnel_ntohs(trunnel_get_uint16(ptr)); + remaining -= 2; ptr += 2; + + /* Parse u16 ito_high_ms */ + CHECK_REMAINING(2, truncated); + obj->ito_high_ms = trunnel_ntohs(trunnel_get_uint16(ptr)); + remaining -= 2; ptr += 2; + trunnel_assert(ptr + remaining == input + len_in); + return len_in - remaining; + + truncated: + return -2; + fail: + result = -1; + return result; +} + +ssize_t +channelpadding_negotiate_parse(channelpadding_negotiate_t **output, const uint8_t *input, const size_t len_in) +{ + ssize_t result; + *output = channelpadding_negotiate_new(); + if (NULL == *output) + return -1; + result = channelpadding_negotiate_parse_into(*output, input, len_in); + if (result < 0) { + channelpadding_negotiate_free(*output); + *output = NULL; + } + return result; +} |