/* packet-jxta.c * * Routines for JXTA packet dissection * JXTA specification from https://jxta-spec.dev.java.net * * 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 * * $Id$ * * Wireshark - Network traffic analyzer * By Gerald Combs * Copyright 2000 Gerald Combs * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #ifdef HAVE_CONFIG_H # include "config.h" #endif #define G_LOG_DOMAIN "jxta" #include #include #include #include #include #include #include #include #include "packet-jxta.h" 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 data_handle = NULL; static dissector_handle_t stream_jxta_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; /** * JXTA Protocol subtree array **/ static gint *const 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 }; /** * global preferences **/ static gboolean gDESEGMENT = TRUE; static gboolean gUDP_HEUR = TRUE; static gboolean gTCP_HEUR = TRUE; static gboolean gSCTP_HEUR = TRUE; static gboolean gMSG_MEDIA = TRUE; /** * 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; /** * Prototypes **/ static gboolean dissect_jxta_UDP_heur(tvbuff_t * tvb, packet_info * pinfo, proto_tree * tree); static gboolean dissect_jxta_TCP_heur(tvbuff_t * tvb, packet_info * pinfo, proto_tree * tree); static gboolean dissect_jxta_SCTP_heur(tvbuff_t * tvb, packet_info * pinfo, proto_tree * tree); static int dissect_jxta_udp(tvbuff_t * tvb, packet_info * pinfo, proto_tree * tree); static int dissect_jxta_stream(tvbuff_t * tvb, packet_info * pinfo, proto_tree * tree); 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); 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); void proto_reg_handoff_jxta(void); /** * 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) { /* 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_memeql(tvb, 0, JXTA_UDP_SIG, sizeof(JXTA_UDP_SIG)) != 0) { return FALSE; } save_desegment_offset = pinfo->desegment_offset; save_desegment_len = pinfo->desegment_len; ret = dissect_jxta_udp(tvb, pinfo, tree); /* g_message( "%d Heuristic UDP Dissection : %d", pinfo->fd->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) { /* 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); /* g_message( "%d Heuristic TCP Dissection : %d", pinfo->fd->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) { /* 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); /* g_message( "%d Heuristic SCTP Dissection : %d", pinfo->fd->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) { guint offset = 0; guint available; gint needed = 0; conversation_t *conversation = find_or_create_conversation(pinfo); DISSECTOR_ASSERT(find_dissector("jxta.udp")); conversation_set_dissector(conversation, find_dissector("jxta.udp")); 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, JXTA_UDP_SIG, sizeof(JXTA_UDP_SIG)) != 0) { /* not ours */ return 0; } offset += 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) { /* g_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, 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, sizeof(JXTA_UDP_SIG), ENC_ASCII|ENC_NA); tree_offset += 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(tvb, tree_offset, (gint) content_length, (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); DISSECTOR_ASSERT(offset == tree_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) { 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; /* g_message("Dissecting%s : %d", (NULL != tree) ? " for display" : "", pinfo->fd->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, 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->fd->num; SE_COPY_ADDRESS(&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->fd->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->fd->num; SE_COPY_ADDRESS(&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->fd->num; SE_COPY_ADDRESS(&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 = -1L; 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; } /* g_message("%d Tpt %s:%d -> %s:%d tvb len=%d\n\t%s %d", pinfo->fd->num, ep_address_to_str(&pinfo->src), pinfo->srcport, ep_address_to_str(&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(tvb, offset + headers_len, (gint) content_length, (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) { /* g_message("%d Tpt %s:%d -> %s:%d", pinfo->fd->num, ep_address_to_str(&tpt_conv_data->initiator_tpt_address), tpt_conv_data->initiator_tpt_port, ep_address_to_str(&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) { /* g_message("%d From initiator : %s -> %s ", pinfo->fd->num, ep_address_to_str(&tpt_conv_data->initiator_address), ep_address_to_str(&tpt_conv_data->receiver_address)); */ pinfo->src = tpt_conv_data->initiator_address; pinfo->srcport = 0; 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) { /* g_message("%d From receiver : %s -> %s ", pinfo->fd->num, ep_address_to_str(&tpt_conv_data->receiver_address), ep_address_to_str(&tpt_conv_data->initiator_address)); */ pinfo->src = tpt_conv_data->receiver_address; pinfo->srcport = 0; pinfo->dst = tpt_conv_data->initiator_address; pinfo->destport = 0; pinfo->ptype = PT_NONE; } else { /* g_message("%d Nothing matches %s:%d -> %s:%d", pinfo->fd->num, ep_address_to_str(&pinfo->src), pinfo->srcport, ep_address_to_str(&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) { /* g_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_conversation(pinfo->fd->num, &pinfo->src, &pinfo->dst, pinfo->ptype, pinfo->srcport, pinfo->destport, 0); jxta_stream_conversation_data *tpt_conv_data; if (tpt_conversation == NULL) { /* * No conversation exists yet - create one. */ tpt_conversation = conversation_new(pinfo->fd->num, &pinfo->src, &pinfo->dst, pinfo->ptype, pinfo->srcport, pinfo->destport, 0); } 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 = se_alloc(sizeof(jxta_stream_conversation_data)); tpt_conv_data->tpt_ptype = pinfo->ptype; SE_COPY_ADDRESS(&tpt_conv_data->initiator_tpt_address, &pinfo->src); tpt_conv_data->initiator_tpt_port = pinfo->srcport; tpt_conv_data->initiator_welcome_frame = 0; tpt_conv_data->initiator_address.type = AT_NONE; tpt_conv_data->initiator_address.len = 0; tpt_conv_data->initiator_address.data = NULL; SE_COPY_ADDRESS(&tpt_conv_data->receiver_tpt_address, &pinfo->dst); tpt_conv_data->receiver_tpt_port = pinfo->destport; tpt_conv_data->receiver_welcome_frame = 0; tpt_conv_data->receiver_address.type = AT_NONE; tpt_conv_data->receiver_address.len = 0; tpt_conv_data->receiver_address.data = NULL; 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->fd->num, &tpt_conv_data->initiator_address, &tpt_conv_data->receiver_address, PT_NONE, 0, 0, NO_PORT_B); if (create && (NULL == peer_conversation)) { peer_conversation = conversation_new(pinfo->fd->num, &tpt_conv_data->initiator_address, &tpt_conv_data->receiver_address, PT_NONE, 0, 0, NO_PORT_B); 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, 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 -1; } } /* Dissect the Welcome Message */ col_set_str(pinfo->cinfo, COL_PROTOCOL, "JXTA"); col_set_str(pinfo->cinfo, COL_INFO, "Welcome"); { gchar *welcomeline = tvb_get_ephemeral_string(tvb, offset, first_linelen); gchar **current_token; guint token_offset = offset; proto_item *jxta_welcome_tree_item = NULL; proto_tree *jxta_welcome_tree = NULL; tokens = g_strsplit(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) { if (jxta_welcome_tree) { proto_tree_add_item(jxta_welcome_tree, hf_jxta_welcome_sig, tvb, token_offset, (gint) strlen(*current_token), ENC_ASCII|ENC_NA); } 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|ENC_NA); } 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|ENC_NA); } 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|ENC_NA); } if (check_col(pinfo->cinfo, COL_INFO)) { col_append_str(pinfo->cinfo, COL_INFO, (initiator ? " -> " : " <- ") ); col_append_str(pinfo->cinfo, COL_INFO, *current_token); } if (NULL != found_addr) { found_addr->type = AT_URI; found_addr->len = (int) strlen(*current_token); found_addr->data = se_strdup(*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|ENC_NA); } 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|ENC_NA); } } 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|ENC_NA); } 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|ENC_NA); } 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|ENC_NA); } } 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: g_strfreev(tokens); col_set_writable(pinfo->cinfo, 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 < sizeof(guint8)) { needed = (gint) (sizeof(guint8) - available); break; } else { headername_len = tvb_get_guint8(tvb, offset); offset += sizeof(guint8); 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 < sizeof(guint16)) { needed = (gint) (sizeof(guint16) - available); break; } else { headervalue_len = tvb_get_ntohs(tvb, offset); offset += sizeof(guint16); 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_ephemeral_string(tvb, headervalue_offset, headervalue_len); } } 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) { /* g_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_add_none_format(tree, hf_jxta_framing, tvb, tree_offset, -1, "JXTA Message Framing Headers"); proto_tree *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, sizeof(gint8), ENC_ASCII|ENC_NA); /* * 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(tvb, tree_offset + sizeof(guint8), headernamelen)); } tree_offset += sizeof(guint8) + 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, sizeof(guint16), 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 + sizeof(guint16), headervaluelen, ENC_NA); } tree_offset += sizeof(guint16) + 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) { gint complete_messages = 0; guint offset = 0; guint tree_offset = 0; guint available; gint needed = 0; emem_strbuf_t* src_addr; emem_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, JXTA_MSG_SIG, sizeof(JXTA_MSG_SIG)) != 0) { /* It is not one of ours */ return 0; } offset += sizeof(JXTA_MSG_SIG); available = tvb_reported_length_remaining(tvb, offset); if (available < sizeof(guint8)) { needed = (gint) (sizeof(guint8) - available); break; } else { message_version = tvb_get_guint8(tvb, offset); offset += sizeof(guint8); 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 < sizeof(guint8)) { needed = (gint) (sizeof(guint8) - available); break; } else { offset += sizeof(guint8); } } /* Read names table */ available = tvb_reported_length_remaining(tvb, offset); if (available < sizeof(guint16)) { needed = (gint) (sizeof(guint16) - available); break; } else { guint16 msg_names_count = tvb_get_ntohs(tvb, offset); guint each_name; offset += sizeof(guint16); 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 + sizeof(name_len)); if (available < name_len) { needed = (gint) (name_len - available); break; } offset += sizeof(name_len) + name_len; } } /* parse element count */ available = tvb_reported_length_remaining(tvb, offset); if (available < sizeof(guint16)) { needed = (gint) (sizeof(guint16) - available); break; } else { guint16 elem_count = tvb_get_ntohs(tvb, offset); guint each_elem; offset += sizeof(guint16); /* 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 if(JXTA_MSG_VERSION_2 == message_version) { processed = dissect_jxta_message_element_2(jxta_message_element_tvb, pinfo, NULL, 0, NULL); } else { /* Sort of a lie, we say that we don't recognize it at all. */ return 0; } if (processed < 0) { needed = -processed; break; } if (0 == processed) { /* XXX bondolo Not really clear what we should do! */ g_warning( "Failure processing message element #%d of %d of frame %d", each_elem, elem_count, pinfo->fd->num ); return 0; } offset += processed; } } if ((AT_URI == pinfo->src.type) && (AT_URI == pinfo->dst.type)) { jxta_tap_header *tap_header = se_alloc(sizeof(jxta_tap_header)); tap_header->src_address = pinfo->src; tap_header->dest_address = pinfo->dst; tap_header->size = offset - message_start_offset ; tap_queue_packet(jxta_tap, pinfo, tap_header); } complete_messages++; /* g_message( "%d Scanned message #%d: ", pinfo->fd->num, complete_messages ); */ } if ((needed > 0) && gDESEGMENT && pinfo->can_desegment) { /* g_message( "Message requesting %d more bytes", needed ); */ pinfo->desegment_offset = 0; pinfo->desegment_len = needed; return -needed; } src_addr = ep_strbuf_new_label(ep_address_to_str(&pinfo->src)); dst_addr = ep_strbuf_new_label(ep_address_to_str(&pinfo->dst)); /* append the port if appropriate */ if (PT_NONE != pinfo->ptype) { ep_strbuf_append_printf(src_addr, ":%d", pinfo->srcport); ep_strbuf_append_printf(dst_addr, ":%d", pinfo->destport); } col_set_str(pinfo->cinfo, COL_PROTOCOL, "JXTA"); if (check_col(pinfo->cinfo, COL_INFO)) { if( complete_messages > 1 ) { col_add_fstr(pinfo->cinfo, COL_INFO, "%d Messages, %s -> %s", complete_messages, src_addr->str, dst_addr->str); } else { col_add_fstr(pinfo->cinfo, COL_INFO, "Message, %s -> %s", src_addr->str, dst_addr->str); } col_set_writable(pinfo->cinfo, 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", src_addr->str, dst_addr->str); 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, sizeof(JXTA_MSG_SIG), ENC_ASCII|ENC_NA); tree_offset += sizeof(JXTA_MSG_SIG); tree_item = proto_tree_add_string(jxta_msg_tree, hf_jxta_message_src, tvb, 0, 0, src_addr->str); PROTO_ITEM_SET_GENERATED(tree_item); tree_item = proto_tree_add_string(jxta_msg_tree, hf_jxta_message_address, tvb, 0, 0, src_addr->str); PROTO_ITEM_SET_HIDDEN(tree_item); PROTO_ITEM_SET_GENERATED(tree_item); if(AT_URI == pinfo->src.type) { tree_item = proto_tree_add_string(jxta_msg_tree, hf_uri_src, tvb, 0, 0, src_addr->str); 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, src_addr->str); 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, dst_addr->str); PROTO_ITEM_SET_GENERATED(tree_item); tree_item = proto_tree_add_string(jxta_msg_tree, hf_jxta_message_address, tvb, 0, 0, dst_addr->str); PROTO_ITEM_SET_HIDDEN(tree_item); PROTO_ITEM_SET_GENERATED(tree_item); if(AT_URI == pinfo->dst.type) { tree_item = proto_tree_add_string(jxta_msg_tree, hf_uri_dst, tvb, 0, 0, src_addr->str); 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, dst_addr->str); 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, sizeof(guint8), message_version); tree_offset += sizeof(guint8); if( message_version > 0 ) { guint8 flags = tvb_get_guint8(tvb, tree_offset); proto_item *flags_ti = proto_tree_add_uint(jxta_msg_tree, hf_jxta_message_flags, tvb, tree_offset, sizeof(guint8), flags); proto_tree *jxta_msg_flags_tree = proto_item_add_subtree(flags_ti, ett_jxta_msg_flags); proto_tree_add_boolean(jxta_msg_flags_tree, hf_jxta_message_flag_utf16be, tvb, tree_offset, 1, flags); proto_tree_add_boolean(jxta_msg_flags_tree, hf_jxta_message_flag_ucs32be, tvb, tree_offset, 1, flags); tree_offset += sizeof(guint8); } msg_names_count = tvb_get_ntohs(tvb, tree_offset); proto_tree_add_uint(jxta_msg_tree, hf_jxta_message_names_count, tvb, tree_offset, sizeof(guint16), msg_names_count); tree_offset += sizeof(guint16); names_table = ep_alloc((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_ephemeral_string(tvb, tree_offset + sizeof(name_len), name_len); proto_tree_add_item(jxta_msg_tree, hf_jxta_message_names_name, tvb, tree_offset, sizeof(name_len), ENC_ASCII|ENC_NA); tree_offset += sizeof(name_len) + 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, sizeof(guint16), ENC_BIG_ENDIAN); tree_offset += sizeof(guint16); /* 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 ) { /* g_message( "%d tvb offset : %d tree offset : %d", pinfo->fd->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. **/ 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, JXTA_MSGELEM_SIG, sizeof(JXTA_MSGELEM_SIG)) != 0) { /* It is not one of ours */ return 0; } offset += sizeof(JXTA_MSGELEM_SIG); /* namespace id field */ available = tvb_reported_length_remaining(tvb, offset); if (available < sizeof(guint8)) { needed = (gint) (sizeof(guint8) - available); break; } offset += sizeof(guint8); /* flags field */ available = tvb_reported_length_remaining(tvb, offset); if (available < sizeof(guint8)) { needed = (gint) (sizeof(guint8) - available); break; } else { flags = tvb_get_guint8(tvb, offset); offset += sizeof(guint8); } /* name field */ available = tvb_reported_length_remaining(tvb, offset); if (available < sizeof(guint16)) { needed = (gint) (sizeof(guint16) - available); break; } else { guint16 name_len = tvb_get_ntohs(tvb, offset); offset += sizeof(guint16); 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 < sizeof(guint16)) { needed = (gint) (sizeof(guint16) - available); break; } type_len = tvb_get_ntohs(tvb, offset); offset += sizeof(guint16); 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 < sizeof(guint16)) { needed = (gint) (sizeof(guint16) - available); break; } encoding_len = tvb_get_ntohs(tvb, offset); offset += sizeof(guint16); 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 < sizeof(guint16)) { needed = (gint) (sizeof(guint16) - available); break; } else { guint32 content_len = tvb_get_ntohl(tvb, offset); offset += sizeof(guint32); 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); processed = dissect_jxta_message_element_1(jxta_signature_element_tvb, pinfo, NULL, 0, NULL); if (processed == 0) { return offset; } if (processed < 0) { needed = -processed; break; } offset += processed; } break; } if ((needed > 0) && gDESEGMENT && pinfo->can_desegment) { /* g_message( "Element1 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); guint8 namespaceID; proto_item *namespace_ti; guint16 name_len; proto_item *flags_ti; proto_tree *jxta_elem_flags_tree = NULL; guint32 content_len; gchar *mediatype = NULL; tvbuff_t *element_content_tvb; proto_tree_add_item(jxta_elem_tree, hf_jxta_element_sig, tvb, tree_offset, sizeof(JXTA_MSGELEM_SIG), ENC_ASCII|ENC_NA); tree_offset += 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, sizeof(guint8), 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 += sizeof(guint8); flags = tvb_get_guint8(tvb, tree_offset); flags_ti = proto_tree_add_uint(jxta_elem_tree, hf_jxta_element_flags, tvb, tree_offset, sizeof(guint8), flags); jxta_elem_flags_tree = proto_item_add_subtree(flags_ti, ett_jxta_elem_1_flags); proto_tree_add_boolean(jxta_elem_flags_tree, hf_jxta_element1_flag_hasType, tvb, tree_offset, 1, flags); proto_tree_add_boolean(jxta_elem_flags_tree, hf_jxta_element1_flag_hasEncoding, tvb, tree_offset, 1, flags); proto_tree_add_boolean(jxta_elem_flags_tree, hf_jxta_element1_flag_hasSignature, tvb, tree_offset, 1, flags); tree_offset += sizeof(guint8); name_len = tvb_get_ntohs(tvb, tree_offset); proto_item_append_text(jxta_elem_tree_item, " \"%s\"", tvb_format_text(tvb, tree_offset + sizeof(guint16), name_len)); proto_tree_add_item(jxta_elem_tree, hf_jxta_element_name, tvb, tree_offset, sizeof(guint16), ENC_ASCII|ENC_NA); tree_offset += sizeof(guint16) + 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, sizeof(guint16), ENC_ASCII|ENC_NA); tree_offset += sizeof(guint16); mediatype = tvb_get_ephemeral_string(tvb, tree_offset, type_len); 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, sizeof(guint16), ENC_ASCII|ENC_NA); tree_offset += sizeof(guint16) + 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, sizeof(guint32), ENC_BIG_ENDIAN); tree_offset += sizeof(guint32); element_content_tvb = tvb_new_subset(tvb, tree_offset, content_len, 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); tree_offset += dissect_jxta_message_element_1(jxta_message_element_tvb, pinfo, jxta_elem_tree, ns_count, names_table); } proto_item_set_end(jxta_elem_tree_item, tvb, tree_offset); 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 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. **/ 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, JXTA_MSGELEM_SIG, sizeof(JXTA_MSGELEM_SIG)) != 0) { /* It is not one of ours */ return 0; } offset += sizeof(JXTA_MSGELEM_SIG); /* flags field */ available = tvb_reported_length_remaining(tvb, offset); if (available < sizeof(guint8)) { needed = (gint) (sizeof(guint8) - available); break; } else { flags = tvb_get_guint8(tvb, offset); offset += sizeof(guint8); } /* namespace id field */ available = tvb_reported_length_remaining(tvb, offset); if (available < sizeof(guint16)) { needed = (gint) (sizeof(guint16) - available); break; } offset += sizeof(guint16); /* name field */ if ((flags & JXTAMSG2_ELMFLAG_NAME_LITERAL) == 0) { available = tvb_reported_length_remaining(tvb, offset); if (available < sizeof(guint16)) { needed = (gint) (sizeof(guint16) - available); break; } offset += sizeof(guint16); } else { /* literal name field */ available = tvb_reported_length_remaining(tvb, offset); if (available < sizeof(guint16)) { needed = (gint) (sizeof(guint16) - available); break; } else { guint16 name_len = tvb_get_ntohs(tvb, offset); offset += sizeof(guint16); 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 < sizeof(guint16)) { needed = (gint) (sizeof(guint16) - available); break; } offset += sizeof(guint16); } /* encoding field */ if ((flags & JXTAMSG2_ELMFLAG_ENCODINGS) != 0) { available = tvb_reported_length_remaining(tvb, offset); if (available < sizeof(guint16)) { needed = (gint) (sizeof(guint16) - available); break; } offset += sizeof(guint16); } /* 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 += 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 < sizeof(guint32)) { needed = (gint) (sizeof(guint32) - available); break; } else { guint64 content_len = tvb_get_ntohl(tvb, offset); offset += sizeof(guint32); 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); processed = dissect_jxta_message_element_2(jxta_signature_element_tvb, pinfo, NULL, 0, NULL); if (processed == 0) { return offset; } if (processed < 0) { needed = -processed; break; } offset += processed; } break; } if ((needed > 0) && gDESEGMENT && pinfo->can_desegment) { /* g_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); proto_item *flags_ti; proto_tree *jxta_elem_flags_tree = NULL; guint16 namespaceID; proto_item *namespace_ti; guint16 nameID; proto_item *name_ti; guint64 content_len; const gchar *mediatype = NULL; tvbuff_t *element_content_tvb; proto_tree_add_item(jxta_elem_tree, hf_jxta_element_sig, tvb, tree_offset, sizeof(JXTA_MSGELEM_SIG), ENC_ASCII|ENC_NA); tree_offset += sizeof(JXTA_MSGELEM_SIG); flags = tvb_get_guint8(tvb, tree_offset); flags_ti = proto_tree_add_uint(jxta_elem_tree, hf_jxta_element_flags, tvb, tree_offset, sizeof(guint8), flags); jxta_elem_flags_tree = proto_item_add_subtree(flags_ti, ett_jxta_elem_2_flags); proto_tree_add_boolean(jxta_elem_flags_tree, hf_jxta_element2_flag_64bitlens, tvb, tree_offset, 1, flags); proto_tree_add_boolean(jxta_elem_flags_tree, hf_jxta_element2_flag_nameLiteral, tvb, tree_offset, 1, flags); proto_tree_add_boolean(jxta_elem_flags_tree, hf_jxta_element2_flag_hasType, tvb, tree_offset, 1, flags); proto_tree_add_boolean(jxta_elem_flags_tree, hf_jxta_element2_flag_hasSignature, tvb, tree_offset, 1, flags); proto_tree_add_boolean(jxta_elem_flags_tree, hf_jxta_element2_flag_hasEncoding, tvb, tree_offset, 1, flags); proto_tree_add_boolean(jxta_elem_flags_tree, hf_jxta_element2_flag_sigOfEncoded, tvb, tree_offset, 1, flags); tree_offset += sizeof(guint8); /* Namespace */ namespaceID = tvb_get_ntohs(tvb, tree_offset); namespace_ti = proto_tree_add_uint(jxta_elem_tree, hf_jxta_element2_namespaceid, tvb, tree_offset, sizeof(guint16), 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 += sizeof(guint16); /* 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, sizeof(guint16), nameID); if (namespaceID < names_count) { proto_item_append_text(name_ti, " (%s)", names_table[nameID]); } else { proto_item_append_text(name_ti, " * BAD *"); } tree_offset += sizeof(guint16); } else { /* literal name */ guint16 name_len = tvb_get_ntohs(tvb, tree_offset); proto_item_append_text(jxta_elem_tree_item, " \"%s\"", tvb_format_text(tvb, tree_offset + sizeof(guint16), name_len)); proto_tree_add_item(jxta_elem_tree, hf_jxta_element_name, tvb, tree_offset, sizeof(guint16), ENC_ASCII|ENC_NA); tree_offset += sizeof(guint16) + 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, sizeof(guint16), mimeID); if (mimeID < names_count) { proto_item_append_text(mime_ti, " (%s)", names_table[mimeID]); mediatype = ep_strdup( names_table[mimeID] ); } else { proto_item_append_text(mime_ti, " * BAD *"); } tree_offset += sizeof(guint16); } else { mediatype = "application/octect-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, sizeof(guint16), 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 += sizeof(guint16); } 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, sizeof(guint64), ENC_BIG_ENDIAN); tree_offset += sizeof(guint64); } else { content_len = tvb_get_ntohl(tvb, tree_offset); proto_tree_add_item(jxta_elem_tree, hf_jxta_element_content_len, tvb, tree_offset, sizeof(guint32), ENC_BIG_ENDIAN); tree_offset += sizeof(guint32); } /* content */ element_content_tvb = tvb_new_subset(tvb, tree_offset, (gint)content_len, (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); 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. **/ static int dissect_media( const gchar* fullmediatype, tvbuff_t * tvb, packet_info * pinfo, proto_tree * tree) { int dissected = 0; if (fullmediatype) { gchar *mediatype = ep_strdup(fullmediatype); gchar *parms_at = strchr(mediatype, ';'); const char *save_match_string = pinfo->match_string; void * save_private_data = pinfo->private_data; /* Based upon what is done in packet-media.c we set up type and params */ if (NULL != parms_at) { pinfo->private_data = ep_strdup( parms_at + 1 ); *parms_at = '\0'; } else { pinfo->private_data = NULL; } /* Set the version that goes to packet-media.c before converting case */ pinfo->match_string = ep_strdup(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 ssl dissector. */ dissector_handle_t ssl_handle = find_dissector("ssl"); if (NULL != ssl_handle) { dissected = call_dissector(ssl_handle, tvb, pinfo, tree); } } else if (0 == strcmp("application/gzip", mediatype)) { tvbuff_t *uncomp_tvb = tvb_child_uncompress(tvb, tvb, 0, tvb_length(tvb)); if( NULL != uncomp_tvb ) { add_new_data_source(pinfo, uncomp_tvb, "Uncompressed Element Content"); /* XXX bondolo 20060201 Force XML for uncompressed data. */ dissected = dissect_media("text/xml;charset=\"UTF-8\"", uncomp_tvb, pinfo, tree); if( dissected > 0 ) { /* report back the uncompressed length. */ dissected = tvb_length(tvb); } } } else { dissected = dissector_try_string(media_type_dissector_table, mediatype, tvb, pinfo, tree) ? tvb_length(tvb) : 0; if( dissected != (int) tvb_length(tvb) ) { /* g_message( "%s : %d expected, %d dissected", mediatype, tvb_length(tvb), dissected ); */ } } if (0 == dissected) { dissected = call_dissector(media_handle, tvb, pinfo, tree); } pinfo->match_string = save_match_string; pinfo->private_data = save_private_data; } if(0 == dissected) { /* display it as raw data */ dissected = call_dissector_only(data_handle, tvb, pinfo, tree); } return dissected; } /** * Register jxta protocol and jxta message protocol, header fields, subtree types, preferences. **/ void proto_register_jxta(void) { module_t *jxta_module; /** 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), 0x01, "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), 0x02, "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), 0x01, "JXTA Message Element Flag -- hasType", HFILL} }, {&hf_jxta_element1_flag_hasEncoding, {"hasEncoding", "jxta.message.element.flags.hasEncoding", FT_BOOLEAN, 3, TFS(&tfs_set_notset), 0x02, "JXTA Message Element Flag -- hasEncoding", HFILL} }, {&hf_jxta_element1_flag_hasSignature, {"hasSignature", "jxta.message.element.flags.hasSignature", FT_BOOLEAN, 3, TFS(&tfs_set_notset), 0x04, "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.length", FT_UINT64, BASE_DEC, NULL, 0x0, "JXTA Message Element Content Length", HFILL} }, {&hf_jxta_element_content, {"Element Content", "jxta.message.element.content", FT_BYTES, BASE_NONE, NULL, 0x0, "JXTA Message Element Content", HFILL} }, }; 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"); new_register_dissector("jxta.udp", dissect_jxta_udp, proto_jxta); new_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)); /* 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_bool_preference(jxta_module, "udp.heuristic", "Try to discover JXTA in UDP datagrams", "Enable to inspect UDP datagrams for JXTA messages.", &gUDP_HEUR); prefs_register_bool_preference(jxta_module, "tcp.heuristic", "Try to discover JXTA in TCP connections", "Enable to inspect TCP connections for JXTA conversations.", &gTCP_HEUR); prefs_register_bool_preference(jxta_module, "sctp.heuristic", "Try to discover JXTA in SCTP connections", "Enable to inspect SCTP connections for JXTA conversations.", &gSCTP_HEUR); } /** * 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; static gboolean udp_register_done = FALSE; static gboolean tcp_register_done = FALSE; static gboolean sctp_register_done = FALSE; if(!init_done) { message_jxta_handle = new_create_dissector_handle(dissect_jxta_message, proto_message_jxta); stream_jxta_handle = find_dissector("jxta.stream"); media_type_dissector_table = find_dissector_table("media_type"); data_handle = find_dissector("data"); media_handle = find_dissector("media"); init_done = TRUE; } if( gMSG_MEDIA ) { if( !msg_media_register_done ) { /* g_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 ) { /* g_message( "Deregistering JXTA Message media type" ); */ dissector_delete_string("media_type", "application/x-jxta-msg", message_jxta_handle); msg_media_register_done = FALSE; } } if( gUDP_HEUR ) { if( !udp_register_done ) { /* g_message( "Registering UDP Heuristic dissector" ); */ heur_dissector_add("udp", dissect_jxta_UDP_heur, proto_jxta); udp_register_done = TRUE; } } else { if( udp_register_done ) { /* g_message( "Deregistering UDP Heuristic dissector" ); */ heur_dissector_delete("udp", dissect_jxta_UDP_heur, proto_jxta); udp_register_done = FALSE; } } if( gTCP_HEUR ) { if( !tcp_register_done ) { /* g_message( "Registering TCP Heuristic dissector" ); */ heur_dissector_add("tcp", dissect_jxta_TCP_heur, proto_jxta); tcp_register_done = TRUE; } } else { if( tcp_register_done ) { /* g_message( "Deregistering TCP Heuristic dissector" ); */ heur_dissector_delete("tcp", dissect_jxta_TCP_heur, proto_jxta); tcp_register_done = FALSE; } } if( gSCTP_HEUR ) { if( !sctp_register_done ) { /* g_message( "Registering SCTP Heuristic dissector" ); */ heur_dissector_add("sctp", dissect_jxta_SCTP_heur, proto_jxta); sctp_register_done = TRUE; } } else { if( sctp_register_done ) { /* g_message( "Deregistering SCTP Heuristic dissector" ); */ heur_dissector_delete("sctp", dissect_jxta_SCTP_heur, proto_jxta); sctp_register_done = FALSE; } } }