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