Add `websockets_origin` option

This allows Origin header checking when clients attempt to upgrade from http->websockets.
pull/2386/head
Roger A. Light 4 years ago
parent 1633010130
commit 4f04f3de92

@ -45,6 +45,8 @@ Broker:
of `per_listener_settings`.
- Protocol version numbers reported in the log when a client connects now
match the MQTT protocol version numbers, not internal Mosquitto values.
- Add the `websockets_origin` option to allow optional enforcement of origin
when a connection attempts an upgrade to WebSockets.
Client library:
- Add MOSQ_OPT_DISABLE_SOCKETPAIR to allow the disabling of the socketpair

@ -1285,6 +1285,19 @@ log_timestamp_format %Y-%m-%dT%H:%M:%S
<para>Not reloaded on reload signal.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><option>websockets_headers_size</option> <replaceable>size</replaceable></term>
<listitem>
<para>Change the websockets headers size. This is a
global option, it is not possible to set per
listener. This option sets the size of the buffer
used in the libwebsockets library when reading HTTP
headers. If you are passing large header data such
as cookies then you may need to increase this
value. If left unset, or set to 0, then the default
of 1024 bytes will be used.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><option>websockets_log_level</option> <replaceable>level</replaceable></term>
<listitem>
@ -1300,16 +1313,23 @@ log_timestamp_format %Y-%m-%dT%H:%M:%S
</listitem>
</varlistentry>
<varlistentry>
<term><option>websockets_headers_size</option> <replaceable>size</replaceable></term>
<term><option>websockets_origin</option> <replaceable>level</replaceable></term>
<listitem>
<para>Change the websockets headers size. This is a
global option, it is not possible to set per
listener. This option sets the size of the buffer
used in the libwebsockets library when reading HTTP
headers. If you are passing large header data such
as cookies then you may need to increase this
value. If left unset, or set to 0, then the default
of 1024 bytes will be used.</para>
<para>
If set, this will be compared to the http origin
header when a connection attempts to upgrade to
WebSockets. Only matching origins will be allowed.
Use the exact string provided by the browser in the
origin header, e.g.
<replaceable>http://example.com:8080</replaceable>.
Can be specified multiple times per listener.
</para>
<para>
If not set, connections from any origin will be allowed.
</para>
<para>
Requires libwebsockets 3.1.0 or later.
</para>
</listitem>
</varlistentry>
</variablelist>

@ -280,6 +280,14 @@
# unset, or set to 0, then the default of 1024 bytes will be used.
#websockets_headers_size
# Enforce origin checking for websockets connections. This should be set to the
# string of the host that you wish to allow connections from, as set as the
# Origin header in the http request.
# For example: https://example.com:8080
# If left unset will allow connections from any origin.
# May be set multiple times.
#websockets_origin
# -----------------------------------------------------------------
# Certificate based SSL/TLS support
# -----------------------------------------------------------------

@ -253,7 +253,7 @@ void config__init(struct mosquitto__config *config)
void config__cleanup(struct mosquitto__config *config)
{
int i;
int i, j;
mosquitto__free(config->clientid_prefixes);
mosquitto__free(config->persistence_location);
@ -298,6 +298,10 @@ void config__cleanup(struct mosquitto__config *config)
#endif
#ifdef WITH_WEBSOCKETS
mosquitto__free(config->listeners[i].http_dir);
for(j=0; j<config->listeners[i].ws_origin_count; j++){
mosquitto__free(config->listeners[i].ws_origins[j]);
}
mosquitto__free(config->listeners[i].ws_origins);
#endif
#ifdef WITH_UNIX_SOCKETS
mosquitto__free(config->listeners[i].unix_socket_path);
@ -799,6 +803,9 @@ static int config__read_file_core(struct mosquitto__config *config, bool reload,
char *kpass_sha = NULL, *kpass_sha_bin = NULL;
char *keyform ;
#endif
#ifdef WITH_WEBSOCKETS
char **ws_origins = NULL;
#endif
*lineno = 0;
@ -2307,6 +2314,24 @@ static int config__read_file_core(struct mosquitto__config *config, bool reload,
return MOSQ_ERR_INVAL;
}
config->websockets_headers_size = (uint16_t)tmp_int;
#else
log__printf(NULL, MOSQ_LOG_WARNING, "Warning: Websockets support not available.");
#endif
}else if(!strcmp(token, "websockets_origin")){
#ifdef WITH_WEBSOCKETS
# if LWS_LIBRARY_VERSION_NUMBER >= 3001000
ws_origins = mosquitto__realloc(cur_listener->ws_origins, sizeof(char *)*(size_t)(cur_listener->ws_origin_count+1));
if(ws_origins == NULL){
log__printf(NULL, MOSQ_LOG_ERR, "Error: Out of memory.");
return MOSQ_ERR_NOMEM;
}
ws_origins[cur_listener->ws_origin_count] = NULL;
if(conf__parse_string(&token, "websockets_origin", &ws_origins[cur_listener->ws_origin_count], &saveptr)) return MOSQ_ERR_INVAL;
cur_listener->ws_origins = ws_origins;
cur_listener->ws_origin_count++;
# else
log__printf(NULL, MOSQ_LOG_WARNING, "Warning: websockets_origin support not available, libwebsockets version is too old.");
# endif
#else
log__printf(NULL, MOSQ_LOG_WARNING, "Warning: Websockets support not available.");
#endif

@ -232,6 +232,8 @@ struct mosquitto__listener {
bool ws_in_init;
char *http_dir;
struct lws_protocols *ws_protocol;
char **ws_origins;
int ws_origin_count;
#endif
struct mosquitto__security_options security_options;
#ifdef WITH_UNIX_SOCKETS

@ -447,6 +447,8 @@ static int callback_http(
struct stat filestat;
struct mosquitto *mosq;
struct lws_pollargs *pollargs = (struct lws_pollargs *)in;
int hlen;
int i;
/* FIXME - ssl cert verification is done here. */
@ -538,6 +540,26 @@ static int callback_http(
/* Access control here */
return 0;
#if LWS_LIBRARY_VERSION_NUMBER >= 3001000
case LWS_CALLBACK_HTTP_CONFIRM_UPGRADE:
hack = lws_context_user(lws_get_context(wsi));
if(hack->listener->ws_origin_count){
hlen = lws_hdr_total_length(wsi, WSI_TOKEN_ORIGIN);
if(hlen <= 0 || hlen >= (int)sizeof(buf)){
return -1;
}
for(i=0; i<hack->listener->ws_origin_count; i++){
lws_hdr_copy(wsi, (char *)buf, sizeof(buf), WSI_TOKEN_ORIGIN);
if((!strcmp(hack->listener->ws_origins[i], (char *)buf))){
return 0;
}
}
return -1;
}else{
return 0;
}
#endif
case LWS_CALLBACK_HTTP_WRITEABLE:
/* Send our data here */
if(u && u->fptr){

Loading…
Cancel
Save