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