/* packet-jxta.c * * Routines for JXTA packet dissection * JXTA specification from https://jxta-spec.dev.java.net (now at https://github.com/chaupal/jxta-spec ?) * * Copyright 2004-08, Mike Duigou * * Heavily based on packet-jabber.c, which in turn is heavily based on * on packet-acap.c, which in turn is heavily based on * packet-imap.c, Copyright 1999, Richard Sharpe * Copied from packet-pop.c, packet-jabber.c, packet-udp.c, packet-http.c * * Wireshark - Network traffic analyzer * By Gerald Combs * Copyright 2000 Gerald Combs * * SPDX-License-Identifier: GPL-2.0-or-later */ #include "config.h" #define WS_LOG_DOMAIN "jxta" #include #include #include #include #include #include #include #include #include "packet-jxta.h" #include "packet-media-type.h" void proto_register_jxta(void); void proto_reg_handoff_jxta(void); static const gchar JXTA_UDP_SIG[] = { 'J', 'X', 'T', 'A' }; static const gchar JXTA_MSG_SIG[] = { 'j', 'x', 'm', 'g' }; static const gchar JXTA_MSGELEM_SIG[] = { 'j', 'x', 'e', 'l' }; static const gchar JXTA_WELCOME_MSG_SIG[] = { 'J', 'X', 'T', 'A', 'H', 'E', 'L', 'L', 'O', ' ' }; static const gchar* JXTA_WELCOME_MSG_VERSION_1_1 = "1.1"; static const gchar* JXTA_WELCOME_MSG_VERSION_3_0 = "3.0"; static const int JXTA_MSG_VERSION_1 = 0; static const int JXTA_MSG_VERSION_2 = 1; static const int JXTAMSG1_ELMFLAG_TYPE = 1 << 0; static const int JXTAMSG1_ELMFLAG_ENCODING = 1 << 1; static const int JXTAMSG1_ELMFLAG_SIGNATURE = 1 << 2; static const int JXTAMSG2_ELMFLAG_UINT64_LENS = 1 << 0; static const int JXTAMSG2_ELMFLAG_NAME_LITERAL = 1 << 1; static const int JXTAMSG2_ELMFLAG_TYPE = 1 << 2; static const int JXTAMSG2_ELMFLAG_SIGNATURE = 1 << 3; static const int JXTAMSG2_ELMFLAG_ENCODINGS = 1 << 4; static int proto_jxta = -1; static int proto_message_jxta = -1; static int jxta_tap = -1; static dissector_table_t media_type_dissector_table = NULL; static dissector_handle_t media_handle = NULL; static dissector_handle_t stream_jxta_handle = NULL; static dissector_handle_t tls_handle = NULL; static int hf_uri_addr = -1; static int hf_uri_src = -1; static int hf_uri_dst = -1; static int hf_jxta_udp = -1; static int hf_jxta_udpsig = -1; static int hf_jxta_welcome = -1; static int hf_jxta_welcome_initiator = -1; static int hf_jxta_welcome_sig = -1; static int hf_jxta_welcome_destAddr = -1; static int hf_jxta_welcome_pubAddr = -1; static int hf_jxta_welcome_peerid = -1; static int hf_jxta_welcome_noProp = -1; static int hf_jxta_welcome_msgVers = -1; static int hf_jxta_welcome_variable = -1; static int hf_jxta_welcome_version = -1; static int hf_jxta_framing = -1; static int hf_jxta_framing_header = -1; static int hf_jxta_framing_header_name = -1; static int hf_jxta_framing_header_value_length = -1; static int hf_jxta_framing_header_value = -1; static int hf_jxta_message_address = -1; static int hf_jxta_message_src = -1; static int hf_jxta_message_dst = -1; static int hf_jxta_message_sig = -1; static int hf_jxta_message_version = -1; static int hf_jxta_message_flags = -1; static int hf_jxta_message_flag_utf16be = -1; static int hf_jxta_message_flag_ucs32be = -1; static int hf_jxta_message_names_count = -1; static int hf_jxta_message_names_name = -1; static int hf_jxta_message_element_count = -1; static int hf_jxta_element = -1; static int hf_jxta_element_sig = -1; static int hf_jxta_element1_namespaceid = -1; static int hf_jxta_element2_namespaceid = -1; static int hf_jxta_element2_nameid = -1; static int hf_jxta_element2_mimeid = -1; static int hf_jxta_element2_encodingid = -1; static int hf_jxta_element_flags = -1; static int hf_jxta_element1_flag_hasType = -1; static int hf_jxta_element1_flag_hasEncoding = -1; static int hf_jxta_element1_flag_hasSignature = -1; static int hf_jxta_element2_flag_64bitlens = -1; static int hf_jxta_element2_flag_nameLiteral = -1; static int hf_jxta_element2_flag_hasType = -1; static int hf_jxta_element2_flag_hasSignature = -1; static int hf_jxta_element2_flag_hasEncoding = -1; static int hf_jxta_element2_flag_sigOfEncoded = -1; static int hf_jxta_element_name = -1; static int hf_jxta_element_type = -1; static int hf_jxta_element_encoding = -1; static int hf_jxta_element_content_len = -1; static int hf_jxta_element_content_len64 = -1; /* static int hf_jxta_element_content = -1; */ /** * JXTA Protocol subtree handles **/ static gint ett_jxta = -1; static gint ett_jxta_welcome = -1; static gint ett_jxta_udp = -1; static gint ett_jxta_framing = -1; static gint ett_jxta_framing_header = -1; static gint ett_jxta_msg = -1; static gint ett_jxta_msg_flags = -1; static gint ett_jxta_elem = -1; static gint ett_jxta_elem_1_flags = -1; static gint ett_jxta_elem_2_flags = -1; static expert_field ei_media_too_short = EI_INIT; static int uri_address_type = -1; /** * global preferences **/ static gboolean gDESEGMENT = TRUE; static gboolean gMSG_MEDIA = TRUE; static dissector_handle_t jxta_udp_handle; /** * Stream Conversation data **/ struct jxta_stream_conversation_data { port_type tpt_ptype; address initiator_tpt_address; guint32 initiator_tpt_port; guint32 initiator_welcome_frame; address initiator_address; address receiver_tpt_address; guint32 receiver_tpt_port; guint32 receiver_welcome_frame; address receiver_address; }; typedef struct jxta_stream_conversation_data jxta_stream_conversation_data; static const char* jxta_conv_get_filter_type(conv_item_t* conv, conv_filter_type_e filter) { if ((filter == CONV_FT_SRC_ADDRESS) && (conv->src_address.type == uri_address_type)) return "jxta.message.src"; if ((filter == CONV_FT_DST_ADDRESS) && (conv->dst_address.type == uri_address_type)) return "jxta.message.dst"; if ((filter == CONV_FT_ANY_ADDRESS) && (conv->src_address.type == uri_address_type)) return "jxta.message.address"; return CONV_FILTER_INVALID; } static ct_dissector_info_t jxta_ct_dissector_info = {&jxta_conv_get_filter_type}; static tap_packet_status jxta_conversation_packet(void *pct, packet_info *pinfo _U_, epan_dissect_t *edt _U_, const void *vip, tap_flags_t flags) { conv_hash_t *hash = (conv_hash_t*) pct; hash->flags = flags; const jxta_tap_header *jxtahdr = (const jxta_tap_header *) vip; add_conversation_table_data(hash, &jxtahdr->src_address, &jxtahdr->dest_address, 0, 0, 1, jxtahdr->size, NULL, NULL, &jxta_ct_dissector_info, CONVERSATION_NONE); return TAP_PACKET_REDRAW; } static const char* jxta_endpoint_get_filter_type(endpoint_item_t* endpoint, conv_filter_type_e filter) { if ((filter == CONV_FT_ANY_ADDRESS) && (endpoint->myaddress.type == uri_address_type)) return "jxta.message.address"; return CONV_FILTER_INVALID; } static et_dissector_info_t jxta_endpoint_dissector_info = {&jxta_endpoint_get_filter_type}; static tap_packet_status jxta_endpoint_packet(void *pit, packet_info *pinfo _U_, epan_dissect_t *edt _U_, const void *vip, tap_flags_t flags) { conv_hash_t *hash = (conv_hash_t*) pit; hash->flags = flags; const jxta_tap_header *jxtahdr = (const jxta_tap_header *)vip; /* Take two "add" passes per packet, adding for each direction, ensures that all packets are counted properly (even if address is sending to itself) XXX - this could probably be done more efficiently inside endpoint_table */ add_endpoint_table_data(hash, &jxtahdr->src_address, 0, TRUE, 1, jxtahdr->size, &jxta_endpoint_dissector_info, ENDPOINT_NONE); add_endpoint_table_data(hash, &jxtahdr->dest_address, 0, FALSE, 1, jxtahdr->size, &jxta_endpoint_dissector_info, ENDPOINT_NONE); return TAP_PACKET_REDRAW; } static int uri_to_str(const address* addr, gchar *buf, int buf_len) { int copy_len = addr->len < (buf_len - 1) ? addr->len : (buf_len - 1); memcpy(buf, addr->data, copy_len ); buf[copy_len] = '\0'; return copy_len+1; } static int uri_str_len(const address* addr) { return addr->len+1; } static const char* uri_col_filter_str(const address* addr _U_, gboolean is_src) { if (is_src) return "uri.src"; return "uri.dst"; } /** * Prototypes **/ static int dissect_jxta_udp(tvbuff_t * tvb, packet_info * pinfo, proto_tree * tree, void * data); static int dissect_jxta_stream(tvbuff_t * tvb, packet_info * pinfo, proto_tree * tree, void * data); static jxta_stream_conversation_data *get_tpt_conversation(packet_info * pinfo); static conversation_t *get_peer_conversation(packet_info * pinfo, jxta_stream_conversation_data* tpt_conv_data, gboolean create); static int dissect_jxta_welcome(tvbuff_t * tvb, packet_info * pinfo, proto_tree * tree, address * found_addr, gboolean initiator); static int dissect_jxta_message_framing(tvbuff_t * tvb, packet_info * pinfo, proto_tree * tree, guint64 * content_length, gchar ** content_type); static int dissect_jxta_message(tvbuff_t * tvb, packet_info * pinfo, proto_tree * tree, void * data); static int dissect_jxta_message_element_1(tvbuff_t * tvb, packet_info * pinfo, proto_tree * tree, guint ns_count, const gchar ** namespaces); static int dissect_jxta_message_element_2(tvbuff_t * tvb, packet_info * pinfo, proto_tree * tree, guint ns_count, const gchar ** namespaces); static int dissect_media( const gchar* fullmediatype, tvbuff_t * tvb, packet_info * pinfo, proto_tree * tree); /** * Heuristically dissect a tvbuff containing a JXTA UDP Message * * @param tvb The buffer to dissect. * @param pinfo Packet Info. * @param tree The protocol tree. * @return TRUE if the tvb contained JXTA data which was dissected otherwise FALSE **/ static gboolean dissect_jxta_UDP_heur(tvbuff_t * tvb, packet_info * pinfo, proto_tree * tree, void * data _U_) { /* This is a heuristic dissector, which means we get all the UDP * traffic not sent to a known dissector and not claimed by * a heuristic dissector called before us! */ int save_desegment_offset; guint32 save_desegment_len; int ret; if (tvb_strneql(tvb, 0, JXTA_UDP_SIG, sizeof (JXTA_UDP_SIG)) != 0) { /* Not a JXTA UDP packet (or not enough bytes to check for the sig) */ return FALSE; } save_desegment_offset = pinfo->desegment_offset; save_desegment_len = pinfo->desegment_len; ret = dissect_jxta_udp(tvb, pinfo, tree, NULL); /* ws_message( "%d Heuristic UDP Dissection : %d", pinfo->num, ret ); */ if (ret < 0) { /* * UDP is not a packet stream protocol, so the UDP dissector * should not, and will not, do the sort of dissection help * that the TCP dissector will. If JXTA messages don't * start and end on UDP packet boundaries, the JXTA dissector * will have to do its own byte stream reassembly. */ pinfo->desegment_offset = save_desegment_offset; pinfo->desegment_len = save_desegment_len; return FALSE; } else if (ret == 0) { /* * A clear rejection. */ pinfo->desegment_offset = save_desegment_offset; pinfo->desegment_len = save_desegment_len; return FALSE; } else { /* * A clear acceptance. */ return TRUE; } } /** * Heuristically dissect a tvbuff containing a JXTA TCP Stream * * @param tvb The buffer to dissect. * @param pinfo Packet Info. * @param tree The protocol tree. * @return TRUE if the tvb contained JXTA data which was dissected otherwise FALSE **/ static gboolean dissect_jxta_TCP_heur(tvbuff_t * tvb, packet_info * pinfo, proto_tree * tree, void * data _U_) { /* This is a heuristic dissector, which means we get all the TCP * traffic not sent to a known dissector and not claimed by * a heuristic dissector called before us! */ int save_desegment_offset; guint32 save_desegment_len; int ret; save_desegment_offset = pinfo->desegment_offset; save_desegment_len = pinfo->desegment_len; ret = dissect_jxta_stream(tvb, pinfo, tree, NULL); /* ws_message( "%d Heuristic TCP Dissection : %d", pinfo->num, ret ); */ if (ret < 0) { /* * A heuristic dissector for a TCP-based protocol can reject * a packet, or it can request that more data be provided. * It must not attempt to do both, as the notion of doing both * is nonsensical - if the packet isn't considered a packet * for the dissector's protocol, that dissector won't be * dissecting it no matter *how* much more data is added. * * Therefore, we treat a negative return from * dissect_jxta_stream() as a rejection. * * If that's not desired - i.e., if we should keep trying to get * more data, in the hopes that we'll eventually be able to * determine whether the packet is a JXTA packet or not - we * should, in this case, leave pinfo->desegment_offset and * pinfo->desegment_len alone, and return TRUE, *NOT* FALSE. */ pinfo->desegment_offset = save_desegment_offset; pinfo->desegment_len = save_desegment_len; return FALSE; } else if (ret == 0) { /* * A clear rejection. */ pinfo->desegment_offset = save_desegment_offset; pinfo->desegment_len = save_desegment_len; return FALSE; } else { /* * A clear acceptance. */ return TRUE; } } /** * Heuristically dissect a tvbuff containing a JXTA SCTP Stream * * @param tvb The buffer to dissect. * @param pinfo Packet Info. * @param tree The protocol tree. * @return TRUE if the tvb contained JXTA data which was dissected otherwise FALSE **/ static gboolean dissect_jxta_SCTP_heur(tvbuff_t * tvb, packet_info * pinfo, proto_tree * tree, void * data _U_) { /* This is a heuristic dissector, which means we get all the SCTP * traffic not sent to a known dissector and not claimed by * a heuristic dissector called before us! */ int save_desegment_offset; guint32 save_desegment_len; int ret; save_desegment_offset = pinfo->desegment_offset; save_desegment_len = pinfo->desegment_len; ret = dissect_jxta_stream(tvb, pinfo, tree, NULL); /* ws_message( "%d Heuristic SCTP Dissection : %d", pinfo->num, ret ); */ if (ret < 0) { /* * SCTP is not a byte stream protocol, so the SCTP dissector * should not, and will not, do the sort of dissection help * that the SCTP dissector will. If JXTA messages don't * start and end on SCTP packet boundaries, the JXTA dissector * will have to do its own byte stream reassembly. * * The SCTP dissector currently won't do reassembly. If that * causes a problem for the JXTA dissector, the correct fix * is to implement reassembly in the SCTP dissector, so *all* * dissectors for protocols running atop SCTP can benefit from * it. */ pinfo->desegment_offset = save_desegment_offset; pinfo->desegment_len = save_desegment_len; return FALSE; } else if (ret == 0) { /* * A clear rejection. */ pinfo->desegment_offset = save_desegment_offset; pinfo->desegment_len = save_desegment_len; return FALSE; } else { /* * A clear acceptance. */ return TRUE; } } /** * Dissect a tvbuff containing a JXTA UDP header, JXTA Message framing and a JXTA Message * * @param tvb The buffer to dissect. * @param pinfo Packet Info. * @param tree The protocol tree. * @return Number of bytes from the tvbuff_t which were processed, 0 (zero) if * the packet was not recognized as a JXTA packet and negative if the * dissector needs more bytes in order to process a PDU. **/ static int dissect_jxta_udp(tvbuff_t * tvb, packet_info * pinfo, proto_tree * tree, void * data _U_) { guint offset = 0; guint available; gint needed = 0; conversation_t *conversation = find_or_create_conversation(pinfo); conversation_set_dissector(conversation, jxta_udp_handle); while (TRUE) { tvbuff_t *jxta_message_framing_tvb; gint processed = 0; guint64 content_length = -1; gchar *content_type = NULL; available = tvb_reported_length_remaining(tvb, offset); if (available < sizeof(JXTA_UDP_SIG)) { needed = (gint) (sizeof(JXTA_UDP_SIG) - available); break; } if (tvb_memeql(tvb, offset, (const guint8*)JXTA_UDP_SIG, sizeof(JXTA_UDP_SIG)) != 0) { /* not ours */ return 0; } offset += (int)sizeof(JXTA_UDP_SIG); jxta_message_framing_tvb = tvb_new_subset_remaining(tvb, offset); processed = dissect_jxta_message_framing(jxta_message_framing_tvb, pinfo, NULL, &content_length, &content_type); if ((0 == processed) || (NULL == content_type) || (content_length <= 0) || (content_length > UINT_MAX)) { /** Buffer did not begin with valid framing headers */ return 0; } if (processed < 0) { needed = -processed; break; } offset += processed; available = tvb_reported_length_remaining(tvb, offset); if (available < content_length) { needed = (gint) (content_length - available); break; } offset += (guint) content_length; break; } if ((needed > 0) && gDESEGMENT && pinfo->can_desegment) { /* ws_message( "UDP requesting %d more bytes", needed ); */ pinfo->desegment_offset = 0; pinfo->desegment_len = needed; return -needed; } col_set_str(pinfo->cinfo, COL_PROTOCOL, "JXTA"); guint tree_offset = 0; proto_item *jxta_tree_item = proto_tree_add_protocol_format(tree, proto_jxta, tvb, tree_offset, -1, "JXTA" ); proto_tree *jxta_tree = proto_item_add_subtree(jxta_tree_item, ett_jxta); proto_item *jxta_udp_tree_item = proto_tree_add_none_format(jxta_tree, hf_jxta_udp, tvb, tree_offset, -1, "JXTA UDP Message"); proto_tree *jxta_udp_tree = proto_item_add_subtree(jxta_udp_tree_item, ett_jxta_udp); tvbuff_t *jxta_message_framing_tvb; guint64 content_length = -1; gchar *content_type = NULL; tvbuff_t *jxta_message_tvb; proto_tree_add_item(jxta_udp_tree, hf_jxta_udpsig, tvb, tree_offset, (int)sizeof(JXTA_UDP_SIG), ENC_ASCII); tree_offset += (int)sizeof(JXTA_UDP_SIG); jxta_message_framing_tvb = tvb_new_subset_remaining(tvb, tree_offset); tree_offset += dissect_jxta_message_framing(jxta_message_framing_tvb, pinfo, jxta_tree, &content_length, &content_type); jxta_message_tvb = tvb_new_subset_length(tvb, tree_offset, (gint) content_length); tree_offset += dissect_media(content_type, jxta_message_tvb, pinfo, tree); proto_item_set_end(jxta_udp_tree_item, tvb, tree_offset); // offset is based on reported lengths. tree_offset is based on captured lengths via dissect_media. // Comment this out for now in favor of dissect_media's expert warning. // DISSECTOR_ASSERT(tree_offset == offset); return offset; } /** * Dissect a tvbuff containing JXTA stream PDUs. This commonly includes * connections over TCP sockets. * *

