Skip to content

Commit

Permalink
Optionally support X-Forwarded-For in both HTTP and WebSocket transpo…
Browse files Browse the repository at this point in the history
…rts (see #3160)
  • Loading branch information
lminiero committed Feb 14, 2023
1 parent 54f96c1 commit c0ea280
Show file tree
Hide file tree
Showing 4 changed files with 56 additions and 0 deletions.
4 changes: 4 additions & 0 deletions conf/janus.transport.http.jcfg.sample
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ general: {
#secure_interface = "eth0" # Whether we should bind this server to a specific interface only
#secure_ip = "192.168.0.1" # Whether we should bind this server to a specific IP address (v4 or v6) only
#acl = "127.,192.168.0." # Only allow requests coming from this comma separated list of addresses
#acl_forwarded = true # Whether we should check the X-Forwarded-For header too for the ACL
# (default=false, since without a proxy in the middle this could be abused)
#mhd_connection_limit = 1020 # Open connections limit in libmicrohttpd (default=1020)
#mhd_debug = false # Ask libmicrohttpd to write warning and error messages to stderr (default=false)
}
Expand All @@ -46,6 +48,8 @@ admin: {
#admin_secure_interface = "eth0" # Whether we should bind this server to a specific interface only
#admin_secure_ip = "192.168.0.1" # Whether we should bind this server to a specific IP address (v4 or v6) only
#admin_acl = "127.,192.168.0." # Only allow requests coming from this comma separated list of addresses
#admin_acl_forwarded = true # Whether we should check the X-Forwarded-For header too for the admin ACL
# (default=false, since without a proxy in the middle this could be abused)
}

# The HTTP servers created in Janus support CORS out of the box, but by
Expand Down
4 changes: 4 additions & 0 deletions conf/janus.transport.websockets.jcfg.sample
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ general: {
# to debug, supported values: err, warn, notice, info, debug, parser,
# header, ext, client, latency, user, count (plus 'none' and 'all')
#ws_acl = "127.,192.168.0." # Only allow requests coming from this comma separated list of addresses
#ws_acl_forwarded = true # Whether we should check the X-Forwarded-For header too for the ACL
# (default=false, since without a proxy in the middle this could be abused)
}

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

# The HTTP servers created in Janus support CORS out of the box, but by
Expand Down
27 changes: 27 additions & 0 deletions transports/janus_http.c
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,7 @@ typedef struct janus_http_msg {
char *acro; /* Value of the Origin HTTP header, if any (needed for CORS) */
char *acrh; /* Value of the Access-Control-Request-Headers HTTP header, if any (needed for CORS) */
char *acrm; /* Value of the Access-Control-Request-Method HTTP header, if any (needed for CORS) */
char *xff; /* Value of the X-Forwarded-For HTTP header, if any */
char *contenttype; /* Content-Type of the payload */
char *payload; /* Payload of the message */
size_t len; /* Length of the message in octets */
Expand All @@ -173,6 +174,7 @@ static void janus_http_msg_free(const janus_refcount *msg_ref) {
g_free(request->acro);
g_free(request->acrh);
g_free(request->acrm);
g_free(request->xff);
g_free(request->response);
g_free(request);
}
Expand Down Expand Up @@ -303,6 +305,7 @@ static gboolean enforce_cors = FALSE;

/* REST and Admin/Monitor ACL list */
static GList *janus_http_access_list = NULL, *janus_http_admin_access_list = NULL;
static gboolean janus_http_check_xff = FALSE, janus_http_admin_check_xff = FALSE;
static janus_mutex access_list_mutex;
static void janus_http_allow_address(const char *ip, gboolean admin) {
if(ip == NULL)
Expand Down Expand Up @@ -736,6 +739,10 @@ int janus_http_init(janus_transport_callbacks *callback, const char *config_path
}
g_strfreev(list);
list = NULL;
/* Check if we should use the value of X-Forwarded-For for checks too */
item = janus_config_get(config, config_general, janus_config_type_item, "acl_forwarded");
if(item && item->value)
janus_http_check_xff = janus_is_true(item->value);
}
item = janus_config_get(config, config_admin, janus_config_type_item, "admin_acl");
if(item && item->value) {
Expand All @@ -754,6 +761,10 @@ int janus_http_init(janus_transport_callbacks *callback, const char *config_path
}
g_strfreev(list);
list = NULL;
/* Check if we should use the value of X-Forwarded-For for checks too */
item = janus_config_get(config, config_general, janus_config_type_item, "admin_acl_forwarded");
if(item && item->value)
janus_http_admin_check_xff = janus_is_true(item->value);
}

/* Any custom value for the Access-Control-Allow-Origin header? */
Expand Down Expand Up @@ -1375,6 +1386,13 @@ static MHD_Result janus_http_handler(void *cls, struct MHD_Connection *connectio
janus_mutex_unlock(&messages_mutex);
*ptr = ts;
MHD_get_connection_values(connection, MHD_HEADER_KIND, &janus_http_headers, msg);
if(janus_http_check_xff && msg->xff) {
/* Any access limitation based on this IP address? */
if(!janus_http_is_allowed(msg->xff, FALSE)) {
JANUS_LOG(LOG_ERR, "IP %s is unauthorized to connect to the Janus API interface\n", msg->xff);
return MHD_NO;
}
}
ret = MHD_YES;
/* Notify handlers about this new transport instance */
if(notify_events && gateway->events_is_enabled()) {
Expand Down Expand Up @@ -1773,6 +1791,13 @@ static MHD_Result janus_http_admin_handler(void *cls, struct MHD_Connection *con
janus_mutex_unlock(&messages_mutex);
*ptr = ts;
MHD_get_connection_values(connection, MHD_HEADER_KIND, &janus_http_headers, msg);
if(janus_http_admin_check_xff && msg->xff) {
/* Any access limitation based on this IP address? */
if(!janus_http_is_allowed(msg->xff, TRUE)) {
JANUS_LOG(LOG_ERR, "IP %s is unauthorized to connect to the Janus API interface\n", msg->xff);
return MHD_NO;
}
}
ret = MHD_YES;
/* Notify handlers about this new transport instance */
if(notify_events && gateway->events_is_enabled()) {
Expand Down Expand Up @@ -2011,6 +2036,8 @@ static MHD_Result janus_http_headers(void *cls, enum MHD_ValueKind kind, const c
request->acrm = g_strdup(value);
} else if(!strcasecmp(key, "Access-Control-Request-Headers")) {
request->acrh = g_strdup(value);
} else if(!strcasecmp(key, "X-Forwarded-For")) {
request->xff = g_strdup(value);
}
janus_refcount_decrease(&request->ref);
return MHD_YES;
Expand Down
21 changes: 21 additions & 0 deletions transports/janus_websockets.c
Original file line number Diff line number Diff line change
Expand Up @@ -332,6 +332,7 @@ static gboolean enforce_cors = FALSE;

/* WebSockets ACL list for both Janus and Admin API */
static GList *janus_websockets_access_list = NULL, *janus_websockets_admin_access_list = NULL;
static gboolean janus_websockets_check_xff = FALSE, janus_websockets_admin_check_xff = FALSE;
static janus_mutex access_list_mutex;
static void janus_websockets_allow_address(const char *ip, gboolean admin) {
if(ip == NULL)
Expand Down Expand Up @@ -649,6 +650,10 @@ int janus_websockets_init(janus_transport_callbacks *callback, const char *confi
}
g_strfreev(list);
list = NULL;
/* Check if we should use the value of X-Forwarded-For for checks too */
item = janus_config_get(config, config_general, janus_config_type_item, "ws_acl_forwarded");
if(item && item->value)
janus_websockets_check_xff = janus_is_true(item->value);
}
item = janus_config_get(config, config_admin, janus_config_type_item, "admin_ws_acl");
if(item && item->value) {
Expand All @@ -667,6 +672,10 @@ int janus_websockets_init(janus_transport_callbacks *callback, const char *confi
}
g_strfreev(list);
list = NULL;
/* Check if we should use the value of X-Forwarded-For for checks too */
item = janus_config_get(config, config_general, janus_config_type_item, "admin_ws_acl_forwarded");
if(item && item->value)
janus_websockets_admin_check_xff = janus_is_true(item->value);
}

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

0 comments on commit c0ea280

Please sign in to comment.