45 #if (defined BUILD_UNIX_SOCKET) && (defined HAVE_SYS_UN_H) && (defined HAVE_SYS_STAT_H) && (defined HAVE_SYS_TYPES_H)
48 #include <sys/types.h>
56 # define MSG_NOSIGNAL SO_NOSIGPIPE
60 #define SOCKET_PATH LOCAL_STATE_DIR "/run/suricata/"
61 #define SOCKET_FILENAME "suricata-command.socket"
62 #define SOCKET_TARGET SOCKET_PATH SOCKET_FILENAME
67 #define MAX_FAILED_RULES 20
69 typedef struct Command_ {
71 TmEcode (*Func)(json_t *, json_t *,
void *);
77 typedef struct Task_ {
83 #define CLIENT_BUFFER_SIZE 4096
84 typedef struct UnixClient_ {
91 typedef struct UnixCommand_ {
92 time_t start_timestamp;
94 struct sockaddr_un client_addr;
96 char sockettarget[PATH_MAX];
107 static int UnixNew(UnixCommand *
this)
109 struct sockaddr_un addr;
113 char sockettarget[PATH_MAX];
114 const char *socketname;
116 this->start_timestamp = time(NULL);
118 this->select_max = 0;
127 strlcpy(sockettarget, socketname,
sizeof(sockettarget));
129 snprintf(sockettarget,
sizeof(sockettarget),
"%s/%s",
130 SOCKET_PATH, socketname);
134 strlcpy(sockettarget, SOCKET_TARGET,
sizeof(sockettarget));
139 strlcpy(this->sockettarget, sockettarget,
sizeof(this->sockettarget));
141 SCLogInfo(
"unix socket '%s'", sockettarget);
144 struct stat stat_buf;
146 if (stat(SOCKET_PATH, &stat_buf) != 0) {
148 ret =
SCMkDir(SOCKET_PATH, S_IRWXU|S_IXGRP|S_IRGRP);
153 "failed to create socket directory %s: %s", SOCKET_PATH, strerror(err));
157 SCLogInfo(
"created socket directory %s", SOCKET_PATH);
163 (void) unlink(sockettarget);
166 addr.sun_family = AF_UNIX;
167 strlcpy(addr.sun_path, sockettarget,
sizeof(addr.sun_path));
168 addr.sun_path[
sizeof(addr.sun_path) - 1] = 0;
169 len = (socklen_t)(strlen(addr.sun_path) +
sizeof(addr.sun_family) + 1);
172 this->socket = socket(AF_UNIX, SOCK_STREAM, 0);
173 if (this->socket == -1) {
175 "Unix Socket: unable to create UNIX socket %s: %s", addr.sun_path, strerror(errno));
178 this->select_max = this->socket + 1;
181 ret = setsockopt(this->socket, SOL_SOCKET, SO_REUSEADDR,
182 (
char *) &on,
sizeof(on));
184 SCLogWarning(
"Cannot set sockets options: %s.", strerror(errno));
188 ret = bind(this->socket, (
struct sockaddr *) &addr,
len);
190 SCLogWarning(
"Unix socket: UNIX socket bind(%s) error: %s", sockettarget, strerror(errno));
194 #if !(defined OS_FREEBSD || defined __OpenBSD__)
198 ret = chmod(sockettarget, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP);
201 SCLogWarning(
"Unable to change permission on socket: %s (%d)", strerror(err), err);
206 if (listen(this->socket, 1) == -1) {
207 SCLogWarning(
"Command server: UNIX socket listen() error: %s", strerror(errno));
213 static void UnixCommandSetMaxFD(UnixCommand *
this)
218 SCLogError(
"Unix command is NULL, warn devel");
222 this->select_max = this->socket + 1;
224 if (item->fd >= this->select_max) {
225 this->select_max = item->fd + 1;
230 static UnixClient *UnixClientAlloc(
void)
232 UnixClient *uclient =
SCMalloc(
sizeof(UnixClient));
238 if (uclient->mbuf == NULL) {
239 SCLogError(
"Can't allocate new client send buffer");
246 static void UnixClientFree(UnixClient *c)
257 static void UnixCommandClose(UnixCommand *
this,
int fd)
260 UnixClient *safe = NULL;
264 if (item->fd == fd) {
278 UnixCommandSetMaxFD(
this);
279 UnixClientFree(item);
282 #define UNIX_PROTO_VERSION_LENGTH 200
283 #define UNIX_PROTO_VERSION_V1 "0.1"
284 #define UNIX_PROTO_V1 1
285 #define UNIX_PROTO_VERSION "0.2"
286 #define UNIX_PROTO_V2 2
288 static int UnixCommandSendJSONToClient(UnixClient *client, json_t *js)
290 MemBufferReset(client->mbuf);
294 .expand_by = CLIENT_BUFFER_SIZE
298 JSON_PRESERVE_ORDER|JSON_COMPACT|JSON_ENSURE_ASCII|
305 if (client->version > UNIX_PROTO_V1) {
321 SCLogDebug(
"sent message of size %"PRIuMAX
" to client socket %d",
335 static int UnixCommandAccept(UnixCommand *
this)
337 char buffer[UNIX_PROTO_VERSION_LENGTH + 1];
345 UnixClient *uclient = NULL;
348 socklen_t
len =
sizeof(this->client_addr);
349 client = accept(this->socket, (
struct sockaddr *) &this->client_addr,
352 SCLogInfo(
"Unix socket: accept() error: %s",
359 buffer[
sizeof(buffer)-1] = 0;
360 ret = recv(client, buffer,
sizeof(buffer)-1, 0);
362 SCLogInfo(
"Command server: client doesn't send version");
366 if (ret >= (
int)(
sizeof(buffer)-1)) {
367 SCLogInfo(
"Command server: client message is too long, "
374 client_msg = json_loads(buffer, 0, &jerror);
375 if (client_msg == NULL) {
376 SCLogInfo(
"Invalid command, error on line %d: %s\n", jerror.line, jerror.text);
381 version = json_object_get(client_msg,
"version");
382 if (!json_is_string(
version)) {
383 SCLogInfo(
"error: version is not a string");
385 json_decref(client_msg);
390 if ((strcmp(json_string_value(
version), UNIX_PROTO_VERSION) != 0)
391 && (strcmp(json_string_value(
version), UNIX_PROTO_VERSION_V1) != 0)) {
392 SCLogInfo(
"Unix socket: invalid client version: \"%s\"",
394 json_decref(client_msg);
398 SCLogDebug(
"Unix socket: client version: \"%s\"",
400 if (strcmp(json_string_value(
version), UNIX_PROTO_VERSION_V1) == 0) {
401 client_version = UNIX_PROTO_V1;
403 client_version = UNIX_PROTO_V2;
407 json_decref(client_msg);
409 server_msg = json_object();
410 if (server_msg == NULL) {
414 json_object_set_new(server_msg,
"return", json_string(
"OK"));
416 uclient = UnixClientAlloc();
418 json_decref(server_msg);
422 uclient->fd = client;
423 uclient->version = client_version;
425 if (UnixCommandSendJSONToClient(uclient, server_msg) != 0) {
428 UnixClientFree(uclient);
429 json_decref(server_msg);
434 json_decref(server_msg);
439 UnixCommandSetMaxFD(
this);
443 static int UnixCommandBackgroundTasks(UnixCommand*
this)
449 int fret = ltask->Func(ltask->data);
466 static int UnixCommandExecute(UnixCommand *
this,
char *command, UnixClient *client)
470 json_t *jsoncmd = NULL;
472 json_t *server_msg = json_object();
477 if (server_msg == NULL) {
481 jsoncmd = json_loads(command, 0, &error);
482 if (jsoncmd == NULL) {
483 SCLogInfo(
"Invalid command, error on line %d: %s\n", error.line, error.text);
487 cmd = json_object_get(jsoncmd,
"command");
488 if(!json_is_string(cmd)) {
489 SCLogInfo(
"error: command is not a string");
492 value = json_string_value(cmd);
495 if (!strcmp(value, lcmd->name)) {
499 cmd = json_object_get(jsoncmd,
"arguments");
500 if(!json_is_object(cmd)) {
501 SCLogInfo(
"error: argument is not an object");
505 fret = lcmd->Func(cmd, server_msg, lcmd->data);
514 json_object_set_new(server_msg,
"message", json_string(
"Unknown command"));
520 json_object_set_new(server_msg,
"return", json_string(
"NOK"));
523 json_object_set_new(server_msg,
"return", json_string(
"OK"));
527 if (UnixCommandSendJSONToClient(client, server_msg) != 0) {
531 json_decref(jsoncmd);
532 json_decref(server_msg);
536 json_decref(jsoncmd);
538 json_decref(server_msg);
539 UnixCommandClose(
this, client->fd);
543 static void UnixCommandRun(UnixCommand *
this, UnixClient *client)
547 if (client->version <= UNIX_PROTO_V1) {
548 ret = recv(client->fd, buffer,
sizeof(buffer) - 1, 0);
551 SCLogDebug(
"Unix socket: lost connection with client");
553 SCLogError(
"Unix socket: error on recv() from client: %s", strerror(errno));
555 UnixCommandClose(
this, client->fd);
558 if (ret >= (
int)(
sizeof(buffer)-1)) {
559 SCLogError(
"Command server: client command is too long, "
561 UnixCommandClose(
this, client->fd);
569 ret = recv(client->fd, buffer +
offset,
sizeof(buffer) -
offset - 1, 0);
573 SCLogDebug(
"Unix socket: lost connection with client");
575 SCLogError(
"Unix socket: error on recv() from client: %s", strerror(errno));
577 UnixCommandClose(
this, client->fd);
580 if (ret >= (
int)(
sizeof(buffer)-
offset - 1)) {
581 SCLogInfo(
"Command server: client command is too long, "
583 UnixCommandClose(
this, client->fd);
586 if (buffer[ret - 1] ==
'\n') {
594 FD_ZERO(&select_set);
595 FD_SET(client->fd, &select_set);
597 tv.tv_usec = 200 * 1000;
599 ret = select(client->fd, &select_set, NULL, NULL, &
tv);
603 if (errno != EINTR) {
604 SCLogInfo(
"Unix socket: lost connection with client");
605 UnixCommandClose(
this, client->fd);
609 }
while (ret == 0 &&
try < 3);
611 ret = recv(client->fd, buffer +
offset,
612 sizeof(buffer) -
offset - 1, 0);
615 }
while (
try < 3 && cmd_over == 0);
617 if (
try == 3 && cmd_over == 0) {
618 SCLogInfo(
"Unix socket: incomplete client message, closing connection");
619 UnixCommandClose(
this, client->fd);
623 UnixCommandExecute(
this, buffer, client);
631 static int UnixMain(UnixCommand *
this)
641 UnixCommandClose(
this, uclient->fd);
647 FD_ZERO(&select_set);
648 FD_SET(this->socket, &select_set);
650 FD_SET(uclient->fd, &select_set);
654 tv.tv_usec = 200 * 1000;
655 ret = select(this->select_max, &select_set, NULL, NULL, &
tv);
660 if (errno == EINTR) {
663 SCLogError(
"Command server: select() fatal error: %s", strerror(errno));
673 if (FD_ISSET(uclient->fd, &select_set)) {
674 UnixCommandRun(
this, uclient);
677 if (FD_ISSET(this->socket, &select_set)) {
678 if (!UnixCommandAccept(
this))
685 static TmEcode UnixManagerShutdownCommand(json_t *cmd,
686 json_t *server_msg,
void *data)
689 json_object_set_new(server_msg,
"message", json_string(
"Closing Suricata"));
694 static TmEcode UnixManagerVersionCommand(json_t *cmd,
695 json_t *server_msg,
void *data)
702 static TmEcode UnixManagerUptimeCommand(json_t *cmd,
703 json_t *server_msg,
void *data)
707 UnixCommand *ucmd = (UnixCommand *)data;
709 uptime = time(NULL) - ucmd->start_timestamp;
710 json_object_set_new(server_msg,
"message", json_integer(uptime));
714 static TmEcode UnixManagerRunningModeCommand(json_t *cmd,
715 json_t *server_msg,
void *data)
718 json_object_set_new(server_msg,
"message", json_string(
RunmodeGetActive()));
722 static TmEcode UnixManagerCaptureModeCommand(json_t *cmd,
723 json_t *server_msg,
void *data)
730 static TmEcode UnixManagerReloadRulesWrapper(json_t *cmd, json_t *server_msg,
void *data,
int do_wait)
735 json_object_set_new(server_msg,
"message",
736 json_string(
"Live rule reload not possible if -s "
737 "or -S option used at runtime."));
743 if (r == 0 && do_wait) {
748 json_object_set_new(server_msg,
"message", json_string(
"Reload already in progress"));
753 json_object_set_new(server_msg,
"message", json_string(
"done"));
757 static TmEcode UnixManagerReloadRules(json_t *cmd, json_t *server_msg,
void *data)
759 return UnixManagerReloadRulesWrapper(cmd, server_msg, data, 1);
762 static TmEcode UnixManagerNonBlockingReloadRules(json_t *cmd, json_t *server_msg,
void *data)
764 return UnixManagerReloadRulesWrapper(cmd, server_msg, data, 0);
767 static TmEcode UnixManagerReloadTimeCommand(json_t *cmd,
768 json_t *server_msg,
void *data)
772 json_t *jdata = NULL;
775 json_object_set_new(server_msg,
"message", jdata);
779 static TmEcode UnixManagerRulesetStatsCommand(json_t *cmd,
780 json_t *server_msg,
void *data)
784 json_t *jdata = NULL;
787 json_object_set_new(server_msg,
"message", jdata);
792 static TmEcode UnixManagerRulesetProfileCommand(json_t *cmd, json_t *server_msg,
void *data)
797 json_t *js = SCProfileRuleTriggerDump(
de_ctx);
799 json_object_set_new(server_msg,
"message", json_string(
"NOK"));
802 json_object_set_new(server_msg,
"message", js);
806 static TmEcode UnixManagerRulesetProfileStartCommand(json_t *cmd, json_t *server_msg,
void *data)
810 json_object_set_new(server_msg,
"message", json_string(
"OK"));
814 static TmEcode UnixManagerRulesetProfileStopCommand(json_t *cmd, json_t *server_msg,
void *data)
818 json_object_set_new(server_msg,
"message", json_string(
"OK"));
823 static TmEcode UnixManagerShowFailedRules(json_t *cmd,
824 json_t *server_msg,
void *data)
830 json_object_set_new(server_msg,
"message", json_string(
"Unable to get info"));
836 json_t *js_sigs_array = json_array();
838 if (js_sigs_array == NULL) {
839 json_object_set_new(server_msg,
"message", json_string(
"Unable to get info"));
845 json_t *jdata = json_object();
847 json_object_set_new(server_msg,
"message", json_string(
"Unable to get the sig"));
851 json_object_set_new(jdata,
"tenant_id", json_integer(list->
tenant_id));
852 json_object_set_new(jdata,
"rule", json_string(sigs_str->
sig_str));
853 json_object_set_new(jdata,
"filename", json_string(sigs_str->
filename));
854 json_object_set_new(jdata,
"line", json_integer(sigs_str->
line));
856 json_object_set_new(jdata,
"error", json_string(sigs_str->
sig_error));
858 json_array_append_new(js_sigs_array, jdata);
859 if (++rules_cnt > MAX_FAILED_RULES) {
863 if (rules_cnt > MAX_FAILED_RULES) {
869 json_object_set_new(server_msg,
"message", js_sigs_array);
875 json_object_clear(js_sigs_array);
876 json_decref(js_sigs_array);
880 static TmEcode UnixManagerConfGetCommand(json_t *cmd,
881 json_t *server_msg,
void *data)
885 const char *confval = NULL;
886 char *variable = NULL;
888 json_t *jarg = json_object_get(cmd,
"variable");
889 if(!json_is_string(jarg)) {
890 SCLogInfo(
"error: variable is not a string");
891 json_object_set_new(server_msg,
"message", json_string(
"variable is not a string"));
895 variable = (
char *)json_string_value(jarg);
897 json_object_set_new(server_msg,
"message", json_string(
"Unable to get value"));
902 json_object_set_new(server_msg,
"message", json_string(confval));
906 json_object_set_new(server_msg,
"message", json_string(
"No string value"));
910 static TmEcode UnixManagerListCommand(json_t *cmd,
911 json_t *answer,
void *data)
916 Command *lcmd = NULL;
917 UnixCommand *gcmd = (UnixCommand *) data;
920 jdata = json_object();
922 json_object_set_new(answer,
"message",
923 json_string(
"internal error at json object creation"));
926 jarray = json_array();
927 if (jarray == NULL) {
928 json_object_set_new(answer,
"message",
929 json_string(
"internal error at json object creation"));
934 json_array_append_new(jarray, json_string(lcmd->name));
938 json_object_set_new(jdata,
"count", json_integer(i));
939 json_object_set_new(jdata,
"commands", jarray);
940 json_object_set_new(answer,
"message", jdata);
944 static TmEcode UnixManagerReopenLogFiles(json_t *cmd, json_t *server_msg,
void *data)
947 json_object_set_new(server_msg,
"message", json_string(
"done"));
952 TmEcode UnixManagerReloadRules(json_t *cmd,
953 json_t *server_msg,
void *data)
957 json_object_set_new(server_msg,
"message",
958 json_string(
"Live rule swap no longer possible."
959 " Engine in shutdown mode."));
964 DetectEngineSpawnLiveRuleSwapMgmtThread();
965 json_object_set_new(server_msg,
"message", json_string(
"Reloading rules"));
971 static UnixCommand command;
989 TmEcode UnixManagerRegisterCommand(
const char * keyword,
990 TmEcode (*Func)(json_t *, json_t *,
void *),
991 void *data,
int flags)
995 Command *lcmd = NULL;
1002 if (keyword == NULL) {
1008 if (!strcmp(keyword, lcmd->name)) {
1009 SCLogError(
"%s already registered", keyword);
1044 TmEcode UnixManagerRegisterBackgroundTask(
TmEcode (*Func)(
void *),
1070 if (UnixNew(&command) == 0) {
1071 int failure_fatal = 0;
1072 if (
SCConfGetBool(
"engine.init-failure-fatal", &failure_fatal) != 1) {
1073 SCLogDebug(
"ConfGetBool could not load the value.");
1075 if (failure_fatal) {
1076 FatalError(
"Unable to create unix command socket");
1084 UnixManagerRegisterCommand(
"shutdown", UnixManagerShutdownCommand, NULL, 0);
1085 UnixManagerRegisterCommand(
"command-list", UnixManagerListCommand, &command, 0);
1086 UnixManagerRegisterCommand(
"help", UnixManagerListCommand, &command, 0);
1087 UnixManagerRegisterCommand(
"version", UnixManagerVersionCommand, &command, 0);
1088 UnixManagerRegisterCommand(
"uptime", UnixManagerUptimeCommand, &command, 0);
1089 UnixManagerRegisterCommand(
"running-mode", UnixManagerRunningModeCommand, &command, 0);
1090 UnixManagerRegisterCommand(
"capture-mode", UnixManagerCaptureModeCommand, &command, 0);
1091 UnixManagerRegisterCommand(
"conf-get", UnixManagerConfGetCommand, &command,
UNIX_CMD_TAKE_ARGS);
1092 UnixManagerRegisterCommand(
"dump-counters", StatsOutputCounterSocket, NULL, 0);
1093 UnixManagerRegisterCommand(
"reload-rules", UnixManagerReloadRules, NULL, 0);
1094 UnixManagerRegisterCommand(
"ruleset-reload-rules", UnixManagerReloadRules, NULL, 0);
1095 UnixManagerRegisterCommand(
"ruleset-reload-nonblocking", UnixManagerNonBlockingReloadRules, NULL, 0);
1096 UnixManagerRegisterCommand(
"ruleset-reload-time", UnixManagerReloadTimeCommand, NULL, 0);
1097 UnixManagerRegisterCommand(
"ruleset-stats", UnixManagerRulesetStatsCommand, NULL, 0);
1098 UnixManagerRegisterCommand(
"ruleset-failed-rules", UnixManagerShowFailedRules, NULL, 0);
1099 #ifdef PROFILE_RULES
1100 UnixManagerRegisterCommand(
"ruleset-profile", UnixManagerRulesetProfileCommand, NULL, 0);
1101 UnixManagerRegisterCommand(
1102 "ruleset-profile-start", UnixManagerRulesetProfileStartCommand, NULL, 0);
1103 UnixManagerRegisterCommand(
1104 "ruleset-profile-stop", UnixManagerRulesetProfileStopCommand, NULL, 0);
1106 UnixManagerRegisterCommand(
"register-tenant-handler", UnixSocketRegisterTenantHandler, &command,
UNIX_CMD_TAKE_ARGS);
1107 UnixManagerRegisterCommand(
"unregister-tenant-handler", UnixSocketUnregisterTenantHandler, &command,
UNIX_CMD_TAKE_ARGS);
1108 UnixManagerRegisterCommand(
"register-tenant", UnixSocketRegisterTenant, &command,
UNIX_CMD_TAKE_ARGS);
1109 UnixManagerRegisterCommand(
"reload-tenant", UnixSocketReloadTenant, &command,
UNIX_CMD_TAKE_ARGS);
1110 UnixManagerRegisterCommand(
"reload-tenants", UnixSocketReloadTenants, &command, 0);
1111 UnixManagerRegisterCommand(
"unregister-tenant", UnixSocketUnregisterTenant, &command,
UNIX_CMD_TAKE_ARGS);
1112 UnixManagerRegisterCommand(
"add-hostbit", UnixSocketHostbitAdd, &command,
UNIX_CMD_TAKE_ARGS);
1113 UnixManagerRegisterCommand(
"remove-hostbit", UnixSocketHostbitRemove, &command,
UNIX_CMD_TAKE_ARGS);
1114 UnixManagerRegisterCommand(
"list-hostbit", UnixSocketHostbitList, &command,
UNIX_CMD_TAKE_ARGS);
1115 UnixManagerRegisterCommand(
"reopen-log-files", UnixManagerReopenLogFiles, NULL, 0);
1116 UnixManagerRegisterCommand(
"memcap-set", UnixSocketSetMemcap, &command,
UNIX_CMD_TAKE_ARGS);
1117 UnixManagerRegisterCommand(
"memcap-show", UnixSocketShowMemcap, &command,
UNIX_CMD_TAKE_ARGS);
1118 UnixManagerRegisterCommand(
"memcap-list", UnixSocketShowAllMemcap, NULL, 0);
1120 UnixManagerRegisterCommand(
"dataset-add", UnixSocketDatasetAdd, &command,
UNIX_CMD_TAKE_ARGS);
1121 UnixManagerRegisterCommand(
"dataset-remove", UnixSocketDatasetRemove, &command,
UNIX_CMD_TAKE_ARGS);
1122 UnixManagerRegisterCommand(
1124 UnixManagerRegisterCommand(
1126 UnixManagerRegisterCommand(
"dataset-dump", UnixSocketDatasetDump, NULL, 0);
1127 UnixManagerRegisterCommand(
1129 UnixManagerRegisterCommand(
1135 typedef struct UnixManagerThreadData_ {
1137 } UnixManagerThreadData;
1139 static TmEcode UnixManagerThreadInit(
ThreadVars *t,
const void *initdata,
void **data)
1141 UnixManagerThreadData *utd =
SCCalloc(1,
sizeof(*utd));
1167 int ret = UnixMain(&command);
1186 if (command.socket != -1) {
1187 close(command.socket);
1188 command.socket = -1;
1189 if (unlink(command.sockettarget) != 0 && errno != ENOENT) {
1190 SCLogWarning(
"unable to remove unix socket file %s: %s", command.sockettarget,
1193 SCLogDebug(
"unix socket file '%s' removed", command.sockettarget);
1195 SCLogInfo(
"unix socket '%s' closed", command.sockettarget);
1202 UnixCommandBackgroundTasks(&command);
1221 if (tv_unixmgr == NULL) {
1240 UnixManagerRegisterCommand(
"iface-stat", LiveDeviceIfaceStat, NULL,
1242 UnixManagerRegisterCommand(
"iface-list", LiveDeviceIfaceList, NULL, 0);
1243 UnixManagerRegisterCommand(
"iface-bypassed-stat",
1244 LiveDeviceGetBypassedStats, NULL, 0);
1246 UnixManagerRegisterCommand(
"ebpf-bypassed-stat",
1247 LiveDeviceGetBypassedStats, NULL, 0);
1269 while (
tv != NULL) {
1270 if (strcasecmp(
tv->
name,
"UnixManagerThread") == 0) {
1315 #if defined(BUILD_UNIX_SOCKET) && defined(HAVE_SYS_UN_H) && defined(HAVE_SYS_STAT_H) && defined(HAVE_SYS_TYPES_H)