2009-12-02 89 views
0

是否有人在那里完成了对数据包捕获接口(如jpcap)的实施UDPSocket(用于UDP数据报)和InputStream(用于TCP流)的工作?可能坐在网络上并接收TCP流/ UDP数据报?

我想在jpcap中给出回调API并不会太难,但是任何人都已经完成了吗?这样做是否有任何问题(例如,我是否必须弄清楚如何自己重新组合TCP流?)

回答

2

我没有做过这件事情,但我在解析捕获的数据包方面做了很多工作在C/C++中。我不知道是否有任何这样的Java库。

从本质上讲,您需要按照IP开始协议栈。 pcap数据从链接级别标题开始,但我认为除了忽略非IP数据包之外,您不关心其中的任何内容。

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

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

一旦这样做,对于UDP,你就要完成了,除非你想检查校验和。 UDP头部中的Length字段告诉你数据包有多长;减去头部的8个字节,并有你的数据。

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

(这比写一个实际的TCP实现要容易得多,因为那么你必须实现Nagle算法和其它细节。)

有很多的关于标题格式的网络信息;谷歌“IP标题”为初学者。像Wireshark这样的网络分析器对于这项工作来说是不可或缺的,因为它会告诉你如何捕获你的数据。事实上,由于Wireshark是开源的,您可以通过查看它的工作方式来了解更多信息。

+0

我补充一点:我觉得最简单的拉包报头为C风格的结构,其复制数据包的布局。这需要预处理器指令来防止内部填充结构,并且您必须记住分别使用ntohs()和ntohl()将16位和32位值转换为主机字节顺序。我不知道类似的方法在Java中是否可行, – ceo 2009-12-03 19:44:33

2

可以使用JNetPcap完成TCP重组。下面是一个完整的例子:

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);