Coverage Report

Created: 2026-09-28 06:52

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/wireshark/epan/dissectors/packet-mongo.c
Line
Count
Source
1
/* packet-mongo.c
2
 * Routines for Mongo Wire Protocol dissection
3
 * Copyright 2010, Alexis La Goutte <alexis.lagoutte at gmail dot com>
4
 * BSON dissection added 2011, Thomas Buchanan <tom at thomasbuchanan dot 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
/*
14
 * See Mongo Wire Protocol Specification
15
 * https://www.mongodb.com/docs/manual/reference/mongodb-wire-protocol/
16
 * See also BSON Specification
17
 * http://bsonspec.org/spec.html
18
 */
19
20
#include "config.h"
21
22
#include <epan/packet.h>
23
#include <epan/tfs.h>
24
#include <wsutil/array.h>
25
#include <epan/expert.h>
26
#include <epan/proto_data.h>
27
#include <epan/exceptions.h>
28
#include <wsutil/crc32.h> // CRC32C_PRELOAD
29
#include <epan/crc32-tvb.h> // crc32c_tvb_offset_calculate
30
#include "packet-tcp.h"
31
#ifdef HAVE_SNAPPY
32
#include <snappy-c.h>
33
#endif
34
35
void proto_register_mongo(void);
36
void proto_reg_handoff_mongo(void);
37
38
static dissector_handle_t mongo_handle;
39
static dissector_handle_t mongo_heur_handle;
40
41
/* Forward declaration */
42
static int
43
dissect_opcode_types(tvbuff_t *tvb, packet_info *pinfo, unsigned offset, proto_tree *mongo_tree, unsigned opcode, unsigned *effective_opcode, uint8_t **command_name);
44
45
/* This is not IANA assigned nor registered */
46
32
#define TCP_PORT_MONGO 27017
47
48
/* All opcodes other than OP_COMPRESSED and OP_MSG were removed
49
 * in MongoDB 5.1 (December 2021)
50
 */
