我们所使用的依赖包是1.4.r1425-1g版本,但是没找到这块的源码和对应的API文档,所以文档展示采用1.4.r1300。
1.包目录结构说明
如下整理的是1.4.r1300版本,总体差距变化和1.4.r1425-1g不是特别大
包 | 核心功能 |
---|---|
org.jnetpcap | 核心 libpcap 功能可在所有平台上使用。 |
org.jnetpcap.nio | 本机内存和 IO 管理类 |
org.jnetpcap.packet | 数据包解码框架 |
org.jnetpcap.packet.annotate | 头定义的注解接口 |
org.jnetpcap.packet.format | JPacket 和 JHeader 对象的格式化类 |
org.jnetpcap.packet.structure | 描述其结构的数据包、标头、字段、绑定和扫描器原语 |
org.jnetpcap.protocol | 网络协议和头定义 |
org.jnetpcap.protocol.application | 应用程序协议套件 |
org.jnetpcap.protocol.lan | LAN 协议套件 |
org.jnetpcap.protocol.network | 网络协议套件 |
org.jnetpcap.protocol.tcpip | Tcp/Ip 协议套件 |
org.jnetpcap.protocol.voip | IP 语音协议家族 |
org.jnetpcap.protocol.vpn | VPN 协议套件 |
org.jnetpcap.protocol.wan | WAN 协议套件 |
org.jnetpcap.util | 各种支持实用方法 |
org.jnetpcap.util.checksum | 循环冗余校验和算法 |
org.jnetpcap.util.config | 配置使用属性 |
org.jnetpcap.util.resolver | 人工标签解析器的地址 |
org.jnetpcap.winpcap | WinPcap 对 libpcap 的扩展,可在有限的平台集上使用 |
2.Pcap
这个类是与 libpcap 和 winpcap 库实现中的原生 pcap_t 结构对等的Java类。 它提供了Java 与libpcap 库方法的直接映射。
2.1.入门了解
Pcap 类提供了几个静态方法,它们允许发现网络接口,然后打开 openLive、openDead 或 openOffline pcap 捕获会话。在所有 3 种情况下,都会返回 Pcap 对象。该对象由 Java VM 地址空间之外的 C pcap_t 结构支持。 Pcap 对象上的任何非静态操作都使用 java JNI API 转换为相应的 Libpcap C 调用,并提供适当的 pcap_t C 结构来完成调用。
从上述静态方法获取 Pcap 对象后,您必须调用 close() 调用以释放任何 Libpcap 资源和支持的 C 结构。 Pcap 对象确实从其 finalize() 方法中隐式调用了 close() 方法,但这只会在 Pcap 被垃圾收集时发生。当不再需要 Pcap 对象和捕获会话时,记住始终调用 close() 的最佳实践。
如果 Pcap 对象关闭并调用其任何非静态方法,则关闭后将抛出 IllegalStateException。
2.2.获取网卡(网络适配器)
与 libpcap 一样,我们首先要找出并获取网络接口名称,以便我们可以告诉 jnetpcap打开一个或多个以供读取。 所以首先我们查询系统上的接口列表:
这个案例已经在我们搭建环境中进行演示了
Java抓包分析一(基于jnetpcap进行抓包)——抓包环境搭建,获取网卡
Pcap.findAllDevs
/**
* @Description:获取网络适配器,当返回List<PcapIf>为空时,说明未获取到网卡
* @author:hutao
* @mail:hutao_2017@aliyun.com
* @date:2021年9月2日
*/
public static List<PcapIf> getPcapIf() {
StringBuilder errbuf = new StringBuilder();
//定义网卡列表
List<PcapIf> ifs = new ArrayList<PcapIf>();
/* 返回值是一个整数结果代码,就像在 C 计数器部分一样。
* ifs 列表中填充了从 C 函数调用 findAllDevs 返回的相应 C 结构 pcap_if 链表中找到的所有网络设备。
*/
int statusCode = Pcap.findAllDevs(ifs, errbuf);
if(statusCode != Pcap.OK){
System.err.println("获取网卡失败:" + errbuf.toString());
}
return ifs;
}
2.3.抓包处理器Handler
定义一个处理器,需要实现PcapPacketHandler来处理我们的抓包逻辑。
public class CustomPcapHandler<Object> implements PcapPacketHandler<Object>{
@Override
//不做任何处理,仅作数据打印
public void nextPacket(PcapPacket packet, Object user) {
System.out.println(packet);
}
}
2.4.监控指定网卡进行抓包
openLive
给定制定的网卡(网络适配器)进行抓包
/**
* @Description:开始捕获数据包
* @param
* @author:hutao
* @mail:hutao_2017@aliyun.com
* @date:2021年9月2日
*/
public static void capturePcap(PcapIf device) {
//截断此大小的数据包
int snaplen = Pcap.DEFAULT_JPACKET_BUFFER_SIZE;
int promiscous = Pcap.MODE_PROMISCUOUS;
//以毫秒为单位
int timeout = 60 * 1000;
//如果发生错误,它将保存一个错误字符串。 错误打开 Live 将返回 null
StringBuilder errbuf = new StringBuilder();
Pcap pcap = Pcap.openLive(device.getName(),snaplen,promiscous,timeout,errbuf);
if(pcap == null) {
System.err.println("获取数据包失败:" + errbuf.toString());
}
CustomPcapHandler<Object> handler = new CustomPcapHandler<Object>();
// 捕获数据包计数
int cnt = 1;
//我们要发送到处理程序的自定义对象
PrintStream out = System.out;
while(true) {
//每个数据包将被分派到抓包处理器Handler
pcap.loop(cnt, handler, out);
}
//pcap.close();
}
3.完整代码示例
3.1.CustomPcapHandler
import org.jnetpcap.packet.PcapPacket;
import org.jnetpcap.packet.PcapPacketHandler;
import org.jnetpcap.protocol.tcpip.Http;
public class CustomPcapHandler<Object> implements PcapPacketHandler<Object>{
@Override
public void nextPacket(PcapPacket packet, Object user) {
System.out.println(packet);
}
}
3.2.CaptureUtils
import java.io.PrintStream;
import java.util.ArrayList;
import java.util.List;
import org.jnetpcap.Pcap;
import org.jnetpcap.PcapIf;
import com.capture.hutao.packetHandler.CustomPcapHandler;
/**
* @Description:抓包工具类
* @author:hutao
* @mail:hutao_2017@aliyun.com
* @date:2021年9月2日
*/
public class CaptureUtils {
/**
* @Description:获取网络适配器,当返回List<PcapIf>为空时,说明未获取到网卡
* @author:hutao
* @mail:hutao_2017@aliyun.com
* @date:2021年9月2日
*/
public static List<PcapIf> getPcapIf() {
StringBuilder errbuf = new StringBuilder();
//定义网卡列表
List<PcapIf> ifs = new ArrayList<PcapIf>();
/* 返回值是一个整数结果代码,就像在 C 计数器部分一样。
* ifs 列表中填充了从 C 函数调用 findAllDevs 返回的相应 C 结构 pcap_if 链表中找到的所有网络设备。
*/
int statusCode = Pcap.findAllDevs(ifs, errbuf);
if(statusCode != Pcap.OK){
System.err.println("获取网卡失败:" + errbuf.toString());
}
return ifs;
}
/**
* @Description:开始捕获数据包
* @param
* @author:hutao
* @mail:hutao_2017@aliyun.com
* @date:2021年9月2日
*/
public static void capturePcap(PcapIf device) {
//截断此大小的数据包
int snaplen = Pcap.DEFAULT_JPACKET_BUFFER_SIZE;
int promiscous = Pcap.MODE_PROMISCUOUS;
//以毫秒为单位
int timeout = 60 * 1000;
//如果发生错误,它将保存一个错误字符串。 错误打开 Live 将返回 null
StringBuilder errbuf = new StringBuilder();
Pcap pcap = Pcap.openLive(device.getName(),snaplen,promiscous,timeout,errbuf);
if(pcap == null) {
System.err.println("获取数据包失败:" + errbuf.toString());
}
CustomPcapHandler<Object> handler = new CustomPcapHandler<Object>();
// 捕获数据包计数
int cnt = 1;
//我们要发送到处理程序的自定义对象
PrintStream out = System.out;
while(true) {
//每个数据包将被分派到抓包处理器Handler
pcap.loop(cnt, handler, out);
}
//pcap.close();
}
}
3.3.DemoTest
import java.util.List;
import org.jnetpcap.PcapIf;
import com.capture.hutao.utils.CaptureUtils;
public class DemoTest {
public static void main(String[] args) {
List<PcapIf> networkAdapter = CaptureUtils.getPcapIf();
CaptureUtils.capturePcap(networkAdapter.get(0));
}
}