使用Jpcap進行java平臺下的ipv6網絡抓包

前陣子做網絡實驗的時候,要求做一個抓包程序,還要能處理ipv6的報文。如此底層的操作,通常我們都認爲是C或者C++的分內事,但其實java也可以做到這一點!

java的網絡功能

稍微熟悉jdk的人都知道java對於網絡的支持基本都在傳輸層以上,也就是說java代碼能操作到的數據最底層也就是面向tcp、udp,動不動就被封裝成“流”或是socket什麼的。如果要實現抓包,通常都要涉及到數據鏈路層的操作。在c或c++,我們可以使用大名鼎鼎的wincap;而在java平臺,現在已經有人將wincap的接口封裝成爲jar包了,所以我們只需要下載wincap和jpcap,安裝後就能直接用java代碼操作底層數據流了

jpcap下載:http://netresearch.ics.uci.edu/kfujii/jpcap/doc/download.html

這裏不打算細述jpcap的基本用法,只是記錄使用jpcap的一些心得,以及jpcap的一些缺陷和不足

jpcap功能簡述

JVM從來沒有提供過操作網絡底層數據的接口,我估計未來也不會,因爲這很明顯不是java“應該和擅長做的事情”,不過還好有JNI這個東西,讓java的觸角可以延伸到許多c++才能做的地方。jpcap的原理說來其實很簡單,就是利用JNI以java開發者喜聞樂見的方式封裝了wincap的接口,所以如果你熟悉wincap,相信jpcap只是小菜一碟

jpcap的jar包很小,裏面封裝的類也不多,如下:

 

Class Hierarchy

 

類的用法基本上看看文檔就知道了,去google一下“jpcap”的教程也有一大把,基本過程如下:

抓取的報文通常都繼承了jpcap.packet.Packet 類,可以通過datalink字段獲得該Packet的數據鏈路層幀,也就是jpcap.packet.DatalinkPacket,從而進行數據鏈路層的包解析

針對常見的報文,如ARP、IP報文,jpcap都有相應的類,例如IPPacket類就封裝了IP報文的各個字段(包括IPV4和IPV6),因此,程序主要的邏輯過程就是用java的instanceof關鍵字,判斷屬於哪一類報文,從而進行相應的處理。

一切都很方便!下面重點說一下如何處理ipv6

jpcap for ipv6

從文檔可以看出,jpcap對ipv6有一定的支持,提供了不少靜態字段和類用於表示ipv6的包,但是在使用過程中,我發現jpcap對於ipv6的支持還是遠遠不夠的(我使用的jpcap版本爲0.6),最主要問題就是缺少對隧道IPV6的支持

現在很多地方由於硬件或其他限制,使用的還不是純粹的ipv6,譬如我宿舍的網絡就是使用隧道的,在配置ipv6時必須輸入“netsh interface ipv6 isatap set router”命令來設置isatap隧道路由器的地址,否則無法連接到www.kame.net等網站。如果用ethereal等軟件進行抓包,就可以看出是在ipv4的PDU裏面包含了ipv6的報文,例如:

clip_image002[5]

可見是使用了隧道機制的ipv6,在ipv4報文的protocol字段,指明瞭是“ipv6”

在遇到隧道形式的ipv6時,JPCAP並沒有提供相應的封裝,抓獲的報文是“jpcap.packet.IPPacket”,但JPCAP僅僅將其解析爲ipv4報文,隧道ipv6報文全部被認爲是ipv4的載荷。我嘗試使用了JPCAP提供的一個demo程序抓取隧道ipv6報文,發現其仍舊無法正確解析v6的內容。在參考了JPCAP的文檔後,發現 JPCAP不能直接提供隧道ipv6的功能,,看來是jpcap的設計者暫時沒有考慮到“v6 on v4”的情況,因此只能像wincap那樣手動處理字節序列

JPCAP中每個Packet的子類都有一個字段是data[],可以獲得報文載荷,例如jpcap.packet.IPPacket.data[]獲得的就是IP報文的載荷。處理比特位對java來說是弱項,很多方面不如c或c++那樣方便,但撇開效率不談,仍然是有辦法做到的,只要掌握一些java環境下的字節移位操作即可。下面是我的程序實例:

 

 

 

裏面的關鍵部分是對字節的移位操作,分以下幾個步驟:

  1. 獲得負載信息,每個Package類都有一個“字節數組”字段data[],包含了報文的負載,如:byte[] ipv6byte = ipp.data;
  2. 然後根據ipv6的報頭結構,逐個處理data裏面的字節
  3. 比如頭四位是報文的version字段,可以這樣處理:int version = ipv6byte[0]>>>4; 關鍵是搞清楚java裏面的右移操作符,“>>>”是指右移並補0,而“>>”則是補1,需要一些基本的計算機組成原理的知識
  4. 緊接着,是八個比特位的“trafficClass”字段,需要把data[0]的後四位跟data[1]的前四位拼起來:int trafficClass = ipv6byte[0]<<4 + ipv6byte[1]>>>4;
  5. 還有一個需要注意的地方,就是java裏面byte類型是有符號的,即字節的最高位是符號位。而ip報文是無符號的,所以要手動轉換一下,如:int nextHeader = ipv6byte[6]&0xff; 否則可能得到一個負號的int

其他的字段同理可得

 

附一張截圖,我自己做的一個抓包程序抓到的隧道ipv6報文

clip_image002

 

最後是廣告時間,推薦一個MyEclipse平臺下的SWING開發插件:M4M。如果你用過NetBean,應該對裏面的GUI開發工具印象深刻,可以支持拖拽和自動對齊,感覺已經很接近VC,至少比以往的java GUI開發工具好很多。但是NetBean開發出來的GUI代碼不能在Eclipse裏面用,現在有了M4M,也一樣可以實現這種方便的開發模式了,至少對我這種GUI傻瓜來說,方便了不少

 

小結

JPCAP由於對隧道ipv6的支持不夠,必須手工進行解析,那樣如果使用隧道機制,則對於所有上層協議的解析都要手工進行,jpcap裏面的“TCPPacket,UDPPacket”等類就作廢了,希望以後的版本可以解決這個問題

 

本demo的源碼下載:http://download.csdn.net/source/2256471

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章