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