docs/ref/modules/control/architecture.md
The Control Module (wm_control) is a lightweight module within wazuh-modulesd that provides manager control operations. It implements a Unix domain socket server that accepts control commands and executes system-level operations.
This module is enabled in manager builds (TARGET=manager) on Unix-like systems.
┌─────────────────────────────────────────────────────────────┐
│ wazuh-modulesd │
│ │
│ ┌───────────────────────────────────────────────────────┐ │
│ │ wm_control Module │ │
│ │ │ │
│ │ ┌──────────────┐ ┌───────────────────────┐ │ │
│ │ │ Socket │ │ Command Dispatcher │ │ │
│ │ │ Listener │─────▶│ wm_control_dispatch │ │ │
│ │ │ send_ip() │ └───────┬───────────────┘ │ │
│ │ └──────────────┘ │ │ │
│ │ │ │ │
│ │ │ │ │
│ │ │ │ │
│ │ ┌──────────▼─────────┐ │ │
│ │ │ Restart/Reload │ │ │
│ │ │ wm_control_execute │ │ │
│ │ │ _action() │ │ │
│ │ └────────────────────┘ │ │
│ └───────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────┘
│ ▲
│ fork + execv │ socket connect
▼ │
┌──────────────────────┐ ┌─────────────────────┐
│ systemctl/ │ │ API / Framework │
│ wazuh-control │ │ Clients │
└──────────────────────┘ └─────────────────────┘
send_ip())The socket listener is the main entry point for control commands.
Functionality:
/var/ossec/queue/sockets/controlImplementation Details:
// Socket creation with specific permissions
int sock = OS_BindUnixDomainWithPerms(
CONTROL_SOCK, // "queue/sockets/control"
SOCK_STREAM, // Stream socket
OS_MAXSTR, // Max connections
getuid(), // Owner UID
wm_getGroupID(), // Wazuh group GID
0660 // Permissions: rw-rw----
);
Main Loop:
select() on socket for incoming connectionsaccept() new client connectionOS_RecvUnix() read command from clientwm_control_dispatch() process commandOS_SendUnix() send response to clientwm_control_dispatch())Routes incoming commands to appropriate handlers.
Command Routing:
size_t wm_control_dispatch(char *command, char **output) {
// Parse command and arguments
char *args = strchr(command, ' ');
if (args) {
*args = '\0';
args++;
}
if (strcmp(command, "restart") == 0) {
return wm_control_execute_action("restart", output);
}
else if (strcmp(command, "reload") == 0) {
return wm_control_execute_action("reload", output);
}
else {
mterror(WM_CONTROL_LOGTAG, "Unknown command: '%s'", command);
os_strdup("Err", *output);
return strlen(*output);
}
}
wm_control_execute_action())Executes restart/reload operations via system commands.
Process Flow:
┌─────────────────────────────────────────────┐
│ wm_control_execute_action("restart") │
└─────────────────┬───────────────────────────┘
│
▼
┌────────────────┐
│ Check systemd? │
└───┬────────┬───┘
│ │
Yes ◄──┘ └──► No
│ │
▼ ▼
┌─────────────┐ ┌──────────────────┐
│ systemctl │ │ wazuh-control │
│ restart │ │ restart │
│ wazuh- │ │ │
│ manager │ │ │
└─────────────┘ └──────────────────┘
Systemd Detection:
static bool wm_control_check_systemd() {
// Check if systemd directory exists
if (access("/run/systemd/system", F_OK) != 0) {
return false;
}
// Check if PID 1 is systemd
FILE *fp = fopen("/proc/1/comm", "r");
if (fp) {
char init_name[256];
if (fgets(init_name, sizeof(init_name), fp)) {
init_name[strcspn(init_name, "\n")] = 0;
if (strcmp(init_name, "systemd") == 0) {
fclose(fp);
return true;
}
}
fclose(fp);
}
return false;
}
Fork and Execute:
switch (fork()) {
case -1: // Fork failed
return error;
case 0: // Child process
// For reload: wait for service active
if (reload && systemd) {
wm_control_wait_for_service_active();
}
// Execute command
execv("/usr/bin/systemctl", ["systemctl", action, "wazuh-manager"]);
_exit(1);
default: // Parent process
return "ok "; // Return immediately
}
Key Design Decision: The parent process returns "ok " immediately after forking, without waiting for the child to complete. This is intentional to prevent socket timeout issues during restart operations.
For reload operations with systemd, the module ensures the service is ready:
static bool wm_control_wait_for_service_active() {
const int timeout = 60; // seconds
while (elapsed < timeout) {
// Check service state
FILE *fp = popen("systemctl is-active wazuh-manager", "r");
char state[256];
fgets(state, sizeof(state), fp);
if (strcmp(state, "active") == 0) {
return true; // Ready for reload
}
if (strcmp(state, "inactive") == 0 || strcmp(state, "failed") == 0) {
return false; // Cannot reload
}
sleep(1);
elapsed++;
}
return false; // Timeout
}
wm_control only accepts restart and reload.
Any other command:
Unknown command)Err to the client1. API/Framework
└─► socket.connect("/var/ossec/queue/sockets/control")
2. API/Framework
└─► socket.send("restart")
3. wm_control Module
└─► wm_control_dispatch("restart", &output)
└─► wm_control_execute_action("restart", &output)
├─► Check systemd available?
├─► fork()
│ └─► Child: execv("systemctl restart wazuh-manager")
└─► Parent: return "ok "
4. API/Framework
└─► socket.recv() → "ok "
5. API/Framework
└─► socket.close()
Main Thread: Module initialization (wm_control_main())
send_ip() to start socket serverSocket Server: Single-threaded event loop (send_ip())
select() for socket eventsAction Execution: Fork-based process isolation
Socket Errors:
Fork Errors:
Systemd Errors:
Access Control:
0660 (owner and group only)Privilege Model:
Attack Surface:
Component: wazuh-execd daemon
/var/ossec/queue/sockets/comComponent: wm_control module (within modulesd)
/var/ossec/queue/sockets/control| Feature | v4.x (execd) | v5.0 (wm_control) | Notes |
|---|---|---|---|
| Manager restart | ✓ wcom socket | ✓ control socket | Migrated |
| Manager reload | ✓ wcom socket | ✓ control socket | Migrated |
| Get primary IP | ✓ wcom socket | ✗ Removed | No longer handled by control socket |
| Configuration serving | ✓ wcom socket | ✗ File-based | Changed approach |
| Config validation | ✓ wcom socket | ✗ File-based | Changed approach |
| File unmerge | ✓ wcom socket | ✗ Removed | Deprecated |
| File uncompress | ✓ wcom socket | ✗ Removed | Deprecated |
| Restart locking | ✓ wcom socket | ✗ Not migrated | TBD |
| Active Response | ✓ execd daemon | ✗ Agents only | Intentional removal |
Socket Performance:
Restart Performance:
Resource Usage:
Potential improvements for future versions: