diff --git a/doc/userguide/manpages/suricata.rst b/doc/userguide/manpages/suricata.rst index 9652d7a43f..a85795c01a 100644 --- a/doc/userguide/manpages/suricata.rst +++ b/doc/userguide/manpages/suricata.rst @@ -45,6 +45,9 @@ SIGHUP used to re-open log files after they may have been moved away by log rotation utilities. +On Windows, when running as a service, the service control code 128 is the +equivalent of SIGUSR2. + FILES AND DIRECTORIES --------------------- diff --git a/doc/userguide/rule-management/rule-reload.rst b/doc/userguide/rule-management/rule-reload.rst index 5da25c7b46..b3b7953d84 100644 --- a/doc/userguide/rule-management/rule-reload.rst +++ b/doc/userguide/rule-management/rule-reload.rst @@ -41,6 +41,30 @@ This will cause Suricata to reload rules without the caller blocking or waiting. suricatasc -c ruleset-reload-nonblocking +.. _rule-reload-windows-service: + +Via Windows service control +--------------------------- + +Windows does not support the ``USR2`` signal or the UNIX domain socket. +Instead, when Suricata is running as a Windows service, a rule reload can be +requested by sending the service the user-defined control code ``128``:: + + sc.exe control Suricata 128 + +This is a non-blocking reload. ``sc.exe`` does not report the result of the +reload; it is logged by Suricata. + +When installed with ``--service-install``, only SYSTEM and Administrators may +send control codes to the Suricata service. A service installed by older +versions of Suricata, or by other tools, may allow any interactive user to +send control codes. This can be restricted with:: + + sc.exe sdset Suricata "D:(A;;CCLCSWRPWPDTLOCRRC;;;SY)(A;;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;BA)(A;;CCLCSWLORC;;;IU)(A;;CCLCSWLORC;;;SU)" + +.. note:: In PowerShell, ``sc`` is an alias for ``Set-Content``, so + ``sc.exe`` must be used. + Resources Reloaded ~~~~~~~~~~~~~~~~~~ diff --git a/src/suricata.c b/src/suricata.c index e79729a033..0da0dac37e 100644 --- a/src/suricata.c +++ b/src/suricata.c @@ -3040,6 +3040,18 @@ void SuricataMainLoop(void) TmThreadCheckThreadState(); +#ifdef OS_WIN32 + /* Service control requests are handled like their signal equivalents, + * SC_SERVICE_REQUEST_RELOAD_RULES like SIGUSR2. */ + uint32_t requests = SCServiceTakeRequests(); + if (requests & SC_SERVICE_REQUEST_RELOAD_RULES) { + SCLogNotice("Rule reload requested by service control"); + if (DetectEngineEnabled() && sigusr2_count < 2) { + sigusr2_count++; + } + } +#endif + if (sighup_count > 0) { OutputNotifyFileRotation(); sighup_count--; diff --git a/src/win32-service.c b/src/win32-service.c index 0b61ebe746..c3b3d64930 100644 --- a/src/win32-service.c +++ b/src/win32-service.c @@ -137,6 +137,9 @@ static bool SCServiceGetCommandLine( static SERVICE_STATUS_HANDLE service_status_handle = 0; +/* Pending SC_SERVICE_REQUEST_* flags, handled by the main loop. */ +static SC_ATOMIC_DECLARE(uint32_t, service_requests); + static int service_argc = 0; static char **service_argv = NULL; @@ -185,11 +188,27 @@ static void SCAtExitHandler(void) } } +/** + * \brief Get and clear the pending service control requests. + * + * \retval SC_SERVICE_REQUEST_* flags + */ +uint32_t SCServiceTakeRequests(void) +{ + return SC_ATOMIC_AND(service_requests, 0); +} + /** * \brief Service handler */ static DWORD WINAPI SCServiceCtrlHandlerEx(DWORD code, DWORD etype, LPVOID edata, LPVOID context) { + if (code == SC_SERVICE_CONTROL_RELOAD_RULES) { + /* Defer logging to the main loop, after logging initialization. */ + SC_ATOMIC_OR(service_requests, SC_SERVICE_REQUEST_RELOAD_RULES); + return NO_ERROR; + } + if (code == SERVICE_CONTROL_SHUTDOWN || code == SERVICE_CONTROL_STOP) { SERVICE_STATUS status = { SERVICE_WIN32, diff --git a/src/win32-service.h b/src/win32-service.h index 87d4bc634e..bb808fe85a 100644 --- a/src/win32-service.h +++ b/src/win32-service.h @@ -25,6 +25,13 @@ #define SURICATA_WIN32_SERVICE_H #ifdef OS_WIN32 +/* User-defined service control codes, must be in the range 128-255. */ +#define SC_SERVICE_CONTROL_RELOAD_RULES 128 + +/* Requests returned by SCServiceTakeRequests(). */ +#define SC_SERVICE_REQUEST_RELOAD_RULES BIT_U32(0) + +uint32_t SCServiceTakeRequests(void); int SCRunningAsService(void); int SCServiceInit(int argc, char **argv); int SCServiceInstall(int argc, char **argv);