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 #include "datasets.h"
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;
66 
67 typedef struct PcapCommand_ {
68  TAILQ_HEAD(, PcapFiles_) files;
69  int running;
70  PcapFiles *current_file;
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 "autofp";
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 
572  SCLogInfo("Starting run for '%s'", this->current_file->filename);
573 
576  RunModeDispatch(RUNMODE_PCAP_FILE, NULL, NULL, NULL);
577 
578  /* Un-pause all the paused threads */
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 #endif
598 }
599 
600 TmEcode UnixSocketPcapFile(TmEcode tm, struct timespec *last_processed)
601 {
602 #ifdef BUILD_UNIX_SOCKET
603  if(last_processed) {
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  }
609  switch (tm) {
610  case TM_ECODE_DONE:
611  SCLogInfo("Marking current task as done");
612  unix_manager_pcap_task_running = 0;
613  return TM_ECODE_DONE;
614  case TM_ECODE_FAILED:
615  SCLogInfo("Marking current task as failed");
616  unix_manager_pcap_task_running = 0;
617  unix_manager_pcap_task_failed = 1;
618  //if we return failed, we can't stop the thread and suricata will fail to close
619  return TM_ECODE_FAILED;
620  case TM_ECODE_OK:
621  if (unix_manager_pcap_task_interrupted == 1) {
622  SCLogInfo("Interrupting current run mode");
623  unix_manager_pcap_task_interrupted = 0;
624  return TM_ECODE_DONE;
625  } else {
626  return TM_ECODE_OK;
627  }
628  }
629 #endif
630  return TM_ECODE_FAILED;
631 }
632 
633 #ifdef BUILD_UNIX_SOCKET
634 /**
635  * \brief Command to add data to a dataset
636  *
637  * \param cmd the content of command Arguments as a json_t object
638  * \param answer the json_t object that has to be used to answer
639  * \param data pointer to data defining the context here a PcapCommand::
640  */
641 TmEcode UnixSocketDatasetAdd(json_t *cmd, json_t* answer, void *data)
642 {
643  /* 1 get dataset name */
644  json_t *narg = json_object_get(cmd, "setname");
645  if (!json_is_string(narg)) {
646  json_object_set_new(answer, "message", json_string("setname is not a string"));
647  return TM_ECODE_FAILED;
648  }
649  const char *set_name = json_string_value(narg);
650 
651  /* 2 get the data type */
652  json_t *targ = json_object_get(cmd, "settype");
653  if (!json_is_string(targ)) {
654  json_object_set_new(answer, "message", json_string("settype is not a string"));
655  return TM_ECODE_FAILED;
656  }
657  const char *type = json_string_value(targ);
658 
659  /* 3 get value */
660  json_t *varg = json_object_get(cmd, "datavalue");
661  if (!json_is_string(varg)) {
662  json_object_set_new(answer, "message", json_string("datavalue is not string"));
663  return TM_ECODE_FAILED;
664  }
665  const char *value = json_string_value(varg);
666 
667  SCLogDebug("dataset-add: %s type %s value %s", set_name, type, value);
668 
670  if (t == DATASET_TYPE_NOTSET) {
671  json_object_set_new(answer, "message", json_string("unknown settype"));
672  return TM_ECODE_FAILED;
673  }
674 
675  Dataset *set = DatasetFind(set_name, t);
676  if (set == NULL) {
677  json_object_set_new(answer, "message", json_string("set not found or wrong type"));
678  return TM_ECODE_FAILED;
679  }
680 
681  int r = DatasetAddSerialized(set, value);
682  if (r == 1) {
683  json_object_set_new(answer, "message", json_string("data added"));
684  return TM_ECODE_OK;
685  } else if (r == 0) {
686  json_object_set_new(answer, "message", json_string("data already in set"));
687  return TM_ECODE_OK;
688  } else {
689  json_object_set_new(answer, "message", json_string("failed to add data"));
690  return TM_ECODE_FAILED;
691  }
692 }
693 
694 TmEcode UnixSocketDatasetRemove(json_t *cmd, json_t* answer, void *data)
695 {
696  /* 1 get dataset name */
697  json_t *narg = json_object_get(cmd, "setname");
698  if (!json_is_string(narg)) {
699  json_object_set_new(answer, "message", json_string("setname is not a string"));
700  return TM_ECODE_FAILED;
701  }
702  const char *set_name = json_string_value(narg);
703 
704  /* 2 get the data type */
705  json_t *targ = json_object_get(cmd, "settype");
706  if (!json_is_string(targ)) {
707  json_object_set_new(answer, "message", json_string("settype is not a string"));
708  return TM_ECODE_FAILED;
709  }
710  const char *type = json_string_value(targ);
711 
712  /* 3 get value */
713  json_t *varg = json_object_get(cmd, "datavalue");
714  if (!json_is_string(varg)) {
715  json_object_set_new(answer, "message", json_string("datavalue is not string"));
716  return TM_ECODE_FAILED;
717  }
718  const char *value = json_string_value(varg);
719 
720  SCLogDebug("dataset-remove: %s type %s value %s", set_name, type, value);
721 
723  if (t == DATASET_TYPE_NOTSET) {
724  json_object_set_new(answer, "message", json_string("unknown settype"));
725  return TM_ECODE_FAILED;
726  }
727 
728  Dataset *set = DatasetFind(set_name, t);
729  if (set == NULL) {
730  json_object_set_new(answer, "message", json_string("set not found or wrong type"));
731  return TM_ECODE_FAILED;
732  }
733 
734  int r = DatasetRemoveSerialized(set, value);
735  if (r == 1) {
736  json_object_set_new(answer, "message", json_string("data removed"));
737  return TM_ECODE_OK;
738  } else if (r == 0) {
739  json_object_set_new(answer, "message", json_string("data is busy, try again"));
740  return TM_ECODE_OK;
741  } else {
742  json_object_set_new(answer, "message", json_string("failed to remove data"));
743  return TM_ECODE_FAILED;
744  }
745 }
746 
747 /**
748  * \brief Command to add a tenant handler
749  *
750  * \param cmd the content of command Arguments as a json_t object
751  * \param answer the json_t object that has to be used to answer
752  * \param data pointer to data defining the context here a PcapCommand::
753  */
754 TmEcode UnixSocketRegisterTenantHandler(json_t *cmd, json_t* answer, void *data)
755 {
756  const char *htype;
757  json_int_t traffic_id = -1;
758 
760  SCLogInfo("error: multi-tenant support not enabled");
761  json_object_set_new(answer, "message", json_string("multi-tenant support not enabled"));
762  return TM_ECODE_FAILED;
763  }
764 
765  /* 1 get tenant id */
766  json_t *jarg = json_object_get(cmd, "id");
767  if (!json_is_integer(jarg)) {
768  SCLogInfo("error: command is not a string");
769  json_object_set_new(answer, "message", json_string("id is not an integer"));
770  return TM_ECODE_FAILED;
771  }
772  int tenant_id = json_integer_value(jarg);
773 
774  /* 2 get tenant handler type */
775  jarg = json_object_get(cmd, "htype");
776  if (!json_is_string(jarg)) {
777  SCLogInfo("error: command is not a string");
778  json_object_set_new(answer, "message", json_string("command is not a string"));
779  return TM_ECODE_FAILED;
780  }
781  htype = json_string_value(jarg);
782 
783  SCLogDebug("add-tenant-handler: %d %s", tenant_id, htype);
784 
785  /* 3 get optional hargs */
786  json_t *hargs = json_object_get(cmd, "hargs");
787  if (hargs != NULL) {
788  if (!json_is_integer(hargs)) {
789  SCLogInfo("error: hargs not a number");
790  json_object_set_new(answer, "message", json_string("hargs not a number"));
791  return TM_ECODE_FAILED;
792  }
793  traffic_id = json_integer_value(hargs);
794  }
795 
796  /* 4 add to system */
797  int r = -1;
798  if (strcmp(htype, "pcap") == 0) {
800  } else if (strcmp(htype, "vlan") == 0) {
801  if (traffic_id < 0) {
802  json_object_set_new(answer, "message", json_string("vlan requires argument"));
803  return TM_ECODE_FAILED;
804  }
805  if (traffic_id > USHRT_MAX) {
806  json_object_set_new(answer, "message", json_string("vlan argument out of range"));
807  return TM_ECODE_FAILED;
808  }
809 
810  SCLogInfo("VLAN handler: id %u maps to tenant %u", (uint32_t)traffic_id, tenant_id);
811  r = DetectEngineTentantRegisterVlanId(tenant_id, (uint32_t)traffic_id);
812  }
813  if (r != 0) {
814  json_object_set_new(answer, "message", json_string("handler setup failure"));
815  return TM_ECODE_FAILED;
816  }
817 
818  if (DetectEngineMTApply() < 0) {
819  json_object_set_new(answer, "message", json_string("couldn't apply settings"));
820  // TODO cleanup
821  return TM_ECODE_FAILED;
822  }
823 
824  json_object_set_new(answer, "message", json_string("handler added"));
825  return TM_ECODE_OK;
826 }
827 
828 /**
829  * \brief Command to remove a tenant handler
830  *
831  * \param cmd the content of command Arguments as a json_t object
832  * \param answer the json_t object that has to be used to answer
833  * \param data pointer to data defining the context here a PcapCommand::
834  */
835 TmEcode UnixSocketUnregisterTenantHandler(json_t *cmd, json_t* answer, void *data)
836 {
837  const char *htype;
838  json_int_t traffic_id = -1;
839 
841  SCLogInfo("error: multi-tenant support not enabled");
842  json_object_set_new(answer, "message", json_string("multi-tenant support not enabled"));
843  return TM_ECODE_FAILED;
844  }
845 
846  /* 1 get tenant id */
847  json_t *jarg = json_object_get(cmd, "id");
848  if (!json_is_integer(jarg)) {
849  SCLogInfo("error: command is not a string");
850  json_object_set_new(answer, "message", json_string("id is not an integer"));
851  return TM_ECODE_FAILED;
852  }
853  int tenant_id = json_integer_value(jarg);
854 
855  /* 2 get tenant handler type */
856  jarg = json_object_get(cmd, "htype");
857  if (!json_is_string(jarg)) {
858  SCLogInfo("error: command is not a string");
859  json_object_set_new(answer, "message", json_string("command is not a string"));
860  return TM_ECODE_FAILED;
861  }
862  htype = json_string_value(jarg);
863 
864  SCLogDebug("add-tenant-handler: %d %s", tenant_id, htype);
865 
866  /* 3 get optional hargs */
867  json_t *hargs = json_object_get(cmd, "hargs");
868  if (hargs != NULL) {
869  if (!json_is_integer(hargs)) {
870  SCLogInfo("error: hargs not a number");
871  json_object_set_new(answer, "message", json_string("hargs not a number"));
872  return TM_ECODE_FAILED;
873  }
874  traffic_id = json_integer_value(hargs);
875  }
876 
877  /* 4 add to system */
878  int r = -1;
879  if (strcmp(htype, "pcap") == 0) {
881  } else if (strcmp(htype, "vlan") == 0) {
882  if (traffic_id < 0) {
883  json_object_set_new(answer, "message", json_string("vlan requires argument"));
884  return TM_ECODE_FAILED;
885  }
886  if (traffic_id > USHRT_MAX) {
887  json_object_set_new(answer, "message", json_string("vlan argument out of range"));
888  return TM_ECODE_FAILED;
889  }
890 
891  SCLogInfo("VLAN handler: removing mapping of %u to tenant %u", (uint32_t)traffic_id, tenant_id);
892  r = DetectEngineTentantUnregisterVlanId(tenant_id, (uint32_t)traffic_id);
893  }
894  if (r != 0) {
895  json_object_set_new(answer, "message", json_string("handler unregister failure"));
896  return TM_ECODE_FAILED;
897  }
898 
899  /* 5 apply it */
900  if (DetectEngineMTApply() < 0) {
901  json_object_set_new(answer, "message", json_string("couldn't apply settings"));
902  // TODO cleanup
903  return TM_ECODE_FAILED;
904  }
905 
906  json_object_set_new(answer, "message", json_string("handler removed"));
907  return TM_ECODE_OK;
908 }
909 
910 /**
911  * \brief Command to add a tenant
912  *
913  * \param cmd the content of command Arguments as a json_t object
914  * \param answer the json_t object that has to be used to answer
915  * \param data pointer to data defining the context here a PcapCommand::
916  */
917 TmEcode UnixSocketRegisterTenant(json_t *cmd, json_t* answer, void *data)
918 {
919  const char *filename;
920 #ifdef OS_WIN32
921  struct _stat st;
922 #else
923  struct stat st;
924 #endif /* OS_WIN32 */
925 
927  SCLogInfo("error: multi-tenant support not enabled");
928  json_object_set_new(answer, "message", json_string("multi-tenant support not enabled"));
929  return TM_ECODE_FAILED;
930  }
931 
932  /* 1 get tenant id */
933  json_t *jarg = json_object_get(cmd, "id");
934  if (!json_is_integer(jarg)) {
935  json_object_set_new(answer, "message", json_string("id is not an integer"));
936  return TM_ECODE_FAILED;
937  }
938  int tenant_id = json_integer_value(jarg);
939 
940  /* 2 get tenant yaml */
941  jarg = json_object_get(cmd, "filename");
942  if (!json_is_string(jarg)) {
943  json_object_set_new(answer, "message", json_string("command is not a string"));
944  return TM_ECODE_FAILED;
945  }
946  filename = json_string_value(jarg);
947 #ifdef OS_WIN32
948  if (_stat(filename, &st) != 0) {
949 #else
950  if (stat(filename, &st) != 0) {
951 #endif /* OS_WIN32 */
952  json_object_set_new(answer, "message", json_string("file does not exist"));
953  return TM_ECODE_FAILED;
954  }
955 
956  SCLogDebug("add-tenant: %d %s", tenant_id, filename);
957 
958  /* setup the yaml in this loop so that it's not done by the loader
959  * threads. ConfYamlLoadFileWithPrefix is not thread safe. */
960  char prefix[64];
961  snprintf(prefix, sizeof(prefix), "multi-detect.%d", tenant_id);
962  if (ConfYamlLoadFileWithPrefix(filename, prefix) != 0) {
963  SCLogError(SC_ERR_CONF_YAML_ERROR, "failed to load yaml %s", filename);
964  json_object_set_new(answer, "message", json_string("failed to load yaml"));
965  return TM_ECODE_FAILED;
966  }
967 
968  /* 3 load into the system */
969  if (DetectEngineLoadTenantBlocking(tenant_id, filename) != 0) {
970  json_object_set_new(answer, "message", json_string("adding tenant failed"));
971  return TM_ECODE_FAILED;
972  }
973 
974  /* 4 apply to the running system */
975  if (DetectEngineMTApply() < 0) {
976  json_object_set_new(answer, "message", json_string("couldn't apply settings"));
977  // TODO cleanup
978  return TM_ECODE_FAILED;
979  }
980 
981  json_object_set_new(answer, "message", json_string("adding tenant succeeded"));
982  return TM_ECODE_OK;
983 }
984 
985 static int reload_cnt = 1;
986 /**
987  * \brief Command to reload a tenant
988  *
989  * \param cmd the content of command Arguments as a json_t object
990  * \param answer the json_t object that has to be used to answer
991  * \param data pointer to data defining the context here a PcapCommand::
992  */
993 TmEcode UnixSocketReloadTenant(json_t *cmd, json_t* answer, void *data)
994 {
995  const char *filename;
996 #ifdef OS_WIN32
997  struct _stat st;
998 #else
999  struct stat st;
1000 #endif /* OS_WIN32 */
1001 
1002  if (!(DetectEngineMultiTenantEnabled())) {
1003  SCLogInfo("error: multi-tenant support not enabled");
1004  json_object_set_new(answer, "message", json_string("multi-tenant support not enabled"));
1005  return TM_ECODE_FAILED;
1006  }
1007 
1008  /* 1 get tenant id */
1009  json_t *jarg = json_object_get(cmd, "id");
1010  if (!json_is_integer(jarg)) {
1011  json_object_set_new(answer, "message", json_string("id is not an integer"));
1012  return TM_ECODE_FAILED;
1013  }
1014  int tenant_id = json_integer_value(jarg);
1015 
1016  /* 2 get tenant yaml */
1017  jarg = json_object_get(cmd, "filename");
1018  if (!json_is_string(jarg)) {
1019  json_object_set_new(answer, "message", json_string("command is not a string"));
1020  return TM_ECODE_FAILED;
1021  }
1022  filename = json_string_value(jarg);
1023 #ifdef OS_WIN32
1024  if (_stat(filename, &st) != 0) {
1025 #else
1026  if (stat(filename, &st) != 0) {
1027 #endif /* OS_WIN32 */
1028  json_object_set_new(answer, "message", json_string("file does not exist"));
1029  return TM_ECODE_FAILED;
1030  }
1031 
1032  SCLogDebug("reload-tenant: %d %s", tenant_id, filename);
1033 
1034  char prefix[64];
1035  snprintf(prefix, sizeof(prefix), "multi-detect.%d.reload.%d", tenant_id, reload_cnt);
1036  SCLogInfo("prefix %s", prefix);
1037 
1038  if (ConfYamlLoadFileWithPrefix(filename, prefix) != 0) {
1039  json_object_set_new(answer, "message", json_string("failed to load yaml"));
1040  return TM_ECODE_FAILED;
1041  }
1042 
1043  /* 3 load into the system */
1044  if (DetectEngineReloadTenantBlocking(tenant_id, filename, reload_cnt) != 0) {
1045  json_object_set_new(answer, "message", json_string("reload tenant failed"));
1046  return TM_ECODE_FAILED;
1047  }
1048 
1049  reload_cnt++;
1050 
1051  /* apply to the running system */
1052  if (DetectEngineMTApply() < 0) {
1053  json_object_set_new(answer, "message", json_string("couldn't apply settings"));
1054  // TODO cleanup
1055  return TM_ECODE_FAILED;
1056  }
1057 
1058  json_object_set_new(answer, "message", json_string("reloading tenant succeeded"));
1059  return TM_ECODE_OK;
1060 }
1061 
1062 /**
1063  * \brief Command to remove a tenant
1064  *
1065  * \param cmd the content of command Arguments as a json_t object
1066  * \param answer the json_t object that has to be used to answer
1067  * \param data pointer to data defining the context here a PcapCommand::
1068  */
1069 TmEcode UnixSocketUnregisterTenant(json_t *cmd, json_t* answer, void *data)
1070 {
1071  if (!(DetectEngineMultiTenantEnabled())) {
1072  SCLogInfo("error: multi-tenant support not enabled");
1073  json_object_set_new(answer, "message", json_string("multi-tenant support not enabled"));
1074  return TM_ECODE_FAILED;
1075  }
1076 
1077  /* 1 get tenant id */
1078  json_t *jarg = json_object_get(cmd, "id");
1079  if (!json_is_integer(jarg)) {
1080  SCLogInfo("error: command is not a string");
1081  json_object_set_new(answer, "message", json_string("id is not an integer"));
1082  return TM_ECODE_FAILED;
1083  }
1084  int tenant_id = json_integer_value(jarg);
1085 
1086  SCLogInfo("remove-tenant: removing tenant %d", tenant_id);
1087 
1088  /* 2 remove it from the system */
1089  char prefix[64];
1090  snprintf(prefix, sizeof(prefix), "multi-detect.%d", tenant_id);
1091 
1093  if (de_ctx == NULL) {
1094  json_object_set_new(answer, "message", json_string("tenant detect engine not found"));
1095  return TM_ECODE_FAILED;
1096  }
1097 
1098  /* move to free list */
1101 
1102  /* update the threads */
1103  if (DetectEngineMTApply() < 0) {
1104  json_object_set_new(answer, "message", json_string("couldn't apply settings"));
1105  // TODO cleanup
1106  return TM_ECODE_FAILED;
1107  }
1108 
1109  /* walk free list, freeing the removed de_ctx */
1111 
1112  json_object_set_new(answer, "message", json_string("removing tenant succeeded"));
1113  return TM_ECODE_OK;
1114 }
1115 
1116 /**
1117  * \brief Command to add a hostbit
1118  *
1119  * \param cmd the content of command Arguments as a json_t object
1120  * \param answer the json_t object that has to be used to answer
1121  */
1122 TmEcode UnixSocketHostbitAdd(json_t *cmd, json_t* answer, void *data_usused)
1123 {
1124  /* 1 get ip address */
1125  json_t *jarg = json_object_get(cmd, "ipaddress");
1126  if (!json_is_string(jarg)) {
1127  json_object_set_new(answer, "message", json_string("ipaddress is not an string"));
1128  return TM_ECODE_FAILED;
1129  }
1130  const char *ipaddress = json_string_value(jarg);
1131 
1132  Address a;
1133  struct in_addr in;
1134  memset(&in, 0, sizeof(in));
1135  if (inet_pton(AF_INET, ipaddress, &in) != 1) {
1136  uint32_t in6[4];
1137  memset(&in6, 0, sizeof(in6));
1138  if (inet_pton(AF_INET6, ipaddress, &in) != 1) {
1139  json_object_set_new(answer, "message", json_string("invalid address string"));
1140  return TM_ECODE_FAILED;
1141  } else {
1142  a.family = AF_INET6;
1143  a.addr_data32[0] = in6[0];
1144  a.addr_data32[1] = in6[1];
1145  a.addr_data32[2] = in6[2];
1146  a.addr_data32[3] = in6[3];
1147  }
1148  } else {
1149  a.family = AF_INET;
1150  a.addr_data32[0] = in.s_addr;
1151  a.addr_data32[1] = 0;
1152  a.addr_data32[2] = 0;
1153  a.addr_data32[3] = 0;
1154  }
1155 
1156  /* 2 get variable name */
1157  jarg = json_object_get(cmd, "hostbit");
1158  if (!json_is_string(jarg)) {
1159  json_object_set_new(answer, "message", json_string("hostbit is not a string"));
1160  return TM_ECODE_FAILED;
1161  }
1162  const char *hostbit = json_string_value(jarg);
1163  uint32_t idx = VarNameStoreLookupByName(hostbit, VAR_TYPE_HOST_BIT);
1164  if (idx == 0) {
1165  json_object_set_new(answer, "message", json_string("hostbit not found"));
1166  return TM_ECODE_FAILED;
1167  }
1168 
1169  /* 3 get expire */
1170  jarg = json_object_get(cmd, "expire");
1171  if (!json_is_integer(jarg)) {
1172  json_object_set_new(answer, "message", json_string("expire is not an integer"));
1173  return TM_ECODE_FAILED;
1174  }
1175  uint32_t expire = json_integer_value(jarg);
1176 
1177  SCLogInfo("add-hostbit: ip %s hostbit %s expire %us", ipaddress, hostbit, expire);
1178 
1179  struct timeval current_time;
1180  TimeGet(&current_time);
1181  Host *host = HostGetHostFromHash(&a);
1182  if (host) {
1183  HostBitSet(host, idx, current_time.tv_sec + expire);
1184  HostUnlock(host);
1185 
1186  json_object_set_new(answer, "message", json_string("hostbit added"));
1187  return TM_ECODE_OK;
1188  } else {
1189  json_object_set_new(answer, "message", json_string("couldn't create host"));
1190  return TM_ECODE_FAILED;
1191  }
1192 }
1193 
1194 /**
1195  * \brief Command to remove a hostbit
1196  *
1197  * \param cmd the content of command Arguments as a json_t object
1198  * \param answer the json_t object that has to be used to answer
1199  */
1200 TmEcode UnixSocketHostbitRemove(json_t *cmd, json_t* answer, void *data_unused)
1201 {
1202  /* 1 get ip address */
1203  json_t *jarg = json_object_get(cmd, "ipaddress");
1204  if (!json_is_string(jarg)) {
1205  json_object_set_new(answer, "message", json_string("ipaddress is not an string"));
1206  return TM_ECODE_FAILED;
1207  }
1208  const char *ipaddress = json_string_value(jarg);
1209 
1210  Address a;
1211  struct in_addr in;
1212  memset(&in, 0, sizeof(in));
1213  if (inet_pton(AF_INET, ipaddress, &in) != 1) {
1214  uint32_t in6[4];
1215  memset(&in6, 0, sizeof(in6));
1216  if (inet_pton(AF_INET6, ipaddress, &in) != 1) {
1217  json_object_set_new(answer, "message", json_string("invalid address string"));
1218  return TM_ECODE_FAILED;
1219  } else {
1220  a.family = AF_INET6;
1221  a.addr_data32[0] = in6[0];
1222  a.addr_data32[1] = in6[1];
1223  a.addr_data32[2] = in6[2];
1224  a.addr_data32[3] = in6[3];
1225  }
1226  } else {
1227  a.family = AF_INET;
1228  a.addr_data32[0] = in.s_addr;
1229  a.addr_data32[1] = 0;
1230  a.addr_data32[2] = 0;
1231  a.addr_data32[3] = 0;
1232  }
1233 
1234  /* 2 get variable name */
1235  jarg = json_object_get(cmd, "hostbit");
1236  if (!json_is_string(jarg)) {
1237  json_object_set_new(answer, "message", json_string("hostbit is not a string"));
1238  return TM_ECODE_FAILED;
1239  }
1240 
1241  const char *hostbit = json_string_value(jarg);
1242  uint32_t idx = VarNameStoreLookupByName(hostbit, VAR_TYPE_HOST_BIT);
1243  if (idx == 0) {
1244  json_object_set_new(answer, "message", json_string("hostbit not found"));
1245  return TM_ECODE_FAILED;
1246  }
1247 
1248  SCLogInfo("remove-hostbit: %s %s", ipaddress, hostbit);
1249 
1250  Host *host = HostLookupHostFromHash(&a);
1251  if (host) {
1252  HostBitUnset(host, idx);
1253  HostUnlock(host);
1254  json_object_set_new(answer, "message", json_string("hostbit removed"));
1255  return TM_ECODE_OK;
1256  } else {
1257  json_object_set_new(answer, "message", json_string("host not found"));
1258  return TM_ECODE_FAILED;
1259  }
1260 }
1261 
1262 /**
1263  * \brief Command to list hostbits for an ip
1264  *
1265  * \param cmd the content of command Arguments as a json_t object
1266  * \param answer the json_t object that has to be used to answer
1267  *
1268  * Message looks like:
1269  * {"message": {"count": 1, "hostbits": [{"expire": 3222, "name": "firefox-users"}]}, "return": "OK"}
1270  *
1271  * \retval r TM_ECODE_OK or TM_ECODE_FAILED
1272  */
1273 TmEcode UnixSocketHostbitList(json_t *cmd, json_t* answer, void *data_unused)
1274 {
1275  /* 1 get ip address */
1276  json_t *jarg = json_object_get(cmd, "ipaddress");
1277  if (!json_is_string(jarg)) {
1278  json_object_set_new(answer, "message", json_string("ipaddress is not an string"));
1279  return TM_ECODE_FAILED;
1280  }
1281  const char *ipaddress = json_string_value(jarg);
1282 
1283  Address a;
1284  struct in_addr in;
1285  memset(&in, 0, sizeof(in));
1286  if (inet_pton(AF_INET, ipaddress, &in) != 1) {
1287  uint32_t in6[4];
1288  memset(&in6, 0, sizeof(in6));
1289  if (inet_pton(AF_INET6, ipaddress, &in) != 1) {
1290  json_object_set_new(answer, "message", json_string("invalid address string"));
1291  return TM_ECODE_FAILED;
1292  } else {
1293  a.family = AF_INET6;
1294  a.addr_data32[0] = in6[0];
1295  a.addr_data32[1] = in6[1];
1296  a.addr_data32[2] = in6[2];
1297  a.addr_data32[3] = in6[3];
1298  }
1299  } else {
1300  a.family = AF_INET;
1301  a.addr_data32[0] = in.s_addr;
1302  a.addr_data32[1] = 0;
1303  a.addr_data32[2] = 0;
1304  a.addr_data32[3] = 0;
1305  }
1306 
1307  SCLogInfo("list-hostbit: %s", ipaddress);
1308 
1309  struct timeval ts;
1310  memset(&ts, 0, sizeof(ts));
1311  TimeGet(&ts);
1312 
1313  struct Bit {
1314  uint32_t id;
1315  uint32_t expire;
1316  } bits[256];
1317  memset(&bits, 0, sizeof(bits));
1318  int i = 0, use = 0;
1319 
1320  Host *host = HostLookupHostFromHash(&a);
1321  if (!host) {
1322  json_object_set_new(answer, "message", json_string("host not found"));
1323  return TM_ECODE_FAILED;
1324  }
1325 
1326  XBit *iter = NULL;
1327  while (use < 256 && HostBitList(host, &iter) == 1) {
1328  bits[use].id = iter->idx;
1329  bits[use].expire = iter->expire;
1330  use++;
1331  }
1332  HostUnlock(host);
1333 
1334  json_t *jdata = json_object();
1335  json_t *jarray = json_array();
1336  if (jarray == NULL || jdata == NULL) {
1337  if (jdata != NULL)
1338  json_decref(jdata);
1339  if (jarray != NULL)
1340  json_decref(jarray);
1341  json_object_set_new(answer, "message",
1342  json_string("internal error at json object creation"));
1343  return TM_ECODE_FAILED;
1344  }
1345 
1346  for (i = 0; i < use; i++) {
1347  json_t *bitobject = json_object();
1348  if (bitobject == NULL)
1349  continue;
1350  uint32_t expire = 0;
1351  if ((uint32_t)ts.tv_sec < bits[i].expire)
1352  expire = bits[i].expire - (uint32_t)ts.tv_sec;
1353 
1354  const char *name = VarNameStoreLookupById(bits[i].id, VAR_TYPE_HOST_BIT);
1355  if (name == NULL)
1356  continue;
1357  json_object_set_new(bitobject, "name", json_string(name));
1358  SCLogDebug("xbit %s expire %u", name, expire);
1359  json_object_set_new(bitobject, "expire", json_integer(expire));
1360  json_array_append_new(jarray, bitobject);
1361  }
1362 
1363  json_object_set_new(jdata, "count", json_integer(i));
1364  json_object_set_new(jdata, "hostbits", jarray);
1365  json_object_set_new(answer, "message", jdata);
1366  return TM_ECODE_OK;
1367 }
1368 
1369 static void MemcapBuildValue(uint64_t val, char *str, uint32_t str_len)
1370 {
1371  if ((val / (1024 * 1024 * 1024)) != 0) {
1372  snprintf(str, str_len, "%"PRIu64"gb", val / (1024*1024*1024));
1373  } else if ((val / (1024 * 1024)) != 0) {
1374  snprintf(str, str_len, "%"PRIu64"mb", val / (1024*1024));
1375  } else {
1376  snprintf(str, str_len, "%"PRIu64"kb", val / (1024));
1377  }
1378 }
1379 
1380 TmEcode UnixSocketSetMemcap(json_t *cmd, json_t* answer, void *data)
1381 {
1382  char *memcap = NULL;
1383  char *value_str = NULL;
1384  uint64_t value;
1385  int i;
1386 
1387  json_t *jarg = json_object_get(cmd, "config");
1388  if (!json_is_string(jarg)) {
1389  json_object_set_new(answer, "message", json_string("memcap key is not a string"));
1390  return TM_ECODE_FAILED;
1391  }
1392  memcap = (char *)json_string_value(jarg);
1393 
1394  jarg = json_object_get(cmd, "memcap");
1395  if (!json_is_string(jarg)) {
1396  json_object_set_new(answer, "message", json_string("memcap value is not a string"));
1397  return TM_ECODE_FAILED;
1398  }
1399  value_str = (char *)json_string_value(jarg);
1400 
1401  if (ParseSizeStringU64(value_str, &value) < 0) {
1402  SCLogError(SC_ERR_SIZE_PARSE, "Error parsing "
1403  "memcap from unix socket: %s", value_str);
1404  json_object_set_new(answer, "message",
1405  json_string("error parsing memcap specified, "
1406  "value not changed"));
1407  return TM_ECODE_FAILED;
1408  }
1409 
1410  for (i = 0; i < MEMCAPS_MAX; i++) {
1411  if (strcmp(memcaps[i].name, memcap) == 0 && memcaps[i].SetFunc) {
1412  int updated = memcaps[i].SetFunc(value);
1413  char message[150];
1414 
1415  if (updated) {
1416  snprintf(message, sizeof(message),
1417  "memcap value for '%s' updated: %"PRIu64" %s",
1418  memcaps[i].name, value,
1419  (value == 0) ? "(unlimited)" : "");
1420  json_object_set_new(answer, "message", json_string(message));
1421  return TM_ECODE_OK;
1422  } else {
1423  if (value == 0) {
1424  snprintf(message, sizeof(message),
1425  "Unlimited value is not allowed for '%s'", memcaps[i].name);
1426  } else {
1427  if (memcaps[i].GetMemuseFunc()) {
1428  char memuse[50];
1429  MemcapBuildValue(memcaps[i].GetMemuseFunc(), memuse, sizeof(memuse));
1430  snprintf(message, sizeof(message),
1431  "memcap value specified for '%s' is less than the memory in use: %s",
1432  memcaps[i].name, memuse);
1433  } else {
1434  snprintf(message, sizeof(message),
1435  "memcap value specified for '%s' is less than the memory in use",
1436  memcaps[i].name);
1437  }
1438  }
1439  json_object_set_new(answer, "message", json_string(message));
1440  return TM_ECODE_FAILED;
1441  }
1442  }
1443  }
1444 
1445  json_object_set_new(answer, "message",
1446  json_string("Memcap value not found. Use 'memcap-list' to show all"));
1447  return TM_ECODE_FAILED;
1448 }
1449 
1450 TmEcode UnixSocketShowMemcap(json_t *cmd, json_t *answer, void *data)
1451 {
1452  char *memcap = NULL;
1453  int i;
1454 
1455  json_t *jarg = json_object_get(cmd, "config");
1456  if (!json_is_string(jarg)) {
1457  json_object_set_new(answer, "message", json_string("memcap name is not a string"));
1458  return TM_ECODE_FAILED;
1459  }
1460  memcap = (char *)json_string_value(jarg);
1461 
1462  for (i = 0; i < MEMCAPS_MAX; i++) {
1463  if (strcmp(memcaps[i].name, memcap) == 0 && memcaps[i].GetFunc) {
1464  char str[50];
1465  uint64_t val = memcaps[i].GetFunc();
1466  json_t *jobj = json_object();
1467  if (jobj == NULL) {
1468  json_object_set_new(answer, "message",
1469  json_string("internal error at json object creation"));
1470  return TM_ECODE_FAILED;
1471  }
1472 
1473  if (val == 0) {
1474  strlcpy(str, "unlimited", sizeof(str));
1475  } else {
1476  MemcapBuildValue(val, str, sizeof(str));
1477  }
1478 
1479  json_object_set_new(jobj, "value", json_string(str));
1480  json_object_set_new(answer, "message", jobj);
1481  return TM_ECODE_OK;
1482  }
1483  }
1484 
1485  json_object_set_new(answer, "message",
1486  json_string("Memcap value not found. Use 'memcap-list' to show all"));
1487  return TM_ECODE_FAILED;
1488 }
1489 
1490 TmEcode UnixSocketShowAllMemcap(json_t *cmd, json_t *answer, void *data)
1491 {
1492  json_t *jmemcaps = json_array();
1493  int i;
1494 
1495  if (jmemcaps == NULL) {
1496  json_object_set_new(answer, "message",
1497  json_string("internal error at json array creation"));
1498  return TM_ECODE_FAILED;
1499  }
1500 
1501  for (i = 0; i < MEMCAPS_MAX; i++) {
1502  json_t *jobj = json_object();
1503  if (jobj == NULL) {
1504  json_decref(jmemcaps);
1505  json_object_set_new(answer, "message",
1506  json_string("internal error at json object creation"));
1507  return TM_ECODE_FAILED;
1508  }
1509  char str[50];
1510  uint64_t val = memcaps[i].GetFunc();
1511 
1512  if (val == 0) {
1513  strlcpy(str, "unlimited", sizeof(str));
1514  } else {
1515  MemcapBuildValue(val, str, sizeof(str));
1516  }
1517 
1518  json_object_set_new(jobj, "name", json_string(memcaps[i].name));
1519  json_object_set_new(jobj, "value", json_string(str));
1520  json_array_append_new(jmemcaps, jobj);
1521  }
1522 
1523  json_object_set_new(answer, "message", jmemcaps);
1525 }
1526 #endif /* BUILD_UNIX_SOCKET */
1527 
1528 #ifdef BUILD_UNIX_SOCKET
1529 /**
1530  * \brief Single thread version of the Pcap file processing.
1531  */
1532 static int RunModeUnixSocketMaster(void)
1533 {
1534  if (UnixManagerInit() != 0)
1535  return 1;
1536 
1537  PcapCommand *pcapcmd = SCMalloc(sizeof(PcapCommand));
1538  if (unlikely(pcapcmd == NULL)) {
1539  SCLogError(SC_ERR_MEM_ALLOC, "Can not allocate pcap command");
1540  return 1;
1541  }
1542  TAILQ_INIT(&pcapcmd->files);
1543  pcapcmd->running = 0;
1544  pcapcmd->current_file = NULL;
1545 
1546  memset(&unix_manager_pcap_last_processed, 0, sizeof(struct timespec));
1547 
1548  SCCtrlMutexInit(&unix_manager_pcap_last_processed_mutex, NULL);
1549 
1550  UnixManagerRegisterCommand("pcap-file", UnixSocketAddPcapFile, pcapcmd, UNIX_CMD_TAKE_ARGS);
1551  UnixManagerRegisterCommand("pcap-file-continuous", UnixSocketAddPcapFileContinuous, pcapcmd, UNIX_CMD_TAKE_ARGS);
1552  UnixManagerRegisterCommand("pcap-file-number", UnixSocketPcapFilesNumber, pcapcmd, 0);
1553  UnixManagerRegisterCommand("pcap-file-list", UnixSocketPcapFilesList, pcapcmd, 0);
1554  UnixManagerRegisterCommand("pcap-last-processed", UnixSocketPcapLastProcessed, pcapcmd, 0);
1555  UnixManagerRegisterCommand("pcap-interrupt", UnixSocketPcapInterrupt, pcapcmd, 0);
1556  UnixManagerRegisterCommand("pcap-current", UnixSocketPcapCurrent, pcapcmd, 0);
1557 
1558  UnixManagerRegisterBackgroundTask(UnixSocketPcapFilesCheck, pcapcmd);
1559 
1562 
1563  return 0;
1564 }
1565 #endif
1566 
1568 {
1570 }
1571 
1572 
1573 
1574 
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:485
ts
uint64_t ts
Definition: source-erf-file.c:54
XBit_::expire
uint32_t expire
Definition: util-var.h:60
ippair.h
detect-engine.h
DetectEngineMTApply
int DetectEngineMTApply(void)
Definition: detect-engine.c:4167
DetectEngineTentantRegisterPcapFile
int DetectEngineTentantRegisterPcapFile(uint32_t tenant_id)
Definition: detect-engine.c:3890
RUNMODE_UNIX_SOCKET
@ RUNMODE_UNIX_SOCKET
Definition: runmodes.h:41
MemcapCommand_::GetFunc
uint64_t(* GetFunc)(void)
Definition: runmode-unix-socket.c:76
PcapFiles_::continuous
bool continuous
Definition: runmode-unix-socket.c:62
DetectEngineDeReference
void DetectEngineDeReference(DetectEngineCtx **de_ctx)
Definition: detect-engine.c:3933
PcapFiles_::should_delete
bool should_delete
Definition: runmode-unix-socket.c:63
TAILQ_INIT
#define TAILQ_INIT(head)
Definition: queue.h:370
stream-tcp.h
DetectEnginePruneFreeList
void DetectEnginePruneFreeList(void)
Definition: detect-engine.c:4024
unlikely
#define unlikely(expr)
Definition: util-optimize.h:35
DetectEngineTentantUnregisterVlanId
int DetectEngineTentantUnregisterVlanId(uint32_t tenant_id, uint16_t vlan_id)
Definition: detect-engine.c:3885
StreamTcpReassembleGetMemcap
uint64_t StreamTcpReassembleGetMemcap()
Return memcap value.
Definition: stream-tcp-reassemble.c:175
SCLogDebug
#define SCLogDebug(...)
Definition: util-debug.h:298
ParseSizeStringU64
int ParseSizeStringU64(const char *size, uint64_t *res)
Definition: util-misc.c:202
DetectEngineGetByTenantId
DetectEngineCtx * DetectEngineGetByTenantId(int tenant_id)
Definition: detect-engine.c:3907
next
struct HtpBodyChunk_ * next
Definition: app-layer-htp.h:0
TM_ECODE_DONE
@ TM_ECODE_DONE
Definition: tm-threads-common.h:82
RunModeDispatch
void RunModeDispatch(int runmode, const char *custom_mode, const char *capture_plugin_name, const char *capture_plugin_args)
Definition: runmodes.c:283
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:3472
DetectEngineCtx_
main detection engine ctx
Definition: detect.h:767
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:494
HostGetHostFromHash
Host * HostGetHostFromHash(Address *a)
Definition: host.c:499
UnixManagerThreadSpawn
void UnixManagerThreadSpawn(int mode)
Definition: unix-manager.c:1241
HostSetMemcap
int HostSetMemcap(uint64_t size)
Update memcap value.
Definition: host.c:67
TAILQ_EMPTY
#define TAILQ_EMPTY(head)
Definition: queue.h:347
TAILQ_FOREACH
#define TAILQ_FOREACH(var, head, field)
Definition: queue.h:350
PcapCommand_
Definition: runmode-unix-socket.c:67
MemcapCommand_::GetMemuseFunc
uint64_t(* GetMemuseFunc)(void)
Definition: runmode-unix-socket.c:77
FlowGetMemuse
uint64_t FlowGetMemuse(void)
Definition: flow.c:136
FlowGetMemcap
uint64_t FlowGetMemcap(void)
Return memcap value.
Definition: flow.c:130
ConfSetFinal
int ConfSetFinal(const char *name, const char *val)
Set a final configuration value.
Definition: conf.c:298
Address_
Definition: decode.h:116
PreRunInit
void PreRunInit(const int runmode)
Definition: suricata.c:2008
stream-tcp-reassemble.h
unix_socket_mode_is_running
int unix_socket_mode_is_running
Definition: runmode-unix-socket.c:54
TAILQ_INSERT_TAIL
#define TAILQ_INSERT_TAIL(head, elm, field)
Definition: queue.h:385
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
TM_ECODE_FAILED
@ TM_ECODE_FAILED
Definition: tm-threads-common.h:81
MemcapCommand_::SetFunc
int(* SetFunc)(uint64_t)
Definition: runmode-unix-socket.c:75
SCJsonString
json_t * SCJsonString(const char *val)
Definition: output-json.c:113
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:80
HostGetMemcap
uint64_t HostGetMemcap(void)
Return memcap value.
Definition: host.c:82
TmThreadContinueThreads
void TmThreadContinueThreads()
Unpauses all threads present in tv_root.
Definition: tm-threads.c:1831
MemcapCommand_::name
const char * name
Definition: runmode-unix-socket.c:74
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:330
RunModeUnixSocketGetDefaultMode
const char * RunModeUnixSocketGetDefaultMode(void)
Definition: runmode-unix-socket.c:80
SC_ERR_SIZE_PARSE
@ SC_ERR_SIZE_PARSE
Definition: util-error.h:230
DetectEngineMultiTenantEnabled
int DetectEngineMultiTenantEnabled(void)
Definition: detect-engine.c:3264
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:412
PreRunPostPrivsDropInit
void PreRunPostPrivsDropInit(const int runmode)
Definition: suricata.c:2033
util-debug.h
DetectEngineMoveToFreeList
int DetectEngineMoveToFreeList(DetectEngineCtx *de_ctx)
Definition: detect-engine.c:3973
TAILQ_FIRST
#define TAILQ_FIRST(head)
Definition: queue.h:339
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:1901
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:645
DATASET_TYPE_NOTSET
#define DATASET_TYPE_NOTSET
Definition: datasets.h:31
IPPairGetMemcap
uint64_t IPPairGetMemcap(void)
Return memcap value.
Definition: ippair.c:80
util-affinity.h
util-time.h
source-pcap-file-directory-helper.h
RunModeUnixSocketIsActive
int RunModeUnixSocketIsActive(void)
Definition: runmode-unix-socket.c:1567
HostGetMemuse
uint64_t HostGetMemuse(void)
Return memuse value.
Definition: host.c:93
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:59
DetectEngineLoadTenantBlocking
int DetectEngineLoadTenantBlocking(uint32_t tenant_id, const char *yaml)
Load a tenant and wait for loading to complete.
Definition: detect-engine.c:3458
SCCtrlMutexLock
#define SCCtrlMutexLock(mut)
Definition: threads-debug.h:376
conf-yaml-loader.h
PcapFiles_
Definition: runmode-unix-socket.c:56
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:79
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:3880
defrag.h
runmodes.h
SCLogInfo
#define SCLogInfo(...)
Macro used to log INFORMATIONAL messages.
Definition: util-debug.h:217
PcapFiles_::poll_interval
time_t poll_interval
Definition: runmode-unix-socket.c:61
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:181
DetectEngineTentantUnregisterPcapFile
int DetectEngineTentantUnregisterPcapFile(uint32_t tenant_id)
Definition: detect-engine.c:3896
RunModeUnixSocketRegister
void RunModeUnixSocketRegister(void)
Definition: runmode-unix-socket.c:587
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:433
UnixManagerInit
int UnixManagerInit(void)
IPPairGetMemuse
uint64_t IPPairGetMemuse(void)
Return memuse value.
Definition: ippair.c:91
SCLogError
#define SCLogError(err_code,...)
Macro used to log ERROR messages.
Definition: util-debug.h:257
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:409
PcapFiles
struct PcapFiles_ PcapFiles
SCMalloc
#define SCMalloc(sz)
Definition: util-mem.h:47
unix-manager.h
str
#define str(s)
Definition: suricata-common.h:273
DatasetGetTypeFromString
enum DatasetTypes DatasetGetTypeFromString(const char *s)
Definition: datasets.c:53
SCFree
#define SCFree(p)
Definition: util-mem.h:61
StreamTcpMemuseCounter
uint64_t StreamTcpMemuseCounter(void)
Definition: stream-tcp.c:156
StreamTcpReassembleMemuseGlobalCounter
uint64_t StreamTcpReassembleMemuseGlobalCounter(void)
Definition: stream-tcp-reassemble.c:132
TAILQ_HEAD
#define TAILQ_HEAD(name, type)
Definition: queue.h:321
SCCtrlMutexInit
#define SCCtrlMutexInit(mut, mutattr)
Definition: threads-debug.h:375
StreamTcpGetMemcap
uint64_t StreamTcpGetMemcap(void)
Return memcap value.
Definition: stream-tcp.c:196
TimeGet
void TimeGet(struct timeval *tv)
Definition: util-time.c:153
PcapFiles_::delay
time_t delay
Definition: runmode-unix-socket.c:60
UnixSocketPcapFile
TmEcode UnixSocketPcapFile(TmEcode tm, struct timespec *last_processed)
Definition: runmode-unix-socket.c:600
app-layer-htp-mem.h
PcapFiles_::output_dir
char * output_dir
Definition: runmode-unix-socket.c:58
HostLookupHostFromHash
Host * HostLookupHostFromHash(Address *a)
look up a host in the hash
Definition: host.c:598
IPPairSetMemcap
int IPPairSetMemcap(uint64_t size)
Update memcap value.
Definition: ippair.c:65
SC_ERR_MEM_ALLOC
@ SC_ERR_MEM_ALLOC
Definition: util-error.h:31
defrag-hash.h
Address_::family
char family
Definition: decode.h:117
PostRunDeinit
void PostRunDeinit(const int runmode, struct timeval *start_time)
Definition: suricata.c:2047
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:1142
MemcapCommand_
Definition: runmode-unix-socket.c:73
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:160
Host_
Definition: host.h:58
SCReturnInt
#define SCReturnInt(x)
Definition: util-debug.h:304
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:57
FlowSetMemcap
int FlowSetMemcap(uint64_t size)
Update memcap value.
Definition: flow.c:115