Coverage Report

Created: 2026-07-12 07:10

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/wireshark/epan/dissectors/packet-bzr.c
Line
Count
Source
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
15
#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, unsigned offset)
66
31
{
67
31
    unsigned header_len;
68
31
    header_len = tvb_get_ntohl(tvb, offset);
69
31
    return 4 + header_len;
70
31
}
71
72
static bool
73
get_bzr_pdu_len(packet_info *pinfo _U_, tvbuff_t *parent_tvb, unsigned offset, unsigned *pdu_len)
74
32
{
75
32
    unsigned    next_offset;
76
32
    unsigned    len = 0, current_len;
77
32
    unsigned    protocol_version_len;
78
32
    uint8_t     cmd = 0;
79
80
32
    tvbuff_t   *tvb = tvb_new_subset_remaining(parent_tvb, offset);
81
82
    /* Protocol version */
83
32
    if (!tvb_find_line_end_remaining(tvb, 0, &protocol_version_len, &next_offset)) /* End of the packet not seen yet */
84
2
        return false;
85
86
30
    len += protocol_version_len + 1;
87
88
    /* Headers */
89
30
    current_len = len;
90
30
    len += get_bzr_prefixed_len(tvb, next_offset);
91
30
    if (current_len >= len) /* Make sure we're advancing */
92
0
        return false;
93
94
2.00k
    while (tvb_reported_length_remaining(tvb, len) > 0) {
95
1.98k
        cmd = tvb_get_uint8(tvb, len);
96
1.98k
        len += 1;
97
98
1.98k
        switch (cmd) {
99
1
        case 's':
100
1
        case 'b':
101
1
            current_len = len;
102
1
            len += get_bzr_prefixed_len(tvb, len);
103
1
            if (current_len >= len) /* Make sure we're advancing */
104
0
                return false;
105
1
            break;
106
44
        case 'o':
107
44
            len += 1;
108
44
            break;
109
10
        case 'e':
110
10
            *pdu_len = len;
111
10
            return true;
112
1.98k
        }
113
1.98k
    }
114
115
20
    return false;
116
30
}
117
118
static int
119
dissect_prefixed_bencode(tvbuff_t *tvb, unsigned offset, packet_info *pinfo, proto_tree *tree)
120
31
{
121
31
    uint32_t    plen;
122
31
    proto_tree *prefixed_bencode_tree;
123
31
    proto_item *ti;
124
31
    tvbuff_t *subtvb;
125
126
31
    plen = tvb_get_ntohl(tvb, offset);
127
128
31
    ti = proto_tree_add_item(tree, hf_bzr_prefixed_bencode, tvb, offset, -1,
129
31
                             ENC_NA);
130
31
    prefixed_bencode_tree = proto_item_add_subtree(ti, ett_prefixed_bencode);
131
132
31
    proto_tree_add_item(prefixed_bencode_tree, hf_bzr_prefixed_bencode_len,
133
31
                        tvb, offset, 4, ENC_BIG_ENDIAN);
134
135
31
    subtvb = tvb_new_subset_length(tvb, offset+4, plen);
136
31
    call_dissector(bencode_handle, subtvb, pinfo, prefixed_bencode_tree);
137
138
31
    proto_item_set_len(ti, 4 + plen);
139
140
31
    return 4 + plen;
141
31
}
142
143
static int
144
dissect_prefixed_bytes(tvbuff_t *tvb, unsigned offset, packet_info *pinfo _U_, proto_tree *tree)
145
0
{
146
0
    uint32_t    plen;
147
0
    proto_tree *prefixed_bytes_tree;
148
0
    proto_item *ti;
149
150
0
    plen = tvb_get_ntohl(tvb, offset);
151
152
0
    ti = proto_tree_add_item(tree, hf_bzr_bytes, tvb, offset, -1, ENC_NA);
153
0
    prefixed_bytes_tree = proto_item_add_subtree(ti, ett_prefixed_bytes);
154
155
0
    proto_tree_add_item(prefixed_bytes_tree, hf_bzr_bytes_length,
156
0
                        tvb, offset, 4, ENC_BIG_ENDIAN);
157
158
0
    proto_tree_add_item(prefixed_bytes_tree, hf_bzr_bytes_data,
159
0
                        tvb, offset+4, plen, ENC_NA);
160
161
0
    proto_item_set_len(ti, 4 + plen);
162
163
0
    return 4 + plen;
164
0
}
165
166
static int
167
dissect_body(tvbuff_t *tvb, unsigned offset, packet_info *pinfo, proto_tree *tree)
168
27
{
169
27
    uint8_t cmd = 0;
170
171
2.01k
    while (tvb_reported_length_remaining(tvb, offset) > 0) {
172
1.98k
        cmd = tvb_get_uint8(tvb, offset);
173
1.98k
        proto_tree_add_item(tree, hf_bzr_packet_kind, tvb, offset, 1, ENC_ASCII);
174
1.98k
        offset += 1;
175
176
1.98k
        switch (cmd) {
177
1
        case 's':
178
1
            offset += dissect_prefixed_bencode(tvb, offset, pinfo, tree);
179
1
            break;
180
0
        case 'b':
181
0
            offset += dissect_prefixed_bytes(tvb, offset, pinfo, tree);
182
0
            break;
183
44
        case 'o':
184
44
            proto_tree_add_item(tree, hf_bzr_result, tvb, offset, 1,
185
44
                                ENC_ASCII);
186
44
            offset += 1;
187
44
            break;
188
10
        case 'e':
189
10
            break;
190
1.98k
        }
191
1.98k
    }
192
193
27
    return offset;
194
27
}
195
196
static void
197
dissect_bzr_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
198
32
{
199
32
    proto_tree *bzr_tree;
200
32
    proto_item *ti;
201
32
    unsigned    offset = 0;
202
32
    unsigned    protocol_version_len;
203
204
32
    ti = proto_tree_add_item(tree, proto_bzr, tvb, offset, -1, ENC_NA);
205
32
    bzr_tree = proto_item_add_subtree(ti, ett_bzr);
206
207
32
    if (!tvb_find_line_end_remaining(tvb, offset, &protocol_version_len, &offset)) /* Invalid packet */
208
2
        return;
209
210
30
    if (bzr_tree)
211
30
    {
212
30
        proto_tree_add_item(bzr_tree, hf_bzr_packet_protocol_version, tvb, 0,
213
30
                            protocol_version_len+1, ENC_ASCII);
214
30
    }
215
216
30
    offset += dissect_prefixed_bencode(tvb, offset, pinfo, bzr_tree);
217
30
    /*offset +=*/ dissect_body(tvb, offset, pinfo, bzr_tree);
218
30
}
219
220
static int
221
dissect_bzr(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_)
222
22
{
223
22
    unsigned  offset = 0, pdu_len;
224
22
    tvbuff_t *next_tvb;
225
226
22
    col_set_str(pinfo->cinfo, COL_PROTOCOL, "BZR");
227
228
22
    col_set_str(pinfo->cinfo, COL_INFO, "Bazaar Smart Protocol");
229
230
54
    while (tvb_reported_length_remaining(tvb, offset) > 0) {
231
32
        if (!get_bzr_pdu_len(pinfo, tvb, offset, &pdu_len)) {
232
22
            if (pinfo->can_desegment && bzr_desegment) {
233
0
                pinfo->desegment_offset = offset;
234
0
                pinfo->desegment_len = DESEGMENT_ONE_MORE_SEGMENT;
235
0
                return tvb_captured_length(tvb);
236
22
            } else {
237
22
                pdu_len = tvb_reported_length_remaining(tvb, offset);
238
22
            }
239
22
        }
240
32
        next_tvb = tvb_new_subset_length(tvb, offset, pdu_len);
241
32
        dissect_bzr_pdu(next_tvb, pinfo, tree);
242
32
        offset += pdu_len;
243
32
    }
244
245
22
    return tvb_captured_length(tvb);
246
22
}
247
248
void
249
proto_register_bzr(void)
250
15
{
251
15
    static hf_register_info hf[] = {
252
15
        { &hf_bzr_packet_kind,
253
15
          { "Packet kind", "bzr.kind", FT_CHAR, BASE_HEX,
254
15
            VALS(message_part_kind), 0x0, NULL, HFILL },
255
15
        },
256
15
        { &hf_bzr_packet_protocol_version,
257
15
          { "Protocol version", "bzr.protocol_version", FT_STRING, BASE_NONE,
258
15
            NULL, 0x0, NULL, HFILL },
259
15
        },
260
15
        { &hf_bzr_prefixed_bencode,
261
15
          { "Bencode packet", "bzr.bencode", FT_NONE, BASE_NONE, NULL, 0x0,
262
15
            "Serialized structure of integers, dictionaries, strings and "
263
15
            "lists.", HFILL },
264
15
        },
265
15
        { &hf_bzr_prefixed_bencode_len,
266
15
          { "Bencode packet length", "bzr.bencode.length", FT_UINT32,
267
15
            BASE_HEX, NULL, 0x0, NULL, HFILL },
268
15
        },
269
15
        { &hf_bzr_bytes,
270
15
          { "Prefixed bytes", "bzr.bytes", FT_NONE, BASE_NONE, NULL, 0x0,
271
15
            "Bytes field with prefixed 32-bit length", HFILL },
272
15
        },
273
15
        { &hf_bzr_bytes_data,
274
15
          { "Prefixed bytes data", "bzr.bytes.data", FT_BYTES, BASE_NONE,
275
15
            NULL, 0x0, NULL, HFILL },
276
15
        },
277
15
        { &hf_bzr_bytes_length,
278
15
          { "Prefixed bytes length", "bzr.bytes.length", FT_UINT32, BASE_HEX,
279
15
            NULL, 0x0, NULL, HFILL },
280
15
        },
281
15
        { &hf_bzr_result,
282
15
          { "Result", "bzr.result", FT_CHAR, BASE_HEX,
283
15
            VALS(message_results), 0x0,
284
15
            "Command result (success or failure with error message)", HFILL
285
15
          },
286
15
        },
287
15
    };
288
289
15
    static int *ett[] = {
290
15
        &ett_bzr,
291
15
        &ett_prefixed_bencode,
292
15
        &ett_prefixed_bytes,
293
15
    };
294
295
15
    module_t *bzr_module;
296
15
    proto_bzr = proto_register_protocol("Bazaar Smart Protocol", "Bazaar", "bzr");
297
15
    bzr_handle = register_dissector("bzr", dissect_bzr, proto_bzr);
298
15
    proto_register_field_array(proto_bzr, hf, array_length(hf));
299
15
    proto_register_subtree_array(ett, array_length(ett));
300
301
15
    bzr_module = prefs_register_protocol(proto_bzr, NULL);
302
303
15
    prefs_register_bool_preference(bzr_module, "desegment",
304
15
                                   "Reassemble Bazaar messages spanning multiple TCP segments",
305
15
                                   "Whether the Bazaar dissector should reassemble messages spanning multiple TCP segments."
306
15
                                   " To use this option, you must also enable \"Allow subdissectors to reassemble TCP streams\""
307
15
                                   " in the TCP protocol settings.",
308
15
                                   &bzr_desegment);
309
15
}
310
311
void
312
proto_reg_handoff_bzr(void)
313
15
{
314
15
    bencode_handle = find_dissector_add_dependency("bencode", proto_bzr);
315
316
15
    dissector_add_uint_with_preference("tcp.port", TCP_PORT_BZR, bzr_handle);
317
15
}
318
319
/*
320
 * Editor modelines  -  https://www.wireshark.org/tools/modelines.html
321
 *
322
 * Local variables:
323
 * c-basic-offset: 4
324
 * tab-width: 8
325
 * indent-tabs-mode: nil
326
 * End:
327
 *
328
 * vi: set shiftwidth=4 tabstop=8 expandtab:
329
 * :indentSize=4:tabSize=8:noTabs=true:
330
 */