diff --git a/include/struct.h b/include/struct.h index c7ba6c622..c96fcd907 100644 --- a/include/struct.h +++ b/include/struct.h @@ -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 */ }; diff --git a/src/conf.c b/src/conf.c index 72641fb48..b569571b6 100644 --- a/src/conf.c +++ b/src/conf.c @@ -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 */ diff --git a/src/modules/websocket.c b/src/modules/websocket.c index abd33a9f3..2a7bea30b 100644 --- a/src/modules/websocket.c +++ b/src/modules/websocket.c @@ -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)