VS下c++解析pcap文件

一、pcap文件格式

https://www.cnblogs.com/Chary/articles/15716063.html

 接口协议(四):以太网(Ethernet)学习(一):协议_以太网协议_QNee的博客-CSDN博客

  

二、代码

pcapParser.h

#ifndef _PCAP_PARSER_H_
#define _PCAP_PARSER_H_

#include <stdint.h>
#include <iostream>

#pragma pack(1)

//pacp文件头结构体
struct pcap_file_header //24字节
{
	uint32_t magic;       /* 0xa1b2c3d4 标记文件开始*/
	uint16_t version_major;   /* magjor Version 2 */
	uint16_t version_minor;   /* magjor Version 4 */
	uint32_t thiszone;      /* gmt to local correction 当地标准事件 一般全0*/
	uint32_t sigfigs;     /* accuracy of timestamps  精确时间戳*/
	uint32_t snaplen;     /* max length saved portion of each pkt 最大存储长度*/
	uint32_t linktype;    /* data link type (LINKTYPE_*) 链路类型*/
};

//时间戳
struct time_val
{
	int tv_sec;         /* seconds 含义同 time_t 对象的值 */
	int tv_usec;        /* and microseconds */
};

//package数据包头结构体
struct package_pkthdr //8+4+4=16
{
	struct time_val ts;  /* time stamp */
	uint32_t caplen; /* length of portion present 32位 ,标识所抓获的数据包保存在pcap文件中的实际长度,以字节为单位*/
	uint32_t len;    /* length this packet (off wire) 抓获的数据包的真实长度,如果文件中保存不是完整的数据包,那么这个值可能要比前面的数据包长度的值大*/
};

// ethnet协议头
struct EthnetHeader_t//14字节
{
	unsigned char srcMac[6];
	unsigned char dstMac[6];
	uint16_t temp; //20230725 临时添加2字节,正常不需要此位
	uint16_t protoType;//连接类型
};

//IP数据报头 20字节
struct IPHeader_t
{
	uint8_t Ver_HLen;       //版本+报头长度
	uint8_t TOS;            //服务类型
	uint16_t TotalLen;       //总长度
	uint16_t ID; //标识
	uint16_t Flag_Segment;   //标志+片偏移
	uint8_t TTL;            //生存周期
	uint8_t Protocol;       //协议类型
	uint16_t Checksum;       //头部校验和
	uint32_t SrcIP; //源IP地址
	uint32_t DstIP; //目的IP地址

};

// UDP头 (8字节)
struct UDPHeader_t
{
	uint16_t SrcPort;    // 源端口号16bit
	uint16_t DstPort;    // 目的端口号16bit
	uint16_t Length;     // 长度
	uint16_t CheckSum;   // 校验码
};

// TCP头 (20字节)
struct TCPHeader_t
{
	uint16_t srcPort;          // 源端口
	uint16_t dstPort;          // 目的端口
	uint32_t SeqNo;            // 序列号
	uint32_t AckNo;            // 确认号
	uint16_t headAndFlags;     // 首部长度即标志位
	uint16_t WinSize;          // 窗口大小
	uint16_t CheckSum;         // 校验和
	uint16_t UrgPtr;           // 紧急指针
};

#pragma pack()

class PcapParser
{
private:
	char mUdpData[4096];             // 4k缓存
	uint32_t mUdpLen;
	char mTcpData[4096*128];             // 4k缓存
	uint32_t mTcpLen;

	uint32_t mPackIndex;


	void ipDecode(const char* buf);
	void udpDecode(const char* buf, int len);
	void tcpDecode(const char* buf, int len);

public:
	PcapParser() : mUdpLen(0), mTcpLen(0), mPackIndex(0){ }
	~PcapParser() {}
public:
	// 过滤Ip
	virtual int ipFilter(const char* srcIp, const char* dstIp) { return 0; }
	// 过滤端口
	virtual int tcpFilter(const uint16_t srcPort, const uint16_t dstPort, const uint32_t msgLen) { return 0; }
	virtual int udpFilter(const uint16_t srcPort, const uint16_t dstPort, const uint32_t msgLen) { return 0; }
	// udp消息回调
	virtual int onUdpMsg(const char* buf, int len) { return 0; }
	// tcp消息回调
	virtual int onTcpMsg(const char* buf, int len) { return 0; }

