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;
106 static int UnixNew(UnixCommand *
this)
108 struct sockaddr_un addr;
112 char sockettarget[PATH_MAX];
113 const char *socketname;
115 this->start_timestamp = time(NULL);
117 this->select_max = 0;
124 if (
ConfGet(
"unix-command.filename", &socketname) == 1) {
126 strlcpy(sockettarget, socketname,
sizeof(sockettarget));
128 snprintf(sockettarget,
sizeof(sockettarget),
"%s/%s",
129 SOCKET_PATH, socketname);
133 strlcpy(sockettarget, SOCKET_TARGET,
sizeof(sockettarget));
136 SCLogInfo(
"unix socket '%s'", sockettarget);
139 struct stat stat_buf;
141 if (stat(SOCKET_PATH, &stat_buf) != 0) {
143 ret =
SCMkDir(SOCKET_PATH, S_IRWXU|S_IXGRP|S_IRGRP);
148 "failed to create socket directory %s: %s", SOCKET_PATH, strerror(err));
152 SCLogInfo(
"created socket directory %s", SOCKET_PATH);
158 (void) unlink(sockettarget);
161 addr.sun_family = AF_UNIX;
162 strlcpy(addr.sun_path, sockettarget,
sizeof(addr.sun_path));
163 addr.sun_path[
sizeof(addr.sun_path) - 1] = 0;
164 len = strlen(addr.sun_path) +
sizeof(addr.sun_family) + 1;
167 this->socket = socket(AF_UNIX, SOCK_STREAM, 0);
168 if (this->socket == -1) {
170 "Unix Socket: unable to create UNIX socket %s: %s", addr.sun_path, strerror(errno));
173 this->select_max = this->socket + 1;
176 ret = setsockopt(this->socket, SOL_SOCKET, SO_REUSEADDR,
177 (
char *) &on,
sizeof(on));
179 SCLogWarning(
"Cannot set sockets options: %s.", strerror(errno));
183 ret = bind(this->socket, (
struct sockaddr *) &addr,
len);
185 SCLogWarning(
"Unix socket: UNIX socket bind(%s) error: %s", sockettarget, strerror(errno));
189 #if !(defined OS_FREEBSD || defined __OpenBSD__)
193 ret = chmod(sockettarget, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP);
196 SCLogWarning(
"Unable to change permission on socket: %s (%d)", strerror(err), err);
201 if (listen(this->socket, 1) == -1) {
202 SCLogWarning(
"Command server: UNIX socket listen() error: %s", strerror(errno));
208 static void UnixCommandSetMaxFD(UnixCommand *
this)
213 SCLogError(
"Unix command is NULL, warn devel");
217 this->select_max = this->socket + 1;
219 if (item->fd >= this->select_max) {
220 this->select_max = item->fd + 1;
225 static UnixClient *UnixClientAlloc(
void)
227 UnixClient *uclient =
SCMalloc(
sizeof(UnixClient));
233 if (uclient->mbuf == NULL) {
234 SCLogError(
"Can't allocate new client send buffer");
241 static void UnixClientFree(UnixClient *c)
252 static void UnixCommandClose(UnixCommand *
this,
int fd)
258 if (item->fd == fd) {
272 UnixCommandSetMaxFD(
this);
273 UnixClientFree(item);
276 #define UNIX_PROTO_VERSION_LENGTH 200
277 #define UNIX_PROTO_VERSION_V1 "0.1"
278 #define UNIX_PROTO_V1 1
279 #define UNIX_PROTO_VERSION "0.2"
280 #define UNIX_PROTO_V2 2
282 static int UnixCommandSendJSONToClient(UnixClient *client, json_t *js)
284 MemBufferReset(client->mbuf);
288 .expand_by = CLIENT_BUFFER_SIZE
292 JSON_PRESERVE_ORDER|JSON_COMPACT|JSON_ENSURE_ASCII|
299 if (client->version > UNIX_PROTO_V1) {
315 SCLogDebug(
"sent message of size %"PRIuMAX
" to client socket %d",
329 static int UnixCommandAccept(UnixCommand *
this)
331 char buffer[UNIX_PROTO_VERSION_LENGTH + 1];
339 UnixClient *uclient = NULL;
342 socklen_t
len =
sizeof(this->client_addr);
343 client = accept(this->socket, (
struct sockaddr *) &this->client_addr,
346 SCLogInfo(
"Unix socket: accept() error: %s",
353 buffer[
sizeof(buffer)-1] = 0;
354 ret = recv(client, buffer,
sizeof(buffer)-1, 0);
356 SCLogInfo(
"Command server: client doesn't send version");
360 if (ret >= (
int)(
sizeof(buffer)-1)) {
361 SCLogInfo(
"Command server: client message is too long, "
368 client_msg = json_loads(buffer, 0, &jerror);
369 if (client_msg == NULL) {
370 SCLogInfo(
"Invalid command, error on line %d: %s\n", jerror.line, jerror.text);
375 version = json_object_get(client_msg,
"version");
376 if (!json_is_string(
version)) {
377 SCLogInfo(
"error: version is not a string");
379 json_decref(client_msg);
384 if ((strcmp(json_string_value(
version), UNIX_PROTO_VERSION) != 0)
385 && (strcmp(json_string_value(
version), UNIX_PROTO_VERSION_V1) != 0)) {
386 SCLogInfo(
"Unix socket: invalid client version: \"%s\"",
388 json_decref(client_msg);
392 SCLogDebug(
"Unix socket: client version: \"%s\"",
394 if (strcmp(json_string_value(
version), UNIX_PROTO_VERSION_V1) == 0) {
395 client_version = UNIX_PROTO_V1;
397 client_version = UNIX_PROTO_V2;
401 json_decref(client_msg);
403 server_msg = json_object();
404 if (server_msg == NULL) {
408 json_object_set_new(server_msg,
"return", json_string(
"OK"));
410 uclient = UnixClientAlloc();
412 json_decref(server_msg);
416 uclient->fd = client;
417 uclient->version = client_version;
419 if (UnixCommandSendJSONToClient(uclient, server_msg) != 0) {
422 UnixClientFree(uclient);
423 json_decref(server_msg);
428 json_decref(server_msg);
433 UnixCommandSetMaxFD(
this);
437 static int UnixCommandBackgroundTasks(UnixCommand*
this)
443 int fret = ltask->Func(ltask->data);
460 static int UnixCommandExecute(UnixCommand *
this,
char *command, UnixClient *client)
464 json_t *jsoncmd = NULL;
466 json_t *server_msg = json_object();
471 if (server_msg == NULL) {
475 jsoncmd = json_loads(command, 0, &error);
476 if (jsoncmd == NULL) {
477 SCLogInfo(
"Invalid command, error on line %d: %s\n", error.line, error.text);
481 cmd = json_object_get(jsoncmd,
"command");
482 if(!json_is_string(cmd)) {
483 SCLogInfo(
"error: command is not a string");
486 value = json_string_value(cmd);
489 if (!strcmp(value, lcmd->name)) {
493 cmd = json_object_get(jsoncmd,
"arguments");
494 if(!json_is_object(cmd)) {
495 SCLogInfo(
"error: argument is not an object");
499 fret = lcmd->Func(cmd, server_msg, lcmd->data);
508 json_object_set_new(server_msg,
"message", json_string(
"Unknown command"));
514 json_object_set_new(server_msg,
"return", json_string(
"NOK"));
517 json_object_set_new(server_msg,
"return", json_string(
"OK"));
521 if (UnixCommandSendJSONToClient(client, server_msg) != 0) {
525 json_decref(jsoncmd);
526 json_decref(server_msg);
530 json_decref(jsoncmd);
532 json_decref(server_msg);
533 UnixCommandClose(
this, client->fd);
537 static void UnixCommandRun(UnixCommand *
this, UnixClient *client)
541 if (client->version <= UNIX_PROTO_V1) {
542 ret = recv(client->fd, buffer,
sizeof(buffer) - 1, 0);
545 SCLogDebug(
"Unix socket: lost connection with client");
547 SCLogError(
"Unix socket: error on recv() from client: %s", strerror(errno));
549 UnixCommandClose(
this, client->fd);
552 if (ret >= (
int)(
sizeof(buffer)-1)) {
553 SCLogError(
"Command server: client command is too long, "
555 UnixCommandClose(
this, client->fd);
562 ret = recv(client->fd, buffer +
offset,
sizeof(buffer) -
offset - 1, 0);
566 SCLogDebug(
"Unix socket: lost connection with client");
568 SCLogError(
"Unix socket: error on recv() from client: %s", strerror(errno));
570 UnixCommandClose(
this, client->fd);
573 if (ret >= (
int)(
sizeof(buffer)-
offset - 1)) {
574 SCLogInfo(
"Command server: client command is too long, "
576 UnixCommandClose(
this, client->fd);
578 if (buffer[ret - 1] ==
'\n') {
586 FD_ZERO(&select_set);
587 FD_SET(client->fd, &select_set);
589 tv.tv_usec = 200 * 1000;
591 ret = select(client->fd, &select_set, NULL, NULL, &
tv);
595 if (errno != EINTR) {
596 SCLogInfo(
"Unix socket: lost connection with client");
597 UnixCommandClose(
this, client->fd);
601 }
while (ret == 0 &&
try < 3);
603 ret = recv(client->fd, buffer +
offset,
604 sizeof(buffer) -
offset - 1, 0);
607 }
while (
try < 3 && cmd_over == 0);
609 if (
try == 3 && cmd_over == 0) {
610 SCLogInfo(
"Unix socket: incomplete client message, closing connection");
611 UnixCommandClose(
this, client->fd);
615 UnixCommandExecute(
this, buffer, client);
623 static int UnixMain(UnixCommand *
this)
633 UnixCommandClose(
this, uclient->fd);
639 FD_ZERO(&select_set);
640 FD_SET(this->socket, &select_set);
642 FD_SET(uclient->fd, &select_set);
646 tv.tv_usec = 200 * 1000;
647 ret = select(this->select_max, &select_set, NULL, NULL, &
tv);
652 if (errno == EINTR) {
655 SCLogError(
"Command server: select() fatal error: %s", strerror(errno));
665 if (FD_ISSET(uclient->fd, &select_set)) {
666 UnixCommandRun(
this, uclient);
669 if (FD_ISSET(this->socket, &select_set)) {
670 if (!UnixCommandAccept(
this))
677 static TmEcode UnixManagerShutdownCommand(json_t *cmd,
678 json_t *server_msg,
void *data)
681 json_object_set_new(server_msg,
"message", json_string(
"Closing Suricata"));
686 static TmEcode UnixManagerVersionCommand(json_t *cmd,
687 json_t *server_msg,
void *data)
694 static TmEcode UnixManagerUptimeCommand(json_t *cmd,
695 json_t *server_msg,
void *data)
699 UnixCommand *ucmd = (UnixCommand *)data;
701 uptime = time(NULL) - ucmd->start_timestamp;
702 json_object_set_new(server_msg,
"message", json_integer(uptime));
706 static TmEcode UnixManagerRunningModeCommand(json_t *cmd,
707 json_t *server_msg,
void *data)
710 json_object_set_new(server_msg,
"message", json_string(
RunmodeGetActive()));
714 static TmEcode UnixManagerCaptureModeCommand(json_t *cmd,
715 json_t *server_msg,
void *data)
722 static TmEcode UnixManagerReloadRulesWrapper(json_t *cmd, json_t *server_msg,
void *data,
int do_wait)
727 json_object_set_new(server_msg,
"message",
728 json_string(
"Live rule reload not possible if -s "
729 "or -S option used at runtime."));
735 if (r == 0 && do_wait) {
740 json_object_set_new(server_msg,
"message", json_string(
"Reload already in progress"));
745 json_object_set_new(server_msg,
"message", json_string(
"done"));
749 static TmEcode UnixManagerReloadRules(json_t *cmd, json_t *server_msg,
void *data)
751 return UnixManagerReloadRulesWrapper(cmd, server_msg, data, 1);
754 static TmEcode UnixManagerNonBlockingReloadRules(json_t *cmd, json_t *server_msg,
void *data)
756 return UnixManagerReloadRulesWrapper(cmd, server_msg, data, 0);
759 static TmEcode UnixManagerReloadTimeCommand(json_t *cmd,
760 json_t *server_msg,
void *data)
764 json_t *jdata = NULL;
767 json_object_set_new(server_msg,
"message", jdata);
771 static TmEcode UnixManagerRulesetStatsCommand(json_t *cmd,
772 json_t *server_msg,
void *data)
776 json_t *jdata = NULL;
779 json_object_set_new(server_msg,
"message", jdata);
784 static TmEcode UnixManagerRulesetProfileCommand(json_t *cmd, json_t *server_msg,
void *data)
789 json_t *js = SCProfileRuleTriggerDump(
de_ctx);
791 json_object_set_new(server_msg,
"message", json_string(
"NOK"));
794 json_object_set_new(server_msg,
"message", js);
798 static TmEcode UnixManagerRulesetProfileStartCommand(json_t *cmd, json_t *server_msg,
void *data)
802 json_object_set_new(server_msg,
"message", json_string(
"OK"));
806 static TmEcode UnixManagerRulesetProfileStopCommand(json_t *cmd, json_t *server_msg,
void *data)
810 json_object_set_new(server_msg,
"message", json_string(
"OK"));
815 static TmEcode UnixManagerShowFailedRules(json_t *cmd,
816 json_t *server_msg,
void *data)
822 json_object_set_new(server_msg,
"message", json_string(
"Unable to get info"));
828 json_t *js_sigs_array = json_array();
830 if (js_sigs_array == NULL) {
831 json_object_set_new(server_msg,
"message", json_string(
"Unable to get info"));
837 json_t *jdata = json_object();
839 json_object_set_new(server_msg,
"message", json_string(
"Unable to get the sig"));
843 json_object_set_new(jdata,
"tenant_id", json_integer(list->
tenant_id));
844 json_object_set_new(jdata,
"rule", json_string(sigs_str->
sig_str));
845 json_object_set_new(jdata,
"filename", json_string(sigs_str->
filename));
846 json_object_set_new(jdata,
"line", json_integer(sigs_str->
line));
848 json_object_set_new(jdata,
"error", json_string(sigs_str->
sig_error));
850 json_array_append_new(js_sigs_array, jdata);
851 if (++rules_cnt > MAX_FAILED_RULES) {
855 if (rules_cnt > MAX_FAILED_RULES) {
861 json_object_set_new(server_msg,
"message", js_sigs_array);
867 json_object_clear(js_sigs_array);
868 json_decref(js_sigs_array);
872 static TmEcode UnixManagerConfGetCommand(json_t *cmd,
873 json_t *server_msg,
void *data)
877 const char *confval = NULL;
878 char *variable = NULL;
880 json_t *jarg = json_object_get(cmd,
"variable");
881 if(!json_is_string(jarg)) {
882 SCLogInfo(
"error: variable is not a string");
883 json_object_set_new(server_msg,
"message", json_string(
"variable is not a string"));
887 variable = (
char *)json_string_value(jarg);
888 if (
ConfGet(variable, &confval) != 1) {
889 json_object_set_new(server_msg,
"message", json_string(
"Unable to get value"));
894 json_object_set_new(server_msg,
"message", json_string(confval));
898 json_object_set_new(server_msg,
"message", json_string(
"No string value"));
902 static TmEcode UnixManagerListCommand(json_t *cmd,
903 json_t *answer,
void *data)
908 Command *lcmd = NULL;
909 UnixCommand *gcmd = (UnixCommand *) data;
912 jdata = json_object();
914 json_object_set_new(answer,
"message",
915 json_string(
"internal error at json object creation"));
918 jarray = json_array();
919 if (jarray == NULL) {
920 json_object_set_new(answer,
"message",
921 json_string(
"internal error at json object creation"));
926 json_array_append_new(jarray, json_string(lcmd->name));
930 json_object_set_new(jdata,
"count", json_integer(i));
931 json_object_set_new(jdata,
"commands", jarray);
932 json_object_set_new(answer,
"message", jdata);
936 static TmEcode UnixManagerReopenLogFiles(json_t *cmd, json_t *server_msg,
void *data)
939 json_object_set_new(server_msg,
"message", json_string(
"done"));
944 TmEcode UnixManagerReloadRules(json_t *cmd,
945 json_t *server_msg,
void *data)
949 json_object_set_new(server_msg,
"message",
950 json_string(
"Live rule swap no longer possible."
951 " Engine in shutdown mode."));
956 DetectEngineSpawnLiveRuleSwapMgmtThread();
957 json_object_set_new(server_msg,
"message", json_string(
"Reloading rules"));
963 static UnixCommand command;
981 TmEcode UnixManagerRegisterCommand(
const char * keyword,
982 TmEcode (*Func)(json_t *, json_t *,
void *),
983 void *data,
int flags)
987 Command *lcmd = NULL;
994 if (keyword == NULL) {
1000 if (!strcmp(keyword, lcmd->name)) {
1001 SCLogError(
"%s already registered", keyword);
1036 TmEcode UnixManagerRegisterBackgroundTask(
TmEcode (*Func)(
void *),
1062 if (UnixNew(&command) == 0) {
1063 int failure_fatal = 0;
1064 if (
ConfGetBool(
"engine.init-failure-fatal", &failure_fatal) != 1) {
1065 SCLogDebug(
"ConfGetBool could not load the value.");
1067 if (failure_fatal) {
1068 FatalError(
"Unable to create unix command socket");
1076 UnixManagerRegisterCommand(
"shutdown", UnixManagerShutdownCommand, NULL, 0);
1077 UnixManagerRegisterCommand(
"command-list", UnixManagerListCommand, &command, 0);
1078 UnixManagerRegisterCommand(
"help", UnixManagerListCommand, &command, 0);
1079 UnixManagerRegisterCommand(
"version", UnixManagerVersionCommand, &command, 0);
1080 UnixManagerRegisterCommand(
"uptime", UnixManagerUptimeCommand, &command, 0);
1081 UnixManagerRegisterCommand(
"running-mode", UnixManagerRunningModeCommand, &command, 0);
1082 UnixManagerRegisterCommand(
"capture-mode", UnixManagerCaptureModeCommand, &command, 0);
1083 UnixManagerRegisterCommand(
"conf-get", UnixManagerConfGetCommand, &command,
UNIX_CMD_TAKE_ARGS);
1084 UnixManagerRegisterCommand(
"dump-counters", StatsOutputCounterSocket, NULL, 0);
1085 UnixManagerRegisterCommand(
"reload-rules", UnixManagerReloadRules, NULL, 0);
1086 UnixManagerRegisterCommand(
"ruleset-reload-rules", UnixManagerReloadRules, NULL, 0);
1087 UnixManagerRegisterCommand(
"ruleset-reload-nonblocking", UnixManagerNonBlockingReloadRules, NULL, 0);
1088 UnixManagerRegisterCommand(
"ruleset-reload-time", UnixManagerReloadTimeCommand, NULL, 0);
1089 UnixManagerRegisterCommand(
"ruleset-stats", UnixManagerRulesetStatsCommand, NULL, 0);
1090 UnixManagerRegisterCommand(
"ruleset-failed-rules", UnixManagerShowFailedRules, NULL, 0);
1091 #ifdef PROFILE_RULES
1092 UnixManagerRegisterCommand(
"ruleset-profile", UnixManagerRulesetProfileCommand, NULL, 0);
1093 UnixManagerRegisterCommand(
1094 "ruleset-profile-start", UnixManagerRulesetProfileStartCommand, NULL, 0);
1095 UnixManagerRegisterCommand(
1096 "ruleset-profile-stop", UnixManagerRulesetProfileStopCommand, NULL, 0);
1098 UnixManagerRegisterCommand(
"register-tenant-handler", UnixSocketRegisterTenantHandler, &command,
UNIX_CMD_TAKE_ARGS);
1099 UnixManagerRegisterCommand(
"unregister-tenant-handler", UnixSocketUnregisterTenantHandler, &command,
UNIX_CMD_TAKE_ARGS);
1100 UnixManagerRegisterCommand(
"register-tenant", UnixSocketRegisterTenant, &command,
UNIX_CMD_TAKE_ARGS);
1101 UnixManagerRegisterCommand(
"reload-tenant", UnixSocketReloadTenant, &command,
UNIX_CMD_TAKE_ARGS);
1102 UnixManagerRegisterCommand(
"reload-tenants", UnixSocketReloadTenants, &command, 0);
1103 UnixManagerRegisterCommand(
"unregister-tenant", UnixSocketUnregisterTenant, &command,
UNIX_CMD_TAKE_ARGS);
1104 UnixManagerRegisterCommand(
"add-hostbit", UnixSocketHostbitAdd, &command,
UNIX_CMD_TAKE_ARGS);
1105 UnixManagerRegisterCommand(
"remove-hostbit", UnixSocketHostbitRemove, &command,
UNIX_CMD_TAKE_ARGS);
1106 UnixManagerRegisterCommand(
"list-hostbit", UnixSocketHostbitList, &command,
UNIX_CMD_TAKE_ARGS);
1107 UnixManagerRegisterCommand(
"reopen-log-files", UnixManagerReopenLogFiles, NULL, 0);
1108 UnixManagerRegisterCommand(
"memcap-set", UnixSocketSetMemcap, &command,
UNIX_CMD_TAKE_ARGS);
1109 UnixManagerRegisterCommand(
"memcap-show", UnixSocketShowMemcap, &command,
UNIX_CMD_TAKE_ARGS);
1110 UnixManagerRegisterCommand(
"memcap-list", UnixSocketShowAllMemcap, NULL, 0);
1112 UnixManagerRegisterCommand(
"dataset-add", UnixSocketDatasetAdd, &command,
UNIX_CMD_TAKE_ARGS);
1113 UnixManagerRegisterCommand(
"dataset-remove", UnixSocketDatasetRemove, &command,
UNIX_CMD_TAKE_ARGS);
1114 UnixManagerRegisterCommand(
1116 UnixManagerRegisterCommand(
"dataset-dump", UnixSocketDatasetDump, NULL, 0);
1117 UnixManagerRegisterCommand(
1119 UnixManagerRegisterCommand(
1125 typedef struct UnixManagerThreadData_ {
1127 } UnixManagerThreadData;
1129 static TmEcode UnixManagerThreadInit(
ThreadVars *t,
const void *initdata,
void **data)
1131 UnixManagerThreadData *utd =
SCCalloc(1,
sizeof(*utd));
1161 ret = UnixMain(&command);
1177 UnixCommandBackgroundTasks(&command);
1197 if (tv_unixmgr == NULL) {
1216 UnixManagerRegisterCommand(
"iface-stat", LiveDeviceIfaceStat, NULL,
1218 UnixManagerRegisterCommand(
"iface-list", LiveDeviceIfaceList, NULL, 0);
1219 UnixManagerRegisterCommand(
"iface-bypassed-stat",
1220 LiveDeviceGetBypassedStats, NULL, 0);
1222 UnixManagerRegisterCommand(
"ebpf-bypassed-stat",
1223 LiveDeviceGetBypassedStats, NULL, 0);
1245 while (
tv != NULL) {
1246 if (strcasecmp(
tv->
name,
"UnixManagerThread") == 0) {
1291 #if defined(BUILD_UNIX_SOCKET) && defined(HAVE_SYS_UN_H) && defined(HAVE_SYS_STAT_H) && defined(HAVE_SYS_TYPES_H)