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.
28 #define NEW_PROTO_TREE_API
32 #include <epan/packet.h>
33 #include <epan/expert.h>
34 #include <epan/dissectors/packet-tcp.h>
36 void proto_register_dbus(void);
37 void proto_reg_handoff_dbus(void);
39 static gboolean dbus_desegment
= TRUE
;
41 static dissector_handle_t dbus_handle
;
42 static dissector_handle_t dbus_handle_tcp
;
44 #define DBUS_MESSAGE_TYPE_INVALID 0
45 #define DBUS_MESSAGE_TYPE_METHOD_CALL 1
46 #define DBUS_MESSAGE_TYPE_METHOD_RETURN 2
47 #define DBUS_MESSAGE_TYPE_ERROR 3
48 #define DBUS_MESSAGE_TYPE_SIGNAL 4
50 static const value_string message_type_vals
[] = {
51 { DBUS_MESSAGE_TYPE_INVALID
, "Invalid" },
52 { DBUS_MESSAGE_TYPE_METHOD_CALL
, "Method call" },
53 { DBUS_MESSAGE_TYPE_METHOD_RETURN
, "Method reply" },
54 { DBUS_MESSAGE_TYPE_ERROR
, "Error reply" },
55 { DBUS_MESSAGE_TYPE_SIGNAL
, "Signal emission" },
59 #define DBUS_HEADER_FIELD_INVALID 0
60 #define DBUS_HEADER_FIELD_PATH 1
61 #define DBUS_HEADER_FIELD_INTERFACE 2
62 #define DBUS_HEADER_FIELD_MEMBER 3
63 #define DBUS_HEADER_FIELD_ERROR_NAME 4
64 #define DBUS_HEADER_FIELD_REPLY_SERIAL 5
65 #define DBUS_HEADER_FIELD_DESTINATION 6
66 #define DBUS_HEADER_FIELD_SENDER 7
67 #define DBUS_HEADER_FIELD_SIGNATURE 8
68 #define DBUS_HEADER_FIELD_UNIX_FDS 9
70 static const value_string field_code_vals
[] = {
71 { DBUS_HEADER_FIELD_INVALID
, "INVALID" },
72 { DBUS_HEADER_FIELD_PATH
, "PATH" },
73 { DBUS_HEADER_FIELD_INTERFACE
, "INTERFACE" },
74 { DBUS_HEADER_FIELD_MEMBER
, "MEMBER" },
75 { DBUS_HEADER_FIELD_ERROR_NAME
, "ERROR_NAME" },
76 { DBUS_HEADER_FIELD_REPLY_SERIAL
, "REPLY_SERIAL" },
77 { DBUS_HEADER_FIELD_DESTINATION
, "DESTINATION" },
78 { DBUS_HEADER_FIELD_SENDER
, "SENDER" },
79 { DBUS_HEADER_FIELD_SIGNATURE
, "SIGNATURE" },
80 { DBUS_HEADER_FIELD_UNIX_FDS
, "UNIX_FDS" },
84 static header_field_info
*hfi_dbus
= NULL
;
86 #define DBUS_HFI_INIT HFI_INIT(proto_dbus)
88 /* XXX, FT_NONE -> FT_BYTES? */
91 static header_field_info hfi_dbus_hdr DBUS_HFI_INIT
=
92 { "Header", "dbus.header", FT_NONE
, BASE_NONE
, NULL
, 0x00, NULL
, HFILL
};
94 static header_field_info hfi_dbus_hdr_endianness DBUS_HFI_INIT
=
95 { "Endianness Flag", "dbus.endianness", FT_STRING
, BASE_NONE
, NULL
, 0x00, NULL
, HFILL
};
97 static header_field_info hfi_dbus_hdr_type DBUS_HFI_INIT
=
98 { "Message Type", "dbus.type", FT_UINT8
, BASE_DEC
, VALS(message_type_vals
), 0x00, NULL
, HFILL
};
100 static header_field_info hfi_dbus_hdr_flags DBUS_HFI_INIT
=
101 { "Message Flags", "dbus.flags", FT_UINT8
, BASE_HEX
, NULL
, 0x00, NULL
, HFILL
};
103 static header_field_info hfi_dbus_hdr_version DBUS_HFI_INIT
=
104 { "Protocol Version", "dbus.version", FT_UINT8
, BASE_DEC
, NULL
, 0x00, NULL
, HFILL
};
106 static header_field_info hfi_dbus_hdr_body_length DBUS_HFI_INIT
=
107 { "Message body Length", "dbus.length", FT_UINT32
, BASE_DEC
, NULL
, 0x00, NULL
, HFILL
};
109 static header_field_info hfi_dbus_hdr_serial DBUS_HFI_INIT
=
110 { "Message Serial (cookie)", "dbus.serial", FT_UINT32
, BASE_DEC
, NULL
, 0x00, NULL
, HFILL
};
112 static header_field_info hfi_dbus_hdr_fields_length DBUS_HFI_INIT
=
113 { "Header fields Length", "dbus.fields_length", FT_UINT32
, BASE_DEC
, NULL
, 0x00, NULL
, HFILL
};
116 static header_field_info hfi_dbus_hdr_field DBUS_HFI_INIT
=
117 { "Header Field", "dbus.field", FT_NONE
, BASE_NONE
, NULL
, 0x00, NULL
, HFILL
};
119 static header_field_info hfi_dbus_hdr_field_code DBUS_HFI_INIT
=
120 { "Field code", "dbus.field.code", FT_UINT8
, BASE_DEC
, VALS(field_code_vals
), 0x00, NULL
, HFILL
};
122 static header_field_info hfi_dbus_type_signature DBUS_HFI_INIT
=
123 { "Type signature", "dbus.type_signature", FT_STRINGZ
, BASE_NONE
, NULL
, 0x00, NULL
, HFILL
};
125 static header_field_info hfi_dbus_body DBUS_HFI_INIT
=
126 { "Body", "dbus.body", FT_NONE
, BASE_NONE
, NULL
, 0x00, NULL
, HFILL
};
129 static header_field_info hfi_dbus_value_bool DBUS_HFI_INIT
=
130 { "Value", "dbus.value.bool", FT_BOOLEAN
, BASE_NONE
, NULL
, 0x00, NULL
, HFILL
};
132 static header_field_info hfi_dbus_value_int DBUS_HFI_INIT
=
133 { "Value", "dbus.value.int", FT_INT32
, BASE_DEC
, NULL
, 0x00, NULL
, HFILL
};
135 static header_field_info hfi_dbus_value_uint DBUS_HFI_INIT
=
136 { "Value", "dbus.value.uint", FT_UINT32
, BASE_DEC
, NULL
, 0x00, NULL
, HFILL
};
138 static header_field_info hfi_dbus_value_str DBUS_HFI_INIT
=
139 { "Value", "dbus.value.str", FT_STRING
, BASE_NONE
, NULL
, 0x00, NULL
, HFILL
};
141 static header_field_info hfi_dbus_value_double DBUS_HFI_INIT
=
142 { "Value", "dbus.value.double", FT_DOUBLE
, BASE_NONE
, NULL
, 0x00, NULL
, HFILL
};
145 static int ett_dbus
= -1;
146 static int ett_dbus_hdr
= -1;
147 static int ett_dbus_body
= -1;
148 static int ett_dbus_field
= -1;
150 static expert_field ei_dbus_value_bool_invalid
= EI_INIT
;
151 static expert_field ei_dbus_value_str_invalid
= EI_INIT
;
152 static expert_field ei_dbus_invalid_object_path
= EI_INIT
;
153 static expert_field ei_dbus_invalid_signature
= EI_INIT
;
158 guint16 (*get16
)(tvbuff_t
*, const gint
);
159 guint32 (*get32
)(tvbuff_t
*, const gint
);
160 gdouble (*getdouble
)(tvbuff_t
*, const gint
);
165 const char *body_sig
;
175 dbus_validate_object_path(const char *path
)
187 while ((*path
>= 'A' && *path
<= 'Z') || (*path
>= 'a' && *path
<= 'z') || (*path
>= '0' && *path
<= '9') || *path
== '_')
193 } while (*path
== '/');
199 dbus_validate_signature(const char *sig _U_
)
206 dissect_dbus_sig(tvbuff_t
*tvb
, dbus_info_t
*dinfo
, proto_tree
*tree
, int offset
, char sig
, dbus_val_t
*ret
)
208 const int org_offset
= offset
;
216 val
= tvb_get_guint8(tvb
, offset
);
219 proto_tree_add_uint_format(tree
, hfi_dbus_value_uint
.id
, tvb
, org_offset
, offset
- org_offset
, val
, "BYTE: %u", val
);
224 case 'b': /* BOOLEAN */
228 val
= dinfo
->get32(tvb
, offset
);
231 ti
= proto_tree_add_boolean_format(tree
, hfi_dbus_value_bool
.id
, tvb
, org_offset
, offset
- org_offset
, val
, "BOOLEAN: %s", val
? "True" : "False");
232 if (val
!= 0 && val
!= 1) {
233 expert_add_info_format(dinfo
->pinfo
, ti
, &ei_dbus_value_bool_invalid
, "Invalid boolean value (must be 0 or 1 is: %u)", val
);
240 case 'n': /* INT16 */
244 val
= (gint16
)dinfo
->get16(tvb
, offset
);
247 proto_tree_add_uint_format(tree
, hfi_dbus_value_int
.id
, tvb
, org_offset
, offset
- org_offset
, val
, "INT16: %d", val
);
252 case 'q': /* UINT16 */
256 val
= dinfo
->get16(tvb
, offset
);
259 proto_tree_add_uint_format(tree
, hfi_dbus_value_uint
.id
, tvb
, org_offset
, offset
- org_offset
, val
, "UINT16: %u", val
);
264 case 'i': /* INT32 */
268 val
= (gint32
) dinfo
->get32(tvb
, offset
);
271 proto_tree_add_int_format(tree
, hfi_dbus_value_int
.id
, tvb
, org_offset
, offset
- org_offset
, val
, "INT32: %d", val
);
276 case 'u': /* UINT32 */
280 val
= dinfo
->get32(tvb
, offset
);
283 proto_tree_add_uint_format(tree
, hfi_dbus_value_uint
.id
, tvb
, org_offset
, offset
- org_offset
, val
, "UINT32: %u", val
);
288 case 'x': /* INT64 */
289 case 't': /* UINT64 */
292 case 'd': /* DOUBLE */
296 val
= dinfo
->getdouble(tvb
, offset
);
299 proto_tree_add_double_format(tree
, hfi_dbus_value_double
.id
, tvb
, org_offset
, offset
- org_offset
, val
, "DOUBLE: %." G_STRINGIFY(DBL_DIG
) "g", val
);
304 case 's': /* STRING */
305 case 'o': /* OBJECT_PATH */
310 len
= dinfo
->get32(tvb
, offset
);
313 val
= tvb_get_string(wmem_packet_scope(), tvb
, offset
, len
);
314 offset
+= (len
+ 1 /* NUL-byte */ + 3) & ~3;
317 ti
= proto_tree_add_string_format(tree
, hfi_dbus_value_str
.id
, tvb
, org_offset
, offset
- org_offset
, val
, "STRING: %s", val
);
318 if (!g_utf8_validate(val
, -1, NULL
)) {
319 expert_add_info(dinfo
->pinfo
, ti
, &ei_dbus_value_str_invalid
);
323 ti
= proto_tree_add_string_format(tree
, hfi_dbus_value_str
.id
, tvb
, org_offset
, offset
- org_offset
, val
, "OBJECT_PATH: %s", val
);
324 if (!dbus_validate_object_path(val
)) {
325 expert_add_info(dinfo
->pinfo
, ti
, &ei_dbus_invalid_object_path
);
333 case 'g': /* SIGNATURE */
338 len
= tvb_get_guint8(tvb
, offset
);
341 val
= tvb_get_string(wmem_packet_scope(), tvb
, offset
, len
);
344 ti
= proto_tree_add_string_format(tree
, hfi_dbus_value_str
.id
, tvb
, org_offset
, offset
- org_offset
, val
, "SIGNATURE: %s", val
);
345 if (!dbus_validate_signature(val
)) {
346 expert_add_info(dinfo
->pinfo
, ti
, &ei_dbus_invalid_signature
);
359 dissect_dbus_field_signature(tvbuff_t
*tvb
, dbus_info_t
*dinfo
, proto_tree
*tree
, int offset
, int field_code
)
361 const int org_offset
= offset
;
367 sig_len
= tvb_get_guint8(tvb
, offset
);
370 /* sig_len = tvb_strsize(tvb, offset); */
372 sig
= tvb_get_string(wmem_packet_scope(), tvb
, offset
, sig_len
);
373 offset
+= (sig_len
+ 1);
375 ti
= proto_tree_add_string(tree
, &hfi_dbus_type_signature
, tvb
, org_offset
, offset
- org_offset
, sig
);
376 if (!dbus_validate_signature(sig
)) {
377 expert_add_info(dinfo
->pinfo
, ti
, &ei_dbus_invalid_signature
);
381 switch (field_code
) {
382 case DBUS_HEADER_FIELD_REPLY_SERIAL
:
383 if (!strcmp(sig
, "u")) { /* UINT32 */
384 dbus_val_t serial_val
;
386 offset
= dissect_dbus_sig(tvb
, dinfo
, tree
, offset
, 'u', &serial_val
);
388 { /* XXX link with sending frame (serial_val.uint) */ }
393 case DBUS_HEADER_FIELD_DESTINATION
:
394 case DBUS_HEADER_FIELD_SENDER
:
395 if (!strcmp(sig
, "s")) { /* STRING */
398 offset
= dissect_dbus_sig(tvb
, dinfo
, tree
, offset
, 's', &addr_val
);
400 SET_ADDRESS((field_code
== DBUS_HEADER_FIELD_DESTINATION
) ? &dinfo
->pinfo
->dst
: &dinfo
->pinfo
->src
,
401 AT_STRINGZ
, (int)strlen(addr_val
.str
)+1, addr_val
.str
);
406 case DBUS_HEADER_FIELD_SIGNATURE
:
407 if (!strcmp(sig
, "g")) { /* SIGNATURE */
410 offset
= dissect_dbus_sig(tvb
, dinfo
, tree
, offset
, 'g', &sig_val
);
412 dinfo
->body_sig
= sig_val
.str
;
421 offset
= dissect_dbus_sig(tvb
, dinfo
, tree
, offset
, *sig
, &val
);
430 dissect_dbus_hdr_fields(tvbuff_t
*tvb
, dbus_info_t
*dinfo
, proto_tree
*tree
, int offset
)
434 end_offset
= offset
+ dinfo
->fields_len
;
436 while (offset
< end_offset
) {
437 proto_tree
*field_tree
;
442 ti
= proto_tree_add_item(tree
, &hfi_dbus_hdr_field
, tvb
, offset
, 0, ENC_NA
);
443 field_tree
= proto_item_add_subtree(ti
, ett_dbus_field
);
445 field_code
= tvb_get_guint8(tvb
, offset
);
446 proto_tree_add_item(field_tree
, &hfi_dbus_hdr_field_code
, tvb
, offset
, 1, dinfo
->enc
);
447 proto_item_append_text(ti
, ": %s", val_to_str(field_code
, field_code_vals
, "Unknown: %d"));
450 offset
= dissect_dbus_field_signature(tvb
, dinfo
, field_tree
, offset
, field_code
);
454 offset
= (offset
+ 7) & ~7; /* XXX ? */
456 proto_item_set_end(ti
, tvb
, offset
);
459 /* XXX, verify if all required fields are preset */
461 if (offset
>= end_offset
) {
469 dissect_dbus_hdr(tvbuff_t
*tvb
, dbus_info_t
*dinfo
, proto_tree
*tree
, int offset
)
471 proto_tree
*hdr_tree
;
476 ti
= proto_tree_add_item(tree
, &hfi_dbus_hdr
, tvb
, offset
, 0, ENC_NA
);
477 hdr_tree
= proto_item_add_subtree(ti
, ett_dbus_hdr
);
479 proto_tree_add_item(hdr_tree
, &hfi_dbus_hdr_endianness
, tvb
, offset
, 1, ENC_ASCII
| ENC_NA
);
482 type
= tvb_get_guint8(tvb
, offset
);
483 col_set_str(dinfo
->pinfo
->cinfo
, COL_INFO
, val_to_str_const(type
, message_type_vals
, ""));
484 proto_tree_add_item(hdr_tree
, &hfi_dbus_hdr_type
, tvb
, offset
, 1, dinfo
->enc
);
487 proto_tree_add_item(hdr_tree
, &hfi_dbus_hdr_flags
, tvb
, offset
, 1, dinfo
->enc
);
490 proto_tree_add_item(hdr_tree
, &hfi_dbus_hdr_version
, tvb
, offset
, 1, dinfo
->enc
);
493 dinfo
->body_len
= dinfo
->get32(tvb
, offset
);
494 proto_tree_add_item(hdr_tree
, &hfi_dbus_hdr_body_length
, tvb
, offset
, 4, dinfo
->enc
);
497 proto_tree_add_item(hdr_tree
, &hfi_dbus_hdr_serial
, tvb
, offset
, 4, dinfo
->enc
);
500 dinfo
->fields_len
= dinfo
->get32(tvb
, offset
);
501 proto_tree_add_item(hdr_tree
, &hfi_dbus_hdr_fields_length
, tvb
, offset
, 4, dinfo
->enc
);
508 dissect_dbus_body(tvbuff_t
*tvb
, dbus_info_t
*dinfo
, proto_tree
*tree
, int offset
)
510 proto_tree
*body_tree
;
513 if (dinfo
->body_len
&& dinfo
->body_sig
[0]) {
514 const char *sig
= dinfo
->body_sig
;
516 ti
= proto_tree_add_item(tree
, &hfi_dbus_body
, tvb
, offset
, 0, ENC_NA
);
517 body_tree
= proto_item_add_subtree(ti
, ett_dbus_body
);
522 offset
= dissect_dbus_sig(tvb
, dinfo
, body_tree
, offset
, *sig
, &val
);
528 proto_item_set_end(ti
, tvb
, offset
);
530 } else if (dinfo
->body_len
|| dinfo
->body_sig
[0]) {
537 dissect_dbus(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void *data _U_
)
539 proto_tree
*dbus_tree
= NULL
;
544 col_set_str(pinfo
->cinfo
, COL_PROTOCOL
, "D-BUS");
545 col_clear(pinfo
->cinfo
, COL_INFO
);
547 memset(&dinfo
, 0, sizeof(dinfo
));
549 switch (tvb_get_guint8(tvb
, 0)) {
551 dinfo
.enc
= ENC_LITTLE_ENDIAN
;
552 dinfo
.get16
= tvb_get_letohs
;
553 dinfo
.get32
= tvb_get_letohl
;
554 dinfo
.getdouble
= tvb_get_letohieee_double
;
557 dinfo
.enc
= ENC_BIG_ENDIAN
;
558 dinfo
.get16
= tvb_get_ntohs
;
559 dinfo
.get32
= tvb_get_ntohl
;
560 dinfo
.getdouble
= tvb_get_ntohieee_double
;
562 default: /* same as BIG_ENDIAN */
563 /* XXX we should probably return 0; */
565 dinfo
.get16
= tvb_get_ntohs
;
566 dinfo
.get32
= tvb_get_ntohl
;
567 dinfo
.getdouble
= tvb_get_ntohieee_double
;
571 proto_item
*ti
= proto_tree_add_item(tree
, hfi_dbus
, tvb
, 0, -1, ENC_NA
);
572 dbus_tree
= proto_item_add_subtree(ti
, ett_dbus
);
576 offset
= dissect_dbus_hdr(tvb
, &dinfo
, dbus_tree
, offset
);
577 offset
= dissect_dbus_hdr_fields(tvb
, &dinfo
, dbus_tree
, offset
);
578 /* header aligned to 8B */
579 offset
= (offset
+ 7) & ~7;
584 offset
= dissect_dbus_body(tvb
, &dinfo
, dbus_tree
, offset
);
589 #define DBUS_HEADER_LEN 16
592 get_dbus_message_len(packet_info
*pinfo _U_
, tvbuff_t
*tvb
, int offset
)
594 guint32 (*get_guint32
)(tvbuff_t
*, const gint
);
596 guint32 len_body
, len_hdr
;
598 switch (tvb_get_guint8(tvb
, offset
)) {
600 get_guint32
= tvb_get_letohl
;
604 get_guint32
= tvb_get_ntohl
;
608 len_hdr
= DBUS_HEADER_LEN
+ get_guint32(tvb
, offset
+ 12);
609 len_hdr
= (len_hdr
+ 7) & ~7;
610 len_body
= get_guint32(tvb
, offset
+ 4);
612 return len_hdr
+ len_body
;
616 dissect_dbus_pdu(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void *data
)
618 return dissect_dbus(tvb
, pinfo
, tree
, data
);
622 dissect_dbus_tcp(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void *data
)
624 tcp_dissect_pdus(tvb
, pinfo
, tree
, dbus_desegment
, DBUS_HEADER_LEN
, get_dbus_message_len
, dissect_dbus_pdu
, data
);
625 return tvb_length(tvb
);
629 proto_register_dbus(void)
631 #ifndef HAVE_HFI_SECTION_INIT
632 static header_field_info
*hfi
[] = {
635 &hfi_dbus_hdr_endianness
,
638 &hfi_dbus_hdr_version
,
639 &hfi_dbus_hdr_body_length
,
640 &hfi_dbus_hdr_serial
,
641 &hfi_dbus_hdr_fields_length
,
644 &hfi_dbus_hdr_field_code
,
645 &hfi_dbus_type_signature
,
648 &hfi_dbus_value_bool
,
650 &hfi_dbus_value_uint
,
652 &hfi_dbus_value_double
,
656 static gint
*ett
[] = {
663 static ei_register_info ei
[] = {
664 { &ei_dbus_value_bool_invalid
, { "dbus.value.bool.invalid", PI_PROTOCOL
, PI_WARN
, "Invalid boolean value", EXPFILL
}},
665 { &ei_dbus_value_str_invalid
, { "dbus.value.str.invalid", PI_PROTOCOL
, PI_WARN
, "Invalid string (not UTF-8)", EXPFILL
}},
666 { &ei_dbus_invalid_object_path
, { "dbus.invalid_object_path", PI_PROTOCOL
, PI_WARN
, "Invalid object_path", EXPFILL
}},
667 { &ei_dbus_invalid_signature
, { "dbus.invalid_signature", PI_PROTOCOL
, PI_WARN
, "Invalid signature", EXPFILL
}},
670 expert_module_t
*expert_dbus
;
674 proto_dbus
= proto_register_protocol("D-Bus", "D-BUS", "dbus");
675 hfi_dbus
= proto_registrar_get_nth(proto_dbus
);
677 proto_register_fields(proto_dbus
, hfi
, array_length(hfi
));
678 proto_register_subtree_array(ett
, array_length(ett
));
679 expert_dbus
= expert_register_protocol(proto_dbus
);
680 expert_register_field_array(expert_dbus
, ei
, array_length(ei
));
682 dbus_handle
= new_create_dissector_handle(dissect_dbus
, proto_dbus
);
683 dbus_handle_tcp
= new_create_dissector_handle(dissect_dbus_tcp
, proto_dbus
);
687 proto_reg_handoff_dbus(void)
689 dissector_add_uint("wtap_encap", WTAP_ENCAP_DBUS
, dbus_handle
);
690 dissector_add_handle("tcp.port", dbus_handle_tcp
);