是否有人在那裏完成了對數據包捕獲接口(如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