是否有人在那里完成了对数据包捕获接口(如jpcap)的实施UDPSocket
(用于UDP数据报)和InputStream
(用于TCP流)的工作?可能坐在网络上并接收TCP流/ UDP数据报?
我想在jpcap中给出回调API并不会太难,但是任何人都已经完成了吗?这样做是否有任何问题(例如,我是否必须弄清楚如何自己重新组合TCP流?)
是否有人在那里完成了对数据包捕获接口(如jpcap)的实施UDPSocket
(用于UDP数据报)和InputStream
(用于TCP流)的工作?可能坐在网络上并接收TCP流/ UDP数据报?
我想在jpcap中给出回调API并不会太难,但是任何人都已经完成了吗?这样做是否有任何问题(例如,我是否必须弄清楚如何自己重新组合TCP流?)
我没有做过这件事情,但我在解析捕获的数据包方面做了很多工作在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是开源的,您可以通过查看它的工作方式来了解更多信息。
可以使用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);
我补充一点:我觉得最简单的拉包报头为C风格的结构,其复制数据包的布局。这需要预处理器指令来防止内部填充结构,并且您必须记住分别使用ntohs()和ntohl()将16位和32位值转换为主机字节顺序。我不知道类似的方法在Java中是否可行, – ceo 2009-12-03 19:44:33