From f48a2ebb558da93cc71c83118b333905a03156f8 Mon Sep 17 00:00:00 2001 From: Lisa Marie Maginnis Date: Tue, 12 Nov 2024 01:06:07 +0100 Subject: [PATCH 1/6] Allowlist for the 401 rate-limit features. Added a new `--401-allowlist` to allow adding a path of an allow-list of IPv4/IPv6 addresses that can bypass the 401 rate-limit settings. This can also be set in the configuration file via `401-allowlist=.` The allow-list is updated when the allowlist file is updated during runtime. The allow-list format is one (1) IP address per line. --- README.turnserver | 2 + examples/etc/turnserver.conf | 17 ++++++ src/apps/relay/mainrelay.c | 14 ++++- src/apps/relay/mainrelay.h | 1 + src/apps/relay/netengine.c | 3 +- src/server/ns_turn_ratelimit.c | 102 ++++++++++++++++++++++++++++++++- src/server/ns_turn_ratelimit.h | 3 +- src/server/ns_turn_server.c | 7 ++- src/server/ns_turn_server.h | 4 +- 9 files changed, 143 insertions(+), 10 deletions(-) diff --git a/README.turnserver b/README.turnserver index 7152cca54..f0e28a1b8 100644 --- a/README.turnserver +++ b/README.turnserver @@ -682,6 +682,8 @@ Options with values: Defaults is 1000. --401-window= Set the time window duration in seconds for rate limiting 401 Unauthorized responses. Defaults is 120. +--401-allowlist= Set the path of the allow-list, one IP per line allowed to bypass the 401 rate-limit settings. + Default is none. ================================== diff --git a/examples/etc/turnserver.conf b/examples/etc/turnserver.conf index 2ccfd5e0a..4ea4f2927 100644 --- a/examples/etc/turnserver.conf +++ b/examples/etc/turnserver.conf @@ -828,6 +828,23 @@ #no-tlsv1_1 #no-tlsv1_2 + +# Set the maximum number of 401 Unauthorized responses allowed per rate-limiting +# window. When set to 0 disalbes 401 rate-limiting. +# +#401-req-limit=1000 + +# Set the time window duration in seconds for rate limiting 401 Unauthorized +# responses. +# +#401-window=120 + +# Set the path of the allow-list, one IP per line allowed to bypass the 401 +# rate-limit settings. By default this is disabled. Uncomment to enable use +# of the 401 rate-limit allow list: +# +#401-allowlist=/etc/coturn/allowlist.txt + # Disable RFC5780 (NAT behavior discovery). # # Originally, if there are more than one listener address from the same diff --git a/src/apps/relay/mainrelay.c b/src/apps/relay/mainrelay.c index 6b4703081..4aeb1895e 100644 --- a/src/apps/relay/mainrelay.c +++ b/src/apps/relay/mainrelay.c @@ -251,7 +251,8 @@ turn_params_t turn_params = { ///////// Ratelimt ///////// RATELIMIT_DEFAULT_MAX_REQUESTS_PER_WINDOW, /* 401-req-limit */ - RATELIMIT_DEFAULT_WINDOW_SECS /* 401-window */ + RATELIMIT_DEFAULT_WINDOW_SECS, /* 401-window */ + NULL /* 401-allowlist */ }; //////////////// OpenSSL Init ////////////////////// @@ -1311,6 +1312,8 @@ static char Usage[] = " per rate-limiting window. If set to 0 disables rate limiting. Default is 1000.\n" " --401-window=\t\t\t\tSet the time window duration in seconds for rate limiting 401 Unauthorized responses.\n" " Default is 120.\n" + " --401-allowlist=\t\t\tSet the path of the allow-list, one IP per line allowed to bypass the 401\n" + " rate-limit settings. Default is none.\n" " --version Print version (and exit).\n" " -h Help\n" "\n"; @@ -1476,9 +1479,9 @@ enum EXTRA_OPTS { FEDERATION_PKEY_OPT, FEDERATION_PKEY_PWD_OPT, FEDERATION_REMOTE_WHITELIST_OPT, - RATELIMIT_OPT, RATELIMIT_REQUESTS_OPT, - RATELIMIT_WINDOW_OPT + RATELIMIT_WINDOW_OPT, + RATELIMIT_ALLOWLIST_OPT }; struct myoption { @@ -1633,6 +1636,7 @@ static const struct myoption long_options[] = { {"syslog-facility", required_argument, NULL, SYSLOG_FACILITY_OPT}, {"401-req-limit", optional_argument, NULL, RATELIMIT_REQUESTS_OPT}, {"401-window", optional_argument, NULL, RATELIMIT_WINDOW_OPT}, + {"401-allowlist", optional_argument, NULL, RATELIMIT_ALLOWLIST_OPT}, {NULL, no_argument, NULL, 0}}; static const struct myoption admin_long_options[] = { @@ -2397,6 +2401,10 @@ static void set_option(int c, char *value) { turn_params.ratelimit_401_window_seconds = get_int_value(value, RATELIMIT_DEFAULT_WINDOW_SECS); TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO, "Setting 401 ratelimit window to: %i seconds\n", turn_params.ratelimit_401_window_seconds); break; + case RATELIMIT_ALLOWLIST_OPT: + STRCPY(turn_params.ratelimit_401_allowlist, value); + TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO, "Setting 401 ratelimit allow list to: %s\n", turn_params.ratelimit_401_allowlist); + break; /* these options have been already taken care of before: */ case 'l': case NO_STDOUT_LOG_OPT: diff --git a/src/apps/relay/mainrelay.h b/src/apps/relay/mainrelay.h index 07d08cf77..e89f9be97 100644 --- a/src/apps/relay/mainrelay.h +++ b/src/apps/relay/mainrelay.h @@ -354,6 +354,7 @@ typedef struct _turn_params_ { vint ratelimit_401_requests_per_window; vint ratelimit_401_window_seconds; + char ratelimit_401_allowlist[1025]; } turn_params_t; extern turn_params_t turn_params; diff --git a/src/apps/relay/netengine.c b/src/apps/relay/netengine.c index 273fada2f..2a89eeecc 100644 --- a/src/apps/relay/netengine.c +++ b/src/apps/relay/netengine.c @@ -1696,7 +1696,8 @@ static void setup_relay_server(struct relay_server *rs, ioa_engine_handle e, int turn_params.oauth_server_name, turn_params.acme_redirect, turn_params.allocation_default_address_family, &turn_params.log_binding, &turn_params.no_stun_backward_compatibility, &turn_params.response_origin_only_with_rfc5780, - &turn_params.ratelimit_401_requests_per_window, &turn_params.ratelimit_401_window_seconds); + &turn_params.ratelimit_401_requests_per_window, &turn_params.ratelimit_401_window_seconds, + &turn_params.ratelimit_401_allowlist); // Intentionally performed outside init_turn_server to help avoid future merge conflicts diff --git a/src/server/ns_turn_ratelimit.c b/src/server/ns_turn_ratelimit.c index 825a998bd..cd2eb6101 100644 --- a/src/server/ns_turn_ratelimit.c +++ b/src/server/ns_turn_ratelimit.c @@ -28,6 +28,8 @@ * SUCH DAMAGE. */ +#include + #include "ns_turn_maps.h" #include "ns_turn_ioalib.h" #include "ns_turn_ratelimit.h" @@ -35,8 +37,95 @@ /////////////////// rate limit ////////////////////////// ur_addr_map *rate_limit_map = NULL; +ur_addr_map *rate_limit_allowlist_map = NULL; + int ratelimit_window_secs = RATELIMIT_DEFAULT_WINDOW_SECS; +time_t last_mtime = 0; + TURN_MUTEX_DECLARE(rate_limit_main_mutex); +TURN_MUTEX_DECLARE(rate_limit_allowlist_mutex); + +void ratelimit_remove_newlines(char *str) { + char *src = str; + char *dst = str; + + while (*src != '\0') { + if (*src != '\r' && *src != '\n') { + *dst++ = *src; + } + src++; + } + *dst = '\0'; +} + +void ratelimit_init_allowlist_map() { + TURN_MUTEX_INIT(&rate_limit_allowlist_mutex); + TURN_MUTEX_LOCK(&rate_limit_allowlist_mutex); + + rate_limit_allowlist_map = (ur_addr_map*)malloc(sizeof(ur_addr_map)); + ur_addr_map_init(rate_limit_allowlist_map); + + TURN_MUTEX_UNLOCK(&rate_limit_allowlist_mutex); +} + +int ratelimit_is_on_allowlist(const char *allowlist, ioa_addr *addr) { + /* If no allowlist provided, return early */ + if (!allowlist) { + return 0; + } + /* Init allow_list map if needed */ + if (rate_limit_allowlist_map == NULL) { + ratelimit_init_allowlist_map(); + } + + /* Check the mtime of the allow list, do we need to update? */ + struct stat fstat; + if (stat(allowlist, &fstat) == 0) { + if (fstat.st_mtime != last_mtime) { + last_mtime = fstat.st_mtime; + + FILE *file = NULL; + file = fopen(allowlist, "r"); + if (file != NULL) { + char line[1024]; + + /* Rebuild map */ + TURN_MUTEX_LOCK(&rate_limit_allowlist_mutex); + ur_addr_map_clean(rate_limit_allowlist_map); + ur_addr_map_init(rate_limit_allowlist_map); + TURN_MUTEX_UNLOCK(&rate_limit_allowlist_mutex); + /* loop over file and add entries */ + while (fgets(line, sizeof(line) - 1, file) != NULL) { + if (!line) { + break; + } + + ioa_addr new_address; + ratelimit_remove_newlines(line); + if(make_ioa_addr_from_full_string((const uint8_t *)line, 0, &new_address) != 0) { + TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "Malformed address in 401 ratelimit allow list file %s: %s\n", allowlist, line); + } else { + TURN_MUTEX_LOCK(&rate_limit_allowlist_mutex); + ur_addr_map_put(rate_limit_allowlist_map, &new_address, (ur_addr_map_value_type)1); + TURN_MUTEX_UNLOCK(&rate_limit_allowlist_mutex); + } + } + if (file) { + fclose(file); + } + } else { + TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "Could not open 401 ratelimit allow list file: %s\n", allowlist); + } + } + } + + ur_addr_map_value_type ratelimit_ptr = 0; + if (ur_addr_map_get(rate_limit_allowlist_map, addr, &ratelimit_ptr)) { + return 1; + } else { + return 0; + } +} void ratelimit_add_node(ioa_addr *address) { // copy address @@ -63,7 +152,7 @@ void ratelimit_init_map() { TURN_MUTEX_UNLOCK(&rate_limit_main_mutex); } -int ratelimit_is_address_limited(ioa_addr *address, int max_requests, int window_seconds) { +int ratelimit_is_address_limited(ioa_addr *address, int max_requests, int window_seconds, const char *allowlist) { /* Housekeeping, prune the map when ADDR_MAP_SIZE is hit and delete expired items */ turn_time_t current_time = turn_time(); @@ -87,7 +176,6 @@ int ratelimit_is_address_limited(ioa_addr *address, int max_requests, int window addr_set_port(address_new, 0); if (ur_addr_map_get(rate_limit_map, address_new, &ratelimit_ptr)) { - free(address_new); ratelimit_entry *rateLimitEntry = (ratelimit_entry *)(void *)(ur_map_value_type)ratelimit_ptr; TURN_MUTEX_LOCK(&(rateLimitEntry->mutex)); @@ -96,6 +184,7 @@ int ratelimit_is_address_limited(ioa_addr *address, int max_requests, int window rateLimitEntry->request_count = 1; rateLimitEntry->last_request_time = current_time; TURN_MUTEX_UNLOCK(&(rateLimitEntry->mutex)); + free(address_new); return 0; } else if (rateLimitEntry->request_count < max_requests) { /* Check if request count is below requests per window; increment the count */ @@ -103,8 +192,17 @@ int ratelimit_is_address_limited(ioa_addr *address, int max_requests, int window rateLimitEntry->request_count++; rateLimitEntry->last_request_time = current_time; TURN_MUTEX_UNLOCK(&(rateLimitEntry->mutex)); + free(address_new); return 0; } else { + /* Before ratelimit, check allow list */ + if(ratelimit_is_on_allowlist(allowlist, address_new)) { + free(address_new); + TURN_MUTEX_UNLOCK(&(rateLimitEntry->mutex)); + return 0; + } + + free(address_new); /* Request is outside of defined window and count, request is ratelimited */ if (rateLimitEntry->request_count < UINT32_MAX) rateLimitEntry->request_count++; diff --git a/src/server/ns_turn_ratelimit.h b/src/server/ns_turn_ratelimit.h index 0fae1f8d0..693fc717a 100644 --- a/src/server/ns_turn_ratelimit.h +++ b/src/server/ns_turn_ratelimit.h @@ -38,7 +38,8 @@ extern "C" { #endif -int ratelimit_is_address_limited(ioa_addr *address, int max_requests, int window_seconds); +int ratelimit_is_address_limited(ioa_addr *address, int max_requests, + int window_seconds, const char *allowlist); void ratelimit_add_node(ioa_addr *address); int ratelimit_delete_expired(ur_map_value_type value); void ratelimit_init_map(void); diff --git a/src/server/ns_turn_server.c b/src/server/ns_turn_server.c index 3a2bf8fa4..8f123990c 100644 --- a/src/server/ns_turn_server.c +++ b/src/server/ns_turn_server.c @@ -3921,7 +3921,8 @@ static int handle_turn_command(turn_turnserver *server, ts_ur_super_session *ss, } if(err_code == 401 && *server->ratelimit_401_requests_per_window > 0) { ioa_addr *rate_limit_address = get_remote_addr_from_ioa_socket(ss->client_socket); - if (ratelimit_is_address_limited(rate_limit_address, *server->ratelimit_401_requests_per_window, *server->ratelimit_401_window_seconds)) { + if (ratelimit_is_address_limited(rate_limit_address, *server->ratelimit_401_requests_per_window, + *server->ratelimit_401_window_seconds, server->ratelimit_401_allowlist)) { no_response = 1; char raddr[129]; addr_to_string_no_port(rate_limit_address, (unsigned char *)raddr); @@ -4929,7 +4930,8 @@ void init_turn_server(turn_turnserver *server, turnserver_id id, int verbose, io const char *acme_redirect, ALLOCATION_DEFAULT_ADDRESS_FAMILY allocation_default_address_family, vintp log_binding, vintp no_stun_backward_compatibility, vintp response_origin_only_with_rfc5780, - vintp ratelimit_401_requests_per_window, vintp ratelimit_401_window_seconds) { + vintp ratelimit_401_requests_per_window, vintp ratelimit_401_window_seconds, + const char *ratelimit_401_allowlist) { if (!server) return; @@ -5011,6 +5013,7 @@ void init_turn_server(turn_turnserver *server, turnserver_id id, int verbose, io server->is_draining = 0; server->ratelimit_401_requests_per_window = ratelimit_401_requests_per_window; server->ratelimit_401_window_seconds = ratelimit_401_window_seconds; + server->ratelimit_401_allowlist = ratelimit_401_allowlist; } ioa_engine_handle turn_server_get_engine(turn_turnserver *s) { diff --git a/src/server/ns_turn_server.h b/src/server/ns_turn_server.h index e88d83332..d9a6ac7b1 100644 --- a/src/server/ns_turn_server.h +++ b/src/server/ns_turn_server.h @@ -212,6 +212,7 @@ struct _turn_turnserver { vintp ratelimit_401_requests_per_window; vintp ratelimit_401_window_seconds; + const char *ratelimit_401_allowlist; }; const char *get_version(turn_turnserver *server); @@ -234,7 +235,8 @@ void init_turn_server(turn_turnserver *server, turnserver_id id, int verbose, io allocate_bps_cb allocate_bps_func, int oauth, const char *oauth_server_name, const char *acme_redirect, ALLOCATION_DEFAULT_ADDRESS_FAMILY allocation_default_address_family, vintp log_binding, vintp no_stun_backward_compatibility, vintp response_origin_only_with_rfc5780, - vintp ratelimit_401_requests_per_window, vintp ratelimit_401_window_seconds); + vintp ratelimit_401_requests_per_window, vintp ratelimit_401_window_seconds, + const char *ratelimit_401_allowlist); ioa_engine_handle turn_server_get_engine(turn_turnserver *s); From c7d952baf9c616b048f343a3abc3501205fa5a4c Mon Sep 17 00:00:00 2001 From: Lisa Marie Maginnis Date: Mon, 16 Dec 2024 13:12:05 +0100 Subject: [PATCH 2/6] Added global lock for addr_map_get, for threading --- src/server/ns_turn_ratelimit.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/server/ns_turn_ratelimit.c b/src/server/ns_turn_ratelimit.c index cd2eb6101..1023e2c3b 100644 --- a/src/server/ns_turn_ratelimit.c +++ b/src/server/ns_turn_ratelimit.c @@ -120,9 +120,12 @@ int ratelimit_is_on_allowlist(const char *allowlist, ioa_addr *addr) { } ur_addr_map_value_type ratelimit_ptr = 0; + TURN_MUTEX_LOCK(&rate_limit_allowlist_mutex); if (ur_addr_map_get(rate_limit_allowlist_map, addr, &ratelimit_ptr)) { + TURN_MUTEX_UNLOCK(&rate_limit_allowlist_mutex); return 1; } else { + TURN_MUTEX_UNLOCK(&rate_limit_allowlist_mutex); return 0; } } From d1fb9ccc88920fab6a03248a52105611da2da974 Mon Sep 17 00:00:00 2001 From: Lisa Marie Maginnis Date: Mon, 16 Dec 2024 14:18:41 +0100 Subject: [PATCH 3/6] Bumped coturn version --- src/ns_turn_defs.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ns_turn_defs.h b/src/ns_turn_defs.h index d7fc19f3e..415217dbb 100644 --- a/src/ns_turn_defs.h +++ b/src/ns_turn_defs.h @@ -31,7 +31,7 @@ #ifndef __IOADEFS__ #define __IOADEFS__ -#define TURN_SERVER_VERSION "wireapp/4.6.2f" +#define TURN_SERVER_VERSION "wireapp/4.6.2i" #define TURN_SERVER_VERSION_NAME "Gorst" #ifndef TURN_SERVER_BUILD_INFO #define TURN_SERVER_BUILD_INFO "" From 2812782cd385bc68bb492fc4bc83cd1b4d9a8774 Mon Sep 17 00:00:00 2001 From: Lisa Marie Maginnis Date: Thu, 26 Dec 2024 12:19:42 +0100 Subject: [PATCH 4/6] Moved allowlist init to main init, moved allowlist reload to signal SIGRTMIN+3 --- src/apps/relay/mainrelay.c | 17 ++++++++ src/server/ns_turn_ratelimit.c | 78 +++++++++++++++------------------- src/server/ns_turn_ratelimit.h | 1 + 3 files changed, 53 insertions(+), 43 deletions(-) diff --git a/src/apps/relay/mainrelay.c b/src/apps/relay/mainrelay.c index 4aeb1895e..98eefa5bf 100644 --- a/src/apps/relay/mainrelay.c +++ b/src/apps/relay/mainrelay.c @@ -285,6 +285,7 @@ static void reload_ssl_certs(evutil_socket_t sock, short events, void *args); static void shutdown_handler(evutil_socket_t sock, short events, void *args); static void drain_handler(evutil_socket_t sock, short events, void *args); +static void ratelimit_update_allowlist_handler(evutil_socket_t sock, short events, void *args); ////////////////////////////////////////////////// @@ -3353,6 +3354,12 @@ int main(int argc, char **argv) { setup_server(); + /* Init allow list if configured */ + if (turn_params.ratelimit_401_allowlist != NULL) { + ratelimit_init_allowlist_map(); + ratelimit_update_allowlist(turn_params.ratelimit_401_allowlist); + } + #if defined(WINDOWS) // TODO: implement it!!! add windows server #else @@ -3365,6 +3372,8 @@ int main(int argc, char **argv) { event_add(ev, NULL); ev = evsignal_new(turn_params.listener.event_base, SIGUSR1, drain_handler, NULL); event_add(ev, NULL); + ev = evsignal_new(turn_params.listener.event_base, SIGRTMIN+3, ratelimit_update_allowlist_handler, NULL); + event_add(ev, NULL); #endif drop_privileges(); @@ -4004,4 +4013,12 @@ static void drain_handler(evutil_socket_t sock, short events, void *args) { UNUSED_ARG(events); UNUSED_ARG(args); } + +static void ratelimit_update_allowlist_handler(evutil_socket_t sock, short events, void *args) { + TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO, "Reloading 401 ratelimit allowlist signal %d\n", sock); + ratelimit_update_allowlist(turn_params.ratelimit_401_allowlist); + + UNUSED_ARG(events); + UNUSED_ARG(args); +} /////////////////////////////// diff --git a/src/server/ns_turn_ratelimit.c b/src/server/ns_turn_ratelimit.c index 1023e2c3b..82537b5ed 100644 --- a/src/server/ns_turn_ratelimit.c +++ b/src/server/ns_turn_ratelimit.c @@ -40,7 +40,6 @@ ur_addr_map *rate_limit_map = NULL; ur_addr_map *rate_limit_allowlist_map = NULL; int ratelimit_window_secs = RATELIMIT_DEFAULT_WINDOW_SECS; -time_t last_mtime = 0; TURN_MUTEX_DECLARE(rate_limit_main_mutex); TURN_MUTEX_DECLARE(rate_limit_allowlist_mutex); @@ -68,58 +67,51 @@ void ratelimit_init_allowlist_map() { TURN_MUTEX_UNLOCK(&rate_limit_allowlist_mutex); } -int ratelimit_is_on_allowlist(const char *allowlist, ioa_addr *addr) { - /* If no allowlist provided, return early */ - if (!allowlist) { - return 0; - } - /* Init allow_list map if needed */ - if (rate_limit_allowlist_map == NULL) { - ratelimit_init_allowlist_map(); - } +void ratelimit_update_allowlist(const char *allowlist) { - /* Check the mtime of the allow list, do we need to update? */ - struct stat fstat; - if (stat(allowlist, &fstat) == 0) { - if (fstat.st_mtime != last_mtime) { - last_mtime = fstat.st_mtime; + FILE *file = NULL; + file = fopen(allowlist, "r"); + if (file != NULL) { + char line[1024]; - FILE *file = NULL; - file = fopen(allowlist, "r"); - if (file != NULL) { - char line[1024]; + /* Rebuild map */ + TURN_MUTEX_LOCK(&rate_limit_allowlist_mutex); + ur_addr_map_clean(rate_limit_allowlist_map); + ur_addr_map_init(rate_limit_allowlist_map); + TURN_MUTEX_UNLOCK(&rate_limit_allowlist_mutex); + /* loop over file and add entries */ + while (fgets(line, sizeof(line) - 1, file) != NULL) { + if (!line) { + break; + } - /* Rebuild map */ + ioa_addr new_address; + ratelimit_remove_newlines(line); + TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO, "Added address to 401 ratelimit allow list from file %s: %s\n", allowlist, line); + if(make_ioa_addr_from_full_string((const uint8_t *)line, 0, &new_address) != 0) { + TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "Malformed address in 401 ratelimit allow list file %s: %s\n", allowlist, line); + } else { TURN_MUTEX_LOCK(&rate_limit_allowlist_mutex); - ur_addr_map_clean(rate_limit_allowlist_map); - ur_addr_map_init(rate_limit_allowlist_map); + ur_addr_map_put(rate_limit_allowlist_map, &new_address, (ur_addr_map_value_type)1); TURN_MUTEX_UNLOCK(&rate_limit_allowlist_mutex); - /* loop over file and add entries */ - while (fgets(line, sizeof(line) - 1, file) != NULL) { - if (!line) { - break; - } - - ioa_addr new_address; - ratelimit_remove_newlines(line); - if(make_ioa_addr_from_full_string((const uint8_t *)line, 0, &new_address) != 0) { - TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "Malformed address in 401 ratelimit allow list file %s: %s\n", allowlist, line); - } else { - TURN_MUTEX_LOCK(&rate_limit_allowlist_mutex); - ur_addr_map_put(rate_limit_allowlist_map, &new_address, (ur_addr_map_value_type)1); - TURN_MUTEX_UNLOCK(&rate_limit_allowlist_mutex); - } - } - if (file) { - fclose(file); - } - } else { - TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "Could not open 401 ratelimit allow list file: %s\n", allowlist); } } + if (file) { + fclose(file); + } + } else { + TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "Could not open 401 ratelimit allow list file: %s\n", allowlist); + } +} + +int ratelimit_is_on_allowlist(const char *allowlist, ioa_addr *addr) { + /* If no allowlist provided, return early */ + if (!allowlist) { + return 0; } ur_addr_map_value_type ratelimit_ptr = 0; + TURN_MUTEX_LOCK(&rate_limit_allowlist_mutex); if (ur_addr_map_get(rate_limit_allowlist_map, addr, &ratelimit_ptr)) { TURN_MUTEX_UNLOCK(&rate_limit_allowlist_mutex); diff --git a/src/server/ns_turn_ratelimit.h b/src/server/ns_turn_ratelimit.h index 693fc717a..65b4135ae 100644 --- a/src/server/ns_turn_ratelimit.h +++ b/src/server/ns_turn_ratelimit.h @@ -43,6 +43,7 @@ int ratelimit_is_address_limited(ioa_addr *address, int max_requests, void ratelimit_add_node(ioa_addr *address); int ratelimit_delete_expired(ur_map_value_type value); void ratelimit_init_map(void); +void ratelimit_update_allowlist(); ////// Rate limit for 401 Unauthorized ////// #define RATELIMIT_DEFAULT_MAX_REQUESTS_PER_WINDOW 1000 From 8ec2e465905012fb0b91b132fe783720e721f77b Mon Sep 17 00:00:00 2001 From: Lisa Marie Maginnis Date: Thu, 26 Dec 2024 12:53:06 +0100 Subject: [PATCH 5/6] cleaned up ratelimit logic with a goto/label to help avoid double free() in the future --- src/server/ns_turn_ratelimit.c | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/src/server/ns_turn_ratelimit.c b/src/server/ns_turn_ratelimit.c index 82537b5ed..30f6fbed6 100644 --- a/src/server/ns_turn_ratelimit.c +++ b/src/server/ns_turn_ratelimit.c @@ -169,6 +169,7 @@ int ratelimit_is_address_limited(ioa_addr *address, int max_requests, int window ioa_addr *address_new = (ioa_addr *)malloc(sizeof(ioa_addr)); *address_new = *address; addr_set_port(address_new, 0); + int retval = 0; if (ur_addr_map_get(rate_limit_map, address_new, &ratelimit_ptr)) { ratelimit_entry *rateLimitEntry = (ratelimit_entry *)(void *)(ur_map_value_type)ratelimit_ptr; @@ -178,32 +179,32 @@ int ratelimit_is_address_limited(ioa_addr *address, int max_requests, int window /* Check if request is inside the ratelimit window; reset the count and request time */ rateLimitEntry->request_count = 1; rateLimitEntry->last_request_time = current_time; - TURN_MUTEX_UNLOCK(&(rateLimitEntry->mutex)); - free(address_new); - return 0; + retval = 0; + goto end_ratelimit_entry; } else if (rateLimitEntry->request_count < max_requests) { /* Check if request count is below requests per window; increment the count */ if (rateLimitEntry->request_count < UINT32_MAX) rateLimitEntry->request_count++; rateLimitEntry->last_request_time = current_time; - TURN_MUTEX_UNLOCK(&(rateLimitEntry->mutex)); - free(address_new); - return 0; + retval = 0; + goto end_ratelimit_entry; } else { /* Before ratelimit, check allow list */ if(ratelimit_is_on_allowlist(allowlist, address_new)) { - free(address_new); - TURN_MUTEX_UNLOCK(&(rateLimitEntry->mutex)); - return 0; + retval = 0; + goto end_ratelimit_entry; } - free(address_new); /* Request is outside of defined window and count, request is ratelimited */ if (rateLimitEntry->request_count < UINT32_MAX) rateLimitEntry->request_count++; rateLimitEntry->last_request_time = current_time; + retval = 1; + + end_ratelimit_entry: TURN_MUTEX_UNLOCK(&(rateLimitEntry->mutex)); - return 1; + free(address_new); + return retval; } } else { // New entry, allow response From 78cef27634feb179375f96c53d8237a72293335a Mon Sep 17 00:00:00 2001 From: Lisa Marie Maginnis Date: Thu, 26 Dec 2024 12:55:38 +0100 Subject: [PATCH 6/6] cleaned up ratelimit logic with a goto/label to help avoid double free() in the future --- src/server/ns_turn_ratelimit.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/server/ns_turn_ratelimit.c b/src/server/ns_turn_ratelimit.c index 30f6fbed6..fc4cd0a5b 100644 --- a/src/server/ns_turn_ratelimit.c +++ b/src/server/ns_turn_ratelimit.c @@ -212,6 +212,7 @@ int ratelimit_is_address_limited(ioa_addr *address, int max_requests, int window ratelimit_add_node(address_new); free(address_new); TURN_MUTEX_UNLOCK(&rate_limit_main_mutex); - return 0; + retval = 0; } + return retval; }