Fix document creation under Windows, add ethereal-filter.html to the NSIS
[obnox/wireshark/wip.git] / 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: packet-distcc.c,v 1.4 2003/09/16 17:36:09 guy Exp $
7  *
8  * Ethereal - Network traffic analyzer
9  * By Gerald Combs <gerald@ethereal.com>
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 "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 int 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)){\
72                 len=tvb_length_remaining(tvb, offset);\
73                 if (check_col(pinfo->cinfo, COL_INFO)) {\
74                         col_append_fstr(pinfo->cinfo, COL_INFO, "[Short" x " PDU]");\
75                 }\
76         }
77
78
79 #define DESEGMENT_TCP(x) \
80         if(distcc_desegment && pinfo->can_desegment){\
81                 /* only attempt reassembly if whe have the full segment */\
82                 if(tvb_length_remaining(tvb, offset)==tvb_reported_length_remaining(tvb, offset)){\
83                         if(parameter>tvb_length_remaining(tvb, offset)){\
84                                 proto_tree_add_text(tree, tvb, offset-12, -1, "[Short " x " PDU]");\
85                                 pinfo->desegment_offset=offset-12;\
86                                 pinfo->desegment_len=parameter-tvb_length_remaining(tvb, offset);\
87                                 return offset+len;\
88                         }\
89                 }\
90         }
91
92
93
94
95
96 static int
97 dissect_distcc_dist(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset, guint32 parameter)
98 {
99         proto_tree_add_uint_format(tree, hf_distcc_version, tvb, offset-12, 12, parameter, "DIST: %d", parameter);
100
101         if (check_col(pinfo->cinfo, COL_INFO)) {
102                 col_append_fstr(pinfo->cinfo, COL_INFO, "DIST:%d ", parameter);
103         }
104
105         return offset;
106 }
107
108 static int
109 dissect_distcc_done(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset, guint32 parameter)
110 {
111         proto_tree_add_uint_format(tree, hf_distcc_version, tvb, offset-12, 12, parameter, "DONE: %d", parameter);
112
113         if (check_col(pinfo->cinfo, COL_INFO)) {
114                 col_append_fstr(pinfo->cinfo, COL_INFO, "DONE:%d ", parameter);
115         }
116
117         return offset;
118 }
119
120 static int
121 dissect_distcc_stat(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset, guint32 parameter)
122 {
123         proto_tree_add_uint_format(tree, hf_distcc_stat, tvb, offset-12, 12, parameter, "STAT: %d", parameter);
124
125         if (check_col(pinfo->cinfo, COL_INFO)) {
126                 col_append_fstr(pinfo->cinfo, COL_INFO, "STAT:%d ", parameter);
127         }
128
129         return offset;
130 }
131
132 static int
133 dissect_distcc_argc(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, int offset, guint32 parameter)
134 {
135         proto_tree_add_uint_format(tree, hf_distcc_argc, tvb, offset-12, 12, parameter, "ARGC: %d", parameter);
136
137         if (check_col(pinfo->cinfo, COL_INFO)) {
138                 col_append_fstr(pinfo->cinfo, COL_INFO, "ARGC:%d ", parameter);
139         }
140
141         return offset;
142 }
143
144 static int
145 dissect_distcc_argv(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, int offset, gint parameter)
146 {
147         char argv[256]; 
148         int argv_len;
149         gint len=parameter;
150
151
152         CHECK_PDU_LEN("ARGV");
153
154         /* see if we need to desegment the PDU */
155         DESEGMENT_TCP("ARGV");
156
157
158
159         argv_len=len>255?255:len;
160         tvb_memcpy(tvb, argv, offset, argv_len);
161         argv[argv_len]=0;
162
163         proto_tree_add_item(tree, hf_distcc_argv, tvb, offset, len, FALSE);
164
165         if (check_col(pinfo->cinfo, COL_INFO)) {
166                 col_append_fstr(pinfo->cinfo, COL_INFO, "%s ", argv);
167         }
168
169         if(len!=parameter){
170                 proto_tree_add_text(tree, tvb, 0, 0, "[Short ARGV PDU]");
171         }
172         return offset+len;
173 }
174
175 static int
176 dissect_distcc_serr(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, int offset, gint parameter)
177 {
178         char argv[256]; 
179         int argv_len;
180         gint len=parameter;
181
182
183         CHECK_PDU_LEN("SERR");
184
185         /* see if we need to desegment the PDU */
186         DESEGMENT_TCP("SERR");
187
188
189
190         argv_len=len>255?255:len;
191         tvb_memcpy(tvb, argv, offset, argv_len);
192         argv[argv_len]=0;
193
194         proto_tree_add_item(tree, hf_distcc_serr, tvb, offset, len, FALSE);
195
196         if (check_col(pinfo->cinfo, COL_INFO)) {
197                 col_append_fstr(pinfo->cinfo, COL_INFO, "SERR:%s ", argv);
198         }
199
200         if(len!=parameter){
201                 proto_tree_add_text(tree, tvb, 0, 0, "[Short SERR PDU]");
202         }
203         return offset+len;
204 }
205
206 static int
207 dissect_distcc_sout(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, int offset, gint parameter)
208 {
209         char argv[256]; 
210         int argv_len;
211         gint len=parameter;
212
213
214         CHECK_PDU_LEN("SOUT");
215
216         /* see if we need to desegment the PDU */
217         DESEGMENT_TCP("SOUT");
218
219
220
221         argv_len=len>255?255:len;
222         tvb_memcpy(tvb, argv, offset, argv_len);
223         argv[argv_len]=0;
224
225         proto_tree_add_item(tree, hf_distcc_sout, tvb, offset, len, FALSE);
226
227         if (check_col(pinfo->cinfo, COL_INFO)) {
228                 col_append_fstr(pinfo->cinfo, COL_INFO, "SOUT:%s ", argv);
229         }
230
231         if(len!=parameter){
232                 proto_tree_add_text(tree, tvb, 0, 0, "[Short SOUT PDU]");
233         }
234         return offset+len;
235 }
236
237
238 static int
239 dissect_distcc_doti(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset, gint parameter)
240 {
241         gint len=parameter;
242
243
244         CHECK_PDU_LEN("DOTI");
245
246         /* see if we need to desegment the PDU */
247         DESEGMENT_TCP("DOTI");
248
249         if (check_col(pinfo->cinfo, COL_INFO)) {
250                 col_append_fstr(pinfo->cinfo, COL_INFO, "DOTI source ");
251         }
252
253         proto_tree_add_item(tree, hf_distcc_doti_source, tvb, offset, len, FALSE);
254         if(len!=parameter){
255                 proto_tree_add_text(tree, tvb, 0, 0, "[Short DOTI PDU]");
256         }
257         return offset+len;
258 }
259
260 static int
261 dissect_distcc_doto(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset, gint parameter)
262 {
263         gint len=parameter;
264
265
266         CHECK_PDU_LEN("DOTO");
267
268         /* see if we need to desegment the PDU */
269         DESEGMENT_TCP("DOTO");
270
271         if (check_col(pinfo->cinfo, COL_INFO)) {
272                 col_append_fstr(pinfo->cinfo, COL_INFO, "DOTO object ");
273         }
274
275         proto_tree_add_item(tree, hf_distcc_doto_object, tvb, offset, len, FALSE);
276         if(len!=parameter){
277                 proto_tree_add_text(tree, tvb, 0, 0, "[Short DOTO PDU]");
278         }
279         return offset+len;
280 }
281
282
283
284 /* Packet dissection routine called by tcp (& udp) when port 3632 detected */
285 static void
286 dissect_distcc(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree)
287 {
288         int offset=0;
289         proto_tree *tree=NULL;
290         proto_item *item=NULL;
291         char token[4];
292         gint parameter;
293         
294
295         if (check_col(pinfo->cinfo, COL_PROTOCOL))
296                 col_set_str(pinfo->cinfo, COL_PROTOCOL, "DISTCC ");
297
298         if (check_col(pinfo->cinfo, COL_INFO))
299                 col_clear(pinfo->cinfo, COL_INFO);
300
301         if (parent_tree) {
302                 item = proto_tree_add_item(parent_tree, proto_distcc, tvb, offset,
303                         -1, FALSE);
304                 tree = proto_item_add_subtree(item, ett_distcc);
305         }
306
307         while(1){
308                 /* we must have at least 12 bytes so we can read the 
309                    token and the parameter */
310                 if(tvb_length_remaining(tvb, offset)<12){
311                         return;
312                 }
313
314                 /* read the token */
315                 tvb_memcpy(tvb, token, offset, 4);
316                 offset+=4;
317
318                 /* read the parameter */
319                 sscanf(tvb_get_ptr(tvb, offset, 8), "%08x", &parameter);
320                 offset+=8;
321
322                 if(!strncmp(token, "DIST", 4)){
323                         offset=dissect_distcc_dist(tvb, pinfo, tree, offset, parameter);
324                 } else if(!strncmp(token, "ARGC", 4)){
325                         offset=dissect_distcc_argc(tvb, pinfo, tree, offset, parameter);
326                 } else if(!strncmp(token, "ARGV", 4)){
327                         offset=dissect_distcc_argv(tvb, pinfo, tree, offset, parameter);
328                 } else if(!strncmp(token, "DOTI", 4)){
329                         offset=dissect_distcc_doti(tvb, pinfo, tree, offset, parameter);
330                 } else if(!strncmp(token, "DONE", 4)){
331                         offset=dissect_distcc_done(tvb, pinfo, tree, offset, parameter);
332                 } else if(!strncmp(token, "STAT", 4)){
333                         offset=dissect_distcc_stat(tvb, pinfo, tree, offset, parameter);
334                 } else if(!strncmp(token, "SERR", 4)){
335                         offset=dissect_distcc_serr(tvb, pinfo, tree, offset, parameter);
336                 } else if(!strncmp(token, "SOUT", 4)){
337                         offset=dissect_distcc_sout(tvb, pinfo, tree, offset, parameter);
338                 } else if(!strncmp(token, "DOTO", 4)){
339                         offset=dissect_distcc_doto(tvb, pinfo, tree, offset, parameter);
340                 } else {
341                         call_dissector(data_handle, tvb, pinfo, tree);
342                         return;
343                 }               
344         }
345
346
347 }
348
349 /* Register protocol with Ethereal. */
350 void
351 proto_register_distcc(void)
352 {
353     static hf_register_info hf[] = {
354         {&hf_distcc_version,
355          {"DISTCC Version", "distcc.version",
356           FT_UINT32, BASE_DEC, NULL, 0x0, "DISTCC Version", HFILL }
357         },
358         {&hf_distcc_argc,
359          {"ARGC", "distcc.argc",
360           FT_UINT32, BASE_DEC, NULL, 0x0, "Number of arguments", HFILL }
361         },
362         {&hf_distcc_argv,
363          {"ARGV", "distcc.argv",
364           FT_STRING, BASE_NONE, NULL, 0x0, "ARGV argument", HFILL }
365         },
366         {&hf_distcc_doti_source,
367          {"Source", "distcc.doti_source",
368           FT_STRING, BASE_NONE, NULL, 0x0, "DOTI Preprocessed Source File (.i)", HFILL }
369         },
370         {&hf_distcc_stat,
371          {"Status", "distcc.status",
372           FT_UINT32, BASE_DEC, NULL, 0x0, "Unix wait status for command completion", HFILL }
373         },
374         {&hf_distcc_serr,
375          {"SERR", "distcc.serr",
376           FT_STRING, BASE_NONE, NULL, 0x0, "STDERR output", HFILL }
377         },
378         {&hf_distcc_sout,
379          {"SOUT", "distcc.sout",
380           FT_STRING, BASE_NONE, NULL, 0x0, "STDOUT output", HFILL }
381         },
382         {&hf_distcc_doto_object,
383          {"Object", "distcc.doto_object",
384           FT_BYTES, BASE_HEX, NULL, 0x0, "DOTO Compiled object file (.o)", HFILL }
385         }
386
387         };
388
389         static gint *ett[] = {
390                 &ett_distcc,
391         };
392
393         module_t *distcc_module;
394
395         proto_distcc = proto_register_protocol("Distcc Distributed Compiler",
396                                            "DISTCC", "distcc");
397         proto_register_field_array(proto_distcc, hf, array_length(hf));
398         proto_register_subtree_array(ett, array_length(ett));
399
400         distcc_module = prefs_register_protocol(proto_distcc,
401             proto_reg_handoff_distcc);
402         prefs_register_uint_preference(distcc_module, "tcp.port",
403                                    "DISTCC TCP Port",
404                                    "Set the TCP port for DISTCC messages",
405                                    10,
406                                    &glb_distcc_tcp_port);
407         prefs_register_bool_preference(distcc_module, "desegment_distcc_over_tcp",
408                 "Desegment all DISTCC-over-TCP messages",
409                 "Whether the DISTCC dissector should desegment all DISTCC-over-TCP messages",
410                 &distcc_desegment);
411 }
412
413 void
414 proto_reg_handoff_distcc(void)
415 {
416         static gboolean registered_dissector = FALSE;
417         static int distcc_tcp_port;
418         static dissector_handle_t distcc_handle;
419
420         if (registered_dissector) {
421                 /*
422                  * We've registered the dissector with a TCP port number
423                  * of "distcc_tcp_port"; we might be changing the TCP port
424                  * number, so remove that registration.
425                  */
426                 dissector_delete("tcp.port", distcc_tcp_port, distcc_handle);
427         } else {
428                 /*
429                  * We haven't registered the dissector yet; get a handle
430                  * for it.
431                  */
432                 distcc_handle = create_dissector_handle(dissect_distcc,
433                     proto_distcc);
434                 registered_dissector = TRUE;
435         }
436         distcc_tcp_port = glb_distcc_tcp_port;
437         dissector_add("tcp.port", distcc_tcp_port, distcc_handle);
438
439         data_handle = find_dissector("data");
440 }