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;
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 */ /* Gather the completion code if present */
if (isdigit(response->str[0]) && isdigit(response->str[1]) && isdigit(response->str[2])) { if (isdigit(where[0]) && isdigit(where[1]) && isdigit(where[2])) {
json_array_append_new(js_respcode_list, json_array_append_new(js_respcode_list,
JsonAddStringN((const char *)response->str , 3)); JsonAddStringN((const char *)where, 3));
offset = 4; offset = 4;
} }
} }
/* move past 3 character completion code */ /* move past 3 character completion code */
if (response->len >= offset) { if (pos >= offset) {
json_array_append_new(js_resplist, json_array_append_new(js_resplist,
JsonAddStringN((const char *)response->str + offset, JsonAddStringN((const char *)where + offset, pos - offset));
response->len - offset)); }
where += pos;
length -= pos;
} }
} }

Loading…
Cancel
Save