Revert "TODO epan/dissectors/asn1/kerberos/packet-kerberos-template.c new GSS flags"
[wireshark-sm.git] / epan / dissectors / packet-adb_cs.c
blob00297d37fb9b128a187bf2e8701771c70ef6f6e1
1 /* packet-adb_cs.c
2 * Routines for Android Debug Bridge Client-Server Protocol
4 * Copyright 2014, Michal Labedzki for Tieto Corporation
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
13 #include "config.h"
15 #include <epan/packet.h>
16 #include <epan/prefs.h>
17 #include <epan/expert.h>
18 #include <wiretap/wtap.h>
20 #include "packet-adb_service.h"
22 static int proto_adb_cs;
24 static int hf_role;
25 static int hf_hex_ascii_length;
26 static int hf_length;
27 static int hf_service;
28 static int hf_status;
29 static int hf_data;
30 static int hf_fail_reason;
32 static int ett_adb_cs;
33 static int ett_length;
35 static expert_field ei_incomplete_message;
37 static dissector_handle_t adb_cs_handle;
38 static dissector_handle_t adb_service_handle;
40 static wmem_tree_t *client_requests;
42 static unsigned server_port = 5037;
44 typedef struct _client_request_t {
45 int64_t service_length;
46 char *service;
47 uint32_t first_in;
48 int64_t service_in;
49 int64_t response_frame;
51 uint8_t status;
52 int64_t data_length;
53 } client_request_t;
55 static const value_string role_vals[] = {
56 { 0x00, "Unknown" },
57 { 0x01, "Server" },
58 { 0x02, "Client" },
59 { 0, NULL }
62 #define SERVICE_NONE NULL
64 #define STATUS_UNKNOWN 0
65 #define STATUS_OKAY 1
66 #define STATUS_FAIL 2
68 void proto_register_adb_cs(void);
69 void proto_reg_handoff_adb_cs(void);
71 static int
72 dissect_adb_cs(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
74 proto_item *main_item;
75 proto_tree *main_tree;
76 proto_item *sub_item;
77 proto_item *p_item;
78 int offset = 0;
79 int64_t length = -1;
80 int direction;
81 bool client_request_service = false;
82 tvbuff_t *next_tvb;
83 adb_service_data_t adb_service_data;
84 uint32_t wireshark_interface_id = 0;
86 col_set_str(pinfo->cinfo, COL_PROTOCOL, "ADB CS");
87 col_clear(pinfo->cinfo, COL_INFO);
89 main_item = proto_tree_add_item(tree, proto_adb_cs, tvb, offset, -1, ENC_NA);
90 main_tree = proto_item_add_subtree(main_item, ett_adb_cs);
92 if (pinfo->rec->presence_flags & WTAP_HAS_INTERFACE_ID)
93 wireshark_interface_id = pinfo->rec->rec_header.packet_header.interface_id;
95 if (pinfo->destport == server_port) { /* Client sent to Server */
96 client_request_t *client_request;
97 char *service = SERVICE_NONE;
98 wmem_tree_t *subtree;
99 wmem_tree_key_t key[5];
101 direction = P2P_DIR_SENT;
103 p_item = proto_tree_add_uint(main_tree, hf_role, tvb, offset, 0, 0x02);
104 proto_item_set_generated(p_item);
106 col_set_str(pinfo->cinfo, COL_INFO, "Client");
108 if (pinfo->rec->presence_flags & WTAP_HAS_INTERFACE_ID)
109 wireshark_interface_id = pinfo->rec->rec_header.packet_header.interface_id;
111 key[0].length = 1;
112 key[0].key = &wireshark_interface_id;
113 key[1].length = 1;
114 key[1].key = &pinfo->srcport;
115 key[2].length = 1;
116 key[2].key = &pinfo->destport;
117 key[3].length = 0;
118 key[3].key = NULL;
120 subtree = (wmem_tree_t *) wmem_tree_lookup32_array(client_requests, key);
121 client_request = (subtree) ? (client_request_t *) wmem_tree_lookup32_le(subtree, pinfo->num) : NULL;
122 if (client_request && client_request->service_in > -1 && client_request->service_in < pinfo->num) {
123 p_item = proto_tree_add_string(main_tree, hf_service, tvb, offset, 0, client_request->service);
124 proto_item_set_generated(p_item);
125 service = client_request->service;
126 client_request_service = true;
127 } else {
128 if (client_request && client_request->service_in > -1 && client_request->service_in <= pinfo->num)
129 client_request_service = true;
130 client_request = NULL;
133 /* heuristic to recognize type of (partial) packet */
134 if (tvb_reported_length_remaining(tvb, offset) >= 4) {
135 uint8_t hex_ascii_length[5];
136 uint32_t ulength;
138 hex_ascii_length[4] = 0;
140 tvb_memcpy(tvb, hex_ascii_length, offset, 4);
141 if (g_ascii_xdigit_value(hex_ascii_length[0]) >= 0 &&
142 g_ascii_xdigit_value(hex_ascii_length[1]) >= 0 &&
143 g_ascii_xdigit_value(hex_ascii_length[2]) >= 0 &&
144 g_ascii_xdigit_value(hex_ascii_length[3]) >= 0) {
145 /* probably 4 bytes ascii hex length field */
146 offset = dissect_ascii_uint32(main_tree, hf_hex_ascii_length, ett_length, hf_length, tvb, offset, &ulength);
147 length = (int64_t) ulength;
148 col_append_fstr(pinfo->cinfo, COL_INFO, " Length=%u", ulength);
153 if (length == -1 && service) {
154 col_append_fstr(pinfo->cinfo, COL_INFO, " Service=<%s>", service);
156 /* Decode services */
157 adb_service_data.service = service;
158 adb_service_data.direction = direction;
160 adb_service_data.session_key_length = 3;
161 adb_service_data.session_key = (uint32_t *) wmem_alloc(pinfo->pool, adb_service_data.session_key_length * sizeof(uint32_t));
162 adb_service_data.session_key[0] = wireshark_interface_id;
163 adb_service_data.session_key[1] = pinfo->destport;
164 adb_service_data.session_key[2] = pinfo->srcport;
166 next_tvb = tvb_new_subset_remaining(tvb, offset);
167 call_dissector_with_data(adb_service_handle, next_tvb, pinfo, tree, &adb_service_data);
169 return tvb_captured_length(tvb);
172 if (!pinfo->fd->visited && length > 0) { /* save Length to client_requests */
173 if (pinfo->rec->presence_flags & WTAP_HAS_INTERFACE_ID)
174 wireshark_interface_id = pinfo->rec->rec_header.packet_header.interface_id;
176 key[0].length = 1;
177 key[0].key = &wireshark_interface_id;
178 key[1].length = 1;
179 key[1].key = &pinfo->srcport;
180 key[2].length = 1;
181 key[2].key = &pinfo->destport;
182 key[3].length = 1;
183 key[3].key = &pinfo->num;
184 key[4].length = 0;
185 key[4].key = NULL;
187 client_request = wmem_new(wmem_file_scope(), client_request_t);
189 client_request->service_length = length;
190 client_request->service = SERVICE_NONE;
191 client_request->response_frame = -1;
192 client_request->first_in = pinfo->num;
193 client_request->service_in = -1;
194 client_request->data_length = -1;
195 wmem_tree_insert32_array(client_requests, key, client_request);
198 if (!pinfo->fd->visited && (length == -1 || (client_request && client_request->service_in == -1 && tvb_reported_length_remaining(tvb, offset) > 0))) { /* save Service to client_requests */
199 if (!client_request) {
200 if (pinfo->rec->presence_flags & WTAP_HAS_INTERFACE_ID)
201 wireshark_interface_id = pinfo->rec->rec_header.packet_header.interface_id;
203 key[0].length = 1;
204 key[0].key = &wireshark_interface_id;
205 key[1].length = 1;
206 key[1].key = &pinfo->srcport;
207 key[2].length = 1;
208 key[2].key = &pinfo->destport;
209 key[3].length = 0;
210 key[3].key = NULL;
212 subtree = (wmem_tree_t *) wmem_tree_lookup32_array(client_requests, key);
213 client_request = (subtree) ? (client_request_t *) wmem_tree_lookup32_le(subtree, pinfo->num - 1) : NULL;
216 if (client_request) {
218 * I've no idea why the length is 64 bits, but that's
219 * too big to be a field length in Wireshark; if it's
220 * greater than the biggest possible length, clamp it
221 * at the biggest possible length - which is probably
222 * going to be bigger than the available data so that
223 * you'll throw an exception.
225 int service_length;
226 if (client_request->service_length <= INT_MAX)
227 service_length = (int)client_request->service_length;
228 else
229 service_length = INT_MAX;
230 client_request->service = (char *) tvb_get_string_enc(wmem_file_scope(), tvb, offset, service_length, ENC_ASCII);
231 client_request->service_in = pinfo->num;
235 if (!client_request_service && tvb_reported_length_remaining(tvb, offset) > 0) {
236 col_append_str(pinfo->cinfo, COL_INFO, " Unknown service");
237 proto_tree_add_item(main_tree, hf_data, tvb, offset, -1, ENC_NA);
238 } else if (tvb_reported_length_remaining(tvb, offset) > 0) {
239 proto_tree_add_item(main_tree, hf_service, tvb, offset, -1, ENC_NA | ENC_ASCII);
241 service = (char *) tvb_get_string_enc(pinfo->pool, tvb, offset, tvb_reported_length_remaining(tvb, offset), ENC_ASCII);
242 col_append_fstr(pinfo->cinfo, COL_INFO, " Service=<%s>", service);
245 offset = tvb_captured_length(tvb);
247 } else if (pinfo->srcport == server_port) { /* Server sent to Client */
248 char *service = SERVICE_NONE;
249 wmem_tree_t *subtree;
250 wmem_tree_key_t key[5];
251 client_request_t *client_request;
252 int64_t response_frame = -1;
253 uint8_t status = STATUS_UNKNOWN;
255 direction = P2P_DIR_RECV;
257 key[0].length = 1;
258 key[0].key = &wireshark_interface_id;
259 key[1].length = 1;
260 key[1].key = &pinfo->destport;
261 key[2].length = 1;
262 key[2].key = &pinfo->srcport;
263 key[3].length = 0;
264 key[3].key = NULL;
266 subtree = (wmem_tree_t *) wmem_tree_lookup32_array(client_requests, key);
267 client_request = (subtree) ? (client_request_t *) wmem_tree_lookup32_le(subtree, pinfo->num - 1) : NULL;
268 if (client_request) {
269 service = client_request->service;
270 status = client_request->status;
271 length = client_request->data_length;
272 response_frame = client_request->response_frame;
275 p_item = proto_tree_add_uint(main_tree, hf_role, tvb, offset, 0, 0x01);
276 proto_item_set_generated(p_item);
278 p_item = proto_tree_add_string(main_tree, hf_service, tvb, offset, 0, service);
279 proto_item_set_generated(p_item);
281 col_set_str(pinfo->cinfo, COL_INFO, "Server");
283 if (!service) {
284 col_append_str(pinfo->cinfo, COL_INFO, " Unknown service");
285 proto_tree_add_item(main_tree, hf_data, tvb, offset, -1, ENC_NA);
287 return tvb_captured_length(tvb);
290 if (response_frame == -1 || response_frame == (int64_t) pinfo->num) {
291 proto_tree_add_item(main_tree, hf_status, tvb, offset, 4, ENC_NA | ENC_ASCII);
292 col_append_fstr(pinfo->cinfo, COL_INFO, " Status=%c%c%c%c", tvb_get_uint8(tvb, offset),
293 tvb_get_uint8(tvb, offset + 1), tvb_get_uint8(tvb, offset + 2), tvb_get_uint8(tvb, offset + 3));
294 offset += 4;
296 if (tvb_memeql(tvb, offset - 4, (const uint8_t *) "FAIL", 4) == 0) {
297 uint32_t ulength;
299 offset = dissect_ascii_uint32(main_tree, hf_hex_ascii_length, ett_length, hf_length, tvb, offset, &ulength);
300 length = (int64_t) ulength;
302 status = STATUS_FAIL;
303 } else if (tvb_memeql(tvb, offset - 4, (const uint8_t *) "OKAY", 4) == 0) {
304 status = STATUS_OKAY;
305 length = -1;
308 if (!pinfo->fd->visited && client_request) {
309 client_request->response_frame = pinfo->num;
310 client_request->status = status;
311 client_request->data_length = length;
315 col_append_fstr(pinfo->cinfo, COL_INFO, " Service=<%s>", service);
317 if (tvb_reported_length_remaining(tvb, offset) <= 0) return offset;
319 if (status == STATUS_FAIL) {
320 const uint8_t* str;
321 sub_item = proto_tree_add_item_ret_string(main_tree, hf_fail_reason, tvb, offset,
322 tvb_reported_length_remaining(tvb, offset), ENC_NA | ENC_ASCII, pinfo->pool, &str);
323 if (length < tvb_reported_length_remaining(tvb, offset)) {
324 expert_add_info(pinfo, sub_item, &ei_incomplete_message);
327 col_append_fstr(pinfo->cinfo, COL_INFO, " Fail=<%s>", str);
328 return tvb_captured_length(tvb);
331 /* Decode services */
332 adb_service_data.service = service;
333 adb_service_data.direction = direction;
335 adb_service_data.session_key_length = 3;
336 adb_service_data.session_key = (uint32_t *) wmem_alloc(pinfo->pool, adb_service_data.session_key_length * sizeof(uint32_t));
337 adb_service_data.session_key[0] = wireshark_interface_id;
338 adb_service_data.session_key[1] = pinfo->destport;
339 adb_service_data.session_key[2] = pinfo->srcport;
341 next_tvb = tvb_new_subset_remaining(tvb, offset);
342 call_dissector_with_data(adb_service_handle, next_tvb, pinfo, tree, &adb_service_data);
343 offset = tvb_captured_length(tvb);
344 } else {
345 col_set_str(pinfo->cinfo, COL_INFO, "Unknown role");
347 p_item = proto_tree_add_uint(main_tree, hf_role, tvb, offset, 0, 0x00);
348 proto_item_set_generated(p_item);
350 next_tvb = tvb_new_subset_remaining(tvb, offset);
351 call_data_dissector(next_tvb, pinfo, main_tree);
352 offset += tvb_captured_length_remaining(tvb, offset);
355 return offset;
358 void
359 proto_register_adb_cs(void)
361 module_t *module;
362 expert_module_t *expert_module;
364 static hf_register_info hf[] = {
365 { &hf_role,
366 { "Role", "adb_cs.role",
367 FT_UINT8, BASE_HEX, VALS(role_vals), 0x00,
368 NULL, HFILL }
370 { &hf_hex_ascii_length,
371 { "Hex ASCII Length", "adb_cs.hex_ascii_length",
372 FT_STRING, BASE_NONE, NULL, 0x00,
373 NULL, HFILL }
375 { &hf_length,
376 { "Length", "adb_cs.length",
377 FT_UINT32, BASE_DEC_HEX, NULL, 0x00,
378 NULL, HFILL }
380 { &hf_service,
381 { "Service", "adb_cs.service",
382 FT_STRING, BASE_NONE, NULL, 0x00,
383 NULL, HFILL }
385 { &hf_fail_reason,
386 { "Fail Reason", "adb_cs.fail_reason",
387 FT_STRING, BASE_NONE, NULL, 0x00,
388 NULL, HFILL }
390 { &hf_status,
391 { "Status", "adb_cs.status",
392 FT_STRING, BASE_NONE, NULL, 0x00,
393 NULL, HFILL }
395 { &hf_data,
396 { "Data", "adb_cs.data",
397 FT_BYTES, BASE_NONE, NULL, 0x00,
398 NULL, HFILL }
402 static int *ett[] = {
403 &ett_adb_cs,
404 &ett_length
407 static ei_register_info ei[] = {
408 { &ei_incomplete_message, { "adb_cs.expert.incomplete_message", PI_PROTOCOL, PI_WARN, "Incomplete message", EXPFILL }},
411 client_requests = wmem_tree_new_autoreset(wmem_epan_scope(), wmem_file_scope());
413 proto_adb_cs = proto_register_protocol("Android Debug Bridge Client-Server", "ADB CS", "adb_cs");
414 adb_cs_handle = register_dissector("adb_cs", dissect_adb_cs, proto_adb_cs);
416 proto_register_field_array(proto_adb_cs, hf, array_length(hf));
417 proto_register_subtree_array(ett, array_length(ett));
418 expert_module = expert_register_protocol(proto_adb_cs);
419 expert_register_field_array(expert_module, ei, array_length(ei));
421 module = prefs_register_protocol(proto_adb_cs, NULL);
422 prefs_register_static_text_preference(module, "version",
423 "ADB CS protocol version is compatible prior to: adb 1.0.31",
424 "Version of protocol supported by this dissector.");
426 prefs_register_uint_preference(module, "server_port",
427 "Server Port",
428 "Server Port",
429 10, &server_port);
432 void
433 proto_reg_handoff_adb_cs(void)
435 adb_service_handle = find_dissector_add_dependency("adb_service", proto_adb_cs);
437 dissector_add_for_decode_as_with_preference("tcp.port", adb_cs_handle);
441 * Editor modelines - https://www.wireshark.org/tools/modelines.html
443 * Local variables:
444 * c-basic-offset: 4
445 * tab-width: 8
446 * indent-tabs-mode: nil
447 * End:
449 * vi: set shiftwidth=4 tabstop=8 expandtab:
450 * :indentSize=4:tabSize=8:noTabs=true: