1
0
mirror of https://github.com/unrealircd/unrealircd.git synced 2026-07-04 20:03:12 +02:00

Add an option to check websocket Origin header via

listen {
	websocket {
		allow-origin { *.example.net; }
	}
}

This allows you to limit websockets to a particular domain, IF the
user is using a normal browser.

Note that any non-browser (eg a websocket command line program) could
just spoof the Origin header, so for that case it doesn't really add
any security or real restriction.
This commit is contained in:
Bram Matthys
2023-11-26 20:08:17 +01:00
parent 98c264aabf
commit 02ac1fc0b3
3 changed files with 38 additions and 1 deletions
+1
View File
@@ -1993,6 +1993,7 @@ struct ConfigItem_listen {
WebServer *webserver; /**< For the webserver module */
void (*start_handshake)(Client *client); /**< Function to call on accept() */
int websocket_options; /**< Websocket options (for the websocket module) */
NameList *websocket_origin; /**< List of permitted Origin */
int rpc_options; /**< For the RPC module */
};
+5 -1
View File
@@ -5325,7 +5325,9 @@ void conf_listen_configure(const char *ip, int port, SocketType socket_type, int
free_tls_options(listen->tls_options);
listen->tls_options = NULL;
}
safe_free(listen->webserver);
safe_free_webserver(listen->webserver);
free_entire_name_list(listen->websocket_origin);
// NOTE: duplicate code overlap with listen_cleanup()
/* Now set the new settings: */
if (tlsconfig)
@@ -11268,6 +11270,8 @@ void listen_cleanup()
free_tls_options(listener->tls_options);
/* listener->ssl_ctx is already freed by close_listener() */
safe_free_webserver(listener->webserver);
free_entire_name_list(listener->websocket_origin);
// NOTE: duplicate code overlap with conf_listen_configure() - but not 100% identical
safe_free(listener);
} else {
/* Still has clients */
+32
View File
@@ -143,6 +143,8 @@ int websocket_config_test(ConfigFile *cf, ConfigEntry *ce, int type, int *errs)
"See https://www.unrealircd.org/docs/Proxy_block",
cep->file->filename, cep->line_number);
errors++;
} else if (!strcmp(cep->name, "allow-origin"))
{
} else
{
config_error("%s:%i: unknown directive listen::options::websocket::%s",
@@ -201,6 +203,10 @@ int websocket_config_run_ex(ConfigFile *cf, ConfigEntry *ce, int type, void *ptr
warned_once_channel = 1;
}
}
} else if (!strcmp(cep->name, "allow-origin"))
{
for (cepp = cep->items; cepp; cepp = cepp->next)
add_name_list(l->websocket_origin, cepp->name);
}
}
return 1;
@@ -350,6 +356,32 @@ int websocket_handle_request(Client *client, WebRequest *web)
}
/** Finally, validate the websocket request (handshake) and proceed or reject. */
if (client->local->listener->websocket_origin)
{
const char *origin = get_nvplist(web->headers, "Origin");
char origin_host[256];
*origin_host = '\0';
if (origin)
{
char *start = strstr(origin, "://");
char *p;
if (start)
{
start += 3;
p = strchr(start, '/');
if (p)
strlncpy(origin_host, start, sizeof(origin_host), p - start);
else
strlcpy(origin_host, start, sizeof(origin_host));
}
}
if (!find_name_list_match(client->local->listener->websocket_origin, origin_host))
{
webserver_send_response(client, 403, "This site is not permitted to connect to us with websockets");
return 0;
}
}
/* Not websocket and webredir loaded? Let that module serve a redirect. */
if (!WSU(client)->handshake_key)