	// pcap文件解析
	void parse(const char* filename);
};


#endif

pcapParser.cpp

#include "pcapParser.h"
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <io.h>
#include <process.h>
#include <stdlib.h>
#include <fcntl.h>
#include <WS2tcpip.h>

#pragma comment(lib, "ws2_32.lib")

// tcp协议解析
void PcapParser::tcpDecode(const char* buf, int len)
{
	int offset = 0;
	TCPHeader_t* tcpHeader = (TCPHeader_t*)(buf + offset);
	offset += sizeof(TCPHeader_t);//20

	uint16_t srcPort = htons(tcpHeader->srcPort);//大小端转换 
	uint16_t dstPort = htons(tcpHeader->dstPort);
	// 用户数据长度
	uint16_t dataLen = len - sizeof(TCPHeader_t);//TCP包总长-TCP包头

	if (0 != tcpFilter(srcPort, dstPort, dataLen))
	{
		// tcp过滤
		return;
	}

	printf("srcPort[%d]->dstPort[%d]\n", srcPort, dstPort);
	

	//存到缓存,用来做粘包,半包处理
	memcpy(mTcpData, buf + offset, dataLen);
	mTcpLen += dataLen;

	std::cout << "=======================================begin=============================================\n";
	std::cout << "data["<< dataLen <<"]: " << mTcpData <<std::endl;
	std::cout << "========================================end==============================================\n";

	//用户数据
	int usedLen = onTcpMsg(mTcpData, mTcpLen);
	if (usedLen > 0)
	{
		memcpy(mTcpData, mTcpData + usedLen, usedLen);
		mTcpLen -= usedLen;
	}
}

// udp协议解析
void PcapParser::udpDecode(const char* buf, int len)
{
	int offset = 0;
	UDPHeader_t* udpHeader = (UDPHeader_t*)(buf + offset);
	offset += sizeof(UDPHeader_t);

	uint16_t srcPort = ntohs(udpHeader->SrcPort);
	uint16_t dstPort = ntohs(udpHeader->DstPort);
	uint16_t packLen = ntohs(udpHeader->Length);

	// 用户数据长度
	uint16_t dataLen = packLen - sizeof(UDPHeader_t);

	if (0 != udpFilter(srcPort, dstPort, dataLen))
	{
		// udp过滤
		return;
	}

	// 存到缓存,用来做粘包,半包处理
	memcpy(mUdpData, buf + offset, dataLen);
	mUdpLen += dataLen;

	// 用户数据
	int usedLen = onUdpMsg(mUdpData, mUdpLen);
	if (usedLen > 0)
	{
		memcpy(mUdpData, mUdpData + usedLen, usedLen);
		mUdpLen -= usedLen;
	}
}

// IP 协议解析
void PcapParser::ipDecode(const char* buf)
{
	int offset = 0;
	IPHeader_t* ipHeader = (IPHeader_t*)(buf + offset);
	offset += sizeof(IPHeader_t);//20

	char srcIp[32] = { 0 };
	char dstIp[32] = { 0 };

	inet_ntop(AF_INET, &ipHeader->SrcIP, srcIp, sizeof(srcIp));
	inet_ntop(AF_INET, &ipHeader->DstIP, dstIp, sizeof(dstIp));

	uint16_t ipPackLen = ntohs(ipHeader->TotalLen);

	printf("地址:srcIp[%s]->dstIp[%s] 协议类型:%#x(6为tcp,17为udp)  ip包总长=%d  packIdx=%d\n", srcIp, dstIp, ipHeader->Protocol, ipPackLen, mPackIndex);

	if (0 != ipFilter(srcIp, dstIp))
	{
		return;
	}

	switch (ipHeader->Protocol)
	{
	case 17:// UDP协议
		udpDecode(buf + offset, ipPackLen - sizeof(IPHeader_t));
		break;
	case 6: // TCP协议
		tcpDecode(buf + offset, ipPackLen - sizeof(IPHeader_t));
		break;
	default:
		printf("[%s:%d]unsupported protocol %#x\n", __FILE__, __LINE__,
			ipHeader->Protocol);
		break;
	}
}

