usage of tcp_dissect_pdu is broken
[metze/wireshark/wip.git] / epan / dissectors / packet-jxta.c
1 /* packet-jxta.c
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>
7  *
8  * $Id$
9  *
10  * Ethereal - Network traffic analyzer
11  * By Gerald Combs <gerald@ethereal.com>
12  * Copyright 1998 Gerald Combs
13  *
14  * Copied from packet-pop.c, packet-jabber.c, packet-udp.c
15  *
16  * JXTA specification from http://spec.jxta.org
17  *
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.
22  *
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.
27  *
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.
31  */
32
33 #ifdef HAVE_CONFIG_H
34 # include "config.h"
35 #endif
36
37 #include <stdio.h>
38
39 #include <string.h>
40 #include <glib.h>
41 #include <epan/packet.h>
42 #include <epan/strutil.h>
43 #include <epan/prefs.h>
44 #include "packet-tcp.h"
45
46 static int proto_jxta = -1;
47
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;
76
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;
82
83 static dissector_handle_t udpm_jxta_handle;
84 static dissector_handle_t tcp_jxta_handle;
85 static dissector_handle_t http_jxta_handle;
86
87 /** our header fields */
88 static hf_register_info hf[] = {
89   { &hf_jxta_udp,
90     { "JXTA UDP Message", "jxta.udp", FT_NONE, BASE_NONE, NULL, 0x0,
91       "JXTA UDP Message", HFILL }
92   },
93   { &hf_jxta_udpsig,
94     { "Signature", "jxta.udpsig", FT_STRING, BASE_NONE, NULL, 0x0,
95       "JXTA UDP Signature", HFILL }
96   },
97   { &hf_jxta_welcome,
98     { "Welcome Message", "jxta.welcome", FT_NONE, BASE_NONE, NULL, 0x0,
99       "JXTA Connection Welcome Message", HFILL }
100   },
101   { &hf_jxta_framing,
102     { "JXTA Message Framing", "jxta.framing", FT_NONE, BASE_NONE, NULL, 0x0,
103       "JXTA Message Framing Header", HFILL }
104   },
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 }
108   },
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 }
112   },
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 }
116   },
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 }
120   },
121   { &hf_jxta_message,
122     { "JXTA Message", "jxta.message", FT_NONE, BASE_NONE, NULL, 0x0,
123       "JXTA Message", HFILL }
124   },
125   { &hf_jxta_message_sig,
126     { "Signature", "jxta.message.signature", FT_STRING, BASE_NONE, NULL, 0x0,
127       "JXTA Message Signature", HFILL }
128   },
129   { &hf_jxta_message_version,
130     { "Version", "jxta.message.version", FT_UINT8, BASE_DEC, NULL, 0x0,
131       "JXTA Message Version", HFILL }
132   },
133   { &hf_jxta_message_namespaces_count,
134     { "Namespace Count", "jxta.message.namespaces", FT_UINT16, BASE_DEC, NULL, 0x0,
135       "JXTA Message Namespaces", HFILL }
136   },
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 }
140   },
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 }
144   },
145   { &hf_jxta_message_element_count,
146     { "Element Count", "jxta.message.elements", FT_UINT16, BASE_DEC, NULL, 0x0,
147       "JXTA Message Element Count", HFILL }
148   },
149   { &hf_jxta_element,
150     { "JXTA Message Element", "jxta.message.element", FT_NONE, BASE_NONE, NULL, 0x0,
151       "JXTA Message Element", HFILL }
152   },
153   { &hf_jxta_element_sig,
154     { "Signature", "jxta.message.element.signature", FT_STRING, BASE_NONE, NULL, 0x0,
155       "JXTA Message Element Signature", HFILL }
156   },
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 }
160   },
161   
162   /* TODO 20050104 bondolo This should be a bitfield */
163   
164   { &hf_jxta_element_flags,
165     { "Flags", "jxta.message.element.flags", FT_UINT8, BASE_HEX, NULL, 0x0,
166       "JXTA Message Element Flags", HFILL }
167   },
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 }
171   },
172   { &hf_jxta_element_name,
173     { "Element Name", "jxta.message.element.name", FT_STRING, BASE_NONE, NULL, 0x0,
174       "JXTA Message Element Name", HFILL }
175   },
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 }
179   },
180   { &hf_jxta_element_type,
181     { "Element Type", "jxta.message.element.type", FT_STRING, BASE_NONE, NULL, 0x0,
182       "JXTA Message Element Name", HFILL }
183   },
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 }
187   },
188   { &hf_jxta_element_encoding,
189     { "Element Type", "jxta.message.element.encoding", FT_STRING, BASE_NONE, NULL, 0x0,
190       "JXTA Message Element Encoding", HFILL }
191   },
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 }
195   },
196   { &hf_jxta_element_content,
197     { "Element Content", "jxta.message.element.content", FT_BYTES, BASE_HEX, NULL, 0x0,
198       "JXTA Message Element Content", HFILL }
199   },
200 };
201
202 /** setup protocol subtree array */
203 static gint * const ett[] = {
204   &ett_jxta_welcome,
205   &ett_jxta_udp,
206   &ett_jxta_framing,
207   &ett_jxta_msg,
208   &ett_jxta_elem
209 };
210
211 static int gUDP_MULTICAST_PORT_JXTA = 1234;
212 static int gHTTP_PORT_JXTA = 9700;
213 static int gTCP_PORT_JXTA = 9701;
214
215 static int regUDP_MULTICAST_PORT_JXTA = -1;
216 static int regHTTP_PORT_JXTA = -1;
217 static int regTCP_PORT_JXTA = -1;
218
219
220 static void dissect_jxta_framing(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree);
221
222 static void dissect_jxta_message(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree);
223
224 void proto_reg_handoff_jxta(void);
225
226 /**
227     Dissect a tvbuff containing a JXTA UDP header, JXTA Message framing and a JXTA Message
228 **/
229 static void dissect_jxta_udp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) {
230   proto_tree      *jxta_tree = NULL;
231   proto_item      *ti;
232
233   if (check_col(pinfo->cinfo, COL_PROTOCOL)) {
234     col_set_str(pinfo->cinfo, COL_PROTOCOL, "JXTA");
235   }
236
237   if (check_col(pinfo->cinfo, COL_INFO)) {
238     /*
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
242      * displaying that.
243      */
244     col_add_fstr(pinfo->cinfo, COL_INFO, "%s", "UDP Message");
245   }
246
247   if (tree) {
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);
250     
251     ti = proto_tree_add_item( jxta_tree, hf_jxta_udpsig, tvb, 0, 4, FALSE );
252   }
253   
254   if( tvb_memeql(tvb, 0, "JXTA", 4) == 0 ) {
255     tvbuff_t* jxta_framed_message_tvb = tvb_new_subset( tvb, 4, -1, -1 );
256
257     dissect_jxta_framing( jxta_framed_message_tvb, pinfo, tree );
258   }
259 }
260
261 static void dissect_jxta_tcp_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) {
262   dissect_jxta_message( tvb, pinfo, tree );
263 }
264
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 
269      proper jxta header.
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);
272   */
273   dissect_jxta_tcp_pdu(tvb, pinfo, tree);
274 }
275
276 /**
277     Dissect a tvbuff containing a JXTA Message framing and a JXTA Message
278 **/
279 static void dissect_jxta_framing(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) {
280   proto_tree      *jxta_tree = NULL;
281   proto_item      *ti;
282   guint offset = 0;
283   tvbuff_t* jxta_message_tvb;
284   
285   if (tree) {
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);
288     }
289     
290   /* parse framing headers */
291   do {
292     guint8 headernamelen = tvb_get_guint8( tvb, offset );
293
294     if(tree) {
295       proto_tree_add_item( jxta_tree, hf_jxta_framing_header_name_length, tvb, offset, 1, headernamelen );
296     }
297     
298     if( tree && (headernamelen != 0) ) {
299       /*
300        * Put header name into protocol tree.
301        */
302       proto_tree_add_item(jxta_tree, hf_jxta_framing_header_name, tvb, offset+1, headernamelen, FALSE);
303     }
304     
305     offset += 1 + headernamelen;
306       
307     if( headernamelen > 0 ) {
308       guint16 headervaluelen = tvb_get_ntohs( tvb, offset );
309
310       if( tree ) {
311         proto_tree_add_uint(jxta_tree, hf_jxta_framing_header_value_length, tvb, offset, 2, headervaluelen );
312
313         /** TODO bondolo Add specific handling for known header types */
314
315         /*
316          * Put header value into protocol tree.
317          */
318         proto_tree_add_item(jxta_tree, hf_jxta_framing_header_value, tvb, offset+2, headervaluelen, FALSE );
319       }
320       
321       offset += 2 + headervaluelen;
322     }
323     
324     if( 0 == headernamelen ) {
325       break;
326     }
327   } while( TRUE );
328   
329   jxta_message_tvb = tvb_new_subset( tvb, offset, -1, -1 );
330
331   /* Call it a new layer and pass the tree as we got it */
332   dissect_jxta_message( jxta_message_tvb, pinfo, tree );
333 }
334
335 /**
336     Dissect a tvbuff containing a JXTA Message
337 **/
338 static void dissect_jxta_message(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) {
339   proto_tree      *jxta_tree = NULL;
340   proto_item      *ti;
341
342   if (check_col(pinfo->cinfo, COL_PROTOCOL)) {
343     col_set_str(pinfo->cinfo, COL_PROTOCOL, "JXTA");
344   }
345
346   if (check_col(pinfo->cinfo, COL_INFO)) {
347     /*
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
351      * displaying that.
352      */
353     col_add_fstr(pinfo->cinfo, COL_INFO, "%s", "Message");
354   }
355
356   if (tree) {
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);
359   }
360
361   if( tree ) {
362     proto_tree_add_item( jxta_tree, hf_jxta_message_sig, tvb, 0, 4, FALSE);
363     
364     if( tvb_memeql(tvb, 0, "jxmg", 4) == 0) {
365         guint8 messageVersion;
366         
367         messageVersion = tvb_get_guint8( tvb, sizeof(guint32) );
368         proto_tree_add_uint( jxta_tree, hf_jxta_message_version, tvb, sizeof(guint32), 1, messageVersion );
369         
370         if( 0 == messageVersion ) {
371             int eachNamespace;
372             guint16 numberOfElements;
373             unsigned int offset = 7;
374             guint16 messageNamespaceCount = tvb_get_ntohs( tvb, 5 );
375             
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 );
380                 
381                 proto_tree_add_uint(jxta_tree, hf_jxta_message_namespace_len, tvb, offset++, namespaceLen, namespaceLen );
382                 
383                 proto_tree_add_item(jxta_tree, hf_jxta_message_namespace_name, tvb, offset, namespaceLen, FALSE);
384                     
385                 offset += namespaceLen;
386             }
387             
388             /* parse elements */
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);
392             
393             while( offset < tvb_reported_length(tvb) ) {
394                     proto_tree   *jxta_elem_tree = NULL;
395                     proto_item      *elem_ti;
396                     
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);
399
400                 /* gross hack for parsing of signature element */
401                 element_parse :
402                 {
403                 proto_tree_add_item( jxta_tree, hf_jxta_element_sig, tvb, offset, 4, FALSE );
404                 offset += 4;
405                 if( tvb_memeql(tvb, offset - 4, "jxel", 4) == 0 ) {
406                     guint8 namespaceID;
407                     guint8 flags;
408                     guint16 nameLen;
409                     guint32 elemContentLength;
410
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);
414                 
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);
418                     
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);
422                     
423                     proto_tree_add_item(jxta_elem_tree, hf_jxta_element_name, tvb, offset, nameLen, FALSE);
424                         
425                     offset += nameLen;
426                     
427                     /* process type */
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);
432
433                         proto_tree_add_item(jxta_elem_tree, hf_jxta_element_type, tvb, offset, typeLen, FALSE);
434
435                         offset += typeLen;
436                     }
437                     
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);
443
444                         proto_tree_add_item(jxta_elem_tree, hf_jxta_element_encoding, tvb, offset, encodingLen, FALSE);
445
446                         offset += encodingLen;
447                     }
448                     
449                     /* content */
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);
453                     
454                     ti = proto_tree_add_item( jxta_elem_tree, hf_jxta_element_content, tvb, offset, elemContentLength, FALSE );
455                     offset += elemContentLength;
456                     
457                     /* XXX Evil Hack Warning : handle parsing of signature element. Would be better with recursion.*/
458                     if( (flags & 0x04) != 0 ) {
459                         goto element_parse;
460                     }
461                 }
462                     
463                 proto_item_set_end( elem_ti, tvb, offset - 1 );
464                 }
465             }
466         }
467     }    
468   }
469 }
470
471 void proto_register_jxta(void)
472 {
473   module_t *jxta_module;
474
475   proto_jxta = proto_register_protocol("JXTA P2P", "JXTA", "jxta");
476   
477    /* Register header fields */
478   proto_register_field_array(proto_jxta, hf, array_length(hf));
479   
480   /* Register JXTA Sub-tree */
481   proto_register_subtree_array(ett, array_length(ett));
482
483   /* Register preferences */
484   jxta_module = prefs_register_protocol(proto_jxta, proto_reg_handoff_jxta);
485   
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);
489
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);
493
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);
497 }
498
499 void proto_reg_handoff_jxta(void) {
500   static gboolean jxta_prefs_initialized = FALSE;
501
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);
506
507     jxta_prefs_initialized = TRUE;
508   } else {
509     dissector_delete("udp.port", regUDP_MULTICAST_PORT_JXTA, udpm_jxta_handle);
510
511     dissector_delete("tcp.port", regTCP_PORT_JXTA, tcp_jxta_handle);
512
513     dissector_delete("http.port", regHTTP_PORT_JXTA, http_jxta_handle);
514   }
515
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;
520    
521   /* register as a sub-dissector of UDP  tagged on port field */
522   dissector_add("udp.port", regUDP_MULTICAST_PORT_JXTA, udpm_jxta_handle);
523
524   /* register as a sub-dissector of TCP tagged on port field*/
525   dissector_add("tcp.port", regTCP_PORT_JXTA, tcp_jxta_handle);
526
527   /* register as a sub-dissector of HTTP tagged on port field */
528   dissector_add("http.port", regHTTP_PORT_JXTA, http_jxta_handle);
529 }