]> git.ipfire.org Git - thirdparty/suricata.git/commitdiff
output/alert: rewrite code for app-layer properties
authorPhilippe Antoine <contact@catenacyber.fr>
Thu, 11 May 2023 08:02:32 +0000 (10:02 +0200)
committerPhilippe Antoine <contact@catenacyber.fr>
Mon, 20 Nov 2023 20:53:13 +0000 (21:53 +0100)
Especially fix setup-app-layer script to not forget this part

This allows, for simple loggers, to have a unique definition
of the actual logging function with the jsonbuilder.
This way, alerts, files, and app-layer event can share the code
to output the same data.

Ticket: #3827

36 files changed:
rust/src/applayertemplate/logger.rs
rust/src/bittorrent_dht/logger.rs
rust/src/http2/logger.rs
rust/src/quic/logger.rs
rust/src/snmp/log.rs
rust/src/ssh/logger.rs
scripts/setup-app-layer.py
src/app-layer-ftp.c
src/app-layer-ftp.h
src/output-json-alert.c
src/output-json-bittorrent-dht.c
src/output-json-dnp3.c
src/output-json-dnp3.h
src/output-json-dns.c
src/output-json-dns.h
src/output-json-file.c
src/output-json-ftp.c
src/output-json-http2.c
src/output-json-http2.h
src/output-json-modbus.c
src/output-json-modbus.h
src/output-json-mqtt.c
src/output-json-mqtt.h
src/output-json-quic.c
src/output-json-quic.h
src/output-json-rfb.c
src/output-json-rfb.h
src/output-json-sip.c
src/output-json-sip.h
src/output-json-snmp.c
src/output-json-ssh.c
src/output-json-template.c
src/output-json-tls.c
src/output-json-tls.h
src/output.c
src/output.h

index 0105526fc0f1fb9df1d7fc7cc785e6e7e28ed86d..766a07acdb9de8d4d87a55dc868096ebc0d76636 100644 (file)
@@ -20,12 +20,14 @@ use crate::jsonbuilder::{JsonBuilder, JsonError};
 use std;
 
 fn log_template(tx: &TemplateTransaction, js: &mut JsonBuilder) -> Result<(), JsonError> {
+    js.open_object("template")?;
     if let Some(ref request) = tx.request {
         js.set_string("request", request)?;
     }
     if let Some(ref response) = tx.response {
         js.set_string("response", response)?;
     }
+    js.close()?;
     Ok(())
 }
 
index 2cfb9270ef673e1997f6ecc1a365bdae32e3f481..74ea7c59ba572677e91131b2784cda3b89567030 100644 (file)
@@ -48,6 +48,7 @@ fn print_ip_addr(addr: &[u8]) -> std::string::String {
 fn log_bittorrent_dht(
     tx: &BitTorrentDHTTransaction, js: &mut JsonBuilder,
 ) -> Result<(), JsonError> {
+    js.open_object("bittorrent_dht")?;
     js.set_hex("transaction_id", &tx.transaction_id)?;
     if let Some(client_version) = &tx.client_version {
         js.set_hex("client_version", client_version)?;
@@ -125,6 +126,7 @@ fn log_bittorrent_dht(
         }
         js.close()?;
     };
+    js.close()?;
     Ok(())
 }
 
index d25f852c43abea432a25a91312ff4900e78b3181..099112b1aeb48bb2fd705788b39e10a3bd9ca8d7 100644 (file)
@@ -192,6 +192,7 @@ fn log_http2_frames(frames: &[HTTP2Frame], js: &mut JsonBuilder) -> Result<bool,
 }
 
 fn log_http2(tx: &HTTP2Transaction, js: &mut JsonBuilder) -> Result<bool, JsonError> {
+    js.open_object("http")?;
     js.set_string("version", "2")?;
 
     let mut common: HashMap<HeaderName, &Vec<u8>> = HashMap::new();
@@ -261,8 +262,8 @@ fn log_http2(tx: &HTTP2Transaction, js: &mut JsonBuilder) -> Result<bool, JsonEr
     let has_response = log_http2_frames(&tx.frames_tc, js)?;
     js.close()?;
 
-    // Close http2.
-    js.close()?;
+    js.close()?; // http2
+    js.close()?; // http
 
     return Ok(has_request || has_response || has_headers);
 }
index e03ebdd6bf2174caecef5c4ca03960546aa8bda3..8cb08830e4d0ea1ea11abb5a110dd9da7ad942a7 100644 (file)
@@ -88,7 +88,7 @@ fn quic_tls_extension_name(e: u16) -> Option<String> {
     }
 }
 
