Coverage Report

Created: 2026-05-14 06:28

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
    return (char*)tvb_get_string_enc(scope, tvb, offset, (int)size, ENC_ASCII);
226
0
}
227
228
static unsigned
229
riemann_dissect_int64(proto_tree *riemann_tree, tvbuff_t *tvb, unsigned offset, int hf_index)
230
0
{
231
0
    uint64_t num;
232
0
    unsigned   len = 0;
233
234
0
    num = riemann_get_uint64(tvb, offset, &len);
235
0
    proto_tree_add_int64(riemann_tree, hf_index, tvb, offset, len, num);
236
0
    return len;
237
0
}
238
239
static unsigned
240
riemann_dissect_sint64(proto_tree *riemann_tree, tvbuff_t *tvb, unsigned offset, int hf_index)
241
0
{
242
0
    int64_t snum;
243
0
    unsigned len = 0;
244
245
0
    len = tvb_get_varint(tvb, offset, FT_VARINT_MAX_LEN, (uint64_t*)&snum, ENC_VARINT_ZIGZAG);
246
0
    if (!len) {
247
0
        len = FT_VARINT_MAX_LEN;
248
0
        snum = 0;
249
        // XXX - Add some failure expert info
250
0
    }
251
252
0
    proto_tree_add_int64(riemann_tree, hf_index, tvb, offset, len, snum);
253
0
    return len;
254
0
}
255
256
static unsigned
257
riemann_dissect_string(proto_tree *riemann_tree, tvbuff_t *tvb, unsigned offset, int hf_index)
258
0
{
259
0
    uint64_t size;
260
0
    unsigned   len = 0, orig_offset = offset;
261
262
0
    size = riemann_get_uint64(tvb, offset, &len);
263
0
    offset += len;
264
0
    proto_tree_add_item(riemann_tree, hf_index, tvb, offset, (int)size, ENC_ASCII);
265
0
    offset += (int)size;
266
267
0
    return offset - orig_offset;
268
0
}
269
270
static unsigned
271
riemann_dissect_attribute(packet_info *pinfo, proto_tree *riemann_tree,
272
                          tvbuff_t *tvb, unsigned offset)
273
0
{
274
0
    uint64_t    tag, fn;
275
0
    int64_t     size;
276
0
    uint8_t     wire;
277
0
    unsigned    len         = 0;
278
0
    unsigned    orig_offset = offset;
279
0
    proto_item *pi;
280
0
    proto_tree *attribute_tree;
281
282
0
    size = (int64_t)riemann_get_uint64(tvb, offset, &len);
283
0
    pi = proto_tree_add_item(riemann_tree, hf_riemann_attribute, tvb, (int)offset, (int)(size + len), ENC_NA);
284
0
    attribute_tree = proto_item_add_subtree(pi, ett_attribute);
285
0
    offset += len;
286
287
0
    while (size > 0) {
288
0
        tag  = riemann_get_uint64(tvb, offset, &len);
289
0
        fn   = tag >> 3;
290
0
        wire = tag & 0x7;
291
0
        offset += len;
292
0
        size   -= len;
293
0
        switch (fn) {
294
0
        case RIEMANN_FN_ATTRIBUTE_KEY:
295
0
            VERIFY_WIRE_FORMAT("Attribute.key", RIEMANN_WIRE_BYTES);
296
0
            len = riemann_dissect_string(attribute_tree, tvb, offset, hf_riemann_attribute_key);
297
0
            break;
298
0
        case RIEMANN_FN_ATTRIBUTE_VALUE:
299
0
            VERIFY_WIRE_FORMAT("Attribute.value", RIEMANN_WIRE_BYTES);
300
0
            len = riemann_dissect_string(attribute_tree, tvb, offset, hf_riemann_attribute_value);
301
0
            break;
302
0
        default:
303
0
            len = 0;
304
0
            UNKNOWN_FIELD_NUMBER_FOR("Attribute");
305
0
        }
306
0
        offset += len;
307
0
        size   -= len;
308
0
    }
309
0
    VERIFY_SIZE_FOR("Attribute");
310
311
0
    return offset - orig_offset;
312
0
}
313
314
static unsigned
315
riemann_dissect_query(packet_info *pinfo, proto_tree *riemann_tree,
316
                      tvbuff_t *tvb, unsigned offset)