//解析pcap文件
void PcapParser::parse(const char* filename)
{
	struct stat st;
	if (stat(filename, &st))
	{
		printf("stat file %s failed, errno=%d errmsg=%s\n", filename, errno, strerror(errno));
		return;
	}

	size_t fileSize = st.st_size;

	if (!fileSize)
	{
		printf("file is empty!\n");
		return;
	}

	char *buf = (char*)malloc(fileSize + 1);

	FILE* fp = fopen(filename, "r");
	if (!fp)
	{
		printf("open file %s failed, errno=%d errmsg=%s\n", filename, errno, strerror(errno));
		return;
	}
	fread(buf, sizeof(char), fileSize, fp);
	fclose(fp);


	size_t offset = 0;
	// pcap 文件头
	pcap_file_header* pcapHeader = (pcap_file_header*)(buf + offset);//24字节
	offset += sizeof(pcap_file_header);
	//标记文件开始,并用来识别文件和字节顺序。值可以为0xa1b2c3d4或者0xd4c3b2a1,如果是0xa1b2c3d4表示是大端模式
	printf("如果magic=0xa1b2c3d4,则为大端;magic=0xd4c3b2a1为小端\n");
	printf("pcap file head -> magic:%#x   version:%d.%d\n", pcapHeader->magic, pcapHeader->version_major, 
		pcapHeader->version_minor);

	size_t proto_offset = 0;//初始偏移
	//mPackIndex = 0;


	while (offset < fileSize)
	{
		// package数据包头
		package_pkthdr* packageHeader = (package_pkthdr*)(buf + offset);//16字节
		proto_offset = offset + sizeof(package_pkthdr);

		// arp协议头
		//是根据IP地址获取物理地址的一个TCP/IP协议
		EthnetHeader_t* ethHeader = (EthnetHeader_t*)(buf + proto_offset);//14字节
		proto_offset += sizeof(EthnetHeader_t);

		uint16_t protocol = ntohs(ethHeader->protoType);//LinkType

		
		printf("mac地址:[%02x:%02x:%02x:%02x:%02x:%02x]->[%02x:%02x:%02x:%02x:%02x:%02x] 协议类型:%04x\n",
		ethHeader->srcMac[0], ethHeader->srcMac[1], ethHeader->srcMac[2], ethHeader->srcMac[3], ethHeader->srcMac[4], ethHeader->srcMac[5],
		ethHeader->dstMac[0], ethHeader->dstMac[1], ethHeader->dstMac[2], ethHeader->dstMac[3], ethHeader->dstMac[4], ethHeader->dstMac[5],
		protocol);
		
		// ip 协议
		if (protocol == 0x0800)//2^11  0x0800代表IP协议( 网际协议) 、 0x0806代表ARP协议(地址解析协议)
		{
			ipDecode(buf + proto_offset);//移到地址后面,取地址后面的数据
		}
		else
		{
			printf("[%s:%d]unsupported protocol %#x\n", __FILE__, __LINE__,
				protocol);
		}

		offset += (packageHeader->caplen + sizeof(package_pkthdr));//移到下一个数据包位置
		mPackIndex++;
	}

	printf("total package count:%d\n", mPackIndex);

	if (buf)
	{
		free(buf);
		buf = NULL;
	}
}



 main.cpp

#include "pcapParser.h"
#include <time.h>
#include<stdio.h>
#include<iostream>

class MsgParser : public PcapParser
{
private:
	int mCount;
public:
	MsgParser()
	{
		mCount = 0;
	}

public:
	int getCount() { return mCount; }
	int onUdpMsg(const char* buf, int len)
	{
		// do something
		return len;
	}
};


