41 #if (defined BUILD_UNIX_SOCKET) && (defined HAVE_SYS_UN_H) && (defined HAVE_SYS_STAT_H) && (defined HAVE_SYS_TYPES_H)
44 #include <sys/types.h>
52 # define MSG_NOSIGNAL SO_NOSIGPIPE
56 #define SOCKET_PATH LOCAL_STATE_DIR "/run/suricata/"
57 #define SOCKET_FILENAME "suricata-command.socket"
58 #define SOCKET_TARGET SOCKET_PATH SOCKET_FILENAME
63 #define MAX_FAILED_RULES 20
65 typedef struct Command_ {
67 TmEcode (*Func)(json_t *, json_t *,
void *);
73 typedef struct Task_ {
79 #define CLIENT_BUFFER_SIZE 4096
80 typedef struct UnixClient_ {
87 typedef struct UnixCommand_ {
88 time_t start_timestamp;
90 struct sockaddr_un client_addr;
102 static int UnixNew(UnixCommand *
this)
104 struct sockaddr_un addr;
108 char sockettarget[PATH_MAX];
109 const char *socketname;
111 this->start_timestamp = time(NULL);
113 this->select_max = 0;
120 if (
ConfGet(
"unix-command.filename", &socketname) == 1) {
122 strlcpy(sockettarget, socketname,
sizeof(sockettarget));
124 snprintf(sockettarget,
sizeof(sockettarget),
"%s/%s",
125 SOCKET_PATH, socketname);
129 strlcpy(sockettarget, SOCKET_TARGET,
sizeof(sockettarget));
132 SCLogInfo(
"Using unix socket file '%s'", sockettarget);
135 struct stat stat_buf;
137 if (stat(SOCKET_PATH, &stat_buf) != 0) {
139 ret =
SCMkDir(SOCKET_PATH, S_IRWXU|S_IXGRP|S_IRGRP);
144 "Cannot create socket directory %s: %s",
145 SOCKET_PATH, strerror(err));
156 (void) unlink(sockettarget);
159 addr.sun_family = AF_UNIX;
160 strlcpy(addr.sun_path, sockettarget,
sizeof(addr.sun_path));
161 addr.sun_path[
sizeof(addr.sun_path) - 1] = 0;
162 len = strlen(addr.sun_path) +
sizeof(addr.sun_family) + 1;
165 this->socket = socket(AF_UNIX, SOCK_STREAM, 0);
166 if (this->socket == -1) {
168 "Unix Socket: unable to create UNIX socket %s: %s",
169 addr.sun_path, strerror(errno));
172 this->select_max = this->socket + 1;
175 ret = setsockopt(this->socket, SOL_SOCKET, SO_REUSEADDR,
176 (
char *) &on,
sizeof(on));
179 "Cannot set sockets options: %s.", strerror(errno));
183 ret = bind(this->socket, (
struct sockaddr *) &addr,
len);
186 "Unix socket: UNIX socket bind(%s) error: %s",
187 sockettarget, strerror(errno));
191 #if !(defined OS_FREEBSD || defined __OpenBSD__)
195 ret = chmod(sockettarget, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP);
199 "Unable to change permission on socket: %s (%d)",
206 if (listen(this->socket, 1) == -1) {
208 "Command server: UNIX socket listen() error: %s",
215 static void UnixCommandSetMaxFD(UnixCommand *
this)
224 this->select_max = this->socket + 1;
226 if (item->fd >= this->select_max) {
227 this->select_max = item->fd + 1;
232 static UnixClient *UnixClientAlloc(
void)
234 UnixClient *uclient =
SCMalloc(
sizeof(UnixClient));
240 if (uclient->mbuf == NULL) {
248 static void UnixClientFree(UnixClient *c)
259 static void UnixCommandClose(UnixCommand *
this,
int fd)
265 if (item->fd == fd) {
279 UnixCommandSetMaxFD(
this);
280 UnixClientFree(item);
283 #define UNIX_PROTO_VERSION_LENGTH 200
284 #define UNIX_PROTO_VERSION_V1 "0.1"
285 #define UNIX_PROTO_V1 1
286 #define UNIX_PROTO_VERSION "0.2"
287 #define UNIX_PROTO_V2 2
289 static int UnixCommandSendJSONToClient(UnixClient *client, json_t *js)
295 .expand_by = CLIENT_BUFFER_SIZE
299 JSON_PRESERVE_ORDER|JSON_COMPACT|JSON_ENSURE_ASCII|
306 if (client->version > UNIX_PROTO_V1) {
322 SCLogDebug(
"sent message of size %"PRIuMAX
" to client socket %d",
336 static int UnixCommandAccept(UnixCommand *
this)
338 char buffer[UNIX_PROTO_VERSION_LENGTH + 1];
346 UnixClient *uclient = NULL;
349 socklen_t
len =
sizeof(this->client_addr);
350 client = accept(this->socket, (
struct sockaddr *) &this->client_addr,
353 SCLogInfo(
"Unix socket: accept() error: %s",
360 buffer[
sizeof(buffer)-1] = 0;
361 ret = recv(client, buffer,
sizeof(buffer)-1, 0);
363 SCLogInfo(
"Command server: client doesn't send version");
367 if (ret >= (
int)(
sizeof(buffer)-1)) {
368 SCLogInfo(
"Command server: client message is too long, "
375 client_msg = json_loads(buffer, 0, &jerror);
376 if (client_msg == NULL) {
377 SCLogInfo(
"Invalid command, error on line %d: %s\n", jerror.line, jerror.text);
382 version = json_object_get(client_msg,
"version");
383 if (!json_is_string(
version)) {
384 SCLogInfo(
"error: version is not a string");
386 json_decref(client_msg);
391 if ((strcmp(json_string_value(
version), UNIX_PROTO_VERSION) != 0)
392 && (strcmp(json_string_value(
version), UNIX_PROTO_VERSION_V1) != 0)) {
393 SCLogInfo(
"Unix socket: invalid client version: \"%s\"",
395 json_decref(client_msg);
399 SCLogDebug(
"Unix socket: client version: \"%s\"",
401 if (strcmp(json_string_value(
version), UNIX_PROTO_VERSION_V1) == 0) {
402 client_version = UNIX_PROTO_V1;
404 client_version = UNIX_PROTO_V2;
408 json_decref(client_msg);
410 server_msg = json_object();
411 if (server_msg == NULL) {
415 json_object_set_new(server_msg,
"return", json_string(
"OK"));
417 uclient = UnixClientAlloc();
420 json_decref(server_msg);
424 uclient->fd = client;
425 uclient->version = client_version;
427 if (UnixCommandSendJSONToClient(uclient, server_msg) != 0) {
430 UnixClientFree(uclient);
431 json_decref(server_msg);
436 json_decref(server_msg);
441 UnixCommandSetMaxFD(
this);
445 static int UnixCommandBackgroundTasks(UnixCommand*
this)
451 int fret = ltask->Func(ltask->data);
468 static int UnixCommandExecute(UnixCommand *
this,
char *command, UnixClient *client)
472 json_t *jsoncmd = NULL;
474 json_t *server_msg = json_object();
479 if (server_msg == NULL) {
483 jsoncmd = json_loads(command, 0, &error);
484 if (jsoncmd == NULL) {
485 SCLogInfo(
"Invalid command, error on line %d: %s\n", error.line, error.text);
489 cmd = json_object_get(jsoncmd,
"command");
490 if(!json_is_string(cmd)) {
491 SCLogInfo(
"error: command is not a string");
494 value = json_string_value(cmd);
497 if (!strcmp(value, lcmd->name)) {
501 cmd = json_object_get(jsoncmd,
"arguments");
502 if(!json_is_object(cmd)) {
503 SCLogInfo(
"error: argument is not an object");
507 fret = lcmd->Func(cmd, server_msg, lcmd->data);
516 json_object_set_new(server_msg,
"message", json_string(
"Unknown command"));
522 json_object_set_new(server_msg,
"return", json_string(
"NOK"));
525 json_object_set_new(server_msg,
"return", json_string(
"OK"));
529 if (UnixCommandSendJSONToClient(client, server_msg) != 0) {
533 json_decref(jsoncmd);
534 json_decref(server_msg);
538 json_decref(jsoncmd);
540 json_decref(server_msg);
541 UnixCommandClose(
this, client->fd);
545 static void UnixCommandRun(UnixCommand *
this, UnixClient *client)
549 if (client->version <= UNIX_PROTO_V1) {
550 ret = recv(client->fd, buffer,
sizeof(buffer) - 1, 0);
553 SCLogDebug(
"Unix socket: lost connection with client");
558 UnixCommandClose(
this, client->fd);
561 if (ret >= (
int)(
sizeof(buffer)-1)) {
564 UnixCommandClose(
this, client->fd);
571 ret = recv(client->fd, buffer +
offset,
sizeof(buffer) -
offset - 1, 0);
575 SCLogDebug(
"Unix socket: lost connection with client");
580 UnixCommandClose(
this, client->fd);
583 if (ret >= (
int)(
sizeof(buffer)-
offset - 1)) {
584 SCLogInfo(
"Command server: client command is too long, "
586 UnixCommandClose(
this, client->fd);
588 if (buffer[ret - 1] ==
'\n') {
596 FD_ZERO(&select_set);
597 FD_SET(client->fd, &select_set);
599 tv.tv_usec = 200 * 1000;
601 ret = select(client->fd, &select_set, NULL, NULL, &
tv);
605 if (errno != EINTR) {
606 SCLogInfo(
"Unix socket: lost connection with client");
607 UnixCommandClose(
this, client->fd);
611 }
while (ret == 0 &&
try < 3);
613 ret = recv(client->fd, buffer +
offset,
614 sizeof(buffer) -
offset - 1, 0);
617 }
while (
try < 3 && cmd_over == 0);
619 if (
try == 3 && cmd_over == 0) {
620 SCLogInfo(
"Unix socket: imcomplete client message, closing connection");
621 UnixCommandClose(
this, client->fd);
625 UnixCommandExecute(
this, buffer, client);
633 static int UnixMain(UnixCommand *
this)
642 FD_ZERO(&select_set);
643 FD_SET(this->socket, &select_set);
645 FD_SET(uclient->fd, &select_set);
649 tv.tv_usec = 200 * 1000;
650 ret = select(this->select_max, &select_set, NULL, NULL, &
tv);
655 if (errno == EINTR) {
664 UnixCommandClose(
this, uclient->fd);
675 if (FD_ISSET(uclient->fd, &select_set)) {
676 UnixCommandRun(
this, uclient);
679 if (FD_ISSET(this->socket, &select_set)) {
680 if (!UnixCommandAccept(
this))
687 static TmEcode UnixManagerShutdownCommand(json_t *cmd,
688 json_t *server_msg,
void *data)
691 json_object_set_new(server_msg,
"message", json_string(
"Closing Suricata"));
696 static TmEcode UnixManagerVersionCommand(json_t *cmd,
697 json_t *server_msg,
void *data)
704 static TmEcode UnixManagerUptimeCommand(json_t *cmd,
705 json_t *server_msg,
void *data)
709 UnixCommand *ucmd = (UnixCommand *)data;
711 uptime = time(NULL) - ucmd->start_timestamp;
712 json_object_set_new(server_msg,
"message", json_integer(uptime));
716 static TmEcode UnixManagerRunningModeCommand(json_t *cmd,
717 json_t *server_msg,
void *data)
720 json_object_set_new(server_msg,
"message", json_string(
RunmodeGetActive()));
724 static TmEcode UnixManagerCaptureModeCommand(json_t *cmd,
725 json_t *server_msg,
void *data)
732 static TmEcode UnixManagerReloadRulesWrapper(json_t *cmd, json_t *server_msg,
void *data,
int do_wait)
737 json_object_set_new(server_msg,
"message",
738 json_string(
"Live rule reload not possible if -s "
739 "or -S option used at runtime."));
745 if (r == 0 && do_wait) {
750 json_object_set_new(server_msg,
"message", json_string(
"Reload already in progress"));
755 json_object_set_new(server_msg,
"message", json_string(
"done"));
759 static TmEcode UnixManagerReloadRules(json_t *cmd, json_t *server_msg,
void *data)
761 return UnixManagerReloadRulesWrapper(cmd, server_msg, data, 1);
764 static TmEcode UnixManagerNonBlockingReloadRules(json_t *cmd, json_t *server_msg,
void *data)
766 return UnixManagerReloadRulesWrapper(cmd, server_msg, data, 0);
769 static TmEcode UnixManagerReloadTimeCommand(json_t *cmd,
770 json_t *server_msg,
void *data)
774 json_t *jdata = NULL;
777 json_object_set_new(server_msg,
"message", jdata);
781 static TmEcode UnixManagerRulesetStatsCommand(json_t *cmd,
782 json_t *server_msg,
void *data)
786 json_t *jdata = NULL;
789 json_object_set_new(server_msg,
"message", jdata);
793 static TmEcode UnixManagerShowFailedRules(json_t *cmd,
794 json_t *server_msg,
void *data)
800 json_object_set_new(server_msg,
"message", json_string(
"Unable to get info"));
806 json_t *js_sigs_array = json_array();
808 if (js_sigs_array == NULL) {
809 json_object_set_new(server_msg,
"message", json_string(
"Unable to get info"));
815 json_t *jdata = json_object();
817 json_object_set_new(server_msg,
"message", json_string(
"Unable to get the sig"));
821 json_object_set_new(jdata,
"tenant_id", json_integer(list->
tenant_id));
822 json_object_set_new(jdata,
"rule", json_string(sigs_str->
sig_str));
823 json_object_set_new(jdata,
"filename", json_string(sigs_str->
filename));
824 json_object_set_new(jdata,
"line", json_integer(sigs_str->
line));
826 json_object_set_new(jdata,
"error", json_string(sigs_str->
sig_error));
828 json_array_append_new(js_sigs_array, jdata);
829 if (++rules_cnt > MAX_FAILED_RULES) {
833 if (rules_cnt > MAX_FAILED_RULES) {
839 json_object_set_new(server_msg,
"message", js_sigs_array);
845 json_object_clear(js_sigs_array);
846 json_decref(js_sigs_array);
850 static TmEcode UnixManagerConfGetCommand(json_t *cmd,
851 json_t *server_msg,
void *data)
855 const char *confval = NULL;
856 char *variable = NULL;
858 json_t *jarg = json_object_get(cmd,
"variable");
859 if(!json_is_string(jarg)) {
860 SCLogInfo(
"error: variable is not a string");
861 json_object_set_new(server_msg,
"message", json_string(
"variable is not a string"));
865 variable = (
char *)json_string_value(jarg);
866 if (
ConfGet(variable, &confval) != 1) {
867 json_object_set_new(server_msg,
"message", json_string(
"Unable to get value"));
872 json_object_set_new(server_msg,
"message", json_string(confval));
876 json_object_set_new(server_msg,
"message", json_string(
"No string value"));
880 static TmEcode UnixManagerListCommand(json_t *cmd,
881 json_t *answer,
void *data)
886 Command *lcmd = NULL;
887 UnixCommand *gcmd = (UnixCommand *) data;
890 jdata = json_object();
892 json_object_set_new(answer,
"message",
893 json_string(
"internal error at json object creation"));
896 jarray = json_array();
897 if (jarray == NULL) {
898 json_object_set_new(answer,
"message",
899 json_string(
"internal error at json object creation"));
904 json_array_append_new(jarray, json_string(lcmd->name));
908 json_object_set_new(jdata,
"count", json_integer(i));
909 json_object_set_new(jdata,
"commands", jarray);
910 json_object_set_new(answer,
"message", jdata);
914 static TmEcode UnixManagerReopenLogFiles(json_t *cmd, json_t *server_msg,
void *data)
917 json_object_set_new(server_msg,
"message", json_string(
"done"));
922 TmEcode UnixManagerReloadRules(json_t *cmd,
923 json_t *server_msg,
void *data)
927 json_object_set_new(server_msg,
"message",
928 json_string(
"Live rule swap no longer possible."
929 " Engine in shutdown mode."));
934 DetectEngineSpawnLiveRuleSwapMgmtThread();
935 json_object_set_new(server_msg,
"message", json_string(
"Reloading rules"));
941 static UnixCommand command;
959 TmEcode UnixManagerRegisterCommand(
const char * keyword,
960 TmEcode (*Func)(json_t *, json_t *,
void *),
961 void *data,
int flags)
965 Command *lcmd = NULL;
972 if (keyword == NULL) {
978 if (!strcmp(keyword, lcmd->name)) {
1014 TmEcode UnixManagerRegisterBackgroundTask(
TmEcode (*Func)(
void *),
1040 if (UnixNew(&command) == 0) {
1041 int failure_fatal = 0;
1042 if (
ConfGetBool(
"engine.init-failure-fatal", &failure_fatal) != 1) {
1043 SCLogDebug(
"ConfGetBool could not load the value.");
1045 if (failure_fatal) {
1047 "Unable to create unix command socket");
1050 "Unable to create unix command socket");
1056 UnixManagerRegisterCommand(
"shutdown", UnixManagerShutdownCommand, NULL, 0);
1057 UnixManagerRegisterCommand(
"command-list", UnixManagerListCommand, &command, 0);
1058 UnixManagerRegisterCommand(
"help", UnixManagerListCommand, &command, 0);
1059 UnixManagerRegisterCommand(
"version", UnixManagerVersionCommand, &command, 0);
1060 UnixManagerRegisterCommand(
"uptime", UnixManagerUptimeCommand, &command, 0);
1061 UnixManagerRegisterCommand(
"running-mode", UnixManagerRunningModeCommand, &command, 0);
1062 UnixManagerRegisterCommand(
"capture-mode", UnixManagerCaptureModeCommand, &command, 0);
1063 UnixManagerRegisterCommand(
"conf-get", UnixManagerConfGetCommand, &command,
UNIX_CMD_TAKE_ARGS);
1064 UnixManagerRegisterCommand(
"dump-counters", StatsOutputCounterSocket, NULL, 0);
1065 UnixManagerRegisterCommand(
"reload-rules", UnixManagerReloadRules, NULL, 0);
1066 UnixManagerRegisterCommand(
"ruleset-reload-rules", UnixManagerReloadRules, NULL, 0);
1067 UnixManagerRegisterCommand(
"ruleset-reload-nonblocking", UnixManagerNonBlockingReloadRules, NULL, 0);
1068 UnixManagerRegisterCommand(
"ruleset-reload-time", UnixManagerReloadTimeCommand, NULL, 0);
1069 UnixManagerRegisterCommand(
"ruleset-stats", UnixManagerRulesetStatsCommand, NULL, 0);
1070 UnixManagerRegisterCommand(
"ruleset-failed-rules", UnixManagerShowFailedRules, NULL, 0);
1071 UnixManagerRegisterCommand(
"register-tenant-handler", UnixSocketRegisterTenantHandler, &command,
UNIX_CMD_TAKE_ARGS);
1072 UnixManagerRegisterCommand(
"unregister-tenant-handler", UnixSocketUnregisterTenantHandler, &command,
UNIX_CMD_TAKE_ARGS);
1073 UnixManagerRegisterCommand(
"register-tenant", UnixSocketRegisterTenant, &command,
UNIX_CMD_TAKE_ARGS);
1074 UnixManagerRegisterCommand(
"reload-tenant", UnixSocketReloadTenant, &command,
UNIX_CMD_TAKE_ARGS);
1075 UnixManagerRegisterCommand(
"unregister-tenant", UnixSocketUnregisterTenant, &command,
UNIX_CMD_TAKE_ARGS);
1076 UnixManagerRegisterCommand(
"add-hostbit", UnixSocketHostbitAdd, &command,
UNIX_CMD_TAKE_ARGS);
1077 UnixManagerRegisterCommand(
"remove-hostbit", UnixSocketHostbitRemove, &command,
UNIX_CMD_TAKE_ARGS);
1078 UnixManagerRegisterCommand(
"list-hostbit", UnixSocketHostbitList, &command,
UNIX_CMD_TAKE_ARGS);
1079 UnixManagerRegisterCommand(
"reopen-log-files", UnixManagerReopenLogFiles, NULL, 0);
1080 UnixManagerRegisterCommand(
"memcap-set", UnixSocketSetMemcap, &command,
UNIX_CMD_TAKE_ARGS);
1081 UnixManagerRegisterCommand(
"memcap-show", UnixSocketShowMemcap, &command,
UNIX_CMD_TAKE_ARGS);
1082 UnixManagerRegisterCommand(
"memcap-list", UnixSocketShowAllMemcap, NULL, 0);
1084 UnixManagerRegisterCommand(
"dataset-add", UnixSocketDatasetAdd, &command,
UNIX_CMD_TAKE_ARGS);
1085 UnixManagerRegisterCommand(
"dataset-remove", UnixSocketDatasetRemove, &command,
UNIX_CMD_TAKE_ARGS);
1090 typedef struct UnixManagerThreadData_ {
1092 } UnixManagerThreadData;
1094 static TmEcode UnixManagerThreadInit(
ThreadVars *t,
const void *initdata,
void **data)
1096 UnixManagerThreadData *utd =
SCCalloc(1,
sizeof(*utd));
1125 ret = UnixMain(&command);
1141 UnixCommandBackgroundTasks(&command);
1161 if (tv_unixmgr == NULL) {
1180 if (unix_socket == 1) {
1182 UnixManagerRegisterCommand(
"iface-stat", LiveDeviceIfaceStat, NULL,
1184 UnixManagerRegisterCommand(
"iface-list", LiveDeviceIfaceList, NULL, 0);
1185 UnixManagerRegisterCommand(
"iface-bypassed-stat",
1186 LiveDeviceGetBypassedStats, NULL, 0);
1188 UnixManagerRegisterCommand(
"ebpf-bypassed-stat",
1189 LiveDeviceGetBypassedStats, NULL, 0);
1211 while (
tv != NULL) {
1212 if (strcasecmp(
tv->
name,
"UnixManagerThread") == 0) {
1261 #if defined(BUILD_UNIX_SOCKET) && defined(HAVE_SYS_UN_H) && defined(HAVE_SYS_STAT_H) && defined(HAVE_SYS_TYPES_H)