Skip to content

Commit 961b576

Browse files
authored
Optionally support X-Forwarded-For in both HTTP and WebSocket transports (fixes #3158) (#3160)
1 parent 51a4c9f commit 961b576

4 files changed

+56
-0
lines changed

conf/janus.transport.http.jcfg.sample

+4
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@ general: {
2020
#secure_interface = "eth0" # Whether we should bind this server to a specific interface only
2121
#secure_ip = "192.168.0.1" # Whether we should bind this server to a specific IP address (v4 or v6) only
2222
#acl = "127.,192.168.0." # Only allow requests coming from this comma separated list of addresses
23+
#acl_forwarded = true # Whether we should check the X-Forwarded-For header too for the ACL
24+
# (default=false, since without a proxy in the middle this could be abused)
2325
#mhd_connection_limit = 1020 # Open connections limit in libmicrohttpd (default=1020)
2426
#mhd_debug = false # Ask libmicrohttpd to write warning and error messages to stderr (default=false)
2527
}
@@ -46,6 +48,8 @@ admin: {
4648
#admin_secure_interface = "eth0" # Whether we should bind this server to a specific interface only
4749
#admin_secure_ip = "192.168.0.1" # Whether we should bind this server to a specific IP address (v4 or v6) only
4850
#admin_acl = "127.,192.168.0." # Only allow requests coming from this comma separated list of addresses
51+
#admin_acl_forwarded = true # Whether we should check the X-Forwarded-For header too for the admin ACL
52+
# (default=false, since without a proxy in the middle this could be abused)
4953
}
5054

5155
# The HTTP servers created in Janus support CORS out of the box, but by

conf/janus.transport.websockets.jcfg.sample

+4
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@ general: {
2121
# to debug, supported values: err, warn, notice, info, debug, parser,
2222
# header, ext, client, latency, user, count (plus 'none' and 'all')
2323
#ws_acl = "127.,192.168.0." # Only allow requests coming from this comma separated list of addresses
24+
#ws_acl_forwarded = true # Whether we should check the X-Forwarded-For header too for the ACL
25+
# (default=false, since without a proxy in the middle this could be abused)
2426
}
2527

2628
# If you want to expose the Admin API via WebSockets as well, you need to
@@ -39,6 +41,8 @@ admin: {
3941
#admin_wss_ip = "192.168.0.1" # Whether we should bind this server to a specific IP address only
4042
#admin_wss_unix = "/run/awss.sock" # Use WebSocket server over UNIX socket instead of TCP
4143
#admin_ws_acl = "127.,192.168.0." # Only allow requests coming from this comma separated list of addresses
44+
#admin_ws_acl_forwarded = true # Whether we should check the X-Forwarded-For header too for the ACL
45+
# (default=false, since without a proxy in the middle this could be abused)
4246
}
4347

4448
# The HTTP servers created in Janus support CORS out of the box, but by

src/transports/janus_http.c

+27
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,7 @@ typedef struct janus_http_msg {
149149
char *acro; /* Value of the Origin HTTP header, if any (needed for CORS) */
150150
char *acrh; /* Value of the Access-Control-Request-Headers HTTP header, if any (needed for CORS) */
151151
char *acrm; /* Value of the Access-Control-Request-Method HTTP header, if any (needed for CORS) */
152+
char *xff; /* Value of the X-Forwarded-For HTTP header, if any */
152153
char *contenttype; /* Content-Type of the payload */
153154
char *payload; /* Payload of the message */
154155
size_t len; /* Length of the message in octets */
@@ -173,6 +174,7 @@ static void janus_http_msg_free(const janus_refcount *msg_ref) {
173174
g_free(request->acro);
174175
g_free(request->acrh);
175176
g_free(request->acrm);
177+
g_free(request->xff);
176178
g_free(request->response);
177179
g_free(request);
178180
}
@@ -303,6 +305,7 @@ static gboolean enforce_cors = FALSE;
303305

304306
/* REST and Admin/Monitor ACL list */
305307
static GList *janus_http_access_list = NULL, *janus_http_admin_access_list = NULL;
308+
static gboolean janus_http_check_xff = FALSE, janus_http_admin_check_xff = FALSE;
306309
static janus_mutex access_list_mutex;
307310
static void janus_http_allow_address(const char *ip, gboolean admin) {
308311
if(ip == NULL)
@@ -736,6 +739,10 @@ int janus_http_init(janus_transport_callbacks *callback, const char *config_path
736739
}
737740
g_strfreev(list);
738741
list = NULL;
742+
/* Check if we should use the value of X-Forwarded-For for checks too */
743+
item = janus_config_get(config, config_general, janus_config_type_item, "acl_forwarded");
744+
if(item && item->value)
745+
janus_http_check_xff = janus_is_true(item->value);
739746
}
740747
item = janus_config_get(config, config_admin, janus_config_type_item, "admin_acl");
741748
if(item && item->value) {
@@ -754,6 +761,10 @@ int janus_http_init(janus_transport_callbacks *callback, const char *config_path
754761
}
755762
g_strfreev(list);
756763
list = NULL;
764+
/* Check if we should use the value of X-Forwarded-For for checks too */
765+
item = janus_config_get(config, config_general, janus_config_type_item, "admin_acl_forwarded");
766+
if(item && item->value)
767+
janus_http_admin_check_xff = janus_is_true(item->value);
757768
}
758769

759770
/* Any custom value for the Access-Control-Allow-Origin header? */
@@ -1375,6 +1386,13 @@ static MHD_Result janus_http_handler(void *cls, struct MHD_Connection *connectio
13751386
janus_mutex_unlock(&messages_mutex);
13761387
*ptr = ts;
13771388
MHD_get_connection_values(connection, MHD_HEADER_KIND, &janus_http_headers, msg);
1389+
if(janus_http_check_xff && msg->xff) {
1390+
/* Any access limitation based on this IP address? */
1391+
if(!janus_http_is_allowed(msg->xff, FALSE)) {
1392+
JANUS_LOG(LOG_ERR, "IP %s is unauthorized to connect to the Janus API interface\n", msg->xff);
1393+
return MHD_NO;
1394+
}
1395+
}
13781396
ret = MHD_YES;
13791397
/* Notify handlers about this new transport instance */
13801398
if(notify_events && gateway->events_is_enabled()) {
@@ -1773,6 +1791,13 @@ static MHD_Result janus_http_admin_handler(void *cls, struct MHD_Connection *con
17731791
janus_mutex_unlock(&messages_mutex);
17741792
*ptr = ts;
17751793
MHD_get_connection_values(connection, MHD_HEADER_KIND, &janus_http_headers, msg);
1794+
if(janus_http_admin_check_xff && msg->xff) {
1795+
/* Any access limitation based on this IP address? */
1796+
if(!janus_http_is_allowed(msg->xff, TRUE)) {
1797+
JANUS_LOG(LOG_ERR, "IP %s is unauthorized to connect to the Janus API interface\n", msg->xff);
1798+
return MHD_NO;
1799+
}
1800+
}
17761801
ret = MHD_YES;
17771802
/* Notify handlers about this new transport instance */
17781803
if(notify_events && gateway->events_is_enabled()) {
@@ -2011,6 +2036,8 @@ static MHD_Result janus_http_headers(void *cls, enum MHD_ValueKind kind, const c
20112036
request->acrm = g_strdup(value);
20122037
} else if(!strcasecmp(key, "Access-Control-Request-Headers")) {
20132038
request->acrh = g_strdup(value);
2039+
} else if(!strcasecmp(key, "X-Forwarded-For")) {
2040+
request->xff = g_strdup(value);
20142041
}
20152042
janus_refcount_decrease(&request->ref);
20162043
return MHD_YES;

src/transports/janus_websockets.c

+21
Original file line numberDiff line numberDiff line change
@@ -332,6 +332,7 @@ static gboolean enforce_cors = FALSE;
332332

333333
/* WebSockets ACL list for both Janus and Admin API */
334334
static GList *janus_websockets_access_list = NULL, *janus_websockets_admin_access_list = NULL;
335+
static gboolean janus_websockets_check_xff = FALSE, janus_websockets_admin_check_xff = FALSE;
335336
static janus_mutex access_list_mutex;
336337
static void janus_websockets_allow_address(const char *ip, gboolean admin) {
337338
if(ip == NULL)
@@ -649,6 +650,10 @@ int janus_websockets_init(janus_transport_callbacks *callback, const char *confi
649650
}
650651
g_strfreev(list);
651652
list = NULL;
653+
/* Check if we should use the value of X-Forwarded-For for checks too */
654+
item = janus_config_get(config, config_general, janus_config_type_item, "ws_acl_forwarded");
655+
if(item && item->value)
656+
janus_websockets_check_xff = janus_is_true(item->value);
652657
}
653658
item = janus_config_get(config, config_admin, janus_config_type_item, "admin_ws_acl");
654659
if(item && item->value) {
@@ -667,6 +672,10 @@ int janus_websockets_init(janus_transport_callbacks *callback, const char *confi
667672
}
668673
g_strfreev(list);
669674
list = NULL;
675+
/* Check if we should use the value of X-Forwarded-For for checks too */
676+
item = janus_config_get(config, config_general, janus_config_type_item, "admin_ws_acl_forwarded");
677+
if(item && item->value)
678+
janus_websockets_admin_check_xff = janus_is_true(item->value);
670679
}
671680

672681
/* Any custom value for the Access-Control-Allow-Origin header? */
@@ -1183,6 +1192,18 @@ static int janus_websockets_common_callback(
11831192
lws_callback_on_writable(wsi);
11841193
return -1;
11851194
}
1195+
/* Check if an X-Forwarded-For header was provided */
1196+
char xff[1024] = {0};
1197+
if(lws_hdr_copy(wsi, xff, 1023, WSI_TOKEN_X_FORWARDED_FOR) > 0) {
1198+
/* If the ACL is enabled, are we supposed to use this header too for checks? */
1199+
if(((!admin && janus_websockets_check_xff) || (admin && janus_websockets_admin_check_xff)) && !janus_websockets_is_allowed(xff, admin)) {
1200+
JANUS_LOG(LOG_ERR, "[%s-%p] IP %s is unauthorized to connect to the WebSockets %s API interface\n",
1201+
log_prefix, wsi, xff, admin ? "Admin" : "Janus");
1202+
/* Close the connection */
1203+
lws_callback_on_writable(wsi);
1204+
return -1;
1205+
}
1206+
}
11861207
JANUS_LOG(LOG_VERB, "[%s-%p] WebSocket connection accepted\n", log_prefix, wsi);
11871208
if(ws_client == NULL) {
11881209
JANUS_LOG(LOG_ERR, "[%s-%p] Invalid WebSocket client instance...\n", log_prefix, wsi);

0 commit comments

Comments
 (0)