-fn log_template(tx: &QuicTransaction, js: &mut JsonBuilder) -> Result<(), JsonError> {
+fn log_quic(tx: &QuicTransaction, js: &mut JsonBuilder) -> Result<(), JsonError> {
     js.open_object("quic")?;
     if tx.header.ty != QuicType::Short {
         js.set_string("version", String::from(tx.header.version).as_str())?;
@@ -153,5 +153,5 @@ pub unsafe extern "C" fn rs_quic_to_json(
     tx: *mut std::os::raw::c_void, js: &mut JsonBuilder,
 ) -> bool {
     let tx = cast_pointer!(tx, QuicTransaction);
-    log_template(tx, js).is_ok()
+    log_quic(tx, js).is_ok()
 }
index 83414816c466721733b1cfc171914243dc18444a..5707f30ccb4eddacd7e85379e470d6048a697d05 100644 (file)
@@ -39,6 +39,7 @@ fn str_of_pdu_type(t:&PduType) -> Cow<str> {
 
 fn snmp_log_response(jsb: &mut JsonBuilder, tx: &mut SNMPTransaction) -> Result<(), JsonError>
 {
+    jsb.open_object("snmp")?;
     jsb.set_uint("version", tx.version as u64)?;
     if tx.encrypted {
         jsb.set_string("pdu_type", "encrypted")?;
@@ -71,11 +72,12 @@ fn snmp_log_response(jsb: &mut JsonBuilder, tx: &mut SNMPTransaction) -> Result<
         }
     }
 
+    jsb.close()?;
     return Ok(());
 }
 
 #[no_mangle]
-pub extern "C" fn rs_snmp_log_json_response(jsb: &mut JsonBuilder, tx: &mut SNMPTransaction) -> bool
+pub extern "C" fn rs_snmp_log_json_response(tx: &mut SNMPTransaction, jsb: &mut JsonBuilder) -> bool
 {
     snmp_log_response(jsb, tx).is_ok()
 }
index 9bc7d7c33f393ed2fce5495babd04b95b072bbc1..008c6cb4517ab19a06bf473302d9a0ba5a1c2cd8 100644 (file)
@@ -19,6 +19,7 @@ use super::ssh::SSHTransaction;
 use crate::jsonbuilder::{JsonBuilder, JsonError};
 
 fn log_ssh(tx: &SSHTransaction, js: &mut JsonBuilder) -> Result<bool, JsonError> {
+    js.open_object("ssh")?;
     if tx.cli_hdr.protover.is_empty() && tx.srv_hdr.protover.is_empty() {
         return Ok(false);
     }
@@ -58,6 +59,7 @@ fn log_ssh(tx: &SSHTransaction, js: &mut JsonBuilder) -> Result<bool, JsonError>
         }
         js.close()?;
     }
+    js.close()?;
     return Ok(true);
 }
 
index 72f28c986c66ba600c5dc2372564fd5d14979c63..d8426634bca8b34095bce28fb7da455aeab5c16d 100755 (executable)
@@ -200,6 +200,10 @@ def logger_patch_output_c(proto):
     output = io.StringIO()
     inlines = open(filename).readlines()
     for i, line in enumerate(inlines):
+        if line.find("ALPROTO_TEMPLATE") > -1:
+            new_line = line.replace("TEMPLATE", proto.upper()).replace(
+                    "template", proto.lower())
+            output.write(new_line)
         if line.find("output-json-template.h") > -1:
             output.write(line.replace("template", proto.lower()))
         if line.find("/* Template JSON logger.") > -1:
index c0a815e31daede8f71eb4c5c4d2d83aeeb9a75c3..f46a4a967e244ea29bcd0afc65b8e883ac94acfe 100644 (file)
@@ -1405,13 +1405,10 @@ uint16_t JsonGetNextLineFromBuffer(const char *buffer, const uint16_t len)
     return c == NULL ? len : (uint16_t)(c - buffer + 1);
 }
 
-void EveFTPDataAddMetadata(const Flow *f, JsonBuilder *jb)
+bool EveFTPDataAddMetadata(void *vtx, JsonBuilder *jb)
 {
-    const FtpDataState *ftp_state = NULL;
-    if (f->alstate == NULL)
-        return;
-
-    ftp_state = (FtpDataState *)f->alstate;
+    const FtpDataState *ftp_state = (FtpDataState *)vtx;
+    jb_open_object(jb, "ftp_data");
 
     if (ftp_state->file_name) {
         jb_set_string_from_bytes(jb, "filename", ftp_state->file_name, ftp_state->file_len);
@@ -1426,6 +1423,8 @@ void EveFTPDataAddMetadata(const Flow *f, JsonBuilder *jb)
         default:
             break;
     }
+    jb_close(jb);
+    return true;
 }
 
 /**
index f79c5c9e76756c6ade056210bc2aff5ef64622cf..fb71d6b52de7bcdbc29aa681f22854781b55df52 100644 (file)
@@ -190,7 +190,7 @@ uint64_t FTPMemuseGlobalCounter(void);
 uint64_t FTPMemcapGlobalCounter(void);
 
 uint16_t JsonGetNextLineFromBuffer(const char *buffer, const uint16_t len);
-void EveFTPDataAddMetadata(const Flow *f, JsonBuilder *jb);
+bool EveFTPDataAddMetadata(void *vtx, JsonBuilder *jb);
 
 #endif /* __APP_LAYER_FTP_H__ */
 
index c3886231c001841d91e1c76f55a3712d6bd1de57..ad9d236f30900521685d46f8f25fd5441d6db039 100644 (file)
@@ -137,164 +137,6 @@ static int AlertJsonDumpStreamSegmentCallback(
     return 1;
 }
 
