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