From 88888c3d8bc2b791e199073f618557a1fe403106 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 15 Dec 2016 14:49:17 +0100 Subject: [PATCH] unix-socket: add/list/remove hostbit commands add-hostbit adds a named hostbit with an expire time in seconds. remove-hostbit removes hostbit by name. add-hostbit, remove-hostbit return success or failure. list-hostbit returns a json array of hostbits with their name and expire time: { "message": { "count": 1, "hostbits": [{ "expire": 3222, "name": "firefox-users" }] }, "return": "OK" } --- src/runmode-unix-socket.c | 254 ++++++++++++++++++++++++++++++++++++++ src/runmode-unix-socket.h | 3 + src/unix-manager.c | 3 + 3 files changed, 260 insertions(+) diff --git a/src/runmode-unix-socket.c b/src/runmode-unix-socket.c index 092cadaa99..7d9ef8ed26 100644 --- a/src/runmode-unix-socket.c +++ b/src/runmode-unix-socket.c @@ -37,6 +37,7 @@ #include "defrag.h" #include "ippair.h" #include "app-layer.h" +#include "host-bit.h" #include "util-profiling.h" @@ -751,6 +752,259 @@ TmEcode UnixSocketUnregisterTenant(json_t *cmd, json_t* answer, void *data) json_object_set_new(answer, "message", json_string("work in progress")); 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; +} #endif /* BUILD_UNIX_SOCKET */ /** diff --git a/src/runmode-unix-socket.h b/src/runmode-unix-socket.h index 20b0fea496..78ef536265 100644 --- a/src/runmode-unix-socket.h +++ b/src/runmode-unix-socket.h @@ -37,6 +37,9 @@ TmEcode UnixSocketUnregisterTenantHandler(json_t *cmd, json_t* answer, void *dat TmEcode UnixSocketRegisterTenant(json_t *cmd, json_t* answer, void *data); TmEcode UnixSocketReloadTenant(json_t *cmd, json_t* answer, void *data); TmEcode UnixSocketUnregisterTenant(json_t *cmd, json_t* answer, void *data); +TmEcode UnixSocketHostbitAdd(json_t *cmd, json_t* answer, void *data); +TmEcode UnixSocketHostbitRemove(json_t *cmd, json_t* answer, void *data); +TmEcode UnixSocketHostbitList(json_t *cmd, json_t* answer, void *data); #endif #endif /* __RUNMODE_UNIX_SOCKET_H__ */ diff --git a/src/unix-manager.c b/src/unix-manager.c index 559a8b3980..2e8cf5a94a 100644 --- a/src/unix-manager.c +++ b/src/unix-manager.c @@ -932,6 +932,9 @@ static TmEcode UnixManagerThreadInit(ThreadVars *t, void *initdata, void **data) UnixManagerRegisterCommand("register-tenant", UnixSocketRegisterTenant, &command, UNIX_CMD_TAKE_ARGS); UnixManagerRegisterCommand("reload-tenant", UnixSocketReloadTenant, &command, UNIX_CMD_TAKE_ARGS); UnixManagerRegisterCommand("unregister-tenant", UnixSocketUnregisterTenant, &command, UNIX_CMD_TAKE_ARGS); + UnixManagerRegisterCommand("add-hostbit", UnixSocketHostbitAdd, &command, UNIX_CMD_TAKE_ARGS); + UnixManagerRegisterCommand("remove-hostbit", UnixSocketHostbitRemove, &command, UNIX_CMD_TAKE_ARGS); + UnixManagerRegisterCommand("list-hostbit", UnixSocketHostbitList, &command, UNIX_CMD_TAKE_ARGS); *data = utd; return TM_ECODE_OK; -- 2.47.2