Skip to content

Commit 9d52c19

Browse files
committed
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.
1 parent 78d6cf3 commit 9d52c19

File tree

9 files changed

+125
-11
lines changed

9 files changed

+125
-11
lines changed

README.turnserver

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -682,6 +682,8 @@ Options with values:
682682
Defaults is 1000.
683683
--401-window=<seconds> Set the time window duration in seconds for rate limiting 401 Unauthorized responses.
684684
Defaults is 120.
685+
--401-allowlist=<filename> Set the path of the allow-list, one IP per line allowed to bypass the 401 rate-limit settings.
686+
Default is none.
685687

686688

687689
==================================

src/apps/relay/mainrelay.c

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -251,7 +251,8 @@ turn_params_t turn_params = {
251251

252252
///////// Ratelimt /////////
253253
RATELIMIT_DEFAULT_MAX_REQUESTS_PER_WINDOW, /* 401-req-limit */
254-
RATELIMIT_DEFAULT_WINDOW_SECS /* 401-window */
254+
RATELIMIT_DEFAULT_WINDOW_SECS, /* 401-window */
255+
NULL /* 401-allowlist */
255256
};
256257

257258
//////////////// OpenSSL Init //////////////////////
@@ -1311,6 +1312,8 @@ static char Usage[] =
13111312
" per rate-limiting window. If set to 0 disables rate limiting. Default is 1000.\n"
13121313
" --401-window=<seconds>\t\t\t\tSet the time window duration in seconds for rate limiting 401 Unauthorized responses.\n"
13131314
" Default is 120.\n"
1315+
" --401-allowlist=<filename>\t\t\tSet the path of the allow-list, one IP per line allowed to bypass the 401\n"
1316+
" rate-limit settings. Default is none.\n"
13141317
" --version Print version (and exit).\n"
13151318
" -h Help\n"
13161319
"\n";
@@ -1476,9 +1479,9 @@ enum EXTRA_OPTS {
14761479
FEDERATION_PKEY_OPT,
14771480
FEDERATION_PKEY_PWD_OPT,
14781481
FEDERATION_REMOTE_WHITELIST_OPT,
1479-
RATELIMIT_OPT,
14801482
RATELIMIT_REQUESTS_OPT,
1481-
RATELIMIT_WINDOW_OPT
1483+
RATELIMIT_WINDOW_OPT,
1484+
RATELIMIT_ALLOWLIST_OPT
14821485
};
14831486

14841487
struct myoption {
@@ -1633,6 +1636,7 @@ static const struct myoption long_options[] = {
16331636
{"syslog-facility", required_argument, NULL, SYSLOG_FACILITY_OPT},
16341637
{"401-req-limit", optional_argument, NULL, RATELIMIT_REQUESTS_OPT},
16351638
{"401-window", optional_argument, NULL, RATELIMIT_WINDOW_OPT},
1639+
{"401-allowlist", optional_argument, NULL, RATELIMIT_ALLOWLIST_OPT},
16361640
{NULL, no_argument, NULL, 0}};
16371641

16381642
static const struct myoption admin_long_options[] = {
@@ -2397,6 +2401,10 @@ static void set_option(int c, char *value) {
23972401
turn_params.ratelimit_401_window_seconds = get_int_value(value, RATELIMIT_DEFAULT_WINDOW_SECS);
23982402
TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO, "Setting 401 ratelimit window to: %i seconds\n", turn_params.ratelimit_401_window_seconds);
23992403
break;
2404+
case RATELIMIT_ALLOWLIST_OPT:
2405+
STRCPY(turn_params.ratelimit_401_allowlist, value);
2406+
TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO, "Setting 401 ratelimit allow list to: %s\n", turn_params.ratelimit_401_allowlist);
2407+
break;
24002408
/* these options have been already taken care of before: */
24012409
case 'l':
24022410
case NO_STDOUT_LOG_OPT:

src/apps/relay/mainrelay.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -354,6 +354,7 @@ typedef struct _turn_params_ {
354354

355355
vint ratelimit_401_requests_per_window;
356356
vint ratelimit_401_window_seconds;
357+
char ratelimit_401_allowlist[1025];
357358
} turn_params_t;
358359

359360
extern turn_params_t turn_params;

src/apps/relay/netengine.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1696,7 +1696,8 @@ static void setup_relay_server(struct relay_server *rs, ioa_engine_handle e, int
16961696
turn_params.oauth_server_name, turn_params.acme_redirect,
16971697
turn_params.allocation_default_address_family, &turn_params.log_binding,
16981698
&turn_params.no_stun_backward_compatibility, &turn_params.response_origin_only_with_rfc5780,
1699-
&turn_params.ratelimit_401_requests_per_window, &turn_params.ratelimit_401_window_seconds);
1699+
&turn_params.ratelimit_401_requests_per_window, &turn_params.ratelimit_401_window_seconds,
1700+
&turn_params.ratelimit_401_allowlist);
17001701

