前言
本學(xué)期學(xué)習(xí)了《計(jì)算機(jī)網(wǎng)絡(luò)》專業(yè)課程,老師布置了課程設(shè)計(jì)大作業(yè),作業(yè)要求如下:
- 使用 JPCAP或 wireshark等抓包,可以使用JAVA、PYTHON或C++寫代碼對(duì)數(shù)據(jù)進(jìn)行分析,最后可視化顯示;
本文只實(shí)現(xiàn)了使用 Java語言的jpcap接口 在 IDEA環(huán)境下抓取數(shù)據(jù)包的功能
一、Java搭建 winpcap開發(fā)環(huán)境
在抓包開始前,需要在Java中搭建winpcap開發(fā)環(huán)境;
1. 名詞解釋
1.1 winpcap
- winpcap就是一個(gè)更加底層的系統(tǒng), 通過這個(gè)軟件可以在window平臺(tái)下實(shí)現(xiàn)直接的網(wǎng)絡(luò)編程;
- 但是要注意的是winpcap的實(shí)現(xiàn)是使用C/C++實(shí)現(xiàn)的, 所以我們就需要一個(gè)中間件來實(shí)現(xiàn)從C到Java的轉(zhuǎn)化;
1.2 jpcap
- jpcap簡(jiǎn)單來說就是對(duì)于winpcap一層封裝 作為一個(gè)中間件,調(diào)用winpcap,提供一個(gè)接口,使Java實(shí)現(xiàn)對(duì)數(shù)據(jù)鏈路層的控制;
- 這樣現(xiàn)實(shí)了平臺(tái)的無關(guān)性;
1.3 網(wǎng)卡
- 無論在什么操作系統(tǒng)下,我們要發(fā)送數(shù)據(jù)報(bào)到網(wǎng)絡(luò)上,就離不開這樣一個(gè)東西:網(wǎng)卡 網(wǎng)卡是工作在數(shù)據(jù)鏈路層
- 涉及幀的發(fā)送與接收、幀的封裝與拆封、介質(zhì)訪問控制、數(shù)據(jù)的編碼與解碼以及數(shù)據(jù)緩存的功能等
- 無論什么數(shù)據(jù)報(bào)從網(wǎng)絡(luò)發(fā)送到本機(jī),都是通過網(wǎng)卡再保存到本地的緩沖區(qū)上 所以我們?cè)诰W(wǎng)絡(luò)編程抓包的時(shí)候,首先要確定就是從哪塊網(wǎng)卡上抓包
2. 搭建開發(fā)環(huán)境
2.1 安裝winpcap
下載安裝包
地址:https://www.winpcap.org/
完成之后,安裝到Windows的電腦中即可
2.2 設(shè)置Jpcap.dll
特別注意:64位的系統(tǒng)要下載64位的對(duì)應(yīng)的DLL;
但是官網(wǎng)上提供的下載是32位系統(tǒng)的?。?/strong>
我在百度網(wǎng)盤上傳了一份64位的:
鏈接:https://pan.baidu.com/s/19xiD0N2UfuV0C0VhALJqLQ 提取碼:ley0
下載到本地之后,將Jpcap.dll放到JDK安裝路徑下的 /jre/bin 目錄下;
2.3 導(dǎo)入jar包
使用IDEA新建一個(gè)普通的Java項(xiàng)目,導(dǎo)入Jar包
打開項(xiàng)目的項(xiàng)目結(jié)構(gòu),將剛才下載Jar包添加到項(xiàng)目結(jié)構(gòu)的庫(kù)中,如下圖:
以上內(nèi)容參考博客 https://blog.csdn.net/wchstrife/article/details/79922073
3. 測(cè)試demo
在進(jìn)行了開發(fā)環(huán)境的搭建后,就讓我們用一個(gè)簡(jiǎn)單的程序試試是否能顯示網(wǎng)卡吧
3.1 代碼實(shí)現(xiàn)
- 如下圖:
import jpcap.JpcapCaptor;
import jpcap.NetworkInterface;
public class JpcapDemo {
public static void main(String[] args) {
/*-------第一步,顯示網(wǎng)絡(luò)設(shè)備列表-------- */
// 獲取網(wǎng)絡(luò)接口列表,返回你所有的網(wǎng)絡(luò)設(shè)備數(shù)組,一般就是網(wǎng)卡;
NetworkInterface[] devices = JpcapCaptor.getDeviceList();
int k = -1;
// 顯示所有網(wǎng)絡(luò)設(shè)備的名稱和描述信息;
// 要注意的是,顯示出來的網(wǎng)絡(luò)設(shè)備在不同網(wǎng)絡(luò)環(huán)境下是不同的,可以在控制臺(tái)使用 ipconfig /all命令查看;
for (NetworkInterface n : devices) {
k++;
System.out.println("序號(hào) " + k + " " + n.name + " | " + n.description);
System.out.println(“------------------------------------------------”);
}
}
}
3.2 網(wǎng)卡分析
- 當(dāng)使用以太網(wǎng)接口時(shí),網(wǎng)卡序號(hào)為 0 -10,以太網(wǎng)對(duì)應(yīng)的網(wǎng)卡為序號(hào)7
- 當(dāng)拔掉網(wǎng)線,使用無線wife網(wǎng)絡(luò)時(shí),網(wǎng)卡序號(hào)變成了 0 -9,以太網(wǎng)對(duì)應(yīng)的網(wǎng)卡消失了
- 如上,顯示出來的網(wǎng)絡(luò)設(shè)備在不同網(wǎng)絡(luò)環(huán)境下是不同的,可以在控制臺(tái)使用 ipconfig /all命令查看,如下圖:
如果你也可以像上面代碼一樣顯示出網(wǎng)絡(luò)設(shè)備的信息,那就恭喜你搭建網(wǎng)絡(luò)環(huán)境成功啦!接著進(jìn)行下一步吧!
二、連接網(wǎng)卡
1. 獲取網(wǎng)絡(luò)接口列表
要想從網(wǎng)絡(luò)中捕獲數(shù)據(jù)包,第一件必須要做的事就是獲取本機(jī)的網(wǎng)絡(luò)接口列表
- Jpcap提供了方法JpcapCaptor.getDeviceList()完成這個(gè)任務(wù),該方法返回一組NetworkInterface對(duì)象
- NetworkInterface接口對(duì)象包含了對(duì)應(yīng)網(wǎng)絡(luò)接口的一些信息,例如:名稱、描述、IP以及MAC地址以及數(shù)據(jù)鏈路層名稱和描述
獲取網(wǎng)絡(luò)接口的代碼就是上面的JpcapDemo代碼,大家可以回頭看看,為了節(jié)省篇幅這里就不貼啦
2. 打開網(wǎng)絡(luò)接口
一旦有了網(wǎng)絡(luò)接口列表就可以從選定用于捕獲數(shù)據(jù)包的網(wǎng)絡(luò)接口,可以使用方法JpcapCaptor.openDevice()來打開指定的網(wǎng)絡(luò)接口,注意此并未開始捕獲數(shù)據(jù)包。
2.1 代碼實(shí)現(xiàn)
- 代碼如下:
/*--------第二步,選擇網(wǎng)卡并打開網(wǎng)卡連接--------*/
// 選擇網(wǎng)卡序號(hào);
// 注意!每臺(tái)設(shè)備連接網(wǎng)絡(luò)的網(wǎng)卡不同,選擇正確的網(wǎng)卡才能捕獲到數(shù)據(jù)包;
System.out.println("請(qǐng)輸入你想要監(jiān)聽的網(wǎng)卡序號(hào): ");
Scanner sc = new Scanner(System.in);
int index = sc.nextInt();
JpcapCaptor jpcap = null;// 聲明一個(gè)JpcapCaptor全局實(shí)例變量 jpcap;
// 打開網(wǎng)卡連接,此時(shí)還未開始捕獲數(shù)據(jù)包;
try {
jpcap = JpcapCaptor.openDevice(devices[index], 1512, true,5000);// 捕獲時(shí)間為5s
} catch (IOException e) {
e.printStackTrace();
System.out.println("抓取數(shù)據(jù)包時(shí)出現(xiàn)異常!!");
}
2.2 方法解釋
靜態(tài)方法 static JpcapCaptor openDevice (NetworkInterface interface, int snaplen, boolean promisc, int to_ms):
創(chuàng)建一個(gè)與指定設(shè)備的連接并返回該連接。調(diào)用該方法必須指定下列參數(shù):
- interface:要打開連接的設(shè)備的實(shí)例;
- snaplen:這個(gè)是比較容易搞混的一個(gè)參數(shù)。其實(shí)這個(gè)參數(shù)不是限制只能捕捉多少數(shù)據(jù)包,而是限制每一次收到一個(gè)數(shù)據(jù)包,只提取該數(shù)據(jù)包中前多少字節(jié);
- promisc:設(shè)置是否混雜模式。處于混雜模式將接收所有數(shù)據(jù)包,若之后又調(diào)用了包過濾函數(shù) setFilter() 將不起任何作用 (后面會(huì)介紹);
- to_ms:指定捕獲數(shù)據(jù)包超時(shí)的時(shí)間;這個(gè)參數(shù)主要用于 processPacket()方法 (后面會(huì)介紹);
三. 捕獲數(shù)據(jù)包
- 上面的第二步結(jié)束后,我們獲得了JpcapCaptor類的對(duì)象 jpcap,這是我們連接的網(wǎng)卡;
- 一旦獲得了JpcapCaptor實(shí)例就可以用來捕獲來自網(wǎng)絡(luò)接口的數(shù)據(jù)包;
- 使用 JpcapCaptor實(shí)例來捕獲數(shù)據(jù)包主要有兩種方法:回調(diào)(callback)以及逐個(gè)捕獲(one-by-one);
1. 逐個(gè)捕獲(one-by-one)
- 使用 JpcapCaptor.getPacket()方法來捕獲數(shù)據(jù)包;這是 JpcapCaptor實(shí)例中四種捕捉包的方法之一;
- 每次調(diào)用 getPacket()只是簡(jiǎn)單返回一個(gè)捕獲的數(shù)據(jù)包,可以循環(huán)使用 getPacket()方法連續(xù)捕獲的數(shù)據(jù)包;
- 受到 to_ms參數(shù)影響, 超時(shí)則停止抓包, 若未抓到包則返回 null;
- 源碼放在 我的Github倉(cāng)庫(kù)
1.1 只捕獲一次
- 部分代碼如下:
/*--------第三步,捕獲數(shù)據(jù)包--------*/
// Packet getPacket() 捕捉并返回一個(gè)數(shù)據(jù)包。這是 JpcapCaptor實(shí)例中四種捕捉包的方法之一;
// 受到 to_ms參數(shù)影響,但一次只抓一個(gè)包并返回,或者超時(shí)返回 null;
// 將抓到的包傳給 Packet類的一個(gè)對(duì)象 packet;
Packet packet = jpcap.getPacket();
System.out.println(packet);
- 我選擇的序號(hào)是4,因?yàn)槲沂窃摼W(wǎng)卡連接了網(wǎng)絡(luò),; 捕獲結(jié)果如下:
注意!上面的捕獲可能會(huì)返回 null,是因?yàn)?to_ms參數(shù)設(shè)置太小,導(dǎo)致未捕獲到數(shù)據(jù)包;
1.2 連續(xù)捕獲
- 代碼如下:
// 捕獲四個(gè)數(shù)據(jù)包;
int i = 0;
while (i < 4) {
Packet packet = jpcap.getPacket();
System.out.println(packet);
i++;// 捕獲四個(gè)數(shù)據(jù)包
}
- 捕獲結(jié)果如下:
好啦!到這一步你就可以成功的捕獲數(shù)據(jù)包了,但是只能逐個(gè)捕獲數(shù)據(jù)包;
那如何進(jìn)行一段時(shí)間的捕獲呢,那就要使用下面的 回調(diào)啦!
2. 回調(diào)(callback)
2.1 實(shí)現(xiàn)的細(xì)節(jié):
(1) 首先定義一個(gè)實(shí)現(xiàn) PacketReceiver接口的類;
- PacketReceiver 接口中只定義了一個(gè) receivePacket()方法;
- Void receivePacket (Packet p):
* 實(shí)現(xiàn)類中的處理接收到的 Packet對(duì)象的方法。每個(gè)Packet對(duì)象代表從熱指定網(wǎng)絡(luò)接口上抓取到的數(shù)據(jù)包;
* 開始接收數(shù)據(jù)包后,當(dāng)接收到數(shù)據(jù)包時(shí)就會(huì)回調(diào)實(shí)現(xiàn) PacketReceiver接口的類的 receivePacket的方法,使之處理接收到的數(shù)據(jù)包;
(2) 然后在主方法中調(diào)用 processPacket() 方法捕獲數(shù)據(jù)包;
- processPacket()或 loopPacket()方法可以指定捕獲的數(shù)據(jù)包的數(shù)量,兩種方法非常相似;
- 通常建議使用 processPacket(),因?yàn)樗С殖瑫r(shí)以及非阻塞模式,而 loopPacket()并不支持,不受 to_ms參數(shù)影響;
- int processPacket(int count, PacketReceiver handler):
* 參數(shù)1: 解釋 一次接收包的個(gè)數(shù)(個(gè)數(shù)到時(shí)到產(chǎn)生回調(diào))捕捉指定數(shù)目的數(shù)據(jù)包,并交由實(shí)現(xiàn)了 PacketReceiver接口的類的實(shí)例(第二個(gè)參數(shù))處理; 如果設(shè)置為 -1,則表示永遠(yuǎn)抓下去—方法不會(huì)返回;
* 參數(shù)2: 解釋 (回調(diào)者)事件臨聽者,必須是實(shí)現(xiàn)了 PacketReceiver接口的一個(gè)實(shí)例對(duì)象,抓到的包將調(diào)用這個(gè)對(duì)象中的 receivePacket(Packet packet)方法處理;
注意! processPacket()方法收到to_ms 參數(shù)的影響,超時(shí)會(huì)結(jié)束該方法;
2.2 捕獲數(shù)據(jù)包
由于使用了新的抓包方法,所以重新貼了一個(gè)全部的實(shí)現(xiàn)代碼,過程和上面是一樣的;
*部分代碼如下,為節(jié)省篇幅,源碼統(tǒng)一放在 我的Github倉(cāng)庫(kù)
import ...
// 類 Receiver實(shí)現(xiàn)了 PacketReceiver接口的 receivePacket()方法;
class Receiver implements PacketReceiver {
@Override
// 重寫 PacketReceiver接口中的 receivePacket()方法;
// 實(shí)現(xiàn)類中的處理接收到的 Packet 對(duì)象的方法,每個(gè) Packet對(duì)象代表從指定網(wǎng)絡(luò)接口上抓取到的數(shù)據(jù)包;
// 抓到的包將調(diào)用這個(gè) PacketReceiver對(duì)象中的 receivePacket(Packet packet)方法處理;
public void receivePacket(Packet packet) {
System.out.println(packet);// 直接將捕獲的包輸出,不做任何處理;
}
}
// 主方法;
public class JpcapProcess {
public static void main(String[] args) {
......
//第二步,監(jiān)聽選中的網(wǎng)卡;
try {
// 參數(shù)一:選擇一個(gè)網(wǎng)卡,調(diào)用 JpcapCaptor.openDevice()連接,返回一個(gè) JpcapCaptor類的對(duì)象 jpcap;
// 參數(shù)二:限制每一次收到一個(gè)數(shù)據(jù)包,只提取該數(shù)據(jù)包中前1512個(gè)字節(jié);
// 參數(shù)三:設(shè)置為非混雜模式,才可以使用下面的捕獲過濾器方法;
// 參數(shù)四:指定超時(shí)的時(shí)間;
JpcapCaptor jpcap = JpcapCaptor.openDevice(devices[index], 1512, true, 6000);
//第三步,捕獲數(shù)據(jù)包;
/* 調(diào)用 processPacket()方法, count = -1對(duì)該方法無影響,主要受 to_ms控制,
改成其他數(shù)值則會(huì)控制每一次捕獲包的數(shù)目;*/
// 換而言之,影響 processPacket()方法的因素有且只有兩個(gè),分別是count 和 to_ms;
// 抓到的包將調(diào)用這個(gè) new Receiver()對(duì)象中的 receivePacket(Packet packet)方法處理;
jpcap.processPacket(5, new Receiver());
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
System.out.println("抓取數(shù)據(jù)包時(shí)出現(xiàn)異常!!");
}
}
}
需要注意的是,如果使用上面代碼未捕獲到數(shù)據(jù)包,則需要檢查網(wǎng)卡是否選擇正確;
或者檢查to_ms參數(shù)是否太小,導(dǎo)致還沒開始捕獲就超時(shí)了;
- 輸出結(jié)果如下:
- 解釋,在源碼中,設(shè)置count = 5, to_ms = 6000,在正常情況下,6000ms 可以捕捉到很多的數(shù)據(jù)包,但控制臺(tái)只輸出了5個(gè),是因?yàn)閏ount = 5 限制了只能捕獲5個(gè);
- 同理,如果設(shè)置 count = -1,理論上可以無限制的捕獲數(shù)據(jù)包,但是因?yàn)橛衪o_ms參數(shù)的限制,并不可以無限制的捕獲數(shù)據(jù)包;
四. 過濾數(shù)據(jù)包
1. 設(shè)置捕獲過濾器:
- 在Jpcap中可以設(shè)置過濾器使得 Jpcap不捕獲不需要的數(shù)據(jù)包;
- 例如:如果僅僅只需捕獲TCP/IPv4數(shù)據(jù)包,就可以設(shè)置過濾器,其方法如下例所示:
// 注意!混雜模式要設(shè)置為false, setFilter()方法才能有效;
JpcapCaptor jpcap = JpcapCaptor.openDevice(devices[index], 65535, false, 20);
// 在捕獲前先設(shè)置過濾;
jpcap.setFilter("ip and tcp", true);
jpcap.processPacket(5, new Receiver());
- 過濾器表達(dá)式 “ip and tcp” 表示 “只保留 IPv4并且 TCP數(shù)據(jù)包,并將其交付給應(yīng)用” ;
- 過濾器的設(shè)置可以減少所需要處理的數(shù)據(jù)包并且提高應(yīng)用的性能;
2. 輸出結(jié)果
- 將setFilter()方法 添加到上面的源碼中后,輸出結(jié)果如下圖:
文章來源:http://www.zghlxwxcb.cn/news/detail-412758.html
- 顯示的就只有協(xié)議字段為6的TCP數(shù)據(jù)包,說明過濾成功;
總結(jié)
這份大作業(yè)需要挺多的時(shí)間去完成的,只能一部分一部分去啃。
這篇博客也只是解決了如何從網(wǎng)卡中捕捉并過濾數(shù)據(jù)包,但還未能對(duì)捕獲到的數(shù)據(jù)包進(jìn)行分析和可視化。
剩下的這些內(nèi)容就等下一篇博客吧!
最后,如果這篇博客對(duì)你有幫助的話,就給我點(diǎn)贊吧!如果有我表述的不清楚或者錯(cuò)誤的地方,歡迎在評(píng)論區(qū)一起討論、批評(píng)指正。拜拜!文章來源地址http://www.zghlxwxcb.cn/news/detail-412758.html
到了這里,關(guān)于基于Java_使用Jpcap進(jìn)行網(wǎng)絡(luò)抓包并分析(6千字保姆級(jí)教程)的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!