51
0
#define OP_REPLY           1
52
0
#define OP_MESSAGE      1000
53
0
#define OP_UPDATE       2001
54
0
#define OP_INSERT       2002
55
#define OP_RESERVED     2003
56
0
#define OP_QUERY        2004
57
0
#define OP_GET_MORE     2005
58
0
#define OP_DELETE       2006
59
0
#define OP_KILL_CURSORS 2007
60
0
#define OP_COMMAND      2010
61
0
#define OP_COMMANDREPLY 2011
62
0
#define OP_COMPRESSED   2012
63
0
#define OP_MSG          2013
64
65
/**************************************************************************/
66
/*                      OpCode                                            */
67
/**************************************************************************/
68
static const value_string opcode_vals[] = {
69
  { OP_REPLY,  "Reply" },
70
  { OP_MESSAGE, "Message" },
71
  { OP_UPDATE,  "Update document" },
72
  { OP_INSERT,  "Insert document" },
73
  { OP_RESERVED,"Reserved" },
74
  { OP_QUERY,  "Query" },
75
  { OP_GET_MORE,  "Get More" },
76
  { OP_DELETE,  "Delete document" },
77
  { OP_KILL_CURSORS,  "Kill Cursors" },
78
  { OP_COMMAND,  "Command Request" },
79
  { OP_COMMANDREPLY,  "Command Reply" },
80
  { OP_COMPRESSED,  "Compressed Data" },
81
  { OP_MSG,  "Extensible Message Format" },
82
  { 0,  NULL }
83
};
84
85
0
#define KIND_BODY               0
86
0
#define KIND_DOCUMENT_SEQUENCE  1
87
88
/**************************************************************************/
89
/*                      Section Kind                                      */
90
/**************************************************************************/
91
static const value_string section_kind_vals[] = {
92
  { KIND_BODY, "Body" },
93
  { KIND_DOCUMENT_SEQUENCE, "Document Sequence" },
94
  { 0,  NULL }
95
};
96
97
/**************************************************************************/
98
/*                      Compression Engines                               */
99
/**************************************************************************/
100
0
#define MONGO_COMPRESSOR_NOOP    0
101
#define MONGO_COMPRESSOR_SNAPPY  1
102
0
#define MONGO_COMPRESSOR_ZLIB    2
103
#define MONGO_COMPRESSOR_ZSTD    3
104
105
static const value_string compressor_vals[] = {
106
  { MONGO_COMPRESSOR_NOOP,   "Noop (Uncompressed)" },
107
  { MONGO_COMPRESSOR_SNAPPY, "Snappy" },
108
  { MONGO_COMPRESSOR_ZLIB,   "Zlib" },
109
  { MONGO_COMPRESSOR_ZSTD,   "Zstd" },
110
  { 0,  NULL }
111
};
112
113
/* BSON Element types */
114
/* See http://bsonspec.org/#/specification for detail */
115
0
#define BSON_ELEMENT_TYPE_DOUBLE         1
116
0
#define BSON_ELEMENT_TYPE_STRING         2
117
0
#define BSON_ELEMENT_TYPE_DOC            3
118
0
#define BSON_ELEMENT_TYPE_ARRAY          4
119
0
#define BSON_ELEMENT_TYPE_BINARY         5
120
0
#define BSON_ELEMENT_TYPE_UNDEF          6  /* Deprecated */
121
0
#define BSON_ELEMENT_TYPE_OBJ_ID         7
122
0
#define BSON_ELEMENT_TYPE_BOOL           8
123
0
#define BSON_ELEMENT_TYPE_DATETIME       9
124
0
#define BSON_ELEMENT_TYPE_NULL          10
125
0
#define BSON_ELEMENT_TYPE_REGEX         11
126
0
#define BSON_ELEMENT_TYPE_DB_PTR        12  /* Deprecated */
127
0
#define BSON_ELEMENT_TYPE_JS_CODE       13
128
0
#define BSON_ELEMENT_TYPE_SYMBOL        14
129
0
#define BSON_ELEMENT_TYPE_JS_CODE_SCOPE 15
130
0
#define BSON_ELEMENT_TYPE_INT32         16  /* 0x10 */
131
0
#define BSON_ELEMENT_TYPE_TIMESTAMP     17  /* 0x11 */
132
0
#define BSON_ELEMENT_TYPE_INT64         18  /* 0x12 */
133
0
#define BSON_ELEMENT_TYPE_DECIMAL128    19  /* 0x13 */
134
0
#define BSON_ELEMENT_TYPE_MIN_KEY      255  /* 0xFF */
135
0
#define BSON_ELEMENT_TYPE_MAX_KEY      127  /* 0x7F */
136
137
static const value_string element_type_vals[] = {
138
  { BSON_ELEMENT_TYPE_DOUBLE,         "Double" },
139
  { BSON_ELEMENT_TYPE_STRING,         "String" },
140
  { BSON_ELEMENT_TYPE_DOC,            "Document" },
141
  { BSON_ELEMENT_TYPE_ARRAY,          "Array" },
142
  { BSON_ELEMENT_TYPE_BINARY,         "Binary" },
143
  { BSON_ELEMENT_TYPE_UNDEF,          "Undefined" },
144
  { BSON_ELEMENT_TYPE_OBJ_ID,         "Object ID" },
145
  { BSON_ELEMENT_TYPE_BOOL,           "Boolean" },
146
  { BSON_ELEMENT_TYPE_DATETIME,       "Datetime" },
147
  { BSON_ELEMENT_TYPE_NULL,           "NULL" },
148
  { BSON_ELEMENT_TYPE_REGEX,          "Regular Expression" },
149
  { BSON_ELEMENT_TYPE_DB_PTR,         "DBPointer" },
150
  { BSON_ELEMENT_TYPE_JS_CODE,        "JavaScript Code" },
151
  { BSON_ELEMENT_TYPE_SYMBOL,         "Symbol" },
152
  { BSON_ELEMENT_TYPE_JS_CODE_SCOPE,  "JavaScript Code w/Scope" },
153
  { BSON_ELEMENT_TYPE_INT32,          "Int32" },
154
  { BSON_ELEMENT_TYPE_TIMESTAMP,      "Timestamp" },
155
  { BSON_ELEMENT_TYPE_INT64,          "Int64" },
156
  { BSON_ELEMENT_TYPE_DECIMAL128,     "128-bit decimal floating point" },
157
  { BSON_ELEMENT_TYPE_MIN_KEY,        "Min Key" },
158
  { BSON_ELEMENT_TYPE_MAX_KEY,        "Max Key" },
159
  { 0, NULL }
160
};
161
162
/* BSON Element Binary subtypes */
163
#define BSON_ELEMENT_BINARY_TYPE_GENERIC  0
164
#define BSON_ELEMENT_BINARY_TYPE_FUNCTION 1
165
#define BSON_ELEMENT_BINARY_TYPE_BINARY   2 /* OLD */
166
#define BSON_ELEMENT_BINARY_TYPE_UUID     3
167
#define BSON_ELEMENT_BINARY_TYPE_MD5      4
168
#define BSON_ELEMENT_BINARY_TYPE_USER   128 /* 0x80 */
169
170
#if 0
171
static const value_string binary_type_vals[] = {
172
  { BSON_ELEMENT_BINARY_TYPE_GENERIC,  "Generic" },
173
  { BSON_ELEMENT_BINARY_TYPE_FUNCTION, "Function" },
174
  { BSON_ELEMENT_BINARY_TYPE_BINARY,   "Binary" },
175
  { BSON_ELEMENT_BINARY_TYPE_UUID,     "UUID" },
176
  { BSON_ELEMENT_BINARY_TYPE_MD5,      "MD5" },
177
  { BSON_ELEMENT_BINARY_TYPE_USER,     "User" },
178
  { 0, NULL }
179
};
180
#endif
181
182
static int proto_mongo;
183
static int hf_mongo_message_length;
184
static int hf_mongo_request_id;
185
static int hf_mongo_response_to;
186
static int hf_mongo_op_code;
187
static int hf_mongo_fullcollectionname;
188
static int hf_mongo_database_name;
189
static int hf_mongo_collection_name;
190
static int hf_mongo_reply_flags;
191
static int hf_mongo_reply_flags_cursornotfound;
192
static int hf_mongo_reply_flags_queryfailure;
193
static int hf_mongo_reply_flags_sharedconfigstale;
194
static int hf_mongo_reply_flags_awaitcapable;
195
static int hf_mongo_cursor_id;
196
static int hf_mongo_starting_from;
197
static int hf_mongo_number_returned;
198
static int hf_mongo_message;
199
static int hf_mongo_zero;
200
static int hf_mongo_update_flags;
201
static int hf_mongo_update_flags_upsert;
202
static int hf_mongo_update_flags_multiupdate;
203
static int hf_mongo_selector;
204
static int hf_mongo_update;
205
static int hf_mongo_insert_flags;
206
static int hf_mongo_insert_flags_continueonerror;
207
static int hf_mongo_query_flags;
208
static int hf_mongo_query_flags_tailablecursor;
209
static int hf_mongo_query_flags_slaveok;
210
static int hf_mongo_query_flags_oplogreplay;
211
static int hf_mongo_query_flags_nocursortimeout;
212
static int hf_mongo_query_flags_awaitdata;
213
static int hf_mongo_query_flags_exhaust;
214
static int hf_mongo_query_flags_partial;
215
static int hf_mongo_number_to_skip;
216
static int hf_mongo_number_to_return;
217
static int hf_mongo_query;
218
static int hf_mongo_return_field_selector;
219
static int hf_mongo_document;
220
static int hf_mongo_document_length;
221
static int hf_mongo_document_empty;
222
static int hf_mongo_delete_flags;
223
static int hf_mongo_delete_flags_singleremove;
224
static int hf_mongo_number_of_cursor_ids;
225
static int hf_mongo_elements;
226
static int hf_mongo_element_name;
227
static int hf_mongo_element_type;
228
static int hf_mongo_element_length;
229
static int hf_mongo_element_value_boolean;
230
static int hf_mongo_element_value_int32;
231
static int hf_mongo_element_value_int64;
232
static int hf_mongo_element_value_decimal128;
233
static int hf_mongo_element_value_double;
234
static int hf_mongo_element_value_string;
235
static int hf_mongo_element_value_string_length;
236
static int hf_mongo_element_value_binary;
237
static int hf_mongo_element_value_binary_length;
238
static int hf_mongo_element_value_regex_pattern;
239
static int hf_mongo_element_value_regex_options;
240
static int hf_mongo_element_value_objectid;
241
static int hf_mongo_element_value_objectid_time;
242
static int hf_mongo_element_value_objectid_host;
243
static int hf_mongo_element_value_objectid_pid;
244
static int hf_mongo_element_value_objectid_machine_id;
245
static int hf_mongo_element_value_objectid_inc;
246
static int hf_mongo_element_value_db_ptr;
247
static int hf_mongo_element_value_js_code;
248
static int hf_mongo_element_value_js_scope;
249
static int hf_mongo_database;
250
static int hf_mongo_commandname;
251
static int hf_mongo_metadata;
252
static int hf_mongo_commandargs;
253
static int hf_mongo_commandreply;
254
static int hf_mongo_outputdocs;
255
static int hf_mongo_unknown;
256
static int hf_mongo_compression_info;
257
static int hf_mongo_original_op_code;
258
static int hf_mongo_uncompressed_size;
259
static int hf_mongo_compressor;
260
static int hf_mongo_compressed_data;
261
static int hf_mongo_unsupported_compressed;
262
static int hf_mongo_msg_flags;
263
static int hf_mongo_msg_flags_checksumpresent;
264
static int hf_mongo_msg_flags_moretocome;
265
static int hf_mongo_msg_flags_exhaustallowed;
266
static int hf_mongo_msg_sections_section;
267
static int hf_mongo_msg_sections_section_kind;
268
static int hf_mongo_msg_sections_section_body;
269
static int hf_mongo_msg_sections_section_doc_sequence;
270
static int hf_mongo_msg_sections_section_size;
271
static int hf_mongo_msg_sections_section_doc_sequence_id;
272
static int hf_mongo_msg_checksum;
273
static int hf_mongo_msg_checksum_status;
274
275
static int ett_mongo;
276
static int ett_mongo_doc;
277
static int ett_mongo_elements;
278
static int ett_mongo_element;
279
static int ett_mongo_objectid;
280
static int ett_mongo_machine_id;
281
static int ett_mongo_code;
282
static int ett_mongo_fcn;
283
static int ett_mongo_flags;
284
static int ett_mongo_compression_info;
285
static int ett_mongo_sections;
286
static int ett_mongo_section;
287
static int ett_mongo_msg_flags;
288
static int ett_mongo_doc_sequence;
289
290
static expert_field ei_mongo_document_recursion_exceeded;
291
static expert_field ei_mongo_document_length_bad;
292
static expert_field ei_mongo_section_size_bad;
293
static expert_field ei_mongo_unknown;
294
static expert_field ei_mongo_unsupported_compression;
295
static expert_field ei_mongo_msg_checksum;
296
297
static int
298
dissect_fullcollectionname(tvbuff_t *tvb, unsigned offset, proto_tree *tree)
299
0
{
300
0
  uint32_t fcn_length, dbn_length;
301
0
  proto_item *ti;
302
0
  proto_tree *fcn_tree;
303
304
0
  fcn_length = tvb_strsize(tvb, offset);
305
0
  ti = proto_tree_add_item(tree, hf_mongo_fullcollectionname, tvb, offset, fcn_length, ENC_ASCII);
306
307
  /* If this doesn't find anything, we'll just throw an exception below */
308
0
  tvb_find_uint8_length(tvb, offset, fcn_length, '.', &dbn_length);
309
0
  dbn_length = dbn_length -offset;
310
311
0
  fcn_tree = proto_item_add_subtree(ti, ett_mongo_fcn);
312
313
0
  proto_tree_add_item(fcn_tree, hf_mongo_database_name, tvb, offset, dbn_length, ENC_ASCII);
314
315
0
  proto_tree_add_item(fcn_tree, hf_mongo_collection_name, tvb, offset + 1 + dbn_length, fcn_length - dbn_length - 2, ENC_ASCII);
316
317
0
  return fcn_length;
318
0
}
319
320
/* http://docs.mongodb.org/manual/reference/limits/ */
321
/* http://www.mongodb.org/display/DOCS/Documents */
322
0
#define BSON_MAX_NESTING 100
323
0
#define BSON_MAX_DOC_SIZE (16 * 1000 * 1000)
324
static int
325
// NOLINTNEXTLINE(misc-no-recursion)
326
dissect_bson_document(tvbuff_t *tvb, packet_info *pinfo, unsigned offset, proto_tree *tree, int hf_mongo_doc)
327
0
{
328
0
  int32_t document_length;
329
0
  unsigned final_offset;
330
0
  proto_item *ti, *elements, *element, *objectid, *js_code, *js_scope, *machine_id;
331
0
  proto_tree *doc_tree, *elements_tree, *element_sub_tree, *objectid_sub_tree, *js_code_sub_tree, *js_scope_sub_tree, *machine_id_sub_tree;
332
333
0
  document_length = tvb_get_letohl(tvb, offset);
334
335
0
  ti = proto_tree_add_item(tree, hf_mongo_doc, tvb, offset, document_length, ENC_NA);
336
0
  doc_tree = proto_item_add_subtree(ti, ett_mongo_doc);
337
338
0
  proto_tree_add_item(doc_tree, hf_mongo_document_length, tvb, offset, 4, ENC_LITTLE_ENDIAN);
339
340
0
  if (document_length < 5) {
341
0
      expert_add_info_format(pinfo, ti, &ei_mongo_document_length_bad, "BSON document length too short: %u", document_length);
342
0
      return MAX(4, document_length); /* see the comment above */
343
0
  }
344
345
0
  if (document_length > BSON_MAX_DOC_SIZE) {
346
0
      expert_add_info_format(pinfo, ti, &ei_mongo_document_length_bad, "BSON document length too long: %u", document_length);
347
0
      return document_length;
348
0
  }
349
350
0
  if (document_length == 5) {
351
    /* document with length 5 is an empty document */
352
    /* don't display the element subtree */
353
0
    proto_tree_add_item(doc_tree, hf_mongo_document_empty, tvb, offset, document_length, ENC_NA);
354
0
    return document_length;
355
0
  }
356
357
0
  unsigned nest_level = p_get_proto_depth(pinfo, proto_mongo);
358
0
  if (++nest_level > BSON_MAX_NESTING) {
359
0
      expert_add_info_format(pinfo, ti, &ei_mongo_document_recursion_exceeded, "BSON document recursion exceeds %u", BSON_MAX_NESTING);
360
      /* return the number of bytes we consumed, these are at least the 4 bytes for the length field */
361
0
      return MAX(4, document_length);
362
0
  }
363
0
  p_set_proto_depth(pinfo, proto_mongo, nest_level);
364
365
0
  final_offset = offset + document_length;
366
0
  offset += 4;
367
368
0
  elements = proto_tree_add_item(doc_tree, hf_mongo_elements, tvb, offset, document_length-5, ENC_NA);
369
0
  elements_tree = proto_item_add_subtree(elements, ett_mongo_elements);
370
371
0
  do {
372
    /* Read document elements */
373
0
    uint8_t e_type;  /* Element type */
374
0
    unsigned str_len;   /* String length */
375
0
    unsigned e_len;     /* Element length */
376
0
    unsigned doc_len;   /* Document length */
377
378
0
    e_type = tvb_get_uint8(tvb, offset);
379
380
0
    element = proto_tree_add_item_ret_length(elements_tree, hf_mongo_element_name, tvb, offset+1, -1, ENC_UTF_8, &str_len);
381
0
    element_sub_tree = proto_item_add_subtree(element, ett_mongo_element);
382
0
    proto_tree_add_item(element_sub_tree, hf_mongo_element_type, tvb, offset, 1, ENC_LITTLE_ENDIAN);
383
384
0
    offset += str_len+1;
385
386
0
    switch(e_type) {
387
0
      case BSON_ELEMENT_TYPE_DOUBLE:
388
0
        proto_tree_add_item(element_sub_tree, hf_mongo_element_value_double, tvb, offset, 8, ENC_LITTLE_ENDIAN);
389
0
        offset += 8;
390
0
        break;
391
0
      case BSON_ELEMENT_TYPE_STRING:
392
0
      case BSON_ELEMENT_TYPE_JS_CODE:
393
0
      case BSON_ELEMENT_TYPE_SYMBOL:
394
0
        str_len = tvb_get_letohl(tvb, offset);
395
0
        proto_tree_add_item(element_sub_tree, hf_mongo_element_value_string_length, tvb, offset, 4, ENC_LITTLE_ENDIAN);
396
0
        proto_tree_add_item(element_sub_tree, hf_mongo_element_value_string, tvb, offset+4, str_len, ENC_UTF_8);
397
0
        offset += str_len+4;
398
0
        break;
399
0
      case BSON_ELEMENT_TYPE_DOC:
400
0
      case BSON_ELEMENT_TYPE_ARRAY:
401
0
        offset += dissect_bson_document(tvb, pinfo, offset, element_sub_tree, hf_mongo_document);
402
0
        break;
403
0
      case BSON_ELEMENT_TYPE_BINARY:
404
0
        e_len = tvb_get_letohl(tvb, offset);
405
        /* TODO - Add functions to decode various binary subtypes */
406
0
        proto_tree_add_item(element_sub_tree, hf_mongo_element_value_binary_length, tvb, offset, 4, ENC_LITTLE_ENDIAN);
407
0
        proto_tree_add_item(element_sub_tree, hf_mongo_element_value_binary, tvb, offset+5, e_len, ENC_NA);
408
0
        offset += e_len+5;
409
0
        break;
410
0
      case BSON_ELEMENT_TYPE_UNDEF:
411
0
      case BSON_ELEMENT_TYPE_NULL:
412
0
      case BSON_ELEMENT_TYPE_MIN_KEY:
413
0
      case BSON_ELEMENT_TYPE_MAX_KEY:
414
        /* Nothing to do, as there is no element content */
415
0
        break;
416
0
      case BSON_ELEMENT_TYPE_OBJ_ID:
417
0
        objectid = proto_tree_add_item(element_sub_tree, hf_mongo_element_value_objectid, tvb, offset, 12, ENC_NA);
418
0
        objectid_sub_tree = proto_item_add_subtree(objectid, ett_mongo_objectid);
419
        /* Unlike most BSON elements, parts of ObjectID are stored Big Endian, so they can be compared bit by bit */
420
0
        proto_tree_add_item(objectid_sub_tree, hf_mongo_element_value_objectid_time, tvb, offset, 4, ENC_BIG_ENDIAN);
421
        /* The machine ID was traditionally split up in Host Hash/PID */
422
0
        machine_id = proto_tree_add_item(objectid_sub_tree, hf_mongo_element_value_objectid_machine_id, tvb, offset+4, 5, ENC_NA);
423
0
        machine_id_sub_tree = proto_item_add_subtree(machine_id, ett_mongo_machine_id);
424
0
        proto_tree_add_item(machine_id_sub_tree, hf_mongo_element_value_objectid_host, tvb, offset+4, 3, ENC_LITTLE_ENDIAN);
425
0
        proto_tree_add_item(machine_id_sub_tree, hf_mongo_element_value_objectid_pid, tvb, offset+7, 2, ENC_LITTLE_ENDIAN);
426
427
0
        proto_tree_add_item(objectid_sub_tree, hf_mongo_element_value_objectid_inc, tvb, offset+9, 3, ENC_BIG_ENDIAN);
428
0
        offset += 12;
429
0
        break;
430
0
      case BSON_ELEMENT_TYPE_BOOL:
431
0
        proto_tree_add_item(element_sub_tree, hf_mongo_element_value_boolean, tvb, offset, 1, ENC_NA);
432
0
        offset += 1;
433
0
        break;
434
0
      case BSON_ELEMENT_TYPE_REGEX:
435
        /* regex pattern */
436
0
        proto_tree_add_item_ret_length(element_sub_tree, hf_mongo_element_value_regex_pattern, tvb, offset, -1, ENC_UTF_8, &str_len);
437
0
        offset += str_len;
438
        /* regex options */
439
0
        proto_tree_add_item_ret_length(element_sub_tree, hf_mongo_element_value_regex_options, tvb, offset, -1, ENC_UTF_8, &str_len);
440
0
        offset += str_len;
441
0
        break;
442
0
      case BSON_ELEMENT_TYPE_DB_PTR:
443
0
        str_len = tvb_get_letohl(tvb, offset);
444
0
        proto_tree_add_item(element_sub_tree, hf_mongo_element_value_string_length, tvb, offset, 4, ENC_LITTLE_ENDIAN);
445
0
        proto_tree_add_item(element_sub_tree, hf_mongo_element_value_string, tvb, offset+4, str_len, ENC_UTF_8);
446
0
        offset += str_len;
447
0
        proto_tree_add_item(element_sub_tree, hf_mongo_element_value_db_ptr, tvb, offset, 12, ENC_NA);
448
0
        offset += 12;
449
0
        break;
450
0
      case BSON_ELEMENT_TYPE_JS_CODE_SCOPE:
451
        /* code_w_s ::= int32 string document */
452
0
        proto_tree_add_item(element_sub_tree, hf_mongo_element_length, tvb, offset, 4, ENC_LITTLE_ENDIAN);
453
0
        e_len = tvb_get_letohl(tvb, offset);
454
0
        offset += 4;
455
0
        str_len = tvb_get_letohl(tvb, offset);
456
0
        js_code = proto_tree_add_item(element_sub_tree, hf_mongo_element_value_js_code, tvb, offset, str_len+4, ENC_NA);
457
0
        js_code_sub_tree = proto_item_add_subtree(js_code, ett_mongo_code);
458
0
        proto_tree_add_item(js_code_sub_tree, hf_mongo_element_value_string_length, tvb, offset, 4, ENC_LITTLE_ENDIAN);
459
0
        proto_tree_add_item(js_code_sub_tree, hf_mongo_element_value_string, tvb, offset+4, str_len, ENC_UTF_8);
460
0
        offset += str_len+4;
461
0
        doc_len = e_len - (str_len + 8);
462
0
        js_scope = proto_tree_add_item(element_sub_tree, hf_mongo_element_value_js_scope, tvb, offset, doc_len, ENC_NA);
463
0
        js_scope_sub_tree = proto_item_add_subtree(js_scope, ett_mongo_code);
464
0
        offset += dissect_bson_document(tvb, pinfo, offset, js_scope_sub_tree, hf_mongo_document);
465
0
        break;
466
0
      case BSON_ELEMENT_TYPE_INT32:
467
0
        proto_tree_add_item(element_sub_tree, hf_mongo_element_value_int32, tvb, offset, 4, ENC_LITTLE_ENDIAN);
468
0
        offset += 4;
469
0
        break;
470
0
      case BSON_ELEMENT_TYPE_DATETIME:
471
0
      case BSON_ELEMENT_TYPE_TIMESTAMP:
472
        /* TODO Implement routine to convert datetime & timestamp values to UTC date/time */
473
        /* for now, simply display the integer value */
474
0
      case BSON_ELEMENT_TYPE_INT64:
475
0
        proto_tree_add_item(element_sub_tree, hf_mongo_element_value_int64, tvb, offset, 8, ENC_LITTLE_ENDIAN);
476
0
        offset += 8;
477
0
        break;
478
0
      case BSON_ELEMENT_TYPE_DECIMAL128:
479
        /* TODO Implement routine to convert to decimal128 for now, simply display bytes */
480
        /* https://github.com/mongodb/specifications/blob/master/source/bson-decimal128/decimal128.rst */
481
0
        proto_tree_add_item(element_sub_tree, hf_mongo_element_value_decimal128, tvb, offset, 16, ENC_NA);
482
0
        offset += 16;
483
0
        break;
484
0
      default:
485
0
        break;
486
0
    }  /* end switch() */
487
0
  } while (offset < final_offset-1);
488
489
  // Restore depth.
490
0
  nest_level--;
491
0
  p_set_proto_depth(pinfo, proto_mongo, nest_level);
492
493
0
  return document_length;
494
0
}
495
496
/* get_first_bson_field returns the first field of the BSON document. Returned string is NULL terminated. Returns NULL on error. */
497
static uint8_t* get_first_bson_field(tvbuff_t *tvb, packet_info *pinfo, unsigned offset)
498
0
{
499
0
  int32_t document_length = tvb_get_letohl(tvb, offset);
500
501
0
  if (document_length < 5) {
502
0
    return NULL;
503
0
  }
504
505
0
  if (document_length > BSON_MAX_DOC_SIZE) {
506
0
    return NULL;
507
0
  }
508
509
0
  if (document_length == 5) {
510
    /* Empty document. */
511
0
    return NULL;
512
0
  }
513
514
0
  offset += 4;
515
516
  /* Read first document element. Ignore first byte (type) */
517
0
  return tvb_get_stringz_enc(pinfo->pool, tvb, offset+1, NULL /* out length */, ENC_ASCII);
518
0
}
519
520
static int
521
dissect_mongo_reply(tvbuff_t *tvb, packet_info *pinfo, unsigned offset, proto_tree *tree)
522
0
{
523
0
  proto_item *ti;
524
0
  proto_tree *flags_tree;
525
0
  uint32_t i, number_returned;
526
527
0
  ti = proto_tree_add_item(tree, hf_mongo_reply_flags, tvb, offset, 4, ENC_NA);
528
0
  flags_tree = proto_item_add_subtree(ti, ett_mongo_flags);
529
0
  proto_tree_add_item(flags_tree, hf_mongo_reply_flags_cursornotfound, tvb, offset, 4, ENC_LITTLE_ENDIAN);
530
0
  proto_tree_add_item(flags_tree, hf_mongo_reply_flags_queryfailure, tvb, offset, 4, ENC_LITTLE_ENDIAN);
531
0
  proto_tree_add_item(flags_tree, hf_mongo_reply_flags_sharedconfigstale, tvb, offset, 4, ENC_LITTLE_ENDIAN);
532
0
  proto_tree_add_item(flags_tree, hf_mongo_reply_flags_awaitcapable, tvb, offset, 4, ENC_LITTLE_ENDIAN);
533
0
  offset += 4;
534
535
0
  proto_tree_add_item(tree, hf_mongo_cursor_id, tvb, offset, 8, ENC_LITTLE_ENDIAN);
536
0
  offset += 8;
537
538
0
  proto_tree_add_item(tree, hf_mongo_starting_from, tvb, offset, 4, ENC_LITTLE_ENDIAN);
539
0
  offset += 4;
540
541
0
  proto_tree_add_item_ret_uint(tree, hf_mongo_number_returned, tvb, offset, 4, ENC_LITTLE_ENDIAN, &number_returned);
542
0
  offset += 4;
543
544
0
  for (i=0; i < number_returned; i++)
545
0
  {
546
0
    offset += dissect_bson_document(tvb, pinfo, offset, tree, hf_mongo_document);
547
0
  }
548
0
  return offset;
549
0
}
550
551
static int
552
dissect_mongo_msg(tvbuff_t *tvb, unsigned offset, proto_tree *tree)
553
0
{
554
0
  proto_tree_add_item(tree, hf_mongo_message, tvb, offset, -1, ENC_ASCII);
555
0
  offset += tvb_strsize(tvb, offset);
556
557
0
  return offset;
558
0
}
559
560
static int
561
dissect_mongo_update(tvbuff_t *tvb, packet_info *pinfo, unsigned offset, proto_tree *tree)
562
0
{
563
0
  proto_item *ti;
564
0
  proto_tree *flags_tree;
565
566
0
  proto_tree_add_item(tree, hf_mongo_zero, tvb, offset, 4, ENC_NA);
567
0
  offset += 4;
568
569
0
  offset += dissect_fullcollectionname(tvb, offset, tree);
570
571
0
  ti = proto_tree_add_item(tree, hf_mongo_update_flags, tvb, offset, 4, ENC_NA);
572
0
  flags_tree = proto_item_add_subtree(ti, ett_mongo_flags);
573
0
  proto_tree_add_item(flags_tree, hf_mongo_update_flags_upsert, tvb, offset, 4, ENC_LITTLE_ENDIAN);
574
0
  proto_tree_add_item(flags_tree, hf_mongo_update_flags_multiupdate, tvb, offset, 4, ENC_LITTLE_ENDIAN);
575
0
  offset += 4;
576
577
0
  offset += dissect_bson_document(tvb, pinfo, offset, tree, hf_mongo_selector);
578
579
0
  offset += dissect_bson_document(tvb, pinfo, offset, tree, hf_mongo_update);
580
581
0
  return offset;
582
0
}
583
584
static int
585
dissect_mongo_insert(tvbuff_t *tvb, packet_info *pinfo, unsigned offset, proto_tree *tree)
586
0
{
587
0
  proto_item *ti;
588
0
  proto_tree *flags_tree;
589
590
0
  ti = proto_tree_add_item(tree, hf_mongo_insert_flags, tvb, offset, 4, ENC_NA);
591
0
  flags_tree = proto_item_add_subtree(ti, ett_mongo_flags);
592
0
  proto_tree_add_item(flags_tree, hf_mongo_insert_flags_continueonerror, tvb, offset, 4, ENC_LITTLE_ENDIAN);
593
0
  offset += 4;
594
595
0
  offset += dissect_fullcollectionname(tvb, offset, tree);
596
597
0
  while(offset < tvb_reported_length(tvb)) {
598
0
    offset += dissect_bson_document(tvb, pinfo, offset, tree, hf_mongo_document);
599
0
  }
600
601
0
  return offset;
602
0
}
603
604
static int
605
dissect_mongo_query(tvbuff_t *tvb, packet_info *pinfo, unsigned offset, proto_tree *tree, uint8_t **command_name)
606
0
{
607
0
  proto_item *ti;
608
0
  proto_tree *flags_tree;
609
0
  int fullcollectionname_len;
610
0
  bool is_command = false;
611
612
0
  ti = proto_tree_add_item(tree, hf_mongo_query_flags, tvb, offset, 4, ENC_NA);
613
0
  flags_tree = proto_item_add_subtree(ti, ett_mongo_flags);
614
0
  proto_tree_add_item(flags_tree, hf_mongo_query_flags_tailablecursor, tvb, offset, 4, ENC_LITTLE_ENDIAN);
615
0
  proto_tree_add_item(flags_tree, hf_mongo_query_flags_slaveok, tvb, offset, 4, ENC_LITTLE_ENDIAN);
616
0
  proto_tree_add_item(flags_tree, hf_mongo_query_flags_oplogreplay, tvb, offset, 4, ENC_LITTLE_ENDIAN);
617
0
  proto_tree_add_item(flags_tree, hf_mongo_query_flags_nocursortimeout, tvb, offset, 4, ENC_LITTLE_ENDIAN);
618
0
  proto_tree_add_item(flags_tree, hf_mongo_query_flags_awaitdata, tvb, offset, 4, ENC_LITTLE_ENDIAN);
619
0
  proto_tree_add_item(flags_tree, hf_mongo_query_flags_exhaust, tvb, offset, 4, ENC_LITTLE_ENDIAN);
620
0
  proto_tree_add_item(flags_tree, hf_mongo_query_flags_partial, tvb, offset, 4, ENC_LITTLE_ENDIAN);
621
0
  offset += 4;
622
623
0
  fullcollectionname_len = dissect_fullcollectionname(tvb, offset, tree);
624
0
  if (tvb_strneql (tvb, offset, "admin.$cmd", strlen("admin.$cmd") + 1) == 0) {
625
0
    is_command = true;
626
0
  }
627
0
  offset += fullcollectionname_len;
628
629
0
  proto_tree_add_item(tree, hf_mongo_number_to_skip, tvb, offset, 4, ENC_LITTLE_ENDIAN);
630
0
  offset += 4;
631
632
0
  proto_tree_add_item(tree, hf_mongo_number_to_return, tvb, offset, 4, ENC_LITTLE_ENDIAN);
633
0
  offset +=4;
634
635
0
  if (is_command && command_name && *command_name == NULL) {
636
0
    *command_name = get_first_bson_field (tvb, pinfo, offset);
637
0
  }
638
639
0
  offset += dissect_bson_document(tvb, pinfo, offset, tree, hf_mongo_query);
640
641
0
  while(offset < tvb_reported_length(tvb)) {
642
0
    offset += dissect_bson_document(tvb, pinfo, offset, tree, hf_mongo_return_field_selector);
643
0
  }
644
0
  return offset;
645
0
}
646
647
static int
648
dissect_mongo_getmore(tvbuff_t *tvb, unsigned offset, proto_tree *tree)
649
0
{
650
651
0
  proto_tree_add_item(tree, hf_mongo_zero, tvb, offset, 4, ENC_NA);
652
0
  offset += 4;
653
654
0
  offset += dissect_fullcollectionname(tvb, offset, tree);
655
656
0
  proto_tree_add_item(tree, hf_mongo_number_to_return, tvb, offset, 4, ENC_LITTLE_ENDIAN);
657
0
  offset += 4;
658
659
0
  proto_tree_add_item(tree, hf_mongo_cursor_id, tvb, offset, 8, ENC_LITTLE_ENDIAN);
660
0
  offset += 8;
661
662
0
  return offset;
663
0
}
664
665
static int
666
dissect_mongo_delete(tvbuff_t *tvb, packet_info *pinfo, unsigned offset, proto_tree *tree)
667
0
{
668
0
  proto_item *ti;
669
0
  proto_tree *flags_tree;
670
671
0
  proto_tree_add_item(tree, hf_mongo_zero, tvb, offset, 4, ENC_NA);
672
0
  offset += 4;
673
674
0
  offset += dissect_fullcollectionname(tvb, offset, tree);
675
676
0
  ti = proto_tree_add_item(tree, hf_mongo_delete_flags, tvb, offset, 4, ENC_NA);
677
0
  flags_tree = proto_item_add_subtree(ti, ett_mongo_flags);
678
0
  proto_tree_add_item(flags_tree, hf_mongo_delete_flags_singleremove, tvb, offset, 4, ENC_LITTLE_ENDIAN);
679
0
  offset += 4;
680
681
0
  offset += dissect_bson_document(tvb, pinfo, offset, tree, hf_mongo_selector);
682
683
0
  return offset;
684
0
}
685
686
static int
687
dissect_mongo_kill_cursors(tvbuff_t *tvb, unsigned offset, proto_tree *tree)
688
0
{
689
690
0
  proto_tree_add_item(tree, hf_mongo_zero, tvb, offset, 4, ENC_NA);
691
0
  offset += 4;
692
693
0
  proto_tree_add_item(tree, hf_mongo_number_of_cursor_ids, tvb, offset, 4, ENC_LITTLE_ENDIAN);
694
0
  offset += 4;
695
696
0
  while(offset < tvb_reported_length(tvb)) {
697
0
    proto_tree_add_item(tree, hf_mongo_cursor_id, tvb, offset, 8, ENC_LITTLE_ENDIAN);
698
0
    offset +=8;
699
0
  }
700
0
  return offset;
701
0
}
702
703
static int
704
dissect_mongo_op_command(tvbuff_t *tvb, packet_info *pinfo, unsigned offset, proto_tree *tree)
705
0
{
706
0
  int32_t db_length, cmd_length;
707
708
0
  db_length = tvb_strsize(tvb, offset);
709
0
  proto_tree_add_item(tree, hf_mongo_database, tvb, offset, db_length, ENC_ASCII);
710
0
  offset += db_length;
711
712
0
  cmd_length = tvb_strsize(tvb, offset);
713
0
  proto_tree_add_item(tree, hf_mongo_commandname, tvb, offset, cmd_length, ENC_ASCII);
714
0
  offset += cmd_length;
715
716
0
  offset += dissect_bson_document(tvb, pinfo, offset, tree, hf_mongo_metadata);
717
718
0
  offset += dissect_bson_document(tvb, pinfo, offset, tree, hf_mongo_commandargs);
719
720
0
  return offset;
721
0
}
722
723
static int
724
dissect_mongo_op_commandreply(tvbuff_t *tvb, packet_info *pinfo, unsigned offset, proto_tree *tree)
725
0
{
726
727
0
  offset += dissect_bson_document(tvb, pinfo, offset, tree, hf_mongo_metadata);
728
729
0
  offset += dissect_bson_document(tvb, pinfo, offset, tree, hf_mongo_commandreply);
730
731
0
  if (tvb_reported_length_remaining(tvb, offset) > 0){
732
0
    offset += dissect_bson_document(tvb, pinfo, offset, tree, hf_mongo_outputdocs);
733
0
  }
734
735
0
  return offset;
736
0
}
737
738
static int
739
// NOLINTNEXTLINE(misc-no-recursion)
740
dissect_mongo_op_compressed(tvbuff_t *tvb, packet_info *pinfo, unsigned offset, proto_tree *tree, unsigned *effective_opcode, uint8_t **command_name)
741
0
{
742
0
  unsigned opcode = 0;
743
0
  uint8_t compressor;
744
0
  proto_item *ti;
745
0
  proto_tree *compression_info_tree;
746
747
0
  ti = proto_tree_add_item(tree, hf_mongo_compression_info, tvb, offset, 9, ENC_NA);
748
0
  compression_info_tree = proto_item_add_subtree(ti, ett_mongo_compression_info);
749
0
  proto_tree_add_item(compression_info_tree, hf_mongo_original_op_code, tvb, offset, 4, ENC_LITTLE_ENDIAN);
750
0
  proto_tree_add_item(compression_info_tree, hf_mongo_uncompressed_size, tvb, offset + 4, 4, ENC_LITTLE_ENDIAN);
751
0
  proto_tree_add_item(compression_info_tree, hf_mongo_compressor, tvb, offset + 8, 1, ENC_NA);
752
0
  proto_tree_add_item(compression_info_tree, hf_mongo_compressed_data, tvb, offset + 9, -1, ENC_NA);
753
754
0
  opcode = tvb_get_letohl(tvb, offset);
755
0
  *effective_opcode = opcode;
756
0
  compressor = tvb_get_uint8(tvb, offset + 8);
757
0
  offset += 9;
758
759
0
  switch(compressor) {
760
0
  case MONGO_COMPRESSOR_NOOP:
761
0
    offset = dissect_opcode_types(tvb, pinfo, offset, tree, opcode, effective_opcode, command_name);
762
0
    break;
763
764
#ifdef HAVE_SNAPPY
765
  case MONGO_COMPRESSOR_SNAPPY: {
766
    tvbuff_t* uncompressed_tvb = tvb_child_uncompress_snappy(tvb, tvb, offset, tvb_captured_length_remaining(tvb, offset));
767
    if (uncompressed_tvb) {
768
        add_new_data_source(pinfo, uncompressed_tvb, "Decompressed Data");
769
770
        dissect_opcode_types(uncompressed_tvb, pinfo, 0, tree, opcode, effective_opcode, command_name);
771
    } else {
772
      expert_add_info_format(pinfo, ti, &ei_mongo_unsupported_compression, "Error uncompressing snappy data");
773
    }
774
775
    offset = tvb_reported_length(tvb);
776
  } break;
777
#endif
778
779
#ifdef HAVE_ZSTD
780
  case MONGO_COMPRESSOR_ZSTD:
781
  {
782
    tvbuff_t *uncompressed_tvb = tvb_child_uncompress_zstd (tvb, tvb, offset, tvb_captured_length_remaining (tvb, offset));
783
    if (!uncompressed_tvb) {
784
      expert_add_info_format(pinfo, ti, &ei_mongo_unsupported_compression, "Error uncompressing zstd data");
785
    } else {
786
      add_new_data_source(pinfo, uncompressed_tvb, "Decompressed Data");
787
      dissect_opcode_types(uncompressed_tvb, pinfo, 0, tree, opcode, effective_opcode, command_name);
788
    }
789
790
    offset = tvb_reported_length(tvb);
791
  }
792
  break;
793
#endif
794
795
0
  case MONGO_COMPRESSOR_ZLIB: {
796
0
    tvbuff_t* compressed_tvb = tvb_child_uncompress_zlib(tvb, tvb, offset, tvb_captured_length_remaining(tvb, offset));
797
798
0
    if (compressed_tvb) {
799
0
      add_new_data_source(pinfo, compressed_tvb, "Decompressed Data");
800
801
0
      dissect_opcode_types(compressed_tvb, pinfo, 0, tree, opcode, effective_opcode, command_name);
802
0
    } else {
803
0
      proto_tree_add_item(compression_info_tree, hf_mongo_unsupported_compressed, tvb, offset, -1, ENC_NA);
804
0
      expert_add_info_format(pinfo, ti, &ei_mongo_unsupported_compression, "Error uncompressing zlib data");
805
0
    }
806
807
0
    offset = tvb_reported_length(tvb);
808
0
  } break;
809
810
0
  default:
811
0
    proto_tree_add_item(compression_info_tree, hf_mongo_unsupported_compressed, tvb, offset, -1, ENC_NA);
812
0
    expert_add_info_format(pinfo, ti, &ei_mongo_unsupported_compression, "Unsupported compression format: %d", compressor);
813
0
    offset = tvb_reported_length(tvb);
814
0
    break;
815
0
  }
816
817
0
  return offset;
818
0
}
819
820
static int
821
dissect_op_msg_section(tvbuff_t *tvb, packet_info *pinfo, unsigned offset, proto_tree *tree, uint8_t **command_name)
822
0
{
823
0
  proto_item *ti;
824
0
  proto_tree *section_tree;
825
0
  uint8_t e_type;
826
0
  int section_len = -1;   /* Section length */
827
828
0
  e_type = tvb_get_uint8(tvb, offset);
829
830
0
  ti = proto_tree_add_item(tree, hf_mongo_msg_sections_section, tvb, offset, 1, ENC_NA);
831
0
  section_tree = proto_item_add_subtree(ti, ett_mongo_section);
832
0
  proto_tree_add_item(section_tree, hf_mongo_msg_sections_section_kind, tvb, offset, 1, ENC_LITTLE_ENDIAN);
833
0
  offset += 1;
834
835
0
  section_len = tvb_get_letohil(tvb, offset);
836
  /* The section length must be strictly smaller than the total message size,
837
   * both signed int32s. This prevents signed integer overflow. */
838
0
  if (section_len < 0 || section_len >= (INT32_MAX-1)) {
839
0
    proto_tree_add_expert_format(section_tree, pinfo, &ei_mongo_section_size_bad, tvb, offset, 4, "Bogus Mongo message section size: %i", section_len);
840
0
    THROW(ReportedBoundsError);
841
0
  }
842
0
  proto_item_set_len(ti, 1 + section_len);
843
844
0
  switch (e_type) {
845
0
    case KIND_BODY:
846
0
      section_len = dissect_bson_document(tvb, pinfo, offset, section_tree, hf_mongo_msg_sections_section_body);
847
      /* If section_len is bogus (e.g., negative), dissect_bson_document sets
848
       * an expert info and can return a different value than read above.
849
       */
850
0
      if (command_name && *command_name == NULL) {
851
0
        *command_name = get_first_bson_field (tvb, pinfo, offset);
852
0
      }
853
0
      break;
854
0
    case KIND_DOCUMENT_SEQUENCE: {
855
0
      int32_t dsi_length;
856
0
      int32_t to_read = section_len;
857
0
      proto_item *documents;
858
0
      proto_tree *documents_tree;
859
860
0
      proto_tree_add_item(section_tree, hf_mongo_msg_sections_section_size, tvb, offset, 4, ENC_LITTLE_ENDIAN);
861
      /* This is redundant with the lengths in the documents, we don't use this
862
       * size at all. We could still report an expert info if it's bogus.
863
       */
864
0
      offset += 4;
865
0
      to_read -= 4;
866
867
0
      dsi_length = tvb_strsize(tvb, offset);
868
0
      proto_tree_add_item(section_tree, hf_mongo_msg_sections_section_doc_sequence_id, tvb, offset, dsi_length, ENC_ASCII);
869
0
      offset += dsi_length;
870
0
      to_read -= dsi_length;
871
872
0
      documents = proto_tree_add_item(section_tree, hf_mongo_msg_sections_section_doc_sequence, tvb, offset, to_read, ENC_NA);
873
0
      documents_tree = proto_item_add_subtree(documents, ett_mongo_doc_sequence);
874
875
0
      while (to_read > 0){
876
0
        int32_t doc_size = dissect_bson_document(tvb, pinfo, offset, documents_tree, hf_mongo_document);
877
0
        to_read -= doc_size;
878
0
        offset += doc_size;
879
0
      }
880
881
0
    } break;
882
0
    default:
883
0
      expert_add_info_format(pinfo, tree, &ei_mongo_unknown, "Unknown section type: %u", e_type);
884
0
  }
885
886
0
  return 1 + section_len;
887
0
}
888
889
static int
890
dissect_mongo_op_msg(tvbuff_t *tvb, packet_info *pinfo, unsigned offset, proto_tree *tree, uint8_t **command_name)
891
0
{
892
0
  static int * const mongo_msg_flags[] = {
893
0
    &hf_mongo_msg_flags_checksumpresent,
894
0
    &hf_mongo_msg_flags_moretocome,
895
0
    &hf_mongo_msg_flags_exhaustallowed,
896
0
    NULL
897
0
  };
898
0
  uint64_t op_msg_flags;
899
0
  bool checksum_present = false;
900
901
0
  proto_tree_add_bitmask_ret_uint64 (tree, tvb, offset, hf_mongo_msg_flags, ett_mongo_msg_flags, mongo_msg_flags, ENC_LITTLE_ENDIAN, &op_msg_flags);
902
0
  if (op_msg_flags & 0x00000001) {
903
0
    checksum_present = true;
904
0
  }
905
906
0
  offset += 4;
907
908
0
  while (tvb_reported_length_remaining(tvb, offset) > (checksum_present ? 4U : 0U)){
909
0
    offset += dissect_op_msg_section(tvb, pinfo, offset, tree, command_name);
910
0
  }
911
912
0
  if (checksum_present) {
913
0
    uint32_t calculated_checksum = ~crc32c_tvb_offset_calculate (tvb, 0, tvb_reported_length (tvb) - 4, CRC32C_PRELOAD);
914
0
    proto_tree_add_checksum(tree, tvb, offset, hf_mongo_msg_checksum, hf_mongo_msg_checksum_status, &ei_mongo_msg_checksum, pinfo, calculated_checksum, ENC_BIG_ENDIAN, PROTO_CHECKSUM_VERIFY);
915
0
    offset += 4;
916
0
  }
917
918
0
  return offset;
919
0
}
920
921
static int
922
// NOLINTNEXTLINE(misc-no-recursion)
923
dissect_opcode_types(tvbuff_t *tvb, packet_info *pinfo, unsigned offset, proto_tree *mongo_tree, unsigned opcode, unsigned *effective_opcode, uint8_t **command_name)
924
0
{
925
0
    *effective_opcode = opcode;
926
927
0
    unsigned recursion_depth = p_get_proto_depth(pinfo, proto_mongo);
928
0
    DISSECTOR_ASSERT(recursion_depth <= BSON_MAX_NESTING);
929
0
    p_set_proto_depth(pinfo, proto_mongo, recursion_depth + 1);
930
931
0
    switch(opcode){
932
0
    case OP_REPLY:
933
0
      offset = dissect_mongo_reply(tvb, pinfo, offset, mongo_tree);
934
0
      break;
935
0
    case OP_MESSAGE:
936
0
      offset = dissect_mongo_msg(tvb, offset, mongo_tree);
937
0
      break;
938
0
    case OP_UPDATE:
939
0
      offset = dissect_mongo_update(tvb, pinfo, offset, mongo_tree);
940
0
      break;
941
0
    case OP_INSERT:
942
0
      offset = dissect_mongo_insert(tvb, pinfo, offset, mongo_tree);
943
0
      break;
944
0
    case OP_QUERY:
945
0
      offset = dissect_mongo_query(tvb, pinfo, offset, mongo_tree, command_name);
946
0
      break;
947
0
    case OP_GET_MORE:
948
0
      offset = dissect_mongo_getmore(tvb, offset, mongo_tree);
949
0
      break;
950
0
    case OP_DELETE:
951
0
      offset = dissect_mongo_delete(tvb, pinfo, offset, mongo_tree);
952
0
      break;
953
0
    case OP_KILL_CURSORS:
954
0
      offset = dissect_mongo_kill_cursors(tvb, offset, mongo_tree);
955
0
      break;
956
0
    case OP_COMMAND:
957
0
      offset = dissect_mongo_op_command(tvb, pinfo, offset, mongo_tree);
958
0
      break;
959
0
    case OP_COMMANDREPLY:
960
0
      offset = dissect_mongo_op_commandreply(tvb, pinfo, offset, mongo_tree);
961
0
      break;
962
0
    case OP_COMPRESSED:
963
0
      offset = dissect_mongo_op_compressed(tvb, pinfo, offset, mongo_tree, effective_opcode, command_name);
964
0
      break;
965
0
    case OP_MSG:
966
0
      offset = dissect_mongo_op_msg(tvb, pinfo, offset, mongo_tree, command_name);
967
0
      break;
968
0
    default:
969
      /* No default Action */
970
0
      break;
971
0
    }
972
973
0
    p_set_proto_depth(pinfo, proto_mongo, recursion_depth);
974
975
0
    return offset;
976
0
}
977
978
static int
979
dissect_mongo_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_)
980
0
{
981
0
    proto_item *ti;
982
0
    proto_tree *mongo_tree;
983
0
    unsigned offset = 0, opcode, effective_opcode = 0;
984
0
    uint32_t response_to;
985
0
    uint8_t *command_name = NULL;
986
987
0
    col_set_str(pinfo->cinfo, COL_PROTOCOL, "MONGO");
988
989
0
    ti = proto_tree_add_item(tree, proto_mongo, tvb, 0, -1, ENC_NA);
990
991
0
    mongo_tree = proto_item_add_subtree(ti, ett_mongo);
992
993
0
    proto_tree_add_item(mongo_tree, hf_mongo_message_length, tvb, offset, 4, ENC_LITTLE_ENDIAN);
994
0
    offset += 4;
995
996
0
    proto_tree_add_item(mongo_tree, hf_mongo_request_id, tvb, offset, 4, ENC_LITTLE_ENDIAN);
997
0
    offset += 4;
998
999
0
    proto_tree_add_item_ret_uint(mongo_tree, hf_mongo_response_to, tvb, offset, 4, ENC_LITTLE_ENDIAN, &response_to);
1000
0
    offset += 4;
1001
1002
0
    proto_tree_add_item(mongo_tree, hf_mongo_op_code, tvb, offset, 4, ENC_LITTLE_ENDIAN);
1003
0
    opcode = tvb_get_letohl(tvb, offset);
1004
0
    offset += 4;
1005
1006
0
    offset = dissect_opcode_types(tvb, pinfo, offset, mongo_tree, opcode, &effective_opcode, &command_name);
1007
1008
0
    if (opcode == 1 || response_to != 0)
1009
0
    {
1010
0
      col_set_str(pinfo->cinfo, COL_INFO, "Response :");
1011
0
    }
1012
0
    else
1013
0
    {
1014
0
      col_set_str(pinfo->cinfo, COL_INFO, "Request :");
1015
1016
0
    }
1017
0
    col_append_fstr(pinfo->cinfo, COL_INFO, " %s", val_to_str_const(effective_opcode, opcode_vals, "Unknown"));
1018
1019
0
    if(opcode != effective_opcode) {
1020
0
      col_append_str(pinfo->cinfo, COL_INFO, " (Compressed)");
1021
0
    }
1022
1023
0
    if (opcode != 1 && response_to == 0 && command_name) {
1024
0
      col_append_fstr(pinfo->cinfo, COL_INFO, " (%s)", (char*) command_name);
1025
0
    }
1026
1027
0
    if(offset < tvb_reported_length(tvb))
1028
0
    {
1029
0
      ti = proto_tree_add_item(mongo_tree, hf_mongo_unknown, tvb, offset, -1, ENC_NA);
1030
0
      expert_add_info(pinfo, ti, &ei_mongo_unknown);
1031
0
    }
1032
1033
0
    return tvb_captured_length(tvb);
1034
0
}
1035
static unsigned
1036
get_mongo_pdu_len(packet_info *pinfo _U_, tvbuff_t *tvb, int offset, void *data _U_)
1037
0
{
1038
0
  uint32_t plen;
1039
1040
  /*
1041
  * Get the length of the MONGO packet.
1042
  */
1043
0
  plen = tvb_get_letohl(tvb, offset);
1044
  /* XXX - This is signed, but we can only return an unsigned to
1045
   * tcp_dissect_pdus. If negative, should we return something like
1046
   * 1 (less than the fixed len 4) so that it causes a ReportedBoundsError?
1047
   */
1048
1049
0
  return plen;
1050
0
}
1051
1052
static int
1053
dissect_mongo(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data)
1054
0
{
1055
0
  tcp_dissect_pdus(tvb, pinfo, tree, 1, 4, get_mongo_pdu_len, dissect_mongo_pdu, data);
1056
0
  return tvb_captured_length(tvb);
1057
0
}
1058
1059
static bool
1060
test_mongo(packet_info *pinfo _U_, tvbuff_t *tvb, int offset, void *data _U_)
1061
1
{
1062
1
  uint32_t opcode;
1063
1064
1
  if (tvb_captured_length_remaining(tvb, offset) < 16) {
1065
0
    return false;
1066
0
  }
1067
1068
1
  if (tvb_get_letohil(tvb, offset) < 4) {
1069
    /* Message sizes are signed in the MongoDB Wire Protocol and
1070
     * include the header.
1071
     */
1072
1
    return false;
1073
1
  }
1074
1075
0
  opcode = tvb_get_letohl(tvb, offset + 12);
1076
  /* As 5.1 and later uses only 2 opcodes, we might be able to use that
1077
   * (plus some other information) to do heuristics on other ports.
1078
   */
1079
0
  return (try_val_to_str(opcode, opcode_vals) != NULL);
1080
1
}
1081
1082
static int
1083
dissect_mongo_tcp_heur(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data)
1084
1
{
1085
1
  if (!test_mongo(pinfo, tvb, 0, data)) {
1086
1
    return 0;
1087
    /* The TLS heuristic dissector should catch this if over TLS. */
1088
1
  }
1089
0
  conversation_t *conversation = find_or_create_conversation(pinfo);
1090
0
  conversation_set_dissector(conversation, mongo_handle);
1091
1092
0
  return dissect_mongo(tvb, pinfo, tree, data);
1093
1
}
1094
1095
void
1096
proto_register_mongo(void)
1097
16
{
1098
16
  expert_module_t* expert_mongo;
1099
1100
16
  static hf_register_info hf[] = {
1101
16
    { &hf_mongo_message_length,
1102
16
      { "Message Length", "mongo.message_length",
1103
16
      FT_INT32, BASE_DEC, NULL, 0x0,
1104
16
      "Total message size (including header)", HFILL }
1105
16
    },
1106
16
    { &hf_mongo_request_id,
1107
16
      { "Request ID", "mongo.request_id",
1108
16
      FT_UINT32, BASE_HEX_DEC, NULL, 0x0,
1109
16
      "Identifier for this message", HFILL }
1110
16
    },
1111
16
    { &hf_mongo_response_to,
1112
16
      { "Response To", "mongo.response_to",
1113
16
      FT_UINT32, BASE_HEX_DEC, NULL, 0x0,
1114
16
      "RequestID from the original request", HFILL }
1115
16
    },
1116
16
    { &hf_mongo_op_code,
1117
16
      { "OpCode", "mongo.opcode",
1118
16
      FT_INT32, BASE_DEC, VALS(opcode_vals), 0x0,
1119
16
      "Type of request message", HFILL }
1120
16
    },
1121
16
    { &hf_mongo_query_flags,
1122
16
      { "Query Flags", "mongo.query.flags",
1123
16
      FT_NONE, BASE_NONE, NULL, 0x0,
1124
16
      "Bit vector of query options.", HFILL }
1125
16
    },
1126
16
    { &hf_mongo_fullcollectionname,
1127
16
      { "fullCollectionName", "mongo.full_collection_name",
1128
16
      FT_STRINGZ, BASE_NONE, NULL, 0x0,
1129
16
      "The full collection name is the concatenation of the database name with the"
1130
16
        " collection name, using a dot for the concatenation", HFILL }
1131
16
    },
1132
16
    { &hf_mongo_database_name,
1133
16
      { "Database Name", "mongo.database_name",
1134
16
      FT_STRING, BASE_NONE, NULL, 0x0,
1135
16
      NULL, HFILL }
1136
16
    },
1137
16
    { &hf_mongo_collection_name,
1138
16
      { "Collection Name", "mongo.collection_name",
1139
16
      FT_STRING, BASE_NONE, NULL, 0x0,
1140
16
      NULL, HFILL }
1141
16
    },
1142
16
    { &hf_mongo_reply_flags,
1143
16
      { "Reply Flags", "mongo.reply.flags",
1144
16
      FT_NONE, BASE_NONE, NULL, 0x0,
1145
16
      "Bit vector of reply options.", HFILL }
1146
16
    },
1147
16
    { &hf_mongo_reply_flags_cursornotfound,
1148
16
      { "Cursor Not Found", "mongo.reply.flags.cursornotfound",
1149
16
      FT_BOOLEAN, 32, TFS(&tfs_yes_no), 0x00000001,
1150
16
      "Set when getMore is called but the cursor id is not valid at the server", HFILL }
1151
16
    },
1152
16
    { &hf_mongo_reply_flags_queryfailure,
1153
16
      { "Query Failure", "mongo.reply.flags.queryfailure",
1154
16
      FT_BOOLEAN, 32, TFS(&tfs_yes_no), 0x00000002,
1155
16
      "Set when query failed. Results consist of one document containing an $err"
1156
16
        " field describing the failure.", HFILL }
1157
16
    },
1158
16
    { &hf_mongo_reply_flags_sharedconfigstale,
1159
16
      { "Shared Config Stale", "mongo.reply.flags.sharedconfigstale",
1160
16
      FT_BOOLEAN, 32, TFS(&tfs_yes_no), 0x00000004,
1161
16
      NULL, HFILL }
1162
16
    },
1163
16
    { &hf_mongo_reply_flags_awaitcapable,
1164
16
      { "Await Capable", "mongo.reply.flags.awaitcapable",
1165
16
      FT_BOOLEAN, 32, TFS(&tfs_yes_no), 0x00000008,
1166
16
      "Set when the server supports the AwaitData Query option", HFILL }
1167
16
    },
1168
16
    { &hf_mongo_message,
1169
16
      { "Message", "mongo.message",
1170
16
      FT_STRINGZ, BASE_NONE, NULL, 0x0,
1171
16
      "Message for the database", HFILL }
1172
16
    },
1173
16
    { &hf_mongo_cursor_id,
1174
16
      { "Cursor ID", "mongo.cursor_id",
1175
16
      FT_INT64, BASE_DEC, NULL, 0x0,
1176
16
      "Cursor id if client needs to do get more's", HFILL }
1177
16
    },
1178
16
    { &hf_mongo_starting_from,
1179
16
      { "Starting From", "mongo.starting_from",
1180
16
      FT_INT32, BASE_DEC, NULL, 0x0,
1181
16
      "Where in the cursor this reply is starting", HFILL }
1182
16
    },
1183
16
    { &hf_mongo_number_returned,
1184
16
      { "Number Returned", "mongo.number_returned",
1185
16
      FT_UINT32, BASE_DEC, NULL, 0x0,
1186
16
      "Number of documents in the reply", HFILL }
1187
16
    },
1188
16
    { &hf_mongo_document,
1189
16
      { "Document", "mongo.document",
1190
16
      FT_NONE, BASE_NONE, NULL, 0x0,
1191
16
      NULL, HFILL }
1192
16
    },
1193
16
    { &hf_mongo_document_length,
1194
16
      { "Document length", "mongo.document.length",
1195
16
      FT_INT32, BASE_DEC, NULL, 0x0,
1196
16
      "Length of BSON Document", HFILL }
1197
16
    },
1198
16
    { &hf_mongo_document_empty,
1199
16
      { "Empty Document", "mongo.document.empty",
1200
16
      FT_NONE, BASE_NONE, NULL, 0x0,
1201
16
      "Document with no elements", HFILL }
1202
16
    },
1203
16
    { &hf_mongo_zero,
1204
16
      { "Zero", "mongo.document.zero",
1205
16
      FT_BYTES, BASE_NONE, NULL, 0x0,
1206
16
      "Reserved (Must be is Zero)", HFILL }
1207
16
    },
1208
16
    { &hf_mongo_update_flags,
1209
16
      { "Update Flags", "mongo.update.flags",
1210
16
      FT_NONE, BASE_NONE, NULL, 0x0,
1211
16
      "Bit vector of update options.", HFILL }
1212
16
    },
1213
16
    { &hf_mongo_update_flags_upsert,
1214
16
      { "Upsert", "mongo.update.flags.upsert",
1215
16
      FT_BOOLEAN, 32, TFS(&tfs_yes_no), 0x00000001,
1216
16
      "If set, the database will insert the supplied object into the collection if no"
1217
16
        " matching document is found", HFILL }
1218
16
    },
1219
16
    { &hf_mongo_update_flags_multiupdate,
1220
16
      { "Multi Update", "mongo.update.flags.multiupdate",
1221
16
      FT_BOOLEAN, 32, TFS(&tfs_yes_no), 0x00000002,
1222
16
      "If set, the database will update all matching objects in the collection."
1223
16
        " Otherwise only updates first matching doc.", HFILL }
1224
16
    },
1225
16
    { &hf_mongo_selector,
1226
16
      { "Selector", "mongo.selector",
1227
16
      FT_NONE, BASE_NONE, NULL, 0x0,
1228
16
      "The query to select the document", HFILL }
1229
16
    },
1230
16
    { &hf_mongo_update,
1231
16
      { "Update", "mongo.update",
1232
16
      FT_NONE, BASE_NONE, NULL, 0x0,
1233
16
      "Specification of the update to perform", HFILL }
1234
16
    },
1235
16
    { &hf_mongo_insert_flags,
1236
16
      { "Insert Flags", "mongo.insert.flags",
1237
16
      FT_NONE, BASE_NONE, NULL, 0x0,
1238
16
      "Bit vector of insert options.", HFILL }
1239
16
    },
1240
16
    { &hf_mongo_insert_flags_continueonerror,
1241
16
      { "ContinueOnError", "mongo.insert.flags.continueonerror",
1242
16
      FT_BOOLEAN, 32, TFS(&tfs_yes_no), 0x00000001,
1243
16
      "If set, the database will not stop processing a bulk insert if one fails"
1244
16
        " (eg due to duplicate IDs)", HFILL }
1245
16
    },
1246
16
    { &hf_mongo_query_flags_tailablecursor,
1247
16
      { "Tailable Cursor", "mongo.query.flags.tailable_cursor",
1248
16
      FT_BOOLEAN, 32, TFS(&tfs_yes_no), 0x00000002,
1249
16
      "Tailable means cursor is not closed when the last data is retrieved", HFILL }
1250
16
    },
1251
16
    { &hf_mongo_query_flags_slaveok,
1252
16
      { "Slave OK", "mongo.query.flags.slave_ok",
1253
16
      FT_BOOLEAN, 32, TFS(&tfs_yes_no), 0x00000004,
1254
16
      "Allow query of replica slave", HFILL }
1255
16
    },
1256
16
    { &hf_mongo_query_flags_oplogreplay,
1257
16
      { "Op Log Reply", "mongo.query.flags.op_log_reply",
1258
16
      FT_BOOLEAN, 32, TFS(&tfs_yes_no), 0x00000008,
1259
16
      "Internal replication use only", HFILL }
1260
16
    },
1261
16
    { &hf_mongo_query_flags_nocursortimeout,
1262
16
      { "No Cursor Timeout", "mongo.query.flags.no_cursor_timeout",
1263
16
      FT_BOOLEAN, 32, TFS(&tfs_yes_no), 0x00000010,
1264
16
      "The server normally times out idle cursors after an inactivity period (10 minutes)"
1265
16
        " to prevent excess memory use. Set this option to prevent that", HFILL }
1266
16
    },
1267
16
    { &hf_mongo_query_flags_awaitdata,
1268
16
      { "AwaitData", "mongo.query.flags.awaitdata",
1269
16
      FT_BOOLEAN, 32, TFS(&tfs_yes_no), 0x00000020,
1270
16
      "If we are at the end of the data, block for a while rather than returning no data."
1271
16
        " After a timeout period, we do return as normal", HFILL }
1272
16
    },
1273
16
    { &hf_mongo_query_flags_exhaust,
1274
16
      { "Exhaust", "mongo.query.flags.exhaust",
1275
16
      FT_BOOLEAN, 32, TFS(&tfs_yes_no), 0x00000040,
1276
16
      "Stream the data down full blast in multiple more packages, on the assumption"
1277
16
        " that the client will fully read all data queried", HFILL }
1278
16
    },
1279
16
    { &hf_mongo_query_flags_partial,
1280
16
      { "Partial", "mongo.query.flags.partial",
1281
16
      FT_BOOLEAN, 32, TFS(&tfs_yes_no), 0x00000080,
1282
16
      "Get partial results from a mongos if some shards are down (instead of throwing an error)", HFILL }
1283
16
    },
1284
16
    { &hf_mongo_number_to_skip,
1285
16
      { "Number To Skip", "mongo.number_to_skip",
1286
16
      FT_INT32, BASE_DEC, NULL, 0x0,
1287
16
      "Number of documents in the skip", HFILL }
1288
16
    },
1289
16
    { &hf_mongo_number_to_return,
1290
16
      { "Number to Return", "mongo.number_to_return",
1291
16
      FT_INT32, BASE_DEC, NULL, 0x0,
1292
16
      "Number of documents in the return", HFILL }
1293
16
    },
1294
16
    { &hf_mongo_query,
1295
16
      { "Query", "mongo.query",
1296
16
      FT_NONE, BASE_NONE, NULL, 0x0,
1297
16
      "Query BSON Document", HFILL }
1298
16
    },
1299
16
    { &hf_mongo_return_field_selector,
1300
16
      { "Return Field Selector", "mongo.return_field_selector",
1301
16
      FT_NONE, BASE_NONE, NULL, 0x0,
1302
16
      "Return Field Selector BSON Document", HFILL }
1303
16
    },
1304
16
    { &hf_mongo_delete_flags,
1305
16
      { "Delete Flags", "mongo.delete.flags",
1306
16
      FT_NONE, BASE_NONE, NULL, 0x0,
1307
16
      "Bit vector of delete options.", HFILL }
1308
16
    },
1309
16
    { &hf_mongo_delete_flags_singleremove,
1310
16
      { "Single Remove", "mongo.delete.flags.singleremove",
1311
16
      FT_BOOLEAN, 32, TFS(&tfs_yes_no), 0x00000001,
1312
16
      "If set, the database will remove only the first matching document in the"
1313
16
        " collection. Otherwise all matching documents will be removed", HFILL }
1314
16
    },
1315
16
    { &hf_mongo_compression_info,
1316
16
      { "Compression Info", "mongo.compression",
1317
16
      FT_NONE, BASE_NONE, NULL, 0x0,
1318
16
      "Compressed Packet", HFILL }
1319
16
    },
1320
16
    { &hf_mongo_original_op_code,
1321
16
      { "Original OpCode", "mongo.compression.original_opcode",
1322
16
      FT_INT32, BASE_DEC, VALS(opcode_vals), 0x0,
1323
16
      "Type of request message (Wrapped)", HFILL }
1324
16
    },
1325
16
    { &hf_mongo_uncompressed_size,
1326
16
      { "Uncompressed Size", "mongo.compression.original_size",
1327
16
      FT_INT32, BASE_DEC, NULL, 0x0,
1328
16
      "Size of the uncompressed packet", HFILL }
1329
16
    },
1330
16
    { &hf_mongo_compressor,
1331
16
      { "Compressor", "mongo.compression.compressor",
1332
16
      FT_INT8, BASE_DEC, VALS(compressor_vals), 0x0,
1333
16
      "Compression engine", HFILL }
1334
16
    },
1335
16
    { &hf_mongo_compressed_data,
1336
16
      { "Compressed Data", "mongo.compression.compressed_data",
1337
16
      FT_NONE, BASE_NONE, NULL, 0x0,
1338
16
      "The compressed data", HFILL }
1339
16
    },
1340
16
    { &hf_mongo_unsupported_compressed,
1341
16
      { "Unsupported Compressed Data", "mongo.compression.unsupported_compressed",
1342
16
      FT_NONE, BASE_NONE, NULL, 0x0,
1343
16
      "This data is compressed with an unsupported compressor engine", HFILL }
1344
16
    },
1345
16
    { &hf_mongo_msg_flags,
1346
16
      { "Message Flags", "mongo.msg.flags",
1347
16
      FT_UINT32, BASE_HEX, NULL, 0x0,
1348
16
      "Bit vector of msg options.", HFILL }
1349
16
    },
1350
16
    { &hf_mongo_msg_flags_checksumpresent,
1351
16
      { "ChecksumPresent", "mongo.msg.flags.checksumpresent",
1352
16
      FT_BOOLEAN, 32, TFS(&tfs_yes_no), 0x00000001,
1353
16
      "The message ends with 4 bytes containing a CRC-32C [1] checksum", HFILL }
1354
16
    },
1355
16
    { &hf_mongo_msg_flags_moretocome,
1356
16
      { "MoreToCome", "mongo.msg.flags.moretocome",
1357
16
      FT_BOOLEAN, 32, TFS(&tfs_yes_no), 0x00000002,
1358
16
      "Another message will follow this one without further action from the receiver", HFILL }
1359
16
    },
1360
16
    { &hf_mongo_msg_flags_exhaustallowed,
1361
16
      { "ExhaustAllowed", "mongo.msg.flags.exhaustallowed",
1362
16
      FT_BOOLEAN, 32, TFS(&tfs_yes_no), 0x00010000,
1363
16
      "The client is prepared for multiple replies to this request using the moreToCome bit.", HFILL }
1364
16
    },
1365
16
    { &hf_mongo_msg_sections_section,
1366
16
      { "Section", "mongo.msg.sections.section",
1367
16
      FT_NONE, BASE_NONE, NULL, 0x0,
1368
16
      NULL, HFILL }
1369
16
    },
1370
16
    { &hf_mongo_msg_sections_section_kind,
1371
16
      { "Kind", "mongo.msg.sections.section.kind",
1372
16
      FT_INT32, BASE_DEC, VALS(section_kind_vals), 0x0,
1373
16
      "Type of section", HFILL }
1374
16
    },
1375
16
    { &hf_mongo_msg_sections_section_body,
1376
16
      { "BodyDocument", "mongo.msg.sections.section.body",
1377
16
      FT_NONE, BASE_NONE, NULL, 0x0,
1378
16
      NULL, HFILL }
1379
16
    },
1380
16
    { &hf_mongo_msg_sections_section_doc_sequence,
1381
16
      { "DocumentSequence", "mongo.msg.sections.section.doc_sequence",
1382
16
      FT_NONE, BASE_NONE, NULL, 0x0,
1383
16
      NULL, HFILL }
1384
16
    },
1385
16
    { &hf_mongo_msg_sections_section_size,
1386
16
      { "Size", "mongo.msg.sections.section.size",
1387
16
      FT_INT32, BASE_DEC, NULL, 0x0,
1388
16
      "Size (in bytes) of document sequence", HFILL }
1389
16
    },
1390
16
    { &hf_mongo_msg_sections_section_doc_sequence_id,
1391
16
      { "SeqID", "mongo.msg.sections.section.doc_sequence_id",
1392
16
      FT_STRING, BASE_NONE, NULL, 0x0,
1393
16
      "Document sequence identifier", HFILL }
1394
16
    },
1395
16
    { &hf_mongo_msg_checksum,
1396
16
      { "Checksum", "mongo.msg.checksum",
1397
16
      FT_UINT32, BASE_HEX, NULL, 0x0,
1398
16
      "CRC32C checksum.", HFILL }
1399
16
    },
1400
16
    { &hf_mongo_msg_checksum_status,
1401
16
      { "Checksum Status", "mongo.msg.checksum.status",
1402
16
      FT_UINT8, BASE_NONE, VALS(proto_checksum_vals), 0x0,
1403
16
      NULL, HFILL }
1404
16
    },
1405
16
    { &hf_mongo_number_of_cursor_ids,
1406
16
      { "Number of Cursor IDS", "mongo.number_to_cursor_ids",
1407
16
      FT_INT32, BASE_DEC, NULL, 0x0,
1408
16
      "Number of cursorIDs in message", HFILL }
1409
16
    },
1410
16
    { &hf_mongo_elements,
1411
16
      { "Elements", "mongo.elements",
1412
16
      FT_NONE, BASE_NONE, NULL, 0x0,
1413
16
      "Document Elements", HFILL }
1414
16
    },
1415
16
    { &hf_mongo_element_name,
1416
16
      { "Element", "mongo.element.name",
1417
16
      FT_STRINGZ, BASE_NONE, NULL, 0x0,
1418
16
      "Element Name", HFILL }
1419
16
    },
1420
16
    { &hf_mongo_element_type,
1421
16
      { "Type", "mongo.element.type",
1422
16
      FT_UINT8, BASE_HEX_DEC, VALS(element_type_vals), 0x0,
1423
16
      "Element Type", HFILL }
1424
16
    },
1425
16
    { &hf_mongo_element_length,
1426
16
      { "Length", "mongo.element.length",
1427
16
      FT_INT32, BASE_DEC, NULL, 0x0,
1428
16
      "Element Length", HFILL }
1429
16
    },
1430
16
    { &hf_mongo_element_value_boolean,
1431
16
      { "Value", "mongo.element.value.bool",
1432
16
      FT_BOOLEAN, BASE_NONE, NULL, 0x0,
1433
16
      "Element Value", HFILL }
1434
16
    },
1435
16
    { &hf_mongo_element_value_int32,
1436
16
      { "Value", "mongo.element.value.int",
1437
16
      FT_INT32, BASE_DEC, NULL, 0x0,
1438
16
      "Element Value", HFILL }
1439
16
    },
1440
16
    { &hf_mongo_element_value_int64,
1441
16
      { "Value", "mongo.element.value.int64",
1442
16
      FT_INT64, BASE_DEC, NULL, 0x0,
1443
16
      "Element Value", HFILL }
1444
16
    },
1445
16
    { &hf_mongo_element_value_decimal128,
1446
16
      { "Value", "mongo.element.value.decimal128",
1447
16
      FT_BYTES, BASE_NONE, NULL, 0x0,
1448
16
      "Element Value", HFILL }
1449
16
    },
1450
16
    { &hf_mongo_element_value_double,
1451
16
      { "Value", "mongo.element.value.double",
1452
16
      FT_DOUBLE, BASE_NONE, NULL, 0x0,
1453
16
      "Element Value", HFILL }
1454
16
    },
1455
16
    { &hf_mongo_element_value_string,
1456
16
      { "Value", "mongo.element.value.string",
1457
16
      FT_STRING, BASE_NONE, NULL, 0x0,
1458
16
      "Element Value", HFILL }
1459
16
    },
1460
16
    { &hf_mongo_element_value_string_length,
1461
16
      { "Length", "mongo.element.value.length",
1462
16
      FT_INT32, BASE_DEC, NULL, 0x0,
1463
16
      "Element Value Length", HFILL }
1464
16
    },
1465
16
    { &hf_mongo_element_value_binary,
1466
16
      { "Value", "mongo.element.value.bytes",
1467
16
      FT_BYTES, BASE_NONE, NULL, 0x0,
1468
16
      "Element Value", HFILL }
1469
16
    },
1470
16
    { &hf_mongo_element_value_binary_length,
1471
16
      { "Length", "mongo.element.value.length",
1472
16
      FT_INT32, BASE_DEC, NULL, 0x0,
1473
16
      "Binary Element Length", HFILL }
1474
16
    },
1475
16
    { &hf_mongo_element_value_regex_pattern,
1476
16
      { "Value", "mongo.element.value.regex.pattern",
1477
16
      FT_STRINGZ, BASE_NONE, NULL, 0x0,
1478
16
      "Regex Pattern", HFILL }
1479
16
    },
1480
16
    { &hf_mongo_element_value_regex_options,
1481
16
      { "Value", "mongo.element.value.regex.options",
1482
16
      FT_STRINGZ, BASE_NONE, NULL, 0x0,
1483
16
      "Regex Options", HFILL }
1484
16
    },
1485
16
    { &hf_mongo_element_value_objectid,
1486
16
      { "ObjectID", "mongo.element.value.objectid",
1487
16
      FT_BYTES, BASE_NONE, NULL, 0x0,
1488
16
      "ObjectID Value", HFILL }
1489
16
    },
1490
16
    { &hf_mongo_element_value_objectid_time,
1491
16
      { "ObjectID Time", "mongo.element.value.objectid.time",
1492
16
      FT_INT32, BASE_DEC, NULL, 0x0,
1493
16
      "ObjectID timestampt", HFILL }
1494
16
    },
1495
16
    { &hf_mongo_element_value_objectid_host,
1496
16
      { "ObjectID Host", "mongo.element.value.objectid.host",
1497
16
      FT_UINT24, BASE_HEX, NULL, 0x0,
1498
16
      "ObjectID Host Hash", HFILL }
1499
16
    },
1500
16
    { &hf_mongo_element_value_objectid_machine_id,
1501
16
      { "ObjectID Machine", "mongo.element.value.objectid.machine_id",
1502
16
      FT_BYTES, BASE_NONE, NULL, 0x0,
1503
16
      "ObjectID machine ID", HFILL }
1504
16
    },
1505
16
    { &hf_mongo_element_value_objectid_pid,
1506
16
      { "ObjectID PID", "mongo.element.value.objectid.pid",
1507
16
      FT_UINT16, BASE_DEC, NULL, 0x0,
1508
16
      "ObjectID process ID", HFILL }
1509
16
    },
1510
16
    { &hf_mongo_element_value_objectid_inc,
1511
16
      { "ObjectID Inc", "mongo.element.value.objectid.inc",
1512
16
      FT_UINT24, BASE_DEC, NULL, 0x0,
1513
16
      "ObjectID increment", HFILL }
1514
16
    },
1515
16
    { &hf_mongo_element_value_db_ptr,
1516
16
      { "ObjectID", "mongo.element.value.db_ptr",
1517
16
      FT_BYTES, BASE_NONE, NULL, 0x0,
1518
16
      "DBPointer", HFILL }
1519
16
    },
1520
16
    { &hf_mongo_element_value_js_code,
1521
16
      { "JavaScript code", "mongo.element.value.js_code",
1522
16
      FT_NONE, BASE_NONE, NULL, 0x0,
1523
16
      "JavaScript code to be evaluated", HFILL }
1524
16
    },
1525
16
    { &hf_mongo_element_value_js_scope,
1526
16
      { "JavaScript scope", "mongo.element.value.js_scope",
1527
16
      FT_NONE, BASE_NONE, NULL, 0x0,
1528
16
      "Scope document for JavaScript evaluation", HFILL }
1529
16
    },
1530
16
    { &hf_mongo_database,
1531
16
      { "database", "mongo.database",
1532
16
      FT_STRING, BASE_NONE, NULL, 0x0,
1533
16
      "the name of the database to run the command on", HFILL }
1534
16
    },
1535
16
    { &hf_mongo_commandname,
1536
16
      { "commandName", "mongo.commandname",
1537
16
      FT_STRING, BASE_NONE, NULL, 0x0,
1538
16
      "the name of the command", HFILL }
1539
16
    },
1540
16
    { &hf_mongo_metadata,
1541
16
      { "metadata", "mongo.metadata",
1542
16
      FT_NONE, BASE_NONE, NULL, 0x0,
1543
16
      NULL, HFILL }
1544
16
    },
1545
16
    { &hf_mongo_commandargs,
1546
16
      { "CommandArgs", "mongo.commandargs",
1547
16
      FT_NONE, BASE_NONE, NULL, 0x0,
1548
16
      NULL, HFILL }
1549
16
    },
1550
16
    { &hf_mongo_commandreply,
1551
16
      { "CommandReply", "mongo.commandreply",
1552
16
      FT_NONE, BASE_NONE, NULL, 0x0,
1553
16
      NULL, HFILL }
1554
16
    },
1555
16
    { &hf_mongo_outputdocs,
1556
16
      { "OutputDocs", "mongo.outputdocs",
1557
16
      FT_NONE, BASE_NONE, NULL, 0x0,
1558
16
      NULL, HFILL }
1559
16
    },
1560
16
    { &hf_mongo_unknown,
1561
16
      { "Unknown", "mongo.unknown",
1562
16
      FT_BYTES, BASE_NONE, NULL, 0x0,
1563
16
      "Unknown Data type", HFILL }
1564
16
    },
1565
16
  };
1566
1567
16
  static int *ett[] = {
1568
16
    &ett_mongo,
1569
16
    &ett_mongo_doc,
1570
16
    &ett_mongo_elements,
1571
16
    &ett_mongo_element,
1572
16
    &ett_mongo_objectid,
1573
16
    &ett_mongo_machine_id,
1574
16
    &ett_mongo_code,
1575
16
    &ett_mongo_fcn,
1576
16
    &ett_mongo_flags,
1577
16
    &ett_mongo_compression_info,
1578
16
    &ett_mongo_sections,
1579
16
    &ett_mongo_section,
1580
16
    &ett_mongo_msg_flags,
1581
16
    &ett_mongo_doc_sequence
1582
16
  };
1583
1584
16
  static ei_register_info ei[] = {
1585
16
     { &ei_mongo_document_recursion_exceeded, { "mongo.document.recursion_exceeded", PI_MALFORMED, PI_ERROR, "BSON document recursion exceeds", EXPFILL }},
1586
16
     { &ei_mongo_document_length_bad, { "mongo.document.length.bad",  PI_MALFORMED, PI_ERROR, "BSON document length bad", EXPFILL }},
1587
16
     { &ei_mongo_section_size_bad, { "mongo.msg.sections.section.size.bad",  PI_MALFORMED, PI_ERROR, "Bogus Mongo message section size", EXPFILL }},
1588
16
     { &ei_mongo_unknown, { "mongo.unknown.expert", PI_UNDECODED, PI_WARN, "Unknown Data (not interpreted)", EXPFILL }},
1589
16
     { &ei_mongo_unsupported_compression, { "mongo.unsupported_compression.expert", PI_UNDECODED, PI_WARN, "This packet was compressed with an unsupported compressor", EXPFILL }},
1590
16
     { &ei_mongo_msg_checksum, { "mongo.bad_checksum.expert", PI_UNDECODED, PI_ERROR, "Bad checksum", EXPFILL }},
1591
16
  };
1592
1593
16
  proto_mongo = proto_register_protocol("Mongo Wire Protocol", "MONGO", "mongo");
1594
1595
  /* Allow dissector to find be found by name. */
1596
16
  mongo_handle = register_dissector_with_description("mongo", "Mongo Wire Protocol", dissect_mongo, proto_mongo);
1597
16
  mongo_heur_handle = register_dissector_with_description("mongo_tcp", "Mongo Wire Protocol over TCP", dissect_mongo_tcp_heur, proto_mongo);
1598
1599
16
  proto_register_field_array(proto_mongo, hf, array_length(hf));
1600
16
  proto_register_subtree_array(ett, array_length(ett));
1601
16
  expert_mongo = expert_register_protocol(proto_mongo);
1602
16
  expert_register_field_array(expert_mongo, ei, array_length(ei));
1603
16
}
1604
1605
1606
void
1607
proto_reg_handoff_mongo(void)
1608
16
{
1609
16
  dissector_add_uint_with_preference("tcp.port", TCP_PORT_MONGO, mongo_heur_handle);
1610
  /* ssl_dissector_add registers TLS as the dissector for TCP on the given
1611
   * port, but Mongo uses the same port by default with or without TLS,
1612
   * so we need to test for the non-TLS version as well.
1613
   * If the TLS heuristic dissector detects TLS on this port, assume Mongo.
1614
   */
1615
16
  dissector_add_uint_with_preference("tls.port", TCP_PORT_MONGO, mongo_handle);
1616
16
}
1617
/*
1618
 * Editor modelines
1619
 *
1620
 * Local Variables:
1621
 * c-basic-offset: 2
1622
 * tab-width: 8
1623
 * indent-tabs-mode: nil
1624
 * End:
1625
 *
1626
 * ex: set shiftwidth=2 tabstop=8 expandtab:
1627
 * :indentSize=2:tabSize=8:noTabs=true:
1628
 */