suricata
runmode-unix-socket.c
Go to the documentation of this file.
1 /* Copyright (C) 2012 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 #include "suricata-common.h"
19 #include "tm-threads.h"
20 #include "conf.h"
21 #include "runmodes.h"
22 #include "runmode-pcap-file.h"
23 #include "output.h"
24 #include "output-json.h"
25 
26 #include "util-debug.h"
27 #include "util-time.h"
28 #include "util-cpu.h"
29 #include "util-affinity.h"
30 #include "unix-manager.h"
31 
32 #include "detect-engine.h"
33 
34 #include "flow-manager.h"
35 #include "flow-timeout.h"
36 #include "stream-tcp.h"
37 #include "stream-tcp-reassemble.h"
39 #include "host.h"
40 #include "defrag.h"
41 #include "defrag-hash.h"
42 #include "ippair.h"
43 #include "app-layer.h"
44 #include "app-layer-htp-mem.h"
45 #include "host-bit.h"
46 
47 #include "util-misc.h"
48 #include "util-profiling.h"
49 
50 #include "conf-yaml-loader.h"
51 
53 
54 typedef struct PcapFiles_ {
55  char *filename;
56  char *output_dir;
57  int tenant_id;
58  time_t delay;
59  time_t poll_interval;
60  bool continuous;
63 } PcapFiles;
64 
65 typedef struct PcapCommand_ {
66  TAILQ_HEAD(, PcapFiles_) files;
67  int running;
68  PcapFiles *current_file;
69 } PcapCommand;
70 
71 typedef struct MemcapCommand_ {
72  const char *name;
73  int (*SetFunc)(uint64_t);
74  uint64_t (*GetFunc)(void);
75  uint64_t (*GetMemuseFunc)(void);
77 
79 {
80  return "autofp";
81 }
82 
83 #ifdef BUILD_UNIX_SOCKET
84 
85 #define MEMCAPS_MAX 7
86 static MemcapCommand memcaps[MEMCAPS_MAX] = {
87  {
88  "stream",
92  },
93  {
94  "stream-reassembly",
98  },
99  {
100  "flow",
104  },
105  {
106  "applayer-proto-http",
107  HTPSetMemcap,
108  HTPGetMemcap,
110  },
111  {
112  "defrag",
116  },
117  {
118  "ippair",
122  },
123  {
124  "host",
128  },
129 };
130 
131 static int RunModeUnixSocketMaster(void);
132 static int unix_manager_pcap_task_running = 0;
133 static int unix_manager_pcap_task_failed = 0;
134 static int unix_manager_pcap_task_interrupted = 0;
135 static struct timespec unix_manager_pcap_last_processed;
136 static SCCtrlMutex unix_manager_pcap_last_processed_mutex;
137 
138 /**
139  * \brief return list of files in the queue
140  *
141  * \retval 0 in case of error, 1 in case of success
142  */
143 static TmEcode UnixSocketPcapFilesList(json_t *cmd, json_t* answer, void *data)
144 {
145  PcapCommand *this = (PcapCommand *) data;
146  int i = 0;
147  PcapFiles *file;
148  json_t *jdata;
149  json_t *jarray;
150 
151  jdata = json_object();
152  if (jdata == NULL) {
153  json_object_set_new(answer, "message",
154  json_string("internal error at json object creation"));
155  return TM_ECODE_FAILED;
156  }
157  jarray = json_array();
158  if (jarray == NULL) {
159  json_decref(jdata);
160  json_object_set_new(answer, "message",
161  json_string("internal error at json object creation"));
162  return TM_ECODE_FAILED;
163  }
164  TAILQ_FOREACH(file, &this->files, next) {
165  json_array_append_new(jarray, SCJsonString(file->filename));
166  i++;
167  }
168  json_object_set_new(jdata, "count", json_integer(i));
169  json_object_set_new(jdata, "files", jarray);
170  json_object_set_new(answer, "message", jdata);
171  return TM_ECODE_OK;
172 }
173 
174 static TmEcode UnixSocketPcapFilesNumber(json_t *cmd, json_t* answer, void *data)
175 {
176  PcapCommand *this = (PcapCommand *) data;
177  int i = 0;
178  PcapFiles *file;
179 
180  TAILQ_FOREACH(file, &this->files, next) {
181  i++;
182  }
183  json_object_set_new(answer, "message", json_integer(i));
184  return TM_ECODE_OK;
185 }
186 
187 static TmEcode UnixSocketPcapCurrent(json_t *cmd, json_t* answer, void *data)
188 {
189  PcapCommand *this = (PcapCommand *) data;
190 
191  if (this->current_file != NULL && this->current_file->filename != NULL) {
192  json_object_set_new(answer, "message",
193  json_string(this->current_file->filename));
194  } else {
195  json_object_set_new(answer, "message", json_string("None"));
196  }
197  return TM_ECODE_OK;
198 }
199 
200 static TmEcode UnixSocketPcapLastProcessed(json_t *cmd, json_t *answer, void *data)
201 {
202  json_int_t epoch_millis;
203  SCCtrlMutexLock(&unix_manager_pcap_last_processed_mutex);
204  epoch_millis = SCTimespecAsEpochMillis(&unix_manager_pcap_last_processed);
205  SCCtrlMutexUnlock(&unix_manager_pcap_last_processed_mutex);
206 
207  json_object_set_new(answer, "message",
208  json_integer(epoch_millis));
209 
210  return TM_ECODE_OK;
211 }
212 
213 static TmEcode UnixSocketPcapInterrupt(json_t *cmd, json_t *answer, void *data)
214 {
215  unix_manager_pcap_task_interrupted = 1;
216 
217  json_object_set_new(answer, "message", json_string("Interrupted"));
218 
219  return TM_ECODE_OK;
220 }
221 
222 static void PcapFilesFree(PcapFiles *cfile)
223 {
224  if (cfile == NULL)
225  return;
226  if (cfile->filename)
227  SCFree(cfile->filename);
228  if (cfile->output_dir)
229  SCFree(cfile->output_dir);
230  SCFree(cfile);
231 }
232 
233 /**
234  * \brief Add file to file queue
235  *
236  * \param this a UnixCommand:: structure
237  * \param filename absolute filename
238  * \param output_dir absolute name of directory where log will be put
239  * \param tenant_id Id of tenant associated with this file
240  * \param continuous If file should be run in continuous mode
241  * \param delete If file should be deleted when done
242  * \param delay Delay required for file modified time before being processed
243  * \param poll_interval How frequently directory mode polls for new files
244  *
245  * \retval 0 in case of error, 1 in case of success
246  */
247 static TmEcode UnixListAddFile(
248  PcapCommand *this,
249  const char *filename,
250  const char *output_dir,
251  int tenant_id,
252  bool continuous,
253  bool should_delete,
254  time_t delay,
255  time_t poll_interval
256 )
257 {
258  PcapFiles *cfile = NULL;
259  if (filename == NULL || this == NULL)
260  return TM_ECODE_FAILED;
261  cfile = SCMalloc(sizeof(PcapFiles));
262  if (unlikely(cfile == NULL)) {
263  SCLogError(SC_ERR_MEM_ALLOC, "Unable to allocate new file");
264  return TM_ECODE_FAILED;
265  }
266  memset(cfile, 0, sizeof(PcapFiles));
267 
268  cfile->filename = SCStrdup(filename);
269  if (unlikely(cfile->filename == NULL)) {
270  SCFree(cfile);
271  SCLogError(SC_ERR_MEM_ALLOC, "Unable to dup filename");
272  return TM_ECODE_FAILED;
273  }
274 
275  if (output_dir) {
276  cfile->output_dir = SCStrdup(output_dir);
277  if (unlikely(cfile->output_dir == NULL)) {
278  SCFree(cfile->filename);
279  SCFree(cfile);
280  SCLogError(SC_ERR_MEM_ALLOC, "Unable to dup output_dir");
281  return TM_ECODE_FAILED;
282  }
283  }
284 
285  cfile->tenant_id = tenant_id;
286  cfile->continuous = continuous;
287  cfile->should_delete = should_delete;
288  cfile->delay = delay;
289  cfile->poll_interval = poll_interval;
290 
291  TAILQ_INSERT_TAIL(&this->files, cfile, next);
292  return TM_ECODE_OK;
293 }
294 
295 /**
296  * \brief Command to add a file to treatment list
297  *
298  * \param cmd the content of command Arguments as a json_t object
299  * \param answer the json_t object that has to be used to answer
300  * \param data pointer to data defining the context here a PcapCommand::
301  * \param continuous If this should run in continuous mode
302  */
303 static TmEcode UnixSocketAddPcapFileImpl(json_t *cmd, json_t* answer, void *data,
304  bool continuous)
305 {
306  PcapCommand *this = (PcapCommand *) data;
307  const char *filename;
308  const char *output_dir;
309  int tenant_id = 0;
310  bool should_delete = false;
311  time_t delay = 30;
312  time_t poll_interval = 5;
313 #ifdef OS_WIN32
314  struct _stat st;
315 #else
316  struct stat st;
317 #endif /* OS_WIN32 */
318 
319  json_t *jarg = json_object_get(cmd, "filename");
320  if (!json_is_string(jarg)) {
321  SCLogError(SC_ERR_INVALID_ARGUMENT, "filename is not a string");
322  json_object_set_new(answer, "message",
323  json_string("filename is not a string"));
324  return TM_ECODE_FAILED;
325  }
326  filename = json_string_value(jarg);
327 #ifdef OS_WIN32
328  if (_stat(filename, &st) != 0) {
329 #else
330  if (stat(filename, &st) != 0) {
331 #endif /* OS_WIN32 */
332  json_object_set_new(answer, "message",
333  json_string("filename does not exist"));
334  return TM_ECODE_FAILED;
335  }
336 
337  json_t *oarg = json_object_get(cmd, "output-dir");
338  if (oarg != NULL) {
339  if (!json_is_string(oarg)) {
340  SCLogError(SC_ERR_INVALID_ARGUMENT, "output-dir is not a string");
341 
342  json_object_set_new(answer, "message",
343  json_string("output-dir is not a string"));
344  return TM_ECODE_FAILED;
345  }
346  output_dir = json_string_value(oarg);
347  } else {
348  SCLogError(SC_ERR_INVALID_ARGUMENT, "can't get output-dir");
349 
350  json_object_set_new(answer, "message",
351  json_string("output-dir param is mandatory"));
352  return TM_ECODE_FAILED;
353  }
354 
355 #ifdef OS_WIN32
356  if (_stat(output_dir, &st) != 0) {
357 #else
358  if (stat(output_dir, &st) != 0) {
359 #endif /* OS_WIN32 */
360  json_object_set_new(answer, "message",
361  json_string("output-dir does not exist"));
362  return TM_ECODE_FAILED;
363  }
364 
365  json_t *targ = json_object_get(cmd, "tenant");
366  if (targ != NULL) {
367  if (!json_is_integer(targ)) {
368  json_object_set_new(answer, "message",
369  json_string("tenant is not a number"));
370  return TM_ECODE_FAILED;
371  }
372  tenant_id = json_number_value(targ);
373  }
374 
375  json_t *delete_arg = json_object_get(cmd, "delete-when-done");
376  if (delete_arg != NULL) {
377  should_delete = json_is_true(delete_arg);
378  }
379 
380  json_t *delay_arg = json_object_get(cmd, "delay");
381  if (delay_arg != NULL) {
382  if (!json_is_integer(delay_arg)) {
383  SCLogError(SC_ERR_INVALID_ARGUMENT, "delay is not a integer");
384  json_object_set_new(answer, "message",
385  json_string("delay is not a integer"));
386  return TM_ECODE_FAILED;
387  }
388  delay = json_integer_value(delay_arg);
389  }
390 
391  json_t *interval_arg = json_object_get(cmd, "poll-interval");
392  if (interval_arg != NULL) {
393  if (!json_is_integer(interval_arg)) {
394  SCLogError(SC_ERR_INVALID_ARGUMENT, "poll-interval is not a integer");
395 
396  json_object_set_new(answer, "message",
397  json_string("poll-interval is not a integer"));
398  return TM_ECODE_FAILED;
399  }
400  poll_interval = json_integer_value(interval_arg);
401  }
402 
403  switch (UnixListAddFile(this, filename, output_dir, tenant_id, continuous,
404  should_delete, delay, poll_interval)) {
405  case TM_ECODE_FAILED:
406  case TM_ECODE_DONE:
407  json_object_set_new(answer, "message",
408  json_string("Unable to add file to list"));
409  return TM_ECODE_FAILED;
410  case TM_ECODE_OK:
411  SCLogInfo("Added file '%s' to list", filename);
412  json_object_set_new(answer, "message",
413  json_string("Successfully added file to list"));
414  return TM_ECODE_OK;
415  }
416  return TM_ECODE_OK;
417 }
418 
419 /**
420  * \brief Command to add a file to treatment list
421  *
422  * \param cmd the content of command Arguments as a json_t object
423  * \param answer the json_t object that has to be used to answer
424  * \param data pointer to data defining the context here a PcapCommand::
425  */
426 static TmEcode UnixSocketAddPcapFile(json_t *cmd, json_t* answer, void *data)
427 {
428  bool continuous = false;
429 
430  json_t *cont_arg = json_object_get(cmd, "continuous");
431  if (cont_arg != NULL) {
432  continuous = json_is_true(cont_arg);
433  }
434 
435  return UnixSocketAddPcapFileImpl(cmd, answer, data, continuous);
436 }
437 
438 /**
439  * \brief Command to add a file to treatment list, forcing continuous mode
440  *
441  * \param cmd the content of command Arguments as a json_t object
442  * \param answer the json_t object that has to be used to answer
443  * \param data pointer to data defining the context here a PcapCommand::
444  */
445 static TmEcode UnixSocketAddPcapFileContinuous(json_t *cmd, json_t* answer, void *data)
446 {
447  return UnixSocketAddPcapFileImpl(cmd, answer, data, true);
448 }
449 
450 /**
451  * \brief Handle the file queue
452  *
453  * This function check if there is currently a file
454  * being parse. If it is not the case, it will start to
455  * work on a new file. This implies to start a new 'pcap-file'
456  * running mode after having set the file and the output dir.
457  * This function also handles the cleaning of the previous
458  * running mode.
459  *
460  * \param this a UnixCommand:: structure
461  * \retval 0 in case of error, 1 in case of success
462  */
463 static TmEcode UnixSocketPcapFilesCheck(void *data)
464 {
465  PcapCommand *this = (PcapCommand *) data;
466  if (unix_manager_pcap_task_running == 1) {
467  return TM_ECODE_OK;
468  }
469  if ((unix_manager_pcap_task_failed == 1) || (this->running == 1)) {
470  if (unix_manager_pcap_task_failed) {
471  SCLogInfo("Preceeding task failed, cleaning the running mode");
472  }
473  unix_manager_pcap_task_failed = 0;
474  this->running = 0;
475 
476  SCLogInfo("Resetting engine state");
477  PostRunDeinit(RUNMODE_PCAP_FILE, NULL /* no ts */);
478 
479  if (this->current_file) {
480  PcapFilesFree(this->current_file);
481  }
482  this->current_file = NULL;
483  }
484 
485  if (TAILQ_EMPTY(&this->files)) {
486  // nothing to do
487  return TM_ECODE_OK;
488  }
489 
490  PcapFiles *cfile = TAILQ_FIRST(&this->files);
491  TAILQ_REMOVE(&this->files, cfile, next);
492 
493  unix_manager_pcap_task_running = 1;
494  this->running = 1;
495 
496  if (ConfSetFinal("pcap-file.file", cfile->filename) != 1) {
497  SCLogError(SC_ERR_INVALID_ARGUMENT, "Can not set working file to '%s'",
498  cfile->filename);
499  PcapFilesFree(cfile);
500  return TM_ECODE_FAILED;
501  }
502 
503  int set_res = 0;
504  if (cfile->continuous) {
505  set_res = ConfSetFinal("pcap-file.continuous", "true");
506  } else {
507  set_res = ConfSetFinal("pcap-file.continuous", "false");
508  }
509  if (set_res != 1) {
510  SCLogError(SC_ERR_INVALID_ARGUMENT, "Can not set continuous mode for pcap processing");
511  PcapFilesFree(cfile);
512  return TM_ECODE_FAILED;
513  }
514  if (cfile->should_delete) {
515  set_res = ConfSetFinal("pcap-file.delete-when-done", "true");
516  } else {
517  set_res = ConfSetFinal("pcap-file.delete-when-done", "false");
518  }
519  if (set_res != 1) {
520  SCLogError(SC_ERR_INVALID_ARGUMENT, "Can not set delete mode for pcap processing");
521  PcapFilesFree(cfile);
522  return TM_ECODE_FAILED;
523  }
524 
525  if (cfile->delay > 0) {
526  char tstr[32];
527  snprintf(tstr, sizeof(tstr), "%" PRIuMAX, (uintmax_t)cfile->delay);
528  if (ConfSetFinal("pcap-file.delay", tstr) != 1) {
529  SCLogError(SC_ERR_INVALID_ARGUMENT, "Can not set delay to '%s'", tstr);
530  PcapFilesFree(cfile);
531  return TM_ECODE_FAILED;
532  }
533  }
534 
535  if (cfile->poll_interval > 0) {
536  char tstr[32];
537  snprintf(tstr, sizeof(tstr), "%" PRIuMAX, (uintmax_t)cfile->poll_interval);
538  if (ConfSetFinal("pcap-file.poll-interval", tstr) != 1) {
540  "Can not set poll-interval to '%s'", tstr);
541  PcapFilesFree(cfile);
542  return TM_ECODE_FAILED;
543  }
544  }
545 
546  if (cfile->tenant_id > 0) {
547  char tstr[16];
548  snprintf(tstr, sizeof(tstr), "%d", cfile->tenant_id);
549  if (ConfSetFinal("pcap-file.tenant-id", tstr) != 1) {
551  "Can not set working tenant-id to '%s'", tstr);
552  PcapFilesFree(cfile);
553  return TM_ECODE_FAILED;
554  }
555  } else {
556  SCLogInfo("pcap-file.tenant-id not set");
557  }
558 
559  if (cfile->output_dir) {
560  if (ConfSetFinal("default-log-dir", cfile->output_dir) != 1) {
562  "Can not set output dir to '%s'", cfile->output_dir);
563  PcapFilesFree(cfile);
564  return TM_ECODE_FAILED;
565  }
566  }
567 
568  this->current_file = cfile;
569 
570  SCLogInfo("Starting run for '%s'", this->current_file->filename);
571 
575 
576  /* Un-pause all the paused threads */
580 
581  return TM_ECODE_OK;
582 }
583 #endif
584 
586 {
587 #ifdef BUILD_UNIX_SOCKET
588  /* a bit of a hack, but register twice to --list-runmodes shows both */
590  "Unix socket mode",
591  RunModeUnixSocketMaster);
593  "Unix socket mode",
594  RunModeUnixSocketMaster);
595 #endif
596 }
597 
598 TmEcode UnixSocketPcapFile(TmEcode tm, struct timespec *last_processed)
599 {
600 #ifdef BUILD_UNIX_SOCKET
601  if(last_processed) {
602  SCCtrlMutexLock(&unix_manager_pcap_last_processed_mutex);
603  unix_manager_pcap_last_processed.tv_sec = last_processed->tv_sec;
604  unix_manager_pcap_last_processed.tv_nsec = last_processed->tv_nsec;
605  SCCtrlMutexUnlock(&unix_manager_pcap_last_processed_mutex);
606  }
607  switch (tm) {
608  case TM_ECODE_DONE:
609  SCLogInfo("Marking current task as done");
610  unix_manager_pcap_task_running = 0;
611  return TM_ECODE_DONE;
612  case TM_ECODE_FAILED:
613  SCLogInfo("Marking current task as failed");
614  unix_manager_pcap_task_running = 0;
615  unix_manager_pcap_task_failed = 1;
616  //if we return failed, we can't stop the thread and suricata will fail to close
617  return TM_ECODE_FAILED;
618  case TM_ECODE_OK:
619  if (unix_manager_pcap_task_interrupted == 1) {
620  SCLogInfo("Interrupting current run mode");
621  unix_manager_pcap_task_interrupted = 0;
622  return TM_ECODE_DONE;
623  } else {
624  return TM_ECODE_OK;
625  }
626  }
627 #endif
628  return TM_ECODE_FAILED;
629 }
630 
631 #ifdef BUILD_UNIX_SOCKET
632 /**
633  * \brief Command to add a tenant handler
634  *
635  * \param cmd the content of command Arguments as a json_t object
636  * \param answer the json_t object that has to be used to answer
637  * \param data pointer to data defining the context here a PcapCommand::
638  */
639 TmEcode UnixSocketRegisterTenantHandler(json_t *cmd, json_t* answer, void *data)
640 {
641  const char *htype;
642  json_int_t traffic_id = -1;
643 
645  SCLogInfo("error: multi-tenant support not enabled");
646  json_object_set_new(answer, "message", json_string("multi-tenant support not enabled"));
647  return TM_ECODE_FAILED;
648  }
649 
650  /* 1 get tenant id */
651  json_t *jarg = json_object_get(cmd, "id");
652  if (!json_is_integer(jarg)) {
653  SCLogInfo("error: command is not a string");
654  json_object_set_new(answer, "message", json_string("id is not an integer"));
655  return TM_ECODE_FAILED;
656  }
657  int tenant_id = json_integer_value(jarg);
658 
659  /* 2 get tenant handler type */
660  jarg = json_object_get(cmd, "htype");
661  if (!json_is_string(jarg)) {
662  SCLogInfo("error: command is not a string");
663  json_object_set_new(answer, "message", json_string("command is not a string"));
664  return TM_ECODE_FAILED;
665  }
666  htype = json_string_value(jarg);
667 
668  SCLogDebug("add-tenant-handler: %d %s", tenant_id, htype);
669 
670  /* 3 get optional hargs */
671  json_t *hargs = json_object_get(cmd, "hargs");
672  if (hargs != NULL) {
673  if (!json_is_integer(hargs)) {
674  SCLogInfo("error: hargs not a number");
675  json_object_set_new(answer, "message", json_string("hargs not a number"));
676  return TM_ECODE_FAILED;
677  }
678  traffic_id = json_integer_value(hargs);
679  }
680 
681  /* 4 add to system */
682  int r = -1;
683  if (strcmp(htype, "pcap") == 0) {
685  } else if (strcmp(htype, "vlan") == 0) {
686  if (traffic_id < 0) {
687  json_object_set_new(answer, "message", json_string("vlan requires argument"));
688  return TM_ECODE_FAILED;
689  }
690  if (traffic_id > USHRT_MAX) {
691  json_object_set_new(answer, "message", json_string("vlan argument out of range"));
692  return TM_ECODE_FAILED;
693  }
694 
695  SCLogInfo("VLAN handler: id %u maps to tenant %u", (uint32_t)traffic_id, tenant_id);
696  r = DetectEngineTentantRegisterVlanId(tenant_id, (uint32_t)traffic_id);
697  }
698  if (r != 0) {
699  json_object_set_new(answer, "message", json_string("handler setup failure"));
700  return TM_ECODE_FAILED;
701  }
702 
703  if (DetectEngineMTApply() < 0) {
704  json_object_set_new(answer, "message", json_string("couldn't apply settings"));
705  // TODO cleanup
706  return TM_ECODE_FAILED;
707  }
708 
709  json_object_set_new(answer, "message", json_string("handler added"));
710  return TM_ECODE_OK;
711 }
712 
713 /**
714  * \brief Command to remove a tenant handler
715  *
716  * \param cmd the content of command Arguments as a json_t object
717  * \param answer the json_t object that has to be used to answer
718  * \param data pointer to data defining the context here a PcapCommand::
719  */
720 TmEcode UnixSocketUnregisterTenantHandler(json_t *cmd, json_t* answer, void *data)
721 {
722  const char *htype;
723  json_int_t traffic_id = -1;
724 
726  SCLogInfo("error: multi-tenant support not enabled");
727  json_object_set_new(answer, "message", json_string("multi-tenant support not enabled"));
728  return TM_ECODE_FAILED;
729  }
730 
731  /* 1 get tenant id */
732  json_t *jarg = json_object_get(cmd, "id");
733  if (!json_is_integer(jarg)) {
734  SCLogInfo("error: command is not a string");
735  json_object_set_new(answer, "message", json_string("id is not an integer"));
736  return TM_ECODE_FAILED;
737  }
738  int tenant_id = json_integer_value(jarg);
739 
740  /* 2 get tenant handler type */
741  jarg = json_object_get(cmd, "htype");
742  if (!json_is_string(jarg)) {
743  SCLogInfo("error: command is not a string");
744  json_object_set_new(answer, "message", json_string("command is not a string"));
745  return TM_ECODE_FAILED;
746  }
747  htype = json_string_value(jarg);
748 
749  SCLogDebug("add-tenant-handler: %d %s", tenant_id, htype);
750 
751  /* 3 get optional hargs */
752  json_t *hargs = json_object_get(cmd, "hargs");
753  if (hargs != NULL) {
754  if (!json_is_integer(hargs)) {
755  SCLogInfo("error: hargs not a number");
756  json_object_set_new(answer, "message", json_string("hargs not a number"));
757  return TM_ECODE_FAILED;
758  }
759  traffic_id = json_integer_value(hargs);
760  }
761 
762  /* 4 add to system */
763  int r = -1;
764  if (strcmp(htype, "pcap") == 0) {
766  } else if (strcmp(htype, "vlan") == 0) {
767  if (traffic_id < 0) {
768  json_object_set_new(answer, "message", json_string("vlan requires argument"));
769  return TM_ECODE_FAILED;
770  }
771  if (traffic_id > USHRT_MAX) {
772  json_object_set_new(answer, "message", json_string("vlan argument out of range"));
773  return TM_ECODE_FAILED;
774  }
775 
776  SCLogInfo("VLAN handler: removing mapping of %u to tenant %u", (uint32_t)traffic_id, tenant_id);
777  r = DetectEngineTentantUnregisterVlanId(tenant_id, (uint32_t)traffic_id);
778  }
779  if (r != 0) {
780  json_object_set_new(answer, "message", json_string("handler unregister failure"));
781  return TM_ECODE_FAILED;
782  }
783 
784  /* 5 apply it */
785  if (DetectEngineMTApply() < 0) {
786  json_object_set_new(answer, "message", json_string("couldn't apply settings"));
787  // TODO cleanup
788  return TM_ECODE_FAILED;
789  }
790 
791  json_object_set_new(answer, "message", json_string("handler removed"));
792  return TM_ECODE_OK;
793 }
794 
795 /**
796  * \brief Command to add a tenant
797  *
798  * \param cmd the content of command Arguments as a json_t object
799  * \param answer the json_t object that has to be used to answer
800  * \param data pointer to data defining the context here a PcapCommand::
801  */
802 TmEcode UnixSocketRegisterTenant(json_t *cmd, json_t* answer, void *data)
803 {
804  const char *filename;
805 #ifdef OS_WIN32
806  struct _stat st;
807 #else
808  struct stat st;
809 #endif /* OS_WIN32 */
810 
812  SCLogInfo("error: multi-tenant support not enabled");
813  json_object_set_new(answer, "message", json_string("multi-tenant support not enabled"));
814  return TM_ECODE_FAILED;
815  }
816 
817  /* 1 get tenant id */
818  json_t *jarg = json_object_get(cmd, "id");
819  if (!json_is_integer(jarg)) {
820  json_object_set_new(answer, "message", json_string("id is not an integer"));
821  return TM_ECODE_FAILED;
822  }
823  int tenant_id = json_integer_value(jarg);
824 
825  /* 2 get tenant yaml */
826  jarg = json_object_get(cmd, "filename");
827  if (!json_is_string(jarg)) {
828  json_object_set_new(answer, "message", json_string("command is not a string"));
829  return TM_ECODE_FAILED;
830  }
831  filename = json_string_value(jarg);
832 #ifdef OS_WIN32
833  if (_stat(filename, &st) != 0) {
834 #else
835  if (stat(filename, &st) != 0) {
836 #endif /* OS_WIN32 */
837  json_object_set_new(answer, "message", json_string("file does not exist"));
838  return TM_ECODE_FAILED;
839  }
840 
841  SCLogDebug("add-tenant: %d %s", tenant_id, filename);
842 
843  /* setup the yaml in this loop so that it's not done by the loader
844  * threads. ConfYamlLoadFileWithPrefix is not thread safe. */
845  char prefix[64];
846  snprintf(prefix, sizeof(prefix), "multi-detect.%d", tenant_id);
847  if (ConfYamlLoadFileWithPrefix(filename, prefix) != 0) {
848  SCLogError(SC_ERR_CONF_YAML_ERROR, "failed to load yaml %s", filename);
849  json_object_set_new(answer, "message", json_string("failed to load yaml"));
850  return TM_ECODE_FAILED;
851  }
852 
853  /* 3 load into the system */
854  if (DetectEngineLoadTenantBlocking(tenant_id, filename) != 0) {
855  json_object_set_new(answer, "message", json_string("adding tenant failed"));
856  return TM_ECODE_FAILED;
857  }
858 
859  /* 4 apply to the running system */
860  if (DetectEngineMTApply() < 0) {
861  json_object_set_new(answer, "message", json_string("couldn't apply settings"));
862  // TODO cleanup
863  return TM_ECODE_FAILED;
864  }
865 
866  json_object_set_new(answer, "message", json_string("adding tenant succeeded"));
867  return TM_ECODE_OK;
868 }
869 
870 static int reload_cnt = 1;
871 /**
872  * \brief Command to reload a tenant
873  *
874  * \param cmd the content of command Arguments as a json_t object
875  * \param answer the json_t object that has to be used to answer
876  * \param data pointer to data defining the context here a PcapCommand::
877  */
878 TmEcode UnixSocketReloadTenant(json_t *cmd, json_t* answer, void *data)
879 {
880  const char *filename;
881 #ifdef OS_WIN32
882  struct _stat st;
883 #else
884  struct stat st;
885 #endif /* OS_WIN32 */
886 
888  SCLogInfo("error: multi-tenant support not enabled");
889  json_object_set_new(answer, "message", json_string("multi-tenant support not enabled"));
890  return TM_ECODE_FAILED;
891  }
892 
893  /* 1 get tenant id */
894  json_t *jarg = json_object_get(cmd, "id");
895  if (!json_is_integer(jarg)) {
896  json_object_set_new(answer, "message", json_string("id is not an integer"));
897  return TM_ECODE_FAILED;
898  }
899  int tenant_id = json_integer_value(jarg);
900 
901  /* 2 get tenant yaml */
902  jarg = json_object_get(cmd, "filename");
903  if (!json_is_string(jarg)) {
904  json_object_set_new(answer, "message", json_string("command is not a string"));
905  return TM_ECODE_FAILED;
906  }
907  filename = json_string_value(jarg);
908 #ifdef OS_WIN32
909  if (_stat(filename, &st) != 0) {
910 #else
911  if (stat(filename, &st) != 0) {
912 #endif /* OS_WIN32 */
913  json_object_set_new(answer, "message", json_string("file does not exist"));
914  return TM_ECODE_FAILED;
915  }
916 
917  SCLogDebug("reload-tenant: %d %s", tenant_id, filename);
918 
919  char prefix[64];
920  snprintf(prefix, sizeof(prefix), "multi-detect.%d.reload.%d", tenant_id, reload_cnt);
921  SCLogInfo("prefix %s", prefix);
922 
923  if (ConfYamlLoadFileWithPrefix(filename, prefix) != 0) {
924  json_object_set_new(answer, "message", json_string("failed to load yaml"));
925  return TM_ECODE_FAILED;
926  }
927 
928  /* 3 load into the system */
929  if (DetectEngineReloadTenantBlocking(tenant_id, filename, reload_cnt) != 0) {
930  json_object_set_new(answer, "message", json_string("reload tenant failed"));
931  return TM_ECODE_FAILED;
932  }
933 
934  reload_cnt++;
935 
936  /* apply to the running system */
937  if (DetectEngineMTApply() < 0) {
938  json_object_set_new(answer, "message", json_string("couldn't apply settings"));
939  // TODO cleanup
940  return TM_ECODE_FAILED;
941  }
942 
943  json_object_set_new(answer, "message", json_string("reloading tenant succeeded"));
944  return TM_ECODE_OK;
945 }
946 
947 /**
948  * \brief Command to remove a tenant
949  *
950  * \param cmd the content of command Arguments as a json_t object
951  * \param answer the json_t object that has to be used to answer
952  * \param data pointer to data defining the context here a PcapCommand::
953  */
954 TmEcode UnixSocketUnregisterTenant(json_t *cmd, json_t* answer, void *data)
955 {
957  SCLogInfo("error: multi-tenant support not enabled");
958  json_object_set_new(answer, "message", json_string("multi-tenant support not enabled"));
959  return TM_ECODE_FAILED;
960  }
961 
962  /* 1 get tenant id */
963  json_t *jarg = json_object_get(cmd, "id");
964  if (!json_is_integer(jarg)) {
965  SCLogInfo("error: command is not a string");
966  json_object_set_new(answer, "message", json_string("id is not an integer"));
967  return TM_ECODE_FAILED;
968  }
969  int tenant_id = json_integer_value(jarg);
970 
971  SCLogInfo("remove-tenant: removing tenant %d", tenant_id);
972 
973  /* 2 remove it from the system */
974  char prefix[64];
975  snprintf(prefix, sizeof(prefix), "multi-detect.%d", tenant_id);
976 
977  DetectEngineCtx *de_ctx = DetectEngineGetByTenantId(tenant_id);
978  if (de_ctx == NULL) {
979  json_object_set_new(answer, "message", json_string("tenant detect engine not found"));
980  return TM_ECODE_FAILED;
981  }
982 
983  /* move to free list */
985  DetectEngineDeReference(&de_ctx);
986 
987  /* update the threads */
988  if (DetectEngineMTApply() < 0) {
989  json_object_set_new(answer, "message", json_string("couldn't apply settings"));
990  // TODO cleanup
991  return TM_ECODE_FAILED;
992  }
993 
994  /* walk free list, freeing the removed de_ctx */
996 
997  json_object_set_new(answer, "message", json_string("removing tenant succeeded"));
998  return TM_ECODE_OK;
999 }
1000 
1001 /**
1002  * \brief Command to add a hostbit
1003  *
1004  * \param cmd the content of command Arguments as a json_t object
1005  * \param answer the json_t object that has to be used to answer
1006  */
1007 TmEcode UnixSocketHostbitAdd(json_t *cmd, json_t* answer, void *data_usused)
1008 {
1009  /* 1 get ip address */
1010  json_t *jarg = json_object_get(cmd, "ipaddress");
1011  if (!json_is_string(jarg)) {
1012  json_object_set_new(answer, "message", json_string("ipaddress is not an string"));
1013  return TM_ECODE_FAILED;
1014  }
1015  const char *ipaddress = json_string_value(jarg);
1016 
1017  Address a;
1018  struct in_addr in;
1019  memset(&in, 0, sizeof(in));
1020  if (inet_pton(AF_INET, ipaddress, &in) != 1) {
1021  uint32_t in6[4];
1022  memset(&in6, 0, sizeof(in6));
1023  if (inet_pton(AF_INET6, ipaddress, &in) != 1) {
1024  json_object_set_new(answer, "message", json_string("invalid address string"));
1025  return TM_ECODE_FAILED;
1026  } else {
1027  a.family = AF_INET6;
1028  a.addr_data32[0] = in6[0];
1029  a.addr_data32[1] = in6[1];
1030  a.addr_data32[2] = in6[2];
1031  a.addr_data32[3] = in6[3];
1032  }
1033  } else {
1034  a.family = AF_INET;
1035  a.addr_data32[0] = in.s_addr;
1036  a.addr_data32[1] = 0;
1037  a.addr_data32[2] = 0;
1038  a.addr_data32[3] = 0;
1039  }
1040 
1041  /* 2 get variable name */
1042  jarg = json_object_get(cmd, "hostbit");
1043  if (!json_is_string(jarg)) {
1044  json_object_set_new(answer, "message", json_string("hostbit is not a string"));
1045  return TM_ECODE_FAILED;
1046  }
1047  const char *hostbit = json_string_value(jarg);
1048  uint32_t idx = VarNameStoreLookupByName(hostbit, VAR_TYPE_HOST_BIT);
1049  if (idx == 0) {
1050  json_object_set_new(answer, "message", json_string("hostbit not found"));
1051  return TM_ECODE_FAILED;
1052  }
1053 
1054  /* 3 get expire */
1055  jarg = json_object_get(cmd, "expire");
1056  if (!json_is_integer(jarg)) {
1057  json_object_set_new(answer, "message", json_string("expire is not an integer"));
1058  return TM_ECODE_FAILED;
1059  }
1060  uint32_t expire = json_integer_value(jarg);
1061 
1062  SCLogInfo("add-hostbit: ip %s hostbit %s expire %us", ipaddress, hostbit, expire);
1063 
1064  struct timeval current_time;
1065  TimeGet(&current_time);
1066  Host *host = HostGetHostFromHash(&a);
1067  if (host) {
1068  HostBitSet(host, idx, current_time.tv_sec + expire);
1069  HostUnlock(host);
1070 
1071  json_object_set_new(answer, "message", json_string("hostbit added"));
1072  return TM_ECODE_OK;
1073  } else {
1074  json_object_set_new(answer, "message", json_string("couldn't create host"));
1075  return TM_ECODE_FAILED;
1076  }
1077 }
1078 
1079 /**
1080  * \brief Command to remove a hostbit
1081  *
1082  * \param cmd the content of command Arguments as a json_t object
1083  * \param answer the json_t object that has to be used to answer
1084  */
1085 TmEcode UnixSocketHostbitRemove(json_t *cmd, json_t* answer, void *data_unused)
1086 {
1087  /* 1 get ip address */
1088  json_t *jarg = json_object_get(cmd, "ipaddress");
1089  if (!json_is_string(jarg)) {
1090  json_object_set_new(answer, "message", json_string("ipaddress is not an string"));
1091  return TM_ECODE_FAILED;
1092  }
1093  const char *ipaddress = json_string_value(jarg);
1094 
1095  Address a;
1096  struct in_addr in;
1097  memset(&in, 0, sizeof(in));
1098  if (inet_pton(AF_INET, ipaddress, &in) != 1) {
1099  uint32_t in6[4];
1100  memset(&in6, 0, sizeof(in6));
1101  if (inet_pton(AF_INET6, ipaddress, &in) != 1) {
1102  json_object_set_new(answer, "message", json_string("invalid address string"));
1103  return TM_ECODE_FAILED;
1104  } else {
1105  a.family = AF_INET6;
1106  a.addr_data32[0] = in6[0];
1107  a.addr_data32[1] = in6[1];
1108  a.addr_data32[2] = in6[2];
1109  a.addr_data32[3] = in6[3];
1110  }
1111  } else {
1112  a.family = AF_INET;
1113  a.addr_data32[0] = in.s_addr;
1114  a.addr_data32[1] = 0;
1115  a.addr_data32[2] = 0;
1116  a.addr_data32[3] = 0;
1117  }
1118 
1119  /* 2 get variable name */
1120  jarg = json_object_get(cmd, "hostbit");
1121  if (!json_is_string(jarg)) {
1122  json_object_set_new(answer, "message", json_string("hostbit is not a string"));
1123  return TM_ECODE_FAILED;
1124  }
1125 
1126  const char *hostbit = json_string_value(jarg);
1127  uint32_t idx = VarNameStoreLookupByName(hostbit, VAR_TYPE_HOST_BIT);
1128  if (idx == 0) {
1129  json_object_set_new(answer, "message", json_string("hostbit not found"));
1130  return TM_ECODE_FAILED;
1131  }
1132 
1133  SCLogInfo("remove-hostbit: %s %s", ipaddress, hostbit);
1134 
1135  Host *host = HostLookupHostFromHash(&a);
1136  if (host) {
1137  HostBitUnset(host, idx);
1138  HostUnlock(host);
1139  json_object_set_new(answer, "message", json_string("hostbit removed"));
1140  return TM_ECODE_OK;
1141  } else {
1142  json_object_set_new(answer, "message", json_string("host not found"));
1143  return TM_ECODE_FAILED;
1144  }
1145 }
1146 
1147 /**
1148  * \brief Command to list hostbits for an ip
1149  *
1150  * \param cmd the content of command Arguments as a json_t object
1151  * \param answer the json_t object that has to be used to answer
1152  *
1153  * Message looks like:
1154  * {"message": {"count": 1, "hostbits": [{"expire": 3222, "name": "firefox-users"}]}, "return": "OK"}
1155  *
1156  * \retval r TM_ECODE_OK or TM_ECODE_FAILED
1157  */
1158 TmEcode UnixSocketHostbitList(json_t *cmd, json_t* answer, void *data_unused)
1159 {
1160  /* 1 get ip address */
1161  json_t *jarg = json_object_get(cmd, "ipaddress");
1162  if (!json_is_string(jarg)) {
1163  json_object_set_new(answer, "message", json_string("ipaddress is not an string"));
1164  return TM_ECODE_FAILED;
1165  }
1166  const char *ipaddress = json_string_value(jarg);
1167 
1168  Address a;
1169  struct in_addr in;
1170  memset(&in, 0, sizeof(in));
1171  if (inet_pton(AF_INET, ipaddress, &in) != 1) {
1172  uint32_t in6[4];
1173  memset(&in6, 0, sizeof(in6));
1174  if (inet_pton(AF_INET6, ipaddress, &in) != 1) {
1175  json_object_set_new(answer, "message", json_string("invalid address string"));
1176  return TM_ECODE_FAILED;
1177  } else {
1178  a.family = AF_INET6;
1179  a.addr_data32[0] = in6[0];
1180  a.addr_data32[1] = in6[1];
1181  a.addr_data32[2] = in6[2];
1182  a.addr_data32[3] = in6[3];
1183  }
1184  } else {
1185  a.family = AF_INET;
1186  a.addr_data32[0] = in.s_addr;
1187  a.addr_data32[1] = 0;
1188  a.addr_data32[2] = 0;
1189  a.addr_data32[3] = 0;
1190  }
1191 
1192  SCLogInfo("list-hostbit: %s", ipaddress);
1193 
1194  struct timeval ts;
1195  memset(&ts, 0, sizeof(ts));
1196  TimeGet(&ts);
1197 
1198  struct Bit {
1199  uint32_t id;
1200  uint32_t expire;
1201  } bits[256];
1202  memset(&bits, 0, sizeof(bits));
1203  int i = 0, use = 0;
1204 
1205  Host *host = HostLookupHostFromHash(&a);
1206  if (!host) {
1207  json_object_set_new(answer, "message", json_string("host not found"));
1208  return TM_ECODE_FAILED;
1209  }
1210 
1211  XBit *iter = NULL;
1212  while (use < 256 && HostBitList(host, &iter) == 1) {
1213  bits[use].id = iter->idx;
1214  bits[use].expire = iter->expire;
1215  use++;
1216  }
1217  HostUnlock(host);
1218 
1219  json_t *jdata = json_object();
1220  json_t *jarray = json_array();
1221  if (jarray == NULL || jdata == NULL) {
1222  if (jdata != NULL)
1223  json_decref(jdata);
1224  if (jarray != NULL)
1225  json_decref(jarray);
1226  json_object_set_new(answer, "message",
1227  json_string("internal error at json object creation"));
1228  return TM_ECODE_FAILED;
1229  }
1230 
1231  for (i = 0; i < use; i++) {
1232  json_t *bitobject = json_object();
1233  if (bitobject == NULL)
1234  continue;
1235  uint32_t expire = 0;
1236  if ((uint32_t)ts.tv_sec < bits[i].expire)
1237  expire = bits[i].expire - (uint32_t)ts.tv_sec;
1238 
1239  const char *name = VarNameStoreLookupById(bits[i].id, VAR_TYPE_HOST_BIT);
1240  if (name == NULL)
1241  continue;
1242  json_object_set_new(bitobject, "name", json_string(name));
1243  SCLogDebug("xbit %s expire %u", name, expire);
1244  json_object_set_new(bitobject, "expire", json_integer(expire));
1245  json_array_append_new(jarray, bitobject);
1246  }
1247 
1248  json_object_set_new(jdata, "count", json_integer(i));
1249  json_object_set_new(jdata, "hostbits", jarray);
1250  json_object_set_new(answer, "message", jdata);
1251  return TM_ECODE_OK;
1252 }
1253 
1254 static void MemcapBuildValue(uint64_t val, char *str, uint32_t str_len)
1255 {
1256  if ((val / (1024 * 1024 * 1024)) != 0) {
1257  snprintf(str, str_len, "%"PRIu64"gb", val / (1024*1024*1024));
1258  } else if ((val / (1024 * 1024)) != 0) {
1259  snprintf(str, str_len, "%"PRIu64"mb", val / (1024*1024));
1260  } else {
1261  snprintf(str, str_len, "%"PRIu64"kb", val / (1024));
1262  }
1263 }
1264 
1265 TmEcode UnixSocketSetMemcap(json_t *cmd, json_t* answer, void *data)
1266 {
1267  char *memcap = NULL;
1268  char *value_str = NULL;
1269  uint64_t value;
1270  int i;
1271 
1272  json_t *jarg = json_object_get(cmd, "config");
1273  if (!json_is_string(jarg)) {
1274  json_object_set_new(answer, "message", json_string("memcap key is not a string"));
1275  return TM_ECODE_FAILED;
1276  }
1277  memcap = (char *)json_string_value(jarg);
1278 
1279  jarg = json_object_get(cmd, "memcap");
1280  if (!json_is_string(jarg)) {
1281  json_object_set_new(answer, "message", json_string("memcap value is not a string"));
1282  return TM_ECODE_FAILED;
1283  }
1284  value_str = (char *)json_string_value(jarg);
1285 
1286  if (ParseSizeStringU64(value_str, &value) < 0) {
1287  SCLogError(SC_ERR_SIZE_PARSE, "Error parsing "
1288  "memcap from unix socket: %s", value_str);
1289  json_object_set_new(answer, "message",
1290  json_string("error parsing memcap specified, "
1291  "value not changed"));
1292  return TM_ECODE_FAILED;
1293  }
1294 
1295  for (i = 0; i < MEMCAPS_MAX; i++) {
1296  if (strcmp(memcaps[i].name, memcap) == 0 && memcaps[i].SetFunc) {
1297  int updated = memcaps[i].SetFunc(value);
1298  char message[150];
1299 
1300  if (updated) {
1301  snprintf(message, sizeof(message),
1302  "memcap value for '%s' updated: %"PRIu64" %s",
1303  memcaps[i].name, value,
1304  (value == 0) ? "(unlimited)" : "");
1305  json_object_set_new(answer, "message", json_string(message));
1306  return TM_ECODE_OK;
1307  } else {
1308  if (value == 0) {
1309  snprintf(message, sizeof(message),
1310  "Unlimited value is not allowed for '%s'", memcaps[i].name);
1311  } else {
1312  if (memcaps[i].GetMemuseFunc()) {
1313  char memuse[50];
1314  MemcapBuildValue(memcaps[i].GetMemuseFunc(), memuse, sizeof(memuse));
1315  snprintf(message, sizeof(message),
1316  "memcap value specified for '%s' is less than the memory in use: %s",
1317  memcaps[i].name, memuse);
1318  } else {
1319  snprintf(message, sizeof(message),
1320  "memcap value specified for '%s' is less than the memory in use",
1321  memcaps[i].name);
1322  }
1323  }
1324  json_object_set_new(answer, "message", json_string(message));
1325  return TM_ECODE_FAILED;
1326  }
1327  }
1328  }
1329 
1330  json_object_set_new(answer, "message",
1331  json_string("Memcap value not found. Use 'memcap-list' to show all"));
1332  return TM_ECODE_FAILED;
1333 }
1334 
1335 TmEcode UnixSocketShowMemcap(json_t *cmd, json_t *answer, void *data)
1336 {
1337  char *memcap = NULL;
1338  int i;
1339 
1340  json_t *jarg = json_object_get(cmd, "config");
1341  if (!json_is_string(jarg)) {
1342  json_object_set_new(answer, "message", json_string("memcap name is not a string"));
1343  return TM_ECODE_FAILED;
1344  }
1345  memcap = (char *)json_string_value(jarg);
1346 
1347  for (i = 0; i < MEMCAPS_MAX; i++) {
1348  if (strcmp(memcaps[i].name, memcap) == 0 && memcaps[i].GetFunc) {
1349  char str[50];
1350  uint64_t val = memcaps[i].GetFunc();
1351  json_t *jobj = json_object();
1352  if (jobj == NULL) {
1353  json_object_set_new(answer, "message",
1354  json_string("internal error at json object creation"));
1355  return TM_ECODE_FAILED;
1356  }
1357 
1358  if (val == 0) {
1359  strlcpy(str, "unlimited", sizeof(str));
1360  } else {
1361  MemcapBuildValue(val, str, sizeof(str));
1362  }
1363 
1364  json_object_set_new(jobj, "value", json_string(str));
1365  json_object_set_new(answer, "message", jobj);
1366  return TM_ECODE_OK;
1367  }
1368  }
1369 
1370  json_object_set_new(answer, "message",
1371  json_string("Memcap value not found. Use 'memcap-list' to show all"));
1372  return TM_ECODE_FAILED;
1373 }
1374 
1375 TmEcode UnixSocketShowAllMemcap(json_t *cmd, json_t *answer, void *data)
1376 {
1377  json_t *jmemcaps = json_array();
1378  int i;
1379 
1380  if (jmemcaps == NULL) {
1381  json_object_set_new(answer, "message",
1382  json_string("internal error at json array creation"));
1383  return TM_ECODE_FAILED;
1384  }
1385 
1386  for (i = 0; i < MEMCAPS_MAX; i++) {
1387  json_t *jobj = json_object();
1388  if (jobj == NULL) {
1389  json_decref(jmemcaps);
1390  json_object_set_new(answer, "message",
1391  json_string("internal error at json object creation"));
1392  return TM_ECODE_FAILED;
1393  }
1394  char str[50];
1395  uint64_t val = memcaps[i].GetFunc();
1396 
1397  if (val == 0) {
1398  strlcpy(str, "unlimited", sizeof(str));
1399  } else {
1400  MemcapBuildValue(val, str, sizeof(str));
1401  }
1402 
1403  json_object_set_new(jobj, "name", json_string(memcaps[i].name));
1404  json_object_set_new(jobj, "value", json_string(str));
1405  json_array_append_new(jmemcaps, jobj);
1406  }
1407 
1408  json_object_set_new(answer, "message", jmemcaps);
1410 }
1411 #endif /* BUILD_UNIX_SOCKET */
1412 
1413 #ifdef BUILD_UNIX_SOCKET
1414 /**
1415  * \brief Single thread version of the Pcap file processing.
1416  */
1417 static int RunModeUnixSocketMaster(void)
1418 {
1419  if (UnixManagerInit() != 0)
1420  return 1;
1421 
1422  PcapCommand *pcapcmd = SCMalloc(sizeof(PcapCommand));
1423  if (unlikely(pcapcmd == NULL)) {
1424  SCLogError(SC_ERR_MEM_ALLOC, "Can not allocate pcap command");
1425  return 1;
1426  }
1427  TAILQ_INIT(&pcapcmd->files);
1428  pcapcmd->running = 0;
1429  pcapcmd->current_file = NULL;
1430 
1431  memset(&unix_manager_pcap_last_processed, 0, sizeof(struct timespec));
1432 
1433  SCCtrlMutexInit(&unix_manager_pcap_last_processed_mutex, NULL);
1434 
1435  UnixManagerRegisterCommand("pcap-file", UnixSocketAddPcapFile, pcapcmd, UNIX_CMD_TAKE_ARGS);
1436  UnixManagerRegisterCommand("pcap-file-continuous", UnixSocketAddPcapFileContinuous, pcapcmd, UNIX_CMD_TAKE_ARGS);
1437  UnixManagerRegisterCommand("pcap-file-number", UnixSocketPcapFilesNumber, pcapcmd, 0);
1438  UnixManagerRegisterCommand("pcap-file-list", UnixSocketPcapFilesList, pcapcmd, 0);
1439  UnixManagerRegisterCommand("pcap-last-processed", UnixSocketPcapLastProcessed, pcapcmd, 0);
1440  UnixManagerRegisterCommand("pcap-interrupt", UnixSocketPcapInterrupt, pcapcmd, 0);
1441  UnixManagerRegisterCommand("pcap-current", UnixSocketPcapCurrent, pcapcmd, 0);
1442 
1443  UnixManagerRegisterBackgroundTask(UnixSocketPcapFilesCheck, pcapcmd);
1444 
1447 
1448  return 0;
1449 }
1450 #endif
1451 
1453 {
1455 }
1456 
1457 
1458 
1459 
uint32_t expire
Definition: util-var.h:60
int ConfYamlLoadFileWithPrefix(const char *filename, const char *prefix)
Load configuration from a YAML file, insert in tree at &#39;prefix&#39;.
#define SCLogDebug(...)
Definition: util-debug.h:335
void DetectEnginePruneFreeList(void)
#define TAILQ_FIRST(head)
Definition: queue.h:339
DetectEngineCtx * DetectEngineGetByTenantId(int tenant_id)
#define TAILQ_FOREACH(var, head, field)
Definition: queue.h:350
uint64_t StreamTcpReassembleGetMemcap()
Return memcap value.
struct HtpBodyChunk_ * next
struct PcapCommand_ PcapCommand
size_t strlcpy(char *dst, const char *src, size_t siz)
Definition: util-strlcpyu.c:43
int unix_socket_mode_is_running
Definition: util-var.h:55
uint64_t IPPairGetMemcap(void)
Return memcap value.
Definition: ippair.c:74
int DetectEngineTentantRegisterPcapFile(uint32_t tenant_id)
uint64_t HTPGetMemcap(void)
Update memcap value.
void DetectEngineDeReference(DetectEngineCtx **de_ctx)
#define unlikely(expr)
Definition: util-optimize.h:35
uint64_t DefragTrackerGetMemcap(void)
Return memcap value.
Definition: defrag-hash.c:53
int DetectEngineTentantUnregisterVlanId(uint32_t tenant_id, uint16_t vlan_id)
int HTPSetMemcap(uint64_t size)
Update memcap value.
uint64_t HTPMemuseGlobalCounter(void)
int DetectEngineReloadTenantBlocking(uint32_t tenant_id, const char *yaml, int reload_cnt)
Reload a tenant and wait for loading to complete.
uint64_t StreamTcpMemuseCounter(void)
Definition: stream-tcp.c:156
uint64_t IPPairGetMemuse(void)
Return memuse value.
Definition: ippair.c:85
#define TAILQ_HEAD(name, type)
Definition: queue.h:321
int IPPairSetMemcap(uint64_t size)
Update memcap value.
Definition: ippair.c:59
TmEcode TmThreadWaitOnThreadInit(void)
Used to check if all threads have finished their initialization. On finding an un-initialized thread...
Definition: tm-threads.c:2079
void HostBitSet(Host *h, uint32_t idx, uint32_t expire)
Definition: host-bit.c:132
int DetectEngineMultiTenantEnabled(void)
main detection engine ctx
Definition: detect.h:756
int UnixManagerInit(void)
uint32_t VarNameStoreLookupByName(const char *name, const enum VarTypes type)
int ParseSizeStringU64(const char *size, uint64_t *res)
Definition: util-misc.c:203
void PacketPoolPostRunmodes(void)
Set the max_pending_return_packets value.
#define str(s)
#define UNIX_CMD_TAKE_ARGS
Definition: unix-manager.h:31
char family
Definition: decode.h:111
void TimeGet(struct timeval *tv)
Definition: util-time.c:146
#define TAILQ_INIT(head)
Definition: queue.h:370
void PreRunInit(const int runmode)
Definition: suricata.c:2241
int RunModeUnixSocketIsActive(void)
void RunModeDispatch(int runmode, const char *custom_mode)
Definition: runmodes.c:278
int DetectEngineMoveToFreeList(DetectEngineCtx *de_ctx)
#define SCLogError(err_code,...)
Macro used to log ERROR messages.
Definition: util-debug.h:294
uint64_t StreamTcpGetMemcap(void)
Return memcap value.
Definition: stream-tcp.c:196
int(* SetFunc)(uint64_t)
int DetectEngineLoadTenantBlocking(uint32_t tenant_id, const char *yaml)
Load a tenant and wait for loading to complete.
int FlowSetMemcap(uint64_t size)
Update memcap value.
Definition: flow.c:98
#define TAILQ_REMOVE(head, elm, field)
Definition: queue.h:412
struct MemcapCommand_ MemcapCommand
uint64_t StreamTcpReassembleMemuseGlobalCounter(void)
int HostSetMemcap(uint64_t size)
Update memcap value.
Definition: host.c:60
int ConfSetFinal(const char *name, const char *val)
Set a final configuration value.
Definition: conf.c:299
const char * RunModeUnixSocketGetDefaultMode(void)
uint64_t(* GetFunc)(void)
void RunModeUnixSocketRegister(void)
#define SCCtrlMutex
void TmThreadContinueThreads()
Unpauses all threads present in tv_root.
Definition: tm-threads.c:1995
void UnixManagerThreadSpawn(int mode)
uint64_t SCTimespecAsEpochMillis(const struct timespec *ts)
Definition: util-time.c:615
#define SCReturnInt(x)
Definition: util-debug.h:341
Host * HostGetHostFromHash(Address *a)
Definition: host.c:500
void HostBitUnset(Host *h, uint32_t idx)
Definition: host-bit.c:140
int DetectEngineTentantUnregisterPcapFile(uint32_t tenant_id)
int StreamTcpReassembleSetMemcap(uint64_t size)
Update memcap value.
#define TAILQ_INSERT_TAIL(head, elm, field)
Definition: queue.h:385
int DetectEngineTentantRegisterVlanId(uint32_t tenant_id, uint16_t vlan_id)
uint64_t HostGetMemuse(void)
Return memuse value.
Definition: host.c:86
int DefragTrackerSetMemcap(uint64_t size)
Update memcap value.
Definition: defrag-hash.c:38
#define SCMalloc(a)
Definition: util-mem.h:222
uint32_t idx
Definition: util-var.h:58
#define SCLogInfo(...)
Macro used to log INFORMATIONAL messages.
Definition: util-debug.h:254
#define SCCtrlMutexLock(mut)
#define SCFree(a)
Definition: util-mem.h:322
Definition: host.h:58
int StreamTcpSetMemcap(uint64_t size)
Update memcap value.
Definition: stream-tcp.c:181
#define TAILQ_ENTRY(type)
Definition: queue.h:330
uint64_t DefragTrackerGetMemuse(void)
Return memuse value.
Definition: defrag-hash.c:64
uint64_t FlowGetMemuse(void)
Definition: flow.c:119
const char * VarNameStoreLookupById(const uint32_t id, const enum VarTypes type)
void HostUnlock(Host *h)
Definition: host.c:486
void PostRunDeinit(const int runmode, struct timeval *start_time)
Definition: suricata.c:2278
#define SCCtrlMutexUnlock(mut)
int HostBitList(Host *h, XBit **iter)
Definition: host-bit.c:185
#define SCStrdup(a)
Definition: util-mem.h:268
void RunModeRegisterNewRunMode(enum RunModes runmode, const char *name, const char *description, int(*RunModeFunc)(void))
Registers a new runmode.
Definition: runmodes.c:419
uint64_t FlowGetMemcap(void)
Return memcap value.
Definition: flow.c:113
#define TAILQ_EMPTY(head)
Definition: queue.h:347
TmEcode UnixSocketPcapFile(TmEcode tm, struct timespec *last_processed)
#define SCCtrlMutexInit(mut, mutattr)
Host * HostLookupHostFromHash(Address *a)
look up a host in the hash
Definition: host.c:599
void PreRunPostPrivsDropInit(const int runmode)
Definition: suricata.c:2264
uint64_t HostGetMemcap(void)
Return memcap value.
Definition: host.c:75
int DetectEngineMTApply(void)