suricata
output-json.c
Go to the documentation of this file.
1/* Copyright (C) 2007-2023 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 * Logs detection and monitoring events in JSON format.
24 *
25 */
26
27#include "suricata-common.h"
28#include "flow.h"
29#include "conf.h"
30
31#include "util-debug.h"
32#include "util-time.h"
33#include "util-var-name.h"
34#include "util-macset.h"
35
36#include "util-unittest.h"
38
39#include "detect-engine.h"
41#include "util-syslog.h"
42
43/* Internal output plugins */
44#include "output-eve-syslog.h"
45#include "output-eve-null.h"
46
47#include "output.h"
48#include "output-json.h"
49
50#include "util-byte.h"
51#include "util-print.h"
52#include "util-proto-name.h"
53#include "util-optimize.h"
54#include "util-buffer.h"
55#include "util-logopenfile.h"
56#include "util-log-redis.h"
57#include "util-device-private.h"
58#include "util-validate.h"
59
60#include "flow-var.h"
61#include "flow-bit.h"
62#include "flow-storage.h"
63
65
66#define DEFAULT_LOG_FILENAME "eve.json"
67#define MODULE_NAME "OutputJSON"
68
69#define MAX_JSON_SIZE 2048
70
71static void OutputJsonDeInitCtx(OutputCtx *);
72static void CreateEveCommunityFlowId(SCJsonBuilder *js, const Flow *f, const uint16_t seed);
73static int CreateJSONEther(
74 SCJsonBuilder *parent, const Packet *p, const Flow *f, enum SCOutputJsonLogDirection dir);
75
76static const char *TRAFFIC_ID_PREFIX = "traffic/id/";
77static const char *TRAFFIC_LABEL_PREFIX = "traffic/label/";
78static size_t traffic_id_prefix_len = 0;
79static size_t traffic_label_prefix_len = 0;
80
82
84{
86
87 traffic_id_prefix_len = strlen(TRAFFIC_ID_PREFIX);
88 traffic_label_prefix_len = strlen(TRAFFIC_LABEL_PREFIX);
89
90 // Register output file types that use the new eve filetype registration
91 // API.
94}
95
96json_t *SCJsonString(const char *val)
97{
98 if (val == NULL){
99 return NULL;
100 }
101 json_t * retval = json_string(val);
102 char retbuf[MAX_JSON_SIZE] = {0};
103 if (retval == NULL) {
104 uint32_t u = 0;
105 uint32_t offset = 0;
106 for (u = 0; u < strlen(val); u++) {
107 if (isprint(val[u])) {
108 PrintBufferData(retbuf, &offset, MAX_JSON_SIZE-1, "%c",
109 val[u]);
110 } else {
112 "\\x%02X", val[u]);
113 }
114 }
115 retbuf[offset] = '\0';
116 retval = json_string(retbuf);
117 }
118 return retval;
119}
120
121/* Default Sensor ID value */
122static int64_t sensor_id = -1; /* -1 = not defined */
123
124void EveFileInfo(SCJsonBuilder *jb, const File *ff, const uint64_t tx_id, const uint16_t flags)
125{
126 SCJbSetStringFromBytes(jb, "filename", ff->name, ff->name_len);
127
128 if (ff->sid_cnt > 0) {
129 SCJbOpenArray(jb, "sid");
130 for (uint32_t i = 0; ff->sid != NULL && i < ff->sid_cnt; i++) {
131 SCJbAppendUint(jb, ff->sid[i]);
132 }
133 SCJbClose(jb);
134 }
135
136#ifdef HAVE_MAGIC
137 if (ff->magic)
138 SCJbSetString(jb, "magic", (char *)ff->magic);
139#endif
140 SCJbSetBool(jb, "gaps", ff->flags & FILE_HAS_GAPS);
141 switch (ff->state) {
143 JB_SET_STRING(jb, "state", "CLOSED");
144 if (ff->flags & FILE_MD5) {
145 SCJbSetHex(jb, "md5", (uint8_t *)ff->md5, (uint32_t)sizeof(ff->md5));
146 }
147 if (ff->flags & FILE_SHA1) {
148 SCJbSetHex(jb, "sha1", (uint8_t *)ff->sha1, (uint32_t)sizeof(ff->sha1));
149 }
150 break;
152 JB_SET_STRING(jb, "state", "TRUNCATED");
153 break;
154 case FILE_STATE_ERROR:
155 JB_SET_STRING(jb, "state", "ERROR");
156 break;
157 default:
158 JB_SET_STRING(jb, "state", "UNKNOWN");
159 break;
160 }
161
162 if (ff->flags & FILE_SHA256) {
163 SCJbSetHex(jb, "sha256", (uint8_t *)ff->sha256, (uint32_t)sizeof(ff->sha256));
164 }
165
166 if (flags & FILE_STORED) {
167 JB_SET_TRUE(jb, "stored");
168 SCJbSetUint(jb, "file_id", ff->file_store_id);
169 } else {
170 JB_SET_FALSE(jb, "stored");
171 if (flags & FILE_STORE) {
172 JB_SET_TRUE(jb, "storing");
173 }
174 }
175
176 SCJbSetUint(jb, "size", FileTrackedSize(ff));
177 if (ff->end > 0) {
178 SCJbSetUint(jb, "start", ff->start);
179 SCJbSetUint(jb, "end", ff->end);
180 }
181 SCJbSetUint(jb, "tx_id", tx_id);
182}
183
184static void EveAddPacketVars(const Packet *p, SCJsonBuilder *js_vars)
185{
186 if (p == NULL || p->pktvar == NULL) {
187 return;
188 }
189 PktVar *pv = p->pktvar;
190 bool open = false;
191 while (pv != NULL) {
192 if (pv->key || pv->id > 0) {
193 if (!open) {
194 SCJbOpenArray(js_vars, "pktvars");
195 open = true;
196 }
197 SCJbStartObject(js_vars);
198
199 if (pv->key != NULL) {
200 uint32_t offset = 0;
201 uint8_t keybuf[pv->key_len + 1];
202 PrintStringsToBuffer(keybuf, &offset, pv->key_len + 1, pv->key, pv->key_len);
203 uint32_t len = pv->value_len;
204 uint8_t printable_buf[len + 1];
205 offset = 0;
206 PrintStringsToBuffer(printable_buf, &offset, len + 1, pv->value, pv->value_len);
207 SCJbSetString(js_vars, (char *)keybuf, (char *)printable_buf);
208 } else {
209 const char *varname = VarNameStoreLookupById(pv->id, VAR_TYPE_PKT_VAR);
210 uint32_t len = pv->value_len;
211 uint8_t printable_buf[len + 1];
212 uint32_t offset = 0;
213 PrintStringsToBuffer(printable_buf, &offset, len + 1, pv->value, pv->value_len);
214 SCJbSetString(js_vars, varname, (char *)printable_buf);
215 }
216 SCJbClose(js_vars);
217 }
218 pv = pv->next;
219 }
220 if (open) {
221 SCJbClose(js_vars);
222 }
223}
224
225/**
226 * \brief Check if string s has prefix prefix.
227 *
228 * \retval true if string has prefix
229 * \retval false if string does not have prefix
230 *
231 * TODO: Move to file with other string handling functions.
232 */
233static bool SCStringHasPrefix(const char *s, const char *prefix)
234{
235 if (strncmp(s, prefix, strlen(prefix)) == 0) {
236 return true;
237 }
238 return false;
239}
240
241static void EveAddFlowVars(const Flow *f, SCJsonBuilder *js_root, SCJsonBuilder **js_traffic)
242{
243 if (f == NULL || f->flowvar == NULL) {
244 return;
245 }
246 SCJsonBuilder *js_flowvars = NULL;
247 SCJsonBuilder *js_traffic_id = NULL;
248 SCJsonBuilder *js_traffic_label = NULL;
249 SCJsonBuilder *js_flowints = NULL;
250 SCJsonBuilder *js_entropyvals = NULL;
251 SCJsonBuilder *js_flowbits = NULL;
252 GenericVar *gv = f->flowvar;
253 while (gv != NULL) {
254 if (gv->type == DETECT_FLOWVAR || gv->type == DETECT_FLOWINT) {
255 FlowVar *fv = (FlowVar *)gv;
256 if (fv->datatype == FLOWVAR_TYPE_STR && fv->key == NULL) {
257 const char *varname = VarNameStoreLookupById(fv->idx,
259 if (varname) {
260 if (js_flowvars == NULL) {
261 js_flowvars = SCJbNewArray();
262 if (js_flowvars == NULL)
263 break;
264 }
265
266 uint32_t len = fv->data.fv_str.value_len;
267 uint8_t printable_buf[len + 1];
268 uint32_t offset = 0;
269 PrintStringsToBuffer(printable_buf, &offset, len + 1, fv->data.fv_str.value,
270 fv->data.fv_str.value_len);
271
272 SCJbStartObject(js_flowvars);
273 SCJbSetString(js_flowvars, varname, (char *)printable_buf);
274 SCJbClose(js_flowvars);
275 }
276 } else if (fv->datatype == FLOWVAR_TYPE_STR && fv->key != NULL) {
277 if (js_flowvars == NULL) {
278 js_flowvars = SCJbNewArray();
279 if (js_flowvars == NULL)
280 break;
281 }
282
283 uint8_t keybuf[fv->keylen + 1];
284 uint32_t offset = 0;
285 PrintStringsToBuffer(keybuf, &offset, fv->keylen + 1, fv->key, fv->keylen);
286
287 uint32_t len = fv->data.fv_str.value_len;
288 uint8_t printable_buf[len + 1];
289 offset = 0;
290 PrintStringsToBuffer(printable_buf, &offset, len + 1, fv->data.fv_str.value,
291 fv->data.fv_str.value_len);
292
293 SCJbStartObject(js_flowvars);
294 SCJbSetString(js_flowvars, (const char *)keybuf, (char *)printable_buf);
295 SCJbClose(js_flowvars);
296 } else if (fv->datatype == FLOWVAR_TYPE_FLOAT) {
297 const char *varname = VarNameStoreLookupById(fv->idx, VAR_TYPE_FLOW_FLOAT);
298 if (varname) {
299 if (js_entropyvals == NULL) {
300 js_entropyvals = SCJbNewObject();
301 if (js_entropyvals == NULL)
302 break;
303 }
304 SCJbSetFloat(js_entropyvals, varname, fv->data.fv_float.value);
305 }
306
307 } else if (fv->datatype == FLOWVAR_TYPE_INT) {
308 const char *varname = VarNameStoreLookupById(fv->idx,
310 if (varname) {
311 if (js_flowints == NULL) {
312 js_flowints = SCJbNewObject();
313 if (js_flowints == NULL)
314 break;
315 }
316 SCJbSetUint(js_flowints, varname, fv->data.fv_int.value);
317 }
318 }
319 } else if (gv->type == DETECT_FLOWBITS) {
320 FlowBit *fb = (FlowBit *)gv;
321 const char *varname = VarNameStoreLookupById(fb->idx,
323 if (varname) {
324 if (SCStringHasPrefix(varname, TRAFFIC_ID_PREFIX)) {
325 if (js_traffic_id == NULL) {
326 js_traffic_id = SCJbNewArray();
327 if (unlikely(js_traffic_id == NULL)) {
328 break;
329 }
330 }
331 SCJbAppendString(js_traffic_id, &varname[traffic_id_prefix_len]);
332 } else if (SCStringHasPrefix(varname, TRAFFIC_LABEL_PREFIX)) {
333 if (js_traffic_label == NULL) {
334 js_traffic_label = SCJbNewArray();
335 if (unlikely(js_traffic_label == NULL)) {
336 break;
337 }
338 }
339 SCJbAppendString(js_traffic_label, &varname[traffic_label_prefix_len]);
340 } else {
341 if (js_flowbits == NULL) {
342 js_flowbits = SCJbNewArray();
343 if (unlikely(js_flowbits == NULL))
344 break;
345 }
346 SCJbAppendString(js_flowbits, varname);
347 }
348 }
349 }
350 gv = gv->next;
351 }
352 if (js_flowbits) {
353 SCJbClose(js_flowbits);
354 SCJbSetObject(js_root, "flowbits", js_flowbits);
355 SCJbFree(js_flowbits);
356 }
357 if (js_flowints) {
358 SCJbClose(js_flowints);
359 SCJbSetObject(js_root, "flowints", js_flowints);
360 SCJbFree(js_flowints);
361 }
362 if (js_entropyvals) {
363 SCJbClose(js_entropyvals);
364 SCJbSetObject(js_root, "entropy", js_entropyvals);
365 SCJbFree(js_entropyvals);
366 }
367 if (js_flowvars) {
368 SCJbClose(js_flowvars);
369 SCJbSetObject(js_root, "flowvars", js_flowvars);
370 SCJbFree(js_flowvars);
371 }
372
373 if (js_traffic_id != NULL || js_traffic_label != NULL) {
374 *js_traffic = SCJbNewObject();
375 if (likely(*js_traffic != NULL)) {
376 if (js_traffic_id != NULL) {
377 SCJbClose(js_traffic_id);
378 SCJbSetObject(*js_traffic, "id", js_traffic_id);
379 SCJbFree(js_traffic_id);
380 }
381 if (js_traffic_label != NULL) {
382 SCJbClose(js_traffic_label);
383 SCJbSetObject(*js_traffic, "label", js_traffic_label);
384 SCJbFree(js_traffic_label);
385 }
386 SCJbClose(*js_traffic);
387 }
388 }
389}
390
391void EveAddMetadata(const Packet *p, const Flow *f, SCJsonBuilder *js)
392{
393 if ((p && p->pktvar) || (f && f->flowvar)) {
394 SCJsonBuilder *js_vars = SCJbNewObject();
395 if (js_vars) {
396 if (f && f->flowvar) {
397 SCJsonBuilder *js_traffic = NULL;
398 EveAddFlowVars(f, js_vars, &js_traffic);
399 if (js_traffic != NULL) {
400 SCJbSetObject(js, "traffic", js_traffic);
401 SCJbFree(js_traffic);
402 }
403 }
404 if (p && p->pktvar) {
405 EveAddPacketVars(p, js_vars);
406 }
407 SCJbClose(js_vars);
408 SCJbSetObject(js, "metadata", js_vars);
409 SCJbFree(js_vars);
410 }
411 }
412}
413
414void EveAddCommonOptions(const OutputJsonCommonSettings *cfg, const Packet *p, const Flow *f,
415 SCJsonBuilder *js, enum SCOutputJsonLogDirection dir)
416{
417 if (cfg->include_suricata_version) {
418 SCJbSetString(js, "suricata_version", PROG_VER);
419 }
420 if (cfg->include_metadata) {
421 EveAddMetadata(p, f, js);
422 }
423 if (cfg->include_ethernet) {
424 CreateJSONEther(js, p, f, dir);
425 }
426 if (cfg->include_community_id && f != NULL) {
427 CreateEveCommunityFlowId(js, f, cfg->community_id_seed);
428 }
429 if (f != NULL && f->tenant_id > 0) {
430 SCJbSetUint(js, "tenant_id", f->tenant_id);
431 }
432}
433
434/**
435 * \brief Jsonify a packet
436 *
437 * \param p Packet
438 * \param js JSON object
439 * \param max_length If non-zero, restricts the number of packet data bytes handled.
440 */
441void EvePacket(const Packet *p, SCJsonBuilder *js, uint32_t max_length)
442{
443 uint32_t max_len = max_length == 0 ? GET_PKT_LEN(p) : max_length;
444 SCJbSetBase64(js, "packet", GET_PKT_DATA(p), max_len);
445
446 if (!SCJbOpenObject(js, "packet_info")) {
447 return;
448 }
449 if (!SCJbSetUint(js, "linktype", p->datalink)) {
450 SCJbClose(js);
451 return;
452 }
453
454 const char *dl_name = DatalinkValueToName(p->datalink);
455
456 // Intentionally ignore the return value from SCJbSetString and proceed
457 // so the jb object is closed
458 (void)SCJbSetString(js, "linktype_name", dl_name == NULL ? "n/a" : dl_name);
459
460 SCJbClose(js);
461}
462
463/** \brief jsonify tcp flags field
464 * Only add 'true' fields in an attempt to keep things reasonably compact.
465 */
466void EveTcpFlags(const uint8_t flags, SCJsonBuilder *js)
467{
468 if (flags & TH_SYN)
469 JB_SET_TRUE(js, "syn");
470 if (flags & TH_FIN)
471 JB_SET_TRUE(js, "fin");
472 if (flags & TH_RST)
473 JB_SET_TRUE(js, "rst");
474 if (flags & TH_PUSH)
475 JB_SET_TRUE(js, "psh");
476 if (flags & TH_ACK)
477 JB_SET_TRUE(js, "ack");
478 if (flags & TH_URG)
479 JB_SET_TRUE(js, "urg");
480 if (flags & TH_ECN)
481 JB_SET_TRUE(js, "ecn");
482 if (flags & TH_CWR)
483 JB_SET_TRUE(js, "cwr");
484}
485
487{
488 char srcip[46] = {0}, dstip[46] = {0};
489 Port sp, dp;
490
491 switch (dir) {
492 case LOG_DIR_PACKET:
493 if (PacketIsIPv4(p)) {
494 PrintInet(AF_INET, (const void *)GET_IPV4_SRC_ADDR_PTR(p),
495 srcip, sizeof(srcip));
496 PrintInet(AF_INET, (const void *)GET_IPV4_DST_ADDR_PTR(p),
497 dstip, sizeof(dstip));
498 } else if (PacketIsIPv6(p)) {
499 PrintInet(AF_INET6, (const void *)GET_IPV6_SRC_ADDR(p),
500 srcip, sizeof(srcip));
501 PrintInet(AF_INET6, (const void *)GET_IPV6_DST_ADDR(p),
502 dstip, sizeof(dstip));
503 } else {
504 /* Not an IP packet so don't do anything */
505 return;
506 }
507 sp = p->sp;
508 dp = p->dp;
509 break;
510 case LOG_DIR_FLOW:
512 if ((PKT_IS_TOSERVER(p))) {
513 if (PacketIsIPv4(p)) {
514 PrintInet(AF_INET, (const void *)GET_IPV4_SRC_ADDR_PTR(p),
515 srcip, sizeof(srcip));
516 PrintInet(AF_INET, (const void *)GET_IPV4_DST_ADDR_PTR(p),
517 dstip, sizeof(dstip));
518 } else if (PacketIsIPv6(p)) {
519 PrintInet(AF_INET6, (const void *)GET_IPV6_SRC_ADDR(p),
520 srcip, sizeof(srcip));
521 PrintInet(AF_INET6, (const void *)GET_IPV6_DST_ADDR(p),
522 dstip, sizeof(dstip));
523 }
524 sp = p->sp;
525 dp = p->dp;
526 } else {
527 if (PacketIsIPv4(p)) {
528 PrintInet(AF_INET, (const void *)GET_IPV4_DST_ADDR_PTR(p),
529 srcip, sizeof(srcip));
530 PrintInet(AF_INET, (const void *)GET_IPV4_SRC_ADDR_PTR(p),
531 dstip, sizeof(dstip));
532 } else if (PacketIsIPv6(p)) {
533 PrintInet(AF_INET6, (const void *)GET_IPV6_DST_ADDR(p),
534 srcip, sizeof(srcip));
535 PrintInet(AF_INET6, (const void *)GET_IPV6_SRC_ADDR(p),
536 dstip, sizeof(dstip));
537 }
538 sp = p->dp;
539 dp = p->sp;
540 }
541 break;
543 if ((PKT_IS_TOCLIENT(p))) {
544 if (PacketIsIPv4(p)) {
545 PrintInet(AF_INET, (const void *)GET_IPV4_SRC_ADDR_PTR(p),
546 srcip, sizeof(srcip));
547 PrintInet(AF_INET, (const void *)GET_IPV4_DST_ADDR_PTR(p),
548 dstip, sizeof(dstip));
549 } else if (PacketIsIPv6(p)) {
550 PrintInet(AF_INET6, (const void *)GET_IPV6_SRC_ADDR(p),
551 srcip, sizeof(srcip));
552 PrintInet(AF_INET6, (const void *)GET_IPV6_DST_ADDR(p),
553 dstip, sizeof(dstip));
554 }
555 sp = p->sp;
556 dp = p->dp;
557 } else {
558 if (PacketIsIPv4(p)) {
559 PrintInet(AF_INET, (const void *)GET_IPV4_DST_ADDR_PTR(p),
560 srcip, sizeof(srcip));
561 PrintInet(AF_INET, (const void *)GET_IPV4_SRC_ADDR_PTR(p),
562 dstip, sizeof(dstip));
563 } else if (PacketIsIPv6(p)) {
564 PrintInet(AF_INET6, (const void *)GET_IPV6_DST_ADDR(p),
565 srcip, sizeof(srcip));
566 PrintInet(AF_INET6, (const void *)GET_IPV6_SRC_ADDR(p),
567 dstip, sizeof(dstip));
568 }
569 sp = p->dp;
570 dp = p->sp;
571 }
572 break;
573 default:
575 return;
576 }
577
578 strlcpy(addr->src_ip, srcip, JSON_ADDR_LEN);
579 strlcpy(addr->dst_ip, dstip, JSON_ADDR_LEN);
580
581 switch (p->proto) {
582 case IPPROTO_UDP:
583 case IPPROTO_TCP:
584 case IPPROTO_SCTP:
585 addr->sp = sp;
586 addr->dp = dp;
587 addr->log_port = true;
588 break;
589 default:
590 addr->log_port = false;
591 break;
592 }
593
594 if (SCProtoNameValid(PacketGetIPProto(p))) {
595 strlcpy(addr->proto, known_proto[PacketGetIPProto(p)], sizeof(addr->proto));
596 } else {
597 snprintf(addr->proto, sizeof(addr->proto), "%" PRIu32, PacketGetIPProto(p));
598 }
599}
600
601#define COMMUNITY_ID_BUF_SIZE 64
602
603static bool CalculateCommunityFlowIdv4(const Flow *f,
604 const uint16_t seed, unsigned char *base64buf)
605{
606 struct {
607 uint16_t seed;
608 uint32_t src;
609 uint32_t dst;
610 uint8_t proto;
611 uint8_t pad0;
612 uint16_t sp;
613 uint16_t dp;
614 } __attribute__((__packed__)) ipv4;
615
616 uint32_t src = f->src.addr_data32[0];
617 uint32_t dst = f->dst.addr_data32[0];
618 uint16_t sp = f->sp;
619 if (f->proto == IPPROTO_ICMP)
620 sp = f->icmp_s.type;
621 sp = htons(sp);
622 uint16_t dp = f->dp;
623 if (f->proto == IPPROTO_ICMP)
624 dp = f->icmp_d.type;
625 dp = htons(dp);
626
627 ipv4.seed = htons(seed);
628 if (ntohl(src) < ntohl(dst) || (src == dst && sp < dp)) {
629 ipv4.src = src;
630 ipv4.dst = dst;
631 ipv4.sp = sp;
632 ipv4.dp = dp;
633 } else {
634 ipv4.src = dst;
635 ipv4.dst = src;
636 ipv4.sp = dp;
637 ipv4.dp = sp;
638 }
639 ipv4.proto = f->proto;
640 ipv4.pad0 = 0;
641
642 uint8_t hash[20];
643 if (SCSha1HashBuffer((const uint8_t *)&ipv4, sizeof(ipv4), hash, sizeof(hash)) == 1) {
644 strlcpy((char *)base64buf, "1:", COMMUNITY_ID_BUF_SIZE);
645 unsigned long out_len = COMMUNITY_ID_BUF_SIZE - 2;
646 if (SCBase64Encode(hash, sizeof(hash), base64buf + 2, &out_len) == SC_BASE64_OK) {
647 return true;
648 }
649 }
650 return false;
651}
652
653static bool CalculateCommunityFlowIdv6(const Flow *f,
654 const uint16_t seed, unsigned char *base64buf)
655{
656 struct {
657 uint16_t seed;
658 uint32_t src[4];
659 uint32_t dst[4];
660 uint8_t proto;
661 uint8_t pad0;
662 uint16_t sp;
663 uint16_t dp;
664 } __attribute__((__packed__)) ipv6;
665
666 uint16_t sp = f->sp;
667 if (f->proto == IPPROTO_ICMPV6)
668 sp = f->icmp_s.type;
669 sp = htons(sp);
670 uint16_t dp = f->dp;
671 if (f->proto == IPPROTO_ICMPV6)
672 dp = f->icmp_d.type;
673 dp = htons(dp);
674
675 ipv6.seed = htons(seed);
676 int cmp_r = memcmp(&f->src, &f->dst, sizeof(f->src));
677 if ((cmp_r < 0) || (cmp_r == 0 && sp < dp)) {
678 memcpy(&ipv6.src, &f->src.addr_data32, 16);
679 memcpy(&ipv6.dst, &f->dst.addr_data32, 16);
680 ipv6.sp = sp;
681 ipv6.dp = dp;
682 } else {
683 memcpy(&ipv6.src, &f->dst.addr_data32, 16);
684 memcpy(&ipv6.dst, &f->src.addr_data32, 16);
685 ipv6.sp = dp;
686 ipv6.dp = sp;
687 }
688 ipv6.proto = f->proto;
689 ipv6.pad0 = 0;
690
691 uint8_t hash[20];
692 if (SCSha1HashBuffer((const uint8_t *)&ipv6, sizeof(ipv6), hash, sizeof(hash)) == 1) {
693 strlcpy((char *)base64buf, "1:", COMMUNITY_ID_BUF_SIZE);
694 unsigned long out_len = COMMUNITY_ID_BUF_SIZE - 2;
695 if (SCBase64Encode(hash, sizeof(hash), base64buf + 2, &out_len) == SC_BASE64_OK) {
696 return true;
697 }
698 }
699 return false;
700}
701
702static void CreateEveCommunityFlowId(SCJsonBuilder *js, const Flow *f, const uint16_t seed)
703{
704 unsigned char buf[COMMUNITY_ID_BUF_SIZE];
705 if (f->flags & FLOW_IPV4) {
706 if (CalculateCommunityFlowIdv4(f, seed, buf)) {
707 SCJbSetString(js, "community_id", (const char *)buf);
708 }
709 } else if (f->flags & FLOW_IPV6) {
710 if (CalculateCommunityFlowIdv6(f, seed, buf)) {
711 SCJbSetString(js, "community_id", (const char *)buf);
712 }
713 }
714}
715
716void CreateEveFlowId(SCJsonBuilder *js, const Flow *f)
717{
718 if (f == NULL) {
719 return;
720 }
721 uint64_t flow_id = FlowGetId(f);
722 SCJbSetUint(js, "flow_id", flow_id);
723 if (f->parent_id) {
724 SCJbSetUint(js, "parent_id", f->parent_id);
725 }
726}
727
728void JSONFormatAndAddMACAddr(SCJsonBuilder *js, const char *key, const uint8_t *val, bool is_array)
729{
730 char eth_addr[19];
731 (void) snprintf(eth_addr, 19, "%02x:%02x:%02x:%02x:%02x:%02x",
732 val[0], val[1], val[2], val[3], val[4], val[5]);
733 if (is_array) {
734 SCJbAppendString(js, eth_addr);
735 } else {
736 SCJbSetString(js, key, eth_addr);
737 }
738}
739
740/* only required to traverse the MAC address set */
741typedef struct JSONMACAddrInfo {
742 SCJsonBuilder *src, *dst;
744
745static int MacSetIterateToJSON(uint8_t *val, MacSetSide side, void *data)
746{
747 JSONMACAddrInfo *info = (JSONMACAddrInfo*) data;
748 if (side == MAC_SET_DST) {
749 JSONFormatAndAddMACAddr(info->dst, NULL, val, true);
750 } else {
751 JSONFormatAndAddMACAddr(info->src, NULL, val, true);
752 }
753 return 0;
754}
755
756static int CreateJSONEther(
757 SCJsonBuilder *js, const Packet *p, const Flow *f, enum SCOutputJsonLogDirection dir)
758{
759 if (p != NULL) {
760 /* this is a packet context, so we need to add scalar fields */
761 if (PacketIsEthernet(p)) {
762 const EthernetHdr *ethh = PacketGetEthernet(p);
763 SCJbOpenObject(js, "ether");
764 SCJbSetUint(js, "ether_type", ethh->eth_type);
765 const uint8_t *src;
766 const uint8_t *dst;
767 switch (dir) {
769 // fallthrough
770 case LOG_DIR_FLOW:
771 if (PKT_IS_TOCLIENT(p)) {
772 src = ethh->eth_dst;
773 dst = ethh->eth_src;
774 } else {
775 src = ethh->eth_src;
776 dst = ethh->eth_dst;
777 }
778 break;
780 if (PKT_IS_TOSERVER(p)) {
781 src = ethh->eth_dst;
782 dst = ethh->eth_src;
783 } else {
784 src = ethh->eth_src;
785 dst = ethh->eth_dst;
786 }
787 break;
788 case LOG_DIR_PACKET:
789 default:
790 src = ethh->eth_src;
791 dst = ethh->eth_dst;
792 break;
793 }
794 JSONFormatAndAddMACAddr(js, "src_mac", src, false);
795 JSONFormatAndAddMACAddr(js, "dest_mac", dst, false);
796 SCJbClose(js);
797 } else if (f != NULL) {
798 /* When pseudopackets do not have associated ethernet metadata,
799 use the first set of mac addresses stored with their flow.
800 The first set of macs should come from the flow's first packet,
801 providing the most fitting representation of the event's ethernet. */
803 if (ms != NULL && MacSetSize(ms) > 0) {
804 uint8_t *src = MacSetGetFirst(ms, MAC_SET_SRC);
805 uint8_t *dst = MacSetGetFirst(ms, MAC_SET_DST);
806 if (dst != NULL && src != NULL) {
807 SCJbOpenObject(js, "ether");
808 JSONFormatAndAddMACAddr(js, "src_mac", src, false);
809 JSONFormatAndAddMACAddr(js, "dest_mac", dst, false);
810 SCJbClose(js);
811 }
812 }
813 }
814 } else if (f != NULL) {
815 /* we are creating an ether object in a flow context, so we need to
816 append to arrays */
818 if (ms != NULL && MacSetSize(ms) > 0) {
819 SCJbOpenObject(js, "ether");
820 JSONMACAddrInfo info;
821 info.dst = SCJbNewArray();
822 info.src = SCJbNewArray();
823 int ret = MacSetForEach(ms, MacSetIterateToJSON, &info);
824 if (unlikely(ret != 0)) {
825 /* should not happen, JSONFlowAppendMACAddrs is sane */
826 SCJbFree(info.dst);
827 SCJbFree(info.src);
828 SCJbClose(js);
829 return ret;
830 }
831 SCJbClose(info.dst);
832 SCJbClose(info.src);
833 /* case is handling netflow too so may need to revert */
834 if (dir == LOG_DIR_FLOW_TOCLIENT) {
835 SCJbSetObject(js, "dest_macs", info.src);
836 SCJbSetObject(js, "src_macs", info.dst);
837 } else {
839 SCJbSetObject(js, "dest_macs", info.dst);
840 SCJbSetObject(js, "src_macs", info.src);
841 }
842 SCJbFree(info.dst);
843 SCJbFree(info.src);
844 SCJbClose(js);
845 }
846 }
847 return 0;
848}
849
850SCJsonBuilder *CreateEveHeader(const Packet *p, enum SCOutputJsonLogDirection dir,
851 const char *event_type, JsonAddrInfo *addr, OutputJsonCtx *eve_ctx)
852{
853 char timebuf[64];
854 const Flow *f = (const Flow *)p->flow;
855
856 SCJsonBuilder *js = SCJbNewObject();
857 if (unlikely(js == NULL)) {
858 return NULL;
859 }
860
861 CreateIsoTimeString(p->ts, timebuf, sizeof(timebuf));
862
863 SCJbSetString(js, "timestamp", timebuf);
864
865 CreateEveFlowId(js, f);
866
867 /* sensor id */
868 if (sensor_id >= 0) {
869 SCJbSetUint(js, "sensor_id", sensor_id);
870 }
871
872 /* input interface */
873 if (p->livedev) {
874 SCJbSetString(js, "in_iface", p->livedev->dev);
875 }
876
877 /* pcap_cnt */
878 if (p->pcap_cnt != 0) {
879 SCJbSetUint(js, "pcap_cnt", p->pcap_cnt);
880 }
881
882 if (event_type) {
883 SCJbSetString(js, "event_type", event_type);
884 }
885
886 /* vlan */
887 if (p->vlan_idx > 0) {
888 SCJbOpenArray(js, "vlan");
889 SCJbAppendUint(js, p->vlan_id[0]);
890 if (p->vlan_idx > 1) {
891 SCJbAppendUint(js, p->vlan_id[1]);
892 }
893 if (p->vlan_idx > 2) {
894 SCJbAppendUint(js, p->vlan_id[2]);
895 }
896 SCJbClose(js);
897 }
898
899 /* 5-tuple */
901 if (addr == NULL) {
902 JsonAddrInfoInit(p, dir, &addr_info);
903 addr = &addr_info;
904 }
905 if (addr->src_ip[0] != '\0') {
906 SCJbSetString(js, "src_ip", addr->src_ip);
907 }
908 if (addr->log_port) {
909 SCJbSetUint(js, "src_port", addr->sp);
910 }
911 if (addr->dst_ip[0] != '\0') {
912 SCJbSetString(js, "dest_ip", addr->dst_ip);
913 }
914 if (addr->log_port) {
915 SCJbSetUint(js, "dest_port", addr->dp);
916 }
917 if (addr->proto[0] != '\0') {
918 SCJbSetString(js, "proto", addr->proto);
919 }
920
921 /* ip version */
922 if (PacketIsIPv4(p)) {
923 SCJbSetUint(js, "ip_v", 4);
924 } else if (PacketIsIPv6(p)) {
925 SCJbSetUint(js, "ip_v", 6);
926 }
927
928 /* icmp */
929 switch (p->proto) {
930 case IPPROTO_ICMP:
931 if (PacketIsICMPv4(p)) {
932 SCJbSetUint(js, "icmp_type", p->icmp_s.type);
933 SCJbSetUint(js, "icmp_code", p->icmp_s.code);
934 }
935 break;
936 case IPPROTO_ICMPV6:
937 if (PacketIsICMPv6(p)) {
938 SCJbSetUint(js, "icmp_type", PacketGetICMPv6(p)->type);
939 SCJbSetUint(js, "icmp_code", PacketGetICMPv6(p)->code);
940 }
941 break;
942 }
943
944 SCJbSetString(js, "pkt_src", PktSrcToString(p->pkt_src));
945
946 if (eve_ctx != NULL) {
947 EveAddCommonOptions(&eve_ctx->cfg, p, f, js, dir);
948 }
949
950 return js;
951}
952
954 const char *event_type, JsonAddrInfo *addr, uint64_t tx_id, OutputJsonCtx *eve_ctx)
955{
956 SCJsonBuilder *js = CreateEveHeader(p, dir, event_type, addr, eve_ctx);
957 if (unlikely(js == NULL))
958 return NULL;
959
960 /* tx id for correlation with other events */
961 SCJbSetUint(js, "tx_id", tx_id);
962
963 return js;
964}
965
966int OutputJSONMemBufferCallback(const char *str, size_t size, void *data)
967{
968 OutputJSONMemBufferWrapper *wrapper = data;
969 MemBuffer **memb = wrapper->buffer;
970
971 if (MEMBUFFER_OFFSET(*memb) + size >= MEMBUFFER_SIZE(*memb)) {
972 MemBufferExpand(memb, wrapper->expand_by);
973 }
974
975 DEBUG_VALIDATE_BUG_ON(size > UINT32_MAX);
976 MemBufferWriteRaw((*memb), (const uint8_t *)str, (uint32_t)size);
977 return 0;
978}
979
980int OutputJSONBuffer(json_t *js, LogFileCtx *file_ctx, MemBuffer **buffer)
981{
982 if (file_ctx->sensor_name) {
983 json_object_set_new(js, "host",
984 json_string(file_ctx->sensor_name));
985 }
986
987 if (file_ctx->is_pcap_offline) {
988 json_object_set_new(js, "pcap_filename", json_string(PcapFileGetFilename()));
989 }
990
991 if (file_ctx->prefix) {
992 MemBufferWriteRaw((*buffer), (const uint8_t *)file_ctx->prefix, file_ctx->prefix_len);
993 }
994
996 .buffer = buffer,
997 .expand_by = JSON_OUTPUT_BUFFER_SIZE
998 };
999
1000 int r = json_dump_callback(js, OutputJSONMemBufferCallback, &wrapper,
1001 file_ctx->json_flags);
1002 if (r != 0)
1003 return TM_ECODE_OK;
1004
1005 LogFileWrite(file_ctx, *buffer);
1006 return 0;
1007}
1008
1010{
1011 LogFileCtx *file_ctx = ctx->file_ctx;
1012 LogFileFlush(file_ctx);
1013}
1014
1016 ThreadVars *tv, const Packet *p, Flow *f, SCJsonBuilder *js, OutputJsonThreadCtx *ctx)
1017{
1018 LogFileCtx *file_ctx = ctx->file_ctx;
1019 MemBuffer **buffer = &ctx->buffer;
1020 if (file_ctx->sensor_name) {
1021 SCJbSetString(js, "host", file_ctx->sensor_name);
1022 }
1023
1024 if (file_ctx->is_pcap_offline) {
1025 SCJbSetString(js, "pcap_filename", PcapFileGetFilename());
1026 }
1027
1028 SCEveRunCallbacks(tv, p, f, js);
1029
1030 SCJbClose(js);
1031
1032 MemBufferReset(*buffer);
1033
1034 if (file_ctx->prefix) {
1035 MemBufferWriteRaw((*buffer), (const uint8_t *)file_ctx->prefix, file_ctx->prefix_len);
1036 }
1037
1038 size_t jslen = SCJbLen(js);
1039 DEBUG_VALIDATE_BUG_ON(SCJbLen(js) > UINT32_MAX);
1040 size_t remaining = MEMBUFFER_SIZE(*buffer) - MEMBUFFER_OFFSET(*buffer);
1041 if (jslen >= remaining) {
1042 size_t expand_by = jslen + 1 - remaining;
1043 if (MemBufferExpand(buffer, (uint32_t)expand_by) < 0) {
1044 if (!ctx->too_large_warning) {
1045 /* Log a warning once, and include enough of the log
1046 * message to hopefully identify the event_type. */
1047 char partial[120];
1048 size_t partial_len = MIN(sizeof(partial), jslen);
1049 memcpy(partial, SCJbPtr(js), partial_len - 1);
1050 partial[partial_len - 1] = '\0';
1051 SCLogWarning("Formatted JSON EVE record too large, will be dropped: %s", partial);
1052 ctx->too_large_warning = true;
1053 }
1054 return;
1055 }
1056 }
1057
1058 MemBufferWriteRaw((*buffer), SCJbPtr(js), (uint32_t)jslen);
1059 LogFileWrite(file_ctx, *buffer);
1060}
1061
1062static inline enum LogFileType FileTypeFromConf(const char *typestr)
1063{
1064 enum LogFileType log_filetype = LOGFILE_TYPE_NOTSET;
1065
1066 if (typestr == NULL) {
1067 log_filetype = LOGFILE_TYPE_FILE;
1068 } else if (strcmp(typestr, "file") == 0 || strcmp(typestr, "regular") == 0) {
1069 log_filetype = LOGFILE_TYPE_FILE;
1070 } else if (strcmp(typestr, "unix_dgram") == 0) {
1071 log_filetype = LOGFILE_TYPE_UNIX_DGRAM;
1072 } else if (strcmp(typestr, "unix_stream") == 0) {
1073 log_filetype = LOGFILE_TYPE_UNIX_STREAM;
1074 } else if (strcmp(typestr, "redis") == 0) {
1075#ifdef HAVE_LIBHIREDIS
1076 log_filetype = LOGFILE_TYPE_REDIS;
1077#else
1078 FatalError("redis JSON output option is not compiled");
1079#endif
1080 }
1081 SCLogDebug("type %s, file type value %d", typestr, log_filetype);
1082 return log_filetype;
1083}
1084
1085static int LogFileTypePrepare(
1086 OutputJsonCtx *json_ctx, enum LogFileType log_filetype, SCConfNode *conf)
1087{
1088
1089 if (log_filetype == LOGFILE_TYPE_FILE || log_filetype == LOGFILE_TYPE_UNIX_DGRAM ||
1090 log_filetype == LOGFILE_TYPE_UNIX_STREAM) {
1091 if (SCConfLogOpenGeneric(conf, json_ctx->file_ctx, DEFAULT_LOG_FILENAME, 1) < 0) {
1092 return -1;
1093 }
1094 }
1095#ifdef HAVE_LIBHIREDIS
1096 else if (log_filetype == LOGFILE_TYPE_REDIS) {
1097 SCLogRedisInit();
1098 SCConfNode *redis_node = SCConfNodeLookupChild(conf, "redis");
1099 if (!json_ctx->file_ctx->sensor_name) {
1100 char hostname[1024];
1101 gethostname(hostname, 1023);
1102 json_ctx->file_ctx->sensor_name = SCStrdup(hostname);
1103 }
1104 if (json_ctx->file_ctx->sensor_name == NULL) {
1105 return -1;
1106 }
1107
1108 if (SCConfLogOpenRedis(redis_node, json_ctx->file_ctx) < 0) {
1109 return -1;
1110 }
1111 }
1112#endif
1113 else if (log_filetype == LOGFILE_TYPE_FILETYPE) {
1114 if (json_ctx->file_ctx->threaded) {
1115 /* Prepare for threaded log output. */
1116 if (!SCLogOpenThreadedFile(NULL, NULL, json_ctx->file_ctx)) {
1117 return -1;
1118 }
1119 }
1120 if (json_ctx->filetype->Init(conf, json_ctx->file_ctx->threaded,
1121 &json_ctx->file_ctx->filetype.init_data) < 0) {
1122 return -1;
1123 }
1124 if (json_ctx->filetype->ThreadInit) {
1125 if (json_ctx->filetype->ThreadInit(json_ctx->file_ctx->filetype.init_data, 0,
1126 &json_ctx->file_ctx->filetype.thread_data) < 0) {
1127 return -1;
1128 }
1129 }
1130 json_ctx->file_ctx->filetype.filetype = json_ctx->filetype;
1131 }
1132
1133 return 0;
1134}
1135
1136/**
1137 * \brief Create a new LogFileCtx for "fast" output style.
1138 * \param conf The configuration node for this output.
1139 * \return A LogFileCtx pointer on success, NULL on failure.
1140 */
1142{
1143 OutputInitResult result = { NULL, false };
1144 OutputCtx *output_ctx = NULL;
1145
1146 OutputJsonCtx *json_ctx = SCCalloc(1, sizeof(OutputJsonCtx));
1147 if (unlikely(json_ctx == NULL)) {
1148 SCLogDebug("could not create new OutputJsonCtx");
1149 return result;
1150 }
1151
1152 /* First lookup a sensor-name value in this outputs configuration
1153 * node (deprecated). If that fails, lookup the global one. */
1154 const char *sensor_name = SCConfNodeLookupChildValue(conf, "sensor-name");
1155 if (sensor_name != NULL) {
1156 SCLogWarning("Found deprecated eve-log setting \"sensor-name\". "
1157 "Please set sensor-name globally.");
1158 }
1159 else {
1160 (void)SCConfGet("sensor-name", &sensor_name);
1161 }
1162
1163 json_ctx->file_ctx = LogFileNewCtx();
1164 if (unlikely(json_ctx->file_ctx == NULL)) {
1165 SCLogDebug("AlertJsonInitCtx: Could not create new LogFileCtx");
1166 goto error_exit;
1167 }
1168
1169 if (sensor_name) {
1170 json_ctx->file_ctx->sensor_name = SCStrdup(sensor_name);
1171 if (json_ctx->file_ctx->sensor_name == NULL) {
1172 goto error_exit;
1173 }
1174 } else {
1175 json_ctx->file_ctx->sensor_name = NULL;
1176 }
1177
1178 output_ctx = SCCalloc(1, sizeof(OutputCtx));
1179 if (unlikely(output_ctx == NULL)) {
1180 goto error_exit;
1181 }
1182
1183 output_ctx->data = json_ctx;
1184 output_ctx->DeInit = OutputJsonDeInitCtx;
1185
1186 if (conf) {
1187 const char *output_s = SCConfNodeLookupChildValue(conf, "filetype");
1188 // Backwards compatibility
1189 if (output_s == NULL) {
1190 output_s = SCConfNodeLookupChildValue(conf, "type");
1191 }
1192
1193 enum LogFileType log_filetype = FileTypeFromConf(output_s);
1194 if (log_filetype == LOGFILE_TYPE_NOTSET) {
1195 SCEveFileType *filetype = SCEveFindFileType(output_s);
1196 if (filetype != NULL) {
1197 log_filetype = LOGFILE_TYPE_FILETYPE;
1198 json_ctx->filetype = filetype;
1199 } else
1200 FatalError("Invalid JSON output option: %s", output_s);
1201 }
1202
1203 const char *prefix = SCConfNodeLookupChildValue(conf, "prefix");
1204 if (prefix != NULL)
1205 {
1206 SCLogInfo("Using prefix '%s' for JSON messages", prefix);
1207 json_ctx->file_ctx->prefix = SCStrdup(prefix);
1208 if (json_ctx->file_ctx->prefix == NULL)
1209 {
1210 FatalError("Failed to allocate memory for eve-log.prefix setting.");
1211 }
1212 json_ctx->file_ctx->prefix_len = (uint32_t)strlen(prefix);
1213 }
1214
1215 /* Threaded file output */
1216 const SCConfNode *threaded = SCConfNodeLookupChild(conf, "threaded");
1217 if (threaded && threaded->val && SCConfValIsTrue(threaded->val)) {
1218 SCLogConfig("Threaded EVE logging configured");
1219 json_ctx->file_ctx->threaded = true;
1220 } else {
1221 json_ctx->file_ctx->threaded = false;
1222 }
1223 if (LogFileTypePrepare(json_ctx, log_filetype, conf) < 0) {
1224 goto error_exit;
1225 }
1226
1227 const char *sensor_id_s = SCConfNodeLookupChildValue(conf, "sensor-id");
1228 if (sensor_id_s != NULL) {
1229 if (StringParseUint64((uint64_t *)&sensor_id, 10, 0, sensor_id_s) < 0) {
1230 FatalError("Failed to initialize JSON output, "
1231 "invalid sensor-id: %s",
1232 sensor_id_s);
1233 }
1234 }
1235
1236 /* Check if top-level metadata should be logged. */
1237 const SCConfNode *metadata = SCConfNodeLookupChild(conf, "metadata");
1238 if (metadata && metadata->val && SCConfValIsFalse(metadata->val)) {
1239 SCLogConfig("Disabling eve metadata logging.");
1240 json_ctx->cfg.include_metadata = false;
1241 } else {
1242 json_ctx->cfg.include_metadata = true;
1243 }
1244
1245 /* Check if ethernet information should be logged. */
1246 const SCConfNode *ethernet = SCConfNodeLookupChild(conf, "ethernet");
1247 if (ethernet && ethernet->val && SCConfValIsTrue(ethernet->val)) {
1248 SCLogConfig("Enabling Ethernet MAC address logging.");
1249 json_ctx->cfg.include_ethernet = true;
1250 } else {
1251 json_ctx->cfg.include_ethernet = false;
1252 }
1253
1254 const SCConfNode *suriver = SCConfNodeLookupChild(conf, "suricata-version");
1255 if (suriver && suriver->val && SCConfValIsTrue(suriver->val)) {
1256 SCLogConfig("Enabling Suricata version logging.");
1257 json_ctx->cfg.include_suricata_version = true;
1258 } else {
1259 json_ctx->cfg.include_suricata_version = false;
1260 }
1261
1262 /* See if we want to enable the community id */
1263 const SCConfNode *community_id = SCConfNodeLookupChild(conf, "community-id");
1264 if (community_id && community_id->val && SCConfValIsTrue(community_id->val)) {
1265 SCLogConfig("Enabling eve community_id logging.");
1266 json_ctx->cfg.include_community_id = true;
1267 } else {
1268 json_ctx->cfg.include_community_id = false;
1269 }
1270 const char *cid_seed = SCConfNodeLookupChildValue(conf, "community-id-seed");
1271 if (cid_seed != NULL) {
1273 10, 0, cid_seed) < 0)
1274 {
1275 FatalError("Failed to initialize JSON output, "
1276 "invalid community-id-seed: %s",
1277 cid_seed);
1278 }
1279 }
1280
1281 /* Do we have a global eve xff configuration? */
1282 const SCConfNode *xff = SCConfNodeLookupChild(conf, "xff");
1283 if (xff != NULL) {
1284 json_ctx->xff_cfg = SCCalloc(1, sizeof(HttpXFFCfg));
1285 if (likely(json_ctx->xff_cfg != NULL)) {
1286 HttpXFFGetCfg(conf, json_ctx->xff_cfg);
1287 }
1288 }
1289
1290 const char *pcapfile_s = SCConfNodeLookupChildValue(conf, "pcap-file");
1291 if (pcapfile_s != NULL && SCConfValIsTrue(pcapfile_s)) {
1292 json_ctx->file_ctx->is_pcap_offline =
1294 }
1295 json_ctx->file_ctx->type = log_filetype;
1296 }
1297
1298 SCLogDebug("returning output_ctx %p", output_ctx);
1299
1300 result.ctx = output_ctx;
1301 result.ok = true;
1302 return result;
1303
1304error_exit:
1305 if (json_ctx->file_ctx) {
1306 if (json_ctx->file_ctx->prefix) {
1307 SCFree(json_ctx->file_ctx->prefix);
1308 }
1309 LogFileFreeCtx(json_ctx->file_ctx);
1310 }
1311 SCFree(json_ctx);
1312
1313 if (output_ctx) {
1314 SCFree(output_ctx);
1315 }
1316 return result;
1317}
1318
1319static void OutputJsonDeInitCtx(OutputCtx *output_ctx)
1320{
1321 OutputJsonCtx *json_ctx = (OutputJsonCtx *)output_ctx->data;
1322 LogFileCtx *logfile_ctx = json_ctx->file_ctx;
1323 if (logfile_ctx->dropped) {
1324 SCLogWarning("%" PRIu64 " events were dropped due to slow or "
1325 "disconnected socket",
1326 logfile_ctx->dropped);
1327 }
1328 if (json_ctx->xff_cfg != NULL) {
1329 SCFree(json_ctx->xff_cfg);
1330 }
1331 LogFileFreeCtx(logfile_ctx);
1332 SCFree(json_ctx);
1333 SCFree(output_ctx);
1334}
uint8_t len
uint16_t dst
uint16_t src
void HttpXFFGetCfg(SCConfNode *conf, HttpXFFCfg *result)
Function to return XFF configuration from a configuration node.
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
int SCConfValIsFalse(const char *val)
Check if a value is false.
Definition conf.c:576
int SCConfGet(const char *name, const char **vptr)
Retrieve the value of a configuration node.
Definition conf.c:350
uint8_t flags
Definition decode-gre.h:0
#define TH_FIN
Definition decode-tcp.h:34
#define TH_ACK
Definition decode-tcp.h:38
#define TH_CWR
Definition decode-tcp.h:43
#define TH_PUSH
Definition decode-tcp.h:37
#define TH_URG
Definition decode-tcp.h:39
#define TH_RST
Definition decode-tcp.h:36
#define TH_SYN
Definition decode-tcp.h:35
#define TH_ECN
Definition decode-tcp.h:41
uint8_t pad0
uint8_t proto
uint16_t type
#define GET_IPV6_DST_ADDR(p)
Definition decode.h:204
#define GET_IPV4_SRC_ADDR_PTR(p)
Definition decode.h:198
#define GET_PKT_DATA(p)
Definition decode.h:209
#define GET_IPV6_SRC_ADDR(p)
Definition decode.h:203
#define PKT_IS_TOCLIENT(p)
Definition decode.h:239
#define GET_PKT_LEN(p)
Definition decode.h:208
#define PKT_IS_TOSERVER(p)
Definition decode.h:238
uint16_t Port
Definition decode.h:218
#define GET_IPV4_DST_ADDR_PTR(p)
Definition decode.h:199
#define IPPROTO_SCTP
Definition decode.h:1228
@ DETECT_FLOWBITS
struct PrefilterEngineFlowbits __attribute__
DNP3 application header.
void * FlowGetStorageById(const Flow *f, FlowStorageId id)
#define FLOWVAR_TYPE_INT
Definition flow-var.h:34
#define FLOWVAR_TYPE_STR
Definition flow-var.h:33
#define FLOWVAR_TYPE_FLOAT
Definition flow-var.h:35
#define FLOW_IPV6
Definition flow.h:102
#define FLOW_IPV4
Definition flow.h:100
ThreadVars * tv
const char * PktSrcToString(enum PktSrcEnum pkt_src)
Definition decode.c:855
struct Thresholds ctx
SCOutputJsonLogDirection
@ LOG_DIR_PACKET
@ LOG_DIR_FLOW
@ LOG_DIR_FLOW_TOSERVER
@ LOG_DIR_FLOW_TOCLIENT
void NullLogInitialize(void)
void SyslogInitialize(void)
void SCEveRunCallbacks(ThreadVars *tv, const Packet *p, Flow *f, SCJsonBuilder *jb)
Definition output-eve.c:53
SCEveFileType * SCEveFindFileType(const char *name)
Definition output-eve.c:82
void OutputJsonFlush(OutputJsonThreadCtx *ctx)
#define MODULE_NAME
Definition output-json.c:67
void EveTcpFlags(const uint8_t flags, SCJsonBuilder *js)
jsonify tcp flags field Only add 'true' fields in an attempt to keep things reasonably compact.
#define COMMUNITY_ID_BUF_SIZE
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)
#define MAX_JSON_SIZE
Definition output-json.c:69
void JsonAddrInfoInit(const Packet *p, enum SCOutputJsonLogDirection dir, JsonAddrInfo *addr)
void EvePacket(const Packet *p, SCJsonBuilder *js, uint32_t max_length)
Jsonify a packet.
int OutputJSONMemBufferCallback(const char *str, size_t size, void *data)
#define DEFAULT_LOG_FILENAME
Definition output-json.c:66
const JsonAddrInfo json_addr_info_zero
Definition output-json.c:81
OutputInitResult OutputJsonInitCtx(SCConfNode *conf)
Create a new LogFileCtx for "fast" output style.
void OutputJsonRegister(void)
Definition output-json.c:83
void EveAddMetadata(const Packet *p, const Flow *f, SCJsonBuilder *js)
int OutputJSONBuffer(json_t *js, LogFileCtx *file_ctx, MemBuffer **buffer)
void JSONFormatAndAddMACAddr(SCJsonBuilder *js, const char *key, const uint8_t *val, bool is_array)
json_t * SCJsonString(const char *val)
Definition output-json.c:96
void OutputJsonBuilderBuffer(ThreadVars *tv, const Packet *p, Flow *f, SCJsonBuilder *js, OutputJsonThreadCtx *ctx)
void CreateEveFlowId(SCJsonBuilder *js, const Flow *f)
SCJsonBuilder * CreateEveHeaderWithTxId(const Packet *p, enum SCOutputJsonLogDirection dir, const char *event_type, JsonAddrInfo *addr, uint64_t tx_id, OutputJsonCtx *eve_ctx)
void EveAddCommonOptions(const OutputJsonCommonSettings *cfg, const Packet *p, const Flow *f, SCJsonBuilder *js, enum SCOutputJsonLogDirection dir)
#define JSON_ADDR_LEN
Definition output-json.h:37
#define JSON_OUTPUT_BUFFER_SIZE
Definition output-json.h:56
void OutputRegisterModule(const char *, const char *, OutputInitFunc)
@ RUNMODE_PCAP_FILE
Definition runmodes.h:30
@ RUNMODE_UNIX_SOCKET
Definition runmodes.h:42
#define JB_SET_TRUE(jb, key)
Definition rust.h:27
#define JB_SET_STRING(jb, key, val)
Definition rust.h:26
#define JB_SET_FALSE(jb, key)
Definition rust.h:28
const char * PcapFileGetFilename(void)
uint8_t * name
Definition util-file.h:88
uint16_t name_len
Definition util-file.h:81
uint8_t md5[SC_MD5_LEN]
Definition util-file.h:94
uint64_t end
Definition util-file.h:106
uint32_t sid_cnt
Definition util-file.h:109
uint16_t flags
Definition util-file.h:80
FileState state
Definition util-file.h:82
uint8_t sha256[SC_SHA256_LEN]
Definition util-file.h:98
uint32_t * sid
Definition util-file.h:108
uint8_t sha1[SC_SHA1_LEN]
Definition util-file.h:96
uint32_t file_store_id
Definition util-file.h:85
uint64_t start
Definition util-file.h:105
uint32_t idx
Definition flow-bit.h:33
uint32_t value
Definition flow-var.h:46
uint16_t value_len
Definition flow-var.h:41
uint8_t * value
Definition flow-var.h:40
uint8_t datatype
Definition flow-var.h:57
uint32_t idx
Definition flow-var.h:59
FlowVarTypeInt fv_int
Definition flow-var.h:65
FlowVarKeyLenType keylen
Definition flow-var.h:58
uint8_t * key
Definition flow-var.h:68
FlowVarTypeStr fv_str
Definition flow-var.h:64
FlowVarTypeFloat fv_float
Definition flow-var.h:66
union FlowVar_::@124 data
Flow data structure.
Definition flow.h:356
struct Flow_::@129::@135 icmp_s
Port dp
Definition flow.h:372
uint8_t proto
Definition flow.h:378
uint32_t flags
Definition flow.h:421
GenericVar * flowvar
Definition flow.h:489
uint32_t tenant_id
Definition flow.h:416
struct Flow_::@131::@137 icmp_d
FlowAddress src
Definition flow.h:359
Port sp
Definition flow.h:361
int64_t parent_id
Definition flow.h:430
FlowAddress dst
Definition flow.h:359
uint8_t type
Definition flow.h:363
uint16_t type
Definition util-var.h:54
struct GenericVar_ * next
Definition util-var.h:57
SCJsonBuilder * src
SCJsonBuilder * dst
char proto[JSON_PROTO_LEN]
Definition output-json.h:46
char src_ip[JSON_ADDR_LEN]
Definition output-json.h:42
char dst_ip[JSON_ADDR_LEN]
Definition output-json.h:43
uint32_t prefix_len
LogFileTypeCtx filetype
enum LogFileType type
SCEveFileType * filetype
void * data
Definition tm-modules.h:91
void(* DeInit)(struct OutputCtx_ *)
Definition tm-modules.h:94
OutputCtx * ctx
Definition output.h:47
SCEveFileType * filetype
Definition output-json.h:80
OutputJsonCommonSettings cfg
Definition output-json.h:78
HttpXFFCfg * xff_cfg
Definition output-json.h:79
LogFileCtx * file_ctx
Definition output-json.h:76
struct Packet_::@33::@40 icmp_s
uint64_t pcap_cnt
Definition decode.h:626
SCTime_t ts
Definition decode.h:555
uint8_t pkt_src
Definition decode.h:611
Port sp
Definition decode.h:508
uint8_t code
Definition decode.h:512
uint8_t type
Definition decode.h:511
PktVar * pktvar
Definition decode.h:597
struct Flow_ * flow
Definition decode.h:546
uint16_t vlan_id[VLAN_MAX_LAYERS]
Definition decode.h:528
int datalink
Definition decode.h:639
struct LiveDevice_ * livedev
Definition decode.h:618
uint8_t vlan_idx
Definition decode.h:529
uint8_t proto
Definition decode.h:523
Port dp
Definition decode.h:516
struct PktVar_ * next
Definition decode.h:313
uint16_t value_len
Definition decode.h:317
uint32_t id
Definition decode.h:312
uint8_t * key
Definition decode.h:318
uint8_t * value
Definition decode.h:319
uint16_t key_len
Definition decode.h:316
char * val
Definition conf.h:39
Structure used to define an EVE output file type plugin.
Definition output-eve.h:74
int(* Init)(const SCConfNode *conf, const bool threaded, void **init_data)
Function to initialize this filetype.
Definition output-eve.h:104
int(* ThreadInit)(const void *init_data, const ThreadId thread_id, void **thread_data)
Initialize thread specific data.
Definition output-eve.h:125
Per thread variable structure.
Definition threadvars.h:58
#define MIN(x, y)
#define str(s)
size_t strlcpy(char *dst, const char *src, size_t siz)
SCRunMode SCRunmodeGet(void)
Get the current run mode.
Definition suricata.c:279
#define PROG_VER
Definition suricata.h:76
@ TM_ECODE_OK
int MemBufferExpand(MemBuffer **buffer, uint32_t expand_by)
expand membuffer by size of 'expand_by'
Definition util-buffer.c:60
uint32_t MemBufferWriteRaw(MemBuffer *dst, const uint8_t *raw, const uint32_t raw_len)
Write a raw buffer to the MemBuffer dst.
#define MEMBUFFER_SIZE(mem_buffer)
Get the MemBuffers current size.
Definition util-buffer.h:61
#define MEMBUFFER_OFFSET(mem_buffer)
Get the MemBuffers current offset.
Definition util-buffer.h:56
int StringParseUint16(uint16_t *res, int base, size_t len, const char *str)
Definition util-byte.c:337
int StringParseUint64(uint64_t *res, int base, size_t len, const char *str)
Definition util-byte.c:308
#define FatalError(...)
Definition util-debug.h:510
#define SCLogDebug(...)
Definition util-debug.h:275
#define SCLogWarning(...)
Macro used to log WARNING messages.
Definition util-debug.h:255
#define SCLogInfo(...)
Macro used to log INFORMATIONAL messages.
Definition util-debug.h:225
#define SCLogConfig(...)
Definition util-debug.h:229
uint64_t FileTrackedSize(const File *file)
get the size of the file
Definition util-file.c:326
#define FILE_HAS_GAPS
Definition util-file.h:59
#define FILE_SHA256
Definition util-file.h:52
#define FILE_MD5
Definition util-file.h:48
#define FILE_STORED
Definition util-file.h:56
@ FILE_STATE_TRUNCATED
Definition util-file.h:73
@ FILE_STATE_ERROR
Definition util-file.h:75
@ FILE_STATE_CLOSED
Definition util-file.h:71
#define FILE_STORE
Definition util-file.h:55
#define FILE_SHA1
Definition util-file.h:50
int LogFileWrite(LogFileCtx *file_ctx, MemBuffer *buffer)
bool SCLogOpenThreadedFile(const char *log_path, const char *append, LogFileCtx *parent_ctx)
int LogFileFreeCtx(LogFileCtx *lf_ctx)
LogFileFreeCtx() Destroy a LogFileCtx (Close the file and free memory)
LogFileCtx * LogFileNewCtx(void)
LogFileNewCtx() Get a new LogFileCtx.
int SCConfLogOpenGeneric(SCConfNode *conf, LogFileCtx *log_ctx, const char *default_filename, int rotate)
open a generic output "log file", which may be a regular file or a socket
void LogFileFlush(LogFileCtx *file_ctx)
LogFileType
@ LOGFILE_TYPE_REDIS
@ LOGFILE_TYPE_FILETYPE
@ LOGFILE_TYPE_FILE
@ LOGFILE_TYPE_UNIX_STREAM
@ LOGFILE_TYPE_NOTSET
@ LOGFILE_TYPE_UNIX_DGRAM
uint8_t * MacSetGetFirst(const MacSet *ms, MacSetSide side)
FlowStorageId MacSetGetFlowStorageID(void)
int MacSetForEach(const MacSet *ms, MacSetIteratorFunc IterFunc, void *data)
int MacSetSize(const MacSet *ms)
MacSetSide
Definition util-macset.h:28
@ MAC_SET_DST
Definition util-macset.h:30
@ MAC_SET_SRC
Definition util-macset.h:29
#define SCFree(p)
Definition util-mem.h:61
#define SCCalloc(nm, sz)
Definition util-mem.h:53
#define SCStrdup(s)
Definition util-mem.h:56
#define likely(expr)
#define unlikely(expr)
const char * PrintInet(int af, const void *src, char *dst, socklen_t size)
Definition util-print.c:231
void PrintStringsToBuffer(uint8_t *dst_buf, uint32_t *dst_buf_offset_ptr, uint32_t dst_buf_size, const uint8_t *src_buf, const uint32_t src_buf_len)
Definition util-print.c:195
#define PrintBufferData(buf, buf_offset_ptr, buf_size,...)
Definition util-print.h:27
bool SCProtoNameValid(uint16_t proto)
Function to check if the received protocol number is valid and do we have corresponding name entry fo...
const char * known_proto[256]
uint64_t offset
void CreateIsoTimeString(const SCTime_t ts, char *str, size_t size)
Definition util-time.c:209
#define DEBUG_VALIDATE_BUG_ON(exp)
const char * VarNameStoreLookupById(const uint32_t id, const enum VarTypes type)
find name for id+type at packet time. As the active store won't be modified, we don't need locks.
@ VAR_TYPE_FLOW_FLOAT
Definition util-var.h:38
@ VAR_TYPE_FLOW_BIT
Definition util-var.h:36
@ VAR_TYPE_FLOW_VAR
Definition util-var.h:39
@ VAR_TYPE_PKT_VAR
Definition util-var.h:33
@ VAR_TYPE_FLOW_INT
Definition util-var.h:37