Coverage Report

Created: 2025-08-04 07:15

/src/wireshark/epan/dissectors/packet-bzr.c
Line
Count
Source (jump to first uncovered line)
1
/* packet-bzr.c
2
 * Routines for Bazaar packet dissection
3
 * Copyright 2011,2013 Jelmer Vernooij <jelmer@samba.org>
4
 *
5
 * http://doc.bazaar.canonical.com/developers/network-protocol.html
6
 *
7
 * Wireshark - Network traffic analyzer
8
 * By Gerald Combs <gerald@wireshark.org>
9
 * Copyright 1998 Gerald Combs
10
 *
11
 * Copied from packet-pop.c
12
 *
13
 * SPDX-License-Identifier: GPL-2.0-or-later
14
 */
15
16
#include "config.h"
17
18
#include <epan/packet.h>
19
#include <epan/prefs.h>
20
21
void proto_register_bzr(void);
22
void proto_reg_handoff_bzr(void);
23
24
static int proto_bzr;
25
26
static int ett_bzr;
27
static int ett_prefixed_bencode;
28
static int ett_prefixed_bytes;
29
30
static int hf_bzr_prefixed_bencode;
31
static int hf_bzr_prefixed_bencode_len;
32
static int hf_bzr_bytes;
33
static int hf_bzr_bytes_data;
34
static int hf_bzr_bytes_length;
35
static int hf_bzr_result;
36
static int hf_bzr_packet_protocol_version;
37
static int hf_bzr_packet_kind;
38
39
static dissector_handle_t bencode_handle;
40
static dissector_handle_t bzr_handle;
41
42
#define REQUEST_VERSION_TWO   "bzr request 2\n"
43
#define RESPONSE_VERSION_TWO  "bzr response 2\n"
44
#define MESSAGE_VERSION_THREE "bzr message 3 (bzr 1.6)\n"
45
46
14
#define TCP_PORT_BZR   4155
47
48
static const value_string message_part_kind[] = {
49
    {'s', "Structure"},
50
    {'b', "Bytes"},
51
    {'o', "Single byte"},
52
    {'e', "End"},
53
    {0, NULL}
54
};
55
56
static const value_string message_results[] = {
57
    {'S', "Success"},
58
    {'E', "Error"},
59
    {0, NULL}
60
};
61
62
/* desegmentation of Bazaar over TCP */
63
static bool bzr_desegment = true;
64
65
static unsigned get_bzr_prefixed_len(tvbuff_t *tvb, int offset)
66
27
{
67
27
    unsigned header_len;
68
27
    header_len = tvb_get_ntohl(tvb, offset);
69
27
    return 4 + header_len;
70
27
}
71
72
static unsigned
73
get_bzr_pdu_len(packet_info *pinfo _U_, tvbuff_t *tvb, int offset)
74
25
{
75
25
    int    next_offset;
76
25
    int    len = 0, current_len;
77
25
    int    protocol_version_len;
78
25
    uint8_t cmd = 0;
79
80
    /* Protocol version */
81
25
    protocol_version_len = tvb_find_line_end(tvb, offset, -1, &next_offset,
82
25
                                             true);
83
25
    if (protocol_version_len == -1) /* End of the packet not seen yet */
84
4
        return -1;
85
86
21
    len += protocol_version_len + 1;
87
88
    /* Headers */
89
21
    current_len = len;
90
21
    len += get_bzr_prefixed_len(tvb, next_offset);
91
21
    if (current_len > len) /* Make sure we're not going backwards */
92
1
        return -1;
93
94
1.59k
    while (tvb_reported_length_remaining(tvb, offset + len) > 0) {
95
1.58k
        cmd = tvb_get_uint8(tvb, offset + len);
96
1.58k
        len += 1;
97
98
1.58k
        switch (cmd) {
99
3
        case 's':
100
6
        case 'b':
101
6
            current_len = len;
102
6
            len += get_bzr_prefixed_len(tvb, offset + len);
103
6
            if (current_len > len) /* Make sure we're not going backwards */
104
3
                return -1;
105
3
            break;
106
74
        case 'o':
107
74
            len += 1;
108
74
            break;
109
4
        case 'e':
110
4
            return len;
111
1.58k
        }
112
1.58k
    }
113
114
13
    return -1;
115
20
}
116
117
static int
118
dissect_prefixed_bencode(tvbuff_t *tvb, int offset, packet_info *pinfo,
119
                         proto_tree *tree)
