suricata
output-json-file.c
Go to the documentation of this file.
1/* Copyright (C) 2007-2021 Open Information Security Foundation
2 *
3 * You can copy, redistribute or modify this Program under the terms of
4 * the GNU General Public License version 2 as published by the Free
5 * Software Foundation.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License
13 * version 2 along with this program; if not, write to the Free Software
14 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
15 * 02110-1301, USA.
16 */
17
18/**
19 * \file
20 *
21 * \author Tom DeCanio <td@npulsetech.com>
22 *
23 * Log files we track.
24 *
25 */
26
27#include "suricata-common.h"
28#include "detect.h"
29#include "pkt-var.h"
30#include "conf.h"
31
32#include "threadvars.h"
33#include "tm-modules.h"
34
35#include "threads.h"
36
37#include "app-layer-parser.h"
38
39#include "detect-filemagic.h"
40
41#include "stream.h"
42
43#include "util-print.h"
44#include "util-unittest.h"
45#include "util-privs.h"
46#include "util-debug.h"
47#include "util-atomic.h"
48#include "util-file.h"
49#include "util-time.h"
50#include "util-buffer.h"
51#include "util-byte.h"
52#include "util-validate.h"
53
54#include "util-logopenfile.h"
55
56#include "output.h"
57#include "output-json.h"
58#include "output-json-file.h"
59#include "output-json-http.h"
60#include "output-json-smtp.h"
62#include "output-json-nfs.h"
63#include "output-json-smb.h"
64
65#include "app-layer-htp.h"
66#include "app-layer-htp-xff.h"
67#include "util-memcmp.h"
69
76
81
82SCJsonBuilder *JsonBuildFileInfoRecord(const Packet *p, const File *ff, void *tx,
83 const uint64_t tx_id, const bool stored, uint8_t dir, HttpXFFCfg *xff_cfg,
84 OutputJsonCtx *eve_ctx)
85{
87
88 switch(dir) {
89 case STREAM_TOCLIENT:
91 break;
92 case STREAM_TOSERVER:
94 break;
95 default:
97 break;
98 }
99
101 JsonAddrInfoInit(p, fdir, &addr);
102
103 /* Overwrite address info with XFF if needed. */
104 int have_xff_ip = 0;
105 char xff_buffer[XFF_MAXLEN];
106 if ((xff_cfg != NULL) && !(xff_cfg->flags & XFF_DISABLED)) {
107 if (FlowGetAppProtocol(p->flow) == ALPROTO_HTTP1) {
108 have_xff_ip = HttpXFFGetIPFromTx(p->flow, tx_id, xff_cfg, xff_buffer, XFF_MAXLEN);
109 }
110 if (have_xff_ip && xff_cfg->flags & XFF_OVERWRITE) {
111 if (p->flowflags & FLOW_PKT_TOCLIENT) {
112 strlcpy(addr.dst_ip, xff_buffer, JSON_ADDR_LEN);
113 } else {
114 strlcpy(addr.src_ip, xff_buffer, JSON_ADDR_LEN);
115 }
116 have_xff_ip = 0;
117 }
118 }
119
120 SCJsonBuilder *js = CreateEveHeader(p, fdir, "fileinfo", &addr, eve_ctx);
121 if (unlikely(js == NULL))
122 return NULL;
123
124 SCJsonBuilderMark mark = { 0, 0, 0 };
126 switch (p->flow->alproto) {
127 case ALPROTO_HTTP1:
128 SCJbOpenObject(js, "http");
129 EveHttpAddMetadata(p->flow, tx_id, js);
130 SCJbClose(js);
131 break;
132 case ALPROTO_SMTP:
133 SCJbGetMark(js, &mark);
134 SCJbOpenObject(js, "smtp");
135 if (EveSMTPAddMetadata(p->flow, tx_id, js)) {
136 SCJbClose(js);
137 } else {
138 SCJbRestoreMark(js, &mark);
139 }
140 SCJbGetMark(js, &mark);
141 SCJbOpenObject(js, "email");
142 if (EveEmailAddMetadata(p->flow, tx_id, js)) {
143 SCJbClose(js);
144 } else {
145 SCJbRestoreMark(js, &mark);
146 }
147 break;
148 case ALPROTO_NFS:
149 /* rpc */
150 SCJbGetMark(js, &mark);
151 SCJbOpenObject(js, "rpc");
152 if (EveNFSAddMetadataRPC(p->flow, tx_id, js)) {
153 SCJbClose(js);
154 } else {
155 SCJbRestoreMark(js, &mark);
156 }
157 /* nfs */
158 SCJbGetMark(js, &mark);
159 SCJbOpenObject(js, "nfs");
160 if (EveNFSAddMetadata(p->flow, tx_id, js)) {
161 SCJbClose(js);
162 } else {
163 SCJbRestoreMark(js, &mark);
164 }
165 break;
166 case ALPROTO_SMB:
167 SCJbGetMark(js, &mark);
168 SCJbOpenObject(js, "smb");
169 if (EveSMBAddMetadata(p->flow, tx_id, js)) {
170 SCJbClose(js);
171 } else {
172 SCJbRestoreMark(js, &mark);
173 }
174 break;
175 default:
177 if (al && al->LogTx) {
178 void *state = FlowGetAppState(p->flow);
179 if (state) {
180 tx = AppLayerParserGetTx(p->flow->proto, p->flow->alproto, state, tx_id);
181 if (tx) {
182 SCJbGetMark(js, &mark);
183 if (!al->LogTx(tx, js)) {
184 SCJbRestoreMark(js, &mark);
185 }
186 }
187 }
188 }
189 break;
190 }
191
192 SCJbSetString(js, "app_proto", AppProtoToString(p->flow->alproto));
193
194 SCJbOpenObject(js, "fileinfo");
195 if (stored) {
196 // the file has just been stored on disk cf OUTPUT_FILEDATA_FLAG_CLOSE
197 // but the flag is not set until the loggers have been called
198 EveFileInfo(js, ff, tx_id, ff->flags | FILE_STORED);
199 } else {
200 EveFileInfo(js, ff, tx_id, ff->flags);
201 }
202 SCJbClose(js);
203
204 /* xff header */
205 if (have_xff_ip && xff_cfg->flags & XFF_EXTRADATA) {
206 SCJbSetString(js, "xff", xff_buffer);
207 }
208
209 return js;
210}
211
212/**
213 * \internal
214 * \brief Write meta data on a single line json record
215 */
216static void FileWriteJsonRecord(ThreadVars *tv, JsonFileLogThread *aft, const Packet *p,
217 const File *ff, void *tx, const uint64_t tx_id, uint8_t dir, OutputJsonCtx *eve_ctx)
218{
219 HttpXFFCfg *xff_cfg = aft->filelog_ctx->xff_cfg != NULL ? aft->filelog_ctx->xff_cfg
221 SCJsonBuilder *js = JsonBuildFileInfoRecord(p, ff, tx, tx_id, false, dir, xff_cfg, eve_ctx);
222 if (unlikely(js == NULL)) {
223 return;
224 }
225
226 OutputJsonBuilderBuffer(tv, p, p->flow, js, aft->ctx);
227 SCJbFree(js);
228}
229
230static int JsonFileLogger(ThreadVars *tv, void *thread_data, const Packet *p, const File *ff,
231 void *tx, const uint64_t tx_id, uint8_t dir)
232{
233 SCEnter();
234 JsonFileLogThread *aft = (JsonFileLogThread *)thread_data;
235
237
238 SCLogDebug("ff %p", ff);
239
240 FileWriteJsonRecord(tv, aft, p, ff, tx, tx_id, dir, aft->filelog_ctx->eve_ctx);
241 return 0;
242}
243
244
245static TmEcode JsonFileLogThreadInit(ThreadVars *t, const void *initdata, void **data)
246{
248 if (unlikely(aft == NULL))
249 return TM_ECODE_FAILED;
250
251 if(initdata == NULL)
252 {
253 SCLogDebug("Error getting context for EveLogFile. \"initdata\" argument NULL");
254 goto error_exit;
255 }
256
257 /* Use the Output Context (file pointer and mutex) */
258 aft->filelog_ctx = ((OutputCtx *)initdata)->data;
259 aft->ctx = CreateEveThreadCtx(t, aft->filelog_ctx->eve_ctx);
260 if (!aft->ctx) {
261 goto error_exit;
262 }
263
264 *data = (void *)aft;
265 return TM_ECODE_OK;
266
267error_exit:
268 SCFree(aft);
269 return TM_ECODE_FAILED;
270}
271
272static TmEcode JsonFileLogThreadDeinit(ThreadVars *t, void *data)
273{
275 if (aft == NULL) {
276 return TM_ECODE_OK;
277 }
278
279 FreeEveThreadCtx(aft->ctx);
280
281 /* clear memory */
282 memset(aft, 0, sizeof(JsonFileLogThread));
283
284 SCFree(aft);
285 return TM_ECODE_OK;
286}
287
288static void OutputFileLogDeinitSub(OutputCtx *output_ctx)
289{
290 OutputFileCtx *ff_ctx = output_ctx->data;
291 if (ff_ctx->xff_cfg != NULL) {
292 SCFree(ff_ctx->xff_cfg);
293 }
294 SCFree(ff_ctx);
295 SCFree(output_ctx);
296}
297
298/** \brief Create a new http log LogFileCtx.
299 * \param conf Pointer to ConfNode containing this loggers configuration.
300 * \return NULL if failure, LogFileCtx* to the file_ctx if succesful
301 * */
302static OutputInitResult OutputFileLogInitSub(SCConfNode *conf, OutputCtx *parent_ctx)
303{
304 OutputInitResult result = { NULL, false };
305 OutputJsonCtx *ojc = parent_ctx->data;
306
307 OutputFileCtx *output_file_ctx = SCCalloc(1, sizeof(OutputFileCtx));
308 if (unlikely(output_file_ctx == NULL))
309 return result;
310
311 OutputCtx *output_ctx = SCCalloc(1, sizeof(OutputCtx));
312 if (unlikely(output_ctx == NULL)) {
313 SCFree(output_file_ctx);
314 return result;
315 }
316
317 if (conf) {
318 const char *force_filestore = SCConfNodeLookupChildValue(conf, "force-filestore");
319 if (force_filestore != NULL && SCConfValIsTrue(force_filestore)) {
321 SCLogConfig("forcing filestore of all files");
322 }
323
324 const char *force_magic = SCConfNodeLookupChildValue(conf, "force-magic");
325 if (force_magic != NULL && SCConfValIsTrue(force_magic)) {
327 SCLogConfig("forcing magic lookup for logged files");
328 }
329
331 }
332
333 if (conf != NULL && SCConfNodeLookupChild(conf, "xff") != NULL) {
334 output_file_ctx->xff_cfg = SCCalloc(1, sizeof(HttpXFFCfg));
335 if (output_file_ctx->xff_cfg != NULL) {
336 HttpXFFGetCfg(conf, output_file_ctx->xff_cfg);
337 }
338 } else if (ojc->xff_cfg) {
339 output_file_ctx->parent_xff_cfg = ojc->xff_cfg;
340 }
341
342 output_file_ctx->eve_ctx = ojc;
343 output_ctx->data = output_file_ctx;
344 output_ctx->DeInit = OutputFileLogDeinitSub;
345
347 result.ctx = output_ctx;
348 result.ok = true;
349 return result;
350}
351
353{
354 /* register as child of eve-log */
355 OutputRegisterFileSubModule(LOGGER_JSON_FILE, "eve-log", "JsonFileLog", "eve-log.files",
356 OutputFileLogInitSub, JsonFileLogger, JsonFileLogThreadInit, JsonFileLogThreadDeinit);
357}
int HttpXFFGetIPFromTx(const Flow *f, uint64_t tx_id, HttpXFFCfg *xff_cfg, char *dstbuf, int dstbuflen)
Function to return XFF IP if any in the selected transaction. The caller needs to lock the flow.
void HttpXFFGetCfg(SCConfNode *conf, HttpXFFCfg *result)
Function to return XFF configuration from a configuration node.
#define XFF_MAXLEN
#define XFF_EXTRADATA
#define XFF_OVERWRITE
#define XFF_DISABLED
void * AppLayerParserGetTx(uint8_t ipproto, AppProto alproto, void *alstate, uint64_t tx_id)
const char * AppProtoToString(AppProto alproto)
Maps the ALPROTO_*, to its string equivalent.
@ ALPROTO_NFS
@ ALPROTO_SMTP
@ ALPROTO_SMB
@ ALPROTO_HTTP1
SCConfNode * SCConfNodeLookupChild(const SCConfNode *node, const char *name)
Lookup a child configuration node by name.
Definition conf.c:796
int SCConfValIsTrue(const char *val)
Check if a value is true.
Definition conf.c:551
const char * SCConfNodeLookupChildValue(const SCConfNode *node, const char *name)
Lookup the value of a child configuration node by name.
Definition conf.c:824
#define FLOW_PKT_TOCLIENT
Definition flow.h:234
ThreadVars * tv
SCOutputJsonLogDirection
@ LOG_DIR_FLOW
@ LOG_DIR_FLOW_TOSERVER
@ LOG_DIR_FLOW_TOCLIENT
EveJsonSimpleAppLayerLogger * SCEveJsonSimpleGetLogger(AppProto alproto)
Definition output.c:931
OutputJsonThreadCtx * CreateEveThreadCtx(ThreadVars *t, OutputJsonCtx *ctx)
void FreeEveThreadCtx(OutputJsonThreadCtx *ctx)
bool EveEmailAddMetadata(const Flow *f, uint64_t tx_id, SCJsonBuilder *js)
struct JsonFileLogThread_ JsonFileLogThread
void JsonFileLogRegister(void)
SCJsonBuilder * JsonBuildFileInfoRecord(const Packet *p, const File *ff, void *tx, const uint64_t tx_id, const bool stored, uint8_t dir, HttpXFFCfg *xff_cfg, OutputJsonCtx *eve_ctx)
struct OutputFileCtx_ OutputFileCtx
bool EveHttpAddMetadata(const Flow *f, uint64_t tx_id, SCJsonBuilder *js)
bool EveNFSAddMetadataRPC(const Flow *f, uint64_t tx_id, SCJsonBuilder *jb)
bool EveNFSAddMetadata(const Flow *f, uint64_t tx_id, SCJsonBuilder *jb)
bool EveSMBAddMetadata(const Flow *f, uint64_t tx_id, SCJsonBuilder *jb)
bool EveSMTPAddMetadata(const Flow *f, uint64_t tx_id, SCJsonBuilder *js)
SCJsonBuilder * CreateEveHeader(const Packet *p, enum SCOutputJsonLogDirection dir, const char *event_type, JsonAddrInfo *addr, OutputJsonCtx *eve_ctx)
void EveFileInfo(SCJsonBuilder *jb, const File *ff, const uint64_t tx_id, const uint16_t flags)
void JsonAddrInfoInit(const Packet *p, enum SCOutputJsonLogDirection dir, JsonAddrInfo *addr)
const JsonAddrInfo json_addr_info_zero
Definition output-json.c:81
void OutputJsonBuilderBuffer(ThreadVars *tv, const Packet *p, Flow *f, SCJsonBuilder *js, OutputJsonThreadCtx *ctx)
#define JSON_ADDR_LEN
Definition output-json.h:37
void OutputRegisterFileSubModule(LoggerId id, const char *parent_name, const char *name, const char *conf_name, OutputInitSubFunc InitFunc, SCFileLogger FileLogFunc, ThreadInitFunc ThreadInit, ThreadDeinitFunc ThreadDeinit)
Register a file output sub-module.
Definition output.c:422
EveJsonSimpleTxLogFunc LogTx
uint16_t flags
Definition util-file.h:80
uint8_t proto
Definition flow.h:378
AppProto alproto
application level protocol
Definition flow.h:450
char src_ip[JSON_ADDR_LEN]
Definition output-json.h:42
char dst_ip[JSON_ADDR_LEN]
Definition output-json.h:43
OutputFileCtx * filelog_ctx
OutputJsonThreadCtx * ctx
void * data
Definition tm-modules.h:91
void(* DeInit)(struct OutputCtx_ *)
Definition tm-modules.h:94
HttpXFFCfg * xff_cfg
OutputJsonCtx * eve_ctx
HttpXFFCfg * parent_xff_cfg
OutputCtx * ctx
Definition output.h:47
HttpXFFCfg * xff_cfg
Definition output-json.h:79
uint8_t flowflags
Definition decode.h:532
struct Flow_ * flow
Definition decode.h:546
Per thread variable structure.
Definition threadvars.h:58
@ LOGGER_JSON_FILE
size_t strlcpy(char *dst, const char *src, size_t siz)
@ TM_ECODE_FAILED
@ TM_ECODE_OK
#define SCEnter(...)
Definition util-debug.h:277
#define SCLogDebug(...)
Definition util-debug.h:275
#define SCLogConfig(...)
Definition util-debug.h:229
void FileForceMagicEnable(void)
Definition util-file.c:98
void FileForceFilestoreEnable(void)
Definition util-file.c:92
void FileForceTrackingEnable(void)
Definition util-file.c:161
void FileForceHashParseCfg(SCConfNode *conf)
Function to parse forced file hashing configuration.
Definition util-file.c:170
#define FILE_LOGGED
Definition util-file.h:53
#define FILE_STORED
Definition util-file.h:56
#define SCFree(p)
Definition util-mem.h:61
#define SCCalloc(nm, sz)
Definition util-mem.h:53
#define unlikely(expr)
#define DEBUG_VALIDATE_BUG_ON(exp)