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