学习使用Jpcap抓取数据包过程中的一些记录和问题

1.      Jpcap

       Jpcap是一个基于Java主要用来捕获网络数据包并进行处理的中间件,通过调用外部动态链接库(Windows.dll, Linux .so)的形式弥补了Java不能处理数据链路层的缺陷。

2.      环境搭建

http://jpcap.sourceforge.net/下载最新 Jpcap 打包资源

      

Window         jpcap-x.xx.xx-win32.zip

Linux             jpcap-x.xx.xx.tar.gz

(x.xx.xx为版本号,具体参考官网)

      

以下环境在Window系统上搭建

1)把资源包下 lib/jpcab.dll文件拷贝到当前编译环境的jre/bin目录下。

 

PS:使用 myEclipse作为IDE的同学如果没有设置本地JDK路径会默认在myEclipse安装的同级路径下生成AppData文件夹,以下是我的当前 jre 路径

G:\AppData\Local\Genuitec\Common\binary\com.sun.java.jdk.win32.x86_1.6.0.013\jre

      

2)资源包下 jars/ net.sourceforge.jpcap-x.xx.xx.jar添加到项目的Reference Libraries

或者将路径添加到classPath里。Jars/javadoc_net.sourceforge.jpcap-x.xx.xx.jarJpcapAPI开发文档。

3. 案例

 

以下是Jpcap官方给出的第一个例子

   

import net.sourceforge.jpcap.capture.*;

import net.sourceforge.jpcap.net.*;

 

public classExample1

{

  privatestaticfinal intINFINITE = -1;

  privatestaticfinal intPACKET_COUNT = 10;

 

  //BPF filter for capturing any packet

  privatestaticfinal StringFILTER =  "";

 

  privatePacket Capturem_pcap;

  private Stringm_device;

 

  publicExample1()throws Exception {

    //Step 1: Instantiate Capturing Engine

    m_pcap =newPacketCapture();

 

//Step 2:  Check for devices 

// 此处官方的例子给出的是m_device = m_pcap.findDevice();经过测试,得到两个结果:

// 1)findDevice()方法取到的device的名字额外包括了适配器具体的名字

//   以下是我输出的结果:

//   \Device\NPF_{EB07CCEA-BFDC-4438-B73D-AB507CFDF470}

//   BroadcomNetLink (TM) Gigabit Ethernet Driver

//   红字部分才是 device需要的名字,多出来适配器的名字后,在接下来用open()调用动态链

//   接库的时候会报CaptureDeviceOpenException:Erroropening adapter异常

//    所以我用subString取了前面有效的部分正好是50个字符,具体的PC也许需要具体测试。

// 2)由于我的本机有包括虚拟网卡在内的共5个网卡适配器,findDevice()默认只取了第一个适

//     配器,并不是那个连着外网的适配器,所以抓不到何与外网交互产生的数据包,于是我用

//     PacketCapture.lookupDevices()取得了所有可用的device,然后挨个测试,确定了

//     第4个device就是那个产生多数据包的适配器,同样,这个参数也需要具体测试。

    m_device  = PacketCapture.lookupDevices()[4].substring(0, 50);

 

    //Step 3: Open Device for Capturing(requires root)

    m_pcap.open(m_device,false);

 

    //Step 4: Add a BPF Filter (seetcpdumpdocumentation)

    m_pcap.setFilter(FILTER,true);

 

    //Step 5: Register a Listener for RawPackets

    m_pcap.addRawPacketListener(newRawPacketHandler());

 

// Step 6:  Capture Data (max. PACKET_COUNT packets)

// 这里的参数表示具体指定捕获多少个包,设为-1时将会一直捕获直到报错或程序退出

    m_pcap.capture(PACKET_COUNT);

    

  }

 

  publicstaticvoid main(String[] args) {

    try {

     Example1 example = new Example1();

    } catch(Exceptione) {

     e.printStackTrace();

     System.exit(1);

    }

  }

}

 

 

class RawPacketHandlerimplementsRawPacketListener

{

  privatestaticintm_counter = 0;

 

  publicvoidrawPacketArrived(RawPacket data) {

    m_counter++;

    System.out.println("Receivedpacket (" +m_counter +")");

  }

}


之后我重新写了这个捕获包的监听器为了只抓TCP的包

先把 Step5替换成

m_pcap.addPacketListener(newTcpPacketHandler());

 

接下来改了原来那个RawPacketHandler

class TcpPacketHandlerimplementsPacketListener {

 

    @Override

    publicvoidpacketArrived(Packet packet) {

        try {

            //only handle TCP packets

 

            if(packetinstanceofTCPPacket) {

                TCPPacket tcpPacket = (TCPPacket) packet;

                byte[] data= tcpPacket.getTCPData();

 

                StringsrcHost = tcpPacket.getSourceAddress();

                StringdstHost = tcpPacket.getDestinationAddress();

                StringisoData = new String(data,"ISO-8859-1");

 

                System.out.println(srcHost+" -> " + dstHost +":" + isoData);

            }

        } catch(Exception e) {

            e.printStackTrace();

        }

    }

}


 

在我运行后发现一个TCP包都捕获不到。

于是我用System.out.println(packet.getClass().getName());打印了所有捕获的

包的类型

 

结果如下图:

 

从中发现,捕获到最多的包是EthernetPackage,然后少数的IPPackageARPPackage

 

研究猜测了一种可能,就是网络层的许多包(包括TCP/UDP)在以太网上传输的时候被封装成了以太包。

 

具体得到其中TCPPacket的办法还在寻找,有知道的请指教一下,拜谢。

你可能感兴趣的:(java,抓包,中间件)