From 3668ea25224a2a7a50c2694e500fae74205b7a87 Mon Sep 17 00:00:00 2001 From: Giuseppe Longo Date: Mon, 20 Nov 2017 15:19:45 +0100 Subject: [PATCH] runmode-unix-socket: add commands for memcap handling This permits to handle memcap values through unix socket for: - stream - stream-reassembly - flow - applayer-proto-http - defrag - ippair - host It will be possible to show or change a memcap value for a specified configuration and list all memcap values available. The following commands are registered for unix-socket: - memcap-set - memcap-show - memcap-list Output: >>> memcap-show flow Success: { "value": "64mb" } >>> memcap-set flow 64mb Success: "memcap value for 'flow' updated: 67108864" Command with invalid memcap key: >>> memcap-set udp 32mb Error: "Available config: stream stream-reassembly flow applayer-proto-http defrag ippair host" Command with an invalid memcap value: >>> memcap-set http 32mmb Error: "error parsing memcap specified, value not changed" --- src/runmode-unix-socket.c | 215 ++++++++++++++++++++++++++++++++++++++ src/runmode-unix-socket.h | 3 + src/unix-manager.c | 4 +- 3 files changed, 221 insertions(+), 1 deletion(-) diff --git a/src/runmode-unix-socket.c b/src/runmode-unix-socket.c index 48bbecf625..939e0d3260 100644 --- a/src/runmode-unix-socket.c +++ b/src/runmode-unix-socket.c @@ -33,12 +33,16 @@ #include "flow-manager.h" #include "flow-timeout.h" #include "stream-tcp.h" +#include "stream-tcp-reassemble.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" @@ -63,6 +67,13 @@ typedef struct PcapCommand_ { 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; @@ -70,6 +81,52 @@ const char *RunModeUnixSocketGetDefaultMode(void) #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; @@ -1136,6 +1193,164 @@ TmEcode UnixSocketHostbitList(json_t *cmd, json_t* answer, void *data_unused) 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 diff --git a/src/runmode-unix-socket.h b/src/runmode-unix-socket.h index 352cc41373..c8a06e06bf 100644 --- a/src/runmode-unix-socket.h +++ b/src/runmode-unix-socket.h @@ -39,6 +39,9 @@ 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); +TmEcode UnixSocketSetMemcap(json_t *cmd, json_t* answer, void *data); +TmEcode UnixSocketShowMemcap(json_t *cmd, json_t *answer, void *data); +TmEcode UnixSocketShowAllMemcap(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 0fae98a879..e401ec57b7 100644 --- a/src/unix-manager.c +++ b/src/unix-manager.c @@ -839,7 +839,6 @@ static TmEcode UnixManagerListCommand(json_t *cmd, SCReturnInt(TM_ECODE_OK); } - static TmEcode UnixManagerReopenLogFiles(json_t *cmd, json_t *server_msg, void *data) { OutputNotifyFileRotation(); @@ -1007,6 +1006,9 @@ int UnixManagerInit(void) UnixManagerRegisterCommand("remove-hostbit", UnixSocketHostbitRemove, &command, UNIX_CMD_TAKE_ARGS); UnixManagerRegisterCommand("list-hostbit", UnixSocketHostbitList, &command, UNIX_CMD_TAKE_ARGS); UnixManagerRegisterCommand("reopen-log-files", UnixManagerReopenLogFiles, NULL, 0); + UnixManagerRegisterCommand("memcap-set", UnixSocketSetMemcap, &command, UNIX_CMD_TAKE_ARGS); + UnixManagerRegisterCommand("memcap-show", UnixSocketShowMemcap, &command, UNIX_CMD_TAKE_ARGS); + UnixManagerRegisterCommand("memcap-list", UnixSocketShowAllMemcap, NULL, 0); return 0; }