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 (
SCConfGet(
"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 = (socklen_t)(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)
255 UnixClient *safe = NULL;
259 if (item->fd == fd) {
273 UnixCommandSetMaxFD(
this);
274 UnixClientFree(item);
277 #define UNIX_PROTO_VERSION_LENGTH 200
278 #define UNIX_PROTO_VERSION_V1 "0.1"
279 #define UNIX_PROTO_V1 1
280 #define UNIX_PROTO_VERSION "0.2"
281 #define UNIX_PROTO_V2 2
283 static int UnixCommandSendJSONToClient(UnixClient *client, json_t *js)
285 MemBufferReset(client->mbuf);
289 .expand_by = CLIENT_BUFFER_SIZE
293 JSON_PRESERVE_ORDER|JSON_COMPACT|JSON_ENSURE_ASCII|
300 if (client->version > UNIX_PROTO_V1) {
316 SCLogDebug(
"sent message of size %"PRIuMAX
" to client socket %d",
330 static int UnixCommandAccept(UnixCommand *
this)
332 char buffer[UNIX_PROTO_VERSION_LENGTH + 1];
340 UnixClient *uclient = NULL;
343 socklen_t
len =
sizeof(this->client_addr);
344 client = accept(this->socket, (
struct sockaddr *) &this->client_addr,
347 SCLogInfo(
"Unix socket: accept() error: %s",
354 buffer[
sizeof(buffer)-1] = 0;
355 ret = recv(client, buffer,
sizeof(buffer)-1, 0);
357 SCLogInfo(
"Command server: client doesn't send version");
361 if (ret >= (
int)(
sizeof(buffer)-1)) {
362 SCLogInfo(
"Command server: client message is too long, "
369 client_msg = json_loads(buffer, 0, &jerror);
370 if (client_msg == NULL) {
371 SCLogInfo(
"Invalid command, error on line %d: %s\n", jerror.line, jerror.text);
376 version = json_object_get(client_msg,
"version");
377 if (!json_is_string(
version)) {
378 SCLogInfo(
"error: version is not a string");
380 json_decref(client_msg);
385 if ((strcmp(json_string_value(
version), UNIX_PROTO_VERSION) != 0)
386 && (strcmp(json_string_value(
version), UNIX_PROTO_VERSION_V1) != 0)) {
387 SCLogInfo(
"Unix socket: invalid client version: \"%s\"",
389 json_decref(client_msg);
393 SCLogDebug(
"Unix socket: client version: \"%s\"",
395 if (strcmp(json_string_value(
version), UNIX_PROTO_VERSION_V1) == 0) {
396 client_version = UNIX_PROTO_V1;
398 client_version = UNIX_PROTO_V2;
402 json_decref(client_msg);
404 server_msg = json_object();
405 if (server_msg == NULL) {
409 json_object_set_new(server_msg,
"return", json_string(
"OK"));
411 uclient = UnixClientAlloc();
413 json_decref(server_msg);
417 uclient->fd = client;
418 uclient->version = client_version;
420 if (UnixCommandSendJSONToClient(uclient, server_msg) != 0) {
423 UnixClientFree(uclient);
424 json_decref(server_msg);
429 json_decref(server_msg);
434 UnixCommandSetMaxFD(
this);
438 static int UnixCommandBackgroundTasks(UnixCommand*
this)
444 int fret = ltask->Func(ltask->data);
461 static int UnixCommandExecute(UnixCommand *
this,
char *command, UnixClient *client)
465 json_t *jsoncmd = NULL;
467 json_t *server_msg = json_object();
472 if (server_msg == NULL) {
476 jsoncmd = json_loads(command, 0, &error);
477 if (jsoncmd == NULL) {
478 SCLogInfo(
"Invalid command, error on line %d: %s\n", error.line, error.text);
482 cmd = json_object_get(jsoncmd,
"command");
483 if(!json_is_string(cmd)) {
484 SCLogInfo(
"error: command is not a string");
487 value = json_string_value(cmd);
490 if (!strcmp(value, lcmd->name)) {
494 cmd = json_object_get(jsoncmd,
"arguments");
495 if(!json_is_object(cmd)) {
496 SCLogInfo(
"error: argument is not an object");
500 fret = lcmd->Func(cmd, server_msg, lcmd->data);
509 json_object_set_new(server_msg,
"message", json_string(
"Unknown command"));
515 json_object_set_new(server_msg,
"return", json_string(
"NOK"));
518 json_object_set_new(server_msg,
"return", json_string(
"OK"));
522 if (UnixCommandSendJSONToClient(client, server_msg) != 0) {
526 json_decref(jsoncmd);
527 json_decref(server_msg);
531 json_decref(jsoncmd);
533 json_decref(server_msg);
534 UnixCommandClose(
this, client->fd);
538 static void UnixCommandRun(UnixCommand *
this, UnixClient *client)
542 if (client->version <= UNIX_PROTO_V1) {
543 ret = recv(client->fd, buffer,
sizeof(buffer) - 1, 0);
546 SCLogDebug(
"Unix socket: lost connection with client");
548 SCLogError(
"Unix socket: error on recv() from client: %s", strerror(errno));
550 UnixCommandClose(
this, client->fd);
553 if (ret >= (
int)(
sizeof(buffer)-1)) {
554 SCLogError(
"Command server: client command is too long, "
556 UnixCommandClose(
this, client->fd);
564 ret = recv(client->fd, buffer +
offset,
sizeof(buffer) -
offset - 1, 0);
568 SCLogDebug(
"Unix socket: lost connection with client");
570 SCLogError(
"Unix socket: error on recv() from client: %s", strerror(errno));
572 UnixCommandClose(
this, client->fd);
575 if (ret >= (
int)(
sizeof(buffer)-
offset - 1)) {
576 SCLogInfo(
"Command server: client command is too long, "
578 UnixCommandClose(
this, client->fd);
581 if (buffer[ret - 1] ==
'\n') {
589 FD_ZERO(&select_set);
590 FD_SET(client->fd, &select_set);
592 tv.tv_usec = 200 * 1000;
594 ret = select(client->fd, &select_set, NULL, NULL, &
tv);
598 if (errno != EINTR) {
599 SCLogInfo(
"Unix socket: lost connection with client");
600 UnixCommandClose(
this, client->fd);
604 }
while (ret == 0 &&
try < 3);
606 ret = recv(client->fd, buffer +
offset,
607 sizeof(buffer) -
offset - 1, 0);
610 }
while (
try < 3 && cmd_over == 0);
612 if (
try == 3 && cmd_over == 0) {
613 SCLogInfo(
"Unix socket: incomplete client message, closing connection");
614 UnixCommandClose(
this, client->fd);
618 UnixCommandExecute(
this, buffer, client);
626 static int UnixMain(UnixCommand *
this)
636 UnixCommandClose(
this, uclient->fd);
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) {
658 SCLogError(
"Command server: select() fatal error: %s", strerror(errno));
668 if (FD_ISSET(uclient->fd, &select_set)) {
669 UnixCommandRun(
this, uclient);
672 if (FD_ISSET(this->socket, &select_set)) {
673 if (!UnixCommandAccept(
this))
680 static TmEcode UnixManagerShutdownCommand(json_t *cmd,
681 json_t *server_msg,
void *data)
684 json_object_set_new(server_msg,
"message", json_string(
"Closing Suricata"));
689 static TmEcode UnixManagerVersionCommand(json_t *cmd,
690 json_t *server_msg,
void *data)
697 static TmEcode UnixManagerUptimeCommand(json_t *cmd,
698 json_t *server_msg,
void *data)
702 UnixCommand *ucmd = (UnixCommand *)data;
704 uptime = time(NULL) - ucmd->start_timestamp;
705 json_object_set_new(server_msg,
"message", json_integer(uptime));
709 static TmEcode UnixManagerRunningModeCommand(json_t *cmd,
710 json_t *server_msg,
void *data)
713 json_object_set_new(server_msg,
"message", json_string(
RunmodeGetActive()));
717 static TmEcode UnixManagerCaptureModeCommand(json_t *cmd,
718 json_t *server_msg,
void *data)
725 static TmEcode UnixManagerReloadRulesWrapper(json_t *cmd, json_t *server_msg,
void *data,
int do_wait)
730 json_object_set_new(server_msg,
"message",
731 json_string(
"Live rule reload not possible if -s "
732 "or -S option used at runtime."));
738 if (r == 0 && do_wait) {
743 json_object_set_new(server_msg,
"message", json_string(
"Reload already in progress"));
748 json_object_set_new(server_msg,
"message", json_string(
"done"));
752 static TmEcode UnixManagerReloadRules(json_t *cmd, json_t *server_msg,
void *data)
754 return UnixManagerReloadRulesWrapper(cmd, server_msg, data, 1);
757 static TmEcode UnixManagerNonBlockingReloadRules(json_t *cmd, json_t *server_msg,
void *data)
759 return UnixManagerReloadRulesWrapper(cmd, server_msg, data, 0);
762 static TmEcode UnixManagerReloadTimeCommand(json_t *cmd,
763 json_t *server_msg,
void *data)
767 json_t *jdata = NULL;
770 json_object_set_new(server_msg,
"message", jdata);
774 static TmEcode UnixManagerRulesetStatsCommand(json_t *cmd,
775 json_t *server_msg,
void *data)
779 json_t *jdata = NULL;
782 json_object_set_new(server_msg,
"message", jdata);
787 static TmEcode UnixManagerRulesetProfileCommand(json_t *cmd, json_t *server_msg,
void *data)
792 json_t *js = SCProfileRuleTriggerDump(
de_ctx);
794 json_object_set_new(server_msg,
"message", json_string(
"NOK"));
797 json_object_set_new(server_msg,
"message", js);
801 static TmEcode UnixManagerRulesetProfileStartCommand(json_t *cmd, json_t *server_msg,
void *data)
805 json_object_set_new(server_msg,
"message", json_string(
"OK"));
809 static TmEcode UnixManagerRulesetProfileStopCommand(json_t *cmd, json_t *server_msg,
void *data)
813 json_object_set_new(server_msg,
"message", json_string(
"OK"));
818 static TmEcode UnixManagerShowFailedRules(json_t *cmd,
819 json_t *server_msg,
void *data)
825 json_object_set_new(server_msg,
"message", json_string(
"Unable to get info"));
831 json_t *js_sigs_array = json_array();
833 if (js_sigs_array == NULL) {
834 json_object_set_new(server_msg,
"message", json_string(
"Unable to get info"));
840 json_t *jdata = json_object();
842 json_object_set_new(server_msg,
"message", json_string(
"Unable to get the sig"));
846 json_object_set_new(jdata,
"tenant_id", json_integer(list->
tenant_id));
847 json_object_set_new(jdata,
"rule", json_string(sigs_str->
sig_str));
848 json_object_set_new(jdata,
"filename", json_string(sigs_str->
filename));
849 json_object_set_new(jdata,
"line", json_integer(sigs_str->
line));
851 json_object_set_new(jdata,
"error", json_string(sigs_str->
sig_error));
853 json_array_append_new(js_sigs_array, jdata);
854 if (++rules_cnt > MAX_FAILED_RULES) {
858 if (rules_cnt > MAX_FAILED_RULES) {
864 json_object_set_new(server_msg,
"message", js_sigs_array);
870 json_object_clear(js_sigs_array);
871 json_decref(js_sigs_array);
875 static TmEcode UnixManagerConfGetCommand(json_t *cmd,
876 json_t *server_msg,
void *data)
880 const char *confval = NULL;
881 char *variable = NULL;
883 json_t *jarg = json_object_get(cmd,
"variable");
884 if(!json_is_string(jarg)) {
885 SCLogInfo(
"error: variable is not a string");
886 json_object_set_new(server_msg,
"message", json_string(
"variable is not a string"));
890 variable = (
char *)json_string_value(jarg);
891 if (
SCConfGet(variable, &confval) != 1) {
892 json_object_set_new(server_msg,
"message", json_string(
"Unable to get value"));
897 json_object_set_new(server_msg,
"message", json_string(confval));
901 json_object_set_new(server_msg,
"message", json_string(
"No string value"));
905 static TmEcode UnixManagerListCommand(json_t *cmd,
906 json_t *answer,
void *data)
911 Command *lcmd = NULL;
912 UnixCommand *gcmd = (UnixCommand *) data;
915 jdata = json_object();
917 json_object_set_new(answer,
"message",
918 json_string(
"internal error at json object creation"));
921 jarray = json_array();
922 if (jarray == NULL) {
923 json_object_set_new(answer,
"message",
924 json_string(
"internal error at json object creation"));
929 json_array_append_new(jarray, json_string(lcmd->name));
933 json_object_set_new(jdata,
"count", json_integer(i));
934 json_object_set_new(jdata,
"commands", jarray);
935 json_object_set_new(answer,
"message", jdata);
939 static TmEcode UnixManagerReopenLogFiles(json_t *cmd, json_t *server_msg,
void *data)
942 json_object_set_new(server_msg,
"message", json_string(
"done"));
947 TmEcode UnixManagerReloadRules(json_t *cmd,
948 json_t *server_msg,
void *data)
952 json_object_set_new(server_msg,
"message",
953 json_string(
"Live rule swap no longer possible."
954 " Engine in shutdown mode."));
959 DetectEngineSpawnLiveRuleSwapMgmtThread();
960 json_object_set_new(server_msg,
"message", json_string(
"Reloading rules"));
966 static UnixCommand command;
984 TmEcode UnixManagerRegisterCommand(
const char * keyword,
985 TmEcode (*Func)(json_t *, json_t *,
void *),
986 void *data,
int flags)
990 Command *lcmd = NULL;
997 if (keyword == NULL) {
1003 if (!strcmp(keyword, lcmd->name)) {
1004 SCLogError(
"%s already registered", keyword);
1039 TmEcode UnixManagerRegisterBackgroundTask(
TmEcode (*Func)(
void *),
1065 if (UnixNew(&command) == 0) {
1066 int failure_fatal = 0;
1067 if (
SCConfGetBool(
"engine.init-failure-fatal", &failure_fatal) != 1) {
1068 SCLogDebug(
"ConfGetBool could not load the value.");
1070 if (failure_fatal) {
1071 FatalError(
"Unable to create unix command socket");
1079 UnixManagerRegisterCommand(
"shutdown", UnixManagerShutdownCommand, NULL, 0);
1080 UnixManagerRegisterCommand(
"command-list", UnixManagerListCommand, &command, 0);
1081 UnixManagerRegisterCommand(
"help", UnixManagerListCommand, &command, 0);
1082 UnixManagerRegisterCommand(
"version", UnixManagerVersionCommand, &command, 0);
1083 UnixManagerRegisterCommand(
"uptime", UnixManagerUptimeCommand, &command, 0);
1084 UnixManagerRegisterCommand(
"running-mode", UnixManagerRunningModeCommand, &command, 0);
1085 UnixManagerRegisterCommand(
"capture-mode", UnixManagerCaptureModeCommand, &command, 0);
1086 UnixManagerRegisterCommand(
"conf-get", UnixManagerConfGetCommand, &command,
UNIX_CMD_TAKE_ARGS);
1087 UnixManagerRegisterCommand(
"dump-counters", StatsOutputCounterSocket, NULL, 0);
1088 UnixManagerRegisterCommand(
"reload-rules", UnixManagerReloadRules, NULL, 0);
1089 UnixManagerRegisterCommand(
"ruleset-reload-rules", UnixManagerReloadRules, NULL, 0);
1090 UnixManagerRegisterCommand(
"ruleset-reload-nonblocking", UnixManagerNonBlockingReloadRules, NULL, 0);
1091 UnixManagerRegisterCommand(
"ruleset-reload-time", UnixManagerReloadTimeCommand, NULL, 0);
1092 UnixManagerRegisterCommand(
"ruleset-stats", UnixManagerRulesetStatsCommand, NULL, 0);
1093 UnixManagerRegisterCommand(
"ruleset-failed-rules", UnixManagerShowFailedRules, NULL, 0);
1094 #ifdef PROFILE_RULES
1095 UnixManagerRegisterCommand(
"ruleset-profile", UnixManagerRulesetProfileCommand, NULL, 0);
1096 UnixManagerRegisterCommand(
1097 "ruleset-profile-start", UnixManagerRulesetProfileStartCommand, NULL, 0);
1098 UnixManagerRegisterCommand(
1099 "ruleset-profile-stop", UnixManagerRulesetProfileStopCommand, NULL, 0);
1101 UnixManagerRegisterCommand(
"register-tenant-handler", UnixSocketRegisterTenantHandler, &command,
UNIX_CMD_TAKE_ARGS);
1102 UnixManagerRegisterCommand(
"unregister-tenant-handler", UnixSocketUnregisterTenantHandler, &command,
UNIX_CMD_TAKE_ARGS);
1103 UnixManagerRegisterCommand(
"register-tenant", UnixSocketRegisterTenant, &command,
UNIX_CMD_TAKE_ARGS);
1104 UnixManagerRegisterCommand(
"reload-tenant", UnixSocketReloadTenant, &command,
UNIX_CMD_TAKE_ARGS);
1105 UnixManagerRegisterCommand(
"reload-tenants", UnixSocketReloadTenants, &command, 0);
1106 UnixManagerRegisterCommand(
"unregister-tenant", UnixSocketUnregisterTenant, &command,
UNIX_CMD_TAKE_ARGS);
1107 UnixManagerRegisterCommand(
"add-hostbit", UnixSocketHostbitAdd, &command,
UNIX_CMD_TAKE_ARGS);
1108 UnixManagerRegisterCommand(
"remove-hostbit", UnixSocketHostbitRemove, &command,
UNIX_CMD_TAKE_ARGS);
1109 UnixManagerRegisterCommand(
"list-hostbit", UnixSocketHostbitList, &command,
UNIX_CMD_TAKE_ARGS);
1110 UnixManagerRegisterCommand(
"reopen-log-files", UnixManagerReopenLogFiles, NULL, 0);
1111 UnixManagerRegisterCommand(
"memcap-set", UnixSocketSetMemcap, &command,
UNIX_CMD_TAKE_ARGS);
1112 UnixManagerRegisterCommand(
"memcap-show", UnixSocketShowMemcap, &command,
UNIX_CMD_TAKE_ARGS);
1113 UnixManagerRegisterCommand(
"memcap-list", UnixSocketShowAllMemcap, NULL, 0);
1115 UnixManagerRegisterCommand(
"dataset-add", UnixSocketDatasetAdd, &command,
UNIX_CMD_TAKE_ARGS);
1116 UnixManagerRegisterCommand(
"dataset-remove", UnixSocketDatasetRemove, &command,
UNIX_CMD_TAKE_ARGS);
1117 UnixManagerRegisterCommand(
1119 UnixManagerRegisterCommand(
1121 UnixManagerRegisterCommand(
"dataset-dump", UnixSocketDatasetDump, NULL, 0);
1122 UnixManagerRegisterCommand(
1124 UnixManagerRegisterCommand(
1130 typedef struct UnixManagerThreadData_ {
1132 } UnixManagerThreadData;
1134 static TmEcode UnixManagerThreadInit(
ThreadVars *t,
const void *initdata,
void **data)
1136 UnixManagerThreadData *utd =
SCCalloc(1,
sizeof(*utd));
1166 ret = UnixMain(&command);
1182 UnixCommandBackgroundTasks(&command);
1202 if (tv_unixmgr == NULL) {
1221 UnixManagerRegisterCommand(
"iface-stat", LiveDeviceIfaceStat, NULL,
1223 UnixManagerRegisterCommand(
"iface-list", LiveDeviceIfaceList, NULL, 0);
1224 UnixManagerRegisterCommand(
"iface-bypassed-stat",
1225 LiveDeviceGetBypassedStats, NULL, 0);
1227 UnixManagerRegisterCommand(
"ebpf-bypassed-stat",
1228 LiveDeviceGetBypassedStats, NULL, 0);
1250 while (
tv != NULL) {
1251 if (strcasecmp(
tv->
name,
"UnixManagerThread") == 0) {
1296 #if defined(BUILD_UNIX_SOCKET) && defined(HAVE_SYS_UN_H) && defined(HAVE_SYS_STAT_H) && defined(HAVE_SYS_TYPES_H)