Coverage Report

Created: 2026-11-12 07:01

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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
 */