Jpcap 网络抓包工具

1.jpcap说明与安装

JAVA语言虽然在TCP/UDP传输方面给予了良好的定义,但对于网络层以下的控制,却是无能为力的。JPCAP扩展包弥补了这一点,jPcap是一个可以让java工作在链路层的类库;当然,它底层还是使用了本机API通过Jini调用,在javaAPI中得到数据。JPCAP实际上并非一个真正去实现对数据链路层的控制,而是一个中间件,JPCAP调用wincap/libpcap,而给JAVA语言提供一个公共的接口,从而实现了平台无关性。在官方网站上声明,JPCAP支持FreeBSD 3.x, Linux RedHat 6.1, Fedora Core 4, Solaris, and Microsoft Windows 2000/XP等系统。jPcap下载地址:http://netresearch.ics.uci.edu/kfujii/jpcap/doc/index.html ; 你可以从jpcap网站上直接下载它的桌面应用程序进行测试,可以全面的统计本机的网络数据流量及收发包数据。
Java代码 收藏代码
  1. JpcapisaJavaclasspackagethatallowsJavaapplicationstocaptureand/orsendpacketstothenetwork.
  2. Jpcapisbasedonlibpcap/winpcapandRawSocketAPI.Therefore,JpcapissupposedtoworkonanyOSonwhichlibpcap/winpcaphasbeenimplemented.Currently,JpcaphasbeentestedonFreeBSD3.x,LinuxRedHat6.1,FedoraCore4,Solaris,andMicrosoftWindows2000/XP.
  3. Jpcapsupportsthefollowingtypesofpackets:Ethernet,IPv4,IPv6,ARP/RARP,TCP,UDP,andICMPv4.Othertypesofpacketsarecapturedasrawpackets(i.e.,instancesofthePacketclass)whichcontainsthewholedataofthepackets.ThisallowsJavaapplicationstoanalyzeunsupportedpackettypes.

本项目中使用的是jPcap0.6版本,从其网站上下载Source build后,可以看到其下详细的目录结构,源码,例程及Native lib。

使用jPcap可以编写出功能完备的网络嗅测程序,本节中,我们只是使用其非常简单的一个功能:统计本机每块网卡上收发数据的总量。
特别注意:jpcap运行时依赖winCap的类库,使用前必须在机地安装winCap(http://www.winpcap.org/ )(如果是在liunx上,则请到http://www.tcpdump.org/ 下载)。本节中jPcap版本为0.6,winCap版本为4.0,运行与win32系统上。


2.jPcap小试:显示本机网络接口详情

jPcap中的API非常简单,可查看其在线文档:http://netresearch.ics.uci.edu/kfujii/jpcap/doc/javadoc/index.html 。当然,要灵活的使用,你必须有良好的tcp/ip协议知识基础,对常用的3个关键类,简介如下:
JpcapCaptor类
这个类是jPcap中的核心对象,一个JpcapCaptor对象代表了了系统中的一个网络接口卡;通过对JpcapCaptor对象的调用,实现网络数据包的抓取和发送。它供了一系列静态方法调用如:获取网卡列表,获取某个网卡上的JpcapCaptor对象。

static NetworkInterface[]getDeviceList()
这个静态方法调用,可以返回机器上网络接口卡对象的数组,数组中每一个NetworkInterface元素对象代表一个网络接口;一般使用jPcap所要做的第一步调用就是这个方法。
static JpcapCaptor openDevice(NetworkInterface interface, int snaplen, boolean promisc, int to_ms)
取得在指定网卡上的Jpcapcator对象,Interface:上所返回的某个网卡对象Snaplen:一次性要抓取数据包的最大长度。 Promisc:设置是否混杂模式。处于混杂模式将接收所有数据包,如果设置为混杂模式后调用了包过滤函数setFilter()将不起任何作用; To_ms:这个参数主要用于processPacket()方法,指定超时的时间;
int loopPacket(int count, PacketReceiver handler)
常用的一种模式是,通过getDeviceList()取得所有网络接口,再通过openDevice方法取得每个网络接口上的JpcapCaptor对象,就可通过这个方法抓包了。loopPacket方法中count参数表示要抓的包的数目,如果设备为-1,责表示永远抓下去---方法不会返回;第二个参数必须是实现了PacketReceiver接口的一个对象,抓到的包将调用这个PacketReceiver对象中的receivePacket(Packet packet)方法处理;所以抓包前,我们必须写一个实现了PacketReceiver接口的类。 特别注意的是:这个方法的调用会阻塞等待,如果没有抓到指定count的包、或count设为-1,这个方法都不会返回。所以,聪明的你肯定想到了,如果要抓取机器上多个卡口上的包,这个方法必须放在一个独立的线程中。
void breakLoop()
即上JpcapCaptor对象上阻塞等待的方法强制终止。当调用processPacket()和loopPacket()后,再调用这个方法可以强制让processPacket()和loopPacket()停止。

interface PacketReceiver :
数据包处理器接口定义,要处理收到的数据包,必须编写这个接口的实现类,在JpcapCaptor对象的loopPacket方法中调用.

这个接口中仅有一个方法定义:
Void receivePacket (Packet p)
实现类中处理接收到的Packet对象的方法。每个Packet对象代表从热指定网络接口上抓取到的数据包。

NetworkInterface类
NetworkInterface类该类的每一个实例代表一个网络设备,一般就是网卡。这个类只有一些数据成员,除了继承自java.lang.Object的基本方法以外,没有定义其它方法。(但我还不知它与jdk5.0以上的API中的java.net.InterfaceAddress类是否可以互换)。

NetworkInterfaceAddress[]addresses
这个接口的网络地址。设定为数组应该是考虑到有些设备同时连接多条线路,例如路由器。但我们的PC机的网卡一般只有一条线路,所以我们一般取addresses[0]就够了。
java.lang.String datalink_description.
数据链路层的描述。描述所在的局域网是什么网。例如,以太网(Ethernet)、无线LAN网(wireless LAN)、令牌环网(token ring)等等。
java.lang.String datalink_name 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}
jPcap的API使用很简单,如下代码示例:显示机器上的所有网络接口DispalyNetInterface.java:

