VS下c++解析pcap文件

一、pcap文件格式

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

二、代码

pcapParser.h

cpp 复制代码
#ifndef _PCAP_PARSER_H_
#define _PCAP_PARSER_H_

#include <stdint.h>

#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 */
	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 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;       //头部校验和
	uint16_t test; //20230725 add lijie
	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*4096];             // 4k缓存
	uint32_t mTcpLen;
	//uint64_t mTcpLen;
	//long long unsigned int 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

cpp 复制代码
#include "pcapParser.h"
//#include <windows.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 = tcpHeader->srcPort;
	uint16_t dstPort = tcpHeader->dstPort;
	// 用户数据长度
	uint16_t dataLen = len - sizeof(TCPHeader_t);

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

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

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

	// 用户数据
	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 + mUdpLen, 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("[%s]->[%s] 协议类型proto:%#x  ipPackLen=%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("[%02x:%02x:%02x:%02x:%02x:%02x]->[%02x:%02x:%02x:%02x:%02x:%02x] proto:%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
		{
			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

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;
}
相关推荐
2401_883041083 小时前
新锐品牌电商代运营公司都有哪些?
大数据·人工智能
青云交3 小时前
大数据新视界 -- 大数据大厂之 Impala 性能优化:融合机器学习的未来之路(上 (2-1))(11/30)
大数据·计算资源·应用案例·数据交互·impala 性能优化·机器学习融合·行业拓展
Json_181790144806 小时前
An In-depth Look into the 1688 Product Details Data API Interface
大数据·json
Qspace丨轻空间8 小时前
气膜场馆:推动体育文化旅游创新发展的关键力量—轻空间
大数据·人工智能·安全·生活·娱乐
ckboss9 小时前
金融小白两周完成一个量化系统 (三)项目进度以及结构框架
金融
Elastic 中国社区官方博客9 小时前
如何将数据从 AWS S3 导入到 Elastic Cloud - 第 3 部分:Elastic S3 连接器
大数据·elasticsearch·搜索引擎·云计算·全文检索·可用性测试·aws
非凸科技10 小时前
非凸科技助力第49届ICPC亚洲区域赛(成都)成功举办
科技·金融·非凸科技
Aloudata10 小时前
从Apache Atlas到Aloudata BIG,数据血缘解析有何改变?
大数据·apache·数据血缘·主动元数据·数据链路
水豚AI课代表10 小时前
分析报告、调研报告、工作方案等的提示词
大数据·人工智能·学习·chatgpt·aigc
拓端研究室TRL13 小时前
【梯度提升专题】XGBoost、Adaboost、CatBoost预测合集:抗乳腺癌药物优化、信贷风控、比特币应用|附数据代码...
大数据