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