2002-09-16 17:49:20 +00:00
|
|
|
/* packet-fix.c
|
|
|
|
* Routines for Financial Information eXchange (FIX) Protocol dissection
|
|
|
|
* Copyright 2000, PC Drew <drewpc@ibsncentral.com>
|
|
|
|
*
|
2006-05-21 04:49:01 +00:00
|
|
|
* Wireshark - Network traffic analyzer
|
|
|
|
* By Gerald Combs <gerald@wireshark.org>
|
2002-09-16 17:49:20 +00:00
|
|
|
* Copyright 1998 Gerald Combs
|
|
|
|
*
|
|
|
|
* This program is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU General Public License
|
|
|
|
* as published by the Free Software Foundation; either version 2
|
|
|
|
* of the License, or (at your option) any later version.
|
2005-01-05 10:01:04 +00:00
|
|
|
*
|
2002-09-16 17:49:20 +00:00
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
2005-01-05 10:01:04 +00:00
|
|
|
*
|
2002-09-16 17:49:20 +00:00
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with this program; if not, write to the Free Software
|
2012-06-28 23:18:38 +00:00
|
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
2002-09-16 17:49:20 +00:00
|
|
|
*
|
|
|
|
* Documentation: http://www.fixprotocol.org/
|
2013-01-05 04:06:31 +00:00
|
|
|
* Fields and messages from http://www.quickfixengine.org/ and http://sourceforge.net/projects/quickfix/files/ xml
|
2009-05-26 00:49:38 +00:00
|
|
|
*
|
2002-09-16 17:49:20 +00:00
|
|
|
*/
|
|
|
|
|
2012-09-20 02:03:38 +00:00
|
|
|
#include "config.h"
|
2002-09-16 17:49:20 +00:00
|
|
|
|
2011-05-20 19:00:09 +00:00
|
|
|
#include <stdlib.h>
|
2002-09-16 17:49:20 +00:00
|
|
|
#include <string.h>
|
2011-05-20 19:00:09 +00:00
|
|
|
|
|
|
|
#include <glib.h>
|
|
|
|
|
2002-09-16 17:49:20 +00:00
|
|
|
#include <epan/packet.h>
|
2009-05-26 00:49:38 +00:00
|
|
|
#include <epan/expert.h>
|
|
|
|
#include <epan/prefs.h>
|
|
|
|
#include <epan/conversation.h>
|
|
|
|
|
|
|
|
#include "packet-tcp.h"
|
2013-05-04 01:37:55 +00:00
|
|
|
#include "packet-ssl.h"
|
2009-05-26 00:49:38 +00:00
|
|
|
|
2013-12-15 23:44:12 +00:00
|
|
|
void proto_register_fix(void);
|
|
|
|
void proto_reg_handoff_fix(void);
|
|
|
|
|
2009-05-26 00:49:38 +00:00
|
|
|
typedef struct _fix_parameter {
|
|
|
|
int field_len;
|
|
|
|
int tag_len;
|
|
|
|
int value_offset;
|
|
|
|
int value_len;
|
|
|
|
int ctrla_offset;
|
|
|
|
} fix_parameter;
|
2002-09-16 17:49:20 +00:00
|
|
|
|
|
|
|
/* Initialize the protocol and registered fields */
|
|
|
|
static int proto_fix = -1;
|
2009-05-26 00:49:38 +00:00
|
|
|
|
|
|
|
/* desegmentation of fix */
|
|
|
|
static gboolean fix_desegment = TRUE;
|
2002-09-16 17:49:20 +00:00
|
|
|
|
|
|
|
/* Initialize the subtree pointers */
|
|
|
|
static gint ett_fix = -1;
|
2009-05-26 00:49:38 +00:00
|
|
|
static gint ett_unknow = -1;
|
|
|
|
static gint ett_badfield = -1;
|
|
|
|
static gint ett_checksum = -1;
|
|
|
|
|
2013-05-26 03:29:07 +00:00
|
|
|
static expert_field ei_fix_checksum_bad = EI_INIT;
|
|
|
|
|
2009-05-26 00:49:38 +00:00
|
|
|
static int hf_fix_data = -1; /* continuation data */
|
2010-05-13 18:28:34 +00:00
|
|
|
static int hf_fix_checksum_good = -1;
|
|
|
|
static int hf_fix_checksum_bad = -1;
|
|
|
|
static int hf_fix_field_value = -1;
|
2009-05-26 00:49:38 +00:00
|
|
|
static int hf_fix_field_tag = -1;
|
|
|
|
|
2013-08-05 18:09:43 +00:00
|
|
|
static dissector_handle_t fix_handle;
|
|
|
|
|
2009-05-26 00:49:38 +00:00
|
|
|
static range_t *global_fix_tcp_range = NULL;
|
|
|
|
static range_t *fix_tcp_range = NULL;
|
|
|
|
|
|
|
|
/* 8=FIX */
|
|
|
|
#define MARKER_TAG "8=FIX"
|
2010-05-13 18:28:34 +00:00
|
|
|
#define MARKER_LEN 5
|
2012-05-03 19:31:03 +00:00
|
|
|
|
2009-05-26 00:49:38 +00:00
|
|
|
static int fix_marker(tvbuff_t *tvb, int offset)
|
|
|
|
{
|
2012-05-03 19:31:03 +00:00
|
|
|
return tvb_strneql(tvb, offset, MARKER_TAG, MARKER_LEN);
|
2009-05-26 00:49:38 +00:00
|
|
|
}
|
2002-09-16 17:49:20 +00:00
|
|
|
|
2009-05-26 00:49:38 +00:00
|
|
|
/*
|
|
|
|
* Fields and messages generated from http://www.quickfixengine.org/ xml (slightly modified)
|
|
|
|
*/
|
2010-05-13 18:28:34 +00:00
|
|
|
|
2009-05-26 00:49:38 +00:00
|
|
|
#include "packet-fix.h"
|
2002-09-16 17:49:20 +00:00
|
|
|
|
|
|
|
static void dissect_fix_init(void) {
|
2011-05-20 15:44:25 +00:00
|
|
|
/* TODO load xml def for private field */
|
|
|
|
/* TODO check that fix_fields is really sorted */
|
2009-05-26 00:49:38 +00:00
|
|
|
}
|
2002-09-16 17:49:20 +00:00
|
|
|
|
2009-05-26 00:49:38 +00:00
|
|
|
static int
|
|
|
|
tag_search(int key)
|
|
|
|
{
|
|
|
|
int lower = 0, upper = array_length(fix_fields) -1;
|
|
|
|
while (lower <= upper) {
|
2011-05-20 15:44:25 +00:00
|
|
|
int middle = (lower + upper) / 2;
|
|
|
|
int res = fix_fields[middle].tag;
|
|
|
|
if (res < key) {
|
|
|
|
lower = middle + 1;
|
|
|
|
} else if (res == key) {
|
|
|
|
return middle;
|
|
|
|
} else {
|
|
|
|
upper = middle - 1;
|
|
|
|
}
|
2009-05-26 00:49:38 +00:00
|
|
|
}
|
|
|
|
return -1;
|
2002-09-16 17:49:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Code to actually dissect the packets */
|
2009-05-26 00:49:38 +00:00
|
|
|
static int fix_next_header(tvbuff_t *tvb, int offset)
|
2002-09-16 17:49:20 +00:00
|
|
|
{
|
2012-01-05 18:54:02 +00:00
|
|
|
/* try to resync to the next start */
|
2014-06-19 17:18:16 +00:00
|
|
|
guint min_len = tvb_length_remaining(tvb, offset);
|
2014-06-17 15:30:58 +00:00
|
|
|
const guint8 *data = tvb_get_string_enc(wmem_packet_scope(), tvb, offset, min_len, ENC_ASCII);
|
2012-05-03 19:31:03 +00:00
|
|
|
const guint8 *start = data;
|
2010-05-13 18:28:34 +00:00
|
|
|
|
2009-05-26 00:49:38 +00:00
|
|
|
while ((start = strstr(start, "\0018"))) {
|
2009-05-26 04:32:51 +00:00
|
|
|
min_len = (guint) (start +1 -data);
|
2009-05-26 00:49:38 +00:00
|
|
|
/* if remaining length < 6 return and let the next desegment round
|
|
|
|
test for 8=FIX
|
|
|
|
*/
|
2014-06-19 17:18:16 +00:00
|
|
|
if (tvb_length_remaining(tvb, min_len + offset) < MARKER_LEN)
|
2009-05-26 00:49:38 +00:00
|
|
|
break;
|
|
|
|
if (!fix_marker(tvb, min_len +offset) )
|
|
|
|
break;
|
|
|
|
start++;
|
|
|
|
}
|
|
|
|
return min_len;
|
|
|
|
}
|
2002-09-16 17:49:20 +00:00
|
|
|
|
2010-05-13 18:28:34 +00:00
|
|
|
/* ----------------------------------------------
|
2009-05-26 00:49:38 +00:00
|
|
|
Format: name=value\001
|
|
|
|
*/
|
|
|
|
static fix_parameter *fix_param(tvbuff_t *tvb, int offset)
|
|
|
|
{
|
|
|
|
static fix_parameter ret;
|
2012-05-03 19:31:03 +00:00
|
|
|
int equals;
|
2002-09-16 17:49:20 +00:00
|
|
|
|
2009-05-26 00:49:38 +00:00
|
|
|
ret.ctrla_offset = tvb_find_guint8(tvb, offset, -1, 0x01);
|
|
|
|
if (ret.ctrla_offset == -1) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
ret.field_len = ret.ctrla_offset - offset + 1;
|
|
|
|
equals = tvb_find_guint8(tvb, offset, ret.field_len, '=');
|
|
|
|
if (equals == -1) {
|
|
|
|
return NULL;
|
2002-09-16 17:49:20 +00:00
|
|
|
}
|
|
|
|
|
2009-05-26 00:49:38 +00:00
|
|
|
ret.value_offset = equals + 1;
|
2012-05-03 19:31:03 +00:00
|
|
|
ret.tag_len = ret.value_offset - offset - 1;
|
|
|
|
ret.value_len = ret.ctrla_offset - ret.value_offset;
|
2009-05-26 00:49:38 +00:00
|
|
|
return &ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* ---------------------------------------------- */
|
|
|
|
static int fix_header_len(tvbuff_t *tvb, int offset)
|
|
|
|
{
|
2012-05-03 19:31:03 +00:00
|
|
|
int base_offset, ctrla_offset;
|
|
|
|
char *value;
|
|
|
|
int size;
|
2009-05-26 00:49:38 +00:00
|
|
|
fix_parameter *tag;
|
2010-05-13 18:28:34 +00:00
|
|
|
|
2009-05-26 00:49:38 +00:00
|
|
|
base_offset = offset;
|
2010-05-13 18:28:34 +00:00
|
|
|
|
2009-05-26 00:49:38 +00:00
|
|
|
/* get at least the fix version: 8=FIX.x.x */
|
|
|
|
if (fix_marker(tvb, offset) != 0) {
|
|
|
|
return fix_next_header(tvb, offset);
|
|
|
|
}
|
2002-09-16 17:49:20 +00:00
|
|
|
|
|
|
|
/* begin string */
|
|
|
|
ctrla_offset = tvb_find_guint8(tvb, offset, -1, 0x01);
|
|
|
|
if (ctrla_offset == -1) {
|
2010-05-13 18:28:34 +00:00
|
|
|
/* it should be there, (minimum size is big enough)
|
2009-05-26 00:49:38 +00:00
|
|
|
* if not maybe it's not really
|
|
|
|
* a FIX packet but it's too late to bail out.
|
|
|
|
*/
|
|
|
|
return fix_next_header(tvb, offset +MARKER_LEN) +MARKER_LEN;
|
2002-09-16 17:49:20 +00:00
|
|
|
}
|
|
|
|
offset = ctrla_offset + 1;
|
|
|
|
|
|
|
|
/* msg length */
|
2009-05-26 00:49:38 +00:00
|
|
|
if (!(tag = fix_param(tvb, offset)) || tvb_strneql(tvb, offset, "9=", 2)) {
|
|
|
|
/* not a tag or not the BodyLength tag, give up */
|
|
|
|
return fix_next_header(tvb, offset);
|
2002-09-16 17:49:20 +00:00
|
|
|
}
|
|
|
|
|
2014-06-17 15:30:58 +00:00
|
|
|
value = tvb_get_string_enc(wmem_packet_scope(), tvb, tag->value_offset, tag->value_len, ENC_ASCII);
|
2009-05-26 00:49:38 +00:00
|
|
|
/* Fix version, msg type, length and checksum aren't in body length.
|
2010-05-13 18:28:34 +00:00
|
|
|
* If the packet is big enough find the checksum
|
2009-05-26 00:49:38 +00:00
|
|
|
*/
|
|
|
|
size = atoi(value) +tag->ctrla_offset - base_offset +1;
|
2014-06-19 17:18:16 +00:00
|
|
|
if (tvb_length_remaining(tvb, base_offset) > size +4) {
|
2009-05-26 00:49:38 +00:00
|
|
|
/* 10= should be there */
|
|
|
|
offset = base_offset +size;
|
|
|
|
if (tvb_strneql(tvb, offset, "10=", 3) != 0) {
|
|
|
|
/* No? bogus packet, try to find the next header */
|
|
|
|
return fix_next_header(tvb, base_offset +MARKER_LEN) +MARKER_LEN;
|
|
|
|
}
|
|
|
|
ctrla_offset = tvb_find_guint8(tvb, offset, -1, 0x01);
|
|
|
|
if (ctrla_offset == -1) {
|
|
|
|
/* assume checksum is 7 bytes 10=xxx\01 */
|
|
|
|
return size+7;
|
|
|
|
}
|
|
|
|
return size +ctrla_offset -offset +1;
|
2002-09-16 17:49:20 +00:00
|
|
|
}
|
2009-05-26 00:49:38 +00:00
|
|
|
else {
|
2002-09-16 17:49:20 +00:00
|
|
|
}
|
2009-05-26 00:49:38 +00:00
|
|
|
/* assume checksum is 7 bytes 10=xxx\01 */
|
|
|
|
return size +7;
|
|
|
|
}
|
2002-09-16 17:49:20 +00:00
|
|
|
|
2009-05-26 00:49:38 +00:00
|
|
|
/* ---------------------------------------------- */
|
2013-11-09 17:46:28 +00:00
|
|
|
static int
|
|
|
|
dissect_fix_packet(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_)
|
2009-05-26 00:49:38 +00:00
|
|
|
{
|
|
|
|
/* Set up structures needed to add the protocol subtree and manage it */
|
2012-05-03 19:31:03 +00:00
|
|
|
proto_item *ti;
|
|
|
|
proto_tree *fix_tree;
|
|
|
|
int pdu_len;
|
|
|
|
int offset = 0;
|
|
|
|
int field_offset, ctrla_offset;
|
|
|
|
int tag_value;
|
|
|
|
char *value;
|
|
|
|
char *tag_str;
|
2009-05-26 00:49:38 +00:00
|
|
|
fix_parameter *tag;
|
2013-06-14 01:02:11 +00:00
|
|
|
const char *msg_type;
|
2003-06-12 08:02:47 +00:00
|
|
|
|
|
|
|
/* Make entries in Protocol column and Info column on summary display */
|
2009-08-09 07:59:51 +00:00
|
|
|
col_set_str(pinfo->cinfo, COL_PROTOCOL, "FIX");
|
2009-08-09 08:14:59 +00:00
|
|
|
col_clear(pinfo->cinfo, COL_INFO);
|
2002-09-16 17:49:20 +00:00
|
|
|
|
2009-05-26 00:49:38 +00:00
|
|
|
/* get at least the fix version: 8=FIX.x.x */
|
|
|
|
if (fix_marker(tvb, 0) != 0) {
|
|
|
|
/* not a fix packet start but it's a fix packet */
|
2009-08-09 07:59:51 +00:00
|
|
|
col_set_str(pinfo->cinfo, COL_INFO, "[FIX continuation]");
|
2011-10-21 02:10:19 +00:00
|
|
|
ti = proto_tree_add_item(tree, proto_fix, tvb, 0, -1, ENC_NA);
|
2009-05-26 00:49:38 +00:00
|
|
|
fix_tree = proto_item_add_subtree(ti, ett_fix);
|
2011-10-04 22:44:31 +00:00
|
|
|
proto_tree_add_item(fix_tree, hf_fix_data, tvb, 0, -1, ENC_NA);
|
2014-06-19 17:18:16 +00:00
|
|
|
return tvb_length(tvb);
|
2009-05-26 00:49:38 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
pdu_len = tvb_reported_length(tvb);
|
2011-10-21 02:10:19 +00:00
|
|
|
ti = proto_tree_add_item(tree, proto_fix, tvb, 0, -1, ENC_NA);
|
2009-05-26 00:49:38 +00:00
|
|
|
fix_tree = proto_item_add_subtree(ti, ett_fix);
|
|
|
|
|
|
|
|
/* begin string */
|
|
|
|
ctrla_offset = tvb_find_guint8(tvb, offset, -1, 0x01);
|
|
|
|
if (ctrla_offset == -1) {
|
2014-06-19 17:18:16 +00:00
|
|
|
return tvb_length(tvb);
|
2009-05-26 00:49:38 +00:00
|
|
|
}
|
|
|
|
offset = ctrla_offset + 1;
|
|
|
|
|
|
|
|
/* msg length */
|
|
|
|
ctrla_offset = tvb_find_guint8(tvb, offset, -1, 0x01);
|
|
|
|
if (ctrla_offset == -1) {
|
2014-06-19 17:18:16 +00:00
|
|
|
return tvb_length(tvb);
|
2009-05-26 00:49:38 +00:00
|
|
|
}
|
|
|
|
offset = ctrla_offset + 1;
|
|
|
|
|
|
|
|
/* msg type */
|
|
|
|
if (!(tag = fix_param(tvb, offset)) || tag->value_len < 1) {
|
2014-06-19 17:18:16 +00:00
|
|
|
return tvb_length(tvb);
|
2009-05-26 00:49:38 +00:00
|
|
|
}
|
|
|
|
|
2014-06-17 15:30:58 +00:00
|
|
|
value = tvb_get_string_enc(wmem_packet_scope(), tvb, tag->value_offset, tag->value_len, ENC_ASCII);
|
2013-06-14 01:02:11 +00:00
|
|
|
msg_type = str_to_str(value, messages_val, "FIX Message (%s)");
|
|
|
|
col_add_str(pinfo->cinfo, COL_INFO, msg_type);
|
2002-09-16 17:49:20 +00:00
|
|
|
|
|
|
|
/* In the interest of speed, if "tree" is NULL, don't do any work not
|
|
|
|
* necessary to generate protocol tree items.
|
|
|
|
*/
|
2009-05-26 00:49:38 +00:00
|
|
|
field_offset = 0;
|
|
|
|
|
|
|
|
while(field_offset < pdu_len && (tag = fix_param(tvb, field_offset)) ) {
|
|
|
|
int i, found;
|
2010-05-13 18:28:34 +00:00
|
|
|
|
2009-05-26 00:49:38 +00:00
|
|
|
if (tag->tag_len < 1) {
|
|
|
|
field_offset = tag->ctrla_offset + 1;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2014-06-17 15:30:58 +00:00
|
|
|
tag_str = tvb_get_string_enc(wmem_packet_scope(), tvb, field_offset, tag->tag_len, ENC_ASCII);
|
2009-05-26 00:49:38 +00:00
|
|
|
tag_value = atoi(tag_str);
|
|
|
|
if (tag->value_len < 1) {
|
|
|
|
proto_tree *field_tree;
|
2003-06-12 08:02:47 +00:00
|
|
|
/* XXX - put an error indication here. It's too late
|
|
|
|
to return FALSE; we've already started dissecting,
|
|
|
|
and if a heuristic dissector starts dissecting
|
|
|
|
(either updating the columns or creating a protocol
|
|
|
|
tree) and then gives up, it leaves crud behind that
|
|
|
|
messes up other dissectors that might process the
|
|
|
|
packet. */
|
2009-05-26 00:49:38 +00:00
|
|
|
ti = proto_tree_add_text(fix_tree, tvb, field_offset, tag->field_len, "%i: <missing value>", tag_value);
|
|
|
|
field_tree = proto_item_add_subtree(ti, ett_badfield);
|
|
|
|
proto_tree_add_uint(field_tree, hf_fix_field_tag, tvb, field_offset, tag->tag_len, tag_value);
|
|
|
|
field_offset = tag->ctrla_offset + 1;
|
|
|
|
continue;
|
2002-09-16 17:49:20 +00:00
|
|
|
}
|
|
|
|
|
2009-05-26 00:49:38 +00:00
|
|
|
/* fix_fields array is sorted by tag_value */
|
|
|
|
found = 0;
|
|
|
|
if ((i = tag_search(tag_value)) >= 0) {
|
|
|
|
found = 1;
|
|
|
|
}
|
2010-05-13 18:28:34 +00:00
|
|
|
|
2014-06-17 15:30:58 +00:00
|
|
|
value = tvb_get_string_enc(wmem_packet_scope(), tvb, tag->value_offset, tag->value_len, ENC_ASCII);
|
2009-05-26 00:49:38 +00:00
|
|
|
if (found) {
|
|
|
|
if (fix_fields[i].table) {
|
|
|
|
if (tree) {
|
|
|
|
switch (fix_fields[i].type) {
|
|
|
|
case 1: /* strings */
|
2010-05-13 18:28:34 +00:00
|
|
|
proto_tree_add_string_format_value(fix_tree, fix_fields[i].hf_id, tvb, field_offset, tag->field_len, value,
|
2013-12-14 12:45:57 +00:00
|
|
|
"%s (%s)", value, str_to_str(value, (const string_string *)fix_fields[i].table, "unknown %s"));
|
2009-05-26 00:49:38 +00:00
|
|
|
break;
|
|
|
|
case 2: /* char */
|
2010-05-13 18:28:34 +00:00
|
|
|
proto_tree_add_string_format_value(fix_tree, fix_fields[i].hf_id, tvb, field_offset, tag->field_len, value,
|
2013-12-14 12:45:57 +00:00
|
|
|
"%s (%s)", value, val_to_str(*value, (const value_string *)fix_fields[i].table, "unknown %d"));
|
2009-05-26 00:49:38 +00:00
|
|
|
break;
|
|
|
|
default:
|
2010-05-13 18:28:34 +00:00
|
|
|
proto_tree_add_string_format_value(fix_tree, fix_fields[i].hf_id, tvb, field_offset, tag->field_len, value,
|
2013-12-14 12:45:57 +00:00
|
|
|
"%s (%s)", value, val_to_str(atoi(value), (const value_string *)fix_fields[i].table, "unknown %d"));
|
2009-05-26 00:49:38 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
proto_item *item;
|
|
|
|
|
|
|
|
/* checksum */
|
|
|
|
switch(tag_value) {
|
|
|
|
case 10:
|
|
|
|
{
|
|
|
|
proto_tree *checksum_tree;
|
|
|
|
guint8 sum = 0;
|
2013-11-09 18:17:00 +00:00
|
|
|
const guint8 *sum_data = tvb_get_ptr(tvb, 0, field_offset);
|
2009-05-26 00:49:38 +00:00
|
|
|
gboolean sum_ok;
|
|
|
|
int j;
|
|
|
|
|
2013-11-09 18:17:00 +00:00
|
|
|
for (j = 0; j < field_offset; j++, sum_data++) {
|
|
|
|
sum += *sum_data;
|
2009-05-26 00:49:38 +00:00
|
|
|
}
|
|
|
|
sum_ok = (atoi(value) == sum);
|
|
|
|
if (sum_ok) {
|
2010-05-13 18:28:34 +00:00
|
|
|
item = proto_tree_add_string_format_value(fix_tree, fix_fields[i].hf_id, tvb, field_offset, tag->field_len,
|
2009-05-26 00:49:38 +00:00
|
|
|
value, "%s [correct]", value);
|
|
|
|
}
|
|
|
|
else {
|
2010-05-13 18:28:34 +00:00
|
|
|
item = proto_tree_add_string_format_value(fix_tree, fix_fields[i].hf_id, tvb, field_offset, tag->field_len,
|
2009-05-26 00:49:38 +00:00
|
|
|
value, "%s [incorrect should be %d]", value, sum);
|
|
|
|
}
|
|
|
|
checksum_tree = proto_item_add_subtree(item, ett_checksum);
|
|
|
|
item = proto_tree_add_boolean(checksum_tree, hf_fix_checksum_good, tvb, field_offset, tag->field_len, sum_ok);
|
|
|
|
PROTO_ITEM_SET_GENERATED(item);
|
|
|
|
item = proto_tree_add_boolean(checksum_tree, hf_fix_checksum_bad, tvb, field_offset, tag->field_len, !sum_ok);
|
|
|
|
PROTO_ITEM_SET_GENERATED(item);
|
|
|
|
if (!sum_ok)
|
2013-05-26 03:29:07 +00:00
|
|
|
expert_add_info(pinfo, item, &ei_fix_checksum_bad);
|
2009-05-26 00:49:38 +00:00
|
|
|
}
|
2002-09-16 17:49:20 +00:00
|
|
|
break;
|
2009-05-26 00:49:38 +00:00
|
|
|
default:
|
2011-05-20 15:44:25 +00:00
|
|
|
proto_tree_add_string(fix_tree, fix_fields[i].hf_id, tvb, field_offset, tag->field_len, value);
|
2009-05-26 00:49:38 +00:00
|
|
|
break;
|
|
|
|
}
|
2002-09-16 17:49:20 +00:00
|
|
|
}
|
2009-05-26 00:49:38 +00:00
|
|
|
}
|
|
|
|
else if (tree) {
|
|
|
|
proto_tree *field_tree;
|
2010-05-13 18:28:34 +00:00
|
|
|
|
2009-05-26 00:49:38 +00:00
|
|
|
/* XXX - it could be -1 if the tag isn't a number */
|
|
|
|
ti = proto_tree_add_text(fix_tree, tvb, field_offset, tag->field_len, "%i: %s", tag_value, value);
|
|
|
|
field_tree = proto_item_add_subtree(ti, ett_unknow);
|
|
|
|
proto_tree_add_uint(field_tree, hf_fix_field_tag, tvb, field_offset, tag->tag_len, tag_value);
|
2011-10-15 18:46:26 +00:00
|
|
|
proto_tree_add_item(field_tree, hf_fix_field_value, tvb, tag->value_offset, tag->value_len, ENC_ASCII|ENC_NA);
|
2009-05-26 00:49:38 +00:00
|
|
|
}
|
2002-09-16 17:49:20 +00:00
|
|
|
|
2009-05-26 00:49:38 +00:00
|
|
|
field_offset = tag->ctrla_offset + 1;
|
2002-09-16 17:49:20 +00:00
|
|
|
|
2009-05-26 00:49:38 +00:00
|
|
|
tag_str = NULL;
|
|
|
|
}
|
2014-06-19 17:18:16 +00:00
|
|
|
return tvb_length(tvb);
|
2009-05-26 00:49:38 +00:00
|
|
|
}
|
2002-09-16 17:49:20 +00:00
|
|
|
|
2009-05-26 00:49:38 +00:00
|
|
|
static guint
|
|
|
|
get_fix_pdu_len(packet_info *pinfo _U_, tvbuff_t *tvb, int offset)
|
|
|
|
{
|
2011-05-20 15:44:25 +00:00
|
|
|
int fix_len;
|
2002-09-16 17:49:20 +00:00
|
|
|
|
2011-05-20 15:44:25 +00:00
|
|
|
fix_len = fix_header_len(tvb, offset);
|
|
|
|
return fix_len;
|
2009-05-26 00:49:38 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* ------------------------------------
|
|
|
|
fixed-length part isn't really a constant but if we assume it's at least:
|
|
|
|
8=FIX.x.y\01 10
|
|
|
|
9=x\01 4
|
|
|
|
35=x\01 5
|
|
|
|
10=y\01 5
|
|
|
|
24
|
|
|
|
it should catch all 9= size
|
|
|
|
*/
|
2002-09-16 17:49:20 +00:00
|
|
|
|
2009-05-26 00:49:38 +00:00
|
|
|
#define FIX_MIN_LEN 24
|
2006-05-06 21:52:47 +00:00
|
|
|
|
2013-11-09 17:46:28 +00:00
|
|
|
static int
|
|
|
|
dissect_fix_pdus(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data)
|
2009-05-26 00:49:38 +00:00
|
|
|
{
|
|
|
|
tcp_dissect_pdus(tvb, pinfo, tree, fix_desegment, FIX_MIN_LEN,
|
2013-11-09 17:46:28 +00:00
|
|
|
get_fix_pdu_len, dissect_fix_packet, data);
|
2002-09-16 17:49:20 +00:00
|
|
|
|
2014-06-19 17:18:16 +00:00
|
|
|
return tvb_length(tvb);
|
2009-05-26 00:49:38 +00:00
|
|
|
}
|
2002-09-16 17:49:20 +00:00
|
|
|
|
2013-11-09 17:46:28 +00:00
|
|
|
static int
|
|
|
|
dissect_fix(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data)
|
2009-05-26 00:49:38 +00:00
|
|
|
{
|
2013-11-09 17:46:28 +00:00
|
|
|
return dissect_fix_pdus(tvb, pinfo, tree, data);
|
2009-05-26 00:49:38 +00:00
|
|
|
}
|
2002-09-16 17:49:20 +00:00
|
|
|
|
2009-05-26 00:49:38 +00:00
|
|
|
/* Code to actually dissect the packets */
|
|
|
|
static gboolean
|
2013-11-09 17:46:28 +00:00
|
|
|
dissect_fix_heur(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
|
2009-05-26 00:49:38 +00:00
|
|
|
{
|
|
|
|
conversation_t *conv;
|
|
|
|
|
|
|
|
/* get at least the fix version: 8=FIX.x.x */
|
|
|
|
if (fix_marker(tvb, 0) != 0) {
|
|
|
|
/* not a fix packet */
|
|
|
|
return FALSE;
|
2006-05-06 21:52:47 +00:00
|
|
|
}
|
|
|
|
|
2010-05-13 18:28:34 +00:00
|
|
|
conv = find_or_create_conversation(pinfo);
|
|
|
|
conversation_set_dissector(conv, fix_handle);
|
2009-05-26 00:49:38 +00:00
|
|
|
|
2013-11-09 17:46:28 +00:00
|
|
|
dissect_fix_pdus(tvb, pinfo, tree, data);
|
2002-09-16 17:49:20 +00:00
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
2006-05-21 04:49:01 +00:00
|
|
|
/* Register the protocol with Wireshark */
|
2010-05-13 18:28:34 +00:00
|
|
|
static void fix_prefs(void)
|
2009-05-26 00:49:38 +00:00
|
|
|
{
|
2013-08-28 19:10:33 +00:00
|
|
|
dissector_delete_uint_range("tcp.port", fix_tcp_range, fix_handle);
|
2011-05-20 15:44:25 +00:00
|
|
|
g_free(fix_tcp_range);
|
|
|
|
fix_tcp_range = range_copy(global_fix_tcp_range);
|
2013-08-28 19:10:33 +00:00
|
|
|
dissector_add_uint_range("tcp.port", fix_tcp_range, fix_handle);
|
2009-05-26 00:49:38 +00:00
|
|
|
}
|
2002-09-16 17:49:20 +00:00
|
|
|
|
|
|
|
/* this format is require because a script is used to build the C function
|
|
|
|
that calls all the protocol registration.
|
|
|
|
*/
|
|
|
|
|
|
|
|
void
|
|
|
|
proto_register_fix(void)
|
|
|
|
{
|
|
|
|
static hf_register_info hf[] = {
|
2009-05-26 00:49:38 +00:00
|
|
|
{ &hf_fix_data,
|
2011-05-20 15:44:25 +00:00
|
|
|
{ "Continuation Data", "fix.data", FT_BYTES, BASE_NONE, NULL, 0x00,
|
From Kovarththanan Rajaratnam via bug 3548:
(1) Trailing/leading spaces are removed from 'name's/'blurb's
(2) Duplicate 'blurb's are replaced with NULL
(3) Empty ("") 'blurb's are replaced with NULL
(4) BASE_NONE, NULL, 0x0 are used for 'display', 'strings' and 'bitmask' fields
for FT_NONE, FT_BYTES, FT_IPv4, FT_IPv6, FT_ABSOLUTE_TIME, FT_RELATIVE_TIME,
FT_PROTOCOL, FT_STRING and FT_STRINGZ field types
(5) Only allow non-zero value for 'display' if 'bitmask' is non-zero
svn path=/trunk/; revision=28770
2009-06-18 21:30:42 +00:00
|
|
|
NULL, HFILL }
|
2009-05-26 00:49:38 +00:00
|
|
|
},
|
2010-05-13 18:28:34 +00:00
|
|
|
|
2009-05-26 00:49:38 +00:00
|
|
|
{ &hf_fix_field_tag,
|
2011-05-20 15:44:25 +00:00
|
|
|
{ "Field Tag", "fix.field.tag", FT_UINT16, BASE_DEC, NULL, 0x0,
|
2009-05-26 00:49:38 +00:00
|
|
|
"Field length.", HFILL }},
|
2010-05-13 18:28:34 +00:00
|
|
|
|
2009-05-26 00:49:38 +00:00
|
|
|
{ &hf_fix_field_value,
|
2011-05-20 15:44:25 +00:00
|
|
|
{ "Field Value", "fix.field.value", FT_STRING, BASE_NONE, NULL, 0x0,
|
2010-09-23 21:46:31 +00:00
|
|
|
NULL, HFILL }},
|
2009-05-26 00:49:38 +00:00
|
|
|
|
2011-05-20 15:44:25 +00:00
|
|
|
{ &hf_fix_checksum_good,
|
|
|
|
{ "Good Checksum", "fix.checksum_good", FT_BOOLEAN, BASE_NONE, NULL, 0x0,
|
|
|
|
"True: checksum matches packet content; False: doesn't match content or not checked", HFILL }},
|
2009-05-26 00:49:38 +00:00
|
|
|
|
2011-05-20 15:44:25 +00:00
|
|
|
{ &hf_fix_checksum_bad,
|
|
|
|
{ "Bad Checksum", "fix.checksum_bad", FT_BOOLEAN, BASE_NONE, NULL, 0x0,
|
|
|
|
"True: checksum doesn't match packet content; False: matches content or not checked", HFILL }},
|
2002-09-16 17:49:20 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
/* Setup protocol subtree array */
|
|
|
|
static gint *ett[] = {
|
|
|
|
&ett_fix,
|
2009-05-26 00:49:38 +00:00
|
|
|
&ett_unknow,
|
|
|
|
&ett_badfield,
|
|
|
|
&ett_checksum,
|
2002-09-16 17:49:20 +00:00
|
|
|
};
|
|
|
|
|
2013-05-26 03:29:07 +00:00
|
|
|
static ei_register_info ei[] = {
|
|
|
|
{ &ei_fix_checksum_bad, { "fix.checksum_bad.expert", PI_CHECKSUM, PI_ERROR, "Bad checksum", EXPFILL }},
|
|
|
|
};
|
|
|
|
|
2009-05-26 00:49:38 +00:00
|
|
|
module_t *fix_module;
|
2013-05-26 03:29:07 +00:00
|
|
|
expert_module_t* expert_fix;
|
2009-05-26 00:49:38 +00:00
|
|
|
|
2002-09-16 17:49:20 +00:00
|
|
|
/* register re-init routine */
|
|
|
|
register_init_routine(&dissect_fix_init);
|
|
|
|
|
|
|
|
/* Register the protocol name and description */
|
|
|
|
proto_fix = proto_register_protocol("Financial Information eXchange Protocol",
|
2011-05-20 15:44:25 +00:00
|
|
|
"FIX", "fix");
|
2002-09-16 17:49:20 +00:00
|
|
|
|
2013-05-06 13:58:36 +00:00
|
|
|
/* Allow dissector to find be found by name. */
|
2013-11-09 17:46:28 +00:00
|
|
|
fix_handle = new_register_dissector("fix", dissect_fix, proto_fix);
|
2013-05-06 13:58:36 +00:00
|
|
|
|
2002-09-16 17:49:20 +00:00
|
|
|
proto_register_field_array(proto_fix, hf, array_length(hf));
|
2009-05-26 00:49:38 +00:00
|
|
|
proto_register_field_array(proto_fix, hf_FIX, array_length(hf_FIX));
|
2002-09-16 17:49:20 +00:00
|
|
|
proto_register_subtree_array(ett, array_length(ett));
|
2013-05-26 03:29:07 +00:00
|
|
|
expert_fix = expert_register_protocol(proto_fix);
|
|
|
|
expert_register_field_array(expert_fix, ei, array_length(ei));
|
2010-05-13 18:28:34 +00:00
|
|
|
|
2009-05-26 00:49:38 +00:00
|
|
|
fix_module = prefs_register_protocol(proto_fix, fix_prefs);
|
|
|
|
prefs_register_bool_preference(fix_module, "desegment",
|
2011-05-20 15:44:25 +00:00
|
|
|
"Reassemble FIX messages spanning multiple TCP segments",
|
|
|
|
"Whether the FIX dissector should reassemble messages spanning multiple TCP segments."
|
2012-05-03 19:31:03 +00:00
|
|
|
" To use this option, you must also enable"
|
|
|
|
" \"Allow subdissectors to reassemble TCP streams\" in the TCP protocol settings.",
|
2011-05-20 15:44:25 +00:00
|
|
|
&fix_desegment);
|
2009-05-26 00:49:38 +00:00
|
|
|
|
|
|
|
prefs_register_range_preference(fix_module, "tcp.port", "TCP Ports", "TCP Ports range", &global_fix_tcp_range, 65535);
|
|
|
|
|
|
|
|
fix_tcp_range = range_empty();
|
2002-09-16 17:49:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
proto_reg_handoff_fix(void)
|
|
|
|
{
|
2008-09-15 16:36:06 +00:00
|
|
|
/* Let the tcp dissector know that we're interested in traffic */
|
2009-05-26 00:49:38 +00:00
|
|
|
heur_dissector_add("tcp", dissect_fix_heur, proto_fix);
|
2008-09-15 16:36:06 +00:00
|
|
|
/* Register a fix handle to "tcp.port" to be able to do 'decode-as' */
|
2014-06-20 16:43:28 +00:00
|
|
|
dissector_add_for_decode_as("tcp.port", fix_handle);
|
2002-09-16 17:49:20 +00:00
|
|
|
}
|
|
|
|
|