diff options
author | Sergey Avseyev <sergey.avseyev@gmail.com> | 2014-12-04 13:22:22 +0300 |
---|---|---|
committer | Anders Broman <a.broman58@gmail.com> | 2014-12-10 07:16:43 +0000 |
commit | c46fa33b418d97e116d0440d2a2375a085a1f227 (patch) | |
tree | 4cd8989ba64b295b0ca06ac73369316c4efa5306 | |
parent | 1f8b16e7ea08be08d15e87dcb139e3d60cf326fd (diff) |
Riemann protocol dissector
Homepage: http://riemann.io/
Sample capture:
http://files.avsej.net/riemann-sample.pcapng
Protocol definition:
https://github.com/aphyr/riemann-java-client/blob/master/src/main/proto/riemann/proto.proto
Implementor's guide:
http://riemann.io/howto.html#write-a-client
Bug: 10758
Change-Id: I28634453423127fe647eb92e48072a90a7f5d232
Reviewed-on: https://code.wireshark.org/review/5620
Reviewed-by: Pascal Quantin <pascal.quantin@gmail.com>
Petri-Dish: Pascal Quantin <pascal.quantin@gmail.com>
Tested-by: Petri Dish Buildbot <buildbot-no-reply@wireshark.org>
Reviewed-by: Alexis La Goutte <alexis.lagoutte@gmail.com>
Reviewed-by: Anders Broman <a.broman58@gmail.com>
-rw-r--r-- | docbook/release-notes.asciidoc | 1 | ||||
-rw-r--r-- | epan/CMakeLists.txt | 1 | ||||
-rw-r--r-- | epan/dissectors/Makefile.common | 1 | ||||
-rw-r--r-- | epan/dissectors/packet-riemann.c | 827 |
4 files changed, 830 insertions, 0 deletions
diff --git a/docbook/release-notes.asciidoc b/docbook/release-notes.asciidoc index dd3adf0d95..72335dc36b 100644 --- a/docbook/release-notes.asciidoc +++ b/docbook/release-notes.asciidoc @@ -90,6 +90,7 @@ AllJoyn Reliable Datagram Protocol HiQnet Elasticsearch Shared Memory Communications - RDMA +Riemann --sort-and-group-- === Updated Protocol Support diff --git a/epan/CMakeLists.txt b/epan/CMakeLists.txt index 5045c6a1ae..8f00aca32a 100644 --- a/epan/CMakeLists.txt +++ b/epan/CMakeLists.txt @@ -1158,6 +1158,7 @@ set(DISSECTOR_SRC dissectors/packet-rfid-pn532.c dissectors/packet-rfid-pn532-hci.c dissectors/packet-rgmp.c + dissectors/packet-riemann.c dissectors/packet-rip.c dissectors/packet-ripng.c dissectors/packet-rlc-lte.c diff --git a/epan/dissectors/Makefile.common b/epan/dissectors/Makefile.common index 35b87f8ea3..5f715bce8a 100644 --- a/epan/dissectors/Makefile.common +++ b/epan/dissectors/Makefile.common @@ -1070,6 +1070,7 @@ DISSECTOR_SRC = \ packet-rfid-pn532.c \ packet-rfid-pn532-hci.c \ packet-rgmp.c \ + packet-riemann.c \ packet-rip.c \ packet-ripng.c \ packet-rlc-lte.c \ diff --git a/epan/dissectors/packet-riemann.c b/epan/dissectors/packet-riemann.c new file mode 100644 index 0000000000..84345e4a7b --- /dev/null +++ b/epan/dissectors/packet-riemann.c @@ -0,0 +1,827 @@ +/** + * packet-riemann.c + * Routines for Riemann dissection + * Copyright 2014, Sergey Avseyev <sergey.avseyev@gmail.com> + * + * Wireshark - Network traffic analyzer + * By Gerald Combs <gerald@wireshark.org> + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +/* Riemann (http://riemann.io) aggregates events from servers and + * applications with a powerful stream processing language. + * + * Protobuf structures layout: + * https://github.com/aphyr/riemann-java-client/blob/master/src/main/proto/riemann/proto.proto + * + * message State { + * optional int64 time = 1; + * optional string state = 2; + * optional string service = 3; + * optional string host = 4; + * optional string description = 5; + * optional bool once = 6; + * repeated string tags = 7; + * optional float ttl = 8; + * } + * + * message Event { + * optional int64 time = 1; + * optional string state = 2; + * optional string service = 3; + * optional string host = 4; + * optional string description = 5; + * repeated string tags = 7; + * optional float ttl = 8; + * repeated Attribute attributes = 9; + * + * optional sint64 metric_sint64 = 13; + * optional double metric_d = 14; + * optional float metric_f = 15; + * } + * + * message Query { + * optional string string = 1; + * } + * + * message Msg { + * optional bool ok = 2; + * optional string error = 3; + * repeated State states = 4; + * optional Query query = 5; + * repeated Event events = 6; + * } + * + * message Attribute { + * required string key = 1; + * optional string value = 2; + * } + */ + +#include "config.h" + +#include <glib.h> + +#include <epan/packet.h> +#include <epan/prefs.h> +#include <epan/expert.h> + +void proto_reg_handoff_riemann(void); +void proto_register_riemann(void); + +static int proto_riemann = -1; +static int hf_riemann_msg_ok = -1; +static int hf_riemann_msg_error = -1; +static int hf_riemann_attribute = -1; +static int hf_riemann_attribute_key = -1; +static int hf_riemann_attribute_value = -1; +static int hf_riemann_query = -1; +static int hf_riemann_query_string = -1; +static int hf_riemann_event = -1; +static int hf_riemann_event_state = -1; +static int hf_riemann_event_service = -1; +static int hf_riemann_event_host = -1; +static int hf_riemann_event_description = -1; +static int hf_riemann_event_tag = -1; +static int hf_riemann_event_ttl = -1; +static int hf_riemann_event_time = -1; +static int hf_riemann_event_metric_d = -1; +static int hf_riemann_event_metric_f = -1; +static int hf_riemann_event_metric_sint64 = -1; +static int hf_riemann_state = -1; +static int hf_riemann_state_service = -1; +static int hf_riemann_state_host = -1; +static int hf_riemann_state_description = -1; +static int hf_riemann_state_tag = -1; +static int hf_riemann_state_ttl = -1; +static int hf_riemann_state_time = -1; +static int hf_riemann_state_state = -1; +static int hf_riemann_state_once = -1; + +static guint udp_port_pref = 0; + +static gint ett_riemann = -1; +static gint ett_query = -1; +static gint ett_event = -1; +static gint ett_attribute = -1; +static gint ett_state = -1; + +#define riemann_MIN_LENGTH 16 +#define MAX_NEEDED_FOR_HEURISTICS 10 + +/* field numbers. see protocol definition above */ +#define FN_MSG_OK 2 +#define FN_MSG_ERROR 3 +#define FN_MSG_STATES 4 +#define FN_MSG_QUERY 5 +#define FN_MSG_EVENTS 6 + +#define FN_EVENT_TIME 1 +#define FN_EVENT_STATE 2 +#define FN_EVENT_SERVICE 3 +#define FN_EVENT_HOST 4 +#define FN_EVENT_DESCRIPTION 5 +#define FN_EVENT_TAGS 7 +#define FN_EVENT_TTL 8 +#define FN_EVENT_ATTRIBUTES 9 +#define FN_EVENT_METRIC_SINT64 13 +#define FN_EVENT_METRIC_D 14 +#define FN_EVENT_METRIC_F 15 + +#define FN_ATTRIBUTE_KEY 1 +#define FN_ATTRIBUTE_VALUE 2 + +#define FN_STATE_TIME 1 +#define FN_STATE_STATE 2 +#define FN_STATE_SERVICE 3 +#define FN_STATE_HOST 4 +#define FN_STATE_DESCRIPTION 5 +#define FN_STATE_ONCE 6 +#define FN_STATE_TAGS 7 +#define FN_STATE_TTL 8 + +#define FN_QUERY_STRING 1 + +/* type codes. see protocol definition above */ +#define WIRE_INTEGER 0 +#define WIRE_DOUBLE 1 +#define WIRE_BYTES 2 +#define WIRE_FLOAT 5 + +static expert_field ef_error_unknown_wire_tag = EI_INIT; +static expert_field ef_error_unknown_field_number = EI_INIT; +static expert_field ef_error_insufficient_data = EI_INIT; + +static void +riemann_verify_wire_format(guint64 field_number, const char *field_name, int expected, int actual, + packet_info *pinfo, proto_item *pi) +{ + if (expected != actual) { + const char *wire_name; + + switch (expected) { + case WIRE_INTEGER: + wire_name = "integer"; + break; + case WIRE_BYTES: + wire_name = "bytes/string"; + break; + case WIRE_FLOAT: + wire_name = "float"; + break; + case WIRE_DOUBLE: + wire_name = "double"; + break; + default: + wire_name = "unknown (check packet-riemann.c)"; + break; + } + expert_add_info_format(pinfo, pi, &ef_error_unknown_wire_tag, + "Expected %s (%d) field to be an %s (%d), but it is %d", + field_name, (int)field_number, wire_name, expected, actual); + } +} + +#define VERIFY_WIRE_FORMAT(field_name, expected) \ + riemann_verify_wire_format(fn, field_name, expected, wire, pinfo, pi) + +#define UNKNOWN_FIELD_NUMBER_FOR(message_name) \ + expert_add_info_format(pinfo, pi, &ef_error_unknown_field_number, \ + "Unknown field number %d for " message_name " (wire format %d)", \ + (int)fn, (int)wire); + +#define VERIFY_SIZE_FOR(message_name) \ + if (size < 0) { \ + expert_add_info_format(pinfo, pi, &ef_error_insufficient_data, \ + "Insufficient data for " message_name " (%d bytes needed)", \ + (int)size * -1); \ + } + +static guint64 +riemann_get_guint64(tvbuff_t *tvb, guint offset, guint *len) +{ + guint64 num = 0; + guint shift = 0; + *len = 0; + while (1) { + guint8 b; + if (shift >= 64) { + return 0; + } + b = tvb_get_guint8(tvb, offset++); + num |= ((b & 0x7f) << shift); + shift += 7; + (*len)++; + if ((b & 0x80) == 0) { + return num; + } + } + return 0; +} + +static guint8 * +riemann_get_string(tvbuff_t *tvb, gint offset) +{ + guint64 size; + guint len = 0; + + size = riemann_get_guint64(tvb, offset, &len); + offset += len; + return tvb_get_string_enc(wmem_packet_scope(), tvb, offset, (gint)size, ENC_ASCII); +} + +static guint +riemann_dissect_int64(proto_tree *riemann_tree, tvbuff_t *tvb, guint offset, int hf_index) +{ + guint64 num; + guint len = 0; + + num = riemann_get_guint64(tvb, offset, &len); + proto_tree_add_int64(riemann_tree, hf_index, tvb, offset, len, num); + return len; +} + +static guint +riemann_dissect_sint64(proto_tree *riemann_tree, tvbuff_t *tvb, guint offset, int hf_index) +{ + guint64 num; + gint64 snum; + guint len = 0; + + num = riemann_get_guint64(tvb, offset, &len); + /* zigzag decoding */ + if (num & 1) { + snum = -((gint64)(num >> 1)) - 1; + } else { + snum = (gint64)(num >> 1); + } + + proto_tree_add_int64(riemann_tree, hf_index, tvb, offset, len, snum); + return len; +} + +static guint +riemann_dissect_string(proto_tree *riemann_tree, tvbuff_t *tvb, guint offset, int hf_index) +{ + guint64 size; + guint len = 0, orig_offset = offset; + + size = riemann_get_guint64(tvb, offset, &len); + offset += len; + proto_tree_add_item(riemann_tree, hf_index, tvb, offset, (gint)size, ENC_ASCII); + offset += (gint)size; + + return offset - orig_offset; +} + +static guint +riemann_dissect_attribute(packet_info *pinfo, proto_tree *riemann_tree, + tvbuff_t *tvb, guint offset) +{ + guint64 tag, fn; + gint64 size; + guint8 wire; + guint len = 0; + guint orig_offset = offset; + proto_item *pi; + proto_tree *attribute_tree; + + size = (gint64)riemann_get_guint64(tvb, offset, &len); + pi = proto_tree_add_item(riemann_tree, hf_riemann_attribute, tvb, (gint)offset, (gint)(size + len), ENC_NA); + attribute_tree = proto_item_add_subtree(pi, ett_attribute); + offset += len; + + while (size > 0) { + tag = riemann_get_guint64(tvb, offset, &len); + fn = tag >> 3; + wire = tag & 0x7; + offset += len; + size -= len; + switch (fn) { + case FN_ATTRIBUTE_KEY: + VERIFY_WIRE_FORMAT("Attribute.key", WIRE_BYTES); + len = riemann_dissect_string(attribute_tree, tvb, offset, hf_riemann_attribute_key); + break; + case FN_ATTRIBUTE_VALUE: + VERIFY_WIRE_FORMAT("Attribute.value", WIRE_BYTES); + len = riemann_dissect_string(attribute_tree, tvb, offset, hf_riemann_attribute_value); + break; + default: + len = 0; + UNKNOWN_FIELD_NUMBER_FOR("Attribute"); + } + offset += len; + size -= len; + } + VERIFY_SIZE_FOR("Attribute"); + + return offset - orig_offset; +} + +static guint +riemann_dissect_query(packet_info *pinfo, proto_tree *riemann_tree, + tvbuff_t *tvb, guint offset) +{ + guint64 tag, fn; + gint64 size; + guint8 wire; + guint orig_offset = offset, len = 0; + proto_item *pi; + proto_tree *query_tree; + + size = (gint64)riemann_get_guint64(tvb, offset, &len); + pi = proto_tree_add_item(riemann_tree, hf_riemann_query, tvb, (gint)offset, (gint)(size + len), ENC_NA); + query_tree = proto_item_add_subtree(pi, ett_query); + offset += len; + + while (size > 0) { + tag = riemann_get_guint64(tvb, offset, &len); + fn = tag >> 3; + wire = tag & 0x7; + offset += len; + size -= len; + switch (fn) { + case FN_QUERY_STRING: + VERIFY_WIRE_FORMAT("Query.string", WIRE_BYTES); + col_append_str(pinfo->cinfo, COL_INFO, riemann_get_string(tvb, offset)); + len = riemann_dissect_string(query_tree, tvb, offset, hf_riemann_query_string); + break; + default: + len = 0; + UNKNOWN_FIELD_NUMBER_FOR("Query"); + } + offset += len; + size -= len; + } + VERIFY_SIZE_FOR("Query"); + + return offset - orig_offset; +} + +static guint +riemann_dissect_event(packet_info *pinfo, proto_tree *riemann_tree, + tvbuff_t *tvb, guint offset) +{ + guint orig_offset = offset, len = 0; + guint64 tag, fn; + gint64 size; + guint8 wire; + proto_item *pi; + proto_tree *event_tree; + gboolean need_comma = FALSE; + + size = riemann_get_guint64(tvb, offset, &len); + pi = proto_tree_add_item(riemann_tree, hf_riemann_event, tvb, (gint)offset, (gint)(size + len), ENC_NA); + event_tree = proto_item_add_subtree(pi, ett_event); + offset += len; + + while (size > 0) { + const char *comma = need_comma ? ", " : ""; + tag = riemann_get_guint64(tvb, offset, &len); + fn = tag >> 3; + wire = tag & 0x7; + offset += len; + size -= len; + switch (fn) { + case FN_EVENT_TIME: + VERIFY_WIRE_FORMAT("Event.time", WIRE_INTEGER); + len = riemann_dissect_int64(event_tree, tvb, offset, hf_riemann_event_time); + break; + case FN_EVENT_STATE: + VERIFY_WIRE_FORMAT("Event.state", WIRE_BYTES); + len = riemann_dissect_string(event_tree, tvb, offset, hf_riemann_event_state); + break; + case FN_EVENT_SERVICE: + VERIFY_WIRE_FORMAT("Event.service", WIRE_BYTES); + col_append_fstr(pinfo->cinfo, COL_INFO, "%s%s", comma, riemann_get_string(tvb, offset)); + len = riemann_dissect_string(event_tree, tvb, offset, hf_riemann_event_service); + need_comma = TRUE; + break; + case FN_EVENT_HOST: + VERIFY_WIRE_FORMAT("Event.host", WIRE_BYTES); + col_append_fstr(pinfo->cinfo, COL_INFO, "%s%s", comma, riemann_get_string(tvb, offset)); + len = riemann_dissect_string(event_tree, tvb, offset, hf_riemann_event_host); + need_comma = TRUE; + break; + case FN_EVENT_DESCRIPTION: + VERIFY_WIRE_FORMAT("Event.description", WIRE_BYTES); + len = riemann_dissect_string(event_tree, tvb, offset, hf_riemann_event_description); + break; + case FN_EVENT_TAGS: + VERIFY_WIRE_FORMAT("Event.tags", WIRE_BYTES); + len = riemann_dissect_string(event_tree, tvb, offset, hf_riemann_event_tag); + break; + case FN_EVENT_TTL: + VERIFY_WIRE_FORMAT("Event.ttl", WIRE_FLOAT); + proto_tree_add_item(event_tree, hf_riemann_event_ttl, tvb, offset, 4, ENC_LITTLE_ENDIAN); + len = 4; + break; + case FN_EVENT_ATTRIBUTES: + VERIFY_WIRE_FORMAT("Event.attributes", WIRE_BYTES); + len = riemann_dissect_attribute(pinfo, event_tree, tvb, offset); + break; + case FN_EVENT_METRIC_SINT64: + VERIFY_WIRE_FORMAT("Event.metric_sint64", WIRE_INTEGER); + len = riemann_dissect_sint64(event_tree, tvb, offset, hf_riemann_event_metric_sint64); + break; + case FN_EVENT_METRIC_D: + VERIFY_WIRE_FORMAT("Event.metric_d", WIRE_DOUBLE); + proto_tree_add_item(riemann_tree, hf_riemann_event_metric_d, tvb, offset, 8, ENC_LITTLE_ENDIAN); + len = 8; + break; + case FN_EVENT_METRIC_F: + VERIFY_WIRE_FORMAT("Event.metric_f", WIRE_FLOAT); + proto_tree_add_item(event_tree, hf_riemann_event_metric_f, tvb, offset, 4, ENC_LITTLE_ENDIAN); + len = 4; + break; + default: + len = 0; + UNKNOWN_FIELD_NUMBER_FOR("Event"); + } + offset += len; + size -= len; + } + col_append_str(pinfo->cinfo, COL_INFO, "; "); + VERIFY_SIZE_FOR("Event"); + + return offset - orig_offset; +} + +static guint +riemann_dissect_state(packet_info *pinfo, proto_tree *riemann_tree, + tvbuff_t *tvb, guint offset) +{ + guint orig_offset = offset, len = 0; + guint64 tag, fn; + gint64 size; + guint8 wire; + proto_item *pi; + proto_tree *state_tree; + gboolean need_comma = FALSE; + + size = riemann_get_guint64(tvb, offset, &len); + pi = proto_tree_add_item(riemann_tree, hf_riemann_state, tvb, offset, (gint)(size + len), ENC_NA); + state_tree = proto_item_add_subtree(pi, ett_state); + offset += len; + + while (size > 0) { + const char *comma = need_comma ? ", " : ""; + tag = riemann_get_guint64(tvb, offset, &len); + fn = tag >> 3; + wire = tag & 0x7; + offset += len; + size -= len; + switch (fn) { + case FN_STATE_TIME: + VERIFY_WIRE_FORMAT("State.time", WIRE_INTEGER); + len = riemann_dissect_int64(state_tree, tvb, offset, hf_riemann_state_time); + break; + case FN_STATE_SERVICE: + VERIFY_WIRE_FORMAT("State.service", WIRE_BYTES); + col_append_fstr(pinfo->cinfo, COL_INFO, "%s%s", comma, riemann_get_string(tvb, offset)); + len = riemann_dissect_string(state_tree, tvb, offset, hf_riemann_state_service); + need_comma = TRUE; + break; + case FN_STATE_HOST: + VERIFY_WIRE_FORMAT("State.host", WIRE_BYTES); + col_append_fstr(pinfo->cinfo, COL_INFO, "%s%s", comma, riemann_get_string(tvb, offset)); + len = riemann_dissect_string(state_tree, tvb, offset, hf_riemann_state_host); + need_comma = TRUE; + break; + case FN_STATE_DESCRIPTION: + VERIFY_WIRE_FORMAT("State.description", WIRE_BYTES); + len = riemann_dissect_string(state_tree, tvb, offset, hf_riemann_state_description); + break; + case FN_STATE_TAGS: + VERIFY_WIRE_FORMAT("State.tags", WIRE_BYTES); + len = riemann_dissect_string(state_tree, tvb, offset, hf_riemann_state_tag); + break; + case FN_STATE_TTL: + VERIFY_WIRE_FORMAT("State.ttl", WIRE_FLOAT); + proto_tree_add_item(state_tree, hf_riemann_state_ttl, tvb, offset, 4, ENC_LITTLE_ENDIAN); + len = 4; + break; + case FN_STATE_STATE: + VERIFY_WIRE_FORMAT("State.state", WIRE_BYTES); + len = riemann_dissect_string(state_tree, tvb, offset, hf_riemann_state_state); + break; + case FN_STATE_ONCE: + VERIFY_WIRE_FORMAT("State.once", WIRE_INTEGER); + proto_tree_add_item(state_tree, hf_riemann_state_once, tvb, offset, 1, ENC_NA); + len = 1; + break; + default: + len = 0; + UNKNOWN_FIELD_NUMBER_FOR("State"); + } + offset += len; + size -= len; + } + col_append_str(pinfo->cinfo, COL_INFO, "; "); + VERIFY_SIZE_FOR("State"); + + return offset - orig_offset; +} + +static guint +riemann_dissect_msg(packet_info *pinfo, proto_item *pi, proto_tree *riemann_tree, + tvbuff_t *tvb, guint offset) +{ + guint64 tag, fn; + gint64 size = (gint64)tvb_reported_length(tvb); + guint8 wire; + guint len, orig_offset = offset; + gboolean cinfo_set = FALSE; + + while (size > 0) { + tag = riemann_get_guint64(tvb, offset, &len); + fn = tag >> 3; + wire = tag & 0x7; + offset += len; + size -= len; + + switch (fn) { + case FN_MSG_OK: + VERIFY_WIRE_FORMAT("Msg.ok", WIRE_INTEGER); + proto_tree_add_item(riemann_tree, hf_riemann_msg_ok, tvb, offset, 1, ENC_NA); + len = 1; + break; + case FN_MSG_ERROR: + VERIFY_WIRE_FORMAT("Msg.error", WIRE_BYTES); + len = riemann_dissect_string(riemann_tree, tvb, offset, hf_riemann_msg_error); + break; + case FN_MSG_QUERY: + VERIFY_WIRE_FORMAT("Msg.query", WIRE_BYTES); + if (!cinfo_set) { + col_set_str(pinfo->cinfo, COL_INFO, "Query: "); + cinfo_set = TRUE; + } + len = riemann_dissect_query(pinfo, riemann_tree, tvb, offset); + break; + case FN_MSG_EVENTS: + VERIFY_WIRE_FORMAT("Msg.events", WIRE_BYTES); + if (!cinfo_set) { + col_set_str(pinfo->cinfo, COL_INFO, "Event: "); + cinfo_set = TRUE; + } + len = riemann_dissect_event(pinfo, riemann_tree, tvb, offset); + break; + case FN_MSG_STATES: + VERIFY_WIRE_FORMAT("Msg.states", WIRE_BYTES); + if (!cinfo_set) { + col_set_str(pinfo->cinfo, COL_INFO, "State: "); + cinfo_set = TRUE; + } + len = riemann_dissect_state(pinfo, riemann_tree, tvb, offset); + break; + default: + len = 0; + UNKNOWN_FIELD_NUMBER_FOR("Msg"); + } + offset += len; + size -= len; + } + VERIFY_SIZE_FOR("Msg"); + + return offset - orig_offset; +} + +static gboolean +is_riemann(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree _U_, void *data _U_) +{ + guint32 reported_length = tvb_reported_length(tvb); + guint32 captured_length = tvb_captured_length(tvb); + guint64 tag, field_number, wire_format; + guint len; + + if ((pinfo->destport != udp_port_pref) || + (reported_length < riemann_MIN_LENGTH) || + (captured_length < MAX_NEEDED_FOR_HEURISTICS)) { + return FALSE; + } + tag = riemann_get_guint64(tvb, 0, &len); + field_number = tag >> 3; + wire_format = tag & 0x7; + if ((field_number == FN_MSG_OK && wire_format == WIRE_INTEGER) || + (field_number == FN_MSG_ERROR && wire_format == WIRE_BYTES) || + (field_number == FN_MSG_QUERY && wire_format == WIRE_BYTES) || + (field_number == FN_MSG_EVENTS && wire_format == WIRE_BYTES) || + (field_number == FN_MSG_STATES && wire_format == WIRE_BYTES)) { + return TRUE; + } + return FALSE; +} + +static int +dissect_riemann(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_) +{ + proto_item *pi; + proto_tree *riemann_tree; + + if (!is_riemann(tvb, pinfo, tree, data)) + return 0; + + col_set_str(pinfo->cinfo, COL_PROTOCOL, "riemann"); + col_clear(pinfo->cinfo, COL_INFO); + + pi = proto_tree_add_item(tree, proto_riemann, tvb, 0, -1, ENC_NA); + riemann_tree = proto_item_add_subtree(pi, ett_riemann); + + return riemann_dissect_msg(pinfo, pi, riemann_tree, tvb, 0); +} + +void +proto_register_riemann(void) +{ + module_t *riemann_module; + expert_module_t *riemann_expert_module; + + static hf_register_info hf[] = { + { &hf_riemann_msg_ok, + { "ok", "riemann.msg.ok", + FT_BOOLEAN, BASE_NONE, TFS(&tfs_true_false), 0, + NULL, HFILL } + }, + { &hf_riemann_msg_error, + { "error", "riemann.msg.error", + FT_STRING, BASE_NONE, NULL, 0, NULL, HFILL } + }, + { &hf_riemann_attribute, + { "attribute", "riemann.attribute", + FT_NONE, BASE_NONE, NULL, 0, NULL, HFILL } + }, + { &hf_riemann_attribute_key, + { "key", "riemann.attribute.key", + FT_STRING, BASE_NONE, NULL, 0, NULL, HFILL } + }, + { &hf_riemann_attribute_value, + { "value", "riemann.attribute.value", + FT_STRING, BASE_NONE, NULL, 0, NULL, HFILL } + }, + { &hf_riemann_query, + { "query", "riemann.query", + FT_NONE, BASE_NONE, NULL, 0, NULL, HFILL } + }, + { &hf_riemann_query_string, + { "string", "riemann.query.string", + FT_STRING, BASE_NONE, NULL, 0, NULL, HFILL } + }, + { &hf_riemann_event, + { "event", "riemann.event", + FT_NONE, BASE_NONE, NULL, 0, NULL, HFILL } + }, + { &hf_riemann_event_state, + { "state", "riemann.event.state", + FT_STRING, BASE_NONE, NULL, 0, NULL, HFILL } + }, + { &hf_riemann_event_service, + { "service", "riemann.event.service", + FT_STRING, BASE_NONE, NULL, 0, NULL, HFILL } + }, + { &hf_riemann_event_host, + { "host", "riemann.event.host", + FT_STRING, BASE_NONE, NULL, 0, NULL, HFILL } + }, + { &hf_riemann_event_description, + { "description", "riemann.event.description", + FT_STRING, BASE_NONE, NULL, 0, NULL, HFILL } + }, + { &hf_riemann_event_tag, + { "tag", "riemann.event.tag", + FT_STRING, BASE_NONE, NULL, 0, NULL, HFILL } + }, + { &hf_riemann_event_time, + { "time", "riemann.event.time", + FT_INT64, BASE_DEC, NULL, 0, NULL, HFILL } + }, + { &hf_riemann_event_ttl, + { "ttl", "riemann.event.ttl", + FT_FLOAT, BASE_NONE, NULL, 0, NULL, HFILL } + }, + { &hf_riemann_event_metric_d, + { "metric_d", "riemann.event.metric_d", + FT_DOUBLE, BASE_NONE, NULL, 0, NULL, HFILL } + }, + { &hf_riemann_event_metric_f, + { "metric_f", "riemann.event.metric_f", + FT_FLOAT, BASE_NONE, NULL, 0, NULL, HFILL } + }, + { &hf_riemann_event_metric_sint64, + { "metric_sint64", "riemann.event.metric_sint64", + FT_INT64, BASE_DEC, NULL, 0, NULL, HFILL } + }, + { &hf_riemann_state, + { "state", "riemann.state", + FT_NONE, BASE_NONE, NULL, 0, NULL, HFILL } + }, + { &hf_riemann_state_service, + { "service", "riemann.state.service", + FT_STRING, BASE_NONE, NULL, 0, NULL, HFILL } + }, + { &hf_riemann_state_host, + { "host", "riemann.state.host", + FT_STRING, BASE_NONE, NULL, 0, NULL, HFILL } + }, + { &hf_riemann_state_description, + { "description", "riemann.state.description", + FT_STRING, BASE_NONE, NULL, 0, NULL, HFILL } + }, + { &hf_riemann_state_tag, + { "tag", "riemann.state.tag", + FT_STRING, BASE_NONE, NULL, 0, NULL, HFILL } + }, + { &hf_riemann_state_time, + { "time", "riemann.state.time", + FT_INT64, BASE_DEC, NULL, 0, NULL, HFILL } + }, + { &hf_riemann_state_ttl, + { "ttl", "riemann.state.ttl", + FT_FLOAT, BASE_NONE, NULL, 0, NULL, HFILL } + }, + { &hf_riemann_state_state, + { "state", "riemann.state.state", + FT_STRING, BASE_NONE, NULL, 0, NULL, HFILL } + }, + { &hf_riemann_state_once, + { "once", "riemann.state.once", + FT_BOOLEAN, BASE_DEC, NULL, 0, NULL, HFILL } + } + }; + + static ei_register_info ei[] = { + { &ef_error_unknown_wire_tag, + { "riemann.unknown_wire_tag", PI_MALFORMED, PI_ERROR, + "Invalid wire format for field", EXPFILL }}, + { &ef_error_unknown_field_number, + { "riemann.unknown_field_number", PI_MALFORMED, PI_ERROR, + "Unknown field number", EXPFILL }}, + { &ef_error_insufficient_data, + { "riemann.insufficient_data", PI_MALFORMED, PI_ERROR, + "The message declared to have more data than received", EXPFILL }} + }; + + static gint *ett[] = { + &ett_riemann, + &ett_query, + &ett_event, + &ett_attribute, + &ett_state + }; + + proto_riemann = proto_register_protocol("Riemann", "Riemann", "riemann"); + riemann_expert_module = expert_register_protocol(proto_riemann); + expert_register_field_array(riemann_expert_module, ei, array_length(ei)); + + proto_register_field_array(proto_riemann, hf, array_length(hf)); + proto_register_subtree_array(ett, array_length(ett)); + + riemann_module = prefs_register_protocol(proto_riemann, proto_reg_handoff_riemann); + + prefs_register_uint_preference(riemann_module, "udp.port", "Riemann UDP Port", + " riemann UDP port if other than the default", + 10, &udp_port_pref); +} + +void +proto_reg_handoff_riemann(void) +{ + static gboolean initialized = FALSE; + static dissector_handle_t riemann_handle; + static int current_port; + + if (!initialized) { + riemann_handle = new_create_dissector_handle(dissect_riemann, proto_riemann); + initialized = TRUE; + } else { + dissector_delete_uint("udp.port", current_port, riemann_handle); + } + current_port = udp_port_pref; + dissector_add_uint("udp.port", current_port, riemann_handle); +} + +/* + * Editor modelines - https://www.wireshark.org/tools/modelines.html + * + * Local variables: + * c-basic-offset: 4 + * tab-width: 8 + * indent-tabs-mode: nil + * End: + * + * vi: set shiftwidth=4 tabstop=8 expandtab: + * :indentSize=4:tabSize=8:noTabs=true: + */ |