The stream (in both directions) will consist of a JXTA Welcome Message * followed by an indeterminate number of JXTA Message Framing Headers and * JXTA Messages. * * @param tvb The buffer to dissect. * @param pinfo Packet Info. * @param tree The protocol tree. * @return Number of bytes from the tvbuff_t which were processed, 0 (zero) if * the packet was not recognized as a JXTA packet and negative if the * dissector needs more bytes in order to process a PDU. **/ static int dissect_jxta_stream(tvbuff_t * tvb, packet_info * pinfo, proto_tree * tree, void * data _U_) { guint offset = 0; guint available = tvb_reported_length_remaining(tvb, offset); gint processed = 0; gint needed = 0; jxta_stream_conversation_data *tpt_conv_data = NULL; proto_item *jxta_tree_item = NULL; proto_tree *jxta_tree = NULL; /* ws_message("Dissecting%s : %d", (NULL != tree) ? " for display" : "", pinfo->num ); */ if (available < sizeof(JXTA_WELCOME_MSG_SIG)) { needed = (gint) (sizeof(JXTA_WELCOME_MSG_SIG) - available); goto Common_Exit; } if (0 == tvb_memeql(tvb, 0, (const guint8*)JXTA_WELCOME_MSG_SIG, sizeof(JXTA_WELCOME_MSG_SIG))) { /* The beginning of a JXTA stream connection */ address *welcome_addr; gboolean initiator = FALSE; tpt_conv_data = get_tpt_conversation(pinfo); if (0 == tpt_conv_data->initiator_welcome_frame) { /* The initiator welcome frame */ tpt_conv_data->tpt_ptype = pinfo->ptype; tpt_conv_data->initiator_welcome_frame = pinfo->num; copy_address_wmem(wmem_file_scope(), &tpt_conv_data->initiator_tpt_address, &pinfo->src); tpt_conv_data->initiator_tpt_port = pinfo->srcport; welcome_addr = &tpt_conv_data->initiator_address; initiator = TRUE; } else { if (tpt_conv_data->initiator_welcome_frame >= pinfo->num) { /* what we saw previously was the receiver welcome message */ tpt_conv_data->receiver_welcome_frame = tpt_conv_data->initiator_welcome_frame; tpt_conv_data->receiver_tpt_address = tpt_conv_data->initiator_tpt_address; tpt_conv_data->receiver_tpt_port = tpt_conv_data->initiator_tpt_port; tpt_conv_data->receiver_address = tpt_conv_data->initiator_address; tpt_conv_data->initiator_welcome_frame = pinfo->num; copy_address_wmem(wmem_file_scope(), &tpt_conv_data->initiator_tpt_address, &pinfo->src); tpt_conv_data->initiator_tpt_port = pinfo->srcport; welcome_addr = &tpt_conv_data->initiator_address; initiator = TRUE; } else { /* The receiver welcome frame */ tpt_conv_data->tpt_ptype = pinfo->ptype; tpt_conv_data->receiver_welcome_frame = pinfo->num; copy_address_wmem(wmem_file_scope(), &tpt_conv_data->receiver_tpt_address, &pinfo->src); tpt_conv_data->receiver_tpt_port = pinfo->srcport; welcome_addr = &tpt_conv_data->receiver_address; initiator = FALSE; } } processed = dissect_jxta_welcome(tvb, pinfo, NULL, welcome_addr, initiator); if( processed < 0 ) { needed = -processed; goto Common_Exit; } /* redo, this time creating the display tree. */ jxta_tree_item = proto_tree_add_protocol_format(tree, proto_jxta, tvb, offset, -1, "JXTA" ); jxta_tree = proto_item_add_subtree(jxta_tree_item, ett_jxta); processed = dissect_jxta_welcome(tvb, pinfo, jxta_tree, welcome_addr, initiator); } else { /* Somewhere in the middle of a JXTA stream connection */ gint64 content_length = G_GINT64_CONSTANT(-1); gchar *content_type = NULL; gint headers_len = dissect_jxta_message_framing(tvb, pinfo, NULL, (guint64*) &content_length, &content_type); if ((0 == headers_len) || (NULL == content_type) || (content_length <= 0) || (content_length > UINT_MAX)) { /** Buffer did not begin with valid framing headers */ return 0; } /* ws_message("%d Tpt %s:%d -> %s:%d tvb len=%d\n\t%s %d", pinfo->num, address_to_str(pinfo->pool, &pinfo->src), pinfo->srcport, address_to_str(pinfo->pool, &pinfo->dst), pinfo->destport, tvb_reported_length_remaining(tvb, 0), content_type ? content_type : "[unknown content type]", (gint) content_length); */ if (headers_len < 0) { /* negative headers_len means we need more bytes */ needed = -headers_len; goto Common_Exit; } available = tvb_reported_length_remaining(tvb, offset + headers_len); if (available >= content_length) { tvbuff_t *jxta_message_tvb = tvb_new_subset_length(tvb, offset + headers_len, (gint) content_length); conversation_t *peer_conversation = NULL; jxta_tree_item = proto_tree_add_protocol_format(tree, proto_jxta, tvb, offset, -1, "JXTA" ); jxta_tree = proto_item_add_subtree(jxta_tree_item, ett_jxta); /* Redo header processing, this time populating the tree. */ headers_len = dissect_jxta_message_framing(tvb, pinfo, jxta_tree, &content_length, &content_type); tpt_conv_data = get_tpt_conversation(pinfo); peer_conversation = get_peer_conversation(pinfo, tpt_conv_data, TRUE); /* Use our source and destination addresses if we have them */ if (NULL != peer_conversation) { /* ws_message("%d Tpt %s:%d -> %s:%d", pinfo->num, address_to_str(pinfo->pool, &tpt_conv_data->initiator_tpt_address), tpt_conv_data->initiator_tpt_port, address_to_str(pinfo->pool, &tpt_conv_data->receiver_tpt_address), tpt_conv_data->receiver_tpt_port); */ if (addresses_equal(&pinfo->src, &tpt_conv_data->initiator_tpt_address) && tpt_conv_data->initiator_tpt_port == pinfo->srcport) { /* ws_message("%d From initiator : %s -> %s ", pinfo->num, address_to_str(pinfo->pool, &tpt_conv_data->initiator_address), address_to_str(pinfo->pool, &tpt_conv_data->receiver_address)); */ copy_address_shallow(&pinfo->src, &tpt_conv_data->initiator_address); pinfo->srcport = 0; copy_address_shallow(&pinfo->dst, &tpt_conv_data->receiver_address); pinfo->destport = 0; pinfo->ptype = PT_NONE; } else if (addresses_equal(&pinfo->src, &tpt_conv_data->receiver_tpt_address) && tpt_conv_data->receiver_tpt_port == pinfo->srcport) { /* ws_message("%d From receiver : %s -> %s ", pinfo->num, address_to_str(pinfo->pool, &tpt_conv_data->receiver_address), address_to_str(pinfo->pool, &tpt_conv_data->initiator_address)); */ copy_address_shallow(&pinfo->src, &tpt_conv_data->receiver_address); pinfo->srcport = 0; copy_address_shallow(&pinfo->dst, &tpt_conv_data->initiator_address); pinfo->destport = 0; pinfo->ptype = PT_NONE; } else { /* ws_message("%d Nothing matches %s:%d -> %s:%d", pinfo->num, address_to_str(pinfo->pool, &pinfo->src), pinfo->srcport, address_to_str(pinfo->pool, &pinfo->dst), pinfo->destport); */ } } processed = headers_len; processed += dissect_media(content_type, jxta_message_tvb, pinfo, tree); } else { /* we need more bytes before we can process message body. */ needed = (gint) ((guint) content_length - available); goto Common_Exit; } } offset += processed; Common_Exit: if ((needed > 0) && gDESEGMENT && pinfo->can_desegment) { /* ws_message( "Stream requesting %d more bytes", needed ); */ pinfo->desegment_offset = offset; pinfo->desegment_len = needed; return -needed; } return offset; } /** * Find or possibly create a transport conversation object for the connection * which is associated with the packet info. * * @param pinfo The packet info from the underlying transport. **/ static jxta_stream_conversation_data *get_tpt_conversation(packet_info * pinfo) { conversation_t *tpt_conversation = find_or_create_conversation(pinfo); jxta_stream_conversation_data *tpt_conv_data; conversation_set_dissector(tpt_conversation, stream_jxta_handle); tpt_conv_data = (jxta_stream_conversation_data *) conversation_get_proto_data(tpt_conversation, proto_jxta); if (NULL == tpt_conv_data) { tpt_conv_data = wmem_new(wmem_file_scope(), jxta_stream_conversation_data); tpt_conv_data->tpt_ptype = pinfo->ptype; copy_address_wmem(wmem_file_scope(), &tpt_conv_data->initiator_tpt_address, &pinfo->src); tpt_conv_data->initiator_tpt_port = pinfo->srcport; tpt_conv_data->initiator_welcome_frame = 0; clear_address(&tpt_conv_data->initiator_address); copy_address_wmem(wmem_file_scope(), &tpt_conv_data->receiver_tpt_address, &pinfo->dst); tpt_conv_data->receiver_tpt_port = pinfo->destport; tpt_conv_data->receiver_welcome_frame = 0; clear_address(&tpt_conv_data->receiver_address); conversation_add_proto_data(tpt_conversation, proto_jxta, tpt_conv_data); } return tpt_conv_data; } /** * Find or possibly create a peer conversation object for the connection * which is associated with the packet info. * * @param tpt_conv_data The transport conversation from which we will locate the peer conversation. * @param create If TRUE then create a new conversation object if necessary. **/ static conversation_t *get_peer_conversation(packet_info * pinfo, jxta_stream_conversation_data* tpt_conv_data, gboolean create) { conversation_t * peer_conversation = NULL; if ((AT_NONE != tpt_conv_data->initiator_address.type) && (AT_NONE != tpt_conv_data->receiver_address.type)) { peer_conversation = find_conversation(pinfo->num, &tpt_conv_data->initiator_address, &tpt_conv_data->receiver_address, CONVERSATION_NONE, 0, 0, NO_PORT_B); if (create && (NULL == peer_conversation)) { peer_conversation = conversation_new(pinfo->num, &tpt_conv_data->initiator_address, &tpt_conv_data->receiver_address, CONVERSATION_NONE, 0, 0, NO_PORT2); conversation_set_dissector(peer_conversation, stream_jxta_handle); } } return peer_conversation; } /** * Dissect a tvbuff containing a JXTA Welcome Message * * @param tvb The buffer to dissect. * @param pinfo Packet Info. * @param tree The protocol tree. * @param found_addr The address found in the welcome message. * @param initiator If TRUE then we believe this welcome message to be the initiator's. * @return Number of bytes from the tvbuff_t which were processed, 0 (zero) if * the packet was not recognized as a JXTA packet and negative if the * dissector needs more bytes in order to process a PDU. **/ static int dissect_jxta_welcome(tvbuff_t * tvb, packet_info * pinfo, proto_tree * tree, address * found_addr, gboolean initiator) { guint offset = 0; gint afterwelcome; gint first_linelen; guint available = tvb_reported_length_remaining(tvb, offset); gchar **tokens = NULL; if (available < sizeof(JXTA_WELCOME_MSG_SIG)) { return (gint) (available - sizeof(JXTA_WELCOME_MSG_SIG)); } if (0 != tvb_memeql(tvb, 0, (const guint8*)JXTA_WELCOME_MSG_SIG, sizeof(JXTA_WELCOME_MSG_SIG))) { /* not ours! */ return 0; } first_linelen = tvb_find_line_end(tvb, offset, -1, &afterwelcome, gDESEGMENT && pinfo->can_desegment); if (-1 == first_linelen) { if (available > 4096) { /* it's too far too be reasonable */ return 0; } else { /* ask for more bytes */ return -DESEGMENT_ONE_MORE_SEGMENT; } } /* Dissect the Welcome Message */ col_set_str(pinfo->cinfo, COL_PROTOCOL, "JXTA"); col_set_str(pinfo->cinfo, COL_INFO, "Welcome"); { gchar *welcomeline = tvb_get_string_enc(pinfo->pool, tvb, offset, first_linelen, ENC_ASCII); gchar **current_token; guint token_offset = offset; proto_item *jxta_welcome_tree_item = NULL; proto_tree *jxta_welcome_tree = NULL; tokens = wmem_strsplit(pinfo->pool, welcomeline, " ", 255); current_token = tokens; if (tree) { jxta_welcome_tree_item = proto_tree_add_none_format(tree, hf_jxta_welcome, tvb, offset, afterwelcome, "JXTA Connection Welcome Message, %s", welcomeline); jxta_welcome_tree = proto_item_add_subtree(jxta_welcome_tree_item, ett_jxta_welcome); } if (jxta_welcome_tree) { proto_item *jxta_welcome_initiator_item = proto_tree_add_boolean(jxta_welcome_tree, hf_jxta_welcome_initiator, tvb, 0, 0, initiator); proto_item_set_generated(jxta_welcome_initiator_item); } if (NULL != *current_token) { proto_tree_add_item(jxta_welcome_tree, hf_jxta_welcome_sig, tvb, token_offset, (gint) strlen(*current_token), ENC_ASCII); token_offset += (guint) strlen(*current_token) + 1; current_token++; } else { /* invalid welcome message */ afterwelcome = 0; goto Common_Exit; } if (NULL != *current_token) { if (jxta_welcome_tree) { proto_tree_add_item(jxta_welcome_tree, hf_jxta_welcome_destAddr, tvb, token_offset, (gint) strlen(*current_token), ENC_ASCII); } token_offset += (guint) strlen(*current_token) + 1; current_token++; } else { /* invalid welcome message */ afterwelcome = 0; goto Common_Exit; } if (NULL != *current_token) { if (jxta_welcome_tree) { proto_tree_add_item(jxta_welcome_tree, hf_jxta_welcome_pubAddr, tvb, token_offset, (gint) strlen(*current_token), ENC_ASCII); } token_offset += (guint) strlen(*current_token) + 1; current_token++; } else { /* invalid welcome message */ afterwelcome = 0; goto Common_Exit; } if (NULL != *current_token) { if (jxta_welcome_tree) { proto_tree_add_item(jxta_welcome_tree, hf_jxta_welcome_peerid, tvb, token_offset, (gint) strlen(*current_token), ENC_ASCII); } col_append_str(pinfo->cinfo, COL_INFO, (initiator ? " -> " : " <- ") ); col_append_str(pinfo->cinfo, COL_INFO, *current_token); if (NULL != found_addr) { set_address(found_addr, uri_address_type, (int)strlen(*current_token) + 1, wmem_strdup(wmem_file_scope(), *current_token)); } token_offset += (guint) strlen(*current_token) + 1; current_token++; } else { /* invalid welcome message */ afterwelcome = 0; goto Common_Exit; } if (NULL != *current_token) { int variable_tokens = 0; gchar **variable_token = current_token; while(NULL != *variable_token) { variable_tokens++; variable_token++; } if( variable_tokens < 1 ) { /* invalid welcome message */ afterwelcome = 0; goto Common_Exit; } if( (2 == variable_tokens) && (0 == strcmp(JXTA_WELCOME_MSG_VERSION_1_1, current_token[variable_tokens -1])) ) { if (jxta_welcome_tree) { proto_tree_add_item(jxta_welcome_tree, hf_jxta_welcome_noProp, tvb, token_offset, (gint) strlen(*current_token), ENC_ASCII); } token_offset += (guint) strlen(*current_token) + 1; current_token++; if (jxta_welcome_tree) { proto_tree_add_item(jxta_welcome_tree, hf_jxta_welcome_version, tvb, token_offset, (gint) strlen(*current_token), ENC_ASCII); } } else if( (3 == variable_tokens) && (0 == strcmp(JXTA_WELCOME_MSG_VERSION_3_0, current_token[variable_tokens -1])) ) { if (jxta_welcome_tree) { proto_tree_add_item(jxta_welcome_tree, hf_jxta_welcome_noProp, tvb, token_offset, (gint) strlen(*current_token), ENC_ASCII); } token_offset += (guint) strlen(*current_token) + 1; current_token++; if (jxta_welcome_tree) { proto_tree_add_item(jxta_welcome_tree, hf_jxta_welcome_msgVers, tvb, token_offset, (gint) strlen(*current_token), ENC_ASCII); } token_offset += (guint) strlen(*current_token) + 1; current_token++; if (jxta_welcome_tree) { proto_tree_add_item(jxta_welcome_tree, hf_jxta_welcome_version, tvb, token_offset, (gint) strlen(*current_token), ENC_ASCII); } } else { /* Unrecognized Welcome Version */ int each_variable_token; for( each_variable_token = 0; each_variable_token < variable_tokens; each_variable_token++ ) { if (jxta_welcome_tree) { jxta_welcome_tree_item = proto_tree_add_item(jxta_welcome_tree, (each_variable_token < (variable_tokens -1) ? hf_jxta_welcome_variable : hf_jxta_welcome_version), tvb, token_offset, (gint) strlen(*current_token), ENC_ASCII|ENC_NA); proto_item_append_text(jxta_welcome_tree_item, " (UNRECOGNIZED)"); } token_offset += (guint) strlen(*current_token) + 1; current_token++; } } } else { /* invalid welcome message */ afterwelcome = 0; goto Common_Exit; } } Common_Exit: col_set_writable(pinfo->cinfo, -1, FALSE); return afterwelcome; } /** * Dissect a tvbuff containing JXTA Message framing. * * @param tvb The buffer to dissect. * @param pinfo Packet Info. * @param tree The protocol tree. * @param content_length Pointer to a buffer for storing the value of the * "content-length" header or NULL. * @param content_type Pointer-to-a-pointer for a new buffer for storing the * value of the "content_type-length" header or NULL. * @return Number of bytes from the tvbuff_t which were processed, 0 (zero) if * the packet was not recognized as a JXTA packet and negative if the * dissector needs more bytes in order to process a PDU. **/ static int dissect_jxta_message_framing(tvbuff_t * tvb, packet_info * pinfo, proto_tree * tree, guint64 * content_length, gchar ** content_type) { guint offset = 0; guint available; gint needed = 0; /* * First go around. Make sure all of the bytes are there. */ do { guint8 headername_len; guint8 headername_offset; guint16 headervalue_len; guint16 headervalue_offset; available = tvb_reported_length_remaining(tvb, offset); if (available < 1) { needed = 1; break; } else { headername_len = tvb_get_guint8(tvb, offset); offset++; headername_offset = offset; available = tvb_reported_length_remaining(tvb, offset); if (available < headername_len) { needed = (gint) (headername_len - available); break; } if (0 == headername_len) { break; } offset += headername_len; } available = tvb_reported_length_remaining(tvb, offset); if (available < 2) { needed = (gint) (2 - available); break; } else { headervalue_len = tvb_get_ntohs(tvb, offset); offset += 2; headervalue_offset = offset; available = tvb_reported_length_remaining(tvb, offset); if (available < headervalue_len) { needed = (gint) (headervalue_len - available); break; } offset += headervalue_len; } if (content_type && (sizeof("content-type") - 1) == headername_len) { if (0 == tvb_strncaseeql(tvb, headername_offset, "content-type", sizeof("content-type") - 1)) { *content_type = tvb_get_string_enc(pinfo->pool, tvb, headervalue_offset, headervalue_len, ENC_ASCII); } } if (content_length && (sizeof(guint64) == headervalue_len) && ((sizeof("content-length") - 1) == headername_len)) { if (0 == tvb_strncaseeql(tvb, headername_offset, "content-length", sizeof("content-length") - 1)) { *content_length = tvb_get_ntoh64(tvb, headervalue_offset); } } } while (TRUE); if ((needed > 0) && gDESEGMENT && pinfo->can_desegment) { /* ws_message( "Framing requesting %d more bytes", needed ); */ pinfo->desegment_offset = 0; pinfo->desegment_len = needed; return -needed; } /* * Second (optional pass) Now that we are sure that all the bytes are there we update the protocol tree. */ if (tree) { guint tree_offset = 0; proto_item *framing_tree_item; proto_tree *framing_tree; framing_tree_item = proto_tree_add_none_format(tree, hf_jxta_framing, tvb, tree_offset, -1, "JXTA Message Framing Headers"); framing_tree = proto_item_add_subtree(framing_tree_item, ett_jxta_framing); /* parse framing headers */ do { guint8 headernamelen = tvb_get_guint8(tvb, tree_offset); proto_item *framing_header_tree_item = proto_tree_add_item(framing_tree, hf_jxta_framing_header, tvb, tree_offset, -1, ENC_NA); proto_tree *framing_header_tree = proto_item_add_subtree(framing_header_tree_item, ett_jxta_framing_header); /* * Put header name into the protocol tree */ proto_tree_add_item(framing_header_tree, hf_jxta_framing_header_name, tvb, tree_offset, (int)sizeof(gint8), ENC_ASCII|ENC_BIG_ENDIAN); /* * Append header name into the header protocol item. It's a nice hint so you don't have to reveal all headers. */ if (headernamelen > 0) { proto_item_append_text(framing_header_tree_item, " \"%s\"", tvb_format_text(pinfo->pool, tvb, tree_offset + 1, headernamelen)); } tree_offset += 1 + headernamelen; if (headernamelen > 0) { guint16 headervaluelen = tvb_get_ntohs(tvb, tree_offset); if (tree) { proto_tree_add_uint(framing_header_tree, hf_jxta_framing_header_value_length, tvb, tree_offset, 2, headervaluelen); /** TODO bondolo Add specific handling for known header types */ /* * Put header value into protocol tree. */ proto_tree_add_item(framing_header_tree, hf_jxta_framing_header_value, tvb, tree_offset + 2, headervaluelen, ENC_NA); } tree_offset += 2 + headervaluelen; } proto_item_set_end(framing_header_tree_item, tvb, tree_offset); if (0 == headernamelen) { break; } } while (TRUE); proto_item_set_end(framing_tree_item, tvb, tree_offset); DISSECTOR_ASSERT(offset == tree_offset); } /* return how many bytes we used up. */ return offset; } /** * Dissect a tvbuff containing one or more JXTA Messages. * * @param tvb The buffer to dissect. * @param pinfo Packet Info. * @param tree The protocol tree. * @return Number of bytes from the tvbuff_t which were processed, 0 (zero) if * the packet was not recognized as a JXTA packet and negative if the * dissector needs more bytes in order to process a PDU. **/ static int dissect_jxta_message(tvbuff_t * tvb, packet_info * pinfo, proto_tree * tree, void * data _U_) { gint complete_messages = 0; guint offset = 0; guint tree_offset = 0; guint available; gint needed = 0; wmem_strbuf_t* src_addr; wmem_strbuf_t* dst_addr; while (TRUE) { guint8 message_version; guint message_start_offset = offset; /* First pass. Make sure all of the bytes we need are available */ available = tvb_reported_length_remaining(tvb, offset); if((0 == available) && (0 != complete_messages)) { /* We have discovered all of the complete messages in the tvbuff. */ break; } if (available < sizeof(JXTA_MSG_SIG)) { needed = (gint) (sizeof(JXTA_MSG_SIG) - available); break; } if (tvb_memeql(tvb, offset, (const guint8*)JXTA_MSG_SIG, sizeof(JXTA_MSG_SIG)) != 0) { /* It is not one of ours */ return 0; } offset += (int)sizeof(JXTA_MSG_SIG); available = tvb_reported_length_remaining(tvb, offset); if (available < 1) { needed = 1; break; } else { message_version = tvb_get_guint8(tvb, offset); offset++; if ((JXTA_MSG_VERSION_1 != message_version) && (JXTA_MSG_VERSION_2 != message_version)) { /* Sort of a lie, we say that we don't recognize it at all. */ return 0; } } /* Read the flags (Version 2 and later) */ if(message_version > 0) { available = tvb_reported_length_remaining(tvb, offset); if (available < 1) { needed = 1; break; } else { offset++; } } /* Read names table */ available = tvb_reported_length_remaining(tvb, offset); if (available < 2) { needed = (gint) (2 - available); break; } else { guint16 msg_names_count = tvb_get_ntohs(tvb, offset); guint each_name; offset += 2; for (each_name = 0; each_name < msg_names_count; each_name++) { guint16 name_len; available = tvb_reported_length_remaining(tvb, offset); if (available < sizeof(name_len)) { needed = (gint) (sizeof(name_len) - available); break; } name_len = tvb_get_ntohs(tvb, offset); available = tvb_reported_length_remaining(tvb, offset + (int)sizeof(name_len)); if (available < name_len) { needed = (gint) (name_len - available); break; } offset += (int)sizeof(name_len) + name_len; } } /* parse element count */ available = tvb_reported_length_remaining(tvb, offset); if (available < 2) { needed = (gint) (2 - available); break; } else { guint16 elem_count = tvb_get_ntohs(tvb, offset); guint each_elem; offset += 2; /* parse elements */ for (each_elem = 0; each_elem < elem_count; each_elem++) { tvbuff_t *jxta_message_element_tvb = tvb_new_subset_remaining(tvb, offset); int processed; if (JXTA_MSG_VERSION_1 == message_version) { processed = dissect_jxta_message_element_1(jxta_message_element_tvb, pinfo, NULL, 0, NULL); } else { /* JXTA_MSG_VERSION_2 */ processed = dissect_jxta_message_element_2(jxta_message_element_tvb, pinfo, NULL, 0, NULL); } if (processed < 0) { needed = -processed; break; } if (0 == processed) { /* XXX bondolo Not really clear what we should do! */ /* eapache: based on reading the code, I believe this can occur * when the message_version is valid but the JXTA_MSGELEM_SIG * (some sort of magic number?) is not. This almost * certainly indicates a corrupt packet, so this should * probably be expert info, not a ws_warning. Pending confirmation * just comment it out since a ws_warning is definitely the * wrong thing to do. * ws_warning( "Failure processing message element #%d of %d of frame %d", each_elem, elem_count, pinfo->num ); */ return 0; } offset += processed; } } if ((uri_address_type == pinfo->src.type) && (uri_address_type == pinfo->dst.type)) { jxta_tap_header *tap_header = wmem_new(wmem_file_scope(), jxta_tap_header); copy_address_shallow(&tap_header->src_address, &pinfo->src); copy_address_shallow(&tap_header->dest_address, &pinfo->dst); tap_header->size = offset - message_start_offset ; tap_queue_packet(jxta_tap, pinfo, tap_header); } complete_messages++; /* ws_message( "%d Scanned message #%d: ", pinfo->num, complete_messages ); */ } if ((needed > 0) && gDESEGMENT && pinfo->can_desegment) { /* ws_message("Frame %d: Message requesting %d more bytes", pinfo->num, needed); */ pinfo->desegment_offset = 0; pinfo->desegment_len = needed; return -needed; } src_addr = wmem_strbuf_create(pinfo->pool); wmem_strbuf_append(src_addr, address_to_str(pinfo->pool, &pinfo->src)); dst_addr = wmem_strbuf_create(pinfo->pool); wmem_strbuf_append(dst_addr, address_to_str(pinfo->pool, &pinfo->dst)); /* append the port if appropriate */ if (PT_NONE != pinfo->ptype) { wmem_strbuf_append_printf(src_addr, ":%d", pinfo->srcport); wmem_strbuf_append_printf(dst_addr, ":%d", pinfo->destport); } col_set_str(pinfo->cinfo, COL_PROTOCOL, "JXTA"); if( complete_messages > 1 ) { col_add_fstr(pinfo->cinfo, COL_INFO, "%d Messages, %s -> %s", complete_messages, wmem_strbuf_get_str(src_addr), wmem_strbuf_get_str(dst_addr)); } else { col_add_fstr(pinfo->cinfo, COL_INFO, "Message, %s -> %s", wmem_strbuf_get_str(src_addr), wmem_strbuf_get_str(dst_addr)); } col_set_writable(pinfo->cinfo, -1, FALSE); while( tree && (complete_messages > 0) ) { proto_item *jxta_msg_tree_item = NULL; proto_tree *jxta_msg_tree = NULL; guint8 message_version; const gchar **names_table = NULL; guint16 msg_names_count; guint each_name; guint16 elem_count; guint each_elem; proto_item *tree_item; jxta_msg_tree_item = proto_tree_add_protocol_format(tree, proto_message_jxta, tvb, tree_offset, -1, "JXTA Message, %s -> %s", wmem_strbuf_get_str(src_addr), wmem_strbuf_get_str(dst_addr)); jxta_msg_tree = proto_item_add_subtree(jxta_msg_tree_item, ett_jxta_msg); proto_tree_add_item(jxta_msg_tree, hf_jxta_message_sig, tvb, tree_offset, (int)sizeof(JXTA_MSG_SIG), ENC_ASCII); tree_offset += (int)sizeof(JXTA_MSG_SIG); tree_item = proto_tree_add_string(jxta_msg_tree, hf_jxta_message_src, tvb, 0, 0, wmem_strbuf_get_str(src_addr)); proto_item_set_generated(tree_item); tree_item = proto_tree_add_string(jxta_msg_tree, hf_jxta_message_address, tvb, 0, 0, wmem_strbuf_get_str(src_addr)); proto_item_set_hidden(tree_item); proto_item_set_generated(tree_item); if(uri_address_type == pinfo->src.type) { tree_item = proto_tree_add_string(jxta_msg_tree, hf_uri_src, tvb, 0, 0, wmem_strbuf_get_str(src_addr)); proto_item_set_hidden(tree_item); proto_item_set_generated(tree_item); tree_item = proto_tree_add_string(jxta_msg_tree, hf_uri_addr, tvb, 0, 0, wmem_strbuf_get_str(src_addr)); proto_item_set_hidden(tree_item); proto_item_set_generated(tree_item); } tree_item = proto_tree_add_string(jxta_msg_tree, hf_jxta_message_dst, tvb, 0, 0, wmem_strbuf_get_str(dst_addr)); proto_item_set_generated(tree_item); tree_item = proto_tree_add_string(jxta_msg_tree, hf_jxta_message_address, tvb, 0, 0, wmem_strbuf_get_str(dst_addr)); proto_item_set_hidden(tree_item); proto_item_set_generated(tree_item); if(uri_address_type == pinfo->dst.type) { tree_item = proto_tree_add_string(jxta_msg_tree, hf_uri_dst, tvb, 0, 0, wmem_strbuf_get_str(dst_addr)); proto_item_set_hidden(tree_item); proto_item_set_generated(tree_item); tree_item = proto_tree_add_string(jxta_msg_tree, hf_uri_addr, tvb, 0, 0, wmem_strbuf_get_str(dst_addr)); proto_item_set_hidden(tree_item); proto_item_set_generated(tree_item); } message_version = tvb_get_guint8(tvb, tree_offset); proto_tree_add_uint(jxta_msg_tree, hf_jxta_message_version, tvb, tree_offset, 1, message_version); tree_offset += 1; if( message_version > 0 ) { static int * const flags[] = { &hf_jxta_message_flag_utf16be, &hf_jxta_message_flag_ucs32be, NULL }; proto_tree_add_bitmask(jxta_msg_tree, tvb, tree_offset, hf_jxta_message_flags, ett_jxta_msg_flags, flags, ENC_NA); tree_offset += 1; } msg_names_count = tvb_get_ntohs(tvb, tree_offset); proto_tree_add_uint(jxta_msg_tree, hf_jxta_message_names_count, tvb, tree_offset, 2, msg_names_count); tree_offset += 2; names_table = (const gchar **)wmem_alloc(pinfo->pool, (msg_names_count + 2) * sizeof(const gchar *)); names_table[0] = ""; names_table[1] = "jxta"; /* parse names */ for (each_name = 0; each_name < msg_names_count; each_name++) { guint16 name_len = tvb_get_ntohs(tvb, tree_offset); names_table[2 + each_name] = tvb_get_string_enc(pinfo->pool, tvb, tree_offset + 2, name_len, ENC_ASCII); proto_tree_add_item(jxta_msg_tree, hf_jxta_message_names_name, tvb, tree_offset, 2, ENC_ASCII|ENC_BIG_ENDIAN); tree_offset += 2 + name_len; } /* parse element count */ elem_count = tvb_get_ntohs(tvb, tree_offset); proto_tree_add_item(jxta_msg_tree, hf_jxta_message_element_count, tvb, tree_offset, 2, ENC_BIG_ENDIAN); tree_offset += 2; /* FIXME bondolo Element count 0 (Process elements until FIN) should be supported. */ /* parse elements */ for (each_elem = 0; each_elem < elem_count; each_elem++) { tvbuff_t *jxta_message_element_tvb = tvb_new_subset_remaining(tvb, tree_offset); if(JXTA_MSG_VERSION_1 == message_version) { tree_offset += dissect_jxta_message_element_1(jxta_message_element_tvb, pinfo, jxta_msg_tree, msg_names_count + 2, names_table); } else if(JXTA_MSG_VERSION_2 == message_version) { tree_offset += dissect_jxta_message_element_2(jxta_message_element_tvb, pinfo, jxta_msg_tree, msg_names_count + 2, names_table); } else { /* Sort of a lie, we say that we don't recognize it at all. */ return 0; } } proto_item_set_end(jxta_msg_tree_item, tvb, tree_offset); complete_messages--; } if( tree ) { /* ws_message( "%d tvb offset : %d tree offset : %d", pinfo->num, offset, tree_offset ); */ DISSECTOR_ASSERT(tree_offset == offset); } return offset; } /** * Dissect a tvbuff containing a JXTA Message Element (Version 1). * * @param tvb The buffer to dissect. * @param pinfo Packet Info. * @param tree The protocol tree. * @return Number of bytes from the tvbuff_t which were processed, 0 (zero) if * the packet was not recognized as a JXTA packet and negative if the * dissector needs more bytes in order to process a PDU. **/ // NOLINTNEXTLINE(misc-no-recursion) static int dissect_jxta_message_element_1(tvbuff_t * tvb, packet_info * pinfo, proto_tree * tree, guint ns_count, const gchar ** names_table) { guint offset = 0; guint available; gint needed = 0; guint8 flags; /* First pass. Make sure all of the bytes we need are available */ while (TRUE) { /* signature field */ available = tvb_reported_length_remaining(tvb, offset); if (available < sizeof(JXTA_MSGELEM_SIG)) { needed = (gint) (sizeof(JXTA_MSGELEM_SIG) - available); } if (tvb_memeql(tvb, offset, (const guint8*)JXTA_MSGELEM_SIG, sizeof(JXTA_MSGELEM_SIG)) != 0) { /* It is not one of ours */ return 0; } offset += (int)sizeof(JXTA_MSGELEM_SIG); /* namespace id field */ available = tvb_reported_length_remaining(tvb, offset); if (available < 1) { needed = 1; break; } offset++; /* flags field */ available = tvb_reported_length_remaining(tvb, offset); if (available < 1) { needed = 1; break; } else { flags = tvb_get_guint8(tvb, offset); offset++; } /* name field */ available = tvb_reported_length_remaining(tvb, offset); if (available < 2) { needed = (gint) (2 - available); break; } else { guint16 name_len = tvb_get_ntohs(tvb, offset); offset += 2; available = tvb_reported_length_remaining(tvb, offset); if (available < name_len) { needed = (gint) (name_len - available); break; } offset += name_len; } /* type field */ if ((flags & JXTAMSG1_ELMFLAG_TYPE) != 0) { guint16 type_len; available = tvb_reported_length_remaining(tvb, offset); if (available < 2) { needed = (gint) (2 - available); break; } type_len = tvb_get_ntohs(tvb, offset); offset += 2; available = tvb_reported_length_remaining(tvb, offset); if (available < type_len) { needed = (gint) (type_len - available); break; } offset += type_len; } /* encoding field */ if ((flags & JXTAMSG1_ELMFLAG_ENCODING) != 0) { guint16 encoding_len; available = tvb_reported_length_remaining(tvb, offset); if (available < 2) { needed = (gint) (2 - available); break; } encoding_len = tvb_get_ntohs(tvb, offset); offset += 2; available = tvb_reported_length_remaining(tvb, offset); if (available < encoding_len) { needed = (gint) (encoding_len - available); break; } offset += encoding_len; } /* content field */ available = tvb_reported_length_remaining(tvb, offset); if (available < 2) { needed = (gint) (2 - available); break; } else { guint32 content_len = tvb_get_ntohl(tvb, offset); offset += 4; available = tvb_reported_length_remaining(tvb, offset); if (available < content_len) { needed = (gint) (content_len - available); break; } offset += content_len; } /* signature element field */ if ((flags & JXTAMSG1_ELMFLAG_SIGNATURE) != 0) { tvbuff_t *jxta_signature_element_tvb; int processed; jxta_signature_element_tvb = tvb_new_subset_remaining(tvb, offset); increment_dissection_depth(pinfo); processed = dissect_jxta_message_element_1(jxta_signature_element_tvb, pinfo, NULL, 0, NULL); decrement_dissection_depth(pinfo); if (processed == 0) { return offset; } if (processed < 0) { needed = -processed; break; } offset += processed; } break; } if ((needed > 0) && gDESEGMENT && pinfo->can_desegment) { /* ws_message( "Element1 requesting %d more bytes", needed ); */ pinfo->desegment_offset = 0; pinfo->desegment_len = needed; return -needed; } /* Second pass : build the proto tree */ guint tree_offset = 0; proto_item *jxta_elem_tree_item = proto_tree_add_item(tree, hf_jxta_element, tvb, tree_offset, -1, ENC_NA); proto_tree *jxta_elem_tree = proto_item_add_subtree(jxta_elem_tree_item, ett_jxta_elem); guint8 namespaceID; proto_item *namespace_ti; guint16 name_len; guint32 content_len; gchar *mediatype = NULL; tvbuff_t *element_content_tvb; static int * const element_flags[] = { &hf_jxta_element1_flag_hasType, &hf_jxta_element1_flag_hasEncoding, &hf_jxta_element1_flag_hasSignature, NULL }; proto_tree_add_item(jxta_elem_tree, hf_jxta_element_sig, tvb, tree_offset, (int)sizeof(JXTA_MSGELEM_SIG), ENC_ASCII); tree_offset += (int)sizeof(JXTA_MSGELEM_SIG); namespaceID = tvb_get_guint8(tvb, tree_offset); namespace_ti = proto_tree_add_uint(jxta_elem_tree, hf_jxta_element1_namespaceid, tvb, tree_offset, 1, namespaceID); if (namespaceID < ns_count) { proto_item_append_text(namespace_ti, " (%s)", names_table[namespaceID]); } else { proto_item_append_text(namespace_ti, " * BAD *"); } tree_offset += 1; flags = tvb_get_guint8(tvb, tree_offset); proto_tree_add_bitmask(jxta_elem_tree, tvb, tree_offset, hf_jxta_element_flags, ett_jxta_elem_1_flags, element_flags, ENC_NA); tree_offset += 1; name_len = tvb_get_ntohs(tvb, tree_offset); proto_item_append_text(jxta_elem_tree_item, " \"%s\"", tvb_format_text(pinfo->pool, tvb, tree_offset + 2, name_len)); proto_tree_add_item(jxta_elem_tree, hf_jxta_element_name, tvb, tree_offset, 2, ENC_ASCII|ENC_BIG_ENDIAN); tree_offset += 2 + name_len; /* process type */ if ((flags & JXTAMSG1_ELMFLAG_TYPE) != 0) { guint16 type_len = tvb_get_ntohs(tvb, tree_offset); proto_tree_add_item(jxta_elem_tree, hf_jxta_element_type, tvb, tree_offset, 2, ENC_ASCII|ENC_BIG_ENDIAN); tree_offset += 2; mediatype = tvb_get_string_enc(pinfo->pool, tvb, tree_offset, type_len, ENC_ASCII); tree_offset += type_len; } /* process encoding */ if ((flags & JXTAMSG1_ELMFLAG_ENCODING) != 0) { guint16 encoding_len = tvb_get_ntohs(tvb, tree_offset); proto_tree_add_item(jxta_elem_tree, hf_jxta_element_encoding, tvb, tree_offset, 2, ENC_ASCII|ENC_BIG_ENDIAN); tree_offset += 2 + encoding_len; } /* content */ content_len = tvb_get_ntohl(tvb, tree_offset); proto_tree_add_item(jxta_elem_tree, hf_jxta_element_content_len, tvb, tree_offset, 4, ENC_BIG_ENDIAN); tree_offset += 4; element_content_tvb = tvb_new_subset_length(tvb, tree_offset, content_len); tree_offset += dissect_media(mediatype, element_content_tvb, pinfo, jxta_elem_tree); /* process the signature element */ if ((flags & JXTAMSG1_ELMFLAG_SIGNATURE) != 0) { tvbuff_t *jxta_message_element_tvb = tvb_new_subset_remaining(tvb, tree_offset); increment_dissection_depth(pinfo); tree_offset += dissect_jxta_message_element_1(jxta_message_element_tvb, pinfo, jxta_elem_tree, ns_count, names_table); decrement_dissection_depth(pinfo); } proto_item_set_end(jxta_elem_tree_item, tvb, tree_offset); // offset is based on reported lengths. tree_offset is based on captured lengths via dissect_media. // Comment this out for now in favor of dissect_media's expert warning. // DISSECTOR_ASSERT(tree_offset == offset); return offset; } /** * Dissect a tvbuff containing a JXTA Message Element (Version 2). * * @param tvb The buffer to dissect. * @param pinfo Packet Info. * @param tree The protocol tree. * @param names_count The number of elements in the names table. * @param names_table The table of names. * @return Number of bytes from the tvbuff_t which were processed, 0 (zero) if * the packet was not recognized as a JXTA packet and negative if the * dissector needs more bytes in order to process a PDU. **/ // NOLINTNEXTLINE(misc-no-recursion) static int dissect_jxta_message_element_2(tvbuff_t * tvb, packet_info * pinfo, proto_tree * tree, guint names_count, const gchar ** names_table) { guint offset = 0; guint available; gint needed = 0; guint8 flags; /* First pass. Make sure all of the bytes we need are available */ while (TRUE) { /* signature field */ available = tvb_reported_length_remaining(tvb, offset); if (available < sizeof(JXTA_MSGELEM_SIG)) { needed = (gint) (sizeof(JXTA_MSGELEM_SIG) - available); } if (tvb_memeql(tvb, offset, (const guint8*)JXTA_MSGELEM_SIG, sizeof(JXTA_MSGELEM_SIG)) != 0) { /* It is not one of ours */ return 0; } offset += (int)sizeof(JXTA_MSGELEM_SIG); /* flags field */ available = tvb_reported_length_remaining(tvb, offset); if (available < 1) { needed = 1; break; } else { flags = tvb_get_guint8(tvb, offset); offset++; } /* namespace id field */ available = tvb_reported_length_remaining(tvb, offset); if (available < 2) { needed = (gint) (2 - available); break; } offset += 2; /* name field */ if ((flags & JXTAMSG2_ELMFLAG_NAME_LITERAL) == 0) { available = tvb_reported_length_remaining(tvb, offset); if (available < 2) { needed = (gint) (2 - available); break; } offset += 2; } else { /* literal name field */ available = tvb_reported_length_remaining(tvb, offset); if (available < 2) { needed = (gint) (2 - available); break; } else { guint16 name_len = tvb_get_ntohs(tvb, offset); offset += 2; available = tvb_reported_length_remaining(tvb, offset); if (available < name_len) { needed = (gint) (name_len - available); break; } offset += name_len; } } /* type field */ if ((flags & JXTAMSG2_ELMFLAG_TYPE) != 0) { available = tvb_reported_length_remaining(tvb, offset); if (available < 2) { needed = (gint) (2 - available); break; } offset += 2; } /* encoding field */ if ((flags & JXTAMSG2_ELMFLAG_ENCODINGS) != 0) { available = tvb_reported_length_remaining(tvb, offset); if (available < 2) { needed = (gint) (2 - available); break; } offset += 2; } /* content field */ if ((flags & JXTAMSG2_ELMFLAG_UINT64_LENS) != 0) { available = tvb_reported_length_remaining(tvb, offset); if (available < sizeof(guint64)) { needed = (gint) (sizeof(guint64) - available); break; } else { guint64 content_len = tvb_get_ntoh64(tvb, offset); offset += (int)sizeof(guint64); available = tvb_reported_length_remaining(tvb, offset); if (available < content_len) { needed = (gint) (content_len - available); break; } offset += (guint) content_len; } } else { available = tvb_reported_length_remaining(tvb, offset); if (available < 4) { needed = (gint) (4 - available); break; } else { guint64 content_len = tvb_get_ntohl(tvb, offset); offset += 4; available = tvb_reported_length_remaining(tvb, offset); if (available < content_len) { needed = (gint) (content_len - available); break; } offset += (guint) content_len; } } /* signature element field */ if ((flags & JXTAMSG2_ELMFLAG_SIGNATURE) != 0) { tvbuff_t *jxta_signature_element_tvb; int processed; jxta_signature_element_tvb = tvb_new_subset_remaining(tvb, offset); increment_dissection_depth(pinfo); processed = dissect_jxta_message_element_2(jxta_signature_element_tvb, pinfo, NULL, 0, NULL); decrement_dissection_depth(pinfo); if (processed == 0) { return offset; } if (processed < 0) { needed = -processed; break; } offset += processed; } break; } if ((needed > 0) && gDESEGMENT && pinfo->can_desegment) { /* ws_message( "Element2 requesting %d more bytes", needed ); */ pinfo->desegment_offset = 0; pinfo->desegment_len = needed; return -needed; } /* Second (optional) pass : build the proto tree */ guint tree_offset = 0; proto_item *jxta_elem_tree_item = proto_tree_add_item(tree, hf_jxta_element, tvb, tree_offset, -1, ENC_NA); proto_tree *jxta_elem_tree = proto_item_add_subtree(jxta_elem_tree_item, ett_jxta_elem); guint16 namespaceID; proto_item *namespace_ti; guint16 nameID; proto_item *name_ti; guint64 content_len; const gchar *mediatype = NULL; tvbuff_t *element_content_tvb; static int * const element_flags[] = { &hf_jxta_element2_flag_64bitlens, &hf_jxta_element2_flag_nameLiteral, &hf_jxta_element2_flag_hasType, &hf_jxta_element2_flag_hasSignature, &hf_jxta_element2_flag_hasEncoding, &hf_jxta_element2_flag_sigOfEncoded, NULL }; proto_tree_add_item(jxta_elem_tree, hf_jxta_element_sig, tvb, tree_offset, (int)sizeof(JXTA_MSGELEM_SIG), ENC_ASCII); tree_offset += (int)sizeof(JXTA_MSGELEM_SIG); flags = tvb_get_guint8(tvb, tree_offset); proto_tree_add_bitmask(jxta_elem_tree, tvb, tree_offset, hf_jxta_element_flags, ett_jxta_elem_2_flags, element_flags, ENC_NA); tree_offset += 1; /* Namespace */ namespaceID = tvb_get_ntohs(tvb, tree_offset); namespace_ti = proto_tree_add_uint(jxta_elem_tree, hf_jxta_element2_namespaceid, tvb, tree_offset, 2, namespaceID); if (namespaceID < names_count) { proto_item_append_text(namespace_ti, " (%s)", names_table[namespaceID]); } else { proto_item_append_text(namespace_ti, " * BAD *"); } tree_offset += 2; /* Name */ if ((flags & JXTAMSG2_ELMFLAG_NAME_LITERAL) == 0) { nameID = tvb_get_ntohs(tvb, tree_offset); name_ti = proto_tree_add_uint(jxta_elem_tree, hf_jxta_element2_nameid, tvb, tree_offset, 2, nameID); if (nameID < names_count) { proto_item_append_text(name_ti, " (%s)", names_table[nameID]); } else { proto_item_append_text(name_ti, " * BAD *"); } tree_offset += 2; } else { /* literal name */ guint16 name_len = tvb_get_ntohs(tvb, tree_offset); proto_item_append_text(jxta_elem_tree_item, " \"%s\"", tvb_format_text(pinfo->pool, tvb, tree_offset + 2, name_len)); proto_tree_add_item(jxta_elem_tree, hf_jxta_element_name, tvb, tree_offset, 2, ENC_ASCII|ENC_BIG_ENDIAN); tree_offset += 2 + name_len; } /* process type */ if ((flags & JXTAMSG2_ELMFLAG_TYPE) != 0) { guint16 mimeID = tvb_get_ntohs(tvb, tree_offset); proto_item *mime_ti = proto_tree_add_uint(jxta_elem_tree, hf_jxta_element2_mimeid, tvb, tree_offset, 2, mimeID); if (mimeID < names_count) { proto_item_append_text(mime_ti, " (%s)", names_table[mimeID]); mediatype = wmem_strdup( pinfo->pool, names_table[mimeID] ); } else { proto_item_append_text(mime_ti, " * BAD *"); } tree_offset += 2; } else { mediatype = "application/octet-stream"; } /* process encoding */ if ((flags & JXTAMSG2_ELMFLAG_ENCODINGS) != 0) { guint16 encodingID = tvb_get_ntohs(tvb, tree_offset); proto_item *encoding_ti = proto_tree_add_uint(jxta_elem_tree, hf_jxta_element2_encodingid, tvb, tree_offset, 2, encodingID); if (encodingID < names_count) { proto_item_append_text(encoding_ti, " (%s)", names_table[encodingID]); } else { proto_item_append_text(encoding_ti, " * BAD *"); } tree_offset += 2; } if ((flags & JXTAMSG2_ELMFLAG_UINT64_LENS) != 0) { content_len = tvb_get_ntoh64(tvb, tree_offset); proto_tree_add_item(jxta_elem_tree, hf_jxta_element_content_len64, tvb, tree_offset, 8, ENC_BIG_ENDIAN); tree_offset += 8; } else { content_len = tvb_get_ntohl(tvb, tree_offset); proto_tree_add_item(jxta_elem_tree, hf_jxta_element_content_len, tvb, tree_offset, 4, ENC_BIG_ENDIAN); tree_offset += 4; } /* content */ element_content_tvb = tvb_new_subset_length(tvb, tree_offset, (gint)content_len); tree_offset += dissect_media(mediatype, element_content_tvb, pinfo, jxta_elem_tree); /* process the signature element */ if ((flags & JXTAMSG2_ELMFLAG_SIGNATURE) != 0) { tvbuff_t *jxta_message_element_tvb = tvb_new_subset_remaining(tvb, tree_offset); tree_offset += dissect_jxta_message_element_1(jxta_message_element_tvb, pinfo, jxta_elem_tree, names_count, names_table); } proto_item_set_end(jxta_elem_tree_item, tvb, tree_offset); // offset is based on reported lengths. tree_offset is based on captured lengths via dissect_media. // Comment this out for now in favor of dissect_media's expert warning. // DISSECTOR_ASSERT(tree_offset == offset); return offset; } /** * Dissect a tvbuff containing arbitrary typed data. * *

