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);
563 ret = recv(client->fd, buffer +
offset,
sizeof(buffer) -
offset - 1, 0);
567 SCLogDebug(
"Unix socket: lost connection with client");
569 SCLogError(
"Unix socket: error on recv() from client: %s", strerror(errno));
571 UnixCommandClose(
this, client->fd);
574 if (ret >= (
int)(
sizeof(buffer)-
offset - 1)) {
575 SCLogInfo(
"Command server: client command is too long, "
577 UnixCommandClose(
this, client->fd);
579 if (buffer[ret - 1] ==
'\n') {
587 FD_ZERO(&select_set);
588 FD_SET(client->fd, &select_set);
590 tv.tv_usec = 200 * 1000;
592 ret = select(client->fd, &select_set, NULL, NULL, &
tv);
596 if (errno != EINTR) {
597 SCLogInfo(
"Unix socket: lost connection with client");
598 UnixCommandClose(
this, client->fd);
602 }
while (ret == 0 &&
try < 3);
604 ret = recv(client->fd, buffer +
offset,
605 sizeof(buffer) -
offset - 1, 0);
608 }
while (
try < 3 && cmd_over == 0);
610 if (
try == 3 && cmd_over == 0) {
611 SCLogInfo(
"Unix socket: incomplete client message, closing connection");
612 UnixCommandClose(
this, client->fd);
616 UnixCommandExecute(
this, buffer, client);
624 static int UnixMain(UnixCommand *
this)
634 UnixCommandClose(
this, uclient->fd);
640 FD_ZERO(&select_set);
641 FD_SET(this->socket, &select_set);
643 FD_SET(uclient->fd, &select_set);
647 tv.tv_usec = 200 * 1000;
648 ret = select(this->select_max, &select_set, NULL, NULL, &
tv);
653 if (errno == EINTR) {
656 SCLogError(
"Command server: select() fatal error: %s", strerror(errno));
666 if (FD_ISSET(uclient->fd, &select_set)) {
667 UnixCommandRun(
this, uclient);
670 if (FD_ISSET(this->socket, &select_set)) {
671 if (!UnixCommandAccept(
this))
678 static TmEcode UnixManagerShutdownCommand(json_t *cmd,
679 json_t *server_msg,
void *data)
682 json_object_set_new(server_msg,
"message", json_string(
"Closing Suricata"));
687 static TmEcode UnixManagerVersionCommand(json_t *cmd,
688 json_t *server_msg,
void *data)
695 static TmEcode UnixManagerUptimeCommand(json_t *cmd,
696 json_t *server_msg,
void *data)
700 UnixCommand *ucmd = (UnixCommand *)data;
702 uptime = time(NULL) - ucmd->start_timestamp;
703 json_object_set_new(server_msg,
"message", json_integer(uptime));
707 static TmEcode UnixManagerRunningModeCommand(json_t *cmd,
708 json_t *server_msg,
void *data)
711 json_object_set_new(server_msg,
"message", json_string(
RunmodeGetActive()));
715 static TmEcode UnixManagerCaptureModeCommand(json_t *cmd,
716 json_t *server_msg,
void *data)
723 static TmEcode UnixManagerReloadRulesWrapper(json_t *cmd, json_t *server_msg,
void *data,
int do_wait)
728 json_object_set_new(server_msg,
"message",
729 json_string(
"Live rule reload not possible if -s "
730 "or -S option used at runtime."));
736 if (r == 0 && do_wait) {
741 json_object_set_new(server_msg,
"message", json_string(
"Reload already in progress"));
746 json_object_set_new(server_msg,
"message", json_string(
"done"));
750 static TmEcode UnixManagerReloadRules(json_t *cmd, json_t *server_msg,
void *data)
752 return UnixManagerReloadRulesWrapper(cmd, server_msg, data, 1);
755 static TmEcode UnixManagerNonBlockingReloadRules(json_t *cmd, json_t *server_msg,
void *data)
757 return UnixManagerReloadRulesWrapper(cmd, server_msg, data, 0);
760 static TmEcode UnixManagerReloadTimeCommand(json_t *cmd,
761 json_t *server_msg,
void *data)
765 json_t *jdata = NULL;
768 json_object_set_new(server_msg,
"message", jdata);
772 static TmEcode UnixManagerRulesetStatsCommand(json_t *cmd,
773 json_t *server_msg,
void *data)
777 json_t *jdata = NULL;
780 json_object_set_new(server_msg,
"message", jdata);
785 static TmEcode UnixManagerRulesetProfileCommand(json_t *cmd, json_t *server_msg,
void *data)
790 json_t *js = SCProfileRuleTriggerDump(
de_ctx);
792 json_object_set_new(server_msg,
"message", json_string(
"NOK"));
795 json_object_set_new(server_msg,
"message", js);
799 static TmEcode UnixManagerRulesetProfileStartCommand(json_t *cmd, json_t *server_msg,
void *data)
803 json_object_set_new(server_msg,
"message", json_string(
"OK"));
807 static TmEcode UnixManagerRulesetProfileStopCommand(json_t *cmd, json_t *server_msg,
void *data)
811 json_object_set_new(server_msg,
"message", json_string(
"OK"));
816 static TmEcode UnixManagerShowFailedRules(json_t *cmd,
817 json_t *server_msg,
void *data)
823 json_object_set_new(server_msg,
"message", json_string(
"Unable to get info"));
829 json_t *js_sigs_array = json_array();
831 if (js_sigs_array == NULL) {
832 json_object_set_new(server_msg,
"message", json_string(
"Unable to get info"));
838 json_t *jdata = json_object();
840 json_object_set_new(server_msg,
"message", json_string(
"Unable to get the sig"));
844 json_object_set_new(jdata,
"tenant_id", json_integer(list->
tenant_id));
845 json_object_set_new(jdata,
"rule", json_string(sigs_str->
sig_str));
846 json_object_set_new(jdata,
"filename", json_string(sigs_str->
filename));
847 json_object_set_new(jdata,
"line", json_integer(sigs_str->
line));
849 json_object_set_new(jdata,
"error", json_string(sigs_str->
sig_error));
851 json_array_append_new(js_sigs_array, jdata);
852 if (++rules_cnt > MAX_FAILED_RULES) {
856 if (rules_cnt > MAX_FAILED_RULES) {
862 json_object_set_new(server_msg,
"message", js_sigs_array);
868 json_object_clear(js_sigs_array);
869 json_decref(js_sigs_array);
873 static TmEcode UnixManagerConfGetCommand(json_t *cmd,
874 json_t *server_msg,
void *data)
878 const char *confval = NULL;
879 char *variable = NULL;
881 json_t *jarg = json_object_get(cmd,
"variable");
882 if(!json_is_string(jarg)) {
883 SCLogInfo(
"error: variable is not a string");
884 json_object_set_new(server_msg,
"message", json_string(
"variable is not a string"));
888 variable = (
char *)json_string_value(jarg);
889 if (
SCConfGet(variable, &confval) != 1) {
890 json_object_set_new(server_msg,
"message", json_string(
"Unable to get value"));
895 json_object_set_new(server_msg,
"message", json_string(confval));
899 json_object_set_new(server_msg,
"message", json_string(
"No string value"));
903 static TmEcode UnixManagerListCommand(json_t *cmd,
904 json_t *answer,
void *data)
909 Command *lcmd = NULL;
910 UnixCommand *gcmd = (UnixCommand *) data;
913 jdata = json_object();
915 json_object_set_new(answer,
"message",
916 json_string(
"internal error at json object creation"));
919 jarray = json_array();
920 if (jarray == NULL) {
921 json_object_set_new(answer,
"message",
922 json_string(
"internal error at json object creation"));
927 json_array_append_new(jarray, json_string(lcmd->name));
931 json_object_set_new(jdata,
"count", json_integer(i));
932 json_object_set_new(jdata,
"commands", jarray);
933 json_object_set_new(answer,
"message", jdata);
937 static TmEcode UnixManagerReopenLogFiles(json_t *cmd, json_t *server_msg,
void *data)
940 json_object_set_new(server_msg,
"message", json_string(
"done"));
945 TmEcode UnixManagerReloadRules(json_t *cmd,
946 json_t *server_msg,
void *data)
950 json_object_set_new(server_msg,
"message",
951 json_string(
"Live rule swap no longer possible."
952 " Engine in shutdown mode."));
957 DetectEngineSpawnLiveRuleSwapMgmtThread();
958 json_object_set_new(server_msg,
"message", json_string(
"Reloading rules"));
964 static UnixCommand command;
982 TmEcode UnixManagerRegisterCommand(
const char * keyword,
983 TmEcode (*Func)(json_t *, json_t *,
void *),
984 void *data,
int flags)
988 Command *lcmd = NULL;
995 if (keyword == NULL) {
1001 if (!strcmp(keyword, lcmd->name)) {
1002 SCLogError(
"%s already registered", keyword);
1037 TmEcode UnixManagerRegisterBackgroundTask(
TmEcode (*Func)(
void *),
1063 if (UnixNew(&command) == 0) {
1064 int failure_fatal = 0;
1065 if (
SCConfGetBool(
"engine.init-failure-fatal", &failure_fatal) != 1) {
1066 SCLogDebug(
"ConfGetBool could not load the value.");
1068 if (failure_fatal) {
1069 FatalError(
"Unable to create unix command socket");
1077 UnixManagerRegisterCommand(
"shutdown", UnixManagerShutdownCommand, NULL, 0);
1078 UnixManagerRegisterCommand(
"command-list", UnixManagerListCommand, &command, 0);
1079 UnixManagerRegisterCommand(
"help", UnixManagerListCommand, &command, 0);
1080 UnixManagerRegisterCommand(
"version", UnixManagerVersionCommand, &command, 0);
1081 UnixManagerRegisterCommand(
"uptime", UnixManagerUptimeCommand, &command, 0);
1082 UnixManagerRegisterCommand(
"running-mode", UnixManagerRunningModeCommand, &command, 0);
1083 UnixManagerRegisterCommand(
"capture-mode", UnixManagerCaptureModeCommand, &command, 0);
1084 UnixManagerRegisterCommand(
"conf-get", UnixManagerConfGetCommand, &command,
UNIX_CMD_TAKE_ARGS);
1085 UnixManagerRegisterCommand(
"dump-counters", StatsOutputCounterSocket, NULL, 0);
1086 UnixManagerRegisterCommand(
"reload-rules", UnixManagerReloadRules, NULL, 0);
1087 UnixManagerRegisterCommand(
"ruleset-reload-rules", UnixManagerReloadRules, NULL, 0);
1088 UnixManagerRegisterCommand(
"ruleset-reload-nonblocking", UnixManagerNonBlockingReloadRules, NULL, 0);
1089 UnixManagerRegisterCommand(
"ruleset-reload-time", UnixManagerReloadTimeCommand, NULL, 0);
1090 UnixManagerRegisterCommand(
"ruleset-stats", UnixManagerRulesetStatsCommand, NULL, 0);
1091 UnixManagerRegisterCommand(
"ruleset-failed-rules", UnixManagerShowFailedRules, NULL, 0);
1092 #ifdef PROFILE_RULES
1093 UnixManagerRegisterCommand(
"ruleset-profile", UnixManagerRulesetProfileCommand, NULL, 0);
1094 UnixManagerRegisterCommand(
1095 "ruleset-profile-start", UnixManagerRulesetProfileStartCommand, NULL, 0);
1096 UnixManagerRegisterCommand(
1097 "ruleset-profile-stop", UnixManagerRulesetProfileStopCommand, NULL, 0);
1099 UnixManagerRegisterCommand(
"register-tenant-handler", UnixSocketRegisterTenantHandler, &command,
UNIX_CMD_TAKE_ARGS);
1100 UnixManagerRegisterCommand(
"unregister-tenant-handler", UnixSocketUnregisterTenantHandler, &command,
UNIX_CMD_TAKE_ARGS);
1101 UnixManagerRegisterCommand(
"register-tenant", UnixSocketRegisterTenant, &command,
UNIX_CMD_TAKE_ARGS);
1102 UnixManagerRegisterCommand(
"reload-tenant", UnixSocketReloadTenant, &command,
UNIX_CMD_TAKE_ARGS);
1103 UnixManagerRegisterCommand(
"reload-tenants", UnixSocketReloadTenants, &command, 0);
1104 UnixManagerRegisterCommand(
"unregister-tenant", UnixSocketUnregisterTenant, &command,
UNIX_CMD_TAKE_ARGS);
1105 UnixManagerRegisterCommand(
"add-hostbit", UnixSocketHostbitAdd, &command,
UNIX_CMD_TAKE_ARGS);
1106 UnixManagerRegisterCommand(
"remove-hostbit", UnixSocketHostbitRemove, &command,
UNIX_CMD_TAKE_ARGS);
1107 UnixManagerRegisterCommand(
"list-hostbit", UnixSocketHostbitList, &command,
UNIX_CMD_TAKE_ARGS);
1108 UnixManagerRegisterCommand(
"reopen-log-files", UnixManagerReopenLogFiles, NULL, 0);
1109 UnixManagerRegisterCommand(
"memcap-set", UnixSocketSetMemcap, &command,
UNIX_CMD_TAKE_ARGS);
1110 UnixManagerRegisterCommand(
"memcap-show", UnixSocketShowMemcap, &command,
UNIX_CMD_TAKE_ARGS);
1111 UnixManagerRegisterCommand(
"memcap-list", UnixSocketShowAllMemcap, NULL, 0);
1113 UnixManagerRegisterCommand(
"dataset-add", UnixSocketDatasetAdd, &command,
UNIX_CMD_TAKE_ARGS);
1114 UnixManagerRegisterCommand(
"dataset-remove", UnixSocketDatasetRemove, &command,
UNIX_CMD_TAKE_ARGS);
1115 UnixManagerRegisterCommand(
1117 UnixManagerRegisterCommand(
1119 UnixManagerRegisterCommand(
"dataset-dump", UnixSocketDatasetDump, NULL, 0);
1120 UnixManagerRegisterCommand(
1122 UnixManagerRegisterCommand(
1128 typedef struct UnixManagerThreadData_ {
1130 } UnixManagerThreadData;
1132 static TmEcode UnixManagerThreadInit(
ThreadVars *t,
const void *initdata,
void **data)
1134 UnixManagerThreadData *utd =
SCCalloc(1,
sizeof(*utd));
1164 ret = UnixMain(&command);
1180 UnixCommandBackgroundTasks(&command);
1200 if (tv_unixmgr == NULL) {
1219 UnixManagerRegisterCommand(
"iface-stat", LiveDeviceIfaceStat, NULL,
1221 UnixManagerRegisterCommand(
"iface-list", LiveDeviceIfaceList, NULL, 0);
1222 UnixManagerRegisterCommand(
"iface-bypassed-stat",
1223 LiveDeviceGetBypassedStats, NULL, 0);
1225 UnixManagerRegisterCommand(
"ebpf-bypassed-stat",
1226 LiveDeviceGetBypassedStats, NULL, 0);
1248 while (
tv != NULL) {
1249 if (strcasecmp(
tv->
name,
"UnixManagerThread") == 0) {
1294 #if defined(BUILD_UNIX_SOCKET) && defined(HAVE_SYS_UN_H) && defined(HAVE_SYS_STAT_H) && defined(HAVE_SYS_TYPES_H)