Frame numbers are unsigned.
[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.2 2003/05/24 20:49:58 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 #include <epan/conversation.h>
42
43 #include "prefs.h"
44
45
46 static int proto_distcc = -1;
47 static int hf_distcc_version = -1;
48 static int hf_distcc_argc = -1;
49 static int hf_distcc_argv = -1;
50 static int hf_distcc_doti_source = -1;
51 static int hf_distcc_stat = -1;
52 static int hf_distcc_serr = -1;
53 static int hf_distcc_sout = -1;
54 static int hf_distcc_doto_object = -1;
55
56
57 static gint ett_distcc = -1;
58
59 static dissector_handle_t distcc_handle;
60 static dissector_handle_t data_handle;
61
62
63 static gboolean distcc_desegment = TRUE;
64
65
66 #define TCP_PORT_DISTCC 3632
67
68 static int glb_distcc_tcp_port = TCP_PORT_DISTCC;
69
70
71 #define CHECK_PDU_LEN(x) \
72         if(parameter>tvb_length_remaining(tvb, offset)){\
73                 len=tvb_length_remaining(tvb, offset);\
74                 if (check_col(pinfo->cinfo, COL_INFO)) {\
75                         col_append_fstr(pinfo->cinfo, COL_INFO, "[Short" x " PDU]");\
76                 }\
77         }
78
79
80 #define DESEGMENT_TCP(x) \
81         if(distcc_desegment && pinfo->can_desegment){\
82                 /* only attempt reassembly if whe have the full segment */\
83                 if(tvb_length_remaining(tvb, offset)==tvb_reported_length_remaining(tvb, offset)){\
84                         if(parameter>tvb_length_remaining(tvb, offset)){\
85                                 proto_tree_add_text(tree, tvb, offset-12, -1, "[Short " x " PDU]");\
86                                 pinfo->desegment_offset=offset-12;\
87                                 pinfo->desegment_len=parameter-tvb_length_remaining(tvb, offset);\
88                                 return offset+len;\
89                         }\
90                 }\
91         }
92
93
94
95
96
97 static int
98 dissect_distcc_dist(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset, guint32 parameter)
99 {
100         proto_tree_add_uint_format(tree, hf_distcc_version, tvb, offset-12, 12, parameter, "DIST: %d", parameter);
101
102         if (check_col(pinfo->cinfo, COL_INFO)) {
103                 col_append_fstr(pinfo->cinfo, COL_INFO, "DIST:%d ", parameter);
104         }
105
106         return offset;
107 }
108
109 static int
110 dissect_distcc_done(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset, guint32 parameter)
111 {
112         proto_tree_add_uint_format(tree, hf_distcc_version, tvb, offset-12, 12, parameter, "DONE: %d", parameter);
113
114         if (check_col(pinfo->cinfo, COL_INFO)) {
115                 col_append_fstr(pinfo->cinfo, COL_INFO, "DONE:%d ", parameter);
116         }
117
118         return offset;
119 }
120
121 static int
122 dissect_distcc_stat(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset, guint32 parameter)
123 {
124         proto_tree_add_uint_format(tree, hf_distcc_stat, tvb, offset-12, 12, parameter, "STAT: %d", parameter);
125
126         if (check_col(pinfo->cinfo, COL_INFO)) {
127                 col_append_fstr(pinfo->cinfo, COL_INFO, "STAT:%d ", parameter);
128         }
129
130         return offset;
131 }
132
133 static int
134 dissect_distcc_argc(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, int offset, guint32 parameter)
135 {
136         proto_tree_add_uint_format(tree, hf_distcc_argc, tvb, offset-12, 12, parameter, "ARGC: %d", parameter);
137
138         if (check_col(pinfo->cinfo, COL_INFO)) {
139                 col_append_fstr(pinfo->cinfo, COL_INFO, "ARGC:%d ", parameter);
140         }
141
142         return offset;
143 }
144
145 static int
146 dissect_distcc_argv(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, int offset, gint parameter)
147 {
148         char argv[256]; 
149         int argv_len;
150         gint len=parameter;
151
152
153         CHECK_PDU_LEN("ARGV");
154
155         /* see if we need to desegment the PDU */
156         DESEGMENT_TCP("ARGV");
157
158
159
160         argv_len=len>255?255:len;
161         tvb_memcpy(tvb, argv, offset, argv_len);
162         argv[argv_len]=0;
163
164         proto_tree_add_item(tree, hf_distcc_argv, tvb, offset, len, FALSE);
165
166         if (check_col(pinfo->cinfo, COL_INFO)) {
167                 col_append_fstr(pinfo->cinfo, COL_INFO, "%s ", argv);
168         }
169
170         if(len!=parameter){
171                 proto_tree_add_text(tree, tvb, 0, 0, "[Short ARGV PDU]");
172         }
173         return offset+len;
174 }
175
176 static int
177 dissect_distcc_serr(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, int offset, gint parameter)
178 {
179         char argv[256]; 
180         int argv_len;
181         gint len=parameter;
182
183
184         CHECK_PDU_LEN("SERR");
185
186         /* see if we need to desegment the PDU */
187         DESEGMENT_TCP("SERR");
188
189
190
191         argv_len=len>255?255:len;
192         tvb_memcpy(tvb, argv, offset, argv_len);
193         argv[argv_len]=0;
194
195         proto_tree_add_item(tree, hf_distcc_serr, tvb, offset, len, FALSE);
196
197         if (check_col(pinfo->cinfo, COL_INFO)) {
198                 col_append_fstr(pinfo->cinfo, COL_INFO, "SERR:%s ", argv);
199         }
200
201         if(len!=parameter){
202                 proto_tree_add_text(tree, tvb, 0, 0, "[Short SERR PDU]");
203         }
204         return offset+len;
205 }
206
207 static int
208 dissect_distcc_sout(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, int offset, gint parameter)
209 {
210         char argv[256]; 
211         int argv_len;
212         gint len=parameter;
213
214
215         CHECK_PDU_LEN("SOUT");
216
217         /* see if we need to desegment the PDU */
218         DESEGMENT_TCP("SOUT");
219
220
221
222         argv_len=len>255?255:len;
223         tvb_memcpy(tvb, argv, offset, argv_len);
224         argv[argv_len]=0;
225
226         proto_tree_add_item(tree, hf_distcc_sout, tvb, offset, len, FALSE);
227
228         if (check_col(pinfo->cinfo, COL_INFO)) {
229                 col_append_fstr(pinfo->cinfo, COL_INFO, "SOUT:%s ", argv);
230         }
231
232         if(len!=parameter){
233                 proto_tree_add_text(tree, tvb, 0, 0, "[Short SOUT PDU]");
234         }
235         return offset+len;
236 }
237
238
239 static int
240 dissect_distcc_doti(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset, gint parameter)
241 {
242         gint len=parameter;
243
244
245         CHECK_PDU_LEN("DOTI");
246
247         /* see if we need to desegment the PDU */
248         DESEGMENT_TCP("DOTI");
249
250         if (check_col(pinfo->cinfo, COL_INFO)) {
251                 col_append_fstr(pinfo->cinfo, COL_INFO, "DOTI source ");
252         }
253
254         proto_tree_add_item(tree, hf_distcc_doti_source, tvb, offset, len, FALSE);
255         if(len!=parameter){
256                 proto_tree_add_text(tree, tvb, 0, 0, "[Short DOTI PDU]");
257         }
258         return offset+len;
259 }
260
261 static int
262 dissect_distcc_doto(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset, gint parameter)
263 {
264         gint len=parameter;
265
266
267         CHECK_PDU_LEN("DOTO");
268
269         /* see if we need to desegment the PDU */
270         DESEGMENT_TCP("DOTO");
271
272         if (check_col(pinfo->cinfo, COL_INFO)) {
273                 col_append_fstr(pinfo->cinfo, COL_INFO, "DOTO object ");
274         }
275
276         proto_tree_add_item(tree, hf_distcc_doto_object, tvb, offset, len, FALSE);
277         if(len!=parameter){
278                 proto_tree_add_text(tree, tvb, 0, 0, "[Short DOTO PDU]");
279         }
280         return offset+len;
281 }
282
283
284
285 /* Packet dissection routine called by tcp (& udp) when port 3632 detected */
286 static void
287 dissect_distcc(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree)
288 {
289         int offset=0;
290         proto_tree *tree=NULL;
291         proto_item *item=NULL;
292         char token[4];
293         gint parameter;
294         
295
296         if (check_col(pinfo->cinfo, COL_PROTOCOL))
297                 col_set_str(pinfo->cinfo, COL_PROTOCOL, "DISTCC ");
298
299         if (check_col(pinfo->cinfo, COL_INFO))
300                 col_clear(pinfo->cinfo, COL_INFO);
301
302         if (parent_tree) {
303                 item = proto_tree_add_item(parent_tree, proto_distcc, tvb, offset,
304                         -1, FALSE);
305                 tree = proto_item_add_subtree(item, ett_distcc);
306         }
307
308         while(1){
309                 /* we must have at least 12 bytes so we can read the 
310                    token and the parameter */
311                 if(tvb_length_remaining(tvb, offset)<12){
312                         return;
313                 }
314
315                 /* read the token */
316                 tvb_memcpy(tvb, token, offset, 4);
317                 offset+=4;
318
319                 /* read the parameter */
320                 sscanf(tvb_get_ptr(tvb, offset, 8), "%08x", &parameter);
321                 offset+=8;
322
323                 if(!strncmp(token, "DIST", 4)){
324                         offset=dissect_distcc_dist(tvb, pinfo, tree, offset, parameter);
325                 } else if(!strncmp(token, "ARGC", 4)){
326                         offset=dissect_distcc_argc(tvb, pinfo, tree, offset, parameter);
327                 } else if(!strncmp(token, "ARGV", 4)){
328                         offset=dissect_distcc_argv(tvb, pinfo, tree, offset, parameter);
329                 } else if(!strncmp(token, "DOTI", 4)){
330                         offset=dissect_distcc_doti(tvb, pinfo, tree, offset, parameter);
331                 } else if(!strncmp(token, "DONE", 4)){
332                         offset=dissect_distcc_done(tvb, pinfo, tree, offset, parameter);
333                 } else if(!strncmp(token, "STAT", 4)){
334                         offset=dissect_distcc_stat(tvb, pinfo, tree, offset, parameter);
335                 } else if(!strncmp(token, "SERR", 4)){
336                         offset=dissect_distcc_serr(tvb, pinfo, tree, offset, parameter);
337                 } else if(!strncmp(token, "SOUT", 4)){
338                         offset=dissect_distcc_sout(tvb, pinfo, tree, offset, parameter);
339                 } else if(!strncmp(token, "DOTO", 4)){
340                         offset=dissect_distcc_doto(tvb, pinfo, tree, offset, parameter);
341                 } else {
342                         call_dissector(data_handle, tvb, pinfo, tree);
343                         return;
344                 }               
345         }
346
347
348 }
349
350 /* Register protocol with Ethereal. */
351 void
352 proto_register_distcc(void)
353 {
354     static hf_register_info hf[] = {
355         {&hf_distcc_version,
356          {"DISTCC Version", "distcc.version",
357           FT_UINT32, BASE_DEC, NULL, 0x0, "DISTCC Version", HFILL }
358         },
359         {&hf_distcc_argc,
360          {"ARGC", "distcc.argc",
361           FT_UINT32, BASE_DEC, NULL, 0x0, "Number of arguments", HFILL }
362         },
363         {&hf_distcc_argv,
364          {"ARGV", "distcc.argv",
365           FT_STRING, BASE_NONE, NULL, 0x0, "ARGV argument", HFILL }
366         },
367         {&hf_distcc_doti_source,
368          {"Source", "distcc.doti_source",
369           FT_STRING, BASE_NONE, NULL, 0x0, "DOTI Preprocessed Source File (.i)", HFILL }
370         },
371         {&hf_distcc_stat,
372          {"Status", "distcc.status",
373           FT_UINT32, BASE_DEC, NULL, 0x0, "Unix wait status for command completion", HFILL }
374         },
375         {&hf_distcc_serr,
376          {"SERR", "distcc.serr",
377           FT_STRING, BASE_NONE, NULL, 0x0, "STDERR output", HFILL }
378         },
379         {&hf_distcc_sout,
380          {"SOUT", "distcc.sout",
381           FT_STRING, BASE_NONE, NULL, 0x0, "STDOUT output", HFILL }
382         },
383         {&hf_distcc_doto_object,
384          {"Object", "distcc.doto_object",
385           FT_BYTES, BASE_HEX, NULL, 0x0, "DOTO Compiled object file (.o)", HFILL }
386         }
387
388         };
389
390         static gint *ett[] = {
391                 &ett_distcc,
392         };
393
394         module_t *distcc_module;
395
396         proto_distcc = proto_register_protocol("Distcc Distributed Compiler",
397                                            "DISTCC", "distcc");
398         proto_register_field_array(proto_distcc, hf, array_length(hf));
399         proto_register_subtree_array(ett, array_length(ett));
400
401         distcc_module = prefs_register_protocol(proto_distcc, NULL);
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 void
413 proto_reg_handoff_distcc(void)
414 {
415         data_handle = find_dissector("data");
416         distcc_handle = create_dissector_handle(dissect_distcc, proto_distcc);
417         dissector_add("tcp.port", glb_distcc_tcp_port, distcc_handle);
418 }