static int dissect_websocket_payload(tvbuff_t *tvb, packet_info *pinfo, proto_tree *ws_tree, guint8 opcode, guint64 payload_length, guint8 mask, const guint8* masking_key) { int offset = 0; int payload_length_32bit; proto_item *ti_unmask, *ti; proto_tree *pl_tree, *mask_tree = NULL; tvbuff_t *unmask_tvb = NULL; /* Wireshark does not handle packets larger than 2^31-1 bytes. */ payload_length_32bit = (int)payload_length; if (payload_length != (guint64)payload_length_32bit) { proto_tree_add_text(ws_tree, tvb, offset, -1, "Payload length %" G_GINT64_MODIFIER "u is too large to dissect", payload_length); return tvb_length(tvb); } /* Payload */ ti = proto_tree_add_item(ws_tree, hf_ws_payload, tvb, offset, payload_length_32bit, ENC_NA); pl_tree = proto_item_add_subtree(ti, ett_ws_pl); if(mask){ unmask_tvb = tvb_unmasked(tvb, offset, payload_length_32bit, masking_key); tvb_set_child_real_data_tvbuff(tvb, unmask_tvb); add_new_data_source(pinfo, unmask_tvb, payload_length_32bit > (int) tvb_length(unmask_tvb) ? "Unmasked Data (truncated)" : "Unmasked Data"); ti = proto_tree_add_item(ws_tree, hf_ws_payload_unmask, unmask_tvb, offset, payload_length_32bit, ENC_NA); mask_tree = proto_item_add_subtree(ti, ett_ws_mask); } /* Extension Data */ /* TODO: Add dissector of Extension (not extension available for the moment...) */ /* Application Data */ switch(opcode){ case WS_CONTINUE: /* Continue */ proto_tree_add_item(pl_tree, hf_ws_payload_continue, tvb, offset, payload_length_32bit, ENC_NA); /* TODO: Add Fragmentation support... */ break; case WS_TEXT: /* Text */ if(mask){ proto_tree_add_item(pl_tree, hf_ws_payload_text_mask, tvb, offset, payload_length_32bit, ENC_NA); ti_unmask = proto_tree_add_item(mask_tree, hf_ws_payload_text_unmask, unmask_tvb, offset, payload_length_32bit, ENC_UTF_8|ENC_NA); PROTO_ITEM_SET_GENERATED(ti_unmask); ti_unmask = proto_tree_add_item(mask_tree, hf_ws_payload_text, unmask_tvb, offset, payload_length_32bit, ENC_UTF_8|ENC_NA); PROTO_ITEM_SET_HIDDEN(ti_unmask); }else{ proto_tree_add_item(pl_tree, hf_ws_payload_text, tvb, offset, payload_length_32bit, ENC_UTF_8|ENC_NA); } offset += payload_length_32bit; break; case WS_BINARY: /* Binary */ if(mask){ proto_tree_add_item(pl_tree, hf_ws_payload_binary_mask, tvb, offset, payload_length_32bit, ENC_NA); ti_unmask = proto_tree_add_item(mask_tree, hf_ws_payload_binary_unmask, unmask_tvb, offset, payload_length_32bit, ENC_NA); PROTO_ITEM_SET_GENERATED(ti_unmask); ti_unmask = proto_tree_add_item(mask_tree, hf_ws_payload_binary, unmask_tvb, offset, payload_length_32bit, ENC_NA); PROTO_ITEM_SET_HIDDEN(ti_unmask); }else{ proto_tree_add_item(pl_tree, hf_ws_payload_binary, tvb, offset, payload_length_32bit, ENC_NA); } offset += payload_length_32bit; break; case WS_CLOSE: /* Close */ if(mask){ proto_tree_add_item(pl_tree, hf_ws_payload_close_mask, tvb, offset, payload_length_32bit, ENC_NA); ti_unmask = proto_tree_add_item(mask_tree, hf_ws_payload_close_unmask, unmask_tvb, offset, payload_length_32bit, ENC_NA); PROTO_ITEM_SET_GENERATED(ti_unmask); ti_unmask = proto_tree_add_item(mask_tree, hf_ws_payload_close, unmask_tvb, offset, payload_length_32bit, ENC_NA); PROTO_ITEM_SET_HIDDEN(ti_unmask); ti_unmask = proto_tree_add_item(mask_tree, hf_ws_payload_close_status_code, unmask_tvb, offset, 2, ENC_BIG_ENDIAN); PROTO_ITEM_SET_GENERATED(ti_unmask); if(payload_length_32bit > 2){ ti_unmask = proto_tree_add_item(mask_tree, hf_ws_payload_close_reason, unmask_tvb, offset+2, payload_length_32bit-2, ENC_ASCII|ENC_NA); PROTO_ITEM_SET_GENERATED(ti_unmask); } }else{ proto_tree_add_item(pl_tree, hf_ws_payload_close, tvb, offset, payload_length_32bit, ENC_NA); proto_tree_add_item(pl_tree, hf_ws_payload_close_status_code, tvb, offset, 2, ENC_BIG_ENDIAN); if(payload_length_32bit > 2){ proto_tree_add_item(pl_tree, hf_ws_payload_close_reason, tvb, offset+2, payload_length_32bit-2, ENC_ASCII|ENC_NA); } } offset += payload_length_32bit; break; case WS_PING: /* Ping */ if(mask){ proto_tree_add_item(pl_tree, hf_ws_payload_ping_mask, tvb, offset, payload_length_32bit, ENC_NA); ti_unmask = proto_tree_add_item(mask_tree, hf_ws_payload_ping_unmask, unmask_tvb, offset, payload_length_32bit, ENC_NA); PROTO_ITEM_SET_GENERATED(ti_unmask); ti_unmask = proto_tree_add_item(mask_tree, hf_ws_payload_ping, unmask_tvb, offset, payload_length_32bit, ENC_NA); PROTO_ITEM_SET_HIDDEN(ti_unmask); }else{ proto_tree_add_item(pl_tree, hf_ws_payload_ping, tvb, offset, payload_length_32bit, ENC_NA); } offset += payload_length_32bit; break; case WS_PONG: /* Pong */ if(mask){ proto_tree_add_item(pl_tree, hf_ws_payload_pong_mask, tvb, offset, payload_length_32bit, ENC_NA); ti_unmask = proto_tree_add_item(mask_tree, hf_ws_payload_pong_unmask, unmask_tvb, offset, payload_length_32bit, ENC_NA); PROTO_ITEM_SET_GENERATED(ti_unmask); ti_unmask = proto_tree_add_item(mask_tree, hf_ws_payload_pong, unmask_tvb, offset, payload_length_32bit, ENC_NA); PROTO_ITEM_SET_HIDDEN(ti_unmask); }else{ proto_tree_add_item(pl_tree, hf_ws_payload_pong, tvb, offset, payload_length_32bit, ENC_NA); } offset += payload_length_32bit; break; default: /* Unknown */ ti = proto_tree_add_item(pl_tree, hf_ws_payload_unknown, tvb, offset, payload_length_32bit, ENC_NA); expert_add_info_format(pinfo, ti, PI_UNDECODED, PI_NOTE, "Dissector for Websocket Opcode (%d)" " code not implemented, Contact Wireshark developers" " if you want this supported", opcode); break; } return offset; }
static int dissect_websocket_payload(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, proto_tree *ws_tree, guint8 opcode, guint payload_length, guint8 mask, const guint8* masking_key) { guint offset = 0; proto_item *ti_unmask, *ti; dissector_handle_t handle; proto_tree *pl_tree, *mask_tree = NULL; tvbuff_t *payload_tvb = NULL; /* Payload */ ti = proto_tree_add_item(ws_tree, hf_ws_payload, tvb, offset, payload_length, ENC_NA); pl_tree = proto_item_add_subtree(ti, ett_ws_pl); if(mask){ payload_tvb = tvb_unmasked(tvb, offset, payload_length, masking_key); tvb_set_child_real_data_tvbuff(tvb, payload_tvb); add_new_data_source(pinfo, payload_tvb, payload_length > tvb_length(payload_tvb) ? "Unmasked Data (truncated)" : "Unmasked Data"); ti = proto_tree_add_item(ws_tree, hf_ws_payload_unmask, payload_tvb, offset, payload_length, ENC_NA); mask_tree = proto_item_add_subtree(ti, ett_ws_mask); }else{ payload_tvb = tvb_new_subset(tvb, offset, payload_length, -1); } handle = dissector_get_uint_handle(port_subdissector_table, pinfo->match_uint); if(handle != NULL){ call_dissector_only(handle, payload_tvb, pinfo, tree, NULL); }else{ dissector_try_heuristic(heur_subdissector_list, payload_tvb, pinfo, tree, NULL); } /* Extension Data */ /* TODO: Add dissector of Extension (not extension available for the moment...) */ /* Application Data */ switch(opcode){ case WS_CONTINUE: /* Continue */ proto_tree_add_item(pl_tree, hf_ws_payload_continue, tvb, offset, payload_length, ENC_NA); /* TODO: Add Fragmentation support... */ break; case WS_TEXT: /* Text */ if(mask){ proto_tree_add_item(pl_tree, hf_ws_payload_text_mask, tvb, offset, payload_length, ENC_NA); ti_unmask = proto_tree_add_item(mask_tree, hf_ws_payload_text_unmask, payload_tvb, offset, payload_length, ENC_UTF_8|ENC_NA); PROTO_ITEM_SET_GENERATED(ti_unmask); ti_unmask = proto_tree_add_item(mask_tree, hf_ws_payload_text, payload_tvb, offset, payload_length, ENC_UTF_8|ENC_NA); PROTO_ITEM_SET_HIDDEN(ti_unmask); }else{ const gchar *saved_match_string = pinfo->match_string; void *save_private_data = pinfo->private_data; pinfo->match_string = NULL; pinfo->private_data = NULL; switch(pref_text_type){ case WEBSOCKET_TEXT: call_dissector(text_lines_handle, payload_tvb, pinfo, pl_tree); break; case WEBSOCKET_JSON: call_dissector(json_handle, payload_tvb, pinfo, pl_tree); break; case WEBSOCKET_NONE: /* falltrough */ default: proto_tree_add_item(pl_tree, hf_ws_payload_text, tvb, offset, payload_length, ENC_UTF_8|ENC_NA); break; } pinfo->match_string = saved_match_string; pinfo->private_data = save_private_data; } offset += payload_length; break; case WS_BINARY: /* Binary */ if(mask){ proto_tree_add_item(pl_tree, hf_ws_payload_binary_mask, tvb, offset, payload_length, ENC_NA); ti_unmask = proto_tree_add_item(mask_tree, hf_ws_payload_binary_unmask, payload_tvb, offset, payload_length, ENC_NA); PROTO_ITEM_SET_GENERATED(ti_unmask); ti_unmask = proto_tree_add_item(mask_tree, hf_ws_payload_binary, payload_tvb, offset, payload_length, ENC_NA); PROTO_ITEM_SET_HIDDEN(ti_unmask); }else{ proto_tree_add_item(pl_tree, hf_ws_payload_binary, tvb, offset, payload_length, ENC_NA); } offset += payload_length; break; case WS_CLOSE: /* Close */ if(mask){ proto_tree_add_item(pl_tree, hf_ws_payload_close_mask, tvb, offset, payload_length, ENC_NA); ti_unmask = proto_tree_add_item(mask_tree, hf_ws_payload_close_unmask, payload_tvb, offset, payload_length, ENC_NA); PROTO_ITEM_SET_GENERATED(ti_unmask); ti_unmask = proto_tree_add_item(mask_tree, hf_ws_payload_close, payload_tvb, offset, payload_length, ENC_NA); PROTO_ITEM_SET_HIDDEN(ti_unmask); ti_unmask = proto_tree_add_item(mask_tree, hf_ws_payload_close_status_code, payload_tvb, offset, 2, ENC_BIG_ENDIAN); PROTO_ITEM_SET_GENERATED(ti_unmask); if(payload_length > 2){ ti_unmask = proto_tree_add_item(mask_tree, hf_ws_payload_close_reason, payload_tvb, offset+2, payload_length-2, ENC_ASCII|ENC_NA); PROTO_ITEM_SET_GENERATED(ti_unmask); } }else{ proto_tree_add_item(pl_tree, hf_ws_payload_close, tvb, offset, payload_length, ENC_NA); proto_tree_add_item(pl_tree, hf_ws_payload_close_status_code, tvb, offset, 2, ENC_BIG_ENDIAN); if(payload_length > 2){ proto_tree_add_item(pl_tree, hf_ws_payload_close_reason, tvb, offset+2, payload_length-2, ENC_ASCII|ENC_NA); } } offset += payload_length; break; case WS_PING: /* Ping */ if(mask){ proto_tree_add_item(pl_tree, hf_ws_payload_ping_mask, tvb, offset, payload_length, ENC_NA); ti_unmask = proto_tree_add_item(mask_tree, hf_ws_payload_ping_unmask, payload_tvb, offset, payload_length, ENC_NA); PROTO_ITEM_SET_GENERATED(ti_unmask); ti_unmask = proto_tree_add_item(mask_tree, hf_ws_payload_ping, payload_tvb, offset, payload_length, ENC_NA); PROTO_ITEM_SET_HIDDEN(ti_unmask); }else{ proto_tree_add_item(pl_tree, hf_ws_payload_ping, tvb, offset, payload_length, ENC_NA); } offset += payload_length; break; case WS_PONG: /* Pong */ if(mask){ proto_tree_add_item(pl_tree, hf_ws_payload_pong_mask, tvb, offset, payload_length, ENC_NA); ti_unmask = proto_tree_add_item(mask_tree, hf_ws_payload_pong_unmask, payload_tvb, offset, payload_length, ENC_NA); PROTO_ITEM_SET_GENERATED(ti_unmask); ti_unmask = proto_tree_add_item(mask_tree, hf_ws_payload_pong, payload_tvb, offset, payload_length, ENC_NA); PROTO_ITEM_SET_HIDDEN(ti_unmask); }else{ proto_tree_add_item(pl_tree, hf_ws_payload_pong, tvb, offset, payload_length, ENC_NA); } offset += payload_length; break; default: /* Unknown */ ti = proto_tree_add_item(pl_tree, hf_ws_payload_unknown, tvb, offset, payload_length, ENC_NA); expert_add_info_format(pinfo, ti, &ei_ws_payload_unknown, "Dissector for Websocket Opcode (%d)" " code not implemented, Contact Wireshark developers" " if you want this supported", opcode); break; } return offset; }