-static void AlertJsonTls(const Flow *f, JsonBuilder *js)
-{
-    SSLState *ssl_state = (SSLState *)FlowGetAppState(f);
-    if (ssl_state) {
-        jb_open_object(js, "tls");
-
-        JsonTlsLogJSONExtended(js, ssl_state);
-
-        jb_close(js);
-    }
-
-    return;
-}
-
-static void AlertJsonSsh(const Flow *f, JsonBuilder *js)
-{
-    void *ssh_state = FlowGetAppState(f);
-    if (ssh_state) {
-        JsonBuilderMark mark = { 0, 0, 0 };
-        void *tx_ptr = rs_ssh_state_get_tx(ssh_state, 0);
-        jb_get_mark(js, &mark);
-        jb_open_object(js, "ssh");
-        if (rs_ssh_log_json(tx_ptr, js)) {
-            jb_close(js);
-        } else {
-            jb_restore_mark(js, &mark);
-        }
-    }
-
-    return;
-}
-
-static void AlertJsonHttp2(const Flow *f, const uint64_t tx_id, JsonBuilder *js)
-{
-    void *h2_state = FlowGetAppState(f);
-    if (h2_state) {
-        void *tx_ptr = rs_http2_state_get_tx(h2_state, tx_id);
-        if (tx_ptr) {
-            JsonBuilderMark mark = { 0, 0, 0 };
-            jb_get_mark(js, &mark);
-            jb_open_object(js, "http");
-            if (rs_http2_log_json(tx_ptr, js)) {
-                jb_close(js);
-            } else {
-                jb_restore_mark(js, &mark);
-            }
-        }
-    }
-
-    return;
-}
-
-static void AlertJsonDnp3(const Flow *f, const uint64_t tx_id, JsonBuilder *js)
-{
-    DNP3State *dnp3_state = (DNP3State *)FlowGetAppState(f);
-    if (dnp3_state) {
-        DNP3Transaction *tx = AppLayerParserGetTx(IPPROTO_TCP, ALPROTO_DNP3,
-            dnp3_state, tx_id);
-        if (tx) {
-            JsonBuilderMark mark = { 0, 0, 0 };
-            jb_get_mark(js, &mark);
-            bool logged = false;
-            jb_open_object(js, "dnp3");
-            if (tx->is_request && tx->done) {
-                jb_open_object(js, "request");
-                JsonDNP3LogRequest(js, tx);
-                jb_close(js);
-                logged = true;
-            }
-            if (!tx->is_request && tx->done) {
-                jb_open_object(js, "response");
-                JsonDNP3LogResponse(js, tx);
-                jb_close(js);
-                logged = true;
-            }
-            if (logged) {
-                /* Close dnp3 object. */
-                jb_close(js);
-            } else {
-                jb_restore_mark(js, &mark);
-            }
-        }
-    }
-}
-
-static void AlertJsonDns(const Flow *f, const uint64_t tx_id, JsonBuilder *js)
-{
-    void *dns_state = (void *)FlowGetAppState(f);
-    if (dns_state) {
-        void *txptr = AppLayerParserGetTx(f->proto, ALPROTO_DNS,
-                                          dns_state, tx_id);
-        if (txptr) {
-            jb_open_object(js, "dns");
-            JsonBuilder *qjs = JsonDNSLogQuery(txptr);
-            if (qjs != NULL) {
-                jb_set_object(js, "query", qjs);
-                jb_free(qjs);
-            }
-            JsonBuilder *ajs = JsonDNSLogAnswer(txptr);
-            if (ajs != NULL) {
-                jb_set_object(js, "answer", ajs);
-                jb_free(ajs);
-            }
-            jb_close(js);
-        }
-    }
-    return;
-}
-
-static void AlertJsonSNMP(const Flow *f, const uint64_t tx_id, JsonBuilder *js)
-{
-    void *snmp_state = (void *)FlowGetAppState(f);
-    if (snmp_state != NULL) {
-        void *tx = AppLayerParserGetTx(f->proto, ALPROTO_SNMP, snmp_state,
-                tx_id);
-        if (tx != NULL) {
-            jb_open_object(js, "snmp");
-            rs_snmp_log_json_response(js, tx);
-            jb_close(js);
-        }
-    }
-}
-
-static void AlertJsonRDP(const Flow *f, const uint64_t tx_id, JsonBuilder *js)
-{
-    void *rdp_state = (void *)FlowGetAppState(f);
-    if (rdp_state != NULL) {
-        void *tx = AppLayerParserGetTx(f->proto, ALPROTO_RDP, rdp_state,
-                tx_id);
-        if (tx != NULL) {
-            JsonBuilderMark mark = { 0, 0, 0 };
-            jb_get_mark(js, &mark);
-            if (!rs_rdp_to_json(tx, js)) {
-                jb_restore_mark(js, &mark);
-            }
-        }
-    }
-}
-
-static void AlertJsonBitTorrentDHT(const Flow *f, const uint64_t tx_id, JsonBuilder *js)
-{
-    void *bittorrent_dht_state = (void *)FlowGetAppState(f);
-    if (bittorrent_dht_state != NULL) {
-        void *tx =
-                AppLayerParserGetTx(f->proto, ALPROTO_BITTORRENT_DHT, bittorrent_dht_state, tx_id);
-        if (tx != NULL) {
-            JsonBuilderMark mark = { 0, 0, 0 };
-            jb_get_mark(js, &mark);
-            jb_open_object(js, "bittorrent_dht");
-            if (rs_bittorrent_dht_logger_log(tx, js)) {
-                jb_close(js);
-            } else {
-                jb_restore_mark(js, &mark);
-            }
-        }
-    }
-}
-
 static void AlertJsonSourceTarget(const Packet *p, const PacketAlert *pa,
                                   JsonBuilder *js, JsonAddrInfo *addr)
 {
@@ -471,7 +313,21 @@ static void AlertAddAppLayer(const Packet *p, JsonBuilder *jb,
         const uint64_t tx_id, const uint16_t option_flags)
 {
     const AppProto proto = FlowGetAppProtocol(p->flow);
+    EveJsonSimpleAppLayerLogger *al = SCEveJsonSimpleGetLogger(proto);
     JsonBuilderMark mark = { 0, 0, 0 };
+    if (al && al->LogTx) {
+        void *state = FlowGetAppState(p->flow);
+        if (state) {
+            void *tx = AppLayerParserGetTx(p->flow->proto, proto, state, tx_id);
+            if (tx) {
+                jb_get_mark(jb, &mark);
+                if (!al->LogTx(tx, jb)) {
+                    jb_restore_mark(jb, &mark);
+                }
+            }
+        }
+        return;
+    }
     switch (proto) {
         case ALPROTO_HTTP1:
             // TODO: Could result in an empty http object being logged.
@@ -486,12 +342,6 @@ static void AlertAddAppLayer(const Packet *p, JsonBuilder *jb,
             }
             jb_close(jb);
             break;
-        case ALPROTO_TLS:
-            AlertJsonTls(p->flow, jb);
-            break;
-        case ALPROTO_SSH:
-            AlertJsonSsh(p->flow, jb);
-            break;
         case ALPROTO_SMTP:
             jb_get_mark(jb, &mark);
             jb_open_object(jb, "smtp");
@@ -535,63 +385,12 @@ static void AlertAddAppLayer(const Packet *p, JsonBuilder *jb,
                 jb_restore_mark(jb, &mark);
             }
             break;
-        case ALPROTO_SIP:
-            JsonSIPAddMetadata(jb, p->flow, tx_id);
-            break;
-        case ALPROTO_RFB:
-            jb_get_mark(jb, &mark);
-            if (!JsonRFBAddMetadata(p->flow, tx_id, jb)) {
-                jb_restore_mark(jb, &mark);
-            }
-            break;
-        case ALPROTO_FTPDATA:
-            jb_get_mark(jb, &mark);
-            jb_open_object(jb, "ftp_data");
-            EveFTPDataAddMetadata(p->flow, jb);
-            jb_close(jb);
-            break;
-        case ALPROTO_DNP3:
-            AlertJsonDnp3(p->flow, tx_id, jb);
-            break;
-        case ALPROTO_HTTP2:
-            AlertJsonHttp2(p->flow, tx_id, jb);
-            break;
-        case ALPROTO_DNS:
-            AlertJsonDns(p->flow, tx_id, jb);
-            break;
         case ALPROTO_IKE:
             jb_get_mark(jb, &mark);
             if (!EveIKEAddMetadata(p->flow, tx_id, jb)) {
                 jb_restore_mark(jb, &mark);
             }
             break;
-        case ALPROTO_MQTT:
-            jb_get_mark(jb, &mark);
-            if (!JsonMQTTAddMetadata(p->flow, tx_id, jb)) {
-                jb_restore_mark(jb, &mark);
-            }
-            break;
-        case ALPROTO_QUIC:
-            jb_get_mark(jb, &mark);
-            if (!JsonQuicAddMetadata(p->flow, tx_id, jb)) {
-                jb_restore_mark(jb, &mark);
-            }
-            break;
-        case ALPROTO_SNMP:
-            AlertJsonSNMP(p->flow, tx_id, jb);
-            break;
-        case ALPROTO_RDP:
-            AlertJsonRDP(p->flow, tx_id, jb);
-            break;
-        case ALPROTO_MODBUS:
-            jb_get_mark(jb, &mark);
-            if (!JsonModbusAddMetadata(p->flow, tx_id, jb)) {
-                jb_restore_mark(jb, &mark);
-            }
-            break;
-        case ALPROTO_BITTORRENT_DHT:
-            AlertJsonBitTorrentDHT(p->flow, tx_id, jb);
-            break;
         default:
             break;
     }
index 08b7dc4d722c94dea429967f5e7c39704288f205..066df78f61fb95236bcb4332ed8e75678f34cad0 100644 (file)
@@ -65,11 +65,9 @@ static int JsonBitTorrentDHTLogger(ThreadVars *tv, void *thread_data, const Pack
         return TM_ECODE_FAILED;
     }
 
-    jb_open_object(js, "bittorrent_dht");
     if (!rs_bittorrent_dht_logger_log(tx, js)) {
         goto error;
     }
-    jb_close(js);
 
     OutputJsonBuilderBuffer(js, thread->ctx);
     jb_free(js);
index 97b1e92e00ce96f3ac8c5a10d43dbc6f8e0e5043..4336e04e070c792e0f5234200da5cb822dffa061 100644 (file)
@@ -210,6 +210,27 @@ void JsonDNP3LogResponse(JsonBuilder *js, DNP3Transaction *dnp3tx)
     jb_close(js);
 }
 
+bool AlertJsonDnp3(void *vtx, JsonBuilder *js)
+{
+    DNP3Transaction *tx = (DNP3Transaction *)vtx;
+    bool logged = false;
+    jb_open_object(js, "dnp3");
+    if (tx->is_request && tx->done) {
+        jb_open_object(js, "request");
+        JsonDNP3LogRequest(js, tx);
+        jb_close(js);
+        logged = true;
+    }
+    if (!tx->is_request && tx->done) {
+        jb_open_object(js, "response");
+        JsonDNP3LogResponse(js, tx);
+        jb_close(js);
+        logged = true;
+    }
+    jb_close(js);
+    return logged;
+}
+
 static int JsonDNP3LoggerToServer(ThreadVars *tv, void *thread_data,
     const Packet *p, Flow *f, void *state, void *vtx, uint64_t tx_id)
 {
index 85d02ff1011c7d63e50abb716462edd5bd8b9bd6..6f81026780d905798335bbb102556120f7c6e229 100644 (file)
@@ -24,5 +24,6 @@ void JsonDNP3LogRequest(JsonBuilder *js, DNP3Transaction *);
 void JsonDNP3LogResponse(JsonBuilder *js, DNP3Transaction *);
 
 void JsonDNP3LogRegister(void);
+bool AlertJsonDnp3(void *vtx, JsonBuilder *js);
 
 #endif /* __OUTPUT_JSON_DNP3_H__ */
index 020e27853a9eb8d224998c574cc3117b8d7fdb4b..b27c67feb24026051ced1e7243a0c2d99fc6f925 100644 (file)
@@ -263,7 +263,7 @@ typedef struct LogDnsLogThread_ {
     OutputJsonThreadCtx *ctx;
 } LogDnsLogThread;
 
-JsonBuilder *JsonDNSLogQuery(void *txptr)
+static JsonBuilder *JsonDNSLogQuery(void *txptr)
 {
     JsonBuilder *queryjb = jb_new_array();
     if (queryjb == NULL) {
@@ -292,7 +292,7 @@ JsonBuilder *JsonDNSLogQuery(void *txptr)
     return queryjb;
 }
 
-JsonBuilder *JsonDNSLogAnswer(void *txptr)
+static JsonBuilder *JsonDNSLogAnswer(void *txptr)
 {
     if (!rs_dns_do_log_answer(txptr, LOG_ALL_RRTYPES)) {
         return NULL;
@@ -304,6 +304,23 @@ JsonBuilder *JsonDNSLogAnswer(void *txptr)
     }
 }
 
+bool AlertJsonDns(void *txptr, JsonBuilder *js)
+{
+    jb_open_object(js, "dns");
+    JsonBuilder *qjs = JsonDNSLogQuery(txptr);
+    if (qjs != NULL) {
+        jb_set_object(js, "query", qjs);
+        jb_free(qjs);
+    }
+    JsonBuilder *ajs = JsonDNSLogAnswer(txptr);
+    if (ajs != NULL) {
+        jb_set_object(js, "answer", ajs);
+        jb_free(ajs);
+    }
+    jb_close(js);
+    return true;
+}
+
 static int JsonDnsLoggerToServer(ThreadVars *tv, void *thread_data,
     const Packet *p, Flow *f, void *alstate, void *txptr, uint64_t tx_id)
 {
index 1e19427361b84042680b053686ff8ce7484468e0..f46cad0110893097c9613bcba4babb62ccf4f60b 100644 (file)
@@ -26,7 +26,6 @@
 
 void JsonDnsLogRegister(void);
 
-JsonBuilder *JsonDNSLogQuery(void *txptr) __attribute__((nonnull));
-JsonBuilder *JsonDNSLogAnswer(void *txptr) __attribute__((nonnull));
+bool AlertJsonDns(void *vtx, JsonBuilder *js);
 
 #endif /* __OUTPUT_JSON_DNS_H__ */
index 3b015ea88e06b9f2aac26a08cf48a88e65b71566..1018be06ee80f759b16cca5683a413505d77edc2 100644 (file)
@@ -123,6 +123,7 @@ JsonBuilder *JsonBuildFileInfoRecord(const Packet *p, const File *ff, void *tx,
         return NULL;
 
     JsonBuilderMark mark = { 0, 0, 0 };
+    EveJsonSimpleAppLayerLogger *al;
     switch (p->flow->alproto) {
         case ALPROTO_HTTP1:
             jb_open_object(js, "http");
@@ -172,13 +173,19 @@ JsonBuilder *JsonBuildFileInfoRecord(const Packet *p, const File *ff, void *tx,
                 jb_restore_mark(js, &mark);
             }
             break;
-        case ALPROTO_HTTP2:
-            jb_get_mark(js, &mark);
-            jb_open_object(js, "http");
-            if (EveHTTP2AddMetadata(p->flow, tx_id, js)) {
-                jb_close(js);
-            } else {
-                jb_restore_mark(js, &mark);
+        default:
+            al = SCEveJsonSimpleGetLogger(p->flow->alproto);
+            if (al && al->LogTx) {
+                void *state = FlowGetAppState(p->flow);
+                if (state) {
+                    tx = AppLayerParserGetTx(p->flow->proto, p->flow->alproto, state, tx_id);
+                    if (tx) {
+                        jb_get_mark(js, &mark);
+                        if (!al->LogTx(tx, js)) {
+                            jb_restore_mark(js, &mark);
+                        }
+                    }
+                }
             }
             break;
     }
index ece9344bf409368654c9d683ef1b8f16d594c944..9fb8b8c622db685566e1177b5bcf91ef15d2aa59 100644 (file)
@@ -57,6 +57,7 @@ static void EveFTPLogCommand(FTPTransaction *tx, JsonBuilder *jb)
             return;
         }
     }
+    jb_open_object(jb, "ftp");
     jb_set_string(jb, "command", tx->command_descriptor->command_name);
     uint32_t min_length = tx->command_descriptor->command_length + 1; /* command + space */
     if (tx->request_length > min_length) {
@@ -149,6 +150,7 @@ static void EveFTPLogCommand(FTPTransaction *tx, JsonBuilder *jb)
     } else {
         JB_SET_FALSE(jb, "reply_truncated");
     }
+    jb_close(jb);
 }
 
 
@@ -169,17 +171,14 @@ static int JsonFTPLogger(ThreadVars *tv, void *thread_data,
     JsonBuilder *jb =
             CreateEveHeaderWithTxId(p, LOG_DIR_FLOW, event_type, NULL, tx_id, thread->ctx);
     if (likely(jb)) {
-        jb_open_object(jb, event_type);
         if (f->alproto == ALPROTO_FTPDATA) {
-            EveFTPDataAddMetadata(f, jb);
+            if (!EveFTPDataAddMetadata(vtx, jb)) {
+                goto fail;
+            }
         } else {
             EveFTPLogCommand(tx, jb);
         }
 
-        if (!jb_close(jb)) {
-            goto fail;
-        }
-
         OutputJsonBuilderBuffer(jb, thread);
 
         jb_free(jb);
index d762e76d0665882c5d0f878e158be5b3bb9555e0..7165ae8f6302df3b92a0f271032792fe753ae7d2 100644 (file)
@@ -61,19 +61,6 @@ typedef struct JsonHttp2LogThread_ {
     OutputJsonThreadCtx *ctx;
 } JsonHttp2LogThread;
 
-
-bool EveHTTP2AddMetadata(const Flow *f, uint64_t tx_id, JsonBuilder *jb)
-{
-    void *state = FlowGetAppState(f);
-    if (state) {
-        void *tx = AppLayerParserGetTx(f->proto, ALPROTO_HTTP2, state, tx_id);
-        if (tx) {
-            return rs_http2_log_json(tx, jb);
-        }
-    }
-    return false;
-}
-
 static int JsonHttp2Logger(ThreadVars *tv, void *thread_data, const Packet *p,
                          Flow *f, void *state, void *txptr, uint64_t tx_id)
 {
@@ -88,11 +75,9 @@ static int JsonHttp2Logger(ThreadVars *tv, void *thread_data, const Packet *p,
     if (unlikely(js == NULL))
         return 0;
 
-    jb_open_object(js, "http");
     if (!rs_http2_log_json(txptr, js)) {
         goto end;
     }
-    jb_close(js);
     OutputJsonBuilderBuffer(js, aft->ctx);
 end:
     jb_free(js);
index 66bf2ade968e852b1fd44af03b3ce1498a1a5a29..88ba420ab2dff1d9f8ab945c4c1e26f1a70e4881 100644 (file)
@@ -25,6 +25,5 @@
 #define __OUTPUT_JSON_HTTP2_H__
 
 void JsonHttp2LogRegister(void);
-bool EveHTTP2AddMetadata(const Flow *f, uint64_t tx_id, JsonBuilder *jb);
 
 #endif /* __OUTPUT_JSON_HTTP2_H__ */
index ace8c061f92dfaea1377d8d8ba5b89f8a70f5ea9..9e508ead9acc3a86899dadba5010fcf17c53e6dd 100644 (file)
@@ -136,19 +136,6 @@ static TmEcode JsonModbusLogThreadDeinit(ThreadVars *t, void *data)
     return TM_ECODE_OK;
 }
 
-bool JsonModbusAddMetadata(const Flow *f, uint64_t tx_id, JsonBuilder *js)
-{
-    void *state = FlowGetAppState(f);
-    if (state) {
-        void *tx = AppLayerParserGetTx(f->proto, ALPROTO_MODBUS, state, tx_id);
-        if (tx) {
-            return rs_modbus_to_json(tx, js);
-        }
-    }
-
-    return false;
-}
-
 void JsonModbusLogRegister(void)
 {
     /* Register as an eve sub-module. */
index 9bde2dae57a38f905c329a592e74ddabcd750954..2b07e4eb2d5c4722abf7ee02f9e043c8bbd178d4 100644 (file)
@@ -19,6 +19,5 @@
 #define __OUTPUT_JSON_MODBUS_H__
 
 void JsonModbusLogRegister(void);
-bool JsonModbusAddMetadata(const Flow *f, uint64_t tx_id, JsonBuilder *js);
 
 #endif /* __OUTPUT_JSON_MODBUS_H__ */
index 9ea890508070f20ffa5b5ceaf365b652eb8f6823..2f600343e20d7d98a1c143713834a15bb23abf8c 100644 (file)
@@ -59,17 +59,9 @@ typedef struct LogMQTTLogThread_ {
     OutputJsonThreadCtx *ctx;
 } LogMQTTLogThread;
 
-bool JsonMQTTAddMetadata(const Flow *f, uint64_t tx_id, JsonBuilder *js)
+bool JsonMQTTAddMetadata(void *vtx, JsonBuilder *js)
 {
-    MQTTState *state = FlowGetAppState(f);
-    if (state) {
-        MQTTTransaction *tx = AppLayerParserGetTx(f->proto, ALPROTO_MQTT, state, tx_id);
-        if (tx) {
-            return rs_mqtt_logger_log(tx, MQTT_DEFAULTS, js);
-        }
-    }
-
-    return false;
+    return rs_mqtt_logger_log(vtx, MQTT_DEFAULTS, js);
 }
 
 static int JsonMQTTLogger(ThreadVars *tv, void *thread_data,
index 1acb4e107faf62fb95f0f87a2283d73606a4c649..42d66f48680d0bf8f85e99ac2efd5c8eb2f8491b 100644 (file)
@@ -25,6 +25,6 @@
 #define __OUTPUT_JSON_MQTT_H__
 
 void JsonMQTTLogRegister(void);
-bool JsonMQTTAddMetadata(const Flow *f, uint64_t tx_id, JsonBuilder *js);
+bool JsonMQTTAddMetadata(void *vtx, JsonBuilder *js);
 
 #endif /* __OUTPUT_JSON_MQTT_H__ */
index fdf2d0f09340d208a0d4c7ba84ff711dd22db2b1..830ac78fdfbb410d3b1ca41ca0b1a11246a9f91f 100644 (file)
@@ -140,19 +140,6 @@ static TmEcode JsonQuicLogThreadDeinit(ThreadVars *t, void *data)
     return TM_ECODE_OK;
 }
 
-bool JsonQuicAddMetadata(const Flow *f, uint64_t tx_id, JsonBuilder *js)
-{
-    void *state = FlowGetAppState(f);
-    if (state) {
-        void *tx = AppLayerParserGetTx(f->proto, ALPROTO_QUIC, state, tx_id);
-        if (tx) {
-            return rs_quic_to_json(tx, js);
-        }
-    }
-
-    return false;
-}
-
 void JsonQuicLogRegister(void)
 {
     /* Register as an eve sub-module. */
index 2448d5063a349c9fa3cea653b1425934762f6504..48e38185f2bd20dffaa2ee562b7b928284fcdc76 100644 (file)
@@ -22,7 +22,6 @@
 #ifndef __OUTPUT_JSON_QUIC_H__
 #define __OUTPUT_JSON_QUIC_H__
 
-bool JsonQuicAddMetadata(const Flow *f, uint64_t tx_id, JsonBuilder *js);
 void JsonQuicLogRegister(void);
 
 #endif /* __OUTPUT_JSON_QUIC_H__ */
index cc12d2f1bbdc37fbac6c0b62e331fc1f42bd5228..e2b832bece139d059989747052c5b24fc4b98890 100644 (file)
 
 #include "rust-bindings.h"
 
-bool JsonRFBAddMetadata(const Flow *f, uint64_t tx_id, JsonBuilder *js)
-{
-    void *state = FlowGetAppState(f);
-    if (state) {
-        RFBTransaction *tx = AppLayerParserGetTx(f->proto, ALPROTO_RFB, state, tx_id);
-        if (tx) {
-            return rs_rfb_logger_log(tx, js);
-        }
-    }
-
-    return false;
-}
-
 static int JsonRFBLogger(ThreadVars *tv, void *thread_data,
     const Packet *p, Flow *f, void *state, void *tx, uint64_t tx_id)
 {
index 1264ee3f6b4b2c0aec99af4b50238f18a88e8d5c..7e4e48ebd4c885a805ece892cb15c692666ec756 100644 (file)
@@ -26,6 +26,4 @@
 
 void JsonRFBLogRegister(void);
 
-bool JsonRFBAddMetadata(const Flow *f, uint64_t tx_id, JsonBuilder *js);
-
 #endif /* __OUTPUT_JSON_RFB_H__ */
index 8297be1cc3eb2e8cad51a2a32131d7a162155a3b..7dd442cf6aba0727a43efaf8173cca7802440277 100644 (file)
 
 #include "rust.h"
 
-void JsonSIPAddMetadata(JsonBuilder *js, const Flow *f, uint64_t tx_id)
-{
-    SIPState *state = FlowGetAppState(f);
-    if (state) {
-        SIPTransaction *tx = AppLayerParserGetTx(f->proto, ALPROTO_SIP, state, tx_id);
-        if (tx) {
-            rs_sip_log_json(tx, js);
-        }
-    }
-}
-
 static int JsonSIPLogger(ThreadVars *tv, void *thread_data,
     const Packet *p, Flow *f, void *state, void *tx, uint64_t tx_id)
 {
index 60145dab5b984bca202883b735b58bb8f2188b89..0d2c53fa50dfc5f8cce7199112f5ad07a646170b 100644 (file)
@@ -26,6 +26,4 @@
 
 void JsonSIPLogRegister(void);
 
-void JsonSIPAddMetadata(JsonBuilder *js, const Flow *f, uint64_t tx_id);
-
 #endif /* __OUTPUT_JSON_SIP_H__ */
index 27545b6f6903e6ecd6c7af70bdf8a706a2e9f521..cbf0a7c992e453112b5339c9ad61c320c6889226 100644 (file)
@@ -59,11 +59,9 @@ static int JsonSNMPLogger(ThreadVars *tv, void *thread_data,
         return TM_ECODE_FAILED;
     }
 
-    jb_open_object(jb, "snmp");
-    if (!rs_snmp_log_json_response(jb, snmptx)) {
+    if (!rs_snmp_log_json_response(snmptx, jb)) {
         goto error;
     }
-    jb_close(jb);
 
     OutputJsonBuilderBuffer(jb, thread);
 
index 5ec70142f634c70d1e8de9bf06c2c027cd09d67b..45a8d8eab33302514e0eced4694cfcfa8f31cab6 100644 (file)
@@ -64,11 +64,9 @@ static int JsonSshLogger(ThreadVars *tv, void *thread_data, const Packet *p,
     if (unlikely(js == NULL))
         return 0;
 
-    jb_open_object(js, "ssh");
     if (!rs_ssh_log_json(txptr, js)) {
         goto end;
     }
-    jb_close(js);
     OutputJsonBuilderBuffer(js, thread);
 
 end:
index 76d42ad834e6b686997161574964cb3c38c42872..2ca48b7ae37332d0cc817684861d009a475386f2 100644 (file)
@@ -74,11 +74,9 @@ static int JsonTemplateLogger(ThreadVars *tv, void *thread_data, const Packet *p
         return TM_ECODE_FAILED;
     }
 
-    jb_open_object(js, "template");
     if (!rs_template_logger_log(tx, js)) {
         goto error;
     }
-    jb_close(js);
 
     OutputJsonBuilderBuffer(js, thread->ctx);
     jb_free(js);
index 9771f4d1cd7c0824e08dbc99e3c8e4f47d17248e..7460a32f2574e37c42971e37fc6a51e1b1a3f904 100644 (file)
@@ -392,8 +392,9 @@ static void JsonTlsLogJSONCustom(OutputTlsCtx *tls_ctx, JsonBuilder *js,
     }
 }
 
-void JsonTlsLogJSONExtended(JsonBuilder *tjs, SSLState * state)
+static bool JsonTlsLogJSONExtendedAux(void *vtx, JsonBuilder *tjs)
 {
+    SSLState *state = (SSLState *)vtx;
     JsonTlsLogJSONBasic(tjs, state);
 
     /* tls serial */
@@ -425,6 +426,15 @@ void JsonTlsLogJSONExtended(JsonBuilder *tjs, SSLState * state)
         JsonTlsLogClientCert(tjs, &state->client_connp, false, false);
         jb_close(tjs);
     }
+    return true;
+}
+
+bool JsonTlsLogJSONExtended(void *vtx, JsonBuilder *tjs)
+{
+    jb_open_object(tjs, "tls");
+    bool r = JsonTlsLogJSONExtendedAux(vtx, tjs);
+    jb_close(tjs);
+    return r;
 }
 
 static int JsonTlsLogger(ThreadVars *tv, void *thread_data, const Packet *p,
@@ -459,7 +469,7 @@ static int JsonTlsLogger(ThreadVars *tv, void *thread_data, const Packet *p,
     }
     /* log extended */
     else if (tls_ctx->flags & LOG_TLS_EXTENDED) {
-        JsonTlsLogJSONExtended(js, ssl_state);
+        JsonTlsLogJSONExtendedAux(ssl_state, js);
     }
     /* log basic */
     else {
index 737e6233ef10aa13796391801c6e34878cc9c138..42f706b91d3fd4a0d7cfc475e8559ac598af5b9d 100644 (file)
@@ -29,6 +29,6 @@ void JsonTlsLogRegister(void);
 #include "app-layer-ssl.h"
 
 void JsonTlsLogJSONBasic(JsonBuilder *js, SSLState *ssl_state);
-void JsonTlsLogJSONExtended(JsonBuilder *js, SSLState *ssl_state);
+bool JsonTlsLogJSONExtended(void *vtx, JsonBuilder *js);
 
 #endif /* __OUTPUT_JSON_TLS_H__ */
index c13ab4862edaa41436a6389ddf617579c1df9068..031831966e1705926defa00f2a6c535e40c97f00 100644 (file)
@@ -67,6 +67,8 @@
 #include "log-stats.h"
 #include "output-json-nfs.h"
 #include "output-json-ftp.h"
+// for misplaced EveFTPDataAddMetadata
+#include "app-layer-ftp.h"
 #include "output-json-tftp.h"
 #include "output-json-smb.h"
 #include "output-json-ike.h"
@@ -1126,3 +1128,53 @@ void OutputRegisterLoggers(void)
     /* BitTorrent DHT JSON logger */
     JsonBitTorrentDHTLogRegister();
 }
+
+static EveJsonSimpleAppLayerLogger simple_json_applayer_loggers[ALPROTO_MAX] = {
+    { ALPROTO_UNKNOWN, NULL },
+    { ALPROTO_HTTP1, NULL }, // special: uses some options flags
+    { ALPROTO_FTP, NULL },   // TODO missing
+    { ALPROTO_SMTP, NULL },  // special: uses state
+    { ALPROTO_TLS, JsonTlsLogJSONExtended },
+    { ALPROTO_SSH, rs_ssh_log_json },
+    { ALPROTO_IMAP, NULL },   // protocol detection only
+    { ALPROTO_JABBER, NULL }, // no parser, no logging
+    { ALPROTO_SMB, NULL },    // special: uses state
+    { ALPROTO_DCERPC, NULL }, // TODO missing
+    { ALPROTO_IRC, NULL },    // no parser, no logging
+    { ALPROTO_DNS, AlertJsonDns },
+    { ALPROTO_MODBUS, (EveJsonSimpleTxLogFunc)rs_modbus_to_json },
+    { ALPROTO_ENIP, NULL }, // no logging
+    { ALPROTO_DNP3, AlertJsonDnp3 },
+    { ALPROTO_NFS, NULL }, // special: uses state
+    { ALPROTO_NTP, NULL }, // no logging
+    { ALPROTO_FTPDATA, EveFTPDataAddMetadata },
+    { ALPROTO_TFTP, NULL }, // TODO missing
+    { ALPROTO_IKE, NULL },  // special: uses state
+    { ALPROTO_KRB5, NULL }, // TODO missing
+    { ALPROTO_QUIC, rs_quic_to_json },
+    { ALPROTO_DHCP, NULL }, // TODO missing
+    { ALPROTO_SNMP, (EveJsonSimpleTxLogFunc)rs_snmp_log_json_response },
+    { ALPROTO_SIP, (EveJsonSimpleTxLogFunc)rs_sip_log_json },
+    { ALPROTO_RFB, rs_rfb_logger_log },
+    { ALPROTO_MQTT, JsonMQTTAddMetadata },
+    { ALPROTO_PGSQL, NULL },  // TODO missing
+    { ALPROTO_TELNET, NULL }, // no logging
+    { ALPROTO_TEMPLATE, rs_template_logger_log },
+    { ALPROTO_RDP, (EveJsonSimpleTxLogFunc)rs_rdp_to_json },
+    { ALPROTO_HTTP2, rs_http2_log_json },
+    { ALPROTO_BITTORRENT_DHT, rs_bittorrent_dht_logger_log },
+    { ALPROTO_HTTP, NULL }, // signature protocol, not for app-layer logging
+    { ALPROTO_FAILED, NULL },
+#ifdef UNITTESTS
+    { ALPROTO_TEST, NULL },
+#endif /* UNITESTS */
+};
+
+EveJsonSimpleAppLayerLogger *SCEveJsonSimpleGetLogger(AppProto alproto)
+{
+    if (alproto < ALPROTO_MAX) {
+        BUG_ON(simple_json_applayer_loggers[alproto].proto != alproto);
+        return &simple_json_applayer_loggers[alproto];
+    }
+    return NULL;
+}
index 5c2d7bc90e62905bc0fa02ca004efc337587bee0..815b2f20ed732087489dfb755f41f6125c8879ea 100644 (file)
@@ -208,4 +208,13 @@ void OutputLoggerExitPrintStats(ThreadVars *, void *);
 void OutputSetupActiveLoggers(void);
 void OutputClearActiveLoggers(void);
 
+typedef bool (*EveJsonSimpleTxLogFunc)(void *, struct JsonBuilder *);
+
+typedef struct EveJsonSimpleAppLayerLogger {
+    AppProto proto;
+    EveJsonSimpleTxLogFunc LogTx;
+} EveJsonSimpleAppLayerLogger;
+
+EveJsonSimpleAppLayerLogger *SCEveJsonSimpleGetLogger(AppProto alproto);
+
 #endif /* ! __OUTPUT_H__ */