317
0
{
318
0
    uint64_t    tag, fn;
319
0
    int64_t     size;
320
0
    uint8_t     wire;
321
0
    unsigned    orig_offset = offset, len = 0;
322
0
    proto_item *pi;
323
0
    proto_tree *query_tree;
324
325
0
    size = (int64_t)riemann_get_uint64(tvb, offset, &len);
326
0
    pi = proto_tree_add_item(riemann_tree, hf_riemann_query, tvb, (int)offset, (int)(size + len), ENC_NA);
327
0
    query_tree = proto_item_add_subtree(pi, ett_query);
328
0
    offset += len;
329
330
0
    while (size > 0) {
331
0
        tag  = riemann_get_uint64(tvb, offset, &len);
332
0
        fn   = tag >> 3;
333
0
        wire = tag & 0x7;
334
0
        offset += len;
335
0
        size   -= len;
336
0
        switch (fn) {
337
0
        case RIEMANN_FN_QUERY_STRING:
338
0
            VERIFY_WIRE_FORMAT("Query.string", RIEMANN_WIRE_BYTES);
339
0
            col_append_str(pinfo->cinfo, COL_INFO, riemann_get_string(pinfo->pool, tvb, offset));
340
0
            len = riemann_dissect_string(query_tree, tvb, offset, hf_riemann_query_string);
341
0
            break;
342
0
        default:
343
0
            len = 0;
344
0
            UNKNOWN_FIELD_NUMBER_FOR("Query");
345
0
        }
346
0
        offset += len;
347
0
        size   -= len;
348
0
    }
349
0
    VERIFY_SIZE_FOR("Query");
350
351
0
    return offset - orig_offset;
352
0
}
353
354
static unsigned
355
riemann_dissect_event(packet_info *pinfo, proto_tree *riemann_tree,
356
                      tvbuff_t *tvb, unsigned offset)
