From: Jason Ish Date: Sun, 15 Mar 2020 17:05:16 +0000 (-0600) Subject: alert/eve: convert to jsonbuilder X-Git-Tag: suricata-6.0.0-beta1~385 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=30cc373b7fd44316cbe220831e8463cb99842ff5;p=thirdparty%2Fsuricata.git alert/eve: convert to jsonbuilder Convert alert Eve logging JsonBuilder. Currently makes heavy use of JsonBuilder being able to log Jansson's json_t which is a temporary measure until all protocols loggers can be converted to JsonBuilder. New functions that replace Jansson versions with JsonBuilder variations use "Eve" instead of "JSON". --- diff --git a/src/output-json-alert.c b/src/output-json-alert.c index ee64fb151c..fed8b3c2b7 100644 --- a/src/output-json-alert.c +++ b/src/output-json-alert.c @@ -127,7 +127,7 @@ static int AlertJsonDumpStreamSegmentCallback(const Packet *p, void *data, const return 1; } -static void AlertJsonTls(const Flow *f, json_t *js) +static void AlertJsonTls(const Flow *f, JsonBuilder *js) { SSLState *ssl_state = (SSLState *)FlowGetAppState(f); if (ssl_state) { @@ -138,13 +138,14 @@ static void AlertJsonTls(const Flow *f, json_t *js) JsonTlsLogJSONBasic(tjs, ssl_state); JsonTlsLogJSONExtended(tjs, ssl_state); - json_object_set_new(js, "tls", tjs); + jb_set_jsont(js, "tls", tjs); + json_decref(tjs); } return; } -static void AlertJsonSsh(const Flow *f, json_t *js) +static void AlertJsonSsh(const Flow *f, JsonBuilder *js) { void *ssh_state = FlowGetAppState(f); if (ssh_state) { @@ -153,13 +154,14 @@ static void AlertJsonSsh(const Flow *f, json_t *js) if (unlikely(tjs == NULL)) return; - json_object_set_new(js, "ssh", tjs); + jb_set_jsont(js, "ssh", tjs); + json_decref(tjs); } return; } -static void AlertJsonDnp3(const Flow *f, const uint64_t tx_id, json_t *js) +static void AlertJsonDnp3(const Flow *f, const uint64_t tx_id, JsonBuilder *js) { DNP3State *dnp3_state = (DNP3State *)FlowGetAppState(f); if (dnp3_state) { @@ -180,7 +182,8 @@ static void AlertJsonDnp3(const Flow *f, const uint64_t tx_id, json_t *js) json_object_set_new(dnp3js, "response", response); } } - json_object_set_new(js, "dnp3", dnp3js); + jb_set_jsont(js, "dnp3", dnp3js); + json_decref(dnp3js); } } } @@ -188,7 +191,7 @@ static void AlertJsonDnp3(const Flow *f, const uint64_t tx_id, json_t *js) return; } -static void AlertJsonDns(const Flow *f, const uint64_t tx_id, json_t *js) +static void AlertJsonDns(const Flow *f, const uint64_t tx_id, JsonBuilder *js) { void *dns_state = (void *)FlowGetAppState(f); if (dns_state) { @@ -207,29 +210,47 @@ static void AlertJsonDns(const Flow *f, const uint64_t tx_id, json_t *js) if (ajs != NULL) { json_object_set_new(dnsjs, "answer", ajs); } - json_object_set_new(js, "dns", dnsjs); + jb_set_jsont(js, "dns", dnsjs); + json_decref(dnsjs); } } return; } static void AlertJsonSourceTarget(const Packet *p, const PacketAlert *pa, - json_t* ajs, JsonAddrInfo *addr) + JsonBuilder *js, JsonAddrInfo *addr) { - json_t *sjs = json_object(); - if (sjs == NULL) { - return; - } - - json_t *tjs = json_object(); - if (tjs == NULL) { - json_decref(sjs); - return; + jb_open_object(js, "source"); + if (pa->s->flags & SIG_FLAG_DEST_IS_TARGET) { + jb_set_string(js, "ip", addr->src_ip); + switch (p->proto) { + case IPPROTO_ICMP: + case IPPROTO_ICMPV6: + break; + case IPPROTO_UDP: + case IPPROTO_TCP: + case IPPROTO_SCTP: + jb_set_uint(js, "port", addr->sp); + break; + } + } else if (pa->s->flags & SIG_FLAG_SRC_IS_TARGET) { + jb_set_string(js, "ip", addr->dst_ip); + switch (p->proto) { + case IPPROTO_ICMP: + case IPPROTO_ICMPV6: + break; + case IPPROTO_UDP: + case IPPROTO_TCP: + case IPPROTO_SCTP: + jb_set_uint(js, "port", addr->dp); + break; + } } + jb_close(js); + jb_open_object(js, "target"); if (pa->s->flags & SIG_FLAG_DEST_IS_TARGET) { - json_object_set(sjs, "ip", json_string(addr->src_ip)); - json_object_set(tjs, "ip", json_string(addr->dst_ip)); + jb_set_string(js, "ip", addr->dst_ip); switch (p->proto) { case IPPROTO_ICMP: case IPPROTO_ICMPV6: @@ -237,13 +258,11 @@ static void AlertJsonSourceTarget(const Packet *p, const PacketAlert *pa, case IPPROTO_UDP: case IPPROTO_TCP: case IPPROTO_SCTP: - json_object_set(sjs, "port", json_integer(addr->sp)); - json_object_set(tjs, "port", json_integer(addr->dp)); + jb_set_uint(js, "port", addr->dp); break; } } else if (pa->s->flags & SIG_FLAG_SRC_IS_TARGET) { - json_object_set(sjs, "ip", json_string(addr->dst_ip)); - json_object_set(tjs, "ip", json_string(addr->src_ip)); + jb_set_string(js, "ip", addr->src_ip); switch (p->proto) { case IPPROTO_ICMP: case IPPROTO_ICMPV6: @@ -251,16 +270,15 @@ static void AlertJsonSourceTarget(const Packet *p, const PacketAlert *pa, case IPPROTO_UDP: case IPPROTO_TCP: case IPPROTO_SCTP: - json_object_set(sjs, "port", json_integer(addr->dp)); - json_object_set(tjs, "port", json_integer(addr->sp)); + jb_set_uint(js, "port", addr->sp); break; } } - json_object_set_new(ajs, "source", sjs); - json_object_set_new(ajs, "target", tjs); + jb_close(js); } -static void AlertJsonMetadata(AlertJsonOutputCtx *json_output_ctx, const PacketAlert *pa, json_t *ajs) +static void AlertJsonMetadata(AlertJsonOutputCtx *json_output_ctx, + const PacketAlert *pa, JsonBuilder *ajs) { if (pa->s->metadata) { const DetectMetadata* kv = pa->s->metadata; @@ -283,17 +301,15 @@ static void AlertJsonMetadata(AlertJsonOutputCtx *json_output_ctx, const PacketA kv = kv->next; } - if (json_object_size(mjs) == 0) { - json_decref(mjs); - } else { - json_object_set_new(ajs, "metadata", mjs); + if (json_object_size(mjs) > 0) { + jb_set_jsont(ajs, "metadata", mjs); } + json_decref(mjs); } } - -void AlertJsonHeader(void *ctx, const Packet *p, const PacketAlert *pa, json_t *js, - uint16_t flags, JsonAddrInfo *addr) +void AlertJsonHeader(void *ctx, const Packet *p, const PacketAlert *pa, + JsonBuilder *js, uint16_t flags, JsonAddrInfo *addr) { AlertJsonOutputCtx *json_output_ctx = (AlertJsonOutputCtx *)ctx; const char *action = "allowed"; @@ -312,74 +328,76 @@ void AlertJsonHeader(void *ctx, const Packet *p, const PacketAlert *pa, json_t * } /* Add tx_id to root element for correlation with other events. */ - json_object_del(js, "tx_id"); - if (pa->flags & PACKET_ALERT_FLAG_TX) - json_object_set_new(js, "tx_id", json_integer(pa->tx_id)); - - json_t *ajs = json_object(); - if (ajs == NULL) { - return; + /* json_object_del(js, "tx_id"); */ + if (pa->flags & PACKET_ALERT_FLAG_TX) { + jb_set_uint(js, "tx_id", pa->tx_id); } - json_object_set_new(ajs, "action", json_string(action)); - json_object_set_new(ajs, "gid", json_integer(pa->s->gid)); - json_object_set_new(ajs, "signature_id", json_integer(pa->s->id)); - json_object_set_new(ajs, "rev", json_integer(pa->s->rev)); - json_object_set_new(ajs, "signature", - SCJsonString((pa->s->msg) ? pa->s->msg : "")); - json_object_set_new(ajs, "category", - SCJsonString((pa->s->class_msg) ? pa->s->class_msg : "")); - json_object_set_new(ajs, "severity", json_integer(pa->s->prio)); + jb_open_object(js, "alert"); - if (p->tenant_id > 0) - json_object_set_new(ajs, "tenant_id", json_integer(p->tenant_id)); + jb_set_string(js, "action", action); + jb_set_uint(js, "gid", pa->s->gid); + jb_set_uint(js, "signature_id", pa->s->id); + jb_set_uint(js, "rev", pa->s->rev); + /* TODO: JsonBuilder should handle unprintable characters like + * SCJsonString. */ + jb_set_string(js, "signature", pa->s->msg ? pa->s->msg: ""); + jb_set_string(js, "category", pa->s->class_msg ? pa->s->class_msg: ""); + jb_set_uint(js, "severity", pa->s->prio); + + if (p->tenant_id > 0) { + jb_set_uint(js, "tenant_id", p->tenant_id); + } if (addr && pa->s->flags & SIG_FLAG_HAS_TARGET) { - AlertJsonSourceTarget(p, pa, ajs, addr); + AlertJsonSourceTarget(p, pa, js, addr); } if ((json_output_ctx != NULL) && (flags & LOG_JSON_RULE_METADATA)) { - AlertJsonMetadata(json_output_ctx, pa, ajs); + AlertJsonMetadata(json_output_ctx, pa, js); } if (flags & LOG_JSON_RULE) { - json_object_set_new(ajs, "rule", json_string(pa->s->sig_str)); + jb_set_string(js, "rule", pa->s->sig_str); } - /* alert */ - json_object_set_new(js, "alert", ajs); + jb_close(js); } -static void AlertJsonTunnel(const Packet *p, json_t *js) +static void AlertJsonTunnel(const Packet *p, JsonBuilder *js) { - json_t *tunnel = json_object(); - if (tunnel == NULL) - return; - if (p->root == NULL) { - json_decref(tunnel); return; } + jb_open_object(js, "tunnel"); + /* get a lock to access root packet fields */ SCMutex *m = &p->root->tunnel_mutex; + JsonAddrInfo addr = json_addr_info_zero; SCMutexLock(m); - JsonFiveTuple((const Packet *)p->root, 0, tunnel); + JsonAddrInfoInit(p->root, 0, &addr); SCMutexUnlock(m); - json_object_set_new(tunnel, "depth", json_integer(p->recursion_level)); + jb_set_string(js, "src_ip", addr.src_ip); + jb_set_uint(js, "src_port", addr.sp); + jb_set_string(js, "dest_ip", addr.dst_ip); + jb_set_uint(js, "dest_port", addr.dp); + jb_set_string(js, "proto", addr.proto); - json_object_set_new(js, "tunnel", tunnel); + jb_set_uint(js, "depth", p->recursion_level); + + jb_close(js); } -static void AlertAddPayload(AlertJsonOutputCtx *json_output_ctx, json_t *js, const Packet *p) +static void AlertAddPayload(AlertJsonOutputCtx *json_output_ctx, JsonBuilder *js, const Packet *p) { if (json_output_ctx->flags & LOG_JSON_PAYLOAD_BASE64) { unsigned long len = p->payload_len * 2 + 1; uint8_t encoded[len]; if (Base64Encode(p->payload, p->payload_len, encoded, &len) == SC_BASE64_OK) { - json_object_set_new(js, "payload", json_string((char *)encoded)); + jb_set_string(js, "payload", (char *)encoded); } } @@ -390,7 +408,7 @@ static void AlertAddPayload(AlertJsonOutputCtx *json_output_ctx, json_t *js, con p->payload_len + 1, p->payload, p->payload_len); printable_buf[p->payload_len] = '\0'; - json_object_set_new(js, "payload_printable", json_string((char *)printable_buf)); + jb_set_string(js, "payload_printable", (char *)printable_buf); } } @@ -412,7 +430,7 @@ static int AlertJson(ThreadVars *tv, JsonAlertLogThread *aft, const Packet *p) } /* First initialize the address info (5-tuple). */ - JsonAddrInfo addr; + JsonAddrInfo addr = json_addr_info_zero; JsonAddrInfoInit(p, LOG_DIR_PACKET, &addr); /* Check for XFF, overwriting address info if needed. */ @@ -443,20 +461,19 @@ static int AlertJson(ThreadVars *tv, JsonAlertLogThread *aft, const Packet *p) } } - json_t *js = CreateJSONHeader(p, LOG_DIR_PACKET, "alert", &addr); - if (unlikely(js == NULL)) + JsonBuilder *jb = CreateEveHeader(p, LOG_DIR_PACKET, "alert", &addr); + if (unlikely(jb == NULL)) return TM_ECODE_OK; - - JsonAddCommonOptions(&json_output_ctx->cfg, p, p->flow, js); + EveAddCommonOptions(&json_output_ctx->cfg, p, p->flow, jb); MemBufferReset(aft->json_buffer); /* alert */ - AlertJsonHeader(json_output_ctx, p, pa, js, json_output_ctx->flags, + AlertJsonHeader(json_output_ctx, p, pa, jb, json_output_ctx->flags, &addr); if (IS_TUNNEL_PKT(p)) { - AlertJsonTunnel(p, js); + AlertJsonTunnel(p, jb); } if (json_output_ctx->flags & LOG_JSON_APP_LAYER && p->flow != NULL) { @@ -471,59 +488,72 @@ static int AlertJson(ThreadVars *tv, JsonAlertLogThread *aft, const Packet *p) if (json_output_ctx->flags & LOG_JSON_HTTP_BODY_BASE64) { JsonHttpLogJSONBodyBase64(hjs, p->flow, pa->tx_id); } - json_object_set_new(js, "http", hjs); + jb_set_jsont(jb, "http", hjs); + json_decref(hjs); } break; case ALPROTO_TLS: - AlertJsonTls(p->flow, js); + AlertJsonTls(p->flow, jb); break; case ALPROTO_SSH: - AlertJsonSsh(p->flow, js); + AlertJsonSsh(p->flow, jb); break; case ALPROTO_SMTP: hjs = JsonSMTPAddMetadata(p->flow, pa->tx_id); if (hjs) { - json_object_set_new(js, "smtp", hjs); + jb_set_jsont(jb, "smtp", hjs); + json_decref(hjs); } hjs = JsonEmailAddMetadata(p->flow, pa->tx_id); if (hjs) { - json_object_set_new(js, "email", hjs); + jb_set_jsont(jb, "email", hjs); + json_decref(hjs); } break; case ALPROTO_NFS: hjs = JsonNFSAddMetadataRPC(p->flow, pa->tx_id); - if (hjs) - json_object_set_new(js, "rpc", hjs); + if (hjs) { + jb_set_jsont(jb, "rpc", hjs); + json_decref(hjs); + } hjs = JsonNFSAddMetadata(p->flow, pa->tx_id); - if (hjs) - json_object_set_new(js, "nfs", hjs); + if (hjs) { + jb_set_jsont(jb, "nfs", hjs); + json_decref(hjs); + } break; case ALPROTO_SMB: hjs = JsonSMBAddMetadata(p->flow, pa->tx_id); - if (hjs) - json_object_set_new(js, "smb", hjs); + if (hjs) { + jb_set_jsont(jb, "smb", hjs); + json_decref(hjs); + } break; case ALPROTO_SIP: hjs = JsonSIPAddMetadata(p->flow, pa->tx_id); - if (hjs) - json_object_set_new(js, "sip", hjs); + if (hjs) { + jb_set_jsont(jb, "sip", hjs); + json_decref(hjs); + } break; case ALPROTO_RFB: hjs = JsonRFBAddMetadata(p->flow, pa->tx_id); if (hjs) - json_object_set_new(js, "rfb", hjs); + jb_set_jsont(jb, "rfb", hjs); break; case ALPROTO_FTPDATA: hjs = JsonFTPDataAddMetadata(p->flow); - if (hjs) - json_object_set_new(js, "ftp-data", hjs); + if (hjs) { + jb_set_jsont(jb, "ftp-data", hjs); + json_decref(hjs); + } break; case ALPROTO_DNP3: - AlertJsonDnp3(p->flow, pa->tx_id, js); + AlertJsonDnp3(p->flow, pa->tx_id, jb); break; case ALPROTO_DNS: - AlertJsonDns(p->flow, pa->tx_id, js); + AlertJsonDns(p->flow, pa->tx_id, jb); break; default: break; @@ -531,12 +561,13 @@ static int AlertJson(ThreadVars *tv, JsonAlertLogThread *aft, const Packet *p) } if (p->flow) { - JsonAddAppProto(p->flow, js); + EveAddAppProto(p->flow, jb); if (json_output_ctx->flags & LOG_JSON_FLOW) { hjs = json_object(); if (hjs != NULL) { JsonAddFlow(p->flow, hjs); - json_object_set_new(js, "flow", hjs); + jb_set_jsont(jb, "flow", hjs); + json_decref(hjs); } } } @@ -567,7 +598,7 @@ static int AlertJson(ThreadVars *tv, JsonAlertLogThread *aft, const Packet *p) unsigned long len = json_output_ctx->payload_buffer_size * 2; uint8_t encoded[len]; Base64Encode(payload->buffer, payload->offset, encoded, &len); - json_object_set_new(js, "payload", json_string((char *)encoded)); + jb_set_string(jb, "payload", (char *)encoded); } if (json_output_ctx->flags & LOG_JSON_PAYLOAD) { @@ -576,42 +607,41 @@ static int AlertJson(ThreadVars *tv, JsonAlertLogThread *aft, const Packet *p) PrintStringsToBuffer(printable_buf, &offset, sizeof(printable_buf), payload->buffer, payload->offset); - json_object_set_new(js, "payload_printable", - json_string((char *)printable_buf)); + jb_set_string(jb, "payload_printable", (char *)printable_buf); } } else if (p->payload_len) { /* Fallback on packet payload */ - AlertAddPayload(json_output_ctx, js, p); + AlertAddPayload(json_output_ctx, jb, p); } } else { /* This is a single packet and not a stream */ - AlertAddPayload(json_output_ctx, js, p); + AlertAddPayload(json_output_ctx, jb, p); } - json_object_set_new(js, "stream", json_integer(stream)); + jb_set_uint(jb, "stream", stream); } /* base64-encoded full packet */ if (json_output_ctx->flags & LOG_JSON_PACKET) { - JsonPacket(p, js, 0); + EvePacket(p, jb, 0); } if (have_xff_ip && xff_cfg->flags & XFF_EXTRADATA) { - json_object_set_new(js, "xff", json_string(xff_buffer)); + jb_set_string(jb, "xff", xff_buffer); } - OutputJSONBuffer(js, aft->file_ctx, &aft->json_buffer); - json_decref(js); + OutputJsonBuilderBuffer(jb, aft->file_ctx, &aft->json_buffer); + jb_free(jb); } if ((p->flags & PKT_HAS_TAG) && (json_output_ctx->flags & LOG_JSON_TAGGED_PACKETS)) { MemBufferReset(aft->json_buffer); - json_t *packetjs = CreateJSONHeader(p, LOG_DIR_PACKET, "packet", NULL); + JsonBuilder *packetjs = CreateEveHeader(p, LOG_DIR_PACKET, "packet", NULL); if (unlikely(packetjs != NULL)) { - JsonPacket(p, packetjs, 0); - OutputJSONBuffer(packetjs, aft->file_ctx, &aft->json_buffer); - json_decref(packetjs); + EvePacket(p, packetjs, 0); + OutputJsonBuilderBuffer(packetjs, aft->file_ctx, &aft->json_buffer); + jb_free(packetjs); } } diff --git a/src/output-json-alert.h b/src/output-json-alert.h index 7db5be76fb..879e39919f 100644 --- a/src/output-json-alert.h +++ b/src/output-json-alert.h @@ -28,7 +28,7 @@ #define __OUTPUT_JSON_ALERT_H__ void JsonAlertLogRegister(void); -void AlertJsonHeader(void *ctx, const Packet *p, const PacketAlert *pa, json_t *js, +void AlertJsonHeader(void *ctx, const Packet *p, const PacketAlert *pa, JsonBuilder *js, uint16_t flags, JsonAddrInfo *addr); #endif /* __OUTPUT_JSON_ALERT_H__ */ diff --git a/src/output-json-drop.c b/src/output-json-drop.c index f41c8ed872..8182cfc1d1 100644 --- a/src/output-json-drop.c +++ b/src/output-json-drop.c @@ -90,67 +90,65 @@ static int DropLogJSON (JsonDropLogThread *aft, const Packet *p) JsonAddrInfo addr = json_addr_info_zero; JsonAddrInfoInit(p, LOG_DIR_PACKET, &addr); - json_t *js = CreateJSONHeader(p, LOG_DIR_PACKET, "drop", &addr); + JsonBuilder *js = CreateEveHeader(p, LOG_DIR_PACKET, "drop", &addr); if (unlikely(js == NULL)) return TM_ECODE_OK; - JsonAddCommonOptions(&drop_ctx->cfg, p, p->flow, js); + EveAddCommonOptions(&drop_ctx->cfg, p, p->flow, js); - json_t *djs = json_object(); - if (unlikely(djs == NULL)) { - json_decref(js); - return TM_ECODE_OK; - } + jb_open_object(js, "drop"); /* reset */ MemBufferReset(aft->buffer); uint16_t proto = 0; if (PKT_IS_IPV4(p)) { - json_object_set_new(djs, "len", json_integer(IPV4_GET_IPLEN(p))); - json_object_set_new(djs, "tos", json_integer(IPV4_GET_IPTOS(p))); - json_object_set_new(djs, "ttl", json_integer(IPV4_GET_IPTTL(p))); - json_object_set_new(djs, "ipid", json_integer(IPV4_GET_IPID(p))); + jb_set_uint(js, "len", IPV4_GET_IPLEN(p)); + jb_set_uint(js, "tos", IPV4_GET_IPTOS(p)); + jb_set_uint(js, "ttl", IPV4_GET_IPTTL(p)); + jb_set_uint(js, "ipid", IPV4_GET_IPID(p)); proto = IPV4_GET_IPPROTO(p); } else if (PKT_IS_IPV6(p)) { - json_object_set_new(djs, "len", json_integer(IPV6_GET_PLEN(p))); - json_object_set_new(djs, "tc", json_integer(IPV6_GET_CLASS(p))); - json_object_set_new(djs, "hoplimit", json_integer(IPV6_GET_HLIM(p))); - json_object_set_new(djs, "flowlbl", json_integer(IPV6_GET_FLOW(p))); + jb_set_uint(js, "len", IPV6_GET_PLEN(p)); + jb_set_uint(js, "tc", IPV6_GET_CLASS(p)); + jb_set_uint(js, "hoplimit", IPV6_GET_HLIM(p)); + jb_set_uint(js, "flowlbl", IPV6_GET_FLOW(p)); proto = IPV6_GET_L4PROTO(p); } switch (proto) { case IPPROTO_TCP: if (PKT_IS_TCP(p)) { - json_object_set_new(djs, "tcpseq", json_integer(TCP_GET_SEQ(p))); - json_object_set_new(djs, "tcpack", json_integer(TCP_GET_ACK(p))); - json_object_set_new(djs, "tcpwin", json_integer(TCP_GET_WINDOW(p))); - json_object_set_new(djs, "syn", TCP_ISSET_FLAG_SYN(p) ? json_true() : json_false()); - json_object_set_new(djs, "ack", TCP_ISSET_FLAG_ACK(p) ? json_true() : json_false()); - json_object_set_new(djs, "psh", TCP_ISSET_FLAG_PUSH(p) ? json_true() : json_false()); - json_object_set_new(djs, "rst", TCP_ISSET_FLAG_RST(p) ? json_true() : json_false()); - json_object_set_new(djs, "urg", TCP_ISSET_FLAG_URG(p) ? json_true() : json_false()); - json_object_set_new(djs, "fin", TCP_ISSET_FLAG_FIN(p) ? json_true() : json_false()); - json_object_set_new(djs, "tcpres", json_integer(TCP_GET_RAW_X2(p->tcph))); - json_object_set_new(djs, "tcpurgp", json_integer(TCP_GET_URG_POINTER(p))); + jb_set_uint(js, "tcpseq", TCP_GET_SEQ(p)); + jb_set_uint(js, "tcpack", TCP_GET_ACK(p)); + jb_set_uint(js, "tcpwin", TCP_GET_WINDOW(p)); + jb_set_bool(js, "syn", TCP_ISSET_FLAG_SYN(p) ? true : false); + jb_set_bool(js, "ack", TCP_ISSET_FLAG_ACK(p) ? true : false); + jb_set_bool(js, "psh", TCP_ISSET_FLAG_PUSH(p) ? true : false); + jb_set_bool(js, "rst", TCP_ISSET_FLAG_RST(p) ? true : false); + jb_set_bool(js, "urg", TCP_ISSET_FLAG_URG(p) ? true : false); + jb_set_bool(js, "fin", TCP_ISSET_FLAG_FIN(p) ? true : false); + jb_set_uint(js, "tcpres", TCP_GET_RAW_X2(p->tcph)); + jb_set_uint(js, "tcpurgp", TCP_GET_URG_POINTER(p)); } break; case IPPROTO_UDP: if (PKT_IS_UDP(p)) { - json_object_set_new(djs, "udplen", json_integer(UDP_GET_LEN(p))); + jb_set_uint(js, "udplen", UDP_GET_LEN(p)); } break; case IPPROTO_ICMP: if (PKT_IS_ICMPV4(p)) { - json_object_set_new(djs, "icmp_id", json_integer(ICMPV4_GET_ID(p))); - json_object_set_new(djs, "icmp_seq", json_integer(ICMPV4_GET_SEQ(p))); + jb_set_uint(js, "icmp_id", ICMPV4_GET_ID(p)); + jb_set_uint(js, "icmp_seq", ICMPV4_GET_SEQ(p)); } else if(PKT_IS_ICMPV6(p)) { - json_object_set_new(djs, "icmp_id", json_integer(ICMPV6_GET_ID(p))); - json_object_set_new(djs, "icmp_seq", json_integer(ICMPV6_GET_SEQ(p))); + jb_set_uint(js, "icmp_id", ICMPV6_GET_ID(p)); + jb_set_uint(js, "icmp_seq", ICMPV6_GET_SEQ(p)); } break; } - json_object_set_new(js, "drop", djs); + + /* Close drop. */ + jb_close(js); if (aft->drop_ctx->flags & LOG_DROP_ALERTS) { int logged = 0; @@ -175,10 +173,8 @@ static int DropLogJSON (JsonDropLogThread *aft, const Packet *p) } } - OutputJSONBuffer(js, aft->drop_ctx->file_ctx, &aft->buffer); - json_object_del(js, "drop"); - json_object_clear(js); - json_decref(js); + OutputJsonBuilderBuffer(js, aft->drop_ctx->file_ctx, &aft->buffer); + jb_free(js); return TM_ECODE_OK; } diff --git a/src/output-json-flow.c b/src/output-json-flow.c index 6f58b5da99..a3c26c17b5 100644 --- a/src/output-json-flow.c +++ b/src/output-json-flow.c @@ -200,6 +200,27 @@ void JsonAddAppProto(Flow *f, json_t *js) } +void EveAddAppProto(Flow *f, JsonBuilder *js) +{ + if (f->alproto) { + jb_set_string(js, "app_proto", AppProtoToString(f->alproto)); + } + if (f->alproto_ts && f->alproto_ts != f->alproto) { + jb_set_string(js, "app_proto_ts", AppProtoToString(f->alproto_ts)); + } + if (f->alproto_tc && f->alproto_tc != f->alproto) { + jb_set_string(js, "app_proto_tc", AppProtoToString(f->alproto_tc)); + } + if (f->alproto_orig != f->alproto && f->alproto_orig != ALPROTO_UNKNOWN) { + jb_set_string(js, "app_proto_orig", AppProtoToString(f->alproto_orig)); + } + if (f->alproto_expect != f->alproto && f->alproto_expect != ALPROTO_UNKNOWN) { + jb_set_string(js, "app_proto_expected", + AppProtoToString(f->alproto_expect)); + } + +} + void JsonAddFlow(Flow *f, json_t *js) { FlowBypassInfo *fc = FlowGetStorageById(f, GetFlowBypassInfoID()); diff --git a/src/output-json-flow.h b/src/output-json-flow.h index d4b017b522..ffdeafef5b 100644 --- a/src/output-json-flow.h +++ b/src/output-json-flow.h @@ -27,5 +27,6 @@ void JsonFlowLogRegister(void); void JsonAddFlow(Flow *f, json_t *js); void JsonAddAppProto(Flow *f, json_t *js); +void EveAddAppProto(Flow *f, JsonBuilder *js); #endif /* __OUTPUT_JSON_FLOW_H__ */ diff --git a/src/output-json.c b/src/output-json.c index ff6ca16163..11aa6eefe2 100644 --- a/src/output-json.c +++ b/src/output-json.c @@ -76,6 +76,7 @@ static void OutputJsonDeInitCtx(OutputCtx *); static void CreateJSONCommunityFlowId(json_t *js, const Flow *f, const uint16_t seed); +static void CreateEveCommunityFlowId(JsonBuilder *js, const Flow *f, const uint16_t seed); static const char *TRAFFIC_ID_PREFIX = "traffic/id/"; static const char *TRAFFIC_LABEL_PREFIX = "traffic/label/"; @@ -150,6 +151,7 @@ json_t *JsonAddStringN(const char *string, size_t size) return SCJsonString(tmpbuf); } + static void JsonAddPacketvars(const Packet *p, json_t *js_vars) { if (p == NULL || p->pktvar == NULL) { @@ -204,6 +206,53 @@ static void JsonAddPacketvars(const Packet *p, json_t *js_vars) } } +static void EveAddPacketVars(const Packet *p, JsonBuilder *js_vars) +{ + if (p == NULL || p->pktvar == NULL) { + return; + } + PktVar *pv = p->pktvar; + bool open = false; + while (pv != NULL) { + if (pv->key || pv->id > 0) { + if (!open) { + jb_open_array(js_vars, "pktvars"); + open = true; + } + jb_start_object(js_vars); + + if (pv->key != NULL) { + uint32_t offset = 0; + uint8_t keybuf[pv->key_len + 1]; + PrintStringsToBuffer(keybuf, &offset, + sizeof(keybuf), + pv->key, pv->key_len); + uint32_t len = pv->value_len; + uint8_t printable_buf[len + 1]; + offset = 0; + PrintStringsToBuffer(printable_buf, &offset, + sizeof(printable_buf), + pv->value, pv->value_len); + jb_set_string(js_vars, (char *)keybuf, (char *)printable_buf); + } else { + const char *varname = VarNameStoreLookupById(pv->id, VAR_TYPE_PKT_VAR); + uint32_t len = pv->value_len; + uint8_t printable_buf[len + 1]; + uint32_t offset = 0; + PrintStringsToBuffer(printable_buf, &offset, + sizeof(printable_buf), + pv->value, pv->value_len); + jb_set_string(js_vars, varname, (char *)printable_buf); + } + jb_close(js_vars); + } + pv = pv->next; + } + if (open) { + jb_close(js_vars); + } +} + /** * \brief Check if string s has prefix prefix. * @@ -365,6 +414,144 @@ static void JsonAddFlowVars(const Flow *f, json_t *js_root, json_t **js_traffic) } } +static void EveAddFlowVars(const Flow *f, JsonBuilder *js_root, JsonBuilder **js_traffic) +{ + if (f == NULL || f->flowvar == NULL) { + return; + } + JsonBuilder *js_flowvars = NULL; + JsonBuilder *js_traffic_id = NULL; + JsonBuilder *js_traffic_label = NULL; + JsonBuilder *js_flowints = NULL; + JsonBuilder *js_flowbits = NULL; + GenericVar *gv = f->flowvar; + while (gv != NULL) { + if (gv->type == DETECT_FLOWVAR || gv->type == DETECT_FLOWINT) { + FlowVar *fv = (FlowVar *)gv; + if (fv->datatype == FLOWVAR_TYPE_STR && fv->key == NULL) { + const char *varname = VarNameStoreLookupById(fv->idx, + VAR_TYPE_FLOW_VAR); + if (varname) { + if (js_flowvars == NULL) { + js_flowvars = jb_new_array(); + if (js_flowvars == NULL) + break; + } + + uint32_t len = fv->data.fv_str.value_len; + uint8_t printable_buf[len + 1]; + uint32_t offset = 0; + PrintStringsToBuffer(printable_buf, &offset, + sizeof(printable_buf), + fv->data.fv_str.value, fv->data.fv_str.value_len); + + jb_start_object(js_flowvars); + jb_set_string(js_flowvars, varname, (char *)printable_buf); + jb_close(js_flowvars); + } + } else if (fv->datatype == FLOWVAR_TYPE_STR && fv->key != NULL) { + if (js_flowvars == NULL) { + js_flowvars = jb_new_array(); + if (js_flowvars == NULL) + break; + } + + uint8_t keybuf[fv->keylen + 1]; + uint32_t offset = 0; + PrintStringsToBuffer(keybuf, &offset, + sizeof(keybuf), + fv->key, fv->keylen); + + uint32_t len = fv->data.fv_str.value_len; + uint8_t printable_buf[len + 1]; + offset = 0; + PrintStringsToBuffer(printable_buf, &offset, + sizeof(printable_buf), + fv->data.fv_str.value, fv->data.fv_str.value_len); + + jb_start_object(js_flowvars); + jb_set_string(js_flowvars, (const char *)keybuf, (char *)printable_buf); + jb_close(js_flowvars); + } else if (fv->datatype == FLOWVAR_TYPE_INT) { + const char *varname = VarNameStoreLookupById(fv->idx, + VAR_TYPE_FLOW_INT); + if (varname) { + if (js_flowints == NULL) { + js_flowints = jb_new_object(); + if (js_flowints == NULL) + break; + } + jb_set_uint(js_flowints, varname, fv->data.fv_int.value); + } + + } + } else if (gv->type == DETECT_FLOWBITS) { + FlowBit *fb = (FlowBit *)gv; + const char *varname = VarNameStoreLookupById(fb->idx, + VAR_TYPE_FLOW_BIT); + if (varname) { + if (SCStringHasPrefix(varname, TRAFFIC_ID_PREFIX)) { + if (js_traffic_id == NULL) { + js_traffic_id = jb_new_array(); + if (unlikely(js_traffic_id == NULL)) { + break; + } + } + jb_append_string(js_traffic_id, &varname[traffic_id_prefix_len]); + } else if (SCStringHasPrefix(varname, TRAFFIC_LABEL_PREFIX)) { + if (js_traffic_label == NULL) { + js_traffic_label = jb_new_array(); + if (unlikely(js_traffic_label == NULL)) { + break; + } + } + jb_append_string(js_traffic_label, &varname[traffic_label_prefix_len]); + } else { + if (js_flowbits == NULL) { + js_flowbits = jb_new_array(); + if (unlikely(js_flowbits == NULL)) + break; + } + jb_append_string(js_flowbits, varname); + } + } + } + gv = gv->next; + } + if (js_flowbits) { + jb_close(js_flowbits); + jb_set_object(js_root, "flowbits", js_flowbits); + jb_free(js_flowbits); + } + if (js_flowints) { + jb_close(js_flowints); + jb_set_object(js_root, "flowints", js_flowints); + jb_free(js_flowints); + } + if (js_flowvars) { + jb_close(js_flowvars); + jb_set_object(js_root, "flowvars", js_flowvars); + jb_free(js_flowvars); + } + + if (js_traffic_id != NULL || js_traffic_label != NULL) { + *js_traffic = jb_new_object(); + if (likely(*js_traffic != NULL)) { + if (js_traffic_id != NULL) { + jb_close(js_traffic_id); + jb_set_object(*js_traffic, "id", js_traffic_id); + jb_free(js_traffic_id); + } + if (js_traffic_label != NULL) { + jb_close(js_traffic_label); + jb_set_object(*js_traffic, "label", js_traffic_label); + jb_free(js_traffic_label); + } + jb_close(*js_traffic); + } + } +} + /** * \brief Add top-level metadata to the eve json object. */ @@ -389,6 +576,29 @@ static void JsonAddMetadata(const Packet *p, const Flow *f, json_t *js) } } +static void EveAddMetadata(const Packet *p, const Flow *f, JsonBuilder *js) +{ + if ((p && p->pktvar) || (f && f->flowvar)) { + JsonBuilder *js_vars = jb_new_object(); + if (js_vars) { + if (f && f->flowvar) { + JsonBuilder *js_traffic = NULL; + EveAddFlowVars(f, js_vars, &js_traffic); + if (js_traffic != NULL) { + jb_set_object(js, "traffic", js_traffic); + jb_free(js_traffic); + } + } + if (p && p->pktvar) { + EveAddPacketVars(p, js_vars); + } + jb_close(js_vars); + jb_set_object(js, "metadata", js_vars); + jb_free(js_vars); + } + } +} + void JsonAddCommonOptions(const OutputJsonCommonSettings *cfg, const Packet *p, const Flow *f, json_t *js) { @@ -400,6 +610,17 @@ void JsonAddCommonOptions(const OutputJsonCommonSettings *cfg, } } +void EveAddCommonOptions(const OutputJsonCommonSettings *cfg, + const Packet *p, const Flow *f, JsonBuilder *js) +{ + if (cfg->include_metadata) { + EveAddMetadata(p, f, js); + } + if (cfg->include_community_id && f != NULL) { + CreateEveCommunityFlowId(js, f, cfg->community_id_seed); + } +} + /** * \brief Jsonify a packet * @@ -424,6 +645,32 @@ void JsonPacket(const Packet *p, json_t *js, unsigned long max_length) json_object_set_new(packetinfo_js, "linktype", json_integer(p->datalink)); json_object_set_new(js, "packet_info", packetinfo_js); } + +/** + * \brief Jsonify a packet + * + * \param p Packet + * \param js JSON object + * \param max_length If non-zero, restricts the number of packet data bytes handled. + */ +void EvePacket(const Packet *p, JsonBuilder *js, unsigned long max_length) +{ + unsigned long max_len = max_length == 0 ? GET_PKT_LEN(p) : max_length; + unsigned long len = 2 * max_len; + uint8_t encoded_packet[len]; + if (Base64Encode((unsigned char*) GET_PKT_DATA(p), max_len, encoded_packet, &len) == SC_BASE64_OK) { + jb_set_string(js, "packet", (char *)encoded_packet); + } + + if (!jb_open_object(js, "packet_info")) { + return; + } + if (!jb_set_uint(js, "linktype", p->datalink)) { + return; + } + jb_close(js); +} + /** \brief jsonify tcp flags field * Only add 'true' fields in an attempt to keep things reasonably compact. */ @@ -706,8 +953,10 @@ void JsonFiveTuple(const Packet *p, enum OutputJsonLogDirection dir, json_t *js) json_object_set_new(js, "proto", json_string(proto)); } -static void CreateJSONCommunityFlowIdv4(json_t *js, const Flow *f, - const uint16_t seed) +#define COMMUNITY_ID_BUF_SIZE 64 + +static bool CalculateCommunityFlowIdv4(const Flow *f, + const uint16_t seed, unsigned char *base64buf) { struct { uint16_t seed; @@ -747,12 +996,13 @@ static void CreateJSONCommunityFlowIdv4(json_t *js, const Flow *f, uint8_t hash[20]; if (ComputeSHA1((const uint8_t *)&ipv4, sizeof(ipv4), hash, sizeof(hash)) == 1) { - unsigned char base64buf[64] = "1:"; - unsigned long out_len = sizeof(base64buf) - 2; + strlcpy((char *)base64buf, "1:", COMMUNITY_ID_BUF_SIZE); + unsigned long out_len = COMMUNITY_ID_BUF_SIZE - 2; if (Base64Encode(hash, sizeof(hash), base64buf+2, &out_len) == SC_BASE64_OK) { - json_object_set_new(js, "community_id", json_string((const char *)base64buf)); + return true; } } + return false; } static inline bool FlowHashRawAddressIPv6LtU32(const uint32_t *a, const uint32_t *b) @@ -767,8 +1017,8 @@ static inline bool FlowHashRawAddressIPv6LtU32(const uint32_t *a, const uint32_t return false; } -static void CreateJSONCommunityFlowIdv6(json_t *js, const Flow *f, - const uint16_t seed) +static bool CalculateCommunityFlowIdv6(const Flow *f, + const uint16_t seed, unsigned char *base64buf) { struct { uint16_t seed; @@ -808,20 +1058,41 @@ static void CreateJSONCommunityFlowIdv6(json_t *js, const Flow *f, uint8_t hash[20]; if (ComputeSHA1((const uint8_t *)&ipv6, sizeof(ipv6), hash, sizeof(hash)) == 1) { - unsigned char base64buf[64] = "1:"; - unsigned long out_len = sizeof(base64buf) - 2; + strlcpy((char *)base64buf, "1:", COMMUNITY_ID_BUF_SIZE); + unsigned long out_len = COMMUNITY_ID_BUF_SIZE - 2; if (Base64Encode(hash, sizeof(hash), base64buf+2, &out_len) == SC_BASE64_OK) { - json_object_set_new(js, "community_id", json_string((const char *)base64buf)); + return true; } } + return false; } static void CreateJSONCommunityFlowId(json_t *js, const Flow *f, const uint16_t seed) { - if (f->flags & FLOW_IPV4) - return CreateJSONCommunityFlowIdv4(js, f, seed); - else if (f->flags & FLOW_IPV6) - return CreateJSONCommunityFlowIdv6(js, f, seed); + unsigned char buf[COMMUNITY_ID_BUF_SIZE]; + if (f->flags & FLOW_IPV4) { + if (CalculateCommunityFlowIdv4(f, seed, buf)) { + json_object_set_new(js, "community_id", json_string((const char *)buf)); + } + } else if (f->flags & FLOW_IPV6) { + if (CalculateCommunityFlowIdv6(f, seed, buf)) { + json_object_set_new(js, "community_id", json_string((const char *)buf)); + } + } +} + +static void CreateEveCommunityFlowId(JsonBuilder *js, const Flow *f, const uint16_t seed) +{ + unsigned char buf[COMMUNITY_ID_BUF_SIZE]; + if (f->flags & FLOW_IPV4) { + if (CalculateCommunityFlowIdv4(f, seed, buf)) { + jb_set_string(js, "community_id", (const char *)buf); + } + } else if (f->flags & FLOW_IPV6) { + if (CalculateCommunityFlowIdv6(f, seed, buf)) { + jb_set_string(js, "community_id", (const char *)buf); + } + } } void CreateJSONFlowId(json_t *js, const Flow *f) @@ -835,6 +1106,18 @@ void CreateJSONFlowId(json_t *js, const Flow *f) } } +void CreateEveFlowId(JsonBuilder *js, const Flow *f) +{ + if (f == NULL) { + return; + } + int64_t flow_id = FlowGetId(f); + jb_set_uint(js, "flow_id", flow_id); + if (f->parent_id) { + jb_set_uint(js, "parent_id", f->parent_id); + } +} + json_t *CreateJSONHeader(const Packet *p, enum OutputJsonLogDirection dir, const char *event_type, JsonAddrInfo *addr) { @@ -917,6 +1200,83 @@ json_t *CreateJSONHeader(const Packet *p, enum OutputJsonLogDirection dir, return js; } +JsonBuilder *CreateEveHeader(const Packet *p, enum OutputJsonLogDirection dir, + const char *event_type, JsonAddrInfo *addr) +{ + char timebuf[64]; + const Flow *f = (const Flow *)p->flow; + + JsonBuilder *js = jb_new_object(); + if (unlikely(js == NULL)) { + return NULL; + } + + CreateIsoTimeString(&p->ts, timebuf, sizeof(timebuf)); + + jb_set_string(js, "timestamp", timebuf); + + CreateEveFlowId(js, f); + + /* sensor id */ + if (sensor_id >= 0) { + jb_set_uint(js, "sensor_id", sensor_id); + } + + /* input interface */ + if (p->livedev) { + jb_set_string(js, "in_iface", p->livedev->dev); + } + + /* pcap_cnt */ + if (p->pcap_cnt != 0) { + jb_set_uint(js, "pcap_cnt", p->pcap_cnt); + } + + if (event_type) { + jb_set_string(js, "event_type", event_type); + } + + /* vlan */ + if (p->vlan_idx > 0) { + jb_open_array(js, "vlan"); + jb_append_uint(js, p->vlan_id[0]); + if (p->vlan_idx > 1) { + jb_append_uint(js, p->vlan_id[1]); + } + jb_close(js); + } + + /* 5-tuple */ + JsonAddrInfo addr_info = json_addr_info_zero; + if (addr == NULL) { + JsonAddrInfoInit(p, dir, &addr_info); + addr = &addr_info; + } + jb_set_string(js, "src_ip", addr->src_ip); + jb_set_uint(js, "src_port", addr->sp); + jb_set_string(js, "dest_ip", addr->dst_ip); + jb_set_uint(js, "dest_port", addr->dp); + jb_set_string(js, "proto", addr->proto); + + /* icmp */ + switch (p->proto) { + case IPPROTO_ICMP: + if (p->icmpv4h) { + jb_set_uint(js, "icmp_type", p->icmpv4h->type); + jb_set_uint(js, "icmp_code", p->icmpv4h->code); + } + break; + case IPPROTO_ICMPV6: + if (p->icmpv6h) { + jb_set_uint(js, "icmp_type", p->icmpv6h->type); + jb_set_uint(js, "icmp_code", p->icmpv6h->code); + } + break; + } + + return js; +} + json_t *CreateJSONHeaderWithTxId(const Packet *p, enum OutputJsonLogDirection dir, const char *event_type, uint64_t tx_id) { @@ -972,6 +1332,33 @@ int OutputJSONBuffer(json_t *js, LogFileCtx *file_ctx, MemBuffer **buffer) return 0; } +int OutputJsonBuilderBuffer(JsonBuilder *js, LogFileCtx *file_ctx, MemBuffer **buffer) +{ + if (file_ctx->sensor_name) { + jb_set_string(js, "host", file_ctx->sensor_name); + } + + if (file_ctx->is_pcap_offline) { + jb_set_string(js, "pcap_filename", PcapFileGetFilename()); + } + + jb_close(js); + + if (file_ctx->prefix) { + MemBufferWriteRaw((*buffer), file_ctx->prefix, file_ctx->prefix_len); + } + + size_t jslen = jb_len(js); + if (MEMBUFFER_OFFSET(*buffer) + jslen >= MEMBUFFER_SIZE(*buffer)) { + MemBufferExpand(buffer, jslen); + } + + MemBufferWriteRaw((*buffer), jb_ptr(js), jslen); + LogFileWrite(file_ctx, *buffer); + + return 0; +} + /** * \brief Create a new LogFileCtx for "fast" output style. * \param conf The configuration node for this output. diff --git a/src/output-json.h b/src/output-json.h index d928a9ee4c..01c0070232 100644 --- a/src/output-json.h +++ b/src/output-json.h @@ -28,6 +28,7 @@ #include "util-buffer.h" #include "util-logopenfile.h" #include "output.h" +#include "rust.h" #include "app-layer-htp-xff.h" @@ -69,15 +70,21 @@ typedef struct OutputJSONMemBufferWrapper_ { int OutputJSONMemBufferCallback(const char *str, size_t size, void *data); void CreateJSONFlowId(json_t *js, const Flow *f); +void CreateEveFlowId(JsonBuilder *js, const Flow *f); void JsonTcpFlags(uint8_t flags, json_t *js); void JsonPacket(const Packet *p, json_t *js, unsigned long max_length); +void EvePacket(const Packet *p, JsonBuilder *js, unsigned long max_length); void JsonFiveTuple(const Packet *, enum OutputJsonLogDirection, json_t *); json_t *CreateJSONHeader(const Packet *p, enum OutputJsonLogDirection dir, const char *event_type, JsonAddrInfo *addr); +JsonBuilder *CreateEveHeader(const Packet *p, + enum OutputJsonLogDirection dir, const char *event_type, + JsonAddrInfo *addr); json_t *CreateJSONHeaderWithTxId(const Packet *p, enum OutputJsonLogDirection dir, const char *event_type, uint64_t tx_id); int OutputJSONBuffer(json_t *js, LogFileCtx *file_ctx, MemBuffer **buffer); +int OutputJsonBuilderBuffer(JsonBuilder *js, LogFileCtx *file_ctx, MemBuffer **buffer); OutputInitResult OutputJsonInitCtx(ConfNode *); OutputInitResult OutputJsonLogInitSub(ConfNode *conf, OutputCtx *parent_ctx); @@ -112,5 +119,7 @@ void SCJsonDecref(json_t *js); void JsonAddCommonOptions(const OutputJsonCommonSettings *cfg, const Packet *p, const Flow *f, json_t *js); +void EveAddCommonOptions(const OutputJsonCommonSettings *cfg, + const Packet *p, const Flow *f, JsonBuilder *js); #endif /* __OUTPUT_JSON_H__ */