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