357
0
{
358
0
    unsigned    orig_offset = offset, len = 0;
359
0
    uint64_t    tag, fn;
360
0
    int64_t     size;
361
0
    uint8_t     wire;
362
0
    proto_item *pi;
363
0
    proto_tree *event_tree;
364
0
    bool        need_comma  = false;
365
366
0
    size = riemann_get_uint64(tvb, offset, &len);
367
0
    pi = proto_tree_add_item(riemann_tree, hf_riemann_event, tvb, (int)offset, (int)(size + len), ENC_NA);
368
0
    event_tree = proto_item_add_subtree(pi, ett_event);
369
0
    offset += len;
370
371
0
    while (size > 0) {
372
0
        const char *comma = need_comma ? ", " : "";
373
0
        tag  = riemann_get_uint64(tvb, offset, &len);
374
0
        fn   = tag >> 3;
375
0
        wire = tag & 0x7;
376
0
        offset += len;
377
0
        size   -= len;
378
0
        switch (fn) {
379
0
        case RIEMANN_FN_EVENT_TIME:
380
0
            VERIFY_WIRE_FORMAT("Event.time", RIEMANN_WIRE_INTEGER);
381
0
            len = riemann_dissect_int64(event_tree, tvb, offset, hf_riemann_event_time);
382
0
            break;
383
0
        case RIEMANN_FN_EVENT_STATE:
384
0
            VERIFY_WIRE_FORMAT("Event.state", RIEMANN_WIRE_BYTES);
385
0
            len = riemann_dissect_string(event_tree, tvb, offset, hf_riemann_event_state);
386
0
            break;
387
0
        case RIEMANN_FN_EVENT_SERVICE:
388
0
            VERIFY_WIRE_FORMAT("Event.service", RIEMANN_WIRE_BYTES);
389
0
            col_append_fstr(pinfo->cinfo, COL_INFO, "%s%s", comma, riemann_get_string(pinfo->pool, tvb, offset));
390
0
            len = riemann_dissect_string(event_tree, tvb, offset, hf_riemann_event_service);
391
0
            need_comma = true;
392
0
            break;
393
0
        case RIEMANN_FN_EVENT_HOST:
394
0
            VERIFY_WIRE_FORMAT("Event.host", RIEMANN_WIRE_BYTES);
395
0
            col_append_fstr(pinfo->cinfo, COL_INFO, "%s%s", comma, riemann_get_string(pinfo->pool, tvb, offset));
396
0
            len = riemann_dissect_string(event_tree, tvb, offset, hf_riemann_event_host);
397
0
            need_comma = true;
398
0
            break;
399
0
        case RIEMANN_FN_EVENT_DESCRIPTION:
400
0
            VERIFY_WIRE_FORMAT("Event.description", RIEMANN_WIRE_BYTES);
401
0
            len = riemann_dissect_string(event_tree, tvb, offset, hf_riemann_event_description);
402
0
            break;
403
0
        case RIEMANN_FN_EVENT_TAGS:
404
0
            VERIFY_WIRE_FORMAT("Event.tags", RIEMANN_WIRE_BYTES);
405
0
            len = riemann_dissect_string(event_tree, tvb, offset, hf_riemann_event_tag);
406
0
            break;
407
0
        case RIEMANN_FN_EVENT_TTL:
408
0
            VERIFY_WIRE_FORMAT("Event.ttl", RIEMANN_WIRE_FLOAT);
409
0
            proto_tree_add_item(event_tree, hf_riemann_event_ttl, tvb, offset, 4, ENC_LITTLE_ENDIAN);
410
0
            len = 4;
411
0
            break;
412
0
        case RIEMANN_FN_EVENT_ATTRIBUTES:
413
0
            VERIFY_WIRE_FORMAT("Event.attributes", RIEMANN_WIRE_BYTES);
414
0
            len = riemann_dissect_attribute(pinfo, event_tree, tvb, offset);
415
0
            break;
416
0
        case RIEMANN_FN_EVENT_TIME_MICROS:
417
0
            VERIFY_WIRE_FORMAT("Event.time_micros", RIEMANN_WIRE_INTEGER);
418
0
            len = riemann_dissect_int64(event_tree, tvb, offset, hf_riemann_event_time_micros);
419
0
            break;
420
0
        case RIEMANN_FN_EVENT_METRIC_SINT64:
421
0
            VERIFY_WIRE_FORMAT("Event.metric_sint64", RIEMANN_WIRE_INTEGER);
422
0
            len = riemann_dissect_sint64(event_tree, tvb, offset, hf_riemann_event_metric_sint64);
423
0
            break;
424
0
        case RIEMANN_FN_EVENT_METRIC_D:
425
0
            VERIFY_WIRE_FORMAT("Event.metric_d", RIEMANN_WIRE_DOUBLE);
426
0
            proto_tree_add_item(event_tree, hf_riemann_event_metric_d, tvb, offset, 8, ENC_LITTLE_ENDIAN);
427
0
            len = 8;
428
0
            break;
429
0
        case RIEMANN_FN_EVENT_METRIC_F:
430
0
            VERIFY_WIRE_FORMAT("Event.metric_f", RIEMANN_WIRE_FLOAT);
431
0
            proto_tree_add_item(event_tree, hf_riemann_event_metric_f, tvb, offset, 4, ENC_LITTLE_ENDIAN);
432
0
            len = 4;
433
0
            break;
434
0
        default:
435
0
            len = 0;
436
0
            UNKNOWN_FIELD_NUMBER_FOR("Event");
437
0
        }
438
0
        offset += len;
439
0
        size   -= len;
440
0
    }
441
0
    col_append_str(pinfo->cinfo, COL_INFO, "; ");
442
0
    VERIFY_SIZE_FOR("Event");
443
444
0
    return offset - orig_offset;
445
0
}
446
447
static unsigned
448
riemann_dissect_state(packet_info *pinfo, proto_tree *riemann_tree,
449
                      tvbuff_t *tvb, unsigned offset)
