New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
ftp/eve: Convert to JsonBuilder #5030
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -60,41 +60,35 @@ typedef struct LogFTPLogThread_ { | |
MemBuffer *buffer; | ||
} LogFTPLogThread; | ||
|
||
static json_t *JsonFTPLogCommand(Flow *f, FTPTransaction *tx) | ||
static void JsonFTPLogCommand(Flow *f, FTPTransaction *tx, JsonBuilder *jb) | ||
{ | ||
json_t *cjs = json_object(); | ||
if (!cjs) { | ||
return cjs; | ||
} | ||
|
||
/* Preallocate array objects to simplify failure case */ | ||
json_t *js_resplist = NULL; | ||
json_t *js_respcode_list = NULL; | ||
JsonBuilder *js_resplist = NULL; | ||
JsonBuilder *js_respcode_list = NULL; | ||
if (!TAILQ_EMPTY(&tx->response_list)) { | ||
js_resplist = json_array(); | ||
js_respcode_list = json_array(); | ||
js_resplist = jb_new_array(); | ||
js_respcode_list = jb_new_array(); | ||
|
||
if (unlikely(js_resplist == NULL || js_respcode_list == NULL)) { | ||
if (js_resplist) { | ||
json_decref(js_resplist); | ||
} else { | ||
json_decref(js_respcode_list); | ||
} | ||
return cjs; | ||
goto fail; | ||
} | ||
} | ||
|
||
json_object_set_new(cjs, "command", json_string(tx->command_descriptor->command_name)); | ||
jb_set_string(jb, "command", tx->command_descriptor->command_name); | ||
uint32_t min_length = tx->command_descriptor->command_length + 1; /* command + space */ | ||
if (tx->request_length > min_length) { | ||
json_object_set_new(cjs, "command_data", | ||
JsonAddStringN((const char *)tx->request + min_length, | ||
tx->request_length - min_length)); | ||
char *s = BytesToString(tx->request + min_length, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @jasonish iirc we talked about a direct There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I see An interface that accepted a count and worked with a non-null-terminated string would be needed. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
tx->request_length - min_length - 1); | ||
if (s) { | ||
jb_set_string(jb, "command_data", s); | ||
SCFree(s); | ||
} | ||
} else { | ||
json_object_set_new(cjs, "command_data", json_string(NULL)); | ||
jb_set_string(jb, "command_data", NULL); | ||
} | ||
|
||
if (!TAILQ_EMPTY(&tx->response_list)) { | ||
int resp_code_cnt = 0; | ||
int resp_cnt = 0; | ||
FTPString *response; | ||
TAILQ_FOREACH(response, &tx->response_list, next) { | ||
/* handle multiple lines within the response, \r\n delimited */ | ||
|
@@ -107,40 +101,61 @@ static json_t *JsonFTPLogCommand(Flow *f, FTPTransaction *tx) | |
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)); | ||
char *s = BytesToString(where, 3); | ||
if (s != NULL) { | ||
jb_append_string(js_respcode_list, s); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. the goal of the jsonbuilder transition is to avoid creating temporary objects like this, but instead "stream" the whole object into a single There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I modeled my implementation after that in Note that I'm building 2 arrays as the response is processed and 2 arrays will be created during that. I'm not sure how the new interfaces support this? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There isn't in some cases. In DNS, to avoid looping throught the responses 2x, I had to use intermediate objects as well in |
||
SCFree(s); | ||
resp_code_cnt++; | ||
} | ||
offset = 4; | ||
} | ||
} | ||
/* move past 3 character completion code */ | ||
if (pos >= offset) { | ||
json_array_append_new(js_resplist, | ||
JsonAddStringN((const char *)where + offset, pos - offset)); | ||
char *s = BytesToString(where + offset, pos - offset); | ||
if (s != NULL) { | ||
jb_append_string(js_resplist, s); | ||
SCFree(s); | ||
resp_cnt++; | ||
} | ||
} | ||
|
||
where += pos; | ||
length -= pos; | ||
} | ||
} | ||
|
||
json_object_set_new(cjs, "reply", js_resplist); | ||
json_object_set_new(cjs, "completion_code", js_respcode_list); | ||
if (resp_cnt) { | ||
jb_close(js_resplist); | ||
jb_set_object(jb, "reply", js_resplist); | ||
} | ||
jb_free(js_resplist); | ||
if (resp_code_cnt) { | ||
jb_close(js_respcode_list); | ||
jb_set_object(jb, "completion_code", js_respcode_list); | ||
} | ||
jb_free(js_respcode_list); | ||
} | ||
|
||
if (tx->dyn_port) { | ||
json_object_set_new(cjs, "dynamic_port", json_integer(tx->dyn_port)); | ||
jb_set_uint(jb, "dynamic_port", tx->dyn_port); | ||
} | ||
|
||
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"))); | ||
jb_set_string(jb, "mode", tx->active ? "active" : "passive"); | ||
} | ||
|
||
json_object_set_new(cjs, "reply_received", | ||
json_string((char *)(tx->done ? "yes" : "no"))); | ||
jb_set_string(jb, "reply_received", tx->done ? "yes" : "no"); | ||
|
||
return; | ||
|
||
return cjs; | ||
fail: | ||
if (js_resplist) { | ||
jb_free(js_resplist); | ||
} else { | ||
jb_free(js_respcode_list); | ||
} | ||
} | ||
|
||
|
||
|
@@ -159,27 +174,30 @@ static int JsonFTPLogger(ThreadVars *tv, void *thread_data, | |
LogFTPLogThread *thread = thread_data; | ||
LogFTPFileCtx *ftp_ctx = thread->ftplog_ctx; | ||
|
||
json_t *js = CreateJSONHeaderWithTxId(p, LOG_DIR_FLOW, event_type, tx_id); | ||
if (likely(js)) { | ||
JsonAddCommonOptions(&ftp_ctx->cfg, p, f, js); | ||
json_t *cjs = NULL; | ||
JsonBuilder *jb = CreateEveHeaderWithTxId(p, LOG_DIR_FLOW, event_type, NULL, tx_id); | ||
if (likely(jb)) { | ||
EveAddCommonOptions(&ftp_ctx->cfg, p, f, jb); | ||
jb_open_object(jb, event_type); | ||
if (f->alproto == ALPROTO_FTPDATA) { | ||
cjs = JsonFTPDataAddMetadata(f); | ||
JsonFTPDataAddMetadata(f, jb); | ||
} else { | ||
cjs = JsonFTPLogCommand(f, tx); | ||
JsonFTPLogCommand(f, tx, jb); | ||
} | ||
|
||
if (cjs) { | ||
json_object_set_new(js, event_type, cjs); | ||
if (!jb_close(jb)) { | ||
goto fail; | ||
} | ||
|
||
MemBufferReset(thread->buffer); | ||
OutputJSONBuffer(js, thread->ftplog_ctx->file_ctx, &thread->buffer); | ||
OutputJsonBuilderBuffer(jb, thread->ftplog_ctx->file_ctx, &thread->buffer); | ||
|
||
json_object_clear(js); | ||
json_decref(js); | ||
jb_free(jb); | ||
} | ||
return TM_ECODE_OK; | ||
|
||
fail: | ||
jb_free(jb); | ||
return TM_ECODE_FAILED; | ||
} | ||
|
||
static void OutputFTPLogDeInitCtxSub(OutputCtx *output_ctx) | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@jasonish I still think we can optimize these constant cases with some preproc magic to become a single string that we append
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, need to look at this again.