Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Optionally support X-Forwarded-For in both HTTP and WebSocket transports (fixes #3158) #3160

Merged
merged 1 commit into from
Feb 14, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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 src/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 src/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