目前java实现解析pcap格式的三方库很多,如jnetpcap、jpcap、pcap4j,但是jnetpcap和jpcap已经很久没有更新了,而且jnetpcap的跨平台表现不是很好,在Linux系统上在很多问题,我这边是获取不到网卡信息(root方式启动)。
综合考虑下来决定采用pcap4j,pcap4j 目前支持DNS、SNMP,以及传输层TCP、UDP,网络层的ARP、ICMP等协议,但是暂不支持Http协议解析,作者在issue中提到2.0版本会添加http支持。
Mac/Linux/UNIX 需要安装libpcap,windows环境需要安装winpcap。
Centos
yum install libpcap-devel
Ubuntu
apt-get install libpcap-dev
Mac
brew install libpcap
Gradle
compile 'org.pcap4j:pcap4j-core:1.+'
compile 'org.pcap4j:pcap4j-packetfactory-static:1.+'
Maven
<dependency>
<groupId>org.pcap4j</groupId>
<artifactId>pcap4j-core</artifactId>
<version>[1.0, 2.0)</version>
</dependency>
<dependency>
<groupId>org.pcap4j</groupId>
<artifactId>pcap4j-packetfactory-static</artifactId>
<version>[1.0, 2.0)</version>
</dependency>
本部分不详细说明各个代码的实现逻辑,具体请查看代码注释吧。
获取抓包设备
可以根据设备名称、设备IP地址进行选择本地的网络设备,具体的代码如下:
/**
* 根据IP获取指定网卡设备
* @param localHost 网卡IP
*
* @return 指定的设备对象
*/
public static PcapNetworkInterface getCaptureNetworkInterface(String localHost) {
List<PcapNetworkInterface> allDevs;
try {
// 获取全部的网卡设备列表,Windows如果获取不到网卡信息,输入:net start npf 启动网卡服务
allDevs = Pcaps.findAllDevs();
for (PcapNetworkInterface networkInterface : allDevs) {
List<PcapAddress> addresses = networkInterface.getAddresses();
for (PcapAddress pcapAddress : addresses) {
// 获取网卡IP地址
String ip = pcapAddress.getAddress().getHostAddress();
if (ip != null && ip.contains(localHost)) {
// 返回指定的设备对象
return networkInterface;
}
}
}
} catch (PcapNativeException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
核心抓包代码
/**
*在线抓包以及保存至本地
*
* @return
* @throws InterruptedException
*/
private boolean captureAndDumpLive() throws InterruptedException {
//将回环地址替换成自己网卡地址( ipconfig 查看)
PcapNetworkInterface nif = PcapNIfManager.getCaptureNetworkInterface("127.0.0.1");
if (nif == null) {
return false;
}
try {
// 抓包
pcapHandle = nif.openLive(SNAPLEN, PromiscuousMode.PROMISCUOUS, TIMEOUT);
// 打开抓包数据写入文件
dumper = pcapHandle.dumpOpen(DUMP_FILE);
// 循环处理 -1 为持续抓包,直至中断退出,可以设定为正整数(抓包个数),
pcapHandle.loop(-1, new CoreCaptureListener());
// 也可以采用如下方式,进行循环抓包,
/*
while (true) {
Packet packet = pcapHandle.getNextPacket();
if (packet == null) {
continue;
} else {
if (condition) {
break;
}
}
}*/
} catch (PcapNativeException e) {
e.printStackTrace();
return false;
} catch (NotOpenException e) {
e.printStackTrace();
return false;
}
return true;
}
抓包处理
class CoreCaptureListener implements PacketListener {
/* (non-Javadoc)
* @see org.pcap4j.core.PacketListener#gotPacket(org.pcap4j.packet.Packet)
*/
@Override
public void gotPacket(Packet packet) {
// 解析DNS 数据信息
if (packet.contains(DnsPacket.class)) {
DnsHeader dnsHeader = packet.get(DnsPacket.class).getHeader();
if (dnsHeader.isResponse()) {
dnsHeader.getAnswers().get(0).getName();
} else {
dnsHeader.getQuestions();
// DNS 记录类型
dnsHeader.getQuestions().get(0).getQType();
}
}
try {
dumper.dump(packet);
} catch (NotOpenException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
只是简单介绍了下pcap4j的基本应用,详细的说明还请去github上查看或者查看在线doc
本文demo下载地址