Skip to content

Commit

Permalink
First Draft
Browse files Browse the repository at this point in the history
  • Loading branch information
e-lisa committed Nov 12, 2024
1 parent 78d6cf3 commit 509835f
Show file tree
Hide file tree
Showing 7 changed files with 122 additions and 10 deletions.
12 changes: 9 additions & 3 deletions src/apps/relay/mainrelay.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 //////////////////////
Expand Down Expand Up @@ -1476,9 +1477,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 {
Expand Down Expand Up @@ -1633,6 +1634,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[] = {
Expand Down Expand Up @@ -2397,6 +2399,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:
Expand Down
1 change: 1 addition & 0 deletions src/apps/relay/mainrelay.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
3 changes: 2 additions & 1 deletion src/apps/relay/netengine.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
102 changes: 100 additions & 2 deletions src/server/ns_turn_ratelimit.c
Original file line number Diff line number Diff line change
Expand Up @@ -28,15 +28,105 @@
* SUCH DAMAGE.
*/

#include <sys/stat.h>

#include "ns_turn_maps.h"
#include "ns_turn_ioalib.h"
#include "ns_turn_ratelimit.h"

/////////////////// 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) {
TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO, "no list\n");
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 */
// ur_addr_map_clean(rate_limit_allowlist_map);
// ratelimit_init_allowlist_map();

/* 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
addr_set_port(&new_address, 0);{
ur_addr_map_put(rate_limit_allowlist_map, &new_address, (ur_addr_map_value_type)0);
}
}

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;
ur_addr_map_put(rate_limit_allowlist_map, addr, (ur_addr_map_value_type)0);
if (ur_addr_map_get(rate_limit_allowlist_map, addr, &ratelimit_ptr)) {
TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO, "FOUND\n");
return 1;
} else {
TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO, "NOT FOUND\n");
return 0;
}
}

void ratelimit_add_node(ioa_addr *address) {
// copy address
Expand All @@ -63,7 +153,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();

Expand All @@ -87,7 +177,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));

Expand All @@ -96,15 +185,24 @@ 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 */
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;
} else {
/* Before ratelimit, check allow list */
if(ratelimit_is_on_allowlist(allowlist, 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++;
Expand Down
3 changes: 2 additions & 1 deletion src/server/ns_turn_ratelimit.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
7 changes: 5 additions & 2 deletions src/server/ns_turn_server.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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) {
Expand Down
4 changes: 3 additions & 1 deletion src/server/ns_turn_server.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -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);

Expand Down

0 comments on commit 509835f

Please sign in to comment.