1 /* packet-bencode.c
2 * Routines for bencode dissection
3 * Copyright (C) 2004,2013 Jelmer Vernooij <jelmer@samba.org>
4 *
5 * Wireshark - Network traffic analyzer
6 * By Gerald Combs <gerald@wireshark.org>
7 * Copyright 1998 Gerald Combs
8 *
9 * Copied from packet-pop.c
10 *
11 * SPDX-License-Identifier: GPL-2.0-or-later
12 */
13
14 #include "config.h"
15
16 #include <epan/packet.h>
17 #include <epan/expert.h>
18 #include <epan/strutil.h>
19
20 void proto_register_bencode(void);
21
22 static int proto_bencode = -1;
23
24 static gint hf_bencode_str_length = -1;
25 static gint hf_bencode_str = -1;
26 static gint hf_bencode_int = -1;
27 static gint hf_bencode_dict = -1;
28 static gint hf_bencode_dict_entry = -1;
29 static gint hf_bencode_list = -1;
30 static gint hf_bencode_truncated_data = -1;
31
32 static gint ett_bencode_dict = -1;
33 static gint ett_bencode_dict_entry = -1;
34 static gint ett_bencode_list = -1;
35
36 static expert_field ei_bencode_str = EI_INIT;
37 static expert_field ei_bencode_str_length = EI_INIT;
38 static expert_field ei_bencode_int = EI_INIT;
39 static expert_field ei_bencode_nest = EI_INIT;
40 static expert_field ei_bencode_dict_key = EI_INIT;
41 static expert_field ei_bencode_dict_value = EI_INIT;
42 static expert_field ei_bencode_invalid = EI_INIT;
43
dissect_bencoding_str(tvbuff_t * tvb,packet_info * pinfo,int offset,int length,proto_tree * tree,proto_item * ti,int treeadd)44 static int dissect_bencoding_str(tvbuff_t *tvb, packet_info *pinfo,
45 int offset, int length, proto_tree *tree, proto_item *ti, int treeadd)
46 {
47 guint8 ch;
48 int stringlen = 0, nextstringlen;
49 int used;
50 int izero = 0;
51
52 if (length < 2) {
53 proto_tree_add_expert(tree, pinfo, &ei_bencode_str, tvb, offset, length);
54 return -1;
55 }
56
57 used = 0;
58
59 while (length >= 1) {
60 ch = tvb_get_guint8(tvb, offset + used);
61 length--;
62 used++;
63
64 if ((ch == ':') && (used > 1)) {
65 if ((stringlen > length) || (stringlen < 0)) {
66 proto_tree_add_expert(tree, pinfo, &ei_bencode_str_length, tvb, offset, length);
67 return -1;
68 }
69 if (tree) {
70 proto_tree_add_uint(tree, hf_bencode_str_length, tvb, offset, used, stringlen);
71 proto_tree_add_item(tree, hf_bencode_str, tvb, offset + used, stringlen, ENC_ASCII|ENC_NA);
72
73 if (treeadd == 1) {
74 proto_item_append_text(ti, " Key: %s",
75 tvb_format_text(pinfo->pool, tvb, offset + used, stringlen));
76 }
77 if (treeadd == 2) {
78 proto_item_append_text(ti, " Value: %s",
79 tvb_format_text(pinfo->pool, tvb, offset + used, stringlen));
80 }
81 }
82 return used + stringlen;
83 }
84
85 if (!izero && (ch >= '0') && (ch <= '9')) {
86 if ((ch == '0') && (used == 1)) {
87 izero = 1;
88 }
89
90 nextstringlen = (stringlen * 10) + (ch - '0');
91 if (nextstringlen >= stringlen) {
92 stringlen = nextstringlen;
93 continue;
94 }
95 }
96
97 proto_tree_add_expert(tree, pinfo, &ei_bencode_str, tvb, offset, length);
98 return -1;
99 }
100
101 proto_tree_add_item(tree, hf_bencode_truncated_data, tvb, offset, length, ENC_NA);
102 return -1;
103 }
104
dissect_bencoding_int(tvbuff_t * tvb,packet_info * pinfo,int offset,int length,proto_tree * tree,proto_item * ti,int treeadd)105 static int dissect_bencoding_int(tvbuff_t *tvb, packet_info *pinfo,
106 int offset, int length, proto_tree *tree, proto_item *ti, int treeadd)
107 {
108 gint32 ival = 0;
109 int neg = 0;
110 int izero = 0;
111 int used;
112 guint8 ch;
113
114 if (length<3) {
115 proto_tree_add_expert(tree, pinfo, &ei_bencode_int, tvb, offset, length);
116 return -1;
117 }
118
119 length--;
120 used = 1;
121
122 while (length >= 1) {
123 ch = tvb_get_guint8(tvb, offset + used);
124 length--;
125 used++;
126
127 switch (ch) {
128 case 'e':
129 if (tree) {
130 if (neg) ival = -ival;
131 proto_tree_add_int(tree, hf_bencode_int, tvb, offset, used, ival);
132 if (treeadd == 2) {
133 proto_item_append_text(ti, " Value: %d", ival);
134 }
135 }
136 return used;
137
138 case '-':
139 if (used == 2) {
140 neg = 1;
141 break;
142 }
143 /* Fall through */
144
145 default:
146 if (!((ch == '0') && (used == 3) && neg)) { /* -0 is invalid */
147 if ((ch == '0') && (used == 2)) { /* as is 0[0-9]+ */
148 izero = 1;
149 break;
150 }
151 if (!izero && (ch >= '0') && (ch <= '9')) {
152 ival = (ival * 10) + (ch - '0');
153 break;
154 }
155 }
156
157 proto_tree_add_expert(tree, pinfo, &ei_bencode_int, tvb, offset, length);
158 return -1;
159 }
160 }
161
162 proto_tree_add_item(tree, hf_bencode_truncated_data, tvb, offset, length, ENC_NA);
163 return -1;
164 }
165
dissect_bencoding_rec(tvbuff_t * tvb,packet_info * pinfo,int offset,int length,proto_tree * tree,int level,proto_item * treei,int treeadd)166 static int dissect_bencoding_rec(tvbuff_t *tvb, packet_info *pinfo,
167 int offset, int length, proto_tree *tree, int level, proto_item *treei, int treeadd)
168 {
169 guint8 op;
170 int oplen = 0, op1len, op2len;
171 int used;
172
173 proto_item *ti = NULL, *td = NULL;
174 proto_tree *itree = NULL, *dtree = NULL;
175
176 if (level > 10) {
177 proto_tree_add_expert(tree, pinfo, &ei_bencode_nest, tvb, offset, -1);
178 return -1;
179 }
180 if (length < 1) {
181 proto_tree_add_item(tree, hf_bencode_truncated_data, tvb, offset, -1, ENC_NA);
182 return length;
183 }
184
185 op = tvb_get_guint8(tvb, offset);
186 oplen = dissect_bencoding_rec(tvb, pinfo, offset, length, NULL, level + 1, NULL, 0);
187 if (oplen < 0)
188 oplen = length;
189
190 switch (op) {
191 case 'd':
192 td = proto_tree_add_item(tree, hf_bencode_dict, tvb, offset, oplen, ENC_NA);
193 dtree = proto_item_add_subtree(td, ett_bencode_dict);
194
195 used = 1;
196 length--;
197
198 while (length >= 1) {
199 op = tvb_get_guint8(tvb, offset + used);
200
201 if (op == 'e') {
202 return used + 1;
203 }
204
205 op1len = dissect_bencoding_str(tvb, pinfo, offset + used, length, NULL, NULL, 0);
206 if (op1len < 0) {
207 proto_tree_add_expert(dtree, pinfo, &ei_bencode_dict_key, tvb, offset + used, -1);
208 return op1len;
209 }
210
211 op2len = -1;
212 if ((length - op1len) > 2)
213 op2len = dissect_bencoding_rec(tvb, pinfo, offset + used + op1len, length - op1len, NULL, level + 1, NULL, 0);
214 if (op2len < 0) {
215 proto_tree_add_expert(dtree, pinfo, &ei_bencode_dict_value, tvb, offset + used + op1len, -1);
216 return op2len;
217 }
218
219 ti = proto_tree_add_item(dtree, hf_bencode_dict_entry, tvb, offset + used, op1len + op2len, ENC_NA);
220 itree = proto_item_add_subtree(ti, ett_bencode_dict_entry);
221
222 dissect_bencoding_str(tvb, pinfo, offset + used, length, itree, ti, 1);
223 dissect_bencoding_rec(tvb, pinfo, offset + used + op1len, length - op1len, itree, level + 1, ti, 2);
224
225 used += op1len + op2len;
226 length -= op1len + op2len;
227 }
228
229 proto_tree_add_item(dtree, hf_bencode_truncated_data, tvb, offset + used, length ? -1 : 0, ENC_NA);
230 return -1;
231
232 case 'l':
233 ti = proto_tree_add_item(tree, hf_bencode_list, tvb, offset, oplen, ENC_NA);
234 itree = proto_item_add_subtree(ti, ett_bencode_list);
235
236 used = 1;
237 length--;
238
239 while (length >= 1) {
240 op = tvb_get_guint8(tvb, offset + used);
241
242 if (op == 'e') {
243 return used + 1;
244 }
245
246 oplen = dissect_bencoding_rec(tvb, pinfo, offset + used, length, itree, level + 1, ti, 0);
247 if (oplen < 1) return oplen;
248
249 used += oplen;
250 length -= oplen;
251 }
252
253 proto_tree_add_item(itree, hf_bencode_truncated_data, tvb, offset + used, -1, ENC_NA);
254 return -1;
255
256 case 'i':
257 return dissect_bencoding_int(tvb, pinfo, offset, length, tree, treei, treeadd);
258
259 default:
260 if ((op >= '1') && (op <= '9')) {
261 return dissect_bencoding_str(tvb, pinfo, offset, length, tree, treei, treeadd);
262 }
263
264 proto_tree_add_expert(tree, pinfo, &ei_bencode_invalid, tvb, offset, -1);
265 }
266
267 return -1;
268 }
269
dissect_bencoding(tvbuff_t * tvb,packet_info * pinfo,proto_tree * tree,void * data _U_)270 static int dissect_bencoding(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_)
271 {
272 dissect_bencoding_rec(tvb, pinfo, 0, tvb_reported_length(tvb), tree, 0, NULL, 0);
273 return tvb_captured_length(tvb);
274 }
275
276 void
proto_register_bencode(void)277 proto_register_bencode(void)
278 {
279 static hf_register_info hf[] = {
280 { &hf_bencode_str_length,
281 { "String Length", "bencode.str.length", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }
282 },
283 { &hf_bencode_str,
284 { "String", "bencode.str", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }
285 },
286 { &hf_bencode_int,
287 { "Integer", "bencode.int", FT_INT32, BASE_DEC, NULL, 0x0, NULL, HFILL }
288 },
289 { &hf_bencode_dict,
290 { "Dictionary", "bencode.dict", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL }
291 },
292 { &hf_bencode_dict_entry,
293 { "Entry", "bencode.dict.entry", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL }
294 },
295 { &hf_bencode_list,
296 { "List", "bencode.list", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL }
297 },
298 { &hf_bencode_truncated_data,
299 { "Truncated Data", "bencode.truncated_data", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL }
300 },
301 };
302
303 static gint *ett[] = {
304 &ett_bencode_dict,
305 &ett_bencode_dict_entry,
306 &ett_bencode_list,
307 };
308
309 static ei_register_info ei[] = {
310 { &ei_bencode_str, { "bencode.str.invalid", PI_MALFORMED, PI_ERROR, "Decode Aborted: Invalid String", EXPFILL }},
311 { &ei_bencode_str_length, { "bencode.str.length.invalid", PI_MALFORMED, PI_ERROR, "Decode Aborted: Invalid String Length", EXPFILL }},
312 { &ei_bencode_int, { "bencode.int.invalid", PI_MALFORMED, PI_ERROR, "Decode Aborted: Invalid Integer", EXPFILL }},
313 { &ei_bencode_nest, { "bencode.nest", PI_MALFORMED, PI_ERROR, "Decode Aborted: Nested Too Deep", EXPFILL }},
314 { &ei_bencode_dict_key, { "bencode.dict.key_invalid", PI_MALFORMED, PI_ERROR, "Decode Aborted: Invalid Dictionary Key", EXPFILL }},
315 { &ei_bencode_dict_value, { "bencode.dict.value_invalid", PI_MALFORMED, PI_ERROR, "Decode Aborted: Invalid Dictionary Value", EXPFILL }},
316 { &ei_bencode_invalid, { "bencode.invalid", PI_MALFORMED, PI_ERROR, "Invalid Bencoding", EXPFILL }},
317 };
318
319 expert_module_t* expert_bencode;
320
321 proto_bencode = proto_register_protocol("Bencode", "Bencode", "bencode");
322 register_dissector("bencode", dissect_bencoding, proto_bencode);
323 proto_register_field_array(proto_bencode, hf, array_length(hf));
324 proto_register_subtree_array(ett, array_length(ett));
325 expert_bencode = expert_register_protocol(proto_bencode);
326 expert_register_field_array(expert_bencode, ei, array_length(ei));
327 }
328
329 /*
330 * Editor modelines - https://www.wireshark.org/tools/modelines.html
331 *
332 * Local variables:
333 * c-basic-offset: 3
334 * tab-width: 8
335 * indent-tabs-mode: nil
336 * End:
337 *
338 * vi: set shiftwidth=3 tabstop=8 expandtab:
339 * :indentSize=3:tabSize=8:noTabs=true:
340 */
341