Wireshark Misinterprets Complete FIX Logon as TCP Reassembled PDU: Troubleshooting and Solution


3 views

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:

  1. Confirmed TCP sequence numbers are contiguous (no missing segments)
  2. Verified IP total length matches payload size
  3. Checked that the FIX message contains complete tags (8=FIX.4.4|9=xxx|...)
  4. 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