pcapParser.h
#ifndef _PCAP_PARSER_H_ #define _PCAP_PARSER_H_ #include#pragma pack(1) //pacp文件头结构体 struct pcap_file_header { uint32_t magic; uint16_t version_major; uint16_t version_minor; uint32_t thiszone; uint32_t sigfigs; uint32_t snaplen; uint32_t linktype; }; //时间戳 struct time_val { int tv_sec; int tv_usec; }; //pcap数据包头结构体 struct pcap_pkthdr { struct time_val ts; uint32_t caplen; uint32_t len; }; // 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#include #include #include #include #include #include #include #include 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:%dn", 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=%dn", 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 %#xn", __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=%sn", 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=%sn", 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.%dn", 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); // ip 协议 if (protocol == 0x0800) { ipDecode(buf + proto_offset); } else { printf("[%s:%d]unsupported protocol %#xn", __FILE__, __LINE__, protocol); } offset += (pcapHeader->caplen + sizeof(pcap_pkthdr)); mPackIndex++; } printf("total package count:%dn", mPackIndex); if (buf) { free(buf); buf = NULL; } }
使用方法,继承PcapParser类,调用parse解析
#include "pcapParser.h" #includeclass 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:%dn", parser.getCount()); return 0; }



