]> git.ipfire.org Git - thirdparty/suricata.git/commitdiff
eve/json: Break multiline FTP responses into array
authorJeff Lucovsky <jeff@lucovsky.org>
Tue, 18 Jun 2019 23:06:59 +0000 (19:06 -0400)
committerVictor Julien <victor@inliniac.net>
Wed, 17 Jul 2019 06:21:54 +0000 (08:21 +0200)
This changeset breaks multi-line FTP responses into separate array
entries. Multi-line responses are those with "text-1\r\ntext-2[...]".
Each of \r\n delimited text segments is reported in the `reply` array;
each text segment _may_ include a completion code; completion codes are
reported in the `completion_code` array.

src/output-json-ftp.c

index b8eedf2db7f580d53cba7fd4016a7fc5af69013d..0bf08daed4a1a406e1e5eaf4d67c12f3f989793e 100644 (file)
@@ -37,6 +37,7 @@
 #include "util-unittest.h"
 #include "util-buffer.h"
 #include "util-debug.h"
+#include "util-mem.h"
 #include "util-byte.h"
 
 #include "output.h"
@@ -61,6 +62,31 @@ typedef struct LogFTPLogThread_ {
     MemBuffer          *buffer;
 } LogFTPLogThread;
 
+/*
+ * \brief Returns the ending offset of the next line.
+ *
+ * Here, "next line" is defined as terminating on
+ * - Newline character
+ * - Null character
+ *
+ * \param buffer Contains zero or more characters.
+ * \param len Size, in bytes, of buffer.
+ *
+ * \retval Offset from the start of buffer indicating the where the
+ * next "line ends". The characters between the input buffer and this
+ * value comprise the line.
+ *
+ * NULL is found first or a newline isn't found, then
+ */
+static uint16_t JsonGetNextLineFromBuffer(const char *buffer, const uint16_t len)
+{
+    if (!buffer || *buffer == '\0')
+        return UINT16_MAX;
+
+    char *c = strchr(buffer, '\n');
+    return c == NULL ? len : c - buffer + 1;
+}
+
 static json_t *JsonFTPLogCommand(Flow *f, FTPTransaction *tx)
 {
     json_t *cjs = json_object();
@@ -99,21 +125,29 @@ static json_t *JsonFTPLogCommand(Flow *f, FTPTransaction *tx)
     if (!TAILQ_EMPTY(&tx->response_list)) {
         FTPString *response;
         TAILQ_FOREACH(response, &tx->response_list, next) {
-            int offset = 0;
-            /* Try to find a completion code if we haven't seen one */
-            if (response->len >= 3)  {
-                /* Gather the completion code if present */
-                if (isdigit(response->str[0]) && isdigit(response->str[1]) && isdigit(response->str[2])) {
-                    json_array_append_new(js_respcode_list,
-                                          JsonAddStringN((const char *)response->str , 3));
-                    offset = 4;
+            /* handle multiple lines within the response, \r\n delimited */
+            uint8_t *where = response->str;
+            uint16_t length = response->len;
+            uint16_t pos;
+            while ((pos = JsonGetNextLineFromBuffer((const char *)where, length)) != UINT16_MAX) {
+                uint16_t offset = 0;
+                /* Try to find a completion code for this line */
+                if (pos >= 3)  {
+                    /* Gather the completion code if present */
+                    if (isdigit(where[0]) && isdigit(where[1]) && isdigit(where[2])) {
+                        json_array_append_new(js_respcode_list,
+                                              JsonAddStringN((const char *)where, 3));
+                        offset = 4;
+                    }
                 }
-            }
-            /* move past 3 character completion code */
-            if (response->len >= offset) {
-                json_array_append_new(js_resplist,
-                                      JsonAddStringN((const char *)response->str + offset,
-                                                     response->len - offset));
+                /* move past 3 character completion code */
+                if (pos >= offset) {
+                    json_array_append_new(js_resplist,
+                                          JsonAddStringN((const char *)where + offset, pos - offset));
+                }
+
+                where += pos;
+                length -= pos;
             }
         }
 
@@ -128,11 +162,11 @@ static json_t *JsonFTPLogCommand(Flow *f, FTPTransaction *tx)
     if (tx->command_descriptor->command == FTP_COMMAND_PORT ||
         tx->command_descriptor->command == FTP_COMMAND_EPRT) {
         json_object_set_new(cjs, "mode",
-                json_string((char*)(tx->active ? "active" : "passive")));
+                json_string((char *)(tx->active ? "active" : "passive")));
     }
 
     json_object_set_new(cjs, "reply_received",
-            json_string((char*)(tx->done ? "yes" : "no")));
+            json_string((char *)(tx->done ? "yes" : "no")));
 
     return cjs;
 }