实验目的
- 掌握 Wireshark 抓包工具的基本操作,包括网卡选择、数据包捕获启停及协议过滤器的使用方法。
- 理解 ARP 协议的工作原理、分层定位(网络层与数据链路层之间)及报文格式,掌握 ARP 请求与响应报文的核心字段含义。
- 能够通过 Wireshark 分析 ARP 报文的硬件类型、协议类型、MAC 地址、IP 地址等关键字段,识别 ARP 请求与响应。
- 掌握 C++ 语言解析原始 ARP 数据包的编程方法,实现对 ARP 报文各字段的提取与格式化输出,加深对网络协议字节序(大端序)的理解。
实验内容简要描述
实验分为三部分:
- Wireshark 使用与 HTTP 协议分析 :启动 Wireshark 并选择网卡,捕获访问南京师范大学官网(南京师范大学)的 HTTP 报文,通过 "http" 过滤器筛选流量,分析数据链路层(Ethernet)、网络层(IPv4)、传输层(TCP)及应用层(HTTP)的报文结构,观察源 / 目的 MAC 地址、IP 地址、端口号、TCP 序列号、HTTP 请求头等字段。
- ARP 协议分析:在 Wireshark 中使用 "arp" 过滤器筛选 ARP 报文,分析 ARP 报文的分层结构(仅数据链路层与网络层相关字段),识别硬件类型、协议类型、操作码(请求 / 响应)、发送端 / 目标端 MAC 地址与 IP 地址等核心字段。
- 解析 ARP 数据包:基于给定的原始 ARP 数据(十六进制字符串),使用 C++ 语言编写解析程序,按照 ARP 数据包格式(28 字节)依次提取硬件类型、协议类型、地址长度、操作码、MAC 地址、IP 地址等字段,并按规范格式输出至文件,重点处理大端序字节序转换及 MAC/IP 地址的格式化。
实验步骤与结果分析
3.1 Wireshark 使用与 HTTP 协议分析
打开终端输入 wireshark 来启动 Wireshark 。

在界面顶部的网卡选项菜单中选择用户自己的网卡(如 eth0) 。

启动桌面的 chrome 浏览器。
开始分组捕获。点击工具栏中的"捕获"按钮,开始分组捕获。

当完整的页面加载完成后,单击捕获对话框中的"停止捕获"按钮,停止分组捕获。此时, Wireshark 主窗口显示已捕获的本次通信的所有协议报文。
在协议筛选框中输入 http ,按回车键,分组列表窗口中将只显示 HTTP 报文。

如图所示 wireshark 的主窗口由三个部分组成。

-
-
- 第一部分为数据包列表,此部分简要的展示了 wireshark 所捕获到的所有数据包的序号、捕获时间戳、源 IP 信息、目的 IP 信息、最高层协议类型、数据包长度以及数据包的简要信息。
- 第二部分为某个数据包的详细信息,第一行为数据帧的概要信息,从第二行依次往后为各层所使用的协议对应的具体信息。如上图所示,对应展示了数据链路层协议( Ethernet 协议)信息、网络层协议( IPv4 )信息、传输层协议( TCP) 信息以及应用层协议( HTTP )信息。
- 第三部分为数据包原始信息,此部分以十六进制和 ASCII 格式显示数据包的原始字节内容。
-
选中一个数据包,查看数据包具体的数据链路层协议信息,可以看到该数据包对应的目的 MAC 地址为 0a:21:54:48:de:96, 源 MAC 地址为 ee:ee:ee:ee:ee:ee

选中一个数据包,查看数据包具体的网络层协议信息。

- 可以看到数据包的源 IP 地址为 232.2.9.124 ,目的 IP 地址为 100.93.62.220 ;
- 数据包所使用的 IP 协议版本为 4 (即 IPv4);
- 整个 IP 数据包的总长度为 185bytes ;
- Identification: 0x606e 为此 IP 数据包的唯一标识;
- Flags 中 Don't fragment: 1 表示数据包不能被分片。 More fragments: 0 ,表示这是最后一个分片(或无分片);
- Fragment offset: 0 表示数据包的分片偏移量是 0 ,此处数据包未被分片,故为 offset 为 0 ;
- Time to live: 59 此处表示数据包在网络中最多可以经过 59 跳(路由器);
- Protocol: TCP (6) 表示 IP 数据包中承载的上层协议是 TCP ;
- Header checksum: 0x5319 为数据包头部校验和;
选中一个数据包,查看数据包具体的传输层协议信息。

- Src Port: 80 源端口号,表示数据包的发送方端口;
- Dst Port: 37106 目标端口号,表示数据包的接收方端口( 80 为 HTTP 服务的默认端口);
- Seq: 1429 序列号,表示当前数据包在数据流中的位置(相对值);
- Ack: 329 确认号,表示接收方期望接收的下一个字节的序列号(相对值);
- Len: 133 数据部分的长度( Payload ),表示该 TCP 段携带了 133 字节的数据;
- Header Length: 32 bytes 表示 TCP 头部的长度是 32 字节;
选中一个数据包,查看数据包具体的应用层协议信息。

