]> git.ipfire.org Git - thirdparty/suricata.git/commitdiff
runmode-unix-socket: add commands for memcap handling
authorGiuseppe Longo <glongo@stamus-networks.com>
Mon, 20 Nov 2017 14:19:45 +0000 (15:19 +0100)
committerVictor Julien <victor@inliniac.net>
Tue, 19 Dec 2017 10:43:54 +0000 (11:43 +0100)
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
src/runmode-unix-socket.h
src/unix-manager.c

index 48bbecf625f30491fc552203fed37a09b875e22d..939e0d326027bc85a7c46c860d9085859e876be9 100644 (file)
 #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
index 352cc41373877a58ce1644fc014794a0a5514030..c8a06e06bf26d326fe9d267b4354606d63f99c5c 100644 (file)
@@ -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__ */
index 0fae98a8792d1bad1437450ad8d64a2811bc550e..e401ec57b7f2fb2b969a19c7a82e8707e75838e3 100644 (file)
@@ -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;
 }