int main(int argc, char* argv[])
{
	if (2 != argc)
	{
		printf("usage: %s [PCAP_FILE]\n", argv[0]);
		return 0;
	}

	MsgParser parser;
	parser.parse(argv[1]);
	//printf("total quote count:%d\n", parser.getCount());
	system("pause");
	return 0;
}



 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/45754.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

自然语言处理实战项目13-基于GRU模型与NER的关键词抽取模型训练全流程

大家好&#xff0c;我是微学AI&#xff0c;今天给大家介绍一下自然语言处理实战项目13-基于GRU模型与NER的关键词抽取模型训练全流程。本文主要介绍关键词抽取样例数据、GRU模型模型构建与训练、命名实体识别(NER)、模型评估与应用&#xff0c;项目的目标是通过训练一个GRU模型…

npm i babel-plugin-import -D之后报错

替换modules/.bin/XX文件 1.vue-cli-service #!/bin/sh basedir$(dirname "$(echo "$0" | sed -e s,\\,/,g)")case uname in*CYGWIN*) basedircygpath -w "$basedir";; esacif [ -x "$basedir/node" ]; then"$basedir/node"…

Audio Clip

Unity支持的音频格式&#xff1a; aiff/wav&#xff1a;适用于较短声音片段 mp3/OGG:适用于较长的音乐片段 多声道强制转为单声道&#xff0c;减小所占内存。 勾选后会对声音有优化 在后台加载声音 Load Type&#xff1a; 第一个&#xff0c;以不压缩的形式存在内存&#…

深度学习(二)

目录 一、神经网络 整体架构: 架构细节: 神经元个数的影响: 神经网络过拟合解决: 卷积网络 整体架构: 卷积层 边缘填充 特征尺寸计算 池化层 特征图变化 递归神经网络 一、神经网络 整体架构: 图中分别为输入层、隐层1、隐层2、输出层 通过输入层输入某数值&#xf…

Java版本企业电子招投标采购系统源码——功能模块功能描述+数字化采购管理 采购招投标

功能模块&#xff1a; 待办消息&#xff0c;招标公告&#xff0c;中标公告&#xff0c;信息发布 描述&#xff1a; 全过程数字化采购管理&#xff0c;打造从供应商管理到采购招投标、采购合同、采购执行的全过程数字化管理。通供应商门户具备内外协同的能力&#xff0c;为外部…

FAQ文档的重点注意事项!别踩坑了

在很多优秀的大企业中&#xff0c;FAQ文档是企业运营管理中不可或缺的重要部分。但是也仅限大企业&#xff0c;很多企业目前还是没有这个意识的。一方面原因是因为缺乏这个客户服务的意识&#xff0c;另一方面也和技术水平不足有关。但是其实现在有不少的第三方搭建平台可以帮助…

【Element-ui】学习与使用

网站快速成型工具Element&#xff0c;一套为开发者、设计师和产品经理准备的基于vue2.0的桌面端组件库 安装 npm i element-ui -S 在项目中安装element-ui&#xff0c;安装了以后查看package.json中的依赖中有没有element-ui的版本&#xff0c;如果有&#xff0c;则说明安装成功…

react 在build读取env 数据

默认会读取.env 文件 npm install dotenv --save npm install dotenv-cli --save-dev例如读取.env.test "build:test": "dotenv -e .env.test react-app-rewired build",.env.test REACT_APP_CURRENTMODE devREACT_APP_Public_Path "https://baid…

如何利用JMeter测试带有Token参数的POST接口

JMeter有一个很强大的功能就是可以用来做接口测试。 接口测试是测试系统组件间接口的一种测试。接口测试主要用于检测外部系统与系统之间以及内部各个子系统之间的交互点。测试的重点是要检查数据的交换&#xff0c;传递和控制管理过程&#xff0c;以及系统间的相互逻辑依赖关系…

TikTok广告数据不好?收下这份常见问题自查手册!

你是一位跨境卖家吗&#xff1f;你是否在TikTok上投放过广告&#xff1f; 如果你的答案是肯定的&#xff0c;那么你可能遇到过一些困扰。比如&#xff0c;你的广告为什么不起量&#xff1f;为什么突然掉量了&#xff1f;为什么成本上升了&#xff1f;到底是哪里出了问题&#…

