/src/wireshark/epan/dissectors/packet-roofnet.c
Line | Count | Source |
1 | | /* packet-roofnet.c |
2 | | * Routines for roofnet dissection |
3 | | * Copyright 2006, Sebastien Tandel (sebastien@tandel.be) |
4 | | * |
5 | | * Wireshark - Network traffic analyzer |
6 | | * By Gerald Combs <gerald@wireshark.org> |
7 | | * Copyright 1998 Gerald Combs |
8 | | * |
9 | | * SPDX-License-Identifier: GPL-2.0-or-later |
10 | | */ |
11 | | |
12 | | #include "config.h" |
13 | | |
14 | | #include <epan/packet.h> |
15 | | #include <epan/addr_resolv.h> |
16 | | #include <epan/expert.h> |
17 | | #include <epan/ptvcursor.h> |
18 | | |
19 | | |
20 | | /* roofnet packet type constants */ |
21 | | #define ROOFNET_PT_QUERY 0x01 |
22 | | #define ROOFNET_PT_REPLY 0x02 |
23 | | #define ROOFNET_PT_DATA 0x04 |
24 | | #define ROOFNET_PT_GATEWAY 0x08 |
25 | | static const value_string roofnet_pt_vals[] = { |
26 | | { ROOFNET_PT_QUERY, "Query" }, |
27 | | { ROOFNET_PT_REPLY, "Reply" }, |
28 | | { ROOFNET_PT_DATA, "Data" }, |
29 | | { ROOFNET_PT_GATEWAY, "Gateway" }, |
30 | | { 0, NULL } |
31 | | }; |
32 | | |
33 | | /* roofnet flag bit masks */ |
34 | 14 | #define ROOFNET_FLAG_ERROR (1<<0) |
35 | 14 | #define ROOFNET_FLAG_UPDATE (1<<1) |
36 | 23 | #define ROOFNET_FLAG_LAYER2 (1<<9) |
37 | 14 | #define ROOFNET_FLAG_RESERVED 0xFDFC |
38 | | #define ROOFNET_FLAG_MASK (ROOFNET_FLAG_ERROR | ROOFNET_FLAG_UPDATE | ROOFNET_FLAG_LAYER2) |
39 | | |
40 | | /* header length */ |
41 | 27 | #define ROOFNET_HEADER_LENGTH 160 |
42 | | /* roofnet max length */ |
43 | | /* may change with time */ |
44 | 27 | #define ROOFNET_MAX_LENGTH 400 |
45 | | /* Roofnet Link Description Length |
46 | | * which is 6 fields of 4 bytes */ |
47 | 55 | #define ROOFNET_LINK_DESCRIPTION_LENGTH 6*4 |
48 | | |
49 | | /* offset constants */ |
50 | 27 | #define ROOFNET_OFFSET_TYPE 1 |
51 | 27 | #define ROOFNET_OFFSET_NLINKS 2 |
52 | 11 | #define ROOFNET_OFFSET_DATA_LENGTH 10 |
53 | | |
54 | | /* offset relative to a link section of roofnet */ |
55 | 44 | #define ROOFNET_LINK_OFFSET_SRC 0 |
56 | 44 | #define ROOFNET_LINK_OFFSET_DST 20 |
57 | | /* roofnet link fields length */ |
58 | 44 | #define ROOFNET_LINK_LEN 24 |
59 | | |
60 | | /* forward reference */ |
61 | | void proto_register_roofnet(void); |
62 | | void proto_reg_handoff_roofnet(void); |
63 | | |
64 | | static dissector_handle_t roofnet_handle; |
65 | | static dissector_handle_t ip_handle; |
66 | | static dissector_handle_t eth_withoutfcs_handle; |
67 | | static int proto_roofnet; |
68 | | |
69 | | /* hf fields for the header of roofnet */ |
70 | | static int hf_roofnet_version; |
71 | | static int hf_roofnet_type; |
72 | | static int hf_roofnet_nlinks; |
73 | | static int hf_roofnet_next; |
74 | | static int hf_roofnet_ttl; |
75 | | static int hf_roofnet_cksum; |
76 | | static int hf_roofnet_flags; |
77 | | static int hf_roofnet_flags_error; |
78 | | static int hf_roofnet_flags_update; |
79 | | static int hf_roofnet_flags_layer2; |
80 | | static int hf_roofnet_flags_reserved; |
81 | | static int hf_roofnet_data_length; |
82 | | static int hf_roofnet_query_dst; |
83 | | static int hf_roofnet_seq; |
84 | | /* static int hf_roofnet_links; */ |
85 | | static int hf_roofnet_link_src; |
86 | | static int hf_roofnet_link_forward; |
87 | | static int hf_roofnet_link_rev; |
88 | | static int hf_roofnet_link_seq; |
89 | | static int hf_roofnet_link_age; |
90 | | static int hf_roofnet_link_dst; |
91 | | |
92 | | static int * const flag_list[] = { |
93 | | &hf_roofnet_flags_error, |
94 | | &hf_roofnet_flags_update, |
95 | | &hf_roofnet_flags_layer2, |
96 | | &hf_roofnet_flags_reserved, |
97 | | NULL |
98 | | }; |
99 | | |
100 | | |
101 | | static int ett_roofnet; |
102 | | static int ett_roofnet_flags; |
103 | | static int ett_roofnet_link; |
104 | | |
105 | | static expert_field ei_roofnet_too_many_links; |
106 | | static expert_field ei_roofnet_too_much_data; |
107 | | |
108 | | /* |
109 | | * dissect the header of roofnet |
110 | | */ |
111 | | static uint16_t dissect_roofnet_header(proto_tree *tree, packet_info *pinfo, tvbuff_t *tvb, unsigned *offset) |
112 | 27 | { |
113 | 27 | uint16_t flags; |
114 | 27 | ptvcursor_t *cursor = ptvcursor_new(pinfo->pool, tree, tvb, *offset); |
115 | | |
116 | 27 | ptvcursor_add(cursor, hf_roofnet_version, 1, ENC_BIG_ENDIAN); |
117 | 27 | ptvcursor_add(cursor, hf_roofnet_type, 1, ENC_BIG_ENDIAN); |
118 | 27 | ptvcursor_add(cursor, hf_roofnet_nlinks, 1, ENC_BIG_ENDIAN); |
119 | 27 | ptvcursor_add(cursor, hf_roofnet_next, 1, ENC_BIG_ENDIAN); |
120 | 27 | ptvcursor_add(cursor, hf_roofnet_ttl, 2, ENC_BIG_ENDIAN); |
121 | 27 | proto_tree_add_checksum(ptvcursor_tree(cursor), ptvcursor_tvbuff(cursor), ptvcursor_current_offset(cursor), |
122 | 27 | hf_roofnet_cksum, -1, NULL, NULL, 0, ENC_BIG_ENDIAN, PROTO_CHECKSUM_NO_FLAGS); |
123 | 27 | ptvcursor_advance(cursor, 2); |
124 | 27 | flags = tvb_get_ntohs(ptvcursor_tvbuff(cursor), ptvcursor_current_offset(cursor)); |
125 | 27 | proto_tree_add_bitmask(ptvcursor_tree(cursor), ptvcursor_tvbuff(cursor), ptvcursor_current_offset(cursor), |
126 | 27 | hf_roofnet_flags, ett_roofnet_flags, flag_list, ENC_BIG_ENDIAN); |
127 | 27 | ptvcursor_advance(cursor, 2); |
128 | 27 | ptvcursor_add(cursor, hf_roofnet_data_length, 2, ENC_BIG_ENDIAN); |
129 | 27 | ptvcursor_add(cursor, hf_roofnet_query_dst, 4, ENC_BIG_ENDIAN); |
130 | 27 | ptvcursor_add(cursor, hf_roofnet_seq, 4, ENC_BIG_ENDIAN); |
131 | | |
132 | 27 | *offset = ptvcursor_current_offset(cursor); |
133 | 27 | ptvcursor_free(cursor); |
134 | | |
135 | 27 | return flags; |
136 | 27 | } |
137 | | |
138 | | /* |
139 | | * dissect the description of link in roofnet |
140 | | */ |
141 | | static void dissect_roofnet_link(proto_tree *tree, packet_info *pinfo, tvbuff_t *tvb, unsigned *offset, unsigned link) |
142 | 44 | { |
143 | 44 | proto_tree *subtree = NULL; |
144 | | |
145 | 44 | ptvcursor_t *cursor = NULL; |
146 | | |
147 | 44 | uint32_t addr_src = 0; |
148 | 44 | uint32_t addr_dst = 0; |
149 | | |
150 | 44 | addr_src = tvb_get_ipv4(tvb, *offset + ROOFNET_LINK_OFFSET_SRC); |
151 | 44 | addr_dst = tvb_get_ipv4(tvb, *offset + ROOFNET_LINK_OFFSET_DST); |
152 | | |
153 | 44 | subtree = proto_tree_add_subtree_format(tree, tvb, *offset, ROOFNET_LINK_LEN, |
154 | 44 | ett_roofnet_link, NULL, "link: %u, src: %s, dst: %s", |
155 | 44 | link, |
156 | 44 | get_hostname(addr_src), |
157 | 44 | get_hostname(addr_dst)); |
158 | | |
159 | 44 | proto_tree_add_ipv4(subtree, hf_roofnet_link_src, tvb, *offset, 4, addr_src); |
160 | 44 | *offset += 4; |
161 | | |
162 | 44 | cursor = ptvcursor_new(pinfo->pool, subtree, tvb, *offset); |
163 | | |
164 | 44 | ptvcursor_add(cursor, hf_roofnet_link_forward, 4, ENC_BIG_ENDIAN); |
165 | 44 | ptvcursor_add(cursor, hf_roofnet_link_rev, 4, ENC_BIG_ENDIAN); |
166 | 44 | ptvcursor_add(cursor, hf_roofnet_link_seq, 4, ENC_BIG_ENDIAN); |
167 | 44 | ptvcursor_add(cursor, hf_roofnet_link_age, 4, ENC_BIG_ENDIAN); |
168 | | |
169 | 44 | *offset = ptvcursor_current_offset(cursor); |
170 | 44 | ptvcursor_free(cursor); |
171 | | |
172 | 44 | proto_tree_add_ipv4(subtree, hf_roofnet_link_dst, tvb, *offset, 4, addr_dst); |
173 | | /* don't increment offset here because the dst of this link is the src of the next one */ |
174 | 44 | } |
175 | | |
176 | | /* |
177 | | * dissect the data in roofnet |
178 | | */ |
179 | | static void dissect_roofnet_data(proto_tree *tree, tvbuff_t *tvb, packet_info * pinfo, int offset, uint16_t flags) |
180 | 11 | { |
181 | 11 | uint16_t roofnet_datalen = 0; |
182 | 11 | uint16_t remaining_datalen = 0; |
183 | | |
184 | 11 | roofnet_datalen = tvb_get_ntohs(tvb, ROOFNET_OFFSET_DATA_LENGTH); |
185 | 11 | remaining_datalen = tvb_reported_length_remaining(tvb, offset); |
186 | | |
187 | | |
188 | | /* dissect on remaining_datalen */ |
189 | 11 | if (roofnet_datalen < remaining_datalen) |
190 | 4 | proto_tree_add_expert_format(tree, pinfo, &ei_roofnet_too_much_data, tvb, offset, roofnet_datalen, |
191 | 4 | "[More payload data (%u) than told by Roofnet (%u)]", |
192 | 4 | remaining_datalen, roofnet_datalen); |
193 | | |
194 | 11 | if (roofnet_datalen == 0) |
195 | 2 | return; |
196 | | |
197 | | /* dissect payload */ |
198 | 9 | if (flags & ROOFNET_FLAG_LAYER2) { |
199 | | /* ethernet frame is padded with 2 bytes at the start */ |
200 | 5 | call_dissector(eth_withoutfcs_handle, tvb_new_subset_remaining(tvb, offset+2), pinfo, tree); |
201 | 5 | } else { |
202 | 4 | call_dissector(ip_handle, tvb_new_subset_remaining(tvb, offset), pinfo, tree); |
203 | 4 | } |
204 | | |
205 | 9 | } |
206 | | |
207 | | /* |
208 | | * entry point of the roofnet dissector |
209 | | */ |
210 | | static int dissect_roofnet(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_) |
211 | 27 | { |
212 | 27 | proto_item * it; |
213 | 27 | proto_tree * roofnet_tree; |
214 | 27 | unsigned offset = 0; |
215 | | |
216 | 27 | uint8_t roofnet_msg_type = 0; |
217 | 27 | uint8_t roofnet_nlinks = 0; |
218 | 27 | uint8_t nlink = 1; |
219 | 27 | uint16_t flags; |
220 | | |
221 | 27 | col_set_str(pinfo->cinfo, COL_PROTOCOL, "Roofnet"); |
222 | | |
223 | 27 | roofnet_msg_type = tvb_get_uint8(tvb, ROOFNET_OFFSET_TYPE); |
224 | | /* Clear out stuff in the info column */ |
225 | 27 | col_add_fstr(pinfo->cinfo, COL_INFO, "Message Type: %s", |
226 | 27 | val_to_str(pinfo->pool, roofnet_msg_type, roofnet_pt_vals, "Unknown (%d)")); |
227 | | |
228 | 27 | it = proto_tree_add_item(tree, proto_roofnet, tvb, offset, -1, ENC_NA); |
229 | 27 | roofnet_tree = proto_item_add_subtree(it, ett_roofnet); |
230 | | |
231 | 27 | flags = dissect_roofnet_header(roofnet_tree, pinfo, tvb, &offset); |
232 | | |
233 | 27 | roofnet_nlinks = tvb_get_uint8(tvb, ROOFNET_OFFSET_NLINKS); |
234 | | /* Check that we do not have a malformed roofnet packet */ |
235 | 27 | if ((roofnet_nlinks*6*4)+ROOFNET_HEADER_LENGTH > ROOFNET_MAX_LENGTH) { |
236 | 2 | expert_add_info_format(pinfo, it, &ei_roofnet_too_many_links, "Too many links (%u)", roofnet_nlinks); |
237 | 2 | return tvb_captured_length(tvb); |
238 | 2 | } |
239 | | |
240 | 69 | for (; roofnet_nlinks > 0; roofnet_nlinks--) { |
241 | | /* Do we have enough buffer to decode the next link ? */ |
242 | 55 | if (tvb_reported_length_remaining(tvb, offset) < ROOFNET_LINK_DESCRIPTION_LENGTH) |
243 | 11 | return offset; |
244 | 44 | dissect_roofnet_link(roofnet_tree, pinfo, tvb, &offset, nlink++); |
245 | 44 | } |
246 | | |
247 | 14 | dissect_roofnet_data(tree, tvb, pinfo, offset+4, flags); |
248 | 14 | return tvb_captured_length(tvb); |
249 | 25 | } |
250 | | |
251 | | void proto_register_roofnet(void) |
252 | 14 | { |
253 | 14 | static hf_register_info hf[] = { |
254 | | /* Roofnet Header */ |
255 | 14 | { &hf_roofnet_version, |
256 | 14 | { "Version", "roofnet.version", |
257 | 14 | FT_UINT8, BASE_DEC, NULL, 0x0, "Roofnet Version", HFILL } |
258 | 14 | }, |
259 | | |
260 | 14 | { &hf_roofnet_type, |
261 | 14 | { "Type", "roofnet.type", |
262 | 14 | FT_UINT8, BASE_DEC, VALS(roofnet_pt_vals), 0x0, "Roofnet Message Type", HFILL } |
263 | 14 | }, |
264 | | |
265 | 14 | { &hf_roofnet_nlinks, |
266 | 14 | { "Number of Links", "roofnet.nlinks", |
267 | 14 | FT_UINT8, BASE_DEC, NULL, 0x0, "Roofnet Number of Links", HFILL } |
268 | 14 | }, |
269 | | |
270 | 14 | { &hf_roofnet_next, |
271 | 14 | { "Next Link", "roofnet.next", |
272 | 14 | FT_UINT8, BASE_DEC, NULL, 0x0, "Roofnet Next Link to Use", HFILL } |
273 | 14 | }, |
274 | | |
275 | 14 | { &hf_roofnet_ttl, |
276 | 14 | { "Time To Live", "roofnet.ttl", |
277 | 14 | FT_UINT16, BASE_DEC, NULL, 0x0, "Roofnet Time to Live", HFILL } |
278 | 14 | }, |
279 | | |
280 | 14 | { &hf_roofnet_cksum, |
281 | 14 | { "Checksum", "roofnet.cksum", |
282 | 14 | FT_UINT16, BASE_DEC, NULL, 0x0, "Roofnet Header Checksum", HFILL } |
283 | 14 | }, |
284 | | |
285 | 14 | { &hf_roofnet_flags, |
286 | 14 | { "Flags", "roofnet.flags", |
287 | 14 | FT_UINT16, BASE_HEX, NULL, 0x0, "Roofnet flags", HFILL } |
288 | 14 | }, |
289 | | |
290 | 14 | { &hf_roofnet_flags_error, |
291 | 14 | { "Roofnet Error", "roofnet.flags.error", |
292 | 14 | FT_BOOLEAN, 16, NULL, ROOFNET_FLAG_ERROR, NULL, HFILL } |
293 | 14 | }, |
294 | | |
295 | 14 | { &hf_roofnet_flags_update, |
296 | 14 | { "Roofnet Update", "roofnet.flags.update", |
297 | 14 | FT_BOOLEAN, 16, NULL, ROOFNET_FLAG_UPDATE, NULL, HFILL } |
298 | 14 | }, |
299 | | |
300 | 14 | { &hf_roofnet_flags_layer2, |
301 | 14 | { "Roofnet Layer 2", "roofnet.flags.layer2", |
302 | 14 | FT_BOOLEAN, 16, NULL, ROOFNET_FLAG_LAYER2, NULL, HFILL } |
303 | 14 | }, |
304 | | |
305 | 14 | { &hf_roofnet_flags_reserved, |
306 | 14 | { "Roofnet Reserved", "roofnet.flags.reserved", |
307 | 14 | FT_BOOLEAN, 16, NULL, ROOFNET_FLAG_RESERVED, NULL, HFILL } |
308 | 14 | }, |
309 | | |
310 | 14 | { &hf_roofnet_data_length, |
311 | 14 | { "Data Length", "roofnet.datalength", |
312 | 14 | FT_UINT16, BASE_DEC, NULL, 0x0, "Data Payload Length", HFILL } |
313 | 14 | }, |
314 | | |
315 | 14 | { &hf_roofnet_query_dst, |
316 | 14 | { "Query Dst", "roofnet.querydst", |
317 | 14 | FT_IPv4, BASE_NONE, NULL, 0x0, "Roofnet Query Destination", HFILL } |
318 | 14 | }, |
319 | | |
320 | 14 | { &hf_roofnet_seq, |
321 | 14 | { "Seq", "roofnet.seq", |
322 | 14 | FT_UINT32, BASE_DEC, NULL, 0x0, "Roofnet Sequential Number", HFILL } |
323 | 14 | }, |
324 | | |
325 | | #if 0 |
326 | | { &hf_roofnet_links, |
327 | | { "Links", "roofnet.links", |
328 | | FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL } |
329 | | }, |
330 | | #endif |
331 | | |
332 | 14 | { &hf_roofnet_link_src, |
333 | 14 | { "Source IP", "roofnet.link.src", |
334 | 14 | FT_IPv4, BASE_NONE, NULL, 0x0, "Roofnet Message Source", HFILL } |
335 | 14 | }, |
336 | | |
337 | 14 | { &hf_roofnet_link_forward, |
338 | 14 | { "Forward", "roofnet.link.forward", |
339 | 14 | FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL } |
340 | 14 | }, |
341 | | |
342 | 14 | { &hf_roofnet_link_rev, |
343 | 14 | { "Rev", "roofnet.link.rev", |
344 | 14 | FT_UINT32, BASE_DEC, NULL, 0x0, "Revision Number", HFILL } |
345 | 14 | }, |
346 | | |
347 | 14 | { &hf_roofnet_link_seq, |
348 | 14 | { "Seq", "roofnet.link.seq", |
349 | 14 | FT_UINT32, BASE_DEC, NULL, 0x0, "Link Sequential Number", HFILL } |
350 | 14 | }, |
351 | | |
352 | 14 | { &hf_roofnet_link_age, |
353 | 14 | { "Age", "roofnet.link.age", |
354 | 14 | FT_UINT32, BASE_DEC, NULL, 0x0, "Information Age", HFILL } |
355 | 14 | }, |
356 | | |
357 | 14 | { &hf_roofnet_link_dst, |
358 | 14 | { "Dst IP", "roofnet.link.dst", |
359 | 14 | FT_IPv4, BASE_NONE, NULL, 0x0, "Roofnet Message Destination", HFILL } |
360 | 14 | } |
361 | 14 | }; |
362 | | |
363 | | /* setup protocol subtree array */ |
364 | 14 | static int *ett[] = { |
365 | 14 | &ett_roofnet, |
366 | 14 | &ett_roofnet_flags, |
367 | 14 | &ett_roofnet_link |
368 | 14 | }; |
369 | | |
370 | 14 | static ei_register_info ei[] = { |
371 | 14 | { &ei_roofnet_too_many_links, { "roofnet.too_many_links", PI_MALFORMED, PI_ERROR, "Too many links", EXPFILL }}, |
372 | 14 | { &ei_roofnet_too_much_data, { "roofnet.too_much_data", PI_MALFORMED, PI_ERROR, "More payload data than told by Roofnet", EXPFILL }}, |
373 | 14 | }; |
374 | | |
375 | 14 | expert_module_t* expert_roofnet; |
376 | | |
377 | 14 | proto_roofnet = proto_register_protocol("Roofnet Protocol", "Roofnet", "roofnet"); |
378 | | |
379 | 14 | proto_register_field_array(proto_roofnet, hf, array_length(hf)); |
380 | 14 | proto_register_subtree_array(ett, array_length(ett)); |
381 | 14 | expert_roofnet = expert_register_protocol(proto_roofnet); |
382 | 14 | expert_register_field_array(expert_roofnet, ei, array_length(ei)); |
383 | | |
384 | 14 | roofnet_handle = register_dissector("roofnet", dissect_roofnet, proto_roofnet); |
385 | 14 | } |
386 | | |
387 | | |
388 | | void proto_reg_handoff_roofnet(void) |
389 | 14 | { |
390 | | /* Until now there is no other option than having an IPv4 payload (maybe |
391 | | * extended one day to IPv6 or other?) */ |
392 | 14 | ip_handle = find_dissector_add_dependency("ip", proto_roofnet); |
393 | 14 | eth_withoutfcs_handle = find_dissector_add_dependency("eth_withoutfcs", proto_roofnet); |
394 | | /* I did not put the type numbers in the ethertypes.h as they only are |
395 | | * experimental and not official */ |
396 | 14 | dissector_add_uint("ethertype", 0x0641, roofnet_handle); |
397 | 14 | dissector_add_uint("ethertype", 0x0643, roofnet_handle); |
398 | 14 | dissector_add_uint("ethertype", 0x0644, roofnet_handle); |
399 | 14 | dissector_add_uint("ethertype", 0x0645, roofnet_handle); |
400 | 14 | } |
401 | | |
402 | | /* |
403 | | * Editor modelines - https://www.wireshark.org/tools/modelines.html |
404 | | * |
405 | | * Local Variables: |
406 | | * c-basic-offset: 2 |
407 | | * tab-width: 8 |
408 | | * indent-tabs-mode: nil |
409 | | * End: |
410 | | * |
411 | | * ex: set shiftwidth=2 tabstop=8 expandtab: |
412 | | * :indentSize=2:tabSize=8:noTabs=true: |
413 | | */ |