2 * Routines for Monero protocol dissection
3 * Copyright 2023, snicket2100 <snicket2100@protonmail.com>
5 * Wireshark - Network traffic analyzer
6 * By Gerald Combs <gerald@wireshark.org>
7 * Copyright 1998 Gerald Combs
9 * SPDX-License-Identifier: GPL-2.0-or-later
13 #include <epan/packet.h>
15 #include <wsutil/array.h>
16 #include <epan/prefs.h>
17 #include <epan/expert.h>
19 #include "packet-tcp.h"
21 #define MONERO_LEVIN_SIGNATURE 0x0101010101012101
22 #define MONERO_PAYLOAD_MAGIC 0x011101010101020101
23 #define MONERO_PAYLOAD_TYPE_INT64 1
24 #define MONERO_PAYLOAD_TYPE_INT32 2
25 #define MONERO_PAYLOAD_TYPE_INT16 3
26 #define MONERO_PAYLOAD_TYPE_INT8 4
27 #define MONERO_PAYLOAD_TYPE_UINT64 5
28 #define MONERO_PAYLOAD_TYPE_UINT32 6
29 #define MONERO_PAYLOAD_TYPE_UINT16 7
30 #define MONERO_PAYLOAD_TYPE_UINT8 8
31 #define MONERO_PAYLOAD_TYPE_FLOAT64 9
32 #define MONERO_PAYLOAD_TYPE_STRING 10
33 #define MONERO_PAYLOAD_TYPE_BOOLEAN 11
34 #define MONERO_PAYLOAD_TYPE_STRUCT 12
35 #define MONERO_PAYLOAD_ARRAY 0x80
37 static const value_string monero_commands
[] =
39 { 1001, "Handshake" },
40 { 1002, "TimedSync" },
42 { 1007, "SupportFlags" },
44 { 2002, "NewTransactions" },
45 { 2003, "GetObjectsRequest" },
46 { 2004, "GetObjectsResponse" },
47 { 2006, "ChainRequest" },
48 { 2007, "ChainResponse" },
49 { 2008, "NewFluffyBlock" },
50 { 2009, "FluffyMissingTxsRequest" },
51 { 2010, "GetTxPoolCompliment" },
55 static const value_string payload_types
[] =
57 { MONERO_PAYLOAD_TYPE_INT64
, "int64" },
58 { MONERO_PAYLOAD_TYPE_INT32
, "int32" },
59 { MONERO_PAYLOAD_TYPE_INT16
, "int16" },
60 { MONERO_PAYLOAD_TYPE_INT8
, "int8" },
61 { MONERO_PAYLOAD_TYPE_UINT64
, "uint64" },
62 { MONERO_PAYLOAD_TYPE_UINT32
, "uint32" },
63 { MONERO_PAYLOAD_TYPE_UINT16
, "uint16" },
64 { MONERO_PAYLOAD_TYPE_UINT8
, "uint8" },
65 { MONERO_PAYLOAD_TYPE_FLOAT64
, "float64" },
66 { MONERO_PAYLOAD_TYPE_STRING
, "string" },
67 { MONERO_PAYLOAD_TYPE_BOOLEAN
, "boolean" },
68 { MONERO_PAYLOAD_TYPE_STRUCT
, "struct" },
70 { MONERO_PAYLOAD_ARRAY
| MONERO_PAYLOAD_TYPE_INT64
, "array[int64]" },
71 { MONERO_PAYLOAD_ARRAY
| MONERO_PAYLOAD_TYPE_INT32
, "array[int32]" },
72 { MONERO_PAYLOAD_ARRAY
| MONERO_PAYLOAD_TYPE_INT16
, "array[int16]" },
73 { MONERO_PAYLOAD_ARRAY
| MONERO_PAYLOAD_TYPE_INT8
, "array[int8]" },
74 { MONERO_PAYLOAD_ARRAY
| MONERO_PAYLOAD_TYPE_UINT64
, "array[uint64]" },
75 { MONERO_PAYLOAD_ARRAY
| MONERO_PAYLOAD_TYPE_UINT32
, "array[uint32]" },
76 { MONERO_PAYLOAD_ARRAY
| MONERO_PAYLOAD_TYPE_UINT16
, "array[uint16]" },
77 { MONERO_PAYLOAD_ARRAY
| MONERO_PAYLOAD_TYPE_UINT8
, "array[uint8]" },
78 { MONERO_PAYLOAD_ARRAY
| MONERO_PAYLOAD_TYPE_FLOAT64
, "array[float64]" },
79 { MONERO_PAYLOAD_ARRAY
| MONERO_PAYLOAD_TYPE_STRING
, "array[string]" },
80 { MONERO_PAYLOAD_ARRAY
| MONERO_PAYLOAD_TYPE_BOOLEAN
, "array[boolean]" },
81 { MONERO_PAYLOAD_ARRAY
| MONERO_PAYLOAD_TYPE_STRUCT
, "array[struct]" },
87 * Monero message header.
88 * - Network signature - 8 bytes
89 * - Body size - 8 bytes
90 * - Have to return data - 1 byte
92 * - Return code - 4 bytes
94 * - Protocol version - 4 bytes
96 #define MONERO_HEADER_LENGTH 8+8+1+4+4+4+4
98 void proto_register_monero(void);
99 void proto_reg_handoff_monero(void);
101 static dissector_handle_t monero_handle
;
103 static int proto_monero
;
105 static int hf_monero_signature
;
106 static int hf_monero_length
;
107 static int hf_monero_havetoreturn
;
108 static int hf_monero_command
;
109 static int hf_monero_return_code
;
110 static int hf_monero_flags
;
111 static int hf_monero_flags_request
;
112 static int hf_monero_flags_response
;
113 static int hf_monero_flags_start_fragment
;
114 static int hf_monero_flags_end_fragment
;
115 static int hf_monero_flags_reserved
;
116 static int hf_monero_protocol
;
117 static int hf_monero_payload
;
118 static int hf_monero_payload_magic
;
119 static int hf_monero_payload_item
;
120 static int hf_monero_payload_item_key
;
121 static int hf_monero_payload_item_type
;
122 static int hf_monero_payload_item_size
;
123 static int hf_monero_payload_item_length
;
124 static int hf_monero_payload_item_value_int8
;
125 static int hf_monero_payload_item_value_int16
;
126 static int hf_monero_payload_item_value_int32
;
127 static int hf_monero_payload_item_value_int64
;
128 static int hf_monero_payload_item_value_uint8
;
129 static int hf_monero_payload_item_value_uint16
;
130 static int hf_monero_payload_item_value_uint32
;
131 static int hf_monero_payload_item_value_uint64
;
132 static int hf_monero_payload_item_value_float64
;
133 static int hf_monero_payload_item_value_string
;
134 static int hf_monero_payload_item_value_boolean
;
135 static int hf_monero_payload_item_value_struct
;
136 static int hf_monero_payload_item_value_array
;
138 static int * const flags_hf_flags
[] = {
139 &hf_monero_flags_request
,
140 &hf_monero_flags_response
,
141 &hf_monero_flags_start_fragment
,
142 &hf_monero_flags_end_fragment
,
143 &hf_monero_flags_reserved
,
147 static int ett_monero
;
148 static int ett_payload
;
149 static int ett_struct
;
150 static int ett_flags
;
152 static bool monero_desegment
= true;
154 static expert_field ei_monero_type_unknown
;
157 get_monero_pdu_length(packet_info
*pinfo _U_
, tvbuff_t
*tvb
,
158 int offset
, void *data _U_
)
161 length
= MONERO_HEADER_LENGTH
;
163 /* add payload length */
164 length
+= (unsigned)tvb_get_letoh64(tvb
, offset
+8);
170 get_varint(tvbuff_t
*tvb
, const int offset
, uint8_t *length
, uint64_t *ret
)
172 uint8_t flag
= tvb_get_uint8(tvb
, offset
) & 0x03;
177 *ret
= tvb_get_uint8(tvb
, offset
) >> 2;
181 *ret
= tvb_get_uint16(tvb
, offset
, ENC_LITTLE_ENDIAN
) >> 2;
185 *ret
= tvb_get_uint32(tvb
, offset
, ENC_LITTLE_ENDIAN
) >> 2;
189 *ret
= tvb_get_uint64(tvb
, offset
, ENC_LITTLE_ENDIAN
) >> 2;
195 static int dissect_encoded_value(tvbuff_t
*tvb
, packet_info
*pinfo _U_
, proto_tree
*tree
, proto_item
*ti
, int offset
, uint32_t type
);
197 // we are parsing generic data structures, recursion is a first class citizen here
198 // NOLINTNEXTLINE(misc-no-recursion)
199 static int dissect_encoded_dictionary(tvbuff_t
*tvb
, packet_info
*pinfo _U_
, proto_tree
*tree
, int offset
)
208 // number of keys in the dictionary
209 get_varint(tvb
, offset
, &length
, &count
);
212 for (; count
> 0; count
--)
214 sti
= proto_tree_add_item(tree
, hf_monero_payload_item
, tvb
, offset
, -1, ENC_NA
);
215 stree
= proto_item_add_subtree(sti
, ett_payload
);
218 length
= tvb_get_uint8(tvb
, offset
);
220 proto_tree_add_item_ret_string(stree
, hf_monero_payload_item_key
, tvb
, offset
, length
, ENC_ASCII
|ENC_NA
, pinfo
->pool
, &key
);
222 proto_item_set_text(sti
, "%s", key
);
226 proto_tree_add_item_ret_uint(stree
, hf_monero_payload_item_type
, tvb
, offset
, 1, ENC_NA
, &type
);
230 offset
= dissect_encoded_value(tvb
, pinfo
, stree
, sti
, offset
, type
);
232 proto_item_set_end(sti
, tvb
, offset
);
238 // we are parsing generic data structures, recursion is a first class citizen here
239 // NOLINTNEXTLINE(misc-no-recursion)
240 static int dissect_encoded_value(tvbuff_t
*tvb
, packet_info
*pinfo _U_
, proto_tree
*tree
, proto_item
*ti
, int offset
, uint32_t type
)
244 uint64_t string_length
;
245 proto_item
*struct_ti
;
246 proto_tree
*struct_tree
;
248 if (!try_val_to_str(type
, payload_types
)) {
249 /* The type is used to determine the length of the value; if it's unknown
250 * then we can't dissect any further. (In particular, this keeps from
251 * looping repeatedly on invalid arrays.)
253 expert_add_info(pinfo
, ti
, &ei_monero_type_unknown
);
254 return tvb_reported_length(tvb
);
258 if (type
& MONERO_PAYLOAD_ARRAY
) {
259 get_varint(tvb
, offset
, &length
, &size
);
260 proto_tree_add_int64(tree
, hf_monero_payload_item_size
, tvb
, offset
, length
, size
);
263 type
-= MONERO_PAYLOAD_ARRAY
;
265 for (; size
> 0; size
--) {
266 if (type
== MONERO_PAYLOAD_TYPE_STRING
) {
267 struct_ti
= proto_tree_add_item(tree
, hf_monero_payload_item_value_array
, tvb
, offset
, -1, ENC_NA
);
268 struct_tree
= proto_item_add_subtree(struct_ti
, ett_struct
);
270 offset
= dissect_encoded_value(tvb
, pinfo
, struct_tree
, ti
, offset
, type
);
272 proto_item_set_end(struct_ti
, tvb
, offset
);
275 offset
= dissect_encoded_value(tvb
, pinfo
, tree
, ti
, offset
, type
);
283 case MONERO_PAYLOAD_TYPE_INT64
:
284 proto_tree_add_item(tree
, hf_monero_payload_item_value_int64
, tvb
, offset
, 8, ENC_LITTLE_ENDIAN
);
288 case MONERO_PAYLOAD_TYPE_INT32
:
289 proto_tree_add_item(tree
, hf_monero_payload_item_value_int32
, tvb
, offset
, 4, ENC_LITTLE_ENDIAN
);
293 case MONERO_PAYLOAD_TYPE_INT16
:
294 proto_tree_add_item(tree
, hf_monero_payload_item_value_int16
, tvb
, offset
, 2, ENC_LITTLE_ENDIAN
);
298 case MONERO_PAYLOAD_TYPE_INT8
:
299 proto_tree_add_item(tree
, hf_monero_payload_item_value_int8
, tvb
, offset
, 1, ENC_LITTLE_ENDIAN
);
303 case MONERO_PAYLOAD_TYPE_UINT64
:
304 proto_tree_add_item(tree
, hf_monero_payload_item_value_uint64
, tvb
, offset
, 8, ENC_LITTLE_ENDIAN
);
308 case MONERO_PAYLOAD_TYPE_UINT32
:
309 proto_tree_add_item(tree
, hf_monero_payload_item_value_uint32
, tvb
, offset
, 4, ENC_LITTLE_ENDIAN
);
313 case MONERO_PAYLOAD_TYPE_UINT16
:
314 proto_tree_add_item(tree
, hf_monero_payload_item_value_uint16
, tvb
, offset
, 2, ENC_LITTLE_ENDIAN
);
318 case MONERO_PAYLOAD_TYPE_UINT8
:
319 proto_tree_add_item(tree
, hf_monero_payload_item_value_uint8
, tvb
, offset
, 1, ENC_LITTLE_ENDIAN
);
323 case MONERO_PAYLOAD_TYPE_FLOAT64
:
324 proto_tree_add_item(tree
, hf_monero_payload_item_value_float64
, tvb
, offset
, 8, ENC_LITTLE_ENDIAN
);
328 case MONERO_PAYLOAD_TYPE_STRING
:
329 get_varint(tvb
, offset
, &length
, &string_length
);
330 proto_tree_add_int64(tree
, hf_monero_payload_item_length
, tvb
, offset
, length
, string_length
);
333 proto_tree_add_item(tree
, hf_monero_payload_item_value_string
, tvb
, offset
, (int) string_length
, ENC_NA
);
334 offset
+= (int)string_length
;
337 case MONERO_PAYLOAD_TYPE_BOOLEAN
:
338 proto_tree_add_item(tree
, hf_monero_payload_item_value_int64
, tvb
, offset
, 1, ENC_LITTLE_ENDIAN
);
342 case MONERO_PAYLOAD_TYPE_STRUCT
:
343 struct_ti
= proto_tree_add_item(tree
, hf_monero_payload_item_value_struct
, tvb
, offset
, -1, ENC_NA
);
344 struct_tree
= proto_item_add_subtree(struct_ti
, ett_struct
);
346 offset
= dissect_encoded_dictionary(tvb
, pinfo
, struct_tree
, offset
);
347 proto_item_set_end(struct_ti
, tvb
, offset
);
351 expert_add_info(pinfo
, ti
, &ei_monero_type_unknown
);
352 offset
= tvb_reported_length(tvb
);
359 static void dissect_encoded_payload(tvbuff_t
*tvb
, packet_info
*pinfo _U_
, proto_tree
*tree
)
361 proto_tree_add_item(tree
, hf_monero_payload_magic
, tvb
, 0, 9, ENC_NA
);
362 dissect_encoded_dictionary(tvb
, pinfo
, tree
, 9);
365 static int dissect_monero_tcp_pdu(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void *data _U_
)
367 proto_item
*ti
, *payload_ti
;
368 proto_tree
*payload_tree
;
370 const char* command_label
;
374 col_set_str(pinfo
->cinfo
, COL_PROTOCOL
, "Monero");
376 ti
= proto_tree_add_item(tree
, proto_monero
, tvb
, 0, -1, ENC_NA
);
377 tree
= proto_item_add_subtree(ti
, ett_monero
);
380 proto_tree_add_item(tree
, hf_monero_signature
, tvb
, 0, 8, ENC_BIG_ENDIAN
);
381 proto_tree_add_item_ret_uint64(tree
, hf_monero_length
, tvb
, 8, 8, ENC_LITTLE_ENDIAN
, &length
);
382 proto_tree_add_item(tree
, hf_monero_havetoreturn
, tvb
, 16, 1, ENC_LITTLE_ENDIAN
);
383 proto_tree_add_item_ret_uint(tree
, hf_monero_command
, tvb
, 17, 4, ENC_LITTLE_ENDIAN
, &command
);
384 proto_tree_add_item(tree
, hf_monero_return_code
, tvb
, 21, 4, ENC_LITTLE_ENDIAN
);
385 proto_tree_add_bitmask(tree
, tvb
, 25, hf_monero_flags
, ett_flags
, flags_hf_flags
, ENC_LITTLE_ENDIAN
);
386 proto_tree_add_item(tree
, hf_monero_protocol
, tvb
, 29, 4, ENC_LITTLE_ENDIAN
);
387 offset
+= MONERO_HEADER_LENGTH
;
389 command_label
= val_to_str(command
, monero_commands
, "[Unknown command %d]");
390 col_add_str(pinfo
->cinfo
, COL_INFO
, command_label
);
393 payload_ti
= proto_tree_add_item(tree
, hf_monero_payload
, tvb
, offset
, (int) length
, ENC_NA
);
394 payload_tree
= proto_item_add_subtree(payload_ti
, ett_payload
);
395 dissect_encoded_payload(tvb_new_subset_length(tvb
, offset
, (int) length
), pinfo
, payload_tree
);
398 return tvb_reported_length(tvb
);
402 dissect_monero(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void *data
)
404 col_clear(pinfo
->cinfo
, COL_INFO
);
405 tcp_dissect_pdus(tvb
, pinfo
, tree
, monero_desegment
, MONERO_HEADER_LENGTH
,
406 get_monero_pdu_length
, dissect_monero_tcp_pdu
, data
);
408 return tvb_reported_length(tvb
);
412 dissect_monero_heur(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void *data
)
415 conversation_t
*conversation
;
417 if (tvb_captured_length(tvb
) < 8)
420 signature
= tvb_get_letoh64(tvb
, 0);
421 if (signature
!= MONERO_LEVIN_SIGNATURE
)
424 /* Ok: This connection should always use the monero dissector */
425 conversation
= find_or_create_conversation(pinfo
);
426 conversation_set_dissector(conversation
, monero_handle
);
428 dissect_monero(tvb
, pinfo
, tree
, data
);
433 proto_register_monero(void)
435 static hf_register_info hf
[] = {
436 { &hf_monero_signature
,
437 { "Signature", "monero.signature",
438 FT_UINT64
, BASE_HEX
, NULL
, 0x0,
442 { "Payload Length", "monero.length",
443 FT_UINT64
, BASE_DEC
, NULL
, 0x0,
446 { &hf_monero_havetoreturn
,
447 { "Have to return data", "monero.have_to_return_data",
448 FT_BOOLEAN
, BASE_NONE
, NULL
, 0x0,
451 { &hf_monero_command
,
452 { "Command", "monero.command",
453 FT_UINT32
, BASE_DEC
, VALS(monero_commands
), 0x0,
456 { &hf_monero_return_code
,
457 { "Return Code", "monero.return_code",
458 FT_INT32
, BASE_DEC
, NULL
, 0x0,
462 { "Flags", "monero.flags",
463 FT_UINT32
, BASE_DEC
, NULL
, 0x0,
466 { &hf_monero_flags_request
,
467 { "Request", "monero.flags.request",
468 FT_BOOLEAN
, 32, TFS(&tfs_set_notset
), 0x00000001,
471 { &hf_monero_flags_response
,
472 { "Response", "monero.flags.response",
473 FT_BOOLEAN
, 32, TFS(&tfs_set_notset
), 0x00000002,
476 { &hf_monero_flags_start_fragment
,
477 { "Start fragment", "monero.flags.start_fragment",
478 FT_BOOLEAN
, 32, TFS(&tfs_set_notset
), 0x00000004,
481 { &hf_monero_flags_end_fragment
,
482 { "End fragment", "monero.flags.end_fragment",
483 FT_BOOLEAN
, 32, TFS(&tfs_set_notset
), 0x00000008,
486 { &hf_monero_flags_reserved
,
487 { "Reserved", "monero.flags.reserved",
488 FT_BOOLEAN
, 32, TFS(&tfs_set_notset
), 0xfffffff0,
491 { &hf_monero_protocol
,
492 { "Protocol version", "monero.version",
493 FT_UINT32
, BASE_DEC
, NULL
, 0x0,
496 { &hf_monero_payload
,
497 { "Payload", "monero.payload",
498 FT_NONE
, BASE_NONE
, NULL
, 0x0,
501 { &hf_monero_payload_magic
,
502 { "Magic number", "monero.payload.magic",
503 FT_BYTES
, BASE_NONE
, NULL
, 0x0,
506 { &hf_monero_payload_item
,
507 { "Entry", "monero.payload.item",
508 FT_BYTES
, BASE_NONE
, NULL
, 0x0,
511 { &hf_monero_payload_item_key
,
512 { "Key", "monero.payload.item.key",
513 FT_STRING
, BASE_NONE
, NULL
, 0x0,
516 { &hf_monero_payload_item_type
,
517 { "Type", "monero.payload.item.type",
518 FT_UINT8
, BASE_DEC
, VALS(payload_types
), 0x0,
521 { &hf_monero_payload_item_size
,
522 { "Size", "monero.payload.item.size",
523 FT_INT64
, BASE_DEC
, NULL
, 0x0,
526 { &hf_monero_payload_item_length
,
527 { "Length", "monero.payload.item.length",
528 FT_INT64
, BASE_DEC
, NULL
, 0x0,
531 { &hf_monero_payload_item_value_int8
,
532 { "Value", "monero.payload.item.value.int8",
533 FT_INT8
, BASE_DEC
, NULL
, 0x0,
536 { &hf_monero_payload_item_value_int16
,
537 { "Value", "monero.payload.item.value.int16",
538 FT_INT16
, BASE_DEC
, NULL
, 0x0,
541 { &hf_monero_payload_item_value_int32
,
542 { "Value", "monero.payload.item.value.int32",
543 FT_INT32
, BASE_DEC
, NULL
, 0x0,
546 { &hf_monero_payload_item_value_int64
,
547 { "Value", "monero.payload.item.value.int64",
548 FT_INT64
, BASE_DEC
, NULL
, 0x0,
551 { &hf_monero_payload_item_value_uint8
,
552 { "Value", "monero.payload.item.value.uint8",
553 FT_UINT8
, BASE_DEC
, NULL
, 0x0,
556 { &hf_monero_payload_item_value_uint16
,
557 { "Value", "monero.payload.item.value.uint16",
558 FT_UINT16
, BASE_DEC
, NULL
, 0x0,
561 { &hf_monero_payload_item_value_uint32
,
562 { "Value", "monero.payload.item.value.uint32",
563 FT_UINT32
, BASE_DEC
, NULL
, 0x0,
566 { &hf_monero_payload_item_value_uint64
,
567 { "Value", "monero.payload.item.value.uint64",
568 FT_UINT64
, BASE_DEC
, NULL
, 0x0,
571 { &hf_monero_payload_item_value_float64
,
572 { "Value", "monero.payload.item.value.float64",
573 FT_DOUBLE
, BASE_DEC
, NULL
, 0x0,
576 { &hf_monero_payload_item_value_string
,
577 { "Value", "monero.payload.item.value.string",
578 FT_BYTES
, BASE_NONE
, NULL
, 0x0,
581 { &hf_monero_payload_item_value_boolean
,
582 { "Value", "monero.payload.item.value.boolean",
583 FT_BOOLEAN
, BASE_NONE
, NULL
, 0x0,
586 { &hf_monero_payload_item_value_struct
,
587 { "Value", "monero.payload.item.value.struct",
588 FT_NONE
, BASE_NONE
, NULL
, 0x0,
591 { &hf_monero_payload_item_value_array
,
592 { "Value", "monero.payload.item.value.array",
593 FT_NONE
, BASE_NONE
, NULL
, 0x0,
598 static int *ett
[] = {
605 module_t
*monero_module
;
606 expert_module_t
* expert_monero
;
608 proto_monero
= proto_register_protocol("Monero protocol", "Monero", "monero");
610 proto_register_subtree_array(ett
, array_length(ett
));
611 proto_register_field_array(proto_monero
, hf
, array_length(hf
));
613 static ei_register_info ei
[] = {
614 { &ei_monero_type_unknown
, { "monero.payload.item.type.unknown", PI_PROTOCOL
, PI_WARN
, "Unknown type", EXPFILL
}},
617 expert_monero
= expert_register_protocol(proto_monero
);
618 expert_register_field_array(expert_monero
, ei
, array_length(ei
));
620 monero_handle
= register_dissector("monero", dissect_monero
, proto_monero
);
622 monero_module
= prefs_register_protocol(proto_monero
, NULL
);
623 prefs_register_bool_preference(monero_module
, "desegment",
624 "Desegment all Monero messages spanning multiple TCP segments",
625 "Whether the Monero dissector should desegment all messages"
626 " spanning multiple TCP segments",
632 proto_reg_handoff_monero(void)
634 dissector_add_for_decode_as_with_preference("tcp.port", monero_handle
);
636 heur_dissector_add( "tcp", dissect_monero_heur
, "Monero over TCP", "monero_tcp", proto_monero
, HEURISTIC_ENABLE
);
640 * Editor modelines - https://www.wireshark.org/tools/modelines.html
645 * indent-tabs-mode: nil
648 * vi: set shiftwidth=2 tabstop=8 expandtab:
649 * :indentSize=2:tabSize=8:noTabs=true: