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