While analyzing FIX protocol traffic in Wireshark (version 4.0.8), I encountered a puzzling scenario where a complete FIX logon message was incorrectly flagged as TCP segment of a reassembled PDU
. Here's the packet breakdown:
Frame 4 (properly parsed):
0000 8a 01 00 00 01 00 00 00 49 01 35 3d 38 3d 46 49
0010 58 2e 34 2e 34 01 34 39 3d 43 4c 49 45 4e 54 01
0020 35 36 3d 55 53 45 52 4e 41 4d 45 01 33 34 3d 31
0030 01 35 32 3d 32 30 32 34 30 38 32 38 01 31 30 3d
0040 30 36 30 01
Frame 6 (incorrectly flagged):
0000 8a 01 00 00 01 00 00 00 49 01 35 3d 38 3d 46 49
0010 58 2e 34 2e 34 01 34 39 3d 53 45 52 56 45 52 01
0020 35 36 3d 41 44 4d 49 4e 01 33 34 3d 32 01 35 32
0030 3d 32 30 32 34 30 38 32 38 01 31 30 3d 31 32 30
0040 01
To verify this wasn't an actual TCP segmentation issue, I performed the following checks:
- Confirmed TCP sequence numbers are contiguous (no missing segments)
- Verified IP total length matches payload size
- Checked that the FIX message contains complete tags (8=FIX.4.4|9=xxx|...)
- Validated TCP checksums
The root cause appears to be Wireshark's heuristic for determining message boundaries in stateful protocols. The FIX dissector makes these assumptions:
/* Sample from Wireshark's packet-fix.c */
if (tvb_reported_length_remaining(tvb, offset) < FIX_MINIMUM_LENGTH) {
expert_add_info_format(pinfo, ti, &ei_fix_short_message,
"Message too short (%d bytes) to be FIX", reported_length);
return offset;
}
Interestingly, the second logon triggers this edge case because:
- The TCP window scaling differs slightly
- The FIX tags appear in different order
- Wireshark's TCP reassembly buffer hasn't been flushed
Here are three approaches to force proper parsing:
Method 1: Clear TCP reassembly cache
// Lua script to reset dissection state
local fix_proto = Proto.get("FIX")
function fix_proto.dissector(tvb,pinfo,tree)
if pinfo.visited then return end
-- Force fresh dissection
end
Method 2: Use display filters
# Explicitly match FIX messages
fix && !tcp.reassembly
Method 3: Protocol preferences
Navigate to Analyze → Enabled Protocols
and toggle FIX protocol
This Python script validates complete FIX messages in PCAPs:
from scapy.all import *
import fixparser
def validate_fix(pcap):
for pkt in rdpcap(pcap):
if TCP in pkt and pkt[TCP].dport == 9876: # FIX port
raw = bytes(pkt[TCP].payload)
if not fixparser.validate_complete(raw):
print(f"Incomplete FIX at frame {pkt.frame_info.number}")
validate_fix("fix_logon.pcap")
The false reassembly flag typically occurs when Wireshark's internal state doesn't perfectly align with the protocol state machine. For FIX protocol analysis, consider using specialized tools like fixinspector
alongside Wireshark for validation.
When analyzing the provided pcap file, we see an interesting Wireshark interpretation anomaly:
Frame 4: [FIX] Logon (normal parsing) Frame 6: [TCP segment of a reassembled PDU] (incorrect interpretation)
Both frames contain complete FIX protocol messages, yet Wireshark treats them differently despite identical protocol characteristics.
Wireshark's reassembly behavior stems from its TCP stack implementation. The key factors influencing this behavior include:
- TCP sequence number tracking
- Packet timing thresholds
- Protocol preference settings
To diagnose this issue, we should verify:
// Check TCP header fields if (tcp_header->seq != expected_seq) { // Triggers reassembly flag } // Validate IP length consistency if (ip_total_len != tcp_payload_len + headers) { // May trigger fragmentation handling }
The FIX protocol dissector might need explicit configuration to prevent false reassembly detection. Try these approaches:
1. Right-click packet → Decode As → FIX 2. Edit preferences → Protocols → TCP: - Disable "Allow subdissector to reassemble TCP streams" - Adjust "Max concurrent TCP streams"
For immediate analysis needs, force Wireshark to parse the packet as FIX:
// Alternative analysis method using tshark tshark -r capture.pcap -Y "tcp.stream eq 1 && tcp.payload" -T json
The root cause often relates to subtle timing or window size variations. This Python snippet simulates Wireshark's decision logic:
def is_reassembly_needed(packet): return ( packet.timestamp_delta > REASSEMBLY_THRESHOLD or packet.tcp_window < MIN_WINDOW_SIZE or len(packet.tcp_payload) < EXPECTED_MIN_SIZE )
For reliable FIX protocol analysis:
- Maintain consistent TCP window sizes
- Avoid microsecond-level packet spacing
- Consider adding FIX protocol markers