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