/src/wireshark/epan/dissectors/packet-fix.c
Line | Count | Source |
1 | | /* packet-fix.c |
2 | | * Routines for Financial Information eXchange (FIX) Protocol dissection |
3 | | * Copyright 2000, PC Drew <drewpc@ibsncentral.com> |
4 | | * |
5 | | * Wireshark - Network traffic analyzer |
6 | | * By Gerald Combs <gerald@wireshark.org> |
7 | | * Copyright 1998 Gerald Combs |
8 | | * |
9 | | * SPDX-License-Identifier: GPL-2.0-or-later |
10 | | * |
11 | | * Documentation: http://www.fixprotocol.org/ |
12 | | * Fields and messages from http://www.quickfixengine.org/ and http://sourceforge.net/projects/quickfix/files/ xml |
13 | | * |
14 | | */ |
15 | | |
16 | | #include "config.h" |
17 | | |
18 | | #include <stdlib.h> |
19 | | |
20 | | #include <epan/packet.h> |
21 | | #include <epan/expert.h> |
22 | | #include <epan/prefs.h> |
23 | | |
24 | | #include <wsutil/strtoi.h> |
25 | | |
26 | | #include "packet-tcp.h" |
27 | | #include "packet-tls.h" |
28 | | |
29 | | void proto_register_fix(void); |
30 | | void proto_reg_handoff_fix(void); |
31 | | |
32 | | typedef struct _fix_parameter { |
33 | | unsigned field_len; |
34 | | unsigned tag_len; |
35 | | unsigned value_offset; |
36 | | unsigned value_len; |
37 | | unsigned ctrla_offset; |
38 | | } fix_parameter; |
39 | | |
40 | | /* Initialize the protocol and registered fields */ |
41 | | static int proto_fix; |
42 | | |
43 | | /* desegmentation of fix */ |
44 | | static bool fix_desegment = true; |
45 | | |
46 | | /* Initialize the subtree pointers */ |
47 | | static int ett_fix; |
48 | | static int ett_unknown; |
49 | | static int ett_badfield; |
50 | | static int ett_checksum; |
51 | | |
52 | | static expert_field ei_fix_checksum_bad; |
53 | | static expert_field ei_fix_missing_field; |
54 | | static expert_field ei_fix_tag_invalid; |
55 | | static expert_field ei_fix_field_invalid; |
56 | | |
57 | | static int hf_fix_data; /* continuation data */ |
58 | | static int hf_fix_checksum_good; |
59 | | static int hf_fix_checksum_bad; |
60 | | static int hf_fix_field_value; |
61 | | static int hf_fix_field_tag; |
62 | | |
63 | | static dissector_handle_t fix_handle; |
64 | | |
65 | | /* 8=FIX */ |
66 | 3.87k | #define MARKER_TAG "8=FIX" |
67 | 3.88k | #define MARKER_LEN 5 |
68 | | |
69 | | static int fix_marker(tvbuff_t *tvb, unsigned offset) |
70 | 3.87k | { |
71 | 3.87k | return tvb_strneql(tvb, offset, MARKER_TAG, MARKER_LEN); |
72 | 3.87k | } |
73 | | |
74 | | /* |
75 | | * Fields and messages generated from http://www.quickfixengine.org/ xml (slightly modified) |
76 | | */ |
77 | | |
78 | | #include "packet-fix.h" |
79 | | |
80 | 16 | static void dissect_fix_init(void) { |
81 | | /* TODO load xml def for private field */ |
82 | | /* TODO check that fix_fields is really sorted */ |
83 | 16 | } |
84 | | |
85 | | static int |
86 | | fix_field_tag_compar(const void *v_needle, const void *v_entry) |
87 | 0 | { |
88 | 0 | int key = *(const int *)v_needle; |
89 | 0 | int entry_tag = ((const fix_field *)v_entry)->tag; |
90 | 0 | return key > entry_tag ? 1 : (key < entry_tag ? -1 : 0); |
91 | 0 | } |
92 | | |
93 | | /* Code to actually dissect the packets */ |
94 | | static int fix_next_header(tvbuff_t *tvb, packet_info* pinfo, unsigned offset) |
95 | 94 | { |
96 | | /* try to resync to the next start */ |
97 | 94 | unsigned min_len = tvb_captured_length_remaining(tvb, offset); |
98 | 94 | const char *data = (char*)tvb_get_string_enc(pinfo->pool, tvb, offset, min_len, ENC_ASCII); |
99 | 94 | const char *start = data; |
100 | | |
101 | 95 | while ((start = strstr(start, "\0018"))) { |
102 | 2 | min_len = (unsigned) (start +1 -data); |
103 | | /* if remaining length < 6 return and let the next desegment round |
104 | | test for 8=FIX |
105 | | */ |
106 | 2 | if (tvb_reported_length_remaining(tvb, min_len + offset) < MARKER_LEN) |
107 | 0 | break; |
108 | 2 | if (!fix_marker(tvb, min_len +offset) ) |
109 | 1 | break; |
110 | 1 | start++; |
111 | 1 | } |
112 | 94 | return min_len; |
113 | 94 | } |
114 | | |
115 | | /* ---------------------------------------------- |
116 | | Format: name=value\001 |
117 | | */ |
118 | | static fix_parameter *fix_param(tvbuff_t *tvb, unsigned offset) |
119 | 35 | { |
120 | 35 | static fix_parameter ret; |
121 | 35 | unsigned equals; |
122 | | |
123 | 35 | if (!tvb_find_uint8_remaining(tvb, offset, 0x01, &ret.ctrla_offset)) { |
124 | 11 | return NULL; |
125 | 11 | } |
126 | | |
127 | 24 | ret.field_len = ret.ctrla_offset - offset + 1; |
128 | 24 | if (!tvb_find_uint8_length(tvb, offset, ret.field_len, '=', &equals)) { |
129 | 12 | return NULL; |
130 | 12 | } |
131 | | |
132 | 12 | ret.value_offset = equals + 1; |
133 | 12 | ret.tag_len = ret.value_offset - offset - 1; |
134 | 12 | ret.value_len = ret.ctrla_offset - ret.value_offset; |
135 | 12 | return &ret; |
136 | 24 | } |
137 | | |
138 | | /* ---------------------------------------------- */ |
139 | | static unsigned |
140 | | fix_header_len(tvbuff_t *tvb, packet_info* pinfo, unsigned offset) |
141 | 94 | { |
142 | 94 | unsigned base_offset, ctrla_offset; |
143 | 94 | int32_t value; |
144 | 94 | unsigned size; |
145 | 94 | fix_parameter *tag; |
146 | | |
147 | 94 | base_offset = offset; |
148 | | |
149 | | /* get at least the fix version: 8=FIX.x.x */ |
150 | 94 | if (fix_marker(tvb, offset) != 0) { |
151 | 62 | return fix_next_header(tvb, pinfo, offset); |
152 | 62 | } |
153 | | |
154 | | /* begin string */ |
155 | 32 | if (!tvb_find_uint8_length(tvb, offset, -1, 0x01, &ctrla_offset)) { |
156 | | /* it should be there, (minimum size is big enough) |
157 | | * if not maybe it's not really |
158 | | * a FIX packet but it's too late to bail out. |
159 | | */ |
160 | 5 | return fix_next_header(tvb, pinfo, offset +MARKER_LEN) +MARKER_LEN; |
161 | 5 | } |
162 | 27 | offset = ctrla_offset + 1; |
163 | | |
164 | | /* msg length */ |
165 | 27 | if (!(tag = fix_param(tvb, offset)) || tvb_strneql(tvb, offset, "9=", 2)) { |
166 | | /* not a tag or not the BodyLength tag, give up */ |
167 | 27 | return fix_next_header(tvb, pinfo, offset); |
168 | 27 | } |
169 | | |
170 | 0 | if (!tvb_get_string_int(tvb, tag->value_offset, tag->value_len, ENC_STR_DEC, &value, NULL)) |
171 | 0 | return fix_next_header(tvb, pinfo, base_offset +MARKER_LEN) +MARKER_LEN; |
172 | | /* Fix version, msg type, length and checksum aren't in body length. |
173 | | * If the packet is big enough find the checksum |
174 | | */ |
175 | 0 | size = value + tag->ctrla_offset - base_offset + 1; |
176 | 0 | if (tvb_reported_length_remaining(tvb, base_offset) > size +4) { |
177 | | /* 10= should be there */ |
178 | 0 | offset = base_offset +size; |
179 | 0 | if (tvb_strneql(tvb, offset, "10=", 3) != 0) { |
180 | | /* No? bogus packet, try to find the next header */ |
181 | 0 | return fix_next_header(tvb, pinfo, base_offset +MARKER_LEN) +MARKER_LEN; |
182 | 0 | } |
183 | 0 | if (!tvb_find_uint8_remaining(tvb, offset, 0x01, &ctrla_offset)) { |
184 | | /* assume checksum is 7 bytes 10=xxx\01 */ |
185 | 0 | return size+7; |
186 | 0 | } |
187 | 0 | return size +ctrla_offset -offset +1; |
188 | 0 | } |
189 | 0 | else { |
190 | 0 | } |
191 | | /* assume checksum is 7 bytes 10=xxx\01 */ |
192 | 0 | return size +7; |
193 | 0 | } |
194 | | |
195 | | /* ---------------------------------------------- */ |
196 | | static int |
197 | | dissect_fix_packet(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_) |
198 | 54 | { |
199 | | /* Set up structures needed to add the protocol subtree and manage it */ |
200 | 54 | proto_item *ti; |
201 | 54 | proto_tree *fix_tree; |
202 | 54 | unsigned pdu_len; |
203 | 54 | unsigned offset = 0; |
204 | 54 | unsigned field_offset, ctrla_offset; |
205 | 54 | uint32_t tag_value; |
206 | 54 | char *value; |
207 | 54 | int32_t ivalue; |
208 | 54 | bool ivalue_valid; |
209 | 54 | proto_item* pi; |
210 | 54 | fix_parameter *tag; |
211 | 54 | const char *msg_type; |
212 | | |
213 | | /* Make entries in Protocol column and Info column on summary display */ |
214 | 54 | col_set_str(pinfo->cinfo, COL_PROTOCOL, "FIX"); |
215 | 54 | col_clear(pinfo->cinfo, COL_INFO); |
216 | | |
217 | | /* get at least the fix version: 8=FIX.x.x */ |
218 | 54 | if (fix_marker(tvb, 0) != 0) { |
219 | | /* not a fix packet start but it's a fix packet */ |
220 | 29 | col_set_str(pinfo->cinfo, COL_INFO, "[FIX continuation]"); |
221 | 29 | ti = proto_tree_add_item(tree, proto_fix, tvb, 0, -1, ENC_NA); |
222 | 29 | fix_tree = proto_item_add_subtree(ti, ett_fix); |
223 | 29 | proto_tree_add_item(fix_tree, hf_fix_data, tvb, 0, -1, ENC_NA); |
224 | 29 | return tvb_captured_length(tvb); |
225 | 29 | } |
226 | | |
227 | 25 | pdu_len = tvb_reported_length(tvb); |
228 | 25 | ti = proto_tree_add_item(tree, proto_fix, tvb, 0, -1, ENC_NA); |
229 | 25 | fix_tree = proto_item_add_subtree(ti, ett_fix); |
230 | | |
231 | | /* begin string */ |
232 | 25 | if (!tvb_find_uint8_remaining(tvb, offset, 0x01, &ctrla_offset)) { |
233 | 9 | expert_add_info_format(pinfo, ti, &ei_fix_missing_field, "Missing BeginString field"); |
234 | 9 | return tvb_captured_length(tvb); |
235 | 9 | } |
236 | 16 | offset = ctrla_offset + 1; |
237 | | |
238 | | /* msg length */ |
239 | 16 | if (!!tvb_find_uint8_remaining(tvb, offset, 0x01, &ctrla_offset)) { |
240 | 8 | expert_add_info_format(pinfo, ti, &ei_fix_missing_field, "Missing BodyLength field"); |
241 | 8 | return tvb_captured_length(tvb); |
242 | 8 | } |
243 | 8 | offset = ctrla_offset + 1; |
244 | | |
245 | | /* msg type */ |
246 | 8 | if (!(tag = fix_param(tvb, offset)) || tag->value_len < 1) { |
247 | 0 | expert_add_info_format(pinfo, ti, &ei_fix_missing_field, "Missing MsgType field"); |
248 | 0 | return tvb_captured_length(tvb); |
249 | 0 | } |
250 | | |
251 | | /* In the interest of speed, if "tree" is NULL, don't do any work not |
252 | | * necessary to generate protocol tree items. |
253 | | */ |
254 | 8 | field_offset = 0; |
255 | | |
256 | 8 | while(field_offset < pdu_len && (tag = fix_param(tvb, field_offset)) ) { |
257 | 0 | const fix_field *field; |
258 | |
|
259 | 0 | if (tag->tag_len < 1) { |
260 | 0 | field_offset = tag->ctrla_offset + 1; |
261 | 0 | continue; |
262 | 0 | } |
263 | | |
264 | 0 | if (!tvb_get_string_uint(tvb, field_offset, tag->tag_len, ENC_STR_DEC, &tag_value, NULL)) { |
265 | 0 | proto_tree_add_expert(fix_tree, pinfo, &ei_fix_tag_invalid, tvb, field_offset, tag->tag_len); |
266 | 0 | break; |
267 | 0 | } |
268 | 0 | if (tag->value_len < 1) { |
269 | 0 | proto_tree *field_tree; |
270 | | /* XXX - put an error indication here. It's too late |
271 | | to return false; we've already started dissecting, |
272 | | and if a heuristic dissector starts dissecting |
273 | | (either updating the columns or creating a protocol |
274 | | tree) and then gives up, it leaves crud behind that |
275 | | messes up other dissectors that might process the |
276 | | packet. */ |
277 | 0 | field_tree = proto_tree_add_subtree_format(fix_tree, tvb, field_offset, tag->field_len, ett_badfield, NULL, "%i: <missing value>", tag_value); |
278 | 0 | proto_tree_add_uint(field_tree, hf_fix_field_tag, tvb, field_offset, tag->tag_len, tag_value); |
279 | 0 | field_offset = tag->ctrla_offset + 1; |
280 | 0 | continue; |
281 | 0 | } |
282 | | |
283 | | /* fix_fields array is sorted by tag_value */ |
284 | 0 | field = bsearch(&tag_value, fix_fields, array_length(fix_fields), sizeof *fix_fields, fix_field_tag_compar); |
285 | |
|
286 | 0 | value = (char*)tvb_get_string_enc(pinfo->pool, tvb, tag->value_offset, tag->value_len, ENC_ASCII); |
287 | 0 | ivalue_valid = ws_strtoi32(value, NULL, &ivalue); |
288 | 0 | if (field) { |
289 | 0 | int hf = fix_hf[field - fix_fields]; |
290 | |
|
291 | 0 | if (field->table) { |
292 | 0 | if (tree) { |
293 | 0 | switch (field->type) { |
294 | 0 | case 1: /* strings */ |
295 | 0 | proto_tree_add_string_format_value(fix_tree, hf, tvb, field_offset, tag->field_len, value, |
296 | 0 | "%s (%s)", value, str_to_str_wmem(pinfo->pool, value, (const string_string *)field->table, "unknown %s")); |
297 | 0 | if (tag_value == 35) { |
298 | | /* Make message type part of the Info column */ |
299 | 0 | msg_type = str_to_str_wmem(pinfo->pool, value, messages_val, "FIX Message (%s)"); |
300 | 0 | col_append_sep_str(pinfo->cinfo, COL_INFO, ", ", msg_type); |
301 | 0 | col_set_fence(pinfo->cinfo, COL_INFO); |
302 | 0 | } |
303 | 0 | break; |
304 | 0 | case 2: /* char */ |
305 | 0 | proto_tree_add_string_format_value(fix_tree, hf, tvb, field_offset, tag->field_len, value, |
306 | 0 | "%s (%s)", value, val_to_str(pinfo->pool, *value, (const value_string *)field->table, "unknown %d")); |
307 | 0 | break; |
308 | 0 | default: |
309 | 0 | if (ivalue_valid) |
310 | 0 | proto_tree_add_string_format_value(fix_tree, hf, tvb, field_offset, tag->field_len, value, |
311 | 0 | "%s (%s)", value, val_to_str(pinfo->pool, ivalue, (const value_string *)field->table, "unknown %d")); |
312 | 0 | else { |
313 | 0 | pi = proto_tree_add_string(fix_tree, hf, tvb, field_offset, tag->field_len, value); |
314 | 0 | expert_add_info_format(pinfo, pi, &ei_fix_field_invalid, "Invalid string %s for fix field tag %i", value, field->tag); |
315 | 0 | } |
316 | 0 | break; |
317 | 0 | } |
318 | 0 | } |
319 | 0 | } |
320 | 0 | else { |
321 | 0 | proto_item *item; |
322 | | |
323 | | /* checksum */ |
324 | 0 | switch(tag_value) { |
325 | 0 | case 10: |
326 | 0 | { |
327 | 0 | proto_tree *checksum_tree; |
328 | 0 | uint8_t sum = 0; |
329 | 0 | const uint8_t *sum_data = tvb_get_ptr(tvb, 0, field_offset); |
330 | 0 | bool sum_ok; |
331 | 0 | unsigned j; |
332 | |
|
333 | 0 | for (j = 0; j < field_offset; j++, sum_data++) { |
334 | 0 | sum += *sum_data; |
335 | 0 | } |
336 | 0 | sum_ok = (ivalue == sum); |
337 | 0 | if (sum_ok) { |
338 | 0 | item = proto_tree_add_string_format_value(fix_tree, hf, tvb, field_offset, tag->field_len, |
339 | 0 | value, "%s [correct]", value); |
340 | 0 | } |
341 | 0 | else { |
342 | 0 | item = proto_tree_add_string_format_value(fix_tree, hf, tvb, field_offset, tag->field_len, |
343 | 0 | value, "%s [incorrect should be %d]", value, sum); |
344 | 0 | } |
345 | 0 | checksum_tree = proto_item_add_subtree(item, ett_checksum); |
346 | 0 | item = proto_tree_add_boolean(checksum_tree, hf_fix_checksum_good, tvb, field_offset, tag->field_len, sum_ok); |
347 | 0 | proto_item_set_generated(item); |
348 | 0 | item = proto_tree_add_boolean(checksum_tree, hf_fix_checksum_bad, tvb, field_offset, tag->field_len, !sum_ok); |
349 | 0 | proto_item_set_generated(item); |
350 | 0 | if (!sum_ok) |
351 | 0 | expert_add_info(pinfo, item, &ei_fix_checksum_bad); |
352 | 0 | } |
353 | 0 | break; |
354 | 0 | default: |
355 | 0 | proto_tree_add_string(fix_tree, hf, tvb, field_offset, tag->field_len, value); |
356 | 0 | break; |
357 | 0 | } |
358 | 0 | } |
359 | 0 | } |
360 | 0 | else if (tree) { |
361 | 0 | proto_tree *field_tree; |
362 | | |
363 | | /* XXX - it could be -1 if the tag isn't a number */ |
364 | 0 | field_tree = proto_tree_add_subtree_format(fix_tree, tvb, field_offset, tag->field_len, ett_unknown, NULL, |
365 | 0 | "%i: %s", tag_value, value); |
366 | 0 | proto_tree_add_uint(field_tree, hf_fix_field_tag, tvb, field_offset, tag->tag_len, tag_value); |
367 | 0 | proto_tree_add_item(field_tree, hf_fix_field_value, tvb, tag->value_offset, tag->value_len, ENC_ASCII); |
368 | 0 | } |
369 | | |
370 | 0 | field_offset = tag->ctrla_offset + 1; |
371 | 0 | } |
372 | 8 | return tvb_captured_length(tvb); |
373 | 8 | } |
374 | | |
375 | | static unsigned |
376 | | get_fix_pdu_len(packet_info *pinfo, tvbuff_t *tvb, int offset, void *data _U_) |
377 | 94 | { |
378 | 94 | unsigned fix_len; |
379 | | |
380 | 94 | fix_len = fix_header_len(tvb, pinfo, offset); |
381 | 94 | return fix_len; |
382 | 94 | } |
383 | | |
384 | | /* ------------------------------------ |
385 | | fixed-length part isn't really a constant but if we assume it's at least: |
386 | | 8=FIX.x.y\01 10 |
387 | | 9=x\01 4 |
388 | | 35=x\01 5 |
389 | | 10=y\01 5 |
390 | | 24 |
391 | | it should catch all 9= size |
392 | | */ |
393 | | |
394 | 73 | #define FIX_MIN_LEN 24 |
395 | | |
396 | | static int |
397 | | dissect_fix_pdus(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data) |
398 | 73 | { |
399 | 73 | tcp_dissect_pdus(tvb, pinfo, tree, fix_desegment, FIX_MIN_LEN, |
400 | 73 | get_fix_pdu_len, dissect_fix_packet, data); |
401 | | |
402 | 73 | return tvb_captured_length(tvb); |
403 | 73 | } |
404 | | |
405 | | static int |
406 | | dissect_fix(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data) |
407 | 54 | { |
408 | 54 | return dissect_fix_pdus(tvb, pinfo, tree, data); |
409 | 54 | } |
410 | | |
411 | | /* Code to actually dissect the packets */ |
412 | | static bool |
413 | | dissect_fix_heur(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data) |
414 | 3.72k | { |
415 | 3.72k | conversation_t *conv; |
416 | | |
417 | | /* get at least the fix version: 8=FIX.x.x */ |
418 | 3.72k | if (fix_marker(tvb, 0) != 0) { |
419 | | /* not a fix packet */ |
420 | 3.70k | return false; |
421 | 3.70k | } |
422 | | |
423 | 19 | conv = find_or_create_conversation(pinfo); |
424 | 19 | conversation_set_dissector(conv, fix_handle); |
425 | | |
426 | 19 | dissect_fix_pdus(tvb, pinfo, tree, data); |
427 | 19 | return true; |
428 | 3.72k | } |
429 | | |
430 | | static bool |
431 | | dissect_fix_heur_ssl(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data) |
432 | 0 | { |
433 | 0 | struct tlsinfo *tlsinfo = (struct tlsinfo *)data; |
434 | | /* get at least the fix version: 8=FIX.x.x */ |
435 | 0 | if (fix_marker(tvb, 0) != 0) { |
436 | | /* not a fix packet */ |
437 | 0 | return false; |
438 | 0 | } |
439 | | |
440 | 0 | dissect_fix_pdus(tvb, pinfo, tree, data); |
441 | 0 | *(tlsinfo->app_handle) = fix_handle; |
442 | 0 | return true; |
443 | 0 | } |
444 | | |
445 | | /* this format is require because a script is used to build the C function |
446 | | that calls all the protocol registration. |
447 | | */ |
448 | | |
449 | | void |
450 | | proto_register_fix(void) |
451 | 16 | { |
452 | 16 | static hf_register_info hf[] = { |
453 | 16 | { &hf_fix_data, |
454 | 16 | { "Continuation Data", "fix.data", FT_BYTES, BASE_NONE, NULL, 0x00, |
455 | 16 | NULL, HFILL } |
456 | 16 | }, |
457 | | |
458 | 16 | { &hf_fix_field_tag, |
459 | 16 | { "Field Tag", "fix.field.tag", FT_UINT16, BASE_DEC, NULL, 0x0, |
460 | 16 | "Field length.", HFILL }}, |
461 | | |
462 | 16 | { &hf_fix_field_value, |
463 | 16 | { "Field Value", "fix.field.value", FT_STRING, BASE_NONE, NULL, 0x0, |
464 | 16 | NULL, HFILL }}, |
465 | | |
466 | 16 | { &hf_fix_checksum_good, |
467 | 16 | { "Good Checksum", "fix.checksum_good", FT_BOOLEAN, BASE_NONE, NULL, 0x0, |
468 | 16 | "True: checksum matches packet content; False: doesn't match content or not checked", HFILL }}, |
469 | | |
470 | 16 | { &hf_fix_checksum_bad, |
471 | 16 | { "Bad Checksum", "fix.checksum_bad", FT_BOOLEAN, BASE_NONE, NULL, 0x0, |
472 | 16 | "True: checksum doesn't match packet content; False: matches content or not checked", HFILL }}, |
473 | 16 | }; |
474 | | |
475 | | /* Setup protocol subtree array */ |
476 | 16 | static int *ett[] = { |
477 | 16 | &ett_fix, |
478 | 16 | &ett_unknown, |
479 | 16 | &ett_badfield, |
480 | 16 | &ett_checksum, |
481 | 16 | }; |
482 | | |
483 | 16 | static ei_register_info ei[] = { |
484 | 16 | { &ei_fix_checksum_bad, { "fix.checksum_bad.expert", PI_CHECKSUM, PI_ERROR, "Bad checksum", EXPFILL }}, |
485 | 16 | { &ei_fix_missing_field, { "fix.missing_field", PI_MALFORMED, PI_ERROR, "Missing mandatory field", EXPFILL }}, |
486 | 16 | { &ei_fix_tag_invalid, { "fix.tag.invalid", PI_MALFORMED, PI_ERROR, "Invalid Tag", EXPFILL }}, |
487 | 16 | { &ei_fix_field_invalid, { "fix.invalid_integer_string", PI_MALFORMED, PI_ERROR, "Invalid integer string", EXPFILL }} |
488 | 16 | }; |
489 | | |
490 | 16 | module_t *fix_module; |
491 | 16 | expert_module_t* expert_fix; |
492 | | |
493 | | /* register re-init routine */ |
494 | 16 | register_init_routine(&dissect_fix_init); |
495 | | |
496 | | /* Register the protocol name and description */ |
497 | 16 | proto_fix = proto_register_protocol("Financial Information eXchange Protocol", "FIX", "fix"); |
498 | | |
499 | | /* Allow dissector to find be found by name. */ |
500 | 16 | fix_handle = register_dissector("fix", dissect_fix, proto_fix); |
501 | | |
502 | 16 | proto_register_field_array(proto_fix, hf, array_length(hf)); |
503 | 16 | proto_register_field_array(proto_fix, hf_FIX, array_length(hf_FIX)); |
504 | 16 | proto_register_subtree_array(ett, array_length(ett)); |
505 | 16 | expert_fix = expert_register_protocol(proto_fix); |
506 | 16 | expert_register_field_array(expert_fix, ei, array_length(ei)); |
507 | | |
508 | 16 | fix_module = prefs_register_protocol(proto_fix, NULL); |
509 | 16 | prefs_register_bool_preference(fix_module, "desegment", |
510 | 16 | "Reassemble FIX messages spanning multiple TCP segments", |
511 | 16 | "Whether the FIX dissector should reassemble messages spanning multiple TCP segments." |
512 | 16 | " To use this option, you must also enable" |
513 | 16 | " \"Allow subdissectors to reassemble TCP streams\" in the TCP protocol settings.", |
514 | 16 | &fix_desegment); |
515 | 16 | } |
516 | | |
517 | | |
518 | | void |
519 | | proto_reg_handoff_fix(void) |
520 | 16 | { |
521 | | /* Let the tcp dissector know that we're interested in traffic */ |
522 | 16 | heur_dissector_add("tcp", dissect_fix_heur, "FIX over TCP", "fix_tcp", proto_fix, HEURISTIC_ENABLE); |
523 | 16 | heur_dissector_add("tls", dissect_fix_heur_ssl, "FIX over TLS", "fix_tls", proto_fix, HEURISTIC_ENABLE); |
524 | 16 | dissector_add_uint_range_with_preference("tcp.port", "", fix_handle); |
525 | 16 | } |
526 | | |
527 | | /* |
528 | | * Editor modelines - https://www.wireshark.org/tools/modelines.html |
529 | | * |
530 | | * Local variables: |
531 | | * c-basic-offset: 4 |
532 | | * tab-width: 8 |
533 | | * indent-tabs-mode: nil |
534 | | * End: |
535 | | * |
536 | | * vi: set shiftwidth=4 tabstop=8 expandtab: |
537 | | * :indentSize=4:tabSize=8:noTabs=true: |
538 | | */ |