2 * Routines for D-Bus dissection
3 * Copyright 2012, Jakub Zawadzki <darkjames-ws@darkjames.pl>
7 * Protocol specification available at http://dbus.freedesktop.org/doc/dbus-specification.html
9 * Wireshark - Network traffic analyzer
10 * By Gerald Combs <gerald@wireshark.org>
11 * Copyright 1998 Gerald Combs
13 * This program is free software; you can redistribute it and/or
14 * modify it under the terms of the GNU General Public License
15 * as published by the Free Software Foundation; either version 2
16 * of the License, or (at your option) any later version.
18 * This program is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU General Public License for more details.
23 * You should have received a copy of the GNU General Public License
24 * along with this program; if not, write to the Free Software
25 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
30 #include <epan/packet.h>
31 #include <epan/strutil.h>
32 #include <epan/expert.h>
33 #include <epan/dissectors/packet-tcp.h>
35 void proto_register_dbus(void);
36 void proto_reg_handoff_dbus(void);
38 static gboolean dbus_desegment = TRUE;
40 static int hf_dbus_hdr = -1;
41 static int hf_dbus_hdr_endianness = -1;
42 static int hf_dbus_hdr_type = -1;
43 static int hf_dbus_hdr_flags = -1;
44 static int hf_dbus_hdr_version = -1;
45 static int hf_dbus_hdr_body_length = -1;
46 static int hf_dbus_hdr_serial = -1;
47 static int hf_dbus_hdr_fields_length = -1;
48 static int hf_dbus_hdr_field = -1;
49 static int hf_dbus_hdr_field_code = -1;
51 static int hf_dbus_value_bool = -1;
52 static int hf_dbus_value_int = -1;
53 static int hf_dbus_value_uint = -1;
54 static int hf_dbus_value_str = -1;
55 static int hf_dbus_value_double = -1;
57 static int hf_dbus_body = -1;
58 static int hf_dbus_type_signature = -1;
60 static int ett_dbus = -1;
61 static int ett_dbus_hdr = -1;
62 static int ett_dbus_body = -1;
63 static int ett_dbus_field = -1;
65 static expert_field ei_dbus_value_bool_invalid = EI_INIT;
66 static expert_field ei_dbus_value_str_invalid = EI_INIT;
67 static expert_field ei_dbus_invalid_object_path = EI_INIT;
68 static expert_field ei_dbus_invalid_signature = EI_INIT;
70 static int proto_dbus = -1;
72 #define DBUS_MESSAGE_TYPE_INVALID 0
73 #define DBUS_MESSAGE_TYPE_METHOD_CALL 1
74 #define DBUS_MESSAGE_TYPE_METHOD_RETURN 2
75 #define DBUS_MESSAGE_TYPE_ERROR 3
76 #define DBUS_MESSAGE_TYPE_SIGNAL 4
78 static const value_string message_type_vals[] = {
79 { DBUS_MESSAGE_TYPE_INVALID, "Invalid" },
80 { DBUS_MESSAGE_TYPE_METHOD_CALL, "Method call" },
81 { DBUS_MESSAGE_TYPE_METHOD_RETURN, "Method reply" },
82 { DBUS_MESSAGE_TYPE_ERROR, "Error reply" },
83 { DBUS_MESSAGE_TYPE_SIGNAL, "Signal emission" },
87 #define DBUS_HEADER_FIELD_INVALID 0
88 #define DBUS_HEADER_FIELD_PATH 1
89 #define DBUS_HEADER_FIELD_INTERFACE 2
90 #define DBUS_HEADER_FIELD_MEMBER 3
91 #define DBUS_HEADER_FIELD_ERROR_NAME 4
92 #define DBUS_HEADER_FIELD_REPLY_SERIAL 5
93 #define DBUS_HEADER_FIELD_DESTINATION 6
94 #define DBUS_HEADER_FIELD_SENDER 7
95 #define DBUS_HEADER_FIELD_SIGNATURE 8
96 #define DBUS_HEADER_FIELD_UNIX_FDS 9
98 static const value_string field_code_vals[] = {
99 { DBUS_HEADER_FIELD_INVALID, "INVALID" },
100 { DBUS_HEADER_FIELD_PATH, "PATH" },
101 { DBUS_HEADER_FIELD_INTERFACE, "INTERFACE" },
102 { DBUS_HEADER_FIELD_MEMBER, "MEMBER" },
103 { DBUS_HEADER_FIELD_ERROR_NAME, "ERROR_NAME" },
104 { DBUS_HEADER_FIELD_REPLY_SERIAL, "REPLY_SERIAL" },
105 { DBUS_HEADER_FIELD_DESTINATION, "DESTINATION" },
106 { DBUS_HEADER_FIELD_SENDER, "SENDER" },
107 { DBUS_HEADER_FIELD_SIGNATURE, "SIGNATURE" },
108 { DBUS_HEADER_FIELD_UNIX_FDS, "UNIX_FDS" },
115 guint16 (*get16)(tvbuff_t *, const gint);
116 guint32 (*get32)(tvbuff_t *, const gint);
117 gdouble (*getdouble)(tvbuff_t *, const gint);
122 const char *body_sig;
132 dbus_validate_object_path(const char *path)
144 while ((*path >= 'A' && *path <= 'Z') || (*path >= 'a' && *path <= 'z') || (*path >= '0' && *path <= '9') || *path == '_')
150 } while (*path == '/');
156 dbus_validate_signature(const char *sig _U_)
163 dissect_dbus_sig(tvbuff_t *tvb, dbus_info_t *dinfo, proto_tree *tree, int offset, char sig, dbus_val_t *ret)
165 const int org_offset = offset;
173 val = tvb_get_guint8(tvb, offset);
176 proto_tree_add_uint_format(tree, hf_dbus_value_uint, tvb, org_offset, offset - org_offset, val, "BYTE: %u", val);
181 case 'b': /* BOOLEAN */
185 val = dinfo->get32(tvb, offset);
188 ti = proto_tree_add_boolean_format(tree, hf_dbus_value_bool, tvb, org_offset, offset - org_offset, val, "BOOLEAN: %s", val ? "True" : "False");
189 if (val != 0 && val != 1) {
190 expert_add_info_format_text(dinfo->pinfo, ti, &ei_dbus_value_bool_invalid, "Invalid boolean value (must be 0 or 1 is: %u)", val);
197 case 'n': /* INT16 */
201 val = (gint16 )dinfo->get16(tvb, offset);
204 proto_tree_add_uint_format(tree, hf_dbus_value_int, tvb, org_offset, offset - org_offset, val, "INT16: %d", val);
209 case 'q': /* UINT16 */
213 val = dinfo->get16(tvb, offset);
216 proto_tree_add_uint_format(tree, hf_dbus_value_uint, tvb, org_offset, offset - org_offset, val, "UINT16: %u", val);
221 case 'i': /* INT32 */
225 val = (gint32) dinfo->get32(tvb, offset);
228 proto_tree_add_int_format(tree, hf_dbus_value_int, tvb, org_offset, offset - org_offset, val, "INT32: %d", val);
233 case 'u': /* UINT32 */
237 val = dinfo->get32(tvb, offset);
240 proto_tree_add_uint_format(tree, hf_dbus_value_uint, tvb, org_offset, offset - org_offset, val, "UINT32: %u", val);
245 case 'x': /* INT64 */
246 case 't': /* UINT64 */
249 case 'd': /* DOUBLE */
253 val = dinfo->getdouble(tvb, offset);
256 proto_tree_add_double_format(tree, hf_dbus_value_double, tvb, org_offset, offset - org_offset, val, "DOUBLE: %." STRINGIFY(DBL_DIG) "g", val);
261 case 's': /* STRING */
262 case 'o': /* OBJECT_PATH */
267 len = dinfo->get32(tvb, offset);
270 val = tvb_get_ephemeral_string(tvb, offset, len);
271 offset += (len + 1 /* NUL-byte */ + 3) & ~3;
274 ti = proto_tree_add_string_format(tree, hf_dbus_value_str, tvb, org_offset, offset - org_offset, val, "STRING: %s", val);
275 if (!g_utf8_validate(val, -1, NULL)) {
276 expert_add_info(dinfo->pinfo, ti, &ei_dbus_value_str_invalid);
280 ti = proto_tree_add_string_format(tree, hf_dbus_value_str, tvb, org_offset, offset - org_offset, val, "OBJECT_PATH: %s", val);
281 if (!dbus_validate_object_path(val)) {
282 expert_add_info(dinfo->pinfo, ti, &ei_dbus_invalid_object_path);
290 case 'g': /* SIGNATURE */
295 len = tvb_get_guint8(tvb, offset);
298 val = tvb_get_ephemeral_string(tvb, offset, len);
301 ti = proto_tree_add_string_format(tree, hf_dbus_value_str, tvb, org_offset, offset - org_offset, val, "SIGNATURE: %s", val);
302 if (!dbus_validate_signature(val)) {
303 expert_add_info(dinfo->pinfo, ti, &ei_dbus_invalid_signature);
316 dissect_dbus_field_signature(tvbuff_t *tvb, dbus_info_t *dinfo, proto_tree *tree, int offset, int field_code)
318 const int org_offset = offset;
324 sig_len = tvb_get_guint8(tvb, offset);
327 /* sig_len = tvb_strsize(tvb, offset); */
329 sig = tvb_get_ephemeral_string(tvb, offset, sig_len);
330 offset += (sig_len + 1);
332 ti = proto_tree_add_string(tree, hf_dbus_type_signature, tvb, org_offset, offset - org_offset, sig);
333 if (!dbus_validate_signature(sig)) {
334 expert_add_info(dinfo->pinfo, ti, &ei_dbus_invalid_signature);
338 switch (field_code) {
339 case DBUS_HEADER_FIELD_REPLY_SERIAL:
340 if (!strcmp(sig, "u")) { /* UINT32 */
341 dbus_val_t serial_val;
343 offset = dissect_dbus_sig(tvb, dinfo, tree, offset, 'u', &serial_val);
345 { /* XXX link with sending frame (serial_val.uint) */ }
350 case DBUS_HEADER_FIELD_DESTINATION:
351 case DBUS_HEADER_FIELD_SENDER:
352 if (!strcmp(sig, "s")) { /* STRING */
355 offset = dissect_dbus_sig(tvb, dinfo, tree, offset, 's', &addr_val);
357 SET_ADDRESS((field_code == DBUS_HEADER_FIELD_DESTINATION) ? &dinfo->pinfo->dst : &dinfo->pinfo->src,
358 AT_STRINGZ, (int)strlen(addr_val.str)+1, addr_val.str);
363 case DBUS_HEADER_FIELD_SIGNATURE:
364 if (!strcmp(sig, "g")) { /* SIGNATURE */
367 offset = dissect_dbus_sig(tvb, dinfo, tree, offset, 'g', &sig_val);
369 dinfo->body_sig = sig_val.str;
378 offset = dissect_dbus_sig(tvb, dinfo, tree, offset, *sig, &val);
387 dissect_dbus_hdr_fields(tvbuff_t *tvb, dbus_info_t *dinfo, proto_tree *tree, int offset)
391 end_offset = offset + dinfo->fields_len;
393 while (offset < end_offset) {
394 proto_tree *field_tree;
399 ti = proto_tree_add_item(tree, hf_dbus_hdr_field, tvb, offset, 0, ENC_NA);
400 field_tree = proto_item_add_subtree(ti, ett_dbus_field);
402 field_code = tvb_get_guint8(tvb, offset);
403 proto_tree_add_item(field_tree, hf_dbus_hdr_field_code, tvb, offset, 1, dinfo->enc);
404 proto_item_append_text(ti, ": %s", val_to_str(field_code, field_code_vals, "Unknown: %d"));
407 offset = dissect_dbus_field_signature(tvb, dinfo, field_tree, offset, field_code);
411 offset = (offset + 7) & ~7; /* XXX ? */
413 proto_item_set_end(ti, tvb, offset);
416 /* XXX, verify if all required fields are preset */
418 if (offset >= end_offset) {
426 dissect_dbus_hdr(tvbuff_t *tvb, dbus_info_t *dinfo, proto_tree *tree, int offset)
428 proto_tree *hdr_tree;
433 ti = proto_tree_add_item(tree, hf_dbus_hdr, tvb, offset, 0, ENC_NA);
434 hdr_tree = proto_item_add_subtree(ti, ett_dbus_hdr);
436 proto_tree_add_item(hdr_tree, hf_dbus_hdr_endianness, tvb, offset, 1, ENC_ASCII | ENC_NA);
439 type = tvb_get_guint8(tvb, offset);
440 col_add_str(dinfo->pinfo->cinfo, COL_INFO, val_to_str_const(type, message_type_vals, ""));
441 proto_tree_add_item(hdr_tree, hf_dbus_hdr_type, tvb, offset, 1, dinfo->enc);
444 proto_tree_add_item(hdr_tree, hf_dbus_hdr_flags, tvb, offset, 1, dinfo->enc);
447 proto_tree_add_item(hdr_tree, hf_dbus_hdr_version, tvb, offset, 1, dinfo->enc);
450 dinfo->body_len = dinfo->get32(tvb, offset);
451 proto_tree_add_item(hdr_tree, hf_dbus_hdr_body_length, tvb, offset, 4, dinfo->enc);
454 proto_tree_add_item(hdr_tree, hf_dbus_hdr_serial, tvb, offset, 4, dinfo->enc);
457 dinfo->fields_len = dinfo->get32(tvb, offset);
458 proto_tree_add_item(hdr_tree, hf_dbus_hdr_fields_length, tvb, offset, 4, dinfo->enc);
465 dissect_dbus_body(tvbuff_t *tvb, dbus_info_t *dinfo, proto_tree *tree, int offset)
467 proto_tree *body_tree;
470 if (dinfo->body_len && dinfo->body_sig[0]) {
471 const char *sig = dinfo->body_sig;
473 ti = proto_tree_add_item(tree, hf_dbus_body, tvb, offset, 0, ENC_NA);
474 body_tree = proto_item_add_subtree(ti, ett_dbus_body);
479 offset = dissect_dbus_sig(tvb, dinfo, body_tree, offset, *sig, &val);
485 proto_item_set_end(ti, tvb, offset);
487 } else if (dinfo->body_len || dinfo->body_sig[0]) {
494 dissect_dbus(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
496 proto_tree *dbus_tree = NULL;
501 col_set_str(pinfo->cinfo, COL_PROTOCOL, "D-BUS");
502 col_clear(pinfo->cinfo, COL_INFO);
504 memset(&dinfo, 0, sizeof(dinfo));
506 switch (tvb_get_guint8(tvb, 0)) {
508 dinfo.enc = ENC_LITTLE_ENDIAN;
509 dinfo.get16 = tvb_get_letohs;
510 dinfo.get32 = tvb_get_letohl;
511 dinfo.getdouble = tvb_get_letohieee_double;
514 dinfo.enc = ENC_BIG_ENDIAN;
515 dinfo.get16 = tvb_get_ntohs;
516 dinfo.get32 = tvb_get_ntohl;
517 dinfo.getdouble = tvb_get_ntohieee_double;
519 default: /* same as BIG_ENDIAN */
520 /* XXX we should probably return 0; */
522 dinfo.get16 = tvb_get_ntohs;
523 dinfo.get32 = tvb_get_ntohl;
524 dinfo.getdouble = tvb_get_ntohieee_double;
528 proto_item *ti = proto_tree_add_item(tree, proto_dbus, tvb, 0, -1, ENC_NA);
529 dbus_tree = proto_item_add_subtree(ti, ett_dbus);
533 offset = dissect_dbus_hdr(tvb, &dinfo, dbus_tree, offset);
534 offset = dissect_dbus_hdr_fields(tvb, &dinfo, dbus_tree, offset);
535 /* header aligned to 8B */
536 offset = (offset + 7) & ~7;
541 offset = dissect_dbus_body(tvb, &dinfo, dbus_tree, offset);
546 #define DBUS_HEADER_LEN 16
549 get_dbus_message_len(packet_info *pinfo _U_, tvbuff_t *tvb, int offset)
551 guint32 (*get_guint32)(tvbuff_t *, const gint);
553 guint32 len_body, len_hdr;
555 switch (tvb_get_guint8(tvb, offset)) {
557 get_guint32 = tvb_get_letohl;
561 get_guint32 = tvb_get_ntohl;
565 len_hdr = DBUS_HEADER_LEN + get_guint32(tvb, offset + 12);
566 len_hdr = (len_hdr + 7) & ~7;
567 len_body = get_guint32(tvb, offset + 4);
569 return len_hdr + len_body;
573 dissect_dbus_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
575 dissect_dbus(tvb, pinfo, tree, NULL);
579 dissect_dbus_tcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
581 tcp_dissect_pdus(tvb, pinfo, tree, dbus_desegment, DBUS_HEADER_LEN, get_dbus_message_len, dissect_dbus_pdu);
582 return tvb_length(tvb);
586 proto_register_dbus(void)
588 /* XXX, FT_NONE -> FT_BYTES? */
589 static hf_register_info hf[] = {
592 { "Header", "dbus.header", FT_NONE, BASE_NONE, NULL, 0x00, NULL, HFILL }
594 { &hf_dbus_hdr_endianness,
595 { "Endianness Flag", "dbus.endianness", FT_STRING, BASE_NONE, NULL, 0x00, NULL, HFILL }
598 { "Message Type", "dbus.type", FT_UINT8, BASE_DEC, VALS(message_type_vals), 0x00, NULL, HFILL }
600 { &hf_dbus_hdr_flags,
601 { "Message Flags", "dbus.flags", FT_UINT8, BASE_HEX, NULL, 0x00, NULL, HFILL }
603 { &hf_dbus_hdr_version,
604 { "Protocol Version", "dbus.version", FT_UINT8, BASE_DEC, NULL, 0x00, NULL, HFILL }
606 { &hf_dbus_hdr_body_length,
607 { "Message body Length", "dbus.length", FT_UINT32, BASE_DEC, NULL, 0x00, NULL, HFILL }
609 { &hf_dbus_hdr_serial,
610 { "Message Serial (cookie)", "dbus.serial", FT_UINT32, BASE_DEC, NULL, 0x00, NULL, HFILL }
612 { &hf_dbus_hdr_fields_length,
613 { "Header fields Length", "dbus.fields_length", FT_UINT32, BASE_DEC, NULL, 0x00, NULL, HFILL }
616 { &hf_dbus_hdr_field,
617 { "Header Field", "dbus.field", FT_NONE, BASE_NONE, NULL, 0x00, NULL, HFILL }
619 { &hf_dbus_hdr_field_code,
620 { "Field code", "dbus.field.code", FT_UINT8, BASE_DEC, VALS(field_code_vals), 0x00, NULL, HFILL }
623 { &hf_dbus_type_signature,
624 { "Type signature", "dbus.type_signature", FT_STRINGZ, BASE_NONE, NULL, 0x00, NULL, HFILL }
628 { "Body", "dbus.body", FT_NONE, BASE_NONE, NULL, 0x00, NULL, HFILL }
632 { &hf_dbus_value_bool,
633 { "Value", "dbus.value.bool", FT_BOOLEAN, BASE_NONE, NULL, 0x00, NULL, HFILL }
635 { &hf_dbus_value_int,
636 { "Value", "dbus.value.int", FT_INT32, BASE_DEC, NULL, 0x00, NULL, HFILL }
638 { &hf_dbus_value_uint,
639 { "Value", "dbus.value.uint", FT_UINT32, BASE_DEC, NULL, 0x00, NULL, HFILL }
641 { &hf_dbus_value_str,
642 { "Value", "dbus.value.str", FT_STRING, BASE_NONE, NULL, 0x00, NULL, HFILL }
644 { &hf_dbus_value_double,
645 { "Value", "dbus.value.double", FT_DOUBLE, BASE_NONE, NULL, 0x00, NULL, HFILL }
649 static gint *ett[] = {
656 static ei_register_info ei[] = {
657 { &ei_dbus_value_bool_invalid, { "dbus.value.bool.invalid", PI_PROTOCOL, PI_WARN, "Invalid boolean value", EXPFILL }},
658 { &ei_dbus_value_str_invalid, { "dbus.value.str.invalid", PI_PROTOCOL, PI_WARN, "Invalid string (not UTF-8)", EXPFILL }},
659 { &ei_dbus_invalid_object_path, { "dbus.invalid_object_path", PI_PROTOCOL, PI_WARN, "Invalid object_path", EXPFILL }},
660 { &ei_dbus_invalid_signature, { "dbus.invalid_signature", PI_PROTOCOL, PI_WARN, "Invalid signature", EXPFILL }},
663 expert_module_t* expert_dbus;
665 proto_dbus = proto_register_protocol("D-Bus", "D-BUS", "dbus");
667 proto_register_field_array(proto_dbus, hf, array_length(hf));
668 proto_register_subtree_array(ett, array_length(ett));
669 expert_dbus = expert_register_protocol(proto_dbus);
670 expert_register_field_array(expert_dbus, ei, array_length(ei));
674 proto_reg_handoff_dbus(void)
676 dissector_handle_t dbus_handle = new_create_dissector_handle(dissect_dbus, proto_dbus);
677 dissector_handle_t dbus_handle_tcp = new_create_dissector_handle(dissect_dbus_tcp, proto_dbus);
679 dissector_add_uint("wtap_encap", WTAP_ENCAP_DBUS, dbus_handle);
680 dissector_add_handle("tcp.port", dbus_handle_tcp);