]> git.ipfire.org Git - thirdparty/suricata.git/commitdiff
prelude: add protocol information through JSON
authorThomas Andrejak <thomas.andrejak@gmail.com>
Thu, 8 Jun 2017 12:56:26 +0000 (14:56 +0200)
committerVictor Julien <victor@inliniac.net>
Mon, 5 Mar 2018 15:14:51 +0000 (16:14 +0100)
src/alert-prelude.c

index 9903fef7c74f0a0f098e173ad514b85d21bfa63c..00d4e379afdec130172ee075f19587222712f892 100644 (file)
 #include "util-print.h"
 
 #include "output.h"
+
+#ifdef HAVE_LIBJANSSON
+#include "output-json.h"
+#include "output-json-http.h"
+#include "output-json-tls.h"
+#include "output-json-ssh.h"
+#include "output-json-smtp.h"
+#include "output-json-email-common.h"
+#include <jansson.h>
+#endif
+
 #include "util-privs.h"
 #include "util-optimize.h"
 
@@ -462,6 +473,103 @@ static int AddIntData(idmef_alert_t *alert, const char *meaning, uint32_t data)
     SCReturnInt(0);
 }
 
+#ifdef HAVE_LIBJANSSON
+/**
+ * \brief Add string data, to be stored in the Additional Data
+ * field of the IDMEF alert (see section 4.2.4.6 of RFC 4765).
+ * \param alert IDMEF alert where to add additional data
+ * \param meaning Name of the value to add to IDMEF alert
+ * \param data String to add to IDMEF alert
+ * \return 0 if ok, else < 0
+ */
+static int AddStringData(idmef_alert_t *alert, const char *meaning, const char *data)
+{
+    int ret;
+    idmef_additional_data_t *ad;
+    prelude_string_t * p_str;
+
+    SCEnter();
+
+    ret = idmef_alert_new_additional_data(alert, &ad, IDMEF_LIST_APPEND);
+    if (unlikely(ret < 0))
+        SCReturnInt(ret);
+
+    ret = idmef_additional_data_new_meaning(ad, &p_str);
+    if (ret < 0) {
+        idmef_additional_data_destroy(ad);
+        SCReturnInt(ret);
+    }
+
+    ret = prelude_string_ncat(p_str, meaning, strlen(meaning));
+    if (ret < 0) {
+        idmef_additional_data_destroy(ad);
+        SCReturnInt(ret);
+    }
+
+    ret = prelude_string_new(&p_str);
+    if (ret < 0) {
+        idmef_additional_data_destroy(ad);
+        SCReturnInt(ret);
+    }
+
+    ret = prelude_string_ncat(p_str, data, strlen(data));
+    if (ret < 0) {
+        prelude_string_destroy(p_str);
+        idmef_additional_data_destroy(ad);
+        SCReturnInt(ret);
+    }
+
+    ret = idmef_additional_data_set_string_dup_fast(ad, prelude_string_get_string(p_str), prelude_string_get_len(p_str));
+
+    prelude_string_destroy(p_str);
+
+    if (ret < 0) {
+        idmef_additional_data_destroy(ad);
+        SCReturnInt(ret);
+    }
+    SCReturnInt(0);
+}
+
+/**
+ * \brief Add real data, to be stored in the Additional Data
+ * field of the IDMEF alert (see section 4.2.4.6 of RFC 4765).
+ * \param alert IDMEF alert where to add additional data
+ * \param meaning Name of the value to add to IDMEF alert
+ * \param data Real to add to IDMEF alert
+ * \return 0 if ok
+ */
+static int AddRealData(idmef_alert_t *alert, const char *meaning, uint32_t data)
+{
+    int ret;
+    prelude_string_t *str;
+    idmef_additional_data_t *ad;
+
+    SCEnter();
+
+    ret = idmef_alert_new_additional_data(alert, &ad, IDMEF_LIST_APPEND);
+    if (unlikely(ret < 0))
+        SCReturnInt(ret);
+
+    idmef_additional_data_set_real(ad, data);
+
+    ret = idmef_additional_data_new_meaning(ad, &str);
+    if (unlikely(ret < 0)) {
+        SCLogDebug("%s: error creating additional-data meaning: %s.",
+                        prelude_strsource(ret), prelude_strerror(ret));
+        SCReturnInt(-1);
+    }
+
+    ret = prelude_string_set_ref(str, meaning);
+    if (unlikely(ret < 0)) {
+        SCLogDebug("%s: error setting integer data meaning: %s.",
+                        prelude_strsource(ret), prelude_strerror(ret));
+        SCReturnInt(-1);
+    }
+
+    SCReturnInt(0);
+}
+#endif
+
 /**
  * \brief Add IPv4 header data, to be stored in the Additional Data
  * field of the IDMEF alert (see section 4.2.4.6 of RFC 4765).
@@ -510,6 +618,185 @@ static int PacketToDataV6(const Packet *p, const PacketAlert *pa, idmef_alert_t
     SCReturnInt(0);
 }
 
+#ifdef HAVE_LIBJANSSON
+/**
+ * \brief Convert JSON object to Prelude additional data with
+ * the right type of data. Browse the JSON object to get
+ * the key=value information.
+ * \param key Name of the JSON value
+ * \param value JSON object to add to the IDMEF alert
+ * \param alert IDMEF alert
+ * \return 0 if ok
+ */
+static int JsonToAdditionalData(const char * key, json_t * value, idmef_alert_t *alert) {
+    int ret;
+    const char *key_js;
+    char local_key[128];
+    json_t *value_js;
+    size_t index;
+    SCEnter();
+
+    if (!json_is_object(value) && key == NULL)
+        SCReturnInt(-1);
+
+    if (json_is_object(value)) {
+        json_object_foreach(value, key_js, value_js) {
+            if (key != NULL) {
+                snprintf(local_key, sizeof(local_key), "%s_%s", key, key_js);
+            } else {
+                snprintf(local_key, sizeof(local_key), "%s", key_js);
+            }
+            ret = JsonToAdditionalData(local_key, value_js, alert);
+        }
+    } else if (json_is_array(value)) {
+        json_array_foreach(value, index, value_js) {
+            ret = snprintf(local_key, sizeof(local_key), "%s_%ju", key, (uintmax_t)index);
+            if (ret < 0 || (size_t)ret >= sizeof(local_key)) {
+                SCLogError(SC_ERR_SPRINTF,"failed to construct key");
+                continue;
+            }
+            ret = JsonToAdditionalData(local_key, value_js, alert);
+        }
+    } else if (json_is_integer(value)) {
+        ret = AddIntData(alert, key, json_integer_value(value));
+    } else if (json_is_real(value)) {
+        ret = AddRealData(alert, key, json_real_value(value));
+    } else if (json_is_boolean(value)) {
+        ret = AddIntData(alert, key, json_is_true(value));
+    } else if (json_is_string(value)) {
+        ret = AddStringData(alert, key, json_string_value(value));
+    } else {
+        ret = AddStringData(alert, key, json_dumps(value, 0));
+    }
+    SCReturnInt(ret);
+}
+
+/**
+ * \brief Handle ALPROTO_HTTP JSON information
+ * \param p Packet where to extract data
+ * \param pa Packet alert information
+ * \param alert IDMEF alert
+ * \return void
+ */
+static void PacketToDataProtoHTTP(const Packet *p, const PacketAlert *pa, idmef_alert_t *alert)
+{
+    json_t *js;
+
+    js = JsonHttpAddMetadata(p->flow, pa->tx_id);
+    if (js == NULL)
+        return;
+
+    JsonToAdditionalData(NULL, js, alert);
+
+    json_decref(js);
+
+}
+
+/**
+ * \brief Handle ALPROTO_TLS JSON information
+ * \param p Packet where to extract data
+ * \param pa Packet alert information
+ * \param alert IDMEF alert
+ * \return void
+ */
+static void PacketToDataProtoTLS(const Packet *p, const PacketAlert *pa, idmef_alert_t *alert)
+{
+    json_t *js;
+    SSLState *ssl_state = (SSLState *)FlowGetAppState(p->flow);
+
+    if (ssl_state == NULL)
+        return;
+
+    js = json_object();
+    if (js == NULL)
+        return;
+
+    JsonTlsLogJSONBasic(js, ssl_state);
+    JsonTlsLogJSONExtended(js, ssl_state);
+    JsonToAdditionalData(NULL, js, alert);
+
+    json_decref(js);
+
+}
+
+/**
+ * \brief Handle ALPROTO_SSH JSON information
+ * \param p Packet where to extract data
+ * \param pa Packet alert information
+ * \param alert IDMEF alert
+ * \return void
+ */
+static void PacketToDataProtoSSH(const Packet *p, const PacketAlert *pa, idmef_alert_t *alert)
+{
+    json_t *js, *s_js;
+    SshState *ssh_state = (SshState *)FlowGetAppState(p->flow);
+
+    if (ssh_state == NULL)
+        return;
+
+    js = json_object();
+    if (js == NULL)
+        return;
+
+    JsonSshLogJSON(js, ssh_state);
+
+    s_js = json_object_get(js, "server");
+    if (s_js != NULL) {
+        JsonToAdditionalData(NULL, s_js, alert);
+    }
+
+    s_js = json_object_get(js, "client");
+    if (s_js != NULL) {
+        JsonToAdditionalData(NULL, s_js, alert);
+    }
+
+    json_decref(js);
+
+}
+
+/**
+ * \brief Handle ALPROTO_SMTP JSON information
+ * \param p Packet where to extract data
+ * \param pa Packet alert information
+ * \param alert IDMEF alert
+ * \return void
+ */
+static void PacketToDataProtoSMTP(const Packet *p, const PacketAlert *pa, idmef_alert_t *alert)
+{
+    json_t *js;
+
+    js = JsonSMTPAddMetadata(p->flow, pa->tx_id);
+    if (js == NULL)
+        return;
+
+    JsonToAdditionalData(NULL, js, alert);
+
+    json_decref(js);
+
+}
+
+/**
+ * \brief Handle ALPROTO_(SMTP|IMAP) Email JSON information
+ * \param p Packet where to extract data
+ * \param pa Packet alert information
+ * \param alert IDMEF alert
+ * \return void
+ */
+static void PacketToDataProtoEmail(const Packet *p, const PacketAlert *pa, idmef_alert_t *alert)
+{
+    json_t *js;
+
+    js = JsonEmailAddMetadata(p->flow, pa->tx_id);
+    if (js == NULL)
+        return;
+
+    JsonToAdditionalData(NULL, js, alert);
+
+    json_decref(js);
+
+}
+
+#endif
 
 /**
  * \brief Convert IP packet to an IDMEF alert (RFC 4765).
@@ -525,6 +812,28 @@ static int PacketToData(const Packet *p, const PacketAlert *pa, idmef_alert_t *a
     if (unlikely(p == NULL))
         SCReturnInt(0);
 
+#ifdef HAVE_LIBJANSSON
+    if (p->flow != NULL) {
+        uint16_t proto = FlowGetAppProtocol(p->flow);
+        switch (proto) {
+            case ALPROTO_HTTP:
+                PacketToDataProtoHTTP(p, pa, alert);
+                break;
+            case ALPROTO_TLS:
+                PacketToDataProtoTLS(p, pa, alert);
+                break;
+            case ALPROTO_SSH:
+                PacketToDataProtoSSH(p, pa, alert);
+                break;
+            case ALPROTO_SMTP:
+            case ALPROTO_IMAP:
+                PacketToDataProtoSMTP(p, pa, alert);
+                PacketToDataProtoEmail(p, pa, alert);
+                break;
+        }
+    }
+#endif
+
     AddIntData(alert, "snort_rule_sid", pa->s->id);
     AddIntData(alert, "snort_rule_rev", pa->s->rev);