解析pcap文件并提取其中五元组

解析pcap文件并提取其中五元组

最近在学习分析pcap文件中的数据包,其中数据包的五元组(源IP,目的IP,源端口,目的端口,协议类型,共13个字节)可以用来作为数据流的标识。我们可以将五元组提取出来,以便日后进行进一步的分析。

首先,我们需要对pcap文件进行解析,然后将五元组数据提取出来并写入二进制文件。这里不再赘述,直接上代码:

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<math.h>
#include<time.h>

typedef int32_t bpf_int32;
typedef u_int32_t bpf_u_int32;
typedef u_int16_t u_short;
typedef u_int32_t u_int32;
typedef u_int16_t u_int16;
typedef u_int8_t u_int8;

//pacp文件头结构体
struct pcap_file_header
{
    bpf_u_int32 magic;       /* 0xa1b2c3d4 */
    u_short version_major;   /* magjor Version 2 */
    u_short version_minor;   /* magjor Version 4 */
    bpf_int32 thiszone;      /* gmt to local correction */
    bpf_u_int32 sigfigs;     /* accuracy of timestamps */
    bpf_u_int32 snaplen;     /* max length saved portion of each pkt */
    bpf_u_int32 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 */
    bpf_u_int32 caplen; /* length of portion present */
    bpf_u_int32 len;    /* length this packet (off wire) */
};

//数据帧头
typedef struct FramHeader_t
{ //Pcap捕获的数据帧头
    u_int8 DstMAC[6]; //目的MAC地址
    u_int8 SrcMAC[6]; //源MAC地址
    u_short FrameType;    //帧类型
} FramHeader_t;

//IP数据报头
typedef struct IPHeader_t
{ //IP数据报头
    u_int8 Ver_HLen;       //版本+报头长度
    u_int8 TOS;            //服务类型
    u_int16 TotalLen;       //总长度
    u_int16 ID; //标识
    u_int16 Flag_Segment;   //标志+片偏移
    u_int8 TTL;            //生存周期
    u_int8 Protocol;       //协议类型
    u_int16 Checksum;       //头部校验和
    u_int32 SrcIP; //源IP地址
    u_int32 DstIP; //目的IP地址
} IPHeader_t;

//TCP数据报头
typedef struct TCPHeader_t
{ //TCP数据报头
    u_int16 SrcPort;//源端口
    u_int16 DstPort;//目的端口
    u_int32 SeqNO;//序号
    u_int32 AckNO; //确认号
    u_int8 HeaderLen; //数据报头的长度(4 bit) + 保留(4 bit)
    u_int8 Flags; //标识TCP不同的控制消息
    u_int16 Window; //窗口大小
    u_int16 Checksum; //校验和
    u_int16 UrgentPointer;  //紧急指针
}TCPHeader_t;

//UDP数据
typedef struct UDPHeader_s
{
    u_int16_t SrcPort;     // 源端口号16bit
    u_int16_t DstPort;    // 目的端口号16bit
    u_int16_t len;        // 数据包长度16bit
    u_int16_t checkSum;   // 校验和16bit
}UDPHeader_t;

typedef struct Quintet
{
	u_int32 SrcIP; //源IP地址
	u_int32 DstIP; //目的IP地址
	u_int16_t SrcPort;     // 源端口号16bit
	u_int16_t DstPort;    // 目的端口号16bit
	u_int8 Protocol;       //协议类型
}Quintet_t;

int main()
{
    struct pcap_pkthdr *ptk_header = NULL;
    FramHeader_t *eth_header = NULL;
    IPHeader_t *ip_header = NULL;
    TCPHeader_t *tcp_header = NULL;
    UDPHeader_t *udp_header = NULL;
    Quintet_t *quintet = NULL;
    //char buf[BUFSIZE];

    //初始化
    ptk_header  = (struct pcap_pkthdr *)malloc(sizeof(struct pcap_pkthdr));
    eth_header = (FramHeader_t *)malloc(sizeof(FramHeader_t));
    ip_header = (IPHeader_t *)malloc(sizeof(IPHeader_t));
    tcp_header = (TCPHeader_t *)malloc(sizeof(TCPHeader_t));
    udp_header = (UDPHeader_t *)malloc(sizeof(UDPHeader_t));
    quintet = (Quintet_t *)malloc(sizeof(Quintet_t));
    //memset(buf, 0, sizeof(buf));

	FILE* pFile = fopen( "data.pcap", "r");
    if( pFile == 0)
    {
        printf( "打开pcap文件失败");
        return 0;
    }

    FILE *output = fopen("output.dat","wb");
    if( output == 0)
    {
    	printf( "打开dat文件失败");
        return 0;
    }

    //开始读数据包
    printf("开始读数据包\n");
    long int pkt_offset;	//用来文件偏移
    pkt_offset = 24;       //pcap文件头结构 24个字节
    int i = 0;
    while(fseek(pFile, pkt_offset, SEEK_SET) == 0) //遍历数据包
    {
        i++;
        memset(ptk_header, 0, sizeof(struct pcap_pkthdr));
        memset(quintet,0,sizeof(struct Quintet));
        //pcap_pkt_header 16 byte
        if(fread(ptk_header, 16, 1, pFile) != 1) //读pcap数据包头结构
        {
            printf("%d: can not read ptk_header\n", i);
            break;
        }

        pkt_offset += 16 + ptk_header->caplen;   //下一个数据包的偏移值
        memset(eth_header , 0, 14);
        //数据帧头 14字为ethnet协议大小,注意指定网卡抓包 不指定是16字节的linuxcooked
        if(fread(eth_header, 14, 1, pFile) != 1) //读Ethernet数据
        {
            printf("%d: can not read eth_header\n", i);
            break;
        }

        if(eth_header->FrameType != 0x0008)
        {
            if(eth_header->FrameType == 0x0081)
            {
                fseek(pFile, 4, SEEK_CUR); //忽略802.1Q
            }
            else
            {
                printf("%d: unknown frame type  %x\n",i,eth_header->FrameType);
                continue;
            }
        }
        //IP数据报头 20字节 不考虑>20字节
        memset(ip_header, 0, sizeof(IPHeader_t));
        if(fread(ip_header, sizeof(IPHeader_t), 1, pFile) != 1)
        {
            printf("%d: can not read tcp_header\n", i);
            break;
        }
        quintet->SrcIP = ip_header->SrcIP;
        quintet->DstIP = ip_header->DstIP;
        quintet->Protocol = ip_header->Protocol;

        memset(tcp_header,0,sizeof(TCPHeader_t));
        memset(udp_header,0,sizeof(UDPHeader_t));
        if(ip_header->Protocol == 0x06) //判断是否是 TCP 协议
        {
            //TCP头 20字节
            if(fread(tcp_header, sizeof(TCPHeader_t), 1, pFile) != 1)
            {
                printf("%d: can not read tcp_header\n", i);
                break;
            }
            quintet->SrcPort = tcp_header->SrcPort;
            quintet->DstPort = tcp_header->DstPort;
        }
        else if(ip_header->Protocol == 0x11)//UDP
        {
            if(fread(udp_header, sizeof(UDPHeader_t), 1, pFile) != 1)
            {
                printf("%d: can not read udp_header\n", i);
            }
            quintet->SrcPort = udp_header->SrcPort;
            quintet->DstPort = udp_header->DstPort;

        }
        fwrite(quintet,13,1,output);


    } // end while
    fclose(pFile);
    fclose(output);
    printf("Finish!\n");
    return 0;
}


评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值