VS下c++解析pcap文件

news2024/11/23 11:18:41

一、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;
}



 

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

向npm注册中心发布包(下)

目录 1、在package.json文件中指定dependencies和devDependencies 1.1 将依赖项添加到 package.json 文件 1.2 从命令行中 将依赖项添加到 package.json 文件 1.3 手动编辑 package.json 文件 2、关于语义版本控制 2.1 在已发布的包中增加语义版本 2.2 使用语义版本控制…

CentOS7系统Nvidia Docker容器基于TensorFlow2.12测试GPU

CentOS7系统Nvidia Docker容器基于TensorFlow1.15测试GPU 参考我的另一篇博客 1. 安装NVIDIA-Docker的Tensorflow2.12.0版本 1. 版本依赖对应关系&#xff1a;从源代码构建 | TensorFlow GPU 版本Python 版本编译器构建工具cuDNNCUDAtensorflow-2.6.03.6-3.9GCC 7.3.1Ba…

Linux设置密码复杂度

在etc目录下pam.d目录下&#xff0c;存在system-auth文件 先将文件备份下&#xff0c;然后在system-auth中插入下面行 password requisite pam_pwquality.so try_first_pass local_users_only retry3 authtok_type minlen8 lcredit-1 ucredit-1 dcredit-1 ocredi…

OpenCV 4.0+Python机器学习与计算机视觉实战

&#x1f482; 个人网站:【办公神器】【游戏大全】【神级源码资源网】&#x1f91f; 前端学习课程&#xff1a;&#x1f449;【28个案例趣学前端】【400个JS面试题】&#x1f485; 寻找学习交流、摸鱼划水的小伙伴&#xff0c;请点击【摸鱼学习交流群】 目录 前言第一部分&…

Shell脚本学习-变量子串

变量子串&#xff1a; man bash&#xff0c;然后搜索&#xff1a;Parameter Expansion。 参数拓展 $字符引进、提出了参数拓展、命令替换和数字替换。变量名或标识被大括号包围才能够被拓展。 我们可以记住一个表&#xff1a; 序号表达式说明1${parameter}返回变量$paramete…

东南大学齿轮箱故障诊断(Python代码,CNN结合LSTM模型)

运行代码要求&#xff1a; 代码运行环境要求&#xff1a;Keras版本>2.4.0&#xff0c;python版本>3.6.0 1.东南大学采集数据平台&#xff1a; 数据 该数据集包含2个子数据集&#xff0c;包括轴承数据和齿轮数据&#xff0c;这两个子数据集都是在传动系动力学模拟器&am…

PVS-Studio Crack,重新编译后的自动分析

PVS-Studio Crack,重新编译后的自动分析 PVS Studio执行静态代码分析并生成报告&#xff0c;帮助程序员查找和修复错误。PVS Studio执行广泛的代码检查&#xff0c;搜索印刷错误和复制粘贴错误也很有用。此类错误的示例&#xff1a;V501、V517、V522、V523、V3001。 静态分析的…

常常会用到的截取字符串substr()、substring()、slice()方法详解

常常会用到的截取字符串substr()、substring()、slice()方法详解 slice() 定义&#xff1a;接受一个或者两个参数&#xff0c;第一个参数指定子字符串的开始位置。第二个参数表示子字符串的结束位置&#xff08;不包括结束位置的那个字符&#xff09;&#xff0c;如果没有传递…

Linux用户权限问题详解

Linux用户权限问题详解 【一】Linux权限的概念&#xff08;1&#xff09;用户类型&#xff08;2&#xff09;如何切换用户&#xff08;3&#xff09;用户相关的一些命令 【二】Linux文件权限管理&#xff08;1&#xff09;文件访问者的分类&#xff08;2&#xff09;文件类型和…

激光点云数据如何在客户端进行管理、查看及分享?

四维轻云是一款地理空间数据在线管理平台&#xff0c;具有地理空间数据的在线管理、查看及分享等功能。在四维轻云平台中&#xff0c;用户可以不受时间地点限制&#xff0c;随时随地上传数字高程模型、激光点云、倾斜摄影模型、正射影像等地理空间数据。 现在&#xff0c;小编…

