From: Thomas Andrejak Date: Thu, 8 Jun 2017 12:56:26 +0000 (+0200) Subject: prelude: add protocol information through JSON X-Git-Tag: suricata-4.1.0-beta1~114 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=eb12001c82f78422061a593e1dbce51e67202931;p=thirdparty%2Fsuricata.git prelude: add protocol information through JSON --- diff --git a/src/alert-prelude.c b/src/alert-prelude.c index 9903fef7c7..00d4e379af 100644 --- a/src/alert-prelude.c +++ b/src/alert-prelude.c @@ -53,6 +53,17 @@ #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 +#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);