Java代码 收藏代码
  1. importjpcap.JpcapCaptor;
  2. importjpcap.NetworkInterface;
  3. importjpcap.PacketReceiver;
  4. importjpcap.packet.Packet;
  5. /**
  6. *使用jpcap显示网络接口数据.
  7. */
  8. publicclassDispalyNetInterface{
  9. publicstaticvoidmain(Stringargs[]){
  10. try{
  11. //获取本机上的网络接口对象数组
  12. finalNetworkInterface[]devices=JpcapCaptor.getDeviceList();
  13. for(inti=0;i<devices.length;i++){
  14. NetworkInterfacenc=devices[i];
  15. //一块卡上可能有多个地址:
  16. Stringaddress="";
  17. for(intt=0;t<nc.addresses.length;t++){
  18. address+="|addresses["+t+"]:"+nc.addresses[t].address.toString();
  19. }
  20. //打印说明:
  21. System.out.println("第"+i+"个接口:"+"|name:"+nc.name
  22. +"|loopback:"+nc.loopback+"\r\naddress:"+address);
  23. }
  24. }catch(Exceptionef){
  25. ef.printStackTrace();
  26. System.out.println("显示网络接口数据失败:"+ef);
  27. }
  28. }
  29. }




不幸的是,这段代码运行时会报如下错误:
Java代码 收藏代码
  1. Exceptioninthread"main"java.lang.UnsatisfiedLinkError:nojpcapinjava.library.path
  2. atjava.lang.ClassLoader.loadLibrary(ClassLoader.java:1682)atjava.lang.Runtime.loadLibrary0(Runtime.java:823)atjava.lang.System.loadLibrary(System.java:1030)atjpcap.JpcapCaptor.<clinit>(JpcapCaptor.java:250)atcn.netjava.cewolf.DispalyNetInterface.main(DispalyNetInterface.java:19)

