加载中...
返回

PcapPlusPlus使用记录(一、环境搭建&简单使用)

简介

由于项目的需要,近期产生了一个需求:将一个 pacp 文件解析出来,然后尝试提取每个连接的各种统计数据,例如提取一个完整的TCP会话中的源IP、目的IP、源端口、目的端口、会话开始时间、会话结束时间、发送的数据包数量、发送的数据包总大小等等。

能够实现这一需求的库有很多,如python中的 scapydpkt ,C++中的 PcapPlusPlus 等,考虑到将来可能需要处理较大的 pcap 文件,以及C++相比于python在执行速度上的优势,我决定使用C++作为流量处理的语言;简单翻阅了一下 PcapPlusPlus的文档 ,我认为这个库的易用性能够满足我较低的水平,因此决定先实践一下再说。

预装依赖

从这里开始,我想将 PcapPlusPlus 简称为 PCPP ,方便文章的撰写之用

本文使用的环境是:Win10 + VisualStudio2019

要使用这个库,我们需要先安装一些依赖。

个人建议将这些依赖下载到同一个地方,方便管理!

  • 安装 WinPcap开发者工具Npcap SDK 。下载解压而已,很简单!我这边使用的是WinPcap 。
  • 安装 pthread-win32工具 ,注意这里的链接跟PCPP文档里面的链接是不一样的!文档里面的URL协议是 ftp ,我下载的时候好像打不开的样子,就改为使用 https 了!
  • 可能还需要一个 Microsoft Visual C++ Redistributable 工具,从这里下下来的是个 exe 文件,我在后面的过程中 暂时没有用到 !也就是说我还没运行过这个EXE,先下载下来而已!

下载PcapPlusPlus

直接从 PcapPlusPlus v21.11 页面上把示例代码下载下来!我这边选用的是 windows-vs2019 这个压缩包!

到这一步,算上我们之前下载 并解压 的依赖,文件夹里面应该有这么多东西:

All right?进入刚才下载的VS2019文件夹里面,有个 ExampleProject ,打开之:

没问题的话,就准备运行示例程序了!

运行示例程序

熟悉VS的朋友可能要迫不及待地把那个 .sln 文件给打开了~不要心急!

首先我们应该修改 .props 文件,这个文件是用来指定项目里面的一些属性的;具体地说,其实就是指定刚才下载的几个依赖的路径而已!如果不修改这个文件,贸然打开 .sln ,那必然是要报错的!

最原始的 .props 文件内容如下:

<?xml version="1.0" encoding="utf-8"?> 
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <ImportGroup Label="PropertySheets" />
  <PropertyGroup Label="UserMacros">
    <PcapPlusPlusHome>Drive:\your\PcapPlusPlus\folder</PcapPlusPlusHome>
    <PcapSdkHome>Drive:\WpdPack\folder</PcapSdkHome>
    <PThreadWin32Home>Drive:\pthread-win32\folder</PThreadWin32Home>
  </PropertyGroup>
  <PropertyGroup />
  <ItemDefinitionGroup />
  <ItemGroup />
</Project>

看到吗?这个文件指定三个关键路径:

  • PcapPlusPlusHome :就是刚才解压出来的PCPP目录,也就是现在这个 ExampleProject 的上级目录!
  • PcapSdkHome :用于处理 pcap 文件的SDK工具的目录,在 预装依赖 小节里面我们下载了WinPcap,还记得吗?把它的路径写在这里即可!如果你选用的是Npcap,道理也一样~
  • PThreadWin32Home :多线程库!把pthread路径填进去吧 😀

在我的PC上,修改完成之后这个文件差不多是这样:

<?xml version="1.0" encoding="utf-8"?> 
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <ImportGroup Label="PropertySheets" />
  <PropertyGroup Label="UserMacros">
    <PcapPlusPlusHome>E:\PcapPlusPlus\pcapplusplus-21.11-windows-vs2019</PcapPlusPlusHome>
    <PcapSdkHome>E:\PcapPlusPlus\WpdPack</PcapSdkHome>
    <PThreadWin32Home>E:\PcapPlusPlus\pthreads-w32-2-9-1-release</PThreadWin32Home>
  </PropertyGroup>
  <PropertyGroup />
  <ItemDefinitionGroup />
  <ItemGroup />
</Project>

