我是靠谱客的博主 文静墨镜,最近开发中收集的这篇文章主要介绍基于Java_利用Jpcap抓包并分析(非常详细保姆级教程)二前言一、Jpcap类综述二、逐层分析数据包 三、回调抓包并分析四、逐个捕获并分析(线程实现)总结,觉得挺不错的,现在分享给大家,希望可以做个参考。
概述
目录
前言
一、Jpcap类综述
二、逐层分析数据包
1. 数据链路层
1.1 方法分析
1.2 代码实现
2. 网络层
2.1 方法分析
2.2 代码实现
3. 传输层
3.1 方法分析
3.2 代码实现
三、回调抓包并分析
1. 回顾: 回调抓包
2. 代码实现
四、逐个捕获并分析(线程实现)
1. 分析数据包类
2. 抓包线程类
3. 测试类
总结
前言
本学期学习了《计算机网络》专业课程,老师布置了课程设计大作业,作业要求如下:
- 使用 JPCAP或 wireshark等抓包,可以使用JAVA、PYTHON或C++写代码对数据进行分析最后可视化显示
本文只实现了使用 Java语言的Jpcap接口 在 IDEA环境下抓取数据包并分析的功能,并未实现可视化功能。
- 之前博主发布了 “利用Jpcap接口 在 IDEA环境下抓取数据包” 的博客,本文是对该博文的续章,如果有些朋友在观看本文时,对其中一些内容不太理解,可以去上一篇博文看看,链接如下:
- 基于Java--使用jpcap接口抓包(非常详细)
回顾上一篇博客:利用 Jpcap接口解决了如何从指定网卡中捕捉并过滤数据包,但还未能对捕获到的数据包进行分析和统计,现在我们来解决分析和统计数据包的问题。
一、Jpcap类综述
- 我们在成功抓取到一个数据包 packet后,只是得到了一个很单纯的数据包,packet它的内在(例如它是什么类型的、长度、是否分片,等等)我们还看不见,要使用 Jpcap所提供的一些类和方法,一层一层地剖析 packet,最终得到我们想要的数据。所以首先我们要学习Jpcap 提供的一些重要的分析数据包的类和方法,如下:
Packet | 这个类是所有被捕获的数据包的基类,继承了 java.lang.Object |
DatalinkPaeket | 这个抽象类描述了数据链路层的包,它继承了 java.lang.Object |
EthemetPacket | 这个类描述了以太帧包,继承了 DatalinkPacket类 |
IPPacket | 这个类描述了 IP包,继承了 Packet类,支持 IPv4和 IPv6 |
IP Address | 继承了 java. lang. Object,这个类描述了 IPv4和 IPv6地址,其中也包含了将 IP地址转换为域名的方法 |
ARPPacket | 这个类描述了 ARP/RARP包,继承了 Packet类 |
TCPPacket | 这个类描述了 TCP包,继承了 IPPacket类 |
UDPPacket | 这个类描述了 UDP包,继承了 IPPacket类 |
ICMPPacket | 这个类描述了 ICMP包,继承了 IPPacket类 |
- 由于对上面类中的方法逐个讲解需要篇幅过长,我将Jpcap中文API文档上传到GitHub上了,需要的同学可以自取,该文档来源网络,侵删致歉。
- Jpcap中文使用文档_GitHub
- 接下来将会结合代码讲解Jpcap类的使用。
二、逐层分析数据包
- 在传输过程前,每一个数据包都会被层层封装,最后以比特流的形式进行传输,在此我们将结合代码分析数据包封装最重要的3层结构,分别是数据链路层、网络层和传输层,每一层都对应着Jpcap不同的类和方法。
- Packet类所有被捕获的数据包的基类,提供了分析数据包一些基本属性的方法,如下图:
1. 数据链路层
1.1 方法分析
- 数据包在数据链路层被封装成帧,每一个帧都是由帧头、帧尾和数据载荷部分构成。 DatalinkPacket类和 EthemetPacket类提供了方法分析数据包的以太帧头部,如下图:
1.2 代码实现
- 运行以下代码可以打印出每个数据包的帧头部所包含的信息,可以根据帧头部的帧类型判断该帧封装了什么类型的数据报,大家可以试试。
/* 数链层,显示数据包的帧头部,每一个数据包都有,都要解析 */
// EthernetPacket类继承 DataPacket类;将 DataPacket类向下转型成EthernetPacket类;
EthernetPacket dataLink = (EthernetPacket) packet.datalink;// DatalinkPacket datalink: 数据链路层报头/以太帧报头;
System.out.println("以太帧首部描述 : " + dataLink.toString());// 描述以太帧头部的字符串
System.out.println("源mac地址 : " + dataLink.getSourceAddress());// 源mac地址
System.out.println("目的mac地址 : " + dataLink.getDestinationAddress());// 目的mac地址
System.out.println("帧类型 : " + dataLink.frametype);// 帧类型
2. 网络层
- 数据包在网络层有两种类型,分别是IP数据报文和ARP数据报文,IPPacket类和 ARPPacket类提供了分析网络层数据包首部的方法,它们都继承了 Packet类。
2.1 方法分析
2.1.1 IPPacket类
2.1.2 ARPPacket类
2.2 代码实现
- 在 IPPacket类和 ARPPacket类帮助下,我们很容易就可以分析网络层报文的首部内容,但是需要注意的是,数据包是被层层封装的,那我们如何知道一个数据包是 IP数据包还是 ARP数据包呢?
- 这时需要使用 getClass()方法,返回抓取到的数据包的类对象,然后使用 equals()方法进行比较,代码如下:
if (packet.getClass().equals(IPPacket.class)) {
// IP数据包, IPPacket类继承 Packet类,包括 IPV4和 IPV6;
IPPacket ipPacket = (IPPacket) packet;// 将 packet类转成 IPPacket类;
System.out.println("IP报文首部 : " + ipPacket.toString());
System.out.println("版本version :" + ipPacket.version);
System.out.println("时间戳sec(秒) : " + ipPacket.sec);
System.out.println("时间戳usec(毫秒) : " + ipPacket.usec);
System.out.println("源IP : " + ipPacket.src_ip.getHostAddress());
System.out.println("目的IP : " + ipPacket.dst_ip.getHostAddress());
System.out.println("协议protocol : " + ipPacket.protocol);
System.out.println("优先权priority:" + ipPacket.priority);
System.out.println("生存时间hop:" + ipPacket.hop_limit);
System.out.println("标志位RF:保留位必须为false: " + ipPacket.rsv_frag);
System.out.println("标志位DF:是否允许分片: " + ipPacket.dont_frag);
System.out.println("标志位MF:后面是否还有分片: " + ipPacket.more_frag);
System.out.println("片偏移offset:" + ipPacket.offset);
// 抓到的flowable 流标签的包,是ipv6数据包;
System.out.println("标识ident:" + ipPacket.ident);
} else if (packet.getClass().equals(ARPPacket.class)) {
// ARP数据包,ARPPacket类继承 Packet类;
ARPPacket arpPacket = (ARPPacket) packet;// 将 packet类转成 ARPPacket类;
System.out.println("硬件类型hardtop : " + arpPacket.hardtype);
System.out.println("协议类型prototype : " + arpPacket.prototype);
System.out.println("操作字段operation : " + arpPacket.operation);
System.out.println("IP首部 : " + arpPacket.toString());// String toString: 返回描述此数据包的字符串;
System.out.println("发送方硬件地址 : " + arpPacket.getSenderHardwareAddress());
System.out.println("接收方硬件地址 : " + arpPacket.getTargetHardwareAddress());
System.out.println("发送方IP地址 : " + arpPacket.getSenderProtocolAddress());
System.out.println("接收方IP地址 : " + arpPacket.getTargetProtocolAddress());
}
- 代码运行后将会打印出数据包网络层的首部内容。
3. 传输层
- 数据报文在传输层有三种类型,分别是TCP数据报文、UDP数据报文和 ICMP数据报文,TCPPacket类 、UDPPacket类 和 ICMPPacket类提供了分析传输层数据报文首部的方法,它们都继承了 IPPacket类。
3.1 方法分析
- 由于这三个类的方法篇幅稍长,我就不贴在此处了,有兴趣的同学可以自己去阅读Jpcap中文API文档,文件我已经放在GitHub仓库了。
- Jpcap中文使用文档_GitHub
3.2 代码实现
- TCP数据报文、UDP数据报文和 ICMP数据报文在网络层都被封装成了 IP数据报,因此我们需要使用上述的 getClass() 和 equals() 方法对它们判断,然后才能正确分析捕获到的数据报文。代码如下:
/* 传输层,显示数据包的 ICMP/ TCP/ UDP 首部 */
if (packet.getClass().equals(TCPPacket.class)) {
// TCP数据报,TCPPacket类继承 IPPacket类;
TCPPacket tcpPacket = (TCPPacket) packet;// 将 TCPPacket类转成 IPPacket类;
System.out.println("TCP报文首部:" + tcpPacket.toString());
System.out.println("标志位DF:是否允许分片: " + tcpPacket.dont_frag);
System.out.println("标志位MF:后面是否还有分片: " + tcpPacket.more_frag);
System.out.println("片偏移offset:" + tcpPacket.offset);
System.out.println("标识ident:" + tcpPacket.ident);
System.out.println("TCP报文");
System.out.println("源端口src_port:" + tcpPacket.src_port);
System.out.println("目的端口dst_port:" + tcpPacket.dst_port);
System.out.println("seq序号:" + tcpPacket.sequence);
System.out.println("窗口大小window:" + tcpPacket.window);
System.out.println("ACK标志:" + tcpPacket.ack);// boolean ack :ACK标志
System.out.println("ack:" + tcpPacket.ack_num);// long ack_num :确认号
} else if (packet.getClass().equals(UDPPacket.class)) {
// UDP数据报,UDPPacket类继承 IPPacket类;
UDPPacket udpPacket = (UDPPacket) packet;
System.out.println("UDP报文首部:" + udpPacket.toString());
System.out.println("标志位DF:是否允许分片: " + udpPacket.dont_frag);
System.out.println("标志位MF:后面是否还有分片: " + udpPacket.more_frag);
System.out.println("片偏移offset:" + udpPacket.offset);
System.out.println("标识ident:" + udpPacket.ident);
System.out.println("UDP报文");
System.out.println("源端口src_port:" + udpPacket.src_port);
System.out.println("目的端口dst_port:" + udpPacket.dst_port);
} else if (packet.getClass().equals(ICMPPacket.class)) {
// ICMP数据报,ICMPPacket类继承 IPPacket类;
ICMPPacket icmpPacket = (ICMPPacket) packet;
System.out.println("ICMP报文首部:" + icmpPacket.toString());// 只包含报文类型和代码;
System.out.println("标志位DF:是否允许分片: " + icmpPacket.dont_frag);
System.out.println("标志位MF:后面是否还有分片: " + icmpPacket.more_frag);
System.out.println("片偏移offset:" + icmpPacket.offset);
System.out.println("标识ident:" + icmpPacket.ident);
System.out.println("ICMP报文类型type:" + icmpPacket.type);
System.out.println("ICMP报文代码code:" + icmpPacket.code);
}
- 到这里,我们对数据包逐层的报文首部的分析就结束了。接下来让我们把分析的代码放进程序中,实现数据包的分析。
三、回调抓包并分析
1. 回顾: 回调抓包
- 在上一篇博文中讲解了利用 processPacket()方法和 loopPacket()方法可以进行抓包,并将抓取到的数据包传给实现了 PacketReceiver接口的 receivePacket()方法进行分析。我们回忆一下抓包的代码,如下:
import jpcap.JpcapCaptor;
import jpcap.NetworkInterface;
import jpcap.PacketReceiver;
import jpcap.packet.Packet;
import java.io.IOException;
import java.util.Scanner;
// 类 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);// 直接将捕获的包输出,不做任何处
System.out.println("---------------------------------------");
}
}
public class JpcapProcess {
public static void main(String[] args) {
// 第一步,获得网卡设备列表;
NetworkInterface[] devices = JpcapCaptor.getDeviceList();
if (devices.length == 0) {
System.out.println("无网卡信息!");
return;
}
// 将本机上所有网卡名称及其网卡描述全部显示出来;
// 这些信息可以在 wireshark中的网络接口处看到,是一一对应的,或者在cmd 用ipconfig /all 可以全部显示;
int k = -1;// 网络设备序号
for (NetworkInterface n : devices) {
k++;
// NetworkInterface 类中的 name和 description方法可以显示设备的名称和描述信息;
System.out.println("序号" + k + " " + n.name + " | " + n.description);
}
System.out.println("-------------------------------------------");
Scanner sc = new Scanner(System.in);
System.out.println("请选择您要监听的网卡序号:");
int index = sc.nextInt();
//第二步,监听选中的网卡;
try {
// 参数一:选择一个网卡,调用 JpcapCaptor.openDevice()连接,返回一个 JpcapCaptor类的对象 jpcap;
// 参数二:限制每一次收到一个数据包,只提取该数据包中前1512个字节;
// 参数三:设置为非混杂模式,才可以使用下面的捕获过滤器方法;
// 参数四:指定超时的时间;
JpcapCaptor jpcap = JpcapCaptor.openDevice(devices[index], 2000, false, 10000);
//第三步,捕获数据包;
// 调用 processPacket()方法, count = -1对该方法无影响,主要受 to_ms控制,改成其他数值则会控制每一次捕获包的数目;
// 换而言之,影响 processPacket()方法的因素有且只有两个,分别是count 和 to_ms;
// 抓到的包将调用这个 new Receiver()对象中的 receivePacket(Packet packet)方法处理;
jpcap.setFilter("arp", true);
jpcap.processPacket(4, new Receiver());
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
System.out.println("抓取数据包时出现异常!!");
}
}
}
- 回忆结束,在上面的代码中还未实现对抓取到的数据包进行分析。接下来我们将重写 receivePacket()方法,在其代码块中实现对数据包的分析和统计。
2. 代码实现
- 在分析数据包时,我们定义各种数据包的count 变量,用来统计每种数据包出现的次数;定义TCP和UDP数据报文的 len 变量,用来统计这两种数据包的总长度。
- 由于篇幅过长,这里只贴上了部分代码,源码上传到了源码获取_GitHub中,需要源码的朋友可以自取。
// 类 Receiver实现了 PacketReceiver接口的 receivePacket()方法;
class Receiver implements PacketReceiver {
private static int packetCount = 0;// count 用来统计各种是数据报出现次数;
private static int packetPacketCount = 0;
private static int ipPacketCount = 0;
private static int tcpPacketCount = 0;
private static int udpPacketCount = 0;
private static int icmpPacketCount = 0;
private static int arpPacketCount = 0;
private static int elsePacketCount = 0;
private static int tcpPacketLength = 0;// length 用来统计TCP、UDP报文长度;
private static int udpPacketLength = 0;
@Override
public void receivePacket(Packet packet) {
packetCount++;
// System.out.println(packet);// 直接将捕获的包输出,不做任何处理;
/* 数链层,显示数据包的帧头部,每一个数据包都有,都要解析 */
// EthernetPacket类继承 DataPacket类;
EthernetPacket dataLink = (EthernetPacket) packet.datalink;// DatalinkPacket datalink: 数据链路层报头/以太帧报头;
System.out.println("以太帧首部 : " + dataLink.toString());// 描述以太帧的字符串
System.out.println("源mac地址 : " + dataLink.getSourceAddress());// 源mac地址
System.out.println("目的mac地址 : " + dataLink.getDestinationAddress());// 目的mac地址
System.out.println("帧类型 : " + dataLink.frametype);// 帧类型
......
}
四、逐个捕获并分析(线程实现)
- 我们上面利用回调方法可以方便地捕获并分析数据包,但是却很难利用线程实现(也可能是受限于博主的水平不够),下面我们将实现利用 getPacket() 方法在线程中实现逐个捕获多个数据包。
1. 分析数据包类
- 创建一个 AnalyzePacket类用来分析和统计捕获到的数据包。代码内容同上面分析的代码,为了节省篇幅,就不贴出来了。源码上传到了GitHub上,需要自取。
2. 抓包线程类
- 创建一个实现了 Runnable接口的抓包线程类,用来捕获数据包。
- 代码如下:
package Jpcap_Test;
import jpcap.JpcapCaptor;
import jpcap.packet.*;
// 线程任务类,用来捕获数据并分析数据包;
class CaptureThread implements Runnable {
private JpcapCaptor jpcap;
public CaptureThread(JpcapCaptor jpcap) {
this.jpcap = jpcap;
}
boolean run = true;// 用来控制是否抓包;
@Override
public void run() {
while (run) {
// 抓包并分析
try {
printThreadInfo();
// 开始抓包
Packet packet = jpcap.getPacket();
// 创建分析数据包对象 ap,分析数据包
AnalyzePacket ap = new AnalyzePacket(packet);
ap.analyzePacket();
// 抓包线程休眠1秒;
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
private static void printThreadInfo() {
System.out.println("当前运行的线程名为: " + Thread.currentThread().getName());
}
}
3. 测试类
- 创建一个测试类,在测试类中我们将启动指定的网卡接口和抓包线程。
- 代码如下:
package Jpcap_Test;
import jpcap.JpcapCaptor;
import jpcap.NetworkInterface;
import java.io.IOException;
// 测试类
public class JpcapGetPacketThread {
public static void main(String[] args) {
NetworkInterface[] devices = JpcapCaptor.getDeviceList();
int k = -1;
for (NetworkInterface n : devices) {
k++;
System.out.println("序号" + k + " " + n.name + " | " + n.description);
}
System.out.println("--------------------------------------------------------");
// 启动一个网卡;
JpcapCaptor jpcap = null;
try {
// 注意! getPacket()方法不受to_ms 参数的影响;此处网卡的选择因不同电脑而异;
jpcap = JpcapCaptor.openDevice(devices[7], 4800, true, 200);
} catch (IOException e) {
e.printStackTrace();
System.out.println("抓取数据包时出现异常!!");
}
// 创建抓包任务 c1;
CaptureThread c1 = new CaptureThread(jpcap);
// 创建抓抓包线程 t1;
Thread t1 = new Thread(c1);
// 启动 t1线程,开始抓包并分析;
t1.start();
// 主线程休眠5秒,此处控制抓包时间;
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
// 停止抓包,将控制抓包任务的变量设为false;
c1.run = false;
}
}
- 好啦!只要一步一步实现上面的代码,便可以实现在线程中抓包并分析了,至于为什么要在这里引出线程,是因为在最后一步的可视化中可能需要使用到多线程了。
总结
- 经过了一个星期的不断尝试和摸索,思考和总结,小白博主终于搞定了对捕获的数据包分析并统计的要求了。可是老师的大作业要求远远没有这么简单。。。
- 呜呜~~有点后悔当初选择了java实现这个大作业,但是既然选择了,那就要全力以赴地完成呀!
- 剩下的内容就是将统计好的数据可视化了,博主暂时还没有什么好的想法,如果有好点子的朋友可以在评论区和博主一起学习讨论呀!热烈欢迎!!
- 如果本文有不足之处,请各位大佬批评指正,如果而本文对你有帮助的话,那就点个赞吧哈哈!!
最后
以上就是文静墨镜为你收集整理的基于Java_利用Jpcap抓包并分析(非常详细保姆级教程)二前言一、Jpcap类综述二、逐层分析数据包 三、回调抓包并分析四、逐个捕获并分析(线程实现)总结的全部内容,希望文章能够帮你解决基于Java_利用Jpcap抓包并分析(非常详细保姆级教程)二前言一、Jpcap类综述二、逐层分析数据包 三、回调抓包并分析四、逐个捕获并分析(线程实现)总结所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
发表评论 取消回复