本学期学习了《计算机网络》专业课程,老师布置了课程设计大作业,作业要求如下:
在抓包开始前,需要在Java中搭建winpcap开发环境;
- winpcap就是一个更加底层的系统, 通过这个软件可以在window平台下实现直接的网络编程;
- 但是要注意的是winpcap的实现是使用C/C++实现的, 所以我们就需要一个中间件来实现从C到Java的转化;
- jpcap简单来说就是对于winpcap一层封装 作为一个中间件,调用winpcap,提供一个接口,使Java实现对数据链路层的控制;
- 这样现实了平台的无关性;
- 无论在什么操作系统下,我们要发送数据报到网络上,就离不开这样一个东西:网卡 网卡是工作在数据链路层
- 涉及帧的发送与接收、帧的封装与拆封、介质访问控制、数据的编码与解码以及数据缓存的功能等
- 无论什么数据报从网络发送到本机,都是通过网卡再保存到本地的缓冲区上 所以我们在网络编程抓包的时候,首先要确定就是从哪块网卡上抓包
下载安装包
地址:https://www.winpcap.org/
完成之后,安装到Windows的电脑中即可
特别注意:64位的系统要下载64位的对应的DLL;
但是官网上提供的下载是32位系统的!!
我在百度网盘上传了一份64位的:
链接:https://pan.baidu.com/s/19xiD0N2UfuV0C0VhALJqLQ 提取码:ley0
下载到本地之后,将Jpcap.dll放到JDK安装路径下的 /jre/bin 目录下;
使用IDEA新建一个普通的Java项目,导入Jar包
打开项目的项目结构,将刚才下载Jar包添加到项目结构的库中,如下图:
以上内容参考博客 https://blog.csdn.net/wchstrife/article/details/79922073
在进行了开发环境的搭建后,就让我们用一个简单的程序试试是否能显示网卡吧
import jpcap.JpcapCaptor;
import jpcap.NetworkInterface;
public class JpcapDemo {
public static void main(String[] args) {
/*-------第一步,显示网络设备列表-------- */
// 获取网络接口列表,返回你所有的网络设备数组,一般就是网卡;
NetworkInterface[] devices = JpcapCaptor.getDeviceList();
int k = -1;
// 显示所有网络设备的名称和描述信息;
// 要注意的是,显示出来的网络设备在不同网络环境下是不同的,可以在控制台使用 ipconfig /all命令查看;
for (NetworkInterface n : devices) {
k++;
System.out.println("序号 " + k + " " + n.name + " | " + n.description);
System.out.println(“------------------------------------------------”);
}
}
}
如果你也可以像上面代码一样显示出网络设备的信息,那就恭喜你搭建网络环境成功啦!接着进行下一步吧!
要想从网络中捕获数据包,第一件必须要做的事就是获取本机的网络接口列表
获取网络接口的代码就是上面的JpcapDemo代码,大家可以回头看看,为了节省篇幅这里就不贴啦
一旦有了网络接口列表就可以从选定用于捕获数据包的网络接口,可以使用方法JpcapCaptor.openDevice()来打开指定的网络接口,注意此并未开始捕获数据包。
/*--------第二步,选择网卡并打开网卡连接--------*/
// 选择网卡序号;
// 注意!每台设备连接网络的网卡不同,选择正确的网卡才能捕获到数据包;
System.out.println("请输入你想要监听的网卡序号: ");
Scanner sc = new Scanner(System.in);
int index = sc.nextInt();
JpcapCaptor jpcap = null;// 声明一个JpcapCaptor全局实例变量 jpcap;
// 打开网卡连接,此时还未开始捕获数据包;
try {
jpcap = JpcapCaptor.openDevice(devices[index], 1512, true,5000);// 捕获时间为5s
} catch (IOException e) {
e.printStackTrace();
System.out.println("抓取数据包时出现异常!!");
}
静态方法 static JpcapCaptor openDevice (NetworkInterface interface, int snaplen, boolean promisc, int to_ms):
创建一个与指定设备的连接并返回该连接。调用该方法必须指定下列参数:
- interface:要打开连接的设备的实例;
- snaplen:这个是比较容易搞混的一个参数。其实这个参数不是限制只能捕捉多少数据包,而是限制每一次收到一个数据包,只提取该数据包中前多少字节;
- promisc:设置是否混杂模式。处于混杂模式将接收所有数据包,若之后又调用了包过滤函数 setFilter() 将不起任何作用 (后面会介绍);
- to_ms:指定捕获数据包超时的时间;这个参数主要用于 processPacket()方法 (后面会介绍);
/*--------第三步,捕获数据包--------*/
// Packet getPacket() 捕捉并返回一个数据包。这是 JpcapCaptor实例中四种捕捉包的方法之一;
// 受到 to_ms参数影响,但一次只抓一个包并返回,或者超时返回 null;
// 将抓到的包传给 Packet类的一个对象 packet;
Packet packet = jpcap.getPacket();
System.out.println(packet);
注意!上面的捕获可能会返回 null,是因为 to_ms参数设置太小,导致未捕获到数据包;
// 捕获四个数据包;
int i = 0;
while (i < 4) {
Packet packet = jpcap.getPacket();
System.out.println(packet);
i++;// 捕获四个数据包
}
好啦!到这一步你就可以成功的捕获数据包了,但是只能逐个捕获数据包;
那如何进行一段时间的捕获呢,那就要使用下面的 回调啦!
(1) 首先定义一个实现 PacketReceiver接口的类;
- Void receivePacket (Packet p):
* 实现类中的处理接收到的 Packet对象的方法。每个Packet对象代表从热指定网络接口上抓取到的数据包;
* 开始接收数据包后,当接收到数据包时就会回调实现 PacketReceiver接口的类的 receivePacket的方法,使之处理接收到的数据包;
(2) 然后在主方法中调用 processPacket() 方法捕获数据包;
- int processPacket(int count, PacketReceiver handler):
* 参数1: 解释 一次接收包的个数(个数到时到产生回调)捕捉指定数目的数据包,并交由实现了 PacketReceiver接口的类的实例(第二个参数)处理; 如果设置为 -1,则表示永远抓下去—方法不会返回;
* 参数2: 解释 (回调者)事件临听者,必须是实现了 PacketReceiver接口的一个实例对象,抓到的包将调用这个对象中的 receivePacket(Packet packet)方法处理;
注意! processPacket()方法收到to_ms 参数的影响,超时会结束该方法;
由于使用了新的抓包方法,所以重新贴了一个全部的实现代码,过程和上面是一样的;
*部分代码如下,为节省篇幅,源码统一放在 我的Github仓库
import ...
// 类 Receiver实现了 PacketReceiver接口的 receivePacket()方法;
class Receiver implements PacketReceiver {
@Override
// 重写 PacketReceiver接口中的 receivePacket()方法;
// 实现类中的处理接收到的 Packet 对象的方法,每个 Packet对象代表从指定网络接口上抓取到的数据包;
// 抓到的包将调用这个 PacketReceiver对象中的 receivePacket(Packet packet)方法处理;
public void receivePacket(Packet packet) {
System.out.println(packet);// 直接将捕获的包输出,不做任何处理;
}
}
// 主方法;
public class JpcapProcess {
public static void main(String[] args) {
......
//第二步,监听选中的网卡;
try {
// 参数一:选择一个网卡,调用 JpcapCaptor.openDevice()连接,返回一个 JpcapCaptor类的对象 jpcap;
// 参数二:限制每一次收到一个数据包,只提取该数据包中前1512个字节;
// 参数三:设置为非混杂模式,才可以使用下面的捕获过滤器方法;
// 参数四:指定超时的时间;
JpcapCaptor jpcap = JpcapCaptor.openDevice(devices[index], 1512, true, 6000);
//第三步,捕获数据包;
/* 调用 processPacket()方法, count = -1对该方法无影响,主要受 to_ms控制,
改成其他数值则会控制每一次捕获包的数目;*/
// 换而言之,影响 processPacket()方法的因素有且只有两个,分别是count 和 to_ms;
// 抓到的包将调用这个 new Receiver()对象中的 receivePacket(Packet packet)方法处理;
jpcap.processPacket(5, new Receiver());
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
System.out.println("抓取数据包时出现异常!!");
}
}
}
需要注意的是,如果使用上面代码未捕获到数据包,则需要检查网卡是否选择正确;
或者检查to_ms参数是否太小,导致还没开始捕获就超时了;
// 注意!混杂模式要设置为false, setFilter()方法才能有效;
JpcapCaptor jpcap = JpcapCaptor.openDevice(devices[index], 65535, false, 20);
// 在捕获前先设置过滤;
jpcap.setFilter("ip and tcp", true);
jpcap.processPacket(5, new Receiver());
这份大作业需要挺多的时间去完成的,只能一部分一部分去啃。
这篇博客也只是解决了如何从网卡中捕捉并过滤数据包,但还未能对捕获到的数据包进行分析和可视化。
剩下的这些内容就等下一篇博客吧!
最后,如果这篇博客对你有帮助的话,就给我点赞吧!如果有我表述的不清楚或者错误的地方,欢迎在评论区一起讨论、批评指正。拜拜!