GET /home...js / HTTP/1.1\r\n 表示这是一个 HTTP GET 请求;
Host 至 Accept-Language 为 HTTP 请求头;
3.2 ARP 协议分析
在协议筛选框中输入arp,按回车键,分组列表窗口中将只显示ARP报文。

可以看到ARP报文的数据包详细信息部分仅存在两层(数据链路层协议信息和网络层协议信息),因为ARP工作在网络层和数据链路层之间。

- 具体查看数据包的数据链路层协议信息。可以发现数据链路层承载的上层协议名称为ARP。

具体查看数据包的网络层协议信息。

- Hardware type: Ethernet (1)表示硬件类型是以太网(Ethernet),值为1;
- Protocol type: IPv4 (0x0800)表示协议类型是 IPv4;
- Hardware size: 6表示硬件地址(MAC 地址)的长度是 6 字节;
- Protocol size: 4表示协议地址(IP 地址)的长度是 4 字节;
- Opcode: request (1)操作码 1 表示 ARP 请求,2 表示 ARP 响应;
- Sender MAC address: ee:ee:ee:ee:ee:ee (ee:ee:ee:ee:ee:ee)表示发送方的 MAC 地址;
- Sender IP address: 172.21.229.11表示发送方的 IP 地址;
- Target MAC address: 00:00:00:00:00:00 (00:00:00:00:00:00)表示目标设备的 MAC 地址;
- Target IP address: 100.99.174.107表示目标设备的 IP 地址;
3.3 解析 ARP 数据包
- 在代码文件中利用C++语言编写代码,实现ARP数据包的解析。
- 实验中使用到的ARP数据为0001080006040001eeeeeeeeeeeeac15e50b0000000000006463ae47
- 要求程序输出的规范格式为(*为具体的字段值,最终结果不包含每行前的序号):
Hardware Type: *
Protocol Type: *
Hardware Address Length: *
Protocol Address Length: *
Operation: *
Sender MAC: *
Sender IP: *
Target MAC: *
Target IP: *
- 代码中相应的头文件包含以及一些必要功能已经给出,不要使用需要额外引入的头文件。
- 代码可以在实验环境中通过自行创建文件,并使用g++工具进行编译调试。
实验所用的解析ARP数据包的完整函数如下:
void parseARPPacket(const uint8_t* arpData, const std::string& outputFile)
{
if (!fileExists(outputFile))
{
std::ofstream createFile(outputFile);
if (!createFile.is_open())
{
std::cerr << "Failed to create output file: " << outputFile << std::endl;
return;
}
createFile.close();
}
std::ofstream outFile(outputFile, std::ios::out | std::ios::trunc);
if (!outFile.is_open())
{
std::cerr << "Failed to open output file: " << outputFile << std::endl;
return;
}
// 解析ARP数据包
// ARP数据包格式(28字节):
// 字节0-1: Hardware Type (2字节)
// 字节2-3: Protocol Type (2字节)
// 字节4: Hardware Address Length (1字节)
// 字节5: Protocol Address Length (1字节)
// 字节6-7: Operation (2字节)
// 字节8-13: Sender MAC (6字节)
// 字节14-17: Sender IP (4字节)
// 字节18-23: Target MAC (6字节)
// 字节24-27: Target IP (4字节)
// 提取Hardware Type (2字节,大端序)
uint16_t hardwareType = (arpData[0] << 8) | arpData[1];
// 提取Protocol Type (2字节,大端序)
uint16_t protocolType = (arpData[2] << 8) | arpData[3];
// 提取Hardware Address Length (1字节)
uint8_t hardwareAddrLen = arpData[4];
// 提取Protocol Address Length (1字节)
uint8_t protocolAddrLen = arpData[5];
// 提取Operation (2字节,大端序)
uint16_t operation = (arpData[6] << 8) | arpData[7];
// 提取Sender MAC (6字节)
std::string senderMAC = formatMAC(&arpData[8]);
// 提取Sender IP (4字节)
std::string senderIP = formatIP(&arpData[14]);
// 提取Target MAC (6字节)
std::string targetMAC = formatMAC(&arpData[18]);
// 提取Target IP (4字节)
std::string targetIP = formatIP(&arpData[24]);
// 输出格式
outFile << "Hardware Type: " << hardwareType << std::endl;
// Protocol Type需添加0x前缀
outFile << "Protocol Type: 0x" << std::hex << std::setfill('0') << std::setw(4) << protocolType << std::dec << std::endl;
outFile << "Hardware Address Length: " << static_cast<int>(hardwareAddrLen) << std::endl;
outFile << "Protocol Address Length: " << static_cast<int>(protocolAddrLen) << std::endl;
outFile << "Operation: " << operation << std::endl;
outFile << "Sender MAC: " << senderMAC << std::endl;
outFile << "Sender IP: " << senderIP << std::endl;
outFile << "Target MAC: " << targetMAC << std::endl;
outFile << "Target IP: " << targetIP << std::endl;
outFile.close();
}