0

有没有人完成了坐在数据包捕获接口(如 jpcap)之上的工作,并实现了UDPSocket(用于 UDP 数据报)和InputStream(用于 TCP 流)?

我想考虑到 jpcap 中的回调 API,这不会太难做,但是那里有人已经做过了吗?这样做有什么问题吗(例如,我是否必须弄清楚如何自己重新组装 TCP 流?)

4

2 回答 2

2

我没有做过这件特别的事情,但我在解析 C/C++ 中捕获的数据包方面做了很多工作。我不知道是否存在适用于此的 Java 库。

从本质上讲,您需要从 IP 开始沿着协议栈向上工作。pcap 数据以链路级标头开头,但我认为除了忽略非 IP 数据包之外,您关心的内容并不多。

IP 最棘手的事情是重新组装分段的数据报。这是使用 Flags 字段和 Fragment Offset 字段中的 More Fragments 位完成的,结合 Identification 字段来区分来自不同数据报的片段 然后使用 Protocol 字段来识别 TCP 和 UDP 数据包,并使用 Header Length 字段来查找相应标题的开头。

对于 TCP 和 UDP,下一步是多路分解,分离捕获的数据包流中的各种连接。两种协议都通过源和目标 IP 地址以及源和目标端口的 4 元组来识别连接(嗯,UDP 本身没有连接,但我没有更好的词),所以连接会是在所有 4 个值上匹配的数据包序列。

一旦完成,对于 UDP,你就快完成了,除非你想检查校验和。UDP 标头中的 Length 字段告诉您数据包有多长;为标题减去 8 个字节,这就是你的数据。

TCP 稍微复杂一些,因为您确实必须重新组装流,这是使用标头中的序列号和长度来完成的。这两者的总和告诉您流中的下一个序列号。请记住,您正在跟踪两个方向的流量。

(这比编写实际的 TCP 实现要容易得多,因为您必须实现 Nagle 算法和其他细节。)

网上有很多关于标题格式的信息;对于初学者来说,谷歌“IP 标头”。像 Wireshark 这样的网络分析仪对于这项工作来说是必不可少的,因为它会向您展示捕获的数据应该是什么样子。确实,由于 Wireshark 是开源的,您可能可以通过查看它的工作方式来了解很多

于 2009-12-03T15:47:21.157 回答
2

Tcp 重组可以使用JNetPcap完成。这是一个完整的例子:

final String SOME_PORT = 8888;

StringBuilder errbuf = new StringBuilder();
Pcap pcap = Pcap.openOffline("/dir/someFile.pcap", errbuf); //Can be replace with .openLive(...)

if (pcap == null) {
    System.err.printf("Error: "+errbuf.toString());
    return;
}

//Handler that receive Tcp Event one by one
AnalyzerListener<TcpStreamEvent> handler = new AnalyzerListener<TcpStreamEvent>() {

    @Override
    public void processAnalyzerEvent(TcpStreamEvent evt) {
        JPacket packet = evt.getPacket();

        Tcp tcp = new Tcp();
        if (packet.hasHeader(tcp)) {

              //Limiting the analysis to a specific protocol
              if (tcp.destination() == SOME_PORT || tcp.source() == SOME_PORT) {
                    String data = new String(tcp.getPayload());
                    System.out.println("Capture data:{"+data+"}");
              }
        }
    }
};

TcpAnalyzer tcpAnalyzer = JRegistry.getAnalyzer(TcpAnalyzer.class);
tcpAnalyzer.addTcpStreamListener(handler, null);

//Starting the capture
pcap.loop(Pcap.LOOP_INFINATE,  JRegistry.getAnalyzer(JController.class), null);
于 2010-06-23T00:45:12.443 回答