eve/json: Break multiline FTP responses into array

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.
pull/4046/head
Jeff Lucovsky 6 years ago committed by Victor Julien
parent 9cf4e2e432
commit 66c565e9e7

@ -37,6 +37,7 @@
#include "util-unittest.h" #include "util-unittest.h"
#include "util-buffer.h" #include "util-buffer.h"
#include "util-debug.h" #include "util-debug.h"
#include "util-mem.h"
#include "util-byte.h" #include "util-byte.h"
#include "output.h" #include "output.h"
@ -61,6 +62,31 @@ typedef struct LogFTPLogThread_ {
MemBuffer *buffer; MemBuffer *buffer;
} LogFTPLogThread; } 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) static json_t *JsonFTPLogCommand(Flow *f, FTPTransaction *tx)
{ {
json_t *cjs = json_object(); json_t *cjs = json_object();
@ -99,21 +125,29 @@ static json_t *JsonFTPLogCommand(Flow *f, FTPTransaction *tx)
if (!TAILQ_EMPTY(&tx->response_list)) { if (!TAILQ_EMPTY(&tx->response_list)) {
FTPString *response; FTPString *response;
TAILQ_FOREACH(response, &tx->response_list, next) { TAILQ_FOREACH(response, &tx->response_list, next) {
int offset = 0; /* handle multiple lines within the response, \r\n delimited */
/* Try to find a completion code if we haven't seen one */ uint8_t *where = response->str;
if (response->len >= 3) { uint16_t length = response->len;
/* Gather the completion code if present */ uint16_t pos;
if (isdigit(response->str[0]) && isdigit(response->str[1]) && isdigit(response->str[2])) { while ((pos = JsonGetNextLineFromBuffer((const char *)where, length)) != UINT16_MAX) {
json_array_append_new(js_respcode_list, uint16_t offset = 0;
JsonAddStringN((const char *)response->str , 3)); /* Try to find a completion code for this line */
offset = 4; 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 */
/* move past 3 character completion code */ if (pos >= offset) {
if (response->len >= offset) { json_array_append_new(js_resplist,
json_array_append_new(js_resplist, JsonAddStringN((const char *)where + offset, pos - offset));
JsonAddStringN((const char *)response->str + offset, }
response->len - 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 || if (tx->command_descriptor->command == FTP_COMMAND_PORT ||
tx->command_descriptor->command == FTP_COMMAND_EPRT) { tx->command_descriptor->command == FTP_COMMAND_EPRT) {
json_object_set_new(cjs, "mode", 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_object_set_new(cjs, "reply_received",
json_string((char*)(tx->done ? "yes" : "no"))); json_string((char *)(tx->done ? "yes" : "no")));
return cjs; return cjs;
} }

Loading…
Cancel
Save