C++ 解析pcap文件
Posted fulianzhou
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C++ 解析pcap文件相关的知识,希望对你有一定的参考价值。
pcapParser.h
#ifndef _PCAP_PARSER_H_
#define _PCAP_PARSER_H_
#include <stdint.h>
#pragma pack(1)
//pacp文件头结构体
struct pcap_file_header
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 */
;
//pcap数据包头结构体
struct pcap_pkthdr
struct time_val ts; /* time stamp */
uint32_t caplen; /* length of portion present */
uint32_t len; /* length this packet (off wire) */
;
// ethnet协议头
struct EthnetHeader_t
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; //头部校验和
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]; // 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)
~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 <unistd.h>
#include <stdlib.h>
#include <fcntl.h>
#include <arpa/inet.h>
void PcapParser::tcpDecode(const char* buf, int len)
int offset = 0;
TCPHeader_t* tcpHeader = (TCPHeader_t*)(buf + offset);
offset += sizeof(TCPHeader_t);
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("[%d]->[%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);
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;
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* fileHeader = (pcap_file_header*)(buf + offset);
offset += sizeof(pcap_file_header);
printf("pcap file - magic:%#x version:%d.%d\\n", fileHeader->magic, fileHeader->version_major, fileHeader->version_minor);
size_t proto_offset = 0;
mPackIndex = 0;
while (offset < fileSize)
// pcap 包头
pcap_pkthdr* pcapHeader = (pcap_pkthdr*)(buf + offset);
proto_offset = offset + sizeof(pcap_pkthdr);
// arp协议头
EthnetHeader_t* ethHeader = (EthnetHeader_t*)(buf + proto_offset);
proto_offset += sizeof(EthnetHeader_t);
uint16_t protocol = ntohs(ethHeader->protoType);
/**
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)
ipDecode(buf + proto_offset);
else
printf("[%s:%d]unsupported protocol %#x\\n", __FILE__, __LINE__,
protocol);
offset += (pcapHeader->caplen + sizeof(pcap_pkthdr));
mPackIndex++;
printf("total package count:%d\\n", mPackIndex);
if (buf)
free(buf);
buf = NULL;
使用方法,继承PcapParser类,调用parse解析
#include "pcapParser.h"
#include <time.h>
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());
return 0;
以上是关于C++ 解析pcap文件的主要内容,如果未能解决你的问题,请参考以下文章