mirror of https://github.com/OISF/suricata
json: rebase fixes
- restore json output-file.[ch] as output-json-file.[ch] after rebase conflict - fix Makefile.am after merge conflict - some dev-log-api-v4.0 rebase json fallout cleanuppull/802/head
parent
6fd1b31c57
commit
18458a14fb
@ -0,0 +1,357 @@
|
|||||||
|
/* Copyright (C) 2007-2013 Open Information Security Foundation
|
||||||
|
*
|
||||||
|
* You can copy, redistribute or modify this Program under the terms of
|
||||||
|
* the GNU General Public License version 2 as published by the Free
|
||||||
|
* Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* version 2 along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||||
|
* 02110-1301, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \file
|
||||||
|
*
|
||||||
|
* \author Tom DeCanio <td@npulsetech.com>
|
||||||
|
*
|
||||||
|
* Log files we track.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "suricata-common.h"
|
||||||
|
#include "debug.h"
|
||||||
|
#include "detect.h"
|
||||||
|
#include "pkt-var.h"
|
||||||
|
#include "conf.h"
|
||||||
|
|
||||||
|
#include "threadvars.h"
|
||||||
|
#include "tm-modules.h"
|
||||||
|
|
||||||
|
#include "threads.h"
|
||||||
|
|
||||||
|
#include "app-layer-parser.h"
|
||||||
|
|
||||||
|
#include "detect-filemagic.h"
|
||||||
|
|
||||||
|
#include "stream.h"
|
||||||
|
|
||||||
|
#include "util-print.h"
|
||||||
|
#include "util-unittest.h"
|
||||||
|
#include "util-privs.h"
|
||||||
|
#include "util-debug.h"
|
||||||
|
#include "util-atomic.h"
|
||||||
|
#include "util-file.h"
|
||||||
|
#include "util-time.h"
|
||||||
|
#include "util-buffer.h"
|
||||||
|
|
||||||
|
#include "output.h"
|
||||||
|
#include "output-json.h"
|
||||||
|
|
||||||
|
#include "log-file.h"
|
||||||
|
#include "util-logopenfile.h"
|
||||||
|
|
||||||
|
#include "app-layer-htp.h"
|
||||||
|
#include "util-memcmp.h"
|
||||||
|
#include "stream-tcp-reassemble.h"
|
||||||
|
|
||||||
|
#ifdef HAVE_LIBJANSSON
|
||||||
|
#include <jansson.h>
|
||||||
|
|
||||||
|
typedef struct OutputFileCtx_ {
|
||||||
|
uint32_t file_cnt;
|
||||||
|
} OutputFileCtx;
|
||||||
|
|
||||||
|
static json_t *LogFileMetaGetUri(Packet *p, File *ff) {
|
||||||
|
HtpState *htp_state = (HtpState *)p->flow->alstate;
|
||||||
|
json_t *js = NULL;
|
||||||
|
if (htp_state != NULL) {
|
||||||
|
htp_tx_t *tx = AppLayerParserGetTx(IPPROTO_TCP, ALPROTO_HTTP, htp_state, ff->txid);
|
||||||
|
if (tx != NULL) {
|
||||||
|
HtpTxUserData *tx_ud = htp_tx_get_user_data(tx);
|
||||||
|
if (tx_ud->request_uri_normalized != NULL) {
|
||||||
|
char *s = SCStrndup((char *) bstr_ptr(tx_ud->request_uri_normalized),
|
||||||
|
bstr_len(tx_ud->request_uri_normalized));
|
||||||
|
js = json_string(s);
|
||||||
|
if (s != NULL)
|
||||||
|
SCFree(s);
|
||||||
|
}
|
||||||
|
return js;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return json_string("<unknown>");
|
||||||
|
}
|
||||||
|
|
||||||
|
static json_t *LogFileMetaGetHost(Packet *p, File *ff) {
|
||||||
|
HtpState *htp_state = (HtpState *)p->flow->alstate;
|
||||||
|
json_t *js = NULL;
|
||||||
|
if (htp_state != NULL) {
|
||||||
|
htp_tx_t *tx = AppLayerParserGetTx(IPPROTO_TCP, ALPROTO_HTTP, htp_state, ff->txid);
|
||||||
|
if (tx != NULL && tx->request_hostname != NULL) {
|
||||||
|
char *s = SCStrndup((char *) bstr_ptr(tx->request_hostname),
|
||||||
|
bstr_len(tx->request_hostname));
|
||||||
|
js = json_string(s);
|
||||||
|
if (s != NULL)
|
||||||
|
SCFree(s);
|
||||||
|
return js;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return json_string("<unknown>");
|
||||||
|
}
|
||||||
|
|
||||||
|
static json_t *LogFileMetaGetReferer(Packet *p, File *ff) {
|
||||||
|
HtpState *htp_state = (HtpState *)p->flow->alstate;
|
||||||
|
json_t *js = NULL;
|
||||||
|
if (htp_state != NULL) {
|
||||||
|
htp_tx_t *tx = AppLayerParserGetTx(IPPROTO_TCP, ALPROTO_HTTP, htp_state, ff->txid);
|
||||||
|
if (tx != NULL) {
|
||||||
|
htp_header_t *h = NULL;
|
||||||
|
h = (htp_header_t *)htp_table_get_c(tx->request_headers,
|
||||||
|
"Referer");
|
||||||
|
if (h != NULL) {
|
||||||
|
char *s = SCStrndup((char *)bstr_ptr(h->value),
|
||||||
|
bstr_len(h->value));
|
||||||
|
js = json_string(s);
|
||||||
|
if (s != NULL)
|
||||||
|
SCFree(s);
|
||||||
|
return js;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return json_string("<unknown>");
|
||||||
|
}
|
||||||
|
|
||||||
|
static json_t *LogFileMetaGetUserAgent(Packet *p, File *ff) {
|
||||||
|
HtpState *htp_state = (HtpState *)p->flow->alstate;
|
||||||
|
json_t *js = NULL;
|
||||||
|
if (htp_state != NULL) {
|
||||||
|
htp_tx_t *tx = AppLayerParserGetTx(IPPROTO_TCP, ALPROTO_HTTP, htp_state, ff->txid);
|
||||||
|
if (tx != NULL) {
|
||||||
|
htp_header_t *h = NULL;
|
||||||
|
h = (htp_header_t *)htp_table_get_c(tx->request_headers,
|
||||||
|
"User-Agent");
|
||||||
|
if (h != NULL) {
|
||||||
|
char *s = SCStrndup((char *)bstr_ptr(h->value),
|
||||||
|
bstr_len(h->value));
|
||||||
|
js = json_string(s);
|
||||||
|
if (s != NULL)
|
||||||
|
SCFree(s);
|
||||||
|
return js;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return json_string("<unknown>");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \internal
|
||||||
|
* \brief Write meta data on a single line json record
|
||||||
|
*/
|
||||||
|
static void LogFileWriteJsonRecord(AlertJsonThread /*LogFileLogThread*/ *aft, Packet *p, File *ff, int ipver) {
|
||||||
|
MemBuffer *buffer = (MemBuffer *)aft->buffer;
|
||||||
|
json_t *js = CreateJSONHeader(p, 0);
|
||||||
|
if (unlikely(js == NULL))
|
||||||
|
return;
|
||||||
|
|
||||||
|
/* reset */
|
||||||
|
MemBufferReset(buffer);
|
||||||
|
|
||||||
|
json_t *fjs = json_object();
|
||||||
|
if (unlikely(fjs == NULL)) {
|
||||||
|
json_decref(js);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
json_object_set_new(fjs, "http_uri", LogFileMetaGetUri(p, ff));
|
||||||
|
json_object_set_new(fjs, "http_host", LogFileMetaGetHost(p, ff));
|
||||||
|
json_object_set_new(fjs, "http_referer", LogFileMetaGetReferer(p, ff));
|
||||||
|
json_object_set_new(fjs, "http_user_agent", LogFileMetaGetUserAgent(p, ff));
|
||||||
|
char *s = SCStrndup((char *)ff->name, ff->name_len);
|
||||||
|
json_object_set_new(fjs, "filename", json_string(s));
|
||||||
|
if (s != NULL)
|
||||||
|
SCFree(s);
|
||||||
|
if (ff->magic)
|
||||||
|
json_object_set_new(fjs, "magic", json_string((char *)ff->magic));
|
||||||
|
else
|
||||||
|
json_object_set_new(fjs, "magic", json_string("unknown"));
|
||||||
|
switch (ff->state) {
|
||||||
|
case FILE_STATE_CLOSED:
|
||||||
|
json_object_set_new(fjs, "state", json_string("CLOSED"));
|
||||||
|
#ifdef HAVE_NSS
|
||||||
|
if (ff->flags & FILE_MD5) {
|
||||||
|
size_t x;
|
||||||
|
int i;
|
||||||
|
char *s = SCMalloc(256);
|
||||||
|
if (likely(s != NULL)) {
|
||||||
|
for (i = 0, x = 0; x < sizeof(ff->md5); x++) {
|
||||||
|
i += snprintf(&s[i], 255-i, "%02x", ff->md5[x]);
|
||||||
|
}
|
||||||
|
json_object_set_new(fjs, "md5", json_string(s));
|
||||||
|
SCFree(s);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
break;
|
||||||
|
case FILE_STATE_TRUNCATED:
|
||||||
|
json_object_set_new(fjs, "state", json_string("TRUNCATED"));
|
||||||
|
break;
|
||||||
|
case FILE_STATE_ERROR:
|
||||||
|
json_object_set_new(fjs, "state", json_string("ERROR"));
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
json_object_set_new(fjs, "state", json_string("UNKNOWN"));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
json_object_set_new(fjs, "stored",
|
||||||
|
(ff->flags & FILE_STORED) ? json_true() : json_false());
|
||||||
|
json_object_set_new(fjs, "size", json_integer(ff->size));
|
||||||
|
|
||||||
|
json_object_set_new(js, "file", fjs);
|
||||||
|
OutputJSON(js, aft, &aft->files_cnt);
|
||||||
|
json_object_del(js, "file");
|
||||||
|
|
||||||
|
json_object_clear(js);
|
||||||
|
json_decref(js);
|
||||||
|
}
|
||||||
|
|
||||||
|
static TmEcode OutputFileLogWrap(ThreadVars *tv, Packet *p, void *data, int ipver)
|
||||||
|
{
|
||||||
|
SCEnter();
|
||||||
|
AlertJsonThread *aft = (AlertJsonThread *)data;
|
||||||
|
uint8_t flags = 0;
|
||||||
|
uint8_t direction = 0;
|
||||||
|
|
||||||
|
/* no flow, no htp state */
|
||||||
|
if (p->flow == NULL) {
|
||||||
|
SCReturnInt(TM_ECODE_OK);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (p->flowflags & FLOW_PKT_TOCLIENT)
|
||||||
|
flags |= (direction = STREAM_TOCLIENT);
|
||||||
|
else
|
||||||
|
flags |= (direction = STREAM_TOSERVER);
|
||||||
|
|
||||||
|
int file_close = (p->flags & PKT_PSEUDO_STREAM_END) ? 1 : 0;
|
||||||
|
int file_trunc = 0;
|
||||||
|
|
||||||
|
FLOWLOCK_WRLOCK(p->flow);
|
||||||
|
file_trunc = StreamTcpReassembleDepthReached(p);
|
||||||
|
|
||||||
|
Flow *f = p->flow;
|
||||||
|
FileContainer *ffc = AppLayerParserGetFiles(f->proto, f->alproto, f->alstate, direction);
|
||||||
|
SCLogDebug("ffc %p", ffc);
|
||||||
|
if (ffc != NULL) {
|
||||||
|
File *ff;
|
||||||
|
for (ff = ffc->head; ff != NULL; ff = ff->next) {
|
||||||
|
if (ff->flags & FILE_LOGGED)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (FileForceMagic() && ff->magic == NULL) {
|
||||||
|
FilemagicGlobalLookup(ff);
|
||||||
|
}
|
||||||
|
|
||||||
|
SCLogDebug("ff %p", ff);
|
||||||
|
|
||||||
|
if (file_trunc && ff->state < FILE_STATE_CLOSED)
|
||||||
|
ff->state = FILE_STATE_TRUNCATED;
|
||||||
|
|
||||||
|
if (ff->state == FILE_STATE_CLOSED ||
|
||||||
|
ff->state == FILE_STATE_TRUNCATED || ff->state == FILE_STATE_ERROR ||
|
||||||
|
(file_close == 1 && ff->state < FILE_STATE_CLOSED))
|
||||||
|
{
|
||||||
|
LogFileWriteJsonRecord(aft, p, ff, ipver);
|
||||||
|
|
||||||
|
ff->flags |= FILE_LOGGED;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
FilePrune(ffc);
|
||||||
|
}
|
||||||
|
|
||||||
|
FLOWLOCK_UNLOCK(p->flow);
|
||||||
|
SCReturnInt(TM_ECODE_OK);
|
||||||
|
}
|
||||||
|
|
||||||
|
TmEcode OutputFileLogIPv4(ThreadVars *tv, Packet *p, void *data)
|
||||||
|
{
|
||||||
|
return OutputFileLogWrap(tv, p, data, AF_INET);
|
||||||
|
}
|
||||||
|
|
||||||
|
TmEcode OutputFileLogIPv6(ThreadVars *tv, Packet *p, void *data)
|
||||||
|
{
|
||||||
|
return OutputFileLogWrap(tv, p, data, AF_INET6);
|
||||||
|
}
|
||||||
|
|
||||||
|
TmEcode OutputFileLog (ThreadVars *tv, Packet *p, void *data)
|
||||||
|
{
|
||||||
|
SCEnter();
|
||||||
|
int r = TM_ECODE_OK;
|
||||||
|
|
||||||
|
/* no flow, no htp state */
|
||||||
|
if (p->flow == NULL) {
|
||||||
|
SCReturnInt(TM_ECODE_OK);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(PKT_IS_TCP(p))) {
|
||||||
|
SCReturnInt(TM_ECODE_OK);
|
||||||
|
}
|
||||||
|
|
||||||
|
SCLogDebug("p->pcap_cnt %"PRIu64, p->pcap_cnt);
|
||||||
|
|
||||||
|
if (PKT_IS_IPV4(p)) {
|
||||||
|
r = OutputFileLogIPv4(tv, p, data);
|
||||||
|
} else if (PKT_IS_IPV6(p)) {
|
||||||
|
r = OutputFileLogIPv6(tv, p, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
SCReturnInt(r);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** \brief Create a new http log LogFileCtx.
|
||||||
|
* \param conf Pointer to ConfNode containing this loggers configuration.
|
||||||
|
* \return NULL if failure, LogFileCtx* to the file_ctx if succesful
|
||||||
|
* */
|
||||||
|
OutputCtx *OutputFileLogInit(ConfNode *conf)
|
||||||
|
{
|
||||||
|
OutputFileCtx *file_ctx = SCMalloc(sizeof(OutputFileCtx));
|
||||||
|
if (unlikely(file_ctx == NULL))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
OutputCtx *output_ctx = SCCalloc(1, sizeof(OutputCtx));
|
||||||
|
if (unlikely(output_ctx == NULL)) {
|
||||||
|
SCFree(file_ctx);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (conf) {
|
||||||
|
const char *force_magic = ConfNodeLookupChildValue(conf, "force-magic");
|
||||||
|
if (force_magic != NULL && ConfValIsTrue(force_magic)) {
|
||||||
|
FileForceMagicEnable();
|
||||||
|
SCLogInfo("forcing magic lookup for logged files");
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *force_md5 = ConfNodeLookupChildValue(conf, "force-md5");
|
||||||
|
if (force_md5 != NULL && ConfValIsTrue(force_md5)) {
|
||||||
|
#ifdef HAVE_NSS
|
||||||
|
FileForceMd5Enable();
|
||||||
|
SCLogInfo("forcing md5 calculation for logged files");
|
||||||
|
#else
|
||||||
|
SCLogInfo("md5 calculation requires linking against libnss");
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
FileForceTrackingEnable();
|
||||||
|
return output_ctx;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
@ -0,0 +1,30 @@
|
|||||||
|
/* Copyright (C) 2007-2013 Open Information Security Foundation
|
||||||
|
*
|
||||||
|
* You can copy, redistribute or modify this Program under the terms of
|
||||||
|
* the GNU General Public License version 2 as published by the Free
|
||||||
|
* Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* version 2 along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||||
|
* 02110-1301, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \file
|
||||||
|
*
|
||||||
|
* \author Tom DeCanio <td@npulsetech.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __OUTPUT_FILELOG_H__
|
||||||
|
#define __OUTPUT_FILELOG_H__
|
||||||
|
|
||||||
|
TmEcode OutputFileLog (ThreadVars *tv, Packet *p, void *data);
|
||||||
|
OutputCtx *OutputFileLogInit(ConfNode *);
|
||||||
|
|
||||||
|
#endif /* __OUTPUT_FILELOG_H__ */
|
Loading…
Reference in New Issue