17011702

17021703
// Intentionally performed outside init_turn_server to help avoid future merge conflicts

src/ns_turn_defs.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@
3131
#ifndef __IOADEFS__
3232
#define __IOADEFS__
3333

34-
#define TURN_SERVER_VERSION "wireapp/4.6.2f"
34+
#define TURN_SERVER_VERSION "wireapp/4.6.2g"
3535
#define TURN_SERVER_VERSION_NAME "Gorst"
3636
#ifndef TURN_SERVER_BUILD_INFO
3737
#define TURN_SERVER_BUILD_INFO ""

src/server/ns_turn_ratelimit.c

Lines changed: 98 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,15 +28,102 @@
2828
* SUCH DAMAGE.
2929
*/
3030

31+
#include <sys/stat.h>
32+
3133
#include "ns_turn_maps.h"
3234
#include "ns_turn_ioalib.h"
3335
#include "ns_turn_ratelimit.h"
3436

3537
/////////////////// rate limit //////////////////////////
3638

3739
ur_addr_map *rate_limit_map = NULL;
40+
ur_addr_map *rate_limit_allowlist_map = NULL;
41+
3842
int ratelimit_window_secs = RATELIMIT_DEFAULT_WINDOW_SECS;
43+
time_t last_mtime = 0;
44+
3945
TURN_MUTEX_DECLARE(rate_limit_main_mutex);
46+
TURN_MUTEX_DECLARE(rate_limit_allowlist_mutex);
47+
48+
void ratelimit_remove_newlines(char *str) {
49+
char *src = str;
50+
char *dst = str;
51+
52+
while (*src != '\0') {
53+
if (*src != '\r' && *src != '\n') {
54+
*dst++ = *src;
55+
}
56+
src++;
57+
}
58+
*dst = '\0';
59+
}
60+
61+
void ratelimit_init_allowlist_map() {
62+
TURN_MUTEX_INIT(&rate_limit_allowlist_mutex);
63+
TURN_MUTEX_LOCK(&rate_limit_allowlist_mutex);
64+
65+
rate_limit_allowlist_map = (ur_addr_map*)malloc(sizeof(ur_addr_map));
66+
ur_addr_map_init(rate_limit_allowlist_map);
67+
68+
TURN_MUTEX_UNLOCK(&rate_limit_allowlist_mutex);
69+
}
70+
71+
int ratelimit_is_on_allowlist(const char *allowlist, ioa_addr *addr) {
72+
/* If no allowlist provided, return early */
73+
if (!allowlist) {
74+
return 0;
75+
}
76+
/* Init allow_list map if needed */
77+
if (rate_limit_allowlist_map == NULL) {
78+
ratelimit_init_allowlist_map();
79+
}
80+
81+
/* Check the mtime of the allow list, do we need to update? */
82+
struct stat fstat;
83+
if (stat(allowlist, &fstat) == 0) {
84+
if (fstat.st_mtime != last_mtime) {
85+
last_mtime = fstat.st_mtime;
86+
87+
FILE *file = NULL;
88+
file = fopen(allowlist, "r");
89+
if (file != NULL) {
90+
char line[1024];
91+
92+
/* Rebuild map */
93+
ur_addr_map_clean(rate_limit_allowlist_map);
94+
ur_addr_map_init(rate_limit_allowlist_map);
95+
96+
/* loop over file and add entries */
97+
while (fgets(line, sizeof(line) - 1, file) != NULL) {
98+
if (!line) {
99+
break;
100+
}
101+
102+
ioa_addr new_address;
103+
ratelimit_remove_newlines(line);
104+
if(make_ioa_addr_from_full_string((const uint8_t *)line, 0, &new_address) != 0) {
105+
TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "Malformed address in 401 ratelimit allow list file %s: %s\n", allowlist, line);
106+
} else {
107+
ur_addr_map_put(rate_limit_allowlist_map, &new_address, (ur_addr_map_value_type)1);
108+
}
109+
}
110+
111+
if (file) {
112+
fclose(file);
113+
}
114+
} else {
115+
TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "Could not open 401 ratelimit allow list file: %s\n", allowlist);
116+
}
117+
}
118+
}
119+
120+
ur_addr_map_value_type ratelimit_ptr = 0;
121+
if (ur_addr_map_get(rate_limit_allowlist_map, addr, &ratelimit_ptr)) {
122+
return 1;
123+
} else {
124+
return 0;
125+
}
126+
}
40127

