2 * Routines for Financial Information eXchange (FIX) Protocol dissection
3 * Copyright 2000, PC Drew <drewpc@ibsncentral.com>
7 * Wireshark - Network traffic analyzer
8 * By Gerald Combs <gerald@wireshark.org>
9 * Copyright 1998 Gerald Combs
11 * This program is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU General Public License
13 * as published by the Free Software Foundation; either version 2
14 * of the License, or (at your option) any later version.
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
25 * Documentation: http://www.fixprotocol.org/
26 * Fields and messages from http://www.quickfixengine.org/ xml
39 #include <epan/packet.h>
40 #include <epan/expert.h>
41 #include <epan/prefs.h>
42 #include <epan/conversation.h>
44 #include "packet-tcp.h"
46 typedef struct _fix_field {
47 int tag; /* FIX tag */
53 typedef struct _fix_parameter {
61 /* Initialize the protocol and registered fields */
62 static int proto_fix = -1;
63 static dissector_handle_t fix_handle;
65 /* desegmentation of fix */
66 static gboolean fix_desegment = TRUE;
68 /* Initialize the subtree pointers */
69 static gint ett_fix = -1;
70 static gint ett_unknow = -1;
71 static gint ett_badfield = -1;
72 static gint ett_checksum = -1;
74 static int hf_fix_data = -1; /* continuation data */
75 static int hf_fix_checksum_good = -1;
76 static int hf_fix_checksum_bad = -1;
77 static int hf_fix_field_value = -1;
78 static int hf_fix_field_tag = -1;
80 static range_t *global_fix_tcp_range = NULL;
81 static range_t *fix_tcp_range = NULL;
84 #define MARKER_TAG "8=FIX"
86 static int fix_marker(tvbuff_t *tvb, int offset)
88 return tvb_strneql(tvb, offset, MARKER_TAG, MARKER_LEN);
92 * Fields and messages generated from http://www.quickfixengine.org/ xml (slightly modified)
95 #include "packet-fix.h"
97 static void dissect_fix_init(void) {
98 /* TODO load xml def for private field */
99 /* TODO check that fix_fields is really sorted */
105 int lower = 0, upper = array_length(fix_fields) -1;
106 while (lower <= upper) {
107 int middle = (lower + upper) / 2;
108 int res = fix_fields[middle].tag;
111 } else if (res == key) {
120 /* Code to actually dissect the packets */
121 static int fix_next_header(tvbuff_t *tvb, int offset)
123 /* try to resynch to the next start */
124 guint min_len = tvb_length_remaining(tvb, offset);
125 const guint8 *data = tvb_get_ephemeral_string(tvb, offset, min_len);
126 const guint8 *start = data;
128 while ((start = strstr(start, "\0018"))) {
129 min_len = (guint) (start +1 -data);
130 /* if remaining length < 6 return and let the next desegment round
133 if (tvb_length_remaining(tvb, min_len + offset) < MARKER_LEN)
135 if (!fix_marker(tvb, min_len +offset) )
142 /* ----------------------------------------------
143 Format: name=value\001
145 static fix_parameter *fix_param(tvbuff_t *tvb, int offset)
147 static fix_parameter ret;
150 ret.ctrla_offset = tvb_find_guint8(tvb, offset, -1, 0x01);
151 if (ret.ctrla_offset == -1) {
155 ret.field_len = ret.ctrla_offset - offset + 1;
156 equals = tvb_find_guint8(tvb, offset, ret.field_len, '=');
161 ret.value_offset = equals + 1;
162 ret.tag_len = ret.value_offset - offset - 1;
163 ret.value_len = ret.ctrla_offset - ret.value_offset;
167 /* ---------------------------------------------- */
168 static int fix_header_len(tvbuff_t *tvb, int offset)
170 int base_offset, ctrla_offset;
175 base_offset = offset;
177 /* get at least the fix version: 8=FIX.x.x */
178 if (fix_marker(tvb, offset) != 0) {
179 return fix_next_header(tvb, offset);
183 ctrla_offset = tvb_find_guint8(tvb, offset, -1, 0x01);
184 if (ctrla_offset == -1) {
185 /* it should be there, (minimum size is big enough)
186 * if not maybe it's not really
187 * a FIX packet but it's too late to bail out.
189 return fix_next_header(tvb, offset +MARKER_LEN) +MARKER_LEN;
191 offset = ctrla_offset + 1;
194 if (!(tag = fix_param(tvb, offset)) || tvb_strneql(tvb, offset, "9=", 2)) {
195 /* not a tag or not the BodyLength tag, give up */
196 return fix_next_header(tvb, offset);
199 value = tvb_get_ephemeral_string(tvb, tag->value_offset, tag->value_len);
200 /* Fix version, msg type, length and checksum aren't in body length.
201 * If the packet is big enough find the checksum
203 size = atoi(value) +tag->ctrla_offset - base_offset +1;
204 if (tvb_length_remaining(tvb, base_offset) > size +4) {
205 /* 10= should be there */
206 offset = base_offset +size;
207 if (tvb_strneql(tvb, offset, "10=", 3) != 0) {
208 /* No? bogus packet, try to find the next header */
209 return fix_next_header(tvb, base_offset +MARKER_LEN) +MARKER_LEN;
211 ctrla_offset = tvb_find_guint8(tvb, offset, -1, 0x01);
212 if (ctrla_offset == -1) {
213 /* assume checksum is 7 bytes 10=xxx\01 */
216 return size +ctrla_offset -offset +1;
220 /* assume checksum is 7 bytes 10=xxx\01 */
224 /* ---------------------------------------------- */
226 dissect_fix_packet(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
228 /* Set up structures needed to add the protocol subtree and manage it */
230 proto_tree *fix_tree;
233 int field_offset, ctrla_offset;
239 /* Make entries in Protocol column and Info column on summary display */
240 col_set_str(pinfo->cinfo, COL_PROTOCOL, "FIX");
241 col_clear(pinfo->cinfo, COL_INFO);
243 /* get at least the fix version: 8=FIX.x.x */
244 if (fix_marker(tvb, 0) != 0) {
245 /* not a fix packet start but it's a fix packet */
246 col_set_str(pinfo->cinfo, COL_INFO, "[FIX continuation]");
247 ti = proto_tree_add_item(tree, proto_fix, tvb, 0, -1, FALSE);
248 fix_tree = proto_item_add_subtree(ti, ett_fix);
249 proto_tree_add_item(fix_tree, hf_fix_data, tvb, 0, -1, FALSE);
253 pdu_len = tvb_reported_length(tvb);
254 ti = proto_tree_add_item(tree, proto_fix, tvb, 0, -1, FALSE);
255 fix_tree = proto_item_add_subtree(ti, ett_fix);
258 ctrla_offset = tvb_find_guint8(tvb, offset, -1, 0x01);
259 if (ctrla_offset == -1) {
262 offset = ctrla_offset + 1;
265 ctrla_offset = tvb_find_guint8(tvb, offset, -1, 0x01);
266 if (ctrla_offset == -1) {
269 offset = ctrla_offset + 1;
272 if (!(tag = fix_param(tvb, offset)) || tag->value_len < 1) {
276 if (check_col(pinfo->cinfo, COL_INFO)) {
277 const char *msg_type;
279 value = tvb_get_ephemeral_string(tvb, tag->value_offset, tag->value_len);
280 msg_type = str_to_str(value, messages_val, "FIX Message (%s)");
281 col_add_str(pinfo->cinfo, COL_INFO, msg_type);
284 /* In the interest of speed, if "tree" is NULL, don't do any work not
285 * necessary to generate protocol tree items.
289 while(field_offset < pdu_len && (tag = fix_param(tvb, field_offset)) ) {
292 if (tag->tag_len < 1) {
293 field_offset = tag->ctrla_offset + 1;
297 tag_str = tvb_get_ephemeral_string(tvb, field_offset, tag->tag_len);
298 tag_value = atoi(tag_str);
299 if (tag->value_len < 1) {
300 proto_tree *field_tree;
301 /* XXX - put an error indication here. It's too late
302 to return FALSE; we've already started dissecting,
303 and if a heuristic dissector starts dissecting
304 (either updating the columns or creating a protocol
305 tree) and then gives up, it leaves crud behind that
306 messes up other dissectors that might process the
308 ti = proto_tree_add_text(fix_tree, tvb, field_offset, tag->field_len, "%i: <missing value>", tag_value);
309 field_tree = proto_item_add_subtree(ti, ett_badfield);
310 proto_tree_add_uint(field_tree, hf_fix_field_tag, tvb, field_offset, tag->tag_len, tag_value);
311 field_offset = tag->ctrla_offset + 1;
315 /* fix_fields array is sorted by tag_value */
317 if ((i = tag_search(tag_value)) >= 0) {
321 value = tvb_get_ephemeral_string(tvb, tag->value_offset, tag->value_len);
323 if (fix_fields[i].table) {
325 switch (fix_fields[i].type) {
326 case 1: /* strings */
327 proto_tree_add_string_format_value(fix_tree, fix_fields[i].hf_id, tvb, field_offset, tag->field_len, value,
328 "%s (%s)", value, str_to_str(value, fix_fields[i].table, "unknow %s"));
331 proto_tree_add_string_format_value(fix_tree, fix_fields[i].hf_id, tvb, field_offset, tag->field_len, value,
332 "%s (%s)", value, val_to_str(*value, fix_fields[i].table, "unknow %d"));
335 proto_tree_add_string_format_value(fix_tree, fix_fields[i].hf_id, tvb, field_offset, tag->field_len, value,
336 "%s (%s)", value, val_to_str(atoi(value), fix_fields[i].table, "unknow %d"));
348 proto_tree *checksum_tree;
350 const guint8 *data = tvb_get_ptr(tvb, 0, field_offset);
354 for (j = 0; j < field_offset; j++, data++) {
357 sum_ok = (atoi(value) == sum);
359 item = proto_tree_add_string_format_value(fix_tree, fix_fields[i].hf_id, tvb, field_offset, tag->field_len,
360 value, "%s [correct]", value);
363 item = proto_tree_add_string_format_value(fix_tree, fix_fields[i].hf_id, tvb, field_offset, tag->field_len,
364 value, "%s [incorrect should be %d]", value, sum);
366 checksum_tree = proto_item_add_subtree(item, ett_checksum);
367 item = proto_tree_add_boolean(checksum_tree, hf_fix_checksum_good, tvb, field_offset, tag->field_len, sum_ok);
368 PROTO_ITEM_SET_GENERATED(item);
369 item = proto_tree_add_boolean(checksum_tree, hf_fix_checksum_bad, tvb, field_offset, tag->field_len, !sum_ok);
370 PROTO_ITEM_SET_GENERATED(item);
372 expert_add_info_format(pinfo, item, PI_CHECKSUM, PI_ERROR, "Bad checksum");
376 proto_tree_add_string(fix_tree, fix_fields[i].hf_id, tvb, field_offset, tag->field_len, value);
382 proto_tree *field_tree;
384 /* XXX - it could be -1 if the tag isn't a number */
385 ti = proto_tree_add_text(fix_tree, tvb, field_offset, tag->field_len, "%i: %s", tag_value, value);
386 field_tree = proto_item_add_subtree(ti, ett_unknow);
387 proto_tree_add_uint(field_tree, hf_fix_field_tag, tvb, field_offset, tag->tag_len, tag_value);
388 proto_tree_add_item(field_tree, hf_fix_field_value, tvb, tag->value_offset, tag->value_len, FALSE);
391 field_offset = tag->ctrla_offset + 1;
399 get_fix_pdu_len(packet_info *pinfo _U_, tvbuff_t *tvb, int offset)
403 fix_len = fix_header_len(tvb, offset);
407 /* ------------------------------------
408 fixed-length part isn't really a constant but if we assume it's at least:
414 it should catch all 9= size
417 #define FIX_MIN_LEN 24
420 dissect_fix_pdus(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
422 tcp_dissect_pdus(tvb, pinfo, tree, fix_desegment, FIX_MIN_LEN,
423 get_fix_pdu_len, dissect_fix_packet);
428 dissect_fix(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
430 dissect_fix_pdus(tvb, pinfo, tree);
433 /* Code to actually dissect the packets */
435 dissect_fix_heur(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
437 conversation_t *conv;
439 /* get at least the fix version: 8=FIX.x.x */
440 if (fix_marker(tvb, 0) != 0) {
441 /* not a fix packet */
445 conv = find_or_create_conversation(pinfo);
446 conversation_set_dissector(conv, fix_handle);
448 dissect_fix_pdus(tvb, pinfo, tree);
452 /* Register the protocol with Wireshark */
453 static void range_delete_fix_tcp_callback(guint32 port) {
454 dissector_delete_uint("tcp.port", port, fix_handle);
457 static void range_add_fix_tcp_callback(guint32 port) {
458 dissector_add_uint("tcp.port", port, fix_handle);
461 static void fix_prefs(void)
463 range_foreach(fix_tcp_range, range_delete_fix_tcp_callback);
464 g_free(fix_tcp_range);
465 fix_tcp_range = range_copy(global_fix_tcp_range);
466 range_foreach(fix_tcp_range, range_add_fix_tcp_callback);
469 /* this format is require because a script is used to build the C function
470 that calls all the protocol registration.
474 proto_register_fix(void)
476 /* Setup list of header fields See Section 1.6.1 for details*/
477 static hf_register_info hf[] = {
479 { "Continuation Data", "fix.data", FT_BYTES, BASE_NONE, NULL, 0x00,
484 { "Field Tag", "fix.field.tag", FT_UINT16, BASE_DEC, NULL, 0x0,
485 "Field length.", HFILL }},
487 { &hf_fix_field_value,
488 { "Field Value", "fix.field.value", FT_STRING, BASE_NONE, NULL, 0x0,
491 { &hf_fix_checksum_good,
492 { "Good Checksum", "fix.checksum_good", FT_BOOLEAN, BASE_NONE, NULL, 0x0,
493 "True: checksum matches packet content; False: doesn't match content or not checked", HFILL }},
495 { &hf_fix_checksum_bad,
496 { "Bad Checksum", "fix.checksum_bad", FT_BOOLEAN, BASE_NONE, NULL, 0x0,
497 "True: checksum doesn't match packet content; False: matches content or not checked", HFILL }},
500 /* Setup protocol subtree array */
501 static gint *ett[] = {
508 module_t *fix_module;
510 /* register re-init routine */
511 register_init_routine(&dissect_fix_init);
513 /* Register the protocol name and description */
514 proto_fix = proto_register_protocol("Financial Information eXchange Protocol",
517 /* Required function calls to register the header fields and subtrees used */
518 proto_register_field_array(proto_fix, hf, array_length(hf));
519 proto_register_field_array(proto_fix, hf_FIX, array_length(hf_FIX));
520 proto_register_subtree_array(ett, array_length(ett));
522 fix_module = prefs_register_protocol(proto_fix, fix_prefs);
523 prefs_register_bool_preference(fix_module, "desegment",
524 "Reassemble FIX messages spanning multiple TCP segments",
525 "Whether the FIX dissector should reassemble messages spanning multiple TCP segments."
526 " To use this option, you must also enable \"Allow subdissectors to reassemble TCP streams\" in the TCP protocol settings.",
529 prefs_register_range_preference(fix_module, "tcp.port", "TCP Ports", "TCP Ports range", &global_fix_tcp_range, 65535);
531 fix_tcp_range = range_empty();
536 proto_reg_handoff_fix(void)
538 /* Let the tcp dissector know that we're interested in traffic */
539 heur_dissector_add("tcp", dissect_fix_heur, proto_fix);
540 /* Register a fix handle to "tcp.port" to be able to do 'decode-as' */
541 fix_handle = create_dissector_handle(dissect_fix, proto_fix);
542 dissector_add_handle("tcp.port", fix_handle);