2 * Routines for RDP multi transport packet dissection
3 * Copyright 2021, David Fort
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
14 #include <epan/packet.h>
15 #include <epan/prefs.h>
16 #include <epan/expert.h>
17 #include <epan/conversation.h>
19 #include "packet-rdp.h"
20 #include "packet-rdpudp.h"
22 #define PNAME "Remote Desktop Protocol Multi-transport"
23 #define PSNAME "RDPMT"
24 #define PFNAME "rdpmt"
26 void proto_register_rdpmt(void);
27 void proto_reg_handoff_rdpmt(void);
29 static dissector_handle_t rdpmt_handle
;
31 static int proto_rdpmt
;
33 static int hf_rdpmt_action
;
34 static int hf_rdpmt_flags
;
35 static int hf_rdpmt_payload_len
;
36 static int hf_rdpmt_header_len
;
37 static int hf_rdpmt_subheader_len
;
38 static int hf_rdpmt_subheader_type
;
39 static int hf_rdpmt_createreq_reqId
;
40 static int hf_rdpmt_createreq_reserved
;
41 static int hf_rdpmt_createreq_cookie
;
42 static int hf_rdpmt_createresp_hrResponse
;
45 static int ett_rdpudp_subheaders
;
46 static int ett_rdpmt_create_req
;
47 static int ett_rdpmt_create_resp
;
48 static int ett_rdpmt_data
;
50 static dissector_handle_t drdynvcDissector
;
52 static const value_string rdpmt_action_vals
[] = {
53 { 0x00, "CreateRequest"},
54 { 0x01, "CreateResponse"},
59 static const value_string rdpmt_subheader_type_vals
[] = {
60 { 0x0, "auto detect request" },
61 { 0x1, "auto detect response" },
66 RDPMT_TUNNEL_CREATE_REQ
= 0,
67 RDPMT_TUNNEL_CREATE_RESP
= 1,
68 RDPMT_TUNNEL_DATA
= 2,
72 dissect_rdpmt(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*parent_tree
, void *data _U_
)
75 proto_tree
*tree
, *subtree
;
76 uint8_t action
, subheader_len
;
80 item
= proto_tree_add_item(parent_tree
, proto_rdpmt
, tvb
, 0, -1, ENC_NA
);
81 tree
= proto_item_add_subtree(item
, ett_rdpmt
);
83 action
= tvb_get_uint8(tvb
, offset
) & 0x0f;
84 proto_tree_add_item(tree
, hf_rdpmt_action
, tvb
, offset
, 1, ENC_NA
);
85 proto_tree_add_item(tree
, hf_rdpmt_flags
, tvb
, offset
, 1, ENC_NA
);
88 payload_len
= tvb_get_uint16(tvb
, offset
, ENC_LITTLE_ENDIAN
);
89 proto_tree_add_item(tree
, hf_rdpmt_payload_len
, tvb
, offset
, 2, ENC_LITTLE_ENDIAN
);
92 subheader_len
= tvb_get_uint8(tvb
, offset
);
93 proto_tree_add_item(tree
, hf_rdpmt_header_len
, tvb
, offset
, 1, ENC_NA
);
96 if (subheader_len
> 4) {
97 tvbuff_t
*subheaders
= tvb_new_subset_length(tvb
, offset
, subheader_len
-4);
98 proto_tree
*subheaders_tree
= proto_tree_add_subtree(tree
, tvb
, offset
, -1, ett_rdpudp_subheaders
, NULL
, "SubHeaders");
99 dissect_rdp_bandwidth_req(subheaders
, 0, pinfo
, subheaders_tree
, !!rdp_isServerAddressTarget(pinfo
));
103 offset
+= subheader_len
- 4;
106 case RDPMT_TUNNEL_CREATE_REQ
: {
109 conversation_t
*conv
= find_or_create_conversation(pinfo
);
111 col_set_str(pinfo
->cinfo
, COL_INFO
, "TunnelCreateRequest");
113 subtree
= proto_tree_add_subtree(tree
, tvb
, offset
, payload_len
, ett_rdpmt_create_req
, NULL
, "TunnelCreateRequest");
114 proto_tree_add_item(subtree
, hf_rdpmt_createreq_reqId
, tvb
, offset
, 4, ENC_LITTLE_ENDIAN
);
115 reqId
= tvb_get_uint32(tvb
, offset
, ENC_LITTLE_ENDIAN
);
118 proto_tree_add_item(subtree
, hf_rdpmt_createreq_reserved
, tvb
, offset
, 4, ENC_LITTLE_ENDIAN
);
121 proto_tree_add_item(subtree
, hf_rdpmt_createreq_cookie
, tvb
, offset
, 16, ENC_NA
);
122 tvb_memcpy(tvb
, cookie
, offset
, 16);
125 rdp_transport_set_udp_conversation(&pinfo
->dst
, pinfo
->destport
, rdpudp_is_reliable_transport(pinfo
), reqId
, cookie
, conv
);
128 case RDPMT_TUNNEL_CREATE_RESP
:
129 col_set_str(pinfo
->cinfo
, COL_INFO
, "TunnelCreateResponse");
130 subtree
= proto_tree_add_subtree(tree
, tvb
, offset
, payload_len
, ett_rdpmt_create_resp
, NULL
, "TunnelCreateResponse");
131 proto_tree_add_item(subtree
, hf_rdpmt_createresp_hrResponse
, tvb
, offset
, 4, ENC_LITTLE_ENDIAN
);
134 case RDPMT_TUNNEL_DATA
:
136 tvbuff_t
*payload
= tvb_new_subset_length(tvb
, offset
, payload_len
);
137 subtree
= proto_tree_add_subtree(tree
, tvb
, offset
, -1, ett_rdpmt_data
, NULL
, "Data");
138 call_dissector(drdynvcDissector
, payload
, pinfo
, subtree
);
147 proto_register_rdpmt(void) {
149 static hf_register_info hf
[] = {
152 {"Action", "rdpmt.action", FT_UINT8
, BASE_HEX
, VALS(rdpmt_action_vals
), 0x0F, NULL
, HFILL
}
155 {"Flags", "rdpmt.flags", FT_UINT8
, BASE_HEX
, NULL
, 0xF0, NULL
, HFILL
}
157 {&hf_rdpmt_payload_len
,
158 {"Payload length", "rdpmt.payloadlen", FT_UINT16
, BASE_DEC
, NULL
, 0, NULL
, HFILL
}
160 {&hf_rdpmt_header_len
,
161 {"Header length", "rdpmt.headerlen", FT_UINT8
, BASE_DEC
, NULL
, 0, NULL
, HFILL
}
163 {&hf_rdpmt_subheader_len
,
164 {"Sub header length", "rdpmt.subheaderlen", FT_UINT8
, BASE_DEC
, NULL
, 0, NULL
, HFILL
}
166 {&hf_rdpmt_subheader_type
,
167 {"Sub header type", "rdpmt.subheadertype", FT_UINT8
, BASE_HEX
, VALS(rdpmt_subheader_type_vals
), 0, NULL
, HFILL
}
169 {&hf_rdpmt_createreq_reqId
,
170 {"RequestID", "rdpmt.createrequest.requestid", FT_UINT32
, BASE_HEX
, NULL
, 0, NULL
, HFILL
}
172 {&hf_rdpmt_createreq_reserved
,
173 {"Reserved", "rdpmt.createrequest.reserved", FT_UINT32
, BASE_HEX
, NULL
, 0, NULL
, HFILL
}
175 {&hf_rdpmt_createreq_cookie
,
176 {"Security cookie", "rdpmt.createrequest.cookie", FT_BYTES
, BASE_NONE
, NULL
, 0, NULL
, HFILL
}
178 {&hf_rdpmt_createresp_hrResponse
,
179 {"hrResponse", "rdpmt.createresponse.hrresponse", FT_INT32
, BASE_DEC
, NULL
, 0, NULL
, HFILL
}
183 /* List of subtrees */
184 static int *ett
[] = {
186 &ett_rdpudp_subheaders
,
187 &ett_rdpmt_create_req
,
188 &ett_rdpmt_create_resp
,
192 /* Register protocol */
193 proto_rdpmt
= proto_register_protocol(PNAME
, PSNAME
, PFNAME
);
194 /* Register fields and subtrees */
195 proto_register_field_array(proto_rdpmt
, hf
, array_length(hf
));
196 proto_register_subtree_array(ett
, array_length(ett
));
198 rdpmt_handle
= register_dissector("rdpmt", dissect_rdpmt
, proto_rdpmt
);
202 rdpmt_heur(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void *data
)
204 uint8_t action
, header_len
;
205 uint16_t payload_len
;
207 if (tvb_reported_length(tvb
) <= 4)
210 action
= tvb_get_uint8(tvb
, 0);
214 payload_len
= tvb_get_uint16(tvb
, 1, ENC_LITTLE_ENDIAN
);
215 header_len
= tvb_get_uint8(tvb
, 3);
217 if ((header_len
< 4UL) || (tvb_reported_length_remaining(tvb
, header_len
) < payload_len
))
220 if (header_len
> 4) {
221 uint8_t subheader_len
, subheader_type
;
226 subheader_len
= tvb_get_uint8(tvb
, 4);
227 if ((subheader_len
< 2) || (subheader_len
> header_len
-4))
230 subheader_type
= tvb_get_uint8(tvb
, 5);
231 if (subheader_type
> 1) /* AUTODETECT_REQUEST or AUTODETECT_RESPONSE */
235 return dissect_rdpmt(tvb
, pinfo
, tree
, data
) > 0;
239 proto_reg_handoff_rdpmt(void)
241 drdynvcDissector
= find_dissector("rdp_drdynvc");
243 heur_dissector_add("tls", rdpmt_heur
, "RDP MultiTransport", "rdpmt_tls_", proto_rdpmt
, true);
244 heur_dissector_add("dtls", rdpmt_heur
, "RDP MultiTransport", "rdpmt_dtls", proto_rdpmt
, true);
248 * Editor modelines - https://www.wireshark.org/tools/modelines.html
253 * indent-tabs-mode: nil
256 * ex: set shiftwidth=2 tabstop=8 expandtab:
257 * :indentSize=2:tabSize=8:noTabs=true: