• 解析pcap文件及读取实现源码


    转自:http://imzc.net/archives/181/%E8%A7%A3%E6%9E%90pcap%E6%96%87%E4%BB%B6%E5%8F%8A%E6%BA%90%E7%A0%81/

    下面pcap文件格式介绍是在网上转的,根据理解,写了个程序来进行解析pcap文件,后续再实现合并pcap功能(wireshark已经自带命令行合并pcap文件工具,在这里只是为了分析pcap文件和学习)。
    ==========================
    默认的*.pcap文件保存格式。

    Pcap文件头24B各字段说明:

    Magic:4B:0x1A 2B 3C 4D:用来标示文件的开始
    Major:2B,0×02 00:当前文件主要的版本号
    Minor:2B,0×04 00当前文件次要的版本号
    ThisZone:4B当地的标准时间;全零
    SigFigs:4B时间戳的精度;全零
    SnapLen:4B最大的存储长度
    LinkType:4B链路类型
    常用类型:
    0            BSD loopback devices, except for later OpenBSD
    1            Ethernet, and Linux loopback devices
    6            802.5 Token Ring
    7            ARCnet
    8            SLIP
    9            PPP
    10           FDDI
    100         LLC/SNAP-encapsulated ATM
    101         “raw IP”, with no link
    102         BSD/OS SLIP
    103         BSD/OS PPP
    104         Cisco HDLC
    105         802.11
    108         later OpenBSD loopback devices (with the AF_value in network byte order)
    113         special Linux “cooked” capture
    114         LocalTalk
     
    Packet 包头和Packet数据组成
    字段说明:
    Timestamp:时间戳高位,精确到seconds
    Timestamp:时间戳低位,精确到microseconds
    Caplen:当前数据区的长度,即抓取到的数据帧长度,由此可以得到下一个数据帧的位置。
    Len:离线数据长度网络中实际数据帧的长度,一般不大于caplen,多数情况下和Caplen数值相等。
    Packet 数据: 即 Packet(通常就是链路层的数据帧)具体内容,长度就是Caplen,这个长度的后面,就是当前PCAP文件中存放的下一个Packet数据包,也就 是说:PCAP文件里面并没有规定捕获的Packet数据包之间有什么间隔字符串,下一组数据在文件中的起始位置。我们需要靠第一个Packet包确定。 最后,Packet数据部分的格式其实就是标准的网路协议格式了可以任何网络教材上找得到。
    ===========================
    我的实现:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    
    //
    //  pcap.h
    //  pcaptest
    //
    //  Created by zc on 12-1-24.
    //  Copyright 2012年 __MyCompanyName__. All rights reserved.
    //
     
    #ifndef pcaptest_pcap_h
    #define pcaptest_pcap_h
     
    typedef unsigned int  bpf_u_int32;
    typedef unsigned short  u_short;
    typedef int bpf_int32;
     
    /*
     Pcap文件头24B各字段说明:
     Magic:4B:0x1A 2B 3C 4D:用来标示文件的开始
     Major:2B,0x02 00:当前文件主要的版本号     
     Minor:2B,0x04 00当前文件次要的版本号
     ThisZone:4B当地的标准时间;全零
     SigFigs:4B时间戳的精度;全零
     SnapLen:4B最大的存储长度    
     LinkType:4B链路类型
     常用类型:
      0            BSD loopback devices, except for later OpenBSD
     1            Ethernet, and Linux loopback devices
     6            802.5 Token Ring
     7            ARCnet
     8            SLIP
     9            PPP
     */
    typedef struct pcap_file_header {
    	bpf_u_int32 magic;
    	u_short version_major;
    	u_short version_minor;
    	bpf_int32 thiszone;    
    	bpf_u_int32 sigfigs;   
    	bpf_u_int32 snaplen;   
    	bpf_u_int32 linktype;  
    }pcap_file_header;
     
    /*
     Packet 包头和Packet数据组成
     字段说明:
     Timestamp:时间戳高位,精确到seconds     
     Timestamp:时间戳低位,精确到microseconds
     Caplen:当前数据区的长度,即抓取到的数据帧长度,由此可以得到下一个数据帧的位置。
     Len:离线数据长度:网络中实际数据帧的长度,一般不大于caplen,多数情况下和Caplen数值相等。
     Packet 数据:即 Packet(通常就是链路层的数据帧)具体内容,长度就是Caplen,这个长度的后面,就是当前PCAP文件中存放的下一个Packet数据包,也就 是说:PCAP文件里面并没有规定捕获的Packet数据包之间有什么间隔字符串,下一组数据在文件中的起始位置。我们需要靠第一个Packet包确定。
     */
     
    typedef struct  timestamp{
    	bpf_u_int32 timestamp_s;
    	bpf_u_int32 timestamp_ms;
    }timestamp;
     
    typedef struct pcap_header{
    	timestamp ts;
    	bpf_u_int32 capture_len;
    	bpf_u_int32 len;
     
    }pcap_header;
     
     
    void prinfPcapFileHeader(pcap_file_header *pfh);
    void printfPcapHeader(pcap_header *ph);
    void printPcap(void * data,size_t size);
     
    #endif
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    
    //
    //  pcap.c
    //  pcaptest
    //
    //  Created by zc on 12-1-24.
    //  Copyright 2012年 __MyCompanyName__. All rights reserved.
    //
     
    #include <stdio.h>
    #include "pcap.h"
     
    void prinfPcapFileHeader(pcap_file_header *pfh){
    	if (pfh==NULL) {
    		return;
    	}
    	printf("=====================\n"
    		   "magic:0x%0x\n"
    		   "version_major:%u\n"
    		   "version_minor:%u\n"
    		   "thiszone:%d\n"
    		   "sigfigs:%u\n"
    		   "snaplen:%u\n"
    		   "linktype:%u\n"
    		   "=====================\n",
    		   pfh->magic,
    		   pfh->version_major,
    		   pfh->version_minor,
    		   pfh->thiszone,
    		   pfh->sigfigs,
    		   pfh->snaplen,
    		   pfh->linktype);
    }
     
    void printfPcapHeader(pcap_header *ph){
    	if (ph==NULL) {
    		return;
    	}
    	printf("=====================\n"
    		   "ts.timestamp_s:%u\n"
    		   "ts.timestamp_ms:%u\n"
    		   "capture_len:%u\n"
    		   "len:%d\n"
    		   "=====================\n",
    		   ph->ts.timestamp_s,
    		   ph->ts.timestamp_ms,
    		   ph->capture_len,
    		   ph->len);
     
     
    }
     
    void printPcap(void * data,size_t size){
    	unsigned  short iPos = 0;
    	//int * p = (int *)data;
    	//unsigned short* p = (unsigned short *)data;
    	if (data==NULL) {
    		return;
    	}
     
    	printf("\n==data:0x%x,len:%lu=========",data,size);
     
    	for (iPos=0; iPos < size/sizeof(unsigned short); iPos++) {
    		//printf(" %x ",(int)( * (p+iPos) ));
    		//unsigned short a = ntohs(p[iPos]);
     
    		unsigned short a = ntohs( *((unsigned short *)data + iPos ) );
    		if (iPos%8==0) printf("\n");
    		if (iPos%4==0) printf(" ");
     
    		printf("%04x",a);
     
     
    	}
    	/*
    	 for (iPos=0; iPos <= size/sizeof(int); iPos++) {
    		//printf(" %x ",(int)( * (p+iPos) ));
    		int a = ntohl(p[iPos]);
     
    		//int a = ntohl( *((int *)data + iPos ) );
    		if (iPos %4==0) printf("\n");
     
    		printf("%08x ",a);
     
     
    	}
    	 */
    	printf("\n============\n");
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    
    //
    //  main.c
    //  pcaptest
    //
    //  Created by zc on 12-1-24.
    //  Copyright 2012年 __MyCompanyName__. All rights reserved.
    //
     
    #include <stdio.h>
    #include <arpa/inet.h>
    #include "pcap.h"
     
    #define PCAP_FILE "ping.pcap"
    #define MAX_ETH_FRAME 1514
    #define ERROR_FILE_OPEN_FAILED -1
    #define ERROR_MEM_ALLOC_FAILED -2
    #define ERROR_PCAP_PARSE_FAILED -3
     
     
    int main (int argc, const char * argv[])
    {
     
    	printf("sizeof:int %lu,unsigned int %lu,char %lu,unsigned char %lu,short:%lu,unsigned short:%lu\n",
    		    sizeof(int),sizeof(unsigned int),sizeof(char),sizeof(unsigned char),sizeof(short),sizeof(unsigned short));
     
    	pcap_file_header  pfh;
    	pcap_header  ph;
    	int count=0;
    	void * buff = NULL;
    	int readSize=0;
    	int ret = 0;
     
    	FILE *fp = fopen(PCAP_FILE, "rw");
     
    	if (fp==NULL) {
    		fprintf(stderr, "Open file %s error.",PCAP_FILE);
    		ret = ERROR_FILE_OPEN_FAILED;
    		goto ERROR;
    	}
     
    	fread(&pfh, sizeof(pcap_file_header), 1, fp);	
    	prinfPcapFileHeader(&pfh);
    	//fseek(fp, 0, sizeof(pcap_file_header));
     
    	buff = (void *)malloc(MAX_ETH_FRAME);
    	for (count=1; ; count++) {
    		memset(buff,0,MAX_ETH_FRAME);
    		//read pcap header to get a packet
    		//get only a pcap head count .
    		readSize=fread(&ph, sizeof(pcap_header), 1, fp);
    		if (readSize<=0) {
    			break;
    		}
    		printfPcapHeader(&ph);
     
     
    		if (buff==NULL) {
    			fprintf(stderr, "malloc memory failed.\n");
    			ret = ERROR_MEM_ALLOC_FAILED;
    			goto ERROR;
    		}
     
    		//get a packet contents.
    		//read ph.capture_len bytes.
    		readSize=fread(buff,1,ph.capture_len, fp);
    		if (readSize != ph.capture_len) {
    			free(buff);
    			fprintf(stderr, "pcap file parse error.\n");
    			ret = ERROR_PCAP_PARSE_FAILED;
    			goto ERROR;
    		}
    		printPcap(buff, ph.capture_len);
     
     
    		printf("===count:%d,readSize:%d===\n",count,readSize);
     
    		if (feof(fp) || readSize <=0 ) { 
    			break;
    		}
    	}
     
    ERROR:
    	//free
    	if (buff) {
    		free(buff);
    		buff=NULL;
    	} 
    	if (fp) {
    		fclose(fp);
    		fp=NULL;
    	}	
     
        return ret;
    }

    Makefile:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    
    objects = main.o pcap.o
     
    pcaptest : $(objects)
    	gcc -o pcaptest  $(objects)
     
    main.o:pcap.h
    pcap.o:pcap.h
     
    .PHONY : clean
    clean :
    	rm pcaptest  $(objects)
  • 相关阅读:
    mysql 在orderby和limit混合使用时重复数据问题
    springboot启动类 注解
    redis RDB和AOF两种持久化的区别
    C#解析逻辑字符串【x>y&&a>b||p=r】
    删除例如联想笔记本系统隐藏分区
    通过贝叶斯算法实现自动识别类别
    将可执行exe文件注册成windows服务
    Windows10中的IIS10安装php manager和IIS URL Rewrite 2.0组件的方法
    添加钩子监听全局鼠标或键盘事件
    C# DateTime.Now和DateTime.UtcNow的区别
  • 原文地址:https://www.cnblogs.com/hnrainll/p/2552943.html
Copyright © 2020-2023  润新知