【问题标题】:tshark export FIX messagestshark 导出 FIX 消息
【发布时间】:2012-11-28 09:50:03
【问题描述】:

目标

我正在努力实现以下目标:

  • 捕获包含FIX protocol 中的对话的网络流量
  • 从网络流量中提取单个 FIX 消息为“不错”的格式,例如CSV
  • 对导出的“nice”格式数据做一些数据分析

我通过以下方式实现了这一目标:

  • 使用 pcap 捕获网络流量
  • 使用 tshark 以 CSV 格式打印相关数据
  • 使用 Python(熊猫)分析数据

问题

问题是一些捕获的 TCP 数据包包含多个 FIX 消息,这意味着当我使用 tshark 导出到 CSV 时,我没有收到每行的 FIX 消息。这使得使用 CSV 变得困难。

这是我用来将相关 FIX 字段提取为 CSV 的 tshark 命令行:

tshark -r dump.pcap \
-R \'(fix.MsgType[0]=="G" or fix.MsgType[0]=="D" or fix.MsgType[0]=="8" or \ fix.MsgType[0]=="F") and fix.ClOrdID != "0"\' \ 
-Tfields -Eseparator=, -Eoccurrence=l -e frame.time_relative \
-e fix.MsgType -e fix.SenderCompID \
-e fix.SenderSubID -e fix.Symbol -e fix.Side \
-e fix.Price -e fix.OrderQty -e fix.ClOrdID \
-e fix.OrderID -e fix.OrdStatus'

请注意,如果数据包中出现多个字段,我目前使用“-Eoccurrence=l”来获取命名字段的最后一次出现。这不是一个可接受的解决方案,因为当一个数据包中有多个 FIX 消息时,信息将被丢弃。

这是我希望在导出的 CSV 文件中看到的每一行(来自一条 FIX 消息的字段):

16.508949000,D,XXX,XXX,YTZ2,2,97480,34,646427,,

当 TCP 数据包中有多个 FIX 消息(本例为三个)并且使用了命令行标志“-Eoccurrence=a”时,我会看到以下内容:

16.515886000,F,F,G,XXX,XXX,XXX,XXX,XXX,XXX,XTZ2,2,97015,22,646429,646430,646431,323180,323175,301151,

问题

有没有办法(不一定使用 tshark)从 pcap 文件中提取每个单独的、特定于协议的消息?

【问题讨论】:

  • 一种意见,FIX 消息中的最后一个字段保证是校验和(10=某个数字)。你为什么不在这个标签上打破你的消息边界,同时读/写 FIX 消息。由于 FIX 消息的长度不同,TCP 数据包肯定会有所不同,因此您不能设置固定的数据包大小来读取 FIX 消息。
  • 在这种情况下,我无法控制将 FIX 消息写入网络,因此无法强制每个数据包发送一条 FIX 消息。我也不直接从网络上读取 FIX。我查看 FIX 的原因是为了进行性能分析。我最终使用“|8=FIX”来指示 TCP 有效负载中第二个或更晚的 FIX 消息的开始(请参阅下面的解决方案)。

标签: pcap fix-protocol tshark


【解决方案1】:

更好的解决方案

使用tcpflow 可以在不离开命令行的情况下正确完成此操作。

我目前的方法是使用类似的东西:

tshark -nr <input_file> -Y'fix' -w- | tcpdump -r- -l -w- | tcpflow -r- -C -B

tcpflow 确保遵循 TCP 流,因此不会丢失 FIX 消息(在单个 TCP 数据包包含超过 1 个 FIX 消息的情况下)。 -C 写入控制台,-B 确保二进制输出。这种方法与在 Wireshark 中跟踪 TCP 流没有什么不同。

FIX 分隔符被保留,这意味着我可以对输出进行一些方便的 grepping,例如

... | tcpflow -r- -C -B | grep -P "\x0135=8\x01"

提取所有执行报告。注意 grep 的 -P 参数,它允许非常强大的 perl 正则表达式。

(以前的)解决方案

我正在使用 Scapy(另请参阅 Scapy DocumentationThe Very Unofficial Dummies Guide to Scapy)读取 pcap 文件并从数据包中提取每个单独的 FIX 消息。

以下是我使用的代码的基础:

from scapy.all import *

def ExtractFIX(pcap):
    """A generator that iterates over the packets in a scapy pcap iterable
and extracts the FIX messages.
In the case where there are multiple FIX messages in one packet, yield each
FIX message individually."""
    for packet in pcap:
        if packet.haslayer('Raw'):
            # Only consider TCP packets which contain raw data.
            load = packet.getlayer('Raw').load

            # Ignore raw data that doesn't contain FIX.
            if not 'FIX' in load:
                continue

            # Replace \x01 with '|'.
            load = re.sub(r'\x01', '|', load)

            # Split out each individual FIX message in the packet by putting a 
            # ';' between them and then using split(';').
            for subMessage in re.sub(r'\|8=FIX', '|;8=FIX', load).split(';'):
                # Yield each sub message. More often than not, there will only be one.
                assert subMessage[-1:] == '|'
                yield subMessage
        else:
            continue

pcap = rdpcap('dump.pcap')
for fixMessage in ExtractFIX(pcap):
    print fixMessage        

我仍然希望能够从网络数据包的“帧”层获取其他信息,尤其是相对(或参考)时间。不幸的是,这似乎不适用于 Scapy 数据包对象 - 它的最顶层是 Ether 层,如下所示。

In [229]: pcap[0]
Out[229]: <Ether  dst=00:0f:53:08:14:81 src=24:b6:fd:cd:d5:f7 type=0x800 |<IP  version=4L ihl=5L tos=0x0 len=215 id=16214 flags=DF frag=0L ttl=128 proto=tcp chksum=0xa53d src=10.129.0.25 dst=10.129.0.115 options=[] |<TCP  sport=2634 dport=54611 seq=3296969378 ack=2383325407 dataofs=8L reserved=0L flags=PA window=65319 chksum=0x4b73 urgptr=0 options=[('NOP', None), ('NOP', None), ('Timestamp', (581177, 2013197542))] |<Raw  load='8=FIX.4.0\x019=0139\x0135=U\x0149=XXX\x0134=110169\x015006=20\x0150=XXX\x0143=N\x0152=20121210-00:12:13\x01122=20121210-00:12:13\x015001=6\x01100=SFE\x0155=AP\x015009=F3\x015022=45810\x015023=3\x015057=2\x0110=232\x01' |>>>>
In [245]: pcap[0].summary()
Out[245]: 'Ether / IP / TCP 10.129.0.25:2634 > 10.129.0.115:54611 PA / Raw'

【讨论】:

  • 看来 scapy.packet.time() 可能给了我想要的东西。 Wireshark 在名为“Frame”的部分中显示了一个 [Time since reference or first frame: 77.326326000 seconds] 字段,该字段看起来像 Ether 层之上的一个层。我认为这只是 Wireshark 生成的额外数据,而不是数据包中实际存在的数据。
猜你喜欢
  • 2014-10-07
  • 2013-02-13
  • 1970-01-01
  • 2023-01-12
  • 1970-01-01
  • 1970-01-01
  • 2014-12-23
  • 1970-01-01
  • 2012-08-24
相关资源
最近更新 更多