450
0
{
451
0
    unsigned    orig_offset = offset, len = 0;
452
0
    uint64_t    tag, fn;
453
0
    int64_t     size;
454
0
    uint8_t     wire;
455
0
    proto_item *pi;
456
0
    proto_tree *state_tree;
457
0
    bool        need_comma  = false;
458
459
0
    size = riemann_get_uint64(tvb, offset, &len);
460
0
    pi   = proto_tree_add_item(riemann_tree, hf_riemann_state, tvb, offset, (int)(size + len), ENC_NA);
461
0
    state_tree = proto_item_add_subtree(pi, ett_state);
462
0
    offset += len;
463
464
0
    while (size > 0) {
465
0
        const char *comma = need_comma ? ", " : "";
466
0
        tag  = riemann_get_uint64(tvb, offset, &len);
467
0
        fn   = tag >> 3;
468
0
        wire = tag & 0x7;
469
0
        offset += len;
470
0
        size   -= len;
471
0
        switch (fn) {
472
0
        case RIEMANN_FN_STATE_TIME:
473
0
            VERIFY_WIRE_FORMAT("State.time", RIEMANN_WIRE_INTEGER);
474
0
            len = riemann_dissect_int64(state_tree, tvb, offset, hf_riemann_state_time);
475
0
            break;
476
0
        case RIEMANN_FN_STATE_SERVICE:
477
0
            VERIFY_WIRE_FORMAT("State.service", RIEMANN_WIRE_BYTES);
478
0
            col_append_fstr(pinfo->cinfo, COL_INFO, "%s%s", comma, riemann_get_string(pinfo->pool, tvb, offset));
479
0
            len = riemann_dissect_string(state_tree, tvb, offset, hf_riemann_state_service);
480
0
            need_comma = true;
481
0
            break;
482
0
        case RIEMANN_FN_STATE_HOST:
483
0
            VERIFY_WIRE_FORMAT("State.host", RIEMANN_WIRE_BYTES);
484
0
            col_append_fstr(pinfo->cinfo, COL_INFO, "%s%s", comma, riemann_get_string(pinfo->pool, tvb, offset));
485
0
            len = riemann_dissect_string(state_tree, tvb, offset, hf_riemann_state_host);
486
0
            need_comma = true;
487
0
            break;
488
0
        case RIEMANN_FN_STATE_DESCRIPTION:
489
0
            VERIFY_WIRE_FORMAT("State.description", RIEMANN_WIRE_BYTES);
490
0
            len = riemann_dissect_string(state_tree, tvb, offset, hf_riemann_state_description);
491
0
            break;
492
0
        case RIEMANN_FN_STATE_TAGS:
493
0
            VERIFY_WIRE_FORMAT("State.tags", RIEMANN_WIRE_BYTES);
494
0
            len = riemann_dissect_string(state_tree, tvb, offset, hf_riemann_state_tag);
495
0
            break;
496
0
        case RIEMANN_FN_STATE_TTL:
497
0
            VERIFY_WIRE_FORMAT("State.ttl", RIEMANN_WIRE_FLOAT);
498
0
            proto_tree_add_item(state_tree, hf_riemann_state_ttl, tvb, offset, 4, ENC_LITTLE_ENDIAN);
499
0
            len = 4;
500
0
            break;
501
0
        case RIEMANN_FN_STATE_STATE:
502
0
            VERIFY_WIRE_FORMAT("State.state", RIEMANN_WIRE_BYTES);
503
0
            len = riemann_dissect_string(state_tree, tvb, offset, hf_riemann_state_state);
504
0
            break;
505
0
        case RIEMANN_FN_STATE_ONCE:
506
0
            VERIFY_WIRE_FORMAT("State.once", RIEMANN_WIRE_INTEGER);
507
0
            proto_tree_add_item(state_tree, hf_riemann_state_once, tvb, offset, 1, ENC_NA);
508
0
            len = 1;
509
0
            break;
510
0
        default:
511
0
            len = 0;
512
0
            UNKNOWN_FIELD_NUMBER_FOR("State");
513
0
        }
514
0
        offset += len;
515
0
        size   -= len;
516
0
    }
517
0
    col_append_str(pinfo->cinfo, COL_INFO, "; ");
518
0
    VERIFY_SIZE_FOR("State");
519
520
0
    return offset - orig_offset;
521
0
}
522
523
static unsigned
524
riemann_dissect_msg(packet_info *pinfo, proto_item *pi, proto_tree *riemann_tree,
525
                    tvbuff_t *tvb, unsigned offset)
