Coverage Report

Created: 2026-11-12 07:01

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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, &parameter))
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
 */