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 <jansson.h>
47 
48 #include "output.h"
49 #include "output-json.h"
50 
51 // MSG_NOSIGNAL does not exists on OS X
52 #ifdef OS_DARWIN
53 # ifndef MSG_NOSIGNAL
54 # define MSG_NOSIGNAL SO_NOSIGPIPE
55 # endif
56 #endif
57 
58 #define SOCKET_PATH LOCAL_STATE_DIR "/run/suricata/"
59 #define SOCKET_FILENAME "suricata-command.socket"
60 #define SOCKET_TARGET SOCKET_PATH SOCKET_FILENAME
61 
62 #define MAX_FAILED_RULES 20
63 
64 typedef struct Command_ {
65  char *name;
66  TmEcode (*Func)(json_t *, json_t *, void *);
67  void *data;
68  int flags;
69  TAILQ_ENTRY(Command_) next;
70 } Command;
71 
72 typedef struct Task_ {
73  TmEcode (*Func)(void *);
74  void *data;
75  TAILQ_ENTRY(Task_) next;
76 } Task;
77 
78 #define CLIENT_BUFFER_SIZE 4096
79 typedef struct UnixClient_ {
80  int fd;
81  MemBuffer *mbuf; /**< buffer for response construction */
82  int version;
83  TAILQ_ENTRY(UnixClient_) next;
84 } UnixClient;
85 
86 typedef struct UnixCommand_ {
87  time_t start_timestamp;
88  int socket;
89  struct sockaddr_un client_addr;
90  int select_max;
91  TAILQ_HEAD(, Command_) commands;
92  TAILQ_HEAD(, Task_) tasks;
93  TAILQ_HEAD(, UnixClient_) clients;
94 } UnixCommand;
95 
96 /**
97  * \brief Create a command unix socket on system
98  *
99  * \retval 0 in case of error, 1 in case of success
100  */
101 static int UnixNew(UnixCommand * this)
102 {
103  struct sockaddr_un addr;
104  int len;
105  int ret;
106  int on = 1;
107  char sockettarget[PATH_MAX];
108  const char *socketname;
109 
110  this->start_timestamp = time(NULL);
111  this->socket = -1;
112  this->select_max = 0;
113 
114  TAILQ_INIT(&this->commands);
115  TAILQ_INIT(&this->tasks);
116  TAILQ_INIT(&this->clients);
117 
118  int check_dir = 0;
119  if (ConfGet("unix-command.filename", &socketname) == 1) {
120  if (PathIsAbsolute(socketname)) {
121  strlcpy(sockettarget, socketname, sizeof(sockettarget));
122  } else {
123  snprintf(sockettarget, sizeof(sockettarget), "%s/%s",
124  SOCKET_PATH, socketname);
125  check_dir = 1;
126  }
127  } else {
128  strlcpy(sockettarget, SOCKET_TARGET, sizeof(sockettarget));
129  check_dir = 1;
130  }
131  SCLogInfo("Using unix socket file '%s'", sockettarget);
132 
133  if (check_dir) {
134  struct stat stat_buf;
135  /* coverity[toctou] */
136  if (stat(SOCKET_PATH, &stat_buf) != 0) {
137  /* coverity[toctou] */
138  ret = SCMkDir(SOCKET_PATH, S_IRWXU|S_IXGRP|S_IRGRP);
139  if (ret != 0) {
140  int err = errno;
141  if (err != EEXIST) {
143  "Cannot create socket directory %s: %s",
144  SOCKET_PATH, strerror(err));
145  return 0;
146  }
147  } else {
148  SCLogInfo("Created socket directory %s",
149  SOCKET_PATH);
150  }
151  }
152  }
153 
154  /* Remove socket file */
155  (void) unlink(sockettarget);
156 
157  /* set address */
158  addr.sun_family = AF_UNIX;
159  strlcpy(addr.sun_path, sockettarget, sizeof(addr.sun_path));
160  addr.sun_path[sizeof(addr.sun_path) - 1] = 0;
161  len = strlen(addr.sun_path) + sizeof(addr.sun_family) + 1;
162 
163  /* create socket */
164  this->socket = socket(AF_UNIX, SOCK_STREAM, 0);
165  if (this->socket == -1) {
167  "Unix Socket: unable to create UNIX socket %s: %s",
168  addr.sun_path, strerror(errno));
169  return 0;
170  }
171  this->select_max = this->socket + 1;
172 
173  /* set reuse option */
174  ret = setsockopt(this->socket, SOL_SOCKET, SO_REUSEADDR,
175  (char *) &on, sizeof(on));
176  if ( ret != 0 ) {
178  "Cannot set sockets options: %s.", strerror(errno));
179  }
180 
181  /* bind socket */
182  ret = bind(this->socket, (struct sockaddr *) &addr, len);
183  if (ret == -1) {
185  "Unix socket: UNIX socket bind(%s) error: %s",
186  sockettarget, strerror(errno));
187  return 0;
188  }
189 
190 #if !(defined OS_FREEBSD || defined __OpenBSD__)
191  /* Set file mode: will not fully work on most system, the group
192  * permission is not changed on some Linux. *BSD won't do the
193  * chmod: it returns EINVAL when calling chmod on sockets. */
194  ret = chmod(sockettarget, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP);
195  if (ret == -1) {
196  int err = errno;
198  "Unable to change permission on socket: %s (%d)",
199  strerror(err),
200  err);
201  }
202 #endif
203 
204  /* listen */
205  if (listen(this->socket, 1) == -1) {
207  "Command server: UNIX socket listen() error: %s",
208  strerror(errno));
209  return 0;
210  }
211  return 1;
212 }
213 
214 static void UnixCommandSetMaxFD(UnixCommand *this)
215 {
216  UnixClient *item;
217 
218  if (this == NULL) {
219  SCLogError(SC_ERR_INVALID_ARGUMENT, "Unix command is NULL, warn devel");
220  return;
221  }
222 
223  this->select_max = this->socket + 1;
224  TAILQ_FOREACH(item, &this->clients, next) {
225  if (item->fd >= this->select_max) {
226  this->select_max = item->fd + 1;
227  }
228  }
229 }
230 
231 static UnixClient *UnixClientAlloc(void)
232 {
233  UnixClient *uclient = SCMalloc(sizeof(UnixClient));
234  if (unlikely(uclient == NULL)) {
235  SCLogError(SC_ERR_MEM_ALLOC, "Can't allocate new client");
236  return NULL;
237  }
238  uclient->mbuf = MemBufferCreateNew(CLIENT_BUFFER_SIZE);
239  if (uclient->mbuf == NULL) {
240  SCLogError(SC_ERR_MEM_ALLOC, "Can't allocate new client send buffer");
241  SCFree(uclient);
242  return NULL;
243  }
244  return uclient;
245 }
246 
247 static void UnixClientFree(UnixClient *c)
248 {
249  if (c != NULL) {
250  MemBufferFree(c->mbuf);
251  SCFree(c);
252  }
253 }
254 
255 /**
256  * \brief Close the unix socket
257  */
258 static void UnixCommandClose(UnixCommand *this, int fd)
259 {
260  UnixClient *item;
261  int found = 0;
262 
263  TAILQ_FOREACH(item, &this->clients, next) {
264  if (item->fd == fd) {
265  found = 1;
266  break;
267  }
268  }
269 
270  if (found == 0) {
271  SCLogError(SC_ERR_INVALID_VALUE, "No fd found in client list");
272  return;
273  }
274 
275  TAILQ_REMOVE(&this->clients, item, next);
276 
277  close(item->fd);
278  UnixCommandSetMaxFD(this);
279  UnixClientFree(item);
280 }
281 
282 #define UNIX_PROTO_VERSION_LENGTH 200
283 #define UNIX_PROTO_VERSION_V1 "0.1"
284 #define UNIX_PROTO_V1 1
285 #define UNIX_PROTO_VERSION "0.2"
286 #define UNIX_PROTO_V2 2
287 
288 static int UnixCommandSendJSONToClient(UnixClient *client, json_t *js)
289 {
290  MemBufferReset(client->mbuf);
291 
292  OutputJSONMemBufferWrapper wrapper = {
293  .buffer = &client->mbuf,
294  .expand_by = CLIENT_BUFFER_SIZE
295  };
296 
297  int r = json_dump_callback(js, OutputJSONMemBufferCallback, &wrapper,
298  JSON_PRESERVE_ORDER|JSON_COMPACT|JSON_ENSURE_ASCII|
299  JSON_ESCAPE_SLASH);
300  if (r != 0) {
301  SCLogWarning(SC_ERR_SOCKET, "unable to serialize JSON object");
302  return -1;
303  }
304 
305  if (client->version > UNIX_PROTO_V1) {
306  if (MEMBUFFER_OFFSET(client->mbuf) + 1 >= MEMBUFFER_SIZE(client->mbuf)) {
307  MemBufferExpand(&client->mbuf, 1);
308  }
309  MemBufferWriteRaw(client->mbuf, "\n", 1);
310  }
311 
312  if (send(client->fd, (const char *)MEMBUFFER_BUFFER(client->mbuf),
313  MEMBUFFER_OFFSET(client->mbuf), MSG_NOSIGNAL) == -1)
314  {
315  SCLogWarning(SC_ERR_SOCKET, "unable to send block of size "
316  "%"PRIuMAX": %s", (uintmax_t)MEMBUFFER_OFFSET(client->mbuf),
317  strerror(errno));
318  return -1;
319  }
320 
321  SCLogDebug("sent message of size %"PRIuMAX" to client socket %d",
322  (uintmax_t)MEMBUFFER_OFFSET(client->mbuf), client->fd);
323  return 0;
324 }
325 
326 /**
327  * \brief Accept a new client on unix socket
328  *
329  * The function is called when a new user is detected
330  * in UnixMain(). It does the initial protocol negotiation
331  * with client.
332  *
333  * \retval 0 in case of error, 1 in case of success
334  */
335 static int UnixCommandAccept(UnixCommand *this)
336 {
337  char buffer[UNIX_PROTO_VERSION_LENGTH + 1];
338  json_t *client_msg;
339  json_t *server_msg;
340  json_t *version;
341  json_error_t jerror;
342  int client;
343  int client_version;
344  int ret;
345  UnixClient *uclient = NULL;
346 
347  /* accept client socket */
348  socklen_t len = sizeof(this->client_addr);
349  client = accept(this->socket, (struct sockaddr *) &this->client_addr,
350  &len);
351  if (client < 0) {
352  SCLogInfo("Unix socket: accept() error: %s",
353  strerror(errno));
354  return 0;
355  }
356  SCLogDebug("Unix socket: client connection");
357 
358  /* read client version */
359  buffer[sizeof(buffer)-1] = 0;
360  ret = recv(client, buffer, sizeof(buffer)-1, 0);
361  if (ret < 0) {
362  SCLogInfo("Command server: client doesn't send version");
363  close(client);
364  return 0;
365  }
366  if (ret >= (int)(sizeof(buffer)-1)) {
367  SCLogInfo("Command server: client message is too long, "
368  "disconnect him.");
369  close(client);
370  return 0;
371  }
372  buffer[ret] = 0;
373 
374  client_msg = json_loads(buffer, 0, &jerror);
375  if (client_msg == NULL) {
376  SCLogInfo("Invalid command, error on line %d: %s\n", jerror.line, jerror.text);
377  close(client);
378  return 0;
379  }
380 
381  version = json_object_get(client_msg, "version");
382  if (!json_is_string(version)) {
383  SCLogInfo("error: version is not a string");
384  close(client);
385  json_decref(client_msg);
386  return 0;
387  }
388 
389  /* check client version */
390  if ((strcmp(json_string_value(version), UNIX_PROTO_VERSION) != 0)
391  && (strcmp(json_string_value(version), UNIX_PROTO_VERSION_V1) != 0)) {
392  SCLogInfo("Unix socket: invalid client version: \"%s\"",
393  json_string_value(version));
394  json_decref(client_msg);
395  close(client);
396  return 0;
397  } else {
398  SCLogDebug("Unix socket: client version: \"%s\"",
399  json_string_value(version));
400  if (strcmp(json_string_value(version), UNIX_PROTO_VERSION_V1) == 0) {
401  client_version = UNIX_PROTO_V1;
402  } else {
403  client_version = UNIX_PROTO_V2;
404  }
405  }
406 
407  json_decref(client_msg);
408  /* send answer */
409  server_msg = json_object();
410  if (server_msg == NULL) {
411  close(client);
412  return 0;
413  }
414  json_object_set_new(server_msg, "return", json_string("OK"));
415 
416  uclient = UnixClientAlloc();
417  if (unlikely(uclient == NULL)) {
418  SCLogError(SC_ERR_MEM_ALLOC, "Can't allocate new client");
419  json_decref(server_msg);
420  close(client);
421  return 0;
422  }
423  uclient->fd = client;
424  uclient->version = client_version;
425 
426  if (UnixCommandSendJSONToClient(uclient, server_msg) != 0) {
427  SCLogWarning(SC_ERR_SOCKET, "Unable to send command");
428 
429  UnixClientFree(uclient);
430  json_decref(server_msg);
431  close(client);
432  return 0;
433  }
434 
435  json_decref(server_msg);
436 
437  /* client connected */
438  SCLogDebug("Unix socket: client connected");
439  TAILQ_INSERT_TAIL(&this->clients, uclient, next);
440  UnixCommandSetMaxFD(this);
441  return 1;
442 }
443 
444 static int UnixCommandBackgroundTasks(UnixCommand* this)
445 {
446  int ret = 1;
447  Task *ltask;
448 
449  TAILQ_FOREACH(ltask, &this->tasks, next) {
450  int fret = ltask->Func(ltask->data);
451  if (fret != TM_ECODE_OK) {
452  ret = 0;
453  }
454  }
455  return ret;
456 }
457 
458 /**
459  * \brief Command dispatcher
460  *
461  * \param this a UnixCommand:: structure
462  * \param command a string containing a json formatted
463  * command
464  *
465  * \retval 0 in case of error, 1 in case of success
466  */
467 static int UnixCommandExecute(UnixCommand * this, char *command, UnixClient *client)
468 {
469  int ret = 1;
470  json_error_t error;
471  json_t *jsoncmd = NULL;
472  json_t *cmd = NULL;
473  json_t *server_msg = json_object();
474  const char * value;
475  int found = 0;
476  Command *lcmd;
477 
478  if (server_msg == NULL) {
479  return 0;
480  }
481 
482  jsoncmd = json_loads(command, 0, &error);
483  if (jsoncmd == NULL) {
484  SCLogInfo("Invalid command, error on line %d: %s\n", error.line, error.text);
485  goto error;
486  }
487 
488  cmd = json_object_get(jsoncmd, "command");
489  if(!json_is_string(cmd)) {
490  SCLogInfo("error: command is not a string");
491  goto error_cmd;
492  }
493  value = json_string_value(cmd);
494 
495  TAILQ_FOREACH(lcmd, &this->commands, next) {
496  if (!strcmp(value, lcmd->name)) {
497  int fret = TM_ECODE_OK;
498  found = 1;
499  if (lcmd->flags & UNIX_CMD_TAKE_ARGS) {
500  cmd = json_object_get(jsoncmd, "arguments");
501  if(!json_is_object(cmd)) {
502  SCLogInfo("error: argument is not an object");
503  goto error_cmd;
504  }
505  }
506  fret = lcmd->Func(cmd, server_msg, lcmd->data);
507  if (fret != TM_ECODE_OK) {
508  ret = 0;
509  }
510  break;
511  }
512  }
513 
514  if (found == 0) {
515  json_object_set_new(server_msg, "message", json_string("Unknown command"));
516  ret = 0;
517  }
518 
519  switch (ret) {
520  case 0:
521  json_object_set_new(server_msg, "return", json_string("NOK"));
522  break;
523  case 1:
524  json_object_set_new(server_msg, "return", json_string("OK"));
525  break;
526  }
527 
528  if (UnixCommandSendJSONToClient(client, server_msg) != 0) {
529  goto error;
530  }
531 
532  json_decref(jsoncmd);
533  json_decref(server_msg);
534  return ret;
535 
536 error_cmd:
537  json_decref(jsoncmd);
538 error:
539  json_decref(server_msg);
540  UnixCommandClose(this, client->fd);
541  return 0;
542 }
543 
544 static void UnixCommandRun(UnixCommand * this, UnixClient *client)
545 {
546  char buffer[4096];
547  int ret;
548  if (client->version <= UNIX_PROTO_V1) {
549  ret = recv(client->fd, buffer, sizeof(buffer) - 1, 0);
550  if (ret <= 0) {
551  if (ret == 0) {
552  SCLogDebug("Unix socket: lost connection with client");
553  } else {
554  SCLogError(SC_ERR_SOCKET, "Unix socket: error on recv() from client: %s",
555  strerror(errno));
556  }
557  UnixCommandClose(this, client->fd);
558  return;
559  }
560  if (ret >= (int)(sizeof(buffer)-1)) {
561  SCLogError(SC_ERR_SOCKET, "Command server: client command is too long, "
562  "disconnect him.");
563  UnixCommandClose(this, client->fd);
564  }
565  buffer[ret] = 0;
566  } else {
567  int try = 0;
568  int offset = 0;
569  int cmd_over = 0;
570  ret = recv(client->fd, buffer + offset, sizeof(buffer) - offset - 1, 0);
571  do {
572  if (ret <= 0) {
573  if (ret == 0) {
574  SCLogInfo("Unix socket: lost connection with client");
575  } else {
576  SCLogInfo("Unix socket: error on recv() from client: %s",
577  strerror(errno));
578  }
579  UnixCommandClose(this, client->fd);
580  return;
581  }
582  if (ret >= (int)(sizeof(buffer)- offset - 1)) {
583  SCLogInfo("Command server: client command is too long, "
584  "disconnect him.");
585  UnixCommandClose(this, client->fd);
586  }
587  if (buffer[ret - 1] == '\n') {
588  buffer[ret-1] = 0;
589  cmd_over = 1;
590  } else {
591  struct timeval tv;
592  fd_set select_set;
593  offset += ret;
594  do {
595  FD_ZERO(&select_set);
596  FD_SET(client->fd, &select_set);
597  tv.tv_sec = 0;
598  tv.tv_usec = 200 * 1000;
599  try++;
600  ret = select(client->fd, &select_set, NULL, NULL, &tv);
601  /* catch select() error */
602  if (ret == -1) {
603  /* Signal was caught: just ignore it */
604  if (errno != EINTR) {
605  SCLogInfo("Unix socket: lost connection with client");
606  UnixCommandClose(this, client->fd);
607  return;
608  }
609  }
610  } while (ret == 0 && try < 3);
611  if (ret > 0) {
612  ret = recv(client->fd, buffer + offset,
613  sizeof(buffer) - offset - 1, 0);
614  }
615  }
616  } while (try < 3 && cmd_over == 0);
617 
618  if (try == 3 && cmd_over == 0) {
619  SCLogInfo("Unix socket: imcomplete client message, closing connection");
620  UnixCommandClose(this, client->fd);
621  return;
622  }
623  }
624  UnixCommandExecute(this, buffer, client);
625 }
626 
627 /**
628  * \brief Select function
629  *
630  * \retval 0 in case of error, 1 in case of success
631  */
632 static int UnixMain(UnixCommand * this)
633 {
634  struct timeval tv;
635  int ret;
636  fd_set select_set;
637  UnixClient *uclient;
638  UnixClient *tclient;
639 
640  /* Wait activity on the socket */
641  FD_ZERO(&select_set);
642  FD_SET(this->socket, &select_set);
643  TAILQ_FOREACH(uclient, &this->clients, next) {
644  FD_SET(uclient->fd, &select_set);
645  }
646 
647  tv.tv_sec = 0;
648  tv.tv_usec = 200 * 1000;
649  ret = select(this->select_max, &select_set, NULL, NULL, &tv);
650 
651  /* catch select() error */
652  if (ret == -1) {
653  /* Signal was caught: just ignore it */
654  if (errno == EINTR) {
655  return 1;
656  }
657  SCLogError(SC_ERR_SOCKET, "Command server: select() fatal error: %s", strerror(errno));
658  return 0;
659  }
660 
662  TAILQ_FOREACH_SAFE(uclient, &this->clients, next, tclient) {
663  UnixCommandClose(this, uclient->fd);
664  }
665  return 1;
666  }
667 
668  /* timeout: continue */
669  if (ret == 0) {
670  return 1;
671  }
672 
673  TAILQ_FOREACH_SAFE(uclient, &this->clients, next, tclient) {
674  if (FD_ISSET(uclient->fd, &select_set)) {
675  UnixCommandRun(this, uclient);
676  }
677  }
678  if (FD_ISSET(this->socket, &select_set)) {
679  if (!UnixCommandAccept(this))
680  return 1;
681  }
682 
683  return 1;
684 }
685 
686 static TmEcode UnixManagerShutdownCommand(json_t *cmd,
687  json_t *server_msg, void *data)
688 {
689  SCEnter();
690  json_object_set_new(server_msg, "message", json_string("Closing Suricata"));
691  EngineStop();
693 }
694 
695 static TmEcode UnixManagerVersionCommand(json_t *cmd,
696  json_t *server_msg, void *data)
697 {
698  SCEnter();
699  json_object_set_new(server_msg, "message", json_string(
700 #ifdef REVISION
701  PROG_VER " (rev " xstr(REVISION) ")"
702 #elif defined RELEASE
703  PROG_VER " RELEASE"
704 #else
705  PROG_VER
706 #endif
707  ));
709 }
710 
711 static TmEcode UnixManagerUptimeCommand(json_t *cmd,
712  json_t *server_msg, void *data)
713 {
714  SCEnter();
715  int uptime;
716  UnixCommand *ucmd = (UnixCommand *)data;
717 
718  uptime = time(NULL) - ucmd->start_timestamp;
719  json_object_set_new(server_msg, "message", json_integer(uptime));
721 }
722 
723 static TmEcode UnixManagerRunningModeCommand(json_t *cmd,
724  json_t *server_msg, void *data)
725 {
726  SCEnter();
727  json_object_set_new(server_msg, "message", json_string(RunmodeGetActive()));
729 }
730 
731 static TmEcode UnixManagerCaptureModeCommand(json_t *cmd,
732  json_t *server_msg, void *data)
733 {
734  SCEnter();
735  json_object_set_new(server_msg, "message", json_string(RunModeGetMainMode()));
737 }
738 
739 static TmEcode UnixManagerReloadRulesWrapper(json_t *cmd, json_t *server_msg, void *data, int do_wait)
740 {
741  SCEnter();
742 
743  if (SuriHasSigFile()) {
744  json_object_set_new(server_msg, "message",
745  json_string("Live rule reload not possible if -s "
746  "or -S option used at runtime."));
748  }
749 
750  int r = DetectEngineReloadStart();
751 
752  if (r == 0 && do_wait) {
753  while (!DetectEngineReloadIsIdle())
754  usleep(100);
755  } else {
756  if (r == -1) {
757  json_object_set_new(server_msg, "message", json_string("Reload already in progress"));
759  }
760  }
761 
762  json_object_set_new(server_msg, "message", json_string("done"));
764 }
765 
766 static TmEcode UnixManagerReloadRules(json_t *cmd, json_t *server_msg, void *data)
767 {
768  return UnixManagerReloadRulesWrapper(cmd, server_msg, data, 1);
769 }
770 
771 static TmEcode UnixManagerNonBlockingReloadRules(json_t *cmd, json_t *server_msg, void *data)
772 {
773  return UnixManagerReloadRulesWrapper(cmd, server_msg, data, 0);
774 }
775 
776 static TmEcode UnixManagerReloadTimeCommand(json_t *cmd,
777  json_t *server_msg, void *data)
778 {
779  SCEnter();
780  TmEcode retval;
781  json_t *jdata = NULL;
782 
783  retval = OutputEngineStatsReloadTime(&jdata);
784  json_object_set_new(server_msg, "message", jdata);
785  SCReturnInt(retval);
786 }
787 
788 static TmEcode UnixManagerRulesetStatsCommand(json_t *cmd,
789  json_t *server_msg, void *data)
790 {
791  SCEnter();
792  TmEcode retval;
793  json_t *jdata = NULL;
794 
795  retval = OutputEngineStatsRuleset(&jdata);
796  json_object_set_new(server_msg, "message", jdata);
797  SCReturnInt(retval);
798 }
799 
800 static TmEcode UnixManagerShowFailedRules(json_t *cmd,
801  json_t *server_msg, void *data)
802 {
803  SCEnter();
804  int rules_cnt = 0;
806  if (de_ctx == NULL) {
807  json_object_set_new(server_msg, "message", json_string("Unable to get info"));
809  }
810 
811  /* Since we need to deference de_ctx, we don't want to lost it. */
812  DetectEngineCtx *list = de_ctx;
813  json_t *js_sigs_array = json_array();
814 
815  if (js_sigs_array == NULL) {
816  json_object_set_new(server_msg, "message", json_string("Unable to get info"));
817  goto error;
818  }
819  while (list) {
820  SigString *sigs_str = NULL;
821  TAILQ_FOREACH(sigs_str, &list->sig_stat.failed_sigs, next) {
822  json_t *jdata = json_object();
823  if (jdata == NULL) {
824  json_object_set_new(server_msg, "message", json_string("Unable to get the sig"));
825  goto error;
826  }
827 
828  json_object_set_new(jdata, "tenant_id", json_integer(list->tenant_id));
829  json_object_set_new(jdata, "rule", json_string(sigs_str->sig_str));
830  json_object_set_new(jdata, "filename", json_string(sigs_str->filename));
831  json_object_set_new(jdata, "line", json_integer(sigs_str->line));
832  if (sigs_str->sig_error) {
833  json_object_set_new(jdata, "error", json_string(sigs_str->sig_error));
834  }
835  json_array_append_new(js_sigs_array, jdata);
836  if (++rules_cnt > MAX_FAILED_RULES) {
837  break;
838  }
839  }
840  if (rules_cnt > MAX_FAILED_RULES) {
841  break;
842  }
843  list = list->next;
844  }
845 
846  json_object_set_new(server_msg, "message", js_sigs_array);
847  DetectEngineDeReference(&de_ctx);
849 
850 error:
851  DetectEngineDeReference(&de_ctx);
852  json_object_clear(js_sigs_array);
853  json_decref(js_sigs_array);
855 }
856 
857 static TmEcode UnixManagerConfGetCommand(json_t *cmd,
858  json_t *server_msg, void *data)
859 {
860  SCEnter();
861 
862  const char *confval = NULL;
863  char *variable = NULL;
864 
865  json_t *jarg = json_object_get(cmd, "variable");
866  if(!json_is_string(jarg)) {
867  SCLogInfo("error: variable is not a string");
868  json_object_set_new(server_msg, "message", json_string("variable is not a string"));
870  }
871 
872  variable = (char *)json_string_value(jarg);
873  if (ConfGet(variable, &confval) != 1) {
874  json_object_set_new(server_msg, "message", json_string("Unable to get value"));
876  }
877 
878  if (confval) {
879  json_object_set_new(server_msg, "message", json_string(confval));
881  }
882 
883  json_object_set_new(server_msg, "message", json_string("No string value"));
885 }
886 
887 static TmEcode UnixManagerListCommand(json_t *cmd,
888  json_t *answer, void *data)
889 {
890  SCEnter();
891  json_t *jdata;
892  json_t *jarray;
893  Command *lcmd = NULL;
894  UnixCommand *gcmd = (UnixCommand *) data;
895  int i = 0;
896 
897  jdata = json_object();
898  if (jdata == NULL) {
899  json_object_set_new(answer, "message",
900  json_string("internal error at json object creation"));
901  return TM_ECODE_FAILED;
902  }
903  jarray = json_array();
904  if (jarray == NULL) {
905  json_object_set_new(answer, "message",
906  json_string("internal error at json object creation"));
907  return TM_ECODE_FAILED;
908  }
909 
910  TAILQ_FOREACH(lcmd, &gcmd->commands, next) {
911  json_array_append_new(jarray, json_string(lcmd->name));
912  i++;
913  }
914 
915  json_object_set_new(jdata, "count", json_integer(i));
916  json_object_set_new(jdata, "commands", jarray);
917  json_object_set_new(answer, "message", jdata);
919 }
920 
921 static TmEcode UnixManagerReopenLogFiles(json_t *cmd, json_t *server_msg, void *data)
922 {
924  json_object_set_new(server_msg, "message", json_string("done"));
926 }
927 
928 #if 0
929 TmEcode UnixManagerReloadRules(json_t *cmd,
930  json_t *server_msg, void *data)
931 {
932  SCEnter();
933  if (suricata_ctl_flags != 0) {
934  json_object_set_new(server_msg, "message",
935  json_string("Live rule swap no longer possible."
936  " Engine in shutdown mode."));
938  } else {
939  /* FIXME : need to check option value */
940  UtilSignalHandlerSetup(SIGUSR2, SignalHandlerSigusr2Idle);
941  DetectEngineSpawnLiveRuleSwapMgmtThread();
942  json_object_set_new(server_msg, "message", json_string("Reloading rules"));
943  }
945 }
946 #endif
947 
948 static UnixCommand command;
949 
950 /**
951  * \brief Add a command to the list of commands
952  *
953  * This function adds a command to the list of commands available
954  * through the unix socket.
955  *
956  * When a command is received from user through the unix socket, the content
957  * of 'Command' field in the JSON message is match against keyword, then the
958  * Func is called. See UnixSocketAddPcapFile() for an example.
959  *
960  * \param keyword name of the command
961  * \param Func function to run when command is received
962  * \param data a pointer to data that are passed to Func when it is run
963  * \param flags a flag now used to tune the command type
964  * \retval TM_ECODE_OK in case of success, TM_ECODE_FAILED in case of failure
965  */
966 TmEcode UnixManagerRegisterCommand(const char * keyword,
967  TmEcode (*Func)(json_t *, json_t *, void *),
968  void *data, int flags)
969 {
970  SCEnter();
971  Command *cmd = NULL;
972  Command *lcmd = NULL;
973 
974  if (Func == NULL) {
975  SCLogError(SC_ERR_INVALID_ARGUMENT, "Null function");
977  }
978 
979  if (keyword == NULL) {
980  SCLogError(SC_ERR_INVALID_ARGUMENT, "Null keyword");
982  }
983 
984  TAILQ_FOREACH(lcmd, &command.commands, next) {
985  if (!strcmp(keyword, lcmd->name)) {
986  SCLogError(SC_ERR_INVALID_ARGUMENT, "%s already registered", keyword);
988  }
989  }
990 
991  cmd = SCMalloc(sizeof(Command));
992  if (unlikely(cmd == NULL)) {
993  SCLogError(SC_ERR_MEM_ALLOC, "Can't alloc cmd");
995  }
996  cmd->name = SCStrdup(keyword);
997  if (unlikely(cmd->name == NULL)) {
998  SCLogError(SC_ERR_MEM_ALLOC, "Can't alloc cmd name");
999  SCFree(cmd);
1001  }
1002  cmd->Func = Func;
1003  cmd->data = data;
1004  cmd->flags = flags;
1005  /* Add it to the list */
1006  TAILQ_INSERT_TAIL(&command.commands, cmd, next);
1007 
1009 }
1010 
1011 /**
1012  * \brief Add a task to the list of tasks
1013  *
1014  * This function adds a task to run in the background. The task is run
1015  * each time the UnixMain() function exits from select.
1016  *
1017  * \param Func function to run when a command is received
1018  * \param data a pointer to data that are passed to Func when it is run
1019  * \retval TM_ECODE_OK in case of success, TM_ECODE_FAILED in case of failure
1020  */
1021 TmEcode UnixManagerRegisterBackgroundTask(TmEcode (*Func)(void *),
1022  void *data)
1023 {
1024  SCEnter();
1025  Task *task = NULL;
1026 
1027  if (Func == NULL) {
1028  SCLogError(SC_ERR_INVALID_ARGUMENT, "Null function");
1030  }
1031 
1032  task = SCMalloc(sizeof(Task));
1033  if (unlikely(task == NULL)) {
1034  SCLogError(SC_ERR_MEM_ALLOC, "Can't alloc task");
1036  }
1037  task->Func = Func;
1038  task->data = data;
1039  /* Add it to the list */
1040  TAILQ_INSERT_TAIL(&command.tasks, task, next);
1041 
1043 }
1044 
1045 int UnixManagerInit(void)
1046 {
1047  if (UnixNew(&command) == 0) {
1048  int failure_fatal = 0;
1049  if (ConfGetBool("engine.init-failure-fatal", &failure_fatal) != 1) {
1050  SCLogDebug("ConfGetBool could not load the value.");
1051  }
1052  if (failure_fatal) {
1054  "Unable to create unix command socket");
1055  exit(EXIT_FAILURE);
1056  } else {
1058  "Unable to create unix command socket");
1059  return -1;
1060  }
1061  }
1062 
1063  /* Init Unix socket */
1064  UnixManagerRegisterCommand("shutdown", UnixManagerShutdownCommand, NULL, 0);
1065  UnixManagerRegisterCommand("command-list", UnixManagerListCommand, &command, 0);
1066  UnixManagerRegisterCommand("help", UnixManagerListCommand, &command, 0);
1067  UnixManagerRegisterCommand("version", UnixManagerVersionCommand, &command, 0);
1068  UnixManagerRegisterCommand("uptime", UnixManagerUptimeCommand, &command, 0);
1069  UnixManagerRegisterCommand("running-mode", UnixManagerRunningModeCommand, &command, 0);
1070  UnixManagerRegisterCommand("capture-mode", UnixManagerCaptureModeCommand, &command, 0);
1071  UnixManagerRegisterCommand("conf-get", UnixManagerConfGetCommand, &command, UNIX_CMD_TAKE_ARGS);
1072  UnixManagerRegisterCommand("dump-counters", StatsOutputCounterSocket, NULL, 0);
1073  UnixManagerRegisterCommand("reload-rules", UnixManagerReloadRules, NULL, 0);
1074  UnixManagerRegisterCommand("ruleset-reload-rules", UnixManagerReloadRules, NULL, 0);
1075  UnixManagerRegisterCommand("ruleset-reload-nonblocking", UnixManagerNonBlockingReloadRules, NULL, 0);
1076  UnixManagerRegisterCommand("ruleset-reload-time", UnixManagerReloadTimeCommand, NULL, 0);
1077  UnixManagerRegisterCommand("ruleset-stats", UnixManagerRulesetStatsCommand, NULL, 0);
1078  UnixManagerRegisterCommand("ruleset-failed-rules", UnixManagerShowFailedRules, NULL, 0);
1079  UnixManagerRegisterCommand("register-tenant-handler", UnixSocketRegisterTenantHandler, &command, UNIX_CMD_TAKE_ARGS);
1080  UnixManagerRegisterCommand("unregister-tenant-handler", UnixSocketUnregisterTenantHandler, &command, UNIX_CMD_TAKE_ARGS);
1081  UnixManagerRegisterCommand("register-tenant", UnixSocketRegisterTenant, &command, UNIX_CMD_TAKE_ARGS);
1082  UnixManagerRegisterCommand("reload-tenant", UnixSocketReloadTenant, &command, UNIX_CMD_TAKE_ARGS);
1083  UnixManagerRegisterCommand("unregister-tenant", UnixSocketUnregisterTenant, &command, UNIX_CMD_TAKE_ARGS);
1084  UnixManagerRegisterCommand("add-hostbit", UnixSocketHostbitAdd, &command, UNIX_CMD_TAKE_ARGS);
1085  UnixManagerRegisterCommand("remove-hostbit", UnixSocketHostbitRemove, &command, UNIX_CMD_TAKE_ARGS);
1086  UnixManagerRegisterCommand("list-hostbit", UnixSocketHostbitList, &command, UNIX_CMD_TAKE_ARGS);
1087  UnixManagerRegisterCommand("reopen-log-files", UnixManagerReopenLogFiles, NULL, 0);
1088  UnixManagerRegisterCommand("memcap-set", UnixSocketSetMemcap, &command, UNIX_CMD_TAKE_ARGS);
1089  UnixManagerRegisterCommand("memcap-show", UnixSocketShowMemcap, &command, UNIX_CMD_TAKE_ARGS);
1090  UnixManagerRegisterCommand("memcap-list", UnixSocketShowAllMemcap, NULL, 0);
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);
1194 #ifdef HAVE_PACKET_EBPF
1195  UnixManagerRegisterCommand("ebpf-bypassed-stats", EBPFGetBypassedStats, NULL, 0);
1196 #endif
1197  }
1198  }
1199 }
1200 
1201 /**
1202  * \brief Used to kill unix manager thread(s).
1203  *
1204  * \todo Kinda hackish since it uses the tv name to identify unix manager
1205  * thread. We need an all weather identification scheme.
1206  */
1207 void UnixSocketKillSocketThread(void)
1208 {
1209  ThreadVars *tv = NULL;
1210 
1211 again:
1213 
1214  /* unix manager thread(s) is/are a part of command threads */
1215  tv = tv_root[TVT_CMD];
1216 
1217  while (tv != NULL) {
1218  if (strcasecmp(tv->name, "UnixManagerThread") == 0) {
1219  /* If the thread dies during init it will have
1220  * THV_RUNNING_DONE set, so we can set the correct flag
1221  * and exit.
1222  */
1227  break;
1228  }
1231  /* Be sure it has shut down */
1232  if (!TmThreadsCheckFlag(tv, THV_CLOSED)) {
1234  usleep(100);
1235  goto again;
1236  }
1237  }
1238  tv = tv->next;
1239  }
1240 
1242  return;
1243 }
1244 
1245 #else /* BUILD_UNIX_SOCKET */
1246 
1248 {
1249  SCLogError(SC_ERR_UNIMPLEMENTED, "Unix socket is not compiled");
1250  return;
1251 }
1252 
1254 {
1255  return;
1256 }
1257 
1259 {
1260  return;
1261 }
1262 
1263 #endif /* BUILD_UNIX_SOCKET */
1264 
1266 {
1267 #if defined(BUILD_UNIX_SOCKET) && defined(HAVE_SYS_UN_H) && defined(HAVE_SYS_STAT_H) && defined(HAVE_SYS_TYPES_H)
1268  tmm_modules[TMM_UNIXMANAGER].name = "UnixManager";
1269  tmm_modules[TMM_UNIXMANAGER].ThreadInit = UnixManagerThreadInit;
1270  tmm_modules[TMM_UNIXMANAGER].ThreadDeinit = UnixManagerThreadDeinit;
1271  tmm_modules[TMM_UNIXMANAGER].Management = UnixManager;
1274 #endif /* BUILD_UNIX_SOCKET */
1275 }
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:96
volatile uint8_t suricata_ctl_flags
Definition: suricata.c:199
#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:1328
#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:189
main detection engine ctx
Definition: detect.h:723
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:197
SCCtrlMutex unix_manager_ctrl_mutex
Definition: unix-manager.h:34
#define UNIX_CMD_TAKE_ARGS
Definition: unix-manager.h:31
#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:683
struct DetectEngineCtx_ * next
Definition: detect.h:859
#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:904
int DetectEngineReloadIsIdle(void)
uint32_t padding
Definition: decode-erspan.h:49
SCCtrlCondT unix_manager_ctrl_cond
Definition: unix-manager.h:33
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)
#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
const char * name
Definition: tm-modules.h:44
#define SCMalloc(a)
Definition: util-mem.h:166
char * sig_error
Definition: detect.h:685
void TmModuleUnixManagerRegister(void)
#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:228
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:201
#define MEMBUFFER_OFFSET(mem_buffer)
Get the MemBuffers current offset.
Definition: util-buffer.h:55
int line
Definition: detect.h:686
TmEcode(* ThreadInit)(ThreadVars *, const void *, void **)
Definition: tm-modules.h:47
int StatsSetupPrivate(ThreadVars *tv)
Definition: counters.c:1201
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:133
#define SCStrdup(a)
Definition: util-mem.h:212
int DetectEngineReloadStart(void)
char name[16]
Definition: threadvars.h:59
char * sig_str
Definition: detect.h:684
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:420
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:1867
#define PROG_VER
Definition: suricata.h:72
int SuriHasSigFile(void)
Definition: suricata.c:234
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:905