suricata
unix-manager.c
Go to the documentation of this file.
1 /* Copyright (C) 2013-2018 Open Information Security Foundation
2  *
3  * You can copy, redistribute or modify this Program under the terms of
4  * the GNU General Public License version 2 as published by the Free
5  * Software Foundation.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * version 2 along with this program; if not, write to the Free Software
14  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
15  * 02110-1301, USA.
16  */
17 
18 /**
19  * \file
20  *
21  * \author Eric Leblond <eric@regit.org>
22  */
23 
24 #include "suricata-common.h"
25 #include "suricata.h"
26 #include "unix-manager.h"
27 #include "detect-engine.h"
28 #include "tm-threads.h"
29 #include "runmodes.h"
30 #include "conf.h"
31 
32 #include "output-json-stats.h"
33 
34 #include "util-privs.h"
35 #include "util-debug.h"
36 #include "util-device.h"
37 #include "util-ebpf.h"
38 #include "util-signal.h"
39 #include "util-buffer.h"
40 
41 #if (defined BUILD_UNIX_SOCKET) && (defined HAVE_SYS_UN_H) && (defined HAVE_SYS_STAT_H) && (defined HAVE_SYS_TYPES_H)
42 #include <sys/un.h>
43 #include <sys/stat.h>
44 #include <sys/types.h>
45 
46 #include "output.h"
47 #include "output-json.h"
48 
49 // MSG_NOSIGNAL does not exists on OS X
50 #ifdef OS_DARWIN
51 # ifndef MSG_NOSIGNAL
52 # define MSG_NOSIGNAL SO_NOSIGPIPE
53 # endif
54 #endif
55 
56 #define SOCKET_PATH LOCAL_STATE_DIR "/run/suricata/"
57 #define SOCKET_FILENAME "suricata-command.socket"
58 #define SOCKET_TARGET SOCKET_PATH SOCKET_FILENAME
59 
60 #define MAX_FAILED_RULES 20
61 
62 typedef struct Command_ {
63  char *name;
64  TmEcode (*Func)(json_t *, json_t *, void *);
65  void *data;
66  int flags;
67  TAILQ_ENTRY(Command_) next;
68 } Command;
69 
70 typedef struct Task_ {
71  TmEcode (*Func)(void *);
72  void *data;
73  TAILQ_ENTRY(Task_) next;
74 } Task;
75 
76 #define CLIENT_BUFFER_SIZE 4096
77 typedef struct UnixClient_ {
78  int fd;
79  MemBuffer *mbuf; /**< buffer for response construction */
80  int version;
81  TAILQ_ENTRY(UnixClient_) next;
82 } UnixClient;
83 
84 typedef struct UnixCommand_ {
85  time_t start_timestamp;
86  int socket;
87  struct sockaddr_un client_addr;
88  int select_max;
89  TAILQ_HEAD(, Command_) commands;
90  TAILQ_HEAD(, Task_) tasks;
91  TAILQ_HEAD(, UnixClient_) clients;
92 } UnixCommand;
93 
94 /**
95  * \brief Create a command unix socket on system
96  *
97  * \retval 0 in case of error, 1 in case of success
98  */
99 static int UnixNew(UnixCommand * this)
100 {
101  struct sockaddr_un addr;
102  int len;
103  int ret;
104  int on = 1;
105  char sockettarget[PATH_MAX];
106  const char *socketname;
107 
108  this->start_timestamp = time(NULL);
109  this->socket = -1;
110  this->select_max = 0;
111 
112  TAILQ_INIT(&this->commands);
113  TAILQ_INIT(&this->tasks);
114  TAILQ_INIT(&this->clients);
115 
116  int check_dir = 0;
117  if (ConfGet("unix-command.filename", &socketname) == 1) {
118  if (PathIsAbsolute(socketname)) {
119  strlcpy(sockettarget, socketname, sizeof(sockettarget));
120  } else {
121  snprintf(sockettarget, sizeof(sockettarget), "%s/%s",
122  SOCKET_PATH, socketname);
123  check_dir = 1;
124  }
125  } else {
126  strlcpy(sockettarget, SOCKET_TARGET, sizeof(sockettarget));
127  check_dir = 1;
128  }
129  SCLogInfo("Using unix socket file '%s'", sockettarget);
130 
131  if (check_dir) {
132  struct stat stat_buf;
133  /* coverity[toctou] */
134  if (stat(SOCKET_PATH, &stat_buf) != 0) {
135  /* coverity[toctou] */
136  ret = SCMkDir(SOCKET_PATH, S_IRWXU|S_IXGRP|S_IRGRP);
137  if (ret != 0) {
138  int err = errno;
139  if (err != EEXIST) {
141  "Cannot create socket directory %s: %s",
142  SOCKET_PATH, strerror(err));
143  return 0;
144  }
145  } else {
146  SCLogInfo("Created socket directory %s",
147  SOCKET_PATH);
148  }
149  }
150  }
151 
152  /* Remove socket file */
153  (void) unlink(sockettarget);
154 
155  /* set address */
156  addr.sun_family = AF_UNIX;
157  strlcpy(addr.sun_path, sockettarget, sizeof(addr.sun_path));
158  addr.sun_path[sizeof(addr.sun_path) - 1] = 0;
159  len = strlen(addr.sun_path) + sizeof(addr.sun_family) + 1;
160 
161  /* create socket */
162  this->socket = socket(AF_UNIX, SOCK_STREAM, 0);
163  if (this->socket == -1) {
165  "Unix Socket: unable to create UNIX socket %s: %s",
166  addr.sun_path, strerror(errno));
167  return 0;
168  }
169  this->select_max = this->socket + 1;
170 
171  /* set reuse option */
172  ret = setsockopt(this->socket, SOL_SOCKET, SO_REUSEADDR,
173  (char *) &on, sizeof(on));
174  if ( ret != 0 ) {
176  "Cannot set sockets options: %s.", strerror(errno));
177  }
178 
179  /* bind socket */
180  ret = bind(this->socket, (struct sockaddr *) &addr, len);
181  if (ret == -1) {
183  "Unix socket: UNIX socket bind(%s) error: %s",
184  sockettarget, strerror(errno));
185  return 0;
186  }
187 
188 #if !(defined OS_FREEBSD || defined __OpenBSD__)
189  /* Set file mode: will not fully work on most system, the group
190  * permission is not changed on some Linux. *BSD won't do the
191  * chmod: it returns EINVAL when calling chmod on sockets. */
192  ret = chmod(sockettarget, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP);
193  if (ret == -1) {
194  int err = errno;
196  "Unable to change permission on socket: %s (%d)",
197  strerror(err),
198  err);
199  }
200 #endif
201 
202  /* listen */
203  if (listen(this->socket, 1) == -1) {
205  "Command server: UNIX socket listen() error: %s",
206  strerror(errno));
207  return 0;
208  }
209  return 1;
210 }
211 
212 static void UnixCommandSetMaxFD(UnixCommand *this)
213 {
214  UnixClient *item;
215 
216  if (this == NULL) {
217  SCLogError(SC_ERR_INVALID_ARGUMENT, "Unix command is NULL, warn devel");
218  return;
219  }
220 
221  this->select_max = this->socket + 1;
222  TAILQ_FOREACH(item, &this->clients, next) {
223  if (item->fd >= this->select_max) {
224  this->select_max = item->fd + 1;
225  }
226  }
227 }
228 
229 static UnixClient *UnixClientAlloc(void)
230 {
231  UnixClient *uclient = SCMalloc(sizeof(UnixClient));
232  if (unlikely(uclient == NULL)) {
233  SCLogError(SC_ERR_MEM_ALLOC, "Can't allocate new client");
234  return NULL;
235  }
236  uclient->mbuf = MemBufferCreateNew(CLIENT_BUFFER_SIZE);
237  if (uclient->mbuf == NULL) {
238  SCLogError(SC_ERR_MEM_ALLOC, "Can't allocate new client send buffer");
239  SCFree(uclient);
240  return NULL;
241  }
242  return uclient;
243 }
244 
245 static void UnixClientFree(UnixClient *c)
246 {
247  if (c != NULL) {
248  MemBufferFree(c->mbuf);
249  SCFree(c);
250  }
251 }
252 
253 /**
254  * \brief Close the unix socket
255  */
256 static void UnixCommandClose(UnixCommand *this, int fd)
257 {
258  UnixClient *item;
259  int found = 0;
260 
261  TAILQ_FOREACH(item, &this->clients, next) {
262  if (item->fd == fd) {
263  found = 1;
264  break;
265  }
266  }
267 
268  if (found == 0) {
269  SCLogError(SC_ERR_INVALID_VALUE, "No fd found in client list");
270  return;
271  }
272 
273  TAILQ_REMOVE(&this->clients, item, next);
274 
275  close(item->fd);
276  UnixCommandSetMaxFD(this);
277  UnixClientFree(item);
278 }
279 
280 #define UNIX_PROTO_VERSION_LENGTH 200
281 #define UNIX_PROTO_VERSION_V1 "0.1"
282 #define UNIX_PROTO_V1 1
283 #define UNIX_PROTO_VERSION "0.2"
284 #define UNIX_PROTO_V2 2
285 
286 static int UnixCommandSendJSONToClient(UnixClient *client, json_t *js)
287 {
288  MemBufferReset(client->mbuf);
289 
290  OutputJSONMemBufferWrapper wrapper = {
291  .buffer = &client->mbuf,
292  .expand_by = CLIENT_BUFFER_SIZE
293  };
294 
295  int r = json_dump_callback(js, OutputJSONMemBufferCallback, &wrapper,
296  JSON_PRESERVE_ORDER|JSON_COMPACT|JSON_ENSURE_ASCII|
298  if (r != 0) {
299  SCLogWarning(SC_ERR_SOCKET, "unable to serialize JSON object");
300  return -1;
301  }
302 
303  if (client->version > UNIX_PROTO_V1) {
304  if (MEMBUFFER_OFFSET(client->mbuf) + 1 >= MEMBUFFER_SIZE(client->mbuf)) {
305  MemBufferExpand(&client->mbuf, 1);
306  }
307  MemBufferWriteRaw(client->mbuf, "\n", 1);
308  }
309 
310  if (send(client->fd, (const char *)MEMBUFFER_BUFFER(client->mbuf),
311  MEMBUFFER_OFFSET(client->mbuf), MSG_NOSIGNAL) == -1)
312  {
313  SCLogWarning(SC_ERR_SOCKET, "unable to send block of size "
314  "%"PRIuMAX": %s", (uintmax_t)MEMBUFFER_OFFSET(client->mbuf),
315  strerror(errno));
316  return -1;
317  }
318 
319  SCLogDebug("sent message of size %"PRIuMAX" to client socket %d",
320  (uintmax_t)MEMBUFFER_OFFSET(client->mbuf), client->fd);
321  return 0;
322 }
323 
324 /**
325  * \brief Accept a new client on unix socket
326  *
327  * The function is called when a new user is detected
328  * in UnixMain(). It does the initial protocol negotiation
329  * with client.
330  *
331  * \retval 0 in case of error, 1 in case of success
332  */
333 static int UnixCommandAccept(UnixCommand *this)
334 {
335  char buffer[UNIX_PROTO_VERSION_LENGTH + 1];
336  json_t *client_msg;
337  json_t *server_msg;
338  json_t *version;
339  json_error_t jerror;
340  int client;
341  int client_version;
342  int ret;
343  UnixClient *uclient = NULL;
344 
345  /* accept client socket */
346  socklen_t len = sizeof(this->client_addr);
347  client = accept(this->socket, (struct sockaddr *) &this->client_addr,
348  &len);
349  if (client < 0) {
350  SCLogInfo("Unix socket: accept() error: %s",
351  strerror(errno));
352  return 0;
353  }
354  SCLogDebug("Unix socket: client connection");
355 
356  /* read client version */
357  buffer[sizeof(buffer)-1] = 0;
358  ret = recv(client, buffer, sizeof(buffer)-1, 0);
359  if (ret < 0) {
360  SCLogInfo("Command server: client doesn't send version");
361  close(client);
362  return 0;
363  }
364  if (ret >= (int)(sizeof(buffer)-1)) {
365  SCLogInfo("Command server: client message is too long, "
366  "disconnect him.");
367  close(client);
368  return 0;
369  }
370  buffer[ret] = 0;
371 
372  client_msg = json_loads(buffer, 0, &jerror);
373  if (client_msg == NULL) {
374  SCLogInfo("Invalid command, error on line %d: %s\n", jerror.line, jerror.text);
375  close(client);
376  return 0;
377  }
378 
379  version = json_object_get(client_msg, "version");
380  if (!json_is_string(version)) {
381  SCLogInfo("error: version is not a string");
382  close(client);
383  json_decref(client_msg);
384  return 0;
385  }
386 
387  /* check client version */
388  if ((strcmp(json_string_value(version), UNIX_PROTO_VERSION) != 0)
389  && (strcmp(json_string_value(version), UNIX_PROTO_VERSION_V1) != 0)) {
390  SCLogInfo("Unix socket: invalid client version: \"%s\"",
391  json_string_value(version));
392  json_decref(client_msg);
393  close(client);
394  return 0;
395  } else {
396  SCLogDebug("Unix socket: client version: \"%s\"",
397  json_string_value(version));
398  if (strcmp(json_string_value(version), UNIX_PROTO_VERSION_V1) == 0) {
399  client_version = UNIX_PROTO_V1;
400  } else {
401  client_version = UNIX_PROTO_V2;
402  }
403  }
404 
405  json_decref(client_msg);
406  /* send answer */
407  server_msg = json_object();
408  if (server_msg == NULL) {
409  close(client);
410  return 0;
411  }
412  json_object_set_new(server_msg, "return", json_string("OK"));
413 
414  uclient = UnixClientAlloc();
415  if (unlikely(uclient == NULL)) {
416  SCLogError(SC_ERR_MEM_ALLOC, "Can't allocate new client");
417  json_decref(server_msg);
418  close(client);
419  return 0;
420  }
421  uclient->fd = client;
422  uclient->version = client_version;
423 
424  if (UnixCommandSendJSONToClient(uclient, server_msg) != 0) {
425  SCLogWarning(SC_ERR_SOCKET, "Unable to send command");
426 
427  UnixClientFree(uclient);
428  json_decref(server_msg);
429  close(client);
430  return 0;
431  }
432 
433  json_decref(server_msg);
434 
435  /* client connected */
436  SCLogDebug("Unix socket: client connected");
437  TAILQ_INSERT_TAIL(&this->clients, uclient, next);
438  UnixCommandSetMaxFD(this);
439  return 1;
440 }
441 
442 static int UnixCommandBackgroundTasks(UnixCommand* this)
443 {
444  int ret = 1;
445  Task *ltask;
446 
447  TAILQ_FOREACH(ltask, &this->tasks, next) {
448  int fret = ltask->Func(ltask->data);
449  if (fret != TM_ECODE_OK) {
450  ret = 0;
451  }
452  }
453  return ret;
454 }
455 
456 /**
457  * \brief Command dispatcher
458  *
459  * \param this a UnixCommand:: structure
460  * \param command a string containing a json formatted
461  * command
462  *
463  * \retval 0 in case of error, 1 in case of success
464  */
465 static int UnixCommandExecute(UnixCommand * this, char *command, UnixClient *client)
466 {
467  int ret = 1;
468  json_error_t error;
469  json_t *jsoncmd = NULL;
470  json_t *cmd = NULL;
471  json_t *server_msg = json_object();
472  const char * value;
473  int found = 0;
474  Command *lcmd;
475 
476  if (server_msg == NULL) {
477  return 0;
478  }
479 
480  jsoncmd = json_loads(command, 0, &error);
481  if (jsoncmd == NULL) {
482  SCLogInfo("Invalid command, error on line %d: %s\n", error.line, error.text);
483  goto error;
484  }
485 
486  cmd = json_object_get(jsoncmd, "command");
487  if(!json_is_string(cmd)) {
488  SCLogInfo("error: command is not a string");
489  goto error_cmd;
490  }
491  value = json_string_value(cmd);
492 
493  TAILQ_FOREACH(lcmd, &this->commands, next) {
494  if (!strcmp(value, lcmd->name)) {
495  int fret = TM_ECODE_OK;
496  found = 1;
497  if (lcmd->flags & UNIX_CMD_TAKE_ARGS) {
498  cmd = json_object_get(jsoncmd, "arguments");
499  if(!json_is_object(cmd)) {
500  SCLogInfo("error: argument is not an object");
501  goto error_cmd;
502  }
503  }
504  fret = lcmd->Func(cmd, server_msg, lcmd->data);
505  if (fret != TM_ECODE_OK) {
506  ret = 0;
507  }
508  break;
509  }
510  }
511 
512  if (found == 0) {
513  json_object_set_new(server_msg, "message", json_string("Unknown command"));
514  ret = 0;
515  }
516 
517  switch (ret) {
518  case 0:
519  json_object_set_new(server_msg, "return", json_string("NOK"));
520  break;
521  case 1:
522  json_object_set_new(server_msg, "return", json_string("OK"));
523  break;
524  }
525 
526  if (UnixCommandSendJSONToClient(client, server_msg) != 0) {
527  goto error;
528  }
529 
530  json_decref(jsoncmd);
531  json_decref(server_msg);
532  return ret;
533 
534 error_cmd:
535  json_decref(jsoncmd);
536 error:
537  json_decref(server_msg);
538  UnixCommandClose(this, client->fd);
539  return 0;
540 }
541 
542 static void UnixCommandRun(UnixCommand * this, UnixClient *client)
543 {
544  char buffer[4096];
545  int ret;
546  if (client->version <= UNIX_PROTO_V1) {
547  ret = recv(client->fd, buffer, sizeof(buffer) - 1, 0);
548  if (ret <= 0) {
549  if (ret == 0) {
550  SCLogDebug("Unix socket: lost connection with client");
551  } else {
552  SCLogError(SC_ERR_SOCKET, "Unix socket: error on recv() from client: %s",
553  strerror(errno));
554  }
555  UnixCommandClose(this, client->fd);
556  return;
557  }
558  if (ret >= (int)(sizeof(buffer)-1)) {
559  SCLogError(SC_ERR_SOCKET, "Command server: client command is too long, "
560  "disconnect him.");
561  UnixCommandClose(this, client->fd);
562  }
563  buffer[ret] = 0;
564  } else {
565  int try = 0;
566  int offset = 0;
567  int cmd_over = 0;
568  ret = recv(client->fd, buffer + offset, sizeof(buffer) - offset - 1, 0);
569  do {
570  if (ret <= 0) {
571  if (ret == 0) {
572  SCLogInfo("Unix socket: lost connection with client");
573  } else {
574  SCLogInfo("Unix socket: error on recv() from client: %s",
575  strerror(errno));
576  }
577  UnixCommandClose(this, client->fd);
578  return;
579  }
580  if (ret >= (int)(sizeof(buffer)- offset - 1)) {
581  SCLogInfo("Command server: client command is too long, "
582  "disconnect him.");
583  UnixCommandClose(this, client->fd);
584  }
585  if (buffer[ret - 1] == '\n') {
586  buffer[ret-1] = 0;
587  cmd_over = 1;
588  } else {
589  struct timeval tv;
590  fd_set select_set;
591  offset += ret;
592  do {
593  FD_ZERO(&select_set);
594  FD_SET(client->fd, &select_set);
595  tv.tv_sec = 0;
596  tv.tv_usec = 200 * 1000;
597  try++;
598  ret = select(client->fd, &select_set, NULL, NULL, &tv);
599  /* catch select() error */
600  if (ret == -1) {
601  /* Signal was caught: just ignore it */
602  if (errno != EINTR) {
603  SCLogInfo("Unix socket: lost connection with client");
604  UnixCommandClose(this, client->fd);
605  return;
606  }
607  }
608  } while (ret == 0 && try < 3);
609  if (ret > 0) {
610  ret = recv(client->fd, buffer + offset,
611  sizeof(buffer) - offset - 1, 0);
612  }
613  }
614  } while (try < 3 && cmd_over == 0);
615 
616  if (try == 3 && cmd_over == 0) {
617  SCLogInfo("Unix socket: imcomplete client message, closing connection");
618  UnixCommandClose(this, client->fd);
619  return;
620  }
621  }
622  UnixCommandExecute(this, buffer, client);
623 }
624 
625 /**
626  * \brief Select function
627  *
628  * \retval 0 in case of error, 1 in case of success
629  */
630 static int UnixMain(UnixCommand * this)
631 {
632  struct timeval tv;
633  int ret;
634  fd_set select_set;
635  UnixClient *uclient;
636  UnixClient *tclient;
637 
638  /* Wait activity on the socket */
639  FD_ZERO(&select_set);
640  FD_SET(this->socket, &select_set);
641  TAILQ_FOREACH(uclient, &this->clients, next) {
642  FD_SET(uclient->fd, &select_set);
643  }
644 
645  tv.tv_sec = 0;
646  tv.tv_usec = 200 * 1000;
647  ret = select(this->select_max, &select_set, NULL, NULL, &tv);
648 
649  /* catch select() error */
650  if (ret == -1) {
651  /* Signal was caught: just ignore it */
652  if (errno == EINTR) {
653  return 1;
654  }
655  SCLogError(SC_ERR_SOCKET, "Command server: select() fatal error: %s", strerror(errno));
656  return 0;
657  }
658 
660  TAILQ_FOREACH_SAFE(uclient, &this->clients, next, tclient) {
661  UnixCommandClose(this, uclient->fd);
662  }
663  return 1;
664  }
665 
666  /* timeout: continue */
667  if (ret == 0) {
668  return 1;
669  }
670 
671  TAILQ_FOREACH_SAFE(uclient, &this->clients, next, tclient) {
672  if (FD_ISSET(uclient->fd, &select_set)) {
673  UnixCommandRun(this, uclient);
674  }
675  }
676  if (FD_ISSET(this->socket, &select_set)) {
677  if (!UnixCommandAccept(this))
678  return 1;
679  }
680 
681  return 1;
682 }
683 
684 static TmEcode UnixManagerShutdownCommand(json_t *cmd,
685  json_t *server_msg, void *data)
686 {
687  SCEnter();
688  json_object_set_new(server_msg, "message", json_string("Closing Suricata"));
689  EngineStop();
691 }
692 
693 static TmEcode UnixManagerVersionCommand(json_t *cmd,
694  json_t *server_msg, void *data)
695 {
696  SCEnter();
697  json_object_set_new(server_msg, "message", json_string(
698 #ifdef REVISION
699  PROG_VER " (" xstr(REVISION) ")"
700 #elif defined RELEASE
701  PROG_VER " RELEASE"
702 #else
703  PROG_VER
704 #endif
705  ));
707 }
708 
709 static TmEcode UnixManagerUptimeCommand(json_t *cmd,
710  json_t *server_msg, void *data)
711 {
712  SCEnter();
713  int uptime;
714  UnixCommand *ucmd = (UnixCommand *)data;
715 
716  uptime = time(NULL) - ucmd->start_timestamp;
717  json_object_set_new(server_msg, "message", json_integer(uptime));
719 }
720 
721 static TmEcode UnixManagerRunningModeCommand(json_t *cmd,
722  json_t *server_msg, void *data)
723 {
724  SCEnter();
725  json_object_set_new(server_msg, "message", json_string(RunmodeGetActive()));
727 }
728 
729 static TmEcode UnixManagerCaptureModeCommand(json_t *cmd,
730  json_t *server_msg, void *data)
731 {
732  SCEnter();
733  json_object_set_new(server_msg, "message", json_string(RunModeGetMainMode()));
735 }
736 
737 static TmEcode UnixManagerReloadRulesWrapper(json_t *cmd, json_t *server_msg, void *data, int do_wait)
738 {
739  SCEnter();
740 
741  if (SuriHasSigFile()) {
742  json_object_set_new(server_msg, "message",
743  json_string("Live rule reload not possible if -s "
744  "or -S option used at runtime."));
746  }
747 
748  int r = DetectEngineReloadStart();
749 
750  if (r == 0 && do_wait) {
751  while (!DetectEngineReloadIsIdle())
752  usleep(100);
753  } else {
754  if (r == -1) {
755  json_object_set_new(server_msg, "message", json_string("Reload already in progress"));
757  }
758  }
759 
760  json_object_set_new(server_msg, "message", json_string("done"));
762 }
763 
764 static TmEcode UnixManagerReloadRules(json_t *cmd, json_t *server_msg, void *data)
765 {
766  return UnixManagerReloadRulesWrapper(cmd, server_msg, data, 1);
767 }
768 
769 static TmEcode UnixManagerNonBlockingReloadRules(json_t *cmd, json_t *server_msg, void *data)
770 {
771  return UnixManagerReloadRulesWrapper(cmd, server_msg, data, 0);
772 }
773 
774 static TmEcode UnixManagerReloadTimeCommand(json_t *cmd,
775  json_t *server_msg, void *data)
776 {
777  SCEnter();
778  TmEcode retval;
779  json_t *jdata = NULL;
780 
781  retval = OutputEngineStatsReloadTime(&jdata);
782  json_object_set_new(server_msg, "message", jdata);
783  SCReturnInt(retval);
784 }
785 
786 static TmEcode UnixManagerRulesetStatsCommand(json_t *cmd,
787  json_t *server_msg, void *data)
788 {
789  SCEnter();
790  TmEcode retval;
791  json_t *jdata = NULL;
792 
793  retval = OutputEngineStatsRuleset(&jdata);
794  json_object_set_new(server_msg, "message", jdata);
795  SCReturnInt(retval);
796 }
797 
798 static TmEcode UnixManagerShowFailedRules(json_t *cmd,
799  json_t *server_msg, void *data)
800 {
801  SCEnter();
802  int rules_cnt = 0;
804  if (de_ctx == NULL) {
805  json_object_set_new(server_msg, "message", json_string("Unable to get info"));
807  }
808 
809  /* Since we need to deference de_ctx, we don't want to lost it. */
810  DetectEngineCtx *list = de_ctx;
811  json_t *js_sigs_array = json_array();
812 
813  if (js_sigs_array == NULL) {
814  json_object_set_new(server_msg, "message", json_string("Unable to get info"));
815  goto error;
816  }
817  while (list) {
818  SigString *sigs_str = NULL;
819  TAILQ_FOREACH(sigs_str, &list->sig_stat.failed_sigs, next) {
820  json_t *jdata = json_object();
821  if (jdata == NULL) {
822  json_object_set_new(server_msg, "message", json_string("Unable to get the sig"));
823  goto error;
824  }
825 
826  json_object_set_new(jdata, "tenant_id", json_integer(list->tenant_id));
827  json_object_set_new(jdata, "rule", json_string(sigs_str->sig_str));
828  json_object_set_new(jdata, "filename", json_string(sigs_str->filename));
829  json_object_set_new(jdata, "line", json_integer(sigs_str->line));
830  if (sigs_str->sig_error) {
831  json_object_set_new(jdata, "error", json_string(sigs_str->sig_error));
832  }
833  json_array_append_new(js_sigs_array, jdata);
834  if (++rules_cnt > MAX_FAILED_RULES) {
835  break;
836  }
837  }
838  if (rules_cnt > MAX_FAILED_RULES) {
839  break;
840  }
841  list = list->next;
842  }
843 
844  json_object_set_new(server_msg, "message", js_sigs_array);
845  DetectEngineDeReference(&de_ctx);
847 
848 error:
849  DetectEngineDeReference(&de_ctx);
850  json_object_clear(js_sigs_array);
851  json_decref(js_sigs_array);
853 }
854 
855 static TmEcode UnixManagerConfGetCommand(json_t *cmd,
856  json_t *server_msg, void *data)
857 {
858  SCEnter();
859 
860  const char *confval = NULL;
861  char *variable = NULL;
862 
863  json_t *jarg = json_object_get(cmd, "variable");
864  if(!json_is_string(jarg)) {
865  SCLogInfo("error: variable is not a string");
866  json_object_set_new(server_msg, "message", json_string("variable is not a string"));
868  }
869 
870  variable = (char *)json_string_value(jarg);
871  if (ConfGet(variable, &confval) != 1) {
872  json_object_set_new(server_msg, "message", json_string("Unable to get value"));
874  }
875 
876  if (confval) {
877  json_object_set_new(server_msg, "message", json_string(confval));
879  }
880 
881  json_object_set_new(server_msg, "message", json_string("No string value"));
883 }
884 
885 static TmEcode UnixManagerListCommand(json_t *cmd,
886  json_t *answer, void *data)
887 {
888  SCEnter();
889  json_t *jdata;
890  json_t *jarray;
891  Command *lcmd = NULL;
892  UnixCommand *gcmd = (UnixCommand *) data;
893  int i = 0;
894 
895  jdata = json_object();
896  if (jdata == NULL) {
897  json_object_set_new(answer, "message",
898  json_string("internal error at json object creation"));
899  return TM_ECODE_FAILED;
900  }
901  jarray = json_array();
902  if (jarray == NULL) {
903  json_object_set_new(answer, "message",
904  json_string("internal error at json object creation"));
905  return TM_ECODE_FAILED;
906  }
907 
908  TAILQ_FOREACH(lcmd, &gcmd->commands, next) {
909  json_array_append_new(jarray, json_string(lcmd->name));
910  i++;
911  }
912 
913  json_object_set_new(jdata, "count", json_integer(i));
914  json_object_set_new(jdata, "commands", jarray);
915  json_object_set_new(answer, "message", jdata);
917 }
918 
919 static TmEcode UnixManagerReopenLogFiles(json_t *cmd, json_t *server_msg, void *data)
920 {
922  json_object_set_new(server_msg, "message", json_string("done"));
924 }
925 
926 #if 0
927 TmEcode UnixManagerReloadRules(json_t *cmd,
928  json_t *server_msg, void *data)
929 {
930  SCEnter();
931  if (suricata_ctl_flags != 0) {
932  json_object_set_new(server_msg, "message",
933  json_string("Live rule swap no longer possible."
934  " Engine in shutdown mode."));
936  } else {
937  /* FIXME : need to check option value */
938  UtilSignalHandlerSetup(SIGUSR2, SignalHandlerSigusr2Idle);
939  DetectEngineSpawnLiveRuleSwapMgmtThread();
940  json_object_set_new(server_msg, "message", json_string("Reloading rules"));
941  }
943 }
944 #endif
945 
946 static UnixCommand command;
947 
948 /**
949  * \brief Add a command to the list of commands
950  *
951  * This function adds a command to the list of commands available
952  * through the unix socket.
953  *
954  * When a command is received from user through the unix socket, the content
955  * of 'Command' field in the JSON message is match against keyword, then the
956  * Func is called. See UnixSocketAddPcapFile() for an example.
957  *
958  * \param keyword name of the command
959  * \param Func function to run when command is received
960  * \param data a pointer to data that are passed to Func when it is run
961  * \param flags a flag now used to tune the command type
962  * \retval TM_ECODE_OK in case of success, TM_ECODE_FAILED in case of failure
963  */
964 TmEcode UnixManagerRegisterCommand(const char * keyword,
965  TmEcode (*Func)(json_t *, json_t *, void *),
966  void *data, int flags)
967 {
968  SCEnter();
969  Command *cmd = NULL;
970  Command *lcmd = NULL;
971 
972  if (Func == NULL) {
973  SCLogError(SC_ERR_INVALID_ARGUMENT, "Null function");
975  }
976 
977  if (keyword == NULL) {
978  SCLogError(SC_ERR_INVALID_ARGUMENT, "Null keyword");
980  }
981 
982  TAILQ_FOREACH(lcmd, &command.commands, next) {
983  if (!strcmp(keyword, lcmd->name)) {
984  SCLogError(SC_ERR_INVALID_ARGUMENT, "%s already registered", keyword);
986  }
987  }
988 
989  cmd = SCMalloc(sizeof(Command));
990  if (unlikely(cmd == NULL)) {
991  SCLogError(SC_ERR_MEM_ALLOC, "Can't alloc cmd");
993  }
994  cmd->name = SCStrdup(keyword);
995  if (unlikely(cmd->name == NULL)) {
996  SCLogError(SC_ERR_MEM_ALLOC, "Can't alloc cmd name");
997  SCFree(cmd);
999  }
1000  cmd->Func = Func;
1001  cmd->data = data;
1002  cmd->flags = flags;
1003  /* Add it to the list */
1004  TAILQ_INSERT_TAIL(&command.commands, cmd, next);
1005 
1007 }
1008 
1009 /**
1010  * \brief Add a task to the list of tasks
1011  *
1012  * This function adds a task to run in the background. The task is run
1013  * each time the UnixMain() function exits from select.
1014  *
1015  * \param Func function to run when a command is received
1016  * \param data a pointer to data that are passed to Func when it is run
1017  * \retval TM_ECODE_OK in case of success, TM_ECODE_FAILED in case of failure
1018  */
1019 TmEcode UnixManagerRegisterBackgroundTask(TmEcode (*Func)(void *),
1020  void *data)
1021 {
1022  SCEnter();
1023  Task *task = NULL;
1024 
1025  if (Func == NULL) {
1026  SCLogError(SC_ERR_INVALID_ARGUMENT, "Null function");
1028  }
1029 
1030  task = SCMalloc(sizeof(Task));
1031  if (unlikely(task == NULL)) {
1032  SCLogError(SC_ERR_MEM_ALLOC, "Can't alloc task");
1034  }
1035  task->Func = Func;
1036  task->data = data;
1037  /* Add it to the list */
1038  TAILQ_INSERT_TAIL(&command.tasks, task, next);
1039 
1041 }
1042 
1043 int UnixManagerInit(void)
1044 {
1045  if (UnixNew(&command) == 0) {
1046  int failure_fatal = 0;
1047  if (ConfGetBool("engine.init-failure-fatal", &failure_fatal) != 1) {
1048  SCLogDebug("ConfGetBool could not load the value.");
1049  }
1050  if (failure_fatal) {
1052  "Unable to create unix command socket");
1053  exit(EXIT_FAILURE);
1054  } else {
1056  "Unable to create unix command socket");
1057  return -1;
1058  }
1059  }
1060 
1061  /* Init Unix socket */
1062  UnixManagerRegisterCommand("shutdown", UnixManagerShutdownCommand, NULL, 0);
1063  UnixManagerRegisterCommand("command-list", UnixManagerListCommand, &command, 0);
1064  UnixManagerRegisterCommand("help", UnixManagerListCommand, &command, 0);
1065  UnixManagerRegisterCommand("version", UnixManagerVersionCommand, &command, 0);
1066  UnixManagerRegisterCommand("uptime", UnixManagerUptimeCommand, &command, 0);
1067  UnixManagerRegisterCommand("running-mode", UnixManagerRunningModeCommand, &command, 0);
1068  UnixManagerRegisterCommand("capture-mode", UnixManagerCaptureModeCommand, &command, 0);
1069  UnixManagerRegisterCommand("conf-get", UnixManagerConfGetCommand, &command, UNIX_CMD_TAKE_ARGS);
1070  UnixManagerRegisterCommand("dump-counters", StatsOutputCounterSocket, NULL, 0);
1071  UnixManagerRegisterCommand("reload-rules", UnixManagerReloadRules, NULL, 0);
1072  UnixManagerRegisterCommand("ruleset-reload-rules", UnixManagerReloadRules, NULL, 0);
1073  UnixManagerRegisterCommand("ruleset-reload-nonblocking", UnixManagerNonBlockingReloadRules, NULL, 0);
1074  UnixManagerRegisterCommand("ruleset-reload-time", UnixManagerReloadTimeCommand, NULL, 0);
1075  UnixManagerRegisterCommand("ruleset-stats", UnixManagerRulesetStatsCommand, NULL, 0);
1076  UnixManagerRegisterCommand("ruleset-failed-rules", UnixManagerShowFailedRules, NULL, 0);
1077  UnixManagerRegisterCommand("register-tenant-handler", UnixSocketRegisterTenantHandler, &command, UNIX_CMD_TAKE_ARGS);
1078  UnixManagerRegisterCommand("unregister-tenant-handler", UnixSocketUnregisterTenantHandler, &command, UNIX_CMD_TAKE_ARGS);
1079  UnixManagerRegisterCommand("register-tenant", UnixSocketRegisterTenant, &command, UNIX_CMD_TAKE_ARGS);
1080  UnixManagerRegisterCommand("reload-tenant", UnixSocketReloadTenant, &command, UNIX_CMD_TAKE_ARGS);
1081  UnixManagerRegisterCommand("unregister-tenant", UnixSocketUnregisterTenant, &command, UNIX_CMD_TAKE_ARGS);
1082  UnixManagerRegisterCommand("add-hostbit", UnixSocketHostbitAdd, &command, UNIX_CMD_TAKE_ARGS);
1083  UnixManagerRegisterCommand("remove-hostbit", UnixSocketHostbitRemove, &command, UNIX_CMD_TAKE_ARGS);
1084  UnixManagerRegisterCommand("list-hostbit", UnixSocketHostbitList, &command, UNIX_CMD_TAKE_ARGS);
1085  UnixManagerRegisterCommand("reopen-log-files", UnixManagerReopenLogFiles, NULL, 0);
1086  UnixManagerRegisterCommand("memcap-set", UnixSocketSetMemcap, &command, UNIX_CMD_TAKE_ARGS);
1087  UnixManagerRegisterCommand("memcap-show", UnixSocketShowMemcap, &command, UNIX_CMD_TAKE_ARGS);
1088  UnixManagerRegisterCommand("memcap-list", UnixSocketShowAllMemcap, NULL, 0);
1089 
1090  UnixManagerRegisterCommand("dataset-add", UnixSocketDatasetAdd, &command, UNIX_CMD_TAKE_ARGS);
1091 
1092  return 0;
1093 }
1094 
1095 typedef struct UnixManagerThreadData_ {
1096  int padding;
1097 } UnixManagerThreadData;
1098 
1099 static TmEcode UnixManagerThreadInit(ThreadVars *t, const void *initdata, void **data)
1100 {
1101  UnixManagerThreadData *utd = SCCalloc(1, sizeof(*utd));
1102  if (utd == NULL)
1103  return TM_ECODE_FAILED;
1104 
1105  *data = utd;
1106  return TM_ECODE_OK;
1107 }
1108 
1109 static TmEcode UnixManagerThreadDeinit(ThreadVars *t, void *data)
1110 {
1111  SCFree(data);
1112  return TM_ECODE_OK;
1113 }
1114 
1115 static TmEcode UnixManager(ThreadVars *th_v, void *thread_data)
1116 {
1117  int ret;
1118 
1119  /* set the thread name */
1120  SCLogDebug("%s started...", th_v->name);
1121 
1122  StatsSetupPrivate(th_v);
1123 
1124  /* Set the threads capability */
1125  th_v->cap_flags = 0;
1126  SCDropCaps(th_v);
1127 
1129  while (1) {
1130  ret = UnixMain(&command);
1131  if (ret == 0) {
1132  SCLogError(SC_ERR_FATAL, "Fatal error on unix socket");
1133  }
1134 
1135  if ((ret == 0) || (TmThreadsCheckFlag(th_v, THV_KILL))) {
1136  UnixClient *item;
1137  UnixClient *titem;
1138  TAILQ_FOREACH_SAFE(item, &(&command)->clients, next, titem) {
1139  close(item->fd);
1140  SCFree(item);
1141  }
1142  StatsSyncCounters(th_v);
1143  break;
1144  }
1145 
1146  UnixCommandBackgroundTasks(&command);
1147  }
1148  return TM_ECODE_OK;
1149 }
1150 
1151 
1152 /** \brief Spawn the unix socket manager thread
1153  *
1154  * \param mode if set to 1, init failure cause suricata exit
1155  * */
1156 void UnixManagerThreadSpawn(int mode)
1157 {
1158  ThreadVars *tv_unixmgr = NULL;
1159 
1162 
1164  "UnixManager", 0);
1165 
1166  if (tv_unixmgr == NULL) {
1167  SCLogError(SC_ERR_INITIALIZATION, "TmThreadsCreate failed");
1168  exit(EXIT_FAILURE);
1169  }
1170  if (TmThreadSpawn(tv_unixmgr) != TM_ECODE_OK) {
1171  SCLogError(SC_ERR_INITIALIZATION, "TmThreadSpawn failed");
1172  exit(EXIT_FAILURE);
1173  }
1174  if (mode == 1) {
1175  if (TmThreadsCheckFlag(tv_unixmgr, THV_RUNNING_DONE)) {
1176  SCLogError(SC_ERR_INITIALIZATION, "Unix socket init failed");
1177  exit(EXIT_FAILURE);
1178  }
1179  }
1180  return;
1181 }
1182 
1183 // TODO can't think of a good name
1185 {
1186  /* Spawn the unix socket manager thread */
1187  int unix_socket = ConfUnixSocketIsEnable();
1188  if (unix_socket == 1) {
1189  if (UnixManagerInit() == 0) {
1190  UnixManagerRegisterCommand("iface-stat", LiveDeviceIfaceStat, NULL,
1192  UnixManagerRegisterCommand("iface-list", LiveDeviceIfaceList, NULL, 0);
1193  UnixManagerRegisterCommand("iface-bypassed-stat",
1194  LiveDeviceGetBypassedStats, NULL, 0);
1195  /* For backward compatibility */
1196  UnixManagerRegisterCommand("ebpf-bypassed-stat",
1197  LiveDeviceGetBypassedStats, NULL, 0);
1199  }
1200  }
1201 }
1202 
1203 /**
1204  * \brief Used to kill unix manager thread(s).
1205  *
1206  * \todo Kinda hackish since it uses the tv name to identify unix manager
1207  * thread. We need an all weather identification scheme.
1208  */
1209 void UnixSocketKillSocketThread(void)
1210 {
1211  ThreadVars *tv = NULL;
1212 
1213 again:
1215 
1216  /* unix manager thread(s) is/are a part of command threads */
1217  tv = tv_root[TVT_CMD];
1218 
1219  while (tv != NULL) {
1220  if (strcasecmp(tv->name, "UnixManagerThread") == 0) {
1221  /* If the thread dies during init it will have
1222  * THV_RUNNING_DONE set, so we can set the correct flag
1223  * and exit.
1224  */
1229  break;
1230  }
1233  /* Be sure it has shut down */
1234  if (!TmThreadsCheckFlag(tv, THV_CLOSED)) {
1236  usleep(100);
1237  goto again;
1238  }
1239  }
1240  tv = tv->next;
1241  }
1242 
1244  return;
1245 }
1246 
1247 #else /* BUILD_UNIX_SOCKET */
1248 
1250 {
1251  SCLogError(SC_ERR_UNIMPLEMENTED, "Unix socket is not compiled");
1252  return;
1253 }
1254 
1256 {
1257  return;
1258 }
1259 
1261 {
1262  return;
1263 }
1264 
1265 #endif /* BUILD_UNIX_SOCKET */
1266 
1268 {
1269 #if defined(BUILD_UNIX_SOCKET) && defined(HAVE_SYS_UN_H) && defined(HAVE_SYS_STAT_H) && defined(HAVE_SYS_TYPES_H)
1270  tmm_modules[TMM_UNIXMANAGER].name = "UnixManager";
1271  tmm_modules[TMM_UNIXMANAGER].ThreadInit = UnixManagerThreadInit;
1272  tmm_modules[TMM_UNIXMANAGER].ThreadDeinit = UnixManagerThreadDeinit;
1273  tmm_modules[TMM_UNIXMANAGER].Management = UnixManager;
1276 #endif /* BUILD_UNIX_SOCKET */
1277 }
MemBuffer * MemBufferCreateNew(uint32_t size)
Definition: util-buffer.c:32
#define SCDropCaps(...)
Definition: util-privs.h:37
uint16_t flags
#define SCLogDebug(...)
Definition: util-debug.h:335
#define MemBufferWriteRaw(dst, raw_buffer, raw_buffer_len)
Write a raw buffer to the MemBuffer dst.
Definition: util-buffer.h:133
uint8_t cap_flags
Definition: tm-modules.h:67
#define MEMBUFFER_SIZE(mem_buffer)
Get the MemBuffers current size.
Definition: util-buffer.h:60
#define TAILQ_FOREACH(var, head, field)
Definition: queue.h:350
struct HtpBodyChunk_ * next
size_t strlcpy(char *dst, const char *src, size_t siz)
Definition: util-strlcpyu.c:43
uint8_t flags
Definition: tm-modules.h:70
#define THV_RUNNING_DONE
Definition: threadvars.h:45
void DetectEngineDeReference(DetectEngineCtx **de_ctx)
#define SCMkDir(a, b)
Definition: util-path.h:29
#define unlikely(expr)
Definition: util-optimize.h:35
DetectEngineCtx * DetectEngineGetCurrent(void)
int ConfGetBool(const char *name, int *val)
Retrieve a configuration value as an boolen.
Definition: conf.c:517
#define MemBufferReset(mem_buffer)
Reset the mem buffer.
Definition: util-buffer.h:42
#define SCCtrlCondInit
#define TAILQ_FOREACH_SAFE(var, head, field, tvar)
Definition: queue.h:356
uint64_t offset
int ConfUnixSocketIsEnable(void)
Definition: util-conf.c:144
volatile uint8_t suricata_ctl_flags
Definition: suricata.c:201
#define TAILQ_HEAD(name, type)
Definition: queue.h:321
ThreadVars * TmThreadCreateCmdThreadByName(const char *name, const char *module, int mucond)
Creates and returns the TV instance for a Command thread (CMD). This function supports only custom sl...
Definition: tm-threads.c:1316
#define xstr(s)
#define SCMutexLock(mut)
int ConfGet(const char *name, const char **vptr)
Retrieve the value of a configuration node.
Definition: conf.c:331
char * RunmodeGetActive(void)
Definition: runmodes.c:187
main detection engine ctx
Definition: detect.h:761
int UnixManagerInit(void)
void TmThreadsSetFlag(ThreadVars *tv, uint16_t flag)
Set a thread flag.
Definition: tm-threads.c:98
#define SURICATA_STOP
Definition: suricata.h:95
#define SCCalloc(nm, a)
Definition: util-mem.h:253
SCCtrlMutex unix_manager_ctrl_mutex
Definition: unix-manager.h:30
#define UNIX_CMD_TAKE_ARGS
Definition: unix-manager.h:27
#define SCMutexUnlock(mut)
#define THV_INIT_DONE
Definition: threadvars.h:36
#define THV_CLOSED
Definition: threadvars.h:41
SCMutex tv_root_lock
Definition: tm-threads.c:82
TmEcode(* Management)(ThreadVars *, void *)
Definition: tm-modules.h:59
#define TAILQ_INIT(head)
Definition: queue.h:370
#define SCLogError(err_code,...)
Macro used to log ERROR messages.
Definition: util-debug.h:294
struct ThreadVars_ * next
Definition: threadvars.h:111
char * filename
Definition: detect.h:715
struct DetectEngineCtx_ * next
Definition: detect.h:898
#define TAILQ_REMOVE(head, elm, field)
Definition: queue.h:412
TmEcode(* ThreadDeinit)(ThreadVars *, void *)
Definition: tm-modules.h:49
#define SCEnter(...)
Definition: util-debug.h:337
SigFileLoaderStat sig_stat
Definition: detect.h:941
int DetectEngineReloadIsIdle(void)
uint32_t padding
Definition: decode-erspan.h:49
SCCtrlCondT unix_manager_ctrl_cond
Definition: unix-manager.h:29
void UnixManagerThreadSpawn(int mode)
int PathIsAbsolute(const char *path)
Check if a path is absolute.
Definition: util-path.c:39
#define SCReturnInt(x)
Definition: util-debug.h:341
#define THV_KILL
Definition: threadvars.h:39
#define SCLogWarning(err_code,...)
Macro used to log WARNING messages.
Definition: util-debug.h:281
void UnixSocketKillSocketThread(void)
TmEcode OutputEngineStatsRuleset(json_t **jdata)
#define MEMBUFFER_BUFFER(mem_buffer)
Get the MemBuffers underlying buffer.
Definition: util-buffer.h:50
#define TAILQ_INSERT_TAIL(head, elm, field)
Definition: queue.h:385
int OutputJSONMemBufferCallback(const char *str, size_t size, void *data)
Definition: output-json.c:796
const char * name
Definition: tm-modules.h:44
#define SCMalloc(a)
Definition: util-mem.h:222
char * sig_error
Definition: detect.h:717
void TmModuleUnixManagerRegister(void)
#define JSON_ESCAPE_SLASH
#define SCLogInfo(...)
Macro used to log INFORMATIONAL messages.
Definition: util-debug.h:254
uint8_t version
Definition: decode-gre.h:405
#define SCFree(a)
Definition: util-mem.h:322
TmModule tmm_modules[TMM_SIZE]
Definition: tm-modules.h:73
#define TAILQ_ENTRY(type)
Definition: queue.h:330
const char * RunModeGetMainMode(void)
Definition: runmodes.c:199
#define MEMBUFFER_OFFSET(mem_buffer)
Get the MemBuffers current offset.
Definition: util-buffer.h:55
TmEcode OutputEngineStatsReloadTime(json_t **jdata)
int line
Definition: detect.h:718
TmEcode(* ThreadInit)(ThreadVars *, const void *, void **)
Definition: tm-modules.h:47
int StatsSetupPrivate(ThreadVars *tv)
Definition: counters.c:1198
int TmThreadsCheckFlag(ThreadVars *tv, uint16_t flag)
Check if a thread flag is set.
Definition: tm-threads.c:90
#define StatsSyncCounters(tv)
Definition: counters.h:134
#define SCStrdup(a)
Definition: util-mem.h:268
int DetectEngineReloadStart(void)
char name[16]
Definition: threadvars.h:59
char * sig_str
Definition: detect.h:716
void EngineStop(void)
make sure threads can stop the engine by calling this function. Purpose: pcap file mode needs to be a...
Definition: suricata.c:431
ThreadVars * tv_root[TVT_MAX]
Definition: tm-threads.c:79
#define SCReturn
Definition: util-debug.h:339
void UtilSignalHandlerSetup(int sig, void(*handler)(int))
Definition: util-signal.c:60
#define THV_DEINIT
Definition: threadvars.h:44
uint8_t len
Per thread variable structure.
Definition: threadvars.h:57
#define SCCtrlMutexInit(mut, mutattr)
const char * thread_name_unix_socket
Definition: runmodes.c:68
uint8_t cap_flags
Definition: threadvars.h:109
void UnixManagerThreadSpawnNonRunmode(void)
int MemBufferExpand(MemBuffer **buffer, uint32_t expand_by)
expand membuffer by size of &#39;expand_by&#39;
Definition: util-buffer.c:60
TmEcode TmThreadSpawn(ThreadVars *tv)
Spawns a thread associated with the ThreadVars instance tv.
Definition: tm-threads.c:1855
#define PROG_VER
Definition: suricata.h:72
int SuriHasSigFile(void)
Definition: suricata.c:242
void MemBufferFree(MemBuffer *buffer)
Definition: util-buffer.c:82
#define TM_FLAG_COMMAND_TM
Definition: tm-modules.h:37
void OutputNotifyFileRotation(void)
Notifies all registered file rotation notification flags.
Definition: output.c:910