栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > C/C++/C#

C++ 解析pcap文件

C/C++/C# 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

C++ 解析pcap文件

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"
#include 
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:%dn", parser.getCount());
    return 0;
}



转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/961016.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号