prelude: add protocol information through JSON

pull/3271/head
Thomas Andrejak 8 years ago committed by Victor Julien
parent 6162ef57bd
commit eb12001c82

@ -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 <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);

Loading…
Cancel
Save