We provide special handling for type media types : *

*
application/x-jxta-tls-block
*
We hand this data off to SSL to dissect.
*
application/gzip
*
We decompress the data and then dissect the contents as text/xml;charset="UTF-8"
*
* * @param fullmediatype The full media type of the buffer to dissect including params * @param tvb The buffer to dissect. * @param pinfo Packet Info. * @param tree The protocol tree. * @return Number of bytes from the tvbuff_t which were processed, 0 (zero) if * the packet was not recognized and negative if the dissector needs * more bytes in order to process a PDU. **/ // NOLINTNEXTLINE(misc-no-recursion) static int dissect_media( const gchar* fullmediatype, tvbuff_t * tvb, packet_info * pinfo, proto_tree * tree) { int dissected = 0; if (fullmediatype) { gchar *mediatype = wmem_strdup(pinfo->pool, fullmediatype); gchar *parms_at = strchr(mediatype, ';'); const char *save_match_string = pinfo->match_string; media_content_info_t content_info = { MEDIA_CONTAINER_OTHER, NULL, NULL, NULL }; /* Based upon what is done in packet-media.c we set up type and params */ if (NULL != parms_at) { content_info.media_str = wmem_strdup( pinfo->pool, parms_at + 1 ); *parms_at = '\0'; } /* Set the version that goes to packet-media.c before converting case */ pinfo->match_string = wmem_strdup(pinfo->pool, mediatype); /* force to lower case */ ascii_strdown_inplace(mediatype); if (0 == strcmp("application/x-jxta-tls-block", mediatype)) { /* If we recognize it as a TLS packet then we shuffle it off to tls dissector. */ if (NULL != tls_handle) { dissected = call_dissector(tls_handle, tvb, pinfo, tree); } } else if (0 == strcmp("application/gzip", mediatype)) { tvbuff_t *uncomp_tvb = tvb_child_uncompress(tvb, tvb, 0, tvb_captured_length(tvb)); if( NULL != uncomp_tvb ) { add_new_data_source(pinfo, uncomp_tvb, "Uncompressed Element Content"); /* XXX bondolo 20060201 Force XML for uncompressed data. */ increment_dissection_depth(pinfo); dissected = dissect_media("text/xml;charset=\"UTF-8\"", uncomp_tvb, pinfo, tree); decrement_dissection_depth(pinfo); if( dissected > 0 ) { /* report back the uncompressed length. */ dissected = tvb_captured_length(tvb); } } } else { dissected = dissector_try_string(media_type_dissector_table, mediatype, tvb, pinfo, tree, &content_info) ? tvb_captured_length(tvb) : 0; if( dissected != (int) tvb_captured_length(tvb) ) { /* ws_message( "%s : %d expected, %d dissected", mediatype, tvb_captured_length(tvb), dissected ); */ } } if (0 == dissected) { dissected = call_dissector_with_data(media_handle, tvb, pinfo, tree, &content_info); } pinfo->match_string = save_match_string; } if(0 == dissected) { /* display it as raw data */ dissected = call_data_dissector(tvb, pinfo, tree); } if (dissected < (int) tvb_reported_length(tvb)) { proto_item *item = proto_tree_add_expert(tree, pinfo, &ei_media_too_short, tvb, 0, dissected); proto_item_set_generated(item); } return dissected; } /** * Register jxta protocol and jxta message protocol, header fields, subtree types, preferences. **/ void proto_register_jxta(void) { module_t *jxta_module; expert_module_t *expert_jxta; /** our header fields */ static hf_register_info hf[] = { {&hf_uri_addr, {"Address", "jxta.uri.addr", FT_STRING, BASE_NONE, NULL, 0x0, "URI Address (source or destination)", HFILL} }, {&hf_uri_src, {"Source", "jxta.uri.src", FT_STRING, BASE_NONE, NULL, 0x0, "URI Source", HFILL} }, {&hf_uri_dst, {"Destination", "jxta.uri.dst", FT_STRING, BASE_NONE, NULL, 0x0, "URI Destination", HFILL} }, {&hf_jxta_udp, {"JXTA UDP", "jxta.udp", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL} }, {&hf_jxta_udpsig, {"Signature", "jxta.udpsig", FT_STRING, BASE_NONE, NULL, 0x0, "JXTA UDP Signature", HFILL} }, {&hf_jxta_welcome, {"Welcome", "jxta.welcome", FT_NONE, BASE_NONE, NULL, 0x00, "JXTA Connection Welcome Message", HFILL} }, {&hf_jxta_welcome_initiator, {"Initiator", "jxta.welcome.initiator", FT_BOOLEAN, BASE_NONE, NULL, 0x00, "JXTA Connection Welcome Message Initiator", HFILL} }, {&hf_jxta_welcome_sig, {"Signature", "jxta.welcome.signature", FT_STRING, BASE_NONE, NULL, 0x0, "JXTA Connection Welcome Message Signature", HFILL} }, {&hf_jxta_welcome_destAddr, {"Destination Address", "jxta.welcome.destAddr", FT_STRING, BASE_NONE, NULL, 0x0, "JXTA Connection Welcome Message Destination Address", HFILL} }, {&hf_jxta_welcome_pubAddr, {"Public Address", "jxta.welcome.pubAddr", FT_STRING, BASE_NONE, NULL, 0x0, "JXTA Connection Welcome Message Public Address", HFILL} }, {&hf_jxta_welcome_peerid, {"PeerID", "jxta.welcome.peerid", FT_STRING, BASE_NONE, NULL, 0x0, "JXTA Connection Welcome Message PeerID", HFILL} }, {&hf_jxta_welcome_noProp, {"No Propagate Flag", "jxta.welcome.noPropFlag", FT_STRING, BASE_NONE, NULL, 0x0, "JXTA Connection Welcome Message No Propagate Flag", HFILL} }, {&hf_jxta_welcome_msgVers, {"Preferred Message Version", "jxta.welcome.msgVersion", FT_STRING, BASE_NONE, NULL, 0x0, "JXTA Connection Welcome Message Preferred Message Version", HFILL} }, {&hf_jxta_welcome_variable, {"Variable Parameter", "jxta.welcome.variable", FT_STRING, BASE_NONE, NULL, 0x0, "JXTA Connection Welcome Message Variable Parameter", HFILL} }, {&hf_jxta_welcome_version, {"Version", "jxta.welcome.version", FT_STRING, BASE_NONE, NULL, 0x0, "JXTA Connection Welcome Message Version", HFILL} }, {&hf_jxta_framing, {"Framing", "jxta.framing", FT_NONE, BASE_NONE, NULL, 0x0, "JXTA Message Framing", HFILL} }, {&hf_jxta_framing_header, {"Header", "jxta.framing.header", FT_NONE, BASE_NONE, NULL, 0x0, "JXTA Message Framing Header", HFILL} }, {&hf_jxta_framing_header_name, {"Name", "jxta.framing.header.name", FT_UINT_STRING, BASE_NONE, NULL, 0x0, "JXTA Message Framing Header Name", HFILL} }, {&hf_jxta_framing_header_value_length, {"Value Length", "jxta.framing.header.valuelen", FT_UINT16, BASE_DEC, NULL, 0x0, "JXTA Message Framing Header Value Length", HFILL} }, {&hf_jxta_framing_header_value, {"Value", "jxta.framing.header.value", FT_BYTES, BASE_NONE, NULL, 0x0, "JXTA Message Framing Header Value", HFILL} }, {&hf_jxta_message_address, {"Address", "jxta.message.address", FT_STRING, BASE_NONE, NULL, 0x0, "JXTA Message Address (source or destination)", HFILL} }, {&hf_jxta_message_src, {"Source", "jxta.message.source", FT_STRING, BASE_NONE, NULL, 0x0, "JXTA Message Source", HFILL} }, {&hf_jxta_message_dst, {"Destination", "jxta.message.destination", FT_STRING, BASE_NONE, NULL, 0x0, "JXTA Message Destination", HFILL} }, {&hf_jxta_message_sig, {"Signature", "jxta.message.signature", FT_STRING, BASE_NONE, NULL, 0x0, "JXTA Message Signature", HFILL} }, {&hf_jxta_message_version, {"Version", "jxta.message.version", FT_UINT8, BASE_DEC, NULL, 0x0, "JXTA Message Version", HFILL} }, {&hf_jxta_message_flags, {"Flags", "jxta.message.flags", FT_UINT8, BASE_HEX, NULL, 0x0, "JXTA Message Flags", HFILL} }, {&hf_jxta_message_flag_utf16be, {"UTF16BE", "jxta.message.flags.UTF-16BE", FT_BOOLEAN, 2, TFS(&tfs_set_notset), 0x1, "JXTA Message Element Flag -- UTF16-BE Strings", HFILL} }, {&hf_jxta_message_flag_ucs32be, {"UCS32BE", "jxta.message.flags.UCS32BE", FT_BOOLEAN, 2, TFS(&tfs_set_notset), 0x2, "JXTA Message Flag -- UCS32-BE Strings", HFILL} }, {&hf_jxta_message_names_count, {"Names Count", "jxta.message.names", FT_UINT16, BASE_DEC, NULL, 0x0, "JXTA Message Names Table", HFILL} }, {&hf_jxta_message_names_name, {"Names Table Name", "jxta.message.names.name", FT_UINT_STRING, BASE_NONE, NULL, 0x0, "JXTA Message Names Table Name", HFILL} }, {&hf_jxta_message_element_count, {"Element Count", "jxta.message.elements", FT_UINT16, BASE_DEC, NULL, 0x0, "JXTA Message Element Count", HFILL} }, {&hf_jxta_element, {"JXTA Message Element", "jxta.message.element", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL} }, {&hf_jxta_element_sig, {"Signature", "jxta.message.element.signature", FT_STRING, BASE_NONE, NULL, 0x0, "JXTA Message Element Signature", HFILL} }, {&hf_jxta_element1_namespaceid, {"Namespace ID", "jxta.message.element.namespaceid", FT_UINT8, BASE_DEC, NULL, 0x0, "JXTA Message Element Namespace ID", HFILL} }, {&hf_jxta_element2_namespaceid, {"Namespace ID", "jxta.message.element.namespaceid", FT_UINT16, BASE_DEC, NULL, 0x0, "JXTA Message Element Namespace ID", HFILL} }, {&hf_jxta_element_flags, {"Flags", "jxta.message.element.flags", FT_UINT8, BASE_HEX, NULL, 0x0, "JXTA Message Element Flags", HFILL} }, {&hf_jxta_element1_flag_hasType, {"hasType", "jxta.message.element.flags.hasType", FT_BOOLEAN, 3, TFS(&tfs_set_notset), 0x1, "JXTA Message Element Flag -- hasType", HFILL} }, {&hf_jxta_element1_flag_hasEncoding, {"hasEncoding", "jxta.message.element.flags.hasEncoding", FT_BOOLEAN, 3, TFS(&tfs_set_notset), 0x2, "JXTA Message Element Flag -- hasEncoding", HFILL} }, {&hf_jxta_element1_flag_hasSignature, {"hasSignature", "jxta.message.element.flags.hasSignature", FT_BOOLEAN, 3, TFS(&tfs_set_notset), 0x4, "JXTA Message Element Flag -- hasSignature", HFILL} }, {&hf_jxta_element2_flag_64bitlens, {"uint64Lens", "jxta.message.element.flags.uint64Lens", FT_BOOLEAN, 6, TFS(&tfs_set_notset), 0x01, "JXTA Message Element Flag -- uint64Lens", HFILL} }, {&hf_jxta_element2_flag_nameLiteral, {"nameLiteral", "jxta.message.element.flags.nameLiteral", FT_BOOLEAN, 6, TFS(&tfs_set_notset), 0x02, "JXTA Message Element Flag -- nameLiteral", HFILL} }, {&hf_jxta_element2_flag_hasType, {"hasEncoding", "jxta.message.element.flags.hasType", FT_BOOLEAN, 6, TFS(&tfs_set_notset), 0x04, "JXTA Message Element Flag -- hasType", HFILL} }, {&hf_jxta_element2_flag_hasSignature, {"hasSignature", "jxta.message.element.flags.hasSignature", FT_BOOLEAN, 6, TFS(&tfs_set_notset), 0x08, "JXTA Message Element Flag -- hasSignature", HFILL} }, {&hf_jxta_element2_flag_hasEncoding, {"hasSignature", "jxta.message.element.flags.hasEncoding", FT_BOOLEAN, 6, TFS(&tfs_set_notset), 0x10, "JXTA Message Element Flag -- hasEncoding", HFILL} }, {&hf_jxta_element2_flag_sigOfEncoded, {"sigOfEncoded", "jxta.message.element.flags.sigOfEncoded", FT_BOOLEAN, 6, TFS(&tfs_set_notset), 0x20, "JXTA Message Element Flag -- sigOfEncoded", HFILL} }, {&hf_jxta_element2_nameid, {"Name ID", "jxta.message.element.nameid", FT_UINT16, BASE_DEC, NULL, 0x0, "JXTA Message Element Name ID", HFILL} }, {&hf_jxta_element_name, {"Element Name", "jxta.message.element.name", FT_UINT_STRING, BASE_NONE, NULL, 0x0, "JXTA Message Element Name", HFILL} }, {&hf_jxta_element2_mimeid, {"MIME ID", "jxta.message.element.mimeid", FT_UINT16, BASE_DEC, NULL, 0x0, "JXTA Message Element MIME ID", HFILL} }, {&hf_jxta_element2_encodingid, {"Encoding ID", "jxta.message.element.encodingid", FT_UINT16, BASE_DEC, NULL, 0x0, "JXTA Message Element Encoding ID", HFILL} }, {&hf_jxta_element_type, {"Element Type", "jxta.message.element.type", FT_UINT_STRING, BASE_NONE, NULL, 0x0, "JXTA Message Element Name", HFILL} }, {&hf_jxta_element_encoding, {"Element Type", "jxta.message.element.encoding", FT_UINT_STRING, BASE_NONE, NULL, 0x0, "JXTA Message Element Encoding", HFILL} }, {&hf_jxta_element_content_len, {"Element Content Length", "jxta.message.element.content.length", FT_UINT32, BASE_DEC, NULL, 0x0, "JXTA Message Element Content Length", HFILL} }, {&hf_jxta_element_content_len64, {"Element Content Length", "jxta.message.element.content.length64", FT_UINT64, BASE_DEC, NULL, 0x0, "JXTA Message Element Content Length", HFILL} }, #if 0 {&hf_jxta_element_content, {"Element Content", "jxta.message.element.content", FT_BYTES, BASE_NONE, NULL, 0x0, "JXTA Message Element Content", HFILL} }, #endif }; static ei_register_info ei[] = { { &ei_media_too_short, { "jxta.media_too_short", PI_PROTOCOL, PI_WARN, "Media length less than expected", EXPFILL }}, }; /** * JXTA Protocol subtree array **/ static gint *ett[] = { &ett_jxta, &ett_jxta_welcome, &ett_jxta_udp, &ett_jxta_framing, &ett_jxta_framing_header, &ett_jxta_msg, &ett_jxta_msg_flags, &ett_jxta_elem, &ett_jxta_elem_1_flags, &ett_jxta_elem_2_flags }; proto_jxta = proto_register_protocol("JXTA P2P", "JXTA", "jxta"); jxta_tap = register_tap("jxta"); proto_message_jxta = proto_register_protocol("JXTA Message", "JXTA Message", "jxta.message"); jxta_udp_handle = register_dissector("jxta.udp", dissect_jxta_udp, proto_jxta); stream_jxta_handle = register_dissector("jxta.stream", dissect_jxta_stream, proto_jxta); /* Register header fields */ proto_register_field_array(proto_jxta, hf, array_length(hf)); /* Register JXTA Sub-tree */ proto_register_subtree_array(ett, array_length(ett)); expert_jxta = expert_register_protocol(proto_jxta); expert_register_field_array(expert_jxta, ei, array_length(ei)); uri_address_type = address_type_dissector_register("AT_URI", "URI/URL/URN", uri_to_str, uri_str_len, NULL, uri_col_filter_str, NULL, NULL, NULL); /* Register preferences */ /* register re-init routine */ jxta_module = prefs_register_protocol(proto_jxta, proto_reg_handoff_jxta); prefs_register_bool_preference(jxta_module, "msg.mediatype", "Register binary JXTA Message as a media type", "Enable to have correctly typed MIME media dissected as JXTA Messages.", &gMSG_MEDIA); prefs_register_bool_preference(jxta_module, "desegment", "Reassemble JXTA messages spanning multiple UDP/TCP/SCTP segments", "Whether the JXTA dissector should reassemble messages spanning multiple UDP/TCP/SCTP segments." " To use this option you must also enable \"Allow subdissectors to reassemble TCP streams\" in the TCP protocol settings " " and enable \"Reassemble fragmented IP datagrams\" in the IP protocol settings.", &gDESEGMENT); prefs_register_obsolete_preference(jxta_module, "udp.heuristic"); prefs_register_obsolete_preference(jxta_module, "tcp.heuristic"); prefs_register_obsolete_preference(jxta_module, "sctp.heuristic"); register_conversation_table(proto_jxta, TRUE, jxta_conversation_packet, jxta_endpoint_packet); } /** * Update registrations in response to preferences changes. **/ void proto_reg_handoff_jxta(void) { static gboolean init_done = FALSE; static dissector_handle_t message_jxta_handle; static gboolean msg_media_register_done = FALSE; if(!init_done) { message_jxta_handle = create_dissector_handle(dissect_jxta_message, proto_message_jxta); media_type_dissector_table = find_dissector_table("media_type"); tls_handle = find_dissector_add_dependency("tls", proto_jxta); media_handle = find_dissector_add_dependency("media", proto_jxta); heur_dissector_add("udp", dissect_jxta_UDP_heur, "JXTA over UDP", "jxta_udp", proto_jxta, HEURISTIC_ENABLE); heur_dissector_add("tcp", dissect_jxta_TCP_heur, "JXTA over TCP", "jxta_tcp", proto_jxta, HEURISTIC_ENABLE); heur_dissector_add("sctp", dissect_jxta_SCTP_heur, "JXTA over SCTP", "jxta_sctp", proto_jxta, HEURISTIC_ENABLE); init_done = TRUE; } if( gMSG_MEDIA ) { if( !msg_media_register_done ) { /* ws_message( "Registering JXTA Message media type" ); */ dissector_add_string("media_type", "application/x-jxta-msg", message_jxta_handle); msg_media_register_done = TRUE; } } else { if( msg_media_register_done ) { /* ws_message( "Deregistering JXTA Message media type" ); */ dissector_delete_string("media_type", "application/x-jxta-msg", message_jxta_handle); msg_media_register_done = FALSE; } } } /* * Editor modelines - https://www.wireshark.org/tools/modelines.html * * Local variables: * c-basic-offset: 4 * tab-width: 8 * indent-tabs-mode: nil * End: * * vi: set shiftwidth=4 tabstop=8 expandtab: * :indentSize=4:tabSize=8:noTabs=true: */