epan/dissectors/pidl/samr/samr.cnf cnf_dissect_lsa_BinaryString => lsarpc_dissect_str...
[wireshark-sm.git] / epan / dissectors / packet-ms-do.c
blobf4e728dc411d06e6428e99826da1721098590b21
1 /* packet-ms-do.c
2 * Routines for MS-DO (Microsoft Delivery Optimization) dissection
3 * Copyright 2023, Benjamin Levine (binyamin.l@sygnia.co, levbinyamin@gmail.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 * Microsoft Delivery Optimization is an internal Windows protocol for exchanging updates between Windows peers.
15 * As of today there are no Microsoft official docs specifying the protocol itself,
16 * this dissector was written as part of my research into MS-DO.
17 * For a detailed explanation see our blog posts:
18 * <Sygnia blog post>
21 #include "config.h"
23 #include <epan/packet.h>
24 #include <epan/conversation.h>
25 #include <epan/expert.h>
27 void proto_reg_handoff_do(void);
28 void proto_register_do(void);
30 static int proto_do;
31 // Message types
32 static int hf_do_handshake_message;
33 static int hf_do_keepalive_message;
34 static int hf_do_choke_message;
35 static int hf_do_unchoke_message;
36 static int hf_do_interested_message;
37 static int hf_do_notinterested_message;
38 static int hf_do_have_message;
39 static int hf_do_bitfield_message;
40 static int hf_do_request_message;
41 static int hf_do_piece_message;
42 static int hf_do_cancel_message;
43 static int hf_do_heap_spraying_message;
44 static int hf_do_unknown_message;
45 // Handshake
46 static int hf_do_protocol_name;
47 static int hf_do_size;
48 static int hf_do_swarm_hash;
49 static int hf_do_peer_id;
50 static int hf_do_peer_id_suffix;
51 // Message header
52 static int hf_do_message_size;
53 static int hf_do_message_id;
54 // BitField
55 static int hf_do_bitfield;
56 static int hf_do_bitfield_piece;
57 static int hf_do_has_piece;
58 // Request & Piece
59 static int hf_do_piece_index;
60 static int hf_do_piece_start_offset;
61 static int hf_do_piece_size;
62 static int hf_do_piece_buffer;
63 static int hf_do_piece_response_size;
64 // "HeapSpraying"
65 static int hf_do_heap_spraying;
67 static int ett_do;
68 static int ett_do_handshake;
69 static int ett_do_message;
70 static int ett_do_bitfield;
71 static int ett_do_bitfield_single;
73 static expert_field ei_do_invalid_message_id;
74 static expert_field ei_do_invalid_message_length;
76 static dissector_handle_t do_handle;
78 #define DO_PORT (7680)
80 #define DO_CHOKE_ID (0)
81 #define DO_UNCHOKE_ID (1)
82 #define DO_INTERESTED_ID (2)
83 #define DO_NOTINTERESTED_ID (3)
84 #define DO_HAVE_ID (4)
85 #define DO_BITFIELD_ID (5)
86 #define DO_REQUEST_ID (6)
87 #define DO_PIECE_ID (7)
88 #define DO_CANCEL_ID (8)
89 #define DO_HEAPSPRAYING_ID (20)
91 static const value_string message_types[] = {
92 { DO_CHOKE_ID, "Choke Message" },
93 { DO_UNCHOKE_ID, "Unchoke Message" },
94 { DO_INTERESTED_ID, "Interested Message" },
95 { DO_NOTINTERESTED_ID, "NotInterested Message" },
96 { DO_HAVE_ID, "Have Message" },
97 { DO_BITFIELD_ID, "BitField Message" },
98 { DO_REQUEST_ID, "Request Message" },
99 { DO_PIECE_ID, "Piece Message" },
100 { DO_CANCEL_ID, "Cancel Message" },
101 { DO_HEAPSPRAYING_ID, "HeapSpraying Message" },
102 { 0, NULL }
105 static value_string_ext message_types_ext = VALUE_STRING_EXT_INIT(message_types);
107 typedef bool (*do_dissect_callback_t)(tvbuff_t*, packet_info*, proto_tree*, uint32_t, uint8_t, unsigned*);
109 static const char*
110 do_get_direction_str(packet_info* pinfo)
112 if (pinfo->match_uint == pinfo->destport)
114 return "Request";
116 else if (pinfo->match_uint == pinfo->srcport)
118 return "Reply";
120 // This shouldn't happen.
121 else
123 DISSECTOR_ASSERT_NOT_REACHED();
128 * Function attempts to identify a handshake and if so, parses it.
129 * If not returns false.
131 static bool
132 dissect_do_handshake(tvbuff_t* tvb, packet_info* pinfo, proto_tree* do_tree, unsigned* offset_ptr)
134 uint8_t protocol_name_length = 0;
135 uint32_t calculated_length = 0;
136 proto_item* handshame_item = NULL;
137 proto_tree* handshake_tree = NULL;
139 /* Identify handshake heuristically.
140 It's hard to detect a handshake as it has a different format to messages.
141 We could search for the "\x0eSwarm protocol" string at the beginning,
142 but the Microsoft code supports other options that may be relevant.
143 Perhaps in the future use conversations, they would have to handle
144 cases where the sniff begins in the middle without any handhsakes.
145 As anyway that approach requires heuristically verifying for handshakes in the middle
146 let's just do that every time without preserving a complex context. */
147 protocol_name_length = tvb_get_uint8(tvb, *offset_ptr);
148 calculated_length = 1 + protocol_name_length + 8 + 32 + 16 + 4;
149 if (calculated_length != tvb_reported_length(tvb))
151 return false;
154 col_add_fstr(pinfo->cinfo, COL_INFO, "Handshake Message (%s)", do_get_direction_str(pinfo));
156 handshame_item = proto_tree_add_item(do_tree, hf_do_handshake_message, tvb, 0, -1, ENC_NA);
157 handshake_tree = proto_item_add_subtree(handshame_item, ett_do_handshake);
159 proto_tree_add_item(handshake_tree, hf_do_protocol_name, tvb, *offset_ptr, 1, ENC_ASCII | ENC_BIG_ENDIAN);
160 *offset_ptr += sizeof(protocol_name_length) + protocol_name_length;
162 proto_tree_add_item(handshake_tree, hf_do_size, tvb, *offset_ptr, 8, ENC_BIG_ENDIAN);
163 *offset_ptr += 8;
165 proto_tree_add_item(handshake_tree, hf_do_swarm_hash, tvb, *offset_ptr, 32, ENC_NA);
166 *offset_ptr += 32;
168 proto_tree_add_item(handshake_tree, hf_do_peer_id, tvb, *offset_ptr, 16, ENC_BIG_ENDIAN);
169 *offset_ptr += 16;
171 proto_tree_add_item(handshake_tree, hf_do_peer_id_suffix, tvb, *offset_ptr, 4, ENC_BIG_ENDIAN);
172 *offset_ptr += 4;
174 return true;
177 static const char*
178 do_message_id_to_str(uint8_t message_id)
180 return val_to_str_ext_const(message_id, &message_types_ext, "Unknown Message");
183 static int
184 do_message_id_to_hfindex(uint8_t message_id)
186 switch (message_id)
188 case DO_CHOKE_ID:
189 return hf_do_choke_message;
190 case DO_UNCHOKE_ID:
191 return hf_do_unchoke_message;
192 case DO_INTERESTED_ID:
193 return hf_do_interested_message;
194 case DO_NOTINTERESTED_ID:
195 return hf_do_notinterested_message;
196 case DO_HAVE_ID:
197 return hf_do_have_message;
198 case DO_BITFIELD_ID:
199 return hf_do_bitfield_message;
200 case DO_REQUEST_ID:
201 return hf_do_request_message;
202 case DO_PIECE_ID:
203 return hf_do_piece_message;
204 case DO_CANCEL_ID:
205 return hf_do_cancel_message;
206 case DO_HEAPSPRAYING_ID:
207 return hf_do_heap_spraying_message;
208 default:
209 return hf_do_unknown_message;
214 * Add a subtree for a single message and add the message header into it.
216 static proto_tree*
217 do_add_message_tree(tvbuff_t* tvb, proto_tree* tree, uint8_t message_id, uint32_t message_full_size, unsigned* offset_ptr)
219 proto_item* message_item = NULL;
220 proto_tree* message_tree = NULL;
222 message_item = proto_tree_add_item(tree, do_message_id_to_hfindex(message_id), tvb, *offset_ptr, message_full_size, ENC_NA);
223 message_tree = proto_item_add_subtree(message_item, ett_do_message);
225 proto_tree_add_item(message_tree, hf_do_message_size, tvb, *offset_ptr, 4, ENC_BIG_ENDIAN);
226 *offset_ptr += 4;
227 proto_tree_add_item(message_tree, hf_do_message_id, tvb, *offset_ptr, 1, ENC_NA);
228 *offset_ptr += 1;
230 return message_tree;
234 * Add KeepAlive message into tree.
236 static void
237 dissect_do_keepalive(tvbuff_t* tvb, packet_info* pinfo, proto_tree* tree, unsigned* offset_ptr)
239 proto_item* message_item = NULL;
240 proto_tree* message_tree = NULL;
242 col_append_sep_str(pinfo->cinfo, COL_INFO, NULL, "KeepAlive Message");
244 message_item = proto_tree_add_item(tree, hf_do_keepalive_message, tvb, *offset_ptr, 4, ENC_NA);
245 message_tree = proto_item_add_subtree(message_item, ett_do_message);
246 proto_tree_add_item(message_tree, hf_do_message_size, tvb, *offset_ptr, 4, ENC_BIG_ENDIAN);
247 *offset_ptr += 4;
251 * Callback to add a message without variables, this is used for multiple simple messages.
253 static bool
254 dissect_do_empty_message(tvbuff_t* tvb, packet_info* pinfo, proto_tree* message_tree, uint32_t message_size, uint8_t message_id, unsigned* offset_ptr)
256 if (1 != message_size)
258 proto_tree_add_expert_format(message_tree, pinfo, &ei_do_invalid_message_length, tvb, *offset_ptr, message_size - 1,
259 "Invalid message size: %u instead of %u", message_size, 1);
260 *offset_ptr += message_size - 1;
261 return false;
264 col_append_sep_str(pinfo->cinfo, COL_INFO, NULL, do_message_id_to_str(message_id));
266 return true;
270 * Callback to add a Have message.
272 static bool
273 dissect_do_have(tvbuff_t* tvb, packet_info* pinfo, proto_tree* message_tree, uint32_t message_size, uint8_t message_id, unsigned* offset_ptr)
275 uint32_t piece_index = -1;
277 if (5 != message_size)
279 proto_tree_add_expert_format(message_tree, pinfo, &ei_do_invalid_message_length, tvb, *offset_ptr, message_size - 1,
280 "Invalid message size: %u instead of %u", message_size, 5);
281 *offset_ptr += message_size - 1;
282 return false;
284 proto_tree_add_item_ret_uint(message_tree, hf_do_piece_index, tvb, *offset_ptr, 4, ENC_BIG_ENDIAN, &piece_index);
285 *offset_ptr += 4;
287 col_append_sep_fstr(pinfo->cinfo, COL_INFO, NULL, "%s (piece %u)", do_message_id_to_str(message_id), piece_index);
289 return true;
293 * Callback to add a BitField message.
295 static bool
296 dissect_do_bitfield(tvbuff_t* tvb, packet_info* pinfo, proto_tree* message_tree, uint32_t message_size, _U_ uint8_t message_id, unsigned* offset_ptr)
298 proto_item* bitfield_item = NULL;
299 proto_tree* bitfield_tree = NULL;
300 proto_item* piece_item = NULL;
301 proto_tree* piece_tree = NULL;
302 uint32_t total_has = 0;
303 uint32_t bitfield_size = 0;
304 uint32_t byte_index = 0;
305 uint32_t bit_index = 0;
306 uint8_t current_byte = 0;
307 bool has_piece = false;
308 uint32_t piece_index = 0;
310 bitfield_size = message_size - 1;
312 bitfield_item = proto_tree_add_item(message_tree, hf_do_bitfield, tvb, *offset_ptr, bitfield_size, ENC_NA);
313 bitfield_tree = proto_item_add_subtree(bitfield_item, ett_do_bitfield);
315 for (byte_index = 0; byte_index < bitfield_size; byte_index++)
317 current_byte = tvb_get_uint8(tvb, *offset_ptr);
318 for (bit_index = 0; bit_index < 8; bit_index++)
320 has_piece = false;
321 // Simplified from dosvc.dll!CBitField::_IsSet
322 if (current_byte & (1 << (7 - bit_index)))
324 has_piece = true;
325 total_has++;
327 piece_index = 8 * byte_index + bit_index;
328 piece_item = proto_tree_add_string_format_value(bitfield_tree, hf_do_bitfield_piece, tvb, *offset_ptr, 1,
329 NULL, "Index: %u, has: %s", piece_index, has_piece ? "true" : "false");
330 piece_tree = proto_item_add_subtree(piece_item, ett_do_bitfield_single);
331 proto_tree_add_uint(piece_tree, hf_do_piece_index, tvb, *offset_ptr, 1, piece_index);
332 proto_tree_add_boolean(piece_tree, hf_do_has_piece, tvb, *offset_ptr, 1, has_piece);
335 *offset_ptr += 1;
338 col_append_sep_fstr(pinfo->cinfo, COL_INFO, NULL, "%s (has %u of %u pieces)",
339 do_message_id_to_str(message_id), total_has, bitfield_size * 8);
341 return true;
345 * Callback to add a Request or Cancel message.
347 static bool
348 dissect_do_request_cancel(tvbuff_t* tvb, _U_ packet_info* pinfo, proto_tree* message_tree, uint32_t message_size, uint8_t message_id, unsigned* offset_ptr)
350 uint32_t piece_index = 0;
351 uint32_t piece_start_offset = 0;
352 uint32_t piece_size = 0;
354 if (13 != message_size)
356 proto_tree_add_expert_format(message_tree, pinfo, &ei_do_invalid_message_length, tvb, *offset_ptr, message_size - 1,
357 "Invalid message size: %u instead of %u", message_size, 13);
358 *offset_ptr += message_size - 1;
359 return false;
362 proto_tree_add_item_ret_uint(message_tree, hf_do_piece_index, tvb, *offset_ptr, 4, ENC_BIG_ENDIAN, &piece_index);
363 *offset_ptr += 4;
364 proto_tree_add_item_ret_uint(message_tree, hf_do_piece_start_offset, tvb, *offset_ptr, 4, ENC_BIG_ENDIAN, &piece_start_offset);
365 *offset_ptr += 4;
366 proto_tree_add_item_ret_uint(message_tree, hf_do_piece_size, tvb, *offset_ptr, 4, ENC_BIG_ENDIAN, &piece_size);
367 *offset_ptr += 4;
369 col_append_sep_fstr(pinfo->cinfo, COL_INFO, NULL, "%s (piece %u; offset 0x%x; size 0x%x)",
370 do_message_id_to_str(message_id), piece_index, piece_start_offset, piece_size);
372 return true;
376 * Callback to add a Piece message.
378 static bool
379 dissect_do_piece(tvbuff_t* tvb, _U_ packet_info* pinfo, proto_tree* message_tree, uint32_t message_size, uint8_t message_id, unsigned* offset_ptr)
381 proto_item* pi = NULL;
382 uint32_t piece_index = 0;
383 uint32_t piece_start_offset = 0;
384 uint32_t piece_size = 0;
386 piece_size = message_size - 9;
388 if (message_size <= 9)
390 proto_tree_add_expert_format(message_tree, pinfo, &ei_do_invalid_message_length, tvb, *offset_ptr, message_size - 1,
391 "Invalid message size: message size %u must be larger than 9", message_size);
392 *offset_ptr += message_size - 1;
393 return false;
395 proto_tree_add_item_ret_uint(message_tree, hf_do_piece_index, tvb, *offset_ptr, 4, ENC_BIG_ENDIAN, &piece_index);
396 *offset_ptr += 4;
397 proto_tree_add_item_ret_uint(message_tree, hf_do_piece_start_offset, tvb, *offset_ptr, 4, ENC_BIG_ENDIAN, &piece_start_offset);
398 *offset_ptr += 4;
399 proto_tree_add_item(message_tree, hf_do_piece_buffer, tvb, *offset_ptr, message_size - 9, ENC_NA);
400 *offset_ptr += message_size - 9;
401 pi = proto_tree_add_uint(message_tree, hf_do_piece_response_size, NULL, 0, 0, piece_size);
402 proto_item_set_generated(pi);
404 col_append_sep_fstr(pinfo->cinfo, COL_INFO, NULL, "%s (piece %u; offset 0x%x; size 0x%x)",
405 do_message_id_to_str(message_id), piece_index, piece_start_offset, piece_size);
407 return true;
411 * Callback to add a "HeapSpraying" message.
413 static bool
414 dissect_do_heap_spraying(tvbuff_t* tvb, packet_info* pinfo, proto_tree* message_tree, uint32_t message_size, _U_ uint8_t message_id, unsigned* offset_ptr)
416 proto_tree_add_item(message_tree, hf_do_heap_spraying, tvb, *offset_ptr, message_size - 1, ENC_NA);
417 *offset_ptr += message_size - 1;
419 col_append_sep_str(pinfo->cinfo, COL_INFO, NULL, do_message_id_to_str(message_id));
421 return true;
425 * Callback to handle an unknown message
426 * Just adds its size (which we have from the message header) to the offset.
428 static bool
429 dissect_do_unkown_message(tvbuff_t* tvb, packet_info* pinfo, proto_tree* message_tree, uint32_t message_size, uint8_t message_id, unsigned* offset_ptr)
431 proto_tree_add_expert_format(message_tree, pinfo, &ei_do_invalid_message_id, tvb, *offset_ptr, message_size - 1,
432 "Unknown message ID: %u", message_id);
434 *offset_ptr += message_size - 1;
436 return true;
439 static do_dissect_callback_t
440 message_id_to_callback(uint8_t message_id)
442 switch (message_id)
444 case DO_CHOKE_ID:
445 case DO_UNCHOKE_ID:
446 case DO_INTERESTED_ID:
447 case DO_NOTINTERESTED_ID:
448 return &dissect_do_empty_message;
449 case DO_HAVE_ID:
450 return &dissect_do_have;
451 case DO_BITFIELD_ID:
452 return &dissect_do_bitfield;
453 case DO_REQUEST_ID:
454 case DO_CANCEL_ID:
455 return dissect_do_request_cancel;
456 case DO_PIECE_ID:
457 return &dissect_do_piece;
458 case DO_HEAPSPRAYING_ID:
459 return &dissect_do_heap_spraying;
460 default:
461 return &dissect_do_unkown_message;
466 * Parse a single message, on success return true.
467 * If true is returned but *desegment_len_ptr is non-zero, the message wasn't parsed as more bytes are required.
469 static bool
470 dissect_do_message(tvbuff_t* tvb, packet_info* pinfo, proto_tree* do_tree, unsigned* offset_ptr, unsigned* desegment_len_ptr)
472 unsigned buffer_size = 0;
473 uint32_t message_size = 0;
474 uint32_t message_full_size = 0;
475 uint8_t message_id = -1;
476 proto_tree* message_tree = NULL;
478 buffer_size = tvb_reported_length_remaining(tvb, *offset_ptr);
480 // Request more bytes if necessary
481 if (buffer_size < 4)
483 *desegment_len_ptr = 4 - buffer_size;
484 return true;
487 message_size = tvb_get_uint32(tvb, *offset_ptr, ENC_BIG_ENDIAN);
489 // KeepAlive case
490 if (0 == message_size)
492 dissect_do_keepalive(tvb, pinfo, do_tree, offset_ptr);
493 return true;
496 if (buffer_size < message_size + 4)
498 // Message size (4 bytes) + required size - current size
499 *desegment_len_ptr = 4 + message_size - buffer_size;
500 return true;
503 message_id = tvb_get_uint8(tvb, *offset_ptr + 4);
504 message_full_size = sizeof(message_size) + message_size;
506 message_tree = do_add_message_tree(tvb, do_tree, message_id, message_full_size, offset_ptr);
508 if (!(*message_id_to_callback(message_id))(tvb, pinfo, message_tree, message_size, message_id, offset_ptr))
510 return false;
513 return true;
516 static int
517 dissect_do(tvbuff_t* tvb, packet_info* pinfo, proto_tree* tree, _U_ void* data)
519 proto_item* ti = NULL;
520 proto_tree* do_tree = NULL;
522 // Using GLib types instead of standard interface to match existing API.
523 unsigned offset = 0;
524 uint32_t desegment_len = 0;
526 col_set_str(pinfo->cinfo, COL_PROTOCOL, "MS-DO");
527 col_clear(pinfo->cinfo, COL_INFO);
529 if (0 == tvb_captured_length(tvb))
531 return tvb_captured_length(tvb);
534 ti = proto_tree_add_item(tree, proto_do, tvb, 0, -1, ENC_NA);
535 do_tree = proto_item_add_subtree(ti, ett_do);
537 // Multiple messages can be concatted, parse them one at a time.
538 while (offset < tvb_reported_length(tvb))
540 // Check if this is a handshake message, if not parse it as a message
541 if (dissect_do_handshake(tvb, pinfo, do_tree, &offset))
543 continue;
546 desegment_len = 0;
547 if (dissect_do_message(tvb, pinfo, do_tree, &offset, &desegment_len))
549 if (desegment_len)
551 // Wait for more data.
552 pinfo->desegment_offset = offset;
553 pinfo->desegment_len = desegment_len;
554 return tvb_reported_length(tvb);
557 else
559 // Parsing error, stop parsing
560 return tvb_captured_length(tvb);
564 return offset;
567 void
568 proto_register_do(void)
570 static hf_register_info hf[] = {
571 { &hf_do_handshake_message,
572 { "Handshake Message", "msdo.Handshake",
573 FT_NONE, BASE_NONE, NULL, 0x0,
574 NULL, HFILL }
576 { &hf_do_keepalive_message,
577 { "KeepAlive Message", "msdo.KeepAlive",
578 FT_NONE, BASE_NONE, NULL, 0x0,
579 NULL, HFILL }
581 { &hf_do_choke_message,
582 { "Choke Message", "msdo.Choke",
583 FT_NONE, BASE_NONE, NULL, 0x0,
584 NULL, HFILL }
586 { &hf_do_unchoke_message,
587 { "UnChoke Message", "msdo.UnChoke",
588 FT_NONE, BASE_NONE, NULL, 0x0,
589 NULL, HFILL }
591 { &hf_do_interested_message,
592 { "Interested Message", "msdo.Interested",
593 FT_NONE, BASE_NONE, NULL, 0x0,
594 NULL, HFILL }
596 { &hf_do_notinterested_message,
597 { "NotInterested Message", "msdo.NotInterested",
598 FT_NONE, BASE_NONE, NULL, 0x0,
599 NULL, HFILL }
601 { &hf_do_have_message,
602 { "Have Message", "msdo.Have",
603 FT_NONE, BASE_NONE, NULL, 0x0,
604 NULL, HFILL }
606 { &hf_do_bitfield_message,
607 { "BitField Message", "msdo.BitField",
608 FT_NONE, BASE_NONE, NULL, 0x0,
609 NULL, HFILL }
611 { &hf_do_request_message,
612 { "Request Message", "msdo.Request",
613 FT_NONE, BASE_NONE, NULL, 0x0,
614 NULL, HFILL }
616 { &hf_do_piece_message,
617 { "Piece Message", "msdo.Piece",
618 FT_NONE, BASE_NONE, NULL, 0x0,
619 NULL, HFILL }
621 { &hf_do_cancel_message,
622 { "Cancel Message", "msdo.Cancel",
623 FT_NONE, BASE_NONE, NULL, 0x0,
624 NULL, HFILL }
626 { &hf_do_heap_spraying_message,
627 { "HeapSpraying Message", "msdo.HeapSpraying",
628 FT_NONE, BASE_NONE, NULL, 0x0,
629 NULL, HFILL }
631 { &hf_do_unknown_message,
632 { "Unknown Message, this shouldn't happen", "msdo.UnknownMessage",
633 FT_NONE, BASE_NONE, NULL, 0x0,
634 NULL, HFILL }
637 { &hf_do_protocol_name,
638 { "Protocol Name", "msdo.Handshake.ProtocolName",
639 FT_UINT_STRING, BASE_NONE, NULL, 0x0,
640 NULL, HFILL }
642 { &hf_do_size,
643 { "Size", "msdo.Handshake.Size",
644 FT_UINT64, BASE_HEX, NULL, 0x0,
645 NULL, HFILL }
647 { &hf_do_swarm_hash,
648 { "Swarm Hash", "msdo.Handshake.SwarmHash",
649 FT_BYTES, BASE_NONE, NULL, 0x0,
650 NULL, HFILL }
652 { &hf_do_peer_id,
653 { "Peer Id", "msdo.Handshake.PeerId",
654 FT_GUID, BASE_NONE, NULL, 0x0,
655 NULL, HFILL }
657 { &hf_do_peer_id_suffix,
658 { "Peer Id Suffix", "msdo.Handshake.PeerIdSuffix",
659 FT_UINT32, BASE_HEX, NULL, 0x0,
660 NULL, HFILL }
663 { &hf_do_message_size,
664 { "Message Size", "msdo.MessageSize",
665 FT_UINT32, BASE_HEX, NULL, 0x0,
666 NULL, HFILL }
668 { &hf_do_message_id,
669 { "Message Id", "msdo.MessageId",
670 FT_UINT32, BASE_DEC | BASE_EXT_STRING, &message_types_ext, 0x0,
671 NULL, HFILL }
674 { &hf_do_bitfield,
675 { "Bit Field", "msdo.BitField.BitField",
676 FT_BYTES, BASE_NONE, NULL, 0x0,
677 NULL, HFILL }
679 { &hf_do_bitfield_piece,
680 { "Bit Field", "msdo.BitField.Piece",
681 FT_STRINGZ, BASE_NONE, NULL, 0x0,
682 NULL, HFILL }
684 { &hf_do_has_piece,
685 { "Has Piece", "msdo.BitField.HasPiece",
686 FT_BOOLEAN, BASE_NONE, NULL, 0x0,
687 NULL, HFILL }
690 { &hf_do_piece_index,
691 { "Piece Index", "msdo.PieceIndex",
692 FT_UINT32, BASE_DEC, NULL, 0x0,
693 NULL, HFILL }
695 { &hf_do_piece_start_offset,
696 { "Piece Start Offset", "msdo.PieceStartOffset",
697 FT_UINT32, BASE_HEX, NULL, 0x0,
698 NULL, HFILL }
700 { &hf_do_piece_size,
701 { "Requested Piece Size", "msdo.PieceSize",
702 FT_UINT32, BASE_HEX, NULL, 0x0,
703 NULL, HFILL }
705 { &hf_do_piece_buffer,
706 { "Piece Buffer", "msdo.PieceBuffer",
707 FT_BYTES, BASE_NONE, NULL, 0x0,
708 NULL, HFILL }
710 { &hf_do_piece_response_size,
711 { "Response Piece Buffer Size", "msdo.PieceSize",
712 FT_UINT32, BASE_HEX, NULL, 0x0,
713 NULL, HFILL }
715 { &hf_do_heap_spraying,
716 { "Heap Spraying Buffer", "msdo.HeapSpraying.HeapSpraying",
717 FT_BYTES, BASE_NONE, NULL, 0x0,
718 NULL, HFILL }
722 static int* ett[] = {
723 &ett_do,
724 &ett_do_handshake,
725 &ett_do_message,
726 &ett_do_bitfield,
727 &ett_do_bitfield_single
730 static ei_register_info ei[] = {
731 { &ei_do_invalid_message_id, { "msdo.invalid_message_id", PI_MALFORMED, PI_WARN, "Unknown message ID", EXPFILL }},
732 { &ei_do_invalid_message_length, { "msdo.invalid_message_length", PI_MALFORMED, PI_ERROR, "Invalid message size", EXPFILL}}
735 expert_module_t* expert_do = NULL;
737 proto_do = proto_register_protocol("Microsoft Delivery Optimization", "MS-DO", "msdo");
739 proto_register_field_array(proto_do, hf, array_length(hf));
740 proto_register_subtree_array(ett, array_length(ett));
741 expert_do = expert_register_protocol(proto_do);
742 expert_register_field_array(expert_do, ei, array_length(ei));
744 do_handle = register_dissector("msdo", dissect_do, proto_do);
747 void
748 proto_reg_handoff_do(void)
750 static bool initialized = false;
752 if (!initialized)
754 dissector_add_uint("tcp.port", DO_PORT, do_handle);
756 initialized = true;