之后,就可以打开 .sln 文件了!示例项目即刻出现!

main.cpp 简单使用PcapPlusPlus解析了一下示例项目里面的 1_packet.pcap 文件,这个文件只有一个数据包,程序把源IP和目的IP输出了一下而已!

直接编译运行即可:

简单使用PCPP处理pcap文件

刚才运行的示例未免太简单,很难体现出咱们这个库的潜力!

在这一小节,我希望使用这个库简单处理一下我之前捕获的一个 pcap 文件,里面包含两万多条数据,其实也还不算很大。

先把代码贴出来,再慢慢解释吧~

#include <iostream>
#include <IPv4Layer.h>
#include <Packet.h>
#include <PcapFileDevice.h>
#include <set>
#include <ctime>

int main(int argc, char* argv[])
{
    // Part 1
	// open a pcap file for reading
	pcpp::IFileReaderDevice* reader = pcpp::IFileReaderDevice::getReader("test_file_1.pcap");
	if (!reader)
	{
		std::cerr << "Cannot determine reader for file type" << std::endl;
		return 1;
	}
	if (!reader->open())
	{
		std::cerr << "Cannot open input.pcap for reading" << std::endl;
		return 1;
	}
    // Part 2
	if (!reader->setFilter("tcp and port 80"))
	{
		std::cerr << "Cannot set filter for file reader" << std::endl;
		return 1;
	}
	// Part 3
	pcpp::RawPacket rawPacket;
	std::set<std::string> dstIPSet;
	clock_t BEGIN = clock();
	while (reader->getNextPacket(rawPacket))
	{
		pcpp::Packet parsedPacket(&rawPacket);
		if (parsedPacket.isPacketOfType(pcpp::IPv4))
		{
			pcpp::IPv4Address dstIP = parsedPacket.getLayerOfType<pcpp::IPv4Layer>()->getDstIPv4Address();
			if (dstIPSet.count(dstIP.toString()) == 0)
				dstIPSet.insert(dstIP.toString());
		}
	}
	clock_t END = clock();
	// Part 4
	std::cout << "There are total " << dstIPSet.size() << " destination IP address.\n";
	std::cout << "Total time: " << double(END - BEGIN) / CLK_TCK * 1000 << " ms.\n";
	// Part 5
	reader->close();
	delete reader;

	return 0;
}

根据 参考资料[4] ,我们这次使用的 reader 跟刚才示例代码使用的不太一样,用的是 IFileReaderDevice 里面的 getReader() API,它会根据文件名来为我们返回合适的Reader!代码里面的 Part 1 就是在干这个事情而已,创建一个合适的Reader,然后打开它,准备读取文件了!

紧接着,我为这个Reader设置了一个过滤器。 reader->setFilter("tcp and port 80") 表明我只希望读取协议为TCP的、且端口为 80 的数据包,其它的数据包(如ICMP、UDP等等)我就不关心了。这个 setFilter 在将来的场景里面应该是蛮有用的,它使用的是 Berkeley Packet Filter (BPF) syntax

来到 Part 3 之后,开始分析我们读到的数据。过滤器是TCP协议和 80 端口,其实我们读取的就是发往某个Web服务的请求而已!我用了一个集合 dstIPSet 来记录目的IP,打算待会看看总共有多少不同的目的主机 😹 使用 while 循环来读取数据包,使用 parsedPacket 来解析数据包,然后获取数据包里面的IPv4地址,把它放到集合里面!

Part 3 有个小点缀,就是在循环外面设置了两个 clock_t ,目的是测试一下整个循环要花多长时间!

Part 4 就是我们的输出啦:

Part 5 还是比较重要的,要把劳苦功高的Reader关掉、还要释放它的空间啊!刚开始编写这个程序的时候我给忘了,罪过罪过~由于PCPP的这个 IFileReaderDevice 是动态分配的,如果不把它 delete 掉的话会发生内存泄露呀!

参考资料

[1] Quick Start - Visual Studio - PcapPlusPlus

[2] Build on Windows (VS) - PcapPlusPlus

[3] 《PCAP》第1期(1):PcapPlusPlus示例程序VS2015配置 - 知乎 (zhihu.com)

[4] 2. Read/Write Pcap Files - PcapPlusPlus

有朋自远方来,不亦说乎?
Built with Hugo
Theme Stack designed by Jimmy