For proto_tree_add_item(..., proto_xxx, ...)use ENC_NA as the encoding arg.
[obnox/wireshark/wip.git] / epan / dissectors / packet-distcc.c
1 /* packet-distcc.c
2  * Routines for distcc dissection
3  * Copyright 2003, Brad Hards <bradh@frogmouth.net>
4  * Copyright 2003, Ronnie Sahlberg, added TCP desegmentation.
5  *
6  * $Id$
7  *
8  * Wireshark - Network traffic analyzer
9  * By Gerald Combs <gerald@wireshark.org>
10  * Copyright 1998 Gerald Combs
11  *
12  * This program is free software; you can redistribute it and/or
13  * modify it under the terms of the GNU General Public License
14  * as published by the Free Software Foundation; either version 2
15  * of the License, or (at your option) any later version.
16  *
17  * This program is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20  * GNU General Public License for more details.
21  *
22  * You should have received a copy of the GNU General Public License
23  * along with this program; if not, write to the Free Software
24  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
25  */
26 /* This dissector supports version 1 of the DISTCC protocol */
27
28 #ifdef HAVE_CONFIG_H
29 # include "config.h"
30 #endif
31
32 #include <stdio.h>
33 #include <stdlib.h>
34
35 #include <string.h>
36 #include <time.h>
37 #include <glib.h>
38
39 #include <epan/packet.h>
40 #include <epan/strutil.h>
41
42 #include <epan/prefs.h>
43
44
45 static int proto_distcc = -1;
46 static int hf_distcc_version = -1;
47 static int hf_distcc_argc = -1;
48 static int hf_distcc_argv = -1;
49 static int hf_distcc_doti_source = -1;
50 static int hf_distcc_stat = -1;
51 static int hf_distcc_serr = -1;
52 static int hf_distcc_sout = -1;
53 static int hf_distcc_doto_object = -1;
54
55
56 static gint ett_distcc = -1;
57
58 static dissector_handle_t data_handle;
59
60
61 static gboolean distcc_desegment = TRUE;
62
63
64 #define TCP_PORT_DISTCC 3632
65
66 static guint glb_distcc_tcp_port = TCP_PORT_DISTCC;
67
68 extern void proto_reg_handoff_distcc(void);
69
70 #define CHECK_PDU_LEN(x) \
71         if(parameter>tvb_length_remaining(tvb, offset) || parameter < 1){\
72                 len=tvb_length_remaining(tvb, offset);\
73                 col_append_str(pinfo->cinfo, COL_INFO, "[Short" x " PDU]");\
74         } \
75         tvb_ensure_bytes_exist(tvb, offset, len);
76
77
78 #define DESEGMENT_TCP(x) \
79         if(distcc_desegment && pinfo->can_desegment){\
80                 /* only attempt reassembly if whe have the full segment */\
81                 if(tvb_length_remaining(tvb, offset)==tvb_reported_length_remaining(tvb, offset)){\
82                         if(parameter>tvb_length_remaining(tvb, offset)){\
83                                 proto_tree_add_text(tree, tvb, offset-12, -1, "[Short " x " PDU]");\
84                                 pinfo->desegment_offset=offset-12;\
85                                 pinfo->desegment_len=parameter-tvb_length_remaining(tvb, offset);\
86                                 return offset+len;\
87                         }\
88                 }\
89         }
90
91
92
93
94
95 static int
96 dissect_distcc_dist(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset, guint32 parameter)
97 {
98         proto_tree_add_uint_format(tree, hf_distcc_version, tvb, offset-12, 12, parameter, "DIST: %d", parameter);
99
100         col_append_fstr(pinfo->cinfo, COL_INFO, "DIST:%d ", parameter);
101
102         return offset;
103 }
104
105 static int
106 dissect_distcc_done(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset, guint32 parameter)
107 {
108         proto_tree_add_uint_format(tree, hf_distcc_version, tvb, offset-12, 12, parameter, "DONE: %d", parameter);
109
110         col_append_fstr(pinfo->cinfo, COL_INFO, "DONE:%d ", parameter);
111
112         return offset;
113 }
114
115 static int
116 dissect_distcc_stat(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset, guint32 parameter)
117 {
118         proto_tree_add_uint_format(tree, hf_distcc_stat, tvb, offset-12, 12, parameter, "STAT: %d", parameter);
119
120         col_append_fstr(pinfo->cinfo, COL_INFO, "STAT:%d ", parameter);
121
122         return offset;
123 }
124
125 static int
126 dissect_distcc_argc(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, int offset, guint32 parameter)
127 {
128         proto_tree_add_uint_format(tree, hf_distcc_argc, tvb, offset-12, 12, parameter, "ARGC: %d", parameter);
129
130         col_append_fstr(pinfo->cinfo, COL_INFO, "ARGC:%d ", parameter);
131
132         return offset;
133 }
134
135 static int
136 dissect_distcc_argv(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, int offset, gint parameter)
137 {
138         char argv[256];
139         int argv_len;
140         gint len=parameter;
141
142
143         CHECK_PDU_LEN("ARGV");
144
145         /* see if we need to desegment the PDU */
146         DESEGMENT_TCP("ARGV");
147
148
149
150         argv_len=len>255?255:len;
151         tvb_memcpy(tvb, argv, offset, argv_len);
152         argv[argv_len]=0;
153
154         proto_tree_add_item(tree, hf_distcc_argv, tvb, offset, len, ENC_ASCII|ENC_NA);
155
156         col_append_fstr(pinfo->cinfo, COL_INFO, "%s ", argv);
157
158         if(len!=parameter){
159                 proto_tree_add_text(tree, tvb, 0, 0, "[Short ARGV PDU]");
160         }
161         return offset+len;
162 }
163
164 static int
165 dissect_distcc_serr(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, int offset, gint parameter)
166 {
167         char argv[256];
168         int argv_len;
169         gint len=parameter;
170
171
172         CHECK_PDU_LEN("SERR");
173
174         /* see if we need to desegment the PDU */
175         DESEGMENT_TCP("SERR");
176
177
178
179         argv_len=len>255?255:len;
180         tvb_memcpy(tvb, argv, offset, argv_len);
181         argv[argv_len]=0;
182
183         proto_tree_add_item(tree, hf_distcc_serr, tvb, offset, len, ENC_ASCII|ENC_NA);
184
185         col_append_fstr(pinfo->cinfo, COL_INFO, "SERR:%s ", argv);
186
187         if(len!=parameter){
188                 proto_tree_add_text(tree, tvb, 0, 0, "[Short SERR PDU]");
189         }
190         return offset+len;
191 }
192
193 static int
194 dissect_distcc_sout(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, int offset, gint parameter)
195 {
196         char argv[256];
197         int argv_len;
198         gint len=parameter;
199
200
201         CHECK_PDU_LEN("SOUT");
202
203         /* see if we need to desegment the PDU */
204         DESEGMENT_TCP("SOUT");
205
206
207
208         argv_len=len>255?255:len;
209         tvb_memcpy(tvb, argv, offset, argv_len);
210         argv[argv_len]=0;
211
212         proto_tree_add_item(tree, hf_distcc_sout, tvb, offset, len, ENC_ASCII|ENC_NA);
213
214         col_append_fstr(pinfo->cinfo, COL_INFO, "SOUT:%s ", argv);
215
216         if(len!=parameter){
217                 proto_tree_add_text(tree, tvb, 0, 0, "[Short SOUT PDU]");
218         }
219         return offset+len;
220 }
221
222
223 static int
224 dissect_distcc_doti(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset, gint parameter)
225 {
226         gint len=parameter;
227
228
229         CHECK_PDU_LEN("DOTI");
230
231         /* see if we need to desegment the PDU */
232         DESEGMENT_TCP("DOTI");
233
234         col_append_str(pinfo->cinfo, COL_INFO, "DOTI source ");
235
236         proto_tree_add_item(tree, hf_distcc_doti_source, tvb, offset, len, ENC_ASCII|ENC_NA);
237         if(len!=parameter){
238                 proto_tree_add_text(tree, tvb, 0, 0, "[Short DOTI PDU]");
239         }
240         return offset+len;
241 }
242
243 static int
244 dissect_distcc_doto(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset, gint parameter)
245 {
246         gint len=parameter;
247
248
249         CHECK_PDU_LEN("DOTO");
250
251         /* see if we need to desegment the PDU */
252         DESEGMENT_TCP("DOTO");
253
254         col_append_str(pinfo->cinfo, COL_INFO, "DOTO object ");
255
256         proto_tree_add_item(tree, hf_distcc_doto_object, tvb, offset, len, ENC_NA);
257         if(len!=parameter){
258                 proto_tree_add_text(tree, tvb, 0, 0, "[Short DOTO PDU]");
259         }
260         return offset+len;
261 }
262
263
264
265 /* Packet dissection routine called by tcp (& udp) when port 3632 detected */
266 static void
267 dissect_distcc(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree)
268 {
269         int offset=0;
270         proto_tree *tree=NULL;
271         proto_item *item=NULL;
272         char token[4];
273         guint32 parameter;
274
275
276         col_set_str(pinfo->cinfo, COL_PROTOCOL, "DISTCC ");
277
278         col_clear(pinfo->cinfo, COL_INFO);
279
280         if (parent_tree) {
281                 item = proto_tree_add_item(parent_tree, proto_distcc, tvb, offset,
282                         -1, ENC_NA);
283                 tree = proto_item_add_subtree(item, ett_distcc);
284         }
285
286         while(1){
287                 /* we must have at least 12 bytes so we can read the
288                    token and the parameter */
289                 if(tvb_length_remaining(tvb, offset)<12){
290                         return;
291                 }
292
293                 /* read the token */
294                 tvb_memcpy(tvb, token, offset, 4);
295                 offset+=4;
296
297                 /* read the parameter */
298                 if (sscanf(tvb_get_ptr(tvb, offset, 8), "%08x", &parameter) != 1)
299                         return;
300                 offset+=8;
301
302                 if(!strncmp(token, "DIST", 4)){
303                         offset=dissect_distcc_dist(tvb, pinfo, tree, offset, parameter);
304                 } else if(!strncmp(token, "ARGC", 4)){
305                         offset=dissect_distcc_argc(tvb, pinfo, tree, offset, parameter);
306                 } else if(!strncmp(token, "ARGV", 4)){
307                         offset=dissect_distcc_argv(tvb, pinfo, tree, offset, parameter);
308                 } else if(!strncmp(token, "DOTI", 4)){
309                         offset=dissect_distcc_doti(tvb, pinfo, tree, offset, parameter);
310                 } else if(!strncmp(token, "DONE", 4)){
311                         offset=dissect_distcc_done(tvb, pinfo, tree, offset, parameter);
312                 } else if(!strncmp(token, "STAT", 4)){
313                         offset=dissect_distcc_stat(tvb, pinfo, tree, offset, parameter);
314                 } else if(!strncmp(token, "SERR", 4)){
315                         offset=dissect_distcc_serr(tvb, pinfo, tree, offset, parameter);
316                 } else if(!strncmp(token, "SOUT", 4)){
317                         offset=dissect_distcc_sout(tvb, pinfo, tree, offset, parameter);
318                 } else if(!strncmp(token, "DOTO", 4)){
319                         offset=dissect_distcc_doto(tvb, pinfo, tree, offset, parameter);
320                 } else {
321                         call_dissector(data_handle, tvb, pinfo, tree);
322                         return;
323                 }
324         }
325
326
327 }
328
329 /* Register protocol with Wireshark. */
330 void
331 proto_register_distcc(void)
332 {
333     static hf_register_info hf[] = {
334         {&hf_distcc_version,
335          {"DISTCC Version", "distcc.version",
336           FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }
337         },
338         {&hf_distcc_argc,
339          {"ARGC", "distcc.argc",
340           FT_UINT32, BASE_DEC, NULL, 0x0, "Number of arguments", HFILL }
341         },
342         {&hf_distcc_argv,
343          {"ARGV", "distcc.argv",
344           FT_STRING, BASE_NONE, NULL, 0x0, "ARGV argument", HFILL }
345         },
346         {&hf_distcc_doti_source,
347          {"Source", "distcc.doti_source",
348           FT_STRING, BASE_NONE, NULL, 0x0, "DOTI Preprocessed Source File (.i)", HFILL }
349         },
350         {&hf_distcc_stat,
351          {"Status", "distcc.status",
352           FT_UINT32, BASE_DEC, NULL, 0x0, "Unix wait status for command completion", HFILL }
353         },
354         {&hf_distcc_serr,
355          {"SERR", "distcc.serr",
356           FT_STRING, BASE_NONE, NULL, 0x0, "STDERR output", HFILL }
357         },
358         {&hf_distcc_sout,
359          {"SOUT", "distcc.sout",
360           FT_STRING, BASE_NONE, NULL, 0x0, "STDOUT output", HFILL }
361         },
362         {&hf_distcc_doto_object,
363          {"Object", "distcc.doto_object",
364           FT_BYTES, BASE_NONE, NULL, 0x0, "DOTO Compiled object file (.o)", HFILL }
365         }
366
367         };
368
369         static gint *ett[] = {
370                 &ett_distcc,
371         };
372
373         module_t *distcc_module;
374
375         proto_distcc = proto_register_protocol("Distcc Distributed Compiler",
376                                            "DISTCC", "distcc");
377         proto_register_field_array(proto_distcc, hf, array_length(hf));
378         proto_register_subtree_array(ett, array_length(ett));
379
380         distcc_module = prefs_register_protocol(proto_distcc,
381             proto_reg_handoff_distcc);
382         prefs_register_uint_preference(distcc_module, "tcp.port",
383                                    "DISTCC TCP Port",
384                                    "Set the TCP port for DISTCC messages",
385                                    10,
386                                    &glb_distcc_tcp_port);
387         prefs_register_bool_preference(distcc_module, "desegment_distcc_over_tcp",
388         "Reassemble DISTCC-over-TCP messages\nspanning multiple TCP segments",
389                 "Whether the DISTCC dissector should reassemble messages spanning multiple TCP segments."
390                 " To use this option, you must also enable \"Allow subdissectors to reassemble TCP streams\" in the TCP protocol settings.",
391                 &distcc_desegment);
392 }
393
394 void
395 proto_reg_handoff_distcc(void)
396 {
397         static gboolean registered_dissector = FALSE;
398         static int distcc_tcp_port;
399         static dissector_handle_t distcc_handle;
400
401         if (!registered_dissector) {
402                 /*
403                  * We haven't registered the dissector yet; get a handle
404                  * for it.
405                  */
406                 distcc_handle = create_dissector_handle(dissect_distcc,
407                     proto_distcc);
408                 data_handle = find_dissector("data");
409                 registered_dissector = TRUE;
410         } else {
411                 /*
412                  * We've registered the dissector with a TCP port number
413                  * of "distcc_tcp_port"; we might be changing the TCP port
414                  * number, so remove that registration.
415                  */
416                 dissector_delete_uint("tcp.port", distcc_tcp_port, distcc_handle);
417         }
418         distcc_tcp_port = glb_distcc_tcp_port;
419         dissector_add_uint("tcp.port", distcc_tcp_port, distcc_handle);
420 }