还记得我们介绍jPcap: “它底层还是使用了本机API通过Jini调用,在javaAPI中得到数据”,这是因为当前cp中少了jpcap要调用的本地dll库。将jpacp下载后lib下面的jpcap.dll复制到当前项目目录下,如果你仅得制了jpcap.dll,操作系统没有安装wincap(http://www.winpcap.org/install/default.htm ),则会看到如下错误提示:
Java代码 收藏代码
  1. Exceptioninthread"main"java.lang.UnsatisfiedLinkError:E:\workspace\trafficManager\jpcap.dll:Can'tfinddependentlibraries
  2. atjava.lang.ClassLoader$NativeLibrary.load(NativeMethod)atjava.lang.ClassLoader.loadLibrary0(ClassLoader.java:1751)atjava.lang.ClassLoader.loadLibrary(ClassLoader.java:1676)atjava.lang.Runtime.loadLibrary0(Runtime.java:823)atjava.lang.System.loadLibrary(System.java:1030)atjpcap.JpcapCaptor.<clinit>(JpcapCaptor.java:250)atcn.netjava.cewolf.DispalyNetInterface.main(DispalyNetInterface.java:17)

配置完好后,再次运行,输出结果正常:
第0个接口:|name: \Device\NPF_GenericDialupAdapter|loopback: false
address: 第1个接口:|name: \Device\NPF_{2A5FD532-45A3-4A2B-9B68-F34C14E4FD2C}|loopback: falseaddress: |addresses[0]: /220.192.159.105第2个接口:|name: \Device\NPF_{14303C1A-4DB3-4BC9-979E-34063E070CBB}|loopback: falseaddress: |addresses[0]: /192.168.1.44
在我的机器上,开着一块局网网卡和一块无线网卡,都显示出来了;上面的”第0个接口”就是指本机的127.0.0.1的回环地址。但不知为什么,loopback也会是false?

要注意两点:一个是jpcap.dll要在路径中;另外,在统计流量时,本机回环地址不需要统计,一般是第0个接口。接下来我们看抓取网卡上的数据包是多么简单:

抓包前,首先要编写实现了PacketReceiver接口的类,即数据包处理器,由与抓包时,对应某个网络接口的JpcapCaptor对象会阻塞,所以我们将每个网卡上得到的对应的JpcapCaptor对象放到一个独立线程中运行;TestPacketReceiver是个数据包解析器,本例中我们只是简单打印出收到的数据包类型及关键参数,阅读如下代码建议参照jPcap的在线文档(http://netresearch.ics.uci.edu/kfujii/jpcap/doc/javadoc/index.html )
TestPacketReceiver.java代码如下:

Java代码 收藏代码
  1. importjpcap.JpcapCaptor;
  2. importjpcap.NetworkInterface;
  3. importjpcap.PacketReceiver;
  4. importjpcap.packet.*;
  5. /**
  6. *使用jpcap显示网络上的各种数据包
  7. *@authorwww.NetJava.cn
  8. */
  9. publicclassDispalyNetPacket{
  10. //程序启动主方法
  11. publicstaticvoidmain(Stringargs[]){
  12. try{
  13. //获取本机上的网络接口对象数组
  14. finalNetworkInterface[]devices=JpcapCaptor.getDeviceList();
  15. for(inti=0;i<devices.length;i++){
  16. NetworkInterfacenc=devices[i];
  17. //创建某个卡口上的抓取对象,最大为2000个
  18. JpcapCaptorjpcap=JpcapCaptor.openDevice(nc,2000,true,20);
  19. startCapThread(jpcap);
  20. System.out.println("开始抓取第"+i+"个卡口上的数据");
  21. }
  22. }catch(Exceptionef){
  23. ef.printStackTrace();
  24. System.out.println("启动失败:"+ef);
  25. }
  26. }
  27. //将每个Captor放到独立线程中运行
  28. publicstaticvoidstartCapThread(finalJpcapCaptorjpcap){
  29. JpcapCaptorjp=jpcap;
  30. java.lang.Runnablernner=newRunnable(){
  31. publicvoidrun(){
  32. //使用接包处理器循环抓包
  33. jpcap.loopPacket(-1,newTestPacketReceiver());
  34. }
  35. };
  36. newThread(rnner).start();//启动抓包线程
  37. }
  38. }
  39. /**
  40. *抓包监听器,实现PacketReceiver中的方法:打印出数据包说明
  41. *@authorwww.NetJava.cn
  42. */
  43. classTestPacketReceiverimplementsPacketReceiver{
  44. /**
  45. *实现的接包方法:
  46. */
  47. publicvoidreceivePacket(Packetpacket){
  48. //Tcp包,在javaSocket中只能得到负载数据
  49. if(packetinstanceofjpcap.packet.TCPPacket){
  50. TCPPacketp=(TCPPacket)packet;
  51. Strings="TCPPacket:|dst_ip"+p.dst_ip+":"+p.dst_port
  52. +"|src_ip"+p.src_ip+":"+p.src_port
  53. +"|len:"+p.len;
  54. System.out.println(s);
  55. }
  56. //UDP包,开着QQ,你就会看到:它是tcp+udp
  57. elseif(packetinstanceofjpcap.packet.UDPPacket){
  58. UDPPacketp=(UDPPacket)packet;
  59. Strings="UDPPacket:|dst_ip"+p.dst_ip+":"+p.dst_port
  60. +"|src_ip"+p.src_ip+":"+p.src_port
  61. +"|len:"+p.len;
  62. System.out.println(s);
  63. }
  64. //如果你要在程序中构造一个ping报文,就要构建ICMPPacket包
  65. elseif(packetinstanceofjpcap.packet.ICMPPacket){
  66. ICMPPacketp=(ICMPPacket)packet;
  67. //ICMP包的路由链
  68. Stringrouter_ip="";
  69. for(inti=0;i<p.router_ip.length;i++){
  70. router_ip+=""+p.router_ip[i].getHostAddress();
  71. }
  72. Strings="@@@ICMPPacket:|router_ip"+router_ip
  73. +"|redir_ip:"+p.redir_ip
  74. +"|mtu:"+p.mtu
  75. +"|length:"+p.len;
  76. System.out.println(s);
  77. }
  78. //是否地址转换协议请求包
  79. elseif(packetinstanceofjpcap.packet.ARPPacket){
  80. ARPPacketp=(ARPPacket)packet;
  81. //Returnsthehardwareaddress(MACaddress)ofthesender
  82. Objectsaa=p.getSenderHardwareAddress();
  83. Objecttaa=p.getTargetHardwareAddress();
  84. Strings="***ARPPacket:|SenderHardwareAddress"+saa
  85. +"|TargetHardwareAddress"+taa
  86. +"|len:"+p.len;
  87. System.out.println(s);
  88. }
  89. //取得链路层数据头:如果你想局网抓包或伪造数据包,嘿嘿
  90. DatalinkPacketdatalink=packet.datalink;
  91. //如果是以太网包
  92. if(datalinkinstanceofjpcap.packet.EthernetPacket){
  93. EthernetPacketep=(EthernetPacket)datalink;
  94. Strings="datalinklayerpacket:"
  95. +"|DestinationAddress:"+ep.getDestinationAddress()
  96. +"|SourceAddress:"+ep.getSourceAddress();
  97. System.out.println(s);
  98. }
  99. }
  100. }




运行这段程序,你机器从网络收所有收发到的数据,就都可以展现在你眼前了!,在我的机器上,摘抄一段输出如下:
Java代码 收藏代码
  1. datalinklayerpacket:|DestinationAddress:01:00:5e:00:00:01|SourceAddress:00:19:e0:f0:ee:55
  2. datalinklayerpacket:|DestinationAddress:01:00:5e:26:4c:da|SourceAddress:00:e0:81:03:7c:01TCPPacket:|dst_ip/128.195.10.200:80|src_ip/192.168.1.44:1083|len:62datalinklayerpacket:|DestinationAddress:00:19:e0:f0:ee:55|SourceAddress:00:02:8a:96:d1:ab***ARPPacket:|SenderHardwareAddress00:19:e0:f0:ee:55|TargetHardwareAddress00:00:00:00:00:00|len:60datalinklayerpacket:|DestinationAddress:ff:ff:ff:ff:ff:ff|SourceAddress:00:19:e0:f0:ee:55***ARPPacket:|SenderHardwareAddress00:02:8a:96:d1:ab|TargetHardwareAddress00:19:e0:f0:ee:55|len:42datalinklayerpacket:|DestinationAddress:00:19:e0:f0:ee:55|SourceAddress:00:02:8a:96:d1:abTCPPacket:|dst_ip/192.168.1.44:1083|src_ip/128.195.10.200:80|len:62datalinklayerpacket:|DestinationAddress:00:02:8a:96:d1:ab|SourceAddress:00:19:e0:f0:ee:55

注意:你可能认为要抓取的数据包应分为发送出去的和接收到的;但对jPcap而言,数据包是从网卡上抓取到的一个packet对象,packet没有收发的概念;如果你要确定这个packet的方向,则可根据其中的属性数据值,如源地址、目标地址确认。如果想深入的研究网络协议就请继续钻研吧,我们的任务可仅仅只是统计网络流量,demo了这么多,赶快实现我们的数据统计模块。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值