Skip to content

Commit

Permalink
Merge pull request #308 from kulkom/master
Browse files Browse the repository at this point in the history
Fix a potential log spamming and DOS attack
  • Loading branch information
davidmoreno authored Sep 5, 2022
2 parents 98e5a9a + 89cc1c0 commit de8ea93
Show file tree
Hide file tree
Showing 2 changed files with 63 additions and 3 deletions.
60 changes: 60 additions & 0 deletions src/onion/low.h
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,66 @@
extern "C" {
#endif

/**
* @short A portable macro for declaring thread-local variables.
* @ingroup low
* @{
*
* This macro should be used instead of C11-and-newer's _Thread_local
* and GCC's __thread for portability's sake.
*/
#if __STDC_VERSION__ >= 201112 && !defined(__STDC_NO_THREADS__)
# define ONION_THREAD_LOCAL _Thread_local
#elif defined(_WIN32) && ( \
defined(_MSC_VER) || \
defined(__ICL) || \
defined(__DMC__) || \
defined(__BORLANDC__) \
)
# define ONION_THREAD_LOCAL __declspec(thread)
#elif defined(__TINYC__) || defined (__SDCC) || defined (__CC65__) || defined (__TenDRA__) /* Might apply to other compilers. From a brief glance PCC supports __thread. */
# error You are using an obsolete compiler that does not support thread-local variables. Onion will not compile. Consider using a different compiler.
#else
# define ONION_THREAD_LOCAL __thread
#endif
/// @}

/**
* @short MACROS FOR CALLING A FUNCTION ONCE AT MOST EVERY X SECONDS IN EACH THREAD.
* @{
*
* This is especially useful for preventing log-spamming, and possible DoS attacks
* that can happen as a consequence of threads having to write out a massive log.
* To use them you MUST include <time.h>.
*/
/**
* @short Call a function once at most every X seconds in each thread - don't count or pass the calls that happened in between.
* @ingroup low
*/
#define ONION_CALL_MAX_ONCE_PER_T(seconds, func, ...) do { \
static ONION_THREAD_LOCAL time_t last_func_call = 0; \
if (difftime(time(0), last_func_call) >= seconds) { \
func(__VA_ARGS__); \
time(&last_func_call); \
} \
} while (0)
/**
* @short Call a function once at most every X seconds in each thread and pass the number of ignored calls + 1 as the last argument (an unsigned int).
* @ingroup low
*/
#define ONION_CALL_MAX_ONCE_PER_T_COUNT(seconds, func, ...) do { \
static ONION_THREAD_LOCAL time_t last_func_call = 0; \
static ONION_THREAD_LOCAL unsigned int func_calls_since = 0; \
if (difftime(time(0), last_func_call) >= seconds) { \
func(__VA_ARGS__, func_calls_since + 1); \
func_calls_since = 0; \
time(&last_func_call); \
} \
else \
++func_calls_since; \
} while (0)
/// @}

/**
* @short NEVER FAILING MEMORY ALLOCATORS
* @{
Expand Down
6 changes: 3 additions & 3 deletions src/onion/response.c
Original file line number Diff line number Diff line change
Expand Up @@ -431,9 +431,9 @@ int onion_response_flush(onion_response * res) {
char tmp[16];
snprintf(tmp, sizeof(tmp), "%X\r\n", (unsigned int)res->buffer_pos);
if ((w = write(req, tmp, strlen(tmp))) <= 0) {
ONION_WARNING("Error writing chunk encoding length (%X) %s. Aborting write.",

(unsigned int)res->buffer_pos, strerror(errno));
ONION_CALL_MAX_ONCE_PER_T_COUNT(1, ONION_WARNING, "Error writing chunk encoding length (%X) %s. Aborting write. (x%u)",
(unsigned int)res->buffer_pos, strerror(errno));
return OCS_CLOSE_CONNECTION;
}
ONION_DEBUG0("Write %d-%d bytes", res->buffer_pos, w);
Expand Down

0 comments on commit de8ea93

Please sign in to comment.