41128
void ratelimit_add_node(ioa_addr *address) {
42129
// copy address
@@ -63,7 +150,7 @@ void ratelimit_init_map() {
63150
TURN_MUTEX_UNLOCK(&rate_limit_main_mutex);
64151
}
65152

66-
int ratelimit_is_address_limited(ioa_addr *address, int max_requests, int window_seconds) {
153+
int ratelimit_is_address_limited(ioa_addr *address, int max_requests, int window_seconds, const char *allowlist) {
67154
/* Housekeeping, prune the map when ADDR_MAP_SIZE is hit and delete expired items */
68155
turn_time_t current_time = turn_time();
69156

@@ -87,7 +174,6 @@ int ratelimit_is_address_limited(ioa_addr *address, int max_requests, int window
87174
addr_set_port(address_new, 0);
88175

89176
if (ur_addr_map_get(rate_limit_map, address_new, &ratelimit_ptr)) {
90-
free(address_new);
91177
ratelimit_entry *rateLimitEntry = (ratelimit_entry *)(void *)(ur_map_value_type)ratelimit_ptr;
92178
TURN_MUTEX_LOCK(&(rateLimitEntry->mutex));
93179

@@ -96,15 +182,25 @@ int ratelimit_is_address_limited(ioa_addr *address, int max_requests, int window
96182
rateLimitEntry->request_count = 1;
97183
rateLimitEntry->last_request_time = current_time;
98184
TURN_MUTEX_UNLOCK(&(rateLimitEntry->mutex));
185+
free(address_new);
99186
return 0;
100187
} else if (rateLimitEntry->request_count < max_requests) {
101188
/* Check if request count is below requests per window; increment the count */
102189
if (rateLimitEntry->request_count < UINT32_MAX)
103190
rateLimitEntry->request_count++;
104191
rateLimitEntry->last_request_time = current_time;
105192
TURN_MUTEX_UNLOCK(&(rateLimitEntry->mutex));
193+
free(address_new);
106194
return 0;
107195
} else {
196+
/* Before ratelimit, check allow list */
197+
if(ratelimit_is_on_allowlist(allowlist, address_new)) {
198+
free(address_new);
199+
TURN_MUTEX_UNLOCK(&(rateLimitEntry->mutex));
200+
return 0;
201+
}
202+
203+
free(address_new);
108204
/* Request is outside of defined window and count, request is ratelimited */
109205
if (rateLimitEntry->request_count < UINT32_MAX)
110206
rateLimitEntry->request_count++;

src/server/ns_turn_ratelimit.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,8 @@
3838
extern "C" {
3939
#endif
4040

41-
int ratelimit_is_address_limited(ioa_addr *address, int max_requests, int window_seconds);
41+
int ratelimit_is_address_limited(ioa_addr *address, int max_requests,
42+
int window_seconds, const char *allowlist);
4243
void ratelimit_add_node(ioa_addr *address);
4344
int ratelimit_delete_expired(ur_map_value_type value);
4445
void ratelimit_init_map(void);

src/server/ns_turn_server.c

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3921,7 +3921,8 @@ static int handle_turn_command(turn_turnserver *server, ts_ur_super_session *ss,
39213921
}
39223922
if(err_code == 401 && *server->ratelimit_401_requests_per_window > 0) {
39233923
ioa_addr *rate_limit_address = get_remote_addr_from_ioa_socket(ss->client_socket);
3924-
if (ratelimit_is_address_limited(rate_limit_address, *server->ratelimit_401_requests_per_window, *server->ratelimit_401_window_seconds)) {
3924+
if (ratelimit_is_address_limited(rate_limit_address, *server->ratelimit_401_requests_per_window,
3925+
*server->ratelimit_401_window_seconds, server->ratelimit_401_allowlist)) {
39253926
no_response = 1;
39263927
char raddr[129];
39273928
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
49294930
const char *acme_redirect, ALLOCATION_DEFAULT_ADDRESS_FAMILY allocation_default_address_family,
49304931
vintp log_binding, vintp no_stun_backward_compatibility,
49314932
vintp response_origin_only_with_rfc5780,
4932-
vintp ratelimit_401_requests_per_window, vintp ratelimit_401_window_seconds) {
4933+
vintp ratelimit_401_requests_per_window, vintp ratelimit_401_window_seconds,
4934+
const char *ratelimit_401_allowlist) {
49334935

49344936
if (!server)
49354937
return;
@@ -5011,6 +5013,7 @@ void init_turn_server(turn_turnserver *server, turnserver_id id, int verbose, io
50115013
server->is_draining = 0;
50125014
server->ratelimit_401_requests_per_window = ratelimit_401_requests_per_window;
50135015
server->ratelimit_401_window_seconds = ratelimit_401_window_seconds;
5016+
server->ratelimit_401_allowlist = ratelimit_401_allowlist;
50145017
}
50155018

50165019
ioa_engine_handle turn_server_get_engine(turn_turnserver *s) {

src/server/ns_turn_server.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -212,6 +212,7 @@ struct _turn_turnserver {
212212

213213
vintp ratelimit_401_requests_per_window;
214214
vintp ratelimit_401_window_seconds;
215+
const char *ratelimit_401_allowlist;
215216
};
216217

217218
const char *get_version(turn_turnserver *server);
@@ -234,7 +235,8 @@ void init_turn_server(turn_turnserver *server, turnserver_id id, int verbose, io
234235
allocate_bps_cb allocate_bps_func, int oauth, const char *oauth_server_name,
235236
const char *acme_redirect, ALLOCATION_DEFAULT_ADDRESS_FAMILY allocation_default_address_family,
236237
vintp log_binding, vintp no_stun_backward_compatibility, vintp response_origin_only_with_rfc5780,
237-
vintp ratelimit_401_requests_per_window, vintp ratelimit_401_window_seconds);
238+
vintp ratelimit_401_requests_per_window, vintp ratelimit_401_window_seconds,
239+
const char *ratelimit_401_allowlist);
238240

239241
ioa_engine_handle turn_server_get_engine(turn_turnserver *s);
240242

0 commit comments

Comments
 (0)