2 * Routines for JXTA packet dissection
3 * Copyright 2004, Mike Duigou <bondolo@jxta.org>
4 * Heavily based on packet-jabber.c, which in turn is heavily based on
5 * on packet-acap.c, which in turn is heavily based on
6 * packet-imap.c, Copyright 1999, Richard Sharpe <rsharpe@ns.aus.com>
10 * Ethereal - Network traffic analyzer
11 * By Gerald Combs <gerald@ethereal.com>
12 * Copyright 1998 Gerald Combs
14 * Copied from packet-pop.c, packet-jabber.c, packet-udp.c
16 * JXTA specification from http://spec.jxta.org
18 * This program is free software; you can redistribute it and/or
19 * modify it under the terms of the GNU General Public License
20 * as published by the Free Software Foundation; either version 2
21 * of the License, or (at your option) any later version.
23 * This program is distributed in the hope that it will be useful,
24 * but WITHOUT ANY WARRANTY; without even the implied warranty of
25 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
26 * GNU General Public License for more details.
28 * You should have received a copy of the GNU General Public License
29 * along with this program; if not, write to the Free Software
30 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
41 #include <epan/packet.h>
42 #include <epan/strutil.h>
43 #include <epan/prefs.h>
44 #include "packet-tcp.h"
46 static int proto_jxta = -1;
48 static int hf_jxta_udp = -1;
49 static int hf_jxta_udpsig = -1;
50 static int hf_jxta_welcome = -1;
51 static int hf_jxta_framing = -1;
52 static int hf_jxta_framing_header_name_length = -1;
53 static int hf_jxta_framing_header_name = -1;
54 static int hf_jxta_framing_header_value_length = -1;
55 static int hf_jxta_framing_header_value = -1;
56 static int hf_jxta_message = -1;
57 static int hf_jxta_message_sig = -1;
58 static int hf_jxta_message_version = -1;
59 static int hf_jxta_message_namespaces_count = -1;
60 static int hf_jxta_message_namespace_len = -1;
61 static int hf_jxta_message_namespace_name = -1;
62 static int hf_jxta_message_element_count = -1;
63 static int hf_jxta_element = -1;
64 static int hf_jxta_element_sig = -1;
65 static int hf_jxta_element_namespaceid = -1;
66 static int hf_jxta_element_flags = -1;
67 static int hf_jxta_element_name_len = -1;
68 static int hf_jxta_element_name = -1;
69 static int hf_jxta_element_type_len = -1;
70 static int hf_jxta_element_type = -1;
71 static int hf_jxta_element_encoding_len = -1;
72 static int hf_jxta_element_encoding = -1;
73 static int hf_jxta_element_data_length = -1;
74 static int hf_jxta_element_content_len = -1;
75 static int hf_jxta_element_content = -1;
77 static gint ett_jxta_welcome = -1;
78 static gint ett_jxta_udp = -1;
79 static gint ett_jxta_framing = -1;
80 static gint ett_jxta_msg = -1;
81 static gint ett_jxta_elem = -1;
83 static dissector_handle_t udpm_jxta_handle;
84 static dissector_handle_t tcp_jxta_handle;
85 static dissector_handle_t http_jxta_handle;
87 /** our header fields */
88 static hf_register_info hf[] = {
90 { "JXTA UDP Message", "jxta.udp", FT_NONE, BASE_NONE, NULL, 0x0,
91 "JXTA UDP Message", HFILL }
94 { "Signature", "jxta.udpsig", FT_STRING, BASE_NONE, NULL, 0x0,
95 "JXTA UDP Signature", HFILL }
98 { "Welcome Message", "jxta.welcome", FT_NONE, BASE_NONE, NULL, 0x0,
99 "JXTA Connection Welcome Message", HFILL }
102 { "JXTA Message Framing", "jxta.framing", FT_NONE, BASE_NONE, NULL, 0x0,
103 "JXTA Message Framing Header", HFILL }
105 { &hf_jxta_framing_header_name_length,
106 { "Name Length", "jxta.framing.header.namelen", FT_UINT8, BASE_DEC, NULL, 0x0,
107 "JXTA Message Framing Header Name Length", HFILL }
109 { &hf_jxta_framing_header_name,
110 { "Name", "jxta.framing.header.name", FT_STRING, BASE_NONE, NULL, 0x0,
111 "JXTA Message Framing Header Name", HFILL }
113 { &hf_jxta_framing_header_value_length,
114 { "Value Length", "jxta.framing.header.valuelen", FT_UINT16, BASE_DEC, NULL, 0x0,
115 "JXTA Message Framing Header Value Length", HFILL }
117 { &hf_jxta_framing_header_value,
118 { "Value", "jxta.framing.header.value", FT_BYTES, BASE_HEX, NULL, 0x0,
119 "JXTA Message Framing Header Value", HFILL }
122 { "JXTA Message", "jxta.message", FT_NONE, BASE_NONE, NULL, 0x0,
123 "JXTA Message", HFILL }
125 { &hf_jxta_message_sig,
126 { "Signature", "jxta.message.signature", FT_STRING, BASE_NONE, NULL, 0x0,
127 "JXTA Message Signature", HFILL }
129 { &hf_jxta_message_version,
130 { "Version", "jxta.message.version", FT_UINT8, BASE_DEC, NULL, 0x0,
131 "JXTA Message Version", HFILL }
133 { &hf_jxta_message_namespaces_count,
134 { "Namespace Count", "jxta.message.namespaces", FT_UINT16, BASE_DEC, NULL, 0x0,
135 "JXTA Message Namespaces", HFILL }
137 { &hf_jxta_message_namespace_len,
138 { "Namespace Name Length", "jxta.message.namespace.len", FT_UINT16, BASE_DEC, NULL, 0x0,
139 "JXTA Message Namespace Name Length", HFILL }
141 { &hf_jxta_message_namespace_name,
142 { "Namespace Name", "jxta.message.namespace.name", FT_STRING, BASE_NONE, NULL, 0x0,
143 "JXTA Message Namespace Name", HFILL }
145 { &hf_jxta_message_element_count,
146 { "Element Count", "jxta.message.elements", FT_UINT16, BASE_DEC, NULL, 0x0,
147 "JXTA Message Element Count", HFILL }
150 { "JXTA Message Element", "jxta.message.element", FT_NONE, BASE_NONE, NULL, 0x0,
151 "JXTA Message Element", HFILL }
153 { &hf_jxta_element_sig,
154 { "Signature", "jxta.message.element.signature", FT_STRING, BASE_NONE, NULL, 0x0,
155 "JXTA Message Element Signature", HFILL }
157 { &hf_jxta_element_namespaceid,
158 { "Namespace ID", "jxta.message.element.namespaceid", FT_UINT8, BASE_DEC, NULL, 0x0,
159 "JXTA Message Element Namespace ID", HFILL }
162 /* TODO 20050104 bondolo This should be a bitfield */
164 { &hf_jxta_element_flags,
165 { "Flags", "jxta.message.element.flags", FT_UINT8, BASE_HEX, NULL, 0x0,
166 "JXTA Message Element Flags", HFILL }
168 { &hf_jxta_element_name_len,
169 { "Element Name Length", "jxta.message.element.name.length", FT_UINT16, BASE_DEC, NULL, 0x0,
170 "JXTA Message Element Name Length", HFILL }
172 { &hf_jxta_element_name,
173 { "Element Name", "jxta.message.element.name", FT_STRING, BASE_NONE, NULL, 0x0,
174 "JXTA Message Element Name", HFILL }
176 { &hf_jxta_element_type_len,
177 { "Element Type Length", "jxta.message.element.type.length", FT_UINT16, BASE_DEC, NULL, 0x0,
178 "JXTA Message Element Name Length", HFILL }
180 { &hf_jxta_element_type,
181 { "Element Type", "jxta.message.element.type", FT_STRING, BASE_NONE, NULL, 0x0,
182 "JXTA Message Element Name", HFILL }
184 { &hf_jxta_element_encoding_len,
185 { "Element Type Length", "jxta.message.element.encoding.length", FT_UINT16, BASE_DEC, NULL, 0x0,
186 "JXTA Message Element Encoding Length", HFILL }
188 { &hf_jxta_element_encoding,
189 { "Element Type", "jxta.message.element.encoding", FT_STRING, BASE_NONE, NULL, 0x0,
190 "JXTA Message Element Encoding", HFILL }
192 { &hf_jxta_element_content_len,
193 { "Element Content Length", "jxta.message.element.content.length", FT_UINT32, BASE_DEC, NULL, 0x0,
194 "JXTA Message Element Content Length", HFILL }
196 { &hf_jxta_element_content,
197 { "Element Content", "jxta.message.element.content", FT_BYTES, BASE_HEX, NULL, 0x0,
198 "JXTA Message Element Content", HFILL }
202 /** setup protocol subtree array */
203 static gint * const ett[] = {
211 static int gUDP_MULTICAST_PORT_JXTA = 1234;
212 static int gHTTP_PORT_JXTA = 9700;
213 static int gTCP_PORT_JXTA = 9701;
215 static int regUDP_MULTICAST_PORT_JXTA = -1;
216 static int regHTTP_PORT_JXTA = -1;
217 static int regTCP_PORT_JXTA = -1;
220 static void dissect_jxta_framing(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree);
222 static void dissect_jxta_message(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree);
224 void proto_reg_handoff_jxta(void);
227 Dissect a tvbuff containing a JXTA UDP header, JXTA Message framing and a JXTA Message
229 static void dissect_jxta_udp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) {
230 proto_tree *jxta_tree = NULL;
233 if (check_col(pinfo->cinfo, COL_PROTOCOL)) {
234 col_set_str(pinfo->cinfo, COL_PROTOCOL, "JXTA");
237 if (check_col(pinfo->cinfo, COL_INFO)) {
239 * bondolo For now just say its a message. eventually put in dest addr.
240 * XXX - if "dest addr" means the IP destination address, that's
241 * already going to be in the "destination address" column if you're
244 col_add_fstr(pinfo->cinfo, COL_INFO, "%s", "UDP Message");
248 ti = proto_tree_add_item(tree, hf_jxta_udp, tvb, 0, -1, FALSE);
249 jxta_tree = proto_item_add_subtree(ti, ett_jxta_udp);
251 ti = proto_tree_add_item( jxta_tree, hf_jxta_udpsig, tvb, 0, 4, FALSE );
254 if( tvb_memeql(tvb, 0, "JXTA", 4) == 0 ) {
255 tvbuff_t* jxta_framed_message_tvb = tvb_new_subset( tvb, 4, -1, -1 );
257 dissect_jxta_framing( jxta_framed_message_tvb, pinfo, tree );
261 static void dissect_jxta_tcp_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) {
262 dissect_jxta_message( tvb, pinfo, tree );
265 static void dissect_jxta_tcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) {
266 /* XXX this is broken.
267 you MUST provide a header dissector and not NULL
268 the header dissector MUST do heuristict to verify it really is a
270 you SHOULD also specify desegmentation as a variable and not always TRUE
271 tcp_dissect_pdus(tvb, pinfo, tree, TRUE, 0, NULL, dissect_jxta_tcp_pdu);
273 dissect_jxta_tcp_pdu(tvb, pinfo, tree);
277 Dissect a tvbuff containing a JXTA Message framing and a JXTA Message
279 static void dissect_jxta_framing(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) {
280 proto_tree *jxta_tree = NULL;
283 tvbuff_t* jxta_message_tvb;
286 ti = proto_tree_add_item(tree, hf_jxta_framing, tvb, 0, -1, FALSE);
287 jxta_tree = proto_item_add_subtree(ti, ett_jxta_framing);
290 /* parse framing headers */
292 guint8 headernamelen = tvb_get_guint8( tvb, offset );
295 proto_tree_add_item( jxta_tree, hf_jxta_framing_header_name_length, tvb, offset, 1, headernamelen );
298 if( tree && (headernamelen != 0) ) {
300 * Put header name into protocol tree.
302 proto_tree_add_item(jxta_tree, hf_jxta_framing_header_name, tvb, offset+1, headernamelen, FALSE);
305 offset += 1 + headernamelen;
307 if( headernamelen > 0 ) {
308 guint16 headervaluelen = tvb_get_ntohs( tvb, offset );
311 proto_tree_add_uint(jxta_tree, hf_jxta_framing_header_value_length, tvb, offset, 2, headervaluelen );
313 /** TODO bondolo Add specific handling for known header types */
316 * Put header value into protocol tree.
318 proto_tree_add_item(jxta_tree, hf_jxta_framing_header_value, tvb, offset+2, headervaluelen, FALSE );
321 offset += 2 + headervaluelen;
324 if( 0 == headernamelen ) {
329 jxta_message_tvb = tvb_new_subset( tvb, offset, -1, -1 );
331 /* Call it a new layer and pass the tree as we got it */
332 dissect_jxta_message( jxta_message_tvb, pinfo, tree );
336 Dissect a tvbuff containing a JXTA Message
338 static void dissect_jxta_message(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) {
339 proto_tree *jxta_tree = NULL;
342 if (check_col(pinfo->cinfo, COL_PROTOCOL)) {
343 col_set_str(pinfo->cinfo, COL_PROTOCOL, "JXTA");
346 if (check_col(pinfo->cinfo, COL_INFO)) {
348 * TODO bondolo For now just say its a message. eventually put in dest addr.
349 * XXX - if "dest addr" means the IP destination address, that's
350 * already going to be in the "destination address" column if you're
353 col_add_fstr(pinfo->cinfo, COL_INFO, "%s", "Message");
357 ti = proto_tree_add_item(tree, hf_jxta_message, tvb, 0, -1, FALSE);
358 jxta_tree = proto_item_add_subtree(ti, ett_jxta_udp);
362 proto_tree_add_item( jxta_tree, hf_jxta_message_sig, tvb, 0, 4, FALSE);
364 if( tvb_memeql(tvb, 0, "jxmg", 4) == 0) {
365 guint8 messageVersion;
367 messageVersion = tvb_get_guint8( tvb, sizeof(guint32) );
368 proto_tree_add_uint( jxta_tree, hf_jxta_message_version, tvb, sizeof(guint32), 1, messageVersion );
370 if( 0 == messageVersion ) {
372 guint16 numberOfElements;
373 unsigned int offset = 7;
374 guint16 messageNamespaceCount = tvb_get_ntohs( tvb, 5 );
376 /* parse namespaces */
377 /* TODO 20050103 bondolo Should record the namespaces and number them. */
378 for( eachNamespace = 0; eachNamespace < messageNamespaceCount; eachNamespace++ ) {
379 guint8 namespaceLen = tvb_get_guint8( tvb, offset );
381 proto_tree_add_uint(jxta_tree, hf_jxta_message_namespace_len, tvb, offset++, namespaceLen, namespaceLen );
383 proto_tree_add_item(jxta_tree, hf_jxta_message_namespace_name, tvb, offset, namespaceLen, FALSE);
385 offset += namespaceLen;
389 numberOfElements = tvb_get_ntohs( tvb, offset );
390 proto_tree_add_item(jxta_tree, hf_jxta_message_element_count, tvb, offset, sizeof(guint16), FALSE );
391 offset += sizeof(guint16);
393 while( offset < tvb_reported_length(tvb) ) {
394 proto_tree *jxta_elem_tree = NULL;
397 elem_ti = proto_tree_add_item(jxta_tree, hf_jxta_element, tvb, 0, -1, FALSE);
398 jxta_elem_tree = proto_item_add_subtree(elem_ti, ett_jxta_elem);
400 /* gross hack for parsing of signature element */
403 proto_tree_add_item( jxta_tree, hf_jxta_element_sig, tvb, offset, 4, FALSE );
405 if( tvb_memeql(tvb, offset - 4, "jxel", 4) == 0 ) {
409 guint32 elemContentLength;
411 namespaceID = tvb_get_guint8( tvb, offset );
412 proto_tree_add_uint( jxta_elem_tree, hf_jxta_element_namespaceid, tvb, offset, sizeof(guint8), namespaceID );
413 offset += sizeof(guint8);
415 flags = tvb_get_guint8( tvb, offset );
416 proto_tree_add_uint( jxta_elem_tree, hf_jxta_element_flags, tvb, offset, sizeof(guint8), flags );
417 offset += sizeof(guint8);
419 nameLen = tvb_get_ntohs( tvb, offset );
420 proto_tree_add_uint( jxta_elem_tree, hf_jxta_element_name_len, tvb, offset, sizeof(guint16), nameLen );
421 offset += sizeof(guint16);
423 proto_tree_add_item(jxta_elem_tree, hf_jxta_element_name, tvb, offset, nameLen, FALSE);
428 if( (flags & 0x01) != 0 ) {
429 guint16 typeLen = tvb_get_ntohs( tvb, offset );
430 proto_tree_add_uint( jxta_elem_tree, hf_jxta_element_type_len, tvb, offset, sizeof(guint16), typeLen );
431 offset += sizeof(guint16);
433 proto_tree_add_item(jxta_elem_tree, hf_jxta_element_type, tvb, offset, typeLen, FALSE);
438 /* process encoding */
439 if( (flags & 0x02) != 0 ) {
440 guint16 encodingLen = tvb_get_ntohs( tvb, offset );
441 ti = proto_tree_add_item( jxta_elem_tree, hf_jxta_element_encoding_len, tvb, offset, sizeof(guint16), FALSE );
442 offset += sizeof(guint16);
444 proto_tree_add_item(jxta_elem_tree, hf_jxta_element_encoding, tvb, offset, encodingLen, FALSE);
446 offset += encodingLen;
450 elemContentLength = tvb_get_ntohl( tvb, offset );
451 ti = proto_tree_add_item( jxta_elem_tree, hf_jxta_element_content_len, tvb, offset, sizeof(guint32), FALSE );
452 offset += sizeof(guint32);
454 ti = proto_tree_add_item( jxta_elem_tree, hf_jxta_element_content, tvb, offset, elemContentLength, FALSE );
455 offset += elemContentLength;
457 /* XXX Evil Hack Warning : handle parsing of signature element. Would be better with recursion.*/
458 if( (flags & 0x04) != 0 ) {
463 proto_item_set_end( elem_ti, tvb, offset - 1 );
471 void proto_register_jxta(void)
473 module_t *jxta_module;
475 proto_jxta = proto_register_protocol("JXTA P2P", "JXTA", "jxta");
477 /* Register header fields */
478 proto_register_field_array(proto_jxta, hf, array_length(hf));
480 /* Register JXTA Sub-tree */
481 proto_register_subtree_array(ett, array_length(ett));
483 /* Register preferences */
484 jxta_module = prefs_register_protocol(proto_jxta, proto_reg_handoff_jxta);
486 prefs_register_uint_preference(jxta_module, "tcp.port", "JXTA TCP Port",
487 "Set the port for JXTA TCP messages",
488 10, &gTCP_PORT_JXTA);
490 prefs_register_uint_preference(jxta_module, "http.port", "JXTA HTTP Port",
491 "Set the port for JXTA HTTP messages",
492 10, &gHTTP_PORT_JXTA);
494 prefs_register_uint_preference(jxta_module, "udp.port", "JXTA UDP Multicast Port",
495 "Set the port for JXTA UDP Multicast messages",
496 10, &gUDP_MULTICAST_PORT_JXTA);
499 void proto_reg_handoff_jxta(void) {
500 static gboolean jxta_prefs_initialized = FALSE;
502 if (!jxta_prefs_initialized) {
503 udpm_jxta_handle = create_dissector_handle(dissect_jxta_udp, proto_jxta);
504 tcp_jxta_handle = create_dissector_handle(dissect_jxta_tcp, proto_jxta);
505 http_jxta_handle = create_dissector_handle(dissect_jxta_message, proto_jxta);
507 jxta_prefs_initialized = TRUE;
509 dissector_delete("udp.port", regUDP_MULTICAST_PORT_JXTA, udpm_jxta_handle);
511 dissector_delete("tcp.port", regTCP_PORT_JXTA, tcp_jxta_handle);
513 dissector_delete("http.port", regHTTP_PORT_JXTA, http_jxta_handle);
516 /* remember what ports we registered on for later removal */
517 regUDP_MULTICAST_PORT_JXTA = gUDP_MULTICAST_PORT_JXTA;
518 regTCP_PORT_JXTA = gTCP_PORT_JXTA;
519 regHTTP_PORT_JXTA = gHTTP_PORT_JXTA;
521 /* register as a sub-dissector of UDP tagged on port field */
522 dissector_add("udp.port", regUDP_MULTICAST_PORT_JXTA, udpm_jxta_handle);
524 /* register as a sub-dissector of TCP tagged on port field*/
525 dissector_add("tcp.port", regTCP_PORT_JXTA, tcp_jxta_handle);
527 /* register as a sub-dissector of HTTP tagged on port field */
528 dissector_add("http.port", regHTTP_PORT_JXTA, http_jxta_handle);