2009-12-02 91 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);