526
0
{
527
0
    uint64_t tag, fn;
528
0
    int64_t  size = (int64_t)tvb_reported_length_remaining(tvb, offset);
529
0
    uint8_t  wire;
530
0
    unsigned len, orig_offset = offset;
531
0
    bool cinfo_set = false;
532
533
0
    while (size > 0) {
534
0
        tag  = riemann_get_uint64(tvb, offset, &len);
535
0
        fn   = tag >> 3;
536
0
        wire = tag & 0x7;
537
0
        offset += len;
538
0
        size   -= len;
539
540
0
        switch (fn) {
541
0
        case RIEMANN_FN_MSG_OK:
542
0
            VERIFY_WIRE_FORMAT("Msg.ok", RIEMANN_WIRE_INTEGER);
543
0
            proto_tree_add_item(riemann_tree, hf_riemann_msg_ok, tvb, offset, 1, ENC_NA);
544
0
            len = 1;
545
0
            break;
546
0
        case RIEMANN_FN_MSG_ERROR:
547
0
            VERIFY_WIRE_FORMAT("Msg.error", RIEMANN_WIRE_BYTES);
548
0
            len = riemann_dissect_string(riemann_tree, tvb, offset, hf_riemann_msg_error);
549
0
            break;
550
0
        case RIEMANN_FN_MSG_QUERY:
551
0
            VERIFY_WIRE_FORMAT("Msg.query", RIEMANN_WIRE_BYTES);
552
0
            if (!cinfo_set) {
553
0
                col_set_str(pinfo->cinfo, COL_INFO, "Query: ");
554
0
                cinfo_set = true;
555
0
            }
556
0
            len = riemann_dissect_query(pinfo, riemann_tree, tvb, offset);
557
0
            break;
558
0
        case RIEMANN_FN_MSG_EVENTS:
559
0
            VERIFY_WIRE_FORMAT("Msg.events", RIEMANN_WIRE_BYTES);
560
0
            if (!cinfo_set) {
561
0
                col_set_str(pinfo->cinfo, COL_INFO, "Event: ");
562
0
                cinfo_set = true;
563
0
            }
564
0
            len = riemann_dissect_event(pinfo, riemann_tree, tvb, offset);
565
0
            break;
566
0
        case RIEMANN_FN_MSG_STATES:
567
0
            VERIFY_WIRE_FORMAT("Msg.states", RIEMANN_WIRE_BYTES);
568
0
            if (!cinfo_set) {
569
0
                col_set_str(pinfo->cinfo, COL_INFO, "State: ");
570
0
                cinfo_set = true;
571
0
            }
572
0
            len = riemann_dissect_state(pinfo, riemann_tree, tvb, offset);
573
0
            break;
574
0
        default:
575
0
            len = 0;
576
0
            UNKNOWN_FIELD_NUMBER_FOR("Msg");
577
0
        }
578
0
        offset += len;
579
0
        size -= len;
580
0
    }
581
0
    VERIFY_SIZE_FOR("Msg");
582
583
0
    return offset - orig_offset;
584
0
}
585
586
static bool
587
is_riemann(tvbuff_t *tvb, unsigned offset)
588
0
{
589
0
    uint32_t reported_length = tvb_reported_length_remaining(tvb, offset);
590
0
    uint32_t captured_length = tvb_captured_length_remaining(tvb, offset);
591
0
    uint64_t tag, field_number, wire_format;
592
0
    unsigned len;
593
594
0
    if ((reported_length < RIEMANN_MIN_LENGTH) ||
595
0
        (captured_length < RIEMANN_MIN_NEEDED_FOR_HEURISTICS)) {
596
0
        return false;
597
0
    }
598
0
    tag = riemann_get_uint64(tvb, offset, &len);
599
0
    field_number = tag >> 3;
600
0
    wire_format  = tag & 0x7;
601
0
    if ((field_number == RIEMANN_FN_MSG_OK     && wire_format == RIEMANN_WIRE_INTEGER) ||
602
0
        (field_number == RIEMANN_FN_MSG_ERROR  && wire_format == RIEMANN_WIRE_BYTES)   ||
603
0
        (field_number == RIEMANN_FN_MSG_QUERY  && wire_format == RIEMANN_WIRE_BYTES)   ||
604
0
        (field_number == RIEMANN_FN_MSG_EVENTS && wire_format == RIEMANN_WIRE_BYTES)   ||
605
0
        (field_number == RIEMANN_FN_MSG_STATES && wire_format == RIEMANN_WIRE_BYTES)) {
606
0
        return true;
607
0
    }
608
0
    return false;
609
0
}
610
611
static int
612
dissect_riemann(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, unsigned offset)
613
0
{
614
0
    proto_item *pi;
615
0
    proto_tree *riemann_tree;
616
617
0
    if (!is_riemann(tvb, offset))
618
0
        return 0;
619
620
0
    col_set_str(pinfo->cinfo, COL_PROTOCOL, "riemann");
621
0
    col_clear(pinfo->cinfo, COL_INFO);
622
623
0
    pi = proto_tree_add_item(tree, proto_riemann, tvb, offset, -1, ENC_NA);
624
0
    riemann_tree = proto_item_add_subtree(pi, ett_riemann);
625
626
0
    return riemann_dissect_msg(pinfo, pi, riemann_tree, tvb, offset);
627
0
}
628
629
static int
630
dissect_riemann_udp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
631
0
{
632
0
    return dissect_riemann(tvb, pinfo, tree, 0);
633
0
}
634
635
static int
636
dissect_riemann_tcp_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
637
0
{
638
0
    return dissect_riemann(tvb, pinfo, tree, 4);
639
0
}
640
641
static unsigned
642
get_riemann_tcp_pdu_len(packet_info *pinfo _U_, tvbuff_t *tvb,
643
                        int offset, void *data _U_)
