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;
65 } PcapFiles;
66 
67 typedef struct PcapCommand_ {
68  TAILQ_HEAD(, PcapFiles_) files;
69  int running;
70  PcapFiles *current_file;
71 } PcapCommand;
72 
73 typedef struct MemcapCommand_ {
74  const char *name;
75  int (*SetFunc)(uint64_t);
76  uint64_t (*GetFunc)(void);
77  uint64_t (*GetMemuseFunc)(void);
79 
81 {
82  return "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 
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  SCLogNotice("dataset-add: %s type %s value %s", set_name, type, value);
668 
669  enum DatasetTypes t = DatasetGetTypeFromString(type);
670 
671  Dataset *set = DatasetFind(set_name, t);
672  if (set == NULL) {
673  json_object_set_new(answer, "message", json_string("set not found or wrong type"));
674  return TM_ECODE_FAILED;
675  }
676 
677  int r = DatasetAddSerialized(set, value);
678  if (r == 1) {
679  json_object_set_new(answer, "message", json_string("data added"));
680  return TM_ECODE_OK;
681  } else if (r == 0) {
682  json_object_set_new(answer, "message", json_string("data already in set"));
683  return TM_ECODE_OK;
684  } else {
685  json_object_set_new(answer, "message", json_string("failed to add data"));
686  return TM_ECODE_FAILED;
687  }
688 }
689 
690 /**
691  * \brief Command to add a tenant handler
692  *
693  * \param cmd the content of command Arguments as a json_t object
694  * \param answer the json_t object that has to be used to answer
695  * \param data pointer to data defining the context here a PcapCommand::
696  */
697 TmEcode UnixSocketRegisterTenantHandler(json_t *cmd, json_t* answer, void *data)
698 {
699  const char *htype;
700  json_int_t traffic_id = -1;
701 
703  SCLogInfo("error: multi-tenant support not enabled");
704  json_object_set_new(answer, "message", json_string("multi-tenant support not enabled"));
705  return TM_ECODE_FAILED;
706  }
707 
708  /* 1 get tenant id */
709  json_t *jarg = json_object_get(cmd, "id");
710  if (!json_is_integer(jarg)) {
711  SCLogInfo("error: command is not a string");
712  json_object_set_new(answer, "message", json_string("id is not an integer"));
713  return TM_ECODE_FAILED;
714  }
715  int tenant_id = json_integer_value(jarg);
716 
717  /* 2 get tenant handler type */
718  jarg = json_object_get(cmd, "htype");
719  if (!json_is_string(jarg)) {
720  SCLogInfo("error: command is not a string");
721  json_object_set_new(answer, "message", json_string("command is not a string"));
722  return TM_ECODE_FAILED;
723  }
724  htype = json_string_value(jarg);
725 
726  SCLogDebug("add-tenant-handler: %d %s", tenant_id, htype);
727 
728  /* 3 get optional hargs */
729  json_t *hargs = json_object_get(cmd, "hargs");
730  if (hargs != NULL) {
731  if (!json_is_integer(hargs)) {
732  SCLogInfo("error: hargs not a number");
733  json_object_set_new(answer, "message", json_string("hargs not a number"));
734  return TM_ECODE_FAILED;
735  }
736  traffic_id = json_integer_value(hargs);
737  }
738 
739  /* 4 add to system */
740  int r = -1;
741  if (strcmp(htype, "pcap") == 0) {
743  } else if (strcmp(htype, "vlan") == 0) {
744  if (traffic_id < 0) {
745  json_object_set_new(answer, "message", json_string("vlan requires argument"));
746  return TM_ECODE_FAILED;
747  }
748  if (traffic_id > USHRT_MAX) {
749  json_object_set_new(answer, "message", json_string("vlan argument out of range"));
750  return TM_ECODE_FAILED;
751  }
752 
753  SCLogInfo("VLAN handler: id %u maps to tenant %u", (uint32_t)traffic_id, tenant_id);
754  r = DetectEngineTentantRegisterVlanId(tenant_id, (uint32_t)traffic_id);
755  }
756  if (r != 0) {
757  json_object_set_new(answer, "message", json_string("handler setup failure"));
758  return TM_ECODE_FAILED;
759  }
760 
761  if (DetectEngineMTApply() < 0) {
762  json_object_set_new(answer, "message", json_string("couldn't apply settings"));
763  // TODO cleanup
764  return TM_ECODE_FAILED;
765  }
766 
767  json_object_set_new(answer, "message", json_string("handler added"));
768  return TM_ECODE_OK;
769 }
770 
771 /**
772  * \brief Command to remove a tenant handler
773  *
774  * \param cmd the content of command Arguments as a json_t object
775  * \param answer the json_t object that has to be used to answer
776  * \param data pointer to data defining the context here a PcapCommand::
777  */
778 TmEcode UnixSocketUnregisterTenantHandler(json_t *cmd, json_t* answer, void *data)
779 {
780  const char *htype;
781  json_int_t traffic_id = -1;
782 
784  SCLogInfo("error: multi-tenant support not enabled");
785  json_object_set_new(answer, "message", json_string("multi-tenant support not enabled"));
786  return TM_ECODE_FAILED;
787  }
788 
789  /* 1 get tenant id */
790  json_t *jarg = json_object_get(cmd, "id");
791  if (!json_is_integer(jarg)) {
792  SCLogInfo("error: command is not a string");
793  json_object_set_new(answer, "message", json_string("id is not an integer"));
794  return TM_ECODE_FAILED;
795  }
796  int tenant_id = json_integer_value(jarg);
797 
798  /* 2 get tenant handler type */
799  jarg = json_object_get(cmd, "htype");
800  if (!json_is_string(jarg)) {
801  SCLogInfo("error: command is not a string");
802  json_object_set_new(answer, "message", json_string("command is not a string"));
803  return TM_ECODE_FAILED;
804  }
805  htype = json_string_value(jarg);
806 
807  SCLogDebug("add-tenant-handler: %d %s", tenant_id, htype);
808 
809  /* 3 get optional hargs */
810  json_t *hargs = json_object_get(cmd, "hargs");
811  if (hargs != NULL) {
812  if (!json_is_integer(hargs)) {
813  SCLogInfo("error: hargs not a number");
814  json_object_set_new(answer, "message", json_string("hargs not a number"));
815  return TM_ECODE_FAILED;
816  }
817  traffic_id = json_integer_value(hargs);
818  }
819 
820  /* 4 add to system */
821  int r = -1;
822  if (strcmp(htype, "pcap") == 0) {
824  } else if (strcmp(htype, "vlan") == 0) {
825  if (traffic_id < 0) {
826  json_object_set_new(answer, "message", json_string("vlan requires argument"));
827  return TM_ECODE_FAILED;
828  }
829  if (traffic_id > USHRT_MAX) {
830  json_object_set_new(answer, "message", json_string("vlan argument out of range"));
831  return TM_ECODE_FAILED;
832  }
833 
834  SCLogInfo("VLAN handler: removing mapping of %u to tenant %u", (uint32_t)traffic_id, tenant_id);
835  r = DetectEngineTentantUnregisterVlanId(tenant_id, (uint32_t)traffic_id);
836  }
837  if (r != 0) {
838  json_object_set_new(answer, "message", json_string("handler unregister failure"));
839  return TM_ECODE_FAILED;
840  }
841 
842  /* 5 apply it */
843  if (DetectEngineMTApply() < 0) {
844  json_object_set_new(answer, "message", json_string("couldn't apply settings"));
845  // TODO cleanup
846  return TM_ECODE_FAILED;
847  }
848 
849  json_object_set_new(answer, "message", json_string("handler removed"));
850  return TM_ECODE_OK;
851 }
852 
853 /**
854  * \brief Command to add a tenant
855  *
856  * \param cmd the content of command Arguments as a json_t object
857  * \param answer the json_t object that has to be used to answer
858  * \param data pointer to data defining the context here a PcapCommand::
859  */
860 TmEcode UnixSocketRegisterTenant(json_t *cmd, json_t* answer, void *data)
861 {
862  const char *filename;
863 #ifdef OS_WIN32
864  struct _stat st;
865 #else
866  struct stat st;
867 #endif /* OS_WIN32 */
868 
870  SCLogInfo("error: multi-tenant support not enabled");
871  json_object_set_new(answer, "message", json_string("multi-tenant support not enabled"));
872  return TM_ECODE_FAILED;
873  }
874 
875  /* 1 get tenant id */
876  json_t *jarg = json_object_get(cmd, "id");
877  if (!json_is_integer(jarg)) {
878  json_object_set_new(answer, "message", json_string("id is not an integer"));
879  return TM_ECODE_FAILED;
880  }
881  int tenant_id = json_integer_value(jarg);
882 
883  /* 2 get tenant yaml */
884  jarg = json_object_get(cmd, "filename");
885  if (!json_is_string(jarg)) {
886  json_object_set_new(answer, "message", json_string("command is not a string"));
887  return TM_ECODE_FAILED;
888  }
889  filename = json_string_value(jarg);
890 #ifdef OS_WIN32
891  if (_stat(filename, &st) != 0) {
892 #else
893  if (stat(filename, &st) != 0) {
894 #endif /* OS_WIN32 */
895  json_object_set_new(answer, "message", json_string("file does not exist"));
896  return TM_ECODE_FAILED;
897  }
898 
899  SCLogDebug("add-tenant: %d %s", tenant_id, filename);
900 
901  /* setup the yaml in this loop so that it's not done by the loader
902  * threads. ConfYamlLoadFileWithPrefix is not thread safe. */
903  char prefix[64];
904  snprintf(prefix, sizeof(prefix), "multi-detect.%d", tenant_id);
905  if (ConfYamlLoadFileWithPrefix(filename, prefix) != 0) {
906  SCLogError(SC_ERR_CONF_YAML_ERROR, "failed to load yaml %s", filename);
907  json_object_set_new(answer, "message", json_string("failed to load yaml"));
908  return TM_ECODE_FAILED;
909  }
910 
911  /* 3 load into the system */
912  if (DetectEngineLoadTenantBlocking(tenant_id, filename) != 0) {
913  json_object_set_new(answer, "message", json_string("adding tenant failed"));
914  return TM_ECODE_FAILED;
915  }
916 
917  /* 4 apply to the running system */
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("adding tenant succeeded"));
925  return TM_ECODE_OK;
926 }
927 
928 static int reload_cnt = 1;
929 /**
930  * \brief Command to reload a tenant
931  *
932  * \param cmd the content of command Arguments as a json_t object
933  * \param answer the json_t object that has to be used to answer
934  * \param data pointer to data defining the context here a PcapCommand::
935  */
936 TmEcode UnixSocketReloadTenant(json_t *cmd, json_t* answer, void *data)
937 {
938  const char *filename;
939 #ifdef OS_WIN32
940  struct _stat st;
941 #else
942  struct stat st;
943 #endif /* OS_WIN32 */
944 
946  SCLogInfo("error: multi-tenant support not enabled");
947  json_object_set_new(answer, "message", json_string("multi-tenant support not enabled"));
948  return TM_ECODE_FAILED;
949  }
950 
951  /* 1 get tenant id */
952  json_t *jarg = json_object_get(cmd, "id");
953  if (!json_is_integer(jarg)) {
954  json_object_set_new(answer, "message", json_string("id is not an integer"));
955  return TM_ECODE_FAILED;
956  }
957  int tenant_id = json_integer_value(jarg);
958 
959  /* 2 get tenant yaml */
960  jarg = json_object_get(cmd, "filename");
961  if (!json_is_string(jarg)) {
962  json_object_set_new(answer, "message", json_string("command is not a string"));
963  return TM_ECODE_FAILED;
964  }
965  filename = json_string_value(jarg);
966 #ifdef OS_WIN32
967  if (_stat(filename, &st) != 0) {
968 #else
969  if (stat(filename, &st) != 0) {
970 #endif /* OS_WIN32 */
971  json_object_set_new(answer, "message", json_string("file does not exist"));
972  return TM_ECODE_FAILED;
973  }
974 
975  SCLogDebug("reload-tenant: %d %s", tenant_id, filename);
976 
977  char prefix[64];
978  snprintf(prefix, sizeof(prefix), "multi-detect.%d.reload.%d", tenant_id, reload_cnt);
979  SCLogInfo("prefix %s", prefix);
980 
981  if (ConfYamlLoadFileWithPrefix(filename, prefix) != 0) {
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 (DetectEngineReloadTenantBlocking(tenant_id, filename, reload_cnt) != 0) {
988  json_object_set_new(answer, "message", json_string("reload tenant failed"));
989  return TM_ECODE_FAILED;
990  }
991 
992  reload_cnt++;
993 
994  /* apply to the running system */
995  if (DetectEngineMTApply() < 0) {
996  json_object_set_new(answer, "message", json_string("couldn't apply settings"));
997  // TODO cleanup
998  return TM_ECODE_FAILED;
999  }
1000 
1001  json_object_set_new(answer, "message", json_string("reloading tenant succeeded"));
1002  return TM_ECODE_OK;
1003 }
1004 
1005 /**
1006  * \brief Command to remove a tenant
1007  *
1008  * \param cmd the content of command Arguments as a json_t object
1009  * \param answer the json_t object that has to be used to answer
1010  * \param data pointer to data defining the context here a PcapCommand::
1011  */
1012 TmEcode UnixSocketUnregisterTenant(json_t *cmd, json_t* answer, void *data)
1013 {
1014  if (!(DetectEngineMultiTenantEnabled())) {
1015  SCLogInfo("error: multi-tenant support not enabled");
1016  json_object_set_new(answer, "message", json_string("multi-tenant support not enabled"));
1017  return TM_ECODE_FAILED;
1018  }
1019 
1020  /* 1 get tenant id */
1021  json_t *jarg = json_object_get(cmd, "id");
1022  if (!json_is_integer(jarg)) {
1023  SCLogInfo("error: command is not a string");
1024  json_object_set_new(answer, "message", json_string("id is not an integer"));
1025  return TM_ECODE_FAILED;
1026  }
1027  int tenant_id = json_integer_value(jarg);
1028 
1029  SCLogInfo("remove-tenant: removing tenant %d", tenant_id);
1030 
1031  /* 2 remove it from the system */
1032  char prefix[64];
1033  snprintf(prefix, sizeof(prefix), "multi-detect.%d", tenant_id);
1034 
1035  DetectEngineCtx *de_ctx = DetectEngineGetByTenantId(tenant_id);
1036  if (de_ctx == NULL) {
1037  json_object_set_new(answer, "message", json_string("tenant detect engine not found"));
1038  return TM_ECODE_FAILED;
1039  }
1040 
1041  /* move to free list */
1043  DetectEngineDeReference(&de_ctx);
1044 
1045  /* update the threads */
1046  if (DetectEngineMTApply() < 0) {
1047  json_object_set_new(answer, "message", json_string("couldn't apply settings"));
1048  // TODO cleanup
1049  return TM_ECODE_FAILED;
1050  }
1051 
1052  /* walk free list, freeing the removed de_ctx */
1054 
1055  json_object_set_new(answer, "message", json_string("removing tenant succeeded"));
1056  return TM_ECODE_OK;
1057 }
1058 
1059 /**
1060  * \brief Command to add a hostbit
1061  *
1062  * \param cmd the content of command Arguments as a json_t object
1063  * \param answer the json_t object that has to be used to answer
1064  */
1065 TmEcode UnixSocketHostbitAdd(json_t *cmd, json_t* answer, void *data_usused)
1066 {
1067  /* 1 get ip address */
1068  json_t *jarg = json_object_get(cmd, "ipaddress");
1069  if (!json_is_string(jarg)) {
1070  json_object_set_new(answer, "message", json_string("ipaddress is not an string"));
1071  return TM_ECODE_FAILED;
1072  }
1073  const char *ipaddress = json_string_value(jarg);
1074 
1075  Address a;
1076  struct in_addr in;
1077  memset(&in, 0, sizeof(in));
1078  if (inet_pton(AF_INET, ipaddress, &in) != 1) {
1079  uint32_t in6[4];
1080  memset(&in6, 0, sizeof(in6));
1081  if (inet_pton(AF_INET6, ipaddress, &in) != 1) {
1082  json_object_set_new(answer, "message", json_string("invalid address string"));
1083  return TM_ECODE_FAILED;
1084  } else {
1085  a.family = AF_INET6;
1086  a.addr_data32[0] = in6[0];
1087  a.addr_data32[1] = in6[1];
1088  a.addr_data32[2] = in6[2];
1089  a.addr_data32[3] = in6[3];
1090  }
1091  } else {
1092  a.family = AF_INET;
1093  a.addr_data32[0] = in.s_addr;
1094  a.addr_data32[1] = 0;
1095  a.addr_data32[2] = 0;
1096  a.addr_data32[3] = 0;
1097  }
1098 
1099  /* 2 get variable name */
1100  jarg = json_object_get(cmd, "hostbit");
1101  if (!json_is_string(jarg)) {
1102  json_object_set_new(answer, "message", json_string("hostbit is not a string"));
1103  return TM_ECODE_FAILED;
1104  }
1105  const char *hostbit = json_string_value(jarg);
1106  uint32_t idx = VarNameStoreLookupByName(hostbit, VAR_TYPE_HOST_BIT);
1107  if (idx == 0) {
1108  json_object_set_new(answer, "message", json_string("hostbit not found"));
1109  return TM_ECODE_FAILED;
1110  }
1111 
1112  /* 3 get expire */
1113  jarg = json_object_get(cmd, "expire");
1114  if (!json_is_integer(jarg)) {
1115  json_object_set_new(answer, "message", json_string("expire is not an integer"));
1116  return TM_ECODE_FAILED;
1117  }
1118  uint32_t expire = json_integer_value(jarg);
1119 
1120  SCLogInfo("add-hostbit: ip %s hostbit %s expire %us", ipaddress, hostbit, expire);
1121 
1122  struct timeval current_time;
1123  TimeGet(&current_time);
1124  Host *host = HostGetHostFromHash(&a);
1125  if (host) {
1126  HostBitSet(host, idx, current_time.tv_sec + expire);
1127  HostUnlock(host);
1128 
1129  json_object_set_new(answer, "message", json_string("hostbit added"));
1130  return TM_ECODE_OK;
1131  } else {
1132  json_object_set_new(answer, "message", json_string("couldn't create host"));
1133  return TM_ECODE_FAILED;
1134  }
1135 }
1136 
1137 /**
1138  * \brief Command to remove a hostbit
1139  *
1140  * \param cmd the content of command Arguments as a json_t object
1141  * \param answer the json_t object that has to be used to answer
1142  */
1143 TmEcode UnixSocketHostbitRemove(json_t *cmd, json_t* answer, void *data_unused)
1144 {
1145  /* 1 get ip address */
1146  json_t *jarg = json_object_get(cmd, "ipaddress");
1147  if (!json_is_string(jarg)) {
1148  json_object_set_new(answer, "message", json_string("ipaddress is not an string"));
1149  return TM_ECODE_FAILED;
1150  }
1151  const char *ipaddress = json_string_value(jarg);
1152 
1153  Address a;
1154  struct in_addr in;
1155  memset(&in, 0, sizeof(in));
1156  if (inet_pton(AF_INET, ipaddress, &in) != 1) {
1157  uint32_t in6[4];
1158  memset(&in6, 0, sizeof(in6));
1159  if (inet_pton(AF_INET6, ipaddress, &in) != 1) {
1160  json_object_set_new(answer, "message", json_string("invalid address string"));
1161  return TM_ECODE_FAILED;
1162  } else {
1163  a.family = AF_INET6;
1164  a.addr_data32[0] = in6[0];
1165  a.addr_data32[1] = in6[1];
1166  a.addr_data32[2] = in6[2];
1167  a.addr_data32[3] = in6[3];
1168  }
1169  } else {
1170  a.family = AF_INET;
1171  a.addr_data32[0] = in.s_addr;
1172  a.addr_data32[1] = 0;
1173  a.addr_data32[2] = 0;
1174  a.addr_data32[3] = 0;
1175  }
1176 
1177  /* 2 get variable name */
1178  jarg = json_object_get(cmd, "hostbit");
1179  if (!json_is_string(jarg)) {
1180  json_object_set_new(answer, "message", json_string("hostbit is not a string"));
1181  return TM_ECODE_FAILED;
1182  }
1183 
1184  const char *hostbit = json_string_value(jarg);
1185  uint32_t idx = VarNameStoreLookupByName(hostbit, VAR_TYPE_HOST_BIT);
1186  if (idx == 0) {
1187  json_object_set_new(answer, "message", json_string("hostbit not found"));
1188  return TM_ECODE_FAILED;
1189  }
1190 
1191  SCLogInfo("remove-hostbit: %s %s", ipaddress, hostbit);
1192 
1193  Host *host = HostLookupHostFromHash(&a);
1194  if (host) {
1195  HostBitUnset(host, idx);
1196  HostUnlock(host);
1197  json_object_set_new(answer, "message", json_string("hostbit removed"));
1198  return TM_ECODE_OK;
1199  } else {
1200  json_object_set_new(answer, "message", json_string("host not found"));
1201  return TM_ECODE_FAILED;
1202  }
1203 }
1204 
1205 /**
1206  * \brief Command to list hostbits for an ip
1207  *
1208  * \param cmd the content of command Arguments as a json_t object
1209  * \param answer the json_t object that has to be used to answer
1210  *
1211  * Message looks like:
1212  * {"message": {"count": 1, "hostbits": [{"expire": 3222, "name": "firefox-users"}]}, "return": "OK"}
1213  *
1214  * \retval r TM_ECODE_OK or TM_ECODE_FAILED
1215  */
1216 TmEcode UnixSocketHostbitList(json_t *cmd, json_t* answer, void *data_unused)
1217 {
1218  /* 1 get ip address */
1219  json_t *jarg = json_object_get(cmd, "ipaddress");
1220  if (!json_is_string(jarg)) {
1221  json_object_set_new(answer, "message", json_string("ipaddress is not an string"));
1222  return TM_ECODE_FAILED;
1223  }
1224  const char *ipaddress = json_string_value(jarg);
1225 
1226  Address a;
1227  struct in_addr in;
1228  memset(&in, 0, sizeof(in));
1229  if (inet_pton(AF_INET, ipaddress, &in) != 1) {
1230  uint32_t in6[4];
1231  memset(&in6, 0, sizeof(in6));
1232  if (inet_pton(AF_INET6, ipaddress, &in) != 1) {
1233  json_object_set_new(answer, "message", json_string("invalid address string"));
1234  return TM_ECODE_FAILED;
1235  } else {
1236  a.family = AF_INET6;
1237  a.addr_data32[0] = in6[0];
1238  a.addr_data32[1] = in6[1];
1239  a.addr_data32[2] = in6[2];
1240  a.addr_data32[3] = in6[3];
1241  }
1242  } else {
1243  a.family = AF_INET;
1244  a.addr_data32[0] = in.s_addr;
1245  a.addr_data32[1] = 0;
1246  a.addr_data32[2] = 0;
1247  a.addr_data32[3] = 0;
1248  }
1249 
1250  SCLogInfo("list-hostbit: %s", ipaddress);
1251 
1252  struct timeval ts;
1253  memset(&ts, 0, sizeof(ts));
1254  TimeGet(&ts);
1255 
1256  struct Bit {
1257  uint32_t id;
1258  uint32_t expire;
1259  } bits[256];
1260  memset(&bits, 0, sizeof(bits));
1261  int i = 0, use = 0;
1262 
1263  Host *host = HostLookupHostFromHash(&a);
1264  if (!host) {
1265  json_object_set_new(answer, "message", json_string("host not found"));
1266  return TM_ECODE_FAILED;
1267  }
1268 
1269  XBit *iter = NULL;
1270  while (use < 256 && HostBitList(host, &iter) == 1) {
1271  bits[use].id = iter->idx;
1272  bits[use].expire = iter->expire;
1273  use++;
1274  }
1275  HostUnlock(host);
1276 
1277  json_t *jdata = json_object();
1278  json_t *jarray = json_array();
1279  if (jarray == NULL || jdata == NULL) {
1280  if (jdata != NULL)
1281  json_decref(jdata);
1282  if (jarray != NULL)
1283  json_decref(jarray);
1284  json_object_set_new(answer, "message",
1285  json_string("internal error at json object creation"));
1286  return TM_ECODE_FAILED;
1287  }
1288 
1289  for (i = 0; i < use; i++) {
1290  json_t *bitobject = json_object();
1291  if (bitobject == NULL)
1292  continue;
1293  uint32_t expire = 0;
1294  if ((uint32_t)ts.tv_sec < bits[i].expire)
1295  expire = bits[i].expire - (uint32_t)ts.tv_sec;
1296 
1297  const char *name = VarNameStoreLookupById(bits[i].id, VAR_TYPE_HOST_BIT);
1298  if (name == NULL)
1299  continue;
1300  json_object_set_new(bitobject, "name", json_string(name));
1301  SCLogDebug("xbit %s expire %u", name, expire);
1302  json_object_set_new(bitobject, "expire", json_integer(expire));
1303  json_array_append_new(jarray, bitobject);
1304  }
1305 
1306  json_object_set_new(jdata, "count", json_integer(i));
1307  json_object_set_new(jdata, "hostbits", jarray);
1308  json_object_set_new(answer, "message", jdata);
1309  return TM_ECODE_OK;
1310 }
1311 
1312 static void MemcapBuildValue(uint64_t val, char *str, uint32_t str_len)
1313 {
1314  if ((val / (1024 * 1024 * 1024)) != 0) {
1315  snprintf(str, str_len, "%"PRIu64"gb", val / (1024*1024*1024));
1316  } else if ((val / (1024 * 1024)) != 0) {
1317  snprintf(str, str_len, "%"PRIu64"mb", val / (1024*1024));
1318  } else {
1319  snprintf(str, str_len, "%"PRIu64"kb", val / (1024));
1320  }
1321 }
1322 
1323 TmEcode UnixSocketSetMemcap(json_t *cmd, json_t* answer, void *data)
1324 {
1325  char *memcap = NULL;
1326  char *value_str = NULL;
1327  uint64_t value;
1328  int i;
1329 
1330  json_t *jarg = json_object_get(cmd, "config");
1331  if (!json_is_string(jarg)) {
1332  json_object_set_new(answer, "message", json_string("memcap key is not a string"));
1333  return TM_ECODE_FAILED;
1334  }
1335  memcap = (char *)json_string_value(jarg);
1336 
1337  jarg = json_object_get(cmd, "memcap");
1338  if (!json_is_string(jarg)) {
1339  json_object_set_new(answer, "message", json_string("memcap value is not a string"));
1340  return TM_ECODE_FAILED;
1341  }
1342  value_str = (char *)json_string_value(jarg);
1343 
1344  if (ParseSizeStringU64(value_str, &value) < 0) {
1345  SCLogError(SC_ERR_SIZE_PARSE, "Error parsing "
1346  "memcap from unix socket: %s", value_str);
1347  json_object_set_new(answer, "message",
1348  json_string("error parsing memcap specified, "
1349  "value not changed"));
1350  return TM_ECODE_FAILED;
1351  }
1352 
1353  for (i = 0; i < MEMCAPS_MAX; i++) {
1354  if (strcmp(memcaps[i].name, memcap) == 0 && memcaps[i].SetFunc) {
1355  int updated = memcaps[i].SetFunc(value);
1356  char message[150];
1357 
1358  if (updated) {
1359  snprintf(message, sizeof(message),
1360  "memcap value for '%s' updated: %"PRIu64" %s",
1361  memcaps[i].name, value,
1362  (value == 0) ? "(unlimited)" : "");
1363  json_object_set_new(answer, "message", json_string(message));
1364  return TM_ECODE_OK;
1365  } else {
1366  if (value == 0) {
1367  snprintf(message, sizeof(message),
1368  "Unlimited value is not allowed for '%s'", memcaps[i].name);
1369  } else {
1370  if (memcaps[i].GetMemuseFunc()) {
1371  char memuse[50];
1372  MemcapBuildValue(memcaps[i].GetMemuseFunc(), memuse, sizeof(memuse));
1373  snprintf(message, sizeof(message),
1374  "memcap value specified for '%s' is less than the memory in use: %s",
1375  memcaps[i].name, memuse);
1376  } else {
1377  snprintf(message, sizeof(message),
1378  "memcap value specified for '%s' is less than the memory in use",
1379  memcaps[i].name);
1380  }
1381  }
1382  json_object_set_new(answer, "message", json_string(message));
1383  return TM_ECODE_FAILED;
1384  }
1385  }
1386  }
1387 
1388  json_object_set_new(answer, "message",
1389  json_string("Memcap value not found. Use 'memcap-list' to show all"));
1390  return TM_ECODE_FAILED;
1391 }
1392 
1393 TmEcode UnixSocketShowMemcap(json_t *cmd, json_t *answer, void *data)
1394 {
1395  char *memcap = NULL;
1396  int i;
1397 
1398  json_t *jarg = json_object_get(cmd, "config");
1399  if (!json_is_string(jarg)) {
1400  json_object_set_new(answer, "message", json_string("memcap name is not a string"));
1401  return TM_ECODE_FAILED;
1402  }
1403  memcap = (char *)json_string_value(jarg);
1404 
1405  for (i = 0; i < MEMCAPS_MAX; i++) {
1406  if (strcmp(memcaps[i].name, memcap) == 0 && memcaps[i].GetFunc) {
1407  char str[50];
1408  uint64_t val = memcaps[i].GetFunc();
1409  json_t *jobj = json_object();
1410  if (jobj == NULL) {
1411  json_object_set_new(answer, "message",
1412  json_string("internal error at json object creation"));
1413  return TM_ECODE_FAILED;
1414  }
1415 
1416  if (val == 0) {
1417  strlcpy(str, "unlimited", sizeof(str));
1418  } else {
1419  MemcapBuildValue(val, str, sizeof(str));
1420  }
1421 
1422  json_object_set_new(jobj, "value", json_string(str));
1423  json_object_set_new(answer, "message", jobj);
1424  return TM_ECODE_OK;
1425  }
1426  }
1427 
1428  json_object_set_new(answer, "message",
1429  json_string("Memcap value not found. Use 'memcap-list' to show all"));
1430  return TM_ECODE_FAILED;
1431 }
1432 
1433 TmEcode UnixSocketShowAllMemcap(json_t *cmd, json_t *answer, void *data)
1434 {
1435  json_t *jmemcaps = json_array();
1436  int i;
1437 
1438  if (jmemcaps == NULL) {
1439  json_object_set_new(answer, "message",
1440  json_string("internal error at json array creation"));
1441  return TM_ECODE_FAILED;
1442  }
1443 
1444  for (i = 0; i < MEMCAPS_MAX; i++) {
1445  json_t *jobj = json_object();
1446  if (jobj == NULL) {
1447  json_decref(jmemcaps);
1448  json_object_set_new(answer, "message",
1449  json_string("internal error at json object creation"));
1450  return TM_ECODE_FAILED;
1451  }
1452  char str[50];
1453  uint64_t val = memcaps[i].GetFunc();
1454 
1455  if (val == 0) {
1456  strlcpy(str, "unlimited", sizeof(str));
1457  } else {
1458  MemcapBuildValue(val, str, sizeof(str));
1459  }
1460 
1461  json_object_set_new(jobj, "name", json_string(memcaps[i].name));
1462  json_object_set_new(jobj, "value", json_string(str));
1463  json_array_append_new(jmemcaps, jobj);
1464  }
1465 
1466  json_object_set_new(answer, "message", jmemcaps);
1468 }
1469 #endif /* BUILD_UNIX_SOCKET */
1470 
1471 #ifdef BUILD_UNIX_SOCKET
1472 /**
1473  * \brief Single thread version of the Pcap file processing.
1474  */
1475 static int RunModeUnixSocketMaster(void)
1476 {
1477  if (UnixManagerInit() != 0)
1478  return 1;
1479 
1480  PcapCommand *pcapcmd = SCMalloc(sizeof(PcapCommand));
1481  if (unlikely(pcapcmd == NULL)) {
1482  SCLogError(SC_ERR_MEM_ALLOC, "Can not allocate pcap command");
1483  return 1;
1484  }
1485  TAILQ_INIT(&pcapcmd->files);
1486  pcapcmd->running = 0;
1487  pcapcmd->current_file = NULL;
1488 
1489  memset(&unix_manager_pcap_last_processed, 0, sizeof(struct timespec));
1490 
1491  SCCtrlMutexInit(&unix_manager_pcap_last_processed_mutex, NULL);
1492 
1493  UnixManagerRegisterCommand("pcap-file", UnixSocketAddPcapFile, pcapcmd, UNIX_CMD_TAKE_ARGS);
1494  UnixManagerRegisterCommand("pcap-file-continuous", UnixSocketAddPcapFileContinuous, pcapcmd, UNIX_CMD_TAKE_ARGS);
1495  UnixManagerRegisterCommand("pcap-file-number", UnixSocketPcapFilesNumber, pcapcmd, 0);
1496  UnixManagerRegisterCommand("pcap-file-list", UnixSocketPcapFilesList, pcapcmd, 0);
1497  UnixManagerRegisterCommand("pcap-last-processed", UnixSocketPcapLastProcessed, pcapcmd, 0);
1498  UnixManagerRegisterCommand("pcap-interrupt", UnixSocketPcapInterrupt, pcapcmd, 0);
1499  UnixManagerRegisterCommand("pcap-current", UnixSocketPcapCurrent, pcapcmd, 0);
1500 
1501  UnixManagerRegisterBackgroundTask(UnixSocketPcapFilesCheck, pcapcmd);
1502 
1505 
1506  return 0;
1507 }
1508 #endif
1509 
1511 {
1513 }
1514 
1515 
1516 
1517 
uint32_t expire
Definition: util-var.h:60
int ConfYamlLoadFileWithPrefix(const char *filename, const char *prefix)
Load configuration from a YAML file, insert in tree at &#39;prefix&#39;.
#define SCLogDebug(...)
Definition: util-debug.h:335
void DetectEnginePruneFreeList(void)
#define TAILQ_FIRST(head)
Definition: queue.h:339
DetectEngineCtx * DetectEngineGetByTenantId(int tenant_id)
#define TAILQ_FOREACH(var, head, field)
Definition: queue.h:350
uint64_t StreamTcpReassembleGetMemcap()
Return memcap value.
struct HtpBodyChunk_ * next
struct PcapCommand_ PcapCommand
size_t strlcpy(char *dst, const char *src, size_t siz)
Definition: util-strlcpyu.c:43
int unix_socket_mode_is_running
Definition: util-var.h:55
uint64_t IPPairGetMemcap(void)
Return memcap value.
Definition: ippair.c:74
int DetectEngineTentantRegisterPcapFile(uint32_t tenant_id)
uint64_t HTPGetMemcap(void)
Update memcap value.
DatasetTypes
Definition: datasets.h:28
void DetectEngineDeReference(DetectEngineCtx **de_ctx)
#define unlikely(expr)
Definition: util-optimize.h:35
uint64_t DefragTrackerGetMemcap(void)
Return memcap value.
Definition: defrag-hash.c:53
int DetectEngineTentantUnregisterVlanId(uint32_t tenant_id, uint16_t vlan_id)
int HTPSetMemcap(uint64_t size)
Update memcap value.
uint64_t HTPMemuseGlobalCounter(void)
int DetectEngineReloadTenantBlocking(uint32_t tenant_id, const char *yaml, int reload_cnt)
Reload a tenant and wait for loading to complete.
uint64_t StreamTcpMemuseCounter(void)
Definition: stream-tcp.c:156
uint64_t IPPairGetMemuse(void)
Return memuse value.
Definition: ippair.c:85
#define TAILQ_HEAD(name, type)
Definition: queue.h:321
int IPPairSetMemcap(uint64_t size)
Update memcap value.
Definition: ippair.c:59
TmEcode TmThreadWaitOnThreadInit(void)
Used to check if all threads have finished their initialization. On finding an un-initialized thread...
Definition: tm-threads.c:2079
void HostBitSet(Host *h, uint32_t idx, uint32_t expire)
Definition: host-bit.c:132
int DetectEngineMultiTenantEnabled(void)
main detection engine ctx
Definition: detect.h:761
int UnixManagerInit(void)
uint32_t VarNameStoreLookupByName(const char *name, const enum VarTypes type)
int ParseSizeStringU64(const char *size, uint64_t *res)
Definition: util-misc.c:203
void PacketPoolPostRunmodes(void)
Set the max_pending_return_packets value.
enum DatasetTypes DatasetGetTypeFromString(const char *s)
Definition: datasets.c:44
#define str(s)
#define UNIX_CMD_TAKE_ARGS
Definition: unix-manager.h:27
char family
Definition: decode.h:111
void TimeGet(struct timeval *tv)
Definition: util-time.c:146
#define TAILQ_INIT(head)
Definition: queue.h:370
void PreRunInit(const int runmode)
Definition: suricata.c:2287
int RunModeUnixSocketIsActive(void)
void RunModeDispatch(int runmode, const char *custom_mode)
Definition: runmodes.c:278
uint8_t type
int DetectEngineMoveToFreeList(DetectEngineCtx *de_ctx)
#define SCLogError(err_code,...)
Macro used to log ERROR messages.
Definition: util-debug.h:294
uint64_t StreamTcpGetMemcap(void)
Return memcap value.
Definition: stream-tcp.c:196
int(* SetFunc)(uint64_t)
int DetectEngineLoadTenantBlocking(uint32_t tenant_id, const char *yaml)
Load a tenant and wait for loading to complete.
int FlowSetMemcap(uint64_t size)
Update memcap value.
Definition: flow.c:98
#define TAILQ_REMOVE(head, elm, field)
Definition: queue.h:412
struct MemcapCommand_ MemcapCommand
uint64_t StreamTcpReassembleMemuseGlobalCounter(void)
int HostSetMemcap(uint64_t size)
Update memcap value.
Definition: host.c:60
int ConfSetFinal(const char *name, const char *val)
Set a final configuration value.
Definition: conf.c:299
const char * RunModeUnixSocketGetDefaultMode(void)
uint64_t(* GetFunc)(void)
void RunModeUnixSocketRegister(void)
#define SCCtrlMutex
json_t * SCJsonString(const char *val)
Definition: output-json.c:107
void TmThreadContinueThreads()
Unpauses all threads present in tv_root.
Definition: tm-threads.c:1995
void UnixManagerThreadSpawn(int mode)
uint64_t SCTimespecAsEpochMillis(const struct timespec *ts)
Definition: util-time.c:615
#define SCReturnInt(x)
Definition: util-debug.h:341
Host * HostGetHostFromHash(Address *a)
Definition: host.c:500
void HostBitUnset(Host *h, uint32_t idx)
Definition: host-bit.c:140
int DetectEngineTentantUnregisterPcapFile(uint32_t tenant_id)
int StreamTcpReassembleSetMemcap(uint64_t size)
Update memcap value.
#define TAILQ_INSERT_TAIL(head, elm, field)
Definition: queue.h:385
Dataset * DatasetFind(const char *name, enum DatasetTypes type)
look for set by name without creating it
Definition: datasets.c:394
int DetectEngineTentantRegisterVlanId(uint32_t tenant_id, uint16_t vlan_id)
uint64_t HostGetMemuse(void)
Return memuse value.
Definition: host.c:86
int DefragTrackerSetMemcap(uint64_t size)
Update memcap value.
Definition: defrag-hash.c:38
#define SCMalloc(a)
Definition: util-mem.h:222
uint32_t idx
Definition: util-var.h:58
#define SCLogInfo(...)
Macro used to log INFORMATIONAL messages.
Definition: util-debug.h:254
#define SCCtrlMutexLock(mut)
#define SCFree(a)
Definition: util-mem.h:322
#define SCLogNotice(...)
Macro used to log NOTICE messages.
Definition: util-debug.h:269
Definition: host.h:58
int StreamTcpSetMemcap(uint64_t size)
Update memcap value.
Definition: stream-tcp.c:181
#define TAILQ_ENTRY(type)
Definition: queue.h:330
uint64_t DefragTrackerGetMemuse(void)
Return memuse value.
Definition: defrag-hash.c:64
uint64_t FlowGetMemuse(void)
Definition: flow.c:119
const char * VarNameStoreLookupById(const uint32_t id, const enum VarTypes type)
void HostUnlock(Host *h)
Definition: host.c:486
void PostRunDeinit(const int runmode, struct timeval *start_time)
Definition: suricata.c:2325
#define SCCtrlMutexUnlock(mut)
int DatasetAddSerialized(Dataset *set, const char *string)
add serialized data to set
Definition: datasets.c:1002
int HostBitList(Host *h, XBit **iter)
Definition: host-bit.c:185
#define SCStrdup(a)
Definition: util-mem.h:268
void RunModeRegisterNewRunMode(enum RunModes runmode, const char *name, const char *description, int(*RunModeFunc)(void))
Registers a new runmode.
Definition: runmodes.c:419
uint64_t FlowGetMemcap(void)
Return memcap value.
Definition: flow.c:113
#define TAILQ_EMPTY(head)
Definition: queue.h:347
TmEcode UnixSocketPcapFile(TmEcode tm, struct timespec *last_processed)
#define SCCtrlMutexInit(mut, mutattr)
Host * HostLookupHostFromHash(Address *a)
look up a host in the hash
Definition: host.c:599
void PreRunPostPrivsDropInit(const int runmode)
Definition: suricata.c:2311
uint64_t HostGetMemcap(void)
Return memcap value.
Definition: host.c:75
int DetectEngineMTApply(void)