mirror of https://github.com/OISF/suricata
You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1460 lines
47 KiB
C
1460 lines
47 KiB
C
/* Copyright (C) 2012 Open Information Security Foundation
|
|
*
|
|
* You can copy, redistribute or modify this Program under the terms of
|
|
* the GNU General Public License version 2 as published by the Free
|
|
* Software Foundation.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* version 2 along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
|
* 02110-1301, USA.
|
|
*/
|
|
|
|
#include "suricata-common.h"
|
|
#include "tm-threads.h"
|
|
#include "conf.h"
|
|
#include "runmodes.h"
|
|
#include "runmode-pcap-file.h"
|
|
#include "output.h"
|
|
#include "output-json.h"
|
|
|
|
#include "util-debug.h"
|
|
#include "util-time.h"
|
|
#include "util-cpu.h"
|
|
#include "util-affinity.h"
|
|
#include "unix-manager.h"
|
|
|
|
#include "detect-engine.h"
|
|
|
|
#include "flow-manager.h"
|
|
#include "flow-timeout.h"
|
|
#include "stream-tcp.h"
|
|
#include "stream-tcp-reassemble.h"
|
|
#include "source-pcap-file-directory-helper.h"
|
|
#include "host.h"
|
|
#include "defrag.h"
|
|
#include "defrag-hash.h"
|
|
#include "ippair.h"
|
|
#include "app-layer.h"
|
|
#include "app-layer-htp-mem.h"
|
|
#include "host-bit.h"
|
|
|
|
#include "util-misc.h"
|
|
#include "util-profiling.h"
|
|
|
|
#include "conf-yaml-loader.h"
|
|
|
|
static const char *default_mode = NULL;
|
|
|
|
int unix_socket_mode_is_running = 0;
|
|
|
|
typedef struct PcapFiles_ {
|
|
char *filename;
|
|
char *output_dir;
|
|
int tenant_id;
|
|
time_t delay;
|
|
time_t poll_interval;
|
|
bool continuous;
|
|
bool should_delete;
|
|
TAILQ_ENTRY(PcapFiles_) next;
|
|
} PcapFiles;
|
|
|
|
typedef struct PcapCommand_ {
|
|
TAILQ_HEAD(, PcapFiles_) files;
|
|
int running;
|
|
PcapFiles *current_file;
|
|
} PcapCommand;
|
|
|
|
typedef struct MemcapCommand_ {
|
|
const char *name;
|
|
int (*SetFunc)(uint64_t);
|
|
uint64_t (*GetFunc)(void);
|
|
uint64_t (*GetMemuseFunc)(void);
|
|
} MemcapCommand;
|
|
|
|
const char *RunModeUnixSocketGetDefaultMode(void)
|
|
{
|
|
return default_mode;
|
|
}
|
|
|
|
#ifdef BUILD_UNIX_SOCKET
|
|
|
|
#define MEMCAPS_MAX 7
|
|
static MemcapCommand memcaps[MEMCAPS_MAX] = {
|
|
{
|
|
"stream",
|
|
StreamTcpSetMemcap,
|
|
StreamTcpGetMemcap,
|
|
StreamTcpMemuseCounter,
|
|
},
|
|
{
|
|
"stream-reassembly",
|
|
StreamTcpReassembleSetMemcap,
|
|
StreamTcpReassembleGetMemcap,
|
|
StreamTcpReassembleMemuseGlobalCounter
|
|
},
|
|
{
|
|
"flow",
|
|
FlowSetMemcap,
|
|
FlowGetMemcap,
|
|
FlowGetMemuse
|
|
},
|
|
{
|
|
"applayer-proto-http",
|
|
HTPSetMemcap,
|
|
HTPGetMemcap,
|
|
HTPMemuseGlobalCounter
|
|
},
|
|
{
|
|
"defrag",
|
|
DefragTrackerSetMemcap,
|
|
DefragTrackerGetMemcap,
|
|
DefragTrackerGetMemuse
|
|
},
|
|
{
|
|
"ippair",
|
|
IPPairSetMemcap,
|
|
IPPairGetMemcap,
|
|
IPPairGetMemuse
|
|
},
|
|
{
|
|
"host",
|
|
HostSetMemcap,
|
|
HostGetMemcap,
|
|
HostGetMemuse
|
|
},
|
|
};
|
|
|
|
static int RunModeUnixSocketMaster(void);
|
|
static int unix_manager_pcap_task_running = 0;
|
|
static int unix_manager_pcap_task_failed = 0;
|
|
static int unix_manager_pcap_task_interrupted = 0;
|
|
static struct timespec unix_manager_pcap_last_processed;
|
|
static SCCtrlMutex unix_manager_pcap_last_processed_mutex;
|
|
|
|
/**
|
|
* \brief return list of files in the queue
|
|
*
|
|
* \retval 0 in case of error, 1 in case of success
|
|
*/
|
|
static TmEcode UnixSocketPcapFilesList(json_t *cmd, json_t* answer, void *data)
|
|
{
|
|
PcapCommand *this = (PcapCommand *) data;
|
|
int i = 0;
|
|
PcapFiles *file;
|
|
json_t *jdata;
|
|
json_t *jarray;
|
|
|
|
jdata = json_object();
|
|
if (jdata == NULL) {
|
|
json_object_set_new(answer, "message",
|
|
json_string("internal error at json object creation"));
|
|
return TM_ECODE_FAILED;
|
|
}
|
|
jarray = json_array();
|
|
if (jarray == NULL) {
|
|
json_decref(jdata);
|
|
json_object_set_new(answer, "message",
|
|
json_string("internal error at json object creation"));
|
|
return TM_ECODE_FAILED;
|
|
}
|
|
TAILQ_FOREACH(file, &this->files, next) {
|
|
json_array_append_new(jarray, SCJsonString(file->filename));
|
|
i++;
|
|
}
|
|
json_object_set_new(jdata, "count", json_integer(i));
|
|
json_object_set_new(jdata, "files", jarray);
|
|
json_object_set_new(answer, "message", jdata);
|
|
return TM_ECODE_OK;
|
|
}
|
|
|
|
static TmEcode UnixSocketPcapFilesNumber(json_t *cmd, json_t* answer, void *data)
|
|
{
|
|
PcapCommand *this = (PcapCommand *) data;
|
|
int i = 0;
|
|
PcapFiles *file;
|
|
|
|
TAILQ_FOREACH(file, &this->files, next) {
|
|
i++;
|
|
}
|
|
json_object_set_new(answer, "message", json_integer(i));
|
|
return TM_ECODE_OK;
|
|
}
|
|
|
|
static TmEcode UnixSocketPcapCurrent(json_t *cmd, json_t* answer, void *data)
|
|
{
|
|
PcapCommand *this = (PcapCommand *) data;
|
|
|
|
if (this->current_file != NULL && this->current_file->filename != NULL) {
|
|
json_object_set_new(answer, "message",
|
|
json_string(this->current_file->filename));
|
|
} else {
|
|
json_object_set_new(answer, "message", json_string("None"));
|
|
}
|
|
return TM_ECODE_OK;
|
|
}
|
|
|
|
static TmEcode UnixSocketPcapLastProcessed(json_t *cmd, json_t *answer, void *data)
|
|
{
|
|
json_int_t epoch_millis;
|
|
SCCtrlMutexLock(&unix_manager_pcap_last_processed_mutex);
|
|
epoch_millis = SCTimespecAsEpochMillis(&unix_manager_pcap_last_processed);
|
|
SCCtrlMutexUnlock(&unix_manager_pcap_last_processed_mutex);
|
|
|
|
json_object_set_new(answer, "message",
|
|
json_integer(epoch_millis));
|
|
|
|
return TM_ECODE_OK;
|
|
}
|
|
|
|
static TmEcode UnixSocketPcapInterrupt(json_t *cmd, json_t *answer, void *data)
|
|
{
|
|
unix_manager_pcap_task_interrupted = 1;
|
|
|
|
json_object_set_new(answer, "message", json_string("Interrupted"));
|
|
|
|
return TM_ECODE_OK;
|
|
}
|
|
|
|
static void PcapFilesFree(PcapFiles *cfile)
|
|
{
|
|
if (cfile == NULL)
|
|
return;
|
|
if (cfile->filename)
|
|
SCFree(cfile->filename);
|
|
if (cfile->output_dir)
|
|
SCFree(cfile->output_dir);
|
|
SCFree(cfile);
|
|
}
|
|
|
|
/**
|
|
* \brief Add file to file queue
|
|
*
|
|
* \param this a UnixCommand:: structure
|
|
* \param filename absolute filename
|
|
* \param output_dir absolute name of directory where log will be put
|
|
* \param tenant_id Id of tenant associated with this file
|
|
* \param continuous If file should be run in continuous mode
|
|
* \param delete If file should be deleted when done
|
|
* \param delay Delay required for file modified time before being processed
|
|
* \param poll_interval How frequently directory mode polls for new files
|
|
*
|
|
* \retval 0 in case of error, 1 in case of success
|
|
*/
|
|
static TmEcode 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
|
|
)
|
|
{
|
|
PcapFiles *cfile = NULL;
|
|
if (filename == NULL || this == NULL)
|
|
return TM_ECODE_FAILED;
|
|
cfile = SCMalloc(sizeof(PcapFiles));
|
|
if (unlikely(cfile == NULL)) {
|
|
SCLogError(SC_ERR_MEM_ALLOC, "Unable to allocate new file");
|
|
return TM_ECODE_FAILED;
|
|
}
|
|
memset(cfile, 0, sizeof(PcapFiles));
|
|
|
|
cfile->filename = SCStrdup(filename);
|
|
if (unlikely(cfile->filename == NULL)) {
|
|
SCFree(cfile);
|
|
SCLogError(SC_ERR_MEM_ALLOC, "Unable to dup filename");
|
|
return TM_ECODE_FAILED;
|
|
}
|
|
|
|
if (output_dir) {
|
|
cfile->output_dir = SCStrdup(output_dir);
|
|
if (unlikely(cfile->output_dir == NULL)) {
|
|
SCFree(cfile->filename);
|
|
SCFree(cfile);
|
|
SCLogError(SC_ERR_MEM_ALLOC, "Unable to dup output_dir");
|
|
return TM_ECODE_FAILED;
|
|
}
|
|
}
|
|
|
|
cfile->tenant_id = tenant_id;
|
|
cfile->continuous = continuous;
|
|
cfile->should_delete = should_delete;
|
|
cfile->delay = delay;
|
|
cfile->poll_interval = poll_interval;
|
|
|
|
TAILQ_INSERT_TAIL(&this->files, cfile, next);
|
|
return TM_ECODE_OK;
|
|
}
|
|
|
|
/**
|
|
* \brief Command to add a file to treatment list
|
|
*
|
|
* \param cmd the content of command Arguments as a json_t object
|
|
* \param answer the json_t object that has to be used to answer
|
|
* \param data pointer to data defining the context here a PcapCommand::
|
|
* \param continuous If this should run in continuous mode
|
|
*/
|
|
static TmEcode UnixSocketAddPcapFileImpl(json_t *cmd, json_t* answer, void *data,
|
|
bool continuous)
|
|
{
|
|
PcapCommand *this = (PcapCommand *) data;
|
|
const char *filename;
|
|
const char *output_dir;
|
|
int tenant_id = 0;
|
|
bool should_delete = false;
|
|
time_t delay = 30;
|
|
time_t poll_interval = 5;
|
|
#ifdef OS_WIN32
|
|
struct _stat st;
|
|
#else
|
|
struct stat st;
|
|
#endif /* OS_WIN32 */
|
|
|
|
json_t *jarg = json_object_get(cmd, "filename");
|
|
if (!json_is_string(jarg)) {
|
|
SCLogError(SC_ERR_INVALID_ARGUMENT, "filename is not a string");
|
|
json_object_set_new(answer, "message",
|
|
json_string("filename is not a string"));
|
|
return TM_ECODE_FAILED;
|
|
}
|
|
filename = json_string_value(jarg);
|
|
#ifdef OS_WIN32
|
|
if (_stat(filename, &st) != 0) {
|
|
#else
|
|
if (stat(filename, &st) != 0) {
|
|
#endif /* OS_WIN32 */
|
|
json_object_set_new(answer, "message",
|
|
json_string("filename does not exist"));
|
|
return TM_ECODE_FAILED;
|
|
}
|
|
|
|
json_t *oarg = json_object_get(cmd, "output-dir");
|
|
if (oarg != NULL) {
|
|
if (!json_is_string(oarg)) {
|
|
SCLogError(SC_ERR_INVALID_ARGUMENT, "output-dir is not a string");
|
|
|
|
json_object_set_new(answer, "message",
|
|
json_string("output-dir is not a string"));
|
|
return TM_ECODE_FAILED;
|
|
}
|
|
output_dir = json_string_value(oarg);
|
|
} else {
|
|
SCLogError(SC_ERR_INVALID_ARGUMENT, "can't get output-dir");
|
|
|
|
json_object_set_new(answer, "message",
|
|
json_string("output-dir param is mandatory"));
|
|
return TM_ECODE_FAILED;
|
|
}
|
|
|
|
#ifdef OS_WIN32
|
|
if (_stat(output_dir, &st) != 0) {
|
|
#else
|
|
if (stat(output_dir, &st) != 0) {
|
|
#endif /* OS_WIN32 */
|
|
json_object_set_new(answer, "message",
|
|
json_string("output-dir does not exist"));
|
|
return TM_ECODE_FAILED;
|
|
}
|
|
|
|
json_t *targ = json_object_get(cmd, "tenant");
|
|
if (targ != NULL) {
|
|
if (!json_is_integer(targ)) {
|
|
json_object_set_new(answer, "message",
|
|
json_string("tenant is not a number"));
|
|
return TM_ECODE_FAILED;
|
|
}
|
|
tenant_id = json_number_value(targ);
|
|
}
|
|
|
|
json_t *delete_arg = json_object_get(cmd, "delete-when-done");
|
|
if (delete_arg != NULL) {
|
|
should_delete = json_is_true(delete_arg);
|
|
}
|
|
|
|
json_t *delay_arg = json_object_get(cmd, "delay");
|
|
if (delay_arg != NULL) {
|
|
if (!json_is_integer(delay_arg)) {
|
|
SCLogError(SC_ERR_INVALID_ARGUMENT, "delay is not a integer");
|
|
json_object_set_new(answer, "message",
|
|
json_string("delay is not a integer"));
|
|
return TM_ECODE_FAILED;
|
|
}
|
|
delay = json_integer_value(delay_arg);
|
|
}
|
|
|
|
json_t *interval_arg = json_object_get(cmd, "poll-interval");
|
|
if (interval_arg != NULL) {
|
|
if (!json_is_integer(interval_arg)) {
|
|
SCLogError(SC_ERR_INVALID_ARGUMENT, "poll-interval is not a integer");
|
|
|
|
json_object_set_new(answer, "message",
|
|
json_string("poll-interval is not a integer"));
|
|
return TM_ECODE_FAILED;
|
|
}
|
|
poll_interval = json_integer_value(interval_arg);
|
|
}
|
|
|
|
switch (UnixListAddFile(this, filename, output_dir, tenant_id, continuous,
|
|
should_delete, delay, poll_interval)) {
|
|
case TM_ECODE_FAILED:
|
|
case TM_ECODE_DONE:
|
|
json_object_set_new(answer, "message",
|
|
json_string("Unable to add file to list"));
|
|
return TM_ECODE_FAILED;
|
|
case TM_ECODE_OK:
|
|
SCLogInfo("Added file '%s' to list", filename);
|
|
json_object_set_new(answer, "message",
|
|
json_string("Successfully added file to list"));
|
|
return TM_ECODE_OK;
|
|
}
|
|
return TM_ECODE_OK;
|
|
}
|
|
|
|
/**
|
|
* \brief Command to add a file to treatment list
|
|
*
|
|
* \param cmd the content of command Arguments as a json_t object
|
|
* \param answer the json_t object that has to be used to answer
|
|
* \param data pointer to data defining the context here a PcapCommand::
|
|
*/
|
|
static TmEcode UnixSocketAddPcapFile(json_t *cmd, json_t* answer, void *data)
|
|
{
|
|
bool continuous = false;
|
|
|
|
json_t *cont_arg = json_object_get(cmd, "continuous");
|
|
if (cont_arg != NULL) {
|
|
continuous = json_is_true(cont_arg);
|
|
}
|
|
|
|
return UnixSocketAddPcapFileImpl(cmd, answer, data, continuous);
|
|
}
|
|
|
|
/**
|
|
* \brief Command to add a file to treatment list, forcing continuous mode
|
|
*
|
|
* \param cmd the content of command Arguments as a json_t object
|
|
* \param answer the json_t object that has to be used to answer
|
|
* \param data pointer to data defining the context here a PcapCommand::
|
|
*/
|
|
static TmEcode UnixSocketAddPcapFileContinuous(json_t *cmd, json_t* answer, void *data)
|
|
{
|
|
return UnixSocketAddPcapFileImpl(cmd, answer, data, true);
|
|
}
|
|
|
|
/**
|
|
* \brief Handle the file queue
|
|
*
|
|
* This function check if there is currently a file
|
|
* being parse. If it is not the case, it will start to
|
|
* work on a new file. This implies to start a new 'pcap-file'
|
|
* running mode after having set the file and the output dir.
|
|
* This function also handles the cleaning of the previous
|
|
* running mode.
|
|
*
|
|
* \param this a UnixCommand:: structure
|
|
* \retval 0 in case of error, 1 in case of success
|
|
*/
|
|
static TmEcode UnixSocketPcapFilesCheck(void *data)
|
|
{
|
|
PcapCommand *this = (PcapCommand *) data;
|
|
if (unix_manager_pcap_task_running == 1) {
|
|
return TM_ECODE_OK;
|
|
}
|
|
if ((unix_manager_pcap_task_failed == 1) || (this->running == 1)) {
|
|
if (unix_manager_pcap_task_failed) {
|
|
SCLogInfo("Preceeding task failed, cleaning the running mode");
|
|
}
|
|
unix_manager_pcap_task_failed = 0;
|
|
this->running = 0;
|
|
|
|
SCLogInfo("Resetting engine state");
|
|
PostRunDeinit(RUNMODE_PCAP_FILE, NULL /* no ts */);
|
|
|
|
if (this->current_file) {
|
|
PcapFilesFree(this->current_file);
|
|
}
|
|
this->current_file = NULL;
|
|
}
|
|
|
|
if (TAILQ_EMPTY(&this->files)) {
|
|
// nothing to do
|
|
return TM_ECODE_OK;
|
|
}
|
|
|
|
PcapFiles *cfile = TAILQ_FIRST(&this->files);
|
|
TAILQ_REMOVE(&this->files, cfile, next);
|
|
|
|
unix_manager_pcap_task_running = 1;
|
|
this->running = 1;
|
|
|
|
if (ConfSetFinal("pcap-file.file", cfile->filename) != 1) {
|
|
SCLogError(SC_ERR_INVALID_ARGUMENT, "Can not set working file to '%s'",
|
|
cfile->filename);
|
|
PcapFilesFree(cfile);
|
|
return TM_ECODE_FAILED;
|
|
}
|
|
|
|
int set_res = 0;
|
|
if (cfile->continuous) {
|
|
set_res = ConfSetFinal("pcap-file.continuous", "true");
|
|
} else {
|
|
set_res = ConfSetFinal("pcap-file.continuous", "false");
|
|
}
|
|
if (set_res != 1) {
|
|
SCLogError(SC_ERR_INVALID_ARGUMENT, "Can not set continuous mode for pcap processing");
|
|
PcapFilesFree(cfile);
|
|
return TM_ECODE_FAILED;
|
|
}
|
|
if (cfile->should_delete) {
|
|
set_res = ConfSetFinal("pcap-file.delete-when-done", "true");
|
|
} else {
|
|
set_res = ConfSetFinal("pcap-file.delete-when-done", "false");
|
|
}
|
|
if (set_res != 1) {
|
|
SCLogError(SC_ERR_INVALID_ARGUMENT, "Can not set delete mode for pcap processing");
|
|
PcapFilesFree(cfile);
|
|
return TM_ECODE_FAILED;
|
|
}
|
|
|
|
if (cfile->delay > 0) {
|
|
char tstr[32];
|
|
snprintf(tstr, sizeof(tstr), "%" PRIuMAX, (uintmax_t)cfile->delay);
|
|
if (ConfSetFinal("pcap-file.delay", tstr) != 1) {
|
|
SCLogError(SC_ERR_INVALID_ARGUMENT, "Can not set delay to '%s'", tstr);
|
|
PcapFilesFree(cfile);
|
|
return TM_ECODE_FAILED;
|
|
}
|
|
}
|
|
|
|
if (cfile->poll_interval > 0) {
|
|
char tstr[32];
|
|
snprintf(tstr, sizeof(tstr), "%" PRIuMAX, (uintmax_t)cfile->poll_interval);
|
|
if (ConfSetFinal("pcap-file.poll-interval", tstr) != 1) {
|
|
SCLogError(SC_ERR_INVALID_ARGUMENT,
|
|
"Can not set poll-interval to '%s'", tstr);
|
|
PcapFilesFree(cfile);
|
|
return TM_ECODE_FAILED;
|
|
}
|
|
}
|
|
|
|
if (cfile->tenant_id > 0) {
|
|
char tstr[16];
|
|
snprintf(tstr, sizeof(tstr), "%d", cfile->tenant_id);
|
|
if (ConfSetFinal("pcap-file.tenant-id", tstr) != 1) {
|
|
SCLogError(SC_ERR_INVALID_ARGUMENT,
|
|
"Can not set working tenant-id to '%s'", tstr);
|
|
PcapFilesFree(cfile);
|
|
return TM_ECODE_FAILED;
|
|
}
|
|
} else {
|
|
SCLogInfo("pcap-file.tenant-id not set");
|
|
}
|
|
|
|
if (cfile->output_dir) {
|
|
if (ConfSetFinal("default-log-dir", cfile->output_dir) != 1) {
|
|
SCLogError(SC_ERR_INVALID_ARGUMENT,
|
|
"Can not set output dir to '%s'", cfile->output_dir);
|
|
PcapFilesFree(cfile);
|
|
return TM_ECODE_FAILED;
|
|
}
|
|
}
|
|
|
|
this->current_file = cfile;
|
|
|
|
PreRunInit(RUNMODE_PCAP_FILE);
|
|
PreRunPostPrivsDropInit(RUNMODE_PCAP_FILE);
|
|
RunModeDispatch(RUNMODE_PCAP_FILE, NULL);
|
|
|
|
/* Un-pause all the paused threads */
|
|
TmThreadWaitOnThreadInit();
|
|
TmThreadContinueThreads();
|
|
|
|
SCLogInfo("Starting run for '%s'", this->current_file->filename);
|
|
|
|
return TM_ECODE_OK;
|
|
}
|
|
#endif
|
|
|
|
void RunModeUnixSocketRegister(void)
|
|
{
|
|
#ifdef BUILD_UNIX_SOCKET
|
|
/* a bit of a hack, but register twice to --list-runmodes shows both */
|
|
RunModeRegisterNewRunMode(RUNMODE_UNIX_SOCKET, "single",
|
|
"Unix socket mode",
|
|
RunModeUnixSocketMaster);
|
|
RunModeRegisterNewRunMode(RUNMODE_UNIX_SOCKET, "autofp",
|
|
"Unix socket mode",
|
|
RunModeUnixSocketMaster);
|
|
default_mode = "autofp";
|
|
#endif
|
|
}
|
|
|
|
TmEcode UnixSocketPcapFile(TmEcode tm, struct timespec *last_processed)
|
|
{
|
|
#ifdef BUILD_UNIX_SOCKET
|
|
SCCtrlMutexLock(&unix_manager_pcap_last_processed_mutex);
|
|
unix_manager_pcap_last_processed.tv_sec = last_processed->tv_sec;
|
|
unix_manager_pcap_last_processed.tv_nsec = last_processed->tv_nsec;
|
|
SCCtrlMutexUnlock(&unix_manager_pcap_last_processed_mutex);
|
|
switch (tm) {
|
|
case TM_ECODE_DONE:
|
|
SCLogInfo("Marking current task as done");
|
|
unix_manager_pcap_task_running = 0;
|
|
return TM_ECODE_DONE;
|
|
case TM_ECODE_FAILED:
|
|
SCLogInfo("Marking current task as failed");
|
|
unix_manager_pcap_task_running = 0;
|
|
unix_manager_pcap_task_failed = 1;
|
|
//if we return failed, we can't stop the thread and suricata will fail to close
|
|
return TM_ECODE_DONE;
|
|
case TM_ECODE_OK:
|
|
if (unix_manager_pcap_task_interrupted == 1) {
|
|
SCLogInfo("Interrupting current run mode");
|
|
unix_manager_pcap_task_interrupted = 0;
|
|
return TM_ECODE_DONE;
|
|
} else {
|
|
return TM_ECODE_OK;
|
|
}
|
|
}
|
|
#endif
|
|
return TM_ECODE_FAILED;
|
|
}
|
|
|
|
#ifdef BUILD_UNIX_SOCKET
|
|
/**
|
|
* \brief Command to add a tenant handler
|
|
*
|
|
* \param cmd the content of command Arguments as a json_t object
|
|
* \param answer the json_t object that has to be used to answer
|
|
* \param data pointer to data defining the context here a PcapCommand::
|
|
*/
|
|
TmEcode UnixSocketRegisterTenantHandler(json_t *cmd, json_t* answer, void *data)
|
|
{
|
|
const char *htype;
|
|
json_int_t traffic_id = -1;
|
|
|
|
if (!(DetectEngineMultiTenantEnabled())) {
|
|
SCLogInfo("error: multi-tenant support not enabled");
|
|
json_object_set_new(answer, "message", json_string("multi-tenant support not enabled"));
|
|
return TM_ECODE_FAILED;
|
|
}
|
|
|
|
/* 1 get tenant id */
|
|
json_t *jarg = json_object_get(cmd, "id");
|
|
if (!json_is_integer(jarg)) {
|
|
SCLogInfo("error: command is not a string");
|
|
json_object_set_new(answer, "message", json_string("id is not an integer"));
|
|
return TM_ECODE_FAILED;
|
|
}
|
|
int tenant_id = json_integer_value(jarg);
|
|
|
|
/* 2 get tenant handler type */
|
|
jarg = json_object_get(cmd, "htype");
|
|
if (!json_is_string(jarg)) {
|
|
SCLogInfo("error: command is not a string");
|
|
json_object_set_new(answer, "message", json_string("command is not a string"));
|
|
return TM_ECODE_FAILED;
|
|
}
|
|
htype = json_string_value(jarg);
|
|
|
|
SCLogDebug("add-tenant-handler: %d %s", tenant_id, htype);
|
|
|
|
/* 3 get optional hargs */
|
|
json_t *hargs = json_object_get(cmd, "hargs");
|
|
if (hargs != NULL) {
|
|
if (!json_is_integer(hargs)) {
|
|
SCLogInfo("error: hargs not a number");
|
|
json_object_set_new(answer, "message", json_string("hargs not a number"));
|
|
return TM_ECODE_FAILED;
|
|
}
|
|
traffic_id = json_integer_value(hargs);
|
|
}
|
|
|
|
/* 4 add to system */
|
|
int r = -1;
|
|
if (strcmp(htype, "pcap") == 0) {
|
|
r = DetectEngineTentantRegisterPcapFile(tenant_id);
|
|
} else if (strcmp(htype, "vlan") == 0) {
|
|
if (traffic_id < 0) {
|
|
json_object_set_new(answer, "message", json_string("vlan requires argument"));
|
|
return TM_ECODE_FAILED;
|
|
}
|
|
if (traffic_id > USHRT_MAX) {
|
|
json_object_set_new(answer, "message", json_string("vlan argument out of range"));
|
|
return TM_ECODE_FAILED;
|
|
}
|
|
|
|
SCLogInfo("VLAN handler: id %u maps to tenant %u", (uint32_t)traffic_id, tenant_id);
|
|
r = DetectEngineTentantRegisterVlanId(tenant_id, (uint32_t)traffic_id);
|
|
}
|
|
if (r != 0) {
|
|
json_object_set_new(answer, "message", json_string("handler setup failure"));
|
|
return TM_ECODE_FAILED;
|
|
}
|
|
|
|
if (DetectEngineMTApply() < 0) {
|
|
json_object_set_new(answer, "message", json_string("couldn't apply settings"));
|
|
// TODO cleanup
|
|
return TM_ECODE_FAILED;
|
|
}
|
|
|
|
json_object_set_new(answer, "message", json_string("handler added"));
|
|
return TM_ECODE_OK;
|
|
}
|
|
|
|
/**
|
|
* \brief Command to remove a tenant handler
|
|
*
|
|
* \param cmd the content of command Arguments as a json_t object
|
|
* \param answer the json_t object that has to be used to answer
|
|
* \param data pointer to data defining the context here a PcapCommand::
|
|
*/
|
|
TmEcode UnixSocketUnregisterTenantHandler(json_t *cmd, json_t* answer, void *data)
|
|
{
|
|
const char *htype;
|
|
json_int_t traffic_id = -1;
|
|
|
|
if (!(DetectEngineMultiTenantEnabled())) {
|
|
SCLogInfo("error: multi-tenant support not enabled");
|
|
json_object_set_new(answer, "message", json_string("multi-tenant support not enabled"));
|
|
return TM_ECODE_FAILED;
|
|
}
|
|
|
|
/* 1 get tenant id */
|
|
json_t *jarg = json_object_get(cmd, "id");
|
|
if (!json_is_integer(jarg)) {
|
|
SCLogInfo("error: command is not a string");
|
|
json_object_set_new(answer, "message", json_string("id is not an integer"));
|
|
return TM_ECODE_FAILED;
|
|
}
|
|
int tenant_id = json_integer_value(jarg);
|
|
|
|
/* 2 get tenant handler type */
|
|
jarg = json_object_get(cmd, "htype");
|
|
if (!json_is_string(jarg)) {
|
|
SCLogInfo("error: command is not a string");
|
|
json_object_set_new(answer, "message", json_string("command is not a string"));
|
|
return TM_ECODE_FAILED;
|
|
}
|
|
htype = json_string_value(jarg);
|
|
|
|
SCLogDebug("add-tenant-handler: %d %s", tenant_id, htype);
|
|
|
|
/* 3 get optional hargs */
|
|
json_t *hargs = json_object_get(cmd, "hargs");
|
|
if (hargs != NULL) {
|
|
if (!json_is_integer(hargs)) {
|
|
SCLogInfo("error: hargs not a number");
|
|
json_object_set_new(answer, "message", json_string("hargs not a number"));
|
|
return TM_ECODE_FAILED;
|
|
}
|
|
traffic_id = json_integer_value(hargs);
|
|
}
|
|
|
|
/* 4 add to system */
|
|
int r = -1;
|
|
if (strcmp(htype, "pcap") == 0) {
|
|
r = DetectEngineTentantUnregisterPcapFile(tenant_id);
|
|
} else if (strcmp(htype, "vlan") == 0) {
|
|
if (traffic_id < 0) {
|
|
json_object_set_new(answer, "message", json_string("vlan requires argument"));
|
|
return TM_ECODE_FAILED;
|
|
}
|
|
if (traffic_id > USHRT_MAX) {
|
|
json_object_set_new(answer, "message", json_string("vlan argument out of range"));
|
|
return TM_ECODE_FAILED;
|
|
}
|
|
|
|
SCLogInfo("VLAN handler: removing mapping of %u to tenant %u", (uint32_t)traffic_id, tenant_id);
|
|
r = DetectEngineTentantUnregisterVlanId(tenant_id, (uint32_t)traffic_id);
|
|
}
|
|
if (r != 0) {
|
|
json_object_set_new(answer, "message", json_string("handler unregister failure"));
|
|
return TM_ECODE_FAILED;
|
|
}
|
|
|
|
/* 5 apply it */
|
|
if (DetectEngineMTApply() < 0) {
|
|
json_object_set_new(answer, "message", json_string("couldn't apply settings"));
|
|
// TODO cleanup
|
|
return TM_ECODE_FAILED;
|
|
}
|
|
|
|
json_object_set_new(answer, "message", json_string("handler added"));
|
|
return TM_ECODE_OK;
|
|
}
|
|
|
|
/**
|
|
* \brief Command to add a tenant
|
|
*
|
|
* \param cmd the content of command Arguments as a json_t object
|
|
* \param answer the json_t object that has to be used to answer
|
|
* \param data pointer to data defining the context here a PcapCommand::
|
|
*/
|
|
TmEcode UnixSocketRegisterTenant(json_t *cmd, json_t* answer, void *data)
|
|
{
|
|
const char *filename;
|
|
#ifdef OS_WIN32
|
|
struct _stat st;
|
|
#else
|
|
struct stat st;
|
|
#endif /* OS_WIN32 */
|
|
|
|
if (!(DetectEngineMultiTenantEnabled())) {
|
|
SCLogInfo("error: multi-tenant support not enabled");
|
|
json_object_set_new(answer, "message", json_string("multi-tenant support not enabled"));
|
|
return TM_ECODE_FAILED;
|
|
}
|
|
|
|
/* 1 get tenant id */
|
|
json_t *jarg = json_object_get(cmd, "id");
|
|
if (!json_is_integer(jarg)) {
|
|
json_object_set_new(answer, "message", json_string("id is not an integer"));
|
|
return TM_ECODE_FAILED;
|
|
}
|
|
int tenant_id = json_integer_value(jarg);
|
|
|
|
/* 2 get tenant yaml */
|
|
jarg = json_object_get(cmd, "filename");
|
|
if (!json_is_string(jarg)) {
|
|
json_object_set_new(answer, "message", json_string("command is not a string"));
|
|
return TM_ECODE_FAILED;
|
|
}
|
|
filename = json_string_value(jarg);
|
|
#ifdef OS_WIN32
|
|
if (_stat(filename, &st) != 0) {
|
|
#else
|
|
if (stat(filename, &st) != 0) {
|
|
#endif /* OS_WIN32 */
|
|
json_object_set_new(answer, "message", json_string("file does not exist"));
|
|
return TM_ECODE_FAILED;
|
|
}
|
|
|
|
SCLogDebug("add-tenant: %d %s", tenant_id, filename);
|
|
|
|
/* setup the yaml in this loop so that it's not done by the loader
|
|
* threads. ConfYamlLoadFileWithPrefix is not thread safe. */
|
|
char prefix[64];
|
|
snprintf(prefix, sizeof(prefix), "multi-detect.%d", tenant_id);
|
|
if (ConfYamlLoadFileWithPrefix(filename, prefix) != 0) {
|
|
SCLogError(SC_ERR_CONF_YAML_ERROR, "failed to load yaml %s", filename);
|
|
json_object_set_new(answer, "message", json_string("failed to load yaml"));
|
|
return TM_ECODE_FAILED;
|
|
}
|
|
|
|
/* 3 load into the system */
|
|
if (DetectEngineLoadTenantBlocking(tenant_id, filename) != 0) {
|
|
json_object_set_new(answer, "message", json_string("adding tenant failed"));
|
|
return TM_ECODE_FAILED;
|
|
}
|
|
|
|
/* 4 apply to the running system */
|
|
if (DetectEngineMTApply() < 0) {
|
|
json_object_set_new(answer, "message", json_string("couldn't apply settings"));
|
|
// TODO cleanup
|
|
return TM_ECODE_FAILED;
|
|
}
|
|
|
|
json_object_set_new(answer, "message", json_string("adding tenant succeeded"));
|
|
return TM_ECODE_OK;
|
|
}
|
|
|
|
static int reload_cnt = 1;
|
|
/**
|
|
* \brief Command to reload a tenant
|
|
*
|
|
* \param cmd the content of command Arguments as a json_t object
|
|
* \param answer the json_t object that has to be used to answer
|
|
* \param data pointer to data defining the context here a PcapCommand::
|
|
*/
|
|
TmEcode UnixSocketReloadTenant(json_t *cmd, json_t* answer, void *data)
|
|
{
|
|
const char *filename;
|
|
#ifdef OS_WIN32
|
|
struct _stat st;
|
|
#else
|
|
struct stat st;
|
|
#endif /* OS_WIN32 */
|
|
|
|
if (!(DetectEngineMultiTenantEnabled())) {
|
|
SCLogInfo("error: multi-tenant support not enabled");
|
|
json_object_set_new(answer, "message", json_string("multi-tenant support not enabled"));
|
|
return TM_ECODE_FAILED;
|
|
}
|
|
|
|
/* 1 get tenant id */
|
|
json_t *jarg = json_object_get(cmd, "id");
|
|
if (!json_is_integer(jarg)) {
|
|
json_object_set_new(answer, "message", json_string("id is not an integer"));
|
|
return TM_ECODE_FAILED;
|
|
}
|
|
int tenant_id = json_integer_value(jarg);
|
|
|
|
/* 2 get tenant yaml */
|
|
jarg = json_object_get(cmd, "filename");
|
|
if (!json_is_string(jarg)) {
|
|
json_object_set_new(answer, "message", json_string("command is not a string"));
|
|
return TM_ECODE_FAILED;
|
|
}
|
|
filename = json_string_value(jarg);
|
|
#ifdef OS_WIN32
|
|
if (_stat(filename, &st) != 0) {
|
|
#else
|
|
if (stat(filename, &st) != 0) {
|
|
#endif /* OS_WIN32 */
|
|
json_object_set_new(answer, "message", json_string("file does not exist"));
|
|
return TM_ECODE_FAILED;
|
|
}
|
|
|
|
SCLogDebug("reload-tenant: %d %s", tenant_id, filename);
|
|
|
|
char prefix[64];
|
|
snprintf(prefix, sizeof(prefix), "multi-detect.%d.reload.%d", tenant_id, reload_cnt);
|
|
SCLogInfo("prefix %s", prefix);
|
|
|
|
if (ConfYamlLoadFileWithPrefix(filename, prefix) != 0) {
|
|
json_object_set_new(answer, "message", json_string("failed to load yaml"));
|
|
return TM_ECODE_FAILED;
|
|
}
|
|
|
|
/* 3 load into the system */
|
|
if (DetectEngineReloadTenantBlocking(tenant_id, filename, reload_cnt) != 0) {
|
|
json_object_set_new(answer, "message", json_string("reload tenant failed"));
|
|
return TM_ECODE_FAILED;
|
|
}
|
|
|
|
reload_cnt++;
|
|
|
|
/* apply to the running system */
|
|
if (DetectEngineMTApply() < 0) {
|
|
json_object_set_new(answer, "message", json_string("couldn't apply settings"));
|
|
// TODO cleanup
|
|
return TM_ECODE_FAILED;
|
|
}
|
|
|
|
json_object_set_new(answer, "message", json_string("reloading tenant succeeded"));
|
|
return TM_ECODE_OK;
|
|
}
|
|
|
|
/**
|
|
* \brief Command to remove a tenant
|
|
*
|
|
* \param cmd the content of command Arguments as a json_t object
|
|
* \param answer the json_t object that has to be used to answer
|
|
* \param data pointer to data defining the context here a PcapCommand::
|
|
*/
|
|
TmEcode UnixSocketUnregisterTenant(json_t *cmd, json_t* answer, void *data)
|
|
{
|
|
if (!(DetectEngineMultiTenantEnabled())) {
|
|
SCLogInfo("error: multi-tenant support not enabled");
|
|
json_object_set_new(answer, "message", json_string("multi-tenant support not enabled"));
|
|
return TM_ECODE_FAILED;
|
|
}
|
|
|
|
/* 1 get tenant id */
|
|
json_t *jarg = json_object_get(cmd, "id");
|
|
if (!json_is_integer(jarg)) {
|
|
SCLogInfo("error: command is not a string");
|
|
json_object_set_new(answer, "message", json_string("id is not an integer"));
|
|
return TM_ECODE_FAILED;
|
|
}
|
|
int tenant_id = json_integer_value(jarg);
|
|
|
|
SCLogInfo("remove-tenant: removing tenant %d", tenant_id);
|
|
|
|
/* 2 remove it from the system */
|
|
char prefix[64];
|
|
snprintf(prefix, sizeof(prefix), "multi-detect.%d", tenant_id);
|
|
|
|
DetectEngineCtx *de_ctx = DetectEngineGetByTenantId(tenant_id);
|
|
if (de_ctx == NULL) {
|
|
json_object_set_new(answer, "message", json_string("tenant detect engine not found"));
|
|
return TM_ECODE_FAILED;
|
|
}
|
|
|
|
/* move to free list */
|
|
DetectEngineMoveToFreeList(de_ctx);
|
|
DetectEngineDeReference(&de_ctx);
|
|
|
|
/* update the threads */
|
|
if (DetectEngineMTApply() < 0) {
|
|
json_object_set_new(answer, "message", json_string("couldn't apply settings"));
|
|
// TODO cleanup
|
|
return TM_ECODE_FAILED;
|
|
}
|
|
|
|
/* walk free list, freeing the removed de_ctx */
|
|
DetectEnginePruneFreeList();
|
|
|
|
json_object_set_new(answer, "message", json_string("removing tenant succeeded"));
|
|
return TM_ECODE_OK;
|
|
}
|
|
|
|
/**
|
|
* \brief Command to add a hostbit
|
|
*
|
|
* \param cmd the content of command Arguments as a json_t object
|
|
* \param answer the json_t object that has to be used to answer
|
|
*/
|
|
TmEcode UnixSocketHostbitAdd(json_t *cmd, json_t* answer, void *data_usused)
|
|
{
|
|
/* 1 get ip address */
|
|
json_t *jarg = json_object_get(cmd, "ipaddress");
|
|
if (!json_is_string(jarg)) {
|
|
json_object_set_new(answer, "message", json_string("ipaddress is not an string"));
|
|
return TM_ECODE_FAILED;
|
|
}
|
|
const char *ipaddress = json_string_value(jarg);
|
|
|
|
Address a;
|
|
struct in_addr in;
|
|
memset(&in, 0, sizeof(in));
|
|
if (inet_pton(AF_INET, ipaddress, &in) != 1) {
|
|
uint32_t in6[4];
|
|
memset(&in6, 0, sizeof(in6));
|
|
if (inet_pton(AF_INET6, ipaddress, &in) != 1) {
|
|
json_object_set_new(answer, "message", json_string("invalid address string"));
|
|
return TM_ECODE_FAILED;
|
|
} else {
|
|
a.family = AF_INET6;
|
|
a.addr_data32[0] = in6[0];
|
|
a.addr_data32[1] = in6[1];
|
|
a.addr_data32[2] = in6[2];
|
|
a.addr_data32[3] = in6[3];
|
|
}
|
|
} else {
|
|
a.family = AF_INET;
|
|
a.addr_data32[0] = in.s_addr;
|
|
a.addr_data32[1] = 0;
|
|
a.addr_data32[2] = 0;
|
|
a.addr_data32[3] = 0;
|
|
}
|
|
|
|
/* 2 get variable name */
|
|
jarg = json_object_get(cmd, "hostbit");
|
|
if (!json_is_string(jarg)) {
|
|
json_object_set_new(answer, "message", json_string("hostbit is not a string"));
|
|
return TM_ECODE_FAILED;
|
|
}
|
|
const char *hostbit = json_string_value(jarg);
|
|
uint32_t idx = VarNameStoreLookupByName(hostbit, VAR_TYPE_HOST_BIT);
|
|
if (idx == 0) {
|
|
json_object_set_new(answer, "message", json_string("hostbit not found"));
|
|
return TM_ECODE_FAILED;
|
|
}
|
|
|
|
/* 3 get expire */
|
|
jarg = json_object_get(cmd, "expire");
|
|
if (!json_is_integer(jarg)) {
|
|
json_object_set_new(answer, "message", json_string("expire is not an integer"));
|
|
return TM_ECODE_FAILED;
|
|
}
|
|
uint32_t expire = json_integer_value(jarg);
|
|
|
|
SCLogInfo("add-hostbit: ip %s hostbit %s expire %us", ipaddress, hostbit, expire);
|
|
|
|
struct timeval current_time;
|
|
TimeGet(¤t_time);
|
|
Host *host = HostGetHostFromHash(&a);
|
|
if (host) {
|
|
HostBitSet(host, idx, current_time.tv_sec + expire);
|
|
HostUnlock(host);
|
|
|
|
json_object_set_new(answer, "message", json_string("hostbit added"));
|
|
return TM_ECODE_OK;
|
|
} else {
|
|
json_object_set_new(answer, "message", json_string("couldn't create host"));
|
|
return TM_ECODE_FAILED;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* \brief Command to remove a hostbit
|
|
*
|
|
* \param cmd the content of command Arguments as a json_t object
|
|
* \param answer the json_t object that has to be used to answer
|
|
*/
|
|
TmEcode UnixSocketHostbitRemove(json_t *cmd, json_t* answer, void *data_unused)
|
|
{
|
|
/* 1 get ip address */
|
|
json_t *jarg = json_object_get(cmd, "ipaddress");
|
|
if (!json_is_string(jarg)) {
|
|
json_object_set_new(answer, "message", json_string("ipaddress is not an string"));
|
|
return TM_ECODE_FAILED;
|
|
}
|
|
const char *ipaddress = json_string_value(jarg);
|
|
|
|
Address a;
|
|
struct in_addr in;
|
|
memset(&in, 0, sizeof(in));
|
|
if (inet_pton(AF_INET, ipaddress, &in) != 1) {
|
|
uint32_t in6[4];
|
|
memset(&in6, 0, sizeof(in6));
|
|
if (inet_pton(AF_INET6, ipaddress, &in) != 1) {
|
|
json_object_set_new(answer, "message", json_string("invalid address string"));
|
|
return TM_ECODE_FAILED;
|
|
} else {
|
|
a.family = AF_INET6;
|
|
a.addr_data32[0] = in6[0];
|
|
a.addr_data32[1] = in6[1];
|
|
a.addr_data32[2] = in6[2];
|
|
a.addr_data32[3] = in6[3];
|
|
}
|
|
} else {
|
|
a.family = AF_INET;
|
|
a.addr_data32[0] = in.s_addr;
|
|
a.addr_data32[1] = 0;
|
|
a.addr_data32[2] = 0;
|
|
a.addr_data32[3] = 0;
|
|
}
|
|
|
|
/* 2 get variable name */
|
|
jarg = json_object_get(cmd, "hostbit");
|
|
if (!json_is_string(jarg)) {
|
|
json_object_set_new(answer, "message", json_string("hostbit is not a string"));
|
|
return TM_ECODE_FAILED;
|
|
}
|
|
|
|
const char *hostbit = json_string_value(jarg);
|
|
uint32_t idx = VarNameStoreLookupByName(hostbit, VAR_TYPE_HOST_BIT);
|
|
if (idx == 0) {
|
|
json_object_set_new(answer, "message", json_string("hostbit not found"));
|
|
return TM_ECODE_FAILED;
|
|
}
|
|
|
|
SCLogInfo("remove-hostbit: %s %s", ipaddress, hostbit);
|
|
|
|
Host *host = HostLookupHostFromHash(&a);
|
|
if (host) {
|
|
HostBitUnset(host, idx);
|
|
HostUnlock(host);
|
|
json_object_set_new(answer, "message", json_string("hostbit removed"));
|
|
return TM_ECODE_OK;
|
|
} else {
|
|
json_object_set_new(answer, "message", json_string("host not found"));
|
|
return TM_ECODE_FAILED;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* \brief Command to list hostbits for an ip
|
|
*
|
|
* \param cmd the content of command Arguments as a json_t object
|
|
* \param answer the json_t object that has to be used to answer
|
|
*
|
|
* Message looks like:
|
|
* {"message": {"count": 1, "hostbits": [{"expire": 3222, "name": "firefox-users"}]}, "return": "OK"}
|
|
*
|
|
* \retval r TM_ECODE_OK or TM_ECODE_FAILED
|
|
*/
|
|
TmEcode UnixSocketHostbitList(json_t *cmd, json_t* answer, void *data_unused)
|
|
{
|
|
/* 1 get ip address */
|
|
json_t *jarg = json_object_get(cmd, "ipaddress");
|
|
if (!json_is_string(jarg)) {
|
|
json_object_set_new(answer, "message", json_string("ipaddress is not an string"));
|
|
return TM_ECODE_FAILED;
|
|
}
|
|
const char *ipaddress = json_string_value(jarg);
|
|
|
|
Address a;
|
|
struct in_addr in;
|
|
memset(&in, 0, sizeof(in));
|
|
if (inet_pton(AF_INET, ipaddress, &in) != 1) {
|
|
uint32_t in6[4];
|
|
memset(&in6, 0, sizeof(in6));
|
|
if (inet_pton(AF_INET6, ipaddress, &in) != 1) {
|
|
json_object_set_new(answer, "message", json_string("invalid address string"));
|
|
return TM_ECODE_FAILED;
|
|
} else {
|
|
a.family = AF_INET6;
|
|
a.addr_data32[0] = in6[0];
|
|
a.addr_data32[1] = in6[1];
|
|
a.addr_data32[2] = in6[2];
|
|
a.addr_data32[3] = in6[3];
|
|
}
|
|
} else {
|
|
a.family = AF_INET;
|
|
a.addr_data32[0] = in.s_addr;
|
|
a.addr_data32[1] = 0;
|
|
a.addr_data32[2] = 0;
|
|
a.addr_data32[3] = 0;
|
|
}
|
|
|
|
SCLogInfo("list-hostbit: %s", ipaddress);
|
|
|
|
struct timeval ts;
|
|
memset(&ts, 0, sizeof(ts));
|
|
TimeGet(&ts);
|
|
|
|
struct Bit {
|
|
uint32_t id;
|
|
uint32_t expire;
|
|
} bits[256];
|
|
memset(&bits, 0, sizeof(bits));
|
|
int i = 0, use = 0;
|
|
|
|
Host *host = HostLookupHostFromHash(&a);
|
|
if (!host) {
|
|
json_object_set_new(answer, "message", json_string("host not found"));
|
|
return TM_ECODE_FAILED;
|
|
}
|
|
|
|
XBit *iter = NULL;
|
|
while (use < 256 && HostBitList(host, &iter) == 1) {
|
|
bits[use].id = iter->idx;
|
|
bits[use].expire = iter->expire;
|
|
use++;
|
|
}
|
|
HostUnlock(host);
|
|
|
|
json_t *jdata = json_object();
|
|
json_t *jarray = json_array();
|
|
if (jarray == NULL || jdata == NULL) {
|
|
if (jdata != NULL)
|
|
json_decref(jdata);
|
|
if (jarray != NULL)
|
|
json_decref(jarray);
|
|
json_object_set_new(answer, "message",
|
|
json_string("internal error at json object creation"));
|
|
return TM_ECODE_FAILED;
|
|
}
|
|
|
|
for (i = 0; i < use; i++) {
|
|
json_t *bitobject = json_object();
|
|
if (bitobject == NULL)
|
|
continue;
|
|
uint32_t expire = 0;
|
|
if ((uint32_t)ts.tv_sec < bits[i].expire)
|
|
expire = bits[i].expire - (uint32_t)ts.tv_sec;
|
|
|
|
const char *name = VarNameStoreLookupById(bits[i].id, VAR_TYPE_HOST_BIT);
|
|
if (name == NULL)
|
|
continue;
|
|
json_object_set_new(bitobject, "name", json_string(name));
|
|
SCLogDebug("xbit %s expire %u", name, expire);
|
|
json_object_set_new(bitobject, "expire", json_integer(expire));
|
|
json_array_append_new(jarray, bitobject);
|
|
}
|
|
|
|
json_object_set_new(jdata, "count", json_integer(i));
|
|
json_object_set_new(jdata, "hostbits", jarray);
|
|
json_object_set_new(answer, "message", jdata);
|
|
return TM_ECODE_OK;
|
|
}
|
|
|
|
static void MemcapBuildValue(uint64_t val, char *str, uint32_t str_len)
|
|
{
|
|
if ((val / (1024 * 1024 * 1024)) != 0) {
|
|
snprintf(str, str_len, "%"PRIu64"gb", val / (1024*1024*1024));
|
|
} else if ((val / (1024 * 1024)) != 0) {
|
|
snprintf(str, str_len, "%"PRIu64"mb", val / (1024*1024));
|
|
} else {
|
|
snprintf(str, str_len, "%"PRIu64"kb", val / (1024));
|
|
}
|
|
}
|
|
|
|
TmEcode UnixSocketSetMemcap(json_t *cmd, json_t* answer, void *data)
|
|
{
|
|
char *memcap = NULL;
|
|
char *value_str = NULL;
|
|
uint64_t value;
|
|
int i;
|
|
|
|
json_t *jarg = json_object_get(cmd, "config");
|
|
if (!json_is_string(jarg)) {
|
|
json_object_set_new(answer, "message", json_string("memcap key is not a string"));
|
|
return TM_ECODE_FAILED;
|
|
}
|
|
memcap = (char *)json_string_value(jarg);
|
|
|
|
jarg = json_object_get(cmd, "memcap");
|
|
if (!json_is_string(jarg)) {
|
|
json_object_set_new(answer, "message", json_string("memcap value is not a string"));
|
|
return TM_ECODE_FAILED;
|
|
}
|
|
value_str = (char *)json_string_value(jarg);
|
|
|
|
if (ParseSizeStringU64(value_str, &value) < 0) {
|
|
SCLogError(SC_ERR_SIZE_PARSE, "Error parsing "
|
|
"memcap from unix socket: %s", value_str);
|
|
json_object_set_new(answer, "message",
|
|
json_string("error parsing memcap specified, "
|
|
"value not changed"));
|
|
return TM_ECODE_FAILED;
|
|
}
|
|
|
|
for (i = 0; i < MEMCAPS_MAX; i++) {
|
|
if (strcmp(memcaps[i].name, memcap) == 0 && memcaps[i].SetFunc) {
|
|
int updated = memcaps[i].SetFunc(value);
|
|
char message[150];
|
|
|
|
if (updated) {
|
|
snprintf(message, sizeof(message),
|
|
"memcap value for '%s' updated: %"PRIu64" %s",
|
|
memcaps[i].name, value,
|
|
(value == 0) ? "(unlimited)" : "");
|
|
json_object_set_new(answer, "message", json_string(message));
|
|
return TM_ECODE_OK;
|
|
} else {
|
|
if (value == 0) {
|
|
snprintf(message, sizeof(message),
|
|
"Unlimited value is not allowed for '%s'", memcaps[i].name);
|
|
} else {
|
|
if (memcaps[i].GetMemuseFunc()) {
|
|
char memuse[50];
|
|
MemcapBuildValue(memcaps[i].GetMemuseFunc(), memuse, sizeof(memuse));
|
|
snprintf(message, sizeof(message),
|
|
"memcap value specified for '%s' is less than the memory in use: %s",
|
|
memcaps[i].name, memuse);
|
|
} else {
|
|
snprintf(message, sizeof(message),
|
|
"memcap value specified for '%s' is less than the memory in use",
|
|
memcaps[i].name);
|
|
}
|
|
}
|
|
json_object_set_new(answer, "message", json_string(message));
|
|
return TM_ECODE_FAILED;
|
|
}
|
|
}
|
|
}
|
|
|
|
json_object_set_new(answer, "message",
|
|
json_string("Memcap value not found. Use 'memcap-list' to show all"));
|
|
return TM_ECODE_FAILED;
|
|
}
|
|
|
|
TmEcode UnixSocketShowMemcap(json_t *cmd, json_t *answer, void *data)
|
|
{
|
|
char *memcap = NULL;
|
|
int i;
|
|
|
|
json_t *jarg = json_object_get(cmd, "config");
|
|
if (!json_is_string(jarg)) {
|
|
json_object_set_new(answer, "message", json_string("memcap name is not a string"));
|
|
return TM_ECODE_FAILED;
|
|
}
|
|
memcap = (char *)json_string_value(jarg);
|
|
|
|
for (i = 0; i < MEMCAPS_MAX; i++) {
|
|
if (strcmp(memcaps[i].name, memcap) == 0 && memcaps[i].GetFunc) {
|
|
char str[50];
|
|
uint64_t val = memcaps[i].GetFunc();
|
|
json_t *jobj = json_object();
|
|
if (jobj == NULL) {
|
|
json_object_set_new(answer, "message",
|
|
json_string("internal error at json object creation"));
|
|
return TM_ECODE_FAILED;
|
|
}
|
|
|
|
if (val == 0) {
|
|
strlcpy(str, "unlimited", sizeof(str));
|
|
} else {
|
|
MemcapBuildValue(val, str, sizeof(str));
|
|
}
|
|
|
|
json_object_set_new(jobj, "value", json_string(str));
|
|
json_object_set_new(answer, "message", jobj);
|
|
return TM_ECODE_OK;
|
|
}
|
|
}
|
|
|
|
json_object_set_new(answer, "message",
|
|
json_string("Memcap value not found. Use 'memcap-list' to show all"));
|
|
return TM_ECODE_FAILED;
|
|
}
|
|
|
|
TmEcode UnixSocketShowAllMemcap(json_t *cmd, json_t *answer, void *data)
|
|
{
|
|
json_t *jmemcaps = json_array();
|
|
int i;
|
|
|
|
if (jmemcaps == NULL) {
|
|
json_object_set_new(answer, "message",
|
|
json_string("internal error at json array creation"));
|
|
return TM_ECODE_FAILED;
|
|
}
|
|
|
|
for (i = 0; i < MEMCAPS_MAX; i++) {
|
|
json_t *jobj = json_object();
|
|
if (jobj == NULL) {
|
|
json_decref(jmemcaps);
|
|
json_object_set_new(answer, "message",
|
|
json_string("internal error at json object creation"));
|
|
return TM_ECODE_FAILED;
|
|
}
|
|
char str[50];
|
|
uint64_t val = memcaps[i].GetFunc();
|
|
|
|
if (val == 0) {
|
|
strlcpy(str, "unlimited", sizeof(str));
|
|
} else {
|
|
MemcapBuildValue(val, str, sizeof(str));
|
|
}
|
|
|
|
json_object_set_new(jobj, "name", json_string(memcaps[i].name));
|
|
json_object_set_new(jobj, "value", json_string(str));
|
|
json_array_append_new(jmemcaps, jobj);
|
|
}
|
|
|
|
json_object_set_new(answer, "message", jmemcaps);
|
|
SCReturnInt(TM_ECODE_OK);
|
|
}
|
|
#endif /* BUILD_UNIX_SOCKET */
|
|
|
|
#ifdef BUILD_UNIX_SOCKET
|
|
/**
|
|
* \brief Single thread version of the Pcap file processing.
|
|
*/
|
|
static int RunModeUnixSocketMaster(void)
|
|
{
|
|
if (UnixManagerInit() != 0)
|
|
return 1;
|
|
|
|
PcapCommand *pcapcmd = SCMalloc(sizeof(PcapCommand));
|
|
if (unlikely(pcapcmd == NULL)) {
|
|
SCLogError(SC_ERR_MEM_ALLOC, "Can not allocate pcap command");
|
|
return 1;
|
|
}
|
|
TAILQ_INIT(&pcapcmd->files);
|
|
pcapcmd->running = 0;
|
|
pcapcmd->current_file = NULL;
|
|
|
|
memset(&unix_manager_pcap_last_processed, 0, sizeof(struct timespec));
|
|
|
|
SCCtrlMutexInit(&unix_manager_pcap_last_processed_mutex, NULL);
|
|
|
|
UnixManagerRegisterCommand("pcap-file", UnixSocketAddPcapFile, pcapcmd, UNIX_CMD_TAKE_ARGS);
|
|
UnixManagerRegisterCommand("pcap-file-continuous", UnixSocketAddPcapFileContinuous, pcapcmd, UNIX_CMD_TAKE_ARGS);
|
|
UnixManagerRegisterCommand("pcap-file-number", UnixSocketPcapFilesNumber, pcapcmd, 0);
|
|
UnixManagerRegisterCommand("pcap-file-list", UnixSocketPcapFilesList, pcapcmd, 0);
|
|
UnixManagerRegisterCommand("pcap-last-processed", UnixSocketPcapLastProcessed, pcapcmd, 0);
|
|
UnixManagerRegisterCommand("pcap-interrupt", UnixSocketPcapInterrupt, pcapcmd, 0);
|
|
UnixManagerRegisterCommand("pcap-current", UnixSocketPcapCurrent, pcapcmd, 0);
|
|
|
|
UnixManagerRegisterBackgroundTask(UnixSocketPcapFilesCheck, pcapcmd);
|
|
|
|
UnixManagerThreadSpawn(1);
|
|
unix_socket_mode_is_running = 1;
|
|
|
|
return 0;
|
|
}
|
|
#endif
|
|
|
|
int RunModeUnixSocketIsActive(void)
|
|
{
|
|
return unix_socket_mode_is_running;
|
|
}
|
|
|
|
|
|
|
|
|