644
0
{
645
0
    return (tvb_get_ntohl(tvb, offset) + 4);
646
0
}
647
648
static int
649
dissect_riemann_tcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
650
0
{
651
0
    tcp_dissect_pdus(tvb, pinfo, tree, true, 4, get_riemann_tcp_pdu_len, dissect_riemann_tcp_pdu, data);
652
653
0
    return tvb_captured_length(tvb);
654
0
}
655
656
void
657
proto_register_riemann(void)
658
15
{
659
15
    expert_module_t *riemann_expert_module;
660
661
15
    static hf_register_info hf[] = {
662
15
        { &hf_riemann_msg_ok,
663
15
          { "ok", "riemann.msg.ok",
664
15
            FT_BOOLEAN, BASE_NONE, NULL, 0, NULL, HFILL }
665
15
        },
666
15
        { &hf_riemann_msg_error,
667
15
          { "error", "riemann.msg.error",
668
15
            FT_STRING, BASE_NONE, NULL, 0, NULL, HFILL }
669
15
        },
670
15
        { &hf_riemann_attribute,
671
15
          { "attribute", "riemann.attribute",
672
15
            FT_NONE, BASE_NONE, NULL, 0, NULL, HFILL }
673
15
        },
674
15
        { &hf_riemann_attribute_key,
675
15
          { "key", "riemann.attribute.key",
676
15
            FT_STRING, BASE_NONE, NULL, 0, NULL, HFILL }
677
15
        },
678
15
        { &hf_riemann_attribute_value,
679
15
          { "value", "riemann.attribute.value",
680
15
            FT_STRING, BASE_NONE, NULL, 0, NULL, HFILL }
681
15
        },
682
15
        { &hf_riemann_query,
683
15
          { "query", "riemann.query",
684
15
            FT_NONE, BASE_NONE, NULL, 0, NULL, HFILL }
685
15
        },
686
15
        { &hf_riemann_query_string,
687
15
          { "string", "riemann.query.string",
688
15
            FT_STRING, BASE_NONE, NULL, 0, NULL, HFILL }
689
15
        },
690
15
        { &hf_riemann_event,
691
15
          { "event", "riemann.event",
692
15
            FT_NONE, BASE_NONE, NULL, 0, NULL, HFILL }
693
15
        },
694
15
        { &hf_riemann_event_state,
695
15
          { "state", "riemann.event.state",
696
15
            FT_STRING, BASE_NONE, NULL, 0, NULL, HFILL }
697
15
        },
698
15
        { &hf_riemann_event_service,
699
15
          { "service", "riemann.event.service",
700
15
            FT_STRING, BASE_NONE, NULL, 0, NULL, HFILL }
701
15
        },
702
15
        { &hf_riemann_event_host,
703
15
          { "host", "riemann.event.host",
704
15
            FT_STRING, BASE_NONE, NULL, 0, NULL, HFILL }
705
15
        },
706
15
        { &hf_riemann_event_description,
707
15
          { "description", "riemann.event.description",
708
15
            FT_STRING, BASE_NONE, NULL, 0, NULL, HFILL }
709
15
        },
710
15
        { &hf_riemann_event_tag,
711
15
          { "tag", "riemann.event.tag",
712
15
            FT_STRING, BASE_NONE, NULL, 0, NULL, HFILL }
713
15
        },
714
15
        { &hf_riemann_event_time,
715
15
          { "time", "riemann.event.time",
716
15
            FT_INT64, BASE_DEC, NULL, 0, NULL, HFILL }
717
15
        },
718
15
        { &hf_riemann_event_ttl,
719
15
          { "ttl", "riemann.event.ttl",
720
15
            FT_FLOAT, BASE_NONE, NULL, 0, NULL, HFILL }
721
15
        },
722
15
        { &hf_riemann_event_metric_d,
723
15
          { "metric_d", "riemann.event.metric_d",
724
15
            FT_DOUBLE, BASE_NONE, NULL, 0, NULL, HFILL }
725
15
        },
726
15
        { &hf_riemann_event_metric_f,
727
15
          { "metric_f", "riemann.event.metric_f",
728
15
            FT_FLOAT, BASE_NONE, NULL, 0, NULL, HFILL }
729
15
        },
730
15
        { &hf_riemann_event_time_micros,
731
15
          { "time_micros", "riemann.event.time_micros",
732
15
            FT_INT64, BASE_DEC, NULL, 0, NULL, HFILL }
733
15
        },
734
15
        { &hf_riemann_event_metric_sint64,
735
15
          { "metric_sint64", "riemann.event.metric_sint64",
736
15
            FT_INT64, BASE_DEC, NULL, 0, NULL, HFILL }
737
15
        },
738
15
        { &hf_riemann_state,
739
15
          { "state", "riemann.state",
740
15
            FT_NONE, BASE_NONE, NULL, 0, NULL, HFILL }
741
15
        },
742
15
        { &hf_riemann_state_service,
743
15
          { "service", "riemann.state.service",
744
15
            FT_STRING, BASE_NONE, NULL, 0, NULL, HFILL }
745
15
        },
746
15
        { &hf_riemann_state_host,
747
15
          { "host", "riemann.state.host",
748
15
            FT_STRING, BASE_NONE, NULL, 0, NULL, HFILL }
749
15
        },
750
15
        { &hf_riemann_state_description,
751
15
          { "description", "riemann.state.description",
752
15
            FT_STRING, BASE_NONE, NULL, 0, NULL, HFILL }
753
15
        },
754
15
        { &hf_riemann_state_tag,
755
15
          { "tag", "riemann.state.tag",
756
15
            FT_STRING, BASE_NONE, NULL, 0, NULL, HFILL }
757
15
        },
758
15
        { &hf_riemann_state_time,
759
15
          { "time", "riemann.state.time",
760
15
            FT_INT64, BASE_DEC, NULL, 0, NULL, HFILL }
761
15
        },
762
15
        { &hf_riemann_state_ttl,
763
15
          { "ttl", "riemann.state.ttl",
764
15
            FT_FLOAT, BASE_NONE, NULL, 0, NULL, HFILL }
765
15
        },
766
15
        { &hf_riemann_state_state,
767
15
          { "state", "riemann.state.state",
768
15
            FT_STRING, BASE_NONE, NULL, 0, NULL, HFILL }
769
15
        },
770
15
        { &hf_riemann_state_once,
771
15
          { "once", "riemann.state.once",
772
15
            FT_BOOLEAN, BASE_NONE, NULL, 0, NULL, HFILL }
773
15
        }
774
15
    };
775
776
15
    static ei_register_info ei[] = {
777
15
        { &ei_error_unknown_wire_tag,
778
15
          { "riemann.unknown_wire_tag", PI_MALFORMED, PI_ERROR,
779
15
            "Invalid format type", EXPFILL }},
780
15
        { &ei_error_unknown_field_number,
781
15
          { "riemann.unknown_field_number", PI_MALFORMED, PI_ERROR,
782
15
            "Unknown field number", EXPFILL }},
783
15
        { &ei_error_insufficient_data,
784
15
          { "riemann.insufficient_data", PI_MALFORMED, PI_ERROR,
785
15
            "Insufficient data", EXPFILL }}
786
15
    };
787
788
15
    static int *ett[] = {
789
15
        &ett_riemann,
790
15
        &ett_query,
791
15
        &ett_event,
792
15
        &ett_attribute,
793
15
        &ett_state
794
15
    };
795
796
15
    proto_riemann = proto_register_protocol("Riemann", "Riemann", "riemann");
797
15
    riemann_expert_module = expert_register_protocol(proto_riemann);
798
15
    expert_register_field_array(riemann_expert_module, ei, array_length(ei));
799
800
15
    proto_register_field_array(proto_riemann, hf, array_length(hf));
801
15
    proto_register_subtree_array(ett, array_length(ett));
802
803
15
    riemann_udp_handle = register_dissector("riemann.udp", dissect_riemann_udp, proto_riemann);
804
15
    riemann_tcp_handle = register_dissector("riemann.tcp", dissect_riemann_tcp, proto_riemann);
805
15
}
806
807
void
808
proto_reg_handoff_riemann(void)
809
15
{
810
15
    dissector_add_for_decode_as_with_preference("tcp.port", riemann_tcp_handle);
811
15
    dissector_add_for_decode_as_with_preference("udp.port", riemann_udp_handle);
812
15
}
813
814
/*
815
 * Editor modelines  -  https://www.wireshark.org/tools/modelines.html
816
 *
817
 * Local variables:
818
 * c-basic-offset: 4
819
 * tab-width: 8
820
 * indent-tabs-mode: nil
821
 * End:
822
 *
823
 * vi: set shiftwidth=4 tabstop=8 expandtab:
824
 * :indentSize=4:tabSize=8:noTabs=true:
825
 */