一.
JPCAP
簡介
眾所周知,JAVA語言雖然在TCP/UDP傳輸方面給予了良好的定義,但對于網絡層以下的控制,卻是無能為力的。JPCAP擴展包彌補了這一點。
JPCAP實際上并非一個真正去實現對數據鏈路層的控制,而是一個中間件,JPCAP調用wincap/libpcap,而給JAVA語言提供一個公共的接口,從而實現了平臺無關性。在官方網站上聲明,JPCAP支持FreeBSD 3.x, Linux RedHat 6.1, Fedora Core 4, Solaris, and Microsoft Windows 2000/XP等系統。
二.
JPCAP
機制
?????? JPCAP的整個結構大體上跟wincap/libpcap是很相像的,例如NetworkInterface類對應wincap的typedef struct _ADAPTER??ADAPTER,getDeviceList()對應pcap_findalldevs()等等。 JPCAP有16個類,下面就其中最重要的4個類做說明。
?
1.
NetworkInterface
該類的每一個實例代表一個網絡設備,一般就是網卡。這個類只有一些數據成員,除了繼承自java.lang.Object的基本方法以外,沒有定義其它方法。
?
數據成員
|
NetworkInterfaceAddress[]
|
addresses
???
這個接口的網絡地址。設定為數組應該是考慮到有些設備同時連接多條線路,例如路由器。但我們的PC機的網卡一般只有一條線路,所以我們一般取addresses[0]就夠了。
|
?java.lang.String
|
datalink_description
.
???
數據鏈路層的描述。描述所在的局域網是什么網。例如,以太網(Ethernet)、無線LAN網(wireless LAN)、令牌環網(token ring)等等。
|
?java.lang.String
|
datalink_name
??
該網絡設備所對應數據鏈路層的名稱。具體來說,例如Ethernet10M、100M、1000M等等。
|
?java.lang.String
|
description
??
網卡是XXXX牌子XXXX型號之類的描述。例如我的網卡描述:Realtek RTL8169/8110 Family Gigabit Ethernet NIC
|
?boolean
|
Loopback
???
標志這個設備是否loopback設備。
|
?byte[]
|
mac_address
???
網卡的MAC地址,6個字節。
|
?java.lang.String
|
Name
???
這個設備的名稱。例如我的網卡名稱:\Device\NPF_{3CE5FDA5-E15D-4F87-B217-255BCB351CD5}
|
?
2.
JpcapCaptor
該類提供了一系列靜態方法實現一些基本的功能。該類一個實例代表建立了一個與指定設備的鏈接,可以通過該類的實例來控制設備,例如設定網卡模式、設定過濾關鍵字等等。
?
數據成員
|
?int
|
dropped_packets?
拋棄的包的數目。
|
protected ?int
|
ID
???
這個數據成員在官方文檔中并沒有做任何說明,查看
JPCAP
源代碼可以發現這個
ID
實際上在其
JNI
的
C
代碼部分傳進來的,這類本身并沒有做出定義,所以是供其內部使用的。實際上在對
JpcapCator
實例的使用中也沒有辦法調用此數據成員。
|
protected static?boolean[]
|
instanciatedFlag
??
同樣在官方文檔中沒有做任何說明,估計其為供內部使用。
|
protected static?int
|
MAX_NUMBER_OF_INSTANCE
同樣在官方文檔中沒有做任何說明,估計其為供內部使用。
|
int
|
received_packets
????????
收到的包的數目
|
方法成員
|
static?NetworkInterface[]
|
getDeviceList
()
??????????
返回一個網絡設備列表。
|
static?JpcapCaptor
|
openDevice
(NetworkInterface interface, int?snaplen, boolean?promisc, int?to_ms)
????????
創建一個與指定設備的連接并返回該連接。注意,以上兩個方法都是靜態方法。
????? Interface
:要打開連接的設備的實例;
????? Snaplen
:這個是比較容易搞混的一個參數。其實這個參數不是限制只能捕捉多少數據包,而是限制每一次收到一個數據包,只提取該數據包中前多少字節;
????? Promisc
:設置是否混雜模式。處于混雜模式將接收所有數據包,若之后又調用了包過濾函數
setFilter()
將不起任何作用;
????? To_ms
:這個參數主要用于
processPacket()
方法,指定超時的時間;
|
?void
|
Close
() ??????????關閉調用該方法的設備的連接,相對于openDivece()打開連接。
|
?JpcapSender
|
getJpcapSenderInstance
()
?????????
該返回一個
JpcapSender
實例,
JpcapSender
類是專門用于控制設備的發送數據包的功能的類。
|
?Packet
|
getPacket
()
??????????
捕捉并返回一個數據包。這是
JpcapCaptor
實例中四種捕捉包的方法之一。
|
?int
|
loopPacket
(int?count, PacketReceiver handler)
?????????
捕捉指定數目的數據包,并交由實現了
PacketReceiver
接口的類的實例處理,并返回捕捉到的數據包數目。如果
count
參數設為-
1
,那么無限循環地捕捉數據。
?????
這個方法不受超時的影響。還記得
openDivice()
中的
to_ms
參數么?那個參數對這個方法沒有影響,如果沒有捕捉到指定數目數據包,那么這個方法將一直阻塞等待。
PacketReceiver
中只有一個抽象方法
void receive(Packet p)
。
|
?int
|
processPacket
(int?count, PacketReceiver handler)
??????????
跟
loopPacket
()
功能一樣,唯一的區別是這個方法受超時的影響,超過指定時間自動返回捕捉到數據包的數目。
|
?int
|
dispatchPacket
(int?count, PacketReceiver?handler)
????????
跟
processPacket
()
功能一樣,區別是這個方法可以處于“non-blocking”模式工作,在這種模式下dispatchPacket()可能立即返回,即使沒有捕捉到任何數據包。
|
?void
|
setFilter
(java.lang.String?condition, boolean?optimize)
??????????.
condition
:
設定要提取的包的關鍵字。
??????
Optimize
:這個參數在說明文檔以及源代碼中都沒有說明,只是說這個參數如果為真,那么過濾器將處于優化模式。
|
?void
|
setNonBlockingMode
(boolean?nonblocking)
????
如果值為“
true
”,那么設定為“
non-blocking
”模式。
|
?void
|
breakLoop
()
????
當調用
processPacket()
和
loopPacket()
后,再調用這個方法可以強制讓
processPacket()
和
loopPacket()
停止。
|
?
3.
JpcapSender
該類專門用于控制數據包的發送。
?
方法成員
|
?void
|
close
()
?????????
強制關閉這個連接。
|
static?JpcapSender
|
openRawSocket
()
????
這個方法返回的
JpcapSender
實例發送數據包時將自動填寫數據鏈路層頭部分。
|
?void
|
sendPacket
(Packet packet)
??????????JpcapSender
最重要的功能,發送數據包。需要注意的是,如果調用這個方法的實例是由
JpcapCaptor
的
getJpcapSenderInstance
()
得到的話,需要自己設定數據鏈路層的頭,而如果是由上面的openRawSocket()
得到的話,那么無需也不能設置,數據鏈路層的頭部將由系統自動生成。
|
?
4.
Packet
這個是所有其它數據包類的父類。Jpcap所支持的數據包有:
ARPPacket、DatalinkPacket、EthernetPacket、ICMPPacket、IPPacket、TCPPacket、UDPPacket
?
三.使用JPCAP
實現監聽
?????? 1
.監聽原理
?????? 在詳細說用JPCAP實現網絡監聽實現前,先簡單介紹下監聽的原理。
?????? 局域網監聽利用的是所謂的“ARP欺騙”技術。在以前曾經一段階段,局域網的布局是使用總線式(或集線式)結構,要到達監聽只需要將網卡設定為混雜模式即可,但現在的局域網絡普遍采用的是交換式網絡,所以單純靠混雜模式來達到監聽的方法已經不可行了。所以為了達到監聽的目的,我們需要“欺騙”路由器、“欺騙”交換機,即“ARP欺騙”技術。
?????? 假設本機為A,監聽目標為B。
首先,偽造一個ARP REPLY包,數據鏈路層頭及ARP內容部分的源MAC地址填入A的MAC地址,而源IP部分填入網關IP,目的地址填入B的MAC、IP,然后將這個包發送給B,而B接收到這個偽造的ARP REPLY包后,由于源IP為網關IP,于是在它的ARP緩存表里刷新了一項,將(網關IP,網關MAC)刷新成(網關IP,A的MAC)。而B要訪問外部的網都需要經過網關,這時候這些要經過網關的包就通通流到A的機器上來了。
接著,再偽造一個ARP REPLY包,數據鏈路層頭及ARP內容部分的源MAC地址填入A的MAC地址,而源IP部分填入B的IP,目的地址填入網關MAC、IP,然后將這個包發給網關,網關接收到這個偽造的ARP REPLY包后,由于源IP為B的IP,于是在它的ARP緩存表里刷新了一項,將(B的IP,B的MAC)刷新成(B的IP,A的MAC)。這時候外部傳給B的數據包經過網關時,就通通轉發給A。
這樣還只是攔截了B的數據包而已,B并不能上網——解決方法是將接收到的包,除了目的地址部分稍做修改,其它原封不動的再轉發出去,這樣就達到了監聽的目的——在B不知不覺中瀏覽了B所有的對外數據包。
?
ARP
數據包解析
單元:
Byte
Ethernet
頭部
|
ARP
數據部分
|
6
|
6
|
2
|
2
|
2
|
2
|
2
|
4
|
6
|
4
|
6
|
目標
MAC
地址
|
源地
MAC
地址
|
類型號
0x0800:ip
0x0806:ARP
|
局域網類型
以太網
0x0001
|
網絡協議類型
IP
網絡
0x0800
|
MAC/IP
地址長度,恒為
0x06/04
|
ARP
包類型
REPLY
0x0002
|
ARP
目標
IP
地址
|
ARP
目標
MAC
地址
|
ARP
源
IP
地址
|
ARP
源
MAC
地址
|
?
2
.用JPCAP
實現監聽
?????? 就如上面說的,為了實現監聽,我們必須做四件事:
A.發送ARP包修改B的ARP緩存表;
B.發送ARP包修改路由ARP緩存表;
C.轉發B發過來的數據包;
D.轉發路由發過來的數據包;
?
下面我們給個小小的例子說明怎樣實現。
我們假定運行這個程序的機器A只有一個網卡,只接一個網絡,所在局域網為Ethernet,并且假定已經通過某種方式獲得B和網關的MAC地址(例如ARP解析獲得)。我們修改了B和網關的ARP表,并對他們的包進行了轉發。
public class changeARP{
???????? private NetworkInterface[] devices;?????????????????????????? //
設備列表
???????? private NetworkInterface device;?????????????????????????????? //
要使用的設備
???????? private JpcapCaptor jpcap;??????????????????????????????????????? //
與設備的連接
???????? private JpcapSender sender;?????????????????????????????????????? //
用于發送的實例
???????? private byte[] targetMAC, gateMAC;?????????????????????? //B
的
MAC
地址,網關的
MAC
地址
???????? private byte[] String targetIp, String gateIp;????????????? //B
的
IP
地址,網關的
IP
地址
???????? /**
???????? *
初始化設備
???????? * JpcapCaptor.getDeviceList()
得到設備可能會有兩個,其中一個必定是“
Generic
*dialup adapter
”,
這是
windows
系統的虛擬網卡,并非真正的硬件設備。
*
注意:在這里有一個小小的
BUG
,如果
JpcapCaptor.getDeviceList()
之前有類似
JFrame jf=new
*JFame
()這類的語句會影響得到設備個數,只會得到真正的硬件設備,而不會出現虛擬網卡。
*
虛擬網卡只有
MAC
地址而沒有
IP
地址,而且如果出現虛擬網卡,那么實際網卡的
MAC
將分
*
配給虛擬網卡,也就是說在程序中調用
device.
mac_address
時得到的是
00 00 00 00 00 00
。
???????? */
???????? private NetworkInterface getDevice() throws IOException {
???????? ???????? devices = JpcapCaptor.getDeviceList();???????????????????????????????????????????????? //
獲得設備列表
?????????????????? device = devices[0];??????????????????????????????????????????????????????????????????????????????? //
只有一個設備
?????????????????? jpcap = JpcapCaptor.openDevice(device, 2000, false, 10000);??? ???????? //
打開與設備的連接
?????????????????? jpcap.setFilter(“ip”,true);?????????????????????????????????????????????????????????????????????? //
只監聽
B
的
IP
數據包
?????????????????? sender = captor.getJpcapSenderInstance();
???????? }
???????? /**
???????? *
修改
B
和網關的
ARP
表。因為網關會定時發數據包刷新自己和
B
的緩存表,所以必須每隔一
???????? *
段時間就發一次包重新更改
B
和網關的
ARP
表。
???????? *@
參數
targetMAC ????????? B
的
MAC
地址,可通過
ARP
解析得到;
???????? *@
參數
targetIp ??????????????? B
的
IP
地址;
???????? *@
參數
gateMAC ????????????
網關的
MAC
地址;
???????? *@
參數
gateIp????????????????????
網關的
IP;
???????? */
???????? public changeARP(byte[] targetMAC, String targetIp,byte[] gateMAC, String gateIp)
??????????????????????????? throws UnknownHostException,InterruptedException {
?????????????????? this. targetMAC = ?targetMAC;
?????????????????? this. targetIp = ?targetIp;
?????????????????? this. gateMAC = gateMAC;
?????????????????? this. gateIp = gateIp;
?????????????????? getDevice();
?????????????????? arpTarget = new ARPPacket();???????????????????????????????????????????????????? //
修改
B
的
ARP
表的
ARP
包
?????????????????? arpTarget.hardtype = ARPPacket.HARDTYPE_ETHER;????????? //
選擇以太網類型
(Ethernet)
?????????????????? arpTarget.prototype = ARPPacket.PROTOTYPE_IP;??????????????? //
選擇
IP
網絡協議類型
?????????????????? arpTarget.operation = ARPPacket.ARP_REPLY;???????????????????????? //
選擇
REPLY
類型
?????????????????? arpTarget.hlen = 6;??????????????????????????????????????????????????????????????????????? //MAC
地址長度固定
6
個字節
?????????????????? arpTarget.plen = 4;??????????????????????????????????????????????????????????????????????? //IP
地址長度固定
4
個字節
?????????????????? arpTarget.sender_hardaddr = device.mac_address;?????????????????????? //A
的
MAC
地址
?????????????????? arpTarget.sender_protoaddr = InetAddress.getByName(gateIp).getAddress();?????? //
網關
IP
?????????????????? arpTarget.target_hardaddr = targetMAC;?????????????????????????????????????????????? //B
的
MAC
地址
????&nbs
posted on 2007-02-02 19:46
???MengChuChen 閱讀(727)
評論(0) 編輯 收藏 所屬分類:
JavaBasic