/src/wireshark/epan/dissectors/packet-distcc.c
Line | Count | Source |
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 | | * Wireshark - Network traffic analyzer |
7 | | * By Gerald Combs <gerald@wireshark.org> |
8 | | * Copyright 1998 Gerald Combs |
9 | | * |
10 | | * SPDX-License-Identifier: GPL-2.0-or-later |
11 | | */ |
12 | | |
13 | | /* |
14 | | * This dissector supports version 1 of the DISTCC protocol: |
15 | | * |
16 | | * https://github.com/distcc/distcc/blob/master/doc/protocol-1.txt |
17 | | */ |
18 | | |
19 | | #include "config.h" |
20 | | |
21 | | #include <epan/packet.h> |
22 | | #include <epan/expert.h> |
23 | | #include <epan/prefs.h> |
24 | | |
25 | | #include <wsutil/strtoi.h> |
26 | | |
27 | | static int proto_distcc; |
28 | | static int hf_distcc_version; |
29 | | static int hf_distcc_argc; |
30 | | static int hf_distcc_argv; |
31 | | static int hf_distcc_doti_source; |
32 | | static int hf_distcc_stat; |
33 | | static int hf_distcc_serr; |
34 | | static int hf_distcc_sout; |
35 | | static int hf_distcc_doto_object; |
36 | | |
37 | | |
38 | | static int ett_distcc; |
39 | | |
40 | | static expert_field ei_distcc_short_pdu; |
41 | | |
42 | | |
43 | | static bool distcc_desegment = true; |
44 | | |
45 | | |
46 | 16 | #define TCP_PORT_DISTCC 3632 |
47 | | |
48 | | void proto_register_distcc(void); |
49 | | extern void proto_reg_handoff_distcc(void); |
50 | | |
51 | | static dissector_handle_t distcc_handle; |
52 | | |
53 | | /* |
54 | | * Check that the value of a token, "parameter" octets at "offset", is all |
55 | | * there. If it is not and TCP can give us more data, ask for the rest of |
56 | | * the PDU, starting at the token, and stop; otherwise dissect what there |
57 | | * is (the caller marks the item as short). |
58 | | */ |
59 | | #define CHECK_PDU_LEN(x) \ |
60 | 0 | if(parameter>(unsigned)tvb_captured_length_remaining(tvb, offset)){\ |
61 | 0 | if(distcc_desegment && pinfo->can_desegment &&\ |
62 | 0 | tvb_captured_length_remaining(tvb, offset)==tvb_reported_length_remaining(tvb, offset)){\ |
63 | 0 | pinfo->desegment_offset=offset-12;\ |
64 | 0 | pinfo->desegment_len=parameter-(unsigned)tvb_captured_length_remaining(tvb, offset);\ |
65 | 0 | return tvb_captured_length(tvb);\ |
66 | 0 | }\ |
67 | 0 | len=tvb_captured_length_remaining(tvb, offset);\ |
68 | 0 | col_append_str(pinfo->cinfo, COL_INFO, "[Short " x " PDU] ");\ |
69 | 0 | } |
70 | | |
71 | | static int |
72 | | dissect_distcc_dist(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset, uint32_t parameter) |
73 | 0 | { |
74 | 0 | proto_tree_add_uint_format(tree, hf_distcc_version, tvb, offset-12, 12, parameter, "DIST: %u", parameter); |
75 | |
|
76 | 0 | col_append_fstr(pinfo->cinfo, COL_INFO, "DIST:%u ", parameter); |
77 | |
|
78 | 0 | return offset; |
79 | 0 | } |
80 | | |
81 | | static int |
82 | | dissect_distcc_done(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset, uint32_t parameter) |
83 | 0 | { |
84 | 0 | proto_tree_add_uint_format(tree, hf_distcc_version, tvb, offset-12, 12, parameter, "DONE: %u", parameter); |
85 | |
|
86 | 0 | col_append_fstr(pinfo->cinfo, COL_INFO, "DONE:%u ", parameter); |
87 | |
|
88 | 0 | return offset; |
89 | 0 | } |
90 | | |
91 | | static int |
92 | | dissect_distcc_stat(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset, uint32_t parameter) |
93 | 0 | { |
94 | 0 | proto_tree_add_uint_format(tree, hf_distcc_stat, tvb, offset-12, 12, parameter, "STAT: %u", parameter); |
95 | |
|
96 | 0 | col_append_fstr(pinfo->cinfo, COL_INFO, "STAT:%u ", parameter); |
97 | |
|
98 | 0 | return offset; |
99 | 0 | } |
100 | | |
101 | | static int |
102 | | dissect_distcc_argc(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset, uint32_t parameter) |
103 | 0 | { |
104 | 0 | proto_tree_add_uint(tree, hf_distcc_argc, tvb, offset-12, 12, parameter); |
105 | |
|
106 | 0 | col_append_fstr(pinfo->cinfo, COL_INFO, "ARGC:%u ", parameter); |
107 | |
|
108 | 0 | return offset; |
109 | 0 | } |
110 | | |
111 | | static int |
112 | | dissect_distcc_argv(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset, unsigned parameter) |
113 | 0 | { |
114 | 0 | int len=(int)parameter; |
115 | 0 | char *argv; |
116 | 0 | proto_item* ti; |
117 | | |
118 | | /* see if we need to desegment the PDU */ |
119 | 0 | CHECK_PDU_LEN("ARGV"); |
120 | | |
121 | | /* |
122 | | * XXX - we have no idea what encoding is being used, other than |
123 | | * it being some flavor of "extended ASCII"; these days, it's |
124 | | * *probably* UTF-8, but it could conceivably be something else. |
125 | | */ |
126 | 0 | ti = proto_tree_add_item_ret_display_string(tree, hf_distcc_argv, tvb, offset, len, ENC_ASCII|ENC_NA, pinfo->pool, &argv); |
127 | |
|
128 | 0 | col_append_fstr(pinfo->cinfo, COL_INFO, "%s ", argv); |
129 | |
|
130 | 0 | if(len!=(int)parameter){ |
131 | 0 | expert_add_info_format(pinfo, ti, &ei_distcc_short_pdu, "[Short ARGV PDU]"); |
132 | 0 | } |
133 | 0 | return offset+len; |
134 | 0 | } |
135 | | |
136 | | static int |
137 | | dissect_distcc_serr(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset, unsigned parameter) |
138 | 0 | { |
139 | 0 | int len=(int)parameter; |
140 | 0 | char *serr; |
141 | 0 | proto_item* ti; |
142 | | |
143 | | /* see if we need to desegment the PDU */ |
144 | 0 | CHECK_PDU_LEN("SERR"); |
145 | | |
146 | | /* |
147 | | * XXX - we have no idea what encoding is being used, other than |
148 | | * it being some flavor of "extended ASCII"; these days, it's |
149 | | * *probably* UTF-8, but it could conceivably be something else. |
150 | | */ |
151 | 0 | ti = proto_tree_add_item_ret_display_string(tree, hf_distcc_serr, tvb, offset, len, ENC_ASCII|ENC_NA, pinfo->pool, &serr); |
152 | |
|
153 | 0 | col_append_fstr(pinfo->cinfo, COL_INFO, "SERR:%s ", serr); |
154 | |
|
155 | 0 | if(len!=(int)parameter){ |
156 | 0 | expert_add_info_format(pinfo, ti, &ei_distcc_short_pdu, "[Short SERR PDU]"); |
157 | 0 | } |
158 | 0 | return offset+len; |
159 | 0 | } |
160 | | |
161 | | static int |
162 | | dissect_distcc_sout(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset, unsigned parameter) |
163 | 0 | { |
164 | 0 | int len=(int)parameter; |
165 | 0 | char *sout; |
166 | 0 | proto_item* ti; |
167 | | |
168 | | /* see if we need to desegment the PDU */ |
169 | 0 | CHECK_PDU_LEN("SOUT"); |
170 | | |
171 | | /* |
172 | | * XXX - we have no idea what encoding is being used, other than |
173 | | * it being some flavor of "extended ASCII"; these days, it's |
174 | | * *probably* UTF-8, but it could conceivably be something else. |
175 | | */ |
176 | 0 | ti = proto_tree_add_item_ret_display_string(tree, hf_distcc_sout, tvb, offset, len, ENC_ASCII|ENC_NA, pinfo->pool, &sout); |
177 | |
|
178 | 0 | col_append_fstr(pinfo->cinfo, COL_INFO, "SOUT:%s ", sout); |
179 | |
|
180 | 0 | if(len!=(int)parameter){ |
181 | 0 | expert_add_info_format(pinfo, ti, &ei_distcc_short_pdu, "[Short SOUT PDU]"); |
182 | 0 | } |
183 | 0 | return offset+len; |
184 | 0 | } |
185 | | |
186 | | |
187 | | static int |
188 | | dissect_distcc_doti(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset, unsigned parameter) |
189 | 0 | { |
190 | 0 | int len=(int)parameter; |
191 | 0 | proto_item* ti; |
192 | | |
193 | | /* see if we need to desegment the PDU */ |
194 | 0 | CHECK_PDU_LEN("DOTI"); |
195 | |
|
196 | 0 | col_append_str(pinfo->cinfo, COL_INFO, "DOTI source "); |
197 | |
|
198 | 0 | ti = proto_tree_add_item(tree, hf_distcc_doti_source, tvb, offset, len, ENC_ASCII); |
199 | |
|
200 | 0 | if(len!=(int)parameter){ |
201 | 0 | expert_add_info_format(pinfo, ti, &ei_distcc_short_pdu, "[Short DOTI PDU]"); |
202 | 0 | } |
203 | 0 | return offset+len; |
204 | 0 | } |
205 | | |
206 | | static int |
207 | | dissect_distcc_doto(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset, unsigned parameter) |
208 | 0 | { |
209 | 0 | int len=(int)parameter; |
210 | 0 | proto_item* ti; |
211 | | |
212 | | /* see if we need to desegment the PDU */ |
213 | 0 | CHECK_PDU_LEN("DOTO"); |
214 | |
|
215 | 0 | col_append_str(pinfo->cinfo, COL_INFO, "DOTO object "); |
216 | |
|
217 | 0 | ti = proto_tree_add_item(tree, hf_distcc_doto_object, tvb, offset, len, ENC_NA); |
218 | |
|
219 | 0 | if(len!=(int)parameter){ |
220 | 0 | expert_add_info_format(pinfo, ti, &ei_distcc_short_pdu, "[Short DOTO PDU]"); |
221 | 0 | } |
222 | 0 | return offset+len; |
223 | 0 | } |
224 | | |
225 | | |
226 | | |
227 | | /* Packet dissection routine called by tcp (& udp) when port 3632 detected */ |
228 | | static int |
229 | | dissect_distcc(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree, void* data _U_) |
230 | 0 | { |
231 | 0 | int offset=0; |
232 | 0 | proto_tree *tree=NULL; |
233 | 0 | proto_item *item=NULL; |
234 | 0 | char buf[13]; |
235 | 0 | uint32_t parameter; |
236 | | |
237 | |
|
238 | 0 | col_set_str(pinfo->cinfo, COL_PROTOCOL, "DISTCC"); |
239 | |
|
240 | 0 | col_clear(pinfo->cinfo, COL_INFO); |
241 | |
|
242 | 0 | if (parent_tree) { |
243 | 0 | item = proto_tree_add_item(parent_tree, proto_distcc, tvb, offset, |
244 | 0 | -1, ENC_NA); |
245 | 0 | tree = proto_item_add_subtree(item, ett_distcc); |
246 | 0 | } |
247 | |
|
248 | 0 | while (tvb_captured_length_remaining(tvb, offset) > 0) { |
249 | 0 | if (tvb_captured_length_remaining(tvb, offset) < 12) { |
250 | | /* the token is split over segments */ |
251 | 0 | if (distcc_desegment && pinfo->can_desegment && |
252 | 0 | tvb_captured_length_remaining(tvb, offset) == tvb_reported_length_remaining(tvb, offset)) { |
253 | 0 | pinfo->desegment_offset = offset; |
254 | 0 | pinfo->desegment_len = 12 - tvb_captured_length_remaining(tvb, offset); |
255 | 0 | return tvb_captured_length(tvb); |
256 | 0 | } |
257 | 0 | proto_tree_add_expert_format_remaining(tree, pinfo, &ei_distcc_short_pdu, tvb, offset, "[Short token]"); |
258 | 0 | break; |
259 | 0 | } |
260 | | |
261 | | /* read the raw token (4 bytes) and parameter (8 bytes) */ |
262 | 0 | tvb_memcpy(tvb, buf, offset, 12); |
263 | 0 | buf[12] = '\0'; |
264 | 0 | offset+=12; |
265 | | |
266 | | /* get the parameter value */ |
267 | 0 | if (!ws_hexstrtou32(buf + 4, NULL, ¶meter)) |
268 | 0 | return offset; |
269 | | |
270 | 0 | if(!strncmp(buf, "DIST", 4)){ |
271 | 0 | offset=dissect_distcc_dist(tvb, pinfo, tree, offset, parameter); |
272 | 0 | } else if(!strncmp(buf, "ARGC", 4)){ |
273 | 0 | offset=dissect_distcc_argc(tvb, pinfo, tree, offset, parameter); |
274 | 0 | } else if(!strncmp(buf, "ARGV", 4)){ |
275 | 0 | offset=dissect_distcc_argv(tvb, pinfo, tree, offset, parameter); |
276 | 0 | } else if(!strncmp(buf, "DOTI", 4)){ |
277 | 0 | offset=dissect_distcc_doti(tvb, pinfo, tree, offset, parameter); |
278 | 0 | } else if(!strncmp(buf, "DONE", 4)){ |
279 | 0 | offset=dissect_distcc_done(tvb, pinfo, tree, offset, parameter); |
280 | 0 | } else if(!strncmp(buf, "STAT", 4)){ |
281 | 0 | offset=dissect_distcc_stat(tvb, pinfo, tree, offset, parameter); |
282 | 0 | } else if(!strncmp(buf, "SERR", 4)){ |
283 | 0 | offset=dissect_distcc_serr(tvb, pinfo, tree, offset, parameter); |
284 | 0 | } else if(!strncmp(buf, "SOUT", 4)){ |
285 | 0 | offset=dissect_distcc_sout(tvb, pinfo, tree, offset, parameter); |
286 | 0 | } else if(!strncmp(buf, "DOTO", 4)){ |
287 | 0 | offset=dissect_distcc_doto(tvb, pinfo, tree, offset, parameter); |
288 | 0 | } else { |
289 | 0 | call_data_dissector(tvb, pinfo, tree); |
290 | 0 | break; |
291 | 0 | } |
292 | 0 | } |
293 | | |
294 | 0 | return tvb_captured_length(tvb); |
295 | 0 | } |
296 | | |
297 | | /* Register protocol with Wireshark. */ |
298 | | void |
299 | | proto_register_distcc(void) |
300 | 16 | { |
301 | 16 | static hf_register_info hf[] = { |
302 | 16 | {&hf_distcc_version, |
303 | 16 | {"DISTCC Version", "distcc.version", |
304 | 16 | FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL } |
305 | 16 | }, |
306 | 16 | {&hf_distcc_argc, |
307 | 16 | {"ARGC", "distcc.argc", |
308 | 16 | FT_UINT32, BASE_DEC, NULL, 0x0, "Number of arguments", HFILL } |
309 | 16 | }, |
310 | 16 | {&hf_distcc_argv, |
311 | 16 | {"ARGV", "distcc.argv", |
312 | 16 | FT_STRING, BASE_NONE, NULL, 0x0, "ARGV argument", HFILL } |
313 | 16 | }, |
314 | 16 | {&hf_distcc_doti_source, |
315 | 16 | {"Source", "distcc.doti_source", |
316 | 16 | FT_STRING, BASE_NONE, NULL, 0x0, "DOTI Preprocessed Source File (.i)", HFILL } |
317 | 16 | }, |
318 | 16 | {&hf_distcc_stat, |
319 | 16 | {"Status", "distcc.status", |
320 | 16 | FT_UINT32, BASE_DEC, NULL, 0x0, "Unix wait status for command completion", HFILL } |
321 | 16 | }, |
322 | 16 | {&hf_distcc_serr, |
323 | 16 | {"SERR", "distcc.serr", |
324 | 16 | FT_STRING, BASE_NONE, NULL, 0x0, "STDERR output", HFILL } |
325 | 16 | }, |
326 | 16 | {&hf_distcc_sout, |
327 | 16 | {"SOUT", "distcc.sout", |
328 | 16 | FT_STRING, BASE_NONE, NULL, 0x0, "STDOUT output", HFILL } |
329 | 16 | }, |
330 | 16 | {&hf_distcc_doto_object, |
331 | 16 | {"Object", "distcc.doto_object", |
332 | 16 | FT_BYTES, BASE_NONE, NULL, 0x0, "DOTO Compiled object file (.o)", HFILL } |
333 | 16 | } |
334 | | |
335 | 16 | }; |
336 | | |
337 | 16 | static int *ett[] = { |
338 | 16 | &ett_distcc, |
339 | 16 | }; |
340 | | |
341 | 16 | static ei_register_info ei[] = { |
342 | 16 | { &ei_distcc_short_pdu, { "distcc.short_pdu", PI_MALFORMED, PI_ERROR, "Short PDU", EXPFILL }}, |
343 | 16 | }; |
344 | | |
345 | 16 | module_t *distcc_module; |
346 | 16 | expert_module_t* expert_distcc; |
347 | | |
348 | 16 | proto_distcc = proto_register_protocol("Distcc Distributed Compiler", "DISTCC", "distcc"); |
349 | | |
350 | 16 | proto_register_field_array(proto_distcc, hf, array_length(hf)); |
351 | 16 | proto_register_subtree_array(ett, array_length(ett)); |
352 | 16 | expert_distcc = expert_register_protocol(proto_distcc); |
353 | 16 | expert_register_field_array(expert_distcc, ei, array_length(ei)); |
354 | | |
355 | 16 | distcc_module = prefs_register_protocol(proto_distcc, NULL); |
356 | | |
357 | 16 | prefs_register_bool_preference(distcc_module, "desegment_distcc_over_tcp", |
358 | 16 | "Reassemble DISTCC-over-TCP messages spanning multiple TCP segments", |
359 | 16 | "Whether the DISTCC dissector should reassemble messages spanning multiple TCP segments." |
360 | 16 | " To use this option, you must also enable \"Allow subdissectors to reassemble TCP streams\" in the TCP protocol settings.", |
361 | 16 | &distcc_desegment); |
362 | | |
363 | 16 | distcc_handle = register_dissector("distcc", dissect_distcc, proto_distcc); |
364 | 16 | } |
365 | | |
366 | | void |
367 | | proto_reg_handoff_distcc(void) |
368 | 16 | { |
369 | 16 | dissector_add_uint_with_preference("tcp.port", TCP_PORT_DISTCC, distcc_handle); |
370 | 16 | } |
371 | | |
372 | | /* |
373 | | * Editor modelines - https://www.wireshark.org/tools/modelines.html |
374 | | * |
375 | | * Local variables: |
376 | | * c-basic-offset: 4 |
377 | | * tab-width: 8 |
378 | | * indent-tabs-mode: nil |
379 | | * End: |
380 | | * |
381 | | * vi: set shiftwidth=4 tabstop=8 expandtab: |
382 | | * :indentSize=4:tabSize=8:noTabs=true: |
383 | | */ |