mirror of
https://github.com/unrealircd/unrealircd.git
synced 2026-07-09 11:53:13 +02:00
Fix potentially sending invalid data over websockets on REHASH.
This makes websocket_common unload last (and near-last: rpc & websocket) and makes us call Mod_Init for these three modules first. This way, the period where the websocket handler is unavailable is kept to a minimum. This also renames the ModuleSetOptions option MOD_OPT_UNLOAD_PRIORITY to MOD_OPT_PRIORITY since it dynamically changes the module priority in the list. For 6.x compatibility, MOD_OPT_UNLOAD_PRIORITY can still be used.
This commit is contained in:
+7
-1
@@ -777,9 +777,15 @@ struct Module
|
||||
#define MOD_OPT_OFFICIAL 0x0002 /* Official module, do not set "tainted" */
|
||||
#define MOD_OPT_PERM_RELOADABLE 0x0004 /* Module is semi-permanent: it can be re-loaded but not un-loaded */
|
||||
#define MOD_OPT_GLOBAL 0x0008 /* Module is required to be loaded globally (i.e. across the entire network) */
|
||||
#define MOD_OPT_UNLOAD_PRIORITY 0x1000 /* Module wants a higher or lower unload priority */
|
||||
#define MOD_OPT_PRIORITY 0x1000 /* Module wants a higher or lower priority for unloading, init, load, etc */
|
||||
#define MOD_OPT_UNLOAD_PRIORITY 0x1000 /* Alias for MOD_OPT_PRIORITY */
|
||||
#define MOD_Dep(name, container,module) {#name, (vFP *) &container, module}
|
||||
|
||||
/** Websocket module should init 'first' because it handles sockets */
|
||||
#define WEBSOCKET_MODULE_PRIORITY_INIT -1000000000
|
||||
/** Websocket module should unload 'last' because it handles sockets */
|
||||
#define WEBSOCKET_MODULE_PRIORITY_UNLOAD 1000000000
|
||||
|
||||
/** Event structs */
|
||||
struct Event {
|
||||
Event *prev; /**< Previous event (linked list) */
|
||||
|
||||
+2
-2
@@ -2091,8 +2091,6 @@ int config_test(void)
|
||||
safe_strdup(old_pid_file, conf_files->pid_file);
|
||||
unrealdns_delasyncconnects();
|
||||
config_rehash();
|
||||
Unload_all_loaded_modules();
|
||||
|
||||
/* Notify permanent modules of the rehash */
|
||||
for (h = Hooks[HOOKTYPE_REHASH]; h; h = h->next)
|
||||
{
|
||||
@@ -2102,6 +2100,8 @@ int config_test(void)
|
||||
continue;
|
||||
(*(h->func.intfunc))();
|
||||
}
|
||||
/* Last step: */
|
||||
Unload_all_loaded_modules();
|
||||
}
|
||||
config_pre_run_log();
|
||||
|
||||
|
||||
+6
-5
@@ -430,18 +430,19 @@ const char *Module_Create(const char *path_)
|
||||
if (Mod_Handle)
|
||||
*Mod_Handle = mod;
|
||||
irc_dlsym(Mod, "Mod_Test", Mod_Test);
|
||||
/* add module here, so ModuleSetOptions() w/MOD_OPT_PRIORITY is available in Mod_Test() */
|
||||
AddListItemPrio(mod, Modules, 0);
|
||||
if (Mod_Test)
|
||||
{
|
||||
if ((ret = (*Mod_Test)(&mod->modinfo)) < MOD_SUCCESS) {
|
||||
ircsnprintf(errorbuf, sizeof(errorbuf), "Mod_Test returned %i",
|
||||
ret);
|
||||
if ((ret = (*Mod_Test)(&mod->modinfo)) < MOD_SUCCESS)
|
||||
{
|
||||
ircsnprintf(errorbuf, sizeof(errorbuf), "Mod_Test returned %i", ret);
|
||||
/* We EXPECT the module to have cleaned up its mess */
|
||||
Module_free(mod);
|
||||
return (errorbuf);
|
||||
}
|
||||
}
|
||||
mod->flags = MODFLAG_TESTING;
|
||||
AddListItemPrio(mod, Modules, 0);
|
||||
return NULL;
|
||||
}
|
||||
else
|
||||
@@ -1221,7 +1222,7 @@ void ModuleSetOptions(Module *module, unsigned int options, int action)
|
||||
{
|
||||
unsigned int oldopts = module->options;
|
||||
|
||||
if (options == MOD_OPT_UNLOAD_PRIORITY)
|
||||
if (options == MOD_OPT_PRIORITY)
|
||||
{
|
||||
DelListItem(module, Modules);
|
||||
AddListItemPrio(module, Modules, action);
|
||||
|
||||
@@ -93,7 +93,7 @@ MOD_INIT()
|
||||
{
|
||||
MARK_AS_OFFICIAL_MODULE(modinfo);
|
||||
/* We must unload early, when all channel modes and such are still in place: */
|
||||
ModuleSetOptions(modinfo->handle, MOD_OPT_UNLOAD_PRIORITY, -99999999);
|
||||
ModuleSetOptions(modinfo->handle, MOD_OPT_PRIORITY, -99999999);
|
||||
|
||||
LoadPersistentLong(modinfo, channeldb_next_event);
|
||||
|
||||
|
||||
@@ -132,7 +132,7 @@ MOD_INIT()
|
||||
|
||||
MARK_AS_OFFICIAL_MODULE(modinfo);
|
||||
/* We must unload early, when all channel modes and such are still in place: */
|
||||
ModuleSetOptions(modinfo->handle, MOD_OPT_UNLOAD_PRIORITY, -99999999);
|
||||
ModuleSetOptions(modinfo->handle, MOD_OPT_PRIORITY, -99999999);
|
||||
|
||||
setcfg(&cfg);
|
||||
|
||||
|
||||
@@ -70,6 +70,10 @@ MOD_TEST()
|
||||
EfunctionAddVoid(modinfo->handle, EFUNC_RPC_RESPONSE, _rpc_response);
|
||||
EfunctionAddVoid(modinfo->handle, EFUNC_RPC_ERROR, _rpc_error);
|
||||
EfunctionAddVoid(modinfo->handle, EFUNC_RPC_ERROR_FMT, TO_VOIDFUNC(_rpc_error_fmt));
|
||||
|
||||
/* Call MOD_INIT very early, since we manage sockets, but depend on websocket_common */
|
||||
ModuleSetOptions(modinfo->handle, MOD_OPT_PRIORITY, WEBSOCKET_MODULE_PRIORITY_INIT+1);
|
||||
|
||||
return MOD_SUCCESS;
|
||||
}
|
||||
|
||||
@@ -79,17 +83,21 @@ MOD_INIT()
|
||||
|
||||
MARK_AS_OFFICIAL_MODULE(modinfo);
|
||||
|
||||
websocket_md = findmoddata_byname("websocket", MODDATATYPE_CLIENT); /* can be NULL */
|
||||
|
||||
HookAdd(modinfo->handle, HOOKTYPE_CONFIGRUN_EX, 0, rpc_config_run_ex_listen);
|
||||
HookAdd(modinfo->handle, HOOKTYPE_CONFIGRUN, 0, rpc_config_run_rpc_user);
|
||||
HookAdd(modinfo->handle, HOOKTYPE_HANDSHAKE, -5000, rpc_client_accept);
|
||||
HookAdd(modinfo->handle, HOOKTYPE_RAWPACKET_IN, INT_MIN, rpc_packet_in_unix_socket);
|
||||
|
||||
/* Call MOD_LOAD very late, since we manage sockets, but depend on websocket_common */
|
||||
ModuleSetOptions(modinfo->handle, MOD_OPT_PRIORITY, WEBSOCKET_MODULE_PRIORITY_UNLOAD-1);
|
||||
|
||||
return MOD_SUCCESS;
|
||||
}
|
||||
|
||||
MOD_LOAD()
|
||||
{
|
||||
websocket_md = findmoddata_byname("websocket", MODDATATYPE_CLIENT); /* can be NULL */
|
||||
return MOD_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -128,7 +128,7 @@ MOD_TEST()
|
||||
MOD_INIT()
|
||||
{
|
||||
MARK_AS_OFFICIAL_MODULE(modinfo);
|
||||
ModuleSetOptions(modinfo->handle, MOD_OPT_UNLOAD_PRIORITY, -9999);
|
||||
ModuleSetOptions(modinfo->handle, MOD_OPT_PRIORITY, -9999);
|
||||
|
||||
LoadPersistentLong(modinfo, tkldb_next_event);
|
||||
|
||||
|
||||
@@ -64,6 +64,9 @@ MOD_TEST()
|
||||
{
|
||||
HookAdd(modinfo->handle, HOOKTYPE_CONFIGTEST, 0, websocket_config_test);
|
||||
HookAdd(modinfo->handle, HOOKTYPE_CONFIGPOSTTEST, 0, websocket_config_posttest);
|
||||
|
||||
/* Call MOD_INIT very early, since we manage sockets, but depend on websocket_common */
|
||||
ModuleSetOptions(modinfo->handle, MOD_OPT_PRIORITY, WEBSOCKET_MODULE_PRIORITY_INIT+1);
|
||||
return MOD_SUCCESS;
|
||||
}
|
||||
|
||||
@@ -73,18 +76,21 @@ MOD_INIT()
|
||||
|
||||
MARK_AS_OFFICIAL_MODULE(modinfo);
|
||||
|
||||
websocket_md = findmoddata_byname("websocket", MODDATATYPE_CLIENT);
|
||||
if (!websocket_md)
|
||||
config_warn("The 'websocket_common' module is not loaded, even though it was promised to be ???");
|
||||
|
||||
HookAdd(modinfo->handle, HOOKTYPE_CONFIGRUN_EX, 0, websocket_config_run_ex);
|
||||
HookAdd(modinfo->handle, HOOKTYPE_PACKET, INT_MAX, websocket_packet_out);
|
||||
HookAdd(modinfo->handle, HOOKTYPE_SECURE_CONNECT, 0, websocket_secure_connect);
|
||||
|
||||
/* Call MOD_LOAD very late, since we manage sockets, but depend on websocket_common */
|
||||
ModuleSetOptions(modinfo->handle, MOD_OPT_PRIORITY, WEBSOCKET_MODULE_PRIORITY_UNLOAD-1);
|
||||
return MOD_SUCCESS;
|
||||
}
|
||||
|
||||
MOD_LOAD()
|
||||
{
|
||||
websocket_md = findmoddata_byname("websocket", MODDATATYPE_CLIENT);
|
||||
if (!websocket_md)
|
||||
config_warn("The 'websocket_common' module is not loaded, even though it was promised to be ???");
|
||||
if (non_utf8_nick_chars_in_use || (iConf.allowed_channelchars == ALLOWED_CHANNELCHARS_ANY))
|
||||
ws_text_mode_available = 0;
|
||||
return MOD_SUCCESS;
|
||||
|
||||
@@ -58,6 +58,10 @@ MOD_TEST()
|
||||
EfunctionAdd(modinfo->handle, EFUNC_WEBSOCKET_HANDLE_WEBSOCKET, _websocket_handle_websocket);
|
||||
EfunctionAdd(modinfo->handle, EFUNC_WEBSOCKET_CREATE_PACKET, _websocket_create_packet);
|
||||
EfunctionAdd(modinfo->handle, EFUNC_WEBSOCKET_CREATE_PACKET_SIMPLE, _websocket_create_packet_simple);
|
||||
|
||||
/* Init first, since we manage sockets */
|
||||
ModuleSetOptions(modinfo->handle, MOD_OPT_PRIORITY, WEBSOCKET_MODULE_PRIORITY_INIT);
|
||||
|
||||
return MOD_SUCCESS;
|
||||
}
|
||||
|
||||
@@ -76,6 +80,9 @@ MOD_INIT()
|
||||
mreq.type = MODDATATYPE_CLIENT;
|
||||
websocket_md = ModDataAdd(modinfo->handle, mreq);
|
||||
|
||||
/* Unload last, since we manage sockets */
|
||||
ModuleSetOptions(modinfo->handle, MOD_OPT_PRIORITY, WEBSOCKET_MODULE_PRIORITY_UNLOAD);
|
||||
|
||||
return MOD_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user