120
24
{
121
24
    uint32_t    plen;
122
24
    proto_tree *prefixed_bencode_tree;
123
24
    proto_item *ti;
124
24
    tvbuff_t *subtvb;
125
126
24
    plen = tvb_get_ntohl(tvb, offset);
127
128
24
    ti = proto_tree_add_item(tree, hf_bzr_prefixed_bencode, tvb, offset, -1,
129
24
                             ENC_NA);
130
24
    prefixed_bencode_tree = proto_item_add_subtree(ti, ett_prefixed_bencode);
131
132
24
    proto_tree_add_item(prefixed_bencode_tree, hf_bzr_prefixed_bencode_len,
133
24
                        tvb, offset, 4, ENC_BIG_ENDIAN);
134
135
24
    subtvb = tvb_new_subset_length(tvb, offset+4, plen);
136
24
    call_dissector(bencode_handle, subtvb, pinfo, prefixed_bencode_tree);
137
138
24
    proto_item_set_len(ti, 4 + plen);
139
140
24
    return 4 + plen;
141
24
}
142
143
static int
144
dissect_prefixed_bytes(tvbuff_t *tvb, int offset, packet_info *pinfo _U_,
145
                       proto_tree *tree)
146
3
{
147
3
    uint32_t    plen;
148
3
    proto_tree *prefixed_bytes_tree;
149
3
    proto_item *ti;
150
151
3
    plen = tvb_get_ntohl(tvb, offset);
152
153
3
    ti = proto_tree_add_item(tree, hf_bzr_bytes, tvb, offset, -1, ENC_NA);
154
3
    prefixed_bytes_tree = proto_item_add_subtree(ti, ett_prefixed_bytes);
155
156
3
    proto_tree_add_item(prefixed_bytes_tree, hf_bzr_bytes_length,
157
3
                        tvb, offset, 4, ENC_BIG_ENDIAN);
158
159
3
    proto_tree_add_item(prefixed_bytes_tree, hf_bzr_bytes_data,
160
3
                        tvb, offset+4, plen, ENC_NA);
161
162
3
    proto_item_set_len(ti, 4 + plen);
163
164
3
    return 4 + plen;
165
3
}
166
167
static int
168
dissect_body(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree)
169
17
{
170
17
    uint8_t cmd = 0;
171
172
1.59k
    while (tvb_reported_length_remaining(tvb, offset) > 0) {
173
1.58k
        cmd = tvb_get_uint8(tvb, offset);
174
1.58k
        proto_tree_add_item(tree, hf_bzr_packet_kind, tvb, offset, 1, ENC_ASCII);
175
1.58k
        offset += 1;
176
177
1.58k
        switch (cmd) {
178
3
        case 's':
179
3
            offset += dissect_prefixed_bencode(tvb, offset, pinfo, tree);
180
3
            break;
181
3
        case 'b':
182
3
            offset += dissect_prefixed_bytes(tvb, offset, pinfo, tree);
183
3
            break;
184
74
        case 'o':
185
74
            proto_tree_add_item(tree, hf_bzr_result, tvb, offset, 1,
186
74
                                ENC_ASCII);
187
74
            offset += 1;
188
74
            break;
189
4
        case 'e':
190
4
            break;
191
1.58k
        }
192
1.58k
    }
193
194
12
    return offset;
195
17
}
196
197
static void
198
dissect_bzr_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
199
25
{
200
25
    proto_tree *bzr_tree;
201
25
    proto_item *ti;
202
25
    int         offset = 0;
203
25
    int         protocol_version_len;
204
205
25
    ti = proto_tree_add_item(tree, proto_bzr, tvb, offset, -1, ENC_NA);
206
25
    bzr_tree = proto_item_add_subtree(ti, ett_bzr);
207
208
25
    protocol_version_len = tvb_find_line_end(tvb, offset, -1, &offset, true);
209
25
    if (protocol_version_len == -1) /* Invalid packet */
210
4
        return;
211
212
21
    if (bzr_tree)
213
21
    {
214
21
        proto_tree_add_item(bzr_tree, hf_bzr_packet_protocol_version, tvb, 0,
215
21
                            protocol_version_len+1, ENC_ASCII);
216
21
    }
217
218
21
    offset += dissect_prefixed_bencode(tvb, offset, pinfo, bzr_tree);
219
21
    /*offset +=*/ dissect_body(tvb, offset, pinfo, bzr_tree);
220
21
}
221
222
static int
223
dissect_bzr(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_)
224
21
{
225
21
    int       offset = 0, pdu_len;
226
21
    tvbuff_t *next_tvb;
227
228
21
    col_set_str(pinfo->cinfo, COL_PROTOCOL, "BZR");
229
230
21
    col_set_str(pinfo->cinfo, COL_INFO, "Bazaar Smart Protocol");
231
232
46
    while (tvb_reported_length_remaining(tvb, offset) > 0) {
233
25
        pdu_len = get_bzr_pdu_len(pinfo, tvb, offset);
234
25
        if (pdu_len == -1) {
235
21
            if (pinfo->can_desegment && bzr_desegment) {
236
0
                pinfo->desegment_offset = offset;
237
0
                pinfo->desegment_len = DESEGMENT_ONE_MORE_SEGMENT;
238
0
                return tvb_captured_length(tvb);
239
21
            } else {
240
21
                pdu_len = tvb_reported_length_remaining(tvb, offset);
241
21
            }
242
21
        }
243
25
        next_tvb = tvb_new_subset_length(tvb, offset, pdu_len);
244
25
        dissect_bzr_pdu(next_tvb, pinfo, tree);
245
25
        offset += pdu_len;
246
25
    }
247
248
21
    return tvb_captured_length(tvb);
249
21
}
250
251
void
252
proto_register_bzr(void)
253
14
{
254
14
    static hf_register_info hf[] = {
255
14
        { &hf_bzr_packet_kind,
256
14
          { "Packet kind", "bzr.kind", FT_CHAR, BASE_HEX,
257
14
            VALS(message_part_kind), 0x0, NULL, HFILL },
258
14
        },
259
14
        { &hf_bzr_packet_protocol_version,
260
14
          { "Protocol version", "bzr.protocol_version", FT_STRING, BASE_NONE,
261
14
            NULL, 0x0, NULL, HFILL },
262
14
        },
263
14
        { &hf_bzr_prefixed_bencode,
264
14
          { "Bencode packet", "bzr.bencode", FT_NONE, BASE_NONE, NULL, 0x0,
265
14
            "Serialized structure of integers, dictionaries, strings and "
266
14
            "lists.", HFILL },
267
14
        },
268
14
        { &hf_bzr_prefixed_bencode_len,
269
14
          { "Bencode packet length", "bzr.bencode.length", FT_UINT32,
270
14
            BASE_HEX, NULL, 0x0, NULL, HFILL },
271
14
        },
272
14
        { &hf_bzr_bytes,
273
14
          { "Prefixed bytes", "bzr.bytes", FT_NONE, BASE_NONE, NULL, 0x0,
274
14
            "Bytes field with prefixed 32-bit length", HFILL },
275
14
        },
276
14
        { &hf_bzr_bytes_data,
277
14
          { "Prefixed bytes data", "bzr.bytes.data", FT_BYTES, BASE_NONE,
278
14
            NULL, 0x0, NULL, HFILL },
279
14
        },
280
14
        { &hf_bzr_bytes_length,
281
14
          { "Prefixed bytes length", "bzr.bytes.length", FT_UINT32, BASE_HEX,
282
14
            NULL, 0x0, NULL, HFILL },
283
14
        },
284
14
        { &hf_bzr_result,
285
14
          { "Result", "bzr.result", FT_CHAR, BASE_HEX,
286
14
            VALS(message_results), 0x0,
287
14
            "Command result (success or failure with error message)", HFILL
288
14
          },
289
14
        },
290
14
    };
291
292
14
    static int *ett[] = {
293
14
        &ett_bzr,
294
14
        &ett_prefixed_bencode,
295
14
        &ett_prefixed_bytes,
296
14
    };
297
298
14
    module_t *bzr_module;
299
14
    proto_bzr = proto_register_protocol("Bazaar Smart Protocol", "Bazaar", "bzr");
300
14
    bzr_handle = register_dissector("bzr", dissect_bzr, proto_bzr);
301
14
    proto_register_field_array(proto_bzr, hf, array_length(hf));
302
14
    proto_register_subtree_array(ett, array_length(ett));
303
304
14
    bzr_module = prefs_register_protocol(proto_bzr, NULL);
305
306
14
    prefs_register_bool_preference(bzr_module, "desegment",
307
14
                                   "Reassemble Bazaar messages spanning multiple TCP segments",
308
14
                                   "Whether the Bazaar dissector should reassemble messages spanning multiple TCP segments."
309
14
                                   " To use this option, you must also enable \"Allow subdissectors to reassemble TCP streams\""
310
14
                                   " in the TCP protocol settings.",
311
14
                                   &bzr_desegment);
312
14
}
313
314
void
315
proto_reg_handoff_bzr(void)
316
14
{
317
14
    bencode_handle = find_dissector_add_dependency("bencode", proto_bzr);
318
319
14
    dissector_add_uint_with_preference("tcp.port", TCP_PORT_BZR, bzr_handle);
320
14
}
321
322
/*
323
 * Editor modelines  -  https://www.wireshark.org/tools/modelines.html
324
 *
325
 * Local variables:
326
 * c-basic-offset: 4
327
 * tab-width: 8
328
 * indent-tabs-mode: nil
329
 * End:
330
 *
331
 * vi: set shiftwidth=4 tabstop=8 expandtab:
332
 * :indentSize=4:tabSize=8:noTabs=true:
333
 */