21#ifdef HAVE_NETINET_IN_H
22#include <netinet/in.h>
60#define MAX_UNCOMPRESSION_FACTOR 25
61#define CHECK_FOR_COMPRESSION_BOMB_AFTER (5 * 1024 * 1024)
69 if (size_in == 0 || size_out < CHECK_FOR_COMPRESSION_BOMB_AFTER)
72 double compression_factor = (double)size_out / size_in;
73 if (compression_factor > MAX_UNCOMPRESSION_FACTOR) {
75 "Detected possible compression bomb with "
76 "input size = %"TOR_PRIuSZ
" and output size = %"TOR_PRIuSZ
" "
77 "(compression factor = %.2f)",
78 size_in, size_out, compression_factor);
93 (void)compression_level;
94 if (method == NO_METHOD) {
97 return (in_len < SIZE_MAX) ? in_len + 1 : in_len;
107 return MAX(in_len, 1024);
115 char **out,
size_t *out_len,
116 const char *in,
size_t in_len,
120 int protocol_warn_level)
127 if (stream == NULL) {
128 log_warn(
LD_GENERAL,
"NULL stream while %scompressing",
130 log_debug(
LD_GENERAL,
"method: %d level: %d at len: %lu",
131 method, compression_level, (
unsigned long)in_len);
135 size_t in_len_orig = in_len;
136 size_t out_remaining, out_alloc;
139 out_remaining = out_alloc =
141 *out = outptr = tor_malloc(out_remaining);
143 const int finish = complete_only || compress;
147 &outptr, &out_remaining,
148 &in, &in_len, finish)) {
149 case TOR_COMPRESS_DONE:
150 if (in_len == 0 || compress) {
156 tor_compress_free(stream);
158 if (stream == NULL) {
159 log_warn(
LD_GENERAL,
"NULL stream while %scompressing",
165 case TOR_COMPRESS_OK:
166 if (compress || complete_only) {
168 "Unexpected %s while %scompressing",
169 complete_only?
"end of input":
"result",
171 log_debug(
LD_GENERAL,
"method: %d level: %d at len: %lu",
172 method, compression_level, (
unsigned long)in_len);
180 case TOR_COMPRESS_BUFFER_FULL: {
181 if (!compress && outptr < *out+out_alloc) {
185 "Possible truncated or corrupt compressed data");
189 log_warn(
LD_GENERAL,
"While %scompressing data: ran out of space.",
201 const size_t offset = outptr - *out;
203 *out = tor_realloc(*out, out_alloc);
204 outptr = *out + offset;
205 out_remaining = out_alloc - offset;
208 case TOR_COMPRESS_ERROR:
210 "Error while %scompressing data: bad input?",
222 *out_len = outptr - *out;
224 log_warn(
LD_BUG,
"We compressed something and got an insanely high "
225 "compression factor; other Tors would think this was a "
226 "compression bomb.");
231 if (out_alloc == *out_len)
232 *out = tor_realloc(*out, out_alloc + 1);
233 (*out)[*out_len] =
'\0';
245 tor_compress_free(stream);
256 const char *in,
size_t in_len,
282 const char *in,
size_t in_len,
285 int protocol_warn_level)
289 complete_only, protocol_warn_level);
299 if (in_len > 2 &&
fast_memeq(in,
"\x1f\x8b", 2)) {
301 }
else if (in_len > 2 && (in[0] & 0x0f) == 8 &&
304 }
else if (in_len > 2 &&
307 }
else if (in_len > 3 &&
311 return UNKNOWN_METHOD;
343 static unsigned supported = 0;
344 if (supported == 0) {
346 for (m = NO_METHOD; m <= UNKNOWN_METHOD; ++m) {
348 supported |= (1u << m);
361 {
"gzip", GZIP_METHOD },
362 {
"deflate", ZLIB_METHOD },
365 {
"x-tor-lzma", LZMA_METHOD },
366 {
"x-zstd" , ZSTD_METHOD },
367 {
"identity", NO_METHOD },
371 {
"x-gzip", GZIP_METHOD },
392 { NO_METHOD,
"uncompressed" },
393 { GZIP_METHOD,
"gzipped" },
394 { ZLIB_METHOD,
"deflated" },
395 { LZMA_METHOD,
"LZMA compressed" },
396 { ZSTD_METHOD,
"Zstandard compressed" },
397 { UNKNOWN_METHOD,
"unknown encoding" },
423 return UNKNOWN_METHOD;
508 if (zlib_state == NULL)
511 state->
u.zlib_state = zlib_state;
518 if (lzma_state == NULL)
521 state->
u.lzma_state = lzma_state;
528 if (zstd_state == NULL)
531 state->
u.zstd_state = zstd_state;
563 char **out,
size_t *out_len,
564 const char **in,
size_t *in_len,
568 const size_t in_len_orig = *in_len;
569 const size_t out_len_orig = *out_len;
572 if (*out_len == 0 && (*in_len > 0 || finish)) {
576 return TOR_COMPRESS_BUFFER_FULL;
583 out, out_len, in, in_len,
588 out, out_len, in, in_len,
593 out, out_len, in, in_len,
604 if (BUG((rv == TOR_COMPRESS_OK) &&
605 *in_len == in_len_orig &&
606 *out_len == out_len_orig)) {
608 "More info on the bug: method == %s, finish == %d, "
609 " *in_len == in_len_orig == %lu, "
610 "*out_len == out_len_orig == %lu",
612 (
unsigned long)in_len_orig, (
unsigned long)out_len_orig);
613 return TOR_COMPRESS_ERROR;
618 return TOR_COMPRESS_ERROR;
631 tor_zlib_compress_free(state->
u.zlib_state);
634 tor_lzma_compress_free(state->
u.lzma_state);
637 tor_zstd_compress_free(state->
u.zstd_state);
703subsys_compress_initialize(
void)
713 .initialize = subsys_compress_initialize,
Inline functions for reading and writing multibyte values from the middle of strings,...
static uint16_t get_uint16(const void *cp)
static uint16_t tor_ntohs(uint16_t a)
Macro definitions for MIN, MAX, and CLAMP.
void atomic_counter_init(atomic_counter_t *counter)
void atomic_counter_sub(atomic_counter_t *counter, size_t sub)
void atomic_counter_add(atomic_counter_t *counter, size_t add)
size_t atomic_counter_get(atomic_counter_t *counter)
const char * tor_compress_version_str(compress_method_t method)
int tor_compress_init(void)
static const struct @29 compression_method_human_names[]
tor_compress_output_t tor_compress_process(tor_compress_state_t *state, char **out, size_t *out_len, const char **in, size_t *in_len, int finish)
int tor_compress_supports_method(compress_method_t method)
static size_t guess_compress_size(int compress, compress_method_t method, compression_level_t compression_level, size_t in_len)
compress_method_t compression_method_get_by_name(const char *name)
int tor_compress_is_compression_bomb(size_t size_in, size_t size_out)
const char * tor_compress_header_version_str(compress_method_t method)
static atomic_counter_t total_compress_allocation
void tor_compress_free_(tor_compress_state_t *state)
unsigned tor_compress_get_supported_method_bitmask(void)
size_t tor_compress_state_size(const tor_compress_state_t *state)
static int tor_compress_impl(int compress, char **out, size_t *out_len, const char *in, size_t in_len, compress_method_t method, compression_level_t compression_level, int complete_only, int protocol_warn_level)
void tor_compress_log_init_warnings(void)
int tor_compress(char **out, size_t *out_len, const char *in, size_t in_len, compress_method_t method)
compress_method_t detect_compression_method(const char *in, size_t in_len)
tor_compress_state_t * tor_compress_new(int compress, compress_method_t method, compression_level_t compression_level)
int tor_uncompress(char **out, size_t *out_len, const char *in, size_t in_len, compress_method_t method, int complete_only, int protocol_warn_level)
const char * compression_method_get_name(compress_method_t method)
size_t tor_compress_get_total_allocation(void)
static const struct @28 compression_method_names[]
const char * compression_method_get_human_name(compress_method_t method)
tor_lzma_compress_state_t * tor_lzma_compress_new(int compress, compress_method_t method, compression_level_t level)
const char * tor_lzma_get_version_str(void)
int tor_lzma_method_supported(void)
const char * tor_lzma_get_header_version_str(void)
tor_compress_output_t tor_lzma_compress_process(tor_lzma_compress_state_t *state, char **out, size_t *out_len, const char **in, size_t *in_len, int finish)
size_t tor_lzma_compress_state_size(const tor_lzma_compress_state_t *state)
size_t tor_lzma_get_total_allocation(void)
Header for compress_lzma.c.
tor_compress_output_t tor_cnone_compress_process(char **out, size_t *out_len, const char **in, size_t *in_len, int finish)
Header for compress_none.c.
Declare subsystem object for the compress module.
const char * tor_zlib_get_header_version_str(void)
const char * tor_zlib_get_version_str(void)
int tor_zlib_method_supported(void)
tor_zlib_compress_state_t * tor_zlib_compress_new(int compress_, compress_method_t method, compression_level_t compression_level)
size_t tor_zlib_get_total_allocation(void)
size_t tor_zlib_compress_state_size(const tor_zlib_compress_state_t *state)
tor_compress_output_t tor_zlib_compress_process(tor_zlib_compress_state_t *state, char **out, size_t *out_len, const char **in, size_t *in_len, int finish)
Header for compress_zlib.c.
const char * tor_zstd_get_header_version_str(void)
int tor_zstd_method_supported(void)
const char * tor_zstd_get_version_str(void)
tor_zstd_compress_state_t * tor_zstd_compress_new(int compress, compress_method_t method, compression_level_t level)
tor_compress_output_t tor_zstd_compress_process(tor_zstd_compress_state_t *state, char **out, size_t *out_len, const char **in, size_t *in_len, int finish)
size_t tor_zstd_get_total_allocation(void)
size_t tor_zstd_compress_state_size(const tor_zstd_compress_state_t *state)
void tor_zstd_warn_if_version_mismatched(void)
Header for compress_zstd.c.
#define fast_memeq(a, b, c)
#define log_fn(severity, domain, args,...)
Headers for util_malloc.c.
union tor_compress_state_t::@30 u
Types used to declare a subsystem.
#define SUBSYS_DECLARE_LOCATION()
#define MOCK_IMPL(rv, funcname, arglist)
Integer definitions used throughout Tor.
Macros to manage assertions, fatal and non-fatal.
#define tor_assert_nonfatal_unreached()