/src/wireshark/epan/dissectors/packet-icep.c
Line | Count | Source |
1 | | /* packet-icep.c |
2 | | * Routines for "The ICE Protocol" dissection |
3 | | * Copyright 2004 _FF_ |
4 | | * Francesco Fondelli <fondelli dot francesco, tiscali dot it> |
5 | | * |
6 | | * Wireshark - Network traffic analyzer |
7 | | * By Gerald Combs <gerald@wireshark.org> |
8 | | * Copyright 1998 Gerald Combs |
9 | | * |
10 | | * SPDX-License-Identifier: GPL-2.0-or-later |
11 | | */ |
12 | | |
13 | | /* |
14 | | TODO: |
15 | | 1) Dissect encoded data (do sth like idl2wrs for CORBA). |
16 | | 2) Add conversations. |
17 | | |
18 | | */ |
19 | | |
20 | | /* |
21 | | NOTES: |
22 | | 1) p. 586 Chapter 23.2 of "The ICE Protocol" |
23 | | "Data is always encoded using little-endian byte order for numeric types." |
24 | | 2) Information about Ice can be found here: http://www.zeroc.com |
25 | | */ |
26 | | |
27 | 0 | #define WS_LOG_DOMAIN "packet-icep" |
28 | | |
29 | | #include "config.h" |
30 | | #include <wireshark.h> |
31 | | |
32 | | #include <epan/packet.h> |
33 | | #include <epan/expert.h> |
34 | | #include <epan/prefs.h> |
35 | | #include "packet-tcp.h" |
36 | | |
37 | | void proto_register_icep(void); |
38 | | void proto_reg_handoff_icep(void); |
39 | | |
40 | | static dissector_handle_t icep_tcp_handle, icep_udp_handle; |
41 | | |
42 | | /* fixed values taken from the standard */ |
43 | | static const uint8_t icep_magic[] = { 'I', 'c', 'e', 'P' }; |
44 | 62 | #define ICEP_HEADER_SIZE 14 |
45 | 9 | #define ICEP_MIN_REPLY_SIZE 5 |
46 | 70 | #define ICEP_MIN_PARAMS_SIZE 6 |
47 | 84 | #define ICEP_MIN_COMMON_REQ_HEADER_SIZE 13 |
48 | | |
49 | | /* Initialize the protocol and registered fields */ |
50 | | static int proto_icep; |
51 | | |
52 | | /* Message Header */ |
53 | | static int hf_icep_protocol_major; |
54 | | static int hf_icep_protocol_minor; |
55 | | static int hf_icep_encoding_major; |
56 | | static int hf_icep_encoding_minor; |
57 | | static int hf_icep_message_type; |
58 | | static int hf_icep_compression_status; |
59 | | static int hf_icep_message_size; |
60 | | static int hf_icep_magic_number; |
61 | | |
62 | | /* [Batch] Request Message Body */ |
63 | | static int hf_icep_request_id; |
64 | | static int hf_icep_id_name; |
65 | | static int hf_icep_id_category; |
66 | | static int hf_icep_facet; |
67 | | static int hf_icep_operation; |
68 | | static int hf_icep_mode; |
69 | | static int hf_icep_context; |
70 | | static int hf_icep_params_size; |
71 | | static int hf_icep_params_major; |
72 | | static int hf_icep_params_minor; |
73 | | static int hf_icep_params_encapsulated; |
74 | | static int hf_icep_reply_data; |
75 | | static int hf_icep_invocation_key; |
76 | | static int hf_icep_invocation_value; |
77 | | |
78 | | /* Reply Message Body */ |
79 | | static int hf_icep_reply_status; |
80 | | |
81 | | /* Initialize the subtree pointers */ |
82 | | static int ett_icep; |
83 | | static int ett_icep_msg; |
84 | | static int ett_icep_invocation_context; |
85 | | |
86 | | static expert_field ei_icep_params_size; |
87 | | static expert_field ei_icep_context_missing; |
88 | | static expert_field ei_icep_reply_data; |
89 | | static expert_field ei_icep_length; |
90 | | static expert_field ei_icep_facet_max_one_element; |
91 | | static expert_field ei_icep_string_too_long; |
92 | | static expert_field ei_icep_string_malformed; |
93 | | static expert_field ei_icep_message_type; |
94 | | static expert_field ei_icep_mode_missing; |
95 | | static expert_field ei_icep_params_encapsulated; |
96 | | static expert_field ei_icep_params_missing; |
97 | | static expert_field ei_icep_batch_requests; |
98 | | static expert_field ei_icep_empty_batch; |
99 | | static expert_field ei_icep_facet_missing; |
100 | | static expert_field ei_icep_context_too_long; |
101 | | |
102 | | /* Preferences */ |
103 | | static unsigned icep_max_batch_requests = 64; |
104 | | static unsigned icep_max_ice_string_len = 512; |
105 | | static unsigned icep_max_ice_context_pairs = 64; |
106 | | |
107 | | |
108 | | static const value_string icep_msgtype_vals[] = { |
109 | | {0x0, "Request"}, |
110 | | {0x1, "Batch request"}, |
111 | | {0x2, "Reply"}, |
112 | | {0x3, "Validate connection"}, |
113 | | {0x4, "Close connection"}, |
114 | | {0, NULL} |
115 | | }; |
116 | | |
117 | | static const value_string icep_zipstatus_vals[] = { |
118 | | {0x0, "Uncompressed, sender cannot accept a compressed reply"}, |
119 | | {0x1, "Uncompressed, sender can accept a compressed reply"}, |
120 | | {0x2, "Compressed, sender can accept a compressed reply"}, |
121 | | {0, NULL} |
122 | | }; |
123 | | |
124 | | static const value_string icep_replystatus_vals[] = { |
125 | | {0x0, "Success"}, |
126 | | {0x1, "User exception"}, |
127 | | {0x2, "Object does not exist"}, |
128 | | {0x3, "Facet does not exist"}, |
129 | | {0x4, "Operation does not exist"}, |
130 | | {0x5, "Unknown Ice local exception"}, |
131 | | {0x6, "Unknown Ice user exception"}, |
132 | | {0x7, "Unknown exception"}, |
133 | | {0, NULL} |
134 | | }; |
135 | | |
136 | | static const value_string icep_mode_vals[] = { |
137 | | {0x0, "normal"}, |
138 | | {0x1, "nonmutating"}, |
139 | | {0x2, "idempotent"}, |
140 | | {0, NULL} |
141 | | }; |
142 | | |
143 | | /* |
144 | | * This function dissects an "Ice string", adds hf to "tree" and returns consumed |
145 | | * bytes in "*consumed", if errors "*consumed" is -1. |
146 | | * |
147 | | * "*dest" is a null terminated version of the dissected Ice string. |
148 | | */ |
149 | | static void dissect_ice_string(packet_info *pinfo, proto_tree *tree, proto_item *item, int hf_icep, |
150 | | tvbuff_t *tvb, uint32_t offset, int32_t *consumed, const uint8_t **dest) |
151 | 695 | { |
152 | | /* p. 586 chapter 23.2.1 and p. 588 chapter 23.2.5 |
153 | | * string == Size + content |
154 | | * string = 1byte (0..254) + string not null terminated |
155 | | * or |
156 | | * string = 1byte (255) + 1int (255..2^32-1) + string not null terminated |
157 | | */ |
158 | | |
159 | 695 | uint32_t Size = 0; |
160 | 695 | const uint8_t *s = NULL; |
161 | | |
162 | 695 | (*consumed) = 0; |
163 | | |
164 | | /* check for first byte */ |
165 | 695 | if ( !tvb_bytes_exist(tvb, offset, 1) ) { |
166 | | |
167 | 2 | expert_add_info_format(pinfo, item, &ei_icep_string_malformed, "1st byte of Size missing"); |
168 | 2 | col_append_str(pinfo->cinfo, COL_INFO, " (1st byte of Size missing)"); |
169 | | |
170 | 2 | (*consumed) = -1; |
171 | 2 | return; |
172 | 2 | } |
173 | | |
174 | | /* get the Size */ |
175 | 693 | Size = tvb_get_uint8(tvb, offset); |
176 | 693 | offset++; |
177 | 693 | (*consumed)++; |
178 | | |
179 | 693 | if ( Size == 255 ) { |
180 | | |
181 | | /* check for next 4 bytes */ |
182 | 9 | if ( !tvb_bytes_exist(tvb, offset, 4) ) { |
183 | | |
184 | 1 | expert_add_info_format(pinfo, item, &ei_icep_string_malformed, "second field of Size missing"); |
185 | 1 | col_append_str(pinfo->cinfo, COL_INFO, " (second field of Size missing)"); |
186 | | |
187 | 1 | (*consumed) = -1; |
188 | 1 | return; |
189 | 1 | } |
190 | | |
191 | | /* get second field of Size */ |
192 | 8 | Size = tvb_get_letohl(tvb, offset); |
193 | 8 | offset += 4; |
194 | 8 | (*consumed) += 4; |
195 | 8 | } |
196 | | |
197 | 692 | ws_debug("string.Size --> %d", Size); |
198 | | |
199 | | /* check if the string exists */ |
200 | 692 | if ( !tvb_bytes_exist(tvb, offset, Size) ) { |
201 | | |
202 | 34 | expert_add_info_format(pinfo, item, &ei_icep_string_malformed, "missing or truncated string"); |
203 | 34 | col_append_str(pinfo->cinfo, COL_INFO, " (missing or truncated string)"); |
204 | | |
205 | 34 | (*consumed) = -1; |
206 | 34 | return; |
207 | 34 | } |
208 | | |
209 | 658 | if ( Size > icep_max_ice_string_len ) { |
210 | |
|
211 | 0 | expert_add_info(pinfo, item, &ei_icep_string_too_long); |
212 | 0 | col_append_str(pinfo->cinfo, COL_INFO, " (string too long)"); |
213 | |
|
214 | 0 | (*consumed) = -1; |
215 | 0 | return; |
216 | 0 | } |
217 | | |
218 | | |
219 | 658 | if ( Size != 0 ) { |
220 | 192 | proto_tree_add_item_ret_string(tree, hf_icep, tvb, offset, Size, ENC_ASCII, pinfo->pool, &s); |
221 | 466 | } else { |
222 | 466 | s = (const uint8_t*)wmem_strdup(pinfo->pool, "(empty)"); |
223 | | /* display the 0x00 Size byte when click on a empty ice_string */ |
224 | 466 | proto_tree_add_string(tree, hf_icep, tvb, offset - 1, 1, (const char*)s); |
225 | 466 | } |
226 | | |
227 | 658 | if ( dest != NULL ) |
228 | 585 | *dest = s; |
229 | | |
230 | | /*offset += Size;*/ |
231 | 658 | (*consumed) += Size; |
232 | 658 | return; |
233 | 658 | } |
234 | | |
235 | | /* |
236 | | * This function dissects an "Ice facet", adds hf(s) to "tree" and returns consumed |
237 | | * bytes in "*consumed", if errors "*consumed" is -1. |
238 | | */ |
239 | | static void dissect_ice_facet(packet_info *pinfo, proto_tree *tree, proto_item *item, int hf_icep, |
240 | | tvbuff_t *tvb, uint32_t offset, int32_t *consumed) |
241 | 66 | { |
242 | | /* p. 588, chapter 23.2.6: |
243 | | * "facet" is a StringSeq, a StringSeq is a: |
244 | | * sequence<string> |
245 | | * |
246 | | * |
247 | | * sequence == Size + SizeElements |
248 | | * sequence = 1byte (0..254) + SizeElements |
249 | | * or |
250 | | * sequence = 1byte (255) + 1int (255..2^32-1) + SizeElements |
251 | | * |
252 | | * |
253 | | * p.613. chapter 23.3.2 |
254 | | * "facet has either zero elements (empty) or one element" |
255 | | * |
256 | | * |
257 | | */ |
258 | | |
259 | 66 | uint32_t Size = 0; /* number of elements in the sequence */ |
260 | | |
261 | 66 | (*consumed) = 0; |
262 | | |
263 | | /* check first byte */ |
264 | 66 | if ( !tvb_bytes_exist(tvb, offset, 1) ) { |
265 | | |
266 | 2 | expert_add_info(pinfo, item, &ei_icep_facet_missing); |
267 | 2 | col_append_str(pinfo->cinfo, COL_INFO, " (facet field missing)"); |
268 | | |
269 | 2 | (*consumed) = -1; |
270 | 2 | return; |
271 | 2 | } |
272 | | |
273 | | /* get first byte of Size */ |
274 | 64 | Size = tvb_get_uint8(tvb, offset); |
275 | 64 | offset++; |
276 | 64 | (*consumed)++; |
277 | | |
278 | 64 | if ( Size == 0 ) { |
279 | | /* display the 0x00 Size byte when click on a empty ice_string */ |
280 | 46 | proto_tree_add_string(tree, hf_icep, tvb, offset - 1, 1, "(empty)"); |
281 | 46 | return; |
282 | 46 | } |
283 | | |
284 | 18 | if ( Size == 1 ) { |
285 | | |
286 | 10 | int32_t consumed_facet = 0; |
287 | | |
288 | 10 | dissect_ice_string(pinfo, tree, item, hf_icep, tvb, offset, &consumed_facet, NULL); |
289 | | |
290 | 10 | if ( consumed_facet == -1 ) { |
291 | 3 | (*consumed) = -1; |
292 | 3 | return; |
293 | 3 | } |
294 | | |
295 | | /*offset += consumed_facet;*/ |
296 | 7 | (*consumed) += consumed_facet; |
297 | 7 | return; |
298 | 10 | } |
299 | | |
300 | | /* if here => Size > 1 => not possible */ |
301 | | |
302 | | /* display the XX Size byte when click here */ |
303 | 8 | expert_add_info(pinfo, item, &ei_icep_facet_max_one_element); |
304 | | |
305 | 8 | col_append_str(pinfo->cinfo, COL_INFO, " (facet can be max one element)"); |
306 | | |
307 | 8 | (*consumed) = -1; |
308 | 8 | return; |
309 | 18 | } |
310 | | |
311 | | /* |
312 | | * This function dissects an "Ice context", adds hf(s) to "tree" and returns consumed |
313 | | * bytes in "*consumed", if errors "*consumed" is -1. |
314 | | */ |
315 | | static void dissect_ice_context(packet_info *pinfo, proto_tree *tree, proto_item *item, |
316 | | tvbuff_t *tvb, uint32_t offset, int32_t *consumed) |
317 | 48 | { |
318 | | /* p. 588, chapter 23.2.7 and p. 613, 23.3.2: |
319 | | * "context" is a dictionary<string, string> |
320 | | * |
321 | | * dictionary<string, string> == Size + SizeKeyValuePairs |
322 | | * dictionary<string, string> = 1byte (0..254) + SizeKeyValuePairs |
323 | | * or |
324 | | * dictionary<string, string>= 1byte (255) + 1int (255..2^32-1)+SizeKeyValuePairs |
325 | | * |
326 | | */ |
327 | | |
328 | 48 | uint32_t Size = 0; /* number of key-value in the dictionary */ |
329 | 48 | uint32_t i = 0; |
330 | 48 | const char *s = NULL; |
331 | | |
332 | 48 | (*consumed) = 0; |
333 | | |
334 | | /* check first byte */ |
335 | 48 | if ( !tvb_bytes_exist(tvb, offset, 1) ) { |
336 | | |
337 | 2 | expert_add_info_format(pinfo, item, &ei_icep_context_missing, "context missing"); |
338 | 2 | col_append_str(pinfo->cinfo, COL_INFO, " (context missing)"); |
339 | | |
340 | 2 | (*consumed) = -1; |
341 | 2 | return; |
342 | 2 | } |
343 | | |
344 | | /* get first byte of Size */ |
345 | 46 | Size = tvb_get_uint8(tvb, offset); |
346 | 46 | offset++; |
347 | 46 | (*consumed)++; |
348 | | |
349 | 46 | if ( Size == 255 ) { |
350 | | |
351 | | /* check for next 4 bytes */ |
352 | 5 | if ( !tvb_bytes_exist(tvb, offset, 4) ) { |
353 | | |
354 | 1 | expert_add_info_format(pinfo, item, &ei_icep_context_missing, "second field of Size missing"); |
355 | 1 | col_append_str(pinfo->cinfo, COL_INFO, " (second field of Size missing)"); |
356 | | |
357 | 1 | (*consumed) = -1; |
358 | 1 | return; |
359 | 1 | } |
360 | | |
361 | | /* get second field of Size */ |
362 | 4 | Size = tvb_get_letohl(tvb, offset); |
363 | 4 | offset += 4; |
364 | 4 | (*consumed) += 4; |
365 | 4 | } |
366 | | |
367 | 45 | ws_debug("context.Size --> %d", Size); |
368 | | |
369 | 45 | if ( Size > icep_max_ice_context_pairs ) { |
370 | | |
371 | | /* display the XX Size byte when click here */ |
372 | 6 | expert_add_info(pinfo, item, &ei_icep_context_too_long); |
373 | | |
374 | 6 | col_append_str(pinfo->cinfo, COL_INFO, " (too long context)"); |
375 | | |
376 | 6 | (*consumed) = -1; |
377 | 6 | return; |
378 | 6 | } |
379 | | |
380 | 39 | if (Size == 0) { |
381 | 14 | s = "(empty)"; |
382 | | /* display the 0x00 Size byte when click on a empty context */ |
383 | 14 | proto_tree_add_string(tree, hf_icep_context, tvb, offset - 1, 1, s); |
384 | 14 | return; |
385 | 14 | } |
386 | | |
387 | | /* looping through the dictionary */ |
388 | 251 | for ( i = 0; i < Size; i++ ) { |
389 | | /* key */ |
390 | 245 | int32_t consumed_key = 0; |
391 | 245 | const uint8_t *str_key = NULL; |
392 | | /* value */ |
393 | 245 | int32_t consumed_value = 0; |
394 | 245 | const uint8_t *str_value = NULL; |
395 | 245 | proto_item *ti; |
396 | 245 | proto_tree *context_tree; |
397 | | |
398 | 245 | ws_debug("looping through context dictionary, loop #%d", i); |
399 | 245 | context_tree = proto_tree_add_subtree(tree, tvb, offset, -1, ett_icep_invocation_context, &ti, "Invocation Context"); |
400 | | |
401 | 245 | dissect_ice_string(pinfo, context_tree, ti, hf_icep_invocation_key, tvb, offset, &consumed_key, &str_key); |
402 | | |
403 | 245 | if ( consumed_key == -1 ) { |
404 | 8 | (*consumed) = -1; |
405 | 8 | return; |
406 | 8 | } |
407 | | |
408 | 237 | offset += consumed_key; |
409 | 237 | (*consumed) += consumed_key; |
410 | | |
411 | 237 | dissect_ice_string(pinfo, context_tree, ti, hf_icep_invocation_value, tvb, offset, &consumed_value, &str_value); |
412 | | |
413 | 237 | if ( consumed_value == -1 ) { |
414 | 11 | (*consumed) = -1; |
415 | 11 | return; |
416 | 11 | } |
417 | | |
418 | 226 | offset += consumed_value; |
419 | 226 | (*consumed) += consumed_value; |
420 | 226 | if (ti) |
421 | 226 | proto_item_set_len(ti, (consumed_key + consumed_value) + 1); |
422 | 226 | } |
423 | 25 | } |
424 | | |
425 | | /* |
426 | | * This function dissects an "Ice params", adds hf(s) to "tree" and returns consumed |
427 | | * bytes in "*consumed", if errors "*consumed" is -1. |
428 | | */ |
429 | | static void dissect_ice_params(packet_info *pinfo, proto_tree *tree, proto_item *item, tvbuff_t *tvb, |
430 | | uint32_t offset, int32_t *consumed) |
431 | 20 | { |
432 | | /* p. 612, chapter 23.3.2 and p. 587, 23.2.2: |
433 | | * "params" is an Encapsulation |
434 | | * |
435 | | * struct Encapsulation { |
436 | | * int size; |
437 | | * byte major; |
438 | | * byte minor; |
439 | | * //(size - 6) bytes of data |
440 | | * } |
441 | | * |
442 | | */ |
443 | | |
444 | 20 | int32_t size = 0; |
445 | 20 | int tvb_data_remained = 0; |
446 | | |
447 | 20 | (*consumed) = 0; |
448 | | |
449 | | /* check first 6 bytes */ |
450 | 20 | if ( !tvb_bytes_exist(tvb, offset, ICEP_MIN_PARAMS_SIZE) ) { |
451 | | |
452 | 2 | expert_add_info(pinfo, item, &ei_icep_params_missing); |
453 | 2 | col_append_str(pinfo->cinfo, COL_INFO, " (params missing)"); |
454 | | |
455 | 2 | (*consumed) = -1; |
456 | 2 | return; |
457 | 2 | } |
458 | | |
459 | | /* get the size */ |
460 | 18 | size = tvb_get_letohl(tvb, offset); |
461 | | |
462 | 18 | ws_debug("params.size --> %d", size); |
463 | | |
464 | 18 | if ( size < ICEP_MIN_PARAMS_SIZE ) { |
465 | | |
466 | 10 | expert_add_info(pinfo, item, &ei_icep_params_size); |
467 | 10 | col_append_str(pinfo->cinfo, COL_INFO, " (params size too small)"); |
468 | | |
469 | 10 | (*consumed) = -1; |
470 | 10 | return; |
471 | 10 | } |
472 | | |
473 | 8 | if ( tree ) { |
474 | | |
475 | 8 | proto_tree_add_item(tree, hf_icep_params_size, tvb, offset, 4, ENC_LITTLE_ENDIAN); |
476 | 8 | offset += 4; |
477 | 8 | (*consumed) += 4; |
478 | | |
479 | 8 | proto_tree_add_item(tree, hf_icep_params_major, tvb, offset, 1, ENC_LITTLE_ENDIAN); |
480 | 8 | offset += 1; |
481 | 8 | (*consumed)++; |
482 | | |
483 | 8 | proto_tree_add_item(tree, hf_icep_params_minor, tvb, offset, 1, ENC_LITTLE_ENDIAN); |
484 | 8 | offset += 1; |
485 | 8 | (*consumed)++; |
486 | | |
487 | 8 | } else { |
488 | | /* skip size, major, minor */ |
489 | 0 | offset += 6; |
490 | 0 | (*consumed) += 6; |
491 | 0 | } |
492 | | |
493 | 8 | if( size == ICEP_MIN_PARAMS_SIZE ) /* no encapsulated data present, it's normal */ |
494 | 0 | return; |
495 | | |
496 | | /* check if I got all encapsulated data */ |
497 | 8 | tvb_data_remained = tvb_reported_length_remaining(tvb, offset); |
498 | | |
499 | 8 | if ( tvb_data_remained < ( size - ICEP_MIN_PARAMS_SIZE ) ) { |
500 | | |
501 | 4 | expert_add_info_format(pinfo, item, &ei_icep_params_encapsulated, "missing encapsulated data (%d bytes)", size - ICEP_MIN_PARAMS_SIZE - tvb_data_remained); |
502 | | |
503 | 4 | col_append_fstr(pinfo->cinfo, COL_INFO, |
504 | 4 | " (missing encapsulated data (%d bytes))", |
505 | 4 | size - ICEP_MIN_PARAMS_SIZE - tvb_data_remained); |
506 | | |
507 | 4 | (*consumed) = -1; |
508 | 4 | return; |
509 | 4 | } |
510 | | |
511 | | /* encapsulated params */ |
512 | 4 | proto_tree_add_item(tree, hf_icep_params_encapsulated, tvb, offset, (size - ICEP_MIN_PARAMS_SIZE), ENC_NA); |
513 | | |
514 | 4 | (*consumed) += (size - ICEP_MIN_PARAMS_SIZE); |
515 | 4 | } |
516 | | |
517 | | static void dissect_icep_request_common(tvbuff_t *tvb, uint32_t offset, |
518 | | packet_info *pinfo, proto_tree *icep_sub_tree, proto_item* icep_sub_item, int32_t *total_consumed) |
519 | 84 | { |
520 | | /* p. 613, chapter 23.3.3 and p. 612 chapter 23.3.2: |
521 | | * Request and BatchRequest differ only in the first 4 bytes (requestID) |
522 | | * so them share this part |
523 | | * |
524 | | * Ice::Identity id; |
525 | | * Ice::StringSeq facet; |
526 | | * string operation; |
527 | | * byte mode; |
528 | | * Ice::Context context; |
529 | | * Encapsulation params; |
530 | | * } |
531 | | */ |
532 | | |
533 | 84 | int32_t consumed = 0; |
534 | 84 | const uint8_t *namestr = NULL; |
535 | 84 | const uint8_t *opstr = NULL; |
536 | | |
537 | 84 | (*total_consumed) = 0; |
538 | | |
539 | | /* check common header (i.e. the batch request one)*/ |
540 | 84 | if ( !tvb_bytes_exist(tvb, offset, ICEP_MIN_COMMON_REQ_HEADER_SIZE) ) { |
541 | | |
542 | 6 | expert_add_info_format(pinfo, icep_sub_item, &ei_icep_length, "too short header"); |
543 | 6 | col_append_str(pinfo->cinfo, COL_INFO, " (too short header)"); |
544 | | |
545 | 6 | goto error; |
546 | 6 | } |
547 | | |
548 | | /* got at least 15 bytes */ |
549 | | |
550 | | /* "id" is a: |
551 | | * struct Identity { |
552 | | * string name; |
553 | | * string category; |
554 | | * } |
555 | | */ |
556 | | |
557 | 78 | dissect_ice_string(pinfo, icep_sub_tree, icep_sub_item, hf_icep_id_name, tvb, offset, &consumed, &namestr); |
558 | | |
559 | 78 | if ( consumed == -1 ) |
560 | 6 | goto error; |
561 | | |
562 | 72 | offset += consumed; ws_debug("consumed --> %d", consumed); |
563 | 72 | (*total_consumed) += consumed; |
564 | | |
565 | | |
566 | 72 | dissect_ice_string(pinfo, icep_sub_tree, icep_sub_item, hf_icep_id_category, tvb, offset, &consumed, NULL); |
567 | | |
568 | 72 | if ( consumed == -1 ) |
569 | 6 | goto error; |
570 | | |
571 | 66 | offset += consumed; ws_debug("consumed --> %d", consumed); |
572 | 66 | (*total_consumed) += consumed; |
573 | | |
574 | | |
575 | | /* "facet" is a: |
576 | | * sequence<string> StringSeq |
577 | | * |
578 | | */ |
579 | | |
580 | 66 | dissect_ice_facet(pinfo, icep_sub_tree, icep_sub_item, hf_icep_facet, tvb, offset, &consumed); |
581 | | |
582 | 66 | if ( consumed == -1 ) |
583 | 13 | goto error; |
584 | | |
585 | 53 | offset += consumed; ws_debug("consumed --> %d", consumed); |
586 | 53 | (*total_consumed) += consumed; |
587 | | |
588 | | /* "operation" is an ice_string |
589 | | * |
590 | | */ |
591 | | |
592 | 53 | dissect_ice_string(pinfo, icep_sub_tree, icep_sub_item, hf_icep_operation, tvb, offset, &consumed, &opstr); |
593 | | |
594 | 53 | if ( consumed == -1 ) |
595 | 3 | goto error; |
596 | 50 | else { |
597 | 50 | offset += consumed; ws_debug("consumed --> %d", consumed); |
598 | 50 | (*total_consumed) += consumed; |
599 | | |
600 | 50 | if ( opstr && namestr ) { |
601 | 50 | ws_debug("operation --> %s.%s()", namestr, opstr); |
602 | 50 | col_append_fstr(pinfo->cinfo, COL_INFO, " %s.%s()", |
603 | 50 | namestr, opstr); |
604 | 50 | opstr = NULL; |
605 | 50 | namestr = NULL; |
606 | 50 | } |
607 | 50 | } |
608 | | |
609 | | /* check and get mode byte */ |
610 | 50 | if ( !tvb_bytes_exist(tvb, offset, 1) ) { |
611 | | |
612 | 2 | expert_add_info(pinfo, icep_sub_item, &ei_icep_mode_missing); |
613 | | |
614 | 2 | col_append_str(pinfo->cinfo, COL_INFO, " (mode field missing)"); |
615 | 2 | goto error; |
616 | 2 | } |
617 | | |
618 | 48 | proto_tree_add_item(icep_sub_tree, hf_icep_mode, tvb, offset, 1, ENC_LITTLE_ENDIAN); |
619 | | |
620 | 48 | offset++; ws_debug("consumed --> 1"); |
621 | 48 | (*total_consumed)++; |
622 | | |
623 | | |
624 | | /* "context" is a dictionary<string, string> |
625 | | * |
626 | | */ |
627 | | |
628 | 48 | dissect_ice_context(pinfo, icep_sub_tree, icep_sub_item, tvb, offset, &consumed); |
629 | | |
630 | 48 | if ( consumed == -1 ) |
631 | 28 | goto error; |
632 | | |
633 | 20 | offset += consumed; ws_debug("consumed --> %d", consumed); |
634 | 20 | (*total_consumed) += consumed; |
635 | | |
636 | | /* "params" is a Encapsulation |
637 | | * |
638 | | */ |
639 | | |
640 | 20 | dissect_ice_params(pinfo, icep_sub_tree, icep_sub_item, tvb, offset, &consumed); |
641 | | |
642 | 20 | if ( consumed == -1 ) |
643 | 16 | goto error; |
644 | | |
645 | | /*offset += consumed;*/ |
646 | 4 | ws_debug("consumed --> %d", consumed); |
647 | 4 | (*total_consumed) += consumed; |
648 | | |
649 | 4 | return; |
650 | | |
651 | 80 | error: |
652 | 80 | (*total_consumed) = -1; |
653 | 80 | } |
654 | | |
655 | | |
656 | | static void dissect_icep_request(tvbuff_t *tvb, uint32_t offset, |
657 | | packet_info *pinfo, proto_tree *icep_tree, proto_item* icep_item) |
658 | 85 | { |
659 | | /* p. 612, chapter 23.3.2: |
660 | | * |
661 | | * struct RequestData { |
662 | | * int requestID; |
663 | | * Ice::Identity id; |
664 | | * Ice::StringSeq facet; |
665 | | * string operation; |
666 | | * byte mode; |
667 | | * Ice::Context context; |
668 | | * Encapsulation params; |
669 | | * } |
670 | | */ |
671 | | |
672 | 85 | proto_item *ti = NULL; |
673 | 85 | proto_tree *icep_sub_tree = NULL; |
674 | 85 | int32_t consumed = 0; |
675 | 85 | uint32_t reqid = 0; |
676 | | |
677 | 85 | ws_debug("dissect request"); |
678 | | |
679 | | /* check for req id */ |
680 | 85 | if ( !tvb_bytes_exist(tvb, offset, 4) ) { |
681 | | |
682 | 2 | expert_add_info_format(pinfo, icep_item, &ei_icep_length, "too short header"); |
683 | 2 | col_append_str(pinfo->cinfo, COL_INFO, " (too short header)"); |
684 | 2 | return; |
685 | 2 | } |
686 | | |
687 | | /* got at least 4 bytes */ |
688 | | |
689 | | /* create display subtree for this message type */ |
690 | | |
691 | 83 | reqid = tvb_get_letohl(tvb, offset); |
692 | | |
693 | 83 | icep_sub_tree = proto_tree_add_subtree(icep_tree, tvb, offset, -1, ett_icep_msg, &ti, "Request Message Body"); |
694 | | |
695 | 83 | proto_tree_add_item(icep_sub_tree, hf_icep_request_id, tvb, offset, 4, ENC_LITTLE_ENDIAN); |
696 | | |
697 | 83 | if ( reqid != 0 ) { |
698 | 69 | col_append_fstr(pinfo->cinfo, COL_INFO, "(%d):", tvb_get_letohl(tvb, offset)); |
699 | 69 | } else |
700 | 14 | col_append_str(pinfo->cinfo, COL_INFO, "(oneway):"); |
701 | | |
702 | | |
703 | 83 | offset += 4; |
704 | 83 | ws_debug("consumed --> 4"); |
705 | | |
706 | 83 | dissect_icep_request_common(tvb, offset, pinfo, icep_sub_tree, ti, &consumed); |
707 | | |
708 | 83 | if ( consumed == -1 ) |
709 | 79 | return; |
710 | | |
711 | | /*offset += consumed;*/ |
712 | 4 | ws_debug("consumed --> %d", consumed); |
713 | 4 | } |
714 | | |
715 | | |
716 | | |
717 | | static void dissect_icep_batch_request(tvbuff_t *tvb, uint32_t offset, |
718 | | packet_info *pinfo, proto_tree *icep_tree, proto_item* icep_item) |
719 | 13 | { |
720 | | /* p. 613, chapter 23.3.3 |
721 | | * A batch request msg is a "sequence" of batch request |
722 | | * Sequence is Size + elements |
723 | | * |
724 | | * struct BatchRequestData { |
725 | | * Ice::Identity id; |
726 | | * Ice::StringSeq facet; |
727 | | * string operation; |
728 | | * byte mode; |
729 | | * Ice::Context context; |
730 | | * Encapsulation params; |
731 | | * } |
732 | | * |
733 | | * NOTE!!!: |
734 | | * The only real implementation of the Ice protocol puts a 32bit count in front |
735 | | * of a Batch Request, *not* an Ice::Sequence (as the standard says). Basically the |
736 | | * same people wrote both code and standard so I'll follow the code. |
737 | | */ |
738 | | |
739 | 13 | proto_item *ti = NULL; |
740 | 13 | proto_tree *icep_sub_tree = NULL; |
741 | 13 | uint32_t num_reqs = 0; |
742 | 13 | uint32_t i = 0; |
743 | 13 | int32_t consumed = 0; |
744 | | |
745 | 13 | ws_debug("dissect batch request"); |
746 | | |
747 | | /* check for first 4 byte */ |
748 | 13 | if ( !tvb_bytes_exist(tvb, offset, 4) ) { |
749 | | |
750 | 1 | expert_add_info_format(pinfo, icep_item, &ei_icep_length, "counter of batch requests missing"); |
751 | 1 | col_append_str(pinfo->cinfo, COL_INFO, " (counter of batch requests missing)"); |
752 | 1 | return; |
753 | 1 | } |
754 | | |
755 | 12 | num_reqs = tvb_get_letohl(tvb, offset); |
756 | 12 | offset += 4; |
757 | | |
758 | 12 | ws_debug("batch_requests.count --> %d", num_reqs); |
759 | | |
760 | 12 | if ( num_reqs > icep_max_batch_requests ) { |
761 | | |
762 | 10 | expert_add_info_format(pinfo, icep_item, &ei_icep_batch_requests, "too many batch requests (%d)", num_reqs); |
763 | | |
764 | 10 | col_append_fstr(pinfo->cinfo, COL_INFO, " (too many batch requests, %d)", num_reqs); |
765 | 10 | return; |
766 | 10 | } |
767 | | |
768 | 2 | if ( num_reqs == 0 ) { |
769 | | |
770 | 1 | proto_tree_add_expert(icep_tree, pinfo, &ei_icep_empty_batch, tvb, offset, -1); |
771 | 1 | col_append_str(pinfo->cinfo, COL_INFO, " (empty batch requests sequence)"); |
772 | | |
773 | 1 | return; |
774 | 1 | } |
775 | | |
776 | | |
777 | 1 | col_append_str(pinfo->cinfo, COL_INFO, ":"); |
778 | | |
779 | | /* |
780 | | * process requests |
781 | | */ |
782 | | |
783 | 1 | for ( i = 0; i < num_reqs; i++ ) { |
784 | | |
785 | 1 | ws_debug("looping through sequence of batch requests, loop #%d", i); |
786 | | |
787 | | /* create display subtree for this message type */ |
788 | | |
789 | 1 | icep_sub_tree = proto_tree_add_subtree_format(icep_tree, tvb, offset, -1, |
790 | 1 | ett_icep_msg, &ti, "Batch Request Message Body: #%d", i); |
791 | | |
792 | 1 | if (i != 0) { |
793 | 0 | col_append_str(pinfo->cinfo, COL_INFO, ","); |
794 | 0 | } |
795 | | |
796 | 1 | dissect_icep_request_common(tvb, offset, pinfo, icep_sub_tree, ti, &consumed); |
797 | | |
798 | 1 | if ( consumed == -1 ) |
799 | 1 | return; |
800 | | |
801 | 0 | if ( icep_tree && ti ) |
802 | 0 | proto_item_set_len(ti, consumed); |
803 | |
|
804 | 0 | offset += consumed; |
805 | 0 | ws_debug("consumed --> %d", consumed); |
806 | 0 | } |
807 | 1 | } |
808 | | |
809 | | static void dissect_icep_reply(tvbuff_t *tvb, uint32_t offset, |
810 | | packet_info *pinfo, proto_tree *icep_tree, proto_item* icep_item) |
811 | 5 | { |
812 | | /* p. 614, chapter 23.3.4: |
813 | | * |
814 | | * struct ReplyData { |
815 | | * int requestId; |
816 | | * byte replyStatus; |
817 | | * [... messageSize - 19 bytes ... ] |
818 | | * } |
819 | | */ |
820 | | |
821 | 5 | int32_t messageSize = 0; |
822 | 5 | uint32_t tvb_data_remained = 0; |
823 | 5 | uint32_t reported_reply_data = 0; |
824 | 5 | proto_item *ti = NULL; |
825 | 5 | proto_tree *icep_sub_tree = NULL; |
826 | | |
827 | 5 | ws_debug("dissect reply"); |
828 | | |
829 | | /* get at least a full reply message header */ |
830 | | |
831 | 5 | if ( !tvb_bytes_exist(tvb, offset, ICEP_MIN_REPLY_SIZE) ) { |
832 | | |
833 | 1 | expert_add_info_format(pinfo, icep_item, &ei_icep_length, "too short header"); |
834 | | |
835 | 1 | col_append_str(pinfo->cinfo, COL_INFO, " (too short header)"); |
836 | 1 | return; |
837 | 1 | } |
838 | | |
839 | | /* got 5 bytes, then data */ |
840 | | |
841 | | /* create display subtree for this message type */ |
842 | | |
843 | 4 | icep_sub_tree = proto_tree_add_subtree(icep_tree, tvb, offset, -1, |
844 | 4 | ett_icep_msg, &ti, "Reply Message Body"); |
845 | | |
846 | 4 | proto_tree_add_item(icep_sub_tree, hf_icep_request_id, tvb, offset, 4, ENC_LITTLE_ENDIAN); |
847 | | |
848 | 4 | col_append_fstr(pinfo->cinfo, COL_INFO, "(%d):", tvb_get_letohl(tvb, offset)); |
849 | | |
850 | 4 | offset += 4; |
851 | | |
852 | 4 | proto_tree_add_item(icep_sub_tree, hf_icep_reply_status, tvb, offset, 1, ENC_LITTLE_ENDIAN); |
853 | | |
854 | 4 | col_append_fstr(pinfo->cinfo, COL_INFO, " %s", |
855 | 4 | val_to_str_const(tvb_get_uint8(tvb, offset), |
856 | 4 | icep_replystatus_vals, |
857 | 4 | "unknown reply status")); |
858 | | |
859 | 4 | offset++; |
860 | | |
861 | 4 | ws_debug("consumed --> %d", 5); |
862 | | |
863 | | /* check if I got all reply data */ |
864 | 4 | tvb_data_remained = tvb_reported_length_remaining(tvb, offset); |
865 | 4 | messageSize = tvb_get_letohl(tvb, 10); |
866 | 4 | reported_reply_data = messageSize - (ICEP_HEADER_SIZE + ICEP_MIN_REPLY_SIZE); |
867 | | |
868 | | /* no */ |
869 | 4 | if ( tvb_data_remained < reported_reply_data ) { |
870 | | |
871 | 2 | expert_add_info_format(pinfo, ti, &ei_icep_reply_data, "Reply Data (missing %d bytes out of %d)", reported_reply_data - tvb_data_remained, reported_reply_data); |
872 | | |
873 | 2 | col_append_fstr(pinfo->cinfo, COL_INFO, |
874 | 2 | " (missing reply data, %d bytes)", |
875 | 2 | reported_reply_data - tvb_data_remained); |
876 | | |
877 | | /*offset += tvb_data_remained;*/ |
878 | 2 | ws_debug("consumed --> %d", tvb_data_remained); |
879 | 2 | return; |
880 | 2 | } |
881 | | |
882 | | /* yes (reported_reply_data can be 0) */ |
883 | | |
884 | 2 | proto_tree_add_item(icep_sub_tree, hf_icep_reply_data, tvb, offset, reported_reply_data, ENC_NA); |
885 | | |
886 | | /*offset += reported_reply_data;*/ |
887 | 2 | ws_debug("consumed --> %d", reported_reply_data); |
888 | 2 | } |
889 | | |
890 | | static unsigned get_icep_pdu_len(packet_info *pinfo _U_, tvbuff_t *tvb, |
891 | | int offset, void *data _U_) |
892 | 72 | { |
893 | 72 | return tvb_get_letohl(tvb, offset + 10); |
894 | 72 | } |
895 | | |
896 | | static int dissect_icep_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_) |
897 | 118 | { |
898 | | /* p. 611, chapter 23.3.1: |
899 | | * |
900 | | * struct HeaderData { |
901 | | * int magic; |
902 | | * byte protocolMajor; |
903 | | * byte protocolMinor; |
904 | | * byte encodingMajor; |
905 | | * byte encodingMinor; |
906 | | * byte messageType; |
907 | | * byte compressionStatus; |
908 | | * int messageSize; |
909 | | * } |
910 | | */ |
911 | | |
912 | 118 | proto_item *ti, *msg_item = NULL; |
913 | 118 | proto_tree *icep_tree; |
914 | 118 | uint32_t offset = 0; |
915 | | |
916 | | /* Make entries in Protocol column and Info column on summary display */ |
917 | | |
918 | 118 | col_set_str(pinfo->cinfo, COL_PROTOCOL, "ICEP"); |
919 | | |
920 | 118 | col_add_str(pinfo->cinfo, COL_INFO, |
921 | 118 | val_to_str(pinfo->pool, tvb_get_uint8(tvb, 8), |
922 | 118 | icep_msgtype_vals, |
923 | 118 | "Unknown Message Type: 0x%02x")); |
924 | | |
925 | 118 | ws_debug("got an icep msg, start analysis"); |
926 | | |
927 | | /* create display subtree for the protocol */ |
928 | | |
929 | 118 | ti = proto_tree_add_item(tree, proto_icep, tvb, 0, -1, ENC_NA); |
930 | 118 | icep_tree = proto_item_add_subtree(ti, ett_icep); |
931 | | |
932 | 118 | if (icep_tree) { |
933 | | /* add items to the subtree */ |
934 | | |
935 | | /* message header */ |
936 | | |
937 | 118 | proto_tree_add_item(icep_tree, hf_icep_magic_number, tvb, offset, 4, ENC_ASCII); |
938 | 118 | offset += 4; |
939 | | |
940 | 118 | proto_tree_add_item(icep_tree, hf_icep_protocol_major, |
941 | 118 | tvb, offset, 1, ENC_LITTLE_ENDIAN); |
942 | 118 | offset++; |
943 | | |
944 | 118 | proto_tree_add_item(icep_tree, hf_icep_protocol_minor, |
945 | 118 | tvb, offset, 1, ENC_LITTLE_ENDIAN); |
946 | 118 | offset++; |
947 | | |
948 | 118 | proto_tree_add_item(icep_tree, hf_icep_encoding_major, |
949 | 118 | tvb, offset, 1, ENC_LITTLE_ENDIAN); |
950 | 118 | offset++; |
951 | | |
952 | 118 | proto_tree_add_item(icep_tree, hf_icep_encoding_minor, |
953 | 118 | tvb, offset, 1, ENC_LITTLE_ENDIAN); |
954 | 118 | offset++; |
955 | | |
956 | 118 | msg_item = proto_tree_add_item(icep_tree, hf_icep_message_type, |
957 | 118 | tvb, offset, 1, ENC_LITTLE_ENDIAN); |
958 | 118 | offset++; |
959 | | |
960 | 118 | proto_tree_add_item(icep_tree, hf_icep_compression_status, |
961 | 118 | tvb, offset, 1, ENC_LITTLE_ENDIAN); |
962 | 118 | offset++; |
963 | | |
964 | 118 | proto_tree_add_item(icep_tree, hf_icep_message_size, |
965 | 118 | tvb, offset, 4, ENC_LITTLE_ENDIAN); |
966 | 118 | offset += 4; |
967 | 118 | } else { |
968 | 0 | offset += ICEP_HEADER_SIZE; |
969 | 0 | } |
970 | | |
971 | 118 | switch(tvb_get_uint8(tvb, 8)) { |
972 | 85 | case 0x0: |
973 | 85 | ws_debug("request message body: parsing %d bytes", |
974 | 85 | tvb_captured_length_remaining(tvb, offset)); |
975 | 85 | dissect_icep_request(tvb, offset, pinfo, icep_tree, ti); |
976 | 85 | break; |
977 | 13 | case 0x1: |
978 | 13 | ws_debug("batch request message body: parsing %d bytes", |
979 | 13 | tvb_captured_length_remaining(tvb, offset)); |
980 | 13 | dissect_icep_batch_request(tvb, offset, pinfo, icep_tree, ti); |
981 | 13 | break; |
982 | 5 | case 0x2: |
983 | 5 | ws_debug("reply message body: parsing %d bytes", |
984 | 5 | tvb_captured_length_remaining(tvb, offset)); |
985 | 5 | dissect_icep_reply(tvb, offset, pinfo, icep_tree, ti); |
986 | 5 | break; |
987 | 2 | case 0x3: |
988 | 4 | case 0x4: |
989 | | /* messages already dissected */ |
990 | 4 | break; |
991 | 10 | default: |
992 | 10 | expert_add_info_format(pinfo, msg_item, &ei_icep_message_type, "Unknown Message Type: 0x%02x", tvb_get_uint8(tvb, 8)); |
993 | 10 | break; |
994 | 118 | } |
995 | 114 | return tvb_captured_length(tvb); |
996 | 118 | } |
997 | | |
998 | | /* entry point */ |
999 | | static gboolean dissect_icep_tcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data) |
1000 | 3.98k | { |
1001 | 3.98k | ws_debug("triggered"); |
1002 | | |
1003 | 3.98k | if ( tvb_memeql(tvb, 0, icep_magic, 4) == -1 ) { |
1004 | | /* Not a ICEP packet. */ |
1005 | 3.92k | return FALSE; |
1006 | 3.92k | } |
1007 | | |
1008 | | /* start dissecting */ |
1009 | | |
1010 | 58 | tcp_dissect_pdus(tvb, pinfo, tree, true, ICEP_HEADER_SIZE, |
1011 | 58 | get_icep_pdu_len, dissect_icep_pdu, data); |
1012 | | |
1013 | 58 | return TRUE; |
1014 | 3.98k | } |
1015 | | |
1016 | | static bool |
1017 | | dissect_icep_tcp_heur(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data) |
1018 | 3.98k | { |
1019 | 3.98k | return (bool)dissect_icep_tcp(tvb, pinfo, tree, data) > 0; |
1020 | 3.98k | } |
1021 | | |
1022 | | static gboolean dissect_icep_udp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data) |
1023 | 2.12k | { |
1024 | 2.12k | ws_debug("triggered"); |
1025 | | |
1026 | 2.12k | if ( tvb_memeql(tvb, 0, icep_magic, 4) == -1 ) { |
1027 | | /* Not a ICEP packet. */ |
1028 | 2.07k | return false; |
1029 | 2.07k | } |
1030 | | |
1031 | | /* start dissecting */ |
1032 | 52 | dissect_icep_pdu(tvb, pinfo, tree, data); |
1033 | 52 | return true; |
1034 | 2.12k | } |
1035 | | |
1036 | | static bool |
1037 | | dissect_icep_udp_heur(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data) |
1038 | 2.12k | { |
1039 | 2.12k | return (bool)dissect_icep_udp(tvb, pinfo, tree, data) > 0; |
1040 | 2.12k | } |
1041 | | |
1042 | | /* Register the protocol with Wireshark */ |
1043 | | |
1044 | | void proto_register_icep(void) |
1045 | 14 | { |
1046 | 14 | module_t *icep_module; |
1047 | 14 | expert_module_t* expert_icep; |
1048 | | |
1049 | | /* Setup list of header fields */ |
1050 | | |
1051 | 14 | static hf_register_info hf[] = { |
1052 | | |
1053 | 14 | { &hf_icep_protocol_major, |
1054 | 14 | { |
1055 | 14 | "Protocol Major", "icep.protocol_major", |
1056 | 14 | FT_INT8, BASE_DEC, NULL, 0x0, |
1057 | 14 | "The protocol major version number", HFILL |
1058 | 14 | } |
1059 | 14 | }, |
1060 | | |
1061 | 14 | { &hf_icep_protocol_minor, |
1062 | 14 | { |
1063 | 14 | "Protocol Minor", "icep.protocol_minor", |
1064 | 14 | FT_INT8, BASE_DEC, NULL, 0x0, |
1065 | 14 | "The protocol minor version number", HFILL |
1066 | 14 | } |
1067 | 14 | }, |
1068 | | |
1069 | 14 | { &hf_icep_encoding_major, |
1070 | 14 | { |
1071 | 14 | "Encoding Major", "icep.encoding_major", |
1072 | 14 | FT_INT8, BASE_DEC, NULL, 0x0, |
1073 | 14 | "The encoding major version number", HFILL |
1074 | 14 | } |
1075 | 14 | }, |
1076 | | |
1077 | 14 | { &hf_icep_encoding_minor, |
1078 | 14 | { |
1079 | 14 | "Encoding Minor", "icep.encoding_minor", |
1080 | 14 | FT_INT8, BASE_DEC, NULL, 0x0, |
1081 | 14 | "The encoding minor version number", HFILL |
1082 | 14 | } |
1083 | 14 | }, |
1084 | | |
1085 | 14 | { &hf_icep_message_type, |
1086 | 14 | { |
1087 | 14 | "Message Type", "icep.message_type", |
1088 | 14 | FT_INT8, BASE_DEC, VALS(icep_msgtype_vals), 0x0, |
1089 | 14 | "The message type", HFILL |
1090 | 14 | } |
1091 | 14 | }, |
1092 | | |
1093 | 14 | { &hf_icep_magic_number, |
1094 | 14 | { |
1095 | 14 | "Magic Number", "icep.magic_number", |
1096 | 14 | FT_STRING, BASE_NONE, NULL, 0x0, |
1097 | 14 | NULL, HFILL |
1098 | 14 | } |
1099 | 14 | }, |
1100 | | |
1101 | 14 | { &hf_icep_compression_status, |
1102 | 14 | { |
1103 | 14 | "Compression Status", "icep.compression_status", |
1104 | 14 | FT_INT8, BASE_DEC, VALS(icep_zipstatus_vals), 0x0, |
1105 | 14 | "The compression status of the message", HFILL |
1106 | 14 | } |
1107 | 14 | }, |
1108 | | |
1109 | 14 | { &hf_icep_message_size, |
1110 | 14 | { |
1111 | 14 | "Message Size", "icep.message_status", |
1112 | 14 | FT_INT32, BASE_DEC, NULL, 0x0, |
1113 | 14 | "The size of the message in bytes, including the header", |
1114 | 14 | HFILL |
1115 | 14 | } |
1116 | 14 | }, |
1117 | | |
1118 | 14 | { &hf_icep_request_id, |
1119 | 14 | { |
1120 | 14 | "Request Identifier", "icep.request_id", |
1121 | 14 | FT_INT32, BASE_DEC, NULL, 0x0, |
1122 | 14 | "The request identifier", |
1123 | 14 | HFILL |
1124 | 14 | } |
1125 | 14 | }, |
1126 | | |
1127 | 14 | { &hf_icep_reply_status, |
1128 | 14 | { |
1129 | 14 | "Reply Status", "icep.protocol_major", |
1130 | 14 | FT_INT8, BASE_DEC, VALS(icep_replystatus_vals), 0x0, |
1131 | 14 | "The reply status", HFILL |
1132 | 14 | } |
1133 | 14 | }, |
1134 | | |
1135 | 14 | { &hf_icep_id_name, |
1136 | 14 | { |
1137 | 14 | "Object Identity Name", "icep.id.name", |
1138 | 14 | FT_STRINGZ, BASE_NONE, NULL, 0x0, |
1139 | 14 | "The object identity name", HFILL |
1140 | 14 | } |
1141 | 14 | }, |
1142 | | |
1143 | 14 | { &hf_icep_id_category, |
1144 | 14 | { |
1145 | 14 | "Object Identity Content", "icep.id.content", |
1146 | 14 | FT_STRINGZ, BASE_NONE, NULL, 0x0, |
1147 | 14 | "The object identity content", HFILL |
1148 | 14 | } |
1149 | 14 | }, |
1150 | | |
1151 | 14 | { &hf_icep_facet, |
1152 | 14 | { |
1153 | 14 | "Facet Name", "icep.facet", |
1154 | 14 | FT_STRINGZ, BASE_NONE, NULL, 0x0, |
1155 | 14 | "The facet name", HFILL |
1156 | 14 | } |
1157 | 14 | }, |
1158 | | |
1159 | 14 | { &hf_icep_operation, |
1160 | 14 | { |
1161 | 14 | "Operation Name", "icep.operation", |
1162 | 14 | FT_STRINGZ, BASE_NONE, NULL, 0x0, |
1163 | 14 | "The operation name", HFILL |
1164 | 14 | } |
1165 | 14 | }, |
1166 | | |
1167 | 14 | { &hf_icep_mode, |
1168 | 14 | { |
1169 | 14 | "Ice::OperationMode", "icep.operation_mode", |
1170 | 14 | FT_INT8, BASE_DEC, VALS(icep_mode_vals), 0x0, |
1171 | 14 | "A byte representing Ice::OperationMode", HFILL |
1172 | 14 | } |
1173 | 14 | }, |
1174 | | |
1175 | 14 | { &hf_icep_context, |
1176 | 14 | { |
1177 | 14 | "Invocation Context", "icep.context", |
1178 | 14 | FT_STRINGZ, BASE_NONE, NULL, 0x0, |
1179 | 14 | "The invocation context", HFILL |
1180 | 14 | } |
1181 | 14 | }, |
1182 | | |
1183 | 14 | { &hf_icep_params_size, |
1184 | 14 | { |
1185 | 14 | "Input Parameters Size", "icep.params.size", |
1186 | 14 | FT_INT32, BASE_DEC, NULL, 0x0, |
1187 | 14 | "The encapsulated input parameters size", |
1188 | 14 | HFILL |
1189 | 14 | } |
1190 | 14 | }, |
1191 | | |
1192 | 14 | { &hf_icep_params_major, |
1193 | 14 | { |
1194 | 14 | "Input Parameters Encoding Major", |
1195 | 14 | "icep.params.major", |
1196 | 14 | FT_INT8, BASE_DEC, NULL, 0x0, |
1197 | 14 | "The major encoding version of encapsulated parameters", |
1198 | 14 | HFILL |
1199 | 14 | } |
1200 | 14 | }, |
1201 | | |
1202 | 14 | { &hf_icep_params_minor, |
1203 | 14 | { |
1204 | 14 | "Input Parameters Encoding Minor", |
1205 | 14 | "icep.params.minor", |
1206 | 14 | FT_INT8, BASE_DEC, NULL, 0x0, |
1207 | 14 | "The minor encoding version of encapsulated parameters", |
1208 | 14 | HFILL |
1209 | 14 | } |
1210 | 14 | }, |
1211 | | |
1212 | 14 | { &hf_icep_params_encapsulated, |
1213 | 14 | { |
1214 | 14 | "Encapsulated parameters", |
1215 | 14 | "icep.params.encapsulated", |
1216 | 14 | FT_BYTES, BASE_NONE, NULL, 0x0, |
1217 | 14 | "Remaining encapsulated parameters", |
1218 | 14 | HFILL |
1219 | 14 | } |
1220 | 14 | }, |
1221 | | |
1222 | 14 | { &hf_icep_reply_data, |
1223 | 14 | { |
1224 | 14 | "Reported reply data", |
1225 | 14 | "icep.params.reply_data", |
1226 | 14 | FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL |
1227 | 14 | } |
1228 | 14 | }, |
1229 | | |
1230 | 14 | { &hf_icep_invocation_key, |
1231 | 14 | { |
1232 | 14 | "Key", |
1233 | 14 | "icep.invocation_key", |
1234 | 14 | FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL |
1235 | 14 | } |
1236 | 14 | }, |
1237 | | |
1238 | 14 | { &hf_icep_invocation_value, |
1239 | 14 | { |
1240 | 14 | "Value", |
1241 | 14 | "icep.invocation_value", |
1242 | 14 | FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL |
1243 | 14 | } |
1244 | 14 | }, |
1245 | 14 | }; |
1246 | | |
1247 | | /* Setup protocol subtree array */ |
1248 | | |
1249 | 14 | static int *ett[] = { |
1250 | 14 | &ett_icep, |
1251 | 14 | &ett_icep_msg, |
1252 | 14 | &ett_icep_invocation_context, |
1253 | 14 | }; |
1254 | | |
1255 | 14 | static ei_register_info ei[] = { |
1256 | 14 | { &ei_icep_string_malformed, { "icep.string.malformed", PI_MALFORMED, PI_ERROR, "String malformed", EXPFILL }}, |
1257 | 14 | { &ei_icep_string_too_long, { "icep.string.too_long", PI_PROTOCOL, PI_WARN, "string too long", EXPFILL }}, |
1258 | 14 | { &ei_icep_facet_missing, { "icep.facet.missing", PI_MALFORMED, PI_ERROR, "facet field missing", EXPFILL }}, |
1259 | 14 | { &ei_icep_facet_max_one_element, { "icep.facet.max_one_element", PI_PROTOCOL, PI_WARN, "facet can be max one element", EXPFILL }}, |
1260 | 14 | { &ei_icep_context_missing, { "icep.context.missing", PI_MALFORMED, PI_ERROR, "context missing", EXPFILL }}, |
1261 | 14 | { &ei_icep_context_too_long, { "icep.context.too_long", PI_PROTOCOL, PI_WARN, "too long context", EXPFILL }}, |
1262 | 14 | { &ei_icep_params_missing, { "icep.params.missing", PI_MALFORMED, PI_ERROR, "params missing", EXPFILL }}, |
1263 | 14 | { &ei_icep_params_size, { "icep.params.size.invalid", PI_PROTOCOL, PI_WARN, "params size too small", EXPFILL }}, |
1264 | 14 | { &ei_icep_params_encapsulated, { "icep.params.encapsulated.missing", PI_PROTOCOL, PI_WARN, "missing encapsulated data", EXPFILL }}, |
1265 | 14 | { &ei_icep_length, { "icep.length_invalid", PI_MALFORMED, PI_ERROR, "Invalid length", EXPFILL }}, |
1266 | 14 | { &ei_icep_mode_missing, { "icep.mode.missing", PI_MALFORMED, PI_ERROR, "mode field missing", EXPFILL }}, |
1267 | 14 | { &ei_icep_batch_requests, { "icep.batch_requests.invalid", PI_PROTOCOL, PI_WARN, "too many batch requests", EXPFILL }}, |
1268 | 14 | { &ei_icep_empty_batch, { "icep.batch_requests.empty", PI_PROTOCOL, PI_WARN, "empty batch requests sequence", EXPFILL }}, |
1269 | 14 | { &ei_icep_reply_data, { "icep.params.reply_data.missing", PI_MALFORMED, PI_ERROR, "Reply Data missing", EXPFILL }}, |
1270 | 14 | { &ei_icep_message_type, { "icep.message_type.unknown", PI_PROTOCOL, PI_WARN, "Unknown Message Type", EXPFILL }}, |
1271 | 14 | }; |
1272 | | |
1273 | | /* Register the protocol name and description */ |
1274 | | |
1275 | 14 | proto_icep = |
1276 | 14 | proto_register_protocol("Internet Communications Engine Protocol", "ICEP", "icep"); |
1277 | | |
1278 | | /* Required function calls to register the header fields and subtrees used */ |
1279 | | |
1280 | 14 | proto_register_field_array(proto_icep, hf, array_length(hf)); |
1281 | 14 | proto_register_subtree_array(ett, array_length(ett)); |
1282 | 14 | expert_icep = expert_register_protocol(proto_icep); |
1283 | 14 | expert_register_field_array(expert_icep, ei, array_length(ei)); |
1284 | | |
1285 | 14 | icep_module = prefs_register_protocol(proto_icep, NULL); |
1286 | 14 | prefs_register_uint_preference(icep_module, "max_batch_requests", |
1287 | 14 | "Maximum batch requests", |
1288 | 14 | "Maximum number of batch requests allowed", |
1289 | 14 | 10, &icep_max_batch_requests); |
1290 | | |
1291 | 14 | prefs_register_uint_preference(icep_module, "max_ice_string_len", |
1292 | 14 | "Maximum string length", |
1293 | 14 | "Maximum length allowed of an ICEP string", |
1294 | 14 | 10, &icep_max_ice_string_len); |
1295 | | |
1296 | 14 | prefs_register_uint_preference(icep_module, "max_ice_context_pairs", |
1297 | 14 | "Maximum context pairs", |
1298 | 14 | "Maximum number of context pairs allowed", |
1299 | 14 | 10, &icep_max_ice_context_pairs); |
1300 | | |
1301 | 14 | icep_tcp_handle = register_dissector("iecp.tcp", dissect_icep_tcp, proto_icep); |
1302 | 14 | icep_udp_handle = register_dissector("iecp.udp", dissect_icep_udp, proto_icep); |
1303 | 14 | } |
1304 | | |
1305 | | |
1306 | | void proto_reg_handoff_icep(void) |
1307 | 14 | { |
1308 | | /* Register as a heuristic TCP/UDP dissector */ |
1309 | 14 | heur_dissector_add("tcp", dissect_icep_tcp_heur, "ICEP over TCP", "icep_tcp", proto_icep, HEURISTIC_ENABLE); |
1310 | 14 | heur_dissector_add("udp", dissect_icep_udp_heur, "ICEP over UDP", "icep_udp", proto_icep, HEURISTIC_ENABLE); |
1311 | | |
1312 | | /* Register TCP port for dissection */ |
1313 | 14 | dissector_add_for_decode_as_with_preference("tcp.port", icep_tcp_handle); |
1314 | | /* Register UDP port for dissection */ |
1315 | 14 | dissector_add_for_decode_as_with_preference("udp.port", icep_udp_handle); |
1316 | 14 | } |
1317 | | |
1318 | | /* |
1319 | | * Editor modelines - https://www.wireshark.org/tools/modelines.html |
1320 | | * |
1321 | | * Local variables: |
1322 | | * c-basic-offset: 4 |
1323 | | * tab-width: 8 |
1324 | | * indent-tabs-mode: nil |
1325 | | * End: |
1326 | | * |
1327 | | * vi: set shiftwidth=4 tabstop=8 expandtab: |
1328 | | * :indentSize=4:tabSize=8:noTabs=true: |
1329 | | */ |