/src/wireshark/epan/dissectors/packet-riemann.c
Line | Count | Source |
1 | | /** |
2 | | * packet-riemann.c |
3 | | * Routines for Riemann dissection |
4 | | * Copyright 2014, Sergey Avseyev <sergey.avseyev@gmail.com> |
5 | | * |
6 | | * Wireshark - Network traffic analyzer |
7 | | * By Gerald Combs <gerald@wireshark.org> |
8 | | * Copyright 1998 Gerald Combs |
9 | | * |
10 | | * SPDX-License-Identifier: GPL-2.0-or-later |
11 | | */ |
12 | | |
13 | | /* Riemann (http://riemann.io) aggregates events from servers and |
14 | | * applications with a powerful stream processing language. |
15 | | * |
16 | | * Protobuf structures layout: |
17 | | * https://github.com/riemann/riemann-java-client/blob/master/riemann-java-client/src/main/proto/riemann/proto.proto |
18 | | * |
19 | | * message State { |
20 | | * optional int64 time = 1; |
21 | | * optional string state = 2; |
22 | | * optional string service = 3; |
23 | | * optional string host = 4; |
24 | | * optional string description = 5; |
25 | | * optional bool once = 6; |
26 | | * repeated string tags = 7; |
27 | | * optional float ttl = 8; |
28 | | * } |
29 | | * |
30 | | * message Event { |
31 | | * optional int64 time = 1; |
32 | | * optional string state = 2; |
33 | | * optional string service = 3; |
34 | | * optional string host = 4; |
35 | | * optional string description = 5; |
36 | | * repeated string tags = 7; |
37 | | * optional float ttl = 8; |
38 | | * repeated Attribute attributes = 9; |
39 | | * |
40 | | * optional int64 time_micros = 10; |
41 | | * optional sint64 metric_sint64 = 13; |
42 | | * optional double metric_d = 14; |
43 | | * optional float metric_f = 15; |
44 | | * } |
45 | | * |
46 | | * message Query { |
47 | | * optional string string = 1; |
48 | | * } |
49 | | * |
50 | | * message Msg { |
51 | | * optional bool ok = 2; |
52 | | * optional string error = 3; |
53 | | * repeated State states = 4; |
54 | | * optional Query query = 5; |
55 | | * repeated Event events = 6; |
56 | | * } |
57 | | * |
58 | | * message Attribute { |
59 | | * required string key = 1; |
60 | | * optional string value = 2; |
61 | | * } |
62 | | */ |
63 | | |
64 | | #include "config.h" |
65 | | |
66 | | #include <epan/packet.h> |
67 | | #include <epan/expert.h> |
68 | | #include "packet-tcp.h" |
69 | | |
70 | | void proto_reg_handoff_riemann(void); |
71 | | void proto_register_riemann(void); |
72 | | |
73 | | static dissector_handle_t riemann_udp_handle, riemann_tcp_handle; |
74 | | |
75 | | static int proto_riemann; |
76 | | static int hf_riemann_msg_ok; |
77 | | static int hf_riemann_msg_error; |
78 | | static int hf_riemann_attribute; |
79 | | static int hf_riemann_attribute_key; |
80 | | static int hf_riemann_attribute_value; |
81 | | static int hf_riemann_query; |
82 | | static int hf_riemann_query_string; |
83 | | static int hf_riemann_event; |
84 | | static int hf_riemann_event_state; |
85 | | static int hf_riemann_event_service; |
86 | | static int hf_riemann_event_host; |
87 | | static int hf_riemann_event_description; |
88 | | static int hf_riemann_event_tag; |
89 | | static int hf_riemann_event_ttl; |
90 | | static int hf_riemann_event_time; |
91 | | static int hf_riemann_event_metric_d; |
92 | | static int hf_riemann_event_metric_f; |
93 | | static int hf_riemann_event_time_micros; |
94 | | static int hf_riemann_event_metric_sint64; |
95 | | static int hf_riemann_state; |
96 | | static int hf_riemann_state_service; |
97 | | static int hf_riemann_state_host; |
98 | | static int hf_riemann_state_description; |
99 | | static int hf_riemann_state_tag; |
100 | | static int hf_riemann_state_ttl; |
101 | | static int hf_riemann_state_time; |
102 | | static int hf_riemann_state_state; |
103 | | static int hf_riemann_state_once; |
104 | | |
105 | | static int ett_riemann; |
106 | | static int ett_query; |
107 | | static int ett_event; |
108 | | static int ett_attribute; |
109 | | static int ett_state; |
110 | | |
111 | 0 | #define RIEMANN_MIN_LENGTH 16 |
112 | 0 | #define RIEMANN_MIN_NEEDED_FOR_HEURISTICS 10 |
113 | | |
114 | | /* field numbers. see protocol definition above */ |
115 | 0 | #define RIEMANN_FN_MSG_OK 2 |
116 | 0 | #define RIEMANN_FN_MSG_ERROR 3 |
117 | 0 | #define RIEMANN_FN_MSG_STATES 4 |
118 | 0 | #define RIEMANN_FN_MSG_QUERY 5 |
119 | 0 | #define RIEMANN_FN_MSG_EVENTS 6 |
120 | | |
121 | 0 | #define RIEMANN_FN_EVENT_TIME 1 |
122 | 0 | #define RIEMANN_FN_EVENT_STATE 2 |
123 | 0 | #define RIEMANN_FN_EVENT_SERVICE 3 |
124 | 0 | #define RIEMANN_FN_EVENT_HOST 4 |
125 | 0 | #define RIEMANN_FN_EVENT_DESCRIPTION 5 |
126 | 0 | #define RIEMANN_FN_EVENT_TAGS 7 |
127 | 0 | #define RIEMANN_FN_EVENT_TTL 8 |
128 | 0 | #define RIEMANN_FN_EVENT_ATTRIBUTES 9 |
129 | 0 | #define RIEMANN_FN_EVENT_TIME_MICROS 10 |
130 | 0 | #define RIEMANN_FN_EVENT_METRIC_SINT64 13 |
131 | 0 | #define RIEMANN_FN_EVENT_METRIC_D 14 |
132 | 0 | #define RIEMANN_FN_EVENT_METRIC_F 15 |
133 | | |
134 | 0 | #define RIEMANN_FN_ATTRIBUTE_KEY 1 |
135 | 0 | #define RIEMANN_FN_ATTRIBUTE_VALUE 2 |
136 | | |
137 | 0 | #define RIEMANN_FN_STATE_TIME 1 |
138 | 0 | #define RIEMANN_FN_STATE_STATE 2 |
139 | 0 | #define RIEMANN_FN_STATE_SERVICE 3 |
140 | 0 | #define RIEMANN_FN_STATE_HOST 4 |
141 | 0 | #define RIEMANN_FN_STATE_DESCRIPTION 5 |
142 | 0 | #define RIEMANN_FN_STATE_ONCE 6 |
143 | 0 | #define RIEMANN_FN_STATE_TAGS 7 |
144 | 0 | #define RIEMANN_FN_STATE_TTL 8 |
145 | | |
146 | 0 | #define RIEMANN_FN_QUERY_STRING 1 |
147 | | |
148 | | /* type codes. see protocol definition above */ |
149 | 0 | #define RIEMANN_WIRE_INTEGER 0 |
150 | 0 | #define RIEMANN_WIRE_DOUBLE 1 |
151 | 0 | #define RIEMANN_WIRE_BYTES 2 |
152 | 0 | #define RIEMANN_WIRE_FLOAT 5 |
153 | | |
154 | | static expert_field ei_error_unknown_wire_tag; |
155 | | static expert_field ei_error_unknown_field_number; |
156 | | static expert_field ei_error_insufficient_data; |
157 | | |
158 | | static void |
159 | | riemann_verify_wire_format(uint64_t field_number, const char *field_name, int expected, int actual, |
160 | | packet_info *pinfo, proto_item *pi) |
161 | 0 | { |
162 | 0 | if (expected != actual) { |
163 | 0 | const char *wire_name; |
164 | |
|
165 | 0 | switch (expected) { |
166 | 0 | case RIEMANN_WIRE_INTEGER: |
167 | 0 | wire_name = "integer"; |
168 | 0 | break; |
169 | 0 | case RIEMANN_WIRE_BYTES: |
170 | 0 | wire_name = "bytes/string"; |
171 | 0 | break; |
172 | 0 | case RIEMANN_WIRE_FLOAT: |
173 | 0 | wire_name = "float"; |
174 | 0 | break; |
175 | 0 | case RIEMANN_WIRE_DOUBLE: |
176 | 0 | wire_name = "double"; |
177 | 0 | break; |
178 | 0 | default: |
179 | 0 | wire_name = "unknown (check packet-riemann.c)"; |
180 | 0 | break; |
181 | 0 | } |
182 | 0 | expert_add_info_format(pinfo, pi, &ei_error_unknown_wire_tag, |
183 | 0 | "Expected %s (%d) field to be an %s (%d), but it is %d", |
184 | 0 | field_name, (int)field_number, wire_name, expected, actual); |
185 | 0 | } |
186 | 0 | } |
187 | | |
188 | | #define VERIFY_WIRE_FORMAT(field_name, expected) \ |
189 | 0 | riemann_verify_wire_format(fn, field_name, expected, wire, pinfo, pi) |
190 | | |
191 | | #define UNKNOWN_FIELD_NUMBER_FOR(message_name) \ |
192 | 0 | expert_add_info_format(pinfo, pi, &ei_error_unknown_field_number, \ |
193 | 0 | "Unknown field number %d for " message_name " (wire format %d)", \ |
194 | 0 | (int)fn, (int)wire); |
195 | | |
196 | | #define VERIFY_SIZE_FOR(message_name) \ |
197 | 0 | if (size < 0) { \ |
198 | 0 | expert_add_info_format(pinfo, pi, &ei_error_insufficient_data, \ |
199 | 0 | "Insufficient data for " message_name " (%d bytes needed)", \ |
200 | 0 | (int)size * -1); \ |
201 | 0 | } |
202 | | |
203 | | static uint64_t |
204 | | riemann_get_uint64(tvbuff_t *tvb, unsigned offset, unsigned *len) |
205 | 0 | { |
206 | 0 | uint64_t num = 0; |
207 | |
|
208 | 0 | *len = tvb_get_varint(tvb, offset, FT_VARINT_MAX_LEN, &num, ENC_VARINT_PROTOBUF); |
209 | 0 | if (*len == 0) { |
210 | 0 | *len = FT_VARINT_MAX_LEN; |
211 | 0 | num = 0; |
212 | | // XXX - Add some failure expert info |
213 | 0 | } |
214 | 0 | return num; |
215 | 0 | } |
216 | | |
217 | | static char * |
218 | | riemann_get_string(wmem_allocator_t *scope, tvbuff_t *tvb, int offset) |
219 | 0 | { |
220 | 0 | uint64_t size; |
221 | 0 | unsigned len = 0; |
222 | |
|
223 | 0 | size = riemann_get_uint64(tvb, offset, &len); |
224 | 0 | offset += len; |
225 | 0 | if (size > (uint64_t)tvb_reported_length_remaining(tvb, offset)) |
226 | 0 | return wmem_strdup(scope, ""); |
227 | 0 | return (char*)tvb_get_string_enc(scope, tvb, offset, (int)size, ENC_ASCII); |
228 | 0 | } |
229 | | |
230 | | static unsigned |
231 | | riemann_dissect_int64(proto_tree *riemann_tree, tvbuff_t *tvb, unsigned offset, int hf_index) |
232 | 0 | { |
233 | 0 | uint64_t num; |
234 | 0 | unsigned len = 0; |
235 | |
|
236 | 0 | num = riemann_get_uint64(tvb, offset, &len); |
237 | 0 | proto_tree_add_int64(riemann_tree, hf_index, tvb, offset, len, num); |
238 | 0 | return len; |
239 | 0 | } |
240 | | |
241 | | static unsigned |
242 | | riemann_dissect_sint64(proto_tree *riemann_tree, tvbuff_t *tvb, unsigned offset, int hf_index) |
243 | 0 | { |
244 | 0 | int64_t snum; |
245 | 0 | unsigned len = 0; |
246 | |
|
247 | 0 | len = tvb_get_varint(tvb, offset, FT_VARINT_MAX_LEN, (uint64_t*)&snum, ENC_VARINT_ZIGZAG); |
248 | 0 | if (!len) { |
249 | 0 | len = FT_VARINT_MAX_LEN; |
250 | 0 | snum = 0; |
251 | | // XXX - Add some failure expert info |
252 | 0 | } |
253 | |
|
254 | 0 | proto_tree_add_int64(riemann_tree, hf_index, tvb, offset, len, snum); |
255 | 0 | return len; |
256 | 0 | } |
257 | | |
258 | | static unsigned |
259 | | riemann_dissect_string(packet_info *pinfo, proto_tree *riemann_tree, tvbuff_t *tvb, unsigned offset, int hf_index) |
260 | 0 | { |
261 | 0 | uint64_t size; |
262 | 0 | unsigned len = 0, orig_offset = offset; |
263 | 0 | int remaining; |
264 | |
|
265 | 0 | size = riemann_get_uint64(tvb, offset, &len); |
266 | 0 | offset += len; |
267 | 0 | remaining = tvb_reported_length_remaining(tvb, offset); |
268 | 0 | if (remaining < 0 || size > (uint64_t)remaining) { |
269 | | /* String longer than the data: report it and consume the rest */ |
270 | 0 | proto_tree_add_expert_format_remaining(riemann_tree, pinfo, &ei_error_insufficient_data, |
271 | 0 | tvb, offset, "String size %" PRIu64 " exceeds remaining data", size); |
272 | 0 | return tvb_reported_length(tvb) - orig_offset; |
273 | 0 | } |
274 | 0 | proto_tree_add_item(riemann_tree, hf_index, tvb, offset, (int)size, ENC_ASCII); |
275 | 0 | offset += (unsigned)size; |
276 | |
|
277 | 0 | return offset - orig_offset; |
278 | 0 | } |
279 | | |
280 | | static unsigned |
281 | | riemann_dissect_attribute(packet_info *pinfo, proto_tree *riemann_tree, |
282 | | tvbuff_t *tvb, unsigned offset) |
283 | 0 | { |
284 | 0 | uint64_t tag, fn; |
285 | 0 | int64_t size; |
286 | 0 | uint8_t wire; |
287 | 0 | unsigned len = 0; |
288 | 0 | unsigned orig_offset = offset; |
289 | 0 | proto_item *pi; |
290 | 0 | proto_tree *attribute_tree; |
291 | |
|
292 | 0 | size = (int64_t)riemann_get_uint64(tvb, offset, &len); |
293 | 0 | pi = proto_tree_add_item(riemann_tree, hf_riemann_attribute, tvb, (int)offset, (int)(size + len), ENC_NA); |
294 | 0 | attribute_tree = proto_item_add_subtree(pi, ett_attribute); |
295 | 0 | offset += len; |
296 | |
|
297 | 0 | while (size > 0) { |
298 | 0 | tag = riemann_get_uint64(tvb, offset, &len); |
299 | 0 | fn = tag >> 3; |
300 | 0 | wire = tag & 0x7; |
301 | 0 | offset += len; |
302 | 0 | size -= len; |
303 | 0 | switch (fn) { |
304 | 0 | case RIEMANN_FN_ATTRIBUTE_KEY: |
305 | 0 | VERIFY_WIRE_FORMAT("Attribute.key", RIEMANN_WIRE_BYTES); |
306 | 0 | len = riemann_dissect_string(pinfo, attribute_tree, tvb, offset, hf_riemann_attribute_key); |
307 | 0 | break; |
308 | 0 | case RIEMANN_FN_ATTRIBUTE_VALUE: |
309 | 0 | VERIFY_WIRE_FORMAT("Attribute.value", RIEMANN_WIRE_BYTES); |
310 | 0 | len = riemann_dissect_string(pinfo, attribute_tree, tvb, offset, hf_riemann_attribute_value); |
311 | 0 | break; |
312 | 0 | default: |
313 | 0 | len = 0; |
314 | 0 | UNKNOWN_FIELD_NUMBER_FOR("Attribute"); |
315 | 0 | } |
316 | 0 | offset += len; |
317 | 0 | size -= len; |
318 | 0 | } |
319 | 0 | VERIFY_SIZE_FOR("Attribute"); |
320 | |
|
321 | 0 | return offset - orig_offset; |
322 | 0 | } |
323 | | |
324 | | static unsigned |
325 | | riemann_dissect_query(packet_info *pinfo, proto_tree *riemann_tree, |
326 | | tvbuff_t *tvb, unsigned offset) |
327 | 0 | { |
328 | 0 | uint64_t tag, fn; |
329 | 0 | int64_t size; |
330 | 0 | uint8_t wire; |
331 | 0 | unsigned orig_offset = offset, len = 0; |
332 | 0 | proto_item *pi; |
333 | 0 | proto_tree *query_tree; |
334 | |
|
335 | 0 | size = (int64_t)riemann_get_uint64(tvb, offset, &len); |
336 | 0 | pi = proto_tree_add_item(riemann_tree, hf_riemann_query, tvb, (int)offset, (int)(size + len), ENC_NA); |
337 | 0 | query_tree = proto_item_add_subtree(pi, ett_query); |
338 | 0 | offset += len; |
339 | |
|
340 | 0 | while (size > 0) { |
341 | 0 | tag = riemann_get_uint64(tvb, offset, &len); |
342 | 0 | fn = tag >> 3; |
343 | 0 | wire = tag & 0x7; |
344 | 0 | offset += len; |
345 | 0 | size -= len; |
346 | 0 | switch (fn) { |
347 | 0 | case RIEMANN_FN_QUERY_STRING: |
348 | 0 | VERIFY_WIRE_FORMAT("Query.string", RIEMANN_WIRE_BYTES); |
349 | 0 | col_append_str(pinfo->cinfo, COL_INFO, riemann_get_string(pinfo->pool, tvb, offset)); |
350 | 0 | len = riemann_dissect_string(pinfo, query_tree, tvb, offset, hf_riemann_query_string); |
351 | 0 | break; |
352 | 0 | default: |
353 | 0 | len = 0; |
354 | 0 | UNKNOWN_FIELD_NUMBER_FOR("Query"); |
355 | 0 | } |
356 | 0 | offset += len; |
357 | 0 | size -= len; |
358 | 0 | } |
359 | 0 | VERIFY_SIZE_FOR("Query"); |
360 | |
|
361 | 0 | return offset - orig_offset; |
362 | 0 | } |
363 | | |
364 | | static unsigned |
365 | | riemann_dissect_event(packet_info *pinfo, proto_tree *riemann_tree, |
366 | | tvbuff_t *tvb, unsigned offset) |
367 | 0 | { |
368 | 0 | unsigned orig_offset = offset, len = 0; |
369 | 0 | uint64_t tag, fn; |
370 | 0 | int64_t size; |
371 | 0 | uint8_t wire; |
372 | 0 | proto_item *pi; |
373 | 0 | proto_tree *event_tree; |
374 | 0 | bool need_comma = false; |
375 | |
|
376 | 0 | size = riemann_get_uint64(tvb, offset, &len); |
377 | 0 | pi = proto_tree_add_item(riemann_tree, hf_riemann_event, tvb, (int)offset, (int)(size + len), ENC_NA); |
378 | 0 | event_tree = proto_item_add_subtree(pi, ett_event); |
379 | 0 | offset += len; |
380 | |
|
381 | 0 | while (size > 0) { |
382 | 0 | const char *comma = need_comma ? ", " : ""; |
383 | 0 | tag = riemann_get_uint64(tvb, offset, &len); |
384 | 0 | fn = tag >> 3; |
385 | 0 | wire = tag & 0x7; |
386 | 0 | offset += len; |
387 | 0 | size -= len; |
388 | 0 | switch (fn) { |
389 | 0 | case RIEMANN_FN_EVENT_TIME: |
390 | 0 | VERIFY_WIRE_FORMAT("Event.time", RIEMANN_WIRE_INTEGER); |
391 | 0 | len = riemann_dissect_int64(event_tree, tvb, offset, hf_riemann_event_time); |
392 | 0 | break; |
393 | 0 | case RIEMANN_FN_EVENT_STATE: |
394 | 0 | VERIFY_WIRE_FORMAT("Event.state", RIEMANN_WIRE_BYTES); |
395 | 0 | len = riemann_dissect_string(pinfo, event_tree, tvb, offset, hf_riemann_event_state); |
396 | 0 | break; |
397 | 0 | case RIEMANN_FN_EVENT_SERVICE: |
398 | 0 | VERIFY_WIRE_FORMAT("Event.service", RIEMANN_WIRE_BYTES); |
399 | 0 | col_append_fstr(pinfo->cinfo, COL_INFO, "%s%s", comma, riemann_get_string(pinfo->pool, tvb, offset)); |
400 | 0 | len = riemann_dissect_string(pinfo, event_tree, tvb, offset, hf_riemann_event_service); |
401 | 0 | need_comma = true; |
402 | 0 | break; |
403 | 0 | case RIEMANN_FN_EVENT_HOST: |
404 | 0 | VERIFY_WIRE_FORMAT("Event.host", RIEMANN_WIRE_BYTES); |
405 | 0 | col_append_fstr(pinfo->cinfo, COL_INFO, "%s%s", comma, riemann_get_string(pinfo->pool, tvb, offset)); |
406 | 0 | len = riemann_dissect_string(pinfo, event_tree, tvb, offset, hf_riemann_event_host); |
407 | 0 | need_comma = true; |
408 | 0 | break; |
409 | 0 | case RIEMANN_FN_EVENT_DESCRIPTION: |
410 | 0 | VERIFY_WIRE_FORMAT("Event.description", RIEMANN_WIRE_BYTES); |
411 | 0 | len = riemann_dissect_string(pinfo, event_tree, tvb, offset, hf_riemann_event_description); |
412 | 0 | break; |
413 | 0 | case RIEMANN_FN_EVENT_TAGS: |
414 | 0 | VERIFY_WIRE_FORMAT("Event.tags", RIEMANN_WIRE_BYTES); |
415 | 0 | len = riemann_dissect_string(pinfo, event_tree, tvb, offset, hf_riemann_event_tag); |
416 | 0 | break; |
417 | 0 | case RIEMANN_FN_EVENT_TTL: |
418 | 0 | VERIFY_WIRE_FORMAT("Event.ttl", RIEMANN_WIRE_FLOAT); |
419 | 0 | proto_tree_add_item(event_tree, hf_riemann_event_ttl, tvb, offset, 4, ENC_LITTLE_ENDIAN); |
420 | 0 | len = 4; |
421 | 0 | break; |
422 | 0 | case RIEMANN_FN_EVENT_ATTRIBUTES: |
423 | 0 | VERIFY_WIRE_FORMAT("Event.attributes", RIEMANN_WIRE_BYTES); |
424 | 0 | len = riemann_dissect_attribute(pinfo, event_tree, tvb, offset); |
425 | 0 | break; |
426 | 0 | case RIEMANN_FN_EVENT_TIME_MICROS: |
427 | 0 | VERIFY_WIRE_FORMAT("Event.time_micros", RIEMANN_WIRE_INTEGER); |
428 | 0 | len = riemann_dissect_int64(event_tree, tvb, offset, hf_riemann_event_time_micros); |
429 | 0 | break; |
430 | 0 | case RIEMANN_FN_EVENT_METRIC_SINT64: |
431 | 0 | VERIFY_WIRE_FORMAT("Event.metric_sint64", RIEMANN_WIRE_INTEGER); |
432 | 0 | len = riemann_dissect_sint64(event_tree, tvb, offset, hf_riemann_event_metric_sint64); |
433 | 0 | break; |
434 | 0 | case RIEMANN_FN_EVENT_METRIC_D: |
435 | 0 | VERIFY_WIRE_FORMAT("Event.metric_d", RIEMANN_WIRE_DOUBLE); |
436 | 0 | proto_tree_add_item(event_tree, hf_riemann_event_metric_d, tvb, offset, 8, ENC_LITTLE_ENDIAN); |
437 | 0 | len = 8; |
438 | 0 | break; |
439 | 0 | case RIEMANN_FN_EVENT_METRIC_F: |
440 | 0 | VERIFY_WIRE_FORMAT("Event.metric_f", RIEMANN_WIRE_FLOAT); |
441 | 0 | proto_tree_add_item(event_tree, hf_riemann_event_metric_f, tvb, offset, 4, ENC_LITTLE_ENDIAN); |
442 | 0 | len = 4; |
443 | 0 | break; |
444 | 0 | default: |
445 | 0 | len = 0; |
446 | 0 | UNKNOWN_FIELD_NUMBER_FOR("Event"); |
447 | 0 | } |
448 | 0 | offset += len; |
449 | 0 | size -= len; |
450 | 0 | } |
451 | 0 | col_append_str(pinfo->cinfo, COL_INFO, "; "); |
452 | 0 | VERIFY_SIZE_FOR("Event"); |
453 | |
|
454 | 0 | return offset - orig_offset; |
455 | 0 | } |
456 | | |
457 | | static unsigned |
458 | | riemann_dissect_state(packet_info *pinfo, proto_tree *riemann_tree, |
459 | | tvbuff_t *tvb, unsigned offset) |
460 | 0 | { |
461 | 0 | unsigned orig_offset = offset, len = 0; |
462 | 0 | uint64_t tag, fn; |
463 | 0 | int64_t size; |
464 | 0 | uint8_t wire; |
465 | 0 | proto_item *pi; |
466 | 0 | proto_tree *state_tree; |
467 | 0 | bool need_comma = false; |
468 | |
|
469 | 0 | size = riemann_get_uint64(tvb, offset, &len); |
470 | 0 | pi = proto_tree_add_item(riemann_tree, hf_riemann_state, tvb, offset, (int)(size + len), ENC_NA); |
471 | 0 | state_tree = proto_item_add_subtree(pi, ett_state); |
472 | 0 | offset += len; |
473 | |
|
474 | 0 | while (size > 0) { |
475 | 0 | const char *comma = need_comma ? ", " : ""; |
476 | 0 | tag = riemann_get_uint64(tvb, offset, &len); |
477 | 0 | fn = tag >> 3; |
478 | 0 | wire = tag & 0x7; |
479 | 0 | offset += len; |
480 | 0 | size -= len; |
481 | 0 | switch (fn) { |
482 | 0 | case RIEMANN_FN_STATE_TIME: |
483 | 0 | VERIFY_WIRE_FORMAT("State.time", RIEMANN_WIRE_INTEGER); |
484 | 0 | len = riemann_dissect_int64(state_tree, tvb, offset, hf_riemann_state_time); |
485 | 0 | break; |
486 | 0 | case RIEMANN_FN_STATE_SERVICE: |
487 | 0 | VERIFY_WIRE_FORMAT("State.service", RIEMANN_WIRE_BYTES); |
488 | 0 | col_append_fstr(pinfo->cinfo, COL_INFO, "%s%s", comma, riemann_get_string(pinfo->pool, tvb, offset)); |
489 | 0 | len = riemann_dissect_string(pinfo, state_tree, tvb, offset, hf_riemann_state_service); |
490 | 0 | need_comma = true; |
491 | 0 | break; |
492 | 0 | case RIEMANN_FN_STATE_HOST: |
493 | 0 | VERIFY_WIRE_FORMAT("State.host", RIEMANN_WIRE_BYTES); |
494 | 0 | col_append_fstr(pinfo->cinfo, COL_INFO, "%s%s", comma, riemann_get_string(pinfo->pool, tvb, offset)); |
495 | 0 | len = riemann_dissect_string(pinfo, state_tree, tvb, offset, hf_riemann_state_host); |
496 | 0 | need_comma = true; |
497 | 0 | break; |
498 | 0 | case RIEMANN_FN_STATE_DESCRIPTION: |
499 | 0 | VERIFY_WIRE_FORMAT("State.description", RIEMANN_WIRE_BYTES); |
500 | 0 | len = riemann_dissect_string(pinfo, state_tree, tvb, offset, hf_riemann_state_description); |
501 | 0 | break; |
502 | 0 | case RIEMANN_FN_STATE_TAGS: |
503 | 0 | VERIFY_WIRE_FORMAT("State.tags", RIEMANN_WIRE_BYTES); |
504 | 0 | len = riemann_dissect_string(pinfo, state_tree, tvb, offset, hf_riemann_state_tag); |
505 | 0 | break; |
506 | 0 | case RIEMANN_FN_STATE_TTL: |
507 | 0 | VERIFY_WIRE_FORMAT("State.ttl", RIEMANN_WIRE_FLOAT); |
508 | 0 | proto_tree_add_item(state_tree, hf_riemann_state_ttl, tvb, offset, 4, ENC_LITTLE_ENDIAN); |
509 | 0 | len = 4; |
510 | 0 | break; |
511 | 0 | case RIEMANN_FN_STATE_STATE: |
512 | 0 | VERIFY_WIRE_FORMAT("State.state", RIEMANN_WIRE_BYTES); |
513 | 0 | len = riemann_dissect_string(pinfo, state_tree, tvb, offset, hf_riemann_state_state); |
514 | 0 | break; |
515 | 0 | case RIEMANN_FN_STATE_ONCE: |
516 | 0 | VERIFY_WIRE_FORMAT("State.once", RIEMANN_WIRE_INTEGER); |
517 | 0 | proto_tree_add_item(state_tree, hf_riemann_state_once, tvb, offset, 1, ENC_NA); |
518 | 0 | len = 1; |
519 | 0 | break; |
520 | 0 | default: |
521 | 0 | len = 0; |
522 | 0 | UNKNOWN_FIELD_NUMBER_FOR("State"); |
523 | 0 | } |
524 | 0 | offset += len; |
525 | 0 | size -= len; |
526 | 0 | } |
527 | 0 | col_append_str(pinfo->cinfo, COL_INFO, "; "); |
528 | 0 | VERIFY_SIZE_FOR("State"); |
529 | |
|
530 | 0 | return offset - orig_offset; |
531 | 0 | } |
532 | | |
533 | | static unsigned |
534 | | riemann_dissect_msg(packet_info *pinfo, proto_item *pi, proto_tree *riemann_tree, |
535 | | tvbuff_t *tvb, unsigned offset) |
536 | 0 | { |
537 | 0 | uint64_t tag, fn; |
538 | 0 | int64_t size = (int64_t)tvb_reported_length_remaining(tvb, offset); |
539 | 0 | uint8_t wire; |
540 | 0 | unsigned len, orig_offset = offset; |
541 | 0 | bool cinfo_set = false; |
542 | |
|
543 | 0 | while (size > 0) { |
544 | 0 | tag = riemann_get_uint64(tvb, offset, &len); |
545 | 0 | fn = tag >> 3; |
546 | 0 | wire = tag & 0x7; |
547 | 0 | offset += len; |
548 | 0 | size -= len; |
549 | |
|
550 | 0 | switch (fn) { |
551 | 0 | case RIEMANN_FN_MSG_OK: |
552 | 0 | VERIFY_WIRE_FORMAT("Msg.ok", RIEMANN_WIRE_INTEGER); |
553 | 0 | proto_tree_add_item(riemann_tree, hf_riemann_msg_ok, tvb, offset, 1, ENC_NA); |
554 | 0 | len = 1; |
555 | 0 | break; |
556 | 0 | case RIEMANN_FN_MSG_ERROR: |
557 | 0 | VERIFY_WIRE_FORMAT("Msg.error", RIEMANN_WIRE_BYTES); |
558 | 0 | len = riemann_dissect_string(pinfo, riemann_tree, tvb, offset, hf_riemann_msg_error); |
559 | 0 | break; |
560 | 0 | case RIEMANN_FN_MSG_QUERY: |
561 | 0 | VERIFY_WIRE_FORMAT("Msg.query", RIEMANN_WIRE_BYTES); |
562 | 0 | if (!cinfo_set) { |
563 | 0 | col_set_str(pinfo->cinfo, COL_INFO, "Query: "); |
564 | 0 | cinfo_set = true; |
565 | 0 | } |
566 | 0 | len = riemann_dissect_query(pinfo, riemann_tree, tvb, offset); |
567 | 0 | break; |
568 | 0 | case RIEMANN_FN_MSG_EVENTS: |
569 | 0 | VERIFY_WIRE_FORMAT("Msg.events", RIEMANN_WIRE_BYTES); |
570 | 0 | if (!cinfo_set) { |
571 | 0 | col_set_str(pinfo->cinfo, COL_INFO, "Event: "); |
572 | 0 | cinfo_set = true; |
573 | 0 | } |
574 | 0 | len = riemann_dissect_event(pinfo, riemann_tree, tvb, offset); |
575 | 0 | break; |
576 | 0 | case RIEMANN_FN_MSG_STATES: |
577 | 0 | VERIFY_WIRE_FORMAT("Msg.states", RIEMANN_WIRE_BYTES); |
578 | 0 | if (!cinfo_set) { |
579 | 0 | col_set_str(pinfo->cinfo, COL_INFO, "State: "); |
580 | 0 | cinfo_set = true; |
581 | 0 | } |
582 | 0 | len = riemann_dissect_state(pinfo, riemann_tree, tvb, offset); |
583 | 0 | break; |
584 | 0 | default: |
585 | 0 | len = 0; |
586 | 0 | UNKNOWN_FIELD_NUMBER_FOR("Msg"); |
587 | 0 | } |
588 | 0 | offset += len; |
589 | 0 | size -= len; |
590 | 0 | } |
591 | 0 | VERIFY_SIZE_FOR("Msg"); |
592 | |
|
593 | 0 | return offset - orig_offset; |
594 | 0 | } |
595 | | |
596 | | static bool |
597 | | is_riemann(tvbuff_t *tvb, unsigned offset) |
598 | 0 | { |
599 | 0 | uint32_t reported_length = tvb_reported_length_remaining(tvb, offset); |
600 | 0 | uint32_t captured_length = tvb_captured_length_remaining(tvb, offset); |
601 | 0 | uint64_t tag, field_number, wire_format; |
602 | 0 | unsigned len; |
603 | |
|
604 | 0 | if ((reported_length < RIEMANN_MIN_LENGTH) || |
605 | 0 | (captured_length < RIEMANN_MIN_NEEDED_FOR_HEURISTICS)) { |
606 | 0 | return false; |
607 | 0 | } |
608 | 0 | tag = riemann_get_uint64(tvb, offset, &len); |
609 | 0 | field_number = tag >> 3; |
610 | 0 | wire_format = tag & 0x7; |
611 | 0 | if ((field_number == RIEMANN_FN_MSG_OK && wire_format == RIEMANN_WIRE_INTEGER) || |
612 | 0 | (field_number == RIEMANN_FN_MSG_ERROR && wire_format == RIEMANN_WIRE_BYTES) || |
613 | 0 | (field_number == RIEMANN_FN_MSG_QUERY && wire_format == RIEMANN_WIRE_BYTES) || |
614 | 0 | (field_number == RIEMANN_FN_MSG_EVENTS && wire_format == RIEMANN_WIRE_BYTES) || |
615 | 0 | (field_number == RIEMANN_FN_MSG_STATES && wire_format == RIEMANN_WIRE_BYTES)) { |
616 | 0 | return true; |
617 | 0 | } |
618 | 0 | return false; |
619 | 0 | } |
620 | | |
621 | | static int |
622 | | dissect_riemann(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, unsigned offset) |
623 | 0 | { |
624 | 0 | proto_item *pi; |
625 | 0 | proto_tree *riemann_tree; |
626 | |
|
627 | 0 | if (!is_riemann(tvb, offset)) |
628 | 0 | return 0; |
629 | | |
630 | 0 | col_set_str(pinfo->cinfo, COL_PROTOCOL, "riemann"); |
631 | 0 | col_clear(pinfo->cinfo, COL_INFO); |
632 | |
|
633 | 0 | pi = proto_tree_add_item(tree, proto_riemann, tvb, offset, -1, ENC_NA); |
634 | 0 | riemann_tree = proto_item_add_subtree(pi, ett_riemann); |
635 | |
|
636 | 0 | return riemann_dissect_msg(pinfo, pi, riemann_tree, tvb, offset); |
637 | 0 | } |
638 | | |
639 | | static int |
640 | | dissect_riemann_udp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_) |
641 | 0 | { |
642 | 0 | return dissect_riemann(tvb, pinfo, tree, 0); |
643 | 0 | } |
644 | | |
645 | | static int |
646 | | dissect_riemann_tcp_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_) |
647 | 0 | { |
648 | 0 | return dissect_riemann(tvb, pinfo, tree, 4); |
649 | 0 | } |
650 | | |
651 | | static unsigned |
652 | | get_riemann_tcp_pdu_len(packet_info *pinfo _U_, tvbuff_t *tvb, |
653 | | int offset, void *data _U_) |
654 | 0 | { |
655 | 0 | return (tvb_get_ntohl(tvb, offset) + 4); |
656 | 0 | } |
657 | | |
658 | | static int |
659 | | dissect_riemann_tcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data) |
660 | 0 | { |
661 | 0 | tcp_dissect_pdus(tvb, pinfo, tree, true, 4, get_riemann_tcp_pdu_len, dissect_riemann_tcp_pdu, data); |
662 | |
|
663 | 0 | return tvb_captured_length(tvb); |
664 | 0 | } |
665 | | |
666 | | void |
667 | | proto_register_riemann(void) |
668 | 16 | { |
669 | 16 | expert_module_t *riemann_expert_module; |
670 | | |
671 | 16 | static hf_register_info hf[] = { |
672 | 16 | { &hf_riemann_msg_ok, |
673 | 16 | { "ok", "riemann.msg.ok", |
674 | 16 | FT_BOOLEAN, BASE_NONE, NULL, 0, NULL, HFILL } |
675 | 16 | }, |
676 | 16 | { &hf_riemann_msg_error, |
677 | 16 | { "error", "riemann.msg.error", |
678 | 16 | FT_STRING, BASE_NONE, NULL, 0, NULL, HFILL } |
679 | 16 | }, |
680 | 16 | { &hf_riemann_attribute, |
681 | 16 | { "attribute", "riemann.attribute", |
682 | 16 | FT_NONE, BASE_NONE, NULL, 0, NULL, HFILL } |
683 | 16 | }, |
684 | 16 | { &hf_riemann_attribute_key, |
685 | 16 | { "key", "riemann.attribute.key", |
686 | 16 | FT_STRING, BASE_NONE, NULL, 0, NULL, HFILL } |
687 | 16 | }, |
688 | 16 | { &hf_riemann_attribute_value, |
689 | 16 | { "value", "riemann.attribute.value", |
690 | 16 | FT_STRING, BASE_NONE, NULL, 0, NULL, HFILL } |
691 | 16 | }, |
692 | 16 | { &hf_riemann_query, |
693 | 16 | { "query", "riemann.query", |
694 | 16 | FT_NONE, BASE_NONE, NULL, 0, NULL, HFILL } |
695 | 16 | }, |
696 | 16 | { &hf_riemann_query_string, |
697 | 16 | { "string", "riemann.query.string", |
698 | 16 | FT_STRING, BASE_NONE, NULL, 0, NULL, HFILL } |
699 | 16 | }, |
700 | 16 | { &hf_riemann_event, |
701 | 16 | { "event", "riemann.event", |
702 | 16 | FT_NONE, BASE_NONE, NULL, 0, NULL, HFILL } |
703 | 16 | }, |
704 | 16 | { &hf_riemann_event_state, |
705 | 16 | { "state", "riemann.event.state", |
706 | 16 | FT_STRING, BASE_NONE, NULL, 0, NULL, HFILL } |
707 | 16 | }, |
708 | 16 | { &hf_riemann_event_service, |
709 | 16 | { "service", "riemann.event.service", |
710 | 16 | FT_STRING, BASE_NONE, NULL, 0, NULL, HFILL } |
711 | 16 | }, |
712 | 16 | { &hf_riemann_event_host, |
713 | 16 | { "host", "riemann.event.host", |
714 | 16 | FT_STRING, BASE_NONE, NULL, 0, NULL, HFILL } |
715 | 16 | }, |
716 | 16 | { &hf_riemann_event_description, |
717 | 16 | { "description", "riemann.event.description", |
718 | 16 | FT_STRING, BASE_NONE, NULL, 0, NULL, HFILL } |
719 | 16 | }, |
720 | 16 | { &hf_riemann_event_tag, |
721 | 16 | { "tag", "riemann.event.tag", |
722 | 16 | FT_STRING, BASE_NONE, NULL, 0, NULL, HFILL } |
723 | 16 | }, |
724 | 16 | { &hf_riemann_event_time, |
725 | 16 | { "time", "riemann.event.time", |
726 | 16 | FT_INT64, BASE_DEC, NULL, 0, NULL, HFILL } |
727 | 16 | }, |
728 | 16 | { &hf_riemann_event_ttl, |
729 | 16 | { "ttl", "riemann.event.ttl", |
730 | 16 | FT_FLOAT, BASE_NONE, NULL, 0, NULL, HFILL } |
731 | 16 | }, |
732 | 16 | { &hf_riemann_event_metric_d, |
733 | 16 | { "metric_d", "riemann.event.metric_d", |
734 | 16 | FT_DOUBLE, BASE_NONE, NULL, 0, NULL, HFILL } |
735 | 16 | }, |
736 | 16 | { &hf_riemann_event_metric_f, |
737 | 16 | { "metric_f", "riemann.event.metric_f", |
738 | 16 | FT_FLOAT, BASE_NONE, NULL, 0, NULL, HFILL } |
739 | 16 | }, |
740 | 16 | { &hf_riemann_event_time_micros, |
741 | 16 | { "time_micros", "riemann.event.time_micros", |
742 | 16 | FT_INT64, BASE_DEC, NULL, 0, NULL, HFILL } |
743 | 16 | }, |
744 | 16 | { &hf_riemann_event_metric_sint64, |
745 | 16 | { "metric_sint64", "riemann.event.metric_sint64", |
746 | 16 | FT_INT64, BASE_DEC, NULL, 0, NULL, HFILL } |
747 | 16 | }, |
748 | 16 | { &hf_riemann_state, |
749 | 16 | { "state", "riemann.state", |
750 | 16 | FT_NONE, BASE_NONE, NULL, 0, NULL, HFILL } |
751 | 16 | }, |
752 | 16 | { &hf_riemann_state_service, |
753 | 16 | { "service", "riemann.state.service", |
754 | 16 | FT_STRING, BASE_NONE, NULL, 0, NULL, HFILL } |
755 | 16 | }, |
756 | 16 | { &hf_riemann_state_host, |
757 | 16 | { "host", "riemann.state.host", |
758 | 16 | FT_STRING, BASE_NONE, NULL, 0, NULL, HFILL } |
759 | 16 | }, |
760 | 16 | { &hf_riemann_state_description, |
761 | 16 | { "description", "riemann.state.description", |
762 | 16 | FT_STRING, BASE_NONE, NULL, 0, NULL, HFILL } |
763 | 16 | }, |
764 | 16 | { &hf_riemann_state_tag, |
765 | 16 | { "tag", "riemann.state.tag", |
766 | 16 | FT_STRING, BASE_NONE, NULL, 0, NULL, HFILL } |
767 | 16 | }, |
768 | 16 | { &hf_riemann_state_time, |
769 | 16 | { "time", "riemann.state.time", |
770 | 16 | FT_INT64, BASE_DEC, NULL, 0, NULL, HFILL } |
771 | 16 | }, |
772 | 16 | { &hf_riemann_state_ttl, |
773 | 16 | { "ttl", "riemann.state.ttl", |
774 | 16 | FT_FLOAT, BASE_NONE, NULL, 0, NULL, HFILL } |
775 | 16 | }, |
776 | 16 | { &hf_riemann_state_state, |
777 | 16 | { "state", "riemann.state.state", |
778 | 16 | FT_STRING, BASE_NONE, NULL, 0, NULL, HFILL } |
779 | 16 | }, |
780 | 16 | { &hf_riemann_state_once, |
781 | 16 | { "once", "riemann.state.once", |
782 | 16 | FT_BOOLEAN, BASE_NONE, NULL, 0, NULL, HFILL } |
783 | 16 | } |
784 | 16 | }; |
785 | | |
786 | 16 | static ei_register_info ei[] = { |
787 | 16 | { &ei_error_unknown_wire_tag, |
788 | 16 | { "riemann.unknown_wire_tag", PI_MALFORMED, PI_ERROR, |
789 | 16 | "Invalid format type", EXPFILL }}, |
790 | 16 | { &ei_error_unknown_field_number, |
791 | 16 | { "riemann.unknown_field_number", PI_MALFORMED, PI_ERROR, |
792 | 16 | "Unknown field number", EXPFILL }}, |
793 | 16 | { &ei_error_insufficient_data, |
794 | 16 | { "riemann.insufficient_data", PI_MALFORMED, PI_ERROR, |
795 | 16 | "Insufficient data", EXPFILL }} |
796 | 16 | }; |
797 | | |
798 | 16 | static int *ett[] = { |
799 | 16 | &ett_riemann, |
800 | 16 | &ett_query, |
801 | 16 | &ett_event, |
802 | 16 | &ett_attribute, |
803 | 16 | &ett_state |
804 | 16 | }; |
805 | | |
806 | 16 | proto_riemann = proto_register_protocol("Riemann", "Riemann", "riemann"); |
807 | 16 | riemann_expert_module = expert_register_protocol(proto_riemann); |
808 | 16 | expert_register_field_array(riemann_expert_module, ei, array_length(ei)); |
809 | | |
810 | 16 | proto_register_field_array(proto_riemann, hf, array_length(hf)); |
811 | 16 | proto_register_subtree_array(ett, array_length(ett)); |
812 | | |
813 | 16 | riemann_udp_handle = register_dissector("riemann.udp", dissect_riemann_udp, proto_riemann); |
814 | 16 | riemann_tcp_handle = register_dissector("riemann.tcp", dissect_riemann_tcp, proto_riemann); |
815 | 16 | } |
816 | | |
817 | | void |
818 | | proto_reg_handoff_riemann(void) |
819 | 16 | { |
820 | 16 | dissector_add_for_decode_as_with_preference("tcp.port", riemann_tcp_handle); |
821 | 16 | dissector_add_for_decode_as_with_preference("udp.port", riemann_udp_handle); |
822 | 16 | } |
823 | | |
824 | | /* |
825 | | * Editor modelines - https://www.wireshark.org/tools/modelines.html |
826 | | * |
827 | | * Local variables: |
828 | | * c-basic-offset: 4 |
829 | | * tab-width: 8 |
830 | | * indent-tabs-mode: nil |
831 | | * End: |
832 | | * |
833 | | * vi: set shiftwidth=4 tabstop=8 expandtab: |
834 | | * :indentSize=4:tabSize=8:noTabs=true: |
835 | | */ |