基于linux下的高并发服务器开发(第二章)- 2.22 setitimer 定时器函数

#include <sys/time.h> int setitimer(int which, const struct itimerval *new_value, struct itimerval *old_value); - 功能&#xff1a;设置定时器&#xff08;闹钟&#xff09;。可以替代alarm函数。精度微妙us&#xff0c;可以实现周期性定时 - 参数&#xff1a; -…

网络安全(黑客)就业分析指导

一、针对网络安全市场分析 市场需求量高&#xff1b;则是发展相对成熟入门比较容易。所需要的技术水平国家政策环境 对于国家与企业的地位愈发重要&#xff0c;没有网络安全就没有国家安全 更有为国效力的正义黑客—红客联盟 可见其重视程度。 需要掌握的知识点偏多 外围打点…

RocketMQ教程-(5)-功能特性-事务消息

事务消息为 Apache RocketMQ 中的高级特性消息&#xff0c;本文为您介绍事务消息的应用场景、功能原理、使用限制、使用方法和使用建议。 事务消息为 Apache RocketMQ 中的高级特性消息&#xff0c;本文为您介绍事务消息的应用场景、功能原理、使用限制、使用方法和使用建议。…

探索NE555:一款经典的集成电路(超详细)

NE555是一款经典的集成电路&#xff0c;它在电子领域被广泛应用于定时器、脉冲发生器、电压控制振荡器等各种应用场景。它的设计简单、易于使用&#xff0c;并且具备稳定可靠的性能&#xff0c;因此深受电子爱好者和工程师的青睐。本篇博客将详细介绍NE555的原理、工作模式和常…

微服务——统一网关Getway

为什么需要网关&#xff1f; 网关的两种实现: 网关Getway——快速入门 步骤一 网关背身也是一个微服务&#xff0c;需要注册到nacos中去 步骤二 成功运行后 可以通过网关进行请求转发到对应服务。 流程如下&#xff1a; 路由断言工厂 网关路由可以配置的东西有如下。 spri…

8.python设计模式【组合模式】

内容&#xff1a;将对象组合成树形结构以表示“部分-整体”的层次结构。组合模式使得用户对单个对象和组合对象的使用具有一致性。角色&#xff1a; 抽象组建&#xff08;component&#xff09;叶子组建(Leaf)复合组建(Composite)客户端 (Client) UML 图 举个例子 需求&#xf…

从原理到实践,分析 Redisson 分布式锁的实现方案(二)

上篇讲解了如何用 Redis 实现分布式锁的方案&#xff0c;它提供了简单的原语来实现基于Redis的分布式锁。然而&#xff0c;Redis作为分布式锁的实现方式也存在一些缺点。本文将引入Redisson来实现分布式锁。 一、Redisson是什么 Redisson是一个基于Redis的分布式Java框架。它提…

(一)认识InfluxDB

以下内容来自 尚硅谷&#xff0c;写这一系列的文章&#xff0c;主要是为了方便后续自己的查看&#xff0c;不用带着个PDF找来找去的&#xff0c;太麻烦&#xff01; 第 1 章 认识InfluxDB 1.1 InfluxDB的使用场景 InfluxDB是一种时序数据库&#xff0c;时序数据库通常被用在监…

day31贪心算法 用最少数量的箭引爆气球 和无重叠区间

题目描述 题目分析&#xff1a; x轴向上射箭&#xff0c;12一支&#xff0c;重叠的需要一支&#xff0c;3-8一支&#xff0c;7-16一支 返回2&#xff1b; 就是让重叠的气球尽量在一起&#xff0c;局部最优&#xff1b;用一支弓箭&#xff0c;全局最优就是最少弓箭&#xff1b…

猿人学第二题—混淆 动态cookie检测

猿人学第二题—混淆 动态cookie检测 1、代码格式化检测2、检测global和navigator.vendorSub3、检测setInterval思考 4、console.log输出检测补环境 简单的document.cookie&#xff0c;location.reload等就不写了 1、代码格式化检测 这里应该是利用了字符串正则匹配性能低的特点…