算法(3)

喝汽水 两瓶即可换一瓶 import java.util.*; public class Main {public static void main(String[] args) {//剩2个空瓶子时&#xff0c;可以先找老板借一瓶汽水&#xff0c;喝掉这瓶满的&#xff0c;喝完以后用3个空瓶子换一瓶满的还给老板。 //也就是说2个空瓶子即可换一瓶汽…

vue如何设置网站标题和logo图标

目录 1、在根目录找到项目index.html文件 2、在index.html 的 title标签中修改名称为自己设计的标题 3、在index.html 的 title标签下的link标签中引入图标 ①格式为&#xff1a; ②注意&#xff1a; 1、在根目录找到项目index.html文件 2、在index.html 的 title标签中修改…

Visual Assist X Crack

Visual Assist X Crack Visual Assist X通过Visual Studio中的关键新功能和对现有功能的改进&#xff0c;大大缩短了应用程序开发时间&#xff0c;使您能够&#xff1a;Visual Assist提高了自动化程度&#xff0c;简化了导航&#xff0c;并在开发过程中显示重要信息。这些功能已…

WebDAV之π-Disk派盘+ WinSCP

WinSCP是一个免费的开源文件传输应用程序&#xff0c;它使用文件传输协议&#xff0c;安全外壳文件传输协议和安全复制协议来进行纯文件或安全文件传输。该应用程序旨在与Windows一起使用&#xff0c;并支持常见的Windows桌面功能&#xff0c;例如拖放文件&#xff0c;跳转列表…

Python web实战 | 使用 Django 搭建 Web 应用程序 【干货】

概要 从社交媒体到在线购物&#xff0c;从在线银行到在线医疗&#xff0c;Web 应用程序为人们提供了方便快捷的服务。Web 应用程序已经成为了人们日常生活中不可或缺的一部分。搭建一个高效、稳定、易用的 Web 应用程序并不是一件容易的事情。本文将介绍如何使用 Django 快速搭…

2_Apollo4BlueLite中断控制器NVIC

1.概述 Apollo4BlueLite 的中断控制器是采用 ARM Cortex-M4 内核&#xff0c;并集成了 NVIC&#xff08;Nested Vectored Interrupt Controller&#xff0c;嵌套向量中断控制器&#xff09;作为其中断控制器。 NVIC 是 ARM Cortex-M 系列处理器中常用的中断控制器&#xff0c…

Linux centos7.x系统将/home磁盘分配给/

1.解除挂载并删除/home卷 umount /home如果出现以下报错 &#xff1a; 可以使用以下命令查看哪些进程在占用 fuser -mv /home杀死这些进程就行 kill -9 进程号然后再执行umount /home就可以成功了 &#xff0c; 同时执行以下命令把逻辑卷删除了 lvremove /dev/centos/home…

腾讯云标准型S6/SA3/SR1/S5/SA2服务器CPU处理器大全

腾讯云服务器CVM标准型CPU处理器大全&#xff0c;包括标准型S6、SA3、SR1、S5、S5se、SA2、S4、SN3ne、S3、SA1、S2ne实例CPU处理器型号大全&#xff0c;标准型S6云服务器CPU采用Intel Ice Lake(2.7GHz/3.3GHz)&#xff0c;标准型S5采用Intel Xeon Cascade Lake 8255C/Intel Xe…

Linux C tcp/ip

服务端代码&#xff1a; #include <stdio.h> #include<sys/types.h> #include<sys/socket.h> #include<string.h> #include<netinet/in.h> #include<arpa/inet.h> #include <unistd.h>/* socket bind listen accept send/receive *…

SpringBoot Redis 多数据源集成支持哨兵模式和Cluster集群模式

Redis 从入门到精通【应用篇】之SpringBoot Redis 多数据源集成支持哨兵模式Cluster集群模式、单机模式 文章目录 Redis 从入门到精通【应用篇】之SpringBoot Redis 多数据源集成支持哨兵模式Cluster集群模式、单机模式0.前言说明项目结构Pom 依赖 1. 配置1.1 通用配置&#xf…