21#ifdef HAVE_NETINET_IN_H
22#include <netinet/in.h>
57#define MAX_UNCOMPRESSION_FACTOR 25
58#define CHECK_FOR_COMPRESSION_BOMB_AFTER (1024*64)
66 if (size_in == 0 || size_out < CHECK_FOR_COMPRESSION_BOMB_AFTER)
69 double compression_factor = (double)size_out / size_in;
70 if (compression_factor > MAX_UNCOMPRESSION_FACTOR) {
72 "Detected possible compression bomb with "
73 "input size = %"TOR_PRIuSZ
" and output size = %"TOR_PRIuSZ
" "
74 "(compression factor = %.2f)",
75 size_in, size_out, compression_factor);
90 (void)compression_level;
91 if (method == NO_METHOD) {
94 return (in_len < SIZE_MAX) ? in_len + 1 : in_len;
104 return MAX(in_len, 1024);
112 char **out,
size_t *out_len,
113 const char *in,
size_t in_len,
117 int protocol_warn_level)
124 if (stream == NULL) {
125 log_warn(
LD_GENERAL,
"NULL stream while %scompressing",
127 log_debug(
LD_GENERAL,
"method: %d level: %d at len: %lu",
128 method, compression_level, (
unsigned long)in_len);
132 size_t in_len_orig = in_len;
133 size_t out_remaining, out_alloc;
136 out_remaining = out_alloc =
138 *out = outptr = tor_malloc(out_remaining);
140 const int finish = complete_only || compress;
144 &outptr, &out_remaining,
145 &in, &in_len, finish)) {
146 case TOR_COMPRESS_DONE:
147 if (in_len == 0 || compress) {
153 tor_compress_free(stream);
155 if (stream == NULL) {
156 log_warn(
LD_GENERAL,
"NULL stream while %scompressing",
162 case TOR_COMPRESS_OK:
163 if (compress || complete_only) {
165 "Unexpected %s while %scompressing",
166 complete_only?
"end of input":
"result",
168 log_debug(
LD_GENERAL,
"method: %d level: %d at len: %lu",
169 method, compression_level, (
unsigned long)in_len);
177 case TOR_COMPRESS_BUFFER_FULL: {
178 if (!compress && outptr < *out+out_alloc) {
182 "Possible truncated or corrupt compressed data");
186 log_warn(
LD_GENERAL,
"While %scompressing data: ran out of space.",
198 const size_t offset = outptr - *out;
200 *out = tor_realloc(*out, out_alloc);
201 outptr = *out + offset;
202 out_remaining = out_alloc - offset;
205 case TOR_COMPRESS_ERROR:
207 "Error while %scompressing data: bad input?",
219 *out_len = outptr - *out;
221 log_warn(
LD_BUG,
"We compressed something and got an insanely high "
222 "compression factor; other Tors would think this was a "
223 "compression bomb.");
228 if (out_alloc == *out_len)
229 *out = tor_realloc(*out, out_alloc + 1);
230 (*out)[*out_len] =
'\0';
242 tor_compress_free(stream);
253 const char *in,
size_t in_len,
279 const char *in,
size_t in_len,
282 int protocol_warn_level)
286 complete_only, protocol_warn_level);
296 if (in_len > 2 &&
fast_memeq(in,
"\x1f\x8b", 2)) {
298 }
else if (in_len > 2 && (in[0] & 0x0f) == 8 &&
301 }
else if (in_len > 2 &&
304 }
else if (in_len > 3 &&
308 return UNKNOWN_METHOD;
340 static unsigned supported = 0;
341 if (supported == 0) {
343 for (m = NO_METHOD; m <= UNKNOWN_METHOD; ++m) {
345 supported |= (1u << m);
358 {
"gzip", GZIP_METHOD },
359 {
"deflate", ZLIB_METHOD },
362 {
"x-tor-lzma", LZMA_METHOD },
363 {
"x-zstd" , ZSTD_METHOD },
364 {
"identity", NO_METHOD },
368 {
"x-gzip", GZIP_METHOD },
389 { NO_METHOD,
"uncompressed" },
390 { GZIP_METHOD,
"gzipped" },
391 { ZLIB_METHOD,
"deflated" },
392 { LZMA_METHOD,
"LZMA compressed" },
393 { ZSTD_METHOD,
"Zstandard compressed" },
394 { UNKNOWN_METHOD,
"unknown encoding" },
420 return UNKNOWN_METHOD;
505 if (zlib_state == NULL)
508 state->
u.zlib_state = zlib_state;
515 if (lzma_state == NULL)
518 state->
u.lzma_state = lzma_state;
525 if (zstd_state == NULL)
528 state->
u.zstd_state = zstd_state;
560 char **out,
size_t *out_len,
561 const char **in,
size_t *in_len,
565 const size_t in_len_orig = *in_len;
566 const size_t out_len_orig = *out_len;
569 if (*out_len == 0 && (*in_len > 0 || finish)) {
573 return TOR_COMPRESS_BUFFER_FULL;
580 out, out_len, in, in_len,
585 out, out_len, in, in_len,
590 out, out_len, in, in_len,
601 if (BUG((rv == TOR_COMPRESS_OK) &&
602 *in_len == in_len_orig &&
603 *out_len == out_len_orig)) {
605 "More info on the bug: method == %s, finish == %d, "
606 " *in_len == in_len_orig == %lu, "
607 "*out_len == out_len_orig == %lu",
609 (
unsigned long)in_len_orig, (
unsigned long)out_len_orig);
610 return TOR_COMPRESS_ERROR;
615 return TOR_COMPRESS_ERROR;
628 tor_zlib_compress_free(state->
u.zlib_state);
631 tor_lzma_compress_free(state->
u.lzma_state);
634 tor_zstd_compress_free(state->
u.zstd_state);
700subsys_compress_initialize(
void)
710 .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()